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