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