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.
20 * \file es32cRobustBufferAccessBehaviorTests.cpp
21 * \brief Implements conformance tests for "Robust Buffer Access Behavior" functionality.
22 */ /*-------------------------------------------------------------------*/
24 #include "es32cRobustBufferAccessBehaviorTests.hpp"
26 #include "gluContextInfo.hpp"
27 #include "gluDefs.hpp"
28 #include "gluStrUtil.hpp"
29 #include "glwEnums.hpp"
30 #include "glwFunctions.hpp"
31 #include "tcuTestLog.hpp"
37 using namespace deqp::RobustBufferAccessBehavior;
41 namespace RobustBufferAccessBehavior
45 * @param context Test context
47 VertexBufferObjectsTest::VertexBufferObjectsTest(deqp::Context& context)
48 : deqp::RobustBufferAccessBehavior::VertexBufferObjectsTest(
49 context, "vertex_buffer_objects", "Verifies that out-of-bound reads from VB result in zero")
51 /* Nothing to be done */
54 /** Prepare shader for current test case
58 std::string VertexBufferObjectsTest::getFragmentShader()
60 return std::string("#version 320 es\n"
62 "layout (location = 0) out lowp uvec4 out_fs_color;\n"
66 " out_fs_color = uvec4(1, 255, 255, 255);\n"
71 /** Prepare shader for current test case
75 std::string VertexBufferObjectsTest::getVertexShader()
77 return std::string("#version 320 es\n"
79 "layout (location = 0) in vec4 in_vs_position;\n"
83 " gl_Position = in_vs_position;\n"
88 /** No verification because of undefined out-of-bound behavior in OpenGL ES
90 * @param texture_id Id of texture
94 bool VertexBufferObjectsTest::verifyInvalidResults(glw::GLuint texture_id)
100 /** Verifies that texutre is filled with 1
102 * @param texture_id Id of texture
104 * @return true when image is filled with 1, false otherwise
106 bool VertexBufferObjectsTest::verifyResults(glw::GLuint texture_id)
108 static const GLuint height = 8;
109 static const GLuint width = 8;
110 static const GLuint pixel_size = 4 * sizeof(GLuint);
112 const Functions& gl = m_context.getRenderContext().getFunctions();
114 const GLint buf_size = width * height * pixel_size;
115 GLubyte pixels[buf_size];
116 deMemset(pixels, 0, buf_size);
118 Texture::Bind(gl, texture_id, GL_TEXTURE_2D);
120 Texture::GetData(gl, texture_id, 0 /* level */, width, height, GL_RGBA_INTEGER, GL_UNSIGNED_INT, pixels);
123 Texture::Bind(gl, 0, GL_TEXTURE_2D);
126 for (GLuint i = 0; i < buf_size; i += pixel_size)
130 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Invalid value: " << (GLuint)pixels[i]
131 << " at offset: " << i << tcu::TestLog::EndMessage;
142 * @param context Test context
144 TexelFetchTest::TexelFetchTest(deqp::Context& context)
145 : deqp::RobustBufferAccessBehavior::TexelFetchTest(context, "texel_fetch",
146 "Verifies that out-of-bound fetches from texture result in zero")
148 /* Nothing to be done */
151 TexelFetchTest::TexelFetchTest(deqp::Context& context, const glw::GLchar* name, const glw::GLchar* description)
152 : deqp::RobustBufferAccessBehavior::TexelFetchTest(context, name, description)
154 /* Nothing to be done */
157 /** Prepare shader for current test case
161 std::string TexelFetchTest::getGeometryShader()
163 return std::string("#version 320 es\n"
165 "layout(points) in;\n"
166 "layout(triangle_strip, max_vertices = 4) out;\n"
168 "out vec2 gs_fs_tex_coord;\n"
172 " gs_fs_tex_coord = vec2(0, 0);\n"
173 " gl_Position = vec4(-1, -1, 0, 1);\n"
176 " gs_fs_tex_coord = vec2(0, 1);\n"
177 " gl_Position = vec4(-1, 1, 0, 1);\n"
180 " gs_fs_tex_coord = vec2(1, 0);\n"
181 " gl_Position = vec4(1, -1, 0, 1);\n"
184 " gs_fs_tex_coord = vec2(1, 1);\n"
185 " gl_Position = vec4(1, 1, 0, 1);\n"
191 /** Prepare shader for current test case
195 std::string TexelFetchTest::getVertexShader()
197 return std::string("#version 320 es\n"
201 " gl_Position = vec4(0, 0, 0, 1);\n"
206 /** Prepare a texture
208 * @param is_source Selects if texutre will be used as source or destination
209 * @param texture_id Id of texutre
211 void TexelFetchTest::prepareTexture(bool is_source, glw::GLuint texture_id)
214 static const GLuint image_height = 16;
215 static const GLuint image_width = 16;
217 /* GL entry points */
218 const Functions& gl = m_context.getRenderContext().getFunctions();
220 /* Texture storage parameters */
221 GLuint height = image_height;
222 GLenum internal_format = 0;
223 GLsizei n_levels = 1;
224 GLenum target = GL_TEXTURE_2D;
225 GLuint width = image_width;
227 /* Prepare texture storage parameters */
231 internal_format = GL_R8;
234 internal_format = GL_RG8_SNORM;
237 internal_format = GL_RGBA32F;
240 height = 2 * image_height;
241 internal_format = GL_R32UI;
243 width = 2 * image_width;
245 case R32UI_MULTISAMPLE:
246 internal_format = GL_R32UI;
248 target = GL_TEXTURE_2D_MULTISAMPLE;
251 TCU_FAIL("Invalid enum");
254 /* Prepare storage */
255 Texture::Bind(gl, texture_id, target);
256 Texture::Storage(gl, target, n_levels, internal_format, width, height, 0);
258 /* Set samplers to NEAREST/NEAREST if required */
259 if (R32UI_MULTISAMPLE != m_test_case)
261 gl.texParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
262 gl.texParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
265 /* Destination image can be left empty */
266 if (false == is_source)
268 Texture::Bind(gl, 0, target);
272 /* Prepare texture */
273 if (R8 == m_test_case)
275 GLubyte source_pixels[image_width * image_height];
276 for (GLuint i = 0; i < image_width * image_height; ++i)
278 source_pixels[i] = (GLubyte)i;
281 Texture::SubImage(gl, GL_TEXTURE_2D, 0 /* level */, 0 /* x */, 0 /* y */, 0 /* z */, width, height,
282 0 /* depth */, GL_RED, GL_UNSIGNED_BYTE, source_pixels);
284 else if (RG8_SNORM == m_test_case)
286 static const GLuint n_components = 2;
288 GLbyte source_pixels[image_width * image_height * n_components];
289 for (GLuint i = 0; i < image_width * image_height; ++i)
291 source_pixels[i * n_components + 0] = (GLubyte)((i % 16));
292 source_pixels[i * n_components + 1] = (GLubyte)((i / 16));
295 Texture::SubImage(gl, GL_TEXTURE_2D, 0 /* level */, 0 /* x */, 0 /* y */, 0 /* z */, width, height,
296 0 /* depth */, GL_RG, GL_BYTE, source_pixels);
298 else if (RGBA32F == m_test_case)
300 static const GLuint n_components = 4;
302 GLfloat source_pixels[image_width * image_height * n_components];
303 for (GLuint i = 0; i < image_width * image_height; ++i)
305 source_pixels[i * n_components + 0] = (GLfloat)(i % 16) / 16.0f;
306 source_pixels[i * n_components + 1] = (GLfloat)(i / 16) / 16.0f;
307 source_pixels[i * n_components + 2] = (GLfloat)i / 256.0f;
308 source_pixels[i * n_components + 3] = 1.0f;
311 Texture::SubImage(gl, GL_TEXTURE_2D, 0 /* level */, 0 /* x */, 0 /* y */, 0 /* z */, width, height,
312 0 /* depth */, GL_RGBA, GL_FLOAT, source_pixels);
314 else if (R32UI_MIPMAP == m_test_case)
316 GLuint source_pixels[image_width * image_height];
317 for (GLuint i = 0; i < image_width * image_height; ++i)
319 source_pixels[i] = i;
322 Texture::SubImage(gl, GL_TEXTURE_2D, 1 /* level */, 0 /* x */, 0 /* y */, 0 /* z */, image_width, image_height,
323 0 /* depth */, GL_RED_INTEGER, GL_UNSIGNED_INT, source_pixels);
325 /* texelFetch() undefined if the computed level of detail is not the texture’s base level and the texture’s
326 minification filter is NEAREST or LINEAR */
327 gl.texParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
329 else if (R32UI_MULTISAMPLE == m_test_case)
332 static const GLchar* cs = "#version 320 es\n"
334 "layout (local_size_x = 16, local_size_y = 16, local_size_z = 1) in;\n"
336 "layout (binding = 0, r32ui) writeonly uniform highp uimage2DMS uni_image;\n"
340 " ivec2 point = ivec2(gl_WorkGroupID.x, gl_WorkGroupID.y);\n"
341 " uint index = gl_WorkGroupID.y * 16U + gl_WorkGroupID.x;\n"
343 " imageStore(uni_image, point, 0, uvec4(index + 0U, 0, 0, 0));\n"
344 " imageStore(uni_image, point, 1, uvec4(index + 1U, 0, 0, 0));\n"
345 " imageStore(uni_image, point, 2, uvec4(index + 2U, 0, 0, 0));\n"
346 " imageStore(uni_image, point, 3, uvec4(index + 3U, 0, 0, 0));\n"
350 Program program(m_context);
351 program.Init(cs, "", "", "", "", "");
354 gl.bindImageTexture(0 /* unit */, texture_id, 0 /* level */, GL_FALSE /* layered */, 0 /* layer */,
355 GL_WRITE_ONLY, GL_R32UI);
356 GLU_EXPECT_NO_ERROR(gl.getError(), "BindImageTexture");
358 gl.dispatchCompute(16, 16, 1);
359 GLU_EXPECT_NO_ERROR(gl.getError(), "DispatchCompute");
362 Texture::Bind(gl, 0, target);
365 /** No verification because of undefined out-of-bound behavior in OpenGL ES
367 * @param texture_id Id of texture
371 bool TexelFetchTest::verifyInvalidResults(glw::GLuint texture_id)
377 /** Verifies that texutre is filled with increasing values
379 * @param texture_id Id of texture
381 * @return true when image is filled with increasing values, false otherwise
383 bool TexelFetchTest::verifyValidResults(glw::GLuint texture_id)
385 static const GLuint height = 16;
386 static const GLuint width = 16;
387 static const GLuint n_pixels = height * width;
389 const Functions& gl = m_context.getRenderContext().getFunctions();
393 if (R8 == m_test_case)
395 static const GLuint n_channels = 4;
397 Texture::Bind(gl, texture_id, GL_TEXTURE_2D);
399 std::vector<GLubyte> pixels;
400 pixels.resize(n_pixels * n_channels);
401 for (GLuint i = 0; i < n_pixels; ++i)
403 pixels[i] = (GLubyte)i;
406 Texture::GetData(gl, texture_id, 0 /* level */, width, height, GL_RGBA, GL_UNSIGNED_BYTE, &pixels[0]);
409 Texture::Bind(gl, 0, GL_TEXTURE_2D);
412 for (GLuint i = 0; i < n_pixels; ++i)
414 const GLubyte expected_red = (GLubyte)i;
415 const GLubyte drawn_red = pixels[i * n_channels];
417 if (expected_red != drawn_red)
419 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Invalid value: " << (GLuint)drawn_red
420 << ". Expected value: " << (GLuint)expected_red
421 << " at offset: " << i << tcu::TestLog::EndMessage;
428 else if (RG8_SNORM == m_test_case)
430 static const GLuint n_channels = 4;
432 Texture::Bind(gl, texture_id, GL_TEXTURE_2D);
434 std::vector<GLubyte> pixels;
435 pixels.resize(n_pixels * n_channels);
436 for (GLuint i = 0; i < n_pixels; ++i)
438 pixels[i * n_channels + 0] = (GLubyte)i;
439 pixels[i * n_channels + 1] = (GLubyte)i;
442 Texture::GetData(gl, texture_id, 0 /* level */, width, height, GL_RGBA, GL_BYTE, &pixels[0]);
445 Texture::Bind(gl, 0, GL_TEXTURE_2D);
448 for (GLuint i = 0; i < n_pixels; ++i)
450 const GLbyte expected_red = (GLubyte)(i % 16);
451 const GLbyte expected_green = (GLubyte)(i / 16);
452 const GLbyte drawn_red = pixels[i * n_channels + 0];
453 const GLbyte drawn_green = pixels[i * n_channels + 1];
455 if ((expected_red != drawn_red) || (expected_green != drawn_green))
457 m_context.getTestContext().getLog()
458 << tcu::TestLog::Message << "Invalid value: " << (GLint)drawn_red << ", " << (GLint)drawn_green
459 << ". Expected value: " << (GLint)expected_red << ", " << (GLint)expected_green
460 << ". At offset: " << i << tcu::TestLog::EndMessage;
467 else if (RGBA32F == m_test_case)
469 static const GLuint n_channels = 4;
471 Texture::Bind(gl, texture_id, GL_TEXTURE_2D);
473 std::vector<GLfloat> pixels;
474 pixels.resize(n_pixels * n_channels);
475 for (GLuint i = 0; i < n_pixels; ++i)
477 pixels[i * n_channels + 0] = (GLfloat)i / (GLfloat)n_pixels;
478 pixels[i * n_channels + 1] = (GLfloat)i / (GLfloat)n_pixels;
479 pixels[i * n_channels + 2] = (GLfloat)i / (GLfloat)n_pixels;
480 pixels[i * n_channels + 3] = (GLfloat)i / (GLfloat)n_pixels;
483 Texture::GetData(gl, texture_id, 0 /* level */, width, height, GL_RGBA, GL_FLOAT, &pixels[0]);
486 Texture::Bind(gl, 0, GL_TEXTURE_2D);
489 for (GLuint i = 0; i < n_pixels; ++i)
491 const GLfloat expected_red = (GLfloat)(i % 16) / 16.0f;
492 const GLfloat expected_green = (GLfloat)(i / 16) / 16.0f;
493 const GLfloat expected_blue = (GLfloat)i / 256.0f;
494 const GLfloat expected_alpha = 1.0f;
495 const GLfloat drawn_red = pixels[i * n_channels + 0];
496 const GLfloat drawn_green = pixels[i * n_channels + 1];
497 const GLfloat drawn_blue = pixels[i * n_channels + 2];
498 const GLfloat drawn_alpha = pixels[i * n_channels + 3];
500 if ((expected_red != drawn_red) || (expected_green != drawn_green) || (expected_blue != drawn_blue) ||
501 (expected_alpha != drawn_alpha))
503 m_context.getTestContext().getLog()
504 << tcu::TestLog::Message << "Invalid value: " << drawn_red << ", " << drawn_green << ", "
505 << drawn_blue << ", " << drawn_alpha << ". Expected value: " << expected_red << ", "
506 << expected_green << ", " << expected_blue << ", " << expected_alpha << ". At offset: " << i
507 << tcu::TestLog::EndMessage;
514 else if (R32UI_MIPMAP == m_test_case)
516 static const GLuint n_channels = 4;
518 Texture::Bind(gl, texture_id, GL_TEXTURE_2D);
520 std::vector<GLuint> pixels;
521 pixels.resize(n_pixels * n_channels);
522 deMemset(&pixels[0], 0, n_pixels * n_channels * sizeof(GLuint));
524 Texture::GetData(gl, texture_id, 1 /* level */, width, height, GL_RGBA_INTEGER, GL_UNSIGNED_INT, &pixels[0]);
527 Texture::Bind(gl, 0, GL_TEXTURE_2D);
530 for (GLuint i = 0; i < n_pixels; ++i)
532 const GLuint expected_red = i;
533 const GLuint drawn_red = pixels[i * n_channels];
535 if (expected_red != drawn_red)
537 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Invalid value: " << drawn_red
538 << ". Expected value: " << expected_red << " at offset: " << i
539 << tcu::TestLog::EndMessage;
546 else if (R32UI_MULTISAMPLE == m_test_case)
548 static const GLuint n_channels = 4;
551 static const GLchar* cs =
554 "layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
556 "layout (binding = 1, r32ui) writeonly uniform lowp uimage2D uni_destination_image;\n"
557 "layout (binding = 0, r32ui) readonly uniform lowp uimage2DMS uni_source_image;\n"
561 " ivec2 point = ivec2(gl_WorkGroupID.x, gl_WorkGroupID.y);\n"
562 " uint index = gl_WorkGroupID.y * 16U + gl_WorkGroupID.x;\n"
564 " uvec4 color_0 = imageLoad(uni_source_image, point, 0);\n"
565 " uvec4 color_1 = imageLoad(uni_source_image, point, 1);\n"
566 " uvec4 color_2 = imageLoad(uni_source_image, point, 2);\n"
567 " uvec4 color_3 = imageLoad(uni_source_image, point, 3);\n"
569 " if (any(equal(uvec4(color_0.r, color_1.r, color_2.r, color_3.r), uvec4(index + 3U))))\n"
571 " imageStore(uni_destination_image, point, uvec4(1U));\n"
575 " imageStore(uni_destination_image, point, uvec4(0U));\n"
580 Program program(m_context);
581 Texture destination_texture(m_context);
583 Texture::Generate(gl, destination_texture.m_id);
584 Texture::Bind(gl, destination_texture.m_id, GL_TEXTURE_2D);
585 Texture::Storage(gl, GL_TEXTURE_2D, 1, GL_R32UI, width, height, 0 /* depth */);
587 program.Init(cs, "", "", "", "", "");
589 gl.bindImageTexture(0 /* unit */, texture_id, 0 /* level */, GL_FALSE /* layered */, 0 /* layer */,
590 GL_READ_ONLY, GL_R32UI);
591 GLU_EXPECT_NO_ERROR(gl.getError(), "BindImageTexture");
592 gl.bindImageTexture(1 /* unit */, destination_texture.m_id, 0 /* level */, GL_FALSE /* layered */,
593 0 /* layer */, GL_WRITE_ONLY, GL_R32UI);
594 GLU_EXPECT_NO_ERROR(gl.getError(), "BindImageTexture");
596 gl.dispatchCompute(16, 16, 1);
597 GLU_EXPECT_NO_ERROR(gl.getError(), "DispatchCompute");
599 /* Pixels buffer initialization */
600 std::vector<GLuint> pixels;
601 pixels.resize(n_pixels * n_channels);
602 for (GLuint i = 0; i < n_pixels * n_channels; ++i)
607 Texture::GetData(gl, destination_texture.m_id, 0 /* level */, width, height, GL_RGBA_INTEGER, GL_UNSIGNED_INT,
611 Texture::Bind(gl, 0, GL_TEXTURE_2D);
614 for (GLuint i = 0; i < n_pixels; ++i)
616 const GLuint expected_red = 1;
617 const GLuint drawn_red = pixels[i * n_channels];
619 if (expected_red != drawn_red)
621 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Invalid value: " << drawn_red
622 << ". Expected value: " << expected_red << " at offset: " << i
623 << tcu::TestLog::EndMessage;
636 * @param context Test context
638 ImageLoadStoreTest::ImageLoadStoreTest(deqp::Context& context)
639 : TexelFetchTest(context, "image_load_store", "Verifies that out-of-bound to image result in zero or is discarded")
641 /* start from RGBA32F as R8, R32UI_MULTISAMPLE and R8_SNORM are not supported under GLES */
642 m_test_case = RGBA32F;
647 * @return tcu::TestNode::STOP
649 tcu::TestNode::IterateResult ImageLoadStoreTest::iterate()
651 if (!m_context.getContextInfo().isExtensionSupported("GL_KHR_robust_buffer_access_behavior"))
653 m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Not Supported");
658 static const GLuint height = 16;
659 static const GLuint width = 16;
661 /* GL entry points */
662 const Functions& gl = m_context.getRenderContext().getFunctions();
664 const unsigned int coord_offsets[] = {
668 /* Test result indicator */
669 bool test_result = true;
671 /* Iterate over all cases */
672 while (LAST != m_test_case)
674 /* Test case result indicator */
675 bool case_result = true;
677 /* Test case objects */
678 Texture destination_texture(m_context);
679 Texture source_texture(m_context);
680 Program program(m_context);
682 /* Prepare textures */
683 Texture::Generate(gl, destination_texture.m_id);
684 Texture::Generate(gl, source_texture.m_id);
686 prepareTexture(false, destination_texture.m_id);
687 prepareTexture(true, source_texture.m_id);
689 /* Test invalid source cases */
690 for (GLuint i = 0; i < DE_LENGTH_OF_ARRAY(coord_offsets); ++i)
692 const std::string& cs = getComputeShader(SOURCE_INVALID, coord_offsets[i]);
693 program.Init(cs, "", "", "", "", "");
697 setTextures(destination_texture.m_id, source_texture.m_id);
700 gl.dispatchCompute(width, height, 1 /* depth */);
701 GLU_EXPECT_NO_ERROR(gl.getError(), "DispatchCompute");
704 if (false == verifyInvalidResults(destination_texture.m_id))
710 /* Test valid case */
711 program.Init(getComputeShader(VALID), "", "", "", "", "");
715 setTextures(destination_texture.m_id, source_texture.m_id);
718 gl.dispatchCompute(width, height, 1 /* depth */);
719 GLU_EXPECT_NO_ERROR(gl.getError(), "DispatchCompute");
722 if (false == verifyValidResults(destination_texture.m_id))
727 /* Test invalid destination cases */
728 for (GLuint i = 0; i < DE_LENGTH_OF_ARRAY(coord_offsets); ++i)
730 const std::string& cs = getComputeShader(DESTINATION_INVALID, coord_offsets[i]);
731 program.Init(cs, "", "", "", "", "");
735 setTextures(destination_texture.m_id, source_texture.m_id);
738 gl.dispatchCompute(width, height, 1 /* depth */);
739 GLU_EXPECT_NO_ERROR(gl.getError(), "DispatchCompute");
742 if (false == verifyValidResults(destination_texture.m_id))
748 /* Set test result */
749 if (false == case_result)
751 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Test case: " << getTestCaseName()
752 << " failed" << tcu::TestLog::EndMessage;
758 m_test_case = (TEST_CASES)((GLuint)m_test_case + 1);
762 if (true == test_result)
764 m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Pass");
768 m_context.getTestContext().setTestResult(QP_TEST_RESULT_FAIL, "Fail");
772 return tcu::TestNode::STOP;
775 /** Prepare shader for current test case
777 * @param version Specify which version should be prepared
781 std::string ImageLoadStoreTest::getComputeShader(VERSION version, GLuint coord_offset)
783 static const GLchar* template_code =
786 "layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
788 "layout (binding = 1, FORMAT) writeonly uniform highp IMAGE uni_destination_image;\n"
789 "layout (binding = 0, FORMAT) readonly uniform highp IMAGE uni_source_image;\n"
793 " ivec2 point_destination = ivec2(gl_WorkGroupID.xy) + ivec2(COORD_OFFSETU);\n"
794 " ivec2 point_source = ivec2(gl_WorkGroupID.xy) + ivec2(COORD_OFFSETU);\n"
800 static const GLchar* copy_regular = " TYPE color = imageLoad(uni_source_image, point_source);\n"
801 " imageStore(uni_destination_image, point_destination, color);\n";
803 static const GLchar* format_rgba32f = "rgba32f";
804 static const GLchar* format_r32ui = "r32ui";
806 static const GLchar* image_vec4 = "image2D";
808 static const GLchar* image_uvec4 = "uimage2D";
810 static const GLchar* type_vec4 = "vec4";
811 static const GLchar* type_uvec4 = "uvec4";
813 const GLchar* copy = copy_regular;
814 const GLchar* format = format_rgba32f;
815 const GLchar* image = image_vec4;
816 const GLchar* type = type_vec4;
817 const GLchar* src_coord_offset = "0";
818 const GLchar* dst_coord_offset = "0";
820 std::stringstream coord_offset_stream;
821 coord_offset_stream << coord_offset;
822 std::string coord_offset_str = coord_offset_stream.str();
824 if (version == SOURCE_INVALID)
825 src_coord_offset = coord_offset_str.c_str();
826 else if (version == DESTINATION_INVALID)
827 dst_coord_offset = coord_offset_str.c_str();
832 format = format_rgba32f;
835 format = format_r32ui;
840 TCU_FAIL("Invalid enum");
844 std::string source = template_code;
846 replaceToken("FORMAT", position, format, source);
847 replaceToken("IMAGE", position, image, source);
848 replaceToken("FORMAT", position, format, source);
849 replaceToken("IMAGE", position, image, source);
850 replaceToken("COORD_OFFSET", position, dst_coord_offset, source);
851 replaceToken("COORD_OFFSET", position, src_coord_offset, source);
853 size_t temp_position = position;
854 replaceToken("COPY", position, copy, source);
855 position = temp_position;
861 replaceToken("TYPE", position, type, source);
864 TCU_FAIL("Invalid enum");
870 /** Set textures as images
872 * @param id_destination Id of texture used as destination
873 * @param id_source Id of texture used as source
875 void ImageLoadStoreTest::setTextures(glw::GLuint id_destination, glw::GLuint id_source)
877 const Functions& gl = m_context.getRenderContext().getFunctions();
892 TCU_FAIL("Invalid enum");
895 gl.bindImageTexture(0 /* unit */, id_source, level, GL_FALSE /* layered */, 0 /* layer */, GL_READ_ONLY, format);
896 GLU_EXPECT_NO_ERROR(gl.getError(), "BindImageTexture");
898 gl.bindImageTexture(1 /* unit */, id_destination, level, GL_FALSE /* layered */, 0 /* layer */, GL_WRITE_ONLY,
900 GLU_EXPECT_NO_ERROR(gl.getError(), "BindImageTexture");
903 /** No verification because of undefined out-of-bound behavior in OpenGL ES
905 * @param texture_id Id of texture
909 bool ImageLoadStoreTest::verifyInvalidResults(glw::GLuint texture_id)
915 /** Verifies that texutre is filled with increasing values
917 * @param texture_id Id of texture
919 * @return true when image is filled with increasing values, false otherwise
921 bool ImageLoadStoreTest::verifyValidResults(glw::GLuint texture_id)
923 static const GLuint height = 16;
924 static const GLuint width = 16;
925 static const GLuint n_pixels = height * width;
927 const Functions& gl = m_context.getRenderContext().getFunctions();
928 gl.memoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
929 GLU_EXPECT_NO_ERROR(gl.getError(), "MemoryBarrier");
933 if (RGBA32F == m_test_case)
935 static const GLuint n_channels = 4;
937 Texture::Bind(gl, texture_id, GL_TEXTURE_2D);
939 std::vector<GLfloat> pixels;
940 pixels.resize(n_pixels * n_channels);
941 for (GLuint i = 0; i < n_pixels; ++i)
943 pixels[i * n_channels + 0] = (GLfloat)i / (GLfloat)n_pixels;
944 pixels[i * n_channels + 1] = (GLfloat)i / (GLfloat)n_pixels;
945 pixels[i * n_channels + 2] = (GLfloat)i / (GLfloat)n_pixels;
946 pixels[i * n_channels + 3] = (GLfloat)i / (GLfloat)n_pixels;
949 Texture::GetData(gl, texture_id, 0 /* level */, width, height, GL_RGBA, GL_FLOAT, &pixels[0]);
952 Texture::Bind(gl, 0, GL_TEXTURE_2D);
955 for (GLuint i = 0; i < n_pixels; ++i)
957 const GLfloat expected_red = (GLfloat)(i % 16) / 16.0f;
958 const GLfloat expected_green = (GLfloat)(i / 16) / 16.0f;
959 const GLfloat expected_blue = (GLfloat)i / 256.0f;
960 const GLfloat expected_alpha = 1.0f;
961 const GLfloat drawn_red = pixels[i * n_channels + 0];
962 const GLfloat drawn_green = pixels[i * n_channels + 1];
963 const GLfloat drawn_blue = pixels[i * n_channels + 2];
964 const GLfloat drawn_alpha = pixels[i * n_channels + 3];
966 if ((expected_red != drawn_red) || (expected_green != drawn_green) || (expected_blue != drawn_blue) ||
967 (expected_alpha != drawn_alpha))
969 m_context.getTestContext().getLog()
970 << tcu::TestLog::Message << "Invalid value: " << drawn_red << ", " << drawn_green << ", "
971 << drawn_blue << ", " << drawn_alpha << ". Expected value: " << expected_red << ", "
972 << expected_green << ", " << expected_blue << ", " << expected_alpha << ". At offset: " << i
973 << tcu::TestLog::EndMessage;
980 else if (R32UI_MIPMAP == m_test_case)
982 static const GLuint n_channels = 4;
984 Texture::Bind(gl, texture_id, GL_TEXTURE_2D);
986 std::vector<GLuint> pixels;
987 pixels.resize(n_pixels * n_channels);
988 for (GLuint i = 0; i < n_pixels * n_channels; ++i)
993 Texture::GetData(gl, texture_id, 1 /* level */, width, height, GL_RGBA_INTEGER, GL_UNSIGNED_INT, &pixels[0]);
996 Texture::Bind(gl, 0, GL_TEXTURE_2D);
999 for (GLuint i = 0; i < n_pixels; ++i)
1001 const GLuint expected_red = i;
1002 const GLuint drawn_red = pixels[i * n_channels];
1004 if (expected_red != drawn_red)
1006 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Invalid value: " << drawn_red
1007 << ". Expected value: " << expected_red << " at offset: " << i
1008 << tcu::TestLog::EndMessage;
1021 * @param context Test context
1023 StorageBufferTest::StorageBufferTest(deqp::Context& context)
1024 : deqp::RobustBufferAccessBehavior::StorageBufferTest(
1025 context, "storage_buffer", "Verifies that out-of-bound access to SSBO results with no error")
1027 /* Nothing to be done here */
1030 /** Prepare shader for current test case
1034 std::string StorageBufferTest::getComputeShader(glw::GLuint offset)
1036 static const GLchar* cs = "#version 320 es\n"
1038 "layout (local_size_x = 4, local_size_y = 1, local_size_z = 1) in;\n"
1040 "layout (binding = 1) buffer Source {\n"
1044 "layout (binding = 0) buffer Destination {\n"
1050 " uint index_destination = gl_LocalInvocationID.x + OFFSETU;\n"
1051 " uint index_source = gl_LocalInvocationID.x + OFFSETU;\n"
1053 " destination.data[index_destination] = source.data[index_source];\n"
1057 std::string destination_offset("0");
1058 std::string source_offset("0");
1059 size_t position = 0;
1060 std::string source = cs;
1062 std::stringstream offset_stream;
1063 offset_stream << offset;
1065 if (m_test_case == SOURCE_INVALID)
1066 source_offset = offset_stream.str();
1067 else if (m_test_case == DESTINATION_INVALID)
1068 destination_offset = offset_stream.str();
1070 replaceToken("OFFSET", position, destination_offset.c_str(), source);
1071 replaceToken("OFFSET", position, source_offset.c_str(), source);
1076 /** Verify test case results
1078 * @param buffer_data Buffer data to verify
1080 * @return true if buffer_data is as expected, false othrewise
1082 bool StorageBufferTest::verifyResults(GLfloat* buffer_data)
1084 static const GLfloat expected_data_valid[4] = { 2.0f, 3.0f, 4.0f, 5.0f };
1085 static const GLfloat expected_data_invalid_destination[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
1086 static const GLfloat expected_data_invalid_source[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
1088 int size = sizeof(GLfloat) * 4;
1090 /* Prepare expected data const for proper case*/
1091 const GLfloat* expected_data = 0;
1092 const GLchar* name = 0;
1093 switch (m_test_case)
1096 expected_data = expected_data_valid;
1097 name = "valid indices";
1099 case SOURCE_INVALID:
1100 expected_data = expected_data_invalid_source;
1101 name = "invalid source indices";
1103 case DESTINATION_INVALID:
1104 expected_data = expected_data_invalid_destination;
1105 name = "invalid destination indices";
1108 TCU_FAIL("Invalid enum");
1111 /* Verify buffer data */
1112 if (m_test_case == VALID && memcmp(expected_data, buffer_data, size) != 0)
1114 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Test case: " << name << " failed"
1115 << tcu::TestLog::EndMessage;
1124 * @param context Test context
1126 UniformBufferTest::UniformBufferTest(deqp::Context& context)
1127 : deqp::RobustBufferAccessBehavior::UniformBufferTest(
1128 context, "uniform_buffer", "Verifies that out-of-bound access to UBO resutls with no error")
1130 /* Nothing to be done here */
1133 /** Prepare shader for current test case
1137 std::string UniformBufferTest::getComputeShader(GLuint offset)
1139 static const GLchar* cs = "#version 320 es\n"
1141 "layout (local_size_x = 4, local_size_y = 1, local_size_z = 1) in;\n"
1143 "layout (binding = 0, std140) uniform Source {\n"
1144 " float data[16];\n"
1147 "layout (binding = 0, std430) buffer Destination {\n"
1153 " uint index_destination = gl_LocalInvocationID.x + OFFSETU;\n"
1154 " uint index_source = gl_LocalInvocationID.x + OFFSETU;\n"
1156 " destination.data[index_destination] = source.data[index_source];\n"
1160 const GLchar* destination_offset = "0";
1161 std::string source_offset("0");
1162 size_t position = 0;
1163 std::string source = cs;
1165 std::stringstream offset_stream;
1166 offset_stream << offset;
1168 if (m_test_case == SOURCE_INVALID)
1169 source_offset = offset_stream.str();
1171 replaceToken("OFFSET", position, destination_offset, source);
1172 replaceToken("OFFSET", position, source_offset.c_str(), source);
1177 } /* RobustBufferAccessBehavior */
1181 * @param context Rendering context.
1183 RobustBufferAccessBehaviorTests::RobustBufferAccessBehaviorTests(deqp::Context& context)
1184 : deqp::RobustBufferAccessBehaviorTests(context)
1186 /* Left blank on purpose */
1189 /** Initializes a multi_bind test group.
1192 void RobustBufferAccessBehaviorTests::init(void)
1194 addChild(new RobustBufferAccessBehavior::VertexBufferObjectsTest(m_context));
1195 addChild(new RobustBufferAccessBehavior::TexelFetchTest(m_context));
1196 addChild(new RobustBufferAccessBehavior::ImageLoadStoreTest(m_context));
1197 addChild(new RobustBufferAccessBehavior::StorageBufferTest(m_context));
1198 addChild(new RobustBufferAccessBehavior::UniformBufferTest(m_context));
1201 } /* es32cts namespace */