Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/windows/native/sun/java2d/d3d/D3DTextRenderer.cpp
32288 views
1
/*
2
* Copyright (c) 2007, 2016, 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 <malloc.h>
27
#include <math.h>
28
#include <jlong.h>
29
30
#include "sun_java2d_d3d_D3DTextRenderer.h"
31
#include "sun_java2d_pipe_BufferedTextPipe.h"
32
33
#include "SurfaceData.h"
34
#include "D3DContext.h"
35
#include "D3DSurfaceData.h"
36
#include "D3DRenderQueue.h"
37
#include "D3DTextRenderer.h"
38
#include "D3DGlyphCache.h"
39
#include "AccelGlyphCache.h"
40
#include "fontscalerdefs.h"
41
42
/**
43
* The current "glyph mode" state. This variable is used to track the
44
* codepath used to render a particular glyph. This variable is reset to
45
* MODE_NOT_INITED at the beginning of every call to D3DTR_DrawGlyphList().
46
* As each glyph is rendered, the glyphMode variable is updated to reflect
47
* the current mode, so if the current mode is the same as the mode used
48
* to render the previous glyph, we can avoid doing costly setup operations
49
* each time.
50
*/
51
typedef enum {
52
MODE_NOT_INITED,
53
MODE_USE_CACHE_GRAY,
54
MODE_USE_CACHE_LCD,
55
MODE_NO_CACHE_GRAY,
56
MODE_NO_CACHE_LCD
57
} GlyphMode;
58
static GlyphMode glyphMode = MODE_NOT_INITED;
59
60
/**
61
* The current bounds of the "cached destination" texture, in destination
62
* coordinate space. The width/height of these bounds will not exceed the
63
* D3DTR_CACHED_DEST_WIDTH/HEIGHT values defined above. These bounds are
64
* only considered valid when the isCachedDestValid flag is JNI_TRUE.
65
*/
66
static SurfaceDataBounds cachedDestBounds;
67
68
/**
69
* This flag indicates whether the "cached destination" texture contains
70
* valid data. This flag is reset to JNI_FALSE at the beginning of every
71
* call to D3DTR_DrawGlyphList(). Once we copy valid destination data
72
* into the cached texture, this flag is set to JNI_TRUE. This way, we
73
* can limit the number of times we need to copy destination data, which
74
* is a very costly operation.
75
*/
76
static jboolean isCachedDestValid = JNI_FALSE;
77
78
/**
79
* The bounds of the previously rendered LCD glyph, in destination
80
* coordinate space. We use these bounds to determine whether the glyph
81
* currently being rendered overlaps the previously rendered glyph (i.e.
82
* its bounding box intersects that of the previously rendered glyph).
83
* If so, we need to re-read the destination area associated with that
84
* previous glyph so that we can correctly blend with the actual
85
* destination data.
86
*/
87
static SurfaceDataBounds previousGlyphBounds;
88
89
/**
90
* Updates the gamma and inverse gamma values for the LCD text shader.
91
*/
92
static HRESULT
93
D3DTR_UpdateLCDTextContrast(D3DContext *d3dc, jint contrast)
94
{
95
HRESULT res;
96
IDirect3DDevice9 *pd3dDevice = d3dc->Get3DDevice();
97
98
jfloat fcon = ((jfloat)contrast) / 100.0f;
99
jfloat invgamma = fcon;
100
jfloat gamma = 1.0f / invgamma;
101
jfloat vals[4];
102
103
// update the "invgamma" parameter of the shader program
104
vals[0] = invgamma;
105
vals[1] = invgamma;
106
vals[2] = invgamma;
107
vals[3] = 0.0f; // unused
108
pd3dDevice->SetPixelShaderConstantF(1, vals, 1);
109
110
// update the "gamma" parameter of the shader program
111
vals[0] = gamma;
112
vals[1] = gamma;
113
vals[2] = gamma;
114
vals[3] = 0.0f; // unused
115
res = pd3dDevice->SetPixelShaderConstantF(2, vals, 1);
116
117
return res;
118
}
119
120
/**
121
* Updates the current gamma-adjusted source color ("src_adj") of the LCD
122
* text shader program. Note that we could calculate this value in the
123
* shader (e.g. just as we do for "dst_adj"), but would be unnecessary work
124
* (and a measurable performance hit, maybe around 5%) since this value is
125
* constant over the entire glyph list. So instead we just calculate the
126
* gamma-adjusted value once and update the uniform parameter of the LCD
127
* shader as needed.
128
*/
129
static HRESULT
130
D3DTR_UpdateLCDTextColor(D3DContext *d3dc, jint contrast)
131
{
132
IDirect3DDevice9 *pd3dDevice = d3dc->Get3DDevice();
133
jfloat gamma = ((jfloat)contrast) / 100.0f;
134
jfloat clr[4];
135
136
J2dTraceLn1(J2D_TRACE_INFO,
137
"D3DTR_UpdateLCDTextColor: contrast=%d", contrast);
138
139
/*
140
* Note: Ideally we would update the "srcAdj" uniform parameter only
141
* when there is a change in the source color. Fortunately, the cost
142
* of querying the current D3D color state and updating the uniform
143
* value is quite small, and in the common case we only need to do this
144
* once per GlyphList, so we gain little from trying to optimize too
145
* eagerly here.
146
*/
147
148
// get the current D3D primary color state
149
jint color = d3dc->pVCacher->GetColor();
150
clr[0] = (jfloat)((color >> 16) & 0xff) / 255.0f;
151
clr[1] = (jfloat)((color >> 8) & 0xff) / 255.0f;
152
clr[2] = (jfloat)((color >> 0) & 0xff) / 255.0f;
153
clr[3] = 0.0f; // unused
154
155
// gamma adjust the primary color
156
clr[0] = (jfloat)pow(clr[0], gamma);
157
clr[1] = (jfloat)pow(clr[1], gamma);
158
clr[2] = (jfloat)pow(clr[2], gamma);
159
160
// update the "srcAdj" parameter of the shader program with this value
161
return pd3dDevice->SetPixelShaderConstantF(0, clr, 1);
162
}
163
164
/**
165
* Enables the LCD text shader and updates any related state, such as the
166
* gamma values.
167
*/
168
static HRESULT
169
D3DTR_EnableLCDGlyphModeState(D3DContext *d3dc, D3DSDOps *dstOps,
170
jboolean useCache, jint contrast)
171
{
172
D3DResource *pGlyphTexRes, *pCachedDestTexRes;
173
IDirect3DTexture9 *pGlyphTex, *pCachedDestTex;
174
175
RETURN_STATUS_IF_NULL(dstOps->pResource, E_FAIL);
176
177
HRESULT res = S_OK;
178
if (useCache) {
179
// glyph cache had been already initialized
180
pGlyphTexRes = d3dc->GetLCDGlyphCache()->GetGlyphCacheTexture();
181
} else {
182
res = d3dc->GetResourceManager()->GetBlitTexture(&pGlyphTexRes);
183
}
184
RETURN_STATUS_IF_FAILED(res);
185
186
pGlyphTex = pGlyphTexRes->GetTexture();
187
188
res = d3dc->GetResourceManager()->
189
GetCachedDestTexture(dstOps->pResource->GetDesc()->Format,
190
&pCachedDestTexRes);
191
RETURN_STATUS_IF_FAILED(res);
192
pCachedDestTex = pCachedDestTexRes->GetTexture();
193
194
IDirect3DDevice9 *pd3dDevice = d3dc->Get3DDevice();
195
D3DTEXTUREFILTERTYPE fhint =
196
d3dc->IsTextureFilteringSupported(D3DTEXF_NONE) ?
197
D3DTEXF_NONE : D3DTEXF_POINT;
198
pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, fhint);
199
pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, fhint);
200
pd3dDevice->SetSamplerState(1, D3DSAMP_MAGFILTER, fhint);
201
pd3dDevice->SetSamplerState(1, D3DSAMP_MINFILTER, fhint);
202
d3dc->UpdateTextureColorState(D3DTA_TEXTURE, 1);
203
204
// bind the texture containing glyph data to texture unit 0
205
d3dc->SetTexture(pGlyphTex, 0);
206
207
// bind the texture tile containing destination data to texture unit 1
208
d3dc->SetTexture(pCachedDestTex, 1);
209
210
// create/enable the LCD text shader
211
res = d3dc->EnableLCDTextProgram();
212
RETURN_STATUS_IF_FAILED(res);
213
214
// update the current contrast settings (note: these change very rarely,
215
// but it seems that D3D pixel shader registers aren't maintained as
216
// part of the pixel shader instance, so we need to update these
217
// everytime around in case another shader blew away the contents
218
// of those registers)
219
D3DTR_UpdateLCDTextContrast(d3dc, contrast);
220
221
// update the current color settings
222
return D3DTR_UpdateLCDTextColor(d3dc, contrast);
223
}
224
225
HRESULT
226
D3DTR_EnableGlyphVertexCache(D3DContext *d3dc)
227
{
228
J2dTraceLn(J2D_TRACE_INFO, "D3DTR_EnableGlyphVertexCache");
229
230
IDirect3DDevice9 *pd3dDevice = d3dc->Get3DDevice();
231
D3DTEXTUREFILTERTYPE fhint =
232
d3dc->IsTextureFilteringSupported(D3DTEXF_NONE) ?
233
D3DTEXF_NONE : D3DTEXF_POINT;
234
pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, fhint);
235
pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, fhint);
236
237
// glyph cache had been successfully initialized if we got here
238
D3DResource *pGlyphCacheTexRes =
239
d3dc->GetGrayscaleGlyphCache()->GetGlyphCacheTexture();
240
return d3dc->SetTexture(pGlyphCacheTexRes->GetTexture(), 0);
241
}
242
243
HRESULT
244
D3DTR_DisableGlyphVertexCache(D3DContext *d3dc)
245
{
246
J2dTraceLn(J2D_TRACE_INFO, "D3DTR_DisableGlyphVertexCache");
247
248
return d3dc->SetTexture(NULL, 0);
249
}
250
251
/**
252
* Disables any pending state associated with the current "glyph mode".
253
*/
254
static HRESULT
255
D3DTR_DisableGlyphModeState(D3DContext *d3dc)
256
{
257
HRESULT res = S_OK;
258
IDirect3DDevice9 *pd3dDevice = d3dc->Get3DDevice();
259
260
switch (glyphMode) {
261
case MODE_NO_CACHE_LCD:
262
case MODE_USE_CACHE_LCD:
263
d3dc->FlushVertexQueue();
264
pd3dDevice->SetPixelShader(NULL);
265
res = d3dc->SetTexture(NULL, 1);
266
break;
267
268
case MODE_NO_CACHE_GRAY:
269
case MODE_USE_CACHE_GRAY:
270
case MODE_NOT_INITED:
271
default:
272
break;
273
}
274
return res;
275
}
276
277
static HRESULT
278
D3DTR_DrawGrayscaleGlyphViaCache(D3DContext *d3dc,
279
GlyphInfo *ginfo, jint x, jint y)
280
{
281
HRESULT res = S_OK;
282
D3DGlyphCache *pGrayscaleGCache;
283
CacheCellInfo *cell;
284
GlyphCacheInfo *gcache;
285
jfloat x1, y1, x2, y2;
286
287
J2dTraceLn(J2D_TRACE_VERBOSE, "D3DTR_DrawGrayscaleGlyphViaCache");
288
289
if (glyphMode != MODE_USE_CACHE_GRAY) {
290
D3DTR_DisableGlyphModeState(d3dc);
291
292
res = d3dc->BeginScene(STATE_GLYPHOP);
293
RETURN_STATUS_IF_FAILED(res);
294
295
glyphMode = MODE_USE_CACHE_GRAY;
296
}
297
298
pGrayscaleGCache = d3dc->GetGrayscaleGlyphCache();
299
gcache = pGrayscaleGCache->GetGlyphCache();
300
cell = AccelGlyphCache_GetCellInfoForCache(ginfo, gcache);
301
if (cell == NULL) {
302
// attempt to add glyph to accelerated glyph cache
303
res = pGrayscaleGCache->AddGlyph(ginfo);
304
RETURN_STATUS_IF_FAILED(res);
305
306
cell = AccelGlyphCache_GetCellInfoForCache(ginfo, gcache);
307
RETURN_STATUS_IF_NULL(cell, E_FAIL);
308
}
309
310
cell->timesRendered++;
311
312
x1 = (jfloat)x;
313
y1 = (jfloat)y;
314
x2 = x1 + ginfo->width;
315
y2 = y1 + ginfo->height;
316
317
return d3dc->pVCacher->DrawTexture(x1, y1, x2, y2,
318
cell->tx1, cell->ty1,
319
cell->tx2, cell->ty2);
320
}
321
322
/**
323
* Evaluates to true if the rectangle defined by gx1/gy1/gx2/gy2 is
324
* inside outerBounds.
325
*/
326
#define INSIDE(gx1, gy1, gx2, gy2, outerBounds) \
327
(((gx1) >= outerBounds.x1) && ((gy1) >= outerBounds.y1) && \
328
((gx2) <= outerBounds.x2) && ((gy2) <= outerBounds.y2))
329
330
/**
331
* Evaluates to true if the rectangle defined by gx1/gy1/gx2/gy2 intersects
332
* the rectangle defined by bounds.
333
*/
334
#define INTERSECTS(gx1, gy1, gx2, gy2, bounds) \
335
((bounds.x2 > (gx1)) && (bounds.y2 > (gy1)) && \
336
(bounds.x1 < (gx2)) && (bounds.y1 < (gy2)))
337
338
/**
339
* This method checks to see if the given LCD glyph bounds fall within the
340
* cached destination texture bounds. If so, this method can return
341
* immediately. If not, this method will copy a chunk of framebuffer data
342
* into the cached destination texture and then update the current cached
343
* destination bounds before returning.
344
*
345
* The agx1, agx2 are "adjusted" glyph bounds, which are only used when checking
346
* against the previous glyph bounds.
347
*/
348
static HRESULT
349
D3DTR_UpdateCachedDestination(D3DContext *d3dc, D3DSDOps *dstOps,
350
GlyphInfo *ginfo,
351
jint gx1, jint gy1, jint gx2, jint gy2,
352
jint agx1, jint agx2,
353
jint glyphIndex, jint totalGlyphs)
354
{
355
jint dx1, dy1, dx2, dy2;
356
D3DResource *pCachedDestTexRes;
357
IDirect3DSurface9 *pCachedDestSurface, *pDst;
358
HRESULT res = S_OK;
359
360
if (isCachedDestValid && INSIDE(gx1, gy1, gx2, gy2, cachedDestBounds)) {
361
// glyph is already within the cached destination bounds; no need
362
// to read back the entire destination region again, but we do
363
// need to see if the current glyph overlaps the previous glyph...
364
365
// only use the "adjusted" glyph bounds when checking against
366
// previous glyph's bounds
367
gx1 = agx1;
368
gx2 = agx2;
369
370
if (INTERSECTS(gx1, gy1, gx2, gy2, previousGlyphBounds)) {
371
// the current glyph overlaps the destination region touched
372
// by the previous glyph, so now we need to read back the part
373
// of the destination corresponding to the previous glyph
374
dx1 = previousGlyphBounds.x1;
375
dy1 = previousGlyphBounds.y1;
376
dx2 = previousGlyphBounds.x2;
377
dy2 = previousGlyphBounds.y2;
378
379
// REMIND: make sure we flush any pending primitives that are
380
// dependent on the current contents of the cached dest
381
d3dc->FlushVertexQueue();
382
383
RETURN_STATUS_IF_NULL(dstOps->pResource, E_FAIL);
384
RETURN_STATUS_IF_NULL(pDst = dstOps->pResource->GetSurface(),
385
E_FAIL);
386
res = d3dc->GetResourceManager()->
387
GetCachedDestTexture(dstOps->pResource->GetDesc()->Format,
388
&pCachedDestTexRes);
389
RETURN_STATUS_IF_FAILED(res);
390
pCachedDestSurface = pCachedDestTexRes->GetSurface();
391
392
// now dxy12 represent the "desired" destination bounds, but the
393
// StretchRect() call may fail if these fall outside the actual
394
// surface bounds; therefore, we use cxy12 to represent the
395
// clamped bounds, and dxy12 are saved for later
396
jint cx1 = (dx1 < 0) ? 0 : dx1;
397
jint cy1 = (dy1 < 0) ? 0 : dy1;
398
jint cx2 = (dx2 > dstOps->width) ? dstOps->width : dx2;
399
jint cy2 = (dy2 > dstOps->height) ? dstOps->height : dy2;
400
401
if (cx2 > cx1 && cy2 > cy1) {
402
// copy destination into subregion of cached texture tile
403
// cx1-cachedDestBounds.x1 == +xoffset from left of texture
404
// cy1-cachedDestBounds.y1 == +yoffset from top of texture
405
// cx2-cachedDestBounds.x1 == +xoffset from left of texture
406
// cy2-cachedDestBounds.y1 == +yoffset from top of texture
407
jint cdx1 = cx1-cachedDestBounds.x1;
408
jint cdy1 = cy1-cachedDestBounds.y1;
409
jint cdx2 = cx2-cachedDestBounds.x1;
410
jint cdy2 = cy2-cachedDestBounds.y1;
411
RECT srcRect = { cx1, cy1, cx2, cy2 };
412
RECT dstRect = { cdx1, cdy1, cdx2, cdy2 };
413
414
IDirect3DDevice9 *pd3dDevice = d3dc->Get3DDevice();
415
res = pd3dDevice->StretchRect(pDst, &srcRect,
416
pCachedDestSurface, &dstRect,
417
D3DTEXF_NONE);
418
}
419
}
420
} else {
421
// destination region is not valid, so we need to read back a
422
// chunk of the destination into our cached texture
423
424
// position the upper-left corner of the destination region on the
425
// "top" line of glyph list
426
// REMIND: this isn't ideal; it would be better if we had some idea
427
// of the bounding box of the whole glyph list (this is
428
// do-able, but would require iterating through the whole
429
// list up front, which may present its own problems)
430
dx1 = gx1;
431
dy1 = gy1;
432
433
jint remainingWidth;
434
if (ginfo->advanceX > 0) {
435
// estimate the width based on our current position in the glyph
436
// list and using the x advance of the current glyph (this is just
437
// a quick and dirty heuristic; if this is a "thin" glyph image,
438
// then we're likely to underestimate, and if it's "thick" then we
439
// may end up reading back more than we need to)
440
remainingWidth =
441
(jint)(ginfo->advanceX * (totalGlyphs - glyphIndex));
442
if (remainingWidth > D3DTR_CACHED_DEST_WIDTH) {
443
remainingWidth = D3DTR_CACHED_DEST_WIDTH;
444
} else if (remainingWidth < ginfo->width) {
445
// in some cases, the x-advance may be slightly smaller
446
// than the actual width of the glyph; if so, adjust our
447
// estimate so that we can accommodate the entire glyph
448
remainingWidth = ginfo->width;
449
}
450
} else {
451
// a negative advance is possible when rendering rotated text,
452
// in which case it is difficult to estimate an appropriate
453
// region for readback, so we will pick a region that
454
// encompasses just the current glyph
455
remainingWidth = ginfo->width;
456
}
457
dx2 = dx1 + remainingWidth;
458
459
// estimate the height (this is another sloppy heuristic; we'll
460
// make the cached destination region tall enough to encompass most
461
// glyphs that are small enough to fit in the glyph cache, and then
462
// we add a little something extra to account for descenders
463
dy2 = dy1 + D3DTR_CACHE_CELL_HEIGHT + 2;
464
465
// REMIND: make sure we flush any pending primitives that are
466
// dependent on the current contents of the cached dest
467
d3dc->FlushVertexQueue();
468
469
RETURN_STATUS_IF_NULL(dstOps->pResource, E_FAIL);
470
RETURN_STATUS_IF_NULL(pDst = dstOps->pResource->GetSurface(), E_FAIL);
471
res = d3dc->GetResourceManager()->
472
GetCachedDestTexture(dstOps->pResource->GetDesc()->Format,
473
&pCachedDestTexRes);
474
RETURN_STATUS_IF_FAILED(res);
475
pCachedDestSurface = pCachedDestTexRes->GetSurface();
476
477
// now dxy12 represent the "desired" destination bounds, but the
478
// StretchRect() call may fail if these fall outside the actual
479
// surface bounds; therefore, we use cxy12 to represent the
480
// clamped bounds, and dxy12 are saved for later
481
jint cx1 = (dx1 < 0) ? 0 : dx1;
482
jint cy1 = (dy1 < 0) ? 0 : dy1;
483
jint cx2 = (dx2 > dstOps->width) ? dstOps->width : dx2;
484
jint cy2 = (dy2 > dstOps->height) ? dstOps->height : dy2;
485
486
if (cx2 > cx1 && cy2 > cy1) {
487
// copy destination into cached texture tile (the upper-left
488
// corner of the destination region will be positioned at the
489
// upper-left corner (0,0) of the texture)
490
RECT srcRect = { cx1, cy1, cx2, cy2 };
491
RECT dstRect = { cx1-dx1, cy1-dy1, cx2-dx1, cy2-dy1 };
492
493
IDirect3DDevice9 *pd3dDevice = d3dc->Get3DDevice();
494
res = pd3dDevice->StretchRect(pDst, &srcRect,
495
pCachedDestSurface, &dstRect,
496
D3DTEXF_NONE);
497
}
498
499
// update the cached bounds and mark it valid
500
cachedDestBounds.x1 = dx1;
501
cachedDestBounds.y1 = dy1;
502
cachedDestBounds.x2 = dx2;
503
cachedDestBounds.y2 = dy2;
504
isCachedDestValid = JNI_TRUE;
505
}
506
507
// always update the previous glyph bounds
508
previousGlyphBounds.x1 = gx1;
509
previousGlyphBounds.y1 = gy1;
510
previousGlyphBounds.x2 = gx2;
511
previousGlyphBounds.y2 = gy2;
512
513
return res;
514
}
515
516
static HRESULT
517
D3DTR_DrawLCDGlyphViaCache(D3DContext *d3dc, D3DSDOps *dstOps,
518
GlyphInfo *ginfo, jint x, jint y,
519
jint glyphIndex, jint totalGlyphs,
520
jboolean rgbOrder, jint contrast)
521
{
522
HRESULT res;
523
D3DGlyphCache *pLCDGCache;
524
CacheCellInfo *cell;
525
GlyphCacheInfo *gcache;
526
jint dx1, dy1, dx2, dy2;
527
jfloat dtx1, dty1, dtx2, dty2;
528
529
J2dTraceLn(J2D_TRACE_VERBOSE, "D3DTR_DrawLCDGlyphViaCache");
530
531
// the glyph cache is initialized before this method is called
532
pLCDGCache = d3dc->GetLCDGlyphCache();
533
534
if (glyphMode != MODE_USE_CACHE_LCD) {
535
D3DTR_DisableGlyphModeState(d3dc);
536
537
res = d3dc->BeginScene(STATE_TEXTUREOP);
538
RETURN_STATUS_IF_FAILED(res);
539
540
pLCDGCache->CheckGlyphCacheByteOrder(rgbOrder);
541
542
res = D3DTR_EnableLCDGlyphModeState(d3dc, dstOps, JNI_TRUE, contrast);
543
RETURN_STATUS_IF_FAILED(res);
544
545
glyphMode = MODE_USE_CACHE_LCD;
546
}
547
548
gcache = pLCDGCache->GetGlyphCache();
549
cell = AccelGlyphCache_GetCellInfoForCache(ginfo, gcache);
550
if (cell == NULL) {
551
// attempt to add glyph to accelerated glyph cache
552
res = pLCDGCache->AddGlyph(ginfo);
553
RETURN_STATUS_IF_FAILED(res);
554
555
// we'll just no-op in the rare case that the cell is NULL
556
cell = AccelGlyphCache_GetCellInfoForCache(ginfo, gcache);
557
RETURN_STATUS_IF_NULL(cell, E_FAIL);
558
}
559
560
cell->timesRendered++;
561
562
// location of the glyph in the destination's coordinate space
563
dx1 = x;
564
dy1 = y;
565
dx2 = dx1 + ginfo->width;
566
dy2 = dy1 + ginfo->height;
567
568
// copy destination into second cached texture, if necessary
569
D3DTR_UpdateCachedDestination(d3dc,
570
dstOps, ginfo,
571
dx1, dy1,
572
dx2, dy2,
573
dx1 + cell->leftOff, // adjusted dx1
574
dx2 + cell->rightOff, // adjusted dx2
575
glyphIndex, totalGlyphs);
576
577
// texture coordinates of the destination tile
578
dtx1 = ((jfloat)(dx1 - cachedDestBounds.x1)) / D3DTR_CACHED_DEST_WIDTH;
579
dty1 = ((jfloat)(dy1 - cachedDestBounds.y1)) / D3DTR_CACHED_DEST_HEIGHT;
580
dtx2 = ((jfloat)(dx2 - cachedDestBounds.x1)) / D3DTR_CACHED_DEST_WIDTH;
581
dty2 = ((jfloat)(dy2 - cachedDestBounds.y1)) / D3DTR_CACHED_DEST_HEIGHT;
582
583
// render composed texture to the destination surface
584
return d3dc->pVCacher->DrawTexture((jfloat)dx1, (jfloat)dy1,
585
(jfloat)dx2, (jfloat)dy2,
586
cell->tx1, cell->ty1,
587
cell->tx2, cell->ty2,
588
dtx1, dty1, dtx2, dty2);
589
}
590
591
static HRESULT
592
D3DTR_DrawGrayscaleGlyphNoCache(D3DContext *d3dc,
593
GlyphInfo *ginfo, jint x, jint y)
594
{
595
jint tw, th;
596
jint sx, sy, sw, sh;
597
jint x0;
598
jint w = ginfo->width;
599
jint h = ginfo->height;
600
HRESULT res = S_OK;
601
602
J2dTraceLn(J2D_TRACE_VERBOSE, "D3DTR_DrawGrayscaleGlyphNoCache");
603
604
if (glyphMode != MODE_NO_CACHE_GRAY) {
605
D3DTR_DisableGlyphModeState(d3dc);
606
607
res = d3dc->BeginScene(STATE_MASKOP);
608
RETURN_STATUS_IF_FAILED(res);
609
610
glyphMode = MODE_NO_CACHE_GRAY;
611
}
612
613
x0 = x;
614
tw = D3D_MASK_CACHE_TILE_WIDTH;
615
th = D3D_MASK_CACHE_TILE_HEIGHT;
616
617
for (sy = 0; sy < h; sy += th, y += th) {
618
x = x0;
619
sh = ((sy + th) > h) ? (h - sy) : th;
620
621
for (sx = 0; sx < w; sx += tw, x += tw) {
622
sw = ((sx + tw) > w) ? (w - sx) : tw;
623
624
res = d3dc->GetMaskCache()->AddMaskQuad(sx, sy, x, y, sw, sh,
625
w, ginfo->image);
626
}
627
}
628
629
return res;
630
}
631
632
static HRESULT
633
D3DTR_DrawLCDGlyphNoCache(D3DContext *d3dc, D3DSDOps *dstOps,
634
GlyphInfo *ginfo, jint x, jint y,
635
jint rowBytesOffset,
636
jboolean rgbOrder, jint contrast)
637
{
638
jfloat tx1, ty1, tx2, ty2;
639
jfloat dx1, dy1, dx2, dy2;
640
jfloat dtx1, dty1, dtx2, dty2;
641
jint tw, th;
642
jint sx, sy, sw, sh;
643
jint cx1, cy1, cx2, cy2;
644
jint x0;
645
jint w = ginfo->width;
646
jint h = ginfo->height;
647
TileFormat tileFormat = rgbOrder ? TILEFMT_3BYTE_RGB : TILEFMT_3BYTE_BGR;
648
649
IDirect3DDevice9 *pd3dDevice = d3dc->Get3DDevice();
650
D3DResource *pBlitTextureRes, *pCachedDestTextureRes;
651
IDirect3DTexture9 *pBlitTexture;
652
IDirect3DSurface9 *pCachedDestSurface, *pDst;
653
HRESULT res;
654
655
J2dTraceLn(J2D_TRACE_VERBOSE, "D3DTR_DrawLCDGlyphNoCache");
656
657
RETURN_STATUS_IF_NULL(dstOps->pResource, E_FAIL);
658
RETURN_STATUS_IF_NULL(pDst = dstOps->pResource->GetSurface(), E_FAIL);
659
660
res = d3dc->GetResourceManager()->GetBlitTexture(&pBlitTextureRes);
661
RETURN_STATUS_IF_FAILED(res);
662
663
res = d3dc->GetResourceManager()->
664
GetCachedDestTexture(dstOps->pResource->GetDesc()->Format,
665
&pCachedDestTextureRes);
666
RETURN_STATUS_IF_FAILED(res);
667
668
pBlitTexture = pBlitTextureRes->GetTexture();
669
pCachedDestSurface = pCachedDestTextureRes->GetSurface();
670
671
if (glyphMode != MODE_NO_CACHE_LCD) {
672
D3DTR_DisableGlyphModeState(d3dc);
673
674
res = d3dc->BeginScene(STATE_TEXTUREOP);
675
RETURN_STATUS_IF_FAILED(res);
676
res = D3DTR_EnableLCDGlyphModeState(d3dc,dstOps, JNI_FALSE, contrast);
677
RETURN_STATUS_IF_FAILED(res);
678
679
glyphMode = MODE_NO_CACHE_LCD;
680
}
681
682
x0 = x;
683
tx1 = 0.0f;
684
ty1 = 0.0f;
685
dtx1 = 0.0f;
686
dty1 = 0.0f;
687
tw = D3DTR_NOCACHE_TILE_SIZE;
688
th = D3DTR_NOCACHE_TILE_SIZE;
689
690
for (sy = 0; sy < h; sy += th, y += th) {
691
x = x0;
692
sh = ((sy + th) > h) ? (h - sy) : th;
693
694
for (sx = 0; sx < w; sx += tw, x += tw) {
695
sw = ((sx + tw) > w) ? (w - sx) : tw;
696
697
// calculate the bounds of the tile to be copied from the
698
// destination into the cached tile
699
cx1 = x;
700
cy1 = y;
701
cx2 = cx1 + sw;
702
cy2 = cy1 + sh;
703
704
// need to clamp to the destination bounds, otherwise the
705
// StretchRect() call may fail
706
if (cx1 < 0) cx1 = 0;
707
if (cy1 < 0) cy1 = 0;
708
if (cx2 > dstOps->width) cx2 = dstOps->width;
709
if (cy2 > dstOps->height) cy2 = dstOps->height;
710
711
if (cx2 > cx1 && cy2 > cy1) {
712
// copy LCD mask into glyph texture tile
713
d3dc->UploadTileToTexture(pBlitTextureRes,
714
ginfo->image+rowBytesOffset,
715
0, 0, sx, sy, sw, sh,
716
ginfo->rowBytes, tileFormat);
717
718
// update the lower-right glyph texture coordinates
719
tx2 = ((jfloat)sw) / D3DC_BLIT_TILE_SIZE;
720
ty2 = ((jfloat)sh) / D3DC_BLIT_TILE_SIZE;
721
722
// calculate the actual destination vertices
723
dx1 = (jfloat)x;
724
dy1 = (jfloat)y;
725
dx2 = dx1 + sw;
726
dy2 = dy1 + sh;
727
728
// copy destination into cached texture tile (the upper-left
729
// corner of the destination region will be positioned at the
730
// upper-left corner (0,0) of the texture)
731
RECT srcRect = { cx1, cy1, cx2, cy2 };
732
RECT dstRect = { cx1-x, cy1-y, cx2-x, cy2-y };
733
pd3dDevice->StretchRect(pDst, &srcRect,
734
pCachedDestSurface,
735
&dstRect,
736
D3DTEXF_NONE);
737
738
// update the remaining destination texture coordinates
739
dtx2 = ((jfloat)sw) / D3DTR_CACHED_DEST_WIDTH;
740
dty2 = ((jfloat)sh) / D3DTR_CACHED_DEST_HEIGHT;
741
742
// render composed texture to the destination surface
743
res = d3dc->pVCacher->DrawTexture( dx1, dy1, dx2, dy2,
744
tx1, ty1, tx2, ty2,
745
dtx1, dty1, dtx2, dty2);
746
747
// unfortunately we need to flush after each tile
748
d3dc->FlushVertexQueue();
749
}
750
}
751
}
752
753
return res;
754
}
755
756
// see DrawGlyphList.c for more on this macro...
757
#define FLOOR_ASSIGN(l, r) \
758
if ((r)<0) (l) = ((int)floor(r)); else (l) = ((int)(r))
759
760
HRESULT
761
D3DTR_DrawGlyphList(D3DContext *d3dc, D3DSDOps *dstOps,
762
jint totalGlyphs, jboolean usePositions,
763
jboolean subPixPos, jboolean rgbOrder, jint lcdContrast,
764
jfloat glyphListOrigX, jfloat glyphListOrigY,
765
unsigned char *images, unsigned char *positions)
766
{
767
int glyphCounter;
768
HRESULT res = S_OK;
769
J2dTraceLn(J2D_TRACE_INFO, "D3DTR_DrawGlyphList");
770
771
RETURN_STATUS_IF_NULL(d3dc, E_FAIL);
772
RETURN_STATUS_IF_NULL(d3dc->Get3DDevice(), E_FAIL);
773
RETURN_STATUS_IF_NULL(dstOps, E_FAIL);
774
RETURN_STATUS_IF_NULL(images, E_FAIL);
775
if (usePositions) {
776
RETURN_STATUS_IF_NULL(positions, E_FAIL);
777
}
778
779
glyphMode = MODE_NOT_INITED;
780
isCachedDestValid = JNI_FALSE;
781
782
for (glyphCounter = 0; glyphCounter < totalGlyphs; glyphCounter++) {
783
jint x, y;
784
jfloat glyphx, glyphy;
785
jboolean grayscale;
786
GlyphInfo *ginfo = (GlyphInfo *)jlong_to_ptr(NEXT_LONG(images));
787
788
if (ginfo == NULL) {
789
// this shouldn't happen, but if it does we'll just break out...
790
J2dRlsTraceLn(J2D_TRACE_ERROR,
791
"D3DTR_DrawGlyphList: glyph info is null");
792
break;
793
}
794
795
grayscale = (ginfo->rowBytes == ginfo->width);
796
797
if (usePositions) {
798
jfloat posx = NEXT_FLOAT(positions);
799
jfloat posy = NEXT_FLOAT(positions);
800
glyphx = glyphListOrigX + posx + ginfo->topLeftX;
801
glyphy = glyphListOrigY + posy + ginfo->topLeftY;
802
FLOOR_ASSIGN(x, glyphx);
803
FLOOR_ASSIGN(y, glyphy);
804
} else {
805
glyphx = glyphListOrigX + ginfo->topLeftX;
806
glyphy = glyphListOrigY + ginfo->topLeftY;
807
FLOOR_ASSIGN(x, glyphx);
808
FLOOR_ASSIGN(y, glyphy);
809
glyphListOrigX += ginfo->advanceX;
810
glyphListOrigY += ginfo->advanceY;
811
}
812
813
if (ginfo->image == NULL) {
814
continue;
815
}
816
817
if (grayscale) {
818
// grayscale or monochrome glyph data
819
if (ginfo->width <= D3DTR_CACHE_CELL_WIDTH &&
820
ginfo->height <= D3DTR_CACHE_CELL_HEIGHT &&
821
SUCCEEDED(d3dc->InitGrayscaleGlyphCache()))
822
{
823
res = D3DTR_DrawGrayscaleGlyphViaCache(d3dc, ginfo, x, y);
824
} else {
825
res = D3DTR_DrawGrayscaleGlyphNoCache(d3dc, ginfo, x, y);
826
}
827
} else {
828
// LCD-optimized glyph data
829
jint rowBytesOffset = 0;
830
831
if (subPixPos) {
832
jint frac = (jint)((glyphx - x) * 3);
833
if (frac != 0) {
834
rowBytesOffset = 3 - frac;
835
x += 1;
836
}
837
}
838
839
if (rowBytesOffset == 0 &&
840
ginfo->width <= D3DTR_CACHE_CELL_WIDTH &&
841
ginfo->height <= D3DTR_CACHE_CELL_HEIGHT &&
842
SUCCEEDED(d3dc->InitLCDGlyphCache()))
843
{
844
res = D3DTR_DrawLCDGlyphViaCache(d3dc, dstOps,
845
ginfo, x, y,
846
glyphCounter, totalGlyphs,
847
rgbOrder, lcdContrast);
848
} else {
849
res = D3DTR_DrawLCDGlyphNoCache(d3dc, dstOps,
850
ginfo, x, y,
851
rowBytesOffset,
852
rgbOrder, lcdContrast);
853
}
854
}
855
856
if (FAILED(res)) {
857
break;
858
}
859
}
860
861
D3DTR_DisableGlyphModeState(d3dc);
862
return res;
863
}
864
865
JNIEXPORT void JNICALL
866
Java_sun_java2d_d3d_D3DTextRenderer_drawGlyphList
867
(JNIEnv *env, jobject self,
868
jint numGlyphs, jboolean usePositions,
869
jboolean subPixPos, jboolean rgbOrder, jint lcdContrast,
870
jfloat glyphListOrigX, jfloat glyphListOrigY,
871
jlongArray imgArray, jfloatArray posArray)
872
{
873
unsigned char *images;
874
875
J2dTraceLn(J2D_TRACE_INFO, "D3DTextRenderer_drawGlyphList");
876
877
images = (unsigned char *)
878
env->GetPrimitiveArrayCritical(imgArray, NULL);
879
if (images != NULL) {
880
D3DContext *d3dc = D3DRQ_GetCurrentContext();
881
D3DSDOps *dstOps = D3DRQ_GetCurrentDestination();
882
883
if (usePositions) {
884
unsigned char *positions = (unsigned char *)
885
env->GetPrimitiveArrayCritical(posArray, NULL);
886
if (positions != NULL) {
887
D3DTR_DrawGlyphList(d3dc, dstOps,
888
numGlyphs, usePositions,
889
subPixPos, rgbOrder, lcdContrast,
890
glyphListOrigX, glyphListOrigY,
891
images, positions);
892
env->ReleasePrimitiveArrayCritical(posArray,
893
positions, JNI_ABORT);
894
}
895
} else {
896
D3DTR_DrawGlyphList(d3dc, dstOps,
897
numGlyphs, usePositions,
898
subPixPos, rgbOrder, lcdContrast,
899
glyphListOrigX, glyphListOrigY,
900
images, NULL);
901
}
902
903
// reset current state, and ensure rendering is flushed to dest
904
if (d3dc != NULL) {
905
d3dc->FlushVertexQueue();
906
}
907
908
env->ReleasePrimitiveArrayCritical(imgArray,
909
images, JNI_ABORT);
910
}
911
}
912
913