Merge vk-gl-cts/opengl-cts-4.6.2 into vk-gl-cts/main
[platform/upstream/VK-GL-CTS.git] / external / openglcts / modules / gl / gl4cSparseBufferTests.cpp
1 /*-------------------------------------------------------------------------
2  * OpenGL Conformance Test Suite
3  * -----------------------------
4  *
5  * Copyright (c) 2015-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  */ /*!
26  * \file  gl4cSparseBufferTests.cpp
27  * \brief Conformance tests for the GL_ARB_sparse_buffer functionality.
28  */ /*-------------------------------------------------------------------*/
29
30 #include "gl4cSparseBufferTests.hpp"
31 #include "gluContextInfo.hpp"
32 #include "gluDefs.hpp"
33 #include "glwEnums.hpp"
34 #include "glwFunctions.hpp"
35 #include "tcuTestLog.hpp"
36
37 #include <string.h>
38 #include <vector>
39
40 #ifndef GL_SPARSE_BUFFER_PAGE_SIZE_ARB
41 #define GL_SPARSE_BUFFER_PAGE_SIZE_ARB 0x82F8
42 #endif
43 #ifndef GL_SPARSE_STORAGE_BIT_ARB
44 #define GL_SPARSE_STORAGE_BIT_ARB 0x0400
45 #endif
46
47 namespace gl4cts
48 {
49 /** Rounds up the provided offset so that it is aligned to the specified value (eg. page size).
50  *  In other words, the result value meets the following requirements:
51  *
52  *  1)  result value % input value  = 0
53  *  2)  result value               >= offset
54  *  3) (result value - offset)     <  input value
55  *
56  *  @param offset Offset to be used for the rounding operation.
57  *  @param value  Value to align the offset to.
58  *
59  *  @return Result value.
60  **/
61 unsigned int SparseBufferTestUtilities::alignOffset(const unsigned int& offset, const unsigned int& value)
62 {
63         return offset + (value - offset % value) % value;
64 }
65
66 /** Builds a compute program object, using the user-specified CS code snippets.
67  *
68  *  @param gl                     DEQP CTS GL functions container.
69  *  @param cs_body_parts          Code snippets to use for the compute shader. Must hold exactly
70  *                                @param n_cs_body_parts null-terminated text strings.
71  *  @param n_cs_body_parts        Number of code snippets accessible via @param cs_body_parts.
72  *
73  *  @return Result PO id if program has been linked successfully, 0 otherwise.
74  **/
75 glw::GLuint SparseBufferTestUtilities::createComputeProgram(const glw::Functions& gl, const char** cs_body_parts,
76                                                                                                                         unsigned int n_cs_body_parts)
77 {
78         glw::GLint  compile_status = GL_FALSE;
79         glw::GLuint cs_id                  = 0;
80         glw::GLint  link_status = GL_FALSE;
81         glw::GLuint po_id                  = 0;
82         bool            result             = true;
83
84         if (n_cs_body_parts > 0)
85         {
86                 cs_id = gl.createShader(GL_COMPUTE_SHADER);
87         }
88
89         po_id = gl.createProgram();
90
91         GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() / glCreateShader() call(s) failed.");
92
93         if (n_cs_body_parts > 0)
94         {
95                 gl.attachShader(po_id, cs_id);
96         }
97
98         GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() call(s) failed.");
99
100         if (n_cs_body_parts > 0)
101         {
102                 gl.shaderSource(cs_id, n_cs_body_parts, cs_body_parts, NULL); /* length */
103         }
104
105         GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call(s) failed.");
106
107         gl.compileShader(cs_id);
108
109         GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() call failed.");
110
111         gl.getShaderiv(cs_id, GL_COMPILE_STATUS, &compile_status);
112
113         GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() call failed");
114
115         char temp[1024];
116         gl.getShaderInfoLog(cs_id, 1024, NULL, temp);
117
118         if (GL_TRUE != compile_status)
119         {
120                 result = false;
121
122                 goto end;
123         }
124
125         gl.linkProgram(po_id);
126
127         GLU_EXPECT_NO_ERROR(gl.getError(), "glLinkProgram() call failed.");
128
129         gl.getProgramiv(po_id, GL_LINK_STATUS, &link_status);
130
131         GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() call failed.");
132
133         if (GL_TRUE != link_status)
134         {
135                 result = false;
136
137                 goto end;
138         }
139
140 end:
141         if (cs_id != 0)
142         {
143                 gl.deleteShader(cs_id);
144
145                 cs_id = 0;
146         }
147
148         if (!result)
149         {
150                 if (po_id != 0)
151                 {
152                         gl.deleteProgram(po_id);
153
154                         po_id = 0;
155                 }
156         } /* if (!result) */
157
158         return po_id;
159 }
160
161 /** Builds a program object, using the user-specified code snippets. Can optionally configure
162  *  the PO to use pre-defined attribute locations & transform feed-back varyings.
163  *
164  *  @param gl                     DEQP CTS GL functions container.
165  *  @param fs_body_parts          Code snippets to use for the fragment shader. Must hold exactly
166  *                                @param n_fs_body_parts null-terminated text strings. May only
167  *                                be NULL if @param n_fs_body_parts is 0.
168  *  @param n_fs_body_parts        See @param fs_body_parts definitions.
169  *  @param vs_body_parts          Code snippets to use for the vertex shader. Must hold exactly
170  *                                @param n_vs_body_parts null-terminated text strings. May only
171  *                                be NULL if @param n_vs_body_parts is 0.
172  *  @param n_vs_body_parts        See @param vs_body_parts definitions.
173  *  @param attribute_names        Null-terminated attribute names to pass to the
174  *                                glBindAttribLocation() call.
175  *                                May only be NULL if @param n_attribute_properties is 0.
176  *  @param attribute_locations    Attribute locations to pass to the glBindAttribLocation() call.
177  *                                May only be NULL if @param n_attribute_properties is 0.
178  *  @param n_attribute_properties See @param attribute_names and @param attribute_locations definitions.
179  *  @param tf_varyings            Transform-feedback varying names to use for the
180  *                                glTransformFeedbackVaryings() call. May only be NULL if
181  *                                @param n_tf_varyings is 0.
182  *  @param n_tf_varyings          See @param tf_varyings definition.
183  *  @param tf_varying_mode        Transform feedback mode to use for the
184  *                                glTransformFeedbackVaryings() call. Only used if @param n_tf_varyings
185  *                                is 0.
186  *
187  *  @return Result PO id if program has been linked successfully, 0 otherwise.
188  **/
189 glw::GLuint SparseBufferTestUtilities::createProgram(const glw::Functions& gl, const char** fs_body_parts,
190                                                                                                          unsigned int n_fs_body_parts, const char** vs_body_parts,
191                                                                                                          unsigned int n_vs_body_parts, const char** attribute_names,
192                                                                                                          const unsigned int*       attribute_locations,
193                                                                                                          unsigned int                      n_attribute_properties,
194                                                                                                          const glw::GLchar* const* tf_varyings, unsigned int n_tf_varyings,
195                                                                                                          glw::GLenum tf_varying_mode)
196 {
197         glw::GLint  compile_status = GL_FALSE;
198         glw::GLuint fs_id                  = 0;
199         glw::GLint  link_status = GL_FALSE;
200         glw::GLuint po_id                  = 0;
201         bool            result             = true;
202         glw::GLuint vs_id                  = 0;
203
204         if (n_fs_body_parts > 0)
205         {
206                 fs_id = gl.createShader(GL_FRAGMENT_SHADER);
207         }
208
209         po_id = gl.createProgram();
210
211         if (n_vs_body_parts > 0)
212         {
213                 vs_id = gl.createShader(GL_VERTEX_SHADER);
214         }
215
216         GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() / glCreateShader() call(s) failed.");
217
218         if (n_fs_body_parts > 0)
219         {
220                 gl.attachShader(po_id, fs_id);
221         }
222
223         if (n_vs_body_parts > 0)
224         {
225                 gl.attachShader(po_id, vs_id);
226         }
227
228         GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() call(s) failed.");
229
230         if (n_fs_body_parts > 0)
231         {
232                 gl.shaderSource(fs_id, n_fs_body_parts, fs_body_parts, NULL); /* length */
233         }
234
235         if (n_vs_body_parts > 0)
236         {
237                 gl.shaderSource(vs_id, n_vs_body_parts, vs_body_parts, NULL); /* length */
238         }
239
240         GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call(s) failed.");
241
242         const glw::GLuint  so_ids[] = { fs_id, vs_id };
243         const unsigned int n_so_ids = sizeof(so_ids) / sizeof(so_ids[0]);
244
245         for (unsigned int n_so_id = 0; n_so_id < n_so_ids; ++n_so_id)
246         {
247                 if (so_ids[n_so_id] != 0)
248                 {
249                         gl.compileShader(so_ids[n_so_id]);
250
251                         GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() call failed.");
252
253                         gl.getShaderiv(so_ids[n_so_id], GL_COMPILE_STATUS, &compile_status);
254
255                         GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() call failed");
256
257                         char temp[1024];
258                         gl.getShaderInfoLog(so_ids[n_so_id], 1024, NULL, temp);
259
260                         if (GL_TRUE != compile_status)
261                         {
262                                 result = false;
263
264                                 goto end;
265                         }
266                 } /* if (so_ids[n_so_id] != 0) */
267         }        /* for (all shader object IDs) */
268
269         for (unsigned int n_attribute = 0; n_attribute < n_attribute_properties; ++n_attribute)
270         {
271                 gl.bindAttribLocation(po_id, attribute_locations[n_attribute], attribute_names[n_attribute]);
272
273                 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindAttribLocation() call failed.");
274         } /* for (all attributes to configure) */
275
276         if (n_tf_varyings != 0)
277         {
278                 gl.transformFeedbackVaryings(po_id, n_tf_varyings, tf_varyings, tf_varying_mode);
279
280                 GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings() call failed.");
281         } /* if (n_tf_varyings != 0) */
282
283         gl.linkProgram(po_id);
284
285         GLU_EXPECT_NO_ERROR(gl.getError(), "glLinkProgram() call failed.");
286
287         gl.getProgramiv(po_id, GL_LINK_STATUS, &link_status);
288
289         GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() call failed.");
290
291         if (GL_TRUE != link_status)
292         {
293                 result = false;
294
295                 goto end;
296         }
297
298 end:
299         if (fs_id != 0)
300         {
301                 gl.deleteShader(fs_id);
302
303                 fs_id = 0;
304         }
305
306         if (vs_id != 0)
307         {
308                 gl.deleteShader(vs_id);
309
310                 vs_id = 0;
311         }
312
313         if (!result)
314         {
315
316                 if (po_id != 0)
317                 {
318                         gl.deleteProgram(po_id);
319
320                         po_id = 0;
321                 }
322         } /* if (!result) */
323
324         return po_id;
325 }
326
327 /** Returns a string with textual representation of the @param flags bitfield
328  *  holding bits applicable to the @param flags argument of glBufferStorage()
329  *  calls.
330  *
331  *  @param flags Flags argument, as supported by the @param flags argument of
332  *               glBufferStorage() entry-point.
333  *
334  *  @return Described string.
335  **/
336 std::string SparseBufferTestUtilities::getSparseBOFlagsString(glw::GLenum flags)
337 {
338         unsigned int      n_flags_added = 0;
339         std::stringstream result_sstream;
340
341         if ((flags & GL_CLIENT_STORAGE_BIT) != 0)
342         {
343                 result_sstream << "GL_CLIENT_STORAGE_BIT";
344
345                 ++n_flags_added;
346         }
347
348         if ((flags & GL_DYNAMIC_STORAGE_BIT) != 0)
349         {
350                 result_sstream << ((n_flags_added) ? " | " : "") << "GL_DYNAMIC_STORAGE_BIT";
351
352                 ++n_flags_added;
353         }
354
355         if ((flags & GL_MAP_COHERENT_BIT) != 0)
356         {
357                 result_sstream << ((n_flags_added) ? " | " : "") << "GL_MAP_COHERENT_BIT";
358
359                 ++n_flags_added;
360         }
361
362         if ((flags & GL_MAP_PERSISTENT_BIT) != 0)
363         {
364                 result_sstream << ((n_flags_added) ? " | " : "") << "GL_MAP_PERSISTENT_BIT";
365
366                 ++n_flags_added;
367         }
368
369         if ((flags & GL_SPARSE_STORAGE_BIT_ARB) != 0)
370         {
371                 result_sstream << ((n_flags_added) ? " | " : "") << "GL_SPARSE_STORAGE_BIT";
372
373                 ++n_flags_added;
374         }
375
376         return result_sstream.str();
377 }
378
379 /** Constructor.
380  *
381  *  @param context     Rendering context
382  *  @param name        Test name
383  *  @param description Test description
384  */
385 NegativeTests::NegativeTests(deqp::Context& context)
386         : TestCase(context, "NegativeTests", "Implements all negative tests described in CTS_ARB_sparse_buffer")
387         , m_helper_bo_id(0)
388         , m_immutable_bo_id(0)
389         , m_immutable_bo_size(1024768)
390         , m_sparse_bo_id(0)
391 {
392         /* Left blank intentionally */
393 }
394
395 /** Stub deinit method. */
396 void NegativeTests::deinit()
397 {
398         const glw::Functions& gl = m_context.getRenderContext().getFunctions();
399
400         if (m_helper_bo_id != 0)
401         {
402                 gl.deleteBuffers(1, &m_helper_bo_id);
403
404                 m_helper_bo_id = 0;
405         }
406
407         if (m_immutable_bo_id != 0)
408         {
409                 gl.deleteBuffers(1, &m_immutable_bo_id);
410
411                 m_immutable_bo_id = 0;
412         }
413
414         if (m_sparse_bo_id != 0)
415         {
416                 gl.deleteBuffers(1, &m_sparse_bo_id);
417
418                 m_sparse_bo_id = 0;
419         }
420 }
421
422 /** Stub init method */
423 void NegativeTests::init()
424 {
425         /* Nothing to do here */
426 }
427
428 /** Executes test iteration.
429  *
430  *  @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
431  */
432 tcu::TestNode::IterateResult NegativeTests::iterate()
433 {
434         glw::GLvoid*              data_ptr  = DE_NULL;
435         const glw::Functions& gl                = m_context.getRenderContext().getFunctions();
436         glw::GLint                        page_size = 0;
437         bool                              result        = true;
438
439         /* Only execute if the implementation supports the GL_ARB_sparse_buffer extension */
440         if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_sparse_buffer"))
441         {
442                 throw tcu::NotSupportedError("GL_ARB_sparse_buffer is not supported");
443         }
444
445         /* Set up */
446         gl.getIntegerv(GL_SPARSE_BUFFER_PAGE_SIZE_ARB, &page_size);
447         GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() call failed.");
448
449         gl.genBuffers(1, &m_helper_bo_id);
450         gl.genBuffers(1, &m_immutable_bo_id);
451         gl.genBuffers(1, &m_sparse_bo_id);
452         GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() call(s) failed.");
453
454         gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bo_id);
455         gl.bindBuffer(GL_COPY_READ_BUFFER, m_immutable_bo_id);
456         gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_helper_bo_id);
457         GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() call failed.");
458
459         gl.bufferStorage(GL_ARRAY_BUFFER, page_size * 3, /* size as per test spec */
460                                          DE_NULL,                                                /* data */
461                                          GL_SPARSE_STORAGE_BIT_ARB);
462         gl.bufferStorage(GL_COPY_READ_BUFFER, m_immutable_bo_size, /* size */
463                                          DE_NULL,                                                                  /* data */
464                                          0);
465         GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferStorage() call(s) failed.");
466
467         /** * Verify glBufferPageCommitmentARB() returns GL_INVALID_ENUM if <target> is
468          *    set to GL_INTERLEAVED_ATTRIBS. */
469         glw::GLint error_code = GL_NO_ERROR;
470
471         gl.bufferPageCommitmentARB(GL_INTERLEAVED_ATTRIBS, 0, /* offset */
472                                                            page_size, GL_TRUE);           /* commit */
473
474         error_code = gl.getError();
475         if (error_code != GL_INVALID_ENUM)
476         {
477                 m_testCtx.getLog() << tcu::TestLog::Message
478                                                    << "Invalid <target> value passed to a glBufferPageCommitmentARB() call"
479                                                           " did not generate a GL_INVALID_ENUM error."
480                                                    << tcu::TestLog::EndMessage;
481
482                 result = false;
483         }
484
485         /*  * Verify glBufferStorage() throws a GL_INVALID_VALUE error if <flags> is
486          *    set to (GL_SPARSE_STORAGE_BIT_ARB | GL_MAP_READ_BIT) or
487          *    (GL_SPARSE_STORAGE_BIT_ARB | GL_MAP_WRITE_BIT). */
488         gl.bufferStorage(GL_ELEMENT_ARRAY_BUFFER, page_size * 3, /* size */
489                                          DE_NULL,                                                                /* data */
490                                          GL_SPARSE_STORAGE_BIT_ARB | GL_MAP_READ_BIT);
491
492         error_code = gl.getError();
493         if (error_code != GL_INVALID_VALUE)
494         {
495                 m_testCtx.getLog() << tcu::TestLog::Message
496                                                    << "Invalid <flags> value set to GL_SPARSE_STORAGE_BIT_ARB | GL_MAP_READ_BIT "
497                                                           "did not generate a GL_INVALID_VALUE error."
498                                                    << tcu::TestLog::EndMessage;
499
500                 result = false;
501         }
502
503         gl.bufferStorage(GL_ELEMENT_ARRAY_BUFFER, page_size * 3, /* size */
504                                          DE_NULL,                                                                /* data */
505                                          GL_SPARSE_STORAGE_BIT_ARB | GL_MAP_WRITE_BIT);
506
507         error_code = gl.getError();
508         if (error_code != GL_INVALID_VALUE)
509         {
510                 m_testCtx.getLog() << tcu::TestLog::Message
511                                                    << "Invalid <flags> value set to GL_SPARSE_STORAGE_BIT_ARB | GL_MAP_WRITE_BIT "
512                                                           "did not generate a GL_INVALID_VALUE error."
513                                                    << tcu::TestLog::EndMessage;
514
515                 result = false;
516         }
517
518         /*  * Verify glBufferPageCommitmentARB() generates a GL_INVALID_OPERATION error if
519          *    it is called for an immutable BO, which has not been initialized with the
520          *    GL_SPARSE_STORAGE_BIT_ARB flag. */
521         gl.bufferPageCommitmentARB(GL_COPY_READ_BUFFER, 0, /* offset */
522                                                            page_size, GL_TRUE); /* commit */
523
524         error_code = gl.getError();
525         if (error_code != GL_INVALID_OPERATION)
526         {
527                 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid error code generated by glBufferPageCommitmentARB() "
528                                                                                                            " issued against an immutable, non-sparse buffer object."
529                                                    << tcu::TestLog::EndMessage;
530
531                 result = false;
532         }
533
534         /*  * Verify glBufferPageCommitmentARB() issues a GL_INVALID_VALUE error if <offset>
535          *    is set to (0.5 * GL_SPARSE_BUFFER_PAGE_SIZE_ARB). Skip if the constant's value
536          *    is equal to 1. */
537         if (page_size != 1)
538         {
539                 gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, page_size / 2, /* offset */
540                                                                    page_size, GL_TRUE);                    /* commit */
541
542                 error_code = gl.getError();
543                 if (error_code != GL_INVALID_VALUE)
544                 {
545                         m_testCtx.getLog() << tcu::TestLog::Message
546                                                            << "Invalid error code generated by glBufferPageCommitmentARB() "
547                                                                   "whose <offset> value was set to (page size / 2)."
548                                                            << tcu::TestLog::EndMessage;
549
550                         result = false;
551                 }
552         } /* if (page_size != 1) */
553
554         /*  * Verify glBufferPageCommitmentARB() emits a GL_INVALID_VALUE error if <size>
555          *    is set to (0.5 * GL_SPARSE_BUFFER_PAGE_SIZE_ARB). Skip if the constant's value
556          *    is equal to 1. */
557         if (page_size != 1)
558         {
559                 gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0,          /* offset */
560                                                                    page_size / 2, GL_TRUE); /* commit */
561
562                 error_code = gl.getError();
563                 if (error_code != GL_INVALID_VALUE)
564                 {
565                         m_testCtx.getLog() << tcu::TestLog::Message
566                                                            << "Invalid error code generated by glBufferPageCommitmentARB() "
567                                                                   "whose <size> value was set to (page size / 2)."
568                                                            << tcu::TestLog::EndMessage;
569
570                         result = false;
571                 }
572         } /* if (page_size != 1) */
573
574         /*  * Verify glBufferPageCommitmentARB() returns GL_INVALID_VALUE if <offset> is
575          *    set to -1, but all other arguments are valid. */
576         gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, -1, /* offset */
577                                                            page_size, GL_TRUE); /* commit */
578
579         error_code = gl.getError();
580         if (error_code != GL_INVALID_VALUE)
581         {
582                 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid error code generated by glBufferPageCommitmentARB() "
583                                                                                                            "whose <offset> argument was set to -1."
584                                                    << tcu::TestLog::EndMessage;
585
586                 result = false;
587         }
588
589         /*  * Verify glBufferPageCommitmentARB() returns GL_INVALID_VALUE if <size> is
590          *    set to -1, but all other arguments are valid. */
591         gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0, /* offset */
592                                                            -1,                             /* size */
593                                                            GL_TRUE);               /* commit */
594
595         error_code = gl.getError();
596         if (error_code != GL_INVALID_VALUE)
597         {
598                 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid error code generated by glBufferPageCommitmentARB() "
599                                                                                                            "whose <size> argument was set to -1."
600                                                    << tcu::TestLog::EndMessage;
601
602                 result = false;
603         }
604
605         /*  * Verify glBufferPageCommitmentARB() returns GL_INVALID_VALUE if BO's size is
606          *    GL_SPARSE_BUFFER_PAGE_SIZE_ARB * 3, but the <offset> is set to 0 and <size>
607          *    argument used for the call is set to GL_SPARSE_BUFFER_PAGE_SIZE_ARB * 4. */
608         gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0, /* offset */
609                                                            page_size * 4,         /* size */
610                                                            GL_TRUE);
611
612         error_code = gl.getError();
613         if (error_code != GL_INVALID_VALUE)
614         {
615                 m_testCtx.getLog() << tcu::TestLog::Message
616                                                    << "Invalid error code generated by glBufferPageCommitmentARB() "
617                                                           "whose <offset> was set to 0 and <size> was set to (page size * 4), "
618                                                           "when the buffer storage size had been configured to be (page size * 3)."
619                                                    << tcu::TestLog::EndMessage;
620
621                 result = false;
622         }
623
624         /*  * Verify glBufferPageCommitmentARB() returns GL_INVALID_VALUE if BO's size is
625          *    GL_SPARSE_BUFFER_PAGE_SIZE_ARB * 3, but the <offset> is set to
626          *    GL_SPARSE_BUFFER_PAGE_SIZE_ARB * 1 and <size> argument used for the call
627          *    is set to GL_SPARSE_BUFFER_PAGE_SIZE_ARB * 3. */
628         gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, page_size * 1, /* offset */
629                                                            page_size * 3,                                  /* size */
630                                                            GL_TRUE);
631
632         error_code = gl.getError();
633         if (error_code != GL_INVALID_VALUE)
634         {
635                 m_testCtx.getLog() << tcu::TestLog::Message
636                                                    << "Invalid error code generated by glBufferPageCommitmentARB() "
637                                                           "whose <offset> was set to (page size) and <size> was set to (page size * 3), "
638                                                           "when the buffer storage size had been configured to be (page size * 3)."
639                                                    << tcu::TestLog::EndMessage;
640
641                 result = false;
642         }
643
644         /*  * Verify that calling glMapBuffer() or glMapBufferRange() against a sparse
645          *    buffer generates a GL_INVALID_OPERATION error. */
646         data_ptr = gl.mapBuffer(GL_ARRAY_BUFFER, GL_READ_ONLY);
647
648         if (data_ptr != DE_NULL)
649         {
650                 m_testCtx.getLog() << tcu::TestLog::Message
651                                                    << "Non-NULL pointer returned by an invalid glMapBuffer() call, issued "
652                                                           "against a sparse buffer object"
653                                                    << tcu::TestLog::EndMessage;
654
655                 result = false;
656         }
657
658         error_code = gl.getError();
659
660         if (error_code != GL_INVALID_OPERATION)
661         {
662                 m_testCtx.getLog() << tcu::TestLog::Message
663                                                    << "Invalid error code generated by glMapBuffer() call, issued against "
664                                                           "a sparse buffer object"
665                                                    << tcu::TestLog::EndMessage;
666
667                 result = false;
668         }
669
670         data_ptr = gl.mapBufferRange(GL_ARRAY_BUFFER, 0, /* offset */
671                                                                  page_size,                      /* length */
672                                                                  GL_MAP_READ_BIT);
673
674         if (data_ptr != DE_NULL)
675         {
676                 m_testCtx.getLog() << tcu::TestLog::Message
677                                                    << "Non-NULL pointer returned by an invalid glMapBufferRange() call, issued "
678                                                           "against a sparse buffer object"
679                                                    << tcu::TestLog::EndMessage;
680
681                 result = false;
682         }
683
684         error_code = gl.getError();
685
686         if (error_code != GL_INVALID_OPERATION)
687         {
688                 m_testCtx.getLog() << tcu::TestLog::Message
689                                                    << "Invalid error code generated by glMapBufferRange() call, issued against "
690                                                           "a sparse buffer object"
691                                                    << tcu::TestLog::EndMessage;
692
693                 result = false;
694         }
695
696         m_testCtx.setTestResult(result ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, result ? "Pass" : "Fail");
697
698         return STOP;
699 }
700
701 /** Constructor.
702  *
703  *  @param context     Rendering context
704  *  @param name        Test name
705  *  @param description Test description
706  */
707 PageSizeGetterTest::PageSizeGetterTest(deqp::Context& context)
708         : TestCase(context, "PageSizeGetterTest",
709                            "Verifies GL_SPARSE_BUFFER_PAGE_SIZE_ARB pname is recognized by the getter functions")
710 {
711         /* Left blank intentionally */
712 }
713
714 /** Stub deinit method. */
715 void PageSizeGetterTest::deinit()
716 {
717         /* Nothing to be done here */
718 }
719
720 /** Stub init method */
721 void PageSizeGetterTest::init()
722 {
723         /* Nothing to do here */
724 }
725
726 /** Executes test iteration.
727  *
728  *  @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
729  */
730 tcu::TestNode::IterateResult PageSizeGetterTest::iterate()
731 {
732         const glw::Functions& gl                           = m_context.getRenderContext().getFunctions();
733         glw::GLboolean            page_size_bool   = false;
734         glw::GLdouble             page_size_double = 0.0;
735         glw::GLfloat              page_size_float  = 0.0f;
736         glw::GLint                        page_size_int = 0;
737         glw::GLint64              page_size_int64  = 0;
738         bool                              result                   = true;
739
740         /* Only execute if the implementation supports the GL_ARB_sparse_buffer extension */
741         if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_sparse_buffer"))
742         {
743                 throw tcu::NotSupportedError("GL_ARB_sparse_buffer is not supported");
744         }
745
746         /* glGetIntegerv() */
747         gl.getIntegerv(GL_SPARSE_BUFFER_PAGE_SIZE_ARB, &page_size_int);
748         GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() call failed");
749
750         if (page_size_int < 1 || page_size_int > 65536)
751         {
752                 m_testCtx.getLog() << tcu::TestLog::Message << "Page size reported by the implementation (" << page_size_int
753                                                    << ")"
754                                                           " by glGetIntegerv() is out of the allowed range."
755                                                    << tcu::TestLog::EndMessage;
756
757                 result = false;
758         }
759
760         /* glGetBooleanv() */
761         gl.getBooleanv(GL_SPARSE_BUFFER_PAGE_SIZE_ARB, &page_size_bool);
762         GLU_EXPECT_NO_ERROR(gl.getError(), "glGetBooleanv() call failed");
763
764         if (!page_size_bool)
765         {
766                 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid page size reported by glGetBooleanv()"
767                                                    << tcu::TestLog::EndMessage;
768
769                 result = false;
770         }
771
772         /* glGetDoublev() */
773         gl.getDoublev(GL_SPARSE_BUFFER_PAGE_SIZE_ARB, &page_size_double);
774         GLU_EXPECT_NO_ERROR(gl.getError(), "glGetDoublev() call failed");
775
776         if (de::abs(page_size_double - page_size_int) > 1e-5)
777         {
778                 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid page size reported by glGetDoublev()"
779                                                                                                            " (reported value: "
780                                                    << page_size_double << ", expected value: " << page_size_int << ")"
781                                                    << tcu::TestLog::EndMessage;
782
783                 result = false;
784         }
785
786         /* glGetFloatv() */
787         gl.getFloatv(GL_SPARSE_BUFFER_PAGE_SIZE_ARB, &page_size_float);
788         GLU_EXPECT_NO_ERROR(gl.getError(), "glGetFloatv() call failed");
789
790         if (de::abs(page_size_float - static_cast<float>(page_size_int)) > 1e-5f)
791         {
792                 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid page size reported by glGetFloatv()"
793                                                                                                            " (reported value: "
794                                                    << page_size_float << ", expected value: " << page_size_int << ")"
795                                                    << tcu::TestLog::EndMessage;
796
797                 result = false;
798         }
799
800         /* glGetInteger64v() */
801         gl.getInteger64v(GL_SPARSE_BUFFER_PAGE_SIZE_ARB, &page_size_int64);
802         GLU_EXPECT_NO_ERROR(gl.getError(), "glGetFloatv() call failed");
803
804         if (page_size_int64 != page_size_int)
805         {
806                 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid page size reported by glGetInteger64v()"
807                                                                                                            " (reported value: "
808                                                    << page_size_int64 << ", expected value: " << page_size_int << ")"
809                                                    << tcu::TestLog::EndMessage;
810
811                 result = false;
812         }
813
814         m_testCtx.setTestResult(result ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, result ? "Pass" : "Fail");
815
816         return STOP;
817 }
818
819 /** Constructor.
820  *
821  *  @param gl                         GL entry-points container
822  *  @param testContext                CTS test context
823  *  @param page_size                  Page size, as reported by implementation for the GL_SPARSE_BUFFER_PAGE_SIZE_ARB query.
824  *  @param pGLBufferPageCommitmentARB Func ptr to glBufferPageCommitmentARB() entry-point.
825  *  @param all_pages_committed        true to run the test with all data memory pages committed,
826  *                                    false to leave some of them without an actual memory backing.
827  */
828 AtomicCounterBufferStorageTestCase::AtomicCounterBufferStorageTestCase(const glw::Functions& gl,
829                                                                                                                                            tcu::TestContext&     testContext,
830                                                                                                                                            glw::GLint page_size, bool all_pages_committed)
831         : m_all_pages_committed(all_pages_committed)
832         , m_gl(gl)
833         , m_gl_atomic_counter_uniform_array_stride(0)
834         , m_gl_max_vertex_atomic_counters_value(0)
835         , m_helper_bo(0)
836         , m_helper_bo_size(0)
837         , m_helper_bo_size_rounded(0)
838         , m_n_draw_calls(3) /* as per test spec */
839         , m_page_size(page_size)
840         , m_po(0)
841         , m_sparse_bo(0)
842         , m_sparse_bo_data_size(0)
843         , m_sparse_bo_data_size_rounded(0)
844         , m_sparse_bo_data_start_offset(0)
845         , m_sparse_bo_data_start_offset_rounded(0)
846         , m_testCtx(testContext)
847         , m_vao(0)
848 {
849         /* Left blank intentionally */
850 }
851
852 /** Releases all GL objects used across all test case iterations.
853  *
854  *  Called once during BufferStorage test run-time.
855  */
856 void AtomicCounterBufferStorageTestCase::deinitTestCaseGlobal()
857 {
858         if (m_helper_bo != 0)
859         {
860                 m_gl.deleteBuffers(1, &m_helper_bo);
861
862                 m_helper_bo = 0;
863         }
864
865         if (m_po != 0)
866         {
867                 m_gl.deleteProgram(m_po);
868
869                 m_po = 0;
870         }
871
872         if (m_vao != 0)
873         {
874                 m_gl.deleteVertexArrays(1, &m_vao);
875
876                 m_vao = 0;
877         }
878 }
879
880 /** Releases temporary GL objects, created specifically for one test case iteration. */
881 void AtomicCounterBufferStorageTestCase::deinitTestCaseIteration()
882 {
883         if (m_sparse_bo != 0)
884         {
885                 m_gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bo);
886                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
887
888                 m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, m_sparse_bo_data_start_offset_rounded,            /* offset */
889                                                                          m_sparse_bo_data_size_rounded, GL_FALSE); /* commit */
890                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
891
892                 m_sparse_bo = 0;
893         }
894 }
895
896 /** Executes a single test iteration. The BufferStorage test will call this method
897  *  numerously during its life-time, testing various valid flag combinations applied
898  *  to the tested sparse buffer object at glBufferStorage() call time.
899  *
900  *  @param sparse_bo_storage_flags <flags> argument, used by the test in the glBufferStorage()
901  *                                 call to set up the sparse buffer's storage.
902  *
903  *  @return true if the test case executed correctly, false otherwise.
904  */
905 bool AtomicCounterBufferStorageTestCase::execute(glw::GLuint sparse_bo_storage_flags)
906 {
907         (void)sparse_bo_storage_flags;
908         static const unsigned char data_zero = 0;
909         bool                                       result       = true;
910
911         /* Only execute if GL_MAX_VERTEX_ATOMIC_COUNTERS is > 0 */
912         if (m_gl_max_vertex_atomic_counters_value == 0)
913         {
914                 m_testCtx.getLog() << tcu::TestLog::Message << "G_MAX_VERTEX_ATOMIC_COUNTERS is 0. Skipping the test."
915                                                    << tcu::TestLog::EndMessage;
916
917                 goto end;
918         }
919
920         /* Bind the test program object */
921         m_gl.useProgram(m_po);
922         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUseProgram() call failed.");
923
924         m_gl.bindBuffer(GL_ATOMIC_COUNTER_BUFFER, m_sparse_bo);
925         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
926
927         /* Try using both ranged and non-ranged AC bindings.
928          *
929          * NOTE: It only makes sense to perform glBindBufferBase() test if all AC pages are
930          *       committed
931          */
932         for (unsigned int n_binding_type = (m_all_pages_committed) ? 0 : 1;
933                  n_binding_type < 2; /* glBindBufferBase(), glBindBufferRange() */
934                  ++n_binding_type)
935         {
936                 bool result_local = true;
937
938                 if (n_binding_type == 0)
939                 {
940                         m_gl.bindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, /* index */
941                                                                 m_sparse_bo);
942
943                         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBufferBase() call failed.");
944                 }
945                 else
946                 {
947                         m_gl.bindBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, /* index */
948                                                                  m_sparse_bo, m_sparse_bo_data_start_offset, m_helper_bo_size);
949
950                         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBufferRange() call failed.");
951                 }
952
953                 /* Zero out the sparse buffer's contents */
954                 m_gl.clearBufferData(GL_ATOMIC_COUNTER_BUFFER, GL_R8, GL_RED, GL_UNSIGNED_BYTE, &data_zero);
955                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glClearBufferData() call failed.");
956
957                 /* Run the test */
958                 m_gl.drawArraysInstanced(GL_POINTS, 0,                                                  /* first */
959                                                                  m_gl_max_vertex_atomic_counters_value, /* count */
960                                                                  m_n_draw_calls);
961                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawArraysInstanced() call failed");
962
963                 /* Retrieve the atomic counter values */
964                 const glw::GLuint* ac_data = NULL;
965                 const unsigned int n_expected_written_values =
966                         (m_all_pages_committed) ? m_gl_max_vertex_atomic_counters_value : m_gl_max_vertex_atomic_counters_value / 2;
967
968                 m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_sparse_bo);
969                 m_gl.bindBuffer(GL_COPY_WRITE_BUFFER, m_helper_bo);
970                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffeR() call failed");
971
972                 m_gl.copyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER,
973                                                            (n_binding_type == 0) ? 0 : m_sparse_bo_data_start_offset, 0, /* writeOffset */
974                                                            m_sparse_bo_data_size);
975                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCopyBufferSubData() call failed.");
976
977                 ac_data = (const glw::GLuint*)m_gl.mapBufferRange(GL_COPY_WRITE_BUFFER, 0, /* offset */
978                                                                                                                   m_sparse_bo_data_size, GL_MAP_READ_BIT);
979
980                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glMapBufferRange() call failed.");
981
982                 for (unsigned int n_counter = 0; n_counter < n_expected_written_values && result_local; ++n_counter)
983                 {
984                         const unsigned int expected_value = m_n_draw_calls;
985                         const unsigned int retrieved_value =
986                                 *((unsigned int*)((unsigned char*)ac_data + m_gl_atomic_counter_uniform_array_stride * n_counter));
987
988                         if (expected_value != retrieved_value)
989                         {
990                                 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid atomic counter value "
991                                                                                                                            "["
992                                                                    << retrieved_value << "]"
993                                                                                                                  " instead of the expected value "
994                                                                                                                  "["
995                                                                    << expected_value << "]"
996                                                                                                                 " at index "
997                                                                    << n_counter << " when using "
998                                                                    << ((n_binding_type == 0) ? "glBindBufferBase()" : "glBindBufferRange()")
999                                                                    << " for AC binding configuration" << tcu::TestLog::EndMessage;
1000
1001                                 result_local = false;
1002                         } /* if (expected_value != retrieved_value) */
1003                 }        /* for (all draw calls that need to be executed) */
1004
1005                 m_gl.unmapBuffer(GL_COPY_WRITE_BUFFER);
1006                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUnmapBuffer() call failed.");
1007
1008                 result &= result_local;
1009         } /* for (both binding types) */
1010
1011 end:
1012         return result;
1013 }
1014
1015 /** Initializes GL objects used across all test case iterations.
1016  *
1017  *  Called once during BufferStorage test run-time.
1018  */
1019 bool AtomicCounterBufferStorageTestCase::initTestCaseGlobal()
1020 {
1021         const glw::GLuint ac_uniform_index = 0; /* only one uniform is defined in the VS below */
1022         std::stringstream n_counters_sstream;
1023         std::string               n_counters_string;
1024         bool                      result = true;
1025
1026         static const char* vs_body_preamble = "#version 430 core\n"
1027                                                                                   "\n";
1028
1029         static const char* vs_body_core = "layout(binding = 0) uniform atomic_uint counters[N_COUNTERS];\n"
1030                                                                           "\n"
1031                                                                           "void main()\n"
1032                                                                           "{\n"
1033                                                                           "    for (uint n = 0; n < N_COUNTERS; ++n)\n"
1034                                                                           "    {\n"
1035                                                                           "        if (n == gl_VertexID)\n"
1036                                                                           "        {\n"
1037                                                                           "            atomicCounterIncrement(counters[n]);\n"
1038                                                                           "        }\n"
1039                                                                           "    }\n"
1040                                                                           "\n"
1041                                                                           "    gl_Position = vec4(0.0, 0.0, 0.0, 1.0);\n"
1042                                                                           "}\n";
1043         const char* vs_body_parts[] = { vs_body_preamble, DE_NULL, /* will be set to n_counters_string.c_str() */
1044                                                                         vs_body_core };
1045         const unsigned int n_vs_body_parts = sizeof(vs_body_parts) / sizeof(vs_body_parts[0]);
1046
1047         /* Retrieve GL_MAX_VERTEX_ATOMIC_COUNTERS value. The test will only be executed if it's >= 1 */
1048         m_gl.getIntegerv(GL_MAX_VERTEX_ATOMIC_COUNTERS, &m_gl_max_vertex_atomic_counters_value);
1049         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGetIntegerv() call failed.");
1050
1051         if (m_gl_max_vertex_atomic_counters_value == 0)
1052         {
1053                 goto end;
1054         }
1055
1056         /* Form the N_COUNTERS declaration string */
1057         n_counters_sstream << "#define N_COUNTERS " << m_gl_max_vertex_atomic_counters_value << "\n";
1058         n_counters_string = n_counters_sstream.str();
1059
1060         vs_body_parts[1] = n_counters_string.c_str();
1061
1062         /* Set up the program object */
1063         DE_ASSERT(m_po == 0);
1064
1065         m_po =
1066                 SparseBufferTestUtilities::createProgram(m_gl, DE_NULL,                                                   /* fs_body_parts   */
1067                                                                                                  0,                                                                               /* n_fs_body_parts */
1068                                                                                                  vs_body_parts, n_vs_body_parts, DE_NULL, /* attribute_names        */
1069                                                                                                  DE_NULL,                                                                 /* attribute_locations    */
1070                                                                                                  0);                                                                      /* n_attribute_properties */
1071
1072         if (m_po == 0)
1073         {
1074                 result = false;
1075
1076                 goto end;
1077         }
1078
1079         /* Helper BO will be used to hold the atomic counter buffer data.
1080          * Determine how much space will be needed.
1081          *
1082          * Min max for the GL constant value is 0. Bail out if that's the
1083          * value we are returned - it is pointless to execute the test in
1084          * such environment.
1085          */
1086         m_gl.getActiveUniformsiv(m_po, 1, /* uniformCount */
1087                                                          &ac_uniform_index, GL_UNIFORM_ARRAY_STRIDE, &m_gl_atomic_counter_uniform_array_stride);
1088         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGetActiveUniformsiv() call failed.");
1089
1090         DE_ASSERT(m_gl_atomic_counter_uniform_array_stride >= (int)sizeof(unsigned int));
1091
1092         m_helper_bo_size                 = m_gl_atomic_counter_uniform_array_stride * m_gl_max_vertex_atomic_counters_value;
1093         m_helper_bo_size_rounded = SparseBufferTestUtilities::alignOffset(m_helper_bo_size, m_page_size);
1094
1095         /* Set up the helper BO */
1096         DE_ASSERT(m_helper_bo == 0);
1097
1098         m_gl.genBuffers(1, &m_helper_bo);
1099         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenBuffers() call failed.");
1100
1101         m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_helper_bo);
1102         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
1103
1104         m_gl.bufferStorage(GL_COPY_READ_BUFFER, m_helper_bo_size_rounded, DE_NULL, GL_MAP_READ_BIT); /* flags */
1105         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferStorage() call failed.");
1106
1107         /* Set up the vertex array object */
1108         DE_ASSERT(m_vao == 0);
1109
1110         m_gl.genVertexArrays(1, &m_vao);
1111         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenVertexArrays() call failed.");
1112
1113         m_gl.bindVertexArray(m_vao);
1114         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindVertexArray() call failed.");
1115
1116 end:
1117         return result;
1118 }
1119
1120 /** Initializes GL objects which are needed for a single test case iteration.
1121  *
1122  *  deinitTestCaseIteration() will be called after the test case is executed in ::execute()
1123  *  to release these objects.
1124  **/
1125 bool AtomicCounterBufferStorageTestCase::initTestCaseIteration(glw::GLuint sparse_bo)
1126 {
1127         bool result = true;
1128
1129         /* Cache the BO id, if not cached already */
1130         DE_ASSERT(m_sparse_bo == 0 || m_sparse_bo == sparse_bo);
1131
1132         m_sparse_bo = sparse_bo;
1133
1134         /* Set up the sparse bufffer. */
1135         int sparse_bo_data_size = 0;
1136
1137         DE_ASSERT(m_helper_bo_size_rounded != 0);
1138
1139         m_gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bo);
1140         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
1141
1142         if (m_all_pages_committed)
1143         {
1144                 /* Commit all required pages */
1145                 sparse_bo_data_size = m_helper_bo_size_rounded;
1146         }
1147         else
1148         {
1149                 /* Only commit the first half of the required pages */
1150                 DE_ASSERT((m_helper_bo_size_rounded % m_page_size) == 0);
1151
1152                 sparse_bo_data_size = (m_helper_bo_size_rounded / m_page_size) * m_page_size / 2;
1153         }
1154
1155         /* NOTE: We need to ensure that the memory region assigned to the atomic counter buffer spans
1156          *       at least through two separate pages.
1157          *
1158          * Since we align up, we need to move one page backward and then apply the alignment function
1159          * to determine the start page index.
1160          */
1161         const int sparse_bo_data_start_offset                    = m_page_size - m_helper_bo_size_rounded / 2;
1162         int               sparse_bo_data_start_offset_minus_page = sparse_bo_data_start_offset - m_page_size;
1163
1164         if (sparse_bo_data_start_offset_minus_page < 0)
1165         {
1166                 sparse_bo_data_start_offset_minus_page = 0;
1167         }
1168
1169         m_sparse_bo_data_start_offset = sparse_bo_data_start_offset;
1170         m_sparse_bo_data_start_offset_rounded =
1171                 SparseBufferTestUtilities::alignOffset(sparse_bo_data_start_offset_minus_page, m_page_size);
1172         m_sparse_bo_data_size = sparse_bo_data_size;
1173         m_sparse_bo_data_size_rounded =
1174                 SparseBufferTestUtilities::alignOffset(m_sparse_bo_data_start_offset + sparse_bo_data_size, m_page_size);
1175
1176         DE_ASSERT((m_sparse_bo_data_size_rounded % m_page_size) == 0);
1177         DE_ASSERT((m_sparse_bo_data_start_offset_rounded % m_page_size) == 0);
1178
1179         m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, m_sparse_bo_data_start_offset_rounded, m_sparse_bo_data_size_rounded,
1180                                                                  GL_TRUE); /* commit */
1181
1182         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
1183
1184         return result;
1185 }
1186
1187 /** Constructor.
1188  *
1189  *  @param gl                         GL entry-points container
1190  *  @param context                    CTS rendering context
1191  *  @param testContext                CTS test context
1192  *  @param page_size                  Page size, as reported by implementation for the GL_SPARSE_BUFFER_PAGE_SIZE_ARB query.
1193  *  @param pGLBufferPageCommitmentARB Func ptr to glBufferPageCommitmentARB() entry-point.
1194  */
1195 BufferTextureStorageTestCase::BufferTextureStorageTestCase(const glw::Functions& gl, deqp::Context& context,
1196                                                                                                                    tcu::TestContext& testContext, glw::GLint page_size)
1197         : m_gl(gl)
1198         , m_helper_bo(0)
1199         , m_helper_bo_data(DE_NULL)
1200         , m_helper_bo_data_size(0)
1201         , m_is_texture_buffer_range_supported(false)
1202         , m_page_size(page_size)
1203         , m_po(0)
1204         , m_po_local_wg_size(1024)
1205         , m_sparse_bo(0)
1206         , m_sparse_bo_size(0)
1207         , m_sparse_bo_size_rounded(0)
1208         , m_ssbo(0)
1209         , m_ssbo_zero_data(DE_NULL)
1210         , m_ssbo_zero_data_size(0)
1211         , m_testCtx(testContext)
1212         , m_to(0)
1213         , m_to_width(65536) /* min max for GL_MAX_TEXTURE_BUFFER_SIZE_ARB */
1214 {
1215         const glu::ContextInfo& context_info   = context.getContextInfo();
1216         glu::RenderContext&             render_context = context.getRenderContext();
1217
1218         if (glu::contextSupports(render_context.getType(), glu::ApiType::core(4, 3)) ||
1219                 context_info.isExtensionSupported("GL_ARB_texture_buffer_range"))
1220         {
1221                 m_is_texture_buffer_range_supported = true;
1222         }
1223 }
1224
1225 /** Releases all GL objects used across all test case iterations.
1226  *
1227  *  Called once during BufferStorage test run-time.
1228  */
1229 void BufferTextureStorageTestCase::deinitTestCaseGlobal()
1230 {
1231         if (m_helper_bo != 0)
1232         {
1233                 m_gl.deleteBuffers(1, &m_helper_bo);
1234
1235                 m_helper_bo = 0;
1236         }
1237
1238         if (m_helper_bo_data != DE_NULL)
1239         {
1240                 delete[] m_helper_bo_data;
1241
1242                 m_helper_bo_data = DE_NULL;
1243         }
1244
1245         if (m_po != 0)
1246         {
1247                 m_gl.deleteProgram(m_po);
1248
1249                 m_po = 0;
1250         }
1251
1252         if (m_ssbo != 0)
1253         {
1254                 m_gl.deleteBuffers(1, &m_ssbo);
1255
1256                 m_ssbo = 0;
1257         }
1258
1259         if (m_ssbo_zero_data != DE_NULL)
1260         {
1261                 delete[] m_ssbo_zero_data;
1262
1263                 m_ssbo_zero_data = DE_NULL;
1264         }
1265
1266         if (m_to != 0)
1267         {
1268                 m_gl.deleteTextures(1, &m_to);
1269
1270                 m_to = 0;
1271         }
1272 }
1273
1274 /** Releases temporary GL objects, created specifically for one test case iteration. */
1275 void BufferTextureStorageTestCase::deinitTestCaseIteration()
1276 {
1277         if (m_sparse_bo != 0)
1278         {
1279                 m_gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bo);
1280                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
1281
1282                 m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0,                                  /* offset */
1283                                                                          m_sparse_bo_size_rounded, GL_FALSE); /* commit */
1284                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
1285
1286                 m_sparse_bo = 0;
1287         }
1288 }
1289
1290 /** Executes a single test iteration. The BufferStorage test will call this method
1291  *  numerously during its life-time, testing various valid flag combinations applied
1292  *  to the tested sparse buffer object at glBufferStorage() call time.
1293  *
1294  *  @param sparse_bo_storage_flags <flags> argument, used by the test in the glBufferStorage()
1295  *                                 call to set up the sparse buffer's storage.
1296  *
1297  *  @return true if the test case executed correctly, false otherwise.
1298  */
1299 bool BufferTextureStorageTestCase::execute(glw::GLuint sparse_bo_storage_flags)
1300 {
1301         (void)sparse_bo_storage_flags;
1302         bool result = true;
1303
1304         /* Bind the program object */
1305         m_gl.useProgram(m_po);
1306         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUseProgram() call failed.");
1307
1308         m_gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, m_ssbo);
1309         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
1310
1311         m_gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, /* index */
1312                                                 m_ssbo);
1313         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBufferBase() call failed.");
1314
1315         /* Set up bindings for the copy ops */
1316         m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_helper_bo);
1317         m_gl.bindBuffer(GL_COPY_WRITE_BUFFER, m_sparse_bo);
1318         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call(s) failed.");
1319
1320         /* Run the test in two iterations:
1321          *
1322          * a) All required pages are committed.
1323          * b) Only half of the pages are committed. */
1324         for (unsigned int n_iteration = 0; n_iteration < 2; ++n_iteration)
1325         {
1326
1327                 /* Test glTexBuffer() and glTexBufferRange() separately. */
1328                 for (int n_entry_point = 0; n_entry_point < (m_is_texture_buffer_range_supported ? 2 : 1); ++n_entry_point)
1329                 {
1330                         bool result_local = true;
1331
1332                         /* Set up the sparse buffer's memory backing. */
1333                         const unsigned int tbo_commit_start_offset = (n_iteration == 0) ? 0 : m_sparse_bo_size_rounded / 2;
1334                         const unsigned int tbo_commit_size =
1335                                 (n_iteration == 0) ? m_sparse_bo_size_rounded : m_sparse_bo_size_rounded / 2;
1336
1337                         m_gl.bindBuffer(GL_TEXTURE_BUFFER, m_sparse_bo);
1338                         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
1339
1340                         m_gl.bufferPageCommitmentARB(GL_TEXTURE_BUFFER, tbo_commit_start_offset, tbo_commit_size,
1341                                                                                  GL_TRUE); /* commit */
1342                         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
1343
1344                         /* Set up the buffer texture's backing */
1345                         if (n_entry_point == 0)
1346                         {
1347                                 m_gl.texBuffer(GL_TEXTURE_BUFFER, GL_RGBA8, m_sparse_bo);
1348
1349                                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glTexBuffer() call failed.");
1350                         }
1351                         else
1352                         {
1353                                 m_gl.texBufferRange(GL_TEXTURE_BUFFER, GL_RGBA8, m_sparse_bo, 0, /* offset */
1354                                                                         m_sparse_bo_size);
1355
1356                                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glTexBufferRange() call failed.");
1357                         }
1358
1359                         /* Set up the sparse buffer's data storage */
1360                         m_gl.copyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, /* readOffset */
1361                                                                    0,                                                                                    /* writeOffset */
1362                                                                    m_helper_bo_data_size);
1363                         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCopyBufferSubData() call failed.");
1364
1365                         /* Run the compute program */
1366                         DE_ASSERT((m_to_width % m_po_local_wg_size) == 0);
1367
1368                         m_gl.dispatchCompute(m_to_width / m_po_local_wg_size, 1, /* num_groups_y */
1369                                                                  1);                                                             /* num_groups_z */
1370                         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDispatchCompute() call failed.");
1371
1372                         /* Flush the caches */
1373                         m_gl.memoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
1374                         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glMemoryBarrier() call failed.");
1375
1376                         /* Map the SSBO into process space, so we can check if the texture buffer's
1377                          * contents was found valid by the compute shader */
1378                         unsigned int            current_tb_offset = 0;
1379                         const unsigned int* ssbo_data_ptr =
1380                                 (const unsigned int*)m_gl.mapBuffer(GL_SHADER_STORAGE_BUFFER, GL_READ_ONLY);
1381
1382                         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glMapBuffer() call failed.");
1383
1384                         for (unsigned int n_texel = 0; n_texel < m_to_width && result_local;
1385                                  ++n_texel, current_tb_offset += 4 /* rgba */)
1386                         {
1387                                 /* NOTE: Since the CS uses std140 layout, we need to move by 4 ints for
1388                                  *       each result value */
1389                                 if (current_tb_offset >= tbo_commit_start_offset &&
1390                                         current_tb_offset < (tbo_commit_start_offset + tbo_commit_size) && ssbo_data_ptr[n_texel * 4] != 1)
1391                                 {
1392                                         m_testCtx.getLog() << tcu::TestLog::Message << "A texel read from the texture buffer at index "
1393                                                                                                                                    "["
1394                                                                            << n_texel << "]"
1395                                                                                                          " was marked as invalid by the CS invocation."
1396                                                                            << tcu::TestLog::EndMessage;
1397
1398                                         result_local = false;
1399                                 } /* if (ssbo_data_ptr[n_texel] != 1) */
1400                         }        /* for (all result values) */
1401
1402                         result &= result_local;
1403
1404                         m_gl.unmapBuffer(GL_SHADER_STORAGE_BUFFER);
1405                         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUnmapBuffer() call failed.");
1406
1407                         /* Remove the physical backing from the sparse buffer  */
1408                         m_gl.bufferPageCommitmentARB(GL_TEXTURE_BUFFER, 0,                                /* offset */
1409                                                                                  m_sparse_bo_size_rounded, GL_FALSE); /* commit */
1410
1411                         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
1412
1413                         /* Reset SSBO's contents */
1414                         m_gl.bufferSubData(GL_SHADER_STORAGE_BUFFER, 0, /* offset */
1415                                                            m_ssbo_zero_data_size, m_ssbo_zero_data);
1416                         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferSubData() call failed.");
1417                 } /* for (both entry-points) */
1418         }        /* for (both iterations) */
1419
1420         return result;
1421 }
1422
1423 /** Initializes GL objects used across all test case iterations.
1424  *
1425  *  Called once during BufferStorage test run-time.
1426  */
1427 bool BufferTextureStorageTestCase::initTestCaseGlobal()
1428 {
1429         /* Set up the test program */
1430         static const char* cs_body =
1431                 "#version 430 core\n"
1432                 "\n"
1433                 "layout(local_size_x = 1024) in;\n"
1434                 "\n"
1435                 "layout(std140, binding = 0) buffer data\n"
1436                 "{\n"
1437                 "    restrict writeonly int result[];\n"
1438                 "};\n"
1439                 "\n"
1440                 "uniform samplerBuffer input_texture;\n"
1441                 "\n"
1442                 "void main()\n"
1443                 "{\n"
1444                 "    uint texel_index = gl_GlobalInvocationID.x;\n"
1445                 "\n"
1446                 "    if (texel_index < 65536)\n"
1447                 "    {\n"
1448                 "        vec4 expected_texel_data = vec4       (float((texel_index)       % 255) / 255.0,\n"
1449                 "                                               float((texel_index + 35)  % 255) / 255.0,\n"
1450                 "                                               float((texel_index + 78)  % 255) / 255.0,\n"
1451                 "                                               float((texel_index + 131) % 255) / 255.0);\n"
1452                 "        vec4 texel_data          = texelFetch(input_texture, int(texel_index) );\n"
1453                 "\n"
1454                 "        if (abs(texel_data.r - expected_texel_data.r) > 1.0 / 255.0 ||\n"
1455                 "            abs(texel_data.g - expected_texel_data.g) > 1.0 / 255.0 ||\n"
1456                 "            abs(texel_data.b - expected_texel_data.b) > 1.0 / 255.0 ||\n"
1457                 "            abs(texel_data.a - expected_texel_data.a) > 1.0 / 255.0)\n"
1458                 "        {\n"
1459                 "            result[texel_index] = 0;\n"
1460                 "        }\n"
1461                 "        else\n"
1462                 "        {\n"
1463                 "            result[texel_index] = 1;\n"
1464                 "        }\n"
1465                 "    }\n"
1466                 "}\n";
1467
1468         m_po = SparseBufferTestUtilities::createComputeProgram(m_gl, &cs_body, 1); /* n_cs_body_parts */
1469
1470         /* Set up a data buffer we will use to initialize the SSBO with default data.
1471          *
1472          * CS uses a std140 layout for the SSBO, so we need to add the additional padding.
1473          */
1474         m_ssbo_zero_data_size = static_cast<unsigned int>(4 * sizeof(int) * m_to_width);
1475         m_ssbo_zero_data          = new unsigned char[m_ssbo_zero_data_size];
1476
1477         memset(m_ssbo_zero_data, 0, m_ssbo_zero_data_size);
1478
1479         /* Set up the SSBO */
1480         m_gl.genBuffers(1, &m_ssbo);
1481         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenBuffers() call failed.");
1482
1483         m_gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, m_ssbo);
1484         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
1485
1486         m_gl.bufferData(GL_SHADER_STORAGE_BUFFER, m_ssbo_zero_data_size, m_ssbo_zero_data, GL_STATIC_DRAW);
1487         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferData() call failed.");
1488
1489         /* During execution, we will need to use a helper buffer object. The BO will hold
1490          * data we will be copying into the sparse buffer object for each iteration.
1491          *
1492          * Create an array to hold the helper buffer's data and fill it with info that
1493          * the compute shader is going to be expecting */
1494         unsigned char* helper_bo_data_traveller_ptr = NULL;
1495
1496         m_helper_bo_data_size = m_to_width * 4; /* rgba */
1497         m_helper_bo_data          = new unsigned char[m_helper_bo_data_size];
1498
1499         helper_bo_data_traveller_ptr = m_helper_bo_data;
1500
1501         for (unsigned int n_texel = 0; n_texel < m_to_width; ++n_texel)
1502         {
1503                 /* Red */
1504                 *helper_bo_data_traveller_ptr = static_cast<unsigned char>(n_texel % 255);
1505                 ++helper_bo_data_traveller_ptr;
1506
1507                 /* Green */
1508                 *helper_bo_data_traveller_ptr = static_cast<unsigned char>((n_texel + 35) % 255);
1509                 ++helper_bo_data_traveller_ptr;
1510
1511                 /* Blue */
1512                 *helper_bo_data_traveller_ptr = static_cast<unsigned char>((n_texel + 78) % 255);
1513                 ++helper_bo_data_traveller_ptr;
1514
1515                 /* Alpha */
1516                 *helper_bo_data_traveller_ptr = static_cast<unsigned char>((n_texel + 131) % 255);
1517                 ++helper_bo_data_traveller_ptr;
1518         } /* for (all texels to be accessible via the buffer texture) */
1519
1520         /* Set up the helper buffer object which we are going to use to copy data into
1521          * the sparse buffer object. */
1522         m_gl.genBuffers(1, &m_helper_bo);
1523         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenBuffers() call failed.");
1524
1525         m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_helper_bo);
1526         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
1527
1528         m_gl.bufferData(GL_COPY_READ_BUFFER, m_helper_bo_data_size, m_helper_bo_data, GL_STATIC_DRAW);
1529         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferData() call failed.");
1530
1531         /* Set up the texture buffer object. We will attach the actual buffer storage
1532          * in execute() */
1533         m_gl.genTextures(1, &m_to);
1534         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenTextures() call failed.");
1535
1536         m_gl.bindTexture(GL_TEXTURE_BUFFER, m_to);
1537         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindTexture() call failed.");
1538
1539         /* Determine the number of bytes both the helper and the sparse buffer
1540          * object need to be able to hold, at maximum */
1541         m_sparse_bo_size                 = static_cast<unsigned int>(m_to_width * sizeof(int));
1542         m_sparse_bo_size_rounded = SparseBufferTestUtilities::alignOffset(m_sparse_bo_size, m_page_size);
1543
1544         return true;
1545 }
1546
1547 /** Initializes GL objects which are needed for a single test case iteration.
1548  *
1549  *  deinitTestCaseIteration() will be called after the test case is executed in ::execute()
1550  *  to release these objects.
1551  **/
1552 bool BufferTextureStorageTestCase::initTestCaseIteration(glw::GLuint sparse_bo)
1553 {
1554         bool result = true;
1555
1556         /* Cache the BO id, if not cached already */
1557         DE_ASSERT(m_sparse_bo == 0 || m_sparse_bo == sparse_bo);
1558
1559         m_sparse_bo = sparse_bo;
1560
1561         return result;
1562 }
1563
1564 /** Constructor.
1565  *
1566  *  @param gl                         GL entry-points container
1567  *  @param testContext                CTS test context
1568  *  @param page_size                  Page size, as reported by implementation for the GL_SPARSE_BUFFER_PAGE_SIZE_ARB query.
1569  *  @param pGLBufferPageCommitmentARB Func ptr to glBufferPageCommitmentARB() entry-point.
1570  */
1571 ClearOpsBufferStorageTestCase::ClearOpsBufferStorageTestCase(const glw::Functions& gl, tcu::TestContext& testContext,
1572                                                                                                                          glw::GLint page_size)
1573         : m_gl(gl)
1574         , m_helper_bo(0)
1575         , m_initial_data(DE_NULL)
1576         , m_n_pages_to_use(16)
1577         , m_page_size(page_size)
1578         , m_sparse_bo(0)
1579         , m_sparse_bo_size_rounded(0)
1580         , m_testCtx(testContext)
1581 {
1582         /* Left blank intentionally */
1583 }
1584
1585 /** Releases all GL objects used across all test case iterations.
1586  *
1587  *  Called once during BufferStorage test run-time.
1588  */
1589 void ClearOpsBufferStorageTestCase::deinitTestCaseGlobal()
1590 {
1591         if (m_helper_bo != 0)
1592         {
1593                 m_gl.deleteBuffers(1, &m_helper_bo);
1594
1595                 m_helper_bo = 0;
1596         }
1597
1598         if (m_initial_data != DE_NULL)
1599         {
1600                 delete[] m_initial_data;
1601
1602                 m_initial_data = DE_NULL;
1603         }
1604 }
1605
1606 /** Releases temporary GL objects, created specifically for one test case iteration. */
1607 void ClearOpsBufferStorageTestCase::deinitTestCaseIteration()
1608 {
1609         if (m_sparse_bo != 0)
1610         {
1611                 m_gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bo);
1612                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
1613
1614                 m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0,                                  /* offset */
1615                                                                          m_sparse_bo_size_rounded, GL_FALSE); /* commit */
1616                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
1617
1618                 m_sparse_bo = 0;
1619         }
1620 }
1621
1622 /** Executes a single test iteration. The BufferStorage test will call this method
1623  *  numerously during its life-time, testing various valid flag combinations applied
1624  *  to the tested sparse buffer object at glBufferStorage() call time.
1625  *
1626  *  @param sparse_bo_storage_flags <flags> argument, used by the test in the glBufferStorage()
1627  *                                 call to set up the sparse buffer's storage.
1628  *
1629  *  @return true if the test case executed correctly, false otherwise.
1630  */
1631 bool ClearOpsBufferStorageTestCase::execute(glw::GLuint sparse_bo_storage_flags)
1632 {
1633         (void)sparse_bo_storage_flags;
1634         bool                       result        = true;
1635         const unsigned int data_rgba8 = 0x12345678;
1636
1637         for (unsigned int n_clear_op_type = 0; n_clear_op_type < 2; /* glClearBufferData(), glClearBufferSubData() */
1638                  ++n_clear_op_type)
1639         {
1640                 const bool use_clear_buffer_data_call = (n_clear_op_type == 0);
1641
1642                 /* We will run the test case in two iterations:
1643                  *
1644                  * 1) All pages will have a physical backing.
1645                  * 2) Half of the pages will have a physical backing.
1646                  */
1647                 for (unsigned int n_iteration = 0; n_iteration < 2; ++n_iteration)
1648                 {
1649                         /* By default, for each iteration all sparse buffer pages are commited.
1650                          *
1651                          * For the last iteration, we need to de-commit the latter half before
1652                          * proceeding with the test.
1653                          */
1654                         const bool all_pages_committed = (n_iteration == 0);
1655
1656                         if (!all_pages_committed)
1657                         {
1658                                 m_gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bo);
1659                                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
1660
1661                                 m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, m_sparse_bo_size_rounded / 2, /* offset */
1662                                                                                          m_sparse_bo_size_rounded / 2,                                  /* size   */
1663                                                                                          GL_TRUE);                                                                              /* commit */
1664                                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
1665                         }
1666
1667                         /* Set up the sparse buffer contents */
1668                         m_gl.bindBuffer(GL_ARRAY_BUFFER, m_helper_bo);
1669                         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
1670
1671                         m_gl.bufferSubData(GL_ARRAY_BUFFER, 0, /* offset */
1672                                                            m_sparse_bo_size_rounded, m_initial_data);
1673                         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferSubData() call failed.");
1674
1675                         m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_helper_bo);
1676                         m_gl.bindBuffer(GL_COPY_WRITE_BUFFER, m_sparse_bo);
1677                         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call(s) failed.");
1678
1679                         m_gl.copyBufferSubData(GL_COPY_READ_BUFFER,  /* readTarget  */
1680                                                                    GL_COPY_WRITE_BUFFER, /* writeTarget */
1681                                                                    0,                                    /* readOffset */
1682                                                                    0,                                    /* writeOffset */
1683                                                                    m_sparse_bo_size_rounded);
1684                         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCopyBufferSubData() call failed.");
1685
1686                         /* Issue the clear call */
1687                         unsigned int clear_region_size             = 0;
1688                         unsigned int clear_region_start_offset = 0;
1689
1690                         if (use_clear_buffer_data_call)
1691                         {
1692                                 DE_ASSERT((m_sparse_bo_size_rounded % sizeof(unsigned int)) == 0);
1693
1694                                 clear_region_size                 = m_sparse_bo_size_rounded;
1695                                 clear_region_start_offset = 0;
1696
1697                                 m_gl.clearBufferData(GL_COPY_WRITE_BUFFER, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, &data_rgba8);
1698                                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glClearBufferData() call failed.");
1699                         }
1700                         else
1701                         {
1702                                 DE_ASSERT(((m_sparse_bo_size_rounded / 2) % sizeof(unsigned int)) == 0);
1703                                 DE_ASSERT(((m_sparse_bo_size_rounded) % sizeof(unsigned int)) == 0);
1704
1705                                 clear_region_size                 = m_sparse_bo_size_rounded / 2;
1706                                 clear_region_start_offset = m_sparse_bo_size_rounded / 2;
1707
1708                                 m_gl.clearBufferSubData(GL_COPY_WRITE_BUFFER, GL_RGBA8, clear_region_start_offset, clear_region_size,
1709                                                                                 GL_RGBA, GL_UNSIGNED_BYTE, &data_rgba8);
1710                                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glClearBufferSubData() call failed.");
1711                         }
1712
1713                         /* Retrieve the modified buffer's contents */
1714                         const unsigned char* result_data = NULL;
1715
1716                         m_gl.copyBufferSubData(GL_COPY_WRITE_BUFFER, /* readTarget  */
1717                                                                    GL_COPY_READ_BUFFER,  /* writeTarget */
1718                                                                    0,                                    /* readOffset  */
1719                                                                    0,                                    /* writeOffset */
1720                                                                    m_sparse_bo_size_rounded);
1721                         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCopyBufferSubData() call failed.");
1722
1723                         result_data = (unsigned char*)m_gl.mapBufferRange(GL_COPY_READ_BUFFER, 0, /* offset */
1724                                                                                                                           m_sparse_bo_size_rounded, GL_MAP_READ_BIT);
1725
1726                         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glMapBufferRange() call failed.");
1727
1728                         /* Verify the result data: unmodified region */
1729                         bool                       result_local                   = true;
1730                         const unsigned int unmodified_region_size = (use_clear_buffer_data_call) ? 0 : clear_region_start_offset;
1731                         const unsigned int unmodified_region_start_offset = 0;
1732
1733                         for (unsigned int n_current_byte = unmodified_region_start_offset;
1734                                  (n_current_byte < unmodified_region_start_offset + unmodified_region_size) && result_local;
1735                                  ++n_current_byte)
1736                         {
1737                                 const unsigned int  current_initial_data_offset = n_current_byte - unmodified_region_start_offset;
1738                                 const unsigned char expected_value                              = m_initial_data[current_initial_data_offset];
1739                                 const unsigned char found_value                                 = result_data[n_current_byte];
1740
1741                                 if (expected_value != found_value)
1742                                 {
1743                                         m_testCtx.getLog() << tcu::TestLog::Message
1744                                                                            << "Unmodified buffer object region has invalid contents. Expected byte "
1745                                                                            << "[" << (int)expected_value << "]"
1746                                                                                                                                                 ", found byte:"
1747                                                                                                                                                 "["
1748                                                                            << (int)found_value << "]"
1749                                                                                                                           " at index "
1750                                                                                                                           "["
1751                                                                            << n_current_byte << "]; "
1752                                                                                                                         "call type:"
1753                                                                                                                         "["
1754                                                                            << ((use_clear_buffer_data_call) ? "glClearBufferData()" :
1755                                                                                                                                                   "glClearBufferSubData()")
1756                                                                            << "]"
1757                                                                                   ", all required pages committed?:"
1758                                                                                   "["
1759                                                                            << ((all_pages_committed) ? "yes" : "no") << "]" << tcu::TestLog::EndMessage;
1760
1761                                         result_local = false;
1762                                         break;
1763                                 }
1764                         }
1765
1766                         result &= result_local;
1767                         result_local = true;
1768
1769                         /* Verify the result data: modified region (clamped to the memory region
1770                          * with actual physical backing) */
1771                         const unsigned int modified_region_size                 = (all_pages_committed) ? clear_region_size : 0;
1772                         const unsigned int modified_region_start_offset = clear_region_start_offset;
1773
1774                         for (unsigned int n_current_byte = modified_region_start_offset;
1775                                  (n_current_byte < modified_region_start_offset + modified_region_size) && result_local;
1776                                  ++n_current_byte)
1777                         {
1778                                 const unsigned char component_offset = n_current_byte % 4;
1779                                 const unsigned char expected_value =
1780                                         static_cast<unsigned char>((data_rgba8 & (0xFFu << (component_offset * 8))) >> (component_offset * 8));
1781                                 const unsigned char found_value = result_data[n_current_byte];
1782
1783                                 if (expected_value != found_value)
1784                                 {
1785                                         m_testCtx.getLog() << tcu::TestLog::Message
1786                                                                            << "Modified buffer object region has invalid contents. Expected byte "
1787                                                                            << "[" << (int)expected_value << "]"
1788                                                                                                                                                 ", found byte:"
1789                                                                                                                                                 "["
1790                                                                            << (int)found_value << "]"
1791                                                                                                                           " at index "
1792                                                                                                                           "["
1793                                                                            << n_current_byte << "]; "
1794                                                                                                                         "call type:"
1795                                                                                                                         "["
1796                                                                            << ((use_clear_buffer_data_call) ? "glClearBufferData()" :
1797                                                                                                                                                   "glClearBufferSubData()")
1798                                                                            << "]"
1799                                                                                   ", all required pages committed?:"
1800                                                                                   "["
1801                                                                            << ((all_pages_committed) ? "yes" : "no") << "]" << tcu::TestLog::EndMessage;
1802
1803                                         result_local = false;
1804                                         break;
1805                                 }
1806                         }
1807
1808                         result &= result_local;
1809
1810                         /* Unmap the storage before proceeding */
1811                         m_gl.unmapBuffer(GL_COPY_READ_BUFFER);
1812                         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUnmapBuffer() call failed.");
1813                 } /* for (both iterations) */
1814         }        /* for (both clear types) */
1815
1816         return result;
1817 }
1818
1819 /** Initializes GL objects used across all test case iterations.
1820  *
1821  *  Called once during BufferStorage test run-time.
1822  */
1823 bool ClearOpsBufferStorageTestCase::initTestCaseGlobal()
1824 {
1825         unsigned int       n_bytes_filled = 0;
1826         const unsigned int n_bytes_needed = m_n_pages_to_use * m_page_size;
1827
1828         /* Determine the number of bytes both the helper and the sparse buffer
1829          * object need to be able to hold, at maximum */
1830         m_sparse_bo_size_rounded = SparseBufferTestUtilities::alignOffset(n_bytes_needed, m_page_size);
1831
1832         /* Set up the helper BO */
1833         DE_ASSERT(m_helper_bo == 0);
1834
1835         m_gl.genBuffers(1, &m_helper_bo);
1836         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenBuffers() call failed.");
1837
1838         m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_helper_bo);
1839         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
1840
1841         m_gl.bufferStorage(GL_COPY_READ_BUFFER, m_sparse_bo_size_rounded, DE_NULL,
1842                                            GL_DYNAMIC_STORAGE_BIT | GL_MAP_READ_BIT); /* flags */
1843         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferStorage() call failed.");
1844
1845         /* Set up a client-side data buffer we will use to fill the sparse BO with data,
1846          * to be later cleared with the clear ops */
1847         DE_ASSERT(m_initial_data == DE_NULL);
1848
1849         m_initial_data = new unsigned char[m_sparse_bo_size_rounded];
1850
1851         while (n_bytes_filled < m_sparse_bo_size_rounded)
1852         {
1853                 m_initial_data[n_bytes_filled] = static_cast<unsigned char>(n_bytes_filled % 256);
1854
1855                 ++n_bytes_filled;
1856         }
1857
1858         return true;
1859 }
1860
1861 /** Initializes GL objects which are needed for a single test case iteration.
1862  *
1863  *  deinitTestCaseIteration() will be called after the test case is executed in ::execute()
1864  *  to release these objects.
1865  **/
1866 bool ClearOpsBufferStorageTestCase::initTestCaseIteration(glw::GLuint sparse_bo)
1867 {
1868         bool result = true;
1869
1870         /* Cache the BO id, if not cached already */
1871         DE_ASSERT(m_sparse_bo == 0 || m_sparse_bo == sparse_bo);
1872
1873         m_sparse_bo = sparse_bo;
1874
1875         /* Set up the sparse bufffer. */
1876         m_gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bo);
1877         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
1878
1879         m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0,                                 /* offset */
1880                                                                  m_sparse_bo_size_rounded, GL_TRUE); /* commit */
1881
1882         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
1883
1884         return result;
1885 }
1886
1887 /** Constructor.
1888  *
1889  *  @param gl                         GL entry-points container
1890  *  @param testContext                CTS test context
1891  *  @param page_size                  Page size, as reported by implementation for the GL_SPARSE_BUFFER_PAGE_SIZE_ARB query.
1892  *  @param pGLBufferPageCommitmentARB Func ptr to glBufferPageCommitmentARB() entry-point.
1893  */
1894 CopyOpsBufferStorageTestCase::CopyOpsBufferStorageTestCase(const glw::Functions& gl, tcu::TestContext& testContext,
1895                                                                                                                    glw::GLint page_size)
1896         : m_gl(gl)
1897         , m_helper_bo(0)
1898         , m_immutable_bo(0)
1899         , m_page_size(page_size)
1900         , m_sparse_bo_size(0)
1901         , m_sparse_bo_size_rounded(0)
1902         , m_testCtx(testContext)
1903 {
1904         m_ref_data[0]   = DE_NULL;
1905         m_ref_data[1]   = DE_NULL;
1906         m_ref_data[2]   = DE_NULL;
1907         m_sparse_bos[0] = 0;
1908         m_sparse_bos[1] = 0;
1909 }
1910
1911 /** Releases all GL objects used across all test case iterations.
1912  *
1913  *  Called once during BufferStorage test run-time.
1914  */
1915
1916 void CopyOpsBufferStorageTestCase::deinitTestCaseGlobal()
1917 {
1918         if (m_helper_bo != 0)
1919         {
1920                 m_gl.deleteBuffers(1, &m_helper_bo);
1921
1922                 m_helper_bo = 0;
1923         }
1924
1925         if (m_immutable_bo != 0)
1926         {
1927                 m_gl.deleteBuffers(1, &m_immutable_bo);
1928
1929                 m_immutable_bo = 0;
1930         }
1931
1932         for (unsigned int n_ref_data_buffer = 0; n_ref_data_buffer < sizeof(m_ref_data) / sizeof(m_ref_data[0]);
1933                  ++n_ref_data_buffer)
1934         {
1935                 if (m_ref_data[n_ref_data_buffer] != DE_NULL)
1936                 {
1937                         delete[] m_ref_data[n_ref_data_buffer];
1938
1939                         m_ref_data[n_ref_data_buffer] = DE_NULL;
1940                 }
1941         }
1942
1943         /* Only release the test case-owned BO */
1944         if (m_sparse_bos[1] != 0)
1945         {
1946                 m_gl.deleteBuffers(1, m_sparse_bos + 1);
1947
1948                 m_sparse_bos[1] = 0;
1949         }
1950 }
1951
1952 /** Releases temporary GL objects, created specifically for one test case iteration. */
1953 void CopyOpsBufferStorageTestCase::deinitTestCaseIteration()
1954 {
1955         for (unsigned int n_sparse_bo = 0; n_sparse_bo < sizeof(m_sparse_bos) / sizeof(m_sparse_bos[0]); ++n_sparse_bo)
1956         {
1957                 const glw::GLuint sparse_bo_id = m_sparse_bos[n_sparse_bo];
1958
1959                 if (sparse_bo_id != 0)
1960                 {
1961                         m_gl.bindBuffer(GL_ARRAY_BUFFER, sparse_bo_id);
1962                         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
1963
1964                         m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0,                                  /* offset */
1965                                                                                  m_sparse_bo_size_rounded, GL_FALSE); /* commit */
1966                         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
1967                 } /* if (sparse_bo_id != 0) */
1968         }        /* for (both BOs) */
1969 }
1970
1971 /** Executes a single test iteration. The BufferStorage test will call this method
1972  *  numerously during its life-time, testing various valid flag combinations applied
1973  *  to the tested sparse buffer object at glBufferStorage() call time.
1974  *
1975  *  @param sparse_bo_storage_flags <flags> argument, used by the test in the glBufferStorage()
1976  *                                 call to set up the sparse buffer's storage.
1977  *
1978  *  @return true if the test case executed correctly, false otherwise.
1979  */
1980 bool CopyOpsBufferStorageTestCase::execute(glw::GLuint sparse_bo_storage_flags)
1981 {
1982         (void)sparse_bo_storage_flags;
1983         bool result = true;
1984
1985         /* Iterate over all test cases */
1986         DE_ASSERT(m_immutable_bo != 0);
1987         DE_ASSERT(m_sparse_bos[0] != 0);
1988         DE_ASSERT(m_sparse_bos[1] != 0);
1989
1990         for (_test_cases_const_iterator test_iterator = m_test_cases.begin(); test_iterator != m_test_cases.end();
1991                  ++test_iterator)
1992         {
1993                 bool                      result_local = true;
1994                 const _test_case& test_case     = *test_iterator;
1995                 const glw::GLuint dst_bo_id =
1996                         test_case.dst_bo_is_sparse ? m_sparse_bos[test_case.dst_bo_sparse_id] : m_immutable_bo;
1997                 const glw::GLuint src_bo_id =
1998                         test_case.src_bo_is_sparse ? m_sparse_bos[test_case.src_bo_sparse_id] : m_immutable_bo;
1999
2000                 /* Initialize immutable BO data (if used) */
2001                 if (dst_bo_id == m_immutable_bo || src_bo_id == m_immutable_bo)
2002                 {
2003                         m_gl.bindBuffer(GL_ARRAY_BUFFER, m_immutable_bo);
2004                         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
2005
2006                         m_gl.bufferSubData(GL_ARRAY_BUFFER, 0, /* offset */
2007                                                            m_sparse_bo_size_rounded, m_ref_data[0]);
2008                         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferSubData() call failed.");
2009                 }
2010
2011                 /* Initialize sparse BO data storage */
2012                 for (unsigned int n_sparse_bo = 0; n_sparse_bo < sizeof(m_sparse_bos) / sizeof(m_sparse_bos[0]); ++n_sparse_bo)
2013                 {
2014                         const bool is_dst_bo = (dst_bo_id == m_sparse_bos[n_sparse_bo]);
2015                         const bool is_src_bo = (src_bo_id == m_sparse_bos[n_sparse_bo]);
2016
2017                         if (!is_dst_bo && !is_src_bo)
2018                                 continue;
2019
2020                         m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_helper_bo);
2021                         m_gl.bindBuffer(GL_COPY_WRITE_BUFFER, m_sparse_bos[n_sparse_bo]);
2022                         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call(s) failed.");
2023
2024                         if (is_dst_bo)
2025                         {
2026                                 m_gl.bufferPageCommitmentARB(GL_COPY_WRITE_BUFFER, test_case.dst_bo_commit_start_offset,
2027                                                                                          test_case.dst_bo_commit_size, GL_TRUE); /* commit */
2028                                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
2029                         }
2030
2031                         if (is_src_bo)
2032                         {
2033                                 m_gl.bufferPageCommitmentARB(GL_COPY_WRITE_BUFFER, test_case.src_bo_commit_start_offset,
2034                                                                                          test_case.src_bo_commit_size, GL_TRUE); /* commit */
2035                                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
2036                         }
2037
2038                         m_gl.bufferSubData(GL_COPY_READ_BUFFER, 0, /* offset */
2039                                                            m_sparse_bo_size_rounded, m_ref_data[1 + n_sparse_bo]);
2040                         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferSubData() call failed.");
2041
2042                         m_gl.copyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, /* readOffset */
2043                                                                    0,                                                                                    /* writeOffset */
2044                                                                    m_sparse_bo_size_rounded);
2045                         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCopyBufferSubData() call failed.");
2046                 } /* for (both sparse BOs) */
2047
2048                 /* Set up the bindings */
2049                 m_gl.bindBuffer(GL_COPY_READ_BUFFER, src_bo_id);
2050                 m_gl.bindBuffer(GL_COPY_WRITE_BUFFER, dst_bo_id);
2051                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
2052
2053                 /* Issue the copy op */
2054                 m_gl.copyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, test_case.src_bo_start_offset,
2055                                                            test_case.dst_bo_start_offset, test_case.n_bytes_to_copy);
2056                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCopyBufferSubData() call failed.");
2057
2058                 /* Retrieve the destination buffer's contents. The BO used for the previous copy op might have
2059                  * been a sparse BO, so copy its storage to a helper immutable BO */
2060                 const unsigned short* dst_bo_data_ptr = NULL;
2061
2062                 m_gl.bindBuffer(GL_COPY_READ_BUFFER, dst_bo_id);
2063                 m_gl.bindBuffer(GL_COPY_WRITE_BUFFER, m_helper_bo);
2064                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
2065
2066                 m_gl.copyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, /* readOffset */
2067                                                            0,                                                                                    /* writeOffset */
2068                                                            m_sparse_bo_size_rounded);
2069                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCopyBufferSubData() call failed.");
2070
2071                 dst_bo_data_ptr = (const unsigned short*)m_gl.mapBufferRange(GL_COPY_WRITE_BUFFER, 0, /* offset */
2072                                                                                                                                          m_sparse_bo_size_rounded, GL_MAP_READ_BIT);
2073
2074                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glMapBufferRange() call failed.");
2075
2076                 /* Verify the retrieved data:
2077                  *
2078                  * 1. Check the bytes which precede the copy op dst offset. These should be equal to
2079                  *    the destination buffer's reference data within the committed memory region.
2080                  **/
2081                 if (test_case.dst_bo_start_offset != 0 && test_case.dst_bo_commit_start_offset < test_case.dst_bo_start_offset)
2082                 {
2083                         DE_ASSERT(((test_case.dst_bo_start_offset - test_case.dst_bo_commit_start_offset) % sizeof(short)) == 0);
2084
2085                         const unsigned int n_valid_values = static_cast<unsigned int>(
2086                                 (test_case.dst_bo_start_offset - test_case.dst_bo_commit_start_offset) / sizeof(short));
2087
2088                         for (unsigned int n_value = 0; n_value < n_valid_values && result_local; ++n_value)
2089                         {
2090                                 const int dst_data_offset = static_cast<int>(sizeof(short) * n_value);
2091
2092                                 if (dst_data_offset >= test_case.dst_bo_commit_start_offset &&
2093                                         dst_data_offset < test_case.dst_bo_commit_start_offset + test_case.dst_bo_commit_size)
2094                                 {
2095                                         const unsigned short expected_short_value =
2096                                                 *(unsigned short*)((unsigned char*)test_case.dst_bo_ref_data + dst_data_offset);
2097                                         const unsigned short found_short_value =
2098                                                 *(unsigned short*)((unsigned char*)dst_bo_data_ptr + dst_data_offset);
2099
2100                                         if (expected_short_value != found_short_value)
2101                                         {
2102                                                 m_testCtx.getLog()
2103                                                         << tcu::TestLog::Message << "Malformed data found in the copy op's destination BO, "
2104                                                                                                                 "preceding the region modified by the copy op. "
2105                                                         << "Destination BO id:" << dst_bo_id << " ("
2106                                                         << ((test_case.dst_bo_is_sparse) ? "sparse buffer)" : "immutable buffer)")
2107                                                         << ", commited region: " << test_case.dst_bo_commit_start_offset << ":"
2108                                                         << (test_case.dst_bo_commit_start_offset + test_case.dst_bo_commit_size)
2109                                                         << ", copy region: " << test_case.dst_bo_start_offset << ":"
2110                                                         << (test_case.dst_bo_start_offset + test_case.n_bytes_to_copy)
2111                                                         << ". Source BO id:" << src_bo_id << " ("
2112                                                         << ((test_case.src_bo_is_sparse) ? "sparse buffer)" : "immutable buffer)")
2113                                                         << ", commited region: " << test_case.src_bo_commit_start_offset << ":"
2114                                                         << (test_case.src_bo_commit_start_offset + test_case.src_bo_commit_size)
2115                                                         << ", copy region: " << test_case.src_bo_start_offset << ":"
2116                                                         << (test_case.src_bo_start_offset + test_case.n_bytes_to_copy) << ". Expected value of "
2117                                                         << expected_short_value << ", found value of " << found_short_value
2118                                                         << " at dst data offset of " << dst_data_offset << "." << tcu::TestLog::EndMessage;
2119
2120                                                 result_local = false;
2121                                         }
2122                                 }
2123                         } /* for (all preceding values which should not have been affected by the copy op) */
2124                 }        /* if (copy op did not modify the beginning of the destination buffer storage) */
2125
2126                 /* 2. Check if the data written to the destination buffer object is correct. */
2127                 for (unsigned int n_copied_short_value = 0;
2128                          n_copied_short_value < test_case.n_bytes_to_copy / sizeof(short) && result_local; ++n_copied_short_value)
2129                 {
2130                         const int src_data_offset =
2131                                 static_cast<unsigned int>(test_case.src_bo_start_offset + sizeof(short) * n_copied_short_value);
2132                         const int dst_data_offset =
2133                                 static_cast<unsigned int>(test_case.dst_bo_start_offset + sizeof(short) * n_copied_short_value);
2134
2135                         if (dst_data_offset >= test_case.dst_bo_commit_start_offset &&
2136                                 dst_data_offset < test_case.dst_bo_commit_start_offset + test_case.dst_bo_commit_size &&
2137                                 src_data_offset >= test_case.src_bo_commit_start_offset &&
2138                                 src_data_offset < test_case.src_bo_commit_start_offset + test_case.src_bo_commit_size)
2139                         {
2140                                 const unsigned short expected_short_value =
2141                                         *(unsigned short*)((unsigned char*)test_case.src_bo_ref_data + src_data_offset);
2142                                 const unsigned short found_short_value =
2143                                         *(unsigned short*)((unsigned char*)dst_bo_data_ptr + dst_data_offset);
2144
2145                                 if (expected_short_value != found_short_value)
2146                                 {
2147                                         m_testCtx.getLog() << tcu::TestLog::Message
2148                                                                            << "Malformed data found in the copy op's destination BO. "
2149                                                                            << "Destination BO id:" << dst_bo_id << " ("
2150                                                                            << ((test_case.dst_bo_is_sparse) ? "sparse buffer)" : "immutable buffer)")
2151                                                                            << ", commited region: " << test_case.dst_bo_commit_start_offset << ":"
2152                                                                            << (test_case.dst_bo_commit_start_offset + test_case.dst_bo_commit_size)
2153                                                                            << ", copy region: " << test_case.dst_bo_start_offset << ":"
2154                                                                            << (test_case.dst_bo_start_offset + test_case.n_bytes_to_copy)
2155                                                                            << ". Source BO id:" << src_bo_id << " ("
2156                                                                            << ((test_case.src_bo_is_sparse) ? "sparse buffer)" : "immutable buffer)")
2157                                                                            << ", commited region: " << test_case.src_bo_commit_start_offset << ":"
2158                                                                            << (test_case.src_bo_commit_start_offset + test_case.src_bo_commit_size)
2159                                                                            << ", copy region: " << test_case.src_bo_start_offset << ":"
2160                                                                            << (test_case.src_bo_start_offset + test_case.n_bytes_to_copy)
2161                                                                            << ". Expected value of " << expected_short_value << ", found value of "
2162                                                                            << found_short_value << " at dst data offset of " << dst_data_offset << "."
2163                                                                            << tcu::TestLog::EndMessage;
2164
2165                                         result_local = false;
2166                                 }
2167                         }
2168                 }
2169
2170                 /* 3. Verify the remaining data in the committed part of the destination buffer object is left intact. */
2171                 const unsigned int commit_region_end_offset =
2172                         test_case.dst_bo_commit_start_offset + test_case.dst_bo_commit_size;
2173                 const unsigned int copy_region_end_offset = test_case.dst_bo_start_offset + test_case.n_bytes_to_copy;
2174
2175                 if (commit_region_end_offset > copy_region_end_offset)
2176                 {
2177                         DE_ASSERT(((commit_region_end_offset - copy_region_end_offset) % sizeof(short)) == 0);
2178
2179                         const unsigned int n_valid_values =
2180                                 static_cast<unsigned int>((commit_region_end_offset - copy_region_end_offset) / sizeof(short));
2181
2182                         for (unsigned int n_value = 0; n_value < n_valid_values && result_local; ++n_value)
2183                         {
2184                                 const int dst_data_offset = static_cast<int>(copy_region_end_offset + sizeof(short) * n_value);
2185
2186                                 if (dst_data_offset >= test_case.dst_bo_commit_start_offset &&
2187                                         dst_data_offset < test_case.dst_bo_commit_start_offset + test_case.dst_bo_commit_size)
2188                                 {
2189                                         const unsigned short expected_short_value =
2190                                                 *(unsigned short*)((unsigned char*)test_case.dst_bo_ref_data + dst_data_offset);
2191                                         const unsigned short found_short_value =
2192                                                 *(unsigned short*)((unsigned char*)dst_bo_data_ptr + dst_data_offset);
2193
2194                                         if (expected_short_value != found_short_value)
2195                                         {
2196                                                 m_testCtx.getLog()
2197                                                         << tcu::TestLog::Message << "Malformed data found in the copy op's destination BO, "
2198                                                                                                                 "following the region modified by the copy op. "
2199                                                         << "Destination BO id:" << dst_bo_id << " ("
2200                                                         << ((test_case.dst_bo_is_sparse) ? "sparse buffer)" : "immutable buffer)")
2201                                                         << ", commited region: " << test_case.dst_bo_commit_start_offset << ":"
2202                                                         << (test_case.dst_bo_commit_start_offset + test_case.dst_bo_commit_size)
2203                                                         << ", copy region: " << test_case.dst_bo_start_offset << ":"
2204                                                         << (test_case.dst_bo_start_offset + test_case.n_bytes_to_copy)
2205                                                         << ". Source BO id:" << src_bo_id << " ("
2206                                                         << ((test_case.src_bo_is_sparse) ? "sparse buffer)" : "immutable buffer)")
2207                                                         << ", commited region: " << test_case.src_bo_commit_start_offset << ":"
2208                                                         << (test_case.src_bo_commit_start_offset + test_case.src_bo_commit_size)
2209                                                         << ", copy region: " << test_case.src_bo_start_offset << ":"
2210                                                         << (test_case.src_bo_start_offset + test_case.n_bytes_to_copy) << ". Expected value of "
2211                                                         << expected_short_value << ", found value of " << found_short_value
2212                                                         << " at dst data offset of " << dst_data_offset << "." << tcu::TestLog::EndMessage;
2213
2214                                                 result_local = false;
2215                                         }
2216                                 }
2217                         } /* for (all preceding values which should not have been affected by the copy op) */
2218                 }        /* if (copy op did not modify the beginning of the destination buffer storage) */
2219
2220                 /* Unmap the buffer storage */
2221                 m_gl.unmapBuffer(GL_COPY_WRITE_BUFFER);
2222                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUnmapBuffer() call failed.");
2223
2224                 /* Clean up */
2225                 for (unsigned int n_sparse_bo = 0; n_sparse_bo < sizeof(m_sparse_bos) / sizeof(m_sparse_bos[0]); ++n_sparse_bo)
2226                 {
2227                         const bool is_dst_bo = (dst_bo_id == m_sparse_bos[n_sparse_bo]);
2228                         const bool is_src_bo = (src_bo_id == m_sparse_bos[n_sparse_bo]);
2229
2230                         if (is_dst_bo || is_src_bo)
2231                         {
2232                                 m_gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bos[n_sparse_bo]);
2233                                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
2234
2235                                 m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0, m_sparse_bo_size_rounded, GL_FALSE); /* commit */
2236                                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
2237                         }
2238                 }
2239
2240                 result &= result_local;
2241         } /* for (all test cases) */
2242
2243         return result;
2244 }
2245
2246 /** Allocates reference buffers, fills them with data and updates the m_ref_data array. */
2247 void CopyOpsBufferStorageTestCase::initReferenceData()
2248 {
2249         DE_ASSERT(m_sparse_bo_size_rounded != 0);
2250         DE_ASSERT((m_sparse_bo_size_rounded % 2) == 0);
2251         DE_ASSERT(sizeof(short) == 2);
2252
2253         for (unsigned int n_ref_data_buffer = 0; n_ref_data_buffer < sizeof(m_ref_data) / sizeof(m_ref_data[0]);
2254                  ++n_ref_data_buffer)
2255         {
2256                 DE_ASSERT(m_ref_data[n_ref_data_buffer] == DE_NULL);
2257
2258                 m_ref_data[n_ref_data_buffer] = new unsigned short[m_sparse_bo_size_rounded / 2];
2259
2260                 /* Write reference values. */
2261                 for (unsigned int n_short_value = 0; n_short_value < m_sparse_bo_size_rounded / 2; ++n_short_value)
2262                 {
2263                         m_ref_data[n_ref_data_buffer][n_short_value] =
2264                                 (unsigned short)((n_ref_data_buffer + 1) * (n_short_value + 1));
2265                 }
2266         } /* for (all reference data buffers) */
2267 }
2268
2269 /** Initializes GL objects used across all test case iterations.
2270  *
2271  *  Called once during BufferStorage test run-time.
2272  */
2273 bool CopyOpsBufferStorageTestCase::initTestCaseGlobal()
2274 {
2275         m_sparse_bo_size                 = 2 * 3 * 4 * m_page_size;
2276         m_sparse_bo_size_rounded = SparseBufferTestUtilities::alignOffset(m_sparse_bo_size, m_page_size);
2277
2278         initReferenceData();
2279
2280         /* Initialize the sparse buffer object */
2281         m_gl.genBuffers(1, m_sparse_bos + 1);
2282         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenBuffers() call failed.");
2283
2284         m_gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bos[1]);
2285         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
2286
2287         m_gl.bufferStorage(GL_ARRAY_BUFFER, m_sparse_bo_size_rounded, DE_NULL, /* data */
2288                                            GL_SPARSE_STORAGE_BIT_ARB);
2289         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferStorage() call failed.");
2290
2291         /* Initialize the immutable buffer objects used by the test */
2292         for (unsigned int n_bo = 0; n_bo < 2; /* helper + immutable BO used for the copy ops */
2293                  ++n_bo)
2294         {
2295                 glw::GLuint* bo_id_ptr = (n_bo == 0) ? &m_helper_bo : &m_immutable_bo;
2296                 glw::GLenum  flags       = GL_DYNAMIC_STORAGE_BIT;
2297
2298                 if (n_bo == 0)
2299                 {
2300                         flags |= GL_MAP_READ_BIT;
2301                 }
2302
2303                 /* Initialize the immutable buffer object */
2304                 m_gl.genBuffers(1, bo_id_ptr);
2305                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenBuffers() call failed.");
2306
2307                 m_gl.bindBuffer(GL_ARRAY_BUFFER, *bo_id_ptr);
2308                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
2309
2310                 m_gl.bufferStorage(GL_ARRAY_BUFFER, m_sparse_bo_size_rounded, m_ref_data[0], flags);
2311                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferStorage() call failed.");
2312         }
2313
2314         return true;
2315 }
2316
2317 /** Initializes GL objects which are needed for a single test case iteration.
2318  *
2319  *  deinitTestCaseIteration() will be called after the test case is executed in ::execute()
2320  *  to release these objects.
2321  **/
2322 bool CopyOpsBufferStorageTestCase::initTestCaseIteration(glw::GLuint sparse_bo)
2323 {
2324         bool result = true;
2325
2326         /* Remember the BO id */
2327         m_sparse_bos[0] = sparse_bo;
2328
2329         /* Initialize test cases, if this is the first call to initTestCaseIteration() */
2330         if (m_test_cases.size() == 0)
2331         {
2332                 initTestCases();
2333         }
2334
2335         /* Make sure all pages of the provided sparse BO are de-committed before
2336          * ::execute() is called. */
2337         m_gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bos[0]);
2338         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
2339
2340         m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0,                                  /* offset */
2341                                                                  m_sparse_bo_size_rounded, GL_FALSE); /* commit */
2342
2343         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
2344
2345         return result;
2346 }
2347
2348 /** Fills m_test_cases with test case descriptors. Each such descriptor defines
2349  *  a single copy op use case.
2350  *
2351  * The descriptors are then iterated over in ::execute(), defining the testing
2352  * behavior of the test copy ops buffer storage test case.
2353  */
2354 void CopyOpsBufferStorageTestCase::initTestCases()
2355 {
2356         /* We need to use the following destination & source BO configurations:
2357          *
2358          * Dst: sparse    BO 1;  Src: sparse    BO 2
2359          * Dst: sparse    BO 1;  Src: immutable BO
2360          * Dst: immutable BO;    Src: sparse    BO 1
2361          * Dst: sparse    BO 1;  Src: sparse    BO 1
2362          */
2363         unsigned int n_test_case = 0;
2364
2365         for (unsigned int n_bo_configuration = 0; n_bo_configuration < 4; /* as per the comment */
2366                  ++n_bo_configuration, ++n_test_case)
2367         {
2368                 glw::GLuint             dst_bo_sparse_id = 0;
2369                 bool                    dst_bo_is_sparse = false;
2370                 unsigned short* dst_bo_ref_data  = DE_NULL;
2371                 glw::GLuint             src_bo_sparse_id = 0;
2372                 bool                    src_bo_is_sparse = false;
2373                 unsigned short* src_bo_ref_data  = DE_NULL;
2374
2375                 switch (n_bo_configuration)
2376                 {
2377                 case 0:
2378                 {
2379                         dst_bo_sparse_id = 0;
2380                         dst_bo_is_sparse = true;
2381                         dst_bo_ref_data  = m_ref_data[1];
2382                         src_bo_sparse_id = 1;
2383                         src_bo_is_sparse = true;
2384                         src_bo_ref_data  = m_ref_data[2];
2385
2386                         break;
2387                 }
2388
2389                 case 1:
2390                 {
2391                         dst_bo_sparse_id = 0;
2392                         dst_bo_is_sparse = true;
2393                         dst_bo_ref_data  = m_ref_data[1];
2394                         src_bo_is_sparse = false;
2395                         src_bo_ref_data  = m_ref_data[0];
2396
2397                         break;
2398                 }
2399
2400                 case 2:
2401                 {
2402                         dst_bo_is_sparse = false;
2403                         dst_bo_ref_data  = m_ref_data[0];
2404                         src_bo_sparse_id = 0;
2405                         src_bo_is_sparse = true;
2406                         src_bo_ref_data  = m_ref_data[1];
2407
2408                         break;
2409                 }
2410
2411                 case 3:
2412                 {
2413                         dst_bo_sparse_id = 0;
2414                         dst_bo_is_sparse = true;
2415                         dst_bo_ref_data  = m_ref_data[1];
2416                         src_bo_sparse_id = 0;
2417                         src_bo_is_sparse = true;
2418                         src_bo_ref_data  = m_ref_data[1];
2419
2420                         break;
2421                 }
2422
2423                 default:
2424                 {
2425                         TCU_FAIL("Invalid BO configuration index");
2426                 }
2427                 } /* switch (n_bo_configuration) */
2428
2429                 /* Need to test the copy operation in three different scenarios,
2430                  * in regard to the destination buffer:
2431                  *
2432                  * a) All pages of the destination region are committed.
2433                  * b) Half of the pages of the destination region are committed.
2434                  * c) None of the pages of the destination region are committed.
2435                  *
2436                  * Destination region spans from 0 to half of the memory we use
2437                  * for the testing purposes.
2438                  */
2439                 DE_ASSERT((m_sparse_bo_size_rounded % m_page_size) == 0);
2440                 DE_ASSERT((m_sparse_bo_size_rounded % 2) == 0);
2441                 DE_ASSERT((m_sparse_bo_size_rounded % 4) == 0);
2442
2443                 for (unsigned int n_dst_region = 0; n_dst_region < 3; /* as per the comment */
2444                          ++n_dst_region)
2445                 {
2446                         glw::GLuint dst_bo_commit_size             = 0;
2447                         glw::GLuint dst_bo_commit_start_offset = 0;
2448
2449                         switch (n_dst_region)
2450                         {
2451                         case 0:
2452                         {
2453                                 dst_bo_commit_start_offset = 0;
2454                                 dst_bo_commit_size                 = m_sparse_bo_size_rounded / 2;
2455
2456                                 break;
2457                         }
2458
2459                         case 1:
2460                         {
2461                                 dst_bo_commit_start_offset = m_sparse_bo_size_rounded / 4;
2462                                 dst_bo_commit_size                 = m_sparse_bo_size_rounded / 4;
2463
2464                                 break;
2465                         }
2466
2467                         case 2:
2468                         {
2469                                 dst_bo_commit_start_offset = 0;
2470                                 dst_bo_commit_size                 = 0;
2471
2472                                 break;
2473                         }
2474
2475                         default:
2476                         {
2477                                 TCU_FAIL("Invalid destination region configuration index");
2478                         }
2479                         } /* switch (n_dst_region) */
2480
2481                         /* Same goes for the source region.
2482                          *
2483                          * Source region spans from m_sparse_bo_size_rounded / 2 to
2484                          * m_sparse_bo_size_rounded.
2485                          *
2486                          **/
2487                         for (unsigned int n_src_region = 0; n_src_region < 3; /* as per the comment */
2488                                  ++n_src_region)
2489                         {
2490                                 glw::GLuint src_bo_commit_size             = 0;
2491                                 glw::GLuint src_bo_commit_start_offset = 0;
2492
2493                                 switch (n_src_region)
2494                                 {
2495                                 case 0:
2496                                 {
2497                                         src_bo_commit_start_offset = m_sparse_bo_size_rounded / 2;
2498                                         src_bo_commit_size                 = m_sparse_bo_size_rounded / 2;
2499
2500                                         break;
2501                                 }
2502
2503                                 case 1:
2504                                 {
2505                                         src_bo_commit_start_offset = 3 * m_sparse_bo_size_rounded / 4;
2506                                         src_bo_commit_size                 = m_sparse_bo_size_rounded / 4;
2507
2508                                         break;
2509                                 }
2510
2511                                 case 2:
2512                                 {
2513                                         src_bo_commit_start_offset = m_sparse_bo_size_rounded / 2;
2514                                         src_bo_commit_size                 = 0;
2515
2516                                         break;
2517                                 }
2518
2519                                 default:
2520                                 {
2521                                         TCU_FAIL("Invalid source region configuration index");
2522                                 }
2523                                 } /* switch (n_src_region) */
2524
2525                                 /* Initialize the test case descriptor */
2526                                 _test_case test_case;
2527
2528                                 test_case.dst_bo_commit_size             = dst_bo_commit_size;
2529                                 test_case.dst_bo_commit_start_offset = dst_bo_commit_start_offset;
2530                                 test_case.dst_bo_sparse_id                       = dst_bo_sparse_id;
2531                                 test_case.dst_bo_is_sparse                       = dst_bo_is_sparse;
2532                                 test_case.dst_bo_ref_data                        = dst_bo_ref_data;
2533                                 test_case.dst_bo_start_offset            = static_cast<glw::GLint>(sizeof(short) * n_test_case);
2534                                 test_case.n_bytes_to_copy                        = static_cast<glw::GLint>(
2535                                         m_sparse_bo_size_rounded / 2 - test_case.dst_bo_start_offset - sizeof(short) * n_test_case);
2536                                 test_case.src_bo_commit_size             = src_bo_commit_size;
2537                                 test_case.src_bo_commit_start_offset = src_bo_commit_start_offset;
2538                                 test_case.src_bo_sparse_id                       = src_bo_sparse_id;
2539                                 test_case.src_bo_is_sparse                       = src_bo_is_sparse;
2540                                 test_case.src_bo_ref_data                        = src_bo_ref_data;
2541                                 test_case.src_bo_start_offset            = m_sparse_bo_size_rounded / 2;
2542
2543                                 DE_ASSERT(test_case.dst_bo_commit_size >= 0);
2544                                 DE_ASSERT(test_case.dst_bo_commit_start_offset >= 0);
2545                                 DE_ASSERT(test_case.dst_bo_ref_data != DE_NULL);
2546                                 DE_ASSERT(test_case.dst_bo_start_offset >= 0);
2547                                 DE_ASSERT(test_case.n_bytes_to_copy >= 0);
2548                                 DE_ASSERT(test_case.src_bo_commit_size >= 0);
2549                                 DE_ASSERT(test_case.src_bo_commit_start_offset >= 0);
2550                                 DE_ASSERT(test_case.src_bo_ref_data != DE_NULL);
2551                                 DE_ASSERT(test_case.src_bo_start_offset >= 0);
2552
2553                                 m_test_cases.push_back(test_case);
2554                         } /* for (all source region commit configurations) */
2555                 }        /* for (all destination region commit configurations) */
2556         }                 /* for (all BO configurations which need to be tested) */
2557 }
2558
2559 /** Constructor.
2560  *
2561  *  @param gl                         GL entry-points container
2562  *  @param testContext                CTS test context
2563  *  @param page_size                  Page size, as reported by implementation for the GL_SPARSE_BUFFER_PAGE_SIZE_ARB query.
2564  *  @param pGLBufferPageCommitmentARB Func ptr to glBufferPageCommitmentARB() entry-point.
2565  */
2566 IndirectDispatchBufferStorageTestCase::IndirectDispatchBufferStorageTestCase(const glw::Functions& gl,
2567                                                                                                                                                          tcu::TestContext&       testContext,
2568                                                                                                                                                          glw::GLint                        page_size)
2569         : m_dispatch_draw_call_args_start_offset(-1)
2570         , m_expected_ac_value(0)
2571         , m_gl(gl)
2572         , m_global_wg_size_x(2048)
2573         , m_helper_bo(0)
2574         , m_local_wg_size_x(1023) /* must stay in sync with the local work-groups's size hardcoded in m_po's body! */
2575         , m_page_size(page_size)
2576         , m_po(0)
2577         , m_sparse_bo(0)
2578         , m_sparse_bo_size(0)
2579         , m_sparse_bo_size_rounded(0)
2580         , m_testCtx(testContext)
2581 {
2582         /* Left blank intentionally */
2583 }
2584
2585 /** Releases all GL objects used across all test case iterations.
2586  *
2587  *  Called once during BufferStorage test run-time.
2588  */
2589 void IndirectDispatchBufferStorageTestCase::deinitTestCaseGlobal()
2590 {
2591         if (m_helper_bo != 0)
2592         {
2593                 m_gl.deleteBuffers(1, &m_helper_bo);
2594
2595                 m_helper_bo = 0;
2596         }
2597
2598         if (m_po != 0)
2599         {
2600                 m_gl.deleteProgram(m_po);
2601
2602                 m_po = 0;
2603         }
2604 }
2605
2606 /** Releases temporary GL objects, created specifically for one test case iteration. */
2607 void IndirectDispatchBufferStorageTestCase::deinitTestCaseIteration()
2608 {
2609         if (m_sparse_bo != 0)
2610         {
2611                 m_gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bo);
2612                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
2613
2614                 m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0,                                  /* offset */
2615                                                                          m_sparse_bo_size_rounded, GL_FALSE); /* commit */
2616                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
2617
2618                 m_sparse_bo = 0;
2619         }
2620 }
2621
2622 /** Executes a single test iteration. The BufferStorage test will call this method
2623  *  numerously during its life-time, testing various valid flag combinations applied
2624  *  to the tested sparse buffer object at glBufferStorage() call time.
2625  *
2626  *  @param sparse_bo_storage_flags <flags> argument, used by the test in the glBufferStorage()
2627  *                                 call to set up the sparse buffer's storage.
2628  *
2629  *  @return true if the test case executed correctly, false otherwise.
2630  */
2631 bool IndirectDispatchBufferStorageTestCase::execute(glw::GLuint sparse_bo_storage_flags)
2632 {
2633         (void)sparse_bo_storage_flags;
2634         bool result = true;
2635
2636         /* Set up the buffer bindings */
2637         m_gl.bindBuffer(GL_ATOMIC_COUNTER_BUFFER, m_helper_bo);
2638         m_gl.bindBuffer(GL_DISPATCH_INDIRECT_BUFFER, m_sparse_bo);
2639         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call(s) failed");
2640
2641         m_gl.bindBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, /* index */
2642                                                  m_helper_bo, 12,                         /* offset */
2643                                                  4);                                              /* size */
2644         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBufferRange() call failed.");
2645
2646         /* Bind the compute program */
2647         m_gl.useProgram(m_po);
2648         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUseProgram() call failed.");
2649
2650         /* Zero out atomic counter value. */
2651         const unsigned int zero_ac_value = 0;
2652
2653         m_gl.bufferSubData(GL_ATOMIC_COUNTER_BUFFER, 12, /* offset */
2654                                            4,                                                    /* size */
2655                                            &zero_ac_value);
2656         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferSubData() call failed.");
2657
2658         m_expected_ac_value = zero_ac_value;
2659
2660         /* Run the test only in a configuration where all arguments are local in
2661          * committed memory page(s): reading arguments from uncommitted pages means
2662          * reading undefined data, which can result in huge dispatches that
2663          * effectively hang the test.
2664          */
2665         m_gl.bufferPageCommitmentARB(GL_DISPATCH_INDIRECT_BUFFER, 0,     /* offset */
2666                                                                  m_sparse_bo_size_rounded, GL_TRUE); /* commit */
2667
2668         m_expected_ac_value += m_global_wg_size_x * m_local_wg_size_x;
2669
2670         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call(s) failed.");
2671
2672         /* Copy the indirect dispatch call args data from the helper BO to the sparse BO */
2673         m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_helper_bo);
2674         m_gl.bindBuffer(GL_COPY_WRITE_BUFFER, m_sparse_bo);
2675         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
2676
2677         m_gl.copyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, /* readOffset */
2678                                                    m_dispatch_draw_call_args_start_offset, sizeof(unsigned int) * 3);
2679
2680         /* Run the program */
2681         m_gl.dispatchComputeIndirect(m_dispatch_draw_call_args_start_offset);
2682         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDispatchComputeIndirect() call failed.");
2683
2684         /* Extract the AC value and verify it */
2685         const unsigned int* ac_data_ptr =
2686                 (const unsigned int*)m_gl.mapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 12, /* offset */
2687                                                                                                  4,                                                        /* length */
2688                                                                                                  GL_MAP_READ_BIT);
2689
2690         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glMapBufferRange() call failed.");
2691
2692         if (*ac_data_ptr != m_expected_ac_value && result)
2693         {
2694                 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid atomic counter value encountered. "
2695                                                                                                            "Expected value: ["
2696                                                    << m_expected_ac_value << "]"
2697                                                                                                          ", found:"
2698                                                                                                          "["
2699                                                    << *ac_data_ptr << "]." << tcu::TestLog::EndMessage;
2700
2701                 result = false;
2702         }
2703
2704         /* Unmap the buffer before we move on with the next iteration */
2705         m_gl.unmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
2706         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUnmapBuffer() call failed.");
2707
2708         return result;
2709 }
2710
2711 /** Initializes GL objects used across all test case iterations.
2712  *
2713  *  Called once during BufferStorage test run-time.
2714  */
2715 bool IndirectDispatchBufferStorageTestCase::initTestCaseGlobal()
2716 {
2717         bool result = true;
2718
2719         /* One of the cases the test case implementation needs to support is the scenario
2720          * where the indirect call arguments are located on the boundary of two (or more) memory pages,
2721          * and some of the pages are not committed.
2722          *
2723          * There are two scenarios which can happen:
2724          *
2725          * a) page size >= sizeof(uint) * 3: Allocate two pages, arg start offset: (page_size - 4) aligned to 4.
2726          *                                   The alignment is a must, since we'll be feeding the offset to an indirect dispatch call.
2727          * b) page size <  sizeof(uint) * 3: Allocate as many pages as needed, disable some of the pages.
2728          *
2729          * For code clarity, the two cases are handled by separate branches, although they could be easily
2730          * merged.
2731          */
2732         const int n_indirect_dispatch_call_arg_bytes = sizeof(unsigned int) * 3;
2733
2734         if (m_page_size >= n_indirect_dispatch_call_arg_bytes)
2735         {
2736                 /* Indirect dispatch call args must be aligned to 4 */
2737                 DE_ASSERT(m_page_size >= 4);
2738
2739                 m_dispatch_draw_call_args_start_offset = SparseBufferTestUtilities::alignOffset(m_page_size - 4, 4);
2740                 m_sparse_bo_size = m_dispatch_draw_call_args_start_offset + n_indirect_dispatch_call_arg_bytes;
2741         }
2742         else
2743         {
2744                 m_dispatch_draw_call_args_start_offset = 0;
2745                 m_sparse_bo_size                                           = n_indirect_dispatch_call_arg_bytes;
2746         }
2747
2748         m_sparse_bo_size_rounded = SparseBufferTestUtilities::alignOffset(m_sparse_bo_size, m_page_size);
2749
2750         /* Set up the helper buffer object. Its structure is as follows:
2751          *
2752          * [ 0-11]: Indirect dispatch call args
2753          * [12-15]: Atomic counter value storage
2754          */
2755         unsigned int       helper_bo_data[4] = { 0 };
2756         const unsigned int n_helper_bo_bytes = sizeof(helper_bo_data);
2757
2758         helper_bo_data[0] = m_global_wg_size_x; /* num_groups_x */
2759         helper_bo_data[1] = 1;                                  /* num_groups_y */
2760         helper_bo_data[2] = 1;                                  /* num_groups_z */
2761         helper_bo_data[3] = 0;                                  /* default atomic counter value */
2762
2763         m_gl.genBuffers(1, &m_helper_bo);
2764         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenBuffers() call failed.");
2765
2766         m_gl.bindBuffer(GL_ARRAY_BUFFER, m_helper_bo);
2767         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
2768
2769         m_gl.bufferData(GL_ARRAY_BUFFER, n_helper_bo_bytes, helper_bo_data, GL_STATIC_DRAW);
2770         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferData() call failed.");
2771
2772         /* Set up the test compute program object */
2773         static const char* cs_body = "#version 430 core\n"
2774                                                                  "\n"
2775                                                                  "layout(local_size_x = 1023)          in;\n"
2776                                                                  "layout(binding      = 0, offset = 0) uniform atomic_uint ac;\n"
2777                                                                  "\n"
2778                                                                  "void main()\n"
2779                                                                  "{\n"
2780                                                                  "    atomicCounterIncrement(ac);\n"
2781                                                                  "}\n";
2782
2783         m_po = SparseBufferTestUtilities::createComputeProgram(m_gl, &cs_body, 1); /* n_cs_body_parts */
2784
2785         result = (m_po != 0);
2786
2787         return result;
2788 }
2789
2790 /** Initializes GL objects which are needed for a single test case iteration.
2791  *
2792  *  deinitTestCaseIteration() will be called after the test case is executed in ::execute()
2793  *  to release these objects.
2794  **/
2795 bool IndirectDispatchBufferStorageTestCase::initTestCaseIteration(glw::GLuint sparse_bo)
2796 {
2797         bool result = true;
2798
2799         /* Cache the BO id, if not cached already */
2800         DE_ASSERT(m_sparse_bo == 0 || m_sparse_bo == sparse_bo);
2801
2802         m_sparse_bo = sparse_bo;
2803
2804         /* Set up the sparse bufffer. */
2805         m_gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bo);
2806         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
2807
2808         m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0,                                 /* offset */
2809                                                                  m_sparse_bo_size_rounded, GL_TRUE); /* commit */
2810
2811         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
2812
2813         return result;
2814 }
2815
2816 /** Constructor.
2817  *
2818  *  @param gl                         GL entry-points container
2819  *  @param testContext                CTS test context
2820  *  @param page_size                  Page size, as reported by implementation for the GL_SPARSE_BUFFER_PAGE_SIZE_ARB query.
2821  *  @param pGLBufferPageCommitmentARB Func ptr to glBufferPageCommitmentARB() entry-point.
2822  */
2823 InvalidateBufferStorageTestCase::InvalidateBufferStorageTestCase(const glw::Functions& gl,
2824                                                                                                                                  tcu::TestContext& testContext, glw::GLint page_size)
2825         : m_gl(gl)
2826         , m_n_pages_to_use(4)
2827         , m_page_size(page_size)
2828         , m_sparse_bo(0)
2829         , m_sparse_bo_size(0)
2830         , m_sparse_bo_size_rounded(0)
2831 {
2832         (void)testContext;
2833         DE_ASSERT((m_n_pages_to_use % 2) == 0);
2834 }
2835
2836 /** Releases all GL objects used across all test case iterations.
2837  *
2838  *  Called once during BufferStorage test run-time.
2839  */
2840 void InvalidateBufferStorageTestCase::deinitTestCaseGlobal()
2841 {
2842         /* Stub */
2843 }
2844
2845 /** Releases temporary GL objects, created specifically for one test case iteration. */
2846 void InvalidateBufferStorageTestCase::deinitTestCaseIteration()
2847 {
2848         if (m_sparse_bo != 0)
2849         {
2850                 m_gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bo);
2851                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
2852
2853                 m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0,                                  /* offset */
2854                                                                          m_sparse_bo_size_rounded, GL_FALSE); /* commit */
2855                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
2856
2857                 m_sparse_bo = 0;
2858         }
2859 }
2860
2861 /** Executes a single test iteration. The BufferStorage test will call this method
2862  *  numerously during its life-time, testing various valid flag combinations applied
2863  *  to the tested sparse buffer object at glBufferStorage() call time.
2864  *
2865  *  @param sparse_bo_storage_flags <flags> argument, used by the test in the glBufferStorage()
2866  *                                 call to set up the sparse buffer's storage.
2867  *
2868  *  @return true if the test case executed correctly, false otherwise.
2869  */
2870 bool InvalidateBufferStorageTestCase::execute(glw::GLuint sparse_bo_storage_flags)
2871 {
2872         (void)sparse_bo_storage_flags;
2873         bool result = true;
2874
2875         /* Since we cannot really perform any validation related to whether buffer
2876          * storage invalidation works corectly, all this test can really do is to verify
2877          * if the implementation does not crash when both entry-points are used against
2878          * a sparse buffer object.
2879          */
2880         for (unsigned int n_entry_point = 0; n_entry_point < 2; /* glInvalidateBuffer(), glInvalidateBufferSubData() */
2881                  ++n_entry_point)
2882         {
2883                 const bool should_test_invalidate_buffer = (n_entry_point == 0);
2884
2885                 /* For glInvalidateBufferSubData(), we need to test two different ranges. */
2886                 for (int n_iteration = 0; n_iteration < ((should_test_invalidate_buffer) ? 1 : 2); ++n_iteration)
2887                 {
2888                         if (should_test_invalidate_buffer)
2889                         {
2890                                 m_gl.invalidateBufferData(m_sparse_bo);
2891                                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glInvalidateBufferData() call failed.");
2892                         }
2893                         else
2894                         {
2895                                 m_gl.invalidateBufferSubData(m_sparse_bo, 0, /* offset */
2896                                                                                          m_sparse_bo_size_rounded * ((n_iteration == 0) ? 1 : 2));
2897                                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glInvalidateBufferSubData() call failed.");
2898                         }
2899                 } /* for (all iterations) */
2900         }        /* for (both entry-points) */
2901
2902         return result;
2903 }
2904
2905 /** Initializes GL objects used across all test case iterations.
2906  *
2907  *  Called once during BufferStorage test run-time.
2908  */
2909 bool InvalidateBufferStorageTestCase::initTestCaseGlobal()
2910 {
2911         const unsigned int n_bytes_needed = m_n_pages_to_use * m_page_size;
2912
2913         /* Determine the number of bytes both the helper and the sparse buffer
2914          * object need to be able to hold, at maximum */
2915         m_sparse_bo_size                 = n_bytes_needed;
2916         m_sparse_bo_size_rounded = SparseBufferTestUtilities::alignOffset(n_bytes_needed, m_page_size);
2917
2918         return true;
2919 }
2920
2921 /** Initializes GL objects which are needed for a single test case iteration.
2922  *
2923  *  deinitTestCaseIteration() will be called after the test case is executed in ::execute()
2924  *  to release these objects.
2925  **/
2926 bool InvalidateBufferStorageTestCase::initTestCaseIteration(glw::GLuint sparse_bo)
2927 {
2928         bool result = true;
2929
2930         /* Cache the BO id, if not cached already */
2931         DE_ASSERT(m_sparse_bo == 0 || m_sparse_bo == sparse_bo);
2932
2933         m_sparse_bo = sparse_bo;
2934
2935         /* Set up the sparse bufffer. */
2936         m_gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bo);
2937         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
2938
2939         m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0,                                 /* offset */
2940                                                                  m_sparse_bo_size_rounded, GL_TRUE); /* commit */
2941
2942         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
2943
2944         return result;
2945 }
2946
2947 /** Constructor.
2948  *
2949  *  @param gl                         GL entry-points container
2950  *  @param testContext                CTS test context
2951  *  @param page_size                  Page size, as reported by implementation for the GL_SPARSE_BUFFER_PAGE_SIZE_ARB query.
2952  *  @param pGLBufferPageCommitmentARB Func ptr to glBufferPageCommitmentARB() entry-point.
2953  */
2954 PixelPackBufferStorageTestCase::PixelPackBufferStorageTestCase(const glw::Functions& gl, tcu::TestContext& testContext,
2955                                                                                                                            glw::GLint page_size)
2956         : m_color_rb(0)
2957         , m_color_rb_height(1024)
2958         , m_color_rb_width(1024)
2959         , m_fbo(0)
2960         , m_gl(gl)
2961         , m_helper_bo(0)
2962         , m_page_size(page_size)
2963         , m_po(0)
2964         , m_ref_data_ptr(DE_NULL)
2965         , m_ref_data_size(0)
2966         , m_sparse_bo(0)
2967         , m_sparse_bo_size(0)
2968         , m_sparse_bo_size_rounded(0)
2969         , m_testCtx(testContext)
2970         , m_vao(0)
2971 {
2972         m_ref_data_size = m_color_rb_width * m_color_rb_height * 4; /* rgba */
2973 }
2974
2975 /** Releases all GL objects used across all test case iterations.
2976  *
2977  *  Called once during BufferStorage test run-time.
2978  */
2979 void PixelPackBufferStorageTestCase::deinitTestCaseGlobal()
2980 {
2981         if (m_color_rb != 0)
2982         {
2983                 m_gl.deleteRenderbuffers(1, &m_color_rb);
2984
2985                 m_color_rb = 0;
2986         }
2987
2988         if (m_fbo != 0)
2989         {
2990                 m_gl.deleteFramebuffers(1, &m_fbo);
2991
2992                 m_fbo = 0;
2993         }
2994
2995         if (m_helper_bo != 0)
2996         {
2997                 m_gl.deleteBuffers(1, &m_helper_bo);
2998
2999                 m_helper_bo = 0;
3000         }
3001
3002         if (m_ref_data_ptr != DE_NULL)
3003         {
3004                 delete[] m_ref_data_ptr;
3005
3006                 m_ref_data_ptr = DE_NULL;
3007         }
3008
3009         if (m_po != 0)
3010         {
3011                 m_gl.deleteProgram(m_po);
3012
3013                 m_po = 0;
3014         }
3015
3016         if (m_vao != 0)
3017         {
3018                 m_gl.deleteVertexArrays(1, &m_vao);
3019
3020                 m_vao = 0;
3021         }
3022 }
3023
3024 /** Releases temporary GL objects, created specifically for one test case iteration. */
3025 void PixelPackBufferStorageTestCase::deinitTestCaseIteration()
3026 {
3027         if (m_sparse_bo != 0)
3028         {
3029                 m_gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bo);
3030                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
3031
3032                 m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0,                                  /* offset */
3033                                                                          m_sparse_bo_size_rounded, GL_FALSE); /* commit */
3034                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
3035
3036                 m_sparse_bo = 0;
3037         }
3038 }
3039
3040 /** Executes a single test iteration. The BufferStorage test will call this method
3041  *  numerously during its life-time, testing various valid flag combinations applied
3042  *  to the tested sparse buffer object at glBufferStorage() call time.
3043  *
3044  *  @param sparse_bo_storage_flags <flags> argument, used by the test in the glBufferStorage()
3045  *                                 call to set up the sparse buffer's storage.
3046  *
3047  *  @return true if the test case executed correctly, false otherwise.
3048  */
3049 bool PixelPackBufferStorageTestCase::execute(glw::GLuint sparse_bo_storage_flags)
3050 {
3051         (void)sparse_bo_storage_flags;
3052         bool result = true;
3053
3054         m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_helper_bo);
3055         m_gl.bindBuffer(GL_PIXEL_PACK_BUFFER, m_sparse_bo);
3056         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call(s) failed.");
3057
3058         /* Run three separate iterations:
3059          *
3060          * a) All pages that are going to hold the texture data are committed.
3061          * b) Use a zig-zag memory page commitment layout patern.
3062          * b) No pages are committed.
3063          */
3064         for (unsigned int n_iteration = 0; n_iteration < 3; ++n_iteration)
3065         {
3066                 bool result_local = true;
3067
3068                 /* Set up the memory page commitment & the storage contents*/
3069                 switch (n_iteration)
3070                 {
3071                 case 0:
3072                 {
3073                         m_gl.bufferPageCommitmentARB(GL_PIXEL_PACK_BUFFER, 0,                    /* offset */
3074                                                                                  m_sparse_bo_size_rounded, GL_TRUE); /* commit */
3075                         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
3076
3077                         break;
3078                 }
3079
3080                 case 1:
3081                 {
3082                         const unsigned int n_pages = 1 + m_ref_data_size / m_page_size;
3083
3084                         DE_ASSERT((m_ref_data_size % m_page_size) == 0);
3085
3086                         for (unsigned int n_page = 0; n_page < n_pages; ++n_page)
3087                         {
3088                                 const bool should_commit = ((n_page % 2) == 0);
3089
3090                                 m_gl.bufferPageCommitmentARB(GL_PIXEL_PACK_BUFFER, m_page_size * n_page, m_page_size,
3091                                                                                          should_commit ? GL_TRUE : GL_FALSE);
3092                                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
3093                         } /* for (all relevant memory pages) */
3094
3095                         break;
3096                 }
3097
3098                 case 2:
3099                 {
3100                         /* Do nothing - all pages already de-committed  */
3101                         break;
3102                 }
3103
3104                 default:
3105                 {
3106                         TCU_FAIL("Invalid iteration index");
3107                 }
3108                 } /* switch (n_iteration) */
3109
3110                 /* Draw full screen quad to generate the black-to-white gradient */
3111                 const unsigned char* read_data_ptr = NULL;
3112
3113                 m_gl.useProgram(m_po);
3114                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUseProgram() call failed.");
3115
3116                 m_gl.drawArrays(GL_TRIANGLE_STRIP, 0 /* first */, 4 /* count */);
3117                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawArrays() call failed.");
3118
3119                 /* Read a framebuffer pixel data */
3120                 m_gl.readPixels(0,                                                                                                                                      /* x */
3121                                                 0,                                                                                                                                      /* y */
3122                                                 m_color_rb_width, m_color_rb_height, GL_RGBA, GL_UNSIGNED_BYTE, 0); /* pixels */
3123                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glReadPixels() call failed.");
3124
3125                 m_gl.copyBufferSubData(GL_PIXEL_PACK_BUFFER, GL_COPY_READ_BUFFER, 0, /* readOffset */
3126                                                            0,                                                                                    /* writeOffset */
3127                                                            m_ref_data_size);
3128                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCopyBufferSubData() call failed.");
3129
3130                 read_data_ptr = (unsigned char*)m_gl.mapBufferRange(GL_COPY_READ_BUFFER, 0, /* offset */
3131                                                                                                                         m_ref_data_size, GL_MAP_READ_BIT);
3132
3133                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glMapBufferRange() call failed.");
3134
3135                 /* Verify the data */
3136                 unsigned int             n_current_tex_data_byte          = 0;
3137                 const unsigned char* read_data_traveller_ptr      = (const unsigned char*)read_data_ptr;
3138                 const unsigned char* reference_data_traveller_ptr = (const unsigned char*)m_ref_data_ptr;
3139
3140                 for (unsigned int y = 0; y < m_color_rb_height && result_local; ++y)
3141                 {
3142                         for (unsigned int x = 0; x < m_color_rb_width && result_local; ++x)
3143                         {
3144                                 for (unsigned int n_component = 0; n_component < 4 /* rgba */ && result_local; ++n_component)
3145                                 {
3146                                         unsigned char expected_value             = 0;
3147                                         bool              is_from_committed_page = true;
3148
3149                                         if (n_iteration == 1) /* zig-zag */
3150                                         {
3151                                                 is_from_committed_page = ((n_current_tex_data_byte / m_page_size) % 2) == 0;
3152                                         }
3153                                         else if (n_iteration == 2) /* no pages committed */
3154                                         {
3155                                                 is_from_committed_page = false;
3156                                         }
3157
3158                                         if (is_from_committed_page)
3159                                         {
3160                                                 expected_value = *reference_data_traveller_ptr;
3161                                         }
3162
3163                                         if (is_from_committed_page && de::abs(expected_value - *read_data_traveller_ptr) > 1)
3164                                         {
3165                                                 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid texel data (channel:" << n_component
3166                                                                                    << ")"
3167                                                                                           " found at X:"
3168                                                                                    << x << ", "
3169                                                                                                    "Y:"
3170                                                                                    << y << ")."
3171                                                                                                    " Expected value:"
3172                                                                                    << expected_value << ","
3173                                                                                                                                 " found value:"
3174                                                                                    << *reference_data_traveller_ptr << tcu::TestLog::EndMessage;
3175
3176                                                 result_local = false;
3177                                         }
3178
3179                                         n_current_tex_data_byte++;
3180                                         read_data_traveller_ptr++;
3181                                         reference_data_traveller_ptr++;
3182                                 } /* for (all components) */
3183                         }        /* for (all columns) */
3184                 }                 /* for (all rows) */
3185
3186                 m_gl.unmapBuffer(GL_COPY_READ_BUFFER);
3187                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUnmapBuffer() call failed.");
3188
3189                 read_data_ptr = DE_NULL;
3190                 result &= result_local;
3191
3192                 /* Clean up */
3193                 m_gl.bufferPageCommitmentARB(GL_PIXEL_PACK_BUFFER, 0,                     /* offset */
3194                                                                          m_sparse_bo_size_rounded, GL_FALSE); /* commit */
3195                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
3196         } /* for (three iterations) */
3197
3198         m_gl.bindBuffer(GL_PIXEL_PACK_BUFFER, 0);
3199         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
3200
3201         return result;
3202 }
3203
3204 /** Initializes GL objects used across all test case iterations.
3205  *
3206  *  Called once during BufferStorage test run-time.
3207  */
3208 bool PixelPackBufferStorageTestCase::initTestCaseGlobal()
3209 {
3210         /* Determine vertex shader and fragment shader that will generate black-to-white gradient. */
3211         const char* gradient_fs_code = "#version 330 core\n"
3212                                                                    "\n"
3213                                                                    "out vec4 result;\n"
3214                                                                    "\n"
3215                                                                    "void main()\n"
3216                                                                    "{\n"
3217                                                                    "    float c = 1.0 - (gl_FragCoord.y - 0.5) / 1023.0;\n"
3218                                                                    "    result  = vec4(c);\n"
3219                                                                    "}\n";
3220
3221         const char* gradient_vs_code = "#version 330\n"
3222                                                                    "\n"
3223                                                                    "void main()\n"
3224                                                                    "{\n"
3225                                                                    "    switch (gl_VertexID)\n"
3226                                                                    "    {\n"
3227                                                                    "        case 0: gl_Position = vec4(-1.0, -1.0, 0.0, 1.0); break;\n"
3228                                                                    "        case 1: gl_Position = vec4( 1.0, -1.0, 0.0, 1.0); break;\n"
3229                                                                    "        case 2: gl_Position = vec4(-1.0,  1.0, 0.0, 1.0); break;\n"
3230                                                                    "        case 3: gl_Position = vec4( 1.0,  1.0, 0.0, 1.0); break;\n"
3231                                                                    "    }\n"
3232                                                                    "}\n";
3233
3234         m_po = SparseBufferTestUtilities::createProgram(m_gl, &gradient_fs_code, 1, /* n_fs_body_parts */
3235                                                                                                         &gradient_vs_code, 1,           /* n_vs_body_parts*/
3236                                                                                                         NULL,                                           /* attribute_names */
3237                                                                                                         NULL,                                           /* attribute_locations */
3238                                                                                                         GL_NONE,                                        /* attribute_properties */
3239                                                                                                         0,                                                      /* tf_varyings */
3240                                                                                                         0,                                                      /* n_tf_varyings */
3241                                                                                                         0);                                                     /* tf_varying_mode */
3242         if (m_po == 0)
3243         {
3244                 TCU_FAIL("Failed to link the test program");
3245         }
3246
3247         /* Generate and bind VAO */
3248         m_gl.genVertexArrays(1, &m_vao);
3249         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenVertexArrays() call failed.");
3250
3251         m_gl.bindVertexArray(m_vao);
3252         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindVertexArray() call failed.");
3253
3254         /* Generate and bind FBO */
3255         m_gl.genFramebuffers(1, &m_fbo);
3256         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenFramebuffers() call failed.");
3257
3258         m_gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo);
3259         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindFramebuffer() call failed.");
3260
3261         m_gl.readBuffer(GL_COLOR_ATTACHMENT0);
3262         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glReadBuffer() call failed.");
3263
3264         /* Generate and bind RBO and attach it to FBO as a color attachment */
3265         m_gl.genRenderbuffers(1, &m_color_rb);
3266         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenRenderbuffers() call failed.");
3267
3268         m_gl.bindRenderbuffer(GL_RENDERBUFFER, m_color_rb);
3269         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindRenderbuffer() call failed.");
3270
3271         m_gl.renderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, m_color_rb_width, m_color_rb_height);
3272         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glRenderbufferStorage() call failed.");
3273
3274         m_gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_color_rb);
3275         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glFramebufferRenderbuffer() call failed.");
3276
3277         if (m_gl.checkFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
3278         {
3279                 throw tcu::NotSupportedError("Cannot execute the test - driver does not support rendering"
3280                                                                          "to a GL_RGBA8 renderbuffer-based color attachment");
3281         }
3282
3283         m_gl.viewport(0, /* x */
3284                                   0, /* y */
3285                                   m_color_rb_width, m_color_rb_height);
3286         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glViewport() call failed.");
3287
3288         /* Determine what sparse buffer storage size we are going to need*/
3289         m_sparse_bo_size                 = m_ref_data_size;
3290         m_sparse_bo_size_rounded = SparseBufferTestUtilities::alignOffset(m_sparse_bo_size, m_page_size);
3291
3292         /* Prepare the texture data */
3293         unsigned char* ref_data_traveller_ptr = DE_NULL;
3294
3295         m_ref_data_ptr             = new unsigned char[m_ref_data_size];
3296         ref_data_traveller_ptr = m_ref_data_ptr;
3297
3298         for (unsigned int y = 0; y < m_color_rb_height; ++y)
3299         {
3300                 const unsigned char color = (unsigned char)((1.0f - float(y) / float(m_color_rb_height - 1)) * 255.0f);
3301
3302                 for (unsigned int x = 0; x < m_color_rb_width; ++x)
3303                 {
3304                         memset(ref_data_traveller_ptr, color, 4); /* rgba */
3305
3306                         ref_data_traveller_ptr += 4; /* rgba */
3307                 }                                                                /* for (all columns) */
3308         }                                                                        /* for (all rows) */
3309
3310         /* Set up the helper buffer object. */
3311         m_gl.genBuffers(1, &m_helper_bo);
3312         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenBuffers() call failed.");
3313
3314         m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_helper_bo);
3315         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
3316
3317         m_gl.bufferStorage(GL_COPY_READ_BUFFER, m_ref_data_size, m_ref_data_ptr, GL_MAP_READ_BIT);
3318         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferStorage() call failed.");
3319
3320         return true;
3321 }
3322
3323 /** Initializes GL objects which are needed for a single test case iteration.
3324  *
3325  *  deinitTestCaseIteration() will be called after the test case is executed in ::execute()
3326  *  to release these objects.
3327  **/
3328 bool PixelPackBufferStorageTestCase::initTestCaseIteration(glw::GLuint sparse_bo)
3329 {
3330         bool result = true;
3331
3332         /* Cache the BO id, if not cached already */
3333         DE_ASSERT(m_sparse_bo == 0 || m_sparse_bo == sparse_bo);
3334
3335         m_sparse_bo = sparse_bo;
3336
3337         return result;
3338 }
3339
3340 /** Constructor.
3341  *
3342  *  @param gl                         GL entry-points container
3343  *  @param testContext                CTS test context
3344  *  @param page_size                  Page size, as reported by implementation for the GL_SPARSE_BUFFER_PAGE_SIZE_ARB query.
3345  *  @param pGLBufferPageCommitmentARB Func ptr to glBufferPageCommitmentARB() entry-point.
3346  */
3347 PixelUnpackBufferStorageTestCase::PixelUnpackBufferStorageTestCase(const glw::Functions& gl,
3348                                                                                                                                    tcu::TestContext& testContext, glw::GLint page_size)
3349         : m_gl(gl)
3350         , m_helper_bo(0)
3351         , m_page_size(page_size)
3352         , m_read_data_ptr(DE_NULL)
3353         , m_sparse_bo(0)
3354         , m_sparse_bo_size(0)
3355         , m_sparse_bo_size_rounded(0)
3356         , m_testCtx(testContext)
3357         , m_texture_data_ptr(DE_NULL)
3358         , m_texture_data_size(0)
3359         , m_to(0)
3360         , m_to_data_zero(DE_NULL)
3361         , m_to_height(1024)
3362         , m_to_width(1024)
3363 {
3364         m_texture_data_size = m_to_width * m_to_height * 4; /* rgba */
3365 }
3366
3367 /** Releases all GL objects used across all test case iterations.
3368  *
3369  *  Called once during BufferStorage test run-time.
3370  */
3371 void PixelUnpackBufferStorageTestCase::deinitTestCaseGlobal()
3372 {
3373         if (m_helper_bo != 0)
3374         {
3375                 m_gl.deleteBuffers(1, &m_helper_bo);
3376
3377                 m_helper_bo = 0;
3378         }
3379
3380         if (m_read_data_ptr != DE_NULL)
3381         {
3382                 delete[] m_read_data_ptr;
3383
3384                 m_read_data_ptr = DE_NULL;
3385         }
3386
3387         if (m_texture_data_ptr != DE_NULL)
3388         {
3389                 delete[] m_texture_data_ptr;
3390
3391                 m_texture_data_ptr = DE_NULL;
3392         }
3393
3394         if (m_to != 0)
3395         {
3396                 m_gl.deleteTextures(1, &m_to);
3397
3398                 m_to = 0;
3399         }
3400
3401         if (m_to_data_zero != DE_NULL)
3402         {
3403                 delete[] m_to_data_zero;
3404
3405                 m_to_data_zero = DE_NULL;
3406         }
3407 }
3408
3409 /** Releases temporary GL objects, created specifically for one test case iteration. */
3410 void PixelUnpackBufferStorageTestCase::deinitTestCaseIteration()
3411 {
3412         if (m_sparse_bo != 0)
3413         {
3414                 m_gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bo);
3415                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
3416
3417                 m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0,                                  /* offset */
3418                                                                          m_sparse_bo_size_rounded, GL_FALSE); /* commit */
3419                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
3420
3421                 m_sparse_bo = 0;
3422         }
3423 }
3424
3425 /** Executes a single test iteration. The BufferStorage test will call this method
3426  *  numerously during its life-time, testing various valid flag combinations applied
3427  *  to the tested sparse buffer object at glBufferStorage() call time.
3428  *
3429  *  @param sparse_bo_storage_flags <flags> argument, used by the test in the glBufferStorage()
3430  *                                 call to set up the sparse buffer's storage.
3431  *
3432  *  @return true if the test case executed correctly, false otherwise.
3433  */
3434 bool PixelUnpackBufferStorageTestCase::execute(glw::GLuint sparse_bo_storage_flags)
3435 {
3436         (void)sparse_bo_storage_flags;
3437         bool result = true;
3438
3439         m_gl.bindBuffer(GL_PIXEL_UNPACK_BUFFER, m_sparse_bo);
3440         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
3441
3442         m_gl.bindTexture(GL_TEXTURE_2D, m_to);
3443         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindTexture() call failed.");
3444
3445         m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_helper_bo);
3446         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindTexture() call failed.");
3447
3448         /* Run three separate iterations:
3449          *
3450          * a) All pages holding the source texture data are committed.
3451          * b) Use a zig-zag memory page commitment layout patern.
3452          * b) No pages are committed.
3453          */
3454         for (unsigned int n_iteration = 0; n_iteration < 3; ++n_iteration)
3455         {
3456                 bool result_local = true;
3457
3458                 /* Set up the memory page commitment & the storage contents*/
3459                 switch (n_iteration)
3460                 {
3461                 case 0:
3462                 {
3463                         m_gl.bufferPageCommitmentARB(GL_PIXEL_UNPACK_BUFFER, 0,                  /* offset */
3464                                                                                  m_sparse_bo_size_rounded, GL_TRUE); /* commit */
3465                         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
3466
3467                         m_gl.copyBufferSubData(GL_COPY_READ_BUFFER, GL_PIXEL_UNPACK_BUFFER, 0, /* readOffset */
3468                                                                    0,                                                                                      /* writeOffset */
3469                                                                    m_texture_data_size);
3470                         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCopyBufferSubData() call failed.");
3471
3472                         break;
3473                 }
3474
3475                 case 1:
3476                 {
3477                         const unsigned int n_pages = m_texture_data_size / m_page_size;
3478
3479                         for (unsigned int n_page = 0; n_page < n_pages; ++n_page)
3480                         {
3481                                 const bool should_commit = ((n_page % 2) == 0);
3482
3483                                 m_gl.bufferPageCommitmentARB(GL_PIXEL_UNPACK_BUFFER, m_page_size * n_page, m_page_size,
3484                                                                                          should_commit ? GL_TRUE : GL_FALSE);
3485                                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
3486
3487                                 if (should_commit)
3488                                 {
3489                                         m_gl.copyBufferSubData(GL_COPY_READ_BUFFER, GL_PIXEL_UNPACK_BUFFER,
3490                                                                                    m_page_size * n_page, /* readOffset */
3491                                                                                    m_page_size * n_page, /* writeOffset */
3492                                                                                    m_page_size);
3493                                         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCopyBufferSubData() call failed.");
3494                                 }
3495                         } /* for (all relevant memory pages) */
3496
3497                         break;
3498                 }
3499
3500                 case 2:
3501                 {
3502                         /* Do nothing */
3503                         break;
3504                 }
3505
3506                 default:
3507                 {
3508                         TCU_FAIL("Invalid iteration index");
3509                 }
3510                 } /* switch (n_iteration) */
3511
3512                 /* Clean up the base mip-map's contents before we proceeding with updating it
3513                  * with data downloaded from the BO, in order to avoid situation where silently
3514                  * failing glTexSubImage2D() calls slip past unnoticed */
3515                 m_gl.bindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
3516                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
3517
3518                 m_gl.texSubImage2D(GL_TEXTURE_2D, 0, /* level */
3519                                                    0,                            /* xoffset */
3520                                                    0,                            /* yoffset */
3521                                                    m_to_width, m_to_height, GL_RGBA, GL_UNSIGNED_BYTE, m_to_data_zero);
3522                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glTexSubImage2D() call failed.");
3523
3524                 m_gl.bindBuffer(GL_PIXEL_UNPACK_BUFFER, m_sparse_bo);
3525                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
3526
3527                 /* Update the base mip-map's contents */
3528                 m_gl.texSubImage2D(GL_TEXTURE_2D, 0, /* level */
3529                                                    0,                            /* xoffset */
3530                                                    0,                            /* yoffset */
3531                                                    m_to_width, m_to_height, GL_RGBA, GL_UNSIGNED_BYTE, (const glw::GLvoid*)0);
3532                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glTexSubImage2D() call failed.");
3533
3534                 /* Read back the stored mip-map data */
3535                 memset(m_read_data_ptr, 0xFF, m_texture_data_size);
3536
3537                 m_gl.getTexImage(GL_TEXTURE_2D, 0, /* level */
3538                                                  GL_RGBA, GL_UNSIGNED_BYTE, m_read_data_ptr);
3539                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGetTexImage() call failed.");
3540
3541                 /* Verify the data */
3542                 unsigned int n_current_tex_data_byte    = 0;
3543                 const char*  read_data_traveller_ptr    = (const char*)m_read_data_ptr;
3544                 const char*  texture_data_traveller_ptr = (const char*)m_texture_data_ptr;
3545
3546                 for (unsigned int y = 0; y < m_to_height && result_local; ++y)
3547                 {
3548                         for (unsigned int x = 0; x < m_to_width && result_local; ++x)
3549                         {
3550                                 for (unsigned int n_component = 0; n_component < 4 /* rgba */ && result_local; ++n_component)
3551                                 {
3552                                         char expected_value                     = 0;
3553                                         bool is_from_committed_page = true;
3554
3555                                         if (n_iteration == 1) /* zig-zag */
3556                                         {
3557                                                 is_from_committed_page = ((n_current_tex_data_byte / m_page_size) % 2) == 0;
3558                                         }
3559                                         else if (n_iteration == 2) /* no pages committed */
3560                                         {
3561                                                 is_from_committed_page = false;
3562                                         }
3563
3564                                         if (is_from_committed_page)
3565                                         {
3566                                                 expected_value = *texture_data_traveller_ptr;
3567                                         }
3568
3569                                         if (is_from_committed_page && de::abs(expected_value - *read_data_traveller_ptr) >= 1)
3570                                         {
3571                                                 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid texel data (channel:" << n_component
3572                                                                                    << ")"
3573                                                                                           " found at X:"
3574                                                                                    << x << ", "
3575                                                                                                    "Y:"
3576                                                                                    << y << ")."
3577                                                                                                    " Expected value:"
3578                                                                                    << expected_value << ","
3579                                                                                                                                 " found value:"
3580                                                                                    << *read_data_traveller_ptr << tcu::TestLog::EndMessage;
3581
3582                                                 result_local = false;
3583                                         }
3584
3585                                         n_current_tex_data_byte++;
3586                                         read_data_traveller_ptr++;
3587                                         texture_data_traveller_ptr++;
3588                                 } /* for (all components) */
3589                         }        /* for (all columns) */
3590                 }                 /* for (all rows) */
3591
3592                 result &= result_local;
3593
3594                 /* Clean up */
3595                 m_gl.bufferPageCommitmentARB(GL_PIXEL_UNPACK_BUFFER, 0,                   /* offset */
3596                                                                          m_sparse_bo_size_rounded, GL_FALSE); /* commit */
3597                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
3598         } /* for (three iterations) */
3599
3600         m_gl.bindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
3601         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
3602
3603         return result;
3604 }
3605
3606 /** Initializes GL objects used across all test case iterations.
3607  *
3608  *  Called once during BufferStorage test run-time.
3609  */
3610 bool PixelUnpackBufferStorageTestCase::initTestCaseGlobal()
3611 {
3612         /* Determine sparse buffer storage size */
3613         m_sparse_bo_size                 = m_texture_data_size;
3614         m_sparse_bo_size_rounded = SparseBufferTestUtilities::alignOffset(m_sparse_bo_size, m_page_size);
3615
3616         /* Prepare the texture data */
3617         unsigned char* texture_data_traveller_ptr = DE_NULL;
3618
3619         m_read_data_ptr                    = new unsigned char[m_texture_data_size];
3620         m_texture_data_ptr                 = new unsigned char[m_texture_data_size];
3621         texture_data_traveller_ptr = m_texture_data_ptr;
3622
3623         for (unsigned int y = 0; y < m_to_height; ++y)
3624         {
3625                 for (unsigned int x = 0; x < m_to_width; ++x)
3626                 {
3627                         const unsigned char color = (unsigned char)(float(x) / float(m_to_width - 1) * 255.0f);
3628
3629                         memset(texture_data_traveller_ptr, color, 4); /* rgba */
3630
3631                         texture_data_traveller_ptr += 4; /* rgba */
3632                 }                                                                        /* for (all columns) */
3633         }                                                                                /* for (all rows) */
3634
3635         m_to_data_zero = new unsigned char[m_texture_data_size];
3636
3637         memset(m_to_data_zero, 0, m_texture_data_size);
3638
3639         /* Set up the helper buffer object */
3640         m_gl.genBuffers(1, &m_helper_bo);
3641         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenBuffers() call failed.");
3642
3643         m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_helper_bo);
3644         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
3645
3646         m_gl.bufferStorage(GL_COPY_READ_BUFFER, m_texture_data_size, m_texture_data_ptr, GL_MAP_READ_BIT);
3647         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferStorage() call failed.");
3648
3649         /* Set up texture object storage */
3650         m_gl.genTextures(1, &m_to);
3651         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenTextures() call failed.");
3652
3653         m_gl.bindTexture(GL_TEXTURE_2D, m_to);
3654         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindTexture() call failed.");
3655
3656         m_gl.texStorage2D(GL_TEXTURE_2D, 1, /* levels */
3657                                           GL_RGBA8, m_to_width, m_to_height);
3658         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glTexStorage2D() call failed.");
3659
3660         return true;
3661 }
3662
3663 /** Initializes GL objects which are needed for a single test case iteration.
3664  *
3665  *  deinitTestCaseIteration() will be called after the test case is executed in ::execute()
3666  *  to release these objects.
3667  **/
3668 bool PixelUnpackBufferStorageTestCase::initTestCaseIteration(glw::GLuint sparse_bo)
3669 {
3670         bool result = true;
3671
3672         /* Cache the BO id, if not cached already */
3673         DE_ASSERT(m_sparse_bo == 0 || m_sparse_bo == sparse_bo);
3674
3675         m_sparse_bo = sparse_bo;
3676
3677         return result;
3678 }
3679
3680 /** Constructor.
3681  *
3682  *  @param gl                         GL entry-points container
3683  *  @param testContext                CTS test context
3684  *  @param page_size                  Page size, as reported by implementation for the GL_SPARSE_BUFFER_PAGE_SIZE_ARB query.
3685  *  @param ibo_usage                  Specifies if an indexed draw call should be used by the test. For more details,
3686  *                                    please see documentation for _ibo_usage.
3687  *  @param use_color_data             true to use the color data for the tested draw call;
3688  *                                    false to omit usage of attribute data.
3689  *  @param pGLBufferPageCommitmentARB Func ptr to glBufferPageCommitmentARB() entry-point.
3690  */
3691 QuadsBufferStorageTestCase::QuadsBufferStorageTestCase(const glw::Functions& gl, tcu::TestContext& testContext,
3692                                                                                                            glw::GLint page_size, _ibo_usage ibo_usage, bool use_color_data)
3693         : m_attribute_color_location(0) /* predefined attribute locations */
3694         , m_attribute_position_location(1) /* predefined attribute locations */
3695         , m_color_data_offset(0)
3696         , m_data(DE_NULL)
3697         , m_data_size(0)
3698         , m_data_size_rounded(0)
3699         , m_fbo(0)
3700         , m_gl(gl)
3701         , m_helper_bo(0)
3702         , m_ibo_data_offset(-1)
3703         , m_ibo_usage(ibo_usage)
3704         , m_n_quad_delta_x(5)
3705         , m_n_quad_delta_y(5)
3706         , m_n_quad_height(5)
3707         , m_n_quad_width(5)
3708         , m_n_quads_x(100) /* as per spec */
3709         , m_n_quads_y(100) /* as per spec */
3710         , m_n_vertices_to_draw(0)
3711         , m_pages_committed(false)
3712         , m_po(0)
3713         , m_sparse_bo(0)
3714         , m_testCtx(testContext)
3715         , m_to(0)
3716         , m_to_height(1024) /* as per spec */
3717         , m_to_width(1024)  /* as per spec */
3718         , m_use_color_data(use_color_data)
3719         , m_vao(0)
3720         , m_vbo_data_offset(-1)
3721 {
3722         /*
3723          * Each quad = 2 triangles, 1 triangle = 3 vertices, 1 vertex = 4 components.
3724          * The inefficient representation has been used on purpose - we want the data to take
3725          * more than 64KB so that it is guaranteed that it will span over more than 1 page.
3726          */
3727         m_data_size = 0;
3728
3729         m_n_vertices_to_draw = m_n_quads_x * /* quads in X */
3730                                                    m_n_quads_y * /* quads in Y */
3731                                                    2 *                   /* triangles */
3732                                                    3;                    /* vertices per triangle */
3733
3734         m_data_size = static_cast<glw::GLuint>(m_n_vertices_to_draw * 4 /* components */ * sizeof(float));
3735
3736         if (m_ibo_usage != IBO_USAGE_NONE)
3737         {
3738                 DE_ASSERT(m_n_vertices_to_draw < 65536);
3739
3740                 m_data_size = static_cast<glw::GLuint>(m_data_size + (m_n_vertices_to_draw * sizeof(unsigned short)));
3741         }
3742
3743         if (m_use_color_data)
3744         {
3745                 m_data_size = static_cast<glw::GLuint>(m_data_size +
3746                                                                                            (m_n_vertices_to_draw * sizeof(unsigned char) * 4 * /* rgba components */
3747                                                                                                 2 *                                                                                                /* triangles */
3748                                                                                                 3)); /* vertices per triangle */
3749         }
3750
3751         m_data_size_rounded = SparseBufferTestUtilities::alignOffset(m_data_size, page_size);
3752 }
3753
3754 /** Allocates a data buffer and fills it with vertex/index/color data. Vertex data is always stored,
3755  *  index data only if m_ibo_usage is different from IBO_USAGE_NONE. Color data is only saved if
3756  *  m_use_color_data is true.
3757  *
3758  *  @param out_data              Deref will be used to store a pointer to the allocated data buffer.
3759  *                               Ownership is transferred to the caller. Must not be NULL.
3760  *  @param out_vbo_data_offset   Deref will be used to store an offset, from which VBO data starts,
3761  *                               relative to the beginning of *out_data. Must not be NULL.
3762  *  @param out_ibo_data_offset   Deref will be used to store an offset, from which IBO data starts,
3763  *                               relative to the beginning of *out_data. May be NULL if m_ibo_usage
3764  *                               is IBO_USAGE_NONE.
3765  *  @param out_color_data_offset Deref will be used to store na offset, from which color data starts,
3766  *                               relative to the beginning of *out_data. May be NULL if m_use_color_data
3767  *                               is false.
3768  *
3769  */
3770 void QuadsBufferStorageTestCase::createTestData(unsigned char** out_data, unsigned int* out_vbo_data_offset,
3771                                                                                                 unsigned int* out_ibo_data_offset,
3772                                                                                                 unsigned int* out_color_data_offset) const
3773 {
3774         unsigned char* data_traveller_ptr = NULL;
3775
3776         *out_data                        = new unsigned char[m_data_size];
3777         *out_vbo_data_offset = 0;
3778
3779         data_traveller_ptr = *out_data;
3780
3781         for (unsigned int n_quad_y = 0; n_quad_y < m_n_quads_y; ++n_quad_y)
3782         {
3783                 for (unsigned int n_quad_x = 0; n_quad_x < m_n_quads_x; ++n_quad_x)
3784                 {
3785                         const unsigned int quad_start_x_px = n_quad_x * (m_n_quad_delta_x + m_n_quad_width);
3786                         const unsigned int quad_start_y_px = n_quad_y * (m_n_quad_delta_y + m_n_quad_height);
3787                         const unsigned int quad_end_x_px   = quad_start_x_px + m_n_quad_width;
3788                         const unsigned int quad_end_y_px   = quad_start_y_px + m_n_quad_height;
3789
3790                         const float quad_end_x_ss   = float(quad_end_x_px) / float(m_to_width) * 2.0f - 1.0f;
3791                         const float quad_end_y_ss   = float(quad_end_y_px) / float(m_to_height) * 2.0f - 1.0f;
3792                         const float quad_start_x_ss = float(quad_start_x_px) / float(m_to_width) * 2.0f - 1.0f;
3793                         const float quad_start_y_ss = float(quad_start_y_px) / float(m_to_height) * 2.0f - 1.0f;
3794
3795                         /*  1,4--5
3796                          *  |\   |
3797                          *  | \  |
3798                          *  2----3,6
3799                          */
3800                         const float v1_4[] = {
3801                                 quad_start_x_ss, quad_start_y_ss, 0.0f, /* z */
3802                                 1.0f,                                                                   /* w */
3803                         };
3804                         const float v2[] = {
3805                                 quad_start_x_ss, quad_end_y_ss, 0.0f, /* z */
3806                                 1.0f                                                              /* w */
3807                         };
3808                         const float v3_6[] = {
3809                                 quad_end_x_ss, quad_end_y_ss, 0.0f, /* z */
3810                                 1.0f                                                            /* w */
3811                         };
3812                         const float v5[] = {
3813                                 quad_end_x_ss, quad_start_y_ss, 0.0f, /* z */
3814                                 1.0f                                                              /* w */
3815                         };
3816
3817                         memcpy(data_traveller_ptr, v1_4, sizeof(v1_4));
3818                         data_traveller_ptr += sizeof(v1_4);
3819
3820                         memcpy(data_traveller_ptr, v2, sizeof(v2));
3821                         data_traveller_ptr += sizeof(v2);
3822
3823                         memcpy(data_traveller_ptr, v3_6, sizeof(v3_6));
3824                         data_traveller_ptr += sizeof(v3_6);
3825
3826                         memcpy(data_traveller_ptr, v1_4, sizeof(v1_4));
3827                         data_traveller_ptr += sizeof(v1_4);
3828
3829                         memcpy(data_traveller_ptr, v5, sizeof(v5));
3830                         data_traveller_ptr += sizeof(v5);
3831
3832                         memcpy(data_traveller_ptr, v3_6, sizeof(v3_6));
3833                         data_traveller_ptr += sizeof(v3_6);
3834                 } /* for (all quads in X) */
3835         }        /* for (all quads in Y) */
3836
3837         /* Set up index data if needed */
3838         if (m_ibo_usage != IBO_USAGE_NONE)
3839         {
3840                 *out_ibo_data_offset = static_cast<unsigned int>(data_traveller_ptr - *out_data);
3841
3842                 for (int index = m_n_vertices_to_draw - 1; index >= 0; --index)
3843                 {
3844                         *(unsigned short*)data_traveller_ptr = (unsigned short)index;
3845                         data_traveller_ptr += sizeof(unsigned short);
3846                 } /* for (all index values) */
3847         }        /* if (m_use_ibo) */
3848         else
3849         {
3850                 *out_ibo_data_offset = 0;
3851         }
3852
3853         /* Set up color data if needed */
3854         if (m_use_color_data)
3855         {
3856                 *out_color_data_offset = static_cast<unsigned int>(data_traveller_ptr - *out_data);
3857
3858                 for (unsigned int n_quad = 0; n_quad < m_n_quads_x * m_n_quads_y; ++n_quad)
3859                 {
3860                         /* Use magic formulas to generate a color data set for the quads. The data
3861                          * needs to be duplicated for 6 vertices forming a single quad. */
3862                         for (unsigned int n_vertex = 0; n_vertex < 6; ++n_vertex)
3863                         {
3864                                 /* Red */
3865                                 *data_traveller_ptr = static_cast<unsigned char>(n_quad % 256); //((n_quad + 15) * 14) % 256;
3866                                 data_traveller_ptr++;
3867
3868                                 /* Green */
3869                                 *data_traveller_ptr = static_cast<unsigned char>(((n_quad + 32) * 7) % 255);
3870                                 data_traveller_ptr++;
3871
3872                                 /* Blue */
3873                                 *data_traveller_ptr = static_cast<unsigned char>(((n_quad + 7) * 53) % 255);
3874                                 data_traveller_ptr++;
3875
3876                                 /* Alpha */
3877                                 *data_traveller_ptr = static_cast<unsigned char>(((n_quad + 13) * 3) % 255);
3878                                 data_traveller_ptr++;
3879                         }
3880                 } /* for (all quads) */
3881         }
3882         else
3883         {
3884                 *out_color_data_offset = 0;
3885         }
3886 }
3887
3888 /** Releases all GL objects used across all test case iterations.
3889  *
3890  *  Called once during BufferStorage test run-time.
3891  */
3892 void QuadsBufferStorageTestCase::deinitTestCaseGlobal()
3893 {
3894         if (m_data != DE_NULL)
3895         {
3896                 delete[] m_data;
3897
3898                 m_data = DE_NULL;
3899         }
3900
3901         if (m_fbo != 0)
3902         {
3903                 m_gl.deleteFramebuffers(1, &m_fbo);
3904
3905                 m_fbo = 0;
3906         }
3907
3908         if (m_helper_bo != 0)
3909         {
3910                 m_gl.deleteBuffers(1, &m_helper_bo);
3911
3912                 m_helper_bo = 0;
3913         }
3914
3915         if (m_po != 0)
3916         {
3917                 m_gl.deleteProgram(m_po);
3918
3919                 m_po = 0;
3920         }
3921
3922         if (m_to != 0)
3923         {
3924                 m_gl.deleteTextures(1, &m_to);
3925
3926                 m_to = 0;
3927         }
3928
3929         if (m_vao != 0)
3930         {
3931                 m_gl.deleteVertexArrays(1, &m_vao);
3932
3933                 m_vao = 0;
3934         }
3935 }
3936
3937 /** Releases temporary GL objects, created specifically for one test case iteration. */
3938 void QuadsBufferStorageTestCase::deinitTestCaseIteration()
3939 {
3940         /* If the test executed successfully, all pages should've been released by now.
3941          * However, if it failed, it's a good idea to de-commit them at this point.
3942          * Redundant calls are fine spec-wise, too. */
3943         if (m_sparse_bo != 0)
3944         {
3945                 m_gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bo);
3946                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
3947
3948                 m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0,                         /* offset */
3949                                                                          m_data_size_rounded, GL_FALSE); /* commit */
3950                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
3951
3952                 m_sparse_bo = 0;
3953         }
3954 }
3955
3956 /** Executes a single test iteration. The BufferStorage test will call this method
3957  *  numerously during its life-time, testing various valid flag combinations applied
3958  *  to the tested sparse buffer object at glBufferStorage() call time.
3959  *
3960  *  @param sparse_bo_storage_flags <flags> argument, used by the test in the glBufferStorage()
3961  *                                 call to set up the sparse buffer's storage.
3962  *
3963  *  @return true if the test case executed correctly, false otherwise.
3964  */
3965 bool QuadsBufferStorageTestCase::execute(glw::GLuint sparse_bo_storage_flags)
3966 {
3967         bool result = true;
3968
3969         m_gl.viewport(0, /* x */
3970                                   0, /* y */
3971                                   m_to_width, m_to_height);
3972
3973         m_gl.useProgram(m_po);
3974         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUseProgram() call failed.");
3975
3976         m_gl.clearColor(0.0f,  /* red */
3977                                         0.0f,  /* green */
3978                                         0.0f,  /* blue */
3979                                         0.0f); /* alpha */
3980         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glClearColor() call failed.");
3981
3982         /* Render the quads.
3983          *
3984          * Run in two iterations:
3985          *
3986          * a) Iteration 1 performs the draw call with the VBO & IBO pages committed
3987          * b) Iteration 2 performs the draw call with the VBO & IBO pages without any
3988          *    physical backing.
3989          **/
3990         for (unsigned int n_iteration = 0; n_iteration < 2; ++n_iteration)
3991         {
3992                 initSparseBO((n_iteration == 0), /* decommit pages after upload */
3993                                          (sparse_bo_storage_flags & GL_DYNAMIC_STORAGE_BIT) != 0);
3994
3995                 m_gl.clear(GL_COLOR_BUFFER_BIT);
3996                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glClear() call failed.");
3997
3998                 switch (m_ibo_usage)
3999                 {
4000                 case IBO_USAGE_NONE:
4001                 {
4002                         m_gl.drawArrays(GL_TRIANGLES, 0, /* first */
4003                                                         m_n_vertices_to_draw);
4004                         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawArrays() call failed.");
4005
4006                         break;
4007                 }
4008
4009                 case IBO_USAGE_INDEXED_DRAW_CALL:
4010                 {
4011                         m_gl.drawElements(GL_TRIANGLES, m_n_vertices_to_draw, GL_UNSIGNED_SHORT,
4012                                                           (glw::GLvoid*)(intptr_t)m_ibo_data_offset);
4013                         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawElements() call failed.");
4014
4015                         break;
4016                 }
4017
4018                 case IBO_USAGE_INDEXED_RANGED_DRAW_CALL:
4019                 {
4020                         m_gl.drawRangeElements(GL_TRIANGLES, 0,          /* start */
4021                                                                    m_n_vertices_to_draw, /* end */
4022                                                                    m_n_vertices_to_draw, /* count */
4023                                                                    GL_UNSIGNED_SHORT, (glw::GLvoid*)(intptr_t)m_ibo_data_offset);
4024                         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawRangeElements() call failed.");
4025
4026                         break;
4027                 }
4028
4029                 default:
4030                 {
4031                         TCU_FAIL("Unrecognized IBO usage value");
4032                 }
4033                 } /* switch (m_ibo_usage) */
4034
4035                 /* Retrieve the rendered output */
4036                 unsigned char* read_data = new unsigned char[m_to_width * m_to_height * sizeof(char) * 4 /* rgba */];
4037
4038                 m_gl.readPixels(0, /* x */
4039                                                 0, /* y */
4040                                                 m_to_width, m_to_height, GL_RGBA, GL_UNSIGNED_BYTE, read_data);
4041                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glReadPixels() call failed.");
4042
4043                 /* IF the data pages have been committed by the time the draw call was made, validate the data.
4044                  *
4045                  * For each quad region (be it filled or not), check the center and make sure the retrieved
4046                  * color corresponds to the expected value.
4047                  */
4048                 if (m_pages_committed)
4049                 {
4050                         for (unsigned int n_quad_region_y = 0; n_quad_region_y < m_n_quads_y * 2; /* quad + empty "delta" region */
4051                                  ++n_quad_region_y)
4052                         {
4053                                 for (unsigned int n_quad_region_x = 0; n_quad_region_x < m_n_quads_x * 2; ++n_quad_region_x)
4054                                 {
4055                                         /* Determine the expected texel color */
4056                                         unsigned char expected_color[4];
4057                                         unsigned char found_color[4];
4058                                         bool              is_delta_region = (n_quad_region_x % 2) != 0 || (n_quad_region_y % 2) != 0;
4059
4060                                         if (is_delta_region)
4061                                         {
4062                                                 memset(expected_color, 0, sizeof(expected_color));
4063                                         } /* if (is_delta_region) */
4064                                         else
4065                                         {
4066                                                 if (m_use_color_data)
4067                                                 {
4068                                                         const unsigned int   n_quad_x = n_quad_region_x / 2;
4069                                                         const unsigned int   n_quad_y = n_quad_region_y / 2;
4070                                                         const unsigned char* data_ptr =
4071                                                                 m_data + m_color_data_offset +
4072                                                                 (n_quad_y * m_n_quads_x + n_quad_x) * 4 /* rgba */ * 6; /* vertices */
4073
4074                                                         memcpy(expected_color, data_ptr, sizeof(expected_color));
4075                                                 } /* if (m_use_color_data) */
4076                                                 else
4077                                                 {
4078                                                         memset(expected_color, 255, sizeof(expected_color));
4079                                                 }
4080                                         }
4081
4082                                         /* Do we have a match? */
4083                                         DE_ASSERT(m_n_quad_height == m_n_quad_delta_y);
4084                                         DE_ASSERT(m_n_quad_width == m_n_quad_delta_x);
4085
4086                                         const unsigned int sample_texel_x = m_n_quad_delta_x * n_quad_region_x;
4087                                         const unsigned int sample_texel_y = m_n_quad_delta_y * n_quad_region_y;
4088
4089                                         memcpy(found_color, read_data + (sample_texel_y * m_to_width + sample_texel_x) * 4, /* rgba */
4090                                                    sizeof(found_color));
4091
4092                                         if (memcmp(expected_color, found_color, sizeof(expected_color)) != 0)
4093                                         {
4094                                                 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid color found at "
4095                                                                                                                                            "("
4096                                                                                    << sample_texel_x << ", " << sample_texel_y << "): "
4097                                                                                                                                                                                   "Expected color:"
4098                                                                                                                                                                                   "("
4099                                                                                    << (int)expected_color[0] << ", " << (int)expected_color[1] << ", "
4100                                                                                    << (int)expected_color[2] << ", " << (int)expected_color[3] << "), "
4101                                                                                                                                                                                                                   "Found:"
4102                                                                                                                                                                                                                   "("
4103                                                                                    << (int)found_color[0] << ", " << (int)found_color[1] << ", "
4104                                                                                    << (int)found_color[2] << ", " << (int)found_color[3] << "), "
4105                                                                                    << tcu::TestLog::EndMessage;
4106
4107                                                 result = false;
4108                                                 goto end;
4109                                         }
4110                                 } /* for (all quads in X) */
4111                         }        /* for (all quads in Y) */
4112                 }                 /* if (m_pages_committed) */
4113
4114                 delete[] read_data;
4115                 read_data = DE_NULL;
4116         } /* for (both iterations) */
4117
4118 end:
4119         return result;
4120 }
4121
4122 /** Creates test data and fills the result buffer object (whose ID is stored under m_helper_bo)
4123  *  with the data.
4124  */
4125 void QuadsBufferStorageTestCase::initHelperBO()
4126 {
4127         DE_ASSERT(m_data == DE_NULL);
4128         DE_ASSERT(m_helper_bo == 0);
4129
4130         createTestData(&m_data, &m_vbo_data_offset, &m_ibo_data_offset, &m_color_data_offset);
4131
4132         m_gl.genBuffers(1, &m_helper_bo);
4133         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenBuffers() call failed.");
4134
4135         m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_helper_bo);
4136         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
4137
4138         m_gl.bufferStorage(GL_COPY_READ_BUFFER, m_data_size, m_data, 0); /* flags */
4139         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferStorage() call failed.");
4140 }
4141
4142 /** Creates test data (if necessary), configures sparse buffer's memory page commitment
4143  *  and uploads the test data to the buffer object. Finally, the method configures the
4144  *  vertex array object, used by ::execute() at the draw call time.
4145  *
4146  *  @param decommit_data_pages_after_upload true to de-commit memory pages requested before
4147  *                                          uploading the vertex/index/color data.
4148  *  @param is_dynamic_storage               true to upload the data via glBufferSubData() call.
4149  *                                          false to use a copy op for the operation.
4150  **/
4151 void QuadsBufferStorageTestCase::initSparseBO(bool decommit_data_pages_after_upload, bool is_dynamic_storage)
4152 {
4153         /* Set up the vertex buffer object. */
4154         if (m_data == DE_NULL)
4155         {
4156                 createTestData(&m_data, &m_vbo_data_offset, &m_ibo_data_offset, &m_color_data_offset);
4157         }
4158         else
4159         {
4160                 /* Sanity checks */
4161                 if (m_ibo_usage != IBO_USAGE_NONE)
4162                 {
4163                         DE_ASSERT(m_vbo_data_offset != m_ibo_data_offset);
4164                 }
4165
4166                 if (m_use_color_data)
4167                 {
4168                         DE_ASSERT(m_vbo_data_offset != m_ibo_data_offset);
4169                         DE_ASSERT(m_ibo_data_offset != m_color_data_offset);
4170                 }
4171         }
4172
4173         /* Commit as many pages as we need to upload the data */
4174         m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0,                        /* offset */
4175                                                                  m_data_size_rounded, GL_TRUE); /* commit */
4176         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
4177
4178         m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_helper_bo);
4179         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
4180
4181         m_pages_committed = true;
4182
4183         /* Upload the data */
4184         if (is_dynamic_storage)
4185         {
4186                 m_gl.bufferSubData(GL_ARRAY_BUFFER, 0, /* offset */
4187                                                    m_data_size, m_data);
4188                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferSubData() call failed.");
4189         }
4190         else
4191         {
4192                 /* Sparse BO cannot be directly uploaded data to. Copy the data from a helper BO */
4193                 m_gl.copyBufferSubData(GL_COPY_READ_BUFFER, GL_ARRAY_BUFFER, 0, /* readOffset */
4194                                                            0,                                                                           /* writeOffset */
4195                                                            m_data_size);
4196                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCopyBufferSubData() call failed.");
4197         }
4198
4199         /* Set the VAO up */
4200         m_gl.vertexAttribPointer(m_attribute_position_location, 4, /* size */
4201                                                          GL_FLOAT, GL_FALSE,                       /* normalized */
4202                                                          0,                                                                /* stride */
4203                                                          (glw::GLvoid*)(intptr_t)m_vbo_data_offset);
4204         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glVertexAttribPointer() call failed.");
4205
4206         m_gl.enableVertexAttribArray(m_attribute_position_location); /* index */
4207         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glEnableVertexAttribPointer() call failed.");
4208
4209         if (m_use_color_data)
4210         {
4211                 m_gl.vertexAttribPointer(m_attribute_color_location, 4, /* size */
4212                                                                  GL_UNSIGNED_BYTE, GL_TRUE,             /* normalized */
4213                                                                  0,                                                             /* stride */
4214                                                                  (glw::GLvoid*)(intptr_t)m_color_data_offset);
4215                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glVertexAttribPointer() call failed.");
4216
4217                 m_gl.enableVertexAttribArray(m_attribute_color_location); /* index */
4218                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glEnableVertexAttribPointer() call failed.");
4219         }
4220         else
4221         {
4222                 m_gl.vertexAttrib4f(m_attribute_color_location, 1.0f, 1.0f, 1.0f, 1.0f);
4223                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glVertexAttrib4f() call failed.");
4224
4225                 m_gl.disableVertexAttribArray(m_attribute_color_location);
4226                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDisableVertexAttribArray() call failed.");
4227         }
4228
4229         if (m_ibo_usage != IBO_USAGE_NONE)
4230         {
4231                 m_gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_sparse_bo);
4232                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
4233         } /* if (m_use_ibo) */
4234
4235         /* If we were requested to do so, decommit the pages we have just uploaded
4236          * the data to.
4237          */
4238         if (decommit_data_pages_after_upload)
4239         {
4240                 m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0,                         /* offset */
4241                                                                          m_data_size_rounded, GL_FALSE); /* commit */
4242                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
4243
4244                 m_pages_committed = false;
4245         } /* if (decommit_data_pages_after_upload) */
4246 }
4247
4248 /** Initializes GL objects used across all test case iterations.
4249  *
4250  *  Called once during BufferStorage test run-time.
4251  */
4252 bool QuadsBufferStorageTestCase::initTestCaseGlobal()
4253 {
4254         bool result = true;
4255
4256         /* Set up the texture object */
4257         DE_ASSERT(m_to == 0);
4258
4259         m_gl.genTextures(1, &m_to);
4260         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenTextures() call failed.");
4261
4262         m_gl.bindTexture(GL_TEXTURE_2D, m_to);
4263         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindTexture() call failed.");
4264
4265         m_gl.texStorage2D(GL_TEXTURE_2D, 1, /* levels */
4266                                           GL_RGBA8, m_to_width, m_to_height);
4267         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glTexStorage2D() call failed.");
4268
4269         /* Set up the framebuffer object */
4270         DE_ASSERT(m_fbo == 0);
4271
4272         m_gl.genFramebuffers(1, &m_fbo);
4273         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenFramebuffers() call failed.");
4274
4275         m_gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo);
4276         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindFramebuffer() call failed.");
4277
4278         m_gl.framebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_to, 0); /* level */
4279         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glFramebufferTexture2D() call failed.");
4280
4281         /* Set up the vertex array object */
4282         DE_ASSERT(m_vao == 0);
4283
4284         m_gl.genVertexArrays(1, &m_vao);
4285         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenVertexArrays() call failed.");
4286
4287         m_gl.bindVertexArray(m_vao);
4288         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindVertexArray() call failed.");
4289
4290         /* Init a helper BO */
4291         initHelperBO();
4292
4293         /* Set up the program object */
4294         const char* fs_body = "#version 430 core\n"
4295                                                   "\n"
4296                                                   "flat in  vec4 fs_color;\n"
4297                                                   "     out vec4 color;\n"
4298                                                   "\n"
4299                                                   "void main()\n"
4300                                                   "{\n"
4301                                                   "    color = fs_color;\n"
4302                                                   "}\n";
4303
4304         const char* vs_body = "#version 430 core\n"
4305                                                   "\n"
4306                                                   "in vec4 color;\n"
4307                                                   "in vec4 position;\n"
4308                                                   "\n"
4309                                                   "flat out vec4 fs_color;\n"
4310                                                   "\n"
4311                                                   "void main()\n"
4312                                                   "{\n"
4313                                                   "    fs_color    = color;\n"
4314                                                   "    gl_Position = position;\n"
4315                                                   "}\n";
4316
4317         const unsigned int attribute_locations[] = { m_attribute_color_location, m_attribute_position_location };
4318         const char*                attribute_names[]     = { "color", "position" };
4319         const unsigned int n_attributes                  = sizeof(attribute_locations) / sizeof(attribute_locations[0]);
4320
4321         DE_ASSERT(m_po == 0);
4322
4323         m_po = SparseBufferTestUtilities::createProgram(m_gl, &fs_body, 1, /* n_fs_body_parts */
4324                                                                                                         &vs_body, 1, attribute_names, attribute_locations,
4325                                                                                                         n_attributes); /* n_vs_body_parts */
4326
4327         if (m_po == 0)
4328         {
4329                 result = false;
4330
4331                 goto end;
4332         }
4333
4334 end:
4335         return result;
4336 }
4337
4338 /** Initializes GL objects which are needed for a single test case iteration.
4339  *
4340  *  deinitTestCaseIteration() will be called after the test case is executed in ::execute()
4341  *  to release these objects.
4342  **/
4343 bool QuadsBufferStorageTestCase::initTestCaseIteration(glw::GLuint sparse_bo)
4344 {
4345         bool result = true;
4346
4347         /* Cache the BO id, if not cached already */
4348         DE_ASSERT(m_sparse_bo == 0 || m_sparse_bo == sparse_bo);
4349
4350         m_sparse_bo = sparse_bo;
4351
4352         return result;
4353 }
4354
4355 /** Constructor.
4356  *
4357  *  @param gl                         GL entry-points container
4358  *  @param testContext                CTS test context
4359  *  @param page_size                  Page size, as reported by implementation for the GL_SPARSE_BUFFER_PAGE_SIZE_ARB query.
4360  *  @param pGLBufferPageCommitmentARB Func ptr to glBufferPageCommitmentARB() entry-point.
4361  */
4362 QueryBufferStorageTestCase::QueryBufferStorageTestCase(const glw::Functions& gl, tcu::TestContext& testContext,
4363                                                                                                            glw::GLint page_size)
4364         : m_gl(gl)
4365         , m_helper_bo(0)
4366         , m_n_triangles(15)
4367         , m_page_size(page_size)
4368         , m_po(0)
4369         , m_qo(0)
4370         , m_sparse_bo(0)
4371         , m_sparse_bo_size(0)
4372         , m_sparse_bo_size_rounded(0)
4373         , m_testCtx(testContext)
4374         , m_vao(0)
4375 {
4376         /* Left blank on purpose */
4377 }
4378
4379 /** Releases all GL objects used across all test case iterations.
4380  *
4381  *  Called once during BufferStorage test run-time.
4382  */
4383 void QueryBufferStorageTestCase::deinitTestCaseGlobal()
4384 {
4385         if (m_helper_bo != 0)
4386         {
4387                 m_gl.deleteBuffers(1, &m_helper_bo);
4388
4389                 m_helper_bo = 0;
4390         }
4391
4392         if (m_po != 0)
4393         {
4394                 m_gl.deleteProgram(m_po);
4395
4396                 m_po = 0;
4397         }
4398
4399         if (m_qo != 0)
4400         {
4401                 m_gl.deleteQueries(1, &m_qo);
4402
4403                 m_qo = 0;
4404         }
4405
4406         if (m_vao != 0)
4407         {
4408                 m_gl.deleteVertexArrays(1, &m_vao);
4409
4410                 m_vao = 0;
4411         }
4412 }
4413
4414 /** Releases temporary GL objects, created specifically for one test case iteration. */
4415 void QueryBufferStorageTestCase::deinitTestCaseIteration()
4416 {
4417         if (m_sparse_bo != 0)
4418         {
4419                 m_gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bo);
4420                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
4421
4422                 m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0,                                  /* offset */
4423                                                                          m_sparse_bo_size_rounded, GL_FALSE); /* commit */
4424                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
4425
4426                 m_sparse_bo = 0;
4427         }
4428 }
4429
4430 /** Executes a single test iteration. The BufferStorage test will call this method
4431  *  numerously during its life-time, testing various valid flag combinations applied
4432  *  to the tested sparse buffer object at glBufferStorage() call time.
4433  *
4434  *  @param sparse_bo_storage_flags <flags> argument, used by the test in the glBufferStorage()
4435  *                                 call to set up the sparse buffer's storage.
4436  *
4437  *  @return true if the test case executed correctly, false otherwise.
4438  */
4439 bool QueryBufferStorageTestCase::execute(glw::GLuint sparse_bo_storage_flags)
4440 {
4441         (void)sparse_bo_storage_flags;
4442         static const unsigned char data_r8_zero = 0;
4443         bool                                       result               = true;
4444
4445         m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_sparse_bo);
4446         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
4447
4448         m_gl.useProgram(m_po);
4449         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUseProgram() call failed.");
4450
4451         /* Run two separate iterations:
4452          *
4453          * a) The page holding the query result value is committed.
4454          * b) The page is not committed.
4455          */
4456         for (unsigned int n_iteration = 0; n_iteration < 2; ++n_iteration)
4457         {
4458                 const bool should_commit_page = (n_iteration == 0);
4459
4460                 /* Set up the memory page commitment */
4461                 m_gl.bufferPageCommitmentARB(GL_QUERY_BUFFER, 0, /* offset */
4462                                                                          m_sparse_bo_size_rounded, should_commit_page ? GL_TRUE : GL_FALSE);
4463                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
4464
4465                 /* Run the draw call */
4466                 m_gl.beginQuery(GL_PRIMITIVES_GENERATED, m_qo);
4467                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBeginQuery() call failed.");
4468
4469                 m_gl.drawArrays(GL_TRIANGLES, 0, /* first */
4470                                                 m_n_triangles * 3);
4471                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawArrays() call failed.");
4472
4473                 m_gl.endQuery(GL_PRIMITIVES_GENERATED);
4474                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glEndQuery() call failed.");
4475
4476                 /* Copy the query result to the sparse buffer */
4477                 for (unsigned int n_getter_call = 0; n_getter_call < 4; ++n_getter_call)
4478                 {
4479                         glw::GLsizei result_n_bytes;
4480
4481                         switch (n_getter_call)
4482                         {
4483                         case 0:
4484                         {
4485                                 result_n_bytes = sizeof(glw::GLint);
4486                                 m_gl.getQueryObjectiv(m_qo, GL_QUERY_RESULT, (glw::GLint*)0); /* params */
4487                                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGetQueryObjectiv() call failed.");
4488
4489                                 break;
4490                         }
4491
4492                         case 1:
4493                         {
4494                                 result_n_bytes = sizeof(glw::GLint);
4495                                 m_gl.getQueryObjectuiv(m_qo, GL_QUERY_RESULT, (glw::GLuint*)0); /* params */
4496                                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGetQueryObjectuiv() call failed.");
4497
4498                                 break;
4499                         }
4500
4501                         case 2:
4502                         {
4503                                 result_n_bytes = sizeof(glw::GLint64);
4504                                 m_gl.getQueryObjecti64v(m_qo, GL_QUERY_RESULT, (glw::GLint64*)0);
4505                                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGetQueryObjecti64v() call failed.");
4506
4507                                 break;
4508                         }
4509
4510                         case 3:
4511                         {
4512                                 result_n_bytes = sizeof(glw::GLint64);
4513                                 m_gl.getQueryObjectui64v(m_qo, GL_QUERY_RESULT, (glw::GLuint64*)0);
4514                                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGetQueryObjectui64v() call failed.");
4515
4516                                 break;
4517                         }
4518
4519                         default:
4520                         {
4521                                 TCU_FAIL("Invalid getter call type");
4522                         }
4523                         } /* switch (n_getter_call) */
4524
4525                         /* Verify the query result */
4526                         if (should_commit_page)
4527                         {
4528                                 const glw::GLint64* result_ptr = NULL;
4529
4530                                 m_gl.bindBuffer(GL_COPY_WRITE_BUFFER, m_helper_bo);
4531                                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
4532
4533                                 m_gl.clearBufferData(GL_COPY_WRITE_BUFFER, GL_R8, GL_RED, GL_UNSIGNED_BYTE, &data_r8_zero);
4534                                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glClearBufferData() call failed.");
4535
4536                                 m_gl.copyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, /* readOffset */
4537                                                                            0,                                                                                    /* writeOffset */
4538                                                                            result_n_bytes);
4539                                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCopyBufferSubData() call failed.");
4540
4541                                 result_ptr = (const glw::GLint64*)m_gl.mapBuffer(GL_COPY_WRITE_BUFFER, GL_READ_ONLY);
4542                                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glMapBuffer() call failed.");
4543
4544                                 if (*result_ptr != m_n_triangles)
4545                                 {
4546                                         m_testCtx.getLog() << tcu::TestLog::Message
4547                                                                            << "Invalid query result stored in a sparse buffer. Found: "
4548                                                                                   "["
4549                                                                            << *result_ptr << "]"
4550                                                                                                                  ", expected: "
4551                                                                                                                  "["
4552                                                                            << m_n_triangles << "]" << tcu::TestLog::EndMessage;
4553
4554                                         result = false;
4555                                 }
4556
4557                                 m_gl.unmapBuffer(GL_COPY_WRITE_BUFFER);
4558                                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUnmapBuffer() call failed.");
4559                         } /* for (all query getter call types) */
4560                 }        /* if (should_commit_page) */
4561         }                 /* for (both iterations) */
4562
4563         return result;
4564 }
4565
4566 /** Initializes GL objects used across all test case iterations.
4567  *
4568  *  Called once during BufferStorage test run-time.
4569  */
4570 bool QueryBufferStorageTestCase::initTestCaseGlobal()
4571 {
4572         /* Determine sparse buffer storage size */
4573         m_sparse_bo_size                 = sizeof(glw::GLuint64);
4574         m_sparse_bo_size_rounded = SparseBufferTestUtilities::alignOffset(m_sparse_bo_size, m_page_size);
4575
4576         /* Set up the test program object */
4577         static const char* vs_body = "#version 140\n"
4578                                                                  "\n"
4579                                                                  "void main()\n"
4580                                                                  "{\n"
4581                                                                  "    gl_Position = vec4(0.0, 0.0, 0.0, 1.0);\n"
4582                                                                  "}\n";
4583
4584         m_po = SparseBufferTestUtilities::createProgram(m_gl, DE_NULL, /* fs_body_parts */
4585                                                                                                         0,                         /* n_fs_body_parts */
4586                                                                                                         &vs_body, 1,   /* n_vs_body_parts */
4587                                                                                                         DE_NULL,           /* attribute_names */
4588                                                                                                         DE_NULL,           /* attribute_locations */
4589                                                                                                         0);                        /* n_attribute_locations */
4590
4591         if (m_po == 0)
4592         {
4593                 TCU_FAIL("Test program linking failure");
4594         }
4595
4596         /* Set up the helper buffer object */
4597         m_gl.genBuffers(1, &m_helper_bo);
4598         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenBuffers() call failed.");
4599
4600         m_gl.bindBuffer(GL_COPY_WRITE_BUFFER, m_helper_bo);
4601         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
4602
4603         m_gl.bufferStorage(GL_COPY_WRITE_BUFFER, sizeof(glw::GLint64), DE_NULL, /* data */
4604                                            GL_MAP_READ_BIT);
4605         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferStorage() call failed.");
4606
4607         /* Set up the test query object */
4608         m_gl.genQueries(1, &m_qo);
4609         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenQueries() call failed.");
4610
4611         /* Set up the VAO */
4612         m_gl.genVertexArrays(1, &m_vao);
4613         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenVertexArrays() call failed.");
4614
4615         m_gl.bindVertexArray(m_vao);
4616         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindVertexArray() call failed.");
4617
4618         return true;
4619 }
4620
4621 /** Initializes GL objects which are needed for a single test case iteration.
4622  *
4623  *  deinitTestCaseIteration() will be called after the test case is executed in ::execute()
4624  *  to release these objects.
4625  **/
4626 bool QueryBufferStorageTestCase::initTestCaseIteration(glw::GLuint sparse_bo)
4627 {
4628         bool result = true;
4629
4630         /* Cache the BO id, if not cached already */
4631         DE_ASSERT(m_sparse_bo == 0 || m_sparse_bo == sparse_bo);
4632
4633         m_sparse_bo = sparse_bo;
4634
4635         /* Set up the sparse buffer. */
4636         m_gl.bindBuffer(GL_QUERY_BUFFER, m_sparse_bo);
4637         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
4638
4639         return result;
4640 }
4641
4642 /** Constructor.
4643  *
4644  *  @param gl                         GL entry-points container
4645  *  @param testContext                CTS test context
4646  *  @param page_size                  Page size, as reported by implementation for the GL_SPARSE_BUFFER_PAGE_SIZE_ARB query.
4647  *  @param pGLBufferPageCommitmentARB Func ptr to glBufferPageCommitmentARB() entry-point.
4648  */
4649 SSBOStorageTestCase::SSBOStorageTestCase(const glw::Functions& gl, tcu::TestContext& testContext, glw::GLint page_size)
4650         : m_gl(gl)
4651         , m_helper_bo(0)
4652         , m_page_size(page_size)
4653         , m_po(0)
4654         , m_po_local_wg_size(1024)
4655         , m_result_bo(0)
4656         , m_sparse_bo(0)
4657         , m_sparse_bo_size(0)
4658         , m_sparse_bo_size_rounded(0)
4659         , m_ssbo_data(DE_NULL)
4660         , m_testCtx(testContext)
4661 {
4662         /* min max for SSBO size from GL_ARB_shader_storage_buffer_object is 16mb;
4663          *
4664          * The specified amount of space lets the test write as many
4665          * ints as it's possible, with an assertion that our CS
4666          * uses a std140 layout and the SSBO only contains an unsized array.
4667          *
4668          * NOTE: 16777216 % 1024 = 0, which is awesome because we can hardcode the
4669          *       local workgroup size directly in the CS.
4670          */
4671         m_sparse_bo_size                 = (16777216 / (sizeof(int) * 4) /* std140 */) * (sizeof(int) * 4);
4672         m_sparse_bo_size_rounded = SparseBufferTestUtilities::alignOffset(m_sparse_bo_size, m_page_size);
4673 }
4674
4675 /** Releases all GL objects used across all test case iterations.
4676  *
4677  *  Called once during BufferStorage test run-time.
4678  */
4679 void SSBOStorageTestCase::deinitTestCaseGlobal()
4680 {
4681         if (m_helper_bo != 0)
4682         {
4683                 m_gl.deleteBuffers(1, &m_helper_bo);
4684
4685                 m_helper_bo = 0;
4686         }
4687
4688         if (m_po != 0)
4689         {
4690                 m_gl.deleteProgram(m_po);
4691
4692                 m_po = 0;
4693         }
4694
4695         if (m_result_bo != 0)
4696         {
4697                 m_gl.deleteBuffers(1, &m_result_bo);
4698
4699                 m_result_bo = 0;
4700         }
4701
4702         if (m_ssbo_data != DE_NULL)
4703         {
4704                 delete[] m_ssbo_data;
4705
4706                 m_ssbo_data = DE_NULL;
4707         }
4708 }
4709
4710 /** Releases temporary GL objects, created specifically for one test case iteration. */
4711 void SSBOStorageTestCase::deinitTestCaseIteration()
4712 {
4713         if (m_sparse_bo != 0)
4714         {
4715                 m_gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bo);
4716                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
4717
4718                 m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0,                                  /* offset */
4719                                                                          m_sparse_bo_size_rounded, GL_FALSE); /* commit */
4720                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
4721
4722                 m_sparse_bo = 0;
4723         }
4724 }
4725
4726 /** Executes a single test iteration. The BufferStorage test will call this method
4727  *  numerously during its life-time, testing various valid flag combinations applied
4728  *  to the tested sparse buffer object at glBufferStorage() call time.
4729  *
4730  *  @param sparse_bo_storage_flags <flags> argument, used by the test in the glBufferStorage()
4731  *                                 call to set up the sparse buffer's storage.
4732  *
4733  *  @return true if the test case executed correctly, false otherwise.
4734  */
4735 bool SSBOStorageTestCase::execute(glw::GLuint sparse_bo_storage_flags)
4736 {
4737         (void)sparse_bo_storage_flags;
4738         bool result = true;
4739
4740         /* Bind the program object */
4741         m_gl.useProgram(m_po);
4742         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUseProgram() call failed.");
4743
4744         /* Set up shader storage buffer bindings */
4745         m_gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, m_sparse_bo);
4746         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
4747
4748         m_gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, /* index */
4749                                                 m_sparse_bo);
4750         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBufferBase() call failed.");
4751
4752         /* Run the test in three iterations:
4753          *
4754          * a) All required pages are committed.
4755          * b) Only half of the pages are committed (in a zig-zag layout)
4756          * c) None of the pages are committed.
4757          */
4758         for (unsigned int n_iteration = 0; n_iteration < 3; ++n_iteration)
4759         {
4760                 bool result_local = true;
4761
4762                 /* Set up the shader storage buffer object's memory backing */
4763                 const bool   is_zigzag_ssbo                       = (n_iteration == 1);
4764                 unsigned int ssbo_commit_size             = 0;
4765                 unsigned int ssbo_commit_start_offset = 0;
4766
4767                 switch (n_iteration)
4768                 {
4769                 case 0:
4770                 case 1:
4771                 {
4772                         ssbo_commit_size                 = m_sparse_bo_size_rounded;
4773                         ssbo_commit_start_offset = 0;
4774
4775                         if (is_zigzag_ssbo)
4776                         {
4777                                 const unsigned int n_pages = ssbo_commit_size / m_page_size;
4778
4779                                 for (unsigned int n_page = 0; n_page < n_pages; n_page += 2)
4780                                 {
4781                                         m_gl.bufferPageCommitmentARB(GL_SHADER_STORAGE_BUFFER, m_page_size * n_page, /* offset */
4782                                                                                                  m_page_size,                                                                    /* size */
4783                                                                                                  GL_TRUE);                                                                               /* commit */
4784                                 } /* for (all memory pages) */
4785                         }
4786                         else
4787                         {
4788                                 m_gl.bufferPageCommitmentARB(GL_SHADER_STORAGE_BUFFER, 0, /* offset */
4789                                                                                          ssbo_commit_size, GL_TRUE);  /* commit */
4790                         }
4791
4792                         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call(s) failed.");
4793
4794                         break;
4795                 }
4796
4797                 case 2:
4798                 {
4799                         /* Use no physical memory backing */
4800                         break;
4801                 }
4802
4803                 default:
4804                 {
4805                         TCU_FAIL("Unrecognized iteration index");
4806                 }
4807                 } /* switch (n_iteration) */
4808
4809                 /* Set up bindings for the copy op */
4810                 m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_helper_bo);
4811                 m_gl.bindBuffer(GL_COPY_WRITE_BUFFER, m_sparse_bo);
4812                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call(s) failed.");
4813
4814                 /* Set up the sparse buffer's data storage */
4815                 m_gl.copyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, /* readOffset */
4816                                                            0,                                                                                    /* writeOffset */
4817                                                            m_sparse_bo_size);
4818                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCopyBufferSubData() call failed.");
4819
4820                 /* Run the compute program */
4821                 DE_ASSERT((m_sparse_bo_size % m_po_local_wg_size) == 0);
4822
4823                 m_gl.dispatchCompute(m_sparse_bo_size / m_po_local_wg_size, 1, /* num_groups_y */
4824                                                          1);                                                                       /* num_groups_z */
4825                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDispatchCompute() call failed.");
4826
4827                 /* Flush the caches */
4828                 m_gl.memoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
4829                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glMemoryBarrier() call failed.");
4830
4831                 /* Copy SSBO's storage to a mappable result BO */
4832                 m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_sparse_bo);
4833                 m_gl.bindBuffer(GL_COPY_WRITE_BUFFER, m_result_bo);
4834                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call(s) failed.");
4835
4836                 m_gl.copyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, /* readOffset */
4837                                                            0,                                                                                    /* writeOffset */
4838                                                            m_sparse_bo_size);
4839                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCopyBufferSubData() call failed.");
4840
4841                 /* Map the result BO to the process space */
4842                 unsigned int            current_ssbo_offset = 0;
4843                 const unsigned int* ssbo_data_ptr = (const unsigned int*)m_gl.mapBuffer(GL_COPY_WRITE_BUFFER, GL_READ_ONLY);
4844
4845                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glMapBuffer() call failed.");
4846
4847                 for (unsigned int n_invocation = 0; current_ssbo_offset < m_sparse_bo_size && result_local; ++n_invocation,
4848                                                   current_ssbo_offset = static_cast<unsigned int>(current_ssbo_offset +
4849                                                                                                                                                   (sizeof(int) * 4 /* std140 */)))
4850                 {
4851                         const unsigned int n_page = current_ssbo_offset / m_page_size;
4852
4853                         if ((is_zigzag_ssbo && (n_page % 2) == 0) ||
4854                                 (!is_zigzag_ssbo && (current_ssbo_offset >= ssbo_commit_start_offset &&
4855                                                                          current_ssbo_offset < (ssbo_commit_start_offset + ssbo_commit_size))))
4856                         {
4857                                 if (ssbo_data_ptr[n_invocation * 4] != (n_invocation + 1))
4858                                 {
4859                                         m_testCtx.getLog() << tcu::TestLog::Message << "Value written to the SSBO at byte "
4860                                                                                                                                    "["
4861                                                                            << (sizeof(int) * n_invocation) << "]"
4862                                                                                                                                                   " is invalid. Found:"
4863                                                                            << "[" << ssbo_data_ptr[n_invocation * 4] << "]"
4864                                                                                                                                                                         ", expected:"
4865                                                                            << "[" << (n_invocation + 1) << "]" << tcu::TestLog::EndMessage;
4866
4867                                         result_local = false;
4868                                 }
4869                         } /* if (ssbo_data_ptr[n_texel] != 1) */
4870                 }        /* for (all result values) */
4871
4872                 result &= result_local;
4873
4874                 m_gl.unmapBuffer(GL_COPY_WRITE_BUFFER);
4875                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUnmapBuffer() call failed.");
4876
4877                 /* Remove the physical backing from the sparse buffer  */
4878                 m_gl.bufferPageCommitmentARB(GL_SHADER_STORAGE_BUFFER, 0,                 /* offset */
4879                                                                          m_sparse_bo_size_rounded, GL_FALSE); /* commit */
4880
4881                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
4882         } /* for (three iterations) */
4883
4884         return result;
4885 }
4886
4887 /** Initializes GL objects used across all test case iterations.
4888  *
4889  *  Called once during BufferStorage test run-time.
4890  */
4891 bool SSBOStorageTestCase::initTestCaseGlobal()
4892 {
4893         /* Set up the test program */
4894         static const char* cs_body =
4895                 "#version 430 core\n"
4896                 "\n"
4897                 "layout(local_size_x = 1024) in;\n"
4898                 "\n"
4899                 "layout(std140, binding = 0) buffer data\n"
4900                 "{\n"
4901                 "    restrict uint io_values[];\n"
4902                 "};\n"
4903                 "\n"
4904                 "void main()\n"
4905                 "{\n"
4906                 "    uint value_index = gl_GlobalInvocationID.x;\n"
4907                 "    uint new_value   = (io_values[value_index] == value_index) ? (value_index + 1u) : value_index;\n"
4908                 "\n"
4909                 "    io_values[value_index] = new_value;\n"
4910                 "}\n";
4911
4912         m_po = SparseBufferTestUtilities::createComputeProgram(m_gl, &cs_body, 1); /* n_cs_body_parts */
4913
4914         /* Set up a data buffer we will use to initialize the SSBO with default data.
4915          *
4916          * CS uses a std140 layout for the SSBO, so we need to add the additional padding.
4917          */
4918         DE_ASSERT((m_sparse_bo_size) != 0);
4919         DE_ASSERT((m_sparse_bo_size % (sizeof(int) * 4)) == 0);
4920         DE_ASSERT((m_sparse_bo_size % 1024) == 0);
4921
4922         m_ssbo_data = new unsigned int[m_sparse_bo_size / sizeof(int)];
4923
4924         memset(m_ssbo_data, 0, m_sparse_bo_size);
4925
4926         for (unsigned int index = 0; index < m_sparse_bo_size / sizeof(int) / 4; ++index)
4927         {
4928                 /* Mind the std140 rules for arrays of ints */
4929                 m_ssbo_data[4 * index] = index;
4930         }
4931
4932         /* During execution, we will need to use a helper buffer object. The BO will hold
4933          * data we will be copying into the sparse buffer object for each iteration.
4934          */
4935         m_gl.genBuffers(1, &m_helper_bo);
4936         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenBuffers() call failed.");
4937
4938         m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_helper_bo);
4939         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
4940
4941         m_gl.bufferData(GL_COPY_READ_BUFFER, m_sparse_bo_size, m_ssbo_data, GL_STATIC_DRAW);
4942         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferData() call failed.");
4943
4944         /* To retrieve the data written to a sparse SSBO, we need to use another
4945          * non-sparse helper BO.
4946          */
4947         m_gl.genBuffers(1, &m_result_bo);
4948         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenBuffers() call failed.");
4949
4950         m_gl.bindBuffer(GL_ARRAY_BUFFER, m_result_bo);
4951         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
4952
4953         m_gl.bufferData(GL_ARRAY_BUFFER, m_sparse_bo_size, DE_NULL, /* data */
4954                                         GL_STATIC_DRAW);
4955         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferData() call failed.");
4956
4957         return true;
4958 }
4959
4960 /** Initializes GL objects which are needed for a single test case iteration.
4961  *
4962  *  deinitTestCaseIteration() will be called after the test case is executed in ::execute()
4963  *  to release these objects.
4964  **/
4965 bool SSBOStorageTestCase::initTestCaseIteration(glw::GLuint sparse_bo)
4966 {
4967         bool result = true;
4968
4969         /* Cache the BO id, if not cached already */
4970         DE_ASSERT(m_sparse_bo == 0 || m_sparse_bo == sparse_bo);
4971
4972         m_sparse_bo = sparse_bo;
4973
4974         return result;
4975 }
4976
4977 /** Constructor.
4978  *
4979  *  @param gl                         GL entry-points container
4980  *  @param testContext                CTS test context
4981  *  @param page_size                  Page size, as reported by implementation for the GL_SPARSE_BUFFER_PAGE_SIZE_ARB query.
4982  *  @param pGLBufferPageCommitmentARB Func ptr to glBufferPageCommitmentARB() entry-point.
4983  *  @param all_pages_committed        true to provide memory backing for all memory pages holding data used by the test.
4984  *                                    false to leave some of them uncommitted.
4985  */
4986 TransformFeedbackBufferStorageTestCase::TransformFeedbackBufferStorageTestCase(const glw::Functions& gl,
4987                                                                                                                                                            tcu::TestContext&     testContext,
4988                                                                                                                                                            glw::GLint                    page_size,
4989                                                                                                                                                            bool all_pages_committed)
4990         : m_all_pages_committed(all_pages_committed)
4991         , m_data_bo(0)
4992         , m_data_bo_index_data_offset(0)
4993         , m_data_bo_indexed_indirect_arg_offset(0)
4994         , m_data_bo_indexed_mdi_arg_offset(0)
4995         , m_data_bo_regular_indirect_arg_offset(0)
4996         , m_data_bo_regular_mdi_arg_offset(0)
4997         , m_data_bo_size(0)
4998         , m_draw_call_baseInstance(1231)
4999         , m_draw_call_baseVertex(65537)
5000         , m_draw_call_first(913)
5001         , m_draw_call_firstIndex(4)
5002         , m_gl(gl)
5003         , m_helper_bo(0)
5004         , m_index_data(DE_NULL)
5005         , m_index_data_size(0)
5006         , m_indirect_arg_data(DE_NULL)
5007         , m_indirect_arg_data_size(0)
5008         , m_min_memory_page_span(4) /* as per test spec */
5009         , m_multidrawcall_drawcount(-1)
5010         , m_multidrawcall_primcount(-1)
5011         , m_n_instances_to_test(4)
5012         , m_n_vertices_per_instance(0)
5013         , m_page_size(page_size)
5014         , m_po_ia(0)
5015         , m_po_sa(0)
5016         , m_result_bo(0)
5017         , m_result_bo_size(0)
5018         , m_result_bo_size_rounded(0)
5019         , m_testCtx(testContext)
5020         , m_vao(0)
5021 {
5022         /* Left blank on purpose */
5023 }
5024
5025 /** Releases all GL objects used across all test case iterations.
5026  *
5027  *  Called once during BufferStorage test run-time.
5028  */
5029 void TransformFeedbackBufferStorageTestCase::deinitTestCaseGlobal()
5030 {
5031         if (m_data_bo != 0)
5032         {
5033                 m_gl.deleteBuffers(1, &m_data_bo);
5034
5035                 m_data_bo = 0;
5036         }
5037
5038         if (m_helper_bo != 0)
5039         {
5040                 m_gl.deleteBuffers(1, &m_helper_bo);
5041
5042                 m_helper_bo = 0;
5043         }
5044
5045         if (m_index_data != DE_NULL)
5046         {
5047                 delete[] m_index_data;
5048
5049                 m_index_data = DE_NULL;
5050         }
5051
5052         if (m_indirect_arg_data != DE_NULL)
5053         {
5054                 delete[] m_indirect_arg_data;
5055
5056                 m_indirect_arg_data = DE_NULL;
5057         }
5058
5059         if (m_po_ia != 0)
5060         {
5061                 m_gl.deleteProgram(m_po_ia);
5062
5063                 m_po_ia = 0;
5064         }
5065
5066         if (m_po_sa != 0)
5067         {
5068                 m_gl.deleteProgram(m_po_sa);
5069
5070                 m_po_sa = 0;
5071         }
5072
5073         if (m_result_bo != 0)
5074         {
5075                 m_gl.deleteBuffers(1, &m_result_bo);
5076
5077                 m_result_bo = 0;
5078         }
5079
5080         if (m_vao != 0)
5081         {
5082                 m_gl.deleteVertexArrays(1, &m_vao);
5083
5084                 m_vao = 0;
5085         }
5086 }
5087
5088 /** Executes a single test iteration. The BufferStorage test will call this method
5089  *  numerously during its life-time, testing various valid flag combinations applied
5090  *  to the tested sparse buffer object at glBufferStorage() call time.
5091  *
5092  *  @param sparse_bo_storage_flags <flags> argument, used by the test in the glBufferStorage()
5093  *                                 call to set up the sparse buffer's storage.
5094  *
5095  *  @return true if the test case executed correctly, false otherwise.
5096  */
5097 bool TransformFeedbackBufferStorageTestCase::execute(glw::GLuint sparse_bo_storage_flags)
5098 {
5099         bool result = true;
5100
5101         /* Iterate through two different transform feedback modes we need to test */
5102         for (unsigned int n_tf_type = 0; n_tf_type < 2; /* interleaved & separate attribs */
5103                  ++n_tf_type)
5104         {
5105                 const bool is_ia_iteration = (n_tf_type == 0);
5106
5107                 /* Bind the test PO to the context */
5108                 m_gl.useProgram(is_ia_iteration ? m_po_ia : m_po_sa);
5109                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUseProgram() call failed.");
5110
5111                 /* Set up TF general binding, which is needed for a glClearBufferData() call
5112                  * we'll be firing shortly.
5113                  */
5114                 m_gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, /* needed for the subsequent glClearBufferData() call */
5115                                                 m_result_bo);
5116                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
5117
5118                 /* Iterate through all draw call types */
5119                 for (unsigned int n_draw_call_type = 0; n_draw_call_type < DRAW_CALL_COUNT; ++n_draw_call_type)
5120                 {
5121                         int                                draw_call_count                                      = 0; /* != 1 for multi-draw calls only */
5122                         int                                draw_call_first_instance_id[2]   = { -1 };
5123                         int                                draw_call_first_vertex_id[2]         = { -1 };
5124                         int                                draw_call_n_instances[2]                     = { 0 };
5125                         int                                draw_call_n_vertices[2]                      = { 0 };
5126                         bool                       draw_call_is_vertex_id_ascending = false;
5127                         const _draw_call   draw_call_type                                       = (_draw_call)n_draw_call_type;
5128                         unsigned int       n_result_bytes_per_instance[2]   = { 0 };
5129                         const unsigned int n_result_bytes_per_vertex            = sizeof(unsigned int) * 2;
5130                         unsigned int       n_result_bytes_total                         = 0;
5131                         glw::GLuint*       result_ptr                                           = DE_NULL;
5132
5133                         m_gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_data_bo);
5134                         m_gl.bindBuffer(GL_DRAW_INDIRECT_BUFFER, m_data_bo);
5135                         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call(s) failed.");
5136
5137                         /* Commit pages needed to execute transform feed-back */
5138                         if (m_all_pages_committed)
5139                         {
5140                                 m_gl.bufferPageCommitmentARB(GL_TRANSFORM_FEEDBACK_BUFFER, 0,   /* offset */
5141                                                                                          m_result_bo_size_rounded, GL_TRUE); /* commit */
5142                                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
5143                         }
5144                         else
5145                         {
5146                                 for (unsigned int n_page = 0; n_page < m_result_bo_size_rounded / m_page_size; ++n_page)
5147                                 {
5148                                         m_gl.bufferPageCommitmentARB(GL_TRANSFORM_FEEDBACK_BUFFER, n_page * m_page_size, /* offset */
5149                                                                                                  m_page_size,                                                                            /* size   */
5150                                                                                                  (n_page % 2 == 0) ? GL_TRUE : GL_FALSE);                        /* commit */
5151                                 }
5152
5153                                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
5154                         }
5155
5156                         /* Zero out the target BO before we begin the TF */
5157                         static const unsigned char data_zero = 0;
5158
5159                         m_gl.clearBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, GL_R8, GL_RED, GL_UNSIGNED_BYTE, &data_zero);
5160                         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glClearBufferData() call failed.");
5161
5162                         /* Set up transform feed-back buffer bindings */
5163                         DE_ASSERT(m_result_bo_size != 0);
5164
5165                         if (is_ia_iteration)
5166                         {
5167                                 DE_ASSERT(m_result_bo != 0);
5168
5169                                 m_gl.bindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, /* index */
5170                                                                          m_result_bo, 0,                                  /* offset */
5171                                                                          m_result_bo_size);
5172
5173                                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBufferRange() call failed.");
5174                         }
5175                         else
5176                         {
5177                                 DE_ASSERT(m_result_bo_size % 2 == 0);
5178
5179                                 m_gl.bindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, /* index */
5180                                                                          m_result_bo, 0,                                  /* offset */
5181                                                                          m_result_bo_size / 2);
5182                                 m_gl.bindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 1, /* index */
5183                                                                          m_result_bo, m_result_bo_size / 2, m_result_bo_size / 2);
5184                                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBufferRange() call(s) failed.");
5185                         }
5186
5187                         m_gl.beginTransformFeedback(GL_POINTS);
5188                         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBeginTransformFeedback() call failed.");
5189
5190                         /* NOTE: Some discussion about the expected "vertex id" value:
5191                          *
5192                          * In GL 4.5 core spec (Feb2/2015 version), we have:
5193                          *
5194                          * >>
5195                          * The index of any element transferred to the GL by DrawElementsOneInstance
5196                          * is referred to as its vertex ID, and may be read by a vertex shader as
5197                          * gl_VertexID. The vertex ID of the ith element transferred is the sum of
5198                          * basevertex and the value stored in the currently bound element array buffer at
5199                          * offset indices +i.
5200                          * <<
5201                          *
5202                          * So for glDrawElements*() derivatives, we will be expecting gl_VertexID to be set to
5203                          * (basevertex + index[i] + i)
5204                          *
5205                          * DrawArrays does not support the "base vertex" concept at all:
5206                          *
5207                          * >>
5208                          * The index of any element transferred to the GL by DrawArraysOneInstance
5209                          * is referred to as its vertex ID, and may be read by a vertex shader as gl_VertexID.
5210                          * The vertex ID of the ith element transferred is first + i.
5211                          * <<
5212                          *
5213                          * For regular draw calls, gl_VertexID should be of form:
5214                          *
5215                          * (first + i)
5216                          *
5217                          * In both cases, gl_InstanceID does NOT include the baseinstance value, as per:
5218                          *
5219                          * >>
5220                          * If an enabled vertex attribute array is instanced (it has a non-zero divisor as
5221                          * specified by VertexAttribDivisor), the element index that is transferred to the GL,
5222                          * for all vertices, is given by
5223                          *
5224                          * floor(instance / divisor) + baseinstance
5225                          *
5226                          * The value of instance may be read by a vertex shader as gl_InstanceID, as
5227                          * described in section 11.1.3.9
5228                          * <<
5229                          */
5230                         switch (draw_call_type)
5231                         {
5232                         case DRAW_CALL_INDEXED:
5233                         {
5234                                 m_gl.drawElements(GL_POINTS, m_n_vertices_per_instance, GL_UNSIGNED_INT,
5235                                                                   (const glw::GLvoid*)(intptr_t)m_data_bo_index_data_offset);
5236                                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawElements() call failed.");
5237
5238                                 draw_call_count                                  = 1;
5239                                 draw_call_first_instance_id[0]   = 0;
5240                                 draw_call_first_vertex_id[0]     = m_n_vertices_per_instance;
5241                                 draw_call_is_vertex_id_ascending = false;
5242                                 draw_call_n_instances[0]                 = 1;
5243                                 draw_call_n_vertices[0]                  = m_n_vertices_per_instance;
5244                                 n_result_bytes_per_instance[0]   = n_result_bytes_per_vertex * m_n_vertices_per_instance;
5245                                 n_result_bytes_total                     = n_result_bytes_per_instance[0] * draw_call_n_instances[0];
5246
5247                                 break;
5248                         }
5249
5250                         case DRAW_CALL_INDEXED_BASE_VERTEX:
5251                         {
5252                                 m_gl.drawElementsBaseVertex(GL_POINTS, m_n_vertices_per_instance, GL_UNSIGNED_INT,
5253                                                                                         (const glw::GLvoid*)(intptr_t)m_data_bo_index_data_offset,
5254                                                                                         m_draw_call_baseVertex);
5255                                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawElementsBaseVertex() call failed.");
5256
5257                                 draw_call_count                                  = 1;
5258                                 draw_call_first_instance_id[0]   = 0;
5259                                 draw_call_first_vertex_id[0]     = m_draw_call_baseVertex + m_n_vertices_per_instance;
5260                                 draw_call_is_vertex_id_ascending = false;
5261                                 draw_call_n_instances[0]                 = 1;
5262                                 draw_call_n_vertices[0]                  = m_n_vertices_per_instance;
5263                                 n_result_bytes_per_instance[0]   = n_result_bytes_per_vertex * m_n_vertices_per_instance;
5264                                 n_result_bytes_total                     = n_result_bytes_per_instance[0] * draw_call_n_instances[0];
5265
5266                                 break;
5267                         }
5268
5269                         case DRAW_CALL_INDEXED_INDIRECT:
5270                         {
5271                                 m_gl.drawElementsIndirect(GL_POINTS, GL_UNSIGNED_INT,
5272                                                                                   (const glw::GLvoid*)(intptr_t)m_data_bo_indexed_indirect_arg_offset);
5273                                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawElementsIndirect() call failed.");
5274
5275                                 draw_call_count                            = 1;
5276                                 draw_call_first_instance_id[0] = 0;
5277                                 draw_call_first_vertex_id[0] =
5278                                         m_draw_call_baseVertex +
5279                                         m_index_data[((unsigned int)(intptr_t)m_multidrawcall_index[1] - m_data_bo_index_data_offset) /
5280                                                                  sizeof(unsigned int)];
5281                                 draw_call_is_vertex_id_ascending = false;
5282                                 draw_call_n_instances[0]                 = m_n_instances_to_test;
5283                                 draw_call_n_vertices[0]                  = m_multidrawcall_count[1];
5284                                 n_result_bytes_per_instance[0]   = n_result_bytes_per_vertex * draw_call_n_vertices[0];
5285                                 n_result_bytes_total                     = n_result_bytes_per_instance[0] * draw_call_n_instances[0];
5286
5287                                 break;
5288                         }
5289
5290                         case DRAW_CALL_INDEXED_INDIRECT_MULTI:
5291                         {
5292                                 m_gl.multiDrawElementsIndirect(GL_POINTS, GL_UNSIGNED_INT,
5293                                                                                            (const glw::GLvoid*)(intptr_t)m_data_bo_indexed_mdi_arg_offset,
5294                                                                                            m_multidrawcall_drawcount, 0); /* stride */
5295                                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glMultiDrawElementsIndirect() call failed.");
5296
5297                                 draw_call_count                            = m_multidrawcall_drawcount;
5298                                 draw_call_first_instance_id[0] = 0;
5299                                 draw_call_first_instance_id[1] = 0;
5300                                 draw_call_first_vertex_id[0] =
5301                                         m_draw_call_baseVertex +
5302                                         m_index_data[((unsigned int)(intptr_t)m_multidrawcall_index[0] - m_data_bo_index_data_offset) /
5303                                                                  sizeof(unsigned int)];
5304                                 draw_call_first_vertex_id[1] =
5305                                         m_draw_call_baseVertex +
5306                                         m_index_data[((unsigned int)(intptr_t)m_multidrawcall_index[1] - m_data_bo_index_data_offset) /
5307                                                                  sizeof(unsigned int)];
5308                                 draw_call_is_vertex_id_ascending = false;
5309                                 draw_call_n_instances[0]                 = 1;
5310                                 draw_call_n_instances[1]                 = m_n_instances_to_test;
5311                                 draw_call_n_vertices[0]                  = m_multidrawcall_count[0];
5312                                 draw_call_n_vertices[1]                  = m_multidrawcall_count[1];
5313                                 n_result_bytes_per_instance[0]   = n_result_bytes_per_vertex * draw_call_n_vertices[0];
5314                                 n_result_bytes_per_instance[1]   = n_result_bytes_per_vertex * draw_call_n_vertices[1];
5315                                 n_result_bytes_total                     = n_result_bytes_per_instance[0] * draw_call_n_instances[0] +
5316                                                                            n_result_bytes_per_instance[1] * draw_call_n_instances[1];
5317
5318                                 break;
5319                         }
5320
5321                         case DRAW_CALL_INDEXED_MULTI:
5322                         {
5323                                 m_gl.multiDrawElements(GL_POINTS, m_multidrawcall_count, GL_UNSIGNED_INT, m_multidrawcall_index,
5324                                                                            m_multidrawcall_drawcount);
5325                                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glMultiDrawElements() call failed");
5326
5327                                 draw_call_count                            = m_multidrawcall_drawcount;
5328                                 draw_call_first_instance_id[0] = 0;
5329                                 draw_call_first_instance_id[1] = 0;
5330                                 draw_call_first_vertex_id[0] =
5331                                         m_index_data[((unsigned int)(intptr_t)m_multidrawcall_index[0] - m_data_bo_index_data_offset) /
5332                                                                  sizeof(unsigned int)];
5333                                 draw_call_first_vertex_id[1] =
5334                                         m_index_data[((unsigned int)(intptr_t)m_multidrawcall_index[1] - m_data_bo_index_data_offset) /
5335                                                                  sizeof(unsigned int)];
5336                                 draw_call_is_vertex_id_ascending = false;
5337                                 draw_call_n_instances[0]                 = 1;
5338                                 draw_call_n_instances[1]                 = 1;
5339                                 draw_call_n_vertices[0]                  = m_multidrawcall_count[0];
5340                                 draw_call_n_vertices[1]                  = m_multidrawcall_count[1];
5341                                 n_result_bytes_per_instance[0]   = n_result_bytes_per_vertex * m_multidrawcall_count[0];
5342                                 n_result_bytes_per_instance[1]   = n_result_bytes_per_vertex * m_multidrawcall_count[1];
5343                                 n_result_bytes_total                     = n_result_bytes_per_instance[0] * draw_call_n_instances[0] +
5344                                                                            n_result_bytes_per_instance[1] * draw_call_n_instances[1];
5345
5346                                 break;
5347                         }
5348
5349                         case DRAW_CALL_INDEXED_MULTI_BASE_VERTEX:
5350                         {
5351                                 m_gl.multiDrawElementsBaseVertex(GL_POINTS, m_multidrawcall_count, GL_UNSIGNED_INT,
5352                                                                                                  m_multidrawcall_index, m_multidrawcall_drawcount,
5353                                                                                                  m_multidrawcall_basevertex);
5354                                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glMultiDrawElementsBaseVertex() call failed.");
5355
5356                                 draw_call_count                            = m_multidrawcall_drawcount;
5357                                 draw_call_first_instance_id[0] = 0;
5358                                 draw_call_first_instance_id[1] = 0;
5359                                 draw_call_first_vertex_id[0] =
5360                                         m_multidrawcall_basevertex[0] +
5361                                         m_index_data[((unsigned int)(intptr_t)m_multidrawcall_index[0] - m_data_bo_index_data_offset) /
5362                                                                  sizeof(unsigned int)];
5363                                 draw_call_first_vertex_id[1] =
5364                                         m_multidrawcall_basevertex[1] +
5365                                         m_index_data[((unsigned int)(intptr_t)m_multidrawcall_index[1] - m_data_bo_index_data_offset) /
5366                                                                  sizeof(unsigned int)];
5367                                 draw_call_is_vertex_id_ascending = false;
5368                                 draw_call_n_instances[0]                 = 1;
5369                                 draw_call_n_instances[1]                 = 1;
5370                                 draw_call_n_vertices[0]                  = m_multidrawcall_count[0];
5371                                 draw_call_n_vertices[1]                  = m_multidrawcall_count[1];
5372                                 n_result_bytes_per_instance[0]   = n_result_bytes_per_vertex * m_multidrawcall_count[0];
5373                                 n_result_bytes_per_instance[1]   = n_result_bytes_per_vertex * m_multidrawcall_count[1];
5374                                 n_result_bytes_total                     = n_result_bytes_per_instance[0] * draw_call_n_instances[0] +
5375                                                                            n_result_bytes_per_instance[1] * draw_call_n_instances[1];
5376
5377                                 break;
5378                         }
5379
5380                         case DRAW_CALL_INSTANCED_INDEXED:
5381                         {
5382                                 m_gl.drawElementsInstanced(GL_POINTS, m_n_vertices_per_instance, GL_UNSIGNED_INT,
5383                                                                                    (const glw::GLvoid*)(intptr_t)m_data_bo_index_data_offset,
5384                                                                                    m_n_instances_to_test);
5385                                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawElementsInstanced() call failed.");
5386
5387                                 draw_call_count                                  = 1;
5388                                 draw_call_first_instance_id[0]   = 0;
5389                                 draw_call_first_vertex_id[0]     = m_index_data[0];
5390                                 draw_call_is_vertex_id_ascending = false;
5391                                 draw_call_n_instances[0]                 = m_n_instances_to_test;
5392                                 draw_call_n_vertices[0]                  = m_n_vertices_per_instance;
5393                                 n_result_bytes_per_instance[0]   = n_result_bytes_per_vertex * m_n_vertices_per_instance;
5394                                 n_result_bytes_total                     = n_result_bytes_per_instance[0] * draw_call_n_instances[0];
5395
5396                                 break;
5397                         }
5398
5399                         case DRAW_CALL_INSTANCED_INDEXED_BASE_VERTEX:
5400                         {
5401                                 m_gl.drawElementsInstancedBaseVertex(GL_POINTS, m_n_vertices_per_instance, GL_UNSIGNED_INT,
5402                                                                                                          (const glw::GLvoid*)(intptr_t)m_data_bo_index_data_offset,
5403                                                                                                          m_n_instances_to_test, m_draw_call_baseVertex);
5404                                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawElementsInstancedBaseVertex() call failed.");
5405
5406                                 draw_call_count                                  = 1;
5407                                 draw_call_first_instance_id[0]   = 0;
5408                                 draw_call_first_vertex_id[0]     = m_draw_call_baseVertex + m_index_data[0];
5409                                 draw_call_is_vertex_id_ascending = false;
5410                                 draw_call_n_instances[0]                 = m_n_instances_to_test;
5411                                 draw_call_n_vertices[0]                  = m_n_vertices_per_instance;
5412                                 n_result_bytes_per_instance[0]   = n_result_bytes_per_vertex * m_n_vertices_per_instance;
5413                                 n_result_bytes_total                     = n_result_bytes_per_instance[0] * draw_call_n_instances[0];
5414
5415                                 break;
5416                         }
5417
5418                         case DRAW_CALL_INSTANCED_INDEXED_BASE_VERTEX_BASE_INSTANCE:
5419                         {
5420                                 m_gl.drawElementsInstancedBaseVertexBaseInstance(
5421                                         GL_POINTS, m_n_vertices_per_instance, GL_UNSIGNED_INT,
5422                                         (const glw::GLvoid*)(intptr_t)m_data_bo_index_data_offset, m_n_instances_to_test,
5423                                         m_draw_call_baseVertex, m_draw_call_baseInstance);
5424
5425                                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawElementsInstancedBaseVertexBaseInstance() call failed.");
5426
5427                                 draw_call_count                                  = 1;
5428                                 draw_call_first_instance_id[0]   = 0;
5429                                 draw_call_first_vertex_id[0]     = m_draw_call_baseVertex + m_index_data[0];
5430                                 draw_call_is_vertex_id_ascending = false;
5431                                 draw_call_n_instances[0]                 = m_n_instances_to_test;
5432                                 draw_call_n_vertices[0]                  = m_n_vertices_per_instance;
5433                                 n_result_bytes_per_instance[0]   = n_result_bytes_per_vertex * m_n_vertices_per_instance;
5434                                 n_result_bytes_total                     = n_result_bytes_per_instance[0] * draw_call_n_instances[0];
5435
5436                                 break;
5437                         }
5438
5439                         case DRAW_CALL_REGULAR:
5440                         {
5441                                 m_gl.drawArrays(GL_POINTS, m_draw_call_first, m_n_vertices_per_instance);
5442
5443                                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawArrays() call failed");
5444
5445                                 draw_call_count                                  = 1;
5446                                 draw_call_first_instance_id[0]   = 0;
5447                                 draw_call_first_vertex_id[0]     = m_draw_call_first;
5448                                 draw_call_is_vertex_id_ascending = true;
5449                                 draw_call_n_instances[0]                 = 1;
5450                                 draw_call_n_vertices[0]                  = m_n_vertices_per_instance;
5451                                 n_result_bytes_per_instance[0]   = n_result_bytes_per_vertex * m_n_vertices_per_instance;
5452                                 n_result_bytes_total                     = n_result_bytes_per_instance[0] * draw_call_n_instances[0];
5453
5454                                 break;
5455                         }
5456
5457                         case DRAW_CALL_REGULAR_INDIRECT:
5458                         {
5459                                 m_gl.drawArraysIndirect(GL_POINTS, (glw::GLvoid*)(intptr_t)m_data_bo_regular_indirect_arg_offset);
5460
5461                                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawArraysIndirect() call failed.");
5462
5463                                 draw_call_count                                  = 1;
5464                                 draw_call_first_instance_id[0]   = 0;
5465                                 draw_call_first_vertex_id[0]     = m_draw_call_first;
5466                                 draw_call_is_vertex_id_ascending = true;
5467                                 draw_call_n_instances[0]                 = m_n_instances_to_test;
5468                                 draw_call_n_vertices[0]                  = m_multidrawcall_count[1];
5469                                 n_result_bytes_per_instance[0]   = n_result_bytes_per_vertex * draw_call_n_vertices[0];
5470                                 n_result_bytes_total                     = n_result_bytes_per_instance[0] * draw_call_n_instances[0];
5471
5472                                 break;
5473                         }
5474
5475                         case DRAW_CALL_REGULAR_INDIRECT_MULTI:
5476                         {
5477                                 m_gl.multiDrawArraysIndirect(GL_POINTS, (glw::GLvoid*)(intptr_t)m_data_bo_regular_mdi_arg_offset,
5478                                                                                          m_multidrawcall_drawcount, 0); /* stride */
5479
5480                                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glMultiDrawArraysIndirect() call failed.");
5481
5482                                 draw_call_count                                  = 2;
5483                                 draw_call_first_instance_id[0]   = 0;
5484                                 draw_call_first_instance_id[1]   = 0;
5485                                 draw_call_first_vertex_id[0]     = m_draw_call_first;
5486                                 draw_call_first_vertex_id[1]     = m_draw_call_first;
5487                                 draw_call_is_vertex_id_ascending = true;
5488                                 draw_call_n_instances[0]                 = 1;
5489                                 draw_call_n_instances[1]                 = m_n_instances_to_test;
5490                                 draw_call_n_vertices[0]                  = m_multidrawcall_count[0];
5491                                 draw_call_n_vertices[1]                  = m_multidrawcall_count[1];
5492                                 n_result_bytes_per_instance[0]   = n_result_bytes_per_vertex * draw_call_n_vertices[0];
5493                                 n_result_bytes_per_instance[1]   = n_result_bytes_per_vertex * draw_call_n_vertices[1];
5494                                 n_result_bytes_total                     = n_result_bytes_per_instance[0] * draw_call_n_instances[0] +
5495                                                                            n_result_bytes_per_instance[1] * draw_call_n_instances[1];
5496
5497                                 break;
5498                         }
5499
5500                         case DRAW_CALL_REGULAR_INSTANCED:
5501                         {
5502                                 m_gl.drawArraysInstanced(GL_POINTS, m_draw_call_first, m_n_vertices_per_instance,
5503                                                                                  m_n_instances_to_test);
5504
5505                                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawArraysInstanced() call failed.");
5506
5507                                 draw_call_count                                  = 1;
5508                                 draw_call_first_instance_id[0]   = 0;
5509                                 draw_call_first_vertex_id[0]     = m_draw_call_first;
5510                                 draw_call_is_vertex_id_ascending = true;
5511                                 draw_call_n_instances[0]                 = m_n_instances_to_test;
5512                                 draw_call_n_vertices[0]                  = m_n_vertices_per_instance;
5513                                 n_result_bytes_per_instance[0]   = n_result_bytes_per_vertex * draw_call_n_vertices[0];
5514                                 n_result_bytes_total                     = n_result_bytes_per_instance[0] * draw_call_n_instances[0];
5515
5516                                 break;
5517                         }
5518
5519                         case DRAW_CALL_REGULAR_INSTANCED_BASE_INSTANCE:
5520                         {
5521                                 m_gl.drawArraysInstancedBaseInstance(GL_POINTS, m_draw_call_first, m_n_vertices_per_instance,
5522                                                                                                          m_n_instances_to_test, m_draw_call_baseInstance);
5523
5524                                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawArraysInstancedBaseInstance() call failed.");
5525
5526                                 draw_call_count                                  = 1;
5527                                 draw_call_first_instance_id[0]   = 0;
5528                                 draw_call_first_vertex_id[0]     = m_draw_call_first;
5529                                 draw_call_is_vertex_id_ascending = true;
5530                                 draw_call_n_instances[0]                 = m_n_instances_to_test;
5531                                 draw_call_n_vertices[0]                  = m_n_vertices_per_instance;
5532                                 n_result_bytes_per_instance[0]   = n_result_bytes_per_vertex * draw_call_n_vertices[0];
5533                                 n_result_bytes_total                     = n_result_bytes_per_instance[0] * draw_call_n_instances[0];
5534
5535                                 break;
5536                         }
5537
5538                         case DRAW_CALL_REGULAR_MULTI:
5539                         {
5540                                 m_gl.multiDrawArrays(GL_POINTS, m_multidrawcall_first, m_multidrawcall_count,
5541                                                                          m_multidrawcall_drawcount);
5542                                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glMultiDrawArrays() call failed.");
5543
5544                                 draw_call_count                                  = m_multidrawcall_drawcount;
5545                                 draw_call_first_instance_id[0]   = 0;
5546                                 draw_call_first_instance_id[1]   = 0;
5547                                 draw_call_first_vertex_id[0]     = m_multidrawcall_first[0];
5548                                 draw_call_first_vertex_id[1]     = m_multidrawcall_first[1];
5549                                 draw_call_is_vertex_id_ascending = true;
5550                                 draw_call_n_instances[0]                 = 1;
5551                                 draw_call_n_instances[1]                 = 1;
5552                                 draw_call_n_vertices[0]                  = m_multidrawcall_count[0];
5553                                 draw_call_n_vertices[1]                  = m_multidrawcall_count[1];
5554                                 n_result_bytes_per_instance[0]   = n_result_bytes_per_vertex * m_multidrawcall_count[0];
5555                                 n_result_bytes_per_instance[1]   = n_result_bytes_per_vertex * m_multidrawcall_count[1];
5556                                 n_result_bytes_total                     = n_result_bytes_per_instance[0] + n_result_bytes_per_instance[1];
5557
5558                                 break;
5559                         }
5560
5561                         default:
5562                         {
5563                                 TCU_FAIL("Unrecognized draw call type");
5564                         }
5565                         } /* switch (draw_call_type) */
5566
5567                         DE_ASSERT(n_result_bytes_total <= m_result_bo_size);
5568
5569                         m_gl.endTransformFeedback();
5570                         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glEndTransformFeedback() call failed.");
5571
5572                         /* Retrieve the captured data */
5573                         glw::GLuint  mappable_bo_id                       = m_helper_bo;
5574                         unsigned int mappable_bo_start_offset = 0;
5575
5576                         /* We cannot map the result BO storage directly into process space, since
5577                          * it's a sparse buffer. Copy the generated data to a helper BO and map
5578                          * that BO instead. */
5579                         m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_result_bo);
5580                         m_gl.bindBuffer(GL_COPY_WRITE_BUFFER, m_helper_bo);
5581                         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call(s) failed.");
5582
5583                         if (is_ia_iteration)
5584                         {
5585                                 m_gl.copyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, /* readOffset */
5586                                                                            0,                                                                                    /* writeOffset */
5587                                                                            n_result_bytes_total);
5588                                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCopyBufferSubData() call failed.");
5589                         }
5590                         else
5591                         {
5592                                 DE_ASSERT((n_result_bytes_total % 2) == 0);
5593
5594                                 m_gl.copyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, /* readOffset */
5595                                                                            0,                                                                                    /* writeOffset */
5596                                                                            n_result_bytes_total / 2);
5597                                 m_gl.copyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER,
5598                                                                            m_result_bo_size / 2,          /* readOffset  */
5599                                                                            m_result_bo_size / 2,          /* writeOffset */
5600                                                                            n_result_bytes_total / 2); /* size        */
5601                                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCopyBufferSubData() call failed.");
5602                         }
5603
5604                         m_gl.bindBuffer(GL_ARRAY_BUFFER, mappable_bo_id);
5605                         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
5606
5607                         result_ptr = (unsigned int*)m_gl.mapBufferRange(GL_ARRAY_BUFFER, mappable_bo_start_offset, m_result_bo_size,
5608                                                                                                                         GL_MAP_READ_BIT);
5609
5610                         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glMapBufferRange() call failed.");
5611
5612                         /* Verify the generated output */
5613                         bool            continue_checking                 = true;
5614                         glw::GLuint result_instance_id_stride = 0;
5615                         glw::GLuint result_vertex_id_stride   = 0;
5616
5617                         if (is_ia_iteration)
5618                         {
5619                                 result_instance_id_stride = 2;
5620                                 result_vertex_id_stride   = 2;
5621                         }
5622                         else
5623                         {
5624                                 result_instance_id_stride = 1;
5625                                 result_vertex_id_stride   = 1;
5626                         }
5627
5628                         /* For all draw calls.. */
5629                         for (int n_draw_call = 0; n_draw_call < draw_call_count && continue_checking; ++n_draw_call)
5630                         {
5631                                 /* ..and resulting draw call instances.. */
5632                                 for (int n_instance = 0; n_instance < draw_call_n_instances[n_draw_call] && continue_checking;
5633                                          ++n_instance)
5634                                 {
5635                                         DE_ASSERT((n_result_bytes_per_instance[n_draw_call] % sizeof(unsigned int)) == 0);
5636
5637                                         /* Determine where the result TF data start from */
5638                                         const glw::GLuint expected_instance_id = draw_call_first_instance_id[n_draw_call] + n_instance;
5639                                         glw::GLuint*      result_instance_id_traveller_ptr = DE_NULL;
5640                                         glw::GLuint*      result_vertex_id_traveller_ptr   = DE_NULL;
5641
5642                                         if (is_ia_iteration)
5643                                         {
5644                                                 result_instance_id_traveller_ptr = result_ptr;
5645
5646                                                 for (int n_prev_draw_call = 0; n_prev_draw_call < n_draw_call; ++n_prev_draw_call)
5647                                                 {
5648                                                         result_instance_id_traveller_ptr += draw_call_n_instances[n_prev_draw_call] *
5649                                                                                                                                 n_result_bytes_per_instance[n_prev_draw_call] /
5650                                                                                                                                 sizeof(unsigned int);
5651                                                 }
5652
5653                                                 result_instance_id_traveller_ptr +=
5654                                                         n_instance * n_result_bytes_per_instance[n_draw_call] / sizeof(unsigned int);
5655                                                 result_vertex_id_traveller_ptr = result_instance_id_traveller_ptr + 1;
5656                                         } /* if (is_ia_iteration) */
5657                                         else
5658                                         {
5659                                                 DE_ASSERT((m_result_bo_size % 2) == 0);
5660
5661                                                 result_instance_id_traveller_ptr = result_ptr;
5662
5663                                                 for (int n_prev_draw_call = 0; n_prev_draw_call < n_draw_call; ++n_prev_draw_call)
5664                                                 {
5665                                                         result_instance_id_traveller_ptr +=
5666                                                                 draw_call_n_instances[n_prev_draw_call] *
5667                                                                 n_result_bytes_per_instance[n_prev_draw_call] /
5668                                                                 2 / /* instance id..instance id data | vertex id..vertex id data */
5669                                                                 sizeof(unsigned int);
5670                                                 }
5671
5672                                                 result_instance_id_traveller_ptr +=
5673                                                         n_instance * n_result_bytes_per_instance[n_draw_call] / 2 / sizeof(unsigned int);
5674                                                 result_vertex_id_traveller_ptr =
5675                                                         result_instance_id_traveller_ptr + (m_result_bo_size / 2) / sizeof(unsigned int);
5676                                         }
5677
5678                                         /* Start checking the generated output */
5679                                         for (int n_point = 0; n_point < draw_call_n_vertices[n_draw_call] && continue_checking; ++n_point)
5680                                         {
5681                                                 glw::GLuint expected_vertex_id  = 1;
5682                                                 glw::GLuint retrieved_instance_id = 2;
5683                                                 glw::GLuint retrieved_vertex_id   = 3;
5684
5685                                                 if (draw_call_is_vertex_id_ascending)
5686                                                 {
5687                                                         expected_vertex_id = draw_call_first_vertex_id[n_draw_call] + n_point;
5688                                                 } /* if (draw_call_is_vertex_id_ascending) */
5689                                                 else
5690                                                 {
5691                                                         if (draw_call_first_vertex_id[n_draw_call] >= n_point)
5692                                                         {
5693                                                                 expected_vertex_id = draw_call_first_vertex_id[n_draw_call] - n_point;
5694                                                         }
5695                                                         else
5696                                                         {
5697                                                                 expected_vertex_id = 0;
5698                                                         }
5699                                                 }
5700
5701                                                 /* Only perform the check if the offsets refer to pages with physical backing.
5702                                                  *
5703                                                  * Note that, on platforms, whose page size % 4 != 0, the values can land partially out of bounds,
5704                                                  * and partially in the safe zone. In such cases, skip the verification. */
5705                                                 const bool result_instance_id_page_has_physical_backing =
5706                                                         (((((char*)result_instance_id_traveller_ptr - (char*)result_ptr) / m_page_size) % 2) ==
5707                                                          0) &&
5708                                                         ((((((char*)result_instance_id_traveller_ptr - (char*)result_ptr) + sizeof(unsigned int) -
5709                                                                 1) /
5710                                                            m_page_size) %
5711                                                           2) == 0);
5712                                                 const bool result_vertex_id_page_has_physical_backing =
5713                                                         (((((char*)result_vertex_id_traveller_ptr - (char*)result_ptr) / m_page_size) % 2) == 0) &&
5714                                                         ((((((char*)result_vertex_id_traveller_ptr - (char*)result_ptr) + sizeof(unsigned int) -
5715                                                                 1) /
5716                                                            m_page_size) %
5717                                                           2) == 0);
5718
5719                                                 retrieved_instance_id = *result_instance_id_traveller_ptr;
5720                                                 result_instance_id_traveller_ptr += result_instance_id_stride;
5721
5722                                                 retrieved_vertex_id = *result_vertex_id_traveller_ptr;
5723                                                 result_vertex_id_traveller_ptr += result_vertex_id_stride;
5724
5725                                                 if ((result_instance_id_page_has_physical_backing &&
5726                                                          retrieved_instance_id != expected_instance_id) ||
5727                                                         (result_vertex_id_page_has_physical_backing && retrieved_vertex_id != expected_vertex_id))
5728                                                 {
5729                                                         m_testCtx.getLog()
5730                                                                 << tcu::TestLog::Message << "For "
5731                                                                                                                         "["
5732                                                                 << getName() << "]"
5733                                                                                                 ", sparse BO flags "
5734                                                                                                 "["
5735                                                                 << SparseBufferTestUtilities::getSparseBOFlagsString(sparse_bo_storage_flags)
5736                                                                 << "]"
5737                                                                    ", draw call type "
5738                                                                 << getDrawCallTypeString(draw_call_type) << " at index "
5739                                                                                                                                                         "["
5740                                                                 << n_draw_call << " / " << (draw_call_count - 1) << "]"
5741                                                                                                                                                                         ", TF mode "
5742                                                                                                                                                                         "["
5743                                                                 << ((is_ia_iteration) ? "interleaved attribs" : "separate attribs") << "]"
5744                                                                 << ", instance "
5745                                                                    "["
5746                                                                 << n_instance << " / " << (draw_call_n_instances[n_draw_call] - 1) << "]"
5747                                                                 << ", point at index "
5748                                                                    "["
5749                                                                 << n_point << " / " << (draw_call_n_vertices[n_draw_call] - 1) << "]"
5750                                                                 << ", VS-level gl_VertexID was equal to "
5751                                                                    "["
5752                                                                 << retrieved_vertex_id << "]"
5753                                                                                                                   " and gl_InstanceID was set to "
5754                                                                                                                   "["
5755                                                                 << retrieved_instance_id << "]"
5756                                                                                                                         ", whereas gl_VertexID of value "
5757                                                                                                                         "["
5758                                                                 << expected_vertex_id << "]"
5759                                                                                                                  " and gl_InstanceID of value "
5760                                                                                                                  "["
5761                                                                 << expected_instance_id << "]"
5762                                                                                                                    " were anticipated."
5763                                                                 << tcu::TestLog::EndMessage;
5764
5765                                                         continue_checking = false;
5766                                                         result                    = false;
5767
5768                                                         break;
5769                                                 } /* if (reported gl_InstanceID / gl_VertexID values are wrong) */
5770                                         }        /* for (all drawn points) */
5771                                 }                 /* for (all instances) */
5772
5773                                 /* Release memory pages we have allocated for the transform feed-back.
5774                                  *
5775                                  * NOTE: For some iterations, this call will attempt to de-commit pages which
5776                                  *       have not been assigned physical backing. This is a valid behavior,
5777                                  *       as per spec.
5778                                  */
5779                                 m_gl.bufferPageCommitmentARB(GL_TRANSFORM_FEEDBACK_BUFFER, 0,    /* offset */
5780                                                                                          m_result_bo_size_rounded, GL_FALSE); /* commit */
5781                                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
5782                         } /* for (all draw call) */
5783
5784                         m_gl.unmapBuffer(GL_ARRAY_BUFFER);
5785                         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUnmapBuffer() call failed.");
5786                 } /* for (all draw call types) */
5787         }        /* for (both TF modes) */
5788
5789         return result;
5790 }
5791
5792 /** Converts the internal enum to a null-terminated text string.
5793  *
5794  *  @param draw_call Draw call type to return a string for.
5795  *
5796  *  @return The requested string or "[?!]", if the enum was not recognized.
5797  **/
5798 const char* TransformFeedbackBufferStorageTestCase::getDrawCallTypeString(_draw_call draw_call)
5799 {
5800         const char* result = "[?!]";
5801
5802         switch (draw_call)
5803         {
5804         case DRAW_CALL_INDEXED:
5805                 result = "glDrawElements()";
5806                 break;
5807         case DRAW_CALL_INDEXED_BASE_VERTEX:
5808                 result = "glDrawElementsBaseVertex()";
5809                 break;
5810         case DRAW_CALL_INDEXED_INDIRECT:
5811                 result = "glDrawElementsIndirect()";
5812                 break;
5813         case DRAW_CALL_INDEXED_INDIRECT_MULTI:
5814                 result = "glMultiDrawElementIndirect()";
5815                 break;
5816         case DRAW_CALL_INDEXED_MULTI:
5817                 result = "glMultiDrawElements()";
5818                 break;
5819         case DRAW_CALL_INDEXED_MULTI_BASE_VERTEX:
5820                 result = "glMultiDrawElementsBaseVertex()";
5821                 break;
5822         case DRAW_CALL_INSTANCED_INDEXED:
5823                 result = "glDrawElementsInstanced()";
5824                 break;
5825         case DRAW_CALL_INSTANCED_INDEXED_BASE_VERTEX:
5826                 result = "glDrawElementsInstancedBaseVertex()";
5827                 break;
5828         case DRAW_CALL_INSTANCED_INDEXED_BASE_VERTEX_BASE_INSTANCE:
5829                 result = "glDrawElementsInstancedBaseVertexBaseInstance()";
5830                 break;
5831         case DRAW_CALL_REGULAR:
5832                 result = "glDrawArrays()";
5833                 break;
5834         case DRAW_CALL_REGULAR_INDIRECT:
5835                 result = "glDrawArraysIndirect()";
5836                 break;
5837         case DRAW_CALL_REGULAR_INDIRECT_MULTI:
5838                 result = "glMultiDrawArraysIndirect()";
5839                 break;
5840         case DRAW_CALL_REGULAR_INSTANCED:
5841                 result = "glDrawArraysInstanced()";
5842                 break;
5843         case DRAW_CALL_REGULAR_INSTANCED_BASE_INSTANCE:
5844                 result = "glDrawArraysInstancedBaseInstance()";
5845                 break;
5846         case DRAW_CALL_REGULAR_MULTI:
5847                 result = "glMultiDrawArrays()";
5848                 break;
5849
5850         default:
5851                 break;
5852         } /* switch (draw_call) */
5853
5854         return result;
5855 }
5856
5857 /** Initializes test data buffer, and then sets up:
5858  *
5859  *  - an immutable buffer object (id stored in m_data_bo), to which the test data
5860  *    is copied.
5861  *  - a mappable immutable buffer object (id stored in m_helper_bo)
5862  **/
5863 void TransformFeedbackBufferStorageTestCase::initDataBO()
5864 {
5865         initTestData();
5866
5867         /* Initialize data BO (the BO which holds index + indirect draw call args */
5868         DE_ASSERT(m_data_bo == 0);
5869
5870         m_gl.genBuffers(1, &m_data_bo);
5871         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenBuffers() call failed.");
5872
5873         m_gl.bindBuffer(GL_ARRAY_BUFFER, m_data_bo);
5874         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
5875
5876         m_gl.bufferStorage(GL_ARRAY_BUFFER, m_data_bo_size, DE_NULL, GL_DYNAMIC_STORAGE_BIT);
5877         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferStorage() call failed.");
5878
5879         m_gl.bufferSubData(GL_ARRAY_BUFFER, m_data_bo_indexed_indirect_arg_offset, m_indirect_arg_data_size,
5880                                            m_indirect_arg_data);
5881         m_gl.bufferSubData(GL_ARRAY_BUFFER, m_data_bo_index_data_offset, m_index_data_size, m_index_data);
5882         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferSubData() call(s) failed.");
5883
5884         /* Generate & bind a helper BO we need to copy the data to from the sparse BO
5885          * if direct mapping is not possible.
5886          */
5887         DE_ASSERT(m_result_bo_size != 0);
5888         DE_ASSERT(m_result_bo == 0);
5889         DE_ASSERT(m_helper_bo == 0);
5890
5891         m_gl.genBuffers(1, &m_helper_bo);
5892         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenBuffers() call failed.");
5893
5894         m_gl.bindBuffer(GL_ARRAY_BUFFER, m_helper_bo);
5895         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
5896
5897         m_gl.bufferStorage(GL_ARRAY_BUFFER, m_result_bo_size, DE_NULL, /* data */
5898                                            GL_MAP_READ_BIT);
5899         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferStorage() call failed.");
5900 }
5901
5902 /** Initializes GL objects used across all test case iterations.
5903  *
5904  *  Called once during BufferStorage test run-time.
5905  */
5906 bool TransformFeedbackBufferStorageTestCase::initTestCaseGlobal()
5907 {
5908         bool result = true;
5909
5910         /* Initialize test program object */
5911         static const char*                tf_varyings[] = { "instance_id", "vertex_id" };
5912         static const unsigned int n_tf_varyings = sizeof(tf_varyings) / sizeof(tf_varyings[0]);
5913         static const char*                vs_body               = "#version 420 core\n"
5914                                                                  "\n"
5915                                                                  "out uint instance_id;\n"
5916                                                                  "out uint vertex_id;\n"
5917                                                                  "\n"
5918                                                                  "void main()\n"
5919                                                                  "{\n"
5920                                                                  "    instance_id = gl_InstanceID;\n"
5921                                                                  "    vertex_id   = gl_VertexID;\n"
5922                                                                  "}\n";
5923
5924         m_po_ia = SparseBufferTestUtilities::createProgram(m_gl, DE_NULL, /* fs_body_parts */
5925                                                                                                            0,                     /* n_fs_body_parts */
5926                                                                                                            &vs_body, 1,   /* n_vs_body_parts */
5927                                                                                                            DE_NULL,               /* attribute_names */
5928                                                                                                            DE_NULL,               /* attribute_locations */
5929                                                                                                            0,                     /* n_attribute_properties */
5930                                                                                                            tf_varyings, n_tf_varyings, GL_INTERLEAVED_ATTRIBS);
5931
5932         m_po_sa = SparseBufferTestUtilities::createProgram(m_gl, DE_NULL, /* fs_body_parts */
5933                                                                                                            0,                     /* n_fs_body_parts */
5934                                                                                                            &vs_body, 1,   /* n_vs_body_parts */
5935                                                                                                            DE_NULL,               /* attribute_names */
5936                                                                                                            DE_NULL,               /* attribute_locations */
5937                                                                                                            0,                     /* n_attribute_properties */
5938                                                                                                            tf_varyings, n_tf_varyings, GL_SEPARATE_ATTRIBS);
5939
5940         if (m_po_ia == 0 || m_po_sa == 0)
5941         {
5942                 result = false;
5943
5944                 goto end;
5945         }
5946
5947         /* Generate & bind a VAO */
5948         m_gl.genVertexArrays(1, &m_vao);
5949         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenVertexArrays() call failed.");
5950
5951         m_gl.bindVertexArray(m_vao);
5952         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindVertexArray() call failed.");
5953
5954         initDataBO();
5955
5956 end:
5957         return result;
5958 }
5959
5960 /** Initializes GL objects which are needed for a single test case iteration.
5961  *
5962  *  deinitTestCaseIteration() will be called after the test case is executed in ::execute()
5963  *  to release these objects.
5964  **/
5965 bool TransformFeedbackBufferStorageTestCase::initTestCaseIteration(glw::GLuint sparse_bo)
5966 {
5967         bool result = true;
5968
5969         /* Initialize buffer objects used by the test case */
5970         m_result_bo = sparse_bo;
5971
5972         /* Sanity check */
5973         DE_ASSERT(m_data_bo != 0);
5974
5975         return result;
5976 }
5977
5978 /** Sets up client-side data arrays, later uploaded to the test buffer object, used as a source for:
5979  *
5980  *  - index data
5981  *  - indirect draw call arguments
5982  *  - multi draw call arguments
5983  **/
5984 void TransformFeedbackBufferStorageTestCase::initTestData()
5985 {
5986         /* We need the result data to span across at least m_min_memory_page_span memory pages.
5987          * Each vertex outputs 2 * sizeof(int) = 8 bytes of data.
5988          *
5989          * For simplicity, we assume the number of bytes we calculate here is per instance. */
5990         m_n_vertices_per_instance = static_cast<unsigned int>((m_page_size * m_min_memory_page_span / (sizeof(int) * 2)));
5991
5992         /* Let:
5993          *
5994          *     index_data_size       = (n of vertices per a single instance) * sizeof(unsigned int)
5995          *     indexed_indirect_size = sizeof(glDrawElementsIndirect()      indirect arguments)
5996          *     indexed_mdi_size      = sizeof(glMultiDrawElementsIndirect() indirect arguments) * 2 (single instance & multiple instances case)
5997          *     regular_indirect_size = sizeof(glDrawArraysIndirect()        indirect arguments)
5998          *     regular_mdi_size      = sizeof(glMultiDrawArraysIndirect()   indirect arguments) * 2 (single instance & multiple instances case)
5999          *
6000          *
6001          * The layout we will use for the data buffer is:
6002          *
6003          * [indexed indirect arg data // Size: indexed_indirect_size bytes]
6004          * [indexed MDI arg data      // Size: indexed_mdi_size      bytes]
6005          * [regular indirect arg data // Size: regular_indirect_size bytes]
6006          * [regular MDI arg data      // Size: regular_mdi_size      bytes]
6007          * [index data                // Size: index_data_size       bytes]
6008          */
6009         const unsigned int indexed_indirect_size = sizeof(unsigned int) * 5 /* as per GL spec */;
6010         const unsigned int indexed_mdi_size              = sizeof(unsigned int) * 5 /* as per GL spec */ * 2; /* draw calls */
6011         const unsigned int regular_indirect_size = sizeof(unsigned int) * 4;                                              /* as per GL spec */
6012         const unsigned int regular_mdi_size              = sizeof(unsigned int) * 4 /* as per GL spec */ * 2; /* draw calls */
6013
6014         m_data_bo_indexed_indirect_arg_offset = 0;
6015         m_data_bo_indexed_mdi_arg_offset          = m_data_bo_indexed_indirect_arg_offset + indexed_indirect_size;
6016         m_data_bo_regular_indirect_arg_offset = m_data_bo_indexed_mdi_arg_offset + indexed_mdi_size;
6017         m_data_bo_regular_mdi_arg_offset          = m_data_bo_regular_indirect_arg_offset + regular_indirect_size;
6018         m_data_bo_index_data_offset                       = m_data_bo_regular_mdi_arg_offset + regular_mdi_size;
6019
6020         /* Form the index data */
6021         DE_ASSERT(m_index_data == DE_NULL);
6022         DE_ASSERT(m_draw_call_firstIndex == sizeof(unsigned int));
6023
6024         m_index_data_size = static_cast<glw::GLuint>(
6025                 (1 /* extra index, as per m_draw_call_firstIndex */ + m_n_vertices_per_instance) * sizeof(unsigned int));
6026         m_index_data = (unsigned int*)new unsigned char[m_index_data_size];
6027
6028         for (unsigned int n_index = 0; n_index < m_n_vertices_per_instance + 1; ++n_index)
6029         {
6030                 m_index_data[n_index] = m_n_vertices_per_instance - n_index;
6031         } /* for (all available indices) */
6032
6033         /* Set multi draw-call arguments */
6034         m_multidrawcall_basevertex[0] = m_draw_call_baseVertex;
6035         m_multidrawcall_basevertex[1] = 257;
6036         m_multidrawcall_count[0]          = m_n_vertices_per_instance;
6037         m_multidrawcall_count[1]          = m_n_vertices_per_instance - 16;
6038         m_multidrawcall_drawcount        = 2;
6039         m_multidrawcall_first[0]          = 0;
6040         m_multidrawcall_first[1]          = m_draw_call_first;
6041         m_multidrawcall_index[0]          = (glw::GLvoid*)(intptr_t)m_data_bo_index_data_offset;
6042         m_multidrawcall_index[1]          = (glw::GLvoid*)(intptr_t)(m_data_bo_index_data_offset + m_draw_call_firstIndex);
6043         m_multidrawcall_primcount        = m_n_instances_to_test;
6044
6045         /* Form the indirect data */
6046         DE_ASSERT(m_indirect_arg_data == DE_NULL);
6047
6048         m_indirect_arg_data_size = m_data_bo_index_data_offset - m_data_bo_indexed_indirect_arg_offset;
6049         m_indirect_arg_data              = (unsigned int*)new unsigned char[m_indirect_arg_data_size];
6050
6051         unsigned int* indirect_arg_data_traveller_ptr = m_indirect_arg_data;
6052
6053         /* 1. Indexed indirect arg data */
6054         DE_ASSERT(((unsigned int)(intptr_t)(m_multidrawcall_index[1]) % sizeof(unsigned int)) == 0);
6055
6056         *indirect_arg_data_traveller_ptr = m_multidrawcall_count[1]; /* count */
6057         indirect_arg_data_traveller_ptr++;
6058
6059         *indirect_arg_data_traveller_ptr = m_n_instances_to_test; /* primCount */
6060         indirect_arg_data_traveller_ptr++;
6061
6062         *indirect_arg_data_traveller_ptr = static_cast<unsigned int>((unsigned int)(intptr_t)(m_multidrawcall_index[1]) /
6063                                                                                                                                  sizeof(unsigned int)); /* firstIndex */
6064         indirect_arg_data_traveller_ptr++;
6065
6066         *indirect_arg_data_traveller_ptr = m_draw_call_baseVertex; /* baseVertex */
6067         indirect_arg_data_traveller_ptr++;
6068
6069         *indirect_arg_data_traveller_ptr = m_draw_call_baseInstance; /* baseInstance */
6070         indirect_arg_data_traveller_ptr++;
6071
6072         /* 2. Indexed MDI arg data */
6073         for (unsigned int n_draw_call = 0; n_draw_call < 2; ++n_draw_call)
6074         {
6075                 DE_ASSERT(((unsigned int)(intptr_t)(m_multidrawcall_index[n_draw_call]) % sizeof(unsigned int)) == 0);
6076
6077                 *indirect_arg_data_traveller_ptr = m_multidrawcall_count[n_draw_call]; /* count */
6078                 indirect_arg_data_traveller_ptr++;
6079
6080                 *indirect_arg_data_traveller_ptr = (n_draw_call == 0) ? 1 : m_n_instances_to_test; /* primCount */
6081                 indirect_arg_data_traveller_ptr++;
6082
6083                 *indirect_arg_data_traveller_ptr = static_cast<unsigned int>(
6084                         (unsigned int)(intptr_t)(m_multidrawcall_index[n_draw_call]) / sizeof(unsigned int)); /* firstIndex */
6085                 indirect_arg_data_traveller_ptr++;
6086
6087                 *indirect_arg_data_traveller_ptr = m_draw_call_baseVertex;
6088                 indirect_arg_data_traveller_ptr++;
6089
6090                 *indirect_arg_data_traveller_ptr = m_draw_call_baseInstance;
6091                 indirect_arg_data_traveller_ptr++;
6092         } /* for (both single-instanced and multi-instanced cases) */
6093
6094         /* 3. Regular indirect arg data */
6095         *indirect_arg_data_traveller_ptr = m_multidrawcall_count[1]; /* count */
6096         indirect_arg_data_traveller_ptr++;
6097
6098         *indirect_arg_data_traveller_ptr = m_n_instances_to_test; /* primCount */
6099         indirect_arg_data_traveller_ptr++;
6100
6101         *indirect_arg_data_traveller_ptr = m_draw_call_first; /* first */
6102         indirect_arg_data_traveller_ptr++;
6103
6104         *indirect_arg_data_traveller_ptr = m_draw_call_baseInstance; /* baseInstance */
6105         indirect_arg_data_traveller_ptr++;
6106
6107         /* 4. Regular MDI arg data */
6108         for (unsigned int n_draw_call = 0; n_draw_call < 2; ++n_draw_call)
6109         {
6110                 *indirect_arg_data_traveller_ptr = m_multidrawcall_count[n_draw_call]; /* count */
6111                 indirect_arg_data_traveller_ptr++;
6112
6113                 *indirect_arg_data_traveller_ptr = (n_draw_call == 0) ? 1 : m_n_instances_to_test; /* instanceCount */
6114                 indirect_arg_data_traveller_ptr++;
6115
6116                 *indirect_arg_data_traveller_ptr = m_draw_call_first; /* first */
6117                 indirect_arg_data_traveller_ptr++;
6118
6119                 *indirect_arg_data_traveller_ptr = m_draw_call_baseInstance; /* baseInstance */
6120                 indirect_arg_data_traveller_ptr++;
6121         } /* for (both single-instanced and multi-instanced cases) */
6122
6123         /* Store the number of bytes we will need to allocate for the data BO */
6124         m_data_bo_size = m_index_data_size + m_indirect_arg_data_size;
6125
6126         /* Determine the number of bytes we will need to have at hand to hold all the captured TF varyings.
6127          * The equation below takes into account the heaviest draw call the test will ever issue.
6128          */
6129         m_result_bo_size =
6130                 static_cast<glw::GLuint>(sizeof(unsigned int) * 2 /* TF varyings per vertex */ *
6131                                                                  (m_multidrawcall_count[0] + m_multidrawcall_count[1]) * m_multidrawcall_primcount);
6132         m_result_bo_size_rounded = SparseBufferTestUtilities::alignOffset(m_result_bo_size, m_page_size);
6133
6134         /* Sanity checks */
6135         DE_ASSERT(m_min_memory_page_span > 0);
6136         DE_ASSERT(m_page_size > 0);
6137         DE_ASSERT(m_result_bo_size >= (m_min_memory_page_span * m_page_size));
6138 }
6139
6140 /** Constructor.
6141  *
6142  *  @param gl                         GL entry-points container
6143  *  @param testContext                CTS test context
6144  *  @param page_size                  Page size, as reported by implementation for the GL_SPARSE_BUFFER_PAGE_SIZE_ARB query.
6145  *  @param pGLBufferPageCommitmentARB Func ptr to glBufferPageCommitmentARB() entry-point.
6146  */
6147 UniformBufferStorageTestCase::UniformBufferStorageTestCase(const glw::Functions& gl, tcu::TestContext& testContext,
6148                                                                                                                    glw::GLint page_size)
6149         : m_gl(gl)
6150         , m_gl_uniform_buffer_offset_alignment_value(0)
6151         , m_helper_bo(0)
6152         , m_n_pages_to_use(4)
6153         , m_n_ubo_uints(0)
6154         , m_page_size(page_size)
6155         , m_po(0)
6156         , m_sparse_bo(0)
6157         , m_sparse_bo_data_size(0)
6158         , m_sparse_bo_data_start_offset(0)
6159         , m_sparse_bo_size(0)
6160         , m_sparse_bo_size_rounded(0)
6161         , m_testCtx(testContext)
6162         , m_tf_bo(0)
6163         , m_ubo_data(DE_NULL)
6164         , m_vao(0)
6165 {
6166         if ((m_n_pages_to_use % 2) != 0)
6167         {
6168                 DE_ASSERT(DE_FALSE);
6169         }
6170 }
6171
6172 /** Releases all GL objects used across all test case iterations.
6173  *
6174  *  Called once during BufferStorage test run-time.
6175  */
6176 void UniformBufferStorageTestCase::deinitTestCaseGlobal()
6177 {
6178         if (m_helper_bo != 0)
6179         {
6180                 m_gl.deleteBuffers(1, &m_helper_bo);
6181
6182                 m_helper_bo = 0;
6183         }
6184
6185         if (m_po != 0)
6186         {
6187                 m_gl.deleteProgram(m_po);
6188
6189                 m_po = 0;
6190         }
6191
6192         if (m_tf_bo != 0)
6193         {
6194                 m_gl.deleteBuffers(1, &m_tf_bo);
6195
6196                 m_tf_bo = 0;
6197         }
6198
6199         if (m_ubo_data != DE_NULL)
6200         {
6201                 delete[] m_ubo_data;
6202
6203                 m_ubo_data = DE_NULL;
6204         }
6205
6206         if (m_vao != 0)
6207         {
6208                 m_gl.deleteVertexArrays(1, &m_vao);
6209
6210                 m_vao = 0;
6211         }
6212 }
6213
6214 /** Releases temporary GL objects, created specifically for one test case iteration. */
6215 void UniformBufferStorageTestCase::deinitTestCaseIteration()
6216 {
6217         if (m_sparse_bo != 0)
6218         {
6219                 m_gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bo);
6220                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
6221
6222                 m_gl.bufferPageCommitmentARB(GL_ARRAY_BUFFER, 0,                                  /* offset */
6223                                                                          m_sparse_bo_size_rounded, GL_FALSE); /* commit */
6224                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
6225
6226                 m_sparse_bo = 0;
6227         }
6228 }
6229
6230 /** Executes a single test iteration. The BufferStorage test will call this method
6231  *  numerously during its life-time, testing various valid flag combinations applied
6232  *  to the tested sparse buffer object at glBufferStorage() call time.
6233  *
6234  *  @param sparse_bo_storage_flags <flags> argument, used by the test in the glBufferStorage()
6235  *                                 call to set up the sparse buffer's storage.
6236  *
6237  *  @return true if the test case executed correctly, false otherwise.
6238  */
6239 bool UniformBufferStorageTestCase::execute(glw::GLuint sparse_bo_storage_flags)
6240 {
6241         (void)sparse_bo_storage_flags;
6242         bool result = true;
6243
6244         m_gl.bindBufferRange(GL_UNIFORM_BUFFER, 0, /* index */
6245                                                  m_sparse_bo, m_sparse_bo_data_start_offset, m_n_ubo_uints * 4 * sizeof(unsigned int));
6246         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBufferBase() call failed.");
6247
6248         /* Run the test in three iterations:
6249          *
6250          * 1) Whole UBO storage is backed by physical backing.
6251          * 2) Half the UBO storage is backed by physical backing.
6252          * 3) None of the UBO storage is backed by physical backing.
6253          */
6254         for (unsigned int n_iteration = 0; n_iteration < 3; ++n_iteration)
6255         {
6256                 bool             result_local                    = true;
6257                 unsigned int ubo_commit_size             = 0;
6258                 unsigned int ubo_commit_start_offset = 0;
6259
6260                 switch (n_iteration)
6261                 {
6262                 case 0:
6263                 {
6264                         ubo_commit_size                 = m_sparse_bo_data_size;
6265                         ubo_commit_start_offset = m_sparse_bo_data_start_offset;
6266
6267                         break;
6268                 }
6269
6270                 case 1:
6271                 {
6272                         DE_ASSERT((m_sparse_bo_data_size % 2) == 0);
6273                         DE_ASSERT((m_sparse_bo_data_size % m_page_size) == 0);
6274
6275                         ubo_commit_size                 = m_sparse_bo_data_size / 2;
6276                         ubo_commit_start_offset = m_sparse_bo_data_start_offset;
6277
6278                         break;
6279                 }
6280
6281                 case 2:
6282                 {
6283                         /* The default values do just fine */
6284
6285                         break;
6286                 }
6287
6288                 default:
6289                 {
6290                         TCU_FAIL("Invalid iteration index");
6291                 }
6292                 } /* switch (n_iteration) */
6293
6294                 m_gl.bufferPageCommitmentARB(GL_UNIFORM_BUFFER, ubo_commit_start_offset, ubo_commit_size, GL_TRUE); /* commit */
6295                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
6296
6297                 /* Copy the UBO data */
6298                 m_gl.copyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, /* readOffset */
6299                                                            ubo_commit_start_offset, ubo_commit_size);
6300                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCopyBufferSubData() call failed.");
6301
6302                 /* Issue the draw call to execute the test */
6303                 m_gl.useProgram(m_po);
6304                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUseProgram() call failed.");
6305
6306                 m_gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_tf_bo);
6307                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
6308
6309                 m_gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, /* index */
6310                                                         m_tf_bo);
6311                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBufferBase() call failed.");
6312
6313                 m_gl.beginTransformFeedback(GL_POINTS);
6314                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBeginTransformFeedback() call failed.");
6315
6316                 m_gl.drawArrays(GL_POINTS, 0, /* first */
6317                                                 m_n_ubo_uints);
6318                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawArrays() call failed.");
6319
6320                 m_gl.endTransformFeedback();
6321                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glEndTransformFeedback() call failed.");
6322
6323                 /* Retrieve the data, verify the output */
6324                 const unsigned int* result_data_ptr =
6325                         (const unsigned int*)m_gl.mapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, GL_READ_ONLY);
6326                 unsigned int ubo_data_offset = m_sparse_bo_data_start_offset;
6327
6328                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glMapBuffer() call failed.");
6329
6330                 for (unsigned int n_vertex = 0; n_vertex < m_n_ubo_uints && result_local;
6331                          ++n_vertex, ubo_data_offset = static_cast<unsigned int>(ubo_data_offset + 4 * sizeof(unsigned int)))
6332                 {
6333                         const bool is_ub_data_physically_backed = (ubo_data_offset >= ubo_commit_start_offset &&
6334                                                                                                            ubo_data_offset < (ubo_commit_start_offset + ubo_commit_size)) ?
6335                                                                                                                   1 :
6336                                                                                                                   0;
6337                         unsigned int       expected_value  = -1;
6338                         const unsigned int retrieved_value = result_data_ptr[n_vertex];
6339
6340                         if (is_ub_data_physically_backed)
6341                         {
6342                                 expected_value = 1;
6343                         }
6344                         else
6345                         {
6346                                 /* Read ops applied against non-committed sparse buffers return an undefined value.
6347                                  */
6348                                 continue;
6349                         }
6350
6351                         if (expected_value != retrieved_value)
6352                         {
6353                                 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value "
6354                                                                                                                            "("
6355                                                                    << retrieved_value << ") "
6356                                                                                                                  "found at index "
6357                                                                                                                  "("
6358                                                                    << n_vertex << ")"
6359                                                                                                   ", instead of the expected value "
6360                                                                                                   "("
6361                                                                    << expected_value << ")"
6362                                                                                                                 ". Iteration index:"
6363                                                                                                                 "("
6364                                                                    << n_iteration << ")" << tcu::TestLog::EndMessage;
6365
6366                                 result_local = false;
6367                         }
6368                 }
6369
6370                 result &= result_local;
6371
6372                 /* Clean up in anticipation for the next iteration */
6373                 static const unsigned char data_zero_r8 = 0;
6374
6375                 m_gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
6376                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUnmapBuffer() call failed.");
6377
6378                 m_gl.clearBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, GL_R8, GL_RED, GL_UNSIGNED_BYTE, &data_zero_r8);
6379                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glClearBufferData() call failed.");
6380
6381                 m_gl.bufferPageCommitmentARB(GL_UNIFORM_BUFFER, 0, m_sparse_bo_size_rounded, GL_FALSE); /* commit */
6382                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferPageCommitmentARB() call failed.");
6383         } /* for (all three iterations) */
6384
6385         return result;
6386 }
6387
6388 /** Initializes GL objects used across all test case iterations.
6389  *
6390  *  Called once during BufferStorage test run-time.
6391  */
6392 bool UniformBufferStorageTestCase::initTestCaseGlobal()
6393 {
6394         /* Cache GL constant values */
6395         glw::GLint gl_max_uniform_block_size_value = 0;
6396
6397         m_gl.getIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &gl_max_uniform_block_size_value);
6398         m_gl.getIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &m_gl_uniform_buffer_offset_alignment_value);
6399         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGetIntegerv() call(s) failed.");
6400
6401         /* Determine the number of uints we can access at once from a single VS invocation */
6402         DE_ASSERT(gl_max_uniform_block_size_value >= 1);
6403
6404         /* Account for the fact that in std140 layout, array elements will be rounded up
6405          * to the size of a vec4, i.e. 16 bytes. */
6406         m_n_ubo_uints = static_cast<unsigned int>(gl_max_uniform_block_size_value / (4 * sizeof(unsigned int)));
6407
6408         /* Prepare the test program */
6409         std::stringstream vs_body_define_sstream;
6410         std::string               vs_body_define_string;
6411
6412         const char* tf_varying           = "result";
6413         const char* vs_body_preamble = "#version 140\n"
6414                                                                    "\n";
6415
6416         const char* vs_body_main = "\n"
6417                                                            "layout(std140) uniform data\n"
6418                                                            "{\n"
6419                                                            "    uint data_input[N_UBO_UINTS];"
6420                                                            "};\n"
6421                                                            "\n"
6422                                                            "out uint result;\n"
6423                                                            "\n"
6424                                                            "void main()\n"
6425                                                            "{\n"
6426                                                            "    result = (data_input[gl_VertexID] == uint(gl_VertexID) ) ? 1u : 0u;\n"
6427                                                            "}";
6428
6429         vs_body_define_sstream << "#define N_UBO_UINTS (" << m_n_ubo_uints << ")\n";
6430         vs_body_define_string = vs_body_define_sstream.str();
6431
6432         const char*                vs_body_parts[] = { vs_body_preamble, vs_body_define_string.c_str(), vs_body_main };
6433         const unsigned int n_vs_body_parts = sizeof(vs_body_parts) / sizeof(vs_body_parts[0]);
6434
6435         m_po = SparseBufferTestUtilities::createProgram(m_gl, DE_NULL,                                                   /* fs_body_parts */
6436                                                                                                         0,                                                                               /* n_fs_body_parts */
6437                                                                                                         vs_body_parts, n_vs_body_parts, DE_NULL, /* attribute_names */
6438                                                                                                         DE_NULL,                                                                 /* attribute_locations */
6439                                                                                                         0,                              /* n_attribute_properties */
6440                                                                                                         &tf_varying, 1, /* n_tf_varyings */
6441                                                                                                         GL_INTERLEAVED_ATTRIBS);
6442
6443         if (m_po == 0)
6444         {
6445                 TCU_FAIL("The test program failed to link");
6446         }
6447
6448         /* Determine the number of bytes the sparse buffer needs to be able to have
6449          * a physical backing or.
6450          *
6451          * We will provide physical backing for twice the required size and then use
6452          * a region in the centered of the allocated memory block.
6453          *
6454          * NOTE: We need to be able to use an offset which is aligned to both the page size,
6455          *       and the UB offset alignment.
6456          * */
6457         m_sparse_bo_data_size = static_cast<unsigned int>(sizeof(unsigned int) * m_page_size);
6458         m_sparse_bo_size          = (m_page_size * m_gl_uniform_buffer_offset_alignment_value) * 2;
6459
6460         if (m_sparse_bo_size < m_sparse_bo_data_size * 2)
6461         {
6462                 m_sparse_bo_size = m_sparse_bo_data_size * 2;
6463         }
6464
6465         m_sparse_bo_size_rounded          = m_sparse_bo_size; /* rounded to the page size by default */
6466         m_sparse_bo_data_start_offset = (m_sparse_bo_size - m_sparse_bo_data_size) / 2;
6467
6468         /* Set up the TFBO storage */
6469         const unsigned tfbo_size = static_cast<unsigned int>(sizeof(unsigned int) * m_n_ubo_uints);
6470
6471         m_gl.genBuffers(1, &m_tf_bo);
6472         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenBuffers() call failed.");
6473
6474         m_gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_tf_bo);
6475         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
6476
6477         m_gl.bufferStorage(GL_TRANSFORM_FEEDBACK_BUFFER, tfbo_size, DE_NULL, /* data */
6478                                            GL_MAP_READ_BIT);
6479         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferStorage() call failed.");
6480
6481         /* Set up the UBO contents. We're actually setting up an immutable BO here,
6482          * but we'll use its contents for a copy op, executed at the beginning of
6483          * each iteration.
6484          */
6485         unsigned int* ubo_data_traveller_ptr = DE_NULL;
6486
6487         DE_ASSERT((m_sparse_bo_data_size % sizeof(unsigned int)) == 0);
6488
6489         m_ubo_data                         = new (std::nothrow) unsigned char[m_sparse_bo_data_size];
6490         ubo_data_traveller_ptr = (unsigned int*)m_ubo_data;
6491
6492         for (unsigned int n_vertex = 0; n_vertex < m_sparse_bo_data_size / (4 * sizeof(unsigned int)); ++n_vertex)
6493         {
6494                 *ubo_data_traveller_ptr = n_vertex;
6495                 ubo_data_traveller_ptr += 4;
6496         }
6497
6498         m_gl.genBuffers(1, &m_helper_bo);
6499         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenBuffers() call failed.");
6500
6501         m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_helper_bo);
6502         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
6503
6504         /* Set up helper BO storage */
6505         m_gl.bufferStorage(GL_COPY_READ_BUFFER, m_sparse_bo_data_size, m_ubo_data, 0); /* flags */
6506         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferStorage() call failed.");
6507
6508         /* Set up the VAO */
6509         m_gl.genVertexArrays(1, &m_vao);
6510         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenVertexArrays() call failed.");
6511
6512         m_gl.bindVertexArray(m_vao);
6513         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindVertexArray() call failed.");
6514
6515         return true;
6516 }
6517
6518 /** Initializes GL objects which are needed for a single test case iteration.
6519  *
6520  *  deinitTestCaseIteration() will be called after the test case is executed in ::execute()
6521  *  to release these objects.
6522  **/
6523 bool UniformBufferStorageTestCase::initTestCaseIteration(glw::GLuint sparse_bo)
6524 {
6525         bool result = true;
6526
6527         /* Cache the BO id, if not cached already */
6528         DE_ASSERT(m_sparse_bo == 0 || m_sparse_bo == sparse_bo);
6529
6530         m_sparse_bo = sparse_bo;
6531
6532         /* Set up the sparse buffer bindings. */
6533         m_gl.bindBuffer(GL_COPY_WRITE_BUFFER, m_sparse_bo);
6534         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call(s) failed.");
6535
6536         m_gl.bindBuffer(GL_COPY_READ_BUFFER, m_helper_bo);
6537         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
6538
6539         m_gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_tf_bo);
6540         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() call failed.");
6541
6542         return result;
6543 }
6544
6545 /** Constructor.
6546  *
6547  *  @param context     Rendering context
6548  *  @param name        Test name
6549  *  @param description Test description
6550  */
6551 BufferStorageTest::BufferStorageTest(deqp::Context& context)
6552         : TestCase(context, "BufferStorageTest", "Tests various interactions between sparse buffers and other API areas")
6553         , m_sparse_bo(0)
6554 {
6555         /* Left blank intentionally */
6556 }
6557
6558 /** Tears down any GL objects set up to run the test. */
6559 void BufferStorageTest::deinit()
6560 {
6561         const glw::Functions& gl = m_context.getRenderContext().getFunctions();
6562
6563         /* De-initialize all test the test cases */
6564         for (TestCasesVectorIterator itTestCase = m_testCases.begin(); itTestCase != m_testCases.end(); ++itTestCase)
6565         {
6566                 (*itTestCase)->deinitTestCaseGlobal();
6567
6568                 delete (*itTestCase);
6569         } /* for (all registered test case objects) */
6570
6571         m_testCases.clear();
6572
6573         if (m_sparse_bo != 0)
6574         {
6575                 gl.deleteBuffers(1, &m_sparse_bo);
6576
6577                 m_sparse_bo = 0;
6578         }
6579 }
6580
6581 /** Stub init method */
6582 void BufferStorageTest::init()
6583 {
6584         /* We cannot initialize the test case objects here as there are cases where there
6585          * is no rendering context bound to the thread, when this method is called. */
6586 }
6587
6588 /** Fills m_testCases with BufferStorageTestCase instances which implement the sub-cases
6589  *  for the second test described in the CTS_ARB_sparse_buffer test specification
6590  **/
6591 void BufferStorageTest::initTestCases()
6592 {
6593         const glw::Functions& gl                = m_context.getRenderContext().getFunctions();
6594         glw::GLint                        page_size = 0;
6595
6596         /* Retrieve "sparse buffer" GL constant values and entry-point func ptrs */
6597         gl.getIntegerv(GL_SPARSE_BUFFER_PAGE_SIZE_ARB, &page_size);
6598         GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_SPARSE_BUFFER_PAGE_SIZE_ARB pname");
6599
6600         /* Initialize all test case objects:
6601          *
6602          * Test cases a1-a6 */
6603         m_testCases.push_back(new QuadsBufferStorageTestCase(
6604                 gl, m_testCtx, page_size, QuadsBufferStorageTestCase::IBO_USAGE_NONE, false)); /* use_color_data */
6605         m_testCases.push_back(new QuadsBufferStorageTestCase(
6606                 gl, m_testCtx, page_size, QuadsBufferStorageTestCase::IBO_USAGE_INDEXED_DRAW_CALL, false)); /* use_color_data */
6607         m_testCases.push_back(new QuadsBufferStorageTestCase(gl, m_testCtx, page_size,
6608                                                                                                                  QuadsBufferStorageTestCase::IBO_USAGE_INDEXED_RANGED_DRAW_CALL,
6609                                                                                                                  false)); /* use_color_data */
6610         m_testCases.push_back(new QuadsBufferStorageTestCase(
6611                 gl, m_testCtx, page_size, QuadsBufferStorageTestCase::IBO_USAGE_INDEXED_DRAW_CALL, true)); /* use_color_data */
6612         m_testCases.push_back(new QuadsBufferStorageTestCase(gl, m_testCtx, page_size,
6613                                                                                                                  QuadsBufferStorageTestCase::IBO_USAGE_INDEXED_RANGED_DRAW_CALL,
6614                                                                                                                  true)); /* use_color_data */
6615
6616         /* Test case b1 */
6617         m_testCases.push_back(
6618                 new TransformFeedbackBufferStorageTestCase(gl, m_testCtx, page_size, true)); /* all_tf_pages_committed */
6619
6620         /* Test case b2 */
6621         m_testCases.push_back(
6622                 new TransformFeedbackBufferStorageTestCase(gl, m_testCtx, page_size, false)); /* all_tf_pages_committed */
6623
6624         /* Test case c */
6625         m_testCases.push_back(new ClearOpsBufferStorageTestCase(gl, m_testCtx, page_size));
6626
6627         /* Test case d */
6628         m_testCases.push_back(new InvalidateBufferStorageTestCase(gl, m_testCtx, page_size));
6629
6630         /* Test case e */
6631         m_testCases.push_back(
6632                 new AtomicCounterBufferStorageTestCase(gl, m_testCtx, page_size, false)); /* all_pages_committed */
6633         m_testCases.push_back(
6634                 new AtomicCounterBufferStorageTestCase(gl, m_testCtx, page_size, true)); /* all_pages_committed */
6635
6636         /* Test case f */
6637         m_testCases.push_back(new BufferTextureStorageTestCase(gl, m_context, m_testCtx, page_size));
6638
6639         /* Test case g */
6640         m_testCases.push_back(new CopyOpsBufferStorageTestCase(gl, m_testCtx, page_size));
6641
6642         /* Test case h */
6643         m_testCases.push_back(new IndirectDispatchBufferStorageTestCase(gl, m_testCtx, page_size));
6644
6645         /* Test case i */
6646         m_testCases.push_back(new SSBOStorageTestCase(gl, m_testCtx, page_size));
6647
6648         /* Test case j */
6649         m_testCases.push_back(new UniformBufferStorageTestCase(gl, m_testCtx, page_size));
6650
6651         /* Test case k */
6652         m_testCases.push_back(new PixelPackBufferStorageTestCase(gl, m_testCtx, page_size));
6653
6654         /* Test case l */
6655         m_testCases.push_back(new PixelUnpackBufferStorageTestCase(gl, m_testCtx, page_size));
6656
6657         /* Test case m */
6658         m_testCases.push_back(new QueryBufferStorageTestCase(gl, m_testCtx, page_size));
6659
6660         /* Initialize all test cases */
6661         for (TestCasesVectorIterator itTestCase = m_testCases.begin(); itTestCase != m_testCases.end(); ++itTestCase)
6662         {
6663                 (*itTestCase)->initTestCaseGlobal();
6664         }
6665 }
6666
6667 /** Executes test iteration.
6668  *
6669  *  @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
6670  */
6671 tcu::TestNode::IterateResult BufferStorageTest::iterate()
6672 {
6673         const glw::Functions& gl         = m_context.getRenderContext().getFunctions();
6674         bool                              result = true;
6675
6676         /* Only execute if the implementation supports the GL_ARB_sparse_buffer extension */
6677         if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_sparse_buffer"))
6678         {
6679                 throw tcu::NotSupportedError("GL_ARB_sparse_buffer is not supported");
6680         }
6681
6682         /* The buffer storage test cases require OpenGL 4.3 feature-set. */
6683         if (!glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 3)))
6684         {
6685                 throw tcu::NotSupportedError("GL_ARB_sparse_buffer conformance tests require OpenGL 4.3 core feature-set");
6686         }
6687
6688         /* Register & initialize the test case objects */
6689         initTestCases();
6690
6691         /* Iterate over all sparse BO flag combinations. We need to consider a total of 4 flags:
6692          *
6693          * - GL_CLIENT_STORAGE_BIT  (bit 0)
6694          * - GL_DYNAMIC_STORAGE_BIT (bit 1)
6695          * - GL_MAP_COHERENT_BIT    (bit 2)
6696          * - GL_MAP_PERSISTENT_BIT  (bit 3)
6697          *
6698          *  GL_MAP_READ_BIT and GL_MAP_WRITE_BIT are excluded, since they are incompatible
6699          *  with sparse buffers by definition.
6700          *
6701          *  GL_SPARSE_STORAGE_BIT_ARB is assumed to be always defined. Some of the combinations are invalid.
6702          *  Such loop iterations will be skipped.
6703          * */
6704
6705         for (unsigned int n_flag_combination = 0; n_flag_combination < (1 << 4); ++n_flag_combination)
6706         {
6707                 const glw::GLint flags = ((n_flag_combination & (1 << 0)) ? GL_CLIENT_STORAGE_BIT : 0) |
6708                                                                  ((n_flag_combination & (1 << 1)) ? GL_DYNAMIC_STORAGE_BIT : 0) |
6709                                                                  ((n_flag_combination & (1 << 2)) ? GL_MAP_COHERENT_BIT : 0) |
6710                                                                  ((n_flag_combination & (1 << 3)) ? GL_MAP_PERSISTENT_BIT : 0) |
6711                                                                  GL_SPARSE_STORAGE_BIT_ARB;
6712
6713                 if ((flags & GL_MAP_PERSISTENT_BIT) != 0)
6714                 {
6715                         if ((flags & GL_MAP_READ_BIT) == 0 && (flags & GL_MAP_WRITE_BIT) == 0)
6716                         {
6717                                 continue;
6718                         }
6719                 }
6720
6721                 if (((flags & GL_MAP_COHERENT_BIT) != 0) && ((flags & GL_MAP_PERSISTENT_BIT) == 0))
6722                 {
6723                         continue;
6724                 }
6725
6726                 /* Set up the sparse BO */
6727                 gl.genBuffers(1, &m_sparse_bo);
6728                 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() call failed.");
6729
6730                 gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bo);
6731                 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() call failed.");
6732
6733                 gl.bufferStorage(GL_ARRAY_BUFFER, 1024768 * 1024, /* as per test spec */
6734                                                  DE_NULL,                                                 /* data */
6735                                                  flags);
6736
6737                 GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferStorage() call failed.");
6738
6739                 for (TestCasesVectorIterator itTestCase = m_testCases.begin(); itTestCase != m_testCases.end(); ++itTestCase)
6740                 {
6741                         gl.bindBuffer(GL_ARRAY_BUFFER, m_sparse_bo);
6742                         GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() call failed.");
6743
6744                         if (!(*itTestCase)->initTestCaseIteration(m_sparse_bo))
6745                         {
6746                                 m_testCtx.getLog() << tcu::TestLog::Message << "Test case [" << (*itTestCase)->getName()
6747                                                                    << "] "
6748                                                                           "has failed to initialize."
6749                                                                    << tcu::TestLog::EndMessage;
6750
6751                                 result = false;
6752                                 goto end;
6753                         }
6754
6755                         if (!(*itTestCase)->execute(flags))
6756                         {
6757                                 m_testCtx.getLog() << tcu::TestLog::Message << "Test case [" << (*itTestCase)->getName()
6758                                                                    << "] "
6759                                                                           "has failed to execute correctly."
6760                                                                    << tcu::TestLog::EndMessage;
6761
6762                                 result = false;
6763                         } /* if (!testCaseResult) */
6764
6765                         (*itTestCase)->deinitTestCaseIteration();
6766                 } /* for (all added test cases) */
6767
6768                 /* Release the sparse BO */
6769                 gl.deleteBuffers(1, &m_sparse_bo);
6770                 GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteBuffers() call failed.");
6771
6772                 m_sparse_bo = 0;
6773         }
6774
6775 end:
6776         m_testCtx.setTestResult(result ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, result ? "Pass" : "Fail");
6777
6778         return STOP;
6779 }
6780
6781 /** Constructor.
6782  *
6783  *  @param context Rendering context.
6784  */
6785 SparseBufferTests::SparseBufferTests(deqp::Context& context)
6786         : TestCaseGroup(context, "sparse_buffer_tests", "Verify conformance of CTS_ARB_sparse_buffer implementation")
6787 {
6788 }
6789
6790 /** Initializes the test group contents. */
6791 void SparseBufferTests::init()
6792 {
6793         addChild(new BufferStorageTest(m_context));
6794         addChild(new NegativeTests(m_context));
6795         addChild(new PageSizeGetterTest(m_context));
6796 }
6797
6798 } /* gl4cts namespace */