RasterDecoder: only reset necessary gl state for DoCopySubTexture
Because RasterDecoder::DoCopySubTexture only depends on several pixel
unpack related state.
Bug: 902904
Change-Id: I08fe3996c85818c745605ca6e80c5af8fbf713a7
Reviewed-on: https://chromium-review.googlesource.com/c/1354135
Commit-Queue: Peng Huang <penghuang@chromium.org>
Reviewed-by: Antoine Labour <piman@chromium.org>
Cr-Commit-Position: refs/heads/master@{#613511}
diff --git a/gpu/command_buffer/service/feature_info.cc b/gpu/command_buffer/service/feature_info.cc
index 7932e09..84425e9 100644
--- a/gpu/command_buffer/service/feature_info.cc
+++ b/gpu/command_buffer/service/feature_info.cc
@@ -1493,7 +1493,10 @@
feature_flags_.ext_robustness =
gfx::HasExtension(extensions, "GL_EXT_robustness");
feature_flags_.ext_pixel_buffer_object =
+ gfx::HasExtension(extensions, "GL_ARB_pixel_buffer_object") ||
gfx::HasExtension(extensions, "GL_NV_pixel_buffer_object");
+ feature_flags_.ext_unpack_subimage =
+ gfx::HasExtension(extensions, "GL_EXT_unpack_subimage");
feature_flags_.oes_rgb8_rgba8 =
gfx::HasExtension(extensions, "GL_OES_rgb8_rgba8");
feature_flags_.angle_robust_resource_initialization =
diff --git a/gpu/command_buffer/service/feature_info.h b/gpu/command_buffer/service/feature_info.h
index 925fd2e..cb42ce97 100644
--- a/gpu/command_buffer/service/feature_info.h
+++ b/gpu/command_buffer/service/feature_info.h
@@ -127,6 +127,7 @@
bool khr_robustness = false;
bool ext_robustness = false;
bool ext_pixel_buffer_object = false;
+ bool ext_unpack_subimage = false;
bool oes_rgb8_rgba8 = false;
bool angle_robust_resource_initialization = false;
bool nv_fence = false;
diff --git a/gpu/command_buffer/service/raster_decoder.cc b/gpu/command_buffer/service/raster_decoder.cc
index 42aa52f..d3d5f1af3 100644
--- a/gpu/command_buffer/service/raster_decoder.cc
+++ b/gpu/command_buffer/service/raster_decoder.cc
@@ -162,36 +162,44 @@
class ScopedTextureBinder {
public:
ScopedTextureBinder(gles2::ContextState* state,
+ GLenum target,
+ GLuint texture,
+ GrContext* gr_context,
+ bool state_is_dirty)
+ : state_(state), target_(target), state_is_dirty_(state_is_dirty) {
+ auto* api = state->api();
+ api->glActiveTextureFn(GL_TEXTURE0);
+ api->glBindTextureFn(target_, texture);
+ if (gr_context)
+ gr_context->resetContext(kTextureBinding_GrGLBackendState);
+ }
+
+ ScopedTextureBinder(gles2::ContextState* state,
gles2::TextureManager* texture_manager,
gles2::TextureRef* texture_ref,
GLenum target,
GrContext* gr_context,
bool state_is_dirty)
- : state_(state),
- target_(target),
- gr_context_(gr_context),
- state_is_dirty_(state_is_dirty) {
- auto* api = state->api();
- api->glActiveTextureFn(GL_TEXTURE0);
- gles2::Texture* texture = texture_ref->texture();
- if (texture->target() == 0)
+ : ScopedTextureBinder(state,
+ target,
+ texture_ref->texture()->service_id(),
+ gr_context,
+ state_is_dirty) {
+ auto* texture = texture_ref->texture();
+ if (!texture->target())
texture_manager->SetTarget(texture_ref, target);
DCHECK_EQ(texture->target(), target_)
<< "Texture bound to more than 1 target.";
- api->glBindTextureFn(target_, texture_ref->service_id());
}
~ScopedTextureBinder() {
if (!state_is_dirty_)
state_->api()->glBindTextureFn(target_, 0);
- if (gr_context_)
- gr_context_->resetContext(kTextureBinding_GrGLBackendState);
}
private:
gles2::ContextState* state_;
GLenum target_;
- GrContext* gr_context_;
const bool state_is_dirty_;
DISALLOW_COPY_AND_ASSIGN(ScopedTextureBinder);
@@ -202,14 +210,29 @@
// scope.
class ScopedPixelUnpackState {
public:
- explicit ScopedPixelUnpackState(gles2::ContextState* state) : state_(state) {
- DCHECK(state_);
- state_->PushTextureUnpackState();
+ explicit ScopedPixelUnpackState(gles2::ContextState* state,
+ GrContext* gr_context,
+ const gles2::FeatureInfo* feature_info) {
+ DCHECK(state);
+ auto* api = state->api();
+ api->glPixelStoreiFn(GL_UNPACK_ALIGNMENT, 4);
+ if (feature_info->gl_version_info().is_es3 ||
+ feature_info->gl_version_info().is_desktop_core_profile ||
+ feature_info->feature_flags().ext_pixel_buffer_object)
+ api->glBindBufferFn(GL_PIXEL_UNPACK_BUFFER, 0);
+
+ if (feature_info->gl_version_info().is_es3 ||
+ feature_info->gl_version_info().is_desktop_core_profile ||
+ feature_info->feature_flags().ext_unpack_subimage)
+ api->glPixelStoreiFn(GL_UNPACK_ROW_LENGTH, 0);
+ if (gr_context) {
+ gr_context->resetContext(kMisc_GrGLBackendState |
+ kPixelStore_GrGLBackendState);
+ }
}
- ~ScopedPixelUnpackState() { state_->RestoreUnpackState(); }
+ ~ScopedPixelUnpackState() = default;
private:
- gles2::ContextState* state_;
DISALLOW_COPY_AND_ASSIGN(ScopedPixelUnpackState);
};
@@ -231,84 +254,13 @@
}
}
-// Commands that do not require that GL state matches ContextState. Some
-// are completely indifferent to GL state. Others require that GL state
-// matches GrContext state tracking.
-bool PermitsInconsistentContextState(CommandId command) {
- // Note that state restoration is expensive. If you're adding any new
- // command which is frequently used between multiple RasterCHROMIUMs for
- // tiled rasterization, make sure to add it to the whitelist below for
- // commands which don't need consistent GL state.
- switch (command) {
- case kBeginQueryEXT:
- case kBeginRasterCHROMIUMImmediate:
- case kCreateAndConsumeTextureINTERNALImmediate:
- case kCreateTransferCacheEntryINTERNAL:
- case kDeleteQueriesEXTImmediate:
- case kDeleteTexturesImmediate:
- case kDeleteTransferCacheEntryINTERNAL:
- case kEndQueryEXT:
- case kEndRasterCHROMIUM:
- case kFinish:
- case kFlush:
- case kGenQueriesEXTImmediate:
- case kGetError:
- case kInsertFenceSyncCHROMIUM:
- case kRasterCHROMIUM:
- case kSetActiveURLCHROMIUM:
- case kUnlockTransferCacheEntryINTERNAL:
- case kWaitSyncTokenCHROMIUM:
- case kTraceBeginCHROMIUM:
- case kTraceEndCHROMIUM:
- case kDeletePaintCacheTextBlobsINTERNALImmediate:
- case kDeletePaintCachePathsINTERNALImmediate:
- case kClearPaintCacheINTERNAL:
- return true;
- case kLoseContextCHROMIUM:
- case kCopySubTexture:
- return false;
- case kNumCommands:
- case kOneBeforeStartPoint:
- NOTREACHED();
- return false;
- }
-
- NOTREACHED();
- return false;
-}
-
} // namespace
// RasterDecoderImpl uses two separate state trackers (gpu::gles2::ContextState
// and GrContext) that cache the current GL driver state. Each class sees a
// fraction of the GL calls issued and can easily become inconsistent with GL
// state. We guard against that by resetting. But resetting is expensive, so we
-// avoid it as much as possible. The argument for correctness is as follows:
-//
-// - GLES2Decoder: The GL state matches the ContextState before and after a
-// command is executed here. The interesting case is making a GLES2Decoder
-// current. If using a virtual context, we will restore state appropriately
-// when the GLES2Decoder is made current because of the call to
-// RasterDecoderImpl::GetContextState.
-//
-// - RasterDecoder: There are two cases to consider
-//
-// Case 1: Making a RasterDecoder current. If we are using virtual contexts,
-// we will restore to |state_| and GrContext::resetContext because of
-// RasterDecoderImpl::{GetContextState,RestoreState}. If not, we will
-// restore to the previous GL state (either |state_| or GrContext consistent
-// with previous GL state).
-//
-// Case 2a: Executing a PermitsInconsistentContextState command: Either the
-// command doesn't inspect/modify GL state (InsertSyncPoint,
-// CreateAndConsumeTexture) or it requires and maintains that GrContext
-// state tracking matches GL context state (e.g. *RasterCHROMIUM --- see
-// raster_decoder_context_state_->PessimisticallyResetGrContext).
-//
-// Case 2b: Executing a command that is not whitelisted: We force GL state to
-// match |state_| as necessary (see |need_context_state_reset|) in
-// DoCommandsImpl with RestoreState(nullptr). This will call
-// GrContext::resetContext.
+// avoid it as much as possible.
class RasterDecoderImpl final : public RasterDecoder,
public gles2::ErrorStateClient,
public ServiceFontManager::Client {
@@ -1348,11 +1300,6 @@
continue;
}
}
- if (!PermitsInconsistentContextState(command)) {
- if (raster_decoder_context_state_->need_context_state_reset) {
- RestoreState(nullptr);
- }
- }
unsigned int info_arg_count = static_cast<unsigned int>(info.arg_count);
if ((info.arg_flags == cmd::kFixed && arg_count == info_arg_count) ||
(info.arg_flags == cmd::kAtLeastN && arg_count >= info_arg_count)) {
@@ -1482,9 +1429,10 @@
uint32_t size;
uint32_t padded_row_size;
+ constexpr GLint unpack_alignment = 4;
if (!gles2::GLES2Util::ComputeImageDataSizes(width, height, 1, format, type,
- state_.unpack_alignment, &size,
- nullptr, &padded_row_size)) {
+ unpack_alignment, &size, nullptr,
+ &padded_row_size)) {
return false;
}
@@ -1501,23 +1449,29 @@
DCHECK_GT(padded_row_size, 0U);
tile_height = kMaxZeroSize / padded_row_size;
if (!gles2::GLES2Util::ComputeImageDataSizes(width, tile_height, 1, format,
- type, state_.unpack_alignment,
- &size, nullptr, nullptr)) {
+ type, unpack_alignment, &size,
+ nullptr, nullptr)) {
return false;
}
} else {
tile_height = height;
}
- api()->glBindTextureFn(texture->target(), texture->service_id());
{
+ const bool state_is_dirty =
+ raster_decoder_context_state_->need_context_state_reset;
+ ScopedTextureBinder binder(&state_, texture->target(),
+ texture->service_id(), gr_context(),
+ state_is_dirty);
+ base::Optional<ScopedPixelUnpackState> pixel_unpack_state;
+ if (raster_decoder_context_state_->need_context_state_reset) {
+ pixel_unpack_state.emplace(&state_, gr_context(), group_->feature_info());
+ }
// Add extra scope to destroy zero and the object it owns right
// after its usage.
// Assumes the size has already been checked.
std::unique_ptr<char[]> zero(new char[size]);
memset(zero.get(), 0, size);
-
- ScopedPixelUnpackState reset_restore(&state_);
GLint y = 0;
while (y < height) {
GLint h = y + tile_height > height ? height - y : tile_height;
@@ -1529,12 +1483,6 @@
}
}
DCHECK(glGetError() == GL_NO_ERROR);
-
- if (gr_context()) {
- gr_context()->resetContext(kPixelStore_GrGLBackendState |
- kTextureBinding_GrGLBackendState);
- }
-
return true;
}
@@ -1544,48 +1492,8 @@
unsigned format,
int width,
int height) {
- DCHECK(target != GL_TEXTURE_3D && target != GL_TEXTURE_2D_ARRAY);
- // This code path can only be called if the texture was originally
- // allocated via TexStorage2D. Note that TexStorage2D is exposed
- // internally for ES 2.0 contexts, but compressed texture support is
- // not part of that exposure.
- DCHECK(feature_info_->IsWebGL2OrES3Context());
-
- GLsizei bytes_required = 0;
- std::string error_str;
- if (!GetCompressedTexSizeInBytes("ClearCompressedTextureLevel", width, height,
- 1, format, &bytes_required,
- state_.GetErrorState())) {
- return false;
- }
-
- TRACE_EVENT1("gpu", "RasterDecoderImpl::ClearCompressedTextureLevel",
- "bytes_required", bytes_required);
-
- api()->glBindBufferFn(GL_PIXEL_UNPACK_BUFFER, 0);
- {
- // Add extra scope to destroy zero and the object it owns right
- // after its usage.
- std::unique_ptr<char[]> zero(new char[bytes_required]);
- memset(zero.get(), 0, bytes_required);
- api()->glBindTextureFn(texture->target(), texture->service_id());
- api()->glCompressedTexSubImage2DFn(target, level, 0, 0, width, height,
- format, bytes_required, zero.get());
- }
- gles2::TextureRef* bound_texture =
- texture_manager()->GetTextureInfoForTarget(&state_, texture->target());
- api()->glBindTextureFn(texture->target(),
- bound_texture ? bound_texture->service_id() : 0);
- gles2::Buffer* bound_buffer =
- buffer_manager()->GetBufferInfoForTarget(&state_, GL_PIXEL_UNPACK_BUFFER);
- if (bound_buffer) {
- api()->glBindBufferFn(GL_PIXEL_UNPACK_BUFFER, bound_buffer->service_id());
- }
-
- if (gr_context()) {
- gr_context()->resetContext(kTextureBinding_GrGLBackendState);
- }
- return true;
+ NOTREACHED();
+ return false;
}
int RasterDecoderImpl::DecoderIdForTest() {
@@ -1996,6 +1904,7 @@
ScopedTextureBinder binder(
&state_, texture_manager(), dest_texture_ref, dest_target, gr_context(),
raster_decoder_context_state_->need_context_state_reset);
+ base::Optional<ScopedPixelUnpackState> pixel_unpack_state;
int source_width = 0;
int source_height = 0;
@@ -2026,6 +1935,14 @@
"source texture bad dimensions");
return;
}
+
+ if (image->GetType() == gl::GLImage::Type::MEMORY &&
+ raster_decoder_context_state_->need_context_state_reset) {
+ // If the image is in shared memory, we may need upload the pixel data
+ // with SubTexImage2D, so we need reset pixel unpack state if gl context
+ // state has been touched by skia.
+ pixel_unpack_state.emplace(&state_, gr_context(), group_->feature_info());
+ }
} else {
if (!source_texture->GetLevelSize(source_target, 0 /* level */,
&source_width, &source_height, nullptr)) {
diff --git a/gpu/command_buffer/service/raster_decoder_unittest.cc b/gpu/command_buffer/service/raster_decoder_unittest.cc
index 8bd41e7..89d2836 100644
--- a/gpu/command_buffer/service/raster_decoder_unittest.cc
+++ b/gpu/command_buffer/service/raster_decoder_unittest.cc
@@ -138,6 +138,7 @@
}
TEST_P(RasterDecoderTest, CopyTexSubImage2DTwiceClearsUnclearedTexture) {
+ raster_decoder_context_state_->need_context_state_reset = true;
// Create uninitialized source texture.
GLuint source_texture_id = kNewClientId;
CreateFakeTexture(source_texture_id, kNewServiceId,
@@ -311,13 +312,6 @@
EXPECT_FALSE(error::IsError(ExecuteCmd(decoder2.get(), end_raster_cmd)));
EXPECT_TRUE(context_state_->need_context_state_reset);
- // Now process a command which requires consistent state.
- LoseContextCHROMIUM lose_context_cmd;
- lose_context_cmd.Init(GL_GUILTY_CONTEXT_RESET_ARB,
- GL_INNOCENT_CONTEXT_RESET_ARB);
- EXPECT_FALSE(error::IsError(ExecuteCmd(decoder2.get(), lose_context_cmd)));
- EXPECT_FALSE(context_state_->need_context_state_reset);
-
decoder1->Destroy(true);
context_state_->context->MakeCurrent(context_state_->surface.get());
decoder2->Destroy(true);
diff --git a/gpu/command_buffer/service/raster_decoder_unittest_base.cc b/gpu/command_buffer/service/raster_decoder_unittest_base.cc
index 5e8409f..0c9edddb 100644
--- a/gpu/command_buffer/service/raster_decoder_unittest_base.cc
+++ b/gpu/command_buffer/service/raster_decoder_unittest_base.cc
@@ -253,14 +253,13 @@
SetupInitCapabilitiesExpectations(group_->feature_info()->IsES3Capable());
SetupInitStateExpectations(group_->feature_info()->IsES3Capable());
- scoped_refptr<raster::RasterDecoderContextState> context_state =
- new raster::RasterDecoderContextState(
- new gl::GLShareGroup(), surface_, context_,
- feature_info->workarounds().use_virtualized_gl_contexts,
- base::DoNothing());
+ raster_decoder_context_state_ = new raster::RasterDecoderContextState(
+ new gl::GLShareGroup(), surface_, context_,
+ feature_info->workarounds().use_virtualized_gl_contexts,
+ base::DoNothing());
decoder_.reset(RasterDecoder::Create(this, command_buffer_service_.get(),
&outputter_, group_.get(),
- std::move(context_state)));
+ raster_decoder_context_state_));
decoder_->SetIgnoreCachedStateForTest(ignore_cached_state_for_test_);
decoder_->GetLogger()->set_log_synthesized_gl_errors(false);
@@ -400,7 +399,8 @@
.Times(Between(1, 2))
.RetiresOnSaturation();
EXPECT_CALL(*gl_, BindTexture(target, Ne(0U))).Times(1).RetiresOnSaturation();
- EXPECT_CALL(*gl_, BindTexture(target, 0)).Times(1).RetiresOnSaturation();
+ if (!raster_decoder_context_state_->need_context_state_reset)
+ EXPECT_CALL(*gl_, BindTexture(target, 0)).Times(1).RetiresOnSaturation();
}
void RasterDecoderTestBase::SetupClearTextureExpectations(
@@ -420,7 +420,7 @@
.Times(1)
.RetiresOnSaturation();
EXPECT_CALL(*gl_, PixelStorei(GL_UNPACK_ALIGNMENT, _))
- .Times(2)
+ .Times(1)
.RetiresOnSaturation();
if (bound_pixel_unpack_buffer) {
EXPECT_CALL(*gl_, BindBuffer(GL_PIXEL_UNPACK_BUFFER, _))
diff --git a/gpu/command_buffer/service/raster_decoder_unittest_base.h b/gpu/command_buffer/service/raster_decoder_unittest_base.h
index f34c5db5..1eae7d8 100644
--- a/gpu/command_buffer/service/raster_decoder_unittest_base.h
+++ b/gpu/command_buffer/service/raster_decoder_unittest_base.h
@@ -262,6 +262,8 @@
uint32_t immediate_buffer_[64];
const bool ignore_cached_state_for_test_;
+ scoped_refptr<raster::RasterDecoderContextState>
+ raster_decoder_context_state_;
private:
GpuPreferences gpu_preferences_;