提交 d6476a65 编写于 作者: A Adam Barth 提交者: GitHub

Port //flow to //lib/ftl (#2847)

This patch removes almost all //base dependency of //flow. The only dependency
left is on tracing.
上级 27a77e45
......@@ -25,6 +25,7 @@ Thumbs.db
/build/linux/bin/eu-strip
/buildtools/
/dart/
/lib/
/mojo/devtools/
/mojo/public/
/native_client/
......
......@@ -47,6 +47,7 @@ source_set("flow") {
deps = [
"//base",
"//lib/ftl",
"//mojo/services/gfx/composition/interfaces",
"//mojo/skia",
"//skia",
......
......@@ -8,7 +8,8 @@
namespace flow {
static sk_sp<SkShader> CreateCheckerboardShader(SkColor c1, SkColor c2,
static sk_sp<SkShader> CreateCheckerboardShader(SkColor c1,
SkColor c2,
int size) {
SkBitmap bm;
bm.allocN32Pixels(2 * size, 2 * size);
......
......@@ -4,16 +4,13 @@
#include "flow/compositor_context.h"
#include "base/logging.h"
#include "third_party/skia/include/core/SkCanvas.h"
namespace flow {
CompositorContext::CompositorContext() {
}
CompositorContext::CompositorContext() {}
CompositorContext::~CompositorContext() {
}
CompositorContext::~CompositorContext() {}
void CompositorContext::BeginFrame(ScopedFrame& frame,
bool enable_instrumentation) {
......@@ -32,7 +29,9 @@ void CompositorContext::EndFrame(ScopedFrame& frame,
}
CompositorContext::ScopedFrame CompositorContext::AcquireFrame(
GrContext* gr_context, SkCanvas& canvas, bool instrumentation_enabled) {
GrContext* gr_context,
SkCanvas& canvas,
bool instrumentation_enabled) {
return ScopedFrame(*this, gr_context, canvas, instrumentation_enabled);
}
......@@ -40,7 +39,9 @@ CompositorContext::ScopedFrame::ScopedFrame(CompositorContext& context,
GrContext* gr_context,
SkCanvas& canvas,
bool instrumentation_enabled)
: context_(context), gr_context_(gr_context), canvas_(&canvas),
: context_(context),
gr_context_(gr_context),
canvas_(&canvas),
instrumentation_enabled_(instrumentation_enabled) {
context_.BeginFrame(*this, instrumentation_enabled_);
}
......
......@@ -8,10 +8,9 @@
#include <memory>
#include <string>
#include "base/macros.h"
#include "base/logging.h"
#include "flow/instrumentation.h"
#include "flow/raster_cache.h"
#include "lib/ftl/macros.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkPictureRecorder.h"
......@@ -41,7 +40,7 @@ class CompositorContext {
friend class CompositorContext;
DISALLOW_COPY_AND_ASSIGN(ScopedFrame);
FTL_DISALLOW_COPY_AND_ASSIGN(ScopedFrame);
};
CompositorContext();
......@@ -68,7 +67,7 @@ class CompositorContext {
void BeginFrame(ScopedFrame& frame, bool enable_instrumentation);
void EndFrame(ScopedFrame& frame, bool enable_instrumentation);
DISALLOW_COPY_AND_ASSIGN(CompositorContext);
FTL_DISALLOW_COPY_AND_ASSIGN(CompositorContext);
};
} // namespace flow
......
......@@ -13,26 +13,26 @@ namespace flow {
static const size_t kMaxSamples = 120;
static const size_t kMaxFrameMarkers = 8;
Stopwatch::Stopwatch() : start_(base::TimeTicks::Now()), current_sample_(0) {
const base::TimeDelta delta;
Stopwatch::Stopwatch() : start_(ftl::TimePoint::Now()), current_sample_(0) {
const ftl::TimeDelta delta;
laps_.resize(kMaxSamples, delta);
}
void Stopwatch::Start() {
start_ = base::TimeTicks::Now();
start_ = ftl::TimePoint::Now();
current_sample_ = (current_sample_ + 1) % kMaxSamples;
}
void Stopwatch::Stop() {
laps_[current_sample_] = base::TimeTicks::Now() - start_;
laps_[current_sample_] = ftl::TimePoint::Now() - start_;
}
void Stopwatch::SetLapTime(const base::TimeDelta& delta) {
void Stopwatch::SetLapTime(const ftl::TimeDelta& delta) {
current_sample_ = (current_sample_ + 1) % kMaxSamples;
laps_[current_sample_] = delta;
}
const base::TimeDelta& Stopwatch::LastLap() const {
const ftl::TimeDelta& Stopwatch::LastLap() const {
return laps_[(current_sample_ - 1) % kMaxSamples];
}
......@@ -40,15 +40,16 @@ static inline constexpr double UnitFrameInterval(double frame_time_ms) {
return frame_time_ms * 60.0 * 1e-3;
}
static inline double UnitHeight(double frame_time_ms, double max_unit_interval) {
static inline double UnitHeight(double frame_time_ms,
double max_unit_interval) {
double unitHeight = UnitFrameInterval(frame_time_ms) / max_unit_interval;
if (unitHeight > 1.0)
unitHeight = 1.0;
return unitHeight;
}
base::TimeDelta Stopwatch::MaxDelta() const {
base::TimeDelta max_delta;
ftl::TimeDelta Stopwatch::MaxDelta() const {
ftl::TimeDelta max_delta;
for (size_t i = 0; i < kMaxSamples; i++) {
if (laps_[i] > max_delta)
max_delta = laps_[i];
......@@ -71,7 +72,8 @@ void Stopwatch::Visualize(SkCanvas& canvas, const SkRect& rect) const {
const SkScalar bottom = y + height;
const SkScalar right = x + width;
// Scale the graph to show frame times up to those that are 3 times the frame time.
// Scale the graph to show frame times up to those that are 3 times the frame
// time.
const double max_interval = kOneFrameMS * 3.0;
const double max_unit_interval = UnitFrameInterval(max_interval);
......@@ -82,20 +84,26 @@ void Stopwatch::Visualize(SkCanvas& canvas, const SkRect& rect) const {
const double sample_margin_unit_width = sample_unit_width / 6.0;
const double sample_margin_width = width * sample_margin_unit_width;
path.moveTo(x, bottom);
path.lineTo(x, y + height * (1.0 - UnitHeight(laps_[0].InMillisecondsF(),
path.lineTo(x, y +
height * (1.0 - UnitHeight(laps_[0].ToMillisecondsF(),
max_unit_interval)));
double unit_x;
double unit_next_x = 0.0;
for (size_t i = 0; i < kMaxSamples; i += 1) {
unit_x = unit_next_x;
unit_next_x = (static_cast<double>(i + 1) / kMaxSamples);
const double sample_y = y + height * (1.0 - UnitHeight(laps_[i].InMillisecondsF(),
max_unit_interval));
const double sample_y =
y +
height *
(1.0 - UnitHeight(laps_[i].ToMillisecondsF(), max_unit_interval));
path.lineTo(x + width * unit_x + sample_margin_width, sample_y);
path.lineTo(x + width * unit_next_x - sample_margin_width, sample_y);
}
path.lineTo(right, y + height * (1.0 - UnitHeight(laps_[kMaxSamples - 1].InMillisecondsF(),
max_unit_interval)));
path.lineTo(
right,
y +
height * (1.0 - UnitHeight(laps_[kMaxSamples - 1].ToMillisecondsF(),
max_unit_interval)));
path.lineTo(right, bottom);
path.close();
......@@ -104,7 +112,7 @@ void Stopwatch::Visualize(SkCanvas& canvas, const SkRect& rect) const {
canvas.drawPath(path, paint);
// Draw horizontal markers.
paint.setStrokeWidth(0); // hairline
paint.setStrokeWidth(0); // hairline
paint.setStyle(SkPaint::Style::kStroke_Style);
paint.setColor(0xCC000000);
......@@ -117,7 +125,8 @@ void Stopwatch::Visualize(SkCanvas& canvas, const SkRect& rect) const {
if (frame_marker_count > kMaxFrameMarkers)
frame_marker_count = 1;
for (size_t frame_index = 0; frame_index < frame_marker_count; frame_index++) {
for (size_t frame_index = 0; frame_index < frame_marker_count;
frame_index++) {
const double frame_height =
height * (1.0 - (UnitFrameInterval((frame_index + 1) * kOneFrameMS) /
max_unit_interval));
......@@ -129,16 +138,19 @@ void Stopwatch::Visualize(SkCanvas& canvas, const SkRect& rect) const {
// We paint it over the current frame, not after it, because when we
// paint this we don't yet have all the times for the current frame.
paint.setStyle(SkPaint::Style::kFill_Style);
if (UnitFrameInterval(LastLap().InMillisecondsF()) > 1.0) {
if (UnitFrameInterval(LastLap().ToMillisecondsF()) > 1.0) {
// budget exceeded
paint.setColor(SK_ColorRED);
} else {
// within budget
paint.setColor(SK_ColorGREEN);
}
double sample_x = x + width * (static_cast<double>(current_sample_) / kMaxSamples)
- sample_margin_width;
canvas.drawRectCoords(sample_x, y, sample_x + width * sample_unit_width + sample_margin_width * 2, bottom, paint);
double sample_x =
x + width * (static_cast<double>(current_sample_) / kMaxSamples) -
sample_margin_width;
canvas.drawRectCoords(sample_x, y, sample_x + width * sample_unit_width +
sample_margin_width * 2,
bottom, paint);
}
Stopwatch::~Stopwatch() = default;
......
......@@ -6,8 +6,10 @@
#define FLOW_INSTRUMENTATION_H_
#include <vector>
#include "base/macros.h"
#include "base/time/time.h"
#include "lib/ftl/macros.h"
#include "lib/ftl/time/time_delta.h"
#include "lib/ftl/time/time_point.h"
#include "third_party/skia/include/core/SkCanvas.h"
namespace flow {
......@@ -27,26 +29,26 @@ class Stopwatch {
private:
Stopwatch& stopwatch_;
DISALLOW_COPY_AND_ASSIGN(ScopedLap);
FTL_DISALLOW_COPY_AND_ASSIGN(ScopedLap);
};
explicit Stopwatch();
~Stopwatch();
const base::TimeDelta& LastLap() const;
base::TimeDelta CurrentLap() const { return base::TimeTicks::Now() - start_; }
base::TimeDelta MaxDelta() const;
const ftl::TimeDelta& LastLap() const;
ftl::TimeDelta CurrentLap() const { return ftl::TimePoint::Now() - start_; }
ftl::TimeDelta MaxDelta() const;
void Visualize(SkCanvas& canvas, const SkRect& rect) const;
void Start();
void Stop();
void SetLapTime(const base::TimeDelta& delta);
void SetLapTime(const ftl::TimeDelta& delta);
private:
base::TimeTicks start_;
std::vector<base::TimeDelta> laps_;
ftl::TimePoint start_;
std::vector<ftl::TimeDelta> laps_;
size_t current_sample_;
DISALLOW_COPY_AND_ASSIGN(Stopwatch);
FTL_DISALLOW_COPY_AND_ASSIGN(Stopwatch);
};
class Counter {
......@@ -60,7 +62,7 @@ class Counter {
private:
size_t count_;
DISALLOW_COPY_AND_ASSIGN(Counter);
FTL_DISALLOW_COPY_AND_ASSIGN(Counter);
};
} // namespace flow
......
......@@ -8,17 +8,15 @@
namespace flow {
BackdropFilterLayer::BackdropFilterLayer() {
}
BackdropFilterLayer::BackdropFilterLayer() {}
BackdropFilterLayer::~BackdropFilterLayer() {
}
BackdropFilterLayer::~BackdropFilterLayer() {}
void BackdropFilterLayer::Paint(PaintContext& context) {
TRACE_EVENT0("flutter", "BackdropFilterLayer::Paint");
SkAutoCanvasRestore save(&context.canvas, false);
context.canvas.saveLayer(SkCanvas::SaveLayerRec{
&paint_bounds(), nullptr, filter_.get(), 0});
context.canvas.saveLayer(
SkCanvas::SaveLayerRec{&paint_bounds(), nullptr, filter_.get(), 0});
PaintChildren(context);
}
......
......@@ -22,7 +22,7 @@ class BackdropFilterLayer : public ContainerLayer {
private:
sk_sp<SkImageFilter> filter_;
DISALLOW_COPY_AND_ASSIGN(BackdropFilterLayer);
FTL_DISALLOW_COPY_AND_ASSIGN(BackdropFilterLayer);
};
} // namespace flow
......
......@@ -11,11 +11,9 @@ namespace flow {
// TODO(abarth): We need to figure out how to allocate these ids sensibly.
static uint32_t next_id = 10;
ChildSceneLayer::ChildSceneLayer() : device_pixel_ratio_(1.0f) {
}
ChildSceneLayer::ChildSceneLayer() : device_pixel_ratio_(1.0f) {}
ChildSceneLayer::~ChildSceneLayer() {
}
ChildSceneLayer::~ChildSceneLayer() {}
void ChildSceneLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) {
transform_ = matrix;
......
......@@ -41,7 +41,7 @@ class ChildSceneLayer : public Layer {
mojo::gfx::composition::SceneTokenPtr scene_token_;
SkMatrix transform_;
DISALLOW_COPY_AND_ASSIGN(ChildSceneLayer);
FTL_DISALLOW_COPY_AND_ASSIGN(ChildSceneLayer);
};
} // namespace flow
......
......@@ -6,11 +6,9 @@
namespace flow {
ClipPathLayer::ClipPathLayer() {
}
ClipPathLayer::ClipPathLayer() {}
ClipPathLayer::~ClipPathLayer() {
}
ClipPathLayer::~ClipPathLayer() {}
void ClipPathLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) {
PrerollChildren(context, matrix);
......
......@@ -23,7 +23,7 @@ class ClipPathLayer : public ContainerLayer {
private:
SkPath clip_path_;
DISALLOW_COPY_AND_ASSIGN(ClipPathLayer);
FTL_DISALLOW_COPY_AND_ASSIGN(ClipPathLayer);
};
} // namespace flow
......
......@@ -6,11 +6,9 @@
namespace flow {
ClipRectLayer::ClipRectLayer() {
}
ClipRectLayer::ClipRectLayer() {}
ClipRectLayer::~ClipRectLayer() {
}
ClipRectLayer::~ClipRectLayer() {}
void ClipRectLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) {
PrerollChildren(context, matrix);
......
......@@ -23,7 +23,7 @@ class ClipRectLayer : public ContainerLayer {
private:
SkRect clip_rect_;
DISALLOW_COPY_AND_ASSIGN(ClipRectLayer);
FTL_DISALLOW_COPY_AND_ASSIGN(ClipRectLayer);
};
} // namespace flow
......
......@@ -6,11 +6,9 @@
namespace flow {
ClipRRectLayer::ClipRRectLayer() {
}
ClipRRectLayer::ClipRRectLayer() {}
ClipRRectLayer::~ClipRRectLayer() {
}
ClipRRectLayer::~ClipRRectLayer() {}
void ClipRRectLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) {
PrerollChildren(context, matrix);
......
......@@ -23,7 +23,7 @@ class ClipRRectLayer : public ContainerLayer {
private:
SkRRect clip_rrect_;
DISALLOW_COPY_AND_ASSIGN(ClipRRectLayer);
FTL_DISALLOW_COPY_AND_ASSIGN(ClipRRectLayer);
};
} // namespace flow
......
......@@ -6,11 +6,9 @@
namespace flow {
ColorFilterLayer::ColorFilterLayer() {
}
ColorFilterLayer::ColorFilterLayer() {}
ColorFilterLayer::~ColorFilterLayer() {
}
ColorFilterLayer::~ColorFilterLayer() {}
void ColorFilterLayer::Paint(PaintContext& context) {
TRACE_EVENT0("flutter", "ColorFilterLayer::Paint");
......
......@@ -27,7 +27,7 @@ class ColorFilterLayer : public ContainerLayer {
SkColor color_;
SkXfermode::Mode transfer_mode_;
DISALLOW_COPY_AND_ASSIGN(ColorFilterLayer);
FTL_DISALLOW_COPY_AND_ASSIGN(ColorFilterLayer);
};
} // namespace flow
......
......@@ -6,11 +6,9 @@
namespace flow {
ContainerLayer::ContainerLayer() {
}
ContainerLayer::ContainerLayer() {}
ContainerLayer::~ContainerLayer() {
}
ContainerLayer::~ContainerLayer() {}
void ContainerLayer::Add(std::unique_ptr<Layer> layer) {
layer->set_parent(this);
......
......@@ -30,7 +30,7 @@ class ContainerLayer : public Layer {
private:
std::vector<std::unique_ptr<Layer>> layers_;
DISALLOW_COPY_AND_ASSIGN(ContainerLayer);
FTL_DISALLOW_COPY_AND_ASSIGN(ContainerLayer);
};
} // namespace flow
......
......@@ -8,20 +8,13 @@
namespace flow {
Layer::Layer()
: parent_(nullptr)
, has_paint_bounds_(false)
, paint_bounds_() {
}
Layer::Layer() : parent_(nullptr), has_paint_bounds_(false), paint_bounds_() {}
Layer::~Layer() {
}
Layer::~Layer() {}
void Layer::Preroll(PrerollContext* context, const SkMatrix& matrix) {
}
void Layer::Preroll(PrerollContext* context, const SkMatrix& matrix) {}
void Layer::UpdateScene(mojo::gfx::composition::SceneUpdate* update,
mojo::gfx::composition::Node* container) {
}
mojo::gfx::composition::Node* container) {}
} // namespace flow
......@@ -8,11 +8,11 @@
#include <memory>
#include <vector>
#include "base/logging.h"
#include "base/macros.h"
#include "base/trace_event/trace_event.h"
#include "flow/instrumentation.h"
#include "flow/raster_cache.h"
#include "lib/ftl/logging.h"
#include "lib/ftl/macros.h"
#include "skia/ext/refptr.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkColor.h"
......@@ -67,7 +67,7 @@ class Layer {
bool has_paint_bounds() const { return has_paint_bounds_; }
const SkRect& paint_bounds() const {
DCHECK(has_paint_bounds_);
FTL_DCHECK(has_paint_bounds_);
return paint_bounds_;
}
......@@ -78,10 +78,10 @@ class Layer {
private:
ContainerLayer* parent_;
bool has_paint_bounds_; // if false, paint_bounds_ is not valid
bool has_paint_bounds_; // if false, paint_bounds_ is not valid
SkRect paint_bounds_;
DISALLOW_COPY_AND_ASSIGN(Layer);
FTL_DISALLOW_COPY_AND_ASSIGN(Layer);
};
} // namespace flow
......
......@@ -9,28 +9,23 @@
namespace flow {
LayerTree::LayerTree() : scene_version_(0), rasterizer_tracing_threshold_(0) {
}
LayerTree::LayerTree() : scene_version_(0), rasterizer_tracing_threshold_(0) {}
LayerTree::~LayerTree() {
}
LayerTree::~LayerTree() {}
void LayerTree::Raster(CompositorContext::ScopedFrame& frame) {
{
TRACE_EVENT0("flutter", "LayerTree::Preroll");
Layer::PrerollContext context = {
frame.context().raster_cache(),
frame.gr_context(),
SkRect::MakeEmpty(),
frame.context().raster_cache(), frame.gr_context(), SkRect::MakeEmpty(),
};
root_layer_->Preroll(&context, SkMatrix());
}
{
Layer::PaintContext context = {
frame.canvas(),
frame.context().frame_time(),
frame.context().engine_time(),
frame.canvas(), frame.context().frame_time(),
frame.context().engine_time(),
};
TRACE_EVENT0("flutter", "LayerTree::Paint");
root_layer_->Paint(context);
......
......@@ -6,12 +6,13 @@
#define FLOW_LAYERS_LAYER_TREE_H_
#include <stdint.h>
#include <memory>
#include "base/macros.h"
#include "base/time/time.h"
#include "flow/compositor_context.h"
#include "flow/layers/layer.h"
#include "lib/ftl/macros.h"
#include "lib/ftl/time/time_delta.h"
#include "third_party/skia/include/core/SkSize.h"
namespace flow {
......@@ -44,13 +45,11 @@ class LayerTree {
scene_version_ = scene_version;
}
void set_construction_time(const base::TimeDelta& delta) {
void set_construction_time(const ftl::TimeDelta& delta) {
construction_time_ = delta;
}
const base::TimeDelta& construction_time() const {
return construction_time_;
}
const ftl::TimeDelta& construction_time() const { return construction_time_; }
// The number of frame intervals missed after which the compositor must
// trace the rasterized picture to a trace file. Specify 0 to disable all
......@@ -68,10 +67,10 @@ class LayerTree {
uint32_t scene_version_;
std::unique_ptr<Layer> root_layer_;
base::TimeDelta construction_time_;
ftl::TimeDelta construction_time_;
uint32_t rasterizer_tracing_threshold_;
DISALLOW_COPY_AND_ASSIGN(LayerTree);
FTL_DISALLOW_COPY_AND_ASSIGN(LayerTree);
};
} // namespace flow
......
......@@ -6,11 +6,9 @@
namespace flow {
OpacityLayer::OpacityLayer() {
}
OpacityLayer::OpacityLayer() {}
OpacityLayer::~OpacityLayer() {
}
OpacityLayer::~OpacityLayer() {}
void OpacityLayer::Paint(PaintContext& context) {
TRACE_EVENT0("flutter", "OpacityLayer::Paint");
......
......@@ -22,7 +22,7 @@ class OpacityLayer : public ContainerLayer {
private:
int alpha_;
DISALLOW_COPY_AND_ASSIGN(OpacityLayer);
FTL_DISALLOW_COPY_AND_ASSIGN(OpacityLayer);
};
} // namespace flow
......
......@@ -31,8 +31,8 @@ void VisualizeStopWatch(SkCanvas& canvas,
bool show_graph,
bool show_labels,
const std::string& label_prefix) {
const int label_x = 8; // distance from x
const int label_y = -10; // distance from y+height
const int label_x = 8; // distance from x
const int label_y = -10; // distance from y+height
if (show_graph) {
SkRect visualization_rect = SkRect::MakeXYWH(x, y, width, height);
......@@ -40,10 +40,10 @@ void VisualizeStopWatch(SkCanvas& canvas,
}
if (show_labels) {
double ms_per_frame = stopwatch.MaxDelta().InMillisecondsF();
double ms_per_frame = stopwatch.MaxDelta().ToMillisecondsF();
double fps;
if (ms_per_frame < kOneFrameMS) {
fps = 1e3 / kOneFrameMS;
fps = 1e3 / kOneFrameMS;
} else {
fps = 1e3 / ms_per_frame;
}
......@@ -51,8 +51,8 @@ void VisualizeStopWatch(SkCanvas& canvas,
std::stringstream stream;
stream.setf(std::ios::fixed | std::ios::showpoint);
stream << std::setprecision(1);
stream << label_prefix << " " << fps << " fps "
<< ms_per_frame << "ms/frame";
stream << label_prefix << " " << fps << " fps " << ms_per_frame
<< "ms/frame";
DrawStatisticsText(canvas, stream.str(), x + label_x, y + height + label_y);
}
}
......@@ -60,9 +60,7 @@ void VisualizeStopWatch(SkCanvas& canvas,
} // namespace
PerformanceOverlayLayer::PerformanceOverlayLayer(uint64_t options)
: options_(options) {
}
: options_(options) {}
void PerformanceOverlayLayer::Paint(PaintContext& context) {
if (!options_)
......@@ -75,17 +73,13 @@ void PerformanceOverlayLayer::Paint(PaintContext& context) {
SkScalar height = paint_bounds().height() / 2;
SkAutoCanvasRestore save(&context.canvas, true);
VisualizeStopWatch(context.canvas, context.frame_time,
x, y, width, height,
VisualizeStopWatch(context.canvas, context.frame_time, x, y, width, height,
options_ & kVisualizeRasterizerStatistics,
options_ & kDisplayRasterizerStatistics,
"Rasterizer");
options_ & kDisplayRasterizerStatistics, "Rasterizer");
VisualizeStopWatch(context.canvas, context.engine_time,
x, y + height, width, height,
options_ & kVisualizeEngineStatistics,
options_ & kDisplayEngineStatistics,
"Engine");
VisualizeStopWatch(context.canvas, context.engine_time, x, y + height, width,
height, options_ & kVisualizeEngineStatistics,
options_ & kDisplayEngineStatistics, "Engine");
}
} // namespace flow
......@@ -5,8 +5,8 @@
#ifndef FLOW_LAYERS_PERFORMANCE_OVERLAY_LAYER_H_
#define FLOW_LAYERS_PERFORMANCE_OVERLAY_LAYER_H_
#include "base/macros.h"
#include "flow/layers/layer.h"
#include "lib/ftl/macros.h"
namespace flow {
......@@ -24,7 +24,7 @@ class PerformanceOverlayLayer : public Layer {
private:
int options_;
DISALLOW_COPY_AND_ASSIGN(PerformanceOverlayLayer);
FTL_DISALLOW_COPY_AND_ASSIGN(PerformanceOverlayLayer);
};
} // namespace flow
......
......@@ -4,9 +4,9 @@
#include "flow/layers/picture_layer.h"
#include "base/logging.h"
#include "flow/checkerboard.h"
#include "flow/raster_cache.h"
#include "lib/ftl/logging.h"
namespace flow {
......@@ -25,7 +25,7 @@ void PictureLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) {
}
void PictureLayer::Paint(PaintContext& context) {
DCHECK(picture_);
FTL_DCHECK(picture_);
if (image_) {
TRACE_EVENT1("flutter", "PictureLayer::Paint", "image", "prerolled");
......
......@@ -34,7 +34,7 @@ class PictureLayer : public Layer {
// If we rasterized the picture separately, image_ holds the pixels.
sk_sp<SkImage> image_;
DISALLOW_COPY_AND_ASSIGN(PictureLayer);
FTL_DISALLOW_COPY_AND_ASSIGN(PictureLayer);
};
} // namespace flow
......
......@@ -6,11 +6,9 @@
namespace flow {
ShaderMaskLayer::ShaderMaskLayer() {
}
ShaderMaskLayer::ShaderMaskLayer() {}
ShaderMaskLayer::~ShaderMaskLayer() {
}
ShaderMaskLayer::~ShaderMaskLayer() {}
void ShaderMaskLayer::Paint(PaintContext& context) {
TRACE_EVENT0("flutter", "ShaderMaskLayer::Paint");
......
......@@ -18,9 +18,7 @@ class ShaderMaskLayer : public ContainerLayer {
void set_shader(sk_sp<SkShader> shader) { shader_ = shader; }
void set_mask_rect(const SkRect& mask_rect) {
mask_rect_ = mask_rect;
}
void set_mask_rect(const SkRect& mask_rect) { mask_rect_ = mask_rect; }
void set_transfer_mode(SkXfermode::Mode transfer_mode) {
transfer_mode_ = transfer_mode;
......@@ -34,7 +32,7 @@ class ShaderMaskLayer : public ContainerLayer {
SkRect mask_rect_;
SkXfermode::Mode transfer_mode_;
DISALLOW_COPY_AND_ASSIGN(ShaderMaskLayer);
FTL_DISALLOW_COPY_AND_ASSIGN(ShaderMaskLayer);
};
} // namespace flow
......
......@@ -6,11 +6,9 @@
namespace flow {
TransformLayer::TransformLayer() {
}
TransformLayer::TransformLayer() {}
TransformLayer::~TransformLayer() {
}
TransformLayer::~TransformLayer() {}
void TransformLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) {
SkMatrix childMatrix;
......
......@@ -22,7 +22,7 @@ class TransformLayer : public ContainerLayer {
private:
SkMatrix transform_;
DISALLOW_COPY_AND_ASSIGN(TransformLayer);
FTL_DISALLOW_COPY_AND_ASSIGN(TransformLayer);
};
} // namespace flow
......
......@@ -5,7 +5,7 @@
#ifndef FLOW_OPEN_GL_H_
#define FLOW_OPEN_GL_H_
#include "build/build_config.h"
#include "lib/ftl/build_config.h"
#if OS_IOS
......
......@@ -4,8 +4,8 @@
#include "flow/raster_cache.h"
#include "base/logging.h"
#include "base/trace_event/trace_event.h"
#include "lib/ftl/logging.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkImage.h"
#include "third_party/skia/include/core/SkPicture.h"
......
......@@ -8,11 +8,11 @@
#include <memory>
#include <unordered_map>
#include "base/macros.h"
#include "flow/instrumentation.h"
#include "lib/ftl/macros.h"
#include "skia/ext/refptr.h"
#include "third_party/skia/include/core/SkSize.h"
#include "third_party/skia/include/core/SkImage.h"
#include "flow/instrumentation.h"
#include "third_party/skia/include/core/SkSize.h"
namespace flow {
......@@ -44,7 +44,7 @@ class RasterCache {
using Cache = std::unordered_map<uint32_t, Entry>;
Cache cache_;
DISALLOW_COPY_AND_ASSIGN(RasterCache);
FTL_DISALLOW_COPY_AND_ASSIGN(RasterCache);
};
} // namespace flow
......
......@@ -5,7 +5,6 @@
#ifndef FLOW_TEXTURE_IMAGE_H_
#define FLOW_TEXTURE_IMAGE_H_
#include "base/macros.h"
#include "third_party/skia/include/core/SkImage.h"
namespace flow {
......
......@@ -13,6 +13,7 @@ source_set("libraries") {
"//flow",
"//flutter/lib/ui",
"//flutter/tonic",
"//lib/ftl",
"//mojo/application",
"//mojo/data_pipe_utils",
"//mojo/public/c/system",
......
......@@ -27,22 +27,17 @@ void Render(Dart_NativeArguments args) {
UIDartState::Current()->window()->client()->Render(scene);
}
void FlushRealTimeEvents(Dart_NativeArguments args) {
UIDartState::Current()->window()->client()->FlushRealTimeEvents();
}
} // namespace
WindowClient::~WindowClient() {
}
WindowClient::~WindowClient() {}
Window::Window(WindowClient* client)
: client_(client) {
}
Window::Window(WindowClient* client) : client_(client) {}
Window::~Window() {
}
Window::~Window() {}
void Window::DidCreateIsolate() {
library_.Set(DartState::Current(), Dart_LookupLibrary(ToDart("dart:ui")));
......@@ -54,15 +49,17 @@ void Window::UpdateWindowMetrics(const sky::ViewportMetricsPtr& metrics) {
return;
DartState::Scope scope(dart_state);
double device_pixel_ratio = metrics->device_pixel_ratio;
DartInvokeField(library_.value(), "_updateWindowMetrics", {
ToDart(device_pixel_ratio),
ToDart(metrics->physical_width / device_pixel_ratio),
ToDart(metrics->physical_height / device_pixel_ratio),
ToDart(metrics->physical_padding_top / device_pixel_ratio),
ToDart(metrics->physical_padding_right / device_pixel_ratio),
ToDart(metrics->physical_padding_bottom / device_pixel_ratio),
ToDart(metrics->physical_padding_left / device_pixel_ratio),
});
DartInvokeField(
library_.value(), "_updateWindowMetrics",
{
ToDart(device_pixel_ratio),
ToDart(metrics->physical_width / device_pixel_ratio),
ToDart(metrics->physical_height / device_pixel_ratio),
ToDart(metrics->physical_padding_top / device_pixel_ratio),
ToDart(metrics->physical_padding_right / device_pixel_ratio),
ToDart(metrics->physical_padding_bottom / device_pixel_ratio),
ToDart(metrics->physical_padding_left / device_pixel_ratio),
});
}
void Window::UpdateLocale(const std::string& language_code,
......@@ -72,10 +69,11 @@ void Window::UpdateLocale(const std::string& language_code,
return;
DartState::Scope scope(dart_state);
DartInvokeField(library_.value(), "_updateLocale", {
StdStringToDart(language_code),
StdStringToDart(country_code),
});
DartInvokeField(
library_.value(), "_updateLocale",
{
StdStringToDart(language_code), StdStringToDart(country_code),
});
}
void Window::PushRoute(const std::string& route) {
......@@ -85,8 +83,8 @@ void Window::PushRoute(const std::string& route) {
DartState::Scope scope(dart_state);
DartInvokeField(library_.value(), "_pushRoute", {
StdStringToDart(route),
});
StdStringToDart(route),
});
}
void Window::PopRoute() {
......@@ -104,8 +102,8 @@ void Window::DispatchPointerPacket(const pointer::PointerPacketPtr& packet) {
return;
DartState::Scope scope(dart_state);
Dart_Handle data_handle = Dart_NewTypedData(Dart_TypedData_kByteData,
packet->GetSerializedSize());
Dart_Handle data_handle =
Dart_NewTypedData(Dart_TypedData_kByteData, packet->GetSerializedSize());
if (Dart_IsError(data_handle))
return;
......@@ -122,17 +120,18 @@ void Window::DispatchPointerPacket(const pointer::PointerPacketPtr& packet) {
DartInvokeField(library_.value(), "_dispatchPointerPacket", {data_handle});
}
void Window::BeginFrame(base::TimeTicks frameTime) {
void Window::BeginFrame(ftl::TimePoint frameTime) {
DartState* dart_state = library_.dart_state().get();
if (!dart_state)
return;
DartState::Scope scope(dart_state);
int64_t microseconds = (frameTime - base::TimeTicks()).InMicroseconds();
int64_t microseconds = (frameTime - ftl::TimePoint()).ToMicroseconds();
DartInvokeField(library_.value(), "_beginFrame", {
Dart_NewInteger(microseconds),
});
DartInvokeField(library_.value(), "_beginFrame",
{
Dart_NewInteger(microseconds),
});
}
void Window::OnAppLifecycleStateChanged(sky::AppLifecycleState state) {
......@@ -141,16 +140,15 @@ void Window::OnAppLifecycleStateChanged(sky::AppLifecycleState state) {
return;
DartState::Scope scope(dart_state);
DartInvokeField(library_.value(), "_onAppLifecycleStateChanged", {
ToDart(static_cast<int>(state))
});
DartInvokeField(library_.value(), "_onAppLifecycleStateChanged",
{ToDart(static_cast<int>(state))});
}
void Window::RegisterNatives(DartLibraryNatives* natives) {
natives->Register({
{ "Window_scheduleFrame", ScheduleFrame, 1, true },
{ "Window_render", Render, 2, true },
{ "Scheduler_FlushRealTimeEvents", FlushRealTimeEvents, 1, true},
{"Window_scheduleFrame", ScheduleFrame, 1, true},
{"Window_render", Render, 2, true},
{"Scheduler_FlushRealTimeEvents", FlushRealTimeEvents, 1, true},
});
}
......
......@@ -5,8 +5,8 @@
#ifndef SKY_ENGINE_CORE_WINDOW_WINDOW_H_
#define SKY_ENGINE_CORE_WINDOW_WINDOW_H_
#include "base/time/time.h"
#include "flutter/tonic/dart_persistent_value.h"
#include "lib/ftl/time/time_point.h"
#include "sky/engine/wtf/text/WTFString.h"
#include "sky/services/engine/sky_engine.mojom.h"
#include "sky/services/pointer/pointer.mojom.h"
......@@ -37,7 +37,7 @@ class Window {
void UpdateLocale(const std::string& language_code,
const std::string& country_code);
void DispatchPointerPacket(const pointer::PointerPacketPtr& packet);
void BeginFrame(base::TimeTicks frameTime);
void BeginFrame(ftl::TimePoint frameTime);
void PushRoute(const std::string& route);
void PopRoute();
......
......@@ -7,6 +7,7 @@ source_set("sky") {
"//base",
"//flow",
"//flutter/lib/ui",
"//lib/ftl/",
"//mojo/public/cpp/system",
"//mojo/services/network/interfaces",
"//skia",
......
......@@ -21,12 +21,9 @@ std::unique_ptr<SkyView> SkyView::Create(SkyViewClient* client) {
}
SkyView::SkyView(SkyViewClient* client)
: client_(client),
weak_factory_(this) {
}
: client_(client), weak_factory_(this) {}
SkyView::~SkyView() {
}
SkyView::~SkyView() {}
void SkyView::SetViewportMetrics(const sky::ViewportMetricsPtr& metrics) {
if (metrics) {
......@@ -38,7 +35,7 @@ void SkyView::SetViewportMetrics(const sky::ViewportMetricsPtr& metrics) {
}
void SkyView::SetLocale(const std::string& language_code,
const std::string& country_code) {
const std::string& country_code) {
if (language_code_ == language_code && country_code_ == country_code)
return;
......@@ -85,7 +82,7 @@ void SkyView::RunFromSnapshot(mojo::ScopedDataPipeConsumerHandle snapshot) {
dart_controller_->RunFromSnapshot(snapshot.Pass());
}
void SkyView::BeginFrame(base::TimeTicks frame_time) {
void SkyView::BeginFrame(ftl::TimePoint frame_time) {
GetWindow()->BeginFrame(frame_time);
}
......@@ -118,4 +115,4 @@ void SkyView::OnAppLifecycleStateChanged(sky::AppLifecycleState state) {
GetWindow()->OnAppLifecycleStateChanged(state);
}
} // namespace blink
} // namespace blink
......@@ -39,11 +39,11 @@ class SkyView : public WindowClient, public IsolateClient {
void SetViewportMetrics(const sky::ViewportMetricsPtr& metrics);
void SetLocale(const std::string& language_code,
const std::string& country_code);
const std::string& country_code);
void PushRoute(const std::string& route);
void PopRoute();
void BeginFrame(base::TimeTicks frame_time);
void BeginFrame(ftl::TimePoint frame_time);
void CreateView(const std::string& script_uri);
......@@ -78,6 +78,6 @@ class SkyView : public WindowClient, public IsolateClient {
DISALLOW_COPY_AND_ASSIGN(SkyView);
};
} // namespace blink
} // namespace blink
#endif // SKY_ENGINE_PUBLIC_SKY_SKY_VIEW_H_
......@@ -53,6 +53,7 @@ source_set("common") {
"//dart/runtime:libdart",
"//flow",
"//flutter/tonic",
"//lib/ftl",
"//mojo/common",
"//mojo/data_pipe_utils",
"//mojo/message_pump",
......
......@@ -133,7 +133,7 @@ void RasterizerDirect::Draw(uint64_t layer_tree_ptr,
bool frameExceededThreshold = false;
uint32_t thresholdInterval = layer_tree->rasterizer_tracing_threshold();
if (thresholdInterval != 0 &&
compositor_context_.frame_time().LastLap().InMillisecondsF() >
compositor_context_.frame_time().LastLap().ToMillisecondsF() >
thresholdInterval * kOneFrameDuration) {
// While rendering the last frame, if we exceeded the tracing threshold
// specified in the layer tree, we force a trace to disk.
......
......@@ -15,7 +15,8 @@ namespace shell {
const int kPipelineDepth = 3;
Animator::Animator(const Engine::Config& config,
rasterizer::RasterizerPtr rasterizer, Engine* engine)
rasterizer::RasterizerPtr rasterizer,
Engine* engine)
: config_(config),
rasterizer_(rasterizer.Pass()),
engine_(engine),
......@@ -24,11 +25,9 @@ Animator::Animator(const Engine::Config& config,
engine_requested_frame_(false),
paused_(false),
is_ready_to_draw_(false),
weak_factory_(this) {
}
weak_factory_(this) {}
Animator::~Animator() {
}
Animator::~Animator() {}
void Animator::RequestFrame() {
if (engine_requested_frame_)
......@@ -40,7 +39,9 @@ void Animator::RequestFrame() {
outstanding_requests_++;
TRACE_COUNTER1("flutter", "outstanding_requests_", outstanding_requests_);
if (outstanding_requests_ >= kPipelineDepth) {
TRACE_EVENT_INSTANT1("flutter", "Frame request deferred", TRACE_EVENT_SCOPE_THREAD, "outstanding_requests_", outstanding_requests_);
TRACE_EVENT_INSTANT1("flutter", "Frame request deferred",
TRACE_EVENT_SCOPE_THREAD, "outstanding_requests_",
outstanding_requests_);
did_defer_frame_request_ = true;
return;
}
......@@ -87,9 +88,11 @@ void Animator::BeginFrame(int64_t time_stamp) {
return;
}
begin_time_ = base::TimeTicks::Now();
base::TimeTicks frame_time = time_stamp ?
base::TimeTicks::FromInternalValue(time_stamp) : begin_time_;
begin_time_ = ftl::TimePoint::Now();
ftl::TimePoint frame_time =
time_stamp
? ftl::TimePoint() + ftl::TimeDelta::FromMicroseconds(time_stamp)
: begin_time_;
is_ready_to_draw_ = true;
engine_->BeginFrame(frame_time);
......@@ -105,13 +108,14 @@ void Animator::BeginFrame(int64_t time_stamp) {
void Animator::Render(std::unique_ptr<flow::LayerTree> layer_tree) {
if (!is_ready_to_draw_)
return; // Only draw once per frame.
return; // Only draw once per frame.
is_ready_to_draw_ = false;
layer_tree->set_construction_time(base::TimeTicks::Now() - begin_time_);
layer_tree->set_construction_time(ftl::TimePoint::Now() - begin_time_);
// TODO(abarth): Doesn't this leak if OnFrameComplete never runs?
rasterizer_->Draw(reinterpret_cast<uint64_t>(layer_tree.release()),
rasterizer_->Draw(
reinterpret_cast<uint64_t>(layer_tree.release()),
base::Bind(&Animator::OnFrameComplete, weak_factory_.GetWeakPtr()));
}
......
......@@ -6,7 +6,7 @@
#define SKY_SHELL_UI_ANIMATOR_H_
#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
#include "lib/ftl/time/time_point.h"
#include "mojo/services/gfx/composition/interfaces/scheduling.mojom.h"
#include "mojo/services/vsync/interfaces/vsync.mojom.h"
#include "sky/shell/ui/engine.h"
......@@ -17,7 +17,8 @@ namespace shell {
class Animator {
public:
explicit Animator(const Engine::Config& config,
rasterizer::RasterizerPtr rasterizer, Engine* engine);
rasterizer::RasterizerPtr rasterizer,
Engine* engine);
~Animator();
void RequestFrame();
......@@ -32,11 +33,12 @@ class Animator {
void set_vsync_provider(vsync::VSyncProviderPtr vsync_provider);
void set_frame_scheduler(
mojo::InterfaceHandle<mojo::gfx::composition::FrameScheduler> frame_scheduler) {
frame_scheduler_ = mojo::gfx::composition::FrameSchedulerPtr::Create(frame_scheduler.Pass());
mojo::InterfaceHandle<mojo::gfx::composition::FrameScheduler>
frame_scheduler) {
frame_scheduler_ = mojo::gfx::composition::FrameSchedulerPtr::Create(
frame_scheduler.Pass());
}
private:
void Animate(mojo::gfx::composition::FrameInfoPtr frame_info);
void BeginFrame(int64_t time_stamp);
......@@ -53,7 +55,7 @@ class Animator {
bool engine_requested_frame_;
bool paused_;
bool is_ready_to_draw_;
base::TimeTicks begin_time_;
ftl::TimePoint begin_time_;
base::WeakPtrFactory<Animator> weak_factory_;
......
......@@ -63,7 +63,7 @@ void Engine::Init() {
blink::initialize(g_platform_impl);
}
void Engine::BeginFrame(base::TimeTicks frame_time) {
void Engine::BeginFrame(ftl::TimePoint frame_time) {
TRACE_EVENT0("flutter", "Engine::BeginFrame");
if (sky_view_)
sky_view_->BeginFrame(frame_time);
......@@ -91,8 +91,8 @@ void Engine::SetServices(ServicesDataPtr services) {
services_ = services.Pass();
if (services_->incoming_services) {
incoming_services_ = mojo::ServiceProviderPtr::Create(
services_->incoming_services.Pass());
incoming_services_ =
mojo::ServiceProviderPtr::Create(services_->incoming_services.Pass());
service_provider_impl_.set_fallback_service_provider(
incoming_services_.get());
}
......@@ -107,10 +107,12 @@ void Engine::SetServices(ServicesDataPtr services) {
// We bind and unbind our Shell here, since this is the only place we use
// it in this class.
auto shell = mojo::ShellPtr::Create(services_->shell.Pass());
mojo::ConnectToService(shell.get(), "mojo:vsync", mojo::GetProxy(&vsync_provider));
mojo::ConnectToService(shell.get(), "mojo:vsync",
mojo::GetProxy(&vsync_provider));
services_->shell = shell.Pass();
} else {
mojo::ConnectToService(incoming_services_.get(), mojo::GetProxy(&vsync_provider));
mojo::ConnectToService(incoming_services_.get(),
mojo::GetProxy(&vsync_provider));
}
animator_->Reset();
animator_->set_vsync_provider(vsync_provider.Pass());
......@@ -203,9 +205,8 @@ void Engine::RunFromFile(const mojo::String& main,
base::FilePath main_dir = base::FilePath(main_str).DirName();
packages_path = main_dir.Append(FILE_PATH_LITERAL(".packages"));
if (!base::PathExists(packages_path)) {
packages_path = main_dir
.Append(base::FilePath::kParentDirectory)
.Append(FILE_PATH_LITERAL(".packages"));
packages_path = main_dir.Append(base::FilePath::kParentDirectory)
.Append(FILE_PATH_LITERAL(".packages"));
if (!base::PathExists(packages_path))
packages_path = base::FilePath();
}
......@@ -223,10 +224,9 @@ void Engine::RunFromBundle(const mojo::String& script_uri,
ConfigureZipAssetBundle(path);
root_bundle_->GetAsStream(
blink::kSnapshotAssetKey,
base::Bind(&Engine::RunFromSnapshotStream, weak_factory_.GetWeakPtr(),
script_uri));
root_bundle_->GetAsStream(blink::kSnapshotAssetKey,
base::Bind(&Engine::RunFromSnapshotStream,
weak_factory_.GetWeakPtr(), script_uri));
}
void Engine::RunFromBundleAndSnapshot(const mojo::String& script_uri,
......@@ -240,10 +240,9 @@ void Engine::RunFromBundleAndSnapshot(const mojo::String& script_uri,
zip_asset_bundle_->AddOverlayFile(blink::kSnapshotAssetKey,
base::FilePath(snapshot_path_str));
root_bundle_->GetAsStream(
blink::kSnapshotAssetKey,
base::Bind(&Engine::RunFromSnapshotStream, weak_factory_.GetWeakPtr(),
script_uri));
root_bundle_->GetAsStream(blink::kSnapshotAssetKey,
base::Bind(&Engine::RunFromSnapshotStream,
weak_factory_.GetWeakPtr(), script_uri));
}
void Engine::PushRoute(const mojo::String& route) {
......@@ -280,9 +279,9 @@ void Engine::DidCreateMainIsolate(Dart_Isolate isolate) {
service_provider_bindings_.AddBinding(
&service_provider_impl_, mojo::GetProxy(&services_from_embedder));
blink::MojoServices::Create(
isolate, services_.Pass(), services_from_embedder.Pass(),
root_bundle_.Pass());
blink::MojoServices::Create(isolate, services_.Pass(),
services_from_embedder.Pass(),
root_bundle_.Pass());
if (zip_asset_bundle_) {
FlutterFontSelector::install(zip_asset_bundle_);
......@@ -293,13 +292,13 @@ void Engine::DidCreateSecondaryIsolate(Dart_Isolate isolate) {
mojo::ServiceProviderPtr services_from_embedder;
mojo::InterfaceRequest<mojo::ServiceProvider> request =
mojo::GetProxy(&services_from_embedder);
blink::Platform::current()->GetUITaskRunner()->PostTask(FROM_HERE,
base::Bind(&Engine::BindToServiceProvider,
weak_factory_.GetWeakPtr(),
blink::Platform::current()->GetUITaskRunner()->PostTask(
FROM_HERE,
base::Bind(&Engine::BindToServiceProvider, weak_factory_.GetWeakPtr(),
base::Passed(&request)));
blink::MojoServices::Create(
isolate, nullptr, services_from_embedder.Pass(), nullptr);
blink::MojoServices::Create(isolate, nullptr, services_from_embedder.Pass(),
nullptr);
}
void Engine::BindToServiceProvider(
......@@ -330,8 +329,8 @@ void Engine::Render(std::unique_ptr<flow::LayerTree> layer_tree) {
return;
if (viewport_metrics_) {
layer_tree->set_scene_version(viewport_metrics_->scene_version);
layer_tree->set_frame_size(SkISize::Make(viewport_metrics_->physical_width,
viewport_metrics_->physical_height));
layer_tree->set_frame_size(SkISize::Make(
viewport_metrics_->physical_width, viewport_metrics_->physical_height));
} else {
layer_tree->set_scene_version(0);
layer_tree->set_frame_size(SkISize::Make(0, 0));
......
......@@ -54,7 +54,7 @@ class Engine : public UIDelegate,
static void Init();
void BeginFrame(base::TimeTicks frame_time);
void BeginFrame(ftl::TimePoint frame_time);
private:
// UIDelegate implementation:
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册