Add preliminary dEQP multiview test.
authorPhilip Rideout <prideout@google.com>
Wed, 20 Dec 2017 23:52:51 +0000 (15:52 -0800)
committerPhilip Rideout <prideout@google.com>
Fri, 12 Jan 2018 22:14:32 +0000 (14:14 -0800)
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
android/cts/master/gles3-master.txt
modules/gles3/functional/CMakeLists.txt
modules/gles3/functional/es3fFunctionalTests.cpp
modules/gles3/functional/es3fMultiviewTests.cpp [new file with mode: 0644]
modules/gles3/functional/es3fMultiviewTests.hpp [new file with mode: 0644]

index 68e62b8..ae8de10 100644 (file)
@@ -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 \
index 8156022..c321527 100644 (file)
@@ -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
index 1adc70e..be74b19 100644 (file)
@@ -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
index 5a57831..1e352da 100644 (file)
@@ -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 (file)
index 0000000..09cf487
--- /dev/null
@@ -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 (file)
index 0000000..e13bcba
--- /dev/null
@@ -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