blob: 821668533b4273c29c3e5dc2dd3e528525cff0d7 [file] [log] [blame]
//
// Copyright 2015 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.
//
// ETCTextureTest:
// Tests for ETC lossy decode formats.
//
#include "test_utils/ANGLETest.h"
#include "media/etc2bc_srgb8_alpha8.inc"
using namespace angle;
namespace
{
class ETCTextureTest : public ANGLETest<>
{
protected:
ETCTextureTest() : mTexture(0u)
{
setWindowWidth(128);
setWindowHeight(128);
setConfigRedBits(8);
setConfigGreenBits(8);
setConfigBlueBits(8);
setConfigAlphaBits(8);
}
void testSetUp() override
{
glGenTextures(1, &mTexture);
ASSERT_GL_NO_ERROR();
}
void testTearDown() override { glDeleteTextures(1, &mTexture); }
GLuint mTexture;
};
// Tests a texture with ETC1 lossy decode format
TEST_P(ETCTextureTest, ETC1Validation)
{
bool supported = IsGLExtensionEnabled("GL_ANGLE_lossy_etc_decode");
glBindTexture(GL_TEXTURE_2D, mTexture);
GLubyte pixel[8] = {0x0, 0x0, 0xf8, 0x2, 0x43, 0xff, 0x4, 0x12};
glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_ETC1_RGB8_LOSSY_DECODE_ANGLE, 4, 4, 0,
sizeof(pixel), pixel);
if (supported)
{
EXPECT_GL_NO_ERROR();
glCompressedTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 4, 4, GL_ETC1_RGB8_LOSSY_DECODE_ANGLE,
sizeof(pixel), pixel);
EXPECT_GL_NO_ERROR();
glCompressedTexImage2D(GL_TEXTURE_2D, 1, GL_ETC1_RGB8_LOSSY_DECODE_ANGLE, 2, 2, 0,
sizeof(pixel), pixel);
EXPECT_GL_NO_ERROR();
glCompressedTexImage2D(GL_TEXTURE_2D, 2, GL_ETC1_RGB8_LOSSY_DECODE_ANGLE, 1, 1, 0,
sizeof(pixel), pixel);
EXPECT_GL_NO_ERROR();
}
else
{
EXPECT_GL_ERROR(GL_INVALID_ENUM);
}
}
// Tests a texture with ETC2 RGB8 lossy decode format
TEST_P(ETCTextureTest, ETC2RGB8Validation)
{
bool supported = IsGLExtensionEnabled("GL_ANGLE_lossy_etc_decode");
glBindTexture(GL_TEXTURE_2D, mTexture);
GLubyte pixel[] = {
0x00, 0x00, 0xf8, 0x02, 0x43, 0xff, 0x04, 0x12, // Individual/differential block
0x1c, 0x65, 0xc6, 0x62, 0xff, 0xf0, 0xff, 0x00, // T block
0x62, 0xf2, 0xe3, 0x32, 0xff, 0x0f, 0xff, 0x00, // H block
0x71, 0x88, 0xfb, 0xee, 0x87, 0x07, 0x11, 0x1f // Planar block
};
glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB8_LOSSY_DECODE_ETC2_ANGLE, 8, 8, 0,
sizeof(pixel), pixel);
if (supported)
{
EXPECT_GL_NO_ERROR();
glCompressedTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 8, 8,
GL_COMPRESSED_RGB8_LOSSY_DECODE_ETC2_ANGLE, sizeof(pixel), pixel);
EXPECT_GL_NO_ERROR();
const GLsizei imageSize = 8;
glCompressedTexImage2D(GL_TEXTURE_2D, 1, GL_COMPRESSED_RGB8_LOSSY_DECODE_ETC2_ANGLE, 4, 4,
0, imageSize, pixel);
EXPECT_GL_NO_ERROR();
glCompressedTexImage2D(GL_TEXTURE_2D, 2, GL_COMPRESSED_RGB8_LOSSY_DECODE_ETC2_ANGLE, 2, 2,
0, imageSize, pixel);
EXPECT_GL_NO_ERROR();
glCompressedTexImage2D(GL_TEXTURE_2D, 3, GL_COMPRESSED_RGB8_LOSSY_DECODE_ETC2_ANGLE, 1, 1,
0, imageSize, pixel);
EXPECT_GL_NO_ERROR();
}
else
{
EXPECT_GL_ERROR(GL_INVALID_ENUM);
}
}
// Tests a cube map array texture with compressed ETC2 RGB8 format
TEST_P(ETCTextureTest, ETC2RGB8_CubeMapValidation)
{
ANGLE_SKIP_TEST_IF(!(IsGLExtensionEnabled("GL_EXT_texture_cube_map_array") &&
(getClientMajorVersion() >= 3 && getClientMinorVersion() > 1)));
constexpr GLsizei kInvalidTextureWidth = 8;
constexpr GLsizei kInvalidTextureHeight = 8;
constexpr GLsizei kCubemapFaceCount = 6;
const std::vector<GLubyte> kInvalidTextureData(
kInvalidTextureWidth * kInvalidTextureHeight * kCubemapFaceCount, 0);
glBindTexture(GL_TEXTURE_CUBE_MAP, mTexture);
EXPECT_GL_NO_ERROR();
glCompressedTexImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, 0, GL_RGB, kInvalidTextureWidth,
kInvalidTextureHeight, kCubemapFaceCount, 0, kInvalidTextureData.size(),
kInvalidTextureData.data());
EXPECT_GL_ERROR(GL_INVALID_ENUM);
constexpr GLenum kFormat = GL_COMPRESSED_RGB8_ETC2;
std::vector<GLubyte> arrayData;
constexpr GLuint kWidth = 4u;
constexpr GLuint kHeight = 4u;
constexpr GLuint kDepth = 6u;
constexpr GLuint kPixelBytes = 8u;
constexpr GLuint kBlockWidth = 4u;
constexpr GLuint kBlockHeight = 4u;
constexpr GLuint kNumBlocksWide = (kWidth + kBlockWidth - 1u) / kBlockWidth;
constexpr GLuint kNumBlocksHigh = (kHeight + kBlockHeight - 1u) / kBlockHeight;
constexpr GLuint kBytes = kNumBlocksWide * kNumBlocksHigh * kPixelBytes * kDepth;
arrayData.reserve(kBytes);
glCompressedTexImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, 0, kFormat, kWidth, kHeight, kDepth, 0,
kBytes, arrayData.data());
EXPECT_GL_NO_ERROR();
glCompressedTexSubImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, 0, 0, 0, 0, kInvalidTextureWidth,
kInvalidTextureHeight, kDepth, GL_RGB, kInvalidTextureData.size(),
kInvalidTextureData.data());
glCompressedTexSubImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, 0, 0, 0, 0, kInvalidTextureWidth,
kInvalidTextureHeight, kDepth, GL_RGB, kInvalidTextureData.size(),
kInvalidTextureData.data());
EXPECT_GL_ERROR(GL_INVALID_OPERATION);
}
// Tests a texture with ETC2 SRGB8 lossy decode format
TEST_P(ETCTextureTest, ETC2SRGB8Validation)
{
bool supported = IsGLExtensionEnabled("GL_ANGLE_lossy_etc_decode");
glBindTexture(GL_TEXTURE_2D, mTexture);
GLubyte pixel[] = {
0x00, 0x00, 0xf8, 0x02, 0x43, 0xff, 0x04, 0x12, // Individual/differential block
0x1c, 0x65, 0xc6, 0x62, 0xff, 0xf0, 0xff, 0x00, // T block
0x62, 0xf2, 0xe3, 0x32, 0xff, 0x0f, 0xff, 0x00, // H block
0x71, 0x88, 0xfb, 0xee, 0x87, 0x07, 0x11, 0x1f // Planar block
};
glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_SRGB8_LOSSY_DECODE_ETC2_ANGLE, 8, 8, 0,
sizeof(pixel), pixel);
if (supported)
{
EXPECT_GL_NO_ERROR();
glCompressedTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 8, 8,
GL_COMPRESSED_SRGB8_LOSSY_DECODE_ETC2_ANGLE, sizeof(pixel),
pixel);
EXPECT_GL_NO_ERROR();
const GLsizei imageSize = 8;
glCompressedTexImage2D(GL_TEXTURE_2D, 1, GL_COMPRESSED_SRGB8_LOSSY_DECODE_ETC2_ANGLE, 4, 4,
0, imageSize, pixel);
EXPECT_GL_NO_ERROR();
glCompressedTexImage2D(GL_TEXTURE_2D, 2, GL_COMPRESSED_SRGB8_LOSSY_DECODE_ETC2_ANGLE, 2, 2,
0, imageSize, pixel);
EXPECT_GL_NO_ERROR();
glCompressedTexImage2D(GL_TEXTURE_2D, 3, GL_COMPRESSED_SRGB8_LOSSY_DECODE_ETC2_ANGLE, 1, 1,
0, imageSize, pixel);
EXPECT_GL_NO_ERROR();
}
else
{
EXPECT_GL_ERROR(GL_INVALID_ENUM);
}
}
// Tests a texture with ETC2 RGB8 punchthrough A1 lossy decode format
TEST_P(ETCTextureTest, ETC2RGB8A1Validation)
{
bool supported = IsGLExtensionEnabled("GL_ANGLE_lossy_etc_decode");
glBindTexture(GL_TEXTURE_2D, mTexture);
GLubyte pixel[] = {
0x80, 0x98, 0x59, 0x02, 0x6e, 0xe7, 0x44, 0x47, // Individual/differential block
0xeb, 0x85, 0x68, 0x30, 0x77, 0x73, 0x44, 0x44, // T block
0xb4, 0x05, 0xab, 0x92, 0xf8, 0x8c, 0x07, 0x73, // H block
0xbb, 0x90, 0x15, 0xba, 0x8a, 0x8c, 0xd5, 0x5f // Planar block
};
glCompressedTexImage2D(GL_TEXTURE_2D, 0,
GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE, 8, 8, 0,
sizeof(pixel), pixel);
if (supported)
{
EXPECT_GL_NO_ERROR();
glCompressedTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 8, 8,
GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE,
sizeof(pixel), pixel);
EXPECT_GL_NO_ERROR();
const GLsizei imageSize = 8;
glCompressedTexImage2D(GL_TEXTURE_2D, 1,
GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE, 4, 4,
0, imageSize, pixel);
EXPECT_GL_NO_ERROR();
glCompressedTexImage2D(GL_TEXTURE_2D, 2,
GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE, 2, 2,
0, imageSize, pixel);
EXPECT_GL_NO_ERROR();
glCompressedTexImage2D(GL_TEXTURE_2D, 3,
GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE, 1, 1,
0, imageSize, pixel);
EXPECT_GL_NO_ERROR();
}
else
{
EXPECT_GL_ERROR(GL_INVALID_ENUM);
}
}
// Tests a texture with ETC2 SRGB8 punchthrough A1 lossy decode format
TEST_P(ETCTextureTest, ETC2SRGB8A1Validation)
{
bool supported = IsGLExtensionEnabled("GL_ANGLE_lossy_etc_decode");
glBindTexture(GL_TEXTURE_2D, mTexture);
GLubyte pixel[] = {
0x80, 0x98, 0x59, 0x02, 0x6e, 0xe7, 0x44, 0x47, // Individual/differential block
0xeb, 0x85, 0x68, 0x30, 0x77, 0x73, 0x44, 0x44, // T block
0xb4, 0x05, 0xab, 0x92, 0xf8, 0x8c, 0x07, 0x73, // H block
0xbb, 0x90, 0x15, 0xba, 0x8a, 0x8c, 0xd5, 0x5f // Planar block
};
glCompressedTexImage2D(GL_TEXTURE_2D, 0,
GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE, 8, 8, 0,
sizeof(pixel), pixel);
if (supported)
{
EXPECT_GL_NO_ERROR();
glCompressedTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 8, 8,
GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE,
sizeof(pixel), pixel);
EXPECT_GL_NO_ERROR();
const GLsizei imageSize = 8;
glCompressedTexImage2D(GL_TEXTURE_2D, 1,
GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE, 4,
4, 0, imageSize, pixel);
EXPECT_GL_NO_ERROR();
glCompressedTexImage2D(GL_TEXTURE_2D, 2,
GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE, 2,
2, 0, imageSize, pixel);
EXPECT_GL_NO_ERROR();
glCompressedTexImage2D(GL_TEXTURE_2D, 3,
GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE, 1,
1, 0, imageSize, pixel);
EXPECT_GL_NO_ERROR();
}
else
{
EXPECT_GL_ERROR(GL_INVALID_ENUM);
}
}
class ETCToBCTextureTest : public ANGLETest<>
{
protected:
static constexpr int kWidth = 4;
static constexpr int kHeight = 4;
static constexpr int kTexSize = 4;
static constexpr int kAbsError = 6;
// the transcoded BC1 data
// {0x0000a534, 0x05055555}
// then decoded RGBA data are
// 0xff000000 0xff000000 0xff000000 0xff000000
// 0xff000000 0xff000000 0xff000000 0xff000000
// 0xff000000 0xff000000 0xffa5a6a5 0xffa5a6a5
// 0xff000000 0xff000000 0xffa5a6a5 0xffa5a6a5
static constexpr uint32_t kEtcAllZero[2] = {0x0, 0x0};
static constexpr uint32_t kEtcRGBData[2] = {0x14050505, 0x00ffff33};
static constexpr uint32_t kExpectedRGBColor[16] = {
0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000,
0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffa5a6a5, 0xffa5a6a5,
0xff000000, 0xff000000, 0xffa5a6a5, 0xffa5a6a5,
};
// the transcoded RGB data (BC1)
// {0x0000a534 0x58585c5f}
// the 16 ETC2 decoded alpha value are
// 20, 20, 182, 182
// 128, 128, 110, 110
// 128, 47, 47, 47
// 128, 65, 65, 65
// max alpha value = 0xb6
// min alpha value = 0x14
// Result BC4 data are 0xb00914b6, 0xdb3ffb91
static constexpr uint32_t kEtcRGBAData[4] = {0xd556975c, 0x088ff048, 0x9e6c6c6c, 0x3f11f1ff};
static constexpr uint32_t kExpectedRGBAColor[16] = {
0x14373737, 0x14373737, 0xb6000000, 0xb6000000, 0x88a5a6a5, 0x88373737,
0x70000000, 0x70000000, 0x88a5a6a5, 0x2b6e6f6e, 0x2b000000, 0x2b000000,
0x88a5a6a5, 0x426e6f6e, 0x42000000, 0x42000000,
};
// Result BC4 data as {0xf6f1836f, 0xc41c5e7c}
static constexpr uint32_t kEacR11Signed[2] = {0xb068efff, 0x00b989e7};
static constexpr uint32_t kExpectedR11SignedColor[16] = {
0xff000003, 0xff000046, 0xff0000ac, 0xff0000ac, 0xff000025, 0xff000003,
0xff000025, 0xff0000ac, 0xff000046, 0xff0000ac, 0xff000003, 0xff000046,
0xff000003, 0xff0000ef, 0xff000003, 0xff000046,
};
// Result BC1 data as {0xa65a7b55, 0xcc3c4f43}
static constexpr uint32_t kRgb8a1[2] = {0x95938c6a, 0x0030e384};
static constexpr uint32_t kExpectedRgb8a1[16] = {
0x00000000, 0xffab697b, 0xffab697b, 0xffd6cba5, 0x00000000, 0x00000000,
0xffab697b, 0xffd6cba5, 0xffab697b, 0x00000000, 0x00000000, 0xffab697b,
0xffab697b, 0x00000000, 0xffab697b, 0x00000000,
};
static constexpr char kVS[] =
"#version 300 es\n"
"in vec4 position;\n"
"void main()\n"
"{\n"
" gl_Position = vec4(position.xy, 0.0, 1.0);\n"
"}\n";
ETCToBCTextureTest() : mEtcTexture(0u)
{
setWindowWidth(256);
setWindowHeight(256);
setConfigRedBits(8);
setConfigGreenBits(8);
setConfigBlueBits(8);
setConfigAlphaBits(8);
}
void testSetUp() override
{
glGenTextures(1, &mEtcTexture);
ASSERT_GL_NO_ERROR();
}
void testTearDown() override { glDeleteTextures(1, &mEtcTexture); }
GLuint mEtcTexture;
};
// Tests GPU compute transcode ETC2_RGB8 to BC1
TEST_P(ETCToBCTextureTest, ETC2Rgb8UnormToBC1_2D)
{
ANGLE_SKIP_TEST_IF(
!IsVulkan() || !IsNVIDIA() ||
!getEGLWindow()->isFeatureEnabled(Feature::SupportsComputeTranscodeEtcToBc) ||
!IsGLExtensionEnabled("GL_EXT_texture_compression_dxt1"));
glViewport(0, 0, kWidth, kHeight);
glBindTexture(GL_TEXTURE_2D, mEtcTexture);
glTexStorage2D(GL_TEXTURE_2D, 1, GL_COMPRESSED_RGB8_ETC2, kTexSize, kTexSize);
glCompressedTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kTexSize, kTexSize, GL_COMPRESSED_RGB8_ETC2,
sizeof(kEtcRGBData), kEtcRGBData);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
draw2DTexturedQuad(0.5f, 1.0f, false);
EXPECT_PIXEL_COLOR_NEAR(0, 0, GLColor(kExpectedRGBColor[0]), kAbsError);
EXPECT_PIXEL_COLOR_NEAR(1, 1, GLColor(kExpectedRGBColor[5]), kAbsError);
EXPECT_PIXEL_COLOR_NEAR(2, 2, GLColor(kExpectedRGBColor[10]), kAbsError);
EXPECT_PIXEL_COLOR_NEAR(3, 3, GLColor(kExpectedRGBColor[15]), kAbsError);
}
// Tests GPU compute transcode ETC2_RGB8 to BC1 with cube texture type
TEST_P(ETCToBCTextureTest, ETC2Rgb8UnormToBC1_Cube)
{
ANGLE_SKIP_TEST_IF(
!IsVulkan() || !IsNVIDIA() ||
!getEGLWindow()->isFeatureEnabled(Feature::SupportsComputeTranscodeEtcToBc) ||
!IsGLExtensionEnabled("GL_EXT_texture_compression_dxt1"));
glViewport(0, 0, kWidth, kHeight);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_CUBE_MAP, mEtcTexture);
glTexStorage2D(GL_TEXTURE_CUBE_MAP, 1, GL_COMPRESSED_RGB8_ETC2, kTexSize, kTexSize);
glCompressedTexSubImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, 0, 0, kTexSize, kTexSize,
GL_COMPRESSED_RGB8_ETC2, sizeof(kEtcAllZero), kEtcAllZero);
glCompressedTexSubImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, 0, 0, kTexSize, kTexSize,
GL_COMPRESSED_RGB8_ETC2, sizeof(kEtcAllZero), kEtcAllZero);
glCompressedTexSubImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, 0, 0, kTexSize, kTexSize,
GL_COMPRESSED_RGB8_ETC2, sizeof(kEtcRGBData), kEtcRGBData);
glCompressedTexSubImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, 0, 0, kTexSize, kTexSize,
GL_COMPRESSED_RGB8_ETC2, sizeof(kEtcAllZero), kEtcAllZero);
glCompressedTexSubImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, 0, 0, kTexSize, kTexSize,
GL_COMPRESSED_RGB8_ETC2, sizeof(kEtcAllZero), kEtcAllZero);
glCompressedTexSubImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, 0, 0, kTexSize, kTexSize,
GL_COMPRESSED_RGB8_ETC2, sizeof(kEtcAllZero), kEtcAllZero);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
constexpr char kTextureCubeFS[] =
"#version 300 es\n"
"precision highp float;\n"
"uniform highp samplerCube texCube;\n"
"uniform vec3 faceCoord;\n"
"out vec4 fragColor;\n"
"void main()\n"
"{\n"
" fragColor = texture(texCube, faceCoord);\n"
"}\n";
GLuint program = CompileProgram(kVS, kTextureCubeFS);
glUseProgram(program);
GLint texCubePos = glGetUniformLocation(program, "texCube");
glUniform1i(texCubePos, 0);
GLint faceCoordpos = glGetUniformLocation(program, "faceCoord");
// sample at (2, 2) on y plane.
glUniform3f(faceCoordpos, 0.25f, 1.0f, 0.25f);
drawQuad(program, "position", 0.5f);
EXPECT_PIXEL_COLOR_NEAR(0, 0, GLColor(kExpectedRGBColor[10]), kAbsError);
}
// Tests GPU compute transcode ETC2_RGB8 to BC1 with 2DArray texture type
TEST_P(ETCToBCTextureTest, ETC2Rgb8UnormToBC1_2DArray)
{
ANGLE_SKIP_TEST_IF(
!IsVulkan() || !IsNVIDIA() ||
!getEGLWindow()->isFeatureEnabled(Feature::SupportsComputeTranscodeEtcToBc) ||
!IsGLExtensionEnabled("GL_EXT_texture_compression_dxt1"));
glViewport(0, 0, kWidth, kHeight);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D_ARRAY, mEtcTexture);
static constexpr int kArraySize = 6;
uint32_t data[2 * kArraySize] = {
kEtcAllZero[0], kEtcAllZero[1], // array 0
kEtcRGBData[0], kEtcRGBData[1], // array 1
kEtcRGBData[0], kEtcRGBData[1], // array 2
kEtcAllZero[0], kEtcAllZero[1], // array 3
kEtcAllZero[0], kEtcAllZero[1], // array 4
kEtcAllZero[0], kEtcAllZero[1], // array 5
};
glTexStorage3D(GL_TEXTURE_2D_ARRAY, 1, GL_COMPRESSED_RGB8_ETC2, kTexSize, kTexSize, kArraySize);
glCompressedTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, kTexSize, kTexSize, kArraySize,
GL_COMPRESSED_RGB8_ETC2, sizeof(data), data);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
constexpr char kTexture2DArrayFS[] =
"#version 300 es\n"
"precision highp float;\n"
"uniform highp sampler2DArray tex2DArray;\n"
"uniform vec3 coord;\n"
"out vec4 fragColor;\n"
"void main()\n"
"{\n"
" fragColor = texture(tex2DArray, coord);\n"
"}\n";
GLuint program = CompileProgram(kVS, kTexture2DArrayFS);
glUseProgram(program);
GLint texCubePos = glGetUniformLocation(program, "tex2DArray");
glUniform1i(texCubePos, 0);
GLint faceCoordpos = glGetUniformLocation(program, "coord");
// sample at (2, 2) on y plane.
glUniform3f(faceCoordpos, 0.625f, 0.625f, 2.0f);
drawQuad(program, "position", 0.5f);
EXPECT_PIXEL_COLOR_NEAR(0, 0, GLColor(kExpectedRGBColor[10]), kAbsError);
}
// Tests GPU compute transcode ETC2_RGB8 to BC1 with partial updates
TEST_P(ETCToBCTextureTest, ETC2Rgb8UnormToBC1_partial)
{
ANGLE_SKIP_TEST_IF(!IsVulkan() || !IsNVIDIA() ||
getEGLWindow()->isFeatureEnabled(Feature::SupportsComputeTranscodeEtcToBc) ||
!IsGLExtensionEnabled("GL_EXT_texture_compression_dxt1"));
glViewport(0, 0, kWidth, kHeight);
glBindTexture(GL_TEXTURE_2D, mEtcTexture);
glTexStorage2D(GL_TEXTURE_2D, 1, GL_COMPRESSED_RGB8_ETC2, kTexSize * 3, kTexSize * 3);
glCompressedTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kTexSize, kTexSize, GL_COMPRESSED_RGB8_ETC2,
sizeof(kEtcAllZero), kEtcAllZero);
glCompressedTexSubImage2D(GL_TEXTURE_2D, 0, 2 * kTexSize, 2 * kTexSize, kTexSize, kTexSize,
GL_COMPRESSED_RGB8_ETC2, sizeof(kEtcRGBData), kEtcRGBData);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
constexpr char kFS[] =
"#version 300 es\n"
"precision highp float;\n"
"uniform highp sampler2D tex2D;\n"
"uniform vec2 coord;\n"
"out vec4 fragColor;\n"
"void main()\n"
"{\n"
" fragColor = texture(tex2D, coord);\n"
"}\n";
GLuint program = CompileProgram(kVS, kFS);
glUseProgram(program);
GLint texCubePos = glGetUniformLocation(program, "tex2D");
glUniform1i(texCubePos, 0);
GLint faceCoordpos = glGetUniformLocation(program, "coord");
// sample at (2, 2) on y plane.
glUniform2f(faceCoordpos, 21.0f / 24.0f, 21.0f / 24.0f);
drawQuad(program, "position", 0.5f);
EXPECT_PIXEL_COLOR_NEAR(0, 0, GLColor(kExpectedRGBColor[10]), kAbsError);
}
// Tests GPU compute transcode ETC2_RGBA8 to BC3
TEST_P(ETCToBCTextureTest, ETC2Rgba8UnormToBC3)
{
ANGLE_SKIP_TEST_IF(
!IsVulkan() || !IsNVIDIA() ||
!getEGLWindow()->isFeatureEnabled(Feature::SupportsComputeTranscodeEtcToBc) ||
!IsGLExtensionEnabled("GL_EXT_texture_compression_s3tc"));
glViewport(0, 0, kWidth, kHeight);
glBindTexture(GL_TEXTURE_2D, mEtcTexture);
glTexStorage2D(GL_TEXTURE_2D, 1, GL_COMPRESSED_RGBA8_ETC2_EAC, kTexSize, kTexSize);
glCompressedTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kTexSize, kTexSize,
GL_COMPRESSED_RGBA8_ETC2_EAC, sizeof(kEtcRGBAData), kEtcRGBAData);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
draw2DTexturedQuad(0.5f, 1.0f, false);
for (int i = 0; i < 4; ++i)
{
for (int j = 0; j < 4; ++j)
{
EXPECT_PIXEL_COLOR_NEAR(j, i, GLColor(kExpectedRGBAColor[i * 4 + j]), kAbsError);
}
}
}
// Tests GPU compute transcode ETC2_RGBA8 to BC3 texture with lod.
TEST_P(ETCToBCTextureTest, ETC2Rgba8UnormToBC3_Lod)
{
ANGLE_SKIP_TEST_IF(
!IsVulkan() || !IsNVIDIA() ||
!getEGLWindow()->isFeatureEnabled(Feature::SupportsComputeTranscodeEtcToBc) ||
!IsGLExtensionEnabled("GL_EXT_texture_compression_s3tc"));
glViewport(0, 0, kWidth, kHeight);
glBindTexture(GL_TEXTURE_2D, mEtcTexture);
glTexStorage2D(GL_TEXTURE_2D, 3, GL_COMPRESSED_RGBA8_ETC2_EAC, kTexSize, kTexSize);
static constexpr uint32_t kAllZero[] = {0, 0, 0, 0};
glCompressedTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kTexSize, kTexSize,
GL_COMPRESSED_RGBA8_ETC2_EAC, sizeof(kAllZero), kAllZero);
glCompressedTexSubImage2D(GL_TEXTURE_2D, 1, 0, 0, kTexSize / 2, kTexSize / 2,
GL_COMPRESSED_RGBA8_ETC2_EAC, sizeof(kAllZero), kAllZero);
glCompressedTexSubImage2D(GL_TEXTURE_2D, 2, 0, 0, kTexSize / 4, kTexSize / 4,
GL_COMPRESSED_RGBA8_ETC2_EAC, sizeof(kEtcRGBAData), kEtcRGBAData);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
constexpr char kVS[] =
"#version 300 es\n"
"in vec2 position;\n"
"out vec2 texCoord;\n"
"void main()\n"
"{\n"
" gl_Position = vec4(position, 0, 1);\n"
" texCoord = position * 0.5 + vec2(0.5);\n"
"}\n";
constexpr char kFS[] =
"#version 300 es\n"
"precision highp float;\n"
"uniform highp sampler2D tex2D;\n"
"in vec2 texCoord;\n"
"out vec4 fragColor;\n"
"void main()\n"
"{\n"
" fragColor = textureLod(tex2D, texCoord, 2.0);\n"
"}\n";
GLuint program = CompileProgram(kVS, kFS);
glUseProgram(program);
GLint texPos = glGetUniformLocation(program, "tex2D");
glUniform1i(texPos, 0);
drawQuad(program, "position", 0.5f);
EXPECT_PIXEL_COLOR_NEAR(0, 0, GLColor(kExpectedRGBAColor[0]), kAbsError);
}
// Tests GPU compute transcode ETC2_SRGB8_ALPHA8 to BC3
TEST_P(ETCToBCTextureTest, ETC2SrgbAlpha8UnormToBC3)
{
ANGLE_SKIP_TEST_IF(
!IsVulkan() || !IsNVIDIA() ||
!getEGLWindow()->isFeatureEnabled(Feature::SupportsComputeTranscodeEtcToBc) ||
!IsGLExtensionEnabled("GL_EXT_texture_compression_s3tc_srgb"));
glViewport(0, 0, pixel_width, pixel_height);
glBindTexture(GL_TEXTURE_2D, mEtcTexture);
EXPECT_GL_NO_ERROR();
glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC, pixel_width,
pixel_height, 0, sizeof(etc2bc_srgb8_alpha8), etc2bc_srgb8_alpha8);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
draw2DTexturedQuad(0.5f, 1.0f, false);
EXPECT_PIXEL_ALPHA_NEAR(96, 160, 255, kAbsError);
EXPECT_PIXEL_ALPHA_NEAR(88, 148, 0, kAbsError);
}
// Tests GPU compute transcode R11 Signed to BC4
TEST_P(ETCToBCTextureTest, ETC2R11SignedToBC4)
{
ANGLE_SKIP_TEST_IF(
!IsVulkan() || !IsNVIDIA() ||
!getEGLWindow()->isFeatureEnabled(Feature::SupportsComputeTranscodeEtcToBc) ||
!IsGLExtensionEnabled("GL_EXT_texture_compression_rgtc"));
glViewport(0, 0, kWidth, kHeight);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, mEtcTexture);
glTexStorage2D(GL_TEXTURE_2D, 1, GL_COMPRESSED_SIGNED_R11_EAC, kTexSize, kTexSize);
glCompressedTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kTexSize, kTexSize,
GL_COMPRESSED_SIGNED_R11_EAC, sizeof(kEacR11Signed), kEacR11Signed);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
constexpr char kVS[] =
"attribute vec2 position;\n"
"varying mediump vec2 texCoord;\n"
"void main()\n"
"{\n"
" gl_Position = vec4(position, 0, 1);\n"
" texCoord = position * 0.5 + vec2(0.5);\n"
"}\n";
constexpr char kFS[] =
"varying mediump vec2 texCoord;\n"
"uniform sampler2D tex;\n"
"void main()\n"
"{\n"
" gl_FragColor = texture2D(tex, texCoord)/2.0 + vec4(0.5, 0.0, 0.0, 0.5);\n"
"}\n";
GLuint program = CompileProgram(kVS, kFS);
glUseProgram(program);
GLint pos = glGetUniformLocation(program, "tex");
glUniform1i(pos, 0);
drawQuad(program, "position", 0.5f);
for (int i = 0; i < 4; ++i)
{
for (int j = 0; j < 4; ++j)
{
EXPECT_PIXEL_COLOR_NEAR(j, i, GLColor(kExpectedR11SignedColor[i * 4 + j]), kAbsError);
}
}
}
// Tests GPU compute transcode RG11 to BC5
TEST_P(ETCToBCTextureTest, ETC2RG11ToBC5)
{
ANGLE_SKIP_TEST_IF(
!IsVulkan() || !IsNVIDIA() ||
!getEGLWindow()->isFeatureEnabled(Feature::SupportsComputeTranscodeEtcToBc) ||
!IsGLExtensionEnabled("GL_EXT_texture_compression_rgtc"));
glViewport(0, 0, kWidth, kHeight);
glBindTexture(GL_TEXTURE_2D, mEtcTexture);
uint32_t data[4] = {
kEtcRGBAData[0],
kEtcRGBAData[1],
kEtcRGBAData[0],
kEtcRGBAData[1],
};
glTexStorage2D(GL_TEXTURE_2D, 1, GL_COMPRESSED_RG11_EAC, kTexSize, kTexSize);
glCompressedTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kTexSize, kTexSize, GL_COMPRESSED_RG11_EAC,
sizeof(data), data);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
draw2DTexturedQuad(0.5f, 1.0f, false);
for (int i = 0; i < 4; ++i)
{
for (int j = 0; j < 4; ++j)
{
uint32_t color = (kExpectedRGBAColor[i * 4 + j] & 0xff000000) >> 24;
color |= color << 8;
color |= 0xff000000;
EXPECT_PIXEL_COLOR_NEAR(j, i, GLColor(color), kAbsError);
}
}
}
// Tests GPU compute transcode RGB8A1 to BC1_RGBA
TEST_P(ETCToBCTextureTest, ETC2Rgb8a1UnormToBC1)
{
ANGLE_SKIP_TEST_IF(
!IsVulkan() || !IsNVIDIA() ||
!getEGLWindow()->isFeatureEnabled(Feature::SupportsComputeTranscodeEtcToBc) ||
!IsGLExtensionEnabled("GL_EXT_texture_compression_s3tc"));
glViewport(0, 0, kWidth, kHeight);
glBindTexture(GL_TEXTURE_2D, mEtcTexture);
glTexStorage2D(GL_TEXTURE_2D, 1, GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2, kTexSize,
kTexSize);
glCompressedTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kTexSize, kTexSize,
GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2, sizeof(kRgb8a1),
kRgb8a1);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
draw2DTexturedQuad(0.5f, 1.0f, false);
for (int i = 0; i < 4; ++i)
{
for (int j = 0; j < 4; ++j)
{
EXPECT_PIXEL_COLOR_NEAR(j, i, GLColor(kExpectedRgb8a1[i * 4 + j]), kAbsError);
}
}
}
ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(ETCTextureTest);
ANGLE_INSTANTIATE_TEST_ES3_AND(ETCToBCTextureTest,
ES3_VULKAN().enable(Feature::SupportsComputeTranscodeEtcToBc));
} // anonymous namespace