1 /*
   2  * Copyright (c) 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 #import <stdlib.h>
  27 
  28 #import "sun_java2d_metal_MTLSurfaceData.h"
  29 
  30 #import "jni_util.h"
  31 #import "MTLRenderQueue.h"
  32 #import "MTLGraphicsConfig.h"
  33 #import "MTLSurfaceData.h"
  34 #import "ThreadUtilities.h"
  35 
  36 /**
  37  * The methods in this file implement the native windowing system specific
  38  * layer for the Metal-based Java 2D pipeline.
  39  */
  40 
  41 /**
  42  * Makes the given context current to its associated "scratch" surface.  If
  43  * the operation is successful, this method will return JNI_TRUE; otherwise,
  44  * returns JNI_FALSE.
  45  */
  46 static jboolean
  47 MTLSD_MakeCurrentToScratch(JNIEnv *env, MTLContext *oglc)
  48 {
  49     J2dTraceLn(J2D_TRACE_INFO, "MTLSD_MakeCurrentToScratch");
  50     return JNI_TRUE;
  51 }
  52 
  53 /**
  54  * This function disposes of any native windowing system resources associated
  55  * with this surface.
  56  */
  57 void
  58 MTLSD_DestroyMTLSurface(JNIEnv *env, MTLSDOps *mtlsdo)
  59 {
  60     J2dTraceLn(J2D_TRACE_INFO, "OGLSD_DestroyOGLSurface");
  61 }
  62 
  63 /**
  64  * Returns a pointer (as a jlong) to the native CGLGraphicsConfigInfo
  65  * associated with the given OGLSDOps.  This method can be called from
  66  * shared code to retrieve the native GraphicsConfig data in a platform-
  67  * independent manner.
  68  */
  69 jlong
  70 MTLSD_GetNativeConfigInfo(BMTLSDOps *oglsdo)
  71 {
  72     J2dTraceLn(J2D_TRACE_INFO, "OGLSD_GetNativeConfigInfo");
  73 
  74     return 0;
  75 }
  76 
  77 /**
  78  * Makes the given GraphicsConfig's context current to its associated
  79  * "scratch" surface.  If there is a problem making the context current,
  80  * this method will return NULL; otherwise, returns a pointer to the
  81  * OGLContext that is associated with the given GraphicsConfig.
  82  */
  83 void *
  84 MTLSD_SetScratchSurface(JNIEnv *env, jlong pConfigInfo)
  85 {
  86     J2dTraceLn(J2D_TRACE_INFO, "MTLSD_SetScratchSurface");
  87 
  88 
  89     MTLGraphicsConfigInfo *mtlInfo = (MTLGraphicsConfigInfo *)jlong_to_ptr(pConfigInfo);
  90     if (mtlInfo == NULL) {
  91          J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLSD_SetScratchSurface: mtl config info is null");
  92          return NULL;
  93     }
  94 
  95     MTLContext *mtlc = mtlInfo->context;
  96     if (mtlc == NULL) {
  97         J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLSD_SetScratchContext: mtl context is null");
  98         return NULL;
  99     }
 100     return mtlc;
 101 }
 102 
 103 /**
 104  * Makes a context current to the given source and destination
 105  * surfaces.  If there is a problem making the context current, this method
 106  * will return NULL; otherwise, returns a pointer to the OGLContext that is
 107  * associated with the destination surface.
 108  */
 109 MTLContext *
 110 MTLSD_MakeMTLContextCurrent(JNIEnv *env, BMTLSDOps *srcOps, BMTLSDOps *dstOps)
 111 {
 112     J2dTraceLn(J2D_TRACE_INFO, "MTLSD_MakeMTLContextCurrent");
 113 
 114     MTLSDOps *dstCGLOps = (MTLSDOps *)dstOps->privOps;
 115 
 116     J2dTraceLn4(J2D_TRACE_VERBOSE, "  src: %d %p dst: %d %p", srcOps->drawableType, srcOps, dstOps->drawableType, dstOps);
 117 
 118     MTLContext *mtlc = dstCGLOps->configInfo->context;
 119     if (mtlc == NULL) {
 120         J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLSD_MakeOGLContextCurrent: context is null");
 121         return NULL;
 122     }
 123 
 124     // it seems to be necessary to explicitly flush between context changes
 125     MTLContext *currentContext = MTLRenderQueue_GetCurrentContext();
 126 
 127     if (dstOps->drawableType == MTLSD_FBOBJECT) {
 128         // first make sure we have a current context (if the context isn't
 129         // already current to some drawable, we will make it current to
 130         // its scratch surface)
 131         if (mtlc != currentContext) {
 132             if (!MTLSD_MakeCurrentToScratch(env, dstOps)) {
 133                 return NULL;
 134             }
 135         }
 136 
 137     }
 138     return mtlc;
 139 }
 140 
 141 /**
 142  * This function initializes a native window surface and caches the window
 143  * bounds in the given OGLSDOps.  Returns JNI_TRUE if the operation was
 144  * successful; JNI_FALSE otherwise.
 145  */
 146 jboolean
 147 MTLSD_InitMTLWindow(JNIEnv *env, MTLSDOps *oglsdo)
 148 {
 149     J2dTraceLn(J2D_TRACE_INFO, "MTLSD_InitMTLWindow");
 150 
 151     return JNI_TRUE;
 152 }
 153 
 154 void
 155 MTLSD_SwapBuffers(JNIEnv *env, jlong pPeerData)
 156 {
 157     J2dTraceLn(J2D_TRACE_INFO, "OGLSD_SwapBuffers");
 158 }
 159 
 160 void
 161 MTLSD_Flush(JNIEnv *env)
 162 {
 163 //fprintf(stderr, "MTLSD_Flush\n");
 164     BMTLSDOps *dstOps = MTLRenderQueue_GetCurrentDestination();
 165     if (dstOps != NULL) {
 166         MTLSDOps *dstCGLOps = (MTLSDOps *)dstOps->privOps;
 167         MTLLayer *layer = (MTLLayer*)dstCGLOps->layer;
 168         if (layer != NULL) {
 169             [JNFRunLoop performOnMainThreadWaiting:NO withBlock:^(){
 170                 [layer blitTexture];
 171             }];
 172         }
 173     } else {
 174  //   fprintf(stderr, "MTLSD_Flush: dstOps=NULL\n");
 175     }
 176 }
 177 
 178 #pragma mark -
 179 #pragma mark "--- CGLSurfaceData methods ---"
 180 
 181 extern LockFunc        MTLSD_Lock;
 182 extern GetRasInfoFunc  MTLSD_GetRasInfo;
 183 extern UnlockFunc      MTLSD_Unlock;
 184 
 185 
 186 JNIEXPORT void JNICALL
 187 Java_sun_java2d_metal_MTLSurfaceData_initOps
 188     (JNIEnv *env, jobject cglsd,
 189      jlong pConfigInfo, jlong pPeerData, jlong layerPtr,
 190      jint xoff, jint yoff, jboolean isOpaque)
 191 {
 192     J2dTraceLn(J2D_TRACE_INFO, "MTLSurfaceData_initOps");
 193     J2dTraceLn1(J2D_TRACE_INFO, "  pPeerData=%p", jlong_to_ptr(pPeerData));
 194     J2dTraceLn2(J2D_TRACE_INFO, "  xoff=%d, yoff=%d", (int)xoff, (int)yoff);
 195 
 196 
 197     BMTLSDOps *bmtlsdo = (BMTLSDOps *)
 198         SurfaceData_InitOps(env, cglsd, sizeof(BMTLSDOps));
 199     MTLSDOps *mtlsdo = (MTLSDOps *)malloc(sizeof(MTLSDOps));
 200     if (mtlsdo == NULL) {
 201         JNU_ThrowOutOfMemoryError(env, "creating native cgl ops");
 202         return;
 203     }
 204 
 205     bmtlsdo->privOps = mtlsdo;
 206 
 207     bmtlsdo->sdOps.Lock               = MTLSD_Lock;
 208     bmtlsdo->sdOps.GetRasInfo         = MTLSD_GetRasInfo;
 209     bmtlsdo->sdOps.Unlock             = MTLSD_Unlock;
 210     bmtlsdo->sdOps.Dispose            = MTLSD_Dispose;
 211 
 212     bmtlsdo->drawableType = MTLSD_UNDEFINED;
 213     bmtlsdo->needsInit = JNI_TRUE;
 214     bmtlsdo->xOffset = xoff;
 215     bmtlsdo->yOffset = yoff;
 216     bmtlsdo->isOpaque = isOpaque;
 217 
 218     mtlsdo->peerData = (AWTView *)jlong_to_ptr(pPeerData);
 219     mtlsdo->layer = (MTLLayer *)jlong_to_ptr(layerPtr);
 220     mtlsdo->configInfo = (MTLGraphicsConfigInfo *)jlong_to_ptr(pConfigInfo);
 221 
 222     if (mtlsdo->configInfo == NULL) {
 223         free(mtlsdo);
 224         JNU_ThrowNullPointerException(env, "Config info is null in initOps");
 225     }
 226 }
 227 
 228 JNIEXPORT void JNICALL
 229 Java_sun_java2d_metal_MTLSurfaceData_clearWindow
 230 (JNIEnv *env, jobject cglsd)
 231 {
 232     J2dTraceLn(J2D_TRACE_INFO, "CGLSurfaceData_clearWindow");
 233 
 234     BMTLSDOps *mtlsdo = (MTLSDOps*) SurfaceData_GetOps(env, cglsd);
 235     MTLSDOps *cglsdo = (MTLSDOps*) mtlsdo->privOps;
 236 
 237     cglsdo->peerData = NULL;
 238     cglsdo->layer = NULL;
 239 }
 240 
 241 #pragma mark -
 242 #pragma mark "--- CGLSurfaceData methods - Mac OS X specific ---"
 243 
 244 // Must be called on the QFT...
 245 JNIEXPORT void JNICALL
 246 Java_sun_java2d_metal_MTLSurfaceData_validate
 247     (JNIEnv *env, jobject jsurfacedata,
 248      jint xoff, jint yoff, jint width, jint height, jboolean isOpaque)
 249 {
 250     J2dTraceLn2(J2D_TRACE_INFO, "MTLLSurfaceData_validate: w=%d h=%d", width, height);
 251 
 252     BMTLSDOps *mtlsdo = (BMTLSDOps*)SurfaceData_GetOps(env, jsurfacedata);
 253     mtlsdo->needsInit = JNI_TRUE;
 254     mtlsdo->xOffset = xoff;
 255     mtlsdo->yOffset = yoff;
 256 
 257     mtlsdo->width = width;
 258     mtlsdo->height = height;
 259     mtlsdo->isOpaque = isOpaque;
 260 
 261     if (mtlsdo->drawableType == MTLSD_WINDOW) {
 262         MTLContext_SetSurfaces(env, ptr_to_jlong(mtlsdo), ptr_to_jlong(mtlsdo));
 263 
 264         // we have to explicitly tell the NSOpenGLContext that its target
 265         // drawable has changed size
 266         MTLSDOps *cglsdo = (MTLSDOps *)mtlsdo->privOps;
 267         MTLContext *mtlc = cglsdo->configInfo->context;
 268 
 269     }
 270 }