diff options
author | erikchen <erikchen@chromium.org> | 2016-03-21 17:58:26 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2016-03-22 01:00:41 +0000 |
commit | 2acd56014bdf216b9808e2b07c4db0a5cbbcf137 (patch) | |
tree | d9a1bb89bdfc9aea0d1afed289cadc90cea13103 /gpu | |
parent | 4c88276f8f1fdcb0a921bfb979e22cd2acf241bb (diff) | |
download | chromium_src-2acd56014bdf216b9808e2b07c4db0a5cbbcf137.zip chromium_src-2acd56014bdf216b9808e2b07c4db0a5cbbcf137.tar.gz chromium_src-2acd56014bdf216b9808e2b07c4db0a5cbbcf137.tar.bz2 |
Make a command buffer workaround for glReadPixels on IOSurface backed textures.
The workaround previously existed in GLRenderer. This CL moves the workaround
into the command buffer.
BUG=581777
CQ_INCLUDE_TRYBOTS=tryserver.chromium.win:win_optional_gpu_tests_rel
Review URL: https://codereview.chromium.org/1806753003
Cr-Commit-Position: refs/heads/master@{#382466}
Diffstat (limited to 'gpu')
-rw-r--r-- | gpu/BUILD.gn | 1 | ||||
-rw-r--r-- | gpu/command_buffer/service/gles2_cmd_decoder.cc | 85 | ||||
-rw-r--r-- | gpu/command_buffer/tests/gl_iosurface_readback_workaround_unittest.cc | 91 | ||||
-rw-r--r-- | gpu/config/gpu_driver_bug_list_json.cc | 13 | ||||
-rw-r--r-- | gpu/config/gpu_driver_bug_workaround_type.h | 2 | ||||
-rw-r--r-- | gpu/gpu.gyp | 1 |
6 files changed, 192 insertions, 1 deletions
diff --git a/gpu/BUILD.gn b/gpu/BUILD.gn index cfa2e4a..8ae7915 100644 --- a/gpu/BUILD.gn +++ b/gpu/BUILD.gn @@ -160,6 +160,7 @@ test("gl_tests") { "command_buffer/tests/gl_ext_srgb_unittest.cc", "command_buffer/tests/gl_fence_sync_unittest.cc", "command_buffer/tests/gl_gpu_memory_buffer_unittest.cc", + "command_buffer/tests/gl_iosurface_readback_workaround_unittest.cc", "command_buffer/tests/gl_lose_context_chromium_unittest.cc", "command_buffer/tests/gl_manager.cc", "command_buffer/tests/gl_manager.h", diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc index ac72097..7ecd8d5 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc @@ -388,6 +388,23 @@ class ScopedResolvedFrameBufferBinder { DISALLOW_COPY_AND_ASSIGN(ScopedResolvedFrameBufferBinder); }; +// When an instance of this class is created, it uses copyTexImage2D to copy the +// contents of the framebuffer into a texture. This texture is then bound to a +// new framebuffer. When the instance is destroyed, the original texture and +// framebuffer are restored. +class ScopedFrameBufferReadPixelHelper { + public: + ScopedFrameBufferReadPixelHelper(ContextState* state, + GLES2DecoderImpl* decoder); + ~ScopedFrameBufferReadPixelHelper(); + + private: + GLuint temp_texture_id_ = 0; + GLuint temp_fbo_id_ = 0; + scoped_ptr<ScopedFrameBufferBinder> fbo_binder_; + DISALLOW_COPY_AND_ASSIGN(ScopedFrameBufferReadPixelHelper); +}; + // Encapsulates an OpenGL texture. class BackTexture { public: @@ -702,6 +719,7 @@ class GLES2DecoderImpl : public GLES2Decoder, public ErrorStateClient { private: friend class ScopedFrameBufferBinder; + friend class ScopedFrameBufferReadPixelHelper; friend class ScopedResolvedFrameBufferBinder; friend class BackFramebuffer; @@ -1914,6 +1932,13 @@ class GLES2DecoderImpl : public GLES2Decoder, public ErrorStateClient { GLuint* source_texture_service_id, GLenum* source_texture_target); + // On Mac OS X, calling glReadPixels() against an FBO whose color attachment + // is an IOSurface-backed texture causes corruption of future glReadPixels() + // calls, even those on different OpenGL contexts. It is believed that this + // is the root cause of top crasher + // http://crbug.com/99393. <rdar://problem/10949687> + bool NeedsIOSurfaceReadbackWorkaround(); + // Generate a member function prototype for each command in an automated and // typesafe way. #define GLES2_CMD_OP(name) \ @@ -2280,6 +2305,41 @@ ScopedResolvedFrameBufferBinder::~ScopedResolvedFrameBufferBinder() { } } +ScopedFrameBufferReadPixelHelper::ScopedFrameBufferReadPixelHelper( + ContextState* state, + GLES2DecoderImpl* decoder) { + DCHECK_EQ(static_cast<unsigned>(GL_FRAMEBUFFER_COMPLETE), + glCheckFramebufferStatusEXT(GL_FRAMEBUFFER)); + + const Framebuffer::Attachment* attachment = + decoder->GetFramebufferInfoForTarget(GL_READ_FRAMEBUFFER_EXT) + ->GetReadBufferAttachment(); + GLsizei width = attachment->width(); + GLsizei height = attachment->height(); + + glGenTextures(1, &temp_texture_id_); + glGenFramebuffersEXT(1, &temp_fbo_id_); + { + ScopedTextureBinder binder(state, temp_texture_id_, GL_TEXTURE_2D); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, width, height, 0); + + fbo_binder_.reset(new ScopedFrameBufferBinder(decoder, temp_fbo_id_)); + } + + glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, + temp_texture_id_, 0); +} + +ScopedFrameBufferReadPixelHelper::~ScopedFrameBufferReadPixelHelper() { + fbo_binder_.reset(); + glDeleteTextures(1, &temp_texture_id_); + glDeleteFramebuffersEXT(1, &temp_fbo_id_); +} + BackTexture::BackTexture( MemoryTracker* memory_tracker, ContextState* state) @@ -9467,6 +9527,9 @@ error::Error GLES2DecoderImpl::HandleReadPixels(uint32_t immediate_data_size, LOCAL_COPY_REAL_GL_ERRORS_TO_WRAPPER("glReadPixels"); ScopedResolvedFrameBufferBinder binder(this, false, true); + scoped_ptr<ScopedFrameBufferReadPixelHelper> helper; + if (NeedsIOSurfaceReadbackWorkaround()) + helper.reset(new ScopedFrameBufferReadPixelHelper(&state_, this)); gfx::Rect rect(x, y, width, height); // Safe before we checked above. gfx::Rect max_rect(max_size); @@ -16092,6 +16155,28 @@ bool GLES2DecoderImpl::NeedsCopyTextureImageWorkaround( return true; } +bool GLES2DecoderImpl::NeedsIOSurfaceReadbackWorkaround() { + if (!workarounds().iosurface_readback_workaround) + return false; + + Framebuffer* framebuffer = + GetFramebufferInfoForTarget(GL_READ_FRAMEBUFFER_EXT); + if (!framebuffer) + return false; + + const Framebuffer::Attachment* attachment = + framebuffer->GetReadBufferAttachment(); + if (!attachment) + return false; + + if (!attachment->IsTextureAttachment()) + return false; + + TextureRef* texture = + texture_manager()->GetTexture(attachment->object_name()); + return texture->texture()->HasImages(); +} + error::Error GLES2DecoderImpl::HandleBindFragmentInputLocationCHROMIUMBucket( uint32_t immediate_data_size, const void* cmd_data) { diff --git a/gpu/command_buffer/tests/gl_iosurface_readback_workaround_unittest.cc b/gpu/command_buffer/tests/gl_iosurface_readback_workaround_unittest.cc new file mode 100644 index 0000000..6a1a7c6 --- /dev/null +++ b/gpu/command_buffer/tests/gl_iosurface_readback_workaround_unittest.cc @@ -0,0 +1,91 @@ +// 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 test that exercises the glReadPixels workaround for IOSurface backed +// textures. +class GLIOSurfaceReadbackWorkaroundTest : public testing::Test { + public: + GLIOSurfaceReadbackWorkaroundTest() {} + + protected: + void SetUp() override { + base::CommandLine command_line(0, NULL); + command_line.AppendSwitchASCII( + switches::kGpuDriverBugWorkarounds, + base::IntToString(gpu::IOSURFACE_READBACK_WORKAROUND)); + gl_.InitializeWithCommandLine(GLManager::Options(), &command_line); + gl_.set_use_iosurface_memory_buffers(true); + DCHECK(gl_.workarounds().iosurface_readback_workaround); + } + + void TearDown() override { + GLTestHelper::CheckGLError("no errors", __LINE__); + gl_.Destroy(); + } + + GLManager gl_; +}; + +TEST_F(GLIOSurfaceReadbackWorkaroundTest, ReadPixels) { + 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)); + + glClearColor(33.0 / 255.0, 44.0 / 255.0, 55.0 / 255.0, 66.0 / 255.0); + glClear(GL_COLOR_BUFFER_BIT); + const uint8_t expected[4] = {33, 44, 55, 66}; + EXPECT_TRUE( + GLTestHelper::CheckPixels(0, 0, 1, 1, 1 /* tolerance */, expected)); + + glClearColor(14.0 / 255.0, 15.0 / 255.0, 16.0 / 255.0, 17.0 / 255.0); + glClear(GL_COLOR_BUFFER_BIT); + const uint8_t expected2[4] = {14, 15, 16, 17}; + EXPECT_TRUE( + GLTestHelper::CheckPixels(0, 0, 1, 1, 1 /* tolerance */, expected2)); + + glReleaseTexImage2DCHROMIUM(source_target, image_id); + glDestroyImageCHROMIUM(image_id); + glDeleteTextures(1, &source_texture); + glDeleteFramebuffers(1, &framebuffer); +} + +#endif // defined(OS_MACOSX) + +} // namespace gpu diff --git a/gpu/config/gpu_driver_bug_list_json.cc b/gpu/config/gpu_driver_bug_list_json.cc index c2dd212..b3840b2 100644 --- a/gpu/config/gpu_driver_bug_list_json.cc +++ b/gpu/config/gpu_driver_bug_list_json.cc @@ -19,7 +19,7 @@ const char kGpuDriverBugListJson[] = LONG_STRING_CONST( { "name": "gpu driver bug list", // Please update the version number whenever you change this file. - "version": "8.52", + "version": "8.53", "entries": [ { "id": 1, @@ -1844,6 +1844,17 @@ LONG_STRING_CONST( "features": [ "disable_multisampled_render_to_texture" ] + }, + { + "id": 154, + "cr_bugs": [581777], + "description": "glReadPixels does not work on IOSurface backed textures", + "os": { + "type": "macosx" + }, + "features": [ + "iosurface_readback_workaround" + ] } ] } diff --git a/gpu/config/gpu_driver_bug_workaround_type.h b/gpu/config/gpu_driver_bug_workaround_type.h index 959f780..da2acc9 100644 --- a/gpu/config/gpu_driver_bug_workaround_type.h +++ b/gpu/config/gpu_driver_bug_workaround_type.h @@ -140,6 +140,8 @@ unfold_short_circuit_as_ternary_operation) \ GPU_OP(UNPACK_ALIGNMENT_WORKAROUND_WITH_UNPACK_BUFFER, \ unpack_alignment_workaround_with_unpack_buffer) \ + GPU_OP(IOSURFACE_READBACK_WORKAROUND, \ + iosurface_readback_workaround) \ GPU_OP(UNROLL_FOR_LOOP_WITH_SAMPLER_ARRAY_INDEX, \ unroll_for_loop_with_sampler_array_index) \ GPU_OP(USE_CLIENT_SIDE_ARRAYS_FOR_STREAM_BUFFERS, \ diff --git a/gpu/gpu.gyp b/gpu/gpu.gyp index 1bd8d2f..690c329 100644 --- a/gpu/gpu.gyp +++ b/gpu/gpu.gyp @@ -362,6 +362,7 @@ 'command_buffer/tests/gl_ext_srgb_unittest.cc', 'command_buffer/tests/gl_fence_sync_unittest.cc', 'command_buffer/tests/gl_gpu_memory_buffer_unittest.cc', + 'command_buffer/tests/gl_iosurface_readback_workaround_unittest.cc', 'command_buffer/tests/gl_lose_context_chromium_unittest.cc', 'command_buffer/tests/gl_manager.cc', 'command_buffer/tests/gl_manager.h', |