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


Quelle  main.rs   Sprache: unbekannt

 
/* 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/. */

/*

   An example of how to implement the Compositor trait that
   allows picture caching surfaces to be composited by the operating
   system.

   The current example supports DirectComposite on Windows only.

*/

use euclid::Angle;
use gleam::gl;
use std::ffi::CString;
use std::sync::mpsc;
use webrender::{CompositorSurfaceTransform, Transaction, api::*};
use webrender::api::units::*;
use webrender::Device;
#[cfg(target_os = "windows")]
use compositor_windows as compositor;
#[cfg(target_os = "linux")]
use compositor_wayland as compositor;
use std::{env, f32, process};

// A very hacky integration with DirectComposite. It proxies calls from the compositor
// interface to a simple C99 library which does the DirectComposition / D3D11 / ANGLE
// interfacing. This is a very unsafe impl due to the way the window pointer is passed
// around!
struct DirectCompositeInterface {
    window: *mut compositor::Window,
}

impl DirectCompositeInterface {
    fn new(window: *mut compositor::Window) -> Self {
        DirectCompositeInterface { window }
    }
}

impl webrender::Compositor for DirectCompositeInterface {
    fn create_surface(
        &mut self,
        _device: &mut Device,
        id: webrender::NativeSurfaceId,
        _virtual_offset: DeviceIntPoint,
        tile_size: DeviceIntSize,
        is_opaque: bool,
    ) {
        compositor::create_surface(
            self.window,
            id.0,
            tile_size.width,
            tile_size.height,
            is_opaque,
        );
    }

    fn destroy_surface(&mut self, _device: &mut Device, id: webrender::NativeSurfaceId) {
        compositor::destroy_surface(self.window, id.0);
    }

    fn create_tile(&mut self, _device: &mut Device, id: webrender::NativeTileId) {
        compositor::create_tile(self.window, id.surface_id.0, id.x, id.y);
    }

    fn destroy_tile(&mut self, _device: &mut Device, id: webrender::NativeTileId) {
        compositor::destroy_tile(self.window, id.surface_id.0, id.x, id.y);
    }

    fn bind(
        &mut self,
        _device: &mut Device,
        id: webrender::NativeTileId,
        dirty_rect: DeviceIntRect,
        _valid_rect: DeviceIntRect,
    ) -> webrender::NativeSurfaceInfo {
        let (fbo_id, x, y) = compositor::bind_surface(
            self.window,
            id.surface_id.0,
            id.x,
            id.y,
            dirty_rect.min.x,
            dirty_rect.min.y,
            dirty_rect.width(),
            dirty_rect.height(),
        );

        webrender::NativeSurfaceInfo {
            origin: DeviceIntPoint::new(x, y),
            fbo_id,
        }
    }

    fn unbind(&mut self, _device: &mut Device) {
        compositor::unbind_surface(self.window);
    }

    fn begin_frame(&mut self, _device: &mut Device) {
        compositor::begin_transaction(self.window);
    }

    fn add_surface(
        &mut self,
        _device: &mut Device,
        id: webrender::NativeSurfaceId,
        transform: CompositorSurfaceTransform,
        clip_rect: DeviceIntRect,
        _image_rendering: ImageRendering,
    ) {
        compositor::add_surface(
            self.window,
            id.0,
            transform.offset.x as i32,
            transform.offset.y as i32,
            clip_rect.min.x,
            clip_rect.min.y,
            clip_rect.width(),
            clip_rect.height(),
        );
    }

    fn end_frame(&mut self, _device: &mut Device) {
        compositor::end_transaction(self.window);
    }
    fn create_external_surface(
        &mut self,
        _device: &mut Device,
        _id: webrender::NativeSurfaceId,
        _: bool,
    ) {
        todo!()
    }

    fn attach_external_image(
        &mut self,
        _device: &mut Device,
        _id: webrender::NativeSurfaceId,
        _external_image: ExternalImageId,
    ) {
        todo!()
    }

    fn enable_native_compositor(&mut self, _device: &mut Device, _enable: bool) {
        todo!()
    }

