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 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 36 RenderStateCache::~RenderStateCache() 37 { 38 clear(); 39 } 40 41 void RenderStateCache::initialize(ID3D11Device *device) 42 { 43 clear(); 44 mDevice = device; 45 } 46 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 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 83 bool RenderStateCache::compareBlendStates(const gl::BlendState &a, const gl::BlendState &b) 84 { 85 return memcmp(&a, &b, sizeof(gl::BlendState)) == 0; 86 } 87 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 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 172 bool RenderStateCache::compareRasterizerStates(const RasterizerStateKey &a, const RasterizerStateKey &b) 173 { 174 return memcmp(&a, &b, sizeof(RasterizerStateKey)) == 0; 175 } 176 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 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 260 bool RenderStateCache::compareDepthStencilStates(const gl::DepthStencilState &a, const gl::DepthStencilState &b) 261 { 262 return memcmp(&a, &b, sizeof(gl::DepthStencilState)) == 0; 263 } 264 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 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 338 bool RenderStateCache::compareSamplerStates(const gl::SamplerState &a, const gl::SamplerState &b) 339 { 340 return memcmp(&a, &b, sizeof(gl::SamplerState)) == 0; 341 } 342 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 }