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