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