Commit dc358af7 by Jamie Madill Committed by Commit Bot

Context: Cache attributes masks.

This cache is updated in the following locations: 1. GLES1: clientActiveTexture. 2. GLES1: disableClientState/enableClientState. 3. Context: linkProgram/useProgram/programBinary. 4. Context: bindVertexArray. 5. Vertex Array: most state changes. Improves performance by about 6% in the GL no-op test. Also includes fixes for keeping the client memory attribs mask in sync. The cache also includes a boolean if there are any enabled client attributes. Bug: angleproject:1391 Change-Id: I93b6a2c8492355958fd5483f14b70535729091d6 Reviewed-on: https://chromium-review.googlesource.com/1147437 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org>
parent 97f45b7b
...@@ -1096,6 +1096,7 @@ void Context::bindVertexArray(GLuint vertexArrayHandle) ...@@ -1096,6 +1096,7 @@ void Context::bindVertexArray(GLuint vertexArrayHandle)
{ {
VertexArray *vertexArray = checkVertexArrayAllocation(vertexArrayHandle); VertexArray *vertexArray = checkVertexArrayAllocation(vertexArrayHandle);
mGLState.setVertexArrayBinding(this, vertexArray); mGLState.setVertexArrayBinding(this, vertexArray);
mStateCache.updateActiveAttribsMask(this);
} }
void Context::bindVertexBuffer(GLuint bindingIndex, void Context::bindVertexBuffer(GLuint bindingIndex,
...@@ -1105,6 +1106,7 @@ void Context::bindVertexBuffer(GLuint bindingIndex, ...@@ -1105,6 +1106,7 @@ void Context::bindVertexBuffer(GLuint bindingIndex,
{ {
Buffer *buffer = mState.mBuffers->checkBufferAllocation(mImplementation.get(), bufferHandle); Buffer *buffer = mState.mBuffers->checkBufferAllocation(mImplementation.get(), bufferHandle);
mGLState.bindVertexBuffer(this, bindingIndex, buffer, offset, stride); mGLState.bindVertexBuffer(this, bindingIndex, buffer, offset, stride);
mStateCache.updateActiveAttribsMask(this);
} }
void Context::bindSampler(GLuint textureUnit, GLuint samplerHandle) void Context::bindSampler(GLuint textureUnit, GLuint samplerHandle)
...@@ -1130,6 +1132,7 @@ void Context::bindImageTexture(GLuint unit, ...@@ -1130,6 +1132,7 @@ void Context::bindImageTexture(GLuint unit,
void Context::useProgram(GLuint program) void Context::useProgram(GLuint program)
{ {
mGLState.setProgram(this, getProgram(program)); mGLState.setProgram(this, getProgram(program));
mStateCache.updateActiveAttribsMask(this);
} }
void Context::useProgramStages(GLuint pipeline, GLbitfield stages, GLuint program) void Context::useProgramStages(GLuint pipeline, GLbitfield stages, GLuint program)
...@@ -2783,6 +2786,7 @@ void Context::detachProgramPipeline(GLuint pipeline) ...@@ -2783,6 +2786,7 @@ void Context::detachProgramPipeline(GLuint pipeline)
void Context::vertexAttribDivisor(GLuint index, GLuint divisor) void Context::vertexAttribDivisor(GLuint index, GLuint divisor)
{ {
mGLState.setVertexAttribDivisor(this, index, divisor); mGLState.setVertexAttribDivisor(this, index, divisor);
mStateCache.updateActiveAttribsMask(this);
} }
void Context::samplerParameteri(GLuint sampler, GLenum pname, GLint param) void Context::samplerParameteri(GLuint sampler, GLenum pname, GLint param)
...@@ -4389,6 +4393,7 @@ void Context::disable(GLenum cap) ...@@ -4389,6 +4393,7 @@ void Context::disable(GLenum cap)
void Context::disableVertexAttribArray(GLuint index) void Context::disableVertexAttribArray(GLuint index)
{ {
mGLState.setEnableVertexAttribArray(index, false); mGLState.setEnableVertexAttribArray(index, false);
mStateCache.updateActiveAttribsMask(this);
} }
void Context::enable(GLenum cap) void Context::enable(GLenum cap)
...@@ -4399,6 +4404,7 @@ void Context::enable(GLenum cap) ...@@ -4399,6 +4404,7 @@ void Context::enable(GLenum cap)
void Context::enableVertexAttribArray(GLuint index) void Context::enableVertexAttribArray(GLuint index)
{ {
mGLState.setEnableVertexAttribArray(index, true); mGLState.setEnableVertexAttribArray(index, true);
mStateCache.updateActiveAttribsMask(this);
} }
void Context::frontFace(GLenum mode) void Context::frontFace(GLenum mode)
...@@ -4606,6 +4612,7 @@ void Context::vertexAttribPointer(GLuint index, ...@@ -4606,6 +4612,7 @@ void Context::vertexAttribPointer(GLuint index,
{ {
mGLState.setVertexAttribPointer(this, index, mGLState.getTargetBuffer(BufferBinding::Array), mGLState.setVertexAttribPointer(this, index, mGLState.getTargetBuffer(BufferBinding::Array),
size, type, ConvertToBool(normalized), false, stride, ptr); size, type, ConvertToBool(normalized), false, stride, ptr);
mStateCache.updateActiveAttribsMask(this);
} }
void Context::vertexAttribFormat(GLuint attribIndex, void Context::vertexAttribFormat(GLuint attribIndex,
...@@ -4629,6 +4636,7 @@ void Context::vertexAttribIFormat(GLuint attribIndex, ...@@ -4629,6 +4636,7 @@ void Context::vertexAttribIFormat(GLuint attribIndex,
void Context::vertexAttribBinding(GLuint attribIndex, GLuint bindingIndex) void Context::vertexAttribBinding(GLuint attribIndex, GLuint bindingIndex)
{ {
mGLState.setVertexAttribBinding(this, attribIndex, bindingIndex); mGLState.setVertexAttribBinding(this, attribIndex, bindingIndex);
mStateCache.updateActiveAttribsMask(this);
} }
void Context::vertexBindingDivisor(GLuint bindingIndex, GLuint divisor) void Context::vertexBindingDivisor(GLuint bindingIndex, GLuint divisor)
...@@ -4649,6 +4657,7 @@ void Context::vertexAttribIPointer(GLuint index, ...@@ -4649,6 +4657,7 @@ void Context::vertexAttribIPointer(GLuint index,
{ {
mGLState.setVertexAttribPointer(this, index, mGLState.getTargetBuffer(BufferBinding::Array), mGLState.setVertexAttribPointer(this, index, mGLState.getTargetBuffer(BufferBinding::Array),
size, type, false, true, stride, pointer); size, type, false, true, stride, pointer);
mStateCache.updateActiveAttribsMask(this);
} }
void Context::vertexAttribI4i(GLuint index, GLint x, GLint y, GLint z, GLint w) void Context::vertexAttribI4i(GLuint index, GLint x, GLint y, GLint z, GLint w)
...@@ -5534,6 +5543,7 @@ void Context::linkProgram(GLuint program) ...@@ -5534,6 +5543,7 @@ void Context::linkProgram(GLuint program)
ASSERT(programObject); ASSERT(programObject);
handleError(programObject->link(this)); handleError(programObject->link(this));
mGLState.onProgramExecutableChange(programObject); mGLState.onProgramExecutableChange(programObject);
mStateCache.updateActiveAttribsMask(this);
} }
void Context::releaseShaderCompiler() void Context::releaseShaderCompiler()
...@@ -5741,6 +5751,7 @@ void Context::programBinary(GLuint program, GLenum binaryFormat, const void *bin ...@@ -5741,6 +5751,7 @@ void Context::programBinary(GLuint program, GLenum binaryFormat, const void *bin
ASSERT(programObject != nullptr); ASSERT(programObject != nullptr);
handleError(programObject->loadBinary(this, binaryFormat, binary, length)); handleError(programObject->loadBinary(this, binaryFormat, binary, length));
mStateCache.updateActiveAttribsMask(this);
} }
void Context::uniform1ui(GLint location, GLuint v0) void Context::uniform1ui(GLint location, GLuint v0)
...@@ -7536,23 +7547,6 @@ bool Context::isGLES1() const ...@@ -7536,23 +7547,6 @@ bool Context::isGLES1() const
return mState.getClientVersion() < Version(2, 0); return mState.getClientVersion() < Version(2, 0);
} }
AttributesMask Context::getActiveBufferedAttribsMask() const
{
// TODO(jmadill): Cache this. http://anglebug.com/1391
ASSERT(mGLState.getProgram() || isGLES1());
const AttributesMask &activeAttribs =
isGLES1() ? mGLState.gles1().getVertexArraysAttributeMask()
: mGLState.getProgram()->getActiveAttribLocationsMask();
const VertexArray *vao = mGLState.getVertexArray();
ASSERT(vao);
const AttributesMask &clientAttribs = vao->getEnabledClientMemoryAttribsMask();
return (activeAttribs & vao->getEnabledAttributesMask() & ~clientAttribs);
}
// ErrorSet implementation. // ErrorSet implementation.
ErrorSet::ErrorSet(Context *context) : mContext(context) ErrorSet::ErrorSet(Context *context) : mContext(context)
{ {
...@@ -7597,4 +7591,39 @@ GLenum ErrorSet::popError() ...@@ -7597,4 +7591,39 @@ GLenum ErrorSet::popError()
mErrors.erase(mErrors.begin()); mErrors.erase(mErrors.begin());
return error; return error;
} }
// StateCache implementation.
StateCache::StateCache() : mCachedHasAnyEnabledClientAttrib(false)
{
}
StateCache::~StateCache() = default;
void StateCache::updateActiveAttribsMask(Context *context)
{
bool isGLES1 = context->isGLES1();
const State &glState = context->getGLState();
if (!isGLES1 && !glState.getProgram())
{
mCachedActiveBufferedAttribsMask = AttributesMask();
mCachedActiveClientAttribsMask = AttributesMask();
return;
}
AttributesMask activeAttribs = isGLES1 ? glState.gles1().getVertexArraysAttributeMask()
: glState.getProgram()->getActiveAttribLocationsMask();
const VertexArray *vao = glState.getVertexArray();
ASSERT(vao);
const AttributesMask &clientAttribs = vao->getClientAttribsMask();
const AttributesMask &enabledAttribs = vao->getEnabledAttributesMask();
activeAttribs &= enabledAttribs;
mCachedActiveClientAttribsMask = activeAttribs & clientAttribs;
mCachedActiveBufferedAttribsMask = activeAttribs & ~clientAttribs;
mCachedHasAnyEnabledClientAttrib = (clientAttribs & enabledAttribs).any();
}
} // namespace gl } // namespace gl
...@@ -81,6 +81,32 @@ class ErrorSet : angle::NonCopyable ...@@ -81,6 +81,32 @@ class ErrorSet : angle::NonCopyable
mutable std::set<GLenum> mErrors; mutable std::set<GLenum> mErrors;
}; };
// Helper class for managing cache variables and state changes.
class StateCache final : angle::NonCopyable
{
public:
StateCache();
~StateCache();
// Places that can trigger updateActiveAttribsMask:
// 1. GLES1: clientActiveTexture.
// 2. GLES1: disableClientState/enableClientState.
// 3. Context: linkProgram/useProgram/programBinary. Note: should check programBinary bits.
// 4. Context: bindVertexArray.
// 5. Vertex Array: most any state change.
AttributesMask getActiveBufferedAttribsMask() const { return mCachedActiveBufferedAttribsMask; }
AttributesMask getActiveClientAttribsMask() const { return mCachedActiveClientAttribsMask; }
bool hasAnyEnabledClientAttrib() const { return mCachedHasAnyEnabledClientAttrib; }
// Cache update functions.
void updateActiveAttribsMask(Context *context);
private:
AttributesMask mCachedActiveBufferedAttribsMask;
AttributesMask mCachedActiveClientAttribsMask;
bool mCachedHasAnyEnabledClientAttrib;
};
class Context final : public egl::LabeledObject, angle::NonCopyable class Context final : public egl::LabeledObject, angle::NonCopyable
{ {
public: public:
...@@ -1493,7 +1519,7 @@ class Context final : public egl::LabeledObject, angle::NonCopyable ...@@ -1493,7 +1519,7 @@ class Context final : public egl::LabeledObject, angle::NonCopyable
// GL_KHR_parallel_shader_compile // GL_KHR_parallel_shader_compile
void maxShaderCompilerThreads(GLuint count); void maxShaderCompilerThreads(GLuint count);
AttributesMask getActiveBufferedAttribsMask() const; const StateCache &getStateCache() const { return mStateCache; }
private: private:
void initialize(); void initialize();
...@@ -1616,6 +1642,9 @@ class Context final : public egl::LabeledObject, angle::NonCopyable ...@@ -1616,6 +1642,9 @@ class Context final : public egl::LabeledObject, angle::NonCopyable
State::DirtyObjects mDrawDirtyObjects; State::DirtyObjects mDrawDirtyObjects;
State::DirtyObjects mPathOperationDirtyObjects; State::DirtyObjects mPathOperationDirtyObjects;
StateCache mStateCache;
State::DirtyBits mTexImageDirtyBits; State::DirtyBits mTexImageDirtyBits;
State::DirtyObjects mTexImageDirtyObjects; State::DirtyObjects mTexImageDirtyObjects;
State::DirtyBits mReadPixelsDirtyBits; State::DirtyBits mReadPixelsDirtyBits;
......
...@@ -59,6 +59,7 @@ void Context::clearDepthx(GLfixed depth) ...@@ -59,6 +59,7 @@ void Context::clearDepthx(GLfixed depth)
void Context::clientActiveTexture(GLenum texture) void Context::clientActiveTexture(GLenum texture)
{ {
mGLState.gles1().setClientTextureUnit(texture - GL_TEXTURE0); mGLState.gles1().setClientTextureUnit(texture - GL_TEXTURE0);
mStateCache.updateActiveAttribsMask(this);
} }
void Context::clipPlanef(GLenum p, const GLfloat *eqn) void Context::clipPlanef(GLenum p, const GLfloat *eqn)
...@@ -109,12 +110,14 @@ void Context::disableClientState(ClientVertexArrayType clientState) ...@@ -109,12 +110,14 @@ void Context::disableClientState(ClientVertexArrayType clientState)
{ {
mGLState.gles1().setClientStateEnabled(clientState, false); mGLState.gles1().setClientStateEnabled(clientState, false);
disableVertexAttribArray(vertexArrayIndex(clientState)); disableVertexAttribArray(vertexArrayIndex(clientState));
mStateCache.updateActiveAttribsMask(this);
} }
void Context::enableClientState(ClientVertexArrayType clientState) void Context::enableClientState(ClientVertexArrayType clientState)
{ {
mGLState.gles1().setClientStateEnabled(clientState, true); mGLState.gles1().setClientStateEnabled(clientState, true);
enableVertexAttribArray(vertexArrayIndex(clientState)); enableVertexAttribArray(vertexArrayIndex(clientState));
mStateCache.updateActiveAttribsMask(this);
} }
void Context::fogf(GLenum pname, GLfloat param) void Context::fogf(GLenum pname, GLfloat param)
......
...@@ -26,15 +26,13 @@ VertexArrayState::VertexArrayState(size_t maxAttribs, size_t maxAttribBindings) ...@@ -26,15 +26,13 @@ VertexArrayState::VertexArrayState(size_t maxAttribs, size_t maxAttribBindings)
mVertexAttributes.emplace_back(static_cast<GLuint>(i)); mVertexAttributes.emplace_back(static_cast<GLuint>(i));
mBindingToAttributeMasks[i].set(i); mBindingToAttributeMasks[i].set(i);
} }
}
VertexArrayState::~VertexArrayState() // Initially all attributes start as "client" with no buffer bound.
{ mClientMemoryAttribsMask.set();
} }
gl::AttributesMask VertexArrayState::getEnabledClientMemoryAttribsMask() const VertexArrayState::~VertexArrayState()
{ {
return (mClientMemoryAttribsMask & mEnabledAttributesMask);
} }
bool VertexArrayState::hasEnabledNullPointerClientArray() const bool VertexArrayState::hasEnabledNullPointerClientArray() const
...@@ -189,6 +187,16 @@ void VertexArray::bindVertexBufferImpl(const Context *context, ...@@ -189,6 +187,16 @@ void VertexArray::bindVertexBufferImpl(const Context *context,
updateObserverBinding(bindingIndex); updateObserverBinding(bindingIndex);
updateCachedBufferBindingSize(bindingIndex); updateCachedBufferBindingSize(bindingIndex);
updateCachedTransformFeedbackBindingValidation(bindingIndex, boundBuffer); updateCachedTransformFeedbackBindingValidation(bindingIndex, boundBuffer);
// Update client memory attribute pointers. Affects all bound attributes.
if (boundBuffer)
{
mState.mClientMemoryAttribsMask &= ~mState.mBindingToAttributeMasks[bindingIndex];
}
else
{
mState.mClientMemoryAttribsMask |= mState.mBindingToAttributeMasks[bindingIndex];
}
} }
void VertexArray::bindVertexBuffer(const Context *context, void VertexArray::bindVertexBuffer(const Context *context,
...@@ -215,6 +223,10 @@ void VertexArray::setVertexAttribBinding(const Context *context, ...@@ -215,6 +223,10 @@ void VertexArray::setVertexAttribBinding(const Context *context,
mState.setAttribBinding(attribIndex, bindingIndex); mState.setAttribBinding(attribIndex, bindingIndex);
setDirtyAttribBit(attribIndex, DIRTY_ATTRIB_BINDING); setDirtyAttribBit(attribIndex, DIRTY_ATTRIB_BINDING);
// Update client attribs mask.
bool hasBuffer = mState.mVertexBindings[bindingIndex].getBuffer().get() != nullptr;
mState.mClientMemoryAttribsMask.set(attribIndex, !hasBuffer);
} }
} }
...@@ -307,7 +319,6 @@ void VertexArray::setVertexAttribPointer(const Context *context, ...@@ -307,7 +319,6 @@ void VertexArray::setVertexAttribPointer(const Context *context,
setDirtyAttribBit(attribIndex, DIRTY_ATTRIB_POINTER); setDirtyAttribBit(attribIndex, DIRTY_ATTRIB_POINTER);
mState.mClientMemoryAttribsMask.set(attribIndex, boundBuffer == nullptr);
mState.mNullPointerClientMemoryAttribsMask.set(attribIndex, mState.mNullPointerClientMemoryAttribsMask.set(attribIndex,
boundBuffer == nullptr && pointer == nullptr); boundBuffer == nullptr && pointer == nullptr);
} }
......
...@@ -65,9 +65,6 @@ class VertexArrayState final : angle::NonCopyable ...@@ -65,9 +65,6 @@ class VertexArrayState final : angle::NonCopyable
void setAttribBinding(size_t attribIndex, GLuint newBindingIndex); void setAttribBinding(size_t attribIndex, GLuint newBindingIndex);
// Combines mClientMemoryAttribsMask with mEnabledAttributesMask.
gl::AttributesMask getEnabledClientMemoryAttribsMask() const;
// Extra validation performed on the Vertex Array. // Extra validation performed on the Vertex Array.
bool hasEnabledNullPointerClientArray() const; bool hasEnabledNullPointerClientArray() const;
...@@ -177,10 +174,7 @@ class VertexArray final : public angle::ObserverInterface, public LabeledObject ...@@ -177,10 +174,7 @@ class VertexArray final : public angle::ObserverInterface, public LabeledObject
return mState.getEnabledAttributesMask(); return mState.getEnabledAttributesMask();
} }
gl::AttributesMask getEnabledClientMemoryAttribsMask() const gl::AttributesMask getClientAttribsMask() const { return mState.mClientMemoryAttribsMask; }
{
return mState.getEnabledClientMemoryAttribsMask();
}
bool hasEnabledNullPointerClientArray() const bool hasEnabledNullPointerClientArray() const
{ {
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "common/mathutil.h" #include "common/mathutil.h"
#include "common/utilities.h" #include "common/utilities.h"
#include "libANGLE/Buffer.h" #include "libANGLE/Buffer.h"
#include "libANGLE/Context.h"
#include "libANGLE/angletypes.h" #include "libANGLE/angletypes.h"
#include "libANGLE/formatutils.h" #include "libANGLE/formatutils.h"
#include "libANGLE/renderer/gl/BufferGL.h" #include "libANGLE/renderer/gl/BufferGL.h"
...@@ -149,7 +150,7 @@ gl::Error VertexArrayGL::syncDrawState(const gl::Context *context, ...@@ -149,7 +150,7 @@ gl::Error VertexArrayGL::syncDrawState(const gl::Context *context,
// Check if any attributes need to be streamed, determines if the index range needs to be // Check if any attributes need to be streamed, determines if the index range needs to be
// computed // computed
const gl::AttributesMask &needsStreamingAttribs = const gl::AttributesMask &needsStreamingAttribs =
(mState.getEnabledClientMemoryAttribsMask() & activeAttributesMask); context->getStateCache().getActiveClientAttribsMask();
// Determine if an index buffer needs to be streamed and the range of vertices that need to be // Determine if an index buffer needs to be streamed and the range of vertices that need to be
// copied // copied
......
...@@ -566,20 +566,15 @@ gl::Error VertexArrayVk::onDraw(const gl::Context *context, ...@@ -566,20 +566,15 @@ gl::Error VertexArrayVk::onDraw(const gl::Context *context,
ContextVk *contextVk = vk::GetImpl(context); ContextVk *contextVk = vk::GetImpl(context);
const gl::State &state = context->getGLState(); const gl::State &state = context->getGLState();
const gl::Program *programGL = state.getProgram(); const gl::Program *programGL = state.getProgram();
const gl::AttributesMask &clientAttribs = mState.getEnabledClientMemoryAttribsMask(); const gl::AttributesMask &clientAttribs = context->getStateCache().getActiveClientAttribsMask();
const gl::AttributesMask &activeAttribs = programGL->getActiveAttribLocationsMask();
uint32_t maxAttrib = programGL->getState().getMaxActiveAttribLocation(); uint32_t maxAttrib = programGL->getState().getMaxActiveAttribLocation();
if (clientAttribs.any()) if (clientAttribs.any())
{ {
const gl::AttributesMask &attribsToStream = (clientAttribs & activeAttribs); ANGLE_TRY(drawCallParams.ensureIndexRangeResolved(context));
if (attribsToStream.any()) ANGLE_TRY(streamVertexData(contextVk, clientAttribs, drawCallParams));
{ commandBuffer->bindVertexBuffers(0, maxAttrib, mCurrentArrayBufferHandles.data(),
ANGLE_TRY(drawCallParams.ensureIndexRangeResolved(context)); mCurrentArrayBufferOffsets.data());
ANGLE_TRY(streamVertexData(contextVk, attribsToStream, drawCallParams));
commandBuffer->bindVertexBuffers(0, maxAttrib, mCurrentArrayBufferHandles.data(),
mCurrentArrayBufferOffsets.data());
}
} }
else if (mVertexBuffersDirty || newCommandBuffer) else if (mVertexBuffersDirty || newCommandBuffer)
{ {
...@@ -588,8 +583,11 @@ gl::Error VertexArrayVk::onDraw(const gl::Context *context, ...@@ -588,8 +583,11 @@ gl::Error VertexArrayVk::onDraw(const gl::Context *context,
commandBuffer->bindVertexBuffers(0, maxAttrib, mCurrentArrayBufferHandles.data(), commandBuffer->bindVertexBuffers(0, maxAttrib, mCurrentArrayBufferHandles.data(),
mCurrentArrayBufferOffsets.data()); mCurrentArrayBufferOffsets.data());
const gl::AttributesMask &bufferedAttribs =
context->getStateCache().getActiveBufferedAttribsMask();
vk::CommandGraphResource *drawFramebuffer = vk::GetImpl(state.getDrawFramebuffer()); vk::CommandGraphResource *drawFramebuffer = vk::GetImpl(state.getDrawFramebuffer());
updateArrayBufferReadDependencies(drawFramebuffer, activeAttribs, updateArrayBufferReadDependencies(drawFramebuffer, bufferedAttribs,
contextVk->getRenderer()->getCurrentQueueSerial()); contextVk->getRenderer()->getCurrentQueueSerial());
} }
......
...@@ -83,13 +83,11 @@ bool ValidateDrawAttribs(Context *context, GLint primcount, GLint maxVertex, GLi ...@@ -83,13 +83,11 @@ bool ValidateDrawAttribs(Context *context, GLint primcount, GLint maxVertex, GLi
{ {
const gl::State &state = context->getGLState(); const gl::State &state = context->getGLState();
const gl::Program *program = state.getProgram(); const gl::Program *program = state.getProgram();
const VertexArray *vao = state.getVertexArray();
bool webglCompatibility = context->getExtensions().webglCompatibility; bool webglCompatibility = context->getExtensions().webglCompatibility;
const VertexArray *vao = state.getVertexArray(); if (context->getStateCache().hasAnyEnabledClientAttrib())
const AttributesMask &clientAttribs = vao->getEnabledClientMemoryAttribsMask();
if (clientAttribs.any())
{ {
if (webglCompatibility || !state.areClientArraysEnabled()) if (webglCompatibility || !state.areClientArraysEnabled())
{ {
...@@ -118,7 +116,7 @@ bool ValidateDrawAttribs(Context *context, GLint primcount, GLint maxVertex, GLi ...@@ -118,7 +116,7 @@ bool ValidateDrawAttribs(Context *context, GLint primcount, GLint maxVertex, GLi
const auto &vertexAttribs = vao->getVertexAttributes(); const auto &vertexAttribs = vao->getVertexAttributes();
const auto &vertexBindings = vao->getVertexBindings(); const auto &vertexBindings = vao->getVertexBindings();
const AttributesMask &activeAttribs = context->getActiveBufferedAttribsMask(); const AttributesMask &activeAttribs = context->getStateCache().getActiveBufferedAttribsMask();
for (size_t attributeIndex : activeAttribs) for (size_t attributeIndex : activeAttribs)
{ {
......
...@@ -4163,12 +4163,18 @@ TEST_P(WebGL2CompatibilityTest, TransformFeedbackCheckNullDeref) ...@@ -4163,12 +4163,18 @@ TEST_P(WebGL2CompatibilityTest, TransformFeedbackCheckNullDeref)
ANGLE_GL_PROGRAM(program, kVS, kFS); ANGLE_GL_PROGRAM(program, kVS, kFS);
glUseProgram(program); glUseProgram(program);
GLBuffer buffer;
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glEnableVertexAttribArray(0); glEnableVertexAttribArray(0);
glDrawArrays(GL_POINTS, 0, 1); glDrawArrays(GL_POINTS, 0, 1);
// This should fail because it is trying to pull one vertex from an empty buffer. // This should fail because it is trying to pull a vertex with no buffer.
EXPECT_GL_ERROR(GL_INVALID_OPERATION);
GLBuffer buffer;
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, nullptr);
// This should fail because it is trying to pull a vertex from an empty buffer.
glDrawArrays(GL_POINTS, 0, 1);
EXPECT_GL_ERROR(GL_INVALID_OPERATION); EXPECT_GL_ERROR(GL_INVALID_OPERATION);
} }
......
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