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