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 : OFFSET_VERTEX)
56 , m_varName(varName)
57 {
58 m_vs = "#version 450 core\n"
59 "#extension GL_ARB_shader_viewport_layer_array: require\n"
60 "in highp vec2 inPosition;\n"
61 "in int in<var_name>;\n"
62 "in highp vec4 inColor;\n"
63 "out int vs<var_name>;\n"
64 "out highp vec3 vsPosition;\n"
65 "out highp vec4 vsColor;\n"
66 "void main()\n"
67 "{\n"
68 " gl_Position = vec4(inPosition, 0.0, 1.0);\n"
69 " gl_<var_name> = (in<var_name> + <viewport_layer_offset>) % <viewport_layer_max>;\n"
70 " vs<var_name> = in<var_name>;\n"
71 " vsPosition = vec3(inPosition, 0.0);\n"
72 " vsColor = inColor;\n"
73 "}\n";
74
75 m_tcs = "#version 450 core\n"
76 "layout(vertices = 3) out;\n"
77 "in highp vec3 vsPosition[];\n"
78 "in highp vec4 vsColor[];\n"
79 "in int vs<var_name>[];\n"
80 "out highp vec3 tcsPosition[];\n"
81 "out highp vec4 tcsColor[];\n"
82 "out int tcs<var_name>[];\n"
83 "void main()\n"
84 "{\n"
85 " tcsPosition[gl_InvocationID] = vsPosition[gl_InvocationID];\n"
86 " tcsColor[gl_InvocationID] = vsColor[gl_InvocationID];\n"
87 " tcs<var_name>[gl_InvocationID] = vs<var_name>[gl_InvocationID];\n"
88 " gl_TessLevelInner[0] = 3;\n"
89 " gl_TessLevelOuter[0] = 3;\n"
90 " gl_TessLevelOuter[1] = 3;\n"
91 " gl_TessLevelOuter[2] = 3;\n"
92 "}\n";
93
94 m_tes = "#version 450 core\n"
95 "#extension GL_ARB_shader_viewport_layer_array: require\n"
96 "layout(triangles, equal_spacing, cw) in;\n"
97 "in highp vec3 tcsPosition[];\n"
98 "in highp vec4 tcsColor[];\n"
99 "in int tcs<var_name>[];\n"
100 "out highp vec4 tesColor;\n"
101 "out highp int tes<var_name>;\n"
102 "void main()\n"
103 "{\n"
104 " vec3 p0 = gl_TessCoord.x * tcsPosition[0];\n"
105 " vec3 p1 = gl_TessCoord.y * tcsPosition[1];\n"
106 " vec3 p2 = gl_TessCoord.z * tcsPosition[2];\n"
107 " tesColor = tcsColor[0];\n"
108 " tes<var_name> = tcs<var_name>[0];\n"
109 " gl_<var_name> = (tcs<var_name>[0] + <viewport_layer_offset>) % <viewport_layer_max>;\n"
110 " gl_Position = vec4(normalize(p0 + p1 + p2), 1.0);\n"
111 "}\n";
112
113 m_gs = "#version 450 core\n"
114 "#extension GL_ARB_shader_viewport_layer_array: require\n"
115 "layout(triangles) in;\n"
116 "layout(triangle_strip, max_vertices = 3) out;\n"
117 "in highp vec4 tesColor[];\n"
118 "in int tes<var_name>[];\n"
119 "out highp vec4 gsColor;\n"
120 "void main()\n"
121 "{\n"
122 " for (int i = 0; i<3; i++)\n"
123 " {\n"
124 " gl_Position = gl_in[i].gl_Position;\n"
125 " gl_<var_name> = (tes<var_name>[i] + <viewport_layer_offset>) % <viewport_layer_max>;\n"
126 " gsColor = tesColor[i];\n"
127 " EmitVertex();\n"
128 " }\n"
129 " EndPrimitive();\n"
130 "}\n";
131
132 m_fs = "#version 450 core\n"
133 "in highp vec4 <input_color>;\n"
134 "out vec4 finalOutColor;\n"
135 "void main()\n"
136 "{\n"
137 " finalOutColor = <input_color>;\n"
138 "}\n";
139
140 this->adaptShaderToPipeline(m_vs, "<var_name>", varName);
141 this->adaptShaderToPipeline(m_vs, "<viewport_layer_offset>", OFFSET_VERTEX);
142 this->adaptShaderToPipeline(m_vs, "<viewport_layer_max>", maxViewportsLayers);
143
144 this->adaptShaderToPipeline(m_tes, "<var_name>", varName);
145 this->adaptShaderToPipeline(m_tes, "<viewport_layer_offset>", OFFSET_TESSELLATION);
146 this->adaptShaderToPipeline(m_tes, "<viewport_layer_max>", maxViewportsLayers);
147
148 this->adaptShaderToPipeline(m_tcs, "<var_name>", varName);
149
150 this->adaptShaderToPipeline(m_gs, "<var_name>", varName);
151 this->adaptShaderToPipeline(m_gs, "<viewport_layer_offset>", OFFSET_GEOMETRY);
152 this->adaptShaderToPipeline(m_gs, "<viewport_layer_max>", maxViewportsLayers);
153
154 this->adaptShaderToPipeline(m_fs, "<input_color>", "vsColor", "tesColor", "gsColor");
155 }
156
adaptShaderToPipeline(std::string & shader,const std::string & varKey,const std::string & vsVersion,const std::string & tesVersion,const std::string & gsVersion)157 void ShaderViewportLayerArrayUtils::ShaderPipeline::adaptShaderToPipeline(std::string& shader,
158 const std::string& varKey,
159 const std::string& vsVersion,
160 const std::string& tesVersion,
161 const std::string& gsVersion)
162 {
163 std::string varName = m_hasGeometryShader ? gsVersion : m_hasTessellationShader ? tesVersion : vsVersion;
164
165 size_t start = 0;
166 while ((start = shader.find(varKey, start)) != std::string::npos)
167 {
168 shader.replace(start, varKey.length(), varName);
169 start += varName.length();
170 }
171 }
172
adaptShaderToPipeline(std::string & shader,const std::string & varKey,const std::string & value)173 void ShaderViewportLayerArrayUtils::ShaderPipeline::adaptShaderToPipeline(std::string& shader,
174 const std::string& varKey,
175 const std::string& value)
176 {
177 this->adaptShaderToPipeline(shader, varKey, value, value, value);
178 }
179
adaptShaderToPipeline(std::string & shader,const std::string & varKey,int value)180 void ShaderViewportLayerArrayUtils::ShaderPipeline::adaptShaderToPipeline(std::string& shader,
181 const std::string& varKey, int value)
182 {
183 std::ostringstream valueStr;
184 valueStr << value;
185
186 this->adaptShaderToPipeline(shader, varKey, valueStr.str(), valueStr.str(), valueStr.str());
187 }
188
~ShaderPipeline()189 ShaderViewportLayerArrayUtils::ShaderPipeline::~ShaderPipeline()
190 {
191 if (m_program)
192 {
193 delete m_program;
194 }
195 }
196
create(const glu::RenderContext & context)197 void ShaderViewportLayerArrayUtils::ShaderPipeline::create(const glu::RenderContext& context)
198 {
199 glu::ProgramSources sources;
200 sources.sources[glu::SHADERTYPE_VERTEX].push_back(m_vs);
201 if (m_hasTessellationShader)
202 {
203 sources.sources[glu::SHADERTYPE_TESSELLATION_CONTROL].push_back(m_tcs);
204 sources.sources[glu::SHADERTYPE_TESSELLATION_EVALUATION].push_back(m_tes);
205 }
206 if (m_hasGeometryShader)
207 {
208 sources.sources[glu::SHADERTYPE_GEOMETRY].push_back(m_gs);
209 }
210 sources.sources[glu::SHADERTYPE_FRAGMENT].push_back(m_fs);
211
212 m_program = new glu::ShaderProgram(context, sources);
213 if (!m_program->isOk())
214 {
215 TCU_FAIL("Shader compilation failed");
216 }
217 }
218
use(const glu::RenderContext & context)219 void ShaderViewportLayerArrayUtils::ShaderPipeline::use(const glu::RenderContext& context)
220 {
221 const glw::Functions& gl = context.getFunctions();
222 gl.useProgram(m_program->getProgram());
223 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram failed");
224 }
225
renderQuad(const glu::RenderContext & context,ShaderPipeline & shaderPipeline,int viewportLayerIndex,tcu::Vec4 color)226 void ShaderViewportLayerArrayUtils::renderQuad(const glu::RenderContext& context, ShaderPipeline& shaderPipeline,
227 int viewportLayerIndex, tcu::Vec4 color)
228 {
229 const glw::Functions& gl = context.getFunctions();
230
231 deUint16 const quadIndices[] = { 0, 1, 2, 2, 1, 3 };
232
233 float const position[] = { -1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f };
234
235 int const viewportLayerIndices[] = { viewportLayerIndex, viewportLayerIndex, viewportLayerIndex,
236 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
474
iterate()475 tcu::TestNode::IterateResult ShaderLayerFramebufferTestCaseBase::iterate()
476 {
477 if (!m_isExtensionSupported)
478 {
479 m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Not supported");
480 return STOP;
481 }
482
483 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
484 const glu::RenderContext& renderContext = m_context.getRenderContext();
485
486 tcu::Vec4 renderColor((m_currentLayer + 1) / (float)m_layersNum, 0.0f, 0.0f, 1.0f);
487
488 for (ShaderPipelineIter pipelineIter = m_shaderPipelines.begin(); pipelineIter != m_shaderPipelines.end();
489 ++pipelineIter)
490 {
491 // bind main framebuffer (layered)
492 gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, m_mainFbo);
493 GLU_EXPECT_NO_ERROR(gl.getError(), "BindFramebuffer");
494
495 // render
496 gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
497 GLU_EXPECT_NO_ERROR(gl.getError(), "ClearColor");
498 gl.clear(GL_COLOR_BUFFER_BIT);
499 GLU_EXPECT_NO_ERROR(gl.getError(), "Clear");
500 ShaderViewportLayerArrayUtils::renderQuad(renderContext, *pipelineIter, m_currentLayer, renderColor);
501 gl.flush();
502 GLU_EXPECT_NO_ERROR(gl.getError(), "Flush");
503
504 // calculate layer offset (same value as gl_Layer in shader)
505 int currentLayerWithOffset = (m_currentLayer + pipelineIter->getViewportLayerOffset()) % m_layersNum;
506
507 // bind framebuffer of this layer
508 gl.bindFramebuffer(GL_READ_FRAMEBUFFER, m_fbos[currentLayerWithOffset]);
509 GLU_EXPECT_NO_ERROR(gl.getError(), "bindFramebuffer() call failed.");
510
511 // verification
512 glw::GLfloat rgba[4] = { -1.f, -1.f, -1.f, -1.f };
513 gl.readPixels(m_fboSize / 2, m_fboSize / 2, 1, 1, GL_RGBA, GL_FLOAT, rgba);
514 GLU_EXPECT_NO_ERROR(gl.getError(), "ReadPixels");
515 bool validationResult =
516 ShaderViewportLayerArrayUtils::validateColor(tcu::Vec4(rgba[0], rgba[1], rgba[2], rgba[3]), renderColor);
517
518 TCU_CHECK_MSG(validationResult, "Expected pixel color did not match rendered one.");
519 }
520
521 if (m_currentLayer < (m_layersNum - 1))
522 {
523 m_currentLayer++;
524 return CONTINUE;
525 }
526
527 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
528 return STOP;
529 }
530
531 /** Constructor.
532 *
533 * @param context Rendering context
534 */
ShaderLayerFramebufferLayeredTestCase(deqp::Context & context)535 ShaderLayerFramebufferLayeredTestCase::ShaderLayerFramebufferLayeredTestCase(deqp::Context& context)
536 : ShaderLayerFramebufferTestCaseBase(
537 context, "ShaderLayerFramebufferLayeredTestCase",
538 "Implements gl_Layer tests for layered framebuffer described in CTS_ARB_shader_viewport_layer_array", true)
539 {
540 }
541
createFBO()542 void ShaderLayerFramebufferLayeredTestCase::createFBO()
543 {
544 const Functions& gl = m_context.getRenderContext().getFunctions();
545
546 gl.genTextures(1, &m_texture);
547 GLU_EXPECT_NO_ERROR(gl.getError(), "GenTextures");
548
549 gl.bindTexture(GL_TEXTURE_3D, m_texture);
550 GLU_EXPECT_NO_ERROR(gl.getError(), "bindTexture() call failed.");
551
552 gl.texImage3D(GL_TEXTURE_3D, 0, GL_RGBA8, m_fboSize, m_fboSize, m_layersNum, 0, GL_RGBA, GL_FLOAT, 0);
553 GLU_EXPECT_NO_ERROR(gl.getError(), "texImage3D() call failed.");
554
555 // create main FBO
556
557 gl.genFramebuffers(1, &m_mainFbo);
558 GLU_EXPECT_NO_ERROR(gl.getError(), "genFramebuffers() call failed.");
559 gl.bindFramebuffer(GL_FRAMEBUFFER, m_mainFbo);
560 GLU_EXPECT_NO_ERROR(gl.getError(), "bindFramebuffer() call failed.");
561 gl.framebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_texture, 0);
562 GLU_EXPECT_NO_ERROR(gl.getError(), "framebufferTexture() call failed.");
563
564 // create FBO for each layer
565
566 for (int i = 0; i < m_layersNum; ++i)
567 {
568 deUint32 layerFbo;
569
570 gl.genFramebuffers(1, &layerFbo);
571 GLU_EXPECT_NO_ERROR(gl.getError(), "genFramebuffers() call failed.");
572 gl.bindFramebuffer(GL_FRAMEBUFFER, layerFbo);
573 GLU_EXPECT_NO_ERROR(gl.getError(), "bindFramebuffer() call failed.");
574 gl.framebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_texture, 0, i);
575 GLU_EXPECT_NO_ERROR(gl.getError(), "framebufferTextureLayer() call failed.");
576
577 m_fbos.push_back(layerFbo);
578 }
579 }
580
deleteFBO()581 void ShaderLayerFramebufferLayeredTestCase::deleteFBO()
582 {
583 const Functions& gl = m_context.getRenderContext().getFunctions();
584
585 gl.deleteFramebuffers(1, &m_mainFbo);
586 GLU_EXPECT_NO_ERROR(gl.getError(), "DeleteFramebuffers");
587 for (int i = 0; i < m_layersNum; ++i)
588 {
589 gl.deleteFramebuffers(1, &(m_fbos[i]));
590 GLU_EXPECT_NO_ERROR(gl.getError(), "DeleteFramebuffers");
591 }
592 gl.deleteTextures(1, &m_texture);
593 GLU_EXPECT_NO_ERROR(gl.getError(), "DeleteTextures");
594 }
595
596 /** Constructor.
597 *
598 * @param context Rendering context
599 */
ShaderLayerFramebufferNonLayeredTestCase(deqp::Context & context)600 ShaderLayerFramebufferNonLayeredTestCase::ShaderLayerFramebufferNonLayeredTestCase(deqp::Context& context)
601 : ShaderLayerFramebufferTestCaseBase(
602 context, "ShaderLayerFramebufferNonLayeredTestCase",
603 "Implements gl_Layer tests for non-layered framebuffer described in CTS_ARB_shader_viewport_layer_array",
604 false)
605 {
606 }
607
createFBO()608 void ShaderLayerFramebufferNonLayeredTestCase::createFBO()
609 {
610 const Functions& gl = m_context.getRenderContext().getFunctions();
611 deUint32 tex;
612
613 gl.genTextures(1, &tex);
614 GLU_EXPECT_NO_ERROR(gl.getError(), "GenTextures");
615
616 gl.bindTexture(GL_TEXTURE_2D, tex);
617 GLU_EXPECT_NO_ERROR(gl.getError(), "bindTexture() call failed.");
618
619 gl.texImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, m_fboSize, m_fboSize, 0, GL_RGBA, GL_FLOAT, 0);
620 GLU_EXPECT_NO_ERROR(gl.getError(), "texImage2D() call failed.");
621
622 // create main FBO
623
624 gl.genFramebuffers(1, &m_mainFbo);
625 GLU_EXPECT_NO_ERROR(gl.getError(), "genFramebuffers() call failed.");
626 gl.bindFramebuffer(GL_FRAMEBUFFER, m_mainFbo);
627 GLU_EXPECT_NO_ERROR(gl.getError(), "bindFramebuffer() call failed.");
628 gl.framebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex, 0);
629 GLU_EXPECT_NO_ERROR(gl.getError(), "framebufferTexture() call failed.");
630
631 // main FBO is only layer
632
633 m_fbos.push_back(m_mainFbo);
634 }
635
deleteFBO()636 void ShaderLayerFramebufferNonLayeredTestCase::deleteFBO()
637 {
638 const Functions& gl = m_context.getRenderContext().getFunctions();
639
640 gl.deleteFramebuffers(1, &m_mainFbo);
641 GLU_EXPECT_NO_ERROR(gl.getError(), "DeleteFramebuffers");
642 gl.deleteTextures(1, &m_texture);
643 GLU_EXPECT_NO_ERROR(gl.getError(), "DeleteTextures");
644 }
645
646 /** Constructor.
647 *
648 * @param context Rendering context.
649 */
ShaderViewportLayerArray(deqp::Context & context)650 ShaderViewportLayerArray::ShaderViewportLayerArray(deqp::Context& context)
651 : TestCaseGroup(context, "shader_viewport_layer_array",
652 "Verify conformance of CTS_ARB_shader_viewport_layer_array implementation")
653 {
654 }
655
656 /** Initializes the test group contents. */
init()657 void ShaderViewportLayerArray::init()
658 {
659 addChild(new ShaderViewportIndexTestCase(m_context));
660 addChild(new ShaderLayerFramebufferLayeredTestCase(m_context));
661 addChild(new ShaderLayerFramebufferNonLayeredTestCase(m_context));
662 }
663 } /* gl4cts namespace */
664