Commit b059d7c6 authored by Glenn Watson's avatar Glenn Watson
Browse files

Bug 1676559 - Pt 8 - Move render target pool from renderer to frame building. r=nical,jnicol

This is an incremental but important step to implementing render
tasks as a proper graph.

By moving the render target management to the frame building step,
we know the texture_id of all sub-passes before the batching is
done for any passes that use these as inputs. This means that
we can directly reference the texture_id during batch, rather
that the old `RenderTaskCache` and `PrevPassAlpha` / `PrevPassColor`
enum fields (although removal of all these will be done in the
next patch).

Another advantage of this is that we have much better knowledge
of which targets are required for rendering a given frame, so
these can be allocated up front at the start of a frame. This
may be a better allocation pattern for some drivers. We also
have better knowledge available on when a texture can be
invalidated, and the render target pool management is simpler since
it is the same as the way other texture cache textures are handled.

Differential Revision: https://phabricator.services.mozilla.com/D98547
parent 5bfe12a2
Loading
Loading
Loading
Loading
+19 −9
Original line number Diff line number Diff line
@@ -16,7 +16,7 @@ use crate::gpu_types::{PrimitiveInstanceData, RasterizationSpace, GlyphInstance}
use crate::gpu_types::{PrimitiveHeader, PrimitiveHeaderIndex, TransformPaletteId, TransformPalette};
use crate::gpu_types::{ImageBrushData, get_shader_opacity, BoxShadowData};
use crate::gpu_types::{ClipMaskInstanceCommon, ClipMaskInstanceImage, ClipMaskInstanceRect, ClipMaskInstanceBoxShadow};
use crate::internal_types::{FastHashMap, SavedTargetIndex, Swizzle, TextureSource, Filter, DeferredResolveIndex};
use crate::internal_types::{FastHashMap, Swizzle, TextureSource, Filter, DeferredResolveIndex};
use crate::picture::{Picture3DContext, PictureCompositeMode, PicturePrimitive, ClusterFlags};
use crate::prim_store::{DeferredResolve, PrimitiveInstanceKind, ClipData};
use crate::prim_store::{VisibleGradientTile, PrimitiveInstance, PrimitiveOpacity, SegmentInstanceIndex};
@@ -1627,9 +1627,12 @@ impl BatchBuilder {
                                        let secondary_id = picture.secondary_render_task_id.expect("no secondary!?");
                                        let content_source = {
                                            let secondary_task = &render_tasks[secondary_id];
                                            let saved_index = secondary_task.saved_index.expect("no saved index!?");
                                            debug_assert_ne!(saved_index, SavedTargetIndex::PENDING);
                                            TextureSource::RenderTaskCache(saved_index, Swizzle::default())
                                            let texture_id = secondary_task.get_target_texture();
                                            TextureSource::TextureCache(
                                                texture_id,
                                                ImageBufferKind::Texture2DArray,
                                                Swizzle::default(),
                                            )
                                        };

                                        // Build BatchTextures for shadow/content
@@ -1966,14 +1969,21 @@ impl BatchBuilder {
                                let uv_rect_address = render_tasks[cache_task_id]
                                    .get_texture_address(gpu_cache)
                                    .as_int();
                                let textures = match render_tasks[cache_task_id].saved_index {
                                    Some(saved_index) => BatchTextures::new(
                                        TextureSource::RenderTaskCache(saved_index, Swizzle::default()),
                                let cache_render_task = &render_tasks[cache_task_id];
                                let textures = if cache_render_task.save_target {
                                    let texture_id = cache_render_task.get_target_texture();
                                    BatchTextures::new(
                                        TextureSource::TextureCache(
                                            texture_id,
                                            ImageBufferKind::Texture2DArray,
                                            Swizzle::default(),
                                        ),
                                        TextureSource::PrevPassAlpha,
                                        TextureSource::Invalid,
                                        clip_mask_texture_id,
                                    ),
                                    None => BatchTextures::render_target_cache(clip_mask_texture_id),
                                    )
                                } else {
                                    BatchTextures::render_target_cache(clip_mask_texture_id)
                                };
                                let batch_params = BrushBatchParameters::shared(
                                    BrushBatchKind::Image(ImageBufferKind::Texture2DArray),
+4 −0
Original line number Diff line number Diff line
@@ -486,6 +486,10 @@ impl Texture {
        self.last_frame_used == frame_id
    }

    pub fn is_render_target(&self) -> bool {
        !self.fbos.is_empty()
    }

    /// Returns true if this texture was used within `threshold` frames of
    /// the current frame.
    pub fn used_recently(&self, current_frame_id: GpuFrameId, threshold: usize) -> bool {
+106 −30
Original line number Diff line number Diff line
@@ -12,7 +12,7 @@ use crate::debug_render::DebugItem;
use crate::gpu_cache::{GpuCache, GpuCacheHandle};
use crate::gpu_types::{PrimitiveHeaders, TransformPalette, ZBufferIdGenerator};
use crate::gpu_types::TransformData;
use crate::internal_types::{FastHashMap, PlaneSplitter, SavedTargetIndex};
use crate::internal_types::{CacheTextureId, FastHashMap, PlaneSplitter};
use crate::picture::{DirtyRegion, PictureUpdateState, SliceId, TileCacheInstance};
use crate::picture::{SurfaceInfo, SurfaceIndex, ROOT_SURFACE_INDEX};
use crate::picture::{BackdropKind, SubpixelMode, TileCacheLogger, RasterConfig, PictureCompositeMode};
@@ -549,6 +549,15 @@ impl FrameBuilder {
            let use_dual_source_blending = scene.config.dual_source_blending_is_enabled &&
                                           scene.config.dual_source_blending_is_supported;

            // As an incremental approach to moving to a proper DAG for render tasks, we
            // implement the existing saved texture functionality here.

            // Textures that are marked for saving until the end of the frame
            let mut saved_texture_ids = Vec::new();
            // Textures that are written to on this pass and should be returned / invalidated
            // on the following pass.
            let mut active_texture_ids = Vec::new();

            for pass in &mut passes {
                let mut ctx = RenderTargetContext {
                    global_device_pixel_scale,
@@ -583,6 +592,60 @@ impl FrameBuilder {

                has_texture_cache_tasks |= !pass.texture_cache.is_empty();
                has_texture_cache_tasks |= !pass.picture_cache.is_empty();

                // Check which textures in this pass need to be saved until the end of
                // the frame. This will all disappear once render task graph is a full DAG.
                let mut save_color = false;
                let mut save_alpha = false;

                for task_id in &pass.tasks {
                    let task = &render_tasks[*task_id];
                    match task.target_kind() {
                        RenderTargetKind::Color => {
                            save_color |= task.save_target;
                        }
                        RenderTargetKind::Alpha => {
                            save_alpha |= task.save_target;
                        }
                    }
                }

                // Return previous frame's textures to the target pool, so they are available
                // for use on subsequent passes. Also include these in the list for the renderer
                // to immediately invalidate once they are no longer used.
                for texture_id in active_texture_ids.drain(..) {
                    resource_cache.return_render_target_to_pool(texture_id);
                    pass.textures_to_invalidate.push(texture_id);
                }

                if let Some(texture_id) = pass.color.texture_id {
                    if save_color {
                        saved_texture_ids.push(texture_id);
                    } else {
                        active_texture_ids.push(texture_id);
                    }
                }

                if let Some(texture_id) = pass.alpha.texture_id {
                    if save_alpha {
                        saved_texture_ids.push(texture_id);
                    } else {
                        active_texture_ids.push(texture_id);
                    }
                }
            }

            assert!(active_texture_ids.is_empty());

            // At the end of the pass loop, return any saved textures to the pool. Also
            // add them to the final pass to invalidate those textures (which will be the
            // pass that writes to picture cache tiles or texture cache targets). This is
            // mostly implicit in the current scheme, but will become a lot clearer and
            // more explicit once we implement the full render task DAG.

            for texture_id in saved_texture_ids.drain(..) {
                resource_cache.return_render_target_to_pool(texture_id);
                passes.last_mut().unwrap().textures_to_invalidate.push(texture_id);
            }

            let mut ctx = RenderTargetContext {
@@ -726,23 +789,6 @@ pub fn build_render_pass(
) {
    profile_scope!("build_render_pass");

    let saved_color = if pass.tasks.iter().any(|&task_id| {
        let t = &render_tasks[task_id];
        t.target_kind() == RenderTargetKind::Color && t.saved_index.is_some()
    }) {
        Some(render_tasks.save_target())
    } else {
        None
    };
    let saved_alpha = if pass.tasks.iter().any(|&task_id| {
        let t = &render_tasks[task_id];
        t.target_kind() == RenderTargetKind::Alpha && t.saved_index.is_some()
    }) {
        Some(render_tasks.save_target())
    } else {
        None
    };

    // Collect a list of picture cache tasks, keyed by picture index.
    // This allows us to only walk that picture root once, adding the
    // primitives to all relevant batches at the same time.
@@ -765,7 +811,7 @@ pub fn build_render_pass(
                        RenderTargetKind::Color => pass.color.allocate(size),
                        RenderTargetKind::Alpha => pass.alpha.allocate(size),
                    };
                    *origin = Some((alloc_origin, target_index));
                    *origin = Some((alloc_origin, CacheTextureId::INVALID, target_index));
                    (None, target_index.0)
                }
                RenderTaskLocation::PictureCache { .. } => {
@@ -789,15 +835,6 @@ pub fn build_render_pass(
                }
            };

            // Replace the pending saved index with a real one
            if let Some(index) = task.saved_index {
                assert_eq!(index, SavedTargetIndex::PENDING);
                task.saved_index = match target_kind {
                    RenderTargetKind::Color => saved_color,
                    RenderTargetKind::Alpha => saved_alpha,
                };
            }

            // Give the render task an opportunity to add any
            // information to the GPU cache, if appropriate.
            let (target_rect, target_index) = task.get_target_rect();
@@ -988,7 +1025,6 @@ pub fn build_render_pass(
        gpu_cache,
        render_tasks,
        deferred_resolves,
        saved_color,
        prim_headers,
        transforms,
        z_generator,
@@ -999,12 +1035,52 @@ pub fn build_render_pass(
        gpu_cache,
        render_tasks,
        deferred_resolves,
        saved_alpha,
        prim_headers,
        transforms,
        z_generator,
        composite_state,
    );

    // Now that the passes have been built, we know what the texture_id is for this surface
    // (since we know the layer count and texture size). Step through the tasks on this
    // texture and store that in the task location. This is used so that tasks that get added
    // on following passes can directly access and reference the texture_id, rather than
    // referring to PrevPassAlpha/Color. Again, this will become a lot simpler once we
    // have the full DAG in place (and once sub-passes are individual textures rather than
    // a single texture array).

    for &task_id in &pass.tasks {
        let task = &mut render_tasks[task_id];
        let target_kind = task.target_kind();

        match task.location {
            RenderTaskLocation::TextureCache { .. } |
            RenderTaskLocation::PictureCache { .. } => {}

            RenderTaskLocation::Dynamic(None, _) => {
                unreachable!();
            }

            RenderTaskLocation::Dynamic(Some((_, ref mut texture_id, _)), _) => {
                assert_eq!(*texture_id, CacheTextureId::INVALID);

                match target_kind {
                    RenderTargetKind::Color => {
                        *texture_id = pass
                            .color
                            .texture_id
                            .expect("bug: color texture must be allocated by now");
                    }
                    RenderTargetKind::Alpha => {
                        *texture_id = pass
                            .alpha
                            .texture_id
                            .expect("bug: alpha texture must be allocated by now");
                    }
                }
            }
        }
    }
}

/// A rendering-oriented representation of the frame built by the render backend
+6 −22
Original line number Diff line number Diff line
@@ -235,6 +235,10 @@ pub struct SwizzleSettings {
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct CacheTextureId(pub u32);

impl CacheTextureId {
    pub const INVALID: CacheTextureId = CacheTextureId(!0);
}

/// Canonical type for texture layer indices.
///
/// WebRender is currently not very consistent about layer index types. Some
@@ -248,21 +252,6 @@ pub struct CacheTextureId(pub u32);
/// the device module when making calls into the platform layer.
pub type LayerIndex = usize;

/// Identifies a render pass target that is persisted until the end of the frame.
///
/// By default, only the targets of the immediately-preceding pass are bound as
/// inputs to the next pass. However, tasks can opt into having their target
/// preserved in a list until the end of the frame, and this type specifies the
/// index in that list.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct SavedTargetIndex(pub u32);

impl SavedTargetIndex {
    pub const PENDING: Self = SavedTargetIndex(!0);
}

#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
@@ -276,17 +265,13 @@ pub enum TextureSource {
    /// Equivalent to `None`, allowing us to avoid using `Option`s everywhere.
    Invalid,
    /// An entry in the texture cache.
    TextureCache(CacheTextureId, Swizzle),
    TextureCache(CacheTextureId, ImageBufferKind, Swizzle),
    /// An external image texture, mananged by the embedding.
    External(DeferredResolveIndex, ImageBufferKind),
    /// The alpha target of the immediately-preceding pass.
    PrevPassAlpha,
    /// The color target of the immediately-preceding pass.
    PrevPassColor,
    /// A render target from an earlier pass. Unlike the immediately-preceding
    /// passes, these are not made available automatically, but are instead
    /// opt-in by the `RenderTask` (see `mark_for_saving()`).
    RenderTaskCache(SavedTargetIndex, Swizzle),
    /// Select a dummy 1x1 white texture. This can be used by image
    /// shaders that want to draw a solid color.
    Dummy,
@@ -295,14 +280,13 @@ pub enum TextureSource {
impl TextureSource {
    pub fn image_buffer_kind(&self) -> ImageBufferKind {
        match *self {
            TextureSource::TextureCache(..) => ImageBufferKind::Texture2D,
            TextureSource::TextureCache(_, image_buffer_kind, _) => image_buffer_kind,

            TextureSource::External(_, image_buffer_kind) => image_buffer_kind,

            // Render tasks use texture arrays for now.
            TextureSource::PrevPassAlpha
            | TextureSource::PrevPassColor
            | TextureSource::RenderTaskCache(..)
            | TextureSource::Dummy => ImageBufferKind::Texture2DArray,


+2 −0
Original line number Diff line number Diff line
@@ -851,6 +851,8 @@ bitflags!{
        const RENDER_TASKS = 0b0001;
        ///
        const TEXTURE_CACHE = 0b00001;
        /// Clear render target pool
        const RENDER_TARGETS = 0b000001;
    }
}

Loading