Home | History | Annotate | Download | only in renderer
      1 #include "precompiled.h"
      2 //
      3 // Copyright (c) 2012 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 // InputLayoutCache.cpp: Defines InputLayoutCache, a class that builds and caches
      9 // D3D11 input layouts.
     10 
     11 #include "libGLESv2/renderer/InputLayoutCache.h"
     12 #include "libGLESv2/renderer/VertexBuffer11.h"
     13 #include "libGLESv2/renderer/BufferStorage11.h"
     14 #include "libGLESv2/renderer/ShaderExecutable11.h"
     15 #include "libGLESv2/ProgramBinary.h"
     16 #include "libGLESv2/Context.h"
     17 #include "libGLESv2/renderer/VertexDataManager.h"
     18 
     19 #include "third_party/murmurhash/MurmurHash3.h"
     20 
     21 namespace rx
     22 {
     23 
     24 const unsigned int InputLayoutCache::kMaxInputLayouts = 1024;
     25 
     26 InputLayoutCache::InputLayoutCache() : mInputLayoutMap(kMaxInputLayouts, hashInputLayout, compareInputLayouts)
     27 {
     28     mCounter = 0;
     29     mDevice = NULL;
     30     mDeviceContext = NULL;
     31     mCurrentIL = NULL;
     32     for (unsigned int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
     33     {
     34         mCurrentBuffers[i] = -1;
     35         mCurrentVertexStrides[i] = -1;
     36         mCurrentVertexOffsets[i] = -1;
     37     }
     38 }
     39 
     40 InputLayoutCache::~InputLayoutCache()
     41 {
     42     clear();
     43 }
     44 
     45 void InputLayoutCache::initialize(ID3D11Device *device, ID3D11DeviceContext *context)
     46 {
     47     clear();
     48     mDevice = device;
     49     mDeviceContext = context;
     50 }
     51 
     52 void InputLayoutCache::clear()
     53 {
     54     for (InputLayoutMap::iterator i = mInputLayoutMap.begin(); i != mInputLayoutMap.end(); i++)
     55     {
     56         i->second.inputLayout->Release();
     57     }
     58     mInputLayoutMap.clear();
     59     markDirty();
     60 }
     61 
     62 void InputLayoutCache::markDirty()
     63 {
     64     mCurrentIL = NULL;
     65     for (unsigned int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
     66     {
     67         mCurrentBuffers[i] = -1;
     68         mCurrentVertexStrides[i] = -1;
     69         mCurrentVertexOffsets[i] = -1;
     70     }
     71 }
     72 
     73 GLenum InputLayoutCache::applyVertexBuffers(TranslatedAttribute attributes[gl::MAX_VERTEX_ATTRIBS],
     74                                             gl::ProgramBinary *programBinary)
     75 {
     76     int sortedSemanticIndices[gl::MAX_VERTEX_ATTRIBS];
     77     programBinary->sortAttributesByLayout(attributes, sortedSemanticIndices);
     78 
     79     if (!mDevice || !mDeviceContext)
     80     {
     81         ERR("InputLayoutCache is not initialized.");
     82         return GL_INVALID_OPERATION;
     83     }
     84 
     85     InputLayoutKey ilKey = { 0 };
     86 
     87     ID3D11Buffer *vertexBuffers[gl::MAX_VERTEX_ATTRIBS] = { NULL };
     88     unsigned int vertexBufferSerials[gl::MAX_VERTEX_ATTRIBS] = { 0 };
     89     UINT vertexStrides[gl::MAX_VERTEX_ATTRIBS] = { 0 };
     90     UINT vertexOffsets[gl::MAX_VERTEX_ATTRIBS] = { 0 };
     91 
     92     static const char* semanticName = "TEXCOORD";
     93 
     94     for (unsigned int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
     95     {
     96         if (attributes[i].active)
     97         {
     98             VertexBuffer11 *vertexBuffer = VertexBuffer11::makeVertexBuffer11(attributes[i].vertexBuffer);
     99             BufferStorage11 *bufferStorage = attributes[i].storage ? BufferStorage11::makeBufferStorage11(attributes[i].storage) : NULL;
    100 
    101             D3D11_INPUT_CLASSIFICATION inputClass = attributes[i].divisor > 0 ? D3D11_INPUT_PER_INSTANCE_DATA : D3D11_INPUT_PER_VERTEX_DATA;
    102 
    103             // Record the type of the associated vertex shader vector in our key
    104             // This will prevent mismatched vertex shaders from using the same input layout
    105             GLint attributeSize;
    106             programBinary->getActiveAttribute(ilKey.elementCount, 0, NULL, &attributeSize, &ilKey.glslElementType[ilKey.elementCount], NULL);
    107 
    108             ilKey.elements[ilKey.elementCount].SemanticName = semanticName;
    109             ilKey.elements[ilKey.elementCount].SemanticIndex = sortedSemanticIndices[i];
    110             ilKey.elements[ilKey.elementCount].Format = attributes[i].attribute->mArrayEnabled ? vertexBuffer->getDXGIFormat(*attributes[i].attribute) : DXGI_FORMAT_R32G32B32A32_FLOAT;
    111             ilKey.elements[ilKey.elementCount].InputSlot = i;
    112             ilKey.elements[ilKey.elementCount].AlignedByteOffset = 0;
    113             ilKey.elements[ilKey.elementCount].InputSlotClass = inputClass;
    114             ilKey.elements[ilKey.elementCount].InstanceDataStepRate = attributes[i].divisor;
    115             ilKey.elementCount++;
    116 
    117             vertexBuffers[i] = bufferStorage ? bufferStorage->getBuffer() : vertexBuffer->getBuffer();
    118             vertexBufferSerials[i] = bufferStorage ? bufferStorage->getSerial() : vertexBuffer->getSerial();
    119             vertexStrides[i] = attributes[i].stride;
    120             vertexOffsets[i] = attributes[i].offset;
    121         }
    122     }
    123 
    124     ID3D11InputLayout *inputLayout = NULL;
    125 
    126     InputLayoutMap::iterator i = mInputLayoutMap.find(ilKey);
    127     if (i != mInputLayoutMap.end())
    128     {
    129         inputLayout = i->second.inputLayout;
    130         i->second.lastUsedTime = mCounter++;
    131     }
    132     else
    133     {
    134         ShaderExecutable11 *shader = ShaderExecutable11::makeShaderExecutable11(programBinary->getVertexExecutable());
    135 
    136         HRESULT result = mDevice->CreateInputLayout(ilKey.elements, ilKey.elementCount, shader->getFunction(), shader->getLength(), &inputLayout);
    137         if (FAILED(result))
    138         {
    139             ERR("Failed to crate input layout, result: 0x%08x", result);
    140             return GL_INVALID_OPERATION;
    141         }
    142 
    143         if (mInputLayoutMap.size() >= kMaxInputLayouts)
    144         {
    145             TRACE("Overflowed the limit of %u input layouts, removing the least recently used "
    146                   "to make room.", kMaxInputLayouts);
    147 
    148             InputLayoutMap::iterator leastRecentlyUsed = mInputLayoutMap.begin();
    149             for (InputLayoutMap::iterator i = mInputLayoutMap.begin(); i != mInputLayoutMap.end(); i++)
    150             {
    151                 if (i->second.lastUsedTime < leastRecentlyUsed->second.lastUsedTime)
    152                 {
    153                     leastRecentlyUsed = i;
    154                 }
    155             }
    156             leastRecentlyUsed->second.inputLayout->Release();
    157             mInputLayoutMap.erase(leastRecentlyUsed);
    158         }
    159 
    160         InputLayoutCounterPair inputCounterPair;
    161         inputCounterPair.inputLayout = inputLayout;
    162         inputCounterPair.lastUsedTime = mCounter++;
    163 
    164         mInputLayoutMap.insert(std::make_pair(ilKey, inputCounterPair));
    165     }
    166 
    167     if (inputLayout != mCurrentIL)
    168     {
    169         mDeviceContext->IASetInputLayout(inputLayout);
    170         mCurrentIL = inputLayout;
    171     }
    172 
    173     for (unsigned int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
    174     {
    175         if (vertexBufferSerials[i] != mCurrentBuffers[i] || vertexStrides[i] != mCurrentVertexStrides[i] ||
    176             vertexOffsets[i] != mCurrentVertexOffsets[i])
    177         {
    178             mDeviceContext->IASetVertexBuffers(i, 1, &vertexBuffers[i], &vertexStrides[i], &vertexOffsets[i]);
    179             mCurrentBuffers[i] = vertexBufferSerials[i];
    180             mCurrentVertexStrides[i] = vertexStrides[i];
    181             mCurrentVertexOffsets[i] = vertexOffsets[i];
    182         }
    183     }
    184 
    185     return GL_NO_ERROR;
    186 }
    187 
    188 std::size_t InputLayoutCache::hashInputLayout(const InputLayoutKey &inputLayout)
    189 {
    190     static const unsigned int seed = 0xDEADBEEF;
    191 
    192     std::size_t hash = 0;
    193     MurmurHash3_x86_32(&inputLayout, sizeof(InputLayoutKey), seed, &hash);
    194     return hash;
    195 }
    196 
    197 bool InputLayoutCache::compareInputLayouts(const InputLayoutKey &a, const InputLayoutKey &b)
    198 {
    199     return memcmp(&a, &b, sizeof(InputLayoutKey)) == 0;
    200 }
    201 
    202 }
    203