Implemented Renderer9::clear.

TRAC #22125

Signed-off-by: Shannon Woods
Signed-off-by: Daniel Koch

git-svn-id: https://angleproject.googlecode.com/svn/branches/dx11proto@1486 736b8ea6-26fd-11df-bfd4-992fa37f6226
diff --git a/src/libGLESv2/renderer/Renderer9.cpp b/src/libGLESv2/renderer/Renderer9.cpp
index 108abd6..039af19 100644
--- a/src/libGLESv2/renderer/Renderer9.cpp
+++ b/src/libGLESv2/renderer/Renderer9.cpp
@@ -88,6 +88,8 @@
     mMaxSupportedSamples = 0;
 
     mVertexDataManager = NULL;
+
+    mMaskedClearSavedState = NULL;
 }
 
 Renderer9::~Renderer9()
@@ -1121,9 +1123,186 @@
 
 void Renderer9::clear(const gl::ClearParameters &clearParams, gl::Framebuffer *frameBuffer)
 {
-    mForceSetDepthStencilState = true;
+    D3DCOLOR color = D3DCOLOR_ARGB(gl::unorm<8>(clearParams.colorClearValue.alpha),
+                                   gl::unorm<8>(clearParams.colorClearValue.red),
+                                   gl::unorm<8>(clearParams.colorClearValue.green),
+                                   gl::unorm<8>(clearParams.colorClearValue.blue));
+    float depth = gl::clamp01(clearParams.depthClearValue);
+    int stencil = clearParams.stencilClearValue & 0x000000FF;
 
-    // TODO
+    unsigned int stencilUnmasked = 0x0;
+    if ((clearParams.mask & GL_STENCIL_BUFFER_BIT) && frameBuffer->hasStencil())
+    {
+        unsigned int stencilSize = gl::GetStencilSize(frameBuffer->getStencilbuffer()->getActualFormat());
+        stencilUnmasked = (0x1 << stencilSize) - 1;
+    }
+
+    bool alphaUnmasked = (gl::GetAlphaSize(mRenderTargetDesc.format) == 0) || clearParams.colorMaskAlpha;
+
+    const bool needMaskedStencilClear = (clearParams.mask & GL_STENCIL_BUFFER_BIT) &&
+                                        (clearParams.stencilWriteMask & stencilUnmasked) != stencilUnmasked;
+    const bool needMaskedColorClear = (clearParams.mask & GL_COLOR_BUFFER_BIT) &&
+                                      !(clearParams.colorMaskRed && clearParams.colorMaskGreen &&
+                                        clearParams.colorMaskBlue && alphaUnmasked);
+
+    if (needMaskedColorClear || needMaskedStencilClear)
+    {
+        // State which is altered in all paths from this point to the clear call is saved.
+        // State which is altered in only some paths will be flagged dirty in the case that
+        //  that path is taken.
+        HRESULT hr;
+        if (mMaskedClearSavedState == NULL)
+        {
+            hr = mDevice->BeginStateBlock();
+            ASSERT(SUCCEEDED(hr) || hr == D3DERR_OUTOFVIDEOMEMORY || hr == E_OUTOFMEMORY);
+
+            mDevice->SetRenderState(D3DRS_ZWRITEENABLE, FALSE);
+            mDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_ALWAYS);
+            mDevice->SetRenderState(D3DRS_ZENABLE, FALSE);
+            mDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
+            mDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
+            mDevice->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
+            mDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
+            mDevice->SetRenderState(D3DRS_CLIPPLANEENABLE, 0);
+            mDevice->SetRenderState(D3DRS_COLORWRITEENABLE, 0);
+            mDevice->SetRenderState(D3DRS_STENCILENABLE, FALSE);
+            mDevice->SetPixelShader(NULL);
+            mDevice->SetVertexShader(NULL);
+            mDevice->SetFVF(D3DFVF_XYZRHW | D3DFVF_DIFFUSE);
+            mDevice->SetStreamSource(0, NULL, 0, 0);
+            mDevice->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE);
+            mDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
+            mDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TFACTOR);
+            mDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
+            mDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TFACTOR);
+            mDevice->SetRenderState(D3DRS_TEXTUREFACTOR, color);
+            mDevice->SetRenderState(D3DRS_MULTISAMPLEMASK, 0xFFFFFFFF);
+
+            for(int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
+            {
+                mDevice->SetStreamSourceFreq(i, 1);
+            }
+
+            hr = mDevice->EndStateBlock(&mMaskedClearSavedState);
+            ASSERT(SUCCEEDED(hr) || hr == D3DERR_OUTOFVIDEOMEMORY || hr == E_OUTOFMEMORY);
+        }
+
+        ASSERT(mMaskedClearSavedState != NULL);
+
+        if (mMaskedClearSavedState != NULL)
+        {
+            hr = mMaskedClearSavedState->Capture();
+            ASSERT(SUCCEEDED(hr));
+        }
+
+        mDevice->SetRenderState(D3DRS_ZWRITEENABLE, FALSE);
+        mDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_ALWAYS);
+        mDevice->SetRenderState(D3DRS_ZENABLE, FALSE);
+        mDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
+        mDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
+        mDevice->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
+        mDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
+        mDevice->SetRenderState(D3DRS_CLIPPLANEENABLE, 0);
+
+        if (clearParams.mask & GL_COLOR_BUFFER_BIT)
+        {
+            mDevice->SetRenderState(D3DRS_COLORWRITEENABLE,
+                                    gl_d3d9::ConvertColorMask(clearParams.colorMaskRed,
+                                                              clearParams.colorMaskGreen,
+                                                              clearParams.colorMaskBlue,
+                                                              clearParams.colorMaskAlpha));
+        }
+        else
+        {
+            mDevice->SetRenderState(D3DRS_COLORWRITEENABLE, 0);
+        }
+
+        if (stencilUnmasked != 0x0 && (clearParams.mask & GL_STENCIL_BUFFER_BIT))
+        {
+            mDevice->SetRenderState(D3DRS_STENCILENABLE, TRUE);
+            mDevice->SetRenderState(D3DRS_TWOSIDEDSTENCILMODE, FALSE);
+            mDevice->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_ALWAYS);
+            mDevice->SetRenderState(D3DRS_STENCILREF, stencil);
+            mDevice->SetRenderState(D3DRS_STENCILWRITEMASK, clearParams.stencilWriteMask);
+            mDevice->SetRenderState(D3DRS_STENCILFAIL, D3DSTENCILOP_REPLACE);
+            mDevice->SetRenderState(D3DRS_STENCILZFAIL, D3DSTENCILOP_REPLACE);
+            mDevice->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE);
+        }
+        else
+        {
+            mDevice->SetRenderState(D3DRS_STENCILENABLE, FALSE);
+        }
+
+        mDevice->SetPixelShader(NULL);
+        mDevice->SetVertexShader(NULL);
+        mDevice->SetFVF(D3DFVF_XYZRHW);
+        mDevice->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE);
+        mDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
+        mDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TFACTOR);
+        mDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
+        mDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TFACTOR);
+        mDevice->SetRenderState(D3DRS_TEXTUREFACTOR, color);
+        mDevice->SetRenderState(D3DRS_MULTISAMPLEMASK, 0xFFFFFFFF);
+
+        for(int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
+        {
+            mDevice->SetStreamSourceFreq(i, 1);
+        }
+
+        float quad[4][4];   // A quadrilateral covering the target, aligned to match the edges
+        quad[0][0] = -0.5f;
+        quad[0][1] = mRenderTargetDesc.height - 0.5f;
+        quad[0][2] = 0.0f;
+        quad[0][3] = 1.0f;
+
+        quad[1][0] = mRenderTargetDesc.width - 0.5f;
+        quad[1][1] = mRenderTargetDesc.height - 0.5f;
+        quad[1][2] = 0.0f;
+        quad[1][3] = 1.0f;
+
+        quad[2][0] = -0.5f;
+        quad[2][1] = -0.5f;
+        quad[2][2] = 0.0f;
+        quad[2][3] = 1.0f;
+
+        quad[3][0] = mRenderTargetDesc.width - 0.5f;
+        quad[3][1] = -0.5f;
+        quad[3][2] = 0.0f;
+        quad[3][3] = 1.0f;
+
+        startScene();
+        mDevice->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, quad, sizeof(float[4]));
+
+        if (clearParams.mask & GL_DEPTH_BUFFER_BIT)
+        {
+            mDevice->SetRenderState(D3DRS_ZENABLE, TRUE);
+            mDevice->SetRenderState(D3DRS_ZWRITEENABLE, TRUE);
+            mDevice->Clear(0, NULL, D3DCLEAR_ZBUFFER, color, depth, stencil);
+        }
+
+        if (mMaskedClearSavedState != NULL)
+        {
+            mMaskedClearSavedState->Apply();
+        }
+    }
+    else if (clearParams.mask)
+    {
+        DWORD dxClearFlags = 0;
+        if (clearParams.mask & GL_COLOR_BUFFER_BIT)
+        {
+            dxClearFlags |= D3DCLEAR_TARGET;
+        }
+        if (clearParams.mask & GL_DEPTH_BUFFER_BIT)
+        {
+            dxClearFlags |= D3DCLEAR_ZBUFFER;
+        }
+        if (clearParams.mask & GL_STENCIL_BUFFER_BIT)
+        {
+            dxClearFlags |= D3DCLEAR_STENCIL;
+        }
+
+        mDevice->Clear(0, NULL, dxClearFlags, color, depth, stencil);
+    }
 }
 
 void Renderer9::markAllStateDirty()
@@ -1151,6 +1330,12 @@
         mEventQueryPool.pop_back();
     }
 
+    if (mMaskedClearSavedState)
+    {
+        mMaskedClearSavedState->Release();
+        mMaskedClearSavedState = NULL;
+    }
+
     mVertexShaderCache.clear();
     mPixelShaderCache.clear();