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