1use std::{marker::PhantomData, mem, num::NonZeroUsize, ops};
11use api::units::*;
12use crate::{
13 device::{
14 Device, Texture, TextureFilter, TextureUploader, UploadPBOPool, VertexUsageHint, VAO,
15 },
16 frame_builder::Frame,
17 gpu_types::{PrimitiveHeaderI, PrimitiveHeaderF},
18 internal_types::Swizzle,
19 render_task::RenderTaskData,
20 transform::TransformData,
21};
22
23use crate::internal_types::FrameVec;
24
25pub const VERTEX_TEXTURE_EXTRA_ROWS: i32 = 10;
26
27pub const MAX_VERTEX_TEXTURE_WIDTH: usize = webrender_build::MAX_VERTEX_TEXTURE_WIDTH;
28
29pub mod desc {
30 use crate::device::{VertexAttribute, VertexAttributeKind, VertexDescriptor};
31
32 pub const PRIM_INSTANCES: VertexDescriptor = VertexDescriptor {
33 vertex_attributes: &[VertexAttribute::quad_instance_vertex()],
34 instance_attributes: &[VertexAttribute {
35 name: "aData",
36 count: 4,
37 kind: VertexAttributeKind::I32,
38 }],
39 };
40
41 pub const BLUR: VertexDescriptor = VertexDescriptor {
42 vertex_attributes: &[VertexAttribute::quad_instance_vertex()],
43 instance_attributes: &[
44 VertexAttribute::gpu_buffer_address("aBlurRenderTaskAddress"),
45 VertexAttribute::gpu_buffer_address("aBlurSourceTaskAddress"),
46 VertexAttribute::i32("aBlurDirection"),
47 VertexAttribute::i32("aBlurEdgeMode"),
48 VertexAttribute::f32x3("aBlurParams"),
49 ],
50 };
51
52 pub const LINE: VertexDescriptor = VertexDescriptor {
53 vertex_attributes: &[VertexAttribute::quad_instance_vertex()],
54 instance_attributes: &[
55 VertexAttribute::f32x4("aTaskRect"),
56 VertexAttribute::f32x2("aLocalSize"),
57 VertexAttribute::f32("aWavyLineThickness"),
58 VertexAttribute::i32("aStyle"),
59 VertexAttribute::f32("aAxisSelect"),
60 ],
61 };
62
63
64 pub const BORDER: VertexDescriptor = VertexDescriptor {
65 vertex_attributes: &[VertexAttribute::quad_instance_vertex()],
66 instance_attributes: &[
67 VertexAttribute::f32x2("aTaskOrigin"),
68 VertexAttribute::f32x4("aRect"),
69 VertexAttribute::f32x4("aColor0"),
70 VertexAttribute::f32x4("aColor1"),
71 VertexAttribute::i32("aFlags"),
72 VertexAttribute::f32x2("aWidths"),
73 VertexAttribute::f32x2("aRadii"),
74 VertexAttribute::f32x4("aClipParams1"),
75 VertexAttribute::f32x4("aClipParams2"),
76 ],
77 };
78
79 pub const SCALE: VertexDescriptor = VertexDescriptor {
80 vertex_attributes: &[VertexAttribute::quad_instance_vertex()],
81 instance_attributes: &[
82 VertexAttribute::f32x4("aScaleTargetRect"),
83 VertexAttribute::f32x4("aScaleSourceRect"),
84 VertexAttribute::f32("aSourceRectType"),
85 ],
86 };
87
88 pub const CLIP_RECT: VertexDescriptor = VertexDescriptor {
89 vertex_attributes: &[VertexAttribute::quad_instance_vertex()],
90 instance_attributes: &[
91 VertexAttribute::f32x4("aClipDeviceArea"),
93 VertexAttribute::f32x4("aClipOrigins"),
94 VertexAttribute::f32("aDevicePixelScale"),
95 VertexAttribute::i32x2("aTransformIds"),
96 VertexAttribute::f32x2("aClipLocalPos"),
98 VertexAttribute::f32x4("aClipLocalRect"),
99 VertexAttribute::f32("aClipMode"),
100 VertexAttribute::f32x4("aClipRect_TL"),
101 VertexAttribute::f32x4("aClipRadii_TL"),
102 VertexAttribute::f32x4("aClipRect_TR"),
103 VertexAttribute::f32x4("aClipRadii_TR"),
104 VertexAttribute::f32x4("aClipRect_BL"),
105 VertexAttribute::f32x4("aClipRadii_BL"),
106 VertexAttribute::f32x4("aClipRect_BR"),
107 VertexAttribute::f32x4("aClipRadii_BR"),
108 ],
109 };
110
111 pub const SVG_FILTER_NODE: VertexDescriptor = VertexDescriptor {
112 vertex_attributes: &[VertexAttribute::quad_instance_vertex()],
113 instance_attributes: &[
114 VertexAttribute::f32x4("aFilterTargetRect"),
115 VertexAttribute::f32x4("aFilterInput1ContentScaleAndOffset"),
116 VertexAttribute::f32x4("aFilterInput2ContentScaleAndOffset"),
117 VertexAttribute::gpu_buffer_address("aFilterInput1TaskAddress"),
118 VertexAttribute::gpu_buffer_address("aFilterInput2TaskAddress"),
119 VertexAttribute::u16("aFilterKind"),
120 VertexAttribute::u16("aFilterInputCount"),
121 VertexAttribute::gpu_buffer_address("aFilterExtraDataAddress"),
122 ],
123 };
124
125 pub const MASK: VertexDescriptor = VertexDescriptor {
126 vertex_attributes: &[VertexAttribute::quad_instance_vertex()],
127 instance_attributes: &[
128 VertexAttribute::i32x4("aData"),
129 VertexAttribute::i32x4("aClipData"),
130 ],
131 };
132
133 pub const COMPOSITE: VertexDescriptor = VertexDescriptor {
134 vertex_attributes: &[VertexAttribute::quad_instance_vertex()],
135 instance_attributes: &[
136 VertexAttribute::f32x4("aDeviceRect"),
137 VertexAttribute::f32x4("aDeviceClipRect"),
138 VertexAttribute::f32x4("aColor"),
139 VertexAttribute::f32x4("aParams"),
140 VertexAttribute::f32x4("aUvRect0"),
141 VertexAttribute::f32x4("aUvRect1"),
142 VertexAttribute::f32x4("aUvRect2"),
143 VertexAttribute::f32x2("aFlip"),
144 VertexAttribute::f32x4("aDeviceRoundedClipRect"),
145 VertexAttribute::f32x4("aDeviceRoundedClipRadii"),
146 ],
147 };
148
149 pub const CLEAR: VertexDescriptor = VertexDescriptor {
150 vertex_attributes: &[VertexAttribute::quad_instance_vertex()],
151 instance_attributes: &[
152 VertexAttribute::f32x4("aRect"),
153 VertexAttribute::f32x4("aColor"),
154 ],
155 };
156
157 pub const COPY: VertexDescriptor = VertexDescriptor {
158 vertex_attributes: &[VertexAttribute::quad_instance_vertex()],
159 instance_attributes: &[
160 VertexAttribute::f32x4("a_src_rect"),
161 VertexAttribute::f32x4("a_dst_rect"),
162 VertexAttribute::f32x2("a_dst_texture_size"),
163 ],
164 };
165}
166
167#[derive(Debug, Copy, Clone, PartialEq)]
168pub enum VertexArrayKind {
169 Primitive,
170 Blur,
171 ClipRect,
172 Border,
173 Scale,
174 LineDecoration,
175 SvgFilterNode,
176 Composite,
177 Clear,
178 Copy,
179 Mask,
180}
181
182pub struct VertexDataTexture<T> {
183 texture: Option<Texture>,
184 format: api::ImageFormat,
185 _marker: PhantomData<T>,
186}
187
188impl<T> VertexDataTexture<T> {
189 pub fn new(format: api::ImageFormat) -> Self {
190 Self {
191 texture: None,
192 format,
193 _marker: PhantomData,
194 }
195 }
196
197 pub fn texture(&self) -> &Texture {
199 self.texture.as_ref().unwrap()
200 }
201
202 pub fn size_in_bytes(&self) -> usize {
204 self.texture.as_ref().map_or(0, |t| t.size_in_bytes())
205 }
206
207 pub fn update<'a>(
208 &'a mut self,
209 device: &mut Device,
210 texture_uploader: &mut TextureUploader<'a>,
211 data: &mut FrameVec<T>,
212 ) {
213 debug_assert!(mem::size_of::<T>() % 16 == 0);
214 let texels_per_item = mem::size_of::<T>() / 16;
215 let items_per_row = MAX_VERTEX_TEXTURE_WIDTH / texels_per_item;
216 debug_assert_ne!(items_per_row, 0);
217
218 let mut len = data.len();
220 if len == 0 {
221 if self.texture.is_some() {
222 return;
223 }
224 data.reserve(items_per_row);
225 len = items_per_row;
226 } else {
227 let extra = len % items_per_row;
231 if extra != 0 {
232 let padding = items_per_row - extra;
233 data.reserve(padding);
234 len += padding;
235 }
236 }
237
238 let needed_height = (len / items_per_row) as i32;
239 let existing_height = self
240 .texture
241 .as_ref()
242 .map_or(0, |t| t.get_dimensions().height);
243
244 if needed_height > existing_height
254 || needed_height + VERTEX_TEXTURE_EXTRA_ROWS < existing_height
255 {
256 if let Some(t) = self.texture.take() {
258 device.delete_texture(t);
259 }
260
261 let texture = device.create_texture(
262 api::ImageBufferKind::Texture2D,
263 self.format,
264 MAX_VERTEX_TEXTURE_WIDTH as i32,
265 needed_height.max(2),
268 TextureFilter::Nearest,
269 None,
270 );
271 self.texture = Some(texture);
272 }
273
274 let logical_width = if needed_height == 1 {
280 data.len() * texels_per_item
281 } else {
282 MAX_VERTEX_TEXTURE_WIDTH - (MAX_VERTEX_TEXTURE_WIDTH % texels_per_item)
283 };
284
285 let rect = DeviceIntRect::from_size(
286 DeviceIntSize::new(logical_width as i32, needed_height),
287 );
288
289 debug_assert!(len <= data.capacity(), "CPU copy will read out of bounds");
290 texture_uploader.upload(
291 device,
292 self.texture(),
293 rect,
294 None,
295 None,
296 data.as_ptr(),
297 len,
298 );
299 }
300
301 pub fn deinit(mut self, device: &mut Device) {
302 if let Some(t) = self.texture.take() {
303 device.delete_texture(t);
304 }
305 }
306}
307
308pub struct VertexDataTextures {
309 prim_header_f_texture: VertexDataTexture<PrimitiveHeaderF>,
310 prim_header_i_texture: VertexDataTexture<PrimitiveHeaderI>,
311 transforms_texture: VertexDataTexture<TransformData>,
312 render_task_texture: VertexDataTexture<RenderTaskData>,
313}
314
315impl VertexDataTextures {
316 pub fn new() -> Self {
317 VertexDataTextures {
318 prim_header_f_texture: VertexDataTexture::new(api::ImageFormat::RGBAF32),
319 prim_header_i_texture: VertexDataTexture::new(api::ImageFormat::RGBAI32),
320 transforms_texture: VertexDataTexture::new(api::ImageFormat::RGBAF32),
321 render_task_texture: VertexDataTexture::new(api::ImageFormat::RGBAF32),
322 }
323 }
324
325 pub fn update(&mut self, device: &mut Device, pbo_pool: &mut UploadPBOPool, frame: &mut Frame) {
326 let mut texture_uploader = device.upload_texture(pbo_pool);
327 self.prim_header_f_texture.update(
328 device,
329 &mut texture_uploader,
330 &mut frame.prim_headers.headers_float,
331 );
332 self.prim_header_i_texture.update(
333 device,
334 &mut texture_uploader,
335 &mut frame.prim_headers.headers_int,
336 );
337 self.transforms_texture
338 .update(device, &mut texture_uploader, &mut frame.transform_palette);
339 self.render_task_texture.update(
340 device,
341 &mut texture_uploader,
342 &mut frame.render_tasks.task_data,
343 );
344
345 texture_uploader.flush(device);
348
349 device.bind_texture(
350 super::TextureSampler::PrimitiveHeadersF,
351 &self.prim_header_f_texture.texture(),
352 Swizzle::default(),
353 );
354 device.bind_texture(
355 super::TextureSampler::PrimitiveHeadersI,
356 &self.prim_header_i_texture.texture(),
357 Swizzle::default(),
358 );
359 device.bind_texture(
360 super::TextureSampler::TransformPalette,
361 &self.transforms_texture.texture(),
362 Swizzle::default(),
363 );
364 device.bind_texture(
365 super::TextureSampler::RenderTasks,
366 &self.render_task_texture.texture(),
367 Swizzle::default(),
368 );
369 }
370
371 pub fn size_in_bytes(&self) -> usize {
372 self.prim_header_f_texture.size_in_bytes()
373 + self.prim_header_i_texture.size_in_bytes()
374 + self.transforms_texture.size_in_bytes()
375 + self.render_task_texture.size_in_bytes()
376 }
377
378 pub fn deinit(self, device: &mut Device) {
379 self.transforms_texture.deinit(device);
380 self.prim_header_f_texture.deinit(device);
381 self.prim_header_i_texture.deinit(device);
382 self.render_task_texture.deinit(device);
383 }
384}
385
386pub struct RendererVAOs {
387 prim_vao: VAO,
388 blur_vao: VAO,
389 clip_rect_vao: VAO,
390 border_vao: VAO,
391 line_vao: VAO,
392 scale_vao: VAO,
393 svg_filter_node_vao: VAO,
394 composite_vao: VAO,
395 clear_vao: VAO,
396 copy_vao: VAO,
397 mask_vao: VAO,
398}
399
400impl RendererVAOs {
401 pub fn new(device: &mut Device, indexed_quads: Option<NonZeroUsize>) -> Self {
402 const QUAD_INDICES: [u16; 6] = [0, 1, 2, 2, 1, 3];
403 const QUAD_VERTICES: [[u8; 2]; 4] = [[0, 0], [0xFF, 0], [0, 0xFF], [0xFF, 0xFF]];
404
405 let instance_divisor = if indexed_quads.is_some() { 0 } else { 1 };
406 let prim_vao = device.create_vao(&desc::PRIM_INSTANCES, instance_divisor);
407
408 device.bind_vao(&prim_vao);
409 match indexed_quads {
410 Some(count) => {
411 assert!(count.get() < u16::MAX as usize);
412 let quad_indices = (0 .. count.get() as u16)
413 .flat_map(|instance| QUAD_INDICES.iter().map(move |&index| instance * 4 + index))
414 .collect::<Vec<_>>();
415 device.update_vao_indices(&prim_vao, &quad_indices, VertexUsageHint::Static);
416 let quad_vertices = (0 .. count.get() as u16)
417 .flat_map(|_| QUAD_VERTICES.iter().cloned())
418 .collect::<Vec<_>>();
419 device.update_vao_main_vertices(&prim_vao, &quad_vertices, VertexUsageHint::Static);
420 }
421 None => {
422 device.update_vao_indices(&prim_vao, &QUAD_INDICES, VertexUsageHint::Static);
423 device.update_vao_main_vertices(&prim_vao, &QUAD_VERTICES, VertexUsageHint::Static);
424 }
425 }
426
427 RendererVAOs {
428 blur_vao: device.create_vao_with_new_instances(&desc::BLUR, &prim_vao),
429 clip_rect_vao: device.create_vao_with_new_instances(&desc::CLIP_RECT, &prim_vao),
430 border_vao: device.create_vao_with_new_instances(&desc::BORDER, &prim_vao),
431 scale_vao: device.create_vao_with_new_instances(&desc::SCALE, &prim_vao),
432 line_vao: device.create_vao_with_new_instances(&desc::LINE, &prim_vao),
433 svg_filter_node_vao: device.create_vao_with_new_instances(&desc::SVG_FILTER_NODE, &prim_vao),
434 composite_vao: device.create_vao_with_new_instances(&desc::COMPOSITE, &prim_vao),
435 clear_vao: device.create_vao_with_new_instances(&desc::CLEAR, &prim_vao),
436 copy_vao: device.create_vao_with_new_instances(&desc::COPY, &prim_vao),
437 mask_vao: device.create_vao_with_new_instances(&desc::MASK, &prim_vao),
438 prim_vao,
439 }
440 }
441
442 pub fn deinit(self, device: &mut Device) {
443 device.delete_vao(self.prim_vao);
444 device.delete_vao(self.clip_rect_vao);
445 device.delete_vao(self.blur_vao);
446 device.delete_vao(self.line_vao);
447 device.delete_vao(self.border_vao);
448 device.delete_vao(self.scale_vao);
449 device.delete_vao(self.svg_filter_node_vao);
450 device.delete_vao(self.composite_vao);
451 device.delete_vao(self.clear_vao);
452 device.delete_vao(self.copy_vao);
453 device.delete_vao(self.mask_vao);
454 }
455}
456
457impl ops::Index<VertexArrayKind> for RendererVAOs {
458 type Output = VAO;
459 fn index(&self, kind: VertexArrayKind) -> &VAO {
460 match kind {
461 VertexArrayKind::Primitive => &self.prim_vao,
462 VertexArrayKind::ClipRect => &self.clip_rect_vao,
463 VertexArrayKind::Blur => &self.blur_vao,
464 VertexArrayKind::Border => &self.border_vao,
465 VertexArrayKind::Scale => &self.scale_vao,
466 VertexArrayKind::LineDecoration => &self.line_vao,
467 VertexArrayKind::SvgFilterNode => &self.svg_filter_node_vao,
468 VertexArrayKind::Composite => &self.composite_vao,
469 VertexArrayKind::Clear => &self.clear_vao,
470 VertexArrayKind::Copy => &self.copy_vao,
471 VertexArrayKind::Mask => &self.mask_vao,
472 }
473 }
474}