summaryrefslogtreecommitdiffstats
path: root/gpu
diff options
context:
space:
mode:
authorgman@chromium.org <gman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-03-10 18:37:56 +0000
committergman@chromium.org <gman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-03-10 18:37:56 +0000
commit4848b9f891c3d572f7dc88478e2a1ca84c28f92d (patch)
tree064eec4ac2a5c569a84e09f9dd8e742a1160fdb0 /gpu
parenta49d43f13bc2a51d2d6a4a618a8b5fabafc3c9f6 (diff)
downloadchromium_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')
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder.cc48
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc80
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc7
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h2
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();