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