1use crate::app::{Config, MessageInternal};
5use crate::drawing::DisplayRotation;
6use crate::geometry::UintSize;
7use crate::input::flatland::{FlatlandMouseInputHandler, FlatlandTouchInputHandler};
8use crate::input::key3::KeyboardInputHandler;
9use crate::render::generic::{self, Backend};
10use crate::render::{self, ContextInner};
11use crate::view::strategies::base::{FlatlandParams, ViewStrategy, ViewStrategyPtr};
12use crate::view::{UserInputMessage, ViewAssistantContext, ViewAssistantPtr, ViewDetails, ViewKey};
13use crate::Size;
14use anyhow::{ensure, Context, Error, Result};
15use async_trait::async_trait;
16use async_utils::hanging_get::client::HangingGetStream;
17use display_utils::BufferCollectionId as DisplayBufferCollectionId;
18use euclid::size2;
19use fidl::endpoints::{create_endpoints, create_proxy, create_request_stream};
20use fidl_fuchsia_images2::PixelFormat;
21use fidl_fuchsia_ui_composition as flatland;
22use fidl_fuchsia_ui_views::ViewRef;
23use fuchsia_async::{self as fasync, OnSignals};
24use fuchsia_component::client::connect_to_protocol;
25use fuchsia_framebuffer::sysmem::BufferCollectionAllocator;
26use fuchsia_framebuffer::{FrameSet, FrameUsage, ImageId};
27use fuchsia_scenic::BufferCollectionTokenPair;
28use fuchsia_trace::{duration, instant};
29use futures::channel::mpsc::UnboundedSender;
30use futures::prelude::*;
31use futures::{StreamExt, TryStreamExt};
32use std::collections::{BTreeMap, BTreeSet, HashMap};
33use zx::{self as zx, Event, HandleBased, MonotonicInstant, Signals};
34
35fn setup_handle_flatland_events(
36 event_stream: flatland::FlatlandEventStream,
37 view_key: ViewKey,
38 app_sender: UnboundedSender<MessageInternal>,
39) {
40 fasync::Task::local(
41 event_stream
42 .try_for_each(move |event| {
43 match event {
44 flatland::FlatlandEvent::OnNextFrameBegin { values } => {
45 app_sender
46 .unbounded_send(MessageInternal::FlatlandOnNextFrameBegin(
47 view_key, values,
48 ))
49 .expect("unbounded_send");
50 }
51 flatland::FlatlandEvent::OnFramePresented { frame_presented_info } => {
52 app_sender
53 .unbounded_send(MessageInternal::FlatlandOnFramePresented(
54 view_key,
55 frame_presented_info,
56 ))
57 .expect("unbounded_send");
58 }
59 flatland::FlatlandEvent::OnError { error } => {
60 app_sender
61 .unbounded_send(MessageInternal::FlatlandOnError(view_key, error))
62 .expect("unbounded_send");
63 }
64 };
65 future::ok(())
66 })
67 .unwrap_or_else(|e| eprintln!("error listening for Flatland Events: {:?}", e)),
68 )
69 .detach();
70}
71
72fn duplicate_import_token(
73 token: &fidl_fuchsia_ui_composition::BufferCollectionImportToken,
74) -> Result<fidl_fuchsia_ui_composition::BufferCollectionImportToken, Error> {
75 let value = token.value.duplicate_handle(zx::Rights::SAME_RIGHTS)?;
76 Ok(fidl_fuchsia_ui_composition::BufferCollectionImportToken { value })
77}
78
79struct Plumber {
80 pub size: UintSize,
81 pub collection_id: u32,
82 pub frame_set: FrameSet,
83 pub image_indexes: BTreeMap<ImageId, u32>,
84 pub context: render::Context,
85}
86
87impl Plumber {
88 async fn new(
89 flatland: &flatland::FlatlandProxy,
90 allocator: &flatland::AllocatorProxy,
91 size: UintSize,
92 pixel_format: PixelFormat,
93 buffer_count: usize,
94 collection_id: u32,
95 first_image_id: u64,
96 ) -> Result<Plumber, Error> {
97 let use_spinel = Config::get().use_spinel;
98
99 ensure!(use_spinel == false, "Spinel support is disabled");
100
101 let usage = if use_spinel { FrameUsage::Gpu } else { FrameUsage::Cpu };
102 let mut buffer_allocator = BufferCollectionAllocator::new(
103 size.width,
104 size.height,
105 pixel_format,
106 usage,
107 buffer_count,
108 )?;
109
110 buffer_allocator.set_name(100, "CarnelianSurface")?;
111
112 let context_token = buffer_allocator.duplicate_token().await?;
113 let mut context = render::Context {
114 inner: ContextInner::Forma(generic::Forma::new_context(
115 context_token,
116 size,
117 DisplayRotation::Deg0,
118 )),
119 };
120
121 let sysmem_buffer_collection_token = buffer_allocator.duplicate_token().await?;
122 let buffer_tokens = BufferCollectionTokenPair::new();
123 let args = flatland::RegisterBufferCollectionArgs {
124 export_token: Some(buffer_tokens.export_token),
125 buffer_collection_token2: Some(sysmem_buffer_collection_token),
128 ..Default::default()
129 };
130
131 allocator
132 .register_buffer_collection(args)
133 .await
134 .expect("fidl error")
135 .expect("error registering buffer collection");
136
137 let buffers = buffer_allocator.allocate_buffers(true).await.context("allocate_buffers")?;
138
139 let blend_mode = if Config::get().needs_blending {
140 flatland::BlendMode::SrcOver
141 } else {
142 flatland::BlendMode::Src
143 };
144 let mut image_ids = BTreeSet::new();
145 let mut image_indexes = BTreeMap::new();
146 let buffer_count = buffers.buffers.as_ref().unwrap().len();
147 for index in 0..buffer_count as usize {
148 let image_id = index + first_image_id as usize;
149 image_ids.insert(image_id as u64);
150 let uindex = index as u32;
151 image_indexes.insert(image_id as u64, uindex);
152 let image_props = flatland::ImageProperties {
153 size: Some(fidl_fuchsia_math::SizeU { width: size.width, height: size.height }),
154 ..Default::default()
155 };
156 let flatland_image_id = flatland::ContentId { value: image_id as u64 };
157 let import_token = duplicate_import_token(&buffer_tokens.import_token)?;
158 flatland.create_image(&flatland_image_id, import_token, uindex, &image_props)?;
159 flatland
160 .set_image_destination_size(
161 &flatland_image_id,
162 &fidl_fuchsia_math::SizeU { width: size.width, height: size.height },
163 )
164 .expect("fidl error");
165 flatland
166 .set_image_blending_function(&flatland_image_id, blend_mode)
167 .expect("fidl error");
168 context.get_image(index as u32);
172 }
173
174 let frame_set = FrameSet::new(DisplayBufferCollectionId(collection_id as u64), image_ids);
175 Ok(Plumber { size, collection_id, frame_set, image_indexes, context })
176 }
177
178 pub fn enter_retirement(&mut self, _flatland: &flatland::FlatlandProxy) {}
179}
180
181const RENDER_BUFFER_COUNT: usize = 3;
182const DEFAULT_PRESENT_INTERVAL: i64 = (1_000_000_000.0 / 60.0) as i64;
183const TRANSFORM_ID: flatland::TransformId = flatland::TransformId { value: 1 };
184
185#[derive(Clone, Copy)]
186struct PresentationTime {
187 presentation_time: i64,
188 latch_point: i64,
189}
190
191pub(crate) struct FlatlandViewStrategy {
192 flatland: flatland::FlatlandProxy,
193 allocator: flatland::AllocatorProxy,
194 view_key: ViewKey,
195 last_presentation_time: i64,
196 future_presentation_times: Vec<PresentationTime>,
197 custom_render_offset: Option<i64>,
198 present_interval: i64,
199 num_presents_allowed: usize,
202 pending_present_count: usize,
204 render_timer_scheduled: bool,
205 missed_frame: bool,
206 app_sender: UnboundedSender<MessageInternal>,
207 next_buffer_collection: u32,
208 plumber: Option<Plumber>,
209 retiring_plumbers: Vec<Plumber>,
210 next_image_id: u64,
211 previous_present_release_event: Option<Event>,
212 current_present_release_event: Option<Event>,
213 flatland_mouse_input_handlers: HashMap<u32, FlatlandMouseInputHandler>,
214 flatland_touch_input_handler: FlatlandTouchInputHandler,
215 keyboard_handler: KeyboardInputHandler,
216}
217
218impl FlatlandViewStrategy {
219 pub(crate) async fn new(
220 key: ViewKey,
221 flatland_params: FlatlandParams,
222 app_sender: UnboundedSender<MessageInternal>,
223 ) -> Result<ViewStrategyPtr, Error> {
224 let flatland = connect_to_protocol::<flatland::FlatlandMarker>()?;
225 if let Some(debug_name) = flatland_params.debug_name {
226 flatland.set_debug_name(&debug_name)?;
227 }
228
229 {
232 use fidl::endpoints::Proxy;
233 use zx::AsHandleRef;
234
235 let koid = flatland.as_channel().get_koid().unwrap().raw_koid();
236 instant!(
237 c"gfx",
238 c"FlatlandViewStrategy::new",
239 fuchsia_trace::Scope::Process,
240 "flatland_koid" => koid
241 );
242 }
243
244 flatland.create_transform(&TRANSFORM_ID)?;
245 flatland.set_root_transform(&TRANSFORM_ID)?;
246 setup_handle_flatland_events(flatland.take_event_stream(), key, app_sender.clone());
247 let allocator = connect_to_protocol::<flatland::AllocatorMarker>()?;
248 Self::create_parent_viewport_watcher(
249 &flatland,
250 app_sender.clone(),
251 key,
252 flatland_params.args.view_creation_token.expect("view_creation_token"),
253 )?;
254
255 let strat = Self {
256 flatland,
257 allocator,
258 view_key: key,
259 app_sender: app_sender,
260 last_presentation_time: fasync::MonotonicInstant::now().into_nanos(),
261 future_presentation_times: Vec::new(),
262 custom_render_offset: None,
263 present_interval: DEFAULT_PRESENT_INTERVAL,
264 num_presents_allowed: 1,
265 pending_present_count: 0,
266 render_timer_scheduled: false,
267 missed_frame: false,
268 plumber: None,
269 retiring_plumbers: Vec::new(),
270 next_buffer_collection: 1,
271 next_image_id: 1,
272 previous_present_release_event: None,
273 current_present_release_event: None,
274 flatland_mouse_input_handlers: HashMap::new(),
275 flatland_touch_input_handler: FlatlandTouchInputHandler::default(),
276 keyboard_handler: KeyboardInputHandler::new(),
277 };
278
279 Ok(Box::new(strat))
280 }
281
282 fn create_parent_viewport_watcher(
283 flatland: &flatland::FlatlandProxy,
284 app_sender: UnboundedSender<MessageInternal>,
285 view_key: ViewKey,
286 view_creation_token: fidl_fuchsia_ui_views::ViewCreationToken,
287 ) -> Result<(), Error> {
288 let (parent_viewport_watcher, server_end) =
289 create_proxy::<flatland::ParentViewportWatcherMarker>();
290
291 let viewref_pair = fuchsia_scenic::ViewRefPair::new()?;
292 let view_ref = fuchsia_scenic::duplicate_view_ref(&viewref_pair.view_ref)?;
293
294 let input = Config::get().input;
296 if input {
297 let view_identity = fidl_fuchsia_ui_views::ViewIdentityOnCreation::from(viewref_pair);
298 let mut view_bound_protocols = flatland::ViewBoundProtocols::default();
299
300 let (touch_client, touch_server) = create_endpoints();
301 let (mouse_client, mouse_server) = create_endpoints();
302 let (view_ref_focused_client, view_ref_focused_server) = create_endpoints();
303
304 view_bound_protocols.touch_source = Some(touch_server);
305 view_bound_protocols.mouse_source = Some(mouse_server);
306 view_bound_protocols.view_ref_focused = Some(view_ref_focused_server);
307
308 flatland.create_view2(
309 view_creation_token,
310 view_identity,
311 view_bound_protocols,
312 server_end,
313 )?;
314
315 let touch_proxy = touch_client.into_proxy();
316 let touch_sender = app_sender.clone();
317
318 fasync::Task::local(async move {
319 let mut events: Vec<fidl_fuchsia_ui_pointer::TouchResponse> = Vec::new();
320 loop {
321 let result = touch_proxy.watch(&events).await;
322 match result {
323 Ok(returned_events) => {
324 events = returned_events
325 .iter()
326 .map(|event| fidl_fuchsia_ui_pointer::TouchResponse {
327 trace_flow_id: event
328 .pointer_sample
329 .as_ref()
330 .and(event.trace_flow_id),
331 response_type: event.pointer_sample.as_ref().and_then(|_| {
332 Some(fidl_fuchsia_ui_pointer::TouchResponseType::Yes)
333 }),
334 ..Default::default()
335 })
336 .collect();
337 touch_sender
338 .unbounded_send(MessageInternal::UserInputMessage(
339 view_key,
340 UserInputMessage::FlatlandTouchEvents(returned_events),
341 ))
342 .expect("failed to send MessageInternal.");
343 }
344 Err(fidl::Error::ClientChannelClosed { .. }) => {
345 println!("touch event connection closed.");
346 return;
347 }
348 Err(fidl_error) => {
349 println!("touch event connection closed error: {:?}", fidl_error);
350 return;
351 }
352 }
353 }
354 })
355 .detach();
356
357 let mouse_proxy = mouse_client.into_proxy();
358 let mouse_sender = app_sender.clone();
359
360 fasync::Task::local(async move {
361 loop {
362 let result = mouse_proxy.watch().await;
363 match result {
364 Ok(returned_events) => {
365 mouse_sender
366 .unbounded_send(MessageInternal::UserInputMessage(
367 view_key,
368 UserInputMessage::FlatlandMouseEvents(returned_events),
369 ))
370 .expect("failed to send MessageInternal.");
371 }
372 Err(fidl::Error::ClientChannelClosed { .. }) => {
373 println!("mouse event connection closed.");
374 return;
375 }
376 Err(fidl_error) => {
377 println!("mouse event connection closed error: {:?}", fidl_error);
378 return;
379 }
380 }
381 }
382 })
383 .detach();
384
385 let view_ref_focused_proxy = view_ref_focused_client.into_proxy();
386 let view_ref_focused_sender = app_sender.clone();
387
388 fasync::Task::local(async move {
389 loop {
390 let result = view_ref_focused_proxy.watch().await;
391 match result {
392 Ok(msg) => {
393 view_ref_focused_sender
394 .unbounded_send(MessageInternal::Focus(
395 view_key,
396 msg.focused.unwrap_or(false),
397 ))
398 .expect("failed to send MessageInternal.");
399 }
400 Err(fidl::Error::ClientChannelClosed { .. }) => {
401 println!("ViewRefFocused connection closed.");
402 return;
403 }
404 Err(fidl_error) => {
405 println!("ViewRefFocused connection closed error: {:?}", fidl_error);
406 return;
407 }
408 }
409 }
410 })
411 .detach();
412
413 Self::listen_for_key_events(view_ref, &app_sender, view_key)?;
414 } else {
415 flatland.create_view(view_creation_token, server_end)?;
416 }
417
418 let sender = app_sender;
419 fasync::Task::local(async move {
420 let mut layout_info_stream = HangingGetStream::new(
421 parent_viewport_watcher,
422 flatland::ParentViewportWatcherProxy::get_layout,
423 );
424
425 while let Some(result) = layout_info_stream.next().await {
426 match result {
427 Ok(layout_info) => {
428 if let Some(fidl_fuchsia_math::SizeU { width, height }) =
429 layout_info.logical_size
430 {
431 sender
432 .unbounded_send(MessageInternal::SizeChanged(
433 view_key,
434 size2(width, height).to_f32(),
435 ))
436 .expect("failed to send MessageInternal.");
437 }
438 if let Some(fidl_fuchsia_math::VecF { x, y }) =
439 layout_info.device_pixel_ratio
440 {
441 sender
442 .unbounded_send(MessageInternal::MetricsChanged(
443 view_key,
444 size2(x, y),
445 ))
446 .expect("failed to send MessageInternal.");
447 }
448 }
449 Err(fidl::Error::ClientChannelClosed { .. }) => {
450 println!("graph link connection closed.");
451 return; }
453 Err(fidl_error) => {
454 println!("graph link GetLayout() error: {:?}", fidl_error);
455 return; }
457 }
458 }
459 })
460 .detach();
461 Ok(())
462 }
463
464 fn do_present(
465 flatland: &flatland::FlatlandProxy,
466 _app_sender: &UnboundedSender<MessageInternal>,
467 _key: ViewKey,
468 presentation_time: i64,
469 release_event: Option<Event>,
470 ) {
471 flatland
472 .present(flatland::PresentArgs {
473 requested_presentation_time: Some(presentation_time),
474 acquire_fences: None,
475 release_fences: release_event.and_then(|release_event| Some(vec![release_event])),
476 unsquashable: Some(true),
477 ..Default::default()
478 })
479 .expect("present error");
480 }
481
482 fn make_view_assistant_context_with_time(
483 view_details: &ViewDetails,
484 image_id: ImageId,
485 image_index: u32,
486 app_sender: UnboundedSender<MessageInternal>,
487 presentation_time: MonotonicInstant,
488 ) -> ViewAssistantContext {
489 ViewAssistantContext {
490 key: view_details.key,
491 size: view_details.logical_size,
492 metrics: view_details.metrics,
493 presentation_time,
494 buffer_count: None,
495 image_id,
496 image_index,
497 app_sender,
498 mouse_cursor_position: None,
499 display_info: None,
500 }
501 }
502
503 fn make_view_assistant_context(
504 view_details: &ViewDetails,
505 image_id: ImageId,
506 image_index: u32,
507 app_sender: UnboundedSender<MessageInternal>,
508 ) -> ViewAssistantContext {
509 Self::make_view_assistant_context_with_time(
510 view_details,
511 image_id,
512 image_index,
513 app_sender,
514 MonotonicInstant::get(),
515 )
516 }
517
518 async fn create_plumber(&mut self, size: UintSize) -> Result<(), Error> {
519 let buffer_collection_id = self.next_buffer_collection;
520 self.next_buffer_collection = self.next_buffer_collection.wrapping_add(1);
521 let next_image_id = self.next_image_id;
522 self.next_image_id = self.next_image_id.wrapping_add(RENDER_BUFFER_COUNT as u64);
523 self.plumber = Some(
524 Plumber::new(
525 &self.flatland,
526 &self.allocator,
527 size.to_u32(),
528 fidl_fuchsia_images2::PixelFormat::B8G8R8A8,
529 RENDER_BUFFER_COUNT,
530 buffer_collection_id,
531 next_image_id,
532 )
533 .await
534 .expect("VmoPlumber::new"),
535 );
536 Ok(())
537 }
538
539 fn next_presentation_time(&self) -> PresentationTime {
540 let now = fasync::MonotonicInstant::now().into_nanos();
541 let legal_next = PresentationTime {
542 presentation_time: self.last_presentation_time + self.present_interval,
543 latch_point: now,
544 };
545 let earliest_presentation_time = self.last_presentation_time + self.present_interval / 2;
548 let next = self
549 .future_presentation_times
550 .iter()
551 .find(|t| t.presentation_time >= earliest_presentation_time && t.latch_point > now)
552 .unwrap_or(&legal_next);
553 *next
554 }
555
556 fn schedule_render_timer(&mut self) {
557 if !self.render_timer_scheduled && !self.missed_frame {
558 let presentation_time = self.next_presentation_time();
559 const DEFAULT_RENDER_OFFSET_DELTA: i64 = 1_000_000; let render_offset = self
564 .custom_render_offset
565 .unwrap_or_else(|| self.present_interval - DEFAULT_RENDER_OFFSET_DELTA);
566 let render_time = presentation_time.latch_point - render_offset;
567 let timer =
568 fasync::Timer::new(fuchsia_async::MonotonicInstant::from_nanos(render_time));
569 let timer_sender = self.app_sender.clone();
570 let key = self.view_key;
571 fasync::Task::local(async move {
572 timer.await;
573 timer_sender.unbounded_send(MessageInternal::Render(key)).expect("unbounded_send");
574 })
575 .detach();
576 self.render_timer_scheduled = true;
577 }
578 }
579
580 fn render_to_image_from_plumber(
581 &mut self,
582 view_details: &ViewDetails,
583 view_assistant: &mut ViewAssistantPtr,
584 ) -> bool {
585 let presentation_time = self.next_presentation_time();
586 let plumber = self.plumber.as_mut().expect("plumber");
587 if let Some(available) = plumber.frame_set.get_available_image() {
588 duration!(c"gfx", c"FlatlandViewStrategy::render.render_to_image");
589 let available_index = plumber.image_indexes.get(&available).expect("index for image");
590 let render_context = Self::make_view_assistant_context_with_time(
591 view_details,
592 available,
593 *available_index,
594 self.app_sender.clone(),
595 MonotonicInstant::from_nanos(presentation_time.presentation_time),
596 );
597 let buffer_ready_event = Event::create();
598 view_assistant
599 .render(&mut plumber.context, buffer_ready_event, &render_context)
600 .unwrap_or_else(|e| panic!("Update error: {:?}", e));
601 plumber.frame_set.mark_prepared(available);
602 let key = view_details.key;
603 let collection_id = plumber.collection_id;
604 let release_event = Event::create();
605 let local_release_event =
606 release_event.duplicate_handle(zx::Rights::SAME_RIGHTS).expect("duplicate_handle");
607 let app_sender = self.app_sender.clone();
608 fasync::Task::local(async move {
609 let signals = OnSignals::new(&local_release_event, Signals::EVENT_SIGNALED);
610 signals.await.expect("to wait");
611 app_sender
612 .unbounded_send(MessageInternal::ImageFreed(key, available, collection_id))
613 .expect("unbounded_send");
614 })
615 .detach();
616 self.current_present_release_event = Some(release_event);
617
618 let image_id = flatland::ContentId { value: available };
619 self.flatland.set_content(&TRANSFORM_ID, &image_id).expect("fidl error");
620
621 plumber.frame_set.mark_presented(available);
623 true
624 } else {
625 instant!(
626 c"gfx",
627 c"FlatlandViewStrategy::no_available_image",
628 fuchsia_trace::Scope::Process
629 );
630 self.missed_frame = true;
631 false
632 }
633 }
634
635 fn retry_missed_frame(&mut self) {
636 if self.missed_frame {
637 self.missed_frame = false;
638 self.render_requested();
639 }
640 }
641
642 fn listen_for_key_events(
643 view_ref: ViewRef,
644 app_sender: &UnboundedSender<MessageInternal>,
645 key: ViewKey,
646 ) -> Result<(), Error> {
647 let keyboard = connect_to_protocol::<fidl_fuchsia_ui_input3::KeyboardMarker>()
648 .context("Failed to connect to Keyboard service")?;
649
650 let (listener_client_end, mut listener_stream) =
651 create_request_stream::<fidl_fuchsia_ui_input3::KeyboardListenerMarker>();
652
653 let event_sender = app_sender.clone();
654
655 fasync::Task::local(async move {
656 keyboard.add_listener(view_ref, listener_client_end).await.expect("add_listener");
657
658 while let Some(event) =
659 listener_stream.try_next().await.expect("Failed to get next key event")
660 {
661 match event {
662 fidl_fuchsia_ui_input3::KeyboardListenerRequest::OnKeyEvent {
663 event,
664 responder,
665 ..
666 } => {
667 responder
671 .send(fidl_fuchsia_ui_input3::KeyEventStatus::Handled)
672 .expect("send");
673 event_sender
674 .unbounded_send(MessageInternal::UserInputMessage(
675 key,
676 UserInputMessage::ScenicKeyEvent(event),
677 ))
678 .expect("unbounded_send");
679 }
680 }
681 }
682 })
683 .detach();
684 Ok(())
685 }
686}
687
688#[async_trait(?Send)]
689impl ViewStrategy for FlatlandViewStrategy {
690 fn initial_metrics(&self) -> Size {
691 size2(1.0, 1.0)
692 }
693
694 fn create_view_assistant_context(&self, view_details: &ViewDetails) -> ViewAssistantContext {
695 ViewAssistantContext {
696 key: view_details.key,
697 size: view_details.logical_size,
698 metrics: view_details.metrics,
699 presentation_time: Default::default(),
700 buffer_count: None,
701 image_id: Default::default(),
702 image_index: Default::default(),
703 app_sender: self.app_sender.clone(),
704 mouse_cursor_position: None,
705 display_info: None,
706 }
707 }
708
709 fn setup(&mut self, view_details: &ViewDetails, view_assistant: &mut ViewAssistantPtr) {
710 duration!(c"gfx", c"FlatlandViewStrategy::setup");
711 let render_context =
712 Self::make_view_assistant_context(view_details, 0, 0, self.app_sender.clone());
713 view_assistant.setup(&render_context).unwrap_or_else(|e| panic!("Setup error: {:?}", e));
714 self.custom_render_offset = view_assistant.get_render_offset();
715 self.render_requested();
716 }
717
718 async fn render(
719 &mut self,
720 view_details: &ViewDetails,
721 view_assistant: &mut ViewAssistantPtr,
722 ) -> bool {
723 let size = view_details.physical_size.floor().to_u32();
724 duration!(c"gfx", c"FlatlandViewStrategy::render",
725 "width" => size.width,
726 "height" => size.height);
727
728 self.render_timer_scheduled = false;
729 if size.width > 0 && size.height > 0 {
730 if self.num_presents_allowed == 0 {
731 instant!(c"gfx", c"FlatlandViewStrategy::present_is_not_allowed",
732 fuchsia_trace::Scope::Process,
733 "counts" => format!("{} pending {} allowed",
734 self.pending_present_count,
735 self.num_presents_allowed).as_str());
736 self.missed_frame = true;
737 return false;
738 }
739
740 if self.plumber.is_none() {
741 duration!(c"gfx", c"FlatlandViewStrategy::render.create_plumber");
742 self.create_plumber(size).await.expect("create_plumber");
743 } else {
744 let current_size = self.plumber.as_ref().expect("plumber").size;
745 if current_size != size {
746 duration!(c"gfx", c"FlatlandViewStrategy::render.create_plumber");
747 let retired_plumber = self.plumber.take().expect("plumber");
748 self.retiring_plumbers.push(retired_plumber);
749 self.create_plumber(size).await.expect("create_plumber");
750 }
751 }
752 self.render_to_image_from_plumber(view_details, view_assistant)
753 } else {
754 true
755 }
756 }
757
758 fn present(&mut self, _view_details: &ViewDetails) {
759 duration!(c"gfx", c"FlatlandViewStrategy::present");
760 if !self.missed_frame {
761 assert!(self.num_presents_allowed > 0);
762 let release_event = self.previous_present_release_event.take();
763 let presentation_time = self.next_presentation_time();
764 Self::do_present(
765 &self.flatland,
766 &self.app_sender,
767 self.view_key,
768 presentation_time.presentation_time,
769 release_event,
770 );
771 self.last_presentation_time = presentation_time.presentation_time;
772 self.pending_present_count += 1;
773 self.num_presents_allowed -= 1;
774 self.previous_present_release_event = self.current_present_release_event.take();
775 }
776 }
777
778 fn present_done(
779 &mut self,
780 _view_details: &ViewDetails,
781 _view_assistant: &mut ViewAssistantPtr,
782 info: fidl_fuchsia_scenic_scheduling::FramePresentedInfo,
783 ) {
784 let num_presents_handled = info.presentation_infos.len();
785 assert!(self.pending_present_count >= num_presents_handled);
786 self.pending_present_count -= num_presents_handled;
787 instant!(
788 c"gfx",
789 c"FlatlandViewStrategy::present_done",
790 fuchsia_trace::Scope::Process,
791 "presents" => format!("{} handled", num_presents_handled).as_str()
792 );
793 }
794
795 fn handle_focus(
796 &mut self,
797 view_details: &ViewDetails,
798 view_assistant: &mut ViewAssistantPtr,
799 focus: bool,
800 ) {
801 let mut render_context =
802 Self::make_view_assistant_context(view_details, 0, 0, self.app_sender.clone());
803 view_assistant
804 .handle_focus_event(&mut render_context, focus)
805 .unwrap_or_else(|e| panic!("handle_focus error: {:?}", e));
806 }
807
808 fn convert_user_input_message(
809 &mut self,
810 _view_details: &ViewDetails,
811 message: UserInputMessage,
812 ) -> Result<Vec<crate::input::Event>, Error> {
813 match message {
814 UserInputMessage::ScenicKeyEvent(key_event) => {
815 let converted_events = self.keyboard_handler.handle_key_event(&key_event);
816 Ok(converted_events)
817 }
818 UserInputMessage::FlatlandMouseEvents(mouse_events) => {
819 let mut events = Vec::new();
820 for mouse_event in &mouse_events {
821 if let Some(pointer_sample) = mouse_event.pointer_sample.as_ref() {
822 let device_id = pointer_sample.device_id.expect("device_id");
823 let handler_entry = self
824 .flatland_mouse_input_handlers
825 .entry(device_id)
826 .or_insert_with(|| FlatlandMouseInputHandler::new(device_id));
827 events.extend(handler_entry.handle_mouse_events(&mouse_events));
828 }
829 }
830 Ok(events)
831 }
832 UserInputMessage::FlatlandTouchEvents(touch_events) => {
833 Ok(self.flatland_touch_input_handler.handle_events(&touch_events))
834 }
835 }
836 }
837
838 fn image_freed(&mut self, image_id: u64, collection_id: u32) {
839 instant!(
840 c"gfx",
841 c"FlatlandViewStrategy::image_freed",
842 fuchsia_trace::Scope::Process,
843 "image_freed" => format!("{} in {}", image_id, collection_id).as_str()
844 );
845
846 self.retry_missed_frame();
847
848 if let Some(plumber) = self.plumber.as_mut() {
849 if plumber.collection_id == collection_id {
850 plumber.frame_set.mark_done_presenting(image_id);
851 return;
852 }
853 }
854
855 for retired_plumber in &mut self.retiring_plumbers {
856 if retired_plumber.collection_id == collection_id {
857 retired_plumber.frame_set.mark_done_presenting(image_id);
858 if retired_plumber.frame_set.no_images_in_use() {
859 retired_plumber.enter_retirement(&self.flatland);
860 }
861 }
862 }
863
864 self.retiring_plumbers.retain(|plumber| !plumber.frame_set.no_images_in_use());
865 }
866
867 fn render_requested(&mut self) {
868 self.schedule_render_timer();
869 }
870
871 fn handle_on_next_frame_begin(
872 &mut self,
873 info: &fidl_fuchsia_ui_composition::OnNextFrameBeginValues,
874 ) {
875 self.num_presents_allowed += info.additional_present_credits.unwrap_or(0) as usize;
876 let future_presentation_infos =
877 info.future_presentation_infos.as_ref().expect("future_presentation_infos");
878 let present_intervals = future_presentation_infos.len();
879 instant!(
880 c"gfx",
881 c"FlatlandViewStrategy::handle_on_next_frame_begin",
882 fuchsia_trace::Scope::Process,
883 "counts" => format!("{} present_intervals", present_intervals).as_str()
884 );
885 if present_intervals > 0 {
886 let times: Vec<_> = future_presentation_infos
887 .iter()
888 .filter_map(|info| info.presentation_time)
889 .collect();
890 let average_interval: i64 =
891 times.as_slice().windows(2).map(|slice| slice[1] - slice[0]).sum::<i64>()
892 / present_intervals as i64;
893 self.present_interval = average_interval;
894 } else {
895 self.present_interval = DEFAULT_PRESENT_INTERVAL;
896 }
897 self.future_presentation_times.splice(
898 ..,
899 future_presentation_infos.iter().map(|t| PresentationTime {
900 presentation_time: t.presentation_time.expect("presentation_time"),
901 latch_point: t.latch_point.expect("latch_point"),
902 }),
903 );
904
905 self.retry_missed_frame();
907 }
908}