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 #ifndef HEADLESS
  27 
  28 #include <stdlib.h>
  29 
  30 #include "sun_java2d_metal_MTLSurfaceData.h"
  31 
  32 #include "jlong.h"
  33 #include "jni_util.h"
  34 #include "MTLSurfaceData.h"
  35 #import "ThreadUtilities.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(MTLSDOps *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 OpenGL texture object.
  86  *
  87  * If the isOpaque parameter is JNI_FALSE, then the texture will have a
  88  * full alpha channel; otherwise, the texture will be opaque (this can
  89  * help save VRAM when translucency is not needed).
  90  *
  91  * If the GL_ARB_texture_non_power_of_two extension is present (texNonPow2
  92  * is JNI_TRUE), the actual texture is allowed to have non-power-of-two
  93  * dimensions, and therefore width==textureWidth and height==textureHeight.
  94  *
  95  * Failing that, if the GL_ARB_texture_rectangle extension is present
  96  * (texRect is JNI_TRUE), the actual texture is allowed to have
  97  * non-power-of-two dimensions, except that instead of using the usual
  98  * GL_TEXTURE_2D target, we need to use the GL_TEXTURE_RECTANGLE_ARB target.
  99  * Note that the GL_REPEAT wrapping mode is not allowed with this target,
 100  * so if that mode is needed (e.g. as is the case in the TexturePaint code)
 101  * one should pass JNI_FALSE to avoid using this extension.  Also note that
 102  * when the texture target is GL_TEXTURE_RECTANGLE_ARB, texture coordinates
 103  * must be specified in the range [0,width] and [0,height] rather than
 104  * [0,1] as is the case with the usual GL_TEXTURE_2D target (so take care)!
 105  *
 106  * Otherwise, the actual texture must have power-of-two dimensions, and
 107  * therefore the textureWidth and textureHeight will be the next
 108  * power-of-two greater than (or equal to) the requested width and height.
 109  */
 110 static jboolean
 111 MTLSD_InitTextureObject(MTLSDOps *mtlsdo,
 112                         jboolean isOpaque,
 113                         jboolean texNonPow2, jboolean texRect,
 114                         jint width, jint height)
 115 {
 116     //TODO
 117     J2dTraceNotImplPrimitive("MTLSD_InitTextureObject");
 118     return JNI_TRUE;
 119 }
 120 
 121 /**
 122  * Initializes an MTL texture, using the given width and height as
 123  * a guide.  See MTLSD_InitTextureObject() for more information.
 124  */
 125 JNIEXPORT jboolean JNICALL
 126 Java_sun_java2d_metal_MTLSurfaceDataBase_initTexture
 127     (JNIEnv *env, jobject mtlsd,
 128      jlong pData, jboolean isOpaque,
 129      jboolean texNonPow2, jboolean texRect,
 130      jint width, jint height)
 131 {
 132     BMTLSDOps *mtlsdo = (BMTLSDOps *)jlong_to_ptr(pData);
 133     J2dTraceLn2(J2D_TRACE_INFO, "MTLSurfaceData_initTexture: w=%d h=%d",
 134                 width, height);
 135 
 136     if (mtlsdo == NULL) {
 137         J2dRlsTraceLn(J2D_TRACE_ERROR,
 138             "MTLSurfaceData_initTexture: ops are null");
 139         return JNI_FALSE;
 140     }
 141 
 142     /*
 143      * We only use the GL_ARB_texture_rectangle extension if it is available
 144      * and the requested bounds are not pow2 (it is probably faster to use
 145      * GL_TEXTURE_2D for pow2 textures, and besides, our TexturePaint
 146      * code relies on GL_REPEAT, which is not allowed for
 147      * GL_TEXTURE_RECTANGLE_ARB targets).
 148      */
 149     texRect = texRect && !MTLSD_IsPowerOfTwo(width, height);
 150 
 151     if (!MTLSD_InitTextureObject(mtlsdo, isOpaque, texNonPow2, texRect,
 152                                  width, height))
 153     {
 154         J2dRlsTraceLn(J2D_TRACE_ERROR,
 155             "MTLSurfaceData_initTexture: could not init texture object");
 156         return JNI_FALSE;
 157     }
 158 
 159     MTLSD_SetNativeDimensions(env, mtlsdo,
 160                               mtlsdo->textureWidth, mtlsdo->textureHeight);
 161 
 162     mtlsdo->drawableType = MTLSD_TEXTURE;
 163     // other fields (e.g. width, height) are set in MTLSD_InitTextureObject()
 164 
 165     return JNI_TRUE;
 166 }
 167 
 168 /**
 169  * Initializes a framebuffer object, using the given width and height as
 170  * a guide.  See MTLSD_InitTextureObject() and MTLSD_InitFBObject()
 171  * for more information.
 172  */
 173 JNIEXPORT jboolean JNICALL
 174 Java_sun_java2d_metal_MTLSurfaceDataBase_initFBObject
 175     (JNIEnv *env, jobject mtlsd,
 176      jlong pData, jboolean isOpaque,
 177      jboolean texNonPow2, jboolean texRect,
 178      jint width, jint height)
 179 {
 180 
 181     BMTLSDOps *bmtlsdo = (BMTLSDOps *)jlong_to_ptr(pData);
 182 
 183     if (bmtlsdo == NULL) {
 184         J2dRlsTraceLn(J2D_TRACE_ERROR,
 185             "MTLSurfaceData_initFBObject: BMTLSDOps are null");
 186         return JNI_FALSE;
 187     }
 188 
 189     MTLSDOps *mtlsdo = (MTLSDOps *)bmtlsdo->privOps;
 190 
 191     if (mtlsdo == NULL) {
 192         J2dRlsTraceLn(J2D_TRACE_ERROR,
 193             "MTLSurfaceData_initFBObject: MTLSDOps are null");
 194         return JNI_FALSE;
 195     }
 196 
 197     J2dTraceLn2(J2D_TRACE_INFO,
 198                 "MTLSurfaceData_initFBObject: w=%d h=%d",
 199                 width, height);
 200 
 201 
 202 
 203     if (mtlsdo->configInfo) {
 204         if (mtlsdo->configInfo->context != NULL) {
 205             MTLContext* ctx = mtlsdo->configInfo->context;
 206             if (ctx == NULL) {
 207               NSLog(@"ctx is NULL");
 208             } else {
 209                 [ThreadUtilities performOnMainThreadWaiting:NO block:^(){
 210                         MTLTextureDescriptor *textureDescriptor =
 211                                     [MTLTextureDescriptor texture2DDescriptorWithPixelFormat: MTLPixelFormatRGBA8Unorm
 212                                                                                        width: width
 213                                                                                       height: height
 214                                                                                    mipmapped: NO];
 215                         ctx->mtlFrameBuffer = [[ctx->mtlDevice newTextureWithDescriptor: textureDescriptor] retain];
 216                 }];
 217             }
 218         }
 219      }
 220 
 221 
 222     bmtlsdo->drawableType = MTLSD_FBOBJECT;
 223 
 224     return JNI_TRUE;
 225 }
 226 
 227 /**
 228  * Initializes a surface in the backbuffer of a given double-buffered
 229  * onscreen window for use in a BufferStrategy.Flip situation.  The bounds of
 230  * the backbuffer surface should always be kept in sync with the bounds of
 231  * the underlying native window.
 232  */
 233 JNIEXPORT jboolean JNICALL
 234 Java_sun_java2d_metal_MTLSurfaceDataBase_initFlipBackbuffer
 235     (JNIEnv *env, jobject mtlsd,
 236      jlong pData)
 237 {
 238     //TODO
 239     J2dTraceNotImplPrimitive("MTLSurfaceDataBase_initFlipBackbuffer");
 240     MTLSDOps *mtlsdo = (MTLSDOps *)jlong_to_ptr(pData);
 241 
 242     J2dTraceLn(J2D_TRACE_INFO, "MTLSurfaceData_initFlipBackbuffer");
 243     return JNI_TRUE;
 244 }
 245 
 246 JNIEXPORT jint JNICALL
 247 Java_sun_java2d_metal_MTLSurfaceDataBase_getTextureTarget
 248     (JNIEnv *env, jobject mtlsd,
 249      jlong pData)
 250 {
 251     //TODO
 252     J2dTraceNotImplPrimitive("MTLSurfaceDataBase_getTextureTarget");
 253     MTLSDOps *mtlsdo = (MTLSDOps *)jlong_to_ptr(pData);
 254 
 255     J2dTraceLn(J2D_TRACE_INFO, "MTLSurfaceData_getTextureTarget");
 256 
 257     return 0;
 258 }
 259 
 260 JNIEXPORT jint JNICALL
 261 Java_sun_java2d_metal_MTLSurfaceDataBase_getTextureID
 262     (JNIEnv *env, jobject mtlsd,
 263      jlong pData)
 264 {
 265     //TODO
 266     J2dTraceNotImplPrimitive("MTLSurfaceDataBase_getTextureID");
 267     return 0;
 268 }
 269 
 270 /**
 271  * Initializes nativeWidth/Height fields of the surfaceData object with
 272  * passed arguments.
 273  */
 274 void
 275 MTLSD_SetNativeDimensions(JNIEnv *env, BMTLSDOps *mtlsdo,
 276                           jint width, jint height)
 277 {
 278     jobject sdObject;
 279 
 280     sdObject = (*env)->NewLocalRef(env, mtlsdo->sdOps.sdObject);
 281     if (sdObject == NULL) {
 282         return;
 283     }
 284 
 285     JNU_SetFieldByName(env, NULL, sdObject, "nativeWidth", "I", width);
 286     if (!((*env)->ExceptionOccurred(env))) {
 287         JNU_SetFieldByName(env, NULL, sdObject, "nativeHeight", "I", height);
 288     }
 289 
 290     (*env)->DeleteLocalRef(env, sdObject);
 291 }
 292 
 293 /**
 294  * Deletes native OpenGL resources associated with this surface.
 295  */
 296 void
 297 MTLSD_Delete(JNIEnv *env, BMTLSDOps *mtlsdo)
 298 {
 299     //TODO
 300     J2dTraceNotImplPrimitive("MTLSD_Delete");
 301     J2dTraceLn1(J2D_TRACE_INFO, "MTLSD_Delete: type=%d",
 302                 mtlsdo->drawableType);
 303 }
 304 
 305 /**
 306  * This is the implementation of the general DisposeFunc defined in
 307  * SurfaceData.h and used by the Disposer mechanism.  It first flushes all
 308  * native OpenGL resources and then frees any memory allocated within the
 309  * native MTLSDOps structure.
 310  */
 311 void
 312 MTLSD_Dispose(JNIEnv *env, SurfaceDataOps *ops)
 313 {
 314     MTLSDOps *mtlsdo = (MTLSDOps *)ops;
 315     jlong pConfigInfo = MTLSD_GetNativeConfigInfo(mtlsdo);
 316 
 317     JNU_CallStaticMethodByName(env, NULL, "sun/java2d/metal/MTLSurfaceData",
 318                                "dispose", "(JJ)V",
 319                                ptr_to_jlong(ops), pConfigInfo);
 320 }
 321 
 322 /**
 323  * This is the implementation of the general surface LockFunc defined in
 324  * SurfaceData.h.
 325  */
 326 jint
 327 MTLSD_Lock(JNIEnv *env,
 328            SurfaceDataOps *ops,
 329            SurfaceDataRasInfo *pRasInfo,
 330            jint lockflags)
 331 {
 332     JNU_ThrowInternalError(env, "MTLSD_Lock not implemented!");
 333     return SD_FAILURE;
 334 }
 335 
 336 /**
 337  * This is the implementation of the general GetRasInfoFunc defined in
 338  * SurfaceData.h.
 339  */
 340 void
 341 MTLSD_GetRasInfo(JNIEnv *env,
 342                  SurfaceDataOps *ops,
 343                  SurfaceDataRasInfo *pRasInfo)
 344 {
 345     JNU_ThrowInternalError(env, "MTLSD_GetRasInfo not implemented!");
 346 }
 347 
 348 /**
 349  * This is the implementation of the general surface UnlockFunc defined in
 350  * SurfaceData.h.
 351  */
 352 void
 353 MTLSD_Unlock(JNIEnv *env,
 354              SurfaceDataOps *ops,
 355              SurfaceDataRasInfo *pRasInfo)
 356 {
 357     JNU_ThrowInternalError(env, "MTLSD_Unlock not implemented!");
 358 }
 359 
 360 #endif /* !HEADLESS */