blob: c69074be49a583867f8bc97d8dc2c1a88fb06e53 [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.
//
#include "test_utils/ANGLETest.h"
#include <vector>
using namespace angle;
namespace
{
class SwizzleTest : public ANGLETest
{
protected:
SwizzleTest()
{
setWindowWidth(128);
setWindowHeight(128);
setConfigRedBits(8);
setConfigGreenBits(8);
setConfigBlueBits(8);
setConfigAlphaBits(8);
constexpr GLenum swizzles[] = {
GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA, GL_ZERO, GL_ONE,
};
// Only use every 13th swizzle permutation, use a prime number to make sure the permuations
// are somewhat evenly distributed. Reduces the permuations from 1296 to 100.
constexpr size_t swizzleReductionFactor = 13;
size_t swizzleCount = 0;
for (GLenum r : swizzles)
{
for (GLenum g : swizzles)
{
for (GLenum b : swizzles)
{
for (GLenum a : swizzles)
{
swizzleCount++;
if (swizzleCount % swizzleReductionFactor != 0)
{
continue;
}
swizzlePermutation permutation;
permutation.swizzleRed = r;
permutation.swizzleGreen = g;
permutation.swizzleBlue = b;
permutation.swizzleAlpha = a;
mPermutations.push_back(permutation);
}
}
}
}
}
void SetUp() override
{
ANGLETest::SetUp();
const std::string vertexShaderSource = SHADER_SOURCE
(
precision highp float;
attribute vec4 position;
varying vec2 texcoord;
void main()
{
gl_Position = position;
texcoord = (position.xy * 0.5) + 0.5;
}
);
const std::string fragmentShaderSource = SHADER_SOURCE
(
precision highp float;
uniform sampler2D tex;
varying vec2 texcoord;
void main()
{
gl_FragColor = texture2D(tex, texcoord);
}
);
mProgram = CompileProgram(vertexShaderSource, fragmentShaderSource);
ASSERT_NE(0u, mProgram);
mTextureUniformLocation = glGetUniformLocation(mProgram, "tex");
ASSERT_NE(-1, mTextureUniformLocation);
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
ASSERT_GL_NO_ERROR();
}
void TearDown() override
{
glDeleteProgram(mProgram);
glDeleteTextures(1, &mTexture);
ANGLETest::TearDown();
}
template <typename T>
void init2DTexture(GLenum internalFormat, GLenum dataFormat, GLenum dataType, const T* data)
{
glGenTextures(1, &mTexture);
glBindTexture(GL_TEXTURE_2D, mTexture);
glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, 1, 1, 0, dataFormat, dataType, data);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
}
void init2DCompressedTexture(GLenum internalFormat, GLsizei width, GLsizei height, GLsizei dataSize, const GLubyte* data)
{
glGenTextures(1, &mTexture);
glBindTexture(GL_TEXTURE_2D, mTexture);
glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, width, height, 0, dataSize, data);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
}
GLubyte getExpectedValue(GLenum swizzle, GLubyte unswizzled[4])
{
switch (swizzle)
{
case GL_RED: return unswizzled[0];
case GL_GREEN: return unswizzled[1];
case GL_BLUE: return unswizzled[2];
case GL_ALPHA: return unswizzled[3];
case GL_ZERO: return 0;
case GL_ONE: return 255;
default: return 0;
}
}
void runTest2D()
{
// TODO(jmadill): Figure out why this fails on Intel.
if (IsIntel() && GetParam().getRenderer() == EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE)
{
std::cout << "Test skipped on Intel." << std::endl;
return;
}
glUseProgram(mProgram);
glBindTexture(GL_TEXTURE_2D, mTexture);
glUniform1i(mTextureUniformLocation, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_RED);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, GL_GREEN);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_BLUE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, GL_ALPHA);
glClear(GL_COLOR_BUFFER_BIT);
drawQuad(mProgram, "position", 0.5f);
GLubyte unswizzled[4];
glReadPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &unswizzled);
ASSERT_GL_NO_ERROR();
for (const auto &permutation : mPermutations)
{
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, permutation.swizzleRed);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, permutation.swizzleGreen);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, permutation.swizzleBlue);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, permutation.swizzleAlpha);
glClear(GL_COLOR_BUFFER_BIT);
drawQuad(mProgram, "position", 0.5f);
EXPECT_PIXEL_EQ(0, 0,
getExpectedValue(permutation.swizzleRed, unswizzled),
getExpectedValue(permutation.swizzleGreen, unswizzled),
getExpectedValue(permutation.swizzleBlue, unswizzled),
getExpectedValue(permutation.swizzleAlpha, unswizzled));
ASSERT_GL_NO_ERROR();
}
}
GLuint mProgram;
GLint mTextureUniformLocation;
GLuint mTexture;
struct swizzlePermutation
{
GLenum swizzleRed;
GLenum swizzleGreen;
GLenum swizzleBlue;
GLenum swizzleAlpha;
};
std::vector<swizzlePermutation> mPermutations;
};
class SwizzleIntegerTest : public SwizzleTest
{
protected:
void SetUp() override
{
ANGLETest::SetUp();
const std::string vertexShaderSource =
"#version 300 es\n"
"precision highp float;\n"
"in vec4 position;\n"
"out vec2 texcoord;\n"
"\n"
"void main()\n"
"{\n"
" gl_Position = position;\n"
" texcoord = (position.xy * 0.5) + 0.5;\n"
"}\n";
const std::string fragmentShaderSource =
"#version 300 es\n"
"precision highp float;\n"
"precision highp usampler2D;\n"
"uniform usampler2D tex;\n"
"in vec2 texcoord;\n"
"out vec4 my_FragColor;\n"
"\n"
"void main()\n"
"{\n"
" uvec4 s = texture(tex, texcoord);\n"
" if (s[0] == 1u) s[0] = 255u;\n"
" if (s[1] == 1u) s[1] = 255u;\n"
" if (s[2] == 1u) s[2] = 255u;\n"
" if (s[3] == 1u) s[3] = 255u;\n"
" my_FragColor = vec4(s) / 255.0;\n"
"}\n";
mProgram = CompileProgram(vertexShaderSource, fragmentShaderSource);
ASSERT_NE(0u, mProgram);
mTextureUniformLocation = glGetUniformLocation(mProgram, "tex");
ASSERT_NE(-1, mTextureUniformLocation);
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
ASSERT_GL_NO_ERROR();
}
};
TEST_P(SwizzleTest, RGBA8_2D)
{
GLubyte data[] = { 1, 64, 128, 200 };
init2DTexture(GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, data);
runTest2D();
}
TEST_P(SwizzleTest, RGB8_2D)
{
GLubyte data[] = { 77, 66, 55 };
init2DTexture(GL_RGB8, GL_RGB, GL_UNSIGNED_BYTE, data);
runTest2D();
}
TEST_P(SwizzleTest, RG8_2D)
{
GLubyte data[] = { 11, 99 };
init2DTexture(GL_RG8, GL_RG, GL_UNSIGNED_BYTE, data);
runTest2D();
}
TEST_P(SwizzleTest, R8_2D)
{
GLubyte data[] = { 2 };
init2DTexture(GL_R8, GL_RED, GL_UNSIGNED_BYTE, data);
runTest2D();
}
TEST_P(SwizzleTest, RGB10_A2_2D)
{
GLuint data[] = {20u | (40u << 10) | (60u << 20) | (2u << 30)};
init2DTexture(GL_RGB10_A2, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, data);
runTest2D();
}
TEST_P(SwizzleTest, RGBA32F_2D)
{
GLfloat data[] = { 0.25f, 0.5f, 0.75f, 0.8f };
init2DTexture(GL_RGBA32F, GL_RGBA, GL_FLOAT, data);
runTest2D();
}
TEST_P(SwizzleTest, RGB32F_2D)
{
GLfloat data[] = { 0.1f, 0.2f, 0.3f };
init2DTexture(GL_RGB32F, GL_RGB, GL_FLOAT, data);
runTest2D();
}
TEST_P(SwizzleTest, RG32F_2D)
{
GLfloat data[] = { 0.9f, 0.1f };
init2DTexture(GL_RG32F, GL_RG, GL_FLOAT, data);
runTest2D();
}
TEST_P(SwizzleTest, R32F_2D)
{
GLfloat data[] = { 0.5f };
init2DTexture(GL_R32F, GL_RED, GL_FLOAT, data);
runTest2D();
}
TEST_P(SwizzleTest, D32F_2D)
{
GLfloat data[] = { 0.5f };
init2DTexture(GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT, GL_FLOAT, data);
runTest2D();
}
TEST_P(SwizzleTest, D16_2D)
{
GLushort data[] = { 0xFF };
init2DTexture(GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, data);
runTest2D();
}
TEST_P(SwizzleTest, D24_2D)
{
GLuint data[] = { 0xFFFF };
init2DTexture(GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, data);
runTest2D();
}
TEST_P(SwizzleTest, L8_2D)
{
GLubyte data[] = {0x77};
init2DTexture(GL_LUMINANCE, GL_LUMINANCE, GL_UNSIGNED_BYTE, data);
runTest2D();
}
TEST_P(SwizzleTest, A8_2D)
{
GLubyte data[] = {0x55};
init2DTexture(GL_ALPHA, GL_ALPHA, GL_UNSIGNED_BYTE, data);
runTest2D();
}
TEST_P(SwizzleTest, LA8_2D)
{
GLubyte data[] = {0x77, 0x66};
init2DTexture(GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, data);
runTest2D();
}
TEST_P(SwizzleTest, L32F_2D)
{
if (!extensionEnabled("GL_OES_texture_float"))
{
std::cout << "Test skipped due to missing GL_OES_texture_float." << std::endl;
return;
}
GLfloat data[] = {0.7f};
init2DTexture(GL_LUMINANCE, GL_LUMINANCE, GL_FLOAT, data);
runTest2D();
}
TEST_P(SwizzleTest, A32F_2D)
{
if (!extensionEnabled("GL_OES_texture_float"))
{
std::cout << "Test skipped due to missing GL_OES_texture_float." << std::endl;
return;
}
GLfloat data[] = {
0.4f,
};
init2DTexture(GL_ALPHA, GL_ALPHA, GL_FLOAT, data);
runTest2D();
}
TEST_P(SwizzleTest, LA32F_2D)
{
if (!extensionEnabled("GL_OES_texture_float"))
{
std::cout << "Test skipped due to missing GL_OES_texture_float." << std::endl;
return;
}
GLfloat data[] = {
0.5f, 0.6f,
};
init2DTexture(GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_FLOAT, data);
runTest2D();
}
#include "media/pixel.inl"
TEST_P(SwizzleTest, CompressedDXT_2D)
{
if (!extensionEnabled("GL_EXT_texture_compression_dxt1"))
{
std::cout << "Test skipped due to missing GL_EXT_texture_compression_dxt1." << std::endl;
return;
}
init2DCompressedTexture(GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, pixel_0_width, pixel_0_height, pixel_0_size, pixel_0_data);
runTest2D();
}
TEST_P(SwizzleIntegerTest, RGB8UI_2D)
{
GLubyte data[] = {77, 66, 55};
init2DTexture(GL_RGB8UI, GL_RGB_INTEGER, GL_UNSIGNED_BYTE, data);
runTest2D();
}
// Test that updating the texture data still generates the correct swizzles
TEST_P(SwizzleTest, SubUpdate)
{
GLColor data(1, 64, 128, 200);
init2DTexture(GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, &data);
glUseProgram(mProgram);
glBindTexture(GL_TEXTURE_2D, mTexture);
glUniform1i(mTextureUniformLocation, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_RED);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, GL_RED);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, GL_RED);
glClear(GL_COLOR_BUFFER_BIT);
drawQuad(mProgram, "position", 0.5f);
GLColor expectedData(data.R, data.R, data.R, data.R);
EXPECT_PIXEL_COLOR_EQ(0, 0, expectedData);
GLColor updateData(32, 234, 28, 232);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &updateData);
glClear(GL_COLOR_BUFFER_BIT);
drawQuad(mProgram, "position", 0.5f);
GLColor expectedUpdateData(updateData.R, updateData.R, updateData.R, updateData.R);
EXPECT_PIXEL_COLOR_EQ(0, 0, expectedUpdateData);
}
// Use this to select which configurations (e.g. which renderer, which GLES major version) these tests should be run against.
ANGLE_INSTANTIATE_TEST(SwizzleTest, ES3_D3D11(), ES3_OPENGL(), ES3_OPENGL(3, 3), ES3_OPENGLES());
ANGLE_INSTANTIATE_TEST(SwizzleIntegerTest,
ES3_D3D11(),
ES3_OPENGL(),
ES3_OPENGL(3, 3),
ES3_OPENGLES());
} // namespace