tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

RenderStateCache.cpp (14197B)


      1 //
      2 // Copyright 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 "libANGLE/renderer/d3d/d3d11/RenderStateCache.h"
     11 
     12 #include <float.h>
     13 
     14 #include "common/Color.h"
     15 #include "common/debug.h"
     16 #include "libANGLE/Context.h"
     17 #include "libANGLE/Framebuffer.h"
     18 #include "libANGLE/FramebufferAttachment.h"
     19 #include "libANGLE/renderer/d3d/d3d11/Context11.h"
     20 #include "libANGLE/renderer/d3d/d3d11/Framebuffer11.h"
     21 #include "libANGLE/renderer/d3d/d3d11/Renderer11.h"
     22 #include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h"
     23 
     24 namespace rx
     25 {
     26 using namespace gl_d3d11;
     27 
     28 RenderStateCache::RenderStateCache()
     29    : mBlendStateCache(kMaxStates),
     30      mRasterizerStateCache(kMaxStates),
     31      mDepthStencilStateCache(kMaxStates),
     32      mSamplerStateCache(kMaxStates)
     33 {}
     34 
     35 RenderStateCache::~RenderStateCache() {}
     36 
     37 void RenderStateCache::clear()
     38 {
     39    mBlendStateCache.Clear();
     40    mRasterizerStateCache.Clear();
     41    mDepthStencilStateCache.Clear();
     42    mSamplerStateCache.Clear();
     43 }
     44 
     45 // static
     46 d3d11::BlendStateKey RenderStateCache::GetBlendStateKey(const gl::Context *context,
     47                                                        Framebuffer11 *framebuffer11,
     48                                                        const gl::BlendStateExt &blendStateExt,
     49                                                        bool sampleAlphaToCoverage)
     50 {
     51    d3d11::BlendStateKey key;
     52    // All fields of the BlendStateExt inside the key should be initialized for the caching to
     53    // work correctly. Due to mrt_perf_workaround, the actual indices of active draw buffers may be
     54    // different, so both arrays should be tracked.
     55    key.blendStateExt                      = gl::BlendStateExt(blendStateExt.getDrawBufferCount());
     56    const gl::AttachmentList &colorbuffers = framebuffer11->getColorAttachmentsForRender(context);
     57    const gl::DrawBufferMask colorAttachmentsForRenderMask =
     58        framebuffer11->getLastColorAttachmentsForRenderMask();
     59 
     60    ASSERT(blendStateExt.getDrawBufferCount() <= colorAttachmentsForRenderMask.size());
     61    ASSERT(colorbuffers.size() == colorAttachmentsForRenderMask.count());
     62 
     63    size_t keyBlendIndex = 0;
     64 
     65    // With blending disabled, factors and equations are ignored when building
     66    // D3D11_RENDER_TARGET_BLEND_DESC, so we can reduce the amount of unique keys by
     67    // enforcing default values.
     68    for (size_t sourceIndex : colorAttachmentsForRenderMask)
     69    {
     70        ASSERT(keyBlendIndex < colorbuffers.size());
     71        const gl::FramebufferAttachment *attachment = colorbuffers[keyBlendIndex];
     72 
     73        // Do not set blend state for null attachments that may be present when
     74        // mrt_perf_workaround is disabled.
     75        if (attachment == nullptr)
     76        {
     77            keyBlendIndex++;
     78            continue;
     79        }
     80 
     81        const uint8_t colorMask = blendStateExt.getColorMaskIndexed(sourceIndex);
     82 
     83        const gl::InternalFormat &internalFormat = *attachment->getFormat().info;
     84 
     85        key.blendStateExt.setColorMaskIndexed(keyBlendIndex,
     86                                              gl_d3d11::GetColorMask(internalFormat) & colorMask);
     87        key.rtvMax = static_cast<uint16_t>(keyBlendIndex) + 1;
     88 
     89        // Some D3D11 drivers produce unexpected results when blending is enabled for integer
     90        // attachments. Per OpenGL ES spec, it must be ignored anyway. When blending is disabled,
     91        // the state remains default to reduce the number of unique keys.
     92        if (blendStateExt.getEnabledMask().test(sourceIndex) && !internalFormat.isInt())
     93        {
     94            key.blendStateExt.setEnabledIndexed(keyBlendIndex, true);
     95            key.blendStateExt.setEquationsIndexed(keyBlendIndex, sourceIndex, blendStateExt);
     96            key.blendStateExt.setFactorsIndexed(keyBlendIndex, sourceIndex, blendStateExt);
     97        }
     98        keyBlendIndex++;
     99    }
    100 
    101    key.sampleAlphaToCoverage = sampleAlphaToCoverage ? 1 : 0;
    102    return key;
    103 }
    104 
    105 angle::Result RenderStateCache::getBlendState(const gl::Context *context,
    106                                              Renderer11 *renderer,
    107                                              const d3d11::BlendStateKey &key,
    108                                              const d3d11::BlendState **outBlendState)
    109 {
    110    auto keyIter = mBlendStateCache.Get(key);
    111    if (keyIter != mBlendStateCache.end())
    112    {
    113        *outBlendState = &keyIter->second;
    114        return angle::Result::Continue;
    115    }
    116 
    117    TrimCache(kMaxStates, kGCLimit, "blend state", &mBlendStateCache);
    118 
    119    // Create a new blend state and insert it into the cache
    120    D3D11_BLEND_DESC blendDesc             = {};  // avoid undefined fields
    121    const gl::BlendStateExt &blendStateExt = key.blendStateExt;
    122 
    123    blendDesc.AlphaToCoverageEnable  = key.sampleAlphaToCoverage != 0 ? TRUE : FALSE;
    124    blendDesc.IndependentBlendEnable = key.rtvMax > 1 ? TRUE : FALSE;
    125 
    126    // D3D11 API always accepts an array of blend states. Its validity depends on the hardware
    127    // feature level. Given that we do not expose GL entrypoints that set per-buffer blend states on
    128    // systems lower than FL10_1, this array will be always valid.
    129 
    130    for (size_t i = 0; i < blendStateExt.getDrawBufferCount(); i++)
    131    {
    132        D3D11_RENDER_TARGET_BLEND_DESC &rtDesc = blendDesc.RenderTarget[i];
    133 
    134        if (blendStateExt.getEnabledMask().test(i))
    135        {
    136            rtDesc.BlendEnable = true;
    137            rtDesc.SrcBlend =
    138                gl_d3d11::ConvertBlendFunc(blendStateExt.getSrcColorIndexed(i), false);
    139            rtDesc.DestBlend =
    140                gl_d3d11::ConvertBlendFunc(blendStateExt.getDstColorIndexed(i), false);
    141            rtDesc.BlendOp = gl_d3d11::ConvertBlendOp(blendStateExt.getEquationColorIndexed(i));
    142            rtDesc.SrcBlendAlpha =
    143                gl_d3d11::ConvertBlendFunc(blendStateExt.getSrcAlphaIndexed(i), true);
    144            rtDesc.DestBlendAlpha =
    145                gl_d3d11::ConvertBlendFunc(blendStateExt.getDstAlphaIndexed(i), true);
    146            rtDesc.BlendOpAlpha =
    147                gl_d3d11::ConvertBlendOp(blendStateExt.getEquationAlphaIndexed(i));
    148        }
    149 
    150        // blendStateExt.colorMask follows the same packing scheme as
    151        // D3D11_RENDER_TARGET_BLEND_DESC.RenderTargetWriteMask
    152        rtDesc.RenderTargetWriteMask = blendStateExt.getColorMaskIndexed(i);
    153    }
    154 
    155    d3d11::BlendState d3dBlendState;
    156    ANGLE_TRY(renderer->allocateResource(GetImplAs<Context11>(context), blendDesc, &d3dBlendState));
    157    const auto &iter = mBlendStateCache.Put(key, std::move(d3dBlendState));
    158 
    159    *outBlendState = &iter->second;
    160 
    161    return angle::Result::Continue;
    162 }
    163 
    164 angle::Result RenderStateCache::getRasterizerState(const gl::Context *context,
    165                                                   Renderer11 *renderer,
    166                                                   const gl::RasterizerState &rasterState,
    167                                                   bool scissorEnabled,
    168                                                   ID3D11RasterizerState **outRasterizerState)
    169 {
    170    d3d11::RasterizerStateKey key;
    171    key.rasterizerState = rasterState;
    172    key.scissorEnabled  = scissorEnabled ? 1 : 0;
    173 
    174    auto keyIter = mRasterizerStateCache.Get(key);
    175    if (keyIter != mRasterizerStateCache.end())
    176    {
    177        *outRasterizerState = keyIter->second.get();
    178        return angle::Result::Continue;
    179    }
    180 
    181    TrimCache(kMaxStates, kGCLimit, "rasterizer state", &mRasterizerStateCache);
    182 
    183    D3D11_CULL_MODE cullMode =
    184        gl_d3d11::ConvertCullMode(rasterState.cullFace, rasterState.cullMode);
    185 
    186    // Disable culling if drawing points
    187    if (rasterState.pointDrawMode)
    188    {
    189        cullMode = D3D11_CULL_NONE;
    190    }
    191 
    192    D3D11_RASTERIZER_DESC rasterDesc;
    193    rasterDesc.FillMode              = D3D11_FILL_SOLID;
    194    rasterDesc.CullMode              = cullMode;
    195    rasterDesc.FrontCounterClockwise = (rasterState.frontFace == GL_CCW) ? FALSE : TRUE;
    196    rasterDesc.DepthBiasClamp = 0.0f;  // MSDN documentation of DepthBiasClamp implies a value of
    197                                       // zero will preform no clamping, must be tested though.
    198    rasterDesc.DepthClipEnable       = TRUE;
    199    rasterDesc.ScissorEnable         = scissorEnabled ? TRUE : FALSE;
    200    rasterDesc.MultisampleEnable     = rasterState.multiSample;
    201    rasterDesc.AntialiasedLineEnable = FALSE;
    202 
    203    if (rasterState.polygonOffsetFill)
    204    {
    205        rasterDesc.SlopeScaledDepthBias = rasterState.polygonOffsetFactor;
    206        rasterDesc.DepthBias            = (INT)rasterState.polygonOffsetUnits;
    207    }
    208    else
    209    {
    210        rasterDesc.SlopeScaledDepthBias = 0.0f;
    211        rasterDesc.DepthBias            = 0;
    212    }
    213 
    214    d3d11::RasterizerState dx11RasterizerState;
    215    ANGLE_TRY(renderer->allocateResource(GetImplAs<Context11>(context), rasterDesc,
    216                                         &dx11RasterizerState));
    217    *outRasterizerState = dx11RasterizerState.get();
    218    mRasterizerStateCache.Put(key, std::move(dx11RasterizerState));
    219 
    220    return angle::Result::Continue;
    221 }
    222 
    223 angle::Result RenderStateCache::getDepthStencilState(const gl::Context *context,
    224                                                     Renderer11 *renderer,
    225                                                     const gl::DepthStencilState &glState,
    226                                                     const d3d11::DepthStencilState **outDSState)
    227 {
    228    auto keyIter = mDepthStencilStateCache.Get(glState);
    229    if (keyIter != mDepthStencilStateCache.end())
    230    {
    231        *outDSState = &keyIter->second;
    232        return angle::Result::Continue;
    233    }
    234 
    235    TrimCache(kMaxStates, kGCLimit, "depth stencil state", &mDepthStencilStateCache);
    236 
    237    D3D11_DEPTH_STENCIL_DESC dsDesc     = {};
    238    dsDesc.DepthEnable                  = glState.depthTest ? TRUE : FALSE;
    239    dsDesc.DepthWriteMask               = ConvertDepthMask(glState.depthMask);
    240    dsDesc.DepthFunc                    = ConvertComparison(glState.depthFunc);
    241    dsDesc.StencilEnable                = glState.stencilTest ? TRUE : FALSE;
    242    dsDesc.StencilReadMask              = ConvertStencilMask(glState.stencilMask);
    243    dsDesc.StencilWriteMask             = ConvertStencilMask(glState.stencilWritemask);
    244    dsDesc.FrontFace.StencilFailOp      = ConvertStencilOp(glState.stencilFail);
    245    dsDesc.FrontFace.StencilDepthFailOp = ConvertStencilOp(glState.stencilPassDepthFail);
    246    dsDesc.FrontFace.StencilPassOp      = ConvertStencilOp(glState.stencilPassDepthPass);
    247    dsDesc.FrontFace.StencilFunc        = ConvertComparison(glState.stencilFunc);
    248    dsDesc.BackFace.StencilFailOp       = ConvertStencilOp(glState.stencilBackFail);
    249    dsDesc.BackFace.StencilDepthFailOp  = ConvertStencilOp(glState.stencilBackPassDepthFail);
    250    dsDesc.BackFace.StencilPassOp       = ConvertStencilOp(glState.stencilBackPassDepthPass);
    251    dsDesc.BackFace.StencilFunc         = ConvertComparison(glState.stencilBackFunc);
    252 
    253    d3d11::DepthStencilState dx11DepthStencilState;
    254    ANGLE_TRY(
    255        renderer->allocateResource(GetImplAs<Context11>(context), dsDesc, &dx11DepthStencilState));
    256    const auto &iter = mDepthStencilStateCache.Put(glState, std::move(dx11DepthStencilState));
    257 
    258    *outDSState = &iter->second;
    259 
    260    return angle::Result::Continue;
    261 }
    262 
    263 angle::Result RenderStateCache::getSamplerState(const gl::Context *context,
    264                                                Renderer11 *renderer,
    265                                                const gl::SamplerState &samplerState,
    266                                                ID3D11SamplerState **outSamplerState)
    267 {
    268    auto keyIter = mSamplerStateCache.Get(samplerState);
    269    if (keyIter != mSamplerStateCache.end())
    270    {
    271        *outSamplerState = keyIter->second.get();
    272        return angle::Result::Continue;
    273    }
    274 
    275    TrimCache(kMaxStates, kGCLimit, "sampler state", &mSamplerStateCache);
    276 
    277    const auto &featureLevel = renderer->getRenderer11DeviceCaps().featureLevel;
    278 
    279    D3D11_SAMPLER_DESC samplerDesc;
    280    samplerDesc.Filter =
    281        gl_d3d11::ConvertFilter(samplerState.getMinFilter(), samplerState.getMagFilter(),
    282                                samplerState.getMaxAnisotropy(), samplerState.getCompareMode());
    283    samplerDesc.AddressU   = gl_d3d11::ConvertTextureWrap(samplerState.getWrapS());
    284    samplerDesc.AddressV   = gl_d3d11::ConvertTextureWrap(samplerState.getWrapT());
    285    samplerDesc.AddressW   = gl_d3d11::ConvertTextureWrap(samplerState.getWrapR());
    286    samplerDesc.MipLODBias = 0;
    287    samplerDesc.MaxAnisotropy =
    288        gl_d3d11::ConvertMaxAnisotropy(samplerState.getMaxAnisotropy(), featureLevel);
    289    samplerDesc.ComparisonFunc = gl_d3d11::ConvertComparison(samplerState.getCompareFunc());
    290    angle::ColorF borderColor;
    291    if (samplerState.getBorderColor().type == angle::ColorGeneric::Type::Float)
    292    {
    293        borderColor = samplerState.getBorderColor().colorF;
    294    }
    295    samplerDesc.BorderColor[0] = borderColor.red;
    296    samplerDesc.BorderColor[1] = borderColor.green;
    297    samplerDesc.BorderColor[2] = borderColor.blue;
    298    samplerDesc.BorderColor[3] = borderColor.alpha;
    299    samplerDesc.MinLOD         = samplerState.getMinLod();
    300    samplerDesc.MaxLOD         = samplerState.getMaxLod();
    301 
    302    if (featureLevel <= D3D_FEATURE_LEVEL_9_3)
    303    {
    304        // Check that maxLOD is nearly FLT_MAX (1000.0f is the default), since 9_3 doesn't support
    305        // anything other than FLT_MAX. Note that Feature Level 9_* only supports GL ES 2.0, so the
    306        // consumer of ANGLE can't modify the Max LOD themselves.
    307        ASSERT(samplerState.getMaxLod() >= 999.9f);
    308 
    309        // Now just set MaxLOD to FLT_MAX. Other parts of the renderer (e.g. the non-zero max LOD
    310        // workaround) should take account of this.
    311        samplerDesc.MaxLOD = FLT_MAX;
    312    }
    313 
    314    d3d11::SamplerState dx11SamplerState;
    315    ANGLE_TRY(
    316        renderer->allocateResource(GetImplAs<Context11>(context), samplerDesc, &dx11SamplerState));
    317    *outSamplerState = dx11SamplerState.get();
    318    mSamplerStateCache.Put(samplerState, std::move(dx11SamplerState));
    319 
    320    return angle::Result::Continue;
    321 }
    322 
    323 }  // namespace rx