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(&params, 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(&params);
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