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