blob: d7a79cdb6113134996dc4f6877c7af9d0c31e670 [file] [log] [blame]
/*-------------------------------------------------------------------------
* OpenGL Conformance Test Suite
* -----------------------------
*
* Copyright (c) 2021 Google Inc.
* Copyright (c) 2021 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 glcTexSubImageTests.cpp
* \brief Texture compatibility tests
*/ /*-------------------------------------------------------------------*/
#include "glcTextureCompatibilityTests.hpp"
#include "glwEnums.hpp"
#include "glwFunctions.hpp"
#include "tcuImageCompare.hpp"
#include "tcuStringTemplate.hpp"
#include "tcuSurface.hpp"
#include "tcuTestLog.hpp"
#include "tcuTextureUtil.hpp"
#include "gluDefs.hpp"
#include "gluDrawUtil.hpp"
#include "gluPixelTransfer.hpp"
#include "gluShaderProgram.hpp"
#include "gluStrUtil.hpp"
#include "gluTextureUtil.hpp"
#include <map>
#include <memory>
#include <vector>
namespace glcts
{
namespace
{
const float vertexPositions[] =
{
-1.0f, -1.0f,
1.0f, -1.0f,
-1.0f, 1.0f,
1.0f, 1.0f,
};
const float vertexTexCoords[] =
{
0.0f, 0.0f,
1.0f, 0.0f,
0.0f, 1.0f,
1.0f, 1.0f,
};
const char* vertShader =
"${VERSION}\n"
"in highp vec4 in_position;\n"
"in highp vec2 in_texCoord;\n"
"out highp vec2 v_texCoord;\n"
"void main (void)\n"
"{\n"
" gl_Position = in_position;\n"
" v_texCoord = in_texCoord;\n"
"}\n";
const char* fragShader =
"${VERSION}\n"
"precision mediump float;\n"
"uniform sampler2D texture0;\n"
"in vec2 v_texCoord;\n"
"out vec4 color;\n"
"void main(void)\n"
"{\n"
" color = texture(texture0, v_texCoord);\n"
"}";
struct TestParameters
{
std::string testName;
glw::GLenum internalFormat;
glw::GLenum format;
glw::GLenum testType;
};
static const TestParameters testParameters[] =
{
{ "rgba4_unsigned_byte", GL_RGBA4, GL_RGBA, GL_UNSIGNED_BYTE },
{ "rgb5_a1_unsigned_byte", GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_BYTE },
{ "rgb5_a1_unsigned_int_10_a2", GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV },
{ "r16f_float", GL_R16F, GL_RED, GL_FLOAT },
{ "rg16f_float", GL_RG16F, GL_RG, GL_FLOAT },
{ "rgb16f_float", GL_RGB16F, GL_RGB, GL_FLOAT },
{ "rgba16f_float", GL_RGBA16F, GL_RGBA, GL_FLOAT },
{ "r11f_g11f_b10f_half_float", GL_R11F_G11F_B10F, GL_RGB, GL_HALF_FLOAT },
{ "r11f_g11f_b10f_float", GL_R11F_G11F_B10F, GL_RGB, GL_FLOAT },
{ "rgb9_e5_half_float", GL_RGB9_E5, GL_RGB, GL_HALF_FLOAT },
{ "rgb9_e5_float", GL_RGB9_E5, GL_RGB, GL_FLOAT },
{ "rgb565_unsigned_byte", GL_RGB565, GL_RGB, GL_UNSIGNED_BYTE },
{ "depth_component16_uint", GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT }
};
class SubImageFormatTest : public deqp::TestCase
{
public:
SubImageFormatTest(deqp::Context& context, const TestParameters testParam, glw::GLsizei textureSize);
virtual ~SubImageFormatTest();
virtual void init (void);
virtual void deinit (void);
virtual IterateResult iterate (void);
private:
void setTextureParameters (glw::GLenum target);
void drawTexture (void);
void initializeProgram();
void setVertexBufferObjects();
void setVertexArrayObjects();
std::shared_ptr<glu::ShaderProgram> m_program;
TestParameters m_testParams;
glw::GLsizei m_textureSize;
glw::GLuint m_texId;
glw::GLuint m_vaoId;
glw::GLenum m_vboIds[2];
};
SubImageFormatTest::SubImageFormatTest (deqp::Context& context, const TestParameters testParams, glw::GLsizei textureSize)
: deqp::TestCase (context, ("texsubimage_format_" + testParams.testName).c_str(), "Pass glTexSubImage with different client format to glTexImage")
, m_testParams (testParams)
, m_textureSize (textureSize)
, m_texId (0)
, m_vaoId (0)
, m_vboIds { 0, 0 }
{
}
SubImageFormatTest::~SubImageFormatTest()
{
}
void SubImageFormatTest::init(void)
{
initializeProgram();
setVertexBufferObjects();
setVertexArrayObjects();
}
void SubImageFormatTest::deinit(void)
{
const auto& gl = m_context.getRenderContext().getFunctions();
gl.deleteTextures(1, &m_texId);
GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteTextures() failed");
gl.deleteBuffers(1, &m_vaoId);
GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteBuffers() failed");
gl.deleteBuffers(DE_LENGTH_OF_ARRAY(m_vboIds), m_vboIds);
GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteBuffers() failed");
}
SubImageFormatTest::IterateResult SubImageFormatTest::iterate(void)
{
const auto& gl = m_context.getRenderContext().getFunctions();
m_context.getTestContext().setTestResult(QP_TEST_RESULT_FAIL, "Fail");
// Render buffer
glw::GLuint rboId;
gl.genRenderbuffers(1, &rboId);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGenRenderbuffers() failed");
gl.bindRenderbuffer(GL_RENDERBUFFER, rboId);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindRenderbuffer() failed");
gl.renderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, m_textureSize, m_textureSize);
GLU_EXPECT_NO_ERROR(gl.getError(), "glRenderbufferStorage() failed");
gl.bindRenderbuffer(GL_RENDERBUFFER, 0);
// Frame buffer
glw::GLuint fboId;
gl.genFramebuffers(1, &fboId);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGenFramebuffers() failed");
gl.bindFramebuffer(GL_FRAMEBUFFER, fboId);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffer() failed");
gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rboId);
GLU_EXPECT_NO_ERROR(gl.getError(), "glFramebufferRenderbuffer() failed");
gl.viewport(0, 0, m_textureSize, m_textureSize);
GLU_EXPECT_NO_ERROR(gl.getError(), "glViewport() failed");
gl.disable(GL_BLEND);
gl.bindTexture(GL_TEXTURE_2D, m_texId);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() failed");
gl.bindVertexArray(m_vaoId);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray() failed");
// Create main texture.
tcu::TextureFormat refTexFormat (glu::mapGLInternalFormat(m_testParams.internalFormat));
glu::TransferFormat refTransferFormat = glu::getTransferFormat(refTexFormat);
tcu::Texture2D refTexture (refTexFormat, m_textureSize, m_textureSize, 1);
refTexture.allocLevel(0);
tcu::fillWithComponentGradients(refTexture.getLevel(0), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f));
// Create variables for reference sub texture.
tcu::TextureFormat refTexFormatSub = glu::mapGLInternalFormat(m_testParams.internalFormat);
tcu::Texture2D refSubTexture (refTexFormatSub, m_textureSize / 2, m_textureSize / 2, 1);
tcu::Surface refSurface (m_textureSize, m_textureSize);
refSubTexture.allocLevel(0);
tcu::fillWithComponentGradients(refSubTexture.getLevel(0), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f));
// Upload the main texture data.
gl.texImage2D(GL_TEXTURE_2D, 0, m_testParams.internalFormat, m_textureSize, m_textureSize, 0, refTransferFormat.format, refTransferFormat.dataType, refTexture.getLevel(0).getDataPtr());
GLU_EXPECT_NO_ERROR(gl.getError(), ("gltexImage2D() failed" + glu::getTextureFormatStr(m_testParams.internalFormat).toString()).c_str());
// Update the content of a previously allocated texture with reference sub texture.
// Reference sub texture is using the same format and data type than main texture.
gl.texSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_textureSize / 2, m_textureSize / 2, refTransferFormat.format, refTransferFormat.dataType, refSubTexture.getLevel(0).getDataPtr());
GLU_EXPECT_NO_ERROR(gl.getError(), ("gltexSubImage2D() failed" + glu::getTextureFormatStr(m_testParams.internalFormat).toString()).c_str());
setTextureParameters(GL_TEXTURE_2D);
drawTexture();
m_context.getTestContext().getLog() << tcu::TestLog::Message << m_testParams.testName.c_str() << " ("
<< m_textureSize << " x " << m_textureSize << ")" << tcu::TestLog::EndMessage;
// Read rendered pixels to reference surface.
glu::readPixels(m_context.getRenderContext(), 0, 0, refSurface.getAccess());
// Create variables for test sub texture.
tcu::TextureFormat testTexFormatSub = glu::mapGLTransferFormat(m_testParams.format, m_testParams.testType);
tcu::Texture2D testSubTexture (testTexFormatSub, m_textureSize / 2, m_textureSize / 2, 1);
tcu::Surface testSurface (m_textureSize, m_textureSize);
testSubTexture.allocLevel(0);
tcu::fillWithComponentGradients(testSubTexture.getLevel(0), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f));
// Upload the main texture data again.
gl.texImage2D(GL_TEXTURE_2D, 0, m_testParams.internalFormat, m_textureSize, m_textureSize, 0, refTransferFormat.format, refTransferFormat.dataType, refTexture.getLevel(0).getDataPtr());
GLU_EXPECT_NO_ERROR(gl.getError(), ("gltexImage2D() failed" + glu::getTextureFormatStr(m_testParams.internalFormat).toString()).c_str());
// Update the content of a previously allocated texture with sub texture but different data type.
gl.texSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_textureSize / 2, m_textureSize / 2, m_testParams.format, m_testParams.testType, testSubTexture.getLevel(0).getDataPtr());
GLU_EXPECT_NO_ERROR(gl.getError(), ("gltexSubImage2D() failed" + glu::getTextureFormatStr(m_testParams.internalFormat).toString()).c_str());
setTextureParameters(GL_TEXTURE_2D);
drawTexture();
// Read rendered pixels to test surface.
readPixels(m_context.getRenderContext(), 0, 0, testSurface.getAccess());
// Execute the comparison.
if (tcu::fuzzyCompare(m_testCtx.getLog(), "texsubimage_format_", "Pass glTexSubImage with different client format to glTexImage",
refSurface, testSurface, 0.001f, tcu::COMPARE_LOG_RESULT))
{
m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Pass");
}
// Cleanup
gl.bindTexture(GL_TEXTURE_2D, 0);
gl.bindFramebuffer(GL_FRAMEBUFFER, fboId);
gl.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
gl.bindFramebuffer(GL_FRAMEBUFFER, 0);
gl.deleteFramebuffers(1, &fboId);
return IterateResult::STOP;
}
void SubImageFormatTest::setTextureParameters(glw::GLenum target)
{
const auto& gl = m_context.getRenderContext().getFunctions();
gl.texParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
GLU_EXPECT_NO_ERROR(gl.getError(), "glTexParameteri() failed");
gl.texParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
GLU_EXPECT_NO_ERROR(gl.getError(), "glTexParameteri() failed");
gl.texParameteri(target, GL_TEXTURE_BASE_LEVEL, 0);
GLU_EXPECT_NO_ERROR(gl.getError(), "glTexParameteri() failed");
gl.texParameteri(target, GL_TEXTURE_MAX_LEVEL, 0);
GLU_EXPECT_NO_ERROR(gl.getError(), "glTexParameteri() failed");
gl.texParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
GLU_EXPECT_NO_ERROR(gl.getError(), "glTexParameteri() failed");
gl.texParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
GLU_EXPECT_NO_ERROR(gl.getError(), "glTexParameteri() failed");
gl.texParameteri(target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
GLU_EXPECT_NO_ERROR(gl.getError(), "glTexParameteri() failed");
}
void SubImageFormatTest::drawTexture(void)
{
const auto& gl = m_context.getRenderContext().getFunctions();
gl.useProgram(m_program->getProgram());
GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() failed");
gl.clearColor(1.0f, 0.0f, 1.0f, 1.0f);
gl.clear(GL_COLOR_BUFFER_BIT);
GLU_EXPECT_NO_ERROR(gl.getError(), "glClear() failed");
gl.drawArrays(GL_TRIANGLE_STRIP, 0, 4);
GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() failed");
gl.finish();
}
void SubImageFormatTest::setVertexBufferObjects()
{
const auto& gl = m_context.getRenderContext().getFunctions();
gl.genBuffers(DE_LENGTH_OF_ARRAY(m_vboIds), m_vboIds);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() failed");
gl.bindBuffer(GL_ARRAY_BUFFER, m_vboIds[0]);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() failed");
gl.bufferData(GL_ARRAY_BUFFER, sizeof(vertexPositions), vertexPositions, GL_STATIC_DRAW);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() failed");
gl.bindBuffer(GL_ARRAY_BUFFER, m_vboIds[1]);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() failed");
gl.bufferData(GL_ARRAY_BUFFER, sizeof(vertexTexCoords), vertexTexCoords, GL_STATIC_DRAW);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() failed");
gl.bindBuffer(GL_ARRAY_BUFFER, 0);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() failed");
}
void SubImageFormatTest::setVertexArrayObjects()
{
const auto& gl = m_context.getRenderContext().getFunctions();
const auto program = m_program->getProgram();
const auto positionLoc = gl.getAttribLocation(program, "in_position");
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetAttribLocation() failed");
const auto texCoordLoc = gl.getAttribLocation(program, "in_texCoord");
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetAttribLocation() failed");
gl.genVertexArrays(1, &m_vaoId);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays() failed");
gl.bindVertexArray(m_vaoId);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray() failed");
gl.bindBuffer(GL_ARRAY_BUFFER, m_vboIds[0]);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() failed");
gl.enableVertexAttribArray(positionLoc);
GLU_EXPECT_NO_ERROR(gl.getError(), "glEnableVertexAttribArray() failed");
gl.vertexAttribPointer(positionLoc, 2, GL_FLOAT, GL_FALSE, 0, 0);
GLU_EXPECT_NO_ERROR(gl.getError(), "glVertexAttribPointer() failed");
gl.bindBuffer(GL_ARRAY_BUFFER, m_vboIds[1]);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() failed");
gl.enableVertexAttribArray(texCoordLoc);
GLU_EXPECT_NO_ERROR(gl.getError(), "glEnableVertexAttribArray() failed");
gl.vertexAttribPointer(texCoordLoc, 2, GL_FLOAT, GL_FALSE, 0, 0);
GLU_EXPECT_NO_ERROR(gl.getError(), "glVertexAttribPointer() failed");
gl.bindVertexArray(0);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray() failed");
}
void SubImageFormatTest::initializeProgram()
{
const auto& gl = m_context.getRenderContext().getFunctions();
gl.genTextures(1, &m_texId);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTextures() failed");
const bool supportsES32 = glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2));
const auto glslVersion = glu::getGLSLVersionDeclaration(supportsES32 ? glu::GLSLVersion::GLSL_VERSION_320_ES : glu::GLSLVersion::GLSL_VERSION_310_ES);
const auto args = std::map<std::string, std::string>{ { "VERSION", glslVersion } };
const auto vs = tcu::StringTemplate(vertShader).specialize(args);
const auto fs = tcu::StringTemplate(fragShader).specialize(args);
m_program = std::make_shared<glu::ShaderProgram>(m_context.getRenderContext(),
glu::ProgramSources() << glu::VertexSource(vs) << glu::FragmentSource(fs));
if (!m_program->isOk())
throw std::runtime_error("Compiling shader program failed.");
}
} // <anonymous>
TextureCompatibilityTests::TextureCompatibilityTests(deqp::Context& context)
: deqp::TestCaseGroup(context, "texture_compatibility", "Tests for texture format compatibility")
{
}
TextureCompatibilityTests::~TextureCompatibilityTests(void)
{
}
void TextureCompatibilityTests::init(void)
{
for (const auto& test : testParameters)
addChild(new SubImageFormatTest(m_context, test, 32));
}
} // glcts