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(¶ms, 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(¶ms); 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 }