Commit b4d557d6 by Alexis Hetu Committed by Alexis Hétu

Adding instanced drawing

- Added the ANGLE extension for instance drawing (GL_ANGLE_instanced_arrays) - VertexDataManager can now pull data either from the current attributes or from the VertexArray object Change-Id: Id0aa078bf9401e4f3f62594e90908fad98954051 Reviewed-on: https://swiftshader-review.googlesource.com/2946Reviewed-by: 's avatarNicolas Capens <capn@google.com> Tested-by: 's avatarAlexis Hétu <sugoi@google.com>
parent e501b8b1
...@@ -327,7 +327,6 @@ struct State ...@@ -327,7 +327,6 @@ struct State
unsigned int activeSampler; // Active texture unit selector - GL_TEXTURE0 unsigned int activeSampler; // Active texture unit selector - GL_TEXTURE0
gl::BindingPointer<Buffer> arrayBuffer; gl::BindingPointer<Buffer> arrayBuffer;
gl::BindingPointer<Buffer> elementArrayBuffer;
gl::BindingPointer<Buffer> copyReadBuffer; gl::BindingPointer<Buffer> copyReadBuffer;
gl::BindingPointer<Buffer> copyWriteBuffer; gl::BindingPointer<Buffer> copyWriteBuffer;
gl::BindingPointer<Buffer> pixelPackBuffer; gl::BindingPointer<Buffer> pixelPackBuffer;
...@@ -338,7 +337,7 @@ struct State ...@@ -338,7 +337,7 @@ struct State
GLuint drawFramebuffer; GLuint drawFramebuffer;
gl::BindingPointer<Renderbuffer> renderbuffer; gl::BindingPointer<Renderbuffer> renderbuffer;
GLuint currentProgram; GLuint currentProgram;
gl::BindingPointer<VertexArray> vertexArray; GLuint vertexArray;
GLuint transformFeedback; GLuint transformFeedback;
gl::BindingPointer<Sampler> sampler[MAX_COMBINED_TEXTURE_IMAGE_UNITS]; gl::BindingPointer<Sampler> sampler[MAX_COMBINED_TEXTURE_IMAGE_UNITS];
...@@ -440,7 +439,9 @@ public: ...@@ -440,7 +439,9 @@ public:
bool normalized, GLsizei stride, const void *pointer); bool normalized, GLsizei stride, const void *pointer);
const void *getVertexAttribPointer(unsigned int attribNum) const; const void *getVertexAttribPointer(unsigned int attribNum) const;
const VertexAttributeArray &getVertexAttributes(); const VertexAttributeArray &getVertexArrayAttributes();
// Context attribute current values can be queried independently from VAO current values
const VertexAttributeArray &getCurrentVertexAttributes();
void setUnpackAlignment(GLint alignment); void setUnpackAlignment(GLint alignment);
GLint getUnpackAlignment() const; GLint getUnpackAlignment() const;
...@@ -555,6 +556,8 @@ public: ...@@ -555,6 +556,8 @@ public:
bool getQueryParameterInfo(GLenum pname, GLenum *type, unsigned int *numParams) const; bool getQueryParameterInfo(GLenum pname, GLenum *type, unsigned int *numParams) const;
bool hasZeroDivisor() const;
void readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei *bufSize, void* pixels); void readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei *bufSize, void* pixels);
void clear(GLbitfield mask); void clear(GLbitfield mask);
void drawArrays(GLenum mode, GLint first, GLsizei count, GLsizei instanceCount = 1); void drawArrays(GLenum mode, GLint first, GLsizei count, GLsizei instanceCount = 1);
...@@ -589,7 +592,7 @@ private: ...@@ -589,7 +592,7 @@ private:
bool applyRenderTarget(); bool applyRenderTarget();
void applyState(GLenum drawMode); void applyState(GLenum drawMode);
GLenum applyVertexBuffer(GLint base, GLint first, GLsizei count); GLenum applyVertexBuffer(GLint base, GLint first, GLsizei count, GLsizei instanceId);
GLenum applyIndexBuffer(const void *indices, GLuint start, GLuint end, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo); GLenum applyIndexBuffer(const void *indices, GLuint start, GLuint end, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo);
void applyShaders(); void applyShaders();
void applyTextures(); void applyTextures();
......
...@@ -108,24 +108,27 @@ unsigned int VertexDataManager::writeAttributeData(StreamingVertexBuffer *vertex ...@@ -108,24 +108,27 @@ unsigned int VertexDataManager::writeAttributeData(StreamingVertexBuffer *vertex
return streamOffset; return streamOffset;
} }
GLenum VertexDataManager::prepareVertexData(GLint start, GLsizei count, TranslatedAttribute *translated) GLenum VertexDataManager::prepareVertexData(GLint start, GLsizei count, TranslatedAttribute *translated, GLsizei instanceId)
{ {
if(!mStreamingBuffer) if(!mStreamingBuffer)
{ {
return GL_OUT_OF_MEMORY; return GL_OUT_OF_MEMORY;
} }
const VertexAttributeArray &attribs = mContext->getVertexAttributes(); const VertexAttributeArray &attribs = mContext->getVertexArrayAttributes();
const VertexAttributeArray &currentAttribs = mContext->getCurrentVertexAttributes();
Program *program = mContext->getCurrentProgram(); Program *program = mContext->getCurrentProgram();
// Determine the required storage size per used buffer // Determine the required storage size per used buffer
for(int i = 0; i < MAX_VERTEX_ATTRIBS; i++) for(int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
{ {
if(program->getAttributeStream(i) != -1 && attribs[i].mArrayEnabled) const VertexAttribute &attrib = attribs[i].mArrayEnabled ? attribs[i] : currentAttribs[i];
if(program->getAttributeStream(i) != -1 && attrib.mArrayEnabled)
{ {
if(!attribs[i].mBoundBuffer) if(!attrib.mBoundBuffer)
{ {
mStreamingBuffer->addRequiredSpace(attribs[i].typeSize() * count); mStreamingBuffer->addRequiredSpace(attrib.typeSize() * count);
} }
} }
} }
...@@ -137,11 +140,18 @@ GLenum VertexDataManager::prepareVertexData(GLint start, GLsizei count, Translat ...@@ -137,11 +140,18 @@ GLenum VertexDataManager::prepareVertexData(GLint start, GLsizei count, Translat
{ {
if(program->getAttributeStream(i) != -1) if(program->getAttributeStream(i) != -1)
{ {
if(attribs[i].mArrayEnabled) const VertexAttribute &attrib = attribs[i].mArrayEnabled ? attribs[i] : currentAttribs[i];
if(attrib.mArrayEnabled)
{ {
Buffer *buffer = attribs[i].mBoundBuffer; const bool isInstanced = attrib.mDivisor > 0;
// Instanced vertices do not apply the 'start' offset
GLint firstVertexIndex = isInstanced ? instanceId / attrib.mDivisor : start;
Buffer *buffer = attrib.mBoundBuffer;
if(!buffer && attribs[i].mPointer == NULL) if(!buffer && attrib.mPointer == NULL)
{ {
// This is an application error that would normally result in a crash, but we catch it and return an error // 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."); ERR("An enabled vertex array has no buffer and no pointer.");
...@@ -153,12 +163,12 @@ GLenum VertexDataManager::prepareVertexData(GLint start, GLsizei count, Translat ...@@ -153,12 +163,12 @@ GLenum VertexDataManager::prepareVertexData(GLint start, GLsizei count, Translat
if(staticBuffer) if(staticBuffer)
{ {
translated[i].vertexBuffer = staticBuffer; translated[i].vertexBuffer = staticBuffer;
translated[i].offset = start * attribs[i].stride() + attribs[i].mOffset; translated[i].offset = firstVertexIndex * attrib.stride() + attrib.mOffset;
translated[i].stride = attribs[i].stride(); translated[i].stride = isInstanced ? 0 : attrib.stride();
} }
else else
{ {
unsigned int streamOffset = writeAttributeData(mStreamingBuffer, start, count, attribs[i]); unsigned int streamOffset = writeAttributeData(mStreamingBuffer, firstVertexIndex, count, attrib);
if(streamOffset == -1) if(streamOffset == -1)
{ {
...@@ -167,10 +177,10 @@ GLenum VertexDataManager::prepareVertexData(GLint start, GLsizei count, Translat ...@@ -167,10 +177,10 @@ GLenum VertexDataManager::prepareVertexData(GLint start, GLsizei count, Translat
translated[i].vertexBuffer = mStreamingBuffer->getResource(); translated[i].vertexBuffer = mStreamingBuffer->getResource();
translated[i].offset = streamOffset; translated[i].offset = streamOffset;
translated[i].stride = attribs[i].typeSize(); translated[i].stride = isInstanced ? 0 : attrib.typeSize();
} }
switch(attribs[i].mType) switch(attrib.mType)
{ {
case GL_BYTE: translated[i].type = sw::STREAMTYPE_SBYTE; break; case GL_BYTE: translated[i].type = sw::STREAMTYPE_SBYTE; break;
case GL_UNSIGNED_BYTE: translated[i].type = sw::STREAMTYPE_BYTE; break; case GL_UNSIGNED_BYTE: translated[i].type = sw::STREAMTYPE_BYTE; break;
...@@ -181,15 +191,15 @@ GLenum VertexDataManager::prepareVertexData(GLint start, GLsizei count, Translat ...@@ -181,15 +191,15 @@ GLenum VertexDataManager::prepareVertexData(GLint start, GLsizei count, Translat
default: UNREACHABLE(); translated[i].type = sw::STREAMTYPE_FLOAT; break; default: UNREACHABLE(); translated[i].type = sw::STREAMTYPE_FLOAT; break;
} }
translated[i].count = attribs[i].mSize; translated[i].count = attrib.mSize;
translated[i].normalized = attribs[i].mNormalized; translated[i].normalized = attrib.mNormalized;
} }
else else
{ {
if(mDirtyCurrentValue[i]) if(mDirtyCurrentValue[i])
{ {
delete mCurrentValueBuffer[i]; delete mCurrentValueBuffer[i];
mCurrentValueBuffer[i] = new ConstantVertexBuffer(attribs[i].getCurrentValue(0), attribs[i].getCurrentValue(1), attribs[i].getCurrentValue(2), attribs[i].getCurrentValue(3)); mCurrentValueBuffer[i] = new ConstantVertexBuffer(attrib.getCurrentValue(0), attrib.getCurrentValue(1), attrib.getCurrentValue(2), attrib.getCurrentValue(3));
mDirtyCurrentValue[i] = false; mDirtyCurrentValue[i] = false;
} }
......
...@@ -81,7 +81,7 @@ class VertexDataManager ...@@ -81,7 +81,7 @@ class VertexDataManager
void dirtyCurrentValue(int index) { mDirtyCurrentValue[index] = true; } void dirtyCurrentValue(int index) { mDirtyCurrentValue[index] = true; }
GLenum prepareVertexData(GLint start, GLsizei count, TranslatedAttribute *outAttribs); GLenum prepareVertexData(GLint start, GLsizei count, TranslatedAttribute *outAttribs, GLsizei instanceId);
private: private:
unsigned int writeAttributeData(StreamingVertexBuffer *vertexBuffer, GLint start, GLsizei count, const VertexAttribute &attribute); unsigned int writeAttributeData(StreamingVertexBuffer *vertexBuffer, GLint start, GLsizei count, const VertexAttribute &attribute);
......
...@@ -1938,6 +1938,119 @@ void GL_APIENTRY glVertexAttribDivisorEXT(GLuint index, GLuint divisor) ...@@ -1938,6 +1938,119 @@ void GL_APIENTRY glVertexAttribDivisorEXT(GLuint index, GLuint divisor)
} }
} }
void GL_APIENTRY glDrawArraysInstancedANGLE(GLenum mode, GLint first, GLsizei count, GLsizei instanceCount)
{
TRACE("(GLenum mode = 0x%X, GLint first = %d, GLsizei count = %d, GLsizei instanceCount = %d)",
mode, first, count, instanceCount);
switch(mode)
{
case GL_POINTS:
case GL_LINES:
case GL_LINE_LOOP:
case GL_LINE_STRIP:
case GL_TRIANGLES:
case GL_TRIANGLE_FAN:
case GL_TRIANGLE_STRIP:
break;
default:
return error(GL_INVALID_ENUM);
}
if(count < 0 || instanceCount < 0)
{
return error(GL_INVALID_VALUE);
}
es2::Context *context = es2::getContext();
if(context)
{
if(!context->hasZeroDivisor())
{
return error(GL_INVALID_OPERATION);
}
es2::TransformFeedback* transformFeedback = context->getTransformFeedback();
if(transformFeedback && transformFeedback->isActive() && (mode != transformFeedback->primitiveMode()))
{
return error(GL_INVALID_OPERATION);
}
context->drawArrays(mode, first, count, instanceCount);
}
}
void GL_APIENTRY glDrawElementsInstancedANGLE(GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instanceCount)
{
TRACE("(GLenum mode = 0x%X, GLsizei count = %d, GLenum type = 0x%X, const void *indices = 0x%0.8p, GLsizei instanceCount = %d)",
mode, count, type, indices, instanceCount);
switch(mode)
{
case GL_POINTS:
case GL_LINES:
case GL_LINE_LOOP:
case GL_LINE_STRIP:
case GL_TRIANGLES:
case GL_TRIANGLE_FAN:
case GL_TRIANGLE_STRIP:
break;
default:
return error(GL_INVALID_ENUM);
}
switch(type)
{
case GL_UNSIGNED_BYTE:
case GL_UNSIGNED_SHORT:
case GL_UNSIGNED_INT:
break;
default:
return error(GL_INVALID_ENUM);
}
if(count < 0 || instanceCount < 0)
{
return error(GL_INVALID_VALUE);
}
es2::Context *context = es2::getContext();
if(context)
{
if(!context->hasZeroDivisor())
{
return error(GL_INVALID_OPERATION);
}
es2::TransformFeedback* transformFeedback = context->getTransformFeedback();
if(transformFeedback && transformFeedback->isActive() && !transformFeedback->isPaused())
{
return error(GL_INVALID_OPERATION);
}
context->drawElements(mode, 0, UINT_MAX, count, type, indices, instanceCount);
}
}
void GL_APIENTRY glVertexAttribDivisorANGLE(GLuint index, GLuint divisor)
{
TRACE("(GLuint index = %d, GLuint divisor = %d)", index, divisor);
es2::Context *context = es2::getContext();
if(context)
{
if(index >= MAX_VERTEX_ATTRIBS)
{
return error(GL_INVALID_VALUE);
}
context->setVertexAttribDivisor(index, divisor);
}
}
void GL_APIENTRY glEnable(GLenum cap) void GL_APIENTRY glEnable(GLenum cap)
{ {
TRACE("(GLenum cap = 0x%X)", cap); TRACE("(GLenum cap = 0x%X)", cap);
...@@ -3758,9 +3871,12 @@ void GL_APIENTRY glGetVertexAttribfv(GLuint index, GLenum pname, GLfloat* params ...@@ -3758,9 +3871,12 @@ void GL_APIENTRY glGetVertexAttribfv(GLuint index, GLenum pname, GLfloat* params
*params = (GLfloat)attribState.mBoundBuffer.name(); *params = (GLfloat)attribState.mBoundBuffer.name();
break; break;
case GL_CURRENT_VERTEX_ATTRIB: case GL_CURRENT_VERTEX_ATTRIB:
for(int i = 0; i < 4; ++i)
{ {
params[i] = attribState.getCurrentValue(i); const VertexAttribute& attrib = context->getCurrentVertexAttributes()[index];
for(int i = 0; i < 4; ++i)
{
params[i] = attrib.getCurrentValue(i);
}
} }
break; break;
case GL_VERTEX_ATTRIB_ARRAY_INTEGER: case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
...@@ -3828,10 +3944,13 @@ void GL_APIENTRY glGetVertexAttribiv(GLuint index, GLenum pname, GLint* params) ...@@ -3828,10 +3944,13 @@ void GL_APIENTRY glGetVertexAttribiv(GLuint index, GLenum pname, GLint* params)
*params = attribState.mBoundBuffer.name(); *params = attribState.mBoundBuffer.name();
break; break;
case GL_CURRENT_VERTEX_ATTRIB: case GL_CURRENT_VERTEX_ATTRIB:
for(int i = 0; i < 4; ++i)
{ {
float currentValue = attribState.getCurrentValue(i); const VertexAttribute& attrib = context->getCurrentVertexAttributes()[index];
params[i] = (GLint)(currentValue > 0.0f ? floor(currentValue + 0.5f) : ceil(currentValue - 0.5f)); for(int i = 0; i < 4; ++i)
{
float currentValue = attrib.getCurrentValue(i);
params[i] = (GLint)(currentValue > 0.0f ? floor(currentValue + 0.5f) : ceil(currentValue - 0.5f));
}
} }
break; break;
case GL_VERTEX_ATTRIB_ARRAY_INTEGER: case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
...@@ -6896,6 +7015,9 @@ __eglMustCastToProperFunctionPointerType es2GetProcAddress(const char *procname) ...@@ -6896,6 +7015,9 @@ __eglMustCastToProperFunctionPointerType es2GetProcAddress(const char *procname)
EXTENSION(glDrawElementsInstancedEXT), EXTENSION(glDrawElementsInstancedEXT),
EXTENSION(glDrawArraysInstancedEXT), EXTENSION(glDrawArraysInstancedEXT),
EXTENSION(glVertexAttribDivisorEXT), EXTENSION(glVertexAttribDivisorEXT),
EXTENSION(glDrawArraysInstancedANGLE),
EXTENSION(glDrawElementsInstancedANGLE),
EXTENSION(glVertexAttribDivisorANGLE),
#undef EXTENSION #undef EXTENSION
}; };
......
...@@ -1912,9 +1912,12 @@ void GL_APIENTRY glGetVertexAttribIiv(GLuint index, GLenum pname, GLint *params) ...@@ -1912,9 +1912,12 @@ void GL_APIENTRY glGetVertexAttribIiv(GLuint index, GLenum pname, GLint *params)
*params = attribState.mBoundBuffer.name(); *params = attribState.mBoundBuffer.name();
break; break;
case GL_CURRENT_VERTEX_ATTRIB: case GL_CURRENT_VERTEX_ATTRIB:
for(int i = 0; i < 4; ++i)
{ {
params[i] = attribState.getCurrentValueI(i); const VertexAttribute& attrib = context->getCurrentVertexAttributes()[index];
for(int i = 0; i < 4; ++i)
{
params[i] = attrib.getCurrentValueI(i);
}
} }
break; break;
case GL_VERTEX_ATTRIB_ARRAY_INTEGER: case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
...@@ -1980,9 +1983,12 @@ void GL_APIENTRY glGetVertexAttribIuiv(GLuint index, GLenum pname, GLuint *param ...@@ -1980,9 +1983,12 @@ void GL_APIENTRY glGetVertexAttribIuiv(GLuint index, GLenum pname, GLuint *param
*params = attribState.mBoundBuffer.name(); *params = attribState.mBoundBuffer.name();
break; break;
case GL_CURRENT_VERTEX_ATTRIB: case GL_CURRENT_VERTEX_ATTRIB:
for(int i = 0; i < 4; ++i)
{ {
params[i] = attribState.getCurrentValueUI(i); const VertexAttribute& attrib = context->getCurrentVertexAttributes()[index];
for(int i = 0; i < 4; ++i)
{
params[i] = attrib.getCurrentValueUI(i);
}
} }
break; break;
case GL_VERTEX_ATTRIB_ARRAY_INTEGER: case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
......
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