Home | History | Annotate | Download | only in d3d11
      1 //
      2 // Copyright (c) 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 // InputLayoutCache.cpp: Defines InputLayoutCache, a class that builds and caches
      8 // D3D11 input layouts.
      9 
     10 #include "libGLESv2/renderer/d3d/d3d11/InputLayoutCache.h"
     11 #include "libGLESv2/renderer/d3d/d3d11/VertexBuffer11.h"
     12 #include "libGLESv2/renderer/d3d/d3d11/Buffer11.h"
     13 #include "libGLESv2/renderer/d3d/d3d11/ShaderExecutable11.h"
     14 #include "libGLESv2/renderer/d3d/d3d11/formatutils11.h"
     15 #include "libGLESv2/renderer/d3d/VertexDataManager.h"
     16 #include "libGLESv2/ProgramBinary.h"
     17 #include "libGLESv2/VertexAttribute.h"
     18 
     19 #include "third_party/murmurhash/MurmurHash3.h"
     20 
     21 namespace rx
     22 {
     23 
     24 static void GetInputLayout(const TranslatedAttribute translatedAttributes[gl::MAX_VERTEX_ATTRIBS],
     25                            gl::VertexFormat inputLayout[gl::MAX_VERTEX_ATTRIBS])
     26 {
     27     for (unsigned int attributeIndex = 0; attributeIndex < gl::MAX_VERTEX_ATTRIBS; attributeIndex++)
     28     {
     29         const TranslatedAttribute &translatedAttribute = translatedAttributes[attributeIndex];
     30 
     31         if (translatedAttributes[attributeIndex].active)
     32         {
     33             inputLayout[attributeIndex] = gl::VertexFormat(*translatedAttribute.attribute,
     34                                                            translatedAttribute.currentValueType);
     35         }
     36     }
     37 }
     38 
     39 const unsigned int InputLayoutCache::kMaxInputLayouts = 1024;
     40 
     41 InputLayoutCache::InputLayoutCache() : mInputLayoutMap(kMaxInputLayouts, hashInputLayout, compareInputLayouts)
     42 {
     43     mCounter = 0;
     44     mDevice = NULL;
     45     mDeviceContext = NULL;
     46     mCurrentIL = NULL;
     47     for (unsigned int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
     48     {
     49         mCurrentBuffers[i] = NULL;
     50         mCurrentVertexStrides[i] = -1;
     51         mCurrentVertexOffsets[i] = -1;
     52     }
     53 }
     54 
     55 InputLayoutCache::~InputLayoutCache()
     56 {
     57     clear();
     58 }
     59 
     60 void InputLayoutCache::initialize(ID3D11Device *device, ID3D11DeviceContext *context)
     61 {
     62     clear();
     63     mDevice = device;
     64     mDeviceContext = context;
     65 }
     66 
     67 void InputLayoutCache::clear()
     68 {
     69     for (InputLayoutMap::iterator i = mInputLayoutMap.begin(); i != mInputLayoutMap.end(); i++)
     70     {
     71         SafeRelease(i->second.inputLayout);
     72     }
     73     mInputLayoutMap.clear();
     74     markDirty();
     75 }
     76 
     77 void InputLayoutCache::markDirty()
     78 {
     79     mCurrentIL = NULL;
     80     for (unsigned int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
     81     {
     82         mCurrentBuffers[i] = NULL;
     83         mCurrentVertexStrides[i] = -1;
     84         mCurrentVertexOffsets[i] = -1;
     85     }
     86 }
     87 
     88 gl::Error InputLayoutCache::applyVertexBuffers(TranslatedAttribute attributes[gl::MAX_VERTEX_ATTRIBS],
     89                                                gl::ProgramBinary *programBinary)
     90 {
     91     int sortedSemanticIndices[gl::MAX_VERTEX_ATTRIBS];
     92     programBinary->sortAttributesByLayout(attributes, sortedSemanticIndices);
     93 
     94     if (!mDevice || !mDeviceContext)
     95     {
     96         return gl::Error(GL_OUT_OF_MEMORY, "Internal input layout cache is not initialized.");
     97     }
     98 
     99     InputLayoutKey ilKey = { 0 };
    100 
    101     static const char* semanticName = "TEXCOORD";
    102 
    103     for (unsigned int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
    104     {
    105         if (attributes[i].active)
    106         {
    107             D3D11_INPUT_CLASSIFICATION inputClass = attributes[i].divisor > 0 ? D3D11_INPUT_PER_INSTANCE_DATA : D3D11_INPUT_PER_VERTEX_DATA;
    108 
    109             gl::VertexFormat vertexFormat(*attributes[i].attribute, attributes[i].currentValueType);
    110             const d3d11::VertexFormat &vertexFormatInfo = d3d11::GetVertexFormatInfo(vertexFormat);
    111 
    112             // Record the type of the associated vertex shader vector in our key
    113             // This will prevent mismatched vertex shaders from using the same input layout
    114             GLint attributeSize;
    115             programBinary->getActiveAttribute(ilKey.elementCount, 0, NULL, &attributeSize, &ilKey.elements[ilKey.elementCount].glslElementType, NULL);
    116 
    117             ilKey.elements[ilKey.elementCount].desc.SemanticName = semanticName;
    118             ilKey.elements[ilKey.elementCount].desc.SemanticIndex = sortedSemanticIndices[i];
    119             ilKey.elements[ilKey.elementCount].desc.Format = vertexFormatInfo.nativeFormat;
    120             ilKey.elements[ilKey.elementCount].desc.InputSlot = i;
    121             ilKey.elements[ilKey.elementCount].desc.AlignedByteOffset = 0;
    122             ilKey.elements[ilKey.elementCount].desc.InputSlotClass = inputClass;
    123             ilKey.elements[ilKey.elementCount].desc.InstanceDataStepRate = attributes[i].divisor;
    124             ilKey.elementCount++;
    125         }
    126     }
    127 
    128     ID3D11InputLayout *inputLayout = NULL;
    129 
    130     InputLayoutMap::iterator keyIter = mInputLayoutMap.find(ilKey);
    131     if (keyIter != mInputLayoutMap.end())
    132     {
    133         inputLayout = keyIter->second.inputLayout;
    134         keyIter->second.lastUsedTime = mCounter++;
    135     }
    136     else
    137     {
    138         gl::VertexFormat shaderInputLayout[gl::MAX_VERTEX_ATTRIBS];
    139         GetInputLayout(attributes, shaderInputLayout);
    140         ShaderExecutable11 *shader = ShaderExecutable11::makeShaderExecutable11(programBinary->getVertexExecutableForInputLayout(shaderInputLayout));
    141 
    142         D3D11_INPUT_ELEMENT_DESC descs[gl::MAX_VERTEX_ATTRIBS];
    143         for (unsigned int j = 0; j < ilKey.elementCount; ++j)
    144         {
    145             descs[j] = ilKey.elements[j].desc;
    146         }
    147 
    148         HRESULT result = mDevice->CreateInputLayout(descs, ilKey.elementCount, shader->getFunction(), shader->getLength(), &inputLayout);
    149         if (FAILED(result))
    150         {
    151             return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal input layout, HRESULT: 0x%08x", result);
    152         }
    153 
    154         if (mInputLayoutMap.size() >= kMaxInputLayouts)
    155         {
    156             TRACE("Overflowed the limit of %u input layouts, removing the least recently used "
    157                   "to make room.", kMaxInputLayouts);
    158 
    159             InputLayoutMap::iterator leastRecentlyUsed = mInputLayoutMap.begin();
    160             for (InputLayoutMap::iterator i = mInputLayoutMap.begin(); i != mInputLayoutMap.end(); i++)
    161             {
    162                 if (i->second.lastUsedTime < leastRecentlyUsed->second.lastUsedTime)
    163                 {
    164                     leastRecentlyUsed = i;
    165                 }
    166             }
    167             SafeRelease(leastRecentlyUsed->second.inputLayout);
    168             mInputLayoutMap.erase(leastRecentlyUsed);
    169         }
    170 
    171         InputLayoutCounterPair inputCounterPair;
    172         inputCounterPair.inputLayout = inputLayout;
    173         inputCounterPair.lastUsedTime = mCounter++;
    174 
    175         mInputLayoutMap.insert(std::make_pair(ilKey, inputCounterPair));
    176     }
    177 
    178     if (inputLayout != mCurrentIL)
    179     {
    180         mDeviceContext->IASetInputLayout(inputLayout);
    181         mCurrentIL = inputLayout;
    182     }
    183 
    184     bool dirtyBuffers = false;
    185     size_t minDiff = gl::MAX_VERTEX_ATTRIBS;
    186     size_t maxDiff = 0;
    187     for (unsigned int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
    188     {
    189         ID3D11Buffer *buffer = NULL;
    190 
    191         if (attributes[i].active)
    192         {
    193             VertexBuffer11 *vertexBuffer = VertexBuffer11::makeVertexBuffer11(attributes[i].vertexBuffer);
    194             Buffer11 *bufferStorage = attributes[i].storage ? Buffer11::makeBuffer11(attributes[i].storage) : NULL;
    195 
    196             buffer = bufferStorage ? bufferStorage->getBuffer(BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK)
    197                                    : vertexBuffer->getBuffer();
    198         }
    199 
    200         UINT vertexStride = attributes[i].stride;
    201         UINT vertexOffset = attributes[i].offset;
    202 
    203         if (buffer != mCurrentBuffers[i] || vertexStride != mCurrentVertexStrides[i] ||
    204             vertexOffset != mCurrentVertexOffsets[i])
    205         {
    206             dirtyBuffers = true;
    207             minDiff = std::min(minDiff, static_cast<size_t>(i));
    208             maxDiff = std::max(maxDiff, static_cast<size_t>(i));
    209 
    210             mCurrentBuffers[i] = buffer;
    211             mCurrentVertexStrides[i] = vertexStride;
    212             mCurrentVertexOffsets[i] = vertexOffset;
    213         }
    214     }
    215 
    216     if (dirtyBuffers)
    217     {
    218         ASSERT(minDiff <= maxDiff && maxDiff < gl::MAX_VERTEX_ATTRIBS);
    219         mDeviceContext->IASetVertexBuffers(minDiff, maxDiff - minDiff + 1, mCurrentBuffers + minDiff,
    220                                            mCurrentVertexStrides + minDiff, mCurrentVertexOffsets + minDiff);
    221     }
    222 
    223     return gl::Error(GL_NO_ERROR);
    224 }
    225 
    226 std::size_t InputLayoutCache::hashInputLayout(const InputLayoutKey &inputLayout)
    227 {
    228     static const unsigned int seed = 0xDEADBEEF;
    229 
    230     std::size_t hash = 0;
    231     MurmurHash3_x86_32(inputLayout.begin(), inputLayout.end() - inputLayout.begin(), seed, &hash);
    232     return hash;
    233 }
    234 
    235 bool InputLayoutCache::compareInputLayouts(const InputLayoutKey &a, const InputLayoutKey &b)
    236 {
    237     if (a.elementCount != b.elementCount)
    238     {
    239         return false;
    240     }
    241 
    242     return std::equal(a.begin(), a.end(), b.begin());
    243 }
    244 
    245 }
    246