Home | History | Annotate | Download | only in renderer
      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 }