Commit 70d79b76 by Jonah Ryan-Davis Committed by Commit Bot

GL: Add state validation functions to GL backend

These functions validate that the driver's reported state matches ANGLE's internal state. Can be useful for debugging Bug: angleproject:3900 Change-Id: I35d15e991986dcab114939c551a88549f09bd263 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1797254 Commit-Queue: Jonah Ryan-Davis <jonahr@google.com> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent 33ffed01
......@@ -253,6 +253,11 @@ std::ostream &FmtHex(std::ostream &os, T value)
# define EVENT(message, ...) (void(0))
#endif
// The state tracked by ANGLE will be validated with the driver state before each call
#if defined(ANGLE_ENABLE_ASSERTS)
# define ANGLE_STATE_VALIDATION_ENABLED
#endif
#if defined(__GNUC__)
# define ANGLE_CRASH() __builtin_trap()
#else
......
......@@ -221,6 +221,10 @@ ANGLE_INLINE angle::Result ContextGL::setDrawArraysState(const gl::Context *cont
ANGLE_TRY(vaoGL->syncClientSideData(context, program->getActiveAttribLocationsMask(), first,
count, instanceCount));
#if defined(ANGLE_STATE_VALIDATION_ENABLED)
vaoGL->validateState();
#endif // ANGLE_STATE_VALIDATION_ENABLED
}
return angle::Result::Continue;
......@@ -252,6 +256,11 @@ ANGLE_INLINE angle::Result ContextGL::setDrawElementsState(const gl::Context *co
*outIndices = indices;
}
#if defined(ANGLE_STATE_VALIDATION_ENABLED)
const VertexArrayGL *vaoGL = GetImplAs<VertexArrayGL>(vao);
vaoGL->validateState();
#endif // ANGLE_STATE_VALIDATION_ENABLED
return angle::Result::Continue;
}
......@@ -264,6 +273,10 @@ angle::Result ContextGL::drawArrays(const gl::Context *context,
const bool usesMultiview = program->usesMultiview();
const GLsizei instanceCount = usesMultiview ? program->getNumViews() : 0;
#if defined(ANGLE_STATE_VALIDATION_ENABLED)
validateState();
#endif
ANGLE_TRY(setDrawArraysState(context, first, count, instanceCount));
if (!usesMultiview)
{
......@@ -424,6 +437,10 @@ angle::Result ContextGL::drawElements(const gl::Context *context,
const GLsizei instanceCount = usesMultiview ? program->getNumViews() : 0;
const void *drawIndexPtr = nullptr;
#if defined(ANGLE_STATE_VALIDATION_ENABLED)
validateState();
#endif // ANGLE_STATE_VALIDATION_ENABLED
ANGLE_TRY(setDrawElementsState(context, count, type, indices, instanceCount, &drawIndexPtr));
if (!usesMultiview)
{
......@@ -780,4 +797,10 @@ void ContextGL::invalidateTexture(gl::TextureType target)
mRenderer->getStateManager()->invalidateTexture(target);
}
void ContextGL::validateState() const
{
const StateManagerGL *stateManager = mRenderer->getStateManager();
stateManager->validateState();
}
} // namespace rx
......@@ -242,6 +242,8 @@ class ContextGL : public ContextImpl
void invalidateTexture(gl::TextureType target) override;
void validateState() const;
private:
angle::Result setDrawArraysState(const gl::Context *context,
GLint first,
......
......@@ -34,6 +34,28 @@
namespace rx
{
namespace
{
static void ValidateStateHelper(const FunctionsGL *functions,
const GLuint localValue,
const GLenum pname,
const char *localName,
const char *driverName)
{
GLint queryValue;
functions->getIntegerv(pname, &queryValue);
if (localValue != static_cast<GLuint>(queryValue))
{
WARN() << localName << " (" << localValue << ") != " << driverName << " (" << queryValue
<< ")";
// Re-add ASSERT: http://anglebug.com/3900
// ASSERT(false);
}
}
} // anonymous namespace
StateManagerGL::IndexedBufferBinding::IndexedBufferBinding() : offset(0), size(0), buffer(0) {}
StateManagerGL::StateManagerGL(const FunctionsGL *functions,
......@@ -2113,4 +2135,34 @@ void StateManagerGL::syncTransformFeedbackState(const gl::Context *context)
mCurrentTransformFeedback = nullptr;
}
}
void StateManagerGL::validateState() const
{
// Current program
ValidateStateHelper(mFunctions, mProgram, GL_CURRENT_PROGRAM, "mProgram", "GL_CURRENT_PROGRAM");
// Buffers
for (gl::BufferBinding bindingType : angle::AllEnums<gl::BufferBinding>())
{
// These binding types need compute support to be queried
if (bindingType == gl::BufferBinding::AtomicCounter ||
bindingType == gl::BufferBinding::DispatchIndirect ||
bindingType == gl::BufferBinding::ShaderStorage)
{
if (!nativegl::SupportsCompute(mFunctions))
{
continue;
}
}
GLenum bindingTypeGL = nativegl::GetBufferBindingQuery(bindingType);
std::string localName = "mBuffers[" + ToString(bindingType) + "]";
ValidateStateHelper(mFunctions, mBuffers[bindingType], bindingTypeGL, localName.c_str(),
nativegl::GetBufferBindingString(bindingType).c_str());
}
// Vertex array object
ValidateStateHelper(mFunctions, mVAO, GL_VERTEX_ARRAY_BINDING, "mVAO",
"GL_VERTEX_ARRAY_BINDING");
}
} // namespace rx
......@@ -184,6 +184,8 @@ class StateManagerGL final : angle::NonCopyable
}
GLuint getBufferID(gl::BufferBinding binding) const { return mBuffers[binding]; }
void validateState() const;
private:
void setTextureCubemapSeamlessEnabled(bool enabled);
......
......@@ -49,6 +49,41 @@ GLuint GetAdjustedDivisor(GLuint numViews, GLuint divisor)
return numViews * divisor;
}
static void ValidateStateHelperGetIntegerv(const FunctionsGL *functions,
const GLuint localValue,
const GLenum pname,
const char *localName,
const char *driverName)
{
GLint queryValue;
functions->getIntegerv(pname, &queryValue);
if (localValue != static_cast<GLuint>(queryValue))
{
WARN() << localName << " (" << localValue << ") != " << driverName << " (" << queryValue
<< ")";
// Re-add ASSERT: http://anglebug.com/3900
// ASSERT(false);
}
}
static void ValidateStateHelperGetVertexAttribiv(const FunctionsGL *functions,
const GLint index,
const GLuint localValue,
const GLenum pname,
const char *localName,
const char *driverName)
{
GLint queryValue;
functions->getVertexAttribiv(index, pname, &queryValue);
if (localValue != static_cast<GLuint>(queryValue))
{
WARN() << localName << "[" << index << "] (" << localValue << ") != " << driverName << "["
<< index << "] (" << queryValue << ")";
// Re-add ASSERT: http://anglebug.com/3900
// ASSERT(false);
}
}
} // anonymous namespace
VertexArrayGL::VertexArrayGL(const VertexArrayState &state,
......@@ -740,4 +775,100 @@ void VertexArrayGL::applyActiveAttribLocationsMask(const gl::AttributesMask &act
}
}
void VertexArrayGL::validateState() const
{
// Ensure this vao is currently bound
ValidateStateHelperGetIntegerv(mFunctions, mVertexArrayID, GL_VERTEX_ARRAY_BINDING,
"mVertexArrayID", "GL_VERTEX_ARRAY_BINDING");
// Element array buffer
if (mAppliedElementArrayBuffer.get() == nullptr)
{
ValidateStateHelperGetIntegerv(
mFunctions, mStreamingElementArrayBuffer, GL_ELEMENT_ARRAY_BUFFER_BINDING,
"mAppliedElementArrayBuffer", "GL_ELEMENT_ARRAY_BUFFER_BINDING");
}
else
{
const BufferGL *bufferGL = GetImplAs<BufferGL>(mAppliedElementArrayBuffer.get());
ValidateStateHelperGetIntegerv(
mFunctions, bufferGL->getBufferID(), GL_ELEMENT_ARRAY_BUFFER_BINDING,
"mAppliedElementArrayBuffer", "GL_ELEMENT_ARRAY_BUFFER_BINDING");
}
// ValidateStateHelperGetIntegerv but with > comparison instead of !=
GLint queryValue;
mFunctions->getIntegerv(GL_MAX_VERTEX_ATTRIBS, &queryValue);
if (mAppliedAttributes.size() > static_cast<GLuint>(queryValue))
{
WARN() << "mAppliedAttributes.size() (" << mAppliedAttributes.size()
<< ") > GL_MAX_VERTEX_ATTRIBS (" << queryValue << ")";
// Re-add ASSERT: http://anglebug.com/3900
// ASSERT(false);
}
// Check each applied attribute/binding
for (GLuint index = 0; index < mAppliedAttributes.size(); index++)
{
VertexAttribute &attribute = mAppliedAttributes[index];
ASSERT(attribute.bindingIndex < mAppliedBindings.size());
VertexBinding &binding = mAppliedBindings[attribute.bindingIndex];
ValidateStateHelperGetVertexAttribiv(
mFunctions, index, attribute.enabled, GL_VERTEX_ATTRIB_ARRAY_ENABLED,
"mAppliedAttributes.enabled", "GL_VERTEX_ATTRIB_ARRAY_ENABLED");
if (attribute.enabled)
{
// Applied attributes
ASSERT(attribute.format);
ValidateStateHelperGetVertexAttribiv(
mFunctions, index, ToGLenum(attribute.format->vertexAttribType),
GL_VERTEX_ATTRIB_ARRAY_TYPE, "mAppliedAttributes.format->vertexAttribType",
"GL_VERTEX_ATTRIB_ARRAY_TYPE");
ValidateStateHelperGetVertexAttribiv(
mFunctions, index, attribute.format->channelCount, GL_VERTEX_ATTRIB_ARRAY_SIZE,
"attribute.format->channelCount", "GL_VERTEX_ATTRIB_ARRAY_SIZE");
ValidateStateHelperGetVertexAttribiv(
mFunctions, index, attribute.format->isNorm(), GL_VERTEX_ATTRIB_ARRAY_NORMALIZED,
"attribute.format->isNorm()", "GL_VERTEX_ATTRIB_ARRAY_NORMALIZED");
ValidateStateHelperGetVertexAttribiv(
mFunctions, index, attribute.format->isPureInt(), GL_VERTEX_ATTRIB_ARRAY_INTEGER,
"attribute.format->isPureInt()", "GL_VERTEX_ATTRIB_ARRAY_INTEGER");
if (supportVertexAttribBinding())
{
ValidateStateHelperGetVertexAttribiv(
mFunctions, index, attribute.relativeOffset, GL_VERTEX_ATTRIB_RELATIVE_OFFSET,
"attribute.relativeOffset", "GL_VERTEX_ATTRIB_RELATIVE_OFFSET");
ValidateStateHelperGetVertexAttribiv(
mFunctions, index, attribute.bindingIndex, GL_VERTEX_ATTRIB_BINDING,
"attribute.bindingIndex", "GL_VERTEX_ATTRIB_BINDING");
}
// Applied bindings
if (binding.getBuffer().get() == nullptr)
{
ValidateStateHelperGetVertexAttribiv(
mFunctions, index, mStreamingArrayBuffer, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING,
"mAppliedBindings.bufferID", "GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING");
}
else
{
const BufferGL *arrayBufferGL = GetImplAs<BufferGL>(binding.getBuffer().get());
ASSERT(arrayBufferGL);
ValidateStateHelperGetVertexAttribiv(
mFunctions, index, arrayBufferGL->getBufferID(),
GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, "mAppliedBindings.bufferID",
"GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING");
ValidateStateHelperGetVertexAttribiv(
mFunctions, index, binding.getStride(), GL_VERTEX_ATTRIB_ARRAY_STRIDE,
"binding.getStride()", "GL_VERTEX_ATTRIB_ARRAY_STRIDE");
ValidateStateHelperGetVertexAttribiv(
mFunctions, index, binding.getDivisor(), GL_VERTEX_ATTRIB_ARRAY_DIVISOR,
"binding.getDivisor()", "GL_VERTEX_ATTRIB_ARRAY_DIVISOR");
}
}
}
}
} // namespace rx
......@@ -56,6 +56,8 @@ class VertexArrayGL : public VertexArrayImpl
void applyNumViewsToDivisor(int numViews);
void applyActiveAttribLocationsMask(const gl::AttributesMask &activeMask);
void validateState() const;
private:
angle::Result syncDrawState(const gl::Context *context,
const gl::AttributesMask &activeAttributesMask,
......
......@@ -963,13 +963,7 @@ void GenerateCaps(const FunctionsGL *functions,
LimitVersion(maxSupportedESVersion, gl::Version(3, 0));
}
// OpenGL 4.2 is required for GL_ARB_compute_shader, some platform drivers have the extension,
// but their maximum supported GL versions are less than 4.2. Explicitly limit the minimum
// GL version to 4.2.
if (functions->isAtLeastGL(gl::Version(4, 3)) || functions->isAtLeastGLES(gl::Version(3, 1)) ||
(functions->isAtLeastGL(gl::Version(4, 2)) &&
functions->hasGLExtension("GL_ARB_compute_shader") &&
functions->hasGLExtension("GL_ARB_shader_storage_buffer_object")))
if (nativegl::SupportsCompute(functions))
{
for (GLuint index = 0u; index < 3u; ++index)
{
......@@ -1572,6 +1566,18 @@ void InitializeFrontendFeatures(const FunctionsGL *functions, angle::FrontendFea
namespace nativegl
{
bool SupportsCompute(const FunctionsGL *functions)
{
// OpenGL 4.2 is required for GL_ARB_compute_shader, some platform drivers have the extension,
// but their maximum supported GL versions are less than 4.2. Explicitly limit the minimum
// GL version to 4.2.
return (functions->isAtLeastGL(gl::Version(4, 3)) ||
functions->isAtLeastGLES(gl::Version(3, 1)) ||
(functions->isAtLeastGL(gl::Version(4, 2)) &&
functions->hasGLExtension("GL_ARB_compute_shader") &&
functions->hasGLExtension("GL_ARB_shader_storage_buffer_object")));
}
bool SupportsFenceSync(const FunctionsGL *functions)
{
return functions->isAtLeastGL(gl::Version(3, 2)) || functions->hasGLExtension("GL_ARB_sync") ||
......@@ -1669,6 +1675,47 @@ GLenum GetTextureBindingQuery(gl::TextureType textureType)
}
}
GLenum GetBufferBindingQuery(gl::BufferBinding bufferBinding)
{
switch (bufferBinding)
{
case gl::BufferBinding::Array:
return GL_ARRAY_BUFFER_BINDING;
case gl::BufferBinding::AtomicCounter:
return GL_ATOMIC_COUNTER_BUFFER_BINDING;
case gl::BufferBinding::CopyRead:
return GL_COPY_READ_BUFFER_BINDING;
case gl::BufferBinding::CopyWrite:
return GL_COPY_WRITE_BUFFER_BINDING;
case gl::BufferBinding::DispatchIndirect:
return GL_DISPATCH_INDIRECT_BUFFER_BINDING;
case gl::BufferBinding::DrawIndirect:
return GL_DRAW_INDIRECT_BUFFER_BINDING;
case gl::BufferBinding::ElementArray:
return GL_ELEMENT_ARRAY_BUFFER_BINDING;
case gl::BufferBinding::PixelPack:
return GL_PIXEL_PACK_BUFFER_BINDING;
case gl::BufferBinding::PixelUnpack:
return GL_PIXEL_UNPACK_BUFFER_BINDING;
case gl::BufferBinding::ShaderStorage:
return GL_SHADER_STORAGE_BUFFER_BINDING;
case gl::BufferBinding::TransformFeedback:
return GL_TRANSFORM_FEEDBACK_BUFFER_BINDING;
case gl::BufferBinding::Uniform:
return GL_UNIFORM_BUFFER_BINDING;
default:
UNREACHABLE();
return 0;
}
}
std::string GetBufferBindingString(gl::BufferBinding bufferBinding)
{
std::ostringstream os;
os << bufferBinding << "_BINDING";
return os.str();
}
} // namespace nativegl
const FunctionsGL *GetFunctionsGL(const gl::Context *context)
......
......@@ -96,6 +96,7 @@ void InitializeFrontendFeatures(const FunctionsGL *functions, angle::FrontendFea
namespace nativegl
{
bool SupportsCompute(const FunctionsGL *functions);
bool SupportsFenceSync(const FunctionsGL *functions);
bool SupportsOcclusionQueries(const FunctionsGL *functions);
bool SupportsNativeRendering(const FunctionsGL *functions,
......@@ -105,6 +106,8 @@ bool SupportsTexImage(gl::TextureType type);
bool UseTexImage2D(gl::TextureType textureType);
bool UseTexImage3D(gl::TextureType textureType);
GLenum GetTextureBindingQuery(gl::TextureType textureType);
GLenum GetBufferBindingQuery(gl::BufferBinding bufferBinding);
std::string GetBufferBindingString(gl::BufferBinding bufferBinding);
} // namespace nativegl
bool CanMapBufferForRead(const FunctionsGL *functions);
......
......@@ -6552,7 +6552,11 @@ TEST_P(GLSLTest_ES3, InitSameNameArray)
TEST_P(GLSLTest, FragData)
{
// Ensures that we don't regress and emit Vulkan layer warnings.
treatPlatformWarningsAsErrors();
// TODO(jonahr): http://anglebug.com/3900 - Remove check once warnings are cleaned up
if (IsVulkan())
{
treatPlatformWarningsAsErrors();
}
constexpr char kFS[] = R"(void main() { gl_FragData[0] = vec4(1, 0, 0, 1); })";
ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), kFS);
......
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