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/MTLTextRenderer.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 <stdlib.h>
27
#include <limits.h>
28
#include <math.h>
29
#include <jlong.h>
30
31
#include "sun_java2d_metal_MTLTextRenderer.h"
32
33
#include "SurfaceData.h"
34
#include "MTLContext.h"
35
#include "MTLRenderQueue.h"
36
#include "MTLTextRenderer.h"
37
#include "MTLVertexCache.h"
38
#include "MTLGlyphCache.h"
39
#include "MTLBlitLoops.h"
40
41
/**
42
* The following constants define the inner and outer bounds of the
43
* accelerated glyph cache.
44
*/
45
#define MTLTR_CACHE_WIDTH 512
46
#define MTLTR_CACHE_HEIGHT 512
47
#define MTLTR_CACHE_CELL_WIDTH 32
48
#define MTLTR_CACHE_CELL_HEIGHT 32
49
50
/**
51
* The current "glyph mode" state. This variable is used to track the
52
* codepath used to render a particular glyph. This variable is reset to
53
* MODE_NOT_INITED at the beginning of every call to MTLTR_DrawGlyphList().
54
* As each glyph is rendered, the glyphMode variable is updated to reflect
55
* the current mode, so if the current mode is the same as the mode used
56
* to render the previous glyph, we can avoid doing costly setup operations
57
* each time.
58
*/
59
typedef enum {
60
MODE_NOT_INITED,
61
MODE_USE_CACHE_GRAY,
62
MODE_USE_CACHE_LCD,
63
MODE_NO_CACHE_GRAY,
64
MODE_NO_CACHE_LCD,
65
MODE_NO_CACHE_COLOR
66
} GlyphMode;
67
static GlyphMode glyphMode = MODE_NOT_INITED;
68
69
/**
70
* There are two separate glyph caches: for AA and for LCD.
71
* Once one of them is initialized as either GRAY or LCD, it
72
* stays in that mode for the duration of the application. It should
73
* be safe to use this one glyph cache for all screens in a multimon
74
* environment, since the glyph cache texture is shared between all contexts,
75
* and (in theory) Metal drivers should be smart enough to manage that
76
* texture across all screens.
77
*/
78
79
static MTLGlyphCacheInfo *glyphCacheLCD = NULL;
80
static MTLGlyphCacheInfo *glyphCacheAA = NULL;
81
82
/**
83
* This value tracks the previous LCD rgbOrder setting, so if the rgbOrder
84
* value has changed since the last time, it indicates that we need to
85
* invalidate the cache, which may already store glyph images in the reverse
86
* order. Note that in most real world applications this value will not
87
* change over the course of the application, but tests like Font2DTest
88
* allow for changing the ordering at runtime, so we need to handle that case.
89
*/
90
static jboolean lastRGBOrder = JNI_TRUE;
91
92
/**
93
* This constant defines the size of the tile to use in the
94
* MTLTR_DrawLCDGlyphNoCache() method. See below for more on why we
95
* restrict this value to a particular size.
96
*/
97
#define MTLTR_NOCACHE_TILE_SIZE 32
98
99
static struct TxtVertex txtVertices[6];
100
static jint vertexCacheIndex = 0;
101
static id<MTLRenderCommandEncoder> lcdCacheEncoder = nil;
102
103
#define LCD_ADD_VERTEX(TX, TY, DX, DY, DZ) \
104
do { \
105
struct TxtVertex *v = &txtVertices[vertexCacheIndex++]; \
106
v->txtpos[0] = TX; \
107
v->txtpos[1] = TY; \
108
v->position[0]= DX; \
109
v->position[1] = DY; \
110
} while (0)
111
112
#define LCD_ADD_TRIANGLES(TX1, TY1, TX2, TY2, DX1, DY1, DX2, DY2) \
113
do { \
114
LCD_ADD_VERTEX(TX1, TY1, DX1, DY1, 0); \
115
LCD_ADD_VERTEX(TX2, TY1, DX2, DY1, 0); \
116
LCD_ADD_VERTEX(TX2, TY2, DX2, DY2, 0); \
117
LCD_ADD_VERTEX(TX2, TY2, DX2, DY2, 0); \
118
LCD_ADD_VERTEX(TX1, TY2, DX1, DY2, 0); \
119
LCD_ADD_VERTEX(TX1, TY1, DX1, DY1, 0); \
120
} while (0)
121
122
/**
123
* Initializes the one glyph cache (texture and data structure).
124
* If lcdCache is JNI_TRUE, the texture will contain RGB data,
125
* otherwise we will simply store the grayscale/monochrome glyph images
126
* as intensity values.
127
*/
128
static jboolean
129
MTLTR_InitGlyphCache(MTLContext *mtlc, jboolean lcdCache)
130
{
131
J2dTraceLn(J2D_TRACE_INFO, "MTLTR_InitGlyphCache");
132
// TODO : Need to verify RGB order in case of LCD
133
MTLPixelFormat pixelFormat =
134
lcdCache ? MTLPixelFormatBGRA8Unorm : MTLPixelFormatA8Unorm;
135
136
MTLGlyphCacheInfo *gcinfo;
137
// init glyph cache data structure
138
gcinfo = MTLGlyphCache_Init(MTLTR_CACHE_WIDTH,
139
MTLTR_CACHE_HEIGHT,
140
MTLTR_CACHE_CELL_WIDTH,
141
MTLTR_CACHE_CELL_HEIGHT,
142
MTLVertexCache_FlushGlyphVertexCache);
143
144
if (gcinfo == NULL) {
145
J2dRlsTraceLn(J2D_TRACE_ERROR,
146
"MTLTR_InitGlyphCache: could not init MTL glyph cache");
147
return JNI_FALSE;
148
}
149
150
MTLTextureDescriptor *textureDescriptor =
151
[MTLTextureDescriptor texture2DDescriptorWithPixelFormat:pixelFormat
152
width:MTLTR_CACHE_WIDTH
153
height:MTLTR_CACHE_HEIGHT
154
mipmapped:NO];
155
156
gcinfo->texture = [mtlc.device newTextureWithDescriptor:textureDescriptor];
157
158
if (lcdCache) {
159
glyphCacheLCD = gcinfo;
160
} else {
161
glyphCacheAA = gcinfo;
162
}
163
164
return JNI_TRUE;
165
}
166
167
id<MTLTexture>
168
MTLTR_GetGlyphCacheTexture()
169
{
170
J2dTraceLn(J2D_TRACE_INFO, "MTLTR_GetGlyphCacheTexture");
171
if (glyphCacheAA != NULL) {
172
return glyphCacheAA->texture;
173
}
174
return NULL;
175
}
176
177
/**
178
* Adds the given glyph to the glyph cache (texture and data structure)
179
* associated with the given MTLContext.
180
*/
181
static void
182
MTLTR_AddToGlyphCache(GlyphInfo *glyph, MTLContext *mtlc,
183
jboolean lcdCache)
184
{
185
MTLCacheCellInfo *ccinfo;
186
MTLGlyphCacheInfo *gcinfo;
187
jint w = glyph->width;
188
jint h = glyph->height;
189
190
J2dTraceLn(J2D_TRACE_INFO, "MTLTR_AddToGlyphCache");
191
if (!lcdCache) {
192
gcinfo = glyphCacheAA;
193
} else {
194
gcinfo = glyphCacheLCD;
195
}
196
197
if ((gcinfo == NULL) || (glyph->image == NULL)) {
198
return;
199
}
200
201
bool isCacheFull = MTLGlyphCache_IsCacheFull(gcinfo, glyph);
202
if (isCacheFull) {
203
MTLGlyphCache_Free(gcinfo);
204
if (!lcdCache) {
205
MTLTR_InitGlyphCache(mtlc, JNI_FALSE);
206
gcinfo = glyphCacheAA;
207
} else {
208
MTLTR_InitGlyphCache(mtlc, JNI_TRUE);
209
gcinfo = glyphCacheLCD;
210
}
211
}
212
MTLGlyphCache_AddGlyph(gcinfo, glyph);
213
ccinfo = (MTLCacheCellInfo *) glyph->cellInfo;
214
215
if (ccinfo != NULL) {
216
// store glyph image in texture cell
217
MTLRegion region = {
218
{ccinfo->x, ccinfo->y, 0},
219
{w, h, 1}
220
};
221
if (!lcdCache) {
222
NSUInteger bytesPerRow = 1 * w;
223
[gcinfo->texture replaceRegion:region
224
mipmapLevel:0
225
withBytes:glyph->image
226
bytesPerRow:bytesPerRow];
227
} else {
228
unsigned int imageBytes = w * h * 4;
229
unsigned char imageData[imageBytes];
230
memset(&imageData, 0, sizeof(imageData));
231
232
int srcIndex = 0;
233
int dstIndex = 0;
234
for (int i = 0; i < (w * h); i++) {
235
imageData[dstIndex++] = glyph->image[srcIndex++];
236
imageData[dstIndex++] = glyph->image[srcIndex++];
237
imageData[dstIndex++] = glyph->image[srcIndex++];
238
imageData[dstIndex++] = 0xFF;
239
}
240
241
NSUInteger bytesPerRow = 4 * w;
242
[gcinfo->texture replaceRegion:region
243
mipmapLevel:0
244
withBytes:imageData
245
bytesPerRow:bytesPerRow];
246
}
247
}
248
}
249
250
static jboolean
251
MTLTR_SetLCDContrast(MTLContext *mtlc,
252
jint contrast,
253
id<MTLRenderCommandEncoder> encoder)
254
{
255
if (![mtlc.paint isKindOfClass:[MTLColorPaint class]]) {
256
return JNI_FALSE;
257
}
258
MTLColorPaint* cPaint = (MTLColorPaint *) mtlc.paint;
259
// update the current color settings
260
double gamma = ((double)contrast) / 100.0;
261
double invgamma = 1.0/gamma;
262
jfloat radj, gadj, badj;
263
jfloat clr[4];
264
jint col = cPaint.color;
265
266
J2dTraceLn2(J2D_TRACE_INFO, "primary color %x, contrast %d", col, contrast);
267
J2dTraceLn2(J2D_TRACE_INFO, "gamma %f, invgamma %f", gamma, invgamma);
268
269
clr[0] = ((col >> 16) & 0xFF)/255.0f;
270
clr[1] = ((col >> 8) & 0xFF)/255.0f;
271
clr[2] = ((col) & 0xFF)/255.0f;
272
273
// gamma adjust the primary color
274
radj = (float)pow(clr[0], gamma);
275
gadj = (float)pow(clr[1], gamma);
276
badj = (float)pow(clr[2], gamma);
277
278
struct LCDFrameUniforms uf = {
279
{radj, gadj, badj},
280
{gamma, gamma, gamma},
281
{invgamma, invgamma, invgamma}};
282
[encoder setFragmentBytes:&uf length:sizeof(uf) atIndex:FrameUniformBuffer];
283
return JNI_TRUE;
284
}
285
286
void
287
MTLTR_EnableGlyphVertexCache(MTLContext *mtlc, BMTLSDOps *dstOps)
288
{
289
J2dTraceLn(J2D_TRACE_INFO, "MTLTR_EnableGlyphVertexCache");
290
291
if (!MTLVertexCache_InitVertexCache()) {
292
return;
293
}
294
295
if (glyphCacheAA == NULL) {
296
if (!MTLTR_InitGlyphCache(mtlc, JNI_FALSE)) {
297
return;
298
}
299
}
300
MTLVertexCache_CreateSamplingEncoder(mtlc, dstOps);
301
}
302
303
void
304
MTLTR_DisableGlyphVertexCache(MTLContext *mtlc)
305
{
306
J2dTraceLn(J2D_TRACE_INFO, "MTLTR_DisableGlyphVertexCache");
307
MTLVertexCache_FlushGlyphVertexCache();
308
MTLVertexCache_FreeVertexCache();
309
}
310
311
void MTLTR_FreeGlyphCaches() {
312
J2dTraceLn(J2D_TRACE_INFO, "MTLTR_FreeGlyphCaches : freeing glyph caches.");
313
314
if (glyphCacheAA != NULL) {
315
[glyphCacheAA->texture release];
316
MTLGlyphCache_Free(glyphCacheAA);
317
glyphCacheAA = NULL;
318
}
319
320
if (glyphCacheLCD != NULL) {
321
[glyphCacheLCD->texture release];
322
MTLGlyphCache_Free(glyphCacheLCD);
323
glyphCacheLCD = NULL;
324
}
325
}
326
327
static MTLPaint* storedPaint = nil;
328
329
static void EnableColorGlyphPainting(MTLContext *mtlc) {
330
storedPaint = mtlc.paint;
331
mtlc.paint = [[MTLPaint alloc] init];
332
}
333
334
static void DisableColorGlyphPainting(MTLContext *mtlc) {
335
[mtlc.paint release];
336
mtlc.paint = storedPaint;
337
storedPaint = nil;
338
}
339
340
static jboolean
341
MTLTR_DrawGrayscaleGlyphViaCache(MTLContext *mtlc,
342
GlyphInfo *ginfo, jint x, jint y, BMTLSDOps *dstOps)
343
{
344
MTLCacheCellInfo *cell;
345
jfloat x1, y1, x2, y2;
346
347
if (glyphMode != MODE_USE_CACHE_GRAY) {
348
if (glyphMode == MODE_NO_CACHE_GRAY) {
349
MTLVertexCache_DisableMaskCache(mtlc);
350
} else if (glyphMode == MODE_USE_CACHE_LCD) {
351
[mtlc.encoderManager endEncoder];
352
lcdCacheEncoder = nil;
353
} else if (glyphMode == MODE_NO_CACHE_COLOR) {
354
DisableColorGlyphPainting(mtlc);
355
}
356
MTLTR_EnableGlyphVertexCache(mtlc, dstOps);
357
glyphMode = MODE_USE_CACHE_GRAY;
358
}
359
360
if (ginfo->cellInfo == NULL) {
361
// attempt to add glyph to accelerated glyph cache
362
MTLTR_AddToGlyphCache(ginfo, mtlc, JNI_FALSE);
363
364
if (ginfo->cellInfo == NULL) {
365
// we'll just no-op in the rare case that the cell is NULL
366
return JNI_TRUE;
367
}
368
}
369
370
cell = (MTLCacheCellInfo *) (ginfo->cellInfo);
371
cell->timesRendered++;
372
373
x1 = (jfloat)x;
374
y1 = (jfloat)y;
375
x2 = x1 + ginfo->width;
376
y2 = y1 + ginfo->height;
377
378
MTLVertexCache_AddGlyphQuad(mtlc,
379
cell->tx1, cell->ty1,
380
cell->tx2, cell->ty2,
381
x1, y1, x2, y2);
382
383
return JNI_TRUE;
384
}
385
386
static jboolean
387
MTLTR_DrawLCDGlyphViaCache(MTLContext *mtlc, BMTLSDOps *dstOps,
388
GlyphInfo *ginfo, jint x, jint y,
389
jboolean rgbOrder, jint contrast)
390
{
391
CacheCellInfo *cell;
392
jfloat tx1, ty1, tx2, ty2;
393
jint w = ginfo->width;
394
jint h = ginfo->height;
395
396
if (glyphMode != MODE_USE_CACHE_LCD) {
397
if (glyphMode == MODE_NO_CACHE_GRAY) {
398
MTLVertexCache_DisableMaskCache(mtlc);
399
} else if (glyphMode == MODE_USE_CACHE_GRAY) {
400
MTLTR_DisableGlyphVertexCache(mtlc);
401
} else if (glyphMode == MODE_NO_CACHE_COLOR) {
402
DisableColorGlyphPainting(mtlc);
403
}
404
405
if (glyphCacheLCD == NULL) {
406
if (!MTLTR_InitGlyphCache(mtlc, JNI_TRUE)) {
407
return JNI_FALSE;
408
}
409
}
410
if (lcdCacheEncoder == nil) {
411
lcdCacheEncoder = [mtlc.encoderManager getLCDEncoder:dstOps->pTexture isSrcOpaque:YES isDstOpaque:YES];
412
}
413
if (rgbOrder != lastRGBOrder) {
414
// need to invalidate the cache in this case; see comments
415
// for lastRGBOrder above
416
MTLGlyphCache_Invalidate(glyphCacheLCD);
417
lastRGBOrder = rgbOrder;
418
}
419
420
glyphMode = MODE_USE_CACHE_LCD;
421
}
422
423
if (ginfo->cellInfo == NULL) {
424
// attempt to add glyph to accelerated glyph cache
425
// TODO : Handle RGB order
426
MTLTR_AddToGlyphCache(ginfo, mtlc, JNI_TRUE);
427
428
if (ginfo->cellInfo == NULL) {
429
// we'll just no-op in the rare case that the cell is NULL
430
return JNI_TRUE;
431
}
432
}
433
cell = (CacheCellInfo *) (ginfo->cellInfo);
434
cell->timesRendered++;
435
436
MTLTR_SetLCDContrast(mtlc, contrast, lcdCacheEncoder);
437
tx1 = cell->tx1;
438
ty1 = cell->ty1;
439
tx2 = cell->tx2;
440
ty2 = cell->ty2;
441
442
J2dTraceLn4(J2D_TRACE_INFO, "tx1 = %f, ty1 = %f, tx2 = %f, ty2 = %f", tx1, ty1, tx2, ty2);
443
J2dTraceLn2(J2D_TRACE_INFO, "width = %d height = %d", dstOps->width, dstOps->height);
444
445
LCD_ADD_TRIANGLES(tx1, ty1, tx2, ty2, x, y, x+w, y+h);
446
447
[lcdCacheEncoder setVertexBytes:txtVertices length:sizeof(txtVertices) atIndex:MeshVertexBuffer];
448
[lcdCacheEncoder setFragmentTexture:glyphCacheLCD->texture atIndex:0];
449
[lcdCacheEncoder setFragmentTexture:dstOps->pTexture atIndex:1];
450
451
[lcdCacheEncoder drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:0 vertexCount:6];
452
453
vertexCacheIndex = 0;
454
455
return JNI_TRUE;
456
}
457
458
static jboolean
459
MTLTR_DrawGrayscaleGlyphNoCache(MTLContext *mtlc,
460
GlyphInfo *ginfo, jint x, jint y, BMTLSDOps *dstOps)
461
{
462
jint tw, th;
463
jint sx, sy, sw, sh;
464
jint x0;
465
jint w = ginfo->width;
466
jint h = ginfo->height;
467
468
J2dTraceLn(J2D_TRACE_INFO, "MTLTR_DrawGrayscaleGlyphNoCache");
469
if (glyphMode != MODE_NO_CACHE_GRAY) {
470
if (glyphMode == MODE_USE_CACHE_GRAY) {
471
MTLTR_DisableGlyphVertexCache(mtlc);
472
} else if (glyphMode == MODE_USE_CACHE_LCD) {
473
[mtlc.encoderManager endEncoder];
474
lcdCacheEncoder = nil;
475
} else if (glyphMode == MODE_NO_CACHE_COLOR) {
476
DisableColorGlyphPainting(mtlc);
477
}
478
MTLVertexCache_EnableMaskCache(mtlc, dstOps);
479
glyphMode = MODE_NO_CACHE_GRAY;
480
}
481
482
x0 = x;
483
tw = MTLVC_MASK_CACHE_TILE_WIDTH;
484
th = MTLVC_MASK_CACHE_TILE_HEIGHT;
485
486
for (sy = 0; sy < h; sy += th, y += th) {
487
x = x0;
488
sh = ((sy + th) > h) ? (h - sy) : th;
489
490
for (sx = 0; sx < w; sx += tw, x += tw) {
491
sw = ((sx + tw) > w) ? (w - sx) : tw;
492
493
J2dTraceLn7(J2D_TRACE_INFO, "sx = %d sy = %d x = %d y = %d sw = %d sh = %d w = %d", sx, sy, x, y, sw, sh, w);
494
MTLVertexCache_AddMaskQuad(mtlc,
495
sx, sy, x, y, sw, sh,
496
w, ginfo->image,
497
dstOps);
498
}
499
}
500
501
return JNI_TRUE;
502
}
503
504
505
static jboolean
506
MTLTR_DrawLCDGlyphNoCache(MTLContext *mtlc, BMTLSDOps *dstOps,
507
GlyphInfo *ginfo, jint x, jint y,
508
jint rowBytesOffset,
509
jboolean rgbOrder, jint contrast)
510
{
511
jfloat tx1, ty1, tx2, ty2;
512
jint tw, th;
513
jint w = ginfo->width;
514
jint h = ginfo->height;
515
id<MTLTexture> blitTexture = nil;
516
517
J2dTraceLn2(J2D_TRACE_INFO, "MTLTR_DrawLCDGlyphNoCache x %d, y%d", x, y);
518
J2dTraceLn3(J2D_TRACE_INFO, "MTLTR_DrawLCDGlyphNoCache rowBytesOffset=%d, rgbOrder=%d, contrast=%d", rowBytesOffset, rgbOrder, contrast);
519
520
521
id<MTLRenderCommandEncoder> encoder = nil;
522
523
MTLTextureDescriptor *textureDescriptor =
524
[MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatBGRA8Unorm
525
width:w
526
height:h
527
mipmapped:NO];
528
529
blitTexture = [mtlc.device newTextureWithDescriptor:textureDescriptor];
530
531
if (glyphMode != MODE_NO_CACHE_LCD) {
532
if (glyphMode == MODE_NO_CACHE_GRAY) {
533
MTLVertexCache_DisableMaskCache(mtlc);
534
} else if (glyphMode == MODE_USE_CACHE_GRAY) {
535
MTLTR_DisableGlyphVertexCache(mtlc);
536
} else if (glyphMode == MODE_USE_CACHE_LCD) {
537
[mtlc.encoderManager endEncoder];
538
lcdCacheEncoder = nil;
539
} else if (glyphMode == MODE_NO_CACHE_COLOR) {
540
DisableColorGlyphPainting(mtlc);
541
}
542
543
if (blitTexture == nil) {
544
J2dTraceLn(J2D_TRACE_ERROR, "can't obtain temporary texture object from pool");
545
return JNI_FALSE;
546
}
547
548
549
glyphMode = MODE_NO_CACHE_LCD;
550
}
551
encoder = [mtlc.encoderManager getLCDEncoder:dstOps->pTexture isSrcOpaque:YES isDstOpaque:YES];
552
MTLTR_SetLCDContrast(mtlc, contrast, encoder);
553
554
unsigned int imageBytes = w * h * 4;
555
unsigned char imageData[imageBytes];
556
memset(&imageData, 0, sizeof(imageData));
557
558
int srcIndex = 0;
559
int dstIndex = 0;
560
for (int i = 0; i < (w * h); i++) {
561
imageData[dstIndex++] = ginfo->image[srcIndex++ + rowBytesOffset];
562
imageData[dstIndex++] = ginfo->image[srcIndex++ + rowBytesOffset];
563
imageData[dstIndex++] = ginfo->image[srcIndex++ + rowBytesOffset];
564
imageData[dstIndex++] = 0xFF;
565
}
566
567
// copy LCD mask into glyph texture tile
568
MTLRegion region = MTLRegionMake2D(0, 0, w, h);
569
570
NSUInteger bytesPerRow = 4 * ginfo->width;
571
[blitTexture replaceRegion:region
572
mipmapLevel:0
573
withBytes:imageData
574
bytesPerRow:bytesPerRow];
575
576
tx1 = 0.0f;
577
ty1 = 0.0f;
578
tx2 = 1.0f;
579
ty2 = 1.0f;
580
581
J2dTraceLn2(J2D_TRACE_INFO, "MTLTR_DrawLCDGlyphNoCache : dstOps->width = %d, dstOps->height = %d", dstOps->width, dstOps->height);
582
583
LCD_ADD_TRIANGLES(tx1, ty1, tx2, ty2, x, y, x+w, y+h);
584
585
[encoder setVertexBytes:txtVertices length:sizeof(txtVertices) atIndex:MeshVertexBuffer];
586
[encoder setFragmentTexture:blitTexture atIndex:0];
587
[encoder setFragmentTexture:dstOps->pTexture atIndex:1];
588
589
[encoder drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:0 vertexCount:6];
590
591
vertexCacheIndex = 0;
592
[mtlc.encoderManager endEncoder];
593
[blitTexture release];
594
595
MTLCommandBufferWrapper* cbwrapper = [mtlc pullCommandBufferWrapper];
596
597
id<MTLCommandBuffer> commandbuf = [cbwrapper getCommandBuffer];
598
[commandbuf addCompletedHandler:^(id <MTLCommandBuffer> commandbuf) {
599
[cbwrapper release];
600
}];
601
602
[commandbuf commit];
603
[commandbuf waitUntilCompleted];
604
605
return JNI_TRUE;
606
}
607
608
static jboolean
609
MTLTR_DrawColorGlyphNoCache(MTLContext *mtlc,
610
GlyphInfo *ginfo, jint x, jint y, BMTLSDOps *dstOps)
611
{
612
id<MTLTexture> dest = dstOps->pTexture;
613
const void *src = ginfo->image;
614
jint w = ginfo->width;
615
jint h = ginfo->height;
616
jint rowBytes = ginfo->rowBytes;
617
unsigned int imageSize = rowBytes * h;
618
619
J2dTraceLn(J2D_TRACE_INFO, "MTLTR_DrawColorGlyphNoCache");
620
621
if (glyphMode != MODE_NO_CACHE_COLOR) {
622
if (glyphMode == MODE_NO_CACHE_GRAY) {
623
MTLVertexCache_DisableMaskCache(mtlc);
624
} else if (glyphMode == MODE_USE_CACHE_GRAY) {
625
MTLTR_DisableGlyphVertexCache(mtlc);
626
} else if (glyphMode == MODE_USE_CACHE_LCD) {
627
[mtlc.encoderManager endEncoder];
628
lcdCacheEncoder = nil;
629
}
630
glyphMode = MODE_NO_CACHE_COLOR;
631
EnableColorGlyphPainting(mtlc);
632
}
633
634
MTLPooledTextureHandle* texHandle = [mtlc.texturePool getTexture:w height:h format:MTLPixelFormatBGRA8Unorm];
635
if (texHandle == nil) {
636
J2dTraceLn(J2D_TRACE_ERROR, "MTLTR_DrawColorGlyphNoCache: can't obtain temporary texture object from pool");
637
return JNI_FALSE;
638
}
639
640
[[mtlc getCommandBufferWrapper] registerPooledTexture:texHandle];
641
642
[texHandle.texture replaceRegion:MTLRegionMake2D(0, 0, w, h)
643
mipmapLevel:0
644
withBytes:src
645
bytesPerRow:rowBytes];
646
647
drawTex2Tex(mtlc, texHandle.texture, dest, JNI_FALSE, dstOps->isOpaque, INTERPOLATION_NEAREST_NEIGHBOR,
648
0, 0, w, h, x, y, x + w, y + h);
649
650
return JNI_TRUE;
651
}
652
653
// see DrawGlyphList.c for more on this macro...
654
#define FLOOR_ASSIGN(l, r) \
655
if ((r)<0) (l) = ((int)floor(r)); else (l) = ((int)(r))
656
657
void
658
MTLTR_DrawGlyphList(JNIEnv *env, MTLContext *mtlc, BMTLSDOps *dstOps,
659
jint totalGlyphs, jboolean usePositions,
660
jboolean subPixPos, jboolean rgbOrder, jint lcdContrast,
661
jfloat glyphListOrigX, jfloat glyphListOrigY,
662
unsigned char *images, unsigned char *positions)
663
{
664
int glyphCounter;
665
666
J2dTraceLn(J2D_TRACE_INFO, "MTLTR_DrawGlyphList");
667
668
RETURN_IF_NULL(mtlc);
669
RETURN_IF_NULL(dstOps);
670
RETURN_IF_NULL(images);
671
if (usePositions) {
672
RETURN_IF_NULL(positions);
673
}
674
675
glyphMode = MODE_NOT_INITED;
676
J2dTraceLn1(J2D_TRACE_INFO, "totalGlyphs = %d", totalGlyphs);
677
jboolean flushBeforeLCD = JNI_FALSE;
678
679
for (glyphCounter = 0; glyphCounter < totalGlyphs; glyphCounter++) {
680
J2dTraceLn(J2D_TRACE_INFO, "Entered for loop for glyph list");
681
jint x, y;
682
jfloat glyphx, glyphy;
683
jboolean ok;
684
GlyphInfo *ginfo = (GlyphInfo *)jlong_to_ptr(NEXT_LONG(images));
685
686
if (ginfo == NULL) {
687
// this shouldn't happen, but if it does we'll just break out...
688
J2dRlsTraceLn(J2D_TRACE_ERROR,
689
"MTLTR_DrawGlyphList: glyph info is null");
690
break;
691
}
692
693
if (usePositions) {
694
jfloat posx = NEXT_FLOAT(positions);
695
jfloat posy = NEXT_FLOAT(positions);
696
glyphx = glyphListOrigX + posx + ginfo->topLeftX;
697
glyphy = glyphListOrigY + posy + ginfo->topLeftY;
698
FLOOR_ASSIGN(x, glyphx);
699
FLOOR_ASSIGN(y, glyphy);
700
} else {
701
glyphx = glyphListOrigX + ginfo->topLeftX;
702
glyphy = glyphListOrigY + ginfo->topLeftY;
703
FLOOR_ASSIGN(x, glyphx);
704
FLOOR_ASSIGN(y, glyphy);
705
glyphListOrigX += ginfo->advanceX;
706
glyphListOrigY += ginfo->advanceY;
707
}
708
709
if (ginfo->image == NULL) {
710
J2dTraceLn(J2D_TRACE_INFO, "Glyph image is null");
711
continue;
712
}
713
714
J2dTraceLn2(J2D_TRACE_INFO, "Glyph width = %d height = %d", ginfo->width, ginfo->height);
715
J2dTraceLn1(J2D_TRACE_INFO, "rowBytes = %d", ginfo->rowBytes);
716
if (ginfo->rowBytes == ginfo->width) {
717
// grayscale or monochrome glyph data
718
if (ginfo->width <= MTLTR_CACHE_CELL_WIDTH &&
719
ginfo->height <= MTLTR_CACHE_CELL_HEIGHT)
720
{
721
J2dTraceLn(J2D_TRACE_INFO, "MTLTR_DrawGlyphList Grayscale cache");
722
ok = MTLTR_DrawGrayscaleGlyphViaCache(mtlc, ginfo, x, y, dstOps);
723
} else {
724
J2dTraceLn(J2D_TRACE_INFO, "MTLTR_DrawGlyphList Grayscale no cache");
725
ok = MTLTR_DrawGrayscaleGlyphNoCache(mtlc, ginfo, x, y, dstOps);
726
}
727
} else if (ginfo->rowBytes == ginfo->width * 4) {
728
J2dTraceLn(J2D_TRACE_INFO, "MTLTR_DrawGlyphList color glyph no cache");
729
ok = MTLTR_DrawColorGlyphNoCache(mtlc, ginfo, x, y, dstOps);
730
flushBeforeLCD = JNI_FALSE;
731
} else {
732
if (!flushBeforeLCD) {
733
[mtlc.encoderManager endEncoder];
734
MTLCommandBufferWrapper* cbwrapper = [mtlc pullCommandBufferWrapper];
735
736
id<MTLCommandBuffer> commandbuf = [cbwrapper getCommandBuffer];
737
[commandbuf addCompletedHandler:^(id <MTLCommandBuffer> commandbuf) {
738
[cbwrapper release];
739
}];
740
741
[commandbuf commit];
742
flushBeforeLCD = JNI_TRUE;
743
}
744
745
// LCD-optimized glyph data
746
jint rowBytesOffset = 0;
747
748
if (subPixPos) {
749
jint frac = (jint)((glyphx - x) * 3);
750
if (frac != 0) {
751
rowBytesOffset = 3 - frac;
752
x += 1;
753
}
754
}
755
756
if (rowBytesOffset == 0 &&
757
ginfo->width <= MTLTR_CACHE_CELL_WIDTH &&
758
ginfo->height <= MTLTR_CACHE_CELL_HEIGHT)
759
{
760
J2dTraceLn(J2D_TRACE_INFO, "MTLTR_DrawGlyphList LCD cache");
761
ok = MTLTR_DrawLCDGlyphViaCache(mtlc, dstOps,
762
ginfo, x, y,
763
rgbOrder, lcdContrast);
764
} else {
765
J2dTraceLn(J2D_TRACE_INFO, "MTLTR_DrawGlyphList LCD no cache");
766
ok = MTLTR_DrawLCDGlyphNoCache(mtlc, dstOps,
767
ginfo, x, y,
768
rowBytesOffset,
769
rgbOrder, lcdContrast);
770
}
771
}
772
773
if (!ok) {
774
break;
775
}
776
}
777
/*
778
* Only in case of grayscale text drawing we need to flush
779
* cache. Still in case of LCD we are not using any intermediate
780
* cache.
781
*/
782
if (glyphMode == MODE_NO_CACHE_GRAY) {
783
MTLVertexCache_DisableMaskCache(mtlc);
784
} else if (glyphMode == MODE_USE_CACHE_GRAY) {
785
MTLTR_DisableGlyphVertexCache(mtlc);
786
} else if (glyphMode == MODE_USE_CACHE_LCD) {
787
[mtlc.encoderManager endEncoder];
788
lcdCacheEncoder = nil;
789
} else if (glyphMode == MODE_NO_CACHE_COLOR) {
790
DisableColorGlyphPainting(mtlc);
791
}
792
}
793
794
JNIEXPORT void JNICALL
795
Java_sun_java2d_metal_MTLTextRenderer_drawGlyphList
796
(JNIEnv *env, jobject self,
797
jint numGlyphs, jboolean usePositions,
798
jboolean subPixPos, jboolean rgbOrder, jint lcdContrast,
799
jfloat glyphListOrigX, jfloat glyphListOrigY,
800
jlongArray imgArray, jfloatArray posArray)
801
{
802
unsigned char *images;
803
804
J2dTraceLn(J2D_TRACE_INFO, "MTLTextRenderer_drawGlyphList");
805
806
images = (unsigned char *)
807
(*env)->GetPrimitiveArrayCritical(env, imgArray, NULL);
808
if (images != NULL) {
809
MTLContext *mtlc = MTLRenderQueue_GetCurrentContext();
810
BMTLSDOps *dstOps = MTLRenderQueue_GetCurrentDestination();
811
812
if (usePositions) {
813
unsigned char *positions = (unsigned char *)
814
(*env)->GetPrimitiveArrayCritical(env, posArray, NULL);
815
if (positions != NULL) {
816
MTLTR_DrawGlyphList(env, mtlc, dstOps,
817
numGlyphs, usePositions,
818
subPixPos, rgbOrder, lcdContrast,
819
glyphListOrigX, glyphListOrigY,
820
images, positions);
821
(*env)->ReleasePrimitiveArrayCritical(env, posArray,
822
positions, JNI_ABORT);
823
}
824
} else {
825
MTLTR_DrawGlyphList(env, mtlc, dstOps,
826
numGlyphs, usePositions,
827
subPixPos, rgbOrder, lcdContrast,
828
glyphListOrigX, glyphListOrigY,
829
images, NULL);
830
}
831
if (mtlc != NULL) {
832
RESET_PREVIOUS_OP();
833
[mtlc.encoderManager endEncoder];
834
MTLCommandBufferWrapper * cbwrapper = [mtlc pullCommandBufferWrapper];
835
id<MTLCommandBuffer> commandbuf = [cbwrapper getCommandBuffer];
836
[commandbuf addCompletedHandler:^(id <MTLCommandBuffer> commandbuf) {
837
[cbwrapper release];
838
}];
839
[commandbuf commit];
840
}
841
842
(*env)->ReleasePrimitiveArrayCritical(env, imgArray,
843
images, JNI_ABORT);
844
}
845
}
846
847