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