Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/macosx/native_NOTIOS/sun/java2d/opengl/CGLSurfaceData.m
38829 views
/*1* Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425#import <stdlib.h>26#import <JavaNativeFoundation/JavaNativeFoundation.h>2728#import "sun_java2d_opengl_CGLSurfaceData.h"2930#import "jni.h"31#import "jni_util.h"32#import "OGLRenderQueue.h"33#import "CGLGraphicsConfig.h"34#import "CGLSurfaceData.h"35#import "CGLLayer.h"36#import "ThreadUtilities.h"3738/* JDK's glext.h is already included and will prevent the Apple glext.h39* being included, so define the externs directly40*/41extern void glBindFramebufferEXT(GLenum target, GLuint framebuffer);42extern CGLError CGLTexImageIOSurface2D(43CGLContextObj ctx, GLenum target, GLenum internal_format,44GLsizei width, GLsizei height, GLenum format, GLenum type,45IOSurfaceRef ioSurface, GLuint plane);4647/**48* The methods in this file implement the native windowing system specific49* layer (CGL) for the OpenGL-based Java 2D pipeline.50*/5152#pragma mark -53#pragma mark "--- Mac OS X specific methods for GL pipeline ---"5455// TODO: hack that's called from OGLRenderQueue to test out unlockFocus behavior56#if 057void58OGLSD_UnlockFocus(OGLContext *oglc, OGLSDOps *dstOps)59{60CGLCtxInfo *ctxinfo = (CGLCtxInfo *)oglc->ctxInfo;61CGLSDOps *cglsdo = (CGLSDOps *)dstOps->privOps;62fprintf(stderr, "about to unlock focus: %p %p\n",63cglsdo->peerData, ctxinfo->context);6465NSOpenGLView *nsView = cglsdo->peerData;66if (nsView != NULL) {67JNF_COCOA_ENTER(env);68[nsView unlockFocus];69JNF_COCOA_EXIT(env);70}71}72#endif7374/**75* Makes the given context current to its associated "scratch" surface. If76* the operation is successful, this method will return JNI_TRUE; otherwise,77* returns JNI_FALSE.78*/79static jboolean80CGLSD_MakeCurrentToScratch(JNIEnv *env, OGLContext *oglc)81{82J2dTraceLn(J2D_TRACE_INFO, "CGLSD_MakeCurrentToScratch");8384if (oglc == NULL) {85J2dRlsTraceLn(J2D_TRACE_ERROR,86"CGLSD_MakeCurrentToScratch: context is null");87return JNI_FALSE;88}8990JNF_COCOA_ENTER(env);9192CGLCtxInfo *ctxinfo = (CGLCtxInfo *)oglc->ctxInfo;93#if USE_NSVIEW_FOR_SCRATCH94[ctxinfo->context makeCurrentContext];95#else96[ctxinfo->context clearDrawable];97[ctxinfo->context makeCurrentContext];98[ctxinfo->context setPixelBuffer: ctxinfo->scratchSurface99cubeMapFace: 0100mipMapLevel: 0101currentVirtualScreen: [ctxinfo->context currentVirtualScreen]];102#endif103104JNF_COCOA_EXIT(env);105106return JNI_TRUE;107}108109/**110* This function disposes of any native windowing system resources associated111* with this surface. For instance, if the given OGLSDOps is of type112* OGLSD_PBUFFER, this method implementation will destroy the actual pbuffer113* surface.114*/115void116OGLSD_DestroyOGLSurface(JNIEnv *env, OGLSDOps *oglsdo)117{118J2dTraceLn(J2D_TRACE_INFO, "OGLSD_DestroyOGLSurface");119120JNF_COCOA_ENTER(env);121122CGLSDOps *cglsdo = (CGLSDOps *)oglsdo->privOps;123if (oglsdo->drawableType == OGLSD_PBUFFER) {124if (oglsdo->textureID != 0) {125j2d_glDeleteTextures(1, &oglsdo->textureID);126oglsdo->textureID = 0;127}128if (cglsdo->pbuffer != NULL) {129[cglsdo->pbuffer release];130cglsdo->pbuffer = NULL;131}132} else if (oglsdo->drawableType == OGLSD_WINDOW) {133// detach the NSView from the NSOpenGLContext134CGLGraphicsConfigInfo *cglInfo = cglsdo->configInfo;135OGLContext *oglc = cglInfo->context;136CGLCtxInfo *ctxinfo = (CGLCtxInfo *)oglc->ctxInfo;137[ctxinfo->context clearDrawable];138}139140oglsdo->drawableType = OGLSD_UNDEFINED;141142JNF_COCOA_EXIT(env);143}144145/**146* Makes the given GraphicsConfig's context current to its associated147* "scratch" surface. If there is a problem making the context current,148* this method will return NULL; otherwise, returns a pointer to the149* OGLContext that is associated with the given GraphicsConfig.150*/151OGLContext *152OGLSD_SetScratchSurface(JNIEnv *env, jlong pConfigInfo)153{154J2dTraceLn(J2D_TRACE_INFO, "OGLSD_SetScratchContext");155156CGLGraphicsConfigInfo *cglInfo = (CGLGraphicsConfigInfo *)jlong_to_ptr(pConfigInfo);157if (cglInfo == NULL) {158J2dRlsTraceLn(J2D_TRACE_ERROR, "OGLSD_SetScratchContext: cgl config info is null");159return NULL;160}161162OGLContext *oglc = cglInfo->context;163if (oglc == NULL) {164J2dRlsTraceLn(J2D_TRACE_ERROR, "OGLSD_SetScratchContext: ogl context is null");165return NULL;166}167168CGLCtxInfo *ctxinfo = (CGLCtxInfo *)oglc->ctxInfo;169170JNF_COCOA_ENTER(env);171172// avoid changing the context's target view whenever possible, since173// calling setView causes flickering; as long as our context is current174// to some view, it's not necessary to switch to the scratch surface175if ([ctxinfo->context view] == nil) {176// it seems to be necessary to explicitly flush between context changes177OGLContext *currentContext = OGLRenderQueue_GetCurrentContext();178if (currentContext != NULL) {179j2d_glFlush();180}181182if (!CGLSD_MakeCurrentToScratch(env, oglc)) {183return NULL;184}185// make sure our context is current186} else if ([NSOpenGLContext currentContext] != ctxinfo->context) {187[ctxinfo->context makeCurrentContext];188}189190if (OGLC_IS_CAP_PRESENT(oglc, CAPS_EXT_FBOBJECT)) {191// the GL_EXT_framebuffer_object extension is present, so this call192// will ensure that we are bound to the scratch surface (and not193// some other framebuffer object)194j2d_glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);195}196197JNF_COCOA_EXIT(env);198199return oglc;200}201202/**203* Makes a context current to the given source and destination204* surfaces. If there is a problem making the context current, this method205* will return NULL; otherwise, returns a pointer to the OGLContext that is206* associated with the destination surface.207*/208OGLContext *209OGLSD_MakeOGLContextCurrent(JNIEnv *env, OGLSDOps *srcOps, OGLSDOps *dstOps)210{211J2dTraceLn(J2D_TRACE_INFO, "OGLSD_MakeOGLContextCurrent");212213CGLSDOps *dstCGLOps = (CGLSDOps *)dstOps->privOps;214215J2dTraceLn4(J2D_TRACE_VERBOSE, " src: %d %p dst: %d %p", srcOps->drawableType, srcOps, dstOps->drawableType, dstOps);216217OGLContext *oglc = dstCGLOps->configInfo->context;218if (oglc == NULL) {219J2dRlsTraceLn(J2D_TRACE_ERROR, "OGLSD_MakeOGLContextCurrent: context is null");220return NULL;221}222223CGLCtxInfo *ctxinfo = (CGLCtxInfo *)oglc->ctxInfo;224225// it seems to be necessary to explicitly flush between context changes226OGLContext *currentContext = OGLRenderQueue_GetCurrentContext();227if (currentContext != NULL) {228j2d_glFlush();229}230231if (dstOps->drawableType == OGLSD_FBOBJECT) {232// first make sure we have a current context (if the context isn't233// already current to some drawable, we will make it current to234// its scratch surface)235if (oglc != currentContext) {236if (!CGLSD_MakeCurrentToScratch(env, oglc)) {237return NULL;238}239}240241// now bind to the fbobject associated with the destination surface;242// this means that all rendering will go into the fbobject destination243// (note that we unbind the currently bound texture first; this is244// recommended procedure when binding an fbobject)245j2d_glBindTexture(GL_TEXTURE_2D, 0);246j2d_glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, dstOps->fbobjectID);247248return oglc;249}250251JNF_COCOA_ENTER(env);252253// set the current surface254if (dstOps->drawableType == OGLSD_PBUFFER) {255// REMIND: pbuffers are not fully tested yet...256[ctxinfo->context clearDrawable];257[ctxinfo->context makeCurrentContext];258[ctxinfo->context setPixelBuffer: dstCGLOps->pbuffer259cubeMapFace: 0260mipMapLevel: 0261currentVirtualScreen: [ctxinfo->context currentVirtualScreen]];262} else {263CGLSDOps *cglsdo = (CGLSDOps *)dstOps->privOps;264NSView *nsView = (NSView *)cglsdo->peerData;265266if ([ctxinfo->context view] != nsView) {267[ctxinfo->context makeCurrentContext];268[ctxinfo->context setView: nsView];269}270}271272if (OGLC_IS_CAP_PRESENT(oglc, CAPS_EXT_FBOBJECT)) {273// the GL_EXT_framebuffer_object extension is present, so we274// must bind to the default (windowing system provided)275// framebuffer276j2d_glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);277}278279if ((srcOps != dstOps) && (srcOps->drawableType == OGLSD_PBUFFER)) {280// bind pbuffer to the render texture object (since we are preparing281// to copy from the pbuffer)282CGLSDOps *srcCGLOps = (CGLSDOps *)srcOps->privOps;283j2d_glBindTexture(GL_TEXTURE_2D, srcOps->textureID);284[ctxinfo->context285setTextureImageToPixelBuffer: srcCGLOps->pbuffer286colorBuffer: GL_FRONT];287}288289JNF_COCOA_EXIT(env);290291return oglc;292}293294/**295* This function initializes a native window surface and caches the window296* bounds in the given OGLSDOps. Returns JNI_TRUE if the operation was297* successful; JNI_FALSE otherwise.298*/299jboolean300OGLSD_InitOGLWindow(JNIEnv *env, OGLSDOps *oglsdo)301{302J2dTraceLn(J2D_TRACE_INFO, "OGLSD_InitOGLWindow");303304if (oglsdo == NULL) {305J2dRlsTraceLn(J2D_TRACE_ERROR, "OGLSD_InitOGLWindow: ops are null");306return JNI_FALSE;307}308309CGLSDOps *cglsdo = (CGLSDOps *)oglsdo->privOps;310if (cglsdo == NULL) {311J2dRlsTraceLn(J2D_TRACE_ERROR, "OGLSD_InitOGLWindow: cgl ops are null");312return JNI_FALSE;313}314315AWTView *v = cglsdo->peerData;316if (v == NULL) {317J2dRlsTraceLn(J2D_TRACE_ERROR, "OGLSD_InitOGLWindow: view is invalid");318return JNI_FALSE;319}320321JNF_COCOA_ENTER(env);322NSRect surfaceBounds = [v bounds];323oglsdo->drawableType = OGLSD_WINDOW;324oglsdo->isOpaque = JNI_TRUE;325oglsdo->width = surfaceBounds.size.width;326oglsdo->height = surfaceBounds.size.height;327JNF_COCOA_EXIT(env);328329J2dTraceLn2(J2D_TRACE_VERBOSE, " created window: w=%d h=%d", oglsdo->width, oglsdo->height);330331return JNI_TRUE;332}333334void335OGLSD_SwapBuffers(JNIEnv *env, jlong pPeerData)336{337J2dTraceLn(J2D_TRACE_INFO, "OGLSD_SwapBuffers");338339JNF_COCOA_ENTER(env);340[[NSOpenGLContext currentContext] flushBuffer];341JNF_COCOA_EXIT(env);342}343344void345OGLSD_Flush(JNIEnv *env)346{347OGLSDOps *dstOps = OGLRenderQueue_GetCurrentDestination();348if (dstOps != NULL) {349CGLSDOps *dstCGLOps = (CGLSDOps *)dstOps->privOps;350CGLLayer *layer = (CGLLayer*)dstCGLOps->layer;351if (layer != NULL) {352[JNFRunLoop performOnMainThreadWaiting:NO withBlock:^(){353AWT_ASSERT_APPKIT_THREAD;354[layer setNeedsDisplay];355356#ifdef REMOTELAYER357/* If there's a remote layer (being used for testing)358* then we want to have that also receive the texture.359* First sync. up its dimensions with that of the layer360* we have attached to the local window and tell it that361* it also needs to copy the texture.362*/363if (layer.remoteLayer != nil) {364CGLLayer* remoteLayer = layer.remoteLayer;365remoteLayer.target = GL_TEXTURE_2D;366remoteLayer.textureID = layer.textureID;367remoteLayer.textureWidth = layer.textureWidth;368remoteLayer.textureHeight = layer.textureHeight;369[remoteLayer setNeedsDisplay];370}371#endif /* REMOTELAYER */372}];373}374}375}376377#pragma mark -378#pragma mark "--- CGLSurfaceData methods ---"379380extern LockFunc OGLSD_Lock;381extern GetRasInfoFunc OGLSD_GetRasInfo;382extern UnlockFunc OGLSD_Unlock;383extern DisposeFunc OGLSD_Dispose;384385JNIEXPORT void JNICALL386Java_sun_java2d_opengl_CGLSurfaceData_initOps387(JNIEnv *env, jobject cglsd, jobject gc,388jlong pConfigInfo, jlong pPeerData, jlong layerPtr,389jint xoff, jint yoff, jboolean isOpaque)390{391J2dTraceLn(J2D_TRACE_INFO, "CGLSurfaceData_initOps");392J2dTraceLn1(J2D_TRACE_INFO, " pPeerData=%p", jlong_to_ptr(pPeerData));393J2dTraceLn2(J2D_TRACE_INFO, " xoff=%d, yoff=%d", (int)xoff, (int)yoff);394395gc = (*env)->NewGlobalRef(env, gc);396if (gc == NULL) {397JNU_ThrowOutOfMemoryError(env, "Initialization of SurfaceData failed.");398return;399}400401OGLSDOps *oglsdo = (OGLSDOps *)402SurfaceData_InitOps(env, cglsd, sizeof(OGLSDOps));403if (oglsdo == NULL) {404(*env)->DeleteGlobalRef(env, gc);405JNU_ThrowOutOfMemoryError(env, "Initialization of SurfaceData failed.");406return;407}408// later the graphicsConfig will be used for deallocation of oglsdo409oglsdo->graphicsConfig = gc;410411CGLSDOps *cglsdo = (CGLSDOps *)malloc(sizeof(CGLSDOps));412if (cglsdo == NULL) {413JNU_ThrowOutOfMemoryError(env, "creating native cgl ops");414return;415}416417oglsdo->privOps = cglsdo;418419oglsdo->sdOps.Lock = OGLSD_Lock;420oglsdo->sdOps.GetRasInfo = OGLSD_GetRasInfo;421oglsdo->sdOps.Unlock = OGLSD_Unlock;422oglsdo->sdOps.Dispose = OGLSD_Dispose;423424oglsdo->drawableType = OGLSD_UNDEFINED;425oglsdo->activeBuffer = GL_FRONT;426oglsdo->needsInit = JNI_TRUE;427oglsdo->xOffset = xoff;428oglsdo->yOffset = yoff;429oglsdo->isOpaque = isOpaque;430431cglsdo->peerData = (AWTView *)jlong_to_ptr(pPeerData);432cglsdo->layer = (CGLLayer *)jlong_to_ptr(layerPtr);433cglsdo->configInfo = (CGLGraphicsConfigInfo *)jlong_to_ptr(pConfigInfo);434435if (cglsdo->configInfo == NULL) {436free(cglsdo);437JNU_ThrowNullPointerException(env, "Config info is null in initOps");438}439}440441JNIEXPORT void JNICALL442Java_sun_java2d_opengl_CGLSurfaceData_clearWindow443(JNIEnv *env, jobject cglsd)444{445J2dTraceLn(J2D_TRACE_INFO, "CGLSurfaceData_clearWindow");446447OGLSDOps *oglsdo = (OGLSDOps*) SurfaceData_GetOps(env, cglsd);448CGLSDOps *cglsdo = (CGLSDOps*) oglsdo->privOps;449450cglsdo->peerData = NULL;451cglsdo->layer = NULL;452}453454JNIEXPORT jboolean JNICALL455Java_sun_java2d_opengl_CGLSurfaceData_initPbuffer456(JNIEnv *env, jobject cglsd,457jlong pData, jlong pConfigInfo, jboolean isOpaque,458jint width, jint height)459{460J2dTraceLn3(J2D_TRACE_INFO, "CGLSurfaceData_initPbuffer: w=%d h=%d opq=%d", width, height, isOpaque);461462OGLSDOps *oglsdo = (OGLSDOps *)jlong_to_ptr(pData);463if (oglsdo == NULL) {464J2dRlsTraceLn(J2D_TRACE_ERROR, "CGLSurfaceData_initPbuffer: ops are null");465return JNI_FALSE;466}467468CGLSDOps *cglsdo = (CGLSDOps *)oglsdo->privOps;469if (cglsdo == NULL) {470J2dRlsTraceLn(J2D_TRACE_ERROR, "CGLSurfaceData_initPbuffer: cgl ops are null");471return JNI_FALSE;472}473474CGLGraphicsConfigInfo *cglInfo = (CGLGraphicsConfigInfo *)475jlong_to_ptr(pConfigInfo);476if (cglInfo == NULL) {477J2dRlsTraceLn(J2D_TRACE_ERROR, "CGLSurfaceData_initPbuffer: cgl config info is null");478return JNI_FALSE;479}480481// find the maximum allowable texture dimensions (this value ultimately482// determines our maximum pbuffer size)483int pbMax = 0;484j2d_glGetIntegerv(GL_MAX_TEXTURE_SIZE, &pbMax);485486int pbWidth = 0;487int pbHeight = 0;488if (OGLC_IS_CAP_PRESENT(cglInfo->context, CAPS_TEXNONPOW2)) {489// use non-power-of-two dimensions directly490pbWidth = (width <= pbMax) ? width : 0;491pbHeight = (height <= pbMax) ? height : 0;492} else {493// find the appropriate power-of-two dimensions494pbWidth = OGLSD_NextPowerOfTwo(width, pbMax);495pbHeight = OGLSD_NextPowerOfTwo(height, pbMax);496}497498J2dTraceLn3(J2D_TRACE_VERBOSE, " desired pbuffer dimensions: w=%d h=%d max=%d", pbWidth, pbHeight, pbMax);499500// if either dimension is 0, we cannot allocate a pbuffer/texture with the501// requested dimensions502if (pbWidth == 0 || pbHeight == 0) {503J2dRlsTraceLn(J2D_TRACE_ERROR, "CGLSurfaceData_initPbuffer: dimensions too large");504return JNI_FALSE;505}506507int format = isOpaque ? GL_RGB : GL_RGBA;508509JNF_COCOA_ENTER(env);510511cglsdo->pbuffer =512[[NSOpenGLPixelBuffer alloc]513initWithTextureTarget: GL_TEXTURE_2D514textureInternalFormat: format515textureMaxMipMapLevel: 0516pixelsWide: pbWidth517pixelsHigh: pbHeight];518if (cglsdo->pbuffer == nil) {519J2dRlsTraceLn(J2D_TRACE_ERROR, "CGLSurfaceData_initPbuffer: could not create pbuffer");520return JNI_FALSE;521}522523// make sure the actual dimensions match those that we requested524GLsizei actualWidth = [cglsdo->pbuffer pixelsWide];525GLsizei actualHeight = [cglsdo->pbuffer pixelsHigh];526if (actualWidth != pbWidth || actualHeight != pbHeight) {527J2dRlsTraceLn2(J2D_TRACE_ERROR, "CGLSurfaceData_initPbuffer: actual (w=%d h=%d) != requested", actualWidth, actualHeight);528[cglsdo->pbuffer release];529return JNI_FALSE;530}531532GLuint texID = 0;533j2d_glGenTextures(1, &texID);534j2d_glBindTexture(GL_TEXTURE_2D, texID);535536oglsdo->drawableType = OGLSD_PBUFFER;537oglsdo->isOpaque = isOpaque;538oglsdo->width = width;539oglsdo->height = height;540oglsdo->textureID = texID;541oglsdo->textureWidth = pbWidth;542oglsdo->textureHeight = pbHeight;543oglsdo->activeBuffer = GL_FRONT;544oglsdo->needsInit = JNI_TRUE;545546OGLSD_INIT_TEXTURE_FILTER(oglsdo, GL_NEAREST);547548JNF_COCOA_EXIT(env);549550return JNI_TRUE;551}552553#pragma mark -554#pragma mark "--- CGLSurfaceData methods - Mac OS X specific ---"555556// Must be called on the QFT...557JNIEXPORT void JNICALL558Java_sun_java2d_opengl_CGLSurfaceData_validate559(JNIEnv *env, jobject jsurfacedata,560jint xoff, jint yoff, jint width, jint height, jboolean isOpaque)561{562J2dTraceLn2(J2D_TRACE_INFO, "CGLSurfaceData_validate: w=%d h=%d", width, height);563564OGLSDOps *oglsdo = (OGLSDOps*)SurfaceData_GetOps(env, jsurfacedata);565oglsdo->needsInit = JNI_TRUE;566oglsdo->xOffset = xoff;567oglsdo->yOffset = yoff;568569oglsdo->width = width;570oglsdo->height = height;571oglsdo->isOpaque = isOpaque;572573if (oglsdo->drawableType == OGLSD_WINDOW) {574OGLContext_SetSurfaces(env, ptr_to_jlong(oglsdo), ptr_to_jlong(oglsdo));575576// we have to explicitly tell the NSOpenGLContext that its target577// drawable has changed size578CGLSDOps *cglsdo = (CGLSDOps *)oglsdo->privOps;579OGLContext *oglc = cglsdo->configInfo->context;580CGLCtxInfo *ctxinfo = (CGLCtxInfo *)oglc->ctxInfo;581582JNF_COCOA_ENTER(env);583[ctxinfo->context update];584JNF_COCOA_EXIT(env);585}586}587588589