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 "D3DPipeline.h"
27 #include "jlong.h"
28
29 #include "GraphicsPrimitiveMgr.h"
30 #include "D3DContext.h"
31 #include "D3DSurfaceData.h"
32 #include "D3DBufImgOps.h"
33 #include "D3DPaints.h"
34 #include "D3DRenderQueue.h"
35 #include "D3DShaders.h"
36 #include "D3DTextRenderer.h"
37 #include "D3DPipelineManager.h"
38 #include "D3DGlyphCache.h"
39
40 typedef struct {
41 D3DBLEND src;
42 D3DBLEND dst;
43 } D3DBlendRule;
44
45 /**
46 * This table contains the standard blending rules (or Porter-Duff compositing
47 * factors) used in SetRenderState(), indexed by the rule constants from the
48 * AlphaComposite class.
49 */
50 D3DBlendRule StdBlendRules[] = {
51 { D3DBLEND_ZERO, D3DBLEND_ZERO }, /* 0 - Nothing */
52 { D3DBLEND_ZERO, D3DBLEND_ZERO }, /* 1 - RULE_Clear */
53 { D3DBLEND_ONE, D3DBLEND_ZERO }, /* 2 - RULE_Src */
54 { D3DBLEND_ONE, D3DBLEND_INVSRCALPHA }, /* 3 - RULE_SrcOver */
55 { D3DBLEND_INVDESTALPHA, D3DBLEND_ONE }, /* 4 - RULE_DstOver */
56 { D3DBLEND_DESTALPHA, D3DBLEND_ZERO }, /* 5 - RULE_SrcIn */
57 { D3DBLEND_ZERO, D3DBLEND_SRCALPHA }, /* 6 - RULE_DstIn */
58 { D3DBLEND_INVDESTALPHA, D3DBLEND_ZERO }, /* 7 - RULE_SrcOut */
59 { D3DBLEND_ZERO, D3DBLEND_INVSRCALPHA }, /* 8 - RULE_DstOut */
60 { D3DBLEND_ZERO, D3DBLEND_ONE }, /* 9 - RULE_Dst */
61 { D3DBLEND_DESTALPHA, D3DBLEND_INVSRCALPHA }, /*10 - RULE_SrcAtop */
62 { D3DBLEND_INVDESTALPHA, D3DBLEND_SRCALPHA }, /*11 - RULE_DstAtop */
63 { D3DBLEND_INVDESTALPHA, D3DBLEND_INVSRCALPHA }, /*12 - RULE_AlphaXor*/
64 };
65
66 void
D3DUtils_SetOrthoMatrixOffCenterLH(D3DMATRIX * m,float width,float height)67 D3DUtils_SetOrthoMatrixOffCenterLH(D3DMATRIX *m,
68 float width, float height)
69 {
70 ZeroMemory(m, sizeof(D3DMATRIX));
71 m->_11 = 2.0f/width;
72 m->_22 = -2.0f/height;
73 m->_33 = 0.5f;
74 m->_44 = 1.0f;
75
76 m->_41 = -1.0f;
77 m->_42 = 1.0f;
78 m->_43 = 0.5f;
79 }
80
81 void
D3DUtils_SetIdentityMatrix(D3DMATRIX * m)82 D3DUtils_SetIdentityMatrix(D3DMATRIX *m)
83 {
84 m->_12 = m->_13 = m->_14 = m->_21 = m->_23 = m->_24 = 0.0f;
85 m->_31 = m->_32 = m->_34 = m->_41 = m->_42 = m->_43 = 0.0f;
86 m->_11 = m->_22 = m->_33 = m->_44 = 1.0f;
87 }
88
89 // the following methods are copies of the AffineTransform's class
90 // corresponding methods, with these changes to the indexes:
91 // 00 -> 11
92 // 11 -> 22
93 // 01 -> 21
94 // 10 -> 12
95 // 02 -> 41
96 // 12 -> 42
97
98 void
D3DUtils_2DConcatenateM(D3DMATRIX * m,D3DMATRIX * m1)99 D3DUtils_2DConcatenateM(D3DMATRIX *m, D3DMATRIX *m1)
100 {
101 float M0, M1;
102 float T00, T10, T01, T11;
103 float T02, T12;
104
105 T00 = m1->_11; T01 = m1->_21; T02 = m1->_41;
106 T10 = m1->_12; T11 = m1->_22; T12 = m1->_42;
107
108 M0 = m->_11;
109 M1 = m->_21;
110 m->_11 = T00 * M0 + T10 * M1;
111 m->_21 = T01 * M0 + T11 * M1;
112 m->_41 += T02 * M0 + T12 * M1;
113
114 M0 = m->_12;
115 M1 = m->_22;
116 m->_12 = T00 * M0 + T10 * M1;
117 m->_22 = T01 * M0 + T11 * M1;
118 m->_42 += T02 * M0 + T12 * M1;
119 }
120
121 #ifdef UPDATE_TX
122
123 void
D3DUtils_2DScaleM(D3DMATRIX * m,float sx,float sy)124 D3DUtils_2DScaleM(D3DMATRIX *m, float sx, float sy)
125 {
126 m->_11 *= sx;
127 m->_22 *= sy;
128 }
129
130 void
D3DUtils_2DInvertM(D3DMATRIX * m)131 D3DUtils_2DInvertM(D3DMATRIX *m)
132 {
133 float M11, M21, M41;
134 float M12, M22, M42;
135 float det;
136
137 M11 = m->_11; M21 = m->_21; M41 = m->_41;
138 M12 = m->_12; M22 = m->_22; M42 = m->_42;
139 det = M11 * M22 - M21 * M12;
140 if (fabs(det) <= 0.0000000001f) {
141 memset(m, 0, sizeof(D3DMATRIX));
142 return;
143 }
144 m->_11 = M22 / det;
145 m->_12 = -M12 / det;
146 m->_21 = -M21 / det;
147 m->_22 = M11 / det;
148 m->_41 = (M21 * M42 - M22 * M41) / det;
149 m->_42 = (M12 * M41 - M11 * M42) / det;
150 }
151
152 void
D3DUtils_2DTranslateM(D3DMATRIX * m,float tx,float ty)153 D3DUtils_2DTranslateM(D3DMATRIX *m, float tx, float ty)
154 {
155 m->_41 = tx * m->_11 + ty * m->_21 + m->_41;
156 m->_42 = tx * m->_12 + ty * m->_22 + m->_42;
157 }
158
159 void
D3DUtils_2DTransformXY(D3DMATRIX * m,float * px,float * py)160 D3DUtils_2DTransformXY(D3DMATRIX *m, float *px, float *py)
161 {
162 float x = *px;
163 float y = *py;
164
165 *px = x * m->_11 + y * m->_21 + m->_41;
166 *py = x * m->_12 + y * m->_22 + m->_42;
167 }
168
169 void
D3DUtils_2DInverseTransformXY(D3DMATRIX * m,float * px,float * py)170 D3DUtils_2DInverseTransformXY(D3DMATRIX *m, float *px, float *py)
171 {
172 float x = *px, y = *py;
173
174 x -= m->_41;
175 y -= m->_42;
176
177 float det = m->_11 * m->_22 - m->_21 * m->_12;
178 if (fabs(det) < 0.0000000001f) {
179 *px = 0.0f;
180 *py = 0.0f;
181 } else {
182 *px = (x * m->_22 - y * m->_21) / det;
183 *py = (y * m->_11 - x * m->_12) / det;
184 }
185 }
186
187 #endif // UPDATE_TX
188
189 static void
D3DContext_DisposeShader(jlong programID)190 D3DContext_DisposeShader(jlong programID)
191 {
192 IDirect3DPixelShader9 *shader =
193 (IDirect3DPixelShader9 *)jlong_to_ptr(programID);
194
195 J2dTraceLn(J2D_TRACE_INFO, "D3DContext_DisposeShader");
196
197 SAFE_RELEASE(shader);
198 }
199
200 // static
201 HRESULT
CreateInstance(IDirect3D9 * pd3d9,UINT adapter,D3DContext ** ppCtx)202 D3DContext::CreateInstance(IDirect3D9 *pd3d9, UINT adapter, D3DContext **ppCtx)
203 {
204 HRESULT res;
205 *ppCtx = new D3DContext(pd3d9, adapter);
206 if (FAILED(res = (*ppCtx)->InitContext())) {
207 delete *ppCtx;
208 *ppCtx = NULL;
209 }
210 return res;
211 }
212
D3DContext(IDirect3D9 * pd3d,UINT adapter)213 D3DContext::D3DContext(IDirect3D9 *pd3d, UINT adapter)
214 {
215 J2dTraceLn(J2D_TRACE_INFO, "D3DContext::D3DContext");
216 J2dTraceLn1(J2D_TRACE_VERBOSE, " pd3d=0x%x", pd3d);
217 pd3dObject = pd3d;
218 pd3dDevice = NULL;
219 adapterOrdinal = adapter;
220
221 pResourceMgr = NULL;
222 pMaskCache = NULL;
223 pVCacher = NULL;
224
225 pSyncQuery = NULL;
226 pSyncRTRes = NULL;
227 pStateBlock = NULL;
228
229 D3DC_INIT_SHADER_LIST(convolvePrograms, MAX_CONVOLVE);
230 D3DC_INIT_SHADER_LIST(rescalePrograms, MAX_RESCALE);
231 D3DC_INIT_SHADER_LIST(lookupPrograms, MAX_LOOKUP);
232 D3DC_INIT_SHADER_LIST(basicGradPrograms, 4);
233 D3DC_INIT_SHADER_LIST(linearGradPrograms, 8);
234 D3DC_INIT_SHADER_LIST(radialGradPrograms, 8);
235
236 pLCDGlyphCache= NULL;
237 pGrayscaleGlyphCache= NULL;
238 lcdTextProgram = NULL;
239 aaPgramProgram = NULL;
240
241 contextCaps = CAPS_EMPTY;
242 bBeginScenePending = FALSE;
243
244 ZeroMemory(&devCaps, sizeof(D3DCAPS9));
245 ZeroMemory(&curParams, sizeof(curParams));
246
247 extraAlpha = 1.0f;
248 }
249
ReleaseDefPoolResources()250 void D3DContext::ReleaseDefPoolResources()
251 {
252 J2dTraceLn(J2D_TRACE_INFO, "D3DContext::ReleaseDefPoolResources");
253
254 EndScene();
255
256 contextCaps = CAPS_EMPTY;
257
258 SAFE_RELEASE(pSyncQuery);
259 SAFE_RELEASE(pStateBlock);
260
261 if (pVCacher != NULL) {
262 pVCacher->ReleaseDefPoolResources();
263 }
264 if (pMaskCache != NULL) {
265 pMaskCache->ReleaseDefPoolResources();
266 }
267 if (pLCDGlyphCache != NULL) {
268 pLCDGlyphCache->ReleaseDefPoolResources();
269 }
270 if (pGrayscaleGlyphCache != NULL) {
271 pGrayscaleGlyphCache->ReleaseDefPoolResources();
272 }
273 if (pResourceMgr != NULL) {
274 if (pSyncRTRes != NULL) {
275 pResourceMgr->ReleaseResource(pSyncRTRes);
276 pSyncRTRes = NULL;
277 }
278 pResourceMgr->ReleaseDefPoolResources();
279 }
280 ZeroMemory(lastTexture, sizeof(lastTexture));
281 ZeroMemory(lastTextureColorState, sizeof(lastTextureColorState));
282 }
283
ReleaseContextResources()284 void D3DContext::ReleaseContextResources()
285 {
286 J2dTraceLn1(J2D_TRACE_INFO,
287 "D3DContext::ReleaseContextResources: pd3dDevice = 0x%x",
288 pd3dDevice);
289
290 ReleaseDefPoolResources();
291
292 // dispose shader lists
293 ShaderList_Dispose(&convolvePrograms);
294 ShaderList_Dispose(&rescalePrograms);
295 ShaderList_Dispose(&lookupPrograms);
296 ShaderList_Dispose(&basicGradPrograms);
297 ShaderList_Dispose(&linearGradPrograms);
298 ShaderList_Dispose(&radialGradPrograms);
299
300 SAFE_DELETE(pLCDGlyphCache);
301 SAFE_DELETE(pGrayscaleGlyphCache);
302
303 SAFE_RELEASE(lcdTextProgram);
304 SAFE_RELEASE(aaPgramProgram);
305
306 SAFE_DELETE(pVCacher);
307 SAFE_DELETE(pMaskCache);
308 SAFE_DELETE(pResourceMgr);
309 }
310
~D3DContext()311 D3DContext::~D3DContext() {
312 J2dTraceLn2(J2D_TRACE_INFO,
313 "~D3DContext: pd3dDevice=0x%x, pd3dObject =0x%x",
314 pd3dDevice, pd3dObject);
315 ReleaseContextResources();
316 SAFE_RELEASE(pd3dDevice);
317 }
318
319 HRESULT
InitDevice(IDirect3DDevice9 * pd3dDevice)320 D3DContext::InitDevice(IDirect3DDevice9 *pd3dDevice)
321 {
322 HRESULT res = S_OK;
323
324 pd3dDevice->GetDeviceCaps(&devCaps);
325
326 J2dRlsTraceLn1(J2D_TRACE_INFO,
327 "D3DContext::InitDevice: device %d", adapterOrdinal);
328
329 // disable some of the unneeded and costly d3d functionality
330 pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
331 pd3dDevice->SetRenderState(D3DRS_SPECULARENABLE, FALSE);
332 pd3dDevice->SetRenderState(D3DRS_LIGHTING, FALSE);
333 pd3dDevice->SetRenderState(D3DRS_CLIPPING, FALSE);
334 pd3dDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE);
335 pd3dDevice->SetRenderState(D3DRS_ZWRITEENABLE, D3DZB_FALSE);
336 pd3dDevice->SetRenderState(D3DRS_COLORVERTEX, FALSE);
337 pd3dDevice->SetRenderState(D3DRS_STENCILENABLE, FALSE);
338
339 // set the default texture addressing mode
340 pd3dDevice->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
341 pd3dDevice->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
342
343 // REMIND: check supported filters with
344 // IDirect3D9::CheckDeviceFormat with D3DUSAGE_QUERY_FILTER
345 pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
346 pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT);
347
348 // these states never change
349 pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
350 pd3dDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
351 pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);
352 pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
353 pd3dDevice->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
354 pd3dDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_MODULATE);
355 pd3dDevice->SetTextureStageState(1, D3DTSS_ALPHAARG2, D3DTA_CURRENT);
356 pd3dDevice->SetTextureStageState(1, D3DTSS_COLORARG2, D3DTA_CURRENT);
357
358 // init the array of latest textures
359 ZeroMemory(lastTexture, sizeof(lastTexture));
360 ZeroMemory(lastTextureColorState, sizeof(lastTextureColorState));
361
362 opState = STATE_CHANGE;
363
364 if (pResourceMgr == NULL) {
365 res = D3DResourceManager::CreateInstance(this, &pResourceMgr);
366 } else {
367 res = pResourceMgr->Init(this);
368 }
369 RETURN_STATUS_IF_FAILED(res);
370
371 if (pVCacher == NULL) {
372 res = D3DVertexCacher::CreateInstance(this, &pVCacher);
373 } else {
374 res = pVCacher->Init(this);
375 }
376 RETURN_STATUS_IF_FAILED(res);
377
378 if (pMaskCache == NULL) {
379 res = D3DMaskCache::CreateInstance(this, &pMaskCache);
380 } else{
381 res = pMaskCache->Init(this);
382 }
383 RETURN_STATUS_IF_FAILED(res);
384
385 if (pLCDGlyphCache != NULL) {
386 if (FAILED(res = pLCDGlyphCache->Init(this))) {
387 // we can live without the cache
388 SAFE_DELETE(pLCDGlyphCache);
389 res = S_OK;
390 }
391 }
392
393 if (pGrayscaleGlyphCache != NULL) {
394 if (FAILED(res = pGrayscaleGlyphCache->Init(this))) {
395 // we can live without the cache
396 SAFE_DELETE(pGrayscaleGlyphCache);
397 res = S_OK;
398 }
399 }
400
401 D3DMATRIX tx;
402 D3DUtils_SetIdentityMatrix(&tx);
403 pd3dDevice->SetTransform(D3DTS_WORLD, &tx);
404 bIsIdentityTx = TRUE;
405
406 if (pSyncQuery == NULL) {
407 // this is allowed to fail, do not propagate the error
408 if (FAILED(pd3dDevice->CreateQuery(D3DQUERYTYPE_EVENT, &pSyncQuery))) {
409 J2dRlsTraceLn(J2D_TRACE_WARNING,
410 "D3DContext::InitDevice: sync query not available");
411 pSyncQuery = NULL;
412 }
413 }
414 if (pSyncRTRes == NULL) {
415 D3DFORMAT format;
416 if (FAILED(GetResourceManager()->
417 CreateRTSurface(32, 32, TRUE, TRUE, &format, &pSyncRTRes))) {
418 J2dRlsTraceLn(J2D_TRACE_WARNING,
419 "D3DContext::InitDevice: "
420 "error creating sync surface");
421 }
422 }
423
424 bBeginScenePending = FALSE;
425
426 J2dRlsTraceLn1(J2D_TRACE_INFO,
427 "D3DContext::InitDefice: successfully initialized device %d",
428 adapterOrdinal);
429
430 return res;
431 }
432
433 HRESULT
CheckAndResetDevice()434 D3DContext::CheckAndResetDevice()
435 {
436 HRESULT res = E_FAIL;
437
438 J2dTraceLn(J2D_TRACE_INFO, "D3DContext::CheckAndResetDevice");
439
440 if (pd3dDevice != NULL) {
441 if (FAILED(res = pd3dDevice->TestCooperativeLevel())) {
442 if (res == D3DERR_DEVICELOST) {
443 J2dTraceLn1(J2D_TRACE_VERBOSE, " device %d is still lost",
444 adapterOrdinal);
445 // nothing to be done here, wait for D3DERR_DEVICENOTRESET
446 return res;
447 } else if (res == D3DERR_DEVICENOTRESET) {
448 J2dTraceLn1(J2D_TRACE_VERBOSE, " device %d needs to be reset",
449 adapterOrdinal);
450 res = ResetContext();
451 } else {
452 // some unexpected error
453 DebugPrintD3DError(res, "D3DContext::CheckAndResetDevice: "\
454 "unknown error %x from TestCooperativeLevel");
455 }
456 } else {
457 J2dTraceLn1(J2D_TRACE_VERBOSE, " device %d is not lost",
458 adapterOrdinal);
459 }
460 } else {
461 J2dTraceLn(J2D_TRACE_VERBOSE, " null device");
462 }
463 return res;
464 }
465
466 HRESULT
ResetContext()467 D3DContext::ResetContext()
468 {
469 HRESULT res = E_FAIL;
470
471 J2dRlsTraceLn(J2D_TRACE_INFO, "D3DContext::ResetContext");
472 if (pd3dDevice != NULL) {
473 D3DPRESENT_PARAMETERS newParams;
474
475 newParams = curParams;
476
477 if (newParams.Windowed) {
478 // reset to the current display mode if we're windowed,
479 // otherwise to the display mode we were in when the device
480 // was lost
481 newParams.BackBufferFormat = D3DFMT_UNKNOWN;
482 newParams.FullScreen_RefreshRateInHz = 0;
483 newParams.BackBufferWidth = 0;
484 newParams.BackBufferHeight = 0;
485 }
486 res = ConfigureContext(&newParams);
487 }
488 return res;
489 }
490
491 HRESULT
ConfigureContext(D3DPRESENT_PARAMETERS * pNewParams)492 D3DContext::ConfigureContext(D3DPRESENT_PARAMETERS *pNewParams)
493 {
494 J2dRlsTraceLn1(J2D_TRACE_INFO, "D3DContext::ConfigureContext device %d",
495 adapterOrdinal);
496 HRESULT res = S_OK;
497 D3DFORMAT stencilFormat;
498 HWND focusHWND = D3DPipelineManager::GetInstance()->GetCurrentFocusWindow();
499 D3DDEVTYPE devType = D3DPipelineManager::GetInstance()->GetDeviceType();
500 // this is needed so that we can find the stencil buffer format
501 if (pNewParams->BackBufferFormat == D3DFMT_UNKNOWN) {
502 D3DDISPLAYMODE dm;
503
504 pd3dObject->GetAdapterDisplayMode(adapterOrdinal, &dm);
505 pNewParams->BackBufferFormat = dm.Format;
506 }
507
508 stencilFormat =
509 D3DPipelineManager::GetInstance()->GetMatchingDepthStencilFormat(
510 adapterOrdinal,
511 pNewParams->BackBufferFormat, pNewParams->BackBufferFormat);
512
513 pNewParams->EnableAutoDepthStencil = TRUE;
514 pNewParams->AutoDepthStencilFormat = stencilFormat;
515
516 // do not set device window in the windowed mode, we use additional
517 // swap chains for rendering, the default chain is not used. otherwise
518 // our scratch focus window will be made visible
519 J2dTraceLn1(J2D_TRACE_VERBOSE, " windowed=%d",pNewParams->Windowed);
520 if (pNewParams->Windowed) {
521 pNewParams->hDeviceWindow = (HWND)0;
522 }
523
524 // The focus window may change when we're entering/exiting the full-screen
525 // mode. It may either be set to the default focus window (when there are
526 // no more devices in fs mode), or to fs window for another device
527 // in fs mode. See D3DPipelineManager::GetCurrentFocusWindow.
528 if (pd3dDevice != NULL) {
529 D3DDEVICE_CREATION_PARAMETERS cParams;
530 pd3dDevice->GetCreationParameters(&cParams);
531 if (cParams.hFocusWindow != focusHWND) {
532 J2dTraceLn(J2D_TRACE_VERBOSE,
533 " focus window changed, need to recreate the device");
534
535 // if fs -> windowed, first exit fs, then recreate, otherwise
536 // the screen might be left in a different display mode
537 if (pNewParams->Windowed && !curParams.Windowed) {
538 J2dTraceLn(J2D_TRACE_VERBOSE,
539 " exiting full-screen mode, reset the device");
540 curParams.Windowed = FALSE;
541 ReleaseDefPoolResources();
542 res = pd3dDevice->Reset(&curParams);
543
544 if (FAILED(res)) {
545 DebugPrintD3DError(res, "D3DContext::ConfigureContext: "\
546 "cound not reset the device");
547 }
548 }
549
550 // note that here we should release all device resources, not only
551 // thos in the default pool since the device is released
552 ReleaseContextResources();
553 SAFE_RELEASE(pd3dDevice);
554 }
555 }
556
557 if (pd3dDevice != NULL) {
558 J2dTraceLn(J2D_TRACE_VERBOSE, " resetting the device");
559
560 ReleaseDefPoolResources();
561
562 if (pNewParams->PresentationInterval == D3DPRESENT_INTERVAL_IMMEDIATE &&
563 !IsImmediateIntervalSupported())
564 {
565 pNewParams->PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
566 }
567
568 res = pd3dDevice->Reset(pNewParams);
569 if (FAILED(res)) {
570 DebugPrintD3DError(res,
571 "D3DContext::ConfigureContext: cound not reset the device");
572 return res;
573 }
574 J2dRlsTraceLn1(J2D_TRACE_INFO,
575 "D3DContext::ConfigureContext: successfully reset device: %d",
576 adapterOrdinal);
577 } else {
578 D3DCAPS9 d3dCaps;
579 DWORD dwBehaviorFlags;
580
581 J2dTraceLn(J2D_TRACE_VERBOSE, " creating a new device");
582
583 if (FAILED(res = pd3dObject->GetDeviceCaps(adapterOrdinal,
584 devType, &d3dCaps)))
585 {
586 DebugPrintD3DError(res,
587 "D3DContext::ConfigureContext: failed to get caps");
588 return res;
589 }
590
591 if (pNewParams->PresentationInterval == D3DPRESENT_INTERVAL_IMMEDIATE &&
592 !(d3dCaps.PresentationIntervals & D3DPRESENT_INTERVAL_IMMEDIATE))
593 {
594 pNewParams->PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
595 }
596
597 // not preserving fpu control word could cause issues (4860749)
598 dwBehaviorFlags = D3DCREATE_FPU_PRESERVE;
599
600 J2dRlsTrace(J2D_TRACE_VERBOSE,
601 "[V] dwBehaviorFlags=D3DCREATE_FPU_PRESERVE|");
602 if (d3dCaps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) {
603 J2dRlsTrace(J2D_TRACE_VERBOSE,
604 "D3DCREATE_HARDWARE_VERTEXPROCESSING");
605 dwBehaviorFlags |= D3DCREATE_HARDWARE_VERTEXPROCESSING;
606 } else {
607 J2dRlsTrace(J2D_TRACE_VERBOSE,
608 "D3DCREATE_SOFTWARE_VERTEXPROCESSING");
609 dwBehaviorFlags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING;
610 }
611 // Handling focus changes by ourselves proved to be problematic,
612 // so we're reverting back to D3D handling
613 // dwBehaviorFlags |= D3DCREATE_NOWINDOWCHANGES;
614 J2dRlsTrace(J2D_TRACE_VERBOSE,"\n");
615
616 if (FAILED(res = pd3dObject->CreateDevice(adapterOrdinal, devType,
617 focusHWND,
618 dwBehaviorFlags,
619 pNewParams, &pd3dDevice)))
620 {
621 DebugPrintD3DError(res,
622 "D3DContext::ConfigureContext: error creating d3d device");
623 return res;
624 }
625 J2dRlsTraceLn1(J2D_TRACE_INFO,
626 "D3DContext::ConfigureContext: successfully created device: %d",
627 adapterOrdinal);
628 bIsHWRasterizer = (devType == D3DDEVTYPE_HAL);
629 }
630
631 curParams = *pNewParams;
632 // during the creation of the device d3d modifies this field, we reset
633 // it back to 0
634 curParams.Flags = 0;
635
636 if (FAILED(res = InitDevice(pd3dDevice))) {
637 ReleaseContextResources();
638 return res;
639 }
640
641 res = InitContextCaps();
642
643 return res;
644 }
645
646 HRESULT
InitContext()647 D3DContext::InitContext()
648 {
649 J2dRlsTraceLn1(J2D_TRACE_INFO, "D3DContext::InitContext device %d",
650 adapterOrdinal);
651
652 D3DPRESENT_PARAMETERS params;
653 ZeroMemory(¶ms, sizeof(D3DPRESENT_PARAMETERS));
654
655 params.hDeviceWindow = 0;
656 params.Windowed = TRUE;
657 params.BackBufferCount = 1;
658 params.BackBufferFormat = D3DFMT_UNKNOWN;
659 params.SwapEffect = D3DSWAPEFFECT_DISCARD;
660 params.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
661
662 return ConfigureContext(¶ms);
663 }
664
665 HRESULT
Sync()666 D3DContext::Sync()
667 {
668 HRESULT res = S_OK;
669
670 J2dTraceLn(J2D_TRACE_INFO, "D3DContext::Sync");
671
672 if (pSyncQuery != NULL) {
673 J2dTrace(J2D_TRACE_VERBOSE, " flushing the device queue..");
674 while (S_FALSE ==
675 (res = pSyncQuery->GetData(NULL, 0, D3DGETDATA_FLUSH))) ;
676 J2dTrace(J2D_TRACE_VERBOSE, ".. done\n");
677 }
678 if (pSyncRTRes != NULL) {
679 D3DLOCKED_RECT lr;
680 IDirect3DSurface9 *pSurface = pSyncRTRes->GetSurface();
681 if (SUCCEEDED(pSurface->LockRect(&lr, NULL, D3DLOCK_NOSYSLOCK))) {
682 pSurface->UnlockRect();
683 }
684 }
685 return res;
686 }
687
688 HRESULT
SaveState()689 D3DContext::SaveState()
690 {
691 HRESULT res;
692
693 RETURN_STATUS_IF_NULL(pd3dDevice, S_OK);
694
695 J2dTraceLn(J2D_TRACE_INFO, "D3DContext::SaveState");
696
697 FlushVertexQueue();
698 UpdateState(STATE_CHANGE);
699
700 if (pStateBlock != NULL) {
701 J2dTraceLn(J2D_TRACE_WARNING,
702 "D3DContext::SaveState: existing state block!");
703 SAFE_RELEASE(pStateBlock);
704 }
705
706 if (SUCCEEDED(res =
707 pd3dDevice->CreateStateBlock(D3DSBT_ALL, &pStateBlock)))
708 {
709 J2dTraceLn(J2D_TRACE_VERBOSE, " created state block");
710 } else {
711 J2dTraceLn(J2D_TRACE_WARNING,
712 "D3DContext::SaveState: failed to create state block");
713 }
714 ZeroMemory(lastTexture, sizeof(lastTexture));
715
716 return res;
717 }
718
719 HRESULT
RestoreState()720 D3DContext::RestoreState()
721 {
722 HRESULT res = S_OK;
723
724 J2dTraceLn(J2D_TRACE_INFO, "D3DContext::RestoreState");
725
726 FlushVertexQueue();
727 UpdateState(STATE_CHANGE);
728
729 if (pStateBlock != NULL) {
730 if (SUCCEEDED(res = pStateBlock->Apply())) {
731 J2dTraceLn(J2D_TRACE_VERBOSE, " restored device state");
732 } else {
733 J2dTraceLn(J2D_TRACE_WARNING,
734 "D3DContext::RestoreState: failed to restore state");
735 }
736 SAFE_RELEASE(pStateBlock);
737 } else {
738 J2dTraceLn(J2D_TRACE_WARNING,
739 "D3DContext::RestoreState: empty state block!");
740 }
741 ZeroMemory(lastTexture, sizeof(lastTexture));
742
743 return res;
744 }
745
746 #define POINT_FILTER_CAP (D3DPTFILTERCAPS_MAGFPOINT|D3DPTFILTERCAPS_MINFPOINT)
747 #define LINEAR_FILTER_CAP (D3DPTFILTERCAPS_MAGFLINEAR|D3DPTFILTERCAPS_MINFLINEAR)
748
749 BOOL
IsStretchRectFilteringSupported(D3DTEXTUREFILTERTYPE fType)750 D3DContext::IsStretchRectFilteringSupported(D3DTEXTUREFILTERTYPE fType)
751 {
752 if (fType == D3DTEXF_POINT) {
753 return ((devCaps.StretchRectFilterCaps & POINT_FILTER_CAP) != 0);
754 }
755 if (fType == D3DTEXF_LINEAR) {
756 return ((devCaps.StretchRectFilterCaps & LINEAR_FILTER_CAP) != 0);
757 }
758 return FALSE;
759 }
760
761 BOOL
IsTextureFilteringSupported(D3DTEXTUREFILTERTYPE fType)762 D3DContext::IsTextureFilteringSupported(D3DTEXTUREFILTERTYPE fType)
763 {
764 if (fType == D3DTEXF_POINT) {
765 return ((devCaps.TextureFilterCaps & POINT_FILTER_CAP) != 0);
766 }
767 if (fType == D3DTEXF_LINEAR) {
768 return ((devCaps.TextureFilterCaps & LINEAR_FILTER_CAP) != 0);
769 }
770 return FALSE;
771 }
772
773 BOOL
IsTextureFormatSupported(D3DFORMAT format,DWORD usage)774 D3DContext::IsTextureFormatSupported(D3DFORMAT format, DWORD usage)
775 {
776 HRESULT hr = pd3dObject->CheckDeviceFormat(adapterOrdinal,
777 devCaps.DeviceType,
778 curParams.BackBufferFormat,
779 usage,
780 D3DRTYPE_TEXTURE,
781 format);
782 return SUCCEEDED( hr );
783 }
784
785 BOOL
IsDepthStencilBufferOk(D3DSURFACE_DESC * pTargetDesc)786 D3DContext::IsDepthStencilBufferOk(D3DSURFACE_DESC *pTargetDesc)
787 {
788 IDirect3DSurface9 *pStencil;
789 J2dTraceLn(J2D_TRACE_INFO, "D3DContext::IsDepthStencilBufferOk");
790
791 if (SUCCEEDED(pd3dDevice->GetDepthStencilSurface(&pStencil))) {
792 D3DSURFACE_DESC descStencil;
793 pStencil->GetDesc(&descStencil);
794 pStencil->Release();
795
796 D3DDISPLAYMODE dm;
797 return
798 (SUCCEEDED(pd3dDevice->GetDisplayMode(0, &dm)) &&
799 pTargetDesc->Width <= descStencil.Width &&
800 pTargetDesc->Height <= descStencil.Height &&
801 SUCCEEDED(pd3dObject->CheckDepthStencilMatch(
802 adapterOrdinal,
803 devCaps.DeviceType,
804 dm.Format, pTargetDesc->Format,
805 descStencil.Format)));
806 }
807 J2dTraceLn(J2D_TRACE_VERBOSE,
808 " current stencil buffer is not compatible with new Render Target");
809
810 return false;
811 }
812
813
814
815 HRESULT
InitDepthStencilBuffer(D3DSURFACE_DESC * pTargetDesc)816 D3DContext::InitDepthStencilBuffer(D3DSURFACE_DESC *pTargetDesc)
817 {
818 HRESULT res;
819 IDirect3DSurface9 *pBB;
820 D3DDISPLAYMODE dm;
821
822 J2dTraceLn(J2D_TRACE_INFO, "D3DContext::InitDepthStencilBuffer");
823
824 if (FAILED(res = pd3dDevice->GetDisplayMode(0, &dm))) {
825 return res;
826 }
827
828 D3DFORMAT newFormat =
829 D3DPipelineManager::GetInstance()->GetMatchingDepthStencilFormat(
830 adapterOrdinal, dm.Format, pTargetDesc->Format);
831
832 res = pd3dDevice->CreateDepthStencilSurface(
833 pTargetDesc->Width, pTargetDesc->Height,
834 newFormat, D3DMULTISAMPLE_NONE, 0, false, &pBB, 0);
835 if (SUCCEEDED(res)) {
836 res = pd3dDevice->SetDepthStencilSurface(pBB);
837 pBB->Release();
838 }
839
840 return res;
841 }
842
843
844 HRESULT
SetRenderTarget(IDirect3DSurface9 * pSurface)845 D3DContext::SetRenderTarget(IDirect3DSurface9 *pSurface)
846 {
847 static D3DMATRIX tx;
848 HRESULT res;
849 D3DSURFACE_DESC descNew;
850 IDirect3DSurface9 *pCurrentTarget;
851
852 J2dTraceLn1(J2D_TRACE_INFO,
853 "D3DContext::SetRenderTarget: pSurface=0x%x",
854 pSurface);
855
856 RETURN_STATUS_IF_NULL(pd3dDevice, E_FAIL);
857 RETURN_STATUS_IF_NULL(pSurface, E_FAIL);
858
859 pSurface->GetDesc(&descNew);
860
861 if (SUCCEEDED(res = pd3dDevice->GetRenderTarget(0, &pCurrentTarget))) {
862 if (pCurrentTarget != pSurface) {
863 FlushVertexQueue();
864 if (FAILED(res = pd3dDevice->SetRenderTarget(0, pSurface))) {
865 DebugPrintD3DError(res, "D3DContext::SetRenderTarget: "\
866 "error setting render target");
867 SAFE_RELEASE(pCurrentTarget);
868 return res;
869 }
870
871 if (!IsDepthStencilBufferOk(&descNew)) {
872 if (FAILED(res = InitDepthStencilBuffer(&descNew))) {
873 SAFE_RELEASE(pCurrentTarget);
874 return res;
875 }
876 }
877 }
878 SAFE_RELEASE(pCurrentTarget);
879 }
880 // we set the transform even if the render target didn't change;
881 // this is because in some cases (fs mode) we use the default SwapChain of
882 // the device, and its render target will be the same as the device's, and
883 // we have to set the matrix correctly. This shouldn't be a performance
884 // issue as render target changes are relatively rare
885 D3DUtils_SetOrthoMatrixOffCenterLH(&tx,
886 (float)descNew.Width,
887 (float)descNew.Height);
888 pd3dDevice->SetTransform(D3DTS_PROJECTION, &tx);
889
890 J2dTraceLn1(J2D_TRACE_VERBOSE, " current render target=0x%x", pSurface);
891 return res;
892 }
893
894 HRESULT
ResetTransform()895 D3DContext::ResetTransform()
896 {
897 HRESULT res = S_OK;
898 D3DMATRIX tx;
899
900 J2dTraceLn(J2D_TRACE_INFO, "D3DContext::ResetTransform");
901 if (pd3dDevice == NULL) {
902 return E_FAIL;
903 }
904
905 // no need for state change, just flush the queue
906 FlushVertexQueue();
907
908 D3DUtils_SetIdentityMatrix(&tx);
909 if (FAILED(res = pd3dDevice->SetTransform(D3DTS_WORLD, &tx))) {
910 DebugPrintD3DError(res, "D3DContext::SetTransform failed");
911 }
912 bIsIdentityTx = TRUE;
913 return res;
914 }
915
916 HRESULT
SetTransform(jdouble m00,jdouble m10,jdouble m01,jdouble m11,jdouble m02,jdouble m12)917 D3DContext::SetTransform(jdouble m00, jdouble m10,
918 jdouble m01, jdouble m11,
919 jdouble m02, jdouble m12)
920 {
921 HRESULT res = S_OK;
922 D3DMATRIX tx, tx1;
923
924 J2dTraceLn(J2D_TRACE_INFO, "D3DContext::SetTransform");
925 if (pd3dDevice == NULL) {
926 return E_FAIL;
927 }
928
929 // no need for state change, just flush the queue
930 FlushVertexQueue();
931
932 // In order to correctly map texels to pixels we need to
933 // adjust geometry by -0.5f in the transformed space.
934 // In order to do that we first create a translated matrix
935 // and then concatenate it with the world transform.
936 //
937 // Note that we only use non-id transform with DrawTexture,
938 // the rest is rendered pre-transformed.
939 //
940 // The identity transform for textures is handled in
941 // D3DVertexCacher::DrawTexture() because shifting by -0.5 for id
942 // transform breaks lines rendering.
943
944 ZeroMemory(&tx1, sizeof(D3DMATRIX));
945
946 tx1._11 = (float)m00;
947 tx1._12 = (float)m10;
948 tx1._21 = (float)m01;
949 tx1._22 = (float)m11;
950 tx1._41 = (float)m02;
951 tx1._42 = (float)m12;
952
953 tx1._33 = 1.0f;
954 tx1._44 = 1.0f;
955
956 D3DUtils_SetIdentityMatrix(&tx);
957 tx._41 = -0.5f;
958 tx._42 = -0.5f;
959 D3DUtils_2DConcatenateM(&tx, &tx1);
960
961 J2dTraceLn4(J2D_TRACE_VERBOSE,
962 " %5f %5f %5f %5f", tx._11, tx._12, tx._13, tx._14);
963 J2dTraceLn4(J2D_TRACE_VERBOSE,
964 " %5f %5f %5f %5f", tx._21, tx._22, tx._23, tx._24);
965 J2dTraceLn4(J2D_TRACE_VERBOSE,
966 " %5f %5f %5f %5f", tx._31, tx._32, tx._33, tx._34);
967 J2dTraceLn4(J2D_TRACE_VERBOSE,
968 " %5f %5f %5f %5f", tx._41, tx._42, tx._43, tx._44);
969 if (FAILED(res = pd3dDevice->SetTransform(D3DTS_WORLD, &tx))) {
970 DebugPrintD3DError(res, "D3DContext::SetTransform failed");
971 }
972 bIsIdentityTx = FALSE;
973
974 return res;
975 }
976
977 HRESULT
SetRectClip(int x1,int y1,int x2,int y2)978 D3DContext::SetRectClip(int x1, int y1, int x2, int y2)
979 {
980 HRESULT res = S_OK;
981 D3DSURFACE_DESC desc;
982 IDirect3DSurface9 *pCurrentTarget;
983
984 J2dTraceLn(J2D_TRACE_INFO, "D3DContext::SetRectClip");
985 J2dTraceLn4(J2D_TRACE_VERBOSE,
986 " x1=%-4d y1=%-4d x2=%-4d y2=%-4d",
987 x1, y1, x2, y2);
988
989 RETURN_STATUS_IF_NULL(pd3dDevice, E_FAIL);
990
991 // no need for state change, just flush the queue
992 FlushVertexQueue();
993
994 pd3dDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE);
995
996 res = pd3dDevice->GetRenderTarget(0, &pCurrentTarget);
997 RETURN_STATUS_IF_FAILED(res);
998
999 pCurrentTarget->GetDesc(&desc);
1000 SAFE_RELEASE(pCurrentTarget);
1001
1002 if (x1 <= 0 && y1 <= 0 &&
1003 (UINT)x2 >= desc.Width && (UINT)y2 >= desc.Height)
1004 {
1005 J2dTraceLn(J2D_TRACE_VERBOSE,
1006 " disabling clip (== render target dimensions)");
1007 return pd3dDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE);
1008 }
1009
1010 // clip to the dimensions of the target surface, otherwise
1011 // SetScissorRect will fail
1012 if (x1 < 0) x1 = 0;
1013 if (y1 < 0) y1 = 0;
1014 if ((UINT)x2 > desc.Width) x2 = desc.Width;
1015 if ((UINT)y2 > desc.Height) y2 = desc.Height;
1016 if (x1 > x2) x2 = x1 = 0;
1017 if (y1 > y2) y2 = y1 = 0;
1018 RECT newRect = { x1, y1, x2, y2 };
1019 if (SUCCEEDED(res = pd3dDevice->SetScissorRect(&newRect))) {
1020 res = pd3dDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, TRUE);
1021 } else {
1022 DebugPrintD3DError(res, "Error setting scissor rect");
1023 J2dRlsTraceLn4(J2D_TRACE_ERROR,
1024 " x1=%-4d y1=%-4d x2=%-4d y2=%-4d",
1025 x1, y1, x2, y2);
1026 }
1027
1028 return res;
1029 }
1030
1031 HRESULT
ResetClip()1032 D3DContext::ResetClip()
1033 {
1034 J2dTraceLn(J2D_TRACE_INFO, "D3DContext::ResetClip");
1035 // no need for state change, just flush the queue
1036 FlushVertexQueue();
1037 pd3dDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE);
1038 return pd3dDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE);
1039 }
1040
1041 ClipType
GetClipType()1042 D3DContext::GetClipType()
1043 {
1044 // REMIND: this method could be optimized: we could keep the
1045 // clip state around when re/setting the clip instead of asking
1046 // every time.
1047 DWORD zEnabled = 0;
1048 DWORD stEnabled = 0;
1049
1050 J2dTraceLn(J2D_TRACE_INFO, "D3DContext::GetClipType");
1051 pd3dDevice->GetRenderState(D3DRS_SCISSORTESTENABLE, &stEnabled);
1052 if (stEnabled) {
1053 return CLIP_RECT;
1054 }
1055 pd3dDevice->GetRenderState(D3DRS_ZENABLE, &zEnabled);
1056 if (zEnabled) {
1057 return CLIP_SHAPE;
1058 }
1059 return CLIP_NONE;
1060 }
1061
1062
1063 /**
1064 * This method assumes that ::SetRenderTarget has already
1065 * been called. SetRenderTarget creates and attaches a
1066 * depth buffer to the target surface prior to setting it
1067 * as target surface to the device.
1068 */
1069 DWORD dwAlphaSt, dwSrcBlendSt, dwDestBlendSt;
1070 D3DMATRIX tx, idTx;
1071
1072 HRESULT
BeginShapeClip()1073 D3DContext::BeginShapeClip()
1074 {
1075 HRESULT res = S_OK;
1076 J2dTraceLn(J2D_TRACE_INFO, "D3DContext::BeginShapeClip");
1077
1078 UpdateState(STATE_CHANGE);
1079
1080 pd3dDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE);
1081
1082 // save alpha blending state
1083 pd3dDevice->GetRenderState(D3DRS_ALPHABLENDENABLE, &dwAlphaSt);
1084 pd3dDevice->GetRenderState(D3DRS_SRCBLEND, &dwSrcBlendSt);
1085 pd3dDevice->GetRenderState(D3DRS_DESTBLEND, &dwDestBlendSt);
1086
1087 pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
1088 pd3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ZERO);
1089 pd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE);
1090
1091 pd3dDevice->GetTransform(D3DTS_WORLD, &tx);
1092 D3DUtils_SetIdentityMatrix(&idTx);
1093 // translate the clip spans by 1.0f in z direction so that the
1094 // clip spans are rendered to the z buffer
1095 idTx._43 = 1.0f;
1096 pd3dDevice->SetTransform(D3DTS_WORLD, &idTx);
1097
1098 // The depth buffer is first cleared with zeroes, which is the farthest
1099 // plane from the viewer (our projection matrix is an inversed orthogonal
1100 // transform).
1101 // To set the clip we'll render the clip spans with Z coordinates of 1.0f
1102 // (the closest to the viewer). Since all rendering primitives
1103 // have their vertices' Z coordinate set to 0.0, they will effectively be
1104 // clipped because the Z depth test for them will fail (vertex with 1.0
1105 // depth is closer than the one with 0.0f)
1106 pd3dDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE);
1107 pd3dDevice->SetRenderState(D3DRS_ZWRITEENABLE, TRUE);
1108 pd3dDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_ALWAYS);
1109 pd3dDevice->Clear(0, NULL, D3DCLEAR_ZBUFFER, 0L, 0.0f, 0x0L);
1110
1111 //res = BeginScene(STATE_SHAPE_CLIPOP);
1112
1113 return res;
1114 }
1115
1116 HRESULT
EndShapeClip()1117 D3DContext::EndShapeClip()
1118 {
1119 HRESULT res;
1120
1121 // no need for state change, just flush the queue
1122 res = FlushVertexQueue();
1123
1124 // restore alpha blending state
1125 pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, dwAlphaSt);
1126 pd3dDevice->SetRenderState(D3DRS_SRCBLEND, dwSrcBlendSt);
1127 pd3dDevice->SetRenderState(D3DRS_DESTBLEND, dwDestBlendSt);
1128
1129 // resore the transform
1130 pd3dDevice->SetTransform(D3DTS_WORLD, &tx);
1131
1132 // Enable the depth buffer.
1133 // We disable further updates to the depth buffer: it should only
1134 // be updated in SetClip method.
1135 pd3dDevice->SetRenderState(D3DRS_ZWRITEENABLE, FALSE);
1136 pd3dDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_LESS);
1137
1138 return res;
1139 }
1140
1141 HRESULT
UploadTileToTexture(D3DResource * pTextureRes,void * pixels,jint dstx,jint dsty,jint srcx,jint srcy,jint srcWidth,jint srcHeight,jint srcStride,TileFormat srcFormat,jint * pPixelsTouchedL,jint * pPixelsTouchedR)1142 D3DContext::UploadTileToTexture(D3DResource *pTextureRes, void *pixels,
1143 jint dstx, jint dsty,
1144 jint srcx, jint srcy,
1145 jint srcWidth, jint srcHeight,
1146 jint srcStride,
1147 TileFormat srcFormat,
1148 jint *pPixelsTouchedL,
1149 jint* pPixelsTouchedR)
1150 {
1151 #ifndef PtrAddBytes
1152 #define PtrAddBytes(p, b) ((void *) (((intptr_t) (p)) + (b)))
1153 #define PtrCoord(p, x, xinc, y, yinc) PtrAddBytes(p, \
1154 ((ptrdiff_t)(y))*(yinc) + \
1155 ((ptrdiff_t)(x))*(xinc))
1156 #endif // PtrAddBytes
1157
1158 HRESULT res = S_OK;
1159 IDirect3DTexture9 *pTexture = pTextureRes->GetTexture();
1160 D3DSURFACE_DESC *pDesc = pTextureRes->GetDesc();
1161 RECT r = { dstx, dsty, dstx+srcWidth, dsty+srcHeight };
1162 RECT *pR = &r;
1163 D3DLOCKED_RECT lockedRect;
1164 DWORD dwLockFlags = D3DLOCK_NOSYSLOCK;
1165 // these are only counted for LCD glyph uploads
1166 jint pixelsTouchedL = 0, pixelsTouchedR = 0;
1167
1168 J2dTraceLn(J2D_TRACE_INFO, "D3DContext::UploadTileToTexture");
1169 J2dTraceLn4(J2D_TRACE_VERBOSE,
1170 " rect={%-4d, %-4d, %-4d, %-4d}",
1171 r.left, r.top, r.right, r.bottom);
1172
1173 if (pDesc->Usage == D3DUSAGE_DYNAMIC) {
1174 // it is safe to lock with discard because we don't care about the
1175 // contents of dynamic textures and dstx,dsty for this case is
1176 // always 0,0 because we are uploading into a tile texture
1177 dwLockFlags |= D3DLOCK_DISCARD;
1178 pR = NULL;
1179 }
1180
1181 if (FAILED(res = pTexture->LockRect(0, &lockedRect, pR, dwLockFlags))) {
1182 DebugPrintD3DError(res,
1183 "D3DContext::UploadImageToTexture: could "\
1184 "not lock texture");
1185 return res;
1186 }
1187
1188 if (srcFormat == TILEFMT_1BYTE_ALPHA) {
1189 // either a MaskFill tile, or a grayscale glyph
1190 if (pDesc->Format == D3DFMT_A8) {
1191 void *pSrcPixels = PtrCoord(pixels, srcx, 1, srcy, srcStride);
1192 void *pDstPixels = lockedRect.pBits;
1193 do {
1194 memcpy(pDstPixels, pSrcPixels, srcWidth);
1195 pSrcPixels = PtrAddBytes(pSrcPixels, srcStride);
1196 pDstPixels = PtrAddBytes(pDstPixels, lockedRect.Pitch);
1197 } while (--srcHeight > 0);
1198 }
1199 else if (pDesc->Format == D3DFMT_A8R8G8B8) {
1200 jubyte *pSrcPixels = (jubyte*)
1201 PtrCoord(pixels, srcx, 1, srcy, srcStride);
1202 jint *pDstPixels = (jint*)lockedRect.pBits;
1203 for (int yy = 0; yy < srcHeight; yy++) {
1204 for (int xx = 0; xx < srcWidth; xx++) {
1205 // only need to set the alpha channel (the D3D texture
1206 // state will be setup in this case to replicate the
1207 // alpha channel as needed)
1208 pDstPixels[xx] = pSrcPixels[xx] << 24;
1209 }
1210 pSrcPixels = (jubyte*)PtrAddBytes(pSrcPixels, srcStride);
1211 pDstPixels = (jint*)PtrAddBytes(pDstPixels, lockedRect.Pitch);
1212 }
1213 }
1214 } else if (srcFormat == TILEFMT_3BYTE_RGB) {
1215 // LCD glyph with RGB order
1216 if (pDesc->Format == D3DFMT_R8G8B8) {
1217 jubyte *pSrcPixels = (jubyte*)
1218 PtrCoord(pixels, srcx, 3, srcy, srcStride);
1219 jubyte *pDstPixels = (jubyte*)lockedRect.pBits;
1220 for (int yy = 0; yy < srcHeight; yy++) {
1221 for (int xx = 0; xx < srcWidth*3; xx+=3) {
1222 // alpha channel is ignored in this case
1223 // (note that this is backwards from what one might
1224 // expect; it appears that D3DFMT_R8G8B8 is actually
1225 // laid out in BGR order in memory)
1226 pDstPixels[xx+0] = pSrcPixels[xx+2];
1227 pDstPixels[xx+1] = pSrcPixels[xx+1];
1228 pDstPixels[xx+2] = pSrcPixels[xx+0];
1229 }
1230 pixelsTouchedL +=
1231 (pDstPixels[0+0]|pDstPixels[0+1]|pDstPixels[0+2]) ? 1 : 0;
1232 jint i = 3*(srcWidth-1);
1233 pixelsTouchedR +=
1234 (pDstPixels[i+0]|pDstPixels[i+1]|pDstPixels[i+2]) ? 1 : 0;
1235
1236 pSrcPixels = (jubyte*)PtrAddBytes(pSrcPixels, srcStride);
1237 pDstPixels = (jubyte*)PtrAddBytes(pDstPixels, lockedRect.Pitch);
1238 }
1239 }
1240 else if (pDesc->Format == D3DFMT_A8R8G8B8) {
1241 jubyte *pSrcPixels = (jubyte*)
1242 PtrCoord(pixels, srcx, 3, srcy, srcStride);
1243 jint *pDstPixels = (jint*)lockedRect.pBits;
1244 for (int yy = 0; yy < srcHeight; yy++) {
1245 for (int dx = 0, sx = 0; dx < srcWidth; dx++, sx+=3) {
1246 // alpha channel is ignored in this case
1247 jubyte r = pSrcPixels[sx+0];
1248 jubyte g = pSrcPixels[sx+1];
1249 jubyte b = pSrcPixels[sx+2];
1250 pDstPixels[dx] = (r << 16) | (g << 8) | (b);
1251 }
1252 pixelsTouchedL += (pDstPixels[0] ? 1 : 0);
1253 pixelsTouchedR += (pDstPixels[srcWidth-1] ? 1 : 0);
1254
1255 pSrcPixels = (jubyte*)PtrAddBytes(pSrcPixels, srcStride);
1256 pDstPixels = (jint*)PtrAddBytes(pDstPixels, lockedRect.Pitch);
1257 }
1258 }
1259 } else if (srcFormat == TILEFMT_3BYTE_BGR) {
1260 // LCD glyph with BGR order
1261 if (pDesc->Format == D3DFMT_R8G8B8) {
1262 void *pSrcPixels = PtrCoord(pixels, srcx, 3, srcy, srcStride);
1263 void *pDstPixels = lockedRect.pBits;
1264 jubyte *pbDst;
1265 do {
1266 // alpha channel is ignored in this case
1267 // (note that this is backwards from what one might
1268 // expect; it appears that D3DFMT_R8G8B8 is actually
1269 // laid out in BGR order in memory)
1270 memcpy(pDstPixels, pSrcPixels, srcWidth * 3);
1271
1272 pbDst = (jubyte*)pDstPixels;
1273 pixelsTouchedL +=(pbDst[0+0]|pbDst[0+1]|pbDst[0+2]) ? 1 : 0;
1274 jint i = 3*(srcWidth-1);
1275 pixelsTouchedR +=(pbDst[i+0]|pbDst[i+1]|pbDst[i+2]) ? 1 : 0;
1276
1277 pSrcPixels = PtrAddBytes(pSrcPixels, srcStride);
1278 pDstPixels = PtrAddBytes(pDstPixels, lockedRect.Pitch);
1279 } while (--srcHeight > 0);
1280 }
1281 else if (pDesc->Format == D3DFMT_A8R8G8B8) {
1282 jubyte *pSrcPixels = (jubyte*)
1283 PtrCoord(pixels, srcx, 3, srcy, srcStride);
1284 jint *pDstPixels = (jint*)lockedRect.pBits;
1285 for (int yy = 0; yy < srcHeight; yy++) {
1286 for (int dx = 0, sx = 0; dx < srcWidth; dx++, sx+=3) {
1287 // alpha channel is ignored in this case
1288 jubyte b = pSrcPixels[sx+0];
1289 jubyte g = pSrcPixels[sx+1];
1290 jubyte r = pSrcPixels[sx+2];
1291 pDstPixels[dx] = (r << 16) | (g << 8) | (b);
1292 }
1293 pixelsTouchedL += (pDstPixels[0] ? 1 : 0);
1294 pixelsTouchedR += (pDstPixels[srcWidth-1] ? 1 : 0);
1295
1296 pSrcPixels = (jubyte*)PtrAddBytes(pSrcPixels, srcStride);
1297 pDstPixels = (jint*)PtrAddBytes(pDstPixels, lockedRect.Pitch);
1298 }
1299 }
1300 } else if (srcFormat == TILEFMT_4BYTE_ARGB_PRE) {
1301 // MaskBlit tile
1302 if (pDesc->Format == D3DFMT_A8R8G8B8) {
1303 void *pSrcPixels = PtrCoord(pixels, srcx, 4, srcy, srcStride);
1304 void *pDstPixels = lockedRect.pBits;
1305 do {
1306 memcpy(pDstPixels, pSrcPixels, srcWidth * 4);
1307 pSrcPixels = PtrAddBytes(pSrcPixels, srcStride);
1308 pDstPixels = PtrAddBytes(pDstPixels, lockedRect.Pitch);
1309 } while (--srcHeight > 0);
1310 }
1311 } else {
1312 // should not happen, no-op just in case...
1313 }
1314
1315 if (pPixelsTouchedL) {
1316 *pPixelsTouchedL = pixelsTouchedL;
1317 }
1318 if (pPixelsTouchedR) {
1319 *pPixelsTouchedR = pixelsTouchedR;
1320 }
1321
1322 return pTexture->UnlockRect(0);
1323 }
1324
1325 HRESULT
InitLCDGlyphCache()1326 D3DContext::InitLCDGlyphCache()
1327 {
1328 if (pLCDGlyphCache == NULL) {
1329 return D3DGlyphCache::CreateInstance(this, CACHE_LCD, &pLCDGlyphCache);
1330 }
1331 return S_OK;
1332 }
1333
1334 HRESULT
InitGrayscaleGlyphCache()1335 D3DContext::InitGrayscaleGlyphCache()
1336 {
1337 if (pGrayscaleGlyphCache == NULL) {
1338 return D3DGlyphCache::CreateInstance(this, CACHE_GRAY,
1339 &pGrayscaleGlyphCache);
1340 }
1341 return S_OK;
1342 }
1343
1344 HRESULT
ResetComposite()1345 D3DContext::ResetComposite()
1346 {
1347 J2dTraceLn(J2D_TRACE_INFO, "D3DContext::ResetComposite");
1348
1349 RETURN_STATUS_IF_NULL(pd3dDevice, E_FAIL);
1350
1351 HRESULT res = UpdateState(STATE_CHANGE);
1352 pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
1353 extraAlpha = 1.0f;
1354 return res;
1355 }
1356
1357 HRESULT
SetAlphaComposite(jint rule,jfloat ea,jint flags)1358 D3DContext::SetAlphaComposite(jint rule, jfloat ea, jint flags)
1359 {
1360 HRESULT res;
1361 J2dTraceLn3(J2D_TRACE_INFO,
1362 "D3DContext::SetAlphaComposite: rule=%-1d ea=%f flags=%d",
1363 rule, ea, flags);
1364
1365 RETURN_STATUS_IF_NULL(pd3dDevice, E_FAIL);
1366
1367 res = UpdateState(STATE_CHANGE);
1368
1369 // we can safely disable blending when:
1370 // - comp is SrcNoEa or SrcOverNoEa, and
1371 // - the source is opaque
1372 // (turning off blending can have a large positive impact on performance)
1373 if ((rule == RULE_Src || rule == RULE_SrcOver) &&
1374 (ea == 1.0f) &&
1375 (flags & D3DC_SRC_IS_OPAQUE))
1376 {
1377 J2dTraceLn1(J2D_TRACE_VERBOSE,
1378 " disabling alpha comp rule=%-1d ea=1.0 src=opq)", rule);
1379 pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
1380 } else {
1381 J2dTraceLn2(J2D_TRACE_VERBOSE,
1382 " enabling alpha comp (rule=%-1d ea=%f)", rule, ea);
1383 pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
1384
1385 pd3dDevice->SetRenderState(D3DRS_SRCBLEND,
1386 StdBlendRules[rule].src);
1387 pd3dDevice->SetRenderState(D3DRS_DESTBLEND,
1388 StdBlendRules[rule].dst);
1389 }
1390
1391 extraAlpha = ea;
1392 return res;
1393 }
1394
1395 #ifdef UPDATE_TX
1396
1397 // Note: this method of adjusting pixel to texel mapping proved to be
1398 // difficult to perfect. The current variation works great for id,
1399 // scale (including all kinds of flips) transforms, but not still not
1400 // for generic transforms.
1401 //
1402 // Since we currently only do DrawTexture with non-id transform we instead
1403 // adjust the geometry (see D3DVertexCacher::DrawTexture(), SetTransform())
1404 //
1405 // In order to enable this code path UpdateTextureTransforms needs to
1406 // be called in SetTexture(), SetTransform() and ResetTranform().
1407 HRESULT
UpdateTextureTransforms(DWORD dwSamplerToUpdate)1408 D3DContext::UpdateTextureTransforms(DWORD dwSamplerToUpdate)
1409 {
1410 HRESULT res = S_OK;
1411 DWORD dwSampler, dwMaxSampler;
1412
1413 if (dwSamplerToUpdate == -1) {
1414 // update all used samplers, dwMaxSampler will be set to max
1415 dwSampler = 0;
1416 dwSampler = MAX_USED_TEXTURE_SAMPLER;
1417 J2dTraceLn(J2D_TRACE_INFO, "D3DContext::UpdateTextureTransforms: "\
1418 "updating all samplers");
1419 } else {
1420 // update only given sampler, dwMaxSampler will be set to it as well
1421 dwSampler = dwSamplerToUpdate;
1422 dwMaxSampler = dwSamplerToUpdate;
1423 J2dTraceLn1(J2D_TRACE_INFO, "D3DContext::UpdateTextureTransforms: "\
1424 "updating sampler %d", dwSampler);
1425 }
1426
1427 do {
1428 D3DTRANSFORMSTATETYPE state =
1429 (D3DTRANSFORMSTATETYPE)(D3DTS_TEXTURE0 + dwSampler);
1430 IDirect3DTexture9 *pTexture = lastTexture[dwSampler];
1431
1432 if (pTexture != NULL) {
1433 D3DMATRIX mt, tx;
1434 D3DSURFACE_DESC texDesc;
1435
1436 pd3dDevice->GetTransform(D3DTS_WORLD, &tx);
1437 J2dTraceLn4(10,
1438 " %5f %5f %5f %5f", tx._11, tx._12, tx._13, tx._14);
1439 J2dTraceLn4(10,
1440 " %5f %5f %5f %5f", tx._21, tx._22, tx._23, tx._24);
1441 J2dTraceLn4(10,
1442 " %5f %5f %5f %5f", tx._31, tx._32, tx._33, tx._34);
1443 J2dTraceLn4(10,
1444 " %5f %5f %5f %5f", tx._41, tx._42, tx._43, tx._44);
1445
1446 // this formula works for scales and flips
1447 if (tx._11 == 0.0f) {
1448 tx._11 = tx._12;
1449 }
1450 if (tx._22 == 0.0f) {
1451 tx._22 = tx._21;
1452 }
1453
1454 pTexture->GetLevelDesc(0, &texDesc);
1455
1456 // shift by .5 texel, but take into account
1457 // the scale factor of the device transform
1458
1459 // REMIND: this approach is not entirely correct,
1460 // as it only takes into account the scale of the device
1461 // transform.
1462 mt._31 = (1.0f / (2.0f * texDesc.Width * tx._11));
1463 mt._32 = (1.0f / (2.0f * texDesc.Height * tx._22));
1464 J2dTraceLn2(J2D_TRACE_VERBOSE, " offsets: tx=%f ty=%f",
1465 mt._31, mt._32);
1466
1467 pd3dDevice->SetTextureStageState(dwSampler,
1468 D3DTSS_TEXTURETRANSFORMFLAGS,
1469 D3DTTFF_COUNT2);
1470 res = pd3dDevice->SetTransform(state, &mt);
1471 } else {
1472 res = pd3dDevice->SetTextureStageState(dwSampler,
1473 D3DTSS_TEXTURETRANSFORMFLAGS,
1474 D3DTTFF_DISABLE);
1475 }
1476 dwSampler++;
1477 } while (dwSampler <= dwMaxSampler);
1478
1479 return res;
1480 }
1481 #endif // UPDATE_TX
1482
1483 /**
1484 * We go into the pains of maintaining the list of set textures
1485 * instead of just calling GetTexture() and comparing the old one
1486 * with the new one because it's actually noticeably slower to call
1487 * GetTexture() (note that we'd have to then call Release() on the
1488 * texture since GetTexture() increases texture's ref. count).
1489 */
1490 HRESULT
SetTexture(IDirect3DTexture9 * pTexture,DWORD dwSampler)1491 D3DContext::SetTexture(IDirect3DTexture9 *pTexture, DWORD dwSampler)
1492 {
1493 HRESULT res = S_OK;
1494 J2dTraceLn(J2D_TRACE_INFO, "D3DContext::SetTexture");
1495
1496 if (dwSampler < 0 || dwSampler > MAX_USED_TEXTURE_SAMPLER) {
1497 J2dTraceLn1(J2D_TRACE_ERROR,
1498 "D3DContext::SetTexture: incorrect sampler: %d", dwSampler);
1499 return E_FAIL;
1500 }
1501 if (lastTexture[dwSampler] != pTexture) {
1502 if (FAILED(res = FlushVertexQueue())) {
1503 return res;
1504 }
1505 J2dTraceLn2(J2D_TRACE_VERBOSE,
1506 " new texture=0x%x on sampler %d", pTexture, dwSampler);
1507 res = pd3dDevice->SetTexture(dwSampler, pTexture);
1508 if (SUCCEEDED(res)) {
1509 lastTexture[dwSampler] = pTexture;
1510 // REMIND: see comment at UpdateTextureTransforms
1511 #ifdef UPDATE_TX
1512 res = UpdateTextureTransforms(dwSampler);
1513 #endif
1514 } else {
1515 lastTexture[dwSampler] = NULL;
1516 }
1517 }
1518 return res;
1519 }
1520
1521 HRESULT
UpdateTextureColorState(DWORD dwState,DWORD dwSampler)1522 D3DContext::UpdateTextureColorState(DWORD dwState, DWORD dwSampler)
1523 {
1524 HRESULT res = S_OK;
1525
1526 if (dwState != lastTextureColorState[dwSampler]) {
1527 res = pd3dDevice->SetTextureStageState(dwSampler,
1528 D3DTSS_ALPHAARG1, dwState);
1529 res = pd3dDevice->SetTextureStageState(dwSampler,
1530 D3DTSS_COLORARG1, dwState);
1531 lastTextureColorState[dwSampler] = dwState;
1532 }
1533
1534 return res;
1535 }
1536
1537 HRESULT /*NOLOCK*/
UpdateState(jbyte newState)1538 D3DContext::UpdateState(jbyte newState)
1539 {
1540 HRESULT res = S_OK;
1541
1542 if (opState == newState) {
1543 // The op is the same as last time, so we can return immediately.
1544 return res;
1545 } else if (opState != STATE_CHANGE) {
1546 res = FlushVertexQueue();
1547 }
1548
1549 switch (opState) {
1550 case STATE_MASKOP:
1551 pMaskCache->Disable();
1552 break;
1553 case STATE_GLYPHOP:
1554 D3DTR_DisableGlyphVertexCache(this);
1555 break;
1556 case STATE_TEXTUREOP:
1557 // optimization: certain state changes (those marked STATE_CHANGE)
1558 // are allowed while texturing is enabled.
1559 // In this case, we can allow previousOp to remain as it is and
1560 // then return early.
1561 if (newState == STATE_CHANGE) {
1562 return res;
1563 }
1564 // REMIND: not necessary if we are switching to MASKOP or GLYPHOP
1565 // (or a complex paint, for that matter), but would that be a
1566 // worthwhile optimization?
1567 SetTexture(NULL);
1568 break;
1569 case STATE_AAPGRAMOP:
1570 res = DisableAAParallelogramProgram();
1571 break;
1572 default:
1573 break;
1574 }
1575
1576 switch (newState) {
1577 case STATE_MASKOP:
1578 pMaskCache->Enable();
1579 UpdateTextureColorState(D3DTA_TEXTURE | D3DTA_ALPHAREPLICATE);
1580 break;
1581 case STATE_GLYPHOP:
1582 D3DTR_EnableGlyphVertexCache(this);
1583 UpdateTextureColorState(D3DTA_TEXTURE | D3DTA_ALPHAREPLICATE);
1584 break;
1585 case STATE_TEXTUREOP:
1586 UpdateTextureColorState(D3DTA_TEXTURE);
1587 break;
1588 case STATE_AAPGRAMOP:
1589 res = EnableAAParallelogramProgram();
1590 break;
1591 default:
1592 break;
1593 }
1594
1595 opState = newState;
1596
1597 return res;
1598 }
1599
FlushVertexQueue()1600 HRESULT D3DContext::FlushVertexQueue()
1601 {
1602 if (pVCacher != NULL) {
1603 return pVCacher->Render();
1604 }
1605 return E_FAIL;
1606 }
1607
BeginScene(jbyte newState)1608 HRESULT D3DContext::BeginScene(jbyte newState)
1609 {
1610 if (!pd3dDevice) {
1611 return E_FAIL;
1612 } else {
1613 UpdateState(newState);
1614 if (!bBeginScenePending) {
1615 bBeginScenePending = TRUE;
1616 HRESULT res = pd3dDevice->BeginScene();
1617 J2dTraceLn(J2D_TRACE_INFO, "D3DContext::BeginScene");
1618 if (FAILED(res)) {
1619 // this will cause context reinitialization
1620 opState = STATE_CHANGE;
1621 }
1622 return res;
1623 }
1624 return S_OK;
1625 }
1626 }
1627
EndScene()1628 HRESULT D3DContext::EndScene() {
1629 if (bBeginScenePending) {
1630 FlushVertexQueue();
1631 bBeginScenePending = FALSE;
1632 J2dTraceLn(J2D_TRACE_INFO, "D3DContext::EndScene");
1633 return pd3dDevice->EndScene();
1634 }
1635 return S_OK;
1636 }
1637
1638 /**
1639 * Compiles and links the given fragment shader program. If
1640 * successful, this function returns a handle to the newly created shader
1641 * program; otherwise returns 0.
1642 */
CreateFragmentProgram(DWORD ** shaders,ShaderList * programs,jint flags)1643 IDirect3DPixelShader9 *D3DContext::CreateFragmentProgram(DWORD **shaders,
1644 ShaderList *programs,
1645 jint flags)
1646 {
1647 DWORD *sourceCode;
1648 IDirect3DPixelShader9 *pProgram;
1649
1650 J2dTraceLn1(J2D_TRACE_INFO,
1651 "D3DContext::CreateFragmentProgram: flags=%d",
1652 flags);
1653
1654 sourceCode = shaders[flags];
1655 if (FAILED(pd3dDevice->CreatePixelShader(sourceCode, &pProgram))) {
1656 J2dRlsTraceLn(J2D_TRACE_ERROR,
1657 "D3DContext::CreateFragmentProgram: error creating program");
1658 return NULL;
1659 }
1660
1661 // add it to the cache
1662 ShaderList_AddProgram(programs, ptr_to_jlong(pProgram),
1663 0 /*unused*/, 0 /*unused*/, flags);
1664
1665 return pProgram;
1666 }
1667
1668 /**
1669 * Locates and enables a fragment program given a list of shader programs
1670 * (ShaderInfos), using this context's state and flags as search
1671 * parameters. The "flags" parameter is a bitwise-or'd value that helps
1672 * differentiate one program for another; the interpretation of this value
1673 * varies depending on the type of shader (BufImgOp, Paint, etc) but here
1674 * it is only used to find another ShaderInfo with that same "flags" value.
1675 */
EnableFragmentProgram(DWORD ** shaders,ShaderList * programList,jint flags)1676 HRESULT D3DContext::EnableFragmentProgram(DWORD **shaders,
1677 ShaderList *programList,
1678 jint flags)
1679 {
1680 HRESULT res;
1681 jlong programID;
1682 IDirect3DPixelShader9 *pProgram;
1683
1684 J2dTraceLn(J2D_TRACE_INFO, "D3DContext::EnableFragmentProgram");
1685
1686 programID =
1687 ShaderList_FindProgram(programList,
1688 0 /*unused*/, 0 /*unused*/, flags);
1689
1690 pProgram = (IDirect3DPixelShader9 *)jlong_to_ptr(programID);
1691 if (pProgram == NULL) {
1692 pProgram = CreateFragmentProgram(shaders, programList, flags);
1693 if (pProgram == NULL) {
1694 return E_FAIL;
1695 }
1696 }
1697
1698 if (FAILED(res = pd3dDevice->SetPixelShader(pProgram))) {
1699 J2dRlsTraceLn(J2D_TRACE_ERROR,
1700 "D3DContext::EnableFragmentProgram: error setting pixel shader");
1701 return res;
1702 }
1703
1704 return S_OK;
1705 }
1706
EnableBasicGradientProgram(jint flags)1707 HRESULT D3DContext::EnableBasicGradientProgram(jint flags)
1708 {
1709 return EnableFragmentProgram((DWORD **)gradShaders,
1710 &basicGradPrograms, flags);
1711 }
1712
EnableLinearGradientProgram(jint flags)1713 HRESULT D3DContext::EnableLinearGradientProgram(jint flags)
1714 {
1715 return EnableFragmentProgram((DWORD **)linearShaders,
1716 &linearGradPrograms, flags);
1717 }
1718
EnableRadialGradientProgram(jint flags)1719 HRESULT D3DContext::EnableRadialGradientProgram(jint flags)
1720 {
1721 return EnableFragmentProgram((DWORD **)radialShaders,
1722 &radialGradPrograms, flags);
1723 }
1724
EnableConvolveProgram(jint flags)1725 HRESULT D3DContext::EnableConvolveProgram(jint flags)
1726 {
1727 return EnableFragmentProgram((DWORD **)convolveShaders,
1728 &convolvePrograms, flags);
1729 }
1730
EnableRescaleProgram(jint flags)1731 HRESULT D3DContext::EnableRescaleProgram(jint flags)
1732 {
1733 return EnableFragmentProgram((DWORD **)rescaleShaders,
1734 &rescalePrograms, flags);
1735 }
1736
EnableLookupProgram(jint flags)1737 HRESULT D3DContext::EnableLookupProgram(jint flags)
1738 {
1739 return EnableFragmentProgram((DWORD **)lookupShaders,
1740 &lookupPrograms, flags);
1741 }
1742
EnableLCDTextProgram()1743 HRESULT D3DContext::EnableLCDTextProgram()
1744 {
1745 HRESULT res;
1746
1747 J2dTraceLn(J2D_TRACE_INFO, "D3DContext::EnableLCDTextProgram");
1748
1749 if (lcdTextProgram == NULL) {
1750 if (FAILED(res = pd3dDevice->CreatePixelShader(lcdtext0,
1751 &lcdTextProgram)))
1752 {
1753 return res;
1754 }
1755 }
1756
1757 if (FAILED(res = pd3dDevice->SetPixelShader(lcdTextProgram))) {
1758 J2dRlsTraceLn(J2D_TRACE_ERROR,
1759 "D3DContext::EnableLCDTextProgram: error setting pixel shader");
1760 return res;
1761 }
1762
1763 return S_OK;
1764 }
1765
EnableAAParallelogramProgram()1766 HRESULT D3DContext::EnableAAParallelogramProgram()
1767 {
1768 HRESULT res;
1769
1770 J2dTraceLn(J2D_TRACE_INFO, "D3DContext::EnableAAParallelogramProgram");
1771
1772 if (aaPgramProgram == NULL) {
1773 if (FAILED(res = pd3dDevice->CreatePixelShader(aapgram0,
1774 &aaPgramProgram))) {
1775 DebugPrintD3DError(res, "D3DContext::EnableAAParallelogramProgram: "
1776 "error creating pixel shader");
1777 return res;
1778 }
1779 }
1780
1781 if (FAILED(res = pd3dDevice->SetPixelShader(aaPgramProgram))) {
1782 DebugPrintD3DError(res, "D3DContext::EnableAAParallelogramProgram: "
1783 "error setting pixel shader");
1784 return res;
1785 }
1786
1787 return S_OK;
1788 }
1789
DisableAAParallelogramProgram()1790 HRESULT D3DContext::DisableAAParallelogramProgram()
1791 {
1792 HRESULT res;
1793
1794 J2dTraceLn(J2D_TRACE_INFO, "D3DContext::DisableAAParallelogramProgram");
1795
1796 if (aaPgramProgram != NULL) {
1797 if (FAILED(res = pd3dDevice->SetPixelShader(NULL))) {
1798 DebugPrintD3DError(res,
1799 "D3DContext::DisableAAParallelogramProgram: "
1800 "error clearing pixel shader");
1801 return res;
1802 }
1803 }
1804
1805 return S_OK;
1806 }
1807
IsAlphaRTSurfaceSupported()1808 BOOL D3DContext::IsAlphaRTSurfaceSupported()
1809 {
1810 HRESULT res = pd3dObject->CheckDeviceFormat(adapterOrdinal,
1811 devCaps.DeviceType,
1812 curParams.BackBufferFormat,
1813 D3DUSAGE_RENDERTARGET,
1814 D3DRTYPE_SURFACE,
1815 D3DFMT_A8R8G8B8);
1816 return SUCCEEDED(res);
1817 }
1818
IsAlphaRTTSupported()1819 BOOL D3DContext::IsAlphaRTTSupported()
1820 {
1821 HRESULT res = pd3dObject->CheckDeviceFormat(adapterOrdinal,
1822 devCaps.DeviceType,
1823 curParams.BackBufferFormat,
1824 D3DUSAGE_RENDERTARGET,
1825 D3DRTYPE_TEXTURE,
1826 D3DFMT_A8R8G8B8);
1827 return SUCCEEDED(res);
1828 }
1829
IsOpaqueRTTSupported()1830 BOOL D3DContext::IsOpaqueRTTSupported()
1831 {
1832 HRESULT res = pd3dObject->CheckDeviceFormat(adapterOrdinal,
1833 devCaps.DeviceType,
1834 curParams.BackBufferFormat,
1835 D3DUSAGE_RENDERTARGET,
1836 D3DRTYPE_TEXTURE,
1837 curParams.BackBufferFormat);
1838 return SUCCEEDED(res);
1839 }
1840
InitContextCaps()1841 HRESULT D3DContext::InitContextCaps() {
1842 J2dTraceLn(J2D_TRACE_INFO, "D3DContext::InitContextCaps");
1843 J2dTraceLn1(J2D_TRACE_VERBOSE, " caps for adapter %d :", adapterOrdinal);
1844
1845 if (pd3dDevice == NULL || pd3dObject == NULL) {
1846 contextCaps = CAPS_EMPTY;
1847 J2dRlsTraceLn(J2D_TRACE_VERBOSE, " | CAPS_EMPTY");
1848 return E_FAIL;
1849 }
1850
1851 contextCaps = CAPS_DEVICE_OK;
1852 J2dRlsTraceLn(J2D_TRACE_VERBOSE, " | CAPS_DEVICE_OK");
1853
1854 if (IsAlphaRTSurfaceSupported()) {
1855 contextCaps |= CAPS_RT_PLAIN_ALPHA;
1856 J2dRlsTraceLn(J2D_TRACE_VERBOSE, " | CAPS_RT_PLAIN_ALPHA");
1857 }
1858 if (IsAlphaRTTSupported()) {
1859 contextCaps |= CAPS_RT_TEXTURE_ALPHA;
1860 J2dRlsTraceLn(J2D_TRACE_VERBOSE, " | CAPS_RT_TEXTURE_ALPHA");
1861 }
1862 if (IsOpaqueRTTSupported()) {
1863 contextCaps |= CAPS_RT_TEXTURE_OPAQUE;
1864 J2dRlsTraceLn(J2D_TRACE_VERBOSE, " | CAPS_RT_TEXTURE_OPAQUE");
1865 }
1866 if (IsPixelShader20Supported()) {
1867 contextCaps |= CAPS_LCD_SHADER | CAPS_BIOP_SHADER | CAPS_PS20;
1868 J2dRlsTraceLn(J2D_TRACE_VERBOSE,
1869 " | CAPS_LCD_SHADER | CAPS_BIOP_SHADER | CAPS_PS20");
1870 // Pre-PS3.0 video boards are very slow with the AA shader, so
1871 // we will require PS30 hw even though the shader is compiled for 2.0a
1872 // if (IsGradientInstructionExtensionSupported()) {
1873 // contextCaps |= CAPS_AA_SHADER;
1874 // J2dRlsTraceLn(J2D_TRACE_VERBOSE, " | CAPS_AA_SHADER");
1875 // }
1876 }
1877 if (IsPixelShader30Supported()) {
1878 if ((contextCaps & CAPS_AA_SHADER) == 0) {
1879 // This flag was not already mentioned above...
1880 J2dRlsTraceLn(J2D_TRACE_VERBOSE, " | CAPS_AA_SHADER");
1881 }
1882 contextCaps |= CAPS_PS30 | CAPS_AA_SHADER;
1883 J2dRlsTraceLn(J2D_TRACE_VERBOSE, " | CAPS_PS30");
1884 }
1885 if (IsMultiTexturingSupported()) {
1886 contextCaps |= CAPS_MULTITEXTURE;
1887 J2dRlsTraceLn(J2D_TRACE_VERBOSE, " | CAPS_MULTITEXTURE");
1888 }
1889 if (!IsPow2TexturesOnly()) {
1890 contextCaps |= CAPS_TEXNONPOW2;
1891 J2dRlsTraceLn(J2D_TRACE_VERBOSE, " | CAPS_TEXNONPOW2");
1892 }
1893 if (!IsSquareTexturesOnly()) {
1894 contextCaps |= CAPS_TEXNONSQUARE;
1895 J2dRlsTraceLn(J2D_TRACE_VERBOSE, " | CAPS_TEXNONSQUARE");
1896 }
1897 return S_OK;
1898 }
1899