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/MTLRenderer.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 <jlong.h>
27
#include <jni_util.h>
28
#include <math.h>
29
30
#include "sun_java2d_metal_MTLRenderer.h"
31
32
#include "MTLRenderer.h"
33
#include "MTLRenderQueue.h"
34
#include "MTLSurfaceData.h"
35
#include "MTLUtils.h"
36
#import "MTLLayer.h"
37
38
/**
39
* Note: Some of the methods in this file apply a "magic number"
40
* translation to line segments. It is same as what we have in
41
* OGLrenderer.
42
*
43
* The "magic numbers" you see here have been empirically derived
44
* after testing on a variety of graphics hardware in order to find some
45
* reasonable middle ground between the two specifications. The general
46
* approach is to apply a fractional translation to vertices so that they
47
* hit pixel centers and therefore touch the same pixels as in our other
48
* pipelines. Emphasis was placed on finding values so that MTL lines with
49
* a slope of +/- 1 hit all the same pixels as our other (software) loops.
50
* The stepping in other diagonal lines rendered with MTL may deviate
51
* slightly from those rendered with our software loops, but the most
52
* important thing is that these magic numbers ensure that all MTL lines
53
* hit the same endpoints as our software loops.
54
*
55
* If you find it necessary to change any of these magic numbers in the
56
* future, just be sure that you test the changes across a variety of
57
* hardware to ensure consistent rendering everywhere.
58
*/
59
60
void MTLRenderer_DrawLine(MTLContext *mtlc, BMTLSDOps * dstOps, jint x1, jint y1, jint x2, jint y2) {
61
if (mtlc == NULL || dstOps == NULL || dstOps->pTexture == NULL) {
62
J2dTraceLn(J2D_TRACE_ERROR, "MTLRenderer_DrawLine: dest is null");
63
return;
64
}
65
66
J2dTraceLn5(J2D_TRACE_INFO, "MTLRenderer_DrawLine (x1=%d y1=%d x2=%d y2=%d), dst tex=%p", x1, y1, x2, y2, dstOps->pTexture);
67
68
id<MTLRenderCommandEncoder> mtlEncoder = [mtlc.encoderManager getRenderEncoder:dstOps];
69
if (mtlEncoder == nil)
70
return;
71
72
// DrawLine implementation same as in OGLRenderer.c
73
struct Vertex verts[2];
74
if (y1 == y2) {
75
// horizontal
76
float fx1 = (float)x1;
77
float fx2 = (float)x2;
78
float fy = ((float)y1) + 0.2f;
79
80
if (x1 > x2) {
81
float t = fx1; fx1 = fx2; fx2 = t;
82
}
83
84
verts[0].position[0] = fx1 + 0.2f;
85
verts[0].position[1] = fy;
86
verts[1].position[0] = fx2 + 1.2f;
87
verts[1].position[1] = fy;
88
} else if (x1 == x2) {
89
// vertical
90
float fx = ((float)x1) + 0.2f;
91
float fy1 = (float)y1;
92
float fy2 = (float)y2;
93
94
if (y1 > y2) {
95
float t = fy1; fy1 = fy2; fy2 = t;
96
}
97
98
verts[0].position[0] = fx;
99
verts[0].position[1] = fy1 + 0.2f;
100
verts[1].position[0] = fx;
101
verts[1].position[1] = fy2 + 1.2f;
102
} else {
103
// diagonal
104
float fx1 = (float)x1;
105
float fy1 = (float)y1;
106
float fx2 = (float)x2;
107
float fy2 = (float)y2;
108
109
if (x1 < x2) {
110
fx1 += 0.2f;
111
fx2 += 1.0f;
112
} else {
113
fx1 += 0.8f;
114
fx2 -= 0.2f;
115
}
116
117
if (y1 < y2) {
118
fy1 += 0.2f;
119
fy2 += 1.0f;
120
} else {
121
fy1 += 0.8f;
122
fy2 -= 0.2f;
123
}
124
verts[0].position[0] = fx1;
125
verts[0].position[1] = fy1;
126
verts[1].position[0] = fx2;
127
verts[1].position[1] = fy2;
128
}
129
130
[mtlEncoder setVertexBytes:verts length:sizeof(verts) atIndex:MeshVertexBuffer];
131
[mtlEncoder drawPrimitives:MTLPrimitiveTypeLine vertexStart:0 vertexCount:2];
132
}
133
134
void MTLRenderer_DrawPixel(MTLContext *mtlc, BMTLSDOps * dstOps, jint x, jint y) {
135
if (mtlc == NULL || dstOps == NULL || dstOps->pTexture == NULL) {
136
J2dTraceLn(J2D_TRACE_ERROR, "MTLRenderer_DrawPixel: dest is null");
137
return;
138
}
139
140
id<MTLTexture> dest = dstOps->pTexture;
141
J2dTraceLn3(J2D_TRACE_INFO, "MTLRenderer_DrawPixel (x=%d y=%d), dst tex=%p", x, y, dest);
142
143
id<MTLRenderCommandEncoder> mtlEncoder = [mtlc.encoderManager getRenderEncoder:dstOps];
144
if (mtlEncoder == nil)
145
return;
146
147
// Translate each vertex by a fraction so
148
// that we hit pixel centers.
149
float fx = (float)x + 0.2f;
150
float fy = (float)y + 0.5f;
151
struct Vertex vert = {{fx, fy}};
152
[mtlEncoder setVertexBytes:&vert length:sizeof(vert) atIndex:MeshVertexBuffer];
153
[mtlEncoder drawPrimitives:MTLPrimitiveTypePoint vertexStart:0 vertexCount:1];
154
}
155
156
void MTLRenderer_DrawRect(MTLContext *mtlc, BMTLSDOps * dstOps, jint x, jint y, jint w, jint h) {
157
if (mtlc == NULL || dstOps == NULL || dstOps->pTexture == NULL) {
158
J2dTraceLn(J2D_TRACE_ERROR, "MTLRenderer_DrawRect: dest is null");
159
return;
160
}
161
162
id<MTLTexture> dest = dstOps->pTexture;
163
J2dTraceLn5(J2D_TRACE_INFO, "MTLRenderer_DrawRect (x=%d y=%d w=%d h=%d), dst tex=%p", x, y, w, h, dest);
164
165
// TODO: use DrawParallelogram(x, y, w, h, lw=1, lh=1)
166
id<MTLRenderCommandEncoder> mtlEncoder = [mtlc.encoderManager getRenderEncoder:dstOps];
167
if (mtlEncoder == nil)
168
return;
169
170
// Translate each vertex by a fraction so
171
// that we hit pixel centers.
172
const int verticesCount = 5;
173
float fx = (float)x + 0.2f;
174
float fy = (float)y + 0.5f;
175
float fw = (float)w;
176
float fh = (float)h;
177
struct Vertex vertices[5] = {
178
{{fx, fy}},
179
{{fx + fw, fy}},
180
{{fx + fw, fy + fh}},
181
{{fx, fy + fh}},
182
{{fx, fy}},
183
};
184
[mtlEncoder setVertexBytes:vertices length:sizeof(vertices) atIndex:MeshVertexBuffer];
185
[mtlEncoder drawPrimitives:MTLPrimitiveTypeLineStrip vertexStart:0 vertexCount:verticesCount];
186
}
187
188
const int POLYLINE_BUF_SIZE = 64;
189
190
NS_INLINE void fillVertex(struct Vertex * vertex, int x, int y) {
191
vertex->position[0] = x;
192
vertex->position[1] = y;
193
}
194
195
void MTLRenderer_DrawPoly(MTLContext *mtlc, BMTLSDOps * dstOps,
196
jint nPoints, jint isClosed,
197
jint transX, jint transY,
198
jint *xPoints, jint *yPoints)
199
{
200
// Note that BufferedRenderPipe.drawPoly() has already rejected polys
201
// with nPoints<2, so we can be certain here that we have nPoints>=2.
202
if (xPoints == NULL || yPoints == NULL || nPoints < 2) { // just for insurance
203
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLRenderer_DrawPoly: points array is empty");
204
return;
205
}
206
207
if (mtlc == NULL || dstOps == NULL || dstOps->pTexture == NULL) {
208
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLRenderer_DrawPoly: dest is null");
209
return;
210
}
211
212
J2dTraceLn4(J2D_TRACE_INFO, "MTLRenderer_DrawPoly: %d points, transX=%d, transY=%d, dst tex=%p", nPoints, transX, transY, dstOps->pTexture);
213
214
__block struct {
215
struct Vertex verts[POLYLINE_BUF_SIZE];
216
} pointsChunk;
217
218
// We intend to submit draw commands in batches of POLYLINE_BUF_SIZE vertices at a time
219
// Subsequent batches need to be connected - so end point in one batch is repeated as first point in subsequent batch
220
// This inflates the total number of points by a factor of number of batches of size POLYLINE_BUF_SIZE
221
nPoints += (nPoints/POLYLINE_BUF_SIZE);
222
223
jint prevX = *(xPoints++);
224
jint prevY = *(yPoints++);
225
const jint firstX = prevX;
226
const jint firstY = prevY;
227
while (nPoints > 0) {
228
const bool isLastChunk = nPoints <= POLYLINE_BUF_SIZE;
229
__block int chunkSize = isLastChunk ? nPoints : POLYLINE_BUF_SIZE;
230
231
fillVertex(pointsChunk.verts, prevX + transX + 0.5f, prevY + transY + 0.5f);
232
J2dTraceLn2(J2D_TRACE_INFO, "MTLRenderer_DrawPoly: Point - (%1.2f, %1.2f)", prevX + transX + 0.5f, prevY + transY + 0.5f);
233
234
for (int i = 1; i < chunkSize; i++) {
235
prevX = *(xPoints++);
236
prevY = *(yPoints++);
237
fillVertex(pointsChunk.verts + i, prevX + transX + 0.5f, prevY + transY + 0.5f);
238
J2dTraceLn2(J2D_TRACE_INFO, "MTLRenderer_DrawPoly: Point - (%1.2f, %1.2f)", prevX + transX + 0.5f,prevY + transY + 0.5f);
239
}
240
241
bool drawCloseSegment = false;
242
if (isClosed && isLastChunk) {
243
if (chunkSize + 2 <= POLYLINE_BUF_SIZE) {
244
fillVertex(pointsChunk.verts + chunkSize, firstX + transX + 0.5f, firstY + transY + 0.5f);
245
J2dTraceLn2(J2D_TRACE_INFO, "MTLRenderer_DrawPoly: Point - (%1.2f, %1.2f)",firstX + transX + 0.5f, firstY + transY + 0.5f);
246
247
++chunkSize;
248
} else
249
drawCloseSegment = true;
250
}
251
252
nPoints -= chunkSize;
253
id<MTLRenderCommandEncoder> mtlEncoder = [mtlc.encoderManager getRenderEncoder:dstOps];
254
if (mtlEncoder == nil)
255
return;
256
257
[mtlEncoder setVertexBytes:pointsChunk.verts length:sizeof(pointsChunk.verts) atIndex:MeshVertexBuffer];
258
[mtlEncoder drawPrimitives:MTLPrimitiveTypeLineStrip vertexStart:0 vertexCount:chunkSize];
259
260
if (drawCloseSegment) {
261
struct Vertex vertices[2] = {
262
{{prevX + transX + 0.5f, prevY + transY + 0.5f}},
263
{{firstX + transX + 0.5f, firstY + transY + 0.5f}}
264
};
265
266
J2dTraceLn2(J2D_TRACE_INFO, "MTLRenderer_DrawPoly: last segment Point1 - (%1.2f, %1.2f)",prevX + transX + 0.5f, prevY + transY + 0.5f);
267
J2dTraceLn2(J2D_TRACE_INFO, "MTLRenderer_DrawPoly: last segment Point2 - (%1.2f, %1.2f)",firstX + transX + 0.5f, firstY + transY + 0.5f);
268
269
[mtlEncoder setVertexBytes:vertices length:sizeof(vertices) atIndex:MeshVertexBuffer];
270
[mtlEncoder drawPrimitives:MTLPrimitiveTypeLine vertexStart:0 vertexCount:2];
271
}
272
}
273
}
274
275
JNIEXPORT void JNICALL
276
Java_sun_java2d_metal_MTLRenderer_drawPoly
277
(JNIEnv *env, jobject mtlr,
278
jintArray xpointsArray, jintArray ypointsArray,
279
jint nPoints, jboolean isClosed,
280
jint transX, jint transY)
281
{
282
jint *xPoints, *yPoints;
283
284
J2dTraceLn(J2D_TRACE_INFO, "MTLRenderer_drawPoly");
285
286
xPoints = (jint *)
287
(*env)->GetPrimitiveArrayCritical(env, xpointsArray, NULL);
288
if (xPoints != NULL) {
289
yPoints = (jint *)
290
(*env)->GetPrimitiveArrayCritical(env, ypointsArray, NULL);
291
if (yPoints != NULL) {
292
MTLContext *mtlc = MTLRenderQueue_GetCurrentContext();
293
BMTLSDOps *dstOps = MTLRenderQueue_GetCurrentDestination();
294
295
MTLRenderer_DrawPoly(mtlc, dstOps,
296
nPoints, isClosed,
297
transX, transY,
298
xPoints, yPoints);
299
if (mtlc != NULL) {
300
RESET_PREVIOUS_OP();
301
[mtlc.encoderManager endEncoder];
302
MTLCommandBufferWrapper * cbwrapper = [mtlc pullCommandBufferWrapper];
303
id<MTLCommandBuffer> commandbuf = [cbwrapper getCommandBuffer];
304
[commandbuf addCompletedHandler:^(id <MTLCommandBuffer> commandbuf) {
305
[cbwrapper release];
306
}];
307
[commandbuf commit];
308
}
309
310
(*env)->ReleasePrimitiveArrayCritical(env, ypointsArray, yPoints,
311
JNI_ABORT);
312
}
313
(*env)->ReleasePrimitiveArrayCritical(env, xpointsArray, xPoints,
314
JNI_ABORT);
315
}
316
}
317
318
const int SCANLINE_MAX_VERTEX_SIZE = 4096;
319
const int VERTEX_STRUCT_SIZE = 8;
320
const int NUM_OF_VERTICES_PER_SCANLINE = 2;
321
322
void
323
MTLRenderer_DrawScanlines(MTLContext *mtlc, BMTLSDOps * dstOps,
324
jint scanlineCount, jint *scanlines)
325
{
326
327
J2dTraceLn2(J2D_TRACE_INFO, "MTLRenderer_DrawScanlines (scanlineCount=%d), dst tex=%p", scanlineCount, dstOps->pTexture);
328
if (mtlc == NULL || dstOps == NULL || dstOps->pTexture == NULL) {
329
J2dTraceLn(J2D_TRACE_ERROR, "MTLRenderer_DrawScanlines: dest is null");
330
return;
331
}
332
RETURN_IF_NULL(scanlines);
333
int vertexSize = NUM_OF_VERTICES_PER_SCANLINE
334
* scanlineCount * VERTEX_STRUCT_SIZE;
335
J2dTraceLn1(J2D_TRACE_INFO, "MTLRenderer_DrawScanlines: Total vertex size : %d", vertexSize);
336
if (vertexSize == 0) return;
337
338
id<MTLRenderCommandEncoder> mtlEncoder = [mtlc.encoderManager getRenderEncoder:dstOps];
339
340
if (mtlEncoder == nil) return;
341
342
if (vertexSize <= SCANLINE_MAX_VERTEX_SIZE) {
343
struct Vertex verts[NUM_OF_VERTICES_PER_SCANLINE * scanlineCount];
344
345
for (int j = 0, i = 0; j < scanlineCount; j++) {
346
// Translate each vertex by a fraction so
347
// that we hit pixel centers.
348
float x1 = ((float)*(scanlines++)) + 0.2f;
349
float x2 = ((float)*(scanlines++)) + 1.2f;
350
float y = ((float)*(scanlines++)) + 0.5f;
351
struct Vertex v1 = {{x1, y}};
352
struct Vertex v2 = {{x2, y}};
353
verts[i++] = v1;
354
verts[i++] = v2;
355
}
356
357
[mtlEncoder setVertexBytes:verts length:sizeof(verts) atIndex:MeshVertexBuffer];
358
[mtlEncoder drawPrimitives:MTLPrimitiveTypeLine vertexStart:0
359
vertexCount:NUM_OF_VERTICES_PER_SCANLINE * scanlineCount];
360
} else {
361
int remainingScanlineCount = vertexSize;
362
do {
363
if (remainingScanlineCount > SCANLINE_MAX_VERTEX_SIZE) {
364
struct Vertex verts[SCANLINE_MAX_VERTEX_SIZE/ VERTEX_STRUCT_SIZE];
365
366
for (int j = 0, i = 0; j < (SCANLINE_MAX_VERTEX_SIZE / (VERTEX_STRUCT_SIZE * 2)); j++) {
367
// Translate each vertex by a fraction so
368
// that we hit pixel centers.
369
float x1 = ((float)*(scanlines++)) + 0.2f;
370
float x2 = ((float)*(scanlines++)) + 1.2f;
371
float y = ((float)*(scanlines++)) + 0.5f;
372
struct Vertex v1 = {{x1, y}};
373
struct Vertex v2 = {{x2, y}};
374
verts[i++] = v1;
375
verts[i++] = v2;
376
}
377
378
[mtlEncoder setVertexBytes:verts length:sizeof(verts) atIndex:MeshVertexBuffer];
379
[mtlEncoder drawPrimitives:MTLPrimitiveTypeLine vertexStart:0
380
vertexCount:(SCANLINE_MAX_VERTEX_SIZE / VERTEX_STRUCT_SIZE)];
381
remainingScanlineCount -= SCANLINE_MAX_VERTEX_SIZE;
382
} else {
383
struct Vertex verts[remainingScanlineCount / VERTEX_STRUCT_SIZE];
384
385
for (int j = 0, i = 0; j < (remainingScanlineCount / (VERTEX_STRUCT_SIZE * 2)); j++) {
386
// Translate each vertex by a fraction so
387
// that we hit pixel centers.
388
float x1 = ((float)*(scanlines++)) + 0.2f;
389
float x2 = ((float)*(scanlines++)) + 1.2f;
390
float y = ((float)*(scanlines++)) + 0.5f;
391
struct Vertex v1 = {{x1, y}};
392
struct Vertex v2 = {{x2, y}};
393
verts[i++] = v1;
394
verts[i++] = v2;
395
}
396
397
[mtlEncoder setVertexBytes:verts length:sizeof(verts) atIndex:MeshVertexBuffer];
398
[mtlEncoder drawPrimitives:MTLPrimitiveTypeLine vertexStart:0
399
vertexCount:(remainingScanlineCount / VERTEX_STRUCT_SIZE)];
400
remainingScanlineCount -= remainingScanlineCount;
401
}
402
J2dTraceLn1(J2D_TRACE_INFO,
403
"MTLRenderer_DrawScanlines: Remaining vertex size %d", remainingScanlineCount);
404
} while (remainingScanlineCount != 0);
405
}
406
}
407
408
void
409
MTLRenderer_FillRect(MTLContext *mtlc, BMTLSDOps * dstOps, jint x, jint y, jint w, jint h)
410
{
411
J2dTraceLn(J2D_TRACE_INFO, "MTLRenderer_FillRect");
412
413
if (mtlc == NULL || dstOps == NULL || dstOps->pTexture == NULL) {
414
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLRenderer_FillRect: current dest is null");
415
return;
416
}
417
418
struct Vertex verts[QUAD_VERTEX_COUNT] = {
419
{ {x, y}},
420
{ {x, y+h}},
421
{ {x+w, y}},
422
{ {x+w, y+h}
423
}};
424
425
426
id<MTLTexture> dest = dstOps->pTexture;
427
J2dTraceLn5(J2D_TRACE_INFO, "MTLRenderer_FillRect (x=%d y=%d w=%d h=%d), dst tex=%p", x, y, w, h, dest);
428
429
// Encode render command.
430
id<MTLRenderCommandEncoder> mtlEncoder = [mtlc.encoderManager getRenderEncoder:dstOps];
431
if (mtlEncoder == nil)
432
return;
433
434
[mtlEncoder setVertexBytes:verts length:sizeof(verts) atIndex:MeshVertexBuffer];
435
[mtlEncoder drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount: QUAD_VERTEX_COUNT];
436
}
437
438
void MTLRenderer_FillSpans(MTLContext *mtlc, BMTLSDOps * dstOps, jint spanCount, jint *spans)
439
{
440
J2dTraceLn(J2D_TRACE_INFO, "MTLRenderer_FillSpans");
441
if (mtlc == NULL || dstOps == NULL || dstOps->pTexture == NULL) {
442
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLRenderer_FillSpans: dest is null");
443
return;
444
}
445
446
// MTLRenderCommandEncoder setVertexBytes usage is recommended if the data is of 4KB.
447
448
// We use a buffer that closely matches the 4KB limit size
449
// This buffer is resued multiple times to encode draw calls of a triangle list
450
// NOTE : Due to nature of *spans data - it is not possible to use triangle strip.
451
// We use triangle list to draw spans
452
453
// Destination texture to which render commands are encoded
454
id<MTLTexture> dest = dstOps->pTexture;
455
id<MTLTexture> destAA = nil;
456
BOOL isDestOpaque = dstOps->isOpaque;
457
if (mtlc.clip.stencilMaskGenerationInProgress == JNI_TRUE) {
458
dest = dstOps->pStencilData;
459
isDestOpaque = NO;
460
}
461
id<MTLRenderCommandEncoder> mtlEncoder = [mtlc.encoderManager getRenderEncoder:dest isDstOpaque:isDestOpaque];
462
if (mtlEncoder == nil) {
463
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLRenderer_FillSpans: mtlEncoder is nil");
464
return;
465
}
466
467
// This is the max no of vertices (of struct Vertex - 8 bytes) we can accomodate in 4KB
468
const int TOTAL_VERTICES_IN_BLOCK = 510;
469
struct Vertex vertexList[TOTAL_VERTICES_IN_BLOCK]; // a total of 170 triangles ==> 85 spans
470
471
jfloat shapeX1 = mtlc.clip.shapeX;
472
jfloat shapeY1 = mtlc.clip.shapeY;
473
jfloat shapeX2 = (mtlc.clip.shapeWidth > 0)? shapeX1 + mtlc.clip.shapeWidth : 0;
474
jfloat shapeY2 = (mtlc.clip.shapeHeight > 0)? shapeY1 + mtlc.clip.shapeHeight : 0;
475
476
int counter = 0;
477
for (int i = 0; i < spanCount; i++) {
478
jfloat x1 = *(spans++);
479
jfloat y1 = *(spans++);
480
jfloat x2 = *(spans++);
481
jfloat y2 = *(spans++);
482
483
if (mtlc.clip.stencilMaskGenerationInProgress == JNI_TRUE) {
484
if (shapeX1 > x1) shapeX1 = x1;
485
if (shapeY1 > y1) shapeY1 = y1;
486
if (shapeX2 < x2) shapeX2 = x2;
487
if (shapeY2 < y2) shapeY2 = y2;
488
}
489
490
struct Vertex verts[6] = {
491
{{x1, y1}},
492
{{x1, y2}},
493
{{x2, y1}},
494
495
{{x1, y2}},
496
{{x2, y1}},
497
{{x2, y2}
498
}};
499
500
memcpy(&vertexList[counter], &verts, sizeof(verts));
501
counter += 6;
502
503
// If vertexList buffer full
504
if (counter % TOTAL_VERTICES_IN_BLOCK == 0) {
505
[mtlEncoder setVertexBytes:vertexList length:sizeof(vertexList) atIndex:MeshVertexBuffer];
506
[mtlEncoder drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:0 vertexCount:TOTAL_VERTICES_IN_BLOCK];
507
counter = 0;
508
}
509
}
510
511
// Draw triangles using remaining vertices if any
512
if (counter != 0) {
513
[mtlEncoder setVertexBytes:vertexList length:sizeof(vertexList) atIndex:MeshVertexBuffer];
514
[mtlEncoder drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:0 vertexCount:counter];
515
}
516
517
if (mtlc.clip.stencilMaskGenerationInProgress == JNI_TRUE) {
518
if (shapeX1 < 0) shapeX1 = 0;
519
if (shapeY1 < 0) shapeY1 = 0;
520
if (shapeX1 > dest.width) shapeX1 = dest.width;
521
if (shapeY1 > dest.height) shapeY1 = dest.height;
522
if (shapeX2 < 0) shapeX2 = 0;
523
if (shapeY2 < 0) shapeY2 = 0;
524
if (shapeX2 > dest.width) shapeX2 = dest.width;
525
if (shapeY2 > dest.height) shapeY2 = dest.height;
526
527
mtlc.clip.shapeX = (NSUInteger) shapeX1;
528
mtlc.clip.shapeY = (NSUInteger) shapeY1;
529
mtlc.clip.shapeWidth = (NSUInteger) (shapeX2 - shapeX1);
530
mtlc.clip.shapeHeight = (NSUInteger) (shapeY2 - shapeY1);
531
}
532
}
533
534
void
535
MTLRenderer_FillParallelogram(MTLContext *mtlc, BMTLSDOps * dstOps,
536
jfloat fx11, jfloat fy11,
537
jfloat dx21, jfloat dy21,
538
jfloat dx12, jfloat dy12)
539
{
540
541
if (mtlc == NULL || dstOps == NULL || dstOps->pTexture == NULL) {
542
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLRenderer_FillParallelogram: current dest is null");
543
return;
544
}
545
546
id<MTLTexture> dest = dstOps->pTexture;
547
J2dTraceLn7(J2D_TRACE_INFO,
548
"MTLRenderer_FillParallelogram"
549
"(x=%6.2f y=%6.2f "
550
"dx1=%6.2f dy1=%6.2f "
551
"dx2=%6.2f dy2=%6.2f dst tex=%p)",
552
fx11, fy11,
553
dx21, dy21,
554
dx12, dy12, dest);
555
556
struct Vertex verts[QUAD_VERTEX_COUNT] = {
557
{ {fx11, fy11}},
558
{ {fx11+dx21, fy11+dy21}},
559
{ {fx11+dx12, fy11+dy12}},
560
{ {fx11 + dx21 + dx12, fy11+ dy21 + dy12}
561
}};
562
563
// Encode render command.
564
id<MTLRenderCommandEncoder> mtlEncoder = [mtlc.encoderManager getRenderEncoder:dstOps];;
565
566
if (mtlEncoder == nil) {
567
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLRenderer_FillParallelogram: error creating MTLRenderCommandEncoder.");
568
return;
569
}
570
571
[mtlEncoder setVertexBytes:verts length:sizeof(verts) atIndex:MeshVertexBuffer];
572
[mtlEncoder drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount: QUAD_VERTEX_COUNT];
573
}
574
575
void
576
MTLRenderer_DrawParallelogram(MTLContext *mtlc, BMTLSDOps * dstOps,
577
jfloat fx11, jfloat fy11,
578
jfloat dx21, jfloat dy21,
579
jfloat dx12, jfloat dy12,
580
jfloat lwr21, jfloat lwr12)
581
{
582
// dx,dy for line width in the "21" and "12" directions.
583
jfloat ldx21 = dx21 * lwr21;
584
jfloat ldy21 = dy21 * lwr21;
585
jfloat ldx12 = dx12 * lwr12;
586
jfloat ldy12 = dy12 * lwr12;
587
588
// calculate origin of the outer parallelogram
589
jfloat ox11 = fx11 - (ldx21 + ldx12) / 2.0f;
590
jfloat oy11 = fy11 - (ldy21 + ldy12) / 2.0f;
591
592
J2dTraceLn8(J2D_TRACE_INFO,
593
"MTLRenderer_DrawParallelogram"
594
"(x=%6.2f y=%6.2f "
595
"dx1=%6.2f dy1=%6.2f lwr1=%6.2f "
596
"dx2=%6.2f dy2=%6.2f lwr2=%6.2f)",
597
fx11, fy11,
598
dx21, dy21, lwr21,
599
dx12, dy12, lwr12);
600
601
602
// Only need to generate 4 quads if the interior still
603
// has a hole in it (i.e. if the line width ratio was
604
// less than 1.0)
605
if (lwr21 < 1.0f && lwr12 < 1.0f) {
606
607
// Note: "TOP", "BOTTOM", "LEFT" and "RIGHT" here are
608
// relative to whether the dxNN variables are positive
609
// and negative. The math works fine regardless of
610
// their signs, but for conceptual simplicity the
611
// comments will refer to the sides as if the dxNN
612
// were all positive. "TOP" and "BOTTOM" segments
613
// are defined by the dxy21 deltas. "LEFT" and "RIGHT"
614
// segments are defined by the dxy12 deltas.
615
616
// Each segment includes its starting corner and comes
617
// to just short of the following corner. Thus, each
618
// corner is included just once and the only lengths
619
// needed are the original parallelogram delta lengths
620
// and the "line width deltas". The sides will cover
621
// the following relative territories:
622
//
623
// T T T T T R
624
// L R
625
// L R
626
// L R
627
// L R
628
// L B B B B B
629
630
// Every segment is drawn as a filled Parallelogram quad
631
// Each quad is encoded using two triangles
632
// For 4 segments - there are 8 triangles in total
633
// Each triangle has 3 vertices
634
const int TOTAL_VERTICES = 8 * 3;
635
struct Vertex vertexList[TOTAL_VERTICES];
636
int i = 0;
637
638
// TOP segment, to left side of RIGHT edge
639
// "width" of original pgram, "height" of hor. line size
640
fx11 = ox11;
641
fy11 = oy11;
642
643
fillVertex(vertexList + (i++), fx11, fy11);
644
fillVertex(vertexList + (i++), fx11 + dx21, fy11 + dy21);
645
fillVertex(vertexList + (i++), fx11 + dx21 + ldx12, fy11 + dy21 + ldy12);
646
647
fillVertex(vertexList + (i++), fx11 + dx21 + ldx12, fy11 + dy21 + ldy12);
648
fillVertex(vertexList + (i++), fx11 + ldx12, fy11 + ldy12);
649
fillVertex(vertexList + (i++), fx11, fy11);
650
651
// RIGHT segment, to top of BOTTOM edge
652
// "width" of vert. line size , "height" of original pgram
653
fx11 = ox11 + dx21;
654
fy11 = oy11 + dy21;
655
fillVertex(vertexList + (i++), fx11, fy11);
656
fillVertex(vertexList + (i++), fx11 + ldx21, fy11 + ldy21);
657
fillVertex(vertexList + (i++), fx11 + ldx21 + dx12, fy11 + ldy21 + dy12);
658
659
fillVertex(vertexList + (i++), fx11 + ldx21 + dx12, fy11 + ldy21 + dy12);
660
fillVertex(vertexList + (i++), fx11 + dx12, fy11 + dy12);
661
fillVertex(vertexList + (i++), fx11, fy11);
662
663
// BOTTOM segment, from right side of LEFT edge
664
// "width" of original pgram, "height" of hor. line size
665
fx11 = ox11 + dx12 + ldx21;
666
fy11 = oy11 + dy12 + ldy21;
667
fillVertex(vertexList + (i++), fx11, fy11);
668
fillVertex(vertexList + (i++), fx11 + dx21, fy11 + dy21);
669
fillVertex(vertexList + (i++), fx11 + dx21 + ldx12, fy11 + dy21 + ldy12);
670
671
fillVertex(vertexList + (i++), fx11 + dx21 + ldx12, fy11 + dy21 + ldy12);
672
fillVertex(vertexList + (i++), fx11 + ldx12, fy11 + ldy12);
673
fillVertex(vertexList + (i++), fx11, fy11);
674
675
// LEFT segment, from bottom of TOP edge
676
// "width" of vert. line size , "height" of inner pgram
677
fx11 = ox11 + ldx12;
678
fy11 = oy11 + ldy12;
679
fillVertex(vertexList + (i++), fx11, fy11);
680
fillVertex(vertexList + (i++), fx11 + ldx21, fy11 + ldy21);
681
fillVertex(vertexList + (i++), fx11 + ldx21 + dx12, fy11 + ldy21 + dy12);
682
683
fillVertex(vertexList + (i++), fx11 + ldx21 + dx12, fy11 + ldy21 + dy12);
684
fillVertex(vertexList + (i++), fx11 + dx12, fy11 + dy12);
685
fillVertex(vertexList + (i++), fx11, fy11);
686
687
// Encode render command.
688
id<MTLRenderCommandEncoder> mtlEncoder = [mtlc.encoderManager getRenderEncoder:dstOps];
689
690
if (mtlEncoder == nil) {
691
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLRenderer_DrawParallelogram: error creating MTLRenderCommandEncoder.");
692
return;
693
}
694
695
[mtlEncoder setVertexBytes:vertexList length:sizeof(vertexList) atIndex:MeshVertexBuffer];
696
[mtlEncoder drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:0 vertexCount:TOTAL_VERTICES];
697
} else {
698
// The line width ratios were large enough to consume
699
// the entire hole in the middle of the parallelogram
700
// so we can just issue one large quad for the outer
701
// parallelogram.
702
dx21 += ldx21;
703
dy21 += ldy21;
704
dx12 += ldx12;
705
dy12 += ldy12;
706
MTLRenderer_FillParallelogram(mtlc, dstOps, ox11, oy11, dx21, dy21, dx12, dy12);
707
}
708
}
709
710
static struct AAVertex aaVertices[6];
711
static jint vertexCacheIndex = 0;
712
713
#define AA_ADD_VERTEX(OU, OV, IU, IV, DX, DY) \
714
do { \
715
struct AAVertex *v = &aaVertices[vertexCacheIndex++]; \
716
v->otxtpos[0] = OU; \
717
v->otxtpos[1] = OV; \
718
v->itxtpos[0] = IU; \
719
v->itxtpos[1] = IV; \
720
v->position[0]= DX; \
721
v->position[1] = DY; \
722
} while (0)
723
724
#define AA_ADD_TRIANGLES(ou11, ov11, iu11, iv11, ou21, ov21, iu21, iv21, ou22, ov22, iu22, iv22, ou12, ov12, iu12, iv12, DX1, DY1, DX2, DY2) \
725
do { \
726
AA_ADD_VERTEX(ou11, ov11, iu11, iv11, DX1, DY1); \
727
AA_ADD_VERTEX(ou21, ov21, iu21, iv21, DX2, DY1); \
728
AA_ADD_VERTEX(ou22, ov22, iu22, iv22, DX2, DY2); \
729
AA_ADD_VERTEX(ou22, ov22, iu22, iv22, DX2, DY2); \
730
AA_ADD_VERTEX(ou12, ov12, iu12, iv12, DX1, DY2); \
731
AA_ADD_VERTEX(ou11, ov11, iu11, iv11, DX1, DY1); \
732
} while (0)
733
734
#define ADJUST_PGRAM(V1, DV, V2) \
735
do { \
736
if ((DV) >= 0) { \
737
(V2) += (DV); \
738
} else { \
739
(V1) += (DV); \
740
} \
741
} while (0)
742
743
// Invert the following transform:
744
// DeltaT(0, 0) == (0, 0)
745
// DeltaT(1, 0) == (DX1, DY1)
746
// DeltaT(0, 1) == (DX2, DY2)
747
// DeltaT(1, 1) == (DX1+DX2, DY1+DY2)
748
// TM00 = DX1, TM01 = DX2, (TM02 = X11)
749
// TM10 = DY1, TM11 = DY2, (TM12 = Y11)
750
// Determinant = TM00*TM11 - TM01*TM10
751
// = DX1*DY2 - DX2*DY1
752
// Inverse is:
753
// IM00 = TM11/det, IM01 = -TM01/det
754
// IM10 = -TM10/det, IM11 = TM00/det
755
// IM02 = (TM01 * TM12 - TM11 * TM02) / det,
756
// IM12 = (TM10 * TM02 - TM00 * TM12) / det,
757
758
#define DECLARE_MATRIX(MAT) \
759
jfloat MAT ## 00, MAT ## 01, MAT ## 02, MAT ## 10, MAT ## 11, MAT ## 12
760
761
#define GET_INVERTED_MATRIX(MAT, X11, Y11, DX1, DY1, DX2, DY2, RET_CODE) \
762
do { \
763
jfloat det = DX1*DY2 - DX2*DY1; \
764
if (det == 0) { \
765
RET_CODE; \
766
} \
767
MAT ## 00 = DY2/det; \
768
MAT ## 01 = -DX2/det; \
769
MAT ## 10 = -DY1/det; \
770
MAT ## 11 = DX1/det; \
771
MAT ## 02 = (DX2 * Y11 - DY2 * X11) / det; \
772
MAT ## 12 = (DY1 * X11 - DX1 * Y11) / det; \
773
} while (0)
774
775
#define TRANSFORM(MAT, TX, TY, X, Y) \
776
do { \
777
TX = (X) * MAT ## 00 + (Y) * MAT ## 01 + MAT ## 02; \
778
TY = (X) * MAT ## 10 + (Y) * MAT ## 11 + MAT ## 12; \
779
} while (0)
780
781
void
782
MTLRenderer_FillAAParallelogram(MTLContext *mtlc, BMTLSDOps * dstOps,
783
jfloat fx11, jfloat fy11,
784
jfloat dx21, jfloat dy21,
785
jfloat dx12, jfloat dy12)
786
{
787
DECLARE_MATRIX(om);
788
// parameters for parallelogram bounding box
789
jfloat bx11, by11, bx22, by22;
790
// parameters for uv texture coordinates of parallelogram corners
791
jfloat ou11, ov11, ou12, ov12, ou21, ov21, ou22, ov22;
792
793
J2dTraceLn6(J2D_TRACE_INFO,
794
"MTLRenderer_FillAAParallelogram "
795
"(x=%6.2f y=%6.2f "
796
"dx1=%6.2f dy1=%6.2f "
797
"dx2=%6.2f dy2=%6.2f)",
798
fx11, fy11,
799
dx21, dy21,
800
dx12, dy12);
801
802
RETURN_IF_NULL(mtlc);
803
RETURN_IF_NULL(dstOps);
804
805
GET_INVERTED_MATRIX(om, fx11, fy11, dx21, dy21, dx12, dy12,
806
return);
807
808
bx11 = bx22 = fx11;
809
by11 = by22 = fy11;
810
ADJUST_PGRAM(bx11, dx21, bx22);
811
ADJUST_PGRAM(by11, dy21, by22);
812
ADJUST_PGRAM(bx11, dx12, bx22);
813
ADJUST_PGRAM(by11, dy12, by22);
814
bx11 = (jfloat) floor(bx11);
815
by11 = (jfloat) floor(by11);
816
bx22 = (jfloat) ceil(bx22);
817
by22 = (jfloat) ceil(by22);
818
819
TRANSFORM(om, ou11, ov11, bx11, by11);
820
TRANSFORM(om, ou21, ov21, bx22, by11);
821
TRANSFORM(om, ou12, ov12, bx11, by22);
822
TRANSFORM(om, ou22, ov22, bx22, by22);
823
824
id<MTLRenderCommandEncoder> encoder =
825
[mtlc.encoderManager getAAShaderRenderEncoder:dstOps];
826
827
AA_ADD_TRIANGLES(ou11, ov11, 5.f, 5.f, ou21, ov21, 6.f, 5.f, ou22, ov22, 6.f, 6.f, ou12, ov12, 5.f, 5.f, bx11, by11, bx22, by22);
828
[encoder setVertexBytes:aaVertices length:sizeof(aaVertices) atIndex:MeshVertexBuffer];
829
[encoder drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:0 vertexCount:6];
830
vertexCacheIndex = 0;
831
}
832
833
void
834
MTLRenderer_FillAAParallelogramInnerOuter(MTLContext *mtlc, MTLSDOps *dstOps,
835
jfloat ox11, jfloat oy11,
836
jfloat ox21, jfloat oy21,
837
jfloat ox12, jfloat oy12,
838
jfloat ix11, jfloat iy11,
839
jfloat ix21, jfloat iy21,
840
jfloat ix12, jfloat iy12)
841
{
842
DECLARE_MATRIX(om);
843
DECLARE_MATRIX(im);
844
// parameters for parallelogram bounding box
845
jfloat bx11, by11, bx22, by22;
846
// parameters for uv texture coordinates of outer parallelogram corners
847
jfloat ou11, ov11, ou12, ov12, ou21, ov21, ou22, ov22;
848
// parameters for uv texture coordinates of inner parallelogram corners
849
jfloat iu11, iv11, iu12, iv12, iu21, iv21, iu22, iv22;
850
851
RETURN_IF_NULL(mtlc);
852
RETURN_IF_NULL(dstOps);
853
854
GET_INVERTED_MATRIX(im, ix11, iy11, ix21, iy21, ix12, iy12,
855
// inner parallelogram is degenerate
856
// therefore it encloses no area
857
// fill outer
858
MTLRenderer_FillAAParallelogram(mtlc, dstOps,
859
ox11, oy11,
860
ox21, oy21,
861
ox12, oy12);
862
return);
863
GET_INVERTED_MATRIX(om, ox11, oy11, ox21, oy21, ox12, oy12,
864
return);
865
866
bx11 = bx22 = ox11;
867
by11 = by22 = oy11;
868
ADJUST_PGRAM(bx11, ox21, bx22);
869
ADJUST_PGRAM(by11, oy21, by22);
870
ADJUST_PGRAM(bx11, ox12, bx22);
871
ADJUST_PGRAM(by11, oy12, by22);
872
bx11 = (jfloat) floor(bx11);
873
by11 = (jfloat) floor(by11);
874
bx22 = (jfloat) ceil(bx22);
875
by22 = (jfloat) ceil(by22);
876
877
TRANSFORM(om, ou11, ov11, bx11, by11);
878
TRANSFORM(om, ou21, ov21, bx22, by11);
879
TRANSFORM(om, ou12, ov12, bx11, by22);
880
TRANSFORM(om, ou22, ov22, bx22, by22);
881
882
TRANSFORM(im, iu11, iv11, bx11, by11);
883
TRANSFORM(im, iu21, iv21, bx22, by11);
884
TRANSFORM(im, iu12, iv12, bx11, by22);
885
TRANSFORM(im, iu22, iv22, bx22, by22);
886
887
id<MTLRenderCommandEncoder> encoder =
888
[mtlc.encoderManager getAAShaderRenderEncoder:dstOps];
889
890
AA_ADD_TRIANGLES(ou11, ov11, iu11, iv11, ou21, ov21, iu21, iv21, ou22, ov22, iu22, iv22, ou12, ov12, iu12, iv12, bx11, by11, bx22, by22);
891
[encoder setVertexBytes:aaVertices length:sizeof(aaVertices) atIndex:MeshVertexBuffer];
892
[encoder drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:0 vertexCount:6];
893
vertexCacheIndex = 0;
894
}
895
896
void
897
MTLRenderer_DrawAAParallelogram(MTLContext *mtlc, BMTLSDOps * dstOps,
898
jfloat fx11, jfloat fy11,
899
jfloat dx21, jfloat dy21,
900
jfloat dx12, jfloat dy12,
901
jfloat lwr21, jfloat lwr12)
902
{
903
// dx,dy for line width in the "21" and "12" directions.
904
jfloat ldx21, ldy21, ldx12, ldy12;
905
// parameters for "outer" parallelogram
906
jfloat ofx11, ofy11, odx21, ody21, odx12, ody12;
907
// parameters for "inner" parallelogram
908
jfloat ifx11, ify11, idx21, idy21, idx12, idy12;
909
910
J2dTraceLn8(J2D_TRACE_INFO,
911
"MTLRenderer_DrawAAParallelogram "
912
"(x=%6.2f y=%6.2f "
913
"dx1=%6.2f dy1=%6.2f lwr1=%6.2f "
914
"dx2=%6.2f dy2=%6.2f lwr2=%6.2f)",
915
fx11, fy11,
916
dx21, dy21, lwr21,
917
dx12, dy12, lwr12);
918
919
RETURN_IF_NULL(mtlc);
920
RETURN_IF_NULL(dstOps);
921
922
// calculate true dx,dy for line widths from the "line width ratios"
923
ldx21 = dx21 * lwr21;
924
ldy21 = dy21 * lwr21;
925
ldx12 = dx12 * lwr12;
926
ldy12 = dy12 * lwr12;
927
928
// calculate coordinates of the outer parallelogram
929
ofx11 = fx11 - (ldx21 + ldx12) / 2.0f;
930
ofy11 = fy11 - (ldy21 + ldy12) / 2.0f;
931
odx21 = dx21 + ldx21;
932
ody21 = dy21 + ldy21;
933
odx12 = dx12 + ldx12;
934
ody12 = dy12 + ldy12;
935
936
// Only process the inner parallelogram if the line width ratio
937
// did not consume the entire interior of the parallelogram
938
// (i.e. if the width ratio was less than 1.0)
939
if (lwr21 < 1.0f && lwr12 < 1.0f) {
940
// calculate coordinates of the inner parallelogram
941
ifx11 = fx11 + (ldx21 + ldx12) / 2.0f;
942
ify11 = fy11 + (ldy21 + ldy12) / 2.0f;
943
idx21 = dx21 - ldx21;
944
idy21 = dy21 - ldy21;
945
idx12 = dx12 - ldx12;
946
idy12 = dy12 - ldy12;
947
948
MTLRenderer_FillAAParallelogramInnerOuter(mtlc, dstOps,
949
ofx11, ofy11,
950
odx21, ody21,
951
odx12, ody12,
952
ifx11, ify11,
953
idx21, idy21,
954
idx12, idy12);
955
} else {
956
MTLRenderer_FillAAParallelogram(mtlc, dstOps,
957
ofx11, ofy11,
958
odx21, ody21,
959
odx12, ody12);
960
}
961
}
962
963