Home | History | Annotate | Download | only in gl
      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 
     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 
    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 
    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 
    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 
    189 ShaderViewportLayerArrayUtils::ShaderPipeline::~ShaderPipeline()
    190 {
    191 	if (m_program)
    192 	{
    193 		delete m_program;
    194 	}
    195 }
    196 
    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 
    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 
    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 
    260 bool ShaderViewportLayerArrayUtils::validateColor(tcu::Vec4 renderedColor, tcu::Vec4 referenceColor)
    261 {
    262 	const float epsilon = 0.008f;
    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 
    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 */
    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 
    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 
    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  */
    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 
    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 
    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 
    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 
    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 */
    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 
    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 
    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 */
    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 
    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 
    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  */
    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. */
    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