Moved VertexDeclarationCache to its own header and source file.

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

git-svn-id: https://angleproject.googlecode.com/svn/branches/dx11proto@1490 736b8ea6-26fd-11df-bfd4-992fa37f6226
diff --git a/src/libGLESv2/renderer/VertexDeclarationCache.cpp b/src/libGLESv2/renderer/VertexDeclarationCache.cpp
new file mode 100644
index 0000000..7beaaeb
--- /dev/null
+++ b/src/libGLESv2/renderer/VertexDeclarationCache.cpp
@@ -0,0 +1,215 @@
+//

+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.

+// Use of this source code is governed by a BSD-style license that can be

+// found in the LICENSE file.

+//

+

+// VertexDeclarationCache.cpp: Implements a helper class to construct and cache vertex declarations.

+

+#include "libGLESv2/ProgramBinary.h"

+#include "libGLESv2/VertexDataManager.h"

+#include "libGLESv2/renderer/VertexDeclarationCache.h"

+

+namespace rx

+{

+

+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

+}

+

+}