Remove programs <-> resources cycle
diff --git a/vello_gpu/src/render/webgl/init.rs b/vello_gpu/src/render/webgl/init.rs index 60a2eef..7d7e197 100644 --- a/vello_gpu/src/render/webgl/init.rs +++ b/vello_gpu/src/render/webgl/init.rs
@@ -19,11 +19,9 @@ WebGlError, WebGlOperation, WebGlResultExt, WebGlShaderProgramOperation, WebGlShaderStage, }; use crate::{ - RenderSettings, RenderSize, Resources, + RenderSettings, Resources, render::common::{DeviceLimits, SharedCore}, }; -use alloc::vec; -use alloc::vec::Vec; use core::cell::Cell; use core::time::Duration; use vello_gpu_shaders::{blend, copy, filter as filter_shader, render}; @@ -65,7 +63,6 @@ pub struct WebGlRendererInit { shaders: WebGlShaders, resources: WebGlResources, - encoded_paints_data: Vec<u8>, core: SharedCore, } @@ -203,12 +200,10 @@ initialize_filter_vao(gl, &webgl_resources); initialize_blend_vao(gl, &webgl_resources); initialize_copy_vao(gl, &webgl_resources); - let encoded_paints_data = vec![0; (resource_texture_dimension_2d << 4) as usize]; let init = WebGlRendererInit { shaders, resources: webgl_resources, - encoded_paints_data, core, }; @@ -394,7 +389,6 @@ let Self { shaders, resources, - encoded_paints_data, core, } = self; let WebGlShaders { @@ -439,18 +433,14 @@ copy_program, copy_uniforms, shader_compilation_stats, - resources, - render_size: RenderSize { - width: 0, - height: 0, - }, - negate_ndc: false, - scene_offset: (0, 0), - encoded_paints_data, - filter_data: Vec::new(), }; - Ok(WebGlRenderer { programs, gl, core }) + Ok(WebGlRenderer { + programs, + resources, + gl, + core, + }) } }
diff --git a/vello_gpu/src/render/webgl/mod.rs b/vello_gpu/src/render/webgl/mod.rs index e65cdc1..48c2b08 100644 --- a/vello_gpu/src/render/webgl/mod.rs +++ b/vello_gpu/src/render/webgl/mod.rs
@@ -56,6 +56,7 @@ #[cfg(feature = "text")] use glifo::PendingClearRect; use passes::{WebGlPrograms, WebGlRendererContext}; +use resources::WebGlResources; use vello_common::color::{AlphaColor, Srgb}; use vello_common::image_cache::ImageCache; use vello_common::multi_atlas::{AtlasConfig, AtlasId}; @@ -80,6 +81,8 @@ pub struct WebGlRenderer { /// Programs for rendering. pub(super) programs: WebGlPrograms, + /// GPU resources for rendering. + pub(super) resources: WebGlResources, /// WebGL context. pub(crate) gl: WebGl2RenderingContext, /// Backend-independent renderer state. @@ -246,7 +249,7 @@ atlas_id: AtlasId, texture_bindings: &WebGlTextureBindings, ) -> Result<(), WebGlError> { - self.programs + self.resources .maybe_create_atlas_textures(&self.gl, atlas_count)?; let (atlas_width, atlas_height) = atlas_config.atlas_size; @@ -254,7 +257,7 @@ width: atlas_width, height: atlas_height, }; - let target = self.programs.resources.atlas_targets[atlas_id.as_u32() as usize].clone(); + let target = self.resources.atlas_targets[atlas_id.as_u32() as usize].clone(); // TODO: Explore using an option instead of a dummy image cache. let dummy_image_cache = self .core @@ -286,21 +289,16 @@ target: &WebGlTextureTarget, render: impl FnOnce(&mut Self) -> Result<(), WebGlError>, ) -> Result<(), WebGlError> { - let previous_target = self.programs.resources.root_target.replace(target.clone()); + let previous_target = self.resources.root_target.replace(target.clone()); let result = render(self); - self.programs.resources.root_target = previous_target; + self.resources.root_target = previous_target; result } fn current_allocations(&self) -> IntermediateTextureAllocations { IntermediateTextureAllocations { - layer_pages: self - .programs - .resources - .layer_textures - .each_ref() - .map(Vec::len), - scratch: self.programs.resources.scratch_texture.is_some(), + layer_pages: self.resources.layer_textures.each_ref().map(Vec::len), + scratch: self.resources.scratch_texture.is_some(), } } @@ -318,7 +316,7 @@ render_target_texture: Option<&WebGlTexture>, scene_offset: (i32, i32), ) -> Result<(), WebGlError> { - let use_depth_buffer = self.programs.resources.root_uses_depth_buffer(); + let use_depth_buffer = self.resources.root_uses_depth_buffer(); let current_allocations = self.current_allocations(); let schedule = self.core.prepare( @@ -331,19 +329,19 @@ scene_offset, ), use_depth_buffer, - self.programs.resources.texture_size, + self.resources.texture_size, current_allocations, |id, image, region| { texture_bindings.encode_paint(id, image, region, render_target_texture) }, )?; - self.programs + self.resources .prepare_intermediate_textures(&self.gl, &schedule)?; // TODO: For the time being, we upload the entire alpha buffer as one big chunk. As a future // refinement, we could have a bounded alpha buffer, and break draws when the alpha // buffer fills. - self.programs.prepare( + self.resources.prepare( &self.gl, &mut self.core.gradient_cache, &self.core.encoded_paints, @@ -354,9 +352,10 @@ &self.core.schedule_storage.filter_context, root_output_target, )?; - self.programs.resources.depth_cleared_this_frame = false; + self.resources.depth_cleared_this_frame = false; let mut ctx = WebGlRendererContext { - programs: &mut self.programs, + programs: &self.programs, + resources: &mut self.resources, gl: &self.gl, texture_bindings, scratch_buffers: &mut self.core.scratch_buffers, @@ -374,19 +373,19 @@ self.gl.bind_framebuffer( WebGl2RenderingContext::FRAMEBUFFER, - self.programs.resources.root_framebuffer(), + self.resources.root_framebuffer(), ); - if self.programs.resources.depth_cleared_this_frame { + if self.resources.depth_cleared_this_frame { // See: https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/WebGL_best_practices#use_invalidateframebuffer // We want to indicate to the GPU driver that we won't read the depth buffer again // until the next clear. This enables the GPU to avoid storing depth tiles back to VRAM. self.gl .invalidate_framebuffer( WebGl2RenderingContext::FRAMEBUFFER, - if self.programs.resources.root_target.is_some() { - &self.programs.resources.offscreen_depth_attachment_array + if self.resources.root_target.is_some() { + &self.resources.offscreen_depth_attachment_array } else { - &self.programs.resources.default_depth_attachment_array + &self.resources.default_depth_attachment_array }, ) .map_js_error(WebGlOperation::DataTransfer( @@ -469,12 +468,12 @@ .get(image_id) .ok_or(RenderError::MissingImage(image_id))?; - self.programs + self.resources .maybe_create_atlas_textures(&self.gl, image_cache.atlas_count() as u32)?; let offset = offset_override.unwrap_or(image_resource.offset); writer.write_to_atlas( &self.gl, - &self.programs.resources.atlas_textures[image_resource.atlas_id.as_u32() as usize], + &self.resources.atlas_textures[image_resource.atlas_id.as_u32() as usize], offset, writer.width(), writer.height(), @@ -509,8 +508,7 @@ /// Returns an individual image atlas texture. pub fn atlas_texture(&self, atlas_id: AtlasId) -> &WebGlTexture { - self.programs - .resources + self.resources .atlas_textures .get(atlas_id.as_u32() as usize) .map(|texture| &**texture) @@ -519,7 +517,7 @@ /// Returns the current allocation state of the image/glyph atlas texture. pub fn atlas_info(&self) -> AtlasTextureInfo { - let resources = &self.programs.resources; + let resources = &self.resources; AtlasTextureInfo { width: resources.atlas_size.0, height: resources.atlas_size.1, @@ -537,11 +535,11 @@ ) -> Result<(), WebGlError> { self.gl.bind_framebuffer( WebGl2RenderingContext::FRAMEBUFFER, - Some(&self.programs.resources.atlas_targets[atlas_id.as_u32() as usize].framebuffer), + Some(&self.resources.atlas_targets[atlas_id.as_u32() as usize].framebuffer), ); // Set viewport to match the atlas texture dimensions - let (atlas_width, atlas_height) = self.programs.resources.atlas_size; + let (atlas_width, atlas_height) = self.resources.atlas_size; self.gl .viewport(0, 0, i32::from(atlas_width), i32::from(atlas_height));
diff --git a/vello_gpu/src/render/webgl/passes/blend.rs b/vello_gpu/src/render/webgl/passes/blend.rs index 3a997c2..cacd240 100644 --- a/vello_gpu/src/render/webgl/passes/blend.rs +++ b/vello_gpu/src/render/webgl/passes/blend.rs
@@ -6,7 +6,7 @@ use crate::render::webgl::WebGlError; use crate::render::webgl::gl::resource::Program; use crate::render::webgl::passes::{ - WebGlPrograms, WebGlRendererContext, checked_instance_count, initialize_packed_u32_attribs, + WebGlRendererContext, checked_instance_count, initialize_packed_u32_attribs, required_uniform_location, }; use crate::render::webgl::resources::WebGlResources; @@ -26,11 +26,11 @@ alphas_texture: WebGlUniformLocation, } -impl WebGlPrograms { +impl WebGlResources { fn upload_blend_instances(&self, gl: &WebGl2RenderingContext, instances: &[GpuBlendInstance]) { gl.bind_buffer( WebGl2RenderingContext::ARRAY_BUFFER, - Some(&self.resources.blend_instance_buffer), + Some(&self.blend_instance_buffer), ); gl.buffer_data_with_u8_array( WebGl2RenderingContext::ARRAY_BUFFER, @@ -83,8 +83,7 @@ self.gl.disable(WebGl2RenderingContext::SCISSOR_TEST); self.gl.disable(WebGl2RenderingContext::DEPTH_TEST); self.gl.depth_mask(false); - self.gl - .bind_vertex_array(Some(&self.programs.resources.blend_vao)); + self.gl.bind_vertex_array(Some(&self.resources.blend_vao)); self.scratch_buffers.blend_instances.clear(); for blend in blends.iter() { @@ -102,13 +101,13 @@ .push(GpuBlendInstance::new(blend, None, texture_size)); } } - self.programs + self.resources .upload_blend_instances(self.gl, &self.scratch_buffers.blend_instances); let instance_count = checked_instance_count(self.scratch_buffers.blend_instances.len())?; self.gl.bind_framebuffer( WebGl2RenderingContext::FRAMEBUFFER, - Some(self.programs.resources.scratch_framebuffer()), + Some(self.resources.scratch_framebuffer()), ); self.gl.viewport( 0, @@ -121,7 +120,7 @@ self.gl.active_texture(WebGl2RenderingContext::TEXTURE2); self.gl.bind_texture( WebGl2RenderingContext::TEXTURE_2D, - Some(&self.programs.resources.alphas_texture), + Some(&self.resources.alphas_texture), ); self.gl .uniform1i(Some(&self.programs.blend_uniforms.alphas_texture), 2); @@ -130,8 +129,7 @@ self.gl.bind_texture( WebGl2RenderingContext::TEXTURE_2D, Some( - self.programs - .resources + self.resources .layer_texture(bindings.layer_id(TextureParity::Even)), ), ); @@ -142,8 +140,7 @@ self.gl.bind_texture( WebGl2RenderingContext::TEXTURE_2D, Some( - self.programs - .resources + self.resources .layer_texture(bindings.layer_id(TextureParity::Odd)), ), ); @@ -160,7 +157,7 @@ .copied() .map(GpuBlendInstance::copy_from_scratch), ); - self.programs + self.resources .upload_copy_instances(self.gl, &self.scratch_buffers.copy_instances); self.gl.disable(WebGl2RenderingContext::BLEND); @@ -169,7 +166,7 @@ self.gl.depth_mask(false); self.gl.bind_framebuffer( WebGl2RenderingContext::FRAMEBUFFER, - Some(self.programs.resources.layer_framebuffer(bindings.target())), + Some(self.resources.layer_framebuffer(bindings.target())), ); self.gl.viewport( 0, @@ -177,14 +174,13 @@ i32::from(texture_size.width()), i32::from(texture_size.height()), ); - self.gl - .bind_vertex_array(Some(&self.programs.resources.copy_vao)); + self.gl.bind_vertex_array(Some(&self.resources.copy_vao)); self.gl.use_program(Some(&self.programs.copy_program)); self.gl.active_texture(WebGl2RenderingContext::TEXTURE0); self.gl.bind_texture( WebGl2RenderingContext::TEXTURE_2D, - Some(self.programs.resources.scratch_binding_texture()), + Some(self.resources.scratch_binding_texture()), ); self.gl .uniform1i(Some(&self.programs.copy_uniforms.source_texture), 0);
diff --git a/vello_gpu/src/render/webgl/passes/clear.rs b/vello_gpu/src/render/webgl/passes/clear.rs index 0c1b85b..dfd31e0 100644 --- a/vello_gpu/src/render/webgl/passes/clear.rs +++ b/vello_gpu/src/render/webgl/passes/clear.rs
@@ -17,16 +17,16 @@ DrawPassTarget::Root(_) => { self.gl.bind_framebuffer( WebGl2RenderingContext::FRAMEBUFFER, - self.programs.resources.root_framebuffer(), + self.resources.root_framebuffer(), ); ( - self.programs.render_size.width, - self.programs.render_size.height, + self.resources.render_size.width, + self.resources.render_size.height, ) } DrawPassTarget::Layer(target) => { let size = self.texture_size(); - let framebuffer = self.programs.resources.layer_framebuffer(target); + let framebuffer = self.resources.layer_framebuffer(target); self.gl .bind_framebuffer(WebGl2RenderingContext::FRAMEBUFFER, Some(framebuffer)); (size.width(), size.height())
diff --git a/vello_gpu/src/render/webgl/passes/copy.rs b/vello_gpu/src/render/webgl/passes/copy.rs index 8436d18..b489048 100644 --- a/vello_gpu/src/render/webgl/passes/copy.rs +++ b/vello_gpu/src/render/webgl/passes/copy.rs
@@ -6,9 +6,7 @@ use crate::copy::GpuCopyInstance; use crate::render::webgl::WebGlError; use crate::render::webgl::gl::resource::Program; -use crate::render::webgl::passes::{ - WebGlPrograms, initialize_packed_u32_attribs, required_uniform_location, -}; +use crate::render::webgl::passes::{initialize_packed_u32_attribs, required_uniform_location}; use crate::render::webgl::resources::WebGlResources; use vello_gpu_shaders::copy; use web_sys::{WebGl2RenderingContext, WebGlUniformLocation}; @@ -18,7 +16,7 @@ pub(crate) source_texture: WebGlUniformLocation, } -impl WebGlPrograms { +impl WebGlResources { pub(crate) fn upload_copy_instances( &self, gl: &WebGl2RenderingContext, @@ -26,7 +24,7 @@ ) { gl.bind_buffer( WebGl2RenderingContext::ARRAY_BUFFER, - Some(&self.resources.copy_instance_buffer), + Some(&self.copy_instance_buffer), ); gl.buffer_data_with_u8_array( WebGl2RenderingContext::ARRAY_BUFFER,
diff --git a/vello_gpu/src/render/webgl/passes/filter.rs b/vello_gpu/src/render/webgl/passes/filter.rs index 4053b7a..1e3cd63 100644 --- a/vello_gpu/src/render/webgl/passes/filter.rs +++ b/vello_gpu/src/render/webgl/passes/filter.rs
@@ -6,7 +6,7 @@ use crate::render::webgl::WebGlError; use crate::render::webgl::gl::resource::Program; use crate::render::webgl::passes::{ - WebGlPrograms, WebGlRendererContext, checked_instance_count, initialize_packed_u32_attribs, + WebGlRendererContext, checked_instance_count, initialize_packed_u32_attribs, required_uniform_location, }; use crate::render::webgl::resources::{ @@ -26,14 +26,14 @@ original_texture: WebGlUniformLocation, } -impl WebGlPrograms { +impl WebGlResources { /// Grow the filter data texture if needed. pub(crate) fn maybe_resize_filter_data_tex( &mut self, gl: &WebGl2RenderingContext, filter_context: &FilterContext, ) -> Result<(), WebGlError> { - let resource_texture_dimension_2d = self.resources.resource_texture_dimension_2d; + let resource_texture_dimension_2d = self.resource_texture_dimension_2d; let Some(required_height) = filter_context.required_filter_data_height(resource_texture_dimension_2d) @@ -41,16 +41,16 @@ return Ok(()); }; - if required_height > self.resources.filter_data_texture_height { + if required_height > self.filter_data_texture_height { let required_size = (resource_texture_dimension_2d * required_height) << 4; self.filter_data.resize(required_size as usize, 0); - self.resources.filter_data_texture = create_data_texture_storage( + self.filter_data_texture = create_data_texture_storage( gl, WebGl2RenderingContext::RGBA32UI, resource_texture_dimension_2d, required_height, )?; - self.resources.filter_data_texture_height = required_height; + self.filter_data_texture_height = required_height; } Ok(()) @@ -66,7 +66,7 @@ return Ok(()); } - let width = self.resources.resource_texture_dimension_2d; + let width = self.resource_texture_dimension_2d; let used_height = filter_context .required_filter_data_height(width) .expect("non-empty filter context must have a data height"); @@ -74,7 +74,7 @@ filter_context.serialize_to_buffer(&mut self.filter_data); upload_rgba32ui_rows( gl, - &self.resources.filter_data_texture, + &self.filter_data_texture, bytemuck::cast_slice::<u8, u32>(&self.filter_data[..used_size]), width, used_height, @@ -90,7 +90,7 @@ ) { gl.bind_buffer( WebGl2RenderingContext::ARRAY_BUFFER, - Some(&self.resources.filter_instance_buffer), + Some(&self.filter_instance_buffer), ); gl.buffer_data_with_u8_array( WebGl2RenderingContext::ARRAY_BUFFER, @@ -143,17 +143,16 @@ bindings: FilterPassBindings, ) -> Result<(), WebGlError> { if let Some(copy_pass) = plan.copy_pass() { - self.programs.upload_copy_instances(self.gl, copy_pass); + self.resources.upload_copy_instances(self.gl, copy_pass); self.gl.disable(WebGl2RenderingContext::BLEND); self.gl.disable(WebGl2RenderingContext::SCISSOR_TEST); self.gl.disable(WebGl2RenderingContext::DEPTH_TEST); self.gl.depth_mask(false); - self.gl - .bind_vertex_array(Some(&self.programs.resources.copy_vao)); + self.gl.bind_vertex_array(Some(&self.resources.copy_vao)); self.gl.use_program(Some(&self.programs.copy_program)); self.gl.bind_framebuffer( WebGl2RenderingContext::FRAMEBUFFER, - Some(self.programs.resources.scratch_framebuffer()), + Some(self.resources.scratch_framebuffer()), ); let scratch_size = self.texture_size(); self.gl.viewport( @@ -165,7 +164,7 @@ self.gl.active_texture(WebGl2RenderingContext::TEXTURE0); self.gl.bind_texture( WebGl2RenderingContext::TEXTURE_2D, - Some(self.programs.resources.layer_texture(bindings.target())), + Some(self.resources.layer_texture(bindings.target())), ); self.gl .uniform1i(Some(&self.programs.copy_uniforms.source_texture), 0); @@ -173,13 +172,12 @@ } self.gl.use_program(Some(&self.programs.filter_program)); - self.gl - .bind_vertex_array(Some(&self.programs.resources.filter_vao)); + self.gl.bind_vertex_array(Some(&self.resources.filter_vao)); self.gl.active_texture(WebGl2RenderingContext::TEXTURE0); self.gl.bind_texture( WebGl2RenderingContext::TEXTURE_2D, - Some(&self.programs.resources.filter_data_texture), + Some(&self.resources.filter_data_texture), ); self.gl .uniform1i(Some(&self.programs.filter_uniforms.filter_data), 0); @@ -187,7 +185,7 @@ self.gl.active_texture(WebGl2RenderingContext::TEXTURE2); self.gl.bind_texture( WebGl2RenderingContext::TEXTURE_2D, - Some(self.programs.resources.scratch_binding_texture()), + Some(self.resources.scratch_binding_texture()), ); self.gl .uniform1i(Some(&self.programs.filter_uniforms.original_texture), 2); @@ -217,7 +215,7 @@ self.gl.depth_mask(false); self.gl.bind_framebuffer( WebGl2RenderingContext::FRAMEBUFFER, - Some(self.programs.resources.layer_framebuffer(output)), + Some(self.resources.layer_framebuffer(output)), ); let target_texture_size = self.texture_size(); self.gl.viewport( @@ -230,14 +228,14 @@ self.gl.active_texture(WebGl2RenderingContext::TEXTURE1); self.gl.bind_texture( WebGl2RenderingContext::TEXTURE_2D, - Some(self.programs.resources.layer_texture(input)), + Some(self.resources.layer_texture(input)), ); self.gl .uniform1i(Some(&self.programs.filter_uniforms.source_texture), 1); // TODO: Filter instances ideally should be uploaded once for the whole round (or even once // globally), not per pass. - self.programs.upload_filter_instances(self.gl, instances); + self.resources.upload_filter_instances(self.gl, instances); self.draw_instanced_quads(checked_instance_count(instances.len())?); Ok(())
diff --git a/vello_gpu/src/render/webgl/passes/mod.rs b/vello_gpu/src/render/webgl/passes/mod.rs index ae81fa8..120aa2d 100644 --- a/vello_gpu/src/render/webgl/passes/mod.rs +++ b/vello_gpu/src/render/webgl/passes/mod.rs
@@ -21,7 +21,7 @@ use crate::render::webgl::{WebGlError, WebGlOperation, WebGlShaderInterfaceOperation}; use crate::util::RangedSlice; use crate::{ - ClearSettings, GpuStrip, RenderSize, + ClearSettings, GpuStrip, blend::BlendStrip, filter::FilterPassPlan, render::common::ScratchBuffers, @@ -31,14 +31,11 @@ RootTarget, }, }; -use alloc::vec::Vec; use vello_common::color::AlphaColor; use vello_common::geometry::{RectU16, SizeU16}; use web_sys::{WebGl2RenderingContext, WebGlUniformLocation}; -/// Contains the WebGL programs and resources for rendering. -// TODO: Split the compiled programs from the resource state, so that `resources` no longer -// depends on `passes` and can sit underneath it. +/// Contains the compiled WebGL programs. #[derive(Debug)] pub(crate) struct WebGlPrograms { /// Program for rendering strips. @@ -59,18 +56,6 @@ pub(crate) copy_uniforms: CopyUniforms, /// Shader compilation stats. pub(crate) shader_compilation_stats: ShaderCompilationStats, - /// WebGL resources for rendering. - pub(crate) resources: WebGlResources, - /// Dimensions of the rendering target. - pub(crate) render_size: RenderSize, - /// Whether the last config buffer upload had NDC Y negation enabled. - pub(crate) negate_ndc: bool, - /// Offset of the scene within the rendering target. - pub(crate) scene_offset: (i32, i32), - /// Scratch buffer for staging encoded paints texture data. - pub(crate) encoded_paints_data: Vec<u8>, - /// Scratch buffer for staging filter data texture data. - pub(crate) filter_data: Vec<u8>, } pub(crate) fn required_uniform_location( @@ -104,7 +89,8 @@ // the GPU must finish drawing before the next `upload_strip_pair` can be executed (effectively pausing // execution). Investigate a buffer pool or creating a new buffer per pass. pub(crate) struct WebGlRendererContext<'a> { - pub(crate) programs: &'a mut WebGlPrograms, + pub(crate) programs: &'a WebGlPrograms, + pub(crate) resources: &'a mut WebGlResources, pub(crate) gl: &'a WebGl2RenderingContext, pub(crate) texture_bindings: &'a WebGlTextureBindings, pub(crate) scratch_buffers: &'a mut ScratchBuffers, @@ -131,7 +117,7 @@ } fn texture_size(&self) -> SizeU16 { - self.programs.resources.texture_size + self.resources.texture_size } }
diff --git a/vello_gpu/src/render/webgl/passes/strip.rs b/vello_gpu/src/render/webgl/passes/strip.rs index 31cc28e..132c7d7 100644 --- a/vello_gpu/src/render/webgl/passes/strip.rs +++ b/vello_gpu/src/render/webgl/passes/strip.rs
@@ -6,7 +6,7 @@ use crate::draw::{EXTERNAL_TEXTURE_SLOT_COUNT, ExternalTextureBindings, ExternalTextureRun}; use crate::render::webgl::gl::resource::Program; use crate::render::webgl::passes::{ - WebGlPrograms, WebGlRendererContext, checked_instance_count, required_uniform_location, + WebGlRendererContext, checked_instance_count, required_uniform_location, }; use crate::render::webgl::resources::{WebGlResources, create_external_sampler}; use crate::render::webgl::{WebGlError, WebGlOperation, WebGlShaderInterfaceOperation}; @@ -44,7 +44,7 @@ external_textures: [WebGlUniformLocation; EXTERNAL_TEXTURE_SLOT_COUNT], } -impl WebGlPrograms { +impl WebGlResources { /// Uploads two strip slices (opaque then alpha) into a single GPU buffer. fn upload_strip_pair( &mut self, @@ -58,7 +58,7 @@ gl.bind_buffer( WebGl2RenderingContext::ARRAY_BUFFER, - Some(&self.resources.strips_buffer), + Some(&self.strips_buffer), ); let opaque_len = size_of_val(opaque_strips); @@ -262,7 +262,7 @@ .active_texture(WebGl2RenderingContext::TEXTURE0 + texture_unit); let (texture, sampler_key): (&WebGlTexture, ExternalSampler) = match texture_source { Some(TextureSourceId::Atlas(atlas_id)) => ( - &self.programs.resources.atlas_textures[atlas_id.as_u32() as usize], + &self.resources.atlas_textures[atlas_id.as_u32() as usize], ExternalSampler::DEFAULT, ), Some(TextureSourceId::External(texture_id, sampler)) => ( @@ -274,13 +274,13 @@ sampler, ), None => ( - &self.programs.resources.placeholder_external_texture, + &self.resources.placeholder_external_texture, ExternalSampler::DEFAULT, ), }; self.gl .bind_texture(WebGl2RenderingContext::TEXTURE_2D, Some(texture)); - let sampler = match self.programs.resources.external_samplers.entry(sampler_key) { + let sampler = match self.resources.external_samplers.entry(sampler_key) { Entry::Occupied(entry) => entry.into_mut(), Entry::Vacant(entry) => { entry.insert(create_external_sampler(self.gl, sampler_key)?) @@ -325,33 +325,33 @@ DrawPassTarget::Root(_) => { self.gl.bind_framebuffer( WebGl2RenderingContext::FRAMEBUFFER, - self.programs.resources.root_framebuffer(), + self.resources.root_framebuffer(), ); - let width = self.programs.render_size.width; - let height = self.programs.render_size.height; + let width = self.resources.render_size.width; + let height = self.resources.render_size.height; self.gl.viewport(0, 0, i32::from(width), i32::from(height)); self.gl.bind_buffer_base( WebGl2RenderingContext::UNIFORM_BUFFER, self.programs.strip_uniforms.config_vs_block_index, - Some(&self.programs.resources.view_config_buffer), + Some(&self.resources.view_config_buffer), ); self.gl.bind_buffer_base( WebGl2RenderingContext::UNIFORM_BUFFER, self.programs.strip_uniforms.config_fs_block_index, - Some(&self.programs.resources.view_config_buffer), + Some(&self.resources.view_config_buffer), ); } DrawPassTarget::Layer(id) => { self.gl.bind_framebuffer( WebGl2RenderingContext::FRAMEBUFFER, - Some(self.programs.resources.layer_framebuffer(*id)), + Some(self.resources.layer_framebuffer(*id)), ); let size = self.texture_size(); self.gl .viewport(0, 0, i32::from(size.width()), i32::from(size.height())); - let buf = &self.programs.resources.layer_config_buffer; + let buf = &self.resources.layer_config_buffer; self.gl.bind_buffer_base( WebGl2RenderingContext::UNIFORM_BUFFER, self.programs.strip_uniforms.config_vs_block_index, @@ -371,14 +371,13 @@ self.gl.use_program(Some(&self.programs.strip_program)); // Set up attributes. - self.gl - .bind_vertex_array(Some(&self.programs.resources.strip_vao)); + self.gl.bind_vertex_array(Some(&self.resources.strip_vao)); // Bind textures. self.gl.active_texture(WebGl2RenderingContext::TEXTURE0); self.gl.bind_texture( WebGl2RenderingContext::TEXTURE_2D, - Some(&self.programs.resources.alphas_texture), + Some(&self.resources.alphas_texture), ); self.gl .uniform1i(Some(&self.programs.strip_uniforms.alphas_texture), 0); @@ -387,8 +386,8 @@ self.gl.bind_texture( WebGl2RenderingContext::TEXTURE_2D, Some(child_layer_texture.map_or_else( - || &self.programs.resources.placeholder_external_texture, - |id| self.programs.resources.layer_texture(id), + || &self.resources.placeholder_external_texture, + |id| self.resources.layer_texture(id), )), ); self.gl @@ -398,7 +397,7 @@ self.gl.active_texture(WebGl2RenderingContext::TEXTURE2); self.gl.bind_texture( WebGl2RenderingContext::TEXTURE_2D, - Some(&self.programs.resources.encoded_paints_texture), + Some(&self.resources.encoded_paints_texture), ); self.gl.uniform1i( Some(&self.programs.strip_uniforms.encoded_paints_texture_fs), @@ -413,7 +412,7 @@ self.gl.active_texture(WebGl2RenderingContext::TEXTURE3); self.gl.bind_texture( WebGl2RenderingContext::TEXTURE_2D, - Some(&self.programs.resources.gradient_texture), + Some(&self.resources.gradient_texture), ); self.gl .uniform1i(Some(&self.programs.strip_uniforms.gradient_texture), 3); @@ -439,7 +438,7 @@ // that possibility in the future. let enable_opaque = self.use_depth_buffer && target.enable_opaque(); - self.programs + self.resources .upload_strip_pair(self.gl, opaque_strips, alpha_strips); let opaque_count = checked_instance_count(opaque_count)?; let alpha_count = checked_instance_count(alpha_count)?; @@ -450,8 +449,8 @@ self.gl.depth_func(WebGl2RenderingContext::LEQUAL); // Clear depth buffer on first use per frame. - if !self.programs.resources.depth_cleared_this_frame { - self.programs.resources.depth_cleared_this_frame = true; + if !self.resources.depth_cleared_this_frame { + self.resources.depth_cleared_this_frame = true; self.gl.clear_depth(1.0); self.gl.clear(WebGl2RenderingContext::DEPTH_BUFFER_BIT); }
diff --git a/vello_gpu/src/render/webgl/probe.rs b/vello_gpu/src/render/webgl/probe.rs index 2bf2e89..ea6a5b5 100644 --- a/vello_gpu/src/render/webgl/probe.rs +++ b/vello_gpu/src/render/webgl/probe.rs
@@ -86,7 +86,7 @@ let render_size = RenderSize { width, height }; // Check whether the canvas framebuffer was configured by the user to // hold a depth buffer, and apply the same to the probe. - let use_depth_buffer = self.programs.resources.drawing_buffer_uses_depth_buffer; + let use_depth_buffer = self.resources.drawing_buffer_uses_depth_buffer; let probe_texture = create_texture_storage( &self.gl,
diff --git a/vello_gpu/src/render/webgl/resources.rs b/vello_gpu/src/render/webgl/resources.rs index c6d3306..cf5235c 100644 --- a/vello_gpu/src/render/webgl/resources.rs +++ b/vello_gpu/src/render/webgl/resources.rs
@@ -4,7 +4,6 @@ //! Creation and growth of the renderer's GPU resources. use crate::render::webgl::gl::resource::{Buffer, Framebuffer, Sampler, Texture, VertexArray}; -use crate::render::webgl::passes::WebGlPrograms; use crate::render::webgl::target::{WebGlTextureTarget, create_framebuffer_for_texture}; use crate::render::webgl::{ WebGlDataTransferOperation, WebGlError, WebGlOperation, WebGlResultExt, @@ -21,6 +20,7 @@ schedule::Schedule, target::{DrawPassTarget, LayerTextureId, RootTarget}, }; +use alloc::vec; use alloc::vec::Vec; use hashbrown::HashMap; use vello_common::image_cache::ImageCache; @@ -101,6 +101,16 @@ pub(crate) layer_config_buffer: Buffer, /// Layer texture pages grouped by parity. pub(crate) layer_textures: [Vec<WebGlIntermediateTexture>; 2], + /// Dimensions of the rendering target. + pub(crate) render_size: RenderSize, + /// Whether the last config buffer upload had NDC Y negation enabled. + pub(crate) negate_ndc: bool, + /// Offset of the scene within the rendering target. + pub(crate) scene_offset: (i32, i32), + /// Scratch buffer for staging encoded paints texture data. + pub(crate) encoded_paints_data: Vec<u8>, + /// Scratch buffer for staging filter data texture data. + pub(crate) filter_data: Vec<u8>, } impl WebGlResources { @@ -157,7 +167,7 @@ } } -impl WebGlPrograms { +impl WebGlResources { /// Prepare resources for rendering. pub(crate) fn prepare( &mut self, @@ -171,7 +181,7 @@ filter_context: &FilterContext, root_target: RootTarget, ) -> Result<(), WebGlError> { - let resource_texture_dimension_2d = self.resources.resource_texture_dimension_2d; + let resource_texture_dimension_2d = self.resource_texture_dimension_2d; self.maybe_resize_alphas_tex(gl, resource_texture_dimension_2d, alphas.len())?; self.maybe_resize_encoded_paints_tex(gl, resource_texture_dimension_2d, paint_idxs)?; @@ -203,7 +213,7 @@ gl: &WebGl2RenderingContext, schedule: &Schedule, ) -> Result<(), WebGlError> { - let current_size = self.resources.texture_size; + let current_size = self.texture_size; let requirements = schedule.intermediate_texture_requirements(); let texture_size = requirements.size; let allocations = requirements.allocations; @@ -214,13 +224,13 @@ if size_changed { upload_layer_config_buffer( gl, - &self.resources.layer_config_buffer, + &self.layer_config_buffer, texture_size, - self.resources.resource_texture_dimension_2d, + self.resource_texture_dimension_2d, ); } - for (index, textures) in self.resources.layer_textures.iter_mut().enumerate() { + for (index, textures) in self.layer_textures.iter_mut().enumerate() { let required_page_count = layer_pages[index]; // When resizing textures, we explicitly first destroy the old textures before creating @@ -244,19 +254,20 @@ } } - let recreate_scratch = (self.resources.scratch_texture.is_some() && size_changed) - || (self.resources.scratch_texture.is_none() && scratch_required); + let recreate_scratch = (self.scratch_texture.is_some() && size_changed) + || (self.scratch_texture.is_none() && scratch_required); if recreate_scratch { // Make sure the old texture is destroyed first. - let _ = self.resources.scratch_texture.take(); + let _ = self.scratch_texture.take(); - self.resources.scratch_texture = Some(ScratchTexture::new( - create_intermediate_texture(gl, texture_size)?, - )); + self.scratch_texture = Some(ScratchTexture::new(create_intermediate_texture( + gl, + texture_size, + )?)); } - self.resources.texture_size = texture_size; + self.texture_size = texture_size; Ok(()) } @@ -267,13 +278,12 @@ gl: &WebGl2RenderingContext, required_atlas_count: u32, ) -> Result<(), WebGlError> { - let (width, height) = self.resources.atlas_size; - while self.resources.atlas_textures.len() < required_atlas_count as usize { + let (width, height) = self.atlas_size; + while self.atlas_textures.len() < required_atlas_count as usize { let texture = create_atlas_texture(gl, width, height)?; - self.resources - .atlas_targets + self.atlas_targets .push(WebGlTextureTarget::for_atlas(gl, &texture, width, height)?); - self.resources.atlas_textures.push(texture); + self.atlas_textures.push(texture); } Ok(()) @@ -290,7 +300,7 @@ // There are 16 1-byte alpha values per texel. .div_ceil(resource_texture_dimension_2d << 4); - let current_alpha_height = self.resources.alpha_texture_height; + let current_alpha_height = self.alpha_texture_height; if required_alpha_height > current_alpha_height { validate_resource_texture_size( resource_texture_dimension_2d, @@ -299,13 +309,13 @@ )?; // We need to resize the alpha texture to fit the new alpha data. - self.resources.alphas_texture = create_data_texture_storage( + self.alphas_texture = create_data_texture_storage( gl, WebGl2RenderingContext::RGBA32UI, resource_texture_dimension_2d, required_alpha_height, )?; - self.resources.alpha_texture_height = required_alpha_height; + self.alpha_texture_height = required_alpha_height; } Ok(()) @@ -321,7 +331,7 @@ let required_texels = paint_idxs.last().unwrap(); let required_encoded_paints_height = required_texels.div_ceil(resource_texture_dimension_2d); - let current_encoded_paints_height = self.resources.encoded_paints_texture_height; + let current_encoded_paints_height = self.encoded_paints_texture_height; if required_encoded_paints_height > current_encoded_paints_height { validate_resource_texture_size( resource_texture_dimension_2d, @@ -333,13 +343,13 @@ (resource_texture_dimension_2d * required_encoded_paints_height) << 4; self.encoded_paints_data .resize(required_encoded_paints_size as usize, 0); - self.resources.encoded_paints_texture = create_data_texture_storage( + self.encoded_paints_texture = create_data_texture_storage( gl, WebGl2RenderingContext::RGBA32UI, resource_texture_dimension_2d, required_encoded_paints_height, )?; - self.resources.encoded_paints_texture_height = required_encoded_paints_height; + self.encoded_paints_texture_height = required_encoded_paints_height; } Ok(()) @@ -361,7 +371,7 @@ let required_gradient_height = (gradient_data_size as u32).div_ceil(resource_texture_dimension_2d * 4); - let current_gradient_height = self.resources.gradient_texture_height; + let current_gradient_height = self.gradient_texture_height; if required_gradient_height > current_gradient_height { validate_resource_texture_size( resource_texture_dimension_2d, @@ -369,13 +379,13 @@ resource_texture_dimension_2d, )?; - self.resources.gradient_texture = create_data_texture_storage( + self.gradient_texture = create_data_texture_storage( gl, WebGl2RenderingContext::RGBA8, resource_texture_dimension_2d, required_gradient_height, )?; - self.resources.gradient_texture_height = required_gradient_height; + self.gradient_texture_height = required_gradient_height; } Ok(()) @@ -410,7 +420,7 @@ gl.bind_buffer( WebGl2RenderingContext::UNIFORM_BUFFER, - Some(&self.resources.view_config_buffer), + Some(&self.view_config_buffer), ); gl.buffer_data_with_u8_array( WebGl2RenderingContext::UNIFORM_BUFFER, @@ -434,7 +444,7 @@ return Ok(()); } - let alpha_texture_width = self.resources.resource_texture_dimension_2d; + let alpha_texture_width = self.resource_texture_dimension_2d; // There are 16 1-byte alpha values per texel. let used_height = (alphas.len() as u32).div_ceil(alpha_texture_width << 4); let used_size = (alpha_texture_width as usize) * (used_height as usize) * 16; @@ -446,7 +456,7 @@ let result = upload_rgba32ui_rows( gl, - &self.resources.alphas_texture, + &self.alphas_texture, bytemuck::cast_slice::<u8, u32>(alphas), alpha_texture_width, used_height, @@ -466,7 +476,7 @@ paint_idxs: &[u32], ) -> Result<(), WebGlError> { if !encoded_paints.is_empty() { - let encoded_paints_texture_width = self.resources.resource_texture_dimension_2d; + let encoded_paints_texture_width = self.resource_texture_dimension_2d; let used_texels = *paint_idxs.last().unwrap(); let used_height = used_texels.div_ceil(encoded_paints_texture_width); let used_size = ((encoded_paints_texture_width * used_height) << 4) as usize; @@ -475,7 +485,7 @@ upload_rgba32ui_rows( gl, - &self.resources.encoded_paints_texture, + &self.encoded_paints_texture, bytemuck::cast_slice::<u8, u32>(&self.encoded_paints_data[..used_size]), encoded_paints_texture_width, used_height, @@ -495,7 +505,7 @@ return Ok(()); } - let gradient_texture_width = self.resources.resource_texture_dimension_2d; + let gradient_texture_width = self.resource_texture_dimension_2d; // Each texel is RGBA8, so 4 bytes per texel. Only the rows covering the LUT cache are // uploaded; see `upload_alpha_texture`. let used_height = (gradient_cache.luts_size() as u32).div_ceil(gradient_texture_width * 4); @@ -509,7 +519,7 @@ gl.active_texture(WebGl2RenderingContext::TEXTURE0); gl.bind_texture( WebGl2RenderingContext::TEXTURE_2D, - Some(&self.resources.gradient_texture), + Some(&self.gradient_texture), ); let result = gl @@ -838,6 +848,14 @@ scratch_texture, layer_config_buffer, layer_textures, + render_size: RenderSize { + width: 0, + height: 0, + }, + negate_ndc: false, + scene_offset: (0, 0), + encoded_paints_data: vec![0; (resource_texture_dimension_2d << 4) as usize], + filter_data: Vec::new(), }) }