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