blob: f61f18872e8d3b6bf649bc5b8de954b4f71debfb [file] [log] [blame]
// Copyright 2016 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.
#ifndef GL_GLEXT_PROTOTYPES
#define GL_GLEXT_PROTOTYPES
#endif
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#include <GLES2/gl2extchromium.h>
#include "base/strings/stringize_macros.h"
#include "base/strings/stringprintf.h"
#include "build/build_config.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"
namespace gpu {
#if defined(OS_MACOSX)
namespace {
// clang-format off
static const char* kSimpleVertexShader = STRINGIZE(
attribute vec2 a_position;
varying vec2 v_texCoord;
void main() {
gl_Position = vec4(a_position.x, a_position.y, 0.0, 1.0);
v_texCoord = (a_position + vec2(1.0, 1.0)) * 0.5;
}
);
// clang-format on
// Generate fragment shader source for sampling out of a texture of |size|
// bound to |target|.
std::string GetFragmentShaderSource(unsigned target, const gfx::Size& size) {
// clang-format off
const char kFragmentShader[] = STRINGIZE(
uniform SamplerType u_texture;
varying vec2 v_texCoord;
void main() {
gl_FragColor = TextureLookup(u_texture, v_texCoord * TextureScale);
}
);
const char kShaderFloatPrecision[] = STRINGIZE(
precision mediump float;
);
// clang-format on
switch (target) {
case GL_TEXTURE_2D:
return base::StringPrintf(
"%s\n"
"#define SamplerType sampler2D\n"
"#define TextureLookup texture2D\n"
"#define TextureScale vec2(1.0, 1.0)\n"
"%s",
kShaderFloatPrecision, kFragmentShader);
case GL_TEXTURE_RECTANGLE_ARB:
return base::StringPrintf(
"%s\n"
"#extension GL_ARB_texture_rectangle : require\n"
"#define SamplerType sampler2DRect\n"
"#define TextureLookup texture2DRect\n"
"#define TextureScale vec2(%f, %f)\n"
"%s",
kShaderFloatPrecision, static_cast<double>(size.width()),
static_cast<double>(size.height()), kFragmentShader);
default:
NOTREACHED();
return std::string();
}
}
} // namespace
// A collection of tests that exercise the glCopyTexImage2D workaround. The
// parameter expresses different formats of the destination texture.
class GLCopyTexImage2DWorkaroundTest : public testing::TestWithParam<GLenum> {
public:
GLCopyTexImage2DWorkaroundTest() {}
protected:
void SetUp() override {
GpuDriverBugWorkarounds workarounds;
workarounds.use_intermediary_for_copy_texture_image = true;
gl_.InitializeWithWorkarounds(GLManager::Options(), workarounds);
gl_.set_use_iosurface_memory_buffers(true);
DCHECK(gl_.workarounds().use_intermediary_for_copy_texture_image);
}
void TearDown() override {
GLTestHelper::CheckGLError("no errors", __LINE__);
gl_.Destroy();
}
GLManager gl_;
};
INSTANTIATE_TEST_CASE_P(GLCopyTexImage2DWorkaroundTestWithParam,
GLCopyTexImage2DWorkaroundTest,
::testing::Values(GL_RGBA));
TEST_P(GLCopyTexImage2DWorkaroundTest, UseIntermediaryTexture) {
int width = 1;
int height = 1;
GLuint source_texture = 0;
GLenum source_target = GL_TEXTURE_RECTANGLE_ARB;
glGenTextures(1, &source_texture);
glBindTexture(source_target, source_texture);
glTexParameteri(source_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(source_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
std::unique_ptr<gfx::GpuMemoryBuffer> buffer(gl_.CreateGpuMemoryBuffer(
gfx::Size(width, height), gfx::BufferFormat::RGBA_8888));
GLuint image_id =
glCreateImageCHROMIUM(buffer->AsClientBuffer(), width, height, GL_RGBA);
ASSERT_NE(0u, image_id);
glBindTexImage2DCHROMIUM(source_target, image_id);
GLuint framebuffer = 0;
glGenFramebuffers(1, &framebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
glFramebufferTexture2D(
GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, source_target, source_texture, 0);
EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE),
glCheckFramebufferStatus(GL_FRAMEBUFFER));
GLenum dest_formats[] = {GL_RGBA, GL_RGB, GL_ALPHA, GL_LUMINANCE};
const uint8_t expectations[4][4] = {
{33, 44, 55, 66}, {33, 44, 55, 255}, {0, 0, 0, 66}, {33, 33, 33, 255}};
for (size_t i = 0; i < sizeof(dest_formats) / sizeof(GLenum); ++i) {
glClearColor(33.0 / 255.0, 44.0 / 255.0, 55.0 / 255.0, 66.0 / 255.0);
glClear(GL_COLOR_BUFFER_BIT);
EXPECT_EQ(glGetError(), GLenum(GL_NO_ERROR));
GLuint dest_texture = 0;
GLenum dest_target = GL_TEXTURE_2D;
GLenum dest_format = dest_formats[i];
glGenTextures(1, &dest_texture);
glBindTexture(dest_target, dest_texture);
glTexParameteri(dest_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(dest_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glCopyTexImage2D(dest_target, 0, dest_format, 0, 0, width, height, 0);
EXPECT_EQ(glGetError(), GLenum(GL_NO_ERROR));
// Check that bound textures haven't changed.
GLint boundTexture = -1;
glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &boundTexture);
EXPECT_EQ(glGetError(), GLenum(GL_NO_ERROR));
EXPECT_EQ(static_cast<GLint>(source_texture), boundTexture);
boundTexture = -1;
glGetIntegerv(GL_TEXTURE_BINDING_2D, &boundTexture);
EXPECT_EQ(glGetError(), GLenum(GL_NO_ERROR));
EXPECT_EQ(static_cast<GLint>(dest_texture), boundTexture);
glClearColor(1.0 / 255.0, 2.0 / 255.0, 3.0 / 255.0, 4.0 / 255.0);
glClear(GL_COLOR_BUFFER_BIT);
EXPECT_EQ(glGetError(), GLenum(GL_NO_ERROR));
glViewport(0, 0, width, height);
std::string fragment_shader_source =
GetFragmentShaderSource(dest_target, gfx::Size(width, height));
GLTestHelper::DrawTextureQuad(dest_target, kSimpleVertexShader,
fragment_shader_source.c_str(), "a_position",
"u_texture", nullptr);
// Verify.
const uint8_t* expected = expectations[i];
EXPECT_TRUE(GLTestHelper::CheckPixels(0, 0, 1, 1, 1 /* tolerance */,
expected, nullptr));
}
}
#endif // defined(OS_MACOSX)
} // namespace gpu