Added Rasterizer state caching to the RenderStateCache.

TRAC #22043

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

Author:    Geoff Lang

git-svn-id: https://angleproject.googlecode.com/svn/branches/dx11proto@1435 736b8ea6-26fd-11df-bfd4-992fa37f6226
diff --git a/src/libGLESv2/renderer/RenderStateCache.cpp b/src/libGLESv2/renderer/RenderStateCache.cpp
index bd46886..170b5cf 100644
--- a/src/libGLESv2/renderer/RenderStateCache.cpp
+++ b/src/libGLESv2/renderer/RenderStateCache.cpp
@@ -17,7 +17,8 @@
 {
 
 RenderStateCache::RenderStateCache() : mDevice(NULL), mCounter(0),
-                                       mBlendStateCache(kMaxBlendStates, hashBlendState, compareBlendStates)
+                                       mBlendStateCache(kMaxBlendStates, hashBlendState, compareBlendStates),
+                                       mRasterizerStateCache(kMaxRasterizerStates, hashRasterizerState, compareRasterizerStates)
 {
 }
 
@@ -39,6 +40,12 @@
         i->second.first->Release();
     }
     mBlendStateCache.clear();
+
+    for (RasterizerStateMap::iterator i = mRasterizerStateCache.begin(); i != mRasterizerStateCache.end(); i++)
+    {
+        i->second.first->Release();
+    }
+    mRasterizerStateCache.clear();
 }
 
 std::size_t RenderStateCache::hashBlendState(const gl::BlendState &blendState)
@@ -136,4 +143,89 @@
     }
 }
 
+std::size_t RenderStateCache::hashRasterizerState(const RasterizerStateKey &rasterState)
+{
+    static const unsigned int seed = 0xABCDEF98;
+
+    std::size_t hash = 0;
+    MurmurHash3_x86_32(&rasterState, sizeof(RasterizerStateKey), seed, &hash);
+    return hash;
+}
+
+bool RenderStateCache::compareRasterizerStates(const RasterizerStateKey &a, const RasterizerStateKey &b)
+{
+    return memcmp(&a, &b, sizeof(RasterizerStateKey)) == 0;
+}
+
+// MSDN's documentation of ID3D11Device::CreateRasterizerState  claims the maximum number of
+// unique rasterizer states an application can create is 4096
+const unsigned int RenderStateCache::kMaxRasterizerStates = 4096;
+
+ID3D11RasterizerState *RenderStateCache::getRasterizerState(const gl::RasterizerState &rasterState,
+                                                            unsigned int depthSize)
+{
+    if (!mDevice)
+    {
+        ERR("RenderStateCache is not initialized.");
+        return NULL;
+    }
+
+    RasterizerStateKey key;
+    key.rasterizerState = rasterState;
+    key.depthSize = depthSize;
+
+    RasterizerStateMap::iterator i = mRasterizerStateCache.find(key);
+    if (i != mRasterizerStateCache.end())
+    {
+        RasterizerStateCounterPair &state = i->second;
+        state.first->AddRef();
+        state.second = mCounter++;
+        return state.first;
+    }
+    else
+    {
+        if (mRasterizerStateCache.size() >= kMaxRasterizerStates)
+        {
+            TRACE("Overflowed the limit of %u rasterizer states, removing the least recently used "
+                  "to make room.", kMaxRasterizerStates);
+
+            RasterizerStateMap::iterator leastRecentlyUsed = mRasterizerStateCache.begin();
+            for (RasterizerStateMap::iterator i = mRasterizerStateCache.begin(); i != mRasterizerStateCache.end(); i++)
+            {
+                if (i->second.second < leastRecentlyUsed->second.second)
+                {
+                    leastRecentlyUsed = i;
+                }
+            }
+            leastRecentlyUsed->second.first->Release();
+            mRasterizerStateCache.erase(leastRecentlyUsed);
+        }
+
+        D3D11_RASTERIZER_DESC rasterDesc;
+        rasterDesc.FillMode = D3D11_FILL_SOLID;
+        rasterDesc.CullMode = gl_d3d11::ConvertCullMode(rasterState.cullFace, rasterState.cullMode);
+        rasterDesc.FrontCounterClockwise = (rasterState.frontFace == GL_CCW) ? TRUE : FALSE;
+        rasterDesc.DepthBias = ldexp(rasterState.polygonOffsetUnits, -static_cast<int>(depthSize));
+        rasterDesc.DepthBiasClamp = 0.0f; // MSDN documentation of DepthBiasClamp implies a value of zero will preform no clamping, must be tested though.
+        rasterDesc.SlopeScaledDepthBias = rasterState.polygonOffsetUnits;
+        rasterDesc.DepthClipEnable = TRUE;
+        rasterDesc.ScissorEnable = rasterState.scissorTest ? TRUE : FALSE;
+        rasterDesc.MultisampleEnable = TRUE;
+        rasterDesc.AntialiasedLineEnable = FALSE;
+
+        ID3D11RasterizerState* dx11RasterizerState = NULL;
+        HRESULT result = mDevice->CreateRasterizerState(&rasterDesc, &dx11RasterizerState);
+        if (FAILED(result) || !dx11RasterizerState)
+        {
+            ERR("Unable to create a ID3D11RasterizerState, HRESULT: 0x%X.", result);
+            return NULL;
+        }
+
+        mRasterizerStateCache.insert(std::make_pair(key, std::make_pair(dx11RasterizerState, mCounter++)));
+
+        dx11RasterizerState->AddRef();
+        return dx11RasterizerState;
+    }
+}
+
 }
\ No newline at end of file