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


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

use api::units::PictureRect;
use crate::pattern::{PatternKind, PatternShaderInput};
use crate::{spatial_tree::SpatialNodeIndex, render_task_graph::RenderTaskId, surface::SurfaceTileDescriptor, picture::TileKey, renderer::GpuBufferAddress, FastHashMap, prim_store::PrimitiveInstanceIndex, gpu_cache::GpuCacheAddress};
use crate::gpu_types::{QuadSegment, TransformPaletteId};
use crate::segment::EdgeAaSegmentMask;

/// A tightly packed command stored in a command buffer
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[derive(Debug, Copy, Clone)]
pub struct Command(u32);

impl Command {
    /// Draw a simple primitive that needs prim instance index only.
    const CMD_DRAW_SIMPLE_PRIM: u32 = 0x00000000;
    /// Change the current spatial node.
    const CMD_SET_SPATIAL_NODE: u32 = 0x10000000;
    /// Draw a complex (3d-split) primitive, that has multiple GPU cache addresses.
    const CMD_DRAW_COMPLEX_PRIM: u32 = 0x20000000;
    /// Draw a primitive, that has a single GPU buffer addresses.
    const CMD_DRAW_INSTANCE: u32 = 0x30000000;
    /// Draw a generic quad primitive
    const CMD_DRAW_QUAD: u32 = 0x40000000;
    /// Set a list of variable-length segments
    const CMD_SET_SEGMENTS: u32 = 0x50000000;

    /// Bitmask for command bits of the command.
    const CMD_MASK: u32 = 0xf0000000;
    /// Bitmask for param bits of the command.
    const PARAM_MASK: u32 = 0x0fffffff;

    /// Encode drawing a simple primitive.
    fn draw_simple_prim(prim_instance_index: PrimitiveInstanceIndex) -> Self {
        Command(Command::CMD_DRAW_SIMPLE_PRIM | prim_instance_index.0)
    }

    /// Encode changing spatial node.
    fn set_spatial_node(spatial_node_index: SpatialNodeIndex) -> Self {
        Command(Command::CMD_SET_SPATIAL_NODE | spatial_node_index.0)
    }

    /// Encode a list of segments that follow
    fn set_segments(count: usize) -> Self {
        Command(Command::CMD_SET_SEGMENTS | count as u32)
    }

    /// Encode drawing a complex prim.
    fn draw_complex_prim(prim_instance_index: PrimitiveInstanceIndex) -> Self {
        Command(Command::CMD_DRAW_COMPLEX_PRIM | prim_instance_index.0)
    }

    fn draw_instance(prim_instance_index: PrimitiveInstanceIndex) -> Self {
        Command(Command::CMD_DRAW_INSTANCE | prim_instance_index.0)
    }

    /// Encode arbitrary data word.
    fn data(data: u32) -> Self {
        Command(data)
    }

    fn draw_quad(prim_instance_index: PrimitiveInstanceIndex) -> Self {
        Command(Command::CMD_DRAW_QUAD | prim_instance_index.0)
    }
}

bitflags! {
    /// Flags related to quad primitives
    #[repr(transparent)]
    #[cfg_attr(feature = "capture", derive(Serialize))]
    #[cfg_attr(feature = "replay", derive(Deserialize))]
    #[derive(Debug, Copy, PartialEq, Eq, Clone, PartialOrd, Ord, Hash)]
    pub struct QuadFlags : u8 {
        const IS_OPAQUE = 1 << 0;

        /// If true, the prim is 2d and axis-aligned in device space. The render task rect can
        /// cheaply be used as a device-space clip in the vertex shader.
        const APPLY_RENDER_TASK_CLIP = 1 << 1;

        /// If true, the device-pixel scale is already applied, so ignore in vertex shaders
        const IGNORE_DEVICE_PIXEL_SCALE = 1 << 2;

        /// If true, use segments for drawing the AA edges, to allow inner section to be opaque
        const USE_AA_SEGMENTS = 1 << 3;

        /// If true, render as a mask. This ignores the blue, green and alpha channels and replaces
        /// them with the red channel in the fragment shader. Used with multiply blending, on top
        /// of premultiplied alpha content, it has the effect of applying a mask to the content under ir.
        const IS_MASK = 1 << 4;
    }
}

