/*------------------------------------------------------------------------- * OpenGL Conformance Test Suite * ----------------------------- * * Copyright (c) 2014-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 * \brief */ /*-------------------------------------------------------------------*/ /*! * \file esextcTextureCubeMapArraySampling.cpp * \brief Texture Cube Map Array Sampling (Test 1) */ /*-------------------------------------------------------------------*/ /* Control logging of positive results. 0 disabled, 1 enabled */ #define TEXTURECUBEMAPARRAYSAMPLINGTEST_IS_PASS_LOG 0 /* Control logging of program source for positive results. 0 disabled, 1 enabled */ #define TEXTURECUBEMAPARRAYSAMPLINGTEST_IS_PASS_PROGRAM_LOG 1 /* Control logging of negative results. 0 disabled, 1 enabled */ #define TEXTURECUBEMAPARRAYSAMPLINGTEST_IS_FAIL_LOG 1 /* Control logging of program source for negative results. 0 disabled, 1 enabled */ #define TEXTURECUBEMAPARRAYSAMPLINGTEST_IS_FAIL_PROGRAM_LOG 1 /* When enabled, textures will be stored as TGA files. Test will not be executed. 0 disabled, 1 enabled */ #define TEXTURECUBEMAPARRAYSAMPLINGTEST_DUMP_TEXTURES_FOR_COMPRESSION 0 /* Output path for TGA files */ #define TEXTURECUBEMAPARRAYSAMPLINGTEST_PATH_FOR_COMPRESSION "c:\\textures\\" #include "esextcTextureCubeMapArraySampling.hpp" #include "esextcTextureCubeMapArraySamplingResources.hpp" #include "gluContextInfo.hpp" #include "glwEnums.hpp" #include "glwFunctions.hpp" #include "tcuTestLog.hpp" #include #include #include #if TEXTURECUBEMAPARRAYSAMPLINGTEST_DUMP_TEXTURES_FOR_COMPRESSION #include #endif /* TEXTURECUBEMAPARRAYSAMPLINGTEST_DUMP_TEXTURES_FOR_COMPRESSION */ namespace glcts { /** Structure used to write shaders' variables to stream * **/ struct var2str { public: /** Constructor. Stores strings used to create variable name * prefixName[index] * * @param prefix Prefix part. Can be null. * @param name Name part. Must not be null. * @param index Index part. Can be null. **/ var2str(const glw::GLchar* prefix, const glw::GLchar* name, const glw::GLchar* index) : m_prefix(prefix), m_name(name), m_index(index) { /* Nothing to be done here */ } const glw::GLchar* m_prefix; const glw::GLchar* m_name; const glw::GLchar* m_index; }; /* Attribute names */ const glw::GLchar* const TextureCubeMapArraySamplingTest::attribute_grad_x = "grad_x"; const glw::GLchar* const TextureCubeMapArraySamplingTest::attribute_grad_y = "grad_y"; const glw::GLchar* const TextureCubeMapArraySamplingTest::attribute_lod = "lod"; const glw::GLchar* const TextureCubeMapArraySamplingTest::attribute_refZ = "refZ"; const glw::GLchar* const TextureCubeMapArraySamplingTest::attribute_texture_coordinate = "texture_coordinates"; /* Compute shader parts */ const glw::GLchar* const TextureCubeMapArraySamplingTest::compute_shader_body = "void main()\n" "{\n" " const int face_width = 3;\n" " const int face_height = 3;\n" " const int vertices_per_face = face_width * face_height;\n" " const int faces_per_layer = 6;\n" " const int layer_width = faces_per_layer * face_width;\n" " const int vertices_per_layer = vertices_per_face * faces_per_layer;\n" "\n" " ivec2 image_coord = ivec2(gl_WorkGroupID.xy);\n" " ivec3 texture_size = textureSize(sampler, 0);\n" "\n" " int layer = image_coord.x / layer_width;\n" " int layer_offset = layer * layer_width;\n" " int layer_index = layer * vertices_per_layer;\n" " int face = (image_coord.x - layer_offset) / face_width;\n" " int face_offset = face * face_width;\n" " int face_index = face * vertices_per_face;\n" " int vertex = image_coord.x - layer_offset - face_offset;\n" " int vertex_index = layer_index + face_index + vertex + (face_height - image_coord.y - 1) * " "face_width;\n" "\n"; const glw::GLchar* const TextureCubeMapArraySamplingTest::compute_shader_layout_binding = "layout(std430, binding="; const glw::GLchar* const TextureCubeMapArraySamplingTest::compute_shader_buffer = ") buffer "; const glw::GLchar* const TextureCubeMapArraySamplingTest::compute_shader_color = "color"; const glw::GLchar* const TextureCubeMapArraySamplingTest::compute_shader_image_store = " imageStore(image, image_coord, "; const glw::GLchar* const TextureCubeMapArraySamplingTest::compute_shader_layout = "layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"; const glw::GLchar* const TextureCubeMapArraySamplingTest::compute_shader_param = "cs_"; /* Fragment shader parts */ const glw::GLchar* const TextureCubeMapArraySamplingTest::fragment_shader_input = "fs_in_color"; const glw::GLchar* const TextureCubeMapArraySamplingTest::fragment_shader_output = "fs_out_color"; const glw::GLchar* const TextureCubeMapArraySamplingTest::fragment_shader_pass_through_body_code = "void main()\n" "{\n" " fs_out_color = fs_in_color;\n" "}\n"; const glw::GLchar* const TextureCubeMapArraySamplingTest::fragment_shader_sampling_body_code = "void main()\n" "{\n"; /* Geometry shader parts */ const glw::GLchar* const TextureCubeMapArraySamplingTest::geometry_shader_emit_vertex_code = " EmitVertex();\n" "}\n"; const glw::GLchar* const TextureCubeMapArraySamplingTest::geometry_shader_extension = "${GEOMETRY_SHADER_REQUIRE}\n"; const glw::GLchar* const TextureCubeMapArraySamplingTest::geometry_shader_layout = "layout(points) in;\n" "layout(points, max_vertices=1) out;\n" "\n"; const glw::GLchar* const TextureCubeMapArraySamplingTest::geometry_shader_sampling_body_code = "void main()\n" "{\n" " gl_Position = gl_in[0].gl_Position;\n"; /* Image types and name */ const glw::GLchar* const TextureCubeMapArraySamplingTest::image_float = "image2D "; const glw::GLchar* const TextureCubeMapArraySamplingTest::image_int = "iimage2D "; const glw::GLchar* const TextureCubeMapArraySamplingTest::image_name = "image"; const glw::GLchar* const TextureCubeMapArraySamplingTest::image_uint = "uimage2D "; /* Interpolation */ const glw::GLchar* const TextureCubeMapArraySamplingTest::interpolation_flat = "flat "; /* Sampler types and name */ const glw::GLchar* const TextureCubeMapArraySamplingTest::sampler_depth = "samplerCubeArrayShadow "; const glw::GLchar* const TextureCubeMapArraySamplingTest::sampler_float = "samplerCubeArray "; const glw::GLchar* const TextureCubeMapArraySamplingTest::sampler_int = "isamplerCubeArray "; const glw::GLchar* const TextureCubeMapArraySamplingTest::sampler_name = "sampler"; const glw::GLchar* const TextureCubeMapArraySamplingTest::sampler_uint = "usamplerCubeArray "; /* Common shader parts for */ const glw::GLchar* const TextureCubeMapArraySamplingTest::shader_code_preamble = "${VERSION}\n" "${TEXTURE_CUBE_MAP_ARRAY_REQUIRE}\n" "\n"; const glw::GLchar* const TextureCubeMapArraySamplingTest::shader_precision = "precision highp float;\n"; const glw::GLchar* const TextureCubeMapArraySamplingTest::shader_input = "in "; const glw::GLchar* const TextureCubeMapArraySamplingTest::shader_layout = "layout(location = 0) "; const glw::GLchar* const TextureCubeMapArraySamplingTest::shader_output = "out "; const glw::GLchar* const TextureCubeMapArraySamplingTest::shader_uniform = "uniform "; const glw::GLchar* const TextureCubeMapArraySamplingTest::shader_writeonly = "writeonly "; /* Tesselation control shader parts */ const glw::GLchar* const TextureCubeMapArraySamplingTest::tesselation_control_shader_layout = "layout(vertices = 1) out;\n" "\n"; const glw::GLchar* const TextureCubeMapArraySamplingTest::tesselation_control_shader_sampling_body_code = "void main()\n" "{\n" " gl_TessLevelInner[0] = 1.0;\n" " gl_TessLevelInner[1] = 1.0;\n" " gl_TessLevelOuter[0] = 1.0;\n" " gl_TessLevelOuter[1] = 1.0;\n" " gl_TessLevelOuter[2] = 1.0;\n" " gl_TessLevelOuter[3] = 1.0;\n" " gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"; const glw::GLchar* const TextureCubeMapArraySamplingTest::tesselation_control_shader_output = "tcs_out_"; /* Tesselation evaluation shader parts */ const glw::GLchar* const TextureCubeMapArraySamplingTest::tesselation_evaluation_shader_input = "tes_in_color"; const glw::GLchar* const TextureCubeMapArraySamplingTest::tesselation_evaluation_shader_layout = "layout(isolines, point_mode) in;\n" "\n"; const glw::GLchar* const TextureCubeMapArraySamplingTest::tesselation_evaluation_shader_pass_through_body_code = "void main()\n" "{\n" " gl_Position = gl_in[0].gl_Position;\n" " fs_in_color = tes_in_color[0];\n" "}\n"; const glw::GLchar* const TextureCubeMapArraySamplingTest::tesselation_evaluation_shader_sampling_body_code = "void main()\n" "{\n" " gl_Position = gl_in[0].gl_Position;\n"; const glw::GLchar* const TextureCubeMapArraySamplingTest::tesselation_shader_extension = "${TESSELLATION_SHADER_REQUIRE}\n"; /* Texture sampling routines */ const glw::GLchar* const TextureCubeMapArraySamplingTest::texture_func = "texture"; const glw::GLchar* const TextureCubeMapArraySamplingTest::textureGather_func = "textureGather"; const glw::GLchar* const TextureCubeMapArraySamplingTest::textureGrad_func = "textureGrad"; const glw::GLchar* const TextureCubeMapArraySamplingTest::textureLod_func = "textureLod"; /* Data types */ const glw::GLchar* const TextureCubeMapArraySamplingTest::type_float = "float "; const glw::GLchar* const TextureCubeMapArraySamplingTest::type_ivec4 = "ivec4 "; const glw::GLchar* const TextureCubeMapArraySamplingTest::type_uint = "uint "; const glw::GLchar* const TextureCubeMapArraySamplingTest::type_uvec4 = "uvec4 "; const glw::GLchar* const TextureCubeMapArraySamplingTest::type_vec3 = "vec3 "; const glw::GLchar* const TextureCubeMapArraySamplingTest::type_vec4 = "vec4 "; /* Vertex shader parts */ const glw::GLchar* const TextureCubeMapArraySamplingTest::vertex_shader_body_code = "void main()\n" "{\n" " gl_PointSize = 1.0f;\n" " gl_Position = vs_in_position;\n"; const glw::GLchar* const TextureCubeMapArraySamplingTest::vertex_shader_input = "vs_in_"; const glw::GLchar* const TextureCubeMapArraySamplingTest::vertex_shader_output = "vs_out_"; const glw::GLchar* const TextureCubeMapArraySamplingTest::vertex_shader_position = "position"; /* Static constants */ const glw::GLuint TextureCubeMapArraySamplingTest::m_get_type_api_status_program_resource = 0x02; const glw::GLuint TextureCubeMapArraySamplingTest::m_get_type_api_status_uniform = 0x01; const glw::GLuint TextureCubeMapArraySamplingTest::bufferDefinition::m_invalid_buffer_object_id = -1; const glw::GLuint TextureCubeMapArraySamplingTest::programDefinition::m_invalid_program_object_id = 0; const glw::GLuint TextureCubeMapArraySamplingTest::shaderDefinition::m_invalid_shader_object_id = 0; const glw::GLuint TextureCubeMapArraySamplingTest::textureDefinition::m_invalid_texture_object_id = -1; const glw::GLuint TextureCubeMapArraySamplingTest::textureDefinition::m_invalid_uniform_location = -1; const glw::GLuint TextureCubeMapArraySamplingTest::vertexArrayObjectDefinition::m_invalid_attribute_location = -1; const glw::GLuint TextureCubeMapArraySamplingTest::vertexArrayObjectDefinition::m_invalid_vertex_array_object_id = -1; /* Functions */ /** Fill image with specified color * @tparam T Image component type * @tparam N_Components Number of image components * * @param image_width Width of image * @param image_height Height of image * @param pixel_components Image will be filled with that color * @param out_data Image data, storage must be allocated **/ template void fillImage(glw::GLsizei image_width, glw::GLsizei image_height, const T* pixel_components, T* out_data) { const glw::GLuint n_components_per_pixel = N_Components; const glw::GLuint n_components_per_line = n_components_per_pixel * image_width; for (glw::GLsizei y = 0; y < image_height; ++y) { const glw::GLuint line_offset = y * n_components_per_line; for (glw::GLsizei x = 0; x < image_width; ++x) { for (glw::GLuint component = 0; component < n_components_per_pixel; ++component) { out_data[line_offset + x * n_components_per_pixel + component] = pixel_components[component]; } } } } /* Out of alphabetical order due to use in other functions */ /** Normalize vector stored in array. Only first N_NormalizedComponents will be normalized. * * @tparam N_NormalizedComponents Number of coordinates to normalize * @tparam N_Components Number of coordinates in vector * * @param data Pointer to first coordinate of first vector in array * @param index Index of vector to be normalized **/ template void vectorNormalize(glw::GLfloat* data, glw::GLuint index) { glw::GLfloat* components = data + index * N_Components; glw::GLfloat sqr_length = 0.0f; for (glw::GLuint i = 0; i < N_NormalizedComponents; ++i) { const glw::GLfloat component = components[i]; sqr_length += component * component; } const glw::GLfloat length = sqrtf(sqr_length); const glw::GLfloat factor = 1.0f / length; for (glw::GLuint i = 0; i < N_NormalizedComponents; ++i) { components[i] *= factor; } } /* Out of alphabetical order due to use in other functions */ /** Set coordinates of 4 element vector stored in array * * @param data Pointer to first coordinate of first vector in array * @param index Index of vector to be normalized * @param x 1st coordinate value * @param y 2nd coordinate value * @param z 3rd coordinate value * @param w 4th coordinate value **/ void vectorSet4(glw::GLfloat* data, glw::GLuint index, glw::GLfloat x, glw::GLfloat y, glw::GLfloat z, glw::GLfloat w) { const glw::GLuint n_components_per_vertex = 4; const glw::GLuint vector_offset = n_components_per_vertex * index; data[vector_offset + 0] = x; data[vector_offset + 1] = y; data[vector_offset + 2] = z; data[vector_offset + 3] = w; } /* Out of alphabetical order due to use in other functions */ /** Subtract vectors: a = b - a * * @tparam N_Components Number of coordinates in vector * * @param a Pointer to vector a * @param b Pointer to vector b **/ template void vectorSubtractInPlace(glw::GLfloat* a, const glw::GLfloat* b) { const glw::GLuint n_components = N_Components; for (glw::GLuint i = 0; i < n_components; ++i) { a[i] -= b[i]; } } /** Prepare color for rgba float textures * * @param cube_face Index of cube's face * @param element_index Index of element in array * @param mipmap_level Mipmap level * @param n_elements Number of elements in array * @param n_mipmap_levels Number of mipmap levels * @param out_data Pointer to components storage **/ void getColorFloatComponents(glw::GLint cube_face, glw::GLint element_index, glw::GLint mipmap_level, glw::GLint n_elements, glw::GLint n_mipmap_levels, glw::GLfloat* out_data) { static const glw::GLfloat n_faces = 6.0f; out_data[0] = ((glw::GLfloat)(mipmap_level + 1)) / ((glw::GLfloat)n_mipmap_levels); out_data[1] = ((glw::GLfloat)(cube_face + 1)) / n_faces; out_data[2] = ((glw::GLfloat)(element_index + 1)) / ((glw::GLfloat)n_elements); out_data[3] = 1.0f / 4.0f; } /** Prepare color for rgba integer textures * * @tparam T Type of components * * @param cube_face Index of cube's face * @param element_index Index of element in array * @param mipmap_level Mipmap level * @param n_elements Number of elements in array, ignored * @param n_mipmap_levels Number of mipmap levels, ignored * @param out_data Pointer to components storage **/ template void getColorIntComponents(glw::GLint cube_face, glw::GLint element_index, glw::GLint mipmap_level, glw::GLint /* n_elements */, glw::GLint /* n_mipmap_levels */, T* out_data) { out_data[0] = static_cast(mipmap_level + 1); out_data[1] = static_cast(cube_face + 1); out_data[2] = static_cast(element_index + 1); out_data[3] = 1; } /** Prepare color for rgba compressed textures * * @param cube_face Index of cube's face * @param element_index Index of element in array * @param mipmap_level Mipmap level * @param n_elements Number of elements in array * @param n_mipmap_levels Number of mipmap levels * @param out_data Pointer to components storage **/ void getCompressedColorUByteComponents(glw::GLint cube_face, glw::GLint element_index, glw::GLint mipmap_level, glw::GLint n_elements, glw::GLint n_mipmap_levels, glw::GLubyte* out_data) { (void)n_mipmap_levels; static const glw::GLuint n_faces = 6; const glw::GLuint n_faces_per_level = n_elements * n_faces; const glw::GLubyte value = static_cast(mipmap_level * n_faces_per_level + element_index * n_faces + cube_face + 1); out_data[0] = value; out_data[1] = value; out_data[2] = value; out_data[3] = value; } /** Get compressed texture data and size from resources. Width, height, number of array elements and mipmap level are used to identify image. * Width and height are dimmensions of base level image, same values are used to identify all mipmap levels. * * @param width Width of texture * @param height Height of texture * @param n_array_elements Number of elemnts in array * @param mipmap_level Level * @param out_image_data Image data * @param out_image_size Image size **/ void getCompressedTexture(glw::GLuint width, glw::GLuint height, glw::GLuint n_array_elements, glw::GLuint mipmap_level, const glw::GLubyte*& out_image_data, glw::GLuint& out_image_size) { for (glw::GLuint i = 0; i < n_compressed_images; ++i) { const compressedImage& image = compressed_images[i]; if ((image.width == width) && (image.height == height) && (image.length == n_array_elements) && (image.level == mipmap_level)) { out_image_data = image.image_data; out_image_size = image.image_size; return; } } out_image_data = 0; out_image_size = 0; } /** Prepare color for depth textures * * @param cube_face Index of cube's face * @param element_index Index of element in array * @param mipmap_level Mipmap level * @param n_elements Number of elements in array * @param n_mipmap_levels Number of mipmap levels * @param out_depth Depth value **/ void getDepthComponent(glw::GLint cube_face, glw::GLint element_index, glw::GLint mipmap_level, glw::GLint n_elements, glw::GLint n_mipmap_levels, glw::GLfloat& out_depth) { static const glw::GLuint n_faces = 6; out_depth = ((glw::GLfloat)(mipmap_level + 1 + cube_face + 1 + element_index + 1)) / ((glw::GLfloat)(n_mipmap_levels + n_faces + n_elements)); } /** Get expected color sampled by texture or textureGather from rgba float textures * * @param pixel_index Index of pixel, identifies pixel at face <0:8> . Ignored. * @param cube_face Index of cube's face * @param element_index Index of element in array * @param n_layers Number of elements in array * @param n_mipmap_levels Number of mipmap levels * @param out_components Pointer to components storage **/ void getExpectedColorFloatComponentsForTexture(glw::GLuint /* pixel_index */, glw::GLint cube_face, glw::GLint element_index, glw::GLint n_layers, glw::GLint n_mipmap_levels, glw::GLfloat* out_components) { getColorFloatComponents(cube_face, element_index, 0 /* mipmap_level */, n_layers, n_mipmap_levels, out_components); } /** Get expected color sampled by textureLod or textureGrad from rgba float textures * * @param pixel_index Index of pixel, identifies pixel at face <0:8> . * @param cube_face Index of cube's face * @param element_index Index of element in array * @param n_layers Number of elements in array * @param n_mipmap_levels Number of mipmap levels * @param out_components Pointer to components storage **/ void getExpectedColorFloatComponentsForTextureLod(glw::GLuint pixel_index, glw::GLint cube_face, glw::GLint element_index, glw::GLint n_layers, glw::GLint n_mipmap_levels, glw::GLfloat* out_components) { glw::GLint mipmap_level = 0; if (1 == pixel_index % 2) { mipmap_level = n_mipmap_levels - 1; } getColorFloatComponents(cube_face, element_index, mipmap_level, n_layers, n_mipmap_levels, out_components); } /** Get expected color sampled by texture or textureGather from rgba integer textures * * @tparam T Type of image components * * @param pixel_index Index of pixel, identifies pixel at face <0:8> . Ignored. * @param cube_face Index of cube's face * @param element_index Index of element in array * @param n_layers Number of elements in array * @param n_mipmap_levels Number of mipmap levels * @param out_components Pointer to components storage **/ template void getExpectedColorIntComponentsForTexture(glw::GLuint /* pixel_index */, glw::GLint cube_face, glw::GLint element_index, glw::GLint n_layers, glw::GLint n_mipmap_levels, T* out_components) { getColorIntComponents(cube_face, element_index, 0 /* mipmap_level */, n_layers, n_mipmap_levels, out_components); } /** Get expected color sampled by textureLod or textureGrad from rgba integer textures * * @tparam T Type of image components * * @param pixel_index Index of pixel, identifies pixel at face <0:8> . * @param cube_face Index of cube's face * @param element_index Index of element in array * @param n_layers Number of elements in array * @param n_mipmap_levels Number of mipmap levels * @param out_components Pointer to components storage **/ template void getExpectedColorIntComponentsForTextureLod(glw::GLuint pixel_index, glw::GLint cube_face, glw::GLint element_index, glw::GLint n_layers, glw::GLint n_mipmap_levels, T* out_components) { glw::GLint mipmap_level = 0; if (1 == pixel_index % 2) { mipmap_level = n_mipmap_levels - 1; } getColorIntComponents(cube_face, element_index, mipmap_level, n_layers, n_mipmap_levels, out_components); } /** Get expected color sampled by texture or textureGather from rgba compressed textures * * @param pixel_index Index of pixel, identifies pixel at face <0:8> . Ignored. * @param cube_face Index of cube's face * @param element_index Index of element in array * @param n_layers Number of elements in array * @param n_mipmap_levels Number of mipmap levels * @param out_components Pointer to components storage **/ void getExpectedCompressedComponentsForTexture(glw::GLuint /* pixel_index */, glw::GLint cube_face, glw::GLint element_index, glw::GLint n_layers, glw::GLint n_mipmap_levels, glw::GLubyte* out_components) { getCompressedColorUByteComponents(cube_face, element_index, 0 /* mipmap_level */, n_layers, n_mipmap_levels, out_components); } /** Get expected color sampled by textureLod or textureGrad from rgba compressed textures * * @param pixel_index Index of pixel, identifies pixel at face <0:8> . * @param cube_face Index of cube's face * @param element_index Index of element in array * @param n_layers Number of elements in array * @param n_mipmap_levels Number of mipmap levels * @param out_components Pointer to components storage **/ void getExpectedCompressedComponentsForTextureLod(glw::GLuint pixel_index, glw::GLint cube_face, glw::GLint element_index, glw::GLint n_layers, glw::GLint n_mipmap_levels, glw::GLubyte* out_components) { glw::GLint mipmap_level = 0; if (1 == pixel_index % 2) { mipmap_level = n_mipmap_levels - 1; } getCompressedColorUByteComponents(cube_face, element_index, mipmap_level, n_layers, n_mipmap_levels, out_components); } /** Get expected color sampled by texture or textureGather from depth textures * * @param pixel_index Index of pixel, identifies pixel at face <0:8> * @param cube_face Index of cube's face. Ignored. * @param element_index Index of element in array. Ignored. * @param n_layers Number of elements in array. Ignored. * @param n_mipmap_levels Number of mipmap levels. Ignored. * @param out_components Pointer to components storage **/ void getExpectedDepthComponentsForTexture(glw::GLuint pixel_index, glw::GLint /* cube_face */, glw::GLint /* element_index */, glw::GLint /* n_layers */, glw::GLint /* n_mipmap_levels */, glw::GLfloat* out_components) { const glw::GLfloat results[9] = { 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f }; out_components[0] = results[pixel_index]; } /** Get expected color sampled by textureLod or textureGrad from depth textures * * @param pixel_index Index of pixel, identifies pixel at face <0:8> . * @param cube_face Index of cube's face. Ignored. * @param element_index Index of element in array. Ignored. * @param n_layers Number of elements in array. Ignored. * @param n_mipmap_levels Number of mipmap levels. Ignored. * @param out_components Pointer to components storage **/ void getExpectedDepthComponentsForTextureLod(glw::GLuint pixel_index, glw::GLint /* cube_face */, glw::GLint /* element_index */, glw::GLint /* n_layers */, glw::GLint /* n_mipmap_levels */, glw::GLfloat* out_components) { if (0 == pixel_index % 2) { out_components[0] = 0.0f; } else { out_components[0] = 1.0f; } } /* Out of alphabetical order due to use in other functions */ /** Prepare color for stencil textures * * @param cube_face Index of cube's face * @param element_index Index of element in array * @param mipmap_level Mipmap level * @param n_elements Number of elements in array * @param n_mipmap_levels Number of mipmap levels * @param out_stencil Stencil value **/ void getStencilComponent(glw::GLint cube_face, glw::GLint element_index, glw::GLint mipmap_level, glw::GLint n_elements, glw::GLint n_mipmap_levels, glw::GLubyte& out_stencil) { static const glw::GLint n_faces = 6; out_stencil = (glw::GLubyte)((mipmap_level + 1 + cube_face + 1 + element_index + 1) * 255 / (n_mipmap_levels + n_faces + n_elements)); } /** Get expected color sampled by texture or textureGather from stencil textures * * @param pixel_index Index of pixel, identifies pixel at face <0:8> . Ignored. * @param cube_face Index of cube's face * @param element_index Index of element in array * @param n_layers Number of elements in array * @param n_mipmap_levels Number of mipmap levels * @param out_components Pointer to components storage **/ void getExpectedStencilComponentsForTexture(glw::GLuint /* pixel_index */, glw::GLint cube_face, glw::GLint element_index, glw::GLint n_layers, glw::GLint n_mipmap_levels, glw::GLuint* out_components) { glw::GLubyte value = 0; getStencilComponent(cube_face, element_index, 0 /* mipmap_level */, n_layers, n_mipmap_levels, value); out_components[0] = value; } /** Get expected color sampled by textureLod or textureGrad from stencil textures * * @param pixel_index Index of pixel, identifies pixel at face <0:8> . * @param cube_face Index of cube's face * @param element_index Index of element in array * @param n_layers Number of elements in array * @param n_mipmap_levels Number of mipmap levels * @param out_components Pointer to components storage **/ void getExpectedStencilComponentsForTextureLod(glw::GLuint pixel_index, glw::GLint cube_face, glw::GLint element_index, glw::GLint n_layers, glw::GLint n_mipmap_levels, glw::GLuint* out_components) { glw::GLubyte value = 0; glw::GLint mipmap_level = 0; if (1 == pixel_index % 2) { mipmap_level = n_mipmap_levels - 1; } getStencilComponent(cube_face, element_index, mipmap_level, n_layers, n_mipmap_levels, value); out_components[0] = value; } /** Returns number of mipmaps for given image dimmensions * * @param texture_width Width of image * @param texture_height Height of image * * @returns Number of mipmaps **/ glw::GLubyte getMipmapLevelCount(glw::GLsizei texture_width, glw::GLsizei texture_height) { glw::GLsizei size = de::max(texture_width, texture_height); glw::GLuint count = 1; while (1 < size) { size /= 2; count += 1; } return (glw::GLubyte)count; } /** Calculate texture coordinates for "right neighbour" of given texture coordinates * * @param texture_coordinates Texture coordinates of original point * @param face Cube map's face index * @param offset Offset of "neighbour" in "right" direction * @param width Image width * @param out_neighbour Texture coordinates of "neighbour" point **/ void getRightNeighbour(const glw::GLfloat* texture_coordinates, glw::GLuint face, glw::GLuint offset, glw::GLuint width, glw::GLfloat* out_neighbour) { const glw::GLfloat step = (float)offset / (float)width; glw::GLfloat& x = out_neighbour[0]; glw::GLfloat& y = out_neighbour[1]; glw::GLfloat& z = out_neighbour[2]; const glw::GLfloat coord_x = texture_coordinates[0]; const glw::GLfloat coord_y = texture_coordinates[1]; const glw::GLfloat coord_z = texture_coordinates[2]; switch (face) { case 0: // +X x = coord_x; y = coord_y - step; z = coord_z; break; case 1: // -X x = coord_x; y = coord_y + step; z = coord_z; break; case 2: // +Y x = coord_x + step; y = coord_y; z = coord_z; break; case 3: // -Y x = coord_x - step; y = coord_y; z = coord_z; break; case 4: // +Z x = coord_x + step; y = coord_y; z = coord_z; break; case 5: // -Z x = coord_x - step; y = coord_y; z = coord_z; break; } } /** Calculate texture coordinates for "top neighbour" of given texture coordinates * * @param texture_coordinates Texture coordinates of original point * @param face Cube map's face index * @param offset Offset of "neighbour" in "top" direction * @param width Image width * @param out_neighbour Texture coordinates of "neighbour" point **/ void getTopNeighbour(const glw::GLfloat* texture_coordinates, glw::GLuint face, glw::GLuint offset, glw::GLuint width, glw::GLfloat* out_neighbour) { glw::GLfloat step = (float)offset / (float)width; glw::GLfloat& x = out_neighbour[0]; glw::GLfloat& y = out_neighbour[1]; glw::GLfloat& z = out_neighbour[2]; const glw::GLfloat coord_x = texture_coordinates[0]; const glw::GLfloat coord_y = texture_coordinates[1]; const glw::GLfloat coord_z = texture_coordinates[2]; switch (face) { case 0: // +X x = coord_x; y = coord_y; z = coord_z + step; break; case 1: // -X x = coord_x; y = coord_y; z = coord_z + step; break; case 2: // +Y x = coord_x; y = coord_y; z = coord_z + step; break; case 3: // -Y x = coord_x; y = coord_y; z = coord_z + step; break; case 4: // +Z x = coord_x; y = coord_y - step; z = coord_z; break; case 5: // -Z x = coord_x; y = coord_y + step; z = coord_z; break; } } /** Write var2str instance to output stream * * @param stream Stream instance * @param var var2str instance * * @returns Stream instance **/ std::ostream& operator<<(std::ostream& stream, const var2str& var) { if (0 != var.m_prefix) { stream << var.m_prefix; } stream << var.m_name; if (0 != var.m_index) { stream << "[" << var.m_index << "]"; } return stream; } /* Out of alphabetical order due to use in other functions */ /** Fill texture's face at given index and level with given color * * @tparam T Type of image component * @tparam N_Components Number of components * * @param gl GL functions * @param cube_face Index of cube map's face * @param element_index Index of element in array * @param mipmap_level Mipmap level * @param texture_format Texture format * @param texture_width Texture width * @param texture_height Texture height * @param components Color used to fill texture **/ template void prepareDataForTexture(const glw::Functions& gl, glw::GLint cube_face, glw::GLint element_index, glw::GLint mipmap_level, glw::GLenum texture_format, glw::GLenum texture_type, glw::GLsizei texture_width, glw::GLsizei texture_height, const T* components) { static const glw::GLuint n_components_per_pixel = N_Components; const glw::GLuint n_pixels = texture_width * texture_height; const glw::GLuint n_total_componenets = n_components_per_pixel * n_pixels; const glw::GLuint z_offset = element_index * 6 + cube_face; std::vector texture_data; texture_data.resize(n_total_componenets); fillImage(texture_width, texture_height, components, &texture_data[0]); gl.texSubImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, mipmap_level, 0 /* x */, 0 /* y */, z_offset, texture_width, texture_height, 1 /* depth */, texture_format, texture_type, &texture_data[0]); GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to update texture data"); } /** Prepare texture's face at given index and level, for rgba float textures. * * @param gl GL functions * @param cube_face Index of cube map's face * @param element_index Index of element in array * @param mipmap_level Mipmap level * @param n_elements Number of elements in array * @param n_mipmap_levels Number of mipmap levels * @param texture_format Texture format * @param texture_width Texture width * @param texture_height Texture height **/ void prepareDataForColorFloatTexture(const glw::Functions& gl, glw::GLint cube_face, glw::GLint element_index, glw::GLint mipmap_level, glw::GLint n_elements, glw::GLint n_mipmap_levels, glw::GLenum texture_format, glw::GLenum texture_type, glw::GLsizei texture_width, glw::GLsizei texture_height) { glw::GLfloat components[4]; getColorFloatComponents(cube_face, element_index, mipmap_level, n_elements, n_mipmap_levels, components); prepareDataForTexture(gl, cube_face, element_index, mipmap_level, texture_format, texture_type, texture_width, texture_height, components); } /** Prepare texture's face at given index and level, for rgba integer textures. * * @tparam T Type of image component * * @param gl GL functions * @param cube_face Index of cube map's face * @param element_index Index of element in array * @param mipmap_level Mipmap level * @param n_elements Number of elements in array * @param n_mipmap_levels Number of mipmap levels * @param texture_format Texture format * @param texture_width Texture width * @param texture_height Texture height **/ template void prepareDataForColorIntTexture(const glw::Functions& gl, glw::GLint cube_face, glw::GLint element_index, glw::GLint mipmap_level, glw::GLint n_elements, glw::GLint n_mipmap_levels, glw::GLenum texture_format, glw::GLenum texture_type, glw::GLsizei texture_width, glw::GLsizei texture_height) { T components[4]; getColorIntComponents(cube_face, element_index, mipmap_level, n_elements, n_mipmap_levels, components); prepareDataForTexture(gl, cube_face, element_index, mipmap_level, texture_format, texture_type, texture_width, texture_height, components); } /** Prepare texture's face at given index and level, for depth textures. * * @param gl GL functions * @param cube_face Index of cube map's face * @param element_index Index of element in array * @param mipmap_level Mipmap level * @param n_elements Number of elements in array * @param n_mipmap_levels Number of mipmap levels * @param texture_format Texture format * @param texture_width Texture width * @param texture_height Texture height **/ void prepareDataForDepthFloatTexture(const glw::Functions& gl, glw::GLint cube_face, glw::GLint element_index, glw::GLint mipmap_level, glw::GLint n_elements, glw::GLint n_mipmap_levels, glw::GLenum texture_format, glw::GLenum texture_type, glw::GLsizei texture_width, glw::GLsizei texture_height) { glw::GLfloat component = 0; getDepthComponent(cube_face, element_index, mipmap_level, n_elements, n_mipmap_levels, component); prepareDataForTexture(gl, cube_face, element_index, mipmap_level, texture_format, texture_type, texture_width, texture_height, &component); } /** Prepare texture's face at given index and level, for stencil textures. * * @param gl GL functions * @param cube_face Index of cube map's face * @param element_index Index of element in array * @param mipmap_level Mipmap level * @param n_elements Number of elements in array * @param n_mipmap_levels Number of mipmap levels * @param texture_format Texture format * @param texture_width Texture width * @param texture_height Texture height **/ void prepareDataForStencilUIntTexture(const glw::Functions& gl, glw::GLint cube_face, glw::GLint element_index, glw::GLint mipmap_level, glw::GLint n_elements, glw::GLint n_mipmap_levels, glw::GLenum texture_format, glw::GLenum texture_type, glw::GLsizei texture_width, glw::GLsizei texture_height) { glw::GLubyte component = 0; getStencilComponent(cube_face, element_index, mipmap_level, n_elements, n_mipmap_levels, component); prepareDataForTexture(gl, cube_face, element_index, mipmap_level, texture_format, texture_type, texture_width, texture_height, &component); } /** Prepare texture's face at given index and level, for depth textures. * * @param gl GL functions * @param cube_face Index of cube map's face * @param element_index Index of element in array * @param mipmap_level Mipmap level * @param n_elements Number of elements in array * @param n_mipmap_levels Number of mipmap levels * @param texture_format Texture format * @param texture_width Texture width * @param texture_height Texture height **/ void prepareDepthTextureFace(const glw::Functions& gl, glw::GLint cube_face, glw::GLint element_index, glw::GLint mipmap_level, glw::GLint n_elements, glw::GLint n_mipmap_levels, glw::GLenum texture_format, glw::GLenum texture_type, glw::GLsizei texture_width, glw::GLsizei texture_height) { switch (texture_type) { case GL_FLOAT: prepareDataForDepthFloatTexture(gl, cube_face, element_index, mipmap_level, n_elements, n_mipmap_levels, texture_format, texture_type, texture_width, texture_height); break; default: TCU_FAIL("Not implemented case !"); } } /** Prepare grad_x vector for given texture_coordinates * * @param grad_x Storage for grad_x * @param face Cube map's face index * @param texture_coordinates Texture coordinate * @param width Image width **/ void prepareGradXForFace(glw::GLfloat* grad_x, glw::GLuint face, glw::GLfloat* texture_coordinates, glw::GLuint width) { static const glw::GLuint n_points_per_face = 9; static const glw::GLuint n_texture_coordinates_components = 4; static const glw::GLuint n_grad_components = 4; for (glw::GLuint i = 0; i < n_points_per_face; i += 2) { const glw::GLuint texture_coordinates_offset = i * n_texture_coordinates_components; const glw::GLuint grad_offset = i * n_grad_components; getRightNeighbour(texture_coordinates + texture_coordinates_offset, face, 1, width, grad_x + grad_offset); } for (glw::GLuint i = 1; i < n_points_per_face; i += 2) { const glw::GLuint texture_coordinates_offset = i * n_texture_coordinates_components; const glw::GLuint grad_offset = i * n_grad_components; getRightNeighbour(texture_coordinates + texture_coordinates_offset, face, 4 * width, width, grad_x + grad_offset); } for (glw::GLuint i = 0; i < n_points_per_face; ++i) { const glw::GLuint texture_coordinates_offset = i * n_texture_coordinates_components; const glw::GLuint grad_offset = i * n_grad_components; vectorSubtractInPlace<3>(grad_x + grad_offset, texture_coordinates + texture_coordinates_offset); } } /** Prepare grad_y vector for given texture_coordinates * * @param grad_y Storage for grad_x * @param face Cube map's face index * @param texture_coordinates Texture coordinate * @param width Image width **/ void prepareGradYForFace(glw::GLfloat* grad_y, glw::GLuint face, glw::GLfloat* texture_coordinates, glw::GLuint width) { static const glw::GLuint n_points_per_face = 9; static const glw::GLuint n_texture_coordinates_components = 4; static const glw::GLuint n_grad_components = 4; for (glw::GLuint i = 0; i < n_points_per_face; i += 2) { const glw::GLuint texture_coordinates_offset = i * n_texture_coordinates_components; const glw::GLuint grad_offset = i * n_grad_components; getTopNeighbour(texture_coordinates + texture_coordinates_offset, face, 1, width, grad_y + grad_offset); } for (glw::GLuint i = 1; i < n_points_per_face; i += 2) { const glw::GLuint texture_coordinates_offset = i * n_texture_coordinates_components; const glw::GLuint grad_offset = i * n_grad_components; getTopNeighbour(texture_coordinates + texture_coordinates_offset, face, 4 * width, width, grad_y + grad_offset); } for (glw::GLuint i = 0; i < n_points_per_face; ++i) { const glw::GLuint texture_coordinates_offset = i * n_texture_coordinates_components; const glw::GLuint grad_offset = i * n_grad_components; vectorSubtractInPlace<3>(grad_y + grad_offset, texture_coordinates + texture_coordinates_offset); } } /** Prepare "lods" for face. * Pattern is: B T B * T B T * B T B * B - base, T - top * * @param lods Storage for lods * @param n_mipmap_levels Number of mipmap levels **/ void prepareLodForFace(glw::GLfloat* lods, glw::GLuint n_mipmap_levels) { const glw::GLfloat base_level = 0.0f; const glw::GLfloat top_level = (glw::GLfloat)(n_mipmap_levels - 1); lods[0] = base_level; lods[1] = top_level; lods[2] = base_level; lods[3] = top_level; lods[4] = base_level; lods[5] = top_level; lods[6] = base_level; lods[7] = top_level; lods[8] = base_level; } /** Prepare position for vertices. Each vertex is placed on a unique pixel of output image. * * @param positions Storage for positions * @param cube_face Texture coordinate * @param element_index Index of element in array * @param n_layers Image width **/ void preparePositionForFace(glw::GLfloat* positions, glw::GLuint cube_face, glw::GLuint element_index, glw::GLuint n_layers) { static const glw::GLuint x_offset_per_face = 3; static const glw::GLuint n_faces = 6; const glw::GLuint x_offset_for_face = (element_index * n_faces + cube_face) * x_offset_per_face; const glw::GLfloat x_step = 2.0f / ((glw::GLfloat)(n_layers * 3)); const glw::GLfloat x_mid_step = x_step / 2.0f; const glw::GLfloat y_step = 2.0f / 3.0f; const glw::GLfloat y_mid_step = y_step / 2.0f; const glw::GLfloat x_left = -1.0f + x_mid_step + ((glw::GLfloat)x_offset_for_face) * x_step; const glw::GLfloat x_middle = x_left + x_step; const glw::GLfloat x_right = x_middle + x_step; const glw::GLfloat y_top = 1.0f - y_mid_step; const glw::GLfloat y_middle = y_top - y_step; const glw::GLfloat y_bottom = y_middle - y_step; vectorSet4(positions, 0, x_left, y_top, 0.0f, 1.0f); vectorSet4(positions, 1, x_middle, y_top, 0.0f, 1.0f); vectorSet4(positions, 2, x_right, y_top, 0.0f, 1.0f); vectorSet4(positions, 3, x_left, y_middle, 0.0f, 1.0f); vectorSet4(positions, 4, x_middle, y_middle, 0.0f, 1.0f); vectorSet4(positions, 5, x_right, y_middle, 0.0f, 1.0f); vectorSet4(positions, 6, x_left, y_bottom, 0.0f, 1.0f); vectorSet4(positions, 7, x_middle, y_bottom, 0.0f, 1.0f); vectorSet4(positions, 8, x_right, y_bottom, 0.0f, 1.0f); } /** Prepare "refZ" for face. * Pattern is: - = + * - = + * - = + * '-' - lower than depth * = - eqaul to depth * + - higher thatn depth * * @param refZs Storage for refZs * @param n_mipmaps Number of mipmap levels * @param face Cube map's face index * @param layer Index of element in array * @param n_layers Number of elements in array **/ void prepareRefZForFace(glw::GLfloat* refZs, glw::GLuint n_mipmaps, glw::GLuint face, glw::GLuint layer, glw::GLuint n_layers) { glw::GLfloat expected_base_depth_value = 0; glw::GLfloat expected_top_depth_value = 0; /* Get depth for top and base levles */ getDepthComponent(face, layer, 0, n_layers, n_mipmaps, expected_base_depth_value); getDepthComponent(face, layer, n_mipmaps - 1, n_layers, n_mipmaps, expected_top_depth_value); /* Use step of 10% */ const glw::GLfloat base_depth_step = expected_base_depth_value * 0.1f; const glw::GLfloat top_depth_step = expected_top_depth_value * 0.1f; /* Top row */ refZs[0] = expected_base_depth_value - base_depth_step; refZs[1] = expected_top_depth_value; refZs[2] = expected_base_depth_value + base_depth_step; /* Center row */ refZs[3] = expected_top_depth_value - top_depth_step; refZs[4] = expected_base_depth_value; refZs[5] = expected_top_depth_value + top_depth_step; /* Bottom row */ refZs[6] = expected_base_depth_value - base_depth_step; refZs[7] = expected_top_depth_value; refZs[8] = expected_base_depth_value + base_depth_step; } /** Prepare texture's face at given index and level, for rgba integer textures. * * @param gl GL functions * @param cube_face Index of cube map's face * @param element_index Index of element in array * @param mipmap_level Mipmap level * @param n_elements Number of elements in array * @param n_mipmap_levels Number of mipmap levels * @param texture_format Texture format * @param texture_width Texture width * @param texture_height Texture height **/ void prepareRGBAIntegerTextureFace(const glw::Functions& gl, glw::GLint cube_face, glw::GLint element_index, glw::GLint mipmap_level, glw::GLint n_elements, glw::GLint n_mipmap_levels, glw::GLenum texture_format, glw::GLenum texture_type, glw::GLsizei texture_width, glw::GLsizei texture_height) { switch (texture_type) { case GL_UNSIGNED_INT: prepareDataForColorIntTexture(gl, cube_face, element_index, mipmap_level, n_elements, n_mipmap_levels, texture_format, texture_type, texture_width, texture_height); break; case GL_INT: prepareDataForColorIntTexture(gl, cube_face, element_index, mipmap_level, n_elements, n_mipmap_levels, texture_format, texture_type, texture_width, texture_height); break; default: TCU_FAIL("Not implemented case !"); } } /** Prepare texture's face at given index and level, for rgba textures. * * @param gl GL functions * @param cube_face Index of cube map's face * @param element_index Index of element in array * @param mipmap_level Mipmap level * @param n_elements Number of elements in array * @param n_mipmap_levels Number of mipmap levels * @param texture_format Texture format * @param texture_width Texture width * @param texture_height Texture height **/ void prepareRGBATextureFace(const glw::Functions& gl, glw::GLint cube_face, glw::GLint element_index, glw::GLint mipmap_level, glw::GLint n_elements, glw::GLint n_mipmap_levels, glw::GLenum texture_format, glw::GLenum texture_type, glw::GLsizei texture_width, glw::GLsizei texture_height) { switch (texture_type) { case GL_UNSIGNED_BYTE: prepareDataForColorIntTexture(gl, cube_face, element_index, mipmap_level, n_elements, n_mipmap_levels, texture_format, texture_type, texture_width, texture_height); break; case GL_FLOAT: prepareDataForColorFloatTexture(gl, cube_face, element_index, mipmap_level, n_elements, n_mipmap_levels, texture_format, texture_type, texture_width, texture_height); break; default: TCU_FAIL("Not implemented case !"); } } /** Prepare texture's face at given index and level, for stencil textures. * * @param gl GL functions * @param cube_face Index of cube map's face * @param element_index Index of element in array * @param mipmap_level Mipmap level * @param n_elements Number of elements in array * @param n_mipmap_levels Number of mipmap levels * @param texture_format Texture format * @param texture_width Texture width * @param texture_height Texture height **/ void prepareStencilTextureFace(const glw::Functions& gl, glw::GLint cube_face, glw::GLint element_index, glw::GLint mipmap_level, glw::GLint n_elements, glw::GLint n_mipmap_levels, glw::GLenum texture_format, glw::GLenum texture_type, glw::GLsizei texture_width, glw::GLsizei texture_height) { switch (texture_type) { case GL_UNSIGNED_BYTE: prepareDataForStencilUIntTexture(gl, cube_face, element_index, mipmap_level, n_elements, n_mipmap_levels, texture_format, texture_type, texture_width, texture_height); break; default: TCU_FAIL("Not implemented case !"); } } /** Prepare texture coordinates for vertices. * Each vertex has unique value. 4 corners, centers of 4 edges and central points are selected. * * @param positions Storage for positions * @param cube_face Texture coordinate * @param element_index Index of element in array * @param n_layers Image width **/ void prepareTextureCoordinatesForFace(glw::GLfloat* data, glw::GLuint width, glw::GLuint height, glw::GLfloat layer, glw::GLuint face) { const glw::GLfloat x_range = (glw::GLfloat)width; const glw::GLfloat y_range = (glw::GLfloat)height; const glw::GLfloat x_step = 2.0f / x_range; const glw::GLfloat y_step = 2.0f / y_range; const glw::GLfloat x_mid_step = x_step / 2.0f; const glw::GLfloat y_mid_step = y_step / 2.0f; const glw::GLfloat left = -1.0f + x_mid_step; const glw::GLfloat right = 1.0f - x_mid_step; const glw::GLfloat top = 1.0f - y_mid_step; const glw::GLfloat bottom = -1.0f + y_mid_step; const glw::GLfloat middle = 0.0f; const glw::GLfloat negative = -1.0f; const glw::GLfloat positive = 1.0f; switch (face) { case 0: vectorSet4(data, 0, positive, left, top, layer); vectorSet4(data, 1, positive, middle, top, layer); vectorSet4(data, 2, positive, right, top, layer); vectorSet4(data, 3, positive, left, middle, layer); vectorSet4(data, 4, positive, middle, middle, layer); vectorSet4(data, 5, positive, right, middle, layer); vectorSet4(data, 6, positive, left, bottom, layer); vectorSet4(data, 7, positive, middle, bottom, layer); vectorSet4(data, 8, positive, right, bottom, layer); break; case 1: vectorSet4(data, 0, negative, left, top, layer); vectorSet4(data, 1, negative, middle, top, layer); vectorSet4(data, 2, negative, right, top, layer); vectorSet4(data, 3, negative, left, middle, layer); vectorSet4(data, 4, negative, middle, middle, layer); vectorSet4(data, 5, negative, right, middle, layer); vectorSet4(data, 6, negative, left, bottom, layer); vectorSet4(data, 7, negative, middle, bottom, layer); vectorSet4(data, 8, negative, right, bottom, layer); break; case 2: vectorSet4(data, 0, left, positive, top, layer); vectorSet4(data, 1, middle, positive, top, layer); vectorSet4(data, 2, right, positive, top, layer); vectorSet4(data, 3, left, positive, middle, layer); vectorSet4(data, 4, middle, positive, middle, layer); vectorSet4(data, 5, right, positive, middle, layer); vectorSet4(data, 6, left, positive, bottom, layer); vectorSet4(data, 7, middle, positive, bottom, layer); vectorSet4(data, 8, right, positive, bottom, layer); break; case 3: vectorSet4(data, 0, left, negative, top, layer); vectorSet4(data, 1, middle, negative, top, layer); vectorSet4(data, 2, right, negative, top, layer); vectorSet4(data, 3, left, negative, middle, layer); vectorSet4(data, 4, middle, negative, middle, layer); vectorSet4(data, 5, right, negative, middle, layer); vectorSet4(data, 6, left, negative, bottom, layer); vectorSet4(data, 7, middle, negative, bottom, layer); vectorSet4(data, 8, right, negative, bottom, layer); break; case 4: vectorSet4(data, 0, left, top, positive, layer); vectorSet4(data, 1, middle, top, positive, layer); vectorSet4(data, 2, right, top, positive, layer); vectorSet4(data, 3, left, middle, positive, layer); vectorSet4(data, 4, middle, middle, positive, layer); vectorSet4(data, 5, right, middle, positive, layer); vectorSet4(data, 6, left, bottom, positive, layer); vectorSet4(data, 7, middle, bottom, positive, layer); vectorSet4(data, 8, right, bottom, positive, layer); break; case 5: vectorSet4(data, 0, left, top, negative, layer); vectorSet4(data, 1, middle, top, negative, layer); vectorSet4(data, 2, right, top, negative, layer); vectorSet4(data, 3, left, middle, negative, layer); vectorSet4(data, 4, middle, middle, negative, layer); vectorSet4(data, 5, right, middle, negative, layer); vectorSet4(data, 6, left, bottom, negative, layer); vectorSet4(data, 7, middle, bottom, negative, layer); vectorSet4(data, 8, right, bottom, negative, layer); break; } vectorNormalize<3, 4>(data, 0); vectorNormalize<3, 4>(data, 1); vectorNormalize<3, 4>(data, 2); vectorNormalize<3, 4>(data, 3); vectorNormalize<3, 4>(data, 4); vectorNormalize<3, 4>(data, 5); vectorNormalize<3, 4>(data, 6); vectorNormalize<3, 4>(data, 7); vectorNormalize<3, 4>(data, 8); } /** Prepare texture coordinates for vertices. For sampling with textureGather routine. * Each vertex has unique value. 4 corners, centers of 4 edges and central points are selected. * * @param positions Storage for positions * @param cube_face Texture coordinate * @param element_index Index of element in array * @param n_layers Image width **/ void prepareTextureCoordinatesForGatherForFace(glw::GLfloat* data, glw::GLuint width, glw::GLuint height, glw::GLfloat layer, glw::GLuint face) { const glw::GLfloat x_range = (glw::GLfloat)width; const glw::GLfloat y_range = (glw::GLfloat)height; const glw::GLfloat x_step = 2.0f / x_range; const glw::GLfloat y_step = 2.0f / y_range; const glw::GLfloat x_mid_step = x_step / 2.0f; const glw::GLfloat y_mid_step = y_step / 2.0f; const glw::GLfloat left = -1.0f + x_mid_step + x_step; const glw::GLfloat right = 1.0f - x_mid_step - x_step; const glw::GLfloat top = 1.0f - y_mid_step - y_step; const glw::GLfloat bottom = -1.0f + y_mid_step + y_step; const glw::GLfloat middle = 0.0f; const glw::GLfloat negative = -1.0f; const glw::GLfloat positive = 1.0f; switch (face) { case 0: vectorSet4(data, 0, positive, left, top, layer); vectorSet4(data, 1, positive, middle, top, layer); vectorSet4(data, 2, positive, right, top, layer); vectorSet4(data, 3, positive, left, middle, layer); vectorSet4(data, 4, positive, middle, middle, layer); vectorSet4(data, 5, positive, right, middle, layer); vectorSet4(data, 6, positive, left, bottom, layer); vectorSet4(data, 7, positive, middle, bottom, layer); vectorSet4(data, 8, positive, right, bottom, layer); break; case 1: vectorSet4(data, 0, negative, left, top, layer); vectorSet4(data, 1, negative, middle, top, layer); vectorSet4(data, 2, negative, right, top, layer); vectorSet4(data, 3, negative, left, middle, layer); vectorSet4(data, 4, negative, middle, middle, layer); vectorSet4(data, 5, negative, right, middle, layer); vectorSet4(data, 6, negative, left, bottom, layer); vectorSet4(data, 7, negative, middle, bottom, layer); vectorSet4(data, 8, negative, right, bottom, layer); break; case 2: vectorSet4(data, 0, left, positive, top, layer); vectorSet4(data, 1, middle, positive, top, layer); vectorSet4(data, 2, right, positive, top, layer); vectorSet4(data, 3, left, positive, middle, layer); vectorSet4(data, 4, middle, positive, middle, layer); vectorSet4(data, 5, right, positive, middle, layer); vectorSet4(data, 6, left, positive, bottom, layer); vectorSet4(data, 7, middle, positive, bottom, layer); vectorSet4(data, 8, right, positive, bottom, layer); break; case 3: vectorSet4(data, 0, left, negative, top, layer); vectorSet4(data, 1, middle, negative, top, layer); vectorSet4(data, 2, right, negative, top, layer); vectorSet4(data, 3, left, negative, middle, layer); vectorSet4(data, 4, middle, negative, middle, layer); vectorSet4(data, 5, right, negative, middle, layer); vectorSet4(data, 6, left, negative, bottom, layer); vectorSet4(data, 7, middle, negative, bottom, layer); vectorSet4(data, 8, right, negative, bottom, layer); break; case 4: vectorSet4(data, 0, left, top, positive, layer); vectorSet4(data, 1, middle, top, positive, layer); vectorSet4(data, 2, right, top, positive, layer); vectorSet4(data, 3, left, middle, positive, layer); vectorSet4(data, 4, middle, middle, positive, layer); vectorSet4(data, 5, right, middle, positive, layer); vectorSet4(data, 6, left, bottom, positive, layer); vectorSet4(data, 7, middle, bottom, positive, layer); vectorSet4(data, 8, right, bottom, positive, layer); break; case 5: vectorSet4(data, 0, left, top, negative, layer); vectorSet4(data, 1, middle, top, negative, layer); vectorSet4(data, 2, right, top, negative, layer); vectorSet4(data, 3, left, middle, negative, layer); vectorSet4(data, 4, middle, middle, negative, layer); vectorSet4(data, 5, right, middle, negative, layer); vectorSet4(data, 6, left, bottom, negative, layer); vectorSet4(data, 7, middle, bottom, negative, layer); vectorSet4(data, 8, right, bottom, negative, layer); break; } vectorNormalize<3, 4>(data, 0); vectorNormalize<3, 4>(data, 1); vectorNormalize<3, 4>(data, 2); vectorNormalize<3, 4>(data, 3); vectorNormalize<3, 4>(data, 4); vectorNormalize<3, 4>(data, 5); vectorNormalize<3, 4>(data, 6); vectorNormalize<3, 4>(data, 7); vectorNormalize<3, 4>(data, 8); } /** Prepare texture's face at given index and level. * * @param gl GL functions * @param cube_face Index of cube map's face * @param element_index Index of element in array * @param mipmap_level Mipmap level * @param n_elements Number of elements in array * @param n_mipmap_levels Number of mipmap levels * @param texture_format Texture format * @param texture_width Texture width * @param texture_height Texture height **/ void prepareTextureFace(const glw::Functions& gl, glw::GLint cube_face, glw::GLint element_index, glw::GLint mipmap_level, glw::GLint n_elements, glw::GLint n_mipmap_levels, glw::GLenum texture_format, glw::GLenum texture_type, glw::GLsizei texture_width, glw::GLsizei texture_height) { switch (texture_format) { case GL_RGBA: prepareRGBATextureFace(gl, cube_face, element_index, mipmap_level, n_elements, n_mipmap_levels, texture_format, texture_type, texture_width, texture_height); break; case GL_RGBA_INTEGER: prepareRGBAIntegerTextureFace(gl, cube_face, element_index, mipmap_level, n_elements, n_mipmap_levels, texture_format, texture_type, texture_width, texture_height); break; case GL_DEPTH_COMPONENT: prepareDepthTextureFace(gl, cube_face, element_index, mipmap_level, n_elements, n_mipmap_levels, texture_format, texture_type, texture_width, texture_height); break; case GL_STENCIL_INDEX: prepareStencilTextureFace(gl, cube_face, element_index, mipmap_level, n_elements, n_mipmap_levels, texture_format, texture_type, texture_width, texture_height); break; default: TCU_FAIL("Not implemented case !"); } } /** Verifies that all pixels rendered for specific face match expectations * * @tparam T Type of image component * @tparam N_Components Number of image components * @tparam Width Width of single face * @tparam Height Height of single face * * @param data Rendered data * @param cube_face Index of face in array * @param expected_values Expected values * @param image_width Widht of whole image **/ template bool verifyFace(const T* data, const glw::GLuint cube_face, const T* expected_values, const glw::GLuint image_width) { static const glw::GLuint size_of_pixel = N_Components; const glw::GLuint data_face_offset = N_Components * Width * cube_face; const glw::GLuint exp_face_offset = N_Components * Width * Height * cube_face; const glw::GLuint data_size_of_line = image_width * size_of_pixel; const glw::GLuint exp_size_of_line = Width * size_of_pixel; for (glw::GLuint y = 0; y < Height; ++y) { const glw::GLuint data_line_offset = y * data_size_of_line; const glw::GLuint exp_line_offset = y * exp_size_of_line; for (glw::GLuint x = 0; x < Width; ++x) { const glw::GLuint data_pixel_offset = data_line_offset + data_face_offset + x * size_of_pixel; const glw::GLuint exp_pixel_offset = exp_line_offset + exp_face_offset + x * size_of_pixel; for (glw::GLuint component = 0; component < N_Components; ++component) { if (data[data_pixel_offset + component] != expected_values[exp_pixel_offset + component]) { return false; } } } } return true; } /** Verifies that all rendered pixels match expectation * * @tparam T Type of image component * @tparam N_Components Number of image components * @tparam Width Width of single face * @tparam Height Height of single face * * @param data Rendered data * @param expected_values Expected values * @param n_layers Number of elements in array **/ template bool verifyImage(const T* data, const T* expected_values, const glw::GLuint n_layers) { static const glw::GLuint n_faces = 6; const glw::GLuint n_total_faces = n_layers * n_faces; for (glw::GLuint face = 0; face < n_total_faces; ++face) { if (false == verifyFace(data, face, expected_values, n_total_faces * Width)) { return false; } } return true; } /** Verifies that all rendered pixels match expectation * * @tparam T Type of image component * @tparam N_Components Number of image components * @tparam Width Width of single face * @tparam Height Height of single face * * @param n_mipmap_levels Number of mipmap levels * @param n_layers Number of elements in array * @param getComponents Routine which is used to obtain components * @param data Rendered data **/ template bool verifyResultImage(glw::GLuint n_mipmap_levels, glw::GLuint n_layers, void (*getComponents)(glw::GLuint pixel_index, glw::GLint cube_face, glw::GLint layer_index, glw::GLint n_layers, glw::GLint n_mipmap_levels, T* out_components), const glw::GLubyte* data) { const glw::GLuint n_components = N_Components; const glw::GLuint face_width = Width; const glw::GLuint face_height = Height; const glw::GLuint n_pixels_per_face = face_width * face_height; const glw::GLuint n_components_per_face = n_pixels_per_face * n_components; const glw::GLuint n_faces = 6; const glw::GLuint n_total_faces = n_layers * n_faces; const glw::GLuint n_total_components = n_total_faces * n_components_per_face; const T* result_image = (const T*)data; std::vector expected_values; expected_values.resize(n_total_components); for (glw::GLuint layer = 0; layer < n_layers; ++layer) { const glw::GLuint layer_offset = layer * n_faces * n_components_per_face; for (glw::GLuint face = 0; face < n_faces; ++face) { const glw::GLuint face_offset = face * n_components_per_face + layer_offset; for (glw::GLuint pixel = 0; pixel < n_pixels_per_face; ++pixel) { const glw::GLuint pixel_offset = pixel * n_components + face_offset; T components[n_components]; getComponents(pixel, face, layer, n_layers, n_mipmap_levels, components); for (glw::GLuint component = 0; component < n_components; ++component) { const glw::GLuint component_offset = pixel_offset + component; expected_values[component_offset] = components[component]; } } } } return verifyImage(result_image, &expected_values[0], n_layers); } /** Constructor * * @param context Test context * @param name Test case's name * @param description Test case's desricption **/ TextureCubeMapArraySamplingTest::TextureCubeMapArraySamplingTest(Context& context, const ExtParameters& extParams, const char* name, const char* description) : TestCaseBase(context, extParams, name, description) , m_framebuffer_object_id(0) , compiled_shaders(0) , invalid_shaders(0) , linked_programs(0) , invalid_programs(0) , tested_cases(0) , failed_cases(0) , invalid_type_cases(0) { /* Prepare formats set */ m_formats.push_back(formatDefinition(GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, false, Float, "GL_RGBA8")); m_formats.push_back(formatDefinition(GL_RGBA32I, GL_RGBA_INTEGER, GL_INT, false, Int, "GL_RGBA32I")); m_formats.push_back(formatDefinition(GL_RGBA32UI, GL_RGBA_INTEGER, GL_UNSIGNED_INT, false, UInt, "GL_RGBA32UI")); m_formats.push_back(formatDefinition(GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT, GL_FLOAT, false, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, Depth, "GL_DEPTH_COMPONENT32F")); m_formats.push_back(formatDefinition(GL_STENCIL_INDEX8, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, false, GL_R32UI, GL_RGBA_INTEGER, GL_UNSIGNED_INT, Stencil, "GL_STENCIL_INDEX8")); /* Prepare sampling functions set */ m_functions.push_back(samplingFunctionDefinition(Texture, "Texture")); m_functions.push_back(samplingFunctionDefinition(TextureLod, "TextureLod")); m_functions.push_back(samplingFunctionDefinition(TextureGrad, "TextureGrad")); m_functions.push_back(samplingFunctionDefinition(TextureGather, "TextureGather")); /* Prepare mutabilities set */ m_mutabilities.push_back(true); m_mutabilities.push_back(false); /* Prepare resolutions set */ m_resolutions.push_back(resolutionDefinition(64, 64, 18)); m_resolutions.push_back(resolutionDefinition(117, 117, 6)); m_resolutions.push_back(resolutionDefinition(256, 256, 6)); m_resolutions.push_back(resolutionDefinition(173, 173, 12)); /* Prepare resolutions set for compressed formats */ m_compressed_resolutions.push_back(resolutionDefinition(8, 8, 12)); m_compressed_resolutions.push_back(resolutionDefinition(13, 13, 12)); } /** Check if getActiveUniform and glGetProgramResourceiv returns correct type for cube array samplers. * * @param program_id Program id * @param sampler_name_p Name of sampler * @param sampler_type Expected type of sampler * * @return Status. 1st LSB - glGetActiveUniform, second LSB glGetProgramResourceiv, 0 valid, 1 invalid. **/ glw::GLuint TextureCubeMapArraySamplingTest::checkUniformAndResourceApi(glw::GLuint program_id, const glw::GLchar* sampler_name_p, samplerType sampler_type) { /* GL functions */ const glw::Functions& gl = m_context.getRenderContext().getFunctions(); glw::GLenum expected_type = 0; glw::GLuint index_getActiveUniform = GL_INVALID_INDEX; glw::GLuint index_getProgramResourceiv = GL_INVALID_INDEX; glw::GLenum props = GL_TYPE; glw::GLuint result = 0; glw::GLchar* name = 0; glw::GLint size = 0; glw::GLenum type_getActiveUniform = 0; glw::GLint type_getProgramResourceiv = 0; // Get type by getActiveUniform gl.getUniformIndices(program_id, 1, &sampler_name_p, &index_getActiveUniform); GLU_EXPECT_NO_ERROR(gl.getError(), "glGetUniformIndices"); if (GL_INVALID_INDEX == index_getActiveUniform) { throw tcu::InternalError("glGetUniformIndices: GL_INVALID_INDEX", "", __FILE__, __LINE__); } gl.getActiveUniform(program_id, index_getActiveUniform, 0, 0, &size, &type_getActiveUniform, name); GLU_EXPECT_NO_ERROR(gl.getError(), "glGetActiveUniform"); // Get type by gl.getProgramResourceiv index_getProgramResourceiv = gl.getProgramResourceIndex(program_id, GL_UNIFORM, sampler_name_p); GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramResourceIndex"); if (GL_INVALID_INDEX == index_getProgramResourceiv) { throw tcu::InternalError("glGetProgramResourceIndex: GL_INVALID_INDEX", "", __FILE__, __LINE__); } gl.getProgramResourceiv(program_id, GL_UNIFORM, index_getProgramResourceiv, 1, &props, 1, 0, &type_getProgramResourceiv); GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramResourceiv"); // Verification switch (sampler_type) { case Float: expected_type = GL_SAMPLER_CUBE_MAP_ARRAY; break; case Int: expected_type = GL_INT_SAMPLER_CUBE_MAP_ARRAY; break; case UInt: expected_type = GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY; break; case Depth: expected_type = GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW; break; case Stencil: expected_type = GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY; break; } if (expected_type != type_getActiveUniform) { result |= m_get_type_api_status_uniform; } if (expected_type != (glw::GLuint)type_getProgramResourceiv) { result |= m_get_type_api_status_program_resource; } return result; } /** Compile shader * * @param info Shader info **/ void TextureCubeMapArraySamplingTest::compile(shaderDefinition& info) { compiled_shaders += 1; if (false == info.compile()) { invalid_shaders += 1; logCompilationLog(info); } } /** Execute compute shader * * @param program_id Program id * @param width Width of result image * @param height Height of result image **/ void TextureCubeMapArraySamplingTest::dispatch(glw::GLuint program_id, glw::GLuint width, glw::GLuint height) { (void)program_id; /* GL functions */ const glw::Functions& gl = m_context.getRenderContext().getFunctions(); gl.dispatchCompute(width, height, 1); GLU_EXPECT_NO_ERROR(gl.getError(), "Failed glDispatchCompute call."); } /** Execute render call * * @param program_id Program id * @param primitive_type Type of primitive * @param n_vertices Number of vertices **/ void TextureCubeMapArraySamplingTest::draw(glw::GLuint program_id, glw::GLenum primitive_type, glw::GLuint n_vertices, glw::GLenum format) { (void)program_id; /* GL functions */ const glw::Functions& gl = m_context.getRenderContext().getFunctions(); const glw::GLenum framebuffer_status = gl.checkFramebufferStatus(GL_DRAW_FRAMEBUFFER); if (GL_FRAMEBUFFER_COMPLETE != framebuffer_status) { throw tcu::InternalError("Framebuffer is incomplete", "", __FILE__, __LINE__); } switch (format) { case GL_RGBA32I: { const glw::GLint clearValue[4] = { 255, 255, 255, 255 }; gl.clearBufferiv(GL_COLOR, 0, clearValue); GLU_EXPECT_NO_ERROR(gl.getError(), "Failed glClearBufferiv call."); } break; case GL_RGBA32UI: case GL_R32UI: { const glw::GLuint clearValue[4] = { 255, 255, 255, 255 }; gl.clearBufferuiv(GL_COLOR, 0, clearValue); GLU_EXPECT_NO_ERROR(gl.getError(), "Failed glClearBufferuiv call."); } break; case GL_DEPTH_COMPONENT32F: gl.clearDepthf(1.0f); GLU_EXPECT_NO_ERROR(gl.getError(), "Failed glClearDepthf call."); break; case GL_STENCIL_INDEX8: gl.clearStencil(1); GLU_EXPECT_NO_ERROR(gl.getError(), "Failed glClearStencil call."); break; default: gl.clearColor(1.0f, 1.0f, 1.0f, 1.0f); GLU_EXPECT_NO_ERROR(gl.getError(), "Failed glClearColor call."); gl.clear(GL_COLOR_BUFFER_BIT); GLU_EXPECT_NO_ERROR(gl.getError(), "Failed glClear call."); } gl.drawArrays(primitive_type, 0, n_vertices); GLU_EXPECT_NO_ERROR(gl.getError(), "Failed glDrawArrays call."); } /** Get attributes specific for type of sampler * * @param sampler_type Type of sampler * @param out_attribute_definitions Array of attributes * @param out_n_attributes Number of attributes **/ void TextureCubeMapArraySamplingTest::getAttributes(samplerType sampler_type, const attributeDefinition*& out_attribute_definitions, glw::GLuint& out_n_attributes) { static attributeDefinition depth_attributes[] = { { attribute_refZ, type_float, RefZ, 1 } }; static const glw::GLuint n_depth_attributes = sizeof(depth_attributes) / sizeof(depth_attributes[0]); switch (sampler_type) { case Depth: out_attribute_definitions = depth_attributes; out_n_attributes = n_depth_attributes; break; default: out_attribute_definitions = 0; out_n_attributes = 0; break; } } /** Get attributes specific for sampling function * * @param sampling_function Sampling function * @param out_attribute_definitions Array of attributes * @param out_n_attributes Number of attributes **/ void TextureCubeMapArraySamplingTest::getAttributes(samplingFunction sampling_function, const attributeDefinition*& out_attribute_definitions, glw::GLuint& out_n_attributes) { static attributeDefinition texture_attributes[] = { { attribute_texture_coordinate, type_vec4, TextureCoordinates, 0 } }; static attributeDefinition textureLod_attributes[] = { { attribute_texture_coordinate, type_vec4, TextureCoordinates, 0 }, { attribute_lod, type_float, Lod, 1 } }; static attributeDefinition textureGrad_attributes[] = { { attribute_texture_coordinate, type_vec4, TextureCoordinates, 0 }, { attribute_grad_x, type_vec3, GradX, 1 }, { attribute_grad_y, type_vec3, GradY, 2 } }; static attributeDefinition textureGather_attributes[] = { { attribute_texture_coordinate, type_vec4, TextureCoordinatesForGather, 0 } }; static const glw::GLuint n_texture_attributes = sizeof(texture_attributes) / sizeof(texture_attributes[0]); static const glw::GLuint n_textureLod_attributes = sizeof(textureLod_attributes) / sizeof(textureLod_attributes[0]); static const glw::GLuint n_textureGrad_attributes = sizeof(textureGrad_attributes) / sizeof(textureGrad_attributes[0]); static const glw::GLuint n_textureGather_attributes = sizeof(textureGather_attributes) / sizeof(textureGather_attributes[0]); switch (sampling_function) { case Texture: out_attribute_definitions = texture_attributes; out_n_attributes = n_texture_attributes; break; case TextureLod: out_attribute_definitions = textureLod_attributes; out_n_attributes = n_textureLod_attributes; break; case TextureGrad: out_attribute_definitions = textureGrad_attributes; out_n_attributes = n_textureGrad_attributes; break; case TextureGather: out_attribute_definitions = textureGather_attributes; out_n_attributes = n_textureGather_attributes; break; } } /** Get information about color type for type of sampler * * @param sampler_type Type of sampler * @param out_color_type Type used for color storage * @param out_interpolation_type Type of interpolation * @param out_sampler_type Type of sampler * @param out_n_components Number of components in color * @param out_is_shadow If shadow sampler **/ void TextureCubeMapArraySamplingTest::getColorType(samplerType sampler_type, const glw::GLchar*& out_color_type, const glw::GLchar*& out_interpolation_type, const glw::GLchar*& out_sampler_type, glw::GLuint& out_n_components, bool& out_is_shadow) { switch (sampler_type) { case Float: out_color_type = type_vec4; out_interpolation_type = ""; out_sampler_type = sampler_float; out_n_components = 4; out_is_shadow = false; break; case Int: out_color_type = type_ivec4; out_interpolation_type = interpolation_flat; out_sampler_type = sampler_int; out_n_components = 4; out_is_shadow = false; break; case UInt: out_color_type = type_uvec4; out_interpolation_type = interpolation_flat; out_sampler_type = sampler_uint; out_n_components = 4; out_is_shadow = false; break; case Depth: out_color_type = type_float; out_interpolation_type = ""; out_sampler_type = sampler_depth; out_n_components = 1; out_is_shadow = true; break; case Stencil: out_color_type = type_uint; out_interpolation_type = interpolation_flat; out_sampler_type = sampler_uint; out_n_components = 1; out_is_shadow = false; break; } } /** Get information about color type for type of sampler * * @param sampler_type Type of sampler * @param out_color_type Type used for color storage * @param out_interpolation_type Type of interpolation * @param out_sampler_type Type of sampler * @param out_image_type Type of image * @param out_n_components Number of components in color * @param out_is_shadow If shadow sampler **/ void TextureCubeMapArraySamplingTest::getColorType(samplerType sampler_type, const glw::GLchar*& out_color_type, const glw::GLchar*& out_interpolation_type, const glw::GLchar*& out_sampler_type, const glw::GLchar*& out_image_type, const glw::GLchar*& out_image_layout, glw::GLuint& out_n_components, bool& out_is_shadow) { getColorType(sampler_type, out_color_type, out_interpolation_type, out_sampler_type, out_n_components, out_is_shadow); switch (sampler_type) { case Float: out_image_type = image_float; out_image_layout = "rgba8"; break; case Depth: out_image_type = image_float; out_image_layout = "rgba8"; break; case Int: out_image_type = image_int; out_image_layout = "rgba32i"; break; case UInt: out_image_type = image_uint; out_image_layout = "rgba32ui"; break; case Stencil: out_image_type = image_uint; out_image_layout = "r32ui"; break; } } /** Prepare code for passthrough fragment shader * * @param sampler_type Type of sampler * @param out_fragment_shader_code Storage for code **/ void TextureCubeMapArraySamplingTest::getPassThroughFragmentShaderCode(samplerType sampler_type, std::string& out_fragment_shader_code) { std::stringstream stream; const glw::GLchar* color_type; const glw::GLchar* interpolation_type; const glw::GLchar* ignored_sampler_type; glw::GLuint ignored_n_components; bool ignored_is_shadow; /* Get type for color variables */ getColorType(sampler_type, color_type, interpolation_type, ignored_sampler_type, ignored_n_components, ignored_is_shadow); /* Preamble */ stream << shader_code_preamble << shader_precision << "/* Pass through fragment shader */" << std::endl; /* in vec4 fs_in_color */ stream << interpolation_type << shader_input << color_type << fragment_shader_input << ";" << std::endl; stream << std::endl; /* layout(location = 0) out vec4 fs_out_color */ stream << shader_layout << shader_output << color_type << fragment_shader_output << ";" << std::endl; stream << std::endl; /* Body */ stream << fragment_shader_pass_through_body_code << std::endl; /* Store result */ out_fragment_shader_code = stream.str(); } /** Prepare code for passthrough tesselation control shader * * @param sampler_type Type of sampler * @param out_tesselation_control_shader_code Storage for code **/ void TextureCubeMapArraySamplingTest::getPassThroughTesselationControlShaderCode( const samplerType& sampler_type, const samplingFunction& sampling_function, std::string& out_tesselation_control_shader_code) { std::stringstream stream; glw::GLuint n_routine_attributes = 0; glw::GLuint n_type_attributes = 0; const attributeDefinition* routine_attribute_definitions = 0; const attributeDefinition* type_attribute_definitions = 0; getAttributes(sampling_function, routine_attribute_definitions, n_routine_attributes); getAttributes(sampler_type, type_attribute_definitions, n_type_attributes); /* Preamble, extension : require */ stream << shader_code_preamble << tesselation_shader_extension << shader_precision << std::endl << "/* Passthrough tesselation control shader */" << std::endl; /* layout(vertices = 1) out */ stream << tesselation_control_shader_layout; /* in type attribute*/ for (glw::GLuint i = 0; i < n_routine_attributes; ++i) { stream << shader_input << routine_attribute_definitions[i].type << vertex_shader_output << routine_attribute_definitions[i].name << "[];" << std::endl; stream << shader_output << routine_attribute_definitions[i].type << tesselation_control_shader_output << routine_attribute_definitions[i].name << "[];" << std::endl; } for (glw::GLuint i = 0; i < n_type_attributes; ++i) { stream << shader_input << type_attribute_definitions[i].type << vertex_shader_output << type_attribute_definitions[i].name << "[];" << std::endl; stream << shader_output << type_attribute_definitions[i].type << tesselation_control_shader_output << type_attribute_definitions[i].name << "[];" << std::endl; } /* Body */ stream << tesselation_control_shader_sampling_body_code; /* tcs_out[gl_InvocationID] = vs_out[gl_InvocationID] */ for (glw::GLuint i = 0; i < n_routine_attributes; ++i) { stream << " " << tesselation_control_shader_output << routine_attribute_definitions[i].name << "[gl_InvocationID] = " << vertex_shader_output << routine_attribute_definitions[i].name << "[gl_InvocationID];" << std::endl; } for (glw::GLuint i = 0; i < n_type_attributes; ++i) { stream << " " << tesselation_control_shader_output << type_attribute_definitions[i].name << "[gl_InvocationID] = " << vertex_shader_output << type_attribute_definitions[i].name << "[gl_InvocationID];" << std::endl; } stream << "}" << std::endl << std::endl; /* Store result */ out_tesselation_control_shader_code = stream.str(); } /** Prepare code for passthrough tesselation evaluation shader * * @param sampler_type Type of sampler * @param out_tesselation_evaluation_shader_code Storage for code **/ void TextureCubeMapArraySamplingTest::getPassThroughTesselationEvaluationShaderCode( samplerType sampler_type, std::string& out_tesselation_evaluation_shader_code) { const glw::GLchar* color_type = 0; bool ignored_is_shadow = false; glw::GLuint ignored_n_components = 0; const glw::GLchar* ignored_sampler_type = 0; const glw::GLchar* interpolation_type = 0; std::stringstream stream; /* Get type for color variables */ getColorType(sampler_type, color_type, interpolation_type, ignored_sampler_type, ignored_n_components, ignored_is_shadow); /* Preamble, extension : require */ stream << shader_code_preamble << tesselation_shader_extension << shader_precision << std::endl << "/* Pass through tesselation evaluation shader */" << std::endl; /* layout(point_mode) in; */ stream << tesselation_evaluation_shader_layout; /* in vec4 tes_in_color[] */ stream << interpolation_type << shader_input << color_type << tesselation_evaluation_shader_input << "[];" << std::endl; stream << std::endl; /* out vec4 fs_in_color[] */ stream << interpolation_type << shader_output << color_type << fragment_shader_input << ";" << std::endl; stream << std::endl; /* Body */ stream << tesselation_evaluation_shader_pass_through_body_code << std::endl; /* Store result */ out_tesselation_evaluation_shader_code = stream.str(); } /** Prepare code for passthrough vertex shader * * @param sampler_type Type of sampler * @param sampling_function Type of sampling function * @param out_vertex_shader_code Storage for code **/ void TextureCubeMapArraySamplingTest::getPassThroughVertexShaderCode(const samplerType& sampler_type, const samplingFunction& sampling_function, std::string& out_vertex_shader_code) { glw::GLuint n_routine_attributes = 0; glw::GLuint n_type_attributes = 0; const attributeDefinition* routine_attribute_definitions = 0; std::stringstream stream; const attributeDefinition* type_attribute_definitions = 0; /* Get attributes for sampling function */ getAttributes(sampling_function, routine_attribute_definitions, n_routine_attributes); getAttributes(sampler_type, type_attribute_definitions, n_type_attributes); /* Preamble */ stream << shader_code_preamble << "/* Pass through vertex shader */" << std::endl << shader_precision; /* in vec4 vs_in_position */ stream << shader_input << type_vec4 << vertex_shader_input << vertex_shader_position << ";" << std::endl; /* in type vs_in_attribute */ for (glw::GLuint i = 0; i < n_routine_attributes; ++i) { stream << shader_input << routine_attribute_definitions[i].type << vertex_shader_input << routine_attribute_definitions[i].name << ";" << std::endl; } /* in float vs_in_refZ */ for (glw::GLuint i = 0; i < n_type_attributes; ++i) { stream << shader_input << type_attribute_definitions[i].type << vertex_shader_input << type_attribute_definitions[i].name << ";" << std::endl; } stream << std::endl; /* out type vs_out_attribute */ for (glw::GLuint i = 0; i < n_routine_attributes; ++i) { stream << shader_output << routine_attribute_definitions[i].type << vertex_shader_output << routine_attribute_definitions[i].name << ";" << std::endl; } /* out float vs_out_refZ */ for (glw::GLuint i = 0; i < n_type_attributes; ++i) { stream << shader_output << type_attribute_definitions[i].type << vertex_shader_output << type_attribute_definitions[i].name << ";" << std::endl; } stream << std::endl; /* Body */ stream << vertex_shader_body_code; /* vs_out = vs_in */ for (glw::GLuint i = 0; i < n_routine_attributes; ++i) { stream << " " << vertex_shader_output << routine_attribute_definitions[i].name << " = " << vertex_shader_input << routine_attribute_definitions[i].name << ";" << std::endl; } for (glw::GLuint i = 0; i < n_type_attributes; ++i) { stream << " " << vertex_shader_output << type_attribute_definitions[i].name << " = " << vertex_shader_input << type_attribute_definitions[i].name << ";" << std::endl; } stream << "}" << std::endl << std::endl; /* Store result */ out_vertex_shader_code = stream.str(); } /** Prepare code for sampling compute shader * * @param sampler_type Type of sampler * @param sampling_function Type of sampling function * @param out_compute_shader_code Storage for code **/ void TextureCubeMapArraySamplingTest::getSamplingComputeShaderCode(const samplerType& sampler_type, const samplingFunction& sampling_function, std::string& out_compute_shader_code) { const glw::GLchar* color_type = 0; const glw::GLchar* image_type_str = 0; const glw::GLchar* image_layout_str = 0; const glw::GLchar* interpolation_type = 0; bool is_shadow_sampler = false; glw::GLuint n_components = 0; glw::GLuint n_routine_attributes = 0; glw::GLuint n_type_attributes = 0; const attributeDefinition* routine_attribute_definitions = 0; const attributeDefinition* type_attribute_definitions = 0; const glw::GLchar* sampler_type_str = 0; std::string sampling_code; std::stringstream stream; /* Get attributes for sampling function */ getAttributes(sampling_function, routine_attribute_definitions, n_routine_attributes); getAttributes(sampler_type, type_attribute_definitions, n_type_attributes); /* Get type for color variables */ getColorType(sampler_type, color_type, interpolation_type, sampler_type_str, image_type_str, image_layout_str, n_components, is_shadow_sampler); /* Get sampling code */ if (false == is_shadow_sampler) { getSamplingFunctionCall(sampling_function, color_type, n_components, compute_shader_param, 0, compute_shader_color, 0, sampler_name, sampling_code); } else { getShadowSamplingFunctionCall(sampling_function, color_type, n_components, compute_shader_param, 0, compute_shader_color, 0, sampler_name, sampling_code); } /* Preamble */ stream << shader_code_preamble << shader_precision << "/* Sampling compute shader */" << std::endl; /* uniform samplerType sampler */ stream << shader_uniform << "highp " << sampler_type_str << sampler_name << ";" << std::endl; /* uniform writeonly image2D image*/ stream << "layout(" << image_layout_str << ") " << shader_uniform << shader_writeonly << "highp " << image_type_str << image_name << ";" << std::endl; /* layout(shared) buffer attribute { type attribute_data[]; }; */ for (glw::GLuint i = 0; i < n_routine_attributes; ++i) { stream << compute_shader_layout_binding << routine_attribute_definitions[i].binding << compute_shader_buffer << routine_attribute_definitions[i].name << std::endl; stream << "{\n"; stream << " " << routine_attribute_definitions[i].type << " " << routine_attribute_definitions[i].name << "_data[];\n"; stream << "};\n"; } for (glw::GLuint i = 0; i < n_type_attributes; ++i) { stream << compute_shader_layout_binding << type_attribute_definitions[i].binding << compute_shader_buffer << type_attribute_definitions[i].name << std::endl; stream << "{\n"; stream << " " << type_attribute_definitions[i].type << " " << type_attribute_definitions[i].name << "_data[];\n"; stream << "};\n"; } /* layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in; */ stream << compute_shader_layout << std::endl; /* main + body */ stream << compute_shader_body; /* type cs_attribute = attribute_data[vertex_index] */ for (glw::GLuint i = 0; i < n_routine_attributes; ++i) { stream << " " << routine_attribute_definitions[i].type << compute_shader_param << routine_attribute_definitions[i].name << " = " << routine_attribute_definitions[i].name << "_data[vertex_index];" << std::endl; } for (glw::GLuint i = 0; i < n_type_attributes; ++i) { stream << " " << type_attribute_definitions[i].type << compute_shader_param << type_attribute_definitions[i].name << " = " << type_attribute_definitions[i].name << "_data[vertex_index];" << std::endl; } /* type color */ stream << std::endl << " " << color_type << compute_shader_color << ";" << std::endl; /* color = texture*/ stream << std::endl << sampling_code << std::endl; //stream << std::endl << compute_shader_color << " = vec4(cs_grad_x, 255.0);" << std::endl; /* imageStore */ stream << compute_shader_image_store; switch (n_components) { case 1: /* imageStore(image, image_coord, color.r);*/ if (sampler_type == Depth) { stream << "vec4(" << compute_shader_color << ")"; } else if (sampler_type == Stencil) { stream << "uvec4(" << compute_shader_color << ")"; } else { // unexpected case DE_ASSERT(false); } break; case 4: /* imageStore(image, image_coord, color);*/ stream << compute_shader_color; break; } stream << ");\n"; stream << "}\n" << std::endl; out_compute_shader_code = stream.str(); } /** Prepare code for sampling fragment shader * * @param sampler_type Type of sampler * @param sampling_function Type of sampling function * @param out_fragment_shader_code Storage for code **/ void TextureCubeMapArraySamplingTest::getSamplingFragmentShaderCode(const samplerType& sampler_type, const samplingFunction& sampling_function, std::string& out_fragment_shader_code) { const glw::GLchar* color_type = 0; const glw::GLchar* interpolation_type = 0; bool is_shadow_sampler = false; glw::GLuint n_components = 0; glw::GLuint n_routine_attributes = 0; glw::GLuint n_type_attributes = 0; const attributeDefinition* routine_attribute_definitions = 0; const attributeDefinition* type_attribute_definitions = 0; const glw::GLchar* sampler_type_str = 0; std::string sampling_code; std::stringstream stream; /* Get attributes for sampling function */ getAttributes(sampling_function, routine_attribute_definitions, n_routine_attributes); getAttributes(sampler_type, type_attribute_definitions, n_type_attributes); /* Get type for color variables */ getColorType(sampler_type, color_type, interpolation_type, sampler_type_str, n_components, is_shadow_sampler); /* Get sampling code */ if (false == is_shadow_sampler) { getSamplingFunctionCall(sampling_function, color_type, n_components, vertex_shader_output, 0, fragment_shader_output, 0, sampler_name, sampling_code); } else { getShadowSamplingFunctionCall(sampling_function, color_type, n_components, vertex_shader_output, 0, fragment_shader_output, 0, sampler_name, sampling_code); } /* Preamble */ stream << shader_code_preamble << shader_precision << "/* Sampling fragment shader */" << std::endl; /* uniform samplerType sampler */ stream << shader_uniform << "highp " << sampler_type_str << sampler_name << ";" << std::endl; stream << std::endl; /* in type attribute */ for (glw::GLuint i = 0; i < n_routine_attributes; ++i) { stream << shader_input << routine_attribute_definitions[i].type << vertex_shader_output << routine_attribute_definitions[i].name << ";" << std::endl; } for (glw::GLuint i = 0; i < n_type_attributes; ++i) { stream << shader_input << type_attribute_definitions[i].type << vertex_shader_output << type_attribute_definitions[i].name << ";" << std::endl; } stream << std::endl; /* layout(location = 0) out vec4 fs_out_color */ stream << shader_layout << shader_output << color_type << fragment_shader_output << ";" << std::endl; stream << std::endl; /* Body */ stream << fragment_shader_sampling_body_code; /* Sampling code */ stream << sampling_code; stream << "}" << std::endl << std::endl; /* Store result */ out_fragment_shader_code = stream.str(); } /** Prepare sampling code * * @param sampling_function Type of sampling function * @param color_type Type of color * @param n_components Number of components * @param attribute_name_prefix Prefix for attributes * @param attribute_index Index for attributes * @param color_variable_name Name of color variable * @param color_variable_index Index for color variable * @param sampler_name_p Name of sampler * @param out_code Result code **/ void TextureCubeMapArraySamplingTest::getSamplingFunctionCall(samplingFunction sampling_function, const glw::GLchar* color_type, glw::GLuint n_components, const glw::GLchar* attribute_name_prefix, const glw::GLchar* attribute_index, const glw::GLchar* color_variable_name, const glw::GLchar* color_variable_index, const glw::GLchar* sampler_name_p, std::string& out_code) { std::stringstream stream; switch (sampling_function) { case Texture: /* fs_in_color = texture(sampler, vs_out_texture_coordinates); */ stream << " " << var2str(0, color_variable_name, color_variable_index); stream << " = " << texture_func << "(" << sampler_name_p; stream << ", " << var2str(attribute_name_prefix, attribute_texture_coordinate, attribute_index); if (1 == n_components) { stream << ").x;" << std::endl; } else { stream << ");" << std::endl; } break; case TextureLod: /* fs_in_color = textureLod(sampler, vs_out_texture_coordinates, lod); */ stream << " " << var2str(0, color_variable_name, color_variable_index); stream << " = " << textureLod_func << "(" << sampler_name_p; stream << ", " << var2str(attribute_name_prefix, attribute_texture_coordinate, attribute_index) << ", " << var2str(attribute_name_prefix, attribute_lod, attribute_index); if (1 == n_components) { stream << ").x;" << std::endl; } else { stream << ");" << std::endl; } break; case TextureGrad: /* fs_in_color = textureGrad(sampler, vs_out_texture_coordinates, vs_out_grad_x, vs_out_grad_y); */ stream << " " << var2str(0, color_variable_name, color_variable_index); stream << " = " << textureGrad_func << "(" << sampler_name_p; stream << ", " << var2str(attribute_name_prefix, attribute_texture_coordinate, attribute_index) << ", " << var2str(attribute_name_prefix, attribute_grad_x, attribute_index) << ", " << var2str(attribute_name_prefix, attribute_grad_y, attribute_index); if (1 == n_components) { stream << ").x;" << std::endl; } else { stream << ");" << std::endl; } break; case TextureGather: if (4 == n_components) { /** * color_type component_0 = textureGather(sampler, vs_out_texture_coordinates, 0); * color_type component_1 = textureGather(sampler, vs_out_texture_coordinates, 1); * color_type component_2 = textureGather(sampler, vs_out_texture_coordinates, 2); * color_type component_3 = textureGather(sampler, vs_out_texture_coordinates, 3); * fs_in_color = color_type(component_0.r, component_1.g, component_2.b, component_3.a); **/ for (glw::GLuint i = 0; i < 4; ++i) { stream << " " << color_type << "component_" << i << " = " << textureGather_func << "(" << sampler_name_p; stream << ", " << var2str(attribute_name_prefix, attribute_texture_coordinate, attribute_index); stream << ", " << i << ");" << std::endl; } stream << " " << var2str(0, color_variable_name, color_variable_index); stream << " = " << color_type << "(component_0.r, " << "component_1.g, " << "component_2.b, " << "component_3.a);" << std::endl; } else { stream << " " << var2str(0, color_variable_name, color_variable_index); stream << " = " << textureGather_func << "(" << sampler_name_p; stream << ", " << var2str(attribute_name_prefix, attribute_texture_coordinate, attribute_index); stream << ").x;" << std::endl; } break; } out_code = stream.str(); } /** Prepare code for sampling geometry shader * * @param sampler_type Type of sampler * @param sampling_function Type of sampling function * @param out_geometry_shader_code Storage for code **/ void TextureCubeMapArraySamplingTest::getSamplingGeometryShaderCode(const samplerType& sampler_type, const samplingFunction& sampling_function, std::string& out_geometry_shader_code) { const glw::GLchar* color_type = 0; const glw::GLchar* interpolation_type = 0; bool is_shadow_sampler = false; glw::GLuint n_components = 0; glw::GLuint n_routine_attributes = 0; glw::GLuint n_type_attributes = 0; const attributeDefinition* routine_attribute_definitions = 0; const attributeDefinition* type_attribute_definitions = 0; const glw::GLchar* sampler_type_str = 0; std::string sampling_code; std::stringstream stream; /* Get attributes for sampling function */ getAttributes(sampling_function, routine_attribute_definitions, n_routine_attributes); getAttributes(sampler_type, type_attribute_definitions, n_type_attributes); /* Get type for color variables */ getColorType(sampler_type, color_type, interpolation_type, sampler_type_str, n_components, is_shadow_sampler); /* Get sampling code */ if (false == is_shadow_sampler) { getSamplingFunctionCall(sampling_function, color_type, n_components, vertex_shader_output, "0", fragment_shader_input, 0, sampler_name, sampling_code); } else { getShadowSamplingFunctionCall(sampling_function, color_type, n_components, vertex_shader_output, "0", fragment_shader_input, 0, sampler_name, sampling_code); } /* Preamble, extension : require */ stream << shader_code_preamble << geometry_shader_extension << shader_precision << std::endl << "/* Sampling geometry shader */" << std::endl; /* In out layout */ stream << geometry_shader_layout; /* uniform samplerType sampler */ stream << shader_uniform << "highp " << sampler_type_str << sampler_name << ";" << std::endl; stream << std::endl; /* in type attribute[]*/ for (glw::GLuint i = 0; i < n_routine_attributes; ++i) { stream << shader_input << routine_attribute_definitions[i].type << vertex_shader_output << routine_attribute_definitions[i].name << "[];" << std::endl; } for (glw::GLuint i = 0; i < n_type_attributes; ++i) { stream << shader_input << type_attribute_definitions[i].type << vertex_shader_output << type_attribute_definitions[i].name << "[];" << std::endl; } stream << std::endl; /* out vec4 fs_in_color */ stream << interpolation_type << shader_output << color_type << fragment_shader_input << ";" << std::endl; stream << std::endl; /* Body */ stream << geometry_shader_sampling_body_code; /* Sampling code */ stream << sampling_code; stream << geometry_shader_emit_vertex_code << std::endl; /* Store result */ out_geometry_shader_code = stream.str(); } /** Prepare code for sampling tesselation control shader * * @param sampler_type Type of sampler * @param sampling_function Type of sampling function * @param out_tesselation_control_shader_code Storage for code **/ void TextureCubeMapArraySamplingTest::getSamplingTesselationControlShaderCode( const samplerType& sampler_type, const samplingFunction& sampling_function, std::string& out_tesselation_control_shader_code) { const glw::GLchar* color_type = 0; const glw::GLchar* interpolation_type = 0; bool is_shadow_sampler = false; glw::GLuint n_components = 0; glw::GLuint n_routine_attributes = 0; glw::GLuint n_type_attributes = 0; const attributeDefinition* routine_attribute_definitions = 0; const attributeDefinition* type_attribute_definitions = 0; const glw::GLchar* sampler_type_str = 0; std::string sampling_code; std::stringstream stream; /* Get attributes for sampling function */ getAttributes(sampling_function, routine_attribute_definitions, n_routine_attributes); getAttributes(sampler_type, type_attribute_definitions, n_type_attributes); /* Get type for color variables */ getColorType(sampler_type, color_type, interpolation_type, sampler_type_str, n_components, is_shadow_sampler); /* Get sampling code */ if (false == is_shadow_sampler) { getSamplingFunctionCall(sampling_function, color_type, n_components, vertex_shader_output, "gl_InvocationID", tesselation_evaluation_shader_input, "gl_InvocationID", sampler_name, sampling_code); } else { getShadowSamplingFunctionCall(sampling_function, color_type, n_components, vertex_shader_output, "gl_InvocationID", tesselation_evaluation_shader_input, "gl_InvocationID", sampler_name, sampling_code); } /* Preamble, extension : require */ stream << shader_code_preamble << tesselation_shader_extension << shader_precision << std::endl << "/* Sampling tesselation control shader */" << std::endl; /* layout(vertices = 1) out */ stream << tesselation_control_shader_layout; /* uniform samplerType sampler */ stream << shader_uniform << "highp " << sampler_type_str << sampler_name << ";" << std::endl; stream << std::endl; /* in type attribute[]*/ for (glw::GLuint i = 0; i < n_routine_attributes; ++i) { stream << shader_input << routine_attribute_definitions[i].type << vertex_shader_output << routine_attribute_definitions[i].name << "[];" << std::endl; } for (glw::GLuint i = 0; i < n_type_attributes; ++i) { stream << shader_input << type_attribute_definitions[i].type << vertex_shader_output << type_attribute_definitions[i].name << "[];" << std::endl; } stream << std::endl; /* out vec4 tes_in_color */ stream << interpolation_type << shader_output << color_type << tesselation_evaluation_shader_input << "[];" << std::endl; stream << std::endl; /* Body */ stream << tesselation_control_shader_sampling_body_code; /* Sampling code */ stream << sampling_code; stream << "}" << std::endl << std::endl; /* Store result */ out_tesselation_control_shader_code = stream.str(); } /** Prepare code for sampling tesselation evaluation shader * * @param sampler_type Type of sampler * @param sampling_function Type of sampling function * @param out_tesselation_evaluation_shader_code Storage for code **/ void TextureCubeMapArraySamplingTest::getSamplingTesselationEvaluationShaderCode( const samplerType& sampler_type, const samplingFunction& sampling_function, std::string& out_tesselation_evaluation_shader_code) { const glw::GLchar* color_type = 0; const glw::GLchar* interpolation_type = 0; bool is_shadow_sampler = false; glw::GLuint n_components = 0; glw::GLuint n_routine_attributes = 0; glw::GLuint n_type_attributes = 0; const attributeDefinition* routine_attribute_definitions = 0; const attributeDefinition* type_attribute_definitions = 0; const glw::GLchar* sampler_type_str = 0; std::string sampling_code; std::stringstream stream; const glw::GLchar* prev_stage_output = (glu::isContextTypeES(m_context.getRenderContext().getType())) ? tesselation_control_shader_output : vertex_shader_output; /* Get attributes for sampling function */ getAttributes(sampling_function, routine_attribute_definitions, n_routine_attributes); getAttributes(sampler_type, type_attribute_definitions, n_type_attributes); /* Get type for color variables */ getColorType(sampler_type, color_type, interpolation_type, sampler_type_str, n_components, is_shadow_sampler); /* Get sampling code */ if (false == is_shadow_sampler) { getSamplingFunctionCall(sampling_function, color_type, n_components, prev_stage_output, "0", fragment_shader_input, 0, sampler_name, sampling_code); } else { getShadowSamplingFunctionCall(sampling_function, color_type, n_components, prev_stage_output, "0", fragment_shader_input, 0, sampler_name, sampling_code); } /* Preamble, extension : require */ stream << shader_code_preamble << tesselation_shader_extension << shader_precision << std::endl << "/* Sampling tesselation evaluation shader */" << std::endl; /* layout(point_mode) in; */ stream << tesselation_evaluation_shader_layout; /* uniform samplerType sampler */ stream << shader_uniform << "highp " << sampler_type_str << sampler_name << ";" << std::endl; stream << std::endl; /* in type attribute[]*/ for (glw::GLuint i = 0; i < n_routine_attributes; ++i) { stream << shader_input << routine_attribute_definitions[i].type << prev_stage_output << routine_attribute_definitions[i].name << "[];" << std::endl; } for (glw::GLuint i = 0; i < n_type_attributes; ++i) { stream << shader_input << type_attribute_definitions[i].type << prev_stage_output << type_attribute_definitions[i].name << "[];" << std::endl; } stream << std::endl; /* out vec4 tes_in_color */ stream << interpolation_type << shader_output << color_type << fragment_shader_input << ";" << std::endl; stream << std::endl; /* Body */ stream << tesselation_evaluation_shader_sampling_body_code; /* Sampling code */ stream << sampling_code; stream << "}" << std::endl << std::endl; /* Store result */ out_tesselation_evaluation_shader_code = stream.str(); } /** Prepare code for sampling vertex shader * * @param sampler_type Type of sampler * @param sampling_function Type of sampling function * @param out_vertex_shader_code Storage for code **/ void TextureCubeMapArraySamplingTest::getSamplingVertexShaderCode(const samplerType& sampler_type, const samplingFunction& sampling_function, std::string& out_vertex_shader_code) { const glw::GLchar* color_type = 0; const glw::GLchar* interpolation_type = 0; bool is_shadow_sampler = false; glw::GLuint n_components = 0; glw::GLuint n_routine_attributes = 0; glw::GLuint n_type_attributes = 0; const attributeDefinition* routine_attribute_definitions = 0; const attributeDefinition* type_attribute_definitions = 0; const glw::GLchar* sampler_type_str = 0; std::string sampling_code; std::stringstream stream; /* Get attributes for sampling function */ getAttributes(sampling_function, routine_attribute_definitions, n_routine_attributes); getAttributes(sampler_type, type_attribute_definitions, n_type_attributes); /* Get type for color variables */ getColorType(sampler_type, color_type, interpolation_type, sampler_type_str, n_components, is_shadow_sampler); /* Get sampling code */ if (false == is_shadow_sampler) { getSamplingFunctionCall(sampling_function, color_type, n_components, vertex_shader_input, 0, fragment_shader_input, 0, sampler_name, sampling_code); } else { getShadowSamplingFunctionCall(sampling_function, color_type, n_components, vertex_shader_input, 0, fragment_shader_input, 0, sampler_name, sampling_code); } /* Preamble */ stream << shader_code_preamble << shader_precision << "/* Sampling vertex shader */" << std::endl; /* uniform samplerType sampler */ stream << shader_uniform << "highp " << sampler_type_str << sampler_name << ";" << std::endl; stream << std::endl; /* in vec4 vs_in_position */ stream << shader_input << type_vec4 << vertex_shader_input << vertex_shader_position << ";" << std::endl; /* in type attribute */ for (glw::GLuint i = 0; i < n_routine_attributes; ++i) { stream << shader_input << routine_attribute_definitions[i].type << vertex_shader_input << routine_attribute_definitions[i].name << ";" << std::endl; } for (glw::GLuint i = 0; i < n_type_attributes; ++i) { stream << shader_input << type_attribute_definitions[i].type << vertex_shader_input << type_attribute_definitions[i].name << ";" << std::endl; } stream << std::endl; /* out vec4 fs_in_color; */ stream << interpolation_type << shader_output << color_type << fragment_shader_input << ";" << std::endl; stream << std::endl; /* Body */ stream << vertex_shader_body_code; /* Sampling code */ stream << sampling_code; stream << "}" << std::endl << std::endl; /* Store result */ out_vertex_shader_code = stream.str(); } /** Prepare shadow sampling code * * @param sampling_function Type of sampling function * @param color_type Type of color * @param n_components Number of components * @param attribute_name_prefix Prefix for attributes * @param attribute_index Index for attributes * @param color_variable_name Name of color variable * @param color_variable_index Index for color variable * @param sampler_name_p Name of sampler * @param out_code Result code **/ void TextureCubeMapArraySamplingTest::getShadowSamplingFunctionCall( samplingFunction sampling_function, const glw::GLchar* color_type, glw::GLuint n_components, const glw::GLchar* attribute_name_prefix, const glw::GLchar* attribute_index, const glw::GLchar* color_variable_name, const glw::GLchar* color_variable_index, const glw::GLchar* sampler_name_p, std::string& out_code) { std::stringstream stream; switch (sampling_function) { case Texture: /* fs_in_color = texture(sampler, vs_out_texture_coordinates); */ stream << " " << var2str(0, color_variable_name, color_variable_index); stream << " = " << texture_func << "(" << sampler_name_p; stream << ", " << var2str(attribute_name_prefix, attribute_texture_coordinate, attribute_index) << ", " << var2str(attribute_name_prefix, attribute_refZ, attribute_index); stream << ");" << std::endl; break; case TextureLod: /* fs_in_color = textureLod(sampler, vs_out_texture_coordinates, lod); */ stream << " " << var2str(0, color_variable_name, color_variable_index); stream << " = " << textureLod_func << "(" << sampler_name_p; stream << ", " << var2str(attribute_name_prefix, attribute_texture_coordinate, attribute_index) << ", " << var2str(attribute_name_prefix, attribute_lod, attribute_index) << ", " << var2str(attribute_name_prefix, attribute_refZ, attribute_index); stream << ");" << std::endl; break; case TextureGrad: /* fs_in_color = textureGrad(sampler, vs_out_texture_coordinates, vs_out_grad_x, vs_out_grad_y); */ throw tcu::NotSupportedError("textureGrad operation is not available for samplerCubeArrayShadow", "", __FILE__, __LINE__); case TextureGather: if (4 == n_components) { /** * color_type component_0 = textureGather(sampler, vs_out_texture_coordinates, 0); * color_type component_1 = textureGather(sampler, vs_out_texture_coordinates, 1); * color_type component_2 = textureGather(sampler, vs_out_texture_coordinates, 2); * color_type component_3 = textureGather(sampler, vs_out_texture_coordinates, 3); * fs_in_color = color_type(component_0.r, component_1.g, component_2.b, component_3.a); **/ for (glw::GLuint i = 0; i < 4; ++i) { stream << " " << color_type << "component_" << i; stream << " = " << textureGather_func << "(" << sampler_name_p; stream << ", " << var2str(attribute_name_prefix, attribute_texture_coordinate, attribute_index) << ", " << var2str(attribute_name_prefix, attribute_refZ, attribute_index); stream << ");" << std::endl; } stream << " " << var2str(0, color_variable_name, color_variable_index); stream << " = " << color_type << "(component_0.r, " << "component_1.g, " << "component_2.b, " << "component_3.a);" << std::endl; } else { stream << " " << var2str(0, color_variable_name, color_variable_index); stream << " = " << textureGather_func << "(" << sampler_name_p; stream << ", " << var2str(attribute_name_prefix, attribute_texture_coordinate, attribute_index) << ", " << var2str(attribute_name_prefix, attribute_refZ, attribute_index); stream << ").x;" << std::endl; } break; } out_code = stream.str(); } /** Check if combination of sampler type and sampling function is supported * * @param sampler_type Type of sampler * @param sampling_function Type of sampling function * * @return true When supported * false When not supported **/ bool TextureCubeMapArraySamplingTest::isSamplerSupportedByFunction(const samplerType sampler_type, const samplingFunction sampling_function) { if ((Depth == sampler_type) && ((TextureLod == sampling_function) || (TextureGrad == sampling_function))) { return false; } return true; } /** Executes the test. * Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise. * @return STOP if the test has finished, CONTINUE to indicate iterate should be called once again. * Note the function throws exception should an error occur! **/ tcu::TestNode::IterateResult TextureCubeMapArraySamplingTest::iterate() { #if TEXTURECUBEMAPARRAYSAMPLINGTEST_DUMP_TEXTURES_FOR_COMPRESSION for (resolutionsVectorType::iterator resolution = m_compressed_resolutions.begin(), end_resolution = m_compressed_resolutions.end(); end_resolution != resolution; ++resolution) { prepareDumpForTextureCompression(*resolution); } m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); return STOP; #else /* TEXTURECUBEMAPARRAYSAMPLINGTEST_DUMP_TEXTURES_FOR_COMPRESSION */ if (false == m_is_texture_cube_map_array_supported) { throw tcu::NotSupportedError(TEXTURE_CUBE_MAP_ARRAY_EXTENSION_NOT_SUPPORTED, "", __FILE__, __LINE__); } // These shader stages are always supported m_shaders.push_back(shaderConfiguration(Compute, GL_POINTS, "Compute")); m_shaders.push_back(shaderConfiguration(Fragment, GL_POINTS, "Fragment")); m_shaders.push_back(shaderConfiguration(Vertex, GL_POINTS, "Vertex")); // Check if geometry shader is supported if (true == m_is_geometry_shader_extension_supported) { m_shaders.push_back(shaderConfiguration(Geometry, GL_POINTS, "Geometry")); } // Check if tesselation shaders are supported if (true == m_is_tessellation_shader_supported) { m_shaders.push_back(shaderConfiguration(Tesselation_Control, m_glExtTokens.PATCHES, "Tesselation_Control")); m_shaders.push_back( shaderConfiguration(Tesselation_Evaluation, m_glExtTokens.PATCHES, "Tesselation_Evaluation")); } /* GL functions */ const glw::Functions& gl = m_context.getRenderContext().getFunctions(); gl.genFramebuffers(1, &m_framebuffer_object_id); if (true == m_is_tessellation_shader_supported) { gl.patchParameteri(m_glExtTokens.PATCH_VERTICES, 1); } gl.pixelStorei(GL_PACK_ALIGNMENT, 1); gl.pixelStorei(GL_UNPACK_ALIGNMENT, 1); testFormats(m_formats, m_resolutions); testFormats(m_compressed_formats, m_compressed_resolutions); if (true == m_is_tessellation_shader_supported) { gl.patchParameteri(m_glExtTokens.PATCH_VERTICES, 3); } gl.pixelStorei(GL_PACK_ALIGNMENT, 4); gl.pixelStorei(GL_UNPACK_ALIGNMENT, 4); gl.deleteFramebuffers(1, &m_framebuffer_object_id); m_framebuffer_object_id = 0; m_testCtx.getLog() << tcu::TestLog::Section("Summary", ""); if ((0 != failed_cases) || (0 != invalid_type_cases)) { m_testCtx.getLog() << tcu::TestLog::Message << "Test failed! Number of found errors: " << failed_cases << tcu::TestLog::EndMessage; m_testCtx.getLog() << tcu::TestLog::Message << "Invalid shaders: " << invalid_shaders << tcu::TestLog::EndMessage; m_testCtx.getLog() << tcu::TestLog::Message << "Invalid programs: " << invalid_programs << tcu::TestLog::EndMessage; m_testCtx.getLog() << tcu::TestLog::Message << "glGetActiveUniform or glGetProgramResourceiv reported invalid type: " << invalid_type_cases << tcu::TestLog::EndMessage; m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); } else { m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); } m_testCtx.getLog() << tcu::TestLog::Message << "Number of executed test cases: " << tested_cases << tcu::TestLog::EndMessage; m_testCtx.getLog() << tcu::TestLog::Message << "Total shaders: " << compiled_shaders << tcu::TestLog::EndMessage; m_testCtx.getLog() << tcu::TestLog::Message << "Total programs: " << linked_programs << tcu::TestLog::EndMessage; m_testCtx.getLog() << tcu::TestLog::EndSection; return STOP; #endif /* TEXTURECUBEMAPARRAYSAMPLINGTEST_DUMP_TEXTURES_FOR_COMPRESSION */ } /** Link program * * @param info Program information **/ void TextureCubeMapArraySamplingTest::link(programDefinition& info) { linked_programs += 1; /* Not supported format */ if (programDefinition::m_invalid_program_object_id == info.getProgramId()) { return; } if (false == info.link()) { invalid_programs += 1; logLinkingLog(info); logProgram(info); } } /** Logs compilation log * * @param info Shader information **/ void TextureCubeMapArraySamplingTest::logCompilationLog(const shaderDefinition& info) { std::string info_log = getCompilationInfoLog(info.getShaderId()); m_testCtx.getLog() << tcu::TestLog::Message << "Shader compilation failure:\n\n" << info_log << tcu::TestLog::EndMessage; m_testCtx.getLog() << tcu::TestLog::Message << "Shader source:\n\n" << info.getSource() << tcu::TestLog::EndMessage; } /** Logs linkig log * * @param info Program information **/ void TextureCubeMapArraySamplingTest::logLinkingLog(const programDefinition& info) { glw::GLuint program_object_id = info.getProgramId(); if (programDefinition::m_invalid_program_object_id == program_object_id) { return; } std::string info_log = getLinkingInfoLog(program_object_id); m_testCtx.getLog() << tcu::TestLog::Message << "Program linking failure:\n\n" << info_log << tcu::TestLog::EndMessage; } /** Logs shaders used by program * * @param info Program information **/ void TextureCubeMapArraySamplingTest::logProgram(const programDefinition& info) { glw::GLuint program_object_id = info.getProgramId(); if (programDefinition::m_invalid_program_object_id == program_object_id) { return; } tcu::MessageBuilder message = m_testCtx.getLog() << tcu::TestLog::Message; message << "Program id: " << program_object_id; const shaderDefinition* compute = info.getShader(Compute); const shaderDefinition* fragment = info.getShader(Fragment); const shaderDefinition* geometry = info.getShader(Geometry); const shaderDefinition* tcs = info.getShader(Tesselation_Control); const shaderDefinition* tes = info.getShader(Tesselation_Evaluation); const shaderDefinition* vertex = info.getShader(Vertex); if (0 != compute) { message << "\nCompute shader:\n" << compute->getSource(); } if (0 != vertex) { message << "\nVertex shader:\n" << vertex->getSource(); } if (0 != geometry) { message << "\nGeometry shader:\n" << geometry->getSource(); } if (0 != tcs) { message << "\nTCS shader:\n" << tcs->getSource(); } if (0 != tes) { message << "\nTES shader:\n" << tes->getSource(); } if (0 != fragment) { message << "\nFragment shader:\n" << fragment->getSource(); } message << tcu::TestLog::EndMessage; } /** Prepare compressed textures * * @param texture Texture information * @param format Texture format * @param resolution Texture resolution * @param mutability Texture mutability **/ void TextureCubeMapArraySamplingTest::prepareCompresedTexture(const textureDefinition& texture, const formatDefinition& format, const resolutionDefinition& resolution, bool mutability) { static const glw::GLint n_faces = 6; const glw::GLint array_length = resolution.m_depth / n_faces; const glw::GLint n_mipmap_levels = getMipmapLevelCount(resolution.m_width, resolution.m_height); glw::GLsizei texture_width = 0; glw::GLsizei texture_height = 0; /* GL functions */ const glw::Functions& gl = m_context.getRenderContext().getFunctions(); texture.bind(GL_TEXTURE_CUBE_MAP_ARRAY); if (false == mutability) { gl.texStorage3D(GL_TEXTURE_CUBE_MAP_ARRAY, n_mipmap_levels, format.m_source.m_internal_format, resolution.m_width, resolution.m_height, resolution.m_depth); GLU_EXPECT_NO_ERROR(gl.getError(), "texStorage3D"); texture_width = resolution.m_width; texture_height = resolution.m_height; for (glw::GLint mipmap_level = 0; mipmap_level < n_mipmap_levels; ++mipmap_level) { const glw::GLubyte* image_data = 0; glw::GLuint image_size = 0; getCompressedTexture(resolution.m_width, resolution.m_height, array_length, mipmap_level, image_data, image_size); if (0 == image_data) { throw tcu::InternalError("Invalid compressed texture", "", __FILE__, __LINE__); } gl.compressedTexSubImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, mipmap_level, 0, /* x_offset */ 0, /* y offset */ 0, /* z offset */ texture_width, texture_height, resolution.m_depth, format.m_source.m_internal_format, image_size, image_data); GLU_EXPECT_NO_ERROR(gl.getError(), "compressedTexSubImage3D"); texture_width = de::max(1, texture_width / 2); texture_height = de::max(1, texture_height / 2); } } else { texture_width = resolution.m_width; texture_height = resolution.m_height; for (glw::GLint mipmap_level = 0; mipmap_level < n_mipmap_levels; ++mipmap_level) { const glw::GLubyte* image_data = 0; glw::GLuint image_size = 0; getCompressedTexture(resolution.m_width, resolution.m_height, array_length, mipmap_level, image_data, image_size); if (0 == image_data) { throw tcu::InternalError("Invalid compressed texture", "", __FILE__, __LINE__); } gl.compressedTexImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, mipmap_level, format.m_source.m_internal_format, texture_width, texture_height, resolution.m_depth, 0 /* border */, image_size, image_data); GLU_EXPECT_NO_ERROR(gl.getError(), "compressedTexImage3D"); texture_width = de::max(1, texture_width / 2); texture_height = de::max(1, texture_height / 2); } } } /** Prepare not comporessed textures * * @param texture Texture information * @param format Texture format * @param resolution Texture resolution * @param mutability Texture mutability **/ void TextureCubeMapArraySamplingTest::prepareTexture(const textureDefinition& texture, const formatDefinition& texture_format, const resolutionDefinition& resolution, bool mutability) { static const glw::GLint n_faces = 6; const glw::GLint n_elements = resolution.m_depth / n_faces; const glw::GLint n_mipmap_levels = getMipmapLevelCount(resolution.m_width, resolution.m_height); glw::GLsizei texture_width = 0; glw::GLsizei texture_height = 0; /* GL functions */ const glw::Functions& gl = m_context.getRenderContext().getFunctions(); texture.bind(GL_TEXTURE_CUBE_MAP_ARRAY); if (false == mutability) { gl.texStorage3D(GL_TEXTURE_CUBE_MAP_ARRAY, n_mipmap_levels, texture_format.m_source.m_internal_format, resolution.m_width, resolution.m_height, resolution.m_depth); } else { texture_width = resolution.m_width; texture_height = resolution.m_height; for (glw::GLint mipmap_level = 0; mipmap_level < n_mipmap_levels; ++mipmap_level) { gl.texImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, mipmap_level, texture_format.m_source.m_internal_format, texture_width, texture_height, resolution.m_depth, 0 /* border */, texture_format.m_source.m_format, texture_format.m_source.m_type, 0 /* data */); texture_width = de::max(1, texture_width / 2); texture_height = de::max(1, texture_height / 2); } } GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to allocate storage for texture"); texture_width = resolution.m_width; texture_height = resolution.m_height; for (glw::GLint mipmap_level = 0; mipmap_level < n_mipmap_levels; ++mipmap_level) { for (glw::GLint element_index = 0; element_index < n_elements; ++element_index) { for (glw::GLint face = 0; face < n_faces; ++face) { prepareTextureFace(gl, face, element_index, mipmap_level, n_elements, n_mipmap_levels, texture_format.m_source.m_format, texture_format.m_source.m_type, texture_width, texture_height); } } texture_width = de::max(1, texture_width / 2); texture_height = de::max(1, texture_height / 2); } // not texture filterable formats if ((texture_format.m_source.m_internal_format == GL_RGBA32UI) || (texture_format.m_source.m_internal_format == GL_RGBA32I) || (texture_format.m_source.m_internal_format == GL_STENCIL_INDEX8) || (texture_format.m_source.m_internal_format == GL_DEPTH_COMPONENT32F)) { gl.texParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST); gl.texParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST); } } /** Setup shader storabe buffer for use with compute shader * * @param attribute Attribute information * @param buffers Collection of buffers * @param program_id Program id **/ void TextureCubeMapArraySamplingTest::setupSharedStorageBuffer(const attributeDefinition& attribute, const bufferCollection& buffers, glw::GLuint program_id) { (void)program_id; /* GL functions */ const glw::Functions& gl = m_context.getRenderContext().getFunctions(); std::string attribute_name = attribute.name; const bufferDefinition* buffer = 0; switch (attribute.attribute_id) { case Position: buffer = &buffers.postion; break; case TextureCoordinates: buffer = &buffers.texture_coordinate; break; case TextureCoordinatesForGather: buffer = &buffers.texture_coordinate_for_gather; break; case Lod: buffer = &buffers.lod; break; case GradX: buffer = &buffers.grad_x; break; case GradY: buffer = &buffers.grad_y; break; case RefZ: buffer = &buffers.refZ; break; } buffer->bind(GL_SHADER_STORAGE_BUFFER, attribute.binding); GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to setup shared storage block"); } /** Setup shader storabe buffers for use with compute shader * * @param format Texture format * @param sampling_function Sampling routine * @param buffers Collection of buffers * @param program_id Program id **/ void TextureCubeMapArraySamplingTest::setupSharedStorageBuffers(const formatDefinition& format, const samplingFunction& sampling_function, const bufferCollection& buffers, glw::GLuint program_id) { const attributeDefinition* format_attributes = 0; glw::GLuint n_format_attributes = 0; glw::GLuint n_routine_attributes = 0; const attributeDefinition* routine_attributes = 0; getAttributes(format.m_sampler_type, format_attributes, n_format_attributes); getAttributes(sampling_function, routine_attributes, n_routine_attributes); for (glw::GLuint i = 0; i < n_routine_attributes; ++i) { setupSharedStorageBuffer(routine_attributes[i], buffers, program_id); } for (glw::GLuint i = 0; i < n_format_attributes; ++i) { setupSharedStorageBuffer(format_attributes[i], buffers, program_id); } } /** Execute tests for set of formats and resolutions * * @param formats Set of texture formats * @param resolutions Set of texture resolutions **/ void TextureCubeMapArraySamplingTest::testFormats(formatsVectorType& formats, resolutionsVectorType& resolutions) { /* GL functions */ const glw::Functions& gl = m_context.getRenderContext().getFunctions(); for (formatsVectorType::iterator format = formats.begin(), end_format = formats.end(); end_format != format; ++format) { shaderCollectionForTextureFormat shader_collection; programCollectionForFormat program_collection; shader_collection.init(gl, *format, m_functions, *this); bool isContextES = (glu::isContextTypeES(m_context.getRenderContext().getType())); program_collection.init(gl, shader_collection, *this, isContextES); for (mutablitiesVectorType::iterator mutability = m_mutabilities.begin(), end_muatbility = m_mutabilities.end(); end_muatbility != mutability; ++mutability) { for (resolutionsVectorType::iterator resolution = resolutions.begin(), end_resolution = resolutions.end(); end_resolution != resolution; ++resolution) { textureDefinition texture; texture.init(gl); try { if (false == format->m_source.m_is_compressed) { prepareTexture(texture, *format, *resolution, *mutability); } else { prepareCompresedTexture(texture, *format, *resolution, *mutability); } } #if TEXTURECUBEMAPARRAYSAMPLINGTEST_IS_FAIL_LOG catch (std::exception& exc) { m_testCtx.getLog() << tcu::TestLog::Section("Exception during texture creation", exc.what()); m_testCtx.getLog() << tcu::TestLog::Message << "Format: " << format->m_name << ", Mutability: " << *mutability << ", W: " << resolution->m_width << ", H: " << resolution->m_height << tcu::TestLog::EndMessage; m_testCtx.getLog() << tcu::TestLog::EndSection; #else /* TEXTURECUBEMAPARRAYSAMPLINGTEST_IS_FAIL_LOG */ catch (...) { #endif /* TEXTURECUBEMAPARRAYSAMPLINGTEST_IS_FAIL_LOG */ continue; } testTexture(*format, *mutability, *resolution, texture, program_collection); } } } } /** Execute tests for given texture * * @param format Texture format * @param mutability Texture mutabilibty * @param resolution Texture resolution * @param texture Textue information * @param shader_collection Collection of shaders * @param program_collection Collection of programs **/ void TextureCubeMapArraySamplingTest::testTexture(const formatDefinition& format, bool mutability, const resolutionDefinition& resolution, textureDefinition& texture, programCollectionForFormat& program_collection) { std::vector result_image; const glw::GLuint image_width = 3 * resolution.m_depth; const glw::GLuint image_height = 3; const glw::GLuint estimated_image_size = static_cast(image_width * image_height * 4 /* components */ * sizeof(glw::GLuint)); result_image.resize(estimated_image_size); /* GL functions */ const glw::Functions& gl = m_context.getRenderContext().getFunctions(); bufferCollection buffers; buffers.init(gl, format, resolution); for (samplingFunctionsVectorType::iterator function = m_functions.begin(), end_function = m_functions.end(); end_function != function; ++function) { for (shadersVectorType::iterator shader = m_shaders.begin(), end_shader = m_shaders.end(); end_shader != shader; ++shader) { const programCollectionForFunction* programs = 0; const programDefinition* program = 0; glw::GLuint program_object_id = programDefinition::m_invalid_program_object_id; textureDefinition color_attachment; programs = program_collection.getPrograms(function->m_function); program = programs->getProgram(shader->m_type); program_object_id = program->getProgramId(); if (programDefinition::m_invalid_program_object_id == program_object_id) { continue; } tested_cases += 1; color_attachment.init(gl); if (Compute != shader->m_type) { setupFramebufferWithTextureAsAttachment(m_framebuffer_object_id, color_attachment.getTextureId(), format.m_destination.m_internal_format, image_width, image_height); } else { color_attachment.bind(GL_TEXTURE_2D); gl.texStorage2D(GL_TEXTURE_2D, 1, format.m_destination.m_internal_format, image_width, image_height); gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); color_attachment.setupImage(0, format.m_destination.m_internal_format); } try { gl.bindFramebuffer(GL_READ_FRAMEBUFFER, 0); gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, m_framebuffer_object_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffer"); gl.useProgram(program_object_id); GLU_EXPECT_NO_ERROR(gl.getError(), "Failed glUseProgram call."); texture.setupSampler(0, sampler_name, program_object_id, format.m_sampler_type == Depth); if (Compute != shader->m_type) { vertexArrayObjectDefinition vao; vao.init(gl, format, function->m_function, buffers, program_object_id); draw(program_object_id, shader->m_primitive_type, image_width * image_height, format.m_destination.m_internal_format); } else { setupSharedStorageBuffers(format, function->m_function, buffers, program_object_id); dispatch(program_object_id, image_width, image_height); } gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); gl.bindFramebuffer(GL_READ_FRAMEBUFFER, m_framebuffer_object_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffer"); color_attachment.bind(GL_TEXTURE_2D); gl.framebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color_attachment.getTextureId(), 0); GLU_EXPECT_NO_ERROR(gl.getError(), "framebufferTexture2D"); gl.viewport(0, 0, 3 * resolution.m_depth, 3); GLU_EXPECT_NO_ERROR(gl.getError(), "viewport"); gl.memoryBarrier(GL_PIXEL_BUFFER_BARRIER_BIT); gl.readPixels(0 /* x */, 0 /* y */, image_width, image_height, format.m_destination.m_format, format.m_destination.m_type, &result_image[0]); GLU_EXPECT_NO_ERROR(gl.getError(), "glReadPixels"); /* GL_DEPTH_COMPONENT is nominally R32F, however R32F is not renderable, so we convert to * RGBA8 instead. Convert the red channel back to R32F for comparison. */ if (format.m_source.m_format == GL_DEPTH_COMPONENT) { unsigned char* p = (unsigned char*)&result_image[0]; float* f = (float*)&result_image[0]; for (unsigned int i = 0; i < image_width * image_height; i++) { *f = (float)p[0] / 255.0f; p += 4; f += 1; } } /* GL_STENCIL_INDEX is nominally one-channel format, however ReadPixels supports only RGBA formats. * Convert the RGBA image to R for comparison. */ if (format.m_source.m_format == GL_STENCIL_INDEX && format.m_destination.m_format == GL_RGBA_INTEGER) { unsigned int* pRGBA = (unsigned int*)&result_image[0]; unsigned int* pR = (unsigned int*)&result_image[0]; for (unsigned int i = 0; i < image_width * image_height; i++) { *pR = pRGBA[0]; pR += 1; pRGBA += 4; } } glw::GLuint get_type_api_status = checkUniformAndResourceApi(program_object_id, sampler_name, format.m_sampler_type); bool verification_result = verifyResult(format, resolution, function->m_function, &result_image[0]); if ((true == verification_result) && (0 == get_type_api_status)) { #if TEXTURECUBEMAPARRAYSAMPLINGTEST_IS_PASS_LOG m_testCtx.getLog() << tcu::TestLog::Message << "Valid result. " << " Format: " << format.m_name << ", Mutability: " << mutability << ", Sampling shader: " << shader->m_name << ", Sampling function: " << function->m_name << ", W: " << resolution.m_width << ", H: " << resolution.m_height << tcu::TestLog::EndMessage; #if TEXTURECUBEMAPARRAYSAMPLINGTEST_IS_PASS_PROGRAM_LOG logProgram(*program); #endif /* TEXTURECUBEMAPARRAYSAMPLINGTEST_IS_PASS_PROGRAM_LOG */ #endif /* TEXTURECUBEMAPARRAYSAMPLINGTEST_IS_PASS_LOG */ } else { #if TEXTURECUBEMAPARRAYSAMPLINGTEST_IS_FAIL_LOG m_testCtx.getLog() << tcu::TestLog::Section("Invalid result", ""); if (true != verification_result) { m_testCtx.getLog() << tcu::TestLog::Message << "Invalid image" << tcu::TestLog::EndMessage; } if (0 != get_type_api_status) { if (0 != (m_get_type_api_status_uniform & get_type_api_status)) { m_testCtx.getLog() << tcu::TestLog::Message << "glGetActiveUniform returns wrong type for sampler" << tcu::TestLog::EndMessage; } if (0 != (m_get_type_api_status_program_resource & get_type_api_status)) { m_testCtx.getLog() << tcu::TestLog::Message << "glGetProgramResourceiv returns wrong type for sampler" << tcu::TestLog::EndMessage; } } m_testCtx.getLog() << tcu::TestLog::Message << "Format: " << format.m_name << ", Mutability: " << mutability << ", Sampling shader: " << shader->m_name << ", Sampling function: " << function->m_name << ", W: " << resolution.m_width << ", H: " << resolution.m_height << tcu::TestLog::EndMessage; #if TEXTURECUBEMAPARRAYSAMPLINGTEST_IS_FAIL_PROGRAM_LOG logProgram(*program); #endif /* TEXTURECUBEMAPARRAYSAMPLINGTEST_IS_FAIL_PROGRAM_LOG */ m_testCtx.getLog() << tcu::TestLog::EndSection; #endif /* TEXTURECUBEMAPARRAYSAMPLINGTEST_IS_FAIL_LOG */ if (false == verification_result) { failed_cases += 1; } if (0 != get_type_api_status) { invalid_type_cases += 1; } } } #if TEXTURECUBEMAPARRAYSAMPLINGTEST_IS_FAIL_LOG catch (std::exception& exc) { m_testCtx.getLog() << tcu::TestLog::Section("Exception during test execution", exc.what()); m_testCtx.getLog() << tcu::TestLog::Message << "Format: " << format.m_name << ", Mutability: " << mutability << ", W: " << resolution.m_width << ", H: " << resolution.m_height << tcu::TestLog::EndMessage; #if TEXTURECUBEMAPARRAYSAMPLINGTEST_IS_FAIL_PROGRAM_LOG logProgram(*program); #endif /* TEXTURECUBEMAPARRAYSAMPLINGTEST_IS_FAIL_PROGRAM_LOG */ m_testCtx.getLog() << tcu::TestLog::EndSection; #else /* TEXTURECUBEMAPARRAYSAMPLINGTEST_IS_FAIL_LOG */ catch (...) { #endif /* TEXTURECUBEMAPARRAYSAMPLINGTEST_IS_FAIL_LOG */ failed_cases += 1; } //run() } } } /** Verify that rendered image match expectations * * @param format Texture format * @param resolution Texture resolution * @param shader_type Shader type * @param sampling_function Type of sampling function * @param data Image data **/ bool TextureCubeMapArraySamplingTest::verifyResult(const formatDefinition& format, const resolutionDefinition& resolution, const samplingFunction sampling_function, unsigned char* data) { componentProvider component_provider = { NULL, NULL, NULL, NULL, NULL, NULL, NULL }; switch (sampling_function) { case Texture: case TextureGather: component_provider.getColorFloatComponents = getExpectedColorFloatComponentsForTexture; component_provider.getColorUByteComponents = getExpectedColorIntComponentsForTexture; component_provider.getColorUintComponents = getExpectedColorIntComponentsForTexture; component_provider.getColorIntComponents = getExpectedColorIntComponentsForTexture; component_provider.getDepthComponents = getExpectedDepthComponentsForTexture; component_provider.getStencilComponents = getExpectedStencilComponentsForTexture; component_provider.getCompressedComponents = getExpectedCompressedComponentsForTexture; break; case TextureLod: case TextureGrad: component_provider.getColorFloatComponents = getExpectedColorFloatComponentsForTextureLod; component_provider.getColorUByteComponents = getExpectedColorIntComponentsForTextureLod; component_provider.getColorUintComponents = getExpectedColorIntComponentsForTextureLod; component_provider.getColorIntComponents = getExpectedColorIntComponentsForTextureLod; component_provider.getDepthComponents = getExpectedDepthComponentsForTextureLod; component_provider.getStencilComponents = getExpectedStencilComponentsForTextureLod; component_provider.getCompressedComponents = getExpectedCompressedComponentsForTextureLod; break; } return verifyResultHelper(format, resolution, component_provider, data); } /** Verify that rendered image match expectations * * @param format Texture format * @param resolution Texture resolution * @param shader_type Shader type * @param sampling_function Type of sampling function * @param data Image data **/ bool TextureCubeMapArraySamplingTest::verifyResultHelper(const formatDefinition& format, const resolutionDefinition& resolution, const componentProvider& component_provider, unsigned char* data) { const glw::GLuint n_mipmap_levels = getMipmapLevelCount(resolution.m_width, resolution.m_height); const glw::GLuint n_layers = resolution.m_depth / 6; bool result = false; if (GL_RGBA == format.m_source.m_format) { if (GL_UNSIGNED_BYTE == format.m_source.m_type) { result = verifyResultImage(n_mipmap_levels, n_layers, component_provider.getColorUByteComponents, data); } else if (GL_FLOAT == format.m_source.m_type) { result = verifyResultImage(n_mipmap_levels, n_layers, component_provider.getColorFloatComponents, data); } else if (GL_COMPRESSED_RGBA8_ETC2_EAC == format.m_source.m_type) { result = verifyResultImage(n_mipmap_levels, n_layers, component_provider.getCompressedComponents, data); } } else if (GL_RGBA_INTEGER == format.m_source.m_format) { if (GL_UNSIGNED_INT == format.m_source.m_type) { result = verifyResultImage(n_mipmap_levels, n_layers, component_provider.getColorUintComponents, data); } else if (GL_INT == format.m_source.m_type) { result = verifyResultImage(n_mipmap_levels, n_layers, component_provider.getColorIntComponents, data); } } if (GL_DEPTH_COMPONENT == format.m_source.m_format) { if (GL_FLOAT == format.m_source.m_type) { result = verifyResultImage(n_mipmap_levels, n_layers, component_provider.getDepthComponents, data); } } if (GL_STENCIL_INDEX == format.m_source.m_format) { if (GL_UNSIGNED_BYTE == format.m_source.m_type) { result = verifyResultImage(n_mipmap_levels, n_layers, component_provider.getStencilComponents, data); } } return result; } /****************************************************************************/ /** Initialize buffer collection * * @param gl GL functions * @param format Texture format * @param resolution Texture resolution **/ void TextureCubeMapArraySamplingTest::bufferCollection::init(const glw::Functions& gl, const formatDefinition& format, const resolutionDefinition& resolution) { (void)format; static const glw::GLuint n_faces = 6; static const glw::GLuint n_lods_components = 1; static const glw::GLuint n_grad_components = 4; static const glw::GLuint n_points_per_face = 9; static const glw::GLuint n_position_components = 4; static const glw::GLuint n_refZ_components = 1; static const glw::GLuint n_texture_coordinates_components = 4; const glw::GLuint n_layers = resolution.m_depth / n_faces; const glw::GLuint n_points_per_layer = n_points_per_face * n_faces; const glw::GLuint n_total_points = n_points_per_layer * n_layers; const glw::GLuint n_position_step_per_face = n_position_components * n_points_per_face; const glw::GLuint n_texture_coordinates_step_per_face = n_texture_coordinates_components * n_points_per_face; const glw::GLuint n_lods_step_per_face = n_lods_components * n_points_per_face; const glw::GLuint n_grad_step_per_face = n_grad_components * n_points_per_face; const glw::GLuint n_refZ_step_per_face = n_refZ_components * n_points_per_face; const glw::GLuint n_position_step_per_layer = n_faces * n_position_step_per_face; const glw::GLuint n_texture_coordinates_step_per_layer = n_faces * n_texture_coordinates_step_per_face; const glw::GLuint n_lods_step_per_layer = n_faces * n_lods_step_per_face; const glw::GLuint n_grad_step_per_layer = n_faces * n_grad_step_per_face; const glw::GLuint n_refZ_step_per_layer = n_faces * n_refZ_step_per_face; const glw::GLuint texture_width = resolution.m_width; const glw::GLuint texture_height = resolution.m_height; const glw::GLuint n_mip_map_levels = getMipmapLevelCount(texture_width, texture_height); std::vector position_buffer_data; std::vector texture_coordinate_buffer_data; std::vector texture_coordinate_for_gather_buffer_data; std::vector lod_buffer_data; std::vector grad_x_buffer_data; std::vector grad_y_buffer_data; std::vector refZ_buffer_data; position_buffer_data.resize(n_total_points * n_position_components); texture_coordinate_buffer_data.resize(n_total_points * n_texture_coordinates_components); texture_coordinate_for_gather_buffer_data.resize(n_total_points * n_texture_coordinates_components); lod_buffer_data.resize(n_total_points * n_lods_components); grad_x_buffer_data.resize(n_total_points * n_grad_components); grad_y_buffer_data.resize(n_total_points * n_grad_components); refZ_buffer_data.resize(n_total_points * n_refZ_components); /* Prepare data */ for (glw::GLuint layer = 0; layer < n_layers; ++layer) { const glw::GLfloat layer_coordinate = (float)layer; for (glw::GLuint face = 0; face < n_faces; ++face) { /* Offsets */ const glw::GLuint position_offset = layer * n_position_step_per_layer + face * n_position_step_per_face; const glw::GLuint texture_coordinates_offset = layer * n_texture_coordinates_step_per_layer + face * n_texture_coordinates_step_per_face; const glw::GLuint lods_offset = layer * n_lods_step_per_layer + face * n_lods_step_per_face; const glw::GLuint grad_offset = layer * n_grad_step_per_layer + face * n_grad_step_per_face; const glw::GLuint refZ_offset = layer * n_refZ_step_per_layer + face * n_refZ_step_per_face; /* Prepare data */ preparePositionForFace(&position_buffer_data[0] + position_offset, face, layer, n_layers * n_faces); prepareTextureCoordinatesForFace(&texture_coordinate_buffer_data[0] + texture_coordinates_offset, texture_width, texture_height, layer_coordinate, face); prepareTextureCoordinatesForGatherForFace(&texture_coordinate_for_gather_buffer_data[0] + texture_coordinates_offset, texture_width, texture_height, layer_coordinate, face); prepareLodForFace(&lod_buffer_data[0] + lods_offset, n_mip_map_levels); prepareGradXForFace(&grad_x_buffer_data[0] + grad_offset, face, &texture_coordinate_buffer_data[0] + texture_coordinates_offset, texture_width); prepareGradYForFace(&grad_y_buffer_data[0] + grad_offset, face, &texture_coordinate_buffer_data[0] + texture_coordinates_offset, texture_width); prepareRefZForFace(&refZ_buffer_data[0] + refZ_offset, n_mip_map_levels, face, layer, n_layers); } } /* Initialize buffers */ postion.init(gl, (glw::GLsizeiptr)(position_buffer_data.size() * sizeof(glw::GLfloat)), &position_buffer_data[0]); texture_coordinate.init(gl, (glw::GLsizeiptr)(texture_coordinate_buffer_data.size() * sizeof(glw::GLfloat)), &texture_coordinate_buffer_data[0]); texture_coordinate_for_gather.init( gl, (glw::GLsizeiptr)(texture_coordinate_for_gather_buffer_data.size() * sizeof(glw::GLfloat)), &texture_coordinate_for_gather_buffer_data[0]); lod.init(gl, (glw::GLsizeiptr)(lod_buffer_data.size() * sizeof(glw::GLfloat)), &lod_buffer_data[0]); grad_x.init(gl, (glw::GLsizeiptr)(grad_x_buffer_data.size() * sizeof(glw::GLfloat)), &grad_x_buffer_data[0]); grad_y.init(gl, (glw::GLsizeiptr)(grad_y_buffer_data.size() * sizeof(glw::GLfloat)), &grad_y_buffer_data[0]); refZ.init(gl, (glw::GLsizeiptr)(refZ_buffer_data.size() * sizeof(glw::GLfloat)), &refZ_buffer_data[0]); } /** Constructor. * **/ TextureCubeMapArraySamplingTest::bufferDefinition::bufferDefinition() : m_gl(0), m_buffer_object_id(m_invalid_buffer_object_id) { } /** Destructor * **/ TextureCubeMapArraySamplingTest::bufferDefinition::~bufferDefinition() { if (m_invalid_buffer_object_id != m_buffer_object_id) { if (0 != m_gl) { m_gl->deleteBuffers(1, &m_buffer_object_id); m_gl = 0; } m_buffer_object_id = m_invalid_buffer_object_id; } } /** Bind buffer * * @param target Target for bind **/ void TextureCubeMapArraySamplingTest::bufferDefinition::bind(glw::GLenum target) const { if (m_invalid_buffer_object_id == m_buffer_object_id) { throw tcu::InternalError("Invalid buffer object id used", "", __FILE__, __LINE__); } m_gl->bindBuffer(target, m_buffer_object_id); GLU_EXPECT_NO_ERROR(m_gl->getError(), "Failed to bind buffer."); } /** Bind buffer * * @param target Target for bind * @param index Index for target **/ void TextureCubeMapArraySamplingTest::bufferDefinition::bind(glw::GLenum target, glw::GLuint index) const { if (m_invalid_buffer_object_id == m_buffer_object_id) { throw tcu::InternalError("Invalid buffer object id used", "", __FILE__, __LINE__); } m_gl->bindBufferBase(target, index, m_buffer_object_id); GLU_EXPECT_NO_ERROR(m_gl->getError(), "Failed to bind buffer."); } /** Initialize buffer definition * * @param gl GL functions * @param buffer_size Size of buffer * @param buffer_data Buffer data **/ void TextureCubeMapArraySamplingTest::bufferDefinition::init(const glw::Functions& gl, glw::GLsizeiptr buffer_size, glw::GLvoid* buffer_data) { m_gl = ≷ m_gl->genBuffers(1, &m_buffer_object_id); GLU_EXPECT_NO_ERROR(m_gl->getError(), "Failed to generate buffer."); m_gl->bindBuffer(GL_ARRAY_BUFFER, m_buffer_object_id); GLU_EXPECT_NO_ERROR(m_gl->getError(), "Failed to bind buffer."); m_gl->bufferData(GL_ARRAY_BUFFER, buffer_size, buffer_data, GL_STATIC_DRAW); GLU_EXPECT_NO_ERROR(m_gl->getError(), "Failed to update buffer's data."); m_gl->bindBuffer(GL_ARRAY_BUFFER, 0); m_gl->getError(); } /** Constructor * * @param internal_format Internal format * @param format Format * @param type Type * @param is_compressed If format is compressed * @param sampler_type Type of sampler * @param name Name of format **/ TextureCubeMapArraySamplingTest::formatDefinition::formatDefinition(glw::GLenum internal_format, glw::GLenum format, glw::GLenum type, bool is_compressed, samplerType sampler_type, const glw::GLchar* name) : m_source(internal_format, format, type, is_compressed) , m_destination(internal_format, format, type, false /* is_compressed*/) , m_sampler_type(sampler_type) , m_name(name) { } /** Constructor * * @param src_internal_format Internal format of source image * @param src_format Format of source image * @param src_type Type of source image * @param src_is_compressed If format of source image is compressed * @param dst_internal_format Internal format of destination image * @param dst_format Format of destination image * @param dst_type Type of destination image * @param sampler_type Type of sampler * @param name Name of format **/ TextureCubeMapArraySamplingTest::formatDefinition::formatDefinition(glw::GLenum src_internal_format, glw::GLenum src_format, glw::GLenum src_type, bool src_is_compressed, glw::GLenum dst_internal_format, glw::GLenum dst_format, glw::GLenum dst_type, samplerType sampler_type, const glw::GLchar* name) : m_source(src_internal_format, src_format, src_type, src_is_compressed) , m_destination(dst_internal_format, dst_format, dst_type, false /* is_compressed*/) , m_sampler_type(sampler_type) , m_name(name) { } /** Constructor * * @param internal_format Internal format * @param format Format * @param type Type * @param is_compressed If format is compressed **/ TextureCubeMapArraySamplingTest::formatInfo::formatInfo(glw::GLenum internal_format, glw::GLenum format, glw::GLenum type, bool is_compressed) : m_internal_format(internal_format), m_format(format), m_type(type), m_is_compressed(is_compressed) { } /** Get collection of programs for sampling function * * @param function Type of sampling function * * @return Collection of programs for given sampling function **/ const TextureCubeMapArraySamplingTest::programCollectionForFunction* TextureCubeMapArraySamplingTest:: programCollectionForFormat::getPrograms(samplingFunction function) const { switch (function) { case Texture: return &m_programs_for_texture; case TextureLod: return &m_programs_for_textureLod; case TextureGrad: return &m_programs_for_textureGrad; case TextureGather: return &m_programs_for_textureGather; } return 0; } /** Initialize program collection for format * * @param gl GL functions * @param shader_collection Collection of shaders * @param test Instance of test class **/ void TextureCubeMapArraySamplingTest::programCollectionForFormat::init( const glw::Functions& gl, const shaderCollectionForTextureFormat& shader_collection, TextureCubeMapArraySamplingTest& test, bool isContextES) { shaderGroup shader_group; shader_collection.getShaderGroup(Texture, shader_group); m_programs_for_texture.init(gl, shader_group, test, isContextES); shader_collection.getShaderGroup(TextureLod, shader_group); m_programs_for_textureLod.init(gl, shader_group, test, isContextES); shader_collection.getShaderGroup(TextureGrad, shader_group); m_programs_for_textureGrad.init(gl, shader_group, test, isContextES); shader_collection.getShaderGroup(TextureGather, shader_group); m_programs_for_textureGather.init(gl, shader_group, test, isContextES); } /** Get program with specified sampling shader * * @param shader_type Type of shader * * @returns Program information **/ const TextureCubeMapArraySamplingTest::programDefinition* TextureCubeMapArraySamplingTest:: programCollectionForFunction::getProgram(shaderType shader_type) const { switch (shader_type) { case Compute: return &program_with_sampling_compute_shader; case Fragment: return &program_with_sampling_fragment_shader; case Geometry: return &program_with_sampling_geometry_shader; case Tesselation_Control: return &program_with_sampling_tesselation_control_shader; case Tesselation_Evaluation: return &program_with_sampling_tesselation_evaluation_shader; case Vertex: return &program_with_sampling_vertex_shader; } return 0; } /** Initialize program collection for sampling function * * @param gl GL functions * @param shader_group Group of shader compatible with sampling function * @param test Instance of test class **/ void TextureCubeMapArraySamplingTest::programCollectionForFunction::init(const glw::Functions& gl, const shaderGroup& shader_group, TextureCubeMapArraySamplingTest& test, bool isContextES) { program_with_sampling_compute_shader.init(gl, shader_group, Compute, isContextES); program_with_sampling_fragment_shader.init(gl, shader_group, Fragment, isContextES); program_with_sampling_vertex_shader.init(gl, shader_group, Vertex, isContextES); test.link(program_with_sampling_compute_shader); test.link(program_with_sampling_fragment_shader); test.link(program_with_sampling_vertex_shader); if (test.m_is_geometry_shader_extension_supported) { program_with_sampling_geometry_shader.init(gl, shader_group, Geometry, isContextES); test.link(program_with_sampling_geometry_shader); } if (test.m_is_tessellation_shader_supported) { program_with_sampling_tesselation_control_shader.init(gl, shader_group, Tesselation_Control, isContextES); program_with_sampling_tesselation_evaluation_shader.init(gl, shader_group, Tesselation_Evaluation, isContextES); test.link(program_with_sampling_tesselation_control_shader); test.link(program_with_sampling_tesselation_evaluation_shader); } } /** Constructor * **/ TextureCubeMapArraySamplingTest::programDefinition::programDefinition() : compute_shader(0) , geometry_shader(0) , fragment_shader(0) , tesselation_control_shader(0) , tesselation_evaluation_shader(0) , vertex_shader(0) , m_program_object_id(m_invalid_program_object_id) , m_gl(DE_NULL) { } /** Destructor * **/ TextureCubeMapArraySamplingTest::programDefinition::~programDefinition() { if (m_invalid_program_object_id != m_program_object_id) { if (0 != m_gl) { m_gl->deleteProgram(m_program_object_id); m_program_object_id = m_invalid_program_object_id; m_gl = 0; } } } /** Get program id * * @returns Program id **/ glw::GLuint TextureCubeMapArraySamplingTest::programDefinition::getProgramId() const { return m_program_object_id; } /** Get shader * * @param shader_type Requested shader type * * @returns Pointer to shader information. Can be null. **/ const TextureCubeMapArraySamplingTest::shaderDefinition* TextureCubeMapArraySamplingTest::programDefinition::getShader( shaderType shader_type) const { switch (shader_type) { case Compute: return compute_shader; case Fragment: return fragment_shader; case Geometry: return geometry_shader; case Tesselation_Control: return tesselation_control_shader; case Tesselation_Evaluation: return tesselation_evaluation_shader; case Vertex: return vertex_shader; } return 0; } /** Initialize program information * * @param gl GL functions * @param shader_group Group of shaders compatible with samplinbg function and texture format * @param shader_type Stage that will execute sampling **/ void TextureCubeMapArraySamplingTest::programDefinition::init(const glw::Functions& gl, const shaderGroup& shader_group, shaderType shader_type, bool isContextES) { m_gl = ≷ bool is_program_defined = false; switch (shader_type) { case Compute: compute_shader = shader_group.sampling_compute_shader; is_program_defined = (0 != compute_shader); break; case Fragment: fragment_shader = shader_group.sampling_fragment_shader; vertex_shader = shader_group.pass_through_vertex_shader; is_program_defined = ((0 != fragment_shader) && (0 != vertex_shader)); break; case Geometry: fragment_shader = shader_group.pass_through_fragment_shader; geometry_shader = shader_group.sampling_geometry_shader; vertex_shader = shader_group.pass_through_vertex_shader; is_program_defined = ((0 != fragment_shader) && (0 != geometry_shader) && (0 != vertex_shader)); break; case Tesselation_Control: fragment_shader = shader_group.pass_through_fragment_shader; tesselation_control_shader = shader_group.sampling_tesselation_control_shader; tesselation_evaluation_shader = shader_group.pass_through_tesselation_evaluation_shader; vertex_shader = shader_group.pass_through_vertex_shader; is_program_defined = ((0 != fragment_shader) && (0 != tesselation_control_shader) && (0 != tesselation_evaluation_shader) && (0 != vertex_shader)); break; case Tesselation_Evaluation: fragment_shader = shader_group.pass_through_fragment_shader; if (isContextES) { tesselation_control_shader = shader_group.pass_through_tesselation_control_shader; } tesselation_evaluation_shader = shader_group.sampling_tesselation_evaluation_shader; vertex_shader = shader_group.pass_through_vertex_shader; is_program_defined = ((0 != fragment_shader) && (0 != tesselation_control_shader) && (0 != tesselation_evaluation_shader) && (0 != vertex_shader)); break; case Vertex: fragment_shader = shader_group.pass_through_fragment_shader; vertex_shader = shader_group.sampling_vertex_shader; is_program_defined = ((0 != fragment_shader) && (0 != vertex_shader)); break; } if (true == is_program_defined) { m_program_object_id = m_gl->createProgram(); GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to create program"); if (m_invalid_program_object_id == m_program_object_id) { throw tcu::InternalError("glCreateProgram return invalid id", "", __FILE__, __LINE__); } } } /** Link program * * @return true When linking was successful * false When linking failed **/ bool TextureCubeMapArraySamplingTest::programDefinition::link() { if (m_invalid_program_object_id == m_program_object_id) { return false; } if (0 != compute_shader) { compute_shader->attach(m_program_object_id); } if (0 != geometry_shader) { geometry_shader->attach(m_program_object_id); } if (0 != fragment_shader) { fragment_shader->attach(m_program_object_id); } if (0 != tesselation_control_shader) { tesselation_control_shader->attach(m_program_object_id); } if (0 != tesselation_evaluation_shader) { tesselation_evaluation_shader->attach(m_program_object_id); } if (0 != vertex_shader) { vertex_shader->attach(m_program_object_id); } /* Link Program */ m_gl->linkProgram(m_program_object_id); GLU_EXPECT_NO_ERROR(m_gl->getError(), "glLinkProgram() call failed."); /* Check linking status */ glw::GLint linkStatus = GL_FALSE; m_gl->getProgramiv(m_program_object_id, GL_LINK_STATUS, &linkStatus); GLU_EXPECT_NO_ERROR(m_gl->getError(), "glGetProgramiv() call failed."); if (linkStatus == GL_FALSE) { return false; } return true; } /** Constructor * * @param width Width * @param height Height * @param depth Depth **/ TextureCubeMapArraySamplingTest::resolutionDefinition::resolutionDefinition(glw::GLuint width, glw::GLuint height, glw::GLuint depth) : m_width(width), m_height(height), m_depth(depth) { } /** Constructor * * @param function Type of sampling function * @param name Name of sampling function **/ TextureCubeMapArraySamplingTest::samplingFunctionDefinition::samplingFunctionDefinition(samplingFunction function, const glw::GLchar* name) : m_function(function), m_name(name) { } /** Initialize shader collection for sampling function * * @param gl GL functions * @param format Texture format * @param sampling_function Sampling function * @param test Instance of test class **/ void TextureCubeMapArraySamplingTest::shaderCollectionForSamplingRoutine::init( const glw::Functions& gl, const formatDefinition& format, const samplingFunction& sampling_function, TextureCubeMapArraySamplingTest& test) { m_sampling_function = sampling_function; std::string pass_through_vertex_shader_source; std::string pass_through_tesselation_control_shader_source; std::string sampling_compute_shader_source; std::string sampling_fragment_shader_source; std::string sampling_geometry_shader_source; std::string sampling_tesselation_control_shader_source; std::string sampling_tesselation_evaluation_shader_source; std::string sampling_vertex_shader_source; test.getPassThroughVertexShaderCode(format.m_sampler_type, m_sampling_function, pass_through_vertex_shader_source); test.getPassThroughTesselationControlShaderCode(format.m_sampler_type, m_sampling_function, pass_through_tesselation_control_shader_source); test.getSamplingComputeShaderCode(format.m_sampler_type, m_sampling_function, sampling_compute_shader_source); test.getSamplingFragmentShaderCode(format.m_sampler_type, m_sampling_function, sampling_fragment_shader_source); test.getSamplingGeometryShaderCode(format.m_sampler_type, m_sampling_function, sampling_geometry_shader_source); test.getSamplingTesselationControlShaderCode(format.m_sampler_type, m_sampling_function, sampling_tesselation_control_shader_source); test.getSamplingTesselationEvaluationShaderCode(format.m_sampler_type, m_sampling_function, sampling_tesselation_evaluation_shader_source); test.getSamplingVertexShaderCode(format.m_sampler_type, m_sampling_function, sampling_vertex_shader_source); pass_through_vertex_shader.init(gl, GL_VERTEX_SHADER, pass_through_vertex_shader_source, &test); sampling_compute_shader.init(gl, GL_COMPUTE_SHADER, sampling_compute_shader_source, &test); sampling_fragment_shader.init(gl, GL_FRAGMENT_SHADER, sampling_fragment_shader_source, &test); sampling_vertex_shader.init(gl, GL_VERTEX_SHADER, sampling_vertex_shader_source, &test); test.compile(pass_through_vertex_shader); test.compile(sampling_compute_shader); test.compile(sampling_fragment_shader); test.compile(sampling_vertex_shader); if (test.m_is_tessellation_shader_supported) { pass_through_tesselation_control_shader.init(gl, test.m_glExtTokens.TESS_CONTROL_SHADER, pass_through_tesselation_control_shader_source, &test); sampling_tesselation_control_shader.init(gl, test.m_glExtTokens.TESS_CONTROL_SHADER, sampling_tesselation_control_shader_source, &test); sampling_tesselation_evaluation_shader.init(gl, test.m_glExtTokens.TESS_EVALUATION_SHADER, sampling_tesselation_evaluation_shader_source, &test); test.compile(pass_through_tesselation_control_shader); test.compile(sampling_tesselation_control_shader); test.compile(sampling_tesselation_evaluation_shader); } if (test.m_is_geometry_shader_extension_supported) { sampling_geometry_shader.init(gl, test.m_glExtTokens.GEOMETRY_SHADER, sampling_geometry_shader_source, &test); test.compile(sampling_geometry_shader); } } /** Get group of shader compatible with sampling function and texture format * * @param function Sampling function * @param shader_group Group of shaders **/ void TextureCubeMapArraySamplingTest::shaderCollectionForTextureFormat::getShaderGroup(samplingFunction function, shaderGroup& shader_group) const { shader_group.init(); for (shaderCollectionForSamplingFunctionVectorType::const_iterator it = per_sampling_routine.begin(), end = per_sampling_routine.end(); end != it; ++it) { if (it->m_sampling_function == function) { shader_group.pass_through_fragment_shader = &pass_through_fragment_shader; shader_group.pass_through_tesselation_control_shader = &it->pass_through_tesselation_control_shader; shader_group.pass_through_tesselation_evaluation_shader = &pass_through_tesselation_evaluation_shader; shader_group.pass_through_vertex_shader = &it->pass_through_vertex_shader; shader_group.sampling_compute_shader = &it->sampling_compute_shader; shader_group.sampling_fragment_shader = &it->sampling_fragment_shader; shader_group.sampling_geometry_shader = &it->sampling_geometry_shader; shader_group.sampling_tesselation_control_shader = &it->sampling_tesselation_control_shader; shader_group.sampling_tesselation_evaluation_shader = &it->sampling_tesselation_evaluation_shader; shader_group.sampling_vertex_shader = &it->sampling_vertex_shader; return; } } } /** Initialize shader collection for texture format * * @param gl GL functions * @param format Texture format * @param sampling_routines Set of sampling functions * @param test Instance of test class **/ void TextureCubeMapArraySamplingTest::shaderCollectionForTextureFormat::init( const glw::Functions& gl, const formatDefinition& format, const samplingFunctionsVectorType& sampling_routines, TextureCubeMapArraySamplingTest& test) { std::string pass_through_fragment_shader_source; std::string pass_through_tesselation_evaluation_shader_source; glw::GLuint n_routines_supporting_format = 0; test.getPassThroughFragmentShaderCode(format.m_sampler_type, pass_through_fragment_shader_source); test.getPassThroughTesselationEvaluationShaderCode(format.m_sampler_type, pass_through_tesselation_evaluation_shader_source); pass_through_fragment_shader.init(gl, GL_FRAGMENT_SHADER, pass_through_fragment_shader_source, &test); if (test.m_is_tessellation_shader_supported) { pass_through_tesselation_evaluation_shader.init(gl, test.m_glExtTokens.TESS_EVALUATION_SHADER, pass_through_tesselation_evaluation_shader_source, &test); } test.compile(pass_through_fragment_shader); if (test.m_is_tessellation_shader_supported) { test.compile(pass_through_tesselation_evaluation_shader); } for (samplingFunctionsVectorType::const_iterator it = sampling_routines.begin(), end = sampling_routines.end(); end != it; ++it) { if (TextureCubeMapArraySamplingTest::isSamplerSupportedByFunction(format.m_sampler_type, it->m_function)) { n_routines_supporting_format += 1; } } per_sampling_routine.resize(n_routines_supporting_format); shaderCollectionForSamplingFunctionVectorType::iterator jt = per_sampling_routine.begin(); for (samplingFunctionsVectorType::const_iterator it = sampling_routines.begin(), end = sampling_routines.end(); end != it; ++it) { if (TextureCubeMapArraySamplingTest::isSamplerSupportedByFunction(format.m_sampler_type, it->m_function)) { jt->init(gl, format, it->m_function, test); ++jt; } } } /** Constructor * * @param type Type of shader * @param is_supported If configuration is supported * @param primitive_type Type of primitive * @param name Name of sampling shader stage **/ TextureCubeMapArraySamplingTest::shaderConfiguration::shaderConfiguration(shaderType type, glw::GLenum primitive_type, const glw::GLchar* name) : m_type(type), m_primitive_type(primitive_type), m_name(name) { } /** Constructor * **/ TextureCubeMapArraySamplingTest::shaderDefinition::shaderDefinition() : m_gl(0), m_shader_stage(0), m_shader_object_id(m_invalid_shader_object_id) { } /** Destructor * **/ TextureCubeMapArraySamplingTest::shaderDefinition::~shaderDefinition() { if (m_invalid_shader_object_id != m_shader_object_id) { if (0 != m_gl) { m_gl->deleteShader(m_shader_object_id); m_gl = 0; } m_shader_object_id = m_invalid_shader_object_id; } m_source.clear(); } /** Attach shade to program * * @parma program_object_id Progam id **/ void TextureCubeMapArraySamplingTest::shaderDefinition::attach(glw::GLuint program_object_id) const { if (0 == m_gl) { throw tcu::InternalError("shaderDefinition not initialized", "", __FILE__, __LINE__); } m_gl->attachShader(program_object_id, m_shader_object_id); GLU_EXPECT_NO_ERROR(m_gl->getError(), "glAttachShader() call failed."); } /** Compile shader * * @returns true When successful * false When compilation failed **/ bool TextureCubeMapArraySamplingTest::shaderDefinition::compile() { glw::GLint compile_status = GL_FALSE; const glw::GLchar* source = m_source.c_str(); /* Set shaders source */ m_gl->shaderSource(m_shader_object_id, 1, &source, NULL); GLU_EXPECT_NO_ERROR(m_gl->getError(), "glShaderSource() call failed."); /* Try to compile the shader */ m_gl->compileShader(m_shader_object_id); GLU_EXPECT_NO_ERROR(m_gl->getError(), "glCompileShader() call failed."); /* Check if all shaders compiled successfully */ m_gl->getShaderiv(m_shader_object_id, GL_COMPILE_STATUS, &compile_status); GLU_EXPECT_NO_ERROR(m_gl->getError(), "glGetShaderiv() call failed."); if (compile_status == GL_FALSE) { return false; } return true; } /** Get shader id * * @returns Shader id **/ glw::GLuint TextureCubeMapArraySamplingTest::shaderDefinition::getShaderId() const { return m_shader_object_id; } /** Get source * * @returns Code of shader **/ const std::string& TextureCubeMapArraySamplingTest::shaderDefinition::getSource() const { return m_source; } /** Initialize shader informations * * @param gl GL functions * @param shader_stage Stage of shader * @param source Source of shader **/ void TextureCubeMapArraySamplingTest::shaderDefinition::init(const glw::Functions& gl, glw::GLenum shader_stage, const std::string& source, TextureCubeMapArraySamplingTest* test) { m_gl = ≷ m_shader_stage = shader_stage; const glw::GLchar* source_cstr = source.c_str(); m_source = test->specializeShader(1, &source_cstr); if (m_invalid_shader_object_id == m_shader_object_id) { if (0 != m_gl) { m_shader_object_id = m_gl->createShader(m_shader_stage); GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to create shader"); if (m_invalid_shader_object_id == m_shader_object_id) { throw tcu::InternalError("glCreateShader returned invalid id", "", __FILE__, __LINE__); } } } } /** Initialize shader group * **/ void TextureCubeMapArraySamplingTest::shaderGroup::init() { pass_through_fragment_shader = 0; pass_through_tesselation_control_shader = 0; pass_through_tesselation_evaluation_shader = 0; pass_through_vertex_shader = 0; sampling_compute_shader = 0; sampling_fragment_shader = 0; sampling_geometry_shader = 0; sampling_tesselation_control_shader = 0; sampling_tesselation_evaluation_shader = 0; sampling_vertex_shader = 0; } /** Constructor * **/ TextureCubeMapArraySamplingTest::textureDefinition::textureDefinition() : m_gl(0), m_texture_object_id(m_invalid_texture_object_id) { } /** Destructor * **/ TextureCubeMapArraySamplingTest::textureDefinition::~textureDefinition() { if (m_invalid_texture_object_id != m_texture_object_id) { if (0 != m_gl) { m_gl->deleteTextures(1, &m_texture_object_id); m_gl = 0; } m_texture_object_id = m_invalid_texture_object_id; } } /** Bind texture * * @param binding_point Where texture will be bound **/ void TextureCubeMapArraySamplingTest::textureDefinition::bind(glw::GLenum binding_point) const { if (0 == m_gl) { throw tcu::InternalError("TextureDefinition not initialized", "", __FILE__, __LINE__); } m_gl->bindTexture(binding_point, m_texture_object_id); GLU_EXPECT_NO_ERROR(m_gl->getError(), "Failed to bind texture"); } /** Get texture id * * @returns Texture id **/ glw::GLuint TextureCubeMapArraySamplingTest::textureDefinition::getTextureId() const { return m_texture_object_id; } /** Initialize texture information * * @param gl GL functions * @param bind_image Address of glBindImageTexture procedure **/ void TextureCubeMapArraySamplingTest::textureDefinition::init(const glw::Functions& gl) { m_gl = ≷ gl.genTextures(1, &m_texture_object_id); GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to generate texture"); } /** Set texture as image * * @param image_unit Index of image unit * @param internal_format Format for image unit **/ void TextureCubeMapArraySamplingTest::textureDefinition::setupImage(glw::GLuint image_unit, glw::GLenum internal_format) { if ((0 == m_gl) || (m_invalid_texture_object_id == m_texture_object_id)) { throw tcu::InternalError("Not initialized textureDefinition", "", __FILE__, __LINE__); } m_gl->bindImageTexture(image_unit, m_texture_object_id, 0, GL_FALSE, 0, GL_WRITE_ONLY, internal_format); GLU_EXPECT_NO_ERROR(m_gl->getError(), "glBindImageTexture"); } /** Setup texture unit with this * * @param texture_unit Index of texture unit * @param sampler_name_p Name of sampler uniform * @param program_id Program id * @param is_shadow If depth comparison should be enabled **/ void TextureCubeMapArraySamplingTest::textureDefinition::setupSampler(glw::GLuint texture_unit, const glw::GLchar* sampler_name_p, glw::GLuint program_id, bool is_shadow) { if ((0 == m_gl) || (m_invalid_texture_object_id == m_texture_object_id)) { throw tcu::InternalError("Not initialized textureDefinition", "", __FILE__, __LINE__); } glw::GLint sampler_location = m_gl->getUniformLocation(program_id, sampler_name_p); if ((m_invalid_uniform_location == (glw::GLuint)sampler_location) || (GL_NO_ERROR != m_gl->getError())) { //throw tcu::InternalError("Failed to get sampler location", sampler_name_p, __FILE__, __LINE__); return; } m_gl->activeTexture(GL_TEXTURE0 + texture_unit); GLU_EXPECT_NO_ERROR(m_gl->getError(), "Failed to activate texture unit"); m_gl->bindTexture(GL_TEXTURE_CUBE_MAP_ARRAY, m_texture_object_id); GLU_EXPECT_NO_ERROR(m_gl->getError(), "Failed to bind texture to GL_TEXTURE_CUBE_MAP_ARRAY_EXT"); if (true == is_shadow) { m_gl->texParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); m_gl->texParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_COMPARE_FUNC, GL_LESS); } m_gl->uniform1i(sampler_location, texture_unit); GLU_EXPECT_NO_ERROR(m_gl->getError(), "Failed to set sampler uniform"); } /** Constructor * **/ TextureCubeMapArraySamplingTest::vertexArrayObjectDefinition::vertexArrayObjectDefinition() : m_gl(0), m_vertex_array_object_id(m_invalid_vertex_array_object_id) { } /** Destructor * **/ TextureCubeMapArraySamplingTest::vertexArrayObjectDefinition::~vertexArrayObjectDefinition() { if (m_invalid_vertex_array_object_id != m_vertex_array_object_id) { if (0 != m_gl) { m_gl->deleteVertexArrays(1, &m_vertex_array_object_id); m_gl = 0; } m_vertex_array_object_id = m_invalid_vertex_array_object_id; } } /** Initialize vertex array object * * @param gl GL functions * @param format Texture format * @param sampling_function Type of sampling function * @param buffers Buffer collection * @param program_id Program id **/ void TextureCubeMapArraySamplingTest::vertexArrayObjectDefinition::init(const glw::Functions& gl, const formatDefinition& format, const samplingFunction& sampling_function, const bufferCollection& buffers, glw::GLuint program_id) { m_gl = ≷ m_gl->genVertexArrays(1, &m_vertex_array_object_id); GLU_EXPECT_NO_ERROR(m_gl->getError(), "Failed to generate VAO."); m_gl->bindVertexArray(m_vertex_array_object_id); GLU_EXPECT_NO_ERROR(m_gl->getError(), "Failed to bind VAO."); attributeDefinition positionAttribute = { vertex_shader_position, type_vec4, Position, 0 }; const attributeDefinition* format_attributes; glw::GLuint n_format_attributes; const attributeDefinition* routine_attributes = 0; glw::GLuint n_routine_attributes = 0; getAttributes(format.m_sampler_type, format_attributes, n_format_attributes); getAttributes(sampling_function, routine_attributes, n_routine_attributes); setupAttribute(positionAttribute, buffers, program_id); for (glw::GLuint i = 0; i < n_routine_attributes; ++i) { setupAttribute(routine_attributes[i], buffers, program_id); } for (glw::GLuint i = 0; i < n_format_attributes; ++i) { setupAttribute(format_attributes[i], buffers, program_id); } } /** Setup vertex array object * * @param attribute Attribute information * @param buffers Buffer collection * @param program_id Program id **/ void TextureCubeMapArraySamplingTest::vertexArrayObjectDefinition::setupAttribute(const attributeDefinition& attribute, const bufferCollection& buffers, glw::GLuint program_id) { std::string attribute_name = vertex_shader_input; const bufferDefinition* buffer = 0; glw::GLuint n_components = 0; glw::GLenum type = GL_FLOAT; attribute_name.append(attribute.name); switch (attribute.attribute_id) { case Position: n_components = 4; buffer = &buffers.postion; break; case TextureCoordinates: n_components = 4; buffer = &buffers.texture_coordinate; break; case TextureCoordinatesForGather: n_components = 4; buffer = &buffers.texture_coordinate_for_gather; break; case Lod: n_components = 1; buffer = &buffers.lod; break; case GradX: n_components = 4; buffer = &buffers.grad_x; break; case GradY: n_components = 4; buffer = &buffers.grad_y; break; case RefZ: n_components = 1; buffer = &buffers.refZ; break; } /* Get attribute location */ glw::GLint attribute_location = m_gl->getAttribLocation(program_id, attribute_name.c_str()); if ((m_invalid_attribute_location == (glw::GLuint)attribute_location) || (GL_NO_ERROR != m_gl->getError())) { //throw tcu::InternalError("Failed to get location of attribute:", attribute_name.c_str(), __FILE__, __LINE__); return; } buffer->bind(GL_ARRAY_BUFFER); m_gl->enableVertexAttribArray(attribute_location); GLU_EXPECT_NO_ERROR(m_gl->getError(), "Failed to enable attribute"); m_gl->vertexAttribPointer(attribute_location, n_components, type, GL_FALSE, 0 /* stride */, 0 /* offset */); GLU_EXPECT_NO_ERROR(m_gl->getError(), "Failed to setup vertex attribute arrays"); } #if TEXTURECUBEMAPARRAYSAMPLINGTEST_DUMP_TEXTURES_FOR_COMPRESSION /** Get file name for given face * Such pattern is used: texture_cube_map_array_sampling_test_w_WIDTH_h_HEIGHT_l_LEVEL_i_INDEX_f_FACE * * @param width Width of texture * @param height Height of texture * @param level Mipmap level * @param index Index of element in array * @param face Cube map's face index * @param name File name **/ void getTextureFileName(glw::GLuint width, glw::GLuint height, glw::GLuint level, glw::GLuint index, glw::GLuint face, std::string& name) { std::stringstream file_name; file_name << TEXTURECUBEMAPARRAYSAMPLINGTEST_PATH_FOR_COMPRESSION; file_name << "texture_cube_map_array_sampling_test_" << "w_" << width << "_h_" << height << "_l_" << level << "_i_" << index << "_f_" << face; name = file_name.str(); } /** Store whole cube map as TGA files. Each face is stored as separate image. * * @param resolution Resolution of base level **/ void prepareDumpForTextureCompression(const TextureCubeMapArraySamplingTest::resolutionDefinition& resolution) { glw::GLsizei texture_width = resolution.m_width; glw::GLsizei texture_height = resolution.m_height; const glw::GLuint n_components = 4; const glw::GLuint n_faces = 6; const glw::GLint n_array_elements = resolution.m_depth / n_faces; const glw::GLint n_mipmap_levels = getMipmapLevelCount(resolution.m_width, resolution.m_height); const unsigned char tga_id_length = 0; // no id const unsigned char tga_color_map_type = 0; // no color map const unsigned char tga_image_type = 2; // rgb no compression const unsigned short tga_color_map_offset = 0; // no color map const unsigned short tga_color_map_length = 0; // no color map const unsigned char tga_color_map_bits_per_pixel = 0; // no color map const unsigned short tga_image_x = 0; const unsigned short tga_image_y = 0; const unsigned char tga_image_bits_per_pixel = 32; const unsigned char tga_image_descriptor = 0x8; // 8 per alpha for (glw::GLint mipmap_level = 0; mipmap_level < n_mipmap_levels; ++mipmap_level) { const unsigned short tga_image_width = texture_width; const unsigned short tga_image_height = texture_height; for (glw::GLint array_index = 0; array_index < n_array_elements; ++array_index) { for (glw::GLint face = 0; face < n_faces; ++face) { std::fstream file; std::string file_name; getTextureFileName(resolution.m_width, resolution.m_height, mipmap_level, array_index, face, file_name); file_name.append(".tga"); file.open(file_name.c_str(), std::fstream::out | std::fstream::binary); file.write((const char*)&tga_id_length, sizeof(tga_id_length)); file.write((const char*)&tga_color_map_type, sizeof(tga_color_map_type)); file.write((const char*)&tga_image_type, sizeof(tga_image_type)); file.write((const char*)&tga_color_map_offset, sizeof(tga_color_map_offset)); file.write((const char*)&tga_color_map_length, sizeof(tga_color_map_length)); file.write((const char*)&tga_color_map_bits_per_pixel, sizeof(tga_color_map_bits_per_pixel)); file.write((const char*)&tga_image_x, sizeof(tga_image_x)); file.write((const char*)&tga_image_y, sizeof(tga_image_y)); file.write((const char*)&tga_image_width, sizeof(tga_image_width)); file.write((const char*)&tga_image_height, sizeof(tga_image_height)); file.write((const char*)&tga_image_bits_per_pixel, sizeof(tga_image_bits_per_pixel)); file.write((const char*)&tga_image_descriptor, sizeof(tga_image_descriptor)); glw::GLubyte components[n_components]; getCompressedColorUByteComponents(face, array_index, mipmap_level, n_array_elements, n_mipmap_levels, components); for (glw::GLuint y = 0; y < texture_height; ++y) { for (glw::GLuint x = 0; x < texture_width; ++x) { for (glw::GLuint i = 0; i < n_components; ++i) { file.write((const char*)&components[i], sizeof(glw::GLubyte)); } } } } } texture_width = de::max(1, texture_width / 2); texture_height = de::max(1, texture_height / 2); } } #endif /* TEXTURECUBEMAPARRAYSAMPLINGTEST_DUMP_TEXTURES_FOR_COMPRESSION */ } /* glcts */