Home | History | Annotate | Download | only in d3d9
      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