diff options
Diffstat (limited to 'gfx/wr/webrender/src/renderer/vertex.rs')
-rw-r--r-- | gfx/wr/webrender/src/renderer/vertex.rs | 1154 |
1 files changed, 1154 insertions, 0 deletions
diff --git a/gfx/wr/webrender/src/renderer/vertex.rs b/gfx/wr/webrender/src/renderer/vertex.rs new file mode 100644 index 0000000000..ff555363d8 --- /dev/null +++ b/gfx/wr/webrender/src/renderer/vertex.rs @@ -0,0 +1,1154 @@ +/* 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/. */ + +//! Rendering logic related to the vertex shaders and their states, uncluding +//! - Vertex Array Objects +//! - vertex layout descriptors +//! - textures bound at vertex stage + +use std::{marker::PhantomData, mem, num::NonZeroUsize, ops}; +use api::units::*; +use crate::{ + device::{ + Device, Texture, TextureFilter, TextureUploader, UploadPBOPool, VertexUsageHint, VAO, + }, + frame_builder::Frame, + gpu_types::{PrimitiveHeaderI, PrimitiveHeaderF, TransformData}, + internal_types::Swizzle, + render_task::RenderTaskData, +}; + +pub const VERTEX_TEXTURE_EXTRA_ROWS: i32 = 10; + +pub const MAX_VERTEX_TEXTURE_WIDTH: usize = webrender_build::MAX_VERTEX_TEXTURE_WIDTH; + +pub mod desc { + use crate::device::{VertexAttribute, VertexAttributeKind, VertexDescriptor}; + + pub const PRIM_INSTANCES: VertexDescriptor = VertexDescriptor { + vertex_attributes: &[VertexAttribute { + name: "aPosition", + count: 2, + kind: VertexAttributeKind::U8Norm, + }], + instance_attributes: &[VertexAttribute { + name: "aData", + count: 4, + kind: VertexAttributeKind::I32, + }], + }; + + pub const BLUR: VertexDescriptor = VertexDescriptor { + vertex_attributes: &[VertexAttribute { + name: "aPosition", + count: 2, + kind: VertexAttributeKind::U8Norm, + }], + instance_attributes: &[ + VertexAttribute { + name: "aBlurRenderTaskAddress", + count: 1, + kind: VertexAttributeKind::U16, + }, + VertexAttribute { + name: "aBlurSourceTaskAddress", + count: 1, + kind: VertexAttributeKind::U16, + }, + VertexAttribute { + name: "aBlurDirection", + count: 1, + kind: VertexAttributeKind::I32, + }, + ], + }; + + pub const LINE: VertexDescriptor = VertexDescriptor { + vertex_attributes: &[VertexAttribute { + name: "aPosition", + count: 2, + kind: VertexAttributeKind::U8Norm, + }], + instance_attributes: &[ + VertexAttribute { + name: "aTaskRect", + count: 4, + kind: VertexAttributeKind::F32, + }, + VertexAttribute { + name: "aLocalSize", + count: 2, + kind: VertexAttributeKind::F32, + }, + VertexAttribute { + name: "aWavyLineThickness", + count: 1, + kind: VertexAttributeKind::F32, + }, + VertexAttribute { + name: "aStyle", + count: 1, + kind: VertexAttributeKind::I32, + }, + VertexAttribute { + name: "aAxisSelect", + count: 1, + kind: VertexAttributeKind::F32, + }, + ], + }; + + pub const FAST_LINEAR_GRADIENT: VertexDescriptor = VertexDescriptor { + vertex_attributes: &[VertexAttribute { + name: "aPosition", + count: 2, + kind: VertexAttributeKind::U8Norm, + }], + instance_attributes: &[ + VertexAttribute { + name: "aTaskRect", + count: 4, + kind: VertexAttributeKind::F32, + }, + VertexAttribute { + name: "aColor0", + count: 4, + kind: VertexAttributeKind::F32, + }, + VertexAttribute { + name: "aColor1", + count: 4, + kind: VertexAttributeKind::F32, + }, + VertexAttribute { + name: "aAxisSelect", + count: 1, + kind: VertexAttributeKind::F32, + }, + ], + }; + + pub const LINEAR_GRADIENT: VertexDescriptor = VertexDescriptor { + vertex_attributes: &[VertexAttribute { + name: "aPosition", + count: 2, + kind: VertexAttributeKind::U8Norm, + }], + instance_attributes: &[ + VertexAttribute { + name: "aTaskRect", + count: 4, + kind: VertexAttributeKind::F32, + }, + VertexAttribute { + name: "aStartPoint", + count: 2, + kind: VertexAttributeKind::F32, + }, + VertexAttribute { + name: "aEndPoint", + count: 2, + kind: VertexAttributeKind::F32, + }, + VertexAttribute { + name: "aScale", + count: 2, + kind: VertexAttributeKind::F32, + }, + VertexAttribute { + name: "aExtendMode", + count: 1, + kind: VertexAttributeKind::I32, + }, + VertexAttribute { + name: "aGradientStopsAddress", + count: 1, + kind: VertexAttributeKind::I32, + }, + ], + }; + + pub const RADIAL_GRADIENT: VertexDescriptor = VertexDescriptor { + vertex_attributes: &[VertexAttribute { + name: "aPosition", + count: 2, + kind: VertexAttributeKind::U8Norm, + }], + instance_attributes: &[ + VertexAttribute { + name: "aTaskRect", + count: 4, + kind: VertexAttributeKind::F32, + }, + VertexAttribute { + name: "aCenter", + count: 2, + kind: VertexAttributeKind::F32, + }, + VertexAttribute { + name: "aScale", + count: 2, + kind: VertexAttributeKind::F32, + }, + VertexAttribute { + name: "aStartRadius", + count: 1, + kind: VertexAttributeKind::F32, + }, + VertexAttribute { + name: "aEndRadius", + count: 1, + kind: VertexAttributeKind::F32, + }, + VertexAttribute { + name: "aXYRatio", + count: 1, + kind: VertexAttributeKind::F32, + }, + VertexAttribute { + name: "aExtendMode", + count: 1, + kind: VertexAttributeKind::I32, + }, + VertexAttribute { + name: "aGradientStopsAddress", + count: 1, + kind: VertexAttributeKind::I32, + }, + ], + }; + + pub const CONIC_GRADIENT: VertexDescriptor = VertexDescriptor { + vertex_attributes: &[VertexAttribute { + name: "aPosition", + count: 2, + kind: VertexAttributeKind::U8Norm, + }], + instance_attributes: &[ + VertexAttribute { + name: "aTaskRect", + count: 4, + kind: VertexAttributeKind::F32, + }, + VertexAttribute { + name: "aCenter", + count: 2, + kind: VertexAttributeKind::F32, + }, + VertexAttribute { + name: "aScale", + count: 2, + kind: VertexAttributeKind::F32, + }, + VertexAttribute { + name: "aStartOffset", + count: 1, + kind: VertexAttributeKind::F32, + }, + VertexAttribute { + name: "aEndOffset", + count: 1, + kind: VertexAttributeKind::F32, + }, + VertexAttribute { + name: "aAngle", + count: 1, + kind: VertexAttributeKind::F32, + }, + VertexAttribute { + name: "aExtendMode", + count: 1, + kind: VertexAttributeKind::I32, + }, + VertexAttribute { + name: "aGradientStopsAddress", + count: 1, + kind: VertexAttributeKind::I32, + }, + ], + }; + + pub const BORDER: VertexDescriptor = VertexDescriptor { + vertex_attributes: &[VertexAttribute { + name: "aPosition", + count: 2, + kind: VertexAttributeKind::U8Norm, + }], + instance_attributes: &[ + VertexAttribute { + name: "aTaskOrigin", + count: 2, + kind: VertexAttributeKind::F32, + }, + VertexAttribute { + name: "aRect", + count: 4, + kind: VertexAttributeKind::F32, + }, + VertexAttribute { + name: "aColor0", + count: 4, + kind: VertexAttributeKind::F32, + }, + VertexAttribute { + name: "aColor1", + count: 4, + kind: VertexAttributeKind::F32, + }, + VertexAttribute { + name: "aFlags", + count: 1, + kind: VertexAttributeKind::I32, + }, + VertexAttribute { + name: "aWidths", + count: 2, + kind: VertexAttributeKind::F32, + }, + VertexAttribute { + name: "aRadii", + count: 2, + kind: VertexAttributeKind::F32, + }, + VertexAttribute { + name: "aClipParams1", + count: 4, + kind: VertexAttributeKind::F32, + }, + VertexAttribute { + name: "aClipParams2", + count: 4, + kind: VertexAttributeKind::F32, + }, + ], + }; + + pub const SCALE: VertexDescriptor = VertexDescriptor { + vertex_attributes: &[VertexAttribute { + name: "aPosition", + count: 2, + kind: VertexAttributeKind::U8Norm, + }], + instance_attributes: &[ + VertexAttribute { + name: "aScaleTargetRect", + count: 4, + kind: VertexAttributeKind::F32, + }, + VertexAttribute { + name: "aScaleSourceRect", + count: 4, + kind: VertexAttributeKind::F32, + }, + ], + }; + + pub const CLIP_RECT: VertexDescriptor = VertexDescriptor { + vertex_attributes: &[VertexAttribute { + name: "aPosition", + count: 2, + kind: VertexAttributeKind::U8Norm, + }], + instance_attributes: &[ + // common clip attributes + VertexAttribute { + name: "aClipDeviceArea", + count: 4, + kind: VertexAttributeKind::F32, + }, + VertexAttribute { + name: "aClipOrigins", + count: 4, + kind: VertexAttributeKind::F32, + }, + VertexAttribute { + name: "aDevicePixelScale", + count: 1, + kind: VertexAttributeKind::F32, + }, + VertexAttribute { + name: "aTransformIds", + count: 2, + kind: VertexAttributeKind::I32, + }, + // specific clip attributes + VertexAttribute { + name: "aClipLocalPos", + count: 2, + kind: VertexAttributeKind::F32, + }, + VertexAttribute { + name: "aClipLocalRect", + count: 4, + kind: VertexAttributeKind::F32, + }, + VertexAttribute { + name: "aClipMode", + count: 1, + kind: VertexAttributeKind::F32, + }, + VertexAttribute { + name: "aClipRect_TL", + count: 4, + kind: VertexAttributeKind::F32, + }, + VertexAttribute { + name: "aClipRadii_TL", + count: 4, + kind: VertexAttributeKind::F32, + }, + VertexAttribute { + name: "aClipRect_TR", + count: 4, + kind: VertexAttributeKind::F32, + }, + VertexAttribute { + name: "aClipRadii_TR", + count: 4, + kind: VertexAttributeKind::F32, + }, + VertexAttribute { + name: "aClipRect_BL", + count: 4, + kind: VertexAttributeKind::F32, + }, + VertexAttribute { + name: "aClipRadii_BL", + count: 4, + kind: VertexAttributeKind::F32, + }, + VertexAttribute { + name: "aClipRect_BR", + count: 4, + kind: VertexAttributeKind::F32, + }, + VertexAttribute { + name: "aClipRadii_BR", + count: 4, + kind: VertexAttributeKind::F32, + }, + ], + }; + + pub const CLIP_BOX_SHADOW: VertexDescriptor = VertexDescriptor { + vertex_attributes: &[VertexAttribute { + name: "aPosition", + count: 2, + kind: VertexAttributeKind::U8Norm, + }], + instance_attributes: &[ + // common clip attributes + VertexAttribute { + name: "aClipDeviceArea", + count: 4, + kind: VertexAttributeKind::F32, + }, + VertexAttribute { + name: "aClipOrigins", + count: 4, + kind: VertexAttributeKind::F32, + }, + VertexAttribute { + name: "aDevicePixelScale", + count: 1, + kind: VertexAttributeKind::F32, + }, + VertexAttribute { + name: "aTransformIds", + count: 2, + kind: VertexAttributeKind::I32, + }, + // specific clip attributes + VertexAttribute { + name: "aClipDataResourceAddress", + count: 2, + kind: VertexAttributeKind::U16, + }, + VertexAttribute { + name: "aClipSrcRectSize", + count: 2, + kind: VertexAttributeKind::F32, + }, + VertexAttribute { + name: "aClipMode", + count: 1, + kind: VertexAttributeKind::I32, + }, + VertexAttribute { + name: "aStretchMode", + count: 2, + kind: VertexAttributeKind::I32, + }, + VertexAttribute { + name: "aClipDestRect", + count: 4, + kind: VertexAttributeKind::F32, + }, + ], + }; + + pub const CLIP_IMAGE: VertexDescriptor = VertexDescriptor { + vertex_attributes: &[VertexAttribute { + name: "aPosition", + count: 2, + kind: VertexAttributeKind::U8Norm, + }], + instance_attributes: &[ + // common clip attributes + VertexAttribute { + name: "aClipDeviceArea", + count: 4, + kind: VertexAttributeKind::F32, + }, + VertexAttribute { + name: "aClipOrigins", + count: 4, + kind: VertexAttributeKind::F32, + }, + VertexAttribute { + name: "aDevicePixelScale", + count: 1, + kind: VertexAttributeKind::F32, + }, + VertexAttribute { + name: "aTransformIds", + count: 2, + kind: VertexAttributeKind::I32, + }, + // specific clip attributes + VertexAttribute { + name: "aClipTileRect", + count: 4, + kind: VertexAttributeKind::F32, + }, + VertexAttribute { + name: "aClipDataResourceAddress", + count: 2, + kind: VertexAttributeKind::U16, + }, + VertexAttribute { + name: "aClipLocalRect", + count: 4, + kind: VertexAttributeKind::F32, + }, + ], + }; + + pub const GPU_CACHE_UPDATE: VertexDescriptor = VertexDescriptor { + vertex_attributes: &[ + VertexAttribute { + name: "aPosition", + count: 2, + kind: VertexAttributeKind::U16Norm, + }, + VertexAttribute { + name: "aValue", + count: 4, + kind: VertexAttributeKind::F32, + }, + ], + instance_attributes: &[], + }; + + pub const RESOLVE: VertexDescriptor = VertexDescriptor { + vertex_attributes: &[VertexAttribute { + name: "aPosition", + count: 2, + kind: VertexAttributeKind::U8Norm, + }], + instance_attributes: &[VertexAttribute { + name: "aRect", + count: 4, + kind: VertexAttributeKind::F32, + }], + }; + + pub const SVG_FILTER: VertexDescriptor = VertexDescriptor { + vertex_attributes: &[VertexAttribute { + name: "aPosition", + count: 2, + kind: VertexAttributeKind::U8Norm, + }], + instance_attributes: &[ + VertexAttribute { + name: "aFilterRenderTaskAddress", + count: 1, + kind: VertexAttributeKind::U16, + }, + VertexAttribute { + name: "aFilterInput1TaskAddress", + count: 1, + kind: VertexAttributeKind::U16, + }, + VertexAttribute { + name: "aFilterInput2TaskAddress", + count: 1, + kind: VertexAttributeKind::U16, + }, + VertexAttribute { + name: "aFilterKind", + count: 1, + kind: VertexAttributeKind::U16, + }, + VertexAttribute { + name: "aFilterInputCount", + count: 1, + kind: VertexAttributeKind::U16, + }, + VertexAttribute { + name: "aFilterGenericInt", + count: 1, + kind: VertexAttributeKind::U16, + }, + VertexAttribute { + name: "aFilterExtraDataAddress", + count: 2, + kind: VertexAttributeKind::U16, + }, + ], + }; + + pub const MASK: VertexDescriptor = VertexDescriptor { + vertex_attributes: &[VertexAttribute { + name: "aPosition", + count: 2, + kind: VertexAttributeKind::U8Norm, + }], + instance_attributes: &[ + VertexAttribute { + name: "aData", + count: 4, + kind: VertexAttributeKind::I32, + }, + VertexAttribute { + name: "aClipData", + count: 4, + kind: VertexAttributeKind::I32, + }, + ], + }; + + pub const VECTOR_STENCIL: VertexDescriptor = VertexDescriptor { + vertex_attributes: &[VertexAttribute { + name: "aPosition", + count: 2, + kind: VertexAttributeKind::U8Norm, + }], + instance_attributes: &[ + VertexAttribute { + name: "aFromPosition", + count: 2, + kind: VertexAttributeKind::F32, + }, + VertexAttribute { + name: "aCtrlPosition", + count: 2, + kind: VertexAttributeKind::F32, + }, + VertexAttribute { + name: "aToPosition", + count: 2, + kind: VertexAttributeKind::F32, + }, + VertexAttribute { + name: "aFromNormal", + count: 2, + kind: VertexAttributeKind::F32, + }, + VertexAttribute { + name: "aCtrlNormal", + count: 2, + kind: VertexAttributeKind::F32, + }, + VertexAttribute { + name: "aToNormal", + count: 2, + kind: VertexAttributeKind::F32, + }, + VertexAttribute { + name: "aPathID", + count: 1, + kind: VertexAttributeKind::U16, + }, + VertexAttribute { + name: "aPad", + count: 1, + kind: VertexAttributeKind::U16, + }, + ], + }; + + pub const VECTOR_COVER: VertexDescriptor = VertexDescriptor { + vertex_attributes: &[VertexAttribute { + name: "aPosition", + count: 2, + kind: VertexAttributeKind::U8Norm, + }], + instance_attributes: &[ + VertexAttribute { + name: "aTargetRect", + count: 4, + kind: VertexAttributeKind::I32, + }, + VertexAttribute { + name: "aStencilOrigin", + count: 2, + kind: VertexAttributeKind::I32, + }, + VertexAttribute { + name: "aSubpixel", + count: 1, + kind: VertexAttributeKind::U16, + }, + VertexAttribute { + name: "aPad", + count: 1, + kind: VertexAttributeKind::U16, + }, + ], + }; + + pub const COMPOSITE: VertexDescriptor = VertexDescriptor { + vertex_attributes: &[VertexAttribute { + name: "aPosition", + count: 2, + kind: VertexAttributeKind::U8Norm, + }], + instance_attributes: &[ + VertexAttribute { + name: "aLocalRect", + count: 4, + kind: VertexAttributeKind::F32, + }, + VertexAttribute { + name: "aDeviceClipRect", + count: 4, + kind: VertexAttributeKind::F32, + }, + VertexAttribute { + name: "aColor", + count: 4, + kind: VertexAttributeKind::F32, + }, + VertexAttribute { + name: "aParams", + count: 4, + kind: VertexAttributeKind::F32, + }, + VertexAttribute { + name: "aUvRect0", + count: 4, + kind: VertexAttributeKind::F32, + }, + VertexAttribute { + name: "aUvRect1", + count: 4, + kind: VertexAttributeKind::F32, + }, + VertexAttribute { + name: "aUvRect2", + count: 4, + kind: VertexAttributeKind::F32, + }, + VertexAttribute { + name: "aTransform", + count: 4, + kind: VertexAttributeKind::F32, + }, + ], + }; + + pub const CLEAR: VertexDescriptor = VertexDescriptor { + vertex_attributes: &[VertexAttribute { + name: "aPosition", + count: 2, + kind: VertexAttributeKind::U8Norm, + }], + instance_attributes: &[ + VertexAttribute { + name: "aRect", + count: 4, + kind: VertexAttributeKind::F32, + }, + VertexAttribute { + name: "aColor", + count: 4, + kind: VertexAttributeKind::F32, + }, + ], + }; + + pub const COPY: VertexDescriptor = VertexDescriptor { + vertex_attributes: &[VertexAttribute { + name: "aPosition", + count: 2, + kind: VertexAttributeKind::U8Norm, + }], + instance_attributes: &[ + VertexAttribute { + name: "a_src_rect", + count: 4, + kind: VertexAttributeKind::F32, + }, + VertexAttribute { + name: "a_dst_rect", + count: 4, + kind: VertexAttributeKind::F32, + }, + VertexAttribute { + name: "a_dst_texture_size", + count: 2, + kind: VertexAttributeKind::F32, + }, + ], + }; +} + +#[derive(Debug, Copy, Clone, PartialEq)] +pub enum VertexArrayKind { + Primitive, + Blur, + ClipImage, + ClipRect, + ClipBoxShadow, + VectorStencil, + VectorCover, + Border, + Scale, + LineDecoration, + FastLinearGradient, + LinearGradient, + RadialGradient, + ConicGradient, + Resolve, + SvgFilter, + Composite, + Clear, + Copy, + Mask, +} + +pub struct VertexDataTexture<T> { + texture: Option<Texture>, + format: api::ImageFormat, + _marker: PhantomData<T>, +} + +impl<T> VertexDataTexture<T> { + pub fn new(format: api::ImageFormat) -> Self { + Self { + texture: None, + format, + _marker: PhantomData, + } + } + + /// Returns a borrow of the GPU texture. Panics if it hasn't been initialized. + pub fn texture(&self) -> &Texture { + self.texture.as_ref().unwrap() + } + + /// Returns an estimate of the GPU memory consumed by this VertexDataTexture. + pub fn size_in_bytes(&self) -> usize { + self.texture.as_ref().map_or(0, |t| t.size_in_bytes()) + } + + pub fn update<'a>( + &'a mut self, + device: &mut Device, + texture_uploader: &mut TextureUploader<'a>, + data: &mut Vec<T>, + ) { + debug_assert!(mem::size_of::<T>() % 16 == 0); + let texels_per_item = mem::size_of::<T>() / 16; + let items_per_row = MAX_VERTEX_TEXTURE_WIDTH / texels_per_item; + debug_assert_ne!(items_per_row, 0); + + // Ensure we always end up with a texture when leaving this method. + let mut len = data.len(); + if len == 0 { + if self.texture.is_some() { + return; + } + data.reserve(items_per_row); + len = items_per_row; + } else { + // Extend the data array to have enough capacity to upload at least + // a multiple of the row size. This ensures memory safety when the + // array is passed to OpenGL to upload to the GPU. + let extra = len % items_per_row; + if extra != 0 { + let padding = items_per_row - extra; + data.reserve(padding); + len += padding; + } + } + + let needed_height = (len / items_per_row) as i32; + let existing_height = self + .texture + .as_ref() + .map_or(0, |t| t.get_dimensions().height); + + // Create a new texture if needed. + // + // These textures are generally very small, which is why we don't bother + // with incremental updates and just re-upload every frame. For most pages + // they're one row each, and on stress tests like css-francine they end up + // in the 6-14 range. So we size the texture tightly to what we need (usually + // 1), and shrink it if the waste would be more than `VERTEX_TEXTURE_EXTRA_ROWS` + // rows. This helps with memory overhead, especially because there are several + // instances of these textures per Renderer. + if needed_height > existing_height + || needed_height + VERTEX_TEXTURE_EXTRA_ROWS < existing_height + { + // Drop the existing texture, if any. + if let Some(t) = self.texture.take() { + device.delete_texture(t); + } + + let texture = device.create_texture( + api::ImageBufferKind::Texture2D, + self.format, + MAX_VERTEX_TEXTURE_WIDTH as i32, + // Ensure height is at least two to work around + // https://bugs.chromium.org/p/angleproject/issues/detail?id=3039 + needed_height.max(2), + TextureFilter::Nearest, + None, + ); + self.texture = Some(texture); + } + + // Note: the actual width can be larger than the logical one, with a few texels + // of each row unused at the tail. This is needed because there is still hardware + // (like Intel iGPUs) that prefers power-of-two sizes of textures ([1]). + // + // [1] https://software.intel.com/en-us/articles/opengl-performance-tips-power-of-two-textures-have-better-performance + let logical_width = if needed_height == 1 { + data.len() * texels_per_item + } else { + MAX_VERTEX_TEXTURE_WIDTH - (MAX_VERTEX_TEXTURE_WIDTH % texels_per_item) + }; + + let rect = DeviceIntRect::from_size( + DeviceIntSize::new(logical_width as i32, needed_height), + ); + + debug_assert!(len <= data.capacity(), "CPU copy will read out of bounds"); + texture_uploader.upload( + device, + self.texture(), + rect, + None, + None, + data.as_ptr(), + len, + ); + } + + pub fn deinit(mut self, device: &mut Device) { + if let Some(t) = self.texture.take() { + device.delete_texture(t); + } + } +} + +pub struct VertexDataTextures { + prim_header_f_texture: VertexDataTexture<PrimitiveHeaderF>, + prim_header_i_texture: VertexDataTexture<PrimitiveHeaderI>, + transforms_texture: VertexDataTexture<TransformData>, + render_task_texture: VertexDataTexture<RenderTaskData>, +} + +impl VertexDataTextures { + pub fn new() -> Self { + VertexDataTextures { + prim_header_f_texture: VertexDataTexture::new(api::ImageFormat::RGBAF32), + prim_header_i_texture: VertexDataTexture::new(api::ImageFormat::RGBAI32), + transforms_texture: VertexDataTexture::new(api::ImageFormat::RGBAF32), + render_task_texture: VertexDataTexture::new(api::ImageFormat::RGBAF32), + } + } + + pub fn update(&mut self, device: &mut Device, pbo_pool: &mut UploadPBOPool, frame: &mut Frame) { + let mut texture_uploader = device.upload_texture(pbo_pool); + self.prim_header_f_texture.update( + device, + &mut texture_uploader, + &mut frame.prim_headers.headers_float, + ); + self.prim_header_i_texture.update( + device, + &mut texture_uploader, + &mut frame.prim_headers.headers_int, + ); + self.transforms_texture + .update(device, &mut texture_uploader, &mut frame.transform_palette); + self.render_task_texture.update( + device, + &mut texture_uploader, + &mut frame.render_tasks.task_data, + ); + + // Flush and drop the texture uploader now, so that + // we can borrow the textures to bind them. + texture_uploader.flush(device); + + device.bind_texture( + super::TextureSampler::PrimitiveHeadersF, + &self.prim_header_f_texture.texture(), + Swizzle::default(), + ); + device.bind_texture( + super::TextureSampler::PrimitiveHeadersI, + &self.prim_header_i_texture.texture(), + Swizzle::default(), + ); + device.bind_texture( + super::TextureSampler::TransformPalette, + &self.transforms_texture.texture(), + Swizzle::default(), + ); + device.bind_texture( + super::TextureSampler::RenderTasks, + &self.render_task_texture.texture(), + Swizzle::default(), + ); + } + + pub fn size_in_bytes(&self) -> usize { + self.prim_header_f_texture.size_in_bytes() + + self.prim_header_i_texture.size_in_bytes() + + self.transforms_texture.size_in_bytes() + + self.render_task_texture.size_in_bytes() + } + + pub fn deinit(self, device: &mut Device) { + self.transforms_texture.deinit(device); + self.prim_header_f_texture.deinit(device); + self.prim_header_i_texture.deinit(device); + self.render_task_texture.deinit(device); + } +} + +pub struct RendererVAOs { + prim_vao: VAO, + blur_vao: VAO, + clip_rect_vao: VAO, + clip_box_shadow_vao: VAO, + clip_image_vao: VAO, + border_vao: VAO, + line_vao: VAO, + scale_vao: VAO, + fast_linear_gradient_vao: VAO, + linear_gradient_vao: VAO, + radial_gradient_vao: VAO, + conic_gradient_vao: VAO, + resolve_vao: VAO, + svg_filter_vao: VAO, + composite_vao: VAO, + clear_vao: VAO, + copy_vao: VAO, + mask_vao: VAO, +} + +impl RendererVAOs { + pub fn new(device: &mut Device, indexed_quads: Option<NonZeroUsize>) -> Self { + const QUAD_INDICES: [u16; 6] = [0, 1, 2, 2, 1, 3]; + const QUAD_VERTICES: [[u8; 2]; 4] = [[0, 0], [0xFF, 0], [0, 0xFF], [0xFF, 0xFF]]; + + let instance_divisor = if indexed_quads.is_some() { 0 } else { 1 }; + let prim_vao = device.create_vao(&desc::PRIM_INSTANCES, instance_divisor); + + device.bind_vao(&prim_vao); + match indexed_quads { + Some(count) => { + assert!(count.get() < u16::MAX as usize); + let quad_indices = (0 .. count.get() as u16) + .flat_map(|instance| QUAD_INDICES.iter().map(move |&index| instance * 4 + index)) + .collect::<Vec<_>>(); + device.update_vao_indices(&prim_vao, &quad_indices, VertexUsageHint::Static); + let quad_vertices = (0 .. count.get() as u16) + .flat_map(|_| QUAD_VERTICES.iter().cloned()) + .collect::<Vec<_>>(); + device.update_vao_main_vertices(&prim_vao, &quad_vertices, VertexUsageHint::Static); + } + None => { + device.update_vao_indices(&prim_vao, &QUAD_INDICES, VertexUsageHint::Static); + device.update_vao_main_vertices(&prim_vao, &QUAD_VERTICES, VertexUsageHint::Static); + } + } + + RendererVAOs { + blur_vao: device.create_vao_with_new_instances(&desc::BLUR, &prim_vao), + clip_rect_vao: device.create_vao_with_new_instances(&desc::CLIP_RECT, &prim_vao), + clip_box_shadow_vao: device + .create_vao_with_new_instances(&desc::CLIP_BOX_SHADOW, &prim_vao), + clip_image_vao: device.create_vao_with_new_instances(&desc::CLIP_IMAGE, &prim_vao), + border_vao: device.create_vao_with_new_instances(&desc::BORDER, &prim_vao), + scale_vao: device.create_vao_with_new_instances(&desc::SCALE, &prim_vao), + line_vao: device.create_vao_with_new_instances(&desc::LINE, &prim_vao), + fast_linear_gradient_vao: device.create_vao_with_new_instances(&desc::FAST_LINEAR_GRADIENT, &prim_vao), + linear_gradient_vao: device.create_vao_with_new_instances(&desc::LINEAR_GRADIENT, &prim_vao), + radial_gradient_vao: device.create_vao_with_new_instances(&desc::RADIAL_GRADIENT, &prim_vao), + conic_gradient_vao: device.create_vao_with_new_instances(&desc::CONIC_GRADIENT, &prim_vao), + resolve_vao: device.create_vao_with_new_instances(&desc::RESOLVE, &prim_vao), + svg_filter_vao: device.create_vao_with_new_instances(&desc::SVG_FILTER, &prim_vao), + composite_vao: device.create_vao_with_new_instances(&desc::COMPOSITE, &prim_vao), + clear_vao: device.create_vao_with_new_instances(&desc::CLEAR, &prim_vao), + copy_vao: device.create_vao_with_new_instances(&desc::COPY, &prim_vao), + mask_vao: device.create_vao_with_new_instances(&desc::MASK, &prim_vao), + prim_vao, + } + } + + pub fn deinit(self, device: &mut Device) { + device.delete_vao(self.prim_vao); + device.delete_vao(self.resolve_vao); + device.delete_vao(self.clip_rect_vao); + device.delete_vao(self.clip_box_shadow_vao); + device.delete_vao(self.clip_image_vao); + device.delete_vao(self.fast_linear_gradient_vao); + device.delete_vao(self.linear_gradient_vao); + device.delete_vao(self.radial_gradient_vao); + device.delete_vao(self.conic_gradient_vao); + device.delete_vao(self.blur_vao); + device.delete_vao(self.line_vao); + device.delete_vao(self.border_vao); + device.delete_vao(self.scale_vao); + device.delete_vao(self.svg_filter_vao); + device.delete_vao(self.composite_vao); + device.delete_vao(self.clear_vao); + device.delete_vao(self.copy_vao); + device.delete_vao(self.mask_vao); + } +} + +impl ops::Index<VertexArrayKind> for RendererVAOs { + type Output = VAO; + fn index(&self, kind: VertexArrayKind) -> &VAO { + match kind { + VertexArrayKind::Primitive => &self.prim_vao, + VertexArrayKind::ClipImage => &self.clip_image_vao, + VertexArrayKind::ClipRect => &self.clip_rect_vao, + VertexArrayKind::ClipBoxShadow => &self.clip_box_shadow_vao, + VertexArrayKind::Blur => &self.blur_vao, + VertexArrayKind::VectorStencil | VertexArrayKind::VectorCover => unreachable!(), + VertexArrayKind::Border => &self.border_vao, + VertexArrayKind::Scale => &self.scale_vao, + VertexArrayKind::LineDecoration => &self.line_vao, + VertexArrayKind::FastLinearGradient => &self.fast_linear_gradient_vao, + VertexArrayKind::LinearGradient => &self.linear_gradient_vao, + VertexArrayKind::RadialGradient => &self.radial_gradient_vao, + VertexArrayKind::ConicGradient => &self.conic_gradient_vao, + VertexArrayKind::Resolve => &self.resolve_vao, + VertexArrayKind::SvgFilter => &self.svg_filter_vao, + VertexArrayKind::Composite => &self.composite_vao, + VertexArrayKind::Clear => &self.clear_vao, + VertexArrayKind::Copy => &self.copy_vao, + VertexArrayKind::Mask => &self.mask_vao, + } + } +} |