Skip to content

Commit 4b65822

Browse files
author
bors-servo
authored
Auto merge of #2694 - glennw:screen-uv2, r=mrobinson
Allow texture cache entries to store non-rectangular UVs. Most of the time, UVs are stored as a (top left, bottom right) pair of coordinates in the texture cache. The exception to this is when we have an off-screen render target that was transformed. In this case, we need access to the four corners within the render surface in order to generate correct UVs when we composite that surface into the framebuffer. Previously, we generated these in the brush shader by transforming the vertex position, and using that to generate a screen space texture coordinate. This patch removes that code, and instead does the calculation of the four corner UVs during render task generation on the CPU. The corner coordinates are then stored in the texture cache entry, and the shaders do a simple bilerp to find the correct UV at each vertex when drawing these images. This has a number of benefits: * We can draw a screen-space rendered surface at any location now with the same logic (we don't need hacks for applying local offsets etc when drawing drop-shadows). * Most importantly, when we store an off-screen surface in the texture cache for use on subsequent frames, the shader that draws that doesn't need to know anything about the transform of the surface when it was rendered. This means the screen-space UV generation doesn't rely on access to the clip-scroll node transform of the source surface. <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/webrender/2694) <!-- Reviewable:end -->
2 parents 9921f2e + d289277 commit 4b65822

14 files changed

+320
-177
lines changed

webrender/res/brush_image.glsl

Lines changed: 9 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -40,24 +40,6 @@ ImageBrushData fetch_image_data(int address) {
4040
return data;
4141
}
4242

43-
struct ImageBrushExtraData {
44-
RectWithSize rendered_task_rect;
45-
vec2 offset;
46-
};
47-
48-
ImageBrushExtraData fetch_image_extra_data(int address) {
49-
vec4[2] raw_data = fetch_from_resource_cache_2(address);
50-
RectWithSize rendered_task_rect = RectWithSize(
51-
raw_data[0].xy,
52-
raw_data[0].zw
53-
);
54-
ImageBrushExtraData data = ImageBrushExtraData(
55-
rendered_task_rect,
56-
raw_data[1].xy
57-
);
58-
return data;
59-
}
60-
6143
#ifdef WR_FEATURE_ALPHA_PASS
6244
vec2 transform_point_snapped(
6345
vec2 local_pos,
@@ -105,7 +87,7 @@ void brush_vs(
10587
max_uv - vec2(0.5)
10688
) / texture_size.xyxy;
10789

108-
vec2 f;
90+
vec2 f = (vi.local_pos - local_rect.p0) / local_rect.size;
10991

11092
#ifdef WR_FEATURE_ALPHA_PASS
11193
int color_mode = user_data.y >> 16;
@@ -121,41 +103,18 @@ void brush_vs(
121103
// image.
122104
switch (raster_space) {
123105
case RASTER_SCREEN: {
124-
ImageBrushExtraData extra_data = fetch_image_extra_data(user_data.z);
125-
126-
vec2 snapped_device_pos;
127-
128-
// For drop-shadows, we need to apply a local offset
129-
// in order to generate the correct screen-space UV.
130-
// For other effects, we can use the 1:1 mapping of
131-
// the vertex device position for the UV generation.
132-
switch (color_mode) {
133-
case COLOR_MODE_ALPHA: {
134-
vec2 local_pos = vi.local_pos - extra_data.offset;
135-
snapped_device_pos = transform_point_snapped(
136-
local_pos,
137-
local_rect,
138-
transform
139-
);
140-
break;
141-
}
142-
default:
143-
snapped_device_pos = vi.snapped_device_pos;
144-
break;
145-
}
146-
147-
f = (snapped_device_pos - extra_data.rendered_task_rect.p0) / extra_data.rendered_task_rect.size;
148-
106+
// Since the screen space UVs specify an arbitrary quad, do
107+
// a bilinear interpolation to get the correct UV for this
108+
// local position.
109+
ImageResourceExtra extra_data = fetch_image_resource_extra(user_data.x);
110+
vec2 x = mix(extra_data.st_tl, extra_data.st_tr, f.x);
111+
vec2 y = mix(extra_data.st_bl, extra_data.st_br, f.x);
112+
f = mix(x, y, f.y);
149113
break;
150114
}
151-
case RASTER_LOCAL:
152-
default: {
153-
f = (vi.local_pos - local_rect.p0) / local_rect.size;
115+
default:
154116
break;
155-
}
156117
}
157-
#else
158-
f = (vi.local_pos - local_rect.p0) / local_rect.size;
159118
#endif
160119

161120
// Offset and scale vUv here to avoid doing it in the fragment shader.

webrender/res/resource_cache.glsl

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
uniform HIGHP_SAMPLER_FLOAT sampler2D sResourceCache;
66

7+
#define VECS_PER_IMAGE_RESOURCE 2
8+
79
// TODO(gw): This is here temporarily while we have
810
// both GPU store and cache. When the GPU
911
// store code is removed, we can change the
@@ -113,4 +115,23 @@ ImageResource fetch_image_resource_direct(ivec2 address) {
113115
return ImageResource(uv_rect, data[1].x, data[1].yzw);
114116
}
115117

118+
// Fetch optional extra data for a texture cache resource. This can contain
119+
// a polygon defining a UV rect within the texture cache resource.
120+
struct ImageResourceExtra {
121+
vec2 st_tl;
122+
vec2 st_tr;
123+
vec2 st_bl;
124+
vec2 st_br;
125+
};
126+
127+
ImageResourceExtra fetch_image_resource_extra(int address) {
128+
vec4 data[2] = fetch_from_resource_cache_2(address + VECS_PER_IMAGE_RESOURCE);
129+
return ImageResourceExtra(
130+
data[0].xy,
131+
data[0].zw,
132+
data[1].xy,
133+
data[1].zw
134+
);
135+
}
136+
116137
#endif //WR_VERTEX_SHADER

webrender/src/batch.rs

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ use gpu_types::{PrimitiveInstance, RasterizationSpace, SimplePrimitiveInstance,
1818
use gpu_types::ZBufferIdGenerator;
1919
use internal_types::{FastHashMap, SavedTargetIndex, SourceTexture};
2020
use picture::{PictureCompositeMode, PicturePrimitive, PictureSurface};
21-
use picture::{IMAGE_BRUSH_BLOCKS, IMAGE_BRUSH_EXTRA_BLOCKS};
2221
use plane_split::{BspSplitter, Polygon, Splitter};
2322
use prim_store::{CachedGradient, ImageSource, PrimitiveIndex, PrimitiveKind, PrimitiveMetadata, PrimitiveStore};
2423
use prim_store::{BrushPrimitive, BrushKind, DeferredResolve, EdgeAaSegmentMask, PictureIndex, PrimitiveRun};
@@ -700,7 +699,7 @@ impl AlphaBatchBuilder {
700699
uv_rect_address.as_int(),
701700
(ShaderColorMode::ColorBitmap as i32) << 16 |
702701
RasterizationSpace::Screen as i32,
703-
picture.extra_gpu_data_handle.as_int(gpu_cache),
702+
0,
704703
],
705704
};
706705
batch.push(PrimitiveInstance::from(instance));
@@ -750,11 +749,7 @@ impl AlphaBatchBuilder {
750749
.as_int();
751750

752751
// Get the GPU cache address of the extra data handle.
753-
let extra_data_address = gpu_cache.get_address(&picture.extra_gpu_data_handle);
754-
let shadow_prim_address = extra_data_address
755-
.offset(IMAGE_BRUSH_EXTRA_BLOCKS);
756-
let shadow_data_address = extra_data_address
757-
.offset(IMAGE_BRUSH_EXTRA_BLOCKS + IMAGE_BRUSH_BLOCKS);
752+
let shadow_prim_address = gpu_cache.get_address(&picture.extra_gpu_data_handle);
758753

759754
let shadow_instance = BrushInstance {
760755
picture_address: task_address,
@@ -770,7 +765,7 @@ impl AlphaBatchBuilder {
770765
shadow_uv_rect_address,
771766
(ShaderColorMode::Alpha as i32) << 16 |
772767
RasterizationSpace::Screen as i32,
773-
shadow_data_address.as_int(),
768+
0,
774769
],
775770
};
776771

@@ -780,7 +775,7 @@ impl AlphaBatchBuilder {
780775
content_uv_rect_address,
781776
(ShaderColorMode::ColorBitmap as i32) << 16 |
782777
RasterizationSpace::Screen as i32,
783-
extra_data_address.as_int(),
778+
0,
784779
],
785780
..shadow_instance
786781
};
@@ -953,7 +948,7 @@ impl AlphaBatchBuilder {
953948
uv_rect_address,
954949
(ShaderColorMode::ColorBitmap as i32) << 16 |
955950
RasterizationSpace::Screen as i32,
956-
picture.extra_gpu_data_handle.as_int(gpu_cache),
951+
0,
957952
],
958953
};
959954
batch.push(PrimitiveInstance::from(instance));

webrender/src/clip_scroll_node.rs

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,9 @@ pub struct ClipScrollNode {
101101
/// World transform for content transformed by this node.
102102
pub world_content_transform: LayoutToWorldFastTransform,
103103

104+
/// The current transform kind of world_content_transform.
105+
pub transform_kind: TransformedRectKind,
106+
104107
/// Pipeline that this layer belongs to
105108
pub pipeline_id: PipelineId,
106109

@@ -142,6 +145,7 @@ impl ClipScrollNode {
142145
local_viewport_rect: *rect,
143146
world_viewport_transform: LayoutToWorldFastTransform::identity(),
144147
world_content_transform: LayoutToWorldFastTransform::identity(),
148+
transform_kind: TransformedRectKind::AxisAligned,
145149
parent: parent_index,
146150
children: Vec::new(),
147151
pipeline_id,
@@ -285,15 +289,10 @@ impl ClipScrollNode {
285289
}
286290
};
287291

288-
let transform_kind = if self.world_content_transform.preserves_2d_axis_alignment() {
289-
TransformedRectKind::AxisAligned
290-
} else {
291-
TransformedRectKind::Complex
292-
};
293292
let data = ClipScrollNodeData {
294293
transform: self.world_content_transform.into(),
295294
inv_transform,
296-
transform_kind: transform_kind as u32 as f32,
295+
transform_kind: self.transform_kind as u32 as f32,
297296
padding: [0.0; 3],
298297
};
299298

@@ -321,6 +320,12 @@ impl ClipScrollNode {
321320

322321
self.update_transform(state, next_coordinate_system_id, scene_properties);
323322

323+
self.transform_kind = if self.world_content_transform.preserves_2d_axis_alignment() {
324+
TransformedRectKind::AxisAligned
325+
} else {
326+
TransformedRectKind::Complex
327+
};
328+
324329
// If this node is a reference frame, we check if it has a non-invertible matrix.
325330
// For non-reference-frames we assume that they will produce only additional
326331
// translations which should be invertible.

webrender/src/frame_builder.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use clip_scroll_node::{ClipScrollNode};
1010
use clip_scroll_tree::{ClipScrollNodeIndex, ClipScrollTree};
1111
use display_list_flattener::{DisplayListFlattener};
1212
use gpu_cache::GpuCache;
13-
use gpu_types::{ClipChainRectIndex, ClipScrollNodeData};
13+
use gpu_types::{ClipChainRectIndex, ClipScrollNodeData, UvRectKind};
1414
use hit_test::{HitTester, HitTestingRun};
1515
use internal_types::{FastHashMap};
1616
use picture::PictureSurface;
@@ -233,6 +233,7 @@ impl FrameBuilder {
233233
PrimitiveIndex(0),
234234
DeviceIntPoint::zero(),
235235
pic_state.tasks,
236+
UvRectKind::Rect,
236237
);
237238

238239
let render_task_id = frame_state.render_tasks.add(root_render_task);

webrender/src/glyph_rasterizer.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ use device::TextureFilter;
2121
use euclid::{TypedPoint2D, TypedSize2D, TypedVector2D};
2222
use glyph_cache::{CachedGlyphInfo, GlyphCache, GlyphCacheEntry};
2323
use gpu_cache::GpuCache;
24+
use gpu_types::UvRectKind;
2425
use internal_types::ResourceCacheError;
2526
#[cfg(feature = "pathfinder")]
2627
use pathfinder_font_renderer;
@@ -800,6 +801,7 @@ impl GlyphRasterizer {
800801
None,
801802
gpu_cache,
802803
Some(glyph_key_cache.eviction_notice()),
804+
UvRectKind::Rect,
803805
);
804806
GlyphCacheEntry::Cached(CachedGlyphInfo {
805807
texture_cache_handle,

webrender/src/gpu_cache.rs

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -151,13 +151,6 @@ impl GpuCacheAddress {
151151
v: u16::MAX,
152152
}
153153
}
154-
155-
pub fn offset(&self, offset: usize) -> Self {
156-
GpuCacheAddress {
157-
u: self.u + offset as u16,
158-
v: self.v
159-
}
160-
}
161154
}
162155

163156
impl Add<usize> for GpuCacheAddress {

webrender/src/gpu_types.rs

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -277,15 +277,38 @@ impl ClipScrollNodeData {
277277
#[repr(C)]
278278
pub struct ClipChainRectIndex(pub usize);
279279

280+
// Texture cache resources can be either a simple rect, or define
281+
// a polygon within a rect by specifying a UV coordinate for each
282+
// corner. This is useful for rendering screen-space rasterized
283+
// off-screen surfaces.
284+
#[derive(Debug, Copy, Clone)]
285+
#[cfg_attr(feature = "capture", derive(Serialize))]
286+
#[cfg_attr(feature = "replay", derive(Deserialize))]
287+
pub enum UvRectKind {
288+
// The 2d bounds of the texture cache entry define the
289+
// valid UV space for this texture cache entry.
290+
Rect,
291+
// The four vertices below define a quad within
292+
// the texture cache entry rect. The shader can
293+
// use a bilerp() to correctly interpolate a
294+
// UV coord in the vertex shader.
295+
Quad {
296+
top_left: DevicePoint,
297+
top_right: DevicePoint,
298+
bottom_left: DevicePoint,
299+
bottom_right: DevicePoint,
300+
},
301+
}
302+
280303
#[derive(Debug, Copy, Clone)]
281304
#[cfg_attr(feature = "capture", derive(Serialize))]
282305
#[cfg_attr(feature = "replay", derive(Deserialize))]
283-
#[repr(C)]
284306
pub struct ImageSource {
285307
pub p0: DevicePoint,
286308
pub p1: DevicePoint,
287309
pub texture_layer: f32,
288310
pub user_data: [f32; 3],
311+
pub uv_rect_kind: UvRectKind,
289312
}
290313

291314
impl ImageSource {
@@ -302,5 +325,22 @@ impl ImageSource {
302325
self.user_data[1],
303326
self.user_data[2],
304327
]);
328+
329+
// If this is a polygon uv kind, then upload the four vertices.
330+
if let UvRectKind::Quad { top_left, top_right, bottom_left, bottom_right } = self.uv_rect_kind {
331+
request.push([
332+
top_left.x,
333+
top_left.y,
334+
top_right.x,
335+
top_right.y,
336+
]);
337+
338+
request.push([
339+
bottom_left.x,
340+
bottom_left.y,
341+
bottom_right.x,
342+
bottom_right.y,
343+
]);
344+
}
305345
}
306346
}

0 commit comments

Comments
 (0)