summaryrefslogtreecommitdiff
path: root/chromium/components/viz/common
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/components/viz/common')
-rw-r--r--chromium/components/viz/common/BUILD.gn61
-rw-r--r--chromium/components/viz/common/DEPS4
-rw-r--r--chromium/components/viz/common/README.md4
-rw-r--r--chromium/components/viz/common/display/renderer_settings.h3
-rw-r--r--chromium/components/viz/common/frame_sinks/begin_frame_args.cc130
-rw-r--r--chromium/components/viz/common/frame_sinks/begin_frame_args.h145
-rw-r--r--chromium/components/viz/common/frame_sinks/begin_frame_args_unittest.cc125
-rw-r--r--chromium/components/viz/common/frame_sinks/begin_frame_source.cc354
-rw-r--r--chromium/components/viz/common/frame_sinks/begin_frame_source.h275
-rw-r--r--chromium/components/viz/common/frame_sinks/begin_frame_source_unittest.cc610
-rw-r--r--chromium/components/viz/common/frame_sinks/delay_based_time_source.cc180
-rw-r--r--chromium/components/viz/common/frame_sinks/delay_based_time_source.h91
-rw-r--r--chromium/components/viz/common/frame_sinks/delay_based_time_source_unittest.cc351
-rw-r--r--chromium/components/viz/common/gl_helper_benchmark.cc2
-rw-r--r--chromium/components/viz/common/gl_helper_scaling.cc10
-rw-r--r--chromium/components/viz/common/gl_helper_scaling.h8
-rw-r--r--chromium/components/viz/common/gl_helper_unittest.cc12
-rw-r--r--chromium/components/viz/common/gpu/DEPS2
-rw-r--r--chromium/components/viz/common/gpu/in_process_context_provider.h3
-rw-r--r--chromium/components/viz/common/gpu/vulkan_context_provider.h30
-rw-r--r--chromium/components/viz/common/gpu/vulkan_in_process_context_provider.cc73
-rw-r--r--chromium/components/viz/common/gpu/vulkan_in_process_context_provider.h45
-rw-r--r--chromium/components/viz/common/hit_test/DEPS4
-rw-r--r--chromium/components/viz/common/hit_test/aggregated_hit_test_region.h15
-rw-r--r--chromium/components/viz/common/quads/DEPS6
-rw-r--r--chromium/components/viz/common/quads/copy_output_request.cc68
-rw-r--r--chromium/components/viz/common/quads/copy_output_request.h114
-rw-r--r--chromium/components/viz/common/quads/copy_output_result.cc47
-rw-r--r--chromium/components/viz/common/quads/copy_output_result.h79
-rw-r--r--chromium/components/viz/common/quads/release_callback.h21
-rw-r--r--chromium/components/viz/common/quads/resource_format.h35
-rw-r--r--chromium/components/viz/common/quads/shared_quad_state.cc65
-rw-r--r--chromium/components/viz/common/quads/shared_quad_state.h61
-rw-r--r--chromium/components/viz/common/quads/single_release_callback.cc29
-rw-r--r--chromium/components/viz/common/quads/single_release_callback.h35
-rw-r--r--chromium/components/viz/common/resources/DEPS2
-rw-r--r--chromium/components/viz/common/resources/buffer_to_texture_target_map.cc2
-rw-r--r--chromium/components/viz/common/resources/platform_color.h2
-rw-r--r--chromium/components/viz/common/resources/resource_format.h28
-rw-r--r--chromium/components/viz/common/resources/resource_format_utils.cc29
-rw-r--r--chromium/components/viz/common/resources/resource_format_utils.h35
-rw-r--r--chromium/components/viz/common/resources/resource_id.h19
-rw-r--r--chromium/components/viz/common/resources/returned_resource.h56
-rw-r--r--chromium/components/viz/common/resources/transferable_resource.cc48
-rw-r--r--chromium/components/viz/common/resources/transferable_resource.h54
-rw-r--r--chromium/components/viz/common/surfaces/DEPS1
-rw-r--r--chromium/components/viz/common/surfaces/sequence_surface_reference_factory.h2
-rw-r--r--chromium/components/viz/common/surfaces/stub_surface_reference_factory.cc17
-rw-r--r--chromium/components/viz/common/surfaces/stub_surface_reference_factory.h34
-rw-r--r--chromium/components/viz/common/surfaces/surface_id.h8
-rw-r--r--chromium/components/viz/common/surfaces/surface_info.h10
-rw-r--r--chromium/components/viz/common/switches.cc18
-rw-r--r--chromium/components/viz/common/switches.h18
-rw-r--r--chromium/components/viz/common/traced_value.cc54
-rw-r--r--chromium/components/viz/common/traced_value.h43
-rw-r--r--chromium/components/viz/common/viz_resource_format_export.h29
56 files changed, 3503 insertions, 103 deletions
diff --git a/chromium/components/viz/common/BUILD.gn b/chromium/components/viz/common/BUILD.gn
index 84f40f15662..95ac2e7fdaf 100644
--- a/chromium/components/viz/common/BUILD.gn
+++ b/chromium/components/viz/common/BUILD.gn
@@ -5,6 +5,27 @@
import("//components/viz/viz.gni")
import("//testing/test.gni")
+viz_component("resource_format") {
+ output_name = "viz_resource_format"
+
+ defines = [ "VIZ_RESOURCE_FORMAT_IMPLEMENTATION" ]
+
+ sources = [
+ "resources/resource_format.h",
+ "resources/resource_format_utils.cc",
+ "resources/resource_format_utils.h",
+ "viz_resource_format_export.h",
+ ]
+
+ configs = [ "//third_party/khronos:khronos_headers" ]
+
+ deps = [
+ "//base",
+ "//skia",
+ "//ui/gfx:buffer_types",
+ ]
+}
+
viz_component("common") {
output_name = "viz_common"
@@ -13,6 +34,12 @@ viz_component("common") {
sources = [
"display/renderer_settings.cc",
"display/renderer_settings.h",
+ "frame_sinks/begin_frame_args.cc",
+ "frame_sinks/begin_frame_args.h",
+ "frame_sinks/begin_frame_source.cc",
+ "frame_sinks/begin_frame_source.h",
+ "frame_sinks/delay_based_time_source.cc",
+ "frame_sinks/delay_based_time_source.h",
"gl_helper.cc",
"gl_helper.h",
"gl_helper_readback_support.cc",
@@ -25,20 +52,33 @@ viz_component("common") {
"gpu/context_provider.h",
"gpu/in_process_context_provider.cc",
"gpu/in_process_context_provider.h",
+ "gpu/vulkan_context_provider.h",
+ "gpu/vulkan_in_process_context_provider.cc",
+ "gpu/vulkan_in_process_context_provider.h",
"hit_test/aggregated_hit_test_region.h",
- "quads/resource_format.h",
+ "quads/copy_output_request.cc",
+ "quads/copy_output_request.h",
+ "quads/copy_output_result.cc",
+ "quads/copy_output_result.h",
+ "quads/release_callback.h",
"quads/shared_bitmap.cc",
"quads/shared_bitmap.h",
+ "quads/shared_quad_state.cc",
+ "quads/shared_quad_state.h",
+ "quads/single_release_callback.cc",
+ "quads/single_release_callback.h",
"quads/texture_mailbox.cc",
"quads/texture_mailbox.h",
"resources/buffer_to_texture_target_map.cc",
"resources/buffer_to_texture_target_map.h",
"resources/platform_color.h",
- "resources/resource_format_utils.cc",
- "resources/resource_format_utils.h",
+ "resources/resource_id.h",
"resources/resource_settings.cc",
"resources/resource_settings.h",
+ "resources/returned_resource.h",
"resources/shared_bitmap_manager.h",
+ "resources/transferable_resource.cc",
+ "resources/transferable_resource.h",
"surfaces/frame_sink_id.cc",
"surfaces/frame_sink_id.h",
"surfaces/frame_sink_id_allocator.h",
@@ -48,6 +88,8 @@ viz_component("common") {
"surfaces/local_surface_id_allocator.h",
"surfaces/sequence_surface_reference_factory.cc",
"surfaces/sequence_surface_reference_factory.h",
+ "surfaces/stub_surface_reference_factory.cc",
+ "surfaces/stub_surface_reference_factory.h",
"surfaces/surface_id.cc",
"surfaces/surface_id.h",
"surfaces/surface_info.h",
@@ -56,10 +98,18 @@ viz_component("common") {
"surfaces/surface_sequence.h",
"surfaces/surface_sequence_generator.cc",
"surfaces/surface_sequence_generator.h",
+ "switches.cc",
+ "switches.h",
+ "traced_value.cc",
+ "traced_value.h",
"viz_common_export.h",
]
deps = [
+ # TODO(staraz): cc/base was added because SharedQuadState includes
+ # cc::MathUtil. Remove it once cc/base/math_util* are moved to viz.
+ "//cc/base",
+
"//base",
"//gpu",
"//gpu/command_buffer/client:gles2_implementation",
@@ -67,6 +117,7 @@ viz_component("common") {
"//gpu/command_buffer/service",
"//gpu/ipc:gl_in_process_context",
"//gpu/skia_bindings:skia_bindings",
+ "//gpu/vulkan:features",
"//mojo/public/cpp/bindings",
"//skia",
"//ui/gfx:color_space",
@@ -75,6 +126,7 @@ viz_component("common") {
]
public_deps = [
+ ":resource_format",
"//gpu/command_buffer/client",
"//gpu/command_buffer/common",
"//mojo/public/cpp/bindings",
@@ -84,6 +136,8 @@ viz_component("common") {
viz_source_set("unit_tests") {
testonly = true
sources = [
+ "frame_sinks/begin_frame_args_unittest.cc",
+ "frame_sinks/delay_based_time_source_unittest.cc",
"gl_helper_unittest.cc",
"resources/buffer_to_texture_target_map_unittest.cc",
"resources/platform_color_unittest.cc",
@@ -94,6 +148,7 @@ viz_source_set("unit_tests") {
deps = [
":common",
"//base/test:test_support",
+ "//components/viz/test:test_support",
"//gpu/command_buffer/client:gles2_implementation",
"//gpu/command_buffer/client:gles2_interface",
"//gpu/ipc:gl_in_process_context",
diff --git a/chromium/components/viz/common/DEPS b/chromium/components/viz/common/DEPS
index 4efdc7698ad..7732773b1b8 100644
--- a/chromium/components/viz/common/DEPS
+++ b/chromium/components/viz/common/DEPS
@@ -7,18 +7,16 @@ specific_include_rules = {
"+gpu/command_buffer/service",
"+gpu/ipc/common",
"+mojo/public/cpp/bindings",
- "+ui/gfx/geometry",
"+services/ui/gpu/interfaces",
"+third_party/skia",
],
".*_unittest\.cc": [
+ "+components/viz/test",
"+gpu/ipc/gl_in_process_context.h",
"+media/base",
- "+ui/gfx",
"+ui/gl",
],
".*_benchmark\.cc": [
"+gpu/ipc/gl_in_process_context.h",
- "+ui/gfx",
],
}
diff --git a/chromium/components/viz/common/README.md b/chromium/components/viz/common/README.md
deleted file mode 100644
index d2e8fd6f3d9..00000000000
--- a/chromium/components/viz/common/README.md
+++ /dev/null
@@ -1,4 +0,0 @@
-This directory contains common code used by implementations of client/, host/,
-and/or service/. It also contains common code used by the users of these
-components (i.e. code outside of //components/viz that use code in client/,
-host/, and/or service/ can also use this code).
diff --git a/chromium/components/viz/common/display/renderer_settings.h b/chromium/components/viz/common/display/renderer_settings.h
index c7fb57c2540..28b529d304e 100644
--- a/chromium/components/viz/common/display/renderer_settings.h
+++ b/chromium/components/viz/common/display/renderer_settings.h
@@ -29,12 +29,15 @@ class VIZ_COMMON_EXPORT RendererSettings {
bool gl_composited_overlay_candidate_quad_border = false;
bool show_overdraw_feedback = false;
bool enable_color_correct_rendering = false;
+ bool use_skia_renderer = false;
int highp_threshold_min = 0;
// Determines whether we disallow non-exact matches when finding resources
// in ResourcePool. Only used for layout or pixel tests, as non-deterministic
// resource sizes can lead to floating point error and noise in these tests.
bool disallow_non_exact_resource_reuse = false;
+
+ int slow_down_compositing_scale_factor = 1;
};
} // namespace viz
diff --git a/chromium/components/viz/common/frame_sinks/begin_frame_args.cc b/chromium/components/viz/common/frame_sinks/begin_frame_args.cc
new file mode 100644
index 00000000000..a955809fdb1
--- /dev/null
+++ b/chromium/components/viz/common/frame_sinks/begin_frame_args.cc
@@ -0,0 +1,130 @@
+// Copyright 2013 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 "components/viz/common/frame_sinks/begin_frame_args.h"
+
+#include "base/trace_event/trace_event_argument.h"
+
+namespace viz {
+
+const char* BeginFrameArgs::TypeToString(BeginFrameArgsType type) {
+ switch (type) {
+ case BeginFrameArgs::INVALID:
+ return "INVALID";
+ case BeginFrameArgs::NORMAL:
+ return "NORMAL";
+ case BeginFrameArgs::MISSED:
+ return "MISSED";
+ case BeginFrameArgs::BEGIN_FRAME_ARGS_TYPE_MAX:
+ return "BEGIN_FRAME_ARGS_TYPE_MAX";
+ }
+ NOTREACHED();
+ return "???";
+}
+
+constexpr uint64_t BeginFrameArgs::kInvalidFrameNumber;
+constexpr uint64_t BeginFrameArgs::kStartingFrameNumber;
+
+BeginFrameArgs::BeginFrameArgs()
+ : frame_time(base::TimeTicks()),
+ deadline(base::TimeTicks()),
+ interval(base::TimeDelta::FromMicroseconds(-1)),
+ sequence_number(kInvalidFrameNumber),
+ source_id(0),
+ type(BeginFrameArgs::INVALID),
+ on_critical_path(true) {}
+
+BeginFrameArgs::BeginFrameArgs(uint32_t source_id,
+ uint64_t sequence_number,
+ base::TimeTicks frame_time,
+ base::TimeTicks deadline,
+ base::TimeDelta interval,
+ BeginFrameArgs::BeginFrameArgsType type)
+ : frame_time(frame_time),
+ deadline(deadline),
+ interval(interval),
+ sequence_number(sequence_number),
+ source_id(source_id),
+ type(type),
+ on_critical_path(true) {
+ DCHECK_LE(kStartingFrameNumber, sequence_number);
+}
+
+BeginFrameArgs BeginFrameArgs::Create(BeginFrameArgs::CreationLocation location,
+ uint32_t source_id,
+ uint64_t sequence_number,
+ base::TimeTicks frame_time,
+ base::TimeTicks deadline,
+ base::TimeDelta interval,
+ BeginFrameArgs::BeginFrameArgsType type) {
+ DCHECK_NE(type, BeginFrameArgs::INVALID);
+ DCHECK_NE(type, BeginFrameArgs::BEGIN_FRAME_ARGS_TYPE_MAX);
+#ifdef NDEBUG
+ return BeginFrameArgs(source_id, sequence_number, frame_time, deadline,
+ interval, type);
+#else
+ BeginFrameArgs args = BeginFrameArgs(source_id, sequence_number, frame_time,
+ deadline, interval, type);
+ args.created_from = location;
+ return args;
+#endif
+}
+
+std::unique_ptr<base::trace_event::ConvertableToTraceFormat>
+BeginFrameArgs::AsValue() const {
+ std::unique_ptr<base::trace_event::TracedValue> state(
+ new base::trace_event::TracedValue());
+ AsValueInto(state.get());
+ return std::move(state);
+}
+
+void BeginFrameArgs::AsValueInto(base::trace_event::TracedValue* state) const {
+ state->SetString("type", "BeginFrameArgs");
+ state->SetString("subtype", TypeToString(type));
+ state->SetInteger("source_id", source_id);
+ state->SetInteger("sequence_number", sequence_number);
+ state->SetDouble("frame_time_us", frame_time.since_origin().InMicroseconds());
+ state->SetDouble("deadline_us", deadline.since_origin().InMicroseconds());
+ state->SetDouble("interval_us", interval.InMicroseconds());
+#ifndef NDEBUG
+ state->SetString("created_from", created_from.ToString());
+#endif
+ state->SetBoolean("on_critical_path", on_critical_path);
+}
+
+// This is a hard-coded deadline adjustment that assumes 60Hz, to be used in
+// cases where a good estimated draw time is not known. Using 1/3 of the vsync
+// as the default adjustment gives the Browser the last 1/3 of a frame to
+// produce output, the Renderer Impl thread the middle 1/3 of a frame to produce
+// ouput, and the Renderer Main thread the first 1/3 of a frame to produce
+// output.
+base::TimeDelta BeginFrameArgs::DefaultEstimatedParentDrawTime() {
+ return base::TimeDelta::FromMicroseconds(16666 / 3);
+}
+
+base::TimeDelta BeginFrameArgs::DefaultInterval() {
+ return base::TimeDelta::FromMicroseconds(16666);
+}
+
+BeginFrameAck::BeginFrameAck()
+ : sequence_number(BeginFrameArgs::kInvalidFrameNumber),
+ source_id(0),
+ has_damage(false) {}
+
+BeginFrameAck::BeginFrameAck(uint32_t source_id,
+ uint64_t sequence_number,
+ bool has_damage)
+ : sequence_number(sequence_number),
+ source_id(source_id),
+ has_damage(has_damage) {
+ DCHECK_LT(BeginFrameArgs::kInvalidFrameNumber, sequence_number);
+}
+
+// static
+BeginFrameAck BeginFrameAck::CreateManualAckWithDamage() {
+ return BeginFrameAck(BeginFrameArgs::kManualSourceId,
+ BeginFrameArgs::kStartingFrameNumber, true);
+}
+
+} // namespace viz
diff --git a/chromium/components/viz/common/frame_sinks/begin_frame_args.h b/chromium/components/viz/common/frame_sinks/begin_frame_args.h
new file mode 100644
index 00000000000..72175015936
--- /dev/null
+++ b/chromium/components/viz/common/frame_sinks/begin_frame_args.h
@@ -0,0 +1,145 @@
+// Copyright 2013 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 COMPONENTS_VIZ_COMMON_FRAME_SINKS_BEGIN_FRAME_ARGS_H_
+#define COMPONENTS_VIZ_COMMON_FRAME_SINKS_BEGIN_FRAME_ARGS_H_
+
+#include <stdint.h>
+#include <memory>
+
+#include "base/location.h"
+#include "base/memory/ref_counted.h"
+#include "base/time/time.h"
+#include "base/values.h"
+#include "components/viz/common/viz_common_export.h"
+
+namespace base {
+namespace trace_event {
+class ConvertableToTraceFormat;
+class TracedValue;
+} // namespace trace_event
+} // namespace base
+
+/**
+ * In debug builds we trace the creation origin of BeginFrameArgs objects. We
+ * reuse the tracked_objects::Location system to do that.
+ *
+ * However, in release builds we don't want this as it doubles the size of the
+ * BeginFrameArgs object. As well it adds a number of largish strings to the
+ * binary. Despite the argument being unused, most compilers are unable to
+ * optimise it away even when unused. Instead we use the BEGINFRAME_FROM_HERE
+ * macro to prevent the data even getting referenced.
+ */
+#ifdef NDEBUG
+#define BEGINFRAME_FROM_HERE nullptr
+#else
+#define BEGINFRAME_FROM_HERE FROM_HERE
+#endif
+
+namespace viz {
+
+struct VIZ_COMMON_EXPORT BeginFrameArgs {
+ enum BeginFrameArgsType {
+ INVALID,
+ NORMAL,
+ MISSED,
+ // Not a real type, but used by the IPC system. Should always remain the
+ // *last* value in this enum.
+ BEGIN_FRAME_ARGS_TYPE_MAX,
+ };
+ static const char* TypeToString(BeginFrameArgsType type);
+
+ static constexpr uint32_t kStartingSourceId = 0;
+ // |source_id| for BeginFrameArgs not created by a BeginFrameSource. Used to
+ // avoid sequence number conflicts of BeginFrameArgs manually fed to an
+ // observer with those fed to the observer by the its BeginFrameSource.
+ static constexpr uint32_t kManualSourceId = UINT32_MAX;
+
+ static constexpr uint64_t kInvalidFrameNumber = 0;
+ static constexpr uint64_t kStartingFrameNumber = 1;
+
+ // Creates an invalid set of values.
+ BeginFrameArgs();
+
+#ifdef NDEBUG
+ typedef const void* CreationLocation;
+#else
+ typedef const tracked_objects::Location& CreationLocation;
+ tracked_objects::Location created_from;
+#endif
+
+ // You should be able to find all instances where a BeginFrame has been
+ // created by searching for "BeginFrameArgs::Create".
+ // The location argument should **always** be BEGINFRAME_FROM_HERE macro.
+ static BeginFrameArgs Create(CreationLocation location,
+ uint32_t source_id,
+ uint64_t sequence_number,
+ base::TimeTicks frame_time,
+ base::TimeTicks deadline,
+ base::TimeDelta interval,
+ BeginFrameArgsType type);
+
+ // This is the default delta that will be used to adjust the deadline when
+ // proper draw-time estimations are not yet available.
+ static base::TimeDelta DefaultEstimatedParentDrawTime();
+
+ // This is the default interval to use to avoid sprinkling the code with
+ // magic numbers.
+ static base::TimeDelta DefaultInterval();
+
+ bool IsValid() const { return interval >= base::TimeDelta(); }
+
+ std::unique_ptr<base::trace_event::ConvertableToTraceFormat> AsValue() const;
+ void AsValueInto(base::trace_event::TracedValue* dict) const;
+
+ base::TimeTicks frame_time;
+ base::TimeTicks deadline;
+ base::TimeDelta interval;
+
+ // |source_id| and |sequence_number| identify a BeginFrame within a single
+ // process and are set by the original BeginFrameSource that created the
+ // BeginFrameArgs. When |source_id| of consecutive BeginFrameArgs changes,
+ // observers should expect the continuity of |sequence_number| to break.
+ uint64_t sequence_number;
+ uint32_t source_id; // |source_id| after |sequence_number| for packing.
+
+ BeginFrameArgsType type;
+ bool on_critical_path;
+
+ private:
+ BeginFrameArgs(uint32_t source_id,
+ uint64_t sequence_number,
+ base::TimeTicks frame_time,
+ base::TimeTicks deadline,
+ base::TimeDelta interval,
+ BeginFrameArgsType type);
+};
+
+// Sent by a BeginFrameObserver as acknowledgment of completing a BeginFrame.
+struct VIZ_COMMON_EXPORT BeginFrameAck {
+ BeginFrameAck();
+ BeginFrameAck(uint32_t source_id, uint64_t sequence_number, bool has_damage);
+
+ // Creates a BeginFrameAck for a manual BeginFrame. Used when clients produce
+ // a CompositorFrame without prior BeginFrame, e.g. for synchronous drawing.
+ static BeginFrameAck CreateManualAckWithDamage();
+
+ // Sequence number of the BeginFrame that is acknowledged.
+ uint64_t sequence_number;
+
+ // Source identifier of the BeginFrame that is acknowledged. The
+ // BeginFrameSource that receives the acknowledgment uses this to discard
+ // BeginFrameAcks for BeginFrames sent by a different source. Such a situation
+ // may occur when the BeginFrameSource of the observer changes while a
+ // BeginFrame from the old source is still in flight.
+ uint32_t source_id; // |source_id| after above fields for packing.
+
+ // |true| if the observer has produced damage (e.g. sent a CompositorFrame or
+ // damaged a surface) as part of responding to the BeginFrame.
+ bool has_damage;
+};
+
+} // namespace viz
+
+#endif // COMPONENTS_VIZ_COMMON_FRAME_SINKS_BEGIN_FRAME_ARGS_H_
diff --git a/chromium/components/viz/common/frame_sinks/begin_frame_args_unittest.cc b/chromium/components/viz/common/frame_sinks/begin_frame_args_unittest.cc
new file mode 100644
index 00000000000..50f898bb15a
--- /dev/null
+++ b/chromium/components/viz/common/frame_sinks/begin_frame_args_unittest.cc
@@ -0,0 +1,125 @@
+// Copyright 2014 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 <string>
+
+#include "components/viz/common/frame_sinks/begin_frame_args.h"
+#include "components/viz/test/begin_frame_args_test.h"
+#include "testing/gtest/include/gtest/gtest-spi.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace viz {
+namespace {
+
+constexpr base::TimeDelta k1Usec = base::TimeDelta::FromMicroseconds(1);
+constexpr base::TimeDelta k2Usec = base::TimeDelta::FromMicroseconds(2);
+constexpr base::TimeDelta k3Usec = base::TimeDelta::FromMicroseconds(3);
+
+TEST(BeginFrameArgsTest, Helpers) {
+ // Quick create methods work
+ BeginFrameArgs args0 =
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 1);
+ EXPECT_TRUE(args0.IsValid()) << args0;
+
+ BeginFrameArgs args1 =
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 1, 0, 0, -1);
+ EXPECT_FALSE(args1.IsValid()) << args1;
+
+ BeginFrameArgs args2 =
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 123, 10, 1, 2, 3);
+ EXPECT_TRUE(args2.IsValid()) << args2;
+ EXPECT_EQ(123u, args2.source_id);
+ EXPECT_EQ(10u, args2.sequence_number);
+ EXPECT_EQ(k1Usec, args2.frame_time.since_origin());
+ EXPECT_EQ(k2Usec, args2.deadline.since_origin());
+ EXPECT_EQ(k3Usec, args2.interval);
+ EXPECT_EQ(BeginFrameArgs::NORMAL, args2.type);
+
+ BeginFrameArgs args4 = CreateBeginFrameArgsForTesting(
+ BEGINFRAME_FROM_HERE, 234, 20, 1, 2, 3, BeginFrameArgs::MISSED);
+ EXPECT_TRUE(args4.IsValid()) << args4;
+ EXPECT_EQ(234u, args4.source_id);
+ EXPECT_EQ(20u, args4.sequence_number);
+ EXPECT_EQ(k1Usec, args4.frame_time.since_origin());
+ EXPECT_EQ(k2Usec, args4.deadline.since_origin());
+ EXPECT_EQ(k3Usec, args4.interval);
+ EXPECT_EQ(BeginFrameArgs::MISSED, args4.type);
+
+ // operator==
+ EXPECT_EQ(
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 123, 20, 4, 5, 6),
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 123, 20, 4, 5, 6));
+
+ EXPECT_NONFATAL_FAILURE(
+ EXPECT_EQ(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 123, 30, 7,
+ 8, 9, BeginFrameArgs::MISSED),
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 123, 30, 7,
+ 8, 9)),
+ "");
+
+ EXPECT_NONFATAL_FAILURE(
+ EXPECT_EQ(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 123, 30, 4,
+ 5, 6),
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 123, 30, 7,
+ 8, 9)),
+ "");
+
+ EXPECT_NONFATAL_FAILURE(
+ EXPECT_EQ(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 123, 30, 7,
+ 8, 9),
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 123, 40, 7,
+ 8, 9)),
+ "");
+
+ EXPECT_NONFATAL_FAILURE(
+ EXPECT_EQ(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 123, 30, 7,
+ 8, 9),
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 234, 30, 7,
+ 8, 9)),
+ "");
+
+ // operator<<
+ std::stringstream out1;
+ out1 << args1;
+ EXPECT_EQ("BeginFrameArgs(NORMAL, 0, 1, 0, 0, -1us)", out1.str());
+ std::stringstream out2;
+ out2 << args2;
+ EXPECT_EQ("BeginFrameArgs(NORMAL, 123, 10, 1, 2, 3us)", out2.str());
+
+ // PrintTo
+ EXPECT_EQ(std::string("BeginFrameArgs(NORMAL, 0, 1, 0, 0, -1us)"),
+ ::testing::PrintToString(args1));
+ EXPECT_EQ(std::string("BeginFrameArgs(NORMAL, 123, 10, 1, 2, 3us)"),
+ ::testing::PrintToString(args2));
+}
+
+TEST(BeginFrameArgsTest, Create) {
+ // BeginFrames are not valid by default
+ BeginFrameArgs args1;
+ EXPECT_FALSE(args1.IsValid()) << args1;
+ EXPECT_TRUE(args1.on_critical_path);
+
+ BeginFrameArgs args2 = BeginFrameArgs::Create(
+ BEGINFRAME_FROM_HERE, 123, 10, base::TimeTicks() + k1Usec,
+ base::TimeTicks() + k2Usec, k3Usec, BeginFrameArgs::NORMAL);
+ EXPECT_TRUE(args2.IsValid()) << args2;
+ EXPECT_EQ(123u, args2.source_id) << args2;
+ EXPECT_EQ(10u, args2.sequence_number) << args2;
+ EXPECT_EQ(k1Usec, args2.frame_time.since_origin()) << args2;
+ EXPECT_EQ(k2Usec, args2.deadline.since_origin()) << args2;
+ EXPECT_EQ(k3Usec, args2.interval) << args2;
+ EXPECT_EQ(BeginFrameArgs::NORMAL, args2.type) << args2;
+}
+
+#ifndef NDEBUG
+TEST(BeginFrameArgsTest, Location) {
+ tracked_objects::Location expected_location = BEGINFRAME_FROM_HERE;
+
+ BeginFrameArgs args = CreateBeginFrameArgsForTesting(expected_location, 0, 1);
+ EXPECT_EQ(expected_location.ToString(), args.created_from.ToString());
+}
+#endif
+
+} // namespace
+} // namespace viz
diff --git a/chromium/components/viz/common/frame_sinks/begin_frame_source.cc b/chromium/components/viz/common/frame_sinks/begin_frame_source.cc
new file mode 100644
index 00000000000..7b3729259de
--- /dev/null
+++ b/chromium/components/viz/common/frame_sinks/begin_frame_source.cc
@@ -0,0 +1,354 @@
+// Copyright 2014 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 "components/viz/common/frame_sinks/begin_frame_source.h"
+
+#include <stddef.h>
+
+#include "base/atomic_sequence_num.h"
+#include "base/auto_reset.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/memory/ptr_util.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/stringprintf.h"
+#include "base/trace_event/trace_event.h"
+#include "base/trace_event/trace_event_argument.h"
+#include "components/viz/common/frame_sinks/delay_based_time_source.h"
+
+namespace viz {
+
+namespace {
+// kDoubleTickDivisor prevents the SyntheticBFS from sending BeginFrames too
+// often to an observer.
+static const double kDoubleTickDivisor = 2.0;
+} // namespace
+
+// BeginFrameObserverBase -------------------------------------------------
+BeginFrameObserverBase::BeginFrameObserverBase() = default;
+
+BeginFrameObserverBase::~BeginFrameObserverBase() = default;
+
+const BeginFrameArgs& BeginFrameObserverBase::LastUsedBeginFrameArgs() const {
+ return last_begin_frame_args_;
+}
+
+void BeginFrameObserverBase::OnBeginFrame(const BeginFrameArgs& args) {
+ DCHECK(args.IsValid());
+ DCHECK(args.frame_time >= last_begin_frame_args_.frame_time);
+ DCHECK(args.sequence_number > last_begin_frame_args_.sequence_number ||
+ args.source_id != last_begin_frame_args_.source_id)
+ << "current " << args.AsValue()->ToString() << ", last "
+ << last_begin_frame_args_.AsValue()->ToString();
+ bool used = OnBeginFrameDerivedImpl(args);
+ if (used) {
+ last_begin_frame_args_ = args;
+ } else {
+ ++dropped_begin_frame_args_;
+ }
+}
+
+void BeginFrameObserverBase::AsValueInto(
+ base::trace_event::TracedValue* state) const {
+ state->SetInteger("dropped_begin_frame_args", dropped_begin_frame_args_);
+
+ state->BeginDictionary("last_begin_frame_args");
+ last_begin_frame_args_.AsValueInto(state);
+ state->EndDictionary();
+}
+
+// BeginFrameSource -------------------------------------------------------
+namespace {
+static base::AtomicSequenceNumber g_next_source_id;
+} // namespace
+
+BeginFrameSource::BeginFrameSource() : source_id_(g_next_source_id.GetNext()) {}
+
+BeginFrameSource::~BeginFrameSource() = default;
+
+void BeginFrameSource::AsValueInto(
+ base::trace_event::TracedValue* state) const {
+ state->SetInteger("source_id", source_id_);
+}
+
+// StubBeginFrameSource ---------------------------------------------------
+bool StubBeginFrameSource::IsThrottled() const {
+ return true;
+}
+
+// SyntheticBeginFrameSource ----------------------------------------------
+SyntheticBeginFrameSource::~SyntheticBeginFrameSource() = default;
+
+// BackToBackBeginFrameSource ---------------------------------------------
+BackToBackBeginFrameSource::BackToBackBeginFrameSource(
+ std::unique_ptr<DelayBasedTimeSource> time_source)
+ : time_source_(std::move(time_source)),
+ next_sequence_number_(BeginFrameArgs::kStartingFrameNumber),
+ weak_factory_(this) {
+ time_source_->SetClient(this);
+ // The time_source_ ticks immediately, so we SetActive(true) for a single
+ // tick when we need it, and keep it as SetActive(false) otherwise.
+ time_source_->SetTimebaseAndInterval(base::TimeTicks(), base::TimeDelta());
+}
+
+BackToBackBeginFrameSource::~BackToBackBeginFrameSource() = default;
+
+void BackToBackBeginFrameSource::AddObserver(BeginFrameObserver* obs) {
+ DCHECK(obs);
+ DCHECK(observers_.find(obs) == observers_.end());
+ observers_.insert(obs);
+ pending_begin_frame_observers_.insert(obs);
+ obs->OnBeginFrameSourcePausedChanged(false);
+ time_source_->SetActive(true);
+}
+
+void BackToBackBeginFrameSource::RemoveObserver(BeginFrameObserver* obs) {
+ DCHECK(obs);
+ DCHECK(observers_.find(obs) != observers_.end());
+ observers_.erase(obs);
+ pending_begin_frame_observers_.erase(obs);
+ if (pending_begin_frame_observers_.empty())
+ time_source_->SetActive(false);
+}
+
+void BackToBackBeginFrameSource::DidFinishFrame(BeginFrameObserver* obs) {
+ if (observers_.find(obs) != observers_.end()) {
+ pending_begin_frame_observers_.insert(obs);
+ time_source_->SetActive(true);
+ }
+}
+
+bool BackToBackBeginFrameSource::IsThrottled() const {
+ return false;
+}
+
+void BackToBackBeginFrameSource::OnTimerTick() {
+ base::TimeTicks frame_time = time_source_->LastTickTime();
+ base::TimeDelta default_interval = BeginFrameArgs::DefaultInterval();
+ BeginFrameArgs args = BeginFrameArgs::Create(
+ BEGINFRAME_FROM_HERE, source_id(), next_sequence_number_, frame_time,
+ frame_time + default_interval, default_interval, BeginFrameArgs::NORMAL);
+ next_sequence_number_++;
+
+ // This must happen after getting the LastTickTime() from the time source.
+ time_source_->SetActive(false);
+
+ std::unordered_set<BeginFrameObserver*> pending_observers;
+ pending_observers.swap(pending_begin_frame_observers_);
+ DCHECK(!pending_observers.empty());
+ for (BeginFrameObserver* obs : pending_observers)
+ obs->OnBeginFrame(args);
+}
+
+// DelayBasedBeginFrameSource ---------------------------------------------
+DelayBasedBeginFrameSource::DelayBasedBeginFrameSource(
+ std::unique_ptr<DelayBasedTimeSource> time_source)
+ : time_source_(std::move(time_source)),
+ next_sequence_number_(BeginFrameArgs::kStartingFrameNumber) {
+ time_source_->SetClient(this);
+}
+
+DelayBasedBeginFrameSource::~DelayBasedBeginFrameSource() = default;
+
+void DelayBasedBeginFrameSource::OnUpdateVSyncParameters(
+ base::TimeTicks timebase,
+ base::TimeDelta interval) {
+ if (!authoritative_interval_.is_zero()) {
+ interval = authoritative_interval_;
+ } else if (interval.is_zero()) {
+ // TODO(brianderson): We should not be receiving 0 intervals.
+ interval = BeginFrameArgs::DefaultInterval();
+ }
+
+ last_timebase_ = timebase;
+ time_source_->SetTimebaseAndInterval(timebase, interval);
+}
+
+void DelayBasedBeginFrameSource::SetAuthoritativeVSyncInterval(
+ base::TimeDelta interval) {
+ authoritative_interval_ = interval;
+ OnUpdateVSyncParameters(last_timebase_, interval);
+}
+
+BeginFrameArgs DelayBasedBeginFrameSource::CreateBeginFrameArgs(
+ base::TimeTicks frame_time) {
+ uint64_t sequence_number = next_sequence_number_++;
+ return BeginFrameArgs::Create(
+ BEGINFRAME_FROM_HERE, source_id(), sequence_number, frame_time,
+ time_source_->NextTickTime(), time_source_->Interval(),
+ BeginFrameArgs::NORMAL);
+}
+
+void DelayBasedBeginFrameSource::AddObserver(BeginFrameObserver* obs) {
+ DCHECK(obs);
+ DCHECK(observers_.find(obs) == observers_.end());
+
+ observers_.insert(obs);
+ obs->OnBeginFrameSourcePausedChanged(false);
+ time_source_->SetActive(true);
+
+ // Missed args should correspond to |last_begin_frame_args_| (particularly,
+ // have the same sequence number) if |last_begin_frame_args_| still correspond
+ // to the last time the time source should have ticked. This may not be the
+ // case if the time source was inactive before AddObserver() was called. In
+ // such a case, we create new args with a new sequence number only if
+ // sufficient time has passed since the last tick.
+ base::TimeTicks last_or_missed_tick_time =
+ time_source_->NextTickTime() - time_source_->Interval();
+ if (!last_begin_frame_args_.IsValid() ||
+ last_or_missed_tick_time >
+ last_begin_frame_args_.frame_time +
+ last_begin_frame_args_.interval / kDoubleTickDivisor) {
+ last_begin_frame_args_ = CreateBeginFrameArgs(last_or_missed_tick_time);
+ }
+ BeginFrameArgs missed_args = last_begin_frame_args_;
+ missed_args.type = BeginFrameArgs::MISSED;
+
+ BeginFrameArgs last_args = obs->LastUsedBeginFrameArgs();
+ if (!last_args.IsValid() ||
+ (missed_args.frame_time >
+ last_args.frame_time + missed_args.interval / kDoubleTickDivisor)) {
+ DCHECK(missed_args.sequence_number > last_args.sequence_number ||
+ missed_args.source_id != last_args.source_id)
+ << "missed " << missed_args.AsValue()->ToString() << ", last "
+ << last_args.AsValue()->ToString();
+ obs->OnBeginFrame(missed_args);
+ }
+}
+
+void DelayBasedBeginFrameSource::RemoveObserver(BeginFrameObserver* obs) {
+ DCHECK(obs);
+ DCHECK(observers_.find(obs) != observers_.end());
+
+ observers_.erase(obs);
+ if (observers_.empty())
+ time_source_->SetActive(false);
+}
+
+bool DelayBasedBeginFrameSource::IsThrottled() const {
+ return true;
+}
+
+void DelayBasedBeginFrameSource::OnTimerTick() {
+ last_begin_frame_args_ = CreateBeginFrameArgs(time_source_->LastTickTime());
+ std::unordered_set<BeginFrameObserver*> observers(observers_);
+ for (auto* obs : observers) {
+ BeginFrameArgs last_args = obs->LastUsedBeginFrameArgs();
+ if (!last_args.IsValid() ||
+ (last_begin_frame_args_.frame_time >
+ last_args.frame_time +
+ last_begin_frame_args_.interval / kDoubleTickDivisor)) {
+ obs->OnBeginFrame(last_begin_frame_args_);
+ }
+ }
+}
+
+// ExternalBeginFrameSource -----------------------------------------------
+ExternalBeginFrameSource::ExternalBeginFrameSource(
+ ExternalBeginFrameSourceClient* client)
+ : client_(client) {
+ DCHECK(client_);
+}
+
+ExternalBeginFrameSource::~ExternalBeginFrameSource() = default;
+
+void ExternalBeginFrameSource::AsValueInto(
+ base::trace_event::TracedValue* state) const {
+ BeginFrameSource::AsValueInto(state);
+
+ state->SetBoolean("paused", paused_);
+ state->SetInteger("num_observers", observers_.size());
+
+ state->BeginDictionary("last_begin_frame_args");
+ last_begin_frame_args_.AsValueInto(state);
+ state->EndDictionary();
+}
+
+void ExternalBeginFrameSource::AddObserver(BeginFrameObserver* obs) {
+ DCHECK(obs);
+ DCHECK(observers_.find(obs) == observers_.end());
+
+ bool observers_was_empty = observers_.empty();
+ observers_.insert(obs);
+ obs->OnBeginFrameSourcePausedChanged(paused_);
+ if (observers_was_empty)
+ client_->OnNeedsBeginFrames(true);
+
+ // Send a MISSED begin frame if necessary.
+ BeginFrameArgs missed_args = GetMissedBeginFrameArgs(obs);
+ if (missed_args.IsValid()) {
+ DCHECK_EQ(BeginFrameArgs::MISSED, missed_args.type);
+ obs->OnBeginFrame(missed_args);
+ }
+}
+
+void ExternalBeginFrameSource::RemoveObserver(BeginFrameObserver* obs) {
+ DCHECK(obs);
+ DCHECK(observers_.find(obs) != observers_.end());
+
+ observers_.erase(obs);
+ if (observers_.empty())
+ client_->OnNeedsBeginFrames(false);
+}
+
+bool ExternalBeginFrameSource::IsThrottled() const {
+ return true;
+}
+
+void ExternalBeginFrameSource::OnSetBeginFrameSourcePaused(bool paused) {
+ if (paused_ == paused)
+ return;
+ paused_ = paused;
+ std::unordered_set<BeginFrameObserver*> observers(observers_);
+ for (auto* obs : observers)
+ obs->OnBeginFrameSourcePausedChanged(paused_);
+}
+
+void ExternalBeginFrameSource::OnBeginFrame(const BeginFrameArgs& args) {
+ // Ignore out of order begin frames because of layer tree frame sink being
+ // recreated.
+ if (last_begin_frame_args_.IsValid() &&
+ (args.frame_time <= last_begin_frame_args_.frame_time ||
+ (args.source_id == last_begin_frame_args_.source_id &&
+ args.sequence_number <= last_begin_frame_args_.sequence_number)))
+ return;
+
+ last_begin_frame_args_ = args;
+ std::unordered_set<BeginFrameObserver*> observers(observers_);
+ for (auto* obs : observers) {
+ // It is possible that the source in which |args| originate changes, or that
+ // our hookup to this source changes, so we have to check for continuity.
+ // See also https://crbug.com/690127 for what may happen without this check.
+ const BeginFrameArgs& last_args = obs->LastUsedBeginFrameArgs();
+ if (!last_args.IsValid() || (args.frame_time > last_args.frame_time)) {
+ DCHECK((args.source_id != last_args.source_id) ||
+ (args.sequence_number > last_args.sequence_number))
+ << "current " << args.AsValue()->ToString() << ", last "
+ << last_args.AsValue()->ToString();
+ obs->OnBeginFrame(args);
+ }
+ }
+}
+
+BeginFrameArgs ExternalBeginFrameSource::GetMissedBeginFrameArgs(
+ BeginFrameObserver* obs) {
+ if (!last_begin_frame_args_.IsValid())
+ return BeginFrameArgs();
+
+ const BeginFrameArgs& last_args = obs->LastUsedBeginFrameArgs();
+ if (last_args.IsValid() &&
+ last_begin_frame_args_.frame_time <= last_args.frame_time) {
+ return BeginFrameArgs();
+ }
+
+ DCHECK((last_begin_frame_args_.source_id != last_args.source_id) ||
+ (last_begin_frame_args_.sequence_number > last_args.sequence_number))
+ << "current " << last_begin_frame_args_.AsValue()->ToString() << ", last "
+ << last_args.AsValue()->ToString();
+ BeginFrameArgs missed_args = last_begin_frame_args_;
+ missed_args.type = BeginFrameArgs::MISSED;
+ return missed_args;
+}
+
+} // namespace viz
diff --git a/chromium/components/viz/common/frame_sinks/begin_frame_source.h b/chromium/components/viz/common/frame_sinks/begin_frame_source.h
new file mode 100644
index 00000000000..8c6c46201fe
--- /dev/null
+++ b/chromium/components/viz/common/frame_sinks/begin_frame_source.h
@@ -0,0 +1,275 @@
+// Copyright 2014 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 COMPONENTS_VIZ_COMMON_FRAME_SINKS_BEGIN_FRAME_SOURCE_H_
+#define COMPONENTS_VIZ_COMMON_FRAME_SINKS_BEGIN_FRAME_SOURCE_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <set>
+#include <string>
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/trace_event/trace_event.h"
+#include "components/viz/common/frame_sinks/begin_frame_args.h"
+#include "components/viz/common/frame_sinks/delay_based_time_source.h"
+
+namespace viz {
+
+// (Pure) Interface for observing BeginFrame messages from BeginFrameSource
+// objects.
+class VIZ_COMMON_EXPORT BeginFrameObserver {
+ public:
+ virtual ~BeginFrameObserver() {}
+
+ // The |args| given to OnBeginFrame is guaranteed to have
+ // |args|.IsValid()==true. If |args|.source_id did not change between
+ // invocations, |args|.sequence_number is guaranteed to be be strictly greater
+ // than the previous call. Further, |args|.frame_time is guaranteed to be
+ // greater than or equal to the previous call even if the source_id changes.
+ //
+ // Side effects: This function can (and most of the time *will*) change the
+ // return value of the LastUsedBeginFrameArgs method. See the documentation
+ // on that method for more information.
+ //
+ // The observer is required call BeginFrameSource::DidFinishFrame() as soon as
+ // it has completed handling the BeginFrame.
+ virtual void OnBeginFrame(const BeginFrameArgs& args) = 0;
+
+ // Returns the last BeginFrameArgs used by the observer. This method's
+ // return value is affected by the OnBeginFrame method!
+ //
+ // - Before the first call of OnBeginFrame, this method should return a
+ // BeginFrameArgs on which IsValid() returns false.
+ //
+ // - If the |args| passed to OnBeginFrame is (or *will be*) used, then
+ // LastUsedBeginFrameArgs return value should become the |args| given to
+ // OnBeginFrame.
+ //
+ // - If the |args| passed to OnBeginFrame is dropped, then
+ // LastUsedBeginFrameArgs return value should *not* change.
+ //
+ // These requirements are designed to allow chaining and nesting of
+ // BeginFrameObservers which filter the incoming BeginFrame messages while
+ // preventing "double dropping" and other bad side effects.
+ virtual const BeginFrameArgs& LastUsedBeginFrameArgs() const = 0;
+
+ virtual void OnBeginFrameSourcePausedChanged(bool paused) = 0;
+};
+
+// Simple base class which implements a BeginFrameObserver which checks the
+// incoming values meet the BeginFrameObserver requirements and implements the
+// required LastUsedBeginFrameArgs behaviour.
+//
+// Users of this class should;
+// - Implement the OnBeginFrameDerivedImpl function.
+// - Recommended (but not required) to call
+// BeginFrameObserverBase::OnValueInto in their overridden OnValueInto
+// function.
+class VIZ_COMMON_EXPORT BeginFrameObserverBase : public BeginFrameObserver {
+ public:
+ BeginFrameObserverBase();
+ ~BeginFrameObserverBase() override;
+
+ // BeginFrameObserver
+
+ // Traces |args| and DCHECK |args| satisfies pre-conditions then calls
+ // OnBeginFrameDerivedImpl and updates the last_begin_frame_args_ value on
+ // true.
+ void OnBeginFrame(const BeginFrameArgs& args) override;
+ const BeginFrameArgs& LastUsedBeginFrameArgs() const override;
+
+ protected:
+ // Return true if the given argument is (or will be) used.
+ virtual bool OnBeginFrameDerivedImpl(const BeginFrameArgs& args) = 0;
+
+ void AsValueInto(base::trace_event::TracedValue* state) const;
+
+ BeginFrameArgs last_begin_frame_args_;
+ int64_t dropped_begin_frame_args_ = 0;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(BeginFrameObserverBase);
+};
+
+// Interface for a class which produces BeginFrame calls to a
+// BeginFrameObserver.
+//
+// BeginFrame calls *normally* occur just after a vsync interrupt when input
+// processing has been finished and provide information about the time values
+// of the vsync times. *However*, these values can be heavily modified or even
+// plain made up (when no vsync signal is available or vsync throttling is
+// turned off). See the BeginFrameObserver for information about the guarantees
+// all BeginFrameSources *must* provide.
+class VIZ_COMMON_EXPORT BeginFrameSource {
+ public:
+ BeginFrameSource();
+ virtual ~BeginFrameSource();
+
+ // Returns an identifier for this BeginFrameSource. Guaranteed unique within a
+ // process, but not across processes. This is used to create BeginFrames that
+ // originate at this source. Note that BeginFrameSources may pass on
+ // BeginFrames created by other sources, with different IDs.
+ uint32_t source_id() const { return source_id_; }
+
+ // BeginFrameObservers use DidFinishFrame to provide back pressure to a frame
+ // source about frame processing (rather than toggling SetNeedsBeginFrames
+ // every frame). For example, the BackToBackFrameSource uses them to make sure
+ // only one frame is pending at a time.
+ virtual void DidFinishFrame(BeginFrameObserver* obs) = 0;
+
+ // Add/Remove an observer from the source. When no observers are added the BFS
+ // should shut down its timers, disable vsync, etc.
+ virtual void AddObserver(BeginFrameObserver* obs) = 0;
+ virtual void RemoveObserver(BeginFrameObserver* obs) = 0;
+
+ // Returns false if the begin frame source will just continue to produce
+ // begin frames without waiting.
+ virtual bool IsThrottled() const = 0;
+
+ virtual void AsValueInto(base::trace_event::TracedValue* state) const;
+
+ private:
+ uint32_t source_id_;
+
+ DISALLOW_COPY_AND_ASSIGN(BeginFrameSource);
+};
+
+// A BeginFrameSource that does nothing.
+class VIZ_COMMON_EXPORT StubBeginFrameSource : public BeginFrameSource {
+ public:
+ void DidFinishFrame(BeginFrameObserver* obs) override {}
+ void AddObserver(BeginFrameObserver* obs) override {}
+ void RemoveObserver(BeginFrameObserver* obs) override {}
+ bool IsThrottled() const override;
+};
+
+// A frame source which ticks itself independently.
+class VIZ_COMMON_EXPORT SyntheticBeginFrameSource : public BeginFrameSource {
+ public:
+ ~SyntheticBeginFrameSource() override;
+
+ virtual void OnUpdateVSyncParameters(base::TimeTicks timebase,
+ base::TimeDelta interval) = 0;
+ // This overrides any past or future interval from updating vsync parameters.
+ virtual void SetAuthoritativeVSyncInterval(base::TimeDelta interval) = 0;
+};
+
+// A frame source which calls BeginFrame (at the next possible time) as soon as
+// an observer acknowledges the prior BeginFrame.
+class VIZ_COMMON_EXPORT BackToBackBeginFrameSource
+ : public SyntheticBeginFrameSource,
+ public DelayBasedTimeSourceClient {
+ public:
+ explicit BackToBackBeginFrameSource(
+ std::unique_ptr<DelayBasedTimeSource> time_source);
+ ~BackToBackBeginFrameSource() override;
+
+ // BeginFrameSource implementation.
+ void AddObserver(BeginFrameObserver* obs) override;
+ void RemoveObserver(BeginFrameObserver* obs) override;
+ void DidFinishFrame(BeginFrameObserver* obs) override;
+ bool IsThrottled() const override;
+
+ // SyntheticBeginFrameSource implementation.
+ void OnUpdateVSyncParameters(base::TimeTicks timebase,
+ base::TimeDelta interval) override {}
+ void SetAuthoritativeVSyncInterval(base::TimeDelta interval) override {}
+
+ // DelayBasedTimeSourceClient implementation.
+ void OnTimerTick() override;
+
+ private:
+ std::unique_ptr<DelayBasedTimeSource> time_source_;
+ std::unordered_set<BeginFrameObserver*> observers_;
+ std::unordered_set<BeginFrameObserver*> pending_begin_frame_observers_;
+ uint64_t next_sequence_number_;
+ base::WeakPtrFactory<BackToBackBeginFrameSource> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(BackToBackBeginFrameSource);
+};
+
+// A frame source which is locked to an external parameters provides from a
+// vsync source and generates BeginFrameArgs for it.
+class VIZ_COMMON_EXPORT DelayBasedBeginFrameSource
+ : public SyntheticBeginFrameSource,
+ public DelayBasedTimeSourceClient {
+ public:
+ explicit DelayBasedBeginFrameSource(
+ std::unique_ptr<DelayBasedTimeSource> time_source);
+ ~DelayBasedBeginFrameSource() override;
+
+ // BeginFrameSource implementation.
+ void AddObserver(BeginFrameObserver* obs) override;
+ void RemoveObserver(BeginFrameObserver* obs) override;
+ void DidFinishFrame(BeginFrameObserver* obs) override {}
+ bool IsThrottled() const override;
+
+ // SyntheticBeginFrameSource implementation.
+ void OnUpdateVSyncParameters(base::TimeTicks timebase,
+ base::TimeDelta interval) override;
+ void SetAuthoritativeVSyncInterval(base::TimeDelta interval) override;
+
+ // DelayBasedTimeSourceClient implementation.
+ void OnTimerTick() override;
+
+ private:
+ BeginFrameArgs CreateBeginFrameArgs(base::TimeTicks frame_time);
+
+ std::unique_ptr<DelayBasedTimeSource> time_source_;
+ std::unordered_set<BeginFrameObserver*> observers_;
+ base::TimeTicks last_timebase_;
+ base::TimeDelta authoritative_interval_;
+ BeginFrameArgs last_begin_frame_args_;
+ uint64_t next_sequence_number_;
+
+ DISALLOW_COPY_AND_ASSIGN(DelayBasedBeginFrameSource);
+};
+
+class VIZ_COMMON_EXPORT ExternalBeginFrameSourceClient {
+ public:
+ // Only called when changed. Assumed false by default.
+ virtual void OnNeedsBeginFrames(bool needs_begin_frames) = 0;
+};
+
+// A BeginFrameSource that is only ticked manually. Usually the endpoint
+// of messages from some other thread/process that send OnBeginFrame and
+// receive SetNeedsBeginFrame messages. This turns such messages back into
+// an observable BeginFrameSource.
+class VIZ_COMMON_EXPORT ExternalBeginFrameSource : public BeginFrameSource {
+ public:
+ // Client lifetime must be preserved by owner past the lifetime of this class.
+ explicit ExternalBeginFrameSource(ExternalBeginFrameSourceClient* client);
+ ~ExternalBeginFrameSource() override;
+
+ // BeginFrameSource implementation.
+ void AddObserver(BeginFrameObserver* obs) override;
+ void RemoveObserver(BeginFrameObserver* obs) override;
+ void DidFinishFrame(BeginFrameObserver* obs) override {}
+ bool IsThrottled() const override;
+ void AsValueInto(base::trace_event::TracedValue* state) const override;
+
+ void OnSetBeginFrameSourcePaused(bool paused);
+ void OnBeginFrame(const BeginFrameArgs& args);
+
+ protected:
+ // Called on AddObserver and gets missed BeginFrameArgs for the given
+ // observer. The missed BeginFrame is sent only if the returned
+ // BeginFrameArgs is valid.
+ virtual BeginFrameArgs GetMissedBeginFrameArgs(BeginFrameObserver* obs);
+
+ BeginFrameArgs last_begin_frame_args_;
+ std::unordered_set<BeginFrameObserver*> observers_;
+ ExternalBeginFrameSourceClient* client_;
+ bool paused_ = false;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ExternalBeginFrameSource);
+};
+
+} // namespace viz
+
+#endif // COMPONENTS_VIZ_COMMON_FRAME_SINKS_BEGIN_FRAME_SOURCE_H_
diff --git a/chromium/components/viz/common/frame_sinks/begin_frame_source_unittest.cc b/chromium/components/viz/common/frame_sinks/begin_frame_source_unittest.cc
new file mode 100644
index 00000000000..0b646241e63
--- /dev/null
+++ b/chromium/components/viz/common/frame_sinks/begin_frame_source_unittest.cc
@@ -0,0 +1,610 @@
+// Copyright 2011 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 "components/viz/common/frame_sinks/begin_frame_source.h"
+
+#include <stdint.h>
+
+#include "base/memory/ptr_util.h"
+#include "base/test/test_simple_task_runner.h"
+#include "components/viz/test/begin_frame_args_test.h"
+#include "components/viz/test/begin_frame_source_test.h"
+#include "components/viz/test/fake_delay_based_time_source.h"
+#include "components/viz/test/ordered_simple_task_runner.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::NiceMock;
+using testing::_;
+
+namespace viz {
+namespace {
+
+// Returns a fake TimeTicks based on the given microsecond offset.
+base::TimeTicks TicksFromMicroseconds(int64_t micros) {
+ return base::TimeTicks() + base::TimeDelta::FromMicroseconds(micros);
+}
+
+// BeginFrameSource testing ----------------------------------------------------
+TEST(BeginFrameSourceTest, SourceIdsAreUnique) {
+ StubBeginFrameSource source1;
+ StubBeginFrameSource source2;
+ StubBeginFrameSource source3;
+ EXPECT_NE(source1.source_id(), source2.source_id());
+ EXPECT_NE(source1.source_id(), source3.source_id());
+ EXPECT_NE(source2.source_id(), source3.source_id());
+}
+
+// BackToBackBeginFrameSource testing
+// ------------------------------------------
+class BackToBackBeginFrameSourceTest : public ::testing::Test {
+ protected:
+ static const int64_t kDeadline;
+ static const int64_t kInterval;
+
+ void SetUp() override {
+ now_src_.reset(new base::SimpleTestTickClock());
+ now_src_->Advance(base::TimeDelta::FromMicroseconds(1000));
+ task_runner_ =
+ make_scoped_refptr(new OrderedSimpleTaskRunner(now_src_.get(), false));
+ std::unique_ptr<FakeDelayBasedTimeSource> time_source(
+ new FakeDelayBasedTimeSource(now_src_.get(), task_runner_.get()));
+ delay_based_time_source_ = time_source.get();
+ source_.reset(new BackToBackBeginFrameSource(std::move(time_source)));
+ obs_ = base::WrapUnique(new ::testing::NiceMock<MockBeginFrameObserver>);
+ }
+
+ void TearDown() override { obs_.reset(); }
+
+ std::unique_ptr<base::SimpleTestTickClock> now_src_;
+ scoped_refptr<OrderedSimpleTaskRunner> task_runner_;
+ std::unique_ptr<BackToBackBeginFrameSource> source_;
+ std::unique_ptr<MockBeginFrameObserver> obs_;
+ FakeDelayBasedTimeSource* delay_based_time_source_; // Owned by |now_src_|.
+};
+
+const int64_t BackToBackBeginFrameSourceTest::kDeadline =
+ BeginFrameArgs::DefaultInterval().InMicroseconds();
+
+const int64_t BackToBackBeginFrameSourceTest::kInterval =
+ BeginFrameArgs::DefaultInterval().InMicroseconds();
+
+TEST_F(BackToBackBeginFrameSourceTest, AddObserverSendsBeginFrame) {
+ EXPECT_BEGIN_FRAME_SOURCE_PAUSED(*obs_, false);
+ source_->AddObserver(obs_.get());
+ EXPECT_TRUE(task_runner_->HasPendingTasks());
+ EXPECT_BEGIN_FRAME_USED(*obs_, source_->source_id(), 1, 1000,
+ 1000 + kDeadline, kInterval);
+ task_runner_->RunPendingTasks();
+
+ EXPECT_BEGIN_FRAME_USED(*obs_, source_->source_id(), 2, 1100,
+ 1100 + kDeadline, kInterval);
+ now_src_->Advance(base::TimeDelta::FromMicroseconds(100));
+ source_->DidFinishFrame(obs_.get());
+ task_runner_->RunPendingTasks();
+}
+
+TEST_F(BackToBackBeginFrameSourceTest,
+ RemoveObserverThenDidFinishFrameProducesNoFrame) {
+ EXPECT_BEGIN_FRAME_SOURCE_PAUSED(*obs_, false);
+ source_->AddObserver(obs_.get());
+ EXPECT_BEGIN_FRAME_USED(*obs_, source_->source_id(), 1, 1000,
+ 1000 + kDeadline, kInterval);
+ task_runner_->RunPendingTasks();
+
+ source_->RemoveObserver(obs_.get());
+ source_->DidFinishFrame(obs_.get());
+
+ // Verify no BeginFrame is sent to |obs_|. There is a pending task in the
+ // task_runner_ as a BeginFrame was posted, but it gets aborted since |obs_|
+ // is removed.
+ task_runner_->RunPendingTasks();
+ EXPECT_FALSE(task_runner_->HasPendingTasks());
+}
+
+TEST_F(BackToBackBeginFrameSourceTest,
+ DidFinishFrameThenRemoveObserverProducesNoFrame) {
+ EXPECT_BEGIN_FRAME_SOURCE_PAUSED(*obs_, false);
+ source_->AddObserver(obs_.get());
+ EXPECT_BEGIN_FRAME_USED(*obs_, source_->source_id(), 1, 1000,
+ 1000 + kDeadline, kInterval);
+ task_runner_->RunPendingTasks();
+
+ now_src_->Advance(base::TimeDelta::FromMicroseconds(100));
+ source_->DidFinishFrame(obs_.get());
+ source_->RemoveObserver(obs_.get());
+
+ EXPECT_TRUE(task_runner_->HasPendingTasks());
+ task_runner_->RunPendingTasks();
+}
+
+TEST_F(BackToBackBeginFrameSourceTest,
+ TogglingObserverThenDidFinishFrameProducesCorrectFrame) {
+ EXPECT_BEGIN_FRAME_SOURCE_PAUSED(*obs_, false);
+ source_->AddObserver(obs_.get());
+ EXPECT_BEGIN_FRAME_USED(*obs_, source_->source_id(), 1, 1000,
+ 1000 + kDeadline, kInterval);
+ task_runner_->RunPendingTasks();
+
+ now_src_->Advance(base::TimeDelta::FromMicroseconds(100));
+ source_->RemoveObserver(obs_.get());
+
+ now_src_->Advance(base::TimeDelta::FromMicroseconds(10));
+ EXPECT_BEGIN_FRAME_SOURCE_PAUSED(*obs_, false);
+ source_->AddObserver(obs_.get());
+
+ now_src_->Advance(base::TimeDelta::FromMicroseconds(10));
+ source_->DidFinishFrame(obs_.get());
+
+ now_src_->Advance(base::TimeDelta::FromMicroseconds(10));
+ // The begin frame is posted at the time when the observer was added,
+ // so it ignores changes to "now" afterward.
+ EXPECT_BEGIN_FRAME_USED(*obs_, source_->source_id(), 2, 1110,
+ 1110 + kDeadline, kInterval);
+ EXPECT_TRUE(task_runner_->HasPendingTasks());
+ task_runner_->RunPendingTasks();
+}
+
+TEST_F(BackToBackBeginFrameSourceTest,
+ DidFinishFrameThenTogglingObserverProducesCorrectFrame) {
+ EXPECT_BEGIN_FRAME_SOURCE_PAUSED(*obs_, false);
+ source_->AddObserver(obs_.get());
+ EXPECT_BEGIN_FRAME_USED(*obs_, source_->source_id(), 1, 1000,
+ 1000 + kDeadline, kInterval);
+ task_runner_->RunPendingTasks();
+
+ now_src_->Advance(base::TimeDelta::FromMicroseconds(100));
+ source_->DidFinishFrame(obs_.get());
+
+ now_src_->Advance(base::TimeDelta::FromMicroseconds(10));
+ source_->RemoveObserver(obs_.get());
+
+ now_src_->Advance(base::TimeDelta::FromMicroseconds(10));
+ EXPECT_BEGIN_FRAME_SOURCE_PAUSED(*obs_, false);
+ source_->AddObserver(obs_.get());
+
+ now_src_->Advance(base::TimeDelta::FromMicroseconds(10));
+ // Ticks at the time at which the observer was added, ignoring the
+ // last change to "now".
+ EXPECT_BEGIN_FRAME_USED(*obs_, source_->source_id(), 2, 1120,
+ 1120 + kDeadline, kInterval);
+ EXPECT_TRUE(task_runner_->HasPendingTasks());
+ task_runner_->RunPendingTasks();
+}
+
+TEST_F(BackToBackBeginFrameSourceTest, DidFinishFrameNoObserver) {
+ EXPECT_BEGIN_FRAME_SOURCE_PAUSED(*obs_, false);
+ source_->AddObserver(obs_.get());
+ source_->RemoveObserver(obs_.get());
+ source_->DidFinishFrame(obs_.get());
+ EXPECT_FALSE(task_runner_->RunPendingTasks());
+}
+
+TEST_F(BackToBackBeginFrameSourceTest, DidFinishFrameMultipleCallsIdempotent) {
+ EXPECT_BEGIN_FRAME_SOURCE_PAUSED(*obs_, false);
+ source_->AddObserver(obs_.get());
+ EXPECT_BEGIN_FRAME_USED(*obs_, source_->source_id(), 1, 1000,
+ 1000 + kDeadline, kInterval);
+ task_runner_->RunPendingTasks();
+
+ now_src_->Advance(base::TimeDelta::FromMicroseconds(100));
+ source_->DidFinishFrame(obs_.get());
+ source_->DidFinishFrame(obs_.get());
+ source_->DidFinishFrame(obs_.get());
+ EXPECT_BEGIN_FRAME_USED(*obs_, source_->source_id(), 2, 1100,
+ 1100 + kDeadline, kInterval);
+ task_runner_->RunPendingTasks();
+
+ now_src_->Advance(base::TimeDelta::FromMicroseconds(100));
+ source_->DidFinishFrame(obs_.get());
+ source_->DidFinishFrame(obs_.get());
+ source_->DidFinishFrame(obs_.get());
+ EXPECT_BEGIN_FRAME_USED(*obs_, source_->source_id(), 3, 1200,
+ 1200 + kDeadline, kInterval);
+ task_runner_->RunPendingTasks();
+}
+
+TEST_F(BackToBackBeginFrameSourceTest, DelayInPostedTaskProducesCorrectFrame) {
+ EXPECT_BEGIN_FRAME_SOURCE_PAUSED(*obs_, false);
+ source_->AddObserver(obs_.get());
+ EXPECT_BEGIN_FRAME_USED(*obs_, source_->source_id(), 1, 1000,
+ 1000 + kDeadline, kInterval);
+ task_runner_->RunPendingTasks();
+
+ now_src_->Advance(base::TimeDelta::FromMicroseconds(100));
+ source_->DidFinishFrame(obs_.get());
+ now_src_->Advance(base::TimeDelta::FromMicroseconds(50));
+ // Ticks at the time the last frame finished, so ignores the last change to
+ // "now".
+ EXPECT_BEGIN_FRAME_USED(*obs_, source_->source_id(), 2, 1100,
+ 1100 + kDeadline, kInterval);
+
+ EXPECT_TRUE(task_runner_->HasPendingTasks());
+ task_runner_->RunPendingTasks();
+}
+
+TEST_F(BackToBackBeginFrameSourceTest, MultipleObserversSynchronized) {
+ NiceMock<MockBeginFrameObserver> obs1, obs2;
+
+ EXPECT_BEGIN_FRAME_SOURCE_PAUSED(obs1, false);
+ source_->AddObserver(&obs1);
+ EXPECT_BEGIN_FRAME_SOURCE_PAUSED(obs2, false);
+ source_->AddObserver(&obs2);
+
+ EXPECT_BEGIN_FRAME_USED(obs1, source_->source_id(), 1, 1000, 1000 + kDeadline,
+ kInterval);
+ EXPECT_BEGIN_FRAME_USED(obs2, source_->source_id(), 1, 1000, 1000 + kDeadline,
+ kInterval);
+ task_runner_->RunPendingTasks();
+
+ now_src_->Advance(base::TimeDelta::FromMicroseconds(100));
+ source_->DidFinishFrame(&obs1);
+ source_->DidFinishFrame(&obs2);
+ EXPECT_BEGIN_FRAME_USED(obs1, source_->source_id(), 2, 1100, 1100 + kDeadline,
+ kInterval);
+ EXPECT_BEGIN_FRAME_USED(obs2, source_->source_id(), 2, 1100, 1100 + kDeadline,
+ kInterval);
+ task_runner_->RunPendingTasks();
+
+ now_src_->Advance(base::TimeDelta::FromMicroseconds(100));
+ source_->DidFinishFrame(&obs1);
+ source_->DidFinishFrame(&obs2);
+ EXPECT_TRUE(task_runner_->HasPendingTasks());
+ source_->RemoveObserver(&obs1);
+ source_->RemoveObserver(&obs2);
+ task_runner_->RunPendingTasks();
+}
+
+TEST_F(BackToBackBeginFrameSourceTest, MultipleObserversInterleaved) {
+ NiceMock<MockBeginFrameObserver> obs1, obs2;
+
+ EXPECT_BEGIN_FRAME_SOURCE_PAUSED(obs1, false);
+ source_->AddObserver(&obs1);
+ EXPECT_BEGIN_FRAME_USED(obs1, source_->source_id(), 1, 1000, 1000 + kDeadline,
+ kInterval);
+ task_runner_->RunPendingTasks();
+
+ now_src_->Advance(base::TimeDelta::FromMicroseconds(100));
+ EXPECT_BEGIN_FRAME_SOURCE_PAUSED(obs2, false);
+ source_->AddObserver(&obs2);
+ EXPECT_BEGIN_FRAME_USED(obs2, source_->source_id(), 2, 1100, 1100 + kDeadline,
+ kInterval);
+ task_runner_->RunPendingTasks();
+
+ now_src_->Advance(base::TimeDelta::FromMicroseconds(100));
+ source_->DidFinishFrame(&obs1);
+ EXPECT_BEGIN_FRAME_USED(obs1, source_->source_id(), 3, 1200, 1200 + kDeadline,
+ kInterval);
+ task_runner_->RunPendingTasks();
+
+ source_->DidFinishFrame(&obs1);
+ source_->RemoveObserver(&obs1);
+ // Removing all finished observers should disable the time source.
+ EXPECT_FALSE(delay_based_time_source_->Active());
+ // Finishing the frame for |obs1| posts a begin frame task, which will be
+ // aborted since |obs1| is removed. Clear that from the task runner.
+ task_runner_->RunPendingTasks();
+
+ now_src_->Advance(base::TimeDelta::FromMicroseconds(100));
+ source_->DidFinishFrame(&obs2);
+ EXPECT_BEGIN_FRAME_USED(obs2, source_->source_id(), 4, 1300, 1300 + kDeadline,
+ kInterval);
+ task_runner_->RunPendingTasks();
+
+ source_->DidFinishFrame(&obs2);
+ source_->RemoveObserver(&obs2);
+}
+
+TEST_F(BackToBackBeginFrameSourceTest, MultipleObserversAtOnce) {
+ NiceMock<MockBeginFrameObserver> obs1, obs2;
+
+ EXPECT_BEGIN_FRAME_SOURCE_PAUSED(obs1, false);
+ EXPECT_BEGIN_FRAME_SOURCE_PAUSED(obs2, false);
+ source_->AddObserver(&obs1);
+ source_->AddObserver(&obs2);
+ EXPECT_BEGIN_FRAME_USED(obs1, source_->source_id(), 1, 1000, 1000 + kDeadline,
+ kInterval);
+ EXPECT_BEGIN_FRAME_USED(obs2, source_->source_id(), 1, 1000, 1000 + kDeadline,
+ kInterval);
+ task_runner_->RunPendingTasks();
+
+ // |obs1| finishes first.
+ now_src_->Advance(base::TimeDelta::FromMicroseconds(100));
+ source_->DidFinishFrame(&obs1);
+
+ // |obs2| finishes also, before getting to the newly posted begin frame.
+ now_src_->Advance(base::TimeDelta::FromMicroseconds(100));
+ source_->DidFinishFrame(&obs2);
+
+ // Because the begin frame source already ticked when |obs1| finished,
+ // we see it as the frame time for both observers.
+ EXPECT_BEGIN_FRAME_USED(obs1, source_->source_id(), 2, 1100, 1100 + kDeadline,
+ kInterval);
+ EXPECT_BEGIN_FRAME_USED(obs2, source_->source_id(), 2, 1100, 1100 + kDeadline,
+ kInterval);
+ task_runner_->RunPendingTasks();
+
+ source_->DidFinishFrame(&obs1);
+ source_->RemoveObserver(&obs1);
+ source_->DidFinishFrame(&obs2);
+ source_->RemoveObserver(&obs2);
+}
+
+// DelayBasedBeginFrameSource testing
+// ------------------------------------------
+class DelayBasedBeginFrameSourceTest : public ::testing::Test {
+ public:
+ std::unique_ptr<base::SimpleTestTickClock> now_src_;
+ scoped_refptr<OrderedSimpleTaskRunner> task_runner_;
+ std::unique_ptr<DelayBasedBeginFrameSource> source_;
+ std::unique_ptr<MockBeginFrameObserver> obs_;
+
+ void SetUp() override {
+ now_src_.reset(new base::SimpleTestTickClock());
+ now_src_->Advance(base::TimeDelta::FromMicroseconds(1000));
+ task_runner_ =
+ make_scoped_refptr(new OrderedSimpleTaskRunner(now_src_.get(), false));
+ std::unique_ptr<DelayBasedTimeSource> time_source(
+ new FakeDelayBasedTimeSource(now_src_.get(), task_runner_.get()));
+ time_source->SetTimebaseAndInterval(
+ base::TimeTicks(), base::TimeDelta::FromMicroseconds(10000));
+ source_.reset(new DelayBasedBeginFrameSource(std::move(time_source)));
+ obs_.reset(new MockBeginFrameObserver);
+ }
+
+ void TearDown() override { obs_.reset(); }
+};
+
+TEST_F(DelayBasedBeginFrameSourceTest,
+ AddObserverCallsOnBeginFrameWithMissedTick) {
+ now_src_->Advance(base::TimeDelta::FromMicroseconds(9010));
+ EXPECT_BEGIN_FRAME_SOURCE_PAUSED(*obs_, false);
+ EXPECT_BEGIN_FRAME_USED_MISSED(*obs_, source_->source_id(), 1, 10000, 20000,
+ 10000);
+ source_->AddObserver(obs_.get()); // Should cause the last tick to be sent
+ // No tasks should need to be run for this to occur.
+}
+
+TEST_F(DelayBasedBeginFrameSourceTest, AddObserverCallsCausesOnBeginFrame) {
+ EXPECT_BEGIN_FRAME_SOURCE_PAUSED(*obs_, false);
+ EXPECT_BEGIN_FRAME_USED_MISSED(*obs_, source_->source_id(), 1, 0, 10000,
+ 10000);
+ source_->AddObserver(obs_.get());
+ EXPECT_EQ(TicksFromMicroseconds(10000), task_runner_->NextTaskTime());
+
+ EXPECT_BEGIN_FRAME_USED(*obs_, source_->source_id(), 2, 10000, 20000, 10000);
+ now_src_->Advance(base::TimeDelta::FromMicroseconds(9010));
+ task_runner_->RunPendingTasks();
+}
+
+TEST_F(DelayBasedBeginFrameSourceTest, BasicOperation) {
+ task_runner_->SetAutoAdvanceNowToPendingTasks(true);
+
+ EXPECT_BEGIN_FRAME_SOURCE_PAUSED(*obs_, false);
+ EXPECT_BEGIN_FRAME_USED_MISSED(*obs_, source_->source_id(), 1, 0, 10000,
+ 10000);
+ source_->AddObserver(obs_.get());
+ EXPECT_BEGIN_FRAME_USED(*obs_, source_->source_id(), 2, 10000, 20000, 10000);
+ EXPECT_BEGIN_FRAME_USED(*obs_, source_->source_id(), 3, 20000, 30000, 10000);
+ EXPECT_BEGIN_FRAME_USED(*obs_, source_->source_id(), 4, 30000, 40000, 10000);
+ task_runner_->RunUntilTime(TicksFromMicroseconds(30001));
+
+ source_->RemoveObserver(obs_.get());
+ // No new frames....
+ task_runner_->RunUntilTime(TicksFromMicroseconds(60000));
+}
+
+TEST_F(DelayBasedBeginFrameSourceTest, VSyncChanges) {
+ task_runner_->SetAutoAdvanceNowToPendingTasks(true);
+ EXPECT_BEGIN_FRAME_SOURCE_PAUSED(*obs_, false);
+ EXPECT_BEGIN_FRAME_USED_MISSED(*obs_, source_->source_id(), 1, 0, 10000,
+ 10000);
+ source_->AddObserver(obs_.get());
+
+ EXPECT_BEGIN_FRAME_USED(*obs_, source_->source_id(), 2, 10000, 20000, 10000);
+ EXPECT_BEGIN_FRAME_USED(*obs_, source_->source_id(), 3, 20000, 30000, 10000);
+ EXPECT_BEGIN_FRAME_USED(*obs_, source_->source_id(), 4, 30000, 40000, 10000);
+ task_runner_->RunUntilTime(TicksFromMicroseconds(30001));
+
+ // Update the vsync information
+ source_->OnUpdateVSyncParameters(TicksFromMicroseconds(27500),
+ base::TimeDelta::FromMicroseconds(10001));
+
+ EXPECT_BEGIN_FRAME_USED(*obs_, source_->source_id(), 5, 40000, 47502, 10001);
+ EXPECT_BEGIN_FRAME_USED(*obs_, source_->source_id(), 6, 47502, 57503, 10001);
+ EXPECT_BEGIN_FRAME_USED(*obs_, source_->source_id(), 7, 57503, 67504, 10001);
+ task_runner_->RunUntilTime(TicksFromMicroseconds(60000));
+}
+
+TEST_F(DelayBasedBeginFrameSourceTest, AuthoritativeVSyncChanges) {
+ task_runner_->SetAutoAdvanceNowToPendingTasks(true);
+ source_->OnUpdateVSyncParameters(TicksFromMicroseconds(500),
+ base::TimeDelta::FromMicroseconds(10000));
+ EXPECT_BEGIN_FRAME_SOURCE_PAUSED(*obs_, false);
+ EXPECT_BEGIN_FRAME_USED_MISSED(*obs_, source_->source_id(), 1, 500, 10500,
+ 10000);
+ source_->AddObserver(obs_.get());
+
+ EXPECT_BEGIN_FRAME_USED(*obs_, source_->source_id(), 2, 10500, 20500, 10000);
+ EXPECT_BEGIN_FRAME_USED(*obs_, source_->source_id(), 3, 20500, 30500, 10000);
+ task_runner_->RunUntilTime(TicksFromMicroseconds(20501));
+
+ // This will keep the same timebase, so 500, 9999
+ source_->SetAuthoritativeVSyncInterval(
+ base::TimeDelta::FromMicroseconds(9999));
+ EXPECT_BEGIN_FRAME_USED(*obs_, source_->source_id(), 4, 30500, 40496, 9999);
+ EXPECT_BEGIN_FRAME_USED(*obs_, source_->source_id(), 5, 40496, 50495, 9999);
+ task_runner_->RunUntilTime(TicksFromMicroseconds(40497));
+
+ // Change the vsync params, but the new interval will be ignored.
+ source_->OnUpdateVSyncParameters(TicksFromMicroseconds(400),
+ base::TimeDelta::FromMicroseconds(1));
+ EXPECT_BEGIN_FRAME_USED(*obs_, source_->source_id(), 6, 50495, 60394, 9999);
+ EXPECT_BEGIN_FRAME_USED(*obs_, source_->source_id(), 7, 60394, 70393, 9999);
+ task_runner_->RunUntilTime(TicksFromMicroseconds(60395));
+}
+
+TEST_F(DelayBasedBeginFrameSourceTest, MultipleObservers) {
+ NiceMock<MockBeginFrameObserver> obs1, obs2;
+
+ // now_src_ starts off at 1000.
+ task_runner_->RunForPeriod(base::TimeDelta::FromMicroseconds(9010));
+ EXPECT_BEGIN_FRAME_SOURCE_PAUSED(obs1, false);
+ EXPECT_BEGIN_FRAME_USED_MISSED(obs1, source_->source_id(), 1, 10000, 20000,
+ 10000);
+ source_->AddObserver(&obs1); // Should cause the last tick to be sent
+ // No tasks should need to be run for this to occur.
+
+ EXPECT_BEGIN_FRAME_USED(obs1, source_->source_id(), 2, 20000, 30000, 10000);
+ task_runner_->RunForPeriod(base::TimeDelta::FromMicroseconds(10000));
+
+ EXPECT_BEGIN_FRAME_SOURCE_PAUSED(obs2, false);
+ // Sequence number unchanged for missed frame with time of last normal frame.
+ EXPECT_BEGIN_FRAME_USED_MISSED(obs2, source_->source_id(), 2, 20000, 30000,
+ 10000);
+ source_->AddObserver(&obs2); // Should cause the last tick to be sent
+ // No tasks should need to be run for this to occur.
+
+ EXPECT_BEGIN_FRAME_USED(obs1, source_->source_id(), 3, 30000, 40000, 10000);
+ EXPECT_BEGIN_FRAME_USED(obs2, source_->source_id(), 3, 30000, 40000, 10000);
+ task_runner_->RunForPeriod(base::TimeDelta::FromMicroseconds(10000));
+
+ source_->RemoveObserver(&obs1);
+
+ EXPECT_BEGIN_FRAME_USED(obs2, source_->source_id(), 4, 40000, 50000, 10000);
+ task_runner_->RunForPeriod(base::TimeDelta::FromMicroseconds(10000));
+
+ source_->RemoveObserver(&obs2);
+ task_runner_->RunUntilTime(TicksFromMicroseconds(50000));
+ EXPECT_FALSE(task_runner_->HasPendingTasks());
+}
+
+TEST_F(DelayBasedBeginFrameSourceTest, DoubleTick) {
+ NiceMock<MockBeginFrameObserver> obs;
+
+ EXPECT_BEGIN_FRAME_SOURCE_PAUSED(obs, false);
+ EXPECT_BEGIN_FRAME_USED_MISSED(obs, source_->source_id(), 1, 0, 10000, 10000);
+ source_->AddObserver(&obs);
+
+ source_->OnUpdateVSyncParameters(TicksFromMicroseconds(5000),
+ base::TimeDelta::FromMicroseconds(10000));
+ now_src_->Advance(base::TimeDelta::FromMicroseconds(4000));
+
+ // No begin frame received.
+ task_runner_->RunPendingTasks();
+
+ // Begin frame received.
+ source_->OnUpdateVSyncParameters(TicksFromMicroseconds(10000),
+ base::TimeDelta::FromMicroseconds(10000));
+ now_src_->Advance(base::TimeDelta::FromMicroseconds(5000));
+ EXPECT_BEGIN_FRAME_USED(obs, source_->source_id(), 2, 10000, 20000, 10000);
+ task_runner_->RunPendingTasks();
+}
+
+TEST_F(DelayBasedBeginFrameSourceTest, DoubleTickMissedFrame) {
+ NiceMock<MockBeginFrameObserver> obs;
+
+ EXPECT_BEGIN_FRAME_SOURCE_PAUSED(obs, false);
+ EXPECT_BEGIN_FRAME_USED_MISSED(obs, source_->source_id(), 1, 0, 10000, 10000);
+ source_->AddObserver(&obs);
+ source_->RemoveObserver(&obs);
+
+ source_->OnUpdateVSyncParameters(TicksFromMicroseconds(5000),
+ base::TimeDelta::FromMicroseconds(10000));
+ now_src_->Advance(base::TimeDelta::FromMicroseconds(4000));
+
+ // No missed frame received.
+ EXPECT_BEGIN_FRAME_SOURCE_PAUSED(obs, false);
+ // This does not cause a missed BeginFrame because of double ticking
+ // prevention. It does not produce a new sequence number.
+ source_->AddObserver(&obs);
+ source_->RemoveObserver(&obs);
+
+ // Missed frame received.
+ source_->OnUpdateVSyncParameters(TicksFromMicroseconds(10000),
+ base::TimeDelta::FromMicroseconds(10000));
+ now_src_->Advance(base::TimeDelta::FromMicroseconds(5000));
+ EXPECT_BEGIN_FRAME_SOURCE_PAUSED(obs, false);
+ // Sequence number is incremented again, because sufficient time has passed.
+ EXPECT_BEGIN_FRAME_USED_MISSED(obs, source_->source_id(), 2, 10000, 20000,
+ 10000);
+ source_->AddObserver(&obs);
+ source_->RemoveObserver(&obs);
+}
+
+// ExternalBeginFrameSource testing
+// --------------------------------------------
+class MockExternalBeginFrameSourceClient
+ : public ExternalBeginFrameSourceClient {
+ public:
+ MOCK_METHOD1(OnNeedsBeginFrames, void(bool));
+};
+
+class ExternalBeginFrameSourceTest : public ::testing::Test {
+ public:
+ std::unique_ptr<MockExternalBeginFrameSourceClient> client_;
+ std::unique_ptr<ExternalBeginFrameSource> source_;
+ std::unique_ptr<MockBeginFrameObserver> obs_;
+
+ void SetUp() override {
+ client_.reset(new MockExternalBeginFrameSourceClient);
+ source_.reset(new ExternalBeginFrameSource(client_.get()));
+ obs_.reset(new MockBeginFrameObserver);
+ }
+
+ void TearDown() override {
+ client_.reset();
+ obs_.reset();
+ }
+};
+
+// https://crbug.com/690127: Duplicate BeginFrame caused DCHECK crash.
+TEST_F(ExternalBeginFrameSourceTest, OnBeginFrameChecksBeginFrameContinuity) {
+ EXPECT_BEGIN_FRAME_SOURCE_PAUSED(*obs_, false);
+ EXPECT_CALL((*client_), OnNeedsBeginFrames(true)).Times(1);
+ source_->AddObserver(obs_.get());
+
+ BeginFrameArgs args = CreateBeginFrameArgsForTesting(
+ BEGINFRAME_FROM_HERE, 0, 2, TicksFromMicroseconds(10000));
+ EXPECT_BEGIN_FRAME_ARGS_USED(*obs_, args);
+ source_->OnBeginFrame(args);
+
+ // Providing same args again to OnBeginFrame() should not notify observer.
+ source_->OnBeginFrame(args);
+
+ // Providing same args through a different ExternalBeginFrameSource also
+ // does not notify observer.
+ EXPECT_BEGIN_FRAME_SOURCE_PAUSED(*obs_, false);
+ EXPECT_CALL((*client_), OnNeedsBeginFrames(true)).Times(1);
+ ExternalBeginFrameSource source2(client_.get());
+ source2.AddObserver(obs_.get());
+ source2.OnBeginFrame(args);
+}
+
+// https://crbug.com/730218: Avoid DCHECK crash in
+// ExternalBeginFrameSource::GetMissedBeginFrameArgs.
+TEST_F(ExternalBeginFrameSourceTest, GetMissedBeginFrameArgs) {
+ BeginFrameArgs args = CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0,
+ 2, 10000, 10100, 100);
+ source_->OnBeginFrame(args);
+
+ EXPECT_BEGIN_FRAME_SOURCE_PAUSED(*obs_, false);
+ EXPECT_BEGIN_FRAME_USED_MISSED(*obs_, 0, 2, 10000, 10100, 100);
+ source_->AddObserver(obs_.get());
+ source_->RemoveObserver(obs_.get());
+
+ // Out of order frame_time. This might not be valid but still shouldn't
+ // cause a DCHECK in ExternalBeginFrameSource code.
+ args = CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 2, 9999, 10100,
+ 101);
+ source_->OnBeginFrame(args);
+
+ EXPECT_CALL((*client_), OnNeedsBeginFrames(true)).Times(1);
+ EXPECT_BEGIN_FRAME_SOURCE_PAUSED(*obs_, false);
+ EXPECT_CALL(*obs_, OnBeginFrame(_)).Times(0);
+ source_->AddObserver(obs_.get());
+}
+
+} // namespace
+} // namespace viz
diff --git a/chromium/components/viz/common/frame_sinks/delay_based_time_source.cc b/chromium/components/viz/common/frame_sinks/delay_based_time_source.cc
new file mode 100644
index 00000000000..1a6cd56f4a2
--- /dev/null
+++ b/chromium/components/viz/common/frame_sinks/delay_based_time_source.cc
@@ -0,0 +1,180 @@
+// Copyright 2011 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 "components/viz/common/frame_sinks/delay_based_time_source.h"
+
+#include <algorithm>
+#include <cmath>
+#include <string>
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/single_thread_task_runner.h"
+#include "base/trace_event/trace_event.h"
+#include "base/trace_event/trace_event_argument.h"
+#include "components/viz/common/frame_sinks/begin_frame_args.h"
+
+namespace viz {
+
+// The following methods correspond to the DelayBasedTimeSource that uses
+// the base::TimeTicks::Now as the timebase.
+DelayBasedTimeSource::DelayBasedTimeSource(
+ base::SingleThreadTaskRunner* task_runner)
+ : client_(nullptr),
+ active_(false),
+ timebase_(base::TimeTicks()),
+ interval_(BeginFrameArgs::DefaultInterval()),
+ last_tick_time_(base::TimeTicks() - interval_),
+ next_tick_time_(base::TimeTicks()),
+ task_runner_(task_runner),
+ weak_factory_(this) {}
+
+DelayBasedTimeSource::~DelayBasedTimeSource() = default;
+
+void DelayBasedTimeSource::SetActive(bool active) {
+ TRACE_EVENT1("cc", "DelayBasedTimeSource::SetActive", "active", active);
+
+ if (active == active_)
+ return;
+
+ active_ = active;
+
+ if (active_) {
+ PostNextTickTask(Now());
+ } else {
+ last_tick_time_ = base::TimeTicks();
+ next_tick_time_ = base::TimeTicks();
+ tick_closure_.Cancel();
+ }
+}
+
+base::TimeDelta DelayBasedTimeSource::Interval() const {
+ return interval_;
+}
+
+bool DelayBasedTimeSource::Active() const {
+ return active_;
+}
+
+base::TimeTicks DelayBasedTimeSource::LastTickTime() const {
+ return last_tick_time_;
+}
+
+base::TimeTicks DelayBasedTimeSource::NextTickTime() const {
+ return next_tick_time_;
+}
+
+void DelayBasedTimeSource::OnTimerTick() {
+ DCHECK(active_);
+
+ last_tick_time_ = next_tick_time_;
+
+ PostNextTickTask(Now());
+
+ // Fire the tick.
+ if (client_)
+ client_->OnTimerTick();
+}
+
+void DelayBasedTimeSource::SetClient(DelayBasedTimeSourceClient* client) {
+ client_ = client;
+}
+
+void DelayBasedTimeSource::SetTimebaseAndInterval(base::TimeTicks timebase,
+ base::TimeDelta interval) {
+ interval_ = interval;
+ timebase_ = timebase;
+}
+
+base::TimeTicks DelayBasedTimeSource::Now() const {
+ return base::TimeTicks::Now();
+}
+
+// This code tries to achieve an average tick rate as close to interval_ as
+// possible. To do this, it has to deal with a few basic issues:
+// 1. PostDelayedTask can delay only at a millisecond granularity. So, 16.666
+// has to posted as 16 or 17.
+// 2. A delayed task may come back a bit late (a few ms), or really late
+// (frames later)
+//
+// The basic idea with this scheduler here is to keep track of where we *want*
+// to run in tick_target_. We update this with the exact interval.
+//
+// Then, when we post our task, we take the floor of (tick_target_ and Now()).
+// If we started at now=0, and 60FPs (all times in milliseconds):
+// now=0 target=16.667 PostDelayedTask(16)
+//
+// When our callback runs, we figure out how far off we were from that goal.
+// Because of the flooring operation, and assuming our timer runs exactly when
+// it should, this yields:
+// now=16 target=16.667
+//
+// Since we can't post a 0.667 ms task to get to now=16, we just treat this as a
+// tick. Then, we update target to be 33.333. We now post another task based on
+// the difference between our target and now:
+// now=16 tick_target=16.667 new_target=33.333 -->
+// PostDelayedTask(floor(33.333 - 16)) --> PostDelayedTask(17)
+//
+// Over time, with no late tasks, this leads to us posting tasks like this:
+// now=0 tick_target=0 new_target=16.667 -->
+// tick(), PostDelayedTask(16)
+// now=16 tick_target=16.667 new_target=33.333 -->
+// tick(), PostDelayedTask(17)
+// now=33 tick_target=33.333 new_target=50.000 -->
+// tick(), PostDelayedTask(17)
+// now=50 tick_target=50.000 new_target=66.667 -->
+// tick(), PostDelayedTask(16)
+//
+// We treat delays in tasks differently depending on the amount of delay we
+// encounter. Suppose we posted a task with a target=16.667:
+// Case 1: late but not unrecoverably-so
+// now=18 tick_target=16.667
+//
+// Case 2: so late we obviously missed the tick
+// now=25.0 tick_target=16.667
+//
+// We treat the first case as a tick anyway, and assume the delay was unusual.
+// Thus, we compute the new_target based on the old timebase:
+// now=18 tick_target=16.667 new_target=33.333 -->
+// tick(), PostDelayedTask(floor(33.333-18)) --> PostDelayedTask(15)
+// This brings us back to 18+15 = 33, which was where we would have been if the
+// task hadn't been late.
+//
+// For the really late delay, we we move to the next logical tick. The timebase
+// is not reset.
+// now=37 tick_target=16.667 new_target=50.000 -->
+// tick(), PostDelayedTask(floor(50.000-37)) --> PostDelayedTask(13)
+void DelayBasedTimeSource::PostNextTickTask(base::TimeTicks now) {
+ if (interval_.is_zero()) {
+ next_tick_time_ = now;
+ } else {
+ next_tick_time_ = now.SnappedToNextTick(timebase_, interval_);
+ if (next_tick_time_ == now)
+ next_tick_time_ += interval_;
+ DCHECK_GT(next_tick_time_, now);
+ }
+ tick_closure_.Reset(base::Bind(&DelayBasedTimeSource::OnTimerTick,
+ weak_factory_.GetWeakPtr()));
+ task_runner_->PostDelayedTask(FROM_HERE, tick_closure_.callback(),
+ next_tick_time_ - now);
+}
+
+std::string DelayBasedTimeSource::TypeString() const {
+ return "DelayBasedTimeSource";
+}
+
+void DelayBasedTimeSource::AsValueInto(
+ base::trace_event::TracedValue* state) const {
+ state->SetString("type", TypeString());
+ state->SetDouble("last_tick_time_us",
+ LastTickTime().since_origin().InMicroseconds());
+ state->SetDouble("next_tick_time_us",
+ NextTickTime().since_origin().InMicroseconds());
+ state->SetDouble("interval_us", interval_.InMicroseconds());
+ state->SetDouble("timebase_us", timebase_.since_origin().InMicroseconds());
+ state->SetBoolean("active", active_);
+}
+
+} // namespace viz
diff --git a/chromium/components/viz/common/frame_sinks/delay_based_time_source.h b/chromium/components/viz/common/frame_sinks/delay_based_time_source.h
new file mode 100644
index 00000000000..9a9d0a3d069
--- /dev/null
+++ b/chromium/components/viz/common/frame_sinks/delay_based_time_source.h
@@ -0,0 +1,91 @@
+// Copyright 2011 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 COMPONENTS_VIZ_COMMON_FRAME_SINKS_DELAY_BASED_TIME_SOURCE_H_
+#define COMPONENTS_VIZ_COMMON_FRAME_SINKS_DELAY_BASED_TIME_SOURCE_H_
+
+#include <memory>
+#include <string>
+
+#include "base/cancelable_callback.h"
+#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "base/memory/weak_ptr.h"
+#include "base/values.h"
+#include "components/viz/common/viz_common_export.h"
+
+namespace base {
+namespace trace_event {
+class TracedValue;
+}
+class SingleThreadTaskRunner;
+} // namespace base
+
+namespace viz {
+class VIZ_COMMON_EXPORT DelayBasedTimeSourceClient {
+ public:
+ virtual void OnTimerTick() = 0;
+
+ protected:
+ virtual ~DelayBasedTimeSourceClient() {}
+};
+
+// This timer implements a time source that achieves the specified interval
+// in face of millisecond-precision delayed callbacks and random queueing
+// delays. DelayBasedTimeSource uses base::TimeTicks::Now as its timebase.
+class VIZ_COMMON_EXPORT DelayBasedTimeSource {
+ public:
+ explicit DelayBasedTimeSource(base::SingleThreadTaskRunner* task_runner);
+ virtual ~DelayBasedTimeSource();
+
+ void SetClient(DelayBasedTimeSourceClient* client);
+
+ void SetTimebaseAndInterval(base::TimeTicks timebase,
+ base::TimeDelta interval);
+
+ base::TimeDelta Interval() const;
+
+ void SetActive(bool active);
+ bool Active() const;
+
+ // Get the last and next tick times. NextTickTime() returns null when
+ // inactive.
+ base::TimeTicks LastTickTime() const;
+ base::TimeTicks NextTickTime() const;
+
+ virtual void AsValueInto(base::trace_event::TracedValue* dict) const;
+
+ protected:
+ // Virtual for testing.
+ virtual base::TimeTicks Now() const;
+ virtual std::string TypeString() const;
+
+ private:
+ void PostNextTickTask(base::TimeTicks now);
+ void ResetTickTask(base::TimeTicks now);
+
+ void OnTimerTick();
+
+ DelayBasedTimeSourceClient* client_;
+
+ bool active_;
+
+ base::TimeTicks timebase_;
+ base::TimeDelta interval_;
+
+ base::TimeTicks last_tick_time_;
+ base::TimeTicks next_tick_time_;
+
+ base::CancelableClosure tick_closure_;
+
+ base::SingleThreadTaskRunner* task_runner_;
+
+ base::WeakPtrFactory<DelayBasedTimeSource> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(DelayBasedTimeSource);
+};
+
+} // namespace viz
+
+#endif // COMPONENTS_VIZ_COMMON_FRAME_SINKS_DELAY_BASED_TIME_SOURCE_H_
diff --git a/chromium/components/viz/common/frame_sinks/delay_based_time_source_unittest.cc b/chromium/components/viz/common/frame_sinks/delay_based_time_source_unittest.cc
new file mode 100644
index 00000000000..be4437dcce4
--- /dev/null
+++ b/chromium/components/viz/common/frame_sinks/delay_based_time_source_unittest.cc
@@ -0,0 +1,351 @@
+// Copyright 2011 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 "components/viz/common/frame_sinks/delay_based_time_source.h"
+
+#include <stdint.h>
+
+#include "base/test/test_simple_task_runner.h"
+#include "components/viz/test/fake_delay_based_time_source.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace viz {
+namespace {
+
+base::TimeDelta Interval() {
+ return base::TimeDelta::FromMicroseconds(base::Time::kMicrosecondsPerSecond /
+ 60);
+}
+
+class DelayBasedTimeSourceTest : public ::testing::Test {
+ protected:
+ void SetUp() override {
+ now_src_ = base::MakeUnique<base::SimpleTestTickClock>();
+ task_runner_ = make_scoped_refptr(new base::TestSimpleTaskRunner);
+ delay_based_time_source_ = base::MakeUnique<FakeDelayBasedTimeSource>(
+ now_src_.get(), task_runner_.get());
+ delay_based_time_source_->SetClient(&client_);
+ }
+
+ void TearDown() override {
+ delay_based_time_source_.reset();
+ task_runner_ = nullptr;
+ now_src_.reset();
+ }
+
+ void SetNow(base::TimeTicks ticks) { now_src_->SetNowTicks(ticks); }
+
+ base::TestSimpleTaskRunner* task_runner() { return task_runner_.get(); }
+
+ FakeDelayBasedTimeSource* timer() { return delay_based_time_source_.get(); }
+
+ FakeDelayBasedTimeSourceClient* client() { return &client_; }
+
+ std::unique_ptr<base::SimpleTestTickClock> now_src_;
+ FakeDelayBasedTimeSourceClient client_;
+ scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
+ std::unique_ptr<FakeDelayBasedTimeSource> delay_based_time_source_;
+};
+
+TEST_F(DelayBasedTimeSourceTest, TaskPostedAndTickCalled) {
+ timer()->SetTimebaseAndInterval(base::TimeTicks(), Interval());
+ timer()->SetActive(true);
+ EXPECT_TRUE(timer()->Active());
+ EXPECT_TRUE(task_runner()->HasPendingTask());
+
+ SetNow(timer()->Now() + base::TimeDelta::FromMilliseconds(16));
+ task_runner()->RunPendingTasks();
+ EXPECT_TRUE(timer()->Active());
+ EXPECT_TRUE(client()->TickCalled());
+}
+
+TEST_F(DelayBasedTimeSourceTest, TickNotCalledWithTaskPosted) {
+ timer()->SetTimebaseAndInterval(base::TimeTicks(), Interval());
+ timer()->SetActive(true);
+ EXPECT_TRUE(task_runner()->HasPendingTask());
+ timer()->SetActive(false);
+ task_runner()->RunPendingTasks();
+ EXPECT_FALSE(client()->TickCalled());
+}
+
+TEST_F(DelayBasedTimeSourceTest, StartTwiceEnqueuesOneTask) {
+ timer()->SetTimebaseAndInterval(base::TimeTicks(), Interval());
+ timer()->SetActive(true);
+ EXPECT_TRUE(task_runner()->HasPendingTask());
+ task_runner()->ClearPendingTasks();
+ timer()->SetActive(true);
+ EXPECT_FALSE(task_runner()->HasPendingTask());
+}
+
+TEST_F(DelayBasedTimeSourceTest, StartWhenRunningDoesntTick) {
+ timer()->SetTimebaseAndInterval(base::TimeTicks(), Interval());
+ timer()->SetActive(true);
+ EXPECT_TRUE(task_runner()->HasPendingTask());
+ task_runner()->RunPendingTasks();
+ task_runner()->ClearPendingTasks();
+ timer()->SetActive(true);
+ EXPECT_FALSE(task_runner()->HasPendingTask());
+}
+
+// At 60Hz, when the tick returns at exactly the requested next time, make sure
+// a 16ms next delay is posted.
+TEST_F(DelayBasedTimeSourceTest, NextDelaySaneWhenExactlyOnRequestedTime) {
+ timer()->SetTimebaseAndInterval(base::TimeTicks(), Interval());
+ timer()->SetActive(true);
+ // Run the first tick.
+ task_runner()->RunPendingTasks();
+
+ EXPECT_EQ(16, task_runner()->NextPendingTaskDelay().InMilliseconds());
+
+ SetNow(timer()->Now() + Interval());
+ task_runner()->RunPendingTasks();
+
+ EXPECT_EQ(16, task_runner()->NextPendingTaskDelay().InMilliseconds());
+}
+
+// At 60Hz, when the tick returns at slightly after the requested next time,
+// make sure a 16ms next delay is posted.
+TEST_F(DelayBasedTimeSourceTest, NextDelaySaneWhenSlightlyAfterRequestedTime) {
+ timer()->SetTimebaseAndInterval(base::TimeTicks(), Interval());
+ timer()->SetActive(true);
+ // Run the first tick.
+ task_runner()->RunPendingTasks();
+
+ EXPECT_EQ(16, task_runner()->NextPendingTaskDelay().InMilliseconds());
+
+ SetNow(timer()->Now() + Interval() + base::TimeDelta::FromMicroseconds(1));
+ task_runner()->RunPendingTasks();
+
+ EXPECT_EQ(16, task_runner()->NextPendingTaskDelay().InMilliseconds());
+}
+
+// At 60Hz, when the tick returns at exactly 2*interval after the requested next
+// time, make sure we don't tick unnecessarily.
+TEST_F(DelayBasedTimeSourceTest,
+ NextDelaySaneWhenExactlyTwiceAfterRequestedTime) {
+ timer()->SetTimebaseAndInterval(base::TimeTicks(), Interval());
+ timer()->SetActive(true);
+ // Run the first tick.
+ task_runner()->RunPendingTasks();
+
+ EXPECT_EQ(16, task_runner()->NextPendingTaskDelay().InMilliseconds());
+
+ SetNow(timer()->Now() + 2 * Interval());
+ task_runner()->RunPendingTasks();
+
+ EXPECT_EQ(16, task_runner()->NextPendingTaskDelay().InMilliseconds());
+}
+
+// At 60Hz, when the tick returns at 2*interval and a bit after the requested
+// next time, make sure a 16ms next delay is posted.
+TEST_F(DelayBasedTimeSourceTest,
+ NextDelaySaneWhenSlightlyAfterTwiceRequestedTime) {
+ timer()->SetTimebaseAndInterval(base::TimeTicks(), Interval());
+ timer()->SetActive(true);
+ // Run the first tick.
+ task_runner()->RunPendingTasks();
+
+ EXPECT_EQ(16, task_runner()->NextPendingTaskDelay().InMilliseconds());
+
+ SetNow(timer()->Now() + 2 * Interval() +
+ base::TimeDelta::FromMicroseconds(1));
+ task_runner()->RunPendingTasks();
+
+ EXPECT_EQ(16, task_runner()->NextPendingTaskDelay().InMilliseconds());
+}
+
+// At 60Hz, when the tick returns halfway to the next frame time, make sure
+// a correct next delay value is posted.
+TEST_F(DelayBasedTimeSourceTest, NextDelaySaneWhenHalfAfterRequestedTime) {
+ timer()->SetTimebaseAndInterval(base::TimeTicks(), Interval());
+ timer()->SetActive(true);
+ // Run the first tick.
+ task_runner()->RunPendingTasks();
+
+ EXPECT_EQ(16, task_runner()->NextPendingTaskDelay().InMilliseconds());
+
+ SetNow(timer()->Now() + Interval() + base::TimeDelta::FromMilliseconds(8));
+ task_runner()->RunPendingTasks();
+
+ EXPECT_EQ(8, task_runner()->NextPendingTaskDelay().InMilliseconds());
+}
+
+TEST_F(DelayBasedTimeSourceTest, JitteryRuntimeWithFutureTimebases) {
+ timer()->SetTimebaseAndInterval(base::TimeTicks(), Interval());
+ timer()->SetActive(true);
+
+ // Run the first tick.
+ task_runner()->RunPendingTasks();
+ EXPECT_EQ(16, task_runner()->NextPendingTaskDelay().InMilliseconds());
+
+ base::TimeTicks future_timebase = timer()->Now() + Interval() * 10;
+
+ // 1ms jitter
+ base::TimeDelta jitter1 = base::TimeDelta::FromMilliseconds(1);
+
+ // Tick with +1ms of jitter
+ future_timebase += Interval();
+ timer()->SetTimebaseAndInterval(future_timebase, Interval());
+ SetNow(timer()->Now() + Interval() + jitter1);
+ task_runner()->RunPendingTasks();
+ EXPECT_EQ(15, task_runner()->NextPendingTaskDelay().InMilliseconds());
+
+ // Tick with 0ms of jitter
+ future_timebase += Interval();
+ timer()->SetTimebaseAndInterval(future_timebase, Interval());
+ SetNow(timer()->Now() + Interval() - jitter1);
+ task_runner()->RunPendingTasks();
+ EXPECT_EQ(16, task_runner()->NextPendingTaskDelay().InMilliseconds());
+
+ // Tick with -1ms of jitter
+ future_timebase += Interval();
+ timer()->SetTimebaseAndInterval(future_timebase, Interval());
+ SetNow(timer()->Now() + Interval() - jitter1);
+ task_runner()->RunPendingTasks();
+ EXPECT_EQ(1, task_runner()->NextPendingTaskDelay().InMilliseconds());
+
+ // Tick with 0ms of jitter
+ future_timebase += Interval();
+ timer()->SetTimebaseAndInterval(future_timebase, Interval());
+ SetNow(timer()->Now() + Interval() + jitter1);
+ task_runner()->RunPendingTasks();
+ EXPECT_EQ(16, task_runner()->NextPendingTaskDelay().InMilliseconds());
+
+ // 8 ms jitter
+ base::TimeDelta jitter8 = base::TimeDelta::FromMilliseconds(8);
+
+ // Tick with +8ms of jitter
+ future_timebase += Interval();
+ timer()->SetTimebaseAndInterval(future_timebase, Interval());
+ SetNow(timer()->Now() + Interval() + jitter8);
+ task_runner()->RunPendingTasks();
+ EXPECT_EQ(8, task_runner()->NextPendingTaskDelay().InMilliseconds());
+
+ // Tick with 0ms of jitter
+ future_timebase += Interval();
+ timer()->SetTimebaseAndInterval(future_timebase, Interval());
+ SetNow(timer()->Now() + Interval() - jitter8);
+ task_runner()->RunPendingTasks();
+ EXPECT_EQ(16, task_runner()->NextPendingTaskDelay().InMilliseconds());
+
+ // Tick with -8ms of jitter
+ future_timebase += Interval();
+ timer()->SetTimebaseAndInterval(future_timebase, Interval());
+ SetNow(timer()->Now() + Interval() - jitter8);
+ task_runner()->RunPendingTasks();
+ EXPECT_EQ(8, task_runner()->NextPendingTaskDelay().InMilliseconds());
+
+ // Tick with 0ms of jitter
+ future_timebase += Interval();
+ timer()->SetTimebaseAndInterval(future_timebase, Interval());
+ SetNow(timer()->Now() + Interval() + jitter8);
+ task_runner()->RunPendingTasks();
+ EXPECT_EQ(16, task_runner()->NextPendingTaskDelay().InMilliseconds());
+
+ // 15 ms jitter
+ base::TimeDelta jitter15 = base::TimeDelta::FromMilliseconds(15);
+
+ // Tick with +15ms jitter
+ future_timebase += Interval();
+ timer()->SetTimebaseAndInterval(future_timebase, Interval());
+ SetNow(timer()->Now() + Interval() + jitter15);
+ task_runner()->RunPendingTasks();
+ EXPECT_EQ(1, task_runner()->NextPendingTaskDelay().InMilliseconds());
+
+ // Tick with 0ms of jitter
+ future_timebase += Interval();
+ timer()->SetTimebaseAndInterval(future_timebase, Interval());
+ SetNow(timer()->Now() + Interval() - jitter15);
+ task_runner()->RunPendingTasks();
+ EXPECT_EQ(16, task_runner()->NextPendingTaskDelay().InMilliseconds());
+
+ // Tick with -15ms of jitter
+ future_timebase += Interval();
+ timer()->SetTimebaseAndInterval(future_timebase, Interval());
+ SetNow(timer()->Now() + Interval() - jitter15);
+ task_runner()->RunPendingTasks();
+ EXPECT_EQ(15, task_runner()->NextPendingTaskDelay().InMilliseconds());
+
+ // Tick with 0ms of jitter
+ future_timebase += Interval();
+ timer()->SetTimebaseAndInterval(future_timebase, Interval());
+ SetNow(timer()->Now() + Interval() + jitter15);
+ task_runner()->RunPendingTasks();
+ EXPECT_EQ(16, task_runner()->NextPendingTaskDelay().InMilliseconds());
+}
+
+TEST_F(DelayBasedTimeSourceTest, AchievesTargetRateWithNoNoise) {
+ int num_iterations = 10;
+
+ timer()->SetTimebaseAndInterval(base::TimeTicks(), Interval());
+ timer()->SetActive(true);
+
+ double total_frame_time = 0.0;
+ for (int i = 0; i < num_iterations; ++i) {
+ int64_t delay_ms = task_runner()->NextPendingTaskDelay().InMilliseconds();
+
+ // accumulate the "delay"
+ total_frame_time += delay_ms / 1000.0;
+
+ // Run the callback exactly when asked
+ SetNow(timer()->Now() + base::TimeDelta::FromMilliseconds(delay_ms));
+ task_runner()->RunPendingTasks();
+ }
+ double average_interval =
+ total_frame_time / static_cast<double>(num_iterations);
+ EXPECT_NEAR(1.0 / 60.0, average_interval, 0.1);
+}
+
+TEST_F(DelayBasedTimeSourceTest, TestDeactivateWhilePending) {
+ timer()->SetTimebaseAndInterval(base::TimeTicks(), Interval());
+ timer()->SetActive(true); // Should post a task.
+ timer()->SetActive(false);
+ // Should run the posted task without crashing.
+ EXPECT_TRUE(task_runner()->HasPendingTask());
+ task_runner()->RunPendingTasks();
+}
+
+TEST_F(DelayBasedTimeSourceTest,
+ TestDeactivateAndReactivateBeforeNextTickTime) {
+ timer()->SetTimebaseAndInterval(base::TimeTicks(), Interval());
+
+ // Should run the activate task, and pick up a new timebase.
+ timer()->SetActive(true);
+ task_runner()->RunPendingTasks();
+
+ // Stop the timer()
+ timer()->SetActive(false);
+
+ // Task will be pending anyway, run it
+ task_runner()->RunPendingTasks();
+
+ // Start the timer() again, but before the next tick time the timer()
+ // previously planned on using. That same tick time should still be targeted.
+ SetNow(timer()->Now() + base::TimeDelta::FromMilliseconds(4));
+ timer()->SetActive(true);
+ EXPECT_EQ(12, task_runner()->NextPendingTaskDelay().InMilliseconds());
+}
+
+TEST_F(DelayBasedTimeSourceTest, TestDeactivateAndReactivateAfterNextTickTime) {
+ timer()->SetTimebaseAndInterval(base::TimeTicks(), Interval());
+
+ // Should run the activate task, and pick up a new timebase.
+ timer()->SetActive(true);
+ task_runner()->RunPendingTasks();
+
+ // Stop the timer().
+ timer()->SetActive(false);
+
+ // Task will be pending anyway, run it.
+ task_runner()->RunPendingTasks();
+
+ // Start the timer() again, but before the next tick time the timer()
+ // previously planned on using. That same tick time should still be targeted.
+ SetNow(timer()->Now() + base::TimeDelta::FromMilliseconds(20));
+ timer()->SetActive(true);
+ EXPECT_EQ(13, task_runner()->NextPendingTaskDelay().InMilliseconds());
+}
+
+} // namespace
+} // namespace viz
diff --git a/chromium/components/viz/common/gl_helper_benchmark.cc b/chromium/components/viz/common/gl_helper_benchmark.cc
index 59c3a73e537..7d9a76b811c 100644
--- a/chromium/components/viz/common/gl_helper_benchmark.cc
+++ b/chromium/components/viz/common/gl_helper_benchmark.cc
@@ -120,7 +120,7 @@ class GLHelperBenchmark : public testing::Test {
gpu::gles2::GLES2Interface* gl_;
std::unique_ptr<GLHelper> helper_;
std::unique_ptr<GLHelperScaling> helper_scaling_;
- std::deque<GLHelperScaling::ScaleOp> x_ops_, y_ops_;
+ base::circular_deque<GLHelperScaling::ScaleOp> x_ops_, y_ops_;
};
TEST_F(GLHelperBenchmark, ScaleBenchmark) {
diff --git a/chromium/components/viz/common/gl_helper_scaling.cc b/chromium/components/viz/common/gl_helper_scaling.cc
index e394202df35..4fa88db8b92 100644
--- a/chromium/components/viz/common/gl_helper_scaling.cc
+++ b/chromium/components/viz/common/gl_helper_scaling.cc
@@ -6,11 +6,11 @@
#include <stddef.h>
-#include <deque>
#include <string>
#include <vector>
#include "base/bind.h"
+#include "base/containers/circular_deque.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/macros.h"
@@ -271,12 +271,12 @@ void GLHelperScaling::ConvertScalerOpsToScalerStages(
const gfx::Size& dst_size,
bool vertically_flip_texture,
bool swizzle,
- std::deque<GLHelperScaling::ScaleOp>* x_ops,
- std::deque<GLHelperScaling::ScaleOp>* y_ops,
+ base::circular_deque<GLHelperScaling::ScaleOp>* x_ops,
+ base::circular_deque<GLHelperScaling::ScaleOp>* y_ops,
std::vector<ScalerStage>* scaler_stages) {
while (!x_ops->empty() || !y_ops->empty()) {
gfx::Size intermediate_size = src_subrect.size();
- std::deque<ScaleOp>* current_queue = NULL;
+ base::circular_deque<ScaleOp>* current_queue = NULL;
if (!y_ops->empty()) {
current_queue = y_ops;
@@ -397,7 +397,7 @@ void GLHelperScaling::ComputeScalerStages(
return;
}
- std::deque<GLHelperScaling::ScaleOp> x_ops, y_ops;
+ base::circular_deque<GLHelperScaling::ScaleOp> x_ops, y_ops;
GLHelperScaling::ScaleOp::AddOps(src_subrect.width(), dst_size.width(), true,
quality == GLHelper::SCALER_QUALITY_GOOD,
&x_ops);
diff --git a/chromium/components/viz/common/gl_helper_scaling.h b/chromium/components/viz/common/gl_helper_scaling.h
index a37ea919ee5..1d21916942b 100644
--- a/chromium/components/viz/common/gl_helper_scaling.h
+++ b/chromium/components/viz/common/gl_helper_scaling.h
@@ -5,10 +5,10 @@
#ifndef COMPONENTS_VIZ_COMMON_GL_HELPER_SCALING_H_
#define COMPONENTS_VIZ_COMMON_GL_HELPER_SCALING_H_
-#include <deque>
#include <map>
#include <vector>
+#include "base/containers/circular_deque.h"
#include "base/macros.h"
#include "components/viz/common/gl_helper.h"
#include "components/viz/common/viz_common_export.h"
@@ -97,7 +97,7 @@ class VIZ_COMMON_EXPORT GLHelperScaling {
int dst,
bool scale_x,
bool allow3,
- std::deque<ScaleOp>* ops) {
+ base::circular_deque<ScaleOp>* ops) {
int num_downscales = 0;
if (allow3 && dst * 3 >= src && dst * 2 < src) {
// Technically, this should be a scale up and then a
@@ -177,8 +177,8 @@ class VIZ_COMMON_EXPORT GLHelperScaling {
const gfx::Size& dst_size,
bool vertically_flip_texture,
bool swizzle,
- std::deque<GLHelperScaling::ScaleOp>* x_ops,
- std::deque<GLHelperScaling::ScaleOp>* y_ops,
+ base::circular_deque<GLHelperScaling::ScaleOp>* x_ops,
+ base::circular_deque<GLHelperScaling::ScaleOp>* y_ops,
std::vector<ScalerStage>* scaler_stages);
scoped_refptr<ShaderProgram> GetShaderProgram(ShaderType type, bool swizzle);
diff --git a/chromium/components/viz/common/gl_helper_unittest.cc b/chromium/components/viz/common/gl_helper_unittest.cc
index 34192b4837c..49a42f581b8 100644
--- a/chromium/components/viz/common/gl_helper_unittest.cc
+++ b/chromium/components/viz/common/gl_helper_unittest.cc
@@ -960,7 +960,7 @@ class GLHelperTest : public testing::Test {
for (int x = 0; x < bmp1.width(); ++x) {
if (!ColorsClose(bmp1.getColor(x, y), bmp2.getColor(x, y),
bmp1.colorType())) {
- LOG(ERROR) << "Bitmap color comparision failure";
+ LOG(ERROR) << "Bitmap color comparison failure";
return false;
}
}
@@ -1038,7 +1038,7 @@ class GLHelperTest : public testing::Test {
ReadBackTexture(src_texture, src_size, pixels, color_type, async);
bool result = IsEqual(input_pixels, output_pixels);
if (!result) {
- LOG(ERROR) << "Bitmap comparision failure Pattern-1";
+ LOG(ERROR) << "Bitmap comparison failure Pattern-1";
return false;
}
const int rect_w = 10, rect_h = 4, src_grid_pitch = 10, src_grid_width = 4;
@@ -1051,7 +1051,7 @@ class GLHelperTest : public testing::Test {
ReadBackTexture(src_texture, src_size, pixels, color_type, async);
result = IsEqual(input_pixels, output_pixels);
if (!result) {
- LOG(ERROR) << "Bitmap comparision failure Pattern-2";
+ LOG(ERROR) << "Bitmap comparison failure Pattern-2";
return false;
}
// Test Pattern-3, Fill with CheckerBoard Pattern.
@@ -1062,7 +1062,7 @@ class GLHelperTest : public testing::Test {
ReadBackTexture(src_texture, src_size, pixels, color_type, async);
result = IsEqual(input_pixels, output_pixels);
if (!result) {
- LOG(ERROR) << "Bitmap comparision failure Pattern-3";
+ LOG(ERROR) << "Bitmap comparison failure Pattern-3";
return false;
}
gl_->DeleteTextures(1, &src_texture);
@@ -1073,7 +1073,7 @@ class GLHelperTest : public testing::Test {
}
void TestAddOps(int src, int dst, bool scale_x, bool allow3) {
- std::deque<GLHelperScaling::ScaleOp> ops;
+ base::circular_deque<GLHelperScaling::ScaleOp> ops;
GLHelperScaling::ScaleOp::AddOps(src, dst, scale_x, allow3, &ops);
// Scale factor 3 is a special case.
// It is currently only allowed by itself.
@@ -1249,7 +1249,7 @@ class GLHelperTest : public testing::Test {
gpu::gles2::GLES2Interface* gl_;
std::unique_ptr<GLHelper> helper_;
std::unique_ptr<GLHelperScaling> helper_scaling_;
- std::deque<GLHelperScaling::ScaleOp> x_ops_, y_ops_;
+ base::circular_deque<GLHelperScaling::ScaleOp> x_ops_, y_ops_;
};
class GLHelperPixelTest : public GLHelperTest {
diff --git a/chromium/components/viz/common/gpu/DEPS b/chromium/components/viz/common/gpu/DEPS
index 945aba3fc2b..d038e11da6e 100644
--- a/chromium/components/viz/common/gpu/DEPS
+++ b/chromium/components/viz/common/gpu/DEPS
@@ -5,7 +5,7 @@ include_rules = [
"+gpu/GLES2/gl2extchromium.h",
"+gpu/ipc",
"+gpu/skia_bindings",
- "+ui/gfx",
+ "+gpu/vulkan",
"+third_party/khronos/GLES2/gl2.h",
"+third_party/khronos/GLES2/gl2ext.h",
"+third_party/skia/include/gpu",
diff --git a/chromium/components/viz/common/gpu/in_process_context_provider.h b/chromium/components/viz/common/gpu/in_process_context_provider.h
index 493191fc389..f1eea6c030f 100644
--- a/chromium/components/viz/common/gpu/in_process_context_provider.h
+++ b/chromium/components/viz/common/gpu/in_process_context_provider.h
@@ -33,8 +33,7 @@ class GrContextForGLES2Interface;
namespace viz {
-class VIZ_COMMON_EXPORT InProcessContextProvider
- : public NON_EXPORTED_BASE(ContextProvider) {
+class VIZ_COMMON_EXPORT InProcessContextProvider : public ContextProvider {
public:
InProcessContextProvider(
scoped_refptr<gpu::InProcessCommandBuffer::Service> service,
diff --git a/chromium/components/viz/common/gpu/vulkan_context_provider.h b/chromium/components/viz/common/gpu/vulkan_context_provider.h
new file mode 100644
index 00000000000..0dc77b003fa
--- /dev/null
+++ b/chromium/components/viz/common/gpu/vulkan_context_provider.h
@@ -0,0 +1,30 @@
+// Copyright (c) 2016 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 COMPONENTS_VIZ_COMMON_GPU_VULKAN_CONTEXT_PROVIDER_H_
+#define COMPONENTS_VIZ_COMMON_GPU_VULKAN_CONTEXT_PROVIDER_H_
+
+#include "base/memory/ref_counted.h"
+#include "components/viz/common/viz_common_export.h"
+
+namespace gpu {
+class VulkanDeviceQueue;
+}
+
+namespace viz {
+
+// The VulkanContextProvider groups sharing of vulkan objects synchronously.
+class VIZ_COMMON_EXPORT VulkanContextProvider
+ : public base::RefCountedThreadSafe<VulkanContextProvider> {
+ public:
+ virtual gpu::VulkanDeviceQueue* GetDeviceQueue() = 0;
+
+ protected:
+ friend class base::RefCountedThreadSafe<VulkanContextProvider>;
+ virtual ~VulkanContextProvider() {}
+};
+
+} // namespace viz
+
+#endif // COMPONENTS_VIZ_COMMON_GPU_VULKAN_CONTEXT_PROVIDER_H_
diff --git a/chromium/components/viz/common/gpu/vulkan_in_process_context_provider.cc b/chromium/components/viz/common/gpu/vulkan_in_process_context_provider.cc
new file mode 100644
index 00000000000..d1714290d3d
--- /dev/null
+++ b/chromium/components/viz/common/gpu/vulkan_in_process_context_provider.cc
@@ -0,0 +1,73 @@
+// Copyright (c) 2016 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 "components/viz/common/gpu/vulkan_in_process_context_provider.h"
+#include "gpu/vulkan/features.h"
+
+#if BUILDFLAG(ENABLE_VULKAN)
+#include "gpu/vulkan/vulkan_device_queue.h"
+#include "gpu/vulkan/vulkan_implementation.h"
+#endif // BUILDFLAG(ENABLE_VULKAN)
+
+namespace viz {
+
+scoped_refptr<VulkanInProcessContextProvider>
+VulkanInProcessContextProvider::Create() {
+#if BUILDFLAG(ENABLE_VULKAN)
+ if (!gpu::VulkanSupported())
+ return nullptr;
+
+ scoped_refptr<VulkanInProcessContextProvider> context_provider(
+ new VulkanInProcessContextProvider);
+ if (!context_provider->Initialize())
+ return nullptr;
+ return context_provider;
+#else
+ return nullptr;
+#endif
+}
+
+bool VulkanInProcessContextProvider::Initialize() {
+#if BUILDFLAG(ENABLE_VULKAN)
+ DCHECK(!device_queue_);
+ std::unique_ptr<gpu::VulkanDeviceQueue> device_queue(
+ new gpu::VulkanDeviceQueue);
+ if (!device_queue->Initialize(
+ gpu::VulkanDeviceQueue::GRAPHICS_QUEUE_FLAG |
+ gpu::VulkanDeviceQueue::PRESENTATION_SUPPORT_QUEUE_FLAG)) {
+ device_queue->Destroy();
+ return false;
+ }
+
+ device_queue_ = std::move(device_queue);
+ return true;
+#else
+ return false;
+#endif
+}
+
+void VulkanInProcessContextProvider::Destroy() {
+#if BUILDFLAG(ENABLE_VULKAN)
+ if (device_queue_) {
+ device_queue_->Destroy();
+ device_queue_.reset();
+ }
+#endif
+}
+
+gpu::VulkanDeviceQueue* VulkanInProcessContextProvider::GetDeviceQueue() {
+#if BUILDFLAG(ENABLE_VULKAN)
+ return device_queue_.get();
+#else
+ return nullptr;
+#endif
+}
+
+VulkanInProcessContextProvider::VulkanInProcessContextProvider() {}
+
+VulkanInProcessContextProvider::~VulkanInProcessContextProvider() {
+ Destroy();
+}
+
+} // namespace viz
diff --git a/chromium/components/viz/common/gpu/vulkan_in_process_context_provider.h b/chromium/components/viz/common/gpu/vulkan_in_process_context_provider.h
new file mode 100644
index 00000000000..9a94fccaf99
--- /dev/null
+++ b/chromium/components/viz/common/gpu/vulkan_in_process_context_provider.h
@@ -0,0 +1,45 @@
+// Copyright 2016 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 COMPONENTS_VIZ_COMMON_GPU_VULKAN_IN_PROCESS_CONTEXT_PROVIDER_H_
+#define COMPONENTS_VIZ_COMMON_GPU_VULKAN_IN_PROCESS_CONTEXT_PROVIDER_H_
+
+#include <memory>
+
+#include "components/viz/common/gpu/vulkan_context_provider.h"
+#include "components/viz/common/viz_common_export.h"
+#include "gpu/vulkan/features.h"
+
+namespace gpu {
+class VulkanDeviceQueue;
+}
+
+namespace viz {
+
+class VIZ_COMMON_EXPORT VulkanInProcessContextProvider
+ : public VulkanContextProvider {
+ public:
+ static scoped_refptr<VulkanInProcessContextProvider> Create();
+
+ bool Initialize();
+ void Destroy();
+
+ // VulkanContextProvider implementation
+ gpu::VulkanDeviceQueue* GetDeviceQueue() override;
+
+ protected:
+ VulkanInProcessContextProvider();
+ ~VulkanInProcessContextProvider() override;
+
+ private:
+#if BUILDFLAG(ENABLE_VULKAN)
+ std::unique_ptr<gpu::VulkanDeviceQueue> device_queue_;
+#endif
+
+ DISALLOW_COPY_AND_ASSIGN(VulkanInProcessContextProvider);
+};
+
+} // namespace viz
+
+#endif // COMPONENTS_VIZ_COMMON_GPU_VULKAN_IN_PROCESS_CONTEXT_PROVIDER_H_
diff --git a/chromium/components/viz/common/hit_test/DEPS b/chromium/components/viz/common/hit_test/DEPS
deleted file mode 100644
index b49b8636b9b..00000000000
--- a/chromium/components/viz/common/hit_test/DEPS
+++ /dev/null
@@ -1,4 +0,0 @@
-include_rules = [
- "+ui/gfx/geometry",
- "+ui/gfx/transform.h",
-] \ No newline at end of file
diff --git a/chromium/components/viz/common/hit_test/aggregated_hit_test_region.h b/chromium/components/viz/common/hit_test/aggregated_hit_test_region.h
index b90bfb19a6e..2f93daae037 100644
--- a/chromium/components/viz/common/hit_test/aggregated_hit_test_region.h
+++ b/chromium/components/viz/common/hit_test/aggregated_hit_test_region.h
@@ -15,7 +15,7 @@ namespace viz {
// A AggregatedHitTestRegion element with child_count of kEndOfList indicates
// the last element and end of the list.
-constexpr int kEndOfList = -1;
+constexpr int32_t kEndOfList = -1;
// An array of AggregatedHitTestRegion elements is used to define the
// aggregated hit-test data for the Display.
@@ -24,6 +24,17 @@ constexpr int kEndOfList = -1;
// write the hit_test data, and the viz host can read without
// process hops.
struct AggregatedHitTestRegion {
+ AggregatedHitTestRegion(FrameSinkId frame_sink_id,
+ uint32_t flags,
+ gfx::Rect rect,
+ gfx::Transform transform,
+ int32_t child_count)
+ : frame_sink_id(frame_sink_id),
+ flags(flags),
+ rect(rect),
+ transform(transform),
+ child_count(child_count) {}
+
// The FrameSinkId corresponding to this region. Events that match
// are routed to this surface.
FrameSinkId frame_sink_id;
@@ -41,7 +52,7 @@ struct AggregatedHitTestRegion {
// The number of children including their children below this entry.
// If this element is not matched then child_count elements can be skipped
// to move to the next entry.
- int child_count;
+ int32_t child_count;
};
} // namespace viz
diff --git a/chromium/components/viz/common/quads/DEPS b/chromium/components/viz/common/quads/DEPS
index 766ac6bb3c0..abf379f6838 100644
--- a/chromium/components/viz/common/quads/DEPS
+++ b/chromium/components/viz/common/quads/DEPS
@@ -1,5 +1,9 @@
include_rules = [
+ # TODO(staraz): cc/base was added because SharedQuadState includes
+ # cc::MathUtil. Remove it once cc/base/math_util* are moved to viz.
+ "+cc/base",
+
"+gpu/command_buffer/common",
"+mojo/public/cpp/bindings",
- "+ui/gfx",
+ "+third_party/skia",
]
diff --git a/chromium/components/viz/common/quads/copy_output_request.cc b/chromium/components/viz/common/quads/copy_output_request.cc
new file mode 100644
index 00000000000..de505d68c32
--- /dev/null
+++ b/chromium/components/viz/common/quads/copy_output_request.cc
@@ -0,0 +1,68 @@
+// Copyright 2013 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 "components/viz/common/quads/copy_output_request.h"
+
+#include "base/bind.h"
+#include "base/logging.h"
+#include "base/trace_event/trace_event.h"
+#include "components/viz/common/quads/copy_output_result.h"
+#include "components/viz/common/quads/texture_mailbox.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+
+namespace viz {
+
+CopyOutputRequest::CopyOutputRequest() : force_bitmap_result_(false) {}
+
+CopyOutputRequest::CopyOutputRequest(bool force_bitmap_result,
+ CopyOutputRequestCallback result_callback)
+ : force_bitmap_result_(force_bitmap_result),
+ result_callback_(std::move(result_callback)) {
+ DCHECK(!result_callback_.is_null());
+ TRACE_EVENT_ASYNC_BEGIN0("viz", "CopyOutputRequest", this);
+}
+
+CopyOutputRequest::~CopyOutputRequest() {
+ if (!result_callback_.is_null())
+ SendResult(CopyOutputResult::CreateEmptyResult());
+}
+
+void CopyOutputRequest::SendResult(std::unique_ptr<CopyOutputResult> result) {
+ TRACE_EVENT_ASYNC_END1("viz", "CopyOutputRequest", this, "success",
+ !result->IsEmpty());
+ if (result_task_runner_) {
+ result_task_runner_->PostTask(
+ FROM_HERE,
+ base::BindOnce(std::move(result_callback_), std::move(result)));
+ result_task_runner_ = nullptr;
+ } else {
+ std::move(result_callback_).Run(std::move(result));
+ }
+}
+
+void CopyOutputRequest::SendEmptyResult() {
+ SendResult(CopyOutputResult::CreateEmptyResult());
+}
+
+void CopyOutputRequest::SendBitmapResult(std::unique_ptr<SkBitmap> bitmap) {
+ SendResult(CopyOutputResult::CreateBitmapResult(std::move(bitmap)));
+}
+
+void CopyOutputRequest::SendTextureResult(
+ const gfx::Size& size,
+ const TextureMailbox& texture_mailbox,
+ std::unique_ptr<SingleReleaseCallback> release_callback) {
+ DCHECK(texture_mailbox.IsTexture());
+ SendResult(CopyOutputResult::CreateTextureResult(
+ size, texture_mailbox, std::move(release_callback)));
+}
+
+void CopyOutputRequest::SetTextureMailbox(
+ const TextureMailbox& texture_mailbox) {
+ DCHECK(!force_bitmap_result_);
+ DCHECK(texture_mailbox.IsTexture());
+ texture_mailbox_ = texture_mailbox;
+}
+
+} // namespace viz
diff --git a/chromium/components/viz/common/quads/copy_output_request.h b/chromium/components/viz/common/quads/copy_output_request.h
new file mode 100644
index 00000000000..ccb42adfdb2
--- /dev/null
+++ b/chromium/components/viz/common/quads/copy_output_request.h
@@ -0,0 +1,114 @@
+// Copyright 2013 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 COMPONENTS_VIZ_COMMON_QUADS_COPY_OUTPUT_REQUEST_H_
+#define COMPONENTS_VIZ_COMMON_QUADS_COPY_OUTPUT_REQUEST_H_
+
+#include <memory>
+
+#include "base/callback.h"
+#include "base/memory/ptr_util.h"
+#include "base/optional.h"
+#include "base/task_runner.h"
+#include "base/unguessable_token.h"
+#include "components/viz/common/quads/single_release_callback.h"
+#include "components/viz/common/quads/texture_mailbox.h"
+#include "components/viz/common/viz_common_export.h"
+#include "mojo/public/cpp/bindings/struct_traits.h"
+#include "ui/gfx/geometry/rect.h"
+
+class SkBitmap;
+
+namespace viz {
+
+namespace mojom {
+class CopyOutputRequestDataView;
+}
+
+class CopyOutputResult;
+
+class VIZ_COMMON_EXPORT CopyOutputRequest {
+ public:
+ using CopyOutputRequestCallback =
+ base::OnceCallback<void(std::unique_ptr<CopyOutputResult> result)>;
+
+ static std::unique_ptr<CopyOutputRequest> CreateEmptyRequest() {
+ return base::WrapUnique(new CopyOutputRequest);
+ }
+ static std::unique_ptr<CopyOutputRequest> CreateRequest(
+ CopyOutputRequestCallback result_callback) {
+ return base::WrapUnique(
+ new CopyOutputRequest(false, std::move(result_callback)));
+ }
+ static std::unique_ptr<CopyOutputRequest> CreateBitmapRequest(
+ CopyOutputRequestCallback result_callback) {
+ return base::WrapUnique(
+ new CopyOutputRequest(true, std::move(result_callback)));
+ }
+
+ ~CopyOutputRequest();
+
+ bool IsEmpty() const { return result_callback_.is_null(); }
+
+ // Requests that the result callback be run as a task posted to the given
+ // |task_runner|. If this is not set, the result callback could be run from
+ // any context.
+ void set_result_task_runner(scoped_refptr<base::TaskRunner> task_runner) {
+ result_task_runner_ = std::move(task_runner);
+ }
+ bool has_result_task_runner() const { return !!result_task_runner_; }
+
+ // Optionally specify the source of this copy request. If set when this copy
+ // request is submitted to a layer, a prior uncommitted copy request from the
+ // same source will be aborted.
+ void set_source(const base::UnguessableToken& source) { source_ = source; }
+ bool has_source() const { return source_.has_value(); }
+ const base::UnguessableToken& source() const { return *source_; }
+
+ bool force_bitmap_result() const { return force_bitmap_result_; }
+
+ // By default copy requests copy the entire layer's subtree output. If an
+ // area is given, then the intersection of this rect (in layer space) with
+ // the layer's subtree output will be returned.
+ void set_area(const gfx::Rect& area) { area_ = area; }
+ bool has_area() const { return area_.has_value(); }
+ const gfx::Rect& area() const { return *area_; }
+
+ // By default copy requests create a new TextureMailbox to return contents
+ // in. This allows a client to provide a TextureMailbox, and the compositor
+ // will place the result inside the TextureMailbox.
+ void SetTextureMailbox(const TextureMailbox& texture_mailbox);
+ bool has_texture_mailbox() const { return texture_mailbox_.has_value(); }
+ const TextureMailbox& texture_mailbox() const { return *texture_mailbox_; }
+
+ void SendEmptyResult();
+ void SendBitmapResult(std::unique_ptr<SkBitmap> bitmap);
+ void SendTextureResult(
+ const gfx::Size& size,
+ const TextureMailbox& texture_mailbox,
+ std::unique_ptr<SingleReleaseCallback> release_callback);
+
+ void SendResult(std::unique_ptr<CopyOutputResult> result);
+
+ private:
+ friend struct mojo::StructTraits<mojom::CopyOutputRequestDataView,
+ std::unique_ptr<CopyOutputRequest>>;
+
+ CopyOutputRequest();
+ CopyOutputRequest(bool force_bitmap_result,
+ CopyOutputRequestCallback result_callback);
+
+ scoped_refptr<base::TaskRunner> result_task_runner_;
+ base::Optional<base::UnguessableToken> source_;
+ bool force_bitmap_result_;
+ base::Optional<gfx::Rect> area_;
+ base::Optional<TextureMailbox> texture_mailbox_;
+ CopyOutputRequestCallback result_callback_;
+
+ DISALLOW_COPY_AND_ASSIGN(CopyOutputRequest);
+};
+
+} // namespace viz
+
+#endif // COMPONENTS_VIZ_COMMON_QUADS_COPY_OUTPUT_REQUEST_H_
diff --git a/chromium/components/viz/common/quads/copy_output_result.cc b/chromium/components/viz/common/quads/copy_output_result.cc
new file mode 100644
index 00000000000..62f723c8223
--- /dev/null
+++ b/chromium/components/viz/common/quads/copy_output_result.cc
@@ -0,0 +1,47 @@
+// Copyright 2013 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 "components/viz/common/quads/copy_output_result.h"
+
+#include "base/logging.h"
+#include "components/viz/common/quads/texture_mailbox.h"
+
+namespace viz {
+
+CopyOutputResult::CopyOutputResult() {}
+
+CopyOutputResult::CopyOutputResult(std::unique_ptr<SkBitmap> bitmap)
+ : size_(bitmap->width(), bitmap->height()), bitmap_(std::move(bitmap)) {
+ DCHECK(bitmap_);
+}
+
+CopyOutputResult::CopyOutputResult(
+ const gfx::Size& size,
+ const TextureMailbox& texture_mailbox,
+ std::unique_ptr<SingleReleaseCallback> release_callback)
+ : size_(size),
+ texture_mailbox_(texture_mailbox),
+ release_callback_(std::move(release_callback)) {
+ DCHECK(texture_mailbox_.IsTexture());
+}
+
+CopyOutputResult::~CopyOutputResult() {
+ if (release_callback_)
+ release_callback_->Run(gpu::SyncToken(), false);
+}
+
+std::unique_ptr<SkBitmap> CopyOutputResult::TakeBitmap() {
+ return std::move(bitmap_);
+}
+
+void CopyOutputResult::TakeTexture(
+ TextureMailbox* texture_mailbox,
+ std::unique_ptr<SingleReleaseCallback>* release_callback) {
+ *texture_mailbox = texture_mailbox_;
+ *release_callback = std::move(release_callback_);
+
+ texture_mailbox_ = TextureMailbox();
+}
+
+} // namespace viz
diff --git a/chromium/components/viz/common/quads/copy_output_result.h b/chromium/components/viz/common/quads/copy_output_result.h
new file mode 100644
index 00000000000..901ea5c9628
--- /dev/null
+++ b/chromium/components/viz/common/quads/copy_output_result.h
@@ -0,0 +1,79 @@
+// Copyright 2013 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 COMPONENTS_VIZ_COMMON_QUADS_COPY_OUTPUT_RESULT_H_
+#define COMPONENTS_VIZ_COMMON_QUADS_COPY_OUTPUT_RESULT_H_
+
+#include <memory>
+
+#include "base/memory/ptr_util.h"
+#include "components/viz/common/quads/single_release_callback.h"
+#include "components/viz/common/quads/texture_mailbox.h"
+#include "components/viz/common/viz_common_export.h"
+#include "mojo/public/cpp/bindings/struct_traits.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/gfx/geometry/size.h"
+
+class SkBitmap;
+
+namespace cc {
+namespace mojom {
+class CopyOutputResultDataView;
+}
+} // namespace cc
+
+namespace viz {
+
+class TextureMailbox;
+
+class VIZ_COMMON_EXPORT CopyOutputResult {
+ public:
+ static std::unique_ptr<CopyOutputResult> CreateEmptyResult() {
+ return base::WrapUnique(new CopyOutputResult);
+ }
+ static std::unique_ptr<CopyOutputResult> CreateBitmapResult(
+ std::unique_ptr<SkBitmap> bitmap) {
+ return base::WrapUnique(new CopyOutputResult(std::move(bitmap)));
+ }
+ static std::unique_ptr<CopyOutputResult> CreateTextureResult(
+ const gfx::Size& size,
+ const TextureMailbox& texture_mailbox,
+ std::unique_ptr<SingleReleaseCallback> release_callback) {
+ return base::WrapUnique(new CopyOutputResult(size, texture_mailbox,
+ std::move(release_callback)));
+ }
+
+ ~CopyOutputResult();
+
+ bool IsEmpty() const { return !HasBitmap() && !HasTexture(); }
+ bool HasBitmap() const { return !!bitmap_ && !bitmap_->isNull(); }
+ bool HasTexture() const { return texture_mailbox_.IsValid(); }
+
+ gfx::Size size() const { return size_; }
+ std::unique_ptr<SkBitmap> TakeBitmap();
+ void TakeTexture(TextureMailbox* texture_mailbox,
+ std::unique_ptr<SingleReleaseCallback>* release_callback);
+
+ private:
+ friend struct mojo::StructTraits<cc::mojom::CopyOutputResultDataView,
+ std::unique_ptr<CopyOutputResult>>;
+
+ CopyOutputResult();
+ explicit CopyOutputResult(std::unique_ptr<SkBitmap> bitmap);
+ explicit CopyOutputResult(
+ const gfx::Size& size,
+ const TextureMailbox& texture_mailbox,
+ std::unique_ptr<SingleReleaseCallback> release_callback);
+
+ gfx::Size size_;
+ std::unique_ptr<SkBitmap> bitmap_;
+ TextureMailbox texture_mailbox_;
+ std::unique_ptr<SingleReleaseCallback> release_callback_;
+
+ DISALLOW_COPY_AND_ASSIGN(CopyOutputResult);
+};
+
+} // namespace viz
+
+#endif // COMPONENTS_VIZ_COMMON_QUADS_COPY_OUTPUT_RESULT_H_
diff --git a/chromium/components/viz/common/quads/release_callback.h b/chromium/components/viz/common/quads/release_callback.h
new file mode 100644
index 00000000000..8166416c16c
--- /dev/null
+++ b/chromium/components/viz/common/quads/release_callback.h
@@ -0,0 +1,21 @@
+// Copyright 2013 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 COMPONENTS_VIZ_COMMON_QUADS_RELEASE_CALLBACK_H_
+#define COMPONENTS_VIZ_COMMON_QUADS_RELEASE_CALLBACK_H_
+
+#include "base/callback.h"
+
+namespace gpu {
+struct SyncToken;
+} // namespace gpu
+
+namespace viz {
+
+typedef base::Callback<void(const gpu::SyncToken& sync_token, bool is_lost)>
+ ReleaseCallback;
+
+} // namespace viz
+
+#endif // COMPONENTS_VIZ_COMMON_QUADS_RELEASE_CALLBACK_H_
diff --git a/chromium/components/viz/common/quads/resource_format.h b/chromium/components/viz/common/quads/resource_format.h
deleted file mode 100644
index 4ae7b0675fb..00000000000
--- a/chromium/components/viz/common/quads/resource_format.h
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright 2013 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 COMPONENTS_VIZ_COMMON_QUADS_RESOURCE_FORMAT_H_
-#define COMPONENTS_VIZ_COMMON_QUADS_RESOURCE_FORMAT_H_
-
-#include "base/logging.h"
-#include "ui/gfx/buffer_types.h"
-
-// TODO(prashant.n): Including third_party/khronos/GLES2/gl2.h causes
-// redefinition errors as macros/functions defined in it conflict with
-// macros/functions defined in ui/gl/gl_bindings.h. (http://crbug.com/512833).
-typedef unsigned int GLenum;
-
-namespace viz {
-
-// Keep in sync with arrays below.
-enum ResourceFormat {
- RGBA_8888,
- RGBA_4444,
- BGRA_8888,
- ALPHA_8,
- LUMINANCE_8,
- RGB_565,
- ETC1,
- RED_8,
- LUMINANCE_F16,
- RGBA_F16,
- RESOURCE_FORMAT_MAX = RGBA_F16,
-};
-
-} // namespace viz
-
-#endif // COMPONENTS_VIZ_COMMON_QUADS_RESOURCE_FORMAT_H_
diff --git a/chromium/components/viz/common/quads/shared_quad_state.cc b/chromium/components/viz/common/quads/shared_quad_state.cc
new file mode 100644
index 00000000000..71eed58d78a
--- /dev/null
+++ b/chromium/components/viz/common/quads/shared_quad_state.cc
@@ -0,0 +1,65 @@
+// Copyright 2012 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 "components/viz/common/quads/shared_quad_state.h"
+
+#include "base/trace_event/trace_event.h"
+#include "base/trace_event/trace_event_argument.h"
+#include "base/values.h"
+#include "cc/base/math_util.h"
+#include "components/viz/common/traced_value.h"
+#include "third_party/skia/include/core/SkBlendMode.h"
+
+namespace viz {
+
+SharedQuadState::SharedQuadState()
+ : is_clipped(false),
+ opacity(0.f),
+ blend_mode(SkBlendMode::kSrcOver),
+ sorting_context_id(0) {}
+
+SharedQuadState::SharedQuadState(const SharedQuadState& other) = default;
+
+SharedQuadState::~SharedQuadState() {
+ TRACE_EVENT_OBJECT_DELETED_WITH_ID(
+ TRACE_DISABLED_BY_DEFAULT("cc.debug.quads"), "viz::SharedQuadState",
+ this);
+}
+
+void SharedQuadState::SetAll(const gfx::Transform& quad_to_target_transform,
+ const gfx::Rect& quad_layer_rect,
+ const gfx::Rect& visible_quad_layer_rect,
+ const gfx::Rect& clip_rect,
+ bool is_clipped,
+ float opacity,
+ SkBlendMode blend_mode,
+ int sorting_context_id) {
+ this->quad_to_target_transform = quad_to_target_transform;
+ this->quad_layer_rect = quad_layer_rect;
+ this->visible_quad_layer_rect = visible_quad_layer_rect;
+ this->clip_rect = clip_rect;
+ this->is_clipped = is_clipped;
+ this->opacity = opacity;
+ this->blend_mode = blend_mode;
+ this->sorting_context_id = sorting_context_id;
+}
+
+void SharedQuadState::AsValueInto(base::trace_event::TracedValue* value) const {
+ cc::MathUtil::AddToTracedValue("transform", quad_to_target_transform, value);
+ cc::MathUtil::AddToTracedValue("layer_content_rect", quad_layer_rect, value);
+ cc::MathUtil::AddToTracedValue("layer_visible_content_rect",
+ visible_quad_layer_rect, value);
+
+ value->SetBoolean("is_clipped", is_clipped);
+
+ cc::MathUtil::AddToTracedValue("clip_rect", clip_rect, value);
+
+ value->SetDouble("opacity", opacity);
+ value->SetString("blend_mode", SkBlendMode_Name(blend_mode));
+ TracedValue::MakeDictIntoImplicitSnapshotWithCategory(
+ TRACE_DISABLED_BY_DEFAULT("cc.debug.quads"), value,
+ "viz::SharedQuadState", this);
+}
+
+} // namespace viz
diff --git a/chromium/components/viz/common/quads/shared_quad_state.h b/chromium/components/viz/common/quads/shared_quad_state.h
new file mode 100644
index 00000000000..d1b0a974745
--- /dev/null
+++ b/chromium/components/viz/common/quads/shared_quad_state.h
@@ -0,0 +1,61 @@
+// Copyright 2012 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 COMPONENTS_VIZ_COMMON_QUADS_SHARED_QUAD_STATE_H_
+#define COMPONENTS_VIZ_COMMON_QUADS_SHARED_QUAD_STATE_H_
+
+#include <memory>
+
+#include "components/viz/common/viz_common_export.h"
+#include "third_party/skia/include/core/SkBlendMode.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/transform.h"
+
+namespace base {
+namespace trace_event {
+class TracedValue;
+}
+} // namespace base
+
+namespace viz {
+
+// SharedQuadState holds a set of properties that are common across multiple
+// DrawQuads. It's purely an optimization - the properties behave in exactly the
+// same way as if they were replicated on each DrawQuad. A given SharedQuadState
+// can only be shared by DrawQuads that are adjacent in their RenderPass'
+// QuadList.
+class VIZ_COMMON_EXPORT SharedQuadState {
+ public:
+ SharedQuadState();
+ SharedQuadState(const SharedQuadState& other);
+ ~SharedQuadState();
+
+ void SetAll(const gfx::Transform& quad_to_target_transform,
+ const gfx::Rect& layer_rect,
+ const gfx::Rect& visible_layer_rect,
+ const gfx::Rect& clip_rect,
+ bool is_clipped,
+ float opacity,
+ SkBlendMode blend_mode,
+ int sorting_context_id);
+ void AsValueInto(base::trace_event::TracedValue* dict) const;
+
+ // Transforms quad rects into the target content space.
+ gfx::Transform quad_to_target_transform;
+ // The rect of the quads' originating layer in the space of the quad rects.
+ gfx::Rect quad_layer_rect;
+ // The size of the visible area in the quads' originating layer, in the space
+ // of the quad rects.
+ gfx::Rect visible_quad_layer_rect;
+ // This rect lives in the target content space.
+ gfx::Rect clip_rect;
+ bool is_clipped;
+ float opacity;
+ SkBlendMode blend_mode;
+ int sorting_context_id;
+};
+
+} // namespace viz
+
+#endif // COMPONENTS_VIZ_COMMON_QUADS_SHARED_QUAD_STATE_H_
diff --git a/chromium/components/viz/common/quads/single_release_callback.cc b/chromium/components/viz/common/quads/single_release_callback.cc
new file mode 100644
index 00000000000..bd3dca9eb12
--- /dev/null
+++ b/chromium/components/viz/common/quads/single_release_callback.cc
@@ -0,0 +1,29 @@
+// Copyright 2013 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 "components/viz/common/quads/single_release_callback.h"
+
+#include "base/callback_helpers.h"
+#include "base/logging.h"
+
+namespace viz {
+
+SingleReleaseCallback::SingleReleaseCallback(const ReleaseCallback& callback)
+ : callback_(callback) {
+ DCHECK(!callback_.is_null())
+ << "Use a NULL SingleReleaseCallback for an empty callback.";
+}
+
+SingleReleaseCallback::~SingleReleaseCallback() {
+ DCHECK(callback_.is_null()) << "SingleReleaseCallback was never run.";
+}
+
+void SingleReleaseCallback::Run(const gpu::SyncToken& sync_token,
+ bool is_lost) {
+ DCHECK(!callback_.is_null())
+ << "SingleReleaseCallback was run more than once.";
+ base::ResetAndReturn(&callback_).Run(sync_token, is_lost);
+}
+
+} // namespace viz
diff --git a/chromium/components/viz/common/quads/single_release_callback.h b/chromium/components/viz/common/quads/single_release_callback.h
new file mode 100644
index 00000000000..29420f57487
--- /dev/null
+++ b/chromium/components/viz/common/quads/single_release_callback.h
@@ -0,0 +1,35 @@
+// Copyright 2013 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 COMPONENTS_VIZ_COMMON_QUADS_SINGLE_RELEASE_CALLBACK_H_
+#define COMPONENTS_VIZ_COMMON_QUADS_SINGLE_RELEASE_CALLBACK_H_
+
+#include <memory>
+
+#include "base/memory/ptr_util.h"
+#include "components/viz/common/quads/release_callback.h"
+#include "components/viz/common/viz_common_export.h"
+
+namespace viz {
+
+class VIZ_COMMON_EXPORT SingleReleaseCallback {
+ public:
+ static std::unique_ptr<SingleReleaseCallback> Create(
+ const ReleaseCallback& cb) {
+ return base::WrapUnique(new SingleReleaseCallback(cb));
+ }
+
+ ~SingleReleaseCallback();
+
+ void Run(const gpu::SyncToken& sync_token, bool is_lost);
+
+ private:
+ explicit SingleReleaseCallback(const ReleaseCallback& callback);
+
+ ReleaseCallback callback_;
+};
+
+} // namespace viz
+
+#endif // COMPONENTS_VIZ_COMMON_QUADS_SINGLE_RELEASE_CALLBACK_H_
diff --git a/chromium/components/viz/common/resources/DEPS b/chromium/components/viz/common/resources/DEPS
index ce3dad47826..fe456ebd62e 100644
--- a/chromium/components/viz/common/resources/DEPS
+++ b/chromium/components/viz/common/resources/DEPS
@@ -1,6 +1,6 @@
include_rules = [
+ "+gpu/command_buffer/common",
"+gpu/GLES2",
"+third_party/khronos/GLES2",
"+third_party/skia",
- "+ui/gfx",
]
diff --git a/chromium/components/viz/common/resources/buffer_to_texture_target_map.cc b/chromium/components/viz/common/resources/buffer_to_texture_target_map.cc
index 83877f4e1fb..4d3e66b9058 100644
--- a/chromium/components/viz/common/resources/buffer_to_texture_target_map.cc
+++ b/chromium/components/viz/common/resources/buffer_to_texture_target_map.cc
@@ -7,7 +7,7 @@
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
-#include "gpu/GLES2/gl2extchromium.h"
+#include "third_party/khronos/GLES2/gl2.h"
namespace viz {
diff --git a/chromium/components/viz/common/resources/platform_color.h b/chromium/components/viz/common/resources/platform_color.h
index 505b6d43269..9c0fa1e66e3 100644
--- a/chromium/components/viz/common/resources/platform_color.h
+++ b/chromium/components/viz/common/resources/platform_color.h
@@ -7,7 +7,7 @@
#include "base/logging.h"
#include "base/macros.h"
-#include "components/viz/common/quads/resource_format.h"
+#include "components/viz/common/resources/resource_format.h"
#include "third_party/skia/include/core/SkTypes.h"
namespace viz {
diff --git a/chromium/components/viz/common/resources/resource_format.h b/chromium/components/viz/common/resources/resource_format.h
new file mode 100644
index 00000000000..1e90781fb63
--- /dev/null
+++ b/chromium/components/viz/common/resources/resource_format.h
@@ -0,0 +1,28 @@
+// Copyright 2013 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 COMPONENTS_VIZ_COMMON_RESOURCES_RESOURCE_FORMAT_H_
+#define COMPONENTS_VIZ_COMMON_RESOURCES_RESOURCE_FORMAT_H_
+
+namespace viz {
+
+// If these values are modified, then it is likely that resource_format_utils.cc
+// has to be updated as well.
+enum ResourceFormat {
+ RGBA_8888,
+ RGBA_4444,
+ BGRA_8888,
+ ALPHA_8,
+ LUMINANCE_8,
+ RGB_565,
+ ETC1,
+ RED_8,
+ LUMINANCE_F16,
+ RGBA_F16,
+ RESOURCE_FORMAT_MAX = RGBA_F16,
+};
+
+} // namespace viz
+
+#endif // COMPONENTS_VIZ_COMMON_RESOURCES_RESOURCE_FORMAT_H_
diff --git a/chromium/components/viz/common/resources/resource_format_utils.cc b/chromium/components/viz/common/resources/resource_format_utils.cc
index f15ddc72682..4cee8649088 100644
--- a/chromium/components/viz/common/resources/resource_format_utils.cc
+++ b/chromium/components/viz/common/resources/resource_format_utils.cc
@@ -4,9 +4,11 @@
#include "components/viz/common/resources/resource_format_utils.h"
+#include "base/logging.h"
+#include "base/macros.h"
#include "third_party/khronos/GLES2/gl2.h"
#include "third_party/khronos/GLES2/gl2ext.h"
-#include "ui/gfx/gpu_memory_buffer.h"
+#include "ui/gfx/buffer_types.h"
namespace viz {
@@ -57,7 +59,7 @@ int BitsPerPixel(ResourceFormat format) {
return 0;
}
-GLenum GLDataType(ResourceFormat format) {
+unsigned int GLDataType(ResourceFormat format) {
DCHECK_LE(format, RESOURCE_FORMAT_MAX);
static const GLenum format_gl_data_type[] = {
GL_UNSIGNED_BYTE, // RGBA_8888
@@ -77,7 +79,7 @@ GLenum GLDataType(ResourceFormat format) {
return format_gl_data_type[format];
}
-GLenum GLDataFormat(ResourceFormat format) {
+unsigned int GLDataFormat(ResourceFormat format) {
DCHECK_LE(format, RESOURCE_FORMAT_MAX);
static const GLenum format_gl_data_format[] = {
GL_RGBA, // RGBA_8888
@@ -96,13 +98,13 @@ GLenum GLDataFormat(ResourceFormat format) {
return format_gl_data_format[format];
}
-GLenum GLInternalFormat(ResourceFormat format) {
+unsigned int GLInternalFormat(ResourceFormat format) {
// In GLES2, the internal format must match the texture format. (It no longer
// is true in GLES3, however it still holds for the BGRA extension.)
return GLDataFormat(format);
}
-GLenum GLCopyTextureInternalFormat(ResourceFormat format) {
+unsigned int GLCopyTextureInternalFormat(ResourceFormat format) {
// In GLES2, valid formats for glCopyTexImage2D are: GL_ALPHA, GL_LUMINANCE,
// GL_LUMINANCE_ALPHA, GL_RGB, or GL_RGBA.
// Extensions typically used for glTexImage2D do not also work for
@@ -151,6 +153,23 @@ gfx::BufferFormat BufferFormat(ResourceFormat format) {
return gfx::BufferFormat::RGBA_8888;
}
+GrPixelConfig ToGrPixelConfig(ResourceFormat format) {
+ switch (format) {
+ case RGBA_8888:
+ return kRGBA_8888_GrPixelConfig;
+ case BGRA_8888:
+ return kBGRA_8888_GrPixelConfig;
+ case RGBA_4444:
+ return kRGBA_4444_GrPixelConfig;
+ case RGBA_F16:
+ return kRGBA_half_GrPixelConfig;
+ default:
+ break;
+ }
+ DCHECK(false) << "Unsupported resource format.";
+ return kSkia8888_GrPixelConfig;
+}
+
bool IsResourceFormatCompressed(ResourceFormat format) {
return format == ETC1;
}
diff --git a/chromium/components/viz/common/resources/resource_format_utils.h b/chromium/components/viz/common/resources/resource_format_utils.h
index 935ccc8796e..262d5d67a93 100644
--- a/chromium/components/viz/common/resources/resource_format_utils.h
+++ b/chromium/components/viz/common/resources/resource_format_utils.h
@@ -5,22 +5,35 @@
#ifndef COMPONENTS_VIZ_COMMON_RESOURCES_RESOURCE_FORMAT_UTILS_H_
#define COMPONENTS_VIZ_COMMON_RESOURCES_RESOURCE_FORMAT_UTILS_H_
-#include "components/viz/common/quads/resource_format.h"
-#include "components/viz/common/viz_common_export.h"
+#include "components/viz/common/resources/resource_format.h"
+#include "components/viz/common/viz_resource_format_export.h"
#include "third_party/skia/include/core/SkImageInfo.h"
+#include "third_party/skia/include/gpu/GrTypes.h"
+#include "ui/gfx/buffer_types.h"
namespace viz {
-VIZ_COMMON_EXPORT SkColorType
+VIZ_RESOURCE_FORMAT_EXPORT SkColorType
ResourceFormatToClosestSkColorType(ResourceFormat format);
-VIZ_COMMON_EXPORT int BitsPerPixel(ResourceFormat format);
-VIZ_COMMON_EXPORT GLenum GLDataType(ResourceFormat format);
-VIZ_COMMON_EXPORT GLenum GLDataFormat(ResourceFormat format);
-VIZ_COMMON_EXPORT GLenum GLInternalFormat(ResourceFormat format);
-VIZ_COMMON_EXPORT GLenum GLCopyTextureInternalFormat(ResourceFormat format);
-VIZ_COMMON_EXPORT gfx::BufferFormat BufferFormat(ResourceFormat format);
-VIZ_COMMON_EXPORT bool IsResourceFormatCompressed(ResourceFormat format);
-VIZ_COMMON_EXPORT bool DoesResourceFormatSupportAlpha(ResourceFormat format);
+VIZ_RESOURCE_FORMAT_EXPORT int BitsPerPixel(ResourceFormat format);
+
+// The following functions use unsigned int instead of GLenum, since including
+// third_party/khronos/GLES2/gl2.h causes redefinition errors as
+// macros/functions defined in it conflict with macros/functions defined in
+// ui/gl/gl_bindings.h. See http://crbug.com/512833 for more information.
+VIZ_RESOURCE_FORMAT_EXPORT unsigned int GLDataType(ResourceFormat format);
+VIZ_RESOURCE_FORMAT_EXPORT unsigned int GLDataFormat(ResourceFormat format);
+VIZ_RESOURCE_FORMAT_EXPORT unsigned int GLInternalFormat(ResourceFormat format);
+VIZ_RESOURCE_FORMAT_EXPORT unsigned int GLCopyTextureInternalFormat(
+ ResourceFormat format);
+
+VIZ_RESOURCE_FORMAT_EXPORT gfx::BufferFormat BufferFormat(
+ ResourceFormat format);
+VIZ_RESOURCE_FORMAT_EXPORT bool IsResourceFormatCompressed(
+ ResourceFormat format);
+VIZ_RESOURCE_FORMAT_EXPORT bool DoesResourceFormatSupportAlpha(
+ ResourceFormat format);
+VIZ_RESOURCE_FORMAT_EXPORT GrPixelConfig ToGrPixelConfig(ResourceFormat format);
} // namespace viz
diff --git a/chromium/components/viz/common/resources/resource_id.h b/chromium/components/viz/common/resources/resource_id.h
new file mode 100644
index 00000000000..b7a3a48c1b1
--- /dev/null
+++ b/chromium/components/viz/common/resources/resource_id.h
@@ -0,0 +1,19 @@
+// Copyright 2015 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 COMPONENTS_VIZ_COMMON_RESOURCES_RESOURCE_ID_H_
+#define COMPONENTS_VIZ_COMMON_RESOURCES_RESOURCE_ID_H_
+
+#include <stdint.h>
+
+#include "base/containers/flat_set.h"
+
+namespace viz {
+
+using ResourceId = uint32_t;
+using ResourceIdSet = base::flat_set<ResourceId>;
+
+} // namespace viz
+
+#endif // COMPONENTS_VIZ_COMMON_RESOURCES_RESOURCE_ID_H_
diff --git a/chromium/components/viz/common/resources/returned_resource.h b/chromium/components/viz/common/resources/returned_resource.h
new file mode 100644
index 00000000000..6e60a51e72a
--- /dev/null
+++ b/chromium/components/viz/common/resources/returned_resource.h
@@ -0,0 +1,56 @@
+// Copyright 2013 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 COMPONENTS_VIZ_COMMON_RESOURCES_RETURNED_RESOURCE_H_
+#define COMPONENTS_VIZ_COMMON_RESOURCES_RETURNED_RESOURCE_H_
+
+#include <vector>
+
+#include "components/viz/common/resources/resource_id.h"
+#include "components/viz/common/resources/returned_resource.h"
+#include "components/viz/common/viz_common_export.h"
+#include "gpu/command_buffer/common/sync_token.h"
+
+namespace viz {
+
+// A ReturnedResource is a struct passed along to a child compositor from a
+// parent compositor that corresponds to a TransferableResource that was
+// first passed to the parent compositor.
+struct VIZ_COMMON_EXPORT ReturnedResource {
+ ReturnedResource() : id(0), count(0), lost(false) {}
+
+ bool operator==(const ReturnedResource& other) const {
+ return id == other.id && sync_token == other.sync_token &&
+ count == other.count && lost == other.lost;
+ }
+
+ bool operator!=(const ReturnedResource& other) const {
+ return !(*this == other);
+ }
+
+ // |id| is an identifier generated by the child compositor that uniquely
+ // identifies a resource. This is the same ID space as TransferableResource.
+ ResourceId id;
+
+ // A |sync_token| is an identifier for a point in the parent compositor's
+ // command buffer. The child compositor then issues a WaitSyncPointCHROMIUM
+ // command with this |sync_token| as a parameter into its own command buffer.
+ // This ensures that uses of the resource submitted by the parent compositor
+ // are executed before commands submitted by the child.
+ gpu::SyncToken sync_token;
+
+ // |count| is a reference count for this resource. A resource may be used
+ // by mulitple compositor frames submitted to the parent compositor. |count|
+ // is the number of references being returned back to the child compositor.
+ int count;
+
+ // If the resource is lost, then the returner cannot give a sync point for it,
+ // and so it has taken ownership of the resource. The receiver cannot do
+ // anything with the resource except delete it.
+ bool lost;
+};
+
+} // namespace viz
+
+#endif // COMPONENTS_VIZ_COMMON_RESOURCES_RETURNED_RESOURCE_H_
diff --git a/chromium/components/viz/common/resources/transferable_resource.cc b/chromium/components/viz/common/resources/transferable_resource.cc
new file mode 100644
index 00000000000..7d44148cf52
--- /dev/null
+++ b/chromium/components/viz/common/resources/transferable_resource.cc
@@ -0,0 +1,48 @@
+// Copyright 2012 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 "components/viz/common/resources/transferable_resource.h"
+#include "components/viz/common/resources/returned_resource.h"
+
+namespace viz {
+
+TransferableResource::TransferableResource()
+ : id(0),
+ format(RGBA_8888),
+ buffer_format(gfx::BufferFormat::RGBA_8888),
+ filter(0),
+ read_lock_fences_enabled(false),
+ is_software(false),
+ shared_bitmap_sequence_number(0),
+#if defined(OS_ANDROID)
+ is_backed_by_surface_texture(false),
+ wants_promotion_hint(false),
+#endif
+ is_overlay_candidate(false) {
+}
+
+TransferableResource::TransferableResource(const TransferableResource& other) =
+ default;
+
+TransferableResource::~TransferableResource() {}
+
+ReturnedResource TransferableResource::ToReturnedResource() const {
+ ReturnedResource returned;
+ returned.id = id;
+ returned.sync_token = mailbox_holder.sync_token;
+ returned.count = 1;
+ return returned;
+}
+
+// static
+std::vector<ReturnedResource> TransferableResource::ReturnResources(
+ const std::vector<TransferableResource>& input) {
+ std::vector<ReturnedResource> out;
+ out.reserve(input.size());
+ for (const auto& r : input)
+ out.push_back(r.ToReturnedResource());
+ return out;
+}
+
+} // namespace viz
diff --git a/chromium/components/viz/common/resources/transferable_resource.h b/chromium/components/viz/common/resources/transferable_resource.h
new file mode 100644
index 00000000000..c85f6917a0d
--- /dev/null
+++ b/chromium/components/viz/common/resources/transferable_resource.h
@@ -0,0 +1,54 @@
+// Copyright 2012 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 COMPONENTS_VIZ_COMMON_RESOURCES_TRANSFERABLE_RESOURCE_H_
+#define COMPONENTS_VIZ_COMMON_RESOURCES_TRANSFERABLE_RESOURCE_H_
+
+#include <stdint.h>
+
+#include <vector>
+
+#include "build/build_config.h"
+#include "components/viz/common/resources/resource_format.h"
+#include "components/viz/common/resources/resource_id.h"
+#include "components/viz/common/viz_common_export.h"
+#include "gpu/command_buffer/common/mailbox_holder.h"
+#include "ui/gfx/buffer_types.h"
+#include "ui/gfx/color_space.h"
+#include "ui/gfx/geometry/size.h"
+
+namespace viz {
+
+struct ReturnedResource;
+
+struct VIZ_COMMON_EXPORT TransferableResource {
+ TransferableResource();
+ TransferableResource(const TransferableResource& other);
+ ~TransferableResource();
+
+ ReturnedResource ToReturnedResource() const;
+ static std::vector<ReturnedResource> ReturnResources(
+ const std::vector<TransferableResource>& input);
+
+ ResourceId id;
+ // Refer to ResourceProvider::Resource for the meaning of the following data.
+ ResourceFormat format;
+ gfx::BufferFormat buffer_format;
+ uint32_t filter;
+ gfx::Size size;
+ gpu::MailboxHolder mailbox_holder;
+ bool read_lock_fences_enabled;
+ bool is_software;
+ uint32_t shared_bitmap_sequence_number;
+#if defined(OS_ANDROID)
+ bool is_backed_by_surface_texture;
+ bool wants_promotion_hint;
+#endif
+ bool is_overlay_candidate;
+ gfx::ColorSpace color_space;
+};
+
+} // namespace viz
+
+#endif // COMPONENTS_VIZ_COMMON_RESOURCES_TRANSFERABLE_RESOURCE_H_
diff --git a/chromium/components/viz/common/surfaces/DEPS b/chromium/components/viz/common/surfaces/DEPS
index 826db9ece7e..16764a92a85 100644
--- a/chromium/components/viz/common/surfaces/DEPS
+++ b/chromium/components/viz/common/surfaces/DEPS
@@ -1,4 +1,3 @@
include_rules = [
"+mojo/public/cpp/bindings",
- "+ui/gfx/geometry",
]
diff --git a/chromium/components/viz/common/surfaces/sequence_surface_reference_factory.h b/chromium/components/viz/common/surfaces/sequence_surface_reference_factory.h
index 93fa9534bf2..c3cbde918b3 100644
--- a/chromium/components/viz/common/surfaces/sequence_surface_reference_factory.h
+++ b/chromium/components/viz/common/surfaces/sequence_surface_reference_factory.h
@@ -13,7 +13,7 @@ namespace viz {
// A surface reference factory that uses SurfaceSequence.
class VIZ_COMMON_EXPORT SequenceSurfaceReferenceFactory
- : public NON_EXPORTED_BASE(SurfaceReferenceFactory) {
+ : public SurfaceReferenceFactory {
public:
SequenceSurfaceReferenceFactory() = default;
diff --git a/chromium/components/viz/common/surfaces/stub_surface_reference_factory.cc b/chromium/components/viz/common/surfaces/stub_surface_reference_factory.cc
new file mode 100644
index 00000000000..e5d2ce50a92
--- /dev/null
+++ b/chromium/components/viz/common/surfaces/stub_surface_reference_factory.cc
@@ -0,0 +1,17 @@
+// Copyright 2017 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 "components/viz/common/surfaces/stub_surface_reference_factory.h"
+
+#include "base/callback.h"
+
+namespace viz {
+
+base::Closure StubSurfaceReferenceFactory::CreateReference(
+ SurfaceReferenceOwner* owner,
+ const SurfaceId& surface_id) const {
+ return base::Closure();
+}
+
+} // namespace viz
diff --git a/chromium/components/viz/common/surfaces/stub_surface_reference_factory.h b/chromium/components/viz/common/surfaces/stub_surface_reference_factory.h
new file mode 100644
index 00000000000..156809c777c
--- /dev/null
+++ b/chromium/components/viz/common/surfaces/stub_surface_reference_factory.h
@@ -0,0 +1,34 @@
+// Copyright 2017 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 COMPONENTS_VIZ_COMMON_SURFACES_STUB_SURFACE_REFERENCE_FACTORY_H_
+#define COMPONENTS_VIZ_COMMON_SURFACES_STUB_SURFACE_REFERENCE_FACTORY_H_
+
+#include "base/compiler_specific.h"
+#include "components/viz/common/surfaces/surface_reference_factory.h"
+#include "components/viz/common/viz_common_export.h"
+
+namespace viz {
+
+// A stub implementation that creates a closure which does nothing.
+// TODO(kylechar): Delete this class and all usage of
+// SurfaceReferenceFactory when surface references are enabled by default.
+class VIZ_COMMON_EXPORT StubSurfaceReferenceFactory
+ : public SurfaceReferenceFactory {
+ public:
+ StubSurfaceReferenceFactory() = default;
+
+ // SurfaceReferenceFactory:
+ base::Closure CreateReference(SurfaceReferenceOwner* owner,
+ const SurfaceId& surface_id) const override;
+
+ protected:
+ ~StubSurfaceReferenceFactory() override = default;
+
+ DISALLOW_COPY_AND_ASSIGN(StubSurfaceReferenceFactory);
+};
+
+} // namespace viz
+
+#endif // COMPONENTS_VIZ_COMMON_SURFACES_STUB_SURFACE_REFERENCE_FACTORY_H_
diff --git a/chromium/components/viz/common/surfaces/surface_id.h b/chromium/components/viz/common/surfaces/surface_id.h
index b008abaf288..dda288c13f2 100644
--- a/chromium/components/viz/common/surfaces/surface_id.h
+++ b/chromium/components/viz/common/surfaces/surface_id.h
@@ -17,13 +17,11 @@
#include "components/viz/common/viz_common_export.h"
#include "mojo/public/cpp/bindings/struct_traits.h"
-namespace cc {
+namespace viz {
+
namespace mojom {
class SurfaceIdDataView;
}
-} // namespace cc
-
-namespace viz {
class VIZ_COMMON_EXPORT SurfaceId {
public:
@@ -70,7 +68,7 @@ class VIZ_COMMON_EXPORT SurfaceId {
}
private:
- friend struct mojo::StructTraits<cc::mojom::SurfaceIdDataView, SurfaceId>;
+ friend struct mojo::StructTraits<mojom::SurfaceIdDataView, SurfaceId>;
FrameSinkId frame_sink_id_;
LocalSurfaceId local_surface_id_;
diff --git a/chromium/components/viz/common/surfaces/surface_info.h b/chromium/components/viz/common/surfaces/surface_info.h
index 1e21fda57d8..b40092bcb4c 100644
--- a/chromium/components/viz/common/surfaces/surface_info.h
+++ b/chromium/components/viz/common/surfaces/surface_info.h
@@ -13,13 +13,11 @@ template <class T>
struct ParamTraits;
} // namespace IPC
-namespace cc {
+namespace viz {
+
namespace mojom {
class SurfaceInfoDataView;
-}
-} // namespace cc
-
-namespace viz {
+} // namespace mojom
// This class contains information about the surface that is being embedded.
class SurfaceInfo {
@@ -50,7 +48,7 @@ class SurfaceInfo {
const gfx::Size& size_in_pixels() const { return size_in_pixels_; }
private:
- friend struct mojo::StructTraits<cc::mojom::SurfaceInfoDataView, SurfaceInfo>;
+ friend struct mojo::StructTraits<mojom::SurfaceInfoDataView, SurfaceInfo>;
friend struct IPC::ParamTraits<SurfaceInfo>;
SurfaceId id_;
diff --git a/chromium/components/viz/common/switches.cc b/chromium/components/viz/common/switches.cc
new file mode 100644
index 00000000000..ee13e20ad7f
--- /dev/null
+++ b/chromium/components/viz/common/switches.cc
@@ -0,0 +1,18 @@
+// Copyright 2017 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 "components/viz/common/switches.h"
+
+namespace switches {
+
+// Disable surface lifetime management using surface references. This enables
+// adding surface sequences and disables adding temporary references.
+const char kDisableSurfaceReferences[] = "disable-surface-references";
+
+// Enables multi-client Surface synchronization. In practice, this indicates
+// that LayerTreeHost expects to be given a valid viz::LocalSurfaceId provided
+// by the parent compositor.
+const char kEnableSurfaceSynchronization[] = "enable-surface-synchronization";
+
+} // namespace switches
diff --git a/chromium/components/viz/common/switches.h b/chromium/components/viz/common/switches.h
new file mode 100644
index 00000000000..69bd3077588
--- /dev/null
+++ b/chromium/components/viz/common/switches.h
@@ -0,0 +1,18 @@
+// Copyright 2017 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 COMPONENTS_VIZ_COMMON_SWITCHES_H_
+#define COMPONENTS_VIZ_COMMON_SWITCHES_H_
+
+#include "components/viz/common/viz_common_export.h"
+
+namespace switches {
+
+// Keep list in alphabetical order.
+VIZ_COMMON_EXPORT extern const char kDisableSurfaceReferences[];
+VIZ_COMMON_EXPORT extern const char kEnableSurfaceSynchronization[];
+
+} // namespace switches
+
+#endif // COMPONENTS_VIZ_COMMON_SWITCHES_H_
diff --git a/chromium/components/viz/common/traced_value.cc b/chromium/components/viz/common/traced_value.cc
new file mode 100644
index 00000000000..b3a23c2f16d
--- /dev/null
+++ b/chromium/components/viz/common/traced_value.cc
@@ -0,0 +1,54 @@
+// Copyright (c) 2013 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 "components/viz/common/traced_value.h"
+
+#include "base/strings/stringprintf.h"
+#include "base/trace_event/trace_event_argument.h"
+
+namespace viz {
+
+void TracedValue::AppendIDRef(const void* id,
+ base::trace_event::TracedValue* state) {
+ state->BeginDictionary();
+ state->SetString("id_ref", base::StringPrintf("%p", id));
+ state->EndDictionary();
+}
+
+void TracedValue::SetIDRef(const void* id,
+ base::trace_event::TracedValue* state,
+ const char* name) {
+ state->BeginDictionary(name);
+ state->SetString("id_ref", base::StringPrintf("%p", id));
+ state->EndDictionary();
+}
+
+void TracedValue::MakeDictIntoImplicitSnapshot(
+ base::trace_event::TracedValue* dict,
+ const char* object_name,
+ const void* id) {
+ dict->SetString("id", base::StringPrintf("%s/%p", object_name, id));
+}
+
+void TracedValue::MakeDictIntoImplicitSnapshotWithCategory(
+ const char* category,
+ base::trace_event::TracedValue* dict,
+ const char* object_name,
+ const void* id) {
+ dict->SetString("cat", category);
+ MakeDictIntoImplicitSnapshot(dict, object_name, id);
+}
+
+void TracedValue::MakeDictIntoImplicitSnapshotWithCategory(
+ const char* category,
+ base::trace_event::TracedValue* dict,
+ const char* object_base_type_name,
+ const char* object_name,
+ const void* id) {
+ dict->SetString("cat", category);
+ dict->SetString("base_type", object_base_type_name);
+ MakeDictIntoImplicitSnapshot(dict, object_name, id);
+}
+
+} // namespace viz
diff --git a/chromium/components/viz/common/traced_value.h b/chromium/components/viz/common/traced_value.h
new file mode 100644
index 00000000000..2f2d144aa5d
--- /dev/null
+++ b/chromium/components/viz/common/traced_value.h
@@ -0,0 +1,43 @@
+// Copyright 2013 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 COMPONENTS_VIZ_COMMON_TRACED_VALUE_H_
+#define COMPONENTS_VIZ_COMMON_TRACED_VALUE_H_
+
+#include "components/viz/common/viz_common_export.h"
+
+namespace base {
+namespace trace_event {
+class TracedValue;
+}
+} // namespace base
+
+namespace viz {
+
+class VIZ_COMMON_EXPORT TracedValue {
+ public:
+ static void AppendIDRef(const void* id,
+ base::trace_event::TracedValue* array);
+ static void SetIDRef(const void* id,
+ base::trace_event::TracedValue* dict,
+ const char* name);
+ static void MakeDictIntoImplicitSnapshot(base::trace_event::TracedValue* dict,
+ const char* object_name,
+ const void* id);
+ static void MakeDictIntoImplicitSnapshotWithCategory(
+ const char* category,
+ base::trace_event::TracedValue* dict,
+ const char* object_name,
+ const void* id);
+ static void MakeDictIntoImplicitSnapshotWithCategory(
+ const char* category,
+ base::trace_event::TracedValue* dict,
+ const char* object_base_type_name,
+ const char* object_name,
+ const void* id);
+};
+
+} // namespace viz
+
+#endif // COMPONENTS_VIZ_COMMON_TRACED_VALUE_H_
diff --git a/chromium/components/viz/common/viz_resource_format_export.h b/chromium/components/viz/common/viz_resource_format_export.h
new file mode 100644
index 00000000000..549ac8c357f
--- /dev/null
+++ b/chromium/components/viz/common/viz_resource_format_export.h
@@ -0,0 +1,29 @@
+// Copyright 2017 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 COMPONENTS_VIZ_COMMON_VIZ_RESOURCE_FORMAT_EXPORT_H_
+#define COMPONENTS_VIZ_COMMON_VIZ_RESOURCE_FORMAT_EXPORT_H_
+
+#if defined(COMPONENT_BUILD)
+#if defined(WIN32)
+
+#if defined(VIZ_RESOURCE_FORMAT_IMPLEMENTATION)
+#define VIZ_RESOURCE_FORMAT_EXPORT __declspec(dllexport)
+#else
+#define VIZ_RESOURCE_FORMAT_EXPORT __declspec(dllimport)
+#endif // defined(VIZ_RESOURCE_FORMAT_IMPLEMENTATION)
+
+#else // defined(WIN32)
+#if defined(VIZ_RESOURCE_FORMAT_IMPLEMENTATION)
+#define VIZ_RESOURCE_FORMAT_EXPORT __attribute__((visibility("default")))
+#else
+#define VIZ_RESOURCE_FORMAT_EXPORT
+#endif
+#endif
+
+#else // defined(COMPONENT_BUILD)
+#define VIZ_RESOURCE_FORMAT_EXPORT
+#endif
+
+#endif // COMPONENTS_VIZ_COMMON_VIZ_RESOURCE_FORMAT_EXPORT_H_