diff options
Diffstat (limited to 'gpu/command_buffer/service')
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; |