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