1 /*------------------------------------------------------------------------- 2 * OpenGL Conformance Test Suite 3 * ----------------------------- 4 * 5 * Copyright (c) 2014-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 21 * \brief 22 */ /*-------------------------------------------------------------------*/ 23 24 /*! 25 * \file esextcGPUShader5ImagesArrayIndexing.cpp 26 * \brief GPUShader5 Images Array Indexing (Test 2) 27 */ /*-------------------------------------------------------------------*/ 28 29 #include "esextcGPUShader5ImagesArrayIndexing.hpp" 30 #include "gluContextInfo.hpp" 31 #include "gluDefs.hpp" 32 #include "glwEnums.hpp" 33 #include "glwFunctions.hpp" 34 #include "tcuTestLog.hpp" 35 #include <string.h> 36 37 namespace glcts 38 { 39 40 const glw::GLuint GPUShader5ImagesArrayIndexing::m_array_size = 4; 41 const glw::GLint GPUShader5ImagesArrayIndexing::m_texture_n_components = 1; 42 43 /** Constructor 44 * 45 * @param context Test context 46 * @param name Test case's name 47 * @param description Test case's description 48 **/ 49 GPUShader5ImagesArrayIndexing::GPUShader5ImagesArrayIndexing(Context& context, const ExtParameters& extParams, 50 const char* name, const char* description) 51 : TestCaseBase(context, extParams, name, description) 52 , m_compute_shader_id(0) 53 , m_data_buffer(DE_NULL) 54 , m_program_id(0) 55 , m_texture_height(0) 56 , m_texture_width(0) 57 , m_to_ids(DE_NULL) 58 , m_fbo_id(0) 59 { 60 /* Nothing to be done here */ 61 } 62 63 /** Initializes GLES objects used during the test. 64 * 65 */ 66 void GPUShader5ImagesArrayIndexing::initTest(void) 67 { 68 /* Check if gpu_shader5 extension is supported */ 69 if (!m_is_gpu_shader5_supported) 70 { 71 throw tcu::NotSupportedError(GPU_SHADER5_EXTENSION_NOT_SUPPORTED, "", __FILE__, __LINE__); 72 } 73 74 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 75 76 /* Calculate platform-specific value that should be used for local_size_x, local_size_y in compute shader */ 77 glw::GLint max_compute_work_group_invocations_value = 0; 78 79 gl.getIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 0, &m_texture_width); 80 GLU_EXPECT_NO_ERROR(gl.getError(), "Could not query GL_MAX_COMPUTE_WORK_GROUP_SIZE!"); 81 82 gl.getIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 1, &m_texture_height); 83 GLU_EXPECT_NO_ERROR(gl.getError(), "Could not query GL_MAX_COMPUTE_WORK_GROUP_SIZE!"); 84 85 gl.getIntegerv(GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS, &max_compute_work_group_invocations_value); 86 GLU_EXPECT_NO_ERROR(gl.getError(), "Could not query GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS!"); 87 88 if (m_texture_width * m_texture_height > max_compute_work_group_invocations_value) 89 { 90 m_texture_width = (max_compute_work_group_invocations_value / m_texture_height); 91 } 92 93 /* Construct compute shader code */ 94 std::string compute_shader_code; 95 const char* compute_shader_code_ptr = DE_NULL; 96 std::stringstream local_size_x_stringstream; 97 std::stringstream local_size_y_stringstream; 98 99 local_size_x_stringstream << m_texture_width; 100 local_size_y_stringstream << m_texture_height; 101 102 compute_shader_code = getComputeShaderCode(local_size_x_stringstream.str(), local_size_y_stringstream.str()); 103 compute_shader_code_ptr = (const char*)compute_shader_code.c_str(); 104 105 /* Create a program object */ 106 m_program_id = gl.createProgram(); 107 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() call failed"); 108 109 /* Create a compute shader object */ 110 m_compute_shader_id = gl.createShader(GL_COMPUTE_SHADER); 111 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader(GL_COMPUTE_SHADER) failed"); 112 113 /* Build a program object that consists only of the compute shader */ 114 if (!buildProgram(m_program_id, m_compute_shader_id, 1, &compute_shader_code_ptr)) 115 { 116 TCU_FAIL("Could not create program object!"); 117 } 118 119 /* Generate texture objects */ 120 m_to_ids = new glw::GLuint[m_array_size]; 121 memset(m_to_ids, 0, m_array_size * sizeof(glw::GLuint)); 122 gl.genTextures(m_array_size, m_to_ids); 123 GLU_EXPECT_NO_ERROR(gl.getError(), "Could not generate texture objects!"); 124 125 /* Allocate a buffer we will later fill with data and use as a data source for a texture object */ 126 glw::GLuint dataSize = m_texture_width * m_texture_height * m_texture_n_components; 127 m_data_buffer = new glw::GLuint[dataSize * m_array_size]; 128 129 for (glw::GLuint array_index = 0; array_index < m_array_size; ++array_index) 130 { 131 for (glw::GLuint index = 0; index < dataSize; ++index) 132 { 133 m_data_buffer[index + array_index * dataSize] = 1 + array_index; 134 } 135 } 136 137 /* Initialize storage for the texture objects */ 138 for (glw::GLuint index = 0; index < m_array_size; index++) 139 { 140 gl.activeTexture(GL_TEXTURE0 + index); 141 gl.bindTexture(GL_TEXTURE_2D, m_to_ids[index]); 142 GLU_EXPECT_NO_ERROR(gl.getError(), "Could not bind a texture object to texture unit!"); 143 144 gl.texStorage2D(GL_TEXTURE_2D, 1 /* levels */, GL_R32UI, m_texture_width, m_texture_height); 145 146 gl.texSubImage2D(GL_TEXTURE_2D, 0 /* level */, 0 /* x offset */, 0 /* y offset */, m_texture_width, 147 m_texture_height, GL_RED_INTEGER, GL_UNSIGNED_INT, &m_data_buffer[index * dataSize]); 148 149 gl.texParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 150 gl.texParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 151 152 GLU_EXPECT_NO_ERROR(gl.getError(), "Could not allocate storage for a texture object!"); 153 } 154 155 delete[] m_data_buffer; 156 m_data_buffer = DE_NULL; 157 } 158 159 /** Executes the test. 160 * 161 * Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise. 162 * 163 * Note the function throws exception should an error occur! 164 * 165 * @return STOP if the test has finished, CONTINUE to indicate iterate should be called once again. 166 **/ 167 tcu::TestNode::IterateResult GPUShader5ImagesArrayIndexing::iterate(void) 168 { 169 initTest(); 170 171 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 172 173 gl.useProgram(m_program_id); 174 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed"); 175 176 for (glw::GLuint index = 0; index < m_array_size; index++) 177 { 178 gl.bindImageTexture(index /* unit */, m_to_ids[index], 0 /* level */, GL_FALSE, /* layered */ 179 0, /* layer */ 180 GL_READ_WRITE, GL_R32UI); 181 GLU_EXPECT_NO_ERROR(gl.getError(), "Could not bind a texture object to image unit!"); 182 } 183 184 gl.dispatchCompute(1, /* num_groups_x */ 185 1, /* num_groups_y */ 186 1); /* num_groups_z */ 187 GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to dispatch compute operation"); 188 189 /* Create and configure a framebuffer object */ 190 gl.genFramebuffers(1, &m_fbo_id); 191 gl.bindFramebuffer(GL_READ_FRAMEBUFFER, m_fbo_id); 192 193 GLU_EXPECT_NO_ERROR(gl.getError(), "Could not create framebuffer object"); 194 195 /* Set viewport */ 196 gl.viewport(0, 0, m_texture_width, m_texture_height); 197 GLU_EXPECT_NO_ERROR(gl.getError(), "glViewport() call failed"); 198 199 /* Allocate space for result data */ 200 const glw::GLuint dataSize = m_texture_width * m_texture_height * m_texture_n_components * 4; 201 m_data_buffer = new glw::GLuint[dataSize]; 202 203 gl.memoryBarrier(GL_PIXEL_BUFFER_BARRIER_BIT); 204 GLU_EXPECT_NO_ERROR(gl.getError(), "Could not set memory barrier!"); 205 206 for (unsigned int i = 0; i < m_array_size; ++i) 207 { 208 /* Attach texture to framebuffer's color attachment 0 */ 209 gl.framebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_to_ids[i], 0 /* level */); 210 GLU_EXPECT_NO_ERROR(gl.getError(), "Error configuring color attachment for framebuffer object!"); 211 212 /* Read the rendered data */ 213 gl.readPixels(0 /* x */, 0 /* y */, m_texture_width, m_texture_height, GL_RGBA_INTEGER, GL_UNSIGNED_INT, 214 m_data_buffer); 215 GLU_EXPECT_NO_ERROR(gl.getError(), "glReadPixels() call failed!"); 216 217 glw::GLuint resultExpected[m_texture_n_components]; 218 219 /* Loop over all pixels and compare the rendered data with reference value */ 220 for (glw::GLint y = 0; y < m_texture_height; ++y) 221 { 222 glw::GLuint* data_row = m_data_buffer + y * m_texture_width * m_texture_n_components * 4; 223 224 for (glw::GLint x = 0; x < m_texture_width; ++x) 225 { 226 glw::GLuint* data = data_row + x * m_texture_n_components * 4; 227 228 resultExpected[0] = x + y + 1 + i; 229 230 if (resultExpected[0] != data[0]) 231 { 232 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid image data acquired for image at index " 233 << i << ", position: (" << x << "," << y << ")" 234 << ". Rendered data [" << data[0] << "]" 235 << " Expected data [" << resultExpected[0] << "]" << tcu::TestLog::EndMessage; 236 237 delete[] m_data_buffer; 238 m_data_buffer = DE_NULL; 239 240 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); 241 return STOP; 242 } /* if (data mismatch) */ 243 244 } /* for (all columns) */ 245 } /* for (all rows) */ 246 } /*for (m_sizeOfArray)*/ 247 248 delete[] m_data_buffer; 249 m_data_buffer = DE_NULL; 250 251 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 252 return STOP; 253 } 254 255 /** Deinitializes GLES objects created during the test. 256 * 257 */ 258 void GPUShader5ImagesArrayIndexing::deinit(void) 259 { 260 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 261 262 /* Reset OpenGL ES state */ 263 gl.useProgram(0); 264 gl.bindBuffer(GL_ARRAY_BUFFER, 0); 265 gl.activeTexture(GL_TEXTURE0); 266 gl.bindTexture(GL_TEXTURE_2D, 0); 267 gl.bindVertexArray(0); 268 269 /* Delete program object and shaders */ 270 if (m_program_id != 0) 271 { 272 gl.deleteProgram(m_program_id); 273 274 m_program_id = 0; 275 } 276 277 if (m_compute_shader_id != 0) 278 { 279 gl.deleteShader(m_compute_shader_id); 280 281 m_compute_shader_id = 0; 282 } 283 284 if (m_data_buffer != DE_NULL) 285 { 286 delete[] m_data_buffer; 287 m_data_buffer = DE_NULL; 288 } 289 290 if (m_to_ids != DE_NULL) 291 { 292 gl.deleteTextures(m_array_size, m_to_ids); 293 delete[] m_to_ids; 294 m_to_ids = DE_NULL; 295 } 296 297 if (m_fbo_id != 0) 298 { 299 gl.deleteFramebuffers(1, &m_fbo_id); 300 m_fbo_id = 0; 301 } 302 303 /* Call base class' deinit() */ 304 TestCaseBase::deinit(); 305 } 306 307 /** Fill compute shader template 308 * 309 * @param _local_size_x String storing a "local_size_x" layout qualifier definition; 310 * @param _local_size_y String storing a "local_size_y" layout qualifier definition; 311 * 312 * @return string containing compute shader code 313 */ 314 std::string GPUShader5ImagesArrayIndexing::getComputeShaderCode(const std::string& local_size_x, 315 const std::string& local_size_y) 316 { 317 /* Compute shader template code */ 318 std::string m_compute_shader_template = 319 "${VERSION}\n" 320 "\n" 321 "${GPU_SHADER5_REQUIRE}\n" 322 "\n" 323 "layout (local_size_x = <-MAX-LOCAL-SIZE-X->,\n" 324 " local_size_y = <-MAX-LOCAL-SIZE-Y->,\n" 325 " local_size_z = 1) in;\n" 326 "\n" 327 "layout (r32ui, binding = 0) uniform highp uimage2D image[4];\n" 328 "\n" 329 "void main(void)\n" 330 "{\n" 331 " uvec4 texel0 = imageLoad(image[0], ivec2(gl_LocalInvocationID.x, gl_LocalInvocationID.y) );\n" 332 " uvec4 texel1 = imageLoad(image[1], ivec2(gl_LocalInvocationID.x, gl_LocalInvocationID.y) );\n" 333 " uvec4 texel2 = imageLoad(image[2], ivec2(gl_LocalInvocationID.x, gl_LocalInvocationID.y) );\n" 334 " uvec4 texel3 = imageLoad(image[3], ivec2(gl_LocalInvocationID.x, gl_LocalInvocationID.y) );\n" 335 " uvec4 addon = uvec4(gl_LocalInvocationID.x+gl_LocalInvocationID.y);\n" 336 "\n" 337 " imageStore(image[0], ivec2( gl_LocalInvocationID.x, gl_LocalInvocationID.y), texel0 + addon);\n" 338 " imageStore(image[1], ivec2( gl_LocalInvocationID.x, gl_LocalInvocationID.y), texel1 + addon);\n" 339 " imageStore(image[2], ivec2( gl_LocalInvocationID.x, gl_LocalInvocationID.y), texel2 + addon);\n" 340 " imageStore(image[3], ivec2( gl_LocalInvocationID.x, gl_LocalInvocationID.y), texel3 + addon);\n" 341 "}\n"; 342 343 /* Insert information on local size in X direction */ 344 std::string template_name = "<-MAX-LOCAL-SIZE-X->"; 345 std::size_t template_position = m_compute_shader_template.find(template_name); 346 347 while (template_position != std::string::npos) 348 { 349 m_compute_shader_template = 350 m_compute_shader_template.replace(template_position, template_name.length(), local_size_x); 351 352 template_position = m_compute_shader_template.find(template_name); 353 } 354 355 /* Insert information on local size in Y direction */ 356 template_name = "<-MAX-LOCAL-SIZE-Y->"; 357 template_position = m_compute_shader_template.find(template_name); 358 359 while (template_position != std::string::npos) 360 { 361 m_compute_shader_template = 362 m_compute_shader_template.replace(template_position, template_name.length(), local_size_y); 363 364 template_position = m_compute_shader_template.find(template_name); 365 } 366 367 return m_compute_shader_template; 368 } 369 370 } // namespace glcts 371