diff options
author | erikchen <erikchen@chromium.org> | 2016-03-16 10:45:44 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2016-03-16 17:47:16 +0000 |
commit | 38cbbce8977df77712707f9f64ae2e0b15e6f201 (patch) | |
tree | 5eee57e671cbe8a39a78617b97d8366e70369d30 /gpu/command_buffer/tests | |
parent | 0d12fa25ae367e972d7eb5a00f02a643243c0243 (diff) | |
download | chromium_src-38cbbce8977df77712707f9f64ae2e0b15e6f201.zip chromium_src-38cbbce8977df77712707f9f64ae2e0b15e6f201.tar.gz chromium_src-38cbbce8977df77712707f9f64ae2e0b15e6f201.tar.bz2 |
Add a workaround for copyTexImage2D as it is sometimes broken on OSX.
copyTexImage2D fails when all of these conditions are met:
1. The internal format of the new texture is GL_ALPHA, GL_RED, or GL_RG. There
are probably a couple more. GL_RGB and GL_RGBA always work fine.
2. The GPU is from Nvidia.
3. The source texture is backed by an IOSurface.
BUG=581777
CQ_INCLUDE_TRYBOTS=tryserver.chromium.win:win_optional_gpu_tests_rel
Review URL: https://codereview.chromium.org/1736093002
Cr-Commit-Position: refs/heads/master@{#381488}
Diffstat (limited to 'gpu/command_buffer/tests')
-rw-r--r-- | gpu/command_buffer/tests/gl_copy_tex_image_2d_workaround_unittest.cc | 122 | ||||
-rw-r--r-- | gpu/command_buffer/tests/gl_manager.cc | 114 | ||||
-rw-r--r-- | gpu/command_buffer/tests/gl_manager.h | 8 | ||||
-rw-r--r-- | gpu/command_buffer/tests/gl_test_utils.cc | 84 | ||||
-rw-r--r-- | gpu/command_buffer/tests/gl_test_utils.h | 6 |
5 files changed, 320 insertions, 14 deletions
diff --git a/gpu/command_buffer/tests/gl_copy_tex_image_2d_workaround_unittest.cc b/gpu/command_buffer/tests/gl_copy_tex_image_2d_workaround_unittest.cc new file mode 100644 index 0000000..cb80ae3 --- /dev/null +++ b/gpu/command_buffer/tests/gl_copy_tex_image_2d_workaround_unittest.cc @@ -0,0 +1,122 @@ +// 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/command_line.h" +#include "base/strings/string_number_conversions.h" +#include "build/build_config.h" +#include "gpu/command_buffer/tests/gl_manager.h" +#include "gpu/command_buffer/tests/gl_test_utils.h" +#include "gpu/config/gpu_switches.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace gpu { + +#if defined(OS_MACOSX) +// 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 { + base::CommandLine command_line(0, NULL); + command_line.AppendSwitchASCII( + switches::kGpuDriverBugWorkarounds, + base::IntToString(gpu::USE_INTERMEDIARY_FOR_COPY_TEXTURE_IMAGE)); + gl_.InitializeWithCommandLine(GLManager::Options(), &command_line); + 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); + GLuint image_id = glCreateGpuMemoryBufferImageCHROMIUM( + width, height, GL_BGRA_EXT, GL_READ_WRITE_CHROMIUM); + 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); + GLTestHelper::DrawTextureQuad(dest_target, gfx::Size(width, height)); + + // Verify. + const uint8_t* expected = expectations[i]; + EXPECT_TRUE( + GLTestHelper::CheckPixels(0, 0, 1, 1, 1 /* tolerance */, expected)); + } +} + +#endif // defined(OS_MACOSX) + +} // namespace gpu diff --git a/gpu/command_buffer/tests/gl_manager.cc b/gpu/command_buffer/tests/gl_manager.cc index 6e4cc59..95778c9 100644 --- a/gpu/command_buffer/tests/gl_manager.cc +++ b/gpu/command_buffer/tests/gl_manager.cc @@ -15,6 +15,7 @@ #include "base/at_exit.h" #include "base/bind.h" #include "base/memory/ref_counted_memory.h" +#include "build/build_config.h" #include "gpu/command_buffer/client/gles2_cmd_helper.h" #include "gpu/command_buffer/client/gles2_implementation.h" #include "gpu/command_buffer/client/gles2_lib.h" @@ -42,6 +43,11 @@ #include "ui/gl/gl_share_group.h" #include "ui/gl/gl_surface.h" +#if defined(OS_MACOSX) +#include "ui/gfx/mac/io_surface.h" +#include "ui/gl/gl_image_io_surface.h" +#endif + namespace gpu { namespace { @@ -101,6 +107,65 @@ class GpuMemoryBufferImpl : public gfx::GpuMemoryBuffer { gfx::BufferFormat format_; }; +#if defined(OS_MACOSX) +class IOSurfaceGpuMemoryBuffer : public gfx::GpuMemoryBuffer { + public: + IOSurfaceGpuMemoryBuffer(const gfx::Size& size, gfx::BufferFormat format) + : mapped_(false), size_(size), format_(format) { + iosurface_ = gfx::CreateIOSurface(size, gfx::BufferFormat::BGRA_8888); + } + + ~IOSurfaceGpuMemoryBuffer() override { + CFRelease(iosurface_); + } + + static IOSurfaceGpuMemoryBuffer* FromClientBuffer(ClientBuffer buffer) { + return reinterpret_cast<IOSurfaceGpuMemoryBuffer*>(buffer); + } + + // Overridden from gfx::GpuMemoryBuffer: + bool Map() override { + DCHECK(!mapped_); + mapped_ = true; + return true; + } + void* memory(size_t plane) override { + DCHECK(mapped_); + DCHECK_LT(plane, gfx::NumberOfPlanesForBufferFormat(format_)); + return IOSurfaceGetBaseAddressOfPlane(iosurface_, plane); + } + void Unmap() override { + DCHECK(mapped_); + mapped_ = false; + } + gfx::Size GetSize() const override { return size_; } + gfx::BufferFormat GetFormat() const override { return format_; } + int stride(size_t plane) const override { + DCHECK_LT(plane, gfx::NumberOfPlanesForBufferFormat(format_)); + return IOSurfaceGetWidthOfPlane(iosurface_, plane); + } + gfx::GpuMemoryBufferId GetId() const override { + NOTREACHED(); + return gfx::GpuMemoryBufferId(0); + } + gfx::GpuMemoryBufferHandle GetHandle() const override { + NOTREACHED(); + return gfx::GpuMemoryBufferHandle(); + } + ClientBuffer AsClientBuffer() override { + return reinterpret_cast<ClientBuffer>(this); + } + + IOSurfaceRef iosurface() { return iosurface_; } + + private: + bool mapped_; + IOSurfaceRef iosurface_; + const gfx::Size size_; + gfx::BufferFormat format_; +}; +#endif // defined(OS_MACOSX) + } // namespace int GLManager::use_count_; @@ -149,10 +214,15 @@ GLManager::~GLManager() { } } -// static scoped_ptr<gfx::GpuMemoryBuffer> GLManager::CreateGpuMemoryBuffer( const gfx::Size& size, gfx::BufferFormat format) { +#if defined(OS_MACOSX) + if (use_iosurface_memory_buffers_) { + return make_scoped_ptr<gfx::GpuMemoryBuffer>( + new IOSurfaceGpuMemoryBuffer(size, format)); + } +#endif // defined(OS_MACOSX) std::vector<uint8_t> data(gfx::BufferSizeForBufferFormat(size, format), 0); scoped_refptr<base::RefCountedBytes> bytes(new base::RefCountedBytes(data)); return make_scoped_ptr<gfx::GpuMemoryBuffer>( @@ -449,23 +519,41 @@ int32_t GLManager::CreateImage(ClientBuffer buffer, size_t width, size_t height, unsigned internalformat) { - GpuMemoryBufferImpl* gpu_memory_buffer = - GpuMemoryBufferImpl::FromClientBuffer(buffer); - - scoped_refptr<gl::GLImageRefCountedMemory> image( - new gl::GLImageRefCountedMemory(gfx::Size(width, height), - internalformat)); - if (!image->Initialize(gpu_memory_buffer->bytes(), - gpu_memory_buffer->GetFormat())) { - return -1; + gfx::Size size(width, height); + scoped_refptr<gl::GLImage> gl_image; + +#if defined(OS_MACOSX) + if (use_iosurface_memory_buffers_) { + IOSurfaceGpuMemoryBuffer* gpu_memory_buffer = + IOSurfaceGpuMemoryBuffer::FromClientBuffer(buffer); + scoped_refptr<gl::GLImageIOSurface> image( + new gl::GLImageIOSurface(size, internalformat)); + if (!image->Initialize(gpu_memory_buffer->iosurface(), + gfx::GenericSharedMemoryId(1), + gfx::BufferFormat::BGRA_8888)) { + return -1; + } + gl_image = image; + } +#endif // defined(OS_MACOSX) + if (!gl_image) { + GpuMemoryBufferImpl* gpu_memory_buffer = + GpuMemoryBufferImpl::FromClientBuffer(buffer); + + scoped_refptr<gl::GLImageRefCountedMemory> image( + new gl::GLImageRefCountedMemory(size, internalformat)); + if (!image->Initialize(gpu_memory_buffer->bytes(), + gpu_memory_buffer->GetFormat())) { + return -1; + } + gl_image = image; } static int32_t next_id = 1; int32_t new_id = next_id++; - gpu::gles2::ImageManager* image_manager = decoder_->GetImageManager(); DCHECK(image_manager); - image_manager->AddImage(image.get(), new_id); + image_manager->AddImage(gl_image.get(), new_id); return new_id; } @@ -474,7 +562,7 @@ int32_t GLManager::CreateGpuMemoryBufferImage(size_t width, unsigned internalformat, unsigned usage) { DCHECK_EQ(usage, static_cast<unsigned>(GL_READ_WRITE_CHROMIUM)); - scoped_ptr<gfx::GpuMemoryBuffer> buffer = GLManager::CreateGpuMemoryBuffer( + scoped_ptr<gfx::GpuMemoryBuffer> buffer = CreateGpuMemoryBuffer( gfx::Size(width, height), gfx::BufferFormat::RGBA_8888); return CreateImage(buffer->AsClientBuffer(), width, height, internalformat); } diff --git a/gpu/command_buffer/tests/gl_manager.h b/gpu/command_buffer/tests/gl_manager.h index 4ee1389..1301fe4 100644 --- a/gpu/command_buffer/tests/gl_manager.h +++ b/gpu/command_buffer/tests/gl_manager.h @@ -78,7 +78,7 @@ class GLManager : private GpuControl { GLManager(); ~GLManager() override; - static scoped_ptr<gfx::GpuMemoryBuffer> CreateGpuMemoryBuffer( + scoped_ptr<gfx::GpuMemoryBuffer> CreateGpuMemoryBuffer( const gfx::Size& size, gfx::BufferFormat format); @@ -93,6 +93,10 @@ class GLManager : private GpuControl { void SetSurface(gfx::GLSurface* surface); + void set_use_iosurface_memory_buffers(bool use_iosurface_memory_buffers) { + use_iosurface_memory_buffers_ = use_iosurface_memory_buffers; + } + void SetCommandsPaused(bool paused) { pause_commands_ = paused; } gles2::GLES2Decoder* decoder() const { @@ -175,6 +179,8 @@ class GLManager : private GpuControl { const CommandBufferId command_buffer_id_; uint64_t next_fence_sync_release_; + bool use_iosurface_memory_buffers_ = false; + // Used on Android to virtualize GL for all contexts. static int use_count_; static scoped_refptr<gfx::GLShareGroup>* base_share_group_; diff --git a/gpu/command_buffer/tests/gl_test_utils.cc b/gpu/command_buffer/tests/gl_test_utils.cc index 4878b14..d9a30ce 100644 --- a/gpu/command_buffer/tests/gl_test_utils.cc +++ b/gpu/command_buffer/tests/gl_test_utils.cc @@ -4,19 +4,71 @@ #include "gpu/command_buffer/tests/gl_test_utils.h" +#include <GLES2/gl2extchromium.h> #include <stdint.h> #include <stdio.h> #include <string> #include "base/memory/scoped_ptr.h" +#include "base/strings/stringize_macros.h" +#include "base/strings/stringprintf.h" #include "testing/gtest/include/gtest/gtest.h" +#include "ui/gfx/geometry/size.h" // GCC requires these declarations, but MSVC requires they not be present. #ifndef COMPILER_MSVC const uint8_t GLTestHelper::kCheckClearValue; #endif +// Compiles a fragment shader for sampling out of a texture of |size| bound to +// |target| and checks for compilation errors. +GLuint LoadFragmentShader(unsigned target, const gfx::Size& size) { + // clang-format off + const char kFragmentShader[] = STRINGIZE( + uniform SamplerType a_texture; + varying vec2 v_texCoord; + void main() { + gl_FragColor = TextureLookup(a_texture, v_texCoord * TextureScale); + } + ); + const char kShaderFloatPrecision[] = STRINGIZE( + precision mediump float; + ); + // clang-format on + + switch (target) { + case GL_TEXTURE_2D: + return GLTestHelper::LoadShader( + GL_FRAGMENT_SHADER, + base::StringPrintf("%s\n" + "#define SamplerType sampler2D\n" + "#define TextureLookup texture2D\n" + "#define TextureScale vec2(1.0, 1.0)\n" + "%s", + kShaderFloatPrecision, + kFragmentShader) + .c_str()); + case GL_TEXTURE_RECTANGLE_ARB: + return GLTestHelper::LoadShader( + GL_FRAGMENT_SHADER, + 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) + .c_str()); + default: + NOTREACHED(); + return 0; + } +} + bool GLTestHelper::HasExtension(const char* extension) { std::string extensions( reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS))); @@ -259,3 +311,35 @@ bool GLTestHelper::SaveBackbufferAsBMP( fclose(fp); return true; } + +void GLTestHelper::DrawTextureQuad(GLenum target, const gfx::Size& size) { + // clang-format off + const char kVertexShader[] = 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 + + // Setup program. + GLuint vertex_shader = + GLTestHelper::LoadShader(GL_VERTEX_SHADER, kVertexShader); + GLuint fragment_shader = LoadFragmentShader(target, size); + GLuint program = GLTestHelper::SetupProgram(vertex_shader, fragment_shader); + EXPECT_NE(program, 0u); + glUseProgram(program); + + GLint sampler_location = glGetUniformLocation(program, "a_texture"); + ASSERT_NE(sampler_location, -1); + + GLuint vertex_buffer = GLTestHelper::SetupUnitQuad(sampler_location); + glDrawArrays(GL_TRIANGLES, 0, 6); + + glDeleteShader(vertex_shader); + glDeleteShader(fragment_shader); + glDeleteProgram(program); + glDeleteBuffers(1, &vertex_buffer); +} diff --git a/gpu/command_buffer/tests/gl_test_utils.h b/gpu/command_buffer/tests/gl_test_utils.h index 537442f..e2f88f5 100644 --- a/gpu/command_buffer/tests/gl_test_utils.h +++ b/gpu/command_buffer/tests/gl_test_utils.h @@ -10,6 +10,10 @@ #include <GLES2/gl2.h> #include <stdint.h> +namespace gfx { +class Size; +} // namespace gfx + class GLTestHelper { public: static const uint8_t kCheckClearValue = 123u; @@ -58,6 +62,8 @@ class GLTestHelper { // Uses ReadPixels to save an area of the current FBO/Backbuffer. static bool SaveBackbufferAsBMP(const char* filename, int width, int height); + + static void DrawTextureQuad(GLenum target, const gfx::Size& size); }; #endif // GPU_COMMAND_BUFFER_TESTS_GL_TEST_UTILS_H_ |