Commit 5c4bc1ff authored by Justin Novosad's avatar Justin Novosad Committed by Commit Bot

Add a single buffered mode to CanvasResourceProvider

This CL completes the initial implementation of Low Latency mode for 2d
canvases

Bug: 788439
Cq-Include-Trybots: luci.chromium.try:linux_layout_tests_slimming_paint_v2;master.tryserver.blink:linux_trusty_blink_rel
Change-Id: I58fcd3fe4ab19fa10f2876f3da4f078fd4fbc2a9
Reviewed-on: https://chromium-review.googlesource.com/1145235
Commit-Queue: Justin Novosad <junov@chromium.org>
Reviewed-by: default avatarFernando Serboncini <fserb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#576962}
parent 48e4f9d4
...@@ -415,9 +415,13 @@ void HTMLCanvasElement::FinalizeFrame() { ...@@ -415,9 +415,13 @@ void HTMLCanvasElement::FinalizeFrame() {
if (!LowLatencyEnabled()) if (!LowLatencyEnabled())
canvas2d_bridge_->FinalizeFrame(); canvas2d_bridge_->FinalizeFrame();
}
if (LowLatencyEnabled() && !dirty_rect_.IsEmpty() && if (LowLatencyEnabled() && !dirty_rect_.IsEmpty()) {
GetOrCreateCanvasResourceProvider(kPreferAcceleration)) { AccelerationHint hint =
Is2d() ? kPreferNoAcceleration : kPreferAcceleration;
if (GetOrCreateCanvasResourceProvider(hint)) {
ResourceProvider()->TryEnableSingleBuffering();
// Push a frame // Push a frame
base::TimeTicks start_time = WTF::CurrentTimeTicks(); base::TimeTicks start_time = WTF::CurrentTimeTicks();
scoped_refptr<CanvasResource> canvas_resource = scoped_refptr<CanvasResource> canvas_resource =
...@@ -1138,9 +1142,8 @@ void HTMLCanvasElement::SetCanvas2DLayerBridgeForTesting( ...@@ -1138,9 +1142,8 @@ void HTMLCanvasElement::SetCanvas2DLayerBridgeForTesting(
scoped_refptr<Image> HTMLCanvasElement::CopiedImage( scoped_refptr<Image> HTMLCanvasElement::CopiedImage(
SourceDrawingBuffer source_buffer, SourceDrawingBuffer source_buffer,
AccelerationHint hint) { AccelerationHint hint) {
if (SurfaceLayerBridge()) { if (PlaceholderFrame())
return PlaceholderFrame()->Bitmap(); return PlaceholderFrame()->Bitmap();
}
if (!IsPaintable()) if (!IsPaintable())
return nullptr; return nullptr;
......
...@@ -120,16 +120,15 @@ class CanvasRenderingContext2DTest : public PageTestBase { ...@@ -120,16 +120,15 @@ class CanvasRenderingContext2DTest : public PageTestBase {
return CanvasElement().GetGPUMemoryUsage(); return CanvasElement().GetGPUMemoryUsage();
} }
void DrawSomething() { void DrawSomething() {
Canvas2DLayerBridge* bridge = CanvasElement().GetCanvas2DLayerBridge(); CanvasElement().DidDraw();
bridge->DidDraw(FloatRect(0, 0, 1, 1)); CanvasElement().FinalizeFrame();
bridge->FinalizeFrame();
// Grabbing an image forces a flush // Grabbing an image forces a flush
bridge->NewImageSnapshot(kPreferAcceleration); CanvasElement().CopiedImage(kBackBuffer, kPreferAcceleration);
} }
void CreateContext(OpacityMode, enum LatencyMode { kNormalLatency, kLowLatency };
String color_space = String(),
LinearPixelMathState = kLinearPixelMathDisabled); void CreateContext(OpacityMode, LatencyMode = kNormalLatency);
ScriptState* GetScriptState() { ScriptState* GetScriptState() {
return ToScriptStateForMainWorld(canvas_element_->GetFrame()); return ToScriptStateForMainWorld(canvas_element_->GetFrame());
} }
...@@ -185,19 +184,12 @@ CanvasRenderingContext2DTest::CanvasRenderingContext2DTest() ...@@ -185,19 +184,12 @@ CanvasRenderingContext2DTest::CanvasRenderingContext2DTest()
opaque_bitmap_(IntSize(10, 10), kOpaqueBitmap), opaque_bitmap_(IntSize(10, 10), kOpaqueBitmap),
alpha_bitmap_(IntSize(10, 10), kTransparentBitmap) {} alpha_bitmap_(IntSize(10, 10), kTransparentBitmap) {}
void CanvasRenderingContext2DTest::CreateContext( void CanvasRenderingContext2DTest::CreateContext(OpacityMode opacity_mode,
OpacityMode opacity_mode, LatencyMode latency_mode) {
String color_space,
LinearPixelMathState LinearPixelMath_state) {
String canvas_type("2d"); String canvas_type("2d");
CanvasContextCreationAttributesCore attributes; CanvasContextCreationAttributesCore attributes;
attributes.alpha = opacity_mode == kNonOpaque; attributes.alpha = opacity_mode == kNonOpaque;
if (!color_space.IsEmpty()) { attributes.low_latency = latency_mode == kLowLatency;
attributes.color_space = color_space;
if (LinearPixelMath_state == kLinearPixelMathEnabled) {
attributes.pixel_format = "float16";
}
}
canvas_element_->GetCanvasRenderingContext(canvas_type, attributes); canvas_element_->GetCanvasRenderingContext(canvas_type, attributes);
} }
...@@ -1209,4 +1201,22 @@ TEST_F(CanvasRenderingContext2DTestWithTestingPlatform, ...@@ -1209,4 +1201,22 @@ TEST_F(CanvasRenderingContext2DTestWithTestingPlatform,
EXPECT_FALSE(layer->NeedsCompositingInputsUpdate()); EXPECT_FALSE(layer->NeedsCompositingInputsUpdate());
} }
TEST_F(CanvasRenderingContext2DTest, LowLatencyIsSingleBuffered) {
CreateContext(kNonOpaque, kLowLatency);
// No need to set-up the layer bridge when testing low latency mode.
DrawSomething();
auto frame1_resource =
CanvasElement()
.GetOrCreateCanvasResourceProvider(kPreferNoAcceleration)
->ProduceFrame();
EXPECT_TRUE(!!frame1_resource);
DrawSomething();
auto frame2_resource =
CanvasElement()
.GetOrCreateCanvasResourceProvider(kPreferNoAcceleration)
->ProduceFrame();
EXPECT_TRUE(!!frame2_resource);
EXPECT_EQ(frame1_resource.get(), frame2_resource.get());
}
} // namespace blink } // namespace blink
...@@ -152,6 +152,7 @@ class CanvasResourceProviderTextureGpuMemoryBuffer final ...@@ -152,6 +152,7 @@ class CanvasResourceProviderTextureGpuMemoryBuffer final
~CanvasResourceProviderTextureGpuMemoryBuffer() override = default; ~CanvasResourceProviderTextureGpuMemoryBuffer() override = default;
bool SupportsDirectCompositing() const override { return true; } bool SupportsDirectCompositing() const override { return true; }
bool SupportsSingleBuffering() const override { return true; }
private: private:
scoped_refptr<CanvasResource> CreateResource() final { scoped_refptr<CanvasResource> CreateResource() final {
...@@ -263,6 +264,7 @@ class CanvasResourceProviderRamGpuMemoryBuffer final ...@@ -263,6 +264,7 @@ class CanvasResourceProviderRamGpuMemoryBuffer final
~CanvasResourceProviderRamGpuMemoryBuffer() override = default; ~CanvasResourceProviderRamGpuMemoryBuffer() override = default;
bool SupportsDirectCompositing() const override { return true; } bool SupportsDirectCompositing() const override { return true; }
bool SupportsSingleBuffering() const override { return true; }
private: private:
scoped_refptr<CanvasResource> CreateResource() final { scoped_refptr<CanvasResource> CreateResource() final {
...@@ -318,6 +320,7 @@ class CanvasResourceProviderSharedBitmap : public CanvasResourceProviderBitmap { ...@@ -318,6 +320,7 @@ class CanvasResourceProviderSharedBitmap : public CanvasResourceProviderBitmap {
} }
~CanvasResourceProviderSharedBitmap() override = default; ~CanvasResourceProviderSharedBitmap() override = default;
bool SupportsDirectCompositing() const override { return true; } bool SupportsDirectCompositing() const override { return true; }
bool SupportsSingleBuffering() const override { return true; }
private: private:
scoped_refptr<CanvasResource> CreateResource() final { scoped_refptr<CanvasResource> CreateResource() final {
...@@ -684,6 +687,7 @@ void CanvasResourceProvider::InvalidateSurface() { ...@@ -684,6 +687,7 @@ void CanvasResourceProvider::InvalidateSurface() {
canvas_image_provider_.reset(); canvas_image_provider_.reset();
xform_canvas_ = nullptr; xform_canvas_ = nullptr;
surface_ = nullptr; surface_ = nullptr;
single_buffer_ = nullptr;
} }
uint32_t CanvasResourceProvider::ContentUniqueID() const { uint32_t CanvasResourceProvider::ContentUniqueID() const {
...@@ -721,6 +725,11 @@ void CanvasResourceProvider::ClearRecycledResources() { ...@@ -721,6 +725,11 @@ void CanvasResourceProvider::ClearRecycledResources() {
} }
scoped_refptr<CanvasResource> CanvasResourceProvider::NewOrRecycledResource() { scoped_refptr<CanvasResource> CanvasResourceProvider::NewOrRecycledResource() {
if (IsSingleBuffered()) {
if (!single_buffer_)
single_buffer_ = CreateResource();
return single_buffer_;
}
if (recycled_resources_.size()) { if (recycled_resources_.size()) {
scoped_refptr<CanvasResource> resource = scoped_refptr<CanvasResource> resource =
std::move(recycled_resources_.back()); std::move(recycled_resources_.back());
...@@ -730,4 +739,11 @@ scoped_refptr<CanvasResource> CanvasResourceProvider::NewOrRecycledResource() { ...@@ -730,4 +739,11 @@ scoped_refptr<CanvasResource> CanvasResourceProvider::NewOrRecycledResource() {
return CreateResource(); return CreateResource();
} }
void CanvasResourceProvider::TryEnableSingleBuffering() {
if (IsSingleBuffered() || !SupportsSingleBuffering())
return;
SetResourceRecyclingEnabled(false);
is_single_buffered_ = true;
}
} // namespace blink } // namespace blink
...@@ -100,11 +100,26 @@ class PLATFORM_EXPORT CanvasResourceProvider ...@@ -100,11 +100,26 @@ class PLATFORM_EXPORT CanvasResourceProvider
virtual bool IsValid() const = 0; virtual bool IsValid() const = 0;
virtual bool IsAccelerated() const = 0; virtual bool IsAccelerated() const = 0;
virtual bool SupportsDirectCompositing() const = 0; virtual bool SupportsDirectCompositing() const = 0;
virtual bool SupportsSingleBuffering() const { return false; }
uint32_t ContentUniqueID() const; uint32_t ContentUniqueID() const;
CanvasResourceDispatcher* ResourceDispatcher() { CanvasResourceDispatcher* ResourceDispatcher() {
return resource_dispatcher_.get(); return resource_dispatcher_.get();
} }
// Indicates that the compositing path is single buffered, meaning that
// ProduceFrame() return a reference to the same resource each time, which
// implies that Producing an animation frame may overwrite the resource used
// by the previous frame. This results in graphics updates skipping the
// queue, thus reducing latency, but with the possible side effects of
// tearring (in cases where the resource is scanned out directly) and
// irregular frame rate.
bool IsSingleBuffered() { return is_single_buffered_; }
// Attempt to enable single buffering mode on this resource provider. May
// fail if the CanvasResourcePRovider subclass does not support this mode of
// operation.
void TryEnableSingleBuffering();
void RecycleResource(scoped_refptr<CanvasResource>); void RecycleResource(scoped_refptr<CanvasResource>);
void SetResourceRecyclingEnabled(bool); void SetResourceRecyclingEnabled(bool);
void ClearRecycledResources(); void ClearRecycledResources();
...@@ -189,6 +204,9 @@ class PLATFORM_EXPORT CanvasResourceProvider ...@@ -189,6 +204,9 @@ class PLATFORM_EXPORT CanvasResourceProvider
WTF::Vector<scoped_refptr<CanvasResource>> recycled_resources_; WTF::Vector<scoped_refptr<CanvasResource>> recycled_resources_;
bool resource_recycling_enabled_ = true; bool resource_recycling_enabled_ = true;
bool is_single_buffered_ = false;
scoped_refptr<CanvasResource> single_buffer_;
base::WeakPtrFactory<CanvasResourceProvider> weak_ptr_factory_; base::WeakPtrFactory<CanvasResourceProvider> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(CanvasResourceProvider); DISALLOW_COPY_AND_ASSIGN(CanvasResourceProvider);
......
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