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 // VertexDeclarationCache.cpp: Implements a helper class to construct and cache vertex declarations.
      9 
     10 #include "libGLESv2/ProgramBinary.h"
     11 #include "libGLESv2/Context.h"
     12 #include "libGLESv2/renderer/VertexBuffer9.h"
     13 #include "libGLESv2/renderer/VertexDeclarationCache.h"
     14 
     15 namespace rx
     16 {
     17 
     18 VertexDeclarationCache::VertexDeclarationCache() : mMaxLru(0)
     19 {
     20     for (int i = 0; i < NUM_VERTEX_DECL_CACHE_ENTRIES; i++)
     21     {
     22         mVertexDeclCache[i].vertexDeclaration = NULL;
     23         mVertexDeclCache[i].lruCount = 0;
     24     }
     25 
     26     for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
     27     {
     28         mAppliedVBs[i].serial = 0;
     29     }
     30 
     31     mLastSetVDecl = NULL;
     32     mInstancingEnabled = true;
     33 }
     34 
     35 VertexDeclarationCache::~VertexDeclarationCache()
     36 {
     37     for (int i = 0; i < NUM_VERTEX_DECL_CACHE_ENTRIES; i++)
     38     {
     39         if (mVertexDeclCache[i].vertexDeclaration)
     40         {
     41             mVertexDeclCache[i].vertexDeclaration->Release();
     42         }
     43     }
     44 }
     45 
     46 GLenum VertexDeclarationCache::applyDeclaration(IDirect3DDevice9 *device, TranslatedAttribute attributes[], gl::ProgramBinary *programBinary, GLsizei instances, GLsizei *repeatDraw)
     47 {
     48     *repeatDraw = 1;
     49 
     50     int indexedAttribute = gl::MAX_VERTEX_ATTRIBS;
     51     int instancedAttribute = gl::MAX_VERTEX_ATTRIBS;
     52 
     53     if (instances > 0)
     54     {
     55         // Find an indexed attribute to be mapped to D3D stream 0
     56         for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
     57         {
     58             if (attributes[i].active)
     59             {
     60                 if (indexedAttribute == gl::MAX_VERTEX_ATTRIBS && attributes[i].divisor == 0)
     61                 {
     62                     indexedAttribute = i;
     63                 }
     64                 else if (instancedAttribute == gl::MAX_VERTEX_ATTRIBS && attributes[i].divisor != 0)
     65                 {
     66                     instancedAttribute = i;
     67                 }
     68                 if (indexedAttribute != gl::MAX_VERTEX_ATTRIBS && instancedAttribute != gl::MAX_VERTEX_ATTRIBS)
     69                     break;   // Found both an indexed and instanced attribute
     70             }
     71         }
     72 
     73         if (indexedAttribute == gl::MAX_VERTEX_ATTRIBS)
     74         {
     75             return GL_INVALID_OPERATION;
     76         }
     77     }
     78 
     79     D3DVERTEXELEMENT9 elements[gl::MAX_VERTEX_ATTRIBS + 1];
     80     D3DVERTEXELEMENT9 *element = &elements[0];
     81 
     82     for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
     83     {
     84         if (attributes[i].active)
     85         {
     86             // Directly binding the storage buffer is not supported for d3d9
     87             ASSERT(attributes[i].storage == NULL);
     88 
     89             int stream = i;
     90 
     91             if (instances > 0)
     92             {
     93                 // Due to a bug on ATI cards we can't enable instancing when none of the attributes are instanced.
     94                 if (instancedAttribute == gl::MAX_VERTEX_ATTRIBS)
     95                 {
     96                     *repeatDraw = instances;
     97                 }
     98                 else
     99                 {
    100                     if (i == indexedAttribute)
    101                     {
    102                         stream = 0;
    103                     }
    104                     else if (i == 0)
    105                     {
    106                         stream = indexedAttribute;
    107                     }
    108 
    109                     UINT frequency = 1;
    110 
    111                     if (attributes[i].divisor == 0)
    112                     {
    113                         frequency = D3DSTREAMSOURCE_INDEXEDDATA | instances;
    114                     }
    115                     else
    116                     {
    117                         frequency = D3DSTREAMSOURCE_INSTANCEDATA | attributes[i].divisor;
    118                     }
    119 
    120                     device->SetStreamSourceFreq(stream, frequency);
    121                     mInstancingEnabled = true;
    122                 }
    123             }
    124 
    125             VertexBuffer9 *vertexBuffer = VertexBuffer9::makeVertexBuffer9(attributes[i].vertexBuffer);
    126 
    127             if (mAppliedVBs[stream].serial != attributes[i].serial ||
    128                 mAppliedVBs[stream].stride != attributes[i].stride ||
    129                 mAppliedVBs[stream].offset != attributes[i].offset)
    130             {
    131                 device->SetStreamSource(stream, vertexBuffer->getBuffer(), attributes[i].offset, attributes[i].stride);
    132                 mAppliedVBs[stream].serial = attributes[i].serial;
    133                 mAppliedVBs[stream].stride = attributes[i].stride;
    134                 mAppliedVBs[stream].offset = attributes[i].offset;
    135             }
    136 
    137             element->Stream = stream;
    138             element->Offset = 0;
    139             element->Type = attributes[i].attribute->mArrayEnabled ? vertexBuffer->getDeclType(*attributes[i].attribute) : D3DDECLTYPE_FLOAT4;
    140             element->Method = D3DDECLMETHOD_DEFAULT;
    141             element->Usage = D3DDECLUSAGE_TEXCOORD;
    142             element->UsageIndex = programBinary->getSemanticIndex(i);
    143             element++;
    144         }
    145     }
    146 
    147     if (instances == 0 || instancedAttribute == gl::MAX_VERTEX_ATTRIBS)
    148     {
    149         if (mInstancingEnabled)
    150         {
    151             for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
    152             {
    153                 device->SetStreamSourceFreq(i, 1);
    154             }
    155 
    156             mInstancingEnabled = false;
    157         }
    158     }
    159 
    160     static const D3DVERTEXELEMENT9 end = D3DDECL_END();
    161     *(element++) = end;
    162 
    163     for (int i = 0; i < NUM_VERTEX_DECL_CACHE_ENTRIES; i++)
    164     {
    165         VertexDeclCacheEntry *entry = &mVertexDeclCache[i];
    166         if (memcmp(entry->cachedElements, elements, (element - elements) * sizeof(D3DVERTEXELEMENT9)) == 0 && entry->vertexDeclaration)
    167         {
    168             entry->lruCount = ++mMaxLru;
    169             if(entry->vertexDeclaration != mLastSetVDecl)
    170             {
    171                 device->SetVertexDeclaration(entry->vertexDeclaration);
    172                 mLastSetVDecl = entry->vertexDeclaration;
    173             }
    174 
    175             return GL_NO_ERROR;
    176         }
    177     }
    178 
    179     VertexDeclCacheEntry *lastCache = mVertexDeclCache;
    180 
    181     for (int i = 0; i < NUM_VERTEX_DECL_CACHE_ENTRIES; i++)
    182     {
    183         if (mVertexDeclCache[i].lruCount < lastCache->lruCount)
    184         {
    185             lastCache = &mVertexDeclCache[i];
    186         }
    187     }
    188 
    189     if (lastCache->vertexDeclaration != NULL)
    190     {
    191         lastCache->vertexDeclaration->Release();
    192         lastCache->vertexDeclaration = NULL;
    193         // mLastSetVDecl is set to the replacement, so we don't have to worry
    194         // about it.
    195     }
    196 
    197     memcpy(lastCache->cachedElements, elements, (element - elements) * sizeof(D3DVERTEXELEMENT9));
    198     device->CreateVertexDeclaration(elements, &lastCache->vertexDeclaration);
    199     device->SetVertexDeclaration(lastCache->vertexDeclaration);
    200     mLastSetVDecl = lastCache->vertexDeclaration;
    201     lastCache->lruCount = ++mMaxLru;
    202 
    203     return GL_NO_ERROR;
    204 }
    205 
    206 void VertexDeclarationCache::markStateDirty()
    207 {
    208     for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
    209     {
    210         mAppliedVBs[i].serial = 0;
    211     }
    212 
    213     mLastSetVDecl = NULL;
    214     mInstancingEnabled = true;   // Forces it to be disabled when not used
    215 }
    216 
    217 }
    218