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 40using tcu::TestLog; 41using tcu::Vec4; 42 43namespace deqp 44{ 45namespace gles3 46{ 47namespace Functional 48{ 49 50static const int NUM_CASE_ITERATIONS = 1; 51static 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}; 57static const float COLOR_VALUES[] = { 58 1, 0, 0, 1, // Red for level 0 59 0, 1, 0, 1, // Green for level 1 60}; 61 62class MultiviewCase : public TestCase 63{ 64public: 65 MultiviewCase(Context& context, const char* name, const char* description, int numSamples); 66 ~MultiviewCase(); 67 void init(); 68 void deinit(); 69 IterateResult iterate(); 70 71private: 72 MultiviewCase(const MultiviewCase& other); 73 MultiviewCase& operator=(const MultiviewCase& other); 74 void setupFramebufferObjects(); 75 void deleteFramebufferObjects(); 76 77 glu::ShaderProgram* m_multiviewProgram; 78 deUint32 m_multiviewFbo; 79 deUint32 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 89MultiviewCase::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 102MultiviewCase::~MultiviewCase() 103{ 104 MultiviewCase::deinit(); 105} 106 107void 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 deUint32 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 145void 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 152void 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 232void 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 241MultiviewCase::IterateResult MultiviewCase::iterate() 242{ 243 TestLog& log = m_testCtx.getLog(); 244 deUint32 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 343MultiviewTests::MultiviewTests(Context& context) : TestCaseGroup(context, "multiview", "Multiview Tests") 344{ 345} 346 347MultiviewTests::~MultiviewTests() 348{ 349} 350 351void 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