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
......@@ -146,6 +146,7 @@ Context::Context(const egl::Config *config, const Context *shareContext, EGLint
mTextureExternalZero = new TextureExternal(0);
mState.activeSampler = 0;
bindVertexArray(0);
bindArrayBuffer(0);
bindElementArrayBuffer(0);
bindTextureCubeMap(0);
......@@ -235,7 +236,6 @@ Context::~Context()
}
mState.arrayBuffer = NULL;
mState.elementArrayBuffer = NULL;
mState.copyReadBuffer = NULL;
mState.copyWriteBuffer = NULL;
mState.pixelPackBuffer = NULL;
......@@ -243,7 +243,6 @@ Context::~Context()
mState.uniformBuffer = NULL;
mState.renderbuffer = NULL;
mState.vertexArray = NULL;
for(int i = 0; i < MAX_COMBINED_TEXTURE_IMAGE_UNITS; ++i)
{
mState.sampler[i] = NULL;
......@@ -752,38 +751,38 @@ GLuint Context::getActiveQuery(GLenum target) const
void Context::setEnableVertexAttribArray(unsigned int attribNum, bool enabled)
{
mState.vertexAttribute[attribNum].mArrayEnabled = enabled;
getCurrentVertexArray()->enableAttribute(attribNum, enabled);
}
void Context::setVertexAttribDivisor(unsigned int attribNum, GLuint divisor)
{
mState.vertexAttribute[attribNum].mDivisor = divisor;
getCurrentVertexArray()->setVertexAttribDivisor(attribNum, divisor);
}
const VertexAttribute &Context::getVertexAttribState(unsigned int attribNum) const
{
return mState.vertexAttribute[attribNum];
return getCurrentVertexArray()->getVertexAttribute(attribNum);
}
void Context::setVertexAttribState(unsigned int attribNum, Buffer *boundBuffer, GLint size, GLenum type, bool normalized,
GLsizei stride, const void *pointer)
{
mState.vertexAttribute[attribNum].mBoundBuffer = boundBuffer;
mState.vertexAttribute[attribNum].mSize = size;
mState.vertexAttribute[attribNum].mType = type;
mState.vertexAttribute[attribNum].mNormalized = normalized;
mState.vertexAttribute[attribNum].mStride = stride;
mState.vertexAttribute[attribNum].mPointer = pointer;
getCurrentVertexArray()->setAttributeState(attribNum, boundBuffer, size, type, normalized, stride, pointer);
}
const void *Context::getVertexAttribPointer(unsigned int attribNum) const
{
return mState.vertexAttribute[attribNum].mPointer;
return getCurrentVertexArray()->getVertexAttribute(attribNum).mPointer;
}
const VertexAttributeArray &Context::getVertexAttributes()
const VertexAttributeArray &Context::getVertexArrayAttributes()
{
return mState.vertexAttribute;
return getCurrentVertexArray()->getVertexAttributes();
}
const VertexAttributeArray &Context::getCurrentVertexAttributes()
{
return mState.vertexAttribute;
}
void Context::setPackAlignment(GLint alignment)
......@@ -979,13 +978,20 @@ void Context::deleteVertexArray(GLuint vertexArray)
if(vertexArrayObject != mVertexArrayMap.end())
{
mVertexArrayNameSpace.release(vertexArrayObject->first);
if(vertexArrayObject->second)
// Vertex array detachment is handled by Context, because 0 is a valid
// VAO, and a pointer to it must be passed from Context to State at
// binding time.
// [OpenGL ES 3.0.2] section 2.10 page 43:
// If a vertex array object that is currently bound is deleted, the binding
// for that object reverts to zero and the default vertex array becomes current.
if(getCurrentVertexArray()->name == vertexArray)
{
vertexArrayObject->second->release();
bindVertexArray(0);
}
mVertexArrayNameSpace.release(vertexArrayObject->first);
delete vertexArrayObject->second;
mVertexArrayMap.erase(vertexArrayObject);
}
}
......@@ -1065,7 +1071,7 @@ void Context::bindElementArrayBuffer(unsigned int buffer)
{
mResourceManager->checkBufferAllocation(buffer);
mState.elementArrayBuffer = getBuffer(buffer);
getCurrentVertexArray()->setElementArrayBuffer(getBuffer(buffer));
}
void Context::bindCopyReadBuffer(GLuint buffer)
......@@ -1172,11 +1178,14 @@ bool Context::bindVertexArray(GLuint array)
{
VertexArray* vertexArray = getVertexArray(array);
if(vertexArray)
if(!vertexArray)
{
mState.vertexArray = vertexArray;
vertexArray = new VertexArray(array);
mVertexArrayMap[array] = vertexArray;
}
mState.vertexArray = array;
return !!vertexArray;
}
......@@ -1394,6 +1403,27 @@ VertexArray *Context::getVertexArray(GLuint array) const
return (vertexArray == mVertexArrayMap.end()) ? NULL : vertexArray->second;
}
VertexArray *Context::getCurrentVertexArray() const
{
return getVertexArray(mState.vertexArray);
}
bool Context::hasZeroDivisor() const
{
// Verify there is at least one active attribute with a divisor of zero
es2::Program *programObject = getCurrentProgram();
for(int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
{
bool active = (programObject->getAttributeStream(attributeIndex) != -1);
if(active && getCurrentVertexArray()->getVertexAttribute(attributeIndex).mDivisor == 0)
{
return true;
}
}
return false;
}
TransformFeedback *Context::getTransformFeedback(GLuint transformFeedback) const
{
TransformFeedbackMap::const_iterator transformFeedbackObject = mTransformFeedbackMap.find(transformFeedback);
......@@ -1415,7 +1445,7 @@ Buffer *Context::getArrayBuffer() const
Buffer *Context::getElementArrayBuffer() const
{
return mState.elementArrayBuffer;
return getCurrentVertexArray()->getElementArrayBuffer();
}
Buffer *Context::getCopyReadBuffer() const
......@@ -1668,8 +1698,8 @@ bool Context::getIntegerv(GLenum pname, GLint *params) const
case GL_MAX_RENDERBUFFER_SIZE: *params = IMPLEMENTATION_MAX_RENDERBUFFER_SIZE; break;
case GL_NUM_SHADER_BINARY_FORMATS: *params = 0; break;
case GL_SHADER_BINARY_FORMATS: /* no shader binary formats are supported */ break;
case GL_ARRAY_BUFFER_BINDING: *params = mState.arrayBuffer.name(); break;
case GL_ELEMENT_ARRAY_BUFFER_BINDING: *params = mState.elementArrayBuffer.name(); break;
case GL_ARRAY_BUFFER_BINDING: *params = getArrayBufferName(); break;
case GL_ELEMENT_ARRAY_BUFFER_BINDING: *params = getCurrentVertexArray()->getElementArrayBuffer()->name; break;
// case GL_FRAMEBUFFER_BINDING: // now equivalent to GL_DRAW_FRAMEBUFFER_BINDING_ANGLE
case GL_DRAW_FRAMEBUFFER_BINDING_ANGLE: *params = mState.drawFramebuffer; break;
case GL_READ_FRAMEBUFFER_BINDING_ANGLE: *params = mState.readFramebuffer; break;
......@@ -2682,11 +2712,11 @@ void Context::applyState(GLenum drawMode)
}
}
GLenum Context::applyVertexBuffer(GLint base, GLint first, GLsizei count)
GLenum Context::applyVertexBuffer(GLint base, GLint first, GLsizei count, GLsizei instanceId)
{
TranslatedAttribute attributes[MAX_VERTEX_ATTRIBS];
GLenum err = mVertexDataManager->prepareVertexData(first, count, attributes);
GLenum err = mVertexDataManager->prepareVertexData(first, count, attributes, instanceId);
if(err != GL_NO_ERROR)
{
return err;
......@@ -2726,7 +2756,7 @@ GLenum Context::applyVertexBuffer(GLint base, GLint first, GLsizei count)
// 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 err = mIndexDataManager->prepareIndexData(type, start, end, count, mState.elementArrayBuffer, indices, indexInfo);
GLenum err = mIndexDataManager->prepareIndexData(type, start, end, count, getCurrentVertexArray()->getElementArrayBuffer(), indices, indexInfo);
if(err == GL_NO_ERROR)
{
......@@ -3289,24 +3319,27 @@ void Context::drawArrays(GLenum mode, GLint first, GLsizei count, GLsizei instan
applyState(mode);
GLenum err = applyVertexBuffer(0, first, count);
if(err != GL_NO_ERROR)
{
return error(err);
}
for(int i = 0; i < instanceCount; ++i)
{
GLenum err = applyVertexBuffer(0, first, count, i);
if(err != GL_NO_ERROR)
{
return error(err);
}
applyShaders();
applyTextures();
applyShaders();
applyTextures();
if(!getCurrentProgram()->validateSamplers(false))
{
return error(GL_INVALID_OPERATION);
}
if(!getCurrentProgram()->validateSamplers(false))
{
return error(GL_INVALID_OPERATION);
}
if(!cullSkipsDraw(mode))
{
device->drawPrimitive(primitiveType, primitiveCount);
}
if(!cullSkipsDraw(mode))
{
device->drawPrimitive(primitiveType, primitiveCount);
}
}
}
void Context::drawElements(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices, GLsizei instanceCount)
......@@ -3316,7 +3349,7 @@ void Context::drawElements(GLenum mode, GLuint start, GLuint end, GLsizei count,
return error(GL_INVALID_OPERATION);
}
if(!indices && !mState.elementArrayBuffer)
if(!indices && !getCurrentVertexArray()->getElementArrayBuffer())
{
return error(GL_INVALID_OPERATION);
}
......@@ -3339,32 +3372,35 @@ void Context::drawElements(GLenum mode, GLuint start, GLuint end, GLsizei count,
applyState(mode);
TranslatedIndexData indexInfo;
GLenum err = applyIndexBuffer(indices, start, end, count, mode, type, &indexInfo);
if(err != GL_NO_ERROR)
{
return error(err);
}
for(int i = 0; i < instanceCount; ++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;
err = applyVertexBuffer(-(int)indexInfo.minIndex, indexInfo.minIndex, vertexCount);
if(err != GL_NO_ERROR)
{
return error(err);
}
GLsizei vertexCount = indexInfo.maxIndex - indexInfo.minIndex + 1;
err = applyVertexBuffer(-(int)indexInfo.minIndex, indexInfo.minIndex, vertexCount, i);
if(err != GL_NO_ERROR)
{
return error(err);
}
applyShaders();
applyTextures();
applyShaders();
applyTextures();
if(!getCurrentProgram()->validateSamplers(false))
{
return error(GL_INVALID_OPERATION);
}
if(!getCurrentProgram()->validateSamplers(false))
{
return error(GL_INVALID_OPERATION);
}
if(!cullSkipsDraw(mode))
{
device->drawIndexedPrimitive(primitiveType, indexInfo.indexOffset, primitiveCount, IndexDataManager::typeSize(type));
}
if(!cullSkipsDraw(mode))
{
device->drawIndexedPrimitive(primitiveType, indexInfo.indexOffset, primitiveCount, IndexDataManager::typeSize(type));
}
}
}
void Context::finish()
......@@ -3465,15 +3501,15 @@ void Context::detachBuffer(GLuint buffer)
// If a buffer object is deleted while it is bound, all bindings to that object in the current context
// (i.e. in the thread that called Delete-Buffers) are reset to zero.
if(mState.arrayBuffer.name() == buffer)
if(getArrayBufferName() == buffer)
{
mState.arrayBuffer = NULL;
}
if(mState.elementArrayBuffer.name() == buffer)
{
mState.elementArrayBuffer = NULL;
}
for(auto vaoIt = mVertexArrayMap.begin(); vaoIt != mVertexArrayMap.end(); vaoIt++)
{
vaoIt->second->detachBuffer(buffer);
}
for(int attribute = 0; attribute < MAX_VERTEX_ATTRIBS; attribute++)
{
......@@ -4081,6 +4117,7 @@ const GLubyte* Context::getExtensions(GLuint index, GLuint* numExt) const
#endif
(const GLubyte*)"GL_NV_fence",
(const GLubyte*)"GL_EXT_instanced_arrays",
(const GLubyte*)"GL_ANGLE_instanced_arrays",
};
static const GLuint numExtensions = sizeof(extensions) / sizeof(*extensions);
......
......@@ -327,7 +327,6 @@ struct State
unsigned int activeSampler; // Active texture unit selector - GL_TEXTURE0
gl::BindingPointer<Buffer> arrayBuffer;
gl::BindingPointer<Buffer> elementArrayBuffer;
gl::BindingPointer<Buffer> copyReadBuffer;
gl::BindingPointer<Buffer> copyWriteBuffer;
gl::BindingPointer<Buffer> pixelPackBuffer;
......@@ -338,7 +337,7 @@ struct State
GLuint drawFramebuffer;
gl::BindingPointer<Renderbuffer> renderbuffer;
GLuint currentProgram;
gl::BindingPointer<VertexArray> vertexArray;
GLuint vertexArray;
GLuint transformFeedback;
gl::BindingPointer<Sampler> sampler[MAX_COMBINED_TEXTURE_IMAGE_UNITS];
......@@ -440,7 +439,9 @@ public:
bool normalized, GLsizei stride, const void *pointer);
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);
GLint getUnpackAlignment() const;
......@@ -555,6 +556,8 @@ public:
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 clear(GLbitfield mask);
void drawArrays(GLenum mode, GLint first, GLsizei count, GLsizei instanceCount = 1);
......@@ -589,7 +592,7 @@ private:
bool applyRenderTarget();
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);
void applyShaders();
void applyTextures();
......
......@@ -108,24 +108,27 @@ unsigned int VertexDataManager::writeAttributeData(StreamingVertexBuffer *vertex
return streamOffset;
}
GLenum VertexDataManager::prepareVertexData(GLint start, GLsizei count, TranslatedAttribute *translated)
GLenum VertexDataManager::prepareVertexData(GLint start, GLsizei count, TranslatedAttribute *translated, GLsizei instanceId)
{
if(!mStreamingBuffer)
{
return GL_OUT_OF_MEMORY;
}
const VertexAttributeArray &attribs = mContext->getVertexAttributes();
const VertexAttributeArray &attribs = mContext->getVertexArrayAttributes();
const VertexAttributeArray &currentAttribs = mContext->getCurrentVertexAttributes();
Program *program = mContext->getCurrentProgram();
// Determine the required storage size per used buffer
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
{
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
ERR("An enabled vertex array has no buffer and no pointer.");
......@@ -153,12 +163,12 @@ GLenum VertexDataManager::prepareVertexData(GLint start, GLsizei count, Translat
if(staticBuffer)
{
translated[i].vertexBuffer = staticBuffer;
translated[i].offset = start * attribs[i].stride() + attribs[i].mOffset;
translated[i].stride = attribs[i].stride();
translated[i].offset = firstVertexIndex * attrib.stride() + attrib.mOffset;
translated[i].stride = isInstanced ? 0 : attrib.stride();
}
else
{
unsigned int streamOffset = writeAttributeData(mStreamingBuffer, start, count, attribs[i]);
unsigned int streamOffset = writeAttributeData(mStreamingBuffer, firstVertexIndex, count, attrib);
if(streamOffset == -1)
{
......@@ -167,10 +177,10 @@ GLenum VertexDataManager::prepareVertexData(GLint start, GLsizei count, Translat
translated[i].vertexBuffer = mStreamingBuffer->getResource();
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_UNSIGNED_BYTE: translated[i].type = sw::STREAMTYPE_BYTE; break;
......@@ -181,15 +191,15 @@ GLenum VertexDataManager::prepareVertexData(GLint start, GLsizei count, Translat
default: UNREACHABLE(); translated[i].type = sw::STREAMTYPE_FLOAT; break;
}
translated[i].count = attribs[i].mSize;
translated[i].normalized = attribs[i].mNormalized;
translated[i].count = attrib.mSize;
translated[i].normalized = attrib.mNormalized;
}
else
{
if(mDirtyCurrentValue[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;
}
......
......@@ -81,7 +81,7 @@ class VertexDataManager
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:
unsigned int writeAttributeData(StreamingVertexBuffer *vertexBuffer, GLint start, GLsizei count, const VertexAttribute &attribute);
......
......@@ -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)
{
TRACE("(GLenum cap = 0x%X)", cap);
......@@ -3758,9 +3871,12 @@ void GL_APIENTRY glGetVertexAttribfv(GLuint index, GLenum pname, GLfloat* params
*params = (GLfloat)attribState.mBoundBuffer.name();
break;
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;
case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
......@@ -3828,10 +3944,13 @@ void GL_APIENTRY glGetVertexAttribiv(GLuint index, GLenum pname, GLint* params)
*params = attribState.mBoundBuffer.name();
break;
case GL_CURRENT_VERTEX_ATTRIB:
for(int i = 0; i < 4; ++i)
{
float currentValue = attribState.getCurrentValue(i);
params[i] = (GLint)(currentValue > 0.0f ? floor(currentValue + 0.5f) : ceil(currentValue - 0.5f));
const VertexAttribute& attrib = context->getCurrentVertexAttributes()[index];
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;
case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
......@@ -6896,6 +7015,9 @@ __eglMustCastToProperFunctionPointerType es2GetProcAddress(const char *procname)
EXTENSION(glDrawElementsInstancedEXT),
EXTENSION(glDrawArraysInstancedEXT),
EXTENSION(glVertexAttribDivisorEXT),
EXTENSION(glDrawArraysInstancedANGLE),
EXTENSION(glDrawElementsInstancedANGLE),
EXTENSION(glVertexAttribDivisorANGLE),
#undef EXTENSION
};
......
......@@ -1912,9 +1912,12 @@ void GL_APIENTRY glGetVertexAttribIiv(GLuint index, GLenum pname, GLint *params)
*params = attribState.mBoundBuffer.name();
break;
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;
case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
......@@ -1980,9 +1983,12 @@ void GL_APIENTRY glGetVertexAttribIuiv(GLuint index, GLenum pname, GLuint *param
*params = attribState.mBoundBuffer.name();
break;
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;
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