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