bitflags! {
    /// Defines the space that a quad primitive is drawn in
    #[repr(transparent)]
    #[cfg_attr(feature = "capture", derive(Serialize))]
    #[cfg_attr(feature = "replay", derive(Deserialize))]
    #[derive(Debug, Copy, PartialEq, Eq, Clone, PartialOrd, Ord, Hash)]
    pub struct MaskFlags : i32 {
        const PRIM_SPACE = 1 << 0;
    }
}

/// The unpacked equivalent to a `Command`.
#[cfg_attr(feature = "capture", derive(Serialize))]
pub enum PrimitiveCommand {
    Simple {
        prim_instance_index: PrimitiveInstanceIndex,
    },
    Complex {
        prim_instance_index: PrimitiveInstanceIndex,
        gpu_address: GpuCacheAddress,
    },
    Instance {
        prim_instance_index: PrimitiveInstanceIndex,
        gpu_buffer_address: GpuBufferAddress,
    },
    Quad {
        pattern: PatternKind,
        pattern_input: PatternShaderInput,
        src_color_task_id: RenderTaskId,
        // TODO(gw): Used for bounding rect only, could possibly remove
        prim_instance_index: PrimitiveInstanceIndex,
        gpu_buffer_address: GpuBufferAddress,
        transform_id: TransformPaletteId,
        quad_flags: QuadFlags,
        edge_flags: EdgeAaSegmentMask,
    },
}

impl PrimitiveCommand {
    pub fn simple(
        prim_instance_index: PrimitiveInstanceIndex,
    ) -> Self {
        PrimitiveCommand::Simple {
            prim_instance_index,
        }
    }

    pub fn complex(
        prim_instance_index: PrimitiveInstanceIndex,
        gpu_address: GpuCacheAddress,
    ) -> Self {
        PrimitiveCommand::Complex {
            prim_instance_index,
            gpu_address,
        }
    }

    pub fn quad(
        pattern: PatternKind,
        pattern_input: PatternShaderInput,
        src_color_task_id: RenderTaskId,
        prim_instance_index: PrimitiveInstanceIndex,
        gpu_buffer_address: GpuBufferAddress,
        transform_id: TransformPaletteId,
        quad_flags: QuadFlags,
        edge_flags: EdgeAaSegmentMask,
    ) -> Self {
        PrimitiveCommand::Quad {
            pattern,
            pattern_input,
            src_color_task_id,
            prim_instance_index,
            gpu_buffer_address,
            transform_id,
            quad_flags,
            edge_flags,
        }
    }

    pub fn instance(
        prim_instance_index: PrimitiveInstanceIndex,
        gpu_buffer_address: GpuBufferAddress,
    ) -> Self {
        PrimitiveCommand::Instance {
            prim_instance_index,
            gpu_buffer_address,
        }
    }
}


/// A list of commands describing how to draw a primitive list.
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct CommandBuffer {
    /// The encoded drawing commands.
    commands: Vec<Command>,
    /// Cached current spatial node.
    current_spatial_node_index: SpatialNodeIndex,
}

impl CommandBuffer {
    /// Construct a new cmd buffer.
    pub fn new() -> Self {
        CommandBuffer {
            commands: Vec::new(),
            current_spatial_node_index: SpatialNodeIndex::INVALID,
        }
    }

    /// Push a list of segments in to the cmd buffer
    pub fn set_segments(
        &mut self,
        segments: &[QuadSegment],
    ) {
        self.commands.push(Command::set_segments(segments.len()));
        for segment in segments {
            self.commands.push(Command::data(segment.task_id.index));
        }
    }

    /// Add a primitive to the command buffer.
    pub fn add_prim(
        &mut self,
        prim_cmd: &PrimitiveCommand,
        spatial_node_index: SpatialNodeIndex,
    ) {
        if self.current_spatial_node_index != spatial_node_index {
            self.commands.push(Command::set_spatial_node(spatial_node_index));
            self.current_spatial_node_index = spatial_node_index;
        }

        self.add_cmd(prim_cmd);
    }

