diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.cc b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.cc index c37effa1acd90..ebc3514ee601a 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.cc @@ -174,6 +174,30 @@ class ScopedScissorTestReset { GLboolean scissor_test_; }; +// Forces GL_RASTERIZER_DISCARD off for the lifetime of the object and restores +// the previous state on destruction. Per GLES3 ยง4.2.3 (and ANGLE +// Context::clear), glClear is silently discarded under rasterizer discard, so +// any internal clear that runs on a context whose state the renderer controls +// must explicitly disable it first. +class ScopedRasterizerDiscardDisable { + public: + explicit ScopedRasterizerDiscardDisable(gl::GLApi* api) : api_(api) { + rasterizer_discard_ = api_->glIsEnabledFn(GL_RASTERIZER_DISCARD); + if (rasterizer_discard_) { + api_->glDisableFn(GL_RASTERIZER_DISCARD); + } + } + ~ScopedRasterizerDiscardDisable() { + if (rasterizer_discard_) { + api_->glEnableFn(GL_RASTERIZER_DISCARD); + } + } + + private: + raw_ptr api_; + GLboolean rasterizer_discard_; +}; + template void DeleteServiceObjects(ClientServiceMap* id_map, bool have_context, @@ -608,6 +632,11 @@ void PassthroughResources::SharedImageData::EnsureClear( ScopedColorMaskZeroReset color_mask_reset(api, use_oes_draw_buffers_indexed); ScopedScissorTestReset scissor_test_reset(api); + // GL_RASTERIZER_DISCARD is renderer-controlled state on this context and + // would cause the glClear below to be silently discarded by ANGLE while + // glCheckFramebufferStatus still reports COMPLETE, leading SetCleared() to + // mark uninitialized memory as cleared. Force it off for this clear. + ScopedRasterizerDiscardDisable rasterizer_discard_disable(api); // Generate a new framebuffer and bind the shared image's uncleared texture // to it.