Move the vertex data manager and vertex declaration cache from Context to Renderer9.

TRAC #22016
Signed-off-by: Daniel Koch
Signed-off-by: Shannon Woods
Author: Nicolas Capens

git-svn-id: https://angleproject.googlecode.com/svn/branches/dx11proto@1474 736b8ea6-26fd-11df-bfd4-992fa37f6226
diff --git a/src/libGLESv2/renderer/Renderer9.cpp b/src/libGLESv2/renderer/Renderer9.cpp
index cab7b88..accc6f8 100644
--- a/src/libGLESv2/renderer/Renderer9.cpp
+++ b/src/libGLESv2/renderer/Renderer9.cpp
@@ -13,6 +13,7 @@
 #include "libGLESv2/Framebuffer.h"
 #include "libGLESv2/Program.h"
 #include "libGLESv2/ProgramBinary.h"
+#include "libGLESv2/VertexDataManager.h"
 #include "libGLESv2/renderer/Renderer9.h"
 #include "libGLESv2/renderer/renderer9_utils.h"
 #include "libGLESv2/renderer/SwapChain9.h"
@@ -85,6 +86,8 @@
     mDeviceLost = false;
 
     mMaxSupportedSamples = 0;
+
+    mVertexDataManager = NULL;
 }
 
 Renderer9::~Renderer9()
@@ -390,6 +393,11 @@
     markAllStateDirty();
 
     mSceneStarted = false;
+
+    if (!mVertexDataManager)
+    {
+        mVertexDataManager = new gl::VertexDataManager(this);
+    }
 }
 
 D3DPRESENT_PARAMETERS Renderer9::getDefaultPresentParameters()
@@ -1083,6 +1091,18 @@
     return true;
 }
 
+GLenum Renderer9::applyVertexBuffer(gl::ProgramBinary *programBinary, gl::VertexAttribute vertexAttributes[], GLint first, GLsizei count, GLsizei instances, GLsizei *repeatDraw)
+{
+    gl::TranslatedAttribute attributes[gl::MAX_VERTEX_ATTRIBS];
+    GLenum err = mVertexDataManager->prepareVertexData(vertexAttributes, programBinary, first, count, attributes, instances);
+    if (err != GL_NO_ERROR)
+    {
+        return err;
+    }
+    
+    return mVertexDeclarationCache.applyDeclaration(mDevice, attributes, programBinary, instances, repeatDraw);
+}
+
 void Renderer9::clear(GLbitfield mask, const gl::Color &colorClear, float depthClear, int stencilClear,
                       gl::Framebuffer *frameBuffer)
 {
@@ -1104,6 +1124,8 @@
     mForceSetBlendState = true;
     mForceSetScissor = true;
     mForceSetViewport = true;
+
+    mVertexDeclarationCache.markStateDirty();
 }
 
 void Renderer9::releaseDeviceResources()
@@ -1116,6 +1138,9 @@
 
     mVertexShaderCache.clear();
     mPixelShaderCache.clear();
+
+    delete mVertexDataManager;
+    mVertexDataManager = NULL;
 }
 
 
@@ -2168,6 +2193,205 @@
     }
 
     return true;
