Commit 19dca998 authored by Jonah Chin's avatar Jonah Chin Committed by Commit Bot

Replace |have_recorded_draw_commands_| in OffscreenCanvasRenderingContext2D

The cause of this bug was the switch to a RecordPaintCanvas() on the
CanvasResourceProvider. Previously, a Clear Operation was done directly
on the skia canvas in OffscreenCanvas::GetOrCreateResourceProvider().

Now that CanvasResourceProvider::Canvas() returns a RecordPaintCanvas(),
a Clear Op is recorded, but not drawn to the backing skia canvas until
flush. The context's tracking boolean, |have_recorded_draw_commands_|,
was not updated to signal that a flush was needed.

This resulted in WritePixels()'s call to FlushRecording() earlying out
with no flush, despite the existence of draw operations.

By replacing |have_recorded_draw_commands_| with a check of the
recorder's actual DisplayItemList, we can avoid juggling the
|have_recorded_draw_commands_| boolean and can always correctly
determine if a flush is necessary.

Bug: 1059121
Change-Id: Ic511229a0cdb0ef3fe48dbd4d760066a0be2d10c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2099299Reviewed-by: default avatarAaron Krajeski <aaronhk@chromium.org>
Reviewed-by: default avatarFernando Serboncini <fserb@chromium.org>
Reviewed-by: default avatarKhushal <khushalsagar@chromium.org>
Commit-Queue: Jonah Chin <jochin@microsoft.com>
Cr-Commit-Position: refs/heads/master@{#751090}
parent 24acf841
...@@ -424,6 +424,7 @@ CanvasResourceProvider* OffscreenCanvas::GetOrCreateResourceProvider() { ...@@ -424,6 +424,7 @@ CanvasResourceProvider* OffscreenCanvas::GetOrCreateResourceProvider() {
base::UmaHistogramEnumeration("Blink.Canvas.ResourceProviderType", base::UmaHistogramEnumeration("Blink.Canvas.ResourceProviderType",
ResourceProvider()->GetType()); ResourceProvider()->GetType());
ResourceProvider()->Clear(); ResourceProvider()->Clear();
DidDraw();
if (needs_matrix_clip_restore_) { if (needs_matrix_clip_restore_) {
needs_matrix_clip_restore_ = false; needs_matrix_clip_restore_ = false;
......
...@@ -87,7 +87,7 @@ OffscreenCanvasRenderingContext2D::OffscreenCanvasRenderingContext2D( ...@@ -87,7 +87,7 @@ OffscreenCanvasRenderingContext2D::OffscreenCanvasRenderingContext2D(
// Clear the background transparent or opaque. // Clear the background transparent or opaque.
if (IsCanvas2DBufferValid()) { if (IsCanvas2DBufferValid()) {
GetOrCreateCanvasResourceProvider()->Clear(); GetCanvasResourceProvider()->Clear();
DidDraw(); DidDraw();
} }
...@@ -120,13 +120,12 @@ void OffscreenCanvasRenderingContext2D::commit() { ...@@ -120,13 +120,12 @@ void OffscreenCanvasRenderingContext2D::commit() {
} }
void OffscreenCanvasRenderingContext2D::FlushRecording() { void OffscreenCanvasRenderingContext2D::FlushRecording() {
if (!have_recorded_draw_commands_) if (!GetCanvasResourceProvider() ||
!GetCanvasResourceProvider()->HasRecordedDrawOps())
return; return;
GetCanvasResourceProvider()->FlushCanvas(); GetCanvasResourceProvider()->FlushCanvas();
GetCanvasResourceProvider()->ReleaseLockedImages(); GetCanvasResourceProvider()->ReleaseLockedImages();
have_recorded_draw_commands_ = false;
} }
void OffscreenCanvasRenderingContext2D::FinalizeFrame() { void OffscreenCanvasRenderingContext2D::FinalizeFrame() {
...@@ -272,7 +271,6 @@ cc::PaintCanvas* OffscreenCanvasRenderingContext2D::GetPaintCanvas() const { ...@@ -272,7 +271,6 @@ cc::PaintCanvas* OffscreenCanvasRenderingContext2D::GetPaintCanvas() const {
} }
void OffscreenCanvasRenderingContext2D::DidDraw() { void OffscreenCanvasRenderingContext2D::DidDraw() {
have_recorded_draw_commands_ = true;
dirty_rect_for_commit_.setWH(Width(), Height()); dirty_rect_for_commit_.setWH(Width(), Height());
Host()->DidDraw(); Host()->DidDraw();
if (GetCanvasResourceProvider() && GetCanvasResourceProvider()->needs_flush()) if (GetCanvasResourceProvider() && GetCanvasResourceProvider()->needs_flush())
...@@ -280,7 +278,6 @@ void OffscreenCanvasRenderingContext2D::DidDraw() { ...@@ -280,7 +278,6 @@ void OffscreenCanvasRenderingContext2D::DidDraw() {
} }
void OffscreenCanvasRenderingContext2D::DidDraw(const SkIRect& dirty_rect) { void OffscreenCanvasRenderingContext2D::DidDraw(const SkIRect& dirty_rect) {
have_recorded_draw_commands_ = true;
dirty_rect_for_commit_.join(dirty_rect); dirty_rect_for_commit_.join(dirty_rect);
Host()->DidDraw(SkRect::Make(dirty_rect_for_commit_)); Host()->DidDraw(SkRect::Make(dirty_rect_for_commit_));
if (GetCanvasResourceProvider() && GetCanvasResourceProvider()->needs_flush()) if (GetCanvasResourceProvider() && GetCanvasResourceProvider()->needs_flush())
...@@ -340,7 +337,6 @@ bool OffscreenCanvasRenderingContext2D::WritePixels( ...@@ -340,7 +337,6 @@ bool OffscreenCanvasRenderingContext2D::WritePixels(
DCHECK(IsPaintable()); DCHECK(IsPaintable());
FinalizeFrame(); FinalizeFrame();
have_recorded_draw_commands_ = false;
return offscreenCanvasForBinding()->ResourceProvider()->WritePixels( return offscreenCanvasForBinding()->ResourceProvider()->WritePixels(
orig_info, pixels, row_bytes, x, y); orig_info, pixels, row_bytes, x, y);
......
...@@ -127,8 +127,6 @@ class MODULES_EXPORT OffscreenCanvasRenderingContext2D final ...@@ -127,8 +127,6 @@ class MODULES_EXPORT OffscreenCanvasRenderingContext2D final
bool PushFrame() override; bool PushFrame() override;
bool HasRecordedDrawCommands() { return have_recorded_draw_commands_; }
protected: protected:
CanvasColorParams ColorParams() const override; CanvasColorParams ColorParams() const override;
bool WritePixels(const SkImageInfo& orig_info, bool WritePixels(const SkImageInfo& orig_info,
...@@ -139,7 +137,6 @@ class MODULES_EXPORT OffscreenCanvasRenderingContext2D final ...@@ -139,7 +137,6 @@ class MODULES_EXPORT OffscreenCanvasRenderingContext2D final
void WillOverwriteCanvas() override; void WillOverwriteCanvas() override;
private: private:
bool have_recorded_draw_commands_;
void FinalizeFrame() final; void FinalizeFrame() final;
void FlushRecording(); void FlushRecording();
......
...@@ -1129,7 +1129,7 @@ GrContext* CanvasResourceProvider::GetGrContext() const { ...@@ -1129,7 +1129,7 @@ GrContext* CanvasResourceProvider::GetGrContext() const {
} }
void CanvasResourceProvider::FlushCanvas() { void CanvasResourceProvider::FlushCanvas() {
if (!recorder_ || !recorder_->ListHasDrawOps()) if (!HasRecordedDrawOps())
return; return;
EnsureSkiaCanvas(); EnsureSkiaCanvas();
last_recording_ = recorder_->finishRecordingAsPicture(); last_recording_ = recorder_->finishRecordingAsPicture();
...@@ -1156,7 +1156,7 @@ bool CanvasResourceProvider::WritePixels(const SkImageInfo& orig_info, ...@@ -1156,7 +1156,7 @@ bool CanvasResourceProvider::WritePixels(const SkImageInfo& orig_info,
TRACE_EVENT0("blink", "CanvasResourceProvider::WritePixels"); TRACE_EVENT0("blink", "CanvasResourceProvider::WritePixels");
DCHECK(IsValid()); DCHECK(IsValid());
DCHECK(!recorder_->ListHasDrawOps()); DCHECK(!HasRecordedDrawOps());
EnsureSkiaCanvas(); EnsureSkiaCanvas();
...@@ -1282,7 +1282,7 @@ void CanvasResourceProvider::SkipQueuedDrawCommands() { ...@@ -1282,7 +1282,7 @@ void CanvasResourceProvider::SkipQueuedDrawCommands() {
// so always update the |mode_| to discard the old copy of canvas content. // so always update the |mode_| to discard the old copy of canvas content.
mode_ = SkSurface::kDiscard_ContentChangeMode; mode_ = SkSurface::kDiscard_ContentChangeMode;
if (!recorder_ || !recorder_->ListHasDrawOps()) if (!HasRecordedDrawOps())
return; return;
recorder_->finishRecordingAsPicture(); recorder_->finishRecordingAsPicture();
cc::PaintCanvas* canvas = cc::PaintCanvas* canvas =
...@@ -1306,4 +1306,8 @@ void CanvasResourceProvider::RestoreBackBuffer(const cc::PaintImage& image) { ...@@ -1306,4 +1306,8 @@ void CanvasResourceProvider::RestoreBackBuffer(const cc::PaintImage& image) {
skia_canvas_->drawImage(image, 0, 0, &copy_paint); skia_canvas_->drawImage(image, 0, 0, &copy_paint);
} }
bool CanvasResourceProvider::HasRecordedDrawOps() const {
return recorder_ && recorder_->ListHasDrawOps();
}
} // namespace blink } // namespace blink
...@@ -218,6 +218,7 @@ class PLATFORM_EXPORT CanvasResourceProvider ...@@ -218,6 +218,7 @@ class PLATFORM_EXPORT CanvasResourceProvider
void RestoreBackBuffer(const cc::PaintImage&); void RestoreBackBuffer(const cc::PaintImage&);
ResourceProviderType GetType() const { return type_; } ResourceProviderType GetType() const { return type_; }
bool HasRecordedDrawOps() const;
protected: protected:
gpu::gles2::GLES2Interface* ContextGL() const; gpu::gles2::GLES2Interface* ContextGL() const;
......
<!DOCTYPE html>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<canvas style="background: red"></canvas>
<script>
test(function() {
var canvas = document.querySelector('canvas');
var offscreenCtx = (new OffscreenCanvas(canvas.width, canvas.height)).getContext('2d');
var imageData = offscreenCtx.createImageData(canvas.width, canvas.height);
var data = imageData.data;
// Set all pixels to [0, 255, 0, 255]
for (var i = 0; i < data.length; i += 4) {
data[i + 1] = data[i + 3] = 255;
}
offscreenCtx.putImageData(imageData, 0, 0);
assert_array_equals(offscreenCtx.getImageData(0, 0, 1, 1).data, [0, 255, 0, 255]);
}, "Verify that imageData is properly set");
</script>
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment