Implemented sampler state caching in the RenderStateCache.

TRAC #22251

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

git-svn-id: https://angleproject.googlecode.com/svn/branches/dx11proto@1664 736b8ea6-26fd-11df-bfd4-992fa37f6226
diff --git a/src/libGLESv2/renderer/RenderStateCache.cpp b/src/libGLESv2/renderer/RenderStateCache.cpp
index 5c36fb8..027b219 100644
--- a/src/libGLESv2/renderer/RenderStateCache.cpp
+++ b/src/libGLESv2/renderer/RenderStateCache.cpp
@@ -1,5 +1,5 @@
 //
-// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Copyright (c) 2012-2013 The ANGLE Project Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 //
@@ -16,17 +16,19 @@
 namespace rx
 {
 
-// MSDN's documentation of ID3D11Device::CreateBlendState, ID3D11Device::CreateRasterizerState
-// and ID3D11Device::CreateDepthStencilState claims the maximum number of unique states of each
-// type an application can create is 4096
+// MSDN's documentation of ID3D11Device::CreateBlendState, ID3D11Device::CreateRasterizerState,
+// ID3D11Device::CreateDepthStencilState and ID3D11Device::CreateSamplerState claims the maximum
+// number of unique states of each type an application can create is 4096
 const unsigned int RenderStateCache::kMaxBlendStates = 4096;
 const unsigned int RenderStateCache::kMaxRasterizerStates = 4096;
 const unsigned int RenderStateCache::kMaxDepthStencilStates = 4096;
+const unsigned int RenderStateCache::kMaxSamplerStates = 4096;
 
 RenderStateCache::RenderStateCache() : mDevice(NULL), mCounter(0),
                                        mBlendStateCache(kMaxBlendStates, hashBlendState, compareBlendStates),
                                        mRasterizerStateCache(kMaxRasterizerStates, hashRasterizerState, compareRasterizerStates),
-                                       mDepthStencilStateCache(kMaxDepthStencilStates, hashDepthStencilState, compareDepthStencilStates)
+                                       mDepthStencilStateCache(kMaxDepthStencilStates, hashDepthStencilState, compareDepthStencilStates),
+                                       mSamplerStateCache(kMaxSamplerStates, hashSamplerState, compareSamplerStates)
 {
 }
 
@@ -60,6 +62,12 @@
         i->second.first->Release();
     }
     mDepthStencilStateCache.clear();
+
+    for (SamplerStateMap::iterator i = mSamplerStateCache.begin(); i != mSamplerStateCache.end(); i++)
+    {
+        i->second.first->Release();
+    }
+    mSamplerStateCache.clear();
 }
 
 std::size_t RenderStateCache::hashBlendState(const gl::BlendState &blendState)
@@ -315,4 +323,83 @@
     }
 }
 
+std::size_t RenderStateCache::hashSamplerState(const gl::SamplerState &samplerState)
+{
+    static const unsigned int seed = 0xABCDEF98;
+
+    std::size_t hash = 0;
+    MurmurHash3_x86_32(&samplerState, sizeof(gl::SamplerState), seed, &hash);
+    return hash;
+}
+
+bool RenderStateCache::compareSamplerStates(const gl::SamplerState &a, const gl::SamplerState &b)
+{
+    return memcmp(&a, &b, sizeof(gl::DepthStencilState)) == 0;
+}
+
+ID3D11SamplerState* RenderStateCache::getSamplerState(const gl::SamplerState &samplerState)
+{
+    if (!mDevice)
+    {
+        ERR("RenderStateCache is not initialized.");
+        return NULL;
+    }
+
+    SamplerStateMap::iterator i = mSamplerStateCache.find(samplerState);
+    if (i != mSamplerStateCache.end())
+    {
+        SamplerStateCounterPair &state = i->second;
+        state.first->AddRef();
+        state.second = mCounter++;
+        return state.first;
+    }
+    else
+    {
+        if (mSamplerStateCache.size() >= kMaxSamplerStates)
+        {
+            TRACE("Overflowed the limit of %u sampler states, removing the least recently used "
+                  "to make room.", kMaxSamplerStates);
+
+            SamplerStateMap::iterator leastRecentlyUsed = mSamplerStateCache.begin();
+            for (SamplerStateMap::iterator i = mSamplerStateCache.begin(); i != mSamplerStateCache.end(); i++)
+            {
+                if (i->second.second < leastRecentlyUsed->second.second)
+                {
+                    leastRecentlyUsed = i;
+                }
+            }
+            leastRecentlyUsed->second.first->Release();
+            mSamplerStateCache.erase(leastRecentlyUsed);
+        }
+
+        D3D11_SAMPLER_DESC samplerDesc;
+        samplerDesc.Filter = gl_d3d11::ConvertFilter(samplerState.minFilter, samplerState.magFilter, samplerState.maxAnisotropy);
+        samplerDesc.AddressU = gl_d3d11::ConvertTextureWrap(samplerState.wrapS);
+        samplerDesc.AddressV = gl_d3d11::ConvertTextureWrap(samplerState.wrapT);
+        samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
+        samplerDesc.MipLODBias = static_cast<float>(samplerState.lodOffset);
+        samplerDesc.MaxAnisotropy = samplerState.maxAnisotropy;
+        samplerDesc.ComparisonFunc = D3D11_COMPARISON_NEVER;
+        samplerDesc.BorderColor[0] = 0.0f;
+        samplerDesc.BorderColor[1] = 0.0f;
+        samplerDesc.BorderColor[2] = 0.0f;
+        samplerDesc.BorderColor[3] = 0.0f;
+        samplerDesc.MinLOD = gl_d3d11::ConvertMinLOD(samplerState.minFilter);
+        samplerDesc.MaxLOD = gl_d3d11::ConvertMaxLOD(samplerState.minFilter);
+
+        ID3D11SamplerState *dx11SamplerState = NULL;
+        HRESULT result = mDevice->CreateSamplerState(&samplerDesc, &dx11SamplerState);
+        if (FAILED(result) || !dx11SamplerState)
+        {
+            ERR("Unable to create a ID3D11DepthStencilState, HRESULT: 0x%X.", result);
+            return NULL;
+        }
+
+        mSamplerStateCache.insert(std::make_pair(samplerState, std::make_pair(dx11SamplerState, mCounter++)));
+
+        dx11SamplerState->AddRef();
+        return dx11SamplerState;
+    }
+}
+
 }
\ No newline at end of file