diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2020-03-11 11:32:04 +0100 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2020-03-18 13:40:17 +0000 |
commit | 31ccca0778db85c159634478b4ec7997f6704860 (patch) | |
tree | 3d33fc3afd9d5ec95541e1bbe074a9cf8da12a0e /chromium/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.cc | |
parent | 248b70b82a40964d5594eb04feca0fa36716185d (diff) | |
download | qtwebengine-chromium-31ccca0778db85c159634478b4ec7997f6704860.tar.gz |
BASELINE: Update Chromium to 80.0.3987.136
Change-Id: I98e1649aafae85ba3a83e67af00bb27ef301db7b
Reviewed-by: Jüri Valdmann <juri.valdmann@qt.io>
Diffstat (limited to 'chromium/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.cc')
-rw-r--r-- | chromium/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.cc | 218 |
1 files changed, 139 insertions, 79 deletions
diff --git a/chromium/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.cc b/chromium/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.cc index 65b672a3573..261c1b0512d 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.cc +++ b/chromium/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.cc @@ -60,11 +60,11 @@ #include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h" #include "third_party/blink/renderer/platform/runtime_enabled_features.h" #include "third_party/blink/renderer/platform/wtf/functional.h" -#include "third_party/blink/renderer/platform/wtf/typed_arrays/array_buffer_contents.h" #include "third_party/skia/include/core/SkPixmap.h" #include "third_party/skia/include/core/SkSurface.h" #include "third_party/skia/include/gpu/GrContext.h" #include "third_party/skia/include/gpu/gl/GrGLTypes.h" +#include "ui/gl/gpu_preference.h" #include "v8/include/v8.h" namespace blink { @@ -91,7 +91,8 @@ scoped_refptr<DrawingBuffer> DrawingBuffer::Create( PreserveDrawingBuffer preserve, WebGLVersion webgl_version, ChromiumImageUsage chromium_image_usage, - const CanvasColorParams& color_params) { + const CanvasColorParams& color_params, + gl::GpuPreference gpu_preference) { if (g_should_fail_drawing_buffer_creation_for_testing) { g_should_fail_drawing_buffer_creation_for_testing = false; return nullptr; @@ -142,7 +143,7 @@ scoped_refptr<DrawingBuffer> DrawingBuffer::Create( std::move(extensions_util), client, discard_framebuffer_supported, want_alpha_channel, premultiplied_alpha, preserve, webgl_version, want_depth_buffer, want_stencil_buffer, chromium_image_usage, - color_params)); + color_params, gpu_preference)); if (!drawing_buffer->Initialize(size, multisample_supported)) { drawing_buffer->BeginDestruction(); return scoped_refptr<DrawingBuffer>(); @@ -168,7 +169,8 @@ DrawingBuffer::DrawingBuffer( bool want_depth, bool want_stencil, ChromiumImageUsage chromium_image_usage, - const CanvasColorParams& color_params) + const CanvasColorParams& color_params, + gl::GpuPreference gpu_preference) : client_(client), preserve_drawing_buffer_(preserve), webgl_version_(webgl_version), @@ -186,13 +188,18 @@ DrawingBuffer::DrawingBuffer( storage_color_space_(color_params.GetStorageGfxColorSpace()), sampler_color_space_(color_params.GetSamplerGfxColorSpace()), use_half_float_storage_(color_params.PixelFormat() == - kF16CanvasPixelFormat), + CanvasPixelFormat::kF16), chromium_image_usage_(chromium_image_usage), opengl_flip_y_extension_( - ContextProvider()->GetCapabilities().mesa_framebuffer_flip_y) { + ContextProvider()->GetCapabilities().mesa_framebuffer_flip_y), + initial_gpu_(gpu_preference), + current_active_gpu_(gpu_preference) { // Used by browser tests to detect the use of a DrawingBuffer. TRACE_EVENT_INSTANT0("test_gpu", "DrawingBufferCreation", TRACE_EVENT_SCOPE_GLOBAL); + // PowerPreferenceToGpuPreference should have resolved the meaning + // of the "default" GPU already. + DCHECK(gpu_preference != gl::GpuPreference::kDefault); } DrawingBuffer::~DrawingBuffer() { @@ -247,7 +254,7 @@ DrawingBuffer::ContextProviderWeakPtr() { return context_provider_->GetWeakPtr(); } -void DrawingBuffer::SetIsHidden(bool hidden) { +void DrawingBuffer::SetIsInHiddenPage(bool hidden) { if (is_hidden_ == hidden) return; is_hidden_ = hidden; @@ -346,15 +353,15 @@ bool DrawingBuffer::PrepareTransferableResourceInternal( ResolveIfNeeded(); if (!using_gpu_compositing_ && !force_gpu_result) { - FinishPrepareTransferableResourceSoftware(bitmap_registrar, out_resource, - out_release_callback); - } else { - FinishPrepareTransferableResourceGpu(out_resource, out_release_callback); + return FinishPrepareTransferableResourceSoftware( + bitmap_registrar, out_resource, out_release_callback); } - return true; + + return FinishPrepareTransferableResourceGpu(out_resource, + out_release_callback); } -void DrawingBuffer::FinishPrepareTransferableResourceSoftware( +bool DrawingBuffer::FinishPrepareTransferableResourceSoftware( cc::SharedBitmapIdRegistrar* bitmap_registrar, viz::TransferableResource* out_resource, std::unique_ptr<viz::SingleReleaseCallback>* out_release_callback) { @@ -392,9 +399,10 @@ void DrawingBuffer::FinishPrepareTransferableResourceSoftware( *out_release_callback = viz::SingleReleaseCallback::Create(std::move(func)); ResetBuffersToAutoClear(); + return true; } -void DrawingBuffer::FinishPrepareTransferableResourceGpu( +bool DrawingBuffer::FinishPrepareTransferableResourceGpu( viz::TransferableResource* out_resource, std::unique_ptr<viz::SingleReleaseCallback>* out_release_callback) { DCHECK(state_restorer_); @@ -420,6 +428,10 @@ void DrawingBuffer::FinishPrepareTransferableResourceGpu( // into the mailbox, and allocate (or recycle) a new backbuffer. color_buffer_for_mailbox = back_color_buffer_; back_color_buffer_ = CreateOrRecycleColorBuffer(); + if (!back_color_buffer_) { + // Context is likely lost. + return false; + } AttachColorBufferToReadFramebuffer(); // Explicitly specify that m_fbo (which is now bound to the just-allocated @@ -438,6 +450,10 @@ void DrawingBuffer::FinishPrepareTransferableResourceGpu( // TODO(sunnyps): We can skip this test if explicit resolve is used since // we'll render to the multisample fbo which will be preserved. color_buffer_for_mailbox = CreateOrRecycleColorBuffer(); + if (!color_buffer_for_mailbox) { + // Context is likely lost. + return false; + } gl_->CopySubTextureCHROMIUM( back_color_buffer_->texture_id, 0, texture_target_, color_buffer_for_mailbox->texture_id, 0, 0, 0, 0, 0, size_.Width(), @@ -499,6 +515,7 @@ void DrawingBuffer::FinishPrepareTransferableResourceGpu( contents_changed_ = false; ResetBuffersToAutoClear(); + return true; } void DrawingBuffer::MailboxReleasedGpu(scoped_refptr<ColorBuffer> color_buffer, @@ -562,7 +579,8 @@ scoped_refptr<StaticBitmapImage> DrawingBuffer::TransferToStaticBitmapImage( SkBitmap black_bitmap; black_bitmap.allocN32Pixels(size_.Width(), size_.Height()); black_bitmap.eraseARGB(0, 0, 0, 0); - return StaticBitmapImage::Create(SkImage::MakeFromBitmap(black_bitmap)); + return UnacceleratedStaticBitmapImage::Create( + SkImage::MakeFromBitmap(black_bitmap)); } DCHECK_EQ(size_.Width(), transferable_resource.size.width()); @@ -646,12 +664,17 @@ DrawingBuffer::ScopedRGBEmulationForBlitFramebuffer:: scoped_refptr<CanvasResource> DrawingBuffer::AsCanvasResource( base::WeakPtr<CanvasResourceProvider> resource_provider) { + // Swap chain must be presented before resource is exported. + ResolveAndPresentSwapChainIfNeeded(); + scoped_refptr<ColorBuffer> canvas_resource_buffer = UsingSwapChain() ? front_color_buffer_ : back_color_buffer_; + return ExternalCanvasResource::Create( canvas_resource_buffer->mailbox, canvas_resource_buffer->size, texture_target_, CanvasColorParams(), context_provider_->GetWeakPtr(), - resource_provider, kLow_SkFilterQuality); + resource_provider, kLow_SkFilterQuality, + /*is_origin_top_left=*/opengl_flip_y_extension_); } DrawingBuffer::ColorBuffer::ColorBuffer( @@ -719,18 +742,11 @@ bool DrawingBuffer::Initialize(const IntSize& size, bool use_multisampling) { bool supports_implicit_resolve = !UsingSwapChain() && extensions_util_->SupportsExtension( "GL_EXT_multisampled_render_to_texture"); - bool supports_screen_space_aa = - !UsingSwapChain() && extensions_util_->SupportsExtension( - "GL_CHROMIUM_screen_space_antialiasing"); if (webgl_preferences.anti_aliasing_mode == kAntialiasingModeUnspecified) { if (use_multisampling) { anti_aliasing_mode_ = kAntialiasingModeMSAAExplicitResolve; if (supports_implicit_resolve) { anti_aliasing_mode_ = kAntialiasingModeMSAAImplicitResolve; - } else if (supports_screen_space_aa && - ContextProvider()->GetGpuFeatureInfo().IsWorkaroundEnabled( - gpu::USE_FRAMEBUFFER_CMAA)) { - anti_aliasing_mode_ = kAntialiasingModeScreenSpaceAntialiasing; } } else { anti_aliasing_mode_ = kAntialiasingModeNone; @@ -738,26 +754,13 @@ bool DrawingBuffer::Initialize(const IntSize& size, bool use_multisampling) { } else { bool prefer_implicit_resolve = (webgl_preferences.anti_aliasing_mode == kAntialiasingModeMSAAImplicitResolve); - bool prefer_screen_space_aa = (webgl_preferences.anti_aliasing_mode == - kAntialiasingModeScreenSpaceAntialiasing); - if ((prefer_implicit_resolve && !supports_implicit_resolve) || - (prefer_screen_space_aa && !supports_screen_space_aa)) { + if (prefer_implicit_resolve && !supports_implicit_resolve) { DLOG(ERROR) << "Invalid anti-aliasing mode specified."; return false; } anti_aliasing_mode_ = webgl_preferences.anti_aliasing_mode; } - // TODO(dshwang): Enable storage textures on all platforms. crbug.com/557848 - // The Linux ATI bot fails - // WebglConformance.conformance_textures_misc_tex_image_webgl, so use storage - // textures only if ScreenSpaceAntialiasing is enabled, because - // ScreenSpaceAntialiasing is much faster with storage textures. - storage_texture_supported_ = - (webgl_version_ > kWebGL1 || - extensions_util_->SupportsExtension("GL_EXT_texture_storage")) && - anti_aliasing_mode_ == kAntialiasingModeScreenSpaceAntialiasing; - sample_count_ = std::min( static_cast<int>(webgl_preferences.msaa_sample_count), max_sample_count); eqaa_storage_sample_count_ = webgl_preferences.eqaa_storage_sample_count; @@ -1110,22 +1113,49 @@ bool DrawingBuffer::ResizeDefaultFramebuffer(const IntSize& size) { void DrawingBuffer::ClearFramebuffers(GLbitfield clear_mask) { ScopedStateRestorer scoped_state_restorer(this); - ClearFramebuffersInternal(clear_mask); + ClearFramebuffersInternal(clear_mask, ClearAllFBOs); } -void DrawingBuffer::ClearFramebuffersInternal(GLbitfield clear_mask) { +void DrawingBuffer::ClearFramebuffersInternal(GLbitfield clear_mask, + ClearOption clear_option) { DCHECK(state_restorer_); state_restorer_->SetFramebufferBindingDirty(); - // We will clear the multisample FBO, but we also need to clear the - // non-multisampled buffer. - if (multisample_fbo_) { + // Clear the multisample FBO, but also clear the non-multisampled buffer if + // requested. + if (multisample_fbo_ && clear_option == ClearAllFBOs) { gl_->BindFramebuffer(GL_FRAMEBUFFER, fbo_); gl_->Clear(GL_COLOR_BUFFER_BIT); } - gl_->BindFramebuffer(GL_FRAMEBUFFER, - multisample_fbo_ ? multisample_fbo_ : fbo_); - gl_->Clear(clear_mask); + if (multisample_fbo_ || clear_option == ClearAllFBOs) { + gl_->BindFramebuffer(GL_FRAMEBUFFER, + multisample_fbo_ ? multisample_fbo_ : fbo_); + gl_->Clear(clear_mask); + } +} + +void DrawingBuffer::ClearNewlyAllocatedFramebuffers(ClearOption clear_option) { + DCHECK(state_restorer_); + + state_restorer_->SetClearStateDirty(); + gl_->Disable(GL_SCISSOR_TEST); + gl_->ClearColor(0, 0, 0, + DefaultBufferRequiresAlphaChannelToBePreserved() ? 1 : 0); + gl_->ColorMask(true, true, true, true); + + GLbitfield clear_mask = GL_COLOR_BUFFER_BIT; + if (!!depth_stencil_buffer_) { + gl_->ClearDepthf(1.0f); + clear_mask |= GL_DEPTH_BUFFER_BIT; + gl_->DepthMask(true); + } + if (!!depth_stencil_buffer_) { + gl_->ClearStencil(0); + clear_mask |= GL_STENCIL_BUFFER_BIT; + gl_->StencilMaskSeparate(GL_FRONT, 0xFFFFFFFF); + } + + ClearFramebuffersInternal(clear_mask, clear_option); } IntSize DrawingBuffer::AdjustSize(const IntSize& desired_size, @@ -1175,25 +1205,7 @@ bool DrawingBuffer::ResizeFramebufferInternal(const IntSize& new_size) { return false; } - state_restorer_->SetClearStateDirty(); - gl_->Disable(GL_SCISSOR_TEST); - gl_->ClearColor(0, 0, 0, - DefaultBufferRequiresAlphaChannelToBePreserved() ? 1 : 0); - gl_->ColorMask(true, true, true, true); - - GLbitfield clear_mask = GL_COLOR_BUFFER_BIT; - if (!!depth_stencil_buffer_) { - gl_->ClearDepthf(1.0f); - clear_mask |= GL_DEPTH_BUFFER_BIT; - gl_->DepthMask(true); - } - if (!!depth_stencil_buffer_) { - gl_->ClearStencil(0); - clear_mask |= GL_STENCIL_BUFFER_BIT; - gl_->StencilMaskSeparate(GL_FRONT, 0xFFFFFFFF); - } - - ClearFramebuffersInternal(clear_mask); + ClearNewlyAllocatedFramebuffers(ClearAllFBOs); return true; } @@ -1235,8 +1247,6 @@ void DrawingBuffer::ResolveMultisampleFramebufferInternal() { } gl_->BindFramebuffer(GL_FRAMEBUFFER, fbo_); - if (anti_aliasing_mode_ == kAntialiasingModeScreenSpaceAntialiasing) - gl_->ApplyScreenSpaceAntialiasingCHROMIUM(); } void DrawingBuffer::ResolveIfNeeded() { @@ -1246,13 +1256,57 @@ void DrawingBuffer::ResolveIfNeeded() { contents_change_resolved_ = true; auto* gl = ContextProvider()->ContextGL(); - if (gl->DidGpuSwitch() == GL_TRUE) { - // TODO(crbug.com/681341): handle preserveDrawingBuffer:true, and - // user-allocated multisampled renderbuffers, by dispatching a context lost - // event. - if (WantExplicitResolve()) { - ReallocateMultisampleRenderbuffer(size_); + gl::GpuPreference active_gpu = gl::GpuPreference::kDefault; + if (gl->DidGpuSwitch(&active_gpu) == GL_TRUE) { + // This code path is mainly taken on macOS (the only platform which, as of + // this writing, dispatches the GPU-switched notifications), and the + // comments below focus only on macOS. + // + // The code below attempts to deduce whether, if a GPU switch occurred, + // it's really necessary to lose the context because certain GPU resources + // are no longer accessible. Resources only become inaccessible if + // CGLSetVirtualScreen is explicitly called against a GL context to change + // its renderer ID. GPU switching notifications are highly asynchronous. + // + // The tests below, of the initial and currently active GPU, replicate + // some logic in GLContextCGL::ForceGpuSwitchIfNeeded. Basically, if a + // context requests the high-performance GPU, then CGLSetVirtualScreen + // will never be called to migrate that context to the low-power + // GPU. However, contexts that were allocated on the integrated GPU will + // be migrated to the discrete GPU, and back, when the discrete GPU is + // activated and deactivated. Also, if the high-performance GPU was + // requested, then that request took effect during context bringup, even + // though the GPU switching notification is generally dispatched a couple + // of seconds after that, so it's not necessary to either lose the context + // or reallocate the multisampled renderbuffers when that initial + // notification is received. + if (initial_gpu_ == gl::GpuPreference::kLowPower && + current_active_gpu_ != active_gpu) { + if ((WantExplicitResolve() && preserve_drawing_buffer_ == kPreserve) || + client_ + ->DrawingBufferClientUserAllocatedMultisampledRenderbuffers()) { + // In these situations there are multisampled renderbuffers whose + // content the application expects to be preserved, but which can not + // be. Forcing a lost context is the only option to keep applications + // rendering correctly. + client_->DrawingBufferClientForceLostContextWithAutoRecovery(); + } else if (WantExplicitResolve()) { + ReallocateMultisampleRenderbuffer(size_); + + // This does a bit more work than desired - clearing any depth and + // stencil renderbuffers is unnecessary, since they weren't reallocated + // - but reusing this code reduces complexity. Note that we do not clear + // the non-multisampled framebuffer, as doing so can cause users' + // content to disappear unexpectedly. + // + // TODO(crbug.com/1046146): perform this clear at the beginning rather + // than at the end of a frame in order to eliminate rendering glitches. + // This should also simplify the code, allowing removal of the + // ClearOption. + ClearNewlyAllocatedFramebuffers(ClearOnlyMultisampledFBO); + } } + current_active_gpu_ = active_gpu; } } @@ -1433,16 +1487,18 @@ void DrawingBuffer::FlipVertically(uint8_t* framebuffer, } } -void DrawingBuffer::PresentSwapChain() { - DCHECK(UsingSwapChain()); - DCHECK_EQ(texture_target_, static_cast<unsigned>(GL_TEXTURE_2D)); - +void DrawingBuffer::ResolveAndPresentSwapChainIfNeeded() { if (!contents_changed_) return; ScopedStateRestorer scoped_state_restorer(this); ResolveIfNeeded(); + if (!UsingSwapChain()) + return; + + DCHECK_EQ(texture_target_, static_cast<unsigned>(GL_TEXTURE_2D)); + if (premultiplied_alpha_false_texture_) { // The rendering results are in |premultiplied_alpha_false_texture_| rather // than the |back_color_buffer_|'s texture. Copy them in, multiplying the @@ -1480,6 +1536,11 @@ void DrawingBuffer::PresentSwapChain() { scoped_refptr<DrawingBuffer::ColorBuffer> DrawingBuffer::CreateColorBuffer( const IntSize& size) { + if (size.IsEmpty()) { + // Context is likely lost. + return nullptr; + } + DCHECK(state_restorer_); state_restorer_->SetFramebufferBindingDirty(); state_restorer_->SetTextureBindingDirty(); @@ -1567,9 +1628,8 @@ scoped_refptr<DrawingBuffer::ColorBuffer> DrawingBuffer::CreateColorBuffer( gl_->BeginSharedImageAccessDirectCHROMIUM( texture_id, GL_SHARED_IMAGE_ACCESS_MODE_READWRITE_CHROMIUM); - // Clear the alpha channel if we allocated a GpuMemoryBuffer and RGB emulation - // is required. - if (gpu_memory_buffer && !want_alpha_channel_ && have_alpha_channel_) { + // Clear the alpha channel if RGB emulation is required. + if (!want_alpha_channel_ && have_alpha_channel_) { GLuint fbo = 0; state_restorer_->SetClearStateDirty(); |