xref: /aosp_15_r20/external/deqp/external/openglcts/modules/gl/gl4cShaderViewportLayerArrayTests.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
1 /*-------------------------------------------------------------------------
2  * OpenGL Conformance Test Suite
3  * -----------------------------
4  *
5  * Copyright (c) 2017 The Khronos Group Inc.
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
22  */ /*-------------------------------------------------------------------*/
23 
24 /**
25  */ /*!
26  * \file  gl4cShaderViewportLayerArrayTests.cpp
27  * \brief Conformance tests for the ARB_shader_viewport_layer_array functionality.
28  */ /*-------------------------------------------------------------------*/
29 
30 #include "gl4cShaderViewportLayerArrayTests.hpp"
31 #include "gluContextInfo.hpp"
32 #include "gluDefs.hpp"
33 #include "gluDrawUtil.hpp"
34 #include "gluObjectWrapper.hpp"
35 #include "gluShaderProgram.hpp"
36 #include "glwEnums.hpp"
37 #include "glwFunctions.hpp"
38 #include "tcuRenderTarget.hpp"
39 
40 #include <sstream>
41 #include <string>
42 #include <vector>
43 
44 using namespace glw;
45 
46 namespace gl4cts
47 {
48 
ShaderPipeline(bool tessellationShader,bool geometryShader,int maxViewportsLayers,const std::string & varName)49 ShaderViewportLayerArrayUtils::ShaderPipeline::ShaderPipeline(bool tessellationShader, bool geometryShader,
50                                                               int maxViewportsLayers, const std::string &varName)
51     : m_program(NULL)
52     , m_hasTessellationShader(tessellationShader)
53     , m_hasGeometryShader(geometryShader)
54     , m_viewportLayerOffset(m_hasGeometryShader     ? OFFSET_GEOMETRY :
55                             m_hasTessellationShader ? OFFSET_TESSELLATION :
56                                                       OFFSET_VERTEX)
57     , m_varName(varName)
58 {
59     m_vs = "#version 450 core\n"
60            "#extension GL_ARB_shader_viewport_layer_array: require\n"
61            "in highp vec2 inPosition;\n"
62            "in int in<var_name>;\n"
63            "in highp vec4 inColor;\n"
64            "out int vs<var_name>;\n"
65            "out highp vec3 vsPosition;\n"
66            "out highp vec4 vsColor;\n"
67            "void main()\n"
68            "{\n"
69            "    gl_Position = vec4(inPosition, 0.0, 1.0);\n"
70            "    gl_<var_name> = (in<var_name> + <viewport_layer_offset>) % <viewport_layer_max>;\n"
71            "    vs<var_name> = in<var_name>;\n"
72            "    vsPosition = vec3(inPosition, 0.0);\n"
73            "    vsColor = inColor;\n"
74            "}\n";
75 
76     m_tcs = "#version 450 core\n"
77             "layout(vertices = 3) out;\n"
78             "in highp vec3 vsPosition[];\n"
79             "in highp vec4 vsColor[];\n"
80             "in int vs<var_name>[];\n"
81             "out highp vec3 tcsPosition[];\n"
82             "out highp vec4 tcsColor[];\n"
83             "out int tcs<var_name>[];\n"
84             "void main()\n"
85             "{\n"
86             "    tcsPosition[gl_InvocationID] = vsPosition[gl_InvocationID];\n"
87             "    tcsColor[gl_InvocationID] = vsColor[gl_InvocationID];\n"
88             "    tcs<var_name>[gl_InvocationID] = vs<var_name>[gl_InvocationID];\n"
89             "    gl_TessLevelInner[0] = 3;\n"
90             "    gl_TessLevelOuter[0] = 3;\n"
91             "    gl_TessLevelOuter[1] = 3;\n"
92             "    gl_TessLevelOuter[2] = 3;\n"
93             "}\n";
94 
95     m_tes = "#version 450 core\n"
96             "#extension GL_ARB_shader_viewport_layer_array: require\n"
97             "layout(triangles, equal_spacing, cw) in;\n"
98             "in highp vec3 tcsPosition[];\n"
99             "in highp vec4 tcsColor[];\n"
100             "in int tcs<var_name>[];\n"
101             "out highp vec4 tesColor;\n"
102             "out highp int tes<var_name>;\n"
103             "void main()\n"
104             "{\n"
105             "    vec3 p0 = gl_TessCoord.x * tcsPosition[0];\n"
106             "    vec3 p1 = gl_TessCoord.y * tcsPosition[1];\n"
107             "    vec3 p2 = gl_TessCoord.z * tcsPosition[2];\n"
108             "    tesColor = tcsColor[0];\n"
109             "    tes<var_name> = tcs<var_name>[0];\n"
110             "    gl_<var_name> = (tcs<var_name>[0] + <viewport_layer_offset>) % <viewport_layer_max>;\n"
111             "    gl_Position = vec4(normalize(p0 + p1 + p2), 1.0);\n"
112             "}\n";
113 
114     m_gs = "#version 450 core\n"
115            "#extension GL_ARB_shader_viewport_layer_array: require\n"
116            "layout(triangles) in;\n"
117            "layout(triangle_strip, max_vertices = 3) out;\n"
118            "in highp vec4 tesColor[];\n"
119            "in int tes<var_name>[];\n"
120            "out highp vec4 gsColor;\n"
121            "void main()\n"
122            "{\n"
123            "    for (int i = 0; i<3; i++)\n"
124            "    {\n"
125            "        gl_Position = gl_in[i].gl_Position;\n"
126            "        gl_<var_name> = (tes<var_name>[i] + <viewport_layer_offset>) % <viewport_layer_max>;\n"
127            "        gsColor = tesColor[i];\n"
128            "        EmitVertex();\n"
129            "    }\n"
130            "    EndPrimitive();\n"
131            "}\n";
132 
133     m_fs = "#version 450 core\n"
134            "in highp vec4 <input_color>;\n"
135            "out vec4 finalOutColor;\n"
136            "void main()\n"
137            "{\n"
138            "    finalOutColor = <input_color>;\n"
139            "}\n";
140 
141     this->adaptShaderToPipeline(m_vs, "<var_name>", varName);
142     this->adaptShaderToPipeline(m_vs, "<viewport_layer_offset>", OFFSET_VERTEX);
143     this->adaptShaderToPipeline(m_vs, "<viewport_layer_max>", maxViewportsLayers);
144 
145     this->adaptShaderToPipeline(m_tes, "<var_name>", varName);
146     this->adaptShaderToPipeline(m_tes, "<viewport_layer_offset>", OFFSET_TESSELLATION);
147     this->adaptShaderToPipeline(m_tes, "<viewport_layer_max>", maxViewportsLayers);
148 
149     this->adaptShaderToPipeline(m_tcs, "<var_name>", varName);
150 
151     this->adaptShaderToPipeline(m_gs, "<var_name>", varName);
152     this->adaptShaderToPipeline(m_gs, "<viewport_layer_offset>", OFFSET_GEOMETRY);
153     this->adaptShaderToPipeline(m_gs, "<viewport_layer_max>", maxViewportsLayers);
154 
155     this->adaptShaderToPipeline(m_fs, "<input_color>", "vsColor", "tesColor", "gsColor");
156 }
157 
adaptShaderToPipeline(std::string & shader,const std::string & varKey,const std::string & vsVersion,const std::string & tesVersion,const std::string & gsVersion)158 void ShaderViewportLayerArrayUtils::ShaderPipeline::adaptShaderToPipeline(std::string &shader,
159                                                                           const std::string &varKey,
160                                                                           const std::string &vsVersion,
161                                                                           const std::string &tesVersion,
162                                                                           const std::string &gsVersion)
163 {
164     std::string varName = m_hasGeometryShader ? gsVersion : m_hasTessellationShader ? tesVersion : vsVersion;
165 
166     size_t start = 0;
167     while ((start = shader.find(varKey, start)) != std::string::npos)
168     {
169         shader.replace(start, varKey.length(), varName);
170         start += varName.length();
171     }
172 }
173 
adaptShaderToPipeline(std::string & shader,const std::string & varKey,const std::string & value)174 void ShaderViewportLayerArrayUtils::ShaderPipeline::adaptShaderToPipeline(std::string &shader,
175                                                                           const std::string &varKey,
176                                                                           const std::string &value)
177 {
178     this->adaptShaderToPipeline(shader, varKey, value, value, value);
179 }
180 
adaptShaderToPipeline(std::string & shader,const std::string & varKey,int value)181 void ShaderViewportLayerArrayUtils::ShaderPipeline::adaptShaderToPipeline(std::string &shader,
182                                                                           const std::string &varKey, int value)
183 {
184     std::ostringstream valueStr;
185     valueStr << value;
186 
187     this->adaptShaderToPipeline(shader, varKey, valueStr.str(), valueStr.str(), valueStr.str());
188 }
189 
~ShaderPipeline()190 ShaderViewportLayerArrayUtils::ShaderPipeline::~ShaderPipeline()
191 {
192     if (m_program)
193     {
194         delete m_program;
195     }
196 }
197 
create(const glu::RenderContext & context)198 void ShaderViewportLayerArrayUtils::ShaderPipeline::create(const glu::RenderContext &context)
199 {
200     glu::ProgramSources sources;
201     sources.sources[glu::SHADERTYPE_VERTEX].push_back(m_vs);
202     if (m_hasTessellationShader)
203     {
204         sources.sources[glu::SHADERTYPE_TESSELLATION_CONTROL].push_back(m_tcs);
205         sources.sources[glu::SHADERTYPE_TESSELLATION_EVALUATION].push_back(m_tes);
206     }
207     if (m_hasGeometryShader)
208     {
209         sources.sources[glu::SHADERTYPE_GEOMETRY].push_back(m_gs);
210     }
211     sources.sources[glu::SHADERTYPE_FRAGMENT].push_back(m_fs);
212 
213     m_program = new glu::ShaderProgram(context, sources);
214     if (!m_program->isOk())
215     {
216         TCU_FAIL("Shader compilation failed");
217     }
218 }
219 
use(const glu::RenderContext & context)220 void ShaderViewportLayerArrayUtils::ShaderPipeline::use(const glu::RenderContext &context)
221 {
222     const glw::Functions &gl = context.getFunctions();
223     gl.useProgram(m_program->getProgram());
224     GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram failed");
225 }
226 
renderQuad(const glu::RenderContext & context,ShaderPipeline & shaderPipeline,int viewportLayerIndex,tcu::Vec4 color)227 void ShaderViewportLayerArrayUtils::renderQuad(const glu::RenderContext &context, ShaderPipeline &shaderPipeline,
228                                                int viewportLayerIndex, tcu::Vec4 color)
229 {
230     const glw::Functions &gl = context.getFunctions();
231 
232     uint16_t const quadIndices[] = {0, 1, 2, 2, 1, 3};
233 
234     float const position[] = {-1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f};
235 
236     int const viewportLayerIndices[] = {viewportLayerIndex, viewportLayerIndex, viewportLayerIndex, viewportLayerIndex};
237 
238     float const colors[] = {color.x(), color.y(), color.z(), color.w(), color.x(), color.y(), color.z(), color.w(),
239                             color.x(), color.y(), color.z(), color.w(), color.x(), color.y(), color.z(), color.w()};
240 
241     std::string varName = "in";
242     varName += shaderPipeline.getVarName();
243 
244     glu::VertexArrayBinding vertexArrays[] = {glu::va::Float("inPosition", 2, 4, 0, position),
245                                               glu::va::Int32(varName, 1, 4, 0, viewportLayerIndices),
246                                               glu::va::Float("inColor", 4, 4, 0, colors)};
247 
248     shaderPipeline.use(context);
249 
250     glu::PrimitiveList primitiveList = shaderPipeline.hasTessellationShader() ?
251                                            glu::pr::Patches(DE_LENGTH_OF_ARRAY(quadIndices), quadIndices) :
252                                            glu::pr::TriangleStrip(DE_LENGTH_OF_ARRAY(quadIndices), quadIndices);
253 
254     glu::draw(context, shaderPipeline.getShaderProgram()->getProgram(), DE_LENGTH_OF_ARRAY(vertexArrays), vertexArrays,
255               primitiveList, (glu::DrawUtilCallback *)DE_NULL);
256 
257     GLU_EXPECT_NO_ERROR(gl.getError(), "glu::draw error");
258 }
259 
validateColor(tcu::Vec4 renderedColor,tcu::Vec4 referenceColor)260 bool ShaderViewportLayerArrayUtils::validateColor(tcu::Vec4 renderedColor, tcu::Vec4 referenceColor)
261 {
262     const float epsilon = 1.1f / 31.0f; // Accommodate framebuffers with 5-bit channels.
263     return de::abs(renderedColor.x() - referenceColor.x()) < epsilon &&
264            de::abs(renderedColor.y() - referenceColor.y()) < epsilon &&
265            de::abs(renderedColor.z() - referenceColor.z()) < epsilon &&
266            de::abs(renderedColor.w() - referenceColor.w()) < epsilon;
267 }
268 
createMaxViewports()269 glw::GLint ShaderViewportIndexTestCase::createMaxViewports()
270 {
271     const Functions &gl                  = m_context.getRenderContext().getFunctions();
272     const tcu::RenderTarget renderTarget = m_context.getRenderContext().getRenderTarget();
273     const GLfloat targetWidth            = (GLfloat)renderTarget.getWidth();
274 
275     GLint maxViewports = 0;
276     gl.getIntegerv(GL_MAX_VIEWPORTS, &maxViewports);
277     GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv error");
278 
279     const int viewportDataSize = 4; // x + y + w + h
280     std::vector<glw::GLfloat> data(maxViewports * viewportDataSize);
281 
282     GLfloat viewportWidth  = 16.0f;
283     GLfloat viewportHeight = 16.0f;
284 
285     int currentX = 0;
286     int currentY = 0;
287     for (GLint i = 0; i < maxViewports; ++i)
288     {
289         GLfloat x = (GLfloat)currentX * viewportWidth;
290         if (x > (targetWidth - viewportWidth))
291         {
292             x        = 0.0f;
293             currentX = 0;
294             currentY++;
295         }
296         GLfloat y = (GLfloat)currentY * viewportHeight;
297 
298         data[i * viewportDataSize + 0] = x;
299         data[i * viewportDataSize + 1] = y;
300         data[i * viewportDataSize + 2] = viewportWidth;
301         data[i * viewportDataSize + 3] = viewportHeight;
302 
303         m_viewportData.push_back(tcu::Vec4(x, y, viewportWidth, viewportHeight));
304 
305         currentX++;
306     }
307 
308     gl.viewportArrayv(0, maxViewports, data.data());
309     GLU_EXPECT_NO_ERROR(gl.getError(), "ViewportArrayv");
310 
311     return maxViewports;
312 }
313 
314 /** Constructor.
315  *
316  *  @param context Rendering context
317  */
ShaderViewportIndexTestCase(deqp::Context & context)318 ShaderViewportIndexTestCase::ShaderViewportIndexTestCase(deqp::Context &context)
319     : TestCase(context, "ShaderViewportIndexTestCase",
320                "Implements gl_ViewportIndex tests described in CTS_ARB_shader_viewport_layer_array")
321     , m_maxViewports(0)
322     , m_currentViewport(0)
323 {
324     m_isExtensionSupported = context.getContextInfo().isExtensionSupported("GL_ARB_shader_viewport_layer_array");
325 }
326 
init()327 void ShaderViewportIndexTestCase::init()
328 {
329     if (!m_isExtensionSupported)
330         return;
331 
332     m_maxViewports = this->createMaxViewports();
333 
334     m_shaderPipelines.push_back(
335         ShaderViewportLayerArrayUtils::ShaderPipeline(false, false, m_maxViewports, "ViewportIndex"));
336     m_shaderPipelines.push_back(
337         ShaderViewportLayerArrayUtils::ShaderPipeline(true, false, m_maxViewports, "ViewportIndex"));
338     m_shaderPipelines.push_back(
339         ShaderViewportLayerArrayUtils::ShaderPipeline(true, true, m_maxViewports, "ViewportIndex"));
340 
341     for (ShaderPipelineIter iter = m_shaderPipelines.begin(); iter != m_shaderPipelines.end(); ++iter)
342     {
343         iter->create(m_context.getRenderContext());
344     }
345 }
346 
deinit()347 void ShaderViewportIndexTestCase::deinit()
348 {
349     const Functions &gl                  = m_context.getRenderContext().getFunctions();
350     const tcu::RenderTarget renderTarget = m_context.getRenderContext().getRenderTarget();
351 
352     gl.viewport(0, 0, renderTarget.getWidth(), renderTarget.getHeight());
353     GLU_EXPECT_NO_ERROR(gl.getError(), "Viewport");
354 }
355 
356 /** Executes test iteration.
357  *
358  *  @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
359  */
iterate()360 tcu::TestNode::IterateResult ShaderViewportIndexTestCase::iterate()
361 {
362     if (!m_isExtensionSupported)
363     {
364         m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Not supported");
365         return STOP;
366     }
367 
368     const glw::Functions &gl                = m_context.getRenderContext().getFunctions();
369     const glu::RenderContext &renderContext = m_context.getRenderContext();
370 
371     tcu::Vec4 renderColor((m_currentViewport + 1) / (float)m_maxViewports, 0.0f, 0.0f, 1.0f);
372     tcu::Vec4 backgroundColor(0.0f, 0.0f, 0.0f, 1.0f);
373 
374     for (ShaderPipelineIter pipelineIter = m_shaderPipelines.begin(); pipelineIter != m_shaderPipelines.end();
375          ++pipelineIter)
376     {
377         // rendering
378 
379         gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
380         GLU_EXPECT_NO_ERROR(gl.getError(), "ClearColor");
381         gl.clear(GL_COLOR_BUFFER_BIT);
382         GLU_EXPECT_NO_ERROR(gl.getError(), "Clear");
383         ShaderViewportLayerArrayUtils::renderQuad(renderContext, *pipelineIter, m_currentViewport, renderColor);
384         gl.flush();
385         GLU_EXPECT_NO_ERROR(gl.getError(), "Flush");
386 
387         // verification
388 
389         std::vector<std::pair<tcu::Vec2, tcu::Vec4>> expectedPixels;
390 
391         for (size_t i = 0; i < m_viewportData.size(); ++i)
392         {
393             tcu::Vec4 viewportData = m_viewportData[i];
394 
395             int currentViewportWithOffset =
396                 (m_currentViewport + pipelineIter->getViewportLayerOffset()) % m_maxViewports;
397 
398             tcu::Vec2 center(viewportData.x() + viewportData.z() * 0.5f, viewportData.y() + viewportData.w() * 0.5f);
399 
400             if (i == (unsigned int)currentViewportWithOffset)
401             {
402                 expectedPixels.push_back(std::make_pair(center, renderColor));
403             }
404             else
405             {
406                 expectedPixels.push_back(std::make_pair(center, backgroundColor));
407             }
408         }
409 
410         for (size_t i = 0; i < expectedPixels.size(); ++i)
411         {
412             glw::GLfloat rgba[4] = {-1.f, -1.f, -1.f, -1.f};
413             gl.readPixels((glw::GLint)expectedPixels[i].first.x(), (glw::GLint)expectedPixels[i].first.y(), 1, 1,
414                           GL_RGBA, GL_FLOAT, rgba);
415             GLU_EXPECT_NO_ERROR(gl.getError(), "ReadPixels");
416             bool validationResult = ShaderViewportLayerArrayUtils::validateColor(
417                 tcu::Vec4(rgba[0], rgba[1], rgba[2], rgba[3]), expectedPixels[i].second);
418             TCU_CHECK_MSG(validationResult, "Expected pixel color did not match rendered one.");
419         }
420     }
421 
422     if (m_currentViewport < (m_maxViewports - 1))
423     {
424         m_currentViewport++;
425         return CONTINUE;
426     }
427 
428     m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
429     return STOP;
430 }
431 
ShaderLayerFramebufferTestCaseBase(deqp::Context & context,const char * name,const char * description,bool layered)432 ShaderLayerFramebufferTestCaseBase::ShaderLayerFramebufferTestCaseBase(deqp::Context &context, const char *name,
433                                                                        const char *description, bool layered)
434     : TestCase(context, name, description)
435     , m_layersNum(layered ? 4 : 1)
436     , m_fboSize(512)
437     , m_texture(0)
438     , m_mainFbo(0)
439     , m_currentLayer(0)
440 {
441     m_isExtensionSupported = context.getContextInfo().isExtensionSupported("GL_ARB_shader_viewport_layer_array");
442 }
443 
init()444 void ShaderLayerFramebufferTestCaseBase::init()
445 {
446     if (!m_isExtensionSupported)
447         return;
448 
449     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
450 
451     this->createFBO();
452 
453     m_shaderPipelines.push_back(ShaderViewportLayerArrayUtils::ShaderPipeline(false, false, m_layersNum, "Layer"));
454     m_shaderPipelines.push_back(ShaderViewportLayerArrayUtils::ShaderPipeline(true, false, m_layersNum, "Layer"));
455     m_shaderPipelines.push_back(ShaderViewportLayerArrayUtils::ShaderPipeline(true, true, m_layersNum, "Layer"));
456 
457     for (ShaderPipelineIter iter = m_shaderPipelines.begin(); iter != m_shaderPipelines.end(); ++iter)
458     {
459         iter->create(m_context.getRenderContext());
460     }
461 
462     gl.viewport(0, 0, m_fboSize, m_fboSize);
463 }
464 
deinit()465 void ShaderLayerFramebufferTestCaseBase::deinit()
466 {
467     const Functions &gl                  = m_context.getRenderContext().getFunctions();
468     const tcu::RenderTarget renderTarget = m_context.getRenderContext().getRenderTarget();
469 
470     gl.viewport(0, 0, renderTarget.getWidth(), renderTarget.getHeight());
471     GLU_EXPECT_NO_ERROR(gl.getError(), "Viewport");
472 }
473 
iterate()474 tcu::TestNode::IterateResult ShaderLayerFramebufferTestCaseBase::iterate()
475 {
476     if (!m_isExtensionSupported)
477     {
478         m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Not supported");
479         return STOP;
480     }
481 
482     const glw::Functions &gl                = m_context.getRenderContext().getFunctions();
483     const glu::RenderContext &renderContext = m_context.getRenderContext();
484 
485     tcu::Vec4 renderColor((m_currentLayer + 1) / (float)m_layersNum, 0.0f, 0.0f, 1.0f);
486 
487     for (ShaderPipelineIter pipelineIter = m_shaderPipelines.begin(); pipelineIter != m_shaderPipelines.end();
488          ++pipelineIter)
489     {
490         // bind main framebuffer (layered)
491         gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, m_mainFbo);
492         GLU_EXPECT_NO_ERROR(gl.getError(), "BindFramebuffer");
493 
494         // render
495         gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
496         GLU_EXPECT_NO_ERROR(gl.getError(), "ClearColor");
497         gl.clear(GL_COLOR_BUFFER_BIT);
498         GLU_EXPECT_NO_ERROR(gl.getError(), "Clear");
499         ShaderViewportLayerArrayUtils::renderQuad(renderContext, *pipelineIter, m_currentLayer, renderColor);
500         gl.flush();
501         GLU_EXPECT_NO_ERROR(gl.getError(), "Flush");
502 
503         // calculate layer offset (same value as gl_Layer in shader)
504         int currentLayerWithOffset = (m_currentLayer + pipelineIter->getViewportLayerOffset()) % m_layersNum;
505 
506         // bind framebuffer of this layer
507         gl.bindFramebuffer(GL_READ_FRAMEBUFFER, m_fbos[currentLayerWithOffset]);
508         GLU_EXPECT_NO_ERROR(gl.getError(), "bindFramebuffer() call failed.");
509 
510         // verification
511         glw::GLfloat rgba[4] = {-1.f, -1.f, -1.f, -1.f};
512         gl.readPixels(m_fboSize / 2, m_fboSize / 2, 1, 1, GL_RGBA, GL_FLOAT, rgba);
513         GLU_EXPECT_NO_ERROR(gl.getError(), "ReadPixels");
514         bool validationResult =
515             ShaderViewportLayerArrayUtils::validateColor(tcu::Vec4(rgba[0], rgba[1], rgba[2], rgba[3]), renderColor);
516 
517         TCU_CHECK_MSG(validationResult, "Expected pixel color did not match rendered one.");
518     }
519 
520     if (m_currentLayer < (m_layersNum - 1))
521     {
522         m_currentLayer++;
523         return CONTINUE;
524     }
525 
526     m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
527     return STOP;
528 }
529 
530 /** Constructor.
531  *
532  *  @param context Rendering context
533  */
ShaderLayerFramebufferLayeredTestCase(deqp::Context & context)534 ShaderLayerFramebufferLayeredTestCase::ShaderLayerFramebufferLayeredTestCase(deqp::Context &context)
535     : ShaderLayerFramebufferTestCaseBase(
536           context, "ShaderLayerFramebufferLayeredTestCase",
537           "Implements gl_Layer tests for layered framebuffer described in CTS_ARB_shader_viewport_layer_array", true)
538 {
539 }
540 
createFBO()541 void ShaderLayerFramebufferLayeredTestCase::createFBO()
542 {
543     const Functions &gl = m_context.getRenderContext().getFunctions();
544 
545     gl.genTextures(1, &m_texture);
546     GLU_EXPECT_NO_ERROR(gl.getError(), "GenTextures");
547 
548     gl.bindTexture(GL_TEXTURE_3D, m_texture);
549     GLU_EXPECT_NO_ERROR(gl.getError(), "bindTexture() call failed.");
550 
551     gl.texImage3D(GL_TEXTURE_3D, 0, GL_RGBA8, m_fboSize, m_fboSize, m_layersNum, 0, GL_RGBA, GL_FLOAT, 0);
552     GLU_EXPECT_NO_ERROR(gl.getError(), "texImage3D() call failed.");
553 
554     // create main FBO
555 
556     gl.genFramebuffers(1, &m_mainFbo);
557     GLU_EXPECT_NO_ERROR(gl.getError(), "genFramebuffers() call failed.");
558     gl.bindFramebuffer(GL_FRAMEBUFFER, m_mainFbo);
559     GLU_EXPECT_NO_ERROR(gl.getError(), "bindFramebuffer() call failed.");
560     gl.framebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_texture, 0);
561     GLU_EXPECT_NO_ERROR(gl.getError(), "framebufferTexture() call failed.");
562 
563     // create FBO for each layer
564 
565     for (int i = 0; i < m_layersNum; ++i)
566     {
567         uint32_t layerFbo;
568 
569         gl.genFramebuffers(1, &layerFbo);
570         GLU_EXPECT_NO_ERROR(gl.getError(), "genFramebuffers() call failed.");
571         gl.bindFramebuffer(GL_FRAMEBUFFER, layerFbo);
572         GLU_EXPECT_NO_ERROR(gl.getError(), "bindFramebuffer() call failed.");
573         gl.framebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_texture, 0, i);
574         GLU_EXPECT_NO_ERROR(gl.getError(), "framebufferTextureLayer() call failed.");
575 
576         m_fbos.push_back(layerFbo);
577     }
578 }
579 
deleteFBO()580 void ShaderLayerFramebufferLayeredTestCase::deleteFBO()
581 {
582     const Functions &gl = m_context.getRenderContext().getFunctions();
583 
584     gl.deleteFramebuffers(1, &m_mainFbo);
585     GLU_EXPECT_NO_ERROR(gl.getError(), "DeleteFramebuffers");
586     for (int i = 0; i < m_layersNum; ++i)
587     {
588         gl.deleteFramebuffers(1, &(m_fbos[i]));
589         GLU_EXPECT_NO_ERROR(gl.getError(), "DeleteFramebuffers");
590     }
591     gl.deleteTextures(1, &m_texture);
592     GLU_EXPECT_NO_ERROR(gl.getError(), "DeleteTextures");
593 }
594 
595 /** Constructor.
596  *
597  *  @param context Rendering context
598  */
ShaderLayerFramebufferNonLayeredTestCase(deqp::Context & context)599 ShaderLayerFramebufferNonLayeredTestCase::ShaderLayerFramebufferNonLayeredTestCase(deqp::Context &context)
600     : ShaderLayerFramebufferTestCaseBase(
601           context, "ShaderLayerFramebufferNonLayeredTestCase",
602           "Implements gl_Layer tests for non-layered framebuffer described in CTS_ARB_shader_viewport_layer_array",
603           false)
604 {
605 }
606 
createFBO()607 void ShaderLayerFramebufferNonLayeredTestCase::createFBO()
608 {
609     const Functions &gl = m_context.getRenderContext().getFunctions();
610     uint32_t tex;
611 
612     gl.genTextures(1, &tex);
613     GLU_EXPECT_NO_ERROR(gl.getError(), "GenTextures");
614 
615     gl.bindTexture(GL_TEXTURE_2D, tex);
616     GLU_EXPECT_NO_ERROR(gl.getError(), "bindTexture() call failed.");
617 
618     gl.texImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, m_fboSize, m_fboSize, 0, GL_RGBA, GL_FLOAT, 0);
619     GLU_EXPECT_NO_ERROR(gl.getError(), "texImage2D() call failed.");
620 
621     // create main FBO
622 
623     gl.genFramebuffers(1, &m_mainFbo);
624     GLU_EXPECT_NO_ERROR(gl.getError(), "genFramebuffers() call failed.");
625     gl.bindFramebuffer(GL_FRAMEBUFFER, m_mainFbo);
626     GLU_EXPECT_NO_ERROR(gl.getError(), "bindFramebuffer() call failed.");
627     gl.framebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex, 0);
628     GLU_EXPECT_NO_ERROR(gl.getError(), "framebufferTexture() call failed.");
629 
630     // main FBO is only layer
631 
632     m_fbos.push_back(m_mainFbo);
633 }
634 
deleteFBO()635 void ShaderLayerFramebufferNonLayeredTestCase::deleteFBO()
636 {
637     const Functions &gl = m_context.getRenderContext().getFunctions();
638 
639     gl.deleteFramebuffers(1, &m_mainFbo);
640     GLU_EXPECT_NO_ERROR(gl.getError(), "DeleteFramebuffers");
641     gl.deleteTextures(1, &m_texture);
642     GLU_EXPECT_NO_ERROR(gl.getError(), "DeleteTextures");
643 }
644 
645 /** Constructor.
646  *
647  *  @param context Rendering context.
648  */
ShaderViewportLayerArray(deqp::Context & context)649 ShaderViewportLayerArray::ShaderViewportLayerArray(deqp::Context &context)
650     : TestCaseGroup(context, "shader_viewport_layer_array",
651                     "Verify conformance of CTS_ARB_shader_viewport_layer_array implementation")
652 {
653 }
654 
655 /** Initializes the test group contents. */
init()656 void ShaderViewportLayerArray::init()
657 {
658     addChild(new ShaderViewportIndexTestCase(m_context));
659     addChild(new ShaderLayerFramebufferLayeredTestCase(m_context));
660     addChild(new ShaderLayerFramebufferNonLayeredTestCase(m_context));
661 }
662 } // namespace gl4cts
663