Cache the index ranges at the gl::Buffer and rx::IndexBuffer levels so that ranges do not need to be re-calculated for direct buffers.
Issue #451
Signed-off-by: Jamie Madill
Signed-off-by: Shannon Woods
Author: Geoff Lang
diff --git a/src/libGLESv2/renderer/IndexBuffer.cpp b/src/libGLESv2/renderer/IndexBuffer.cpp
index 3d5d7a7..e24583a 100644
--- a/src/libGLESv2/renderer/IndexBuffer.cpp
+++ b/src/libGLESv2/renderer/IndexBuffer.cpp
@@ -176,28 +176,9 @@
}
}
-unsigned int StaticIndexBufferInterface::lookupRange(intptr_t offset, GLsizei count, unsigned int *minIndex, unsigned int *maxIndex)
+IndexRangeCache *StaticIndexBufferInterface::getIndexRangeCache()
{
- 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 StaticIndexBufferInterface::addRange(intptr_t offset, GLsizei count, unsigned int minIndex, unsigned int maxIndex, unsigned int streamOffset)
-{
- IndexRange indexRange = {offset, count};
- IndexResult indexResult = {minIndex, maxIndex, streamOffset};
- mCache[indexRange] = indexResult;
+ return &mIndexRangeCache;
}
}
-
diff --git a/src/libGLESv2/renderer/IndexBuffer.h b/src/libGLESv2/renderer/IndexBuffer.h
index 1afbd62..98fa5fe 100644
--- a/src/libGLESv2/renderer/IndexBuffer.h
+++ b/src/libGLESv2/renderer/IndexBuffer.h
@@ -11,6 +11,7 @@
#define LIBGLESV2_RENDERER_INDEXBUFFER_H_
#include "common/angleutils.h"
+#include "libGLESv2/renderer/IndexRangeCache.h"
namespace rx
{
@@ -99,37 +100,10 @@
virtual bool reserveBufferSpace(unsigned int size, GLenum indexType);
- unsigned int lookupRange(intptr_t offset, GLsizei count, unsigned int *minIndex, unsigned int *maxIndex); // Returns the offset into the index buffer, or -1 if not found
- void addRange(intptr_t offset, GLsizei count, unsigned int minIndex, unsigned int maxIndex, unsigned int streamOffset);
+ IndexRangeCache *getIndexRangeCache();
private:
- 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
- {
- unsigned int minIndex;
- unsigned int maxIndex;
- unsigned int streamOffset;
- };
-
- std::map<IndexRange, IndexResult> mCache;
+ IndexRangeCache mIndexRangeCache;
};
}
diff --git a/src/libGLESv2/renderer/IndexDataManager.cpp b/src/libGLESv2/renderer/IndexDataManager.cpp
index 723072b..5056bcb 100644
--- a/src/libGLESv2/renderer/IndexDataManager.cpp
+++ b/src/libGLESv2/renderer/IndexDataManager.cpp
@@ -13,6 +13,7 @@
#include "libGLESv2/Buffer.h"
#include "libGLESv2/main.h"
+#include "libGLESv2/formatutils.h"
#include "libGLESv2/renderer/IndexBuffer.h"
namespace rx
@@ -53,17 +54,6 @@
delete mCountingBuffer;
}
-static unsigned int indexTypeSize(GLenum type)
-{
- 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);
- }
-}
-
static void convertIndices(GLenum type, const void *input, GLsizei count, void *output)
{
if (type == GL_UNSIGNED_BYTE)
@@ -142,7 +132,7 @@
default: UNREACHABLE(); alignedOffset = false;
}
- if (indexTypeSize(type) * count + offset > storage->getSize())
+ if (gl::GetTypeBytes(type) * count + offset > storage->getSize())
{
return GL_INVALID_OPERATION;
}
@@ -162,18 +152,26 @@
{
indexBuffer = streamingBuffer;
streamOffset = offset;
- computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex);
+
+ if (!buffer->getIndexRangeCache()->findRange(type, offset, count, &translated->minIndex,
+ &translated->maxIndex, NULL))
+ {
+ computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex);
+ buffer->getIndexRangeCache()->addRange(type, offset, count, translated->minIndex,
+ translated->maxIndex, offset);
+ }
}
else if (staticBuffer && staticBuffer->getBufferSize() != 0 && staticBuffer->getIndexType() == type && alignedOffset)
{
indexBuffer = staticBuffer;
- streamOffset = staticBuffer->lookupRange(offset, count, &translated->minIndex, &translated->maxIndex);
- if (streamOffset == -1)
+ if (!staticBuffer->getIndexRangeCache()->findRange(type, offset, count, &translated->minIndex,
+ &translated->maxIndex, &streamOffset))
{
- streamOffset = (offset / indexTypeSize(type)) * indexTypeSize(destinationIndexType);
+ streamOffset = (offset / gl::GetTypeBytes(type)) * gl::GetTypeBytes(destinationIndexType);
computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex);
- staticBuffer->addRange(offset, count, translated->minIndex, translated->maxIndex, streamOffset);
+ staticBuffer->getIndexRangeCache()->addRange(type, offset, count, translated->minIndex,
+ translated->maxIndex, streamOffset);
}
}
else
@@ -185,7 +183,7 @@
if (staticBuffer->getBufferSize() == 0 && alignedOffset)
{
indexBuffer = staticBuffer;
- convertCount = storage->getSize() / indexTypeSize(type);
+ convertCount = storage->getSize() / gl::GetTypeBytes(type);
}
else
{
@@ -200,7 +198,7 @@
return GL_INVALID_OPERATION;
}
- unsigned int bufferSizeRequired = convertCount * indexTypeSize(destinationIndexType);
+ unsigned int bufferSizeRequired = convertCount * gl::GetTypeBytes(destinationIndexType);
indexBuffer->reserveBufferSpace(bufferSizeRequired, type);
void* output = NULL;
@@ -223,20 +221,21 @@
if (staticBuffer)
{
- streamOffset = (offset / indexTypeSize(type)) * indexTypeSize(destinationIndexType);
- staticBuffer->addRange(offset, count, translated->minIndex, translated->maxIndex, streamOffset);
+ streamOffset = (offset / gl::GetTypeBytes(type)) * gl::GetTypeBytes(destinationIndexType);
+ staticBuffer->getIndexRangeCache()->addRange(type, offset, count, translated->minIndex,
+ translated->maxIndex, streamOffset);
}
}
translated->storage = directStorage ? storage : NULL;
translated->indexBuffer = indexBuffer->getIndexBuffer();
translated->serial = directStorage ? storage->getSerial() : indexBuffer->getSerial();
- translated->startIndex = streamOffset / indexTypeSize(destinationIndexType);
+ translated->startIndex = streamOffset / gl::GetTypeBytes(destinationIndexType);
translated->startOffset = streamOffset;
if (buffer)
{
- buffer->promoteStaticUsage(count * indexTypeSize(type));
+ buffer->promoteStaticUsage(count * gl::GetTypeBytes(type));
}
return GL_NO_ERROR;
diff --git a/src/libGLESv2/renderer/IndexRangeCache.cpp b/src/libGLESv2/renderer/IndexRangeCache.cpp
new file mode 100644
index 0000000..b504aa1
--- /dev/null
+++ b/src/libGLESv2/renderer/IndexRangeCache.cpp
@@ -0,0 +1,97 @@
+#include "precompiled.h"
+//
+// Copyright (c) 2013 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.
+//
+
+// IndexRangeCache.cpp: Defines the rx::IndexRangeCache class which stores information about
+// ranges of indices.
+
+#include "libGLESv2/renderer/IndexRangeCache.h"
+#include "libGLESv2/formatutils.h"
+#include "common/debug.h"
+#include <tuple>
+
+namespace rx
+{
+
+void IndexRangeCache::addRange(GLenum type, intptr_t offset, GLsizei count, unsigned int minIdx, unsigned int maxIdx,
+ unsigned int streamOffset)
+{
+ mIndexRangeCache[IndexRange(type, offset, count)] = IndexBounds(minIdx, maxIdx, streamOffset);
+}
+
+void IndexRangeCache::invalidateRange(unsigned int offset, unsigned int size)
+{
+ unsigned int invalidateStart = offset;
+ unsigned int invalidateEnd = offset + size;
+
+ IndexRangeMap::iterator i = mIndexRangeCache.begin();
+ while (i != mIndexRangeCache.end())
+ {
+ unsigned int rangeStart = i->second.streamOffset;
+ unsigned int rangeEnd = i->second.streamOffset + (gl::GetTypeBytes(i->first.type) * i->first.count);
+
+ if (invalidateEnd < rangeStart || invalidateStart > rangeEnd)
+ {
+ ++i;
+ }
+ else
+ {
+ i = mIndexRangeCache.erase(i);
+ }
+ }
+}
+
+bool IndexRangeCache::findRange(GLenum type, intptr_t offset, GLsizei count, unsigned int *outMinIndex,
+ unsigned int *outMaxIndex, unsigned int *outStreamOffset) const
+{
+ IndexRangeMap::const_iterator i = mIndexRangeCache.find(IndexRange(type, offset, count));
+ if (i != mIndexRangeCache.end())
+ {
+ if (outMinIndex) *outMinIndex = i->second.minIndex;
+ if (outMaxIndex) *outMaxIndex = i->second.maxIndex;
+ if (outStreamOffset) *outStreamOffset = i->second.streamOffset;
+ return true;
+ }
+ else
+ {
+ if (outMinIndex) *outMinIndex = 0;
+ if (outMaxIndex) *outMaxIndex = 0;
+ if (outStreamOffset) *outStreamOffset = 0;
+ return false;
+ }
+}
+
+void IndexRangeCache::clear()
+{
+ mIndexRangeCache.clear();
+}
+
+IndexRangeCache::IndexRange::IndexRange()
+ : type(GL_NONE), offset(0), count(0)
+{
+}
+
+IndexRangeCache::IndexRange::IndexRange(GLenum typ, intptr_t off, GLsizei c)
+ : type(typ), offset(off), count(c)
+{
+}
+
+bool IndexRangeCache::IndexRange::operator<(const IndexRange& rhs) const
+{
+ return std::make_tuple(type, offset, count) < std::make_tuple(rhs.type, rhs.offset, rhs.count);
+}
+
+IndexRangeCache::IndexBounds::IndexBounds()
+ : minIndex(0), maxIndex(0), streamOffset(0)
+{
+}
+
+IndexRangeCache::IndexBounds::IndexBounds(unsigned int minIdx, unsigned int maxIdx, unsigned int offset)
+ : minIndex(minIdx), maxIndex(maxIdx), streamOffset(offset)
+{
+}
+
+}
diff --git a/src/libGLESv2/renderer/IndexRangeCache.h b/src/libGLESv2/renderer/IndexRangeCache.h
new file mode 100644
index 0000000..5a5ade1
--- /dev/null
+++ b/src/libGLESv2/renderer/IndexRangeCache.h
@@ -0,0 +1,58 @@
+//
+// Copyright (c) 2013 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.
+//
+
+// IndexRangeCache.h: Defines the rx::IndexRangeCache class which stores information about
+// ranges of indices.
+
+#ifndef LIBGLESV2_RENDERER_INDEXRANGECACHE_H_
+#define LIBGLESV2_RENDERER_INDEXRANGECACHE_H_
+
+#include "common/angleutils.h"
+
+namespace rx
+{
+
+class IndexRangeCache
+{
+ public:
+ void addRange(GLenum type, intptr_t offset, GLsizei count, unsigned int minIdx, unsigned int maxIdx,
+ unsigned int streamOffset);
+ bool findRange(GLenum type, intptr_t offset, GLsizei count, unsigned int *outMinIndex,
+ unsigned int *outMaxIndex, unsigned int *outStreamOffset) const;
+
+ void invalidateRange(unsigned int offset, unsigned int size);
+ void clear();
+
+ private:
+ struct IndexRange
+ {
+ GLenum type;
+ intptr_t offset;
+ GLsizei count;
+
+ IndexRange();
+ IndexRange(GLenum type, intptr_t offset, GLsizei count);
+
+ bool operator<(const IndexRange& rhs) const;
+ };
+
+ struct IndexBounds
+ {
+ unsigned int minIndex;
+ unsigned int maxIndex;
+ unsigned int streamOffset;
+
+ IndexBounds();
+ IndexBounds(unsigned int minIdx, unsigned int maxIdx, unsigned int offset);
+ };
+
+ typedef std::map<IndexRange, IndexBounds> IndexRangeMap;
+ IndexRangeMap mIndexRangeCache;
+};
+
+}
+
+#endif LIBGLESV2_RENDERER_INDEXRANGECACHE_H