    /// Add a cmd to the command buffer.
    pub fn add_cmd(
        &mut self,
        prim_cmd: &PrimitiveCommand,
    ) {
        match *prim_cmd {
            PrimitiveCommand::Simple { prim_instance_index } => {
                self.commands.push(Command::draw_simple_prim(prim_instance_index));
            }
            PrimitiveCommand::Complex { prim_instance_index, gpu_address } => {
                self.commands.push(Command::draw_complex_prim(prim_instance_index));
                self.commands.push(Command::data((gpu_address.u as u32) << 16 | gpu_address.v as u32));
            }
            PrimitiveCommand::Instance { prim_instance_index, gpu_buffer_address } => {
                self.commands.push(Command::draw_instance(prim_instance_index));
                self.commands.push(Command::data((gpu_buffer_address.u as u32) << 16 | gpu_buffer_address.v as u32));
            }
            PrimitiveCommand::Quad { pattern, pattern_input, prim_instance_index, gpu_buffer_address, transform_id, quad_flags, edge_flags, src_color_task_id } => {
                self.commands.push(Command::draw_quad(prim_instance_index));
                self.commands.push(Command::data(pattern as u32));
                self.commands.push(Command::data(pattern_input.0 as u32));
                self.commands.push(Command::data(pattern_input.1 as u32));
                self.commands.push(Command::data(src_color_task_id.index));
                self.commands.push(Command::data((gpu_buffer_address.u as u32) << 16 | gpu_buffer_address.v as u32));
                self.commands.push(Command::data(transform_id.0));
                self.commands.push(Command::data((quad_flags.bits() as u32) << 16 | edge_flags.bits() as u32));
            }
        }
    }

    /// Iterate the command list, calling a provided closure for each primitive draw command.
    pub fn iter_prims<F>(
        &self,
        f: &mut F,
    ) where F: FnMut(&PrimitiveCommand, SpatialNodeIndex, &[RenderTaskId]) {
        let mut current_spatial_node_index = SpatialNodeIndex::INVALID;
        let mut cmd_iter = self.commands.iter();
        // TODO(gw): Consider pre-allocating this / Smallvec if it shows up in profiles.
        let mut segments = Vec::new();

        while let Some(cmd) = cmd_iter.next() {
            let command = cmd.0 & Command::CMD_MASK;
            let param = cmd.0 & Command::PARAM_MASK;

            match command {
                Command::CMD_DRAW_SIMPLE_PRIM => {
                    let prim_instance_index = PrimitiveInstanceIndex(param);
                    let cmd = PrimitiveCommand::simple(prim_instance_index);
                    f(&cmd, current_spatial_node_index, &[]);
                }
                Command::CMD_SET_SPATIAL_NODE => {
                    current_spatial_node_index = SpatialNodeIndex(param);
                }
                Command::CMD_DRAW_COMPLEX_PRIM => {
                    let prim_instance_index = PrimitiveInstanceIndex(param);
                    let data = cmd_iter.next().unwrap();
                    let gpu_address = GpuCacheAddress {
                        u: (data.0 >> 16) as u16,
                        v: (data.0 & 0xffff) as u16,
                    };
                    let cmd = PrimitiveCommand::complex(
                        prim_instance_index,
                        gpu_address,
                    );
                    f(&cmd, current_spatial_node_index, &[]);
                }
                Command::CMD_DRAW_QUAD => {
                    let prim_instance_index = PrimitiveInstanceIndex(param);
                    let pattern = PatternKind::from_u32(cmd_iter.next().unwrap().0);
                    let pattern_input = PatternShaderInput(
                        cmd_iter.next().unwrap().0 as i32,
                        cmd_iter.next().unwrap().0 as i32,
                    );
                    let src_color_task_id = RenderTaskId { index: cmd_iter.next().unwrap().0 };
                    let data = cmd_iter.next().unwrap();
                    let transform_id = TransformPaletteId(cmd_iter.next().unwrap().0);
                    let bits = cmd_iter.next().unwrap().0;
                    let quad_flags = QuadFlags::from_bits((bits >> 16) as u8).unwrap();
                    let edge_flags = EdgeAaSegmentMask::from_bits((bits & 0xff) as u8).unwrap();
                    let gpu_buffer_address = GpuBufferAddress {
                        u: (data.0 >> 16) as u16,
                        v: (data.0 & 0xffff) as u16,
                    };
                    let cmd = PrimitiveCommand::quad(
                        pattern,
                        pattern_input,
                        src_color_task_id,
                        prim_instance_index,
                        gpu_buffer_address,
                        transform_id,
                        quad_flags,
                        edge_flags,
                    );
                    f(&cmd, current_spatial_node_index, &segments);
                    segments.clear()
                }
                Command::CMD_DRAW_INSTANCE => {
                    let prim_instance_index = PrimitiveInstanceIndex(param);
                    let data = cmd_iter.next().unwrap();
                    let gpu_buffer_address = GpuBufferAddress {
                        u: (data.0 >> 16) as u16,
                        v: (data.0 & 0xffff) as u16,
                    };
                    let cmd = PrimitiveCommand::instance(
                        prim_instance_index,
                        gpu_buffer_address,
                    );
                    f(&cmd, current_spatial_node_index, &[]);
                }
                Command::CMD_SET_SEGMENTS => {
                    let count = param;
                    for _ in 0 .. count {
                        segments.push(RenderTaskId { index: cmd_iter.next().unwrap().0 });
                    }
                }
                _ => {
                    unreachable!();
                }
            }
        }
    }
}

