From b94a40ad582a579c0dd1f409ef7c65cc32c036dd Mon Sep 17 00:00:00 2001 From: Jonah Chin Date: Thu, 20 Feb 2020 20:03:09 +0000 Subject: [PATCH] Revert "Add a PaintRecorder to CanvasResourceProvider" This reverts commit 2a3b118991ac0ddd19d5bd5eacb150fc82a6f6b1. Reason for revert: crbug.com/1054408 Original change's description: > Add a PaintRecorder to CanvasResourceProvider > > This CL is the first step in creating a PaintRecord backed resource > provider for canvas OOP-R. > > Changes of ownership: > - PaintRecorder entirely moved from Canvas2DLayerBridge to > CanvasResourceProvider. > - Management of needs_flush_ for MemoryManagedPaintRecorder moved to > CanvasResourceProvider. > - RestoreCanvasMatrixClipStack logic centralized to CanvasResourceHost > and can be accessed via callback > - Backing SkiaPaintCanvas now private to CanvasResourceProvider with no > external access. Any users of the backing SkiaPaintCanvas in > Canvas2DLayerBridge had their functionality moved to > CanvasResourceProvider (ie. new RestoreBackBuffer() function) > > Updates to test files: > - Addition of explicit FlushCanvas() calls in tests that used to expect > SkiaPaintCanvas to immediately update. > - Some tests expected the CanvasResourceProvider to be created on first > draw. This expectation has been changed since the > CanvasResourceProvider now gets set up on SetCanvasResourceHost(). > > Other new functionality: > - Display Item List now has a bit that tracks if it contains any draw > operations. This is used to see if there are draw ops to flush. > > Bug: 1019288 > Change-Id: I717b18e22d6699dc876d8f8121a25d147738579d > Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1891292 > Commit-Queue: Khushal > Reviewed-by: Aaron Krajeski > Reviewed-by: Juanmi Huertas > Reviewed-by: Fernando Serboncini > Reviewed-by: Khushal > Cr-Commit-Position: refs/heads/master@{#743002} TBR=senorblanco@chromium.org,fserb@chromium.org,khushalsagar@chromium.org,aaronhk@chromium.org,juanmihd@chromium.org,jochin@microsoft.com Change-Id: Icd1e97d26d3b4b46598f02c03b163ba31a1c2881 No-Presubmit: true No-Tree-Checks: true No-Try: true Bug: 1019288 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2067239 Reviewed-by: Fernando Serboncini Commit-Queue: Jonah Chin Cr-Commit-Position: refs/heads/master@{#743213} --- cc/paint/display_item_list.cc | 1 - cc/paint/display_item_list.h | 4 - cc/paint/paint_recorder.cc | 4 - cc/paint/paint_recorder.h | 2 - .../core/html/canvas/html_canvas_element.cc | 24 ++-- .../canvas2d/base_rendering_context_2d.cc | 6 +- .../canvas2d/canvas_rendering_context_2d.cc | 6 +- .../canvas_rendering_context_2d_test.cc | 16 ++- .../offscreen_canvas_rendering_context_2d.cc | 66 ++++++++--- .../offscreen_canvas_rendering_context_2d.h | 9 +- .../graphics/canvas_2d_layer_bridge.cc | 103 ++++++++++++------ .../graphics/canvas_2d_layer_bridge.h | 29 +++-- .../graphics/canvas_2d_layer_bridge_test.cc | 60 +++++----- .../platform/graphics/canvas_resource_host.cc | 17 --- .../platform/graphics/canvas_resource_host.h | 2 - .../graphics/canvas_resource_provider.cc | 83 ++++---------- .../graphics/canvas_resource_provider.h | 23 +--- .../graphics/canvas_resource_provider_test.cc | 2 - 18 files changed, 213 insertions(+), 244 deletions(-) diff --git a/cc/paint/display_item_list.cc b/cc/paint/display_item_list.cc index 9429fef1569657..2c665340219a57 100644 --- a/cc/paint/display_item_list.cc +++ b/cc/paint/display_item_list.cc @@ -241,7 +241,6 @@ void DisplayItemList::Reset() { offsets_.shrink_to_fit(); begin_paired_indices_.clear(); begin_paired_indices_.shrink_to_fit(); - has_draw_ops_ = false; } sk_sp DisplayItemList::ReleaseAsRecord() { diff --git a/cc/paint/display_item_list.h b/cc/paint/display_item_list.h index 7a7718168d55bb..eefd3b69040136 100644 --- a/cc/paint/display_item_list.h +++ b/cc/paint/display_item_list.h @@ -87,8 +87,6 @@ class CC_PAINT_EXPORT DisplayItemList if (usage_hint_ == kTopLevelDisplayItemList) offsets_.push_back(offset); const T* op = paint_op_buffer_.push(std::forward(args)...); - if (op->IsDrawOp()) - has_draw_ops_ = true; DCHECK(op->IsValid()); return offset; } @@ -199,7 +197,6 @@ class CC_PAINT_EXPORT DisplayItemList int max_ops_to_analyze = 1); std::string ToString() const; - bool has_draw_ops() const { return has_draw_ops_; } private: friend class DisplayItemListTest; @@ -249,7 +246,6 @@ class CC_PAINT_EXPORT DisplayItemList #endif UsageHint usage_hint_; - bool has_draw_ops_ = false; friend class base::RefCountedThreadSafe; FRIEND_TEST_ALL_PREFIXES(DisplayItemListTest, BytesUsed); diff --git a/cc/paint/paint_recorder.cc b/cc/paint/paint_recorder.cc index 1fb95143f49a49..08f0bd9417fc8b 100644 --- a/cc/paint/paint_recorder.cc +++ b/cc/paint/paint_recorder.cc @@ -47,8 +47,4 @@ std::unique_ptr PaintRecorder::CreateCanvas( return std::make_unique(list, bounds); } -bool PaintRecorder::ListHasDrawOps() const { - return display_item_list_->has_draw_ops(); -} - } // namespace cc diff --git a/cc/paint/paint_recorder.h b/cc/paint/paint_recorder.h index 6beb024c236987..b57fcb239113e5 100644 --- a/cc/paint/paint_recorder.h +++ b/cc/paint/paint_recorder.h @@ -37,8 +37,6 @@ class CC_PAINT_EXPORT PaintRecorder { sk_sp finishRecordingAsPicture(); - bool ListHasDrawOps() const; - protected: virtual std::unique_ptr CreateCanvas(DisplayItemList* list, const SkRect& bounds); diff --git a/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc b/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc index 9d6cf1ea388a7f..967ff28ec04a5b 100644 --- a/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc +++ b/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc @@ -140,11 +140,11 @@ void HTMLCanvasElement::Dispose() { if (context_) { UMA_HISTOGRAM_BOOLEAN("Blink.Canvas.HasRendered", bool(ResourceProvider())); - if (context_->Host()) { + if (ResourceProvider()) { UMA_HISTOGRAM_BOOLEAN("Blink.Canvas.IsComposited", context_->IsComposited()); - context_->DetachHost(); } + context_->DetachHost(); context_ = nullptr; } @@ -1506,30 +1506,20 @@ void HTMLCanvasElement::ReplaceExisting2dLayerBridge( if (canvas2d_bridge_) { image = canvas2d_bridge_->NewImageSnapshot(kPreferNoAcceleration); // image can be null if allocation failed in which case we should just - // abort the surface switch to retain the old surface which is still + // abort the surface switch to reatain the old surface which is still // functional. if (!image) return; } + new_layer_bridge->SetCanvasResourceHost(this); ReplaceResourceProvider(nullptr); canvas2d_bridge_ = std::move(new_layer_bridge); - canvas2d_bridge_->SetCanvasResourceHost(this); - - cc::PaintCanvas* canvas = canvas2d_bridge_->GetPaintCanvas(); - // Paint canvas automatically has the clip re-applied. Since image already - // contains clip, it needs to be drawn before the clip stack is re-applied. - // Remove clip from canvas and restore it after the image is drawn. - canvas->restoreToCount(1); - canvas->save(); - - // TODO(jochin): Consider using ResourceProvider()->RestoreBackBuffer() here - // to avoid all of this clip stack manipulation. if (image) canvas2d_bridge_->DrawFullImage(image->PaintImageForCurrentFrame()); - RestoreCanvasMatrixClipStack(canvas); - canvas2d_bridge_->DidRestoreCanvasMatrixClipStack(canvas); - + RestoreCanvasMatrixClipStack(canvas2d_bridge_->GetPaintCanvas()); + canvas2d_bridge_->DidRestoreCanvasMatrixClipStack( + canvas2d_bridge_->GetPaintCanvas()); UpdateMemoryUsage(); } diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.cc b/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.cc index 5b176570083022..7b0b4bfa2a7305 100644 --- a/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.cc +++ b/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.cc @@ -50,11 +50,6 @@ void BaseRenderingContext2D::RealizeSaves() { ValidateStateStack(); if (GetState().HasUnrealizedSaves()) { DCHECK_GE(state_stack_.size(), 1u); - // GetOrCreatePaintCanvas() can call RestoreMatrixClipStack which syncs - // canvas to state_stack_. Get the canvas before adjusting state_stack_ to - // ensure canvas is synced prior to adjusting state_stack_. - cc::PaintCanvas* canvas = GetOrCreatePaintCanvas(); - // Reduce the current state's unrealized count by one now, // to reflect the fact we are saving one state. state_stack_.back()->Restore(); @@ -67,6 +62,7 @@ void BaseRenderingContext2D::RealizeSaves() { // state (in turn necessary to support correct resizing and unwinding of the // stack). state_stack_.back()->ResetUnrealizedSaveCount(); + cc::PaintCanvas* canvas = GetOrCreatePaintCanvas(); if (canvas) canvas->save(); ValidateStateStack(); diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.cc b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.cc index d56313c7eac0cf..02caa1db2c01f9 100644 --- a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.cc +++ b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.cc @@ -441,14 +441,14 @@ cc::PaintCanvas* CanvasRenderingContext2D::GetOrCreatePaintCanvas() { if (isContextLost()) return nullptr; if (canvas()->GetOrCreateCanvas2DLayerBridge()) - return canvas()->GetCanvas2DLayerBridge()->GetPaintCanvas(); + return GetPaintCanvas(); return nullptr; } cc::PaintCanvas* CanvasRenderingContext2D::GetPaintCanvas() const { - if (isContextLost() || !canvas()->GetCanvas2DLayerBridge()) + if (isContextLost()) return nullptr; - if (canvas() && canvas()->GetCanvas2DLayerBridge()->ResourceProvider()) + if (canvas() && canvas()->GetCanvas2DLayerBridge()) return canvas()->GetCanvas2DLayerBridge()->GetPaintCanvas(); return nullptr; } diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_test.cc b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_test.cc index bf6055d53f3c58..3b75ce5f944461 100644 --- a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_test.cc +++ b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_test.cc @@ -736,10 +736,13 @@ TEST_F(CanvasRenderingContext2DTest, size, CanvasColorParams(), kPreferNoAcceleration); fake_deaccelerate_surface->SetCanvasResourceHost(&host); + cc::PaintCanvas* paint_canvas_ptr = + fake_deaccelerate_surface->GetPaintCanvas(); FakeCanvas2DLayerBridge* surface_ptr = fake_deaccelerate_surface.get(); EXPECT_CALL(*fake_deaccelerate_surface, DrawFullImage(_)).Times(1); - EXPECT_CALL(*fake_deaccelerate_surface, DidRestoreCanvasMatrixClipStack(_)) + EXPECT_CALL(*fake_deaccelerate_surface, + DidRestoreCanvasMatrixClipStack(paint_canvas_ptr)) .Times(1); EXPECT_TRUE(CanvasElement().GetCanvas2DLayerBridge()->IsAccelerated()); @@ -1140,14 +1143,11 @@ TEST_F(CanvasRenderingContext2DTestAccelerated, CreateContext(kNonOpaque); IntSize size(300, 300); std::unique_ptr bridge = - std::make_unique( - size, Canvas2DLayerBridge::kEnableAcceleration, CanvasColorParams()); + MakeBridge(size, Canvas2DLayerBridge::kEnableAcceleration); // Force hibernatation to occur in an immediate task. bridge->DontUseIdleSchedulingForTesting(); CanvasElement().SetResourceProviderForTesting(nullptr, std::move(bridge), size); - CanvasElement().GetCanvas2DLayerBridge()->SetCanvasResourceHost( - canvas_element_); EXPECT_TRUE(CanvasElement().GetCanvas2DLayerBridge()->IsAccelerated()); // Take a snapshot to trigger lazy resource provider creation @@ -1188,14 +1188,12 @@ TEST_F(CanvasRenderingContext2DTestAccelerated, CreateContext(kNonOpaque); IntSize size(300, 300); std::unique_ptr bridge = - std::make_unique( - size, Canvas2DLayerBridge::kEnableAcceleration, CanvasColorParams()); + MakeBridge(size, Canvas2DLayerBridge::kEnableAcceleration); // Force hibernatation to occur in an immediate task. bridge->DontUseIdleSchedulingForTesting(); CanvasElement().SetResourceProviderForTesting(nullptr, std::move(bridge), size); - CanvasElement().GetCanvas2DLayerBridge()->SetCanvasResourceHost( - canvas_element_); + EXPECT_TRUE(CanvasElement().GetCanvas2DLayerBridge()->IsAccelerated()); EXPECT_TRUE(CanvasElement().GetLayoutBoxModelObject()); diff --git a/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.cc b/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.cc index 112234eb1618b0..811704201094e1 100644 --- a/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.cc +++ b/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.cc @@ -19,6 +19,7 @@ #include "third_party/blink/renderer/platform/fonts/text_run_paint_info.h" #include "third_party/blink/renderer/platform/graphics/canvas_resource_provider.h" #include "third_party/blink/renderer/platform/graphics/graphics_types.h" +#include "third_party/blink/renderer/platform/graphics/memory_managed_paint_recorder.h" #include "third_party/blink/renderer/platform/graphics/paint/paint_canvas.h" #include "third_party/blink/renderer/platform/graphics/skia/skia_utils.h" #include "third_party/blink/renderer/platform/graphics/static_bitmap_image.h" @@ -85,9 +86,20 @@ OffscreenCanvasRenderingContext2D::OffscreenCanvasRenderingContext2D( bernoulli_distribution_(kUMASampleProbability) { is_valid_size_ = IsValidImageSize(Host()->Size()); - // Clear the background transparent or opaque. + // A raw pointer is safe here because the callback is only used by the + // recorder_ + set_needs_flush_callback_ = + WTF::BindRepeating(&OffscreenCanvasRenderingContext2D::SetNeedsFlush, + WrapWeakPersistent(this)); + StartRecording(); + + // Clear the background transparent or opaque. Similar code at + // CanvasResourceProvider::Clear(). if (IsCanvas2DBufferValid()) { - GetOrCreateCanvasResourceProvider()->Clear(); + DCHECK(recorder_); + recorder_->getRecordingCanvas()->clear( + ColorParams().GetOpacityMode() == kOpaque ? SK_ColorBLACK + : SK_ColorTRANSPARENT); DidDraw(); } @@ -119,13 +131,29 @@ void OffscreenCanvasRenderingContext2D::commit() { GetOffscreenFontCache().PruneLocalFontCache(kMaxCachedFonts); } +void OffscreenCanvasRenderingContext2D::StartRecording() { + recorder_ = + std::make_unique(set_needs_flush_callback_); + cc::PaintCanvas* canvas = recorder_->beginRecording(Width(), Height()); + // Always save an initial frame, to support resetting the top level matrix + // and clip. + canvas->save(); + RestoreMatrixClipStack(canvas); +} + void OffscreenCanvasRenderingContext2D::FlushRecording() { if (!have_recorded_draw_commands_) return; - GetCanvasResourceProvider()->FlushCanvas(); + { // Make a new scope so that PaintRecord gets deleted and that gets timed + CanvasResourceProvider* resource_provider = GetCanvasResourceProvider(); + cc::PaintCanvas* canvas = resource_provider->Canvas(); + canvas->drawPicture(recorder_->finishRecordingAsPicture()); + resource_provider->FlushSkia(); + } GetCanvasResourceProvider()->ReleaseLockedImages(); + StartRecording(); have_recorded_draw_commands_ = false; } @@ -137,6 +165,7 @@ void OffscreenCanvasRenderingContext2D::FinalizeFrame() { if (!GetOrCreateCanvasResourceProvider()) return; FlushRecording(); + needs_flush_ = false; } // BaseRenderingContext2D implementation @@ -181,6 +210,7 @@ OffscreenCanvasRenderingContext2D::GetCanvasResourceProvider() const { void OffscreenCanvasRenderingContext2D::Reset() { Host()->DiscardResourceProvider(); BaseRenderingContext2D::Reset(); + StartRecording(); // Because the host may have changed to a zero size is_valid_size_ = IsValidImageSize(Host()->Size()); } @@ -232,7 +262,11 @@ ImageBitmap* OffscreenCanvasRenderingContext2D::TransferToImageBitmap( return nullptr; } } + + // "Transfer" means no retained buffer. Matrix transformations need to be + // preserved though. Host()->DiscardResourceProvider(); + RestoreMatrixClipStack(recorder_->getRecordingCanvas()); return MakeGarbageCollected(std::move(image)); } @@ -259,23 +293,17 @@ bool OffscreenCanvasRenderingContext2D::ParseColorOrCurrentColor( return ::blink::ParseColorOrCurrentColor(color, color_string, nullptr); } -cc::PaintCanvas* OffscreenCanvasRenderingContext2D::GetOrCreatePaintCanvas() { - if (!is_valid_size_ || !GetOrCreateCanvasResourceProvider()) - return nullptr; - return GetPaintCanvas(); -} - cc::PaintCanvas* OffscreenCanvasRenderingContext2D::GetPaintCanvas() const { - if (!is_valid_size_ || !GetCanvasResourceProvider()) + if (!is_valid_size_) return nullptr; - return GetCanvasResourceProvider()->Canvas(); + return recorder_->getRecordingCanvas(); } void OffscreenCanvasRenderingContext2D::DidDraw() { have_recorded_draw_commands_ = true; dirty_rect_for_commit_.setWH(Width(), Height()); Host()->DidDraw(); - if (GetCanvasResourceProvider() && GetCanvasResourceProvider()->needs_flush()) + if (needs_flush_) FinalizeFrame(); } @@ -283,7 +311,7 @@ void OffscreenCanvasRenderingContext2D::DidDraw(const SkIRect& dirty_rect) { have_recorded_draw_commands_ = true; dirty_rect_for_commit_.join(dirty_rect); Host()->DidDraw(SkRect::Make(dirty_rect_for_commit_)); - if (GetCanvasResourceProvider() && GetCanvasResourceProvider()->needs_flush()) + if (needs_flush_) FinalizeFrame(); } @@ -341,6 +369,13 @@ bool OffscreenCanvasRenderingContext2D::WritePixels( DCHECK(IsPaintable()); FinalizeFrame(); have_recorded_draw_commands_ = false; + // Add a save to initialize the transform/clip stack and then restore it after + // the draw. This is needed because each recording initializes and the resets + // this state after every flush. + cc::PaintCanvas* canvas = GetCanvasResourceProvider()->Canvas(); + PaintCanvasAutoRestore auto_restore(canvas, true); + if (GetOrCreateCanvasResourceProvider()) + RestoreMatrixClipStack(canvas); return offscreenCanvasForBinding()->ResourceProvider()->WritePixels( orig_info, pixels, row_bytes, x, y); @@ -503,7 +538,7 @@ void OffscreenCanvasRenderingContext2D::DrawTextInternal( double y, CanvasRenderingContext2DState::PaintType paint_type, double* max_width) { - cc::PaintCanvas* paint_canvas = GetOrCreatePaintCanvas(); + cc::PaintCanvas* paint_canvas = GetPaintCanvas(); if (!paint_canvas) return; @@ -613,4 +648,7 @@ bool OffscreenCanvasRenderingContext2D::IsCanvas2DBufferValid() const { return false; } +void OffscreenCanvasRenderingContext2D::SetNeedsFlush() { + needs_flush_ = true; +} } // namespace blink diff --git a/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.h b/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.h index b99acfdee6dda9..63fec778f45a3e 100644 --- a/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.h +++ b/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.h @@ -12,6 +12,7 @@ #include "third_party/blink/renderer/core/html/canvas/canvas_rendering_context.h" #include "third_party/blink/renderer/core/html/canvas/canvas_rendering_context_factory.h" #include "third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.h" +#include "third_party/blink/renderer/platform/graphics/paint/paint_recorder.h" namespace blink { @@ -106,7 +107,7 @@ class MODULES_EXPORT OffscreenCanvasRenderingContext2D final bool ParseColorOrCurrentColor(Color&, const String& color_string) const final; - cc::PaintCanvas* GetOrCreatePaintCanvas() final; + cc::PaintCanvas* GetOrCreatePaintCanvas() final { return GetPaintCanvas(); } cc::PaintCanvas* GetPaintCanvas() const final; void DidDraw() final; @@ -138,6 +139,8 @@ class MODULES_EXPORT OffscreenCanvasRenderingContext2D final int y) override; private: + void StartRecording(); + std::unique_ptr recorder_; bool have_recorded_draw_commands_; void FinalizeFrame() final; void FlushRecording(); @@ -162,6 +165,10 @@ class MODULES_EXPORT OffscreenCanvasRenderingContext2D final std::mt19937 random_generator_; std::bernoulli_distribution bernoulli_distribution_; + + void SetNeedsFlush(); + base::RepeatingClosure set_needs_flush_callback_; + bool needs_flush_ = false; }; } // namespace blink diff --git a/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.cc b/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.cc index b2b976a900f31c..96a6f667a43b20 100644 --- a/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.cc +++ b/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.cc @@ -46,6 +46,7 @@ #include "third_party/blink/renderer/platform/graphics/gpu/shared_context_rate_limiter.h" #include "third_party/blink/renderer/platform/graphics/gpu/shared_gpu_context.h" #include "third_party/blink/renderer/platform/graphics/graphics_layer.h" +#include "third_party/blink/renderer/platform/graphics/memory_managed_paint_recorder.h" #include "third_party/blink/renderer/platform/graphics/paint/paint_canvas.h" #include "third_party/blink/renderer/platform/graphics/static_bitmap_image.h" #include "third_party/blink/renderer/platform/graphics/unaccelerated_static_bitmap_image.h" @@ -123,6 +124,22 @@ Canvas2DLayerBridge::Canvas2DLayerBridge(const IntSize& size, // Used by browser tests to detect the use of a Canvas2DLayerBridge. TRACE_EVENT_INSTANT0("test_gpu", "Canvas2DLayerBridgeCreation", TRACE_EVENT_SCOPE_GLOBAL); + + // A raw pointer is safe here because the callback is only used by the + // |recorder_|. + set_needs_flush_callback_ = WTF::BindRepeating( + &Canvas2DLayerBridge::SetNeedsFlush, WTF::Unretained(this)); + StartRecording(); + + // Clear the background transparent or opaque. Similar code at + // CanvasResourceProvider::Clear(). + if (IsValid()) { + DCHECK(recorder_); + recorder_->getRecordingCanvas()->clear( + color_params_.GetOpacityMode() == kOpaque ? SK_ColorBLACK + : SK_ColorTRANSPARENT); + DidDraw(FloatRect(0.f, 0.f, size_.Width(), size_.Height())); + } } Canvas2DLayerBridge::~Canvas2DLayerBridge() { @@ -145,12 +162,18 @@ Canvas2DLayerBridge::~Canvas2DLayerBridge() { layer_ = nullptr; } -void Canvas2DLayerBridge::SetCanvasResourceHost(CanvasResourceHost* host) { - resource_host_ = host; +void Canvas2DLayerBridge::StartRecording() { + recorder_ = + std::make_unique(set_needs_flush_callback_); + cc::PaintCanvas* canvas = + recorder_->beginRecording(size_.Width(), size_.Height()); - if (resource_host_ && GetOrCreateResourceProvider()) { - EnsureCleared(); - } + // Always save an initial frame, to support resetting the top level matrix + // and clip. + canvas->save(); + + if (resource_host_) + resource_host_->RestoreCanvasMatrixClipStack(canvas); } void Canvas2DLayerBridge::ResetResourceProvider() { @@ -329,11 +352,9 @@ CanvasResourceProvider* Canvas2DLayerBridge::GetOrCreateResourceProvider( // circular callstack from HTMLCanvasElement. resource_provider = resource_host_->GetOrCreateCanvasResourceProviderImpl(adjusted_hint); - if (!resource_provider || !resource_provider->IsValid()) + if (!resource_provider) return nullptr; - EnsureCleared(); - if (IsAccelerated() && !layer_) { layer_ = cc::TextureLayer::CreateForMailbox(this); layer_->SetIsDrawable(true); @@ -371,11 +392,9 @@ CanvasResourceProvider* Canvas2DLayerBridge::GetOrCreateResourceProvider( return resource_provider; } -cc::PaintCanvas* Canvas2DLayerBridge::GetPaintCanvas() { +cc::PaintCanvas* Canvas2DLayerBridge::GetPaintCanvas() const { DCHECK(resource_host_); - if (GetOrCreateResourceProvider()) - return ResourceProvider()->Canvas(); - return nullptr; + return recorder_->getRecordingCanvas(); } void Canvas2DLayerBridge::UpdateFilterQuality() { @@ -472,6 +491,14 @@ bool Canvas2DLayerBridge::WritePixels(const SkImageInfo& orig_info, last_record_tainted_by_write_pixels_ = true; have_recorded_draw_commands_ = false; + // Apply clipstack to canvas_ and then restore it to original state once + // we leave this scope. This is needed because each recording initializes and + // resets this state after every flush. + cc::PaintCanvas* canvas = ResourceProvider()->Canvas(); + PaintCanvasAutoRestore auto_restore(canvas, true); + if (GetOrCreateResourceProvider()) { + resource_host_->RestoreCanvasMatrixClipStack(canvas); + } ResourceProvider()->WritePixels(orig_info, pixels, row_bytes, x, y); return true; @@ -479,7 +506,8 @@ bool Canvas2DLayerBridge::WritePixels(const SkImageInfo& orig_info, void Canvas2DLayerBridge::SkipQueuedDrawCommands() { if (have_recorded_draw_commands_) { - ResourceProvider()->SkipQueuedDrawCommands(); + recorder_->finishRecordingAsPicture(); + StartRecording(); have_recorded_draw_commands_ = false; } @@ -487,19 +515,8 @@ void Canvas2DLayerBridge::SkipQueuedDrawCommands() { rate_limiter_->Reset(); } -void Canvas2DLayerBridge::EnsureCleared() { - if (cleared_) - return; - cleared_ = true; - ResourceProvider()->Clear(); - DidDraw(FloatRect(0.f, 0.f, size_.Width(), size_.Height())); -} - -void Canvas2DLayerBridge::CalculateDirtyRegion() { - // 1 pixel is added around the rect for anti-alias effect - // TODO(khushalsagar) : Remove the need for this 1 pixel addition. - int canvas_width = size_.Width() + 1; - int canvas_height = size_.Height() + 1; +void Canvas2DLayerBridge::CalculateDirtyRegion(int canvas_width, + int canvas_height) { base::CheckedNumeric area(canvas_width); area *= canvas_height; if (!area.IsValid() || area.ValueOrDie() < kMinAreaForComputingDirtyRegion) @@ -639,15 +656,24 @@ void Canvas2DLayerBridge::FlushRecording() { } timer.emplace(); } + { // Make a new scope so that PaintRecord gets deleted and that gets timed + cc::PaintCanvas* canvas = ResourceProvider()->Canvas(); + last_recording_ = recorder_->finishRecordingAsPicture(); + SkScalar canvas_width = canvas->getLocalClipBounds().width(); + SkScalar canvas_height = canvas->getLocalClipBounds().height(); + DCHECK_GE(canvas_width, size_.Width()); + DCHECK_GE(canvas_height, size_.Height()); + if (will_measure) { + CalculateDirtyRegion(canvas_width, canvas_height); + } - ResourceProvider()->FlushCanvas(); - last_recording_ = ResourceProvider()->last_recording(); - if (last_recording_ && will_measure) - CalculateDirtyRegion(); - last_record_tainted_by_write_pixels_ = false; - if (!clear_frame_ || !resource_host_ || !resource_host_->IsPrinting()) { - last_recording_ = nullptr; - clear_frame_ = false; + canvas->drawPicture(last_recording_); + last_record_tainted_by_write_pixels_ = false; + if (!clear_frame_ || !resource_host_ || !resource_host_->IsPrinting()) { + last_recording_ = nullptr; + clear_frame_ = false; + } + ResourceProvider()->FlushSkia(); } // Finish up the timing operation @@ -671,6 +697,7 @@ void Canvas2DLayerBridge::FlushRecording() { if (GetOrCreateResourceProvider()) ResourceProvider()->ReleaseLockedImages(); + StartRecording(); have_recorded_draw_commands_ = false; } @@ -792,7 +819,7 @@ cc::Layer* Canvas2DLayerBridge::Layer() { } void Canvas2DLayerBridge::DidDraw(const FloatRect& /* rect */) { - if (ResourceProvider() && ResourceProvider()->needs_flush()) + if (needs_flush_) FinalizeFrame(); have_recorded_draw_commands_ = true; } @@ -821,6 +848,8 @@ void Canvas2DLayerBridge::FinalizeFrame() { if (rate_limiter_) rate_limiter_->Tick(); + + needs_flush_ = false; } void Canvas2DLayerBridge::DoPaintInvalidation(const FloatRect& dirty_rect) { @@ -851,6 +880,10 @@ void Canvas2DLayerBridge::WillOverwriteCanvas() { SkipQueuedDrawCommands(); } +void Canvas2DLayerBridge::SetNeedsFlush() { + needs_flush_ = true; +} + void Canvas2DLayerBridge::Logger::ReportHibernationEvent( HibernationEvent event) { UMA_HISTOGRAM_ENUMERATION("Blink.Canvas.HibernationEvents", event); diff --git a/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.h b/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.h index d295f573880099..6b39d2a4ac37d2 100644 --- a/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.h +++ b/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.h @@ -45,6 +45,7 @@ #include "third_party/blink/renderer/platform/graphics/canvas_color_params.h" #include "third_party/blink/renderer/platform/graphics/canvas_resource_host.h" #include "third_party/blink/renderer/platform/graphics/graphics_types.h" +#include "third_party/blink/renderer/platform/graphics/paint/paint_recorder.h" #include "third_party/blink/renderer/platform/platform_export.h" #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" #include "third_party/blink/renderer/platform/wtf/deque.h" @@ -113,8 +114,7 @@ class PLATFORM_EXPORT Canvas2DLayerBridge : public cc::TextureLayerClient { virtual void DidRestoreCanvasMatrixClipStack(cc::PaintCanvas*) {} virtual bool IsAccelerated() const; - // This may recreate CanvasResourceProvider - cc::PaintCanvas* GetPaintCanvas(); + cc::PaintCanvas* GetPaintCanvas() const; bool IsValid(); bool WritePixels(const SkImageInfo&, const void* pixels, @@ -124,7 +124,9 @@ class PLATFORM_EXPORT Canvas2DLayerBridge : public cc::TextureLayerClient { void DontUseIdleSchedulingForTesting() { dont_use_idle_scheduling_for_testing_ = true; } - void SetCanvasResourceHost(CanvasResourceHost* host); + void SetCanvasResourceHost(CanvasResourceHost* host) { + resource_host_ = host; + } void Hibernate(); bool IsHibernating() const { return hibernation_image_ != nullptr; } @@ -136,6 +138,14 @@ class PLATFORM_EXPORT Canvas2DLayerBridge : public cc::TextureLayerClient { cc::TextureLayer* layer_for_testing() { return layer_.get(); } + // TODO(jochin): Remove this function completely once recorder_ has been + // moved into CanvasResourceProvider. + sk_sp record_for_testing() { + sk_sp record = recorder_->finishRecordingAsPicture(); + StartRecording(); + return record; + } + // The values of the enum entries must not change because they are used for // usage metrics histograms. New values can be added to the end. enum HibernationEvent { @@ -189,12 +199,13 @@ class PLATFORM_EXPORT Canvas2DLayerBridge : public cc::TextureLayerClient { bool CheckResourceProviderValid(); void ResetResourceProvider(); + void StartRecording(); void SkipQueuedDrawCommands(); - void EnsureCleared(); bool ShouldAccelerate(AccelerationHint) const; - void CalculateDirtyRegion(); + void CalculateDirtyRegion(int canvas_width, int canvas_height); + std::unique_ptr recorder_; sk_sp hibernation_image_; scoped_refptr layer_; std::unique_ptr rate_limiter_; @@ -245,12 +256,12 @@ class PLATFORM_EXPORT Canvas2DLayerBridge : public cc::TextureLayerClient { Deque pending_raster_timers_; sk_sp last_recording_; - - // This tracks whether the canvas has been cleared once after - // this bridge was created. - bool cleared_ = false; cc::InvalidationRegion dirty_invalidate_region_; + void SetNeedsFlush(); + base::RepeatingClosure set_needs_flush_callback_; + bool needs_flush_ = false; + base::WeakPtrFactory weak_ptr_factory_{this}; DISALLOW_COPY_AND_ASSIGN(Canvas2DLayerBridge); diff --git a/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge_test.cc b/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge_test.cc index 7c955f9c3660bb..a8ed0b5cd3c17c 100644 --- a/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge_test.cc +++ b/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge_test.cc @@ -360,13 +360,6 @@ TEST_F(Canvas2DLayerBridgeTest, FallbackToSoftwareIfContextLost) { EXPECT_FALSE(bridge->IsAccelerated()); } -void DrawSomething(Canvas2DLayerBridge* bridge) { - bridge->DidDraw(FloatRect(0, 0, 1, 1)); - bridge->FinalizeFrame(); - // Grabbing an image forces a flush - bridge->NewImageSnapshot(kPreferAcceleration); -} - TEST_F(Canvas2DLayerBridgeTest, FallbackToSoftwareOnFailedTextureAlloc) { { // No fallback case. @@ -387,19 +380,14 @@ TEST_F(Canvas2DLayerBridgeTest, FallbackToSoftwareOnFailedTextureAlloc) { ->ContextProvider() ->GetGrContext(); std::unique_ptr bridge = - std::make_unique( - IntSize(300, 150), Canvas2DLayerBridge::kEnableAcceleration, - CanvasColorParams()); - bridge->DontUseIdleSchedulingForTesting(); + MakeBridge(IntSize(300, 150), Canvas2DLayerBridge::kEnableAcceleration, + CanvasColorParams()); EXPECT_TRUE(bridge->IsValid()); EXPECT_TRUE(bridge->IsAccelerated()); // We don't yet know that // allocation will fail. // This will cause SkSurface_Gpu creation to fail without // Canvas2DLayerBridge otherwise detecting that anything was disabled. gr->abandonContext(); - host_ = std::make_unique(IntSize(300, 150)); - bridge->SetCanvasResourceHost(host_.get()); - DrawSomething(bridge.get()); scoped_refptr snapshot = bridge->NewImageSnapshot(kPreferAcceleration); EXPECT_FALSE(bridge->IsAccelerated()); @@ -415,6 +403,13 @@ class MockLogger : public Canvas2DLayerBridge::Logger { ~MockLogger() override = default; }; +void DrawSomething(Canvas2DLayerBridge* bridge) { + bridge->DidDraw(FloatRect(0, 0, 1, 1)); + bridge->FinalizeFrame(); + // Grabbing an image forces a flush + bridge->NewImageSnapshot(kPreferAcceleration); +} + #if CANVAS2D_HIBERNATION_ENABLED TEST_F(Canvas2DLayerBridgeTest, HibernationLifeCycle) #else @@ -850,17 +845,13 @@ TEST_F(Canvas2DLayerBridgeTest, ResourceRecycling) { viz::TransferableResource resources[3]; std::unique_ptr callbacks[3]; - PaintFlags flags; std::unique_ptr bridge = MakeBridge( IntSize(300, 150), Canvas2DLayerBridge::kForceAccelerationForTesting, CanvasColorParams()); - bridge->GetPaintCanvas()->drawLine(0, 0, 2, 2, flags); DrawSomething(bridge.get()); ASSERT_TRUE(bridge->PrepareTransferableResource(nullptr, &resources[0], &callbacks[0])); - - bridge->GetPaintCanvas()->drawLine(0, 0, 2, 2, flags); DrawSomething(bridge.get()); ASSERT_TRUE(bridge->PrepareTransferableResource(nullptr, &resources[1], &callbacks[1])); @@ -870,7 +861,6 @@ TEST_F(Canvas2DLayerBridgeTest, ResourceRecycling) { // Now release the first resource and draw again. It should be reused due to // recycling. callbacks[0]->Run(gpu::SyncToken(), false); - bridge->GetPaintCanvas()->drawLine(0, 0, 2, 2, flags); DrawSomething(bridge.get()); ASSERT_TRUE(bridge->PrepareTransferableResource(nullptr, &resources[2], &callbacks[2])); @@ -890,16 +880,13 @@ TEST_F(Canvas2DLayerBridgeTest, NoResourceRecyclingWhenPageHidden) { viz::TransferableResource resources[2]; std::unique_ptr callbacks[2]; - PaintFlags flags; std::unique_ptr bridge = MakeBridge( IntSize(300, 150), Canvas2DLayerBridge::kForceAccelerationForTesting, CanvasColorParams()); - bridge->GetPaintCanvas()->drawLine(0, 0, 2, 2, flags); DrawSomething(bridge.get()); ASSERT_TRUE(bridge->PrepareTransferableResource(nullptr, &resources[0], &callbacks[0])); - bridge->GetPaintCanvas()->drawLine(0, 0, 2, 2, flags); DrawSomething(bridge.get()); ASSERT_TRUE(bridge->PrepareTransferableResource(nullptr, &resources[1], &callbacks[1])); @@ -1015,14 +1002,17 @@ TEST_F(Canvas2DLayerBridgeTest, ImagesLockedUntilCacheLimit) { // First 2 images are budgeted, they should remain locked after the op. bridge->GetPaintCanvas()->drawImage(images[0].paint_image(), 0u, 0u, nullptr); bridge->GetPaintCanvas()->drawImage(images[1].paint_image(), 0u, 0u, nullptr); - bridge->GetOrCreateResourceProvider()->FlushCanvas(); + // TODO(jochin): Can just call provider::FlushSkia() once we move recorder_ + // to the resource provider. The following is a temp workaround. + cc::PaintCanvas* canvas = bridge->GetOrCreateResourceProvider()->Canvas(); + canvas->drawPicture(bridge->record_for_testing()); EXPECT_EQ(image_decode_cache_.num_locked_images(), 2); // Next image is not budgeted, we should unlock all images other than the last // image. image_decode_cache_.set_budget_exceeded(true); bridge->GetPaintCanvas()->drawImage(images[2].paint_image(), 0u, 0u, nullptr); - bridge->GetOrCreateResourceProvider()->FlushCanvas(); + canvas->drawPicture(bridge->record_for_testing()); EXPECT_EQ(image_decode_cache_.num_locked_images(), 1); // Ask the provider to release everything, no locked images should remain. @@ -1043,7 +1033,10 @@ TEST_F(Canvas2DLayerBridgeTest, QueuesCleanupTaskForLockedImages) { SkMatrix::I(), 0u, color_params.GetStorageGfxColorSpace()); bridge->GetPaintCanvas()->drawImage(image.paint_image(), 0u, 0u, nullptr); - bridge->GetOrCreateResourceProvider()->FlushCanvas(); + // TODO(jochin): Can just call provider::FlushSkia() once we move recorder_ + // to the resource provider. The following is a temp workaround. + cc::PaintCanvas* canvas = bridge->GetOrCreateResourceProvider()->Canvas(); + canvas->drawPicture(bridge->record_for_testing()); EXPECT_EQ(image_decode_cache_.num_locked_images(), 1); base::RunLoop().RunUntilIdle(); @@ -1116,26 +1109,23 @@ TEST_F(Canvas2DLayerBridgeTest, WritePixelsRestoresClipStack) { std::move(host)); PaintFlags flags; - // MakeBridge() results in a call to restore the matrix. So we already have 1. EXPECT_EQ(bridge->GetPaintCanvas()->getTotalMatrix().get(SkMatrix::kMTransX), - 5); - // Drawline so WritePixels has something to flush - bridge->GetPaintCanvas()->drawLine(0, 0, 2, 2, flags); - bridge->DidDraw(FloatRect(0, 0, 1, 1)); + 0); - // WritePixels flushes recording. Post flush, a new drawing canvas is created - // that should have the matrix restored onto it. + cc::PaintCanvas* canvas = bridge->GetOrCreateResourceProvider()->Canvas(); bridge->WritePixels(SkImageInfo::MakeN32Premul(10, 10), nullptr, 10, 0, 0); + // Recording canvas maintain clip stack, while underlying SkCanvas should not. + EXPECT_EQ(canvas->getTotalMatrix().get(SkMatrix::kMTransX), 0); EXPECT_EQ(bridge->GetPaintCanvas()->getTotalMatrix().get(SkMatrix::kMTransX), 5); bridge->GetPaintCanvas()->drawLine(0, 0, 2, 2, flags); - // Standard flush recording. Post flush, a new drawing canvas is created that - // should have the matrix restored onto it. + // Flush recording. Recording canvas should maintain matrix, while SkCanvas + // should not. DrawSomething(bridge.get()); - EXPECT_EQ(bridge->GetPaintCanvas()->getTotalMatrix().get(SkMatrix::kMTransX), 5); + EXPECT_EQ(canvas->getTotalMatrix().get(SkMatrix::kMTransX), 0); } TEST_F(Canvas2DLayerBridgeTest, DisplayedCanvasIsRateLimited) { diff --git a/third_party/blink/renderer/platform/graphics/canvas_resource_host.cc b/third_party/blink/renderer/platform/graphics/canvas_resource_host.cc index d63606224c1dc6..f7c20310f27986 100644 --- a/third_party/blink/renderer/platform/graphics/canvas_resource_host.cc +++ b/third_party/blink/renderer/platform/graphics/canvas_resource_host.cc @@ -19,18 +19,6 @@ CanvasResourceHost::ReplaceResourceProvider( std::move(resource_provider_); resource_provider_ = std::move(new_resource_provider); UpdateMemoryUsage(); - if (resource_provider_) { - resource_provider_->Canvas()->restoreToCount(1); - InitializeForRecording(resource_provider_->Canvas()); - // Using unretained here since CanvasResourceHost owns |resource_provider_| - // and is guaranteed to outlive it - resource_provider_->SetRestoreClipStackCallback(base::BindRepeating( - &CanvasResourceHost::InitializeForRecording, base::Unretained(this))); - } - if (old_resource_provider) { - old_resource_provider->SetRestoreClipStackCallback( - CanvasResourceProvider::RestoreMatrixClipStackCb()); - } return old_resource_provider; } @@ -39,9 +27,4 @@ void CanvasResourceHost::DiscardResourceProvider() { UpdateMemoryUsage(); } -void CanvasResourceHost::InitializeForRecording(cc::PaintCanvas* canvas) { - canvas->save(); - RestoreCanvasMatrixClipStack(canvas); -} - } // namespace blink diff --git a/third_party/blink/renderer/platform/graphics/canvas_resource_host.h b/third_party/blink/renderer/platform/graphics/canvas_resource_host.h index 16dbe14e1697e5..9c1e69a63b4613 100644 --- a/third_party/blink/renderer/platform/graphics/canvas_resource_host.h +++ b/third_party/blink/renderer/platform/graphics/canvas_resource_host.h @@ -43,8 +43,6 @@ class PLATFORM_EXPORT CanvasResourceHost { virtual bool IsPrinting() const { return false; } private: - void InitializeForRecording(cc::PaintCanvas* canvas); - std::unique_ptr resource_provider_; }; diff --git a/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc b/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc index bcbd2a5266fc9e..2c855dda1eb6b5 100644 --- a/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc +++ b/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc @@ -17,11 +17,9 @@ #include "gpu/command_buffer/common/shared_image_usage.h" #include "gpu/config/gpu_driver_bug_workaround_type.h" #include "gpu/config/gpu_feature_info.h" -#include "third_party/blink/public/common/features.h" #include "third_party/blink/public/platform/platform.h" #include "third_party/blink/renderer/platform/graphics/accelerated_static_bitmap_image.h" #include "third_party/blink/renderer/platform/graphics/gpu/shared_gpu_context.h" -#include "third_party/blink/renderer/platform/graphics/memory_managed_paint_recorder.h" #include "third_party/blink/renderer/platform/graphics/unaccelerated_static_bitmap_image.h" #include "third_party/skia/include/core/SkSurface.h" @@ -231,7 +229,6 @@ class CanvasResourceProviderSharedImage : public CanvasResourceProvider { if (IsGpuContextLost()) return nullptr; - FlushCanvas(); // Its important to end read access and ref the resource before the WillDraw // call below. Since it relies on resource ref-count to trigger // copy-on-write and asserts that we only have write access when the @@ -267,7 +264,6 @@ class CanvasResourceProviderSharedImage : public CanvasResourceProvider { return SnapshotInternal(orientation); if (!cached_snapshot_) { - FlushCanvas(); EndWriteAccess(); cached_snapshot_ = resource_->Bitmap(); } @@ -566,8 +562,8 @@ class CanvasResourceProviderSwapChain final : public CanvasResourceProvider { "CanvasResourceProviderSwapChain::ProduceCanvasResource"); if (!IsValid()) return nullptr; - FlushCanvas(); if (dirty_) { + FlushSkia(); resource_->PresentSwapChain(); dirty_ = false; } @@ -1026,11 +1022,11 @@ SkSurface* CanvasResourceProvider::GetSkSurface() const { return surface_.get(); } -void CanvasResourceProvider::EnsureSkiaCanvas() { - WillDraw(); - - if (skia_canvas_) - return; +void CanvasResourceProvider::InitializePaintCanvas() { + // Since canvas_ has a reference to canvas_image_provider_, canvas must be + // deleted before the image_provider. + canvas_ = nullptr; + canvas_image_provider_ = nullptr; // Create an ImageDecodeCache for half float images only if the canvas is // using half float back storage. @@ -1050,27 +1046,26 @@ void CanvasResourceProvider::EnsureSkiaCanvas() { context_flushes.enable = true; context_flushes.max_draws_before_flush = kMaxDrawsBeforeContextFlush; } - skia_canvas_ = std::make_unique( - GetSkSurface()->getCanvas(), canvas_image_provider_.get(), - context_flushes); + canvas_ = std::make_unique(GetSkSurface()->getCanvas(), + canvas_image_provider_.get(), + context_flushes); } cc::PaintCanvas* CanvasResourceProvider::Canvas() { - if (!recorder_) { - // A raw pointer is safe here because the callback is only used by the - // |recorder_|. - recorder_ = std::make_unique(WTF::BindRepeating( - &CanvasResourceProvider::SetNeedsFlush, WTF::Unretained(this))); + WillDraw(); - return recorder_->beginRecording(Size().Width(), Size().Height()); + if (!canvas_) { + TRACE_EVENT0("blink", "CanvasResourceProvider::Canvas"); + DCHECK(!canvas_image_provider_); + InitializePaintCanvas(); } - return recorder_->getRecordingCanvas(); + return canvas_.get(); } void CanvasResourceProvider::OnContextDestroyed() { if (canvas_image_provider_) { - DCHECK(skia_canvas_); - skia_canvas_->reset_image_provider(); + DCHECK(canvas_); + canvas_->reset_image_provider(); canvas_image_provider_.reset(); } } @@ -1092,7 +1087,6 @@ scoped_refptr CanvasResourceProvider::SnapshotInternal( } cc::PaintImage CanvasResourceProvider::MakeImageSnapshot() { - FlushCanvas(); auto sk_image = GetSkSurface()->makeImageSnapshot(); if (!sk_image) return cc::PaintImage(); @@ -1132,18 +1126,8 @@ GrContext* CanvasResourceProvider::GetGrContext() const { return context_provider_wrapper_->ContextProvider()->GetGrContext(); } -void CanvasResourceProvider::FlushCanvas() { - if (!recorder_ || !recorder_->ListHasDrawOps()) - return; - EnsureSkiaCanvas(); - last_recording_ = recorder_->finishRecordingAsPicture(); - skia_canvas_->drawPicture(last_recording_); - cc::PaintCanvas* canvas = - recorder_->beginRecording(Size().Width(), Size().Height()); - if (restore_clip_stack_callback_) - restore_clip_stack_callback_.Run(canvas); +void CanvasResourceProvider::FlushSkia() const { GetSkSurface()->flush(); - needs_flush_ = false; } bool CanvasResourceProvider::IsGpuContextLost() const { @@ -1160,18 +1144,6 @@ bool CanvasResourceProvider::WritePixels(const SkImageInfo& orig_info, TRACE_EVENT0("blink", "CanvasResourceProvider::WritePixels"); DCHECK(IsValid()); - DCHECK(!recorder_->ListHasDrawOps()); - - EnsureSkiaCanvas(); - - // Apply clipstack to skia_canvas_ and then restore it to original state once - // we leave this scope. This is needed because each recording initializes and - // resets this state after every flush. restore_clip_stack_callback_ sets the - // initial save required for a restore. - cc::PaintCanvasAutoRestore auto_restore(skia_canvas_.get(), false); - if (restore_clip_stack_callback_) - restore_clip_stack_callback_.Run(skia_canvas_.get()); - return GetSkSurface()->getCanvas()->writePixels(orig_info, pixels, row_bytes, x, y); } @@ -1281,29 +1253,12 @@ scoped_refptr CanvasResourceProvider::GetImportedResource() return canvas_resources_.back(); } -void CanvasResourceProvider::SkipQueuedDrawCommands() { - if (!recorder_) - return; - recorder_->finishRecordingAsPicture(); - cc::PaintCanvas* canvas = - recorder_->beginRecording(Size().Width(), Size().Height()); - if (restore_clip_stack_callback_) - restore_clip_stack_callback_.Run(canvas); -} - -void CanvasResourceProvider::SetRestoreClipStackCallback( - RestoreMatrixClipStackCb callback) { - DCHECK(restore_clip_stack_callback_.is_null() || callback.is_null()); - restore_clip_stack_callback_ = std::move(callback); -} - void CanvasResourceProvider::RestoreBackBuffer(const cc::PaintImage& image) { DCHECK_EQ(image.height(), Size().Height()); DCHECK_EQ(image.width(), Size().Width()); - EnsureSkiaCanvas(); cc::PaintFlags copy_paint; copy_paint.setBlendMode(SkBlendMode::kSrc); - skia_canvas_->drawImage(image, 0, 0, ©_paint); + Canvas()->drawImage(image, 0, 0, ©_paint); } } // namespace blink diff --git a/third_party/blink/renderer/platform/graphics/canvas_resource_provider.h b/third_party/blink/renderer/platform/graphics/canvas_resource_provider.h index 1427ccff104bb2..f6787de36f02dd 100644 --- a/third_party/blink/renderer/platform/graphics/canvas_resource_provider.h +++ b/third_party/blink/renderer/platform/graphics/canvas_resource_provider.h @@ -9,7 +9,6 @@ #include "cc/raster/playback_image_provider.h" #include "third_party/blink/renderer/platform/graphics/canvas_resource.h" #include "third_party/blink/renderer/platform/graphics/image_orientation.h" -#include "third_party/blink/renderer/platform/graphics/paint/paint_recorder.h" #include "third_party/skia/include/core/SkSurface.h" class GrContext; @@ -94,9 +93,6 @@ class PLATFORM_EXPORT CanvasResourceProvider kMaxValue = kSwapChain, }; - using RestoreMatrixClipStackCb = - base::RepeatingCallback; - void static RecordTypeToUMA(ResourceProviderType type); // TODO(juanmihd): Clean up creation methods/usage. See crbug.com/1035589. @@ -142,8 +138,9 @@ class PLATFORM_EXPORT CanvasResourceProvider void OnContextDestroyed() override; cc::PaintCanvas* Canvas(); + void InitializePaintCanvas(); void ReleaseLockedImages(); - void FlushCanvas(); + void FlushSkia() const; const CanvasColorParams& ColorParams() const { return color_params_; } void SetFilterQuality(SkFilterQuality quality) { filter_quality_ = quality; } const IntSize& Size() const { return size_; } @@ -213,12 +210,6 @@ class PLATFORM_EXPORT CanvasResourceProvider return canvas_resources_.size(); } - void SkipQueuedDrawCommands(); - const sk_sp& last_recording() const { - return last_recording_; - } - void SetRestoreClipStackCallback(RestoreMatrixClipStackCb); - bool needs_flush() const { return needs_flush_; } void RestoreBackBuffer(const cc::PaintImage&); protected: @@ -270,8 +261,6 @@ class PLATFORM_EXPORT CanvasResourceProvider cc::ImageDecodeCache* ImageDecodeCacheRGBA8(); cc::ImageDecodeCache* ImageDecodeCacheF16(); - void EnsureSkiaCanvas(); - void SetNeedsFlush() { needs_flush_ = true; } base::WeakPtr context_provider_wrapper_; base::WeakPtr resource_dispatcher_; @@ -281,11 +270,7 @@ class PLATFORM_EXPORT CanvasResourceProvider const CanvasColorParams color_params_; const bool is_origin_top_left_; std::unique_ptr canvas_image_provider_; - std::unique_ptr skia_canvas_; - std::unique_ptr recorder_; - sk_sp last_recording_; - - bool needs_flush_ = false; + std::unique_ptr canvas_; const cc::PaintImage::Id snapshot_paint_image_id_; cc::PaintImage::ContentId snapshot_paint_image_content_id_ = @@ -304,8 +289,6 @@ class PLATFORM_EXPORT CanvasResourceProvider // underlying GrContext is flushed. static constexpr int kMaxDrawsBeforeContextFlush = 50; - RestoreMatrixClipStackCb restore_clip_stack_callback_; - base::WeakPtrFactory weak_ptr_factory_{this}; DISALLOW_COPY_AND_ASSIGN(CanvasResourceProvider); diff --git a/third_party/blink/renderer/platform/graphics/canvas_resource_provider_test.cc b/third_party/blink/renderer/platform/graphics/canvas_resource_provider_test.cc index 53bd355e03d4f8..88527710512ec9 100644 --- a/third_party/blink/renderer/platform/graphics/canvas_resource_provider_test.cc +++ b/third_party/blink/renderer/platform/graphics/canvas_resource_provider_test.cc @@ -246,7 +246,6 @@ TEST_F(CanvasResourceProviderTest, // Resource updated after draw. provider->Canvas()->clear(SK_ColorWHITE); - provider->FlushCanvas(); new_image = provider->Snapshot(); EXPECT_NE(new_image->GetMailboxHolder().mailbox, image->GetMailboxHolder().mailbox); @@ -255,7 +254,6 @@ TEST_F(CanvasResourceProviderTest, auto original_mailbox = image->GetMailboxHolder().mailbox; image.reset(); provider->Canvas()->clear(SK_ColorBLACK); - provider->FlushCanvas(); EXPECT_EQ(original_mailbox, provider->Snapshot()->GetMailboxHolder().mailbox); }