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