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 package sun.java2d.metal; 27 28 import sun.awt.SunHints; 29 import sun.awt.image.PixelConverter; 30 import sun.java2d.SunGraphics2D; 31 import sun.java2d.SurfaceData; 32 import sun.java2d.SurfaceDataProxy; 33 import sun.java2d.loops.CompositeType; 34 import sun.java2d.loops.GraphicsPrimitive; 35 import sun.java2d.loops.MaskFill; 36 import sun.java2d.loops.SurfaceType; 37 import sun.java2d.pipe.ParallelogramPipe; 38 import sun.java2d.pipe.PixelToParallelogramConverter; 39 import sun.java2d.pipe.RenderBuffer; 40 import sun.java2d.pipe.TextPipe; 41 import sun.java2d.pipe.hw.AccelSurface; 42 import sun.lwawt.macosx.CPlatformView; 43 44 import java.awt.*; 45 import java.awt.image.ColorModel; 46 import java.awt.image.Raster; 47 48 import static sun.java2d.metal.MTLContext.MTLContextCaps.CAPS_EXT_LCD_SHADER; 49 import static sun.java2d.metal.MTLContext.MTLContextCaps.CAPS_EXT_TEXRECT; 50 import static sun.java2d.pipe.BufferedOpCodes.FLUSH_SURFACE; 51 import static sun.java2d.pipe.BufferedOpCodes.SWAP_BUFFERS; 52 import static sun.java2d.pipe.hw.ContextCapabilities.*; 53 54 public abstract class MTLSurfaceData extends SurfaceData 55 implements AccelSurface { 56 57 /** 58 * Pixel formats 59 */ 60 public static final int PF_INT_ARGB = 0; 61 public static final int PF_INT_ARGB_PRE = 1; 62 public static final int PF_INT_RGB = 2; 63 public static final int PF_INT_RGBX = 3; 64 public static final int PF_INT_BGR = 4; 65 public static final int PF_INT_BGRX = 5; 66 public static final int PF_USHORT_565_RGB = 6; 67 public static final int PF_USHORT_555_RGB = 7; 68 public static final int PF_USHORT_555_RGBX = 8; 69 public static final int PF_BYTE_GRAY = 9; 70 public static final int PF_USHORT_GRAY = 10; 71 public static final int PF_3BYTE_BGR = 11; 72 /** 73 * SurfaceTypes 74 */ 75 76 private static final String DESC_MTL_SURFACE = "MTL Surface"; 77 private static final String DESC_MTL_SURFACE_RTT = 78 "MTL Surface (render-to-texture)"; 79 private static final String DESC_MTL_TEXTURE = "MTL Texture"; 80 81 82 static final SurfaceType MTLSurface = 83 SurfaceType.Any.deriveSubType(DESC_MTL_SURFACE, 84 PixelConverter.ArgbPre.instance); 85 static final SurfaceType MTLSurfaceRTT = 86 MTLSurface.deriveSubType(DESC_MTL_SURFACE_RTT); 87 static final SurfaceType MTLTexture = 88 SurfaceType.Any.deriveSubType(DESC_MTL_TEXTURE); 89 90 protected static MTLRenderer mtlRenderPipe; 91 protected static PixelToParallelogramConverter mtlTxRenderPipe; 92 protected static ParallelogramPipe mtlAAPgramPipe; 93 protected static MTLTextRenderer mtlTextPipe; 94 protected static MTLDrawImage mtlImagePipe; 95 /** This will be true if the fbobject system property has been enabled. */ 96 private static boolean isFBObjectEnabled; 97 /** This will be true if the lcdshader system property has been enabled.*/ 98 private static boolean isLCDShaderEnabled; 99 /** This will be true if the biopshader system property has been enabled.*/ 100 private static boolean isBIOpShaderEnabled; 101 /** This will be true if the gradshader system property has been enabled.*/ 102 private static boolean isGradShaderEnabled; 103 104 static { 105 if (!GraphicsEnvironment.isHeadless()) { 106 // fbobject currently enabled by default; use "false" to disable 107 String fbo = java.security.AccessController.doPrivileged( 108 new sun.security.action.GetPropertyAction( 109 "java2d.metal.fbobject")); 110 isFBObjectEnabled = !"false".equals(fbo); 111 112 // lcdshader currently enabled by default; use "false" to disable 113 String lcd = java.security.AccessController.doPrivileged( 114 new sun.security.action.GetPropertyAction( 115 "java2d.metal.lcdshader")); 116 isLCDShaderEnabled = !"false".equals(lcd); 117 118 // biopshader currently enabled by default; use "false" to disable 119 String biop = java.security.AccessController.doPrivileged( 120 new sun.security.action.GetPropertyAction( 121 "java2d.metal.biopshader")); 122 isBIOpShaderEnabled = !"false".equals(biop); 123 124 // gradshader currently enabled by default; use "false" to disable 125 String grad = java.security.AccessController.doPrivileged( 126 new sun.security.action.GetPropertyAction( 127 "java2d.metal.gradshader")); 128 isGradShaderEnabled = !"false".equals(grad); 129 130 MTLRenderQueue rq = MTLRenderQueue.getInstance(); 131 mtlImagePipe = new MTLDrawImage(); 132 mtlTextPipe = new MTLTextRenderer(rq); 133 mtlRenderPipe = new MTLRenderer(rq); 134 if (GraphicsPrimitive.tracingEnabled()) { 135 mtlTextPipe = mtlTextPipe.traceWrap(); 136 //The wrapped mtlRenderPipe will wrap the AA pipe as well... 137 //mtlAAPgramPipe = mtlRenderPipe.traceWrap(); 138 } 139 mtlAAPgramPipe = mtlRenderPipe.getAAParallelogramPipe(); 140 mtlTxRenderPipe = 141 new PixelToParallelogramConverter(mtlRenderPipe, 142 mtlRenderPipe, 143 1.0, 0.25, true); 144 145 MTLBlitLoops.register(); 146 MTLMaskFill.register(); 147 MTLMaskBlit.register(); 148 } 149 } 150 151 protected final int scale; 152 protected final int width; 153 protected final int height; 154 protected CPlatformView pView; 155 protected int type; 156 private MTLGraphicsConfig graphicsConfig; 157 // these fields are set from the native code when the surface is 158 // initialized 159 private int nativeWidth; 160 private int nativeHeight; 161 162 /** 163 * Returns the appropriate SurfaceType corresponding to the given OpenGL 164 * surface type constant (e.g. TEXTURE -> MTLTexture). 165 */ 166 private static SurfaceType getCustomSurfaceType(int oglType) { 167 switch (oglType) { 168 case TEXTURE: 169 return MTLTexture; 170 case RT_TEXTURE: 171 return MTLSurfaceRTT; 172 default: 173 return MTLSurface; 174 } 175 } 176 177 static void swapBuffers(long window) { 178 MTLRenderQueue rq = MTLRenderQueue.getInstance(); 179 rq.lock(); 180 try { 181 RenderBuffer buf = rq.getBuffer(); 182 rq.ensureCapacityAndAlignment(12, 4); 183 buf.putInt(SWAP_BUFFERS); 184 buf.putLong(window); 185 rq.flushNow(); 186 } finally { 187 rq.unlock(); 188 } 189 } 190 191 native void validate(int xoff, int yoff, int width, int height, boolean isOpaque); 192 193 private native void initOps(long pConfigInfo, long pPeerData, long layerPtr, 194 int xoff, int yoff, boolean isOpaque); 195 196 protected MTLSurfaceData(MTLGraphicsConfig gc, ColorModel cm, int type, 197 int width, int height) { 198 super(getCustomSurfaceType(type), cm); 199 this.graphicsConfig = gc; 200 this.type = type; 201 setBlitProxyKey(gc.getProxyKey()); 202 203 // TEXTURE shouldn't be scaled, it is used for managed BufferedImages. 204 scale = type == TEXTURE ? 1 : gc.getDevice().getScaleFactor(); 205 this.width = width * scale; 206 this.height = height * scale; 207 } 208 209 protected MTLSurfaceData(CPlatformView pView, MTLGraphicsConfig gc, 210 ColorModel cm, int type, int width, int height) 211 { 212 this(gc, cm, type, width, height); 213 this.pView = pView; 214 this.graphicsConfig = gc; 215 216 long pConfigInfo = gc.getNativeConfigInfo(); 217 long pPeerData = 0L; 218 boolean isOpaque = true; 219 if (pView != null) { 220 pPeerData = pView.getAWTView(); 221 isOpaque = pView.isOpaque(); 222 } 223 MTLGraphicsConfig.refPConfigInfo(pConfigInfo); 224 initOps(pConfigInfo, pPeerData, 0, 0, 0, isOpaque); 225 } 226 227 protected MTLSurfaceData(MTLLayer layer, MTLGraphicsConfig gc, 228 ColorModel cm, int type, int width, int height) 229 { 230 this(gc, cm, type, width, height); 231 this.graphicsConfig = gc; 232 233 long pConfigInfo = gc.getNativeConfigInfo(); 234 long layerPtr = 0L; 235 boolean isOpaque = true; 236 if (layer != null) { 237 layerPtr = layer.getPointer(); 238 isOpaque = layer.isOpaque(); 239 } 240 MTLGraphicsConfig.refPConfigInfo(pConfigInfo); 241 initOps(pConfigInfo, 0, layerPtr, 0, 0, isOpaque); 242 } 243 244 @Override //SurfaceData 245 public GraphicsConfiguration getDeviceConfiguration() { 246 return graphicsConfig; 247 } 248 249 /** 250 * Creates a SurfaceData object representing the primary (front) buffer of 251 * an on-screen Window. 252 */ 253 public static MTLWindowSurfaceData createData(CPlatformView pView) { 254 MTLGraphicsConfig gc = getGC(pView); 255 return new MTLWindowSurfaceData(pView, gc); 256 } 257 258 /** 259 * Creates a SurfaceData object representing the intermediate buffer 260 * between the Java2D flusher thread and the AppKit thread. 261 */ 262 public static MTLLayerSurfaceData createData(MTLLayer layer) { 263 MTLGraphicsConfig gc = getGC(layer); 264 Rectangle r = layer.getBounds(); 265 return new MTLLayerSurfaceData(layer, gc, r.width, r.height); 266 } 267 268 /** 269 * Creates a SurfaceData object representing the back buffer of a 270 * double-buffered on-screen Window. 271 */ 272 public static MTLOffScreenSurfaceData createData(CPlatformView pView, 273 Image image, int type) { 274 MTLGraphicsConfig gc = getGC(pView); 275 Rectangle r = pView.getBounds(); 276 if (type == FLIP_BACKBUFFER) { 277 return new MTLOffScreenSurfaceData(pView, gc, r.width, r.height, 278 image, gc.getColorModel(), FLIP_BACKBUFFER); 279 } else { 280 return new MTLVSyncOffScreenSurfaceData(pView, gc, r.width, 281 r.height, image, gc.getColorModel(), type); 282 } 283 } 284 285 /** 286 * Creates a SurfaceData object representing an off-screen buffer (either a 287 * FBO or Texture). 288 */ 289 public static MTLOffScreenSurfaceData createData(MTLGraphicsConfig gc, 290 int width, int height, ColorModel cm, Image image, int type) { 291 return new MTLOffScreenSurfaceData(null, gc, width, height, image, cm, 292 type); 293 } 294 295 public static MTLGraphicsConfig getGC(CPlatformView pView) { 296 if (pView != null) { 297 return (MTLGraphicsConfig)pView.getGraphicsConfiguration(); 298 } else { 299 // REMIND: this should rarely (never?) happen, but what if 300 // default config is not CGL? 301 GraphicsEnvironment env = GraphicsEnvironment 302 .getLocalGraphicsEnvironment(); 303 GraphicsDevice gd = env.getDefaultScreenDevice(); 304 return (MTLGraphicsConfig) gd.getDefaultConfiguration(); 305 } 306 } 307 308 public static MTLGraphicsConfig getGC(MTLLayer layer) { 309 return (MTLGraphicsConfig)layer.getGraphicsConfiguration(); 310 } 311 312 public void validate() { 313 // Overridden in MTLWindowSurfaceData below 314 } 315 316 @Override 317 public double getDefaultScaleX() { 318 return scale; 319 } 320 321 @Override 322 public double getDefaultScaleY() { 323 return scale; 324 } 325 326 protected native void clearWindow(); 327 328 protected native boolean initTexture(long pData, 329 boolean isOpaque, boolean texNonPow2, 330 boolean texRect, 331 int width, int height); 332 333 protected native boolean initRTexture(long pData, 334 boolean isOpaque, boolean texNonPow2, 335 boolean texRect, 336 int width, int height); 337 338 protected native boolean initFlipBackbuffer(long pData); 339 340 @Override 341 public SurfaceDataProxy makeProxyFor(SurfaceData srcData) { 342 return MTLSurfaceDataProxy.createProxy(srcData, graphicsConfig); 343 } 344 345 /** 346 * Note: This should only be called from the QFT under the AWT lock. 347 * This method is kept separate from the initSurface() method below just 348 * to keep the code a bit cleaner. 349 */ 350 private void initSurfaceNow(int width, int height) { 351 boolean isOpaque = (getTransparency() == Transparency.OPAQUE); 352 boolean success = false; 353 354 switch (type) { 355 case TEXTURE: 356 success = initTexture(getNativeOps(), 357 isOpaque, isTexNonPow2Available(), 358 isTexRectAvailable(), 359 width, height); 360 break; 361 362 case RT_TEXTURE: 363 success = initRTexture(getNativeOps(), 364 isOpaque, isTexNonPow2Available(), 365 isTexRectAvailable(), 366 width, height); 367 break; 368 369 case FLIP_BACKBUFFER: 370 success = initFlipBackbuffer(getNativeOps()); 371 break; 372 373 default: 374 break; 375 } 376 377 if (!success) { 378 throw new OutOfMemoryError("can't create offscreen surface"); 379 } 380 } 381 382 /** 383 * Initializes the appropriate OpenGL offscreen surface based on the value 384 * of the type parameter. If the surface creation fails for any reason, 385 * an OutOfMemoryError will be thrown. 386 */ 387 protected void initSurface(final int width, final int height) { 388 MTLRenderQueue rq = MTLRenderQueue.getInstance(); 389 rq.lock(); 390 try { 391 switch (type) { 392 case TEXTURE: 393 case RT_TEXTURE: 394 // need to make sure the context is current before 395 // creating the texture or fbobject 396 MTLContext.setScratchSurface(graphicsConfig); 397 break; 398 default: 399 break; 400 } 401 rq.flushAndInvokeNow(new Runnable() { 402 public void run() { 403 initSurfaceNow(width, height); 404 } 405 }); 406 } finally { 407 rq.unlock(); 408 } 409 } 410 411 /** 412 * Returns the MTLContext for the GraphicsConfig associated with this 413 * surface. 414 */ 415 public final MTLContext getContext() { 416 return graphicsConfig.getContext(); 417 } 418 419 /** 420 * Returns the MTLGraphicsConfig associated with this surface. 421 */ 422 final MTLGraphicsConfig getMTLGraphicsConfig() { 423 return graphicsConfig; 424 } 425 426 /** 427 * Returns one of the surface type constants defined above. 428 */ 429 public final int getType() { 430 return type; 431 } 432 433 /** 434 * For now, we can only render LCD text if: 435 * - the fragment shader extension is available, and 436 * - the source color is opaque, and 437 * - blending is SrcOverNoEa or disabled 438 * - and the destination is opaque 439 * 440 * Eventually, we could enhance the native OGL text rendering code 441 * and remove the above restrictions, but that would require significantly 442 * more code just to support a few uncommon cases. 443 */ 444 public boolean canRenderLCDText(SunGraphics2D sg2d) { 445 return 446 graphicsConfig.isCapPresent(CAPS_EXT_LCD_SHADER) && 447 sg2d.surfaceData.getTransparency() == Transparency.OPAQUE && 448 sg2d.paintState <= SunGraphics2D.PAINT_OPAQUECOLOR && 449 (sg2d.compositeState <= SunGraphics2D.COMP_ISCOPY || 450 (sg2d.compositeState <= SunGraphics2D.COMP_ALPHA && canHandleComposite(sg2d.composite))); 451 } 452 453 private boolean canHandleComposite(Composite c) { 454 if (c instanceof AlphaComposite) { 455 AlphaComposite ac = (AlphaComposite)c; 456 457 return ac.getRule() == AlphaComposite.SRC_OVER && ac.getAlpha() >= 1f; 458 } 459 return false; 460 } 461 462 public void validatePipe(SunGraphics2D sg2d) { 463 TextPipe textpipe; 464 boolean validated = false; 465 466 // MTLTextRenderer handles both AA and non-AA text, but 467 // only works with the following modes: 468 // (Note: For LCD text we only enter this code path if 469 // canRenderLCDText() has already validated that the mode is 470 // CompositeType.SrcNoEa (opaque color), which will be subsumed 471 // by the CompositeType.SrcNoEa (any color) test below.) 472 473 if (/* CompositeType.SrcNoEa (any color) */ 474 (sg2d.compositeState <= SunGraphics2D.COMP_ISCOPY && 475 sg2d.paintState <= SunGraphics2D.PAINT_ALPHACOLOR) || 476 477 /* CompositeType.SrcOver (any color) */ 478 (sg2d.compositeState == SunGraphics2D.COMP_ALPHA && 479 sg2d.paintState <= SunGraphics2D.PAINT_ALPHACOLOR && 480 (((AlphaComposite)sg2d.composite).getRule() == 481 AlphaComposite.SRC_OVER)) || 482 483 /* CompositeType.Xor (any color) */ 484 (sg2d.compositeState == SunGraphics2D.COMP_XOR && 485 sg2d.paintState <= SunGraphics2D.PAINT_ALPHACOLOR)) 486 { 487 textpipe = mtlTextPipe; 488 } else { 489 // do this to initialize textpipe correctly; we will attempt 490 // to override the non-text pipes below 491 super.validatePipe(sg2d); 492 textpipe = sg2d.textpipe; 493 validated = true; 494 } 495 496 PixelToParallelogramConverter txPipe = null; 497 MTLRenderer nonTxPipe = null; 498 499 if (sg2d.antialiasHint != SunHints.INTVAL_ANTIALIAS_ON) { 500 if (sg2d.paintState <= SunGraphics2D.PAINT_ALPHACOLOR) { 501 if (sg2d.compositeState <= SunGraphics2D.COMP_XOR) { 502 txPipe = mtlTxRenderPipe; 503 nonTxPipe = mtlRenderPipe; 504 } 505 } else if (sg2d.compositeState <= SunGraphics2D.COMP_ALPHA) { 506 if (MTLPaints.isValid(sg2d)) { 507 txPipe = mtlTxRenderPipe; 508 nonTxPipe = mtlRenderPipe; 509 } 510 // custom paints handled by super.validatePipe() below 511 } 512 } else { 513 if (sg2d.paintState <= SunGraphics2D.PAINT_ALPHACOLOR) { 514 if (graphicsConfig.isCapPresent(CAPS_PS30) && 515 (sg2d.imageComp == CompositeType.SrcOverNoEa || 516 sg2d.imageComp == CompositeType.SrcOver)) 517 { 518 if (!validated) { 519 super.validatePipe(sg2d); 520 validated = true; 521 } 522 PixelToParallelogramConverter aaConverter = 523 new PixelToParallelogramConverter(sg2d.shapepipe, 524 mtlAAPgramPipe, 525 1.0/8.0, 0.499, 526 false); 527 sg2d.drawpipe = aaConverter; 528 sg2d.fillpipe = aaConverter; 529 sg2d.shapepipe = aaConverter; 530 } else if (sg2d.compositeState == SunGraphics2D.COMP_XOR) { 531 // install the solid pipes when AA and XOR are both enabled 532 txPipe = mtlTxRenderPipe; 533 nonTxPipe = mtlRenderPipe; 534 } 535 } 536 // other cases handled by super.validatePipe() below 537 } 538 539 if (txPipe != null) { 540 if (sg2d.transformState >= SunGraphics2D.TRANSFORM_TRANSLATESCALE) { 541 sg2d.drawpipe = txPipe; 542 sg2d.fillpipe = txPipe; 543 } else if (sg2d.strokeState != SunGraphics2D.STROKE_THIN) { 544 sg2d.drawpipe = txPipe; 545 sg2d.fillpipe = nonTxPipe; 546 } else { 547 sg2d.drawpipe = nonTxPipe; 548 sg2d.fillpipe = nonTxPipe; 549 } 550 // Note that we use the transforming pipe here because it 551 // will examine the shape and possibly perform an optimized 552 // operation if it can be simplified. The simplifications 553 // will be valid for all STROKE and TRANSFORM types. 554 sg2d.shapepipe = txPipe; 555 } else { 556 if (!validated) { 557 super.validatePipe(sg2d); 558 } 559 } 560 561 // install the text pipe based on our earlier decision 562 sg2d.textpipe = textpipe; 563 564 // always override the image pipe with the specialized OGL pipe 565 sg2d.imagepipe = mtlImagePipe; 566 } 567 568 @Override 569 protected MaskFill getMaskFill(SunGraphics2D sg2d) { 570 if (sg2d.paintState > SunGraphics2D.PAINT_ALPHACOLOR) { 571 /* 572 * We can only accelerate non-Color MaskFill operations if 573 * all of the following conditions hold true: 574 * - there is an implementation for the given paintState 575 * - the current Paint can be accelerated for this destination 576 * - multitexturing is available (since we need to modulate 577 * the alpha mask texture with the paint texture) 578 * 579 * In all other cases, we return null, in which case the 580 * validation code will choose a more general software-based loop. 581 */ 582 if (!MTLPaints.isValid(sg2d) || 583 !graphicsConfig.isCapPresent(CAPS_MULTITEXTURE)) 584 { 585 return null; 586 } 587 } 588 return super.getMaskFill(sg2d); 589 } 590 591 public void flush() { 592 invalidate(); 593 MTLRenderQueue rq = MTLRenderQueue.getInstance(); 594 rq.lock(); 595 try { 596 // make sure we have a current context before 597 // disposing the native resources (e.g. texture object) 598 MTLContext.setScratchSurface(graphicsConfig); 599 600 RenderBuffer buf = rq.getBuffer(); 601 rq.ensureCapacityAndAlignment(12, 4); 602 buf.putInt(FLUSH_SURFACE); 603 buf.putLong(getNativeOps()); 604 605 // this call is expected to complete synchronously, so flush now 606 rq.flushNow(); 607 } finally { 608 rq.unlock(); 609 } 610 } 611 612 /** 613 * Returns true if OpenGL textures can have non-power-of-two dimensions 614 * when using the basic GL_TEXTURE_2D target. 615 */ 616 boolean isTexNonPow2Available() { 617 return graphicsConfig.isCapPresent(CAPS_TEXNONPOW2); 618 } 619 620 /** 621 * Returns true if OpenGL textures can have non-power-of-two dimensions 622 * when using the GL_TEXTURE_RECTANGLE_ARB target (only available when the 623 * GL_ARB_texture_rectangle extension is present). 624 */ 625 boolean isTexRectAvailable() { 626 return graphicsConfig.isCapPresent(CAPS_EXT_TEXRECT); 627 } 628 629 /** 630 * Returns true if the surface is an on-screen window surface or 631 * a FBO texture attached to an on-screen CALayer. 632 * 633 * Needed by Mac OS X port. 634 */ 635 public boolean isOnScreen() { 636 return getType() == WINDOW; 637 } 638 639 private native int getTextureTarget(long pData); 640 641 private native int getTextureID(long pData); 642 643 /** 644 * If this surface is backed by a texture object, returns the target 645 * for that texture (either GL_TEXTURE_2D or GL_TEXTURE_RECTANGLE_ARB). 646 * Otherwise, this method will return zero. 647 */ 648 public final int getTextureTarget() { 649 return getTextureTarget(getNativeOps()); 650 } 651 652 /** 653 * If this surface is backed by a texture object, returns the texture ID 654 * for that texture. 655 * Otherwise, this method will return zero. 656 */ 657 public final int getTextureID() { 658 return getTextureID(getNativeOps()); 659 } 660 661 /** 662 * Returns native resource of specified {@code resType} associated with 663 * this surface. 664 * 665 * Specifically, for {@code MTLSurfaceData} this method returns the 666 * the following: 667 * <pre> 668 * TEXTURE - texture id 669 * </pre> 670 * 671 * Note: the resource returned by this method is only valid on the rendering 672 * thread. 673 * 674 * @return native resource of specified type or 0L if 675 * such resource doesn't exist or can not be retrieved. 676 * @see AccelSurface#getNativeResource 677 */ 678 public long getNativeResource(int resType) { 679 if (resType == TEXTURE) { 680 return getTextureID(); 681 } 682 return 0L; 683 } 684 685 public Raster getRaster(int x, int y, int w, int h) { 686 throw new InternalError("not implemented yet"); 687 } 688 689 @Override 690 public boolean copyArea(SunGraphics2D sg2d, int x, int y, int w, int h, 691 int dx, int dy) { 692 if (sg2d.compositeState >= SunGraphics2D.COMP_XOR) { 693 return false; 694 } 695 mtlRenderPipe.copyArea(sg2d, x, y, w, h, dx, dy); 696 return true; 697 } 698 699 public Rectangle getNativeBounds() { 700 MTLRenderQueue rq = MTLRenderQueue.getInstance(); 701 rq.lock(); 702 try { 703 return new Rectangle(nativeWidth, nativeHeight); 704 } finally { 705 rq.unlock(); 706 } 707 } 708 709 public static class MTLWindowSurfaceData extends MTLSurfaceData { 710 711 public MTLWindowSurfaceData(CPlatformView pView, 712 MTLGraphicsConfig gc) { 713 super(pView, gc, gc.getColorModel(), WINDOW, 0, 0); 714 } 715 716 @Override 717 public SurfaceData getReplacement() { 718 return pView.getSurfaceData(); 719 } 720 721 @Override 722 public Rectangle getBounds() { 723 Rectangle r = pView.getBounds(); 724 return new Rectangle(0, 0, r.width, r.height); 725 } 726 727 /** 728 * Returns destination Component associated with this SurfaceData. 729 */ 730 @Override 731 public Object getDestination() { 732 return pView.getDestination(); 733 } 734 735 public void validate() { 736 MTLRenderQueue rq = MTLRenderQueue.getInstance(); 737 rq.lock(); 738 try { 739 rq.flushAndInvokeNow(() -> { 740 Rectangle peerBounds = pView.getBounds(); 741 validate(0, 0, peerBounds.width, peerBounds.height, pView.isOpaque()); 742 }); 743 } finally { 744 rq.unlock(); 745 } 746 } 747 748 @Override 749 public void invalidate() { 750 super.invalidate(); 751 clearWindow(); 752 } 753 } 754 755 /** 756 * A surface which implements an intermediate buffer between 757 * the Java2D flusher thread and the AppKit thread. 758 * 759 * This surface serves as a buffer attached to a MTLLayer and 760 * the layer redirects all painting to the buffer's graphics. 761 */ 762 public static class MTLLayerSurfaceData extends MTLSurfaceData { 763 764 private MTLLayer layer; 765 766 public MTLLayerSurfaceData(MTLLayer layer, MTLGraphicsConfig gc, 767 int width, int height) { 768 super(layer, gc, gc.getColorModel(), RT_TEXTURE, width, height); 769 this.layer = layer; 770 initSurface(this.width, this.height); 771 } 772 773 @Override 774 public SurfaceData getReplacement() { 775 return layer.getSurfaceData(); 776 } 777 778 @Override 779 public boolean isOnScreen() { 780 return true; 781 } 782 783 @Override 784 public Rectangle getBounds() { 785 return new Rectangle(width, height); 786 } 787 788 @Override 789 public Object getDestination() { 790 return layer.getDestination(); 791 } 792 793 @Override 794 public int getTransparency() { 795 return layer.getTransparency(); 796 } 797 798 @Override 799 public void invalidate() { 800 super.invalidate(); 801 clearWindow(); 802 } 803 } 804 805 /** 806 * A surface which implements a v-synced flip back-buffer with COPIED 807 * FlipContents. 808 * 809 * This surface serves as a back-buffer to the outside world, while it is 810 * actually an offscreen surface. When the BufferStrategy this surface 811 * belongs to is showed, it is first copied to the real private 812 * FLIP_BACKBUFFER, which is then flipped. 813 */ 814 public static class MTLVSyncOffScreenSurfaceData extends 815 MTLOffScreenSurfaceData { 816 private MTLOffScreenSurfaceData flipSurface; 817 818 public MTLVSyncOffScreenSurfaceData(CPlatformView pView, 819 MTLGraphicsConfig gc, int width, int height, Image image, 820 ColorModel cm, int type) { 821 super(pView, gc, width, height, image, cm, type); 822 flipSurface = MTLSurfaceData.createData(pView, image, 823 FLIP_BACKBUFFER); 824 } 825 826 public SurfaceData getFlipSurface() { 827 return flipSurface; 828 } 829 830 @Override 831 public void flush() { 832 flipSurface.flush(); 833 super.flush(); 834 } 835 } 836 837 public static class MTLOffScreenSurfaceData extends MTLSurfaceData { 838 private Image offscreenImage; 839 840 public MTLOffScreenSurfaceData(CPlatformView pView, 841 MTLGraphicsConfig gc, int width, int height, Image image, 842 ColorModel cm, int type) { 843 super(pView, gc, cm, type, width, height); 844 offscreenImage = image; 845 initSurface(this.width, this.height); 846 } 847 848 @Override 849 public SurfaceData getReplacement() { 850 return restoreContents(offscreenImage); 851 } 852 853 @Override 854 public Rectangle getBounds() { 855 if (type == FLIP_BACKBUFFER) { 856 Rectangle r = pView.getBounds(); 857 return new Rectangle(0, 0, r.width, r.height); 858 } else { 859 return new Rectangle(width, height); 860 } 861 } 862 863 /** 864 * Returns destination Image associated with this SurfaceData. 865 */ 866 @Override 867 public Object getDestination() { 868 return offscreenImage; 869 } 870 } 871 872 873 // additional cleanup 874 private static native void destroyCGLContext(long ctx); 875 876 public static void destroyOGLContext(long ctx) { 877 if (ctx != 0L) { 878 destroyCGLContext(ctx); 879 } 880 } 881 882 public static void dispose(long pData, long pConfigInfo) { 883 MTLGraphicsConfig.deRefPConfigInfo(pConfigInfo); 884 } 885 }