tor-browser

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

VertexDeclarationCache.cpp (8621B)


      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 // VertexDeclarationCache.cpp: Implements a helper class to construct and cache vertex declarations.
      8 
      9 #include "libANGLE/renderer/d3d/d3d9/VertexDeclarationCache.h"
     10 
     11 #include "libANGLE/Context.h"
     12 #include "libANGLE/VertexAttribute.h"
     13 #include "libANGLE/formatutils.h"
     14 #include "libANGLE/renderer/d3d/ProgramD3D.h"
     15 #include "libANGLE/renderer/d3d/d3d9/Context9.h"
     16 #include "libANGLE/renderer/d3d/d3d9/VertexBuffer9.h"
     17 #include "libANGLE/renderer/d3d/d3d9/formatutils9.h"
     18 
     19 namespace rx
     20 {
     21 
     22 VertexDeclarationCache::VertexDeclarationCache() : mMaxLru(0)
     23 {
     24    for (int i = 0; i < NUM_VERTEX_DECL_CACHE_ENTRIES; i++)
     25    {
     26        mVertexDeclCache[i].vertexDeclaration = nullptr;
     27        mVertexDeclCache[i].lruCount          = 0;
     28    }
     29 
     30    for (VBData &vb : mAppliedVBs)
     31    {
     32        vb.serial = 0;
     33    }
     34 
     35    mLastSetVDecl      = nullptr;
     36    mInstancingEnabled = true;
     37 }
     38 
     39 VertexDeclarationCache::~VertexDeclarationCache()
     40 {
     41    for (int i = 0; i < NUM_VERTEX_DECL_CACHE_ENTRIES; i++)
     42    {
     43        SafeRelease(mVertexDeclCache[i].vertexDeclaration);
     44    }
     45 }
     46 
     47 angle::Result VertexDeclarationCache::applyDeclaration(
     48    const gl::Context *context,
     49    IDirect3DDevice9 *device,
     50    const std::vector<TranslatedAttribute> &attributes,
     51    gl::Program *program,
     52    GLint start,
     53    GLsizei instances,
     54    GLsizei *repeatDraw)
     55 {
     56    ASSERT(gl::MAX_VERTEX_ATTRIBS >= attributes.size());
     57 
     58    *repeatDraw = 1;
     59 
     60    const size_t invalidAttribIndex = attributes.size();
     61    size_t indexedAttribute         = invalidAttribIndex;
     62    size_t instancedAttribute       = invalidAttribIndex;
     63 
     64    if (instances == 0)
     65    {
     66        for (size_t i = 0; i < attributes.size(); ++i)
     67        {
     68            if (attributes[i].divisor != 0)
     69            {
     70                // If a divisor is set, it still applies even if an instanced draw was not used, so
     71                // treat as a single-instance draw.
     72                instances = 1;
     73                break;
     74            }
     75        }
     76    }
     77 
     78    if (instances > 0)
     79    {
     80        // Find an indexed attribute to be mapped to D3D stream 0
     81        for (size_t i = 0; i < attributes.size(); i++)
     82        {
     83            if (attributes[i].active)
     84            {
     85                if (indexedAttribute == invalidAttribIndex && attributes[i].divisor == 0)
     86                {
     87                    indexedAttribute = i;
     88                }
     89                else if (instancedAttribute == invalidAttribIndex && attributes[i].divisor != 0)
     90                {
     91                    instancedAttribute = i;
     92                }
     93                if (indexedAttribute != invalidAttribIndex &&
     94                    instancedAttribute != invalidAttribIndex)
     95                    break;  // Found both an indexed and instanced attribute
     96            }
     97        }
     98 
     99        // The validation layer checks that there is at least one active attribute with a zero
    100        // divisor as per the GL_ANGLE_instanced_arrays spec.
    101        ASSERT(indexedAttribute != invalidAttribIndex);
    102    }
    103 
    104    D3DCAPS9 caps;
    105    device->GetDeviceCaps(&caps);
    106 
    107    D3DVERTEXELEMENT9 elements[gl::MAX_VERTEX_ATTRIBS + 1];
    108    D3DVERTEXELEMENT9 *element = &elements[0];
    109 
    110    ProgramD3D *programD3D      = GetImplAs<ProgramD3D>(program);
    111    const auto &semanticIndexes = programD3D->getAttribLocationToD3DSemantics();
    112 
    113    for (size_t i = 0; i < attributes.size(); i++)
    114    {
    115        if (attributes[i].active)
    116        {
    117            // Directly binding the storage buffer is not supported for d3d9
    118            ASSERT(attributes[i].storage == nullptr);
    119 
    120            int stream = static_cast<int>(i);
    121 
    122            if (instances > 0)
    123            {
    124                // Due to a bug on ATI cards we can't enable instancing when none of the attributes
    125                // are instanced.
    126                if (instancedAttribute == invalidAttribIndex)
    127                {
    128                    *repeatDraw = instances;
    129                }
    130                else
    131                {
    132                    if (i == indexedAttribute)
    133                    {
    134                        stream = 0;
    135                    }
    136                    else if (i == 0)
    137                    {
    138                        stream = static_cast<int>(indexedAttribute);
    139                    }
    140 
    141                    UINT frequency = 1;
    142 
    143                    if (attributes[i].divisor == 0)
    144                    {
    145                        frequency = D3DSTREAMSOURCE_INDEXEDDATA | instances;
    146                    }
    147                    else
    148                    {
    149                        frequency = D3DSTREAMSOURCE_INSTANCEDATA | attributes[i].divisor;
    150                    }
    151 
    152                    device->SetStreamSourceFreq(stream, frequency);
    153                    mInstancingEnabled = true;
    154                }
    155            }
    156 
    157            VertexBuffer9 *vertexBuffer = GetAs<VertexBuffer9>(attributes[i].vertexBuffer.get());
    158 
    159            unsigned int offset = 0;
    160            ANGLE_TRY(attributes[i].computeOffset(context, start, &offset));
    161 
    162            if (mAppliedVBs[stream].serial != attributes[i].serial ||
    163                mAppliedVBs[stream].stride != attributes[i].stride ||
    164                mAppliedVBs[stream].offset != offset)
    165            {
    166                device->SetStreamSource(stream, vertexBuffer->getBuffer(), offset,
    167                                        attributes[i].stride);
    168                mAppliedVBs[stream].serial = attributes[i].serial;
    169                mAppliedVBs[stream].stride = attributes[i].stride;
    170                mAppliedVBs[stream].offset = offset;
    171            }
    172 
    173            angle::FormatID vertexformatID =
    174                gl::GetVertexFormatID(*attributes[i].attribute, gl::VertexAttribType::Float);
    175            const d3d9::VertexFormat &d3d9VertexInfo =
    176                d3d9::GetVertexFormatInfo(caps.DeclTypes, vertexformatID);
    177 
    178            element->Stream     = static_cast<WORD>(stream);
    179            element->Offset     = 0;
    180            element->Type       = static_cast<BYTE>(d3d9VertexInfo.nativeFormat);
    181            element->Method     = D3DDECLMETHOD_DEFAULT;
    182            element->Usage      = D3DDECLUSAGE_TEXCOORD;
    183            element->UsageIndex = static_cast<BYTE>(semanticIndexes[i]);
    184            element++;
    185        }
    186    }
    187 
    188    if (instances == 0 || instancedAttribute == invalidAttribIndex)
    189    {
    190        if (mInstancingEnabled)
    191        {
    192            for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
    193            {
    194                device->SetStreamSourceFreq(i, 1);
    195            }
    196 
    197            mInstancingEnabled = false;
    198        }
    199    }
    200 
    201    static const D3DVERTEXELEMENT9 end = D3DDECL_END();
    202    *(element++)                       = end;
    203 
    204    for (int i = 0; i < NUM_VERTEX_DECL_CACHE_ENTRIES; i++)
    205    {
    206        VertexDeclCacheEntry *entry = &mVertexDeclCache[i];
    207        if (memcmp(entry->cachedElements, elements,
    208                   (element - elements) * sizeof(D3DVERTEXELEMENT9)) == 0 &&
    209            entry->vertexDeclaration)
    210        {
    211            entry->lruCount = ++mMaxLru;
    212            if (entry->vertexDeclaration != mLastSetVDecl)
    213            {
    214                device->SetVertexDeclaration(entry->vertexDeclaration);
    215                mLastSetVDecl = entry->vertexDeclaration;
    216            }
    217 
    218            return angle::Result::Continue;
    219        }
    220    }
    221 
    222    VertexDeclCacheEntry *lastCache = mVertexDeclCache;
    223 
    224    for (int i = 0; i < NUM_VERTEX_DECL_CACHE_ENTRIES; i++)
    225    {
    226        if (mVertexDeclCache[i].lruCount < lastCache->lruCount)
    227        {
    228            lastCache = &mVertexDeclCache[i];
    229        }
    230    }
    231 
    232    if (lastCache->vertexDeclaration != nullptr)
    233    {
    234        SafeRelease(lastCache->vertexDeclaration);
    235        // mLastSetVDecl is set to the replacement, so we don't have to worry
    236        // about it.
    237    }
    238 
    239    memcpy(lastCache->cachedElements, elements, (element - elements) * sizeof(D3DVERTEXELEMENT9));
    240    HRESULT result = device->CreateVertexDeclaration(elements, &lastCache->vertexDeclaration);
    241    ANGLE_TRY_HR(GetImplAs<Context9>(context), result,
    242                 "Failed to create internal vertex declaration");
    243 
    244    device->SetVertexDeclaration(lastCache->vertexDeclaration);
    245    mLastSetVDecl       = lastCache->vertexDeclaration;
    246    lastCache->lruCount = ++mMaxLru;
    247 
    248    return angle::Result::Continue;
    249 }
    250 
    251 void VertexDeclarationCache::markStateDirty()
    252 {
    253    for (VBData &vb : mAppliedVBs)
    254    {
    255        vb.serial = 0;
    256    }
    257 
    258    mLastSetVDecl      = nullptr;
    259    mInstancingEnabled = true;  // Forces it to be disabled when not used
    260 }
    261 
    262 }  // namespace rx