commit 10f57e6c5d5640cb8c72badc0036e0798b952151
parent d385716b1faebe6b5a3187a5eec2a4b0e263f014
Author: Nicolas Silva <nical@fastmail.com>
Date: Tue, 9 Dec 2025 08:19:04 +0000
Bug 2000393 - Add GpuBufferDataF and implement it for image brush data. r=gw
We have a lot of places in the code where we push various gpu blocks in gpu buffers and figuring out what that corresponds to is a somewhat tedious exercise for the reader. In addition, changing the data representation is tricky because we can't grep for the a particular type name for the CPU side.
This patch series addresses it by adding convenience for representing series of gpu blocks to be pushed as simple structs. The patch implements it for the image brush primitive data.
Other types will be added in followup patches in this series.
Differential Revision: https://phabricator.services.mozilla.com/D272771
Diffstat:
12 files changed, 127 insertions(+), 87 deletions(-)
diff --git a/gfx/wr/webrender/res/brush_image.glsl b/gfx/wr/webrender/res/brush_image.glsl
@@ -31,15 +31,15 @@ flat varying mediump vec2 v_perspective;
#define BLEND_MODE_ALPHA 0
#define BLEND_MODE_PREMUL_ALPHA 1
-struct ImageBrushData {
+struct ImageBrushPrimitiveData {
vec4 color;
vec4 background_color;
vec2 stretch_size;
};
-ImageBrushData fetch_image_data(int address) {
+ImageBrushPrimitiveData fetch_image_data(int address) {
vec4[3] raw_data = fetch_from_gpu_buffer_3f(address);
- ImageBrushData data = ImageBrushData(
+ ImageBrushPrimitiveData data = ImageBrushPrimitiveData(
raw_data[0],
raw_data[1],
raw_data[2].xy
@@ -63,7 +63,7 @@ void brush_vs(
int brush_flags,
vec4 segment_data
) {
- ImageBrushData image_data = fetch_image_data(prim_address);
+ ImageBrushPrimitiveData image_data = fetch_image_data(prim_address);
// If this is in WR_FEATURE_TEXTURE_RECT mode, the rect and size use
// non-normalized texture coordinates.
diff --git a/gfx/wr/webrender/src/frame_builder.rs b/gfx/wr/webrender/src/frame_builder.rs
@@ -13,7 +13,7 @@ use crate::spatial_node::SpatialNodeType;
use crate::spatial_tree::{SpatialTree, SpatialNodeIndex};
use crate::composite::{CompositorKind, CompositeState, CompositeStatePreallocator};
use crate::debug_item::DebugItem;
-use crate::gpu_types::{PrimitiveHeaders, TransformPalette, ZBufferIdGenerator};
+use crate::gpu_types::{ImageBrushPrimitiveData, PrimitiveHeaders, TransformPalette, ZBufferIdGenerator};
use crate::gpu_types::{QuadSegment, TransformData};
use crate::internal_types::{FastHashMap, PlaneSplitter, FrameStamp};
use crate::picture::{DirtyRegion, SliceId, TileCacheInstance};
@@ -24,7 +24,7 @@ use crate::prim_store::{PictureIndex, PrimitiveScratchBuffer};
use crate::prim_store::{DeferredResolve, PrimitiveInstance};
use crate::profiler::{self, TransactionProfile};
use crate::render_backend::{DataStores, ScratchBuffer};
-use crate::renderer::{GpuBufferAddress, GpuBufferBuilder, GpuBufferBuilderF, GpuBufferBuilderI, GpuBufferF, GpuBufferI};
+use crate::renderer::{GpuBufferAddress, GpuBufferBuilder, GpuBufferBuilderF, GpuBufferBuilderI, GpuBufferF, GpuBufferI, GpuBufferDataF};
use crate::render_target::{PictureCacheTarget, PictureCacheTargetKind};
use crate::render_target::{RenderTargetContext, RenderTargetKind, RenderTarget};
use crate::render_task_graph::{Pass, RenderTaskGraph, RenderTaskId, SubPassSurface};
@@ -100,15 +100,13 @@ impl FrameGlobalResources {
&mut self,
gpu_buffers: &mut GpuBufferBuilder,
) {
- let mut writer = gpu_buffers.f32.write_blocks(3);
- writer.push_one(PremultipliedColorF::WHITE);
- writer.push_one(PremultipliedColorF::WHITE);
- writer.push_one([
- -1.0, // -ve means use prim rect for stretch size
- 0.0,
- 0.0,
- 0.0,
- ]);
+ let mut writer = gpu_buffers.f32.write_blocks(ImageBrushPrimitiveData::NUM_BLOCKS);
+ writer.push(&ImageBrushPrimitiveData {
+ color: PremultipliedColorF::WHITE,
+ background_color: PremultipliedColorF::WHITE,
+ // -ve means use prim rect for stretch size
+ stretch_size: LayoutSize::new(-1.0, 0.0),
+ });
self.default_image_data = writer.finish();
let mut writer = gpu_buffers.f32.write_blocks(1);
diff --git a/gfx/wr/webrender/src/gpu_types.rs b/gfx/wr/webrender/src/gpu_types.rs
@@ -12,7 +12,7 @@ use crate::internal_types::{FastHashMap, FrameVec, FrameMemory};
use crate::prim_store::ClipData;
use crate::render_task::RenderTaskAddress;
use crate::render_task_graph::RenderTaskId;
-use crate::renderer::{GpuBufferAddress, GpuBufferBuilderF, GpuBufferHandle, GpuBufferWriterF, ShaderColorMode};
+use crate::renderer::{GpuBufferAddress, GpuBufferBuilderF, GpuBufferHandle, GpuBufferWriterF, GpuBufferDataF, ShaderColorMode};
use std::i32;
use crate::util::{MatrixHelpers, TransformedRectKind};
use glyph_rasterizer::SubpixelDirection;
@@ -22,6 +22,7 @@ use crate::util::pack_as_float;
// Contains type that must exactly match the same structures declared in GLSL.
pub const VECS_PER_TRANSFORM: usize = 8;
+pub const VECS_PER_SPECIFIC_BRUSH: usize = 3;
#[derive(Copy, Clone, Debug, PartialEq)]
#[repr(C)]
@@ -1038,6 +1039,25 @@ impl ImageSource {
}
}
+// Must correspond to ImageBrushPrimitiveData in brush_image.glsl
+// Images are drawn as a white color, modulated by the total
+// opacity coming from any collapsed property bindings.
+#[derive(Copy, Clone, Debug)]
+pub struct ImageBrushPrimitiveData {
+ pub color: PremultipliedColorF,
+ pub background_color: PremultipliedColorF,
+ pub stretch_size: LayoutSize,
+}
+
+impl GpuBufferDataF for ImageBrushPrimitiveData {
+ const NUM_BLOCKS: usize = VECS_PER_SPECIFIC_BRUSH;
+ fn write(&self, writer: &mut GpuBufferWriterF) {
+ writer.push_one(self.color);
+ writer.push_one(self.background_color);
+ writer.push_one([self.stretch_size.width, self.stretch_size.height, 0.0, 0.0]);
+ }
+}
+
// Set the local -> world transform for a given spatial
// node in the transform palette.
fn register_transform(
diff --git a/gfx/wr/webrender/src/picture.rs b/gfx/wr/webrender/src/picture.rs
@@ -116,7 +116,7 @@ use crate::intern::ItemUid;
use crate::internal_types::{FastHashMap, FastHashSet, PlaneSplitter, FilterGraphOp, FilterGraphNode, Filter, FrameId};
use crate::internal_types::{PlaneSplitterIndex, PlaneSplitAnchor, TextureSource};
use crate::frame_builder::{FrameBuildingContext, FrameBuildingState, PictureState, PictureContext};
-use crate::gpu_types::{UvRectKind, ZBufferId, BlurEdgeMode};
+use crate::gpu_types::{BlurEdgeMode, ImageBrushPrimitiveData, UvRectKind, ZBufferId};
use peek_poke::{PeekPoke, poke_into_vec, peek_from_slice, ensure_red_zone};
use plane_split::{Clipper, Polygon};
use crate::prim_store::{PrimitiveTemplateKind, PictureIndex, PrimitiveInstance, PrimitiveInstanceKind};
@@ -7273,14 +7273,11 @@ impl PicturePrimitive {
).translate(shadow.offset);
// ImageBrush colors
- writer.push_one(shadow.color.premultiplied());
- writer.push_one(PremultipliedColorF::WHITE);
- writer.push_one([
- shadow_rect.width(),
- shadow_rect.height(),
- 0.0,
- 0.0,
- ]);
+ writer.push(&ImageBrushPrimitiveData {
+ color: shadow.color.premultiplied(),
+ background_color: PremultipliedColorF::WHITE,
+ stretch_size: shadow_rect.size(),
+ });
// segment rect / extra data
writer.push_one(shadow_rect);
diff --git a/gfx/wr/webrender/src/prim_store/borders.rs b/gfx/wr/webrender/src/prim_store/borders.rs
@@ -6,6 +6,7 @@ use api::{NormalBorder, PremultipliedColorF, Shadow, RasterSpace};
use api::units::*;
use crate::border::create_border_segments;
use crate::border::NormalBorderAu;
+use crate::gpu_types::ImageBrushPrimitiveData;
use crate::renderer::GpuBufferWriterF;
use crate::scene_building::{CreateShadow, IsVisible};
use crate::frame_builder::FrameBuildingState;
@@ -79,14 +80,11 @@ impl NormalBorderData {
// Border primitives currently used for
// image borders, and run through the
// normal brush_image shader.
- writer.push_one(PremultipliedColorF::WHITE);
- writer.push_one(PremultipliedColorF::WHITE);
- writer.push_one([
- prim_size.width,
- prim_size.height,
- 0.0,
- 0.0,
- ]);
+ writer.push(&ImageBrushPrimitiveData {
+ color: PremultipliedColorF::WHITE,
+ background_color: PremultipliedColorF::WHITE,
+ stretch_size: prim_size,
+ });
}
fn write_segment_gpu_blocks(
@@ -279,14 +277,11 @@ impl ImageBorderData {
// Border primitives currently used for
// image borders, and run through the
// normal brush_image shader.
- writer.push_one(PremultipliedColorF::WHITE);
- writer.push_one(PremultipliedColorF::WHITE);
- writer.push_one([
- prim_size.width,
- prim_size.height,
- 0.0,
- 0.0,
- ]);
+ writer.push(&ImageBrushPrimitiveData {
+ color: PremultipliedColorF::WHITE,
+ background_color: PremultipliedColorF::WHITE,
+ stretch_size: *prim_size,
+ });
}
fn write_segment_gpu_blocks(
diff --git a/gfx/wr/webrender/src/prim_store/gradient/conic.rs b/gfx/wr/webrender/src/prim_store/gradient/conic.rs
@@ -11,6 +11,7 @@
use euclid::vec2;
use api::{ColorF, ExtendMode, GradientStop, PremultipliedColorF};
use api::units::*;
+use crate::gpu_types::ImageBrushPrimitiveData;
use crate::pattern::{Pattern, PatternBuilder, PatternBuilderContext, PatternBuilderState, PatternKind, PatternShaderInput, PatternTextureInput};
use crate::prim_store::gradient::{gpu_gradient_stops_blocks, write_gpu_gradient_stops_tree, GradientKind};
use crate::scene_building::IsVisible;
@@ -263,14 +264,11 @@ impl ConicGradientTemplate {
) {
let mut writer = frame_state.frame_gpu_data.f32.write_blocks(3 + self.brush_segments.len() * VECS_PER_SEGMENT);
// write_prim_gpu_blocks
- writer.push_one(PremultipliedColorF::WHITE);
- writer.push_one(PremultipliedColorF::WHITE);
- writer.push_one([
- self.stretch_size.width,
- self.stretch_size.height,
- 0.0,
- 0.0,
- ]);
+ writer.push(&ImageBrushPrimitiveData {
+ color: PremultipliedColorF::WHITE,
+ background_color: PremultipliedColorF::WHITE,
+ stretch_size: self.stretch_size,
+ });
// write_segment_gpu_blocks
for segment in &self.brush_segments {
// has to match VECS_PER_SEGMENT
diff --git a/gfx/wr/webrender/src/prim_store/gradient/linear.rs b/gfx/wr/webrender/src/prim_store/gradient/linear.rs
@@ -12,6 +12,7 @@ use euclid::approxeq::ApproxEq;
use euclid::{point2, vec2, size2};
use api::{ExtendMode, GradientStop, LineOrientation, PremultipliedColorF, ColorF, ColorU};
use api::units::*;
+use crate::gpu_types::ImageBrushPrimitiveData;
use crate::pattern::{Pattern, PatternBuilder, PatternBuilderContext, PatternBuilderState, PatternKind, PatternShaderInput, PatternTextureInput};
use crate::prim_store::gradient::{gpu_gradient_stops_blocks, write_gpu_gradient_stops_tree, GradientKind};
use crate::scene_building::IsVisible;
@@ -498,15 +499,11 @@ impl LinearGradientTemplate {
// Write_prim_gpu_blocks
if self.cached {
- // We are using the image brush.
- writer.push_one(PremultipliedColorF::WHITE);
- writer.push_one(PremultipliedColorF::WHITE);
- writer.push_one([
- self.stretch_size.width,
- self.stretch_size.height,
- 0.0,
- 0.0,
- ]);
+ writer.push(&ImageBrushPrimitiveData {
+ color: PremultipliedColorF::WHITE,
+ background_color: PremultipliedColorF::WHITE,
+ stretch_size: self.stretch_size,
+ });
} else {
// We are using the gradient brush.
writer.push_one([
diff --git a/gfx/wr/webrender/src/prim_store/gradient/radial.rs b/gfx/wr/webrender/src/prim_store/gradient/radial.rs
@@ -11,6 +11,7 @@
use euclid::{vec2, size2};
use api::{ColorF, ColorU, ExtendMode, GradientStop, PremultipliedColorF};
use api::units::*;
+use crate::gpu_types::ImageBrushPrimitiveData;
use crate::pattern::{Pattern, PatternBuilder, PatternBuilderContext, PatternBuilderState, PatternKind, PatternShaderInput, PatternTextureInput};
use crate::prim_store::gradient::GradientKind;
use crate::scene_building::IsVisible;
@@ -231,14 +232,12 @@ impl RadialGradientTemplate {
let mut writer = frame_state.frame_gpu_data.f32.write_blocks(3 + self.brush_segments.len() * VECS_PER_SEGMENT);
// write_prim_gpu_blocks
- writer.push_one(PremultipliedColorF::WHITE);
- writer.push_one(PremultipliedColorF::WHITE);
- writer.push_one([
- self.stretch_size.width,
- self.stretch_size.height,
- 0.0,
- 0.0,
- ]);
+ writer.push(&ImageBrushPrimitiveData {
+ color: PremultipliedColorF::WHITE,
+ background_color: PremultipliedColorF::WHITE,
+ stretch_size: self.stretch_size,
+ });
+
// write_segment_gpu_blocks
for segment in &self.brush_segments {
// has to match VECS_PER_SEGMENT
diff --git a/gfx/wr/webrender/src/prim_store/image.rs b/gfx/wr/webrender/src/prim_store/image.rs
@@ -10,6 +10,7 @@ use api::{
use api::units::*;
use euclid::point2;
use crate::composite::CompositorSurfaceKind;
+use crate::gpu_types::ImageBrushPrimitiveData;
use crate::renderer::{GpuBufferBuilderF, GpuBufferWriterF};
use crate::scene_building::{CreateShadow, IsVisible};
use crate::frame_builder::{FrameBuildingContext, FrameBuildingState};
@@ -395,18 +396,14 @@ impl ImageData {
}
pub fn write_prim_gpu_blocks(&self, adjustment: &AdjustedImageSource, writer: &mut GpuBufferWriterF) {
- 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.
- writer.push_one(self.color.premultiplied());
- writer.push_one(PremultipliedColorF::WHITE);
- writer.push_one([
- stretch_size.width + self.tile_spacing.width,
- stretch_size.height + self.tile_spacing.height,
- 0.0,
- 0.0,
- ]);
+ let stretch_size = adjustment.map_stretch_size(self.stretch_size)
+ + self.tile_spacing;
+
+ writer.push(&ImageBrushPrimitiveData {
+ color: self.color.premultiplied(),
+ background_color: PremultipliedColorF::WHITE,
+ stretch_size,
+ });
}
}
diff --git a/gfx/wr/webrender/src/prim_store/line_dec.rs b/gfx/wr/webrender/src/prim_store/line_dec.rs
@@ -7,6 +7,7 @@ use api::{
LineOrientation, LineStyle, PremultipliedColorF, Shadow,
};
use api::units::*;
+use crate::gpu_types::ImageBrushPrimitiveData;
use crate::renderer::GpuBufferWriterF;
use crate::scene_building::{CreateShadow, IsVisible};
use crate::frame_builder::FrameBuildingState;
@@ -89,14 +90,14 @@ impl LineDecorationData {
) {
match self.cache_key.as_ref() {
Some(cache_key) => {
- writer.push_one(self.color.premultiplied());
- writer.push_one(PremultipliedColorF::WHITE);
- writer.push_one([
- cache_key.size.width.to_f32_px(),
- cache_key.size.height.to_f32_px(),
- 0.0,
- 0.0,
- ]);
+ writer.push(&ImageBrushPrimitiveData {
+ color: self.color.premultiplied(),
+ background_color: PremultipliedColorF::WHITE,
+ stretch_size: LayoutSize::new(
+ cache_key.size.width.to_f32_px(),
+ cache_key.size.height.to_f32_px(),
+ ),
+ });
}
None => {
writer.push_one(self.color.premultiplied());
diff --git a/gfx/wr/webrender/src/renderer/gpu_buffer.rs b/gfx/wr/webrender/src/renderer/gpu_buffer.rs
@@ -266,6 +266,30 @@ impl Into<GpuBufferBlockI> for [i32; 4] {
}
}
+pub trait GpuBufferDataF {
+ const NUM_BLOCKS: usize;
+ fn write(&self, writer: &mut GpuBufferWriterF);
+}
+
+//pub trait GpuBufferDataI {
+// const NUM_BLOCKS: usize;
+// fn write(&self, writer: &mut GpuBufferWriterI);
+//}
+
+impl GpuBufferDataF for [f32; 4] {
+ const NUM_BLOCKS: usize = 1;
+ fn write(&self, writer: &mut GpuBufferWriterF) {
+ writer.push_one(*self);
+ }
+}
+
+//impl GpuBufferDataI for [i32; 4] {
+// const NUM_BLOCKS: usize = 1;
+// fn write(&self, writer: &mut GpuBufferWriterI) {
+// writer.push_one(*self);
+// }
+//}
+
/// Record a patch to the GPU buffer for a render task
struct DeferredBlock {
task_id: RenderTaskId,
@@ -331,6 +355,20 @@ impl<'a, T> GpuBufferWriter<'a, T> where T: Texel {
}
}
+impl<'a> GpuBufferWriterF<'a> {
+ pub fn push<Data: GpuBufferDataF>(&mut self, data: &Data) {
+ let _start_index = self.buffer.len();
+ data.write(self);
+ debug_assert_eq!(self.buffer.len() - _start_index, Data::NUM_BLOCKS);
+ }
+}
+
+//impl<'a> GpuBufferWriterI<'a> {
+// pub fn push<Data: GpuBufferDataI>(&mut self, data: &Data) {
+// data.write(self);
+// }
+//}
+
impl<'a, T> Drop for GpuBufferWriter<'a, T> {
fn drop(&mut self) {
assert!(self.buffer.len() <= self.index + self.max_block_count, "Attempt to write too many GpuBuffer blocks");
diff --git a/gfx/wr/webrender/src/renderer/mod.rs b/gfx/wr/webrender/src/renderer/mod.rs
@@ -129,7 +129,7 @@ pub use debug::DebugRenderer;
pub use shade::{PendingShadersToPrecache, Shaders, SharedShaders};
pub use vertex::{desc, VertexArrayKind, MAX_VERTEX_TEXTURE_WIDTH};
pub use gpu_buffer::{GpuBuffer, GpuBufferF, GpuBufferBuilderF, GpuBufferI, GpuBufferBuilderI};
-pub use gpu_buffer::{GpuBufferHandle, GpuBufferAddress, GpuBufferBuilder, GpuBufferWriterF, GpuBufferBlockF};
+pub use gpu_buffer::{GpuBufferHandle, GpuBufferAddress, GpuBufferBuilder, GpuBufferWriterF, GpuBufferBlockF, GpuBufferDataF};
/// The size of the array of each type of vertex data texture that
/// is round-robin-ed each frame during bind_frame_data. Doing this