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