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