Commit cc73f241 by Jamie Madill Committed by Commit Bot

Micro-optimize some validation checks.

Prepares for caching hasMappedBuffer. Also inclines several checks for faster speed. Bug: angleproject:2746 Change-Id: I74f9408d7b41e245c3f58d367dd2cc8fbace4a7a Reviewed-on: https://chromium-review.googlesource.com/1150762 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarFrank Henigman <fjhenigman@chromium.org> Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org>
parent 2da5356e
...@@ -1002,21 +1002,11 @@ void Framebuffer::invalidateCompletenessCache() ...@@ -1002,21 +1002,11 @@ void Framebuffer::invalidateCompletenessCache()
} }
} }
GLenum Framebuffer::checkStatus(const Context *context) GLenum Framebuffer::checkStatusImpl(const Context *context)
{ {
// The default framebuffer is always complete except when it is surfaceless in which ASSERT(!isDefault());
// case it is always unsupported. We return early because the default framebuffer may ASSERT(hasAnyDirtyBit() || !mCachedStatus.valid());
// not be subject to the same rules as application FBOs. ie, it could have 0x0 size.
if (mState.mId == 0)
{
ASSERT(mCachedStatus.valid());
ASSERT(mCachedStatus.value() == GL_FRAMEBUFFER_COMPLETE ||
mCachedStatus.value() == GL_FRAMEBUFFER_UNDEFINED_OES);
return mCachedStatus.value();
}
if (hasAnyDirtyBit() || !mCachedStatus.valid())
{
mCachedStatus = checkStatusWithGLFrontEnd(context); mCachedStatus = checkStatusWithGLFrontEnd(context);
if (mCachedStatus.value() == GL_FRAMEBUFFER_COMPLETE) if (mCachedStatus.value() == GL_FRAMEBUFFER_COMPLETE)
...@@ -1033,7 +1023,6 @@ GLenum Framebuffer::checkStatus(const Context *context) ...@@ -1033,7 +1023,6 @@ GLenum Framebuffer::checkStatus(const Context *context)
mCachedStatus = GL_FRAMEBUFFER_UNSUPPORTED; mCachedStatus = GL_FRAMEBUFFER_UNSUPPORTED;
} }
} }
}
return mCachedStatus.value(); return mCachedStatus.value();
} }
...@@ -1884,11 +1873,6 @@ FramebufferAttachment *Framebuffer::getAttachmentFromSubjectIndex(angle::Subject ...@@ -1884,11 +1873,6 @@ FramebufferAttachment *Framebuffer::getAttachmentFromSubjectIndex(angle::Subject
} }
} }
bool Framebuffer::isComplete(const Context *context)
{
return (checkStatus(context) == GL_FRAMEBUFFER_COMPLETE);
}
bool Framebuffer::formsRenderingFeedbackLoopWith(const State &state) const bool Framebuffer::formsRenderingFeedbackLoopWith(const State &state) const
{ {
const Program *program = state.getProgram(); const Program *program = state.getProgram();
......
...@@ -239,13 +239,27 @@ class Framebuffer final : public angle::ObserverInterface, ...@@ -239,13 +239,27 @@ class Framebuffer final : public angle::ObserverInterface,
void invalidateCompletenessCache(); void invalidateCompletenessCache();
GLenum checkStatus(const Context *context); GLenum checkStatus(const Context *context)
{
// The default framebuffer is always complete except when it is surfaceless in which
// case it is always unsupported.
ASSERT(mState.mId != 0 || mCachedStatus.valid());
if (mState.mId == 0 || (!hasAnyDirtyBit() && mCachedStatus.valid()))
{
return mCachedStatus.value();
}
return checkStatusImpl(context);
}
// For when we don't want to check completeness in getSamples(). // For when we don't want to check completeness in getSamples().
int getCachedSamples(const Context *context); int getCachedSamples(const Context *context);
// Helper for checkStatus == GL_FRAMEBUFFER_COMPLETE. // Helper for checkStatus == GL_FRAMEBUFFER_COMPLETE.
bool isComplete(const Context *context); bool isComplete(const Context *context)
{
return (checkStatus(context) == GL_FRAMEBUFFER_COMPLETE);
}
bool hasValidDepthStencil() const; bool hasValidDepthStencil() const;
...@@ -343,6 +357,7 @@ class Framebuffer final : public angle::ObserverInterface, ...@@ -343,6 +357,7 @@ class Framebuffer final : public angle::ObserverInterface,
GLuint matchId, GLuint matchId,
size_t dirtyBit); size_t dirtyBit);
GLenum checkStatusWithGLFrontEnd(const Context *context); GLenum checkStatusWithGLFrontEnd(const Context *context);
GLenum checkStatusImpl(const Context *context);
void setAttachment(const Context *context, void setAttachment(const Context *context,
GLenum type, GLenum type,
GLenum binding, GLenum binding,
......
...@@ -1321,12 +1321,6 @@ void Program::unlink() ...@@ -1321,12 +1321,6 @@ void Program::unlink()
mInfoLog.reset(); mInfoLog.reset();
} }
bool Program::hasLinkedShaderStage(ShaderType shaderType) const
{
ASSERT(shaderType != ShaderType::InvalidEnum);
return mState.mLinkedShaderStages[shaderType];
}
Error Program::loadBinary(const Context *context, Error Program::loadBinary(const Context *context,
GLenum binaryFormat, GLenum binaryFormat,
const void *binary, const void *binary,
...@@ -2050,15 +2044,8 @@ void Program::validate(const Caps &caps) ...@@ -2050,15 +2044,8 @@ void Program::validate(const Caps &caps)
} }
} }
bool Program::validateSamplers(InfoLog *infoLog, const Caps &caps) bool Program::validateSamplersImpl(InfoLog *infoLog, const Caps &caps)
{ {
// Skip cache if we're using an infolog, so we get the full error.
// Also skip the cache if the sample mapping has changed, or if we haven't ever validated.
if (infoLog == nullptr && mCachedValidateSamplersResult.valid())
{
return mCachedValidateSamplersResult.value();
}
if (mTextureUnitTypesCache.empty()) if (mTextureUnitTypesCache.empty())
{ {
mTextureUnitTypesCache.resize(caps.maxCombinedTextureImageUnits, TextureType::InvalidEnum); mTextureUnitTypesCache.resize(caps.maxCombinedTextureImageUnits, TextureType::InvalidEnum);
...@@ -2125,11 +2112,6 @@ bool Program::isValidated() const ...@@ -2125,11 +2112,6 @@ bool Program::isValidated() const
return mValidated; return mValidated;
} }
GLuint Program::getActiveUniformBlockCount() const
{
return static_cast<GLuint>(mState.mUniformBlocks.size());
}
GLuint Program::getActiveAtomicCounterBufferCount() const GLuint Program::getActiveAtomicCounterBufferCount() const
{ {
return static_cast<GLuint>(mState.mAtomicCounterBuffers.size()); return static_cast<GLuint>(mState.mAtomicCounterBuffers.size());
......
...@@ -490,7 +490,11 @@ class Program final : angle::NonCopyable, public LabeledObject ...@@ -490,7 +490,11 @@ class Program final : angle::NonCopyable, public LabeledObject
Error link(const Context *context); Error link(const Context *context);
bool isLinked() const { return mLinked; } bool isLinked() const { return mLinked; }
bool hasLinkedShaderStage(ShaderType shaderType) const; bool hasLinkedShaderStage(ShaderType shaderType) const
{
ASSERT(shaderType != ShaderType::InvalidEnum);
return mState.mLinkedShaderStages[shaderType];
}
Error loadBinary(const Context *context, Error loadBinary(const Context *context,
GLenum binaryFormat, GLenum binaryFormat,
...@@ -627,7 +631,11 @@ class Program final : angle::NonCopyable, public LabeledObject ...@@ -627,7 +631,11 @@ class Program final : angle::NonCopyable, public LabeledObject
GLsizei bufSize, GLsizei bufSize,
GLsizei *length, GLsizei *length,
GLchar *blockName) const; GLchar *blockName) const;
GLuint getActiveUniformBlockCount() const; GLuint getActiveUniformBlockCount() const
{
return static_cast<GLuint>(mState.mUniformBlocks.size());
}
GLuint getActiveAtomicCounterBufferCount() const; GLuint getActiveAtomicCounterBufferCount() const;
GLuint getActiveShaderStorageBlockCount() const; GLuint getActiveShaderStorageBlockCount() const;
GLint getActiveUniformBlockMaxNameLength() const; GLint getActiveUniformBlockMaxNameLength() const;
...@@ -665,7 +673,18 @@ class Program final : angle::NonCopyable, public LabeledObject ...@@ -665,7 +673,18 @@ class Program final : angle::NonCopyable, public LabeledObject
bool isFlaggedForDeletion() const; bool isFlaggedForDeletion() const;
void validate(const Caps &caps); void validate(const Caps &caps);
bool validateSamplers(InfoLog *infoLog, const Caps &caps); bool validateSamplers(InfoLog *infoLog, const Caps &caps)
{
// Skip cache if we're using an infolog, so we get the full error.
// Also skip the cache if the sample mapping has changed, or if we haven't ever validated.
if (infoLog == nullptr && mCachedValidateSamplersResult.valid())
{
return mCachedValidateSamplersResult.value();
}
return validateSamplersImpl(infoLog, caps);
}
bool isValidated() const; bool isValidated() const;
bool samplesFromTexture(const State &state, GLuint textureID) const; bool samplesFromTexture(const State &state, GLuint textureID) const;
...@@ -821,6 +840,8 @@ class Program final : angle::NonCopyable, public LabeledObject ...@@ -821,6 +840,8 @@ class Program final : angle::NonCopyable, public LabeledObject
GLuint getSamplerUniformBinding(const VariableLocation &uniformLocation) const; GLuint getSamplerUniformBinding(const VariableLocation &uniformLocation) const;
bool validateSamplersImpl(InfoLog *infoLog, const Caps &caps);
ProgramState mState; ProgramState mState;
rx::ProgramImpl *mProgram; rx::ProgramImpl *mProgram;
......
...@@ -2603,32 +2603,6 @@ void State::getBooleani_v(GLenum target, GLuint index, GLboolean *data) ...@@ -2603,32 +2603,6 @@ void State::getBooleani_v(GLenum target, GLuint index, GLboolean *data)
} }
} }
bool State::hasMappedBuffer(BufferBinding target) const
{
if (target == BufferBinding::Array)
{
const VertexArray *vao = getVertexArray();
const auto &vertexAttribs = vao->getVertexAttributes();
const auto &vertexBindings = vao->getVertexBindings();
for (size_t attribIndex : vao->getEnabledAttributesMask())
{
const VertexAttribute &vertexAttrib = vertexAttribs[attribIndex];
auto *boundBuffer = vertexBindings[vertexAttrib.bindingIndex].getBuffer().get();
if (vertexAttrib.enabled && boundBuffer && boundBuffer->isMapped())
{
return true;
}
}
return false;
}
else
{
Buffer *buffer = getTargetBuffer(target);
return (buffer && buffer->isMapped());
}
}
Error State::syncDirtyObjects(const Context *context, const DirtyObjects &bitset) Error State::syncDirtyObjects(const Context *context, const DirtyObjects &bitset)
{ {
const DirtyObjects &dirtyObjects = mDirtyObjects & bitset; const DirtyObjects &dirtyObjects = mDirtyObjects & bitset;
......
...@@ -349,7 +349,6 @@ class State : public angle::ObserverInterface, angle::NonCopyable ...@@ -349,7 +349,6 @@ class State : public angle::ObserverInterface, angle::NonCopyable
void getInteger64i_v(GLenum target, GLuint index, GLint64 *data); void getInteger64i_v(GLenum target, GLuint index, GLint64 *data);
void getBooleani_v(GLenum target, GLuint index, GLboolean *data); void getBooleani_v(GLenum target, GLuint index, GLboolean *data);
bool hasMappedBuffer(BufferBinding target) const;
bool isRobustResourceInitEnabled() const { return mRobustResourceInit; } bool isRobustResourceInitEnabled() const { return mRobustResourceInit; }
// Sets the dirty bit for the program executable. // Sets the dirty bit for the program executable.
......
...@@ -486,4 +486,21 @@ bool VertexArray::hasTransformFeedbackBindingConflict(const gl::Context *context ...@@ -486,4 +486,21 @@ bool VertexArray::hasTransformFeedbackBindingConflict(const gl::Context *context
return false; return false;
} }
bool VertexArray::hasMappedEnabledArrayBuffer() const
{
// TODO(jmadill): Cache this. http://anglebug.com/2746
for (size_t attribIndex : mState.mEnabledAttributesMask)
{
const VertexAttribute &vertexAttrib = mState.mVertexAttributes[attribIndex];
ASSERT(vertexAttrib.enabled);
const VertexBinding &vertexBinding = mState.mVertexBindings[vertexAttrib.bindingIndex];
gl::Buffer *boundBuffer = vertexBinding.getBuffer().get();
if (boundBuffer && boundBuffer->isMapped())
{
return true;
}
}
return false;
}
} // namespace gl } // namespace gl
...@@ -178,6 +178,8 @@ class VertexArray final : public angle::ObserverInterface, ...@@ -178,6 +178,8 @@ class VertexArray final : public angle::ObserverInterface,
return mState.hasEnabledNullPointerClientArray(); return mState.hasEnabledNullPointerClientArray();
} }
bool hasMappedEnabledArrayBuffer() const;
// Observer implementation // Observer implementation
void onSubjectStateChange(const gl::Context *context, void onSubjectStateChange(const gl::Context *context,
angle::SubjectIndex index, angle::SubjectIndex index,
......
...@@ -2628,16 +2628,11 @@ bool ValidateDrawBase(Context *context, PrimitiveMode mode, GLsizei count) ...@@ -2628,16 +2628,11 @@ bool ValidateDrawBase(Context *context, PrimitiveMode mode, GLsizei count)
// WebGL buffers cannot be mapped/unmapped because the MapBufferRange, FlushMappedBufferRange, // WebGL buffers cannot be mapped/unmapped because the MapBufferRange, FlushMappedBufferRange,
// and UnmapBuffer entry points are removed from the WebGL 2.0 API. // and UnmapBuffer entry points are removed from the WebGL 2.0 API.
// https://www.khronos.org/registry/webgl/specs/latest/2.0/#5.14 // https://www.khronos.org/registry/webgl/specs/latest/2.0/#5.14
if (!extensions.webglCompatibility) if (!extensions.webglCompatibility && state.getVertexArray()->hasMappedEnabledArrayBuffer())
{
// Check for mapped buffers
// TODO(jmadill): Optimize this check for non - WebGL contexts.
if (state.hasMappedBuffer(BufferBinding::Array))
{ {
context->handleError(InvalidOperation()); context->handleError(InvalidOperation());
return false; return false;
} }
}
// Note: these separate values are not supported in WebGL, due to D3D's limitations. See // Note: these separate values are not supported in WebGL, due to D3D's limitations. See
// Section 6.10 of the WebGL 1.0 spec. // Section 6.10 of the WebGL 1.0 spec.
...@@ -2692,7 +2687,6 @@ bool ValidateDrawBase(Context *context, PrimitiveMode mode, GLsizei count) ...@@ -2692,7 +2687,6 @@ bool ValidateDrawBase(Context *context, PrimitiveMode mode, GLsizei count)
// If we are running GLES1, there is no current program. // If we are running GLES1, there is no current program.
if (context->getClientVersion() >= Version(2, 0)) if (context->getClientVersion() >= Version(2, 0))
{ {
gl::Program *program = state.getProgram(); gl::Program *program = state.getProgram();
if (!program) if (!program)
{ {
...@@ -2996,20 +2990,6 @@ bool ValidateDrawElementsCommon(Context *context, ...@@ -2996,20 +2990,6 @@ bool ValidateDrawElementsCommon(Context *context,
return false; return false;
} }
// WebGL buffers cannot be mapped/unmapped because the MapBufferRange, FlushMappedBufferRange,
// and UnmapBuffer entry points are removed from the WebGL 2.0 API.
// https://www.khronos.org/registry/webgl/specs/latest/2.0/#5.14
if (!context->getExtensions().webglCompatibility)
{
// Check for mapped buffers
// TODO(jmadill): Optimize this check for non - WebGL contexts.
if (state.hasMappedBuffer(gl::BufferBinding::ElementArray))
{
context->handleError(InvalidOperation() << "Index buffer is mapped.");
return false;
}
}
const gl::VertexArray *vao = state.getVertexArray(); const gl::VertexArray *vao = state.getVertexArray();
gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get(); gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get();
...@@ -3036,6 +3016,14 @@ bool ValidateDrawElementsCommon(Context *context, ...@@ -3036,6 +3016,14 @@ bool ValidateDrawElementsCommon(Context *context,
return false; return false;
} }
} }
else if (elementArrayBuffer && elementArrayBuffer->isMapped())
{
// WebGL buffers cannot be mapped/unmapped because the MapBufferRange,
// FlushMappedBufferRange, and UnmapBuffer entry points are removed from the WebGL 2.0 API.
// https://www.khronos.org/registry/webgl/specs/latest/2.0/#5.14
context->handleError(InvalidOperation() << "Index buffer is mapped.");
return false;
}
if (context->getExtensions().webglCompatibility || if (context->getExtensions().webglCompatibility ||
!context->getGLState().areClientArraysEnabled()) !context->getGLState().areClientArraysEnabled())
......
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