From 86926a18c499d18389a10c94f9f984925fae0d9b Mon Sep 17 00:00:00 2001 From: Philip Rideout Date: Wed, 20 Dec 2017 15:52:51 -0800 Subject: [PATCH] Add preliminary dEQP multiview test. This is a pretty basic test of multiview, we'll be enhancing the test in the near future to provide coverage for additional texture formats. Test: Passes on Pixel 2 hardware, ran dEQP with --deqp-case=dEQP-GLES3.functional.multiview.* Change-Id: I16e855641da04e3a09e54d82808f1034e87bc4fc Component: AOSP --- Android.mk | 1 + android/cts/master/gles3-master.txt | 3 + modules/gles3/functional/CMakeLists.txt | 2 + modules/gles3/functional/es3fFunctionalTests.cpp | 2 + modules/gles3/functional/es3fMultiviewTests.cpp | 359 +++++++++++++++++++++++ modules/gles3/functional/es3fMultiviewTests.hpp | 55 ++++ 6 files changed, 422 insertions(+) create mode 100644 modules/gles3/functional/es3fMultiviewTests.cpp create mode 100644 modules/gles3/functional/es3fMultiviewTests.hpp diff --git a/Android.mk b/Android.mk index 68e62b8..ae8de10 100644 --- a/Android.mk +++ b/Android.mk @@ -712,6 +712,7 @@ LOCAL_SRC_FILES := \ modules/gles3/functional/es3fInternalFormatQueryTests.cpp \ modules/gles3/functional/es3fLifetimeTests.cpp \ modules/gles3/functional/es3fMultisampleTests.cpp \ + modules/gles3/functional/es3fMultiviewTests.cpp \ modules/gles3/functional/es3fNegativeBufferApiTests.cpp \ modules/gles3/functional/es3fNegativeFragmentApiTests.cpp \ modules/gles3/functional/es3fNegativeShaderApiTests.cpp \ diff --git a/android/cts/master/gles3-master.txt b/android/cts/master/gles3-master.txt index 8156022..c321527 100644 --- a/android/cts/master/gles3-master.txt +++ b/android/cts/master/gles3-master.txt @@ -30428,6 +30428,9 @@ dEQP-GLES3.functional.fbo.msaa.8_samples.depth_component16 dEQP-GLES3.functional.fbo.msaa.8_samples.depth32f_stencil8 dEQP-GLES3.functional.fbo.msaa.8_samples.depth24_stencil8 dEQP-GLES3.functional.fbo.msaa.8_samples.stencil_index8 +dEQP-GLES3.functional.fbo.multiview.samples_1 +dEQP-GLES3.functional.fbo.multiview.samples_2 +dEQP-GLES3.functional.fbo.multiview.samples_4 dEQP-GLES3.functional.fbo.invalidate.default.render_none dEQP-GLES3.functional.fbo.invalidate.default.render_color dEQP-GLES3.functional.fbo.invalidate.default.render_depth diff --git a/modules/gles3/functional/CMakeLists.txt b/modules/gles3/functional/CMakeLists.txt index 1adc70e..be74b19 100644 --- a/modules/gles3/functional/CMakeLists.txt +++ b/modules/gles3/functional/CMakeLists.txt @@ -53,6 +53,8 @@ set(DEQP_GLES3_FUNCTIONAL_SRCS es3fFunctionalTests.hpp es3fLifetimeTests.cpp es3fLifetimeTests.hpp + es3fMultiviewTests.cpp + es3fMultiviewTests.hpp es3fPrerequisiteTests.cpp es3fPrerequisiteTests.hpp es3fRasterizationTests.cpp diff --git a/modules/gles3/functional/es3fFunctionalTests.cpp b/modules/gles3/functional/es3fFunctionalTests.cpp index 5a57831..1e352da 100644 --- a/modules/gles3/functional/es3fFunctionalTests.cpp +++ b/modules/gles3/functional/es3fFunctionalTests.cpp @@ -47,6 +47,7 @@ #include "es3fBlendTests.hpp" #include "es3fRandomFragmentOpTests.hpp" #include "es3fMultisampleTests.hpp" +#include "es3fMultiviewTests.hpp" #include "es3fImplementationLimitTests.hpp" #include "es3fDitheringTests.hpp" #include "es3fClippingTests.hpp" @@ -272,6 +273,7 @@ public: addChild(new FboStencilTests (m_context)); addChild(new FramebufferBlitTests (m_context)); addChild(new FboMultisampleTests (m_context)); + addChild(new MultiviewTests (m_context)); addChild(new FboInvalidateTests (m_context)); } }; diff --git a/modules/gles3/functional/es3fMultiviewTests.cpp b/modules/gles3/functional/es3fMultiviewTests.cpp new file mode 100644 index 0000000..09cf487 --- /dev/null +++ b/modules/gles3/functional/es3fMultiviewTests.cpp @@ -0,0 +1,359 @@ +/*------------------------------------------------------------------------- + * drawElements Quality Program OpenGL ES 3.0 Module + * ------------------------------------------------- + * + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ /*! + * \file + * \brief Multiview tests. + * Tests functionality provided by the three multiview extensions. + * Note that this file is formatted using external/openglcts/.clang-format + */ /*--------------------------------------------------------------------*/ + +#include "es3fMultiviewTests.hpp" + +#include "deString.h" +#include "deStringUtil.hpp" +#include "gluContextInfo.hpp" +#include "gluPixelTransfer.hpp" +#include "gluShaderProgram.hpp" +#include "glw.h" +#include "glwEnums.hpp" +#include "glwFunctions.hpp" +#include "tcuRenderTarget.hpp" +#include "tcuSurface.hpp" +#include "tcuTestLog.hpp" +#include "tcuVector.hpp" + +using tcu::TestLog; +using tcu::Vec4; + +namespace deqp +{ +namespace gles3 +{ +namespace Functional +{ + +static const int NUM_CASE_ITERATIONS = 1; +static const float UNIT_SQUARE[16] = { + 1.0f, 1.0f, 0.05f, 1.0f, // Vertex 0 + 1.0f, -1.0f, 0.05f, 1.0f, // Vertex 1 + -1.0f, 1.0f, 0.05f, 1.0f, // Vertex 2 + -1.0f, -1.0f, 0.05f, 1.0f // Vertex 3 +}; +static const float COLOR_VALUES[] = { + 1, 0, 0, 1, // Red for level 0 + 0, 1, 0, 1, // Green for level 1 +}; + +class MultiviewCase : public TestCase +{ +public: + MultiviewCase(Context& context, const char* name, const char* description, int numSamples); + ~MultiviewCase(); + void init(); + void deinit(); + IterateResult iterate(); + +private: + MultiviewCase(const MultiviewCase& other); + MultiviewCase& operator=(const MultiviewCase& other); + void setupFramebufferObjects(); + void deleteFramebufferObjects(); + + glu::ShaderProgram* m_multiviewProgram; + deUint32 m_multiviewFbo; + deUint32 m_arrayTexture; + + glu::ShaderProgram* m_finalProgram; + + int m_caseIndex; + const int m_numSamples; + const int m_width; + const int m_height; +}; + +MultiviewCase::MultiviewCase(Context& context, const char* name, const char* description, int numSamples) + : TestCase(context, name, description) + , m_multiviewProgram(DE_NULL) + , m_multiviewFbo(0) + , m_arrayTexture(0) + , m_finalProgram(DE_NULL) + , m_caseIndex(0) + , m_numSamples(numSamples) + , m_width(512) + , m_height(512) +{ +} + +MultiviewCase::~MultiviewCase() +{ + MultiviewCase::deinit(); +} + +void MultiviewCase::setupFramebufferObjects() +{ + const glw::Functions& gl = m_context.getRenderContext().getFunctions(); + + // First create the array texture and multiview FBO. + + gl.genTextures(1, &m_arrayTexture); + gl.bindTexture(GL_TEXTURE_2D_ARRAY, m_arrayTexture); + gl.texStorage3D(GL_TEXTURE_2D_ARRAY, 1 /* num mipmaps */, GL_RGBA8, m_width / 2, m_height, 2 /* num levels */); + gl.texParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + gl.texParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + GLU_EXPECT_NO_ERROR(gl.getError(), "Create array texture"); + + gl.genFramebuffers(1, &m_multiviewFbo); + gl.bindFramebuffer(GL_FRAMEBUFFER, m_multiviewFbo); + if (m_numSamples == 1) + { + gl.framebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_arrayTexture, 0 /* mip level */, + 0 /* base view index */, 2 /* num views */); + } + else + { + gl.framebufferTextureMultisampleMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_arrayTexture, + 0 /* mip level */, m_numSamples /* samples */, + 0 /* base view index */, 2 /* num views */); + } + GLU_EXPECT_NO_ERROR(gl.getError(), "Create multiview FBO"); + deUint32 fboStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER); + if (fboStatus == GL_FRAMEBUFFER_UNSUPPORTED) + { + throw tcu::NotSupportedError("Framebuffer unsupported", "", __FILE__, __LINE__); + } + else if (fboStatus != GL_FRAMEBUFFER_COMPLETE) + { + throw tcu::TestError("Failed to create framebuffer object", "", __FILE__, __LINE__); + } +} + +void MultiviewCase::deleteFramebufferObjects() +{ + const glw::Functions& gl = m_context.getRenderContext().getFunctions(); + gl.deleteTextures(1, &m_arrayTexture); + gl.deleteFramebuffers(1, &m_multiviewFbo); +} + +void MultiviewCase::init() +{ + const glu::ContextInfo& contextInfo = m_context.getContextInfo(); + bool mvsupported = contextInfo.isExtensionSupported("GL_OVR_multiview"); + if (!mvsupported) + { + TCU_THROW(NotSupportedError, "Multiview is not supported"); + } + + if (m_numSamples > 1) + { + bool msaasupported = contextInfo.isExtensionSupported("GL_OVR_multiview_multisampled_render_to_texture"); + if (!msaasupported) + { + TCU_THROW(NotSupportedError, "Implicit MSAA multiview is not supported"); + } + } + + const char* multiviewVertexShader = "#version 300 es\n" + "#extension GL_OVR_multiview : enable\n" + "layout(num_views=2) in;\n" + "layout(location = 0) in mediump vec4 a_position;\n" + "uniform mediump vec4 uColor[2];\n" + "out mediump vec4 vColor;\n" + "void main() {\n" + " vColor = uColor[gl_ViewID_OVR];\n" + " gl_Position = a_position;\n" + "}\n"; + + const char* multiviewFragmentShader = "#version 300 es\n" + "layout(location = 0) out mediump vec4 dEQP_FragColor;\n" + "in mediump vec4 vColor;\n" + "void main() {\n" + " dEQP_FragColor = vColor;\n" + "}\n"; + + m_multiviewProgram = new glu::ShaderProgram( + m_context.getRenderContext(), glu::makeVtxFragSources(multiviewVertexShader, multiviewFragmentShader)); + DE_ASSERT(!m_multiviewProgram); + if (!m_multiviewProgram->isOk()) + { + m_testCtx.getLog() << *m_multiviewProgram; + TCU_FAIL("Failed to compile multiview shader"); + } + + // Draw the first layer on the left half of the screen and the second layer + // on the right half. + const char* finalVertexShader = "#version 300 es\n" + "layout(location = 0) in mediump vec4 a_position;\n" + "out highp vec3 vTexCoord;\n" + "void main() {\n" + " vTexCoord.x = fract(a_position.x + 1.0);\n" + " vTexCoord.y = .5 * (a_position.y + 1.0);\n" + " vTexCoord.z = a_position.x;\n" + " gl_Position = a_position;\n" + "}\n"; + + const char* finalFragmentShader = "#version 300 es\n" + "layout(location = 0) out mediump vec4 dEQP_FragColor;\n" + "uniform sampler2DArray uArrayTexture;\n" + "in highp vec3 vTexCoord;\n" + "void main() {\n" + " vec3 uvw = vTexCoord;\n" + " uvw.z = floor(vTexCoord.z + 1.0);\n" + " dEQP_FragColor = texture(uArrayTexture, uvw);\n" + "}\n"; + + m_finalProgram = new glu::ShaderProgram(m_context.getRenderContext(), + glu::makeVtxFragSources(finalVertexShader, finalFragmentShader)); + DE_ASSERT(!m_finalProgram); + if (!m_finalProgram->isOk()) + { + m_testCtx.getLog() << *m_finalProgram; + TCU_FAIL("Failed to compile final shader"); + } + + m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); + GLU_CHECK_MSG("Case initialization finished"); +} + +void MultiviewCase::deinit() +{ + deleteFramebufferObjects(); + delete m_multiviewProgram; + m_multiviewProgram = DE_NULL; + delete m_finalProgram; + m_finalProgram = DE_NULL; +} + +MultiviewCase::IterateResult MultiviewCase::iterate() +{ + TestLog& log = m_testCtx.getLog(); + deUint32 colorUniform = glGetUniformLocation(m_multiviewProgram->getProgram(), "uColor"); + std::string header = "Case iteration " + de::toString(m_caseIndex + 1) + " / " + de::toString(NUM_CASE_ITERATIONS); + log << TestLog::Section(header, header); + + DE_ASSERT(m_multiviewProgram); + + // Create and bind the multiview FBO. + + try + { + setupFramebufferObjects(); + } + catch (tcu::NotSupportedError& e) + { + log << TestLog::Message << "ERROR: " << e.what() << "." << TestLog::EndMessage << TestLog::EndSection; + m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Not supported"); + return STOP; + } + catch (tcu::InternalError& e) + { + log << TestLog::Message << "ERROR: " << e.what() << "." << TestLog::EndMessage << TestLog::EndSection; + m_testCtx.setTestResult(QP_TEST_RESULT_INTERNAL_ERROR, "Error"); + return STOP; + } + + // Draw full screen quad into the multiview framebuffer. + // The quad should be instanced into both layers of the array texture. + + const glw::Functions& gl = m_context.getRenderContext().getFunctions(); + gl.bindFramebuffer(GL_FRAMEBUFFER, m_multiviewFbo); + gl.viewport(0, 0, m_width / 2, m_height); + gl.useProgram(m_multiviewProgram->getProgram()); + gl.uniform4fv(colorUniform, 2, COLOR_VALUES); + gl.enableVertexAttribArray(0); + gl.vertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, &UNIT_SQUARE[0]); + gl.drawArrays(GL_TRIANGLE_STRIP, 0, 4); + + // Sample from the array texture to draw a quad into the backbuffer. + + const int backbufferWidth = m_context.getRenderTarget().getWidth(); + const int backbufferHeight = m_context.getRenderTarget().getHeight(); + gl.bindFramebuffer(GL_FRAMEBUFFER, 0); + gl.viewport(0, 0, backbufferWidth, backbufferHeight); + gl.useProgram(m_finalProgram->getProgram()); + gl.bindTexture(GL_TEXTURE_2D_ARRAY, m_arrayTexture); + gl.drawArrays(GL_TRIANGLE_STRIP, 0, 4); + + // Read back the framebuffer, ensure that the left half is red and the + // right half is green. + + tcu::Surface pixels(backbufferWidth, backbufferHeight); + glu::readPixels(m_context.getRenderContext(), 0, 0, pixels.getAccess()); + bool failed = false; + for (int y = 0; y < backbufferHeight; y++) + { + for (int x = 0; x < backbufferWidth; x++) + { + tcu::RGBA pixel = pixels.getPixel(x, y); + if (x < backbufferWidth / 2) + { + if (pixel.getRed() != 255 || pixel.getGreen() != 0 || pixel.getBlue() != 0) + { + failed = true; + } + } + else + { + if (pixel.getRed() != 0 || pixel.getGreen() != 255 || pixel.getBlue() != 0) + { + failed = true; + } + } + if (failed) + { + break; + } + } + } + + deleteFramebufferObjects(); + + if (failed) + { + log << TestLog::Image("Result image", "Result image", pixels); + } + + log << TestLog::Message << "Test result: " << (failed ? "Failed!" : "Passed!") << TestLog::EndMessage; + + if (failed) + { + m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); + return STOP; + } + + return (++m_caseIndex < NUM_CASE_ITERATIONS) ? CONTINUE : STOP; +} + +MultiviewTests::MultiviewTests(Context& context) : TestCaseGroup(context, "multiview", "Multiview Tests") +{ +} + +MultiviewTests::~MultiviewTests() +{ +} + +void MultiviewTests::init() +{ + addChild(new MultiviewCase(m_context, "samples_1", "Multiview test without multisampling", 1)); + addChild(new MultiviewCase(m_context, "samples_2", "Multiview test with MSAAx2", 2)); + addChild(new MultiviewCase(m_context, "samples_4", "Multiview test without MSAAx4", 4)); +} + +} // namespace Functional +} // namespace gles3 +} // namespace deqp diff --git a/modules/gles3/functional/es3fMultiviewTests.hpp b/modules/gles3/functional/es3fMultiviewTests.hpp new file mode 100644 index 0000000..e13bcba --- /dev/null +++ b/modules/gles3/functional/es3fMultiviewTests.hpp @@ -0,0 +1,55 @@ +#ifndef _ES3FMULTIVIEWTESTS_HPP +#define _ES3FMULTIVIEWTESTS_HPP +/*------------------------------------------------------------------------- + * drawElements Quality Program OpenGL ES 3.0 Module + * ------------------------------------------------- + * + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ /*! + * \file + * \brief Multiview tests. + * Tests functionality provided by the three multiview extensions. + * Note that this file is formatted using external/openglcts/.clang-format +*/ /*--------------------------------------------------------------------*/ + +#include "tcuDefs.hpp" +#include "tes3TestCase.hpp" + +namespace deqp +{ +namespace gles3 +{ +namespace Functional +{ + +class MultiviewTests : public TestCaseGroup +{ +public: + MultiviewTests(Context& context); + ~MultiviewTests(); + + void init(); + +private: + MultiviewTests(const MultiviewTests& other); + MultiviewTests& operator=(const MultiviewTests& other); +}; + +} // namespace Functional +} // namespace gles3 +} // namespace deqp + +#endif // _ES3FMULTIVIEWTESTS_HPP -- 2.7.4