Commit 74b91b5a by Alexis Hetu Committed by Alexis Hétu

Primitive restart implementation

Wrote a new version of primitive restart entirely handled by the index data manager. Passes all primitive_restart dEQP tests Change-Id: I0ce28764a33300a6625f1c369f95d8d178e1e3c0 Reviewed-on: https://swiftshader-review.googlesource.com/10951Tested-by: 's avatarAlexis Hétu <sugoi@google.com> Reviewed-by: 's avatarNicolas Capens <nicolascapens@google.com>
parent 7a473b78
...@@ -2972,7 +2972,7 @@ GLenum Context::applyVertexBuffer(GLint base, GLint first, GLsizei count, GLsize ...@@ -2972,7 +2972,7 @@ GLenum Context::applyVertexBuffer(GLint base, GLint first, GLsizei count, GLsize
// Applies the indices and element array bindings // Applies the indices and element array bindings
GLenum Context::applyIndexBuffer(const void *indices, GLuint start, GLuint end, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo) GLenum Context::applyIndexBuffer(const void *indices, GLuint start, GLuint end, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo)
{ {
GLenum err = mIndexDataManager->prepareIndexData(type, start, end, count, getCurrentVertexArray()->getElementArrayBuffer(), indices, indexInfo); GLenum err = mIndexDataManager->prepareIndexData(mode, type, start, end, count, getCurrentVertexArray()->getElementArrayBuffer(), indices, indexInfo, isPrimitiveRestartFixedIndexEnabled());
if(err == GL_NO_ERROR) if(err == GL_NO_ERROR)
{ {
...@@ -3483,11 +3483,29 @@ void Context::drawElements(GLenum mode, GLuint start, GLuint end, GLsizei count, ...@@ -3483,11 +3483,29 @@ void Context::drawElements(GLenum mode, GLuint start, GLuint end, GLsizei count,
return error(GL_INVALID_OPERATION); return error(GL_INVALID_OPERATION);
} }
GLenum internalMode = mode;
if(isPrimitiveRestartFixedIndexEnabled())
{
switch(mode)
{
case GL_TRIANGLE_FAN:
case GL_TRIANGLE_STRIP:
internalMode = GL_TRIANGLES;
break;
case GL_LINE_LOOP:
case GL_LINE_STRIP:
internalMode = GL_LINES;
break;
default:
break;
}
}
sw::DrawType primitiveType; sw::DrawType primitiveType;
int primitiveCount; int primitiveCount;
int verticesPerPrimitive; int verticesPerPrimitive;
if(!es2sw::ConvertPrimitiveType(mode, count, type, primitiveType, primitiveCount, verticesPerPrimitive)) if(!es2sw::ConvertPrimitiveType(internalMode, count, type, primitiveType, primitiveCount, verticesPerPrimitive))
return error(GL_INVALID_ENUM); return error(GL_INVALID_ENUM);
if(primitiveCount <= 0) if(primitiveCount <= 0)
...@@ -3500,19 +3518,19 @@ void Context::drawElements(GLenum mode, GLuint start, GLuint end, GLsizei count, ...@@ -3500,19 +3518,19 @@ void Context::drawElements(GLenum mode, GLuint start, GLuint end, GLsizei count,
return; return;
} }
applyState(mode); TranslatedIndexData indexInfo(primitiveCount);
GLenum err = applyIndexBuffer(indices, start, end, count, mode, type, &indexInfo);
if(err != GL_NO_ERROR)
{
return error(err);
}
applyState(internalMode);
for(int i = 0; i < instanceCount; ++i) for(int i = 0; i < instanceCount; ++i)
{ {
device->setInstanceID(i); device->setInstanceID(i);
TranslatedIndexData indexInfo;
GLenum err = applyIndexBuffer(indices, start, end, count, mode, type, &indexInfo);
if(err != GL_NO_ERROR)
{
return error(err);
}
GLsizei vertexCount = indexInfo.maxIndex - indexInfo.minIndex + 1; GLsizei vertexCount = indexInfo.maxIndex - indexInfo.minIndex + 1;
err = applyVertexBuffer(-(int)indexInfo.minIndex, indexInfo.minIndex, vertexCount, i); err = applyVertexBuffer(-(int)indexInfo.minIndex, indexInfo.minIndex, vertexCount, i);
if(err != GL_NO_ERROR) if(err != GL_NO_ERROR)
...@@ -3529,13 +3547,13 @@ void Context::drawElements(GLenum mode, GLuint start, GLuint end, GLsizei count, ...@@ -3529,13 +3547,13 @@ void Context::drawElements(GLenum mode, GLuint start, GLuint end, GLsizei count,
} }
TransformFeedback* transformFeedback = getTransformFeedback(); TransformFeedback* transformFeedback = getTransformFeedback();
if(!cullSkipsDraw(mode) || (transformFeedback->isActive() && !transformFeedback->isPaused())) if(!cullSkipsDraw(internalMode) || (transformFeedback->isActive() && !transformFeedback->isPaused()))
{ {
device->drawIndexedPrimitive(primitiveType, indexInfo.indexOffset, primitiveCount); device->drawIndexedPrimitive(primitiveType, indexInfo.indexOffset, indexInfo.primitiveCount);
} }
if(transformFeedback) if(transformFeedback)
{ {
transformFeedback->addVertexOffset(primitiveCount * verticesPerPrimitive); transformFeedback->addVertexOffset(indexInfo.primitiveCount * verticesPerPrimitive);
} }
} }
} }
......
...@@ -63,37 +63,213 @@ void copyIndices(GLenum type, const void *input, GLsizei count, void *output) ...@@ -63,37 +63,213 @@ void copyIndices(GLenum type, const void *input, GLsizei count, void *output)
else UNREACHABLE(type); else UNREACHABLE(type);
} }
inline GLsizei getNumIndices(const std::vector<GLsizei>& restartIndices, size_t i, GLsizei count)
{
return (i == 0) ? restartIndices[0] : ((i == restartIndices.size()) ? (count - restartIndices[i - 1] - 1) : (restartIndices[i] - restartIndices[i - 1] - 1));
}
void copyIndices(GLenum mode, GLenum type, const std::vector<GLsizei>& restartIndices, const void *input, GLsizei count, void* output)
{
size_t bytesPerIndex = 0;
const unsigned char* inPtr = static_cast<const unsigned char*>(input);
unsigned char* outPtr = static_cast<unsigned char*>(output);
switch(type)
{
case GL_UNSIGNED_BYTE:
bytesPerIndex = sizeof(GLubyte);
break;
case GL_UNSIGNED_INT:
bytesPerIndex = sizeof(GLuint);
break;
case GL_UNSIGNED_SHORT:
bytesPerIndex = sizeof(GLushort);
break;
default:
UNREACHABLE(type);
}
size_t numRestarts = restartIndices.size();
switch(mode)
{
case GL_TRIANGLES:
case GL_LINES:
case GL_POINTS:
{
GLsizei verticesPerPrimitive = (mode == GL_TRIANGLES) ? 3 : ((mode == GL_LINES) ? 2 : 1);
for(size_t i = 0; i <= numRestarts; ++i)
{
GLsizei numIndices = getNumIndices(restartIndices, i, count);
size_t numBytes = (numIndices / verticesPerPrimitive) * verticesPerPrimitive * bytesPerIndex;
if(numBytes > 0)
{
memcpy(outPtr, inPtr, numBytes);
outPtr += numBytes;
}
inPtr += (numIndices + 1) * bytesPerIndex;
}
}
break;
case GL_TRIANGLE_FAN:
for(size_t i = 0; i <= numRestarts; ++i)
{
GLsizei numIndices = getNumIndices(restartIndices, i, count);
GLsizei numTriangles = (numIndices - 2);
for(GLsizei tri = 0; tri < numTriangles; ++tri)
{
memcpy(outPtr, inPtr, bytesPerIndex);
outPtr += bytesPerIndex;
memcpy(outPtr, inPtr + ((tri + 1) * bytesPerIndex), bytesPerIndex + bytesPerIndex);
outPtr += bytesPerIndex + bytesPerIndex;
}
inPtr += (numIndices + 1) * bytesPerIndex;
}
break;
case GL_TRIANGLE_STRIP:
for(size_t i = 0; i <= numRestarts; ++i)
{
GLsizei numIndices = getNumIndices(restartIndices, i, count);
GLsizei numTriangles = (numIndices - 2);
for(GLsizei tri = 0; tri < numTriangles; ++tri)
{
if(tri & 1) // Reverse odd triangles
{
memcpy(outPtr, inPtr + ((tri + 1) * bytesPerIndex), bytesPerIndex);
outPtr += bytesPerIndex;
memcpy(outPtr, inPtr + ((tri + 0) * bytesPerIndex), bytesPerIndex);
outPtr += bytesPerIndex;
memcpy(outPtr, inPtr + ((tri + 2) * bytesPerIndex), bytesPerIndex);
outPtr += bytesPerIndex;
}
else
{
size_t numBytes = 3 * bytesPerIndex;
memcpy(outPtr, inPtr + (tri * bytesPerIndex), numBytes);
outPtr += numBytes;
}
}
inPtr += (numIndices + 1) * bytesPerIndex;
}
break;
case GL_LINE_LOOP:
for(size_t i = 0; i <= numRestarts; ++i)
{
GLsizei numIndices = getNumIndices(restartIndices, i, count);
if(numIndices >= 2)
{
GLsizei numLines = numIndices;
memcpy(outPtr, inPtr + (numIndices - 1) * bytesPerIndex, bytesPerIndex); // Last vertex
outPtr += bytesPerIndex;
memcpy(outPtr, inPtr, bytesPerIndex); // First vertex
outPtr += bytesPerIndex;
size_t bytesPerLine = 2 * bytesPerIndex;
for(GLsizei tri = 0; tri < (numLines - 1); ++tri)
{
memcpy(outPtr, inPtr + tri * bytesPerIndex, bytesPerLine);
outPtr += bytesPerLine;
}
}
inPtr += (numIndices + 1) * bytesPerIndex;
}
break;
case GL_LINE_STRIP:
for(size_t i = 0; i <= numRestarts; ++i)
{
GLsizei numIndices = getNumIndices(restartIndices, i, count);
GLsizei numLines = numIndices - 1;
size_t bytesPerLine = 2 * bytesPerIndex;
for(GLsizei tri = 0; tri < numLines; ++tri)
{
memcpy(outPtr, inPtr + tri * bytesPerIndex, bytesPerLine);
outPtr += bytesPerLine;
}
inPtr += (numIndices + 1) * bytesPerIndex;
}
break;
default:
UNREACHABLE(mode);
break;
}
}
template<class IndexType> template<class IndexType>
void computeRange(const IndexType *indices, GLsizei count, GLuint *minIndex, GLuint *maxIndex) void computeRange(const IndexType *indices, GLsizei count, GLuint *minIndex, GLuint *maxIndex, std::vector<GLsizei>* restartIndices)
{ {
*minIndex = indices[0]; *maxIndex = 0;
*maxIndex = indices[0]; *minIndex = MAX_ELEMENTS_INDICES;
for(GLsizei i = 0; i < count; i++) for(GLsizei i = 0; i < count; i++)
{ {
if(restartIndices && indices[i] == IndexType(-1))
{
restartIndices->push_back(i);
continue;
}
if(*minIndex > indices[i]) *minIndex = indices[i]; if(*minIndex > indices[i]) *minIndex = indices[i];
if(*maxIndex < indices[i]) *maxIndex = indices[i]; if(*maxIndex < indices[i]) *maxIndex = indices[i];
} }
} }
void computeRange(GLenum type, const void *indices, GLsizei count, GLuint *minIndex, GLuint *maxIndex) void computeRange(GLenum type, const void *indices, GLsizei count, GLuint *minIndex, GLuint *maxIndex, std::vector<GLsizei>* restartIndices)
{ {
if(type == GL_UNSIGNED_BYTE) if(type == GL_UNSIGNED_BYTE)
{ {
computeRange(static_cast<const GLubyte*>(indices), count, minIndex, maxIndex); computeRange(static_cast<const GLubyte*>(indices), count, minIndex, maxIndex, restartIndices);
} }
else if(type == GL_UNSIGNED_INT) else if(type == GL_UNSIGNED_INT)
{ {
computeRange(static_cast<const GLuint*>(indices), count, minIndex, maxIndex); computeRange(static_cast<const GLuint*>(indices), count, minIndex, maxIndex, restartIndices);
} }
else if(type == GL_UNSIGNED_SHORT) else if(type == GL_UNSIGNED_SHORT)
{ {
computeRange(static_cast<const GLushort*>(indices), count, minIndex, maxIndex); computeRange(static_cast<const GLushort*>(indices), count, minIndex, maxIndex, restartIndices);
} }
else UNREACHABLE(type); else UNREACHABLE(type);
} }
GLenum IndexDataManager::prepareIndexData(GLenum type, GLuint start, GLuint end, GLsizei count, Buffer *buffer, const void *indices, TranslatedIndexData *translated) int recomputePrimitiveCount(GLenum mode, GLsizei count, const std::vector<GLsizei>& restartIndices, unsigned int* primitiveCount)
{
size_t numRestarts = restartIndices.size();
*primitiveCount = 0;
unsigned int countOffset = 0;
unsigned int vertexPerPrimitive = 0;
switch(mode)
{
case GL_TRIANGLES: // 3 vertex per primitive
++vertexPerPrimitive;
case GL_LINES: // 2 vertex per primitive
vertexPerPrimitive += 2;
for(size_t i = 0; i <= numRestarts; ++i)
{
unsigned int nbIndices = getNumIndices(restartIndices, i, count);
*primitiveCount += nbIndices / vertexPerPrimitive;
}
return vertexPerPrimitive;
case GL_TRIANGLE_FAN:
case GL_TRIANGLE_STRIP: // (N - 2) polygons, 3 vertex per primitive
++vertexPerPrimitive;
--countOffset;
case GL_LINE_STRIP: // (N - 1) polygons, 2 vertex per primitive
--countOffset;
case GL_LINE_LOOP: // N polygons, 2 vertex per primitive
vertexPerPrimitive += 2;
for(size_t i = 0; i <= numRestarts; ++i)
{
unsigned int nbIndices = getNumIndices(restartIndices, i, count);
*primitiveCount += (nbIndices >= vertexPerPrimitive) ? (nbIndices + countOffset) : 0;
}
return vertexPerPrimitive;
case GL_POINTS:
*primitiveCount = count - restartIndices.size();
return 1;
default:
UNREACHABLE(mode);
return -1;
}
}
GLenum IndexDataManager::prepareIndexData(GLenum mode, GLenum type, GLuint start, GLuint end, GLsizei count, Buffer *buffer, const void *indices, TranslatedIndexData *translated, bool primitiveRestart)
{ {
if(!mStreamingBuffer) if(!mStreamingBuffer)
{ {
...@@ -112,14 +288,49 @@ GLenum IndexDataManager::prepareIndexData(GLenum type, GLuint start, GLuint end, ...@@ -112,14 +288,49 @@ GLenum IndexDataManager::prepareIndexData(GLenum type, GLuint start, GLuint end,
indices = static_cast<const GLubyte*>(buffer->data()) + offset; indices = static_cast<const GLubyte*>(buffer->data()) + offset;
} }
std::vector<GLsizei>* restartIndices = primitiveRestart ? new std::vector<GLsizei>() : nullptr;
computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex, restartIndices);
if(restartIndices && restartIndices->empty())
{
delete restartIndices;
restartIndices = nullptr;
}
StreamingIndexBuffer *streamingBuffer = mStreamingBuffer; StreamingIndexBuffer *streamingBuffer = mStreamingBuffer;
sw::Resource *staticBuffer = buffer ? buffer->getResource() : NULL; sw::Resource *staticBuffer = buffer ? buffer->getResource() : NULL;
if(staticBuffer) if(restartIndices)
{ {
computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex); int vertexPerPrimitive = recomputePrimitiveCount(mode, count, *restartIndices, &translated->primitiveCount);
if(vertexPerPrimitive == -1)
{
delete restartIndices;
return GL_INVALID_ENUM;
}
size_t streamOffset = 0;
int convertCount = translated->primitiveCount * vertexPerPrimitive;
streamingBuffer->reserveSpace(convertCount * typeSize(type), type);
void *output = streamingBuffer->map(typeSize(type) * convertCount, &streamOffset);
if(output == NULL)
{
delete restartIndices;
ERR("Failed to map index buffer.");
return GL_OUT_OF_MEMORY;
}
copyIndices(mode, type, *restartIndices, staticBuffer ? buffer->data() : indices, count, output);
streamingBuffer->unmap();
translated->indexBuffer = streamingBuffer->getResource();
translated->indexOffset = static_cast<unsigned int>(streamOffset);
delete restartIndices;
}
else if(staticBuffer)
{
translated->indexBuffer = staticBuffer; translated->indexBuffer = staticBuffer;
translated->indexOffset = static_cast<unsigned int>(offset); translated->indexOffset = static_cast<unsigned int>(offset);
} }
...@@ -137,11 +348,9 @@ GLenum IndexDataManager::prepareIndexData(GLenum type, GLuint start, GLuint end, ...@@ -137,11 +348,9 @@ GLenum IndexDataManager::prepareIndexData(GLenum type, GLuint start, GLuint end,
return GL_OUT_OF_MEMORY; return GL_OUT_OF_MEMORY;
} }
copyIndices(type, staticBuffer ? buffer->data() : indices, convertCount, output); copyIndices(type, indices, convertCount, output);
streamingBuffer->unmap(); streamingBuffer->unmap();
computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex);
translated->indexBuffer = streamingBuffer->getResource(); translated->indexBuffer = streamingBuffer->getResource();
translated->indexOffset = static_cast<unsigned int>(streamOffset); translated->indexOffset = static_cast<unsigned int>(streamOffset);
} }
......
...@@ -27,9 +27,12 @@ namespace es2 ...@@ -27,9 +27,12 @@ namespace es2
struct TranslatedIndexData struct TranslatedIndexData
{ {
TranslatedIndexData(unsigned int primitiveCount) : primitiveCount(primitiveCount) {}
unsigned int minIndex; unsigned int minIndex;
unsigned int maxIndex; unsigned int maxIndex;
unsigned int indexOffset; unsigned int indexOffset;
unsigned int primitiveCount;
sw::Resource *indexBuffer; sw::Resource *indexBuffer;
}; };
...@@ -58,7 +61,7 @@ public: ...@@ -58,7 +61,7 @@ public:
IndexDataManager(); IndexDataManager();
virtual ~IndexDataManager(); virtual ~IndexDataManager();
GLenum prepareIndexData(GLenum type, GLuint start, GLuint end, GLsizei count, Buffer *arrayElementBuffer, const void *indices, TranslatedIndexData *translated); GLenum prepareIndexData(GLenum mode, GLenum type, GLuint start, GLuint end, GLsizei count, Buffer *arrayElementBuffer, const void *indices, TranslatedIndexData *translated, bool primitiveRestart);
static std::size_t typeSize(GLenum type); static std::size_t typeSize(GLenum type);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment