зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1514942 - Update webrender to commit 112669978e1c7970145f47e3b28127538715a2e5 (WR PR #3393). r=kats
https://github.com/servo/webrender/pull/3393 Differential Revision: https://phabricator.services.mozilla.com/D14852 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
64b3a44ed2
Коммит
48eec304c7
|
@ -1 +1 @@
|
|||
b0e4a13491f9f780222d3aa374fa8f0c07508e73
|
||||
112669978e1c7970145f47e3b28127538715a2e5
|
||||
|
|
|
@ -15,10 +15,12 @@ use gpu_types::{PrimitiveInstanceData, RasterizationSpace, GlyphInstance};
|
|||
use gpu_types::{PrimitiveHeader, PrimitiveHeaderIndex, TransformPaletteId, TransformPalette};
|
||||
use internal_types::{FastHashMap, SavedTargetIndex, TextureSource};
|
||||
use picture::{Picture3DContext, PictureCompositeMode, PicturePrimitive, PictureSurface};
|
||||
use prim_store::{DeferredResolve, PrimitiveTemplateKind, PrimitiveDataStore};
|
||||
use prim_store::{EdgeAaSegmentMask, ImageSource, PrimitiveInstanceKind};
|
||||
use prim_store::{DeferredResolve, PrimitiveTemplateKind};
|
||||
use prim_store::{EdgeAaSegmentMask, PrimitiveInstanceKind};
|
||||
use prim_store::{VisibleGradientTile, PrimitiveInstance, PrimitiveOpacity, SegmentInstanceIndex};
|
||||
use prim_store::{BrushSegment, ClipMaskKind, ClipTaskIndex};
|
||||
use prim_store::image::ImageSource;
|
||||
use render_backend::FrameResources;
|
||||
use render_task::{RenderTaskAddress, RenderTaskId, RenderTaskTree};
|
||||
use renderer::{BlendMode, ImageBufferKind, ShaderColorMode};
|
||||
use renderer::BLOCKS_PER_UV_RECT;
|
||||
|
@ -549,10 +551,10 @@ impl AlphaBatchBuilder {
|
|||
render_tasks,
|
||||
).unwrap_or(OPAQUE_TASK_ADDRESS);
|
||||
|
||||
let prim_data = &ctx.resources.as_common_data(&prim_instance);
|
||||
let prim_common_data = &ctx.resources.as_common_data(&prim_instance);
|
||||
let prim_rect = LayoutRect::new(
|
||||
prim_instance.prim_origin,
|
||||
prim_data.prim_size,
|
||||
prim_common_data.prim_size,
|
||||
);
|
||||
|
||||
match prim_instance.kind {
|
||||
|
@ -1521,26 +1523,20 @@ impl AlphaBatchBuilder {
|
|||
);
|
||||
}
|
||||
PrimitiveInstanceKind::YuvImage { data_handle, segment_instance_index, .. } => {
|
||||
let prim_data = &ctx.resources.prim_data_store[data_handle];
|
||||
let (format, yuv_key, image_rendering, color_depth, color_space) = match prim_data.kind {
|
||||
PrimitiveTemplateKind::YuvImage { ref format, yuv_key, ref image_rendering, ref color_depth, ref color_space, .. } => {
|
||||
(format, yuv_key, image_rendering, color_depth, color_space)
|
||||
}
|
||||
_ => unreachable!()
|
||||
};
|
||||
let yuv_image_data = &ctx.resources.yuv_image_data_store[data_handle].kind;
|
||||
let mut textures = BatchTextures::no_texture();
|
||||
let mut uv_rect_addresses = [0; 3];
|
||||
|
||||
//yuv channel
|
||||
let channel_count = format.get_plane_num();
|
||||
let channel_count = yuv_image_data.format.get_plane_num();
|
||||
debug_assert!(channel_count <= 3);
|
||||
for channel in 0 .. channel_count {
|
||||
let image_key = yuv_key[channel];
|
||||
let image_key = yuv_image_data.yuv_key[channel];
|
||||
|
||||
let cache_item = resolve_image(
|
||||
ImageRequest {
|
||||
key: image_key,
|
||||
rendering: *image_rendering,
|
||||
rendering: yuv_image_data.image_rendering,
|
||||
tile: None,
|
||||
},
|
||||
ctx.resource_cache,
|
||||
|
@ -1560,16 +1556,16 @@ impl AlphaBatchBuilder {
|
|||
// All yuv textures should be the same type.
|
||||
let buffer_kind = get_buffer_kind(textures.colors[0]);
|
||||
assert!(
|
||||
textures.colors[1 .. format.get_plane_num()]
|
||||
textures.colors[1 .. yuv_image_data.format.get_plane_num()]
|
||||
.iter()
|
||||
.all(|&tid| buffer_kind == get_buffer_kind(tid))
|
||||
);
|
||||
|
||||
let kind = BrushBatchKind::YuvImage(
|
||||
buffer_kind,
|
||||
*format,
|
||||
*color_depth,
|
||||
*color_space,
|
||||
yuv_image_data.format,
|
||||
yuv_image_data.color_depth,
|
||||
yuv_image_data.color_space,
|
||||
);
|
||||
|
||||
let batch_params = BrushBatchParameters::shared(
|
||||
|
@ -1585,7 +1581,7 @@ impl AlphaBatchBuilder {
|
|||
|
||||
let specified_blend_mode = BlendMode::PremultipliedAlpha;
|
||||
|
||||
let non_segmented_blend_mode = if !prim_data.opacity.is_opaque ||
|
||||
let non_segmented_blend_mode = if !prim_common_data.opacity.is_opaque ||
|
||||
prim_instance.clip_task_index != ClipTaskIndex::INVALID ||
|
||||
transform_kind == TransformedRectKind::Complex
|
||||
{
|
||||
|
@ -1596,7 +1592,7 @@ impl AlphaBatchBuilder {
|
|||
|
||||
debug_assert!(segment_instance_index != SegmentInstanceIndex::INVALID);
|
||||
let (prim_cache_address, segments) = if segment_instance_index == SegmentInstanceIndex::UNUSED {
|
||||
(gpu_cache.get_address(&prim_data.gpu_cache_handle), None)
|
||||
(gpu_cache.get_address(&prim_common_data.gpu_cache_handle), None)
|
||||
} else {
|
||||
let segment_instance = &ctx.scratch.segment_instances[segment_instance_index];
|
||||
let segments = Some(&ctx.scratch.segments[segment_instance.segments_range]);
|
||||
|
@ -1620,7 +1616,7 @@ impl AlphaBatchBuilder {
|
|||
|
||||
self.add_segmented_prim_to_batch(
|
||||
segments,
|
||||
prim_data.opacity,
|
||||
prim_common_data.opacity,
|
||||
&batch_params,
|
||||
specified_blend_mode,
|
||||
non_segmented_blend_mode,
|
||||
|
@ -1635,27 +1631,22 @@ impl AlphaBatchBuilder {
|
|||
);
|
||||
}
|
||||
PrimitiveInstanceKind::Image { data_handle, image_instance_index, .. } => {
|
||||
let prim_data = &ctx.resources.prim_data_store[data_handle];
|
||||
let (source, alpha_type, key, image_rendering) = match prim_data.kind {
|
||||
PrimitiveTemplateKind::Image { ref source, alpha_type, key, image_rendering, .. } => {
|
||||
(source, alpha_type, key, image_rendering)
|
||||
}
|
||||
_ => unreachable!()
|
||||
};
|
||||
let image_data = &ctx.resources.image_data_store[data_handle].kind;
|
||||
let common_data = &ctx.resources.image_data_store[data_handle].common;
|
||||
let image_instance = &ctx.prim_store.images[image_instance_index];
|
||||
let opacity_binding = ctx.prim_store.get_opacity_binding(image_instance.opacity_binding_index);
|
||||
let specified_blend_mode = match alpha_type {
|
||||
let specified_blend_mode = match image_data.alpha_type {
|
||||
AlphaType::PremultipliedAlpha => BlendMode::PremultipliedAlpha,
|
||||
AlphaType::Alpha => BlendMode::Alpha,
|
||||
};
|
||||
let request = ImageRequest {
|
||||
key: key,
|
||||
rendering: image_rendering,
|
||||
key: image_data.key,
|
||||
rendering: image_data.image_rendering,
|
||||
tile: None,
|
||||
};
|
||||
|
||||
if image_instance.visible_tiles.is_empty() {
|
||||
let cache_item = match *source {
|
||||
let cache_item = match image_data.source {
|
||||
ImageSource::Default => {
|
||||
resolve_image(
|
||||
request,
|
||||
|
@ -1681,7 +1672,7 @@ impl AlphaBatchBuilder {
|
|||
let textures = BatchTextures::color(cache_item.texture_id);
|
||||
|
||||
let opacity = PrimitiveOpacity::from_alpha(opacity_binding);
|
||||
let opacity = opacity.combine(prim_data.opacity);
|
||||
let opacity = opacity.combine(common_data.opacity);
|
||||
|
||||
let non_segmented_blend_mode = if !opacity.is_opaque ||
|
||||
prim_instance.clip_task_index != ClipTaskIndex::INVALID ||
|
||||
|
@ -1696,7 +1687,7 @@ impl AlphaBatchBuilder {
|
|||
BrushBatchKind::Image(get_buffer_kind(cache_item.texture_id)),
|
||||
textures,
|
||||
[
|
||||
ShaderColorMode::Image as i32 | ((alpha_type as i32) << 16),
|
||||
ShaderColorMode::Image as i32 | ((image_data.alpha_type as i32) << 16),
|
||||
RasterizationSpace::Local as i32,
|
||||
get_shader_opacity(opacity_binding),
|
||||
],
|
||||
|
@ -1705,7 +1696,7 @@ impl AlphaBatchBuilder {
|
|||
|
||||
debug_assert!(image_instance.segment_instance_index != SegmentInstanceIndex::INVALID);
|
||||
let (prim_cache_address, segments) = if image_instance.segment_instance_index == SegmentInstanceIndex::UNUSED {
|
||||
(gpu_cache.get_address(&prim_data.gpu_cache_handle), None)
|
||||
(gpu_cache.get_address(&common_data.gpu_cache_handle), None)
|
||||
} else {
|
||||
let segment_instance = &ctx.scratch.segment_instances[image_instance.segment_instance_index];
|
||||
let segments = Some(&ctx.scratch.segments[segment_instance.segments_range]);
|
||||
|
@ -1749,7 +1740,7 @@ impl AlphaBatchBuilder {
|
|||
gpu_cache,
|
||||
deferred_resolves,
|
||||
request.with_tile(tile.tile_offset),
|
||||
alpha_type,
|
||||
image_data.alpha_type,
|
||||
get_shader_opacity(opacity_binding),
|
||||
) {
|
||||
let prim_cache_address = gpu_cache.get_address(&tile.handle);
|
||||
|
@ -2271,22 +2262,18 @@ impl BrushBatchParameters {
|
|||
impl PrimitiveInstance {
|
||||
pub fn is_cacheable(
|
||||
&self,
|
||||
prim_data_store: &PrimitiveDataStore,
|
||||
resources: &FrameResources,
|
||||
resource_cache: &ResourceCache,
|
||||
) -> bool {
|
||||
let image_key = match self.kind {
|
||||
PrimitiveInstanceKind::Image { data_handle, .. } |
|
||||
PrimitiveInstanceKind::Image { data_handle, .. } => {
|
||||
let image_data = &resources.image_data_store[data_handle].kind;
|
||||
image_data.key
|
||||
}
|
||||
PrimitiveInstanceKind::YuvImage { data_handle, .. } => {
|
||||
let prim_data = &prim_data_store[data_handle];
|
||||
match prim_data.kind {
|
||||
PrimitiveTemplateKind::YuvImage { ref yuv_key, .. } => {
|
||||
yuv_key[0]
|
||||
}
|
||||
PrimitiveTemplateKind::Image { key, .. } => {
|
||||
key
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
let yuv_image_data =
|
||||
&resources.yuv_image_data_store[data_handle].kind;
|
||||
yuv_image_data.yuv_key[0]
|
||||
}
|
||||
PrimitiveInstanceKind::Picture { .. } |
|
||||
PrimitiveInstanceKind::TextRun { .. } |
|
||||
|
|
|
@ -27,6 +27,7 @@ use prim_store::{PrimitiveKey, PrimitiveSceneData, PrimitiveInstanceKind, NinePa
|
|||
use prim_store::{PrimitiveStore, PrimitiveStoreStats, LineDecorationCacheKey};
|
||||
use prim_store::{ScrollNodeAndClipChain, PictureIndex, register_prim_chase_id, get_line_decoration_sizes};
|
||||
use prim_store::gradient::{GradientStopKey, LinearGradient, RadialGradient, RadialGradientParams};
|
||||
use prim_store::image::{Image, YuvImage};
|
||||
use prim_store::text_run::TextRun;
|
||||
use render_backend::{DocumentView};
|
||||
use resource_cache::{FontInstanceMap, ImageRequest};
|
||||
|
@ -1820,7 +1821,9 @@ impl<'a> DisplayListFlattener<'a> {
|
|||
|
||||
for item in &items {
|
||||
match item {
|
||||
// TODO(djg): ugh. de-duplicate this code.
|
||||
ShadowItem::Image(ref pending_image) => {
|
||||
self.add_shadow_prim(&pending_shadow, pending_image, &mut prims)
|
||||
}
|
||||
ShadowItem::Primitive(ref pending_primitive) => {
|
||||
self.add_shadow_prim(&pending_shadow, pending_primitive, &mut prims)
|
||||
}
|
||||
|
@ -1897,6 +1900,9 @@ impl<'a> DisplayListFlattener<'a> {
|
|||
self.add_primitive_to_draw_list(shadow_prim_instance);
|
||||
}
|
||||
}
|
||||
ShadowItem::Image(pending_image) => {
|
||||
self.add_shadow_prim_to_draw_list(pending_image)
|
||||
},
|
||||
ShadowItem::Primitive(pending_primitive) => {
|
||||
self.add_shadow_prim_to_draw_list(pending_primitive)
|
||||
},
|
||||
|
@ -2415,7 +2421,7 @@ impl<'a> DisplayListFlattener<'a> {
|
|||
clip_and_scroll,
|
||||
&info,
|
||||
Vec::new(),
|
||||
PrimitiveKeyKind::Image {
|
||||
Image {
|
||||
key: image_key,
|
||||
tile_spacing: tile_spacing.into(),
|
||||
stretch_size: stretch_size.into(),
|
||||
|
@ -2443,11 +2449,11 @@ impl<'a> DisplayListFlattener<'a> {
|
|||
YuvData::InterleavedYCbCr(plane_0) => [plane_0, ImageKey::DUMMY, ImageKey::DUMMY],
|
||||
};
|
||||
|
||||
self.add_primitive(
|
||||
self.add_nonshadowable_primitive(
|
||||
clip_and_scroll,
|
||||
info,
|
||||
Vec::new(),
|
||||
PrimitiveKeyKind::YuvImage {
|
||||
YuvImage {
|
||||
color_depth,
|
||||
yuv_key,
|
||||
format,
|
||||
|
@ -2669,10 +2675,17 @@ pub struct PendingShadow {
|
|||
|
||||
pub enum ShadowItem {
|
||||
Shadow(PendingShadow),
|
||||
Image(PendingPrimitive<Image>),
|
||||
Primitive(PendingPrimitive<PrimitiveKeyKind>),
|
||||
TextRun(PendingPrimitive<TextRun>),
|
||||
}
|
||||
|
||||
impl From<PendingPrimitive<Image>> for ShadowItem {
|
||||
fn from(image: PendingPrimitive<Image>) -> Self {
|
||||
ShadowItem::Image(image)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<PendingPrimitive<PrimitiveKeyKind>> for ShadowItem {
|
||||
fn from(container: PendingPrimitive<PrimitiveKeyKind>) -> Self {
|
||||
ShadowItem::Primitive(container)
|
||||
|
|
|
@ -21,7 +21,7 @@ use internal_types::FastHashSet;
|
|||
use plane_split::{Clipper, Polygon, Splitter};
|
||||
use prim_store::{PictureIndex, PrimitiveInstance, SpaceMapper, VisibleFace, PrimitiveInstanceKind};
|
||||
use prim_store::{get_raster_rects, CoordinateSpaceMapping, PointKey};
|
||||
use prim_store::{OpacityBindingStorage, PrimitiveTemplateKind, ImageInstanceStorage, OpacityBindingIndex, SizeKey};
|
||||
use prim_store::{OpacityBindingStorage, ImageInstanceStorage, OpacityBindingIndex, SizeKey};
|
||||
use print_tree::PrintTreePrinter;
|
||||
use render_backend::FrameResources;
|
||||
use render_task::{ClearMode, RenderTask, RenderTaskCacheEntryHandle, TileBlit};
|
||||
|
@ -784,7 +784,7 @@ impl TileCache {
|
|||
|
||||
// Some primitives can not be cached (e.g. external video images)
|
||||
let is_cacheable = prim_instance.is_cacheable(
|
||||
&resources.prim_data_store,
|
||||
&resources,
|
||||
resource_cache,
|
||||
);
|
||||
|
||||
|
@ -809,7 +809,7 @@ impl TileCache {
|
|||
}
|
||||
}
|
||||
PrimitiveInstanceKind::Image { data_handle, image_instance_index, .. } => {
|
||||
let prim_data = &resources.prim_data_store[data_handle];
|
||||
let image_data = &resources.image_data_store[data_handle].kind;
|
||||
let image_instance = &image_instances[image_instance_index];
|
||||
let opacity_binding_index = image_instance.opacity_binding_index;
|
||||
|
||||
|
@ -822,25 +822,11 @@ impl TileCache {
|
|||
}
|
||||
}
|
||||
|
||||
match prim_data.kind {
|
||||
PrimitiveTemplateKind::Image { key, .. } => {
|
||||
image_keys.push(key);
|
||||
}
|
||||
_ => {
|
||||
unreachable!();
|
||||
}
|
||||
}
|
||||
image_keys.push(image_data.key);
|
||||
}
|
||||
PrimitiveInstanceKind::YuvImage { data_handle, .. } => {
|
||||
let prim_data = &resources.prim_data_store[data_handle];
|
||||
match prim_data.kind {
|
||||
PrimitiveTemplateKind::YuvImage { ref yuv_key, .. } => {
|
||||
image_keys.extend_from_slice(yuv_key);
|
||||
}
|
||||
_ => {
|
||||
unreachable!();
|
||||
}
|
||||
}
|
||||
let yuv_image_data = &resources.yuv_image_data_store[data_handle].kind;
|
||||
image_keys.extend_from_slice(&yuv_image_data.yuv_key);
|
||||
}
|
||||
PrimitiveInstanceKind::TextRun { .. } |
|
||||
PrimitiveInstanceKind::LineDecoration { .. } |
|
||||
|
@ -1410,11 +1396,12 @@ impl PrimitiveList {
|
|||
PrimitiveInstanceKind::NormalBorder { data_handle, .. } |
|
||||
PrimitiveInstanceKind::ImageBorder { data_handle, .. } |
|
||||
PrimitiveInstanceKind::Rectangle { data_handle, .. } |
|
||||
PrimitiveInstanceKind::YuvImage { data_handle, .. } |
|
||||
PrimitiveInstanceKind::Image { data_handle, .. } |
|
||||
PrimitiveInstanceKind::Clear { data_handle, .. } => {
|
||||
&resources.prim_interner[data_handle]
|
||||
}
|
||||
PrimitiveInstanceKind::Image { data_handle, .. } => {
|
||||
&resources.image_interner[data_handle]
|
||||
}
|
||||
PrimitiveInstanceKind::LinearGradient { data_handle, .. } => {
|
||||
&resources.linear_grad_interner[data_handle]
|
||||
}
|
||||
|
@ -1424,6 +1411,9 @@ impl PrimitiveList {
|
|||
PrimitiveInstanceKind::TextRun { data_handle, .. } => {
|
||||
&resources.text_run_interner[data_handle]
|
||||
}
|
||||
PrimitiveInstanceKind::YuvImage { data_handle, .. } => {
|
||||
&resources.yuv_image_interner[data_handle]
|
||||
}
|
||||
};
|
||||
|
||||
// Get the key for the cluster that this primitive should
|
||||
|
|
|
@ -0,0 +1,581 @@
|
|||
/* 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::{
|
||||
AlphaType, ColorDepth, ColorF, ColorU, DeviceIntRect, DeviceIntSideOffsets,
|
||||
DeviceIntSize, ImageRendering, LayoutRect, LayoutSize, LayoutPrimitiveInfo,
|
||||
PremultipliedColorF, Shadow, TileOffset, YuvColorSpace, YuvFormat
|
||||
};
|
||||
use api::ImageKey as ApiImageKey;
|
||||
use display_list_flattener::{AsInstanceKind, CreateShadow, IsVisible};
|
||||
use frame_builder::FrameBuildingState;
|
||||
use gpu_cache::{GpuCacheHandle, GpuDataRequest};
|
||||
use intern::{DataStore, Handle, Internable, Interner, InternDebug, UpdateList};
|
||||
use picture::SurfaceIndex;
|
||||
use prim_store::{
|
||||
EdgeAaSegmentMask, OpacityBindingIndex, PrimitiveInstanceKind,
|
||||
PrimitiveOpacity, PrimitiveSceneData, PrimKey, PrimKeyCommonData,
|
||||
PrimTemplate, PrimTemplateCommonData, PrimitiveStore, SegmentInstanceIndex,
|
||||
SizeKey
|
||||
};
|
||||
use render_task::{
|
||||
BlitSource, RenderTask, RenderTaskCacheEntryHandle, RenderTaskCacheKey,
|
||||
RenderTaskCacheKeyKind
|
||||
};
|
||||
use resource_cache::ImageRequest;
|
||||
use util::pack_as_float;
|
||||
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(feature = "capture", derive(Serialize))]
|
||||
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
||||
pub struct VisibleImageTile {
|
||||
pub tile_offset: TileOffset,
|
||||
pub handle: GpuCacheHandle,
|
||||
pub edge_flags: EdgeAaSegmentMask,
|
||||
pub local_rect: LayoutRect,
|
||||
pub local_clip_rect: LayoutRect,
|
||||
}
|
||||
|
||||
// Key that identifies a unique (partial) image that is being
|
||||
// stored in the render task cache.
|
||||
#[derive(Debug, Copy, Clone, Eq, Hash, PartialEq)]
|
||||
#[cfg_attr(feature = "capture", derive(Serialize))]
|
||||
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
||||
pub struct ImageCacheKey {
|
||||
pub request: ImageRequest,
|
||||
pub texel_rect: Option<DeviceIntRect>,
|
||||
}
|
||||
|
||||
/// Instance specific fields for an image primitive. These are
|
||||
/// currently stored in a separate array to avoid bloating the
|
||||
/// size of PrimitiveInstance. In the future, we should be able
|
||||
/// to remove this and store the information inline, by:
|
||||
/// (a) Removing opacity collapse / binding support completely.
|
||||
/// Once we have general picture caching, we don't need this.
|
||||
/// (b) Change visible_tiles to use Storage in the primitive
|
||||
/// scratch buffer. This will reduce the size of the
|
||||
/// visible_tiles field here, and save memory allocation
|
||||
/// when image tiling is used. I've left it as a Vec for
|
||||
/// now to reduce the number of changes, and because image
|
||||
/// tiling is very rare on real pages.
|
||||
#[derive(Debug)]
|
||||
pub struct ImageInstance {
|
||||
pub opacity_binding_index: OpacityBindingIndex,
|
||||
pub segment_instance_index: SegmentInstanceIndex,
|
||||
pub visible_tiles: Vec<VisibleImageTile>,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "capture", derive(Serialize))]
|
||||
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
||||
pub struct Image {
|
||||
pub key: ApiImageKey,
|
||||
pub stretch_size: SizeKey,
|
||||
pub tile_spacing: SizeKey,
|
||||
pub color: ColorU,
|
||||
pub sub_rect: Option<DeviceIntRect>,
|
||||
pub image_rendering: ImageRendering,
|
||||
pub alpha_type: AlphaType,
|
||||
}
|
||||
|
||||
pub type ImageKey = PrimKey<Image>;
|
||||
|
||||
impl ImageKey {
|
||||
pub fn new(
|
||||
is_backface_visible: bool,
|
||||
prim_size: LayoutSize,
|
||||
prim_relative_clip_rect: LayoutRect,
|
||||
image: Image,
|
||||
) -> Self {
|
||||
|
||||
ImageKey {
|
||||
common: PrimKeyCommonData {
|
||||
is_backface_visible,
|
||||
prim_size: prim_size.into(),
|
||||
prim_relative_clip_rect: prim_relative_clip_rect.into(),
|
||||
},
|
||||
kind: image,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl InternDebug for ImageKey {}
|
||||
|
||||
impl AsInstanceKind<ImageDataHandle> for ImageKey {
|
||||
/// Construct a primitive instance that matches the type
|
||||
/// of primitive key.
|
||||
fn as_instance_kind(
|
||||
&self,
|
||||
data_handle: ImageDataHandle,
|
||||
prim_store: &mut PrimitiveStore,
|
||||
) -> PrimitiveInstanceKind {
|
||||
// TODO(gw): Refactor this to not need a separate image
|
||||
// instance (see ImageInstance struct).
|
||||
let image_instance_index = prim_store.images.push(ImageInstance {
|
||||
opacity_binding_index: OpacityBindingIndex::INVALID,
|
||||
segment_instance_index: SegmentInstanceIndex::INVALID,
|
||||
visible_tiles: Vec::new(),
|
||||
});
|
||||
|
||||
PrimitiveInstanceKind::Image {
|
||||
data_handle,
|
||||
image_instance_index,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Where to find the texture data for an image primitive.
|
||||
#[cfg_attr(feature = "capture", derive(Serialize))]
|
||||
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
||||
#[derive(Debug)]
|
||||
pub enum ImageSource {
|
||||
// A normal image - just reference the texture cache.
|
||||
Default,
|
||||
// An image that is pre-rendered into the texture cache
|
||||
// via a render task.
|
||||
Cache {
|
||||
size: DeviceIntSize,
|
||||
handle: Option<RenderTaskCacheEntryHandle>,
|
||||
},
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "capture", derive(Serialize))]
|
||||
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
||||
pub struct ImageData {
|
||||
pub key: ApiImageKey,
|
||||
pub stretch_size: LayoutSize,
|
||||
pub tile_spacing: LayoutSize,
|
||||
pub color: ColorF,
|
||||
pub source: ImageSource,
|
||||
pub image_rendering: ImageRendering,
|
||||
pub sub_rect: Option<DeviceIntRect>,
|
||||
pub alpha_type: AlphaType,
|
||||
}
|
||||
|
||||
impl From<Image> for ImageData {
|
||||
fn from(image: Image) -> Self {
|
||||
ImageData {
|
||||
key: image.key,
|
||||
color: image.color.into(),
|
||||
stretch_size: image.stretch_size.into(),
|
||||
tile_spacing: image.tile_spacing.into(),
|
||||
source: ImageSource::Default,
|
||||
sub_rect: image.sub_rect,
|
||||
image_rendering: image.image_rendering,
|
||||
alpha_type: image.alpha_type,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ImageData {
|
||||
/// Update the GPU cache for a given primitive template. This may be called multiple
|
||||
/// times per frame, by each primitive reference that refers to this interned
|
||||
/// template. The initial request call to the GPU cache ensures that work is only
|
||||
/// done if the cache entry is invalid (due to first use or eviction).
|
||||
pub fn update(
|
||||
&mut self,
|
||||
// TODO(gw): Passing in surface_index here is not ideal. The primitive template
|
||||
// code shouldn't depend on current surface state. This is due to a
|
||||
// limitation in how render task caching works. We should fix this by
|
||||
// allowing render task caching to assign to surfaces implicitly
|
||||
// during pass allocation.
|
||||
surface_index: SurfaceIndex,
|
||||
common: &mut PrimTemplateCommonData,
|
||||
frame_state: &mut FrameBuildingState,
|
||||
) {
|
||||
if let Some(mut request) = frame_state.gpu_cache.request(&mut common.gpu_cache_handle) {
|
||||
self.write_prim_gpu_blocks(&mut request);
|
||||
}
|
||||
|
||||
common.opacity = {
|
||||
let image_properties = frame_state
|
||||
.resource_cache
|
||||
.get_image_properties(self.key);
|
||||
|
||||
match image_properties {
|
||||
Some(image_properties) => {
|
||||
let is_tiled = image_properties.tiling.is_some();
|
||||
|
||||
if self.tile_spacing != LayoutSize::zero() && !is_tiled {
|
||||
self.source = ImageSource::Cache {
|
||||
// Size in device-pixels we need to allocate in render task cache.
|
||||
size: image_properties.descriptor.size.to_i32(),
|
||||
handle: None,
|
||||
};
|
||||
}
|
||||
|
||||
// Work out whether this image is a normal / simple type, or if
|
||||
// we need to pre-render it to the render task cache.
|
||||
if let Some(rect) = self.sub_rect {
|
||||
// We don't properly support this right now.
|
||||
debug_assert!(!is_tiled);
|
||||
self.source = ImageSource::Cache {
|
||||
// Size in device-pixels we need to allocate in render task cache.
|
||||
size: rect.size,
|
||||
handle: None,
|
||||
};
|
||||
}
|
||||
|
||||
let mut request_source_image = false;
|
||||
let mut is_opaque = image_properties.descriptor.is_opaque;
|
||||
let request = ImageRequest {
|
||||
key: self.key,
|
||||
rendering: self.image_rendering,
|
||||
tile: None,
|
||||
};
|
||||
|
||||
// Every frame, for cached items, we need to request the render
|
||||
// task cache item. The closure will be invoked on the first
|
||||
// time through, and any time the render task output has been
|
||||
// evicted from the texture cache.
|
||||
match self.source {
|
||||
ImageSource::Cache { ref mut size, ref mut handle } => {
|
||||
let padding = DeviceIntSideOffsets::new(
|
||||
0,
|
||||
(self.tile_spacing.width * size.width as f32 / self.stretch_size.width) as i32,
|
||||
(self.tile_spacing.height * size.height as f32 / self.stretch_size.height) as i32,
|
||||
0,
|
||||
);
|
||||
|
||||
let inner_size = *size;
|
||||
size.width += padding.horizontal();
|
||||
size.height += padding.vertical();
|
||||
|
||||
is_opaque &= padding == DeviceIntSideOffsets::zero();
|
||||
|
||||
let image_cache_key = ImageCacheKey {
|
||||
request,
|
||||
texel_rect: self.sub_rect,
|
||||
};
|
||||
let surfaces = &mut frame_state.surfaces;
|
||||
|
||||
// Request a pre-rendered image task.
|
||||
*handle = Some(frame_state.resource_cache.request_render_task(
|
||||
RenderTaskCacheKey {
|
||||
size: *size,
|
||||
kind: RenderTaskCacheKeyKind::Image(image_cache_key),
|
||||
},
|
||||
frame_state.gpu_cache,
|
||||
frame_state.render_tasks,
|
||||
None,
|
||||
image_properties.descriptor.is_opaque,
|
||||
|render_tasks| {
|
||||
// We need to render the image cache this frame,
|
||||
// so will need access to the source texture.
|
||||
request_source_image = true;
|
||||
|
||||
// Create a task to blit from the texture cache to
|
||||
// a normal transient render task surface. This will
|
||||
// copy only the sub-rect, if specified.
|
||||
let cache_to_target_task = RenderTask::new_blit_with_padding(
|
||||
inner_size,
|
||||
&padding,
|
||||
BlitSource::Image { key: image_cache_key },
|
||||
);
|
||||
let cache_to_target_task_id = render_tasks.add(cache_to_target_task);
|
||||
|
||||
// Create a task to blit the rect from the child render
|
||||
// task above back into the right spot in the persistent
|
||||
// render target cache.
|
||||
let target_to_cache_task = RenderTask::new_blit(
|
||||
*size,
|
||||
BlitSource::RenderTask {
|
||||
task_id: cache_to_target_task_id,
|
||||
},
|
||||
);
|
||||
let target_to_cache_task_id = render_tasks.add(target_to_cache_task);
|
||||
|
||||
// Hook this into the render task tree at the right spot.
|
||||
surfaces[surface_index.0].tasks.push(target_to_cache_task_id);
|
||||
|
||||
// Pass the image opacity, so that the cached render task
|
||||
// item inherits the same opacity properties.
|
||||
target_to_cache_task_id
|
||||
}
|
||||
));
|
||||
}
|
||||
ImageSource::Default => {
|
||||
// Normal images just reference the source texture each frame.
|
||||
request_source_image = true;
|
||||
}
|
||||
}
|
||||
|
||||
if request_source_image && !is_tiled {
|
||||
frame_state.resource_cache.request_image(
|
||||
request,
|
||||
frame_state.gpu_cache,
|
||||
);
|
||||
}
|
||||
|
||||
if is_opaque {
|
||||
PrimitiveOpacity::from_alpha(self.color.a)
|
||||
} else {
|
||||
PrimitiveOpacity::translucent()
|
||||
}
|
||||
}
|
||||
None => {
|
||||
PrimitiveOpacity::opaque()
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub fn write_prim_gpu_blocks(&self, request: &mut GpuDataRequest) {
|
||||
// Images are drawn as a white color, modulated by the total
|
||||
// opacity coming from any collapsed property bindings.
|
||||
request.push(self.color.premultiplied());
|
||||
request.push(PremultipliedColorF::WHITE);
|
||||
request.push([
|
||||
self.stretch_size.width + self.tile_spacing.width,
|
||||
self.stretch_size.height + self.tile_spacing.height,
|
||||
0.0,
|
||||
0.0,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
pub type ImageTemplate = PrimTemplate<ImageData>;
|
||||
|
||||
impl From<ImageKey> for ImageTemplate {
|
||||
fn from(image: ImageKey) -> Self {
|
||||
let common = PrimTemplateCommonData::with_key_common(image.common);
|
||||
|
||||
ImageTemplate {
|
||||
common,
|
||||
kind: image.kind.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "capture", derive(Serialize))]
|
||||
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
||||
#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)]
|
||||
pub struct ImageDataMarker;
|
||||
|
||||
pub type ImageDataStore = DataStore<ImageKey, ImageTemplate, ImageDataMarker>;
|
||||
pub type ImageDataHandle = Handle<ImageDataMarker>;
|
||||
pub type ImageDataUpdateList = UpdateList<ImageKey>;
|
||||
pub type ImageDataInterner = Interner<ImageKey, PrimitiveSceneData, ImageDataMarker>;
|
||||
|
||||
impl Internable for Image {
|
||||
type Marker = ImageDataMarker;
|
||||
type Source = ImageKey;
|
||||
type StoreData = ImageTemplate;
|
||||
type InternData = PrimitiveSceneData;
|
||||
|
||||
/// Build a new key from self with `info`.
|
||||
fn build_key(
|
||||
self,
|
||||
info: &LayoutPrimitiveInfo,
|
||||
prim_relative_clip_rect: LayoutRect,
|
||||
) -> ImageKey {
|
||||
ImageKey::new(
|
||||
info.is_backface_visible,
|
||||
info.rect.size,
|
||||
prim_relative_clip_rect,
|
||||
self
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl CreateShadow for Image {
|
||||
fn create_shadow(&self, shadow: &Shadow) -> Self {
|
||||
Image {
|
||||
tile_spacing: self.tile_spacing,
|
||||
stretch_size: self.stretch_size,
|
||||
key: self.key,
|
||||
sub_rect: self.sub_rect,
|
||||
image_rendering: self.image_rendering,
|
||||
alpha_type: self.alpha_type,
|
||||
color: shadow.color.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IsVisible for Image {
|
||||
fn is_visible(&self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#[cfg_attr(feature = "capture", derive(Serialize))]
|
||||
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
||||
pub struct YuvImage {
|
||||
pub color_depth: ColorDepth,
|
||||
pub yuv_key: [ApiImageKey; 3],
|
||||
pub format: YuvFormat,
|
||||
pub color_space: YuvColorSpace,
|
||||
pub image_rendering: ImageRendering,
|
||||
}
|
||||
|
||||
pub type YuvImageKey = PrimKey<YuvImage>;
|
||||
|
||||
impl YuvImageKey {
|
||||
pub fn new(
|
||||
is_backface_visible: bool,
|
||||
prim_size: LayoutSize,
|
||||
prim_relative_clip_rect: LayoutRect,
|
||||
yuv_image: YuvImage,
|
||||
) -> Self {
|
||||
|
||||
YuvImageKey {
|
||||
common: PrimKeyCommonData {
|
||||
is_backface_visible,
|
||||
prim_size: prim_size.into(),
|
||||
prim_relative_clip_rect: prim_relative_clip_rect.into(),
|
||||
},
|
||||
kind: yuv_image,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl InternDebug for YuvImageKey {}
|
||||
|
||||
impl AsInstanceKind<YuvImageDataHandle> for YuvImageKey {
|
||||
/// Construct a primitive instance that matches the type
|
||||
/// of primitive key.
|
||||
fn as_instance_kind(
|
||||
&self,
|
||||
data_handle: YuvImageDataHandle,
|
||||
_prim_store: &mut PrimitiveStore,
|
||||
) -> PrimitiveInstanceKind {
|
||||
PrimitiveInstanceKind::YuvImage {
|
||||
data_handle,
|
||||
segment_instance_index: SegmentInstanceIndex::INVALID
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "capture", derive(Serialize))]
|
||||
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
||||
pub struct YuvImageData {
|
||||
pub color_depth: ColorDepth,
|
||||
pub yuv_key: [ApiImageKey; 3],
|
||||
pub format: YuvFormat,
|
||||
pub color_space: YuvColorSpace,
|
||||
pub image_rendering: ImageRendering,
|
||||
}
|
||||
|
||||
impl From<YuvImage> for YuvImageData {
|
||||
fn from(image: YuvImage) -> Self {
|
||||
YuvImageData {
|
||||
color_depth: image.color_depth,
|
||||
yuv_key: image.yuv_key,
|
||||
format: image.format,
|
||||
color_space: image.color_space,
|
||||
image_rendering: image.image_rendering,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl YuvImageData {
|
||||
/// Update the GPU cache for a given primitive template. This may be called multiple
|
||||
/// times per frame, by each primitive reference that refers to this interned
|
||||
/// template. The initial request call to the GPU cache ensures that work is only
|
||||
/// done if the cache entry is invalid (due to first use or eviction).
|
||||
pub fn update(
|
||||
&mut self,
|
||||
common: &mut PrimTemplateCommonData,
|
||||
frame_state: &mut FrameBuildingState,
|
||||
) {
|
||||
if let Some(mut request) = frame_state.gpu_cache.request(&mut common.gpu_cache_handle) {
|
||||
self.write_prim_gpu_blocks(&mut request);
|
||||
};
|
||||
|
||||
let channel_num = self.format.get_plane_num();
|
||||
debug_assert!(channel_num <= 3);
|
||||
for channel in 0 .. channel_num {
|
||||
frame_state.resource_cache.request_image(
|
||||
ImageRequest {
|
||||
key: self.yuv_key[channel],
|
||||
rendering: self.image_rendering,
|
||||
tile: None,
|
||||
},
|
||||
frame_state.gpu_cache,
|
||||
);
|
||||
}
|
||||
|
||||
common.opacity = PrimitiveOpacity::translucent();
|
||||
}
|
||||
|
||||
pub fn write_prim_gpu_blocks(&self, request: &mut GpuDataRequest) {
|
||||
request.push([
|
||||
self.color_depth.rescaling_factor(),
|
||||
pack_as_float(self.color_space as u32),
|
||||
pack_as_float(self.format as u32),
|
||||
0.0
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
pub type YuvImageTemplate = PrimTemplate<YuvImageData>;
|
||||
|
||||
impl From<YuvImageKey> for YuvImageTemplate {
|
||||
fn from(image: YuvImageKey) -> Self {
|
||||
let common = PrimTemplateCommonData::with_key_common(image.common);
|
||||
|
||||
YuvImageTemplate {
|
||||
common,
|
||||
kind: image.kind.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "capture", derive(Serialize))]
|
||||
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
||||
#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)]
|
||||
pub struct YuvImageDataMarker;
|
||||
|
||||
pub type YuvImageDataStore = DataStore<YuvImageKey, YuvImageTemplate, YuvImageDataMarker>;
|
||||
pub type YuvImageDataHandle = Handle<YuvImageDataMarker>;
|
||||
pub type YuvImageDataUpdateList = UpdateList<YuvImageKey>;
|
||||
pub type YuvImageDataInterner = Interner<YuvImageKey, PrimitiveSceneData, YuvImageDataMarker>;
|
||||
|
||||
impl Internable for YuvImage {
|
||||
type Marker = YuvImageDataMarker;
|
||||
type Source = YuvImageKey;
|
||||
type StoreData = YuvImageTemplate;
|
||||
type InternData = PrimitiveSceneData;
|
||||
|
||||
/// Build a new key from self with `info`.
|
||||
fn build_key(
|
||||
self,
|
||||
info: &LayoutPrimitiveInfo,
|
||||
prim_relative_clip_rect: LayoutRect,
|
||||
) -> YuvImageKey {
|
||||
YuvImageKey::new(
|
||||
info.is_backface_visible,
|
||||
info.rect.size,
|
||||
prim_relative_clip_rect,
|
||||
self
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl IsVisible for YuvImage {
|
||||
fn is_visible(&self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(target_os = "linux")]
|
||||
fn test_struct_sizes() {
|
||||
use std::mem;
|
||||
// The sizes of these structures are critical for performance on a number of
|
||||
// talos stress tests. If you get a failure here on CI, there's two possibilities:
|
||||
// (a) You made a structure smaller than it currently is. Great work! Update the
|
||||
// test expectations and move on.
|
||||
// (b) You made a structure larger. This is not necessarily a problem, but should only
|
||||
// be done with care, and after checking if talos performance regresses badly.
|
||||
assert_eq!(mem::size_of::<Image>(), 56, "Image size changed");
|
||||
assert_eq!(mem::size_of::<ImageTemplate>(), 144, "ImageTemplate size changed");
|
||||
assert_eq!(mem::size_of::<ImageKey>(), 84, "ImageKey size changed");
|
||||
assert_eq!(mem::size_of::<YuvImage>(), 36, "YuvImage size changed");
|
||||
assert_eq!(mem::size_of::<YuvImageTemplate>(), 96, "YuvImageTemplate size changed");
|
||||
assert_eq!(mem::size_of::<YuvImageKey>(), 64, "YuvImageKey size changed");
|
||||
}
|
|
@ -2,13 +2,13 @@
|
|||
* 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::{AlphaType, BorderRadius, ClipMode, ColorF, PictureRect, ColorU, LayoutVector2D};
|
||||
use api::{DeviceIntRect, DeviceIntSize, DevicePixelScale, DeviceRect, LayoutSideOffsetsAu};
|
||||
use api::{FilterOp, ImageKey, ImageRendering, TileOffset, RepeatMode, MixBlendMode};
|
||||
use api::{BorderRadius, ClipMode, ColorF, PictureRect, ColorU, LayoutVector2D};
|
||||
use api::{DeviceIntRect, DevicePixelScale, DeviceRect, LayoutSideOffsetsAu};
|
||||
use api::{FilterOp, ImageRendering, TileOffset, RepeatMode, MixBlendMode};
|
||||
use api::{LayoutPoint, LayoutRect, LayoutSideOffsets, LayoutSize, PropertyBindingId};
|
||||
use api::{PremultipliedColorF, PropertyBinding, Shadow, YuvColorSpace, YuvFormat};
|
||||
use api::{DeviceIntSideOffsets, WorldPixel, BoxShadowClipMode, NormalBorder, WorldRect, LayoutToWorldScale};
|
||||
use api::{PicturePixel, RasterPixel, ColorDepth, LineStyle, LineOrientation, LayoutSizeAu, AuHelpers};
|
||||
use api::{PremultipliedColorF, PropertyBinding, Shadow};
|
||||
use api::{WorldPixel, BoxShadowClipMode, NormalBorder, WorldRect, LayoutToWorldScale};
|
||||
use api::{PicturePixel, RasterPixel, LineStyle, LineOrientation, LayoutSizeAu, AuHelpers};
|
||||
use api::LayoutPrimitiveInfo;
|
||||
use app_units::Au;
|
||||
use border::{get_max_scale_for_border, build_border_instances, create_border_segments};
|
||||
|
@ -23,16 +23,17 @@ use frame_builder::PrimitiveContext;
|
|||
use glyph_rasterizer::GlyphKey;
|
||||
use gpu_cache::{GpuCache, GpuCacheAddress, GpuCacheHandle, GpuDataRequest, ToGpuBlocks};
|
||||
use gpu_types::BrushFlags;
|
||||
use image::{self, Repetition};
|
||||
use image::{Repetition};
|
||||
use intern;
|
||||
use picture::{PictureCompositeMode, PicturePrimitive, PictureUpdateState, TileCacheUpdateState};
|
||||
use picture::{ClusterRange, PrimitiveList, SurfaceIndex, SurfaceInfo, RetainedTiles, RasterConfig};
|
||||
use prim_store::gradient::{LinearGradientDataHandle, RadialGradientDataHandle};
|
||||
use prim_store::image::{ImageDataHandle, ImageInstance, VisibleImageTile, YuvImageDataHandle};
|
||||
use prim_store::text_run::{TextRunDataHandle, TextRunPrimitive};
|
||||
#[cfg(debug_assertions)]
|
||||
use render_backend::{FrameId};
|
||||
use render_backend::FrameResources;
|
||||
use render_task::{BlitSource, RenderTask, RenderTaskCacheKey, to_cache_size};
|
||||
use render_task::{RenderTask, RenderTaskCacheKey, to_cache_size};
|
||||
use render_task::{RenderTaskCacheKeyKind, RenderTaskId, RenderTaskCacheEntryHandle};
|
||||
use renderer::{MAX_VERTEX_TEXTURE_WIDTH};
|
||||
use resource_cache::{ImageProperties, ImageRequest, ResourceCache};
|
||||
|
@ -47,6 +48,7 @@ use util::{pack_as_float, project_rect, raster_rect_to_device_pixels};
|
|||
use smallvec::SmallVec;
|
||||
|
||||
pub mod gradient;
|
||||
pub mod image;
|
||||
pub mod text_run;
|
||||
|
||||
/// Counter for unique primitive IDs for debug tracing.
|
||||
|
@ -480,22 +482,6 @@ pub enum PrimitiveKeyKind {
|
|||
Rectangle {
|
||||
color: ColorU,
|
||||
},
|
||||
YuvImage {
|
||||
color_depth: ColorDepth,
|
||||
yuv_key: [ImageKey; 3],
|
||||
format: YuvFormat,
|
||||
color_space: YuvColorSpace,
|
||||
image_rendering: ImageRendering,
|
||||
},
|
||||
Image {
|
||||
key: ImageKey,
|
||||
stretch_size: SizeKey,
|
||||
tile_spacing: SizeKey,
|
||||
color: ColorU,
|
||||
sub_rect: Option<DeviceIntRect>,
|
||||
image_rendering: ImageRendering,
|
||||
alpha_type: AlphaType,
|
||||
},
|
||||
Picture {
|
||||
composite_mode_key: PictureCompositeKey,
|
||||
},
|
||||
|
@ -727,6 +713,14 @@ impl PrimKeyCommonData {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "capture", derive(Serialize))]
|
||||
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
||||
pub struct PrimKey<T> {
|
||||
pub common: PrimKeyCommonData,
|
||||
pub kind: T,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "capture", derive(Serialize))]
|
||||
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
||||
|
@ -761,7 +755,7 @@ impl AsInstanceKind<PrimitiveDataHandle> for PrimitiveKey {
|
|||
fn as_instance_kind(
|
||||
&self,
|
||||
data_handle: PrimitiveDataHandle,
|
||||
prim_store: &mut PrimitiveStore,
|
||||
_: &mut PrimitiveStore,
|
||||
) -> PrimitiveInstanceKind {
|
||||
match self.kind {
|
||||
PrimitiveKeyKind::LineDecoration { .. } => {
|
||||
|
@ -793,26 +787,6 @@ impl AsInstanceKind<PrimitiveDataHandle> for PrimitiveKey {
|
|||
segment_instance_index: SegmentInstanceIndex::INVALID,
|
||||
}
|
||||
}
|
||||
PrimitiveKeyKind::YuvImage { .. } => {
|
||||
PrimitiveInstanceKind::YuvImage {
|
||||
data_handle,
|
||||
segment_instance_index: SegmentInstanceIndex::INVALID
|
||||
}
|
||||
}
|
||||
PrimitiveKeyKind::Image { .. } => {
|
||||
// TODO(gw): Refactor this to not need a separate image
|
||||
// instance (see ImageInstance struct).
|
||||
let image_instance_index = prim_store.images.push(ImageInstance {
|
||||
opacity_binding_index: OpacityBindingIndex::INVALID,
|
||||
segment_instance_index: SegmentInstanceIndex::INVALID,
|
||||
visible_tiles: Vec::new(),
|
||||
});
|
||||
|
||||
PrimitiveInstanceKind::Image {
|
||||
data_handle,
|
||||
image_instance_index,
|
||||
}
|
||||
}
|
||||
PrimitiveKeyKind::Picture { .. } => {
|
||||
// Should never be hit as this method should not be
|
||||
// called for pictures.
|
||||
|
@ -850,23 +824,6 @@ pub enum PrimitiveTemplateKind {
|
|||
Rectangle {
|
||||
color: ColorF,
|
||||
},
|
||||
YuvImage {
|
||||
color_depth: ColorDepth,
|
||||
yuv_key: [ImageKey; 3],
|
||||
format: YuvFormat,
|
||||
color_space: YuvColorSpace,
|
||||
image_rendering: ImageRendering,
|
||||
},
|
||||
Image {
|
||||
key: ImageKey,
|
||||
stretch_size: LayoutSize,
|
||||
tile_spacing: LayoutSize,
|
||||
color: ColorF,
|
||||
source: ImageSource,
|
||||
image_rendering: ImageRendering,
|
||||
sub_rect: Option<DeviceIntRect>,
|
||||
alpha_type: AlphaType,
|
||||
},
|
||||
Clear,
|
||||
Picture {
|
||||
|
||||
|
@ -934,27 +891,6 @@ impl PrimitiveKeyKind {
|
|||
color: color.into(),
|
||||
}
|
||||
}
|
||||
PrimitiveKeyKind::YuvImage { color_depth, yuv_key, format, color_space, image_rendering, .. } => {
|
||||
PrimitiveTemplateKind::YuvImage {
|
||||
color_depth,
|
||||
yuv_key,
|
||||
format,
|
||||
color_space,
|
||||
image_rendering,
|
||||
}
|
||||
}
|
||||
PrimitiveKeyKind::Image { alpha_type, key, color, stretch_size, tile_spacing, image_rendering, sub_rect, .. } => {
|
||||
PrimitiveTemplateKind::Image {
|
||||
key,
|
||||
color: color.into(),
|
||||
stretch_size: stretch_size.into(),
|
||||
tile_spacing: tile_spacing.into(),
|
||||
source: ImageSource::Default,
|
||||
sub_rect,
|
||||
image_rendering,
|
||||
alpha_type,
|
||||
}
|
||||
}
|
||||
PrimitiveKeyKind::LineDecoration { cache_key, color } => {
|
||||
PrimitiveTemplateKind::LineDecoration {
|
||||
cache_key,
|
||||
|
@ -991,6 +927,13 @@ impl PrimTemplateCommonData {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "capture", derive(Serialize))]
|
||||
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
||||
pub struct PrimTemplate<T> {
|
||||
pub common: PrimTemplateCommonData,
|
||||
pub kind: T,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "capture", derive(Serialize))]
|
||||
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
||||
pub struct PrimitiveTemplate {
|
||||
|
@ -1078,26 +1021,6 @@ impl PrimitiveTemplateKind {
|
|||
}
|
||||
}
|
||||
}
|
||||
PrimitiveTemplateKind::YuvImage { color_depth, format, color_space, .. } => {
|
||||
request.push([
|
||||
color_depth.rescaling_factor(),
|
||||
pack_as_float(color_space as u32),
|
||||
pack_as_float(format as u32),
|
||||
0.0
|
||||
]);
|
||||
}
|
||||
PrimitiveTemplateKind::Image { stretch_size, tile_spacing, color, .. } => {
|
||||
// Images are drawn as a white color, modulated by the total
|
||||
// opacity coming from any collapsed property bindings.
|
||||
request.push(color.premultiplied());
|
||||
request.push(PremultipliedColorF::WHITE);
|
||||
request.push([
|
||||
stretch_size.width + tile_spacing.width,
|
||||
stretch_size.height + tile_spacing.height,
|
||||
0.0,
|
||||
0.0,
|
||||
]);
|
||||
}
|
||||
PrimitiveTemplateKind::Picture { .. } => {}
|
||||
}
|
||||
}
|
||||
|
@ -1127,9 +1050,7 @@ impl PrimitiveTemplateKind {
|
|||
}
|
||||
PrimitiveTemplateKind::Clear |
|
||||
PrimitiveTemplateKind::LineDecoration { .. } |
|
||||
PrimitiveTemplateKind::Image { .. } |
|
||||
PrimitiveTemplateKind::Rectangle { .. } |
|
||||
PrimitiveTemplateKind::YuvImage { .. } |
|
||||
PrimitiveTemplateKind::Picture { .. } => {}
|
||||
}
|
||||
}
|
||||
|
@ -1142,12 +1063,6 @@ impl PrimitiveTemplate {
|
|||
/// done if the cache entry is invalid (due to first use or eviction).
|
||||
pub fn update(
|
||||
&mut self,
|
||||
// TODO(gw): Passing in surface_index here is not ideal. The primitive template
|
||||
// code shouldn't depend on current surface state. This is due to a
|
||||
// limitation in how render task caching works. We should fix this by
|
||||
// allowing render task caching to assign to surfaces implicitly
|
||||
// during pass allocation.
|
||||
surface_index: SurfaceIndex,
|
||||
frame_state: &mut FrameBuildingState,
|
||||
) {
|
||||
if let Some(mut request) = frame_state.gpu_cache.request(&mut self.common.gpu_cache_handle) {
|
||||
|
@ -1192,153 +1107,6 @@ impl PrimitiveTemplate {
|
|||
None => PrimitiveOpacity::from_alpha(color.a),
|
||||
}
|
||||
}
|
||||
PrimitiveTemplateKind::YuvImage { format, yuv_key, image_rendering, .. } => {
|
||||
let channel_num = format.get_plane_num();
|
||||
debug_assert!(channel_num <= 3);
|
||||
for channel in 0 .. channel_num {
|
||||
frame_state.resource_cache.request_image(
|
||||
ImageRequest {
|
||||
key: yuv_key[channel],
|
||||
rendering: image_rendering,
|
||||
tile: None,
|
||||
},
|
||||
frame_state.gpu_cache,
|
||||
);
|
||||
}
|
||||
|
||||
PrimitiveOpacity::translucent()
|
||||
}
|
||||
PrimitiveTemplateKind::Image { key, stretch_size, ref color, tile_spacing, ref mut source, sub_rect, image_rendering, .. } => {
|
||||
let image_properties = frame_state
|
||||
.resource_cache
|
||||
.get_image_properties(key);
|
||||
|
||||
match image_properties {
|
||||
Some(image_properties) => {
|
||||
let is_tiled = image_properties.tiling.is_some();
|
||||
|
||||
if tile_spacing != LayoutSize::zero() && !is_tiled {
|
||||
*source = ImageSource::Cache {
|
||||
// Size in device-pixels we need to allocate in render task cache.
|
||||
size: image_properties.descriptor.size.to_i32(),
|
||||
handle: None,
|
||||
};
|
||||
}
|
||||
|
||||
// Work out whether this image is a normal / simple type, or if
|
||||
// we need to pre-render it to the render task cache.
|
||||
if let Some(rect) = sub_rect {
|
||||
// We don't properly support this right now.
|
||||
debug_assert!(!is_tiled);
|
||||
*source = ImageSource::Cache {
|
||||
// Size in device-pixels we need to allocate in render task cache.
|
||||
size: rect.size,
|
||||
handle: None,
|
||||
};
|
||||
}
|
||||
|
||||
let mut request_source_image = false;
|
||||
let mut is_opaque = image_properties.descriptor.is_opaque;
|
||||
let request = ImageRequest {
|
||||
key,
|
||||
rendering: image_rendering,
|
||||
tile: None,
|
||||
};
|
||||
|
||||
// Every frame, for cached items, we need to request the render
|
||||
// task cache item. The closure will be invoked on the first
|
||||
// time through, and any time the render task output has been
|
||||
// evicted from the texture cache.
|
||||
match *source {
|
||||
ImageSource::Cache { ref mut size, ref mut handle } => {
|
||||
let padding = DeviceIntSideOffsets::new(
|
||||
0,
|
||||
(tile_spacing.width * size.width as f32 / stretch_size.width) as i32,
|
||||
(tile_spacing.height * size.height as f32 / stretch_size.height) as i32,
|
||||
0,
|
||||
);
|
||||
|
||||
let inner_size = *size;
|
||||
size.width += padding.horizontal();
|
||||
size.height += padding.vertical();
|
||||
|
||||
is_opaque &= padding == DeviceIntSideOffsets::zero();
|
||||
|
||||
let image_cache_key = ImageCacheKey {
|
||||
request,
|
||||
texel_rect: sub_rect,
|
||||
};
|
||||
let surfaces = &mut frame_state.surfaces;
|
||||
|
||||
// Request a pre-rendered image task.
|
||||
*handle = Some(frame_state.resource_cache.request_render_task(
|
||||
RenderTaskCacheKey {
|
||||
size: *size,
|
||||
kind: RenderTaskCacheKeyKind::Image(image_cache_key),
|
||||
},
|
||||
frame_state.gpu_cache,
|
||||
frame_state.render_tasks,
|
||||
None,
|
||||
image_properties.descriptor.is_opaque,
|
||||
|render_tasks| {
|
||||
// We need to render the image cache this frame,
|
||||
// so will need access to the source texture.
|
||||
request_source_image = true;
|
||||
|
||||
// Create a task to blit from the texture cache to
|
||||
// a normal transient render task surface. This will
|
||||
// copy only the sub-rect, if specified.
|
||||
let cache_to_target_task = RenderTask::new_blit_with_padding(
|
||||
inner_size,
|
||||
&padding,
|
||||
BlitSource::Image { key: image_cache_key },
|
||||
);
|
||||
let cache_to_target_task_id = render_tasks.add(cache_to_target_task);
|
||||
|
||||
// Create a task to blit the rect from the child render
|
||||
// task above back into the right spot in the persistent
|
||||
// render target cache.
|
||||
let target_to_cache_task = RenderTask::new_blit(
|
||||
*size,
|
||||
BlitSource::RenderTask {
|
||||
task_id: cache_to_target_task_id,
|
||||
},
|
||||
);
|
||||
let target_to_cache_task_id = render_tasks.add(target_to_cache_task);
|
||||
|
||||
// Hook this into the render task tree at the right spot.
|
||||
surfaces[surface_index.0].tasks.push(target_to_cache_task_id);
|
||||
|
||||
// Pass the image opacity, so that the cached render task
|
||||
// item inherits the same opacity properties.
|
||||
target_to_cache_task_id
|
||||
}
|
||||
));
|
||||
}
|
||||
ImageSource::Default => {
|
||||
// Normal images just reference the source texture each frame.
|
||||
request_source_image = true;
|
||||
}
|
||||
}
|
||||
|
||||
if request_source_image && !is_tiled {
|
||||
frame_state.resource_cache.request_image(
|
||||
request,
|
||||
frame_state.gpu_cache,
|
||||
);
|
||||
}
|
||||
|
||||
if is_opaque {
|
||||
PrimitiveOpacity::from_alpha(color.a)
|
||||
} else {
|
||||
PrimitiveOpacity::translucent()
|
||||
}
|
||||
}
|
||||
None => {
|
||||
PrimitiveOpacity::opaque()
|
||||
}
|
||||
}
|
||||
}
|
||||
PrimitiveTemplateKind::Picture { .. } => {
|
||||
PrimitiveOpacity::translucent()
|
||||
}
|
||||
|
@ -1415,17 +1183,6 @@ impl OpacityBinding {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(feature = "capture", derive(Serialize))]
|
||||
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
||||
pub struct VisibleImageTile {
|
||||
pub tile_offset: TileOffset,
|
||||
pub handle: GpuCacheHandle,
|
||||
pub edge_flags: EdgeAaSegmentMask,
|
||||
pub local_rect: LayoutRect,
|
||||
pub local_clip_rect: LayoutRect,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(feature = "capture", derive(Serialize))]
|
||||
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
||||
|
@ -1562,16 +1319,6 @@ impl BrushSegment {
|
|||
}
|
||||
}
|
||||
|
||||
// Key that identifies a unique (partial) image that is being
|
||||
// stored in the render task cache.
|
||||
#[derive(Debug, Copy, Clone, Eq, Hash, PartialEq)]
|
||||
#[cfg_attr(feature = "capture", derive(Serialize))]
|
||||
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
||||
pub struct ImageCacheKey {
|
||||
pub request: ImageRequest,
|
||||
pub texel_rect: Option<DeviceIntRect>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "capture", derive(Serialize))]
|
||||
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
||||
|
@ -1582,21 +1329,6 @@ pub struct LineDecorationCacheKey {
|
|||
pub size: LayoutSizeAu,
|
||||
}
|
||||
|
||||
// Where to find the texture data for an image primitive.
|
||||
#[cfg_attr(feature = "capture", derive(Serialize))]
|
||||
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
||||
#[derive(Debug)]
|
||||
pub enum ImageSource {
|
||||
// A normal image - just reference the texture cache.
|
||||
Default,
|
||||
// An image that is pre-rendered into the texture cache
|
||||
// via a render task.
|
||||
Cache {
|
||||
size: DeviceIntSize,
|
||||
handle: Option<RenderTaskCacheEntryHandle>,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
struct ClipRect {
|
||||
|
@ -1832,8 +1564,6 @@ impl IsVisible for PrimitiveKeyKind {
|
|||
match *self {
|
||||
PrimitiveKeyKind::NormalBorder { .. } |
|
||||
PrimitiveKeyKind::ImageBorder { .. } |
|
||||
PrimitiveKeyKind::YuvImage { .. } |
|
||||
PrimitiveKeyKind::Image { .. } |
|
||||
PrimitiveKeyKind::Clear |
|
||||
PrimitiveKeyKind::Picture { .. } => {
|
||||
true
|
||||
|
@ -1873,19 +1603,7 @@ impl CreateShadow for PrimitiveKeyKind {
|
|||
widths,
|
||||
}
|
||||
}
|
||||
PrimitiveKeyKind::Image { alpha_type, image_rendering, tile_spacing, stretch_size, key, sub_rect, .. } => {
|
||||
PrimitiveKeyKind::Image {
|
||||
tile_spacing,
|
||||
stretch_size,
|
||||
key,
|
||||
sub_rect,
|
||||
image_rendering,
|
||||
alpha_type,
|
||||
color: shadow.color.into(),
|
||||
}
|
||||
}
|
||||
PrimitiveKeyKind::ImageBorder { .. } |
|
||||
PrimitiveKeyKind::YuvImage { .. } |
|
||||
PrimitiveKeyKind::Picture { .. } |
|
||||
PrimitiveKeyKind::Clear => {
|
||||
panic!("bug: this prim is not supported in shadow contexts");
|
||||
|
@ -1894,25 +1612,6 @@ impl CreateShadow for PrimitiveKeyKind {
|
|||
}
|
||||
}
|
||||
|
||||
/// Instance specific fields for an image primitive. These are
|
||||
/// currently stored in a separate array to avoid bloating the
|
||||
/// size of PrimitiveInstance. In the future, we should be able
|
||||
/// to remove this and store the information inline, by:
|
||||
/// (a) Removing opacity collapse / binding support completely.
|
||||
/// Once we have general picture caching, we don't need this.
|
||||
/// (b) Change visible_tiles to use Storage in the primitive
|
||||
/// scratch buffer. This will reduce the size of the
|
||||
/// visible_tiles field here, and save memory allocation
|
||||
/// when image tiling is used. I've left it as a Vec for
|
||||
/// now to reduce the number of changes, and because image
|
||||
/// tiling is very rare on real pages.
|
||||
#[derive(Debug)]
|
||||
pub struct ImageInstance {
|
||||
pub opacity_binding_index: OpacityBindingIndex,
|
||||
pub segment_instance_index: SegmentInstanceIndex,
|
||||
pub visible_tiles: Vec<VisibleImageTile>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
#[cfg_attr(feature = "capture", derive(Serialize))]
|
||||
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
||||
|
@ -1965,12 +1664,12 @@ pub enum PrimitiveInstanceKind {
|
|||
},
|
||||
YuvImage {
|
||||
/// Handle to the common interned data for this primitive.
|
||||
data_handle: PrimitiveDataHandle,
|
||||
data_handle: YuvImageDataHandle,
|
||||
segment_instance_index: SegmentInstanceIndex,
|
||||
},
|
||||
Image {
|
||||
/// Handle to the common interned data for this primitive.
|
||||
data_handle: PrimitiveDataHandle,
|
||||
data_handle: ImageDataHandle,
|
||||
image_instance_index: ImageInstanceIndex,
|
||||
},
|
||||
LinearGradient {
|
||||
|
@ -2076,8 +1775,9 @@ impl PrimitiveInstance {
|
|||
PrimitiveInstanceKind::Clear { data_handle, .. } |
|
||||
PrimitiveInstanceKind::NormalBorder { data_handle, .. } |
|
||||
PrimitiveInstanceKind::ImageBorder { data_handle, .. } |
|
||||
PrimitiveInstanceKind::Rectangle { data_handle, .. } |
|
||||
PrimitiveInstanceKind::YuvImage { data_handle, .. } |
|
||||
PrimitiveInstanceKind::Rectangle { data_handle, .. } => {
|
||||
data_handle.uid()
|
||||
}
|
||||
PrimitiveInstanceKind::Image { data_handle, .. } => {
|
||||
data_handle.uid()
|
||||
}
|
||||
|
@ -2090,6 +1790,9 @@ impl PrimitiveInstance {
|
|||
PrimitiveInstanceKind::TextRun { data_handle, .. } => {
|
||||
data_handle.uid()
|
||||
}
|
||||
PrimitiveInstanceKind::YuvImage { data_handle, .. } => {
|
||||
data_handle.uid()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2766,7 +2469,7 @@ impl PrimitiveStore {
|
|||
}
|
||||
|
||||
pic_state.is_cacheable &= prim_instance.is_cacheable(
|
||||
&resources.prim_data_store,
|
||||
&resources,
|
||||
frame_state.resource_cache,
|
||||
);
|
||||
|
||||
|
@ -2944,10 +2647,7 @@ impl PrimitiveStore {
|
|||
|
||||
// Update the template this instane references, which may refresh the GPU
|
||||
// cache with any shared template data.
|
||||
prim_data.update(
|
||||
pic_context.surface_index,
|
||||
frame_state,
|
||||
);
|
||||
prim_data.update(frame_state);
|
||||
|
||||
match &prim_data.kind {
|
||||
PrimitiveTemplateKind::LineDecoration { ref cache_key, .. } => {
|
||||
|
@ -3032,20 +2732,14 @@ impl PrimitiveStore {
|
|||
|
||||
// Update the template this instane references, which may refresh the GPU
|
||||
// cache with any shared template data.
|
||||
prim_data.update(
|
||||
pic_context.surface_index,
|
||||
frame_state,
|
||||
);
|
||||
prim_data.update(frame_state);
|
||||
}
|
||||
PrimitiveInstanceKind::NormalBorder { data_handle, ref mut cache_handles, .. } => {
|
||||
let prim_data = &mut resources.prim_data_store[*data_handle];
|
||||
|
||||
// Update the template this instane references, which may refresh the GPU
|
||||
// cache with any shared template data.
|
||||
prim_data.update(
|
||||
pic_context.surface_index,
|
||||
frame_state,
|
||||
);
|
||||
prim_data.update(frame_state);
|
||||
|
||||
let template = match prim_data.kind {
|
||||
PrimitiveTemplateKind::NormalBorder { ref template, .. } => template,
|
||||
|
@ -3109,20 +2803,14 @@ impl PrimitiveStore {
|
|||
|
||||
// Update the template this instane references, which may refresh the GPU
|
||||
// cache with any shared template data.
|
||||
prim_data.update(
|
||||
pic_context.surface_index,
|
||||
frame_state,
|
||||
);
|
||||
prim_data.update(frame_state);
|
||||
}
|
||||
PrimitiveInstanceKind::Rectangle { data_handle, segment_instance_index, opacity_binding_index, .. } => {
|
||||
let prim_data = &mut resources.prim_data_store[*data_handle];
|
||||
|
||||
// Update the template this instane references, which may refresh the GPU
|
||||
// cache with any shared template data.
|
||||
prim_data.update(
|
||||
pic_context.surface_index,
|
||||
frame_state,
|
||||
);
|
||||
prim_data.update(frame_state);
|
||||
|
||||
update_opacity_binding(
|
||||
&mut self.opacity_bindings,
|
||||
|
@ -3130,37 +2818,37 @@ impl PrimitiveStore {
|
|||
frame_context.scene_properties,
|
||||
);
|
||||
|
||||
write_segment(prim_data, *segment_instance_index, frame_state, scratch);
|
||||
write_segment(*segment_instance_index, frame_state, scratch, |request| {
|
||||
prim_data.kind.write_prim_gpu_blocks(
|
||||
request,
|
||||
prim_data.prim_size,
|
||||
);
|
||||
});
|
||||
}
|
||||
PrimitiveInstanceKind::YuvImage { data_handle, segment_instance_index, .. } => {
|
||||
let prim_data = &mut resources.prim_data_store[*data_handle];
|
||||
let yuv_image_data = &mut resources.yuv_image_data_store[*data_handle];
|
||||
|
||||
// Update the template this instane references, which may refresh the GPU
|
||||
// cache with any shared template data.
|
||||
prim_data.update(
|
||||
pic_context.surface_index,
|
||||
frame_state,
|
||||
);
|
||||
yuv_image_data.kind.update(&mut yuv_image_data.common, frame_state);
|
||||
|
||||
write_segment(prim_data, *segment_instance_index, frame_state, scratch);
|
||||
write_segment(*segment_instance_index, frame_state, scratch, |request| {
|
||||
yuv_image_data.kind.write_prim_gpu_blocks(request);
|
||||
});
|
||||
}
|
||||
PrimitiveInstanceKind::Image { data_handle, image_instance_index, .. } => {
|
||||
let prim_data = &mut resources.prim_data_store[*data_handle];
|
||||
let prim_data = &mut resources.image_data_store[*data_handle];
|
||||
let common_data = &mut prim_data.common;
|
||||
let image_data = &mut prim_data.kind;
|
||||
|
||||
// Update the template this instane references, which may refresh the GPU
|
||||
// cache with any shared template data.
|
||||
prim_data.update(
|
||||
image_data.update(
|
||||
pic_context.surface_index,
|
||||
common_data,
|
||||
frame_state,
|
||||
);
|
||||
|
||||
let (key, stretch_size, tile_spacing, image_rendering) = match prim_data.kind {
|
||||
PrimitiveTemplateKind::Image { ref key, ref stretch_size, ref tile_spacing, ref image_rendering, .. } => {
|
||||
(key, stretch_size, tile_spacing, image_rendering)
|
||||
}
|
||||
_ => unreachable!()
|
||||
};
|
||||
|
||||
let image_instance = &mut self.images[*image_instance_index];
|
||||
|
||||
update_opacity_binding(
|
||||
|
@ -3173,7 +2861,7 @@ impl PrimitiveStore {
|
|||
|
||||
let image_properties = frame_state
|
||||
.resource_cache
|
||||
.get_image_properties(*key);
|
||||
.get_image_properties(image_data.key);
|
||||
|
||||
if let Some(image_properties) = image_properties {
|
||||
if let Some(tile_size) = image_properties.tiling {
|
||||
|
@ -3192,19 +2880,19 @@ impl PrimitiveStore {
|
|||
&tight_clip_rect
|
||||
);
|
||||
|
||||
let base_edge_flags = edge_flags_for_tile_spacing(tile_spacing);
|
||||
let base_edge_flags = edge_flags_for_tile_spacing(&image_data.tile_spacing);
|
||||
|
||||
let stride = *stretch_size + *tile_spacing;
|
||||
let stride = image_data.stretch_size + image_data.tile_spacing;
|
||||
|
||||
let repetitions = image::repetitions(
|
||||
let repetitions = ::image::repetitions(
|
||||
&prim_local_rect,
|
||||
&visible_rect,
|
||||
stride,
|
||||
);
|
||||
|
||||
let request = ImageRequest {
|
||||
key: *key,
|
||||
rendering: *image_rendering,
|
||||
key: image_data.key,
|
||||
rendering: image_data.image_rendering,
|
||||
tile: None,
|
||||
};
|
||||
|
||||
|
@ -3213,10 +2901,10 @@ impl PrimitiveStore {
|
|||
|
||||
let image_rect = LayoutRect {
|
||||
origin,
|
||||
size: *stretch_size,
|
||||
size: image_data.stretch_size,
|
||||
};
|
||||
|
||||
let tiles = image::tiles(
|
||||
let tiles = ::image::tiles(
|
||||
&image_rect,
|
||||
&visible_rect,
|
||||
&device_image_size,
|
||||
|
@ -3257,7 +2945,9 @@ impl PrimitiveStore {
|
|||
}
|
||||
}
|
||||
|
||||
write_segment(prim_data, image_instance.segment_instance_index, frame_state, scratch);
|
||||
write_segment(image_instance.segment_instance_index, frame_state, scratch, |request| {
|
||||
image_data.write_prim_gpu_blocks(request);
|
||||
});
|
||||
}
|
||||
PrimitiveInstanceKind::LinearGradient { data_handle, ref mut visible_tiles_range, .. } => {
|
||||
let prim_data = &mut resources.linear_grad_data_store[*data_handle];
|
||||
|
@ -3348,12 +3038,12 @@ impl PrimitiveStore {
|
|||
}
|
||||
}
|
||||
|
||||
fn write_segment(
|
||||
prim_data: &PrimitiveTemplate,
|
||||
fn write_segment<F>(
|
||||
segment_instance_index: SegmentInstanceIndex,
|
||||
frame_state: &mut FrameBuildingState,
|
||||
scratch: &mut PrimitiveScratchBuffer,
|
||||
) {
|
||||
f: F,
|
||||
) where F: Fn(&mut GpuDataRequest) {
|
||||
debug_assert!(segment_instance_index != SegmentInstanceIndex::INVALID);
|
||||
if segment_instance_index != SegmentInstanceIndex::UNUSED {
|
||||
let segment_instance = &mut scratch.segment_instances[segment_instance_index];
|
||||
|
@ -3361,10 +3051,7 @@ fn write_segment(
|
|||
if let Some(mut request) = frame_state.gpu_cache.request(&mut segment_instance.gpu_cache_handle) {
|
||||
let segments = &scratch.segments[segment_instance.segments_range];
|
||||
|
||||
prim_data.kind.write_prim_gpu_blocks(
|
||||
&mut request,
|
||||
prim_data.prim_size,
|
||||
);
|
||||
f(&mut request);
|
||||
|
||||
for segment in segments {
|
||||
request.write_segment(
|
||||
|
@ -3402,7 +3089,7 @@ fn decompose_repeated_primitive(
|
|||
);
|
||||
let stride = *stretch_size + *tile_spacing;
|
||||
|
||||
let repetitions = image::repetitions(prim_local_rect, &visible_rect, stride);
|
||||
let repetitions = ::image::repetitions(prim_local_rect, &visible_rect, stride);
|
||||
for Repetition { origin, .. } in repetitions {
|
||||
let mut handle = GpuCacheHandle::new();
|
||||
let rect = LayoutRect {
|
||||
|
@ -3622,22 +3309,17 @@ impl PrimitiveInstance {
|
|||
segment_instance_index
|
||||
}
|
||||
PrimitiveInstanceKind::Image { data_handle, image_instance_index, .. } => {
|
||||
let prim_data = &resources.prim_data_store[data_handle];
|
||||
let image_data = &resources.image_data_store[data_handle].kind;
|
||||
let image_instance = &mut prim_store.images[image_instance_index];
|
||||
match prim_data.kind {
|
||||
PrimitiveTemplateKind::Image { key, .. } => {
|
||||
// tiled images don't support segmentation
|
||||
if frame_state
|
||||
.resource_cache
|
||||
.get_image_properties(key)
|
||||
.and_then(|properties| properties.tiling)
|
||||
.is_some() {
|
||||
image_instance.segment_instance_index = SegmentInstanceIndex::UNUSED;
|
||||
return;
|
||||
}
|
||||
// tiled images don't support segmentation
|
||||
if frame_state
|
||||
.resource_cache
|
||||
.get_image_properties(image_data.key)
|
||||
.and_then(|properties| properties.tiling)
|
||||
.is_some() {
|
||||
image_instance.segment_instance_index = SegmentInstanceIndex::UNUSED;
|
||||
return;
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
&mut image_instance.segment_instance_index
|
||||
}
|
||||
PrimitiveInstanceKind::Picture { .. } |
|
||||
|
@ -4056,8 +3738,8 @@ fn test_struct_sizes() {
|
|||
// be done with care, and after checking if talos performance regresses badly.
|
||||
assert_eq!(mem::size_of::<PrimitiveInstance>(), 128, "PrimitiveInstance size changed");
|
||||
assert_eq!(mem::size_of::<PrimitiveInstanceKind>(), 40, "PrimitiveInstanceKind size changed");
|
||||
assert_eq!(mem::size_of::<PrimitiveTemplate>(), 144, "PrimitiveTemplate size changed");
|
||||
assert_eq!(mem::size_of::<PrimitiveTemplateKind>(), 88, "PrimitiveTemplateKind size changed");
|
||||
assert_eq!(mem::size_of::<PrimitiveTemplate>(), 112, "PrimitiveTemplate size changed");
|
||||
assert_eq!(mem::size_of::<PrimitiveTemplateKind>(), 56, "PrimitiveTemplateKind size changed");
|
||||
assert_eq!(mem::size_of::<PrimitiveKey>(), 124, "PrimitiveKey size changed");
|
||||
assert_eq!(mem::size_of::<PrimitiveKeyKind>(), 96, "PrimitiveKeyKind size changed");
|
||||
}
|
||||
|
|
|
@ -404,9 +404,11 @@ pub struct IpcProfileCounters {
|
|||
#[derive(Clone)]
|
||||
pub struct InternProfileCounters {
|
||||
pub prims: ResourceProfileCounter,
|
||||
pub images: ResourceProfileCounter,
|
||||
pub linear_gradients: ResourceProfileCounter,
|
||||
pub radial_gradients: ResourceProfileCounter,
|
||||
pub text_runs: ResourceProfileCounter,
|
||||
pub yuv_images: ResourceProfileCounter,
|
||||
pub clips: ResourceProfileCounter,
|
||||
}
|
||||
|
||||
|
@ -450,9 +452,11 @@ impl BackendProfileCounters {
|
|||
},
|
||||
intern: InternProfileCounters {
|
||||
prims: ResourceProfileCounter::new("Interned primitives"),
|
||||
images: ResourceProfileCounter::new("Interned images"),
|
||||
linear_gradients: ResourceProfileCounter::new("Interned linear gradients"),
|
||||
radial_gradients: ResourceProfileCounter::new("Interned radial gradients"),
|
||||
text_runs: ResourceProfileCounter::new("Interned text runs"),
|
||||
yuv_images: ResourceProfileCounter::new("Interned YUV images"),
|
||||
clips: ResourceProfileCounter::new("Interned clips"),
|
||||
},
|
||||
}
|
||||
|
@ -1103,9 +1107,11 @@ impl Profiler {
|
|||
&[
|
||||
&backend_profile.intern.clips,
|
||||
&backend_profile.intern.prims,
|
||||
&backend_profile.intern.images,
|
||||
&backend_profile.intern.linear_gradients,
|
||||
&backend_profile.intern.radial_gradients,
|
||||
&backend_profile.intern.text_runs,
|
||||
&backend_profile.intern.yuv_images,
|
||||
],
|
||||
debug_renderer,
|
||||
true,
|
||||
|
|
|
@ -34,6 +34,7 @@ use picture::RetainedTiles;
|
|||
use prim_store::{PrimitiveDataStore, PrimitiveScratchBuffer, PrimitiveInstance};
|
||||
use prim_store::{PrimitiveInstanceKind, PrimTemplateCommonData};
|
||||
use prim_store::gradient::{LinearGradientDataStore, RadialGradientDataStore};
|
||||
use prim_store::image::{ImageDataStore, YuvImageDataStore};
|
||||
use prim_store::text_run::TextRunDataStore;
|
||||
use profiler::{BackendProfileCounters, IpcProfileCounters, ResourceProfileCounters};
|
||||
use record::ApiRecordingReceiver;
|
||||
|
@ -205,9 +206,11 @@ pub struct FrameResources {
|
|||
/// Currently active / available primitives. Kept in sync with the
|
||||
/// primitive interner in the scene builder, per document.
|
||||
pub prim_data_store: PrimitiveDataStore,
|
||||
pub image_data_store: ImageDataStore,
|
||||
pub linear_grad_data_store: LinearGradientDataStore,
|
||||
pub radial_grad_data_store: RadialGradientDataStore,
|
||||
pub text_run_data_store: TextRunDataStore,
|
||||
pub yuv_image_data_store: YuvImageDataStore,
|
||||
}
|
||||
|
||||
impl FrameResources {
|
||||
|
@ -221,12 +224,14 @@ impl FrameResources {
|
|||
PrimitiveInstanceKind::NormalBorder { data_handle, .. } |
|
||||
PrimitiveInstanceKind::ImageBorder { data_handle, .. } |
|
||||
PrimitiveInstanceKind::Rectangle { data_handle, .. } |
|
||||
PrimitiveInstanceKind::YuvImage { data_handle, .. } |
|
||||
PrimitiveInstanceKind::Image { data_handle, .. } |
|
||||
PrimitiveInstanceKind::Clear { data_handle, .. } => {
|
||||
let prim_data = &self.prim_data_store[data_handle];
|
||||
&prim_data.common
|
||||
}
|
||||
PrimitiveInstanceKind::Image { data_handle, .. } => {
|
||||
let prim_data = &self.image_data_store[data_handle];
|
||||
&prim_data.common
|
||||
}
|
||||
PrimitiveInstanceKind::LinearGradient { data_handle, .. } => {
|
||||
let prim_data = &self.linear_grad_data_store[data_handle];
|
||||
&prim_data.common
|
||||
|
@ -239,6 +244,10 @@ impl FrameResources {
|
|||
let prim_data = &self.text_run_data_store[data_handle];
|
||||
&prim_data.common
|
||||
}
|
||||
PrimitiveInstanceKind::YuvImage { data_handle, .. } => {
|
||||
let prim_data = &self.yuv_image_data_store[data_handle];
|
||||
&prim_data.common
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1221,6 +1230,10 @@ impl RenderBackend {
|
|||
updates.prim_updates,
|
||||
&mut profile_counters.intern.prims,
|
||||
);
|
||||
doc.resources.image_data_store.apply_updates(
|
||||
updates.image_updates,
|
||||
&mut profile_counters.intern.images,
|
||||
);
|
||||
doc.resources.linear_grad_data_store.apply_updates(
|
||||
updates.linear_grad_updates,
|
||||
&mut profile_counters.intern.linear_gradients,
|
||||
|
@ -1233,6 +1246,10 @@ impl RenderBackend {
|
|||
updates.text_run_updates,
|
||||
&mut profile_counters.intern.text_runs,
|
||||
);
|
||||
doc.resources.yuv_image_data_store.apply_updates(
|
||||
updates.yuv_image_updates,
|
||||
&mut profile_counters.intern.yuv_images,
|
||||
);
|
||||
}
|
||||
|
||||
// TODO: this scroll variable doesn't necessarily mean we scrolled. It is only used
|
||||
|
@ -1712,4 +1729,3 @@ impl RenderBackend {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -21,7 +21,8 @@ use gpu_types::{BorderInstance, ImageSource, UvRectKind};
|
|||
use internal_types::{CacheTextureId, FastHashMap, LayerIndex, SavedTargetIndex};
|
||||
#[cfg(feature = "pathfinder")]
|
||||
use pathfinder_partitioner::mesh::Mesh;
|
||||
use prim_store::{PictureIndex, ImageCacheKey, LineDecorationCacheKey};
|
||||
use prim_store::{PictureIndex, LineDecorationCacheKey};
|
||||
use prim_store::image::ImageCacheKey;
|
||||
#[cfg(feature = "debugger")]
|
||||
use print_tree::{PrintTreePrinter};
|
||||
use render_backend::FrameId;
|
||||
|
|
|
@ -20,6 +20,10 @@ use prim_store::gradient::{
|
|||
LinearGradient, LinearGradientDataInterner, LinearGradientDataUpdateList,
|
||||
RadialGradient, RadialGradientDataInterner, RadialGradientDataUpdateList
|
||||
};
|
||||
use prim_store::image::{
|
||||
Image, ImageDataInterner, ImageDataUpdateList,
|
||||
YuvImage, YuvImageDataInterner, YuvImageDataUpdateList,
|
||||
};
|
||||
use prim_store::text_run::{TextRunDataInterner, TextRun, TextRunDataUpdateList};
|
||||
use resource_cache::{BlobImageRasterizerEpoch, FontInstanceMap};
|
||||
use render_backend::DocumentView;
|
||||
|
@ -35,9 +39,11 @@ use std::time::Duration;
|
|||
pub struct DocumentResourceUpdates {
|
||||
pub clip_updates: ClipDataUpdateList,
|
||||
pub prim_updates: PrimitiveDataUpdateList,
|
||||
pub image_updates: ImageDataUpdateList,
|
||||
pub linear_grad_updates: LinearGradientDataUpdateList,
|
||||
pub radial_grad_updates: RadialGradientDataUpdateList,
|
||||
pub text_run_updates: TextRunDataUpdateList,
|
||||
pub yuv_image_updates: YuvImageDataUpdateList,
|
||||
}
|
||||
|
||||
/// Represents the work associated to a transaction before scene building.
|
||||
|
@ -185,9 +191,11 @@ pub enum SceneSwapResult {
|
|||
pub struct DocumentResources {
|
||||
pub clip_interner: ClipDataInterner,
|
||||
pub prim_interner: PrimitiveDataInterner,
|
||||
pub image_interner: ImageDataInterner,
|
||||
pub linear_grad_interner: LinearGradientDataInterner,
|
||||
pub radial_grad_interner: RadialGradientDataInterner,
|
||||
pub text_run_interner: TextRunDataInterner,
|
||||
pub yuv_image_interner: YuvImageDataInterner,
|
||||
}
|
||||
|
||||
// Access to `DocumentResources` interners by `Internable`
|
||||
|
@ -196,31 +204,29 @@ pub trait InternerMut<I: Internable>
|
|||
fn interner_mut(&mut self) -> &mut Interner<I::Source, I::InternData, I::Marker>;
|
||||
}
|
||||
|
||||
impl InternerMut<PrimitiveKeyKind> for DocumentResources {
|
||||
fn interner_mut(&mut self) -> &mut PrimitiveDataInterner {
|
||||
&mut self.prim_interner
|
||||
macro_rules! impl_internet_mut {
|
||||
($($ty:ident: $mem:ident,)*) => {
|
||||
$(impl InternerMut<$ty> for DocumentResources {
|
||||
fn interner_mut(&mut self) -> &mut Interner<
|
||||
<$ty as Internable>::Source,
|
||||
<$ty as Internable>::InternData,
|
||||
<$ty as Internable>::Marker
|
||||
> {
|
||||
&mut self.$mem
|
||||
}
|
||||
})*
|
||||
}
|
||||
}
|
||||
|
||||
impl InternerMut<LinearGradient> for DocumentResources {
|
||||
fn interner_mut(&mut self) -> &mut LinearGradientDataInterner {
|
||||
&mut self.linear_grad_interner
|
||||
}
|
||||
impl_internet_mut! {
|
||||
Image: image_interner,
|
||||
LinearGradient: linear_grad_interner,
|
||||
RadialGradient: radial_grad_interner,
|
||||
TextRun: text_run_interner,
|
||||
PrimitiveKeyKind: prim_interner,
|
||||
YuvImage: yuv_image_interner,
|
||||
}
|
||||
|
||||
impl InternerMut<RadialGradient> for DocumentResources {
|
||||
fn interner_mut(&mut self) -> &mut RadialGradientDataInterner {
|
||||
&mut self.radial_grad_interner
|
||||
}
|
||||
}
|
||||
|
||||
impl InternerMut<TextRun> for DocumentResources {
|
||||
fn interner_mut(&mut self) -> &mut TextRunDataInterner {
|
||||
&mut self.text_run_interner
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// A document in the scene builder contains the current scene,
|
||||
// as well as a persistent clip interner. This allows clips
|
||||
// to be de-duplicated, and persisted in the GPU cache between
|
||||
|
@ -391,6 +397,11 @@ impl SceneBuilder {
|
|||
.prim_interner
|
||||
.end_frame_and_get_pending_updates();
|
||||
|
||||
let image_updates = item
|
||||
.doc_resources
|
||||
.image_interner
|
||||
.end_frame_and_get_pending_updates();
|
||||
|
||||
let linear_grad_updates = item
|
||||
.doc_resources
|
||||
.linear_grad_interner
|
||||
|
@ -406,13 +417,20 @@ impl SceneBuilder {
|
|||
.text_run_interner
|
||||
.end_frame_and_get_pending_updates();
|
||||
|
||||
let yuv_image_updates = item
|
||||
.doc_resources
|
||||
.yuv_image_interner
|
||||
.end_frame_and_get_pending_updates();
|
||||
|
||||
doc_resource_updates = Some(
|
||||
DocumentResourceUpdates {
|
||||
clip_updates,
|
||||
prim_updates,
|
||||
image_updates,
|
||||
linear_grad_updates,
|
||||
radial_grad_updates,
|
||||
text_run_updates,
|
||||
yuv_image_updates,
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -521,6 +539,11 @@ impl SceneBuilder {
|
|||
.prim_interner
|
||||
.end_frame_and_get_pending_updates();
|
||||
|
||||
let image_updates = doc
|
||||
.resources
|
||||
.image_interner
|
||||
.end_frame_and_get_pending_updates();
|
||||
|
||||
let linear_grad_updates = doc
|
||||
.resources
|
||||
.linear_grad_interner
|
||||
|
@ -536,13 +559,20 @@ impl SceneBuilder {
|
|||
.text_run_interner
|
||||
.end_frame_and_get_pending_updates();
|
||||
|
||||
let yuv_image_updates = doc
|
||||
.resources
|
||||
.yuv_image_interner
|
||||
.end_frame_and_get_pending_updates();
|
||||
|
||||
doc_resource_updates = Some(
|
||||
DocumentResourceUpdates {
|
||||
clip_updates,
|
||||
prim_updates,
|
||||
image_updates,
|
||||
linear_grad_updates,
|
||||
radial_grad_updates,
|
||||
text_run_updates,
|
||||
yuv_image_updates,
|
||||
}
|
||||
);
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче