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