Skip to content

Commit

Permalink
Reland "Create MemoryManagedPaintCanvas class"
Browse files Browse the repository at this point in the history
This change was landed and reverted
  https://chromium-review.googlesource.com/c/chromium/src/+/1960469

We were flushing mid-draw and this was causing problems. Flush after
DidDraw instead.

Change-Id: I0d40c5f823014601203c84469749314add107e58
Bug: 1016727, 1015729, 1035865, 1035865
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1976501
Commit-Queue: Aaron Krajeski <aaronhk@chromium.org>
Reviewed-by: Aaron Krajeski <aaronhk@chromium.org>
Reviewed-by: Jeremy Roman <jbroman@chromium.org>
Reviewed-by: Khushal <khushalsagar@chromium.org>
Cr-Commit-Position: refs/heads/master@{#726913}
  • Loading branch information
mysteryDate authored and Commit Bot committed Dec 20, 2019
1 parent f2053e9 commit 86ff5cc
Show file tree
Hide file tree
Showing 12 changed files with 257 additions and 18 deletions.
8 changes: 7 additions & 1 deletion cc/paint/paint_recorder.cc
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ PaintRecorder::~PaintRecorder() = default;

PaintCanvas* PaintRecorder::beginRecording(const SkRect& bounds) {
display_item_list_->StartPaint();
canvas_.emplace(display_item_list_.get(), bounds);
canvas_ = CreateCanvas(display_item_list_.get(), bounds);
return getRecordingCanvas();
}

Expand All @@ -41,4 +41,10 @@ sk_sp<PaintRecord> PaintRecorder::finishRecordingAsPicture() {
return display_item_list_->ReleaseAsRecord();
}

std::unique_ptr<RecordPaintCanvas> PaintRecorder::CreateCanvas(
DisplayItemList* list,
const SkRect& bounds) {
return std::make_unique<RecordPaintCanvas>(list, bounds);
}

} // namespace cc
10 changes: 7 additions & 3 deletions cc/paint/paint_recorder.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class CC_PAINT_EXPORT PaintRecorder {
public:
PaintRecorder();
PaintRecorder(const PaintRecorder&) = delete;
~PaintRecorder();
virtual ~PaintRecorder();

PaintRecorder& operator=(const PaintRecorder&) = delete;

Expand All @@ -32,14 +32,18 @@ class CC_PAINT_EXPORT PaintRecorder {

// Only valid while recording.
ALWAYS_INLINE RecordPaintCanvas* getRecordingCanvas() {
return canvas_.has_value() ? &canvas_.value() : nullptr;
return canvas_.get();
}

sk_sp<PaintRecord> finishRecordingAsPicture();

protected:
virtual std::unique_ptr<RecordPaintCanvas> CreateCanvas(DisplayItemList* list,
const SkRect& bounds);

private:
scoped_refptr<DisplayItemList> display_item_list_;
base::Optional<RecordPaintCanvas> canvas_;
std::unique_ptr<RecordPaintCanvas> canvas_;
};

} // namespace cc
Expand Down
2 changes: 1 addition & 1 deletion cc/paint/record_paint_canvas.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ namespace cc {
class DisplayItemList;
class PaintFlags;

class CC_PAINT_EXPORT RecordPaintCanvas final : public PaintCanvas {
class CC_PAINT_EXPORT RecordPaintCanvas : public PaintCanvas {
public:
RecordPaintCanvas(DisplayItemList* list, const SkRect& bounds);
RecordPaintCanvas(const RecordPaintCanvas&) = delete;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -85,6 +86,11 @@ OffscreenCanvasRenderingContext2D::OffscreenCanvasRenderingContext2D(
bernoulli_distribution_(kUMASampleProbability) {
is_valid_size_ = IsValidImageSize(Host()->Size());

// 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
Expand Down Expand Up @@ -126,13 +132,12 @@ void OffscreenCanvasRenderingContext2D::commit() {
}

void OffscreenCanvasRenderingContext2D::StartRecording() {
recorder_ = std::make_unique<PaintRecorder>();

recorder_ =
std::make_unique<MemoryManagedPaintRecorder>(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);
}

Expand Down Expand Up @@ -160,6 +165,7 @@ void OffscreenCanvasRenderingContext2D::FinalizeFrame() {
if (!GetOrCreateCanvasResourceProvider())
return;
FlushRecording();
needs_flush_ = false;
}

// BaseRenderingContext2D implementation
Expand Down Expand Up @@ -293,23 +299,20 @@ cc::PaintCanvas* OffscreenCanvasRenderingContext2D::DrawingCanvas() const {
return recorder_->getRecordingCanvas();
}

cc::PaintCanvas* OffscreenCanvasRenderingContext2D::ExistingDrawingCanvas()
const {
if (!is_valid_size_)
return nullptr;
return recorder_->getRecordingCanvas();
}

void OffscreenCanvasRenderingContext2D::DidDraw() {
have_recorded_draw_commands_ = true;
Host()->DidDraw();
dirty_rect_for_commit_.setWH(Width(), Height());
Host()->DidDraw();
if (needs_flush_)
FinalizeFrame();
}

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 (needs_flush_)
FinalizeFrame();
}

bool OffscreenCanvasRenderingContext2D::StateHasFilter() {
Expand Down Expand Up @@ -642,4 +645,8 @@ bool OffscreenCanvasRenderingContext2D::IsCanvas2DBufferValid() const {
return GetCanvasResourceProvider()->IsValid();
return false;
}

void OffscreenCanvasRenderingContext2D::SetNeedsFlush() {
needs_flush_ = true;
}
} // namespace blink
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,9 @@ class MODULES_EXPORT OffscreenCanvasRenderingContext2D final
bool ParseColorOrCurrentColor(Color&, const String& color_string) const final;

cc::PaintCanvas* DrawingCanvas() const final;
cc::PaintCanvas* ExistingDrawingCanvas() const final;
cc::PaintCanvas* ExistingDrawingCanvas() const final {
return DrawingCanvas();
}

void DidDraw() final;
void DidDraw(const SkIRect& dirty_rect) final;
Expand Down Expand Up @@ -160,6 +162,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;
};

DEFINE_TYPE_CASTS(OffscreenCanvasRenderingContext2D,
Expand Down
4 changes: 4 additions & 0 deletions third_party/blink/renderer/platform/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -995,6 +995,10 @@ jumbo_component("platform") {
"graphics/mailbox_texture_holder.h",
"graphics/main_thread_mutator_client.cc",
"graphics/main_thread_mutator_client.h",
"graphics/memory_managed_paint_canvas.cc",
"graphics/memory_managed_paint_canvas.h",
"graphics/memory_managed_paint_recorder.cc",
"graphics/memory_managed_paint_recorder.h",
"graphics/mutator_client.h",
"graphics/offscreen_canvas_placeholder.cc",
"graphics/offscreen_canvas_placeholder.h",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,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"
Expand Down Expand Up @@ -74,6 +75,11 @@ 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
Expand Down Expand Up @@ -109,9 +115,11 @@ Canvas2DLayerBridge::~Canvas2DLayerBridge() {
}

void Canvas2DLayerBridge::StartRecording() {
recorder_ = std::make_unique<PaintRecorder>();
recorder_ =
std::make_unique<MemoryManagedPaintRecorder>(set_needs_flush_callback_);
cc::PaintCanvas* canvas =
recorder_->beginRecording(size_.Width(), size_.Height());

// Always save an initial frame, to support resetting the top level matrix
// and clip.
canvas->save();
Expand Down Expand Up @@ -715,6 +723,8 @@ cc::Layer* Canvas2DLayerBridge::Layer() {
}

void Canvas2DLayerBridge::DidDraw(const FloatRect& /* rect */) {
if (needs_flush_)
FinalizeFrame();
have_recorded_draw_commands_ = true;
}

Expand Down Expand Up @@ -742,6 +752,8 @@ void Canvas2DLayerBridge::FinalizeFrame() {

if (rate_limiter_)
rate_limiter_->Tick();

needs_flush_ = false;
}

void Canvas2DLayerBridge::DoPaintInvalidation(const FloatRect& dirty_rect) {
Expand Down Expand Up @@ -772,6 +784,10 @@ void Canvas2DLayerBridge::WillOverwriteCanvas() {
SkipQueuedDrawCommands();
}

void Canvas2DLayerBridge::SetNeedsFlush() {
needs_flush_ = true;
}

void Canvas2DLayerBridge::Logger::ReportHibernationEvent(
HibernationEvent event) {
UMA_HISTOGRAM_ENUMERATION("Blink.Canvas.HibernationEvents", event);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,10 @@ class PLATFORM_EXPORT Canvas2DLayerBridge : public cc::TextureLayerClient {

sk_sp<cc::PaintRecord> last_recording_;

void SetNeedsFlush();
base::RepeatingClosure set_needs_flush_callback_;
bool needs_flush_ = false;

base::WeakPtrFactory<Canvas2DLayerBridge> weak_ptr_factory_{this};

DISALLOW_COPY_AND_ASSIGN(Canvas2DLayerBridge);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "third_party/blink/renderer/platform/graphics/memory_managed_paint_canvas.h"

namespace blink {

MemoryManagedPaintCanvas::MemoryManagedPaintCanvas(
cc::DisplayItemList* list,
const SkRect& bounds,
base::RepeatingClosure set_needs_flush_callback)
: RecordPaintCanvas(list, bounds),
set_needs_flush_callback_(std::move(set_needs_flush_callback)) {}

MemoryManagedPaintCanvas::~MemoryManagedPaintCanvas() = default;

void MemoryManagedPaintCanvas::drawImage(const cc::PaintImage& image,
SkScalar left,
SkScalar top,
const cc::PaintFlags* flags) {
DCHECK(!image.IsPaintWorklet());
RecordPaintCanvas::drawImage(image, left, top, flags);
UpdateMemoryUsage(image);
}

void MemoryManagedPaintCanvas::drawImageRect(
const cc::PaintImage& image,
const SkRect& src,
const SkRect& dst,
const cc::PaintFlags* flags,
PaintCanvas::SrcRectConstraint constraint) {
RecordPaintCanvas::drawImageRect(image, src, dst, flags, constraint);
UpdateMemoryUsage(image);
}

void MemoryManagedPaintCanvas::UpdateMemoryUsage(const cc::PaintImage& image) {
if (cached_image_ids_.contains(image.content_id()))
return;

cached_image_ids_.insert(image.content_id());
total_stored_image_memory_ +=
image.GetSkImage()->imageInfo().computeMinByteSize();

if (total_stored_image_memory_ > kMaxPinnedMemory)
set_needs_flush_callback_.Run();
}

} // namespace blink
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_MEMORY_MANAGED_PAINT_CANVAS_H_
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_MEMORY_MANAGED_PAINT_CANVAS_H_

#include <memory>

#include "cc/paint/record_paint_canvas.h"
#include "third_party/blink/public/platform/platform.h"

namespace blink {

// MemoryManagedPaintCanvas overrides the potentially memory intensive image
// drawing methods of PaintCanvas and keeps track of how much memory is
// being pinned between flushes. This allows the rendering context to flush if
// too much memory is used.
class PLATFORM_EXPORT MemoryManagedPaintCanvas final
: public cc::RecordPaintCanvas {
public:
MemoryManagedPaintCanvas(cc::DisplayItemList* list,
const SkRect& bounds,
base::RepeatingClosure set_needs_flush_callback);
explicit MemoryManagedPaintCanvas(const cc::RecordPaintCanvas&) = delete;
~MemoryManagedPaintCanvas() override;

void drawImage(const cc::PaintImage& image,
SkScalar left,
SkScalar top,
const cc::PaintFlags* flags) override;
void drawImageRect(const cc::PaintImage& image,
const SkRect& src,
const SkRect& dst,
const cc::PaintFlags* flags,
SrcRectConstraint constraint) override;

private:
void UpdateMemoryUsage(const cc::PaintImage& image);

base::flat_set<int> cached_image_ids_;
uint64_t total_stored_image_memory_ = 0;

base::RepeatingClosure set_needs_flush_callback_;

// The same value as is used in content::WebGraphicsConext3DProviderImpl.
static constexpr uint64_t kMaxPinnedMemory = 64 * 1024 * 1024;
};

} // namespace blink

#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_MEMORY_MANAGED_PAINT_CANVAS_H_
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* Copyright (C) 2019 Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include "third_party/blink/renderer/platform/graphics/memory_managed_paint_recorder.h"

namespace blink {

MemoryManagedPaintRecorder::MemoryManagedPaintRecorder(
base::RepeatingClosure set_needs_flush_callback)
: set_needs_flush_callback_(std::move(set_needs_flush_callback)) {}

std::unique_ptr<cc::RecordPaintCanvas> MemoryManagedPaintRecorder::CreateCanvas(
cc::DisplayItemList* list,
const SkRect& bounds) {
return std::make_unique<MemoryManagedPaintCanvas>(list, bounds,
set_needs_flush_callback_);
}

} // namespace blink
Loading

0 comments on commit 86ff5cc

Please sign in to comment.