Bug 1921980 - Adjust the image primitive to compensate for the difference in the picture's rasterized area. r=gw

Differential Revision: https://phabricator.services.mozilla.com/D227256
This commit is contained in:
Nicolas Silva 2024-11-07 09:01:56 +00:00
Родитель c0c13f6ff1
Коммит be82e29897
5 изменённых файлов: 140 добавлений и 17 удалений

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

@ -2569,9 +2569,13 @@ impl BatchBuilder {
(gpu_cache.get_address(&segment_instance.gpu_cache_handle), segments)
};
let local_rect = image_instance.adjustment.map_local_rect(&prim_rect);
let local_clip_rect = image_instance.tight_local_clip_rect
.intersection_unchecked(&local_rect);
let prim_header = PrimitiveHeader {
local_rect: prim_rect,
local_clip_rect: prim_info.clip_chain.local_clip_rect,
local_rect,
local_clip_rect,
specific_prim_address: prim_cache_address,
transform_id,
};

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

@ -99,6 +99,7 @@ use api::{PropertyBinding, PropertyBindingId, FilterPrimitive, FilterOpGraphPict
use api::{DebugFlags, ImageKey, ColorF, ColorU, PrimitiveFlags, SnapshotInfo};
use api::{ImageRendering, ColorDepth, YuvRangedColorSpace, YuvFormat, AlphaType};
use api::units::*;
use crate::prim_store::image::AdjustedImageSource;
use crate::{command_buffer::PrimitiveCommand, render_task_graph::RenderTaskGraphBuilder, renderer::GpuBufferBuilderF};
use crate::box_shadow::BLUR_SAMPLE_SCALE;
use crate::clip::{ClipStore, ClipChainInstance, ClipLeafId, ClipNodeId, ClipTreeBuilder};
@ -8334,6 +8335,10 @@ fn request_render_task(
let task_id = match snapshot {
Some(info) => {
let adjustment = AdjustedImageSource::from_rects(
&info.area,
&surface_rects.clipped_local.cast_unit()
);
let task_id = frame_state.resource_cache.render_as_image(
info.key.as_image(),
surface_rects.task_size,
@ -8341,6 +8346,7 @@ fn request_render_task(
&mut frame_state.frame_gpu_data.f32,
frame_state.gpu_cache,
is_opaque,
&adjustment,
f
);

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

@ -718,7 +718,7 @@ fn prepare_interned_prim_for_render(
&mut scratch.segments,
&mut scratch.segment_instances,
|request| {
image_data.write_prim_gpu_blocks(request);
image_data.write_prim_gpu_blocks(&image_instance.adjustment, request);
},
);
}

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

@ -8,6 +8,7 @@ use api::{
RasterSpace, Shadow, YuvColorSpace, ColorRange, YuvFormat,
};
use api::units::*;
use euclid::point2;
use crate::composite::CompositorSurfaceKind;
use crate::scene_building::{CreateShadow, IsVisible};
use crate::frame_builder::{FrameBuildingContext, FrameBuildingState};
@ -72,6 +73,7 @@ pub struct ImageInstance {
pub visible_tiles: Vec<VisibleImageTile>,
pub src_color: Option<RenderTaskId>,
pub normalized_uvs: bool,
pub adjustment: AdjustedImageSource,
}
#[cfg_attr(feature = "capture", derive(Serialize))]
@ -169,9 +171,25 @@ impl ImageData {
tile: None,
};
// Tighten the clip rect because decomposing the repeated image can
// produce primitives that are partially covering the original image
// rect and we want to clip these extra parts out.
// We also rely on having a tight clip rect in some cases other than
// tiled/repeated images, for example when rendering a snapshot image
// where the snapshot area is tighter than the rasterized area.
let tight_clip_rect = visibility
.clip_chain
.local_clip_rect
.intersection(&common.prim_rect).unwrap();
image_instance.tight_local_clip_rect = tight_clip_rect;
image_instance.adjustment = AdjustedImageSource::new();
match image_properties {
// Non-tiled (most common) path.
Some(ImageProperties { tiling: None, ref descriptor, ref external_image, .. }) => {
Some(ImageProperties { tiling: None, ref descriptor, ref external_image, adjustment, .. }) => {
image_instance.adjustment = adjustment;
let mut size = frame_state.resource_cache.request_image(
request,
frame_state.gpu_cache,
@ -298,15 +316,6 @@ impl ImageData {
// thing.
let active_rect = visible_rect;
// Tighten the clip rect because decomposing the repeated image can
// produce primitives that are partially covering the original image
// rect and we want to clip these extra parts out.
let tight_clip_rect = visibility
.clip_chain
.local_clip_rect
.intersection(&common.prim_rect).unwrap();
image_instance.tight_local_clip_rect = tight_clip_rect;
let visible_rect = compute_conservative_visible_rect(
&visibility.clip_chain,
frame_state.current_dirty_region().combined,
@ -374,19 +383,20 @@ impl ImageData {
}
if let Some(mut request) = frame_state.gpu_cache.request(&mut common.gpu_cache_handle) {
self.write_prim_gpu_blocks(&mut request);
self.write_prim_gpu_blocks(&image_instance.adjustment, &mut request);
}
}
pub fn write_prim_gpu_blocks(&self, request: &mut GpuDataRequest) {
pub fn write_prim_gpu_blocks(&self, adjustment: &AdjustedImageSource, request: &mut GpuDataRequest) {
let stretch_size = adjustment.map_stretch_size(self.stretch_size);
// Images are drawn as a white color, modulated by the total
// opacity coming from any collapsed property bindings.
// Size has to match `VECS_PER_SPECIFIC_BRUSH` from `brush_image.glsl` exactly.
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,
stretch_size.width + self.tile_spacing.width,
stretch_size.height + self.tile_spacing.height,
0.0,
0.0,
]);
@ -449,6 +459,7 @@ impl InternablePrimitive for Image {
visible_tiles: Vec::new(),
src_color: None,
normalized_uvs: false,
adjustment: AdjustedImageSource::new(),
});
PrimitiveInstanceKind::Image {
@ -483,6 +494,95 @@ impl IsVisible for Image {
}
}
/// Represents an adjustment to apply to an image primitive.
/// This can be used to compensate for a difference between the bounds of
/// the images expected by the primitive and the bounds that were actually
/// drawn in the texture cache.
///
/// This happens when rendering snapshot images: A picture is marked so that
/// a specific reference area in layout space can be rendered as an image.
/// However, the bounds of the rasterized area of the picture typically differ
/// from that reference area.
///
/// The adjustment is stored as 4 floats (x0, y0, x1, y1) that represent a
/// transformation of the primitve's local rect such that:
///
/// ```
/// adjusted_rect.min = prim_rect.min + prim_rect.size() * (x0, y0);
/// adjusted_rect.max = prim_rect.max + prim_rect.size() * (x1, y1);
/// ```
#[derive(Copy, Clone, Debug)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct AdjustedImageSource {
x0: f32,
y0: f32,
x1: f32,
y1: f32,
}
impl AdjustedImageSource {
/// The "identity" adjustment.
pub fn new() -> Self {
AdjustedImageSource {
x0: 0.0,
y0: 0.0,
x1: 0.0,
y1: 0.0,
}
}
/// An adjustment to render an image item defined in function of the `reference`
/// rect whereas the `actual` rect was cached instead.
pub fn from_rects(reference: &LayoutRect, actual: &LayoutRect) -> Self {
let ref_size = reference.size();
let min_offset = reference.min.to_vector();
let max_offset = reference.max.to_vector();
AdjustedImageSource {
x0: (actual.min.x - min_offset.x) / ref_size.width,
y0: (actual.min.y - min_offset.y) / ref_size.height,
x1: (actual.max.x - max_offset.x) / ref_size.width,
y1: (actual.max.y - max_offset.y) / ref_size.height,
}
}
/// Adjust the primitive's local rect.
pub fn map_local_rect(&self, rect: &LayoutRect) -> LayoutRect {
let w = rect.width();
let h = rect.height();
LayoutRect {
min: point2(
rect.min.x + w * self.x0,
rect.min.y + h * self.y0,
),
max: point2(
rect.max.x + w * self.x1,
rect.max.y + h * self.y1,
),
}
}
/// The stretch size has to be adjusted as well because it is defined
/// using the snapshot area as reference but will stretch the rasterized
/// area instead.
///
/// It has to be scaled by a factor of (adjusted.size() / prim_rect.size()).
/// We derive the formula in function of the adjustment factors:
///
/// ```
/// factor = (adjusted.max - adjusted.min) / (w, h)
/// = (rect.max + (w, h) * (x1, y1) - (rect.min + (w, h) * (x0, y0))) / (w, h)
/// = ((w, h) + (w, h) * (x1, y1) - (w, h) * (x0, y0)) / (w, h)
/// = (1.0, 1.0) + (x1, y1) - (x0, y0)
/// ```
pub fn map_stretch_size(&self, size: LayoutSize) -> LayoutSize {
LayoutSize::new(
size.width * (1.0 + self.x1 - self.x0),
size.height * (1.0 + self.y1 - self.y0),
)
}
}
////////////////////////////////////////////////////////////////////////////////
#[cfg_attr(feature = "capture", derive(Serialize))]

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

@ -13,6 +13,7 @@ use euclid::size2;
use crate::render_target::RenderTargetKind;
use crate::render_task::{RenderTaskLocation, StaticRenderTaskSurface};
use crate::{render_api::{ClearCache, AddFont, ResourceUpdate, MemoryReport}, util::WeakTable};
use crate::prim_store::image::AdjustedImageSource;
use crate::image_tiling::{compute_tile_size, compute_tile_range};
#[cfg(feature = "capture")]
use crate::capture::ExternalCaptureImage;
@ -178,6 +179,7 @@ pub struct ImageProperties {
// Potentially a subset of the image's total rectangle. This rectangle is what
// we map to the (layout space) display item bounds.
pub visible_rect: DeviceIntRect,
pub adjustment: AdjustedImageSource,
}
#[derive(Debug, Copy, Clone, PartialEq)]
@ -206,6 +208,7 @@ struct ImageResource {
/// This is used to express images that are virtually very large
/// but with only a visible sub-set that is valid at a given time.
visible_rect: DeviceIntRect,
adjustment: AdjustedImageSource,
generation: ImageGeneration,
}
@ -636,6 +639,7 @@ impl ResourceCache {
gpu_buffer_builder: &mut GpuBufferBuilderF,
gpu_cache: &mut GpuCache,
is_opaque: bool,
adjustment: &AdjustedImageSource,
f: &mut dyn FnMut(&mut RenderTaskGraphBuilder, &mut GpuBufferBuilderF, &mut GpuCache) -> RenderTaskId,
) -> RenderTaskId {
@ -698,6 +702,11 @@ impl ResourceCache {
})
);
self.resources.image_templates
.get_mut(image_key)
.unwrap()
.adjustment = *adjustment;
task_id
}
@ -924,6 +933,7 @@ impl ResourceCache {
data,
tiling,
visible_rect: *visible_rect,
adjustment: AdjustedImageSource::new(),
generation: ImageGeneration(0),
};
@ -993,6 +1003,7 @@ impl ResourceCache {
data,
tiling,
visible_rect: descriptor.size.into(),
adjustment: AdjustedImageSource::new(),
generation: ImageGeneration(image.generation.0 + 1),
};
}
@ -1373,6 +1384,7 @@ impl ResourceCache {
external_image,
tiling: image_template.tiling,
visible_rect: image_template.visible_rect,
adjustment: image_template.adjustment,
}
})
}
@ -2405,6 +2417,7 @@ impl ResourceCache {
descriptor: template.descriptor,
tiling: template.tiling,
visible_rect: template.descriptor.size.into(),
adjustment: AdjustedImageSource::new(), // TODO(nical)
generation: template.generation,
});
}