Moved D3DConstantTable, IndexDataManager, VertexDataManager and vertexconversion files.
TRAC #22198
Signed-off-by: Nicolas Capens
Signed-off-by: Daniel Koch
git-svn-id: https://angleproject.googlecode.com/svn/branches/dx11proto@1547 736b8ea6-26fd-11df-bfd4-992fa37f6226
diff --git a/src/libGLESv2/renderer/D3DConstantTable.cpp b/src/libGLESv2/renderer/D3DConstantTable.cpp
new file mode 100644
index 0000000..10a0f9d
--- /dev/null
+++ b/src/libGLESv2/renderer/D3DConstantTable.cpp
@@ -0,0 +1,231 @@
+//
+// 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.
+//
+
+// D3DConstantTable.cpp: Implements the D3DConstantTable class which parses
+// information about constants from the CTAB comment in a D3D shader blob.
+// Restructures the constant table as a hierarchy of constants in the same
+// way as D3DX.
+
+#include "libGLESv2/renderer/D3DConstantTable.h"
+
+#include <d3d9.h>
+#include <d3d9types.h>
+#include <windows.h>
+#include <mmsystem.h>
+
+#include "libGLESv2/BinaryStream.h"
+
+const static int SHADER_VERSION_MASK = D3DVS_VERSION(0, 0);
+const static int FOURCC_CTAB = MAKEFOURCC('C','T','A','B');
+
+namespace gl
+{
+// These structs and constants correspond to the format of the constant table in a shader binary.
+// They match the corresponding structures in d3dx9shader.h.
+namespace ctab
+{
+struct ConstantTable
+{
+ DWORD size;
+ DWORD creator;
+ DWORD version;
+ DWORD constants;
+ DWORD constantInfos;
+ DWORD flags;
+ DWORD target;
+};
+
+struct ConstantInfo
+{
+ DWORD name;
+ WORD registerSet;
+ WORD registerIndex;
+ WORD registerCount;
+ WORD reserved;
+ DWORD typeInfo;
+ DWORD defaultValue;
+};
+
+struct TypeInfo
+{
+ WORD typeClass;
+ WORD type;
+ WORD rows;
+ WORD columns;
+ WORD elements;
+ WORD structMembers;
+ DWORD structMemberInfos;
+};
+
+struct StructMemberInfo
+{
+ DWORD name;
+ DWORD typeInfo;
+};
+}
+
+D3DConstant::D3DConstant(const char *base, const ctab::ConstantInfo *constantInfo)
+{
+ const ctab::TypeInfo *typeInfo = reinterpret_cast<const ctab::TypeInfo*>(base + constantInfo->typeInfo);
+
+ name = base + constantInfo->name;
+ registerSet = static_cast<RegisterSet>(constantInfo->registerSet);
+ registerIndex = constantInfo->registerIndex;
+ registerCount = constantInfo->registerCount;
+ typeClass = static_cast<Class>(typeInfo->typeClass);
+ type = static_cast<Type>(typeInfo->type);
+ rows = typeInfo->rows;
+ columns = typeInfo->columns;
+ elements = typeInfo->elements;
+
+ if (typeClass == CLASS_STRUCT)
+ {
+ addStructMembers(base, registerSet, registerIndex, typeInfo);
+ }
+}
+
+D3DConstant::D3DConstant(const char *base, RegisterSet registerSet, unsigned registerIndex, const ctab::StructMemberInfo *memberInfo)
+ : registerSet(registerSet), registerIndex(registerIndex)
+{
+ const ctab::TypeInfo *typeInfo = reinterpret_cast<const ctab::TypeInfo*>(base + memberInfo->typeInfo);
+
+ name = base + memberInfo->name;
+ registerCount = typeInfo->rows * typeInfo->elements;
+ typeClass = static_cast<Class>(typeInfo->typeClass);
+ type = static_cast<Type>(typeInfo->type);
+ rows = typeInfo->rows;
+ columns = typeInfo->columns;
+ elements = typeInfo->elements;
+
+ if (typeClass == CLASS_STRUCT)
+ {
+ registerCount = addStructMembers(base, registerSet, registerIndex, typeInfo);
+ }
+}
+
+D3DConstant::~D3DConstant()
+{
+ for (size_t j = 0; j < structMembers.size(); ++j)
+ {
+ for (size_t i = 0; i < structMembers[j].size(); ++i)
+ {
+ delete structMembers[j][i];
+ }
+ }
+}
+
+unsigned D3DConstant::addStructMembers(const char *base, RegisterSet registerSet, unsigned registerIndex, const ctab::TypeInfo *typeInfo)
+{
+ const ctab::StructMemberInfo *memberInfos = reinterpret_cast<const ctab::StructMemberInfo*>(
+ base + typeInfo->structMemberInfos);
+
+ unsigned memberIndex = registerIndex;
+
+ structMembers.resize(elements);
+
+ for (unsigned j = 0; j < elements; ++j)
+ {
+ structMembers[j].resize(typeInfo->structMembers);
+
+ for (unsigned i = 0; i < typeInfo->structMembers; ++i)
+ {
+ const ctab::TypeInfo *memberTypeInfo = reinterpret_cast<const ctab::TypeInfo*>(
+ base + memberInfos[i].typeInfo);
+
+ D3DConstant *member = new D3DConstant(base, registerSet, memberIndex, memberInfos + i);
+ memberIndex += member->registerCount;
+
+ structMembers[j][i] = member;
+ }
+ }
+
+ return memberIndex - registerIndex;
+}
+
+D3DConstantTable::D3DConstantTable(void *blob, size_t size) : mError(false)
+{
+ BinaryInputStream stream(blob, size);
+
+ int version;
+ stream.read(&version);
+ if ((version & SHADER_VERSION_MASK) != SHADER_VERSION_MASK)
+ {
+ mError = true;
+ return;
+ }
+
+ const ctab::ConstantTable* constantTable = NULL;
+
+ while (!stream.error())
+ {
+ int token;
+ stream.read(&token);
+
+ if ((token & D3DSI_OPCODE_MASK) == D3DSIO_COMMENT)
+ {
+ size_t length = ((token & D3DSI_COMMENTSIZE_MASK) >> D3DSI_COMMENTSIZE_SHIFT) * sizeof(DWORD);
+
+ int fourcc;
+ stream.read(&fourcc);
+ if (fourcc == FOURCC_CTAB)
+ {
+ constantTable = reinterpret_cast<const ctab::ConstantTable*>(static_cast<const char*>(blob) + stream.offset());
+ break;
+ }
+
+ stream.skip(length - sizeof(fourcc));
+ }
+ else if (token == D3DSIO_END)
+ {
+ break;
+ }
+ }
+
+ mError = !constantTable || stream.error();
+ if (mError)
+ {
+ return;
+ }
+
+ const char *base = reinterpret_cast<const char*>(constantTable);
+
+ mConstants.resize(constantTable->constants);
+ const ctab::ConstantInfo *constantInfos =
+ reinterpret_cast<const ctab::ConstantInfo*>(base + constantTable->constantInfos);
+ for (size_t i = 0; i < constantTable->constants; ++i)
+ {
+ mConstants[i] = new D3DConstant(base, constantInfos + i);
+ }
+}
+
+D3DConstantTable::~D3DConstantTable()
+{
+ for (size_t i = 0; i < mConstants.size(); ++i)
+ {
+ delete mConstants[i];
+ }
+}
+
+const D3DConstant *D3DConstantTable::getConstant(unsigned index) const
+{
+ return mConstants[index];
+}
+
+const D3DConstant *D3DConstantTable::getConstantByName(const char *name) const
+{
+ for (size_t i = 0; i < mConstants.size(); ++i)
+ {
+ const D3DConstant *constant = getConstant(i);
+ if (constant->name == name)
+ {
+ return constant;
+ }
+ }
+
+ return NULL;
+}
+
+}
diff --git a/src/libGLESv2/renderer/D3DConstantTable.h b/src/libGLESv2/renderer/D3DConstantTable.h
new file mode 100644
index 0000000..c2c8e9f
--- /dev/null
+++ b/src/libGLESv2/renderer/D3DConstantTable.h
@@ -0,0 +1,117 @@
+//
+// 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.
+//
+
+// D3DConstantTable.h: Implements the D3DConstantTable class which parses
+// information about constants from the CTAB comment in a D3D shader blob.
+// Restructures the constant table as a hierarchy of constants in the same
+// way as D3DX.
+
+#ifndef LIBGLESV2_D3DCONSTANTTABLE_H_
+#define LIBGLESV2_D3DCONSTANTTABLE_H_
+
+#include <vector>
+#include <string>
+
+#include "common/angleutils.h"
+
+namespace gl
+{
+
+namespace ctab
+{
+struct ConstantTable;
+struct ConstantInfo;
+struct TypeInfo;
+struct StructMemberInfo;
+}
+
+struct D3DConstant
+{
+ // These enums match those in d3dx9shader.h.
+ enum Class
+ {
+ CLASS_SCALAR,
+ CLASS_VECTOR,
+ CLASS_MATRIX_ROWS,
+ CLASS_MATRIX_COLUMNS,
+ CLASS_OBJECT,
+ CLASS_STRUCT,
+ };
+
+ enum RegisterSet
+ {
+ RS_BOOL,
+ RS_INT4,
+ RS_FLOAT4,
+ RS_SAMPLER,
+ };
+
+ enum Type
+ {
+ PT_VOID,
+ PT_BOOL,
+ PT_INT,
+ PT_FLOAT,
+ PT_STRING,
+ PT_TEXTURE,
+ PT_TEXTURE1D,
+ PT_TEXTURE2D,
+ PT_TEXTURE3D,
+ PT_TEXTURECUBE,
+ PT_SAMPLER,
+ PT_SAMPLER1D,
+ PT_SAMPLER2D,
+ PT_SAMPLER3D,
+ PT_SAMPLERCUBE,
+ PT_PIXELSHADER,
+ PT_VERTEXSHADER,
+ PT_PIXELFRAGMENT,
+ PT_VERTEXFRAGMENT,
+ PT_UNSUPPORTED,
+ };
+
+ D3DConstant(const char *base, const ctab::ConstantInfo *constantInfo);
+ ~D3DConstant();
+
+ std::string name;
+ RegisterSet registerSet;
+ unsigned registerIndex;
+ unsigned registerCount;
+ Class typeClass;
+ Type type;
+ unsigned rows;
+ unsigned columns;
+ unsigned elements;
+
+ // Array of structure members.
+ std::vector<std::vector<const D3DConstant*> > structMembers;
+
+ private:
+ D3DConstant(const char *base, RegisterSet registerSet, unsigned registerIndex, const ctab::StructMemberInfo *memberInfo);
+ unsigned addStructMembers(const char *base, RegisterSet registerSet, unsigned registerIndex, const ctab::TypeInfo *typeInfo);
+};
+
+class D3DConstantTable
+{
+ public:
+ D3DConstantTable(void *blob, size_t size);
+ ~D3DConstantTable();
+
+ bool error() const { return mError; }
+
+ unsigned constants() const { return mConstants.size(); }
+ const D3DConstant *getConstant(unsigned index) const;
+ const D3DConstant *getConstantByName(const char *name) const;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(D3DConstantTable);
+ std::vector<const D3DConstant*> mConstants;
+ bool mError;
+};
+
+}
+
+#endif // LIBGLESV2_D3DCONSTANTTABLE_H_
diff --git a/src/libGLESv2/renderer/IndexDataManager.cpp b/src/libGLESv2/renderer/IndexDataManager.cpp
new file mode 100644
index 0000000..272478f
--- /dev/null
+++ b/src/libGLESv2/renderer/IndexDataManager.cpp
@@ -0,0 +1,473 @@
+//
+// Copyright (c) 2002-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.
+//
+
+// IndexDataManager.cpp: Defines the IndexDataManager, a class that
+// runs the Buffer translation process for index buffers.
+
+#include "libGLESv2/renderer/IndexDataManager.h"
+
+#include "common/debug.h"
+
+#include "libGLESv2/Buffer.h"
+#include "libGLESv2/mathutil.h"
+#include "libGLESv2/main.h"
+
+namespace gl
+{
+unsigned int IndexBuffer::mCurrentSerial = 1;
+
+IndexDataManager::IndexDataManager(rx::Renderer9 *renderer) : mRenderer(renderer)
+{
+ mStreamingBufferShort = new StreamingIndexBuffer(mRenderer, INITIAL_INDEX_BUFFER_SIZE, D3DFMT_INDEX16);
+
+ if (renderer->get32BitIndexSupport())
+ {
+ mStreamingBufferInt = new StreamingIndexBuffer(mRenderer, INITIAL_INDEX_BUFFER_SIZE, D3DFMT_INDEX32);
+
+ if (!mStreamingBufferInt)
+ {
+ // Don't leave it in a half-initialized state
+ delete mStreamingBufferShort;
+ mStreamingBufferShort = NULL;
+ }
+ }
+ else
+ {
+ mStreamingBufferInt = NULL;
+ }
+
+ if (!mStreamingBufferShort)
+ {
+ ERR("Failed to allocate the streaming index buffer(s).");
+ }
+
+ mCountingBuffer = NULL;
+}
+
+IndexDataManager::~IndexDataManager()
+{
+ delete mStreamingBufferShort;
+ delete mStreamingBufferInt;
+ delete mCountingBuffer;
+}
+
+void convertIndices(GLenum type, const void *input, GLsizei count, void *output)
+{
+ if (type == GL_UNSIGNED_BYTE)
+ {
+ const GLubyte *in = static_cast<const GLubyte*>(input);
+ GLushort *out = static_cast<GLushort*>(output);
+
+ for (GLsizei i = 0; i < count; i++)
+ {
+ out[i] = in[i];
+ }
+ }
+ else if (type == GL_UNSIGNED_INT)
+ {
+ memcpy(output, input, count * sizeof(GLuint));
+ }
+ else if (type == GL_UNSIGNED_SHORT)
+ {
+ memcpy(output, input, count * sizeof(GLushort));
+ }
+ else UNREACHABLE();
+}
+
+template <class IndexType>
+void computeRange(const IndexType *indices, GLsizei count, GLuint *minIndex, GLuint *maxIndex)
+{
+ *minIndex = indices[0];
+ *maxIndex = indices[0];
+
+ for (GLsizei i = 0; i < count; i++)
+ {
+ if (*minIndex > indices[i]) *minIndex = indices[i];
+ if (*maxIndex < indices[i]) *maxIndex = indices[i];
+ }
+}
+
+void computeRange(GLenum type, const GLvoid *indices, GLsizei count, GLuint *minIndex, GLuint *maxIndex)
+{
+ if (type == GL_UNSIGNED_BYTE)
+ {
+ computeRange(static_cast<const GLubyte*>(indices), count, minIndex, maxIndex);
+ }
+ else if (type == GL_UNSIGNED_INT)
+ {
+ computeRange(static_cast<const GLuint*>(indices), count, minIndex, maxIndex);
+ }
+ else if (type == GL_UNSIGNED_SHORT)
+ {
+ computeRange(static_cast<const GLushort*>(indices), count, minIndex, maxIndex);
+ }
+ else UNREACHABLE();
+}
+
+GLenum IndexDataManager::prepareIndexData(GLenum type, GLsizei count, Buffer *buffer, const GLvoid *indices, TranslatedIndexData *translated, IDirect3DIndexBuffer9 **d3dIndexBuffer, unsigned int *serial)
+{
+ if (!mStreamingBufferShort)
+ {
+ return GL_OUT_OF_MEMORY;
+ }
+
+ D3DFORMAT format = (type == GL_UNSIGNED_INT) ? D3DFMT_INDEX32 : D3DFMT_INDEX16;
+ intptr_t offset = reinterpret_cast<intptr_t>(indices);
+ bool alignedOffset = false;
+
+ if (buffer != NULL)
+ {
+ switch (type)
+ {
+ case GL_UNSIGNED_BYTE: alignedOffset = (offset % sizeof(GLubyte) == 0); break;
+ case GL_UNSIGNED_SHORT: alignedOffset = (offset % sizeof(GLushort) == 0); break;
+ case GL_UNSIGNED_INT: alignedOffset = (offset % sizeof(GLuint) == 0); break;
+ default: UNREACHABLE(); alignedOffset = false;
+ }
+
+ if (typeSize(type) * count + offset > static_cast<std::size_t>(buffer->size()))
+ {
+ return GL_INVALID_OPERATION;
+ }
+
+ indices = static_cast<const GLubyte*>(buffer->data()) + offset;
+ }
+
+ StreamingIndexBuffer *streamingBuffer = (type == GL_UNSIGNED_INT) ? mStreamingBufferInt : mStreamingBufferShort;
+
+ StaticIndexBuffer *staticBuffer = buffer ? buffer->getStaticIndexBuffer() : NULL;
+ IndexBuffer *indexBuffer = streamingBuffer;
+ UINT streamOffset = 0;
+
+ if (staticBuffer && staticBuffer->lookupType(type) && alignedOffset)
+ {
+ indexBuffer = staticBuffer;
+ streamOffset = staticBuffer->lookupRange(offset, count, &translated->minIndex, &translated->maxIndex);
+
+ if (streamOffset == -1)
+ {
+ streamOffset = (offset / typeSize(type)) * indexSize(format);
+ computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex);
+ staticBuffer->addRange(offset, count, translated->minIndex, translated->maxIndex, streamOffset);
+ }
+ }
+ else
+ {
+ int convertCount = count;
+
+ if (staticBuffer)
+ {
+ if (staticBuffer->size() == 0 && alignedOffset)
+ {
+ indexBuffer = staticBuffer;
+ convertCount = buffer->size() / typeSize(type);
+ }
+ else
+ {
+ buffer->invalidateStaticData();
+ staticBuffer = NULL;
+ }
+ }
+
+ void *output = NULL;
+
+ if (indexBuffer)
+ {
+ indexBuffer->reserveSpace(convertCount * indexSize(format), type);
+ output = indexBuffer->map(indexSize(format) * convertCount, &streamOffset);
+ }
+
+ if (output == NULL)
+ {
+ ERR("Failed to map index buffer.");
+ return GL_OUT_OF_MEMORY;
+ }
+
+ convertIndices(type, staticBuffer ? buffer->data() : indices, convertCount, output);
+ indexBuffer->unmap();
+
+ computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex);
+
+ if (staticBuffer)
+ {
+ streamOffset = (offset / typeSize(type)) * indexSize(format);
+ staticBuffer->addRange(offset, count, translated->minIndex, translated->maxIndex, streamOffset);
+ }
+ }
+
+ *d3dIndexBuffer = indexBuffer->getBuffer();
+ *serial = indexBuffer->getSerial();
+ translated->startIndex = streamOffset / indexSize(format);
+
+ if (buffer)
+ {
+ buffer->promoteStaticUsage(count * typeSize(type));
+ }
+
+ return GL_NO_ERROR;
+}
+
+std::size_t IndexDataManager::indexSize(D3DFORMAT format) const
+{
+ return (format == D3DFMT_INDEX32) ? sizeof(unsigned int) : sizeof(unsigned short);
+}
+
+std::size_t IndexDataManager::typeSize(GLenum type) const
+{
+ switch (type)
+ {
+ case GL_UNSIGNED_INT: return sizeof(GLuint);
+ case GL_UNSIGNED_SHORT: return sizeof(GLushort);
+ case GL_UNSIGNED_BYTE: return sizeof(GLubyte);
+ default: UNREACHABLE(); return sizeof(GLushort);
+ }
+}
+
+StaticIndexBuffer *IndexDataManager::getCountingIndices(GLsizei count)
+{
+ if (count <= 65536) // 16-bit indices
+ {
+ const unsigned int spaceNeeded = count * sizeof(unsigned short);
+
+ if (!mCountingBuffer || mCountingBuffer->size() < spaceNeeded)
+ {
+ delete mCountingBuffer;
+ mCountingBuffer = new StaticIndexBuffer(mRenderer);
+ mCountingBuffer->reserveSpace(spaceNeeded, GL_UNSIGNED_SHORT);
+
+ UINT offset;
+ unsigned short *data = static_cast<unsigned short*>(mCountingBuffer->map(spaceNeeded, &offset));
+
+ if (data)
+ {
+ for(int i = 0; i < count; i++)
+ {
+ data[i] = i;
+ }
+
+ mCountingBuffer->unmap();
+ }
+ }
+ }
+ else if (mStreamingBufferInt) // 32-bit indices supported
+ {
+ const unsigned int spaceNeeded = count * sizeof(unsigned int);
+
+ if (!mCountingBuffer || mCountingBuffer->size() < spaceNeeded)
+ {
+ delete mCountingBuffer;
+ mCountingBuffer = new StaticIndexBuffer(mRenderer);
+ mCountingBuffer->reserveSpace(spaceNeeded, GL_UNSIGNED_INT);
+
+ UINT offset;
+ unsigned int *data = static_cast<unsigned int*>(mCountingBuffer->map(spaceNeeded, &offset));
+
+ if (data)
+ {
+ for(int i = 0; i < count; i++)
+ {
+ data[i] = i;
+ }
+
+ mCountingBuffer->unmap();
+ }
+ }
+ }
+ else return NULL;
+
+ return mCountingBuffer;
+}
+
+IndexBuffer::IndexBuffer(rx::Renderer9 *renderer, UINT size, D3DFORMAT format) : mRenderer(renderer), mBufferSize(size), mIndexBuffer(NULL)
+{
+ if (size > 0)
+ {
+ // D3D9_REPLACE
+ HRESULT result = mRenderer->createIndexBuffer(size, D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, format, &mIndexBuffer);
+ mSerial = issueSerial();
+
+ if (FAILED(result))
+ {
+ ERR("Out of memory allocating an index buffer of size %lu.", size);
+ }
+ }
+}
+
+IndexBuffer::~IndexBuffer()
+{
+ if (mIndexBuffer)
+ {
+ mIndexBuffer->Release();
+ }
+}
+
+IDirect3DIndexBuffer9 *IndexBuffer::getBuffer() const
+{
+ return mIndexBuffer;
+}
+
+unsigned int IndexBuffer::getSerial() const
+{
+ return mSerial;
+}
+
+unsigned int IndexBuffer::issueSerial()
+{
+ return mCurrentSerial++;
+}
+
+void IndexBuffer::unmap()
+{
+ if (mIndexBuffer)
+ {
+ mIndexBuffer->Unlock();
+ }
+}
+
+StreamingIndexBuffer::StreamingIndexBuffer(rx::Renderer9 *renderer, UINT initialSize, D3DFORMAT format) : IndexBuffer(renderer, initialSize, format)
+{
+ mWritePosition = 0;
+}
+
+StreamingIndexBuffer::~StreamingIndexBuffer()
+{
+}
+
+void *StreamingIndexBuffer::map(UINT requiredSpace, UINT *offset)
+{
+ void *mapPtr = NULL;
+
+ if (mIndexBuffer)
+ {
+ HRESULT result = mIndexBuffer->Lock(mWritePosition, requiredSpace, &mapPtr, D3DLOCK_NOOVERWRITE);
+
+ if (FAILED(result))
+ {
+ ERR(" Lock failed with error 0x%08x", result);
+ return NULL;
+ }
+
+ *offset = mWritePosition;
+ mWritePosition += requiredSpace;
+ }
+
+ return mapPtr;
+}
+
+void StreamingIndexBuffer::reserveSpace(UINT requiredSpace, GLenum type)
+{
+ if (requiredSpace > mBufferSize)
+ {
+ if (mIndexBuffer)
+ {
+ mIndexBuffer->Release();
+ mIndexBuffer = NULL;
+ }
+
+ mBufferSize = std::max(requiredSpace, 2 * mBufferSize);
+
+ // D3D9_REPLACE
+ HRESULT result = mRenderer->createIndexBuffer(mBufferSize, D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, type == GL_UNSIGNED_INT ? D3DFMT_INDEX32 : D3DFMT_INDEX16, &mIndexBuffer);
+ mSerial = issueSerial();
+
+ if (FAILED(result))
+ {
+ ERR("Out of memory allocating a vertex buffer of size %lu.", mBufferSize);
+ }
+
+ mWritePosition = 0;
+ }
+ else if (mWritePosition + requiredSpace > mBufferSize) // Recycle
+ {
+ void *dummy;
+ mIndexBuffer->Lock(0, 1, &dummy, D3DLOCK_DISCARD);
+ mIndexBuffer->Unlock();
+
+ mWritePosition = 0;
+ }
+}
+
+StaticIndexBuffer::StaticIndexBuffer(rx::Renderer9 *renderer) : IndexBuffer(renderer, 0, D3DFMT_UNKNOWN)
+{
+ mCacheType = GL_NONE;
+}
+
+StaticIndexBuffer::~StaticIndexBuffer()
+{
+}
+
+void *StaticIndexBuffer::map(UINT requiredSpace, UINT *offset)
+{
+ void *mapPtr = NULL;
+
+ if (mIndexBuffer)
+ {
+ HRESULT result = mIndexBuffer->Lock(0, requiredSpace, &mapPtr, 0);
+
+ if (FAILED(result))
+ {
+ ERR(" Lock failed with error 0x%08x", result);
+ return NULL;
+ }
+
+ *offset = 0;
+ }
+
+ return mapPtr;
+}
+
+void StaticIndexBuffer::reserveSpace(UINT requiredSpace, GLenum type)
+{
+ if (!mIndexBuffer && mBufferSize == 0)
+ {
+ // D3D9_REPLACE
+ HRESULT result = mRenderer->createIndexBuffer(requiredSpace, D3DUSAGE_WRITEONLY, type == GL_UNSIGNED_INT ? D3DFMT_INDEX32 : D3DFMT_INDEX16, &mIndexBuffer);
+ mSerial = issueSerial();
+
+ if (FAILED(result))
+ {
+ ERR("Out of memory allocating a vertex buffer of size %lu.", mBufferSize);
+ }
+
+ mBufferSize = requiredSpace;
+ mCacheType = type;
+ }
+ else if (mIndexBuffer && mBufferSize >= requiredSpace && mCacheType == type)
+ {
+ // Already allocated
+ }
+ else UNREACHABLE(); // Static index buffers can't be resized
+}
+
+bool StaticIndexBuffer::lookupType(GLenum type)
+{
+ return mCacheType == type;
+}
+
+UINT StaticIndexBuffer::lookupRange(intptr_t offset, GLsizei count, UINT *minIndex, UINT *maxIndex)
+{
+ IndexRange range = {offset, count};
+
+ std::map<IndexRange, IndexResult>::iterator res = mCache.find(range);
+
+ if (res == mCache.end())
+ {
+ return -1;
+ }
+
+ *minIndex = res->second.minIndex;
+ *maxIndex = res->second.maxIndex;
+ return res->second.streamOffset;
+}
+
+void StaticIndexBuffer::addRange(intptr_t offset, GLsizei count, UINT minIndex, UINT maxIndex, UINT streamOffset)
+{
+ IndexRange indexRange = {offset, count};
+ IndexResult indexResult = {minIndex, maxIndex, streamOffset};
+ mCache[indexRange] = indexResult;
+}
+
+}
diff --git a/src/libGLESv2/renderer/IndexDataManager.h b/src/libGLESv2/renderer/IndexDataManager.h
new file mode 100644
index 0000000..6e4a6e4
--- /dev/null
+++ b/src/libGLESv2/renderer/IndexDataManager.h
@@ -0,0 +1,146 @@
+//
+// Copyright (c) 2002-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.
+//
+
+// IndexDataManager.h: Defines the IndexDataManager, a class that
+// runs the Buffer translation process for index buffers.
+
+#ifndef LIBGLESV2_INDEXDATAMANAGER_H_
+#define LIBGLESV2_INDEXDATAMANAGER_H_
+
+#include <vector>
+#include <cstddef>
+
+#define GL_APICALL
+#include <GLES2/gl2.h>
+
+#include "libGLESv2/Context.h"
+
+namespace
+{
+ enum { INITIAL_INDEX_BUFFER_SIZE = 4096 * sizeof(GLuint) };
+}
+
+namespace gl
+{
+
+struct TranslatedIndexData
+{
+ UINT minIndex;
+ UINT maxIndex;
+ UINT startIndex;
+};
+
+class IndexBuffer
+{
+ public:
+ IndexBuffer(rx::Renderer9 *renderer, UINT size, D3DFORMAT format);
+ virtual ~IndexBuffer();
+
+ UINT size() const { return mBufferSize; }
+ virtual void *map(UINT requiredSpace, UINT *offset) = 0;
+ void unmap();
+ virtual void reserveSpace(UINT requiredSpace, GLenum type) = 0;
+
+ IDirect3DIndexBuffer9 *getBuffer() const;
+ unsigned int getSerial() const;
+
+ protected:
+ rx::Renderer9 *const mRenderer; // D3D9_REPLACE
+
+ IDirect3DIndexBuffer9 *mIndexBuffer;
+ UINT mBufferSize;
+
+ unsigned int mSerial;
+ static unsigned int issueSerial();
+ static unsigned int mCurrentSerial;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(IndexBuffer);
+};
+
+class StreamingIndexBuffer : public IndexBuffer
+{
+ public:
+ StreamingIndexBuffer(rx::Renderer9 *renderer, UINT initialSize, D3DFORMAT format);
+ ~StreamingIndexBuffer();
+
+ virtual void *map(UINT requiredSpace, UINT *offset);
+ virtual void reserveSpace(UINT requiredSpace, GLenum type);
+
+ private:
+ UINT mWritePosition;
+};
+
+class StaticIndexBuffer : public IndexBuffer
+{
+ public:
+ explicit StaticIndexBuffer(rx::Renderer9 *renderer);
+ ~StaticIndexBuffer();
+
+ virtual void *map(UINT requiredSpace, UINT *offset);
+ virtual void reserveSpace(UINT requiredSpace, GLenum type);
+
+ bool lookupType(GLenum type);
+ UINT lookupRange(intptr_t offset, GLsizei count, UINT *minIndex, UINT *maxIndex); // Returns the offset into the index buffer, or -1 if not found
+ void addRange(intptr_t offset, GLsizei count, UINT minIndex, UINT maxIndex, UINT streamOffset);
+
+ private:
+ GLenum mCacheType;
+
+ struct IndexRange
+ {
+ intptr_t offset;
+ GLsizei count;
+
+ bool operator<(const IndexRange& rhs) const
+ {
+ if (offset != rhs.offset)
+ {
+ return offset < rhs.offset;
+ }
+ if (count != rhs.count)
+ {
+ return count < rhs.count;
+ }
+ return false;
+ }
+ };
+
+ struct IndexResult
+ {
+ UINT minIndex;
+ UINT maxIndex;
+ UINT streamOffset;
+ };
+
+ std::map<IndexRange, IndexResult> mCache;
+};
+
+class IndexDataManager
+{
+ public:
+ IndexDataManager(rx::Renderer9 *renderer);
+ virtual ~IndexDataManager();
+
+ GLenum prepareIndexData(GLenum type, GLsizei count, Buffer *arrayElementBuffer, const GLvoid *indices, TranslatedIndexData *translated, IDirect3DIndexBuffer9 **indexBuffer, unsigned int *serial);
+ StaticIndexBuffer *getCountingIndices(GLsizei count);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(IndexDataManager);
+
+ std::size_t typeSize(GLenum type) const;
+ std::size_t indexSize(D3DFORMAT format) const;
+
+ rx::Renderer9 *const mRenderer; // D3D9_REPLACE
+
+ StreamingIndexBuffer *mStreamingBufferShort;
+ StreamingIndexBuffer *mStreamingBufferInt;
+ StaticIndexBuffer *mCountingBuffer;
+};
+
+}
+
+#endif // LIBGLESV2_INDEXDATAMANAGER_H_
diff --git a/src/libGLESv2/renderer/Renderer9.cpp b/src/libGLESv2/renderer/Renderer9.cpp
index 6e82f0f..41ab0ab 100644
--- a/src/libGLESv2/renderer/Renderer9.cpp
+++ b/src/libGLESv2/renderer/Renderer9.cpp
@@ -14,8 +14,8 @@
#include "libGLESv2/Framebuffer.h"
#include "libGLESv2/Program.h"
#include "libGLESv2/ProgramBinary.h"
-#include "libGLESv2/IndexDataManager.h"
-#include "libGLESv2/VertexDataManager.h"
+#include "libGLESv2/renderer/IndexDataManager.h"
+#include "libGLESv2/renderer/VertexDataManager.h"
#include "libGLESv2/renderer/Renderer9.h"
#include "libGLESv2/renderer/renderer9_utils.h"
#include "libGLESv2/renderer/ShaderExecutable9.h"
diff --git a/src/libGLESv2/renderer/Renderer9.h b/src/libGLESv2/renderer/Renderer9.h
index ce0eb02..15f3623 100644
--- a/src/libGLESv2/renderer/Renderer9.h
+++ b/src/libGLESv2/renderer/Renderer9.h
@@ -26,7 +26,7 @@
#include "libGLESv2/renderer/ShaderCache.h"
#include "libGLESv2/renderer/VertexDeclarationCache.h"
#include "libGLESv2/renderer/Renderer.h"
-#include "libGLESv2/IndexDataManager.h"
+#include "libGLESv2/renderer/IndexDataManager.h"
namespace gl
{
diff --git a/src/libGLESv2/renderer/ShaderExecutable.h b/src/libGLESv2/renderer/ShaderExecutable.h
index bce6708..cbb30ee 100644
--- a/src/libGLESv2/renderer/ShaderExecutable.h
+++ b/src/libGLESv2/renderer/ShaderExecutable.h
@@ -11,7 +11,7 @@
#define LIBGLESV2_RENDERER_SHADEREXECUTABLE_H_
#include "common/angleutils.h"
-#include "libGLESv2/D3DConstantTable.h"
+#include "libGLESv2/renderer/D3DConstantTable.h"
namespace rx
{
diff --git a/src/libGLESv2/renderer/ShaderExecutable9.h b/src/libGLESv2/renderer/ShaderExecutable9.h
index e3802d6..d5d3f93 100644
--- a/src/libGLESv2/renderer/ShaderExecutable9.h
+++ b/src/libGLESv2/renderer/ShaderExecutable9.h
@@ -13,7 +13,7 @@
#include <d3d9.h>
#include "libGLESv2/renderer/ShaderExecutable.h"
-#include "libGLESv2/D3DConstantTable.h"
+#include "libGLESv2/renderer/D3DConstantTable.h"
namespace rx
{
diff --git a/src/libGLESv2/renderer/VertexDataManager.cpp b/src/libGLESv2/renderer/VertexDataManager.cpp
new file mode 100644
index 0000000..da43a67
--- /dev/null
+++ b/src/libGLESv2/renderer/VertexDataManager.cpp
@@ -0,0 +1,792 @@
+//
+// Copyright (c) 2002-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.
+//
+
+// VertexDataManager.h: Defines the VertexDataManager, a class that
+// runs the Buffer translation process.
+
+#include "libGLESv2/renderer/VertexDataManager.h"
+
+#include "common/debug.h"
+
+#include "libGLESv2/renderer/Renderer9.h"
+#include "libGLESv2/Buffer.h"
+#include "libGLESv2/ProgramBinary.h"
+#include "libGLESv2/main.h"
+
+#include "libGLESv2/renderer/vertexconversion.h"
+#include "libGLESv2/renderer/IndexDataManager.h"
+
+#include <limits>
+
+namespace
+{
+ enum { INITIAL_STREAM_BUFFER_SIZE = 1024*1024 };
+ // This has to be at least 4k or else it fails on ATI cards.
+ enum { CONSTANT_VERTEX_BUFFER_SIZE = 4096 };
+}
+
+namespace gl
+{
+unsigned int VertexBuffer::mCurrentSerial = 1;
+
+int elementsInBuffer(const VertexAttribute &attribute, int size)
+{
+ int stride = attribute.stride();
+ return (size - attribute.mOffset % stride + (stride - attribute.typeSize())) / stride;
+}
+
+VertexDataManager::VertexDataManager(rx::Renderer9 *renderer) : mRenderer(renderer)
+{
+ for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
+ {
+ mCurrentValue[i][0] = std::numeric_limits<float>::quiet_NaN();
+ mCurrentValue[i][1] = std::numeric_limits<float>::quiet_NaN();
+ mCurrentValue[i][2] = std::numeric_limits<float>::quiet_NaN();
+ mCurrentValue[i][3] = std::numeric_limits<float>::quiet_NaN();
+ mCurrentValueBuffer[i] = NULL;
+ mCurrentValueOffsets[i] = 0;
+ }
+
+ // D3D9_REPLACE
+ checkVertexCaps(renderer->getCapsDeclTypes());
+
+ mStreamingBuffer = new StreamingVertexBuffer(renderer, INITIAL_STREAM_BUFFER_SIZE);
+
+ if (!mStreamingBuffer)
+ {
+ ERR("Failed to allocate the streaming vertex buffer.");
+ }
+}
+
+VertexDataManager::~VertexDataManager()
+{
+ delete mStreamingBuffer;
+
+ for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
+ {
+ delete mCurrentValueBuffer[i];
+ }
+}
+
+std::size_t VertexDataManager::writeAttributeData(ArrayVertexBuffer *vertexBuffer, GLint start, GLsizei count, const VertexAttribute &attribute, GLsizei instances)
+{
+ Buffer *buffer = attribute.mBoundBuffer.get();
+
+ int inputStride = attribute.stride();
+ int elementSize = attribute.typeSize();
+ const FormatConverter &converter = formatConverter(attribute);
+ std::size_t streamOffset = 0;
+
+ void *output = NULL;
+
+ if (vertexBuffer)
+ {
+ output = vertexBuffer->map(attribute, spaceRequired(attribute, count, instances), &streamOffset);
+ }
+
+ if (output == NULL)
+ {
+ ERR("Failed to map vertex buffer.");
+ return -1;
+ }
+
+ const char *input = NULL;
+
+ if (buffer)
+ {
+ int offset = attribute.mOffset;
+
+ input = static_cast<const char*>(buffer->data()) + offset;
+ }
+ else
+ {
+ input = static_cast<const char*>(attribute.mPointer);
+ }
+
+ if (instances == 0 || attribute.mDivisor == 0)
+ {
+ input += inputStride * start;
+ }
+
+ if (converter.identity && inputStride == elementSize)
+ {
+ memcpy(output, input, count * inputStride);
+ }
+ else
+ {
+ converter.convertArray(input, inputStride, count, output);
+ }
+
+ vertexBuffer->unmap();
+
+ return streamOffset;
+}
+
+GLenum VertexDataManager::prepareVertexData(const VertexAttribute attribs[], ProgramBinary *programBinary, GLint start, GLsizei count, TranslatedAttribute *translated, GLsizei instances)
+{
+ if (!mStreamingBuffer)
+ {
+ return GL_OUT_OF_MEMORY;
+ }
+
+ for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
+ {
+ translated[attributeIndex].active = (programBinary->getSemanticIndex(attributeIndex) != -1);
+ }
+
+ // Determine the required storage size per used buffer, and invalidate static buffers that don't contain matching attributes
+ for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
+ {
+ if (translated[i].active && attribs[i].mArrayEnabled)
+ {
+ Buffer *buffer = attribs[i].mBoundBuffer.get();
+ StaticVertexBuffer *staticBuffer = buffer ? buffer->getStaticVertexBuffer() : NULL;
+
+ if (staticBuffer)
+ {
+ if (staticBuffer->size() == 0)
+ {
+ int totalCount = elementsInBuffer(attribs[i], buffer->size());
+ staticBuffer->addRequiredSpace(spaceRequired(attribs[i], totalCount, 0));
+ }
+ else if (staticBuffer->lookupAttribute(attribs[i]) == -1)
+ {
+ // This static buffer doesn't have matching attributes, so fall back to using the streaming buffer
+ // Add the space of all previous attributes belonging to the invalidated static buffer to the streaming buffer
+ for (int previous = 0; previous < i; previous++)
+ {
+ if (translated[previous].active && attribs[previous].mArrayEnabled)
+ {
+ Buffer *previousBuffer = attribs[previous].mBoundBuffer.get();
+ StaticVertexBuffer *previousStaticBuffer = previousBuffer ? previousBuffer->getStaticVertexBuffer() : NULL;
+
+ if (staticBuffer == previousStaticBuffer)
+ {
+ mStreamingBuffer->addRequiredSpace(spaceRequired(attribs[previous], count, instances));
+ }
+ }
+ }
+
+ mStreamingBuffer->addRequiredSpace(spaceRequired(attribs[i], count, instances));
+
+ buffer->invalidateStaticData();
+ }
+ }
+ else
+ {
+ mStreamingBuffer->addRequiredSpace(spaceRequired(attribs[i], count, instances));
+ }
+ }
+ }
+
+ // Reserve the required space per used buffer
+ for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
+ {
+ if (translated[i].active && attribs[i].mArrayEnabled)
+ {
+ Buffer *buffer = attribs[i].mBoundBuffer.get();
+ ArrayVertexBuffer *staticBuffer = buffer ? buffer->getStaticVertexBuffer() : NULL;
+ ArrayVertexBuffer *vertexBuffer = staticBuffer ? staticBuffer : mStreamingBuffer;
+
+ if (vertexBuffer)
+ {
+ vertexBuffer->reserveRequiredSpace();
+ }
+ }
+ }
+
+ // Perform the vertex data translations
+ for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
+ {
+ if (translated[i].active)
+ {
+ if (attribs[i].mArrayEnabled)
+ {
+ Buffer *buffer = attribs[i].mBoundBuffer.get();
+
+ if (!buffer && attribs[i].mPointer == NULL)
+ {
+ // This is an application error that would normally result in a crash, but we catch it and return an error
+ ERR("An enabled vertex array has no buffer and no pointer.");
+ return GL_INVALID_OPERATION;
+ }
+
+ const FormatConverter &converter = formatConverter(attribs[i]);
+
+ StaticVertexBuffer *staticBuffer = buffer ? buffer->getStaticVertexBuffer() : NULL;
+ ArrayVertexBuffer *vertexBuffer = staticBuffer ? staticBuffer : static_cast<ArrayVertexBuffer*>(mStreamingBuffer);
+
+ std::size_t streamOffset = -1;
+
+ if (staticBuffer)
+ {
+ streamOffset = staticBuffer->lookupAttribute(attribs[i]);
+
+ if (streamOffset == -1)
+ {
+ // Convert the entire buffer
+ int totalCount = elementsInBuffer(attribs[i], buffer->size());
+ int startIndex = attribs[i].mOffset / attribs[i].stride();
+
+ streamOffset = writeAttributeData(staticBuffer, -startIndex, totalCount, attribs[i], 0);
+ }
+
+ if (streamOffset != -1)
+ {
+ streamOffset += (attribs[i].mOffset / attribs[i].stride()) * converter.outputElementSize;
+
+ if (instances == 0 || attribs[i].mDivisor == 0)
+ {
+ streamOffset += start * converter.outputElementSize;
+ }
+ }
+ }
+ else
+ {
+ streamOffset = writeAttributeData(mStreamingBuffer, start, count, attribs[i], instances);
+ }
+
+ if (streamOffset == -1)
+ {
+ return GL_OUT_OF_MEMORY;
+ }
+
+ translated[i].vertexBuffer = vertexBuffer->getBuffer();
+ translated[i].serial = vertexBuffer->getSerial();
+ translated[i].divisor = attribs[i].mDivisor;
+
+ translated[i].type = converter.d3dDeclType;
+ translated[i].stride = converter.outputElementSize;
+ translated[i].offset = streamOffset;
+ }
+ else
+ {
+ if (!mCurrentValueBuffer[i])
+ {
+ mCurrentValueBuffer[i] = new StreamingVertexBuffer(mRenderer, CONSTANT_VERTEX_BUFFER_SIZE);
+ }
+
+ StreamingVertexBuffer *buffer = mCurrentValueBuffer[i];
+
+ if (mCurrentValue[i][0] != attribs[i].mCurrentValue[0] ||
+ mCurrentValue[i][1] != attribs[i].mCurrentValue[1] ||
+ mCurrentValue[i][2] != attribs[i].mCurrentValue[2] ||
+ mCurrentValue[i][3] != attribs[i].mCurrentValue[3])
+ {
+ const int requiredSpace = 4 * sizeof(float);
+ buffer->addRequiredSpace(requiredSpace);
+ buffer->reserveRequiredSpace();
+ float *data = static_cast<float*>(buffer->map(VertexAttribute(), requiredSpace, &mCurrentValueOffsets[i]));
+ if (data)
+ {
+ data[0] = attribs[i].mCurrentValue[0];
+ data[1] = attribs[i].mCurrentValue[1];
+ data[2] = attribs[i].mCurrentValue[2];
+ data[3] = attribs[i].mCurrentValue[3];
+ buffer->unmap();
+
+ mCurrentValue[i][0] = attribs[i].mCurrentValue[0];
+ mCurrentValue[i][1] = attribs[i].mCurrentValue[1];
+ mCurrentValue[i][2] = attribs[i].mCurrentValue[2];
+ mCurrentValue[i][3] = attribs[i].mCurrentValue[3];
+ }
+ }
+
+ translated[i].vertexBuffer = mCurrentValueBuffer[i]->getBuffer();
+ translated[i].serial = mCurrentValueBuffer[i]->getSerial();
+ translated[i].divisor = 0;
+
+ translated[i].type = D3DDECLTYPE_FLOAT4;
+ translated[i].stride = 0;
+ translated[i].offset = mCurrentValueOffsets[i];
+ }
+ }
+ }
+
+ for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
+ {
+ if (translated[i].active && attribs[i].mArrayEnabled)
+ {
+ Buffer *buffer = attribs[i].mBoundBuffer.get();
+
+ if (buffer)
+ {
+ buffer->promoteStaticUsage(count * attribs[i].typeSize());
+ }
+ }
+ }
+
+ return GL_NO_ERROR;
+}
+
+std::size_t VertexDataManager::spaceRequired(const VertexAttribute &attrib, std::size_t count, GLsizei instances) const
+{
+ size_t elementSize = formatConverter(attrib).outputElementSize;
+
+ if (instances == 0 || attrib.mDivisor == 0)
+ {
+ return elementSize * count;
+ }
+ else
+ {
+ return elementSize * ((instances + attrib.mDivisor - 1) / attrib.mDivisor);
+ }
+}
+
+// Mapping from OpenGL-ES vertex attrib type to D3D decl type:
+//
+// BYTE SHORT (Cast)
+// BYTE-norm FLOAT (Normalize) (can't be exactly represented as SHORT-norm)
+// UNSIGNED_BYTE UBYTE4 (Identity) or SHORT (Cast)
+// UNSIGNED_BYTE-norm UBYTE4N (Identity) or FLOAT (Normalize)
+// SHORT SHORT (Identity)
+// SHORT-norm SHORT-norm (Identity) or FLOAT (Normalize)
+// UNSIGNED_SHORT FLOAT (Cast)
+// UNSIGNED_SHORT-norm USHORT-norm (Identity) or FLOAT (Normalize)
+// FIXED (not in WebGL) FLOAT (FixedToFloat)
+// FLOAT FLOAT (Identity)
+
+// GLToCType maps from GL type (as GLenum) to the C typedef.
+template <GLenum GLType> struct GLToCType { };
+
+template <> struct GLToCType<GL_BYTE> { typedef GLbyte type; };
+template <> struct GLToCType<GL_UNSIGNED_BYTE> { typedef GLubyte type; };
+template <> struct GLToCType<GL_SHORT> { typedef GLshort type; };
+template <> struct GLToCType<GL_UNSIGNED_SHORT> { typedef GLushort type; };
+template <> struct GLToCType<GL_FIXED> { typedef GLuint type; };
+template <> struct GLToCType<GL_FLOAT> { typedef GLfloat type; };
+
+// This differs from D3DDECLTYPE in that it is unsized. (Size expansion is applied last.)
+enum D3DVertexType
+{
+ D3DVT_FLOAT,
+ D3DVT_SHORT,
+ D3DVT_SHORT_NORM,
+ D3DVT_UBYTE,
+ D3DVT_UBYTE_NORM,
+ D3DVT_USHORT_NORM
+};
+
+// D3DToCType maps from D3D vertex type (as enum D3DVertexType) to the corresponding C type.
+template <unsigned int D3DType> struct D3DToCType { };
+
+template <> struct D3DToCType<D3DVT_FLOAT> { typedef float type; };
+template <> struct D3DToCType<D3DVT_SHORT> { typedef short type; };
+template <> struct D3DToCType<D3DVT_SHORT_NORM> { typedef short type; };
+template <> struct D3DToCType<D3DVT_UBYTE> { typedef unsigned char type; };
+template <> struct D3DToCType<D3DVT_UBYTE_NORM> { typedef unsigned char type; };
+template <> struct D3DToCType<D3DVT_USHORT_NORM> { typedef unsigned short type; };
+
+// Encode the type/size combinations that D3D permits. For each type/size it expands to a widener that will provide the appropriate final size.
+template <unsigned int type, int size>
+struct WidenRule
+{
+};
+
+template <int size> struct WidenRule<D3DVT_FLOAT, size> : gl::NoWiden<size> { };
+template <int size> struct WidenRule<D3DVT_SHORT, size> : gl::WidenToEven<size> { };
+template <int size> struct WidenRule<D3DVT_SHORT_NORM, size> : gl::WidenToEven<size> { };
+template <int size> struct WidenRule<D3DVT_UBYTE, size> : gl::WidenToFour<size> { };
+template <int size> struct WidenRule<D3DVT_UBYTE_NORM, size> : gl::WidenToFour<size> { };
+template <int size> struct WidenRule<D3DVT_USHORT_NORM, size> : gl::WidenToEven<size> { };
+
+// VertexTypeFlags encodes the D3DCAPS9::DeclType flag and vertex declaration flag for each D3D vertex type & size combination.
+template <unsigned int d3dtype, int size>
+struct VertexTypeFlags
+{
+};
+
+template <unsigned int _capflag, unsigned int _declflag>
+struct VertexTypeFlagsHelper
+{
+ enum { capflag = _capflag };
+ enum { declflag = _declflag };
+};
+
+template <> struct VertexTypeFlags<D3DVT_FLOAT, 1> : VertexTypeFlagsHelper<0, D3DDECLTYPE_FLOAT1> { };
+template <> struct VertexTypeFlags<D3DVT_FLOAT, 2> : VertexTypeFlagsHelper<0, D3DDECLTYPE_FLOAT2> { };
+template <> struct VertexTypeFlags<D3DVT_FLOAT, 3> : VertexTypeFlagsHelper<0, D3DDECLTYPE_FLOAT3> { };
+template <> struct VertexTypeFlags<D3DVT_FLOAT, 4> : VertexTypeFlagsHelper<0, D3DDECLTYPE_FLOAT4> { };
+template <> struct VertexTypeFlags<D3DVT_SHORT, 2> : VertexTypeFlagsHelper<0, D3DDECLTYPE_SHORT2> { };
+template <> struct VertexTypeFlags<D3DVT_SHORT, 4> : VertexTypeFlagsHelper<0, D3DDECLTYPE_SHORT4> { };
+template <> struct VertexTypeFlags<D3DVT_SHORT_NORM, 2> : VertexTypeFlagsHelper<D3DDTCAPS_SHORT2N, D3DDECLTYPE_SHORT2N> { };
+template <> struct VertexTypeFlags<D3DVT_SHORT_NORM, 4> : VertexTypeFlagsHelper<D3DDTCAPS_SHORT4N, D3DDECLTYPE_SHORT4N> { };
+template <> struct VertexTypeFlags<D3DVT_UBYTE, 4> : VertexTypeFlagsHelper<D3DDTCAPS_UBYTE4, D3DDECLTYPE_UBYTE4> { };
+template <> struct VertexTypeFlags<D3DVT_UBYTE_NORM, 4> : VertexTypeFlagsHelper<D3DDTCAPS_UBYTE4N, D3DDECLTYPE_UBYTE4N> { };
+template <> struct VertexTypeFlags<D3DVT_USHORT_NORM, 2> : VertexTypeFlagsHelper<D3DDTCAPS_USHORT2N, D3DDECLTYPE_USHORT2N> { };
+template <> struct VertexTypeFlags<D3DVT_USHORT_NORM, 4> : VertexTypeFlagsHelper<D3DDTCAPS_USHORT4N, D3DDECLTYPE_USHORT4N> { };
+
+
+// VertexTypeMapping maps GL type & normalized flag to preferred and fallback D3D vertex types (as D3DVertexType enums).
+template <GLenum GLtype, bool normalized>
+struct VertexTypeMapping
+{
+};
+
+template <D3DVertexType Preferred, D3DVertexType Fallback = Preferred>
+struct VertexTypeMappingBase
+{
+ enum { preferred = Preferred };
+ enum { fallback = Fallback };
+};
+
+template <> struct VertexTypeMapping<GL_BYTE, false> : VertexTypeMappingBase<D3DVT_SHORT> { }; // Cast
+template <> struct VertexTypeMapping<GL_BYTE, true> : VertexTypeMappingBase<D3DVT_FLOAT> { }; // Normalize
+template <> struct VertexTypeMapping<GL_UNSIGNED_BYTE, false> : VertexTypeMappingBase<D3DVT_UBYTE, D3DVT_FLOAT> { }; // Identity, Cast
+template <> struct VertexTypeMapping<GL_UNSIGNED_BYTE, true> : VertexTypeMappingBase<D3DVT_UBYTE_NORM, D3DVT_FLOAT> { }; // Identity, Normalize
+template <> struct VertexTypeMapping<GL_SHORT, false> : VertexTypeMappingBase<D3DVT_SHORT> { }; // Identity
+template <> struct VertexTypeMapping<GL_SHORT, true> : VertexTypeMappingBase<D3DVT_SHORT_NORM, D3DVT_FLOAT> { }; // Cast, Normalize
+template <> struct VertexTypeMapping<GL_UNSIGNED_SHORT, false> : VertexTypeMappingBase<D3DVT_FLOAT> { }; // Cast
+template <> struct VertexTypeMapping<GL_UNSIGNED_SHORT, true> : VertexTypeMappingBase<D3DVT_USHORT_NORM, D3DVT_FLOAT> { }; // Cast, Normalize
+template <bool normalized> struct VertexTypeMapping<GL_FIXED, normalized> : VertexTypeMappingBase<D3DVT_FLOAT> { }; // FixedToFloat
+template <bool normalized> struct VertexTypeMapping<GL_FLOAT, normalized> : VertexTypeMappingBase<D3DVT_FLOAT> { }; // Identity
+
+
+// Given a GL type & norm flag and a D3D type, ConversionRule provides the type conversion rule (Cast, Normalize, Identity, FixedToFloat).
+// The conversion rules themselves are defined in vertexconversion.h.
+
+// Almost all cases are covered by Cast (including those that are actually Identity since Cast<T,T> knows it's an identity mapping).
+template <GLenum fromType, bool normalized, unsigned int toType>
+struct ConversionRule : gl::Cast<typename GLToCType<fromType>::type, typename D3DToCType<toType>::type>
+{
+};
+
+// All conversions from normalized types to float use the Normalize operator.
+template <GLenum fromType> struct ConversionRule<fromType, true, D3DVT_FLOAT> : gl::Normalize<typename GLToCType<fromType>::type> { };
+
+// Use a full specialisation for this so that it preferentially matches ahead of the generic normalize-to-float rules.
+template <> struct ConversionRule<GL_FIXED, true, D3DVT_FLOAT> : gl::FixedToFloat<GLint, 16> { };
+template <> struct ConversionRule<GL_FIXED, false, D3DVT_FLOAT> : gl::FixedToFloat<GLint, 16> { };
+
+// A 2-stage construction is used for DefaultVertexValues because float must use SimpleDefaultValues (i.e. 0/1)
+// whether it is normalized or not.
+template <class T, bool normalized>
+struct DefaultVertexValuesStage2
+{
+};
+
+template <class T> struct DefaultVertexValuesStage2<T, true> : gl::NormalizedDefaultValues<T> { };
+template <class T> struct DefaultVertexValuesStage2<T, false> : gl::SimpleDefaultValues<T> { };
+
+// Work out the default value rule for a D3D type (expressed as the C type) and
+template <class T, bool normalized>
+struct DefaultVertexValues : DefaultVertexValuesStage2<T, normalized>
+{
+};
+
+template <bool normalized> struct DefaultVertexValues<float, normalized> : gl::SimpleDefaultValues<float> { };
+
+// Policy rules for use with Converter, to choose whether to use the preferred or fallback conversion.
+// The fallback conversion produces an output that all D3D9 devices must support.
+template <class T> struct UsePreferred { enum { type = T::preferred }; };
+template <class T> struct UseFallback { enum { type = T::fallback }; };
+
+// Converter ties it all together. Given an OpenGL type/norm/size and choice of preferred/fallback conversion,
+// it provides all the members of the appropriate VertexDataConverter, the D3DCAPS9::DeclTypes flag in cap flag
+// and the D3DDECLTYPE member needed for the vertex declaration in declflag.
+template <GLenum fromType, bool normalized, int size, template <class T> class PreferenceRule>
+struct Converter
+ : gl::VertexDataConverter<typename GLToCType<fromType>::type,
+ WidenRule<PreferenceRule< VertexTypeMapping<fromType, normalized> >::type, size>,
+ ConversionRule<fromType,
+ normalized,
+ PreferenceRule< VertexTypeMapping<fromType, normalized> >::type>,
+ DefaultVertexValues<typename D3DToCType<PreferenceRule< VertexTypeMapping<fromType, normalized> >::type>::type, normalized > >
+{
+private:
+ enum { d3dtype = PreferenceRule< VertexTypeMapping<fromType, normalized> >::type };
+ enum { d3dsize = WidenRule<d3dtype, size>::finalWidth };
+
+public:
+ enum { capflag = VertexTypeFlags<d3dtype, d3dsize>::capflag };
+ enum { declflag = VertexTypeFlags<d3dtype, d3dsize>::declflag };
+};
+
+// Initialise a TranslationInfo
+#define TRANSLATION(type, norm, size, preferred) \
+ { \
+ Converter<type, norm, size, preferred>::identity, \
+ Converter<type, norm, size, preferred>::finalSize, \
+ Converter<type, norm, size, preferred>::convertArray, \
+ static_cast<D3DDECLTYPE>(Converter<type, norm, size, preferred>::declflag) \
+ }
+
+#define TRANSLATION_FOR_TYPE_NORM_SIZE(type, norm, size) \
+ { \
+ Converter<type, norm, size, UsePreferred>::capflag, \
+ TRANSLATION(type, norm, size, UsePreferred), \
+ TRANSLATION(type, norm, size, UseFallback) \
+ }
+
+#define TRANSLATIONS_FOR_TYPE(type) \
+ { \
+ { TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 1), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 2), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 3), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 4) }, \
+ { TRANSLATION_FOR_TYPE_NORM_SIZE(type, true, 1), TRANSLATION_FOR_TYPE_NORM_SIZE(type, true, 2), TRANSLATION_FOR_TYPE_NORM_SIZE(type, true, 3), TRANSLATION_FOR_TYPE_NORM_SIZE(type, true, 4) }, \
+ }
+
+#define TRANSLATIONS_FOR_TYPE_NO_NORM(type) \
+ { \
+ { TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 1), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 2), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 3), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 4) }, \
+ { TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 1), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 2), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 3), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 4) }, \
+ }
+
+const VertexDataManager::TranslationDescription VertexDataManager::mPossibleTranslations[NUM_GL_VERTEX_ATTRIB_TYPES][2][4] = // [GL types as enumerated by typeIndex()][normalized][size-1]
+{
+ TRANSLATIONS_FOR_TYPE(GL_BYTE),
+ TRANSLATIONS_FOR_TYPE(GL_UNSIGNED_BYTE),
+ TRANSLATIONS_FOR_TYPE(GL_SHORT),
+ TRANSLATIONS_FOR_TYPE(GL_UNSIGNED_SHORT),
+ TRANSLATIONS_FOR_TYPE_NO_NORM(GL_FIXED),
+ TRANSLATIONS_FOR_TYPE_NO_NORM(GL_FLOAT)
+};
+
+void VertexDataManager::checkVertexCaps(DWORD declTypes)
+{
+ for (unsigned int i = 0; i < NUM_GL_VERTEX_ATTRIB_TYPES; i++)
+ {
+ for (unsigned int j = 0; j < 2; j++)
+ {
+ for (unsigned int k = 0; k < 4; k++)
+ {
+ if (mPossibleTranslations[i][j][k].capsFlag == 0 || (declTypes & mPossibleTranslations[i][j][k].capsFlag) != 0)
+ {
+ mAttributeTypes[i][j][k] = mPossibleTranslations[i][j][k].preferredConversion;
+ }
+ else
+ {
+ mAttributeTypes[i][j][k] = mPossibleTranslations[i][j][k].fallbackConversion;
+ }
+ }
+ }
+ }
+}
+
+// This is used to index mAttributeTypes and mPossibleTranslations.
+unsigned int VertexDataManager::typeIndex(GLenum type) const
+{
+ switch (type)
+ {
+ case GL_BYTE: return 0;
+ case GL_UNSIGNED_BYTE: return 1;
+ case GL_SHORT: return 2;
+ case GL_UNSIGNED_SHORT: return 3;
+ case GL_FIXED: return 4;
+ case GL_FLOAT: return 5;
+
+ default: UNREACHABLE(); return 5;
+ }
+}
+
+VertexBuffer::VertexBuffer(rx::Renderer9 *renderer, std::size_t size, DWORD usageFlags) : mRenderer(renderer), mVertexBuffer(NULL)
+{
+ if (size > 0)
+ {
+ // D3D9_REPLACE
+ HRESULT result = mRenderer->createVertexBuffer(size, usageFlags,&mVertexBuffer);
+ mSerial = issueSerial();
+
+ if (FAILED(result))
+ {
+ ERR("Out of memory allocating a vertex buffer of size %lu.", size);
+ }
+ }
+}
+
+VertexBuffer::~VertexBuffer()
+{
+ if (mVertexBuffer)
+ {
+ mVertexBuffer->Release();
+ }
+}
+
+void VertexBuffer::unmap()
+{
+ if (mVertexBuffer)
+ {
+ mVertexBuffer->Unlock();
+ }
+}
+
+IDirect3DVertexBuffer9 *VertexBuffer::getBuffer() const
+{
+ return mVertexBuffer;
+}
+
+unsigned int VertexBuffer::getSerial() const
+{
+ return mSerial;
+}
+
+unsigned int VertexBuffer::issueSerial()
+{
+ return mCurrentSerial++;
+}
+
+ArrayVertexBuffer::ArrayVertexBuffer(rx::Renderer9 *renderer, std::size_t size, DWORD usageFlags) : VertexBuffer(renderer, size, usageFlags)
+{
+ mBufferSize = size;
+ mWritePosition = 0;
+ mRequiredSpace = 0;
+}
+
+ArrayVertexBuffer::~ArrayVertexBuffer()
+{
+}
+
+void ArrayVertexBuffer::addRequiredSpace(UINT requiredSpace)
+{
+ mRequiredSpace += requiredSpace;
+}
+
+StreamingVertexBuffer::StreamingVertexBuffer(rx::Renderer9 *renderer, std::size_t initialSize) : ArrayVertexBuffer(renderer, initialSize, D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY)
+{
+}
+
+StreamingVertexBuffer::~StreamingVertexBuffer()
+{
+}
+
+void *StreamingVertexBuffer::map(const VertexAttribute &attribute, std::size_t requiredSpace, std::size_t *offset)
+{
+ void *mapPtr = NULL;
+
+ if (mVertexBuffer)
+ {
+ HRESULT result = mVertexBuffer->Lock(mWritePosition, requiredSpace, &mapPtr, D3DLOCK_NOOVERWRITE);
+
+ if (FAILED(result))
+ {
+ ERR("Lock failed with error 0x%08x", result);
+ return NULL;
+ }
+
+ *offset = mWritePosition;
+ mWritePosition += requiredSpace;
+ }
+
+ return mapPtr;
+}
+
+void StreamingVertexBuffer::reserveRequiredSpace()
+{
+ if (mRequiredSpace > mBufferSize)
+ {
+ if (mVertexBuffer)
+ {
+ mVertexBuffer->Release();
+ mVertexBuffer = NULL;
+ }
+
+ mBufferSize = std::max(mRequiredSpace, 3 * mBufferSize / 2); // 1.5 x mBufferSize is arbitrary and should be checked to see we don't have too many reallocations.
+
+ // D3D9_REPLACE
+ HRESULT result = mRenderer->createVertexBuffer(mBufferSize, D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, &mVertexBuffer);
+ mSerial = issueSerial();
+
+ if (FAILED(result))
+ {
+ ERR("Out of memory allocating a vertex buffer of size %lu.", mBufferSize);
+ }
+
+ mWritePosition = 0;
+ }
+ else if (mWritePosition + mRequiredSpace > mBufferSize) // Recycle
+ {
+ if (mVertexBuffer)
+ {
+ void *dummy;
+ mVertexBuffer->Lock(0, 1, &dummy, D3DLOCK_DISCARD);
+ mVertexBuffer->Unlock();
+ }
+
+ mWritePosition = 0;
+ }
+
+ mRequiredSpace = 0;
+}
+
+StaticVertexBuffer::StaticVertexBuffer(rx::Renderer9 *renderer) : ArrayVertexBuffer(renderer, 0, D3DUSAGE_WRITEONLY)
+{
+}
+
+StaticVertexBuffer::~StaticVertexBuffer()
+{
+}
+
+void *StaticVertexBuffer::map(const VertexAttribute &attribute, std::size_t requiredSpace, std::size_t *streamOffset)
+{
+ void *mapPtr = NULL;
+
+ if (mVertexBuffer)
+ {
+ HRESULT result = mVertexBuffer->Lock(mWritePosition, requiredSpace, &mapPtr, 0);
+
+ if (FAILED(result))
+ {
+ ERR("Lock failed with error 0x%08x", result);
+ return NULL;
+ }
+
+ int attributeOffset = attribute.mOffset % attribute.stride();
+ VertexElement element = {attribute.mType, attribute.mSize, attribute.stride(), attribute.mNormalized, attributeOffset, mWritePosition};
+ mCache.push_back(element);
+
+ *streamOffset = mWritePosition;
+ mWritePosition += requiredSpace;
+ }
+
+ return mapPtr;
+}
+
+void StaticVertexBuffer::reserveRequiredSpace()
+{
+ if (!mVertexBuffer && mBufferSize == 0)
+ {
+ // D3D9_REPLACE
+ HRESULT result = mRenderer->createVertexBuffer(mRequiredSpace, D3DUSAGE_WRITEONLY, &mVertexBuffer);
+ mSerial = issueSerial();
+
+ if (FAILED(result))
+ {
+ ERR("Out of memory allocating a vertex buffer of size %lu.", mRequiredSpace);
+ }
+
+ mBufferSize = mRequiredSpace;
+ }
+ else if (mVertexBuffer && mBufferSize >= mRequiredSpace)
+ {
+ // Already allocated
+ }
+ else UNREACHABLE(); // Static vertex buffers can't be resized
+
+ mRequiredSpace = 0;
+}
+
+std::size_t StaticVertexBuffer::lookupAttribute(const VertexAttribute &attribute)
+{
+ for (unsigned int element = 0; element < mCache.size(); element++)
+ {
+ if (mCache[element].type == attribute.mType &&
+ mCache[element].size == attribute.mSize &&
+ mCache[element].stride == attribute.stride() &&
+ mCache[element].normalized == attribute.mNormalized)
+ {
+ if (mCache[element].attributeOffset == attribute.mOffset % attribute.stride())
+ {
+ return mCache[element].streamOffset;
+ }
+ }
+ }
+
+ return -1;
+}
+
+const VertexDataManager::FormatConverter &VertexDataManager::formatConverter(const VertexAttribute &attribute) const
+{
+ return mAttributeTypes[typeIndex(attribute.mType)][attribute.mNormalized][attribute.mSize - 1];
+}
+}
diff --git a/src/libGLESv2/renderer/VertexDataManager.h b/src/libGLESv2/renderer/VertexDataManager.h
new file mode 100644
index 0000000..971aeca
--- /dev/null
+++ b/src/libGLESv2/renderer/VertexDataManager.h
@@ -0,0 +1,166 @@
+//
+// Copyright (c) 2002-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.
+//
+
+// VertexDataManager.h: Defines the VertexDataManager, a class that
+// runs the Buffer translation process.
+
+#ifndef LIBGLESV2_VERTEXDATAMANAGER_H_
+#define LIBGLESV2_VERTEXDATAMANAGER_H_
+
+#include <vector>
+#include <cstddef>
+
+#define GL_APICALL
+#include <GLES2/gl2.h>
+
+#include "libGLESv2/Context.h"
+
+namespace gl
+{
+
+struct TranslatedAttribute
+{
+ bool active;
+
+ D3DDECLTYPE type;
+ UINT offset;
+ UINT stride; // 0 means not to advance the read pointer at all
+
+ IDirect3DVertexBuffer9 *vertexBuffer;
+ unsigned int serial;
+ unsigned int divisor;
+};
+
+class VertexBuffer
+{
+ public:
+ VertexBuffer(rx::Renderer9 *renderer, std::size_t size, DWORD usageFlags);
+ virtual ~VertexBuffer();
+
+ void unmap();
+
+ IDirect3DVertexBuffer9 *getBuffer() const;
+ unsigned int getSerial() const;
+
+ protected:
+ rx::Renderer9 *const mRenderer; // D3D9_REPLACE
+ IDirect3DVertexBuffer9 *mVertexBuffer;
+
+ unsigned int mSerial;
+ static unsigned int issueSerial();
+ static unsigned int mCurrentSerial;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(VertexBuffer);
+};
+
+class ArrayVertexBuffer : public VertexBuffer
+{
+ public:
+ ArrayVertexBuffer(rx::Renderer9 *renderer, std::size_t size, DWORD usageFlags);
+ ~ArrayVertexBuffer();
+
+ std::size_t size() const { return mBufferSize; }
+ virtual void *map(const VertexAttribute &attribute, std::size_t requiredSpace, std::size_t *streamOffset) = 0;
+ virtual void reserveRequiredSpace() = 0;
+ void addRequiredSpace(UINT requiredSpace);
+
+ protected:
+ std::size_t mBufferSize;
+ std::size_t mWritePosition;
+ std::size_t mRequiredSpace;
+};
+
+class StreamingVertexBuffer : public ArrayVertexBuffer
+{
+ public:
+ StreamingVertexBuffer(rx::Renderer9 *renderer, std::size_t initialSize);
+ ~StreamingVertexBuffer();
+
+ void *map(const VertexAttribute &attribute, std::size_t requiredSpace, std::size_t *streamOffset);
+ void reserveRequiredSpace();
+};
+
+class StaticVertexBuffer : public ArrayVertexBuffer
+{
+ public:
+ explicit StaticVertexBuffer(rx::Renderer9 *renderer);
+ ~StaticVertexBuffer();
+
+ void *map(const VertexAttribute &attribute, std::size_t requiredSpace, std::size_t *streamOffset);
+ void reserveRequiredSpace();
+
+ std::size_t lookupAttribute(const VertexAttribute &attribute); // Returns the offset into the vertex buffer, or -1 if not found
+
+ private:
+ struct VertexElement
+ {
+ GLenum type;
+ GLint size;
+ GLsizei stride;
+ bool normalized;
+ int attributeOffset;
+
+ std::size_t streamOffset;
+ };
+
+ std::vector<VertexElement> mCache;
+};
+
+class VertexDataManager
+{
+ public:
+ VertexDataManager(rx::Renderer9 *renderer);
+ virtual ~VertexDataManager();
+
+ GLenum prepareVertexData(const VertexAttribute attribs[], ProgramBinary *programBinary, GLint start, GLsizei count, TranslatedAttribute *outAttribs, GLsizei instances);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(VertexDataManager);
+
+ std::size_t spaceRequired(const VertexAttribute &attrib, std::size_t count, GLsizei instances) const;
+ std::size_t writeAttributeData(ArrayVertexBuffer *vertexBuffer, GLint start, GLsizei count, const VertexAttribute &attribute, GLsizei instances);
+
+ rx::Renderer9 *const mRenderer; // D3D9_REPLACE
+
+ StreamingVertexBuffer *mStreamingBuffer;
+
+ float mCurrentValue[MAX_VERTEX_ATTRIBS][4];
+ StreamingVertexBuffer *mCurrentValueBuffer[MAX_VERTEX_ATTRIBS];
+ std::size_t mCurrentValueOffsets[MAX_VERTEX_ATTRIBS];
+
+ // Attribute format conversion
+ struct FormatConverter
+ {
+ bool identity;
+ std::size_t outputElementSize;
+ void (*convertArray)(const void *in, std::size_t stride, std::size_t n, void *out);
+ D3DDECLTYPE d3dDeclType;
+ };
+
+ enum { NUM_GL_VERTEX_ATTRIB_TYPES = 6 };
+
+ FormatConverter mAttributeTypes[NUM_GL_VERTEX_ATTRIB_TYPES][2][4]; // [GL types as enumerated by typeIndex()][normalized][size - 1]
+
+ struct TranslationDescription
+ {
+ DWORD capsFlag;
+ FormatConverter preferredConversion;
+ FormatConverter fallbackConversion;
+ };
+
+ // This table is used to generate mAttributeTypes.
+ static const TranslationDescription mPossibleTranslations[NUM_GL_VERTEX_ATTRIB_TYPES][2][4]; // [GL types as enumerated by typeIndex()][normalized][size - 1]
+
+ void checkVertexCaps(DWORD declTypes);
+
+ unsigned int typeIndex(GLenum type) const;
+ const FormatConverter &formatConverter(const VertexAttribute &attribute) const;
+};
+
+}
+
+#endif // LIBGLESV2_VERTEXDATAMANAGER_H_
diff --git a/src/libGLESv2/renderer/VertexDeclarationCache.cpp b/src/libGLESv2/renderer/VertexDeclarationCache.cpp
index 37ccf5f..b69ad5d 100644
--- a/src/libGLESv2/renderer/VertexDeclarationCache.cpp
+++ b/src/libGLESv2/renderer/VertexDeclarationCache.cpp
@@ -7,7 +7,7 @@
// VertexDeclarationCache.cpp: Implements a helper class to construct and cache vertex declarations.
#include "libGLESv2/ProgramBinary.h"
-#include "libGLESv2/VertexDataManager.h"
+#include "libGLESv2/renderer/VertexDataManager.h"
#include "libGLESv2/renderer/VertexDeclarationCache.h"
namespace rx
diff --git a/src/libGLESv2/renderer/VertexDeclarationCache.h b/src/libGLESv2/renderer/VertexDeclarationCache.h
index 3b4545e..f977eb6 100644
--- a/src/libGLESv2/renderer/VertexDeclarationCache.h
+++ b/src/libGLESv2/renderer/VertexDeclarationCache.h
@@ -10,7 +10,7 @@
#define LIBGLESV2_RENDERER_VERTEXDECLARATIONCACHE_H_
#include "libGLESv2/Context.h"
-#include "libGLESv2/VertexDataManager.h"
+#include "libGLESv2/renderer/VertexDataManager.h"
namespace gl
{
diff --git a/src/libGLESv2/renderer/vertexconversion.h b/src/libGLESv2/renderer/vertexconversion.h
new file mode 100644
index 0000000..5bb8b89
--- /dev/null
+++ b/src/libGLESv2/renderer/vertexconversion.h
@@ -0,0 +1,208 @@
+//
+// Copyright (c) 2002-2010 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.
+//
+
+// vertexconversion.h: A library of vertex conversion classes that can be used to build
+// the FormatConverter objects used by the buffer conversion system.
+
+#ifndef LIBGLESV2_VERTEXCONVERSION_H_
+#define LIBGLESV2_VERTEXCONVERSION_H_
+
+#include <cstddef>
+#include <limits>
+
+#include "libGLESv2/Context.h" // Defines Index
+
+namespace gl
+{
+
+// Conversion types:
+// static const bool identity: true if this is an identity transform, false otherwise
+// static U convert(T): convert a single element from the input type to the output type
+// typedef ... OutputType: the type produced by this conversion
+
+template <class T>
+struct Identity
+{
+ static const bool identity = true;
+
+ typedef T OutputType;
+
+ static T convert(T x)
+ {
+ return x;
+ }
+};
+
+template <class FromT, class ToT>
+struct Cast
+{
+ static const bool identity = false;
+
+ typedef ToT OutputType;
+
+ static ToT convert(FromT x)
+ {
+ return static_cast<ToT>(x);
+ }
+};
+
+template <class T>
+struct Cast<T, T>
+{
+ static const bool identity = true;
+
+ typedef T OutputType;
+
+ static T convert(T x)
+ {
+ return static_cast<T>(x);
+ }
+};
+
+template <class T>
+struct Normalize
+{
+ static const bool identity = false;
+
+ typedef float OutputType;
+
+ static float convert(T x)
+ {
+ typedef std::numeric_limits<T> NL;
+ float f = static_cast<float>(x);
+
+ if (NL::is_signed)
+ {
+ // const float => VC2008 computes it at compile time
+ // static const float => VC2008 computes it the first time we get here, stores it to memory with static guard and all that.
+ const float divisor = 1.0f/(2*static_cast<float>(NL::max())+1);
+ return (2*f+1)*divisor;
+ }
+ else
+ {
+ return f/NL::max();
+ }
+ }
+};
+
+template <class FromType, std::size_t ScaleBits>
+struct FixedToFloat
+{
+ static const bool identity = false;
+
+ typedef float OutputType;
+
+ static float convert(FromType x)
+ {
+ const float divisor = 1.0f / static_cast<float>(static_cast<FromType>(1) << ScaleBits);
+ return static_cast<float>(x) * divisor;
+ }
+};
+
+// Widen types:
+// static const unsigned int initialWidth: number of components before conversion
+// static const unsigned int finalWidth: number of components after conversion
+
+// Float is supported at any size.
+template <std::size_t N>
+struct NoWiden
+{
+ static const std::size_t initialWidth = N;
+ static const std::size_t finalWidth = N;
+};
+
+// SHORT, norm-SHORT, norm-UNSIGNED_SHORT are supported but only with 2 or 4 components
+template <std::size_t N>
+struct WidenToEven
+{
+ static const std::size_t initialWidth = N;
+ static const std::size_t finalWidth = N+(N&1);
+};
+
+template <std::size_t N>
+struct WidenToFour
+{
+ static const std::size_t initialWidth = N;
+ static const std::size_t finalWidth = 4;
+};
+
+// Most types have 0 and 1 that are just that.
+template <class T>
+struct SimpleDefaultValues
+{
+ static T zero() { return static_cast<T>(0); }
+ static T one() { return static_cast<T>(1); }
+};
+
+// But normalised types only store [0,1] or [-1,1] so 1.0 is represented by the max value.
+template <class T>
+struct NormalizedDefaultValues
+{
+ static T zero() { return static_cast<T>(0); }
+ static T one() { return std::numeric_limits<T>::max(); }
+};
+
+// Converter:
+// static const bool identity: true if this is an identity transform (with no widening)
+// static const std::size_t finalSize: number of bytes per output vertex
+// static void convertArray(const void *in, std::size_t stride, std::size_t n, void *out): convert an array of vertices. Input may be strided, but output will be unstrided.
+
+template <class InT, class WidenRule, class Converter, class DefaultValueRule = SimpleDefaultValues<InT> >
+struct VertexDataConverter
+{
+ typedef typename Converter::OutputType OutputType;
+ typedef InT InputType;
+
+ static const bool identity = (WidenRule::initialWidth == WidenRule::finalWidth) && Converter::identity;
+ static const std::size_t finalSize = WidenRule::finalWidth * sizeof(OutputType);
+
+ static void convertArray(const InputType *in, std::size_t stride, std::size_t n, OutputType *out)
+ {
+ for (std::size_t i = 0; i < n; i++)
+ {
+ const InputType *ein = pointerAddBytes(in, i * stride);
+
+ copyComponent(out, ein, 0, static_cast<OutputType>(DefaultValueRule::zero()));
+ copyComponent(out, ein, 1, static_cast<OutputType>(DefaultValueRule::zero()));
+ copyComponent(out, ein, 2, static_cast<OutputType>(DefaultValueRule::zero()));
+ copyComponent(out, ein, 3, static_cast<OutputType>(DefaultValueRule::one()));
+
+ out += WidenRule::finalWidth;
+ }
+ }
+
+ static void convertArray(const void *in, std::size_t stride, std::size_t n, void *out)
+ {
+ return convertArray(static_cast<const InputType*>(in), stride, n, static_cast<OutputType*>(out));
+ }
+
+ private:
+ // Advance the given pointer by a number of bytes (not pointed-to elements).
+ template <class T>
+ static T *pointerAddBytes(T *basePtr, std::size_t numBytes)
+ {
+ return reinterpret_cast<T *>(reinterpret_cast<uintptr_t>(basePtr) + numBytes);
+ }
+
+ static void copyComponent(OutputType *out, const InputType *in, std::size_t elementindex, OutputType defaultvalue)
+ {
+ if (WidenRule::finalWidth > elementindex)
+ {
+ if (WidenRule::initialWidth > elementindex)
+ {
+ out[elementindex] = Converter::convert(in[elementindex]);
+ }
+ else
+ {
+ out[elementindex] = defaultvalue;
+ }
+ }
+ }
+};
+
+}
+
+#endif // LIBGLESV2_VERTEXCONVERSION_H_