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/MTLGlyphCache.m
41159 views
1
/*
2
* Copyright (c) 2020, 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 "jni.h"
28
#include "MTLGlyphCache.h"
29
#include "Trace.h"
30
31
/**
32
* When the cache is full, we will try to reuse the cache cells that have
33
* been used relatively less than the others (and we will save the cells that
34
* have been rendered more than the threshold defined here).
35
*/
36
#define TIMES_RENDERED_THRESHOLD 5
37
38
/**
39
* Creates a new GlyphCacheInfo structure, fills in the initial values, and
40
* then returns a pointer to the GlyphCacheInfo record.
41
*
42
* Note that this method only sets up a data structure describing a
43
* rectangular region of accelerated memory, containing "virtual" cells of
44
* the requested size. The cell information is added lazily to the linked
45
* list describing the cache as new glyphs are added. Platform specific
46
* glyph caching code is responsible for actually creating the accelerated
47
* memory surface that will contain the individual glyph images.
48
*
49
* Each glyph contains a reference to a list of cell infos - one per glyph
50
* cache. There may be multiple glyph caches (for example, one per graphics
51
* adapter), so if the glyph is cached on two devices its cell list will
52
* consists of two elements corresponding to different glyph caches.
53
*
54
* The platform-specific glyph caching code is supposed to use
55
* GetCellInfoForCache method for retrieving cache infos from the glyph's list.
56
*
57
* Note that if it is guaranteed that there will be only one global glyph
58
* cache then it one does not have to use AccelGlyphCache_GetCellInfoForCache
59
* for retrieving cell info for the glyph, but instead just use the struct's
60
* field directly.
61
*/
62
MTLGlyphCacheInfo *
63
MTLGlyphCache_Init(jint width, jint height,
64
jint cellWidth, jint cellHeight,
65
MTLFlushFunc *func)
66
{
67
MTLGlyphCacheInfo *gcinfo;
68
69
J2dTraceLn(J2D_TRACE_INFO, "MTLGlyphCache_Init");
70
71
gcinfo = (MTLGlyphCacheInfo *)malloc(sizeof(MTLGlyphCacheInfo));
72
if (gcinfo == NULL) {
73
J2dRlsTraceLn(J2D_TRACE_ERROR,
74
"MTLGlyphCache_Init: could not allocate MTLGlyphCacheInfo");
75
return NULL;
76
}
77
78
gcinfo->head = NULL;
79
gcinfo->tail = NULL;
80
gcinfo->width = width;
81
gcinfo->height = height;
82
gcinfo->cellWidth = cellWidth;
83
gcinfo->cellHeight = cellHeight;
84
gcinfo->Flush = func;
85
86
return gcinfo;
87
}
88
89
/**
90
* Attempts to add the provided glyph to the specified cache. If the
91
* operation is successful, a pointer to the newly occupied cache cell is
92
* stored in the glyph's cellInfo field; otherwise, its cellInfo field is
93
* set to NULL, indicating that the glyph's original bits should be rendered
94
* instead. If the cache is full, the least-recently-used glyph is
95
* invalidated and its cache cell is reassigned to the new glyph being added.
96
*
97
* Note that this method only ensures that a rectangular region in the
98
* "virtual" glyph cache is available for the glyph image. Platform specific
99
* glyph caching code is responsible for actually caching the glyph image
100
* in the associated accelerated memory surface.
101
*
102
* Returns created cell info if it was successfully created and added to the
103
* cache and glyph's cell lists, NULL otherwise.
104
*/
105
MTLCacheCellInfo *
106
MTLGlyphCache_AddGlyph(MTLGlyphCacheInfo *cache, GlyphInfo *glyph)
107
{
108
MTLCacheCellInfo *cellinfo = NULL;
109
jint w = glyph->width;
110
jint h = glyph->height;
111
112
J2dTraceLn(J2D_TRACE_INFO, "MTLGlyphCache_AddGlyph");
113
114
if ((glyph->width > cache->cellWidth) ||
115
(glyph->height > cache->cellHeight))
116
{
117
return NULL;
118
}
119
120
jint x, y;
121
122
if (cache->head == NULL) {
123
x = 0;
124
y = 0;
125
} else {
126
x = cache->tail->x + cache->cellWidth;
127
y = cache->tail->y;
128
if ((x + cache->cellWidth) > cache->width) {
129
x = 0;
130
y += cache->cellHeight;
131
}
132
}
133
134
// create new CacheCellInfo
135
cellinfo = (MTLCacheCellInfo *)malloc(sizeof(MTLCacheCellInfo));
136
if (cellinfo == NULL) {
137
J2dTraceLn(J2D_TRACE_ERROR, "could not allocate CellInfo");
138
return NULL;
139
}
140
141
cellinfo->cacheInfo = cache;
142
cellinfo->glyphInfo = glyph;
143
cellinfo->timesRendered = 0;
144
cellinfo->x = x;
145
cellinfo->y = y;
146
cellinfo->leftOff = 0;
147
cellinfo->rightOff = 0;
148
cellinfo->tx1 = (jfloat)cellinfo->x / cache->width;
149
cellinfo->ty1 = (jfloat)cellinfo->y / cache->height;
150
cellinfo->tx2 = cellinfo->tx1 + ((jfloat)w / cache->width);
151
cellinfo->ty2 = cellinfo->ty1 + ((jfloat)h / cache->height);
152
153
if (cache->head == NULL) {
154
// initialize the head cell
155
cache->head = cellinfo;
156
} else {
157
// update existing tail cell
158
cache->tail->next = cellinfo;
159
}
160
161
// add the new cell to the end of the list
162
cache->tail = cellinfo;
163
cellinfo->next = NULL;
164
cellinfo->nextGCI = NULL;
165
166
// add cache cell to the glyph's cells list
167
MTLGlyphCache_AddCellInfo(glyph, cellinfo);
168
return cellinfo;
169
}
170
171
172
bool
173
MTLGlyphCache_IsCacheFull(MTLGlyphCacheInfo *cache, GlyphInfo *glyph)
174
{
175
jint w = glyph->width;
176
jint h = glyph->height;
177
178
J2dTraceLn(J2D_TRACE_INFO, "MTLGlyphCache_IsCacheFull");
179
180
jint x, y;
181
182
if (cache->head == NULL) {
183
return JNI_FALSE;
184
} else {
185
x = cache->tail->x + cache->cellWidth;
186
y = cache->tail->y;
187
if ((x + cache->cellWidth) > cache->width) {
188
x = 0;
189
y += cache->cellHeight;
190
if ((y + cache->cellHeight) > cache->height) {
191
return JNI_TRUE;
192
}
193
}
194
}
195
return JNI_FALSE;
196
}
197
/**
198
* Invalidates all cells in the cache. Note that this method does not
199
* attempt to compact the cache in any way; it just invalidates any cells
200
* that already exist.
201
*/
202
void
203
MTLGlyphCache_Invalidate(MTLGlyphCacheInfo *cache)
204
{
205
MTLCacheCellInfo *cellinfo;
206
207
J2dTraceLn(J2D_TRACE_INFO, "MTLGlyphCache_Invalidate");
208
209
if (cache == NULL) {
210
return;
211
}
212
213
// flush any pending vertices that may be depending on the current
214
// glyph cache layout
215
if (cache->Flush != NULL) {
216
cache->Flush();
217
}
218
219
cellinfo = cache->head;
220
while (cellinfo != NULL) {
221
if (cellinfo->glyphInfo != NULL) {
222
// if the cell is occupied, notify the base glyph that its
223
// cached version for this cache is about to be invalidated
224
MTLGlyphCache_RemoveCellInfo(cellinfo->glyphInfo, cellinfo);
225
}
226
cellinfo = cellinfo->next;
227
}
228
}
229
230
/**
231
* Invalidates and frees all cells and the cache itself. The "cache" pointer
232
* becomes invalid after this function returns.
233
*/
234
void
235
MTLGlyphCache_Free(MTLGlyphCacheInfo *cache)
236
{
237
MTLCacheCellInfo *cellinfo;
238
239
J2dTraceLn(J2D_TRACE_INFO, "MTLGlyphCache_Free");
240
241
if (cache == NULL) {
242
return;
243
}
244
245
// flush any pending vertices that may be depending on the current
246
// glyph cache
247
if (cache->Flush != NULL) {
248
cache->Flush();
249
}
250
251
while (cache->head != NULL) {
252
cellinfo = cache->head;
253
if (cellinfo->glyphInfo != NULL) {
254
// if the cell is occupied, notify the base glyph that its
255
// cached version for this cache is about to be invalidated
256
MTLGlyphCache_RemoveCellInfo(cellinfo->glyphInfo, cellinfo);
257
}
258
cache->head = cellinfo->next;
259
free(cellinfo);
260
}
261
free(cache);
262
}
263
264
/**
265
* Add cell info to the head of the glyph's list of cached cells.
266
*/
267
void
268
MTLGlyphCache_AddCellInfo(GlyphInfo *glyph, MTLCacheCellInfo *cellInfo)
269
{
270
// assert (glyph != NULL && cellInfo != NULL)
271
J2dTraceLn(J2D_TRACE_INFO, "MTLGlyphCache_AddCellInfo");
272
J2dTraceLn2(J2D_TRACE_VERBOSE, " glyph 0x%x: adding cell 0x%x to the list",
273
glyph, cellInfo);
274
275
cellInfo->glyphInfo = glyph;
276
cellInfo->nextGCI = glyph->cellInfo;
277
glyph->cellInfo = cellInfo;
278
glyph->managed = MANAGED_GLYPH;
279
}
280
281
/**
282
* Removes cell info from the glyph's list of cached cells.
283
*/
284
void
285
MTLGlyphCache_RemoveCellInfo(GlyphInfo *glyph, MTLCacheCellInfo *cellInfo)
286
{
287
MTLCacheCellInfo *currCellInfo = glyph->cellInfo;
288
MTLCacheCellInfo *prevInfo = NULL;
289
// assert (glyph!= NULL && glyph->cellInfo != NULL && cellInfo != NULL)
290
J2dTraceLn(J2D_TRACE_INFO, "MTLGlyphCache_RemoveCellInfo");
291
do {
292
if (currCellInfo == cellInfo) {
293
J2dTraceLn2(J2D_TRACE_VERBOSE,
294
" glyph 0x%x: removing cell 0x%x from glyph's list",
295
glyph, currCellInfo);
296
if (prevInfo == NULL) { // it's the head, chop-chop
297
glyph->cellInfo = currCellInfo->nextGCI;
298
} else {
299
prevInfo->nextGCI = currCellInfo->nextGCI;
300
}
301
currCellInfo->glyphInfo = NULL;
302
currCellInfo->nextGCI = NULL;
303
return;
304
}
305
prevInfo = currCellInfo;
306
currCellInfo = currCellInfo->nextGCI;
307
} while (currCellInfo != NULL);
308
J2dTraceLn2(J2D_TRACE_WARNING, "MTLGlyphCache_RemoveCellInfo: "\
309
"no cell 0x%x in glyph 0x%x's cell list",
310
cellInfo, glyph);
311
}
312
313
/**
314
* Removes cell info from the glyph's list of cached cells.
315
*/
316
JNIEXPORT void
317
MTLGlyphCache_RemoveAllCellInfos(GlyphInfo *glyph)
318
{
319
MTLCacheCellInfo *currCell, *prevCell;
320
321
J2dTraceLn(J2D_TRACE_INFO, "MTLGlyphCache_RemoveAllCellInfos");
322
323
if (glyph == NULL || glyph->cellInfo == NULL) {
324
return;
325
}
326
327
// invalidate all of this glyph's accelerated cache cells
328
currCell = glyph->cellInfo;
329
do {
330
currCell->glyphInfo = NULL;
331
prevCell = currCell;
332
currCell = currCell->nextGCI;
333
prevCell->nextGCI = NULL;
334
} while (currCell != NULL);
335
336
glyph->cellInfo = NULL;
337
}
338
339
/**
340
* Returns cell info associated with particular cache from the glyph's list of
341
* cached cells.
342
*/
343
MTLCacheCellInfo *
344
MTLGlyphCache_GetCellInfoForCache(GlyphInfo *glyph, MTLGlyphCacheInfo *cache)
345
{
346
// assert (glyph != NULL && cache != NULL)
347
J2dTraceLn(J2D_TRACE_VERBOSE2, "MTLGlyphCache_GetCellInfoForCache");
348
349
if (glyph->cellInfo != NULL) {
350
MTLCacheCellInfo *cellInfo = glyph->cellInfo;
351
do {
352
if (cellInfo->cacheInfo == cache) {
353
J2dTraceLn3(J2D_TRACE_VERBOSE2,
354
" glyph 0x%x: found cell 0x%x for cache 0x%x",
355
glyph, cellInfo, cache);
356
return cellInfo;
357
}
358
cellInfo = cellInfo->nextGCI;
359
} while (cellInfo != NULL);
360
}
361
J2dTraceLn2(J2D_TRACE_VERBOSE2, " glyph 0x%x: no cell for cache 0x%x",
362
glyph, cache);
363
return NULL;
364
}
365
366