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