1 /*-------------------------------------------------------------------------
2 * OpenGL Conformance Test Suite
3 * -----------------------------
5 * Copyright (c) 2016 The Khronos Group Inc.
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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.
22 */ /*-------------------------------------------------------------------*/
25 * \file es32cRobustBufferAccessBehaviorTests.cpp
26 * \brief Implements conformance tests for "Robust Buffer Access Behavior" functionality.
27 */ /*-------------------------------------------------------------------*/
29 #include "es32cRobustBufferAccessBehaviorTests.hpp"
31 #include "gluDefs.hpp"
32 #include "gluStrUtil.hpp"
33 #include "glwEnums.hpp"
34 #include "glwFunctions.hpp"
35 #include "tcuTestLog.hpp"
41 using namespace deqp::RobustBufferAccessBehavior;
45 namespace RobustBufferAccessBehavior
49 * @param context Test context
51 VertexBufferObjectsTest::VertexBufferObjectsTest(deqp::Context& context)
52 : deqp::RobustBufferAccessBehavior::VertexBufferObjectsTest(
53 context, "vertex_buffer_objects", "Verifies that out-of-bound reads from VB result in zero")
55 /* Nothing to be done */
60 * @return tcu::TestNode::STOP
62 tcu::TestNode::IterateResult VertexBufferObjectsTest::iterate()
64 return deqp::RobustBufferAccessBehavior::VertexBufferObjectsTest::iterate();
67 /** Prepare shader for current test case
71 std::string VertexBufferObjectsTest::getFragmentShader()
73 return std::string("#version 320 es\n"
75 "layout (location = 0) out lowp uvec4 out_fs_color;\n"
79 " out_fs_color = uvec4(1, 255, 255, 255);\n"
84 /** Prepare shader for current test case
88 std::string VertexBufferObjectsTest::getVertexShader()
90 return std::string("#version 320 es\n"
92 "layout (location = 0) in vec4 in_vs_position;\n"
96 " gl_Position = in_vs_position;\n"
101 /** No verification because of undefined out-of-bound behavior in OpenGL ES
103 * @param texture_id Id of texture
107 bool VertexBufferObjectsTest::verifyInvalidResults(glw::GLuint texture_id)
113 /** Verifies that texutre is filled with 1
115 * @param texture_id Id of texture
117 * @return true when image is filled with 1, false otherwise
119 bool VertexBufferObjectsTest::verifyResults(glw::GLuint texture_id)
121 static const GLuint height = 8;
122 static const GLuint width = 8;
123 static const GLuint pixel_size = 4 * sizeof(GLuint);
125 const Functions& gl = m_context.getRenderContext().getFunctions();
127 const GLint buf_size = width * height * pixel_size;
128 GLubyte pixels[buf_size];
129 deMemset(pixels, 0, buf_size);
131 Texture::Bind(gl, texture_id, GL_TEXTURE_2D);
133 Texture::GetData(gl, texture_id, 0 /* level */, width, height, GL_RGBA_INTEGER, GL_UNSIGNED_INT, pixels);
136 Texture::Bind(gl, 0, GL_TEXTURE_2D);
139 for (GLuint i = 0; i < buf_size; i += pixel_size)
143 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Invalid value: " << (GLuint)pixels[i]
144 << " at offset: " << i << tcu::TestLog::EndMessage;
155 * @param context Test context
157 TexelFetchTest::TexelFetchTest(deqp::Context& context)
158 : deqp::RobustBufferAccessBehavior::TexelFetchTest(context, "texel_fetch",
159 "Verifies that out-of-bound fetches from texture result in zero")
161 /* Nothing to be done */
164 TexelFetchTest::TexelFetchTest(deqp::Context& context, const glw::GLchar* name, const glw::GLchar* description)
165 : deqp::RobustBufferAccessBehavior::TexelFetchTest(context, name, description)
167 /* Nothing to be done */
172 * @return tcu::TestNode::STOP
174 tcu::TestNode::IterateResult TexelFetchTest::iterate()
176 return deqp::RobustBufferAccessBehavior::TexelFetchTest::iterate();
179 /** Prepares source code for fragment shader
181 * @param is_case_valid Selects if valid or invalid case is tested
183 * @return string with prepared code
185 std::string TexelFetchTest::getFragmentShader(bool is_case_valid)
187 static const GLchar* plane_0 = " int plane = 0;\n";
189 static const GLchar* plane_1 = " int plane = 1;\n";
191 static const GLchar* plane_2 = " int plane = 2;\n";
193 static const GLchar* plane_sample_invalid = " int plane = 9;\n";
195 static const GLchar* plane_sample_valid = " int plane = gl_SampleID;\n";
197 static const GLchar* point_invalid = " ivec2 point = ivec2(gs_fs_tex_coord * 16.0) + ivec2(16, 16);\n";
199 static const GLchar* point_valid = " ivec2 point = ivec2(gs_fs_tex_coord * 16.0);\n";
201 static const GLchar* sampler_regular = "sampler2D";
202 static const GLchar* sampler_regular_u = "usampler2D";
203 static const GLchar* sampler_multisampled_u = "usampler2DMS";
205 static const GLchar* template_code = "#version 320 es\n"
207 " in lowp vec2 gs_fs_tex_coord;\n"
208 "layout (location = 0) out lowp TYPE out_fs_color;\n"
210 "layout (location = 0) uniform lowp SAMPLER uni_texture;\n"
216 " out_fs_color = texelFetch(uni_texture, point, plane);\n"
220 static const GLchar* type_vec4 = "vec4";
221 static const GLchar* type_uvec4 = "uvec4";
223 const GLchar* plane = plane_0;
224 const GLchar* point = point_valid;
225 const GLchar* sampler = sampler_regular;
226 const GLchar* type = type_vec4;
228 if ((R8 == m_test_case) || (RG8_SNORM == m_test_case) || (RGBA32F == m_test_case))
230 if (false == is_case_valid)
232 point = point_invalid;
235 else if (R32UI_MIPMAP == m_test_case)
238 sampler = sampler_regular_u;
241 if (false == is_case_valid)
246 else if (R32UI_MULTISAMPLE == m_test_case)
248 plane = plane_sample_valid;
249 sampler = sampler_multisampled_u;
252 if (false == is_case_valid)
254 plane = plane_sample_invalid;
259 std::string source = template_code;
260 replaceToken("TYPE", position, type, source);
261 replaceToken("SAMPLER", position, sampler, source);
262 replaceToken("PLANE", position, plane, source);
263 replaceToken("POINT", position, point, source);
268 /** Prepare shader for current test case
272 std::string TexelFetchTest::getGeometryShader()
274 return std::string("#version 320 es\n"
276 "layout(points) in;\n"
277 "layout(triangle_strip, max_vertices = 4) out;\n"
279 "out vec2 gs_fs_tex_coord;\n"
283 " gs_fs_tex_coord = vec2(0, 0);\n"
284 " gl_Position = vec4(-1, -1, 0, 1);\n"
287 " gs_fs_tex_coord = vec2(0, 1);\n"
288 " gl_Position = vec4(-1, 1, 0, 1);\n"
291 " gs_fs_tex_coord = vec2(1, 0);\n"
292 " gl_Position = vec4(1, -1, 0, 1);\n"
295 " gs_fs_tex_coord = vec2(1, 1);\n"
296 " gl_Position = vec4(1, 1, 0, 1);\n"
302 /** Prepare shader for current test case
306 std::string TexelFetchTest::getVertexShader()
308 return std::string("#version 320 es\n"
312 " gl_Position = vec4(0, 0, 0, 1);\n"
317 /** Prepare a texture
319 * @param is_source Selects if texutre will be used as source or destination
320 * @param texture_id Id of texutre
322 void TexelFetchTest::prepareTexture(bool is_source, glw::GLuint texture_id)
325 static const GLuint image_height = 16;
326 static const GLuint image_width = 16;
328 /* GL entry points */
329 const Functions& gl = m_context.getRenderContext().getFunctions();
331 /* Texture storage parameters */
332 GLuint height = image_height;
333 GLenum internal_format = 0;
334 GLsizei n_levels = 1;
335 GLenum target = GL_TEXTURE_2D;
336 GLuint width = image_width;
338 /* Prepare texture storage parameters */
342 internal_format = GL_R8;
345 internal_format = GL_RG8_SNORM;
348 internal_format = GL_RGBA32F;
351 height = 2 * image_height;
352 internal_format = GL_R32UI;
354 width = 2 * image_width;
356 case R32UI_MULTISAMPLE:
357 internal_format = GL_R32UI;
359 target = GL_TEXTURE_2D_MULTISAMPLE;
362 TCU_FAIL("Invalid enum");
365 /* Prepare storage */
366 Texture::Bind(gl, texture_id, target);
367 Texture::Storage(gl, target, n_levels, internal_format, width, height, 0);
369 /* Set samplers to NEAREST/NEAREST if required */
370 if (R32UI_MULTISAMPLE != m_test_case)
372 gl.texParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
373 gl.texParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
376 /* Destination image can be left empty */
377 if (false == is_source)
379 Texture::Bind(gl, 0, target);
383 /* Prepare texture */
384 if (R8 == m_test_case)
386 GLubyte source_pixels[image_width * image_height];
387 for (GLuint i = 0; i < image_width * image_height; ++i)
389 source_pixels[i] = (GLubyte)i;
392 Texture::SubImage(gl, GL_TEXTURE_2D, 0 /* level */, 0 /* x */, 0 /* y */, 0 /* z */, width, height,
393 0 /* depth */, GL_RED, GL_UNSIGNED_BYTE, source_pixels);
395 else if (RG8_SNORM == m_test_case)
397 static const GLuint n_components = 2;
399 GLbyte source_pixels[image_width * image_height * n_components];
400 for (GLuint i = 0; i < image_width * image_height; ++i)
402 source_pixels[i * n_components + 0] = (GLubyte)((i % 16));
403 source_pixels[i * n_components + 1] = (GLubyte)((i / 16));
406 Texture::SubImage(gl, GL_TEXTURE_2D, 0 /* level */, 0 /* x */, 0 /* y */, 0 /* z */, width, height,
407 0 /* depth */, GL_RG, GL_BYTE, source_pixels);
409 else if (RGBA32F == m_test_case)
411 static const GLuint n_components = 4;
413 GLfloat source_pixels[image_width * image_height * n_components];
414 for (GLuint i = 0; i < image_width * image_height; ++i)
416 source_pixels[i * n_components + 0] = (GLfloat)(i % 16) / 16.0f;
417 source_pixels[i * n_components + 1] = (GLfloat)(i / 16) / 16.0f;
418 source_pixels[i * n_components + 2] = (GLfloat)i / 256.0f;
419 source_pixels[i * n_components + 3] = 1.0f;
422 Texture::SubImage(gl, GL_TEXTURE_2D, 0 /* level */, 0 /* x */, 0 /* y */, 0 /* z */, width, height,
423 0 /* depth */, GL_RGBA, GL_FLOAT, source_pixels);
425 else if (R32UI_MIPMAP == m_test_case)
427 GLuint source_pixels[image_width * image_height];
428 for (GLuint i = 0; i < image_width * image_height; ++i)
430 source_pixels[i] = i;
433 Texture::SubImage(gl, GL_TEXTURE_2D, 1 /* level */, 0 /* x */, 0 /* y */, 0 /* z */, image_width, image_height,
434 0 /* depth */, GL_RED_INTEGER, GL_UNSIGNED_INT, source_pixels);
436 /* texelFetch() undefined if the computed level of detail is not the texture’s base level and the texture’s
437 minification filter is NEAREST or LINEAR */
438 gl.texParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
440 else if (R32UI_MULTISAMPLE == m_test_case)
443 static const GLchar* cs = "#version 320 es\n"
445 "layout (local_size_x = 16, local_size_y = 16, local_size_z = 1) in;\n"
447 "layout (binding = 0, r32ui) writeonly uniform highp uimage2DMS uni_image;\n"
451 " ivec2 point = ivec2(gl_WorkGroupID.x, gl_WorkGroupID.y);\n"
452 " uint index = gl_WorkGroupID.y * 16U + gl_WorkGroupID.x;\n"
454 " imageStore(uni_image, point, 0, uvec4(index + 0U, 0, 0, 0));\n"
455 " imageStore(uni_image, point, 1, uvec4(index + 1U, 0, 0, 0));\n"
456 " imageStore(uni_image, point, 2, uvec4(index + 2U, 0, 0, 0));\n"
457 " imageStore(uni_image, point, 3, uvec4(index + 3U, 0, 0, 0));\n"
461 Program program(m_context);
462 program.Init(cs, "", "", "", "", "");
465 gl.bindImageTexture(0 /* unit */, texture_id, 0 /* level */, GL_FALSE /* layered */, 0 /* layer */,
466 GL_WRITE_ONLY, GL_R32UI);
467 GLU_EXPECT_NO_ERROR(gl.getError(), "BindImageTexture");
469 gl.dispatchCompute(16, 16, 1);
470 GLU_EXPECT_NO_ERROR(gl.getError(), "DispatchCompute");
473 Texture::Bind(gl, 0, target);
476 /** No verification because of undefined out-of-bound behavior in OpenGL ES
478 * @param texture_id Id of texture
482 bool TexelFetchTest::verifyInvalidResults(glw::GLuint texture_id)
488 /** Verifies that texutre is filled with increasing values
490 * @param texture_id Id of texture
492 * @return true when image is filled with increasing values, false otherwise
494 bool TexelFetchTest::verifyValidResults(glw::GLuint texture_id)
496 static const GLuint height = 16;
497 static const GLuint width = 16;
498 static const GLuint n_pixels = height * width;
500 const Functions& gl = m_context.getRenderContext().getFunctions();
504 if (R8 == m_test_case)
506 static const GLuint n_channels = 4;
508 Texture::Bind(gl, texture_id, GL_TEXTURE_2D);
510 std::vector<GLubyte> pixels;
511 pixels.resize(n_pixels * n_channels);
512 for (GLuint i = 0; i < n_pixels; ++i)
514 pixels[i] = (GLubyte)i;
517 Texture::GetData(gl, texture_id, 0 /* level */, width, height, GL_RGBA, GL_UNSIGNED_BYTE, &pixels[0]);
520 Texture::Bind(gl, 0, GL_TEXTURE_2D);
523 for (GLuint i = 0; i < n_pixels; ++i)
525 const GLubyte expected_red = (GLubyte)i;
526 const GLubyte drawn_red = pixels[i * n_channels];
528 if (expected_red != drawn_red)
530 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Invalid value: " << (GLuint)drawn_red
531 << ". Expected value: " << (GLuint)expected_red
532 << " at offset: " << i << tcu::TestLog::EndMessage;
539 else if (RG8_SNORM == m_test_case)
541 static const GLuint n_channels = 4;
543 Texture::Bind(gl, texture_id, GL_TEXTURE_2D);
545 std::vector<GLubyte> pixels;
546 pixels.resize(n_pixels * n_channels);
547 for (GLuint i = 0; i < n_pixels; ++i)
549 pixels[i * n_channels + 0] = (GLubyte)i;
550 pixels[i * n_channels + 1] = (GLubyte)i;
553 Texture::GetData(gl, texture_id, 0 /* level */, width, height, GL_RGBA, GL_BYTE, &pixels[0]);
556 Texture::Bind(gl, 0, GL_TEXTURE_2D);
559 for (GLuint i = 0; i < n_pixels; ++i)
561 const GLbyte expected_red = (GLubyte)(i % 16);
562 const GLbyte expected_green = (GLubyte)(i / 16);
563 const GLbyte drawn_red = pixels[i * n_channels + 0];
564 const GLbyte drawn_green = pixels[i * n_channels + 1];
566 if ((expected_red != drawn_red) || (expected_green != drawn_green))
568 m_context.getTestContext().getLog()
569 << tcu::TestLog::Message << "Invalid value: " << (GLint)drawn_red << ", " << (GLint)drawn_green
570 << ". Expected value: " << (GLint)expected_red << ", " << (GLint)expected_green
571 << ". At offset: " << i << tcu::TestLog::EndMessage;
578 else if (RGBA32F == m_test_case)
580 static const GLuint n_channels = 4;
582 Texture::Bind(gl, texture_id, GL_TEXTURE_2D);
584 std::vector<GLfloat> pixels;
585 pixels.resize(n_pixels * n_channels);
586 for (GLuint i = 0; i < n_pixels; ++i)
588 pixels[i * n_channels + 0] = (GLfloat)i / (GLfloat)n_pixels;
589 pixels[i * n_channels + 1] = (GLfloat)i / (GLfloat)n_pixels;
590 pixels[i * n_channels + 2] = (GLfloat)i / (GLfloat)n_pixels;
591 pixels[i * n_channels + 3] = (GLfloat)i / (GLfloat)n_pixels;
594 Texture::GetData(gl, texture_id, 0 /* level */, width, height, GL_RGBA, GL_FLOAT, &pixels[0]);
597 Texture::Bind(gl, 0, GL_TEXTURE_2D);
600 for (GLuint i = 0; i < n_pixels; ++i)
602 const GLfloat expected_red = (GLfloat)(i % 16) / 16.0f;
603 const GLfloat expected_green = (GLfloat)(i / 16) / 16.0f;
604 const GLfloat expected_blue = (GLfloat)i / 256.0f;
605 const GLfloat expected_alpha = 1.0f;
606 const GLfloat drawn_red = pixels[i * n_channels + 0];
607 const GLfloat drawn_green = pixels[i * n_channels + 1];
608 const GLfloat drawn_blue = pixels[i * n_channels + 2];
609 const GLfloat drawn_alpha = pixels[i * n_channels + 3];
611 if ((expected_red != drawn_red) || (expected_green != drawn_green) || (expected_blue != drawn_blue) ||
612 (expected_alpha != drawn_alpha))
614 m_context.getTestContext().getLog()
615 << tcu::TestLog::Message << "Invalid value: " << drawn_red << ", " << drawn_green << ", "
616 << drawn_blue << ", " << drawn_alpha << ". Expected value: " << expected_red << ", "
617 << expected_green << ", " << expected_blue << ", " << expected_alpha << ". At offset: " << i
618 << tcu::TestLog::EndMessage;
625 else if (R32UI_MIPMAP == m_test_case)
627 static const GLuint n_channels = 4;
629 Texture::Bind(gl, texture_id, GL_TEXTURE_2D);
631 std::vector<GLuint> pixels;
632 pixels.resize(n_pixels * n_channels);
633 deMemset(&pixels[0], 0, n_pixels * n_channels * sizeof(GLuint));
635 Texture::GetData(gl, texture_id, 1 /* level */, width, height, GL_RGBA_INTEGER, GL_UNSIGNED_INT, &pixels[0]);
638 Texture::Bind(gl, 0, GL_TEXTURE_2D);
641 for (GLuint i = 0; i < n_pixels; ++i)
643 const GLuint expected_red = i;
644 const GLuint drawn_red = pixels[i * n_channels];
646 if (expected_red != drawn_red)
648 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Invalid value: " << drawn_red
649 << ". Expected value: " << expected_red << " at offset: " << i
650 << tcu::TestLog::EndMessage;
657 else if (R32UI_MULTISAMPLE == m_test_case)
659 static const GLuint n_channels = 4;
662 static const GLchar* cs =
665 "layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
667 "layout (binding = 1, r32ui) writeonly uniform lowp uimage2D uni_destination_image;\n"
668 "layout (binding = 0, r32ui) readonly uniform lowp uimage2DMS uni_source_image;\n"
672 " ivec2 point = ivec2(gl_WorkGroupID.x, gl_WorkGroupID.y);\n"
673 " uint index = gl_WorkGroupID.y * 16U + gl_WorkGroupID.x;\n"
675 " uvec4 color_0 = imageLoad(uni_source_image, point, 0);\n"
676 " uvec4 color_1 = imageLoad(uni_source_image, point, 1);\n"
677 " uvec4 color_2 = imageLoad(uni_source_image, point, 2);\n"
678 " uvec4 color_3 = imageLoad(uni_source_image, point, 3);\n"
680 " if (any(equal(uvec4(color_0.r, color_1.r, color_2.r, color_3.r), uvec4(index + 3U))))\n"
682 " imageStore(uni_destination_image, point, uvec4(1U));\n"
686 " imageStore(uni_destination_image, point, uvec4(0U));\n"
691 Program program(m_context);
692 Texture destination_texture(m_context);
694 Texture::Generate(gl, destination_texture.m_id);
695 Texture::Bind(gl, destination_texture.m_id, GL_TEXTURE_2D);
696 Texture::Storage(gl, GL_TEXTURE_2D, 1, GL_R32UI, width, height, 0 /* depth */);
698 program.Init(cs, "", "", "", "", "");
700 gl.bindImageTexture(0 /* unit */, texture_id, 0 /* level */, GL_FALSE /* layered */, 0 /* layer */,
701 GL_READ_ONLY, GL_R32UI);
702 GLU_EXPECT_NO_ERROR(gl.getError(), "BindImageTexture");
703 gl.bindImageTexture(1 /* unit */, destination_texture.m_id, 0 /* level */, GL_FALSE /* layered */,
704 0 /* layer */, GL_WRITE_ONLY, GL_R32UI);
705 GLU_EXPECT_NO_ERROR(gl.getError(), "BindImageTexture");
707 gl.dispatchCompute(16, 16, 1);
708 GLU_EXPECT_NO_ERROR(gl.getError(), "DispatchCompute");
710 /* Pixels buffer initialization */
711 std::vector<GLuint> pixels;
712 pixels.resize(n_pixels * n_channels);
713 for (GLuint i = 0; i < n_pixels * n_channels; ++i)
718 Texture::GetData(gl, destination_texture.m_id, 0 /* level */, width, height, GL_RGBA_INTEGER, GL_UNSIGNED_INT,
722 Texture::Bind(gl, 0, GL_TEXTURE_2D);
725 for (GLuint i = 0; i < n_pixels; ++i)
727 const GLuint expected_red = 1;
728 const GLuint drawn_red = pixels[i * n_channels];
730 if (expected_red != drawn_red)
732 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Invalid value: " << drawn_red
733 << ". Expected value: " << expected_red << " at offset: " << i
734 << tcu::TestLog::EndMessage;
747 * @param context Test context
749 ImageLoadStoreTest::ImageLoadStoreTest(deqp::Context& context)
750 : TexelFetchTest(context, "image_load_store", "Verifies that out-of-bound to image result in zero or is discarded")
752 /* start from RGBA32F as R8, R32UI_MULTISAMPLE and R8_SNORM are not supported under GLES */
753 m_test_case = RGBA32F;
758 * @return tcu::TestNode::STOP
760 tcu::TestNode::IterateResult ImageLoadStoreTest::iterate()
763 static const GLuint height = 16;
764 static const GLuint width = 16;
766 /* GL entry points */
767 const Functions& gl = m_context.getRenderContext().getFunctions();
769 /* Test result indicator */
770 bool test_result = true;
772 /* Iterate over all cases */
773 while (LAST != m_test_case)
775 /* Test case result indicator */
776 bool case_result = true;
778 /* Test case objects */
779 Texture destination_texture(m_context);
780 Program invalid_destination_program(m_context);
781 Program invalid_source_program(m_context);
782 Texture source_texture(m_context);
783 Program valid_program(m_context);
785 const std::string& cs_invalid_destination = getComputeShader(DESTINATION_INVALID);
786 const std::string& cs_invalid_source = getComputeShader(SOURCE_INVALID);
787 const std::string& cs_valid = getComputeShader(VALID);
789 /* Prepare textures */
790 Texture::Generate(gl, destination_texture.m_id);
791 Texture::Generate(gl, source_texture.m_id);
793 prepareTexture(false, destination_texture.m_id);
794 prepareTexture(true, source_texture.m_id);
796 /* Prepare programs */
797 invalid_destination_program.Init(cs_invalid_destination, "" /* fs */, "" /* gs */, "" /* tcs */, "" /* tes */,
799 invalid_source_program.Init(cs_invalid_source, "" /* fs */, "" /* gs */, "" /* tcs */, "" /* tes */,
801 valid_program.Init(cs_valid, "" /* fs */, "" /* gs */, "" /* tcs */, "" /* tes */, "" /* vs */);
803 /* Test invalid source case */
805 invalid_source_program.Use();
808 setTextures(destination_texture.m_id, source_texture.m_id);
811 gl.dispatchCompute(width, height, 1 /* depth */);
812 GLU_EXPECT_NO_ERROR(gl.getError(), "DispatchCompute");
815 if (false == verifyInvalidResults(destination_texture.m_id))
820 /* Test valid case */
825 setTextures(destination_texture.m_id, source_texture.m_id);
828 gl.dispatchCompute(width, height, 1 /* depth */);
829 GLU_EXPECT_NO_ERROR(gl.getError(), "DispatchCompute");
832 if (false == verifyValidResults(destination_texture.m_id))
837 /* Test invalid destination case */
839 invalid_destination_program.Use();
842 setTextures(destination_texture.m_id, source_texture.m_id);
845 gl.dispatchCompute(width, height, 1 /* depth */);
846 GLU_EXPECT_NO_ERROR(gl.getError(), "DispatchCompute");
849 if (false == verifyValidResults(destination_texture.m_id))
854 /* Set test result */
855 if (false == case_result)
857 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Test case: " << getTestCaseName()
858 << " failed" << tcu::TestLog::EndMessage;
864 m_test_case = (TEST_CASES)((GLuint)m_test_case + 1);
868 if (true == test_result)
870 m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Pass");
874 m_context.getTestContext().setTestResult(QP_TEST_RESULT_FAIL, "Fail");
878 return tcu::TestNode::STOP;
881 /** Prepare shader for current test case
883 * @param version Specify which version should be prepared
887 std::string ImageLoadStoreTest::getComputeShader(VERSION version)
889 static const GLchar* template_code =
892 "layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
894 "layout (binding = 1, FORMAT) writeonly uniform highp IMAGE uni_destination_image;\n"
895 "layout (binding = 0, FORMAT) readonly uniform highp IMAGE uni_source_image;\n"
899 " ivec2 point_destination = POINT;\n"
900 " ivec2 point_source = POINT;\n"
906 static const GLchar* copy_regular = " TYPE color = imageLoad(uni_source_image, point_source);\n"
907 " imageStore(uni_destination_image, point_destination, color);\n";
909 static const GLchar* format_rgba32f = "rgba32f";
910 static const GLchar* format_r32ui = "r32ui";
912 static const GLchar* image_vec4 = "image2D";
914 static const GLchar* image_uvec4 = "uimage2D";
916 static const GLchar* point_invalid = "ivec2(gl_WorkGroupID.x + 16U, gl_WorkGroupID.y + 16U)";
918 static const GLchar* point_valid = "ivec2(gl_WorkGroupID.x, gl_WorkGroupID.y)";
920 static const GLchar* type_vec4 = "vec4";
921 static const GLchar* type_uvec4 = "uvec4";
923 const GLchar* copy = copy_regular;
924 const GLchar* format = format_rgba32f;
925 const GLchar* image = image_vec4;
926 const GLchar* point_destination = point_valid;
927 const GLchar* point_source = point_valid;
928 const GLchar* type = type_vec4;
935 point_source = point_invalid;
937 case DESTINATION_INVALID:
938 point_destination = point_invalid;
941 TCU_FAIL("Invalid enum");
947 format = format_rgba32f;
950 format = format_r32ui;
955 TCU_FAIL("Invalid enum");
959 std::string source = template_code;
961 replaceToken("FORMAT", position, format, source);
962 replaceToken("IMAGE", position, image, source);
963 replaceToken("FORMAT", position, format, source);
964 replaceToken("IMAGE", position, image, source);
965 replaceToken("POINT", position, point_destination, source);
966 replaceToken("POINT", position, point_source, source);
968 size_t temp_position = position;
969 replaceToken("COPY", position, copy, source);
970 position = temp_position;
976 replaceToken("TYPE", position, type, source);
979 TCU_FAIL("Invalid enum");
985 /** Set textures as images
987 * @param id_destination Id of texture used as destination
988 * @param id_source Id of texture used as source
990 void ImageLoadStoreTest::setTextures(glw::GLuint id_destination, glw::GLuint id_source)
992 const Functions& gl = m_context.getRenderContext().getFunctions();
1000 format = GL_RGBA32F;
1007 TCU_FAIL("Invalid enum");
1010 gl.bindImageTexture(0 /* unit */, id_source, level, GL_FALSE /* layered */, 0 /* layer */, GL_READ_ONLY, format);
1011 GLU_EXPECT_NO_ERROR(gl.getError(), "BindImageTexture");
1013 gl.bindImageTexture(1 /* unit */, id_destination, level, GL_FALSE /* layered */, 0 /* layer */, GL_WRITE_ONLY,
1015 GLU_EXPECT_NO_ERROR(gl.getError(), "BindImageTexture");
1018 /** No verification because of undefined out-of-bound behavior in OpenGL ES
1020 * @param texture_id Id of texture
1024 bool ImageLoadStoreTest::verifyInvalidResults(glw::GLuint texture_id)
1030 /** Verifies that texutre is filled with increasing values
1032 * @param texture_id Id of texture
1034 * @return true when image is filled with increasing values, false otherwise
1036 bool ImageLoadStoreTest::verifyValidResults(glw::GLuint texture_id)
1038 static const GLuint height = 16;
1039 static const GLuint width = 16;
1040 static const GLuint n_pixels = height * width;
1042 const Functions& gl = m_context.getRenderContext().getFunctions();
1043 gl.memoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
1044 GLU_EXPECT_NO_ERROR(gl.getError(), "MemoryBarrier");
1048 if (RGBA32F == m_test_case)
1050 static const GLuint n_channels = 4;
1052 Texture::Bind(gl, texture_id, GL_TEXTURE_2D);
1054 std::vector<GLfloat> pixels;
1055 pixels.resize(n_pixels * n_channels);
1056 for (GLuint i = 0; i < n_pixels; ++i)
1058 pixels[i * n_channels + 0] = (GLfloat)i / (GLfloat)n_pixels;
1059 pixels[i * n_channels + 1] = (GLfloat)i / (GLfloat)n_pixels;
1060 pixels[i * n_channels + 2] = (GLfloat)i / (GLfloat)n_pixels;
1061 pixels[i * n_channels + 3] = (GLfloat)i / (GLfloat)n_pixels;
1064 Texture::GetData(gl, texture_id, 0 /* level */, width, height, GL_RGBA, GL_FLOAT, &pixels[0]);
1067 Texture::Bind(gl, 0, GL_TEXTURE_2D);
1070 for (GLuint i = 0; i < n_pixels; ++i)
1072 const GLfloat expected_red = (GLfloat)(i % 16) / 16.0f;
1073 const GLfloat expected_green = (GLfloat)(i / 16) / 16.0f;
1074 const GLfloat expected_blue = (GLfloat)i / 256.0f;
1075 const GLfloat expected_alpha = 1.0f;
1076 const GLfloat drawn_red = pixels[i * n_channels + 0];
1077 const GLfloat drawn_green = pixels[i * n_channels + 1];
1078 const GLfloat drawn_blue = pixels[i * n_channels + 2];
1079 const GLfloat drawn_alpha = pixels[i * n_channels + 3];
1081 if ((expected_red != drawn_red) || (expected_green != drawn_green) || (expected_blue != drawn_blue) ||
1082 (expected_alpha != drawn_alpha))
1084 m_context.getTestContext().getLog()
1085 << tcu::TestLog::Message << "Invalid value: " << drawn_red << ", " << drawn_green << ", "
1086 << drawn_blue << ", " << drawn_alpha << ". Expected value: " << expected_red << ", "
1087 << expected_green << ", " << expected_blue << ", " << expected_alpha << ". At offset: " << i
1088 << tcu::TestLog::EndMessage;
1095 else if (R32UI_MIPMAP == m_test_case)
1097 static const GLuint n_channels = 4;
1099 Texture::Bind(gl, texture_id, GL_TEXTURE_2D);
1101 std::vector<GLuint> pixels;
1102 pixels.resize(n_pixels * n_channels);
1103 for (GLuint i = 0; i < n_pixels * n_channels; ++i)
1108 Texture::GetData(gl, texture_id, 1 /* level */, width, height, GL_RGBA_INTEGER, GL_UNSIGNED_INT, &pixels[0]);
1111 Texture::Bind(gl, 0, GL_TEXTURE_2D);
1114 for (GLuint i = 0; i < n_pixels; ++i)
1116 const GLuint expected_red = i;
1117 const GLuint drawn_red = pixels[i * n_channels];
1119 if (expected_red != drawn_red)
1121 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Invalid value: " << drawn_red
1122 << ". Expected value: " << expected_red << " at offset: " << i
1123 << tcu::TestLog::EndMessage;
1136 * @param context Test context
1138 StorageBufferTest::StorageBufferTest(deqp::Context& context)
1139 : deqp::RobustBufferAccessBehavior::StorageBufferTest(
1140 context, "storage_buffer", "Verifies that out-of-bound access to SSBO results with no error")
1142 /* Nothing to be done here */
1147 * @return tcu::TestNode::STOP
1149 tcu::TestNode::IterateResult StorageBufferTest::iterate()
1151 return deqp::RobustBufferAccessBehavior::StorageBufferTest::iterate();
1154 /** Prepare shader for current test case
1158 std::string StorageBufferTest::getComputeShader()
1160 static const GLchar* cs = "#version 320 es\n"
1162 "layout (local_size_x = 4, local_size_y = 1, local_size_z = 1) in;\n"
1164 "layout (binding = 1) buffer Source {\n"
1168 "layout (binding = 0) buffer Destination {\n"
1174 " uint index_destination = gl_LocalInvocationID.x + OFFSETU;\n"
1175 " uint index_source = gl_LocalInvocationID.x + OFFSETU;\n"
1177 " destination.data[index_destination] = source.data[index_source];\n"
1181 const GLchar* destination_offset;
1182 size_t position = 0;
1183 std::string source = cs;
1184 const GLchar* source_offset;
1186 switch (m_test_case)
1189 destination_offset = "0";
1190 source_offset = "0";
1192 case SOURCE_INVALID:
1193 destination_offset = "0";
1194 source_offset = "16";
1196 case DESTINATION_INVALID:
1197 destination_offset = "16";
1198 source_offset = "0";
1201 TCU_FAIL("Invalid enum");
1204 replaceToken("OFFSET", position, destination_offset, source);
1205 replaceToken("OFFSET", position, source_offset, source);
1210 /** Verify test case results
1212 * @param buffer_data Buffer data to verify
1214 * @return true if buffer_data is as expected, false othrewise
1216 bool StorageBufferTest::verifyResults(GLfloat* buffer_data)
1218 static const GLfloat expected_data_valid[4] = { 2.0f, 3.0f, 4.0f, 5.0f };
1219 static const GLfloat expected_data_invalid_destination[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
1220 static const GLfloat expected_data_invalid_source[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
1222 int size = sizeof(GLfloat) * 4;
1224 /* Prepare expected data const for proper case*/
1225 const GLfloat* expected_data = 0;
1226 const GLchar* name = 0;
1227 switch (m_test_case)
1230 expected_data = expected_data_valid;
1231 name = "valid indices";
1233 case SOURCE_INVALID:
1234 expected_data = expected_data_invalid_source;
1235 name = "invalid source indices";
1237 case DESTINATION_INVALID:
1238 expected_data = expected_data_invalid_destination;
1239 name = "invalid destination indices";
1242 TCU_FAIL("Invalid enum");
1245 /* Verify buffer data */
1246 if (m_test_case == VALID && memcmp(expected_data, buffer_data, size) != 0)
1248 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Test case: " << name << " failed"
1249 << tcu::TestLog::EndMessage;
1258 * @param context Test context
1260 UniformBufferTest::UniformBufferTest(deqp::Context& context)
1261 : deqp::RobustBufferAccessBehavior::UniformBufferTest(
1262 context, "uniform_buffer", "Verifies that out-of-bound access to UBO resutls with no error")
1264 /* Nothing to be done here */
1269 * @return tcu::TestNode::STOP
1271 tcu::TestNode::IterateResult UniformBufferTest::iterate()
1273 return deqp::RobustBufferAccessBehavior::UniformBufferTest::iterate();
1276 /** Prepare shader for current test case
1280 std::string UniformBufferTest::getComputeShader()
1282 static const GLchar* cs = "#version 320 es\n"
1284 "layout (local_size_x = 4, local_size_y = 1, local_size_z = 1) in;\n"
1286 "layout (binding = 0) uniform Source {\n"
1287 " float data[16];\n"
1290 "layout (binding = 0) buffer Destination {\n"
1296 " uint index_destination = gl_LocalInvocationID.x + OFFSETU;\n"
1297 " uint index_source = gl_LocalInvocationID.x + OFFSETU;\n"
1299 " destination.data[index_destination] = source.data[index_source];\n"
1303 const GLchar* destination_offset;
1304 size_t position = 0;
1305 std::string source = cs;
1306 const GLchar* source_offset;
1308 switch (m_test_case)
1311 destination_offset = "0";
1312 source_offset = "0";
1314 case SOURCE_INVALID:
1315 destination_offset = "0";
1316 source_offset = "16";
1319 TCU_FAIL("Invalid enum");
1322 replaceToken("OFFSET", position, destination_offset, source);
1323 replaceToken("OFFSET", position, source_offset, source);
1328 /** Verify test case results
1330 * @param buffer_data Buffer data to verify
1332 * @return true if buffer_data is as expected, false othrewise
1334 bool UniformBufferTest::verifyResults(GLfloat* buffer_data)
1336 static const GLfloat expected_data_valid[4] = { 2.0f, 3.0f, 4.0f, 5.0f };
1337 static const GLfloat expected_data_invalid_source[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
1339 int size = sizeof(GLfloat) * 4;
1341 /* Prepare expected data const for proper case*/
1342 const GLfloat* expected_data = 0;
1343 const GLchar* name = 0;
1344 switch (m_test_case)
1347 expected_data = expected_data_valid;
1348 name = "valid indices";
1350 case SOURCE_INVALID:
1351 expected_data = expected_data_invalid_source;
1352 name = "invalid source indices";
1355 TCU_FAIL("Invalid enum");
1358 /* Verify buffer data */
1359 if (m_test_case == VALID && memcmp(expected_data, buffer_data, size) != 0)
1361 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Test case: " << name << " failed"
1362 << tcu::TestLog::EndMessage;
1369 } /* RobustBufferAccessBehavior */
1373 * @param context Rendering context.
1375 RobustBufferAccessBehaviorTests::RobustBufferAccessBehaviorTests(deqp::Context& context)
1376 : deqp::RobustBufferAccessBehaviorTests(context)
1378 /* Left blank on purpose */
1381 /** Initializes a multi_bind test group.
1384 void RobustBufferAccessBehaviorTests::init(void)
1386 addChild(new RobustBufferAccessBehavior::VertexBufferObjectsTest(m_context));
1387 addChild(new RobustBufferAccessBehavior::TexelFetchTest(m_context));
1388 addChild(new RobustBufferAccessBehavior::ImageLoadStoreTest(m_context));
1389 addChild(new RobustBufferAccessBehavior::StorageBufferTest(m_context));
1390 addChild(new RobustBufferAccessBehavior::UniformBufferTest(m_context));
1393 } /* es32cts namespace */