blob: 971e7a81b43b9a8a3c1b904a24d8c5a7d9062ae3 [file] [log] [blame]
/*-------------------------------------------------------------------------
* 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 esextcTextureBorderClampSamplingTexture.cpp
* \brief Verify that sampling a texture with GL_CLAMP_TO_BORDER_EXT
* wrap mode enabled gives correct results (Test 7)
*/ /*-------------------------------------------------------------------*/
#include "esextcTextureBorderClampSamplingTexture.hpp"
#include "esextcTextureBorderClampCompressedResources.hpp"
#include "gluDefs.hpp"
#include "glwEnums.hpp"
#include "glwFunctions.hpp"
#include "tcuTestLog.hpp"
namespace glcts
{
template <typename InputType, typename OutputType>
const glw::GLuint TextureBorderClampSamplingTexture<InputType, OutputType>::m_texture_unit = 0;
/** Constructor
*
* @param nComponents number of components
* @param target texture target
* @param inputInternalFormat input texture internal format
* @param outputInternalFormat output texture internal format
* @param filtering contains parameters for GL_TEXTURE_MAG_FILTER and GL_TEXTURE_MIN_FILTER - in our case can be GL_NEAREST or GL_LINEAR
* @param inputFormat input texture format
* @param outputFormat output texture format
* @param width texture/viewport width
* @param height texture/viewport height
* @param initValue value used for input texture to fill all texels with
* @param initBorderColor value of border color for input texture
* @param expectedValue expected value for texture texels for points taken from inside of input texture
* @param expectedBorderColor expected value for texture texels for points taken from outside of input texture
* @param inputType enum representing data type for input texture
* @param outputType enum representing data type for output texture
**/
template <typename InputType, typename OutputType>
TestConfiguration<InputType, OutputType>::TestConfiguration(
glw::GLsizei nInComponents, glw::GLsizei nOutComponents, glw::GLenum target, glw::GLenum inputInternalFormat,
glw::GLenum outputInternalFormat, glw::GLenum filtering, glw::GLenum inputFormat, glw::GLenum outputFormat,
glw::GLuint width, glw::GLuint height, glw::GLuint depth, InputType initValue, InputType initBorderColor,
OutputType expectedValue, OutputType expectedBorderColor, glw::GLenum inputType, glw::GLenum outputType)
: m_n_in_components(nInComponents)
, m_n_out_components(nOutComponents)
, m_target(target)
, m_input_internal_format(inputInternalFormat)
, m_output_internal_format(outputInternalFormat)
, m_filtering(filtering)
, m_input_format(inputFormat)
, m_output_format(outputFormat)
, m_width(width)
, m_height(height)
, m_depth(depth)
, m_init_value(initValue)
, m_init_border_color(initBorderColor)
, m_expected_value(expectedValue)
, m_expected_border_color(expectedBorderColor)
, m_input_type(inputType)
, m_output_type(outputType)
{
/* Nothing to be done here */
}
/** Copy Contructor
*
* @param configuration const reference to the configuration which will be copied
*/
template <typename InputType, typename OutputType>
TestConfiguration<InputType, OutputType>::TestConfiguration(const TestConfiguration& configuration)
{
m_n_in_components = configuration.get_n_in_components();
m_n_out_components = configuration.get_n_out_components();
m_target = configuration.get_target();
m_input_internal_format = configuration.get_input_internal_format();
m_output_internal_format = configuration.get_output_internal_format();
m_filtering = configuration.get_filtering();
m_input_format = configuration.get_input_format();
m_output_format = configuration.get_output_format();
m_width = configuration.get_width();
m_height = configuration.get_height();
m_depth = configuration.get_depth();
m_init_value = configuration.get_init_value();
m_init_border_color = configuration.get_init_border_color();
m_expected_value = configuration.get_expected_value();
m_expected_border_color = configuration.get_expected_border_color();
m_input_type = configuration.get_input_type();
m_output_type = configuration.get_output_type();
}
/** Constructor
*
* @param context Test context
* @param name Test case's name
* @param description Test case's description
**/
template <typename InputType, typename OutputType>
TextureBorderClampSamplingTexture<InputType, OutputType>::TextureBorderClampSamplingTexture(
Context& context, const ExtParameters& extParams, const char* name, const char* description,
const TestConfiguration<InputType, OutputType>& configuration)
: TestCaseBase(context, extParams, name, description)
, m_attr_position_location(-1)
, m_attr_texcoord_location(-1)
, m_fbo_id(0)
, m_fs_id(0)
, m_po_id(0)
, m_sampler_id(0)
, m_test_configuration(configuration)
, m_input_to_id(0)
, m_output_to_id(0)
, m_position_vbo_id(0)
, m_text_coord_vbo_id(0)
, m_vs_id(0)
, m_vao_id(0)
{
/* Nothing to be done here */
}
/** Initializes GLES objects used during the test.
*
**/
template <typename InputType, typename OutputType>
void TextureBorderClampSamplingTexture<InputType, OutputType>::initTest(void)
{
if (!m_is_texture_border_clamp_supported)
{
throw tcu::NotSupportedError(TEXTURE_BORDER_CLAMP_NOT_SUPPORTED, "", __FILE__, __LINE__);
}
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Generate and bind VAO */
gl.genVertexArrays(1, &m_vao_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "Could not generate vertex array object");
gl.bindVertexArray(m_vao_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding vertex array object!");
/* Generate sampler object */
gl.genSamplers(1, &m_sampler_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "Error generating sampler object!");
/* Create framebuffer object */
gl.genFramebuffers(1, &m_fbo_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "Error generating framebuffer object!");
/* Set up clear color */
gl.clearColor(0.5 /* red */, 0.5 /* green */, 0.5 /* blue */, 1 /* alpha */);
GLU_EXPECT_NO_ERROR(gl.getError(), "Error setting clear color value!");
/* Input attributes for vertex shader */
/* Full screen quad */
glw::GLfloat vertices[] = { -1.0f, -1.0f, 0.0f, 1.0f, -1.0f, 1.0f, 0.0f, 1.0f,
1.0f, -1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f };
/* Texture coords */
glw::GLfloat coords[] = {
-1.0f, -1.0f, /* for bottom-left corner of the viewport */
-1.0f, 2.0f, /* for top-left corner of the viewport */
2.0f, -1.0f, /* for bottom-right corner of the viewport */
2.0f, 2.0f /* for top-right corner of the viewport */
};
/* Generate buffer object */
gl.genBuffers(1, &m_position_vbo_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "Error generating buffer object!");
/* Bind buffer object */
gl.bindBuffer(GL_ARRAY_BUFFER, m_position_vbo_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding buffer object!");
/* Set data for buffer object */
gl.bufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
GLU_EXPECT_NO_ERROR(gl.getError(), "Error setting data for buffer object!");
/* Generate buffer object */
gl.genBuffers(1, &m_text_coord_vbo_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "Error generating buffer object!");
/* Bind buffer object */
gl.bindBuffer(GL_ARRAY_BUFFER, m_text_coord_vbo_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding buffer object!");
/* Set data for buffer object */
gl.bufferData(GL_ARRAY_BUFFER, sizeof(coords), coords, GL_STATIC_DRAW);
GLU_EXPECT_NO_ERROR(gl.getError(), "Error seting data for buffer object!");
/* Create program object */
m_po_id = gl.createProgram();
/* Create shader objects */
m_vs_id = gl.createShader(GL_VERTEX_SHADER);
m_fs_id = gl.createShader(GL_FRAGMENT_SHADER);
/* Get vertex shader code */
std::string vsCode = getVertexShaderCode();
const char* vsCodePtr = (const char*)vsCode.c_str();
/* Get fragment shader code */
std::string fshaderCode = getFragmentShaderCode();
const char* fshaderCodePtr = (const char*)fshaderCode.c_str();
/* Build program */
if (!buildProgram(m_po_id, m_fs_id, 1, &fshaderCodePtr, m_vs_id, 1, &vsCodePtr))
{
TCU_FAIL("Program could not have been created sucessfully from a valid vertex/fragment shader!");
}
createTextures();
}
/** Set data for input texture
*
* @param buffer reference to buffer where initial data will be stored
*/
template <typename InputType, typename OutputType>
void TextureBorderClampSamplingTexture<InputType, OutputType>::setInitData(std::vector<InputType>& buffer)
{
const InputType initDataTexel = m_test_configuration.get_init_value();
glw::GLuint size = m_test_configuration.get_width() * m_test_configuration.get_height() *
m_test_configuration.get_depth() * m_test_configuration.get_n_in_components();
for (glw::GLuint i = 0; i < size; ++i)
{
buffer[i] = initDataTexel;
}
}
/** Create input and output textures
*
*/
template <typename InputType, typename OutputType>
void TextureBorderClampSamplingTexture<InputType, OutputType>::createTextures(void)
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Generate input texture */
gl.genTextures(1, &m_input_to_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "Error generating texture object!");
/* Bind input texture */
gl.bindTexture(m_test_configuration.get_target(), m_input_to_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding texture object!");
glw::GLsizei components = m_test_configuration.get_n_in_components();
glw::GLsizei texelsNumber =
m_test_configuration.get_width() * m_test_configuration.get_height() * m_test_configuration.get_depth();
/* Allocate storage for input texture and fill it with data */
{
switch (m_test_configuration.get_target())
{
case GL_TEXTURE_2D:
{
gl.texStorage2D(m_test_configuration.get_target(), /* target */
1, /* levels */
m_test_configuration.get_input_internal_format(), /* internalformat */
m_test_configuration.get_width(), /* width */
m_test_configuration.get_height()); /* height */
GLU_EXPECT_NO_ERROR(gl.getError(), "Error allocating storage for texture object!");
if (m_test_configuration.get_input_internal_format() == GL_COMPRESSED_RGBA8_ETC2_EAC)
{
gl.compressedTexSubImage2D(m_test_configuration.get_target(), /* target */
0, /* level */
0, /* xoffset */
0, /* yoffset */
m_test_configuration.get_width(), /* width */
m_test_configuration.get_height(), /* height */
m_test_configuration.get_input_internal_format(), /* internalformat */
sizeof(compressed_image_data_2D), /* image size */
compressed_image_data_2D); /* data */
GLU_EXPECT_NO_ERROR(gl.getError(), "Error filling texture with compressed data!");
}
else
{
std::vector<InputType> inputData(components * texelsNumber);
setInitData(inputData);
gl.texSubImage2D(m_test_configuration.get_target(), /* target */
0, /* level */
0, /* xoffset */
0, /* yoffset */
m_test_configuration.get_width(), /* width */
m_test_configuration.get_height(), /* height */
m_test_configuration.get_input_format(), /* format */
m_test_configuration.get_input_type(), /* type */
&inputData[0]); /* data */
GLU_EXPECT_NO_ERROR(gl.getError(), "Error filling texture with data!");
}
break;
}
case GL_TEXTURE_2D_ARRAY:
case GL_TEXTURE_3D:
{
gl.texStorage3D(m_test_configuration.get_target(), /* target */
1, /* levels */
m_test_configuration.get_input_internal_format(), /* internalformat*/
m_test_configuration.get_width(), /* width */
m_test_configuration.get_height(), /* height */
m_test_configuration.get_depth()); /* depth */
GLU_EXPECT_NO_ERROR(gl.getError(), "Error allocating storage for texture object!");
if (m_test_configuration.get_input_internal_format() == GL_COMPRESSED_RGBA8_ETC2_EAC)
{
gl.compressedTexSubImage3D(m_test_configuration.get_target(), /* target */
0, /* level */
0, /* xoffset */
0, /* yoffset */
0, /* zoffset */
m_test_configuration.get_width(), /* width */
m_test_configuration.get_height(), /* height */
m_test_configuration.get_depth(), /* depth */
m_test_configuration.get_input_internal_format(), /* internalformat */
sizeof(compressed_image_data_2D_array), /* image size */
compressed_image_data_2D_array); /* data */
GLU_EXPECT_NO_ERROR(gl.getError(), "Error filling texture with compressed data!");
}
else
{
std::vector<InputType> inputData(components * texelsNumber);
setInitData(inputData);
gl.texSubImage3D(m_test_configuration.get_target(), /* target */
0, /* level */
0, /* xoffset */
0, /* yoffset */
0, /* zoffset */
m_test_configuration.get_width(), /* width */
m_test_configuration.get_height(), /* height */
m_test_configuration.get_depth(), /* depth */
m_test_configuration.get_input_format(), /* format */
m_test_configuration.get_input_type(), /* type */
&inputData[0]); /* data */
GLU_EXPECT_NO_ERROR(gl.getError(), "Error filling texture with data!");
}
break;
}
default:
TCU_FAIL("Test parameters can contain only following targets: GL_TEXTURE_2D, GL_TEXTURE_2D_ARRAY, "
"GL_TEXTURE_3D!");
}
}
/* Generate output texture */
gl.genTextures(1, &m_output_to_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "Error generating texture object!");
/* Bind output texture */
gl.bindTexture(GL_TEXTURE_2D, m_output_to_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding texture object!");
/* Allocate storage for output texture */
gl.texStorage2D(GL_TEXTURE_2D, 1, m_test_configuration.get_output_internal_format(),
m_test_configuration.get_width(), m_test_configuration.get_height());
GLU_EXPECT_NO_ERROR(gl.getError(), "Error allocating storage for texture object!");
}
/** Executes the test.
*
* Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
*
* Note the function throws exception should an error occur!
*
* @return STOP if the test has finished, CONTINUE to indicate iterate should be called once again.
**/
template <typename InputType, typename OutputType>
tcu::TestNode::IterateResult TextureBorderClampSamplingTexture<InputType, OutputType>::iterate(void)
{
/* Initialize test case */
initTest();
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
bool testResult = true;
gl.useProgram(m_po_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "Error using program!");
/* Configure vertices position attribute */
gl.bindBuffer(GL_ARRAY_BUFFER, m_position_vbo_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "Could not bind buffer object!");
m_attr_position_location = gl.getAttribLocation(m_po_id, "vertex_position_in");
GLU_EXPECT_NO_ERROR(gl.getError(), "Could not get attribute location!");
gl.vertexAttribPointer(m_attr_position_location, 4, GL_FLOAT, GL_FALSE, 0, 0);
GLU_EXPECT_NO_ERROR(gl.getError(), "Could not set vertex attribute pointer!");
gl.enableVertexAttribArray(m_attr_position_location);
GLU_EXPECT_NO_ERROR(gl.getError(), "Could not enable vertex attribute array!");
/* Configure texture coordinates attribute */
gl.bindBuffer(GL_ARRAY_BUFFER, m_text_coord_vbo_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "Could not bind buffer object!");
m_attr_texcoord_location = gl.getAttribLocation(m_po_id, "texture_coords_in");
GLU_EXPECT_NO_ERROR(gl.getError(), "Could not get attribute location!");
gl.vertexAttribPointer(m_attr_texcoord_location, 2, GL_FLOAT, GL_FALSE, 0, 0);
GLU_EXPECT_NO_ERROR(gl.getError(), "Could not set vertex attribute pointer!");
gl.enableVertexAttribArray(m_attr_texcoord_location);
GLU_EXPECT_NO_ERROR(gl.getError(), "Could not enable vertex attribute array!");
/* Configure and bind sampler to texture unit */
gl.activeTexture(GL_TEXTURE0);
GLU_EXPECT_NO_ERROR(gl.getError(), "Error setting active texture unit!");
gl.bindTexture(m_test_configuration.get_target(), m_input_to_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding texture!");
glw::GLint samplerLocation = gl.getUniformLocation(m_po_id, "test_sampler");
GLU_EXPECT_NO_ERROR(gl.getError(), "Erros getting sampler location!");
gl.uniform1i(samplerLocation, m_texture_unit);
GLU_EXPECT_NO_ERROR(gl.getError(), "Could not bind sampler location to texture unit!");
gl.bindSampler(m_texture_unit, m_sampler_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "Could not bind sampler object to texture unit!");
/* Set GL_TEXTURE_BORDER_COLOR_EXT for sampler object */
switch (m_test_configuration.get_input_internal_format())
{
case GL_RGBA32F:
case GL_RGBA8:
case GL_DEPTH_COMPONENT32F:
case GL_DEPTH_COMPONENT16:
case GL_COMPRESSED_RGBA8_ETC2_EAC:
{
glw::GLfloat val = (glw::GLfloat)m_test_configuration.get_init_border_color();
glw::GLfloat border_color[] = { val, val, val, val };
gl.samplerParameterfv(m_sampler_id, m_glExtTokens.TEXTURE_BORDER_COLOR, border_color);
break;
}
case GL_R32UI:
{
glw::GLuint val = (glw::GLuint)m_test_configuration.get_init_border_color();
glw::GLuint border_color[] = { val, val, val, val };
gl.samplerParameterIuiv(m_sampler_id, m_glExtTokens.TEXTURE_BORDER_COLOR, border_color);
break;
}
case GL_R32I:
{
glw::GLint val = (glw::GLint)m_test_configuration.get_init_border_color();
glw::GLint border_color[] = { val, val, val, val };
gl.samplerParameterIiv(m_sampler_id, m_glExtTokens.TEXTURE_BORDER_COLOR, border_color);
break;
}
default:
throw tcu::TestError("Unsupported sized internal format. Should never happen!", "", __FILE__, __LINE__);
break;
};
GLU_EXPECT_NO_ERROR(gl.getError(), "Error setting border color parameter!");
/* Set sampler's GL_TEXTURE_WRAP_* parameters values to GL_CLAMP_TO_BORDER_EXT */
gl.samplerParameteri(m_sampler_id, GL_TEXTURE_WRAP_S, m_glExtTokens.CLAMP_TO_BORDER);
GLU_EXPECT_NO_ERROR(gl.getError(), "Error setting GL_TEXTURE_WRAP_S parameter!");
gl.samplerParameteri(m_sampler_id, GL_TEXTURE_WRAP_R, m_glExtTokens.CLAMP_TO_BORDER);
GLU_EXPECT_NO_ERROR(gl.getError(), "Error setting GL_TEXTURE_WRAP_R parameter!");
gl.samplerParameteri(m_sampler_id, GL_TEXTURE_WRAP_T, m_glExtTokens.CLAMP_TO_BORDER);
GLU_EXPECT_NO_ERROR(gl.getError(), "Error setting GL_TEXTURE_WRAP_T parameter!");
/* Set GL_TEXTURE_MAG_FILTER and GL_TEXTURE_MIN_FILTER parameters values */
gl.samplerParameteri(m_sampler_id, GL_TEXTURE_MAG_FILTER, m_test_configuration.get_filtering());
GLU_EXPECT_NO_ERROR(gl.getError(), "Error setting value for GL_TEXTURE_MAG_FILTER parameter!");
gl.samplerParameteri(m_sampler_id, GL_TEXTURE_MIN_FILTER, m_test_configuration.get_filtering());
GLU_EXPECT_NO_ERROR(gl.getError(), "Error setting value for GL_TEXTURE_MIN_FILTER parameter!");
for (glw::GLint i = getStartingLayerIndex(); i < getLastLayerIndex(); ++i)
{
/* Configure layer (third texture coordinate) */
glw::GLint layerLocation = gl.getUniformLocation(m_po_id, "layer");
GLU_EXPECT_NO_ERROR(gl.getError(), "Error getting layer uniform location!");
gl.uniform1f(layerLocation, getCoordinateValue(i));
GLU_EXPECT_NO_ERROR(gl.getError(), "Error setting layer uniform variable!");
/* Bind framebuffer object */
gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, m_fbo_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding framebuffer object!");
/* Set view port */
gl.viewport(0, /* x */
0, /* y */
m_test_configuration.get_width(), /* width */
m_test_configuration.get_height()); /* height */
GLU_EXPECT_NO_ERROR(gl.getError(), "Error setting view port!");
/* Attach texture to framebuffer */
gl.framebufferTexture2D(GL_DRAW_FRAMEBUFFER, /* target */
GL_COLOR_ATTACHMENT0, /* attachment */
GL_TEXTURE_2D, /* textarget */
m_output_to_id, /* texture */
0); /* level */
GLU_EXPECT_NO_ERROR(gl.getError(), "Could not attach texture object to GL_COLOR_ATTACHMENT0!");
/* Check framebuffer status */
checkFramebufferStatus(GL_DRAW_FRAMEBUFFER);
/* Clear the color buffer with (0.5, 0.5, 0.5, 1) color */
gl.clear(GL_COLOR_BUFFER_BIT);
GLU_EXPECT_NO_ERROR(gl.getError(), "Error clearing color buffer");
/* Render */
gl.drawArrays(GL_TRIANGLE_STRIP, 0, 4);
GLU_EXPECT_NO_ERROR(gl.getError(), "Rendering failed!");
/* Get data from framebuffer's color attachment and compare with expected values.
* For GL_NEAREST filtering and GL_TEXTURE_3D texture target and Layer equal to
* -1 or Depth the whole texture is expected to be filled with border color
*/
OutputType expectedColor;
switch (m_test_configuration.get_target())
{
case GL_TEXTURE_2D:
case GL_TEXTURE_2D_ARRAY:
expectedColor = m_test_configuration.get_expected_value();
break;
case GL_TEXTURE_3D:
if (i > -1 && i < (glw::GLint)m_test_configuration.get_depth())
expectedColor = m_test_configuration.get_expected_value();
else
expectedColor = m_test_configuration.get_expected_border_color();
break;
default:
TCU_FAIL("Not allowed texture target - should be one of GL_TEXTURE_2D, GL_TEXTURE_2D_ARRAY, GL_TEXTURE_3D");
}
if (!checkResult(expectedColor, m_test_configuration.get_expected_border_color(), i))
{
testResult = false;
}
}
if (testResult)
{
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
}
else
{
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
}
return STOP;
}
/** Deinitializes GLES objects created during the test.
*
*/
template <typename InputType, typename OutputType>
void TextureBorderClampSamplingTexture<InputType, OutputType>::deinit(void)
{
/* Get GL entry points */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Reset Gl state */
gl.bindTexture(GL_TEXTURE_2D, 0);
gl.bindTexture(GL_TEXTURE_2D_ARRAY, 0);
gl.bindTexture(GL_TEXTURE_3D, 0);
gl.bindBuffer(GL_ARRAY_BUFFER, 0);
gl.bindSampler(m_texture_unit, 0);
gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
gl.bindFramebuffer(GL_READ_FRAMEBUFFER, 0);
gl.bindVertexArray(0);
if (m_attr_position_location != -1)
{
gl.disableVertexAttribArray(m_attr_position_location);
m_attr_position_location = -1;
}
if (m_attr_texcoord_location != -1)
{
gl.disableVertexAttribArray(m_attr_texcoord_location);
m_attr_texcoord_location = -1;
}
gl.useProgram(0);
/* Delete Gl objects */
if (m_fbo_id != 0)
{
gl.deleteFramebuffers(1, &m_fbo_id);
m_fbo_id = 0;
}
if (m_po_id != 0)
{
gl.deleteProgram(m_po_id);
m_po_id = 0;
}
if (m_fs_id != 0)
{
gl.deleteShader(m_fs_id);
m_fs_id = 0;
}
if (m_vs_id != 0)
{
gl.deleteShader(m_vs_id);
m_vs_id = 0;
}
if (m_input_to_id != 0)
{
gl.deleteTextures(1, &m_input_to_id);
m_input_to_id = 0;
}
if (m_output_to_id != 0)
{
gl.deleteTextures(1, &m_output_to_id);
m_output_to_id = 0;
}
if (m_sampler_id != 0)
{
gl.deleteSamplers(1, &m_sampler_id);
m_sampler_id = 0;
}
if (m_position_vbo_id != 0)
{
gl.deleteBuffers(1, &m_position_vbo_id);
m_position_vbo_id = 0;
}
if (m_text_coord_vbo_id != 0)
{
gl.deleteBuffers(1, &m_text_coord_vbo_id);
m_text_coord_vbo_id = 0;
}
if (m_vao_id != 0)
{
gl.deleteVertexArrays(1, &m_vao_id);
m_vao_id = 0;
}
/* Deinitialize base class */
TestCaseBase::deinit();
}
/** Check Framebuffer Status - throw exception if status is different than GL_FRAMEBUFFER_COMPLETE
*
* @param framebuffer - GL_DRAW_FRAMEBUFFER, GL_READ_FRAMEBUFFER or GL_FRAMEBUFFER
*
*/
template <typename InputType, typename OutputType>
void TextureBorderClampSamplingTexture<InputType, OutputType>::checkFramebufferStatus(glw::GLenum framebuffer)
{
/* Get GL entry points */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Check framebuffer status */
glw::GLenum framebufferStatus = gl.checkFramebufferStatus(framebuffer);
if (GL_FRAMEBUFFER_COMPLETE != framebufferStatus)
{
switch (framebufferStatus)
{
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
{
TCU_FAIL("Framebuffer incomplete, status: GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT");
}
case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS:
{
TCU_FAIL("Framebuffer incomplete, status: GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS");
}
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
{
TCU_FAIL("Framebuffer incomplete, status: GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT");
}
case GL_FRAMEBUFFER_UNSUPPORTED:
{
TCU_FAIL("Framebuffer incomplete, status: GL_FRAMEBUFFER_UNSUPPORTED");
}
default:
{
TCU_FAIL("Framebuffer incomplete, status not recognized");
}
}
} /* if (GL_FRAMEBUFFER_COMPLETE != framebuffer_status) */
}
/** Get result data and check if it is as expected
*
* @return returns true if result data is as expected, otherwise returns false
*/
template <typename InputType, typename OutputType>
bool TextureBorderClampSamplingTexture<InputType, OutputType>::checkResult(OutputType expectedValue,
OutputType expectedBorderColor,
glw::GLint layer)
{
/* Get GL entry points */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Bind draw framebuffer to read framebuffer */
gl.bindFramebuffer(GL_READ_FRAMEBUFFER, m_fbo_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding framebuffer object!");
std::vector<OutputType> resultData(m_test_configuration.get_width() * m_test_configuration.get_height() *
m_test_configuration.get_n_out_components());
/* Read data from framebuffer */
gl.readPixels(0, /* x */
0, /* y */
m_test_configuration.get_width(), /* width */
m_test_configuration.get_height(), /* height */
m_test_configuration.get_output_format(), /* format */
m_test_configuration.get_output_type(), /* type */
&resultData[0]); /* data */
GLU_EXPECT_NO_ERROR(gl.getError(), "Error reading pixels from color buffer");
/* Choose comparision method depending on filtering mode */
if (m_test_configuration.get_filtering() == GL_NEAREST)
{
return checkNearest(resultData, expectedValue, expectedBorderColor, layer);
}
else
{
return checkLinear(resultData, layer);
}
}
/** Create fragment shader code
*
* @return string with fragment shader code
*/
template <typename InputType, typename OutputType>
std::string TextureBorderClampSamplingTexture<InputType, OutputType>::getFragmentShaderCode(void)
{
std::stringstream result;
std::string coordType;
std::string samplerType;
std::string outType;
std::string outCommand;
/* Check input texture format and prepare sampler prefix */
switch (m_test_configuration.get_input_internal_format())
{
case GL_RGBA32F:
case GL_RGBA8:
case GL_DEPTH_COMPONENT32F:
case GL_DEPTH_COMPONENT16:
case GL_COMPRESSED_RGBA8_ETC2_EAC:
samplerType = "";
break;
case GL_R32UI:
samplerType = "u";
break;
case GL_R32I:
samplerType = "i";
break;
default:
throw tcu::TestError("Not allowed internal format", "", __FILE__, __LINE__);
}
/* Check input texture target and prepare approperiate texture coordinate type and sampler type */
switch (m_test_configuration.get_target())
{
case GL_TEXTURE_2D:
coordType = "vec2";
samplerType += "sampler2D";
break;
case GL_TEXTURE_2D_ARRAY:
coordType = "vec3";
samplerType += "sampler2DArray";
break;
case GL_TEXTURE_3D:
coordType = "vec3";
samplerType += "sampler3D";
break;
default:
throw tcu::TestError("Not allowed texture target!", "", __FILE__, __LINE__);
}
/* Check output texture format and prepare approperiate texel fetching method and output type */
switch (m_test_configuration.get_output_internal_format())
{
case GL_RGBA8:
outType = "vec4";
outCommand = "texture(test_sampler, texture_coords_out)";
break;
case GL_R8:
outType = "float";
outCommand = "texture(test_sampler, texture_coords_out).x";
break;
case GL_R32UI:
outType = "uint";
outCommand = "uint(texture(test_sampler, texture_coords_out).x)";
break;
case GL_R32I:
outType = "int";
outCommand = "int(texture(test_sampler, texture_coords_out).x)";
break;
default:
throw tcu::TestError("Not allowed internal format!", "", __FILE__, __LINE__);
}
result << "${VERSION}\n"
"\n"
"precision highp float;\n"
"precision highp "
<< samplerType << ";\n"
"\n"
"uniform "
<< samplerType << " test_sampler;\n"
"in "
<< coordType << " texture_coords_out;\n"
"layout(location = 0) out "
<< outType << " color;\n"
"\n"
"void main()\n"
"{\n"
" color = "
<< outCommand << ";\n"
"}\n";
return result.str();
}
/** Create vertex shader code
*
* @return string with vertex shader code
*/
template <typename InputType, typename OutputType>
std::string TextureBorderClampSamplingTexture<InputType, OutputType>::getVertexShaderCode(void)
{
std::stringstream result;
std::string coordType;
std::string coordAssignment;
/* Check input texture target and prepare approperiate coordinate type and coordinate assignment method */
switch (m_test_configuration.get_target())
{
case GL_TEXTURE_2D:
coordType = "vec2";
coordAssignment = "texture_coords_in";
break;
case GL_TEXTURE_2D_ARRAY:
case GL_TEXTURE_3D:
coordType = "vec3";
coordAssignment = "vec3(texture_coords_in, layer)";
break;
default:
throw tcu::TestError("Not allowed texture target!", "", __FILE__, __LINE__);
}
result << "${VERSION}\n"
"\n"
"precision highp float;\n"
"\n"
"layout (location = 0) in vec4 vertex_position_in;\n"
"layout (location = 1) in vec2 texture_coords_in;\n"
"out "
<< coordType << " texture_coords_out;\n"
"uniform float layer;\n"
"\n"
"void main()\n"
"{\n"
" gl_Position = vertex_position_in;\n"
" texture_coords_out = "
<< coordAssignment << ";\n"
"}\n";
return result.str();
}
/** Check if result data is the same as expected data when GL_NEAREST filtering is set
* @param buffer reference to the buffer with result data
* @param expectedValue it is the value which should be read from texture if coordinates are inside of [0,1]
* @param expectedBorderColor it is the value which should be read from texture if coordinates are outside of [0,1]
* @return returns true if result data is as expected, otherwise returns false
*/
template <typename InputType, typename OutputType>
bool TextureBorderClampSamplingTexture<InputType, OutputType>::checkNearest(std::vector<OutputType>& buffer,
OutputType expectedValue,
OutputType expectedBorderColor,
glw::GLint layer)
{
glw::GLuint width = m_test_configuration.get_width();
glw::GLuint height = m_test_configuration.get_height();
glw::GLuint in_components = m_test_configuration.get_n_in_components();
glw::GLuint out_components = m_test_configuration.get_n_out_components();
glw::GLuint outRowWidth = m_test_configuration.get_width() * out_components;
glw::GLuint index = 0;
/* Check if center point is equal to expectedValue */
std::pair<glw::GLuint, glw::GLuint> centerPoint(width / 2, height / 2);
for (glw::GLuint i = 0; i < deMinu32(out_components, in_components); ++i)
{
index = centerPoint.second * outRowWidth + centerPoint.first * out_components + i;
if (buffer[index] != expectedValue)
{
m_testCtx.getLog() << tcu::TestLog::Message << "Wrong value for layer (" << layer << ") at point (x,y) = ("
<< centerPoint.first << "," << centerPoint.second << ") , component (" << i << ")\n"
<< "Expected value [" << (glw::GLint)expectedValue << "]\n"
<< "Result value [" << (glw::GLint)buffer[index] << "]\n"
<< tcu::TestLog::EndMessage;
return false;
}
}
/* Check if following points (marked as BC) contain values equal border color
*
* (-1, -1) (0, -1) (1, -1) (2, -1)
* *-------+-------+-------*
* | | | |
* | BC | BC | BC |
* | | | |
* (-1, 0) +-------+-------+-------+ (2, 0)
* | | | |
* | BC | 0 | BC |
* | | | |
* (-1, 1) +-------+-------+-------+ (2, 1)
* | | | |
* | BC | BC | BC |
* | | | |
* *-------+-------+-------*
* (-1, 2) (0, 2) (1, 2) (2, 2)
*/
std::vector<std::pair<glw::GLuint, glw::GLuint> > borderPoints;
borderPoints.push_back(std::pair<glw::GLuint, glw::GLuint>(width / 6, height / 6));
borderPoints.push_back(std::pair<glw::GLuint, glw::GLuint>(width / 2, height / 6));
borderPoints.push_back(std::pair<glw::GLuint, glw::GLuint>((glw::GLuint)(width / 6.0 * 5), height / 6));
borderPoints.push_back(std::pair<glw::GLuint, glw::GLuint>(width / 6, height / 2));
borderPoints.push_back(std::pair<glw::GLuint, glw::GLuint>((glw::GLuint)(width / 6.0 * 5), height / 2));
borderPoints.push_back(std::pair<glw::GLuint, glw::GLuint>(width / 6, (glw::GLuint)(height / 6.0 * 5)));
borderPoints.push_back(std::pair<glw::GLuint, glw::GLuint>(width / 2, (glw::GLuint)(height / 6.0 * 5)));
borderPoints.push_back(
std::pair<glw::GLuint, glw::GLuint>((glw::GLuint)(width / 6.0 * 5), (glw::GLuint)(height / 6.0 * 5)));
for (glw::GLuint j = 0; j < borderPoints.size(); ++j)
{
for (glw::GLuint i = 0; i < deMinu32(out_components, in_components); ++i)
{
index = borderPoints[j].second * outRowWidth + borderPoints[j].first * out_components + i;
if (buffer[index] != expectedBorderColor)
{
m_testCtx.getLog() << tcu::TestLog::Message << "Wrong value for layer (" << layer
<< ") at point (x,y) = (" << borderPoints[j].first << "," << borderPoints[j].second
<< ") , component (" << i << ")\n"
<< "Expected value [" << (glw::GLint)expectedBorderColor << "]\n"
<< "Result value [" << (glw::GLint)buffer[index] << "]\n"
<< tcu::TestLog::EndMessage;
return false;
}
}
}
return true;
}
/** Check if result data is as expected when GL_LINEAR filtering is set
*
* @param buffer reference to the buffer with result data
* @return returns true if result data is as expected, otherwise return false
*/
template <typename InputType, typename OutputType>
bool TextureBorderClampSamplingTexture<InputType, OutputType>::checkLinear(std::vector<OutputType>& buffer,
glw::GLint layer)
{
glw::GLuint centerX = m_test_configuration.get_width() / 2;
glw::GLuint centerY = m_test_configuration.get_height() / 2;
glw::GLuint stepX = m_test_configuration.get_width() / 3;
glw::GLuint stepY = m_test_configuration.get_height() / 3;
glw::GLuint index = 0;
glw::GLuint in_components = m_test_configuration.get_n_in_components();
glw::GLuint out_components = m_test_configuration.get_n_out_components();
glw::GLuint outRowWidth = m_test_configuration.get_width() * out_components;
/* Check values from center to the bottom */
for (glw::GLuint y = centerY; y < centerY + stepY; ++y)
{
for (glw::GLuint c = 0; c < deMinu32(out_components, in_components); ++c)
{
index = y * outRowWidth + centerX * out_components + c;
if (buffer[index + outRowWidth] - buffer[index] < 0)
{
m_testCtx.getLog() << tcu::TestLog::Message << "For layer (" << layer
<< ") when moving from center point (x, y) = (" << centerX << "," << centerY
<< ") to the bottom\n"
<< "at point (x, y) = (" << centerX << "," << y
<< ") - texel values stopped to be monotonically increasing\n"
<< tcu::TestLog::EndMessage;
return false;
}
}
}
/* Check values from center to the top */
for (glw::GLuint y = centerY; y > centerY - stepY; --y)
{
for (glw::GLuint c = 0; c < deMinu32(out_components, in_components); ++c)
{
index = y * outRowWidth + centerX * out_components + c;
if (buffer[index - outRowWidth] - buffer[index] < 0)
{
m_testCtx.getLog() << tcu::TestLog::Message << "For layer (" << layer
<< ") when moving from center point (x, y) = (" << centerX << "," << centerY
<< ") to the top\n"
<< "at point (x, y) = (" << centerX << "," << y
<< ")- texel values stopped to be monotonically increasing\n"
<< tcu::TestLog::EndMessage;
return false;
}
}
}
/* Check values from center to the right */
for (glw::GLuint x = centerX; x < centerX + stepX; ++x)
{
for (glw::GLuint c = 0; c < deMinu32(out_components, in_components); ++c)
{
index = centerY + x * out_components + c;
if (buffer[index + out_components] - buffer[index] < 0)
{
m_testCtx.getLog() << tcu::TestLog::Message << "For layer (" << layer
<< ") when moving from center point (x, y) = (" << centerX << "," << centerY
<< ") to the right\n"
<< "at point (x, y) = (" << x << "," << centerY
<< ")- texel values stopped to be monotonically increasing\n"
<< tcu::TestLog::EndMessage;
return false;
}
}
}
/* Check values from center to the left */
for (glw::GLuint x = centerY; x > centerX - stepX; --x)
{
for (glw::GLuint c = 0; c < deMinu32(out_components, in_components); ++c)
{
index = centerY + x * out_components + c;
if (buffer[index - out_components] - buffer[index] < 0)
{
m_testCtx.getLog() << tcu::TestLog::Message << "For layer (" << layer
<< ") when moving from center point (x, y) = (" << centerX << "," << centerY
<< ") to the left\n"
<< "at point (x, y) = (" << x << "," << centerY
<< ")- texel values stopped to be monotonically increasing\n"
<< tcu::TestLog::EndMessage;
return false;
}
}
}
return true;
}
/** Returns start layer index
*
* @return returns start layer index (0 for GL_TEXTURE_2D target , otherwise -1)
*/
template <typename InputType, typename OutputType>
glw::GLint TextureBorderClampSamplingTexture<InputType, OutputType>::getStartingLayerIndex()
{
switch (m_test_configuration.get_target())
{
case GL_TEXTURE_2D:
case GL_TEXTURE_2D_ARRAY:
return 0;
case GL_TEXTURE_3D:
return -1;
default:
TCU_FAIL("Not allowed texture target - should be one of GL_TEXTURE_2D, GL_TEXTURE_2D_ARRAY, GL_TEXTURE_3D");
}
}
/** Returns last layer index
*
* @return returns last layer index (1 for GL_TEXTURE_2D target , otherwise depth + 1)
*/
template <typename InputType, typename OutputType>
glw::GLint TextureBorderClampSamplingTexture<InputType, OutputType>::getLastLayerIndex()
{
switch (m_test_configuration.get_target())
{
case GL_TEXTURE_2D:
case GL_TEXTURE_2D_ARRAY:
return m_test_configuration.get_depth();
case GL_TEXTURE_3D:
return m_test_configuration.get_depth() + 1;
default:
TCU_FAIL("Not allowed texture target - should be one of GL_TEXTURE_2D, GL_TEXTURE_2D_ARRAY, GL_TEXTURE_3D");
}
}
/** Returns third texture coordinate to access a particular layer in a texture
*
* @return returns third texture coordinate
*/
template <typename InputType, typename OutputType>
glw::GLfloat TextureBorderClampSamplingTexture<InputType, OutputType>::getCoordinateValue(glw::GLint index)
{
switch (m_test_configuration.get_target())
{
case GL_TEXTURE_2D:
return 0.0f;
break;
case GL_TEXTURE_2D_ARRAY:
return (glw::GLfloat)index;
case GL_TEXTURE_3D:
return static_cast<glw::GLfloat>(index) / static_cast<glw::GLfloat>(m_test_configuration.get_depth());
default:
TCU_FAIL("Not allowed texture target - should be one of GL_TEXTURE_2D, GL_TEXTURE_2D_ARRAY, GL_TEXTURE_3D");
}
}
} // namespace glcts