Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add basic infrastructure for caching Pictures, enable for some blurs. #2651

Merged
merged 1 commit into from Apr 15, 2018
Merged
Changes from all commits
Commits
File filter...
Filter file types
Jump to…
Jump to file
Failed to load files.

Always

Just for now

Add basic infrastructure for caching Pictures, enable for some blurs.

Adds the basic infrastructure for caching the outputs of a
rasterized Picture in the texture cache.

For now, this only applies if the following conditions are met:
 * The picture has a blur filter on it (includes text-shadows).
 * The contents of the picture and clips are in the root
   coordinate system (no rotations / perspective etc).

This covers most real-world use cases of blurs and text-shadows.

Future work:
 * Expand to cache other Picture types (e.g. drop-shadows, other filters).
 * Support caching of complex coordinate system pictures which
   are not animating (and thus worth caching).
 * Support deep comparison of picture elements between display lists.
   (caching only applies during scrolling in this first pass).
  • Loading branch information
gw3583 committed Apr 15, 2018
commit d48fe709a0a852d8e47cffc1486de0c88326374e
@@ -11,12 +11,12 @@ use clip::{ClipSource, ClipStore, ClipWorkItem};
use clip_scroll_tree::{CoordinateSystemId};
use euclid::{TypedTransform3D, vec3};
use glyph_rasterizer::GlyphFormat;
use gpu_cache::{GpuCache, GpuCacheAddress};
use gpu_cache::{GpuCache, GpuCacheAddress, GpuCacheHandle};
use gpu_types::{BrushFlags, BrushInstance, ClipChainRectIndex, ZBufferId, ZBufferIdGenerator};
use gpu_types::{ClipMaskInstance, ClipScrollNodeIndex, RasterizationSpace};
use gpu_types::{CompositePrimitiveInstance, PrimitiveInstance, SimplePrimitiveInstance};
use internal_types::{FastHashMap, SavedTargetIndex, SourceTexture};
use picture::{PictureCompositeMode, PicturePrimitive};
use picture::{PictureCompositeMode, PicturePrimitive, PictureSurface};
use plane_split::{BspSplitter, Polygon, Splitter};
use prim_store::{CachedGradient, ImageSource, PrimitiveIndex, PrimitiveKind, PrimitiveMetadata, PrimitiveStore};
use prim_store::{BrushPrimitive, BrushKind, DeferredResolve, EdgeAaSegmentMask, PictureIndex, PrimitiveRun};
@@ -514,8 +514,12 @@ impl AlphaBatchBuilder {
let pic = &ctx.prim_store.pictures[brush.get_picture_index().0];
let batch = self.batch_list.get_suitable_batch(key, &pic_metadata.screen_rect.as_ref().expect("bug").clipped);

let render_task_id = pic.surface.expect("BUG: unexpected surface in splitting");
let source_task_address = render_tasks.get_task_address(render_task_id);
let source_task_id = pic
.surface
.as_ref()
.expect("BUG: unexpected surface in splitting")
.resolve_render_task_id();
let source_task_address = render_tasks.get_task_address(source_task_id);
let gpu_address = gpu_handle.as_int(gpu_cache);

let instance = CompositePrimitiveInstance::new(
@@ -669,21 +673,18 @@ impl AlphaBatchBuilder {
match filter {
FilterOp::Blur(..) => {
match picture.surface {
Some(cache_task_id) => {
Some(ref surface) => {
let kind = BatchKind::Brush(
BrushBatchKind::Image(ImageBufferKind::Texture2DArray)
);
let (uv_rect_address, textures) = surface.resolve(render_tasks);
let key = BatchKey::new(
kind,
non_segmented_blend_mode,
BatchTextures::render_target_cache(),
textures,
);
let batch = self.batch_list.get_suitable_batch(key, &task_relative_bounding_rect);

let uv_rect_address = render_tasks[cache_task_id]
.get_texture_handle()
.as_int(gpu_cache);

let instance = BrushInstance {
picture_address: task_address,
prim_address: prim_cache_address,
@@ -695,7 +696,7 @@ impl AlphaBatchBuilder {
edge_flags: EdgeAaSegmentMask::empty(),
brush_flags: BrushFlags::empty(),
user_data: [
uv_rect_address,
uv_rect_address.as_int(gpu_cache),
(BrushImageSourceKind::Color as i32) << 16 |
RasterizationSpace::Screen as i32,
picture.extra_gpu_data_handle.as_int(gpu_cache),
@@ -710,10 +711,10 @@ impl AlphaBatchBuilder {
}
}
FilterOp::DropShadow(..) => {
if let Some(cache_task_id) = picture.surface {
// Draw an instance of the shadow first, following by the content.
// Draw an instance of the shadow first, following by the content.

// Both the shadow and the content get drawn as a brush image.
// Both the shadow and the content get drawn as a brush image.
if let Some(ref surface) = picture.surface {
let kind = BatchKind::Brush(
BrushBatchKind::Image(ImageBufferKind::Texture2DArray),
);
@@ -739,6 +740,7 @@ impl AlphaBatchBuilder {
let content_key = BatchKey::new(kind, non_segmented_blend_mode, content_textures);

// Retrieve the UV rect addresses for shadow/content.
let cache_task_id = surface.resolve_render_task_id();
let shadow_uv_rect_address = render_tasks[cache_task_id]
.get_texture_handle()
.as_int(gpu_cache);
@@ -793,7 +795,7 @@ impl AlphaBatchBuilder {
}
_ => {
match picture.surface {
Some(cache_task_id) => {
Some(ref surface) => {
let key = BatchKey::new(
BatchKind::Brush(BrushBatchKind::Blend),
BlendMode::PremultipliedAlpha,
@@ -837,6 +839,7 @@ impl AlphaBatchBuilder {
}
};

let cache_task_id = surface.resolve_render_task_id();
let cache_task_address = render_tasks.get_task_address(cache_task_id);

let instance = BrushInstance {
@@ -868,7 +871,11 @@ impl AlphaBatchBuilder {
}
}
Some(PictureCompositeMode::MixBlend(mode)) => {
let cache_task_id = picture.surface.expect("bug: no surface allocated");
let cache_task_id = picture
.surface
.as_ref()
.expect("bug: no surface allocated")
.resolve_render_task_id();
let backdrop_id = picture.secondary_render_task_id.expect("no backdrop!?");

let key = BatchKey::new(
@@ -907,8 +914,11 @@ impl AlphaBatchBuilder {
false
}
Some(PictureCompositeMode::Blit) => {
let cache_task_id =
picture.surface.expect("bug: no surface allocated");
let cache_task_id = picture
.surface
.as_ref()
.expect("bug: no surface allocated")
.resolve_render_task_id();
let kind = BatchKind::Brush(
BrushBatchKind::Image(ImageBufferKind::Texture2DArray)
);
@@ -1465,6 +1475,43 @@ impl AlphaBatchHelpers for PrimitiveStore {
}
}

impl PictureSurface {
// Retrieve the uv rect handle, and texture for a picture surface.
fn resolve<'a>(
&'a self,
render_tasks: &'a RenderTaskTree,
) -> (&'a GpuCacheHandle, BatchTextures) {
match *self {
PictureSurface::TextureCache(ref cache_item) => {
(
&cache_item.uv_rect_handle,
BatchTextures::color(cache_item.texture_id),
)
}
PictureSurface::RenderTask(task_id) => {
(
render_tasks[task_id].get_texture_handle(),
BatchTextures::render_target_cache(),
)
}
}
}

// Retrieve the render task id for a picture surface. Should only
// be used where it's known that this picture surface will never
// be persisted in the texture cache.
fn resolve_render_task_id(&self) -> RenderTaskId {
match *self {
PictureSurface::TextureCache(..) => {
panic!("BUG: unexpectedly cached render task");
}
PictureSurface::RenderTask(task_id) => {
task_id
}
}
}
}

pub fn resolve_image(
request: ImageRequest,
resource_cache: &ResourceCache,
@@ -558,6 +558,7 @@ pub struct ClipChain {
pub combined_outer_screen_rect: DeviceIntRect,
pub combined_inner_screen_rect: DeviceIntRect,
pub nodes: ClipChainNodeRef,
pub has_non_root_coord_system: bool,
}

impl ClipChain {
@@ -567,6 +568,7 @@ impl ClipChain {
combined_inner_screen_rect: *screen_rect,
combined_outer_screen_rect: *screen_rect,
nodes: None,
has_non_root_coord_system: false,
}
}

@@ -599,6 +601,8 @@ impl ClipChain {
self.combined_inner_screen_rect.intersection(&new_node.screen_inner_rect)
.unwrap_or_else(DeviceIntRect::zero);

self.has_non_root_coord_system |= new_node.work_item.coordinate_system_id != CoordinateSystemId::root();

self.nodes = Some(Arc::new(new_node));
}
}
@@ -13,6 +13,7 @@ use gpu_cache::GpuCache;
use gpu_types::{ClipChainRectIndex, ClipScrollNodeData};
use hit_test::{HitTester, HitTestingRun};
use internal_types::{FastHashMap};
use picture::PictureSurface;
use prim_store::{CachedGradient, PrimitiveIndex, PrimitiveRun, PrimitiveStore};
use profiler::{FrameProfileCounters, GpuCacheProfileCounters, TextureCacheProfileCounters};
use render_backend::FrameId;
@@ -80,12 +81,14 @@ pub struct PictureContext<'a> {

pub struct PictureState {
pub tasks: Vec<RenderTaskId>,
pub has_non_root_coord_system: bool,
}

impl PictureState {
pub fn new() -> PictureState {
PictureState {
tasks: Vec::new(),
has_non_root_coord_system: false,
}
}
}
@@ -231,7 +234,7 @@ impl FrameBuilder {
);

let render_task_id = frame_state.render_tasks.add(root_render_task);
pic.surface = Some(render_task_id);
pic.surface = Some(PictureSurface::RenderTask(render_task_id));
Some(render_task_id)
}

ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.