Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/EncoderManager.m
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
#include "EncoderManager.h"
27
#include "MTLContext.h"
28
#include "sun_java2d_SunGraphics2D.h"
29
#import "common.h"
30
31
// NOTE: uncomment to disable comparing cached encoder states with requested (for debugging)
32
// #define ALWAYS_UPDATE_ENCODER_STATES
33
34
const SurfaceRasterFlags defaultRasterFlags = { JNI_FALSE, JNI_TRUE };
35
36
// Internal utility class that represents the set of 'mutable' encoder properties
37
@interface EncoderStates : NSObject
38
@property (readonly) MTLClip * clip;
39
40
- (id)init;
41
- (void)dealloc;
42
43
- (void)reset:(id<MTLTexture>)destination
44
isDstOpaque:(jboolean)isDstOpaque
45
isDstPremultiplied:(jboolean)isDstPremultiplied
46
isAA:(jboolean)isAA
47
isText:(jboolean)isText
48
isLCD:(jboolean)isLCD;
49
50
- (void)updateEncoder:(id<MTLRenderCommandEncoder>)encoder
51
context:(MTLContext *)mtlc
52
renderOptions:(const RenderOptions *)renderOptions
53
forceUpdate:(jboolean)forceUpdate;
54
@property (assign) jboolean aa;
55
@property (assign) jboolean text;
56
@property (assign) jboolean lcd;
57
@property (assign) jboolean aaShader;
58
@property (retain) MTLPaint* paint;
59
@end
60
61
@implementation EncoderStates {
62
MTLPipelineStatesStorage * _pipelineStateStorage;
63
id<MTLDevice> _device;
64
65
// Persistent encoder properties
66
id<MTLTexture> _destination;
67
SurfaceRasterFlags _dstFlags;
68
69
jboolean _isAA;
70
jboolean _isText;
71
jboolean _isLCD;
72
jboolean _isAAShader;
73
74
//
75
// Cached 'mutable' states of encoder
76
//
77
78
// Composite rule and source raster flags (it affects the CAD-multipliers (of pipelineState))
79
MTLComposite * _composite;
80
SurfaceRasterFlags _srcFlags;
81
82
// Paint mode (it affects shaders (of pipelineState) and corresponding buffers)
83
MTLPaint * _paint;
84
85
// If true, indicates that encoder is used for texture drawing (user must do [encoder setFragmentTexture:] before drawing)
86
jboolean _isTexture;
87
int _interpolationMode;
88
89
// Clip rect or stencil
90
MTLClip * _clip;
91
92
// Transform (affects transformation inside vertex shader)
93
MTLTransform * _transform;
94
}
95
@synthesize aa = _isAA;
96
@synthesize text = _isText;
97
@synthesize lcd = _isLCD;
98
@synthesize aaShader = _isAAShader;
99
@synthesize paint = _paint;
100
101
- (id)init {
102
self = [super init];
103
if (self) {
104
_destination = nil;
105
_composite = [[MTLComposite alloc] init];
106
_paint = [[MTLPaint alloc] init];
107
_transform = [[MTLTransform alloc] init];
108
_clip = [[MTLClip alloc] init];
109
}
110
return self;
111
}
112
113
- (void)dealloc {
114
[_composite release];
115
[_paint release];
116
[_transform release];
117
[super dealloc];
118
}
119
120
- (void)setContext:(MTLContext * _Nonnull)mtlc {
121
self->_pipelineStateStorage = mtlc.pipelineStateStorage;
122
self->_device = mtlc.device;
123
}
124
125
- (void)reset:(id<MTLTexture>)destination
126
isDstOpaque:(jboolean)isDstOpaque
127
isDstPremultiplied:(jboolean)isDstPremultiplied
128
isAA:(jboolean)isAA
129
isText:(jboolean)isText
130
isLCD:(jboolean)isLCD {
131
_destination = destination;
132
_dstFlags.isOpaque = isDstOpaque;
133
_dstFlags.isPremultiplied = isDstPremultiplied;
134
_isAA = isAA;
135
_isText = isText;
136
_isLCD = isLCD;
137
// NOTE: probably it's better to invalidate/reset all cached states now
138
}
139
140
- (void)updateEncoder:(id<MTLRenderCommandEncoder>)encoder
141
context:(MTLContext *)mtlc
142
renderOptions:(const RenderOptions *)renderOptions
143
forceUpdate:(jboolean)forceUpdate
144
{
145
// 1. Process special case for stencil mask generation
146
if (mtlc.clip.stencilMaskGenerationInProgress == JNI_TRUE) {
147
// use separate pipeline state for stencil generation
148
if (forceUpdate || (_clip.stencilMaskGenerationInProgress != JNI_TRUE)) {
149
[_clip copyFrom:mtlc.clip];
150
[_clip setMaskGenerationPipelineState:encoder
151
destWidth:_destination.width
152
destHeight:_destination.height
153
pipelineStateStorage:_pipelineStateStorage];
154
}
155
156
[self updateTransform:encoder transform:mtlc.transform forceUpdate:forceUpdate];
157
return;
158
}
159
160
// 2. Otherwise update all 'mutable' properties of encoder
161
[self updatePipelineState:encoder
162
context:mtlc
163
renderOptions:renderOptions
164
forceUpdate:forceUpdate];
165
[self updateTransform:encoder transform:mtlc.transform forceUpdate:forceUpdate];
166
[self updateClip:encoder clip:mtlc.clip forceUpdate:forceUpdate];
167
}
168
169
//
170
// Internal methods that update states when necessary (compare with cached states)
171
//
172
173
// Updates pipelineState (and corresponding buffers) with use of paint+composite+flags
174
- (void)updatePipelineState:(id<MTLRenderCommandEncoder>)encoder
175
context:(MTLContext *)mtlc
176
renderOptions:(const RenderOptions *)renderOptions
177
forceUpdate:(jboolean)forceUpdate
178
{
179
if (!forceUpdate
180
&& [_paint isEqual:mtlc.paint]
181
&& [_composite isEqual:mtlc.composite]
182
&& (_isTexture == renderOptions->isTexture && (!renderOptions->isTexture || _interpolationMode == renderOptions->interpolation)) // interpolation is used only in texture mode
183
&& _isAA == renderOptions->isAA
184
&& _isAAShader == renderOptions->isAAShader
185
&& _isText == renderOptions->isText
186
&& _isLCD == renderOptions->isLCD
187
&& _srcFlags.isOpaque == renderOptions->srcFlags.isOpaque && _srcFlags.isPremultiplied == renderOptions->srcFlags.isPremultiplied)
188
return;
189
190
self.paint = mtlc.paint;
191
[_composite copyFrom:mtlc.composite];
192
_isTexture = renderOptions->isTexture;
193
_interpolationMode = renderOptions->interpolation;
194
_isAA = renderOptions->isAA;
195
_isAAShader = renderOptions->isAAShader;
196
_isText = renderOptions->isText;
197
_isLCD = renderOptions->isLCD;
198
_srcFlags = renderOptions->srcFlags;
199
200
if ((jint)[mtlc.composite getCompositeState] == sun_java2d_SunGraphics2D_COMP_XOR) {
201
202
[mtlc.paint setXorModePipelineState:encoder
203
context:mtlc
204
renderOptions:renderOptions
205
pipelineStateStorage:_pipelineStateStorage];
206
} else {
207
[mtlc.paint setPipelineState:encoder
208
context:mtlc
209
renderOptions:renderOptions
210
pipelineStateStorage:_pipelineStateStorage];
211
}
212
}
213
214
- (void) updateClip:(id<MTLRenderCommandEncoder>)encoder clip:(MTLClip *)clip forceUpdate:(jboolean)forceUpdate
215
{
216
if (clip.stencilMaskGenerationInProgress == JNI_TRUE) {
217
// don't set setScissorOrStencil when generation in progress
218
return;
219
}
220
221
if (!forceUpdate && [_clip isEqual:clip])
222
return;
223
224
[_clip copyFrom:clip];
225
[_clip setScissorOrStencil:encoder
226
destWidth:_destination.width
227
destHeight:_destination.height
228
device:_device];
229
}
230
231
- (void)updateTransform:(id <MTLRenderCommandEncoder>)encoder
232
transform:(MTLTransform *)transform
233
forceUpdate:(jboolean)forceUpdate
234
{
235
if (!forceUpdate
236
&& [_transform isEqual:transform])
237
return;
238
239
[_transform copyFrom:transform];
240
[_transform setVertexMatrix:encoder
241
destWidth:_destination.width
242
destHeight:_destination.height];
243
}
244
245
@end
246
247
@implementation EncoderManager {
248
MTLContext * _mtlc; // used to obtain CommandBufferWrapper and Composite/Paint/Transform
249
250
id<MTLRenderCommandEncoder> _encoder;
251
252
// 'Persistent' properties of encoder
253
id<MTLTexture> _destination;
254
id<MTLTexture> _aaDestination;
255
BOOL _useStencil;
256
257
// 'Mutable' states of encoder
258
EncoderStates * _encoderStates;
259
}
260
261
- (id _Nonnull)init {
262
self = [super init];
263
if (self) {
264
_encoder = nil;
265
_destination = nil;
266
_aaDestination = nil;
267
_useStencil = NO;
268
_encoderStates = [[EncoderStates alloc] init];
269
270
}
271
return self;
272
}
273
274
- (void)dealloc {
275
[_encoderStates release];
276
[super dealloc];
277
}
278
279
- (void)setContext:(MTLContex * _Nonnull)mtlc {
280
self->_mtlc = mtlc;
281
[self->_encoderStates setContext:mtlc];
282
}
283
284
- (id<MTLRenderCommandEncoder> _Nonnull) getRenderEncoder:(const BMTLSDOps * _Nonnull)dstOps
285
{
286
return [self getRenderEncoder:dstOps->pTexture isDstOpaque:dstOps->isOpaque];
287
}
288
289
- (id<MTLRenderCommandEncoder> _Nonnull)getAARenderEncoder:(const BMTLSDOps * _Nonnull)dstOps {
290
id<MTLTexture> dstTxt = dstOps->pTexture;
291
RenderOptions roptions = {JNI_FALSE, JNI_TRUE, INTERPOLATION_NEAREST_NEIGHBOR, defaultRasterFlags, {dstOps->isOpaque, JNI_TRUE}, JNI_FALSE, JNI_FALSE, JNI_FALSE};
292
return [self getEncoder:dstTxt renderOptions:&roptions];
293
}
294
295
- (id<MTLRenderCommandEncoder> _Nonnull)getAAShaderRenderEncoder:(const BMTLSDOps * _Nonnull)dstOps
296
{
297
RenderOptions roptions = {JNI_FALSE, JNI_FALSE, INTERPOLATION_NEAREST_NEIGHBOR, defaultRasterFlags, {dstOps->isOpaque, JNI_TRUE}, JNI_FALSE, JNI_FALSE, JNI_TRUE};
298
return [self getEncoder:dstOps->pTexture renderOptions:&roptions];
299
}
300
301
- (id<MTLRenderCommandEncoder> _Nonnull)getRenderEncoder:(id<MTLTexture> _Nonnull)dest
302
isDstOpaque:(bool)isOpaque
303
{
304
RenderOptions roptions = {JNI_FALSE, JNI_FALSE, INTERPOLATION_NEAREST_NEIGHBOR, defaultRasterFlags, {isOpaque, JNI_TRUE}, JNI_FALSE, JNI_FALSE, JNI_FALSE};
305
return [self getEncoder:dest renderOptions:&roptions];
306
}
307
308
- (id<MTLRenderCommandEncoder> _Nonnull) getTextureEncoder:(const BMTLSDOps * _Nonnull)dstOps
309
isSrcOpaque:(bool)isSrcOpaque
310
{
311
return [self getTextureEncoder:dstOps->pTexture
312
isSrcOpaque:isSrcOpaque
313
isDstOpaque:dstOps->isOpaque
314
interpolation:INTERPOLATION_NEAREST_NEIGHBOR];
315
}
316
317
- (id<MTLRenderCommandEncoder> _Nonnull) getTextureEncoder:(id<MTLTexture> _Nonnull)dest
318
isSrcOpaque:(bool)isSrcOpaque
319
isDstOpaque:(bool)isDstOpaque
320
{
321
return [self getTextureEncoder:dest
322
isSrcOpaque:isSrcOpaque
323
isDstOpaque:isDstOpaque
324
interpolation:INTERPOLATION_NEAREST_NEIGHBOR
325
isAA:JNI_FALSE];
326
}
327
328
- (id<MTLRenderCommandEncoder> _Nonnull) getLCDEncoder:(id<MTLTexture> _Nonnull)dest
329
isSrcOpaque:(bool)isSrcOpaque
330
isDstOpaque:(bool)isDstOpaque
331
{
332
RenderOptions roptions = {JNI_TRUE, JNI_FALSE, INTERPOLATION_NEAREST_NEIGHBOR, {isSrcOpaque, JNI_TRUE }, {isDstOpaque, JNI_TRUE}, JNI_FALSE, JNI_TRUE, JNI_FALSE};
333
return [self getEncoder:dest renderOptions:&roptions];
334
}
335
336
- (id<MTLRenderCommandEncoder> _Nonnull) getTextureEncoder:(id<MTLTexture> _Nonnull)dest
337
isSrcOpaque:(bool)isSrcOpaque
338
isDstOpaque:(bool)isDstOpaque
339
interpolation:(int)interpolation
340
isAA:(jboolean)isAA
341
{
342
RenderOptions roptions = {JNI_TRUE, isAA, interpolation, { isSrcOpaque, JNI_TRUE }, {isDstOpaque, JNI_TRUE}, JNI_FALSE, JNI_FALSE, JNI_FALSE};
343
return [self getEncoder:dest renderOptions:&roptions];
344
}
345
346
- (id<MTLRenderCommandEncoder> _Nonnull) getTextureEncoder:(id<MTLTexture> _Nonnull)dest
347
isSrcOpaque:(bool)isSrcOpaque
348
isDstOpaque:(bool)isDstOpaque
349
interpolation:(int)interpolation
350
{
351
return [self getTextureEncoder:dest isSrcOpaque:isSrcOpaque isDstOpaque:isDstOpaque interpolation:interpolation isAA:JNI_FALSE];
352
}
353
354
- (id<MTLRenderCommandEncoder> _Nonnull) getTextEncoder:(const BMTLSDOps * _Nonnull)dstOps
355
isSrcOpaque:(bool)isSrcOpaque
356
{
357
RenderOptions roptions = {JNI_TRUE, JNI_FALSE, INTERPOLATION_NEAREST_NEIGHBOR, { isSrcOpaque, JNI_TRUE }, {dstOps->isOpaque, JNI_TRUE}, JNI_TRUE, JNI_FALSE, JNI_FALSE};
358
return [self getEncoder:dstOps->pTexture renderOptions:&roptions];
359
}
360
361
- (id<MTLRenderCommandEncoder> _Nonnull) getEncoder:(id <MTLTexture> _Nonnull)dest
362
renderOptions:(const RenderOptions * _Nonnull)renderOptions
363
{
364
//
365
// 1. check whether it's necessary to call endEncoder
366
//
367
jboolean needEnd = JNI_FALSE;
368
if (_encoder != nil) {
369
if (_destination != dest || renderOptions->isAA != _encoderStates.aa) {
370
J2dTraceLn2(J2D_TRACE_VERBOSE,
371
"end common encoder because of dest change: %p -> %p",
372
_destination, dest);
373
needEnd = JNI_TRUE;
374
} else if ((_useStencil == NO) != ([_mtlc.clip isShape] == NO)) {
375
// 1. When mode changes RECT -> SHAPE we must recreate encoder with
376
// stencilAttachment (todo: consider the case when current encoder already
377
// has stencil)
378
//
379
// 2. When mode changes SHAPE -> RECT it seems that we can use the same
380
// encoder with disabled stencil test, but [encoder
381
// setDepthStencilState:nil] causes crash, so we have to recreate encoder
382
// in such case
383
J2dTraceLn2(J2D_TRACE_VERBOSE,
384
"end common encoder because toggle stencil: %d -> %d",
385
(int)_useStencil, (int)[_mtlc.clip isShape]);
386
needEnd = JNI_TRUE;
387
}
388
}
389
if (needEnd)
390
[self endEncoder];
391
392
//
393
// 2. recreate encoder if necessary
394
//
395
jboolean forceUpdate = JNI_FALSE;
396
#ifdef ALWAYS_UPDATE_ENCODER_STATES
397
forceUpdate = JNI_TRUE;
398
#endif // ALWAYS_UPDATE_ENCODER_STATES
399
400
if (_encoder == nil) {
401
_destination = dest;
402
_useStencil = [_mtlc.clip isShape] && !_mtlc.clip.stencilMaskGenerationInProgress;
403
forceUpdate = JNI_TRUE;
404
405
MTLCommandBufferWrapper *cbw = [_mtlc getCommandBufferWrapper];
406
MTLRenderPassDescriptor *rpd =
407
[MTLRenderPassDescriptor renderPassDescriptor];
408
MTLRenderPassColorAttachmentDescriptor *ca = rpd.colorAttachments[0];
409
ca.texture = dest;
410
411
// TODO: Find out why we cannot use
412
// if (_mtlc.clip.stencilMaskGenerationInProgress == YES) {
413
// ca.loadAction = MTLLoadActionClear;
414
// ca.clearColor = MTLClearColorMake(0.0f, 0.0f,0.0f, 0.0f);
415
// }
416
// here to avoid creation of clearEncoder in beginShapeClip
417
418
ca.loadAction = MTLLoadActionLoad;
419
ca.storeAction = MTLStoreActionStore;
420
421
if (_useStencil && !renderOptions->isAA) {
422
// If you enable stencil testing or stencil writing, the
423
// MTLRenderPassDescriptor must include a stencil attachment.
424
rpd.stencilAttachment.loadAction = MTLLoadActionLoad;
425
rpd.stencilAttachment.storeAction = MTLStoreActionStore;
426
rpd.stencilAttachment.texture = _mtlc.clip.stencilTextureRef;
427
} else if (_mtlc.clip.stencilMaskGenerationInProgress == YES) {
428
rpd.stencilAttachment.texture = _mtlc.clip.dstOps->pStencilTexture;
429
rpd.stencilAttachment.clearStencil = 0;
430
rpd.stencilAttachment.loadAction = _mtlc.clip.stencilMaskGenerationStarted? MTLLoadActionLoad : MTLLoadActionClear;
431
_mtlc.clip.stencilMaskGenerationStarted = YES;
432
rpd.stencilAttachment.storeAction = MTLStoreActionStore;
433
}
434
435
// J2dTraceLn1(J2D_TRACE_VERBOSE, "created render encoder to draw on
436
// tex=%p", dest);
437
_encoder = [[cbw getCommandBuffer] renderCommandEncoderWithDescriptor:rpd];
438
439
[_encoderStates reset:dest
440
isDstOpaque:renderOptions->dstFlags.isOpaque
441
isDstPremultiplied:YES
442
isAA:renderOptions->isAA
443
isText:renderOptions->isText
444
isLCD:renderOptions->isLCD];
445
}
446
447
//
448
// 3. update encoder states
449
//
450
[_encoderStates updateEncoder:_encoder
451
context:_mtlc
452
renderOptions:renderOptions
453
forceUpdate:forceUpdate];
454
455
return _encoder;
456
}
457
458
- (id<MTLBlitCommandEncoder> _Nonnull) createBlitEncoder {
459
[self endEncoder];
460
return [[[_mtlc getCommandBufferWrapper] getCommandBuffer] blitCommandEncoder];
461
}
462
463
- (void) endEncoder {
464
if (_encoder != nil) {
465
[_encoder endEncoding];
466
_encoder = nil;
467
_destination = nil;
468
}
469
}
470
471
@end
472
473