1use api::units::*;
6use api::{ColorF, ImageBufferKind, ImageRendering, PremultipliedColorF};
7use crate::batch::BatchTextures;
8use crate::composite::{
9 CompositeState, CompositeSurfaceFormat, CompositeTileSurface, CompositorConfig,
10 CompositorInputLayer, CompositorSurfaceUsage, CompositorSurfaceTransform,
11 CompositeRoundedCorner, NativeTileId, ResolvedExternalSurface,
12 ResolvedExternalSurfaceColorData, ClipRadius, CompositeFeatures, CompositorKind, TileKind,
13};
14use crate::frame_builder::Frame;
15use crate::{CompositorInputConfig, PictureCacheDebugInfo, debug_colors};
16use api::{ClipMode, DebugFlags};
17use std::collections::HashSet;
18use std::mem;
19use crate::debug_item::DebugItem;
20use crate::segment::EdgeMask;
21use crate::device::DrawTarget;
22use crate::gpu_types::{CompositeInstance, ZBufferId};
23use crate::internal_types::{FastHashMap, TextureSource};
24use crate::picture::ResolvedSurfaceTexture;
25use super::RenderResults;
26use crate::profiler::{self};
27use crate::rectangle_occlusion as occlusion;
28use crate::renderer::{
29 GPU_SAMPLER_TAG_OPAQUE, GPU_SAMPLER_TAG_TRANSPARENT, GPU_TAG_COMPOSITE, PartialPresentMode,
30};
31use crate::renderer::{FramebufferKind, Renderer, RendererStats, VertexArrayKind};
32use crate::segment::SegmentBuilder;
33use crate::tile_cache::TileId;
34use euclid::{Scale, Transform3D, default};
35
36#[derive(Debug, Copy, Clone)]
37pub(super) struct OcclusionItemKey {
38 pub tile_index: usize,
39 pub needs_mask: bool,
40}
41
42pub(super) struct SwapChainLayer {
43 pub occlusion: occlusion::FrontToBackBuilder<OcclusionItemKey>,
44}
45
46pub(super) struct CompositeTileState {
47 pub local_rect: PictureRect,
48 pub local_valid_rect: PictureRect,
49 pub device_clip_rect: DeviceRect,
50 pub z_id: ZBufferId,
51 pub device_tile_box: DeviceRect,
52 pub visible_rects: Vec<DeviceRect>,
53}
54
55impl CompositeTileState {
56 pub fn same_state(&self, other: &CompositeTileState) -> bool {
57 self.local_rect == other.local_rect
58 && self.local_valid_rect == other.local_valid_rect
59 && self.device_clip_rect == other.device_clip_rect
60 && self.z_id == other.z_id
61 && self.device_tile_box == other.device_tile_box
62 }
63}
64
65pub(super) struct LayerCompositorFrameState {
66 pub tile_states: FastHashMap<TileId, CompositeTileState>,
67 pub rects_without_id: Vec<DeviceRect>,
68}
69
70impl Renderer {
71 fn update_external_native_surfaces(
73 &mut self,
74 external_surfaces: &[ResolvedExternalSurface],
75 results: &mut RenderResults,
76 ) {
77 if external_surfaces.is_empty() {
78 return;
79 }
80
81 let opaque_sampler = self.gpu_profiler.start_sampler(GPU_SAMPLER_TAG_OPAQUE);
82
83 self.device.disable_depth();
84 self.set_blend(false, FramebufferKind::Main);
85
86 for surface in external_surfaces {
87 let (native_surface_id, surface_size) = match surface.update_params {
89 Some(params) => params,
90 None => continue,
91 };
92
93 let surface_rect = surface_size.into();
96
97 let surface_info = self.compositor_config
99 .compositor()
100 .unwrap()
101 .bind(
102 &mut self.device,
103 NativeTileId {
104 surface_id: native_surface_id,
105 x: 0,
106 y: 0,
107 },
108 surface_rect,
109 surface_rect,
110 );
111
112 let draw_target = DrawTarget::NativeSurface {
114 offset: surface_info.origin,
115 external_fbo_id: surface_info.fbo_id,
116 dimensions: surface_size,
117 };
118 self.device.bind_draw_target(draw_target);
119
120 let projection = Transform3D::ortho(
121 0.0,
122 surface_size.width as f32,
123 0.0,
124 surface_size.height as f32,
125 self.device.ortho_near_plane(),
126 self.device.ortho_far_plane(),
127 );
128
129 let ( textures, instance ) = match surface.color_data {
130 ResolvedExternalSurfaceColorData::Yuv{
131 ref planes, color_space, format, channel_bit_depth, .. } => {
132
133 let textures = BatchTextures::composite_yuv(
134 planes[0].texture,
135 planes[1].texture,
136 planes[2].texture,
137 );
138
139 let uv_rects = [
145 self.texture_resolver.get_uv_rect(&textures.input.colors[0], planes[0].uv_rect),
146 self.texture_resolver.get_uv_rect(&textures.input.colors[1], planes[1].uv_rect),
147 self.texture_resolver.get_uv_rect(&textures.input.colors[2], planes[2].uv_rect),
148 ];
149
150 let instance = CompositeInstance::new_yuv(
151 surface_rect.to_f32(),
152 surface_rect.to_f32(),
153 color_space,
156 format,
157 channel_bit_depth,
158 uv_rects,
159 (false, false),
160 None,
161 );
162
163 self.shaders
165 .borrow_mut()
166 .get_composite_shader(
167 CompositeSurfaceFormat::Yuv,
168 surface.image_buffer_kind,
169 instance.get_yuv_features(),
170 ).bind(
171 &mut self.device,
172 &projection,
173 None,
174 &mut self.renderer_errors,
175 &mut self.profile,
176 &mut self.command_log,
177 );
178
179 ( textures, instance )
180 },
181 ResolvedExternalSurfaceColorData::Rgb{ ref plane, .. } => {
182 let textures = BatchTextures::composite_rgb(plane.texture);
183 let uv_rect = self.texture_resolver.get_uv_rect(&textures.input.colors[0], plane.uv_rect);
184 let instance = CompositeInstance::new_rgb(
185 surface_rect.to_f32(),
186 surface_rect.to_f32(),
187 PremultipliedColorF::WHITE,
188 uv_rect,
189 plane.texture.uses_normalized_uvs(),
190 (false, false),
191 None,
192 );
193 let features = instance.get_rgb_features();
194
195 self.shaders
196 .borrow_mut()
197 .get_composite_shader(
198 CompositeSurfaceFormat::Rgba,
199 surface.image_buffer_kind,
200 features,
201 ).bind(
202 &mut self.device,
203 &projection,
204 None,
205 &mut self.renderer_errors,
206 &mut self.profile,
207 &mut self.command_log,
208 );
209
210 ( textures, instance )
211 },
212 };
213
214 self.draw_instanced_batch(
215 &[instance],
216 VertexArrayKind::Composite,
217 &textures,
218 &mut results.stats,
219 );
220
221 self.compositor_config
222 .compositor()
223 .unwrap()
224 .unbind(&mut self.device);
225 }
226
227 self.gpu_profiler.finish_sampler(opaque_sampler);
228 }
229
230 fn draw_tile_list<'a, I: Iterator<Item = &'a occlusion::Item<OcclusionItemKey>>>(
232 &mut self,
233 tiles_iter: I,
234 composite_state: &CompositeState,
235 external_surfaces: &[ResolvedExternalSurface],
236 projection: &default::Transform3D<f32>,
237 stats: &mut RendererStats,
238 ) {
239 let mut current_shader_params = (
240 CompositeSurfaceFormat::Rgba,
241 ImageBufferKind::Texture2D,
242 CompositeFeatures::empty(),
243 None,
244 );
245 let mut current_textures = BatchTextures::empty();
246 let mut instances = Vec::new();
247
248 for item in tiles_iter {
249 let tile = &composite_state.tiles[item.key.tile_index];
250
251 let clip_rect = item.rectangle;
252 let tile_rect = composite_state.get_device_rect(&tile.local_rect, tile.transform_index);
253 let transform = composite_state.get_device_transform(tile.transform_index);
254 let flip = (transform.scale.x < 0.0, transform.scale.y < 0.0);
255
256 let clip = if item.key.needs_mask {
257 tile.clip_index.map(|index| {
258 composite_state.get_compositor_clip(index)
259 })
260 } else {
261 None
262 };
263
264 let (instance, textures, shader_params) = match tile.surface {
266 CompositeTileSurface::Color { color } => {
267 let dummy = TextureSource::Dummy;
268 let image_buffer_kind = dummy.image_buffer_kind();
269 let instance = CompositeInstance::new(
270 tile_rect,
271 clip_rect,
272 color.premultiplied(),
273 flip,
274 clip,
275 );
276 let features = instance.get_rgb_features();
277 (
278 instance,
279 BatchTextures::composite_rgb(dummy),
280 (CompositeSurfaceFormat::Rgba, image_buffer_kind, features, None),
281 )
282 }
283 CompositeTileSurface::Texture { surface: ResolvedSurfaceTexture::TextureCache { texture } } => {
284 let instance = CompositeInstance::new(
285 tile_rect,
286 clip_rect,
287 PremultipliedColorF::WHITE,
288 flip,
289 clip,
290 );
291 let features = instance.get_rgb_features();
292 (
293 instance,
294 BatchTextures::composite_rgb(texture),
295 (
296 CompositeSurfaceFormat::Rgba,
297 ImageBufferKind::Texture2D,
298 features,
299 None,
300 ),
301 )
302 }
303 CompositeTileSurface::ExternalSurface { external_surface_index } => {
304 let surface = &external_surfaces[external_surface_index.0];
305
306 match surface.color_data {
307 ResolvedExternalSurfaceColorData::Yuv{ ref planes, color_space, format, channel_bit_depth, .. } => {
308 let textures = BatchTextures::composite_yuv(
309 planes[0].texture,
310 planes[1].texture,
311 planes[2].texture,
312 );
313
314 let uv_rects = [
320 self.texture_resolver.get_uv_rect(&textures.input.colors[0], planes[0].uv_rect),
321 self.texture_resolver.get_uv_rect(&textures.input.colors[1], planes[1].uv_rect),
322 self.texture_resolver.get_uv_rect(&textures.input.colors[2], planes[2].uv_rect),
323 ];
324
325 let instance = CompositeInstance::new_yuv(
326 tile_rect,
327 clip_rect,
328 color_space,
329 format,
330 channel_bit_depth,
331 uv_rects,
332 flip,
333 clip,
334 );
335 let features = instance.get_yuv_features();
336
337 (
338 instance,
339 textures,
340 (
341 CompositeSurfaceFormat::Yuv,
342 surface.image_buffer_kind,
343 features,
344 None
345 ),
346 )
347 },
348 ResolvedExternalSurfaceColorData::Rgb { ref plane, .. } => {
349 let uv_rect = self.texture_resolver.get_uv_rect(&plane.texture, plane.uv_rect);
350 let instance = CompositeInstance::new_rgb(
351 tile_rect,
352 clip_rect,
353 PremultipliedColorF::WHITE,
354 uv_rect,
355 plane.texture.uses_normalized_uvs(),
356 flip,
357 clip,
358 );
359 let features = instance.get_rgb_features();
360 (
361 instance,
362 BatchTextures::composite_rgb(plane.texture),
363 (
364 CompositeSurfaceFormat::Rgba,
365 surface.image_buffer_kind,
366 features,
367 Some(self.texture_resolver.get_texture_size(&plane.texture).to_f32()),
368 ),
369 )
370 },
371 }
372 }
373 CompositeTileSurface::Texture { surface: ResolvedSurfaceTexture::Native { .. } } => {
374 unreachable!("bug: found native surface in simple composite path");
375 }
376 };
377
378 let flush_batch = !current_textures.is_compatible_with(&textures) ||
380 shader_params != current_shader_params;
381
382 if flush_batch && !instances.is_empty() {
383 self.shaders
384 .borrow_mut()
385 .get_composite_shader(
386 current_shader_params.0,
387 current_shader_params.1,
388 current_shader_params.2,
389 ).bind(
390 &mut self.device,
391 projection,
392 current_shader_params.3,
393 &mut self.renderer_errors,
394 &mut self.profile,
395 &mut self.command_log,
396 );
397 self.draw_instanced_batch(
398 &instances,
399 VertexArrayKind::Composite,
400 ¤t_textures,
401 stats,
402 );
403
404 instances.clear();
405 }
406 current_shader_params = shader_params;
407 current_textures = textures;
408
409 instances.push(instance);
411 }
412
413 if !instances.is_empty() {
415 self.shaders
416 .borrow_mut()
417 .get_composite_shader(
418 current_shader_params.0,
419 current_shader_params.1,
420 current_shader_params.2,
421 ).bind(
422 &mut self.device,
423 projection,
424 current_shader_params.3,
425 &mut self.renderer_errors,
426 &mut self.profile,
427 &mut self.command_log,
428 );
429 self.draw_instanced_batch(
430 &instances,
431 VertexArrayKind::Composite,
432 ¤t_textures,
433 stats,
434 );
435 }
436 }
437
438 fn composite_pass(
441 &mut self,
442 composite_state: &CompositeState,
443 draw_target: DrawTarget,
444 clear_color: ColorF,
445 projection: &default::Transform3D<f32>,
446 results: &mut RenderResults,
447 partial_present_mode: Option<PartialPresentMode>,
448 layer: &SwapChainLayer,
449 ) {
450 self.device.bind_draw_target(draw_target);
451 self.device.disable_depth_write();
452 self.device.disable_depth();
453
454 if let Some(partial_present) = self.compositor_config.partial_present() {
460 if let Some(PartialPresentMode::Single { dirty_rect }) = partial_present_mode {
461 partial_present.set_buffer_damage_region(&[dirty_rect.to_i32()]);
462 }
463 }
464
465 let clear_color = Some(clear_color.to_array());
467
468 match partial_present_mode {
469 Some(PartialPresentMode::Single { dirty_rect }) => {
470 if !dirty_rect.is_empty() && layer.occlusion.test(&dirty_rect) {
475 self.device.clear_target(clear_color,
477 None,
478 Some(draw_target.to_framebuffer_rect(dirty_rect.to_i32())));
479 }
480 }
481 None => {
482 self.device.clear_target(clear_color,
484 None,
485 None);
486 }
487 }
488
489 let opaque_items = layer.occlusion.opaque_items();
491 if !opaque_items.is_empty() {
492 let opaque_sampler = self.gpu_profiler.start_sampler(GPU_SAMPLER_TAG_OPAQUE);
493 self.set_blend(false, FramebufferKind::Main);
494 self.draw_tile_list(
495 opaque_items.iter(),
496 &composite_state,
497 &composite_state.external_surfaces,
498 projection,
499 &mut results.stats,
500 );
501 self.gpu_profiler.finish_sampler(opaque_sampler);
502 }
503
504 let alpha_items = layer.occlusion.alpha_items();
506 if !alpha_items.is_empty() {
507 let transparent_sampler = self.gpu_profiler.start_sampler(GPU_SAMPLER_TAG_TRANSPARENT);
508 self.set_blend(true, FramebufferKind::Main);
509 self.set_blend_mode_premultiplied_alpha(FramebufferKind::Main);
510 self.draw_tile_list(
511 alpha_items.iter().rev(),
512 &composite_state,
513 &composite_state.external_surfaces,
514 projection,
515 &mut results.stats,
516 );
517 self.gpu_profiler.finish_sampler(transparent_sampler);
518 }
519 }
520
521 fn composite_simple(
526 &mut self,
527 composite_state: &CompositeState,
528 frame_device_size: DeviceIntSize,
529 fb_draw_target: DrawTarget,
530 projection: &default::Transform3D<f32>,
531 results: &mut RenderResults,
532 partial_present_mode: Option<PartialPresentMode>,
533 device_size: DeviceIntSize,
534 ) {
535 let _gm = self.gpu_profiler.start_marker("framebuffer");
536 let _timer = self.gpu_profiler.start_timer(GPU_TAG_COMPOSITE);
537
538 let num_tiles = composite_state.tiles.len();
539 self.profile.set(profiler::PICTURE_TILES, num_tiles);
540
541 let (window_is_opaque, enable_screenshot) = match self.compositor_config.layer_compositor() {
542 Some(ref compositor) => {
543 let props = compositor.get_window_properties();
544 (props.is_opaque, props.enable_screenshot)
545 }
546 None => (true, true)
547 };
548
549 let mut input_layers: Vec<CompositorInputLayer> = Vec::new();
550 let mut swapchain_layers = Vec::new();
551 let cap = composite_state.tiles.len();
552 let mut segment_builder = SegmentBuilder::new();
553 let mut tile_index_to_layer_index = vec![None; composite_state.tiles.len()];
554 let mut full_render_occlusion = occlusion::FrontToBackBuilder::with_capacity(cap, cap);
555 let mut layer_compositor_frame_state = LayerCompositorFrameState{
556 tile_states: FastHashMap::default(),
557 rects_without_id: Vec::new(),
558 };
559
560 if self.debug_overlay_state.is_enabled {
564 self.debug_overlay_state.layer_index = input_layers.len();
565
566 input_layers.push(CompositorInputLayer {
567 usage: CompositorSurfaceUsage::DebugOverlay,
568 is_opaque: false,
569 offset: DeviceIntPoint::zero(),
570 clip_rect: device_size.into(),
571 rounded_clip_rect: device_size.into(),
572 rounded_clip_radii: ClipRadius::EMPTY,
573 });
574
575 swapchain_layers.push(SwapChainLayer {
576 occlusion: occlusion::FrontToBackBuilder::with_capacity(cap, cap),
577 });
578 }
579
580 for (idx, tile) in composite_state.tiles.iter().enumerate() {
583 let device_tile_box = composite_state.get_device_rect(
584 &tile.local_rect,
585 tile.transform_index
586 );
587
588 if let Some(ref _compositor) = self.compositor_config.layer_compositor() {
589 match tile.tile_id {
590 Some(tile_id) => {
591 layer_compositor_frame_state.
592 tile_states
593 .insert(
594 tile_id,
595 CompositeTileState {
596 local_rect: tile.local_rect,
597 local_valid_rect: tile.local_valid_rect,
598 device_clip_rect: tile.device_clip_rect,
599 z_id: tile.z_id,
600 device_tile_box: device_tile_box,
601 visible_rects: Vec::new(),
602 },
603 );
604 }
605 None => {}
606 }
607 }
608
609 let device_valid_rect = composite_state
611 .get_device_rect(&tile.local_valid_rect, tile.transform_index);
612
613 let rect = device_tile_box
614 .intersection_unchecked(&tile.device_clip_rect)
615 .intersection_unchecked(&device_valid_rect);
616
617 if rect.is_empty() {
618 continue;
619 }
620
621 let mut disable_external_composite = enable_screenshot;
622 if let CompositeTileSurface::ExternalSurface { .. } = tile.surface {
623 let transformed_rect = composite_state.get_device_rect(
624 &tile.local_rect,
625 tile.transform_index
626 );
627 if let None = transformed_rect.try_cast::<i16>() {
628 disable_external_composite = true;
630 }
631 }
632
633 let usage = match tile.surface {
635 CompositeTileSurface::Texture { .. } |
636 CompositeTileSurface::Color { .. } => {
637 CompositorSurfaceUsage::Content
638 }
639 CompositeTileSurface::ExternalSurface { external_surface_index } => {
640 match (self.current_compositor_kind, disable_external_composite) {
641 (CompositorKind::Native { .. }, _) | (CompositorKind::Draw { .. }, _) => {
642 CompositorSurfaceUsage::Content
643 }
644 (CompositorKind::Layer { .. }, true) => {
645 CompositorSurfaceUsage::Content
646 }
647 (CompositorKind::Layer { .. }, false) => {
648 let surface = &composite_state.external_surfaces[external_surface_index.0];
649
650 match surface.external_image_id {
654 Some(external_image_id) => {
655 let image_key = match surface.color_data {
656 ResolvedExternalSurfaceColorData::Rgb { image_dependency, .. } => image_dependency.key,
657 ResolvedExternalSurfaceColorData::Yuv { image_dependencies, .. } => image_dependencies[0].key,
658 };
659
660 CompositorSurfaceUsage::External {
661 image_key,
662 external_image_id,
663 transform_index: tile.transform_index,
664 }
665 }
666 None => {
667 CompositorSurfaceUsage::Content
668 }
669 }
670 }
671 }
672 }
673 };
674
675 if let Some(ref _compositor) = self.compositor_config.layer_compositor() {
676 if let CompositeTileSurface::ExternalSurface { .. } = tile.surface {
677 assert!(tile.tile_id.is_none());
678 if let CompositorSurfaceUsage::Content = usage {
680 layer_compositor_frame_state.rects_without_id.push(rect);
681 }
682 } else {
683 assert!(tile.tile_id.is_some());
684 }
685 }
686
687 let new_layer_kind = match input_layers.last() {
689 Some(curr_layer) => {
690 match (curr_layer.usage, usage) {
691 (CompositorSurfaceUsage::Content, CompositorSurfaceUsage::Content) => None,
693 (CompositorSurfaceUsage::External { .. }, CompositorSurfaceUsage::Content) => Some(usage),
694
695 (CompositorSurfaceUsage::Content, CompositorSurfaceUsage::External { .. }) |
697 (CompositorSurfaceUsage::External { .. }, CompositorSurfaceUsage::External { .. }) => {
698 match self.compositor_config {
700 CompositorConfig::Draw { .. } | CompositorConfig::Native { .. } => None,
701 CompositorConfig::Layer { .. } => {
702 Some(usage)
703 }
704 }
705 }
706 (CompositorSurfaceUsage::DebugOverlay, _) => {
707 Some(usage)
708 }
709 (_, CompositorSurfaceUsage::DebugOverlay) => {
711 unreachable!();
712 }
713 }
714 }
715 None => {
716 Some(usage)
718 }
719 };
720
721 if let Some(new_layer_kind) = new_layer_kind {
722 let (offset, clip_rect, is_opaque, rounded_clip_rect, rounded_clip_radii) = match usage {
723 CompositorSurfaceUsage::Content => {
724 (
725 DeviceIntPoint::zero(),
726 device_size.into(),
727 false, device_size.into(),
729 ClipRadius::EMPTY,
730 )
731 }
732 CompositorSurfaceUsage::External { .. } => {
733 let rect = composite_state.get_device_rect(
734 &tile.local_rect,
735 tile.transform_index
736 );
737
738 let clip_rect = tile.device_clip_rect.to_i32();
739 let is_opaque = tile.kind != TileKind::Alpha;
740
741 if self.debug_flags.contains(DebugFlags::EXTERNAL_COMPOSITE_BORDERS) {
742 self.external_composite_debug_items.push(DebugItem::Rect {
743 outer_color: debug_colors::ORANGERED,
744 inner_color: ColorF { r: 0.0, g: 0.0, b: 0.0, a: 0.0 },
745 rect: tile.device_clip_rect,
746 thickness: 10,
747 });
748 }
749
750 let (rounded_clip_rect, rounded_clip_radii) = match tile.clip_index {
751 Some(clip_index) => {
752 let clip = composite_state.get_compositor_clip(clip_index);
753 let radius = ClipRadius {
754 top_left: clip.radius.top_left.width.round() as i32,
755 top_right: clip.radius.top_right.width.round() as i32,
756 bottom_left: clip.radius.bottom_left.width.round() as i32,
757 bottom_right: clip.radius.bottom_right.width.round() as i32,
758 };
759 (clip.rect.to_i32(), radius)
760 }
761 None => {
762 (clip_rect, ClipRadius::EMPTY)
763 }
764 };
765
766 (
767 rect.min.to_i32(),
768 clip_rect,
769 is_opaque,
770 rounded_clip_rect,
771 rounded_clip_radii,
772 )
773 }
774 CompositorSurfaceUsage::DebugOverlay => unreachable!(),
775 };
776
777 input_layers.push(CompositorInputLayer {
778 usage: new_layer_kind,
779 is_opaque,
780 offset,
781 clip_rect,
782 rounded_clip_rect,
783 rounded_clip_radii,
784 });
785
786 swapchain_layers.push(SwapChainLayer {
787 occlusion: occlusion::FrontToBackBuilder::with_capacity(cap, cap),
788 })
789 }
790 tile_index_to_layer_index[idx] = Some(input_layers.len() - 1);
791
792 let is_opaque = tile.kind == TileKind::Opaque;
795
796 match tile.clip_index {
797 Some(clip_index) => {
798 let clip = composite_state.get_compositor_clip(clip_index);
799
800 segment_builder.initialize(
802 rect.cast_unit(),
803 None,
804 rect.cast_unit(),
805 );
806 segment_builder.push_clip_rect(
807 clip.rect.cast_unit(),
808 Some(clip.radius),
809 ClipMode::Clip,
810 );
811 segment_builder.build(|segment| {
812 let key = OcclusionItemKey { tile_index: idx, needs_mask: segment.has_mask };
813
814 full_render_occlusion.add(
815 &segment.rect.cast_unit(),
816 is_opaque && !segment.has_mask,
817 key,
818 );
819 });
820 }
821 None => {
822 full_render_occlusion.add(&rect, is_opaque, OcclusionItemKey {
823 tile_index: idx,
824 needs_mask: false,
825 });
826 }
827 }
828 }
829
830 assert_eq!(swapchain_layers.len(), input_layers.len());
831
832 if window_is_opaque {
833 match input_layers.last_mut() {
834 Some(_layer) => {
835 }
842 None => {
843 input_layers.push(CompositorInputLayer {
847 usage: CompositorSurfaceUsage::Content,
848 is_opaque: true,
849 offset: DeviceIntPoint::zero(),
850 clip_rect: device_size.into(),
851 rounded_clip_rect: device_size.into(),
852 rounded_clip_radii: ClipRadius::EMPTY,
853 });
854
855 swapchain_layers.push(SwapChainLayer {
856 occlusion: occlusion::FrontToBackBuilder::with_capacity(cap, cap),
857 });
858 }
859 }
860 }
861
862 let mut full_render = self.debug_overlay_state.is_enabled;
863
864 if let Some(ref mut compositor) = self.compositor_config.layer_compositor() {
866 let input = CompositorInputConfig {
867 enable_screenshot,
868 layers: &input_layers,
869 };
870 full_render |= compositor.begin_frame(&input);
871 }
872
873 let mut partial_present_mode = if full_render {
875 None
876 } else {
877 partial_present_mode
878 };
879
880 assert_eq!(swapchain_layers.len(), input_layers.len());
881
882 if let Some(ref _compositor) = self.compositor_config.layer_compositor() {
884 for item in full_render_occlusion
886 .opaque_items()
887 .iter()
888 .chain(full_render_occlusion.alpha_items().iter()) {
889 let tile = &composite_state.tiles[item.key.tile_index];
890 match tile.tile_id {
891 Some(tile_id) => {
892 if let Some(tile_state) = layer_compositor_frame_state.tile_states.get_mut(&tile_id) {
893 tile_state.visible_rects.push(item.rectangle);
894 } else {
895 unreachable!();
896 }
897 }
898 None => {}
899 }
900 }
901
902 let can_use_partial_present =
903 !self.force_redraw && !full_render &&
904 self.layer_compositor_frame_state_in_prev_frame.is_some();
905
906 if can_use_partial_present {
907 let mut combined_dirty_rect = DeviceRect::zero();
908
909 for tile in composite_state.tiles.iter() {
910 if tile.tile_id.is_none() {
911 match tile.surface {
912 CompositeTileSurface::ExternalSurface { .. } => {}
913 CompositeTileSurface::Texture { .. } |
914 CompositeTileSurface::Color { .. } => {
915 unreachable!();
916 },
917 }
918 continue;
919 }
920
921 assert!(tile.tile_id.is_some());
922
923 let tiles_exists_in_prev_frame =
924 self.layer_compositor_frame_state_in_prev_frame
925 .as_ref()
926 .unwrap()
927 .tile_states
928 .contains_key(&tile.tile_id.unwrap());
929 let tile_id = tile.tile_id.unwrap();
930 let tile_state = layer_compositor_frame_state.tile_states.get(&tile_id).unwrap();
931
932 if tiles_exists_in_prev_frame {
933 let prev_tile_state = self.layer_compositor_frame_state_in_prev_frame
934 .as_ref()
935 .unwrap()
936 .tile_states
937 .get(&tile_id)
938 .unwrap();
939
940 if tile_state.same_state(prev_tile_state) {
941 let dirty_rect = composite_state.get_device_rect(
944 &tile.local_dirty_rect,
945 tile.transform_index,
946 );
947 for rect in tile_state.visible_rects.iter() {
948 let visible_dirty_rect = rect.intersection(&dirty_rect);
949 if visible_dirty_rect.is_some() {
950 combined_dirty_rect = combined_dirty_rect.union(&visible_dirty_rect.unwrap());
951 }
952 }
953 } else {
954 for rect in tile_state.visible_rects
957 .iter()
958 .chain(prev_tile_state.visible_rects.iter()) {
959 combined_dirty_rect = combined_dirty_rect.union(&rect);
960 }
961 }
962 } else {
963 for rect in &tile_state.visible_rects {
965 combined_dirty_rect = combined_dirty_rect.union(&rect);
966 }
967 }
968 }
969
970 for (tile_id, tile_state) in self.layer_compositor_frame_state_in_prev_frame
972 .as_ref()
973 .unwrap()
974 .tile_states
975 .iter() {
976 if !layer_compositor_frame_state.tile_states.contains_key(&tile_id) {
977 for rect in tile_state.visible_rects.iter() {
978 combined_dirty_rect = combined_dirty_rect.union(&rect);
979 }
980 }
981 }
982
983 for rect in layer_compositor_frame_state
985 .rects_without_id
986 .iter()
987 .chain(self.layer_compositor_frame_state_in_prev_frame.as_ref().unwrap().rects_without_id.iter()) {
988 combined_dirty_rect = combined_dirty_rect.union(&rect);
989 }
990
991 let device_rect = DeviceRect::from_size(device_size.to_f32());
992 let clipped_dirty_rect = combined_dirty_rect.intersection_unchecked(&device_rect);
993
994 partial_present_mode = Some(PartialPresentMode::Single {
995 dirty_rect: clipped_dirty_rect,
996 });
997 } else {
998 partial_present_mode = None;
999 }
1000
1001 self.layer_compositor_frame_state_in_prev_frame = Some(layer_compositor_frame_state);
1002 }
1003
1004 let mut opaque_rounded_corners: HashSet<CompositeRoundedCorner> = HashSet::new();
1007
1008 for (idx, tile) in composite_state.tiles.iter().enumerate() {
1011 let device_tile_box = composite_state.get_device_rect(
1012 &tile.local_rect,
1013 tile.transform_index
1014 );
1015
1016 let partial_clip_rect = match partial_present_mode {
1019 Some(PartialPresentMode::Single { dirty_rect }) => dirty_rect,
1020 None => device_tile_box,
1021 };
1022
1023 let device_valid_rect = composite_state
1025 .get_device_rect(&tile.local_valid_rect, tile.transform_index);
1026
1027 let rect = device_tile_box
1028 .intersection_unchecked(&tile.device_clip_rect)
1029 .intersection_unchecked(&partial_clip_rect)
1030 .intersection_unchecked(&device_valid_rect);
1031
1032 if rect.is_empty() {
1033 continue;
1034 }
1035
1036 let layer_index = match tile_index_to_layer_index[idx] {
1037 None => {
1038 error!("rect {:?} should have valid layer index", rect);
1040 continue;
1041 }
1042 Some(layer_index) => layer_index,
1043 };
1044
1045 let layer = &mut swapchain_layers[layer_index];
1047
1048 let is_opaque = tile.kind == TileKind::Opaque;
1049
1050 match tile.clip_index {
1051 Some(clip_index) => {
1052 let clip = composite_state.get_compositor_clip(clip_index);
1053
1054 segment_builder.initialize(
1056 rect.cast_unit(),
1057 None,
1058 rect.cast_unit(),
1059 );
1060 segment_builder.push_clip_rect(
1061 clip.rect.cast_unit(),
1062 Some(clip.radius),
1063 ClipMode::Clip,
1064 );
1065 segment_builder.build(|segment| {
1066 let key = OcclusionItemKey { tile_index: idx, needs_mask: segment.has_mask };
1067
1068 let radius = if segment.edge_flags ==
1069 EdgeMask::TOP | EdgeMask::LEFT &&
1070 !clip.radius.top_left.is_empty() {
1071 Some(clip.radius.top_left)
1072 } else if segment.edge_flags ==
1073 EdgeMask::TOP | EdgeMask::RIGHT &&
1074 !clip.radius.top_right.is_empty() {
1075 Some(clip.radius.top_right)
1076 } else if segment.edge_flags ==
1077 EdgeMask::BOTTOM | EdgeMask::LEFT &&
1078 !clip.radius.bottom_left.is_empty() {
1079 Some(clip.radius.bottom_left)
1080 } else if segment.edge_flags ==
1081 EdgeMask::BOTTOM | EdgeMask::RIGHT &&
1082 !clip.radius.bottom_right.is_empty() {
1083 Some(clip.radius.bottom_right)
1084 } else {
1085 None
1086 };
1087
1088 if let Some(radius) = radius {
1089 let rounded_corner = CompositeRoundedCorner {
1090 rect: segment.rect.cast_unit(),
1091 radius: radius,
1092 edge_flags: segment.edge_flags,
1093 };
1094
1095 if opaque_rounded_corners.contains(&rounded_corner) {
1097 return;
1098 }
1099
1100 if is_opaque {
1101 opaque_rounded_corners.insert(rounded_corner);
1102 }
1103 }
1104
1105 layer.occlusion.add(
1106 &segment.rect.cast_unit(),
1107 is_opaque && !segment.has_mask,
1108 key,
1109 );
1110 });
1111 }
1112 None => {
1113 layer.occlusion.add(&rect, is_opaque, OcclusionItemKey {
1114 tile_index: idx,
1115 needs_mask: false,
1116 });
1117 }
1118 }
1119 }
1120
1121 assert_eq!(swapchain_layers.len(), input_layers.len());
1122 let mut content_clear_color = Some(self.clear_color);
1123
1124 for (layer_index, (layer, swapchain_layer)) in input_layers.iter().zip(swapchain_layers.iter()).enumerate() {
1125 self.device.reset_state();
1126
1127 match layer.usage {
1129 CompositorSurfaceUsage::Content => {}
1130 CompositorSurfaceUsage::External { .. } | CompositorSurfaceUsage::DebugOverlay => {
1131 continue;
1132 }
1133 }
1134
1135 let clear_color = content_clear_color.take().unwrap_or(ColorF::TRANSPARENT);
1137
1138 if let Some(ref mut _compositor) = self.compositor_config.layer_compositor() {
1139 if let Some(PartialPresentMode::Single { dirty_rect }) = partial_present_mode {
1140 let device_rect = DeviceRect::from_size(device_size.to_f32());
1141 let clipped_dirty_rect = dirty_rect.intersection_unchecked(&device_rect);
1142 if clipped_dirty_rect.is_empty() {
1143 continue;
1144 }
1145 }
1146 }
1147
1148 let draw_target = match self.compositor_config {
1149 CompositorConfig::Layer { ref mut compositor } => {
1150 match partial_present_mode {
1151 Some(PartialPresentMode::Single { dirty_rect }) => {
1152 compositor.bind_layer(layer_index, &[dirty_rect.to_i32()]);
1153 }
1154 None => {
1155 compositor.bind_layer(layer_index, &[]);
1156 }
1157 };
1158
1159 DrawTarget::NativeSurface {
1160 offset: -layer.offset,
1161 external_fbo_id: 0,
1162 dimensions: frame_device_size,
1163 }
1164 }
1165 CompositorConfig::Draw { .. } | CompositorConfig::Native { .. } => {
1167 fb_draw_target
1168 }
1169 };
1170
1171 self.composite_pass(
1175 composite_state,
1176 draw_target,
1177 clear_color,
1178 projection,
1179 results,
1180 partial_present_mode,
1181 swapchain_layer,
1182 );
1183
1184 if let Some(ref mut compositor) = self.compositor_config.layer_compositor() {
1185 match partial_present_mode {
1186 Some(PartialPresentMode::Single { dirty_rect }) => {
1187 compositor.present_layer(layer_index, &[dirty_rect.to_i32()]);
1188 }
1189 None => {
1190 compositor.present_layer(layer_index, &[]);
1191 }
1192 };
1193 }
1194 }
1195
1196 if let Some(ref mut compositor) = self.compositor_config.layer_compositor() {
1198 for (layer_index, layer) in input_layers.iter().enumerate() {
1199 let transform = match layer.usage {
1202 CompositorSurfaceUsage::Content => CompositorSurfaceTransform::identity(),
1203 CompositorSurfaceUsage::External { transform_index, .. } => composite_state.get_compositor_transform(transform_index),
1204 CompositorSurfaceUsage::DebugOverlay => CompositorSurfaceTransform::identity(),
1205 };
1206
1207 compositor.add_surface(
1208 layer_index,
1209 transform,
1210 layer.clip_rect,
1211 ImageRendering::Auto,
1212 layer.rounded_clip_rect,
1213 layer.rounded_clip_radii,
1214 );
1215 }
1216 }
1217 }
1218
1219 pub(super) fn composite_frame(
1220 &mut self,
1221 frame: &mut Frame,
1222 device_size: Option<DeviceIntSize>,
1223 results: &mut RenderResults,
1224 present_mode: Option<PartialPresentMode>,
1225 ) {
1226 profile_scope!("main target");
1227 if let Some(device_size) = device_size {
1228 if let Some(history) = &mut self.command_log {
1229 history.begin_render_target("Window", device_size);
1230 }
1231
1232 results.stats.color_target_count += 1;
1233 results.picture_cache_debug = mem::replace(
1234 &mut frame.composite_state.picture_cache_debug,
1235 PictureCacheDebugInfo::new(),
1236 );
1237 results.did_rasterize_any_tile = frame.composite_state.did_rasterize_any_tile;
1238
1239 let size = frame.device_rect.size().to_f32();
1240 let surface_origin_is_top_left = self.device.surface_origin_is_top_left();
1241 let (bottom, top) = if surface_origin_is_top_left {
1242 (0.0, size.height)
1243 } else {
1244 (size.height, 0.0)
1245 };
1246
1247 let projection = Transform3D::ortho(
1248 0.0,
1249 size.width,
1250 bottom,
1251 top,
1252 self.device.ortho_near_plane(),
1253 self.device.ortho_far_plane(),
1254 );
1255
1256 let fb_scale = Scale::<_, _, FramebufferPixel>::new(1i32);
1257 let mut fb_rect = frame.device_rect * fb_scale;
1258
1259 if !surface_origin_is_top_left {
1260 let h = fb_rect.height();
1261 fb_rect.min.y = device_size.height - fb_rect.max.y;
1262 fb_rect.max.y = fb_rect.min.y + h;
1263 }
1264
1265 let draw_target = DrawTarget::Default {
1266 rect: fb_rect,
1267 total_size: device_size * fb_scale,
1268 surface_origin_is_top_left,
1269 };
1270
1271 match self.current_compositor_kind {
1274 CompositorKind::Native { .. } => {
1275 self.update_external_native_surfaces(
1279 &frame.composite_state.external_surfaces,
1280 results,
1281 );
1282 }
1283 CompositorKind::Draw { .. } | CompositorKind::Layer { .. } => {
1284 self.composite_simple(
1285 &frame.composite_state,
1286 frame.device_rect.size(),
1287 draw_target,
1288 &projection,
1289 results,
1290 present_mode,
1291 device_size,
1292 );
1293 }
1294 }
1295 self.force_redraw = false;
1297 } else {
1298 self.force_redraw = true;
1301 }
1302 }
1303
1304 pub(super) fn calculate_dirty_rects(
1308 &mut self,
1309 buffer_age: usize,
1310 composite_state: &CompositeState,
1311 draw_target_dimensions: DeviceIntSize,
1312 results: &mut RenderResults,
1313 ) -> Option<PartialPresentMode> {
1314 if let Some(ref _compositor) = self.compositor_config.layer_compositor() {
1315 return None;
1317 }
1318
1319 let mut partial_present_mode = None;
1320
1321 let (max_partial_present_rects, draw_previous_partial_present_regions) =
1322 match self.current_compositor_kind {
1323 CompositorKind::Native { .. } => {
1324 (1, false)
1329 }
1330 CompositorKind::Draw {
1331 draw_previous_partial_present_regions,
1332 max_partial_present_rects,
1333 } => (
1334 max_partial_present_rects,
1335 draw_previous_partial_present_regions,
1336 ),
1337 CompositorKind::Layer { .. } => {
1338 unreachable!();
1339 }
1340 };
1341
1342 if max_partial_present_rects > 0 {
1343 let prev_frames_damage_rect = if let Some(..) = self.compositor_config.partial_present()
1344 {
1345 self.buffer_damage_tracker
1346 .get_damage_rect(buffer_age)
1347 .or_else(|| Some(DeviceRect::from_size(draw_target_dimensions.to_f32())))
1348 } else {
1349 None
1350 };
1351
1352 let can_use_partial_present = composite_state.dirty_rects_are_valid
1353 && !self.force_redraw
1354 && !(prev_frames_damage_rect.is_none() && draw_previous_partial_present_regions)
1355 && !self.debug_overlay_state.is_enabled;
1356
1357 if can_use_partial_present {
1358 let mut combined_dirty_rect = DeviceRect::zero();
1359 let fb_rect = DeviceRect::from_size(draw_target_dimensions.to_f32());
1360
1361 for tile in &composite_state.tiles {
1364 let dirty_rect = composite_state
1365 .get_device_rect(&tile.local_dirty_rect, tile.transform_index);
1366
1367 if let Some(dirty_rect) = dirty_rect.intersection(&fb_rect) {
1372 combined_dirty_rect = combined_dirty_rect.union(&dirty_rect);
1373 }
1374 }
1375
1376 let combined_dirty_rect = combined_dirty_rect.round();
1377 let combined_dirty_rect_i32 = combined_dirty_rect.to_i32();
1378 if !combined_dirty_rect.is_empty() {
1381 results.dirty_rects.push(combined_dirty_rect_i32);
1382 }
1383
1384 if draw_previous_partial_present_regions {
1386 self.buffer_damage_tracker
1387 .push_dirty_rect(&combined_dirty_rect);
1388 }
1389
1390 let total_dirty_rect = if draw_previous_partial_present_regions {
1396 combined_dirty_rect.union(&prev_frames_damage_rect.unwrap())
1397 } else {
1398 combined_dirty_rect
1399 };
1400
1401 partial_present_mode = Some(PartialPresentMode::Single {
1402 dirty_rect: total_dirty_rect,
1403 });
1404 } else {
1405 let fb_rect = DeviceIntRect::from_size(draw_target_dimensions);
1408 results.dirty_rects.push(fb_rect);
1409
1410 if draw_previous_partial_present_regions {
1411 self.buffer_damage_tracker
1412 .push_dirty_rect(&fb_rect.to_f32());
1413 }
1414 }
1415 }
1416
1417 partial_present_mode
1418 }
1419}