Path: blob/master/src/java.desktop/share/native/common/java2d/opengl/OGLVertexCache.c
41159 views
/*1* Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425#ifndef HEADLESS2627#include <stdlib.h>28#include <string.h>2930#include "sun_java2d_SunGraphics2D.h"3132#include "OGLPaints.h"33#include "OGLVertexCache.h"3435typedef struct _J2DVertex {36jfloat tx, ty;37jubyte r, g, b, a;38jfloat dx, dy;39} J2DVertex;4041static J2DVertex *vertexCache = NULL;42static jint vertexCacheIndex = 0;4344static GLuint maskCacheTexID = 0;45static jint maskCacheIndex = 0;4647#define OGLVC_ADD_VERTEX(TX, TY, R, G, B, A, DX, DY) \48do { \49J2DVertex *v = &vertexCache[vertexCacheIndex++]; \50v->tx = TX; \51v->ty = TY; \52v->r = R; \53v->g = G; \54v->b = B; \55v->a = A; \56v->dx = DX; \57v->dy = DY; \58} while (0)5960#define OGLVC_ADD_QUAD(TX1, TY1, TX2, TY2, DX1, DY1, DX2, DY2, R, G, B, A) \61do { \62OGLVC_ADD_VERTEX(TX1, TY1, R, G, B, A, DX1, DY1); \63OGLVC_ADD_VERTEX(TX2, TY1, R, G, B, A, DX2, DY1); \64OGLVC_ADD_VERTEX(TX2, TY2, R, G, B, A, DX2, DY2); \65OGLVC_ADD_VERTEX(TX1, TY2, R, G, B, A, DX1, DY2); \66} while (0)6768jboolean69OGLVertexCache_InitVertexCache(OGLContext *oglc)70{71J2dTraceLn(J2D_TRACE_INFO, "OGLVertexCache_InitVertexCache");7273if (vertexCache == NULL) {74vertexCache = (J2DVertex *)malloc(OGLVC_MAX_INDEX * sizeof(J2DVertex));75if (vertexCache == NULL) {76return JNI_FALSE;77}78}7980if (!oglc->vertexCacheEnabled) {81j2d_glTexCoordPointer(2, GL_FLOAT,82sizeof(J2DVertex), vertexCache);83j2d_glColorPointer(4, GL_UNSIGNED_BYTE,84sizeof(J2DVertex), ((jfloat *)vertexCache) + 2);85j2d_glVertexPointer(2, GL_FLOAT,86sizeof(J2DVertex), ((jfloat *)vertexCache) + 3);8788j2d_glEnableClientState(GL_TEXTURE_COORD_ARRAY);89j2d_glEnableClientState(GL_COLOR_ARRAY);90j2d_glEnableClientState(GL_VERTEX_ARRAY);9192oglc->vertexCacheEnabled = JNI_TRUE;93}9495return JNI_TRUE;96}9798void99OGLVertexCache_FlushVertexCache()100{101J2dTraceLn(J2D_TRACE_INFO, "OGLVertexCache_FlushVertexCache");102103if (vertexCacheIndex > 0) {104j2d_glDrawArrays(GL_QUADS, 0, vertexCacheIndex);105}106vertexCacheIndex = 0;107}108109/**110* This method is somewhat hacky, but necessary for the foreseeable future.111* The problem is the way OpenGL handles color values in vertex arrays. When112* a vertex in a vertex array contains a color, and then the vertex array113* is rendered via glDrawArrays(), the global OpenGL color state is actually114* modified each time a vertex is rendered. This means that after all115* vertices have been flushed, the global OpenGL color state will be set to116* the color of the most recently rendered element in the vertex array.117*118* The reason this is a problem for us is that we do not want to flush the119* vertex array (in the case of mask/glyph operations) or issue a glEnd()120* (in the case of non-antialiased primitives) everytime the current color121* changes, which would defeat any benefit from batching in the first place.122* We handle this in practice by not calling CHECK/RESET_PREVIOUS_OP() when123* the simple color state is changing in OGLPaints_SetColor(). This is124* problematic for vertex caching because we may end up with the following125* situation, for example:126* SET_COLOR (orange)127* MASK_FILL128* MASK_FILL129* SET_COLOR (blue; remember, this won't cause a flush)130* FILL_RECT (this will cause the vertex array to be flushed)131*132* In this case, we would actually end up rendering an orange FILL_RECT,133* not a blue one as intended, because flushing the vertex cache flush would134* override the color state from the most recent SET_COLOR call.135*136* Long story short, the easiest way to resolve this problem is to call137* this method just after disabling the mask/glyph cache, which will ensure138* that the appropriate color state is restored.139*/140void141OGLVertexCache_RestoreColorState(OGLContext *oglc)142{143if (oglc->paintState == sun_java2d_SunGraphics2D_PAINT_ALPHACOLOR) {144OGLPaints_SetColor(oglc, oglc->pixel);145}146}147148static jboolean149OGLVertexCache_InitMaskCache()150{151J2dTraceLn(J2D_TRACE_INFO, "OGLVertexCache_InitMaskCache");152153maskCacheTexID =154OGLContext_CreateBlitTexture(GL_INTENSITY8, GL_LUMINANCE,155OGLVC_MASK_CACHE_WIDTH_IN_TEXELS,156OGLVC_MASK_CACHE_HEIGHT_IN_TEXELS);157158// init special fully opaque tile in the upper-right corner of159// the mask cache texture160{161GLubyte allOnes[OGLVC_MASK_CACHE_TILE_SIZE];162memset(allOnes, 0xff, OGLVC_MASK_CACHE_TILE_SIZE);163j2d_glTexSubImage2D(GL_TEXTURE_2D, 0,164OGLVC_MASK_CACHE_SPECIAL_TILE_X,165OGLVC_MASK_CACHE_SPECIAL_TILE_Y,166OGLVC_MASK_CACHE_TILE_WIDTH,167OGLVC_MASK_CACHE_TILE_HEIGHT,168GL_LUMINANCE, GL_UNSIGNED_BYTE, allOnes);169}170171return JNI_TRUE;172}173174void175OGLVertexCache_EnableMaskCache(OGLContext *oglc)176{177J2dTraceLn(J2D_TRACE_INFO, "OGLVertexCache_EnableMaskCache");178179if (!OGLVertexCache_InitVertexCache(oglc)) {180return;181}182183if (maskCacheTexID == 0) {184if (!OGLVertexCache_InitMaskCache()) {185return;186}187}188189j2d_glEnable(GL_TEXTURE_2D);190j2d_glBindTexture(GL_TEXTURE_2D, maskCacheTexID);191OGLC_UPDATE_TEXTURE_FUNCTION(oglc, GL_MODULATE);192j2d_glPixelStorei(GL_UNPACK_ALIGNMENT, 1);193}194195void196OGLVertexCache_DisableMaskCache(OGLContext *oglc)197{198J2dTraceLn(J2D_TRACE_INFO, "OGLVertexCache_DisableMaskCache");199200OGLVertexCache_FlushVertexCache();201OGLVertexCache_RestoreColorState(oglc);202203j2d_glDisable(GL_TEXTURE_2D);204j2d_glPixelStorei(GL_UNPACK_ALIGNMENT, 4);205j2d_glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);206j2d_glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);207j2d_glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);208209maskCacheIndex = 0;210}211212void213OGLVertexCache_AddMaskQuad(OGLContext *oglc,214jint srcx, jint srcy,215jint dstx, jint dsty,216jint width, jint height,217jint maskscan, void *mask)218{219jfloat tx1, ty1, tx2, ty2;220jfloat dx1, dy1, dx2, dy2;221222J2dTraceLn1(J2D_TRACE_INFO, "OGLVertexCache_AddMaskQuad: %d",223maskCacheIndex);224225if (maskCacheIndex >= OGLVC_MASK_CACHE_MAX_INDEX ||226vertexCacheIndex >= OGLVC_MAX_INDEX)227{228OGLVertexCache_FlushVertexCache();229maskCacheIndex = 0;230}231232if (mask != NULL) {233jint texx = OGLVC_MASK_CACHE_TILE_WIDTH *234(maskCacheIndex % OGLVC_MASK_CACHE_WIDTH_IN_TILES);235jint texy = OGLVC_MASK_CACHE_TILE_HEIGHT *236(maskCacheIndex / OGLVC_MASK_CACHE_WIDTH_IN_TILES);237238// update the source pointer offsets239j2d_glPixelStorei(GL_UNPACK_SKIP_PIXELS, srcx);240j2d_glPixelStorei(GL_UNPACK_SKIP_ROWS, srcy);241j2d_glPixelStorei(GL_UNPACK_ROW_LENGTH, maskscan);242243// copy alpha mask into texture tile244j2d_glTexSubImage2D(GL_TEXTURE_2D, 0,245texx, texy, width, height,246GL_LUMINANCE, GL_UNSIGNED_BYTE, mask);247248tx1 = ((jfloat)texx) / OGLVC_MASK_CACHE_WIDTH_IN_TEXELS;249ty1 = ((jfloat)texy) / OGLVC_MASK_CACHE_HEIGHT_IN_TEXELS;250251maskCacheIndex++;252} else {253// use special fully opaque tile254tx1 = ((jfloat)OGLVC_MASK_CACHE_SPECIAL_TILE_X) /255OGLVC_MASK_CACHE_WIDTH_IN_TEXELS;256ty1 = ((jfloat)OGLVC_MASK_CACHE_SPECIAL_TILE_Y) /257OGLVC_MASK_CACHE_HEIGHT_IN_TEXELS;258}259260tx2 = tx1 + (((jfloat)width) / OGLVC_MASK_CACHE_WIDTH_IN_TEXELS);261ty2 = ty1 + (((jfloat)height) / OGLVC_MASK_CACHE_HEIGHT_IN_TEXELS);262263dx1 = (jfloat)dstx;264dy1 = (jfloat)dsty;265dx2 = dx1 + width;266dy2 = dy1 + height;267268OGLVC_ADD_QUAD(tx1, ty1, tx2, ty2,269dx1, dy1, dx2, dy2,270oglc->r, oglc->g, oglc->b, oglc->a);271}272273void274OGLVertexCache_AddGlyphQuad(OGLContext *oglc,275jfloat tx1, jfloat ty1, jfloat tx2, jfloat ty2,276jfloat dx1, jfloat dy1, jfloat dx2, jfloat dy2)277{278J2dTraceLn(J2D_TRACE_INFO, "OGLVertexCache_AddGlyphQuad");279280if (vertexCacheIndex >= OGLVC_MAX_INDEX) {281OGLVertexCache_FlushVertexCache();282}283284OGLVC_ADD_QUAD(tx1, ty1, tx2, ty2,285dx1, dy1, dx2, dy2,286oglc->r, oglc->g, oglc->b, oglc->a);287}288289#endif /* !HEADLESS */290291292