зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1574493 - Part 2. Remove snapping in frame building. r=kvark
This will be rewritten in a later patch in the series. The shaders will be provided the correct information and will no longer need to concern themselves with snapping. Differential Revision: https://phabricator.services.mozilla.com/D45057 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
7cda552aeb
Коммит
571a0f49e1
|
@ -70,9 +70,7 @@ void main(void) {
|
|||
ph.local_clip_rect,
|
||||
ph.z,
|
||||
transform,
|
||||
pic_task,
|
||||
ph.local_rect,
|
||||
ph.snap_offsets
|
||||
pic_task
|
||||
);
|
||||
|
||||
// TODO(gw): transform bounds may be referenced by
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* 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/. */
|
||||
|
||||
#include rect,render_task,gpu_cache,snap,transform
|
||||
#include rect,render_task,gpu_cache,transform
|
||||
|
||||
#ifdef WR_VERTEX_SHADER
|
||||
|
||||
|
@ -11,7 +11,6 @@ in ivec4 aClipDataResourceAddress;
|
|||
in vec2 aClipLocalPos;
|
||||
in vec4 aClipTileRect;
|
||||
in vec4 aClipDeviceArea;
|
||||
in vec4 aClipSnapOffsets;
|
||||
in vec4 aClipOrigins;
|
||||
in float aDevicePixelScale;
|
||||
|
||||
|
@ -23,7 +22,6 @@ struct ClipMaskInstance {
|
|||
vec2 local_pos;
|
||||
RectWithSize tile_rect;
|
||||
RectWithSize sub_rect;
|
||||
vec4 snap_offsets;
|
||||
vec2 task_origin;
|
||||
vec2 screen_origin;
|
||||
float device_pixel_scale;
|
||||
|
@ -39,7 +37,6 @@ ClipMaskInstance fetch_clip_item() {
|
|||
cmi.local_pos = aClipLocalPos;
|
||||
cmi.tile_rect = RectWithSize(aClipTileRect.xy, aClipTileRect.zw);
|
||||
cmi.sub_rect = RectWithSize(aClipDeviceArea.xy, aClipDeviceArea.zw);
|
||||
cmi.snap_offsets = aClipSnapOffsets;
|
||||
cmi.task_origin = aClipOrigins.xy;
|
||||
cmi.screen_origin = aClipOrigins.zw;
|
||||
cmi.device_pixel_scale = aDevicePixelScale;
|
||||
|
@ -64,23 +61,10 @@ ClipVertexInfo write_clip_tile_vertex(RectWithSize local_clip_rect,
|
|||
Transform prim_transform,
|
||||
Transform clip_transform,
|
||||
RectWithSize sub_rect,
|
||||
vec4 snap_offsets,
|
||||
vec2 task_origin,
|
||||
vec2 screen_origin,
|
||||
float device_pixel_scale) {
|
||||
vec2 device_pos = screen_origin + sub_rect.p0 + aPosition.xy * sub_rect.size;
|
||||
|
||||
// If the primitive we are drawing a clip mask for was snapped, then
|
||||
// remove the effect of that snapping, so that the local position
|
||||
// interpolation below works correctly relative to the clip item.
|
||||
vec2 snap_offset = mix(
|
||||
snap_offsets.xy,
|
||||
snap_offsets.zw,
|
||||
aPosition.xy
|
||||
);
|
||||
|
||||
device_pos -= snap_offset;
|
||||
|
||||
vec2 world_pos = device_pos / device_pixel_scale;
|
||||
|
||||
vec4 pos = prim_transform.m * vec4(world_pos, 0.0, 1.0);
|
||||
|
|
|
@ -52,7 +52,6 @@ void main(void) {
|
|||
prim_transform,
|
||||
clip_transform,
|
||||
cmi.sub_rect,
|
||||
cmi.snap_offsets,
|
||||
cmi.task_origin,
|
||||
cmi.screen_origin,
|
||||
cmi.device_pixel_scale
|
||||
|
|
|
@ -35,7 +35,6 @@ void main(void) {
|
|||
prim_transform,
|
||||
clip_transform,
|
||||
cmi.sub_rect,
|
||||
cmi.snap_offsets,
|
||||
cmi.task_origin,
|
||||
cmi.screen_origin,
|
||||
cmi.device_pixel_scale
|
||||
|
|
|
@ -77,7 +77,6 @@ void main(void) {
|
|||
prim_transform,
|
||||
clip_transform,
|
||||
cmi.sub_rect,
|
||||
cmi.snap_offsets,
|
||||
cmi.task_origin,
|
||||
cmi.screen_origin,
|
||||
cmi.device_pixel_scale
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* 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/. */
|
||||
|
||||
#include rect,render_task,gpu_cache,snap,transform
|
||||
#include rect,render_task,gpu_cache,transform
|
||||
|
||||
#define EXTEND_MODE_CLAMP 0
|
||||
#define EXTEND_MODE_REPEAT 1
|
||||
|
@ -47,13 +47,12 @@ uniform HIGHP_SAMPLER_FLOAT isampler2D sPrimitiveHeadersI;
|
|||
// Instanced attributes
|
||||
in ivec4 aData;
|
||||
|
||||
#define VECS_PER_PRIM_HEADER_F 3U
|
||||
#define VECS_PER_PRIM_HEADER_F 2U
|
||||
#define VECS_PER_PRIM_HEADER_I 2U
|
||||
|
||||
struct PrimitiveHeader {
|
||||
RectWithSize local_rect;
|
||||
RectWithSize local_clip_rect;
|
||||
vec4 snap_offsets;
|
||||
float z;
|
||||
int specific_prim_address;
|
||||
int transform_id;
|
||||
|
@ -66,7 +65,6 @@ PrimitiveHeader fetch_prim_header(int index) {
|
|||
ivec2 uv_f = get_fetch_uv(index, VECS_PER_PRIM_HEADER_F);
|
||||
vec4 local_rect = TEXEL_FETCH(sPrimitiveHeadersF, uv_f, 0, ivec2(0, 0));
|
||||
vec4 local_clip_rect = TEXEL_FETCH(sPrimitiveHeadersF, uv_f, 0, ivec2(1, 0));
|
||||
ph.snap_offsets = TEXEL_FETCH(sPrimitiveHeadersF, uv_f, 0, ivec2(2, 0));
|
||||
ph.local_rect = RectWithSize(local_rect.xy, local_rect.zw);
|
||||
ph.local_clip_rect = RectWithSize(local_clip_rect.xy, local_clip_rect.zw);
|
||||
|
||||
|
@ -91,9 +89,7 @@ VertexInfo write_vertex(RectWithSize instance_rect,
|
|||
RectWithSize local_clip_rect,
|
||||
float z,
|
||||
Transform transform,
|
||||
PictureTask task,
|
||||
RectWithSize snap_rect,
|
||||
vec4 snap_offsets) {
|
||||
PictureTask task) {
|
||||
|
||||
// Select the corner of the local rect that we are processing.
|
||||
vec2 local_pos = instance_rect.p0 + instance_rect.size * aPosition.xy;
|
||||
|
@ -101,13 +97,6 @@ VertexInfo write_vertex(RectWithSize instance_rect,
|
|||
// Clamp to the two local clip rects.
|
||||
vec2 clamped_local_pos = clamp_rect(local_pos, local_clip_rect);
|
||||
|
||||
/// Compute the snapping offset.
|
||||
vec2 snap_offset = compute_snap_offset(
|
||||
clamped_local_pos,
|
||||
snap_rect,
|
||||
snap_offsets
|
||||
);
|
||||
|
||||
// Transform the current vertex to world space.
|
||||
vec4 world_pos = transform.m * vec4(clamped_local_pos, 0.0, 1.0);
|
||||
|
||||
|
@ -115,13 +104,13 @@ VertexInfo write_vertex(RectWithSize instance_rect,
|
|||
vec2 device_pos = world_pos.xy * task.device_pixel_scale;
|
||||
|
||||
// Apply offsets for the render task to get correct screen location.
|
||||
vec2 final_offset = snap_offset - task.content_origin + task.common_data.task_rect.p0;
|
||||
vec2 final_offset = -task.content_origin + task.common_data.task_rect.p0;
|
||||
|
||||
gl_Position = uTransform * vec4(device_pos + final_offset * world_pos.w, z * world_pos.w, world_pos.w);
|
||||
|
||||
VertexInfo vi = VertexInfo(
|
||||
clamped_local_pos,
|
||||
snap_offset,
|
||||
vec2(0.0, 0.0),
|
||||
world_pos
|
||||
);
|
||||
|
||||
|
|
|
@ -1,22 +0,0 @@
|
|||
/* 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/. */
|
||||
|
||||
#ifdef WR_VERTEX_SHADER
|
||||
|
||||
/// Given a point within a local rectangle, and the device space corners
|
||||
/// offsets for the unsnapped primitive, return the snap offsets. This *must*
|
||||
/// exactly match the logic in the Rust compute_snap_offset_impl function.
|
||||
vec2 compute_snap_offset(
|
||||
vec2 reference_pos,
|
||||
RectWithSize reference_rect,
|
||||
vec4 snap_positions
|
||||
) {
|
||||
/// Compute the position of this vertex inside the snap rectangle.
|
||||
vec2 normalized_snap_pos = (reference_pos - reference_rect.p0) / reference_rect.size;
|
||||
|
||||
/// Compute the actual world offset for this vertex needed to make it snap.
|
||||
return mix(snap_positions.xy, snap_positions.zw, normalized_snap_pos);
|
||||
}
|
||||
|
||||
#endif //WR_VERTEX_SHADER
|
|
@ -10,7 +10,7 @@ use crate::clip_scroll_tree::{ClipScrollTree, ROOT_SPATIAL_NODE_INDEX, SpatialNo
|
|||
use crate::glyph_rasterizer::GlyphFormat;
|
||||
use crate::gpu_cache::{GpuBlockData, GpuCache, GpuCacheHandle, GpuCacheAddress};
|
||||
use crate::gpu_types::{BrushFlags, BrushInstance, PrimitiveHeaders, ZBufferId, ZBufferIdGenerator};
|
||||
use crate::gpu_types::{ClipMaskInstance, SplitCompositeInstance, SnapOffsets};
|
||||
use crate::gpu_types::{ClipMaskInstance, SplitCompositeInstance};
|
||||
use crate::gpu_types::{PrimitiveInstanceData, RasterizationSpace, GlyphInstance};
|
||||
use crate::gpu_types::{PrimitiveHeader, PrimitiveHeaderIndex, TransformPaletteId, TransformPalette};
|
||||
use crate::internal_types::{FastHashMap, SavedTargetIndex, Swizzle, TextureSource, Filter};
|
||||
|
@ -18,7 +18,6 @@ use crate::picture::{Picture3DContext, PictureCompositeMode, PicturePrimitive, T
|
|||
use crate::prim_store::{DeferredResolve, EdgeAaSegmentMask, PrimitiveInstanceKind, PrimitiveVisibilityIndex, PrimitiveVisibilityMask};
|
||||
use crate::prim_store::{VisibleGradientTile, PrimitiveInstance, PrimitiveOpacity, SegmentInstanceIndex};
|
||||
use crate::prim_store::{BrushSegment, ClipMaskKind, ClipTaskIndex, VECS_PER_SEGMENT};
|
||||
use crate::prim_store::{recompute_snap_offsets};
|
||||
use crate::prim_store::image::ImageSource;
|
||||
use crate::render_backend::DataStores;
|
||||
use crate::render_target::RenderTargetContext;
|
||||
|
@ -708,7 +707,7 @@ impl BatchBuilder {
|
|||
let prim_common_data = &ctx.data_stores.as_common_data(&prim_instance);
|
||||
let prim_rect = LayoutRect::new(
|
||||
prim_instance.prim_origin,
|
||||
prim_common_data.prim_size,
|
||||
prim_common_data.prim_size
|
||||
);
|
||||
|
||||
let mut batch_features = BatchFeatures::empty();
|
||||
|
@ -720,7 +719,6 @@ impl BatchBuilder {
|
|||
batch_features |= BatchFeatures::ANTIALIASING;
|
||||
}
|
||||
|
||||
let snap_offsets = prim_info.snap_offsets;
|
||||
let prim_vis_mask = prim_info.visibility_mask;
|
||||
let clip_task_address = ctx.get_prim_clip_task_address(
|
||||
prim_info.clip_task_index,
|
||||
|
@ -751,7 +749,6 @@ impl BatchBuilder {
|
|||
let prim_header = PrimitiveHeader {
|
||||
local_rect: prim_rect,
|
||||
local_clip_rect: prim_info.combined_local_clip_rect,
|
||||
snap_offsets,
|
||||
specific_prim_address: prim_cache_address,
|
||||
transform_id,
|
||||
};
|
||||
|
@ -818,7 +815,6 @@ impl BatchBuilder {
|
|||
let prim_header = PrimitiveHeader {
|
||||
local_rect: prim_rect,
|
||||
local_clip_rect: prim_info.combined_local_clip_rect,
|
||||
snap_offsets,
|
||||
specific_prim_address: prim_cache_address,
|
||||
transform_id,
|
||||
};
|
||||
|
@ -870,7 +866,6 @@ impl BatchBuilder {
|
|||
let prim_header = PrimitiveHeader {
|
||||
local_rect: prim_rect,
|
||||
local_clip_rect: prim_info.combined_local_clip_rect,
|
||||
snap_offsets,
|
||||
specific_prim_address: prim_cache_address,
|
||||
transform_id,
|
||||
};
|
||||
|
@ -1040,7 +1035,6 @@ impl BatchBuilder {
|
|||
let prim_header = PrimitiveHeader {
|
||||
local_rect: prim_rect,
|
||||
local_clip_rect: prim_info.combined_local_clip_rect,
|
||||
snap_offsets,
|
||||
specific_prim_address: prim_cache_address,
|
||||
transform_id,
|
||||
};
|
||||
|
@ -1077,9 +1071,8 @@ impl BatchBuilder {
|
|||
let prim_cache_address = gpu_cache.get_address(&ctx.globals.default_image_handle);
|
||||
|
||||
let prim_header = PrimitiveHeader {
|
||||
local_rect: picture.snapped_local_rect,
|
||||
local_rect: picture.local_rect,
|
||||
local_clip_rect: prim_info.combined_local_clip_rect,
|
||||
snap_offsets,
|
||||
specific_prim_address: prim_cache_address,
|
||||
transform_id,
|
||||
};
|
||||
|
@ -1104,9 +1097,8 @@ impl BatchBuilder {
|
|||
);
|
||||
|
||||
let prim_header = PrimitiveHeader {
|
||||
local_rect: pic.snapped_local_rect,
|
||||
local_rect: pic.local_rect,
|
||||
local_clip_rect: child_prim_info.combined_local_clip_rect,
|
||||
snap_offsets,
|
||||
specific_prim_address: GpuCacheAddress::INVALID,
|
||||
transform_id: transforms
|
||||
.get_id(
|
||||
|
@ -1225,7 +1217,6 @@ impl BatchBuilder {
|
|||
let prim_header = PrimitiveHeader {
|
||||
local_rect: local_tile_rect,
|
||||
local_clip_rect: local_tile_clip_rect,
|
||||
snap_offsets: SnapOffsets::empty(),
|
||||
specific_prim_address: prim_cache_address,
|
||||
transform_id,
|
||||
};
|
||||
|
@ -1295,7 +1286,6 @@ impl BatchBuilder {
|
|||
let prim_header = PrimitiveHeader {
|
||||
local_rect: local_tile_rect,
|
||||
local_clip_rect: local_tile_clip_rect,
|
||||
snap_offsets: SnapOffsets::empty(),
|
||||
specific_prim_address: prim_cache_address,
|
||||
transform_id,
|
||||
};
|
||||
|
@ -1412,7 +1402,6 @@ impl BatchBuilder {
|
|||
|
||||
let shadow_prim_header = PrimitiveHeader {
|
||||
local_rect: shadow_rect,
|
||||
snap_offsets: prim_info.shadow_snap_offsets,
|
||||
specific_prim_address: shadow_prim_address,
|
||||
..prim_header
|
||||
};
|
||||
|
@ -1705,9 +1694,8 @@ impl BatchBuilder {
|
|||
};
|
||||
|
||||
let prim_header = PrimitiveHeader {
|
||||
local_rect: picture.snapped_local_rect,
|
||||
local_rect: picture.local_rect,
|
||||
local_clip_rect: prim_info.combined_local_clip_rect,
|
||||
snap_offsets,
|
||||
specific_prim_address: prim_cache_address,
|
||||
transform_id,
|
||||
};
|
||||
|
@ -1828,7 +1816,6 @@ impl BatchBuilder {
|
|||
let prim_header = PrimitiveHeader {
|
||||
local_rect: prim_rect,
|
||||
local_clip_rect: prim_info.combined_local_clip_rect,
|
||||
snap_offsets,
|
||||
specific_prim_address: prim_cache_address,
|
||||
transform_id,
|
||||
};
|
||||
|
@ -1903,7 +1890,6 @@ impl BatchBuilder {
|
|||
let prim_header = PrimitiveHeader {
|
||||
local_rect: prim_rect,
|
||||
local_clip_rect: prim_info.combined_local_clip_rect,
|
||||
snap_offsets,
|
||||
specific_prim_address: prim_cache_address,
|
||||
transform_id,
|
||||
};
|
||||
|
@ -2013,7 +1999,6 @@ impl BatchBuilder {
|
|||
let prim_header = PrimitiveHeader {
|
||||
local_rect: prim_rect,
|
||||
local_clip_rect: prim_info.combined_local_clip_rect,
|
||||
snap_offsets,
|
||||
specific_prim_address: prim_cache_address,
|
||||
transform_id,
|
||||
};
|
||||
|
@ -2119,7 +2104,6 @@ impl BatchBuilder {
|
|||
let prim_header = PrimitiveHeader {
|
||||
local_rect: prim_rect,
|
||||
local_clip_rect: prim_info.combined_local_clip_rect,
|
||||
snap_offsets,
|
||||
specific_prim_address: prim_cache_address,
|
||||
transform_id,
|
||||
};
|
||||
|
@ -2168,7 +2152,6 @@ impl BatchBuilder {
|
|||
let prim_header = PrimitiveHeader {
|
||||
local_rect: prim_rect,
|
||||
local_clip_rect: image_instance.tight_local_clip_rect,
|
||||
snap_offsets,
|
||||
specific_prim_address: gpu_cache.get_address(&gpu_handle),
|
||||
transform_id,
|
||||
};
|
||||
|
@ -2212,7 +2195,6 @@ impl BatchBuilder {
|
|||
let mut prim_header = PrimitiveHeader {
|
||||
local_rect: prim_rect,
|
||||
local_clip_rect: prim_info.combined_local_clip_rect,
|
||||
snap_offsets,
|
||||
specific_prim_address: GpuCacheAddress::INVALID,
|
||||
transform_id,
|
||||
};
|
||||
|
@ -2340,7 +2322,6 @@ impl BatchBuilder {
|
|||
let mut prim_header = PrimitiveHeader {
|
||||
local_rect: prim_rect,
|
||||
local_clip_rect: prim_info.combined_local_clip_rect,
|
||||
snap_offsets,
|
||||
specific_prim_address: GpuCacheAddress::INVALID,
|
||||
transform_id,
|
||||
};
|
||||
|
@ -2444,10 +2425,9 @@ impl BatchBuilder {
|
|||
let prim_cache_address = gpu_cache.get_address(&ctx.globals.default_image_handle);
|
||||
let backdrop_picture = &ctx.prim_store.pictures[backdrop_pic_index.0];
|
||||
let prim_header = PrimitiveHeader {
|
||||
local_rect: backdrop_picture.snapped_local_rect,
|
||||
local_rect: backdrop_picture.local_rect,
|
||||
local_clip_rect: prim_info.combined_local_clip_rect,
|
||||
transform_id,
|
||||
snap_offsets: SnapOffsets::empty(),
|
||||
specific_prim_address: prim_cache_address,
|
||||
};
|
||||
|
||||
|
@ -2668,18 +2648,10 @@ impl BatchBuilder {
|
|||
let user_data = [stops_handle.as_int(gpu_cache), 0, 0, 0];
|
||||
|
||||
for tile in visible_tiles {
|
||||
// Adjust the snap offsets for the tile.
|
||||
let snap_offsets = recompute_snap_offsets(
|
||||
tile.local_rect,
|
||||
base_prim_header.local_rect,
|
||||
base_prim_header.snap_offsets,
|
||||
);
|
||||
|
||||
let prim_header = PrimitiveHeader {
|
||||
specific_prim_address: gpu_cache.get_address(&tile.handle),
|
||||
local_rect: tile.local_rect,
|
||||
local_clip_rect: tile.local_clip_rect,
|
||||
snap_offsets,
|
||||
..*base_prim_header
|
||||
};
|
||||
let prim_header_index = prim_headers.push(&prim_header, z_id, user_data);
|
||||
|
@ -2949,7 +2921,6 @@ impl ClipBatcher {
|
|||
local_pos,
|
||||
tile_rect: LayoutRect::zero(),
|
||||
sub_rect,
|
||||
snap_offsets: SnapOffsets::empty(),
|
||||
task_origin,
|
||||
screen_origin,
|
||||
device_pixel_scale,
|
||||
|
@ -3075,7 +3046,6 @@ impl ClipBatcher {
|
|||
actual_rect: DeviceIntRect,
|
||||
world_rect: &WorldRect,
|
||||
device_pixel_scale: DevicePixelScale,
|
||||
snap_offsets: SnapOffsets,
|
||||
task_origin: DevicePoint,
|
||||
screen_origin: DevicePoint,
|
||||
) {
|
||||
|
@ -3108,7 +3078,6 @@ impl ClipBatcher {
|
|||
DevicePoint::zero(),
|
||||
actual_rect.size.to_f32(),
|
||||
),
|
||||
snap_offsets,
|
||||
task_origin,
|
||||
screen_origin,
|
||||
device_pixel_scale: device_pixel_scale.0,
|
||||
|
|
|
@ -392,7 +392,7 @@ impl FrameBuilder {
|
|||
&frame_context,
|
||||
gpu_cache,
|
||||
&self.clip_store,
|
||||
&data_stores.clip,
|
||||
data_stores,
|
||||
);
|
||||
|
||||
{
|
||||
|
|
|
@ -169,7 +169,6 @@ pub struct ClipMaskInstance {
|
|||
pub local_pos: LayoutPoint,
|
||||
pub tile_rect: LayoutRect,
|
||||
pub sub_rect: DeviceRect,
|
||||
pub snap_offsets: SnapOffsets,
|
||||
pub task_origin: DevicePoint,
|
||||
pub screen_origin: DevicePoint,
|
||||
pub device_pixel_scale: f32,
|
||||
|
@ -250,7 +249,6 @@ impl PrimitiveHeaders {
|
|||
self.headers_float.push(PrimitiveHeaderF {
|
||||
local_rect: prim_header.local_rect,
|
||||
local_clip_rect: prim_header.local_clip_rect,
|
||||
snap_offsets: prim_header.snap_offsets,
|
||||
});
|
||||
|
||||
self.headers_int.push(PrimitiveHeaderI {
|
||||
|
@ -271,7 +269,6 @@ impl PrimitiveHeaders {
|
|||
pub struct PrimitiveHeader {
|
||||
pub local_rect: LayoutRect,
|
||||
pub local_clip_rect: LayoutRect,
|
||||
pub snap_offsets: SnapOffsets,
|
||||
pub specific_prim_address: GpuCacheAddress,
|
||||
pub transform_id: TransformPaletteId,
|
||||
}
|
||||
|
@ -284,7 +281,6 @@ pub struct PrimitiveHeader {
|
|||
pub struct PrimitiveHeaderF {
|
||||
pub local_rect: LayoutRect,
|
||||
pub local_clip_rect: LayoutRect,
|
||||
pub snap_offsets: SnapOffsets,
|
||||
}
|
||||
|
||||
// i32 parts of a primitive header
|
||||
|
@ -593,33 +589,6 @@ pub enum UvRectKind {
|
|||
},
|
||||
}
|
||||
|
||||
/// Represents offsets in device pixels that a primitive
|
||||
/// was snapped to.
|
||||
#[cfg_attr(feature = "capture", derive(Serialize))]
|
||||
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[repr(C)]
|
||||
pub struct SnapOffsets {
|
||||
/// How far the top left corner was snapped
|
||||
pub top_left: DeviceVector2D,
|
||||
/// How far the bottom right corner was snapped
|
||||
pub bottom_right: DeviceVector2D,
|
||||
}
|
||||
|
||||
impl SnapOffsets {
|
||||
pub fn empty() -> Self {
|
||||
SnapOffsets {
|
||||
top_left: DeviceVector2D::zero(),
|
||||
bottom_right: DeviceVector2D::zero(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
let zero = DeviceVector2D::zero();
|
||||
self.top_left == zero && self.bottom_right == zero
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[cfg_attr(feature = "capture", derive(Serialize))]
|
||||
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
||||
|
|
|
@ -7,7 +7,7 @@ use api::{PropertyBinding, PropertyBindingId, FilterPrimitive, FontRenderMode};
|
|||
use api::{DebugFlags, RasterSpace, ImageKey, ColorF};
|
||||
use api::units::*;
|
||||
use crate::box_shadow::{BLUR_SAMPLE_SCALE};
|
||||
use crate::clip::{ClipStore, ClipDataStore, ClipChainInstance, ClipDataHandle, ClipChainId};
|
||||
use crate::clip::{ClipStore, ClipChainInstance, ClipDataHandle, ClipChainId};
|
||||
use crate::clip_scroll_tree::{ROOT_SPATIAL_NODE_INDEX,
|
||||
ClipScrollTree, CoordinateSpaceMapping, SpatialNodeIndex, VisibleFace, CoordinateSystemId
|
||||
};
|
||||
|
@ -1781,7 +1781,7 @@ impl<'a> PictureUpdateState<'a> {
|
|||
frame_context: &FrameBuildingContext,
|
||||
gpu_cache: &mut GpuCache,
|
||||
clip_store: &ClipStore,
|
||||
clip_data_store: &ClipDataStore,
|
||||
data_stores: &mut DataStores,
|
||||
) {
|
||||
profile_marker!("UpdatePictures");
|
||||
|
||||
|
@ -1798,7 +1798,7 @@ impl<'a> PictureUpdateState<'a> {
|
|||
frame_context,
|
||||
gpu_cache,
|
||||
clip_store,
|
||||
clip_data_store,
|
||||
data_stores,
|
||||
);
|
||||
|
||||
if !state.are_raster_roots_assigned {
|
||||
|
@ -1861,7 +1861,7 @@ impl<'a> PictureUpdateState<'a> {
|
|||
frame_context: &FrameBuildingContext,
|
||||
gpu_cache: &mut GpuCache,
|
||||
clip_store: &ClipStore,
|
||||
clip_data_store: &ClipDataStore,
|
||||
data_stores: &mut DataStores,
|
||||
) {
|
||||
if let Some(prim_list) = picture_primitives[pic_index.0].pre_update(
|
||||
self,
|
||||
|
@ -1874,7 +1874,7 @@ impl<'a> PictureUpdateState<'a> {
|
|||
frame_context,
|
||||
gpu_cache,
|
||||
clip_store,
|
||||
clip_data_store,
|
||||
data_stores,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1882,6 +1882,7 @@ impl<'a> PictureUpdateState<'a> {
|
|||
prim_list,
|
||||
self,
|
||||
frame_context,
|
||||
data_stores,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -2196,6 +2197,10 @@ pub struct PrimitiveClusterIndex(pub u32);
|
|||
#[cfg_attr(feature = "capture", derive(Serialize))]
|
||||
pub struct ClusterIndex(pub u16);
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[cfg_attr(feature = "capture", derive(Serialize))]
|
||||
pub struct PrimitiveIndex(pub u32);
|
||||
|
||||
impl ClusterIndex {
|
||||
pub const INVALID: ClusterIndex = ClusterIndex(u16::MAX);
|
||||
}
|
||||
|
@ -2217,6 +2222,10 @@ pub struct PrimitiveList {
|
|||
pub pictures: PictureList,
|
||||
/// List of primitives grouped into clusters.
|
||||
pub clusters: SmallVec<[PrimitiveCluster; 4]>,
|
||||
/// List of primitive indicies that can only update
|
||||
/// the cluster during frame building. This maps to
|
||||
/// primitives in the prim_instances array.
|
||||
pub deferred_prims: Vec<PrimitiveIndex>,
|
||||
}
|
||||
|
||||
impl PrimitiveList {
|
||||
|
@ -2229,6 +2238,7 @@ impl PrimitiveList {
|
|||
prim_instances: Vec::new(),
|
||||
pictures: SmallVec::new(),
|
||||
clusters: SmallVec::new(),
|
||||
deferred_prims: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2243,10 +2253,11 @@ impl PrimitiveList {
|
|||
let mut pictures = SmallVec::new();
|
||||
let mut clusters_map = FastHashMap::default();
|
||||
let mut clusters: SmallVec<[PrimitiveCluster; 4]> = SmallVec::new();
|
||||
let mut deferred_prims = Vec::new();
|
||||
|
||||
// Walk the list of primitive instances and extract any that
|
||||
// are pictures.
|
||||
for prim_instance in &mut prim_instances {
|
||||
for (prim_index, prim_instance) in &mut prim_instances.iter_mut().enumerate() {
|
||||
// Check if this primitive is a picture. In future we should
|
||||
// remove this match and embed this info directly in the primitive instance.
|
||||
let is_pic = match prim_instance.kind {
|
||||
|
@ -2302,8 +2313,12 @@ impl PrimitiveList {
|
|||
(data.is_backface_visible, data.prim_size)
|
||||
}
|
||||
PrimitiveInstanceKind::Backdrop { data_handle, .. } => {
|
||||
// We don't know the actual size of the backdrop until frame
|
||||
// building, so use an empty rect for now and add it to the
|
||||
// deferred primitive list.
|
||||
let data = &interners.backdrop[data_handle];
|
||||
(data.is_backface_visible, data.prim_size)
|
||||
deferred_prims.push(PrimitiveIndex(prim_index as u32));
|
||||
(data.is_backface_visible, LayoutSize::zero())
|
||||
}
|
||||
PrimitiveInstanceKind::PushClipChain |
|
||||
PrimitiveInstanceKind::PopClipChain => {
|
||||
|
@ -2358,6 +2373,7 @@ impl PrimitiveList {
|
|||
prim_instances,
|
||||
pictures,
|
||||
clusters,
|
||||
deferred_prims,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2423,17 +2439,10 @@ pub struct PicturePrimitive {
|
|||
/// composited into the parent picture.
|
||||
pub spatial_node_index: SpatialNodeIndex,
|
||||
|
||||
/// The local rect of this picture. It is built
|
||||
/// dynamically when updating visibility. It takes
|
||||
/// into account snapping in device space for its
|
||||
/// children.
|
||||
pub snapped_local_rect: LayoutRect,
|
||||
|
||||
/// The local rect of this picture. It is built
|
||||
/// dynamically during the first picture traversal. It
|
||||
/// does not take into account snapping in device for
|
||||
/// its children.
|
||||
pub unsnapped_local_rect: LayoutRect,
|
||||
/// is composed of already snapped primitives.
|
||||
pub local_rect: LayoutRect,
|
||||
|
||||
/// If false, this picture needs to (re)build segments
|
||||
/// if it supports segment rendering. This can occur
|
||||
|
@ -2458,8 +2467,7 @@ impl PicturePrimitive {
|
|||
) {
|
||||
pt.new_level(format!("{:?}", self_index));
|
||||
pt.add_item(format!("prim_count: {:?}", self.prim_list.prim_instances.len()));
|
||||
pt.add_item(format!("snapped_local_rect: {:?}", self.snapped_local_rect));
|
||||
pt.add_item(format!("unsnapped_local_rect: {:?}", self.unsnapped_local_rect));
|
||||
pt.add_item(format!("local_rect: {:?}", self.local_rect));
|
||||
pt.add_item(format!("spatial_node_index: {:?}", self.spatial_node_index));
|
||||
pt.add_item(format!("raster_config: {:?}", self.raster_config));
|
||||
pt.add_item(format!("requested_composite_mode: {:?}", self.requested_composite_mode));
|
||||
|
@ -2568,8 +2576,7 @@ impl PicturePrimitive {
|
|||
is_backface_visible,
|
||||
requested_raster_space,
|
||||
spatial_node_index,
|
||||
snapped_local_rect: LayoutRect::zero(),
|
||||
unsnapped_local_rect: LayoutRect::zero(),
|
||||
local_rect: LayoutRect::zero(),
|
||||
tile_cache,
|
||||
options,
|
||||
segments_are_valid: false,
|
||||
|
@ -2673,7 +2680,7 @@ impl PicturePrimitive {
|
|||
|
||||
match self.raster_config {
|
||||
Some(ref raster_config) => {
|
||||
let pic_rect = PictureRect::from_untyped(&self.snapped_local_rect.to_untyped());
|
||||
let pic_rect = PictureRect::from_untyped(&self.local_rect.to_untyped());
|
||||
|
||||
let device_pixel_scale = frame_state
|
||||
.surfaces[raster_config.surface_index.0]
|
||||
|
@ -3437,6 +3444,7 @@ impl PicturePrimitive {
|
|||
prim_list: PrimitiveList,
|
||||
state: &mut PictureUpdateState,
|
||||
frame_context: &FrameBuildingContext,
|
||||
data_stores: &mut DataStores,
|
||||
) {
|
||||
// Restore the pictures list used during recursion.
|
||||
self.prim_list = prim_list;
|
||||
|
@ -3444,6 +3452,59 @@ impl PicturePrimitive {
|
|||
// Pop the state information about this picture.
|
||||
state.pop_picture();
|
||||
|
||||
// Update any primitives/cluster bounding rects that can only be done
|
||||
// with information available during frame building.
|
||||
for prim_index in &self.prim_list.deferred_prims {
|
||||
let prim_instance = &mut self.prim_list.prim_instances[prim_index.0 as usize];
|
||||
match prim_instance.kind {
|
||||
PrimitiveInstanceKind::Backdrop { data_handle, .. } => {
|
||||
// The actual size and clip rect of this primitive are determined by computing the bounding
|
||||
// box of the projected rect of the backdrop-filter element onto the backdrop.
|
||||
let prim_data = &mut data_stores.backdrop[data_handle];
|
||||
let spatial_node_index = prim_data.kind.spatial_node_index;
|
||||
|
||||
// We cannot use the relative transform between the backdrop and the element because
|
||||
// that doesn't take into account any projection transforms that both spatial nodes are children of.
|
||||
// Instead, we first project from the element to the world space and get a flattened 2D bounding rect
|
||||
// in the screen space, we then map this rect from the world space to the backdrop space to get the
|
||||
// proper bounding box where the backdrop-filter needs to be processed.
|
||||
|
||||
let prim_to_world_mapper = SpaceMapper::new_with_target(
|
||||
ROOT_SPATIAL_NODE_INDEX,
|
||||
spatial_node_index,
|
||||
LayoutRect::max_rect(),
|
||||
frame_context.clip_scroll_tree,
|
||||
);
|
||||
|
||||
let backdrop_to_world_mapper = SpaceMapper::new_with_target(
|
||||
ROOT_SPATIAL_NODE_INDEX,
|
||||
prim_instance.spatial_node_index,
|
||||
LayoutRect::max_rect(),
|
||||
frame_context.clip_scroll_tree,
|
||||
);
|
||||
|
||||
// First map to the screen and get a flattened rect
|
||||
let prim_rect = prim_to_world_mapper.map(&prim_data.kind.border_rect).unwrap_or_else(LayoutRect::zero);
|
||||
// Backwards project the flattened rect onto the backdrop
|
||||
let prim_rect = backdrop_to_world_mapper.unmap(&prim_rect).unwrap_or_else(LayoutRect::zero);
|
||||
|
||||
// TODO(aosmond): Is this safe? Updating the primitive size during
|
||||
// frame building is usually problematic since scene building will cache
|
||||
// the primitive information in the GPU already.
|
||||
prim_instance.prim_origin = prim_rect.origin;
|
||||
prim_data.common.prim_size = prim_rect.size;
|
||||
prim_instance.local_clip_rect = prim_rect;
|
||||
|
||||
// Update the cluster bounding rect now that we have the backdrop rect.
|
||||
let cluster = &mut self.prim_list.clusters[prim_instance.cluster_index.0 as usize];
|
||||
cluster.bounding_rect = cluster.bounding_rect.union(&prim_rect);
|
||||
}
|
||||
_ => {
|
||||
panic!("BUG: unexpected deferred primitive kind for cluster updates");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for cluster in &mut self.prim_list.clusters {
|
||||
// Skip the cluster if backface culled.
|
||||
if !cluster.is_backface_visible {
|
||||
|
@ -3503,11 +3564,6 @@ impl PicturePrimitive {
|
|||
let surface_index = state.pop_surface();
|
||||
debug_assert_eq!(surface_index, raster_config.surface_index);
|
||||
|
||||
// Snapping may change the local rect slightly, and as such should just be
|
||||
// considered an estimated size for determining if we need raster roots and
|
||||
// preparing the tile cache.
|
||||
self.unsnapped_local_rect = surface_rect;
|
||||
|
||||
// Check if any of the surfaces can't be rasterized in local space but want to.
|
||||
if raster_config.establishes_raster_root {
|
||||
if surface_rect.size.width > MAX_SURFACE_SIZE ||
|
||||
|
@ -3518,6 +3574,8 @@ impl PicturePrimitive {
|
|||
}
|
||||
}
|
||||
|
||||
self.local_rect = surface_rect;
|
||||
|
||||
// Drop shadows draw both a content and shadow rect, so need to expand the local
|
||||
// rect of any surfaces to be composited in parent surfaces correctly.
|
||||
match raster_config.composite_mode {
|
||||
|
@ -3586,14 +3644,14 @@ impl PicturePrimitive {
|
|||
// Basic brush primitive header is (see end of prepare_prim_for_render_inner in prim_store.rs)
|
||||
// [brush specific data]
|
||||
// [segment_rect, segment data]
|
||||
let shadow_rect = self.snapped_local_rect.translate(shadow.offset);
|
||||
let shadow_rect = self.local_rect.translate(shadow.offset);
|
||||
|
||||
// ImageBrush colors
|
||||
request.push(shadow.color.premultiplied());
|
||||
request.push(PremultipliedColorF::WHITE);
|
||||
request.push([
|
||||
self.snapped_local_rect.size.width,
|
||||
self.snapped_local_rect.size.height,
|
||||
self.local_rect.size.width,
|
||||
self.local_rect.size.height,
|
||||
0.0,
|
||||
0.0,
|
||||
]);
|
||||
|
|
|
@ -22,7 +22,7 @@ use crate::frame_builder::{FrameBuildingContext, FrameBuildingState, PictureCont
|
|||
use crate::frame_builder::{FrameVisibilityContext, FrameVisibilityState};
|
||||
use crate::glyph_rasterizer::GlyphKey;
|
||||
use crate::gpu_cache::{GpuCache, GpuCacheAddress, GpuCacheHandle, GpuDataRequest, ToGpuBlocks};
|
||||
use crate::gpu_types::{BrushFlags, SnapOffsets};
|
||||
use crate::gpu_types::{BrushFlags};
|
||||
use crate::image::{Repetition};
|
||||
use crate::intern;
|
||||
use malloc_size_of::MallocSizeOf;
|
||||
|
@ -932,7 +932,6 @@ impl BrushSegment {
|
|||
frame_state: &mut FrameBuildingState,
|
||||
clip_data_store: &mut ClipDataStore,
|
||||
unclipped: &DeviceRect,
|
||||
prim_snap_offsets: SnapOffsets,
|
||||
device_pixel_scale: DevicePixelScale,
|
||||
) -> ClipMaskKind {
|
||||
match clip_chain {
|
||||
|
@ -955,9 +954,8 @@ impl BrushSegment {
|
|||
// Get a minimal device space rect, clipped to the screen that we
|
||||
// need to allocate for the clip mask, as well as interpolated
|
||||
// snap offsets.
|
||||
let (device_rect, snap_offsets) = match get_clipped_device_rect(
|
||||
let device_rect = match get_clipped_device_rect(
|
||||
unclipped,
|
||||
prim_snap_offsets,
|
||||
&pic_state.map_raster_to_world,
|
||||
segment_world_rect,
|
||||
device_pixel_scale,
|
||||
|
@ -977,7 +975,6 @@ impl BrushSegment {
|
|||
frame_state.resource_cache,
|
||||
frame_state.render_tasks,
|
||||
clip_data_store,
|
||||
snap_offsets,
|
||||
device_pixel_scale,
|
||||
frame_context.fb_config,
|
||||
);
|
||||
|
@ -1435,18 +1432,6 @@ pub struct PrimitiveVisibility {
|
|||
/// The current combined local clip for this primitive, from
|
||||
/// the primitive local clip above and the current clip chain.
|
||||
pub combined_local_clip_rect: LayoutRect,
|
||||
|
||||
/// The snap offsets in device space for this primitive. They are
|
||||
/// generated based on the visible rect, which is the local rect
|
||||
/// clipped by the combined local clip for most primitives, or
|
||||
/// just the local rect for pictures.
|
||||
pub snap_offsets: SnapOffsets,
|
||||
|
||||
/// The snap offsets in device space for the drop shadow for
|
||||
/// picture primitives, if applicable. Similar to snap offsets,
|
||||
/// they are generated based on the local rect translated by the
|
||||
/// drop shadow offset.
|
||||
pub shadow_snap_offsets: SnapOffsets,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
|
@ -1807,7 +1792,7 @@ impl PrimitiveStore {
|
|||
world_culling_rect: &WorldRect,
|
||||
frame_context: &FrameVisibilityContext,
|
||||
frame_state: &mut FrameVisibilityState,
|
||||
) -> Option<PictureRect> {
|
||||
) {
|
||||
let (mut prim_list, surface_index, apply_local_clip_rect, world_culling_rect, is_composite) = {
|
||||
let pic = &mut self.pictures[pic_index.0];
|
||||
let mut world_culling_rect = *world_culling_rect;
|
||||
|
@ -1827,7 +1812,7 @@ impl PrimitiveStore {
|
|||
// relative transforms have changed, which means we need to
|
||||
// re-map the dependencies of any child primitives.
|
||||
world_culling_rect = tile_cache.pre_update(
|
||||
PictureRect::from_untyped(&pic.unsnapped_local_rect.to_untyped()),
|
||||
PictureRect::from_untyped(&pic.local_rect.to_untyped()),
|
||||
surface_index,
|
||||
frame_context,
|
||||
frame_state,
|
||||
|
@ -1861,19 +1846,13 @@ impl PrimitiveStore {
|
|||
frame_context.clip_scroll_tree,
|
||||
);
|
||||
|
||||
let mut map_local_to_raster = SpaceMapper::new(
|
||||
surface.raster_spatial_node_index,
|
||||
RasterRect::max_rect(),
|
||||
);
|
||||
|
||||
let mut surface_rect = PictureRect::zero();
|
||||
|
||||
for prim_instance in &mut prim_list.prim_instances {
|
||||
prim_instance.reset();
|
||||
|
||||
if prim_instance.is_chased() {
|
||||
#[cfg(debug_assertions)] // needed for ".id" part
|
||||
println!("\tpreparing {:?} in {:?}", prim_instance.id, pic_index);
|
||||
println!("\t{:?}", prim_instance.kind);
|
||||
}
|
||||
|
||||
// Get the cluster and see if is visible
|
||||
|
@ -1889,12 +1868,7 @@ impl PrimitiveStore {
|
|||
frame_context.clip_scroll_tree,
|
||||
);
|
||||
|
||||
map_local_to_raster.set_target_spatial_node(
|
||||
prim_instance.spatial_node_index,
|
||||
frame_context.clip_scroll_tree,
|
||||
);
|
||||
|
||||
let (is_passthrough, snap_to_visible, prim_local_rect, prim_shadow_rect) = match prim_instance.kind {
|
||||
let (is_passthrough, prim_local_rect, prim_shadow_rect) = match prim_instance.kind {
|
||||
PrimitiveInstanceKind::PushClipChain => {
|
||||
frame_state.clip_chain_stack.push_clip(
|
||||
prim_instance.clip_chain_id,
|
||||
|
@ -1916,7 +1890,7 @@ impl PrimitiveStore {
|
|||
frame_state.clip_store,
|
||||
);
|
||||
|
||||
let pic_surface_rect = self.update_visibility(
|
||||
self.update_visibility(
|
||||
pic_index,
|
||||
surface_index,
|
||||
&world_culling_rect,
|
||||
|
@ -1926,8 +1900,6 @@ impl PrimitiveStore {
|
|||
|
||||
frame_state.clip_chain_stack.pop_clip();
|
||||
|
||||
let pic = &self.pictures[pic_index.0];
|
||||
|
||||
// The local rect of pictures is calculated dynamically based on
|
||||
// the content of children, which may move due to the spatial
|
||||
// node they are attached to. Other parts of the code (such as
|
||||
|
@ -1937,74 +1909,22 @@ impl PrimitiveStore {
|
|||
// this way. In future, we could perhaps just store the
|
||||
// size in the picture primitive, to that there isn't
|
||||
// any duplicated data.
|
||||
prim_instance.prim_origin = pic.snapped_local_rect.origin;
|
||||
let pic = &self.pictures[pic_index.0];
|
||||
prim_instance.prim_origin = pic.local_rect.origin;
|
||||
|
||||
let shadow_rect = match pic.raster_config {
|
||||
Some(ref rc) => match rc.composite_mode {
|
||||
// If we have a drop shadow filter, we also need to include the shadow in
|
||||
// our local rect for the purpose of calculating the size of the picture.
|
||||
PictureCompositeMode::Filter(Filter::DropShadows(ref shadows)) => {
|
||||
let mut rect = LayoutRect::zero();
|
||||
for shadow in shadows {
|
||||
rect = rect.union(&pic.snapped_local_rect.translate(shadow.offset));
|
||||
}
|
||||
|
||||
rect
|
||||
}
|
||||
_ => LayoutRect::zero(),
|
||||
}
|
||||
None => {
|
||||
if let Some(ref rect) = pic_surface_rect {
|
||||
surface_rect = surface_rect.union(rect);
|
||||
}
|
||||
LayoutRect::zero()
|
||||
let shadow_rect = if let Some(RasterConfig { composite_mode: PictureCompositeMode::Filter(Filter::DropShadows(ref shadows)), .. }) = pic.raster_config {
|
||||
// If we have a drop shadow filter, we also need to include the shadow in
|
||||
// our local rect for the purpose of calculating the size of the picture.
|
||||
let mut rect = LayoutRect::zero();
|
||||
for shadow in shadows {
|
||||
rect = rect.union(&pic.local_rect.translate(shadow.offset));
|
||||
}
|
||||
rect
|
||||
} else {
|
||||
LayoutRect::zero()
|
||||
};
|
||||
|
||||
if prim_instance.is_chased() {
|
||||
if pic.unsnapped_local_rect != pic.snapped_local_rect {
|
||||
println!("\tsnapped from {:?} to {:?}", pic.unsnapped_local_rect, pic.snapped_local_rect);
|
||||
}
|
||||
}
|
||||
|
||||
(pic.raster_config.is_none(), false, pic.snapped_local_rect, shadow_rect)
|
||||
}
|
||||
PrimitiveInstanceKind::Backdrop { data_handle } => {
|
||||
// The actual size and clip rect of this primitive are determined by computing the bounding
|
||||
// box of the projected rect of the backdrop-filter element onto the backdrop.
|
||||
let prim_data = &mut frame_state.data_stores.backdrop[data_handle];
|
||||
let spatial_node_index = prim_data.kind.spatial_node_index;
|
||||
|
||||
// We cannot use the relative transform between the backdrop and the element because
|
||||
// that doesn't take into account any projection transforms that both spatial nodes are children of.
|
||||
// Instead, we first project from the element to the world space and get a flattened 2D bounding rect
|
||||
// in the screen space, we then map this rect from the world space to the backdrop space to get the
|
||||
// proper bounding box where the backdrop-filter needs to be processed.
|
||||
|
||||
let prim_to_world_mapper = SpaceMapper::new_with_target(
|
||||
ROOT_SPATIAL_NODE_INDEX,
|
||||
spatial_node_index,
|
||||
LayoutRect::max_rect(),
|
||||
frame_context.clip_scroll_tree,
|
||||
);
|
||||
|
||||
let backdrop_to_world_mapper = SpaceMapper::new_with_target(
|
||||
ROOT_SPATIAL_NODE_INDEX,
|
||||
prim_instance.spatial_node_index,
|
||||
LayoutRect::max_rect(),
|
||||
frame_context.clip_scroll_tree,
|
||||
);
|
||||
|
||||
// First map to the screen and get a flattened rect
|
||||
let prim_rect = prim_to_world_mapper.map(&prim_data.kind.border_rect).unwrap_or_else(LayoutRect::zero);
|
||||
// Backwards project the flattened rect onto the backdrop
|
||||
let prim_rect = backdrop_to_world_mapper.unmap(&prim_rect).unwrap_or_else(LayoutRect::zero);
|
||||
|
||||
prim_instance.prim_origin = prim_rect.origin;
|
||||
prim_data.common.prim_size = prim_rect.size;
|
||||
prim_instance.local_clip_rect = prim_rect;
|
||||
|
||||
(false, true, prim_rect, LayoutRect::zero())
|
||||
(pic.raster_config.is_none(), pic.local_rect, shadow_rect)
|
||||
}
|
||||
_ => {
|
||||
let prim_data = &frame_state.data_stores.as_common_data(&prim_instance);
|
||||
|
@ -2014,7 +1934,7 @@ impl PrimitiveStore {
|
|||
prim_data.prim_size,
|
||||
);
|
||||
|
||||
(false, true, prim_rect, LayoutRect::zero())
|
||||
(false, prim_rect, LayoutRect::zero())
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -2027,8 +1947,6 @@ impl PrimitiveStore {
|
|||
clip_chain: ClipChainInstance::empty(),
|
||||
clip_task_index: ClipTaskIndex::INVALID,
|
||||
combined_local_clip_rect: LayoutRect::zero(),
|
||||
snap_offsets: SnapOffsets::empty(),
|
||||
shadow_snap_offsets: SnapOffsets::empty(),
|
||||
visibility_mask: PrimitiveVisibilityMask::empty(),
|
||||
}
|
||||
);
|
||||
|
@ -2171,56 +2089,6 @@ impl PrimitiveStore {
|
|||
continue;
|
||||
}
|
||||
|
||||
// All pictures must snap to their primitive rect instead of the
|
||||
// visible rect like most primitives. This is because the picture's
|
||||
// visible rect includes the effect of the picture's clip rect,
|
||||
// which was not considered by the picture's children. The primitive
|
||||
// rect however is simply the union of the visible rect of the
|
||||
// children, which they snapped to, which is precisely what we also
|
||||
// need to snap to in order to be consistent.
|
||||
let visible_rect = if snap_to_visible {
|
||||
match combined_local_clip_rect.intersection(&prim_local_rect) {
|
||||
Some(r) => r,
|
||||
None => {
|
||||
if prim_instance.is_chased() {
|
||||
println!("\tculled for zero visible rectangle");
|
||||
}
|
||||
prim_instance.visibility_info = PrimitiveVisibilityIndex::INVALID;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
prim_local_rect
|
||||
};
|
||||
|
||||
// This is how primitives get snapped. In general, snapping a picture's
|
||||
// visible rect here will have no effect, but if it is rasterized in its
|
||||
// own space, or it has a blur or drop shadow effect applied, it may
|
||||
// provide a snapping offset.
|
||||
let (snapped_visible_rect, snap_offsets) = get_snapped_rect(
|
||||
visible_rect,
|
||||
&map_local_to_raster,
|
||||
surface.device_pixel_scale,
|
||||
).unwrap_or((visible_rect, SnapOffsets::empty()));
|
||||
|
||||
let (combined_visible_rect, shadow_snap_offsets) = if !prim_shadow_rect.is_empty() {
|
||||
let (snapped_shadow_rect, shadow_snap_offsets) = get_snapped_rect(
|
||||
prim_shadow_rect,
|
||||
&map_local_to_raster,
|
||||
surface.device_pixel_scale,
|
||||
).unwrap_or((prim_shadow_rect, SnapOffsets::empty()));
|
||||
|
||||
(snapped_visible_rect.union(&snapped_shadow_rect), shadow_snap_offsets)
|
||||
} else {
|
||||
(snapped_visible_rect, SnapOffsets::empty())
|
||||
};
|
||||
|
||||
// Include the snapped primitive/picture local rect, including any shadows,
|
||||
// in the area affected by the surface.
|
||||
if let Some(rect) = map_local_to_surface.map(&combined_visible_rect) {
|
||||
surface_rect = surface_rect.union(&rect);
|
||||
}
|
||||
|
||||
// When the debug display is enabled, paint a colored rectangle around each
|
||||
// primitive.
|
||||
if frame_context.debug_flags.contains(::api::DebugFlags::PRIMITIVE_DBG) {
|
||||
|
@ -2257,8 +2125,6 @@ impl PrimitiveStore {
|
|||
clip_chain,
|
||||
clip_task_index: ClipTaskIndex::INVALID,
|
||||
combined_local_clip_rect,
|
||||
snap_offsets,
|
||||
shadow_snap_offsets,
|
||||
visibility_mask: PrimitiveVisibilityMask::empty(),
|
||||
}
|
||||
);
|
||||
|
@ -2289,55 +2155,18 @@ impl PrimitiveStore {
|
|||
// TODO(gw): In future, if we support specifying a flag which gets the
|
||||
// stretch size from the segment rect in the shaders, we can
|
||||
// remove this invalidation here completely.
|
||||
if let Some(ref raster_config) = pic.raster_config {
|
||||
// Inflate the local bounding rect if required by the filter effect.
|
||||
// This inflaction factor is to be applied to the surface itself.
|
||||
if pic.options.inflate_if_required {
|
||||
surface_rect = raster_config.composite_mode.inflate_picture_rect(surface_rect, surface.inflation_factor);
|
||||
}
|
||||
if let Some(RasterConfig { composite_mode: PictureCompositeMode::TileCache { .. }, .. }) = pic.raster_config {
|
||||
let mut tile_cache = frame_state.tile_cache.take().unwrap();
|
||||
|
||||
// Layout space for the picture is picture space from the
|
||||
// perspective of its child primitives.
|
||||
let pic_local_rect = surface_rect * Scale::new(1.0);
|
||||
if pic.snapped_local_rect != pic_local_rect {
|
||||
match raster_config.composite_mode {
|
||||
PictureCompositeMode::Filter(Filter::DropShadows(..)) => {
|
||||
for handle in &pic.extra_gpu_data_handles {
|
||||
frame_state.gpu_cache.invalidate(handle);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
// Invalidate any segments built for this picture, since the local
|
||||
// rect has changed.
|
||||
pic.segments_are_valid = false;
|
||||
pic.snapped_local_rect = pic_local_rect;
|
||||
}
|
||||
|
||||
if let PictureCompositeMode::TileCache { .. } = raster_config.composite_mode {
|
||||
let mut tile_cache = frame_state.tile_cache.take().unwrap();
|
||||
|
||||
// Build the dirty region(s) for this tile cache.
|
||||
tile_cache.post_update(
|
||||
frame_state.resource_cache,
|
||||
frame_state.gpu_cache,
|
||||
frame_context,
|
||||
frame_state.scratch,
|
||||
);
|
||||
|
||||
pic.tile_cache = Some(tile_cache);
|
||||
}
|
||||
|
||||
None
|
||||
} else {
|
||||
let parent_surface = &frame_context.surfaces[parent_surface_index.0 as usize];
|
||||
let map_surface_to_parent_surface = SpaceMapper::new_with_target(
|
||||
parent_surface.surface_spatial_node_index,
|
||||
surface.surface_spatial_node_index,
|
||||
PictureRect::max_rect(),
|
||||
frame_context.clip_scroll_tree,
|
||||
// Build the dirty region(s) for this tile cache.
|
||||
tile_cache.post_update(
|
||||
frame_state.resource_cache,
|
||||
frame_state.gpu_cache,
|
||||
frame_context,
|
||||
frame_state.scratch,
|
||||
);
|
||||
map_surface_to_parent_surface.map(&surface_rect)
|
||||
|
||||
pic.tile_cache = Some(tile_cache);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3311,7 +3140,7 @@ impl PrimitiveStore {
|
|||
splitter,
|
||||
frame_context.clip_scroll_tree,
|
||||
prim_instance.spatial_node_index,
|
||||
pic.snapped_local_rect,
|
||||
pic.local_rect,
|
||||
&prim_info.combined_local_clip_rect,
|
||||
frame_state.current_dirty_region().combined,
|
||||
plane_split_anchor,
|
||||
|
@ -3621,13 +3450,15 @@ impl<'a> GpuDataRequest<'a> {
|
|||
impl PrimitiveInstance {
|
||||
fn build_segments_if_needed(
|
||||
&mut self,
|
||||
prim_clip_chain: &ClipChainInstance,
|
||||
prim_info: &PrimitiveVisibility,
|
||||
frame_state: &mut FrameBuildingState,
|
||||
prim_store: &mut PrimitiveStore,
|
||||
data_stores: &DataStores,
|
||||
segments_store: &mut SegmentStorage,
|
||||
segment_instances_store: &mut SegmentInstanceStorage,
|
||||
) {
|
||||
let prim_clip_chain = &prim_info.clip_chain;
|
||||
|
||||
// Usually, the primitive rect can be found from information
|
||||
// in the instance and primitive template.
|
||||
let mut prim_local_rect = LayoutRect::new(
|
||||
|
@ -3671,7 +3502,7 @@ impl PrimitiveInstance {
|
|||
|
||||
// Override the prim local rect with the dynamically calculated
|
||||
// local rect for the picture.
|
||||
prim_local_rect = pic.snapped_local_rect;
|
||||
prim_local_rect = pic.local_rect;
|
||||
|
||||
segment_instance_index
|
||||
} else {
|
||||
|
@ -3858,7 +3689,6 @@ impl PrimitiveInstance {
|
|||
frame_state,
|
||||
&mut data_stores.clip,
|
||||
unclipped,
|
||||
prim_info.snap_offsets,
|
||||
device_pixel_scale,
|
||||
);
|
||||
clip_mask_instances.push(clip_mask_kind);
|
||||
|
@ -3879,10 +3709,7 @@ impl PrimitiveInstance {
|
|||
let segment_clip_chain = frame_state
|
||||
.clip_store
|
||||
.build_clip_chain_instance(
|
||||
segment.local_rect.translate(LayoutVector2D::new(
|
||||
self.prim_origin.x,
|
||||
self.prim_origin.y,
|
||||
)),
|
||||
segment.local_rect.translate(self.prim_origin.to_vector()),
|
||||
&pic_state.map_local_to_pic,
|
||||
&pic_state.map_pic_to_world,
|
||||
&frame_context.clip_scroll_tree,
|
||||
|
@ -3905,7 +3732,6 @@ impl PrimitiveInstance {
|
|||
frame_state,
|
||||
&mut data_stores.clip,
|
||||
unclipped,
|
||||
prim_info.snap_offsets,
|
||||
device_pixel_scale,
|
||||
);
|
||||
clip_mask_instances.push(clip_mask_kind);
|
||||
|
@ -3944,7 +3770,7 @@ impl PrimitiveInstance {
|
|||
};
|
||||
|
||||
self.build_segments_if_needed(
|
||||
&prim_info.clip_chain,
|
||||
&prim_info,
|
||||
frame_state,
|
||||
prim_store,
|
||||
data_stores,
|
||||
|
@ -3978,9 +3804,8 @@ impl PrimitiveInstance {
|
|||
// Get a minimal device space rect, clipped to the screen that we
|
||||
// need to allocate for the clip mask, as well as interpolated
|
||||
// snap offsets.
|
||||
if let Some((device_rect, snap_offsets)) = get_clipped_device_rect(
|
||||
if let Some(device_rect) = get_clipped_device_rect(
|
||||
&unclipped,
|
||||
prim_info.snap_offsets,
|
||||
&pic_state.map_raster_to_world,
|
||||
prim_info.clipped_world_rect,
|
||||
device_pixel_scale,
|
||||
|
@ -3994,7 +3819,6 @@ impl PrimitiveInstance {
|
|||
frame_state.resource_cache,
|
||||
frame_state.render_tasks,
|
||||
&mut data_stores.clip,
|
||||
snap_offsets,
|
||||
device_pixel_scale,
|
||||
frame_context.fb_config,
|
||||
);
|
||||
|
@ -4017,80 +3841,6 @@ impl PrimitiveInstance {
|
|||
}
|
||||
}
|
||||
|
||||
/// Mimics the GLSL mix() function.
|
||||
fn mix(x: f32, y: f32, a: f32) -> f32 {
|
||||
x * (1.0 - a) + y * a
|
||||
}
|
||||
|
||||
/// Given a point within a local rectangle, and the device space corners
|
||||
/// of a snapped primitive, return the snap offsets.
|
||||
fn compute_snap_offset_impl<PixelSpace>(
|
||||
reference_pos: Point2D<f32, PixelSpace>,
|
||||
reference_rect: Rect<f32, PixelSpace>,
|
||||
prim_top_left: DevicePoint,
|
||||
prim_bottom_right: DevicePoint,
|
||||
) -> DeviceVector2D {
|
||||
let normalized_snap_pos = Point2D::<f32, PixelSpace>::new(
|
||||
(reference_pos.x - reference_rect.origin.x) / reference_rect.size.width,
|
||||
(reference_pos.y - reference_rect.origin.y) / reference_rect.size.height,
|
||||
);
|
||||
|
||||
let top_left = DeviceVector2D::new(
|
||||
(prim_top_left.x + 0.5).floor() - prim_top_left.x,
|
||||
(prim_top_left.y + 0.5).floor() - prim_top_left.y,
|
||||
);
|
||||
|
||||
let bottom_right = DeviceVector2D::new(
|
||||
(prim_bottom_right.x + 0.5).floor() - prim_bottom_right.x,
|
||||
(prim_bottom_right.y + 0.5).floor() - prim_bottom_right.y,
|
||||
);
|
||||
|
||||
DeviceVector2D::new(
|
||||
mix(top_left.x, bottom_right.x, normalized_snap_pos.x),
|
||||
mix(top_left.y, bottom_right.y, normalized_snap_pos.y),
|
||||
)
|
||||
}
|
||||
|
||||
/// Given the snapping offsets for a primitive rectangle, recompute
|
||||
/// the snapping offsets to be relative to given local rectangle.
|
||||
/// This *must* exactly match the logic in the GLSL
|
||||
/// compute_snap_offset function.
|
||||
pub fn recompute_snap_offsets<PixelSpace>(
|
||||
local_rect: Rect<f32, PixelSpace>,
|
||||
prim_rect: Rect<f32, PixelSpace>,
|
||||
snap_offsets: SnapOffsets,
|
||||
) -> SnapOffsets
|
||||
{
|
||||
if prim_rect.is_empty() || snap_offsets.is_empty() {
|
||||
return SnapOffsets::empty();
|
||||
}
|
||||
|
||||
let normalized_top_left = Point2D::<f32, PixelSpace>::new(
|
||||
(local_rect.origin.x - prim_rect.origin.x) / prim_rect.size.width,
|
||||
(local_rect.origin.y - prim_rect.origin.y) / prim_rect.size.height,
|
||||
);
|
||||
|
||||
let normalized_bottom_right = Point2D::<f32, PixelSpace>::new(
|
||||
(local_rect.origin.x + local_rect.size.width - prim_rect.origin.x) / prim_rect.size.width,
|
||||
(local_rect.origin.y + local_rect.size.height - prim_rect.origin.y) / prim_rect.size.height,
|
||||
);
|
||||
|
||||
let top_left = DeviceVector2D::new(
|
||||
mix(snap_offsets.top_left.x, snap_offsets.bottom_right.x, normalized_top_left.x),
|
||||
mix(snap_offsets.top_left.y, snap_offsets.bottom_right.y, normalized_top_left.y),
|
||||
);
|
||||
|
||||
let bottom_right = DeviceVector2D::new(
|
||||
mix(snap_offsets.top_left.x, snap_offsets.bottom_right.x, normalized_bottom_right.x),
|
||||
mix(snap_offsets.top_left.y, snap_offsets.bottom_right.y, normalized_bottom_right.y),
|
||||
);
|
||||
|
||||
SnapOffsets {
|
||||
top_left,
|
||||
bottom_right,
|
||||
}
|
||||
}
|
||||
|
||||
/// Retrieve the exact unsnapped device space rectangle for a primitive.
|
||||
fn get_unclipped_device_rect(
|
||||
prim_rect: PictureRect,
|
||||
|
@ -4109,11 +3859,10 @@ fn get_unclipped_device_rect(
|
|||
/// scale per-raster-root.
|
||||
fn get_clipped_device_rect(
|
||||
unclipped: &DeviceRect,
|
||||
prim_snap_offsets: SnapOffsets,
|
||||
map_to_world: &SpaceMapper<RasterPixel, WorldPixel>,
|
||||
prim_bounding_rect: WorldRect,
|
||||
device_pixel_scale: DevicePixelScale,
|
||||
) -> Option<(DeviceIntRect, SnapOffsets)> {
|
||||
) -> Option<DeviceIntRect> {
|
||||
let unclipped_raster_rect = {
|
||||
let world_rect = *unclipped * Scale::new(1.0);
|
||||
let raster_rect = world_rect * device_pixel_scale.inv();
|
||||
|
@ -4138,28 +3887,7 @@ fn get_clipped_device_rect(
|
|||
device_pixel_scale,
|
||||
);
|
||||
|
||||
let fx0 = (clipped.origin.x - unclipped.origin.x) / unclipped.size.width;
|
||||
let fy0 = (clipped.origin.y - unclipped.origin.y) / unclipped.size.height;
|
||||
|
||||
let fx1 = (clipped.origin.x + clipped.size.width - unclipped.origin.x) / unclipped.size.width;
|
||||
let fy1 = (clipped.origin.y + clipped.size.height - unclipped.origin.y) / unclipped.size.height;
|
||||
|
||||
let top_left = DeviceVector2D::new(
|
||||
mix(prim_snap_offsets.top_left.x, prim_snap_offsets.bottom_right.x, fx0),
|
||||
mix(prim_snap_offsets.top_left.y, prim_snap_offsets.bottom_right.y, fy0),
|
||||
);
|
||||
|
||||
let bottom_right = DeviceVector2D::new(
|
||||
mix(prim_snap_offsets.top_left.x, prim_snap_offsets.bottom_right.x, fx1),
|
||||
mix(prim_snap_offsets.top_left.y, prim_snap_offsets.bottom_right.y, fy1),
|
||||
);
|
||||
|
||||
let snap_offsets = SnapOffsets {
|
||||
top_left,
|
||||
bottom_right,
|
||||
};
|
||||
|
||||
Some((clipped.to_i32(), snap_offsets))
|
||||
Some(clipped.to_i32())
|
||||
}
|
||||
|
||||
pub fn get_raster_rects(
|
||||
|
@ -4197,61 +3925,6 @@ pub fn get_raster_rects(
|
|||
Some((clipped.to_i32(), unclipped))
|
||||
}
|
||||
|
||||
/// Snap the given rect in raster space if the transform is
|
||||
/// axis-aligned. It return the snapped rect transformed back into the
|
||||
/// given pixel space, and the snap offsets in device space.
|
||||
pub fn get_snapped_rect<PixelSpace>(
|
||||
prim_rect: Rect<f32, PixelSpace>,
|
||||
map_to_raster: &SpaceMapper<PixelSpace, RasterPixel>,
|
||||
device_pixel_scale: DevicePixelScale,
|
||||
) -> Option<(Rect<f32, PixelSpace>, SnapOffsets)> where PixelSpace: fmt::Debug {
|
||||
let is_axis_aligned = match map_to_raster.kind {
|
||||
CoordinateSpaceMapping::Local |
|
||||
CoordinateSpaceMapping::ScaleOffset(..) => true,
|
||||
CoordinateSpaceMapping::Transform(ref transform) => transform.preserves_2d_axis_alignment(),
|
||||
};
|
||||
|
||||
if is_axis_aligned {
|
||||
let raster_rect = map_to_raster.map(&prim_rect)?;
|
||||
|
||||
let device_rect = {
|
||||
let world_rect = raster_rect * Scale::new(1.0);
|
||||
world_rect * device_pixel_scale
|
||||
};
|
||||
|
||||
let top_left = compute_snap_offset_impl(
|
||||
prim_rect.origin,
|
||||
prim_rect,
|
||||
device_rect.origin,
|
||||
device_rect.bottom_right(),
|
||||
);
|
||||
|
||||
let bottom_right = compute_snap_offset_impl(
|
||||
prim_rect.bottom_right(),
|
||||
prim_rect,
|
||||
device_rect.origin,
|
||||
device_rect.bottom_right(),
|
||||
);
|
||||
|
||||
let snap_offsets = SnapOffsets {
|
||||
top_left,
|
||||
bottom_right,
|
||||
};
|
||||
|
||||
let snapped_device_rect = DeviceRect::new(
|
||||
device_rect.origin + top_left,
|
||||
device_rect.size + (bottom_right - top_left).to_size()
|
||||
);
|
||||
|
||||
let snapped_world_rect = snapped_device_rect / device_pixel_scale;
|
||||
let snapped_raster_rect = snapped_world_rect * Scale::new(1.0);
|
||||
let snapped_prim_rect = map_to_raster.unmap(&snapped_raster_rect)?;
|
||||
Some((snapped_prim_rect, snap_offsets))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the inline (horizontal) and block (vertical) sizes
|
||||
/// for a given line decoration.
|
||||
pub fn get_line_decoration_sizes(
|
||||
|
|
|
@ -663,7 +663,6 @@ impl RenderTarget for AlphaRenderTarget {
|
|||
task_info.actual_rect,
|
||||
&ctx.screen_world_rect,
|
||||
task_info.device_pixel_scale,
|
||||
task_info.snap_offsets,
|
||||
target_rect.origin.to_f32(),
|
||||
task_info.actual_rect.origin.to_f32(),
|
||||
);
|
||||
|
|
|
@ -14,7 +14,7 @@ use crate::filterdata::SFilterData;
|
|||
use crate::frame_builder::FrameBuilderConfig;
|
||||
use crate::freelist::{FreeList, FreeListHandle, WeakFreeListHandle};
|
||||
use crate::gpu_cache::{GpuCache, GpuCacheAddress, GpuCacheHandle};
|
||||
use crate::gpu_types::{BorderInstance, ImageSource, UvRectKind, SnapOffsets};
|
||||
use crate::gpu_types::{BorderInstance, ImageSource, UvRectKind};
|
||||
use crate::internal_types::{CacheTextureId, FastHashMap, LayerIndex, SavedTargetIndex, TextureSource};
|
||||
use crate::prim_store::{PictureIndex, PrimitiveVisibilityMask};
|
||||
use crate::prim_store::image::ImageCacheKey;
|
||||
|
@ -125,7 +125,6 @@ pub struct CacheMaskTask {
|
|||
pub actual_rect: DeviceIntRect,
|
||||
pub root_spatial_node_index: SpatialNodeIndex,
|
||||
pub clip_node_range: ClipNodeRange,
|
||||
pub snap_offsets: SnapOffsets,
|
||||
pub device_pixel_scale: DevicePixelScale,
|
||||
}
|
||||
|
||||
|
@ -523,7 +522,6 @@ impl RenderTask {
|
|||
resource_cache: &mut ResourceCache,
|
||||
render_tasks: &mut RenderTaskGraph,
|
||||
clip_data_store: &mut ClipDataStore,
|
||||
snap_offsets: SnapOffsets,
|
||||
device_pixel_scale: DevicePixelScale,
|
||||
fb_config: &FrameBuilderConfig,
|
||||
) -> Self {
|
||||
|
@ -617,7 +615,6 @@ impl RenderTask {
|
|||
actual_rect: outer_rect,
|
||||
clip_node_range,
|
||||
root_spatial_node_index,
|
||||
snap_offsets,
|
||||
device_pixel_scale,
|
||||
}),
|
||||
clear_mode,
|
||||
|
|
|
@ -620,11 +620,6 @@ pub(crate) mod desc {
|
|||
count: 4,
|
||||
kind: VertexAttributeKind::F32,
|
||||
},
|
||||
VertexAttribute {
|
||||
name: "aClipSnapOffsets",
|
||||
count: 4,
|
||||
kind: VertexAttributeKind::F32,
|
||||
},
|
||||
VertexAttribute {
|
||||
name: "aClipOrigins",
|
||||
count: 4,
|
||||
|
|
Загрузка…
Ссылка в новой задаче