mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
254 lines
8.3 KiB
C++
254 lines
8.3 KiB
C++
// Copyright 2013 The Chromium 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 <GLES2/gl2.h>
|
|
#include <GLES2/gl2ext.h>
|
|
#include <GLES2/gl2extchromium.h>
|
|
|
|
#include "base/basictypes.h"
|
|
#include "gpu/command_buffer/tests/gl_manager.h"
|
|
#include "gpu/command_buffer/tests/gl_test_utils.h"
|
|
#include "testing/gtest/include/gtest/gtest.h"
|
|
|
|
#define SHADER(src) #src
|
|
|
|
namespace gpu {
|
|
|
|
static const uint16 kRedMask = 0xF800;
|
|
static const uint16 kGreenMask = 0x07E0;
|
|
static const uint16 kBlueMask = 0x001F;
|
|
|
|
// Color palette in 565 format.
|
|
static const uint16 kPalette[] = {
|
|
kGreenMask | kBlueMask, // Cyan.
|
|
kBlueMask | kRedMask, // Magenta.
|
|
kRedMask | kGreenMask, // Yellow.
|
|
0x0000, // Black.
|
|
kRedMask, // Red.
|
|
kGreenMask, // Green.
|
|
kBlueMask, // Blue.
|
|
0xFFFF, // White.
|
|
};
|
|
static const unsigned kBlockSize = 4;
|
|
static const unsigned kPaletteSize = sizeof(kPalette) / sizeof(kPalette[0]);
|
|
static const unsigned kTextureWidth = kBlockSize * kPaletteSize;
|
|
static const unsigned kTextureHeight = kBlockSize;
|
|
|
|
static const char* extension(GLenum format) {
|
|
switch(format) {
|
|
case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
|
|
case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
|
|
return "GL_EXT_texture_compression_dxt1";
|
|
case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
|
|
return "GL_CHROMIUM_texture_compression_dxt3";
|
|
case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
|
|
return "GL_CHROMIUM_texture_compression_dxt5";
|
|
default:
|
|
NOTREACHED();
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
// Index that chooses the given colors (color_0 and color_1),
|
|
// not the interpolated colors (color_2 and color_3).
|
|
static const uint16 kColor0 = 0x0000;
|
|
static const uint16 kColor1 = 0x5555;
|
|
|
|
static GLuint LoadCompressedTexture(const void* data,
|
|
GLsizeiptr size,
|
|
GLenum format,
|
|
GLsizei width,
|
|
GLsizei height) {
|
|
GLuint texture;
|
|
glGenTextures(1, &texture);
|
|
glBindTexture(GL_TEXTURE_2D, texture);
|
|
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, format, width, height, 0, size, data);
|
|
return texture;
|
|
}
|
|
|
|
GLuint LoadTextureDXT1(bool alpha) {
|
|
const unsigned kStride = 4;
|
|
uint16 data[kStride * kPaletteSize];
|
|
for (unsigned i = 0; i < kPaletteSize; ++i) {
|
|
// Each iteration defines a 4x4 block of texture.
|
|
unsigned j = kStride * i;
|
|
data[j++] = kPalette[i]; // color_0.
|
|
data[j++] = kPalette[i]; // color_1.
|
|
data[j++] = kColor0; // color index.
|
|
data[j++] = kColor1; // color index.
|
|
}
|
|
GLenum format = alpha ?
|
|
GL_COMPRESSED_RGBA_S3TC_DXT1_EXT : GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
|
|
return LoadCompressedTexture(
|
|
data, sizeof(data), format, kTextureWidth, kTextureHeight);
|
|
}
|
|
|
|
GLuint LoadTextureDXT3() {
|
|
const unsigned kStride = 8;
|
|
const uint16 kOpaque = 0xFFFF;
|
|
uint16 data[kStride * kPaletteSize];
|
|
for (unsigned i = 0; i < kPaletteSize; ++i) {
|
|
// Each iteration defines a 4x4 block of texture.
|
|
unsigned j = kStride * i;
|
|
data[j++] = kOpaque; // alpha row 0.
|
|
data[j++] = kOpaque; // alpha row 1.
|
|
data[j++] = kOpaque; // alpha row 2.
|
|
data[j++] = kOpaque; // alpha row 3.
|
|
data[j++] = kPalette[i]; // color_0.
|
|
data[j++] = kPalette[i]; // color_1.
|
|
data[j++] = kColor0; // color index.
|
|
data[j++] = kColor1; // color index.
|
|
}
|
|
return LoadCompressedTexture(data,
|
|
sizeof(data),
|
|
GL_COMPRESSED_RGBA_S3TC_DXT3_EXT,
|
|
kTextureWidth,
|
|
kTextureHeight);
|
|
}
|
|
|
|
GLuint LoadTextureDXT5() {
|
|
const unsigned kStride = 8;
|
|
const uint16 kClear = 0x0000;
|
|
const uint16 kAlpha7 = 0xFFFF; // Opaque alpha index.
|
|
uint16 data[kStride * kPaletteSize];
|
|
for (unsigned i = 0; i < kPaletteSize; ++i) {
|
|
// Each iteration defines a 4x4 block of texture.
|
|
unsigned j = kStride * i;
|
|
data[j++] = kClear; // alpha_0 | alpha_1.
|
|
data[j++] = kAlpha7; // alpha index.
|
|
data[j++] = kAlpha7; // alpha index.
|
|
data[j++] = kAlpha7; // alpha index.
|
|
data[j++] = kPalette[i]; // color_0.
|
|
data[j++] = kPalette[i]; // color_1.
|
|
data[j++] = kColor0; // color index.
|
|
data[j++] = kColor1; // color index.
|
|
}
|
|
return LoadCompressedTexture(data,
|
|
sizeof(data),
|
|
GL_COMPRESSED_RGBA_S3TC_DXT5_EXT,
|
|
kTextureWidth,
|
|
kTextureHeight);
|
|
}
|
|
|
|
static void ToRGB888(uint16 rgb565, uint8 rgb888[]) {
|
|
uint8 r5 = (rgb565 & kRedMask) >> 11;
|
|
uint8 g6 = (rgb565 & kGreenMask) >> 5;
|
|
uint8 b5 = (rgb565 & kBlueMask);
|
|
// Replicate upper bits to lower empty bits.
|
|
rgb888[0] = (r5 << 3) | (r5 >> 2);
|
|
rgb888[1] = (g6 << 2) | (g6 >> 4);
|
|
rgb888[2] = (b5 << 3) | (b5 >> 2);
|
|
}
|
|
|
|
class CompressedTextureTest : public ::testing::TestWithParam<GLenum> {
|
|
protected:
|
|
void SetUp() override {
|
|
GLManager::Options options;
|
|
options.size = gfx::Size(kTextureWidth, kTextureHeight);
|
|
gl_.Initialize(options);
|
|
}
|
|
|
|
void TearDown() override { gl_.Destroy(); }
|
|
|
|
GLuint LoadProgram() {
|
|
const char* v_shader_src = SHADER(
|
|
attribute vec2 a_position;
|
|
varying vec2 v_texcoord;
|
|
void main() {
|
|
gl_Position = vec4(a_position, 0.0, 1.0);
|
|
v_texcoord = (a_position + 1.0) * 0.5;
|
|
}
|
|
);
|
|
const char* f_shader_src = SHADER(
|
|
precision mediump float;
|
|
uniform sampler2D u_texture;
|
|
varying vec2 v_texcoord;
|
|
void main() {
|
|
gl_FragColor = texture2D(u_texture, v_texcoord);
|
|
}
|
|
);
|
|
return GLTestHelper::LoadProgram(v_shader_src, f_shader_src);
|
|
}
|
|
|
|
GLuint LoadTexture(GLenum format) {
|
|
switch (format) {
|
|
case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: return LoadTextureDXT1(false);
|
|
case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: return LoadTextureDXT1(true);
|
|
case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: return LoadTextureDXT3();
|
|
case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: return LoadTextureDXT5();
|
|
default: NOTREACHED();
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
private:
|
|
GLManager gl_;
|
|
};
|
|
|
|
// The test draws a texture in the given format and verifies that the drawn
|
|
// pixels are of the same color as the texture.
|
|
// The texture consists of 4x4 blocks of texels (same as DXT), one for each
|
|
// color defined in kPalette.
|
|
TEST_P(CompressedTextureTest, Draw) {
|
|
GLenum format = GetParam();
|
|
|
|
// This test is only valid if compressed texture extension is supported.
|
|
const char* ext = extension(format);
|
|
if (!GLTestHelper::HasExtension(ext))
|
|
return;
|
|
|
|
// Load shader program.
|
|
GLuint program = LoadProgram();
|
|
ASSERT_NE(program, 0u);
|
|
GLint position_loc = glGetAttribLocation(program, "a_position");
|
|
GLint texture_loc = glGetUniformLocation(program, "u_texture");
|
|
ASSERT_NE(position_loc, -1);
|
|
ASSERT_NE(texture_loc, -1);
|
|
glUseProgram(program);
|
|
|
|
// Load geometry.
|
|
GLuint vbo = GLTestHelper::SetupUnitQuad(position_loc);
|
|
ASSERT_NE(vbo, 0u);
|
|
|
|
// Load texture.
|
|
GLuint texture = LoadTexture(format);
|
|
ASSERT_NE(texture, 0u);
|
|
glActiveTexture(GL_TEXTURE0);
|
|
glBindTexture(GL_TEXTURE_2D, texture);
|
|
glUniform1i(texture_loc, 0);
|
|
|
|
// Draw.
|
|
glDrawArrays(GL_TRIANGLES, 0, 6);
|
|
glFlush();
|
|
|
|
// Verify results.
|
|
int origin[] = {0, 0};
|
|
uint8 expected_rgba[] = {0, 0, 0, 255};
|
|
for (unsigned i = 0; i < kPaletteSize; ++i) {
|
|
origin[0] = kBlockSize * i;
|
|
ToRGB888(kPalette[i], expected_rgba);
|
|
EXPECT_TRUE(GLTestHelper::CheckPixels(origin[0], origin[1],
|
|
kBlockSize, kBlockSize,
|
|
0, expected_rgba));
|
|
}
|
|
GLTestHelper::CheckGLError("CompressedTextureTest.Draw", __LINE__);
|
|
}
|
|
|
|
static const GLenum kFormats[] = {
|
|
GL_COMPRESSED_RGB_S3TC_DXT1_EXT,
|
|
GL_COMPRESSED_RGBA_S3TC_DXT1_EXT,
|
|
GL_COMPRESSED_RGBA_S3TC_DXT3_EXT,
|
|
GL_COMPRESSED_RGBA_S3TC_DXT5_EXT
|
|
};
|
|
INSTANTIATE_TEST_CASE_P(Format,
|
|
CompressedTextureTest,
|
|
::testing::ValuesIn(kFormats));
|
|
|
|
} // namespace gpu
|