    fn deinit(&mut self, _device: &mut Device) {
        compositor::deinit(self.window);
    }

    fn get_capabilities(&self, _device: &mut Device) -> webrender::CompositorCapabilities {
        webrender::CompositorCapabilities {
            virtual_surface_size: 1024 * 1024,
            ..Default::default()
        }
    }

    fn invalidate_tile(
        &mut self,
        _device: &mut Device,
        _id: webrender::NativeTileId,
        _valid_rect: DeviceIntRect,
    ) {
    }

    fn start_compositing(
        &mut self,
        _device: &mut Device,
        _color: webrender::webrender_api::ColorF,
        _dirty_rects: &[DeviceIntRect],
        _opaque_rects: &[DeviceIntRect],
    ) {
    }

    fn create_backdrop_surface(
        &mut self,
        _device: &mut Device,
        _id: webrender::NativeSurfaceId,
        _color: webrender::webrender_api::ColorF,
    ) {
        todo!()
    }

    fn get_window_visibility(&self, _device: &mut Device) -> webrender::WindowVisibility {
        todo!()
    }
}

// Simplisitic implementation of the WR notifier interface to know when a frame
// has been prepared and can be rendered.
struct Notifier {
    tx: mpsc::Sender<()>,
}

impl Notifier {
    fn new(tx: mpsc::Sender<()>) -> Self {
        Notifier { tx }
    }
}

impl RenderNotifier for Notifier {
    fn clone(&self) -> Box<dyn RenderNotifier> {
        Box::new(Notifier {
            tx: self.tx.clone(),
        })
    }

    fn wake_up(&self, _composite_needed: bool) {}

    fn new_frame_ready(&self, _: DocumentId, _scrolled: bool, _composite_needed: bool, _: FramePublishId) {
        self.tx.send(()).ok();
    }
}

fn push_rotated_rect(
    builder: &mut DisplayListBuilder,
    rect: LayoutRect,
    color: ColorF,
    spatial_id: SpatialId,
    _root_pipeline_id: PipelineId,
    angle: f32,
    time: f32,
    item_key: SpatialTreeItemKey,
) {
    let color = color.scale_rgb(time);
    let rotation = LayoutTransform::rotation(
        0.0,
        0.0,
        1.0,
        Angle::radians(2.0 * std::f32::consts::PI * angle),
    );
    let center = rect.center();
    let transform_origin = LayoutVector3D::new(center.x, center.y, 0.0);
    let transform = rotation
        .pre_translate(-transform_origin)
        .then_translate(transform_origin);
    let spatial_id = builder.push_reference_frame(
        LayoutPoint::zero(),
        spatial_id,
        TransformStyle::Flat,
        PropertyBinding::Value(transform),
        ReferenceFrameKind::Transform {
            is_2d_scale_translation: false,
            should_snap: false,
            paired_with_perspective: false,
        },
        item_key,
    );
    builder.push_rect(
        &CommonItemProperties::new(
            rect,
            SpaceAndClipInfo {
                spatial_id,
                clip_chain_id: ClipChainId::INVALID,
            },
        ),
        rect,
        color,
    );
}

