1 // 2 // Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. 3 // Use of this source code is governed by a BSD-style license that can be 4 // found in the LICENSE file. 5 // 6 7 // Blit9.cpp: Surface copy utility class. 8 9 #include "libGLESv2/renderer/d3d/d3d9/Blit9.h" 10 #include "libGLESv2/renderer/d3d/d3d9/renderer9_utils.h" 11 #include "libGLESv2/renderer/d3d/d3d9/formatutils9.h" 12 #include "libGLESv2/renderer/d3d/d3d9/TextureStorage9.h" 13 #include "libGLESv2/renderer/d3d/d3d9/RenderTarget9.h" 14 #include "libGLESv2/renderer/d3d/d3d9/Renderer9.h" 15 #include "libGLESv2/Framebuffer.h" 16 #include "libGLESv2/FramebufferAttachment.h" 17 #include "libGLESv2/main.h" 18 19 namespace 20 { 21 // Precompiled shaders 22 #include "libGLESv2/renderer/d3d/d3d9/shaders/compiled/standardvs.h" 23 #include "libGLESv2/renderer/d3d/d3d9/shaders/compiled/flipyvs.h" 24 #include "libGLESv2/renderer/d3d/d3d9/shaders/compiled/passthroughps.h" 25 #include "libGLESv2/renderer/d3d/d3d9/shaders/compiled/luminanceps.h" 26 #include "libGLESv2/renderer/d3d/d3d9/shaders/compiled/componentmaskps.h" 27 28 const BYTE* const g_shaderCode[] = 29 { 30 g_vs20_standardvs, 31 g_vs20_flipyvs, 32 g_ps20_passthroughps, 33 g_ps20_luminanceps, 34 g_ps20_componentmaskps 35 }; 36 37 const size_t g_shaderSize[] = 38 { 39 sizeof(g_vs20_standardvs), 40 sizeof(g_vs20_flipyvs), 41 sizeof(g_ps20_passthroughps), 42 sizeof(g_ps20_luminanceps), 43 sizeof(g_ps20_componentmaskps) 44 }; 45 } 46 47 namespace rx 48 { 49 Blit9::Blit9(rx::Renderer9 *renderer) 50 : mRenderer(renderer), mQuadVertexBuffer(NULL), mQuadVertexDeclaration(NULL), mSavedStateBlock(NULL), mSavedRenderTarget(NULL), mSavedDepthStencil(NULL) 51 { 52 initGeometry(); 53 memset(mCompiledShaders, 0, sizeof(mCompiledShaders)); 54 } 55 56 Blit9::~Blit9() 57 { 58 SafeRelease(mSavedStateBlock); 59 SafeRelease(mQuadVertexBuffer); 60 SafeRelease(mQuadVertexDeclaration); 61 62 for (int i = 0; i < SHADER_COUNT; i++) 63 { 64 SafeRelease(mCompiledShaders[i]); 65 } 66 } 67 68 void Blit9::initGeometry() 69 { 70 static const float quad[] = 71 { 72 -1, -1, 73 -1, 1, 74 1, -1, 75 1, 1 76 }; 77 78 IDirect3DDevice9 *device = mRenderer->getDevice(); 79 80 HRESULT result = device->CreateVertexBuffer(sizeof(quad), D3DUSAGE_WRITEONLY, 0, D3DPOOL_DEFAULT, &mQuadVertexBuffer, NULL); 81 82 if (FAILED(result)) 83 { 84 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); 85 return gl::error(GL_OUT_OF_MEMORY); 86 } 87 88 void *lockPtr = NULL; 89 result = mQuadVertexBuffer->Lock(0, 0, &lockPtr, 0); 90 91 if (FAILED(result) || lockPtr == NULL) 92 { 93 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); 94 return gl::error(GL_OUT_OF_MEMORY); 95 } 96 97 memcpy(lockPtr, quad, sizeof(quad)); 98 mQuadVertexBuffer->Unlock(); 99 100 static const D3DVERTEXELEMENT9 elements[] = 101 { 102 { 0, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 }, 103 D3DDECL_END() 104 }; 105 106 result = device->CreateVertexDeclaration(elements, &mQuadVertexDeclaration); 107 108 if (FAILED(result)) 109 { 110 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); 111 return gl::error(GL_OUT_OF_MEMORY); 112 } 113 } 114 115 template <class D3DShaderType> 116 bool Blit9::setShader(ShaderId source, const char *profile, 117 D3DShaderType *(rx::Renderer9::*createShader)(const DWORD *, size_t length), 118 HRESULT (WINAPI IDirect3DDevice9::*setShader)(D3DShaderType*)) 119 { 120 IDirect3DDevice9 *device = mRenderer->getDevice(); 121 122 D3DShaderType *shader; 123 124 if (mCompiledShaders[source] != NULL) 125 { 126 shader = static_cast<D3DShaderType*>(mCompiledShaders[source]); 127 } 128 else 129 { 130 const BYTE* shaderCode = g_shaderCode[source]; 131 size_t shaderSize = g_shaderSize[source]; 132 133 shader = (mRenderer->*createShader)(reinterpret_cast<const DWORD*>(shaderCode), shaderSize); 134 if (!shader) 135 { 136 ERR("Failed to create shader for blit operation"); 137 return false; 138 } 139 140 mCompiledShaders[source] = shader; 141 } 142 143 HRESULT hr = (device->*setShader)(shader); 144 145 if (FAILED(hr)) 146 { 147 ERR("Failed to set shader for blit operation"); 148 return false; 149 } 150 151 return true; 152 } 153 154 bool Blit9::setVertexShader(ShaderId shader) 155 { 156 return setShader<IDirect3DVertexShader9>(shader, "vs_2_0", &rx::Renderer9::createVertexShader, &IDirect3DDevice9::SetVertexShader); 157 } 158 159 bool Blit9::setPixelShader(ShaderId shader) 160 { 161 return setShader<IDirect3DPixelShader9>(shader, "ps_2_0", &rx::Renderer9::createPixelShader, &IDirect3DDevice9::SetPixelShader); 162 } 163 164 RECT Blit9::getSurfaceRect(IDirect3DSurface9 *surface) const 165 { 166 D3DSURFACE_DESC desc; 167 surface->GetDesc(&desc); 168 169 RECT rect; 170 rect.left = 0; 171 rect.top = 0; 172 rect.right = desc.Width; 173 rect.bottom = desc.Height; 174 175 return rect; 176 } 177 178 bool Blit9::boxFilter(IDirect3DSurface9 *source, IDirect3DSurface9 *dest) 179 { 180 IDirect3DTexture9 *texture = copySurfaceToTexture(source, getSurfaceRect(source)); 181 if (!texture) 182 { 183 return false; 184 } 185 186 IDirect3DDevice9 *device = mRenderer->getDevice(); 187 188 saveState(); 189 190 device->SetTexture(0, texture); 191 device->SetRenderTarget(0, dest); 192 193 setVertexShader(SHADER_VS_STANDARD); 194 setPixelShader(SHADER_PS_PASSTHROUGH); 195 196 setCommonBlitState(); 197 device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); 198 device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); 199 200 setViewport(getSurfaceRect(dest), 0, 0); 201 202 render(); 203 204 SafeRelease(texture); 205 206 restoreState(); 207 208 return true; 209 } 210 211 bool Blit9::copy2D(gl::Framebuffer *framebuffer, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, TextureStorage *storage, GLint level) 212 { 213 RenderTarget9 *renderTarget = NULL; 214 IDirect3DSurface9 *source = NULL; 215 gl::FramebufferAttachment *colorbuffer = framebuffer->getColorbuffer(0); 216 217 if (colorbuffer) 218 { 219 renderTarget = d3d9::GetAttachmentRenderTarget(colorbuffer); 220 } 221 222 if (renderTarget) 223 { 224 source = renderTarget->getSurface(); 225 } 226 227 if (!source) 228 { 229 ERR("Failed to retrieve the render target."); 230 return gl::error(GL_OUT_OF_MEMORY, false); 231 } 232 233 TextureStorage9_2D *storage9 = TextureStorage9_2D::makeTextureStorage9_2D(storage); 234 IDirect3DSurface9 *destSurface = storage9->getSurfaceLevel(level, true); 235 bool result = false; 236 237 if (destSurface) 238 { 239 result = copy(source, sourceRect, destFormat, xoffset, yoffset, destSurface); 240 SafeRelease(destSurface); 241 } 242 243 SafeRelease(source); 244 return result; 245 } 246 247 bool Blit9::copyCube(gl::Framebuffer *framebuffer, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, TextureStorage *storage, GLenum target, GLint level) 248 { 249 RenderTarget9 *renderTarget = NULL; 250 IDirect3DSurface9 *source = NULL; 251 gl::FramebufferAttachment *colorbuffer = framebuffer->getColorbuffer(0); 252 253 if (colorbuffer) 254 { 255 renderTarget = d3d9::GetAttachmentRenderTarget(colorbuffer); 256 } 257 258 if (renderTarget) 259 { 260 source = renderTarget->getSurface(); 261 } 262 263 if (!source) 264 { 265 ERR("Failed to retrieve the render target."); 266 return gl::error(GL_OUT_OF_MEMORY, false); 267 } 268 269 TextureStorage9_Cube *storage9 = TextureStorage9_Cube::makeTextureStorage9_Cube(storage); 270 IDirect3DSurface9 *destSurface = storage9->getCubeMapSurface(target, level, true); 271 bool result = false; 272 273 if (destSurface) 274 { 275 result = copy(source, sourceRect, destFormat, xoffset, yoffset, destSurface); 276 SafeRelease(destSurface); 277 } 278 279 SafeRelease(source); 280 return result; 281 } 282 283 bool Blit9::copy(IDirect3DSurface9 *source, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, IDirect3DSurface9 *dest) 284 { 285 if (!dest) 286 { 287 return false; 288 } 289 290 IDirect3DDevice9 *device = mRenderer->getDevice(); 291 292 D3DSURFACE_DESC sourceDesc; 293 D3DSURFACE_DESC destDesc; 294 source->GetDesc(&sourceDesc); 295 dest->GetDesc(&destDesc); 296 297 if (sourceDesc.Format == destDesc.Format && destDesc.Usage & D3DUSAGE_RENDERTARGET && 298 d3d9_gl::IsFormatChannelEquivalent(destDesc.Format, destFormat)) // Can use StretchRect 299 { 300 RECT destRect = {xoffset, yoffset, xoffset + (sourceRect.right - sourceRect.left), yoffset + (sourceRect.bottom - sourceRect.top)}; 301 HRESULT result = device->StretchRect(source, &sourceRect, dest, &destRect, D3DTEXF_POINT); 302 303 if (FAILED(result)) 304 { 305 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); 306 return gl::error(GL_OUT_OF_MEMORY, false); 307 } 308 } 309 else 310 { 311 return formatConvert(source, sourceRect, destFormat, xoffset, yoffset, dest); 312 } 313 return true; 314 } 315 316 bool Blit9::formatConvert(IDirect3DSurface9 *source, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, IDirect3DSurface9 *dest) 317 { 318 IDirect3DTexture9 *texture = copySurfaceToTexture(source, sourceRect); 319 if (!texture) 320 { 321 return false; 322 } 323 324 IDirect3DDevice9 *device = mRenderer->getDevice(); 325 326 saveState(); 327 328 device->SetTexture(0, texture); 329 device->SetRenderTarget(0, dest); 330 331 setViewport(sourceRect, xoffset, yoffset); 332 333 setCommonBlitState(); 334 if (setFormatConvertShaders(destFormat)) 335 { 336 render(); 337 } 338 339 SafeRelease(texture); 340 341 restoreState(); 342 343 return true; 344 } 345 346 bool Blit9::setFormatConvertShaders(GLenum destFormat) 347 { 348 bool okay = setVertexShader(SHADER_VS_STANDARD); 349 350 switch (destFormat) 351 { 352 default: UNREACHABLE(); 353 case GL_RGBA: 354 case GL_BGRA_EXT: 355 case GL_RGB: 356 case GL_RG_EXT: 357 case GL_RED_EXT: 358 case GL_ALPHA: 359 okay = okay && setPixelShader(SHADER_PS_COMPONENTMASK); 360 break; 361 362 case GL_LUMINANCE: 363 case GL_LUMINANCE_ALPHA: 364 okay = okay && setPixelShader(SHADER_PS_LUMINANCE); 365 break; 366 } 367 368 if (!okay) 369 { 370 return false; 371 } 372 373 enum { X = 0, Y = 1, Z = 2, W = 3 }; 374 375 // The meaning of this constant depends on the shader that was selected. 376 // See the shader assembly code above for details. 377 // Allocate one array for both registers and split it into two float4's. 378 float psConst[8] = { 0 }; 379 float *multConst = &psConst[0]; 380 float *addConst = &psConst[4]; 381 382 switch (destFormat) 383 { 384 default: UNREACHABLE(); 385 case GL_RGBA: 386 case GL_BGRA_EXT: 387 multConst[X] = 1; 388 multConst[Y] = 1; 389 multConst[Z] = 1; 390 multConst[W] = 1; 391 addConst[X] = 0; 392 addConst[Y] = 0; 393 addConst[Z] = 0; 394 addConst[W] = 0; 395 break; 396 397 case GL_RGB: 398 multConst[X] = 1; 399 multConst[Y] = 1; 400 multConst[Z] = 1; 401 multConst[W] = 0; 402 addConst[X] = 0; 403 addConst[Y] = 0; 404 addConst[Z] = 0; 405 addConst[W] = 1; 406 break; 407 408 case GL_RG_EXT: 409 multConst[X] = 1; 410 multConst[Y] = 1; 411 multConst[Z] = 0; 412 multConst[W] = 0; 413 addConst[X] = 0; 414 addConst[Y] = 0; 415 addConst[Z] = 0; 416 addConst[W] = 1; 417 break; 418 419 case GL_RED_EXT: 420 multConst[X] = 1; 421 multConst[Y] = 0; 422 multConst[Z] = 0; 423 multConst[W] = 0; 424 addConst[X] = 0; 425 addConst[Y] = 0; 426 addConst[Z] = 0; 427 addConst[W] = 1; 428 break; 429 430 case GL_ALPHA: 431 multConst[X] = 0; 432 multConst[Y] = 0; 433 multConst[Z] = 0; 434 multConst[W] = 1; 435 addConst[X] = 0; 436 addConst[Y] = 0; 437 addConst[Z] = 0; 438 addConst[W] = 0; 439 break; 440 441 case GL_LUMINANCE: 442 multConst[X] = 1; 443 multConst[Y] = 0; 444 multConst[Z] = 0; 445 multConst[W] = 0; 446 addConst[X] = 0; 447 addConst[Y] = 0; 448 addConst[Z] = 0; 449 addConst[W] = 1; 450 break; 451 452 case GL_LUMINANCE_ALPHA: 453 multConst[X] = 1; 454 multConst[Y] = 0; 455 multConst[Z] = 0; 456 multConst[W] = 1; 457 addConst[X] = 0; 458 addConst[Y] = 0; 459 addConst[Z] = 0; 460 addConst[W] = 0; 461 break; 462 } 463 464 mRenderer->getDevice()->SetPixelShaderConstantF(0, psConst, 2); 465 466 return true; 467 } 468 469 IDirect3DTexture9 *Blit9::copySurfaceToTexture(IDirect3DSurface9 *surface, const RECT &sourceRect) 470 { 471 if (!surface) 472 { 473 return NULL; 474 } 475 476 IDirect3DDevice9 *device = mRenderer->getDevice(); 477 478 D3DSURFACE_DESC sourceDesc; 479 surface->GetDesc(&sourceDesc); 480 481 // Copy the render target into a texture 482 IDirect3DTexture9 *texture; 483 HRESULT result = device->CreateTexture(sourceRect.right - sourceRect.left, sourceRect.bottom - sourceRect.top, 1, D3DUSAGE_RENDERTARGET, sourceDesc.Format, D3DPOOL_DEFAULT, &texture, NULL); 484 485 if (FAILED(result)) 486 { 487 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); 488 return gl::error(GL_OUT_OF_MEMORY, (IDirect3DTexture9*)NULL); 489 } 490 491 IDirect3DSurface9 *textureSurface; 492 result = texture->GetSurfaceLevel(0, &textureSurface); 493 494 if (FAILED(result)) 495 { 496 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); 497 SafeRelease(texture); 498 return gl::error(GL_OUT_OF_MEMORY, (IDirect3DTexture9*)NULL); 499 } 500 501 mRenderer->endScene(); 502 result = device->StretchRect(surface, &sourceRect, textureSurface, NULL, D3DTEXF_NONE); 503 504 SafeRelease(textureSurface); 505 506 if (FAILED(result)) 507 { 508 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); 509 SafeRelease(texture); 510 return gl::error(GL_OUT_OF_MEMORY, (IDirect3DTexture9*)NULL); 511 } 512 513 return texture; 514 } 515 516 void Blit9::setViewport(const RECT &sourceRect, GLint xoffset, GLint yoffset) 517 { 518 IDirect3DDevice9 *device = mRenderer->getDevice(); 519 520 D3DVIEWPORT9 vp; 521 vp.X = xoffset; 522 vp.Y = yoffset; 523 vp.Width = sourceRect.right - sourceRect.left; 524 vp.Height = sourceRect.bottom - sourceRect.top; 525 vp.MinZ = 0.0f; 526 vp.MaxZ = 1.0f; 527 device->SetViewport(&vp); 528 529 float halfPixelAdjust[4] = { -1.0f/vp.Width, 1.0f/vp.Height, 0, 0 }; 530 device->SetVertexShaderConstantF(0, halfPixelAdjust, 1); 531 } 532 533 void Blit9::setCommonBlitState() 534 { 535 IDirect3DDevice9 *device = mRenderer->getDevice(); 536 537 device->SetDepthStencilSurface(NULL); 538 539 device->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID); 540 device->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE); 541 device->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); 542 device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); 543 device->SetRenderState(D3DRS_CLIPPLANEENABLE, 0); 544 device->SetRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_ALPHA | D3DCOLORWRITEENABLE_BLUE | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_RED); 545 device->SetRenderState(D3DRS_SRGBWRITEENABLE, FALSE); 546 device->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE); 547 548 device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT); 549 device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT); 550 device->SetSamplerState(0, D3DSAMP_SRGBTEXTURE, FALSE); 551 device->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); 552 device->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); 553 554 RECT scissorRect = {0}; // Scissoring is disabled for flipping, but we need this to capture and restore the old rectangle 555 device->SetScissorRect(&scissorRect); 556 557 for(int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) 558 { 559 device->SetStreamSourceFreq(i, 1); 560 } 561 } 562 563 void Blit9::render() 564 { 565 IDirect3DDevice9 *device = mRenderer->getDevice(); 566 567 HRESULT hr = device->SetStreamSource(0, mQuadVertexBuffer, 0, 2 * sizeof(float)); 568 hr = device->SetVertexDeclaration(mQuadVertexDeclaration); 569 570 mRenderer->startScene(); 571 hr = device->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); 572 } 573 574 void Blit9::saveState() 575 { 576 IDirect3DDevice9 *device = mRenderer->getDevice(); 577 578 HRESULT hr; 579 580 device->GetDepthStencilSurface(&mSavedDepthStencil); 581 device->GetRenderTarget(0, &mSavedRenderTarget); 582 583 if (mSavedStateBlock == NULL) 584 { 585 hr = device->BeginStateBlock(); 586 ASSERT(SUCCEEDED(hr) || hr == D3DERR_OUTOFVIDEOMEMORY || hr == E_OUTOFMEMORY); 587 588 setCommonBlitState(); 589 590 static const float dummyConst[8] = { 0 }; 591 592 device->SetVertexShader(NULL); 593 device->SetVertexShaderConstantF(0, dummyConst, 2); 594 device->SetPixelShader(NULL); 595 device->SetPixelShaderConstantF(0, dummyConst, 2); 596 597 D3DVIEWPORT9 dummyVp; 598 dummyVp.X = 0; 599 dummyVp.Y = 0; 600 dummyVp.Width = 1; 601 dummyVp.Height = 1; 602 dummyVp.MinZ = 0; 603 dummyVp.MaxZ = 1; 604 605 device->SetViewport(&dummyVp); 606 607 device->SetTexture(0, NULL); 608 609 device->SetStreamSource(0, mQuadVertexBuffer, 0, 0); 610 611 device->SetVertexDeclaration(mQuadVertexDeclaration); 612 613 hr = device->EndStateBlock(&mSavedStateBlock); 614 ASSERT(SUCCEEDED(hr) || hr == D3DERR_OUTOFVIDEOMEMORY || hr == E_OUTOFMEMORY); 615 } 616 617 ASSERT(mSavedStateBlock != NULL); 618 619 if (mSavedStateBlock != NULL) 620 { 621 hr = mSavedStateBlock->Capture(); 622 ASSERT(SUCCEEDED(hr)); 623 } 624 } 625 626 void Blit9::restoreState() 627 { 628 IDirect3DDevice9 *device = mRenderer->getDevice(); 629 630 device->SetDepthStencilSurface(mSavedDepthStencil); 631 SafeRelease(mSavedDepthStencil); 632 633 device->SetRenderTarget(0, mSavedRenderTarget); 634 SafeRelease(mSavedRenderTarget); 635 636 ASSERT(mSavedStateBlock != NULL); 637 638 if (mSavedStateBlock != NULL) 639 { 640 mSavedStateBlock->Apply(); 641 } 642 } 643 644 } 645