1 /* 2 * Copyright (c) 2019, 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 java.awt.*; 29 30 import sun.awt.image.PixelConverter; 31 import sun.java2d.SurfaceData; 32 33 import java.awt.Composite; 34 import sun.java2d.loops.CompositeType; 35 import sun.java2d.loops.GraphicsPrimitive; 36 import java.awt.image.ColorModel; 37 import java.awt.image.Raster; 38 import sun.java2d.loops.SurfaceType; 39 import sun.java2d.metal.MetalLayer; 40 import sun.awt.SunHints; 41 import sun.java2d.metal.MetalGraphicsConfig; 42 import sun.java2d.opengl.CGLGraphicsConfig; 43 import sun.java2d.opengl.CGLLayer; 44 import sun.java2d.opengl.CGLSurfaceData; 45 import sun.java2d.opengl.OGLRenderQueue; 46 import sun.lwawt.macosx.CPlatformView; 47 import sun.java2d.pipe.hw.AccelSurface; 48 import sun.java2d.metal.MetalRenderer; 49 import sun.java2d.metal.MetalRenderQueue; 50 import sun.java2d.pipe.PixelToParallelogramConverter; 51 import sun.java2d.pipe.ParallelogramPipe; 52 import sun.java2d.SunGraphics2D; 53 54 public class MetalSurfaceData extends SurfaceData 55 implements AccelSurface { 56 //protected final int scale; 57 protected final int width; 58 protected final int height; 59 protected CPlatformView pView; 60 private MetalGraphicsConfig graphicsConfig; 61 62 //private MetalGraphicsConfig graphicsConfig; 63 private int nativeWidth, nativeHeight; 64 protected int type; 65 protected static ParallelogramPipe mtlAAPgramPipe; 66 protected static MetalRenderer mtlRenderPipe; 67 protected static PixelToParallelogramConverter mtlTxRenderPipe; 68 69 /** 70 * SurfaceTypes 71 */ 72 private static final String DESC_METAL_SURFACE = "Metal Surface"; 73 74 static final SurfaceType MetalSurface = 75 SurfaceType.Any.deriveSubType(DESC_METAL_SURFACE, 76 PixelConverter.ArgbPre.instance); 77 78 private native int getTextureTarget(long pData); 79 private native int getTextureID(long pData); 80 protected native boolean initTexture(long pData, 81 boolean isOpaque, 82 int width, int height); 83 protected native void clearWindow(); 84 85 static { 86 if (!GraphicsEnvironment.isHeadless()) { 87 MetalRenderQueue rq = MetalRenderQueue.getInstance(); 88 mtlRenderPipe = new MetalRenderer(rq); 89 90 mtlAAPgramPipe = mtlRenderPipe.getAAParallelogramPipe(); 91 92 mtlTxRenderPipe = 93 new PixelToParallelogramConverter(mtlRenderPipe, 94 mtlRenderPipe, 95 1.0, 0.25, true); 96 MetalBlitLoops.register(); 97 } 98 } 99 100 native void validate(int xoff, int yoff, int width, int height, boolean isOpaque); 101 102 private native void initOps(long pConfigInfo, long pPeerData, long layerPtr, 103 int xoff, int yoff, boolean isOpaque); 104 105 MetalSurfaceData(MetalGraphicsConfig gc, ColorModel cm, int type, 106 int width, int height) { 107 // TODO : Map the coming type to proper custom type and call super() 108 //super(gc, cm, type); 109 //super(SurfaceType.Any3Byte, cm ); 110 super(MetalSurface, cm ); 111 // TEXTURE shouldn't be scaled, it is used for managed BufferedImages. 112 // TODO : We need to set scale factor 113 //scale = type == TEXTURE ? 1 : gc.getDevice().getScaleFactor(); 114 this.width = width ;// * scale; 115 this.height = height;// * scale; 116 117 graphicsConfig = gc; 118 } 119 120 protected MetalSurfaceData(CPlatformView pView, MetalGraphicsConfig gc, 121 ColorModel cm, int type, int width, int height) 122 { 123 this(gc, cm, type, width, height); 124 this.pView = pView; 125 this.graphicsConfig = gc; 126 127 // TODO : Check whether we need native config info here 128 long pConfigInfo = gc.getNativeConfigInfo(); 129 long pPeerData = 0L; 130 boolean isOpaque = true; 131 if (pView != null) { 132 pPeerData = pView.getAWTView(); 133 isOpaque = pView.isOpaque(); 134 } 135 // TODO : check initOps logic it is native is OGL 136 initOps(pConfigInfo, pPeerData, 0, 0, 0, isOpaque); 137 } 138 139 protected MetalSurfaceData(MetalLayer layer, MetalGraphicsConfig gc, 140 ColorModel cm, int type, int width, int height) 141 { 142 this(gc, cm, type, width, height); 143 this.graphicsConfig = gc; 144 145 long pConfigInfo = gc.getNativeConfigInfo(); 146 long layerPtr = 0L; 147 boolean isOpaque = true; 148 if (layer != null) { 149 layerPtr = layer.getPointer(); 150 isOpaque = layer.isOpaque(); 151 } 152 initOps(pConfigInfo, 0, layerPtr, 0, 0, isOpaque); 153 } 154 155 public GraphicsConfiguration getDeviceConfiguration() { 156 return graphicsConfig; //dummy 157 } 158 159 public static MetalWindowSurfaceData createData(CPlatformView pView) { 160 MetalGraphicsConfig gc = getGC(pView); 161 return new MetalWindowSurfaceData(pView, gc); 162 } 163 164 public static MetalSurfaceData createData(MetalLayer layer) { 165 MetalGraphicsConfig gc = getGC(layer); 166 Rectangle r = layer.getBounds(); 167 //return new MetalSurfaceData( gc, gc.getColorModel(), 1, r.width, r.height); 168 return new MetalLayerSurfaceData(layer, gc, r.width, r.height); 169 } 170 171 public static MetalGraphicsConfig getGC(CPlatformView pView) { 172 if (pView != null) { 173 return (MetalGraphicsConfig)pView.getGraphicsConfiguration(); 174 } else { 175 // REMIND: this should rarely (never?) happen, but what if 176 // default config is not CGL? 177 GraphicsEnvironment env = GraphicsEnvironment 178 .getLocalGraphicsEnvironment(); 179 GraphicsDevice gd = env.getDefaultScreenDevice(); 180 return (MetalGraphicsConfig) gd.getDefaultConfiguration(); 181 } 182 } 183 184 public static MetalGraphicsConfig getGC(MetalLayer layer) { 185 return (MetalGraphicsConfig)layer.getGraphicsConfiguration(); 186 } 187 188 public void validate() { 189 // Overridden in MetalWindowSurfaceData below 190 } 191 192 public Rectangle getNativeBounds() { 193 MetalRenderQueue rq = MetalRenderQueue.getInstance(); 194 rq.lock(); 195 try { 196 return new Rectangle(nativeWidth, nativeHeight); 197 } finally { 198 rq.unlock(); 199 } 200 } 201 202 public long getNativeResource(int resType) { 203 if (resType == TEXTURE) { 204 return getTextureID(); 205 } 206 return 0L; 207 } 208 209 public Object getDestination() { 210 return this; //dummy 211 } 212 213 214 //Returns one of the surface type constants defined above. 215 216 public final int getType() { 217 return type; 218 } 219 220 // 221 // If this surface is backed by a texture object, returns the target 222 // for that texture (either GL_TEXTURE_2D or GL_TEXTURE_RECTANGLE_ARB). 223 /// Otherwise, this method will return zero. 224 public final int getTextureTarget() { 225 return getTextureTarget(getNativeOps()); 226 } 227 228 // 229 // If this surface is backed by a texture object, returns the texture ID 230 // for that texture. 231 //Otherwise, this method will return zero. 232 // 233 public final int getTextureID() { 234 return getTextureID(getNativeOps()); 235 } 236 237 // Returns the MetalContext for the GraphicsConfig associated with this 238 //surface. 239 public final MetalContext getContext() { 240 return graphicsConfig.getContext(); 241 } 242 243 244 245 246 public void validatePipe(SunGraphics2D sg2d) { 247 //TextPipe textpipe; 248 //boolean validated = false; 249 250 // OGLTextRenderer handles both AA and non-AA text, but 251 // only works with the following modes: 252 // (Note: For LCD text we only enter this code path if 253 // canRenderLCDText() has already validated that the mode is 254 // CompositeType.SrcNoEa (opaque color), which will be subsumed 255 // by the CompositeType.SrcNoEa (any color) test below.) 256 257 // Copy block from OGLSurfaceData 258 //textpipe = sg2d.textpipe; //tmp 259 260 PixelToParallelogramConverter txPipe = null; 261 MetalRenderer nonTxPipe = null; 262 263 if (sg2d.antialiasHint != SunHints.INTVAL_ANTIALIAS_ON) { 264 if (sg2d.paintState <= SunGraphics2D.PAINT_ALPHACOLOR) { 265 if (sg2d.compositeState <= SunGraphics2D.COMP_XOR) { 266 txPipe = mtlTxRenderPipe; 267 nonTxPipe = mtlRenderPipe; 268 } 269 } else if (sg2d.compositeState <= SunGraphics2D.COMP_ALPHA) { 270 //if (OGLPaints.isValid(sg2d)) { 271 txPipe = mtlTxRenderPipe; 272 nonTxPipe = mtlRenderPipe; 273 //} 274 // custom paints handled by super.validatePipe() below 275 } 276 } else { 277 if (sg2d.paintState <= SunGraphics2D.PAINT_ALPHACOLOR) { 278 if (//graphicsConfig.isCapPresent(CAPS_PS30) && 279 (sg2d.imageComp == CompositeType.SrcOverNoEa || 280 sg2d.imageComp == CompositeType.SrcOver)) 281 { 282 //if (!validated) { 283 super.validatePipe(sg2d); 284 //validated = true; 285 //} 286 PixelToParallelogramConverter aaConverter = 287 new PixelToParallelogramConverter(sg2d.shapepipe, 288 mtlAAPgramPipe, 289 1.0/8.0, 0.499, 290 false); 291 sg2d.drawpipe = aaConverter; 292 sg2d.fillpipe = aaConverter; 293 sg2d.shapepipe = aaConverter; 294 } else if (sg2d.compositeState == SunGraphics2D.COMP_XOR) { 295 // install the solid pipes when AA and XOR are both enabled 296 txPipe = mtlTxRenderPipe; 297 nonTxPipe = mtlRenderPipe; 298 } 299 } 300 // other cases handled by super.validatePipe() below 301 } 302 303 if (txPipe != null) { 304 if (sg2d.transformState >= SunGraphics2D.TRANSFORM_TRANSLATESCALE) { 305 sg2d.drawpipe = txPipe; 306 sg2d.fillpipe = txPipe; 307 } else if (sg2d.strokeState != SunGraphics2D.STROKE_THIN) { 308 sg2d.drawpipe = txPipe; 309 sg2d.fillpipe = nonTxPipe; 310 } else { 311 sg2d.drawpipe = nonTxPipe; 312 sg2d.fillpipe = nonTxPipe; 313 } 314 // Note that we use the transforming pipe here because it 315 // will examine the shape and possibly perform an optimized 316 // operation if it can be simplified. The simplifications 317 // will be valid for all STROKE and TRANSFORM types. 318 sg2d.shapepipe = txPipe; 319 } else { 320 321 super.validatePipe(sg2d); 322 323 } 324 325 // install the text pipe based on our earlier decision 326 //sg2d.textpipe = textpipe; 327 328 // always override the image pipe with the specialized OGL pipe 329 // TODO : We dont override image pipe with MetalImagePipe. 330 // this needs to be implemented. 331 sg2d.imagepipe = imagepipe; 332 } 333 334 public SurfaceData getReplacement() { 335 return this; //dummy 336 } 337 338 /* 339 * TODO : In case of OpenGL their is no getRaster() 340 * implementation in CGLSurfaceData or OGLSurfaceData. 341 * Needs more verification. 342 */ 343 public Raster getRaster(int x, int y, int w, int h) { 344 throw new InternalError("not implemented yet"); 345 //System.out.println("MetalSurfaceData -- getRaster() not implemented yet"); 346 } 347 348 public Rectangle getBounds() { 349 //Rectangle r = pView.getBounds(); 350 return new Rectangle(0, 0, width, height); 351 } 352 353 protected void initSurface(final int width, final int height) { 354 MetalRenderQueue rq = MetalRenderQueue.getInstance(); 355 rq.lock(); 356 try { 357 rq.flushAndInvokeNow(new Runnable() { 358 public void run() { 359 initSurfaceNow(width, height); 360 } 361 }); 362 } finally { 363 rq.unlock(); 364 } 365 } 366 367 private void initSurfaceNow(int width, int height) { 368 boolean isOpaque = (getTransparency() == Transparency.OPAQUE); 369 boolean success = false; 370 371 /*switch (type) { 372 case TEXTURE: 373 success = initTexture(getNativeOps(), 374 isOpaque, isTexNonPow2Available(), 375 isTexRectAvailable(), 376 width, height); 377 break; 378 379 case FBOBJECT: 380 success = initFBObject(getNativeOps(), 381 isOpaque, isTexNonPow2Available(), 382 isTexRectAvailable(), 383 width, height); 384 break; 385 386 case FLIP_BACKBUFFER: 387 success = initFlipBackbuffer(getNativeOps()); 388 break; 389 390 default: 391 break; 392 }*/ 393 394 success = initTexture(getNativeOps(), 395 isOpaque, 396 width, height); 397 if (!success) { 398 throw new OutOfMemoryError("can't create offscreen surface"); 399 } 400 } 401 402 /** 403 * Creates a SurfaceData object representing the back buffer of a 404 * double-buffered on-screen Window. 405 */ 406 /*public static CGLOffScreenSurfaceData createData(CPlatformView pView, 407 Image image, int type) { 408 CGLGraphicsConfig gc = getGC(pView); 409 Rectangle r = pView.getBounds(); 410 if (type == FLIP_BACKBUFFER) { 411 return new CGLOffScreenSurfaceData(pView, gc, r.width, r.height, 412 image, gc.getColorModel(), FLIP_BACKBUFFER); 413 } else { 414 return new CGLVSyncOffScreenSurfaceData(pView, gc, r.width, 415 r.height, image, gc.getColorModel(), type); 416 } 417 }*/ 418 419 /** 420 * Creates a SurfaceData object representing an off-screen buffer (either a 421 * FBO or Texture). 422 */ 423 public static MetalOffScreenSurfaceData createData(MetalGraphicsConfig gc, 424 int width, int height, ColorModel cm, Image image, int type) { 425 return new MetalOffScreenSurfaceData(null, gc, width, height, image, cm, 426 type); 427 } 428 429 public static class MetalWindowSurfaceData extends MetalSurfaceData { 430 431 public MetalWindowSurfaceData(CPlatformView pView, 432 MetalGraphicsConfig gc) { 433 super(pView, gc, gc.getColorModel(), WINDOW, 0, 0); 434 } 435 436 @Override 437 public SurfaceData getReplacement() { 438 return pView.getSurfaceData(); 439 } 440 441 @Override 442 public Rectangle getBounds() { 443 Rectangle r = pView.getBounds(); 444 return new Rectangle(0, 0, r.width, r.height); 445 } 446 447 /** 448 * Returns destination Component associated with this SurfaceData. 449 */ 450 @Override 451 public Object getDestination() { 452 return pView.getDestination(); 453 } 454 455 @Override 456 public void validate() { 457 MetalRenderQueue rq = MetalRenderQueue.getInstance(); 458 rq.lock(); 459 try { 460 rq.flushAndInvokeNow(new Runnable() { 461 public void run() { 462 Rectangle peerBounds = pView.getBounds(); 463 validate(0, 0, peerBounds.width, peerBounds.height, pView.isOpaque()); 464 } 465 }); 466 } finally { 467 rq.unlock(); 468 } 469 } 470 471 @Override 472 public void invalidate() { 473 super.invalidate(); 474 clearWindow(); 475 } 476 } 477 478 public static class MetalLayerSurfaceData extends MetalSurfaceData { 479 480 private MetalLayer layer; 481 482 public MetalLayerSurfaceData(MetalLayer layer, MetalGraphicsConfig gc, 483 int width, int height) { 484 super(layer, gc, gc.getColorModel(), RT_TEXTURE, width, height); 485 this.layer = layer; 486 initSurface(this.width, this.height); 487 } 488 489 @Override 490 public SurfaceData getReplacement() { 491 return layer.getSurfaceData(); 492 } 493 494 /*@Override 495 boolean isOnScreen() { 496 return true; 497 }*/ 498 499 @Override 500 public Rectangle getBounds() { 501 return new Rectangle(width, height); 502 } 503 504 @Override 505 public Object getDestination() { 506 return layer.getDestination(); 507 } 508 509 @Override 510 public int getTransparency() { 511 return layer.getTransparency(); 512 } 513 514 @Override 515 public void invalidate() { 516 super.invalidate(); 517 clearWindow(); 518 } 519 } 520 521 public static class MetalOffScreenSurfaceData extends MetalSurfaceData { 522 private Image offscreenImage; 523 524 public MetalOffScreenSurfaceData(CPlatformView pView, 525 MetalGraphicsConfig gc, int width, int height, Image image, 526 ColorModel cm, int type) { 527 super(pView, gc, cm, type, width, height); 528 offscreenImage = image; 529 initSurface(this.width, this.height); 530 } 531 532 @Override 533 public SurfaceData getReplacement() { 534 return restoreContents(offscreenImage); 535 } 536 537 @Override 538 public Rectangle getBounds() { 539 if (type == FLIP_BACKBUFFER) { 540 Rectangle r = pView.getBounds(); 541 return new Rectangle(0, 0, r.width, r.height); 542 } else { 543 return new Rectangle(width, height); 544 } 545 } 546 547 /** 548 * Returns destination Image associated with this SurfaceData. 549 */ 550 @Override 551 public Object getDestination() { 552 return offscreenImage; 553 } 554 } 555 // TODO : We have some OGL Mac specific functions, verify their use case 556 }