-} 
+}
+
+VertexDeclarationCache::VertexDeclarationCache() : mMaxLru(0)
+{
+    for (int i = 0; i < NUM_VERTEX_DECL_CACHE_ENTRIES; i++)
+    {
+        mVertexDeclCache[i].vertexDeclaration = NULL;
+        mVertexDeclCache[i].lruCount = 0;
+    }
+
+    for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
+    {
+        mAppliedVBs[i].serial = 0;
+    }
+
+    mLastSetVDecl = NULL;
+    mInstancingEnabled = true;
+}
+
+VertexDeclarationCache::~VertexDeclarationCache()
+{
+    for (int i = 0; i < NUM_VERTEX_DECL_CACHE_ENTRIES; i++)
+    {
+        if (mVertexDeclCache[i].vertexDeclaration)
+        {
+            mVertexDeclCache[i].vertexDeclaration->Release();
+        }
+    }
+}
+
+GLenum VertexDeclarationCache::applyDeclaration(IDirect3DDevice9 *device, gl::TranslatedAttribute attributes[], gl::ProgramBinary *programBinary, GLsizei instances, GLsizei *repeatDraw)
+{
+    *repeatDraw = 1;
+
+    int indexedAttribute = gl::MAX_VERTEX_ATTRIBS;
+    int instancedAttribute = gl::MAX_VERTEX_ATTRIBS;
+
+    if (instances > 0)
+    {
+        // Find an indexed attribute to be mapped to D3D stream 0
+        for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
+        {
+            if (attributes[i].active)
+            {
+                if (indexedAttribute == gl::MAX_VERTEX_ATTRIBS)
+                {
+                    if (attributes[i].divisor == 0)
+                    {
+                        indexedAttribute = i;
+                    }
+                }
+                else if (instancedAttribute == gl::MAX_VERTEX_ATTRIBS)
+                {
+                    if (attributes[i].divisor != 0)
+                    {
+                        instancedAttribute = i;
+                    }
+                }
+                else break;   // Found both an indexed and instanced attribute
+            }
+        }
+
+        if (indexedAttribute == gl::MAX_VERTEX_ATTRIBS)
+        {
+            return GL_INVALID_OPERATION;
+        }
+    }
+
+    D3DVERTEXELEMENT9 elements[gl::MAX_VERTEX_ATTRIBS + 1];
+    D3DVERTEXELEMENT9 *element = &elements[0];
+
+    for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
+    {
+        if (attributes[i].active)
+        {
+            int stream = i;
+
+            if (instances > 0)
+            {
+                // Due to a bug on ATI cards we can't enable instancing when none of the attributes are instanced.
+                if (instancedAttribute == gl::MAX_VERTEX_ATTRIBS)
+                {
+                    *repeatDraw = instances;
+                }
+                else
+                {
+                    if (i == indexedAttribute)
+                    {
+                        stream = 0;
+                    }
+                    else if (i == 0)
+                    {
+                        stream = indexedAttribute;
+                    }
+
+                    UINT frequency = 1;
+                    
+                    if (attributes[i].divisor == 0)
+                    {
+                        frequency = D3DSTREAMSOURCE_INDEXEDDATA | instances;
+                    }
+                    else
+                    {
+                        frequency = D3DSTREAMSOURCE_INSTANCEDATA | attributes[i].divisor;
+                    }
+                    
+                    device->SetStreamSourceFreq(stream, frequency);
+                    mInstancingEnabled = true;
+                }
+            }
+
+            if (mAppliedVBs[stream].serial != attributes[i].serial ||
+                mAppliedVBs[stream].stride != attributes[i].stride ||
+                mAppliedVBs[stream].offset != attributes[i].offset)
+            {
+                device->SetStreamSource(stream, attributes[i].vertexBuffer, attributes[i].offset, attributes[i].stride);
+                mAppliedVBs[stream].serial = attributes[i].serial;
+                mAppliedVBs[stream].stride = attributes[i].stride;
+                mAppliedVBs[stream].offset = attributes[i].offset;
+            }
+
+            element->Stream = stream;
+            element->Offset = 0;
+            element->Type = attributes[i].type;
+            element->Method = D3DDECLMETHOD_DEFAULT;
+            element->Usage = D3DDECLUSAGE_TEXCOORD;
+            element->UsageIndex = programBinary->getSemanticIndex(i);
+            element++;
+        }
+    }
+
+    if (instances == 0 || instancedAttribute == gl::MAX_VERTEX_ATTRIBS)
+    {
+        if (mInstancingEnabled)
+        {
+            for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
+            {
+                device->SetStreamSourceFreq(i, 1);
+            }
+
+            mInstancingEnabled = false;
+        }
+    }
+
+    static const D3DVERTEXELEMENT9 end = D3DDECL_END();
+    *(element++) = end;
+
+    for (int i = 0; i < NUM_VERTEX_DECL_CACHE_ENTRIES; i++)
+    {
+        VertexDeclCacheEntry *entry = &mVertexDeclCache[i];
+        if (memcmp(entry->cachedElements, elements, (element - elements) * sizeof(D3DVERTEXELEMENT9)) == 0 && entry->vertexDeclaration)
+        {
+            entry->lruCount = ++mMaxLru;
+            if(entry->vertexDeclaration != mLastSetVDecl)
+            {
+                device->SetVertexDeclaration(entry->vertexDeclaration);
+                mLastSetVDecl = entry->vertexDeclaration;
+            }
+
+            return GL_NO_ERROR;
+        }
+    }
+
+    VertexDeclCacheEntry *lastCache = mVertexDeclCache;
+
+    for (int i = 0; i < NUM_VERTEX_DECL_CACHE_ENTRIES; i++)
+    {
+        if (mVertexDeclCache[i].lruCount < lastCache->lruCount)
+        {
+            lastCache = &mVertexDeclCache[i];
+        }
+    }
+
+    if (lastCache->vertexDeclaration != NULL)
+    {
+        lastCache->vertexDeclaration->Release();
+        lastCache->vertexDeclaration = NULL;
+        // mLastSetVDecl is set to the replacement, so we don't have to worry
+        // about it.
+    }
+
+    memcpy(lastCache->cachedElements, elements, (element - elements) * sizeof(D3DVERTEXELEMENT9));
+    device->CreateVertexDeclaration(elements, &lastCache->vertexDeclaration);
+    device->SetVertexDeclaration(lastCache->vertexDeclaration);
+    mLastSetVDecl = lastCache->vertexDeclaration;
+    lastCache->lruCount = ++mMaxLru;
+
+    return GL_NO_ERROR;
+}
+
+void VertexDeclarationCache::markStateDirty()
+{
+    for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
+    {
+        mAppliedVBs[i].serial = 0;
+    }
+
+    mLastSetVDecl = NULL;
+    mInstancingEnabled = true;   // Forces it to be disabled when not used
+}
 
 }
\ No newline at end of file