Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  composite.rs

  Sprache: Rust
 

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */


use api::units::*;
use api::{ColorF, ImageBufferKind, ImageRendering, PremultipliedColorF};
use crate::batch::BatchTextures;
use crate::composite::{
    CompositeState, CompositeSurfaceFormat, CompositeTileSurface, CompositorConfig,
    CompositorInputLayer, CompositorSurfaceUsage, CompositorSurfaceTransform,
    CompositeRoundedCorner, NativeTileId, ResolvedExternalSurface,
    ResolvedExternalSurfaceColorData, ClipRadius, CompositeFeatures, CompositorKind, TileKind,
};
use crate::frame_builder::Frame;
use crate::{CompositorInputConfig, PictureCacheDebugInfo, debug_colors};
use api::{ClipMode, DebugFlags};
use std::collections::HashSet;
use std::mem;
use crate::debug_item::DebugItem;
use crate::segment::EdgeMask;
use crate::device::DrawTarget;
use crate::gpu_types::{CompositeInstance, ZBufferId};
use crate::internal_types::{FastHashMap, TextureSource};
use crate::picture::ResolvedSurfaceTexture;
use super::RenderResults;
use crate::profiler::{self};
use crate::rectangle_occlusion as occlusion;
use crate::renderer::{
    GPU_SAMPLER_TAG_OPAQUE, GPU_SAMPLER_TAG_TRANSPARENT, GPU_TAG_COMPOSITE, PartialPresentMode,
};
use crate::renderer::{FramebufferKind, Renderer, RendererStats, VertexArrayKind};
use crate::segment::SegmentBuilder;
use crate::tile_cache::TileId;
use euclid::{Scale, Transform3D, default};

#[derive(Debug, Copy, Clone)]
pub(superstruct OcclusionItemKey {
    pub tile_index: usize,
    pub needs_mask: bool,
}

pub(superstruct SwapChainLayer {
    pub occlusion: occlusion::FrontToBackBuilder<OcclusionItemKey>,
}

pub(superstruct CompositeTileState {
    pub local_rect: PictureRect,
    pub local_valid_rect: PictureRect,
    pub device_clip_rect: DeviceRect,
    pub z_id: ZBufferId,
    pub device_tile_box: DeviceRect,
    pub visible_rects: Vec<DeviceRect>,
}

impl CompositeTileState {
    pub fn same_state(&self, other: &CompositeTileState) -> bool {
        self.local_rect == other.local_rect
            && self.local_valid_rect == other.local_valid_rect
            && self.device_clip_rect == other.device_clip_rect
            && self.z_id == other.z_id
            && self.device_tile_box == other.device_tile_box
    }
}

pub(superstruct LayerCompositorFrameState {
    pub tile_states: FastHashMap<TileId, CompositeTileState>,
    pub rects_without_id: Vec<DeviceRect>,
}

impl Renderer {
    /// Rasterize any external compositor surfaces that require updating
    fn update_external_native_surfaces(
        &mut self,
        external_surfaces: &[ResolvedExternalSurface],
        results: &mut RenderResults,
    ) {
        if external_surfaces.is_empty() {
            return;
        }

        let opaque_sampler = self.gpu_profiler.start_sampler(GPU_SAMPLER_TAG_OPAQUE);

        self.device.disable_depth();
        self.set_blend(false, FramebufferKind::Main);

        for surface in external_surfaces {
            // See if this surface needs to be updated
            let (native_surface_id, surface_size) = match surface.update_params {
                Some(params) => params,
                None => continue,
            };

            // When updating an external surface, the entire surface rect is used
            // for all of the draw, dirty, valid and clip rect parameters.
            let surface_rect = surface_size.into();

            // Bind the native compositor surface to update
            let surface_info = self.compositor_config
                .compositor()
                .unwrap()
                .bind(
                    &mut self.device,
                    NativeTileId {
                        surface_id: native_surface_id,
                        x: 0,
                        y: 0,
                    },
                    surface_rect,
                    surface_rect,
                );

            // Bind the native surface to current FBO target
            let draw_target = DrawTarget::NativeSurface {
                offset: surface_info.origin,
                external_fbo_id: surface_info.fbo_id,
                dimensions: surface_size,
            };
            self.device.bind_draw_target(draw_target);

            let projection = Transform3D::ortho(
                0.0,
                surface_size.width as f32,
                0.0,
                surface_size.height as f32,
                self.device.ortho_near_plane(),
                self.device.ortho_far_plane(),
            );

            let ( textures, instance ) = match surface.color_data {
                ResolvedExternalSurfaceColorData::Yuv{
                        ref planes, color_space, format, channel_bit_depth, .. } => {

                    let textures = BatchTextures::composite_yuv(
                        planes[0].texture,
                        planes[1].texture,
                        planes[2].texture,
                    );

                    // When the texture is an external texture, the UV rect is not known when
                    // the external surface descriptor is created, because external textures
                    // are not resolved until the lock() callback is invoked at the start of
                    // the frame render. To handle this, query the texture resolver for the
                    // UV rect if it's an external texture, otherwise use the default UV rect.
                    let uv_rects = [
                        self.texture_resolver.get_uv_rect(&textures.input.colors[0], planes[0].uv_rect),
                        self.texture_resolver.get_uv_rect(&textures.input.colors[1], planes[1].uv_rect),
                        self.texture_resolver.get_uv_rect(&textures.input.colors[2], planes[2].uv_rect),
                    ];

                    let instance = CompositeInstance::new_yuv(
                        surface_rect.to_f32(),
                        surface_rect.to_f32(),
                        // z-id is not relevant when updating a native compositor surface.
                        // TODO(gw): Support compositor surfaces without z-buffer, for memory / perf win here.
                        color_space,
                        format,
                        channel_bit_depth,
                        uv_rects,
                        (falsefalse),
                        None,
                    );

                    // Bind an appropriate YUV shader for the texture format kind
                    self.shaders
                        .borrow_mut()
                        .get_composite_shader(
                            CompositeSurfaceFormat::Yuv,
                            surface.image_buffer_kind,
                            instance.get_yuv_features(),
                        ).bind(
                            &mut self.device,
                            &projection,
                            None,
                            &mut self.renderer_errors,
                            &mut self.profile,
                            &mut self.command_log,
                        );

                    ( textures, instance )
                },
                ResolvedExternalSurfaceColorData::Rgb{ ref plane, .. } => {
                    let textures = BatchTextures::composite_rgb(plane.texture);
                    let uv_rect = self.texture_resolver.get_uv_rect(&textures.input.colors[0], plane.uv_rect);
                    let instance = CompositeInstance::new_rgb(
                        surface_rect.to_f32(),
                        surface_rect.to_f32(),
                        PremultipliedColorF::WHITE,
                        uv_rect,
                        plane.texture.uses_normalized_uvs(),
                        (falsefalse),
                        None,
                    );
                    let features = instance.get_rgb_features();

                    self.shaders
                        .borrow_mut()
                        .get_composite_shader(
                            CompositeSurfaceFormat::Rgba,
                            surface.image_buffer_kind,
                            features,
                        ).bind(
                            &mut self.device,
                            &projection,
                            None,
                            &mut self.renderer_errors,
                            &mut self.profile,
                            &mut self.command_log,
                        );

                    ( textures, instance )
                },
            };

            self.draw_instanced_batch(
                &[instance],
                VertexArrayKind::Composite,
                &textures,
                &mut results.stats,
            );

            self.compositor_config
                .compositor()
                .unwrap()
                .unbind(&mut self.device);
        }

        self.gpu_profiler.finish_sampler(opaque_sampler);
    }

    /// Draw a list of tiles to the framebuffer
    fn draw_tile_list<'a, I: Iterator<Item = &'a occlusion::Item<OcclusionItemKey>>>(
        &mut self,
        tiles_iter: I,
        composite_state: &CompositeState,
        external_surfaces: &[ResolvedExternalSurface],
        projection: &default::Transform3D<f32>,
        stats: &mut RendererStats,
    ) {
        let mut current_shader_params = (
            CompositeSurfaceFormat::Rgba,
            ImageBufferKind::Texture2D,
            CompositeFeatures::empty(),
            None,
        );
        let mut current_textures = BatchTextures::empty();
        let mut instances = Vec::new();

        for item in tiles_iter {
            let tile = &composite_state.tiles[item.key.tile_index];

            let clip_rect = item.rectangle;
            let tile_rect = composite_state.get_device_rect(&tile.local_rect, tile.transform_index);
            let transform = composite_state.get_device_transform(tile.transform_index);
            let flip = (transform.scale.x < 0.0, transform.scale.y < 0.0);

            let clip = if item.key.needs_mask {
                tile.clip_index.map(|index| {
                    composite_state.get_compositor_clip(index)
                })
            } else {
                None
            };

            // Work out the draw params based on the tile surface
            let (instance, textures, shader_params) = match tile.surface {
                CompositeTileSurface::Color { color } => {
                    let dummy = TextureSource::Dummy;
                    let image_buffer_kind = dummy.image_buffer_kind();
                    let instance = CompositeInstance::new(
                        tile_rect,
                        clip_rect,
                        color.premultiplied(),
                        flip,
                        clip,
                    );
                    let features = instance.get_rgb_features();
                    (
                        instance,
                        BatchTextures::composite_rgb(dummy),
                        (CompositeSurfaceFormat::Rgba, image_buffer_kind, features, None),
                    )
                }
                CompositeTileSurface::Texture { surface: ResolvedSurfaceTexture::TextureCache { texture } } => {
                    let instance = CompositeInstance::new(
                        tile_rect,
                        clip_rect,
                        PremultipliedColorF::WHITE,
                        flip,
                        clip,
                    );
                    let features = instance.get_rgb_features();
                    (
                        instance,
                        BatchTextures::composite_rgb(texture),
                        (
                            CompositeSurfaceFormat::Rgba,
                            ImageBufferKind::Texture2D,
                            features,
                            None,
                        ),
                    )
                }
                CompositeTileSurface::ExternalSurface { external_surface_index } => {
                    let surface = &external_surfaces[external_surface_index.0];

                    match surface.color_data {
                        ResolvedExternalSurfaceColorData::Yuv{ ref planes, color_space, format, channel_bit_depth, .. } => {
                            let textures = BatchTextures::composite_yuv(
                                planes[0].texture,
                                planes[1].texture,
                                planes[2].texture,
                            );

                            // When the texture is an external texture, the UV rect is not known when
                            // the external surface descriptor is created, because external textures
                            // are not resolved until the lock() callback is invoked at the start of
                            // the frame render. To handle this, query the texture resolver for the
                            // UV rect if it's an external texture, otherwise use the default UV rect.
                            let uv_rects = [
                                self.texture_resolver.get_uv_rect(&textures.input.colors[0], planes[0].uv_rect),
                                self.texture_resolver.get_uv_rect(&textures.input.colors[1], planes[1].uv_rect),
                                self.texture_resolver.get_uv_rect(&textures.input.colors[2], planes[2].uv_rect),
                            ];

                            let instance = CompositeInstance::new_yuv(
                                tile_rect,
                                clip_rect,
                                color_space,
                                format,
                                channel_bit_depth,
                                uv_rects,
                                flip,
                                clip,
                            );
                            let features = instance.get_yuv_features();

                            (
                                instance,
                                textures,
                                (
                                    CompositeSurfaceFormat::Yuv,
                                    surface.image_buffer_kind,
                                    features,
                                    None
                                ),
                            )
                        },
                        ResolvedExternalSurfaceColorData::Rgb { ref plane, .. } => {
                            let uv_rect = self.texture_resolver.get_uv_rect(&plane.texture, plane.uv_rect);
                            let instance = CompositeInstance::new_rgb(
                                tile_rect,
                                clip_rect,
                                PremultipliedColorF::WHITE,
                                uv_rect,
                                plane.texture.uses_normalized_uvs(),
                                flip,
                                clip,
                            );
                            let features = instance.get_rgb_features();
                            (
                                instance,
                                BatchTextures::composite_rgb(plane.texture),
                                (
                                    CompositeSurfaceFormat::Rgba,
                                    surface.image_buffer_kind,
                                    features,
                                    Some(self.texture_resolver.get_texture_size(&plane.texture).to_f32()),
                                ),
                            )
                        },
                    }
                }
                CompositeTileSurface::Texture { surface: ResolvedSurfaceTexture::Native { .. } } => {
                    unreachable!("bug: found native surface in simple composite path");
                }
            };

            // Flush batch if shader params or textures changed
            let flush_batch = !current_textures.is_compatible_with(&textures) ||
                shader_params != current_shader_params;

            if flush_batch && !instances.is_empty() {
                self.shaders
                    .borrow_mut()
                    .get_composite_shader(
                        current_shader_params.0,
                        current_shader_params.1,
                        current_shader_params.2,
                    ).bind(
                        &mut self.device,
                        projection,
                        current_shader_params.3,
                        &mut self.renderer_errors,
                        &mut self.profile,
                        &mut self.command_log,
                    );
                self.draw_instanced_batch(
                    &instances,
                    VertexArrayKind::Composite,
                    ¤t_textures,
                    stats,
                );

                instances.clear();
            }
            current_shader_params = shader_params;
            current_textures = textures;

            // Add instance to current batch
            instances.push(instance);
        }

        // Flush the last batch
        if !instances.is_empty() {
            self.shaders
                .borrow_mut()
                .get_composite_shader(
                    current_shader_params.0,
                    current_shader_params.1,
                    current_shader_params.2,
                ).bind(
                    &mut self.device,
                    projection,
                    current_shader_params.3,
                    &mut self.renderer_errors,
                    &mut self.profile,
                    &mut self.command_log,
                );
            self.draw_instanced_batch(
                &instances,
                VertexArrayKind::Composite,
                ¤t_textures,
                stats,
            );
        }
    }

    // Composite tiles in a swapchain. When using LayerCompositor, we may
    // split the compositing in to multiple swapchains.
    fn composite_pass(
        &mut self,
        composite_state: &CompositeState,
        draw_target: DrawTarget,
        clear_color: ColorF,
        projection: &default::Transform3D<f32>,
        results: &mut RenderResults,
        partial_present_mode: Option<PartialPresentMode>,
        layer: &SwapChainLayer,
    ) {
        self.device.bind_draw_target(draw_target);
        self.device.disable_depth_write();
        self.device.disable_depth();

        // If using KHR_partial_update, call eglSetDamageRegion.
        // This must be called exactly once per frame, and prior to any rendering to the main
        // framebuffer. Additionally, on Mali-G77 we encountered rendering issues when calling
        // this earlier in the frame, during offscreen render passes. So call it now, immediately
        // before rendering to the main framebuffer. See bug 1685276 for details.
        if let Some(partial_present) = self.compositor_config.partial_present() {
            if let Some(PartialPresentMode::Single { dirty_rect }) = partial_present_mode {
                partial_present.set_buffer_damage_region(&[dirty_rect.to_i32()]);
            }
        }

        // Clear the framebuffer
        let clear_color = Some(clear_color.to_array());

        match partial_present_mode {
            Some(PartialPresentMode::Single { dirty_rect }) => {
                // There is no need to clear if the dirty rect is occluded. Additionally,
                // on Mali-G77 we have observed artefacts when calling glClear (even with
                // the empty scissor rect set) after calling eglSetDamageRegion with an
                // empty damage region. So avoid clearing in that case. See bug 1709548.
                if !dirty_rect.is_empty() && layer.occlusion.test(&dirty_rect) {
                    // We have a single dirty rect, so clear only that
                    self.device.clear_target(clear_color,
                                             None,
                                             Some(draw_target.to_framebuffer_rect(dirty_rect.to_i32())));
                }
            }
            None => {
                // Partial present is disabled, so clear the entire framebuffer
                self.device.clear_target(clear_color,
                                         None,
                                         None);
            }
        }

        // Draw opaque tiles
        let opaque_items = layer.occlusion.opaque_items();
        if !opaque_items.is_empty() {
            let opaque_sampler = self.gpu_profiler.start_sampler(GPU_SAMPLER_TAG_OPAQUE);
            self.set_blend(false, FramebufferKind::Main);
            self.draw_tile_list(
                opaque_items.iter(),
                &composite_state,
                &composite_state.external_surfaces,
                projection,
                &mut results.stats,
            );
            self.gpu_profiler.finish_sampler(opaque_sampler);
        }

        // Draw alpha tiles
        let alpha_items = layer.occlusion.alpha_items();
        if !alpha_items.is_empty() {
            let transparent_sampler = self.gpu_profiler.start_sampler(GPU_SAMPLER_TAG_TRANSPARENT);
            self.set_blend(true, FramebufferKind::Main);
            self.set_blend_mode_premultiplied_alpha(FramebufferKind::Main);
            self.draw_tile_list(
                alpha_items.iter().rev(),
                &composite_state,
                &composite_state.external_surfaces,
                projection,
                &mut results.stats,
            );
            self.gpu_profiler.finish_sampler(transparent_sampler);
        }
    }

    /// Composite picture cache tiles into the framebuffer. This is currently
    /// the only way that picture cache tiles get drawn. In future, the tiles
    /// will often be handed to the OS compositor, and this method will be
    /// rarely used.
    fn composite_simple(
        &mut self,
        composite_state: &CompositeState,
        frame_device_size: DeviceIntSize,
        fb_draw_target: DrawTarget,
        projection: &default::Transform3D<f32>,
        results: &mut RenderResults,
        partial_present_mode: Option<PartialPresentMode>,
        device_size: DeviceIntSize,
    ) {
        let _gm = self.gpu_profiler.start_marker("framebuffer");
        let _timer = self.gpu_profiler.start_timer(GPU_TAG_COMPOSITE);

        let num_tiles = composite_state.tiles.len();
        self.profile.set(profiler::PICTURE_TILES, num_tiles);

        let (window_is_opaque, enable_screenshot)  = match self.compositor_config.layer_compositor() {
            Some(ref compositor) => {
                let props = compositor.get_window_properties();
                (props.is_opaque, props.enable_screenshot)
            }
            None => (truetrue)
        };

        let mut input_layers: Vec<CompositorInputLayer> = Vec::new();
        let mut swapchain_layers = Vec::new();
        let cap = composite_state.tiles.len();
        let mut segment_builder = SegmentBuilder::new();
        let mut tile_index_to_layer_index = vec![None; composite_state.tiles.len()];
        let mut full_render_occlusion = occlusion::FrontToBackBuilder::with_capacity(cap, cap);
        let mut layer_compositor_frame_state = LayerCompositorFrameState{
            tile_states: FastHashMap::default(),
            rects_without_id: Vec::new(),
        };

        // Calculate layers with full device rect

        // Add a debug overlay request if enabled
        if self.debug_overlay_state.is_enabled {
            self.debug_overlay_state.layer_index = input_layers.len();

            input_layers.push(CompositorInputLayer {
                usage: CompositorSurfaceUsage::DebugOverlay,
                is_opaque: false,
                offset: DeviceIntPoint::zero(),
                clip_rect: device_size.into(),
                rounded_clip_rect: device_size.into(),
                rounded_clip_radii: ClipRadius::EMPTY,
            });

            swapchain_layers.push(SwapChainLayer {
                occlusion: occlusion::FrontToBackBuilder::with_capacity(cap, cap),
            });
        }

        // NOTE: Tiles here are being iterated in front-to-back order by
        //       z-id, due to the sort in composite_state.end_frame()
        for (idx, tile) in composite_state.tiles.iter().enumerate() {
            let device_tile_box = composite_state.get_device_rect(
                &tile.local_rect,
                tile.transform_index
            );

            if let Some(ref _compositor) = self.compositor_config.layer_compositor() {
                match tile.tile_id {
                    Some(tile_id) => {
                        layer_compositor_frame_state.
                            tile_states
                            .insert(
                            tile_id,
                            CompositeTileState {
                                local_rect: tile.local_rect,
                                local_valid_rect: tile.local_valid_rect,
                                device_clip_rect: tile.device_clip_rect,
                                z_id: tile.z_id,
                                device_tile_box: device_tile_box,
                                visible_rects: Vec::new(),
                            },
                        );
                    }
                    None => {}
                }
            }

            // Simple compositor needs the valid rect in device space to match clip rect
            let device_valid_rect = composite_state
                .get_device_rect(&tile.local_valid_rect, tile.transform_index);

            let rect = device_tile_box
                .intersection_unchecked(&tile.device_clip_rect)
                .intersection_unchecked(&device_valid_rect);

            if rect.is_empty() {
                continue;
            }

            let mut disable_external_composite = enable_screenshot;
            if let CompositeTileSurface::ExternalSurface { .. } = tile.surface {
                let transformed_rect = composite_state.get_device_rect(
                    &tile.local_rect,
                    tile.transform_index
                );
                if let None = transformed_rect.try_cast::<i16>() {
                    // Disable external composite when rect is big.
                    disable_external_composite = true;
                }
            }

            // Determine if the tile is an external surface or content
            let usage = match tile.surface {
                CompositeTileSurface::Texture { .. } |
                CompositeTileSurface::Color { .. } => {
                    CompositorSurfaceUsage::Content
                }
                CompositeTileSurface::ExternalSurface { external_surface_index } => {
                    match (self.current_compositor_kind, disable_external_composite) {
                        (CompositorKind::Native { .. }, _) | (CompositorKind::Draw { .. }, _) => {
                            CompositorSurfaceUsage::Content
                        }
                        (CompositorKind::Layer { .. }, true) => {
                            CompositorSurfaceUsage::Content
                        }
                        (CompositorKind::Layer { .. }, false) => {
                            let surface = &composite_state.external_surfaces[external_surface_index.0];

                            // TODO(gwc): For now, we only select a hardware overlay swapchain if we
                            // have an external image, but it may make sense to do for compositor
                            // surfaces without in future.
                            match surface.external_image_id {
                                Some(external_image_id) => {
                                    let image_key = match surface.color_data {
                                        ResolvedExternalSurfaceColorData::Rgb { image_dependency, .. } => image_dependency.key,
                                        ResolvedExternalSurfaceColorData::Yuv { image_dependencies, .. } => image_dependencies[0].key,
                                    };

                                    CompositorSurfaceUsage::External {
                                        image_key,
                                        external_image_id,
                                        transform_index: tile.transform_index,
                                    }
                                }
                                None => {
                                    CompositorSurfaceUsage::Content
                                }
                            }
                        }
                    }
                }
            };

            if let Some(ref _compositor) = self.compositor_config.layer_compositor() {
                if let CompositeTileSurface::ExternalSurface { .. } = tile.surface {
                    assert!(tile.tile_id.is_none());
                    // ExternalSurface is not promoted to external composite.
                    if let CompositorSurfaceUsage::Content = usage {
                        layer_compositor_frame_state.rects_without_id.push(rect);
                    }
                } else {
                    assert!(tile.tile_id.is_some());
                }
            }

            // Determine whether we need a new layer, and if so, what kind
            let new_layer_kind = match input_layers.last() {
                Some(curr_layer) => {
                    match (curr_layer.usage, usage) {
                        // Content -> content, composite in to same layer
                        (CompositorSurfaceUsage::Content, CompositorSurfaceUsage::Content) => None,
                        (CompositorSurfaceUsage::External { .. }, CompositorSurfaceUsage::Content) => Some(usage),

                        // Switch of layer type, or video -> video, need new swapchain
                        (CompositorSurfaceUsage::Content, CompositorSurfaceUsage::External { .. }) |
                        (CompositorSurfaceUsage::External { .. }, CompositorSurfaceUsage::External { .. }) => {
                            // Only create a new layer if we're using LayerCompositor
                            match self.compositor_config {
                                CompositorConfig::Draw { .. } | CompositorConfig::Native { .. } => None,
                                CompositorConfig::Layer { .. } => {
                                    Some(usage)
                                }
                            }
                        }
                        (CompositorSurfaceUsage::DebugOverlay, _) => {
                            Some(usage)
                        }
                        // Should not encounter debug layers as new layer
                        (_, CompositorSurfaceUsage::DebugOverlay) => {
                            unreachable!();
                        }
                    }
                }
                None => {
                    // No layers yet, so we need a new one
                    Some(usage)
                }
            };

            if let Some(new_layer_kind) = new_layer_kind {
                let (offset, clip_rect, is_opaque, rounded_clip_rect, rounded_clip_radii) = match usage {
                    CompositorSurfaceUsage::Content => {
                        (
                            DeviceIntPoint::zero(),
                            device_size.into(),
                            false,      // Assume not opaque, we'll calculate this later
                            device_size.into(),
                            ClipRadius::EMPTY,
                        )
                    }
                    CompositorSurfaceUsage::External { .. } => {
                        let rect = composite_state.get_device_rect(
                            &tile.local_rect,
                            tile.transform_index
                        );

                        let clip_rect = tile.device_clip_rect.to_i32();
                        let is_opaque = tile.kind != TileKind::Alpha;

                        if self.debug_flags.contains(DebugFlags::EXTERNAL_COMPOSITE_BORDERS) {
                            self.external_composite_debug_items.push(DebugItem::Rect {
                                outer_color: debug_colors::ORANGERED,
                                inner_color: ColorF { r: 0.0, g: 0.0, b: 0.0, a: 0.0 },
                                rect: tile.device_clip_rect,
                                thickness: 10,
                            });
                        }

                        let (rounded_clip_rect, rounded_clip_radii) = match tile.clip_index {
                            Some(clip_index) => {
                                let clip = composite_state.get_compositor_clip(clip_index);
                                let radius = ClipRadius {
                                    top_left: clip.radius.top_left.width.round() as i32,
                                    top_right: clip.radius.top_right.width.round() as i32,
                                    bottom_left: clip.radius.bottom_left.width.round() as i32,
                                    bottom_right: clip.radius.bottom_right.width.round() as i32,
                                };
                                (clip.rect.to_i32(), radius)
                            }
                            None => {
                                (clip_rect, ClipRadius::EMPTY)
                            }
                        };

                        (
                            rect.min.to_i32(),
                            clip_rect,
                            is_opaque,
                            rounded_clip_rect,
                            rounded_clip_radii,
                        )
                    }
                    CompositorSurfaceUsage::DebugOverlay => unreachable!(),
                };

                input_layers.push(CompositorInputLayer {
                    usage: new_layer_kind,
                    is_opaque,
                    offset,
                    clip_rect,
                    rounded_clip_rect,
                    rounded_clip_radii,
                });

                swapchain_layers.push(SwapChainLayer {
                    occlusion: occlusion::FrontToBackBuilder::with_capacity(cap, cap),
                })
            }
            tile_index_to_layer_index[idx] = Some(input_layers.len() - 1);

            // Caluclate actual visible tile's rects

            let is_opaque = tile.kind == TileKind::Opaque;

            match tile.clip_index {
                Some(clip_index) => {
                    let clip = composite_state.get_compositor_clip(clip_index);

                    // TODO(gw): Make segment builder generic on unit to avoid casts below.
                    segment_builder.initialize(
                        rect.cast_unit(),
                        None,
                        rect.cast_unit(),
                    );
                    segment_builder.push_clip_rect(
                        clip.rect.cast_unit(),
                        Some(clip.radius),
                        ClipMode::Clip,
                    );
                    segment_builder.build(|segment| {
                        let key = OcclusionItemKey { tile_index: idx, needs_mask: segment.has_mask };

                        full_render_occlusion.add(
                            &segment.rect.cast_unit(),
                            is_opaque && !segment.has_mask,
                            key,
                        );
                    });
                }
                None => {
                    full_render_occlusion.add(&rect, is_opaque, OcclusionItemKey {
                        tile_index: idx,
                        needs_mask: false,
                    });
                }
            }
        }

        assert_eq!(swapchain_layers.len(), input_layers.len());

        if window_is_opaque {
            match input_layers.last_mut() {
                Some(_layer) => {
                    // If the window is opaque, and the last(back) layer is
                    //  a content layer then mark that as opaque.
                    // TODO: This causes talos performance regressions.
                    // if let CompositorSurfaceUsage::Content = layer.usage {
                    //     layer.is_opaque = true;
                    // }
                }
                None => {
                    // If no tiles were present, and we expect an opaque window,
                    // add an empty layer to force a composite that clears the screen,
                    // to match existing semantics.
                    input_layers.push(CompositorInputLayer {
                        usage: CompositorSurfaceUsage::Content,
                        is_opaque: true,
                        offset: DeviceIntPoint::zero(),
                        clip_rect: device_size.into(),
                        rounded_clip_rect: device_size.into(),
                        rounded_clip_radii: ClipRadius::EMPTY,
                    });

                    swapchain_layers.push(SwapChainLayer {
                        occlusion: occlusion::FrontToBackBuilder::with_capacity(cap, cap),
                    });
                }
            }
        }

        let mut full_render = self.debug_overlay_state.is_enabled;

        // Start compositing if using OS compositor
        if let Some(ref mut compositor) = self.compositor_config.layer_compositor() {
            let input = CompositorInputConfig {
                enable_screenshot,
                layers: &input_layers,
            };
            full_render |= compositor.begin_frame(&input);
        }

        // Full render is requested when layer tree is updated.
        let mut partial_present_mode = if full_render {
            None
        } else {
            partial_present_mode
        };

        assert_eq!(swapchain_layers.len(), input_layers.len());

        // Recalculate dirty rect for layer compositor
        if let Some(ref _compositor) = self.compositor_config.layer_compositor() {
            // Set visible rests of current frame to each tile's CompositeTileState.
            for item in full_render_occlusion
            .opaque_items()
            .iter()
            .chain(full_render_occlusion.alpha_items().iter()) {
                let tile = &composite_state.tiles[item.key.tile_index];
                match tile.tile_id {
                    Some(tile_id) => {
                        if let Some(tile_state) = layer_compositor_frame_state.tile_states.get_mut(&tile_id) {
                            tile_state.visible_rects.push(item.rectangle);
                        } else {
                            unreachable!();
                        }
                    }
                    None => {}
                }
            }

            let can_use_partial_present =
                !self.force_redraw && !full_render &&
                self.layer_compositor_frame_state_in_prev_frame.is_some();

            if can_use_partial_present {
                let mut combined_dirty_rect = DeviceRect::zero();

                for tile in composite_state.tiles.iter() {
                    if tile.tile_id.is_none() {
                        match tile.surface {
                            CompositeTileSurface::ExternalSurface { .. } => {}
                            CompositeTileSurface::Texture { .. }  |
                            CompositeTileSurface::Color { .. } => {
                                unreachable!();
                            },
                        }
                        continue;
                    }

                    assert!(tile.tile_id.is_some());

                    let tiles_exists_in_prev_frame =
                        self.layer_compositor_frame_state_in_prev_frame
                        .as_ref()
                        .unwrap()
                        .tile_states
                        .contains_key(&tile.tile_id.unwrap());
                    let tile_id = tile.tile_id.unwrap();
                    let tile_state = layer_compositor_frame_state.tile_states.get(&tile_id).unwrap();

                    if tiles_exists_in_prev_frame {
                        let prev_tile_state = self.layer_compositor_frame_state_in_prev_frame
                            .as_ref()
                            .unwrap()
                            .tile_states
                            .get(&tile_id)
                            .unwrap();

                        if tile_state.same_state(prev_tile_state) {
                            // Case that tile is same state in previous frame and current frame.
                            // Intersection of tile's dirty rect and tile's visible rects are actual dirty rects.
                            let dirty_rect = composite_state.get_device_rect(
                                &tile.local_dirty_rect,
                                tile.transform_index,
                            );
                            for rect in tile_state.visible_rects.iter()  {
                                let visible_dirty_rect = rect.intersection(&dirty_rect);
                                if visible_dirty_rect.is_some() {
                                    combined_dirty_rect = combined_dirty_rect.union(&visible_dirty_rect.unwrap());
                                }
                            }
                        } else {
                            // If tile is rendered in previous frame, but its state is different,
                            // both visible rects in previous frame and current frame are dirty rects.
                            for rect in tile_state.visible_rects
                                .iter()
                                .chain(prev_tile_state.visible_rects.iter())  {
                                combined_dirty_rect = combined_dirty_rect.union(&rect);
                            }
                        }
                    } else {
                        // If tile is not rendered in previous frame, its all visible rects are dirty rects.
                        for rect in &tile_state.visible_rects {
                            combined_dirty_rect = combined_dirty_rect.union(&rect);
                        }
                    }
                }

                // Case that tile is rendered in pervious frame, but not in current frame.
                for (tile_id, tile_state) in self.layer_compositor_frame_state_in_prev_frame
                    .as_ref()
                    .unwrap()
                    .tile_states
                    .iter() {
                    if !layer_compositor_frame_state.tile_states.contains_key(&tile_id) {
                        for rect in tile_state.visible_rects.iter()  {
                            combined_dirty_rect = combined_dirty_rect.union(&rect);
                        }
                    }
                }

                // Case that ExternalSurface is not promoted to external composite.
                for rect in layer_compositor_frame_state
                    .rects_without_id
                    .iter()
                    .chain(self.layer_compositor_frame_state_in_prev_frame.as_ref().unwrap().rects_without_id.iter())  {
                    combined_dirty_rect = combined_dirty_rect.union(&rect);
                }

                let device_rect = DeviceRect::from_size(device_size.to_f32());
                let clipped_dirty_rect = combined_dirty_rect.intersection_unchecked(&device_rect);

                partial_present_mode = Some(PartialPresentMode::Single {
                    dirty_rect: clipped_dirty_rect,
                });
            } else {
                partial_present_mode = None;
            }

            self.layer_compositor_frame_state_in_prev_frame = Some(layer_compositor_frame_state);
        }

        // Check tiles handling with partial_present_mode

        let mut opaque_rounded_corners: HashSet<CompositeRoundedCorner> = HashSet::new();

        // NOTE: Tiles here are being iterated in front-to-back order by
        //       z-id, due to the sort in composite_state.end_frame()
        for (idx, tile) in composite_state.tiles.iter().enumerate() {
            let device_tile_box = composite_state.get_device_rect(
                &tile.local_rect,
                tile.transform_index
            );

            // Determine a clip rect to apply to this tile, depending on what
            // the partial present mode is.
            let partial_clip_rect = match partial_present_mode {
                Some(PartialPresentMode::Single { dirty_rect }) => dirty_rect,
                None => device_tile_box,
            };

            // Simple compositor needs the valid rect in device space to match clip rect
            let device_valid_rect = composite_state
                .get_device_rect(&tile.local_valid_rect, tile.transform_index);

            let rect = device_tile_box
                .intersection_unchecked(&tile.device_clip_rect)
                .intersection_unchecked(&partial_clip_rect)
                .intersection_unchecked(&device_valid_rect);

            if rect.is_empty() {
                continue;
            }

            let layer_index = match tile_index_to_layer_index[idx] {
                None => {
                    // The rect of partial present should be subset of the rect of full render.
                    error!("rect {:?} should have valid layer index", rect);
                    continue;
                }
                Some(layer_index) => layer_index,
            };

            // For normal tiles, add to occlusion tracker
            let layer = &mut swapchain_layers[layer_index];

            let is_opaque = tile.kind == TileKind::Opaque;

            match tile.clip_index {
                Some(clip_index) => {
                    let clip = composite_state.get_compositor_clip(clip_index);

                        // TODO(gw): Make segment builder generic on unit to avoid casts below.
                    segment_builder.initialize(
                        rect.cast_unit(),
                        None,
                        rect.cast_unit(),
                    );
                    segment_builder.push_clip_rect(
                        clip.rect.cast_unit(),
                        Some(clip.radius),
                        ClipMode::Clip,
                    );
                    segment_builder.build(|segment| {
                        let key = OcclusionItemKey { tile_index: idx, needs_mask: segment.has_mask };

                        let radius = if segment.edge_flags ==
                            EdgeMask::TOP | EdgeMask::LEFT &&
                            !clip.radius.top_left.is_empty() {
                            Some(clip.radius.top_left)
                        } else if segment.edge_flags ==
                            EdgeMask::TOP | EdgeMask::RIGHT &&
                            !clip.radius.top_right.is_empty() {
                            Some(clip.radius.top_right)
                        } else if segment.edge_flags ==
                            EdgeMask::BOTTOM | EdgeMask::LEFT &&
                            !clip.radius.bottom_left.is_empty() {
                            Some(clip.radius.bottom_left)
                        } else if segment.edge_flags ==
                            EdgeMask::BOTTOM | EdgeMask::RIGHT &&
                            !clip.radius.bottom_right.is_empty() {
                            Some(clip.radius.bottom_right)
                        } else {
                            None
                        };

                        if let Some(radius) = radius {
                            let rounded_corner = CompositeRoundedCorner {
                                    rect: segment.rect.cast_unit(),
                                    radius: radius,
                                    edge_flags: segment.edge_flags,
                            };

                            // Drop overdraw rounded rect
                            if opaque_rounded_corners.contains(&rounded_corner) {
                                return;
                            }

                            if is_opaque {
                                opaque_rounded_corners.insert(rounded_corner);
                            }
                        }

                        layer.occlusion.add(
                            &segment.rect.cast_unit(),
                            is_opaque && !segment.has_mask,
                            key,
                        );
                    });
                }
                None => {
                    layer.occlusion.add(&rect, is_opaque, OcclusionItemKey {
                        tile_index: idx,
                        needs_mask: false,
                    });
                }
            }
        }

        assert_eq!(swapchain_layers.len(), input_layers.len());
        let mut content_clear_color = Some(self.clear_color);

        for (layer_index, (layer, swapchain_layer)) in input_layers.iter().zip(swapchain_layers.iter()).enumerate() {
            self.device.reset_state();

            // Skip compositing external images or debug layers here
            match layer.usage {
                CompositorSurfaceUsage::Content => {}
                CompositorSurfaceUsage::External { .. } | CompositorSurfaceUsage::DebugOverlay => {
                    continue;
                }
            }

            // Only use supplied clear color for first content layer we encounter
            let clear_color = content_clear_color.take().unwrap_or(ColorF::TRANSPARENT);

            if let Some(ref mut _compositor) = self.compositor_config.layer_compositor() {
                if let Some(PartialPresentMode::Single { dirty_rect }) = partial_present_mode {
                    let device_rect = DeviceRect::from_size(device_size.to_f32());
                    let clipped_dirty_rect = dirty_rect.intersection_unchecked(&device_rect);
                    if clipped_dirty_rect.is_empty() {
                        continue;
                    }
                }
            }

            let draw_target = match self.compositor_config {
                CompositorConfig::Layer { ref mut compositor } => {
                    match partial_present_mode {
                        Some(PartialPresentMode::Single { dirty_rect }) => {
                            compositor.bind_layer(layer_index, &[dirty_rect.to_i32()]);
                        }
                        None => {
                            compositor.bind_layer(layer_index, &[]);
                        }
                    };

                    DrawTarget::NativeSurface {
                        offset: -layer.offset,
                        external_fbo_id: 0,
                        dimensions: frame_device_size,
                    }
                }
                // Native can be hit when switching compositors (disable when using Layer)
                CompositorConfig::Draw { .. } | CompositorConfig::Native { .. } => {
                    fb_draw_target
                }
            };

            // TODO(gwc): When supporting external attached swapchains, need to skip the composite pass here

            // Draw each compositing pass in to a swap chain
            self.composite_pass(
                composite_state,
                draw_target,
                clear_color,
                projection,
                results,
                partial_present_mode,
                swapchain_layer,
            );

            if let Some(ref mut compositor) = self.compositor_config.layer_compositor() {
                match partial_present_mode {
                    Some(PartialPresentMode::Single { dirty_rect }) => {
                        compositor.present_layer(layer_index, &[dirty_rect.to_i32()]);
                    }
                    None => {
                        compositor.present_layer(layer_index, &[]);
                    }
                };
            }
        }

        // End frame notify for experimental compositor
        if let Some(ref mut compositor) = self.compositor_config.layer_compositor() {
            for (layer_index, layer) in input_layers.iter().enumerate() {
                // External surfaces need transform applied, but content
                // surfaces are always at identity
                let transform = match layer.usage {
                    CompositorSurfaceUsage::Content => CompositorSurfaceTransform::identity(),
                    CompositorSurfaceUsage::External { transform_index, .. } => composite_state.get_compositor_transform(transform_index),
                    CompositorSurfaceUsage::DebugOverlay => CompositorSurfaceTransform::identity(),
                };

                compositor.add_surface(
                    layer_index,
                    transform,
                    layer.clip_rect,
                    ImageRendering::Auto,
                    layer.rounded_clip_rect,
                    layer.rounded_clip_radii,
                );
            }
        }
    }

    pub(superfn composite_frame(
        &mut self,
        frame: &mut Frame,
        device_size: Option<DeviceIntSize>,
        results: &mut RenderResults,
        present_mode: Option<PartialPresentMode>,
    ) {
        profile_scope!("main target");
        if let Some(device_size) = device_size {
            if let Some(history) = &mut self.command_log {
                history.begin_render_target("Window", device_size);
            }

            results.stats.color_target_count += 1;
            results.picture_cache_debug = mem::replace(
                &mut frame.composite_state.picture_cache_debug,
                PictureCacheDebugInfo::new(),
            );
            results.did_rasterize_any_tile = frame.composite_state.did_rasterize_any_tile;

            let size = frame.device_rect.size().to_f32();
            let surface_origin_is_top_left = self.device.surface_origin_is_top_left();
            let (bottom, top) = if surface_origin_is_top_left {
                (0.0, size.height)
            } else {
                (size.height, 0.0)
            };

            let projection = Transform3D::ortho(
                0.0,
                size.width,
                bottom,
                top,
                self.device.ortho_near_plane(),
                self.device.ortho_far_plane(),
            );

            let fb_scale = Scale::<_, _, FramebufferPixel>::new(1i32);
            let mut fb_rect = frame.device_rect * fb_scale;

            if !surface_origin_is_top_left {
                let h = fb_rect.height();
                fb_rect.min.y = device_size.height - fb_rect.max.y;
                fb_rect.max.y = fb_rect.min.y + h;
            }

            let draw_target = DrawTarget::Default {
                rect: fb_rect,
                total_size: device_size * fb_scale,
                surface_origin_is_top_left,
            };

            // If we have a native OS compositor, then make use of that interface
            // to specify how to composite each of the picture cache surfaces.
            match self.current_compositor_kind {
                CompositorKind::Native { .. } => {
                    // We have already queued surfaces for early native composition by this point.
                    // All that is left is to finally update any external native surfaces that were
                    // invalidated so that composition can complete.
                    self.update_external_native_surfaces(
                        &frame.composite_state.external_surfaces,
                        results,
                    );
                }
                CompositorKind::Draw { .. } | CompositorKind::Layer { .. } => {
                    self.composite_simple(
                        &frame.composite_state,
                        frame.device_rect.size(),
                        draw_target,
                        &projection,
                        results,
                        present_mode,
                        device_size,
                    );
                }
            }
            // Reset force_redraw. It was used in composite_simple() with layer compositor.
            self.force_redraw = false;
        } else {
            // Rendering a frame without presenting it will confuse the partial
            // present logic, so force a full present for the next frame.
            self.force_redraw = true;
        }
    }

    /// Update the dirty rects based on current compositing mode and config
    // TODO(gw): This can be tidied up significantly once the Draw compositor
    //           is implemented in terms of the compositor trait.
    pub(superfn calculate_dirty_rects(
        &mut self,
        buffer_age: usize,
        composite_state: &CompositeState,
        draw_target_dimensions: DeviceIntSize,
        results: &mut RenderResults,
    ) -> Option<PartialPresentMode> {
        if let Some(ref _compositor) = self.compositor_config.layer_compositor() {
            // Calculate dirty rects of layer compositor in composite_simple()
            return None;
        }

        let mut partial_present_mode = None;

        let (max_partial_present_rects, draw_previous_partial_present_regions) =
            match self.current_compositor_kind {
                CompositorKind::Native { .. } => {
                    // Assume that we can return a single dirty rect for native
                    // compositor for now, and that there is no buffer-age functionality.
                    // These params can be exposed by the compositor capabilities struct
                    // as the Draw compositor is ported to use it.
                    (1false)
                }
                CompositorKind::Draw {
                    draw_previous_partial_present_regions,
                    max_partial_present_rects,
                } => (
                    max_partial_present_rects,
                    draw_previous_partial_present_regions,
                ),
                CompositorKind::Layer { .. } => {
                    unreachable!();
                }
            };

        if max_partial_present_rects > 0 {
            let prev_frames_damage_rect = if let Some(..) = self.compositor_config.partial_present()
            {
                self.buffer_damage_tracker
                    .get_damage_rect(buffer_age)
                    .or_else(|| Some(DeviceRect::from_size(draw_target_dimensions.to_f32())))
            } else {
                None
            };

            let can_use_partial_present = composite_state.dirty_rects_are_valid
                && !self.force_redraw
                && !(prev_frames_damage_rect.is_none() && draw_previous_partial_present_regions)
                && !self.debug_overlay_state.is_enabled;

            if can_use_partial_present {
                let mut combined_dirty_rect = DeviceRect::zero();
                let fb_rect = DeviceRect::from_size(draw_target_dimensions.to_f32());

                // Work out how many dirty rects WR produced, and if that's more than
                // what the device supports.
                for tile in &composite_state.tiles {
                    let dirty_rect = composite_state
                        .get_device_rect(&tile.local_dirty_rect, tile.transform_index);

                    // In pathological cases where a tile is extremely zoomed, it
                    // may end up with device coords outside the range of an i32,
                    // so clamp it to the frame buffer rect here, before it gets
                    // casted to an i32 rect below.
                    if let Some(dirty_rect) = dirty_rect.intersection(&fb_rect) {
                        combined_dirty_rect = combined_dirty_rect.union(&dirty_rect);
                    }
                }

                let combined_dirty_rect = combined_dirty_rect.round();
                let combined_dirty_rect_i32 = combined_dirty_rect.to_i32();
                // Return this frame's dirty region. If nothing has changed, don't return any dirty
                // rects at all (the client can use this as a signal to skip present completely).
                if !combined_dirty_rect.is_empty() {
                    results.dirty_rects.push(combined_dirty_rect_i32);
                }

                // Track this frame's dirty region, for calculating subsequent frames' damage.
                if draw_previous_partial_present_regions {
                    self.buffer_damage_tracker
                        .push_dirty_rect(&combined_dirty_rect);
                }

                // If the implementation requires manually keeping the buffer consistent,
                // then we must combine this frame's dirty region with that of previous frames
                // to determine the total_dirty_rect. The is used to determine what region we
                // render to, and is what we send to the compositor as the buffer damage region
                // (eg for KHR_partial_update).
                let total_dirty_rect = if draw_previous_partial_present_regions {
                    combined_dirty_rect.union(&prev_frames_damage_rect.unwrap())
                } else {
                    combined_dirty_rect
                };

                partial_present_mode = Some(PartialPresentMode::Single {
                    dirty_rect: total_dirty_rect,
                });
            } else {
                // If we don't have a valid partial present scenario, return a single
                // dirty rect to the client that covers the entire framebuffer.
                let fb_rect = DeviceIntRect::from_size(draw_target_dimensions);
                results.dirty_rects.push(fb_rect);

                if draw_previous_partial_present_regions {
                    self.buffer_damage_tracker
                        .push_dirty_rect(&fb_rect.to_f32());
                }
            }
        }

        partial_present_mode
    }
}

Messung V0.5 in Prozent
C=99 H=100 G=99

¤ Diese beiden folgenden Angebotsgruppen bietet das Unternehmen0.48Angebot  (Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können 2026-08-26) ¤

*Eine klare Vorstellung vom Zielzustand






Normalansicht

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

letze Version des Elbe Quellennavigators


Jenseits des Üblichen ....

Besucher

Besucher

Statistik
#Sources=277311
#Domains=752002