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
40typedef 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 */
50D3DBlendRule 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
66void
67D3DUtils_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
81void
82D3DUtils_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
98void
99D3DUtils_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
123void
124D3DUtils_2DScaleM(D3DMATRIX *m, float sx, float sy)
125{
126    m->_11 *= sx;
127    m->_22 *= sy;
128}
129
130void
131D3DUtils_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
152void
153D3DUtils_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
159void
160D3DUtils_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
169void
170D3DUtils_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
189static void
190D3DContext_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
201HRESULT
202D3DContext::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
213D3DContext::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
250void 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
284void 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
311D3DContext::~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
319HRESULT
320D3DContext::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
433HRESULT
434D3DContext::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
466HRESULT
467D3DContext::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
491HRESULT
492D3DContext::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
646HRESULT
647D3DContext::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
665HRESULT
666D3DContext::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
688HRESULT
689D3DContext::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
719HRESULT
720D3DContext::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
749BOOL
750D3DContext::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
761BOOL
762D3DContext::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
773BOOL
774D3DContext::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
785BOOL
786D3DContext::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
815HRESULT
816D3DContext::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
844HRESULT
845D3DContext::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
894HRESULT
895D3DContext::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
916HRESULT
917D3DContext::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
977HRESULT
978D3DContext::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
1031HRESULT
1032D3DContext::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
1041ClipType
1042D3DContext::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 */
1069DWORD dwAlphaSt, dwSrcBlendSt, dwDestBlendSt;
1070D3DMATRIX tx, idTx;
1071
1072HRESULT
1073D3DContext::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
1116HRESULT
1117D3DContext::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
1141HRESULT
1142D3DContext::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, (y)*(yinc) + (x)*(xinc))
1154#endif // PtrAddBytes
1155
1156    HRESULT res = S_OK;
1157    IDirect3DTexture9 *pTexture = pTextureRes->GetTexture();
1158    D3DSURFACE_DESC *pDesc = pTextureRes->GetDesc();
1159    RECT r = { dstx, dsty, dstx+srcWidth, dsty+srcHeight };
1160    RECT *pR = &r;
1161    D3DLOCKED_RECT lockedRect;
1162    DWORD dwLockFlags = D3DLOCK_NOSYSLOCK;
1163    // these are only counted for LCD glyph uploads
1164    jint pixelsTouchedL = 0, pixelsTouchedR = 0;
1165
1166    J2dTraceLn(J2D_TRACE_INFO, "D3DContext::UploadTileToTexture");
1167    J2dTraceLn4(J2D_TRACE_VERBOSE,
1168        " rect={%-4d, %-4d, %-4d, %-4d}",
1169        r.left, r.top, r.right, r.bottom);
1170
1171    if (pDesc->Usage == D3DUSAGE_DYNAMIC) {
1172        // it is safe to lock with discard because we don't care about the
1173        // contents of dynamic textures and dstx,dsty for this case is
1174        // always 0,0 because we are uploading into a tile texture
1175        dwLockFlags |= D3DLOCK_DISCARD;
1176        pR = NULL;
1177    }
1178
1179    if (FAILED(res = pTexture->LockRect(0, &lockedRect, pR, dwLockFlags))) {
1180        DebugPrintD3DError(res,
1181            "D3DContext::UploadImageToTexture: could "\
1182            "not lock texture");
1183        return res;
1184    }
1185
1186    if (srcFormat == TILEFMT_1BYTE_ALPHA) {
1187        // either a MaskFill tile, or a grayscale glyph
1188        if (pDesc->Format == D3DFMT_A8) {
1189            void *pSrcPixels = PtrCoord(pixels, srcx, 1, srcy, srcStride);
1190            void *pDstPixels = lockedRect.pBits;
1191            do {
1192                memcpy(pDstPixels, pSrcPixels, srcWidth);
1193                pSrcPixels = PtrAddBytes(pSrcPixels, srcStride);
1194                pDstPixels = PtrAddBytes(pDstPixels, lockedRect.Pitch);
1195            } while (--srcHeight > 0);
1196        }
1197        else if (pDesc->Format == D3DFMT_A8R8G8B8) {
1198            jubyte *pSrcPixels = (jubyte*)
1199                PtrCoord(pixels, srcx, 1, srcy, srcStride);
1200            jint *pDstPixels = (jint*)lockedRect.pBits;
1201            for (int yy = 0; yy < srcHeight; yy++) {
1202                for (int xx = 0; xx < srcWidth; xx++) {
1203                    // only need to set the alpha channel (the D3D texture
1204                    // state will be setup in this case to replicate the
1205                    // alpha channel as needed)
1206                    pDstPixels[xx] = pSrcPixels[xx] << 24;
1207                }
1208                pSrcPixels = (jubyte*)PtrAddBytes(pSrcPixels, srcStride);
1209                pDstPixels = (jint*)PtrAddBytes(pDstPixels, lockedRect.Pitch);
1210            }
1211        }
1212    } else if (srcFormat == TILEFMT_3BYTE_RGB) {
1213        // LCD glyph with RGB order
1214        if (pDesc->Format == D3DFMT_R8G8B8) {
1215            jubyte *pSrcPixels = (jubyte*)
1216                PtrCoord(pixels, srcx, 3, srcy, srcStride);
1217            jubyte *pDstPixels = (jubyte*)lockedRect.pBits;
1218            for (int yy = 0; yy < srcHeight; yy++) {
1219                for (int xx = 0; xx < srcWidth*3; xx+=3) {
1220                    // alpha channel is ignored in this case
1221                    // (note that this is backwards from what one might
1222                    // expect; it appears that D3DFMT_R8G8B8 is actually
1223                    // laid out in BGR order in memory)
1224                    pDstPixels[xx+0] = pSrcPixels[xx+2];
1225                    pDstPixels[xx+1] = pSrcPixels[xx+1];
1226                    pDstPixels[xx+2] = pSrcPixels[xx+0];
1227                }
1228                pixelsTouchedL +=
1229                    (pDstPixels[0+0]|pDstPixels[0+1]|pDstPixels[0+2]) ? 1 : 0;
1230                jint i = 3*(srcWidth-1);
1231                pixelsTouchedR +=
1232                    (pDstPixels[i+0]|pDstPixels[i+1]|pDstPixels[i+2]) ? 1 : 0;
1233
1234                pSrcPixels = (jubyte*)PtrAddBytes(pSrcPixels, srcStride);
1235                pDstPixels = (jubyte*)PtrAddBytes(pDstPixels, lockedRect.Pitch);
1236            }
1237        }
1238        else if (pDesc->Format == D3DFMT_A8R8G8B8) {
1239            jubyte *pSrcPixels = (jubyte*)
1240                PtrCoord(pixels, srcx, 3, srcy, srcStride);
1241            jint *pDstPixels = (jint*)lockedRect.pBits;
1242            for (int yy = 0; yy < srcHeight; yy++) {
1243                for (int dx = 0, sx = 0; dx < srcWidth; dx++, sx+=3) {
1244                    // alpha channel is ignored in this case
1245                    jubyte r = pSrcPixels[sx+0];
1246                    jubyte g = pSrcPixels[sx+1];
1247                    jubyte b = pSrcPixels[sx+2];
1248                    pDstPixels[dx] = (r << 16) | (g << 8) | (b);
1249                }
1250                pixelsTouchedL += (pDstPixels[0]          ? 1 : 0);
1251                pixelsTouchedR += (pDstPixels[srcWidth-1] ? 1 : 0);
1252
1253                pSrcPixels = (jubyte*)PtrAddBytes(pSrcPixels, srcStride);
1254                pDstPixels = (jint*)PtrAddBytes(pDstPixels, lockedRect.Pitch);
1255            }
1256        }
1257    } else if (srcFormat == TILEFMT_3BYTE_BGR) {
1258        // LCD glyph with BGR order
1259        if (pDesc->Format == D3DFMT_R8G8B8) {
1260            void *pSrcPixels = PtrCoord(pixels, srcx, 3, srcy, srcStride);
1261            void *pDstPixels = lockedRect.pBits;
1262            jubyte *pbDst;
1263            do {
1264                // alpha channel is ignored in this case
1265                // (note that this is backwards from what one might
1266                // expect; it appears that D3DFMT_R8G8B8 is actually
1267                // laid out in BGR order in memory)
1268                memcpy(pDstPixels, pSrcPixels, srcWidth * 3);
1269
1270                pbDst = (jubyte*)pDstPixels;
1271                pixelsTouchedL +=(pbDst[0+0]|pbDst[0+1]|pbDst[0+2]) ? 1 : 0;
1272                jint i = 3*(srcWidth-1);
1273                pixelsTouchedR +=(pbDst[i+0]|pbDst[i+1]|pbDst[i+2]) ? 1 : 0;
1274
1275                pSrcPixels = PtrAddBytes(pSrcPixels, srcStride);
1276                pDstPixels = PtrAddBytes(pDstPixels, lockedRect.Pitch);
1277            } while (--srcHeight > 0);
1278        }
1279        else if (pDesc->Format == D3DFMT_A8R8G8B8) {
1280            jubyte *pSrcPixels = (jubyte*)
1281                PtrCoord(pixels, srcx, 3, srcy, srcStride);
1282            jint *pDstPixels = (jint*)lockedRect.pBits;
1283            for (int yy = 0; yy < srcHeight; yy++) {
1284                for (int dx = 0, sx = 0; dx < srcWidth; dx++, sx+=3) {
1285                    // alpha channel is ignored in this case
1286                    jubyte b = pSrcPixels[sx+0];
1287                    jubyte g = pSrcPixels[sx+1];
1288                    jubyte r = pSrcPixels[sx+2];
1289                    pDstPixels[dx] = (r << 16) | (g << 8) | (b);
1290                }
1291                pixelsTouchedL += (pDstPixels[0]          ? 1 : 0);
1292                pixelsTouchedR += (pDstPixels[srcWidth-1] ? 1 : 0);
1293
1294                pSrcPixels = (jubyte*)PtrAddBytes(pSrcPixels, srcStride);
1295                pDstPixels = (jint*)PtrAddBytes(pDstPixels, lockedRect.Pitch);
1296            }
1297        }
1298    } else if (srcFormat == TILEFMT_4BYTE_ARGB_PRE) {
1299        // MaskBlit tile
1300        if (pDesc->Format == D3DFMT_A8R8G8B8) {
1301            void *pSrcPixels = PtrCoord(pixels, srcx, 4, srcy, srcStride);
1302            void *pDstPixels = lockedRect.pBits;
1303            do {
1304                memcpy(pDstPixels, pSrcPixels, srcWidth * 4);
1305                pSrcPixels = PtrAddBytes(pSrcPixels, srcStride);
1306                pDstPixels = PtrAddBytes(pDstPixels, lockedRect.Pitch);
1307            } while (--srcHeight > 0);
1308        }
1309    } else {
1310        // should not happen, no-op just in case...
1311    }
1312
1313    if (pPixelsTouchedL) {
1314        *pPixelsTouchedL  = pixelsTouchedL;
1315    }
1316    if (pPixelsTouchedR) {
1317        *pPixelsTouchedR = pixelsTouchedR;
1318    }
1319
1320    return pTexture->UnlockRect(0);
1321}
1322
1323HRESULT
1324D3DContext::InitLCDGlyphCache()
1325{
1326    if (pLCDGlyphCache == NULL) {
1327        return D3DGlyphCache::CreateInstance(this, CACHE_LCD, &pLCDGlyphCache);
1328    }
1329    return S_OK;
1330}
1331
1332HRESULT
1333D3DContext::InitGrayscaleGlyphCache()
1334{
1335    if (pGrayscaleGlyphCache == NULL) {
1336        return D3DGlyphCache::CreateInstance(this, CACHE_GRAY,
1337                                             &pGrayscaleGlyphCache);
1338    }
1339    return S_OK;
1340}
1341
1342HRESULT
1343D3DContext::ResetComposite()
1344{
1345    J2dTraceLn(J2D_TRACE_INFO, "D3DContext::ResetComposite");
1346
1347    RETURN_STATUS_IF_NULL(pd3dDevice, E_FAIL);
1348
1349    HRESULT res = UpdateState(STATE_CHANGE);
1350    pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
1351    extraAlpha = 1.0f;
1352    return res;
1353}
1354
1355HRESULT
1356D3DContext::SetAlphaComposite(jint rule, jfloat ea, jint flags)
1357{
1358    HRESULT res;
1359    J2dTraceLn3(J2D_TRACE_INFO,
1360                "D3DContext::SetAlphaComposite: rule=%-1d ea=%f flags=%d",
1361                rule, ea, flags);
1362
1363    RETURN_STATUS_IF_NULL(pd3dDevice, E_FAIL);
1364
1365    res = UpdateState(STATE_CHANGE);
1366
1367    // we can safely disable blending when:
1368    //   - comp is SrcNoEa or SrcOverNoEa, and
1369    //   - the source is opaque
1370    // (turning off blending can have a large positive impact on performance)
1371    if ((rule == RULE_Src || rule == RULE_SrcOver) &&
1372        (ea == 1.0f) &&
1373        (flags & D3DC_SRC_IS_OPAQUE))
1374    {
1375        J2dTraceLn1(J2D_TRACE_VERBOSE,
1376                    "  disabling alpha comp rule=%-1d ea=1.0 src=opq)", rule);
1377        pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
1378    } else {
1379        J2dTraceLn2(J2D_TRACE_VERBOSE,
1380                    "  enabling alpha comp (rule=%-1d ea=%f)", rule, ea);
1381        pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
1382
1383        pd3dDevice->SetRenderState(D3DRS_SRCBLEND,
1384                                   StdBlendRules[rule].src);
1385        pd3dDevice->SetRenderState(D3DRS_DESTBLEND,
1386                                   StdBlendRules[rule].dst);
1387    }
1388
1389    extraAlpha = ea;
1390    return res;
1391}
1392
1393#ifdef UPDATE_TX
1394
1395// Note: this method of adjusting pixel to texel mapping proved to be
1396// difficult to perfect. The current variation works great for id,
1397// scale (including all kinds of flips) transforms, but not still not
1398// for generic transforms.
1399//
1400// Since we currently only do DrawTexture with non-id transform we instead
1401// adjust the geometry (see D3DVertexCacher::DrawTexture(), SetTransform())
1402//
1403// In order to enable this code path UpdateTextureTransforms needs to
1404// be called in SetTexture(), SetTransform() and ResetTranform().
1405HRESULT
1406D3DContext::UpdateTextureTransforms(DWORD dwSamplerToUpdate)
1407{
1408    HRESULT res = S_OK;
1409    DWORD dwSampler, dwMaxSampler;
1410
1411    if (dwSamplerToUpdate == -1) {
1412        // update all used samplers, dwMaxSampler will be set to max
1413        dwSampler = 0;
1414        dwSampler = MAX_USED_TEXTURE_SAMPLER;
1415        J2dTraceLn(J2D_TRACE_INFO, "D3DContext::UpdateTextureTransforms: "\
1416                                   "updating all samplers");
1417    } else {
1418        // update only given sampler, dwMaxSampler will be set to it as well
1419        dwSampler = dwSamplerToUpdate;
1420        dwMaxSampler = dwSamplerToUpdate;
1421        J2dTraceLn1(J2D_TRACE_INFO, "D3DContext::UpdateTextureTransforms: "\
1422                                    "updating sampler %d", dwSampler);
1423    }
1424
1425    do {
1426        D3DTRANSFORMSTATETYPE state =
1427            (D3DTRANSFORMSTATETYPE)(D3DTS_TEXTURE0 + dwSampler);
1428        IDirect3DTexture9 *pTexture = lastTexture[dwSampler];
1429
1430        if (pTexture != NULL) {
1431            D3DMATRIX mt, tx;
1432            D3DSURFACE_DESC texDesc;
1433
1434            pd3dDevice->GetTransform(D3DTS_WORLD, &tx);
1435            J2dTraceLn4(10,
1436                        "  %5f %5f %5f %5f", tx._11, tx._12, tx._13, tx._14);
1437            J2dTraceLn4(10,
1438                        "  %5f %5f %5f %5f", tx._21, tx._22, tx._23, tx._24);
1439            J2dTraceLn4(10,
1440                        "  %5f %5f %5f %5f", tx._31, tx._32, tx._33, tx._34);
1441            J2dTraceLn4(10,
1442                        "  %5f %5f %5f %5f", tx._41, tx._42, tx._43, tx._44);
1443
1444            // this formula works for scales and flips
1445            if (tx._11 == 0.0f) {
1446                tx._11 = tx._12;
1447            }
1448            if (tx._22 == 0.0f) {
1449                tx._22 = tx._21;
1450            }
1451
1452            pTexture->GetLevelDesc(0, &texDesc);
1453
1454            // shift by .5 texel, but take into account
1455            // the scale factor of the device transform
1456
1457            // REMIND: this approach is not entirely correct,
1458            // as it only takes into account the scale of the device
1459            // transform.
1460            mt._31 = (1.0f / (2.0f * texDesc.Width  * tx._11));
1461            mt._32 = (1.0f / (2.0f * texDesc.Height * tx._22));
1462            J2dTraceLn2(J2D_TRACE_VERBOSE, "  offsets: tx=%f ty=%f",
1463                        mt._31, mt._32);
1464
1465            pd3dDevice->SetTextureStageState(dwSampler,
1466                                             D3DTSS_TEXTURETRANSFORMFLAGS,
1467                                             D3DTTFF_COUNT2);
1468            res = pd3dDevice->SetTransform(state, &mt);
1469        } else {
1470            res = pd3dDevice->SetTextureStageState(dwSampler,
1471                                                   D3DTSS_TEXTURETRANSFORMFLAGS,
1472                                                   D3DTTFF_DISABLE);
1473        }
1474        dwSampler++;
1475    } while (dwSampler <= dwMaxSampler);
1476
1477    return res;
1478}
1479#endif // UPDATE_TX
1480
1481/**
1482 * We go into the pains of maintaining the list of set textures
1483 * instead of just calling GetTexture() and comparing the old one
1484 * with the new one because it's actually noticeably slower to call
1485 * GetTexture() (note that we'd have to then call Release() on the
1486 * texture since GetTexture() increases texture's ref. count).
1487 */
1488HRESULT
1489D3DContext::SetTexture(IDirect3DTexture9 *pTexture, DWORD dwSampler)
1490{
1491    HRESULT res = S_OK;
1492    J2dTraceLn(J2D_TRACE_INFO, "D3DContext::SetTexture");
1493
1494    if (dwSampler < 0 || dwSampler > MAX_USED_TEXTURE_SAMPLER) {
1495        J2dTraceLn1(J2D_TRACE_ERROR,
1496                    "D3DContext::SetTexture: incorrect sampler: %d", dwSampler);
1497        return E_FAIL;
1498    }
1499    if (lastTexture[dwSampler] != pTexture) {
1500        if (FAILED(res = FlushVertexQueue())) {
1501            return res;
1502        }
1503        J2dTraceLn2(J2D_TRACE_VERBOSE,
1504                    "  new texture=0x%x on sampler %d", pTexture, dwSampler);
1505        res = pd3dDevice->SetTexture(dwSampler, pTexture);
1506        if (SUCCEEDED(res)) {
1507            lastTexture[dwSampler] = pTexture;
1508            // REMIND: see comment at UpdateTextureTransforms
1509#ifdef UPDATE_TX
1510            res = UpdateTextureTransforms(dwSampler);
1511#endif
1512        }  else {
1513            lastTexture[dwSampler] = NULL;
1514        }
1515    }
1516    return res;
1517}
1518
1519HRESULT
1520D3DContext::UpdateTextureColorState(DWORD dwState, DWORD dwSampler)
1521{
1522    HRESULT res = S_OK;
1523
1524    if (dwState != lastTextureColorState[dwSampler]) {
1525        res = pd3dDevice->SetTextureStageState(dwSampler,
1526                                               D3DTSS_ALPHAARG1, dwState);
1527        res = pd3dDevice->SetTextureStageState(dwSampler,
1528                                               D3DTSS_COLORARG1, dwState);
1529        lastTextureColorState[dwSampler] = dwState;
1530    }
1531
1532    return res;
1533}
1534
1535HRESULT /*NOLOCK*/
1536D3DContext::UpdateState(jbyte newState)
1537{
1538    HRESULT res = S_OK;
1539
1540    if (opState == newState) {
1541        // The op is the same as last time, so we can return immediately.
1542        return res;
1543    } else if (opState != STATE_CHANGE) {
1544        res = FlushVertexQueue();
1545    }
1546
1547    switch (opState) {
1548    case STATE_MASKOP:
1549        pMaskCache->Disable();
1550        break;
1551    case STATE_GLYPHOP:
1552        D3DTR_DisableGlyphVertexCache(this);
1553        break;
1554    case STATE_TEXTUREOP:
1555        // optimization: certain state changes (those marked STATE_CHANGE)
1556        // are allowed while texturing is enabled.
1557        // In this case, we can allow previousOp to remain as it is and
1558        // then return early.
1559        if (newState == STATE_CHANGE) {
1560            return res;
1561        }
1562        // REMIND: not necessary if we are switching to MASKOP or GLYPHOP
1563        // (or a complex paint, for that matter), but would that be a
1564        // worthwhile optimization?
1565        SetTexture(NULL);
1566        break;
1567    case STATE_AAPGRAMOP:
1568        res = DisableAAParallelogramProgram();
1569        break;
1570    default:
1571        break;
1572    }
1573
1574    switch (newState) {
1575    case STATE_MASKOP:
1576        pMaskCache->Enable();
1577        UpdateTextureColorState(D3DTA_TEXTURE | D3DTA_ALPHAREPLICATE);
1578        break;
1579    case STATE_GLYPHOP:
1580        D3DTR_EnableGlyphVertexCache(this);
1581        UpdateTextureColorState(D3DTA_TEXTURE | D3DTA_ALPHAREPLICATE);
1582        break;
1583    case STATE_TEXTUREOP:
1584        UpdateTextureColorState(D3DTA_TEXTURE);
1585        break;
1586    case STATE_AAPGRAMOP:
1587        res = EnableAAParallelogramProgram();
1588        break;
1589    default:
1590        break;
1591    }
1592
1593    opState = newState;
1594
1595    return res;
1596}
1597
1598HRESULT D3DContext::FlushVertexQueue()
1599{
1600    if (pVCacher != NULL) {
1601        return pVCacher->Render();
1602    }
1603    return E_FAIL;
1604}
1605
1606HRESULT D3DContext::BeginScene(jbyte newState)
1607{
1608    if (!pd3dDevice) {
1609        return E_FAIL;
1610    } else {
1611        UpdateState(newState);
1612        if (!bBeginScenePending) {
1613            bBeginScenePending = TRUE;
1614            HRESULT res = pd3dDevice->BeginScene();
1615            J2dTraceLn(J2D_TRACE_INFO, "D3DContext::BeginScene");
1616            if (FAILED(res)) {
1617                // this will cause context reinitialization
1618                opState = STATE_CHANGE;
1619            }
1620            return res;
1621        }
1622        return S_OK;
1623    }
1624}
1625
1626HRESULT D3DContext::EndScene() {
1627    if (bBeginScenePending) {
1628        FlushVertexQueue();
1629        bBeginScenePending = FALSE;
1630        J2dTraceLn(J2D_TRACE_INFO, "D3DContext::EndScene");
1631        return pd3dDevice->EndScene();
1632    }
1633    return S_OK;
1634}
1635
1636/**
1637 * Compiles and links the given fragment shader program.  If
1638 * successful, this function returns a handle to the newly created shader
1639 * program; otherwise returns 0.
1640 */
1641IDirect3DPixelShader9 *D3DContext::CreateFragmentProgram(DWORD **shaders,
1642                                                       ShaderList *programs,
1643                                                       jint flags)
1644{
1645    DWORD *sourceCode;
1646    IDirect3DPixelShader9 *pProgram;
1647
1648    J2dTraceLn1(J2D_TRACE_INFO,
1649                "D3DContext::CreateFragmentProgram: flags=%d",
1650                flags);
1651
1652    sourceCode = shaders[flags];
1653    if (FAILED(pd3dDevice->CreatePixelShader(sourceCode, &pProgram))) {
1654        J2dRlsTraceLn(J2D_TRACE_ERROR,
1655            "D3DContext::CreateFragmentProgram: error creating program");
1656        return NULL;
1657    }
1658
1659    // add it to the cache
1660    ShaderList_AddProgram(programs, ptr_to_jlong(pProgram),
1661                          0 /*unused*/, 0 /*unused*/, flags);
1662
1663    return pProgram;
1664}
1665
1666/**
1667 * Locates and enables a fragment program given a list of shader programs
1668 * (ShaderInfos), using this context's state and flags as search
1669 * parameters.  The "flags" parameter is a bitwise-or'd value that helps
1670 * differentiate one program for another; the interpretation of this value
1671 * varies depending on the type of shader (BufImgOp, Paint, etc) but here
1672 * it is only used to find another ShaderInfo with that same "flags" value.
1673 */
1674HRESULT D3DContext::EnableFragmentProgram(DWORD **shaders,
1675                                          ShaderList *programList,
1676                                          jint flags)
1677{
1678    HRESULT res;
1679    jlong programID;
1680    IDirect3DPixelShader9 *pProgram;
1681
1682    J2dTraceLn(J2D_TRACE_INFO, "D3DContext::EnableFragmentProgram");
1683
1684    programID =
1685        ShaderList_FindProgram(programList,
1686                               0 /*unused*/, 0 /*unused*/, flags);
1687
1688    pProgram = (IDirect3DPixelShader9 *)jlong_to_ptr(programID);
1689    if (pProgram == NULL) {
1690        pProgram = CreateFragmentProgram(shaders, programList, flags);
1691        if (pProgram == NULL) {
1692            return E_FAIL;
1693        }
1694    }
1695
1696    if (FAILED(res = pd3dDevice->SetPixelShader(pProgram))) {
1697        J2dRlsTraceLn(J2D_TRACE_ERROR,
1698            "D3DContext::EnableFragmentProgram: error setting pixel shader");
1699        return res;
1700    }
1701
1702    return S_OK;
1703}
1704
1705HRESULT D3DContext::EnableBasicGradientProgram(jint flags)
1706{
1707    return EnableFragmentProgram((DWORD **)gradShaders,
1708                                 &basicGradPrograms, flags);
1709}
1710
1711HRESULT D3DContext::EnableLinearGradientProgram(jint flags)
1712{
1713    return EnableFragmentProgram((DWORD **)linearShaders,
1714                                 &linearGradPrograms, flags);
1715}
1716
1717HRESULT D3DContext::EnableRadialGradientProgram(jint flags)
1718{
1719    return EnableFragmentProgram((DWORD **)radialShaders,
1720                                 &radialGradPrograms, flags);
1721}
1722
1723HRESULT D3DContext::EnableConvolveProgram(jint flags)
1724{
1725    return EnableFragmentProgram((DWORD **)convolveShaders,
1726                                 &convolvePrograms, flags);
1727}
1728
1729HRESULT D3DContext::EnableRescaleProgram(jint flags)
1730{
1731    return EnableFragmentProgram((DWORD **)rescaleShaders,
1732                                 &rescalePrograms, flags);
1733}
1734
1735HRESULT D3DContext::EnableLookupProgram(jint flags)
1736{
1737    return EnableFragmentProgram((DWORD **)lookupShaders,
1738                                 &lookupPrograms, flags);
1739}
1740
1741HRESULT D3DContext::EnableLCDTextProgram()
1742{
1743    HRESULT res;
1744
1745    J2dTraceLn(J2D_TRACE_INFO, "D3DContext::EnableLCDTextProgram");
1746
1747    if (lcdTextProgram == NULL) {
1748        if (FAILED(res = pd3dDevice->CreatePixelShader(lcdtext0,
1749                                                       &lcdTextProgram)))
1750        {
1751            return res;
1752        }
1753    }
1754
1755    if (FAILED(res = pd3dDevice->SetPixelShader(lcdTextProgram))) {
1756        J2dRlsTraceLn(J2D_TRACE_ERROR,
1757            "D3DContext::EnableLCDTextProgram: error setting pixel shader");
1758        return res;
1759    }
1760
1761    return S_OK;
1762}
1763
1764HRESULT D3DContext::EnableAAParallelogramProgram()
1765{
1766    HRESULT res;
1767
1768    J2dTraceLn(J2D_TRACE_INFO, "D3DContext::EnableAAParallelogramProgram");
1769
1770    if (aaPgramProgram == NULL) {
1771        if (FAILED(res = pd3dDevice->CreatePixelShader(aapgram0,
1772                                                       &aaPgramProgram))) {
1773            DebugPrintD3DError(res, "D3DContext::EnableAAParallelogramProgram: "
1774                               "error creating pixel shader");
1775            return res;
1776        }
1777    }
1778
1779    if (FAILED(res = pd3dDevice->SetPixelShader(aaPgramProgram))) {
1780        DebugPrintD3DError(res, "D3DContext::EnableAAParallelogramProgram: "
1781                           "error setting pixel shader");
1782        return res;
1783    }
1784
1785    return S_OK;
1786}
1787
1788HRESULT D3DContext::DisableAAParallelogramProgram()
1789{
1790    HRESULT res;
1791
1792    J2dTraceLn(J2D_TRACE_INFO, "D3DContext::DisableAAParallelogramProgram");
1793
1794    if (aaPgramProgram != NULL) {
1795        if (FAILED(res = pd3dDevice->SetPixelShader(NULL))) {
1796            DebugPrintD3DError(res,
1797                               "D3DContext::DisableAAParallelogramProgram: "
1798                               "error clearing pixel shader");
1799            return res;
1800        }
1801    }
1802
1803    return S_OK;
1804}
1805
1806BOOL D3DContext::IsAlphaRTSurfaceSupported()
1807{
1808    HRESULT res = pd3dObject->CheckDeviceFormat(adapterOrdinal,
1809            devCaps.DeviceType,
1810            curParams.BackBufferFormat,
1811            D3DUSAGE_RENDERTARGET,
1812            D3DRTYPE_SURFACE,
1813            D3DFMT_A8R8G8B8);
1814    return SUCCEEDED(res);
1815}
1816
1817BOOL D3DContext::IsAlphaRTTSupported()
1818{
1819    HRESULT res = pd3dObject->CheckDeviceFormat(adapterOrdinal,
1820            devCaps.DeviceType,
1821            curParams.BackBufferFormat,
1822            D3DUSAGE_RENDERTARGET,
1823            D3DRTYPE_TEXTURE,
1824            D3DFMT_A8R8G8B8);
1825    return SUCCEEDED(res);
1826}
1827
1828BOOL D3DContext::IsOpaqueRTTSupported()
1829{
1830    HRESULT res = pd3dObject->CheckDeviceFormat(adapterOrdinal,
1831            devCaps.DeviceType,
1832            curParams.BackBufferFormat,
1833            D3DUSAGE_RENDERTARGET,
1834            D3DRTYPE_TEXTURE,
1835            curParams.BackBufferFormat);
1836    return SUCCEEDED(res);
1837}
1838
1839HRESULT D3DContext::InitContextCaps() {
1840    J2dTraceLn(J2D_TRACE_INFO, "D3DContext::InitContextCaps");
1841    J2dTraceLn1(J2D_TRACE_VERBOSE, "  caps for adapter %d :", adapterOrdinal);
1842
1843    if (pd3dDevice == NULL || pd3dObject == NULL) {
1844        contextCaps = CAPS_EMPTY;
1845        J2dRlsTraceLn(J2D_TRACE_VERBOSE, "  | CAPS_EMPTY");
1846        return E_FAIL;
1847    }
1848
1849    contextCaps = CAPS_DEVICE_OK;
1850    J2dRlsTraceLn(J2D_TRACE_VERBOSE, "  | CAPS_DEVICE_OK");
1851
1852    if (IsAlphaRTSurfaceSupported()) {
1853        contextCaps |= CAPS_RT_PLAIN_ALPHA;
1854        J2dRlsTraceLn(J2D_TRACE_VERBOSE, "  | CAPS_RT_PLAIN_ALPHA");
1855    }
1856    if (IsAlphaRTTSupported()) {
1857        contextCaps |= CAPS_RT_TEXTURE_ALPHA;
1858        J2dRlsTraceLn(J2D_TRACE_VERBOSE, "  | CAPS_RT_TEXTURE_ALPHA");
1859    }
1860    if (IsOpaqueRTTSupported()) {
1861        contextCaps |= CAPS_RT_TEXTURE_OPAQUE;
1862        J2dRlsTraceLn(J2D_TRACE_VERBOSE, "  | CAPS_RT_TEXTURE_OPAQUE");
1863    }
1864    if (IsPixelShader20Supported()) {
1865        contextCaps |= CAPS_LCD_SHADER | CAPS_BIOP_SHADER | CAPS_PS20;
1866        J2dRlsTraceLn(J2D_TRACE_VERBOSE,
1867                      "  | CAPS_LCD_SHADER | CAPS_BIOP_SHADER | CAPS_PS20");
1868        // Pre-PS3.0 video boards are very slow with the AA shader, so
1869        // we will require PS30 hw even though the shader is compiled for 2.0a
1870//        if (IsGradientInstructionExtensionSupported()) {
1871//            contextCaps |= CAPS_AA_SHADER;
1872//            J2dRlsTraceLn(J2D_TRACE_VERBOSE, "  | CAPS_AA_SHADER");
1873//        }
1874    }
1875    if (IsPixelShader30Supported()) {
1876        if ((contextCaps & CAPS_AA_SHADER) == 0) {
1877            // This flag was not already mentioned above...
1878            J2dRlsTraceLn(J2D_TRACE_VERBOSE, "  | CAPS_AA_SHADER");
1879        }
1880        contextCaps |= CAPS_PS30 | CAPS_AA_SHADER;
1881        J2dRlsTraceLn(J2D_TRACE_VERBOSE, "  | CAPS_PS30");
1882    }
1883    if (IsMultiTexturingSupported()) {
1884        contextCaps |= CAPS_MULTITEXTURE;
1885        J2dRlsTraceLn(J2D_TRACE_VERBOSE, "  | CAPS_MULTITEXTURE");
1886    }
1887    if (!IsPow2TexturesOnly()) {
1888        contextCaps |= CAPS_TEXNONPOW2;
1889        J2dRlsTraceLn(J2D_TRACE_VERBOSE, "  | CAPS_TEXNONPOW2");
1890    }
1891    if (!IsSquareTexturesOnly()) {
1892        contextCaps |= CAPS_TEXNONSQUARE;
1893        J2dRlsTraceLn(J2D_TRACE_VERBOSE, "  | CAPS_TEXNONSQUARE");
1894    }
1895    return S_OK;
1896}
1897