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