From 07ee2e9cc42c374acc38a7dd7d59d489d40a399f Mon Sep 17 00:00:00 2001 From: Adoo Date: Tue, 14 May 2024 22:17:43 +0800 Subject: [PATCH] =?UTF-8?q?feat(gpu):=20=F0=9F=8E=B8=20the=20`wgpu`=20impl?= =?UTF-8?q?ementation=20is=20compatible=20with=20WebGL?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 3 +- Cargo.toml | 4 +- examples/wordle_game/src/main.rs | 1 + gpu/src/gpu_backend.rs | 51 +++++++----- gpu/src/gpu_backend/atlas.rs | 7 +- gpu/src/gpu_backend/textures_mgr.rs | 2 +- gpu/src/lib.rs | 30 ++++++-- gpu/src/wgpu_impl.rs | 77 ++++++++++++------- .../wgpu_impl/draw_color_triangles_pass.rs | 4 +- gpu/src/wgpu_impl/draw_img_triangles_pass.rs | 27 ++++--- .../wgpu_impl/draw_linear_gradient_pass.rs | 38 ++++----- .../wgpu_impl/draw_radial_gradient_pass.rs | 34 ++++---- .../wgpu_impl/shaders/color_triangles.wgsl | 2 +- gpu/src/wgpu_impl/shaders/img_triangles.wgsl | 20 ++--- .../shaders/linear_gradient_triangles.wgsl | 6 +- .../shaders/radial_gradient_triangles.wgsl | 6 +- gpu/src/wgpu_impl/{storage.rs => uniform.rs} | 49 +++++------- 17 files changed, 199 insertions(+), 162 deletions(-) rename gpu/src/wgpu_impl/{storage.rs => uniform.rs} (60%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 351d9b6fa..9eb26890e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,10 +30,11 @@ Please only add new entries below the [Unreleased](#unreleased---releasedate) he - **core**: The split functions in `StateReader::map_reader`, `StateWriter::map_writer`, and `StateWriter::split_writer` no longer need to return a reference. (#568 @M-Adoo) - **core**: Introduced `StateWatcher` for watching state modifies, which was previously the responsibility of `StateReader`. This results in a cleaner and more compact `StateReader` implementation. (#556, @M-Adoo) - **gpu**: Introduced `GPUBackendImpl::max_textures_per_draw` to set a limit on textures per draw phase (#562 @M-Adoo) +- **gpu**: Updated the `wgpu` implementation of the GPU backend to support WebGL. (#578, @M-Adoo) ### Fixed -- **gpu**: Retrieve the texture limit size from the GPU instead of using a hardcoded value. (#pr, @M-Adoo) +- **gpu**: Retrieve the texture limit size from the GPU instead of using a hardcoded value. (#578, @M-Adoo) ### Changed diff --git a/Cargo.toml b/Cargo.toml index ef1dc6949..026a0961c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,7 +21,9 @@ resolver = "2" debug = true [profile.release] -debug = true +lto = true +strip = true +codegen-units = 1 [workspace.package] authors = ["RibirX"] diff --git a/examples/wordle_game/src/main.rs b/examples/wordle_game/src/main.rs index b34e72538..fe243da1d 100644 --- a/examples/wordle_game/src/main.rs +++ b/examples/wordle_game/src/main.rs @@ -7,6 +7,7 @@ mod wordle; fn main() { App::run(wordle_game()) .with_app_theme(material::purple::light()) + .with_size(Size::new(700., 620.)) .with_title("Wordle Game"); } diff --git a/gpu/src/gpu_backend.rs b/gpu/src/gpu_backend.rs index aac4595fd..3280f50ad 100644 --- a/gpu/src/gpu_backend.rs +++ b/gpu/src/gpu_backend.rs @@ -107,15 +107,13 @@ where self.begin_draw_phase(); let output_size = output.size(); for cmd in commands.into_iter() { + let max_tex_per_draw = self.gpu_impl.limits().max_tex_load_per_draw; let maybe_used = match cmd { PaintCommand::ImgPath { .. } => 2, PaintCommand::PopClip => 0, _ => 1, }; - if self.tex_ids_map.all_textures().len() + maybe_used - >= self.gpu_impl.load_tex_limit_per_draw() - || !self.continues_cmd(&cmd) - { + if !self.can_batch(&cmd) { // if the next command may hit the texture limit, submit the current draw phase. // And start a new draw phase. self.draw_triangles(output); @@ -123,8 +121,7 @@ where self.begin_draw_phase(); assert!( - self.tex_ids_map.all_textures().len() + maybe_used - < self.gpu_impl.load_tex_limit_per_draw(), + self.tex_ids_map.all_textures().len() + maybe_used < max_tex_per_draw, "The GPUBackend implementation does not provide a sufficient texture limit per draw." ) } @@ -195,7 +192,7 @@ where let img_start = img_slice.rect.origin.to_f32().to_array(); let img_size = img_slice.rect.size.to_f32().to_array(); let mask_head_and_tex_idx = - (mask_head as i32) << 16 | self.tex_ids_map.tex_idx(img_slice.tex_id) as i32; + mask_head << 16 | self.tex_ids_map.tex_idx(img_slice.tex_id) as i32; let prim_idx = self.img_prims.len() as u32; let prim = ImgPrimitive { transform: ts.inverse().unwrap().to_array(), @@ -242,8 +239,7 @@ where let ts = path.transform; if let Some((rect, mask_head)) = self.new_mask_layer(path) { let stop = (self.linear_gradient_stops.len() << 16 | linear_gradient.stops.len()) as u32; - let mask_head_and_spread = - (mask_head as i32) << 16 | linear_gradient.spread_method as i32; + let mask_head_and_spread = mask_head << 16 | linear_gradient.spread_method as i32; let prim: LinearGradientPrimitive = LinearGradientPrimitive { transform: ts.inverse().unwrap().to_array(), stop, @@ -343,17 +339,30 @@ where self.linear_gradient_stops.clear(); } - fn continues_cmd(&self, cmd: &PaintCommand) -> bool { - matches!( - (self.current_phase, cmd), - (CurrentPhase::None, _) - | (_, PaintCommand::Clip(_)) - | (_, PaintCommand::PopClip) - | (CurrentPhase::Color, PaintCommand::ColorPath { .. }) - | (CurrentPhase::Img, PaintCommand::ImgPath { .. }) - | (CurrentPhase::RadialGradient, PaintCommand::RadialGradient { .. }) - | (CurrentPhase::LinearGradient, PaintCommand::LinearGradient { .. }) - ) + fn can_batch(&self, cmd: &PaintCommand) -> bool { + let limits = self.gpu_impl.limits(); + let tex_used = self.tex_ids_map.all_textures().len(); + match (self.current_phase, cmd) { + (CurrentPhase::None, _) | (_, PaintCommand::PopClip) => true, + (_, PaintCommand::Clip(_)) | (CurrentPhase::Color, PaintCommand::ColorPath { .. }) => { + tex_used < limits.max_tex_load_per_draw + } + (CurrentPhase::Img, PaintCommand::ImgPath { .. }) => { + tex_used < limits.max_tex_load_per_draw - 1 + && self.img_prims.len() < limits.max_image_primitives_per_draw + } + (CurrentPhase::RadialGradient, PaintCommand::RadialGradient { .. }) => { + tex_used < limits.max_tex_load_per_draw + && self.radial_gradient_prims.len() < limits.max_radial_gradient_primitives_per_draw + && self.radial_gradient_stops.len() < limits.max_gradient_stop_primitives_per_draw + } + (CurrentPhase::LinearGradient, PaintCommand::LinearGradient { .. }) => { + tex_used < limits.max_tex_load_per_draw + && self.linear_gradient_prims.len() < limits.max_linear_gradient_primitives_per_draw + && self.linear_gradient_stops.len() < limits.max_gradient_stop_primitives_per_draw + } + _ => false, + } } fn current_clip_mask_index(&self) -> i32 { @@ -412,7 +421,7 @@ where gpu_impl.load_mask_layers(&self.mask_layers); let textures = self.tex_ids_map.all_textures(); - let max_textures = gpu_impl.load_tex_limit_per_draw(); + let max_textures = gpu_impl.limits().max_tex_load_per_draw; let mut tex_buffer = Vec::with_capacity(max_textures); textures.iter().take(max_textures).for_each(|id| { tex_buffer.push(self.tex_mgr.texture(*id)); diff --git a/gpu/src/gpu_backend/atlas.rs b/gpu/src/gpu_backend/atlas.rs index d9d7051fe..834f918fe 100644 --- a/gpu/src/gpu_backend/atlas.rs +++ b/gpu/src/gpu_backend/atlas.rs @@ -172,7 +172,7 @@ where pub(crate) fn end_frame(&mut self) { self .cache - .end_frame(&self.config.label) + .end_frame(self.config.label) .for_each(|h| release_handle!(self, h)); self .islands @@ -232,14 +232,15 @@ mod tests { #[test] fn resource_clear() { let mut wgpu = block_on(WgpuImpl::headless()); + let size = wgpu.limits().texture_size_limit; let mut atlas = Atlas::::new( - AtlasConfig::new("", DeviceSize::new(4096, 4096)), + AtlasConfig::new("", size), ColorFormat::Rgba8, AntiAliasing::None, &mut wgpu, ); atlas.allocate(1, (), DeviceSize::new(32, 32), &mut wgpu); - atlas.allocate(2, (), DeviceSize::new(4097, 16), &mut wgpu); + atlas.allocate(2, (), size, &mut wgpu); atlas.end_frame(); atlas.end_frame(); wgpu.end_frame(); diff --git a/gpu/src/gpu_backend/textures_mgr.rs b/gpu/src/gpu_backend/textures_mgr.rs index ec94d37b8..5b9fdf73f 100644 --- a/gpu/src/gpu_backend/textures_mgr.rs +++ b/gpu/src/gpu_backend/textures_mgr.rs @@ -75,7 +75,7 @@ where T::Host: GPUBackendImpl, { pub(super) fn new(gpu_impl: &mut T::Host, anti_aliasing: AntiAliasing) -> Self { - let max_size = gpu_impl.texture_size_limit(); + let max_size = gpu_impl.limits().texture_size_limit; Self { alpha_atlas: Atlas::new( diff --git a/gpu/src/lib.rs b/gpu/src/lib.rs index 2738b0102..9075ed405 100644 --- a/gpu/src/lib.rs +++ b/gpu/src/lib.rs @@ -82,12 +82,8 @@ pub trait GPUBackendImpl { /// A frame start, call once per frame fn begin_frame(&mut self); - /// Returns the maximum number of textures that the backend can load in a - /// single draw phase. - #[inline] - fn load_tex_limit_per_draw(&self) -> usize { 8 } - - fn texture_size_limit(&self) -> DeviceSize; + /// Returns the limits of the GPU backend. + fn limits(&self) -> GPULimits; /// Create a texture. fn new_texture( @@ -167,6 +163,28 @@ pub trait GPUBackendImpl { fn end_frame(&mut self); } +/// Represents the sets of limits an GPU backend can provide. +pub struct GPULimits { + /// The maximum size of the texture that the backend can create. + pub texture_size_limit: DeviceSize, + /// The maximum number of textures that the backend can load in a single draw + pub max_tex_load_per_draw: usize, + /// The maximum number of mask layers that the backend can load in a single + /// draw phase + pub max_image_primitives_per_draw: usize, + /// The maximum number of radial gradient primitives that the backend can load + /// in a single draw + pub max_radial_gradient_primitives_per_draw: usize, + /// The maximum number of linear gradient primitives that the backend can load + /// in a single draw + pub max_linear_gradient_primitives_per_draw: usize, + /// The maximum number of gradient stops that the backend can load in a single + /// draw phase + pub max_gradient_stop_primitives_per_draw: usize, + /// The maximum number of mask layers that the backend can load in a single + pub max_mask_layers_per_draw: usize, +} + #[repr(packed)] #[derive(AsBytes, PartialEq, Clone, Copy)] pub struct ColorAttr { diff --git a/gpu/src/wgpu_impl.rs b/gpu/src/wgpu_impl.rs index 25998c525..359661cea 100644 --- a/gpu/src/wgpu_impl.rs +++ b/gpu/src/wgpu_impl.rs @@ -1,4 +1,8 @@ -use std::{error::Error, mem::MaybeUninit, ops::Range}; +use std::{ + error::Error, + mem::{size_of, MaybeUninit}, + ops::Range, +}; use futures::channel::oneshot; use ribir_geom::{DevicePoint, DeviceRect, DeviceSize}; @@ -9,15 +13,15 @@ use self::{ draw_color_triangles_pass::DrawColorTrianglesPass, draw_img_triangles_pass::DrawImgTrianglesPass, draw_linear_gradient_pass::DrawLinearGradientTrianglesPass, draw_radial_gradient_pass::DrawRadialGradientTrianglesPass, draw_texture_pass::DrawTexturePass, - storage::Storage, + uniform::Uniform, }; use crate::{ - gpu_backend::Texture, ColorAttr, GPUBackendImpl, GradientStopPrimitive, ImagePrimIndex, - ImgPrimitive, LinearGradientPrimIndex, LinearGradientPrimitive, MaskLayer, + gpu_backend::Texture, ColorAttr, GPUBackendImpl, GPULimits, GradientStopPrimitive, + ImagePrimIndex, ImgPrimitive, LinearGradientPrimIndex, LinearGradientPrimitive, MaskLayer, RadialGradientPrimIndex, RadialGradientPrimitive, }; mod buffer_pool; -mod storage; +mod uniform; mod vertex_buffer; mod draw_alpha_triangles_pass; @@ -27,6 +31,16 @@ mod draw_linear_gradient_pass; mod draw_radial_gradient_pass; mod draw_texture_pass; +pub const MAX_UNIFORM_BYTES: usize = 16 << 10; // (16 KiB) +pub const MAX_IMG_PRIMITIVES: usize = MAX_UNIFORM_BYTES / size_of::(); +pub const MAX_RADIAL_GRADIENT_PRIMITIVES: usize = + MAX_UNIFORM_BYTES / size_of::(); +pub const MAX_LINEAR_GRADIENT_PRIMITIVES: usize = + MAX_UNIFORM_BYTES / size_of::(); +pub const MAX_GRADIENT_STOPS: usize = MAX_UNIFORM_BYTES / size_of::(); +pub const MAX_MASK_LAYERS: usize = MAX_UNIFORM_BYTES / size_of::(); +pub const TEX_PER_DRAW: usize = 8; + pub struct WgpuImpl { device: wgpu::Device, queue: wgpu::Queue, @@ -43,7 +57,7 @@ pub struct WgpuImpl { linear_gradient_pass: DrawLinearGradientTrianglesPass, texs_layout: wgpu::BindGroupLayout, textures_bind: Option, - mask_layers_storage: Storage, + mask_layers_uniform: Uniform, } macro_rules! command_encoder { @@ -57,18 +71,26 @@ macro_rules! command_encoder { } pub(crate) use command_encoder; -const TEX_PER_DRAW: usize = 8; - impl GPUBackendImpl for WgpuImpl { type Texture = WgpuTexture; - fn texture_size_limit(&self) -> DeviceSize { + fn limits(&self) -> crate::GPULimits { let limits = self.device.limits(); - DeviceSize::new(limits.max_texture_dimension_2d as i32, limits.max_texture_dimension_2d as i32) + let texture_size_limit = DeviceSize::new( + limits.max_texture_dimension_2d as i32, + limits.max_texture_dimension_2d as i32, + ); + GPULimits { + texture_size_limit, + max_tex_load_per_draw: TEX_PER_DRAW, + max_image_primitives_per_draw: MAX_IMG_PRIMITIVES, + max_radial_gradient_primitives_per_draw: MAX_RADIAL_GRADIENT_PRIMITIVES, + max_linear_gradient_primitives_per_draw: MAX_LINEAR_GRADIENT_PRIMITIVES, + max_gradient_stop_primitives_per_draw: MAX_GRADIENT_STOPS, + max_mask_layers_per_draw: MAX_MASK_LAYERS, + } } - fn load_tex_limit_per_draw(&self) -> usize { TEX_PER_DRAW } - fn begin_frame(&mut self) { if self.command_encoder.is_none() { let encoder = self @@ -134,19 +156,19 @@ impl GPUBackendImpl for WgpuImpl { fn load_img_primitives(&mut self, primitives: &[ImgPrimitive]) { self .img_triangles_pass - .load_img_primitives(&self.device, &self.queue, primitives); + .load_img_primitives(&self.queue, primitives); } fn load_radial_gradient_primitives(&mut self, primitives: &[RadialGradientPrimitive]) { self .radial_gradient_pass - .load_radial_gradient_primitives(&self.device, &self.queue, primitives); + .load_radial_gradient_primitives(&self.queue, primitives); } fn load_radial_gradient_stops(&mut self, stops: &[GradientStopPrimitive]) { self .radial_gradient_pass - .load_gradient_stops(&self.device, &self.queue, stops); + .load_gradient_stops(&self.queue, stops); } fn load_radial_gradient_vertices(&mut self, buffers: &VertexBuffers) { @@ -158,13 +180,13 @@ impl GPUBackendImpl for WgpuImpl { fn load_linear_gradient_primitives(&mut self, primitives: &[LinearGradientPrimitive]) { self .linear_gradient_pass - .load_linear_gradient_primitives(&self.device, &self.queue, primitives); + .load_linear_gradient_primitives(&self.queue, primitives); } fn load_linear_gradient_stops(&mut self, stops: &[GradientStopPrimitive]) { self .linear_gradient_pass - .load_gradient_stops(&self.device, &self.queue, stops); + .load_gradient_stops(&self.queue, stops); } fn load_linear_gradient_vertices(&mut self, buffers: &VertexBuffers) { @@ -175,8 +197,8 @@ impl GPUBackendImpl for WgpuImpl { fn load_mask_layers(&mut self, layers: &[crate::MaskLayer]) { self - .mask_layers_storage - .write_buffer(&self.device, &self.queue, layers); + .mask_layers_uniform + .write_buffer(&self.queue, layers); } fn draw_alpha_triangles(&mut self, indices: &Range, texture: &mut Self::Texture) { @@ -198,7 +220,7 @@ impl GPUBackendImpl for WgpuImpl { &self.device, encoder, self.textures_bind.as_ref().unwrap(), - &self.mask_layers_storage, + &self.mask_layers_uniform, ); self.submit() @@ -216,7 +238,7 @@ impl GPUBackendImpl for WgpuImpl { &self.device, encoder, self.textures_bind.as_ref().unwrap(), - &self.mask_layers_storage, + &self.mask_layers_uniform, ); self.submit() @@ -246,7 +268,7 @@ impl GPUBackendImpl for WgpuImpl { &self.device, encoder, self.textures_bind.as_ref().unwrap(), - &self.mask_layers_storage, + &self.mask_layers_uniform, ); self.submit() } @@ -262,7 +284,7 @@ impl GPUBackendImpl for WgpuImpl { &self.device, encoder, self.textures_bind.as_ref().unwrap(), - &self.mask_layers_storage, + &self.mask_layers_uniform, ); self.submit() } @@ -547,7 +569,10 @@ impl WgpuImpl { let (device, queue) = adapter .request_device( - &wgpu::DeviceDescriptor { label: Some("Request device"), ..Default::default() }, + &wgpu::DeviceDescriptor { + required_limits: wgpu::Limits::downlevel_webgl2_defaults(), + ..Default::default() + }, None, ) .await @@ -569,7 +594,7 @@ impl WgpuImpl { let draw_tex_pass = DrawTexturePass::new(&device); let alpha_triangles_pass = DrawAlphaTrianglesPass::new(&device); - let mask_layers_storage = Storage::new(&device, wgpu::ShaderStages::FRAGMENT, 512); + let mask_layers_storage = Uniform::new(&device, wgpu::ShaderStages::FRAGMENT); let texs_layout = textures_layout(&device); let color_triangles_pass = DrawColorTrianglesPass::new(&device, mask_layers_storage.layout(), &texs_layout); @@ -594,7 +619,7 @@ impl WgpuImpl { linear_gradient_pass, texs_layout, textures_bind: None, - mask_layers_storage, + mask_layers_uniform: mask_layers_storage, } } diff --git a/gpu/src/wgpu_impl/draw_color_triangles_pass.rs b/gpu/src/wgpu_impl/draw_color_triangles_pass.rs index ae3bd6486..4abee89dc 100644 --- a/gpu/src/wgpu_impl/draw_color_triangles_pass.rs +++ b/gpu/src/wgpu_impl/draw_color_triangles_pass.rs @@ -2,7 +2,7 @@ use std::{mem::size_of, ops::Range}; use ribir_painter::{Color, Vertex, VertexBuffers}; -use super::{storage::Storage, vertex_buffer::VerticesBuffer}; +use super::{uniform::Uniform, vertex_buffer::VerticesBuffer}; use crate::{ColorAttr, MaskLayer, WgpuTexture}; pub struct DrawColorTrianglesPass { @@ -43,7 +43,7 @@ impl DrawColorTrianglesPass { pub fn draw_triangles( &mut self, texture: &WgpuTexture, indices: Range, clear: Option, device: &wgpu::Device, encoder: &mut wgpu::CommandEncoder, textures_bind: &wgpu::BindGroup, - mask_layer_storage: &Storage, + mask_layer_storage: &Uniform, ) { self.update(texture.format(), device); let pipeline = self.pipeline.as_ref().unwrap(); diff --git a/gpu/src/wgpu_impl/draw_img_triangles_pass.rs b/gpu/src/wgpu_impl/draw_img_triangles_pass.rs index 799916689..c988fe368 100644 --- a/gpu/src/wgpu_impl/draw_img_triangles_pass.rs +++ b/gpu/src/wgpu_impl/draw_img_triangles_pass.rs @@ -2,7 +2,7 @@ use std::{mem::size_of, ops::Range}; use ribir_painter::{Color, Vertex, VertexBuffers}; -use super::{storage::Storage, vertex_buffer::VerticesBuffer}; +use super::{uniform::Uniform, vertex_buffer::VerticesBuffer}; use crate::{ImagePrimIndex, ImgPrimitive, MaskLayer, WgpuTexture}; pub struct DrawImgTrianglesPass { @@ -10,7 +10,7 @@ pub struct DrawImgTrianglesPass { layout: wgpu::PipelineLayout, pipeline: Option, shader: wgpu::ShaderModule, - prims_storage: Storage, + prims_uniform: Uniform, format: Option, } @@ -18,7 +18,7 @@ impl DrawImgTrianglesPass { pub fn new( device: &wgpu::Device, mask_layout: &wgpu::BindGroupLayout, texs_layout: &wgpu::BindGroupLayout, ) -> Self { - let prims_storage = Storage::new(device, wgpu::ShaderStages::FRAGMENT, 64); + let prims_storage = Uniform::new(device, wgpu::ShaderStages::FRAGMENT); let layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { label: Some("Image pipeline layout"), bind_group_layouts: &[mask_layout, prims_storage.layout(), texs_layout], @@ -31,7 +31,14 @@ impl DrawImgTrianglesPass { source: wgpu::ShaderSource::Wgsl(include_str!("./shaders/img_triangles.wgsl").into()), }); - Self { vertices_buffer, layout, pipeline: None, shader, prims_storage, format: None } + Self { + vertices_buffer, + layout, + pipeline: None, + shader, + prims_uniform: prims_storage, + format: None, + } } pub fn load_triangles_vertices( @@ -42,19 +49,15 @@ impl DrawImgTrianglesPass { .write_buffer(buffers, device, queue); } - pub fn load_img_primitives( - &mut self, device: &wgpu::Device, queue: &wgpu::Queue, primitives: &[ImgPrimitive], - ) { - self - .prims_storage - .write_buffer(device, queue, primitives); + pub fn load_img_primitives(&mut self, queue: &wgpu::Queue, primitives: &[ImgPrimitive]) { + self.prims_uniform.write_buffer(queue, primitives); } #[allow(clippy::too_many_arguments)] pub fn draw_triangles( &mut self, texture: &WgpuTexture, indices: Range, clear: Option, device: &wgpu::Device, encoder: &mut wgpu::CommandEncoder, textures_bind: &wgpu::BindGroup, - mask_layer_storage: &Storage, + mask_layer_storage: &Uniform, ) { self.update(texture.format(), device); let pipeline = self.pipeline.as_ref().unwrap(); @@ -70,7 +73,7 @@ impl DrawImgTrianglesPass { rpass.set_vertex_buffer(0, self.vertices_buffer.vertices().slice(..)); rpass.set_index_buffer(self.vertices_buffer.indices().slice(..), wgpu::IndexFormat::Uint32); rpass.set_bind_group(0, mask_layer_storage.bind_group(), &[]); - rpass.set_bind_group(1, self.prims_storage.bind_group(), &[]); + rpass.set_bind_group(1, self.prims_uniform.bind_group(), &[]); rpass.set_bind_group(2, textures_bind, &[]); rpass.set_pipeline(pipeline); diff --git a/gpu/src/wgpu_impl/draw_linear_gradient_pass.rs b/gpu/src/wgpu_impl/draw_linear_gradient_pass.rs index ca62901d9..f49774c7b 100644 --- a/gpu/src/wgpu_impl/draw_linear_gradient_pass.rs +++ b/gpu/src/wgpu_impl/draw_linear_gradient_pass.rs @@ -2,7 +2,7 @@ use std::{mem::size_of, ops::Range}; use ribir_painter::{Color, Vertex, VertexBuffers}; -use super::{storage::Storage, vertex_buffer::VerticesBuffer}; +use super::{uniform::Uniform, vertex_buffer::VerticesBuffer}; use crate::{ GradientStopPrimitive, LinearGradientPrimIndex, LinearGradientPrimitive, MaskLayer, WgpuTexture, }; @@ -12,8 +12,8 @@ pub struct DrawLinearGradientTrianglesPass { pipeline: Option, shader: wgpu::ShaderModule, format: Option, - prims_storage: Storage, - stops_storage: Storage, + prims_uniform: Uniform, + stops_uniform: Uniform, layout: wgpu::PipelineLayout, } @@ -28,14 +28,14 @@ impl DrawLinearGradientTrianglesPass { include_str!("./shaders/linear_gradient_triangles.wgsl").into(), ), }); - let prims_storage = Storage::new(device, wgpu::ShaderStages::FRAGMENT, 64); - let stops_storage = Storage::new(device, wgpu::ShaderStages::FRAGMENT, 64); + let prims_uniform = Uniform::new(device, wgpu::ShaderStages::FRAGMENT); + let stops_unifrom = Uniform::new(device, wgpu::ShaderStages::FRAGMENT); let layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { label: Some("update triangles pipeline layout"), bind_group_layouts: &[ mask_layout, - stops_storage.layout(), - prims_storage.layout(), + stops_unifrom.layout(), + prims_uniform.layout(), texs_layout, ], push_constant_ranges: &[], @@ -45,8 +45,8 @@ impl DrawLinearGradientTrianglesPass { pipeline: None, shader, format: None, - prims_storage, - stops_storage, + prims_uniform, + stops_uniform: stops_unifrom, layout, } } @@ -61,26 +61,20 @@ impl DrawLinearGradientTrianglesPass { } pub fn load_linear_gradient_primitives( - &mut self, device: &wgpu::Device, queue: &wgpu::Queue, primitives: &[LinearGradientPrimitive], + &mut self, queue: &wgpu::Queue, primitives: &[LinearGradientPrimitive], ) { - self - .prims_storage - .write_buffer(device, queue, primitives); + self.prims_uniform.write_buffer(queue, primitives); } - pub fn load_gradient_stops( - &mut self, device: &wgpu::Device, queue: &wgpu::Queue, stops: &[GradientStopPrimitive], - ) { - self - .stops_storage - .write_buffer(device, queue, stops); + pub fn load_gradient_stops(&mut self, queue: &wgpu::Queue, stops: &[GradientStopPrimitive]) { + self.stops_uniform.write_buffer(queue, stops); } #[allow(clippy::too_many_arguments)] pub fn draw_triangles( &mut self, texture: &WgpuTexture, indices: Range, clear: Option, device: &wgpu::Device, encoder: &mut wgpu::CommandEncoder, textures_bind: &wgpu::BindGroup, - mask_layer_storage: &Storage, + mask_layer_storage: &Uniform, ) { self.update(texture.format(), device); let pipeline = self.pipeline.as_ref().unwrap(); @@ -97,8 +91,8 @@ impl DrawLinearGradientTrianglesPass { rpass.set_vertex_buffer(0, self.vertices_buffer.vertices().slice(..)); rpass.set_index_buffer(self.vertices_buffer.indices().slice(..), wgpu::IndexFormat::Uint32); rpass.set_bind_group(0, mask_layer_storage.bind_group(), &[]); - rpass.set_bind_group(1, self.stops_storage.bind_group(), &[]); - rpass.set_bind_group(2, self.prims_storage.bind_group(), &[]); + rpass.set_bind_group(1, self.stops_uniform.bind_group(), &[]); + rpass.set_bind_group(2, self.prims_uniform.bind_group(), &[]); rpass.set_bind_group(3, textures_bind, &[]); rpass.set_pipeline(pipeline); diff --git a/gpu/src/wgpu_impl/draw_radial_gradient_pass.rs b/gpu/src/wgpu_impl/draw_radial_gradient_pass.rs index 0e2583b98..86d9207ca 100644 --- a/gpu/src/wgpu_impl/draw_radial_gradient_pass.rs +++ b/gpu/src/wgpu_impl/draw_radial_gradient_pass.rs @@ -2,7 +2,7 @@ use std::{mem::size_of, ops::Range}; use ribir_painter::{Color, Vertex, VertexBuffers}; -use super::{storage::Storage, vertex_buffer::VerticesBuffer}; +use super::{uniform::Uniform, vertex_buffer::VerticesBuffer}; use crate::{ GradientStopPrimitive, MaskLayer, RadialGradientPrimIndex, RadialGradientPrimitive, WgpuTexture, }; @@ -12,8 +12,8 @@ pub struct DrawRadialGradientTrianglesPass { pipeline: Option, shader: wgpu::ShaderModule, format: Option, - prims_storage: Storage, - stops_storage: Storage, + prims_uniform: Uniform, + stops_uniform: Uniform, layout: wgpu::PipelineLayout, } @@ -28,8 +28,8 @@ impl DrawRadialGradientTrianglesPass { include_str!("./shaders/radial_gradient_triangles.wgsl").into(), ), }); - let prims_storage = Storage::new(device, wgpu::ShaderStages::FRAGMENT, 64); - let stops_storage = Storage::new(device, wgpu::ShaderStages::FRAGMENT, 64); + let prims_storage = Uniform::new(device, wgpu::ShaderStages::FRAGMENT); + let stops_storage = Uniform::new(device, wgpu::ShaderStages::FRAGMENT); let layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { label: Some("update triangles pipeline layout"), bind_group_layouts: &[ @@ -46,8 +46,8 @@ impl DrawRadialGradientTrianglesPass { pipeline: None, shader, format: None, - prims_storage, - stops_storage, + prims_uniform: prims_storage, + stops_uniform: stops_storage, layout, } } @@ -62,26 +62,20 @@ impl DrawRadialGradientTrianglesPass { } pub fn load_radial_gradient_primitives( - &mut self, device: &wgpu::Device, queue: &wgpu::Queue, primitives: &[RadialGradientPrimitive], + &mut self, queue: &wgpu::Queue, primitives: &[RadialGradientPrimitive], ) { - self - .prims_storage - .write_buffer(device, queue, primitives); + self.prims_uniform.write_buffer(queue, primitives); } - pub fn load_gradient_stops( - &mut self, device: &wgpu::Device, queue: &wgpu::Queue, stops: &[GradientStopPrimitive], - ) { - self - .stops_storage - .write_buffer(device, queue, stops); + pub fn load_gradient_stops(&mut self, queue: &wgpu::Queue, stops: &[GradientStopPrimitive]) { + self.stops_uniform.write_buffer(queue, stops); } #[allow(clippy::too_many_arguments)] pub fn draw_triangles( &mut self, texture: &WgpuTexture, indices: Range, clear: Option, device: &wgpu::Device, encoder: &mut wgpu::CommandEncoder, textures_bind: &wgpu::BindGroup, - mask_layer_storage: &Storage, + mask_layer_storage: &Uniform, ) { self.update(texture.format(), device); let pipeline = self.pipeline.as_ref().unwrap(); @@ -98,8 +92,8 @@ impl DrawRadialGradientTrianglesPass { rpass.set_vertex_buffer(0, self.vertices_buffer.vertices().slice(..)); rpass.set_index_buffer(self.vertices_buffer.indices().slice(..), wgpu::IndexFormat::Uint32); rpass.set_bind_group(0, mask_layer_storage.bind_group(), &[]); - rpass.set_bind_group(1, self.stops_storage.bind_group(), &[]); - rpass.set_bind_group(2, self.prims_storage.bind_group(), &[]); + rpass.set_bind_group(1, self.stops_uniform.bind_group(), &[]); + rpass.set_bind_group(2, self.prims_uniform.bind_group(), &[]); rpass.set_bind_group(3, textures_bind, &[]); rpass.set_pipeline(pipeline); diff --git a/gpu/src/wgpu_impl/shaders/color_triangles.wgsl b/gpu/src/wgpu_impl/shaders/color_triangles.wgsl index 6196f7cdf..85d39b744 100644 --- a/gpu/src/wgpu_impl/shaders/color_triangles.wgsl +++ b/gpu/src/wgpu_impl/shaders/color_triangles.wgsl @@ -32,7 +32,7 @@ struct MaskLayer { } @group(0) @binding(0) -var mask_layers: array; +var mask_layers: array; @group(1) @binding(0) var s_sampler: sampler; diff --git a/gpu/src/wgpu_impl/shaders/img_triangles.wgsl b/gpu/src/wgpu_impl/shaders/img_triangles.wgsl index 463665e52..f5bfdc039 100644 --- a/gpu/src/wgpu_impl/shaders/img_triangles.wgsl +++ b/gpu/src/wgpu_impl/shaders/img_triangles.wgsl @@ -24,7 +24,7 @@ struct VertexOutput { } @group(0) @binding(0) -var mask_layers: array; +var mask_layers: array; @vertex fn vs_main(v: VertexInput) -> VertexOutput { @@ -48,7 +48,7 @@ struct MaskLayer { @group(1) @binding(0) -var primtives: array; +var primtives: array; @group(2) @binding(0) var s_sampler: sampler; @@ -80,42 +80,42 @@ fn fs_main(f: VertexOutput) -> @location(0) vec4 { case 0: { let img_tex_size = textureDimensions(tex_0); img_pos = img_pos / vec2(f32(img_tex_size.x), f32(img_tex_size.y)); - color = textureSample(tex_0, s_sampler, img_pos); + color = textureSampleLevel(tex_0, s_sampler, img_pos, 0.); } case 1: { let img_tex_size = textureDimensions(tex_1); img_pos = img_pos / vec2(f32(img_tex_size.x), f32(img_tex_size.y)); - color = textureSample(tex_1, s_sampler, img_pos); + color = textureSampleLevel(tex_1, s_sampler, img_pos, 0.); } case 2: { let img_tex_size = textureDimensions(tex_2); img_pos = img_pos / vec2(f32(img_tex_size.x), f32(img_tex_size.y)); - color = textureSample(tex_2, s_sampler, img_pos); + color = textureSampleLevel(tex_2, s_sampler, img_pos, 0.); } case 3: { let img_tex_size = textureDimensions(tex_3); img_pos = img_pos / vec2(f32(img_tex_size.x), f32(img_tex_size.y)); - color = textureSample(tex_3, s_sampler, img_pos); + color = textureSampleLevel(tex_3, s_sampler, img_pos, 0.); } case 4: { let img_tex_size = textureDimensions(tex_4); img_pos = img_pos / vec2(f32(img_tex_size.x), f32(img_tex_size.y)); - color = textureSample(tex_4, s_sampler, img_pos); + color = textureSampleLevel(tex_4, s_sampler, img_pos, 0.); } case 5: { let img_tex_size = textureDimensions(tex_5); img_pos = img_pos / vec2(f32(img_tex_size.x), f32(img_tex_size.y)); - color = textureSample(tex_5, s_sampler, img_pos); + color = textureSampleLevel(tex_5, s_sampler, img_pos, 0.); } case 6: { let img_tex_size = textureDimensions(tex_6); img_pos = img_pos / vec2(f32(img_tex_size.x), f32(img_tex_size.y)); - color = textureSample(tex_6, s_sampler, img_pos); + color = textureSampleLevel(tex_6, s_sampler, img_pos, 0.); } case 7: { let img_tex_size = textureDimensions(tex_7); img_pos = img_pos / vec2(f32(img_tex_size.x), f32(img_tex_size.y)); - color = textureSample(tex_7, s_sampler, img_pos); + color = textureSampleLevel(tex_7, s_sampler, img_pos, 0.); } default: { color = vec4(1., 0., 0., 1.); } }; diff --git a/gpu/src/wgpu_impl/shaders/linear_gradient_triangles.wgsl b/gpu/src/wgpu_impl/shaders/linear_gradient_triangles.wgsl index 0f5db25d1..07683c7b3 100644 --- a/gpu/src/wgpu_impl/shaders/linear_gradient_triangles.wgsl +++ b/gpu/src/wgpu_impl/shaders/linear_gradient_triangles.wgsl @@ -51,13 +51,13 @@ struct Primitive { } @group(0) @binding(0) -var mask_layers: array; +var mask_layers: array; @group(1) @binding(0) -var stops: array; +var stops: array; @group(2) @binding(0) -var prims: array; +var prims: array; @group(3) @binding(0) var s_sampler: sampler; diff --git a/gpu/src/wgpu_impl/shaders/radial_gradient_triangles.wgsl b/gpu/src/wgpu_impl/shaders/radial_gradient_triangles.wgsl index 411db8601..fe78e96f7 100644 --- a/gpu/src/wgpu_impl/shaders/radial_gradient_triangles.wgsl +++ b/gpu/src/wgpu_impl/shaders/radial_gradient_triangles.wgsl @@ -53,13 +53,13 @@ struct Primitive { } @group(0) @binding(0) -var mask_layers: array; +var mask_layers: array; @group(1) @binding(0) -var stops: array; +var stops: array; @group(2) @binding(0) -var prims: array; +var prims: array; @group(3) @binding(0) var s_sampler: sampler; diff --git a/gpu/src/wgpu_impl/storage.rs b/gpu/src/wgpu_impl/uniform.rs similarity index 60% rename from gpu/src/wgpu_impl/storage.rs rename to gpu/src/wgpu_impl/uniform.rs index 197329d8e..0f41a2067 100644 --- a/gpu/src/wgpu_impl/storage.rs +++ b/gpu/src/wgpu_impl/uniform.rs @@ -1,22 +1,24 @@ -use std::{any::type_name, marker::PhantomData, mem::size_of}; +use std::{any::type_name, marker::PhantomData}; use zerocopy::AsBytes; -pub struct Storage { +use crate::MAX_UNIFORM_BYTES; + +pub struct Uniform { layout: wgpu::BindGroupLayout, buffer: wgpu::Buffer, bind: wgpu::BindGroup, _phantom: PhantomData, } -impl Storage { - pub fn new(device: &wgpu::Device, visibility: wgpu::ShaderStages, init_count: usize) -> Self { +impl Uniform { + pub fn new(device: &wgpu::Device, visibility: wgpu::ShaderStages) -> Self { let layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { entries: &[wgpu::BindGroupLayoutEntry { binding: 0, visibility, ty: wgpu::BindingType::Buffer { - ty: wgpu::BufferBindingType::Storage { read_only: true }, + ty: wgpu::BufferBindingType::Uniform, has_dynamic_offset: false, min_binding_size: None, }, @@ -24,42 +26,29 @@ impl Storage { }], label: Some(&format!("{} storage layout", type_name::())), }); - let (buffer, bind) = - Self::new_bind(device, &layout, (size_of::() * init_count) as wgpu::BufferAddress); - let _phantom = PhantomData; - Self { layout, buffer, bind, _phantom } - } - - pub fn write_buffer(&mut self, device: &wgpu::Device, queue: &wgpu::Queue, data: &[T]) { - let buffer_size = (std::mem::size_of_val(data)) as wgpu::BufferAddress; - if self.buffer.size() < buffer_size { - (self.buffer, self.bind) = Self::new_bind(device, &self.layout, buffer_size); - } - - queue.write_buffer(&self.buffer, 0, data.as_bytes()); - } - - pub fn bind_group(&self) -> &wgpu::BindGroup { &self.bind } - pub fn layout(&self) -> &wgpu::BindGroupLayout { &self.layout } - - fn new_bind( - device: &wgpu::Device, layout: &wgpu::BindGroupLayout, bytes: wgpu::BufferAddress, - ) -> (wgpu::Buffer, wgpu::BindGroup) { let buffer = device.create_buffer(&wgpu::BufferDescriptor { label: Some(&format!("{} storage buffer", type_name::())), - size: bytes, - usage: wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST, + size: MAX_UNIFORM_BYTES as u64, + usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST, mapped_at_creation: false, }); let bind = device.create_bind_group(&wgpu::BindGroupDescriptor { label: Some(&format!("{} storage bind", type_name::())), - layout, + layout: &layout, entries: &[wgpu::BindGroupEntry { binding: 0, resource: wgpu::BindingResource::Buffer(buffer.as_entire_buffer_binding()), }], }); - (buffer, bind) + let _phantom = PhantomData; + Self { layout, buffer, bind, _phantom } + } + + pub fn write_buffer(&mut self, queue: &wgpu::Queue, data: &[T]) { + queue.write_buffer(&self.buffer, 0, data.as_bytes()); } + + pub fn bind_group(&self) -> &wgpu::BindGroup { &self.bind } + pub fn layout(&self) -> &wgpu::BindGroupLayout { &self.layout } }