1 /*-------------------------------------------------------------------------
2 * OpenGL Conformance Test Suite
3 * -----------------------------
4 *
5 * Copyright (c) 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 glcRobustBufferAccessBehaviorTests.cpp
21 * \brief Implements conformance tests for "Robust Buffer Access Behavior" functionality.
22 */ /*-------------------------------------------------------------------*/
23
24 #include "glcRobustBufferAccessBehaviorTests.hpp"
25
26 #include "deSharedPtr.hpp"
27 #include "gluContextInfo.hpp"
28 #include "gluDefs.hpp"
29 #include "gluShaderUtil.hpp"
30 #include "glwEnums.hpp"
31 #include "glwFunctions.hpp"
32 #include "tcuCommandLine.hpp"
33 #include "tcuStringTemplate.hpp"
34 #include "tcuTestLog.hpp"
35
36 #include <cstring>
37 #include <string>
38
39 using namespace glw;
40
41 namespace glcts
42 {
43 namespace RobustBufferAccessBehavior
44 {
45 /* Buffer constants */
46 const GLuint Buffer::m_invalid_id = -1;
47
48 const GLenum Buffer::m_targets[Buffer::m_n_targets] = {
49 GL_ARRAY_BUFFER, /* 0 */
50 GL_ATOMIC_COUNTER_BUFFER, /* 1 */
51 GL_COPY_READ_BUFFER, /* 2 */
52 GL_COPY_WRITE_BUFFER, /* 3 */
53 GL_DISPATCH_INDIRECT_BUFFER, /* 4 */
54 GL_DRAW_INDIRECT_BUFFER, /* 5 */
55 GL_ELEMENT_ARRAY_BUFFER, /* 6 */
56 GL_PIXEL_PACK_BUFFER, /* 7 */
57 GL_PIXEL_UNPACK_BUFFER, /* 8 */
58 GL_QUERY_BUFFER, /* 9 */
59 GL_SHADER_STORAGE_BUFFER, /* 10 */
60 GL_TRANSFORM_FEEDBACK_BUFFER, /* 11 */
61 GL_UNIFORM_BUFFER, /* 12 */
62 };
63
64 /** Constructor.
65 *
66 * @param context CTS context.
67 **/
Buffer(const glw::Functions & gl)68 Buffer::Buffer(const glw::Functions& gl) : m_id(m_invalid_id), m_gl(gl), m_target(GL_ARRAY_BUFFER)
69 {
70 }
71
72 /** Destructor
73 *
74 **/
~Buffer()75 Buffer::~Buffer()
76 {
77 Release();
78 }
79
80 /** Initialize buffer instance
81 *
82 * @param target Buffer target
83 * @param usage Buffer usage enum
84 * @param size <size> parameter
85 * @param data <data> parameter
86 **/
InitData(glw::GLenum target,glw::GLenum usage,glw::GLsizeiptr size,const glw::GLvoid * data)87 void Buffer::InitData(glw::GLenum target, glw::GLenum usage, glw::GLsizeiptr size, const glw::GLvoid* data)
88 {
89 /* Delete previous buffer instance */
90 Release();
91
92 m_target = target;
93
94 Generate(m_gl, m_id);
95 Bind(m_gl, m_id, m_target);
96 Data(m_gl, m_target, usage, size, data);
97 }
98
99 /** Release buffer instance
100 *
101 **/
Release()102 void Buffer::Release()
103 {
104 if (m_invalid_id != m_id)
105 {
106 m_gl.deleteBuffers(1, &m_id);
107 m_id = m_invalid_id;
108 }
109 }
110
111 /** Binds buffer to its target
112 *
113 **/
Bind() const114 void Buffer::Bind() const
115 {
116 Bind(m_gl, m_id, m_target);
117 }
118
119 /** Binds indexed buffer
120 *
121 * @param index <index> parameter
122 **/
BindBase(glw::GLuint index) const123 void Buffer::BindBase(glw::GLuint index) const
124 {
125 BindBase(m_gl, m_id, m_target, index);
126 }
127
128 /** Bind buffer to given target
129 *
130 * @param gl GL functions
131 * @param id Id of buffer
132 * @param target Buffer target
133 **/
Bind(const glw::Functions & gl,glw::GLuint id,glw::GLenum target)134 void Buffer::Bind(const glw::Functions& gl, glw::GLuint id, glw::GLenum target)
135 {
136 gl.bindBuffer(target, id);
137 GLU_EXPECT_NO_ERROR(gl.getError(), "BindBuffer");
138 }
139
140 /** Binds indexed buffer
141 *
142 * @param gl GL functions
143 * @param id Id of buffer
144 * @param target Buffer target
145 * @param index <index> parameter
146 **/
BindBase(const glw::Functions & gl,glw::GLuint id,glw::GLenum target,glw::GLuint index)147 void Buffer::BindBase(const glw::Functions& gl, glw::GLuint id, glw::GLenum target, glw::GLuint index)
148 {
149 gl.bindBufferBase(target, index, id);
150 GLU_EXPECT_NO_ERROR(gl.getError(), "BindBufferBase");
151 }
152
153 /** Allocate memory for buffer and sends initial content
154 *
155 * @param gl GL functions
156 * @param target Buffer target
157 * @param usage Buffer usage enum
158 * @param size <size> parameter
159 * @param data <data> parameter
160 **/
Data(const glw::Functions & gl,glw::GLenum target,glw::GLenum usage,glw::GLsizeiptr size,const glw::GLvoid * data)161 void Buffer::Data(const glw::Functions& gl, glw::GLenum target, glw::GLenum usage, glw::GLsizeiptr size,
162 const glw::GLvoid* data)
163 {
164 gl.bufferData(target, size, data, usage);
165 GLU_EXPECT_NO_ERROR(gl.getError(), "BufferData");
166 }
167
168 /** Generate buffer
169 *
170 * @param gl GL functions
171 * @param out_id Id of buffer
172 **/
Generate(const glw::Functions & gl,glw::GLuint & out_id)173 void Buffer::Generate(const glw::Functions& gl, glw::GLuint& out_id)
174 {
175 GLuint id = m_invalid_id;
176
177 gl.genBuffers(1, &id);
178 GLU_EXPECT_NO_ERROR(gl.getError(), "GenBuffers");
179
180 if (m_invalid_id == id)
181 {
182 TCU_FAIL("Got invalid id");
183 }
184
185 out_id = id;
186 }
187
188 /** Update range of buffer
189 *
190 * @param gl GL functions
191 * @param target Buffer target
192 * @param offset Offset in buffer
193 * @param size <size> parameter
194 * @param data <data> parameter
195 **/
SubData(const glw::Functions & gl,glw::GLenum target,glw::GLintptr offset,glw::GLsizeiptr size,glw::GLvoid * data)196 void Buffer::SubData(const glw::Functions& gl, glw::GLenum target, glw::GLintptr offset, glw::GLsizeiptr size,
197 glw::GLvoid* data)
198 {
199 gl.bufferSubData(target, offset, size, data);
200 GLU_EXPECT_NO_ERROR(gl.getError(), "BufferSubData");
201 }
202
203 /* Framebuffer constants */
204 const GLuint Framebuffer::m_invalid_id = -1;
205
206 /** Constructor.
207 *
208 * @param context CTS context.
209 **/
Framebuffer(const glw::Functions & gl)210 Framebuffer::Framebuffer(const glw::Functions& gl) : m_id(m_invalid_id), m_gl(gl)
211 {
212 /* Nothing to done here */
213 }
214
215 /** Destructor
216 *
217 **/
~Framebuffer()218 Framebuffer::~Framebuffer()
219 {
220 Release();
221 }
222
223 /** Release texture instance
224 *
225 **/
Release()226 void Framebuffer::Release()
227 {
228 if (m_invalid_id != m_id)
229 {
230 m_gl.deleteFramebuffers(1, &m_id);
231 m_id = m_invalid_id;
232 }
233 }
234
235 /** Attach texture to specified attachment
236 *
237 * @param gl GL functions
238 * @param target Framebuffer target
239 * @param attachment Attachment
240 * @param texture_id Texture id
241 * @param level Level of mipmap
242 * @param width Texture width
243 * @param height Texture height
244 **/
AttachTexture(const glw::Functions & gl,glw::GLenum target,glw::GLenum attachment,glw::GLuint texture_id,glw::GLint level,glw::GLuint width,glw::GLuint height)245 void Framebuffer::AttachTexture(const glw::Functions& gl, glw::GLenum target, glw::GLenum attachment,
246 glw::GLuint texture_id, glw::GLint level, glw::GLuint width, glw::GLuint height)
247 {
248 gl.framebufferTexture(target, attachment, texture_id, level);
249 GLU_EXPECT_NO_ERROR(gl.getError(), "FramebufferTexture");
250
251 gl.viewport(0 /* x */, 0 /* y */, width, height);
252 GLU_EXPECT_NO_ERROR(gl.getError(), "Viewport");
253 }
254
255 /** Binds framebuffer to DRAW_FRAMEBUFFER
256 *
257 * @param gl GL functions
258 * @param target Framebuffer target
259 * @param id ID of framebuffer
260 **/
Bind(const glw::Functions & gl,glw::GLenum target,glw::GLuint id)261 void Framebuffer::Bind(const glw::Functions& gl, glw::GLenum target, glw::GLuint id)
262 {
263 gl.bindFramebuffer(target, id);
264 GLU_EXPECT_NO_ERROR(gl.getError(), "BindFramebuffer");
265 }
266
267 /** Generate framebuffer
268 *
269 **/
Generate(const glw::Functions & gl,glw::GLuint & out_id)270 void Framebuffer::Generate(const glw::Functions& gl, glw::GLuint& out_id)
271 {
272 GLuint id = m_invalid_id;
273
274 gl.genFramebuffers(1, &id);
275 GLU_EXPECT_NO_ERROR(gl.getError(), "GenFramebuffers");
276
277 if (m_invalid_id == id)
278 {
279 TCU_FAIL("Invalid id");
280 }
281
282 out_id = id;
283 }
284
285 /* Program constants */
286 const GLuint Program::m_invalid_id = 0;
287
288 /** Constructor.
289 *
290 * @param context CTS context.
291 **/
Program(const glw::Functions & gl)292 Program::Program(const glw::Functions& gl)
293 : m_id(m_invalid_id)
294 , m_compute(gl)
295 , m_fragment(gl)
296 , m_geometry(gl)
297 , m_tess_ctrl(gl)
298 , m_tess_eval(gl)
299 , m_vertex(gl)
300 , m_gl(gl)
301 {
302 /* Nothing to be done here */
303 }
304
305 /** Destructor
306 *
307 **/
~Program()308 Program::~Program()
309 {
310 Release();
311 }
312
313 /** Initialize program instance
314 *
315 * @param compute_shader Compute shader source code
316 * @param fragment_shader Fragment shader source code
317 * @param geometry_shader Geometry shader source code
318 * @param tesselation_control_shader Tesselation control shader source code
319 * @param tesselation_evaluation_shader Tesselation evaluation shader source code
320 * @param vertex_shader Vertex shader source code
321 **/
Init(const std::string & compute_shader,const std::string & fragment_shader,const std::string & geometry_shader,const std::string & tesselation_control_shader,const std::string & tesselation_evaluation_shader,const std::string & vertex_shader)322 void Program::Init(const std::string& compute_shader, const std::string& fragment_shader,
323 const std::string& geometry_shader, const std::string& tesselation_control_shader,
324 const std::string& tesselation_evaluation_shader, const std::string& vertex_shader)
325 {
326 /* Delete previous program */
327 Release();
328
329 /* Initialize shaders */
330 m_compute.Init(GL_COMPUTE_SHADER, compute_shader);
331 m_fragment.Init(GL_FRAGMENT_SHADER, fragment_shader);
332 m_geometry.Init(GL_GEOMETRY_SHADER, geometry_shader);
333 m_tess_ctrl.Init(GL_TESS_CONTROL_SHADER, tesselation_control_shader);
334 m_tess_eval.Init(GL_TESS_EVALUATION_SHADER, tesselation_evaluation_shader);
335 m_vertex.Init(GL_VERTEX_SHADER, vertex_shader);
336
337 /* Create program, set up transform feedback and attach shaders */
338 Create(m_gl, m_id);
339 Attach(m_gl, m_id, m_compute.m_id);
340 Attach(m_gl, m_id, m_fragment.m_id);
341 Attach(m_gl, m_id, m_geometry.m_id);
342 Attach(m_gl, m_id, m_tess_ctrl.m_id);
343 Attach(m_gl, m_id, m_tess_eval.m_id);
344 Attach(m_gl, m_id, m_vertex.m_id);
345
346 /* Link program */
347 Link(m_gl, m_id);
348 }
349
350 /** Release program instance
351 *
352 **/
Release()353 void Program::Release()
354 {
355 if (m_invalid_id != m_id)
356 {
357 Use(m_gl, m_invalid_id);
358
359 m_gl.deleteProgram(m_id);
360 m_id = m_invalid_id;
361 }
362
363 m_compute.Release();
364 m_fragment.Release();
365 m_geometry.Release();
366 m_tess_ctrl.Release();
367 m_tess_eval.Release();
368 m_vertex.Release();
369 }
370
371 /** Set program as active
372 *
373 **/
Use() const374 void Program::Use() const
375 {
376 Use(m_gl, m_id);
377 }
378
379 /** Attach shader to program
380 *
381 * @param gl GL functions
382 * @param program_id Id of program
383 * @param shader_id Id of shader
384 **/
Attach(const glw::Functions & gl,glw::GLuint program_id,glw::GLuint shader_id)385 void Program::Attach(const glw::Functions& gl, glw::GLuint program_id, glw::GLuint shader_id)
386 {
387 /* Sanity checks */
388 if ((m_invalid_id == program_id) || (Shader::m_invalid_id == shader_id))
389 {
390 return;
391 }
392
393 gl.attachShader(program_id, shader_id);
394 GLU_EXPECT_NO_ERROR(gl.getError(), "AttachShader");
395 }
396
397 /** Create program instance
398 *
399 * @param gl GL functions
400 * @param out_id Id of program
401 **/
Create(const glw::Functions & gl,glw::GLuint & out_id)402 void Program::Create(const glw::Functions& gl, glw::GLuint& out_id)
403 {
404 const GLuint id = gl.createProgram();
405 GLU_EXPECT_NO_ERROR(gl.getError(), "CreateProgram");
406
407 if (m_invalid_id == id)
408 {
409 TCU_FAIL("Failed to create program");
410 }
411
412 out_id = id;
413 }
414
415 /** Link program
416 *
417 * @param gl GL functions
418 * @param id Id of program
419 **/
Link(const glw::Functions & gl,glw::GLuint id)420 void Program::Link(const glw::Functions& gl, glw::GLuint id)
421 {
422 GLint status = GL_FALSE;
423
424 gl.linkProgram(id);
425 GLU_EXPECT_NO_ERROR(gl.getError(), "LinkProgram");
426
427 /* Get link status */
428 gl.getProgramiv(id, GL_LINK_STATUS, &status);
429 GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramiv");
430
431 /* Log link error */
432 if (GL_TRUE != status)
433 {
434 glw::GLint length = 0;
435 std::string message;
436
437 /* Get error log length */
438 gl.getProgramiv(id, GL_INFO_LOG_LENGTH, &length);
439 GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramiv");
440
441 message.resize(length, 0);
442
443 /* Get error log */
444 gl.getProgramInfoLog(id, length, 0, &message[0]);
445 GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramInfoLog");
446
447 TCU_FAIL(message.c_str());
448 }
449 }
450
451 /** Use program
452 *
453 * @param gl GL functions
454 * @param id Id of program
455 **/
Use(const glw::Functions & gl,glw::GLuint id)456 void Program::Use(const glw::Functions& gl, glw::GLuint id)
457 {
458 gl.useProgram(id);
459 GLU_EXPECT_NO_ERROR(gl.getError(), "UseProgram");
460 }
461
462 /* Shader's constants */
463 const GLuint Shader::m_invalid_id = 0;
464
465 /** Constructor.
466 *
467 * @param context CTS context.
468 **/
Shader(const glw::Functions & gl)469 Shader::Shader(const glw::Functions& gl) : m_id(m_invalid_id), m_gl(gl)
470 {
471 /* Nothing to be done here */
472 }
473
474 /** Destructor
475 *
476 **/
~Shader()477 Shader::~Shader()
478 {
479 Release();
480 }
481
482 /** Initialize shader instance
483 *
484 * @param stage Shader stage
485 * @param source Source code
486 **/
Init(glw::GLenum stage,const std::string & source)487 void Shader::Init(glw::GLenum stage, const std::string& source)
488 {
489 if (true == source.empty())
490 {
491 /* No source == no shader */
492 return;
493 }
494
495 /* Delete any previous shader */
496 Release();
497
498 Create(m_gl, stage, m_id);
499 Source(m_gl, m_id, source);
500
501 Compile(m_gl, m_id);
502 }
503
504 /** Release shader instance
505 *
506 **/
Release()507 void Shader::Release()
508 {
509 if (m_invalid_id != m_id)
510 {
511 m_gl.deleteShader(m_id);
512 m_id = m_invalid_id;
513 }
514 }
515
516 /** Compile shader
517 *
518 * @param gl GL functions
519 * @param id Shader id
520 **/
Compile(const glw::Functions & gl,glw::GLuint id)521 void Shader::Compile(const glw::Functions& gl, glw::GLuint id)
522 {
523 GLint status = GL_FALSE;
524
525 /* Compile */
526 gl.compileShader(id);
527 GLU_EXPECT_NO_ERROR(gl.getError(), "CompileShader");
528
529 /* Get compilation status */
530 gl.getShaderiv(id, GL_COMPILE_STATUS, &status);
531 GLU_EXPECT_NO_ERROR(gl.getError(), "GetShaderiv");
532
533 /* Log compilation error */
534 if (GL_TRUE != status)
535 {
536 glw::GLint length = 0;
537 std::string message;
538
539 /* Error log length */
540 gl.getShaderiv(id, GL_INFO_LOG_LENGTH, &length);
541 GLU_EXPECT_NO_ERROR(gl.getError(), "GetShaderiv");
542
543 /* Prepare storage */
544 message.resize(length, 0);
545
546 /* Get error log */
547 gl.getShaderInfoLog(id, length, 0, &message[0]);
548 GLU_EXPECT_NO_ERROR(gl.getError(), "GetShaderInfoLog");
549
550 TCU_FAIL(message.c_str());
551 }
552 }
553
554 /** Create shader
555 *
556 * @param gl GL functions
557 * @param stage Shader stage
558 * @param out_id Shader id
559 **/
Create(const glw::Functions & gl,glw::GLenum stage,glw::GLuint & out_id)560 void Shader::Create(const glw::Functions& gl, glw::GLenum stage, glw::GLuint& out_id)
561 {
562 const GLuint id = gl.createShader(stage);
563 GLU_EXPECT_NO_ERROR(gl.getError(), "CreateShader");
564
565 if (m_invalid_id == id)
566 {
567 TCU_FAIL("Failed to create shader");
568 }
569
570 out_id = id;
571 }
572
573 /** Set shader's source code
574 *
575 * @param gl GL functions
576 * @param id Shader id
577 * @param source Shader source code
578 **/
Source(const glw::Functions & gl,glw::GLuint id,const std::string & source)579 void Shader::Source(const glw::Functions& gl, glw::GLuint id, const std::string& source)
580 {
581 const GLchar* code = source.c_str();
582
583 gl.shaderSource(id, 1 /* count */, &code, 0 /* lengths */);
584 GLU_EXPECT_NO_ERROR(gl.getError(), "ShaderSource");
585 }
586
587 /* Texture static fields */
588 const GLuint Texture::m_invalid_id = -1;
589
590 /** Constructor.
591 *
592 * @param context CTS context.
593 **/
Texture(const glw::Functions & gl)594 Texture::Texture(const glw::Functions& gl) : m_id(m_invalid_id), m_gl(gl)
595 {
596 /* Nothing to done here */
597 }
598
599 /** Destructor
600 *
601 **/
~Texture()602 Texture::~Texture()
603 {
604 Release();
605 }
606
607 /** Release texture instance
608 *
609 **/
Release()610 void Texture::Release()
611 {
612 if (m_invalid_id != m_id)
613 {
614 m_gl.deleteTextures(1, &m_id);
615 m_id = m_invalid_id;
616 }
617 }
618
619 /** Bind texture to target
620 *
621 * @param gl GL functions
622 * @param id Id of texture
623 * @param tex_type Type of texture
624 **/
Bind(const glw::Functions & gl,glw::GLuint id,glw::GLenum target)625 void Texture::Bind(const glw::Functions& gl, glw::GLuint id, glw::GLenum target)
626 {
627 gl.bindTexture(target, id);
628 GLU_EXPECT_NO_ERROR(gl.getError(), "BindTexture");
629 }
630
631 /** Set contents of compressed texture
632 *
633 * @param gl GL functions
634 * @param target Texture target
635 * @param level Mipmap level
636 * @param internal_format Format of data
637 * @param width Width of texture
638 * @param height Height of texture
639 * @param depth Depth of texture
640 * @param image_size Size of data
641 * @param data Buffer with image data
642 **/
CompressedImage(const glw::Functions & gl,glw::GLenum target,glw::GLint level,glw::GLenum internal_format,glw::GLuint width,glw::GLuint height,glw::GLuint depth,glw::GLsizei image_size,const glw::GLvoid * data)643 void Texture::CompressedImage(const glw::Functions& gl, glw::GLenum target, glw::GLint level,
644 glw::GLenum internal_format, glw::GLuint width, glw::GLuint height, glw::GLuint depth,
645 glw::GLsizei image_size, const glw::GLvoid* data)
646 {
647 switch (target)
648 {
649 case GL_TEXTURE_1D:
650 gl.compressedTexImage1D(target, level, internal_format, width, 0 /* border */, image_size, data);
651 GLU_EXPECT_NO_ERROR(gl.getError(), "CompressedTexImage1D");
652 break;
653 case GL_TEXTURE_1D_ARRAY:
654 case GL_TEXTURE_2D:
655 case GL_TEXTURE_RECTANGLE:
656 gl.compressedTexImage2D(target, level, internal_format, width, height, 0 /* border */, image_size, data);
657 GLU_EXPECT_NO_ERROR(gl.getError(), "CompressedTexImage2D");
658 break;
659 case GL_TEXTURE_CUBE_MAP:
660 gl.compressedTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, level, internal_format, width, height, 0 /* border */,
661 image_size, data);
662 gl.compressedTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, level, internal_format, width, height, 0 /* border */,
663 image_size, data);
664 gl.compressedTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, level, internal_format, width, height, 0 /* border */,
665 image_size, data);
666 gl.compressedTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, level, internal_format, width, height, 0 /* border */,
667 image_size, data);
668 gl.compressedTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, level, internal_format, width, height, 0 /* border */,
669 image_size, data);
670 gl.compressedTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, level, internal_format, width, height, 0 /* border */,
671 image_size, data);
672 GLU_EXPECT_NO_ERROR(gl.getError(), "CompressedTexImage2D");
673 break;
674 case GL_TEXTURE_3D:
675 case GL_TEXTURE_2D_ARRAY:
676 gl.compressedTexImage3D(target, level, internal_format, width, height, depth, 0 /* border */, image_size, data);
677 GLU_EXPECT_NO_ERROR(gl.getError(), "CompressedTexImage3D");
678 break;
679 default:
680 TCU_FAIL("Invliad enum");
681 }
682 }
683
684 /** Generate texture instance
685 *
686 * @param gl GL functions
687 * @param out_id Id of texture
688 **/
Generate(const glw::Functions & gl,glw::GLuint & out_id)689 void Texture::Generate(const glw::Functions& gl, glw::GLuint& out_id)
690 {
691 GLuint id = m_invalid_id;
692
693 gl.genTextures(1, &id);
694 GLU_EXPECT_NO_ERROR(gl.getError(), "GenTextures");
695
696 if (m_invalid_id == id)
697 {
698 TCU_FAIL("Invalid id");
699 }
700
701 out_id = id;
702 }
703
704 /** Get texture data
705 *
706 * @param gl GL functions
707 * @param target Texture target
708 * @param format Format of data
709 * @param type Type of data
710 * @param out_data Buffer for data
711 **/
GetData(const glw::Functions & gl,glw::GLint level,glw::GLenum target,glw::GLenum format,glw::GLenum type,glw::GLvoid * out_data)712 void Texture::GetData(const glw::Functions& gl, glw::GLint level, glw::GLenum target, glw::GLenum format,
713 glw::GLenum type, glw::GLvoid* out_data)
714 {
715 gl.getTexImage(target, level, format, type, out_data);
716 GLU_EXPECT_NO_ERROR(gl.getError(), "GetTexImage");
717 }
718
719 /** Get texture data
720 *
721 * @param gl GL functions
722 * @param id Texture id
723 * @param level Mipmap level
724 * @param width Texture width
725 * @param height Texture height
726 * @param format Format of data
727 * @param type Type of data
728 * @param out_data Buffer for data
729 **/
GetData(const glw::Functions & gl,glw::GLuint id,glw::GLint level,glw::GLuint width,glw::GLuint height,glw::GLenum format,glw::GLenum type,glw::GLvoid * out_data)730 void Texture::GetData(const glw::Functions& gl, glw::GLuint id, glw::GLint level, glw::GLuint width, glw::GLuint height,
731 glw::GLenum format, glw::GLenum type, glw::GLvoid* out_data)
732 {
733 GLuint fbo;
734 gl.genFramebuffers(1, &fbo);
735 GLU_EXPECT_NO_ERROR(gl.getError(), "GenFramebuffers");
736 gl.bindFramebuffer(GL_FRAMEBUFFER, fbo);
737 GLU_EXPECT_NO_ERROR(gl.getError(), "BindFramebuffer");
738 gl.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, id, level);
739 GLU_EXPECT_NO_ERROR(gl.getError(), "FramebufferTexture2D");
740
741 gl.readPixels(0, 0, width, height, format, type, out_data);
742 GLU_EXPECT_NO_ERROR(gl.getError(), "ReadPixels");
743
744 gl.bindFramebuffer(GL_FRAMEBUFFER, 0);
745 }
746
747 /** Generate texture instance
748 *
749 * @param gl GL functions
750 * @param target Texture target
751 * @param level Mipmap level
752 * @param pname Parameter to query
753 * @param param Result of query
754 **/
GetLevelParameter(const glw::Functions & gl,glw::GLenum target,glw::GLint level,glw::GLenum pname,glw::GLint * param)755 void Texture::GetLevelParameter(const glw::Functions& gl, glw::GLenum target, glw::GLint level, glw::GLenum pname,
756 glw::GLint* param)
757 {
758 gl.getTexLevelParameteriv(target, level, pname, param);
759 GLU_EXPECT_NO_ERROR(gl.getError(), "GetTexLevelParameteriv");
760 }
761
762 /** Set contents of texture
763 *
764 * @param gl GL functions
765 * @param target Texture target
766 * @param level Mipmap level
767 * @param internal_format Format of data
768 * @param width Width of texture
769 * @param height Height of texture
770 * @param depth Depth of texture
771 * @param format Format of data
772 * @param type Type of data
773 * @param data Buffer with image data
774 **/
Image(const glw::Functions & gl,glw::GLenum target,glw::GLint level,glw::GLenum internal_format,glw::GLuint width,glw::GLuint height,glw::GLuint depth,glw::GLenum format,glw::GLenum type,const glw::GLvoid * data)775 void Texture::Image(const glw::Functions& gl, glw::GLenum target, glw::GLint level, glw::GLenum internal_format,
776 glw::GLuint width, glw::GLuint height, glw::GLuint depth, glw::GLenum format, glw::GLenum type,
777 const glw::GLvoid* data)
778 {
779 switch (target)
780 {
781 case GL_TEXTURE_1D:
782 gl.texImage1D(target, level, internal_format, width, 0 /* border */, format, type, data);
783 GLU_EXPECT_NO_ERROR(gl.getError(), "TexImage1D");
784 break;
785 case GL_TEXTURE_1D_ARRAY:
786 case GL_TEXTURE_2D:
787 case GL_TEXTURE_RECTANGLE:
788 gl.texImage2D(target, level, internal_format, width, height, 0 /* border */, format, type, data);
789 GLU_EXPECT_NO_ERROR(gl.getError(), "TexImage2D");
790 break;
791 case GL_TEXTURE_CUBE_MAP:
792 gl.texImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, level, internal_format, width, height, 0 /* border */, format,
793 type, data);
794 gl.texImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, level, internal_format, width, height, 0 /* border */, format,
795 type, data);
796 gl.texImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, level, internal_format, width, height, 0 /* border */, format,
797 type, data);
798 gl.texImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, level, internal_format, width, height, 0 /* border */, format,
799 type, data);
800 gl.texImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, level, internal_format, width, height, 0 /* border */, format,
801 type, data);
802 gl.texImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, level, internal_format, width, height, 0 /* border */, format,
803 type, data);
804 GLU_EXPECT_NO_ERROR(gl.getError(), "TexImage2D");
805 break;
806 case GL_TEXTURE_3D:
807 case GL_TEXTURE_2D_ARRAY:
808 gl.texImage3D(target, level, internal_format, width, height, depth, 0 /* border */, format, type, data);
809 GLU_EXPECT_NO_ERROR(gl.getError(), "TexImage3D");
810 break;
811 default:
812 TCU_FAIL("Invliad enum");
813 }
814 }
815
816 /** Allocate storage for texture
817 *
818 * @param gl GL functions
819 * @param target Texture target
820 * @param levels Number of levels
821 * @param internal_format Internal format of texture
822 * @param width Width of texture
823 * @param height Height of texture
824 * @param depth Depth of texture
825 **/
Storage(const glw::Functions & gl,glw::GLenum target,glw::GLsizei levels,glw::GLenum internal_format,glw::GLuint width,glw::GLuint height,glw::GLuint depth)826 void Texture::Storage(const glw::Functions& gl, glw::GLenum target, glw::GLsizei levels, glw::GLenum internal_format,
827 glw::GLuint width, glw::GLuint height, glw::GLuint depth)
828 {
829 switch (target)
830 {
831 case GL_TEXTURE_1D:
832 gl.texStorage1D(target, levels, internal_format, width);
833 GLU_EXPECT_NO_ERROR(gl.getError(), "TexStorage1D");
834 break;
835 case GL_TEXTURE_1D_ARRAY:
836 case GL_TEXTURE_2D:
837 case GL_TEXTURE_RECTANGLE:
838 case GL_TEXTURE_CUBE_MAP:
839 gl.texStorage2D(target, levels, internal_format, width, height);
840 GLU_EXPECT_NO_ERROR(gl.getError(), "TexStorage2D");
841 break;
842 case GL_TEXTURE_2D_MULTISAMPLE:
843 gl.texStorage2DMultisample(target, levels, internal_format, width, height, GL_FALSE);
844 GLU_EXPECT_NO_ERROR(gl.getError(), "TexStorage2DMultisample");
845 break;
846 case GL_TEXTURE_3D:
847 case GL_TEXTURE_2D_ARRAY:
848 gl.texStorage3D(target, levels, internal_format, width, height, depth);
849 GLU_EXPECT_NO_ERROR(gl.getError(), "TexStorage3D");
850 break;
851 default:
852 TCU_FAIL("Invliad enum");
853 }
854 }
855
856 /** Set contents of texture
857 *
858 * @param gl GL functions
859 * @param target Texture target
860 * @param level Mipmap level
861 * @param x X offset
862 * @param y Y offset
863 * @param z Z offset
864 * @param width Width of texture
865 * @param height Height of texture
866 * @param depth Depth of texture
867 * @param format Format of data
868 * @param type Type of data
869 * @param pixels Buffer with image data
870 **/
SubImage(const glw::Functions & gl,glw::GLenum target,glw::GLint level,glw::GLint x,glw::GLint y,glw::GLint z,glw::GLsizei width,glw::GLsizei height,glw::GLsizei depth,glw::GLenum format,glw::GLenum type,const glw::GLvoid * pixels)871 void Texture::SubImage(const glw::Functions& gl, glw::GLenum target, glw::GLint level, glw::GLint x, glw::GLint y,
872 glw::GLint z, glw::GLsizei width, glw::GLsizei height, glw::GLsizei depth, glw::GLenum format,
873 glw::GLenum type, const glw::GLvoid* pixels)
874 {
875 switch (target)
876 {
877 case GL_TEXTURE_1D:
878 gl.texSubImage1D(target, level, x, width, format, type, pixels);
879 GLU_EXPECT_NO_ERROR(gl.getError(), "TexSubImage1D");
880 break;
881 case GL_TEXTURE_1D_ARRAY:
882 case GL_TEXTURE_2D:
883 case GL_TEXTURE_RECTANGLE:
884 gl.texSubImage2D(target, level, x, y, width, height, format, type, pixels);
885 GLU_EXPECT_NO_ERROR(gl.getError(), "TexSubImage2D");
886 break;
887 case GL_TEXTURE_CUBE_MAP:
888 gl.texSubImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, level, x, y, width, height, format, type, pixels);
889 gl.texSubImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, level, x, y, width, height, format, type, pixels);
890 gl.texSubImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, level, x, y, width, height, format, type, pixels);
891 gl.texSubImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, level, x, y, width, height, format, type, pixels);
892 gl.texSubImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, level, x, y, width, height, format, type, pixels);
893 gl.texSubImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, level, x, y, width, height, format, type, pixels);
894 GLU_EXPECT_NO_ERROR(gl.getError(), "TexSubImage2D");
895 break;
896 case GL_TEXTURE_3D:
897 case GL_TEXTURE_2D_ARRAY:
898 gl.texSubImage3D(target, level, x, y, z, width, height, depth, format, type, pixels);
899 GLU_EXPECT_NO_ERROR(gl.getError(), "TexSubImage3D");
900 break;
901 default:
902 TCU_FAIL("Invliad enum");
903 }
904 }
905
906 /* VertexArray constants */
907 const GLuint VertexArray::m_invalid_id = -1;
908
909 /** Constructor.
910 *
911 * @param context CTS context.
912 **/
VertexArray(const glw::Functions & gl)913 VertexArray::VertexArray(const glw::Functions& gl) : m_id(m_invalid_id), m_gl(gl)
914 {
915 }
916
917 /** Destructor
918 *
919 **/
~VertexArray()920 VertexArray::~VertexArray()
921 {
922 Release();
923 }
924
925 /** Release vertex array object instance
926 *
927 **/
Release()928 void VertexArray::Release()
929 {
930 if (m_invalid_id != m_id)
931 {
932 Bind(m_gl, 0);
933
934 m_gl.deleteVertexArrays(1, &m_id);
935
936 m_id = m_invalid_id;
937 }
938 }
939
940 /** Binds Vertex array object
941 *
942 * @param gl GL functions
943 * @param id ID of vertex array object
944 **/
Bind(const glw::Functions & gl,glw::GLuint id)945 void VertexArray::Bind(const glw::Functions& gl, glw::GLuint id)
946 {
947 gl.bindVertexArray(id);
948 GLU_EXPECT_NO_ERROR(gl.getError(), "BindVertexArray");
949 }
950
951 /** Generates Vertex array object
952 *
953 * @param gl GL functions
954 * @param out_id ID of vertex array object
955 **/
Generate(const glw::Functions & gl,glw::GLuint & out_id)956 void VertexArray::Generate(const glw::Functions& gl, glw::GLuint& out_id)
957 {
958 GLuint id = m_invalid_id;
959
960 gl.genVertexArrays(1, &id);
961 GLU_EXPECT_NO_ERROR(gl.getError(), "GenVertexArrays");
962
963 if (m_invalid_id == id)
964 {
965 TCU_FAIL("Invalid id");
966 }
967
968 out_id = id;
969 }
970
971 template <typename TYPE>
initPixels(std::vector<TYPE> & pixels,GLuint n_pixels,GLuint n_channels)972 void initPixels(std::vector<TYPE>& pixels, GLuint n_pixels, GLuint n_channels)
973 {
974 if (n_channels == 1)
975 {
976 for (GLuint i = 0; i < n_pixels; ++i)
977 pixels[i] = static_cast<TYPE>(i);
978 }
979 else if (n_channels == 2)
980 {
981 for (GLuint i = 0; i < n_pixels; ++i)
982 {
983 GLuint idx = i * 2;
984 pixels[idx] = static_cast<TYPE>(i);
985 pixels[idx + 1] = pixels[idx];
986 }
987 }
988 else if (n_channels == 4)
989 {
990 for (GLuint i = 0; i < n_pixels; ++i)
991 {
992 GLuint idx = i * 4;
993 pixels[idx] = static_cast<TYPE>(i);
994 pixels[idx + 1] = pixels[idx];
995 pixels[idx + 2] = pixels[idx];
996 pixels[idx + 3] = pixels[idx];
997 }
998 }
999 else
1000 TCU_FAIL("Unsuported number of channels");
1001 }
1002
RobustnessBase(tcu::TestContext & testCtx,const char * name,const char * description,glu::ApiType apiType)1003 RobustnessBase::RobustnessBase(tcu::TestContext& testCtx, const char* name, const char* description,
1004 glu::ApiType apiType)
1005 : tcu::TestCase(testCtx, name, description), m_api_type(apiType), m_context_is_es(false), m_has_khr_robust_buffer_access(false)
1006 {
1007 }
1008
createRobustContext(glu::ResetNotificationStrategy reset)1009 glu::RenderContext* RobustnessBase::createRobustContext(glu::ResetNotificationStrategy reset)
1010 {
1011 // Create test context to verify if required extensions are available
1012 {
1013 deqp::Context context(m_testCtx, glu::ContextType(m_api_type));
1014 const glu::ContextInfo& contextInfo = context.getContextInfo();
1015 glu::ContextType context_type = context.getRenderContext().getType();
1016 if (!contextInfo.isExtensionSupported("GL_KHR_robustness") &&
1017 !contextSupports(context_type, glu::ApiType::es(3, 2)))
1018 {
1019 m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "GL_KHR_robustness extension not supported");
1020 return NULL;
1021 }
1022
1023 m_has_khr_robust_buffer_access = contextInfo.isExtensionSupported("GL_KHR_robust_buffer_access_behavior") ||
1024 contextInfo.isExtensionSupported("GL_ARB_robust_buffer_access_behavior") ||
1025 contextSupports(context_type, glu::ApiType::core(4, 5));
1026 if (!m_has_khr_robust_buffer_access && !contextSupports(context_type, glu::ApiType::core(4, 3)))
1027 {
1028 m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED,
1029 "robust_buffer_access_behavior extension not supported");
1030 return NULL;
1031 }
1032
1033 glu::GLSLVersion glslVersion = glu::getContextTypeGLSLVersion(context_type);
1034 m_specializationMap["VERSION"] = glu::getGLSLVersionDeclaration(glslVersion);
1035 m_context_is_es = glu::isContextTypeES(context_type);
1036 }
1037
1038 glu::RenderConfig renderCfg(glu::ContextType(m_api_type, glu::CONTEXT_ROBUST));
1039 const tcu::CommandLine& commandLine = m_testCtx.getCommandLine();
1040 glu::parseRenderConfig(&renderCfg, commandLine);
1041
1042 if (commandLine.getSurfaceType() == tcu::SURFACETYPE_WINDOW)
1043 renderCfg.resetNotificationStrategy = reset;
1044 else
1045 throw tcu::NotSupportedError("Test not supported in non-windowed context");
1046
1047 /* Try to create core/es robusness context */
1048 return createRenderContext(m_testCtx.getPlatform(), commandLine, renderCfg);
1049 }
1050
1051 /** Constructor
1052 *
1053 * @param testCtx Test context
1054 **/
VertexBufferObjectsTest(tcu::TestContext & testCtx,glu::ApiType apiType)1055 VertexBufferObjectsTest::VertexBufferObjectsTest(tcu::TestContext& testCtx, glu::ApiType apiType)
1056 : RobustnessBase(testCtx, "vertex_buffer_objects", "Verifies that out-of-bound reads from VB result in zero",
1057 apiType)
1058 {
1059 /* Nothing to be done */
1060 }
1061
1062 /** Execute test
1063 *
1064 * @return tcu::TestNode::STOP
1065 **/
iterate()1066 tcu::TestNode::IterateResult VertexBufferObjectsTest::iterate()
1067 {
1068 de::SharedPtr<glu::RenderContext> robustContext(createRobustContext());
1069 if (!robustContext.get())
1070 return STOP;
1071
1072 static const GLuint invalid_elements[] = {
1073 9, 1, 12, 10, 2, 3, 11, 3, 4, 12, 4, 5, 13, 5, 6, 14, 6, 7, 15, 7, 8, 16, 8, 1,
1074 };
1075
1076 static const GLuint valid_elements[] = {
1077 0, 1, 2, 0, 2, 3, 0, 3, 4, 0, 4, 5, 0, 5, 6, 0, 6, 7, 0, 7, 8, 0, 8, 1,
1078 };
1079
1080 static const GLfloat vertices[] = {
1081 0.0f, 0.0f, 0.0f, /* 0 */
1082 -1.0f, 0.0f, 0.0f, /* 1 */
1083 -1.0f, 1.0f, 0.0f, /* 2 */
1084 0.0f, 1.0f, 0.0f, /* 3 */
1085 1.0f, 1.0f, 0.0f, /* 4 */
1086 1.0f, 0.0f, 0.0f, /* 5 */
1087 1.0f, -1.0f, 0.0f, /* 6 */
1088 0.0f, -1.0f, 0.0f, /* 7 */
1089 -1.0f, -1.0f, 0.0f, /* 8 */
1090 };
1091
1092 static const GLuint height = 8;
1093 static const GLuint n_vertices = 24;
1094 static const GLuint width = 8;
1095
1096 /* GL entry points */
1097 const Functions& gl = robustContext->getFunctions();
1098
1099 /* Test case objects */
1100 Framebuffer framebuffer(gl);
1101 Program program(gl);
1102 Texture texture(gl);
1103 Buffer elements_buffer(gl);
1104 Buffer vertices_buffer(gl);
1105 VertexArray vao(gl);
1106
1107 /* Vertex array */
1108 VertexArray::Generate(gl, vao.m_id);
1109 VertexArray::Bind(gl, vao.m_id);
1110
1111 /* Buffers initialization */
1112 elements_buffer.InitData(GL_ELEMENT_ARRAY_BUFFER, GL_DYNAMIC_DRAW, sizeof(valid_elements), valid_elements);
1113 vertices_buffer.InitData(GL_ARRAY_BUFFER, GL_DYNAMIC_DRAW, sizeof(vertices), vertices);
1114
1115 /* Texture initialization */
1116 Texture::Generate(gl, texture.m_id);
1117 Texture::Bind(gl, texture.m_id, GL_TEXTURE_2D);
1118 Texture::Storage(gl, GL_TEXTURE_2D, 1, GL_R8UI, width, height, 0);
1119 Texture::Bind(gl, 0, GL_TEXTURE_2D);
1120
1121 /* Framebuffer initialization*/
1122 Framebuffer::Generate(gl, framebuffer.m_id);
1123 Framebuffer::Bind(gl, GL_DRAW_FRAMEBUFFER, framebuffer.m_id);
1124 Framebuffer::AttachTexture(gl, GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture.m_id, 0 /* level */, width,
1125 height);
1126
1127 /* Shaders initialization */
1128 program.Init("" /* cs */, getFragmentShader(), "" /* gs */, "" /* tcs */, "" /* tes */, getVertexShader());
1129 Program::Use(gl, program.m_id);
1130
1131 /* Vertex buffer initialization */
1132 vertices_buffer.Bind();
1133 gl.bindVertexBuffer(0 /* bindindex = location */, vertices_buffer.m_id, 0 /* offset */, 12 /* stride */);
1134 gl.vertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 12, NULL);
1135 gl.enableVertexAttribArray(0 /* location */);
1136
1137 /* Binding elements/indices buffer */
1138 elements_buffer.Bind();
1139
1140 cleanTexture(gl, texture.m_id);
1141
1142 gl.drawElements(GL_TRIANGLES, n_vertices, GL_UNSIGNED_INT, 0 /* indices */);
1143 GLU_EXPECT_NO_ERROR(gl.getError(), "DrawElements");
1144
1145 if (false == verifyValidResults(gl, texture.m_id))
1146 {
1147 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid result for valid input" << tcu::TestLog::EndMessage;
1148
1149 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
1150 return tcu::TestNode::STOP;
1151 }
1152
1153 /* Generate invalid data sets */
1154 const GLuint invalid_elements_offsets[] = {
1155 0, // close fetch
1156 4 * 1024, // near fetch (4K of the end of the object)
1157 1024 * 1024, // medium fetch (1MB past the end of the object)
1158 10 * 1024 * 1024 // high fetch (10MB beyond the end of the object)
1159 };
1160 const GLuint invalid_buffers_count = DE_LENGTH_OF_ARRAY(invalid_elements_offsets);
1161 const GLuint item_count = DE_LENGTH_OF_ARRAY(invalid_elements);
1162 GLuint invalid_elements_set[invalid_buffers_count][item_count];
1163 for (GLuint buffer_index = 0; buffer_index < invalid_buffers_count; ++buffer_index)
1164 {
1165 for (GLuint item_index = 0; item_index < item_count; ++item_index)
1166 invalid_elements_set[buffer_index][item_index] =
1167 invalid_elements[item_index] + invalid_elements_offsets[buffer_index];
1168 }
1169
1170 for (GLuint buffer_index = 0; buffer_index < invalid_buffers_count; ++buffer_index)
1171 {
1172 /* Create elements/indices buffer */
1173 elements_buffer.InitData(GL_ELEMENT_ARRAY_BUFFER, GL_DYNAMIC_DRAW, sizeof(invalid_elements_set[buffer_index]),
1174 invalid_elements_set[buffer_index]);
1175 elements_buffer.Bind();
1176
1177 cleanTexture(gl, texture.m_id);
1178
1179 gl.drawElements(GL_TRIANGLES, n_vertices, GL_UNSIGNED_INT, 0 /* indices */);
1180 GLU_EXPECT_NO_ERROR(gl.getError(), "DrawElements");
1181
1182 if (false == verifyInvalidResults(gl, texture.m_id))
1183 {
1184 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid result for invalid input"
1185 << tcu::TestLog::EndMessage;
1186 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
1187 return tcu::TestNode::STOP;
1188 }
1189 }
1190
1191 /* Done */
1192 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1193 return tcu::TestNode::STOP;
1194 }
1195
1196 /** Prepare shader for current test case
1197 *
1198 * @return Source
1199 **/
getFragmentShader()1200 std::string VertexBufferObjectsTest::getFragmentShader()
1201 {
1202 const char* source = "${VERSION}\n"
1203 "layout (location = 0) out lowp uvec4 out_fs_color;\n"
1204 "void main()\n"
1205 "{\n"
1206 " out_fs_color = uvec4(1, 255, 255, 255);\n"
1207 "}\n";
1208 return tcu::StringTemplate(source).specialize(m_specializationMap);
1209 }
1210
1211 /** Prepare shader for current test case
1212 *
1213 * @return Source
1214 **/
getVertexShader()1215 std::string VertexBufferObjectsTest::getVertexShader()
1216 {
1217 const char* source = "${VERSION}\n"
1218 "layout (location = 0) in vec4 in_vs_position;\n"
1219 "void main()\n"
1220 "{\n"
1221 " gl_Position = in_vs_position;\n"
1222 "}\n";
1223
1224 return tcu::StringTemplate(source).specialize(m_specializationMap);
1225 }
1226
1227 /** Fill texture with value 128
1228 *
1229 * @param texture_id Id of texture
1230 **/
cleanTexture(const Functions & gl,glw::GLuint texture_id)1231 void VertexBufferObjectsTest::cleanTexture(const Functions& gl, glw::GLuint texture_id)
1232 {
1233 static const GLuint height = 8;
1234 static const GLuint width = 8;
1235
1236 GLubyte pixels[width * height];
1237 for (GLuint i = 0; i < width * height; ++i)
1238 {
1239 pixels[i] = 128;
1240 }
1241
1242 Texture::Bind(gl, texture_id, GL_TEXTURE_2D);
1243
1244 Texture::SubImage(gl, GL_TEXTURE_2D, 0 /* level */, 0 /* x */, 0 /* y */, 0 /* z */, width, height, 0 /* depth */,
1245 GL_RED_INTEGER, GL_UNSIGNED_BYTE, pixels);
1246
1247 /* Unbind */
1248 Texture::Bind(gl, 0, GL_TEXTURE_2D);
1249 }
1250
1251 /** Verifies that texutre is not filled with 1
1252 *
1253 * @param texture_id Id of texture
1254 *
1255 * @return false when image is filled with 1, true otherwise
1256 **/
verifyInvalidResults(const Functions & gl,glw::GLuint texture_id)1257 bool VertexBufferObjectsTest::verifyInvalidResults(const Functions& gl, glw::GLuint texture_id)
1258 {
1259 // In OpenGL ES there is undefined out-of-bound behavior - no verification
1260 if (m_context_is_es)
1261 return true;
1262 return !verifyResults(gl, texture_id);
1263 }
1264
1265 /** Verifies that texutre is filled with 1
1266 *
1267 * @param texture_id Id of texture
1268 *
1269 * @return true when image is filled with 1, false otherwise
1270 **/
verifyValidResults(const Functions & gl,glw::GLuint texture_id)1271 bool VertexBufferObjectsTest::verifyValidResults(const Functions& gl, glw::GLuint texture_id)
1272 {
1273 return verifyResults(gl, texture_id);
1274 }
1275
1276 /** Verifies that texutre is filled with 1
1277 *
1278 * @param texture_id Id of texture
1279 *
1280 * @return true when image is filled with 1, false otherwise
1281 **/
verifyResults(const Functions & gl,glw::GLuint texture_id)1282 bool VertexBufferObjectsTest::verifyResults(const Functions& gl, glw::GLuint texture_id)
1283 {
1284 static const GLuint height = 8;
1285 static const GLuint width = 8;
1286 GLuint pixel_size = 4 * sizeof(GLuint);
1287 GLuint expected_value = 1;
1288
1289 std::vector<GLubyte> pixels(width * height * pixel_size, 0);
1290 Texture::Bind(gl, texture_id, GL_TEXTURE_2D);
1291 Texture::GetData(gl, texture_id, 0 /* level */, width, height, GL_RGBA_INTEGER, GL_UNSIGNED_INT, &pixels[0]);
1292 Texture::Bind(gl, 0, GL_TEXTURE_2D);
1293
1294 /* Verify */
1295 for (GLuint i = 0; i < pixels.size(); i += pixel_size)
1296 {
1297 if (expected_value != pixels[i])
1298 return false;
1299 }
1300
1301 return true;
1302 }
1303
1304 /** Constructor
1305 *
1306 * @param testCtx Test context
1307 **/
TexelFetchTest(tcu::TestContext & testCtx,glu::ApiType apiType)1308 TexelFetchTest::TexelFetchTest(tcu::TestContext& testCtx, glu::ApiType apiType)
1309 : RobustnessBase(testCtx, "texel_fetch", "Verifies that out-of-bound fetches from texture result in zero", apiType)
1310 , m_test_case(R8)
1311 {
1312 /* Nothing to be done */
1313 }
1314
1315 /** Constructor
1316 *
1317 * @param testCtx Test context
1318 * @param name Test name
1319 * @param description Test description
1320 * @param apiType Api type
1321 **/
TexelFetchTest(tcu::TestContext & testCtx,const char * name,const char * description,glu::ApiType apiType)1322 TexelFetchTest::TexelFetchTest(tcu::TestContext& testCtx, const char* name, const char* description,
1323 glu::ApiType apiType)
1324 : RobustnessBase(testCtx, name, description, apiType), m_test_case(R8)
1325 {
1326 /* Nothing to be done */
1327 }
1328
1329 /** Execute test
1330 *
1331 * @return tcu::TestNode::STOP
1332 **/
iterate()1333 tcu::TestNode::IterateResult TexelFetchTest::iterate()
1334 {
1335 de::SharedPtr<glu::RenderContext> robustContext(createRobustContext());
1336 if (!robustContext.get())
1337 return STOP;
1338
1339 /* Constants */
1340 static const GLuint height = 16;
1341 static const GLuint width = 16;
1342
1343 /* GL entry points */
1344 const Functions& gl = robustContext->getFunctions();
1345
1346 /* Test result indicator */
1347 bool test_result = true;
1348
1349 GLuint invalid_fetch_offsets[] = {
1350 16, // near fetch
1351 512, // medium fetch
1352 1008, // high fetch
1353 };
1354 GLuint fetch_offsets_count = sizeof(invalid_fetch_offsets) / sizeof(GLuint);
1355 glu::ContextType contextType = robustContext->getType();
1356
1357 /* Iterate over all cases */
1358 for (; m_test_case < LAST; m_test_case = (TEST_CASES)((GLuint)m_test_case + 1))
1359 {
1360 GLint level = 0;
1361 GLenum texture_target = GL_TEXTURE_2D;
1362
1363 if (R32UI_MULTISAMPLE == m_test_case || RG8_SNORM == m_test_case)
1364 {
1365 // 1. RG8_SNORM case:
1366 // Skip RG8_SNORM format case.
1367 // RG8_SNORM is not required to be used as a render target
1368 // OpenGL 4.5 Core Spec, Page 197
1369 //
1370 // 2. R32UI_MULTISAMPLE case
1371 // Skip test in multi sample case
1372 // texelFetch with invalid lod plane results undefined value
1373 // OpenGL 4.5 Core Spec, around page 377
1374 m_test_case = (TEST_CASES)((GLuint)m_test_case + 1);
1375 continue;
1376 }
1377
1378 /* */
1379 Texture destination_texture(gl);
1380 Framebuffer framebuffer(gl);
1381 Texture source_texture(gl);
1382 Program program(gl);
1383 VertexArray vao(gl);
1384
1385 /* Prepare VAO */
1386 VertexArray::Generate(gl, vao.m_id);
1387 VertexArray::Bind(gl, vao.m_id);
1388
1389 /* Prepare textures */
1390 Texture::Generate(gl, destination_texture.m_id);
1391 Texture::Generate(gl, source_texture.m_id);
1392
1393 if (R32UI_MULTISAMPLE == m_test_case)
1394 {
1395 GLint max_integer_samples;
1396 gl.getIntegerv(GL_MAX_INTEGER_SAMPLES, &max_integer_samples);
1397 GLint max_image_samples;
1398 gl.getIntegerv(GL_MAX_IMAGE_SAMPLES, &max_image_samples);
1399 if (max_integer_samples < 4 || max_image_samples < 4)
1400 {
1401 /* prepareTexture() hard-codes 4 samples (n_levels) for
1402 * R32UI_MULTISAMPLE case. This value exceeds the required
1403 * min-max value (1 in OpenGL ES 3.2) and is not supported
1404 * by all implementations.
1405 *
1406 * Also, the test uses a compute shader with images
1407 * to upload the texture so max_image_samples >= 4
1408 * is also required.
1409 */
1410 m_testCtx.getLog() << tcu::TestLog::Message << "Test case: " << getTestCaseName() << " not supported"
1411 << tcu::TestLog::EndMessage;
1412
1413 continue;
1414 }
1415 }
1416
1417 prepareTexture(gl, false, destination_texture.m_id);
1418 prepareTexture(gl, true, source_texture.m_id);
1419
1420 /* Select FBO settings */
1421 if (R32UI_MIPMAP == m_test_case)
1422 {
1423 level = 1;
1424 }
1425 else if (R32UI_MULTISAMPLE == m_test_case)
1426 {
1427 texture_target = GL_TEXTURE_2D_MULTISAMPLE;
1428 }
1429
1430 /* Prepare FBO */
1431 Framebuffer::Generate(gl, framebuffer.m_id);
1432 Framebuffer::Bind(gl, GL_DRAW_FRAMEBUFFER, framebuffer.m_id);
1433 Framebuffer::AttachTexture(gl, GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, destination_texture.m_id, level,
1434 width, height);
1435
1436 /* Prepare valid program */
1437 program.Init("" /* cs */, getFragmentShader(contextType, true), getGeometryShader(), "" /* tcs */, "" /* tes */,
1438 getVertexShader());
1439
1440 /* Test valid case */
1441 /* Set program */
1442 Program::Use(gl, program.m_id);
1443
1444 /* Set texture */
1445 gl.activeTexture(GL_TEXTURE0); /* location = 0 */
1446 GLU_EXPECT_NO_ERROR(gl.getError(), "ActiveTexture");
1447 Texture::Bind(gl, source_texture.m_id, texture_target);
1448 gl.uniform1i(0 /* location */, 0 /* texture unit */);
1449 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform1i");
1450
1451 /* Check if setup is supported */
1452 GLenum fbo_status = gl.checkFramebufferStatus(GL_DRAW_FRAMEBUFFER);
1453 GLU_EXPECT_NO_ERROR(gl.getError(), "CheckFramebufferStatus");
1454 if (GL_FRAMEBUFFER_COMPLETE != fbo_status)
1455 {
1456 m_testCtx.getLog() << tcu::TestLog::Message << "Test case: " << getTestCaseName() << " not supported"
1457 << tcu::TestLog::EndMessage;
1458
1459 continue;
1460 }
1461
1462 /* Enable multisampling */
1463 if (R32UI_MULTISAMPLE == m_test_case)
1464 {
1465 gl.enable(GL_MULTISAMPLE);
1466 GLU_EXPECT_NO_ERROR(gl.getError(), "Enable");
1467 }
1468
1469 /* Draw */
1470 gl.drawArrays(GL_POINTS, 0 /* first */, 1 /* count */);
1471 {
1472 /* Get error from draw */
1473 GLenum error = gl.getError();
1474
1475 /* Disable multisampling */
1476 if (R32UI_MULTISAMPLE == m_test_case)
1477 {
1478 gl.disable(GL_MULTISAMPLE);
1479 GLU_EXPECT_NO_ERROR(gl.getError(), "Disable");
1480 }
1481
1482 /* Handle error from draw */
1483 GLU_EXPECT_NO_ERROR(error, "DrawArrays");
1484 }
1485
1486 /* Verification */
1487 if (false == verifyValidResults(gl, destination_texture.m_id))
1488 {
1489 test_result = false;
1490 }
1491
1492 /* Test invalid cases */
1493 for (GLuint index = 0; index < fetch_offsets_count; ++index)
1494 {
1495 /* Prepare invalid program */
1496 program.Init("" /* cs */, getFragmentShader(contextType, false, invalid_fetch_offsets[index]),
1497 getGeometryShader(), "" /* tcs */, "" /* tes */, getVertexShader());
1498 Program::Use(gl, program.m_id);
1499 Framebuffer::Bind(gl, GL_DRAW_FRAMEBUFFER, framebuffer.m_id);
1500
1501 /* Set texture */
1502 gl.activeTexture(GL_TEXTURE0); /* location = 0 */
1503 GLU_EXPECT_NO_ERROR(gl.getError(), "ActiveTexture");
1504 Texture::Bind(gl, source_texture.m_id, texture_target);
1505 gl.uniform1i(0 /* location */, 0 /* texture unit */);
1506 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform1i");
1507
1508 /* Draw */
1509 gl.clear(GL_COLOR_BUFFER_BIT);
1510 gl.drawArrays(GL_POINTS, 0 /* first */, 1 /* count */);
1511 GLU_EXPECT_NO_ERROR(gl.getError(), "DrawArrays");
1512
1513 /* Verification */
1514 if (false == verifyInvalidResults(gl, destination_texture.m_id))
1515 {
1516 test_result = false;
1517 m_testCtx.getLog() << tcu::TestLog::Message << "Test case: " << getTestCaseName() << " failed for "
1518 << invalid_fetch_offsets[index] << " offset" << tcu::TestLog::EndMessage;
1519 }
1520 }
1521 }
1522
1523 /* Set result */
1524 if (true == test_result)
1525 {
1526 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1527 }
1528 else
1529 {
1530 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
1531 }
1532
1533 /* Done */
1534 return tcu::TestNode::STOP;
1535 }
1536
1537 /** Prepares source code for fragment shader
1538 *
1539 * @param is_case_valid Selects if valid or invalid case is tested
1540 *
1541 * @return string with prepared code
1542 **/
getFragmentShader(const glu::ContextType &,bool is_case_valid,GLuint fetch_offset)1543 std::string TexelFetchTest::getFragmentShader(const glu::ContextType&, bool is_case_valid, GLuint fetch_offset)
1544 {
1545 const GLchar* source = "${VERSION}\n"
1546 "in lowp vec2 gs_fs_tex_coord;\n"
1547 "layout (location = 0) out lowp ${TYPE} out_fs_color;\n"
1548 "layout (location = 0) uniform lowp ${SAMPLER} uni_texture;\n"
1549 "\n"
1550 "void main()\n"
1551 "{\n"
1552 " ivec2 point = ivec2(gs_fs_tex_coord * 16.0 + float(${OFFSET}));\n"
1553 " out_fs_color = texelFetch(uni_texture, point, ${PLANE});\n"
1554 "}\n";
1555
1556 m_specializationMap["PLANE"] = "0";
1557 m_specializationMap["SAMPLER"] = "sampler2D";
1558 m_specializationMap["TYPE"] = "vec4";
1559
1560 if (R32UI_MIPMAP == m_test_case)
1561 {
1562 m_specializationMap["PLANE"] = "1";
1563 m_specializationMap["SAMPLER"] = "usampler2D";
1564 m_specializationMap["TYPE"] = "uvec4";
1565
1566 if (false == is_case_valid)
1567 {
1568 fetch_offset = 0;
1569 m_specializationMap["PLANE"] = "2";
1570 }
1571 }
1572 else if (R32UI_MULTISAMPLE == m_test_case)
1573 {
1574 m_specializationMap["PLANE"] = "9";
1575 m_specializationMap["SAMPLER"] = "usampler2DMS";
1576 m_specializationMap["TYPE"] = "uvec4";
1577
1578 if (false == is_case_valid)
1579 {
1580 fetch_offset = 0;
1581 m_specializationMap["PLANE"] = "gl_SampleID";
1582 }
1583 }
1584
1585 std::stringstream offset;
1586 offset << fetch_offset;
1587 m_specializationMap["OFFSET"] = offset.str();
1588
1589 return tcu::StringTemplate(source).specialize(m_specializationMap);
1590 }
1591
1592 /** Prepare shader for current test case
1593 *
1594 * @return Source
1595 **/
getGeometryShader()1596 std::string TexelFetchTest::getGeometryShader()
1597 {
1598 static const GLchar* source = "${VERSION}\n"
1599 "layout(points) in;\n"
1600 "layout(triangle_strip, max_vertices = 4) out;\n"
1601 "\n"
1602 "out vec2 gs_fs_tex_coord;\n"
1603 "\n"
1604 "void main()\n"
1605 "{\n"
1606 " gs_fs_tex_coord = vec2(0, 0);\n"
1607 " gl_Position = vec4(-1, -1, 0, 1);\n"
1608 " EmitVertex();\n"
1609 "\n"
1610 " gs_fs_tex_coord = vec2(0, 1);\n"
1611 " gl_Position = vec4(-1, 1, 0, 1);\n"
1612 " EmitVertex();\n"
1613 "\n"
1614 " gs_fs_tex_coord = vec2(1, 0);\n"
1615 " gl_Position = vec4(1, -1, 0, 1);\n"
1616 " EmitVertex();\n"
1617 "\n"
1618 " gs_fs_tex_coord = vec2(1, 1);\n"
1619 " gl_Position = vec4(1, 1, 0, 1);\n"
1620 " EmitVertex();\n"
1621 "}\n";
1622
1623 return tcu::StringTemplate(source).specialize(m_specializationMap);
1624 }
1625
1626 /** Prepare shader for current test case
1627 *
1628 * @return Source
1629 **/
getVertexShader()1630 std::string TexelFetchTest::getVertexShader()
1631 {
1632 static const GLchar* source = "${VERSION}\n"
1633 "\n"
1634 "void main()\n"
1635 "{\n"
1636 " gl_Position = vec4(0, 0, 0, 1);\n"
1637 "}\n";
1638 return tcu::StringTemplate(source).specialize(m_specializationMap);
1639 }
1640
1641 /** Returns name of current test case
1642 *
1643 * @return Name of test case
1644 **/
getTestCaseName() const1645 const glw::GLchar* TexelFetchTest::getTestCaseName() const
1646 {
1647 const GLchar* name = "";
1648
1649 switch (m_test_case)
1650 {
1651 case R8:
1652 name = "Sampling GL_R8 texture";
1653 break;
1654 case RG8_SNORM:
1655 name = "Sampling GL_RG8_SNORM texture";
1656 break;
1657 case RGBA32F:
1658 name = "Sampling GL_RGBA32F texture";
1659 break;
1660 case R32UI_MIPMAP:
1661 name = "Sampling mipmap of GL_32UI texture";
1662 break;
1663 case R32UI_MULTISAMPLE:
1664 name = "Sampling GL_32UI multisampled texture";
1665 break;
1666 default:
1667 TCU_FAIL("Invalid enum");
1668 }
1669
1670 return name;
1671 }
1672
1673 /** Prepare a texture
1674 *
1675 * @param is_source Selects if texutre will be used as source or destination
1676 * @param texture_id Id of texutre
1677 **/
prepareTexture(const Functions & gl,bool is_source,glw::GLuint texture_id)1678 void TexelFetchTest::prepareTexture(const Functions& gl, bool is_source, glw::GLuint texture_id)
1679 {
1680 /* Image size */
1681 static const GLuint image_height = 16;
1682 static const GLuint image_width = 16;
1683
1684 /* Texture storage parameters */
1685 GLuint height = image_height;
1686 GLenum internal_format = 0;
1687 GLsizei n_levels = 1;
1688 GLenum target = GL_TEXTURE_2D;
1689 GLuint width = image_width;
1690
1691 /* Prepare texture storage parameters */
1692 switch (m_test_case)
1693 {
1694 case R8:
1695 internal_format = GL_R8;
1696 break;
1697 case RG8_SNORM:
1698 internal_format = GL_RG8_SNORM;
1699 break;
1700 case RGBA32F:
1701 internal_format = GL_RGBA32F;
1702 break;
1703 case R32UI_MIPMAP:
1704 height = 2 * image_height;
1705 internal_format = GL_R32UI;
1706 n_levels = 2;
1707 width = 2 * image_width;
1708 break;
1709 case R32UI_MULTISAMPLE:
1710 internal_format = GL_R32UI;
1711 n_levels = 4;
1712 target = GL_TEXTURE_2D_MULTISAMPLE;
1713 break;
1714 default:
1715 TCU_FAIL("Invalid enum");
1716 }
1717
1718 /* Prepare storage */
1719 Texture::Bind(gl, texture_id, target);
1720 Texture::Storage(gl, target, n_levels, internal_format, width, height, 0);
1721
1722 /* Set samplers to NEAREST/NEAREST if required. The results of texelFetch builtins
1723 are undefined if the computed level of detail is not the texture's base level and
1724 the texture's minification filter is NEAREST or LINEAR. */
1725 if (R32UI_MIPMAP == m_test_case)
1726 {
1727 gl.texParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
1728 gl.texParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1729 }
1730 else if (R32UI_MULTISAMPLE != m_test_case)
1731 {
1732 gl.texParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1733 gl.texParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1734 }
1735
1736 /* Destination image can be left empty */
1737 if (false == is_source)
1738 {
1739 Texture::Bind(gl, 0, target);
1740 return;
1741 }
1742
1743 /* Prepare texture */
1744 if (R8 == m_test_case)
1745 {
1746 GLubyte source_pixels[image_width * image_height];
1747 for (GLuint i = 0; i < image_width * image_height; ++i)
1748 {
1749 source_pixels[i] = static_cast<GLubyte>(i);
1750 }
1751
1752 Texture::SubImage(gl, GL_TEXTURE_2D, 0 /* level */, 0 /* x */, 0 /* y */, 0 /* z */, width, height,
1753 0 /* depth */, GL_RED, GL_UNSIGNED_BYTE, source_pixels);
1754 }
1755 else if (RG8_SNORM == m_test_case)
1756 {
1757 static const GLuint n_components = 2;
1758
1759 GLbyte source_pixels[image_width * image_height * n_components];
1760 for (GLuint i = 0; i < image_width * image_height; ++i)
1761 {
1762 source_pixels[i * n_components + 0] = static_cast<GLubyte>((i % 16) - 8);
1763 source_pixels[i * n_components + 1] = static_cast<GLubyte>((i / 16) - 8);
1764 }
1765
1766 Texture::SubImage(gl, GL_TEXTURE_2D, 0 /* level */, 0 /* x */, 0 /* y */, 0 /* z */, width, height,
1767 0 /* depth */, GL_RG, GL_BYTE, source_pixels);
1768 }
1769 else if (RGBA32F == m_test_case)
1770 {
1771 static const GLuint n_components = 4;
1772
1773 GLfloat source_pixels[image_width * image_height * n_components];
1774 for (GLuint i = 0; i < image_width * image_height; ++i)
1775 {
1776 source_pixels[i * n_components + 0] = (GLfloat)(i % 16) / 16.0f;
1777 source_pixels[i * n_components + 1] = (GLfloat)(i / 16) / 16.0f;
1778 source_pixels[i * n_components + 2] = (GLfloat)i / 256.0f;
1779 source_pixels[i * n_components + 3] = 1.0f;
1780 }
1781
1782 Texture::SubImage(gl, GL_TEXTURE_2D, 0 /* level */, 0 /* x */, 0 /* y */, 0 /* z */, width, height,
1783 0 /* depth */, GL_RGBA, GL_FLOAT, source_pixels);
1784 }
1785 else if (R32UI_MIPMAP == m_test_case)
1786 {
1787 GLuint source_pixels[image_width * image_height];
1788 for (GLuint i = 0; i < image_width * image_height; ++i)
1789 {
1790 source_pixels[i] = i;
1791 }
1792
1793 Texture::SubImage(gl, GL_TEXTURE_2D, 1 /* level */, 0 /* x */, 0 /* y */, 0 /* z */, image_width, image_height,
1794 0 /* depth */, GL_RED_INTEGER, GL_UNSIGNED_INT, source_pixels);
1795 }
1796 else if (R32UI_MULTISAMPLE == m_test_case)
1797 {
1798 /* Compute shader */
1799 static const GLchar* source =
1800 "${VERSION}\n"
1801 "\n"
1802 "layout (local_size_x = ${LOCAL_SIZE}, local_size_y = ${LOCAL_SIZE}, local_size_z = 1) in;\n"
1803 "layout (${QUALIFIERS}) writeonly uniform highp uimage2DMS uni_image;\n"
1804 "\n"
1805 "void main()\n"
1806 "{\n"
1807 " const ivec2 point = ivec2(gl_WorkGroupID.x, gl_WorkGroupID.y);\n"
1808 " const uint index = gl_WorkGroupID.y * 16U + gl_WorkGroupID.x;\n"
1809 "\n"
1810 " imageStore(uni_image, point, 0, uvec4(index + 0U, 0, 0, 0));\n"
1811 " imageStore(uni_image, point, 1, uvec4(index + 1U, 0, 0, 0));\n"
1812 " imageStore(uni_image, point, 2, uvec4(index + 2U, 0, 0, 0));\n"
1813 " imageStore(uni_image, point, 3, uvec4(index + 3U, 0, 0, 0));\n"
1814 "}\n"
1815 "\n";
1816
1817 if (m_context_is_es)
1818 {
1819 m_specializationMap["LOCAL_SIZE"] = "16";
1820 m_specializationMap["QUALIFIERS"] = "binding = 0, r32ui";
1821 }
1822 else
1823 {
1824 m_specializationMap["LOCAL_SIZE"] = "1";
1825 m_specializationMap["QUALIFIERS"] = "location = 0";
1826 }
1827
1828 Program program(gl);
1829 std::string cs = tcu::StringTemplate(source).specialize(m_specializationMap);
1830 program.Init(cs, "", "", "", "", "");
1831 program.Use();
1832
1833 gl.bindImageTexture(0 /* unit */, texture_id, 0 /* level */, GL_FALSE /* layered */, 0 /* layer */,
1834 GL_WRITE_ONLY, GL_R32UI);
1835 GLU_EXPECT_NO_ERROR(gl.getError(), "BindImageTexture");
1836
1837 if (!m_context_is_es)
1838 {
1839 gl.uniform1i(0 /* location */, 0 /* image unit*/);
1840 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform1i");
1841 }
1842
1843 gl.dispatchCompute(16, 16, 1);
1844 GLU_EXPECT_NO_ERROR(gl.getError(), "DispatchCompute");
1845 }
1846
1847 Texture::Bind(gl, 0, target);
1848 }
1849
1850 /** Verifies that texutre is filled with 0 or with (0, 0, 0, x),
1851 * where x may be 0, 1 or the biggest representable integer value.
1852 *
1853 * @param texture_id Id of texture
1854 *
1855 * @return true when image is filled with 0, 1 or biggest represetable integer number, false otherwise
1856 **/
verifyInvalidResults(const Functions & gl,glw::GLuint texture_id)1857 bool TexelFetchTest::verifyInvalidResults(const Functions& gl, glw::GLuint texture_id)
1858 {
1859 static const GLuint height = 16;
1860 static const GLuint width = 16;
1861 static const GLuint n_pixels = height * width;
1862
1863 // OpenGL ES has undefined out-of-bound behavior - no verification
1864 if (m_context_is_es)
1865 return true;
1866
1867 bool result = true;
1868
1869 if (R8 == m_test_case)
1870 {
1871 static const GLuint n_channels = 4;
1872
1873 std::vector<GLubyte> pixels(n_pixels * n_channels);
1874 initPixels(pixels, n_pixels, n_channels);
1875
1876 Texture::Bind(gl, texture_id, GL_TEXTURE_2D);
1877
1878 Texture::GetData(gl, 0 /* level */, GL_TEXTURE_2D, GL_RGBA, GL_UNSIGNED_BYTE, &pixels[0]);
1879
1880 /* Unbind */
1881 Texture::Bind(gl, 0, GL_TEXTURE_2D);
1882
1883 /* Verify */
1884 for (GLuint i = 0; i < n_pixels; ++i)
1885 {
1886 const GLubyte expected_red = 0;
1887 const GLubyte drawn_red = pixels[i * n_channels];
1888
1889 if (expected_red != drawn_red)
1890 {
1891 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value: " << (GLuint)drawn_red
1892 << ". Expected value: " << (GLuint)expected_red << " at offset: " << i
1893 << tcu::TestLog::EndMessage;
1894
1895 result = false;
1896 break;
1897 }
1898 }
1899 }
1900 else if (RG8_SNORM == m_test_case)
1901 {
1902 static const GLuint n_channels = 4;
1903
1904 std::vector<GLbyte> pixels(n_pixels * n_channels);
1905 initPixels(pixels, n_pixels, n_channels);
1906
1907 Texture::Bind(gl, texture_id, GL_TEXTURE_2D);
1908
1909 Texture::GetData(gl, 0 /* level */, GL_TEXTURE_2D, GL_RGBA, GL_BYTE, &pixels[0]);
1910
1911 /* Unbind */
1912 Texture::Bind(gl, 0, GL_TEXTURE_2D);
1913
1914 /* Verify */
1915 for (GLuint i = 0; i < n_pixels; ++i)
1916 {
1917 const GLbyte expected_red = 0;
1918 const GLbyte expected_green = 0;
1919 const GLbyte drawn_red = pixels[i * n_channels + 0];
1920 const GLbyte drawn_green = pixels[i * n_channels + 1];
1921
1922 if ((expected_red != drawn_red) || (expected_green != drawn_green))
1923 {
1924 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value: " << (GLint)drawn_red << ", "
1925 << (GLint)drawn_green << ". Expected value: " << (GLint)expected_red << ", "
1926 << (GLint)expected_green << ". At offset: " << i << tcu::TestLog::EndMessage;
1927
1928 result = false;
1929 break;
1930 }
1931 }
1932 }
1933 else if (RGBA32F == m_test_case)
1934 {
1935 static const GLuint n_channels = 4;
1936
1937 std::vector<GLfloat> pixels(n_pixels * n_channels);
1938 for (GLuint i = 0; i < n_pixels; ++i)
1939 {
1940 const GLuint idx = i * n_channels;
1941 const GLfloat value = static_cast<GLfloat>(i) / n_pixels;
1942 pixels[idx + 0] = value;
1943 pixels[idx + 1] = value;
1944 pixels[idx + 2] = value;
1945 pixels[idx + 3] = value;
1946 }
1947
1948 Texture::Bind(gl, texture_id, GL_TEXTURE_2D);
1949
1950 Texture::GetData(gl, 0 /* level */, GL_TEXTURE_2D, GL_RGBA, GL_FLOAT, &pixels[0]);
1951
1952 /* Unbind */
1953 Texture::Bind(gl, 0, GL_TEXTURE_2D);
1954
1955 /* Verify */
1956 for (GLuint i = 0; i < n_pixels; ++i)
1957 {
1958 const GLfloat expected_red = 0.0f;
1959 const GLfloat expected_green = 0.0f;
1960 const GLfloat expected_blue = 0.0f;
1961 const GLfloat expected_alpha_0 =
1962 0.0f; /* OpenGL 4.5 (and ES) specifies two possiblities (0 or 1) for alpha channel (Chapter 11.1.3.12). */
1963 const GLfloat expected_alpha_1 = 1.0f;
1964 const GLfloat drawn_red = pixels[i * n_channels + 0];
1965 const GLfloat drawn_green = pixels[i * n_channels + 1];
1966 const GLfloat drawn_blue = pixels[i * n_channels + 2];
1967 const GLfloat drawn_alpha = pixels[i * n_channels + 3];
1968
1969 const GLfloat precision = 0.0009765625; /* (1.f / 1024.f) */
1970
1971 if ((de::abs(expected_red - drawn_red) > precision) ||
1972 (de::abs(expected_green - drawn_green) > precision) ||
1973 (de::abs(expected_blue - drawn_blue) > precision) ||
1974 ((de::abs(expected_alpha_0 - drawn_alpha) > precision) &&
1975 (de::abs(expected_alpha_1 - drawn_alpha) > precision)))
1976 {
1977 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value: " << drawn_red << ", " << drawn_green
1978 << ", " << drawn_blue << ", " << drawn_alpha << ". Expected value: " << expected_red
1979 << ", " << expected_green << ", " << expected_blue << ", " << expected_alpha_0
1980 << " or " << expected_alpha_1 << ". At offset: " << i << tcu::TestLog::EndMessage;
1981
1982 result = false;
1983 break;
1984 }
1985 }
1986 }
1987 else if (R32UI_MIPMAP == m_test_case)
1988 {
1989 static const GLuint n_channels = 4;
1990
1991 std::vector<GLuint> pixels(n_pixels * n_channels);
1992 initPixels(pixels, n_pixels, n_channels);
1993
1994 Texture::Bind(gl, texture_id, GL_TEXTURE_2D);
1995
1996 Texture::GetData(gl, texture_id, 1 /* level */, width, height, GL_RGBA_INTEGER, GL_UNSIGNED_INT, &pixels[0]);
1997
1998 /* Unbind */
1999 Texture::Bind(gl, 0, GL_TEXTURE_2D);
2000
2001 /* Verify */
2002 for (GLuint i = 0; i < n_pixels; ++i)
2003 {
2004 const GLuint expected_red = 0;
2005 const GLuint drawn_red = pixels[i * n_channels];
2006
2007 if (expected_red != drawn_red)
2008 {
2009 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value: " << drawn_red
2010 << ". Expected value: " << expected_red << " at offset: " << i
2011 << tcu::TestLog::EndMessage;
2012
2013 result = false;
2014 break;
2015 }
2016 }
2017 }
2018 else if (R32UI_MULTISAMPLE == m_test_case)
2019 {
2020 static const GLuint n_channels = 4;
2021
2022 /* Compute shader */
2023 static const GLchar* source =
2024 "${VERSION}\n"
2025 "\n"
2026 "layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
2027 "\n"
2028 "layout (location = 1) writeonly uniform uimage2D uni_destination_image;\n"
2029 "layout (location = 0, r32ui) readonly uniform uimage2DMS uni_source_image;\n"
2030 "\n"
2031 "void main()\n"
2032 "{\n"
2033 " const ivec2 point = ivec2(gl_WorkGroupID.x, gl_WorkGroupID.y);\n"
2034 "\n"
2035 " const uvec4 color_0 = imageLoad(uni_source_image, point, 0);\n"
2036 " const uvec4 color_1 = imageLoad(uni_source_image, point, 1);\n"
2037 " const uvec4 color_2 = imageLoad(uni_source_image, point, 2);\n"
2038 " const uvec4 color_3 = imageLoad(uni_source_image, point, 3);\n"
2039 "\n"
2040 " if (any(equal(uvec4(color_0.r, color_1.r, color_2.r, color_3.r), uvec4(0))))\n"
2041 " {\n"
2042 " imageStore(uni_destination_image, point, uvec4(1, 1, 1, 1));\n"
2043 " }\n"
2044 " else\n"
2045 " {\n"
2046 " imageStore(uni_destination_image, point, uvec4(0, 0, 0, 0));\n"
2047 " }\n"
2048 "}\n"
2049 "\n";
2050
2051 Program program(gl);
2052 Texture destination_texture(gl);
2053
2054 Texture::Generate(gl, destination_texture.m_id);
2055 Texture::Bind(gl, destination_texture.m_id, GL_TEXTURE_2D);
2056 Texture::Storage(gl, GL_TEXTURE_2D, 1, GL_R32UI, width, height, 0 /* depth */);
2057
2058 std::string cs = tcu::StringTemplate(source).specialize(m_specializationMap);
2059 program.Init(cs, "", "", "", "", "");
2060 program.Use();
2061 gl.bindImageTexture(0 /* unit */, texture_id, 0 /* level */, GL_FALSE /* layered */, 0 /* layer */,
2062 GL_READ_ONLY, GL_R32UI);
2063 GLU_EXPECT_NO_ERROR(gl.getError(), "BindImageTexture");
2064 gl.bindImageTexture(1 /* unit */, destination_texture.m_id, 0 /* level */, GL_FALSE /* layered */,
2065 0 /* layer */, GL_WRITE_ONLY, GL_R32UI);
2066 GLU_EXPECT_NO_ERROR(gl.getError(), "BindImageTexture");
2067
2068 gl.uniform1i(0 /* location */, 0 /* image unit*/);
2069 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform1i");
2070
2071 gl.uniform1i(1 /* location */, 1 /* image unit*/);
2072 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform1i");
2073
2074 gl.dispatchCompute(16, 16, 1);
2075 GLU_EXPECT_NO_ERROR(gl.getError(), "DispatchCompute");
2076
2077 /* Pixels buffer initialization */
2078 std::vector<GLuint> pixels(n_pixels * n_channels);
2079 initPixels(pixels, n_pixels, n_channels);
2080
2081 Texture::GetData(gl, 0 /* level */, GL_TEXTURE_2D, GL_RGBA_INTEGER, GL_UNSIGNED_INT, &pixels[0]);
2082
2083 /* Unbind */
2084 Texture::Bind(gl, 0, GL_TEXTURE_2D);
2085
2086 /* Verify */
2087 for (GLuint i = 0; i < n_pixels; ++i)
2088 {
2089 const GLuint expected_red = 1;
2090 const GLuint drawn_red = pixels[i * n_channels];
2091
2092 if (expected_red != drawn_red)
2093 {
2094 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value: " << drawn_red
2095 << ". Expected value: " << expected_red << " at offset: " << i
2096 << tcu::TestLog::EndMessage;
2097
2098 result = false;
2099 break;
2100 }
2101 }
2102 }
2103
2104 return result;
2105 }
2106
2107 /** Verifies that texutre is filled with increasing values
2108 *
2109 * @param texture_id Id of texture
2110 *
2111 * @return true when image is filled with increasing values, false otherwise
2112 **/
verifyValidResults(const Functions & gl,glw::GLuint texture_id)2113 bool TexelFetchTest::verifyValidResults(const Functions& gl, glw::GLuint texture_id)
2114 {
2115 static const GLuint height = 16;
2116 static const GLuint width = 16;
2117 static const GLuint n_pixels = height * width;
2118
2119 bool result = true;
2120
2121 if (R8 == m_test_case)
2122 {
2123 static const GLuint n_channels = 4;
2124
2125 Texture::Bind(gl, texture_id, GL_TEXTURE_2D);
2126
2127 std::vector<GLubyte> pixels(n_pixels * n_channels);
2128 initPixels(pixels, n_pixels, n_channels);
2129
2130 Texture::GetData(gl, texture_id, 0 /* level */, width, height, GL_RGBA, GL_UNSIGNED_BYTE, &pixels[0]);
2131
2132 /* Unbind */
2133 Texture::Bind(gl, 0, GL_TEXTURE_2D);
2134
2135 /* Verify */
2136 for (GLuint i = 0; i < n_pixels; ++i)
2137 {
2138 const GLubyte expected_red = static_cast<GLubyte>(i);
2139 const GLubyte drawn_red = pixels[i * n_channels];
2140
2141 if (expected_red != drawn_red)
2142 {
2143 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value: " << (GLuint)drawn_red
2144 << ". Expected value: " << (GLuint)expected_red << " at offset: " << i
2145 << tcu::TestLog::EndMessage;
2146
2147 result = false;
2148 break;
2149 }
2150 }
2151 }
2152 else if (RG8_SNORM == m_test_case)
2153 {
2154 static const GLuint n_channels = 4;
2155
2156 Texture::Bind(gl, texture_id, GL_TEXTURE_2D);
2157
2158 std::vector<GLbyte> pixels(n_pixels * n_channels);
2159 initPixels(pixels, n_pixels, n_channels);
2160
2161 Texture::GetData(gl, texture_id, 0 /* level */, width, height, GL_RGBA, GL_BYTE, &pixels[0]);
2162
2163 /* Unbind */
2164 Texture::Bind(gl, 0, GL_TEXTURE_2D);
2165
2166 /* Verify */
2167 for (GLuint i = 0; i < n_pixels; ++i)
2168 {
2169 const GLbyte expected_red = static_cast<GLubyte>((i % 16) - 8);
2170 const GLbyte expected_green = static_cast<GLubyte>((i / 16) - 8);
2171 const GLbyte drawn_red = pixels[i * n_channels + 0];
2172 const GLbyte drawn_green = pixels[i * n_channels + 1];
2173
2174 if ((expected_red != drawn_red) || (expected_green != drawn_green))
2175 {
2176 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value: " << (GLint)drawn_red << ", "
2177 << (GLint)drawn_green << ". Expected value: " << (GLint)expected_red << ", "
2178 << (GLint)expected_green << ". At offset: " << i << tcu::TestLog::EndMessage;
2179
2180 result = false;
2181 break;
2182 }
2183 }
2184 }
2185 else if (RGBA32F == m_test_case)
2186 {
2187 static const GLuint n_channels = 4;
2188
2189 Texture::Bind(gl, texture_id, GL_TEXTURE_2D);
2190
2191 std::vector<GLfloat> pixels(n_pixels * n_channels);
2192 for (GLuint i = 0; i < n_pixels; ++i)
2193 {
2194 const GLuint idx = i * n_channels;
2195 const GLfloat value = static_cast<GLfloat>(i) / n_pixels;
2196 pixels[idx + 0] = value;
2197 pixels[idx + 1] = value;
2198 pixels[idx + 2] = value;
2199 pixels[idx + 3] = value;
2200 }
2201
2202 Texture::GetData(gl, texture_id, 0 /* level */, width, height, GL_RGBA, GL_FLOAT, &pixels[0]);
2203
2204 /* Unbind */
2205 Texture::Bind(gl, 0, GL_TEXTURE_2D);
2206
2207 /* Verify */
2208 for (GLuint i = 0; i < n_pixels; ++i)
2209 {
2210 const GLfloat expected_red = (GLfloat)(i % 16) / 16.0f;
2211 const GLfloat expected_green = (GLfloat)(i / 16) / 16.0f;
2212 const GLfloat expected_blue = (GLfloat)i / 256.0f;
2213 const GLfloat expected_alpha = 1.0f;
2214 const GLuint idx = i * n_channels;
2215 const GLfloat drawn_red = pixels[idx + 0];
2216 const GLfloat drawn_green = pixels[idx + 1];
2217 const GLfloat drawn_blue = pixels[idx + 2];
2218 const GLfloat drawn_alpha = pixels[idx + 3];
2219
2220 if ((expected_red != drawn_red) || (expected_green != drawn_green) || (expected_blue != drawn_blue) ||
2221 (expected_alpha != drawn_alpha))
2222 {
2223 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value: " << drawn_red << ", " << drawn_green
2224 << ", " << drawn_blue << ", " << drawn_alpha << ". Expected value: " << expected_red
2225 << ", " << expected_green << ", " << expected_blue << ", " << expected_alpha
2226 << ". At offset: " << i << tcu::TestLog::EndMessage;
2227
2228 result = false;
2229 break;
2230 }
2231 }
2232 }
2233 else if (R32UI_MIPMAP == m_test_case)
2234 {
2235 static const GLuint n_channels = 4;
2236
2237 Texture::Bind(gl, texture_id, GL_TEXTURE_2D);
2238
2239 std::vector<GLuint> pixels(n_pixels * n_channels, 0);
2240
2241 Texture::GetData(gl, texture_id, 1 /* level */, width, height, GL_RGBA_INTEGER, GL_UNSIGNED_INT, &pixels[0]);
2242
2243 /* Unbind */
2244 Texture::Bind(gl, 0, GL_TEXTURE_2D);
2245
2246 /* Verify */
2247 for (GLuint i = 0; i < n_pixels; ++i)
2248 {
2249 const GLuint expected_red = i;
2250 const GLuint drawn_red = pixels[i * n_channels];
2251
2252 if (expected_red != drawn_red)
2253 {
2254 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value: " << drawn_red
2255 << ". Expected value: " << expected_red << " at offset: " << i
2256 << tcu::TestLog::EndMessage;
2257
2258 result = false;
2259 break;
2260 }
2261 }
2262 }
2263 else if (R32UI_MULTISAMPLE == m_test_case)
2264 {
2265 static const GLuint n_channels = 4;
2266
2267 /* Compute shader */
2268 static const GLchar* source =
2269 "${VERSION}\n"
2270 "\n"
2271 "layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
2272 "\n"
2273 "layout (location = 1, r32ui) writeonly uniform uimage2D uni_destination_image;\n"
2274 "layout (location = 0, r32ui) readonly uniform uimage2DMS uni_source_image;\n"
2275 "\n"
2276 "void main()\n"
2277 "{\n"
2278 " const ivec2 point = ivec2(gl_WorkGroupID.x, gl_WorkGroupID.y);\n"
2279 " const uint index = gl_WorkGroupID.y * 16U + gl_WorkGroupID.x;\n"
2280 "\n"
2281 " const uvec4 color_0 = imageLoad(uni_source_image, point, 0);\n"
2282 " const uvec4 color_1 = imageLoad(uni_source_image, point, 1);\n"
2283 " const uvec4 color_2 = imageLoad(uni_source_image, point, 2);\n"
2284 " const uvec4 color_3 = imageLoad(uni_source_image, point, 3);\n"
2285 "\n"
2286 " if (any(equal(uvec4(color_0.r, color_1.r, color_2.r, color_3.r), uvec4(index + 3U))))\n"
2287 " {\n"
2288 " imageStore(uni_destination_image, point, uvec4(1U));\n"
2289 " }\n"
2290 " else\n"
2291 " {\n"
2292 " imageStore(uni_destination_image, point, uvec4(0U));\n"
2293 " }\n"
2294 "}\n"
2295 "\n";
2296
2297 Program program(gl);
2298 Texture destination_texture(gl);
2299
2300 Texture::Generate(gl, destination_texture.m_id);
2301 Texture::Bind(gl, destination_texture.m_id, GL_TEXTURE_2D);
2302 Texture::Storage(gl, GL_TEXTURE_2D, 1, GL_R32UI, width, height, 0 /* depth */);
2303
2304 std::string cs = tcu::StringTemplate(source).specialize(m_specializationMap);
2305 program.Init(cs, "", "", "", "", "");
2306 program.Use();
2307 gl.bindImageTexture(0 /* unit */, texture_id, 0 /* level */, GL_FALSE /* layered */, 0 /* layer */,
2308 GL_READ_ONLY, GL_R32UI);
2309 GLU_EXPECT_NO_ERROR(gl.getError(), "BindImageTexture");
2310 gl.bindImageTexture(1 /* unit */, destination_texture.m_id, 0 /* level */, GL_FALSE /* layered */,
2311 0 /* layer */, GL_WRITE_ONLY, GL_R32UI);
2312 GLU_EXPECT_NO_ERROR(gl.getError(), "BindImageTexture");
2313
2314 if (!m_context_is_es)
2315 {
2316 gl.uniform1i(0 /* location */, 0 /* image unit*/);
2317 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform1i");
2318
2319 gl.uniform1i(1 /* location */, 1 /* image unit*/);
2320 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform1i");
2321 }
2322
2323 gl.dispatchCompute(16, 16, 1);
2324 GLU_EXPECT_NO_ERROR(gl.getError(), "DispatchCompute");
2325
2326 /* Pixels buffer initialization */
2327 std::vector<GLuint> pixels(n_pixels * n_channels);
2328 initPixels(pixels, n_pixels, n_channels);
2329
2330 Texture::GetData(gl, destination_texture.m_id, 0 /* level */, width, height, GL_RGBA_INTEGER, GL_UNSIGNED_INT,
2331 &pixels[0]);
2332
2333 /* Unbind */
2334 Texture::Bind(gl, 0, GL_TEXTURE_2D);
2335
2336 /* Verify */
2337 for (GLuint i = 0; i < n_pixels; ++i)
2338 {
2339 const GLuint expected_red = 1;
2340 const GLuint drawn_red = pixels[i * n_channels];
2341
2342 if (expected_red != drawn_red)
2343 {
2344 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value: " << drawn_red
2345 << ". Expected value: " << expected_red << " at offset: " << i
2346 << tcu::TestLog::EndMessage;
2347
2348 result = false;
2349 break;
2350 }
2351 }
2352 }
2353
2354 return result;
2355 }
2356
2357 /** Constructor
2358 *
2359 * @param testCtx Test context
2360 * @param apiType Api type
2361 **/
ImageLoadStoreTest(tcu::TestContext & testCtx,glu::ApiType apiType)2362 ImageLoadStoreTest::ImageLoadStoreTest(tcu::TestContext& testCtx, glu::ApiType apiType)
2363 : TexelFetchTest(testCtx, "image_load_store", "Verifies that out-of-bound to image result in zero or is discarded",
2364 apiType)
2365 {
2366 }
2367
2368 /** Execute test
2369 *
2370 * @return tcu::TestNode::STOP
2371 **/
iterate()2372 tcu::TestNode::IterateResult ImageLoadStoreTest::iterate()
2373 {
2374 de::SharedPtr<glu::RenderContext> robustContext(createRobustContext());
2375 if (!robustContext.get())
2376 return STOP;
2377
2378 /* Constants */
2379 static const GLuint height = 16;
2380 static const GLuint width = 16;
2381
2382 /* GL entry points */
2383 const Functions& gl = robustContext->getFunctions();
2384
2385 struct FetchingOffset
2386 {
2387 GLuint coord_offset;
2388 GLuint sample_offset;
2389 };
2390 const FetchingOffset fetching_offsets[] = {
2391 { 16, 4 }, { 512, 4 }, { 1024, 8 }, { 2048, 8 },
2392 };
2393
2394 /* For ES start from RGBA32F as R8, R32UI_MULTISAMPLE and R8_SNORM are not supported */
2395 if (m_context_is_es)
2396 m_test_case = RGBA32F;
2397
2398 /* Test result indicator */
2399 bool test_result = true;
2400
2401 /* Iterate over all cases */
2402 for (; m_test_case < LAST; m_test_case = (TEST_CASES)((GLuint)m_test_case + 1))
2403 {
2404 /* Test case result indicator */
2405 bool case_result = true;
2406
2407 if (R32UI_MULTISAMPLE == m_test_case)
2408 {
2409 // Skip invalid program test in multi sample case
2410 // texelFetch with invalid lod plane results undefined value
2411 // OpenGL 4.5 Core Spec, around page 377
2412 continue;
2413 }
2414
2415 /* Test case objects */
2416 Texture destination_texture(gl);
2417 Texture source_texture(gl);
2418 Program program(gl);
2419
2420 /* Prepare textures */
2421 Texture::Generate(gl, destination_texture.m_id);
2422 Texture::Generate(gl, source_texture.m_id);
2423
2424 if (R32UI_MULTISAMPLE == m_test_case)
2425 {
2426 GLint max_integer_samples;
2427 gl.getIntegerv(GL_MAX_INTEGER_SAMPLES, &max_integer_samples);
2428 GLint max_image_samples;
2429 gl.getIntegerv(GL_MAX_IMAGE_SAMPLES, &max_image_samples);
2430 if (max_integer_samples < 4 || max_image_samples < 4)
2431 {
2432 /* prepareTexture() hard-codes 4 samples (n_levels) for
2433 * R32UI_MULTISAMPLE case. This value exceeds the required
2434 * min-max value (1 in OpenGL ES 3.2) and is not supported
2435 * by all implementations.
2436 *
2437 * Also, the test uses a compute shader with images
2438 * to upload the texture so max_image_samples >= 4
2439 * is also required.
2440 */
2441 m_testCtx.getLog() << tcu::TestLog::Message << "Test case: " << getTestCaseName() << " not supported"
2442 << tcu::TestLog::EndMessage;
2443 continue;
2444 }
2445 }
2446
2447 prepareTexture(gl, false, destination_texture.m_id);
2448 prepareTexture(gl, true, source_texture.m_id);
2449
2450 /* Test invalid source cases */
2451 for (GLuint i = 0; i < DE_LENGTH_OF_ARRAY(fetching_offsets); ++i)
2452 {
2453 const FetchingOffset& fo = fetching_offsets[i];
2454 const std::string& cs = getComputeShader(SOURCE_INVALID, fo.coord_offset, fo.sample_offset);
2455 program.Init(cs, "", "", "", "", "");
2456 program.Use();
2457
2458 /* Set texture */
2459 setTextures(gl, destination_texture.m_id, source_texture.m_id);
2460
2461 /* Dispatch */
2462 gl.dispatchCompute(width, height, 1 /* depth */);
2463 GLU_EXPECT_NO_ERROR(gl.getError(), "DispatchCompute");
2464
2465 /* Verification */
2466 if (false == verifyInvalidResults(gl, destination_texture.m_id))
2467 {
2468 case_result = false;
2469 }
2470 }
2471
2472 /* Test valid case */
2473 program.Init(getComputeShader(VALID), "", "", "", "", "");
2474 program.Use();
2475
2476 /* Set texture */
2477 setTextures(gl, destination_texture.m_id, source_texture.m_id);
2478
2479 /* Set memory barrier with previous invalid tests */
2480 gl.memoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
2481 GLU_EXPECT_NO_ERROR(gl.getError(), "MemoryBarrier");
2482
2483 /* Dispatch */
2484 gl.dispatchCompute(width, height, 1 /* depth */);
2485 GLU_EXPECT_NO_ERROR(gl.getError(), "DispatchCompute");
2486
2487 /* Verification */
2488 if (false == verifyValidResults(gl, destination_texture.m_id))
2489 {
2490 case_result = false;
2491 }
2492
2493 /* Test invalid destination cases */
2494 for (GLuint i = 0; i < DE_LENGTH_OF_ARRAY(fetching_offsets); ++i)
2495 {
2496 const FetchingOffset& fo = fetching_offsets[i];
2497 const std::string& cs = getComputeShader(DESTINATION_INVALID, fo.coord_offset, fo.sample_offset);
2498 program.Init(cs, "", "", "", "", "");
2499 program.Use();
2500
2501 /* Set texture */
2502 setTextures(gl, destination_texture.m_id, source_texture.m_id);
2503
2504 /* Dispatch */
2505 gl.dispatchCompute(width, height, 1 /* depth */);
2506 GLU_EXPECT_NO_ERROR(gl.getError(), "DispatchCompute");
2507
2508 /* Verification */
2509 if (false == verifyValidResults(gl, destination_texture.m_id))
2510 {
2511 case_result = false;
2512 }
2513 }
2514
2515 /* Set test result */
2516 if (false == case_result)
2517 {
2518 m_testCtx.getLog() << tcu::TestLog::Message << "Test case: " << getTestCaseName() << " failed"
2519 << tcu::TestLog::EndMessage;
2520
2521 test_result = false;
2522 }
2523 }
2524
2525 /* Set result */
2526 if (true == test_result)
2527 {
2528 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
2529 }
2530 else
2531 {
2532 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
2533 }
2534
2535 /* Done */
2536 return tcu::TestNode::STOP;
2537 }
2538
2539 /** Prepare shader for current test case
2540 *
2541 * @param version Specify which version should be prepared
2542 *
2543 * @return Source
2544 **/
getComputeShader(VERSION version,GLuint coord_offset,GLuint sample_offset)2545 std::string ImageLoadStoreTest::getComputeShader(VERSION version, GLuint coord_offset, GLuint sample_offset)
2546 {
2547 static const GLchar* source =
2548 "${VERSION}\n"
2549 "\n"
2550 "layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
2551 "\n"
2552 "layout (${QUALIFIER} = 1, ${FORMAT}) writeonly uniform highp ${IMAGE} uni_destination_image;\n"
2553 "layout (${QUALIFIER} = 0, ${FORMAT}) readonly uniform highp ${IMAGE} uni_source_image;\n"
2554 "\n"
2555 "void main()\n"
2556 "{\n"
2557 " ivec2 point_destination = ivec2(gl_WorkGroupID.xy) + ivec2(${DST_COORD_OFFSET}U);\n"
2558 " ivec2 point_source = ivec2(gl_WorkGroupID.xy) + ivec2(${SRC_COORD_OFFSET}U);\n"
2559 "\n"
2560 "${COPY}"
2561 "}\n";
2562
2563 static const GLchar* copy_multisampled =
2564 " ${TYPE} color_0 = imageLoad(uni_source_image, point_source, 0 + ${SRC_SAMPLE_OFFSET});\n"
2565 " ${TYPE} color_1 = imageLoad(uni_source_image, point_source, 1 + ${SRC_SAMPLE_OFFSET});\n"
2566 " ${TYPE} color_2 = imageLoad(uni_source_image, point_source, 2 + ${SRC_SAMPLE_OFFSET});\n"
2567 " ${TYPE} color_3 = imageLoad(uni_source_image, point_source, 3 + ${SRC_SAMPLE_OFFSET});\n"
2568 " imageStore(uni_destination_image, point_destination, 0 + ${DST_SAMPLE_OFFSET}, color_0);\n"
2569 " imageStore(uni_destination_image, point_destination, 1 + ${DST_SAMPLE_OFFSET}, color_1);\n"
2570 " imageStore(uni_destination_image, point_destination, 2 + ${DST_SAMPLE_OFFSET}, color_2);\n"
2571 " imageStore(uni_destination_image, point_destination, 3 + ${DST_SAMPLE_OFFSET}, color_3);\n";
2572
2573 static const GLchar* copy_regular = " ${TYPE} color = imageLoad(uni_source_image, point_source);\n"
2574 " imageStore(uni_destination_image, point_destination, color);\n";
2575
2576 std::string src_coord_offset_str("0");
2577 std::string dst_coord_offset_str("0");
2578 std::string src_sample_offset_str("0");
2579 std::string dst_sample_offset_str("0");
2580
2581 std::stringstream coord_offset_stream;
2582 coord_offset_stream << coord_offset;
2583 std::stringstream sample_offset_stream;
2584 sample_offset_stream << sample_offset;
2585
2586 m_specializationMap["QUALIFIER"] = m_context_is_es ? "binding" : "location";
2587 m_specializationMap["IMAGE"] = "image2D";
2588 m_specializationMap["TYPE"] = "vec4";
2589 switch (m_test_case)
2590 {
2591 case R8:
2592 m_specializationMap["FORMAT"] = "r8";
2593 break;
2594 case RG8_SNORM:
2595 m_specializationMap["FORMAT"] = "rg8_snorm";
2596 break;
2597 case RGBA32F:
2598 m_specializationMap["FORMAT"] = "rgba32f";
2599 break;
2600 case R32UI_MIPMAP:
2601 m_specializationMap["FORMAT"] = "r32ui";
2602 m_specializationMap["IMAGE"] = "uimage2D";
2603 m_specializationMap["TYPE"] = "uvec4";
2604 break;
2605 case R32UI_MULTISAMPLE:
2606 m_specializationMap["FORMAT"] = "r32ui";
2607 m_specializationMap["IMAGE"] = "uimage2DMS";
2608 m_specializationMap["TYPE"] = "uvec4";
2609 break;
2610 default:
2611 TCU_FAIL("Invalid enum");
2612 }
2613
2614 m_specializationMap["SRC_COORD_OFFSET"] = "0";
2615 m_specializationMap["SRC_SAMPLE_OFFSET"] = "0";
2616 m_specializationMap["DST_COORD_OFFSET"] = "0";
2617 m_specializationMap["DST_SAMPLE_OFFSET"] = "0";
2618
2619 if (version == SOURCE_INVALID)
2620 {
2621 m_specializationMap["SRC_COORD_OFFSET"] = coord_offset_stream.str();
2622 m_specializationMap["SRC_SAMPLE_OFFSET"] = sample_offset_stream.str();
2623 }
2624 else if (version == DESTINATION_INVALID)
2625 {
2626 m_specializationMap["DST_COORD_OFFSET"] = coord_offset_stream.str();
2627 m_specializationMap["DST_SAMPLE_OFFSET"] = sample_offset_stream.str();
2628 }
2629
2630 const GLchar* copy = (m_test_case == R32UI_MULTISAMPLE) ? copy_multisampled : copy_regular;
2631 m_specializationMap["COPY"] = tcu::StringTemplate(copy).specialize(m_specializationMap);
2632
2633 return tcu::StringTemplate(source).specialize(m_specializationMap);
2634 }
2635
2636 /** Set textures as images
2637 *
2638 * @param id_destination Id of texture used as destination
2639 * @param id_source Id of texture used as source
2640 **/
setTextures(const Functions & gl,glw::GLuint id_destination,glw::GLuint id_source)2641 void ImageLoadStoreTest::setTextures(const Functions& gl, glw::GLuint id_destination, glw::GLuint id_source)
2642 {
2643 GLenum format = 0;
2644 GLint level = 0;
2645
2646 switch (m_test_case)
2647 {
2648 case R8:
2649 format = GL_R8;
2650 break;
2651 case RG8_SNORM:
2652 format = GL_RG8_SNORM;
2653 break;
2654 case RGBA32F:
2655 format = GL_RGBA32F;
2656 break;
2657 case R32UI_MIPMAP:
2658 format = GL_R32UI;
2659 level = 1;
2660 break;
2661 case R32UI_MULTISAMPLE:
2662 format = GL_R32UI;
2663 break;
2664 default:
2665 TCU_FAIL("Invalid enum");
2666 }
2667
2668 gl.bindImageTexture(0 /* unit */, id_source, level, GL_FALSE /* layered */, 0 /* layer */, GL_READ_ONLY, format);
2669 GLU_EXPECT_NO_ERROR(gl.getError(), "BindImageTexture");
2670
2671 gl.bindImageTexture(1 /* unit */, id_destination, level, GL_FALSE /* layered */, 0 /* layer */, GL_WRITE_ONLY,
2672 format);
2673 GLU_EXPECT_NO_ERROR(gl.getError(), "BindImageTexture");
2674
2675 if (!m_context_is_es)
2676 {
2677 gl.uniform1i(0 /* location */, 0 /* image unit*/);
2678 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform1i");
2679
2680 gl.uniform1i(1 /* location */, 1 /* image unit*/);
2681 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform1i");
2682 }
2683 }
2684
2685 /** Verifies that texutre is filled with 0
2686 *
2687 * @param texture_id Id of texture
2688 *
2689 * @return true when image is filled with 0, false otherwise
2690 **/
verifyInvalidResults(const Functions & gl,glw::GLuint texture_id)2691 bool ImageLoadStoreTest::verifyInvalidResults(const Functions& gl, glw::GLuint texture_id)
2692 {
2693 static const GLuint height = 16;
2694 static const GLuint width = 16;
2695 static const GLuint n_pixels = height * width;
2696
2697 // OpenGL ES has undefined out-of-bound behavior - no verification
2698 if (m_context_is_es)
2699 return true;
2700
2701 gl.memoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
2702 GLU_EXPECT_NO_ERROR(gl.getError(), "MemoryBarrier");
2703
2704 bool result = true;
2705
2706 if (R8 == m_test_case)
2707 {
2708 static const GLuint n_channels = 1;
2709
2710 std::vector<GLubyte> pixels(n_pixels * n_channels);
2711 initPixels(pixels, n_pixels, n_channels);
2712
2713 Texture::Bind(gl, texture_id, GL_TEXTURE_2D);
2714
2715 Texture::GetData(gl, 0 /* level */, GL_TEXTURE_2D, GL_RED, GL_UNSIGNED_BYTE, &pixels[0]);
2716
2717 /* Unbind */
2718 Texture::Bind(gl, 0, GL_TEXTURE_2D);
2719
2720 /* Verify */
2721 for (GLuint i = 0; i < n_pixels; ++i)
2722 {
2723 const GLubyte expected_red = 0;
2724 const GLubyte drawn_red = pixels[i];
2725
2726 if (expected_red != drawn_red)
2727 {
2728 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value: " << (GLuint)drawn_red
2729 << ". Expected value: " << (GLuint)expected_red << " at offset: " << i
2730 << tcu::TestLog::EndMessage;
2731
2732 result = false;
2733 break;
2734 }
2735 }
2736 }
2737 else if (RG8_SNORM == m_test_case)
2738 {
2739 static const GLuint n_channels = 2;
2740
2741 std::vector<GLbyte> pixels(n_pixels * n_channels);
2742 initPixels(pixels, n_pixels, n_channels);
2743
2744 Texture::Bind(gl, texture_id, GL_TEXTURE_2D);
2745
2746 Texture::GetData(gl, 0 /* level */, GL_TEXTURE_2D, GL_RG, GL_BYTE, &pixels[0]);
2747
2748 /* Unbind */
2749 Texture::Bind(gl, 0, GL_TEXTURE_2D);
2750
2751 /* Verify */
2752 for (GLuint i = 0; i < n_pixels; ++i)
2753 {
2754 const GLbyte expected_red = 0;
2755 const GLbyte expected_green = 0;
2756 const GLbyte drawn_red = pixels[i * n_channels + 0];
2757 const GLbyte drawn_green = pixels[i * n_channels + 1];
2758
2759 if ((expected_red != drawn_red) || (expected_green != drawn_green))
2760 {
2761 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value: " << (GLint)drawn_red << ", "
2762 << (GLint)drawn_green << ". Expected value: " << (GLint)expected_red << ", "
2763 << (GLint)expected_green << ". At offset: " << i << tcu::TestLog::EndMessage;
2764
2765 result = false;
2766 break;
2767 }
2768 }
2769 }
2770 else if (RGBA32F == m_test_case)
2771 {
2772 static const GLuint n_channels = 4;
2773
2774 std::vector<GLfloat> pixels(n_pixels * n_channels);
2775 for (GLuint i = 0; i < n_pixels; ++i)
2776 {
2777 GLuint idx = i * n_channels;
2778 GLfloat value = static_cast<GLfloat>(i) / n_pixels;
2779 pixels[idx + 0] = value;
2780 pixels[idx + 1] = value;
2781 pixels[idx + 2] = value;
2782 pixels[idx + 3] = value;
2783 }
2784
2785 Texture::Bind(gl, texture_id, GL_TEXTURE_2D);
2786
2787 Texture::GetData(gl, 0 /* level */, GL_TEXTURE_2D, GL_RGBA, GL_FLOAT, &pixels[0]);
2788
2789 /* Unbind */
2790 Texture::Bind(gl, 0, GL_TEXTURE_2D);
2791
2792 /* Verify */
2793 for (GLuint i = 0; i < n_pixels; ++i)
2794 {
2795 const GLfloat expected_red = 0.0f;
2796 const GLfloat expected_green = 0.0f;
2797 const GLfloat expected_blue = 0.0f;
2798 const GLfloat expected_alpha = 0.0f;
2799 const GLuint idx = i * n_channels;
2800 const GLfloat drawn_red = pixels[idx + 0];
2801 const GLfloat drawn_green = pixels[idx + 1];
2802 const GLfloat drawn_blue = pixels[idx + 2];
2803 const GLfloat drawn_alpha = pixels[idx + 3];
2804
2805 if ((expected_red != drawn_red) || (expected_green != drawn_green) || (expected_blue != drawn_blue) ||
2806 (expected_alpha != drawn_alpha))
2807 {
2808 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value: " << drawn_red << ", " << drawn_green
2809 << ", " << drawn_blue << ", " << drawn_alpha << ". Expected value: " << expected_red
2810 << ", " << expected_green << ", " << expected_blue << ", " << expected_alpha
2811 << ". At offset: " << i << tcu::TestLog::EndMessage;
2812
2813 result = false;
2814 break;
2815 }
2816 }
2817 }
2818 else if (R32UI_MIPMAP == m_test_case)
2819 {
2820 static const GLuint n_channels = 1;
2821
2822 std::vector<GLuint> pixels(n_pixels * n_channels);
2823 initPixels(pixels, n_pixels, n_channels);
2824
2825 Texture::Bind(gl, texture_id, GL_TEXTURE_2D);
2826
2827 Texture::GetData(gl, 1 /* level */, GL_TEXTURE_2D, GL_RED_INTEGER, GL_UNSIGNED_INT, &pixels[0]);
2828
2829 /* Unbind */
2830 Texture::Bind(gl, 0, GL_TEXTURE_2D);
2831
2832 /* Verify */
2833 for (GLuint i = 0; i < n_pixels; ++i)
2834 {
2835 const GLuint expected_red = 0;
2836 const GLuint drawn_red = pixels[i];
2837
2838 if (expected_red != drawn_red)
2839 {
2840 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value: " << drawn_red
2841 << ". Expected value: " << expected_red << " at offset: " << i
2842 << tcu::TestLog::EndMessage;
2843
2844 result = false;
2845 break;
2846 }
2847 }
2848 }
2849 else if (R32UI_MULTISAMPLE == m_test_case)
2850 {
2851 static const GLuint n_channels = 1;
2852
2853 /* Compute shader */
2854 static const GLchar* cs = "${VERSION}\n"
2855 "\n"
2856 "layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
2857 "\n"
2858 "layout (location = 1) writeonly uniform uimage2D uni_destination_image;\n"
2859 "layout (location = 0, r32ui) readonly uniform uimage2DMS uni_source_image;\n"
2860 "\n"
2861 "void main()\n"
2862 "{\n"
2863 " const ivec2 point = ivec2(gl_WorkGroupID.x, gl_WorkGroupID.y);\n"
2864 "\n"
2865 " const uvec4 color_0 = imageLoad(uni_source_image, point, 0);\n"
2866 " const uvec4 color_1 = imageLoad(uni_source_image, point, 1);\n"
2867 " const uvec4 color_2 = imageLoad(uni_source_image, point, 2);\n"
2868 " const uvec4 color_3 = imageLoad(uni_source_image, point, 3);\n"
2869 "\n"
2870 " if (any(equal(uvec4(color_0.r, color_1.r, color_2.r, color_3.r), uvec4(0))))\n"
2871 " {\n"
2872 " imageStore(uni_destination_image, point, uvec4(1, 1, 1, 1));\n"
2873 " }\n"
2874 " else\n"
2875 " {\n"
2876 " imageStore(uni_destination_image, point, uvec4(0, 0, 0, 0));\n"
2877 " }\n"
2878 "}\n"
2879 "\n";
2880
2881 Program program(gl);
2882 Texture destination_texture(gl);
2883
2884 Texture::Generate(gl, destination_texture.m_id);
2885 Texture::Bind(gl, destination_texture.m_id, GL_TEXTURE_2D);
2886 Texture::Storage(gl, GL_TEXTURE_2D, 1, GL_R32UI, width, height, 0 /* depth */);
2887
2888 program.Init(cs, "", "", "", "", "");
2889 program.Use();
2890 gl.bindImageTexture(0 /* unit */, texture_id, 0 /* level */, GL_FALSE /* layered */, 0 /* layer */,
2891 GL_READ_ONLY, GL_R32UI);
2892 GLU_EXPECT_NO_ERROR(gl.getError(), "BindImageTexture");
2893 gl.bindImageTexture(1 /* unit */, destination_texture.m_id, 0 /* level */, GL_FALSE /* layered */,
2894 0 /* layer */, GL_WRITE_ONLY, GL_R32UI);
2895 GLU_EXPECT_NO_ERROR(gl.getError(), "BindImageTexture");
2896
2897 gl.uniform1i(0 /* location */, 0 /* image unit*/);
2898 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform1i");
2899
2900 gl.uniform1i(1 /* location */, 1 /* image unit*/);
2901 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform1i");
2902
2903 gl.dispatchCompute(16, 16, 1);
2904 GLU_EXPECT_NO_ERROR(gl.getError(), "DispatchCompute");
2905
2906 /* Pixels buffer initialization */
2907 std::vector<GLuint> pixels(n_pixels * n_channels);
2908 initPixels(pixels, n_pixels, n_channels);
2909
2910 Texture::GetData(gl, 0 /* level */, GL_TEXTURE_2D, GL_RED_INTEGER, GL_UNSIGNED_INT, &pixels[0]);
2911
2912 /* Unbind */
2913 Texture::Bind(gl, 0, GL_TEXTURE_2D);
2914
2915 /* Verify */
2916 for (GLuint i = 0; i < n_pixels; ++i)
2917 {
2918 const GLuint expected_red = 1;
2919 const GLuint drawn_red = pixels[i];
2920
2921 if (expected_red != drawn_red)
2922 {
2923 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value: " << drawn_red
2924 << ". Expected value: " << expected_red << " at offset: " << i
2925 << tcu::TestLog::EndMessage;
2926
2927 result = false;
2928 break;
2929 }
2930 }
2931 }
2932
2933 return result;
2934 }
2935
2936 /** Verifies that texutre is filled with increasing values
2937 *
2938 * @param texture_id Id of texture
2939 *
2940 * @return true when image is filled with increasing values, false otherwise
2941 **/
verifyValidResults(const glw::Functions & gl,glw::GLuint texture_id)2942 bool ImageLoadStoreTest::verifyValidResults(const glw::Functions& gl, glw::GLuint texture_id)
2943 {
2944 static const GLuint height = 16;
2945 static const GLuint width = 16;
2946 static const GLuint n_pixels = height * width;
2947
2948 gl.memoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
2949 GLU_EXPECT_NO_ERROR(gl.getError(), "MemoryBarrier");
2950
2951 bool result = true;
2952
2953 if (R8 == m_test_case)
2954 {
2955 static const GLuint n_channels = 1;
2956
2957 Texture::Bind(gl, texture_id, GL_TEXTURE_2D);
2958
2959 std::vector<GLubyte> pixels(n_pixels * n_channels);
2960 initPixels(pixels, n_pixels, n_channels);
2961
2962 Texture::GetData(gl, 0 /* level */, GL_TEXTURE_2D, GL_RED, GL_UNSIGNED_BYTE, &pixels[0]);
2963
2964 /* Unbind */
2965 Texture::Bind(gl, 0, GL_TEXTURE_2D);
2966
2967 /* Verify */
2968 for (GLuint i = 0; i < n_pixels; ++i)
2969 {
2970 const GLubyte expected_red = static_cast<GLubyte>(i);
2971 const GLubyte drawn_red = pixels[i];
2972
2973 if (expected_red != drawn_red)
2974 {
2975 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value: " << (GLuint)drawn_red
2976 << ". Expected value: " << (GLuint)expected_red << " at offset: " << i
2977 << tcu::TestLog::EndMessage;
2978
2979 result = false;
2980 break;
2981 }
2982 }
2983 }
2984 else if (RG8_SNORM == m_test_case)
2985 {
2986 static const GLuint n_channels = 2;
2987
2988 Texture::Bind(gl, texture_id, GL_TEXTURE_2D);
2989
2990 std::vector<GLbyte> pixels(n_pixels * n_channels);
2991 initPixels(pixels, n_pixels, n_channels);
2992
2993 Texture::GetData(gl, 0 /* level */, GL_TEXTURE_2D, GL_RG, GL_BYTE, &pixels[0]);
2994
2995 /* Unbind */
2996 Texture::Bind(gl, 0, GL_TEXTURE_2D);
2997
2998 /* Verify */
2999 for (GLuint i = 0; i < n_pixels; ++i)
3000 {
3001 const GLbyte expected_red = static_cast<GLubyte>((i % 16) - 8);
3002 const GLbyte expected_green = static_cast<GLubyte>((i / 16) - 8);
3003 const GLbyte drawn_red = pixels[i * n_channels + 0];
3004 const GLbyte drawn_green = pixels[i * n_channels + 1];
3005
3006 if ((expected_red != drawn_red) || (expected_green != drawn_green))
3007 {
3008 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value: " << (GLint)drawn_red << ", "
3009 << (GLint)drawn_green << ". Expected value: " << (GLint)expected_red << ", "
3010 << (GLint)expected_green << ". At offset: " << i << tcu::TestLog::EndMessage;
3011
3012 result = false;
3013 break;
3014 }
3015 }
3016 }
3017 else if (RGBA32F == m_test_case)
3018 {
3019 static const GLuint n_channels = 4;
3020
3021 Texture::Bind(gl, texture_id, GL_TEXTURE_2D);
3022
3023 std::vector<GLfloat> pixels(n_pixels * n_channels);
3024 for (GLuint i = 0; i < n_pixels; ++i)
3025 {
3026 GLfloat value = static_cast<GLfloat>(i) / n_pixels;
3027 pixels[i * n_channels + 0] = value;
3028 pixels[i * n_channels + 1] = value;
3029 pixels[i * n_channels + 2] = value;
3030 pixels[i * n_channels + 3] = value;
3031 }
3032
3033 Texture::GetData(gl, texture_id, 0 /* level */, width, height, GL_RGBA, GL_FLOAT, &pixels[0]);
3034
3035 /* Unbind */
3036 Texture::Bind(gl, 0, GL_TEXTURE_2D);
3037
3038 /* Verify */
3039 for (GLuint i = 0; i < n_pixels; ++i)
3040 {
3041 const GLfloat expected_red = (GLfloat)(i % 16) / 16.0f;
3042 const GLfloat expected_green = (GLfloat)(i / 16) / 16.0f;
3043 const GLfloat expected_blue = (GLfloat)i / 256.0f;
3044 const GLfloat expected_alpha = 1.0f;
3045 const GLuint idx = i * n_channels;
3046 const GLfloat drawn_red = pixels[idx + 0];
3047 const GLfloat drawn_green = pixels[idx + 1];
3048 const GLfloat drawn_blue = pixels[idx + 2];
3049 const GLfloat drawn_alpha = pixels[idx + 3];
3050
3051 if ((expected_red != drawn_red) || (expected_green != drawn_green) || (expected_blue != drawn_blue) ||
3052 (expected_alpha != drawn_alpha))
3053 {
3054 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value: " << drawn_red << ", " << drawn_green
3055 << ", " << drawn_blue << ", " << drawn_alpha << ". Expected value: " << expected_red
3056 << ", " << expected_green << ", " << expected_blue << ", " << expected_alpha
3057 << ". At offset: " << i << tcu::TestLog::EndMessage;
3058
3059 result = false;
3060 break;
3061 }
3062 }
3063 }
3064 else if (R32UI_MIPMAP == m_test_case)
3065 {
3066 static const GLuint n_channels = 4;
3067
3068 Texture::Bind(gl, texture_id, GL_TEXTURE_2D);
3069
3070 std::vector<GLuint> pixels(n_pixels * n_channels);
3071 initPixels(pixels, n_pixels, n_channels);
3072
3073 Texture::GetData(gl, texture_id, 1 /* level */, width, height, GL_RGBA_INTEGER, GL_UNSIGNED_INT, &pixels[0]);
3074
3075 /* Unbind */
3076 Texture::Bind(gl, 0, GL_TEXTURE_2D);
3077
3078 /* Verify */
3079 for (GLuint i = 0; i < n_pixels; ++i)
3080 {
3081 const GLuint expected_red = i;
3082 const GLuint drawn_red = pixels[i * n_channels];
3083
3084 if (expected_red != drawn_red)
3085 {
3086 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value: " << drawn_red
3087 << ". Expected value: " << expected_red << " at offset: " << i
3088 << tcu::TestLog::EndMessage;
3089
3090 result = false;
3091 break;
3092 }
3093 }
3094 }
3095 else if (R32UI_MULTISAMPLE == m_test_case)
3096 {
3097 static const GLuint n_channels = 1;
3098
3099 /* Compute shader */
3100 static const GLchar* cs =
3101 "${VERSION}\n"
3102 "\n"
3103 "layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
3104 "\n"
3105 "layout (location = 1) writeonly uniform uimage2D uni_destination_image;\n"
3106 "layout (location = 0, r32ui) readonly uniform uimage2DMS uni_source_image;\n"
3107 "\n"
3108 "void main()\n"
3109 "{\n"
3110 " const ivec2 point = ivec2(gl_WorkGroupID.x, gl_WorkGroupID.y);\n"
3111 " const uint index = gl_WorkGroupID.y * 16 + gl_WorkGroupID.x;\n"
3112 "\n"
3113 " const uvec4 color_0 = imageLoad(uni_source_image, point, 0);\n"
3114 " const uvec4 color_1 = imageLoad(uni_source_image, point, 1);\n"
3115 " const uvec4 color_2 = imageLoad(uni_source_image, point, 2);\n"
3116 " const uvec4 color_3 = imageLoad(uni_source_image, point, 3);\n"
3117 "\n"
3118 " if (any(equal(uvec4(color_0.r, color_1.r, color_2.r, color_3.r), uvec4(index + 3))))\n"
3119 " {\n"
3120 " imageStore(uni_destination_image, point, uvec4(1, 1, 1, 1));\n"
3121 " }\n"
3122 " else\n"
3123 " {\n"
3124 " imageStore(uni_destination_image, point, uvec4(0, 0, 0, 0));\n"
3125 " }\n"
3126 "}\n"
3127 "\n";
3128
3129 Program program(gl);
3130 Texture destination_texture(gl);
3131
3132 Texture::Generate(gl, destination_texture.m_id);
3133 Texture::Bind(gl, destination_texture.m_id, GL_TEXTURE_2D);
3134 Texture::Storage(gl, GL_TEXTURE_2D, 1, GL_R32UI, width, height, 0 /* depth */);
3135
3136 program.Init(cs, "", "", "", "", "");
3137 program.Use();
3138 gl.bindImageTexture(0 /* unit */, texture_id, 0 /* level */, GL_FALSE /* layered */, 0 /* layer */,
3139 GL_READ_ONLY, GL_R32UI);
3140 GLU_EXPECT_NO_ERROR(gl.getError(), "BindImageTexture");
3141 gl.bindImageTexture(1 /* unit */, destination_texture.m_id, 0 /* level */, GL_FALSE /* layered */,
3142 0 /* layer */, GL_WRITE_ONLY, GL_R32UI);
3143 GLU_EXPECT_NO_ERROR(gl.getError(), "BindImageTexture");
3144
3145 gl.uniform1i(0 /* location */, 0 /* image unit*/);
3146 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform1i");
3147
3148 gl.uniform1i(1 /* location */, 1 /* image unit*/);
3149 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform1i");
3150
3151 gl.dispatchCompute(16, 16, 1);
3152 GLU_EXPECT_NO_ERROR(gl.getError(), "DispatchCompute");
3153
3154 /* Pixels buffer initialization */
3155 std::vector<GLuint> pixels(n_pixels * n_channels);
3156 initPixels(pixels, n_pixels, n_channels);
3157
3158 Texture::GetData(gl, 0 /* level */, GL_TEXTURE_2D, GL_RED_INTEGER, GL_UNSIGNED_INT, &pixels[0]);
3159
3160 /* Unbind */
3161 Texture::Bind(gl, 0, GL_TEXTURE_2D);
3162
3163 /* Verify */
3164 for (GLuint i = 0; i < n_pixels; ++i)
3165 {
3166 const GLuint expected_red = 1;
3167 const GLuint drawn_red = pixels[i];
3168
3169 if (expected_red != drawn_red)
3170 {
3171 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value: " << drawn_red
3172 << ". Expected value: " << expected_red << " at offset: " << i
3173 << tcu::TestLog::EndMessage;
3174
3175 result = false;
3176 break;
3177 }
3178 }
3179 }
3180
3181 return result;
3182 }
3183
3184 /* StorageBufferTest constants */
3185 const GLfloat StorageBufferTest::m_destination_data[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
3186 const GLfloat StorageBufferTest::m_source_data[4] = { 2.0f, 3.0f, 4.0f, 5.0f };
3187
3188 /** Constructor
3189 *
3190 * @param testCtx Test context
3191 * @param apiType Api type
3192 **/
StorageBufferTest(tcu::TestContext & testCtx,glu::ApiType apiType)3193 StorageBufferTest::StorageBufferTest(tcu::TestContext& testCtx, glu::ApiType apiType)
3194 : RobustnessBase(testCtx, "storage_buffer", "Verifies that out-of-bound access to SSBO is discared or resutls in 0",
3195 apiType)
3196 , m_test_case(VALID)
3197 {
3198 /* Nothing to be done here */
3199 }
3200
3201
3202 /** Execute test
3203 *
3204 * @return tcu::TestNode::STOP
3205 **/
iterate()3206 tcu::TestNode::IterateResult StorageBufferTest::iterate()
3207 {
3208 de::SharedPtr<glu::RenderContext> robustContext(createRobustContext());
3209 if (!robustContext.get())
3210 return STOP;
3211
3212 /* GL entry points */
3213 const Functions& gl = robustContext->getFunctions();
3214
3215 /* Test result indicator */
3216 bool test_result = true;
3217
3218 GLuint test_offsets[] = {
3219 16, // close fetch
3220 4 * 1024, // near fetch (4K of the end of the object)
3221 1024 * 1024, // medium fetch (1MB past the end of the object)
3222 10 * 1024 * 1024 // high fetch (10MB beyond the end of the object)
3223 };
3224
3225 /* Iterate over all cases */
3226 while (LAST != m_test_case)
3227 {
3228 /* Test case objects */
3229 Buffer destination_buffer(gl);
3230 Buffer source_buffer(gl);
3231 Program program(gl);
3232
3233 /* Buffers initialization */
3234 destination_buffer.InitData(GL_SHADER_STORAGE_BUFFER, GL_DYNAMIC_COPY, sizeof(m_destination_data),
3235 m_destination_data);
3236 source_buffer.InitData(GL_SHADER_STORAGE_BUFFER, GL_DYNAMIC_COPY, sizeof(m_source_data), m_source_data);
3237
3238 destination_buffer.BindBase(0);
3239 source_buffer.BindBase(1);
3240
3241 for (GLuint i = 0; i < DE_LENGTH_OF_ARRAY(test_offsets); ++i)
3242 {
3243 /* Initialize shader */
3244 const std::string& cs = getComputeShader(test_offsets[i]);
3245 program.Init(cs, "" /* fs */, "" /* gs */, "" /* tcs */, "" /* tes */, "" /* vs */);
3246 program.Use();
3247
3248 /* Dispatch compute */
3249 gl.dispatchCompute(1 /* x */, 1 /* y */, 1 /* z */);
3250 GLU_EXPECT_NO_ERROR(gl.getError(), "DispatchCompute");
3251
3252 /* Set memory barrier */
3253 gl.memoryBarrier(GL_ALL_BARRIER_BITS);
3254 GLU_EXPECT_NO_ERROR(gl.getError(), "MemoryBarrier");
3255
3256 /* Verify results */
3257 destination_buffer.Bind();
3258 GLfloat* buffer_data =
3259 (GLfloat*)gl.mapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, sizeof(m_destination_data), GL_MAP_READ_BIT);
3260 GLU_EXPECT_NO_ERROR(gl.getError(), "MapBufferRange");
3261
3262 test_result &= verifyResults(buffer_data);
3263
3264 gl.unmapBuffer(GL_SHADER_STORAGE_BUFFER);
3265 GLU_EXPECT_NO_ERROR(gl.getError(), "UnmapBuffer");
3266 }
3267
3268 /* Increment */
3269 m_test_case = (VERSION)((GLuint)m_test_case + 1);
3270 }
3271
3272 /* Set result */
3273 if (true == test_result)
3274 {
3275 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
3276 }
3277 else
3278 {
3279 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
3280 }
3281
3282 /* Done */
3283 return tcu::TestNode::STOP;
3284 }
3285
3286 /** Prepare shader for current test case
3287 *
3288 * @return Source
3289 **/
getComputeShader(GLuint offset)3290 std::string StorageBufferTest::getComputeShader(GLuint offset)
3291 {
3292 static const GLchar* source = "${VERSION}\n"
3293 "\n"
3294 "layout (local_size_x = 4, local_size_y = 1, local_size_z = 1) in;\n"
3295 "\n"
3296 "layout (binding = 1, std430) buffer Source {\n"
3297 " float data[];\n"
3298 "} source;\n"
3299 "\n"
3300 "layout (binding = 0, std430) buffer Destination {\n"
3301 " float data[];\n"
3302 "} destination;\n"
3303 "\n"
3304 "void main()\n"
3305 "{\n"
3306 " uint index_destination = gl_LocalInvocationID.x + ${DST_OFFSET}U;\n"
3307 " uint index_source = gl_LocalInvocationID.x + ${SRC_OFFSET}U;\n"
3308 "\n"
3309 " destination.data[index_destination] = source.data[index_source];\n"
3310 "}\n"
3311 "\n";
3312
3313 std::stringstream offset_stream;
3314 offset_stream << offset;
3315
3316 m_specializationMap["DST_OFFSET"] = "0";
3317 m_specializationMap["SRC_OFFSET"] = "0";
3318 if (m_test_case == SOURCE_INVALID)
3319 m_specializationMap["SRC_OFFSET"] = offset_stream.str();
3320 else if (m_test_case == DESTINATION_INVALID)
3321 m_specializationMap["DST_OFFSET"] = offset_stream.str();
3322
3323 return tcu::StringTemplate(source).specialize(m_specializationMap);
3324 }
3325
3326 /** Verify test case results
3327 *
3328 * @param buffer_data Buffer data to verify
3329 *
3330 * @return true if buffer_data is as expected, false othrewise
3331 **/
verifyResults(GLfloat * buffer_data)3332 bool StorageBufferTest::verifyResults(GLfloat* buffer_data)
3333 {
3334 /* KHR_robust_buffer_access_behavior (and also GL 4.5 and later) states
3335 * which values can be expected when reading or writing outside of a
3336 * buffer's range. If supported, we will compare results against those
3337 * expectations.
3338 *
3339 * Otherwise, we will attempt to match results against previously observed
3340 * and valid behavior.
3341 */
3342 static const GLfloat expected_data_valid[4] = { 2.0f, 3.0f, 4.0f, 5.0f };
3343 static const GLfloat expected_data_invalid_source[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
3344 static const GLfloat expected_data_invalid_destination[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
3345
3346 /* OpenGL ES has undefined out-of-bound behavior - verify only valid result*/
3347 if (m_context_is_es && (m_test_case != VALID))
3348 return true;
3349
3350 /* Prepare expected data const for proper case*/
3351 const GLchar* name = 0;
3352 bool check_expected_data = false;
3353 const GLfloat* expected_data = 0;
3354 switch (m_test_case)
3355 {
3356 case VALID:
3357 name = "valid indices";
3358 check_expected_data = true;
3359 expected_data = expected_data_valid;
3360 break;
3361 case SOURCE_INVALID:
3362 name = "invalid source indices";
3363 if (m_has_khr_robust_buffer_access)
3364 {
3365 for (int b = 0; b < 4; b++)
3366 {
3367 /* Each out-of-range read can either be 0 or any value within
3368 * the source buffer.
3369 * */
3370 bool valid = false;
3371 if (buffer_data[b] == 0.0f)
3372 {
3373 valid = true;
3374 }
3375 else
3376 {
3377 for (int c = 0; c < 4 && !valid; c++)
3378 {
3379 if (buffer_data[b] == m_source_data[c])
3380 {
3381 valid = true;
3382 }
3383 }
3384 }
3385 if (!valid)
3386 {
3387 m_testCtx.getLog() << tcu::TestLog::Message << "Test case: " << name << " failed"
3388 << tcu::TestLog::EndMessage;
3389 }
3390 }
3391 }
3392 else
3393 {
3394 check_expected_data = true;
3395 expected_data = expected_data_invalid_source;
3396 }
3397 break;
3398 case DESTINATION_INVALID:
3399 name = "invalid destination indices";
3400 if (m_has_khr_robust_buffer_access)
3401 {
3402 for (int b = 0; b < 4; b++)
3403 {
3404 bool valid = false;
3405 /* Each out-of-range write can either be discarded (in which
3406 * case it would have the original destination value) or it
3407 * could write any value within the buffer (so we need to check
3408 * against each possible source value).
3409 */
3410 if (buffer_data[b] == m_destination_data[b])
3411 {
3412 valid = true;
3413 }
3414 else
3415 {
3416 for (int c = 0; c < 4 && !valid; c++)
3417 {
3418 if (buffer_data[b] == m_source_data[c])
3419 {
3420 valid = true;
3421 }
3422 }
3423 }
3424 if (!valid)
3425 {
3426 m_testCtx.getLog() << tcu::TestLog::Message << "Test case: " << name << " failed"
3427 << tcu::TestLog::EndMessage;
3428 }
3429 }
3430 }
3431 else
3432 {
3433 check_expected_data = true;
3434 expected_data = expected_data_invalid_destination;
3435 }
3436 break;
3437 default:
3438 TCU_FAIL("Invalid enum");
3439 }
3440
3441 if (check_expected_data)
3442 {
3443 /* Verify buffer data */
3444 int size = static_cast<int>(sizeof(GLfloat) * 4);
3445 if (0 != memcmp(expected_data, buffer_data, size))
3446 {
3447 m_testCtx.getLog() << tcu::TestLog::Message << "Test case: " << name << " failed"
3448 << tcu::TestLog::EndMessage;
3449 return false;
3450 }
3451 }
3452
3453 return true;
3454 }
3455
3456 /** Constructor
3457 *
3458 * @param context Test context
3459 **/
UniformBufferTest(tcu::TestContext & testCtx,glu::ApiType apiType)3460 UniformBufferTest::UniformBufferTest(tcu::TestContext& testCtx, glu::ApiType apiType)
3461 : RobustnessBase(testCtx, "uniform_buffer", "Verifies that out-of-bound access to UBO resutls in 0", apiType)
3462 , m_test_case(VALID)
3463 {
3464 /* Nothing to be done here */
3465 }
3466
3467 /** Execute test
3468 *
3469 * @return tcu::TestNode::STOP
3470 **/
iterate()3471 tcu::TestNode::IterateResult UniformBufferTest::iterate()
3472 {
3473 de::SharedPtr<glu::RenderContext> robustContext(createRobustContext());
3474 if (!robustContext.get())
3475 return STOP;
3476
3477 static const GLfloat destination_data[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
3478 /* The source buffer is packed std140 so we need vec4s */
3479 static const GLfloat source_data[16] = {
3480 2.0f, 0.0f, 0.0f, 0.0f, 3.0f, 0.0f, 0.0f, 0.0f, 4.0f, 0.0f, 0.0f, 0.0f, 5.0f, 0.0f, 0.0f, 0.0f,
3481 };
3482
3483 GLuint test_offsets[] = {
3484 16, // close fetch
3485 4 * 1024, // near fetch (4K of the end of the object)
3486 1024 * 1024, // medium fetch (1MB past the end of the object)
3487 10 * 1024 * 1024 // high fetch (10MB beyond the end of the object)
3488 };
3489
3490 /* GL entry points */
3491 const Functions& gl = robustContext->getFunctions();
3492
3493 /* Test result indicator */
3494 bool test_result = true;
3495
3496 /* Iterate over all cases */
3497 while (LAST != m_test_case)
3498 {
3499 /* Test case objects */
3500 Buffer destination_buffer(gl);
3501 Buffer source_buffer(gl);
3502 Program program(gl);
3503
3504 /* Buffers initialization */
3505 destination_buffer.InitData(GL_SHADER_STORAGE_BUFFER, GL_DYNAMIC_COPY, sizeof(destination_data),
3506 destination_data);
3507 source_buffer.InitData(GL_UNIFORM_BUFFER, GL_DYNAMIC_COPY, sizeof(source_data), source_data);
3508
3509 destination_buffer.BindBase(0);
3510 source_buffer.BindBase(0);
3511
3512 for (GLuint i = 0; i < DE_LENGTH_OF_ARRAY(test_offsets); ++i)
3513 {
3514 /* Initialize shader */
3515 const std::string& cs = getComputeShader(test_offsets[i]);
3516 program.Init(cs, "" /* fs */, "" /* gs */, "" /* tcs */, "" /* tes */, "" /* vs */);
3517 program.Use();
3518
3519 /* Dispatch compute */
3520 gl.dispatchCompute(1 /* x */, 1 /* y */, 1 /* z */);
3521 GLU_EXPECT_NO_ERROR(gl.getError(), "DispatchCompute");
3522
3523 /* Set memory barrier */
3524 gl.memoryBarrier(GL_ALL_BARRIER_BITS);
3525 GLU_EXPECT_NO_ERROR(gl.getError(), "MemoryBarrier");
3526
3527 /* Verify results */
3528 destination_buffer.Bind();
3529 GLfloat* buffer_data =
3530 (GLfloat*)gl.mapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, sizeof(destination_data), GL_MAP_READ_BIT);
3531 GLU_EXPECT_NO_ERROR(gl.getError(), "MapBufferRange");
3532
3533 test_result &= verifyResults(buffer_data);
3534
3535 gl.unmapBuffer(GL_SHADER_STORAGE_BUFFER);
3536 GLU_EXPECT_NO_ERROR(gl.getError(), "UnmapBuffer");
3537 }
3538
3539 /* Increment */
3540 m_test_case = (VERSION)((GLuint)m_test_case + 1);
3541 }
3542
3543 /* Set result */
3544 if (true == test_result)
3545 {
3546 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
3547 }
3548 else
3549 {
3550 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
3551 }
3552
3553 /* Done */
3554 return tcu::TestNode::STOP;
3555 }
3556
3557 /** Prepare shader for current test case
3558 *
3559 * @return Source
3560 **/
getComputeShader(GLuint offset)3561 std::string UniformBufferTest::getComputeShader(GLuint offset)
3562 {
3563 static const GLchar* source = "${VERSION}\n"
3564 "\n"
3565 "layout (local_size_x = 4, local_size_y = 1, local_size_z = 1) in;\n"
3566 "\n"
3567 "layout (binding = 0, std140) uniform Source {\n"
3568 " float data[16];\n"
3569 "} source;\n"
3570 "\n"
3571 "layout (binding = 0, std430) buffer Destination {\n"
3572 " float data[];\n"
3573 "} destination;\n"
3574 "\n"
3575 "void main()\n"
3576 "{\n"
3577 " uint index_destination = gl_LocalInvocationID.x;\n"
3578 " uint index_source = gl_LocalInvocationID.x + ${OFFSET}U;\n"
3579 "\n"
3580 " destination.data[index_destination] = source.data[index_source];\n"
3581 "}\n"
3582 "\n";
3583
3584 m_specializationMap["OFFSET"] = "0";
3585 if (m_test_case == SOURCE_INVALID)
3586 {
3587 std::stringstream offset_stream;
3588 offset_stream << offset;
3589 m_specializationMap["OFFSET"] = offset_stream.str();
3590 }
3591
3592 return tcu::StringTemplate(source).specialize(m_specializationMap);
3593 }
3594
3595 /** Verify test case results
3596 *
3597 * @param buffer_data Buffer data to verify
3598 *
3599 * @return true if buffer_data is as expected, false othrewise
3600 **/
verifyResults(GLfloat * buffer_data)3601 bool UniformBufferTest::verifyResults(GLfloat* buffer_data)
3602 {
3603 static const GLfloat expected_data_valid[4] = { 2.0f, 3.0f, 4.0f, 5.0f };
3604 static const GLfloat expected_data_invalid_source[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
3605
3606 int size = static_cast<int>(sizeof(GLfloat) * 4);
3607
3608 /* Prepare expected data const for proper case*/
3609 const GLfloat* expected_data = 0;
3610 const GLchar* name = 0;
3611 switch (m_test_case)
3612 {
3613 case VALID:
3614 expected_data = expected_data_valid;
3615 name = "valid indices";
3616 break;
3617 case SOURCE_INVALID:
3618 expected_data = expected_data_invalid_source;
3619 name = "invalid source indices";
3620 break;
3621 default:
3622 TCU_FAIL("Invalid enum");
3623 }
3624
3625 /* Verify buffer data */
3626 if (0 != memcmp(expected_data, buffer_data, size))
3627 {
3628 m_testCtx.getLog() << tcu::TestLog::Message << "Test case: " << name << " failed" << tcu::TestLog::EndMessage;
3629 return false;
3630 }
3631
3632 return true;
3633 }
3634 } /* RobustBufferAccessBehavior */
3635
3636 /** Constructor.
3637 *
3638 * @param context Rendering context.
3639 **/
RobustBufferAccessBehaviorTests(tcu::TestContext & testCtx,glu::ApiType apiType)3640 RobustBufferAccessBehaviorTests::RobustBufferAccessBehaviorTests(tcu::TestContext& testCtx, glu::ApiType apiType)
3641 : tcu::TestCaseGroup(testCtx, "robust_buffer_access_behavior",
3642 "Verifies \"robust buffer access behavior\" functionality")
3643 , m_ApiType(apiType)
3644 {
3645 /* Left blank on purpose */
3646 }
3647
3648 /** Initializes a multi_bind test group.
3649 *
3650 **/
init(void)3651 void RobustBufferAccessBehaviorTests::init(void)
3652 {
3653 addChild(new RobustBufferAccessBehavior::VertexBufferObjectsTest(m_testCtx, m_ApiType));
3654 addChild(new RobustBufferAccessBehavior::TexelFetchTest(m_testCtx, m_ApiType));
3655 addChild(new RobustBufferAccessBehavior::ImageLoadStoreTest(m_testCtx, m_ApiType));
3656 addChild(new RobustBufferAccessBehavior::StorageBufferTest(m_testCtx, m_ApiType));
3657 addChild(new RobustBufferAccessBehavior::UniformBufferTest(m_testCtx, m_ApiType));
3658 }
3659
3660 } /* glcts */
3661