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 **/
CubeMapArrayDataStorage()48 CubeMapArrayDataStorage::CubeMapArrayDataStorage() : m_data_array(DE_NULL), m_depth(0), m_height(0), m_width(0)
49 {
50 }
51 
52 /** Destructor **/
~CubeMapArrayDataStorage()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  **/
init(const glw::GLuint width,const glw::GLuint height,const glw::GLuint depth,glw::GLubyte initial_value)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 **/
deinit(void)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  **/
getDataArray() const98 glw::GLubyte* CubeMapArrayDataStorage::getDataArray() const
99 {
100 	return m_data_array;
101 }
102 
103 /** Returns size of the array in bytes **/
getArraySize() const104 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  **/
TextureCubeMapArrayStencilAttachments(Context & context,const ExtParameters & extParams,const char * name,const char * description,glw::GLboolean immutable_storage,glw::GLboolean fbo_layered)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  **/
iterate(void)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  */
deinit(void)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 **/
buildAndUseProgram(glw::GLuint test_index)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  */
checkFramebufferStatus(glw::GLenum framebuffer_status)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 **/
cleanAfterTest(void)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  **/
createImmutableCubeArrayColor(glw::GLuint test_index)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  **/
createImmutableCubeArrayStencil(glw::GLuint test_index)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  **/
createMutableCubeArrayColor(glw::GLuint test_index)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  **/
createMutableCubeArrayStencil(glw::GLuint test_index)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  **/
fillStencilData(glw::GLuint test_index)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  */
getGeometryShaderCode(const std::string & max_vertices,const std::string & n_layers)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. **/
initTest(void)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  **/
initTestIteration(glw::GLuint test_index)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  */
readPixelsAndCompareWithExpectedResult(glw::GLuint test_index)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 **/
setupLayeredFramebuffer()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. **/
setupNonLayeredFramebuffer()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