Implemented masked clearing in Renderer11.

TRAC #22343

Signed-off-by: Nicolas Capens
Signed-off-by: Shannon Woods
Author: Geoff Lang

git-svn-id: https://angleproject.googlecode.com/svn/branches/dx11proto@1759 736b8ea6-26fd-11df-bfd4-992fa37f6226
diff --git a/src/libGLESv2/renderer/Renderer11.cpp b/src/libGLESv2/renderer/Renderer11.cpp
index 0f350ba..abc2e34 100644
--- a/src/libGLESv2/renderer/Renderer11.cpp
+++ b/src/libGLESv2/renderer/Renderer11.cpp
@@ -32,6 +32,9 @@
 #include "libGLESv2/renderer/shaders/compiled/passthroughlum11ps.h"
 #include "libGLESv2/renderer/shaders/compiled/passthroughlumalpha11ps.h"
 
+#include "libGLESv2/renderer/shaders/compiled/clear11vs.h"
+#include "libGLESv2/renderer/shaders/compiled/clear11ps.h"
+
 #include <sstream>
 
 namespace rx
@@ -69,6 +72,14 @@
     mCopyLumPS = NULL;
     mCopyLumAlphaPS = NULL;
 
+    mClearResourcesInitialized = false;
+    mClearVB = NULL;
+    mClearIL = NULL;
+    mClearVS = NULL;
+    mClearPS = NULL;
+    mClearScissorRS = NULL;
+    mClearNoScissorRS = NULL;
+
     mD3d11Module = NULL;
     mDxgiModule = NULL;
 
@@ -1220,8 +1231,7 @@
 
      if (needMaskedColorClear || needMaskedStencilClear || needScissoredClear)
      {
-         // TODO
-         UNIMPLEMENTED();
+         maskedClear(clearParams);
      }
      else
      {
@@ -1293,6 +1303,166 @@
     }
 }
 
