blob: f16641857283e52a616bcd83b121b803d23334eb [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 glcCompressedFormatTests.cpp
* \brief Tests for OpenGL ES 3.1 and 3.2 compressed image formats
*/ /*-------------------------------------------------------------------*/
#include "glcCompressedFormatTests.hpp"
#include "gluDefs.hpp"
#include "glwEnums.hpp"
#include "glwFunctions.hpp"
#include "gluShaderProgram.hpp"
#include "gluPixelTransfer.hpp"
#include "gluStrUtil.hpp"
#include "tcuResource.hpp"
#include "tcuSurface.hpp"
#include "tcuImageCompare.hpp"
#include "tcuTestLog.hpp"
#include "tcuStringTemplate.hpp"
#include "deUniquePtr.hpp"
#include <algorithm>
#include <map>
#include <vector>
#include <memory>
#include <functional>
#include <fstream>
namespace glcts
{
namespace
{
using namespace glw;
using namespace glu;
using namespace tcu;
using namespace std;
struct FormatInfo
{
ApiType minApi;
const char* name;
GLenum internalFormat;
GLenum format;
GLenum sizedFormat;
bool issRGB;
IVec2 blockSize;
};
const ApiType gles31 = ApiType::es(3, 1);
const ApiType gles32 = ApiType::es(3, 2);
// List of compressed texture formats (table 8.17)
const FormatInfo compressedFormats[] =
{
// ETC (table C.2)
// minApi, name , internalFormat , format , sizedFormat , issRGB , blockSize
{ gles31, "r11_eac" , GL_COMPRESSED_R11_EAC , GL_RED , GL_R8 , false , { 4, 4 } },
{ gles31, "signed_r11_eac" , GL_COMPRESSED_SIGNED_R11_EAC , GL_RED , GL_R8 , false , { 4, 4 } },
{ gles31, "rg11_eac" , GL_COMPRESSED_RG11_EAC , GL_RG , GL_RG8 , false , { 4, 4 } },
{ gles31, "signed_rg11_eac" , GL_COMPRESSED_SIGNED_RG11_EAC , GL_RG , GL_RG8 , false , { 4, 4 } },
{ gles31, "rgb8_etc2" , GL_COMPRESSED_RGB8_ETC2 , GL_RGB , GL_RGB8 , false , { 4, 4 } },
{ gles31, "srgb8_etc2" , GL_COMPRESSED_SRGB8_ETC2 , GL_RGB , GL_SRGB8 , true , { 4, 4 } },
{ gles31, "rgb8_punchthrough_alpha1_etc2" , GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 , GL_RGBA , GL_RGBA8 , false , { 4, 4 } },
{ gles31, "srgb8_punchthrough_alpha1_etc2" , GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 , GL_RGBA , GL_SRGB8_ALPHA8 , true , { 4, 4 } },
{ gles31, "rgba8_etc2_eac" , GL_COMPRESSED_RGBA8_ETC2_EAC , GL_RGBA , GL_RGBA8 , false , { 4, 4 } },
{ gles31, "srgb8_alpha8_etc2_eac" , GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC , GL_RGBA , GL_SRGB8_ALPHA8 , true , { 4, 4 } },
// ASTC (table C.1)
// minApi, name , internalFormat , format , sizedFormat , issRGB , blockSize
{ gles32, "rgba_astc_4x4" , GL_COMPRESSED_RGBA_ASTC_4x4 , GL_RGBA , GL_RGBA8 , false , { 4, 4 } },
{ gles32, "rgba_astc_5x4" , GL_COMPRESSED_RGBA_ASTC_5x4 , GL_RGBA , GL_RGBA8 , false , { 5, 4 } },
{ gles32, "rgba_astc_5x5" , GL_COMPRESSED_RGBA_ASTC_5x5 , GL_RGBA , GL_RGBA8 , false , { 5, 5 } },
{ gles32, "rgba_astc_6x5" , GL_COMPRESSED_RGBA_ASTC_6x5 , GL_RGBA , GL_RGBA8 , false , { 6, 5 } },
{ gles32, "rgba_astc_6x6" , GL_COMPRESSED_RGBA_ASTC_6x6 , GL_RGBA , GL_RGBA8 , false , { 6, 6 } },
{ gles32, "rgba_astc_8x5" , GL_COMPRESSED_RGBA_ASTC_8x5 , GL_RGBA , GL_RGBA8 , false , { 8, 5 } },
{ gles32, "rgba_astc_8x6" , GL_COMPRESSED_RGBA_ASTC_8x6 , GL_RGBA , GL_RGBA8 , false , { 8, 6 } },
{ gles32, "rgba_astc_8x8" , GL_COMPRESSED_RGBA_ASTC_8x8 , GL_RGBA , GL_RGBA8 , false , { 8, 8 } },
{ gles32, "rgba_astc_10x5" , GL_COMPRESSED_RGBA_ASTC_10x5 , GL_RGBA , GL_RGBA8 , false , { 10, 5 } },
{ gles32, "rgba_astc_10x6" , GL_COMPRESSED_RGBA_ASTC_10x6 , GL_RGBA , GL_RGBA8 , false , { 10, 6 } },
{ gles32, "rgba_astc_10x8" , GL_COMPRESSED_RGBA_ASTC_10x8 , GL_RGBA , GL_RGBA8 , false , { 10, 8 } },
{ gles32, "rgba_astc_10x10" , GL_COMPRESSED_RGBA_ASTC_10x10 , GL_RGBA , GL_RGBA8 , false , { 10, 10 } },
{ gles32, "rgba_astc_12x10" , GL_COMPRESSED_RGBA_ASTC_12x10 , GL_RGBA , GL_RGBA8 , false , { 12, 10 } },
{ gles32, "rgba_astc_12x12" , GL_COMPRESSED_RGBA_ASTC_12x12 , GL_RGBA , GL_RGBA8 , false , { 12, 12 } },
{ gles32, "srgb8_alpha8_astc_4x4" , GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4 , GL_RGBA , GL_SRGB8_ALPHA8 , true , { 4, 4 } },
{ gles32, "srgb8_alpha8_astc_5x4" , GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4 , GL_RGBA , GL_SRGB8_ALPHA8 , true , { 5, 4 } },
{ gles32, "srgb8_alpha8_astc_5x5" , GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5 , GL_RGBA , GL_SRGB8_ALPHA8 , true , { 5, 5 } },
{ gles32, "srgb8_alpha8_astc_6x5" , GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5 , GL_RGBA , GL_SRGB8_ALPHA8 , true , { 6, 5 } },
{ gles32, "srgb8_alpha8_astc_6x6" , GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6 , GL_RGBA , GL_SRGB8_ALPHA8 , true , { 6, 6 } },
{ gles32, "srgb8_alpha8_astc_8x5" , GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5 , GL_RGBA , GL_SRGB8_ALPHA8 , true , { 8, 5 } },
{ gles32, "srgb8_alpha8_astc_8x6" , GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6 , GL_RGBA , GL_SRGB8_ALPHA8 , true , { 8, 6 } },
{ gles32, "srgb8_alpha8_astc_8x8" , GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8 , GL_RGBA , GL_SRGB8_ALPHA8 , true , { 8, 8 } },
{ gles32, "srgb8_alpha8_astc_10x5" , GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5 , GL_RGBA , GL_SRGB8_ALPHA8 , true , { 10, 5 } },
{ gles32, "srgb8_alpha8_astc_10x6" , GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6 , GL_RGBA , GL_SRGB8_ALPHA8 , true , { 10, 6 } },
{ gles32, "srgb8_alpha8_astc_10x8" , GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8 , GL_RGBA , GL_SRGB8_ALPHA8 , true , { 10, 8 } },
{ gles32, "srgb8_alpha8_astc_10x10" , GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10 , GL_RGBA , GL_SRGB8_ALPHA8 , true , { 10, 10 } },
{ gles32, "srgb8_alpha8_astc_12x10" , GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10 , GL_RGBA , GL_SRGB8_ALPHA8 , true , { 12, 10 } },
{ gles32, "srgb8_alpha8_astc_12x12" , GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12 , GL_RGBA , GL_SRGB8_ALPHA8 , true , { 12, 12 } },
};
struct UnsizedFormatInfo
{
GLenum format;
GLenum dataType;
};
const map<GLenum, UnsizedFormatInfo>
unsizedFormats =
{
{ GL_RGBA32UI , { GL_RGBA_INTEGER , GL_UNSIGNED_INT } },
{ GL_RGBA32I , { GL_RGBA_INTEGER , GL_INT } },
{ GL_RGBA32F , { GL_RGBA , GL_FLOAT } },
{ GL_RGBA16F , { GL_RGBA , GL_FLOAT } },
{ GL_RG32F , { GL_RG , GL_FLOAT } },
{ GL_RGBA16UI , { GL_RGBA_INTEGER , GL_UNSIGNED_SHORT } },
{ GL_RG32UI , { GL_RG_INTEGER , GL_UNSIGNED_INT } },
{ GL_RGBA16I , { GL_RGBA_INTEGER , GL_SHORT } },
{ GL_RG32I , { GL_RG_INTEGER , GL_INT } }
};
const vector<pair<vector<GLenum>, vector<GLenum>>>
copyFormats =
{
// Table 16.3 - copy between compressed and uncompressed
// 128bit texel / block size
{
{ GL_RGBA32UI, GL_RGBA32I, GL_RGBA32F },
{
GL_COMPRESSED_RGBA8_ETC2_EAC, GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC, GL_COMPRESSED_RG11_EAC,
GL_COMPRESSED_SIGNED_RG11_EAC, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4,
GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6,
GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8,
GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8,
GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12,
}
},
// 64bit texel / block size
{
{ GL_RGBA16F, GL_RG32F, GL_RGBA16UI, GL_RG32UI, GL_RGBA16I, GL_RG32I },
{
GL_COMPRESSED_RGB8_ETC2, GL_COMPRESSED_SRGB8_ETC2, GL_COMPRESSED_R11_EAC, GL_COMPRESSED_SIGNED_R11_EAC,
GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2, GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2
}
},
// Table 16.4 - only entries for compressed formats are included
{ { GL_COMPRESSED_R11_EAC , GL_COMPRESSED_SIGNED_R11_EAC }, {} },
{ { GL_COMPRESSED_RG11_EAC , GL_COMPRESSED_SIGNED_RG11_EAC }, {} },
{ { GL_COMPRESSED_RGB8_ETC2 , GL_COMPRESSED_SRGB8_ETC2 }, {} },
{ { GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 , GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 }, {} },
{ { GL_COMPRESSED_RGBA8_ETC2_EAC , GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC }, {} },
{ { GL_COMPRESSED_RGBA_ASTC_4x4 , GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4 }, {} },
{ { GL_COMPRESSED_RGBA_ASTC_5x4 , GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4 }, {} },
{ { GL_COMPRESSED_RGBA_ASTC_5x5 , GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5 }, {} },
{ { GL_COMPRESSED_RGBA_ASTC_6x5 , GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5 }, {} },
{ { GL_COMPRESSED_RGBA_ASTC_6x6 , GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6 }, {} },
{ { GL_COMPRESSED_RGBA_ASTC_8x5 , GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5 }, {} },
{ { GL_COMPRESSED_RGBA_ASTC_8x6 , GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6 }, {} },
{ { GL_COMPRESSED_RGBA_ASTC_8x8 , GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8 }, {} },
{ { GL_COMPRESSED_RGBA_ASTC_10x5 , GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5 }, {} },
{ { GL_COMPRESSED_RGBA_ASTC_10x6 , GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6 }, {} },
{ { GL_COMPRESSED_RGBA_ASTC_10x8 , GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8 }, {} },
{ { GL_COMPRESSED_RGBA_ASTC_10x10 , GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10 }, {} },
{ { GL_COMPRESSED_RGBA_ASTC_12x10 , GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10 }, {} },
{ { GL_COMPRESSED_RGBA_ASTC_12x12 , GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12 }, {} }
};
#include "glcCompressedFormatTests_data.inl"
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* vertexShader =
"${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* fragmentShader =
"${VERSION}\n"
"uniform highp vec4 offset;\n"
"uniform highp vec4 scale;\n"
"uniform highp sampler2D sampler;\n"
"in highp vec2 v_texCoord;\n"
"layout(location = 0) out highp vec4 out_color;\n"
"void main (void)\n"
"{\n"
" out_color = texture(sampler, v_texCoord) * scale + offset;\n"
"}\n";
struct OffsetInfo
{
Vec4 offset;
Vec4 scale;
};
const OffsetInfo defaultOffset { { 0.0f, 0.0f, 0.0f, 0.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } };
const map<GLenum, OffsetInfo> offsets =
{
{ GL_COMPRESSED_SIGNED_R11_EAC , { { 0.5f, 0.0f, 0.0f, 0.0f }, { 0.5f, 0.0f, 0.0f, 1.0f } } },
{ GL_COMPRESSED_SIGNED_RG11_EAC , { { 0.5f, 0.5f, 0.0f, 0.0f }, { 0.5f, 0.5f, 0.0f, 1.0f } } }
};
class SharedData
{
public:
explicit SharedData (deqp::Context& context);
virtual ~SharedData ();
void init();
void deinit();
GLuint programId() const;
GLuint texId(int index) const;
GLuint vaoId() const;
GLuint offsetLoc() const;
GLuint scaleLoc() const;
private:
deqp::Context& m_context;
size_t m_initCount;
vector<GLuint> m_texIds;
shared_ptr<ShaderProgram> m_program;
GLuint m_vaoId;
GLuint m_vboIds[2];
GLuint m_offsetLoc;
GLuint m_scaleLoc;
SharedData (const SharedData& other) = delete;
SharedData& operator= (const SharedData& other) = delete;
};
SharedData::SharedData (deqp::Context& context)
: m_context(context)
, m_initCount(0)
{
}
SharedData::~SharedData ()
{
DE_ASSERT(m_initCount <= 0);
}
void SharedData::init ()
{
++m_initCount;
if (m_initCount > 1)
return;
const auto& gl = m_context.getRenderContext().getFunctions();
// program
const bool supportsES32 = contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2));
const auto glslVersion = getGLSLVersionDeclaration(supportsES32 ? glu::GLSL_VERSION_320_ES : glu::GLSL_VERSION_310_ES);
const auto args = map<string, string> { { "VERSION", glslVersion } };
const auto vs = StringTemplate(vertexShader).specialize(args);
const auto fs = StringTemplate(fragmentShader).specialize(args);
m_program = make_shared<ShaderProgram>(m_context.getRenderContext(), ProgramSources() << glu::VertexSource(vs) << glu::FragmentSource(fs));
if (!m_program->isOk())
throw runtime_error("Compiling shader program failed");
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");
m_offsetLoc = gl.getUniformLocation(program, "offset");
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetAttribLocation() failed");
m_scaleLoc = gl.getUniformLocation(program, "scale");
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetAttribLocation() failed");
// buffers
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");
// vertex array objects
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 SharedData::deinit ()
{
DE_ASSERT(m_initCount > 0);
--m_initCount;
if (m_initCount > 0)
return;
const auto& gl = m_context.getRenderContext().getFunctions();
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");
gl.deleteTextures(m_texIds.size(), m_texIds.data());
GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteTextures() failed");
}
GLuint SharedData::programId () const
{
return m_program->getProgram();
}
GLuint SharedData::texId (int index) const
{
return m_texIds[index];
}
GLuint SharedData::vaoId () const
{
return m_vaoId;
}
GLuint SharedData::offsetLoc () const
{
return m_offsetLoc;
}
GLuint SharedData::scaleLoc () const
{
return m_scaleLoc;
}
struct {
const GLsizei width = 8;
const GLsizei height = 8;
const GLsizei depth = 6;
const vector<deUint8> data =
{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
};
} invalidTexture;
struct ApiTestContext
{
TestLog& log;
const glw::Functions& gl;
vector<GLuint>& texIds;
vector<GLuint>& bufferIds;
const Archive& archive;
void bindTexture(GLenum target, GLuint texId);
};
void ApiTestContext::bindTexture (GLenum target, GLuint texId)
{
gl.bindTexture(target, texId);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() failed");
}
typedef function<void (ApiTestContext&)> ApiCaseFn;
struct ApiCaseStep
{
ApiCaseFn code;
GLenum expectedError;
};
typedef function<void (deqp::Context&, vector<ApiCaseStep>&)> ApiCaseStepGeneratorFn;
struct ApiCaseParams
{
ApiType minApi;
string name;
string description;
size_t texIdsCount;
size_t bufferIdsCount;
vector<ApiCaseStep> steps;
ApiCaseStepGeneratorFn stepsGenerator;
};
const GLenum cubemapFaces[] =
{
GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
GL_TEXTURE_CUBE_MAP_POSITIVE_Z, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z,
};
struct ImageInfo
{
GLuint width;
GLuint height;
vector<GLubyte> data;
};
ImageInfo loadImage (const Archive& archive, GLenum format, size_t imageIndex)
{
const auto data = imageData.find(format);
if (data == imageData.end())
{
ostringstream msg;
msg << "No image data found for format: " << format;
TCU_FAIL(msg.str().c_str());
}
if (imageIndex >= data->second.size())
{
ostringstream msg;
msg << "Image index out of range for format: " << format << " index: " << imageIndex;
TCU_FAIL(msg.str().c_str());
}
const de::UniquePtr<Resource> resource (archive.getResource(data->second[imageIndex].path.c_str()));
if (!resource || resource->getSize() <= 0)
TCU_FAIL("Failed to read file: "+data->second[imageIndex].path);
ImageInfo result;
result.width = data->second[imageIndex].width;
result.height = data->second[imageIndex].height;
const auto size = resource->getSize();
result.data.resize(size);
resource->setPosition(0);
resource->read(result.data.data(), size);
return result;
}
void setTextureParameters (const glw::Functions& gl, GLenum target)
{
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");
const auto repeatMode = GL_CLAMP_TO_EDGE;
gl.texParameteri(target, GL_TEXTURE_WRAP_S, repeatMode);
GLU_EXPECT_NO_ERROR(gl.getError(), "glTexParameteri() failed");
gl.texParameteri(target, GL_TEXTURE_WRAP_T, repeatMode);
GLU_EXPECT_NO_ERROR(gl.getError(), "glTexParameteri() failed");
gl.texParameteri(target, GL_TEXTURE_WRAP_R, repeatMode);
GLU_EXPECT_NO_ERROR(gl.getError(), "glTexParameteri() failed");
}
ApiCaseParams apiTests[] =
{
{
gles31, // ApiType minApi;
"invalid_target", // string name;
"Invalid texture target for compressed format", // string description;
1, // size_t texIdsCount;
0, // size_t bufferIdsCount;
{ // vector<ApiCaseStep> steps;
{
[](ApiTestContext& context)
{
context.bindTexture(GL_TEXTURE_3D, context.texIds[0]);
},
GL_NO_ERROR
},
{
[](ApiTestContext& context)
{
context.gl.compressedTexImage2D(GL_TEXTURE_3D, 0, GL_COMPRESSED_RGB8_ETC2, invalidTexture.width, invalidTexture.height, 0, invalidTexture.data.size(), invalidTexture.data.data());
},
GL_INVALID_ENUM
},
{
[](ApiTestContext& context)
{
context.gl.compressedTexSubImage2D(GL_TEXTURE_3D, 0, 0, 0, invalidTexture.width, invalidTexture.height, GL_COMPRESSED_RGB8_ETC2, invalidTexture.data.size(), invalidTexture.data.data());
},
GL_INVALID_ENUM
},
},
DE_NULL, // ApiCaseStepGeneratorFn stepsGenerator;
},
{
gles31, // ApiType minApi;
"invalid_width_or_height", // string name;
"Different values for width and height for cubemap texture target", // string description;
1, // size_t texIdsCount;
0, // size_t bufferIdsCount;
{ // vector<ApiCaseStep> steps;
{
[](ApiTestContext& context)
{
context.bindTexture(GL_TEXTURE_CUBE_MAP, context.texIds[0]);
},
GL_NO_ERROR
}
},
[](deqp::Context&, vector<ApiCaseStep>& steps) // ApiCaseStepGeneratorFn stepsGenerator;
{
steps.push_back(
{
[](ApiTestContext& context)
{
context.bindTexture(GL_TEXTURE_CUBE_MAP, context.texIds[0]);
},
GL_NO_ERROR
});
for(size_t i = 0; i < DE_LENGTH_OF_ARRAY(cubemapFaces); ++i)
{
steps.push_back(
{
[i](ApiTestContext& context)
{
context.gl.compressedTexImage2D(cubemapFaces[i], 0, GL_COMPRESSED_RGB8_ETC2, invalidTexture.width - i % 2, invalidTexture.height - (i + 1) % 2, 0, invalidTexture.data.size(), invalidTexture.data.data());
},
GL_INVALID_VALUE
});
steps.push_back(
{
[i](ApiTestContext& context)
{
const auto format = GL_COMPRESSED_RGB8_ETC2;
const GLsizei blockSize = 4;
const GLsizei blockDataSize = 8;
const auto data = loadImage(context.archive, format, 0);
const auto& gl = context.gl;
gl.compressedTexImage2D(cubemapFaces[i], 0, format, data.width, data.height, 0, data.data.size(), data.data.data());
GLU_EXPECT_NO_ERROR(gl.getError(), "glCompressedTexImage2D() failed");
const auto updateWidth = invalidTexture.width - (i % 2) * blockSize;
const auto updateHeight = invalidTexture.height - ((i + 1) % 2) * blockSize;
const auto updateDataSize = (updateWidth / blockSize) * (updateHeight / blockSize) * blockDataSize;
DE_ASSERT(updateDataSize <= invalidTexture.data.size());
context.gl.compressedTexSubImage2D(cubemapFaces[i], 0, 0, 0, updateWidth, updateHeight, format, updateDataSize, invalidTexture.data.data());
},
GL_NO_ERROR
});
}
}
},
{
gles32, // ApiType minApi;
"invalid_width_or_height_array", // string name;
"Different values for width and height for cubemap texture target", // string description;
1, // size_t texIdsCount;
0, // size_t bufferIdsCount;
{ // vector<ApiCaseStep> steps;
{
[](ApiTestContext& context)
{
context.bindTexture(GL_TEXTURE_CUBE_MAP, context.texIds[0]);
},
GL_NO_ERROR
},
{
[](ApiTestContext& context)
{
context.gl.compressedTexImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, 0, GL_COMPRESSED_RGB8_ETC2, invalidTexture.width - 1, invalidTexture.height, 6, 0, invalidTexture.data.size(), invalidTexture.data.data());
},
GL_INVALID_VALUE
}
},
DE_NULL, // ApiCaseStepGeneratorFn stepsGenerator;
},
{
gles31, // ApiType minApi;
"invalid_size_value_negative", // string name;
"Negative width, height or imageSize for compressed texture image", // string description;
3, // size_t texIdsCount;
0, // size_t bufferIdsCount;
{}, // vector<ApiCaseStep> steps;
[](deqp::Context& testContext, vector<ApiCaseStep>& steps) // ApiCaseStepGeneratorFn stepsGenerator;
{
auto format = GL_COMPRESSED_RGB8_ETC2;
const auto data = loadImage(testContext.getTestContext().getArchive(), format, 0);
steps.push_back(
{
[format, data](ApiTestContext& context)
{
DE_ASSERT(context.texIds.size() >= 3);
context.bindTexture(GL_TEXTURE_2D, context.texIds[0]);
context.gl.compressedTexImage2D(GL_TEXTURE_2D, 0, format, data.width, -1, 0, data.data.size(), data.data.data());
},
GL_INVALID_VALUE
});
steps.push_back(
{
[format, data](ApiTestContext& context)
{
context.gl.compressedTexImage2D(GL_TEXTURE_2D, 0, format, data.width, data.height, 0, data.data.size(), data.data.data());
},
GL_NO_ERROR
});
steps.push_back(
{
[format, data](ApiTestContext& context)
{
context.gl.compressedTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, data.width, -1, format, data.data.size(), data.data.data());
},
GL_INVALID_VALUE
});
steps.push_back(
{
[format, data](ApiTestContext& context)
{
DE_ASSERT(context.texIds.size() >= 3);
context.bindTexture(GL_TEXTURE_2D, context.texIds[1]);
context.gl.compressedTexImage2D(GL_TEXTURE_2D, 0, format, -276, data.height, 0, data.data.size(), data.data.data());
},
GL_INVALID_VALUE
});
steps.push_back(
{
[format, data](ApiTestContext& context)
{
context.gl.compressedTexImage2D(GL_TEXTURE_2D, 0, format, data.width, data.height, 0, data.data.size(), data.data.data());
},
GL_NO_ERROR
});
steps.push_back(
{
[format, data](ApiTestContext& context)
{
context.gl.compressedTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, -276, data.height, format, data.data.size(), data.data.data());
},
GL_INVALID_VALUE
});
steps.push_back(
{
[format, data](ApiTestContext& context)
{
DE_ASSERT(context.texIds.size() >= 3);
context.bindTexture(GL_TEXTURE_2D, context.texIds[2]);
context.gl.compressedTexImage2D(GL_TEXTURE_2D, 0, format, data.width, data.height, 0, -66543, data.data.data());
},
GL_INVALID_VALUE
});
steps.push_back(
{
[format, data](ApiTestContext& context)
{
context.gl.compressedTexImage2D(GL_TEXTURE_2D, 0, format, data.width, data.height, 0, data.data.size(), data.data.data());
},
GL_NO_ERROR
});
steps.push_back(
{
[format, data](ApiTestContext& context)
{
context.gl.compressedTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, data.width, data.height, format, -66543, data.data.data());
},
GL_INVALID_VALUE
});
}
},
{
gles31, // ApiType minApi;
"invalid_border_nonzero", // string name;
"Non zero border values are not supported", // string description;
2, // size_t texIdsCount;
0, // size_t bufferIdsCount;
{ // vector<ApiCaseStep> steps;
{
[](ApiTestContext& context)
{
context.bindTexture(GL_TEXTURE_2D, context.texIds[0]);
context.gl.compressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB8_ETC2, invalidTexture.width, invalidTexture.height, 1, invalidTexture.data.size(), invalidTexture.data.data());
},
GL_INVALID_VALUE
},
},
[](deqp::Context&, vector<ApiCaseStep>& steps) // ApiCaseStepGeneratorFn stepsGenerator;
{
for(size_t j = 0; j < DE_LENGTH_OF_ARRAY(cubemapFaces); ++j)
steps.push_back(
{
[j](ApiTestContext& context)
{
context.bindTexture(GL_TEXTURE_CUBE_MAP, context.texIds[1]);
context.gl.compressedTexImage2D(cubemapFaces[j], 0, GL_COMPRESSED_RGB8_ETC2, invalidTexture.width, invalidTexture.height, 1, invalidTexture.data.size(), invalidTexture.data.data());
},
GL_INVALID_VALUE
});
},
},
{
gles32, // ApiType minApi;
"invalid_border_nonzero_array", // string name;
"Non zero border values are not supported", // string description;
1, // size_t texIdsCount;
0, // size_t bufferIdsCount;
{ // vector<ApiCaseStep> steps;
{
[](ApiTestContext& context)
{
context.bindTexture(GL_TEXTURE_CUBE_MAP, context.texIds[0]);
context.gl.compressedTexImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, 0, GL_COMPRESSED_RGB8_ETC2, invalidTexture.width, invalidTexture.height, invalidTexture.depth, 1, invalidTexture.data.size(), invalidTexture.data.data());
},
GL_INVALID_VALUE
},
},
DE_NULL, // ApiCaseStepGeneratorFn stepsGenerator;
},
{
gles31, // ApiType minApi;
"invalid_format_mismatch", // string name;
"Subimage format differs from previously specified texture format", // string description;
1, // size_t texIdsCount;
0, // size_t bufferIdsCount;
{ // vector<ApiCaseStep> steps;
{
[](ApiTestContext& context)
{
const auto& gl = context.gl;
const auto format0 = GL_COMPRESSED_RGB8_ETC2;
const auto data0 = loadImage(context.archive, format0, 0);
const auto format1 = GL_COMPRESSED_R11_EAC;
const auto data1 = loadImage(context.archive, format1, 0);
DE_ASSERT(data0.width == data1.width && data0.height == data1.height);
context.bindTexture(GL_TEXTURE_2D, context.texIds[0]);
gl.compressedTexImage2D(GL_TEXTURE_2D, 0, format0, data0.width, data0.height, 0, data0.data.size(), data0.data.data());
GLU_EXPECT_NO_ERROR(gl.getError(), "glCompressedTexImage2D() failed");
gl.compressedTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, data1.width, data1.height, format1, data1.data.size(), data1.data.data());
},
GL_INVALID_OPERATION
},
},
DE_NULL, // ApiCaseStepGeneratorFn stepsGenerator;
},
{
gles31, // ApiType minApi;
"invalid_target_3d", // string name;
"Invalid texture target for compressed texture", // string description;
1, // size_t texIdsCount;
0, // size_t bufferIdsCount;
{}, // vector<ApiCaseStep> steps;
[](deqp::Context& testContext, vector<ApiCaseStep>& steps) // ApiCaseStepGeneratorFn stepsGenerator;
{
for(auto i = 0; i < DE_LENGTH_OF_ARRAY(compressedFormats); ++i)
{
if (!contextSupports(testContext.getRenderContext().getType(), compressedFormats[i].minApi))
continue;
const auto data = loadImage(testContext.getTestContext().getArchive(), compressedFormats[i].internalFormat, 0);
steps.push_back(
{
[](ApiTestContext& context)
{
context.bindTexture(GL_TEXTURE_2D, context.texIds[0]);
},
GL_NO_ERROR
});
steps.push_back(
{
[i, data](ApiTestContext& context)
{
context.gl.compressedTexImage3D(GL_TEXTURE_2D, 0, compressedFormats[i].internalFormat, data.width, data.height, 1, 0, data.data.size(), data.data.data());
},
GL_INVALID_ENUM
});
steps.push_back(
{
[i, data](ApiTestContext& context)
{
context.gl.compressedTexSubImage3D(GL_TEXTURE_2D, 0, 0, 0, 0, data.width, data.height, 1, compressedFormats[i].internalFormat, data.data.size(), data.data.data());
},
GL_INVALID_ENUM
});
}
}
},
{
gles31, // ApiType minApi;
"texstorage_accepts_compressed_format", // string name;
"TexStorage should accept compressed format", // string description;
DE_LENGTH_OF_ARRAY(compressedFormats), // size_t texIdsCount;
0, // size_t bufferIdsCount;
{}, // vector<ApiCaseStep> steps;
[](deqp::Context& testContext, vector<ApiCaseStep>& steps) // ApiCaseStepGeneratorFn stepsGenerator;
{
for(auto i = 0; i < DE_LENGTH_OF_ARRAY(compressedFormats); ++i)
{
if (!contextSupports(testContext.getRenderContext().getType(), compressedFormats[i].minApi))
continue;
steps.push_back(
{
[i](ApiTestContext& context)
{
const auto& gl = context.gl;
const size_t textureWidth = 240;
const size_t textureHeight = 240;
context.bindTexture(GL_TEXTURE_2D, context.texIds[i]);
gl.texStorage2D(GL_TEXTURE_2D, 1, compressedFormats[i].internalFormat, textureWidth, textureHeight);
},
GL_NO_ERROR
});
}
}
},
{
gles31, // ApiType minApi;
"invalid_teximage_with_compressed_format", // string name;
"TexImage should not accept compressed format", // string description;
2, // size_t texIdsCount;
0, // size_t bufferIdsCount;
{}, // vector<ApiCaseStep> steps;
[](deqp::Context& testContext, vector<ApiCaseStep>& steps) // ApiCaseStepGeneratorFn stepsGenerator;
{
for(auto i = 0; i < DE_LENGTH_OF_ARRAY(compressedFormats); ++i)
{
const auto format = compressedFormats[i];
if (!contextSupports(testContext.getRenderContext().getType(), format.minApi))
continue;
const auto data = loadImage(testContext.getTestContext().getArchive(), format.internalFormat, 0);
steps.push_back(
{
[format, data](ApiTestContext& context)
{
const auto& gl = context.gl;
context.bindTexture(GL_TEXTURE_2D, context.texIds[0]);
gl.texImage2D(GL_TEXTURE_2D, 0, format.internalFormat, data.width, data.height, 0, format.format, GL_UNSIGNED_BYTE, data.data.data());
},
GL_INVALID_VALUE
});
steps.push_back(
{
[format, data](ApiTestContext& context)
{
const auto& gl = context.gl;
context.bindTexture(GL_TEXTURE_3D, context.texIds[1]);
gl.texImage3D(GL_TEXTURE_3D, 0, format.internalFormat, data.width, data.height, 1, 0, format.format, GL_UNSIGNED_BYTE, data.data.data());
},
GL_INVALID_VALUE
});
}
}
},
{
gles31, // ApiType minApi;
"invalid_format", // string name;
"Uncompressed internal format for compressed texture", // string description;
2, // size_t texIdsCount;
0, // size_t bufferIdsCount;
{ // vector<ApiCaseStep> steps;
{
[](ApiTestContext& context)
{
context.bindTexture(GL_TEXTURE_2D, context.texIds[1]);
},
GL_NO_ERROR
},
{
[](ApiTestContext& context)
{
context.gl.compressedTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, invalidTexture.width, invalidTexture.height, 0, invalidTexture.data.size(), invalidTexture.data.data());
},
GL_INVALID_ENUM
},
{
[](ApiTestContext& context)
{
context.gl.compressedTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, invalidTexture.width, invalidTexture.height, GL_RGB, invalidTexture.data.size(), invalidTexture.data.data());
},
GL_INVALID_OPERATION
},
{
[](ApiTestContext& context)
{
const GLenum format = GL_COMPRESSED_RGB8_ETC2;
const auto data = loadImage(context.archive, format, 0);
const auto& gl = context.gl;
gl.compressedTexImage2D(GL_TEXTURE_2D, 0, format, data.width, data.height, 0, data.data.size(), data.data.data());
GLU_EXPECT_NO_ERROR(gl.getError(), "glCompressedTexImage2D() failed");
context.gl.compressedTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, invalidTexture.width, invalidTexture.height, GL_RGB, invalidTexture.data.size(), invalidTexture.data.data());
},
GL_INVALID_OPERATION
},
{
[](ApiTestContext& context)
{
context.bindTexture(GL_TEXTURE_CUBE_MAP, context.texIds[0]);
},
GL_NO_ERROR
}
},
[](deqp::Context&, vector<ApiCaseStep>& steps) // ApiCaseStepGeneratorFn stepsGenerator;
{
for(size_t j = 0; j < DE_LENGTH_OF_ARRAY(cubemapFaces); ++j)
{
steps.push_back(
{
[j](ApiTestContext& context)
{
context.gl.compressedTexImage2D(cubemapFaces[j], 0, GL_RGB, invalidTexture.width, invalidTexture.height, 0, invalidTexture.data.size(), invalidTexture.data.data());
},
GL_INVALID_ENUM
});
steps.push_back(
{
[j](ApiTestContext& context)
{
const GLenum format = GL_COMPRESSED_RGB8_ETC2;
const auto data = loadImage(context.archive, format, 0);
const auto& gl = context.gl;
gl.compressedTexImage2D(cubemapFaces[j], 0, format, data.width, data.height, 0, data.data.size(), data.data.data());
GLU_EXPECT_NO_ERROR(gl.getError(), "glCompressedTexImage2D() failed");
context.gl.compressedTexSubImage2D(cubemapFaces[j], 0, 0, 0, invalidTexture.width, invalidTexture.height, GL_RGB, invalidTexture.data.size(), invalidTexture.data.data());
},
GL_INVALID_OPERATION
});
}
}
},
{
gles32, // ApiType minApi;
"invalid_format_array", // string name;
"Uncompressed internal format for compressed texture", // string description;
1, // size_t texIdsCount;
0, // size_t bufferIdsCount;
{ // vector<ApiCaseStep> steps;
{
[](ApiTestContext& context)
{
context.bindTexture(GL_TEXTURE_CUBE_MAP, context.texIds[0]);
},
GL_NO_ERROR
},
{
[](ApiTestContext& context)
{
context.gl.compressedTexImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, 0, GL_RGB, invalidTexture.width, invalidTexture.height, 6, 0, invalidTexture.data.size(), invalidTexture.data.data());
},
GL_INVALID_ENUM
},
{
[](ApiTestContext& context)
{
const GLenum format = GL_COMPRESSED_RGB8_ETC2;
const auto data = loadImage(context.archive, format, 0);
const auto& gl = context.gl;
vector<GLubyte> arrayData;
arrayData.reserve(6 * data.data.size());
for(size_t k = 0; k < 6; ++k)
std::copy(data.data.begin(), data.data.end(), std::back_inserter(arrayData));
context.gl.compressedTexImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, 0, format, data.width, data.height, 6, 0, arrayData.size(), arrayData.data());
GLU_EXPECT_NO_ERROR(gl.getError(), "glCompressedTexImage3D() failed");
context.gl.compressedTexSubImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, 0, 0, 0, 0, invalidTexture.width, invalidTexture.height, 6, GL_RGB, invalidTexture.data.size(), invalidTexture.data.data());context.gl.compressedTexSubImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, 0, 0, 0, 0, invalidTexture.width, invalidTexture.height, 6, GL_RGB, invalidTexture.data.size(), invalidTexture.data.data());
},
GL_INVALID_OPERATION
}
},
DE_NULL // ApiCaseStepGeneratorFn stepsGenerator;
},
{
gles31, // ApiType minApi;
"invalid_too_small_unpack_buffer", // string name;
"Pixel unpack buffer with not enough space for required texture data", // string description;
1, // size_t texIdsCount;
1, // size_t bufferIdsCount;
{ // vector<ApiCaseStep> steps;
{
[](ApiTestContext& context)
{
const GLenum format = GL_COMPRESSED_RGB8_ETC2;
const auto data = loadImage(context.archive, format, 0);
const auto& gl = context.gl;
context.bindTexture(GL_TEXTURE_2D, context.texIds[0]);
gl.bindBuffer(GL_PIXEL_UNPACK_BUFFER, context.bufferIds[0]);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() failed");
gl.bufferData(GL_PIXEL_UNPACK_BUFFER, data.data.size() / 2, data.data.data(), GL_STATIC_READ);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() failed");
gl.compressedTexImage2D(GL_TEXTURE_2D, 0, format, data.width, data.height, 0, data.data.size(), 0);
},
GL_INVALID_OPERATION
},
{
[](ApiTestContext& context)
{
const GLenum format = GL_COMPRESSED_RGB8_ETC2;
const auto data = loadImage(context.archive, format, 0);
const auto& gl = context.gl;
context.bindTexture(GL_TEXTURE_2D, context.texIds[0]);
gl.bindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
gl.compressedTexImage2D(GL_TEXTURE_2D, 0, format, data.width, data.height, 0, data.data.size(), data.data.data());
GLU_EXPECT_NO_ERROR(gl.getError(), "glCompressedTexImage2D() failed");
gl.bindBuffer(GL_PIXEL_UNPACK_BUFFER, context.bufferIds[0]);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() failed");
gl.bufferData(GL_PIXEL_UNPACK_BUFFER, data.data.size() / 2, data.data.data(), GL_STATIC_READ);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() failed");
gl.compressedTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, data.width, data.height, format, data.data.size(), 0);
},
GL_INVALID_OPERATION
}
},
DE_NULL // ApiCaseStepGeneratorFn stepsGenerator;
},
{
gles31, // ApiType minApi;
"invalid_inconsistent_data_size", // string name;
"Data size is not consistent with texture internal format and dimensions", // string description;
1, // size_t texIdsCount;
0, // size_t bufferIdsCount;
{}, // vector<ApiCaseStep> steps;
[](deqp::Context& testContext, vector<ApiCaseStep>& steps) // ApiCaseStepGeneratorFn stepsGenerator;
{
for(auto i = 0; i < DE_LENGTH_OF_ARRAY(compressedFormats); ++i)
{
const auto& format = compressedFormats[i];
if (!contextSupports(testContext.getRenderContext().getType(), format.minApi))
continue;
const auto data0 = loadImage(testContext.getTestContext().getArchive(), format.internalFormat, 0);
const auto data1 = loadImage(testContext.getTestContext().getArchive(), format.internalFormat, 1);
steps.push_back(
{
[format, data0](ApiTestContext& context)
{
const auto& gl = context.gl;
context.bindTexture(GL_TEXTURE_2D, context.texIds[0]);
gl.compressedTexImage2D(GL_TEXTURE_2D, 0, format.internalFormat, data0.width - 12, data0.height - 12, 0, data0.data.size(), data0.data.data());
},
GL_INVALID_VALUE
});
}
}
},
{
gles32, // ApiType minApi;
"invalid_inconsistent_data_size_array", // string name;
"Data size is not consistent with texture internal format and dimensions", // string description;
2, // size_t texIdsCount;
0, // size_t bufferIdsCount;
{}, // vector<ApiCaseStep> steps;
[](deqp::Context& testContext, vector<ApiCaseStep>& steps) // ApiCaseStepGeneratorFn stepsGenerator;
{
for(auto i = 0; i < DE_LENGTH_OF_ARRAY(compressedFormats); ++i)
{
const auto& format = compressedFormats[i];
if (!contextSupports(testContext.getRenderContext().getType(), format.minApi))
continue;
const auto data0 = loadImage(testContext.getTestContext().getArchive(), format.internalFormat, 0);
const auto data1 = loadImage(testContext.getTestContext().getArchive(), format.internalFormat, 1);
steps.push_back(
{
[format, data0](ApiTestContext& context)
{
context.bindTexture(GL_TEXTURE_CUBE_MAP, context.texIds[0]);
},
GL_NO_ERROR
});
for(size_t j = 0; j < DE_LENGTH_OF_ARRAY(cubemapFaces); ++j)
steps.push_back(
{
[j, format, data0](ApiTestContext& context)
{
context.gl.compressedTexImage2D(cubemapFaces[j], 0, format.internalFormat, data0.width, data0.height, 0, data0.data.size(), data0.data.data());
},
GL_NO_ERROR
});
steps.push_back(
{
[format, data0](ApiTestContext& context)
{
vector<GLubyte> arrayData;
arrayData.reserve(6 * data0.data.size());
for(size_t k = 0; k < 6; ++k)
std::copy(data0.data.begin(), data0.data.end(), std::back_inserter(arrayData));
context.bindTexture(GL_TEXTURE_CUBE_MAP, context.texIds[1]);
context.gl.compressedTexImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, 0, format.internalFormat, data0.width, data0.height, 6, 0, arrayData.size(), arrayData.data());
},
GL_NO_ERROR
});
steps.push_back(
{
[format, data1](ApiTestContext& context)
{
context.gl.compressedTexSubImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, 0, 0, 0, 0, data1.width, data1.height, 1, format.internalFormat, data1.data.size() - 1, data1.data.data());
},
GL_INVALID_VALUE
});
}
}
},
{
gles31, // ApiType minApi;
"invalid_offset_or_size", // string name;
"Offset or image size not aligned with block size", // string description;
1, // size_t texIdsCount;
0, // size_t bufferIdsCount;
{}, // vector<ApiCaseStep> steps;
[](deqp::Context& testContext, vector<ApiCaseStep>& steps) // ApiCaseStepGeneratorFn stepsGenerator;
{
for(auto i = 0; i < DE_LENGTH_OF_ARRAY(compressedFormats); ++i)
{
const auto& format = compressedFormats[i];
if (!contextSupports(testContext.getRenderContext().getType(), format.minApi))
continue;
const auto data0 = loadImage(testContext.getTestContext().getArchive(), format.internalFormat, 0);
const auto data1 = loadImage(testContext.getTestContext().getArchive(), format.internalFormat, 1);
steps.push_back(
{
[format, data0](ApiTestContext& context)
{
context.bindTexture(GL_TEXTURE_2D, context.texIds[0]);
context.gl.compressedTexImage2D(GL_TEXTURE_2D, 0, format.internalFormat, data0.width, data0.height, 0, data0.data.size(), data0.data.data());
},
GL_NO_ERROR
});
steps.push_back(
{
[format, data1](ApiTestContext& context)
{
context.gl.compressedTexImage2D(GL_TEXTURE_2D, 1, format.internalFormat, data1.width, data1.height, 0, data1.data.size(), data1.data.data());
},
GL_NO_ERROR
});
steps.push_back(
{
[format, data1](ApiTestContext& context)
{
context.gl.compressedTexSubImage2D(GL_TEXTURE_2D, 0, format.blockSize.x() - 2, 0, data1.width, data1.height, format.internalFormat, data1.data.size(), data1.data.data());
},
GL_INVALID_OPERATION
});
steps.push_back(
{
[format, data1](ApiTestContext& context)
{
context.gl.compressedTexSubImage2D(GL_TEXTURE_2D, 0, 0, format.blockSize.y() - 2, data1.width, data1.height, format.internalFormat, data1.data.size(), data1.data.data());
},
GL_INVALID_OPERATION
});
}
}
},
{
gles32, // ApiType minApi;
"copy_compressed_to_uncompressed", // string name;
"Copying pixels from compressed to uncompressed texture", // string description;
2, // size_t texIdsCount;
0, // size_t bufferIdsCount;
{}, // vector<ApiCaseStep> steps;
[](deqp::Context&, vector<ApiCaseStep>& steps) // ApiCaseStepGeneratorFn stepsGenerator;
{
for(const auto& format : copyFormats)
{
if (format.second.empty())
continue;
for(const auto& uncompressedFormat : format.first)
{
for(const auto& compressedFormat : format.second)
{
steps.push_back(
{
[uncompressedFormat, compressedFormat](ApiTestContext& context)
{
const auto& gl = context.gl;
const auto& image = imageData.at(compressedFormat);
const auto& unsizedInfo = unsizedFormats.at(uncompressedFormat);
const auto textureData = loadImage(context.archive, compressedFormat, 0);
const auto compressedInfo = find_if(begin(compressedFormats), end(compressedFormats), [compressedFormat](const FormatInfo& fmt) { return fmt.internalFormat == compressedFormat; });
DE_ASSERT((GLsizei)textureData.width == image[0].width && (GLsizei)textureData.height == image[0].height);
DE_ASSERT(compressedInfo != end(compressedFormats));
const auto targetWidth = image[0].width / compressedInfo->blockSize[0];
const auto targetHeight = image[0].height / compressedInfo->blockSize[1];
context.log
<< TestLog::Message
<< "Copying from " << getTextureFormatStr(compressedFormat).toString() << " " << image[0].width << "x" << image[0].height
<< " to " << getTextureFormatStr(uncompressedFormat).toString() << " " << targetWidth << "x" << targetHeight
<< TestLog::EndMessage;
context.bindTexture(GL_TEXTURE_2D, context.texIds[0]);
gl.texImage2D(GL_TEXTURE_2D, 0, uncompressedFormat, targetWidth, targetHeight, 0, unsizedInfo.format, unsizedInfo.dataType, 0);
GLU_EXPECT_NO_ERROR(gl.getError(), "glTexImage2D() failed");
setTextureParameters(context.gl, GL_TEXTURE_2D);
context.bindTexture(GL_TEXTURE_2D, context.texIds[1]);
gl.compressedTexImage2D(GL_TEXTURE_2D, 0, compressedFormat, image[0].width, image[0].height, 0, textureData.data.size(), textureData.data.data());
GLU_EXPECT_NO_ERROR(gl.getError(), "glCompressedTexImage2D() failed");
setTextureParameters(context.gl, GL_TEXTURE_2D);
context.bindTexture(GL_TEXTURE_2D, 0);
gl.copyImageSubData(context.texIds[1], GL_TEXTURE_2D, 0, 0, 0, 0, context.texIds[0], GL_TEXTURE_2D, 0, 0, 0, 0, image[0].width, image[0].height, 1);
},
GL_NO_ERROR
});
}
}
}
}
},
{
gles32, // ApiType minApi;
"copy_uncompressed_to_compressed", // string name;
"Copying pixels from uncompressed to compressed texture", // string description;
2, // size_t texIdsCount;
0, // size_t bufferIdsCount;
{}, // vector<ApiCaseStep> steps;
[](deqp::Context&, vector<ApiCaseStep>& steps) // ApiCaseStepGeneratorFn stepsGenerator;
{
for(const auto& format : copyFormats)
{
if (format.second.empty())
continue;
for(const auto& uncompressedFormat : format.first)
{
for(const auto& compressedFormat : format.second)
{
steps.push_back(
{
[uncompressedFormat, compressedFormat](ApiTestContext& context)
{
const auto& gl = context.gl;
const auto& image = imageData.at(compressedFormat);
const auto& unsizedInfo = unsizedFormats.at(uncompressedFormat);
const auto textureData = loadImage(context.archive, compressedFormat, 0);
const auto compressedInfo = find_if(begin(compressedFormats), end(compressedFormats), [compressedFormat](const FormatInfo& fmt) { return fmt.internalFormat == compressedFormat; });
DE_ASSERT(compressedInfo != end(compressedFormats));
const auto sourceWidth = image[0].width / compressedInfo->blockSize[0];
const auto sourceHeight = image[0].height / compressedInfo->blockSize[1];
DE_ASSERT((GLsizei)textureData.width == image[0].width && (GLsizei)textureData.height == image[0].height);
context.log
<< TestLog::Message
<< "Copying from " << getTextureFormatStr(uncompressedFormat).toString() << " " << sourceWidth << "x" << sourceHeight
<< " to " << getTextureFormatStr(compressedFormat).toString() << " " << image[0].width << "x" << image[0].height
<< TestLog::EndMessage;
context.bindTexture(GL_TEXTURE_2D, context.texIds[0]);
gl.texImage2D(GL_TEXTURE_2D, 0, uncompressedFormat, sourceWidth, sourceHeight, 0, unsizedInfo.format, unsizedInfo.dataType, 0);
GLU_EXPECT_NO_ERROR(gl.getError(), "glTexImage2D() failed");
setTextureParameters(context.gl, GL_TEXTURE_2D);
context.bindTexture(GL_TEXTURE_2D, context.texIds[1]);
gl.compressedTexImage2D(GL_TEXTURE_2D, 0, compressedFormat, image[0].width, image[0].height, 0, textureData.data.size(), textureData.data.data());
GLU_EXPECT_NO_ERROR(gl.getError(), "glCompressedTexImage2D() failed");
setTextureParameters(context.gl, GL_TEXTURE_2D);
context.bindTexture(GL_TEXTURE_2D, 0);
gl.copyImageSubData(context.texIds[0], GL_TEXTURE_2D, 0, 0, 0, 0, context.texIds[1], GL_TEXTURE_2D, 0, 0, 0, 0, sourceWidth, sourceHeight, 1);
},
GL_NO_ERROR
});
}
}
}
}
},
{
gles32, // ApiType minApi;
"copy_compressed_to_compressed", // string name;
"Copying of pixels between compatible compressed texture formats", // string description;
2, // size_t texIdsCount;
0, // size_t bufferIdsCount;
{}, // vector<ApiCaseStep> steps;
[](deqp::Context&, vector<ApiCaseStep>& steps) // ApiCaseStepGeneratorFn stepsGenerator;
{
for(const auto& format : copyFormats)
{
if (!format.second.empty())
continue;
for(const auto& format0 : format.first)
{
for(const auto& format1 : format.first)
{
steps.push_back(
{
[format0, format1](ApiTestContext& context)
{
const auto& gl = context.gl;
const auto image0 = loadImage(context.archive, format0, 0);
const auto image1 = loadImage(context.archive, format1, 1);
DE_ASSERT(image0.width == 2 * image1.width && image0.height == 2 * image1.height);
context.bindTexture(GL_TEXTURE_2D, context.texIds[0]);
gl.compressedTexImage2D(GL_TEXTURE_2D, 0, format0, image0.width, image0.height, 0, image0.data.size(), image0.data.data());
GLU_EXPECT_NO_ERROR(gl.getError(), "glCompressedTexImage2D() failed");
setTextureParameters(context.gl, GL_TEXTURE_2D);
context.bindTexture(GL_TEXTURE_2D, context.texIds[1]);
gl.compressedTexImage2D(GL_TEXTURE_2D, 0, format1, image1.width, image1.height, 0, image1.data.size(), image1.data.data());
GLU_EXPECT_NO_ERROR(gl.getError(), "glCompressedTexImage2D() failed");
setTextureParameters(context.gl, GL_TEXTURE_2D);
context.bindTexture(GL_TEXTURE_2D, 0);
gl.copyImageSubData(context.texIds[1], GL_TEXTURE_2D, 0, 0, 0, 0, context.texIds[0], GL_TEXTURE_2D, 0, 0, 0, 0, image1.width, image1.height, 1);
},
GL_NO_ERROR
});
}
}
}
}
}
};
class CompressedApiTest : public deqp::TestCase
{
public:
explicit CompressedApiTest (deqp::Context& context, const ApiCaseParams& params);
virtual ~CompressedApiTest ();
virtual void init (void) override;
virtual void deinit (void) override;
virtual IterateResult iterate (void) override;
private:
ApiCaseParams m_params;
vector<GLuint> m_texIds;
vector<GLuint> m_bufferIds;
};
CompressedApiTest::CompressedApiTest (deqp::Context& context, const ApiCaseParams& params)
: deqp::TestCase(context, params.name.c_str(), params.description.c_str())
, m_params(params)
{
}
CompressedApiTest::~CompressedApiTest ()
{
}
void CompressedApiTest::init (void)
{
const auto& gl = m_context.getRenderContext().getFunctions();
if (m_params.texIdsCount > 0)
{
m_texIds.resize(m_params.texIdsCount);
gl.genTextures(m_texIds.size(), m_texIds.data());
GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTextures() failed");
m_bufferIds.resize(m_params.bufferIdsCount);
gl.genBuffers(m_bufferIds.size(), m_bufferIds.data());
GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() failed");
}
}
void CompressedApiTest::deinit (void)
{
const auto& gl = m_context.getRenderContext().getFunctions();
if (!m_bufferIds.empty())
{
gl.deleteBuffers(m_bufferIds.size(), m_bufferIds.data());
GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteBuffers() failed");
m_bufferIds.erase(m_bufferIds.begin(), m_bufferIds.end());
}
if (!m_texIds.empty())
{
gl.deleteTextures(m_texIds.size(), m_texIds.data());
GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteTextures() failed");
m_texIds.erase(m_texIds.begin(), m_texIds.end());
}
}
CompressedApiTest::IterateResult CompressedApiTest::iterate (void)
{
const auto& gl = m_context.getRenderContext().getFunctions();
ApiTestContext caseContext =
{
m_context.getTestContext().getLog(),
gl,
m_texIds,
m_bufferIds,
m_context.getTestContext().getArchive()
};
vector<ApiCaseStep> steps (m_params.steps);
if (m_params.stepsGenerator)
m_params.stepsGenerator(m_context, steps);
size_t stepIndex = 0;
for(const auto& step : steps)
{
step.code(caseContext);
const auto errorCode = gl.getError();
if (errorCode != step.expectedError)
{
ostringstream msg;
msg << "Got wrong error code: " << glu::getErrorStr(errorCode)
<< ", expected: " << glu::getErrorStr(step.expectedError)
<< " after step " << stepIndex;
TCU_FAIL(msg.str().c_str());
}
++stepIndex;
}
m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Pass");
return IterateResult::STOP;
}
class CompressedFormatTest : public deqp::TestCase
{
public:
CompressedFormatTest (deqp::Context& context, shared_ptr<SharedData> data, const FormatInfo& format);
virtual ~CompressedFormatTest ();
virtual void init (void);
virtual void deinit (void);
virtual IterateResult iterate (void);
private:
Surface drawTestImage (const glw::Functions& gl, GLuint texId, GLsizei width, GLsizei height);
shared_ptr<SharedData> m_data;
const FormatInfo& formatInfo;
};
CompressedFormatTest::CompressedFormatTest (deqp::Context& context, shared_ptr<SharedData> data, const FormatInfo& format)
: deqp::TestCase(context, format.name, "Test rendering of compressed format ")
, m_data(data)
, formatInfo(format)
{
}
CompressedFormatTest::~CompressedFormatTest ()
{
}
void CompressedFormatTest::init (void)
{
m_data->init();
}
void CompressedFormatTest::deinit (void)
{
m_data->deinit();
}
Surface CompressedFormatTest::drawTestImage (const glw::Functions& gl, GLuint texId, GLsizei width, GLsizei height)
{
gl.clearColor(1.0f, 0.2f, 1.0f, 1.0f);
gl.clear(GL_COLOR_BUFFER_BIT);
GLU_EXPECT_NO_ERROR(gl.getError(), "glClear() failed");
gl.disable(GL_BLEND);
GLU_EXPECT_NO_ERROR(gl.getError(), "glDisable() failed");
gl.bindTexture(GL_TEXTURE_2D, texId);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() failed");
gl.drawArrays(GL_TRIANGLE_STRIP, 0, 4);
GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() failed");
gl.bindTexture(GL_TEXTURE_2D, 0);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() failed");
Surface result(width, height);
readPixels(m_context.getRenderContext(), 0, 0, result.getAccess());
return result;
}
CompressedFormatTest::IterateResult CompressedFormatTest::iterate (void)
{
const auto& archive = m_context.getTestContext().getArchive();
const auto image0 = loadImage(archive, formatInfo.internalFormat, 0);
const auto image1 = loadImage(archive, formatInfo.internalFormat, 1);
const auto image2 = loadImage(archive, formatInfo.internalFormat, 2);
DE_ASSERT(image0.width == 2 * image1.width &&
image0.height == 2 * image1.height &&
image0.width % 4 == 0 &&
image0.height % 4 == 0 &&
image0.width == image2.width &&
image0.height == image2.height);
const auto& gl = m_context.getRenderContext().getFunctions();
GLuint texIds[2];
gl.genTextures(DE_LENGTH_OF_ARRAY(texIds), texIds);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTextures() failed");
GLuint fboId;
gl.genFramebuffers(1, &fboId);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGenFramebuffers() failed");
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");
const GLenum bufferFormats[2][2] = {
{ GL_RGB8 , GL_SRGB8_ALPHA8 },
{ GL_RGBA8 , GL_SRGB8_ALPHA8 }
};
const bool hasAlpha = formatInfo.format == GL_RGBA;
gl.renderbufferStorage(GL_RENDERBUFFER, bufferFormats[hasAlpha][formatInfo.issRGB], image0.width, image0.height);
GLU_EXPECT_NO_ERROR(gl.getError(), "glRenderbufferStorage() failed");
gl.bindRenderbuffer(GL_RENDERBUFFER, 0);
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, image0.width, image0.height);
GLU_EXPECT_NO_ERROR(gl.getError(), "glViewport() failed");
gl.useProgram(m_data->programId());
GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() failed");
gl.uniform4fv(m_data->offsetLoc(), 1, defaultOffset.offset.getPtr());
GLU_EXPECT_NO_ERROR(gl.getError(), "glUniform4fv() failed");
gl.uniform4fv(m_data->scaleLoc(), 1, defaultOffset.scale.getPtr());
GLU_EXPECT_NO_ERROR(gl.getError(), "glUniform4fv() failed");
gl.blendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBlendFunc() failed");
gl.disable(GL_BLEND);
GLU_EXPECT_NO_ERROR(gl.getError(), "glDisable() failed");
// reference image
gl.bindTexture(GL_TEXTURE_2D, texIds[0]);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() failed");
gl.texImage2D(GL_TEXTURE_2D, 0, formatInfo.sizedFormat, image2.width, image2.height, 0, formatInfo.format, GL_UNSIGNED_BYTE, image2.data.data());
GLU_EXPECT_NO_ERROR(gl.getError(), "glTexImage2D() failed");
setTextureParameters(gl, GL_TEXTURE_2D);
// compressed image
gl.bindTexture(GL_TEXTURE_2D, texIds[1]);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() failed");
gl.compressedTexImage2D(GL_TEXTURE_2D, 0, formatInfo.internalFormat, image0.width, image0.height, 0, image0.data.size(), image0.data.data());
GLU_EXPECT_NO_ERROR(gl.getError(), "glCompressedTexImage2D() failed");
gl.compressedTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, image1.width, image1.height, formatInfo.internalFormat, image1.data.size(), image1.data.data());
GLU_EXPECT_NO_ERROR(gl.getError(), "glCompressedTexSubImage2D() failed");
setTextureParameters(gl, GL_TEXTURE_2D);
gl.bindTexture(GL_TEXTURE_2D, 0);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() failed");
gl.bindVertexArray(m_data->vaoId());
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray() failed");
gl.useProgram(m_data->programId());
GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() failed");
gl.uniform4fv(m_data->offsetLoc(), 1, defaultOffset.offset.getPtr());
GLU_EXPECT_NO_ERROR(gl.getError(), "glUniform4fv() failed");
gl.uniform4fv(m_data->scaleLoc(), 1, defaultOffset.scale.getPtr());
GLU_EXPECT_NO_ERROR(gl.getError(), "glUniform4fv() failed");
const auto referenceImage = drawTestImage(gl, texIds[0], image0.width, image0.height);
const auto& offsetIt = offsets.find(formatInfo.internalFormat);
const auto& offset = offsetIt != offsets.end() ? offsetIt->second : defaultOffset;
gl.uniform4fv(m_data->offsetLoc(), 1, offset.offset.getPtr());
GLU_EXPECT_NO_ERROR(gl.getError(), "glUniform4fv() failed");
gl.uniform4fv(m_data->scaleLoc(), 1, offset.scale.getPtr());
GLU_EXPECT_NO_ERROR(gl.getError(), "glUniform4fv() failed");
const auto compressedImage = drawTestImage(gl, texIds[1], image0.width, image0.height);
gl.disable(GL_BLEND);
GLU_EXPECT_NO_ERROR(gl.getError(), "glDisable() failed");
gl.bindTexture(GL_TEXTURE_2D, 0);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindtexture() failed");
gl.deleteRenderbuffers(1, &rboId);
GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteRenderbuffers() failed");
gl.deleteTextures(DE_LENGTH_OF_ARRAY(texIds), texIds);
GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteTextures() failed");
gl.deleteFramebuffers(1, &fboId);
GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteFramebuffers() failed");
if (!fuzzyCompare(m_testCtx.getLog(), "compressed_vs_uncompressed", "Image comparison result", referenceImage, compressedImage, 0.0f, CompareLogMode::COMPARE_LOG_ON_ERROR))
TCU_FAIL("Rendered image comparison failed.");
m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Pass");
return IterateResult::STOP;
}
} //
CompressedFormatTests::CompressedFormatTests (deqp::Context& context)
: deqp::TestCaseGroup(context, "compressed_format", "Tests for compressed image formats")
{
}
CompressedFormatTests::~CompressedFormatTests (void)
{
}
void CompressedFormatTests::init (void)
{
const auto apiGroup = new TestCaseGroup(m_context, "api", "Api call return values");
addChild(apiGroup);
for(const auto& apiCase : apiTests)
if (glu::contextSupports(m_context.getRenderContext().getType(), apiCase.minApi))
apiGroup->addChild(new CompressedApiTest(m_context, apiCase));
const auto formatGroup = new TestCaseGroup(m_context, "format", "Compressed format textures");
addChild(formatGroup);
const auto sharedData = make_shared<SharedData>(m_context);
for(const auto& formatInfo : compressedFormats)
if (glu::contextSupports(m_context.getRenderContext().getType(), formatInfo.minApi))
formatGroup->addChild(new CompressedFormatTest(m_context, sharedData, formatInfo));
}
} // glcts