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 #include "jlong.h"
  36 
  37 /**
  38  * The following methods are implemented in the windowing system (i.e. GLX
  39  * and WGL) source files.
  40  */
  41 extern jlong MTLSD_GetNativeConfigInfo(BMTLSDOps *mtlsdo);
  42 extern jboolean MTLSD_InitMTLWindow(JNIEnv *env, MTLSDOps *mtlsdo);
  43 extern void MTLSD_DestroyMTLSurface(JNIEnv *env, MTLSDOps *mtlsdo);
  44 
  45 void MTLSD_SetNativeDimensions(JNIEnv *env, BMTLSDOps *mtlsdo, jint w, jint h);
  46 
  47 /**
  48  * This table contains the "pixel formats" for all system memory surfaces
  49  * that OpenGL is capable of handling, indexed by the "PF_" constants defined
  50  * in MTLSurfaceData.java.  These pixel formats contain information that is
  51  * passed to OpenGL when copying from a system memory ("Sw") surface to
  52  * an OpenGL "Surface" (via glDrawPixels()) or "Texture" (via glTexImage2D()).
  53  */
  54 MTLPixelFormat MTPixelFormats[] = {};
  55 
  56 /**
  57  * Given a starting value and a maximum limit, returns the first power-of-two
  58  * greater than the starting value.  If the resulting value is greater than
  59  * the maximum limit, zero is returned.
  60  */
  61 jint
  62 MTLSD_NextPowerOfTwo(jint val, jint max)
  63 {
  64     jint i;
  65 
  66     if (val > max) {
  67         return 0;
  68     }
  69 
  70     for (i = 1; i < val; i *= 2);
  71 
  72     return i;
  73 }
  74 
  75 /**
  76  * Returns true if both given dimensions are a power of two.
  77  */
  78 static jboolean
  79 MTLSD_IsPowerOfTwo(jint width, jint height)
  80 {
  81     return (((width & (width-1)) | (height & (height-1))) == 0);
  82 }
  83 
  84 /**
  85  * Initializes an MTL texture, using the given width and height as
  86  * a guide.
  87  */
  88 JNIEXPORT jboolean JNICALL
  89 Java_sun_java2d_metal_MTLSurfaceData_initTexture
  90     (JNIEnv *env, jobject mtlsd,
  91      jlong pData, jboolean isOpaque,
  92      jboolean texNonPow2, jboolean texRect,
  93      jint width, jint height)
  94 {
  95     BMTLSDOps *bmtlsdo = (BMTLSDOps *)jlong_to_ptr(pData);
  96     J2dTraceLn3(J2D_TRACE_INFO, "MTLSurfaceData_initTexture: w=%d h=%d p=%p", width, height, bmtlsdo);
  97 
  98     if (bmtlsdo == NULL) {
  99         J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLSurfaceData_initTexture: ops are null");
 100         return JNI_FALSE;
 101     }
 102 
 103     if (width <= 0 || height <= 0) {
 104         J2dRlsTraceLn2(J2D_TRACE_ERROR, "MTLSurfaceData_initTexture: texture dimensions is incorrect, w=%d, h=%d", width, height);
 105         return JNI_FALSE;
 106     }
 107 
 108     MTLSDOps *mtlsdo = (MTLSDOps *)bmtlsdo->privOps;
 109     if (mtlsdo == NULL) {
 110         J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLSurfaceData_initTexture: MTLSDOps are null");
 111         return JNI_FALSE;
 112     }
 113 
 114     if (mtlsdo->configInfo == NULL || mtlsdo->configInfo->context == NULL) {
 115         J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLSurfaceData_initTexture: MTLSDOps wasn't initialized (context is null)");
 116         return JNI_FALSE;
 117     }
 118 
 119     MTLContext* ctx = mtlsdo->configInfo->context;
 120 
 121     MTLTextureDescriptor *textureDescriptor = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat: MTLPixelFormatBGRA8Unorm width: width height: height mipmapped: NO];
 122     bmtlsdo->pTexture = [[ctx.device newTextureWithDescriptor: textureDescriptor] retain];
 123     bmtlsdo->isOpaque = isOpaque;
 124     bmtlsdo->xOffset = 0;
 125     bmtlsdo->yOffset = 0;
 126     bmtlsdo->width = width;
 127     bmtlsdo->height = height;
 128     bmtlsdo->textureWidth = width;
 129     bmtlsdo->textureHeight = height;
 130     bmtlsdo->textureTarget = -1;
 131     bmtlsdo->drawableType = MTLSD_TEXTURE;
 132 
 133     MTLSD_SetNativeDimensions(env, bmtlsdo, width, width);
 134     J2dTraceLn4(J2D_TRACE_VERBOSE, "\tcreated MTLTexture [texture]: w=%d h=%d bp=%p [tex=%p]", width, height, bmtlsdo, bmtlsdo->pTexture);
 135 
 136     return JNI_TRUE;
 137 }
 138 
 139 /**
 140  * Initializes a framebuffer object, using the given width and height as
 141  * a guide.  See MTLSD_InitTextureObject() and MTLSD_initRTexture()
 142  * for more information.
 143  */
 144 JNIEXPORT jboolean JNICALL
 145 Java_sun_java2d_metal_MTLSurfaceData_initRTexture
 146     (JNIEnv *env, jobject mtlsd,
 147      jlong pData, jboolean isOpaque,
 148      jboolean texNonPow2, jboolean texRect,
 149      jint width, jint height)
 150 {
 151 
 152     BMTLSDOps *bmtlsdo = (BMTLSDOps *)jlong_to_ptr(pData);
 153 
 154     if (bmtlsdo == NULL) {
 155         J2dRlsTraceLn(J2D_TRACE_ERROR,
 156             "MTLSurfaceData_initRTexture: BMTLSDOps are null");
 157         return JNI_FALSE;
 158     }
 159 
 160     MTLSDOps *mtlsdo = (MTLSDOps *)bmtlsdo->privOps;
 161 
 162     if (mtlsdo == NULL) {
 163         J2dRlsTraceLn(J2D_TRACE_ERROR,
 164             "MTLSurfaceData_initRTexture: MTLSDOps are null");
 165         return JNI_FALSE;
 166     }
 167 
 168     if (mtlsdo->configInfo == NULL || mtlsdo->configInfo->context == NULL) {
 169         J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLSurfaceData_initRTexture: MTLSDOps wasn't initialized (context is null)");
 170         return JNI_FALSE;
 171     }
 172 
 173     const MTLContext* ctx = mtlsdo->configInfo->context;
 174     MTLTextureDescriptor *textureDescriptor = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat: MTLPixelFormatBGRA8Unorm width: width height: height mipmapped: NO];
 175     bmtlsdo->pTexture = [[ctx.device newTextureWithDescriptor: textureDescriptor] retain];;
 176 
 177     bmtlsdo->isOpaque = isOpaque;
 178     bmtlsdo->xOffset = 0;
 179     bmtlsdo->yOffset = 0;
 180     bmtlsdo->width = width;
 181     bmtlsdo->height = height;
 182     bmtlsdo->textureWidth = width;
 183     bmtlsdo->textureHeight = height;
 184     bmtlsdo->textureTarget = -1;
 185     bmtlsdo->drawableType = MTLSD_RT_TEXTURE;
 186 
 187     MTLSD_SetNativeDimensions(env, bmtlsdo, width, width);
 188     J2dTraceLn4(J2D_TRACE_VERBOSE, "\tcreated MTLTexture [FBObject]: w=%d h=%d bp=%p [tex=%p]", width, height, bmtlsdo, bmtlsdo->pTexture);
 189 
 190     return JNI_TRUE;
 191 }
 192 
 193 /**
 194  * Initializes a surface in the backbuffer of a given double-buffered
 195  * onscreen window for use in a BufferStrategy.Flip situation.  The bounds of
 196  * the backbuffer surface should always be kept in sync with the bounds of
 197  * the underlying native window.
 198  */
 199 JNIEXPORT jboolean JNICALL
 200 Java_sun_java2d_metal_MTLSurfaceData_initFlipBackbuffer
 201     (JNIEnv *env, jobject mtlsd,
 202      jlong pData)
 203 {
 204     //TODO
 205     J2dTraceNotImplPrimitive("MTLSurfaceData_initFlipBackbuffer");
 206     MTLSDOps *mtlsdo = (MTLSDOps *)jlong_to_ptr(pData);
 207 
 208     J2dTraceLn(J2D_TRACE_INFO, "MTLSurfaceData_initFlipBackbuffer");
 209     return JNI_TRUE;
 210 }
 211 
 212 JNIEXPORT jint JNICALL
 213 Java_sun_java2d_metal_MTLSurfaceData_getTextureTarget
 214     (JNIEnv *env, jobject mtlsd,
 215      jlong pData)
 216 {
 217     //TODO
 218     J2dTraceNotImplPrimitive("MTLSurfaceData_getTextureTarget");
 219     MTLSDOps *mtlsdo = (MTLSDOps *)jlong_to_ptr(pData);
 220 
 221     J2dTraceLn(J2D_TRACE_INFO, "MTLSurfaceData_getTextureTarget");
 222 
 223     return 0;
 224 }
 225 
 226 JNIEXPORT jint JNICALL
 227 Java_sun_java2d_metal_MTLSurfaceData_getTextureID
 228     (JNIEnv *env, jobject mtlsd,
 229      jlong pData)
 230 {
 231     //TODO
 232     J2dTraceNotImplPrimitive("MTLSurfaceData_getTextureID");
 233     return 0;
 234 }
 235 
 236 /**
 237  * Initializes nativeWidth/Height fields of the surfaceData object with
 238  * passed arguments.
 239  */
 240 void
 241 MTLSD_SetNativeDimensions(JNIEnv *env, BMTLSDOps *mtlsdo,
 242                           jint width, jint height)
 243 {
 244     jobject sdObject;
 245 
 246     sdObject = (*env)->NewLocalRef(env, mtlsdo->sdOps.sdObject);
 247     if (sdObject == NULL) {
 248         return;
 249     }
 250 
 251     JNU_SetFieldByName(env, NULL, sdObject, "nativeWidth", "I", width);
 252     if (!((*env)->ExceptionOccurred(env))) {
 253         JNU_SetFieldByName(env, NULL, sdObject, "nativeHeight", "I", height);
 254     }
 255 
 256     (*env)->DeleteLocalRef(env, sdObject);
 257 }
 258 
 259 /**
 260  * Deletes native OpenGL resources associated with this surface.
 261  */
 262 void
 263 MTLSD_Delete(JNIEnv *env, BMTLSDOps *mtlsdo)
 264 {
 265     //TODO
 266     J2dTraceNotImplPrimitive("MTLSD_Delete");
 267     J2dTraceLn1(J2D_TRACE_INFO, "MTLSD_Delete: type=%d",
 268                 mtlsdo->drawableType);
 269 }
 270 
 271 /**
 272  * This is the implementation of the general DisposeFunc defined in
 273  * SurfaceData.h and used by the Disposer mechanism.  It first flushes all
 274  * native OpenGL resources and then frees any memory allocated within the
 275  * native MTLSDOps structure.
 276  */
 277 void
 278 MTLSD_Dispose(JNIEnv *env, SurfaceDataOps *ops)
 279 {
 280     MTLSDOps *mtlsdo = (MTLSDOps *)ops;
 281     jlong pConfigInfo = MTLSD_GetNativeConfigInfo(mtlsdo);
 282 
 283     JNU_CallStaticMethodByName(env, NULL, "sun/java2d/metal/MTLSurfaceData",
 284                                "dispose", "(JJ)V",
 285                                ptr_to_jlong(ops), pConfigInfo);
 286 }
 287 
 288 /**
 289  * This is the implementation of the general surface LockFunc defined in
 290  * SurfaceData.h.
 291  */
 292 jint
 293 MTLSD_Lock(JNIEnv *env,
 294            SurfaceDataOps *ops,
 295            SurfaceDataRasInfo *pRasInfo,
 296            jint lockflags)
 297 {
 298     JNU_ThrowInternalError(env, "MTLSD_Lock not implemented!");
 299     return SD_FAILURE;
 300 }
 301 
 302 /**
 303  * This is the implementation of the general GetRasInfoFunc defined in
 304  * SurfaceData.h.
 305  */
 306 void
 307 MTLSD_GetRasInfo(JNIEnv *env,
 308                  SurfaceDataOps *ops,
 309                  SurfaceDataRasInfo *pRasInfo)
 310 {
 311     JNU_ThrowInternalError(env, "MTLSD_GetRasInfo not implemented!");
 312 }
 313 
 314 /**
 315  * This is the implementation of the general surface UnlockFunc defined in
 316  * SurfaceData.h.
 317  */
 318 void
 319 MTLSD_Unlock(JNIEnv *env,
 320              SurfaceDataOps *ops,
 321              SurfaceDataRasInfo *pRasInfo)
 322 {
 323     JNU_ThrowInternalError(env, "MTLSD_Unlock not implemented!");
 324 }
 325 
 326 /**
 327  * This function disposes of any native windowing system resources associated
 328  * with this surface.
 329  */
 330 void
 331 MTLSD_DestroyMTLSurface(JNIEnv *env, MTLSDOps *mtlsdo)
 332 {
 333     J2dTraceLn(J2D_TRACE_INFO, "OGLSD_DestroyOGLSurface");
 334 }
 335 
 336 /**
 337  * Returns a pointer (as a jlong) to the native CGLGraphicsConfigInfo
 338  * associated with the given OGLSDOps.  This method can be called from
 339  * shared code to retrieve the native GraphicsConfig data in a platform-
 340  * independent manner.
 341  */
 342 jlong
 343 MTLSD_GetNativeConfigInfo(BMTLSDOps *mtlsdo)
 344 {
 345     J2dTraceLn(J2D_TRACE_INFO, "OGLSD_GetNativeConfigInfo");
 346 
 347     return 0;
 348 }
 349 
 350 /**
 351  * This function initializes a native window surface and caches the window
 352  * bounds in the given OGLSDOps.  Returns JNI_TRUE if the operation was
 353  * successful; JNI_FALSE otherwise.
 354  */
 355 jboolean
 356 MTLSD_InitMTLWindow(JNIEnv *env, MTLSDOps *oglsdo)
 357 {
 358     J2dTraceLn(J2D_TRACE_INFO, "MTLSD_InitMTLWindow");
 359 
 360     return JNI_TRUE;
 361 }
 362 
 363 void
 364 MTLSD_SwapBuffers(JNIEnv *env, jlong pPeerData)
 365 {
 366     J2dTraceLn(J2D_TRACE_INFO, "OGLSD_SwapBuffers");
 367 }
 368 
 369 #pragma mark -
 370 #pragma mark "--- CGLSurfaceData methods ---"
 371 
 372 extern LockFunc        MTLSD_Lock;
 373 extern GetRasInfoFunc  MTLSD_GetRasInfo;
 374 extern UnlockFunc      MTLSD_Unlock;
 375 
 376 
 377 JNIEXPORT void JNICALL
 378 Java_sun_java2d_metal_MTLSurfaceData_initOps
 379     (JNIEnv *env, jobject cglsd,
 380      jlong pConfigInfo, jlong pPeerData, jlong layerPtr,
 381      jint xoff, jint yoff, jboolean isOpaque)
 382 {
 383     BMTLSDOps *bmtlsdo = (BMTLSDOps *)SurfaceData_InitOps(env, cglsd, sizeof(BMTLSDOps));
 384     MTLSDOps *mtlsdo = (MTLSDOps *)malloc(sizeof(MTLSDOps));
 385 
 386     J2dTraceLn1(J2D_TRACE_INFO, "MTLSurfaceData_initOps p=%p", bmtlsdo);
 387     J2dTraceLn1(J2D_TRACE_INFO, "  pPeerData=%p", jlong_to_ptr(pPeerData));
 388     J2dTraceLn1(J2D_TRACE_INFO, "  layerPtr=%p", jlong_to_ptr(layerPtr));
 389     J2dTraceLn2(J2D_TRACE_INFO, "  xoff=%d, yoff=%d", (int)xoff, (int)yoff);
 390 
 391     if (mtlsdo == NULL) {
 392         JNU_ThrowOutOfMemoryError(env, "creating native cgl ops");
 393         return;
 394     }
 395 
 396     bmtlsdo->privOps = mtlsdo;
 397 
 398     bmtlsdo->sdOps.Lock               = MTLSD_Lock;
 399     bmtlsdo->sdOps.GetRasInfo         = MTLSD_GetRasInfo;
 400     bmtlsdo->sdOps.Unlock             = MTLSD_Unlock;
 401     bmtlsdo->sdOps.Dispose            = MTLSD_Dispose;
 402 
 403     bmtlsdo->drawableType = MTLSD_UNDEFINED;
 404     bmtlsdo->needsInit = JNI_TRUE;
 405     bmtlsdo->xOffset = xoff;
 406     bmtlsdo->yOffset = yoff;
 407     bmtlsdo->isOpaque = isOpaque;
 408 
 409     mtlsdo->peerData = (AWTView *)jlong_to_ptr(pPeerData);
 410     mtlsdo->layer = (MTLLayer *)jlong_to_ptr(layerPtr);
 411     mtlsdo->configInfo = (MTLGraphicsConfigInfo *)jlong_to_ptr(pConfigInfo);
 412 
 413     if (mtlsdo->configInfo == NULL) {
 414         free(mtlsdo);
 415         JNU_ThrowNullPointerException(env, "Config info is null in initOps");
 416     }
 417 }
 418 
 419 JNIEXPORT void JNICALL
 420 Java_sun_java2d_metal_MTLSurfaceData_clearWindow
 421 (JNIEnv *env, jobject cglsd)
 422 {
 423     J2dTraceLn(J2D_TRACE_INFO, "CGLSurfaceData_clearWindow");
 424 
 425     BMTLSDOps *mtlsdo = (MTLSDOps*) SurfaceData_GetOps(env, cglsd);
 426     MTLSDOps *cglsdo = (MTLSDOps*) mtlsdo->privOps;
 427 
 428     cglsdo->peerData = NULL;
 429     cglsdo->layer = NULL;
 430 }
 431 
 432 JNIEXPORT void JNICALL
 433 Java_sun_java2d_metal_MTLSurfaceData_validate
 434     (JNIEnv *env, jobject jsurfacedata,
 435      jint xoff, jint yoff, jint width, jint height, jboolean isOpaque)
 436 {
 437     J2dTraceLn2(J2D_TRACE_INFO, "MTLLSurfaceData_validate: w=%d h=%d", width, height);
 438 
 439     BMTLSDOps *mtlsdo = (BMTLSDOps*)SurfaceData_GetOps(env, jsurfacedata);
 440     mtlsdo->needsInit = JNI_TRUE;
 441     mtlsdo->xOffset = xoff;
 442     mtlsdo->yOffset = yoff;
 443 
 444     mtlsdo->width = width;
 445     mtlsdo->height = height;
 446     mtlsdo->isOpaque = isOpaque;
 447 
 448     if (mtlsdo->drawableType == MTLSD_WINDOW) {
 449         // J2dTraceLn4(J2D_TRACE_INFO, "MTLContext_SetSurfaces: w=%d h=%d src=%p dst=%p", width, height, mtlsdo, mtlsdo);
 450         [MTLContext setSurfacesEnv:env src:ptr_to_jlong(mtlsdo) dst:ptr_to_jlong(mtlsdo)];
 451 
 452         // we have to explicitly tell the NSOpenGLContext that its target
 453         // drawable has changed size
 454         MTLSDOps *cglsdo = (MTLSDOps *)mtlsdo->privOps;
 455         MTLContext *mtlc = cglsdo->configInfo->context;
 456 
 457     }
 458 }