annotate src/share/native/sun/java2d/opengl/OGLContext.c @ 11015:5b49ef2244cf

8087201: OGL: rendering of lcd text is slow Reviewed-by: serb, prr
author bae
date Thu, 09 Jul 2015 18:28:54 +0300
parents cc67fbf19cfb
children
rev   line source
duke@0 1 /*
lana@9000 2 * Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved.
duke@0 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
duke@0 4 *
duke@0 5 * This code is free software; you can redistribute it and/or modify it
duke@0 6 * under the terms of the GNU General Public License version 2 only, as
ohair@2362 7 * published by the Free Software Foundation. Oracle designates this
duke@0 8 * particular file as subject to the "Classpath" exception as provided
ohair@2362 9 * by Oracle in the LICENSE file that accompanied this code.
duke@0 10 *
duke@0 11 * This code is distributed in the hope that it will be useful, but WITHOUT
duke@0 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
duke@0 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
duke@0 14 * version 2 for more details (a copy is included in the LICENSE file that
duke@0 15 * accompanied this code).
duke@0 16 *
duke@0 17 * You should have received a copy of the GNU General Public License version
duke@0 18 * 2 along with this work; if not, write to the Free Software Foundation,
duke@0 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
duke@0 20 *
ohair@2362 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
ohair@2362 22 * or visit www.oracle.com if you need additional information or have any
ohair@2362 23 * questions.
duke@0 24 */
duke@0 25
duke@0 26 #ifndef HEADLESS
duke@0 27
duke@0 28 #include <stdlib.h>
duke@0 29 #include <string.h>
duke@0 30
duke@0 31 #include "sun_java2d_SunGraphics2D.h"
duke@0 32
duke@0 33 #include "jlong.h"
duke@0 34 #include "jni_util.h"
duke@0 35 #include "OGLContext.h"
duke@0 36 #include "OGLRenderQueue.h"
duke@0 37 #include "OGLSurfaceData.h"
duke@0 38 #include "GraphicsPrimitiveMgr.h"
duke@0 39 #include "Region.h"
duke@0 40
duke@0 41 /**
duke@0 42 * The following methods are implemented in the windowing system (i.e. GLX
duke@0 43 * and WGL) source files.
duke@0 44 */
duke@0 45 extern jboolean OGLSD_InitOGLWindow(JNIEnv *env, OGLSDOps *oglsdo);
duke@0 46 extern OGLContext *OGLSD_MakeOGLContextCurrent(JNIEnv *env,
duke@0 47 OGLSDOps *srcOps,
duke@0 48 OGLSDOps *dstOps);
duke@0 49
duke@0 50 /**
duke@0 51 * This table contains the standard blending rules (or Porter-Duff compositing
duke@0 52 * factors) used in glBlendFunc(), indexed by the rule constants from the
duke@0 53 * AlphaComposite class.
duke@0 54 */
duke@0 55 OGLBlendRule StdBlendRules[] = {
duke@0 56 { GL_ZERO, GL_ZERO }, /* 0 - Nothing */
duke@0 57 { GL_ZERO, GL_ZERO }, /* 1 - RULE_Clear */
duke@0 58 { GL_ONE, GL_ZERO }, /* 2 - RULE_Src */
duke@0 59 { GL_ONE, GL_ONE_MINUS_SRC_ALPHA }, /* 3 - RULE_SrcOver */
duke@0 60 { GL_ONE_MINUS_DST_ALPHA, GL_ONE }, /* 4 - RULE_DstOver */
duke@0 61 { GL_DST_ALPHA, GL_ZERO }, /* 5 - RULE_SrcIn */
duke@0 62 { GL_ZERO, GL_SRC_ALPHA }, /* 6 - RULE_DstIn */
duke@0 63 { GL_ONE_MINUS_DST_ALPHA, GL_ZERO }, /* 7 - RULE_SrcOut */
duke@0 64 { GL_ZERO, GL_ONE_MINUS_SRC_ALPHA }, /* 8 - RULE_DstOut */
duke@0 65 { GL_ZERO, GL_ONE }, /* 9 - RULE_Dst */
duke@0 66 { GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA }, /*10 - RULE_SrcAtop */
duke@0 67 { GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA }, /*11 - RULE_DstAtop */
duke@0 68 { GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA }, /*12 - RULE_AlphaXor*/
duke@0 69 };
duke@0 70
duke@0 71 /** Evaluates to "front" or "back", depending on the value of buf. */
duke@0 72 #define OGLC_ACTIVE_BUFFER_NAME(buf) \
duke@0 73 (buf == GL_FRONT || buf == GL_COLOR_ATTACHMENT0_EXT) ? "front" : "back"
duke@0 74
duke@0 75 /**
duke@0 76 * Initializes the viewport and projection matrix, effectively positioning
duke@0 77 * the origin at the top-left corner of the surface. This allows Java 2D
duke@0 78 * coordinates to be passed directly to OpenGL, which is typically based on
duke@0 79 * a bottom-right coordinate system. This method also sets the appropriate
duke@0 80 * read and draw buffers.
duke@0 81 */
duke@0 82 static void
duke@0 83 OGLContext_SetViewport(OGLSDOps *srcOps, OGLSDOps *dstOps)
duke@0 84 {
duke@0 85 jint width = dstOps->width;
duke@0 86 jint height = dstOps->height;
duke@0 87
duke@0 88 J2dTraceLn4(J2D_TRACE_INFO,
duke@0 89 "OGLContext_SetViewport: w=%d h=%d read=%s draw=%s",
duke@0 90 width, height,
duke@0 91 OGLC_ACTIVE_BUFFER_NAME(srcOps->activeBuffer),
duke@0 92 OGLC_ACTIVE_BUFFER_NAME(dstOps->activeBuffer));
duke@0 93
duke@0 94 // set the viewport and projection matrix
duke@0 95 j2d_glViewport(dstOps->xOffset, dstOps->yOffset,
duke@0 96 (GLsizei)width, (GLsizei)height);
duke@0 97 j2d_glMatrixMode(GL_PROJECTION);
duke@0 98 j2d_glLoadIdentity();
duke@0 99 j2d_glOrtho(0.0, (GLdouble)width, (GLdouble)height, 0.0, -1.0, 1.0);
duke@0 100
duke@0 101 // set the active read and draw buffers
duke@0 102 j2d_glReadBuffer(srcOps->activeBuffer);
duke@0 103 j2d_glDrawBuffer(dstOps->activeBuffer);
duke@0 104
duke@0 105 // set the color mask to enable alpha channel only when necessary
duke@0 106 j2d_glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, (GLboolean)!dstOps->isOpaque);
duke@0 107 }
duke@0 108
duke@0 109 /**
duke@0 110 * Initializes the alpha channel of the current surface so that it contains
duke@0 111 * fully opaque alpha values.
duke@0 112 */
duke@0 113 static void
duke@0 114 OGLContext_InitAlphaChannel()
duke@0 115 {
duke@0 116 GLboolean scissorEnabled;
duke@0 117
duke@0 118 J2dTraceLn(J2D_TRACE_INFO, "OGLContext_InitAlphaChannel");
duke@0 119
duke@0 120 // it is possible for the scissor test to be enabled at this point;
duke@0 121 // if it is, disable it temporarily since it can affect the glClear() op
duke@0 122 scissorEnabled = j2d_glIsEnabled(GL_SCISSOR_TEST);
duke@0 123 if (scissorEnabled) {
duke@0 124 j2d_glDisable(GL_SCISSOR_TEST);
duke@0 125 }
duke@0 126
duke@0 127 // set the color mask so that we only affect the alpha channel
duke@0 128 j2d_glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE);
duke@0 129
duke@0 130 // clear the color buffer so that the alpha channel is fully opaque
duke@0 131 j2d_glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
duke@0 132 j2d_glClear(GL_COLOR_BUFFER_BIT);
duke@0 133
duke@0 134 // restore the color mask (as it was set in OGLContext_SetViewport())
duke@0 135 j2d_glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE);
duke@0 136
duke@0 137 // re-enable scissor test, only if it was enabled earlier
duke@0 138 if (scissorEnabled) {
duke@0 139 j2d_glEnable(GL_SCISSOR_TEST);
duke@0 140 }
duke@0 141 }
duke@0 142
duke@0 143 /**
duke@0 144 * Fetches the OGLContext associated with the given destination surface,
duke@0 145 * makes the context current for those surfaces, updates the destination
duke@0 146 * viewport, and then returns a pointer to the OGLContext.
duke@0 147 */
duke@0 148 OGLContext *
duke@0 149 OGLContext_SetSurfaces(JNIEnv *env, jlong pSrc, jlong pDst)
duke@0 150 {
duke@0 151 OGLSDOps *srcOps = (OGLSDOps *)jlong_to_ptr(pSrc);
duke@0 152 OGLSDOps *dstOps = (OGLSDOps *)jlong_to_ptr(pDst);
duke@0 153 OGLContext *oglc = NULL;
duke@0 154
duke@0 155 J2dTraceLn(J2D_TRACE_INFO, "OGLContext_SetSurfaces");
duke@0 156
duke@0 157 if (srcOps == NULL || dstOps == NULL) {
duke@0 158 J2dRlsTraceLn(J2D_TRACE_ERROR,
duke@0 159 "OGLContext_SetSurfaces: ops are null");
duke@0 160 return NULL;
duke@0 161 }
duke@0 162
duke@0 163 J2dTraceLn2(J2D_TRACE_VERBOSE, " srctype=%d dsttype=%d",
duke@0 164 srcOps->drawableType, dstOps->drawableType);
duke@0 165
duke@0 166 if (dstOps->drawableType == OGLSD_TEXTURE) {
duke@0 167 J2dRlsTraceLn(J2D_TRACE_ERROR,
duke@0 168 "OGLContext_SetSurfaces: texture cannot be used as destination");
duke@0 169 return NULL;
duke@0 170 }
duke@0 171
duke@0 172 if (dstOps->drawableType == OGLSD_UNDEFINED) {
duke@0 173 // initialize the surface as an OGLSD_WINDOW
duke@0 174 if (!OGLSD_InitOGLWindow(env, dstOps)) {
duke@0 175 J2dRlsTraceLn(J2D_TRACE_ERROR,
duke@0 176 "OGLContext_SetSurfaces: could not init OGL window");
duke@0 177 return NULL;
duke@0 178 }
duke@0 179 }
duke@0 180
duke@0 181 // make the context current
duke@0 182 oglc = OGLSD_MakeOGLContextCurrent(env, srcOps, dstOps);
duke@0 183 if (oglc == NULL) {
duke@0 184 J2dRlsTraceLn(J2D_TRACE_ERROR,
duke@0 185 "OGLContext_SetSurfaces: could not make context current");
duke@0 186 return NULL;
duke@0 187 }
duke@0 188
duke@0 189 // update the viewport
duke@0 190 OGLContext_SetViewport(srcOps, dstOps);
duke@0 191
duke@0 192 // perform additional one-time initialization, if necessary
duke@0 193 if (dstOps->needsInit) {
duke@0 194 if (dstOps->isOpaque) {
duke@0 195 // in this case we are treating the destination as opaque, but
duke@0 196 // to do so, first we need to ensure that the alpha channel
duke@0 197 // is filled with fully opaque values (see 6319663)
duke@0 198 OGLContext_InitAlphaChannel();
duke@0 199 }
duke@0 200 dstOps->needsInit = JNI_FALSE;
duke@0 201 }
duke@0 202
duke@0 203 return oglc;
duke@0 204 }
duke@0 205
duke@0 206 /**
duke@0 207 * Resets the current clip state (disables both scissor and depth tests).
duke@0 208 */
duke@0 209 void
duke@0 210 OGLContext_ResetClip(OGLContext *oglc)
duke@0 211 {
duke@0 212 J2dTraceLn(J2D_TRACE_INFO, "OGLContext_ResetClip");
duke@0 213
duke@0 214 RETURN_IF_NULL(oglc);
duke@0 215 CHECK_PREVIOUS_OP(OGL_STATE_CHANGE);
duke@0 216
duke@0 217 j2d_glDisable(GL_SCISSOR_TEST);
duke@0 218 j2d_glDisable(GL_DEPTH_TEST);
duke@0 219 }
duke@0 220
duke@0 221 /**
duke@0 222 * Sets the OpenGL scissor bounds to the provided rectangular clip bounds.
duke@0 223 */
duke@0 224 void
duke@0 225 OGLContext_SetRectClip(OGLContext *oglc, OGLSDOps *dstOps,
duke@0 226 jint x1, jint y1, jint x2, jint y2)
duke@0 227 {
duke@0 228 jint width = x2 - x1;
duke@0 229 jint height = y2 - y1;
duke@0 230
duke@0 231 J2dTraceLn4(J2D_TRACE_INFO,
duke@0 232 "OGLContext_SetRectClip: x=%d y=%d w=%d h=%d",
duke@0 233 x1, y1, width, height);
duke@0 234
duke@0 235 RETURN_IF_NULL(dstOps);
duke@0 236 RETURN_IF_NULL(oglc);
duke@0 237 CHECK_PREVIOUS_OP(OGL_STATE_CHANGE);
duke@0 238
duke@0 239 if ((width < 0) || (height < 0)) {
duke@0 240 // use an empty scissor rectangle when the region is empty
duke@0 241 width = 0;
duke@0 242 height = 0;
duke@0 243 }
duke@0 244
duke@0 245 j2d_glDisable(GL_DEPTH_TEST);
duke@0 246 j2d_glEnable(GL_SCISSOR_TEST);
duke@0 247
duke@0 248 // the scissor rectangle is specified using the lower-left
duke@0 249 // origin of the clip region (in the framebuffer's coordinate
duke@0 250 // space), so we must account for the x/y offsets of the
duke@0 251 // destination surface
duke@0 252 j2d_glScissor(dstOps->xOffset + x1,
duke@0 253 dstOps->yOffset + dstOps->height - (y1 + height),
duke@0 254 width, height);
duke@0 255 }
duke@0 256
duke@0 257 /**
duke@0 258 * Sets up a complex (shape) clip using the OpenGL depth buffer. This
duke@0 259 * method prepares the depth buffer so that the clip Region spans can
duke@0 260 * be "rendered" into it. The depth buffer is first cleared, then the
duke@0 261 * depth func is setup so that when we render the clip spans,
duke@0 262 * nothing is rendered into the color buffer, but for each pixel that would
duke@0 263 * be rendered, a non-zero value is placed into that location in the depth
duke@0 264 * buffer. With depth test enabled, pixels will only be rendered into the
duke@0 265 * color buffer if the corresponding value at that (x,y) location in the
duke@0 266 * depth buffer differs from the incoming depth value.
duke@0 267 */
duke@0 268 void
duke@0 269 OGLContext_BeginShapeClip(OGLContext *oglc)
duke@0 270 {
duke@0 271 J2dTraceLn(J2D_TRACE_INFO, "OGLContext_BeginShapeClip");
duke@0 272
duke@0 273 RETURN_IF_NULL(oglc);
duke@0 274 RESET_PREVIOUS_OP();
duke@0 275
duke@0 276 j2d_glDisable(GL_SCISSOR_TEST);
duke@0 277
duke@0 278 // enable depth test and clear depth buffer so that depth values are at
duke@0 279 // their maximum; also set the depth func to GL_ALWAYS so that the
duke@0 280 // depth values of the clip spans are forced into the depth buffer
duke@0 281 j2d_glEnable(GL_DEPTH_TEST);
duke@0 282 j2d_glClearDepth(1.0);
duke@0 283 j2d_glClear(GL_DEPTH_BUFFER_BIT);
duke@0 284 j2d_glDepthFunc(GL_ALWAYS);
duke@0 285
duke@0 286 // disable writes into the color buffer while we set up the clip
duke@0 287 j2d_glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
duke@0 288
duke@0 289 // save current transform
duke@0 290 j2d_glMatrixMode(GL_MODELVIEW);
duke@0 291 j2d_glPushMatrix();
duke@0 292
duke@0 293 // use identity transform plus slight translation in the z-axis when
duke@0 294 // setting the clip spans; this will push the clip spans (which would
duke@0 295 // normally be at z=0) to the z=1 plane to give them some depth
duke@0 296 j2d_glLoadIdentity();
duke@0 297 j2d_glTranslatef(0.0f, 0.0f, 1.0f);
duke@0 298 }
duke@0 299
duke@0 300 /**
duke@0 301 * Finishes setting up the shape clip by resetting the depth func
duke@0 302 * so that future rendering operations will once again be written into the
duke@0 303 * color buffer (while respecting the clip set up in the depth buffer).
duke@0 304 */
duke@0 305 void
duke@0 306 OGLContext_EndShapeClip(OGLContext *oglc, OGLSDOps *dstOps)
duke@0 307 {
duke@0 308 J2dTraceLn(J2D_TRACE_INFO, "OGLContext_EndShapeClip");
duke@0 309
duke@0 310 RETURN_IF_NULL(dstOps);
duke@0 311 RETURN_IF_NULL(oglc);
duke@0 312 RESET_PREVIOUS_OP();
duke@0 313
duke@0 314 // restore transform
duke@0 315 j2d_glPopMatrix();
duke@0 316
duke@0 317 // re-enable writes into the color buffer
duke@0 318 j2d_glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, (GLboolean)!dstOps->isOpaque);
duke@0 319
duke@0 320 // enable the depth test so that only fragments within the clip region
duke@0 321 // (i.e. those fragments whose z-values are >= the values currently
duke@0 322 // stored in the depth buffer) are rendered
duke@0 323 j2d_glDepthFunc(GL_GEQUAL);
duke@0 324 }
duke@0 325
duke@0 326 /**
duke@0 327 * Initializes the OpenGL state responsible for applying extra alpha. This
duke@0 328 * step is only necessary for any operation that uses glDrawPixels() or
duke@0 329 * glCopyPixels() with a non-1.0f extra alpha value. Since the source is
duke@0 330 * always premultiplied, we apply the extra alpha value to both alpha and
duke@0 331 * color components using GL_*_SCALE.
duke@0 332 */
duke@0 333 void
duke@0 334 OGLContext_SetExtraAlpha(jfloat ea)
duke@0 335 {
duke@0 336 J2dTraceLn1(J2D_TRACE_INFO, "OGLContext_SetExtraAlpha: ea=%f", ea);
duke@0 337
duke@0 338 j2d_glPixelTransferf(GL_ALPHA_SCALE, ea);
duke@0 339 j2d_glPixelTransferf(GL_RED_SCALE, ea);
duke@0 340 j2d_glPixelTransferf(GL_GREEN_SCALE, ea);
duke@0 341 j2d_glPixelTransferf(GL_BLUE_SCALE, ea);
duke@0 342 }
duke@0 343
duke@0 344 /**
duke@0 345 * Resets all OpenGL compositing state (disables blending and logic
duke@0 346 * operations).
duke@0 347 */
duke@0 348 void
duke@0 349 OGLContext_ResetComposite(OGLContext *oglc)
duke@0 350 {
duke@0 351 J2dTraceLn(J2D_TRACE_INFO, "OGLContext_ResetComposite");
duke@0 352
duke@0 353 RETURN_IF_NULL(oglc);
duke@0 354 CHECK_PREVIOUS_OP(OGL_STATE_CHANGE);
duke@0 355
duke@0 356 // disable blending and XOR mode
duke@0 357 if (oglc->compState == sun_java2d_SunGraphics2D_COMP_ALPHA) {
duke@0 358 j2d_glDisable(GL_BLEND);
duke@0 359 } else if (oglc->compState == sun_java2d_SunGraphics2D_COMP_XOR) {
duke@0 360 j2d_glDisable(GL_COLOR_LOGIC_OP);
duke@0 361 j2d_glDisable(GL_ALPHA_TEST);
duke@0 362 }
duke@0 363
duke@0 364 // set state to default values
duke@0 365 oglc->compState = sun_java2d_SunGraphics2D_COMP_ISCOPY;
duke@0 366 oglc->extraAlpha = 1.0f;
duke@0 367 }
duke@0 368
duke@0 369 /**
duke@0 370 * Initializes the OpenGL blending state. XOR mode is disabled and the
duke@0 371 * appropriate blend functions are setup based on the AlphaComposite rule
duke@0 372 * constant.
duke@0 373 */
duke@0 374 void
duke@0 375 OGLContext_SetAlphaComposite(OGLContext *oglc,
duke@0 376 jint rule, jfloat extraAlpha, jint flags)
duke@0 377 {
duke@0 378 J2dTraceLn1(J2D_TRACE_INFO,
duke@0 379 "OGLContext_SetAlphaComposite: flags=%d", flags);
duke@0 380
duke@0 381 RETURN_IF_NULL(oglc);
duke@0 382 CHECK_PREVIOUS_OP(OGL_STATE_CHANGE);
duke@0 383
duke@0 384 // disable XOR mode
duke@0 385 if (oglc->compState == sun_java2d_SunGraphics2D_COMP_XOR) {
duke@0 386 j2d_glDisable(GL_COLOR_LOGIC_OP);
duke@0 387 j2d_glDisable(GL_ALPHA_TEST);
duke@0 388 }
duke@0 389
duke@0 390 // we can safely disable blending when:
duke@0 391 // - comp is SrcNoEa or SrcOverNoEa, and
duke@0 392 // - the source is opaque
duke@0 393 // (turning off blending can have a large positive impact on
duke@0 394 // performance)
duke@0 395 if ((rule == RULE_Src || rule == RULE_SrcOver) &&
duke@0 396 (extraAlpha == 1.0f) &&
duke@0 397 (flags & OGLC_SRC_IS_OPAQUE))
duke@0 398 {
duke@0 399 J2dTraceLn1(J2D_TRACE_VERBOSE,
duke@0 400 " disabling alpha comp: rule=%d ea=1.0 src=opq", rule);
duke@0 401 j2d_glDisable(GL_BLEND);
duke@0 402 } else {
duke@0 403 J2dTraceLn2(J2D_TRACE_VERBOSE,
duke@0 404 " enabling alpha comp: rule=%d ea=%f", rule, extraAlpha);
duke@0 405 j2d_glEnable(GL_BLEND);
duke@0 406 j2d_glBlendFunc(StdBlendRules[rule].src, StdBlendRules[rule].dst);
duke@0 407 }
duke@0 408
duke@0 409 // update state
duke@0 410 oglc->compState = sun_java2d_SunGraphics2D_COMP_ALPHA;
duke@0 411 oglc->extraAlpha = extraAlpha;
duke@0 412 }
duke@0 413
duke@0 414 /**
duke@0 415 * Initializes the OpenGL logic op state to XOR mode. Blending is disabled
duke@0 416 * before enabling logic op mode. The XOR pixel value will be applied
duke@0 417 * later in the OGLContext_SetColor() method.
duke@0 418 */
duke@0 419 void
duke@0 420 OGLContext_SetXorComposite(OGLContext *oglc, jint xorPixel)
duke@0 421 {
duke@0 422 J2dTraceLn1(J2D_TRACE_INFO,
duke@0 423 "OGLContext_SetXorComposite: xorPixel=%08x", xorPixel);
duke@0 424
duke@0 425 RETURN_IF_NULL(oglc);
duke@0 426 CHECK_PREVIOUS_OP(OGL_STATE_CHANGE);
duke@0 427
duke@0 428 // disable blending mode
duke@0 429 if (oglc->compState == sun_java2d_SunGraphics2D_COMP_ALPHA) {
duke@0 430 j2d_glDisable(GL_BLEND);
duke@0 431 }
duke@0 432
duke@0 433 // enable XOR mode
duke@0 434 j2d_glEnable(GL_COLOR_LOGIC_OP);
duke@0 435 j2d_glLogicOp(GL_XOR);
duke@0 436
duke@0 437 // set up the alpha test so that we discard transparent fragments (this
duke@0 438 // is primarily useful for rendering text in XOR mode)
duke@0 439 j2d_glEnable(GL_ALPHA_TEST);
duke@0 440 j2d_glAlphaFunc(GL_NOTEQUAL, 0.0f);
duke@0 441
duke@0 442 // update state
duke@0 443 oglc->compState = sun_java2d_SunGraphics2D_COMP_XOR;
duke@0 444 oglc->xorPixel = xorPixel;
duke@0 445 oglc->extraAlpha = 1.0f;
duke@0 446 }
duke@0 447
duke@0 448 /**
duke@0 449 * Resets the OpenGL transform state back to the identity matrix.
duke@0 450 */
duke@0 451 void
duke@0 452 OGLContext_ResetTransform(OGLContext *oglc)
duke@0 453 {
duke@0 454 J2dTraceLn(J2D_TRACE_INFO, "OGLContext_ResetTransform");
duke@0 455
duke@0 456 RETURN_IF_NULL(oglc);
duke@0 457 CHECK_PREVIOUS_OP(OGL_STATE_CHANGE);
duke@0 458
duke@0 459 j2d_glMatrixMode(GL_MODELVIEW);
duke@0 460 j2d_glLoadIdentity();
duke@0 461 }
duke@0 462
duke@0 463 /**
duke@0 464 * Initializes the OpenGL transform state by setting the modelview transform
duke@0 465 * using the given matrix parameters.
duke@0 466 *
duke@0 467 * REMIND: it may be worthwhile to add serial id to AffineTransform, so we
duke@0 468 * could do a quick check to see if the xform has changed since
duke@0 469 * last time... a simple object compare won't suffice...
duke@0 470 */
duke@0 471 void
duke@0 472 OGLContext_SetTransform(OGLContext *oglc,
duke@0 473 jdouble m00, jdouble m10,
duke@0 474 jdouble m01, jdouble m11,
duke@0 475 jdouble m02, jdouble m12)
duke@0 476 {
duke@0 477 J2dTraceLn(J2D_TRACE_INFO, "OGLContext_SetTransform");
duke@0 478
duke@0 479 RETURN_IF_NULL(oglc);
duke@0 480 CHECK_PREVIOUS_OP(OGL_STATE_CHANGE);
duke@0 481
duke@0 482 if (oglc->xformMatrix == NULL) {
duke@0 483 size_t arrsize = 16 * sizeof(GLdouble);
duke@0 484 oglc->xformMatrix = (GLdouble *)malloc(arrsize);
duke@0 485 memset(oglc->xformMatrix, 0, arrsize);
duke@0 486 oglc->xformMatrix[10] = 1.0;
duke@0 487 oglc->xformMatrix[15] = 1.0;
duke@0 488 }
duke@0 489
duke@0 490 // copy values from AffineTransform object into native matrix array
duke@0 491 oglc->xformMatrix[0] = m00;
duke@0 492 oglc->xformMatrix[1] = m10;
duke@0 493 oglc->xformMatrix[4] = m01;
duke@0 494 oglc->xformMatrix[5] = m11;
duke@0 495 oglc->xformMatrix[12] = m02;
duke@0 496 oglc->xformMatrix[13] = m12;
duke@0 497
duke@0 498 J2dTraceLn3(J2D_TRACE_VERBOSE, " [%lf %lf %lf]",
duke@0 499 oglc->xformMatrix[0], oglc->xformMatrix[4],
duke@0 500 oglc->xformMatrix[12]);
duke@0 501 J2dTraceLn3(J2D_TRACE_VERBOSE, " [%lf %lf %lf]",
duke@0 502 oglc->xformMatrix[1], oglc->xformMatrix[5],
duke@0 503 oglc->xformMatrix[13]);
duke@0 504
duke@0 505 j2d_glMatrixMode(GL_MODELVIEW);
duke@0 506 j2d_glLoadMatrixd(oglc->xformMatrix);
duke@0 507 }
duke@0 508
duke@0 509 /**
duke@0 510 * Creates a 2D texture of the given format and dimensions and returns the
duke@0 511 * texture object identifier. This method is typically used to create a
duke@0 512 * temporary texture for intermediate work, such as in the
duke@0 513 * OGLContext_InitBlitTileTexture() method below.
duke@0 514 */
duke@0 515 GLuint
duke@0 516 OGLContext_CreateBlitTexture(GLenum internalFormat, GLenum pixelFormat,
duke@0 517 GLuint width, GLuint height)
duke@0 518 {
duke@0 519 GLuint texID;
duke@0 520 GLint sp, sr, rl, align;
duke@0 521 GLclampf priority = 1.0f;
duke@0 522
duke@0 523 J2dTraceLn(J2D_TRACE_INFO, "OGLContext_CreateBlitTexture");
duke@0 524
duke@0 525 j2d_glGenTextures(1, &texID);
duke@0 526 j2d_glBindTexture(GL_TEXTURE_2D, texID);
duke@0 527 j2d_glPrioritizeTextures(1, &texID, &priority);
duke@0 528 j2d_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
duke@0 529 j2d_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
duke@0 530 OGLSD_RESET_TEXTURE_WRAP(GL_TEXTURE_2D);
duke@0 531
duke@0 532 // save pixel store parameters (since this method could be invoked after
duke@0 533 // the caller has already set up its pixel store parameters)
duke@0 534 j2d_glGetIntegerv(GL_UNPACK_SKIP_PIXELS, &sp);
duke@0 535 j2d_glGetIntegerv(GL_UNPACK_SKIP_ROWS, &sr);
duke@0 536 j2d_glGetIntegerv(GL_UNPACK_ROW_LENGTH, &rl);
duke@0 537 j2d_glGetIntegerv(GL_UNPACK_ALIGNMENT, &align);
duke@0 538
duke@0 539 // set pixel store parameters to default values
duke@0 540 j2d_glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
duke@0 541 j2d_glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
duke@0 542 j2d_glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
duke@0 543 j2d_glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
duke@0 544
duke@0 545 j2d_glTexImage2D(GL_TEXTURE_2D, 0, internalFormat,
duke@0 546 width, height, 0,
duke@0 547 pixelFormat, GL_UNSIGNED_BYTE, NULL);
duke@0 548
duke@0 549 // restore pixel store parameters
duke@0 550 j2d_glPixelStorei(GL_UNPACK_SKIP_PIXELS, sp);
duke@0 551 j2d_glPixelStorei(GL_UNPACK_SKIP_ROWS, sr);
duke@0 552 j2d_glPixelStorei(GL_UNPACK_ROW_LENGTH, rl);
duke@0 553 j2d_glPixelStorei(GL_UNPACK_ALIGNMENT, align);
duke@0 554
duke@0 555 return texID;
duke@0 556 }
duke@0 557
duke@0 558 /**
duke@0 559 * Initializes a small texture tile for use with tiled blit operations (see
duke@0 560 * OGLBlitLoops.c and OGLMaskBlit.c for usage examples). The texture ID for
duke@0 561 * the tile is stored in the given OGLContext. The tile is initially filled
duke@0 562 * with garbage values, but the tile is updated as needed (via
duke@0 563 * glTexSubImage2D()) with real RGBA values used in tiled blit situations.
duke@0 564 * The internal format for the texture is GL_RGBA8, which should be sufficient
duke@0 565 * for storing system memory surfaces of any known format (see PixelFormats
duke@0 566 * for a list of compatible surface formats).
duke@0 567 */
duke@0 568 jboolean
duke@0 569 OGLContext_InitBlitTileTexture(OGLContext *oglc)
duke@0 570 {
duke@0 571 J2dTraceLn(J2D_TRACE_INFO, "OGLContext_InitBlitTileTexture");
duke@0 572
duke@0 573 oglc->blitTextureID =
duke@0 574 OGLContext_CreateBlitTexture(GL_RGBA8, GL_RGBA,
duke@0 575 OGLC_BLIT_TILE_SIZE,
duke@0 576 OGLC_BLIT_TILE_SIZE);
duke@0 577
duke@0 578 return JNI_TRUE;
duke@0 579 }
duke@0 580
duke@0 581 /**
duke@0 582 * Destroys the OpenGL resources associated with the given OGLContext.
duke@0 583 * It is required that the native context associated with the OGLContext
duke@0 584 * be made current prior to calling this method.
duke@0 585 */
duke@0 586 void
duke@0 587 OGLContext_DestroyContextResources(OGLContext *oglc)
duke@0 588 {
duke@0 589 J2dTraceLn(J2D_TRACE_INFO, "OGLContext_DestroyContextResources");
duke@0 590
duke@0 591 if (oglc->xformMatrix != NULL) {
duke@0 592 free(oglc->xformMatrix);
duke@0 593 }
duke@0 594
duke@0 595 if (oglc->blitTextureID != 0) {
duke@0 596 j2d_glDeleteTextures(1, &oglc->blitTextureID);
duke@0 597 }
duke@0 598 }
duke@0 599
duke@0 600 /**
duke@0 601 * Returns JNI_TRUE if the given extension name is available for the current
duke@0 602 * GraphicsConfig; JNI_FALSE otherwise. An extension is considered available
duke@0 603 * if its identifier string is found amongst the space-delimited GL_EXTENSIONS
duke@0 604 * string.
duke@0 605 *
duke@0 606 * Adapted from the OpenGL Red Book, pg. 506.
duke@0 607 */
duke@0 608 jboolean
duke@0 609 OGLContext_IsExtensionAvailable(const char *extString, char *extName)
duke@0 610 {
duke@0 611 jboolean ret = JNI_FALSE;
duke@0 612 char *p = (char *)extString;
duke@0 613 char *end;
duke@0 614
duke@0 615 if (extString == NULL) {
duke@0 616 J2dTraceLn(J2D_TRACE_INFO, "OGLContext_IsExtensionAvailable");
duke@0 617 J2dRlsTraceLn(J2D_TRACE_ERROR,
duke@0 618 "OGLContext_IsExtensionAvailable: extension string is null");
duke@0 619 return JNI_FALSE;
duke@0 620 }
duke@0 621
duke@0 622 end = p + strlen(p);
duke@0 623
duke@0 624 while (p < end) {
duke@0 625 size_t n = strcspn(p, " ");
duke@0 626
duke@0 627 if ((strlen(extName) == n) && (strncmp(extName, p, n) == 0)) {
duke@0 628 ret = JNI_TRUE;
duke@0 629 break;
duke@0 630 }
duke@0 631
duke@0 632 p += (n + 1);
duke@0 633 }
duke@0 634
duke@0 635 J2dRlsTraceLn2(J2D_TRACE_INFO,
duke@0 636 "OGLContext_IsExtensionAvailable: %s=%s",
duke@0 637 extName, ret ? "true" : "false");
duke@0 638
duke@0 639 return ret;
duke@0 640 }
duke@0 641
duke@0 642 /**
duke@0 643 * Returns JNI_TRUE only if all of the following conditions are met:
duke@0 644 * - the GL_EXT_framebuffer_object extension is available
duke@0 645 * - FBO support has been enabled via the system property
duke@0 646 * - we can successfully create an FBO with depth capabilities
duke@0 647 */
duke@0 648 static jboolean
duke@0 649 OGLContext_IsFBObjectExtensionAvailable(JNIEnv *env,
duke@0 650 const char *extString)
duke@0 651 {
duke@0 652 jboolean isFBObjectEnabled = JNI_FALSE;
duke@0 653 GLuint fbobjectID, textureID, depthID;
duke@0 654 jint width = 1, height = 1;
duke@0 655
duke@0 656 J2dTraceLn(J2D_TRACE_INFO, "OGLContext_IsFBObjectExtensionAvailable");
duke@0 657
duke@0 658 // first see if the fbobject extension is available
duke@0 659 if (!OGLContext_IsExtensionAvailable(extString,
duke@0 660 "GL_EXT_framebuffer_object"))
duke@0 661 {
duke@0 662 return JNI_FALSE;
duke@0 663 }
duke@0 664
vadim@7514 665 // next see if the depth texture extension is available
vadim@7514 666 if (!OGLContext_IsExtensionAvailable(extString,
vadim@7514 667 "GL_ARB_depth_texture"))
vadim@7514 668 {
vadim@7514 669 return JNI_FALSE;
vadim@7514 670 }
vadim@7514 671
duke@0 672 // next see if the fbobject system property has been enabled
duke@0 673 isFBObjectEnabled =
duke@0 674 JNU_GetStaticFieldByName(env, NULL,
duke@0 675 "sun/java2d/opengl/OGLSurfaceData",
duke@0 676 "isFBObjectEnabled", "Z").z;
duke@0 677 if (!isFBObjectEnabled) {
duke@0 678 J2dRlsTraceLn(J2D_TRACE_INFO,
duke@0 679 "OGLContext_IsFBObjectExtensionAvailable: disabled via flag");
duke@0 680 return JNI_FALSE;
duke@0 681 }
duke@0 682
duke@0 683 // finally, create a dummy fbobject with depth capabilities to see
duke@0 684 // if this configuration is supported by the drivers/hardware
duke@0 685 // (first we initialize a color texture object that will be used to
duke@0 686 // construct the dummy fbobject)
duke@0 687 j2d_glGenTextures(1, &textureID);
duke@0 688 j2d_glBindTexture(GL_TEXTURE_2D, textureID);
duke@0 689 j2d_glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,
duke@0 690 width, height, 0,
duke@0 691 GL_RGB, GL_UNSIGNED_BYTE, NULL);
duke@0 692 j2d_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
duke@0 693 j2d_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
duke@0 694
duke@0 695 // initialize framebuffer object using color texture created above
duke@0 696 if (!OGLSD_InitFBObject(&fbobjectID, &depthID,
duke@0 697 textureID, GL_TEXTURE_2D,
duke@0 698 width, height))
duke@0 699 {
duke@0 700 J2dRlsTraceLn(J2D_TRACE_INFO,
duke@0 701 "OGLContext_IsFBObjectExtensionAvailable: fbobject unsupported");
duke@0 702 j2d_glDeleteTextures(1, &textureID);
duke@0 703 return JNI_FALSE;
duke@0 704 }
duke@0 705
duke@0 706 // delete the temporary resources
duke@0 707 j2d_glDeleteTextures(1, &textureID);
duke@0 708 j2d_glDeleteRenderbuffersEXT(1, &depthID);
duke@0 709 j2d_glDeleteFramebuffersEXT(1, &fbobjectID);
duke@0 710
duke@0 711 J2dRlsTraceLn(J2D_TRACE_INFO,
duke@0 712 "OGLContext_IsFBObjectExtensionAvailable: fbobject supported");
duke@0 713
duke@0 714 return JNI_TRUE;
duke@0 715 }
duke@0 716
duke@0 717 /**
duke@0 718 * Returns JNI_TRUE only if all of the following conditions are met:
duke@0 719 * - the GL_ARB_fragment_shader extension is available
duke@0 720 * - the LCD text shader codepath has been enabled via the system property
duke@0 721 * - the hardware supports the minimum number of texture units
duke@0 722 */
duke@0 723 static jboolean
duke@0 724 OGLContext_IsLCDShaderSupportAvailable(JNIEnv *env,
duke@0 725 jboolean fragShaderAvailable)
duke@0 726 {
duke@0 727 jboolean isLCDShaderEnabled = JNI_FALSE;
duke@0 728 GLint maxTexUnits;
duke@0 729
duke@0 730 J2dTraceLn(J2D_TRACE_INFO, "OGLContext_IsLCDShaderSupportAvailable");
duke@0 731
duke@0 732 // first see if the fragment shader extension is available
duke@0 733 if (!fragShaderAvailable) {
duke@0 734 return JNI_FALSE;
duke@0 735 }
duke@0 736
duke@0 737 // next see if the lcdshader system property has been enabled
duke@0 738 isLCDShaderEnabled =
duke@0 739 JNU_GetStaticFieldByName(env, NULL,
duke@0 740 "sun/java2d/opengl/OGLSurfaceData",
duke@0 741 "isLCDShaderEnabled", "Z").z;
duke@0 742 if (!isLCDShaderEnabled) {
duke@0 743 J2dRlsTraceLn(J2D_TRACE_INFO,
duke@0 744 "OGLContext_IsLCDShaderSupportAvailable: disabled via flag");
duke@0 745 return JNI_FALSE;
duke@0 746 }
duke@0 747
duke@0 748 // finally, check to see if the hardware supports the required number
duke@0 749 // of texture units
duke@0 750 j2d_glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS_ARB, &maxTexUnits);
bae@10910 751 if (maxTexUnits < 2) {
duke@0 752 J2dRlsTraceLn1(J2D_TRACE_INFO,
duke@0 753 "OGLContext_IsLCDShaderSupportAvailable: not enough tex units (%d)",
duke@0 754 maxTexUnits);
duke@0 755 }
duke@0 756
duke@0 757 J2dRlsTraceLn(J2D_TRACE_INFO,
duke@0 758 "OGLContext_IsLCDShaderSupportAvailable: LCD text shader supported");
duke@0 759
duke@0 760 return JNI_TRUE;
duke@0 761 }
duke@0 762
duke@0 763 /**
duke@0 764 * Returns JNI_TRUE only if all of the following conditions are met:
duke@0 765 * - the GL_ARB_fragment_shader extension is available
duke@0 766 * - the BufferedImageOp shader codepath has been enabled via the
duke@0 767 * system property
duke@0 768 */
duke@0 769 static jboolean
duke@0 770 OGLContext_IsBIOpShaderSupportAvailable(JNIEnv *env,
duke@0 771 jboolean fragShaderAvailable)
duke@0 772 {
duke@0 773 jboolean isBIOpShaderEnabled = JNI_FALSE;
duke@0 774
duke@0 775 J2dTraceLn(J2D_TRACE_INFO, "OGLContext_IsBIOpShaderSupportAvailable");
duke@0 776
duke@0 777 // first see if the fragment shader extension is available
duke@0 778 if (!fragShaderAvailable) {
duke@0 779 return JNI_FALSE;
duke@0 780 }
duke@0 781
duke@0 782 // next see if the biopshader system property has been enabled
duke@0 783 isBIOpShaderEnabled =
duke@0 784 JNU_GetStaticFieldByName(env, NULL,
duke@0 785 "sun/java2d/opengl/OGLSurfaceData",
duke@0 786 "isBIOpShaderEnabled", "Z").z;
duke@0 787 if (!isBIOpShaderEnabled) {
duke@0 788 J2dRlsTraceLn(J2D_TRACE_INFO,
duke@0 789 "OGLContext_IsBIOpShaderSupportAvailable: disabled via flag");
duke@0 790 return JNI_FALSE;
duke@0 791 }
duke@0 792
duke@0 793 /*
duke@0 794 * Note: In theory we should probably do some other checks here, like
duke@0 795 * linking a sample shader to see if the hardware truly supports our
duke@0 796 * shader programs. However, our current BufferedImageOp shaders were
duke@0 797 * designed to support first-generation shader-level hardware, so the
duke@0 798 * assumption is that if our shaders work on those GPUs, then they'll
duke@0 799 * work on newer ones as well. Also, linking a fragment program can
duke@0 800 * cost valuable CPU cycles, which is another reason to avoid these
duke@0 801 * checks at startup.
duke@0 802 */
duke@0 803
duke@0 804 J2dRlsTraceLn(J2D_TRACE_INFO,
duke@0 805 "OGLContext_IsBIOpShaderSupportAvailable: BufferedImageOp shader supported");
duke@0 806
duke@0 807 return JNI_TRUE;
duke@0 808 }
duke@0 809
duke@0 810 /**
duke@0 811 * Returns JNI_TRUE only if all of the following conditions are met:
duke@0 812 * - the GL_ARB_fragment_shader extension is available
duke@0 813 * - the Linear/RadialGradientPaint shader codepath has been enabled via the
duke@0 814 * system property
duke@0 815 */
duke@0 816 static jboolean
duke@0 817 OGLContext_IsGradShaderSupportAvailable(JNIEnv *env,
duke@0 818 jboolean fragShaderAvailable)
duke@0 819 {
duke@0 820 jboolean isGradShaderEnabled = JNI_FALSE;
duke@0 821
duke@0 822 J2dTraceLn(J2D_TRACE_INFO, "OGLContext_IsGradShaderSupportAvailable");
duke@0 823
duke@0 824 // first see if the fragment shader extension is available
duke@0 825 if (!fragShaderAvailable) {
duke@0 826 return JNI_FALSE;
duke@0 827 }
duke@0 828
duke@0 829 // next see if the gradshader system property has been enabled
duke@0 830 isGradShaderEnabled =
duke@0 831 JNU_GetStaticFieldByName(env, NULL,
duke@0 832 "sun/java2d/opengl/OGLSurfaceData",
duke@0 833 "isGradShaderEnabled", "Z").z;
duke@0 834 if (!isGradShaderEnabled) {
duke@0 835 J2dRlsTraceLn(J2D_TRACE_INFO,
duke@0 836 "OGLContext_IsGradShaderSupportAvailable: disabled via flag");
duke@0 837 return JNI_FALSE;
duke@0 838 }
duke@0 839
duke@0 840 J2dRlsTraceLn(J2D_TRACE_INFO,
duke@0 841 "OGLContext_IsGradShaderSupportAvailable: Linear/RadialGradientPaint shader supported");
duke@0 842
duke@0 843 return JNI_TRUE;
duke@0 844 }
duke@0 845
duke@0 846 /**
duke@0 847 * Checks for the presence of the optional extensions used by
duke@0 848 * the Java 2D OpenGL pipeline. The given caps bitfield is updated
duke@0 849 * to reflect the availability of these extensions.
duke@0 850 */
duke@0 851 void
duke@0 852 OGLContext_GetExtensionInfo(JNIEnv *env, jint *caps)
duke@0 853 {
duke@0 854 jint vcap = OGLC_VENDOR_OTHER;
duke@0 855 const char *vendor = (char *)j2d_glGetString(GL_VENDOR);
duke@0 856 const char *e = (char *)j2d_glGetString(GL_EXTENSIONS);
duke@0 857 jboolean fragShaderAvail =
duke@0 858 OGLContext_IsExtensionAvailable(e, "GL_ARB_fragment_shader");
duke@0 859
duke@0 860 J2dTraceLn(J2D_TRACE_INFO, "OGLContext_GetExtensionInfo");
duke@0 861
tdv@430 862 *caps |= CAPS_TEXNONSQUARE;
duke@0 863 if (OGLContext_IsExtensionAvailable(e, "GL_ARB_multitexture")) {
tdv@430 864 *caps |= CAPS_MULTITEXTURE;
duke@0 865 }
duke@0 866 if (OGLContext_IsExtensionAvailable(e, "GL_ARB_texture_non_power_of_two")){
tdv@430 867 *caps |= CAPS_TEXNONPOW2;
duke@0 868 }
tdv@430 869 // 6656574: Use of the GL_ARB_texture_rectangle extension by Java 2D
tdv@430 870 // complicates any third-party libraries that try to interact with
tdv@430 871 // the OGL pipeline (and we've run into driver bugs in the past related
tdv@430 872 // to this extension), so for now we will disable its use by default (unless
tdv@430 873 // forced). We will still make use of the GL_ARB_texture_non_power_of_two
tdv@430 874 // extension when available, which is the better choice going forward
tdv@430 875 // anyway.
tdv@430 876 if (OGLContext_IsExtensionAvailable(e, "GL_ARB_texture_rectangle") &&
tdv@430 877 getenv("J2D_OGL_TEXRECT") != NULL)
tdv@430 878 {
tdv@430 879 *caps |= CAPS_EXT_TEXRECT;
duke@0 880 }
duke@0 881 if (OGLContext_IsFBObjectExtensionAvailable(env, e)) {
tdv@430 882 *caps |= CAPS_EXT_FBOBJECT;
duke@0 883 }
duke@0 884 if (OGLContext_IsLCDShaderSupportAvailable(env, fragShaderAvail)) {
tdv@430 885 *caps |= CAPS_EXT_LCD_SHADER | CAPS_PS20;
duke@0 886 }
duke@0 887 if (OGLContext_IsBIOpShaderSupportAvailable(env, fragShaderAvail)) {
tdv@430 888 *caps |= CAPS_EXT_BIOP_SHADER | CAPS_PS20;
duke@0 889 }
duke@0 890 if (OGLContext_IsGradShaderSupportAvailable(env, fragShaderAvail)) {
tdv@430 891 *caps |= CAPS_EXT_GRAD_SHADER | CAPS_PS20;
duke@0 892 }
tdv@430 893 if (OGLContext_IsExtensionAvailable(e, "GL_NV_fragment_program")) {
tdv@430 894 // this is an Nvidia board, at least PS 2.0, but we can't
tdv@430 895 // use the "max instructions" heuristic since GeForce FX
tdv@430 896 // boards report 1024 even though they're only PS 2.0,
tdv@430 897 // so we'll check the following, which does imply PS 3.0
tdv@430 898 if (OGLContext_IsExtensionAvailable(e, "GL_NV_fragment_program2")) {
tdv@430 899 *caps |= CAPS_PS30;
tdv@430 900 }
tdv@430 901 } else {
tdv@430 902 // for all other boards, we look at the "max instructions"
tdv@430 903 // count reported by the GL_ARB_fragment_program extension
tdv@430 904 // as a heuristic for detecting PS 3.0 compatible hardware
tdv@430 905 if (OGLContext_IsExtensionAvailable(e, "GL_ARB_fragment_program")) {
tdv@430 906 GLint instr;
tdv@430 907 j2d_glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB,
tdv@430 908 GL_MAX_PROGRAM_INSTRUCTIONS_ARB, &instr);
tdv@430 909 if (instr > 512) {
tdv@430 910 *caps |= CAPS_PS30;
tdv@430 911 }
tdv@430 912 }
tdv@430 913 }
bae@11015 914 if (OGLContext_IsExtensionAvailable(e, "GL_NV_texture_barrier")) {
bae@11015 915 *caps |= CAPS_EXT_TEXBARRIER;
bae@11015 916 }
bae@11015 917
duke@0 918 // stuff vendor descriptor in the upper bits of the caps
duke@0 919 if (vendor != NULL) {
duke@0 920 if (strncmp(vendor, "ATI", 3) == 0) {
duke@0 921 vcap = OGLC_VENDOR_ATI;
duke@0 922 } else if (strncmp(vendor, "NVIDIA", 6) == 0) {
duke@0 923 vcap = OGLC_VENDOR_NVIDIA;
serb@10382 924 } else if (strncmp(vendor, "Intel", 5) == 0) {
serb@10382 925 vcap = OGLC_VENDOR_INTEL;
duke@0 926 }
tdv@430 927 // REMIND: new in 7 - check if needs fixing
tdv@430 928 *caps |= ((vcap & OGLC_VCAP_MASK) << OGLC_VCAP_OFFSET);
duke@0 929 }
tdv@430 930
duke@0 931 }
duke@0 932
duke@0 933 /**
duke@0 934 * Returns JNI_TRUE if the given GL_VERSION string meets the minimum
duke@0 935 * requirements (>= 1.2); JNI_FALSE otherwise.
duke@0 936 */
duke@0 937 jboolean
duke@0 938 OGLContext_IsVersionSupported(const unsigned char *versionstr)
duke@0 939 {
duke@0 940 J2dTraceLn(J2D_TRACE_INFO, "OGLContext_IsVersionSupported");
duke@0 941
duke@0 942 if (versionstr == NULL) {
duke@0 943 J2dRlsTraceLn(J2D_TRACE_ERROR,
duke@0 944 "OGLContext_IsVersionSupported: version string is null");
duke@0 945 return JNI_FALSE;
duke@0 946 }
duke@0 947
duke@0 948 // note that this check allows for OpenGL 2.x
duke@0 949 return ((versionstr[0] == '1' && versionstr[2] >= '2') ||
duke@0 950 (versionstr[0] >= '2'));
duke@0 951 }
duke@0 952
duke@0 953 /**
duke@0 954 * Compiles and links the given fragment shader program. If
duke@0 955 * successful, this function returns a handle to the newly created shader
duke@0 956 * program; otherwise returns 0.
duke@0 957 */
duke@0 958 GLhandleARB
duke@0 959 OGLContext_CreateFragmentProgram(const char *fragmentShaderSource)
duke@0 960 {
duke@0 961 GLhandleARB fragmentShader, fragmentProgram;
duke@0 962 GLint success;
duke@0 963 int infoLogLength = 0;
duke@0 964
duke@0 965 J2dTraceLn(J2D_TRACE_INFO, "OGLContext_CreateFragmentProgram");
duke@0 966
duke@0 967 // create the shader object and compile the shader source code
duke@0 968 fragmentShader = j2d_glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
duke@0 969 j2d_glShaderSourceARB(fragmentShader, 1, &fragmentShaderSource, NULL);
duke@0 970 j2d_glCompileShaderARB(fragmentShader);
duke@0 971 j2d_glGetObjectParameterivARB(fragmentShader,
duke@0 972 GL_OBJECT_COMPILE_STATUS_ARB,
duke@0 973 &success);
duke@0 974
duke@0 975 // print the compiler messages, if necessary
duke@0 976 j2d_glGetObjectParameterivARB(fragmentShader,
duke@0 977 GL_OBJECT_INFO_LOG_LENGTH_ARB,
duke@0 978 &infoLogLength);
duke@0 979 if (infoLogLength > 1) {
duke@0 980 char infoLog[1024];
duke@0 981 j2d_glGetInfoLogARB(fragmentShader, 1024, NULL, infoLog);
duke@0 982 J2dRlsTraceLn2(J2D_TRACE_WARNING,
duke@0 983 "OGLContext_CreateFragmentProgram: compiler msg (%d):\n%s",
duke@0 984 infoLogLength, infoLog);
duke@0 985 }
duke@0 986
duke@0 987 if (!success) {
duke@0 988 J2dRlsTraceLn(J2D_TRACE_ERROR,
duke@0 989 "OGLContext_CreateFragmentProgram: error compiling shader");
duke@0 990 j2d_glDeleteObjectARB(fragmentShader);
duke@0 991 return 0;
duke@0 992 }
duke@0 993
duke@0 994 // create the program object and attach it to the shader
duke@0 995 fragmentProgram = j2d_glCreateProgramObjectARB();
duke@0 996 j2d_glAttachObjectARB(fragmentProgram, fragmentShader);
duke@0 997
duke@0 998 // it is now safe to delete the shader object
duke@0 999 j2d_glDeleteObjectARB(fragmentShader);
duke@0 1000
duke@0 1001 // link the program
duke@0 1002 j2d_glLinkProgramARB(fragmentProgram);
duke@0 1003 j2d_glGetObjectParameterivARB(fragmentProgram,
duke@0 1004 GL_OBJECT_LINK_STATUS_ARB,
duke@0 1005 &success);
duke@0 1006
duke@0 1007 // print the linker messages, if necessary
duke@0 1008 j2d_glGetObjectParameterivARB(fragmentProgram,
duke@0 1009 GL_OBJECT_INFO_LOG_LENGTH_ARB,
duke@0 1010 &infoLogLength);
duke@0 1011 if (infoLogLength > 1) {
duke@0 1012 char infoLog[1024];
duke@0 1013 j2d_glGetInfoLogARB(fragmentProgram, 1024, NULL, infoLog);
duke@0 1014 J2dRlsTraceLn2(J2D_TRACE_WARNING,
duke@0 1015 "OGLContext_CreateFragmentProgram: linker msg (%d):\n%s",
duke@0 1016 infoLogLength, infoLog);
duke@0 1017 }
duke@0 1018
duke@0 1019 if (!success) {
duke@0 1020 J2dRlsTraceLn(J2D_TRACE_ERROR,
duke@0 1021 "OGLContext_CreateFragmentProgram: error linking shader");
duke@0 1022 j2d_glDeleteObjectARB(fragmentProgram);
duke@0 1023 return 0;
duke@0 1024 }
duke@0 1025
duke@0 1026 return fragmentProgram;
duke@0 1027 }
duke@0 1028
tdv@430 1029 /*
tdv@430 1030 * Class: sun_java2d_opengl_OGLContext
tdv@430 1031 * Method: getOGLIdString
tdv@430 1032 * Signature: ()Ljava/lang/String;
tdv@430 1033 */
tdv@430 1034 JNIEXPORT jstring JNICALL Java_sun_java2d_opengl_OGLContext_getOGLIdString
tdv@430 1035 (JNIEnv *env, jclass oglcc)
tdv@430 1036 {
tdv@430 1037 char *vendor, *renderer, *version;
tdv@430 1038 char *pAdapterId;
tdv@430 1039 jobject ret = NULL;
tdv@430 1040 int len;
tdv@430 1041
tdv@430 1042 J2dTraceLn(J2D_TRACE_INFO, "OGLContext_getOGLIdString");
tdv@430 1043
tdv@430 1044 vendor = (char*)j2d_glGetString(GL_VENDOR);
tdv@430 1045 if (vendor == NULL) {
tdv@430 1046 vendor = "Unknown Vendor";
tdv@430 1047 }
tdv@430 1048 renderer = (char*)j2d_glGetString(GL_RENDERER);
tdv@430 1049 if (renderer == NULL) {
tdv@430 1050 renderer = "Unknown Renderer";
tdv@430 1051 }
tdv@430 1052 version = (char*)j2d_glGetString(GL_VERSION);
tdv@430 1053 if (version == NULL) {
tdv@430 1054 version = "unknown version";
tdv@430 1055 }
tdv@430 1056
tdv@430 1057 // 'vendor renderer (version)0'
tdv@430 1058 len = strlen(vendor) + 1 + strlen(renderer) + 1 + 1+strlen(version)+1 + 1;
tdv@430 1059 pAdapterId = malloc(len);
tdv@430 1060 if (pAdapterId != NULL) {
tdv@430 1061
tdv@430 1062 jio_snprintf(pAdapterId, len, "%s %s (%s)", vendor, renderer, version);
tdv@430 1063
tdv@430 1064 J2dTraceLn1(J2D_TRACE_VERBOSE, " id=%s", pAdapterId);
tdv@430 1065
tdv@430 1066 ret = JNU_NewStringPlatform(env, pAdapterId);
tdv@430 1067
tdv@430 1068 free(pAdapterId);
tdv@430 1069 }
tdv@430 1070
tdv@430 1071 return ret;
tdv@430 1072 }
tdv@430 1073
duke@0 1074 #endif /* !HEADLESS */