xref: /aosp_15_r20/external/deqp/modules/gles3/functional/es3fMultiviewTests.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program OpenGL ES 3.0 Module
3  * -------------------------------------------------
4  *
5  * Copyright 2018 The Android Open Source Project
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  */ /*!
20  * \file
21  * \brief Multiview tests.
22  * Tests functionality provided by the three multiview extensions.
23  */ /*--------------------------------------------------------------------*/
24 
25 #include "es3fMultiviewTests.hpp"
26 
27 #include "deString.h"
28 #include "deStringUtil.hpp"
29 #include "gluContextInfo.hpp"
30 #include "gluPixelTransfer.hpp"
31 #include "gluShaderProgram.hpp"
32 #include "glw.h"
33 #include "glwEnums.hpp"
34 #include "glwFunctions.hpp"
35 #include "tcuRenderTarget.hpp"
36 #include "tcuSurface.hpp"
37 #include "tcuTestLog.hpp"
38 #include "tcuVector.hpp"
39 
40 using tcu::TestLog;
41 using tcu::Vec4;
42 
43 namespace deqp
44 {
45 namespace gles3
46 {
47 namespace Functional
48 {
49 
50 static const int NUM_CASE_ITERATIONS = 1;
51 static const float UNIT_SQUARE[16]   = {
52     1.0f,  1.0f,  0.05f, 1.0f, // Vertex 0
53     1.0f,  -1.0f, 0.05f, 1.0f, // Vertex 1
54     -1.0f, 1.0f,  0.05f, 1.0f, // Vertex 2
55     -1.0f, -1.0f, 0.05f, 1.0f  // Vertex 3
56 };
57 static const float COLOR_VALUES[] = {
58     1, 0, 0, 1, // Red for level 0
59     0, 1, 0, 1, // Green for level 1
60 };
61 
62 class MultiviewCase : public TestCase
63 {
64 public:
65     MultiviewCase(Context &context, const char *name, const char *description, int numSamples);
66     ~MultiviewCase();
67     void init();
68     void deinit();
69     IterateResult iterate();
70 
71 private:
72     MultiviewCase(const MultiviewCase &other);
73     MultiviewCase &operator=(const MultiviewCase &other);
74     void setupFramebufferObjects();
75     void deleteFramebufferObjects();
76 
77     glu::ShaderProgram *m_multiviewProgram;
78     uint32_t m_multiviewFbo;
79     uint32_t m_arrayTexture;
80 
81     glu::ShaderProgram *m_finalProgram;
82 
83     int m_caseIndex;
84     const int m_numSamples;
85     const int m_width;
86     const int m_height;
87 };
88 
MultiviewCase(Context & context,const char * name,const char * description,int numSamples)89 MultiviewCase::MultiviewCase(Context &context, const char *name, const char *description, int numSamples)
90     : TestCase(context, name, description)
91     , m_multiviewProgram(DE_NULL)
92     , m_multiviewFbo(0)
93     , m_arrayTexture(0)
94     , m_finalProgram(DE_NULL)
95     , m_caseIndex(0)
96     , m_numSamples(numSamples)
97     , m_width(512)
98     , m_height(512)
99 {
100 }
101 
~MultiviewCase()102 MultiviewCase::~MultiviewCase()
103 {
104     MultiviewCase::deinit();
105 }
106 
setupFramebufferObjects()107 void MultiviewCase::setupFramebufferObjects()
108 {
109     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
110 
111     // First create the array texture and multiview FBO.
112 
113     gl.genTextures(1, &m_arrayTexture);
114     gl.bindTexture(GL_TEXTURE_2D_ARRAY, m_arrayTexture);
115     gl.texStorage3D(GL_TEXTURE_2D_ARRAY, 1 /* num mipmaps */, GL_RGBA8, m_width / 2, m_height, 2 /* num levels */);
116     gl.texParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
117     gl.texParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
118     GLU_EXPECT_NO_ERROR(gl.getError(), "Create array texture");
119 
120     gl.genFramebuffers(1, &m_multiviewFbo);
121     gl.bindFramebuffer(GL_FRAMEBUFFER, m_multiviewFbo);
122     if (m_numSamples == 1)
123     {
124         gl.framebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_arrayTexture, 0 /* mip level */,
125                                           0 /* base view index */, 2 /* num views */);
126     }
127     else
128     {
129         gl.framebufferTextureMultisampleMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_arrayTexture,
130                                                      0 /* mip level */, m_numSamples /* samples */,
131                                                      0 /* base view index */, 2 /* num views */);
132     }
133     GLU_EXPECT_NO_ERROR(gl.getError(), "Create multiview FBO");
134     uint32_t fboStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER);
135     if (fboStatus == GL_FRAMEBUFFER_UNSUPPORTED)
136     {
137         throw tcu::NotSupportedError("Framebuffer unsupported", "", __FILE__, __LINE__);
138     }
139     else if (fboStatus != GL_FRAMEBUFFER_COMPLETE)
140     {
141         throw tcu::TestError("Failed to create framebuffer object", "", __FILE__, __LINE__);
142     }
143 }
144 
deleteFramebufferObjects()145 void MultiviewCase::deleteFramebufferObjects()
146 {
147     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
148     gl.deleteTextures(1, &m_arrayTexture);
149     gl.deleteFramebuffers(1, &m_multiviewFbo);
150 }
151 
init()152 void MultiviewCase::init()
153 {
154     const glu::ContextInfo &contextInfo = m_context.getContextInfo();
155     bool mvsupported                    = contextInfo.isExtensionSupported("GL_OVR_multiview");
156     if (!mvsupported)
157     {
158         TCU_THROW(NotSupportedError, "Multiview is not supported");
159     }
160 
161     if (m_numSamples > 1)
162     {
163         bool msaasupported = contextInfo.isExtensionSupported("GL_OVR_multiview_multisampled_render_to_texture");
164         if (!msaasupported)
165         {
166             TCU_THROW(NotSupportedError, "Implicit MSAA multiview is not supported");
167         }
168     }
169 
170     const char *multiviewVertexShader = "#version 300 es\n"
171                                         "#extension GL_OVR_multiview : enable\n"
172                                         "layout(num_views=2) in;\n"
173                                         "layout(location = 0) in mediump vec4 a_position;\n"
174                                         "uniform mediump vec4 uColor[2];\n"
175                                         "out mediump vec4 vColor;\n"
176                                         "void main() {\n"
177                                         "  vColor = uColor[gl_ViewID_OVR];\n"
178                                         "  gl_Position = a_position;\n"
179                                         "}\n";
180 
181     const char *multiviewFragmentShader = "#version 300 es\n"
182                                           "layout(location = 0) out mediump vec4 dEQP_FragColor;\n"
183                                           "in mediump vec4 vColor;\n"
184                                           "void main() {\n"
185                                           "  dEQP_FragColor = vColor;\n"
186                                           "}\n";
187 
188     m_multiviewProgram = new glu::ShaderProgram(
189         m_context.getRenderContext(), glu::makeVtxFragSources(multiviewVertexShader, multiviewFragmentShader));
190     DE_ASSERT(m_multiviewProgram);
191     if (!m_multiviewProgram->isOk())
192     {
193         m_testCtx.getLog() << *m_multiviewProgram;
194         TCU_FAIL("Failed to compile multiview shader");
195     }
196 
197     // Draw the first layer on the left half of the screen and the second layer
198     // on the right half.
199     const char *finalVertexShader = "#version 300 es\n"
200                                     "layout(location = 0) in mediump vec4 a_position;\n"
201                                     "out highp vec3 vTexCoord;\n"
202                                     "void main() {\n"
203                                     "  vTexCoord.x = fract(a_position.x + 1.0);\n"
204                                     "  vTexCoord.y = .5 * (a_position.y + 1.0);\n"
205                                     "  vTexCoord.z = a_position.x;\n"
206                                     "  gl_Position = a_position;\n"
207                                     "}\n";
208 
209     const char *finalFragmentShader = "#version 300 es\n"
210                                       "layout(location = 0) out mediump vec4 dEQP_FragColor;\n"
211                                       "uniform lowp sampler2DArray uArrayTexture;\n"
212                                       "in highp vec3 vTexCoord;\n"
213                                       "void main() {\n"
214                                       "  highp vec3 uvw = vTexCoord;\n"
215                                       "  uvw.z = floor(vTexCoord.z + 1.0);\n"
216                                       "  dEQP_FragColor = texture(uArrayTexture, uvw);\n"
217                                       "}\n";
218 
219     m_finalProgram = new glu::ShaderProgram(m_context.getRenderContext(),
220                                             glu::makeVtxFragSources(finalVertexShader, finalFragmentShader));
221     DE_ASSERT(m_finalProgram);
222     if (!m_finalProgram->isOk())
223     {
224         m_testCtx.getLog() << *m_finalProgram;
225         TCU_FAIL("Failed to compile final shader");
226     }
227 
228     m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
229     GLU_CHECK_MSG("Case initialization finished");
230 }
231 
deinit()232 void MultiviewCase::deinit()
233 {
234     deleteFramebufferObjects();
235     delete m_multiviewProgram;
236     m_multiviewProgram = DE_NULL;
237     delete m_finalProgram;
238     m_finalProgram = DE_NULL;
239 }
240 
iterate()241 MultiviewCase::IterateResult MultiviewCase::iterate()
242 {
243     TestLog &log          = m_testCtx.getLog();
244     uint32_t colorUniform = glGetUniformLocation(m_multiviewProgram->getProgram(), "uColor");
245     std::string header = "Case iteration " + de::toString(m_caseIndex + 1) + " / " + de::toString(NUM_CASE_ITERATIONS);
246     log << TestLog::Section(header, header);
247 
248     DE_ASSERT(m_multiviewProgram);
249 
250     // Create and bind the multiview FBO.
251 
252     try
253     {
254         setupFramebufferObjects();
255     }
256     catch (tcu::NotSupportedError &e)
257     {
258         log << TestLog::Message << "ERROR: " << e.what() << "." << TestLog::EndMessage << TestLog::EndSection;
259         m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Not supported");
260         return STOP;
261     }
262     catch (tcu::InternalError &e)
263     {
264         log << TestLog::Message << "ERROR: " << e.what() << "." << TestLog::EndMessage << TestLog::EndSection;
265         m_testCtx.setTestResult(QP_TEST_RESULT_INTERNAL_ERROR, "Error");
266         return STOP;
267     }
268 
269     log << TestLog::EndSection;
270 
271     // Draw full screen quad into the multiview framebuffer.
272     // The quad should be instanced into both layers of the array texture.
273 
274     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
275     gl.bindFramebuffer(GL_FRAMEBUFFER, m_multiviewFbo);
276     gl.viewport(0, 0, m_width / 2, m_height);
277     gl.useProgram(m_multiviewProgram->getProgram());
278     gl.uniform4fv(colorUniform, 2, COLOR_VALUES);
279     gl.enableVertexAttribArray(0);
280     gl.vertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, &UNIT_SQUARE[0]);
281     gl.drawArrays(GL_TRIANGLE_STRIP, 0, 4);
282 
283     // Sample from the array texture to draw a quad into the backbuffer.
284 
285     const int backbufferWidth  = m_context.getRenderTarget().getWidth();
286     const int backbufferHeight = m_context.getRenderTarget().getHeight();
287     gl.bindFramebuffer(GL_FRAMEBUFFER, 0);
288     gl.viewport(0, 0, backbufferWidth, backbufferHeight);
289     gl.useProgram(m_finalProgram->getProgram());
290     gl.bindTexture(GL_TEXTURE_2D_ARRAY, m_arrayTexture);
291     gl.drawArrays(GL_TRIANGLE_STRIP, 0, 4);
292 
293     // Read back the framebuffer, ensure that the left half is red and the
294     // right half is green.
295 
296     tcu::Surface pixels(backbufferWidth, backbufferHeight);
297     glu::readPixels(m_context.getRenderContext(), 0, 0, pixels.getAccess());
298     bool failed = false;
299     for (int y = 0; y < backbufferHeight; y++)
300     {
301         for (int x = 0; x < backbufferWidth; x++)
302         {
303             tcu::RGBA pixel = pixels.getPixel(x, y);
304             if (x < backbufferWidth / 2)
305             {
306                 if (pixel.getRed() != 255 || pixel.getGreen() != 0 || pixel.getBlue() != 0)
307                 {
308                     failed = true;
309                 }
310             }
311             else if (x > backbufferWidth / 2)
312             {
313                 if (pixel.getRed() != 0 || pixel.getGreen() != 255 || pixel.getBlue() != 0)
314                 {
315                     failed = true;
316                 }
317             }
318             if (failed)
319             {
320                 break;
321             }
322         }
323     }
324 
325     deleteFramebufferObjects();
326 
327     if (failed)
328     {
329         log << TestLog::Image("Result image", "Result image", pixels);
330     }
331 
332     log << TestLog::Message << "Test result: " << (failed ? "Failed!" : "Passed!") << TestLog::EndMessage;
333 
334     if (failed)
335     {
336         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
337         return STOP;
338     }
339 
340     return (++m_caseIndex < NUM_CASE_ITERATIONS) ? CONTINUE : STOP;
341 }
342 
MultiviewTests(Context & context)343 MultiviewTests::MultiviewTests(Context &context) : TestCaseGroup(context, "multiview", "Multiview Tests")
344 {
345 }
346 
~MultiviewTests()347 MultiviewTests::~MultiviewTests()
348 {
349 }
350 
init()351 void MultiviewTests::init()
352 {
353     addChild(new MultiviewCase(m_context, "samples_1", "Multiview test without multisampling", 1));
354     addChild(new MultiviewCase(m_context, "samples_2", "Multiview test with MSAAx2", 2));
355     addChild(new MultiviewCase(m_context, "samples_4", "Multiview test without MSAAx4", 4));
356 }
357 
358 } // namespace Functional
359 } // namespace gles3
360 } // namespace deqp
361