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