blob: 170b5cf31a6d79da592d41df8a28611c9efe42e5 [file] [log] [blame]
daniel@transgaming.com0673d792012-11-28 19:37:44 +00001//
2// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7// RenderStateCache.cpp: Defines rx::RenderStateCache, a cache of Direct3D render
8// state objects.
9
10#include "libGLESv2/renderer/RenderStateCache.h"
11#include "libGLESv2/renderer/renderer11_utils.h"
12
13#include "common/debug.h"
14#include "third_party/murmurhash/MurmurHash3.h"
15
16namespace rx
17{
18
19RenderStateCache::RenderStateCache() : mDevice(NULL), mCounter(0),
daniel@transgaming.comed453e02012-11-28 19:38:11 +000020 mBlendStateCache(kMaxBlendStates, hashBlendState, compareBlendStates),
21 mRasterizerStateCache(kMaxRasterizerStates, hashRasterizerState, compareRasterizerStates)
daniel@transgaming.com0673d792012-11-28 19:37:44 +000022{
23}
24
25RenderStateCache::~RenderStateCache()
26{
27 clear();
28}
29
30void RenderStateCache::initialize(ID3D11Device* device)
31{
32 clear();
33 mDevice = device;
34}
35
36void RenderStateCache::clear()
37{
38 for (BlendStateMap::iterator i = mBlendStateCache.begin(); i != mBlendStateCache.end(); i++)
39 {
40 i->second.first->Release();
41 }
42 mBlendStateCache.clear();
daniel@transgaming.comed453e02012-11-28 19:38:11 +000043
44 for (RasterizerStateMap::iterator i = mRasterizerStateCache.begin(); i != mRasterizerStateCache.end(); i++)
45 {
46 i->second.first->Release();
47 }
48 mRasterizerStateCache.clear();
daniel@transgaming.com0673d792012-11-28 19:37:44 +000049}
50
51std::size_t RenderStateCache::hashBlendState(const gl::BlendState &blendState)
52{
53 static const unsigned int seed = 0xABCDEF98;
54
55 std::size_t hash = 0;
56 MurmurHash3_x86_32(&blendState, sizeof(gl::BlendState), seed, &hash);
57 return hash;
58}
59
60bool RenderStateCache::compareBlendStates(const gl::BlendState &a, const gl::BlendState &b)
61{
62 return memcmp(&a, &b, sizeof(gl::BlendState)) == 0;
63}
64
65// MSDN's documentation of ID3D11Device::CreateBlendState claims the maximum number of
66// unique blend states an application can create is 4096
67const unsigned int RenderStateCache::kMaxBlendStates = 4096;
68
69ID3D11BlendState *RenderStateCache::getBlendState(const gl::BlendState &blendState)
70{
71 if (!mDevice)
72 {
73 ERR("RenderStateCache is not initialized.");
74 return NULL;
75 }
76
77 BlendStateMap::iterator i = mBlendStateCache.find(blendState);
78 if (i != mBlendStateCache.end())
79 {
80 BlendStateCounterPair &state = i->second;
81 state.first->AddRef();
82 state.second = mCounter++;
83 return state.first;
84 }
85 else
86 {
87 if (mBlendStateCache.size() >= kMaxBlendStates)
88 {
89 TRACE("Overflowed the limit of %u blend states, removing the least recently used "
90 "to make room.", kMaxBlendStates);
91
92 BlendStateMap::iterator leastRecentlyUsed = mBlendStateCache.begin();
93 for (BlendStateMap::iterator i = mBlendStateCache.begin(); i != mBlendStateCache.end(); i++)
94 {
95 if (i->second.second < leastRecentlyUsed->second.second)
96 {
97 leastRecentlyUsed = i;
98 }
99 }
100 leastRecentlyUsed->second.first->Release();
101 mBlendStateCache.erase(leastRecentlyUsed);
102 }
103
104 // Create a new blend state and insert it into the cache
105 D3D11_BLEND_DESC blendDesc = { 0 };
106 blendDesc.AlphaToCoverageEnable = blendState.sampleAlphaToCoverage;
107 blendDesc.IndependentBlendEnable = FALSE;
108
109 for (unsigned int i = 0; i < D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; i++)
110 {
111 D3D11_RENDER_TARGET_BLEND_DESC &rtBlend = blendDesc.RenderTarget[i];
112
113 rtBlend.BlendEnable = blendState.blend;
114 if (blendState.blend)
115 {
116 rtBlend.SrcBlend = gl_d3d11::ConvertBlendFunc(blendState.sourceBlendRGB);
117 rtBlend.DestBlend = gl_d3d11::ConvertBlendFunc(blendState.destBlendRGB);
118 rtBlend.BlendOp = gl_d3d11::ConvertBlendOp(blendState.blendEquationRGB);
119
120 rtBlend.SrcBlendAlpha = gl_d3d11::ConvertBlendFunc(blendState.sourceBlendAlpha);
121 rtBlend.DestBlendAlpha = gl_d3d11::ConvertBlendFunc(blendState.destBlendAlpha);
122 rtBlend.BlendOpAlpha = gl_d3d11::ConvertBlendOp(blendState.blendEquationAlpha);
123
124 rtBlend.RenderTargetWriteMask = gl_d3d11::ConvertColorMask(blendState.colorMaskRed,
125 blendState.colorMaskGreen,
126 blendState.colorMaskBlue,
127 blendState.colorMaskAlpha);
128 }
129 }
130
131 ID3D11BlendState* dx11BlendState = NULL;
132 HRESULT result = mDevice->CreateBlendState(&blendDesc, &dx11BlendState);
133 if (FAILED(result) || !dx11BlendState)
134 {
135 ERR("Unable to create a ID3D11BlendState, HRESULT: 0x%X.", result);
136 return NULL;
137 }
138
139 mBlendStateCache.insert(std::make_pair(blendState, std::make_pair(dx11BlendState, mCounter++)));
140
141 dx11BlendState->AddRef();
142 return dx11BlendState;
143 }
144}
145
daniel@transgaming.comed453e02012-11-28 19:38:11 +0000146std::size_t RenderStateCache::hashRasterizerState(const RasterizerStateKey &rasterState)
147{
148 static const unsigned int seed = 0xABCDEF98;
149
150 std::size_t hash = 0;
151 MurmurHash3_x86_32(&rasterState, sizeof(RasterizerStateKey), seed, &hash);
152 return hash;
153}
154
155bool RenderStateCache::compareRasterizerStates(const RasterizerStateKey &a, const RasterizerStateKey &b)
156{
157 return memcmp(&a, &b, sizeof(RasterizerStateKey)) == 0;
158}
159
160// MSDN's documentation of ID3D11Device::CreateRasterizerState claims the maximum number of
161// unique rasterizer states an application can create is 4096
162const unsigned int RenderStateCache::kMaxRasterizerStates = 4096;
163
164ID3D11RasterizerState *RenderStateCache::getRasterizerState(const gl::RasterizerState &rasterState,
165 unsigned int depthSize)
166{
167 if (!mDevice)
168 {
169 ERR("RenderStateCache is not initialized.");
170 return NULL;
171 }
172
173 RasterizerStateKey key;
174 key.rasterizerState = rasterState;
175 key.depthSize = depthSize;
176
177 RasterizerStateMap::iterator i = mRasterizerStateCache.find(key);
178 if (i != mRasterizerStateCache.end())
179 {
180 RasterizerStateCounterPair &state = i->second;
181 state.first->AddRef();
182 state.second = mCounter++;
183 return state.first;
184 }
185 else
186 {
187 if (mRasterizerStateCache.size() >= kMaxRasterizerStates)
188 {
189 TRACE("Overflowed the limit of %u rasterizer states, removing the least recently used "
190 "to make room.", kMaxRasterizerStates);
191
192 RasterizerStateMap::iterator leastRecentlyUsed = mRasterizerStateCache.begin();
193 for (RasterizerStateMap::iterator i = mRasterizerStateCache.begin(); i != mRasterizerStateCache.end(); i++)
194 {
195 if (i->second.second < leastRecentlyUsed->second.second)
196 {
197 leastRecentlyUsed = i;
198 }
199 }
200 leastRecentlyUsed->second.first->Release();
201 mRasterizerStateCache.erase(leastRecentlyUsed);
202 }
203
204 D3D11_RASTERIZER_DESC rasterDesc;
205 rasterDesc.FillMode = D3D11_FILL_SOLID;
206 rasterDesc.CullMode = gl_d3d11::ConvertCullMode(rasterState.cullFace, rasterState.cullMode);
207 rasterDesc.FrontCounterClockwise = (rasterState.frontFace == GL_CCW) ? TRUE : FALSE;
208 rasterDesc.DepthBias = ldexp(rasterState.polygonOffsetUnits, -static_cast<int>(depthSize));
209 rasterDesc.DepthBiasClamp = 0.0f; // MSDN documentation of DepthBiasClamp implies a value of zero will preform no clamping, must be tested though.
210 rasterDesc.SlopeScaledDepthBias = rasterState.polygonOffsetUnits;
211 rasterDesc.DepthClipEnable = TRUE;
212 rasterDesc.ScissorEnable = rasterState.scissorTest ? TRUE : FALSE;
213 rasterDesc.MultisampleEnable = TRUE;
214 rasterDesc.AntialiasedLineEnable = FALSE;
215
216 ID3D11RasterizerState* dx11RasterizerState = NULL;
217 HRESULT result = mDevice->CreateRasterizerState(&rasterDesc, &dx11RasterizerState);
218 if (FAILED(result) || !dx11RasterizerState)
219 {
220 ERR("Unable to create a ID3D11RasterizerState, HRESULT: 0x%X.", result);
221 return NULL;
222 }
223
224 mRasterizerStateCache.insert(std::make_pair(key, std::make_pair(dx11RasterizerState, mCounter++)));
225
226 dx11RasterizerState->AddRef();
227 return dx11RasterizerState;
228 }
229}
230
daniel@transgaming.com0673d792012-11-28 19:37:44 +0000231}