blob: a3c4b21a884ade9e65817398b4d9cb5240a4ab37 [file] [log] [blame]
//
// Copyright 2016 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// CopyCompressedTextureTest.cpp: Tests of the GL_CHROMIUM_copy_compressed_texture extension
#include "test_utils/ANGLETest.h"
namespace angle
{
class CopyCompressedTextureTest : public ANGLETest
{
protected:
CopyCompressedTextureTest()
{
setWindowWidth(256);
setWindowHeight(256);
setConfigRedBits(8);
setConfigGreenBits(8);
setConfigBlueBits(8);
setConfigAlphaBits(8);
}
void testSetUp() override
{
glGenTextures(2, mTextures);
constexpr char kVS[] =
"attribute vec2 a_position;\n"
"varying vec2 v_texcoord;\n"
"void main()\n"
"{\n"
" gl_Position = vec4(a_position, 0.0, 1.0);\n"
" v_texcoord = (a_position + 1.0) * 0.5;\n"
"}\n";
constexpr char kFS[] =
"precision mediump float;\n"
"uniform sampler2D u_texture;\n"
"varying vec2 v_texcoord;\n"
"void main()\n"
"{\n"
" gl_FragColor = texture2D(u_texture, v_texcoord);\n"
"}\n";
mProgram = CompileProgram(kVS, kFS);
ASSERT_NE(0u, mProgram);
}
void testTearDown() override
{
glDeleteTextures(2, mTextures);
glDeleteProgram(mProgram);
}
bool checkExtensions() const
{
if (!IsGLExtensionEnabled("GL_CHROMIUM_copy_compressed_texture"))
{
std::cout
<< "Test skipped because GL_CHROMIUM_copy_compressed_texture is not available."
<< std::endl;
return false;
}
EXPECT_NE(nullptr, glCompressedCopyTextureCHROMIUM);
if (glCompressedCopyTextureCHROMIUM == nullptr)
{
return false;
}
return true;
}
GLuint mProgram = 0;
GLuint mTextures[2] = {0, 0};
};
namespace
{
const GLColor &CompressedImageColor = GLColor::red;
// Single compressed ATC block of source pixels all set to:
// CompressedImageColor.
const uint8_t CompressedImageATC[8] = {0x0, 0x7c, 0x0, 0xf8, 0x55, 0x55, 0x55, 0x55};
// Single compressed ATCIA block of source pixels all set to:
// CompressedImageColor.
const uint8_t CompressedImageATCIA[16] = {0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x7c, 0x0, 0xf8, 0x55, 0x55, 0x55, 0x55};
// Single compressed DXT1 block of source pixels all set to:
// CompressedImageColor.
const uint8_t CompressedImageDXT1[8] = {0x00, 0xf8, 0x00, 0xf8, 0xaa, 0xaa, 0xaa, 0xaa};
// Single compressed DXT5 block of source pixels all set to:
// CompressedImageColor.
const uint8_t CompressedImageDXT5[16] = {0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0xf8, 0x0, 0xf8, 0xaa, 0xaa, 0xaa, 0xaa};
// Single compressed DXT1 block of source pixels all set to:
// CompressedImageColor.
const uint8_t CompressedImageETC1[8] = {0x0, 0x0, 0xf8, 0x2, 0xff, 0xff, 0x0, 0x0};
} // anonymous namespace
// Test to ensure that the basic functionality of the extension works.
TEST_P(CopyCompressedTextureTest, Basic)
{
ANGLE_SKIP_TEST_IF(!checkExtensions());
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_compression_dxt1"));
glBindTexture(GL_TEXTURE_2D, mTextures[0]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 4, 4, 0,
sizeof(CompressedImageDXT1), CompressedImageDXT1);
ASSERT_GL_NO_ERROR();
glBindTexture(GL_TEXTURE_2D, mTextures[1]);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glCompressedCopyTextureCHROMIUM(mTextures[0], mTextures[1]);
ASSERT_GL_NO_ERROR();
// Load texture.
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, mTextures[1]);
GLint textureLoc = glGetUniformLocation(mProgram, "u_texture");
glUseProgram(mProgram);
glUniform1i(textureLoc, 0);
// Draw.
drawQuad(mProgram, "a_position", 0.5f);
EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, CompressedImageColor);
ASSERT_GL_NO_ERROR();
}
// Test validation of compressed formats
TEST_P(CopyCompressedTextureTest, InternalFormat)
{
if (!checkExtensions())
{
return;
}
struct Data
{
GLint format;
const uint8_t *data;
GLsizei dataSize;
Data() : Data(GL_NONE, nullptr, 0) {}
Data(GLint format, const uint8_t *data, GLsizei dataSize)
: format(format), data(data), dataSize(dataSize)
{}
};
std::vector<Data> supportedFormats;
if (IsGLExtensionEnabled("GL_AMD_compressed_ATC_texture"))
{
supportedFormats.push_back(
Data(GL_ATC_RGB_AMD, CompressedImageATC, sizeof(CompressedImageATC)));
supportedFormats.push_back(Data(GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD, CompressedImageATCIA,
sizeof(CompressedImageATCIA)));
}
if (IsGLExtensionEnabled("GL_EXT_texture_compression_dxt1"))
{
supportedFormats.push_back(Data(GL_COMPRESSED_RGB_S3TC_DXT1_EXT, CompressedImageDXT1,
sizeof(CompressedImageDXT1)));
}
if (IsGLExtensionEnabled("GL_ANGLE_texture_compression_dxt5"))
{
supportedFormats.push_back(Data(GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, CompressedImageDXT5,
sizeof(CompressedImageDXT5)));
}
if (IsGLExtensionEnabled("GL_OES_compressed_ETC1_RGB8_texture"))
{
supportedFormats.push_back(
Data(GL_ETC1_RGB8_OES, CompressedImageETC1, sizeof(CompressedImageETC1)));
}
for (const auto &supportedFormat : supportedFormats)
{
glBindTexture(GL_TEXTURE_2D, mTextures[0]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glCompressedTexImage2D(GL_TEXTURE_2D, 0, supportedFormat.format, 4, 4, 0,
supportedFormat.dataSize, supportedFormat.data);
ASSERT_GL_NO_ERROR();
glBindTexture(GL_TEXTURE_2D, mTextures[1]);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glCompressedCopyTextureCHROMIUM(mTextures[0], mTextures[1]);
ASSERT_GL_NO_ERROR();
}
}
// Test that uncompressed textures generate errors when copying
TEST_P(CopyCompressedTextureTest, InternalFormatNotSupported)
{
if (!checkExtensions())
{
return;
}
glBindTexture(GL_TEXTURE_2D, mTextures[0]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::red);
ASSERT_GL_NO_ERROR();
glBindTexture(GL_TEXTURE_2D, mTextures[1]);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
ASSERT_GL_NO_ERROR();
// Check that the GL_RGBA format reports an error.
glCompressedCopyTextureCHROMIUM(mTextures[0], mTextures[1]);
EXPECT_GL_ERROR(GL_INVALID_OPERATION);
}
// Test validation of texture IDs
TEST_P(CopyCompressedTextureTest, InvalidTextureIds)
{
if (!checkExtensions())
{
return;
}
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_compression_dxt1"));
glBindTexture(GL_TEXTURE_2D, mTextures[0]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 4, 4, 0,
sizeof(CompressedImageDXT1), CompressedImageDXT1);
ASSERT_GL_NO_ERROR();
glBindTexture(GL_TEXTURE_2D, mTextures[1]);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
ASSERT_GL_NO_ERROR();
glCompressedCopyTextureCHROMIUM(mTextures[0], 99993);
EXPECT_GL_ERROR(GL_INVALID_VALUE);
glCompressedCopyTextureCHROMIUM(99994, mTextures[1]);
EXPECT_GL_ERROR(GL_INVALID_VALUE);
glCompressedCopyTextureCHROMIUM(99995, 99996);
EXPECT_GL_ERROR(GL_INVALID_VALUE);
glCompressedCopyTextureCHROMIUM(mTextures[0], mTextures[1]);
EXPECT_GL_NO_ERROR();
}
// Test that only 2D textures are valid
TEST_P(CopyCompressedTextureTest, BindingPoints)
{
if (!checkExtensions())
{
return;
}
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_compression_dxt1"));
glBindTexture(GL_TEXTURE_CUBE_MAP, mTextures[0]);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
for (GLenum face = GL_TEXTURE_CUBE_MAP_POSITIVE_X; face <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z;
face++)
{
glCompressedTexImage2D(face, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 4, 4, 0,
sizeof(CompressedImageDXT1), CompressedImageDXT1);
}
ASSERT_GL_NO_ERROR();
glBindTexture(GL_TEXTURE_CUBE_MAP, mTextures[1]);
glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
ASSERT_GL_NO_ERROR();
glCompressedCopyTextureCHROMIUM(mTextures[0], mTextures[1]);
EXPECT_GL_ERROR(GL_INVALID_VALUE);
}
// Test the destination texture cannot be immutable
TEST_P(CopyCompressedTextureTest, Immutable)
{
if (!checkExtensions() || getClientMajorVersion() < 3)
{
return;
}
// http://anglebug.com/4092
ANGLE_SKIP_TEST_IF((IsAndroid() && IsVulkan()) || isSwiftshader());
glBindTexture(GL_TEXTURE_2D, mTextures[0]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 4, 4, 0,
sizeof(CompressedImageDXT1), CompressedImageDXT1);
ASSERT_GL_NO_ERROR();
glBindTexture(GL_TEXTURE_2D, mTextures[1]);
glTexStorage2D(GL_TEXTURE_2D, 1, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 4, 4);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
ASSERT_GL_NO_ERROR();
glCompressedCopyTextureCHROMIUM(mTextures[0], mTextures[1]);
EXPECT_GL_ERROR(GL_INVALID_OPERATION);
}
// Use this to select which configurations (e.g. which renderer, which GLES major version) these
// tests should be run against.
ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(CopyCompressedTextureTest);
} // namespace angle