Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.desktop/macosx/classes/sun/java2d/metal/MTLSurfaceData.java
41159 views
1
/*
2
* Copyright (c) 2019, 2021, 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
43
import java.awt.AlphaComposite;
44
import java.awt.Composite;
45
import java.awt.GraphicsConfiguration;
46
import java.awt.GraphicsEnvironment;
47
import java.awt.Image;
48
import java.awt.Rectangle;
49
import java.awt.Transparency;
50
51
import java.awt.image.ColorModel;
52
import java.awt.image.Raster;
53
54
import static sun.java2d.pipe.BufferedOpCodes.DISPOSE_SURFACE;
55
import static sun.java2d.pipe.BufferedOpCodes.FLUSH_SURFACE;
56
import static sun.java2d.pipe.hw.ContextCapabilities.CAPS_MULTITEXTURE;
57
import static sun.java2d.pipe.hw.ContextCapabilities.CAPS_PS30;
58
59
60
public abstract class MTLSurfaceData extends SurfaceData
61
implements AccelSurface {
62
63
/**
64
* Pixel formats
65
*/
66
public static final int PF_INT_ARGB = 0;
67
public static final int PF_INT_ARGB_PRE = 1;
68
public static final int PF_INT_RGB = 2;
69
public static final int PF_INT_RGBX = 3;
70
public static final int PF_INT_BGR = 4;
71
public static final int PF_INT_BGRX = 5;
72
public static final int PF_USHORT_565_RGB = 6;
73
public static final int PF_USHORT_555_RGB = 7;
74
public static final int PF_USHORT_555_RGBX = 8;
75
public static final int PF_BYTE_GRAY = 9;
76
public static final int PF_USHORT_GRAY = 10;
77
public static final int PF_3BYTE_BGR = 11;
78
/**
79
* SurfaceTypes
80
*/
81
82
private static final String DESC_MTL_SURFACE = "MTL Surface";
83
private static final String DESC_MTL_SURFACE_RTT =
84
"MTL Surface (render-to-texture)";
85
private static final String DESC_MTL_TEXTURE = "MTL Texture";
86
87
88
static final SurfaceType MTLSurface =
89
SurfaceType.Any.deriveSubType(DESC_MTL_SURFACE,
90
PixelConverter.ArgbPre.instance);
91
static final SurfaceType MTLSurfaceRTT =
92
MTLSurface.deriveSubType(DESC_MTL_SURFACE_RTT);
93
static final SurfaceType MTLTexture =
94
SurfaceType.Any.deriveSubType(DESC_MTL_TEXTURE);
95
96
protected static MTLRenderer mtlRenderPipe;
97
protected static PixelToParallelogramConverter mtlTxRenderPipe;
98
protected static ParallelogramPipe mtlAAPgramPipe;
99
protected static MTLTextRenderer mtlTextPipe;
100
protected static MTLDrawImage mtlImagePipe;
101
102
static {
103
if (!GraphicsEnvironment.isHeadless()) {
104
MTLRenderQueue rq = MTLRenderQueue.getInstance();
105
mtlImagePipe = new MTLDrawImage();
106
mtlTextPipe = new MTLTextRenderer(rq);
107
mtlRenderPipe = new MTLRenderer(rq);
108
if (GraphicsPrimitive.tracingEnabled()) {
109
mtlTextPipe = mtlTextPipe.traceWrap();
110
//The wrapped mtlRenderPipe will wrap the AA pipe as well...
111
//mtlAAPgramPipe = mtlRenderPipe.traceWrap();
112
}
113
mtlAAPgramPipe = mtlRenderPipe.getAAParallelogramPipe();
114
mtlTxRenderPipe =
115
new PixelToParallelogramConverter(mtlRenderPipe,
116
mtlRenderPipe,
117
1.0, 0.25, true);
118
119
MTLBlitLoops.register();
120
MTLMaskFill.register();
121
MTLMaskBlit.register();
122
}
123
}
124
125
protected final int scale;
126
protected final int width;
127
protected final int height;
128
protected int type;
129
private MTLGraphicsConfig graphicsConfig;
130
// these fields are set from the native code when the surface is
131
// initialized
132
private int nativeWidth;
133
private int nativeHeight;
134
135
/**
136
* Returns the appropriate SurfaceType corresponding to the given Metal
137
* surface type constant (e.g. TEXTURE -> MTLTexture).
138
*/
139
private static SurfaceType getCustomSurfaceType(int mtlType) {
140
switch (mtlType) {
141
case TEXTURE:
142
return MTLTexture;
143
case RT_TEXTURE:
144
return MTLSurfaceRTT;
145
default:
146
return MTLSurface;
147
}
148
}
149
150
private native void initOps(MTLGraphicsConfig gc, long pConfigInfo, long pPeerData, long layerPtr,
151
int xoff, int yoff, boolean isOpaque);
152
153
private MTLSurfaceData(MTLLayer layer, MTLGraphicsConfig gc,
154
ColorModel cm, int type, int width, int height)
155
{
156
super(getCustomSurfaceType(type), cm);
157
this.graphicsConfig = gc;
158
this.type = type;
159
setBlitProxyKey(gc.getProxyKey());
160
161
// TEXTURE shouldn't be scaled, it is used for managed BufferedImages.
162
scale = type == TEXTURE ? 1 : gc.getDevice().getScaleFactor();
163
this.width = width * scale;
164
this.height = height * scale;
165
166
long pConfigInfo = gc.getNativeConfigInfo();
167
long layerPtr = 0L;
168
boolean isOpaque = true;
169
if (layer != null) {
170
layerPtr = layer.getPointer();
171
isOpaque = layer.isOpaque();
172
}
173
initOps(gc, pConfigInfo, 0, layerPtr, 0, 0, isOpaque);
174
}
175
176
@Override
177
public GraphicsConfiguration getDeviceConfiguration() {
178
return graphicsConfig;
179
}
180
181
/**
182
* Creates a SurfaceData object representing the intermediate buffer
183
* between the Java2D flusher thread and the AppKit thread.
184
*/
185
public static MTLLayerSurfaceData createData(MTLLayer layer) {
186
MTLGraphicsConfig gc = (MTLGraphicsConfig)layer.getGraphicsConfiguration();
187
Rectangle r = layer.getBounds();
188
return new MTLLayerSurfaceData(layer, gc, r.width, r.height);
189
}
190
191
/**
192
* Creates a SurfaceData object representing an off-screen buffer
193
*/
194
public static MTLOffScreenSurfaceData createData(MTLGraphicsConfig gc,
195
int width, int height,
196
ColorModel cm, Image image,
197
int type) {
198
return new MTLOffScreenSurfaceData(gc, width, height, image, cm,
199
type);
200
}
201
202
@Override
203
public double getDefaultScaleX() {
204
return scale;
205
}
206
207
@Override
208
public double getDefaultScaleY() {
209
return scale;
210
}
211
212
@Override
213
public Rectangle getBounds() {
214
return new Rectangle(width, height);
215
}
216
217
protected native void clearWindow();
218
219
protected native boolean initTexture(long pData, boolean isOpaque, int width, int height);
220
221
protected native boolean initRTexture(long pData, boolean isOpaque, int width, int height);
222
223
protected native boolean initFlipBackbuffer(long pData);
224
225
@Override
226
public SurfaceDataProxy makeProxyFor(SurfaceData srcData) {
227
return MTLSurfaceDataProxy.createProxy(srcData, graphicsConfig);
228
}
229
230
/**
231
* Note: This should only be called from the QFT under the AWT lock.
232
* This method is kept separate from the initSurface() method below just
233
* to keep the code a bit cleaner.
234
*/
235
private void initSurfaceNow(int width, int height) {
236
boolean isOpaque = (getTransparency() == Transparency.OPAQUE);
237
boolean success = false;
238
239
switch (type) {
240
case TEXTURE:
241
success = initTexture(getNativeOps(), isOpaque, width, height);
242
break;
243
244
case RT_TEXTURE:
245
success = initRTexture(getNativeOps(), isOpaque, width, height);
246
break;
247
248
case FLIP_BACKBUFFER:
249
success = initFlipBackbuffer(getNativeOps());
250
break;
251
252
default:
253
break;
254
}
255
256
if (!success) {
257
throw new OutOfMemoryError("can't create offscreen surface");
258
}
259
}
260
261
/**
262
* Initializes the appropriate Metal offscreen surface based on the value
263
* of the type parameter. If the surface creation fails for any reason,
264
* an OutOfMemoryError will be thrown.
265
*/
266
protected void initSurface(final int width, final int height) {
267
MTLRenderQueue rq = MTLRenderQueue.getInstance();
268
rq.lock();
269
try {
270
switch (type) {
271
case TEXTURE:
272
case RT_TEXTURE:
273
// need to make sure the context is current before
274
// creating the texture
275
MTLContext.setScratchSurface(graphicsConfig);
276
break;
277
default:
278
break;
279
}
280
rq.flushAndInvokeNow(new Runnable() {
281
public void run() {
282
initSurfaceNow(width, height);
283
}
284
});
285
} finally {
286
rq.unlock();
287
}
288
}
289
290
/**
291
* Returns the MTLContext for the GraphicsConfig associated with this
292
* surface.
293
*/
294
public final MTLContext getContext() {
295
return graphicsConfig.getContext();
296
}
297
298
/**
299
* Returns the MTLGraphicsConfig associated with this surface.
300
*/
301
final MTLGraphicsConfig getMTLGraphicsConfig() {
302
return graphicsConfig;
303
}
304
305
/**
306
* Returns one of the surface type constants defined above.
307
*/
308
public final int getType() {
309
return type;
310
}
311
312
/**
313
* For now, we can only render LCD text if:
314
* - the fragment shader extension is available, and
315
* - the source color is opaque, and
316
* - blending is SrcOverNoEa or disabled
317
* - and the destination is opaque
318
*
319
* Eventually, we could enhance the native MTL text rendering code
320
* and remove the above restrictions, but that would require significantly
321
* more code just to support a few uncommon cases.
322
*/
323
public boolean canRenderLCDText(SunGraphics2D sg2d) {
324
return
325
sg2d.surfaceData.getTransparency() == Transparency.OPAQUE &&
326
sg2d.paintState <= SunGraphics2D.PAINT_OPAQUECOLOR &&
327
(sg2d.compositeState <= SunGraphics2D.COMP_ISCOPY ||
328
(sg2d.compositeState <= SunGraphics2D.COMP_ALPHA && canHandleComposite(sg2d.composite)));
329
}
330
331
private boolean canHandleComposite(Composite c) {
332
if (c instanceof AlphaComposite) {
333
AlphaComposite ac = (AlphaComposite)c;
334
335
return ac.getRule() == AlphaComposite.SRC_OVER && ac.getAlpha() >= 1f;
336
}
337
return false;
338
}
339
340
public void validatePipe(SunGraphics2D sg2d) {
341
TextPipe textpipe;
342
boolean validated = false;
343
344
// MTLTextRenderer handles both AA and non-AA text, but
345
// only works with the following modes:
346
// (Note: For LCD text we only enter this code path if
347
// canRenderLCDText() has already validated that the mode is
348
// CompositeType.SrcNoEa (opaque color), which will be subsumed
349
// by the CompositeType.SrcNoEa (any color) test below.)
350
351
if (/* CompositeType.SrcNoEa (any color) */
352
(sg2d.compositeState <= SunGraphics2D.COMP_ISCOPY &&
353
sg2d.paintState <= SunGraphics2D.PAINT_ALPHACOLOR) ||
354
355
/* CompositeType.SrcOver (any color) */
356
(sg2d.compositeState == SunGraphics2D.COMP_ALPHA &&
357
sg2d.paintState <= SunGraphics2D.PAINT_ALPHACOLOR &&
358
(((AlphaComposite)sg2d.composite).getRule() ==
359
AlphaComposite.SRC_OVER)) ||
360
361
/* CompositeType.Xor (any color) */
362
(sg2d.compositeState == SunGraphics2D.COMP_XOR &&
363
sg2d.paintState <= SunGraphics2D.PAINT_ALPHACOLOR))
364
{
365
textpipe = mtlTextPipe;
366
} else {
367
// do this to initialize textpipe correctly; we will attempt
368
// to override the non-text pipes below
369
super.validatePipe(sg2d);
370
textpipe = sg2d.textpipe;
371
validated = true;
372
}
373
374
PixelToParallelogramConverter txPipe = null;
375
MTLRenderer nonTxPipe = null;
376
377
if (sg2d.antialiasHint != SunHints.INTVAL_ANTIALIAS_ON) {
378
if (sg2d.paintState <= SunGraphics2D.PAINT_ALPHACOLOR) {
379
if (sg2d.compositeState <= SunGraphics2D.COMP_XOR) {
380
txPipe = mtlTxRenderPipe;
381
nonTxPipe = mtlRenderPipe;
382
}
383
} else if (sg2d.compositeState <= SunGraphics2D.COMP_ALPHA) {
384
if (MTLPaints.isValid(sg2d)) {
385
txPipe = mtlTxRenderPipe;
386
nonTxPipe = mtlRenderPipe;
387
}
388
// custom paints handled by super.validatePipe() below
389
}
390
} else {
391
if (sg2d.paintState <= SunGraphics2D.PAINT_ALPHACOLOR) {
392
if (graphicsConfig.isCapPresent(CAPS_PS30) &&
393
(sg2d.imageComp == CompositeType.SrcOverNoEa ||
394
sg2d.imageComp == CompositeType.SrcOver))
395
{
396
if (!validated) {
397
super.validatePipe(sg2d);
398
validated = true;
399
}
400
PixelToParallelogramConverter aaConverter =
401
new PixelToParallelogramConverter(sg2d.shapepipe,
402
mtlAAPgramPipe,
403
1.0/8.0, 0.499,
404
false);
405
sg2d.drawpipe = aaConverter;
406
sg2d.fillpipe = aaConverter;
407
sg2d.shapepipe = aaConverter;
408
} else if (sg2d.compositeState == SunGraphics2D.COMP_XOR) {
409
// install the solid pipes when AA and XOR are both enabled
410
txPipe = mtlTxRenderPipe;
411
nonTxPipe = mtlRenderPipe;
412
}
413
}
414
// other cases handled by super.validatePipe() below
415
}
416
417
if (txPipe != null) {
418
if (sg2d.transformState >= SunGraphics2D.TRANSFORM_TRANSLATESCALE) {
419
sg2d.drawpipe = txPipe;
420
sg2d.fillpipe = txPipe;
421
} else if (sg2d.strokeState != SunGraphics2D.STROKE_THIN) {
422
sg2d.drawpipe = txPipe;
423
sg2d.fillpipe = nonTxPipe;
424
} else {
425
sg2d.drawpipe = nonTxPipe;
426
sg2d.fillpipe = nonTxPipe;
427
}
428
// Note that we use the transforming pipe here because it
429
// will examine the shape and possibly perform an optimized
430
// operation if it can be simplified. The simplifications
431
// will be valid for all STROKE and TRANSFORM types.
432
sg2d.shapepipe = txPipe;
433
} else {
434
if (!validated) {
435
super.validatePipe(sg2d);
436
}
437
}
438
439
// install the text pipe based on our earlier decision
440
sg2d.textpipe = textpipe;
441
442
// always override the image pipe with the specialized MTL pipe
443
sg2d.imagepipe = mtlImagePipe;
444
}
445
446
@Override
447
protected MaskFill getMaskFill(SunGraphics2D sg2d) {
448
if (sg2d.paintState > SunGraphics2D.PAINT_ALPHACOLOR) {
449
/*
450
* We can only accelerate non-Color MaskFill operations if
451
* all of the following conditions hold true:
452
* - there is an implementation for the given paintState
453
* - the current Paint can be accelerated for this destination
454
* - multitexturing is available (since we need to modulate
455
* the alpha mask texture with the paint texture)
456
*
457
* In all other cases, we return null, in which case the
458
* validation code will choose a more general software-based loop.
459
*/
460
if (!MTLPaints.isValid(sg2d) ||
461
!graphicsConfig.isCapPresent(CAPS_MULTITEXTURE))
462
{
463
return null;
464
}
465
}
466
return super.getMaskFill(sg2d);
467
}
468
469
public void flush() {
470
invalidate();
471
MTLRenderQueue rq = MTLRenderQueue.getInstance();
472
rq.lock();
473
try {
474
// make sure we have a current context before
475
// disposing the native resources (e.g. texture object)
476
MTLContext.setScratchSurface(graphicsConfig);
477
478
RenderBuffer buf = rq.getBuffer();
479
rq.ensureCapacityAndAlignment(12, 4);
480
buf.putInt(FLUSH_SURFACE);
481
buf.putLong(getNativeOps());
482
483
// this call is expected to complete synchronously, so flush now
484
rq.flushNow();
485
} finally {
486
rq.unlock();
487
}
488
}
489
490
public boolean isOnScreen() {
491
return false;
492
}
493
494
private native long getMTLTexturePointer(long pData);
495
496
/**
497
* Returns native resource of specified {@code resType} associated with
498
* this surface.
499
*
500
* Specifically, for {@code MTLSurfaceData} this method returns the
501
* the following:
502
* <pre>
503
* TEXTURE - texture id
504
* </pre>
505
*
506
* Note: the resource returned by this method is only valid on the rendering
507
* thread.
508
*
509
* @return native resource of specified type or 0L if
510
* such resource doesn't exist or can not be retrieved.
511
* @see AccelSurface#getNativeResource
512
*/
513
public long getNativeResource(int resType) {
514
if (resType == TEXTURE) {
515
return getMTLTexturePointer(getNativeOps());
516
}
517
return 0L;
518
}
519
520
public Raster getRaster(int x, int y, int w, int h) {
521
throw new InternalError("not implemented yet");
522
}
523
524
@Override
525
public boolean copyArea(SunGraphics2D sg2d, int x, int y, int w, int h,
526
int dx, int dy) {
527
if (sg2d.compositeState >= SunGraphics2D.COMP_XOR) {
528
return false;
529
}
530
mtlRenderPipe.copyArea(sg2d, x, y, w, h, dx, dy);
531
return true;
532
}
533
534
public Rectangle getNativeBounds() {
535
MTLRenderQueue rq = MTLRenderQueue.getInstance();
536
rq.lock();
537
try {
538
return new Rectangle(nativeWidth, nativeHeight);
539
} finally {
540
rq.unlock();
541
}
542
}
543
544
/**
545
* A surface which implements an intermediate buffer between
546
* the Java2D flusher thread and the AppKit thread.
547
*
548
* This surface serves as a buffer attached to a MTLLayer and
549
* the layer redirects all painting to the buffer's graphics.
550
*/
551
public static class MTLLayerSurfaceData extends MTLSurfaceData {
552
553
private final MTLLayer layer;
554
555
private MTLLayerSurfaceData(MTLLayer layer, MTLGraphicsConfig gc,
556
int width, int height) {
557
super(layer, gc, gc.getColorModel(), RT_TEXTURE, width, height);
558
this.layer = layer;
559
initSurface(this.width, this.height);
560
}
561
562
@Override
563
public SurfaceData getReplacement() {
564
return layer.getSurfaceData();
565
}
566
567
@Override
568
public boolean isOnScreen() {
569
return true;
570
}
571
572
@Override
573
public Object getDestination() {
574
return layer.getDestination();
575
}
576
577
@Override
578
public int getTransparency() {
579
return layer.getTransparency();
580
}
581
582
@Override
583
public void invalidate() {
584
super.invalidate();
585
clearWindow();
586
}
587
}
588
589
/**
590
* SurfaceData object representing an off-screen buffer
591
*/
592
public static class MTLOffScreenSurfaceData extends MTLSurfaceData {
593
private final Image offscreenImage;
594
595
public MTLOffScreenSurfaceData(MTLGraphicsConfig gc, int width,
596
int height, Image image,
597
ColorModel cm, int type) {
598
super(null, gc, cm, type, width, height);
599
offscreenImage = image;
600
initSurface(this.width, this.height);
601
}
602
603
@Override
604
public SurfaceData getReplacement() {
605
return restoreContents(offscreenImage);
606
}
607
608
/**
609
* Returns destination Image associated with this SurfaceData.
610
*/
611
@Override
612
public Object getDestination() {
613
return offscreenImage;
614
}
615
}
616
617
618
/**
619
* Disposes the native resources associated with the given MTLSurfaceData
620
* (referenced by the pData parameter). This method is invoked from
621
* the native Dispose() method from the Disposer thread when the
622
* Java-level MTLSurfaceData object is about to go away.
623
*/
624
public static void dispose(long pData, MTLGraphicsConfig gc) {
625
MTLRenderQueue rq = MTLRenderQueue.getInstance();
626
rq.lock();
627
try {
628
// make sure we have a current context before
629
// disposing the native resources (e.g. texture object)
630
MTLContext.setScratchSurface(gc);
631
RenderBuffer buf = rq.getBuffer();
632
rq.ensureCapacityAndAlignment(12, 4);
633
buf.putInt(DISPOSE_SURFACE);
634
buf.putLong(pData);
635
636
// this call is expected to complete synchronously, so flush now
637
rq.flushNow();
638
} finally {
639
rq.unlock();
640
}
641
}
642
}
643
644