/// Abstracts whether a command buffer is being built for a tiled (picture cache)
/// or simple (child surface).
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub enum CommandBufferBuilderKind {
    Tiled {
        // TODO(gw): It might be worth storing this as a 2d-array instead
        //           of a hash map if it ever shows up in profiles. This is
        //           slightly complicated by the sub_slice_index in the
        //           TileKey structure - could have a 2 level array?
        tiles: FastHashMap<TileKey, SurfaceTileDescriptor>,
    },
    Simple {
        render_task_id: RenderTaskId,
        root_task_id: Option<RenderTaskId>,
        dirty_rect: PictureRect,
    },
    Invalid,
}

#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct CommandBufferBuilder {
    pub kind: CommandBufferBuilderKind,

    /// If a command buffer establishes a sub-graph, then at the end of constructing
    /// the surface, the parent surface is supplied as an input dependency, and the
    /// parent surface gets a duplicated (existing) task with the same location, and
    /// with the sub-graph output as an input dependency.
    pub establishes_sub_graph: bool,

    /// If this surface builds a sub-graph, it will mark a task in the filter sub-graph
    /// as a resolve source for the input from the parent surface.
    pub resolve_source: Option<RenderTaskId>,

    /// List of render tasks that depend on the task that will be created for this builder.
    pub extra_dependencies: Vec<RenderTaskId>,
}

impl CommandBufferBuilder {
    pub fn empty() -> Self {
        CommandBufferBuilder {
            kind: CommandBufferBuilderKind::Invalid,
            establishes_sub_graph: false,
            resolve_source: None,
            extra_dependencies: Vec::new(),
        }
    }

    /// Construct a tiled command buffer builder.
    pub fn new_tiled(
        tiles: FastHashMap<TileKey, SurfaceTileDescriptor>,
    ) -> Self {
        CommandBufferBuilder {
            kind: CommandBufferBuilderKind::Tiled {
                tiles,
            },
            establishes_sub_graph: false,
            resolve_source: None,
            extra_dependencies: Vec::new(),
        }
    }

    /// Construct a simple command buffer builder.
    pub fn new_simple(
        render_task_id: RenderTaskId,
        establishes_sub_graph: bool,
        root_task_id: Option<RenderTaskId>,
        dirty_rect: PictureRect,
    ) -> Self {
        CommandBufferBuilder {
            kind: CommandBufferBuilderKind::Simple {
                render_task_id,
                root_task_id,
                dirty_rect,
            },
            establishes_sub_graph,
            resolve_source: None,
            extra_dependencies: Vec::new(),
        }
    }
}

// Index into a command buffer stored in a `CommandBufferList`.
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[derive(Debug, Copy, Clone)]
pub struct CommandBufferIndex(pub u32);

// Container for a list of command buffers that are built for a frame.
pub struct CommandBufferList {
    cmd_buffers: Vec<CommandBuffer>,
}

impl CommandBufferList {
    pub fn new() -> Self {
        CommandBufferList {
            cmd_buffers: Vec::new(),
        }
    }

    pub fn create_cmd_buffer(
        &mut self,
    ) -> CommandBufferIndex {
        let index = CommandBufferIndex(self.cmd_buffers.len() as u32);
        self.cmd_buffers.push(CommandBuffer::new());
        index
    }

    pub fn get(&self, index: CommandBufferIndex) -> &CommandBuffer {
        &self.cmd_buffers[index.0 as usize]
    }

    pub fn get_mut(&mut self, index: CommandBufferIndex) -> &mut CommandBuffer {
        &mut self.cmd_buffers[index.0 as usize]
    }
}

[ Dauer der Verarbeitung: 0.42 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