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:
WR Updater Bot 2018-12-18 14:15:39 +00:00
Родитель 64b3a44ed2
Коммит 48eec304c7
10 изменённых файлов: 806 добавлений и 500 удалений

Просмотреть файл

@ -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)
.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,
}
);