1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/angle/src/libGLESv2/renderer/RenderStateCache.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,406 @@ 1.4 +#include "precompiled.h" 1.5 +// 1.6 +// Copyright (c) 2012-2013 The ANGLE Project Authors. All rights reserved. 1.7 +// Use of this source code is governed by a BSD-style license that can be 1.8 +// found in the LICENSE file. 1.9 +// 1.10 + 1.11 +// RenderStateCache.cpp: Defines rx::RenderStateCache, a cache of Direct3D render 1.12 +// state objects. 1.13 + 1.14 +#include "libGLESv2/renderer/RenderStateCache.h" 1.15 +#include "libGLESv2/renderer/renderer11_utils.h" 1.16 + 1.17 +#include "common/debug.h" 1.18 +#include "third_party/murmurhash/MurmurHash3.h" 1.19 + 1.20 +namespace rx 1.21 +{ 1.22 + 1.23 +// MSDN's documentation of ID3D11Device::CreateBlendState, ID3D11Device::CreateRasterizerState, 1.24 +// ID3D11Device::CreateDepthStencilState and ID3D11Device::CreateSamplerState claims the maximum 1.25 +// number of unique states of each type an application can create is 4096 1.26 +const unsigned int RenderStateCache::kMaxBlendStates = 4096; 1.27 +const unsigned int RenderStateCache::kMaxRasterizerStates = 4096; 1.28 +const unsigned int RenderStateCache::kMaxDepthStencilStates = 4096; 1.29 +const unsigned int RenderStateCache::kMaxSamplerStates = 4096; 1.30 + 1.31 +RenderStateCache::RenderStateCache() : mDevice(NULL), mCounter(0), 1.32 + mBlendStateCache(kMaxBlendStates, hashBlendState, compareBlendStates), 1.33 + mRasterizerStateCache(kMaxRasterizerStates, hashRasterizerState, compareRasterizerStates), 1.34 + mDepthStencilStateCache(kMaxDepthStencilStates, hashDepthStencilState, compareDepthStencilStates), 1.35 + mSamplerStateCache(kMaxSamplerStates, hashSamplerState, compareSamplerStates) 1.36 +{ 1.37 +} 1.38 + 1.39 +RenderStateCache::~RenderStateCache() 1.40 +{ 1.41 + clear(); 1.42 +} 1.43 + 1.44 +void RenderStateCache::initialize(ID3D11Device *device) 1.45 +{ 1.46 + clear(); 1.47 + mDevice = device; 1.48 +} 1.49 + 1.50 +void RenderStateCache::clear() 1.51 +{ 1.52 + for (BlendStateMap::iterator i = mBlendStateCache.begin(); i != mBlendStateCache.end(); i++) 1.53 + { 1.54 + i->second.first->Release(); 1.55 + } 1.56 + mBlendStateCache.clear(); 1.57 + 1.58 + for (RasterizerStateMap::iterator i = mRasterizerStateCache.begin(); i != mRasterizerStateCache.end(); i++) 1.59 + { 1.60 + i->second.first->Release(); 1.61 + } 1.62 + mRasterizerStateCache.clear(); 1.63 + 1.64 + for (DepthStencilStateMap::iterator i = mDepthStencilStateCache.begin(); i != mDepthStencilStateCache.end(); i++) 1.65 + { 1.66 + i->second.first->Release(); 1.67 + } 1.68 + mDepthStencilStateCache.clear(); 1.69 + 1.70 + for (SamplerStateMap::iterator i = mSamplerStateCache.begin(); i != mSamplerStateCache.end(); i++) 1.71 + { 1.72 + i->second.first->Release(); 1.73 + } 1.74 + mSamplerStateCache.clear(); 1.75 +} 1.76 + 1.77 +std::size_t RenderStateCache::hashBlendState(const gl::BlendState &blendState) 1.78 +{ 1.79 + static const unsigned int seed = 0xABCDEF98; 1.80 + 1.81 + std::size_t hash = 0; 1.82 + MurmurHash3_x86_32(&blendState, sizeof(gl::BlendState), seed, &hash); 1.83 + return hash; 1.84 +} 1.85 + 1.86 +bool RenderStateCache::compareBlendStates(const gl::BlendState &a, const gl::BlendState &b) 1.87 +{ 1.88 + return memcmp(&a, &b, sizeof(gl::BlendState)) == 0; 1.89 +} 1.90 + 1.91 +ID3D11BlendState *RenderStateCache::getBlendState(const gl::BlendState &blendState) 1.92 +{ 1.93 + if (!mDevice) 1.94 + { 1.95 + ERR("RenderStateCache is not initialized."); 1.96 + return NULL; 1.97 + } 1.98 + 1.99 + BlendStateMap::iterator i = mBlendStateCache.find(blendState); 1.100 + if (i != mBlendStateCache.end()) 1.101 + { 1.102 + BlendStateCounterPair &state = i->second; 1.103 + state.second = mCounter++; 1.104 + return state.first; 1.105 + } 1.106 + else 1.107 + { 1.108 + if (mBlendStateCache.size() >= kMaxBlendStates) 1.109 + { 1.110 + TRACE("Overflowed the limit of %u blend states, removing the least recently used " 1.111 + "to make room.", kMaxBlendStates); 1.112 + 1.113 + BlendStateMap::iterator leastRecentlyUsed = mBlendStateCache.begin(); 1.114 + for (BlendStateMap::iterator i = mBlendStateCache.begin(); i != mBlendStateCache.end(); i++) 1.115 + { 1.116 + if (i->second.second < leastRecentlyUsed->second.second) 1.117 + { 1.118 + leastRecentlyUsed = i; 1.119 + } 1.120 + } 1.121 + leastRecentlyUsed->second.first->Release(); 1.122 + mBlendStateCache.erase(leastRecentlyUsed); 1.123 + } 1.124 + 1.125 + // Create a new blend state and insert it into the cache 1.126 + D3D11_BLEND_DESC blendDesc = { 0 }; 1.127 + blendDesc.AlphaToCoverageEnable = blendState.sampleAlphaToCoverage; 1.128 + blendDesc.IndependentBlendEnable = FALSE; 1.129 + 1.130 + for (unsigned int i = 0; i < D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; i++) 1.131 + { 1.132 + D3D11_RENDER_TARGET_BLEND_DESC &rtBlend = blendDesc.RenderTarget[i]; 1.133 + 1.134 + rtBlend.BlendEnable = blendState.blend; 1.135 + if (blendState.blend) 1.136 + { 1.137 + rtBlend.SrcBlend = gl_d3d11::ConvertBlendFunc(blendState.sourceBlendRGB, false); 1.138 + rtBlend.DestBlend = gl_d3d11::ConvertBlendFunc(blendState.destBlendRGB, false); 1.139 + rtBlend.BlendOp = gl_d3d11::ConvertBlendOp(blendState.blendEquationRGB); 1.140 + 1.141 + rtBlend.SrcBlendAlpha = gl_d3d11::ConvertBlendFunc(blendState.sourceBlendAlpha, true); 1.142 + rtBlend.DestBlendAlpha = gl_d3d11::ConvertBlendFunc(blendState.destBlendAlpha, true); 1.143 + rtBlend.BlendOpAlpha = gl_d3d11::ConvertBlendOp(blendState.blendEquationAlpha); 1.144 + } 1.145 + 1.146 + rtBlend.RenderTargetWriteMask = gl_d3d11::ConvertColorMask(blendState.colorMaskRed, 1.147 + blendState.colorMaskGreen, 1.148 + blendState.colorMaskBlue, 1.149 + blendState.colorMaskAlpha); 1.150 + } 1.151 + 1.152 + ID3D11BlendState *dx11BlendState = NULL; 1.153 + HRESULT result = mDevice->CreateBlendState(&blendDesc, &dx11BlendState); 1.154 + if (FAILED(result) || !dx11BlendState) 1.155 + { 1.156 + ERR("Unable to create a ID3D11BlendState, HRESULT: 0x%X.", result); 1.157 + return NULL; 1.158 + } 1.159 + 1.160 + mBlendStateCache.insert(std::make_pair(blendState, std::make_pair(dx11BlendState, mCounter++))); 1.161 + 1.162 + return dx11BlendState; 1.163 + } 1.164 +} 1.165 + 1.166 +std::size_t RenderStateCache::hashRasterizerState(const RasterizerStateKey &rasterState) 1.167 +{ 1.168 + static const unsigned int seed = 0xABCDEF98; 1.169 + 1.170 + std::size_t hash = 0; 1.171 + MurmurHash3_x86_32(&rasterState, sizeof(RasterizerStateKey), seed, &hash); 1.172 + return hash; 1.173 +} 1.174 + 1.175 +bool RenderStateCache::compareRasterizerStates(const RasterizerStateKey &a, const RasterizerStateKey &b) 1.176 +{ 1.177 + return memcmp(&a, &b, sizeof(RasterizerStateKey)) == 0; 1.178 +} 1.179 + 1.180 +ID3D11RasterizerState *RenderStateCache::getRasterizerState(const gl::RasterizerState &rasterState, 1.181 + bool scissorEnabled, unsigned int depthSize) 1.182 +{ 1.183 + if (!mDevice) 1.184 + { 1.185 + ERR("RenderStateCache is not initialized."); 1.186 + return NULL; 1.187 + } 1.188 + 1.189 + RasterizerStateKey key; 1.190 + key.rasterizerState = rasterState; 1.191 + key.scissorEnabled = scissorEnabled; 1.192 + key.depthSize = depthSize; 1.193 + 1.194 + RasterizerStateMap::iterator i = mRasterizerStateCache.find(key); 1.195 + if (i != mRasterizerStateCache.end()) 1.196 + { 1.197 + RasterizerStateCounterPair &state = i->second; 1.198 + state.second = mCounter++; 1.199 + return state.first; 1.200 + } 1.201 + else 1.202 + { 1.203 + if (mRasterizerStateCache.size() >= kMaxRasterizerStates) 1.204 + { 1.205 + TRACE("Overflowed the limit of %u rasterizer states, removing the least recently used " 1.206 + "to make room.", kMaxRasterizerStates); 1.207 + 1.208 + RasterizerStateMap::iterator leastRecentlyUsed = mRasterizerStateCache.begin(); 1.209 + for (RasterizerStateMap::iterator i = mRasterizerStateCache.begin(); i != mRasterizerStateCache.end(); i++) 1.210 + { 1.211 + if (i->second.second < leastRecentlyUsed->second.second) 1.212 + { 1.213 + leastRecentlyUsed = i; 1.214 + } 1.215 + } 1.216 + leastRecentlyUsed->second.first->Release(); 1.217 + mRasterizerStateCache.erase(leastRecentlyUsed); 1.218 + } 1.219 + 1.220 + D3D11_CULL_MODE cullMode = gl_d3d11::ConvertCullMode(rasterState.cullFace, rasterState.cullMode); 1.221 + 1.222 + // Disable culling if drawing points 1.223 + if (rasterState.pointDrawMode) 1.224 + { 1.225 + cullMode = D3D11_CULL_NONE; 1.226 + } 1.227 + 1.228 + D3D11_RASTERIZER_DESC rasterDesc; 1.229 + rasterDesc.FillMode = D3D11_FILL_SOLID; 1.230 + rasterDesc.CullMode = cullMode; 1.231 + rasterDesc.FrontCounterClockwise = (rasterState.frontFace == GL_CCW) ? FALSE: TRUE; 1.232 + rasterDesc.DepthBias = ldexp(rasterState.polygonOffsetUnits, -static_cast<int>(depthSize)); 1.233 + rasterDesc.DepthBiasClamp = 0.0f; // MSDN documentation of DepthBiasClamp implies a value of zero will preform no clamping, must be tested though. 1.234 + rasterDesc.SlopeScaledDepthBias = rasterState.polygonOffsetFactor; 1.235 + rasterDesc.DepthClipEnable = TRUE; 1.236 + rasterDesc.ScissorEnable = scissorEnabled ? TRUE : FALSE; 1.237 + rasterDesc.MultisampleEnable = rasterState.multiSample; 1.238 + rasterDesc.AntialiasedLineEnable = FALSE; 1.239 + 1.240 + ID3D11RasterizerState *dx11RasterizerState = NULL; 1.241 + HRESULT result = mDevice->CreateRasterizerState(&rasterDesc, &dx11RasterizerState); 1.242 + if (FAILED(result) || !dx11RasterizerState) 1.243 + { 1.244 + ERR("Unable to create a ID3D11RasterizerState, HRESULT: 0x%X.", result); 1.245 + return NULL; 1.246 + } 1.247 + 1.248 + mRasterizerStateCache.insert(std::make_pair(key, std::make_pair(dx11RasterizerState, mCounter++))); 1.249 + 1.250 + return dx11RasterizerState; 1.251 + } 1.252 +} 1.253 + 1.254 +std::size_t RenderStateCache::hashDepthStencilState(const gl::DepthStencilState &dsState) 1.255 +{ 1.256 + static const unsigned int seed = 0xABCDEF98; 1.257 + 1.258 + std::size_t hash = 0; 1.259 + MurmurHash3_x86_32(&dsState, sizeof(gl::DepthStencilState), seed, &hash); 1.260 + return hash; 1.261 +} 1.262 + 1.263 +bool RenderStateCache::compareDepthStencilStates(const gl::DepthStencilState &a, const gl::DepthStencilState &b) 1.264 +{ 1.265 + return memcmp(&a, &b, sizeof(gl::DepthStencilState)) == 0; 1.266 +} 1.267 + 1.268 +ID3D11DepthStencilState *RenderStateCache::getDepthStencilState(const gl::DepthStencilState &dsState) 1.269 +{ 1.270 + if (!mDevice) 1.271 + { 1.272 + ERR("RenderStateCache is not initialized."); 1.273 + return NULL; 1.274 + } 1.275 + 1.276 + DepthStencilStateMap::iterator i = mDepthStencilStateCache.find(dsState); 1.277 + if (i != mDepthStencilStateCache.end()) 1.278 + { 1.279 + DepthStencilStateCounterPair &state = i->second; 1.280 + state.second = mCounter++; 1.281 + return state.first; 1.282 + } 1.283 + else 1.284 + { 1.285 + if (mDepthStencilStateCache.size() >= kMaxDepthStencilStates) 1.286 + { 1.287 + TRACE("Overflowed the limit of %u depth stencil states, removing the least recently used " 1.288 + "to make room.", kMaxDepthStencilStates); 1.289 + 1.290 + DepthStencilStateMap::iterator leastRecentlyUsed = mDepthStencilStateCache.begin(); 1.291 + for (DepthStencilStateMap::iterator i = mDepthStencilStateCache.begin(); i != mDepthStencilStateCache.end(); i++) 1.292 + { 1.293 + if (i->second.second < leastRecentlyUsed->second.second) 1.294 + { 1.295 + leastRecentlyUsed = i; 1.296 + } 1.297 + } 1.298 + leastRecentlyUsed->second.first->Release(); 1.299 + mDepthStencilStateCache.erase(leastRecentlyUsed); 1.300 + } 1.301 + 1.302 + D3D11_DEPTH_STENCIL_DESC dsDesc = { 0 }; 1.303 + dsDesc.DepthEnable = dsState.depthTest ? TRUE : FALSE; 1.304 + dsDesc.DepthWriteMask = gl_d3d11::ConvertDepthMask(dsState.depthMask); 1.305 + dsDesc.DepthFunc = gl_d3d11::ConvertComparison(dsState.depthFunc); 1.306 + dsDesc.StencilEnable = dsState.stencilTest ? TRUE : FALSE; 1.307 + dsDesc.StencilReadMask = gl_d3d11::ConvertStencilMask(dsState.stencilMask); 1.308 + dsDesc.StencilWriteMask = gl_d3d11::ConvertStencilMask(dsState.stencilWritemask); 1.309 + dsDesc.FrontFace.StencilFailOp = gl_d3d11::ConvertStencilOp(dsState.stencilFail); 1.310 + dsDesc.FrontFace.StencilDepthFailOp = gl_d3d11::ConvertStencilOp(dsState.stencilPassDepthFail); 1.311 + dsDesc.FrontFace.StencilPassOp = gl_d3d11::ConvertStencilOp(dsState.stencilPassDepthPass); 1.312 + dsDesc.FrontFace.StencilFunc = gl_d3d11::ConvertComparison(dsState.stencilFunc); 1.313 + dsDesc.BackFace.StencilFailOp = gl_d3d11::ConvertStencilOp(dsState.stencilBackFail); 1.314 + dsDesc.BackFace.StencilDepthFailOp = gl_d3d11::ConvertStencilOp(dsState.stencilBackPassDepthFail); 1.315 + dsDesc.BackFace.StencilPassOp = gl_d3d11::ConvertStencilOp(dsState.stencilBackPassDepthPass); 1.316 + dsDesc.BackFace.StencilFunc = gl_d3d11::ConvertComparison(dsState.stencilBackFunc); 1.317 + 1.318 + ID3D11DepthStencilState *dx11DepthStencilState = NULL; 1.319 + HRESULT result = mDevice->CreateDepthStencilState(&dsDesc, &dx11DepthStencilState); 1.320 + if (FAILED(result) || !dx11DepthStencilState) 1.321 + { 1.322 + ERR("Unable to create a ID3D11DepthStencilState, HRESULT: 0x%X.", result); 1.323 + return NULL; 1.324 + } 1.325 + 1.326 + mDepthStencilStateCache.insert(std::make_pair(dsState, std::make_pair(dx11DepthStencilState, mCounter++))); 1.327 + 1.328 + return dx11DepthStencilState; 1.329 + } 1.330 +} 1.331 + 1.332 +std::size_t RenderStateCache::hashSamplerState(const gl::SamplerState &samplerState) 1.333 +{ 1.334 + static const unsigned int seed = 0xABCDEF98; 1.335 + 1.336 + std::size_t hash = 0; 1.337 + MurmurHash3_x86_32(&samplerState, sizeof(gl::SamplerState), seed, &hash); 1.338 + return hash; 1.339 +} 1.340 + 1.341 +bool RenderStateCache::compareSamplerStates(const gl::SamplerState &a, const gl::SamplerState &b) 1.342 +{ 1.343 + return memcmp(&a, &b, sizeof(gl::SamplerState)) == 0; 1.344 +} 1.345 + 1.346 +ID3D11SamplerState *RenderStateCache::getSamplerState(const gl::SamplerState &samplerState) 1.347 +{ 1.348 + if (!mDevice) 1.349 + { 1.350 + ERR("RenderStateCache is not initialized."); 1.351 + return NULL; 1.352 + } 1.353 + 1.354 + SamplerStateMap::iterator i = mSamplerStateCache.find(samplerState); 1.355 + if (i != mSamplerStateCache.end()) 1.356 + { 1.357 + SamplerStateCounterPair &state = i->second; 1.358 + state.second = mCounter++; 1.359 + return state.first; 1.360 + } 1.361 + else 1.362 + { 1.363 + if (mSamplerStateCache.size() >= kMaxSamplerStates) 1.364 + { 1.365 + TRACE("Overflowed the limit of %u sampler states, removing the least recently used " 1.366 + "to make room.", kMaxSamplerStates); 1.367 + 1.368 + SamplerStateMap::iterator leastRecentlyUsed = mSamplerStateCache.begin(); 1.369 + for (SamplerStateMap::iterator i = mSamplerStateCache.begin(); i != mSamplerStateCache.end(); i++) 1.370 + { 1.371 + if (i->second.second < leastRecentlyUsed->second.second) 1.372 + { 1.373 + leastRecentlyUsed = i; 1.374 + } 1.375 + } 1.376 + leastRecentlyUsed->second.first->Release(); 1.377 + mSamplerStateCache.erase(leastRecentlyUsed); 1.378 + } 1.379 + 1.380 + D3D11_SAMPLER_DESC samplerDesc; 1.381 + samplerDesc.Filter = gl_d3d11::ConvertFilter(samplerState.minFilter, samplerState.magFilter, samplerState.maxAnisotropy); 1.382 + samplerDesc.AddressU = gl_d3d11::ConvertTextureWrap(samplerState.wrapS); 1.383 + samplerDesc.AddressV = gl_d3d11::ConvertTextureWrap(samplerState.wrapT); 1.384 + samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP; 1.385 + samplerDesc.MipLODBias = static_cast<float>(samplerState.lodOffset); 1.386 + samplerDesc.MaxAnisotropy = samplerState.maxAnisotropy; 1.387 + samplerDesc.ComparisonFunc = D3D11_COMPARISON_NEVER; 1.388 + samplerDesc.BorderColor[0] = 0.0f; 1.389 + samplerDesc.BorderColor[1] = 0.0f; 1.390 + samplerDesc.BorderColor[2] = 0.0f; 1.391 + samplerDesc.BorderColor[3] = 0.0f; 1.392 + samplerDesc.MinLOD = gl_d3d11::ConvertMinLOD(samplerState.minFilter, samplerState.lodOffset); 1.393 + samplerDesc.MaxLOD = gl_d3d11::ConvertMaxLOD(samplerState.minFilter, samplerState.lodOffset); 1.394 + 1.395 + ID3D11SamplerState *dx11SamplerState = NULL; 1.396 + HRESULT result = mDevice->CreateSamplerState(&samplerDesc, &dx11SamplerState); 1.397 + if (FAILED(result) || !dx11SamplerState) 1.398 + { 1.399 + ERR("Unable to create a ID3D11DepthStencilState, HRESULT: 0x%X.", result); 1.400 + return NULL; 1.401 + } 1.402 + 1.403 + mSamplerStateCache.insert(std::make_pair(samplerState, std::make_pair(dx11SamplerState, mCounter++))); 1.404 + 1.405 + return dx11SamplerState; 1.406 + } 1.407 +} 1.408 + 1.409 +} 1.410 \ No newline at end of file