Commit 14a26aea by Martin Radev Committed by Commit Bot

Disallow indirect draw calls for multi-view framebuffers

According to the ANGLE_multiview spec indirect draw calls must generate an INVALID_OPERATION error if the number of views in the active draw framebuffer is greater than 1. The patch addresses this by extending the indirect draw call validation. BUG=angleproject:2062 TEST=angle_end2end_tests Change-Id: Ic30ef9a0eabba454aeea6176df1be8bd2ccd9783 Reviewed-on: https://chromium-review.googlesource.com/583027Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org> Commit-Queue: Martin Radev <mradev@nvidia.com>
parent 4c56c607
......@@ -1604,4 +1604,14 @@ int Framebuffer::getSamples(const ValidationContext *context)
return getSamples(static_cast<const Context *>(context));
}
GLsizei Framebuffer::getNumViews() const
{
const FramebufferAttachment *attachment = getFirstNonNullAttachment();
if (attachment == nullptr)
{
return FramebufferAttachment::kDefaultNumViews;
}
return attachment->getNumViews();
}
} // namespace gl
......@@ -172,6 +172,7 @@ class Framebuffer final : public LabeledObject, public OnAttachmentDirtyReceiver
const FramebufferAttachment *getFirstNonNullAttachment() const;
const FramebufferAttachment *getAttachment(GLenum attachment) const;
GLsizei getNumViews() const;
size_t getDrawbufferStateCount() const;
GLenum getDrawBufferState(size_t drawBuffer) const;
......
......@@ -172,6 +172,19 @@ bool ValidateDrawIndirectBase(Context *context, GLenum mode, const void *indirec
return false;
}
// ANGLE_multiview spec, revision 1:
// An INVALID_OPERATION is generated by DrawArraysIndirect and DrawElementsIndirect if the
// number of views in the draw framebuffer is greater than 1.
const Framebuffer *drawFramebuffer = context->getGLState().getDrawFramebuffer();
ASSERT(drawFramebuffer != nullptr);
if (drawFramebuffer->getNumViews() > 1)
{
context->handleError(
InvalidOperation()
<< "The number of views in the active draw framebuffer is greater than 1.");
return false;
}
return true;
}
......
......@@ -55,6 +55,7 @@
'<(angle_path)/src/tests/gl_tests/MaxTextureSizeTest.cpp',
'<(angle_path)/src/tests/gl_tests/MipmapTest.cpp',
'<(angle_path)/src/tests/gl_tests/MultisampleCompatibilityTest.cpp',
'<(angle_path)/src/tests/gl_tests/MultiviewDrawTest.cpp',
'<(angle_path)/src/tests/gl_tests/media/pixel.inl',
'<(angle_path)/src/tests/gl_tests/PackUnpackTest.cpp',
'<(angle_path)/src/tests/gl_tests/PathRenderingTest.cpp',
......
//
// Copyright 2017 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Multiview draw tests:
// Test issuing multiview Draw* commands.
//
#include "test_utils/ANGLETest.h"
#include "test_utils/gl_raii.h"
using namespace angle;
class MultiviewDrawTest : public ANGLETest
{
protected:
MultiviewDrawTest()
{
setWindowWidth(128);
setWindowHeight(128);
setWebGLCompatibilityEnabled(true);
}
void SetUp() override
{
ANGLETest::SetUp();
glRequestExtensionANGLE = reinterpret_cast<PFNGLREQUESTEXTENSIONANGLEPROC>(
eglGetProcAddress("glRequestExtensionANGLE"));
}
// Requests the ANGLE_multiview extension and returns true if the operation succeeds.
bool requestMultiviewExtension()
{
if (extensionRequestable("GL_ANGLE_multiview"))
{
glRequestExtensionANGLE("GL_ANGLE_multiview");
}
if (!extensionEnabled("GL_ANGLE_multiview"))
{
std::cout << "Test skipped due to missing GL_ANGLE_multiview." << std::endl;
return false;
}
return true;
}
PFNGLREQUESTEXTENSIONANGLEPROC glRequestExtensionANGLE = nullptr;
};
// The test verifies that glDraw*Indirect:
// 1) generates an INVALID_OPERATION error if the number of views in the draw framebuffer is greater
// than 1.
// 2) does not generate any error if the draw framebuffer has exactly 1 view.
TEST_P(MultiviewDrawTest, IndirectDraw)
{
if (!requestMultiviewExtension())
{
return;
}
GLTexture tex2d;
glBindTexture(GL_TEXTURE_2D, tex2d);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
const GLint viewportOffsets[4] = {0, 0, 2, 0};
ASSERT_GL_NO_ERROR();
const std::string fsSource =
"#version 300 es\n"
"#extension GL_OVR_multiview : require\n"
"precision mediump float;\n"
"void main()\n"
"{}\n";
GLVertexArray vao;
glBindVertexArray(vao);
const float kVertexData[3] = {0.0f};
const unsigned int kIndices[3] = {0u, 1u, 2u};
GLBuffer vbo;
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 3u, &kVertexData[0], GL_STATIC_DRAW);
ASSERT_GL_NO_ERROR();
GLBuffer ibo;
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned int) * 3, &kIndices[0], GL_STATIC_DRAW);
ASSERT_GL_NO_ERROR();
GLBuffer commandBuffer;
glBindBuffer(GL_DRAW_INDIRECT_BUFFER, commandBuffer);
const GLuint commandData[] = {1u, 1u, 0u, 0u, 0u};
glBufferData(GL_DRAW_INDIRECT_BUFFER, sizeof(GLuint) * 5u, &commandData[0], GL_STATIC_DRAW);
ASSERT_GL_NO_ERROR();
GLFramebuffer framebuffer;
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
// Check for a GL_INVALID_OPERATION error with the framebuffer having 2 views.
{
const std::string &vsSource =
"#version 300 es\n"
"#extension GL_OVR_multiview : require\n"
"layout(num_views = 2) in;\n"
"void main()\n"
"{}\n";
ANGLE_GL_PROGRAM(program, vsSource, fsSource);
glUseProgram(program);
glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2d, 0,
2, &viewportOffsets[0]);
glDrawArraysIndirect(GL_TRIANGLES, nullptr);
EXPECT_GL_ERROR(GL_INVALID_OPERATION);
glDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_INT, nullptr);
EXPECT_GL_ERROR(GL_INVALID_OPERATION);
}
// Check that no errors are generated if the number of views is 1.
{
const std::string &vsSource =
"#version 300 es\n"
"#extension GL_OVR_multiview : require\n"
"layout(num_views = 1) in;\n"
"void main()\n"
"{}\n";
ANGLE_GL_PROGRAM(program, vsSource, fsSource);
glUseProgram(program);
glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2d, 0,
1, &viewportOffsets[0]);
glDrawArraysIndirect(GL_TRIANGLES, nullptr);
EXPECT_GL_NO_ERROR();
glDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_INT, nullptr);
EXPECT_GL_NO_ERROR();
}
}
ANGLE_INSTANTIATE_TEST(MultiviewDrawTest, ES31_OPENGL());
\ No newline at end of file
......@@ -44,6 +44,7 @@ class GLWrapper
GLuint mHandle = 0;
};
using GLVertexArray = GLWrapper<glGenVertexArrays, glDeleteVertexArrays>;
using GLBuffer = GLWrapper<glGenBuffers, glDeleteBuffers>;
using GLTexture = GLWrapper<glGenTextures, glDeleteTextures>;
using GLFramebuffer = GLWrapper<glGenFramebuffers, glDeleteFramebuffers>;
......
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