Restore state after Blit operations

TRAC #12202

Signed-off-by: Nicolas Capens
Signed-off-by: Daniel Koch

Author:    Andrew Lewycky

git-svn-id: https://angleproject.googlecode.com/svn/trunk@257 736b8ea6-26fd-11df-bfd4-992fa37f6226
diff --git a/src/libGLESv2/Blit.cpp b/src/libGLESv2/Blit.cpp
index 2cec8c2..0c288b4 100644
--- a/src/libGLESv2/Blit.cpp
+++ b/src/libGLESv2/Blit.cpp
@@ -122,7 +122,7 @@
 };
 
 Blit::Blit(Context *context)
-  : mContext(context), mQuadVertexBuffer(NULL), mQuadVertexDeclaration(NULL)
+  : mContext(context), mQuadVertexBuffer(NULL), mQuadVertexDeclaration(NULL), mSavedRenderTarget(NULL), mSavedDepthStencil(NULL), mSavedStateBlock(NULL)
 {
     initGeometry();
     memset(mCompiledShaders, 0, sizeof(mCompiledShaders));
@@ -130,6 +130,7 @@
 
 Blit::~Blit()
 {
+    if (mSavedStateBlock) mSavedStateBlock->Release();
     if (mQuadVertexBuffer) mQuadVertexBuffer->Release();
     if (mQuadVertexDeclaration) mQuadVertexDeclaration->Release();
 
@@ -262,6 +263,9 @@
     }
 
     IDirect3DDevice9 *device = getDevice();
+
+    saveState();
+
     device->SetTexture(0, texture);
     device->SetRenderTarget(0, dest);
 
@@ -278,6 +282,8 @@
 
     texture->Release();
 
+    restoreState();
+
     return true;
 }
 
@@ -291,6 +297,8 @@
 
     IDirect3DDevice9 *device = getDevice();
 
+    saveState();
+
     device->SetTexture(0, texture);
     device->SetRenderTarget(0, dest);
 
@@ -304,6 +312,8 @@
 
     texture->Release();
 
+    restoreState();
+
     return true;
 }
 
@@ -468,4 +478,82 @@
     hr = device->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
 }
 
+void Blit::saveState()
+{
+    IDirect3DDevice9 *device = getDevice();
+
+    HRESULT hr;
+
+    device->GetDepthStencilSurface(&mSavedDepthStencil);
+    device->GetRenderTarget(0, &mSavedRenderTarget);
+
+    if (mSavedStateBlock == NULL)
+    {
+        hr = device->BeginStateBlock();
+        ASSERT(SUCCEEDED(hr) || hr == D3DERR_OUTOFVIDEOMEMORY || hr == E_OUTOFMEMORY);
+
+        setCommonBlitState();
+
+        static const float dummyConst[4] = { 0, 0, 0, 0 };
+
+        device->SetVertexShader(NULL);
+        device->SetVertexShaderConstantF(0, dummyConst, 1);
+        device->SetPixelShader(NULL);
+        device->SetPixelShaderConstantF(0, dummyConst, 1);
+
+        D3DVIEWPORT9 dummyVp;
+        dummyVp.X = 0;
+        dummyVp.Y = 0;
+        dummyVp.Width = 1;
+        dummyVp.Height = 1;
+        dummyVp.MinZ = 0;
+        dummyVp.MaxZ = 1;
+
+        device->SetViewport(&dummyVp);
+
+        device->SetTexture(0, NULL);
+
+        device->SetStreamSource(0, mQuadVertexBuffer, 0, 0);
+
+        device->SetVertexDeclaration(mQuadVertexDeclaration);
+
+        hr = device->EndStateBlock(&mSavedStateBlock);
+        ASSERT(SUCCEEDED(hr) || hr == D3DERR_OUTOFVIDEOMEMORY || hr == E_OUTOFMEMORY);
+    }
+
+    ASSERT(mSavedStateBlock != NULL);
+
+    if (mSavedStateBlock != NULL)
+    {
+        hr = mSavedStateBlock->Capture();
+        ASSERT(SUCCEEDED(hr));
+    }
+}
+
+void Blit::restoreState()
+{
+    IDirect3DDevice9 *device = getDevice();
+
+    device->SetDepthStencilSurface(mSavedDepthStencil);
+    if (mSavedDepthStencil != NULL)
+    {
+        mSavedDepthStencil->Release();
+        mSavedDepthStencil = NULL;
+    }
+
+    device->SetRenderTarget(0, mSavedRenderTarget);
+    if (mSavedRenderTarget != NULL)
+    {
+        mSavedRenderTarget->Release();
+        mSavedRenderTarget = NULL;
+    }
+
+    ASSERT(mSavedStateBlock != NULL);
+
+    if (mSavedStateBlock != NULL)
+    {
+        mSavedStateBlock->Apply();
+    }
+}
+
 }
diff --git a/src/libGLESv2/Blit.h b/src/libGLESv2/Blit.h
index 8d87fa6..a83aac3 100644
--- a/src/libGLESv2/Blit.h
+++ b/src/libGLESv2/Blit.h
@@ -77,6 +77,12 @@
     bool setPixelShader(ShaderId shader);
     void render();
 
+    void saveState();
+    void restoreState();
+    IDirect3DStateBlock9 *mSavedStateBlock;
+    IDirect3DSurface9 *mSavedRenderTarget;
+    IDirect3DSurface9 *mSavedDepthStencil;
+
     DISALLOW_COPY_AND_ASSIGN(Blit);
 };
 }