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