Support translating indices.
TRAC #11393
Signed-off-by: Nicolas Capens
Signed-off-by: Daniel Koch
Author: Andrew Lewycky
git-svn-id: https://angleproject.googlecode.com/svn/trunk@72 736b8ea6-26fd-11df-bfd4-992fa37f6226
diff --git a/src/libGLESv2/Context.cpp b/src/libGLESv2/Context.cpp
index b330b0d..f13db41 100644
--- a/src/libGLESv2/Context.cpp
+++ b/src/libGLESv2/Context.cpp
@@ -23,6 +23,7 @@
#include "utilities.h"
#include "geometry/backend.h"
#include "geometry/VertexDataManager.h"
+#include "geometry/IndexDataManager.h"
#include "geometry/dx9.h"
#undef near
@@ -138,6 +139,7 @@
mBufferBackEnd = NULL;
mVertexDataManager = NULL;
+ mIndexDataManager = NULL;
mInvalidEnum = false;
mInvalidValue = false;
@@ -166,6 +168,7 @@
delete mBufferBackEnd;
delete mVertexDataManager;
+ delete mIndexDataManager;
while (!mBufferMap.empty())
{
@@ -206,6 +209,7 @@
{
mBufferBackEnd = new Dx9BackEnd(device);
mVertexDataManager = new VertexDataManager(this, mBufferBackEnd);
+ mIndexDataManager = new IndexDataManager(this, mBufferBackEnd);
}
// Wrap the existing Direct3D 9 resources into GL objects and assign them to the '0' names
@@ -1020,50 +1024,26 @@
lookupAttributeMapping(translated);
- mBufferBackEnd->preDraw(translated);
+ mBufferBackEnd->setupAttributesPreDraw(translated);
}
-void Context::applyVertexBuffer(GLsizei count, const void *indices, GLenum indexType)
+void Context::applyVertexBuffer(const TranslatedIndexData &indexInfo)
{
TranslatedAttribute translated[MAX_VERTEX_ATTRIBS];
- mVertexDataManager->preRenderValidate(adjustIndexPointer(indices), count, translated);
+ mVertexDataManager->preRenderValidate(indexInfo, translated);
lookupAttributeMapping(translated);
- mBufferBackEnd->preDraw(translated);
+ mBufferBackEnd->setupAttributesPreDraw(translated);
}
// Applies the indices and element array bindings to the Direct3D 9 device
-void Context::applyIndexBuffer(const void *indices, GLsizei count)
+TranslatedIndexData Context::applyIndexBuffer(const void *indices, GLsizei count, GLenum mode, GLenum type)
{
- GLsizei length = count * sizeof(Index);
-
- IDirect3DDevice9 *device = getDevice();
-
- IDirect3DIndexBuffer9 *indexBuffer = NULL;
- void *data;
-
- HRESULT result = device->CreateIndexBuffer(length, 0, D3DFMT_INDEX16, D3DPOOL_MANAGED, &indexBuffer, NULL);
-
- if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
- {
- return error(GL_OUT_OF_MEMORY);
- }
-
- ASSERT(SUCCEEDED(result));
-
- if (indexBuffer)
- {
- indexBuffer->Lock(0, length, &data, 0);
- memcpy(data, adjustIndexPointer(indices), length);
- indexBuffer->Unlock();
-
- device->SetIndices(indexBuffer);
- indexBuffer->Release(); // Will only effectively be deleted when no longer in use
- }
-
- startIndex = 0;
+ TranslatedIndexData indexInfo = mIndexDataManager->preRenderValidate(mode, type, count, getBuffer(elementArrayBuffer), indices);
+ mBufferBackEnd->setupIndicesPreDraw(indexInfo);
+ return indexInfo;
}
// Applies the shaders and shader constants to the Direct3D 9 device
@@ -1480,7 +1460,7 @@
if (!cullSkipsDraw(mode))
{
device->BeginScene();
- device->DrawPrimitive(primitiveType, first, primitiveCount);
+ device->DrawPrimitive(primitiveType, 0, primitiveCount);
device->EndScene();
}
}
@@ -1515,15 +1495,15 @@
}
applyState();
- applyVertexBuffer(count, indices, type);
- applyIndexBuffer(indices, count);
+ TranslatedIndexData indexInfo = applyIndexBuffer(indices, count, mode, type);
+ applyVertexBuffer(indexInfo);
applyShaders();
applyTextures();
if (!cullSkipsDraw(mode))
{
device->BeginScene();
- device->DrawIndexedPrimitive(primitiveType, 0, 0, count, startIndex, primitiveCount);
+ device->DrawIndexedPrimitive(primitiveType, -(INT)indexInfo.minIndex, indexInfo.minIndex, indexInfo.maxIndex-indexInfo.minIndex+1, indexInfo.offset/sizeof(Index), primitiveCount);
device->EndScene();
}
}
diff --git a/src/libGLESv2/Context.h b/src/libGLESv2/Context.h
index 65cf8ec..649114a 100644
--- a/src/libGLESv2/Context.h
+++ b/src/libGLESv2/Context.h
@@ -30,6 +30,7 @@
namespace gl
{
struct TranslatedAttribute;
+struct TranslatedIndexData;
class Buffer;
class Shader;
@@ -43,6 +44,7 @@
class Depthbuffer;
class Stencilbuffer;
class VertexDataManager;
+class IndexDataManager;
class BufferBackEnd;
enum
@@ -189,8 +191,6 @@
AttributeState vertexAttribute[MAX_VERTEX_ATTRIBS];
GLuint samplerTexture[SAMPLER_TYPE_COUNT][MAX_TEXTURE_IMAGE_UNITS];
- unsigned int startIndex;
-
GLint unpackAlignment;
GLint packAlignment;
};
@@ -257,8 +257,8 @@
bool applyRenderTarget(bool ignoreViewport);
void applyState();
void applyVertexBuffer(GLint first, GLsizei count);
- void applyVertexBuffer(GLsizei count, const void *indices, GLenum indexType);
- void applyIndexBuffer(const void *indices, GLsizei count);
+ void applyVertexBuffer(const TranslatedIndexData &indexInfo);
+ TranslatedIndexData applyIndexBuffer(const void *indices, GLsizei count, GLenum mode, GLenum type);
void applyShaders();
void applyTextures();
@@ -321,6 +321,7 @@
BufferBackEnd *mBufferBackEnd;
VertexDataManager *mVertexDataManager;
+ IndexDataManager *mIndexDataManager;
Texture *mIncompleteTextures[SAMPLER_TYPE_COUNT];
diff --git a/src/libGLESv2/geometry/IndexDataManager.cpp b/src/libGLESv2/geometry/IndexDataManager.cpp
new file mode 100644
index 0000000..b0e864c
--- /dev/null
+++ b/src/libGLESv2/geometry/IndexDataManager.cpp
@@ -0,0 +1,119 @@
+//
+// 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.
+//
+
+// geometry/IndexDataManager.cpp: Defines the IndexDataManager, a class that
+// runs the Buffer translation process for index buffers.
+
+#include "geometry/IndexDataManager.h"
+
+#include "common/debug.h"
+#include "Buffer.h"
+#include "geometry/backend.h"
+
+namespace
+{
+ enum { INITIAL_INDEX_BUFFER_SIZE = sizeof(gl::Index) * 8192 };
+}
+
+namespace gl
+{
+
+IndexDataManager::IndexDataManager(Context *context, BufferBackEnd *backend)
+ : mContext(context), mBackend(backend)
+{
+ mStreamBuffer = mBackend->createIndexBuffer(INITIAL_INDEX_BUFFER_SIZE);
+}
+
+IndexDataManager::~IndexDataManager()
+{
+ delete mStreamBuffer;
+}
+
+namespace
+{
+
+template <class InputIndexType>
+void copyIndices(const InputIndexType *in, GLsizei count, Index *out, GLuint *minIndex, GLuint *maxIndex)
+{
+ GLuint minIndexSoFar = *in;
+ GLuint maxIndexSoFar = *in;
+
+ for (GLsizei i = 0; i < count; i++)
+ {
+ if (minIndexSoFar > *in) minIndexSoFar = *in;
+ if (maxIndexSoFar < *in) maxIndexSoFar = *in;
+
+ *out++ = *in++;
+ }
+
+ *minIndex = minIndexSoFar;
+ *maxIndex = maxIndexSoFar;
+}
+
+}
+
+TranslatedIndexData IndexDataManager::preRenderValidate(GLenum mode, GLenum type, GLsizei count, Buffer *arrayElementBuffer, const void *indices)
+{
+ ASSERT(type == GL_UNSIGNED_SHORT || type == GL_UNSIGNED_BYTE);
+ ASSERT(count > 0);
+
+ TranslatedIndexData translated;
+
+ translated.count = count;
+
+ std::size_t requiredSpace = spaceRequired(mode, type, count);
+
+ if (requiredSpace > mStreamBuffer->size())
+ {
+ std::size_t newSize = std::max(requiredSpace, 2 * mStreamBuffer->size());
+
+ TranslatedIndexBuffer *newStreamBuffer = mBackend->createIndexBuffer(newSize);
+
+ delete mStreamBuffer;
+ mStreamBuffer = newStreamBuffer;
+ }
+
+ mStreamBuffer->reserveSpace(requiredSpace);
+
+ size_t offset;
+ void *output = mStreamBuffer->map(requiredSpace, &offset);
+
+ translated.buffer = mStreamBuffer;
+ translated.offset = offset;
+
+ translated.indices = static_cast<const Index*>(output);
+
+ if (arrayElementBuffer != NULL)
+ {
+ indices = static_cast<const GLubyte*>(arrayElementBuffer->data()) + reinterpret_cast<GLsizei>(indices);
+ }
+
+ Index *out = static_cast<Index*>(output);
+
+ if (type == GL_UNSIGNED_SHORT)
+ {
+ const GLushort *in = static_cast<const GLushort*>(indices);
+
+ copyIndices(in, count, out, &translated.minIndex, &translated.maxIndex);
+ }
+ else
+ {
+ const GLubyte *in = static_cast<const GLubyte*>(indices);
+
+ copyIndices(in, count, out, &translated.minIndex, &translated.maxIndex);
+ }
+
+ mStreamBuffer->unmap();
+
+ return translated;
+}
+
+std::size_t IndexDataManager::spaceRequired(GLenum mode, GLenum type, GLsizei count)
+{
+ return count * sizeof(Index);
+}
+
+}
diff --git a/src/libGLESv2/geometry/IndexDataManager.h b/src/libGLESv2/geometry/IndexDataManager.h
new file mode 100644
index 0000000..d590a9b
--- /dev/null
+++ b/src/libGLESv2/geometry/IndexDataManager.h
@@ -0,0 +1,60 @@
+//
+// 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.
+//
+
+// geometry/IndexDataManager.h: Defines the IndexDataManager, a class that
+// runs the Buffer translation process for index buffers.
+
+#ifndef LIBGLESV2_GEOMETRY_INDEXDATAMANAGER_H_
+#define LIBGLESV2_GEOMETRY_INDEXDATAMANAGER_H_
+
+#include <bitset>
+#include <cstddef>
+
+#define GL_APICALL
+#include <GLES2/gl2.h>
+
+#include "Context.h"
+
+namespace gl
+{
+
+class Buffer;
+class BufferBackEnd;
+class TranslatedIndexBuffer;
+struct FormatConverter;
+
+struct TranslatedIndexData
+{
+ GLuint minIndex;
+ GLuint maxIndex;
+ GLuint count;
+
+ const Index *indices;
+
+ TranslatedIndexBuffer *buffer;
+ GLsizei offset;
+};
+
+class IndexDataManager
+{
+ public:
+ IndexDataManager(Context *context, BufferBackEnd *backend);
+ ~IndexDataManager();
+
+ TranslatedIndexData preRenderValidate(GLenum mode, GLenum type, GLsizei count, Buffer *arrayElementBuffer, const void *indices);
+
+ private:
+ std::size_t spaceRequired(GLenum mode, GLenum type, GLsizei count);
+
+ Context *mContext;
+ BufferBackEnd *mBackend;
+
+ TranslatedIndexBuffer *mStreamBuffer;
+};
+
+}
+
+#endif // LIBGLESV2_GEOMETRY_INDEXDATAMANAGER_H_
diff --git a/src/libGLESv2/geometry/VertexDataManager.cpp b/src/libGLESv2/geometry/VertexDataManager.cpp
index 120d928..c11feba 100644
--- a/src/libGLESv2/geometry/VertexDataManager.cpp
+++ b/src/libGLESv2/geometry/VertexDataManager.cpp
@@ -14,6 +14,7 @@
#include "Buffer.h"
#include "geometry/backend.h"
+#include "geometry/IndexDataManager.h"
namespace
{
@@ -51,17 +52,17 @@
void VertexDataManager::ArrayTranslationHelper::translate(const FormatConverter &converter, GLsizei stride, const void *source, void *dest)
{
- converter.convertArray(source, stride, mFirst+mCount, dest);
+ converter.convertArray(source, stride, mCount, dest);
}
-VertexDataManager::IndexedTranslationHelper::IndexedTranslationHelper(const Index *indices, GLsizei count)
- : mIndices(indices), mCount(count)
+VertexDataManager::IndexedTranslationHelper::IndexedTranslationHelper(const Index *indices, Index minIndex, GLsizei count)
+ : mIndices(indices), mMinIndex(minIndex), mCount(count)
{
}
void VertexDataManager::IndexedTranslationHelper::translate(const FormatConverter &converter, GLsizei stride, const void *source, void *dest)
{
- converter.convertIndexed(source, stride, mCount, mIndices, dest);
+ converter.convertIndexed(source, stride, mMinIndex, mCount, mIndices, dest);
}
std::bitset<MAX_VERTEX_ATTRIBS> VertexDataManager::activeAttribs()
@@ -85,43 +86,16 @@
{
ArrayTranslationHelper translationHelper(start, count);
- return internalPreRenderValidate(mContext->vertexAttribute, activeAttribs(), start, start+count, &translationHelper, outAttribs);
+ return internalPreRenderValidate(mContext->vertexAttribute, activeAttribs(), start, start+count-1, &translationHelper, outAttribs);
}
-namespace
-{
-
-void indexRange(const Index *indices, std::size_t count, Index *minOut, Index *maxOut)
-{
- ASSERT(count > 0);
-
- Index minSoFar = indices[0];
- Index maxSoFar = indices[0];
-
- for (std::size_t i = 1; i < count; i++)
- {
- if (indices[i] > maxSoFar) maxSoFar = indices[i];
- if (indices[i] < minSoFar) minSoFar = indices[i];
- }
-
- *minOut = minSoFar;
- *maxOut = maxSoFar;
-}
-
-}
-
-GLenum VertexDataManager::preRenderValidate(const Index *indices, GLsizei count,
+GLenum VertexDataManager::preRenderValidate(const TranslatedIndexData &indexInfo,
TranslatedAttribute *outAttribs)
{
- Index minIndex;
- Index maxIndex;
+ IndexedTranslationHelper translationHelper(indexInfo.indices, indexInfo.minIndex, indexInfo.count);
- indexRange(indices, count, &minIndex, &maxIndex);
-
- IndexedTranslationHelper translationHelper(indices, count);
-
- return internalPreRenderValidate(mContext->vertexAttribute, activeAttribs(), minIndex, maxIndex, &translationHelper, outAttribs);
+ return internalPreRenderValidate(mContext->vertexAttribute, activeAttribs(), indexInfo.minIndex, indexInfo.maxIndex, &translationHelper, outAttribs);
}
GLenum VertexDataManager::internalPreRenderValidate(const AttributeState *attribs,
@@ -159,8 +133,8 @@
translated[i].type = attribs[i].mType;
translated[i].size = attribs[i].mSize;
translated[i].normalized = attribs[i].mNormalized;
- translated[i].offset = static_cast<std::size_t>(static_cast<const char*>(attribs[i].mPointer) - static_cast<const char*>(NULL));
translated[i].stride = interpretGlStride(attribs[i]);
+ translated[i].offset = static_cast<std::size_t>(static_cast<const char*>(attribs[i].mPointer) - static_cast<const char*>(NULL)) + translated[i].stride * minIndex;
translated[i].buffer = mContext->getBuffer(attribs[i].mBoundBuffer)->identityBuffer();
}
else
@@ -173,7 +147,7 @@
// Handle any attributes needing translation or lifting.
if (translateOrLift.any())
{
- std::size_t count = maxIndex + 1;
+ std::size_t count = maxIndex - minIndex + 1;
std::size_t requiredSpace = 0;
@@ -222,6 +196,10 @@
input = attribs[i].mPointer;
}
+ size_t inputStride = interpretGlStride(attribs[i]);
+
+ input = static_cast<const char*>(input) + inputStride * minIndex;
+
translator->translate(formatConverter, interpretGlStride(attribs[i]), input, output);
mStreamBuffer->unmap();
diff --git a/src/libGLESv2/geometry/VertexDataManager.h b/src/libGLESv2/geometry/VertexDataManager.h
index 8f2fbd9..0d19261 100644
--- a/src/libGLESv2/geometry/VertexDataManager.h
+++ b/src/libGLESv2/geometry/VertexDataManager.h
@@ -26,6 +26,7 @@
class TranslatedVertexBuffer;
struct TranslatedAttribute;
struct FormatConverter;
+struct TranslatedIndexData;
class VertexDataManager
{
@@ -39,8 +40,7 @@
GLsizei count,
TranslatedAttribute *outAttribs);
- GLenum preRenderValidate(const Index *indices,
- GLsizei count,
+ GLenum preRenderValidate(const TranslatedIndexData &indexInfo,
TranslatedAttribute* outAttribs);
private:
@@ -69,12 +69,13 @@
class IndexedTranslationHelper : public TranslationHelper
{
public:
- IndexedTranslationHelper(const Index *indices, GLsizei count);
+ IndexedTranslationHelper(const Index *indices, Index minIndex, GLsizei count);
void translate(const FormatConverter &converter, GLint stride, const void *source, void *dest);
private:
const Index *mIndices;
+ Index mMinIndex;
GLsizei mCount;
};
diff --git a/src/libGLESv2/geometry/backend.h b/src/libGLESv2/geometry/backend.h
index 94ba37b..8c3cd04 100644
--- a/src/libGLESv2/geometry/backend.h
+++ b/src/libGLESv2/geometry/backend.h
@@ -26,7 +26,7 @@
{
bool identity;
std::size_t outputVertexSize;
- void (*convertIndexed)(const void *in, std::size_t stride, std::size_t n, const Index *indices, void *out);
+ void (*convertIndexed)(const void *in, std::size_t stride, Index minIndex, std::size_t n, const Index *indices, void *out);
void (*convertArray)(const void *in, std::size_t stride, std::size_t n, void *out);
};
@@ -57,7 +57,8 @@
virtual TranslatedIndexBuffer *createIndexBuffer(std::size_t size) = 0;
virtual FormatConverter getFormatConverter(GLenum type, std::size_t size, bool normalize) = 0;
- virtual GLenum preDraw(const TranslatedAttribute *attributes) = 0;
+ virtual GLenum setupIndicesPreDraw(const TranslatedIndexData &indexInfo) = 0;
+ virtual GLenum setupAttributesPreDraw(const TranslatedAttribute *attributes) = 0;
};
class TranslatedBuffer
diff --git a/src/libGLESv2/geometry/dx9.cpp b/src/libGLESv2/geometry/dx9.cpp
index 73bab0e..c6681e9 100644
--- a/src/libGLESv2/geometry/dx9.cpp
+++ b/src/libGLESv2/geometry/dx9.cpp
@@ -17,6 +17,7 @@
#include "common/debug.h"
#include "geometry/vertexconversion.h"
+#include "geometry/IndexDataManager.h"
namespace
{
@@ -179,7 +180,13 @@
return ib ? static_cast<Dx9IndexBuffer*>(ib)->getBuffer() : NULL;
}
-GLenum Dx9BackEnd::preDraw(const TranslatedAttribute *attributes)
+GLenum Dx9BackEnd::setupIndicesPreDraw(const TranslatedIndexData &indexInfo)
+{
+ mDevice->SetIndices(getDxBuffer(indexInfo.buffer));
+ return GL_NO_ERROR;
+}
+
+GLenum Dx9BackEnd::setupAttributesPreDraw(const TranslatedAttribute *attributes)
{
HRESULT hr;
diff --git a/src/libGLESv2/geometry/dx9.h b/src/libGLESv2/geometry/dx9.h
index a1eeeb5..3e49672 100644
--- a/src/libGLESv2/geometry/dx9.h
+++ b/src/libGLESv2/geometry/dx9.h
@@ -27,7 +27,8 @@
virtual TranslatedIndexBuffer *createIndexBuffer(std::size_t size);
virtual FormatConverter getFormatConverter(GLenum type, std::size_t size, bool normalize);
- virtual GLenum preDraw(const TranslatedAttribute *attributes);
+ virtual GLenum setupIndicesPreDraw(const TranslatedIndexData &indexInfo);
+ virtual GLenum setupAttributesPreDraw(const TranslatedAttribute *attributes);
private:
IDirect3DDevice9 *mDevice;
diff --git a/src/libGLESv2/geometry/vertexconversion.h b/src/libGLESv2/geometry/vertexconversion.h
index 5bbb06f..c299021 100644
--- a/src/libGLESv2/geometry/vertexconversion.h
+++ b/src/libGLESv2/geometry/vertexconversion.h
@@ -180,12 +180,12 @@
return convertArray(static_cast<const InputType*>(in), stride, n, static_cast<OutputType*>(out));
}
- static void convertIndexed(const InputType *in, std::size_t stride, std::size_t n, const Index *indices, OutputType *out)
+ static void convertIndexed(const InputType *in, std::size_t stride, Index minIndex, std::size_t n, const Index *indices, OutputType *out)
{
for (std::size_t i = 0; i < n; i++)
{
- const InputType *ein = pointerAddBytes(in, indices[i] * stride);
- OutputType *eout = pointerAddBytes(out, indices[i] * finalSize);
+ const InputType *ein = pointerAddBytes(in, (indices[i] - minIndex) * stride);
+ OutputType *eout = pointerAddBytes(out, (indices[i] - minIndex) * finalSize);
copyComponent(eout, ein, 0, static_cast<OutputType>(DefaultValueRule::zero()));
copyComponent(eout, ein, 1, static_cast<OutputType>(DefaultValueRule::zero()));
@@ -194,9 +194,9 @@
}
}
- static void convertIndexed(const void *in, std::size_t stride, std::size_t n, const Index *indices, void *out)
+ static void convertIndexed(const void *in, std::size_t stride, Index minIndex, std::size_t n, const Index *indices, void *out)
{
- convertIndexed(static_cast<const InputType*>(in), stride, n, indices, static_cast<OutputType*>(out));
+ convertIndexed(static_cast<const InputType*>(in), stride, minIndex, n, indices, static_cast<OutputType*>(out));
}
private:
diff --git a/src/libGLESv2/libGLESv2.vcproj b/src/libGLESv2/libGLESv2.vcproj
index 2c75ee0..9c552d9 100644
--- a/src/libGLESv2/libGLESv2.vcproj
+++ b/src/libGLESv2/libGLESv2.vcproj
@@ -238,6 +238,10 @@
>
</File>
<File
+ RelativePath=".\geometry\IndexDataManager.cpp"
+ >
+ </File>
+ <File
RelativePath=".\geometry\VertexDataManager.cpp"
>
</File>
@@ -316,6 +320,10 @@
>
</File>
<File
+ RelativePath=".\geometry\IndexDataManager.h"
+ >
+ </File>
+ <File
RelativePath=".\geometry\vertexconversion.h"
>
</File>