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