+void Renderer11::maskedClear(const gl::ClearParameters &clearParams)
+{
+    HRESULT result;
+
+    if (!mClearResourcesInitialized)
+    {
+        ASSERT(!mClearVB && !mClearVS && !mClearPS && !mClearScissorRS && !mClearNoScissorRS);
+
+        D3D11_BUFFER_DESC vbDesc;
+        vbDesc.ByteWidth = sizeof(d3d11::PositionDepthColorVertex) * 4;
+        vbDesc.Usage = D3D11_USAGE_DYNAMIC;
+        vbDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
+        vbDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
+        vbDesc.MiscFlags = 0;
+        vbDesc.StructureByteStride = 0;
+
+        result = mDevice->CreateBuffer(&vbDesc, NULL, &mClearVB);
+        ASSERT(SUCCEEDED(result));
+        d3d11::SetDebugName(mClearVB, "Renderer11 masked clear vertex buffer");
+
+        D3D11_INPUT_ELEMENT_DESC quadLayout[] =
+        {
+            { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT,    0,  0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
+            { "COLOR",    0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
+        };
+
+        result = mDevice->CreateInputLayout(quadLayout, 2, g_VS_Clear, sizeof(g_VS_Clear), &mClearIL);
+        ASSERT(SUCCEEDED(result));
+        d3d11::SetDebugName(mClearIL, "Renderer11 masked clear input layout");
+
+        result = mDevice->CreateVertexShader(g_VS_Clear, sizeof(g_VS_Clear), NULL, &mClearVS);
+        ASSERT(SUCCEEDED(result));
+        d3d11::SetDebugName(mClearVS, "Renderer11 masked clear vertex shader");
+
+        result = mDevice->CreatePixelShader(g_PS_Clear, sizeof(g_PS_Clear), NULL, &mClearPS);
+        ASSERT(SUCCEEDED(result));
+        d3d11::SetDebugName(mClearPS, "Renderer11 masked clear pixel shader");
+
+        D3D11_RASTERIZER_DESC rsScissorDesc;
+        rsScissorDesc.FillMode = D3D11_FILL_SOLID;
+        rsScissorDesc.CullMode = D3D11_CULL_NONE;
+        rsScissorDesc.FrontCounterClockwise = FALSE;
+        rsScissorDesc.DepthBias = 0;
+        rsScissorDesc.DepthBiasClamp = 0.0f;
+        rsScissorDesc.SlopeScaledDepthBias = 0.0f;
+        rsScissorDesc.DepthClipEnable = FALSE;
+        rsScissorDesc.ScissorEnable = TRUE;
+        rsScissorDesc.MultisampleEnable = FALSE;
+        rsScissorDesc.AntialiasedLineEnable = FALSE;
+
+        result = mDevice->CreateRasterizerState(&rsScissorDesc, &mClearScissorRS);
+        ASSERT(SUCCEEDED(result));
+        d3d11::SetDebugName(mClearScissorRS, "Renderer11 masked clear scissor rasterizer state");
+
+        D3D11_RASTERIZER_DESC rsNoScissorDesc;
+        rsNoScissorDesc.FillMode = D3D11_FILL_SOLID;
+        rsNoScissorDesc.CullMode = D3D11_CULL_NONE;
+        rsNoScissorDesc.FrontCounterClockwise = FALSE;
+        rsNoScissorDesc.DepthBias = 0;
+        rsNoScissorDesc.DepthBiasClamp = 0.0f;
+        rsNoScissorDesc.SlopeScaledDepthBias = 0.0f;
+        rsNoScissorDesc.DepthClipEnable = FALSE;
+        rsNoScissorDesc.ScissorEnable = FALSE;
+        rsNoScissorDesc.MultisampleEnable = FALSE;
+        rsNoScissorDesc.AntialiasedLineEnable = FALSE;
+
+        result = mDevice->CreateRasterizerState(&rsNoScissorDesc, &mClearNoScissorRS);
+        ASSERT(SUCCEEDED(result));
+        d3d11::SetDebugName(mClearNoScissorRS, "Renderer11 masked clear no scissor rasterizer state");
+
+        mClearResourcesInitialized = true;
+    }
+
+    // Prepare the depth stencil state to write depth values if the depth should be cleared
+    // and stencil values if the stencil should be cleared
+    gl::DepthStencilState glDSState;
+    glDSState.depthTest = (clearParams.mask & GL_DEPTH_BUFFER_BIT) != 0;
+    glDSState.depthFunc = GL_ALWAYS;
+    glDSState.depthMask = (clearParams.mask & GL_DEPTH_BUFFER_BIT) != 0;
+    glDSState.stencilTest = (clearParams.mask & GL_STENCIL_BUFFER_BIT) != 0;
+    glDSState.stencilFunc = GL_ALWAYS;
+    glDSState.stencilMask = 0;
+    glDSState.stencilFail = GL_REPLACE;
+    glDSState.stencilPassDepthFail = GL_REPLACE;
+    glDSState.stencilPassDepthPass = GL_REPLACE;
+    glDSState.stencilWritemask = clearParams.stencilWriteMask;
+    glDSState.stencilBackFunc = GL_ALWAYS;
+    glDSState.stencilBackMask = 0;
+    glDSState.stencilBackFail = GL_REPLACE;
+    glDSState.stencilBackPassDepthFail = GL_REPLACE;
+    glDSState.stencilBackPassDepthPass = GL_REPLACE;
+    glDSState.stencilBackWritemask = clearParams.stencilWriteMask;
+
+    int stencilClear = clearParams.stencilClearValue & 0x000000FF;
+
+    ID3D11DepthStencilState *dsState = mStateCache.getDepthStencilState(glDSState);
+
+    // Prepare the blend state to use a write mask if the color buffer should be cleared
+    gl::BlendState glBlendState;
+    glBlendState.blend = false;
+    glBlendState.sourceBlendRGB = GL_ONE;
+    glBlendState.destBlendRGB = GL_ZERO;
+    glBlendState.sourceBlendAlpha = GL_ONE;
+    glBlendState.destBlendAlpha = GL_ZERO;
+    glBlendState.blendEquationRGB = GL_FUNC_ADD;
+    glBlendState.blendEquationAlpha = GL_FUNC_ADD;
+    glBlendState.colorMaskRed = (clearParams.mask & GL_COLOR_BUFFER_BIT) ? clearParams.colorMaskRed : false;
+    glBlendState.colorMaskGreen = (clearParams.mask & GL_COLOR_BUFFER_BIT) ? clearParams.colorMaskGreen : false;
+    glBlendState.colorMaskBlue = (clearParams.mask & GL_COLOR_BUFFER_BIT) ? clearParams.colorMaskBlue : false;
+    glBlendState.colorMaskBlue = (clearParams.mask & GL_COLOR_BUFFER_BIT) ? clearParams.colorMaskBlue : false;
+    glBlendState.sampleAlphaToCoverage = false;
+    glBlendState.dither = false;
+
+    static const float blendFactors[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
+    static const UINT sampleMask = 0xFFFFFFFF;
+
+    ID3D11BlendState *blendState = mStateCache.getBlendState(glBlendState);
+
+    // Set the vertices
+    D3D11_MAPPED_SUBRESOURCE mappedResource;
+    result = mDeviceContext->Map(mClearVB, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
+    if (FAILED(result))
+    {
+        ERR("Failed to map masked clear vertex buffer, HRESULT: 0x%X.", result);
+        return;
+    }
+
+    d3d11::PositionDepthColorVertex *vertices = reinterpret_cast<d3d11::PositionDepthColorVertex*>(mappedResource.pData);
+
+    float depthClear = gl::clamp01(clearParams.depthClearValue);
+    d3d11::SetPositionDepthColorVertex(&vertices[0], -1.0f,  1.0f, depthClear, clearParams.colorClearValue);
+    d3d11::SetPositionDepthColorVertex(&vertices[1], -1.0f, -1.0f, depthClear, clearParams.colorClearValue);
+    d3d11::SetPositionDepthColorVertex(&vertices[2],  1.0f,  1.0f, depthClear, clearParams.colorClearValue);
+    d3d11::SetPositionDepthColorVertex(&vertices[3],  1.0f, -1.0f, depthClear, clearParams.colorClearValue);
+
+    mDeviceContext->Unmap(mClearVB, 0);
+
+    // Apply state
+    mDeviceContext->OMSetBlendState(blendState, blendFactors, sampleMask);
+    mDeviceContext->OMSetDepthStencilState(dsState, stencilClear);
+    mDeviceContext->RSSetState(mScissorEnabled ? mClearScissorRS : mClearNoScissorRS);
+
+    // Apply shaders
+    mDeviceContext->IASetInputLayout(mClearIL);
+    mDeviceContext->VSSetShader(mClearVS, NULL, 0);
+    mDeviceContext->PSSetShader(mClearPS, NULL, 0);
+
+    // Apply vertex buffer
+    static UINT stride = sizeof(d3d11::PositionDepthColorVertex);
+    static UINT startIdx = 0;
+    mDeviceContext->IASetVertexBuffers(0, 1, &mClearVB, &stride, &startIdx);
+    mDeviceContext->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
+
+    // Draw the clear quad
+    mDeviceContext->Draw(4, 0);
+
+    // Clean up
+    markAllStateDirty();
+}
+
 void Renderer11::markAllStateDirty()
 {
     mAppliedRenderTargetSerial = 0;
@@ -1391,6 +1561,44 @@
     }
 
     mCopyResourcesInitialized = false;
+
+    if (mClearVB)
+    {
+        mClearVB->Release();
+        mClearVB = NULL;
+    }
+
+    if (mClearIL)
+    {
+        mClearIL->Release();
+        mClearIL = NULL;
+    }
+
+    if (mClearVS)
+    {
+        mClearVS->Release();
+        mClearVS = NULL;
+    }
+
+    if (mClearPS)
+    {
+        mClearPS->Release();
+        mClearPS = NULL;
+    }
+
+    if (mClearScissorRS)
+    {
+        mClearScissorRS->Release();
+        mClearScissorRS = NULL;
+    }
+
+    if (mClearNoScissorRS)
+    {
+        mClearNoScissorRS->Release();
+        mClearNoScissorRS = NULL;
+    }
+
+    mClearResourcesInitialized = false;
 }
 
 void Renderer11::markDeviceLost()