Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(155)

Side by Side Diff: examples/ui/noodles/noodles_view.cc

Issue 1558813002: Add a multi-threaded rendering example. (Closed) Base URL: git@github.com:domokit/mojo.git@moz-15
Patch Set: Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « examples/ui/noodles/noodles_view.h ('k') | examples/ui/noodles/rasterizer.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "examples/ui/noodles/noodles_view.h"
6
7 #include <math.h>
8
9 #include <cstdlib>
10
11 #include "base/bind.h"
12 #include "base/logging.h"
13 #include "base/message_loop/message_loop.h"
14 #include "examples/ui/noodles/frame.h"
15 #include "examples/ui/noodles/rasterizer.h"
16 #include "third_party/skia/include/core/SkCanvas.h"
17 #include "third_party/skia/include/core/SkColor.h"
18 #include "third_party/skia/include/core/SkPath.h"
19 #include "third_party/skia/include/core/SkPicture.h"
20 #include "third_party/skia/include/core/SkPictureRecorder.h"
21
22 namespace examples {
23
24 static constexpr double kSecondsBetweenChanges = 10.0;
25
26 template <typename T>
27 static void Drop(scoped_ptr<T> ptr) {}
abarth 2016/01/10 03:25:56 There's a declaration in base for this. base::Ign
jeffbrown 2016/01/26 08:30:37 I thought so too but there's only IgnoreResult, no
28
29 static scoped_ptr<base::MessagePump> CreateMessagePumpMojo() {
30 return base::MessageLoop::CreateMessagePumpForType(
31 base::MessageLoop::TYPE_DEFAULT);
32 }
33
34 static void Lissajous(SkPath* path,
35 double ax,
36 double ay,
37 int wx,
38 int wy,
39 double p) {
40 uint32_t segments = ceil(fabs(ax) + fabs(ay)) / 2u + 1u;
41 for (uint32_t i = 0; i < segments; ++i) {
42 double t = M_PI * 2.0 * i / segments;
43 double x = ax * sin(t * wx);
44 double y = ay * sin(t * wy + p);
45 if (i == 0u)
46 path->moveTo(x, y);
47 else
48 path->lineTo(x, y);
49 }
50 path->close();
51 }
52
53 NoodlesView::NoodlesView(
54 mojo::ApplicationImpl* app_impl,
55 const mojo::ui::ViewProvider::CreateViewCallback& create_view_callback)
56 : BaseView(app_impl, "Noodles", create_view_callback),
57 choreographer_(scene(), this),
58 frame_queue_(std::make_shared<FrameQueue>()),
59 rasterizer_delegate_(
60 make_scoped_ptr(new RasterizerDelegate(frame_queue_))) {
61 base::Thread::Options options;
62 options.message_pump_factory = base::Bind(&CreateMessagePumpMojo);
63
64 rasterizer_thread_.reset(new base::Thread("noodles_rasterizer"));
65 rasterizer_thread_->StartWithOptions(options);
66 rasterizer_task_runner_ = rasterizer_thread_->message_loop()->task_runner();
67
68 rasterizer_task_runner_->PostTask(
69 FROM_HERE,
70 base::Bind(&RasterizerDelegate::CreateRasterizer,
71 base::Unretained(rasterizer_delegate_.get()),
72 base::Passed(app_impl->CreateApplicationConnector()),
73 base::Passed(TakeScene().PassInterface())));
74 }
75
76 NoodlesView::~NoodlesView() {
77 // Ensure destruction happens on the correct thread.
78 rasterizer_task_runner_->PostTask(
79 FROM_HERE, base::Bind(&Drop<RasterizerDelegate>,
80 base::Passed(&rasterizer_delegate_)));
81 }
82
83 void NoodlesView::OnLayout(mojo::ui::ViewLayoutParamsPtr layout_params,
84 mojo::Array<uint32_t> children_needing_layout,
85 const OnLayoutCallback& callback) {
86 size_.width = layout_params->constraints->max_width;
87 size_.height = layout_params->constraints->max_height;
88
89 // Submit the new layout information.
90 auto info = mojo::ui::ViewLayoutResult::New();
91 info->size = size_.Clone();
92 callback.Run(info.Pass());
93
94 choreographer_.ScheduleDraw();
95 }
96
97 void NoodlesView::OnDraw(const mojo::gfx::composition::FrameInfo& frame_info,
98 const base::TimeDelta& time_delta) {
99 // Update the animation.
100 alpha_ += time_delta.InSecondsF();
101
102 // Create and post a new frame to the renderer.
103 auto metadata = mojo::gfx::composition::SceneMetadata::New();
104 metadata->presentation_time = frame_info.presentation_time;
105 std::unique_ptr<Frame> frame(
106 new Frame(size_, CreatePicture(), metadata.Pass()));
107 if (frame_queue_->PutFrame(std::move(frame))) {
abarth 2016/01/10 03:25:56 This isn't great for perf, but I guess that's not
jeffbrown 2016/01/26 08:30:37 Yeah we should really have more backpressure here.
108 rasterizer_task_runner_->PostTask(
109 FROM_HERE, base::Bind(&RasterizerDelegate::PublishNextFrame,
110 base::Unretained(rasterizer_delegate_.get())));
111 }
112
113 // Loop!
114 choreographer_.ScheduleDraw();
abarth 2016/01/10 03:25:56 This should go at the top of the function.
jeffbrown 2016/01/26 08:30:37 Done. Note that Choreographer also contains an op
115 }
116
117 skia::RefPtr<SkPicture> NoodlesView::CreatePicture() {
118 constexpr int count = 4;
119 constexpr int padding = 1;
abarth 2016/01/10 03:25:56 Why not just const ?
jeffbrown 2016/01/26 08:30:37 Eh? constexpr is my new favorite keyword. I'll a
120
121 if (alpha_ > kSecondsBetweenChanges) {
122 alpha_ = 0.0;
123 wx_ = rand() % 9 + 1;
124 wy_ = rand() % 9 + 1;
125 }
126
127 SkPictureRecorder recorder;
128 SkCanvas* canvas = recorder.beginRecording(size_.width, size_.height);
129
130 double cx = size_.width * 0.5;
131 double cy = size_.height * 0.5;
132 canvas->translate(cx, cy);
133
134 double phase = alpha_;
135 for (int i = 0; i < count; i++, phase += 0.1) {
136 SkPaint paint;
137 SkScalar hsv[3] = {fmod(phase * 120, 360), 1, 1};
138 paint.setColor(SkHSVToColor(hsv));
139 paint.setStyle(SkPaint::kStroke_Style);
140 paint.setAntiAlias(true);
141
142 SkPath path;
143 Lissajous(&path, cx - padding, cy - padding, wx_, wy_, phase);
144 canvas->drawPath(path, paint);
145 }
146
147 canvas->flush();
abarth 2016/01/10 03:25:56 I don't think you need to flush here. endRecordin
jeffbrown 2016/01/26 08:30:37 Removed, here and in other places.
148 return skia::AdoptRef(recorder.endRecordingAsPicture());
149 }
150
151 NoodlesView::FrameQueue::FrameQueue() {}
152
153 NoodlesView::FrameQueue::~FrameQueue() {}
154
155 bool NoodlesView::FrameQueue::PutFrame(std::unique_ptr<Frame> frame) {
156 std::lock_guard<std::mutex> lock(mutex_);
157 bool was_empty = !next_frame_.get();
158 next_frame_.swap(frame);
159 return was_empty;
160 }
161
162 std::unique_ptr<Frame> NoodlesView::FrameQueue::TakeFrame() {
163 std::lock_guard<std::mutex> lock(mutex_);
164 return std::move(next_frame_);
165 }
166
167 NoodlesView::RasterizerDelegate::RasterizerDelegate(
168 const std::shared_ptr<FrameQueue>& frame_queue)
169 : frame_queue_(frame_queue) {
170 DCHECK(frame_queue_);
171 }
172
173 NoodlesView::RasterizerDelegate::~RasterizerDelegate() {}
174
175 void NoodlesView::RasterizerDelegate::CreateRasterizer(
176 mojo::InterfacePtrInfo<mojo::ApplicationConnector> connector_info,
177 mojo::InterfacePtrInfo<mojo::gfx::composition::Scene> scene_info) {
178 rasterizer_.reset(
179 new Rasterizer(mojo::MakeProxy(connector_info.Pass()).Pass(),
180 mojo::MakeProxy(scene_info.Pass()).Pass()));
181 }
182
183 void NoodlesView::RasterizerDelegate::PublishNextFrame() {
184 std::unique_ptr<Frame> frame(frame_queue_->TakeFrame());
185 DCHECK(frame);
186 rasterizer_->PublishFrame(std::move(frame));
187 }
188
189 } // namespace examples
OLDNEW
« no previous file with comments | « examples/ui/noodles/noodles_view.h ('k') | examples/ui/noodles/rasterizer.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698