summaryrefslogtreecommitdiffstats
path: root/gpu/command_buffer/service
diff options
context:
space:
mode:
Diffstat (limited to 'gpu/command_buffer/service')
-rw-r--r--gpu/command_buffer/service/context_state.cc4
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder.cc75
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc21
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h2
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder_unittest_framebuffers.cc160
5 files changed, 221 insertions, 41 deletions
diff --git a/gpu/command_buffer/service/context_state.cc b/gpu/command_buffer/service/context_state.cc
index 1a3a8c0..8b299dc 100644
--- a/gpu/command_buffer/service/context_state.cc
+++ b/gpu/command_buffer/service/context_state.cc
@@ -451,12 +451,8 @@ void ContextState::UpdatePackParameters() const {
return;
if (bound_pixel_pack_buffer.get()) {
glPixelStorei(GL_PACK_ROW_LENGTH, pack_row_length);
- glPixelStorei(GL_PACK_SKIP_PIXELS, pack_skip_pixels);
- glPixelStorei(GL_PACK_SKIP_ROWS, pack_skip_rows);
} else {
glPixelStorei(GL_PACK_ROW_LENGTH, 0);
- glPixelStorei(GL_PACK_SKIP_PIXELS, 0);
- glPixelStorei(GL_PACK_SKIP_ROWS, 0);
}
}
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index 026e2a9..515a825 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -9130,17 +9130,19 @@ error::Error GLES2DecoderImpl::HandleReadPixels(uint32_t immediate_data_size,
uint32_t unpadded_row_size = 0;
uint32_t padded_row_size = 0;
uint32_t skip_size = 0;
+ uint32_t padding = 0;
if (!GLES2Util::ComputeImageDataSizesES3(width, height, 1,
format, type,
params,
&pixels_size,
&unpadded_row_size,
&padded_row_size,
- &skip_size)) {
+ &skip_size,
+ &padding)) {
return error::kOutOfBounds;
}
- void* pixels = nullptr;
+ uint8_t* pixels = nullptr;
Buffer* buffer = state_.bound_pixel_pack_buffer.get();
if (pixels_shm_id == 0) {
if (buffer) {
@@ -9150,7 +9152,7 @@ error::Error GLES2DecoderImpl::HandleReadPixels(uint32_t immediate_data_size,
return error::kNoError;
}
uint32_t size = 0;
- if (!SafeAddUint32(pixels_size, pixels_shm_offset, &size)) {
+ if (!SafeAddUint32(pixels_size + skip_size, pixels_shm_offset, &size)) {
LOCAL_SET_GL_ERROR(
GL_INVALID_VALUE, "glReadPixels", "size + offset overflow");
return error::kNoError;
@@ -9160,7 +9162,8 @@ error::Error GLES2DecoderImpl::HandleReadPixels(uint32_t immediate_data_size,
"pixel pack buffer is not large enough");
return error::kNoError;
}
- pixels = reinterpret_cast<void *>(pixels_shm_offset);
+ pixels = reinterpret_cast<uint8_t *>(pixels_shm_offset);
+ pixels += skip_size;
} else {
return error::kInvalidArguments;
}
@@ -9168,7 +9171,8 @@ error::Error GLES2DecoderImpl::HandleReadPixels(uint32_t immediate_data_size,
if (buffer) {
return error::kInvalidArguments;
} else {
- pixels = GetSharedMemoryAs<void*>(
+ DCHECK_EQ(0u, skip_size);
+ pixels = GetSharedMemoryAs<uint8_t*>(
pixels_shm_id, pixels_shm_offset, pixels_size);
if (!pixels) {
return error::kOutOfBounds;
@@ -9318,27 +9322,17 @@ error::Error GLES2DecoderImpl::HandleReadPixels(uint32_t immediate_data_size,
if (!max_rect.Contains(rect)) {
rect.Intersect(max_rect);
if (!rect.IsEmpty()) {
- // TODO(yunchao): need to handle the out-of-bounds case for reading pixels
- // into PIXEL_PACK buffer.
- if (pixels_shm_id == 0) {
- LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, "glReadPixels",
- "read pixels out of bounds into PIXEL_PACK buffer");
- return error::kNoError;
- }
-
- int8_t* dst = static_cast<int8_t*>(pixels);
if (y < 0) {
- uint32_t skip_rows_bytes = static_cast<uint32_t>(-y) * padded_row_size;
- dst += skip_rows_bytes;
+ pixels += static_cast<uint32_t>(-y) * padded_row_size;;
}
if (x < 0) {
uint32_t group_size = GLES2Util::ComputeImageGroupSize(format, type);
uint32_t leading_bytes = static_cast<uint32_t>(-x) * group_size;
- dst += leading_bytes;
+ pixels += leading_bytes;
}
for (GLint iy = rect.y(); iy < rect.bottom(); ++iy) {
- glReadPixels(rect.x(), iy, rect.width(), 1, format, type, dst);
- dst += padded_row_size;
+ glReadPixels(rect.x(), iy, rect.width(), 1, format, type, pixels);
+ pixels += padded_row_size;
}
}
} else {
@@ -9373,7 +9367,34 @@ error::Error GLES2DecoderImpl::HandleReadPixels(uint32_t immediate_data_size,
glDeleteBuffersARB(1, &buffer);
}
}
- glReadPixels(x, y, width, height, format, type, pixels);
+ if (pixels_shm_id == 0 &&
+ workarounds().pack_parameters_workaround_with_pack_buffer) {
+ if (state_.pack_row_length > 0 && state_.pack_row_length < width) {
+ // Some drivers (for example, NVidia Linux) reset in this case.
+ for (GLint iy = y; iy < y + height; ++iy) {
+ // Need to set PACK_ALIGNMENT for last row. See comment below.
+ if (iy + 1 == y + height && padding > 0)
+ glPixelStorei(GL_PACK_ALIGNMENT, 1);
+ glReadPixels(x, iy, width, 1, format, type, pixels);
+ if (iy + 1 == y + height && padding > 0)
+ glPixelStorei(GL_PACK_ALIGNMENT, state_.pack_alignment);
+ pixels += padded_row_size;
+ }
+ } else if (padding > 0) {
+ // Some drivers (for example, NVidia Linux) incorrectly require the
+ // pack buffer to have padding for the last row.
+ if (height > 1)
+ glReadPixels(x, y, width, height - 1, format, type, pixels);
+ glPixelStorei(GL_PACK_ALIGNMENT, 1);
+ pixels += padded_row_size * (height - 1);
+ glReadPixels(x, y + height - 1, width, 1, format, type, pixels);
+ glPixelStorei(GL_PACK_ALIGNMENT, state_.pack_alignment);
+ } else {
+ glReadPixels(x, y, width, height, format, type, pixels);
+ }
+ } else {
+ glReadPixels(x, y, width, height, format, type, pixels);
+ }
}
if (pixels_shm_id != 0) {
GLenum error = LOCAL_PEEK_GL_ERROR("glReadPixels");
@@ -9425,16 +9446,20 @@ error::Error GLES2DecoderImpl::HandlePixelStorei(uint32_t immediate_data_size,
default:
break;
}
- // For pack and unpack parameters (except for alignment), we don't apply them
- // if no buffer is bound at PIXEL_PACK or PIXEL_UNPACK. We will handle pack
- // and unpack according to the user specified parameters on the client side.
+ // For pack skip parameters, we don't apply them and handle them in command
+ // buffer.
+ // For alignment parameters, we always apply them.
+ // For other parameters, we don't apply them if no buffer is bound at
+ // PIXEL_PACK or PIXEL_UNPACK. We will handle pack and unpack according to
+ // the user specified parameters on the client side.
switch (pname) {
case GL_PACK_ROW_LENGTH:
- case GL_PACK_SKIP_PIXELS:
- case GL_PACK_SKIP_ROWS:
if (state_.bound_pixel_pack_buffer.get())
glPixelStorei(pname, param);
break;
+ case GL_PACK_SKIP_PIXELS:
+ case GL_PACK_SKIP_ROWS:
+ break;
case GL_UNPACK_ROW_LENGTH:
case GL_UNPACK_IMAGE_HEIGHT:
case GL_UNPACK_SKIP_PIXELS:
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 4c4e9f0..88a46bd 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc
@@ -841,12 +841,6 @@ void GLES2DecoderTestBase::DoBindBuffer(
EXPECT_CALL(*gl_, PixelStorei(GL_PACK_ROW_LENGTH, _))
.Times(1)
.RetiresOnSaturation();
- EXPECT_CALL(*gl_, PixelStorei(GL_PACK_SKIP_PIXELS, _))
- .Times(1)
- .RetiresOnSaturation();
- EXPECT_CALL(*gl_, PixelStorei(GL_PACK_SKIP_ROWS, _))
- .Times(1)
- .RetiresOnSaturation();
}
cmds::BindBuffer cmd;
cmd.Init(target, client_id);
@@ -1825,6 +1819,15 @@ void GLES2DecoderTestBase::DoScissor(GLint x,
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
}
+void GLES2DecoderTestBase::DoPixelStorei(GLenum pname, GLint param) {
+ EXPECT_CALL(*gl_, PixelStorei(pname, param))
+ .Times(1)
+ .RetiresOnSaturation();
+ cmds::PixelStorei cmd;
+ cmd.Init(pname, param);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+}
+
void GLES2DecoderTestBase::SetupVertexBuffer() {
DoEnableVertexAttribArray(1);
DoBindBuffer(GL_ARRAY_BUFFER, client_buffer_id_, kServiceBufferId);
@@ -1929,12 +1932,6 @@ void GLES2DecoderTestBase::SetupInitStateManualExpectations(bool es3_capable) {
EXPECT_CALL(*gl_, PixelStorei(GL_PACK_ROW_LENGTH, 0))
.Times(1)
.RetiresOnSaturation();
- EXPECT_CALL(*gl_, PixelStorei(GL_PACK_SKIP_PIXELS, 0))
- .Times(1)
- .RetiresOnSaturation();
- EXPECT_CALL(*gl_, PixelStorei(GL_PACK_SKIP_ROWS, 0))
- .Times(1)
- .RetiresOnSaturation();
EXPECT_CALL(*gl_, PixelStorei(GL_UNPACK_ROW_LENGTH, 0))
.Times(1)
.RetiresOnSaturation();
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 ff8c0ab..1e08254 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h
@@ -356,6 +356,8 @@ class GLES2DecoderTestBase : public ::testing::TestWithParam<bool> {
void DoScissor(GLint x, GLint y, GLsizei width, GLsizei height);
+ void DoPixelStorei(GLenum pname, GLint param);
+
void SetupVertexBuffer();
void SetupAllNeededVertexBuffers();
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_framebuffers.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_framebuffers.cc
index 3383e26..ec0234d 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_framebuffers.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_framebuffers.cc
@@ -818,6 +818,166 @@ TEST_P(GLES3DecoderTest, ReadPixelsPixelPackBufferIsNotLargeEnough) {
EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
}
+TEST_P(GLES2DecoderManualInitTest, ReadPixels2RowLengthWorkaround) {
+ base::CommandLine command_line(0, NULL);
+ command_line.AppendSwitchASCII(
+ switches::kGpuDriverBugWorkarounds,
+ base::IntToString(gpu::PACK_PARAMETERS_WORKAROUND_WITH_PACK_BUFFER));
+ command_line.AppendSwitch(switches::kEnableUnsafeES3APIs);
+ InitState init;
+ init.gl_version = "OpenGL ES 3.0";
+ init.bind_generates_resource = true;
+ init.context_type = CONTEXT_TYPE_OPENGLES3;
+ InitDecoderWithCommandLine(init, &command_line);
+
+ const GLsizei kWidth = 5;
+ const GLsizei kHeight = 3;
+ const GLint kBytesPerPixel = 4;
+ const GLenum kFormat = GL_RGBA;
+ const GLenum kType = GL_UNSIGNED_BYTE;
+ const GLint kRowLength = 4;
+ GLint size = (kRowLength * (kHeight - 1) + kWidth) * kBytesPerPixel;
+
+ DoBindBuffer(GL_PIXEL_PACK_BUFFER, client_buffer_id_, kServiceBufferId);
+ DoBufferData(GL_PIXEL_PACK_BUFFER, size);
+
+ DoPixelStorei(GL_PACK_ROW_LENGTH, kRowLength);
+
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ for (GLint ii = 0; ii < kHeight; ++ii) {
+ void* offset = reinterpret_cast<void*>(ii * kRowLength * kBytesPerPixel);
+ EXPECT_CALL(*gl_, ReadPixels(0, ii, kWidth, 1, kFormat, kType, offset))
+ .Times(1)
+ .RetiresOnSaturation();
+ }
+
+ ReadPixels cmd;
+ cmd.Init(0, 0, kWidth, kHeight,
+ kFormat, kType,
+ 0, 0, 0, 0,
+ false);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_P(GLES2DecoderManualInitTest, ReadPixels2AlignmentWorkaround) {
+ base::CommandLine command_line(0, NULL);
+ command_line.AppendSwitchASCII(
+ switches::kGpuDriverBugWorkarounds,
+ base::IntToString(gpu::PACK_PARAMETERS_WORKAROUND_WITH_PACK_BUFFER));
+ command_line.AppendSwitch(switches::kEnableUnsafeES3APIs);
+ InitState init;
+ init.gl_version = "OpenGL ES 3.0";
+ init.bind_generates_resource = true;
+ init.context_type = CONTEXT_TYPE_OPENGLES3;
+ InitDecoderWithCommandLine(init, &command_line);
+
+ const GLsizei kWidth = 5;
+ const GLsizei kHeight = 3;
+ const GLint kBytesPerPixel = 4;
+ const GLenum kFormat = GL_RGBA;
+ const GLenum kType = GL_UNSIGNED_BYTE;
+ const GLint kAlignment = 8;
+ const GLint kPadding = 4;
+ GLint size = kWidth * kBytesPerPixel * kHeight + kPadding * (kHeight - 1);
+
+ DoBindBuffer(GL_PIXEL_PACK_BUFFER, client_buffer_id_, kServiceBufferId);
+ DoBufferData(GL_PIXEL_PACK_BUFFER, size);
+
+ DoPixelStorei(GL_PACK_ALIGNMENT, kAlignment);
+
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ uint8_t* offset = reinterpret_cast<uint8_t*>(0);
+ EXPECT_CALL(*gl_,
+ ReadPixels(0, 0, kWidth, kHeight - 1, kFormat, kType, offset))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, PixelStorei(GL_PACK_ALIGNMENT, 1))
+ .Times(1)
+ .RetiresOnSaturation();
+ offset += (kWidth * kBytesPerPixel + kPadding) * (kHeight - 1);
+ EXPECT_CALL(*gl_,
+ ReadPixels(0, kHeight - 1, kWidth, 1, kFormat, kType, offset))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, PixelStorei(GL_PACK_ALIGNMENT, kAlignment))
+ .Times(1)
+ .RetiresOnSaturation();
+
+ ReadPixels cmd;
+ cmd.Init(0, 0, kWidth, kHeight,
+ kFormat, kType,
+ 0, 0, 0, 0,
+ false);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_P(GLES2DecoderManualInitTest,
+ ReadPixels2RowLengthAndAlignmentWorkarounds) {
+ base::CommandLine command_line(0, NULL);
+ command_line.AppendSwitchASCII(
+ switches::kGpuDriverBugWorkarounds,
+ base::IntToString(gpu::PACK_PARAMETERS_WORKAROUND_WITH_PACK_BUFFER));
+ command_line.AppendSwitch(switches::kEnableUnsafeES3APIs);
+ InitState init;
+ init.gl_version = "OpenGL ES 3.0";
+ init.bind_generates_resource = true;
+ init.context_type = CONTEXT_TYPE_OPENGLES3;
+ InitDecoderWithCommandLine(init, &command_line);
+
+ const GLsizei kWidth = 5;
+ const GLsizei kHeight = 3;
+ const GLint kBytesPerPixel = 4;
+ const GLenum kFormat = GL_RGBA;
+ const GLenum kType = GL_UNSIGNED_BYTE;
+ const GLint kAlignment = 8;
+ const GLint kRowLength = 3;
+ const GLint kPadding = 4;
+ GLint padded_row_size = kRowLength * kBytesPerPixel + kPadding;
+ GLint unpadded_row_size = kWidth * kBytesPerPixel;
+ GLint size = padded_row_size * (kHeight - 1) + unpadded_row_size;
+
+ DoBindBuffer(GL_PIXEL_PACK_BUFFER, client_buffer_id_, kServiceBufferId);
+ DoBufferData(GL_PIXEL_PACK_BUFFER, size);
+
+ DoPixelStorei(GL_PACK_ALIGNMENT, kAlignment);
+ DoPixelStorei(GL_PACK_ROW_LENGTH, kRowLength);
+
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ for (GLint ii = 0; ii < kHeight - 1; ++ii) {
+ void* offset = reinterpret_cast<void*>(ii * padded_row_size);
+ EXPECT_CALL(*gl_, ReadPixels(0, ii, kWidth, 1, kFormat, kType, offset))
+ .Times(1)
+ .RetiresOnSaturation();
+ }
+ EXPECT_CALL(*gl_, PixelStorei(GL_PACK_ALIGNMENT, 1))
+ .Times(1)
+ .RetiresOnSaturation();
+ void* offset = reinterpret_cast<void*>((kHeight - 1) * padded_row_size);
+ EXPECT_CALL(*gl_,
+ ReadPixels(0, kHeight - 1, kWidth, 1, kFormat, kType, offset))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, PixelStorei(GL_PACK_ALIGNMENT, kAlignment))
+ .Times(1)
+ .RetiresOnSaturation();
+
+ ReadPixels cmd;
+ cmd.Init(0, 0, kWidth, kHeight,
+ kFormat, kType,
+ 0, 0, 0, 0,
+ false);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
TEST_P(GLES2DecoderRGBBackbufferTest, ReadPixelsNoAlphaBackbuffer) {
const GLsizei kWidth = 3;
const GLsizei kHeight = 3;