• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include "precompiled.h"
2 //
3 // Copyright (c) 2012-2013 The ANGLE Project Authors. All rights reserved.
4 // Use of this source code is governed by a BSD-style license that can be
5 // found in the LICENSE file.
6 //
7 
8 // RenderStateCache.cpp: Defines rx::RenderStateCache, a cache of Direct3D render
9 // state objects.
10 
11 #include "libGLESv2/renderer/RenderStateCache.h"
12 #include "libGLESv2/renderer/renderer11_utils.h"
13 
14 #include "common/debug.h"
15 #include "third_party/murmurhash/MurmurHash3.h"
16 
17 namespace rx
18 {
19 
20 // MSDN's documentation of ID3D11Device::CreateBlendState, ID3D11Device::CreateRasterizerState,
21 // ID3D11Device::CreateDepthStencilState and ID3D11Device::CreateSamplerState claims the maximum
22 // number of unique states of each type an application can create is 4096
23 const unsigned int RenderStateCache::kMaxBlendStates = 4096;
24 const unsigned int RenderStateCache::kMaxRasterizerStates = 4096;
25 const unsigned int RenderStateCache::kMaxDepthStencilStates = 4096;
26 const unsigned int RenderStateCache::kMaxSamplerStates = 4096;
27 
RenderStateCache()28 RenderStateCache::RenderStateCache() : mDevice(NULL), mCounter(0),
29                                        mBlendStateCache(kMaxBlendStates, hashBlendState, compareBlendStates),
30                                        mRasterizerStateCache(kMaxRasterizerStates, hashRasterizerState, compareRasterizerStates),
31                                        mDepthStencilStateCache(kMaxDepthStencilStates, hashDepthStencilState, compareDepthStencilStates),
32                                        mSamplerStateCache(kMaxSamplerStates, hashSamplerState, compareSamplerStates)
33 {
34 }
35 
~RenderStateCache()36 RenderStateCache::~RenderStateCache()
37 {
38     clear();
39 }
40 
initialize(ID3D11Device * device)41 void RenderStateCache::initialize(ID3D11Device *device)
42 {
43     clear();
44     mDevice = device;
45 }
46 
clear()47 void RenderStateCache::clear()
48 {
49     for (BlendStateMap::iterator i = mBlendStateCache.begin(); i != mBlendStateCache.end(); i++)
50     {
51         i->second.first->Release();
52     }
53     mBlendStateCache.clear();
54 
55     for (RasterizerStateMap::iterator i = mRasterizerStateCache.begin(); i != mRasterizerStateCache.end(); i++)
56     {
57         i->second.first->Release();
58     }
59     mRasterizerStateCache.clear();
60 
61     for (DepthStencilStateMap::iterator i = mDepthStencilStateCache.begin(); i != mDepthStencilStateCache.end(); i++)
62     {
63         i->second.first->Release();
64     }
65     mDepthStencilStateCache.clear();
66 
67     for (SamplerStateMap::iterator i = mSamplerStateCache.begin(); i != mSamplerStateCache.end(); i++)
68     {
69         i->second.first->Release();
70     }
71     mSamplerStateCache.clear();
72 }
73 
hashBlendState(const gl::BlendState & blendState)74 std::size_t RenderStateCache::hashBlendState(const gl::BlendState &blendState)
75 {
76     static const unsigned int seed = 0xABCDEF98;
77 
78     std::size_t hash = 0;
79     MurmurHash3_x86_32(&blendState, sizeof(gl::BlendState), seed, &hash);
80     return hash;
81 }
82 
compareBlendStates(const gl::BlendState & a,const gl::BlendState & b)83 bool RenderStateCache::compareBlendStates(const gl::BlendState &a, const gl::BlendState &b)
84 {
85     return memcmp(&a, &b, sizeof(gl::BlendState)) == 0;
86 }
87 
getBlendState(const gl::BlendState & blendState)88 ID3D11BlendState *RenderStateCache::getBlendState(const gl::BlendState &blendState)
89 {
90     if (!mDevice)
91     {
92         ERR("RenderStateCache is not initialized.");
93         return NULL;
94     }
95 
96     BlendStateMap::iterator i = mBlendStateCache.find(blendState);
97     if (i != mBlendStateCache.end())
98     {
99         BlendStateCounterPair &state = i->second;
100         state.second = mCounter++;
101         return state.first;
102     }
103     else
104     {
105         if (mBlendStateCache.size() >= kMaxBlendStates)
106         {
107             TRACE("Overflowed the limit of %u blend states, removing the least recently used "
108                   "to make room.", kMaxBlendStates);
109 
110             BlendStateMap::iterator leastRecentlyUsed = mBlendStateCache.begin();
111             for (BlendStateMap::iterator i = mBlendStateCache.begin(); i != mBlendStateCache.end(); i++)
112             {
113                 if (i->second.second < leastRecentlyUsed->second.second)
114                 {
115                     leastRecentlyUsed = i;
116                 }
117             }
118             leastRecentlyUsed->second.first->Release();
119             mBlendStateCache.erase(leastRecentlyUsed);
120         }
121 
122         // Create a new blend state and insert it into the cache
123         D3D11_BLEND_DESC blendDesc = { 0 };
124         blendDesc.AlphaToCoverageEnable = blendState.sampleAlphaToCoverage;
125         blendDesc.IndependentBlendEnable = FALSE;
126 
127         for (unsigned int i = 0; i < D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; i++)
128         {
129             D3D11_RENDER_TARGET_BLEND_DESC &rtBlend = blendDesc.RenderTarget[i];
130 
131             rtBlend.BlendEnable = blendState.blend;
132             if (blendState.blend)
133             {
134                 rtBlend.SrcBlend = gl_d3d11::ConvertBlendFunc(blendState.sourceBlendRGB, false);
135                 rtBlend.DestBlend = gl_d3d11::ConvertBlendFunc(blendState.destBlendRGB, false);
136                 rtBlend.BlendOp = gl_d3d11::ConvertBlendOp(blendState.blendEquationRGB);
137 
138                 rtBlend.SrcBlendAlpha = gl_d3d11::ConvertBlendFunc(blendState.sourceBlendAlpha, true);
139                 rtBlend.DestBlendAlpha = gl_d3d11::ConvertBlendFunc(blendState.destBlendAlpha, true);
140                 rtBlend.BlendOpAlpha = gl_d3d11::ConvertBlendOp(blendState.blendEquationAlpha);
141             }
142 
143             rtBlend.RenderTargetWriteMask = gl_d3d11::ConvertColorMask(blendState.colorMaskRed,
144                                                                        blendState.colorMaskGreen,
145                                                                        blendState.colorMaskBlue,
146                                                                        blendState.colorMaskAlpha);
147         }
148 
149         ID3D11BlendState *dx11BlendState = NULL;
150         HRESULT result = mDevice->CreateBlendState(&blendDesc, &dx11BlendState);
151         if (FAILED(result) || !dx11BlendState)
152         {
153             ERR("Unable to create a ID3D11BlendState, HRESULT: 0x%X.", result);
154             return NULL;
155         }
156 
157         mBlendStateCache.insert(std::make_pair(blendState, std::make_pair(dx11BlendState, mCounter++)));
158 
159         return dx11BlendState;
160     }
161 }
162 
hashRasterizerState(const RasterizerStateKey & rasterState)163 std::size_t RenderStateCache::hashRasterizerState(const RasterizerStateKey &rasterState)
164 {
165     static const unsigned int seed = 0xABCDEF98;
166 
167     std::size_t hash = 0;
168     MurmurHash3_x86_32(&rasterState, sizeof(RasterizerStateKey), seed, &hash);
169     return hash;
170 }
171 
compareRasterizerStates(const RasterizerStateKey & a,const RasterizerStateKey & b)172 bool RenderStateCache::compareRasterizerStates(const RasterizerStateKey &a, const RasterizerStateKey &b)
173 {
174     return memcmp(&a, &b, sizeof(RasterizerStateKey)) == 0;
175 }
176 
getRasterizerState(const gl::RasterizerState & rasterState,bool scissorEnabled,unsigned int depthSize)177 ID3D11RasterizerState *RenderStateCache::getRasterizerState(const gl::RasterizerState &rasterState,
178                                                             bool scissorEnabled, unsigned int depthSize)
179 {
180     if (!mDevice)
181     {
182         ERR("RenderStateCache is not initialized.");
183         return NULL;
184     }
185 
186     RasterizerStateKey key;
187     key.rasterizerState = rasterState;
188     key.scissorEnabled = scissorEnabled;
189     key.depthSize = depthSize;
190 
191     RasterizerStateMap::iterator i = mRasterizerStateCache.find(key);
192     if (i != mRasterizerStateCache.end())
193     {
194         RasterizerStateCounterPair &state = i->second;
195         state.second = mCounter++;
196         return state.first;
197     }
198     else
199     {
200         if (mRasterizerStateCache.size() >= kMaxRasterizerStates)
201         {
202             TRACE("Overflowed the limit of %u rasterizer states, removing the least recently used "
203                   "to make room.", kMaxRasterizerStates);
204 
205             RasterizerStateMap::iterator leastRecentlyUsed = mRasterizerStateCache.begin();
206             for (RasterizerStateMap::iterator i = mRasterizerStateCache.begin(); i != mRasterizerStateCache.end(); i++)
207             {
208                 if (i->second.second < leastRecentlyUsed->second.second)
209                 {
210                     leastRecentlyUsed = i;
211                 }
212             }
213             leastRecentlyUsed->second.first->Release();
214             mRasterizerStateCache.erase(leastRecentlyUsed);
215         }
216 
217         D3D11_CULL_MODE cullMode = gl_d3d11::ConvertCullMode(rasterState.cullFace, rasterState.cullMode);
218 
219         // Disable culling if drawing points
220         if (rasterState.pointDrawMode)
221         {
222             cullMode = D3D11_CULL_NONE;
223         }
224 
225         D3D11_RASTERIZER_DESC rasterDesc;
226         rasterDesc.FillMode = D3D11_FILL_SOLID;
227         rasterDesc.CullMode = cullMode;
228         rasterDesc.FrontCounterClockwise = (rasterState.frontFace == GL_CCW) ? FALSE: TRUE;
229         rasterDesc.DepthBias = ldexp(rasterState.polygonOffsetUnits, -static_cast<int>(depthSize));
230         rasterDesc.DepthBiasClamp = 0.0f; // MSDN documentation of DepthBiasClamp implies a value of zero will preform no clamping, must be tested though.
231         rasterDesc.SlopeScaledDepthBias = rasterState.polygonOffsetFactor;
232         rasterDesc.DepthClipEnable = TRUE;
233         rasterDesc.ScissorEnable = scissorEnabled ? TRUE : FALSE;
234         rasterDesc.MultisampleEnable = rasterState.multiSample;
235         rasterDesc.AntialiasedLineEnable = FALSE;
236 
237         ID3D11RasterizerState *dx11RasterizerState = NULL;
238         HRESULT result = mDevice->CreateRasterizerState(&rasterDesc, &dx11RasterizerState);
239         if (FAILED(result) || !dx11RasterizerState)
240         {
241             ERR("Unable to create a ID3D11RasterizerState, HRESULT: 0x%X.", result);
242             return NULL;
243         }
244 
245         mRasterizerStateCache.insert(std::make_pair(key, std::make_pair(dx11RasterizerState, mCounter++)));
246 
247         return dx11RasterizerState;
248     }
249 }
250 
hashDepthStencilState(const gl::DepthStencilState & dsState)251 std::size_t RenderStateCache::hashDepthStencilState(const gl::DepthStencilState &dsState)
252 {
253     static const unsigned int seed = 0xABCDEF98;
254 
255     std::size_t hash = 0;
256     MurmurHash3_x86_32(&dsState, sizeof(gl::DepthStencilState), seed, &hash);
257     return hash;
258 }
259 
compareDepthStencilStates(const gl::DepthStencilState & a,const gl::DepthStencilState & b)260 bool RenderStateCache::compareDepthStencilStates(const gl::DepthStencilState &a, const gl::DepthStencilState &b)
261 {
262     return memcmp(&a, &b, sizeof(gl::DepthStencilState)) == 0;
263 }
264 
getDepthStencilState(const gl::DepthStencilState & dsState)265 ID3D11DepthStencilState *RenderStateCache::getDepthStencilState(const gl::DepthStencilState &dsState)
266 {
267     if (!mDevice)
268     {
269         ERR("RenderStateCache is not initialized.");
270         return NULL;
271     }
272 
273     DepthStencilStateMap::iterator i = mDepthStencilStateCache.find(dsState);
274     if (i != mDepthStencilStateCache.end())
275     {
276         DepthStencilStateCounterPair &state = i->second;
277         state.second = mCounter++;
278         return state.first;
279     }
280     else
281     {
282         if (mDepthStencilStateCache.size() >= kMaxDepthStencilStates)
283         {
284             TRACE("Overflowed the limit of %u depth stencil states, removing the least recently used "
285                   "to make room.", kMaxDepthStencilStates);
286 
287             DepthStencilStateMap::iterator leastRecentlyUsed = mDepthStencilStateCache.begin();
288             for (DepthStencilStateMap::iterator i = mDepthStencilStateCache.begin(); i != mDepthStencilStateCache.end(); i++)
289             {
290                 if (i->second.second < leastRecentlyUsed->second.second)
291                 {
292                     leastRecentlyUsed = i;
293                 }
294             }
295             leastRecentlyUsed->second.first->Release();
296             mDepthStencilStateCache.erase(leastRecentlyUsed);
297         }
298 
299         D3D11_DEPTH_STENCIL_DESC dsDesc = { 0 };
300         dsDesc.DepthEnable = dsState.depthTest ? TRUE : FALSE;
301         dsDesc.DepthWriteMask = gl_d3d11::ConvertDepthMask(dsState.depthMask);
302         dsDesc.DepthFunc = gl_d3d11::ConvertComparison(dsState.depthFunc);
303         dsDesc.StencilEnable = dsState.stencilTest ? TRUE : FALSE;
304         dsDesc.StencilReadMask = gl_d3d11::ConvertStencilMask(dsState.stencilMask);
305         dsDesc.StencilWriteMask = gl_d3d11::ConvertStencilMask(dsState.stencilWritemask);
306         dsDesc.FrontFace.StencilFailOp = gl_d3d11::ConvertStencilOp(dsState.stencilFail);
307         dsDesc.FrontFace.StencilDepthFailOp = gl_d3d11::ConvertStencilOp(dsState.stencilPassDepthFail);
308         dsDesc.FrontFace.StencilPassOp = gl_d3d11::ConvertStencilOp(dsState.stencilPassDepthPass);
309         dsDesc.FrontFace.StencilFunc = gl_d3d11::ConvertComparison(dsState.stencilFunc);
310         dsDesc.BackFace.StencilFailOp = gl_d3d11::ConvertStencilOp(dsState.stencilBackFail);
311         dsDesc.BackFace.StencilDepthFailOp = gl_d3d11::ConvertStencilOp(dsState.stencilBackPassDepthFail);
312         dsDesc.BackFace.StencilPassOp = gl_d3d11::ConvertStencilOp(dsState.stencilBackPassDepthPass);
313         dsDesc.BackFace.StencilFunc = gl_d3d11::ConvertComparison(dsState.stencilBackFunc);
314 
315         ID3D11DepthStencilState *dx11DepthStencilState = NULL;
316         HRESULT result = mDevice->CreateDepthStencilState(&dsDesc, &dx11DepthStencilState);
317         if (FAILED(result) || !dx11DepthStencilState)
318         {
319             ERR("Unable to create a ID3D11DepthStencilState, HRESULT: 0x%X.", result);
320             return NULL;
321         }
322 
323         mDepthStencilStateCache.insert(std::make_pair(dsState, std::make_pair(dx11DepthStencilState, mCounter++)));
324 
325         return dx11DepthStencilState;
326     }
327 }
328 
hashSamplerState(const gl::SamplerState & samplerState)329 std::size_t RenderStateCache::hashSamplerState(const gl::SamplerState &samplerState)
330 {
331     static const unsigned int seed = 0xABCDEF98;
332 
333     std::size_t hash = 0;
334     MurmurHash3_x86_32(&samplerState, sizeof(gl::SamplerState), seed, &hash);
335     return hash;
336 }
337 
compareSamplerStates(const gl::SamplerState & a,const gl::SamplerState & b)338 bool RenderStateCache::compareSamplerStates(const gl::SamplerState &a, const gl::SamplerState &b)
339 {
340     return memcmp(&a, &b, sizeof(gl::SamplerState)) == 0;
341 }
342 
getSamplerState(const gl::SamplerState & samplerState)343 ID3D11SamplerState *RenderStateCache::getSamplerState(const gl::SamplerState &samplerState)
344 {
345     if (!mDevice)
346     {
347         ERR("RenderStateCache is not initialized.");
348         return NULL;
349     }
350 
351     SamplerStateMap::iterator i = mSamplerStateCache.find(samplerState);
352     if (i != mSamplerStateCache.end())
353     {
354         SamplerStateCounterPair &state = i->second;
355         state.second = mCounter++;
356         return state.first;
357     }
358     else
359     {
360         if (mSamplerStateCache.size() >= kMaxSamplerStates)
361         {
362             TRACE("Overflowed the limit of %u sampler states, removing the least recently used "
363                   "to make room.", kMaxSamplerStates);
364 
365             SamplerStateMap::iterator leastRecentlyUsed = mSamplerStateCache.begin();
366             for (SamplerStateMap::iterator i = mSamplerStateCache.begin(); i != mSamplerStateCache.end(); i++)
367             {
368                 if (i->second.second < leastRecentlyUsed->second.second)
369                 {
370                     leastRecentlyUsed = i;
371                 }
372             }
373             leastRecentlyUsed->second.first->Release();
374             mSamplerStateCache.erase(leastRecentlyUsed);
375         }
376 
377         D3D11_SAMPLER_DESC samplerDesc;
378         samplerDesc.Filter = gl_d3d11::ConvertFilter(samplerState.minFilter, samplerState.magFilter, samplerState.maxAnisotropy);
379         samplerDesc.AddressU = gl_d3d11::ConvertTextureWrap(samplerState.wrapS);
380         samplerDesc.AddressV = gl_d3d11::ConvertTextureWrap(samplerState.wrapT);
381         samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
382         samplerDesc.MipLODBias = static_cast<float>(samplerState.lodOffset);
383         samplerDesc.MaxAnisotropy = samplerState.maxAnisotropy;
384         samplerDesc.ComparisonFunc = D3D11_COMPARISON_NEVER;
385         samplerDesc.BorderColor[0] = 0.0f;
386         samplerDesc.BorderColor[1] = 0.0f;
387         samplerDesc.BorderColor[2] = 0.0f;
388         samplerDesc.BorderColor[3] = 0.0f;
389         samplerDesc.MinLOD = gl_d3d11::ConvertMinLOD(samplerState.minFilter, samplerState.lodOffset);
390         samplerDesc.MaxLOD = gl_d3d11::ConvertMaxLOD(samplerState.minFilter, samplerState.lodOffset);
391 
392         ID3D11SamplerState *dx11SamplerState = NULL;
393         HRESULT result = mDevice->CreateSamplerState(&samplerDesc, &dx11SamplerState);
394         if (FAILED(result) || !dx11SamplerState)
395         {
396             ERR("Unable to create a ID3D11DepthStencilState, HRESULT: 0x%X.", result);
397             return NULL;
398         }
399 
400         mSamplerStateCache.insert(std::make_pair(samplerState, std::make_pair(dx11SamplerState, mCounter++)));
401 
402         return dx11SamplerState;
403     }
404 }
405 
406 }