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

Side by Side Diff: services/gfx/compositor/compositor_engine.cc

Issue 1552963002: Initial checkin of the new Mozart compositor. (Closed) Base URL: git@github.com:domokit/mojo.git@moz-11
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
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 "services/gfx/compositor/compositor_engine.h"
6
7 #include <algorithm>
8 #include <sstream>
9 #include <utility>
10
11 #include "base/bind.h"
12 #include "base/bind_helpers.h"
13 #include "base/time/time.h"
14 #include "mojo/services/gfx/composition/cpp/logging.h"
15 #include "services/gfx/compositor/backend/gpu_output.h"
16 #include "services/gfx/compositor/graph/snapshot.h"
17 #include "services/gfx/compositor/render/render_frame.h"
18 #include "services/gfx/compositor/renderer_impl.h"
19 #include "services/gfx/compositor/scene_impl.h"
20
21 namespace compositor {
22
23 // TODO(jeffbrown): Determine and document a more appropriate size limit
24 // for viewports somewhere. May be limited by the renderer output.
25 static const int32_t kMaxViewportWidth = 65536;
26 static const int32_t kMaxViewportHeight = 65536;
27
28 CompositorEngine::CompositorEngine() : weak_factory_(this) {}
29
30 CompositorEngine::~CompositorEngine() {}
31
32 mojo::gfx::composition::SceneTokenPtr CompositorEngine::CreateScene(
33 mojo::InterfaceRequest<mojo::gfx::composition::Scene> scene_request,
34 const mojo::String& label) {
35 auto scene_token = mojo::gfx::composition::SceneToken::New();
36 scene_token->value = next_scene_token_value_++;
37 CHECK(scene_token->value);
38 CHECK(!FindScene(scene_token->value));
39
40 // Create the state and bind implementation to it.
41 std::string sanitized_label =
42 label.get().substr(0, mojo::gfx::composition::kLabelMaxLength);
43 SceneState* scene_state = new SceneState(scene_token.Pass(), sanitized_label);
44 SceneImpl* scene_impl =
45 new SceneImpl(this, scene_state, scene_request.Pass());
46 scene_state->set_scene_impl(scene_impl);
47 base::Closure error_handler =
48 base::Bind(&CompositorEngine::OnSceneConnectionError,
49 base::Unretained(this), scene_state);
50 scene_impl->set_connection_error_handler(error_handler);
51
52 // Add to registry.
53 scenes_by_token_.insert({scene_state->scene_token()->value, scene_state});
54 DVLOG(1) << "CreateScene: scene=" << scene_state;
55 return scene_state->scene_token()->Clone();
56 }
57
58 void CompositorEngine::OnSceneConnectionError(SceneState* scene_state) {
59 DCHECK(IsSceneStateRegisteredDebug(scene_state));
60 DVLOG(1) << "OnSceneConnectionError: scene=" << scene_state;
61
62 DestroyScene(scene_state);
63 }
64
65 void CompositorEngine::DestroyScene(SceneState* scene_state) {
66 DCHECK(IsSceneStateRegisteredDebug(scene_state));
67 DVLOG(1) << "DestroyScene: scene=" << scene_state;
68
69 // Unlink from other scenes.
70 for (auto& pair : scenes_by_token_) {
71 SceneState* other_scene_state = pair.second;
72 other_scene_state->scene_def()->UnlinkReferencedScene(
73 scene_state->scene_def(),
74 base::Bind(&CompositorEngine::SendResourceUnavailable,
75 base::Unretained(this),
76 base::Unretained(other_scene_state)));
77 }
78
79 // Destroy any renderers using this scene.
80 for (auto& renderer : renderers_) {
81 if (renderer->root_scene() == scene_state) {
82 LOG(ERROR) << "Destroying renderer whose root scene has become "
83 "unavailable: renderer="
84 << renderer;
85 DestroyRenderer(renderer);
86 }
87 }
88
89 // Destroy.
90 InvalidateScene(scene_state);
91
92 // Remove from registry.
93 scenes_by_token_.erase(scene_state->scene_token()->value);
94 delete scene_state;
95 }
96
97 void CompositorEngine::CreateRenderer(
98 mojo::ContextProviderPtr context_provider,
99 mojo::InterfaceRequest<mojo::gfx::composition::Renderer> renderer_request,
100 const mojo::String& label) {
101 DCHECK(context_provider);
102 uint32_t renderer_id = next_renderer_id_++;
103
104 // Create the state and bind implementation to it.
105 std::string sanitized_label =
106 label.get().substr(0, mojo::gfx::composition::kLabelMaxLength);
abarth 2016/01/10 22:55:35 This pattern recurs a bunch. Maybe factor it out
jeffbrown 2016/01/16 03:28:31 Done.
107 RendererState* renderer_state =
108 new RendererState(renderer_id, sanitized_label);
109 RendererImpl* renderer_impl =
110 new RendererImpl(this, renderer_state, renderer_request.Pass());
111 renderer_state->set_renderer_impl(renderer_impl);
112 renderer_impl->set_connection_error_handler(
113 base::Bind(&CompositorEngine::OnRendererConnectionError,
114 base::Unretained(this), renderer_state));
115
116 // Create the renderer.
117 SchedulerCallbacks scheduler_callbacks(
118 base::Bind(&CompositorEngine::OnOutputUpdateRequest,
119 weak_factory_.GetWeakPtr(), renderer_state->GetWeakPtr()),
120 base::Bind(&CompositorEngine::OnOutputSnapshotRequest,
121 weak_factory_.GetWeakPtr(), renderer_state->GetWeakPtr()));
122 std::unique_ptr<Output> output(new GpuOutput(
123 context_provider.Pass(), scheduler_callbacks,
124 base::Bind(&CompositorEngine::OnOutputError, weak_factory_.GetWeakPtr(),
125 renderer_state->GetWeakPtr())));
126 renderer_state->set_output(std::move(output));
127
128 // Add to registry.
129 renderers_.push_back(renderer_state);
130 DVLOG(1) << "CreateRenderer: " << renderer_state;
131 }
132
133 void CompositorEngine::OnRendererConnectionError(
134 RendererState* renderer_state) {
135 DCHECK(IsRendererStateRegisteredDebug(renderer_state));
136 DVLOG(1) << "OnRendererConnectionError: renderer=" << renderer_state;
137
138 DestroyRenderer(renderer_state);
139 }
140
141 void CompositorEngine::DestroyRenderer(RendererState* renderer_state) {
142 DCHECK(IsRendererStateRegisteredDebug(renderer_state));
143 DVLOG(1) << "DestroyRenderer: renderer=" << renderer_state;
144
145 // Remove from registry.
146 renderers_.erase(
147 std::find(renderers_.begin(), renderers_.end(), renderer_state));
148 delete renderer_state;
149 }
150
151 void CompositorEngine::SetListener(
152 SceneState* scene_state,
153 mojo::gfx::composition::SceneListenerPtr listener) {
154 DCHECK(IsSceneStateRegisteredDebug(scene_state));
155 DVLOG(1) << "SetSceneListener: scene=" << scene_state;
156
157 scene_state->set_scene_listener(listener.Pass());
158 }
159
160 void CompositorEngine::Update(SceneState* scene_state,
161 mojo::gfx::composition::SceneUpdatePtr update) {
162 DCHECK(IsSceneStateRegisteredDebug(scene_state));
163 DVLOG(1) << "Update: scene=" << scene_state << ", update=" << update;
164
165 scene_state->scene_def()->EnqueueUpdate(update.Pass());
166 }
167
168 void CompositorEngine::Publish(
169 SceneState* scene_state,
170 mojo::gfx::composition::SceneMetadataPtr metadata) {
171 DCHECK(IsSceneStateRegisteredDebug(scene_state));
172 DVLOG(1) << "Publish: scene=" << scene_state << ", metadata=" << metadata;
173
174 if (!metadata)
175 metadata = mojo::gfx::composition::SceneMetadata::New();
176 int64_t presentation_time = metadata->presentation_time;
177 scene_state->scene_def()->EnqueuePublish(metadata.Pass());
178
179 // Implicitly schedule fresh snapshots.
180 InvalidateScene(scene_state);
181
182 // Ensure that the scene will be presented eventually, even if it is
183 // not associated with any renderer. Note that this is only a backstop
184 // in case the scene does not get presented sooner as part of snapshotting
185 // a renderer.
186 MojoTimeTicks now = MojoGetTimeTicksNow();
187 DCHECK(now >= 0);
188 if (presentation_time <= now) {
189 SceneDef::Disposition disposition = PresentScene(scene_state, now);
190 if (disposition == SceneDef::Disposition::kFailed)
191 DestroyScene(scene_state);
192 } else {
193 base::MessageLoop::current()->PostDelayedTask(
194 FROM_HERE, base::Bind(&CompositorEngine::OnPresentScene,
195 weak_factory_.GetWeakPtr(),
196 scene_state->GetWeakPtr(), presentation_time),
197 base::TimeDelta::FromMicroseconds(presentation_time - now));
abarth 2016/01/10 22:55:35 Do we need to schedule this for earlier so that it
jeffbrown 2016/01/16 03:28:32 It actually doesn't matter here. This only happen
198 }
199 }
200
201 void CompositorEngine::ScheduleFrame(SceneState* scene_state,
202 const SceneFrameCallback& callback) {
203 DCHECK(IsSceneStateRegisteredDebug(scene_state));
204
205 scene_state->AddSceneFrameCallback(callback);
206
207 // TODO(jeffbrown): Be more selective and do this work only for scenes
208 // which are strongly associated with the renderer so it doesn't receive
209 // conflicting timing signals coming from multiple renderers.
210 for (auto& renderer : renderers_) {
211 ScheduleFrameForRenderer(renderer, SchedulingMode::kUpdateAndSnapshot);
212 }
213 }
214
215 void CompositorEngine::SetRootScene(
216 RendererState* renderer_state,
217 mojo::gfx::composition::SceneTokenPtr scene_token,
218 uint32 scene_version,
219 mojo::RectPtr viewport) {
220 DCHECK(IsRendererStateRegisteredDebug(renderer_state));
221 DCHECK(scene_token);
222 DCHECK(viewport);
223 DVLOG(1) << "SetRootScene: renderer=" << renderer_state
224 << ", scene_token=" << scene_token
225 << ", scene_version=" << scene_version << ", viewport=" << viewport;
226
227 if (viewport->width < 1 || viewport->width > kMaxViewportWidth ||
228 viewport->height < 1 || viewport->height > kMaxViewportHeight) {
abarth 2016/01/10 22:55:35 nit: I would have tested <= 0
jeffbrown 2016/01/16 03:28:31 Done.
229 LOG(ERROR) << "Invalid viewport size: " << viewport;
230 DestroyRenderer(renderer_state);
231 return;
232 }
233
234 // Find the scene.
235 SceneState* scene_state = FindScene(scene_token->value);
236 if (!scene_state) {
237 LOG(ERROR) << "Could not set the renderer's root scene, scene not found: "
238 "scene_token="
239 << scene_token;
240 DestroyRenderer(renderer_state);
241 return;
242 }
243
244 // Update the root.
245 if (renderer_state->SetRootScene(scene_state, scene_version, *viewport)) {
246 ScheduleFrameForRenderer(renderer_state, SchedulingMode::kSnapshot);
247 }
248 }
249
250 void CompositorEngine::HitTest(
251 RendererState* renderer_state,
252 mojo::PointPtr point,
253 const mojo::gfx::composition::HitTester::HitTestCallback& callback) {
254 DCHECK(IsRendererStateRegisteredDebug(renderer_state));
255 DCHECK(point);
256 DVLOG(1) << "HitTest: renderer=" << renderer_state << ", point=" << point;
257
258 if (renderer_state->frame()) {
259 callback.Run(
260 renderer_state->frame()->HitTest(SkPoint::Make(point->x, point->y)));
261 } else {
262 callback.Run(nullptr);
abarth 2016/01/10 22:55:35 It's odd that there are two "failed" results here:
jeffbrown 2016/01/16 03:28:32 Good point.
263 }
264 }
265
266 SceneDef* CompositorEngine::ResolveSceneReference(
267 mojo::gfx::composition::SceneToken* scene_token) {
268 SceneState* scene_state = FindScene(scene_token->value);
269 return scene_state ? scene_state->scene_def() : nullptr;
270 }
271
272 void CompositorEngine::SendResourceUnavailable(SceneState* scene_state,
273 uint32_t resource_id) {
274 DCHECK(IsSceneStateRegisteredDebug(scene_state));
275 DVLOG(2) << "SendResourceUnavailable: resource_id=" << resource_id;
276
277 // TODO: Detect ANRs
abarth 2016/01/10 22:55:35 ANRs?
jeffbrown 2016/01/16 03:28:31 "Application Not Responding"
278 if (scene_state->scene_listener())
abarth 2016/01/10 22:55:35 Multiline ifs require { }
jeffbrown 2016/01/16 03:28:32 Done.
279 scene_state->scene_listener()->OnResourceUnavailable(
280 resource_id, base::Bind(&base::DoNothing));
281 }
282
283 SceneState* CompositorEngine::FindScene(uint32_t scene_token) {
284 auto it = scenes_by_token_.find(scene_token);
285 return it != scenes_by_token_.end() ? it->second : nullptr;
286 }
287
288 void CompositorEngine::InvalidateScene(SceneState* scene_state) {
289 DCHECK(IsSceneStateRegisteredDebug(scene_state));
290 DVLOG(2) << "InvalidateScene: scene=" << scene_state;
291
292 for (auto& renderer : renderers_) {
293 if (renderer->snapshot() &&
294 renderer->snapshot()->InvalidateScene(scene_state->scene_def())) {
295 ScheduleFrameForRenderer(renderer, SchedulingMode::kSnapshot);
296 }
297 }
298 }
299
300 SceneDef::Disposition CompositorEngine::PresentScene(
301 SceneState* scene_state,
302 int64_t presentation_time) {
303 DCHECK(IsSceneStateRegisteredDebug(scene_state));
304 DVLOG(2) << "PresentScene: scene=" << scene_state;
305
306 std::ostringstream errs;
307 SceneDef::Disposition disposition = scene_state->scene_def()->Present(
308 presentation_time, base::Bind(&CompositorEngine::ResolveSceneReference,
309 base::Unretained(this)),
310 base::Bind(&CompositorEngine::SendResourceUnavailable,
311 base::Unretained(this), base::Unretained(scene_state)),
312 errs);
313 if (disposition == SceneDef::Disposition::kFailed) {
314 LOG(ERROR) << "Scene published invalid updates: scene=" << scene_state;
315 LOG(ERROR) << errs.str();
316 // Caller is responsible for destroying the scene.
317 }
318 return disposition;
319 }
320
321 void CompositorEngine::PresentRenderer(RendererState* renderer_state,
322 int64_t presentation_time) {
323 DCHECK(IsRendererStateRegisteredDebug(renderer_state));
324 DVLOG(2) << "PresentRenderer: renderer_state=" << renderer_state;
325
326 // TODO(jeffbrown): Be more selective and do this work only for scenes
327 // associated with the renderer that actually have pending updates.
328 std::vector<SceneState*> dead_scenes;
329 for (auto& pair : scenes_by_token_) {
330 SceneState* scene_state = pair.second;
331 SceneDef::Disposition disposition =
332 PresentScene(scene_state, presentation_time);
333 if (disposition == SceneDef::Disposition::kFailed)
334 dead_scenes.push_back(scene_state);
335 }
336 for (SceneState* scene_state : dead_scenes)
337 DestroyScene(scene_state);
abarth 2016/01/10 22:55:35 Should we DCHECK that scene_state isn't in scenes_
jeffbrown 2016/01/16 03:28:32 You mean after DestroyScene returns? I don't thin
338 }
339
340 void CompositorEngine::SnapshotRenderer(
341 RendererState* renderer_state,
342 const mojo::gfx::composition::FrameInfo& frame_info) {
343 DCHECK(IsRendererStateRegisteredDebug(renderer_state));
344 DVLOG(2) << "SnapshotRenderer: renderer_state=" << renderer_state;
345
346 if (VLOG_IS_ON(2)) {
347 std::ostringstream block_log;
348 SnapshotRendererInner(renderer_state, frame_info, &block_log);
349 if (!renderer_state->valid()) {
350 DVLOG(2) << "Rendering completely blocked: " << block_log.str();
351 } else if (!block_log.str().empty()) {
352 DVLOG(2) << "Rendering partially blocked: " << block_log.str();
353 } else {
354 DVLOG(2) << "Rendering unblocked";
355 }
356 } else {
357 SnapshotRendererInner(renderer_state, frame_info, nullptr);
358 }
359 }
360
361 void CompositorEngine::SnapshotRendererInner(
362 RendererState* renderer_state,
363 const mojo::gfx::composition::FrameInfo& frame_info,
364 std::ostream* block_log) {
365 if (!renderer_state->root_scene()) {
366 if (block_log)
367 *block_log << "No root scene" << std::endl;
368 renderer_state->SetSnapshot(nullptr);
369 return;
370 }
371
372 SnapshotBuilder builder(block_log);
373 renderer_state->SetSnapshot(
374 builder.Build(renderer_state->root_scene()->scene_def(),
375 renderer_state->root_scene_viewport(), frame_info));
376
377 if (renderer_state->valid())
378 renderer_state->output()->SubmitFrame(renderer_state->frame());
379 }
380
381 void CompositorEngine::ScheduleFrameForRenderer(
382 RendererState* renderer_state,
383 SchedulingMode scheduling_mode) {
384 DCHECK(IsRendererStateRegisteredDebug(renderer_state));
385 renderer_state->output()->scheduler()->ScheduleFrame(scheduling_mode);
386 }
387
388 void CompositorEngine::OnOutputError(
389 const base::WeakPtr<RendererState>& renderer_state_weak) {
390 RendererState* renderer_state = renderer_state_weak.get();
391 if (!renderer_state)
392 return;
393 DCHECK(IsRendererStateRegisteredDebug(renderer_state));
394
395 LOG(ERROR) << "Renderer encountered a fatal error: renderer="
396 << renderer_state;
397
398 DestroyRenderer(renderer_state);
399 }
400
401 void CompositorEngine::OnOutputUpdateRequest(
402 const base::WeakPtr<RendererState>& renderer_state_weak,
403 const mojo::gfx::composition::FrameInfo& frame_info) {
404 RendererState* renderer_state = renderer_state_weak.get();
405 if (!renderer_state)
406 return;
407 DCHECK(IsRendererStateRegisteredDebug(renderer_state));
408
409 // TODO(jeffbrown): Be more selective and do this work only for scenes
410 // associated with the renderer.
411 for (auto& pair : scenes_by_token_) {
412 pair.second->DispatchSceneFrameCallbacks(frame_info);
413 }
414 }
415
416 void CompositorEngine::OnOutputSnapshotRequest(
417 const base::WeakPtr<RendererState>& renderer_state_weak,
418 const mojo::gfx::composition::FrameInfo& frame_info) {
419 RendererState* renderer_state = renderer_state_weak.get();
420 if (!renderer_state)
421 return;
422 DCHECK(IsRendererStateRegisteredDebug(renderer_state));
423
424 PresentRenderer(renderer_state, frame_info.presentation_time);
425 SnapshotRenderer(renderer_state, frame_info);
426 }
427
428 void CompositorEngine::OnPresentScene(
429 const base::WeakPtr<SceneState>& scene_state_weak,
430 int64_t presentation_time) {
431 SceneState* scene_state = scene_state_weak.get();
432 if (!scene_state)
433 return;
434 DCHECK(IsSceneStateRegisteredDebug(scene_state));
435
436 SceneDef::Disposition disposition =
437 PresentScene(scene_state, presentation_time);
438 if (disposition == SceneDef::Disposition::kFailed)
439 DestroyScene(scene_state);
440 else if (disposition == SceneDef::Disposition::kSucceeded)
441 InvalidateScene(scene_state);
442 }
443
444 } // namespace compositor
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698