Path: blob/master/src/java.desktop/macosx/native/libawt_lwawt/java2d/opengl/CGLSurfaceData.m
41159 views
/*1* Copyright (c) 2011, 2019, 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>2627#import "sun_java2d_opengl_CGLSurfaceData.h"2829#import "JNIUtilities.h"30#import "OGLRenderQueue.h"31#import "CGLGraphicsConfig.h"32#import "CGLSurfaceData.h"33#import "ThreadUtilities.h"3435/* JDK's glext.h is already included and will prevent the Apple glext.h36* being included, so define the externs directly37*/38extern void glBindFramebufferEXT(GLenum target, GLuint framebuffer);39extern CGLError CGLTexImageIOSurface2D(40CGLContextObj ctx, GLenum target, GLenum internal_format,41GLsizei width, GLsizei height, GLenum format, GLenum type,42IOSurfaceRef ioSurface, GLuint plane);4344/**45* The methods in this file implement the native windowing system specific46* layer (CGL) for the OpenGL-based Java 2D pipeline.47*/4849#pragma mark -50#pragma mark "--- Mac OS X specific methods for GL pipeline ---"5152// TODO: hack that's called from OGLRenderQueue to test out unlockFocus behavior53#if 054void55OGLSD_UnlockFocus(OGLContext *oglc, OGLSDOps *dstOps)56{57CGLCtxInfo *ctxinfo = (CGLCtxInfo *)oglc->ctxInfo;58CGLSDOps *cglsdo = (CGLSDOps *)dstOps->privOps;59fprintf(stderr, "about to unlock focus: %p %p\n",60cglsdo->peerData, ctxinfo->context);6162NSOpenGLView *nsView = cglsdo->peerData;63if (nsView != NULL) {64JNI_COCOA_ENTER(env);65[nsView unlockFocus];66JNI_COCOA_EXIT(env);67}68}69#endif7071/**72* Makes the given context current to its associated "scratch" surface. If73* the operation is successful, this method will return JNI_TRUE; otherwise,74* returns JNI_FALSE.75*/76static jboolean77CGLSD_MakeCurrentToScratch(JNIEnv *env, OGLContext *oglc)78{79J2dTraceLn(J2D_TRACE_INFO, "CGLSD_MakeCurrentToScratch");8081if (oglc == NULL) {82J2dRlsTraceLn(J2D_TRACE_ERROR,83"CGLSD_MakeCurrentToScratch: context is null");84return JNI_FALSE;85}8687JNI_COCOA_ENTER(env);8889CGLCtxInfo *ctxinfo = (CGLCtxInfo *)oglc->ctxInfo;90#if USE_NSVIEW_FOR_SCRATCH91[ctxinfo->context makeCurrentContext];92#else93[ctxinfo->context clearDrawable];94[ctxinfo->context makeCurrentContext];95[ctxinfo->context setPixelBuffer: ctxinfo->scratchSurface96cubeMapFace: 097mipMapLevel: 098currentVirtualScreen: [ctxinfo->context currentVirtualScreen]];99#endif100101JNI_COCOA_EXIT(env);102103return JNI_TRUE;104}105106/**107* This function disposes of any native windowing system resources associated108* with this surface.109*/110void111OGLSD_DestroyOGLSurface(JNIEnv *env, OGLSDOps *oglsdo)112{113J2dTraceLn(J2D_TRACE_INFO, "OGLSD_DestroyOGLSurface");114115JNI_COCOA_ENTER(env);116117CGLSDOps *cglsdo = (CGLSDOps *)oglsdo->privOps;118if (oglsdo->drawableType == OGLSD_WINDOW) {119// detach the NSView from the NSOpenGLContext120CGLGraphicsConfigInfo *cglInfo = cglsdo->configInfo;121OGLContext *oglc = cglInfo->context;122CGLCtxInfo *ctxinfo = (CGLCtxInfo *)oglc->ctxInfo;123[ctxinfo->context clearDrawable];124}125126oglsdo->drawableType = OGLSD_UNDEFINED;127128JNI_COCOA_EXIT(env);129}130131/**132* Makes the given GraphicsConfig's context current to its associated133* "scratch" surface. If there is a problem making the context current,134* this method will return NULL; otherwise, returns a pointer to the135* OGLContext that is associated with the given GraphicsConfig.136*/137OGLContext *138OGLSD_SetScratchSurface(JNIEnv *env, jlong pConfigInfo)139{140J2dTraceLn(J2D_TRACE_INFO, "OGLSD_SetScratchContext");141142CGLGraphicsConfigInfo *cglInfo = (CGLGraphicsConfigInfo *)jlong_to_ptr(pConfigInfo);143if (cglInfo == NULL) {144J2dRlsTraceLn(J2D_TRACE_ERROR, "OGLSD_SetScratchContext: cgl config info is null");145return NULL;146}147148OGLContext *oglc = cglInfo->context;149if (oglc == NULL) {150J2dRlsTraceLn(J2D_TRACE_ERROR, "OGLSD_SetScratchContext: ogl context is null");151return NULL;152}153154CGLCtxInfo *ctxinfo = (CGLCtxInfo *)oglc->ctxInfo;155156JNI_COCOA_ENTER(env);157158// avoid changing the context's target view whenever possible, since159// calling setView causes flickering; as long as our context is current160// to some view, it's not necessary to switch to the scratch surface161if ([ctxinfo->context view] == nil) {162// it seems to be necessary to explicitly flush between context changes163OGLContext *currentContext = OGLRenderQueue_GetCurrentContext();164if (currentContext != NULL) {165j2d_glFlush();166}167168if (!CGLSD_MakeCurrentToScratch(env, oglc)) {169return NULL;170}171// make sure our context is current172} else if ([NSOpenGLContext currentContext] != ctxinfo->context) {173[ctxinfo->context makeCurrentContext];174}175176if (OGLC_IS_CAP_PRESENT(oglc, CAPS_EXT_FBOBJECT)) {177// the GL_EXT_framebuffer_object extension is present, so this call178// will ensure that we are bound to the scratch surface (and not179// some other framebuffer object)180j2d_glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);181}182183JNI_COCOA_EXIT(env);184185return oglc;186}187188/**189* Makes a context current to the given source and destination190* surfaces. If there is a problem making the context current, this method191* will return NULL; otherwise, returns a pointer to the OGLContext that is192* associated with the destination surface.193*/194OGLContext *195OGLSD_MakeOGLContextCurrent(JNIEnv *env, OGLSDOps *srcOps, OGLSDOps *dstOps)196{197J2dTraceLn(J2D_TRACE_INFO, "OGLSD_MakeOGLContextCurrent");198199CGLSDOps *dstCGLOps = (CGLSDOps *)dstOps->privOps;200201J2dTraceLn4(J2D_TRACE_VERBOSE, " src: %d %p dst: %d %p", srcOps->drawableType, srcOps, dstOps->drawableType, dstOps);202203OGLContext *oglc = dstCGLOps->configInfo->context;204if (oglc == NULL) {205J2dRlsTraceLn(J2D_TRACE_ERROR, "OGLSD_MakeOGLContextCurrent: context is null");206return NULL;207}208209CGLCtxInfo *ctxinfo = (CGLCtxInfo *)oglc->ctxInfo;210211// it seems to be necessary to explicitly flush between context changes212OGLContext *currentContext = OGLRenderQueue_GetCurrentContext();213if (currentContext != NULL) {214j2d_glFlush();215}216217if (dstOps->drawableType == OGLSD_FBOBJECT) {218// first make sure we have a current context (if the context isn't219// already current to some drawable, we will make it current to220// its scratch surface)221if (oglc != currentContext) {222if (!CGLSD_MakeCurrentToScratch(env, oglc)) {223return NULL;224}225}226227// now bind to the fbobject associated with the destination surface;228// this means that all rendering will go into the fbobject destination229// (note that we unbind the currently bound texture first; this is230// recommended procedure when binding an fbobject)231j2d_glBindTexture(GL_TEXTURE_2D, 0);232j2d_glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, dstOps->fbobjectID);233234return oglc;235}236237JNI_COCOA_ENTER(env);238239CGLSDOps *cglsdo = (CGLSDOps *)dstOps->privOps;240NSView *nsView = (NSView *)cglsdo->peerData;241242if ([ctxinfo->context view] != nsView) {243[ctxinfo->context makeCurrentContext];244[ctxinfo->context setView: nsView];245}246247if (OGLC_IS_CAP_PRESENT(oglc, CAPS_EXT_FBOBJECT)) {248// the GL_EXT_framebuffer_object extension is present, so we249// must bind to the default (windowing system provided)250// framebuffer251j2d_glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);252}253254JNI_COCOA_EXIT(env);255256return oglc;257}258259/**260* This function initializes a native window surface and caches the window261* bounds in the given OGLSDOps. Returns JNI_TRUE if the operation was262* successful; JNI_FALSE otherwise.263*/264jboolean265OGLSD_InitOGLWindow(JNIEnv *env, OGLSDOps *oglsdo)266{267J2dTraceLn(J2D_TRACE_INFO, "OGLSD_InitOGLWindow");268269if (oglsdo == NULL) {270J2dRlsTraceLn(J2D_TRACE_ERROR, "OGLSD_InitOGLWindow: ops are null");271return JNI_FALSE;272}273274CGLSDOps *cglsdo = (CGLSDOps *)oglsdo->privOps;275if (cglsdo == NULL) {276J2dRlsTraceLn(J2D_TRACE_ERROR, "OGLSD_InitOGLWindow: cgl ops are null");277return JNI_FALSE;278}279280AWTView *v = cglsdo->peerData;281if (v == NULL) {282J2dRlsTraceLn(J2D_TRACE_ERROR, "OGLSD_InitOGLWindow: view is invalid");283return JNI_FALSE;284}285286JNI_COCOA_ENTER(env);287NSRect surfaceBounds = [v bounds];288oglsdo->drawableType = OGLSD_WINDOW;289oglsdo->isOpaque = JNI_TRUE;290oglsdo->width = surfaceBounds.size.width;291oglsdo->height = surfaceBounds.size.height;292JNI_COCOA_EXIT(env);293294J2dTraceLn2(J2D_TRACE_VERBOSE, " created window: w=%d h=%d", oglsdo->width, oglsdo->height);295296return JNI_TRUE;297}298299void300OGLSD_SwapBuffers(JNIEnv *env, jlong pPeerData)301{302J2dTraceLn(J2D_TRACE_INFO, "OGLSD_SwapBuffers");303304JNI_COCOA_ENTER(env);305[[NSOpenGLContext currentContext] flushBuffer];306JNI_COCOA_EXIT(env);307}308309void310OGLSD_Flush(JNIEnv *env)311{312OGLSDOps *dstOps = OGLRenderQueue_GetCurrentDestination();313if (dstOps != NULL) {314CGLSDOps *dstCGLOps = (CGLSDOps *)dstOps->privOps;315CGLLayer *layer = (CGLLayer*)dstCGLOps->layer;316if (layer != NULL) {317[ThreadUtilities performOnMainThreadWaiting:NO block:^(){318AWT_ASSERT_APPKIT_THREAD;319[layer setNeedsDisplay];320}];321}322}323}324325#pragma mark -326#pragma mark "--- CGLSurfaceData methods ---"327328extern LockFunc OGLSD_Lock;329extern GetRasInfoFunc OGLSD_GetRasInfo;330extern UnlockFunc OGLSD_Unlock;331extern DisposeFunc OGLSD_Dispose;332333JNIEXPORT void JNICALL334Java_sun_java2d_opengl_CGLSurfaceData_initOps335(JNIEnv *env, jobject cglsd, jobject gc,336jlong pConfigInfo, jlong pPeerData, jlong layerPtr,337jint xoff, jint yoff, jboolean isOpaque)338{339J2dTraceLn(J2D_TRACE_INFO, "CGLSurfaceData_initOps");340J2dTraceLn1(J2D_TRACE_INFO, " pPeerData=%p", jlong_to_ptr(pPeerData));341J2dTraceLn2(J2D_TRACE_INFO, " xoff=%d, yoff=%d", (int)xoff, (int)yoff);342343gc = (*env)->NewGlobalRef(env, gc);344if (gc == NULL) {345JNU_ThrowOutOfMemoryError(env, "Initialization of SurfaceData failed.");346return;347}348349OGLSDOps *oglsdo = (OGLSDOps *)350SurfaceData_InitOps(env, cglsd, sizeof(OGLSDOps));351if (oglsdo == NULL) {352(*env)->DeleteGlobalRef(env, gc);353JNU_ThrowOutOfMemoryError(env, "Initialization of SurfaceData failed.");354return;355}356// later the graphicsConfig will be used for deallocation of oglsdo357oglsdo->graphicsConfig = gc;358359CGLSDOps *cglsdo = (CGLSDOps *)malloc(sizeof(CGLSDOps));360if (cglsdo == NULL) {361JNU_ThrowOutOfMemoryError(env, "creating native cgl ops");362return;363}364365oglsdo->privOps = cglsdo;366367oglsdo->sdOps.Lock = OGLSD_Lock;368oglsdo->sdOps.GetRasInfo = OGLSD_GetRasInfo;369oglsdo->sdOps.Unlock = OGLSD_Unlock;370oglsdo->sdOps.Dispose = OGLSD_Dispose;371372oglsdo->drawableType = OGLSD_UNDEFINED;373oglsdo->activeBuffer = GL_FRONT;374oglsdo->needsInit = JNI_TRUE;375oglsdo->xOffset = xoff;376oglsdo->yOffset = yoff;377oglsdo->isOpaque = isOpaque;378379cglsdo->peerData = (AWTView *)jlong_to_ptr(pPeerData);380cglsdo->layer = (CGLLayer *)jlong_to_ptr(layerPtr);381cglsdo->configInfo = (CGLGraphicsConfigInfo *)jlong_to_ptr(pConfigInfo);382383if (cglsdo->configInfo == NULL) {384free(cglsdo);385JNU_ThrowNullPointerException(env, "Config info is null in initOps");386}387}388389JNIEXPORT void JNICALL390Java_sun_java2d_opengl_CGLSurfaceData_clearWindow391(JNIEnv *env, jobject cglsd)392{393J2dTraceLn(J2D_TRACE_INFO, "CGLSurfaceData_clearWindow");394395OGLSDOps *oglsdo = (OGLSDOps*) SurfaceData_GetOps(env, cglsd);396CGLSDOps *cglsdo = (CGLSDOps*) oglsdo->privOps;397398cglsdo->peerData = NULL;399cglsdo->layer = NULL;400}401402403