| /* |
| * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. Oracle designates this |
| * particular file as subject to the "Classpath" exception as provided |
| * by Oracle in the LICENSE file that accompanied this code. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| |
| #import <stdlib.h> |
| #import <JavaNativeFoundation/JavaNativeFoundation.h> |
| |
| #import "sun_java2d_opengl_CGLSurfaceData.h" |
| |
| #import "jni.h" |
| #import "jni_util.h" |
| #import "OGLRenderQueue.h" |
| #import "CGLGraphicsConfig.h" |
| #import "CGLSurfaceData.h" |
| #import "CGLLayer.h" |
| #import "ThreadUtilities.h" |
| |
| /* JDK's glext.h is already included and will prevent the Apple glext.h |
| * being included, so define the externs directly |
| */ |
| extern void glBindFramebufferEXT(GLenum target, GLuint framebuffer); |
| extern CGLError CGLTexImageIOSurface2D( |
| CGLContextObj ctx, GLenum target, GLenum internal_format, |
| GLsizei width, GLsizei height, GLenum format, GLenum type, |
| IOSurfaceRef ioSurface, GLuint plane); |
| |
| /** |
| * The methods in this file implement the native windowing system specific |
| * layer (CGL) for the OpenGL-based Java 2D pipeline. |
| */ |
| |
| #pragma mark - |
| #pragma mark "--- Mac OS X specific methods for GL pipeline ---" |
| |
| // TODO: hack that's called from OGLRenderQueue to test out unlockFocus behavior |
| #if 0 |
| void |
| OGLSD_UnlockFocus(OGLContext *oglc, OGLSDOps *dstOps) |
| { |
| CGLCtxInfo *ctxinfo = (CGLCtxInfo *)oglc->ctxInfo; |
| CGLSDOps *cglsdo = (CGLSDOps *)dstOps->privOps; |
| fprintf(stderr, "about to unlock focus: %p %p\n", |
| cglsdo->peerData, ctxinfo->context); |
| |
| NSOpenGLView *nsView = cglsdo->peerData; |
| if (nsView != NULL) { |
| JNF_COCOA_ENTER(env); |
| [nsView unlockFocus]; |
| JNF_COCOA_EXIT(env); |
| } |
| } |
| #endif |
| |
| /** |
| * Makes the given context current to its associated "scratch" surface. If |
| * the operation is successful, this method will return JNI_TRUE; otherwise, |
| * returns JNI_FALSE. |
| */ |
| static jboolean |
| CGLSD_MakeCurrentToScratch(JNIEnv *env, OGLContext *oglc) |
| { |
| J2dTraceLn(J2D_TRACE_INFO, "CGLSD_MakeCurrentToScratch"); |
| |
| if (oglc == NULL) { |
| J2dRlsTraceLn(J2D_TRACE_ERROR, |
| "CGLSD_MakeCurrentToScratch: context is null"); |
| return JNI_FALSE; |
| } |
| |
| JNF_COCOA_ENTER(env); |
| |
| CGLCtxInfo *ctxinfo = (CGLCtxInfo *)oglc->ctxInfo; |
| #if USE_NSVIEW_FOR_SCRATCH |
| [ctxinfo->context makeCurrentContext]; |
| [ctxinfo->context setView: ctxinfo->scratchSurface]; |
| #else |
| [ctxinfo->context clearDrawable]; |
| [ctxinfo->context makeCurrentContext]; |
| [ctxinfo->context setPixelBuffer: ctxinfo->scratchSurface |
| cubeMapFace: 0 |
| mipMapLevel: 0 |
| currentVirtualScreen: [ctxinfo->context currentVirtualScreen]]; |
| #endif |
| |
| JNF_COCOA_EXIT(env); |
| |
| return JNI_TRUE; |
| } |
| |
| /** |
| * This function disposes of any native windowing system resources associated |
| * with this surface. For instance, if the given OGLSDOps is of type |
| * OGLSD_PBUFFER, this method implementation will destroy the actual pbuffer |
| * surface. |
| */ |
| void |
| OGLSD_DestroyOGLSurface(JNIEnv *env, OGLSDOps *oglsdo) |
| { |
| J2dTraceLn(J2D_TRACE_INFO, "OGLSD_DestroyOGLSurface"); |
| |
| JNF_COCOA_ENTER(env); |
| |
| CGLSDOps *cglsdo = (CGLSDOps *)oglsdo->privOps; |
| if (oglsdo->drawableType == OGLSD_PBUFFER) { |
| if (oglsdo->textureID != 0) { |
| j2d_glDeleteTextures(1, &oglsdo->textureID); |
| oglsdo->textureID = 0; |
| } |
| if (cglsdo->pbuffer != NULL) { |
| [cglsdo->pbuffer release]; |
| cglsdo->pbuffer = NULL; |
| } |
| } else if (oglsdo->drawableType == OGLSD_WINDOW) { |
| // detach the NSView from the NSOpenGLContext |
| CGLGraphicsConfigInfo *cglInfo = cglsdo->configInfo; |
| OGLContext *oglc = cglInfo->context; |
| CGLCtxInfo *ctxinfo = (CGLCtxInfo *)oglc->ctxInfo; |
| [ctxinfo->context clearDrawable]; |
| } |
| |
| oglsdo->drawableType = OGLSD_UNDEFINED; |
| |
| JNF_COCOA_EXIT(env); |
| } |
| |
| /** |
| * Returns a pointer (as a jlong) to the native CGLGraphicsConfigInfo |
| * associated with the given OGLSDOps. This method can be called from |
| * shared code to retrieve the native GraphicsConfig data in a platform- |
| * independent manner. |
| */ |
| jlong |
| OGLSD_GetNativeConfigInfo(OGLSDOps *oglsdo) |
| { |
| J2dTraceLn(J2D_TRACE_INFO, "OGLSD_GetNativeConfigInfo"); |
| |
| if (oglsdo == NULL) { |
| J2dRlsTraceLn(J2D_TRACE_ERROR, "OGLSD_GetNativeConfigInfo: ops are null"); |
| return 0L; |
| } |
| |
| CGLSDOps *cglsdo = (CGLSDOps *)oglsdo->privOps; |
| if (cglsdo == NULL) { |
| J2dRlsTraceLn(J2D_TRACE_ERROR, "OGLSD_GetNativeConfigInfo: cgl ops are null"); |
| return 0L; |
| } |
| |
| return ptr_to_jlong(cglsdo->configInfo); |
| } |
| |
| /** |
| * Makes the given GraphicsConfig's context current to its associated |
| * "scratch" surface. If there is a problem making the context current, |
| * this method will return NULL; otherwise, returns a pointer to the |
| * OGLContext that is associated with the given GraphicsConfig. |
| */ |
| OGLContext * |
| OGLSD_SetScratchSurface(JNIEnv *env, jlong pConfigInfo) |
| { |
| J2dTraceLn(J2D_TRACE_INFO, "OGLSD_SetScratchContext"); |
| |
| CGLGraphicsConfigInfo *cglInfo = (CGLGraphicsConfigInfo *)jlong_to_ptr(pConfigInfo); |
| if (cglInfo == NULL) { |
| J2dRlsTraceLn(J2D_TRACE_ERROR, "OGLSD_SetScratchContext: cgl config info is null"); |
| return NULL; |
| } |
| |
| OGLContext *oglc = cglInfo->context; |
| if (oglc == NULL) { |
| J2dRlsTraceLn(J2D_TRACE_ERROR, "OGLSD_SetScratchContext: ogl context is null"); |
| return NULL; |
| } |
| |
| CGLCtxInfo *ctxinfo = (CGLCtxInfo *)oglc->ctxInfo; |
| |
| JNF_COCOA_ENTER(env); |
| |
| // avoid changing the context's target view whenever possible, since |
| // calling setView causes flickering; as long as our context is current |
| // to some view, it's not necessary to switch to the scratch surface |
| if ([ctxinfo->context view] == nil) { |
| // it seems to be necessary to explicitly flush between context changes |
| OGLContext *currentContext = OGLRenderQueue_GetCurrentContext(); |
| if (currentContext != NULL) { |
| j2d_glFlush(); |
| } |
| |
| if (!CGLSD_MakeCurrentToScratch(env, oglc)) { |
| return NULL; |
| } |
| // make sure our context is current |
| } else if ([NSOpenGLContext currentContext] != ctxinfo->context) { |
| [ctxinfo->context makeCurrentContext]; |
| } |
| |
| if (OGLC_IS_CAP_PRESENT(oglc, CAPS_EXT_FBOBJECT)) { |
| // the GL_EXT_framebuffer_object extension is present, so this call |
| // will ensure that we are bound to the scratch surface (and not |
| // some other framebuffer object) |
| j2d_glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); |
| } |
| |
| JNF_COCOA_EXIT(env); |
| |
| return oglc; |
| } |
| |
| /** |
| * Makes a context current to the given source and destination |
| * surfaces. If there is a problem making the context current, this method |
| * will return NULL; otherwise, returns a pointer to the OGLContext that is |
| * associated with the destination surface. |
| */ |
| OGLContext * |
| OGLSD_MakeOGLContextCurrent(JNIEnv *env, OGLSDOps *srcOps, OGLSDOps *dstOps) |
| { |
| J2dTraceLn(J2D_TRACE_INFO, "OGLSD_MakeOGLContextCurrent"); |
| |
| CGLSDOps *dstCGLOps = (CGLSDOps *)dstOps->privOps; |
| |
| J2dTraceLn4(J2D_TRACE_VERBOSE, " src: %d %p dst: %d %p", srcOps->drawableType, srcOps, dstOps->drawableType, dstOps); |
| |
| OGLContext *oglc = dstCGLOps->configInfo->context; |
| if (oglc == NULL) { |
| J2dRlsTraceLn(J2D_TRACE_ERROR, "OGLSD_MakeOGLContextCurrent: context is null"); |
| return NULL; |
| } |
| |
| CGLCtxInfo *ctxinfo = (CGLCtxInfo *)oglc->ctxInfo; |
| |
| // it seems to be necessary to explicitly flush between context changes |
| OGLContext *currentContext = OGLRenderQueue_GetCurrentContext(); |
| if (currentContext != NULL) { |
| j2d_glFlush(); |
| } |
| |
| if (dstOps->drawableType == OGLSD_FBOBJECT) { |
| // first make sure we have a current context (if the context isn't |
| // already current to some drawable, we will make it current to |
| // its scratch surface) |
| if (oglc != currentContext) { |
| if (!CGLSD_MakeCurrentToScratch(env, oglc)) { |
| return NULL; |
| } |
| } |
| |
| // now bind to the fbobject associated with the destination surface; |
| // this means that all rendering will go into the fbobject destination |
| // (note that we unbind the currently bound texture first; this is |
| // recommended procedure when binding an fbobject) |
| j2d_glBindTexture(GL_TEXTURE_2D, 0); |
| j2d_glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, dstOps->fbobjectID); |
| |
| return oglc; |
| } |
| |
| JNF_COCOA_ENTER(env); |
| |
| // set the current surface |
| if (dstOps->drawableType == OGLSD_PBUFFER) { |
| // REMIND: pbuffers are not fully tested yet... |
| [ctxinfo->context clearDrawable]; |
| [ctxinfo->context makeCurrentContext]; |
| [ctxinfo->context setPixelBuffer: dstCGLOps->pbuffer |
| cubeMapFace: 0 |
| mipMapLevel: 0 |
| currentVirtualScreen: [ctxinfo->context currentVirtualScreen]]; |
| } else { |
| CGLSDOps *cglsdo = (CGLSDOps *)dstOps->privOps; |
| NSView *nsView = (NSView *)cglsdo->peerData; |
| |
| if ([ctxinfo->context view] != nsView) { |
| [ctxinfo->context makeCurrentContext]; |
| [ctxinfo->context setView: nsView]; |
| } |
| } |
| |
| if (OGLC_IS_CAP_PRESENT(oglc, CAPS_EXT_FBOBJECT)) { |
| // the GL_EXT_framebuffer_object extension is present, so we |
| // must bind to the default (windowing system provided) |
| // framebuffer |
| j2d_glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); |
| } |
| |
| if ((srcOps != dstOps) && (srcOps->drawableType == OGLSD_PBUFFER)) { |
| // bind pbuffer to the render texture object (since we are preparing |
| // to copy from the pbuffer) |
| CGLSDOps *srcCGLOps = (CGLSDOps *)srcOps->privOps; |
| j2d_glBindTexture(GL_TEXTURE_2D, srcOps->textureID); |
| [ctxinfo->context |
| setTextureImageToPixelBuffer: srcCGLOps->pbuffer |
| colorBuffer: GL_FRONT]; |
| } |
| |
| JNF_COCOA_EXIT(env); |
| |
| return oglc; |
| } |
| |
| /** |
| * This function initializes a native window surface and caches the window |
| * bounds in the given OGLSDOps. Returns JNI_TRUE if the operation was |
| * successful; JNI_FALSE otherwise. |
| */ |
| jboolean |
| OGLSD_InitOGLWindow(JNIEnv *env, OGLSDOps *oglsdo) |
| { |
| J2dTraceLn(J2D_TRACE_INFO, "OGLSD_InitOGLWindow"); |
| |
| if (oglsdo == NULL) { |
| J2dRlsTraceLn(J2D_TRACE_ERROR, "OGLSD_InitOGLWindow: ops are null"); |
| return JNI_FALSE; |
| } |
| |
| CGLSDOps *cglsdo = (CGLSDOps *)oglsdo->privOps; |
| if (cglsdo == NULL) { |
| J2dRlsTraceLn(J2D_TRACE_ERROR, "OGLSD_InitOGLWindow: cgl ops are null"); |
| return JNI_FALSE; |
| } |
| |
| AWTView *v = cglsdo->peerData; |
| if (v == NULL) { |
| J2dRlsTraceLn(J2D_TRACE_ERROR, "OGLSD_InitOGLWindow: view is invalid"); |
| return JNI_FALSE; |
| } |
| |
| JNF_COCOA_ENTER(env); |
| NSRect surfaceBounds = [v bounds]; |
| oglsdo->drawableType = OGLSD_WINDOW; |
| oglsdo->isOpaque = JNI_TRUE; |
| oglsdo->width = surfaceBounds.size.width; |
| oglsdo->height = surfaceBounds.size.height; |
| JNF_COCOA_EXIT(env); |
| |
| J2dTraceLn2(J2D_TRACE_VERBOSE, " created window: w=%d h=%d", oglsdo->width, oglsdo->height); |
| |
| return JNI_TRUE; |
| } |
| |
| void |
| OGLSD_SwapBuffers(JNIEnv *env, jlong pPeerData) |
| { |
| J2dTraceLn(J2D_TRACE_INFO, "OGLSD_SwapBuffers"); |
| |
| JNF_COCOA_ENTER(env); |
| [[NSOpenGLContext currentContext] flushBuffer]; |
| JNF_COCOA_EXIT(env); |
| } |
| |
| void |
| OGLSD_Flush(JNIEnv *env) |
| { |
| OGLSDOps *dstOps = OGLRenderQueue_GetCurrentDestination(); |
| if (dstOps != NULL) { |
| CGLSDOps *dstCGLOps = (CGLSDOps *)dstOps->privOps; |
| CGLLayer *layer = (CGLLayer*)dstCGLOps->layer; |
| if (layer != NULL) { |
| [JNFRunLoop performOnMainThreadWaiting:NO withBlock:^(){ |
| AWT_ASSERT_APPKIT_THREAD; |
| [layer setNeedsDisplay]; |
| |
| #ifdef REMOTELAYER |
| /* If there's a remote layer (being used for testing) |
| * then we want to have that also receive the texture. |
| * First sync. up its dimensions with that of the layer |
| * we have attached to the local window and tell it that |
| * it also needs to copy the texture. |
| */ |
| if (layer.remoteLayer != nil) { |
| CGLLayer* remoteLayer = layer.remoteLayer; |
| remoteLayer.target = GL_TEXTURE_2D; |
| remoteLayer.textureID = layer.textureID; |
| remoteLayer.textureWidth = layer.textureWidth; |
| remoteLayer.textureHeight = layer.textureHeight; |
| [remoteLayer setNeedsDisplay]; |
| } |
| #endif /* REMOTELAYER */ |
| }]; |
| } |
| } |
| } |
| |
| #pragma mark - |
| #pragma mark "--- CGLSurfaceData methods ---" |
| |
| extern LockFunc OGLSD_Lock; |
| extern GetRasInfoFunc OGLSD_GetRasInfo; |
| extern UnlockFunc OGLSD_Unlock; |
| extern DisposeFunc OGLSD_Dispose; |
| |
| |
| void |
| CGLSD_Dispose(JNIEnv *env, SurfaceDataOps *ops) |
| { |
| OGLSDOps *oglsdo = (OGLSDOps *)ops; |
| jlong pConfigInfo = OGLSD_GetNativeConfigInfo(oglsdo); |
| JNU_CallStaticMethodByName(env, NULL, "sun/java2d/opengl/CGLSurfaceData", |
| "dispose", "(JJ)V", |
| ptr_to_jlong(ops), pConfigInfo); |
| } |
| |
| |
| JNIEXPORT void JNICALL |
| Java_sun_java2d_opengl_CGLSurfaceData_initOps |
| (JNIEnv *env, jobject cglsd, |
| jlong pConfigInfo, jlong pPeerData, jlong layerPtr, |
| jint xoff, jint yoff, jboolean isOpaque) |
| { |
| J2dTraceLn(J2D_TRACE_INFO, "CGLSurfaceData_initOps"); |
| J2dTraceLn1(J2D_TRACE_INFO, " pPeerData=%p", jlong_to_ptr(pPeerData)); |
| J2dTraceLn2(J2D_TRACE_INFO, " xoff=%d, yoff=%d", (int)xoff, (int)yoff); |
| |
| OGLSDOps *oglsdo = (OGLSDOps *) |
| SurfaceData_InitOps(env, cglsd, sizeof(OGLSDOps)); |
| CGLSDOps *cglsdo = (CGLSDOps *)malloc(sizeof(CGLSDOps)); |
| if (cglsdo == NULL) { |
| JNU_ThrowOutOfMemoryError(env, "creating native cgl ops"); |
| return; |
| } |
| |
| oglsdo->privOps = cglsdo; |
| |
| oglsdo->sdOps.Lock = OGLSD_Lock; |
| oglsdo->sdOps.GetRasInfo = OGLSD_GetRasInfo; |
| oglsdo->sdOps.Unlock = OGLSD_Unlock; |
| oglsdo->sdOps.Dispose = CGLSD_Dispose; |
| |
| oglsdo->drawableType = OGLSD_UNDEFINED; |
| oglsdo->activeBuffer = GL_FRONT; |
| oglsdo->needsInit = JNI_TRUE; |
| oglsdo->xOffset = xoff; |
| oglsdo->yOffset = yoff; |
| oglsdo->isOpaque = isOpaque; |
| |
| cglsdo->peerData = (AWTView *)jlong_to_ptr(pPeerData); |
| cglsdo->layer = (CGLLayer *)jlong_to_ptr(layerPtr); |
| cglsdo->configInfo = (CGLGraphicsConfigInfo *)jlong_to_ptr(pConfigInfo); |
| |
| if (cglsdo->configInfo == NULL) { |
| free(cglsdo); |
| JNU_ThrowNullPointerException(env, "Config info is null in initOps"); |
| } |
| } |
| |
| JNIEXPORT void JNICALL |
| Java_sun_java2d_opengl_CGLSurfaceData_clearWindow |
| (JNIEnv *env, jobject cglsd) |
| { |
| J2dTraceLn(J2D_TRACE_INFO, "CGLSurfaceData_clearWindow"); |
| |
| OGLSDOps *oglsdo = (OGLSDOps*) SurfaceData_GetOps(env, cglsd); |
| CGLSDOps *cglsdo = (CGLSDOps*) oglsdo->privOps; |
| |
| cglsdo->peerData = NULL; |
| cglsdo->layer = NULL; |
| } |
| |
| JNIEXPORT jboolean JNICALL |
| Java_sun_java2d_opengl_CGLSurfaceData_initPbuffer |
| (JNIEnv *env, jobject cglsd, |
| jlong pData, jlong pConfigInfo, jboolean isOpaque, |
| jint width, jint height) |
| { |
| J2dTraceLn3(J2D_TRACE_INFO, "CGLSurfaceData_initPbuffer: w=%d h=%d opq=%d", width, height, isOpaque); |
| |
| OGLSDOps *oglsdo = (OGLSDOps *)jlong_to_ptr(pData); |
| if (oglsdo == NULL) { |
| J2dRlsTraceLn(J2D_TRACE_ERROR, "CGLSurfaceData_initPbuffer: ops are null"); |
| return JNI_FALSE; |
| } |
| |
| CGLSDOps *cglsdo = (CGLSDOps *)oglsdo->privOps; |
| if (cglsdo == NULL) { |
| J2dRlsTraceLn(J2D_TRACE_ERROR, "CGLSurfaceData_initPbuffer: cgl ops are null"); |
| return JNI_FALSE; |
| } |
| |
| CGLGraphicsConfigInfo *cglInfo = (CGLGraphicsConfigInfo *) |
| jlong_to_ptr(pConfigInfo); |
| if (cglInfo == NULL) { |
| J2dRlsTraceLn(J2D_TRACE_ERROR, "CGLSurfaceData_initPbuffer: cgl config info is null"); |
| return JNI_FALSE; |
| } |
| |
| // find the maximum allowable texture dimensions (this value ultimately |
| // determines our maximum pbuffer size) |
| int pbMax = 0; |
| j2d_glGetIntegerv(GL_MAX_TEXTURE_SIZE, &pbMax); |
| |
| int pbWidth = 0; |
| int pbHeight = 0; |
| if (OGLC_IS_CAP_PRESENT(cglInfo->context, CAPS_TEXNONPOW2)) { |
| // use non-power-of-two dimensions directly |
| pbWidth = (width <= pbMax) ? width : 0; |
| pbHeight = (height <= pbMax) ? height : 0; |
| } else { |
| // find the appropriate power-of-two dimensions |
| pbWidth = OGLSD_NextPowerOfTwo(width, pbMax); |
| pbHeight = OGLSD_NextPowerOfTwo(height, pbMax); |
| } |
| |
| J2dTraceLn3(J2D_TRACE_VERBOSE, " desired pbuffer dimensions: w=%d h=%d max=%d", pbWidth, pbHeight, pbMax); |
| |
| // if either dimension is 0, we cannot allocate a pbuffer/texture with the |
| // requested dimensions |
| if (pbWidth == 0 || pbHeight == 0) { |
| J2dRlsTraceLn(J2D_TRACE_ERROR, "CGLSurfaceData_initPbuffer: dimensions too large"); |
| return JNI_FALSE; |
| } |
| |
| int format = isOpaque ? GL_RGB : GL_RGBA; |
| |
| JNF_COCOA_ENTER(env); |
| |
| cglsdo->pbuffer = |
| [[NSOpenGLPixelBuffer alloc] |
| initWithTextureTarget: GL_TEXTURE_2D |
| textureInternalFormat: format |
| textureMaxMipMapLevel: 0 |
| pixelsWide: pbWidth |
| pixelsHigh: pbHeight]; |
| if (cglsdo->pbuffer == nil) { |
| J2dRlsTraceLn(J2D_TRACE_ERROR, "CGLSurfaceData_initPbuffer: could not create pbuffer"); |
| return JNI_FALSE; |
| } |
| |
| // make sure the actual dimensions match those that we requested |
| GLsizei actualWidth = [cglsdo->pbuffer pixelsWide]; |
| GLsizei actualHeight = [cglsdo->pbuffer pixelsHigh]; |
| if (actualWidth != pbWidth || actualHeight != pbHeight) { |
| J2dRlsTraceLn2(J2D_TRACE_ERROR, "CGLSurfaceData_initPbuffer: actual (w=%d h=%d) != requested", actualWidth, actualHeight); |
| [cglsdo->pbuffer release]; |
| return JNI_FALSE; |
| } |
| |
| GLuint texID = 0; |
| j2d_glGenTextures(1, &texID); |
| j2d_glBindTexture(GL_TEXTURE_2D, texID); |
| |
| oglsdo->drawableType = OGLSD_PBUFFER; |
| oglsdo->isOpaque = isOpaque; |
| oglsdo->width = width; |
| oglsdo->height = height; |
| oglsdo->textureID = texID; |
| oglsdo->textureWidth = pbWidth; |
| oglsdo->textureHeight = pbHeight; |
| oglsdo->activeBuffer = GL_FRONT; |
| oglsdo->needsInit = JNI_TRUE; |
| |
| OGLSD_INIT_TEXTURE_FILTER(oglsdo, GL_NEAREST); |
| |
| JNF_COCOA_EXIT(env); |
| |
| return JNI_TRUE; |
| } |
| |
| #pragma mark - |
| #pragma mark "--- CGLSurfaceData methods - Mac OS X specific ---" |
| |
| // Must be called on the QFT... |
| JNIEXPORT void JNICALL |
| Java_sun_java2d_opengl_CGLSurfaceData_validate |
| (JNIEnv *env, jobject jsurfacedata, |
| jint xoff, jint yoff, jint width, jint height, jboolean isOpaque) |
| { |
| J2dTraceLn2(J2D_TRACE_INFO, "CGLSurfaceData_validate: w=%d h=%d", width, height); |
| |
| OGLSDOps *oglsdo = (OGLSDOps*)SurfaceData_GetOps(env, jsurfacedata); |
| oglsdo->needsInit = JNI_TRUE; |
| oglsdo->xOffset = xoff; |
| oglsdo->yOffset = yoff; |
| |
| oglsdo->width = width; |
| oglsdo->height = height; |
| oglsdo->isOpaque = isOpaque; |
| |
| if (oglsdo->drawableType == OGLSD_WINDOW) { |
| OGLContext_SetSurfaces(env, ptr_to_jlong(oglsdo), ptr_to_jlong(oglsdo)); |
| |
| // we have to explicitly tell the NSOpenGLContext that its target |
| // drawable has changed size |
| CGLSDOps *cglsdo = (CGLSDOps *)oglsdo->privOps; |
| OGLContext *oglc = cglsdo->configInfo->context; |
| CGLCtxInfo *ctxinfo = (CGLCtxInfo *)oglc->ctxInfo; |
| |
| JNF_COCOA_ENTER(env); |
| [ctxinfo->context update]; |
| JNF_COCOA_EXIT(env); |
| } |
| } |