1 /*
   2  * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 #ifndef HEADLESS
  27 
  28 #include <stdlib.h>
  29 
  30 #include "sun_java2d_opengl_OGLSurfaceData.h"
  31 
  32 #include "jlong.h"
  33 #include "jni_util.h"
  34 #include "OGLSurfaceData.h"
  35 
  36 /**
  37  * The following methods are implemented in the windowing system (i.e. GLX
  38  * and WGL) source files.
  39  */
  40 extern jlong OGLSD_GetNativeConfigInfo(OGLSDOps *oglsdo);
  41 extern jboolean OGLSD_InitOGLWindow(JNIEnv *env, OGLSDOps *oglsdo);
  42 extern void OGLSD_DestroyOGLSurface(JNIEnv *env, OGLSDOps *oglsdo);
  43 
  44 void OGLSD_SetNativeDimensions(JNIEnv *env, OGLSDOps *oglsdo, jint w, jint h);
  45 
  46 /**
  47  * This table contains the "pixel formats" for all system memory surfaces
  48  * that OpenGL is capable of handling, indexed by the "PF_" constants defined
  49  * in OGLSurfaceData.java.  These pixel formats contain information that is
  50  * passed to OpenGL when copying from a system memory ("Sw") surface to
  51  * an OpenGL "Surface" (via glDrawPixels()) or "Texture" (via glTexImage2D()).
  52  */
  53 OGLPixelFormat PixelFormats[] = {
  54     { GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV,
  55       4, 1, 0,                                     }, /* 0 - IntArgb      */
  56     { GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV,
  57       4, 1, 1,                                     }, /* 1 - IntArgbPre   */
  58     { GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV,
  59       4, 0, 1,                                     }, /* 2 - IntRgb       */
  60     { GL_RGBA, GL_UNSIGNED_INT_8_8_8_8,
  61       4, 0, 1,                                     }, /* 3 - IntRgbx      */
  62     { GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV,
  63       4, 0, 1,                                     }, /* 4 - IntBgr       */
  64     { GL_BGRA, GL_UNSIGNED_INT_8_8_8_8,
  65       4, 0, 1,                                     }, /* 5 - IntBgrx      */
  66     { GL_RGB,  GL_UNSIGNED_SHORT_5_6_5,
  67       2, 0, 1,                                     }, /* 6 - Ushort565Rgb */
  68     { GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV,
  69       2, 0, 1,                                     }, /* 7 - Ushort555Rgb */
  70     { GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1,
  71       2, 0, 1,                                     }, /* 8 - Ushort555Rgbx*/
  72     { GL_LUMINANCE, GL_UNSIGNED_BYTE,
  73       1, 0, 1,                                     }, /* 9 - ByteGray     */
  74     { GL_LUMINANCE, GL_UNSIGNED_SHORT,
  75       2, 0, 1,                                     }, /*10 - UshortGray   */
  76     { GL_BGR,  GL_UNSIGNED_BYTE,
  77       1, 0, 1,                                     }, /*11 - ThreeByteBgr */};
  78 
  79 /**
  80  * Given a starting value and a maximum limit, returns the first power-of-two
  81  * greater than the starting value.  If the resulting value is greater than
  82  * the maximum limit, zero is returned.
  83  */
  84 jint
  85 OGLSD_NextPowerOfTwo(jint val, jint max)
  86 {
  87     jint i;
  88 
  89     if (val > max) {
  90         return 0;
  91     }
  92 
  93     for (i = 1; i < val; i *= 2);
  94 
  95     return i;
  96 }
  97 
  98 /**
  99  * Returns true if both given dimensions are a power of two.
 100  */
 101 static jboolean
 102 OGLSD_IsPowerOfTwo(jint width, jint height)
 103 {
 104     return (((width & (width-1)) | (height & (height-1))) == 0);
 105 }
 106 
 107 /**
 108  * Initializes an OpenGL texture object.
 109  *
 110  * If the isOpaque parameter is JNI_FALSE, then the texture will have a
 111  * full alpha channel; otherwise, the texture will be opaque (this can
 112  * help save VRAM when translucency is not needed).
 113  *
 114  * If the GL_ARB_texture_non_power_of_two extension is present (texNonPow2
 115  * is JNI_TRUE), the actual texture is allowed to have non-power-of-two
 116  * dimensions, and therefore width==textureWidth and height==textureHeight.
 117  *
 118  * Failing that, if the GL_ARB_texture_rectangle extension is present
 119  * (texRect is JNI_TRUE), the actual texture is allowed to have
 120  * non-power-of-two dimensions, except that instead of using the usual
 121  * GL_TEXTURE_2D target, we need to use the GL_TEXTURE_RECTANGLE_ARB target.
 122  * Note that the GL_REPEAT wrapping mode is not allowed with this target,
 123  * so if that mode is needed (e.g. as is the case in the TexturePaint code)
 124  * one should pass JNI_FALSE to avoid using this extension.  Also note that
 125  * when the texture target is GL_TEXTURE_RECTANGLE_ARB, texture coordinates
 126  * must be specified in the range [0,width] and [0,height] rather than
 127  * [0,1] as is the case with the usual GL_TEXTURE_2D target (so take care)!
 128  *
 129  * Otherwise, the actual texture must have power-of-two dimensions, and
 130  * therefore the textureWidth and textureHeight will be the next
 131  * power-of-two greater than (or equal to) the requested width and height.
 132  */
 133 static jboolean
 134 OGLSD_InitTextureObject(OGLSDOps *oglsdo,
 135                         jboolean isOpaque,
 136                         jboolean texNonPow2, jboolean texRect,
 137                         jint width, jint height)
 138 {
 139     GLenum texTarget, texProxyTarget;
 140     GLint format = GL_RGBA;
 141     GLint size = GL_UNSIGNED_INT_8_8_8_8;
 142     GLuint texID;
 143     GLsizei texWidth, texHeight, realWidth, realHeight;
 144     GLint texMax;
 145 
 146     J2dTraceLn4(J2D_TRACE_INFO,
 147                 "OGLSD_InitTextureObject: w=%d h=%d opq=%d nonpow2=%d",
 148                 width, height, isOpaque, texNonPow2);
 149 
 150     if (oglsdo == NULL) {
 151         J2dRlsTraceLn(J2D_TRACE_ERROR,
 152                       "OGLSD_InitTextureObject: ops are null");
 153         return JNI_FALSE;
 154     }
 155 
 156     if (texNonPow2) {
 157         // use non-pow2 dimensions with GL_TEXTURE_2D target
 158         j2d_glGetIntegerv(GL_MAX_TEXTURE_SIZE, &texMax);
 159         texWidth = (width <= texMax) ? width : 0;
 160         texHeight = (height <= texMax) ? height : 0;
 161         texTarget = GL_TEXTURE_2D;
 162         texProxyTarget = GL_PROXY_TEXTURE_2D;
 163     } else if (texRect) {
 164         // use non-pow2 dimensions with GL_TEXTURE_RECTANGLE_ARB target
 165         j2d_glGetIntegerv(GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB, &texMax);
 166         texWidth = (width <= texMax) ? width : 0;
 167         texHeight = (height <= texMax) ? height : 0;
 168         texTarget = GL_TEXTURE_RECTANGLE_ARB;
 169         texProxyTarget = GL_PROXY_TEXTURE_RECTANGLE_ARB;
 170     } else {
 171         // find the appropriate power-of-two dimensions
 172         j2d_glGetIntegerv(GL_MAX_TEXTURE_SIZE, &texMax);
 173         texWidth = OGLSD_NextPowerOfTwo(width, texMax);
 174         texHeight = OGLSD_NextPowerOfTwo(height, texMax);
 175         texTarget = GL_TEXTURE_2D;
 176         texProxyTarget = GL_PROXY_TEXTURE_2D;
 177     }
 178 
 179     J2dTraceLn3(J2D_TRACE_VERBOSE,
 180                 "  desired texture dimensions: w=%d h=%d max=%d",
 181                 texWidth, texHeight, texMax);
 182 
 183     // if either dimension is 0, we cannot allocate a texture with the
 184     // requested dimensions
 185     if ((texWidth == 0) || (texHeight == 0)) {
 186         J2dRlsTraceLn(J2D_TRACE_ERROR,
 187             "OGLSD_InitTextureObject: texture dimensions too large");
 188         return JNI_FALSE;
 189     }
 190 
 191     // now use a proxy to determine whether we can create a texture with
 192     // the calculated power-of-two dimensions and the given internal format
 193     j2d_glTexImage2D(texProxyTarget, 0, format,
 194                      texWidth, texHeight, 0,
 195                      format, size, NULL);
 196     j2d_glGetTexLevelParameteriv(texProxyTarget, 0,
 197                                  GL_TEXTURE_WIDTH, &realWidth);
 198     j2d_glGetTexLevelParameteriv(texProxyTarget, 0,
 199                                  GL_TEXTURE_HEIGHT, &realHeight);
 200 
 201     // if the requested dimensions and proxy dimensions don't match,
 202     // we shouldn't attempt to create the texture
 203     if ((realWidth != texWidth) || (realHeight != texHeight)) {
 204         J2dRlsTraceLn2(J2D_TRACE_ERROR,
 205             "OGLSD_InitTextureObject: actual (w=%d h=%d) != requested",
 206                        realWidth, realHeight);
 207         return JNI_FALSE;
 208     }
 209 
 210     // initialize the texture with some dummy data (this allows us to create
 211     // a texture object once with 2^n dimensions, and then use
 212     // glTexSubImage2D() to provide further updates)
 213     j2d_glGenTextures(1, &texID);
 214     j2d_glBindTexture(texTarget, texID);
 215     j2d_glTexImage2D(texTarget, 0, format,
 216                      texWidth, texHeight, 0,
 217                      format, size, NULL);
 218 
 219     oglsdo->isOpaque = isOpaque;
 220     oglsdo->xOffset = 0;
 221     oglsdo->yOffset = 0;
 222     oglsdo->width = width;
 223     oglsdo->height = height;
 224     oglsdo->textureID = texID;
 225     oglsdo->textureWidth = texWidth;
 226     oglsdo->textureHeight = texHeight;
 227     oglsdo->textureTarget = texTarget;
 228     OGLSD_INIT_TEXTURE_FILTER(oglsdo, GL_NEAREST);
 229     OGLSD_RESET_TEXTURE_WRAP(texTarget);
 230 
 231     J2dTraceLn3(J2D_TRACE_VERBOSE, "  created texture: w=%d h=%d id=%d",
 232                 width, height, texID);
 233 
 234     return JNI_TRUE;
 235 }
 236 
 237 /**
 238  * Initializes an OpenGL texture, using the given width and height as
 239  * a guide.  See OGLSD_InitTextureObject() for more information.
 240  */
 241 JNIEXPORT jboolean JNICALL
 242 Java_sun_java2d_opengl_OGLSurfaceData_initTexture
 243     (JNIEnv *env, jobject oglsd,
 244      jlong pData, jboolean isOpaque,
 245      jboolean texNonPow2, jboolean texRect,
 246      jint width, jint height)
 247 {
 248     OGLSDOps *oglsdo = (OGLSDOps *)jlong_to_ptr(pData);
 249 
 250     J2dTraceLn2(J2D_TRACE_INFO, "OGLSurfaceData_initTexture: w=%d h=%d",
 251                 width, height);
 252 
 253     if (oglsdo == NULL) {
 254         J2dRlsTraceLn(J2D_TRACE_ERROR,
 255             "OGLSurfaceData_initTexture: ops are null");
 256         return JNI_FALSE;
 257     }
 258 
 259     /*
 260      * We only use the GL_ARB_texture_rectangle extension if it is available
 261      * and the requested bounds are not pow2 (it is probably faster to use
 262      * GL_TEXTURE_2D for pow2 textures, and besides, our TexturePaint
 263      * code relies on GL_REPEAT, which is not allowed for
 264      * GL_TEXTURE_RECTANGLE_ARB targets).
 265      */
 266     texRect = texRect && !OGLSD_IsPowerOfTwo(width, height);
 267 
 268     if (!OGLSD_InitTextureObject(oglsdo, isOpaque, texNonPow2, texRect,
 269                                  width, height))
 270     {
 271         J2dRlsTraceLn(J2D_TRACE_ERROR,
 272             "OGLSurfaceData_initTexture: could not init texture object");
 273         return JNI_FALSE;
 274     }
 275 
 276     OGLSD_SetNativeDimensions(env, oglsdo,
 277                               oglsdo->textureWidth, oglsdo->textureHeight);
 278 
 279     oglsdo->drawableType = OGLSD_TEXTURE;
 280     // other fields (e.g. width, height) are set in OGLSD_InitTextureObject()
 281 
 282     return JNI_TRUE;
 283 }
 284 
 285 /**
 286  * Initializes a framebuffer object based on the given textureID and its
 287  * width/height.  This method will iterate through all possible depth formats
 288  * to find one that is supported by the drivers/hardware.  (Since our use of
 289  * the depth buffer is fairly simplistic, we hope to find a depth format that
 290  * uses as little VRAM as possible.)  If an appropriate depth buffer is found
 291  * and all attachments are successful (i.e. the framebuffer object is
 292  * "complete"), then this method will return JNI_TRUE and will initialize
 293  * the values of fbobjectID and depthID using the IDs created by this method.
 294  * Otherwise, this method returns JNI_FALSE.  Note that the caller is only
 295  * responsible for deleting the allocated fbobject and depth renderbuffer
 296  * resources if this method returned JNI_TRUE.
 297  */
 298 jboolean
 299 OGLSD_InitFBObject(GLuint *fbobjectID, GLuint *depthID,
 300                    GLuint textureID, GLenum textureTarget,
 301                    jint textureWidth, jint textureHeight)
 302 {
 303     GLenum depthFormats[] = {
 304         GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT32
 305     };
 306     GLuint fboTmpID, depthTmpID;
 307     jboolean foundDepth = JNI_FALSE;
 308     int i;
 309 
 310     J2dTraceLn3(J2D_TRACE_INFO, "OGLSD_InitFBObject: w=%d h=%d texid=%d",
 311                 textureWidth, textureHeight, textureID);
 312 
 313     // initialize framebuffer object
 314     j2d_glGenFramebuffersEXT(1, &fboTmpID);
 315     j2d_glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fboTmpID);
 316 
 317     // attach color texture to framebuffer object
 318     j2d_glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,
 319                                   GL_COLOR_ATTACHMENT0_EXT,
 320                                   textureTarget, textureID, 0);
 321 
 322     // attempt to create a depth renderbuffer of a particular format; we
 323     // will start with the smallest size and then work our way up
 324     for (i = 0; i < 3; i++) {
 325         GLenum error, status;
 326         GLenum depthFormat = depthFormats[i];
 327         int depthSize = 16 + (i * 8);
 328 
 329         // initialize depth renderbuffer
 330         j2d_glGenRenderbuffersEXT(1, &depthTmpID);
 331         j2d_glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, depthTmpID);
 332         j2d_glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, depthFormat,
 333                                      textureWidth, textureHeight);
 334 
 335         // creation of depth buffer could potentially fail, so check for error
 336         error = j2d_glGetError();
 337         if (error != GL_NO_ERROR) {
 338             J2dTraceLn2(J2D_TRACE_VERBOSE,
 339                 "OGLSD_InitFBObject: could not create depth buffer: depth=%d error=%x",
 340                            depthSize, error);
 341             j2d_glDeleteRenderbuffersEXT(1, &depthTmpID);
 342             continue;
 343         }
 344 
 345         // attach depth renderbuffer to framebuffer object
 346         j2d_glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT,
 347                                          GL_DEPTH_ATTACHMENT_EXT,
 348                                          GL_RENDERBUFFER_EXT, depthTmpID);
 349 
 350         // now check for framebuffer "completeness"
 351         status = j2d_glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
 352 
 353         if (status == GL_FRAMEBUFFER_COMPLETE_EXT) {
 354             // we found a valid format, so break out of the loop
 355             J2dTraceLn1(J2D_TRACE_VERBOSE,
 356                         "  framebuffer is complete: depth=%d", depthSize);
 357             foundDepth = JNI_TRUE;
 358             break;
 359         } else {
 360             // this depth format didn't work, so delete and try another format
 361             J2dTraceLn2(J2D_TRACE_VERBOSE,
 362                         "  framebuffer is incomplete: depth=%d status=%x",
 363                         depthSize, status);
 364             j2d_glDeleteRenderbuffersEXT(1, &depthTmpID);
 365         }
 366     }
 367 
 368     // unbind the texture and framebuffer objects (they will be bound again
 369     // later as needed)
 370     j2d_glBindTexture(textureTarget, 0);
 371     j2d_glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
 372     j2d_glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
 373 
 374     if (!foundDepth) {
 375         J2dRlsTraceLn(J2D_TRACE_ERROR,
 376             "OGLSD_InitFBObject: could not find valid depth format");
 377         j2d_glDeleteFramebuffersEXT(1, &fboTmpID);
 378         return JNI_FALSE;
 379     }
 380 
 381     *fbobjectID = fboTmpID;
 382     *depthID = depthTmpID;
 383 
 384     return JNI_TRUE;
 385 }
 386 
 387 /**
 388  * Initializes a framebuffer object, using the given width and height as
 389  * a guide.  See OGLSD_InitTextureObject() and OGLSD_InitFBObject()
 390  * for more information.
 391  */
 392 JNIEXPORT jboolean JNICALL
 393 Java_sun_java2d_opengl_OGLSurfaceData_initFBObject
 394     (JNIEnv *env, jobject oglsd,
 395      jlong pData, jboolean isOpaque,
 396      jboolean texNonPow2, jboolean texRect,
 397      jint width, jint height)
 398 {
 399     OGLSDOps *oglsdo = (OGLSDOps *)jlong_to_ptr(pData);
 400     GLuint fbobjectID, depthID;
 401 
 402     J2dTraceLn2(J2D_TRACE_INFO,
 403                 "OGLSurfaceData_initFBObject: w=%d h=%d",
 404                 width, height);
 405 
 406     if (oglsdo == NULL) {
 407         J2dRlsTraceLn(J2D_TRACE_ERROR,
 408             "OGLSurfaceData_initFBObject: ops are null");
 409         return JNI_FALSE;
 410     }
 411 
 412     // initialize color texture object
 413     if (!OGLSD_InitTextureObject(oglsdo, isOpaque, texNonPow2, texRect,
 414                                  width, height))
 415     {
 416         J2dRlsTraceLn(J2D_TRACE_ERROR,
 417             "OGLSurfaceData_initFBObject: could not init texture object");
 418         return JNI_FALSE;
 419     }
 420 
 421     // initialize framebuffer object using color texture created above
 422     if (!OGLSD_InitFBObject(&fbobjectID, &depthID,
 423                             oglsdo->textureID, oglsdo->textureTarget,
 424                             oglsdo->textureWidth, oglsdo->textureHeight))
 425     {
 426         J2dRlsTraceLn(J2D_TRACE_ERROR,
 427             "OGLSurfaceData_initFBObject: could not init fbobject");
 428         j2d_glDeleteTextures(1, &oglsdo->textureID);
 429         return JNI_FALSE;
 430     }
 431 
 432     oglsdo->drawableType = OGLSD_FBOBJECT;
 433     // other fields (e.g. width, height) are set in OGLSD_InitTextureObject()
 434     oglsdo->fbobjectID = fbobjectID;
 435     oglsdo->depthID = depthID;
 436 
 437     OGLSD_SetNativeDimensions(env, oglsdo,
 438                               oglsdo->textureWidth, oglsdo->textureHeight);
 439 
 440     // framebuffer objects differ from other OpenGL surfaces in that the
 441     // value passed to glRead/DrawBuffer() must be GL_COLOR_ATTACHMENTn_EXT,
 442     // rather than GL_FRONT (or GL_BACK)
 443     oglsdo->activeBuffer = GL_COLOR_ATTACHMENT0_EXT;
 444 
 445     return JNI_TRUE;
 446 }
 447 
 448 /**
 449  * Initializes a surface in the backbuffer of a given double-buffered
 450  * onscreen window for use in a BufferStrategy.Flip situation.  The bounds of
 451  * the backbuffer surface should always be kept in sync with the bounds of
 452  * the underlying native window.
 453  */
 454 JNIEXPORT jboolean JNICALL
 455 Java_sun_java2d_opengl_OGLSurfaceData_initFlipBackbuffer
 456     (JNIEnv *env, jobject oglsd,
 457      jlong pData)
 458 {
 459     OGLSDOps *oglsdo = (OGLSDOps *)jlong_to_ptr(pData);
 460 
 461     J2dTraceLn(J2D_TRACE_INFO, "OGLSurfaceData_initFlipBackbuffer");
 462 
 463     if (oglsdo == NULL) {
 464         J2dRlsTraceLn(J2D_TRACE_ERROR,
 465             "OGLSurfaceData_initFlipBackbuffer: ops are null");
 466         return JNI_FALSE;
 467     }
 468 
 469     if (oglsdo->drawableType == OGLSD_UNDEFINED) {
 470         if (!OGLSD_InitOGLWindow(env, oglsdo)) {
 471             J2dRlsTraceLn(J2D_TRACE_ERROR,
 472                 "OGLSurfaceData_initFlipBackbuffer: could not init window");
 473             return JNI_FALSE;
 474         }
 475     }
 476 
 477     if (oglsdo->drawableType != OGLSD_WINDOW) {
 478         J2dRlsTraceLn(J2D_TRACE_ERROR,
 479             "OGLSurfaceData_initFlipBackbuffer: drawable is not a window");
 480         return JNI_FALSE;
 481     }
 482 
 483     oglsdo->drawableType = OGLSD_FLIP_BACKBUFFER;
 484     // x/yOffset have already been set in OGLSD_InitOGLWindow()...
 485     // REMIND: for some reason, flipping won't work properly on IFB unless we
 486     //         explicitly use BACK_LEFT rather than BACK...
 487     oglsdo->activeBuffer = GL_BACK_LEFT;
 488 
 489     OGLSD_SetNativeDimensions(env, oglsdo, oglsdo->width, oglsdo->height);
 490 
 491     return JNI_TRUE;
 492 }
 493 
 494 JNIEXPORT jint JNICALL
 495 Java_sun_java2d_opengl_OGLSurfaceData_getTextureTarget
 496     (JNIEnv *env, jobject oglsd,
 497      jlong pData)
 498 {
 499     OGLSDOps *oglsdo = (OGLSDOps *)jlong_to_ptr(pData);
 500 
 501     J2dTraceLn(J2D_TRACE_INFO, "OGLSurfaceData_getTextureTarget");
 502 
 503     if (oglsdo == NULL) {
 504         J2dRlsTraceLn(J2D_TRACE_ERROR,
 505             "OGLSurfaceData_getTextureTarget: ops are null");
 506         return 0;
 507     }
 508 
 509     return (jint)oglsdo->textureTarget;
 510 }
 511 
 512 JNIEXPORT jint JNICALL
 513 Java_sun_java2d_opengl_OGLSurfaceData_getTextureID
 514     (JNIEnv *env, jobject oglsd,
 515      jlong pData)
 516 {
 517     OGLSDOps *oglsdo = (OGLSDOps *)jlong_to_ptr(pData);
 518 
 519     J2dTraceLn(J2D_TRACE_INFO, "OGLSurfaceData_getTextureID");
 520 
 521     if (oglsdo == NULL) {
 522         J2dRlsTraceLn(J2D_TRACE_ERROR,
 523             "OGLSurfaceData_getTextureID: ops are null");
 524         return 0L;
 525     }
 526 
 527     return (jint)oglsdo->textureID;
 528 }
 529 
 530 /**
 531  * Initializes nativeWidth/Height fields of the surfaceData object with
 532  * passed arguments.
 533  */
 534 void
 535 OGLSD_SetNativeDimensions(JNIEnv *env, OGLSDOps *oglsdo,
 536                           jint width, jint height)
 537 {
 538     jobject sdObject;
 539 
 540     sdObject = (*env)->NewLocalRef(env, oglsdo->sdOps.sdObject);
 541     if (sdObject == NULL) {
 542         return;
 543     }
 544 
 545     JNU_SetFieldByName(env, NULL, sdObject, "nativeWidth", "I", width);
 546     if (!((*env)->ExceptionOccurred(env))) {
 547     JNU_SetFieldByName(env, NULL, sdObject, "nativeHeight", "I", height);
 548     }
 549 
 550     (*env)->DeleteLocalRef(env, sdObject);
 551 }
 552 
 553 /**
 554  * Deletes native OpenGL resources associated with this surface.
 555  */
 556 void
 557 OGLSD_Delete(JNIEnv *env, OGLSDOps *oglsdo)
 558 {
 559     J2dTraceLn1(J2D_TRACE_INFO, "OGLSD_Delete: type=%d",
 560                 oglsdo->drawableType);
 561 
 562     if (oglsdo->drawableType == OGLSD_TEXTURE) {
 563         if (oglsdo->textureID != 0) {
 564             j2d_glDeleteTextures(1, &oglsdo->textureID);
 565             oglsdo->textureID = 0;
 566         }
 567     } else if (oglsdo->drawableType == OGLSD_FBOBJECT) {
 568         if (oglsdo->textureID != 0) {
 569             j2d_glDeleteTextures(1, &oglsdo->textureID);
 570             oglsdo->textureID = 0;
 571         }
 572         if (oglsdo->depthID != 0) {
 573             j2d_glDeleteRenderbuffersEXT(1, &oglsdo->depthID);
 574             oglsdo->depthID = 0;
 575         }
 576         if (oglsdo->fbobjectID != 0) {
 577             j2d_glDeleteFramebuffersEXT(1, &oglsdo->fbobjectID);
 578             oglsdo->fbobjectID = 0;
 579         }
 580     } else {
 581         // dispose windowing system resources (pbuffer, pixmap, etc)
 582         OGLSD_DestroyOGLSurface(env, oglsdo);
 583     }
 584 }
 585 
 586 /**
 587  * This is the implementation of the general DisposeFunc defined in
 588  * SurfaceData.h and used by the Disposer mechanism.  It first flushes all
 589  * native OpenGL resources and then frees any memory allocated within the
 590  * native OGLSDOps structure.
 591  */
 592 void
 593 OGLSD_Dispose(JNIEnv *env, SurfaceDataOps *ops)
 594 {
 595     OGLSDOps *oglsdo = (OGLSDOps *)ops;
 596     jlong pConfigInfo = OGLSD_GetNativeConfigInfo(oglsdo);
 597 
 598     JNU_CallStaticMethodByName(env, NULL, "sun/java2d/opengl/OGLSurfaceData",
 599                                "dispose", "(JJ)V",
 600                                ptr_to_jlong(ops), pConfigInfo);
 601 }
 602 
 603 /**
 604  * This is the implementation of the general surface LockFunc defined in
 605  * SurfaceData.h.
 606  */
 607 jint
 608 OGLSD_Lock(JNIEnv *env,
 609            SurfaceDataOps *ops,
 610            SurfaceDataRasInfo *pRasInfo,
 611            jint lockflags)
 612 {
 613     JNU_ThrowInternalError(env, "OGLSD_Lock not implemented!");
 614     return SD_FAILURE;
 615 }
 616 
 617 /**
 618  * This is the implementation of the general GetRasInfoFunc defined in
 619  * SurfaceData.h.
 620  */
 621 void
 622 OGLSD_GetRasInfo(JNIEnv *env,
 623                  SurfaceDataOps *ops,
 624                  SurfaceDataRasInfo *pRasInfo)
 625 {
 626     JNU_ThrowInternalError(env, "OGLSD_GetRasInfo not implemented!");
 627 }
 628 
 629 /**
 630  * This is the implementation of the general surface UnlockFunc defined in
 631  * SurfaceData.h.
 632  */
 633 void
 634 OGLSD_Unlock(JNIEnv *env,
 635              SurfaceDataOps *ops,
 636              SurfaceDataRasInfo *pRasInfo)
 637 {
 638     JNU_ThrowInternalError(env, "OGLSD_Unlock not implemented!");
 639 }
 640 
 641 #endif /* !HEADLESS */