Home | History | Annotate | Download | only in texture_cube_map_array
      1 /*-------------------------------------------------------------------------
      2  * OpenGL Conformance Test Suite
      3  * -----------------------------
      4  *
      5  * Copyright (c) 2014-2016 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  * \file  esextcTextureCubeMapArrayStencilAttachments.cpp
     26  * \brief Texture Cube Map Array Stencil Attachments (Test 3)
     27  */ /*-------------------------------------------------------------------*/
     28 
     29 #include "esextcTextureCubeMapArrayStencilAttachments.hpp"
     30 #include "gluContextInfo.hpp"
     31 #include "gluDefs.hpp"
     32 #include "glwEnums.hpp"
     33 #include "glwFunctions.hpp"
     34 #include "tcuTestLog.hpp"
     35 #include <string.h>
     36 
     37 namespace glcts
     38 {
     39 
     40 /** Number of byte for one vec4 position */
     41 const glw::GLuint TextureCubeMapArrayStencilAttachments::m_n_components = 4;
     42 /** Number of configuration different cube map array textures*/
     43 const glw::GLuint TextureCubeMapArrayStencilAttachments::m_n_cube_map_array_configurations = 4;
     44 /** Number of vertices per triangle use in gemoetry shader*/
     45 const glw::GLuint TextureCubeMapArrayStencilAttachments::m_n_vertices_gs = 3;
     46 
     47 /** Constructor **/
     48 CubeMapArrayDataStorage::CubeMapArrayDataStorage() : m_data_array(DE_NULL), m_depth(0), m_height(0), m_width(0)
     49 {
     50 }
     51 
     52 /** Destructor **/
     53 CubeMapArrayDataStorage::~CubeMapArrayDataStorage()
     54 {
     55 	deinit();
     56 }
     57 
     58 /** Initializes data array
     59  *
     60  *   @param width         width of the texture;
     61  *   @param height        height of the texture;
     62  *   @param depth         number of layers in the texture (for cube map array must be multiple of 6);
     63  *   @param initial_value value which the allocated storage should be cleared with;
     64  **/
     65 void CubeMapArrayDataStorage::init(const glw::GLuint width, const glw::GLuint height, const glw::GLuint depth,
     66 								   glw::GLubyte initial_value)
     67 {
     68 	deinit();
     69 
     70 	m_width  = width;
     71 	m_height = height;
     72 	m_depth  = depth;
     73 
     74 	m_data_array = new glw::GLubyte[getArraySize()];
     75 
     76 	memset(m_data_array, initial_value, getArraySize() * sizeof(glw::GLubyte));
     77 }
     78 
     79 /** Deinitializes data array **/
     80 void CubeMapArrayDataStorage::deinit(void)
     81 {
     82 	if (m_data_array != DE_NULL)
     83 	{
     84 		delete[] m_data_array;
     85 
     86 		m_data_array = DE_NULL;
     87 	}
     88 
     89 	m_width  = 0;
     90 	m_height = 0;
     91 	m_depth  = 0;
     92 }
     93 
     94 /** Returns pointer to array.
     95  *
     96  *  @return As per description.
     97  **/
     98 glw::GLubyte* CubeMapArrayDataStorage::getDataArray() const
     99 {
    100 	return m_data_array;
    101 }
    102 
    103 /** Returns size of the array in bytes **/
    104 glw::GLuint CubeMapArrayDataStorage::getArraySize() const
    105 {
    106 	return m_width * m_height * m_depth * TextureCubeMapArrayStencilAttachments::m_n_components;
    107 }
    108 
    109 /* Fragment shader code */
    110 const char* TextureCubeMapArrayStencilAttachments::m_fragment_shader_code = "${VERSION}\n"
    111 																			"\n"
    112 																			"${TEXTURE_CUBE_MAP_ARRAY_REQUIRE}\n"
    113 																			"\n"
    114 																			"precision highp float;\n"
    115 																			"\n"
    116 																			"layout(location = 0) out vec4 color;\n"
    117 																			"\n"
    118 																			"void main()\n"
    119 																			"{\n"
    120 																			"    color = vec4(0, 1, 1, 0);\n"
    121 																			"}\n";
    122 
    123 /* Vertex shader code */
    124 const char* TextureCubeMapArrayStencilAttachments::m_vertex_shader_code = "${VERSION}\n"
    125 																		  "\n"
    126 																		  "${TEXTURE_CUBE_MAP_ARRAY_REQUIRE}\n"
    127 																		  "\n"
    128 																		  "precision highp float;\n"
    129 																		  "\n"
    130 																		  "in vec4 vertex_position;\n"
    131 																		  "\n"
    132 																		  "void main()\n"
    133 																		  "{\n"
    134 																		  "    gl_Position = vertex_position;\n"
    135 																		  "}\n";
    136 
    137 /** Constructor
    138  *
    139  *  @param context            Test context
    140  *  @param name               Test case's name
    141  *  @param description        Test case's description
    142  *  @param immutable_storage  if set to true, immutable textures will be used;
    143  *  @param fbo_layered        if set to true, a layered draw framebuffer will be used;
    144  **/
    145 TextureCubeMapArrayStencilAttachments::TextureCubeMapArrayStencilAttachments(Context&			  context,
    146 																			 const ExtParameters& extParams,
    147 																			 const char* name, const char* description,
    148 																			 glw::GLboolean immutable_storage,
    149 																			 glw::GLboolean fbo_layered)
    150 	: TestCaseBase(context, extParams, name, description)
    151 	, m_fbo_layered(fbo_layered)
    152 	, m_immutable_storage(immutable_storage)
    153 	, m_fbo_draw_id(0)
    154 	, m_fbo_read_id(0)
    155 	, m_fragment_shader_id(0)
    156 	, m_geometry_shader_id(0)
    157 	, m_program_id(0)
    158 	, m_texture_cube_array_stencil_id(0)
    159 	, m_texture_cube_array_color_id(0)
    160 	, m_vao_id(0)
    161 	, m_vbo_id(0)
    162 	, m_vertex_shader_id(0)
    163 	, m_cube_map_array_data(DE_NULL)
    164 	, m_result_data(DE_NULL)
    165 {
    166 	/* Nothing to be done here */
    167 }
    168 
    169 /** Executes the test.
    170  *
    171  *  Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
    172  *
    173  *  Note the function throws exception should an error occur!
    174  *
    175  *  @return STOP if the test has finished, CONTINUE to indicate iterate() should be called once again.
    176  **/
    177 tcu::TestNode::IterateResult TextureCubeMapArrayStencilAttachments::iterate(void)
    178 {
    179 	initTest();
    180 
    181 	/* Retrieve ES entry-points */
    182 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
    183 
    184 	/* Set up stencil function */
    185 	gl.stencilFunc(GL_LESS, 0 /* ref */, 0xFF /* mask */);
    186 	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not setup stencil function");
    187 
    188 	/* Set up stencil operation */
    189 	gl.stencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
    190 	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not setup stencil operation");
    191 
    192 	/* Set up clear color */
    193 	gl.clearColor(1 /* red */, 0 /* green */, 0 /* blue */, 1 /* alpha */);
    194 	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not set stencil color value!");
    195 
    196 	bool has_test_failed = false;
    197 
    198 	/* Iterate through all defined configurations */
    199 	for (glw::GLuint test_index = 0; test_index < m_n_cube_map_array_configurations; test_index++)
    200 	{
    201 		/* Build and activate a test-specific program object */
    202 		buildAndUseProgram(test_index);
    203 
    204 		/* Create textures, framebuffer... before for every test iteration */
    205 		initTestIteration(test_index);
    206 
    207 		/* Clear the color buffer with (1, 0, 0, 1) color */
    208 		gl.clear(GL_COLOR_BUFFER_BIT);
    209 		GLU_EXPECT_NO_ERROR(gl.getError(), "Could not clear color buffer");
    210 
    211 		/* Draw a full-screen quad */
    212 		gl.drawArrays(GL_TRIANGLE_STRIP, 0 /* first */, 4 /* count */);
    213 		GLU_EXPECT_NO_ERROR(gl.getError(), "Rendering failed!");
    214 
    215 		/* Read the rendered data */
    216 		glw::GLuint array_size =
    217 			m_cube_map_array_data[test_index].getArraySize() / m_cube_map_array_data[test_index].getDepth();
    218 
    219 		m_result_data = new glw::GLubyte[array_size];
    220 
    221 		memset(m_result_data, 0, sizeof(glw::GLubyte) * array_size);
    222 
    223 		gl.bindFramebuffer(GL_READ_FRAMEBUFFER, m_fbo_read_id);
    224 		GLU_EXPECT_NO_ERROR(gl.getError(), "Could not bind read framebuffer");
    225 
    226 		if (m_fbo_layered)
    227 		{
    228 			for (glw::GLuint n_layer = 0; n_layer < m_cube_map_array_data[test_index].getDepth(); ++n_layer)
    229 			{
    230 				gl.framebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_texture_cube_array_color_id,
    231 										   0, /* level */
    232 										   n_layer);
    233 				GLU_EXPECT_NO_ERROR(gl.getError(),
    234 									"Could not attach texture layer to color attachment of read framebuffer");
    235 
    236 				/* Is the data correct? */
    237 				has_test_failed = readPixelsAndCompareWithExpectedResult(test_index);
    238 
    239 				if (has_test_failed)
    240 				{
    241 					break;
    242 				}
    243 			} /* for (all layers) */
    244 		}	 /* if (m_fbo_layered) */
    245 		else
    246 		{
    247 			gl.framebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_texture_cube_array_color_id,
    248 									   0 /* level */, 0);
    249 			GLU_EXPECT_NO_ERROR(gl.getError(),
    250 								"Could not attach texture layer to color attachment of read framebuffer");
    251 
    252 			/* Is the data correct? */
    253 			has_test_failed = readPixelsAndCompareWithExpectedResult(test_index);
    254 		}
    255 
    256 		/* Clean up */
    257 		cleanAfterTest();
    258 
    259 		if (has_test_failed)
    260 		{
    261 			break;
    262 		}
    263 	} /* for (all configurations) */
    264 
    265 	if (has_test_failed)
    266 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
    267 	else
    268 		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
    269 
    270 	return STOP;
    271 }
    272 
    273 /** Deinitializes GLES objects created during the test.
    274  *
    275  */
    276 void TextureCubeMapArrayStencilAttachments::deinit(void)
    277 {
    278 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
    279 
    280 	/* Disable the stencil test */
    281 	gl.disable(GL_STENCIL_TEST);
    282 
    283 	/* If any of the iterations have broken, we should clean up here. */
    284 	cleanAfterTest();
    285 
    286 	gl.bindVertexArray(0);
    287 
    288 	/* Release test-wide objects */
    289 	if (m_vbo_id != 0)
    290 	{
    291 		gl.deleteBuffers(1, &m_vbo_id);
    292 
    293 		m_vbo_id = 0;
    294 	}
    295 
    296 	if (m_fbo_draw_id != 0)
    297 	{
    298 		gl.deleteFramebuffers(1, &m_fbo_draw_id);
    299 
    300 		m_fbo_draw_id = 0;
    301 	}
    302 
    303 	if (m_fbo_read_id != 0)
    304 	{
    305 		gl.deleteFramebuffers(1, &m_fbo_read_id);
    306 
    307 		m_fbo_read_id = 0;
    308 	}
    309 
    310 	if (m_vao_id != 0)
    311 	{
    312 		gl.deleteVertexArrays(1, &m_vao_id);
    313 
    314 		m_vao_id = 0;
    315 	}
    316 
    317 	if (m_cube_map_array_data != DE_NULL)
    318 	{
    319 		delete[] m_cube_map_array_data;
    320 
    321 		m_cube_map_array_data = DE_NULL;
    322 	}
    323 
    324 	/* Deinitialize base class */
    325 	TestCaseBase::deinit();
    326 }
    327 
    328 /** Build and use a program object **/
    329 void TextureCubeMapArrayStencilAttachments::buildAndUseProgram(glw::GLuint test_index)
    330 {
    331 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
    332 
    333 	/* Create a program object */
    334 	m_program_id = gl.createProgram();
    335 	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not create a program object");
    336 
    337 	/* Create shader objects that will make up the program object */
    338 	m_fragment_shader_id = gl.createShader(GL_FRAGMENT_SHADER);
    339 	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not create a fragment shader object");
    340 
    341 	m_vertex_shader_id = gl.createShader(GL_VERTEX_SHADER);
    342 	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not create a vertex shader object");
    343 
    344 	if (m_fbo_layered)
    345 	{
    346 		std::string		  geometry_shader_code;
    347 		const char*		  geometry_shader_code_ptr = DE_NULL;
    348 		std::stringstream max_vertices_sstream;
    349 		std::stringstream n_iterations_sstream;
    350 
    351 		max_vertices_sstream << m_cube_map_array_data[test_index].getDepth() * m_n_vertices_gs;
    352 		n_iterations_sstream << m_cube_map_array_data[test_index].getDepth();
    353 
    354 		geometry_shader_code	 = getGeometryShaderCode(max_vertices_sstream.str(), n_iterations_sstream.str());
    355 		geometry_shader_code_ptr = geometry_shader_code.c_str();
    356 
    357 		m_geometry_shader_id = gl.createShader(m_glExtTokens.GEOMETRY_SHADER);
    358 		GLU_EXPECT_NO_ERROR(gl.getError(), "Could not create a geometry shader object");
    359 
    360 		/* Build a program object */
    361 		if (!buildProgram(m_program_id, m_fragment_shader_id, 1, &m_fragment_shader_code, m_geometry_shader_id, 1,
    362 						  &geometry_shader_code_ptr, m_vertex_shader_id, 1, &m_vertex_shader_code))
    363 		{
    364 			TCU_FAIL("Program could not have been created sucessfully from valid vertex/geometry/fragment shaders");
    365 		}
    366 	} /* if (m_fbo_layered) */
    367 	else
    368 	{
    369 		/* Build a program object */
    370 		if (!buildProgram(m_program_id, m_fragment_shader_id, 1, &m_fragment_shader_code, m_vertex_shader_id, 1,
    371 						  &m_vertex_shader_code))
    372 		{
    373 			TCU_FAIL("Program could not have been created sucessfully from valid vertex/fragment shaders");
    374 		}
    375 	}
    376 
    377 	/* Use program */
    378 	glw::GLint posAttrib = -1;
    379 
    380 	gl.useProgram(m_program_id);
    381 	GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed");
    382 
    383 	posAttrib = gl.getAttribLocation(m_program_id, "vertex_position");
    384 	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not get attribute location!");
    385 
    386 	if (posAttrib == -1)
    387 	{
    388 		TCU_FAIL("vertex_position attribute is considered inactive");
    389 	}
    390 
    391 	gl.vertexAttribPointer(posAttrib, 4, GL_FLOAT, GL_FALSE, 0, 0);
    392 	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not configure vertex_position vertex attribute array");
    393 
    394 	gl.enableVertexAttribArray(posAttrib);
    395 	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not enable vertex attribute array!");
    396 }
    397 
    398 /** Check Framebuffer Status. Throws a TestError exception, should the framebuffer status
    399  *  be found incomplete.
    400  *
    401  *  @param framebuffer_status FBO status, as returned by glCheckFramebufferStatus(), to check.
    402  *
    403  */
    404 void TextureCubeMapArrayStencilAttachments::checkFramebufferStatus(glw::GLenum framebuffer_status)
    405 {
    406 	if (GL_FRAMEBUFFER_COMPLETE != framebuffer_status)
    407 	{
    408 		switch (framebuffer_status)
    409 		{
    410 		case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
    411 		{
    412 			TCU_FAIL("Framebuffer incomplete, status: GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT");
    413 		}
    414 
    415 		case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS:
    416 		{
    417 			TCU_FAIL("Framebuffer incomplete, status: GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS");
    418 		}
    419 
    420 		case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
    421 		{
    422 			TCU_FAIL("Framebuffer incomplete, status: GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT");
    423 		}
    424 
    425 		case GL_FRAMEBUFFER_UNSUPPORTED:
    426 		{
    427 			TCU_FAIL("Framebuffer incomplete, status: Error: GL_FRAMEBUFFER_UNSUPPORTED");
    428 		}
    429 
    430 		default:
    431 		{
    432 			TCU_FAIL("Framebuffer incomplete, status not recognized");
    433 		}
    434 		}; /* switch (framebuffer_status) */
    435 	}	  /* if (GL_FRAMEBUFFER_COMPLETE != framebuffer_status) */
    436 }
    437 
    438 /** Clean after test **/
    439 void TextureCubeMapArrayStencilAttachments::cleanAfterTest(void)
    440 {
    441 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
    442 
    443 	gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
    444 	gl.bindFramebuffer(GL_READ_FRAMEBUFFER, 0);
    445 	gl.bindTexture(GL_TEXTURE_CUBE_MAP_ARRAY, 0);
    446 	gl.useProgram(0);
    447 
    448 	if (m_program_id != 0)
    449 	{
    450 		gl.deleteProgram(m_program_id);
    451 
    452 		m_program_id = 0;
    453 	}
    454 
    455 	if (m_fragment_shader_id != 0)
    456 	{
    457 		gl.deleteShader(m_fragment_shader_id);
    458 
    459 		m_fragment_shader_id = 0;
    460 	}
    461 
    462 	if (m_geometry_shader_id != 0)
    463 	{
    464 		gl.deleteShader(m_geometry_shader_id);
    465 
    466 		m_geometry_shader_id = 0;
    467 	}
    468 
    469 	if (m_vertex_shader_id != 0)
    470 	{
    471 		gl.deleteShader(m_vertex_shader_id);
    472 
    473 		m_vertex_shader_id = 0;
    474 	}
    475 
    476 	if (m_texture_cube_array_color_id != 0)
    477 	{
    478 		gl.deleteTextures(1, &m_texture_cube_array_color_id);
    479 
    480 		m_texture_cube_array_color_id = 0;
    481 	}
    482 
    483 	if (m_texture_cube_array_stencil_id != 0)
    484 	{
    485 		gl.deleteTextures(1, &m_texture_cube_array_stencil_id);
    486 
    487 		m_texture_cube_array_stencil_id = 0;
    488 	}
    489 
    490 	if (m_result_data != DE_NULL)
    491 	{
    492 		delete[] m_result_data;
    493 
    494 		m_result_data = DE_NULL;
    495 	}
    496 }
    497 
    498 /** Create an immutable texture storage for a color texture.
    499  *
    500  *  @param test_index number of the test configuration to use texture properties from.
    501  **/
    502 void TextureCubeMapArrayStencilAttachments::createImmutableCubeArrayColor(glw::GLuint test_index)
    503 {
    504 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
    505 
    506 	gl.texStorage3D(GL_TEXTURE_CUBE_MAP_ARRAY,					   /* target */
    507 					1,											   /* levels */
    508 					GL_RGBA8,									   /* internalformat */
    509 					m_cube_map_array_data[test_index].getWidth(),  /* width */
    510 					m_cube_map_array_data[test_index].getHeight(), /* height */
    511 					m_cube_map_array_data[test_index].getDepth()); /* depth */
    512 
    513 	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not create an immutable color texture storage!");
    514 }
    515 
    516 /** Create an immutable texture storage for a stencil texture.
    517  *
    518  *  @param test_index number of the test configuration to use texture properties from.
    519  **/
    520 void TextureCubeMapArrayStencilAttachments::createImmutableCubeArrayStencil(glw::GLuint test_index)
    521 {
    522 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
    523 
    524 	fillStencilData(test_index);
    525 
    526 	gl.texStorage3D(GL_TEXTURE_CUBE_MAP_ARRAY,					   /* target */
    527 					1,											   /* levels */
    528 					GL_DEPTH24_STENCIL8,						   /* internalformat */
    529 					m_cube_map_array_data[test_index].getWidth(),  /* width */
    530 					m_cube_map_array_data[test_index].getHeight(), /* height */
    531 					m_cube_map_array_data[test_index].getDepth()); /* depth */
    532 
    533 	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not create an immutable stencil texture storage!");
    534 
    535 	gl.texSubImage3D(GL_TEXTURE_CUBE_MAP_ARRAY,							/* target */
    536 					 0,													/* level */
    537 					 0,													/* xoffset */
    538 					 0,													/* yoffset */
    539 					 0,													/* zoffset */
    540 					 m_cube_map_array_data[test_index].getWidth(),		/* width */
    541 					 m_cube_map_array_data[test_index].getHeight(),		/* height */
    542 					 m_cube_map_array_data[test_index].getDepth(),		/* depth */
    543 					 GL_DEPTH_STENCIL,									/* format */
    544 					 GL_UNSIGNED_INT_24_8,								/* type */
    545 					 m_cube_map_array_data[test_index].getDataArray()); /* data */
    546 
    547 	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not fill allocated texture storage with texture data!");
    548 }
    549 
    550 /** Create a mutable texture storage for a color texture.
    551  *
    552  *  @param test_index number of the test configuration to use texture properties from.
    553  *
    554  **/
    555 void TextureCubeMapArrayStencilAttachments::createMutableCubeArrayColor(glw::GLuint test_index)
    556 {
    557 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
    558 
    559 	gl.texImage3D(GL_TEXTURE_CUBE_MAP_ARRAY,						 /* target */
    560 				  0,												 /* level */
    561 				  GL_RGBA8,											 /* internal format */
    562 				  m_cube_map_array_data[test_index].getWidth(),		 /* width */
    563 				  m_cube_map_array_data[test_index].getHeight(),	 /* height */
    564 				  m_cube_map_array_data[test_index].getDepth(),		 /* depth */
    565 				  0,												 /* border */
    566 				  GL_RGBA,											 /* format */
    567 				  GL_UNSIGNED_BYTE,									 /* type */
    568 				  m_cube_map_array_data[test_index].getDataArray()); /* pixel data */
    569 
    570 	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not create a mutable color texture storage!");
    571 }
    572 
    573 /** Create a mutable texture storage for a stencil texture.
    574  *
    575  *  @param test_index number of the test configuration to use texture properties from.
    576  **/
    577 void TextureCubeMapArrayStencilAttachments::createMutableCubeArrayStencil(glw::GLuint test_index)
    578 {
    579 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
    580 
    581 	fillStencilData(test_index);
    582 
    583 	gl.texImage3D(GL_TEXTURE_CUBE_MAP_ARRAY,						 /* target */
    584 				  0,												 /* level */
    585 				  GL_DEPTH24_STENCIL8,								 /* internal format */
    586 				  m_cube_map_array_data[test_index].getWidth(),		 /* width */
    587 				  m_cube_map_array_data[test_index].getHeight(),	 /* height */
    588 				  m_cube_map_array_data[test_index].getDepth(),		 /* depth */
    589 				  0,												 /* border */
    590 				  GL_DEPTH_STENCIL,									 /* format */
    591 				  GL_UNSIGNED_INT_24_8,								 /* type */
    592 				  m_cube_map_array_data[test_index].getDataArray()); /* pixel data */
    593 
    594 	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not create a mutable stencil texture storage!");
    595 }
    596 
    597 /** Fill the texture used as stencil attachment with reference values
    598  *
    599  *  @param test_index index of the test configuration this call is being made for.
    600  *
    601  **/
    602 void TextureCubeMapArrayStencilAttachments::fillStencilData(glw::GLuint test_index)
    603 {
    604 	glw::GLubyte* const data = m_cube_map_array_data[test_index].getDataArray();
    605 
    606 	memset(data, 0, m_cube_map_array_data[test_index].getArraySize() * sizeof(glw::GLubyte));
    607 
    608 	for (glw::GLuint depth_index = 0; depth_index < m_cube_map_array_data[test_index].getDepth(); depth_index++)
    609 	{
    610 		for (glw::GLuint x = 0; x < m_cube_map_array_data[test_index].getWidth(); x++)
    611 		{
    612 			for (glw::GLuint y = m_cube_map_array_data[test_index].getHeight() / 2;
    613 				 y < m_cube_map_array_data[test_index].getHeight(); y++)
    614 			{
    615 				glw::GLuint depth_position_in_array = m_cube_map_array_data[test_index].getWidth() *
    616 													  m_cube_map_array_data[test_index].getHeight() * m_n_components *
    617 													  depth_index;
    618 
    619 				glw::GLuint y_position_in_array = m_cube_map_array_data[test_index].getHeight() * m_n_components * y;
    620 
    621 				glw::GLuint x_position_in_array = m_n_components * x;
    622 
    623 				glw::GLuint index_array = depth_position_in_array + y_position_in_array + x_position_in_array;
    624 
    625 				memset((data + index_array), 1, m_n_components);
    626 
    627 			} /* for (all rows) */
    628 		}	 /* for (all columns) */
    629 	}		  /* for (all layers) */
    630 }
    631 
    632 /** Returns a geometry shader code, adapted to user-specific values.
    633  *
    634  *  @param max_vertices  String storing maximum amount of vertices that geometry shader can output;
    635  *  @param n_layers      String storing number of layer-faces in cube map array texture;
    636  */
    637 std::string TextureCubeMapArrayStencilAttachments::getGeometryShaderCode(const std::string& max_vertices,
    638 																		 const std::string& n_layers)
    639 {
    640 	/* Geometry shader template code */
    641 	std::string m_geometry_shader_template = "${VERSION}\n"
    642 											 "\n"
    643 											 "${GEOMETRY_SHADER_REQUIRE}\n"
    644 											 "\n"
    645 											 "layout(triangles)                                       in;\n"
    646 											 "layout(triangle_strip, max_vertices = <-MAX-VERTICES->) out;\n"
    647 											 "\n"
    648 											 "void main(void)\n"
    649 											 "{\n"
    650 											 "   int layer;\n"
    651 											 "\n"
    652 											 "   for (layer = 0; layer < <-N_LAYERS->; layer++)\n"
    653 											 "   {\n"
    654 											 "       gl_Layer    = layer;\n"
    655 											 "       gl_Position = gl_in[0].gl_Position;\n"
    656 											 "       EmitVertex();\n"
    657 											 "\n"
    658 											 "       gl_Layer    = layer;\n"
    659 											 "       gl_Position = gl_in[1].gl_Position;\n"
    660 											 "       EmitVertex();\n"
    661 											 "\n"
    662 											 "       gl_Layer    = layer;\n"
    663 											 "       gl_Position = gl_in[2].gl_Position;\n"
    664 											 "       EmitVertex();\n"
    665 											 "\n"
    666 											 "       EndPrimitive();\n"
    667 											 "   }\n"
    668 											 "}\n";
    669 
    670 	/* Replace a "maximum number of emitted vertices" token with user-provided value */
    671 	std::string template_name	 = "<-MAX-VERTICES->";
    672 	std::size_t template_position = m_geometry_shader_template.find(template_name);
    673 
    674 	while (template_position != std::string::npos)
    675 	{
    676 		m_geometry_shader_template =
    677 			m_geometry_shader_template.replace(template_position, template_name.length(), max_vertices);
    678 
    679 		template_position = m_geometry_shader_template.find(template_name);
    680 	}
    681 
    682 	/* Do the same for the number of layers we want the geometry shader to modify. */
    683 	template_name	 = "<-N_LAYERS->";
    684 	template_position = m_geometry_shader_template.find(template_name);
    685 
    686 	while (template_position != std::string::npos)
    687 	{
    688 		m_geometry_shader_template =
    689 			m_geometry_shader_template.replace(template_position, template_name.length(), n_layers);
    690 
    691 		template_position = m_geometry_shader_template.find(template_name);
    692 	}
    693 	if (!m_is_geometry_shader_extension_supported && m_fbo_layered)
    694 	{
    695 		throw tcu::NotSupportedError(GEOMETRY_SHADER_EXTENSION_NOT_SUPPORTED);
    696 	}
    697 
    698 	return m_geometry_shader_template;
    699 }
    700 
    701 /** Initializes GLES objects created during the test. **/
    702 void TextureCubeMapArrayStencilAttachments::initTest(void)
    703 {
    704 	/* Check if EXT_texture_cube_map_array extension is supported */
    705 	if (!m_is_texture_cube_map_array_supported)
    706 	{
    707 		throw tcu::NotSupportedError(TEXTURE_CUBE_MAP_ARRAY_EXTENSION_NOT_SUPPORTED, "", __FILE__, __LINE__);
    708 	}
    709 	if (!m_is_geometry_shader_extension_supported && m_fbo_layered)
    710 	{
    711 		throw tcu::NotSupportedError(GEOMETRY_SHADER_EXTENSION_NOT_SUPPORTED);
    712 	}
    713 
    714 	/* Retrieve ES entry-points */
    715 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
    716 
    717 	/* Create 4 different configurations of cube map array texture */
    718 	m_cube_map_array_data = new CubeMapArrayDataStorage[m_n_cube_map_array_configurations];
    719 
    720 	m_cube_map_array_data[0].init(64, 64, 18);
    721 	m_cube_map_array_data[1].init(117, 117, 6);
    722 	m_cube_map_array_data[2].init(256, 256, 6);
    723 	m_cube_map_array_data[3].init(173, 173, 12);
    724 
    725 	/* full screen square */
    726 	glw::GLfloat vertices[] = { -1.0f, -1.0f, 0.0f, 1.0f, -1.0f, 1.0f, 0.0f, 1.0f,
    727 								1.0f,  -1.0f, 0.0f, 1.0f, 1.0f,  1.0f, 0.0f, 1.0f };
    728 
    729 	/* Generate and bind VAO */
    730 	gl.genVertexArrays(1, &m_vao_id);
    731 	gl.bindVertexArray(m_vao_id);
    732 
    733 	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not create vertex array object");
    734 
    735 	gl.genBuffers(1, &m_vbo_id);
    736 	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not generate buffer object!");
    737 
    738 	gl.bindBuffer(GL_ARRAY_BUFFER, m_vbo_id);
    739 	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not bind buffer object!");
    740 
    741 	gl.bufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    742 	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not set data for buffer object!");
    743 
    744 	/* Create and configure framebuffer object */
    745 	gl.genFramebuffers(1, &m_fbo_read_id);
    746 	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not generate framebuffer object!");
    747 
    748 	gl.genFramebuffers(1, &m_fbo_draw_id);
    749 	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not generate framebuffer object!");
    750 
    751 	gl.enable(GL_STENCIL_TEST);
    752 	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not enable stencil test!");
    753 }
    754 
    755 /** Create and set OpenGL object need for one test iteration
    756  *
    757  *  @param test_index number of the test configuration to use texture properties from.
    758  **/
    759 void TextureCubeMapArrayStencilAttachments::initTestIteration(glw::GLuint test_index)
    760 {
    761 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
    762 
    763 	/* Set up texture storage for color data */
    764 	gl.genTextures(1, &m_texture_cube_array_color_id);
    765 	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not generate texture object!");
    766 
    767 	gl.bindTexture(GL_TEXTURE_CUBE_MAP_ARRAY, m_texture_cube_array_color_id);
    768 	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not bind a texture object to GL_TEXTURE_CUBE_MAP_ARRAY_EXT target");
    769 
    770 	if (m_immutable_storage)
    771 	{
    772 		createImmutableCubeArrayColor(test_index);
    773 	}
    774 	else
    775 	{
    776 		createMutableCubeArrayColor(test_index);
    777 	}
    778 
    779 	/* Set up texture storage for stencil data */
    780 	gl.genTextures(1, &m_texture_cube_array_stencil_id);
    781 	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not generate texture object!");
    782 
    783 	gl.bindTexture(GL_TEXTURE_CUBE_MAP_ARRAY, m_texture_cube_array_stencil_id);
    784 	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not bind texture object to GL_TEXTURE_CUBE_MAP_ARRAY_EXT target");
    785 
    786 	if (m_immutable_storage)
    787 	{
    788 		createImmutableCubeArrayStencil(test_index);
    789 	}
    790 	else
    791 	{
    792 		createMutableCubeArrayStencil(test_index);
    793 	}
    794 
    795 	/* Set up the draw framebuffer */
    796 	gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, m_fbo_draw_id);
    797 	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not bind draw framebuffer!");
    798 
    799 	gl.viewport(0, 0, m_cube_map_array_data[test_index].getWidth(), m_cube_map_array_data[test_index].getHeight());
    800 	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not set viewport");
    801 
    802 	if (m_fbo_layered)
    803 	{
    804 		setupLayeredFramebuffer();
    805 	}
    806 	else
    807 	{
    808 		setupNonLayeredFramebuffer();
    809 	}
    810 
    811 	/* Is the draw FBO complete, now that we're done with configuring it? */
    812 	checkFramebufferStatus(gl.checkFramebufferStatus(GL_DRAW_FRAMEBUFFER));
    813 }
    814 
    815 /** Read pixels from color attachment of read framebuffer and compare them with expected result.
    816  *
    817  *  @param test_index index of cube map array configuration
    818  *
    819  *  @return true if failed, false otherwise.
    820  */
    821 bool TextureCubeMapArrayStencilAttachments::readPixelsAndCompareWithExpectedResult(glw::GLuint test_index)
    822 {
    823 	const glw::Functions& gl			  = m_context.getRenderContext().getFunctions();
    824 	bool				  has_test_failed = false;
    825 
    826 	gl.readPixels(0 /* x */, 0 /* y */, m_cube_map_array_data[test_index].getWidth(),
    827 				  m_cube_map_array_data[test_index].getHeight(), GL_RGBA, GL_UNSIGNED_BYTE, m_result_data);
    828 
    829 	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not read pixel data from color buffer");
    830 
    831 	glw::GLubyte expectedData[] = { 0, 0, 0, 0 };
    832 
    833 	/* Loop over all pixels and compare the rendered data with reference values */
    834 	for (glw::GLuint y = 0; y < m_cube_map_array_data[test_index].getHeight(); ++y)
    835 	{
    836 		/* Top half should be filled with different data than the bottom half */
    837 		if (y >= m_cube_map_array_data[test_index].getHeight() / 2)
    838 		{
    839 			expectedData[0] = 0;
    840 			expectedData[1] = 255;
    841 			expectedData[2] = 255;
    842 			expectedData[3] = 0;
    843 		}
    844 		else
    845 		{
    846 			expectedData[0] = 255;
    847 			expectedData[1] = 0;
    848 			expectedData[2] = 0;
    849 			expectedData[3] = 255;
    850 		}
    851 
    852 		const glw::GLubyte* data_row =
    853 			m_result_data + y * m_cube_map_array_data[test_index].getHeight() * m_n_cube_map_array_configurations;
    854 
    855 		for (glw::GLuint x = 0; x < m_cube_map_array_data[test_index].getWidth(); ++x)
    856 		{
    857 			const glw::GLubyte* data = data_row + x * m_n_components;
    858 
    859 			if (data[0] != expectedData[0] || data[1] != expectedData[1] || data[2] != expectedData[2] ||
    860 				data[3] != expectedData[3])
    861 			{
    862 				m_testCtx.getLog() << tcu::TestLog::Message << "Expected Data ( " << (unsigned int)expectedData[0]
    863 								   << "," << (unsigned int)expectedData[1] << "," << (unsigned int)expectedData[2]
    864 								   << "," << (unsigned int)expectedData[3] << ") "
    865 								   << "Result Data ( " << (unsigned int)data[0] << "," << (unsigned int)data[1] << ","
    866 								   << (unsigned int)data[2] << "," << (unsigned int)data[3] << ")"
    867 								   << tcu::TestLog::EndMessage;
    868 
    869 				has_test_failed = true;
    870 			}
    871 		} /* for (all pixels in a row) */
    872 	}	 /* for (all rows) */
    873 
    874 	return has_test_failed;
    875 }
    876 
    877 /** Attach color and stencil attachments to a layer framebuffer **/
    878 void TextureCubeMapArrayStencilAttachments::setupLayeredFramebuffer()
    879 {
    880 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
    881 
    882 	gl.framebufferTexture(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_texture_cube_array_color_id, 0 /* level */);
    883 	GLU_EXPECT_NO_ERROR(gl.getError(), "Error attaching texture to GL_COLOR_ATTACHMENT0!");
    884 
    885 	gl.framebufferTexture(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, m_texture_cube_array_stencil_id,
    886 						  0 /* level */);
    887 	GLU_EXPECT_NO_ERROR(gl.getError(), "Error attaching texture to GL_DEPTH_STENCIL_ATTACHMENT! ");
    888 }
    889 
    890 /** Attach color and stencil attachments to a non-layered framebuffer. **/
    891 void TextureCubeMapArrayStencilAttachments::setupNonLayeredFramebuffer()
    892 {
    893 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
    894 
    895 	gl.framebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_texture_cube_array_color_id, 0 /* level */,
    896 							   0 /* layer */);
    897 	GLU_EXPECT_NO_ERROR(gl.getError(), "Error attaching texture layer 0 to GL_COLOR_ATTACHMENT0!");
    898 
    899 	gl.framebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, m_texture_cube_array_stencil_id,
    900 							   0 /* level */, 0 /* layer */);
    901 	GLU_EXPECT_NO_ERROR(gl.getError(), "Error attaching texture layer 0 to GL_DEPTH_STENCIL_ATTACHMENT! ");
    902 }
    903 
    904 } // namespace glcts
    905