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 }