fn build_display_list(
    builder: &mut DisplayListBuilder,
    scroll_id: ExternalScrollId,
    root_pipeline_id: PipelineId,
    layout_size: LayoutSize,
    time: f32,
    invalidations: Invalidations,
) {
    let size_factor = match invalidations {
        Invalidations::Small => 0.1,
        Invalidations::Large | Invalidations::Scrolling => 1.0,
    };

    let fixed_space_info = SpaceAndClipInfo {
        spatial_id: SpatialId::root_scroll_node(root_pipeline_id),
        clip_chain_id: ClipChainId::INVALID,
    };

    let scroll_spatial_id = builder.define_scroll_frame(
        fixed_space_info.spatial_id,
        scroll_id,
        LayoutRect::from_size(layout_size),
        LayoutRect::from_size(layout_size),
        LayoutVector2D::zero(),
        APZScrollGeneration::default(),
        HasScrollLinkedEffect::No,
        SpatialTreeItemKey::new(1, 0),
    );

    builder.push_rect(
        &CommonItemProperties::new(
            LayoutRect::from_size(layout_size).inflate(-10.0, -10.0),
            fixed_space_info,
        ),
        LayoutRect::from_size(layout_size).inflate(-10.0, -10.0),
        ColorF::new(0.8, 0.8, 0.8, 1.0),
    );

    push_rotated_rect(
        builder,
        LayoutRect::from_origin_and_size(
            LayoutPoint::new(100.0, 100.0),
            LayoutSize::new(size_factor * 400.0, size_factor * 400.0),
        ),
        ColorF::new(1.0, 0.0, 0.0, 1.0),
        scroll_spatial_id,
        root_pipeline_id,
        time,
        time,
        SpatialTreeItemKey::new(1, 1),
    );

    push_rotated_rect(
        builder,
        LayoutRect::from_origin_and_size(
            LayoutPoint::new(800.0, 100.0),
            LayoutSize::new(size_factor * 100.0, size_factor * 600.0),
        ),
        ColorF::new(0.0, 1.0, 0.0, 1.0),
        fixed_space_info.spatial_id,
        root_pipeline_id,
        0.2,
        time,
        SpatialTreeItemKey::new(1, 2),
    );

    push_rotated_rect(
        builder,
        LayoutRect::from_origin_and_size(
            LayoutPoint::new(700.0, 200.0),
            LayoutSize::new(size_factor * 300.0, size_factor * 300.0),
        ),
        ColorF::new(0.0, 0.0, 1.0, 1.0),
        scroll_spatial_id,
        root_pipeline_id,
        0.1,
        time,
        SpatialTreeItemKey::new(1, 3),
    );

    push_rotated_rect(
        builder,
        LayoutRect::from_origin_and_size(
            LayoutPoint::new(100.0, 600.0),
            LayoutSize::new(size_factor * 400.0, size_factor * 400.0),
        ),
        ColorF::new(1.0, 1.0, 0.0, 1.0),
        scroll_spatial_id,
        root_pipeline_id,
        time,
        time,
        SpatialTreeItemKey::new(1, 4),
    );

    push_rotated_rect(
        builder,
        LayoutRect::from_origin_and_size(
            LayoutPoint::new(700.0, 600.0),
            LayoutSize::new(size_factor * 400.0, size_factor * 400.0),
        ),
        ColorF::new(0.0, 1.0, 1.0, 1.0),
        scroll_spatial_id,
        root_pipeline_id,
        time,
        time,
        SpatialTreeItemKey::new(1, 5),
    );
}

#[derive(Debug, Copy, Clone)]
enum Invalidations {
    Large,
    Small,
    Scrolling,
}

#[repr(C)]
#[derive(Debug, Copy, Clone)]
enum Sync {
    None = 0,
    Swap = 1,
    Commit = 2,
    Flush = 3,
    Query = 4,
}

