Optimize ValidateDrawStates.
Apparently returning a small struct was slow enough to make a 2-3%
difference in benchmark scores. Very visible on the MSVC sampling
profiler.
Bug: angleproject:2747
Change-Id: I459a127f3f2a0fc3a08db15c37257a67f63f20ce
Reviewed-on: https://chromium-review.googlesource.com/1181465
Reviewed-by: Frank Henigman <fjhenigman@chromium.org>
Reviewed-by: Geoff Lang <geofflang@chromium.org>
Commit-Queue: Jamie Madill <jmadill@chromium.org>
diff --git a/src/libANGLE/validationES.cpp b/src/libANGLE/validationES.cpp
index bc0a3f0..5812e3a 100644
--- a/src/libANGLE/validationES.cpp
+++ b/src/libANGLE/validationES.cpp
@@ -2542,7 +2542,9 @@
return true;
}
-ErrorAndMessage ValidateDrawStates(Context *context)
+// Note all errors returned from this function are INVALID_OPERATION except for the draw framebuffer
+// completeness check.
+const char *ValidateDrawStates(Context *context)
{
const Extensions &extensions = context->getExtensions();
const State &state = context->getGLState();
@@ -2552,7 +2554,7 @@
// https://www.khronos.org/registry/webgl/specs/latest/2.0/#5.14
if (!extensions.webglCompatibility && state.getVertexArray()->hasMappedEnabledArrayBuffer())
{
- return {GL_INVALID_OPERATION, nullptr};
+ return kErrorBufferMapped;
}
// Note: these separate values are not supported in WebGL, due to D3D's limitations. See
@@ -2586,14 +2588,15 @@
WARN() << "This ANGLE implementation does not support separate front/back "
"stencil writemasks, reference values, or stencil mask values.";
}
- return {GL_INVALID_OPERATION, kErrorStencilReferenceMaskOrMismatch};
+ return kErrorStencilReferenceMaskOrMismatch;
}
}
}
if (!framebuffer->isComplete(context))
{
- return {GL_INVALID_FRAMEBUFFER_OPERATION, nullptr};
+ // Note: this error should be generated as INVALID_FRAMEBUFFER_OPERATION.
+ return kErrorDrawFramebufferIncomplete;
}
if (context->getStateCache().hasAnyEnabledClientAttrib())
@@ -2604,14 +2607,14 @@
// If a vertex attribute is enabled as an array via enableVertexAttribArray but no
// buffer is bound to that attribute via bindBuffer and vertexAttribPointer, then calls
// to drawArrays or drawElements will generate an INVALID_OPERATION error.
- return {GL_INVALID_OPERATION, kErrorVertexArrayNoBuffer};
+ return kErrorVertexArrayNoBuffer;
}
if (state.getVertexArray()->hasEnabledNullPointerClientArray())
{
// This is an application error that would normally result in a crash, but we catch it
// and return an error
- return {GL_INVALID_OPERATION, kErrorVertexArrayNoBufferPointer};
+ return kErrorVertexArrayNoBufferPointer;
}
}
@@ -2621,7 +2624,7 @@
Program *program = state.getProgram();
if (!program)
{
- return {GL_INVALID_OPERATION, kErrorProgramNotBound};
+ return kErrorProgramNotBound;
}
// In OpenGL ES spec for UseProgram at section 7.3, trying to render without
@@ -2631,12 +2634,12 @@
if (!program->hasLinkedShaderStage(ShaderType::Vertex) ||
!program->hasLinkedShaderStage(ShaderType::Fragment))
{
- return {GL_INVALID_OPERATION, kErrorNoActiveGraphicsShaderStage};
+ return kErrorNoActiveGraphicsShaderStage;
}
if (!program->validateSamplers(nullptr, context->getCaps()))
{
- return {GL_INVALID_OPERATION, nullptr};
+ return kErrorTextureTypeConflict;
}
if (extensions.multiview)
@@ -2645,20 +2648,20 @@
const int framebufferNumViews = framebuffer->getNumViews();
if (framebufferNumViews != programNumViews)
{
- return {GL_INVALID_OPERATION, kErrorMultiviewMismatch};
+ return kErrorMultiviewMismatch;
}
const TransformFeedback *transformFeedbackObject = state.getCurrentTransformFeedback();
if (transformFeedbackObject != nullptr && transformFeedbackObject->isActive() &&
framebufferNumViews > 1)
{
- return {GL_INVALID_OPERATION, kErrorMultiviewTransformFeedback};
+ return kErrorMultiviewTransformFeedback;
}
if (extensions.disjointTimerQuery && framebufferNumViews > 1 &&
state.isQueryActive(QueryType::TimeElapsed))
{
- return {GL_INVALID_OPERATION, kErrorMultiviewTimerQuery};
+ return kErrorMultiviewTimerQuery;
}
}
@@ -2674,20 +2677,20 @@
if (uniformBuffer.get() == nullptr)
{
// undefined behaviour
- return {GL_INVALID_OPERATION, kErrorUniformBufferUnbound};
+ return kErrorUniformBufferUnbound;
}
size_t uniformBufferSize = GetBoundBufferAvailableSize(uniformBuffer);
if (uniformBufferSize < uniformBlock.dataSize)
{
// undefined behaviour
- return {GL_INVALID_OPERATION, kErrorUniformBufferTooSmall};
+ return kErrorUniformBufferTooSmall;
}
if (extensions.webglCompatibility &&
uniformBuffer->isBoundForTransformFeedbackAndOtherUse())
{
- return {GL_INVALID_OPERATION, kErrorUniformBufferBoundForTransformFeedback};
+ return kErrorUniformBufferBoundForTransformFeedback;
}
}
@@ -2698,36 +2701,36 @@
if (transformFeedbackObject != nullptr && transformFeedbackObject->isActive() &&
transformFeedbackObject->buffersBoundForOtherUse())
{
- return {GL_INVALID_OPERATION, kErrorTransformFeedbackBufferDoubleBound};
+ return kErrorTransformFeedbackBufferDoubleBound;
}
// Detect rendering feedback loops for WebGL.
if (framebuffer->formsRenderingFeedbackLoopWith(state))
{
- return {GL_INVALID_OPERATION, kErrorFeedbackLoop};
+ return kErrorFeedbackLoop;
}
// Detect that the vertex shader input types match the attribute types
if (!ValidateVertexShaderAttributeTypeMatch(context))
{
- return {GL_INVALID_OPERATION, kErrorVertexShaderTypeMismatch};
+ return kErrorVertexShaderTypeMismatch;
}
// Detect that the color buffer types match the fragment shader output types
if (!ValidateFragmentShaderColorBufferTypeMatch(context))
{
- return {GL_INVALID_OPERATION, kErrorDrawBufferTypeMismatch};
+ return kErrorDrawBufferTypeMismatch;
}
const VertexArray *vao = context->getGLState().getVertexArray();
if (vao->hasTransformFeedbackBindingConflict(context))
{
- return {GL_INVALID_OPERATION, kErrorVertexBufferBoundForTransformFeedback};
+ return kErrorVertexBufferBoundForTransformFeedback;
}
}
}
- return {GL_NO_ERROR, nullptr};
+ return nullptr;
}
bool ValidateDrawBase(Context *context, PrimitiveMode mode, GLsizei count)
@@ -2768,17 +2771,15 @@
const State &state = context->getGLState();
- const ErrorAndMessage &errorAndMessage = ValidateDrawStates(context);
- if (errorAndMessage.errorType != GL_NO_ERROR)
+ const char *errorMessage = ValidateDrawStates(context);
+ if (errorMessage)
{
- if (errorAndMessage.message)
- {
- context->handleError(Error(errorAndMessage.errorType, errorAndMessage.message));
- }
- else
- {
- context->handleError(Error(errorAndMessage.errorType));
- }
+ // All errors from ValidateDrawStates should return INVALID_OPERATION except Framebuffer
+ // Incomplete.
+ GLenum errorCode =
+ (errorMessage == kErrorDrawFramebufferIncomplete ? GL_INVALID_FRAMEBUFFER_OPERATION
+ : GL_INVALID_OPERATION);
+ context->handleError(Error(errorCode, errorMessage));
return false;
}