diff options
author | gman@chromium.org <gman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-03-10 18:37:56 +0000 |
---|---|---|
committer | gman@chromium.org <gman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-03-10 18:37:56 +0000 |
commit | 4848b9f891c3d572f7dc88478e2a1ca84c28f92d (patch) | |
tree | 064eec4ac2a5c569a84e09f9dd8e742a1160fdb0 /gpu | |
parent | a49d43f13bc2a51d2d6a4a618a8b5fabafc3c9f6 (diff) | |
download | chromium_src-4848b9f891c3d572f7dc88478e2a1ca84c28f92d.zip chromium_src-4848b9f891c3d572f7dc88478e2a1ca84c28f92d.tar.gz chromium_src-4848b9f891c3d572f7dc88478e2a1ca84c28f92d.tar.bz2 |
Make readPixels work around bug in OSX drivers that don't always
set Alpha to 255 when reading an RGB backbuffer as RGBA.
TEST=unit tests
BUG=72598
Review URL: http://codereview.chromium.org/6646006
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@77662 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'gpu')
4 files changed, 123 insertions, 14 deletions
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc index 29ba3d6..b42c220 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc @@ -4863,9 +4863,57 @@ error::Error GLES2DecoderImpl::HandleReadPixels( GLenum error = glGetError(); if (error == GL_NO_ERROR) { *result = true; + + GLenum read_format = GetBoundReadFrameBufferInternalFormat(); + uint32 channels_exist = GLES2Util::GetChannelsForFormat(read_format); + if ((channels_exist & 0x0008) == 0) { + // Set the alpha to 255 because some drivers are buggy in this regard. + uint32 temp_size; + if (!GLES2Util::ComputeImageDataSize( + width, 1, format, type, pack_alignment_, &temp_size)) { + SetGLError(GL_INVALID_VALUE, "glReadPixels: dimensions out of range"); + return error::kNoError; + } + GLsizei unpadded_row_size = temp_size; + if (!GLES2Util::ComputeImageDataSize( + width, 2, format, type, pack_alignment_, &temp_size)) { + SetGLError(GL_INVALID_VALUE, "glReadPixels: dimensions out of range"); + return error::kNoError; + } + GLsizei padded_row_size = temp_size - unpadded_row_size; + if (padded_row_size < 0 || unpadded_row_size < 0) { + SetGLError(GL_INVALID_VALUE, "glReadPixels: dimensions out of range"); + return error::kNoError; + } + // NOTE: Assumes the type is GL_UNSIGNED_BYTE which was true at the time + // of this implementation. + if (type != GL_UNSIGNED_BYTE) { + SetGLError(GL_INVALID_OPERATION, "unsupported readPixel format"); + return error::kNoError; + } + switch (format) { + case GL_RGBA: + case GL_ALPHA: { + int offset = (format == GL_ALPHA) ? 0 : 3; + int step = (format == GL_ALPHA) ? 1 : 4; + uint8* dst = static_cast<uint8*>(pixels) + offset; + for (GLint yy = 0; yy < height; ++yy) { + uint8* end = dst + unpadded_row_size; + for (uint8* d = dst; d < end; d += step) { + *d = 255; + } + dst += padded_row_size; + } + break; + } + default: + break; + } + } } else { SetGLError(error, NULL); } + return error::kNoError; } diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc index 4b738a5..2363d2f 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc @@ -42,6 +42,15 @@ class GLES2DecoderTest : public GLES2DecoderTestBase { bool init); }; +class GLES2DecoderRGBBackbufferTest : public GLES2DecoderTest { + public: + GLES2DecoderRGBBackbufferTest() { } + + virtual void SetUp() { + InitDecoder("", false); + } +}; + class GLES2DecoderWithShaderTest : public GLES2DecoderWithShaderTestBase { public: GLES2DecoderWithShaderTest() @@ -1411,12 +1420,14 @@ class ReadPixelsEmulator { // pack_alignment is the alignment you want ReadPixels to use // when copying. The actual data passed in pixels should be contiguous. ReadPixelsEmulator(GLsizei width, GLsizei height, GLint bytes_per_pixel, - const void* pixels, GLint pack_alignment) + const void* src_pixels, const void* expected_pixels, + GLint pack_alignment) : width_(width), height_(height), pack_alignment_(pack_alignment), bytes_per_pixel_(bytes_per_pixel), - pixels_(reinterpret_cast<const int8*>(pixels)) { + src_pixels_(reinterpret_cast<const int8*>(src_pixels)), + expected_pixels_(reinterpret_cast<const int8*>(expected_pixels)) { } void ReadPixels( @@ -1427,7 +1438,7 @@ class ReadPixelsEmulator { DCHECK_LE(x + width, width_); DCHECK_LE(y + height, height_); for (GLint yy = 0; yy < height; ++yy) { - const int8* src = GetPixelAddress(x, y + yy); + const int8* src = GetPixelAddress(src_pixels_, x, y + yy); const void* dst = ComputePackAlignmentAddress(0, yy, width, pixels); memcpy(const_cast<void*>(dst), src, width * bytes_per_pixel_); } @@ -1436,7 +1447,8 @@ class ReadPixelsEmulator { bool CompareRowSegment( GLint x, GLint y, GLsizei width, const void* data) const { DCHECK(x + width <= width_ || width == 0); - return memcmp(data, GetPixelAddress(x, y), width * bytes_per_pixel_) == 0; + return memcmp(data, GetPixelAddress(expected_pixels_, x, y), + width * bytes_per_pixel_) == 0; } // Helper to compute address of pixel in pack aligned data. @@ -1452,7 +1464,7 @@ class ReadPixelsEmulator { GLint ComputeImageDataSize(GLint width, GLint height) const { GLint row_size = width * bytes_per_pixel_; if (height > 1) { - GLint temp = row_size + pack_alignment_; + GLint temp = row_size + pack_alignment_ - 1; GLint padded_row_size = (temp / pack_alignment_) * pack_alignment_; GLint size_of_all_but_last_row = (height - 1) * padded_row_size; return size_of_all_but_last_row + row_size; @@ -1462,15 +1474,16 @@ class ReadPixelsEmulator { } private: - const int8* GetPixelAddress(GLint x, GLint y) const { - return pixels_ + (width_ * y + x) * bytes_per_pixel_; + const int8* GetPixelAddress(const int8* base, GLint x, GLint y) const { + return base + (width_ * y + x) * bytes_per_pixel_; } GLsizei width_; GLsizei height_; GLint pack_alignment_; GLint bytes_per_pixel_; - const int8* pixels_; + const int8* src_pixels_; + const int8* expected_pixels_; }; } // anonymous namespace @@ -1529,7 +1542,7 @@ void GLES2DecoderTest::CheckReadPixelsOutOfRange( } ReadPixelsEmulator emu( - kWidth, kHeight, kBytesPerPixel, kSrcPixels, kPackAlignment); + kWidth, kHeight, kBytesPerPixel, kSrcPixels, kSrcPixels, kPackAlignment); typedef ReadPixels::Result Result; Result* result = GetSharedMemoryAs<Result*>(); uint32 result_shm_id = kSharedMemoryId; @@ -1621,7 +1634,7 @@ TEST_F(GLES2DecoderTest, ReadPixels) { context_->SetSize(gfx::Size(INT_MAX, INT_MAX)); ReadPixelsEmulator emu( - kWidth, kHeight, kBytesPerPixel, kSrcPixels, kPackAlignment); + kWidth, kHeight, kBytesPerPixel, kSrcPixels, kSrcPixels, kPackAlignment); typedef ReadPixels::Result Result; Result* result = GetSharedMemoryAs<Result*>(); uint32 result_shm_id = kSharedMemoryId; @@ -1648,6 +1661,53 @@ TEST_F(GLES2DecoderTest, ReadPixels) { } } +TEST_F(GLES2DecoderRGBBackbufferTest, ReadPixelsNoAlphaBackbuffer) { + const GLsizei kWidth = 3; + const GLsizei kHeight = 3; + const GLint kBytesPerPixel = 4; + const GLint kPackAlignment = 4; + static const uint8 kExpectedPixels[kWidth * kHeight * kBytesPerPixel] = { + 12, 13, 14, 255, 19, 18, 19, 255, 13, 14, 18, 255, + 29, 28, 23, 255, 21, 22, 21, 255, 28, 23, 22, 255, + 31, 34, 39, 255, 32, 37, 32, 255, 34, 39, 37, 255, + }; + static const uint8 kSrcPixels[kWidth * kHeight * kBytesPerPixel] = { + 12, 13, 14, 18, 19, 18, 19, 12, 13, 14, 18, 19, + 29, 28, 23, 22, 21, 22, 21, 29, 28, 23, 22, 21, + 31, 34, 39, 37, 32, 37, 32, 31, 34, 39, 37, 32, + }; + + context_->SetSize(gfx::Size(INT_MAX, INT_MAX)); + + ReadPixelsEmulator emu( + kWidth, kHeight, kBytesPerPixel, kSrcPixels, kExpectedPixels, + kPackAlignment); + typedef ReadPixels::Result Result; + Result* result = GetSharedMemoryAs<Result*>(); + uint32 result_shm_id = kSharedMemoryId; + uint32 result_shm_offset = kSharedMemoryOffset; + uint32 pixels_shm_id = kSharedMemoryId; + uint32 pixels_shm_offset = kSharedMemoryOffset + sizeof(*result); + void* dest = &result[1]; + EXPECT_CALL(*gl_, GetError()) + .WillOnce(Return(GL_NO_ERROR)) + .WillOnce(Return(GL_NO_ERROR)) + .RetiresOnSaturation(); + EXPECT_CALL( + *gl_, ReadPixels(0, 0, kWidth, kHeight, GL_RGBA, GL_UNSIGNED_BYTE, _)) + .WillOnce(Invoke(&emu, &ReadPixelsEmulator::ReadPixels)); + ReadPixels cmd; + cmd.Init(0, 0, kWidth, kHeight, GL_RGBA, GL_UNSIGNED_BYTE, + pixels_shm_id, pixels_shm_offset, + result_shm_id, result_shm_offset); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + for (GLint yy = 0; yy < kHeight; ++yy) { + EXPECT_TRUE(emu.CompareRowSegment( + 0, yy, kWidth, + emu.ComputePackAlignmentAddress(0, yy, kWidth, dest))); + } +} + TEST_F(GLES2DecoderTest, ReadPixelsOutOfRange) { static GLint tests[][4] = { { -2, -1, 9, 5, }, // out of range on all sides diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc index 7125745..18a920f 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc @@ -46,10 +46,11 @@ GLES2DecoderTestBase::GLES2DecoderTestBase() GLES2DecoderTestBase::~GLES2DecoderTestBase() {} void GLES2DecoderTestBase::SetUp() { - InitDecoder(""); + InitDecoder("", true); } -void GLES2DecoderTestBase::InitDecoder(const char* extensions) { +void GLES2DecoderTestBase::InitDecoder( + const char* extensions, bool has_alpha_backbuffer) { gl_.reset(new StrictMock<MockGLInterface>()); ::gfx::GLInterface::SetGLInterface(gl_.get()); group_ = ContextGroup::Ref(new ContextGroup()); @@ -61,7 +62,7 @@ void GLES2DecoderTestBase::InitDecoder(const char* extensions) { EXPECT_TRUE(group_->Initialize(extensions)); EXPECT_CALL(*gl_, GetIntegerv(GL_ALPHA_BITS, _)) - .WillOnce(SetArgumentPointee<1>(8)) + .WillOnce(SetArgumentPointee<1>(has_alpha_backbuffer ? 8 : 0)) .RetiresOnSaturation(); EXPECT_CALL(*gl_, EnableVertexAttribArray(0)) .Times(1) diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h index 79e2a9b..c184f17 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h @@ -160,7 +160,7 @@ class GLES2DecoderTestBase : public testing::Test { void SetBucketAsCString(uint32 bucket_id, const char* str); - void InitDecoder(const char* extensions); + void InitDecoder(const char* extensions, bool has_alpha_backbuffer); const ContextGroup& group() const { return *group_.get(); |