fn main() {
    let args: Vec<String> = env::args().collect();

    if args.len() != 6 {
        println!("USAGE: compositor [native|none] [small|large|scroll] [none|swap|commit|flush|query] width height");
        process::exit(0);
    }

    let enable_compositor = match args[1].parse::<String>().unwrap().as_str() {
        "native" => true,
        "none" => false,
        _ => panic!("invalid compositor [native, none]"),
    };

    let inv_mode = match args[2].parse::<String>().unwrap().as_str() {
        "small" => Invalidations::Small,
        "large" => Invalidations::Large,
        "scroll" => Invalidations::Scrolling,
        _ => panic!("invalid invalidations [small, large, scroll]"),
    };

    let sync_mode = match args[3].parse::<String>().unwrap().as_str() {
        "none" => Sync::None,
        "swap" => Sync::Swap,
        "commit" => Sync::Commit,
        "flush" => Sync::Flush,
        "query" => Sync::Query,
        _ => panic!("invalid sync mode [none, swap, commit, flush, query]"),
    };

    let width = args[4].parse().unwrap();
    let height = args[5].parse().unwrap();
    let device_size = DeviceIntSize::new(width, height);

    // Load GL, construct WR and the native compositor interface.
    let window = compositor::create_window(
        device_size.width,
        device_size.height,
        enable_compositor,
        sync_mode as i32,
    );
    let debug_flags = DebugFlags::empty();
    let compositor_config = if enable_compositor {
        webrender::CompositorConfig::Native {
            compositor: Box::new(DirectCompositeInterface::new(window)),
        }
    } else {
        webrender::CompositorConfig::Draw {
            max_partial_present_rects: 0,
            draw_previous_partial_present_regions: false,
            partial_present: None,
        }
    };
    let opts = webrender::WebRenderOptions {
        clear_color: ColorF::new(1.0, 1.0, 1.0, 1.0),
        debug_flags,
        compositor_config,
        surface_origin_is_top_left: false,
        ..webrender::WebRenderOptions::default()
    };
    let (tx, rx) = mpsc::channel();
    let notifier = Box::new(Notifier::new(tx));
    let gl = unsafe {
        gl::GlesFns::load_with(|symbol| {
            let symbol = CString::new(symbol).unwrap();
            let ptr = compositor::get_proc_address(symbol.as_ptr());
            ptr
        })
    };
    let (mut renderer, sender) =
        webrender::create_webrender_instance(gl.clone(), notifier, opts, None).unwrap();
    let mut api = sender.create_api();
    let document_id = api.add_document(device_size);
    let device_pixel_ratio = 1.0;
    let mut current_epoch = Epoch(0);
    let root_pipeline_id = PipelineId(0, 0);
    let layout_size = device_size.to_f32() / euclid::Scale::new(device_pixel_ratio);
    let mut time = 0.0;
    let scroll_id = ExternalScrollId(3, root_pipeline_id);

    // Kick off first transaction which will mean we get a notify below to build the DL and render.
    let mut txn = Transaction::new();
    txn.set_root_pipeline(root_pipeline_id);

    if let Invalidations::Scrolling = inv_mode {
        let mut root_builder = DisplayListBuilder::new(root_pipeline_id);
        root_builder.begin();

        build_display_list(
            &mut root_builder,
            scroll_id,
            root_pipeline_id,
            layout_size,
            1.0,
            inv_mode,
        );

        txn.set_display_list(current_epoch, root_builder.end());
    }

    txn.generate_frame(0, RenderReasons::empty());
    api.send_transaction(document_id, txn);

    // Tick the compositor (in this sample, we don't block on UI events)
    while compositor::tick(window) {
        // If there is a new frame ready to draw
        if let Ok(..) = rx.try_recv() {
            // Update and render. This will invoke the native compositor interface implemented above
            // as required.
            renderer.update();
            renderer.render(device_size, 0).unwrap();
            let _ = renderer.flush_pipeline_info();

            // Construct a simple display list that can be drawn and composited by DC.
            let mut txn = Transaction::new();

            match inv_mode {
                Invalidations::Small | Invalidations::Large => {
                    let mut root_builder = DisplayListBuilder::new(root_pipeline_id);
                    root_builder.begin();

                    build_display_list(
                        &mut root_builder,
                        scroll_id,
                        root_pipeline_id,
                        layout_size,
                        time,
                        inv_mode,
                    );

                    txn.set_display_list(current_epoch, root_builder.end());
                }
                Invalidations::Scrolling => {
                    let d = 0.5 - 0.5 * (2.0 * f32::consts::PI * 5.0 * time).cos();
                    txn.set_scroll_offsets(
                        scroll_id,
                        vec![SampledScrollOffset {
                            offset: LayoutVector2D::new(0.0, (d * 100.0).round()),
                            generation: APZScrollGeneration::default(),
                        }],
                    );
                }
            }

            txn.generate_frame(0, RenderReasons::empty());
            api.send_transaction(document_id, txn);
            current_epoch.0 += 1;
            time += 0.001;
            if time > 1.0 {
                time = 0.0;
            }

            // This does nothing when native compositor is enabled
            compositor::swap_buffers(window);
        }
    }

    renderer.deinit();
    compositor::destroy_window(window);
}

[ Dauer der Verarbeitung: 0.26 Sekunden  (vorverarbeitet)  ]

                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge