#ifndef _GLCROBUSTBUFFERACCESSBEHAVIORTESTS_HPP #define _GLCROBUSTBUFFERACCESSBEHAVIORTESTS_HPP /*------------------------------------------------------------------------- * OpenGL Conformance Test Suite * ----------------------------- * * Copyright (c) 2016 The Khronos Group Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ /*! * \file glcRobustBufferAccessBehaviorTests.hpp * \brief Declares test classes for "Robust Buffer Access Behavior" functionality. */ /*-------------------------------------------------------------------*/ #include "glcRobustnessTests.hpp" #include "glcTestCase.hpp" #include "glwDefs.hpp" #include "glwEnums.hpp" #include namespace glcts { namespace RobustBufferAccessBehavior { /** Replace first occurance of with in starting at **/ void replaceToken(const glw::GLchar* token, size_t& search_position, const glw::GLchar* text, std::string& string); /** Represents buffer instance * Provides basic buffer functionality **/ class Buffer { public: /* Public methods */ /* Ctr & Dtr */ Buffer(const glw::Functions& gl); ~Buffer(); /* Init & Release */ void InitData(glw::GLenum target, glw::GLenum usage, glw::GLsizeiptr size, const glw::GLvoid* data); void Release(); /* Functionality */ void Bind() const; void BindBase(glw::GLuint index) const; /* Public static routines */ /* Functionality */ static void Bind(const glw::Functions& gl, glw::GLuint id, glw::GLenum target); static void BindBase(const glw::Functions& gl, glw::GLuint id, glw::GLenum target, glw::GLuint index); static void Data(const glw::Functions& gl, glw::GLenum target, glw::GLenum usage, glw::GLsizeiptr size, const glw::GLvoid* data); static void Generate(const glw::Functions& gl, glw::GLuint& out_id); static void SubData(const glw::Functions& gl, glw::GLenum target, glw::GLintptr offset, glw::GLsizeiptr size, glw::GLvoid* data); /* Public fields */ glw::GLuint m_id; /* Public constants */ static const glw::GLuint m_invalid_id; static const glw::GLuint m_n_targets = 13; static const glw::GLenum m_targets[m_n_targets]; private: /* Private enums */ /* Private fields */ const glw::Functions& m_gl; glw::GLenum m_target; }; /** Represents framebuffer * Provides basic functionality **/ class Framebuffer { public: /* Public methods */ /* Ctr & Dtr */ Framebuffer(const glw::Functions& gl); ~Framebuffer(); /* Init & Release */ void Release(); /* Public static routines */ static void AttachTexture(const glw::Functions& gl, glw::GLenum target, glw::GLenum attachment, glw::GLuint texture_id, glw::GLint level, glw::GLuint width, glw::GLuint height); static void Bind(const glw::Functions& gl, glw::GLenum target, glw::GLuint id); static void Generate(const glw::Functions& gl, glw::GLuint& out_id); /* Public fields */ glw::GLuint m_id; /* Public constants */ static const glw::GLuint m_invalid_id; private: /* Private fields */ const glw::Functions& m_gl; }; /** Represents shader instance. * Provides basic functionality for shaders. **/ class Shader { public: /* Public methods */ /* Ctr & Dtr */ Shader(const glw::Functions& gl); ~Shader(); /* Init & Realese */ void Init(glw::GLenum stage, const std::string& source); void Release(); /* Public static routines */ /* Functionality */ static void Compile(const glw::Functions& gl, glw::GLuint id); static void Create(const glw::Functions& gl, glw::GLenum stage, glw::GLuint& out_id); static void Source(const glw::Functions& gl, glw::GLuint id, const std::string& source); /* Public fields */ glw::GLuint m_id; /* Public constants */ static const glw::GLuint m_invalid_id; private: /* Private fields */ const glw::Functions& m_gl; }; /** Represents program instance. * Provides basic functionality **/ class Program { public: /* Public methods */ /* Ctr & Dtr */ Program(const glw::Functions& gl); ~Program(); /* Init & Release */ void 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); void Release(); /* Functionality */ void Use() const; /* Public static routines */ /* Functionality */ static void Attach(const glw::Functions& gl, glw::GLuint program_id, glw::GLuint shader_id); static void Create(const glw::Functions& gl, glw::GLuint& out_id); static void Link(const glw::Functions& gl, glw::GLuint id); static void Use(const glw::Functions& gl, glw::GLuint id); /* Public fields */ glw::GLuint m_id; Shader m_compute; Shader m_fragment; Shader m_geometry; Shader m_tess_ctrl; Shader m_tess_eval; Shader m_vertex; /* Public constants */ static const glw::GLuint m_invalid_id; private: /* Private fields */ const glw::Functions& m_gl; }; /** Represents texture instance **/ class Texture { public: /* Public methods */ /* Ctr & Dtr */ Texture(const glw::Functions& gl); ~Texture(); /* Init & Release */ void Release(); /* Public static routines */ /* Functionality */ static void Bind(const glw::Functions& gl, glw::GLuint id, glw::GLenum target); static void 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); static void Generate(const glw::Functions& gl, glw::GLuint& out_id); static void GetData(const glw::Functions& gl, glw::GLint level, glw::GLenum target, glw::GLenum format, glw::GLenum type, glw::GLvoid* out_data); static void 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); static void GetLevelParameter(const glw::Functions& gl, glw::GLenum target, glw::GLint level, glw::GLenum pname, glw::GLint* param); static void 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); static void Storage(const glw::Functions& gl, glw::GLenum target, glw::GLsizei levels, glw::GLenum internal_format, glw::GLuint width, glw::GLuint height, glw::GLuint depth); static void 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); /* Public fields */ glw::GLuint m_id; /* Public constants */ static const glw::GLuint m_invalid_id; private: /* Private fields */ const glw::Functions& m_gl; }; /** Represents Vertex array object * Provides basic functionality **/ class VertexArray { public: /* Public methods */ /* Ctr & Dtr */ VertexArray(const glw::Functions& gl); ~VertexArray(); /* Init & Release */ void Release(); /* Public static methods */ static void Bind(const glw::Functions& gl, glw::GLuint id); static void Generate(const glw::Functions& gl, glw::GLuint& out_id); /* Public fields */ glw::GLuint m_id; /* Public constants */ static const glw::GLuint m_invalid_id; private: /* Private fields */ const glw::Functions& m_gl; }; class RobustnessBase : public tcu::TestCase { public: RobustnessBase(tcu::TestContext& testCtx, const char* name, const char* description, glu::ApiType apiType); glu::RenderContext* createRobustContext( glu::ResetNotificationStrategy reset = glu::RESET_NOTIFICATION_STRATEGY_NO_RESET_NOTIFICATION); protected: glu::ApiType m_api_type; bool m_context_is_es; bool m_has_khr_robust_buffer_access; std::map m_specializationMap; }; /** Implementation of test VertexBufferObjects. Description follows: * * This test verifies that any "out-of-bound" read from vertex buffer result with abnormal program exit * * Steps: * - prepare vertex buffer with the following vertices: * * 0 - [ 0, 0, 0], * * 1 - [-1, 0, 0], * * 2 - [-1, 1, 0], * * 3 - [ 0, 1, 0], * * 4 - [ 1, 1, 0], * * 5 - [ 1, 0, 0], * * 6 - [ 1, -1, 0], * * 7 - [ 0, -1, 0], * * 8 - [-1, -1, 0]; * - prepare element buffer: * * valid: * 0, 1, 2, * 0, 2, 3, * 0, 3, 4, * 0, 4, 5, * 0, 5, 6, * 0, 6, 7, * 0, 7, 8, * 0, 8, 1; * * invalid: * 9, 1, 2, * 10, 2, 3, * 11, 3, 4, * 12, 4, 5, * 13, 5, 6, * 14, 6, 7, * 15, 7, 8, * 16, 8, 1; * - prepare program consisting of vertex and fragment shader that will output * value 1; * - prepare framebuffer with R8UI texture attached as color 0, filled with * value 128; * - execute draw call with invalid element buffer; * - inspect contents of framebuffer, it is expected that it is filled with * value 1; * - clean framebuffer to value 128; * - execute draw call with valid element buffer; * - inspect contents of framebuffer, it is expected that it is filled with * value 1. **/ class VertexBufferObjectsTest : public RobustnessBase { public: /* Public methods */ VertexBufferObjectsTest(tcu::TestContext& testCtx, glu::ApiType apiType); virtual ~VertexBufferObjectsTest() { } /* Public methods inherited from TestCase */ virtual tcu::TestNode::IterateResult iterate(void); protected: /* Protected methods */ std::string getFragmentShader(); std::string getVertexShader(); void cleanTexture(const glw::Functions& gl, glw::GLuint texture_id); bool verifyInvalidResults(const glw::Functions& gl, glw::GLuint texture_id); bool verifyValidResults(const glw::Functions& gl, glw::GLuint texture_id); bool verifyResults(const glw::Functions& gl, glw::GLuint texture_id); }; /** Implementation of test TexelFetch. Description follows: * * This test verifies that any "out-of-bound" fetch from texture result in * "zero". * * Steps: * - prepare program consisting of vertex, geometry and fragment shader that * will output full-screen quad; Each fragment should receive value of * corresponding texel from source texture; Use texelFetch function; * - prepare 16x16 2D R8UI source texture filled with unique values; * - prepare framebuffer with 16x16 R8UI texture as color attachment, filled * with value 0; * - execute draw call; * - inspect contents of framebuffer, it is expected to match source texture; * - modify program so it will fetch invalid texels; * - execute draw call; * - inspect contents of framebuffer, it is expected that it will be filled * with value 0 for RGB channels and with 0, 1 or the biggest representable * integral number for alpha channel. * * Repeat steps for: * - R8 texture; * - RG8_SNORM texture; * - RGBA32F texture; * - mipmap at level 1; * - a texture with 4 samples. **/ class TexelFetchTest : public RobustnessBase { public: /* Public methods */ TexelFetchTest(tcu::TestContext& testCtx, glu::ApiType apiType); TexelFetchTest(tcu::TestContext& testCtx, const char* name, const char* description, glu::ApiType apiType); virtual ~TexelFetchTest() { } /* Public methods inherited from TestCase */ virtual tcu::TestNode::IterateResult iterate(void); protected: /* Protected enums */ enum TEST_CASES { R8, RG8_SNORM, R32UI_MULTISAMPLE, RGBA32F, R32UI_MIPMAP, /* */ LAST }; enum VERSION { VALID, SOURCE_INVALID, DESTINATION_INVALID, }; /* Protected methods */ const glw::GLchar* getTestCaseName() const; void prepareTexture(const glw::Functions& gl, bool is_source, glw::GLuint texture_id); /* Protected fields */ TEST_CASES m_test_case; protected: /* Protected methods */ std::string getFragmentShader(const glu::ContextType& contextType, bool is_case_valid, glw::GLuint fetch_offset = 0); std::string getGeometryShader(); std::string getVertexShader(); virtual bool verifyInvalidResults(const glw::Functions& gl, glw::GLuint texture_id); virtual bool verifyValidResults(const glw::Functions& gl, glw::GLuint texture_id); }; /** Implementation of test ImageLoadStore. Description follows: * * This test verifies that any "out-of-bound" access to image result in "zero" * or is discarded. * * Modify TexelFetch test in the following aspects: * - use compute shader instead of "draw" pipeline; * - use imageLoad instead of texelFetch; * - use destination image instead of framebuffer; Store texel with imageStore; * - for each case from TexelFetch verify: * * valid coordinates for source and destination images; * * invalid coordinates for destination and valid ones for source image; * * valid coordinates for destination and invalid ones for source image. **/ class ImageLoadStoreTest : public TexelFetchTest { public: /* Public methods */ ImageLoadStoreTest(tcu::TestContext& testCtx, glu::ApiType apiType); virtual ~ImageLoadStoreTest() { } /* Public methods inherited from TestCase */ virtual tcu::TestNode::IterateResult iterate(void); protected: /* Protected methods */ std::string getComputeShader(VERSION version, glw::GLuint coord_offset = 0, glw::GLuint sample_offset = 0); void setTextures(const glw::Functions& gl, glw::GLuint id_destination, glw::GLuint id_source); bool verifyInvalidResults(const glw::Functions& gl, glw::GLuint texture_id); bool verifyValidResults(const glw::Functions& gl, glw::GLuint texture_id); }; /** Implementation of test StorageBuffer. Description follows: * * This test verifies that any "out-of-bound" access to buffer result in zero * or is discarded. * * Steps: * - prepare compute shader based on the following code snippet: * * uint dst_index = gl_LocalInvocationID.x; * uint src_index = gl_LocalInvocationID.x; * destination[dst_index] = source[src_index]; * * where source and destination are storage buffers, defined as unsized arrays * of floats; * - prepare two buffers of 4 floats: * * destination filled with value 1; * * source filled with unique values; * - dispatch program to copy all 4 values; * - inspect program to verify that contents of source buffer were copied to * destination; * - repeat steps for the following cases: * * value of dst_index is equal to gl_LocalInvocationID.x + 16; It is * expected that destination buffer will not be modified; * * value of src_index is equal to gl_LocalInvocationID.x + 16; It is * expected that destination buffer will be filled with value 0. **/ class StorageBufferTest : public RobustnessBase { public: /* Public methods */ StorageBufferTest(tcu::TestContext& testCtx, glu::ApiType apiType); virtual ~StorageBufferTest() { } /* Public methods inherited from TestCase */ virtual tcu::TestNode::IterateResult iterate(void); protected: /* Protected enums */ enum VERSION { VALID, SOURCE_INVALID, DESTINATION_INVALID, /* */ LAST }; /* Private methods */ std::string getComputeShader(glw::GLuint offset); bool verifyResults(glw::GLfloat* buffer_data); /* Protected fields */ VERSION m_test_case; /* Protected constants */ static const glw::GLfloat m_destination_data[4]; static const glw::GLfloat m_source_data[4]; }; /** Implementation of test UniformBuffer. Description follows: * * This test verifies that any "out-of-bound" read from uniform buffer result * in zero; * * Modify StorageBuffer test in the following aspects: * - use uniform buffer for source instead of storage buffer; * - ignore the case with invalid value of dst_index. **/ class UniformBufferTest : public RobustnessBase { public: /* Public methods */ UniformBufferTest(tcu::TestContext& testCtx, glu::ApiType apiType); virtual ~UniformBufferTest() { } /* Public methods inherited from TestCase */ virtual tcu::TestNode::IterateResult iterate(void); protected: /* Protected enums */ enum VERSION { VALID, SOURCE_INVALID, /* */ LAST }; /* Protected methods */ std::string getComputeShader(glw::GLuint offset); bool verifyResults(glw::GLfloat* buffer_data); /* Protected fields */ VERSION m_test_case; }; } /* RobustBufferAccessBehavior */ /** Group class for multi bind conformance tests */ class RobustBufferAccessBehaviorTests : public tcu::TestCaseGroup { public: /* Public methods */ RobustBufferAccessBehaviorTests(tcu::TestContext& testCtx, glu::ApiType apiType); virtual ~RobustBufferAccessBehaviorTests(void) { } virtual void init(void); private: /* Private methods */ RobustBufferAccessBehaviorTests(const RobustBufferAccessBehaviorTests& other); RobustBufferAccessBehaviorTests& operator=(const RobustBufferAccessBehaviorTests& other); glu::ApiType m_ApiType; }; } /* glcts */ #endif // _GLCROBUSTBUFFERACCESSBEHAVIORTESTS_HPP