From 3bf199647a2f9fdb705d5a5229a490ed93848c0a Mon Sep 17 00:00:00 2001 From: Zakor Gyula Date: Fri, 10 Jan 2020 16:07:18 +0100 Subject: [PATCH 1/6] Remove push constants --- webrender/build_gfx.rs | 20 +-------- webrender/res/base.glsl | 2 - webrender/res/base_gfx.glsl | 1 - webrender/src/device/gfx/device.rs | 69 ++++++----------------------- webrender/src/device/gfx/program.rs | 37 +++------------- 5 files changed, 20 insertions(+), 109 deletions(-) diff --git a/webrender/build_gfx.rs b/webrender/build_gfx.rs index f18136985f..98da75905b 100644 --- a/webrender/build_gfx.rs +++ b/webrender/build_gfx.rs @@ -255,17 +255,7 @@ fn process_glsl_for_spirv(file_path: &Path, file_name: &str) -> Option { cache_path: Option, save_cache: bool, - // The device supports push constants - pub use_push_consts: bool, swizzle_settings: SwizzleSettings, color_formats: TextureFormatPair, optimal_pbo_stride: NonZeroUsize, @@ -381,7 +379,7 @@ impl Device { descriptor_count, cache_path, save_cache, - backend_api, + backend_api: _backend_api, } = init; let renderer_name = "TODO renderer name".to_owned(); let features = adapter.physical_device.features(); @@ -464,12 +462,6 @@ impl Device { let render_passes = HalRenderPasses::create_render_passes(&device, SURFACE_FORMAT, DEPTH_FORMAT); - // Disable push constants for Intel's Vulkan driver on Windows - let has_broken_push_const_support = cfg!(target_os = "windows") - && backend_api == BackendApiType::Vulkan - && adapter.info.vendor == 0x8086; - let use_push_consts = !has_broken_push_const_support; - let (frame_depth, surface_format, dimensions, frame_count) = Self::init_drawables(&device, &mut heaps, &adapter, surface.as_mut(), dimensions); @@ -654,10 +646,7 @@ impl Device { let pipeline_layout = unsafe { device.create_pipeline_layout( &set_layouts, - Some(( - hal::pso::ShaderStageFlags::VERTEX | hal::pso::ShaderStageFlags::FRAGMENT, - 0..PUSH_CONSTANT_BLOCK_SIZE as u32, - )), + &[], ) } .expect("create_pipeline_layout failed"); @@ -700,11 +689,7 @@ impl Device { &descriptor_data, &DescriptorGroup::Default, DESCRIPTOR_SET_LOCALS, - if use_push_consts { - 1 - } else { - descriptor_count.unwrap_or(DESCRIPTOR_COUNT) - }, + descriptor_count.unwrap_or(DESCRIPTOR_COUNT), Vec::new(), ); @@ -821,7 +806,6 @@ impl Device { download_buffer: None, instance_buffer_range: 0..0, - use_push_consts, swizzle_settings: SwizzleSettings { bgra8_sampling_swizzle: Swizzle::Rgba, }, @@ -850,9 +834,6 @@ impl Device { } device.inside_frame = false; } - if device.use_push_consts { - device.bind_uniforms(Locals::default()); - } device } @@ -1024,14 +1005,12 @@ impl Device { } Self::reset(&mut self.bound_per_group_textures, &mut self.per_group_descriptors); - if !self.use_push_consts { - Self::push_back_and_reset( - &mut self.bound_locals_descriptor, - None, - &mut self.bound_locals, - &mut self.locals_descriptors, - ); - } + Self::push_back_and_reset( + &mut self.bound_locals_descriptor, + None, + &mut self.bound_locals, + &mut self.locals_descriptors, + ); self.locals_buffer.reset(); @@ -1276,7 +1255,6 @@ impl Device { &mut self.shader_modules, self.pipeline_cache.as_ref(), self.surface_format, - self.use_push_consts, ) } @@ -1334,18 +1312,6 @@ impl Device { } } - fn update_push_constants(&mut self) { - if self.use_push_consts { - self.programs - .get_mut(&self.bound_program) - .expect("Invalid bound program") - .constants[..] - .copy_from_slice(unsafe { - std::mem::transmute::<_, &[u32; 17]>(&self.bound_locals) - }); - } - } - fn bind_uniforms(&mut self, locals: Locals) { let descriptor = self.locals_descriptors.bind_locals( locals, @@ -1373,9 +1339,7 @@ impl Device { if self.bound_locals.uTransform != projection { let mut new_locals = self.bound_locals; new_locals.uTransform = projection; - if !self.use_push_consts { - self.bind_uniforms(new_locals); - } + self.bind_uniforms(new_locals); self.bound_locals = new_locals; } } @@ -1583,7 +1547,6 @@ impl Device { fn draw(&mut self) { assert!(self.inside_render_pass); - self.update_push_constants(); assert_eq!(self.draw_target_usage, DrawTargetUsage::Draw); let descriptor_group = self @@ -1611,10 +1574,9 @@ impl Device { self.bound_per_draw_descriptor.as_ref().unwrap().raw(), desc_set_per_pass, desc_set_per_group, - self.bound_locals_descriptor.as_ref().map(|d| d.raw()), + self.bound_locals_descriptor.as_ref().unwrap().raw(), self.next_id, self.descriptor_data.pipeline_layout(&descriptor_group), - self.use_push_consts, &self.quad_buffer, &self.instance_buffers[self.next_id], self.instance_buffer_range.clone(), @@ -2485,10 +2447,9 @@ impl Device { descriptor.raw(), None, desc_set_per_group, - self.bound_locals_descriptor.as_ref().map(|d| d.raw()), + self.bound_locals_descriptor.as_ref().unwrap().raw(), self.next_id, self.descriptor_data.pipeline_layout(&descriptor_group), - self.use_push_consts, &self.quad_buffer, &self.instance_buffers[self.next_id], self.instance_buffer_range.clone(), @@ -2792,9 +2753,7 @@ impl Device { } let mut new_locals = self.bound_locals; new_locals.uMode = mode; - if !self.use_push_consts { - self.bind_uniforms(new_locals); - } + self.bind_uniforms(new_locals); self.bound_locals = new_locals; } diff --git a/webrender/src/device/gfx/program.rs b/webrender/src/device/gfx/program.rs index 176770f6fd..d7a5ecd06d 100644 --- a/webrender/src/device/gfx/program.rs +++ b/webrender/src/device/gfx/program.rs @@ -17,10 +17,8 @@ use super::super::{ShaderKind, VertexArrayKind}; use super::super::super::shader_source; const ENTRY_NAME: &str = "main"; -// The size of the push constant block is 68 bytes, and we upload it with u32 data (4 bytes). -pub(super) const PUSH_CONSTANT_BLOCK_SIZE: usize = 68; // 68 / 4 - // The number of specialization constants in each shader. -const SPECIALIZATION_CONSTANT_COUNT: usize = 8; +// The number of specialization constants in each shader. +const SPECIALIZATION_CONSTANT_COUNT: usize = 7; // Size of a specialization constant variable in bytes. const SPECIALIZATION_CONSTANT_SIZE: usize = 4; const SPECIALIZATION_FEATURES: &'static [&'static str] = &[ @@ -52,7 +50,6 @@ pub(crate) struct Program { pub(super) index_buffer: Option; 1]>>, pub(super) shader_name: String, pub(super) shader_kind: ShaderKind, - pub(super) constants: [u32; PUSH_CONSTANT_BLOCK_SIZE / 4], last_frame_used: usize, } @@ -71,7 +68,6 @@ impl Program { shader_modules: &mut FastHashMap, pipeline_cache: Option<&B::PipelineCache>, surface_format: ImageFormat, - use_push_consts: bool, ) -> Program { if !shader_modules.contains_key(shader_name) { let vs_file = format!("{}.vert.spv", shader_name); @@ -100,7 +96,7 @@ impl Program { let mut specialization_data = vec![0; (SPECIALIZATION_CONSTANT_COUNT - 1) * SPECIALIZATION_CONSTANT_SIZE]; - let mut constants = SPECIALIZATION_FEATURES + let constants = SPECIALIZATION_FEATURES .iter() .zip(specialization_data.chunks_mut(SPECIALIZATION_CONSTANT_SIZE)) .enumerate() @@ -113,15 +109,6 @@ impl Program { } }) .collect::>(); - constants.push(hal::pso::SpecializationConstant { - id: (SPECIALIZATION_CONSTANT_COUNT - 1) as _, - range: { - let from = (SPECIALIZATION_CONSTANT_COUNT - 1) * SPECIALIZATION_CONSTANT_SIZE; - let to = from + SPECIALIZATION_CONSTANT_SIZE; - from as _..to as _ - }, - }); - specialization_data.extend_from_slice(&[use_push_consts as u8, 0, 0, 0]); let pipelines = { let (vs_entry, fs_entry) = ( @@ -601,7 +588,6 @@ impl Program { index_buffer, shader_name: String::from(shader_name), shader_kind, - constants: [0; PUSH_CONSTANT_BLOCK_SIZE / 4], last_frame_used: 0, } } @@ -612,10 +598,9 @@ impl Program { desc_set_per_draw: &B::DescriptorSet, desc_set_per_pass: Option<&B::DescriptorSet>, desc_set_per_frame: &B::DescriptorSet, - desc_set_locals: Option<&B::DescriptorSet>, + desc_set_locals: &B::DescriptorSet, next_id: usize, pipeline_layout: &B::PipelineLayout, - use_push_consts: bool, vertex_buffer: &VertexBufferHandler, instance_buffer: &InstanceBufferHandler, instance_buffer_range: std::ops::Range, @@ -632,18 +617,6 @@ impl Program { None => vertex_buffer, }; unsafe { - if use_push_consts { - cmd_buffer.push_graphics_constants( - pipeline_layout, - hal::pso::ShaderStageFlags::VERTEX | hal::pso::ShaderStageFlags::FRAGMENT, - 0, - &self.constants, - ); - } - - if !use_push_consts { - assert!(desc_set_locals.is_some()); - } use std::iter; cmd_buffer.bind_graphics_descriptor_sets( pipeline_layout, @@ -652,7 +625,7 @@ impl Program { .into_iter() .chain(iter::once(desc_set_per_frame)) .chain(iter::once(desc_set_per_draw)) - .chain(desc_set_locals), + .chain(iter::once(desc_set_locals)), &[], ); From 2f7e202b718e186655f11178a857693ef853b723 Mon Sep 17 00:00:00 2001 From: Gyula Zakor Date: Sun, 12 Jan 2020 19:47:00 +0100 Subject: [PATCH 2/6] Bake uMode into pipeline --- webrender/build_gfx.rs | 1 - webrender/res/base_gfx.glsl | 1 + webrender/src/device/gfx/descriptor.rs | 4 +- webrender/src/device/gfx/device.rs | 11 +-- webrender/src/device/gfx/program.rs | 129 ++++++++++++++++--------- 5 files changed, 87 insertions(+), 59 deletions(-) diff --git a/webrender/build_gfx.rs b/webrender/build_gfx.rs index 98da75905b..5ae4a8421c 100644 --- a/webrender/build_gfx.rs +++ b/webrender/build_gfx.rs @@ -336,7 +336,6 @@ fn replace_non_sampler_uniforms(new_data: &mut String) { \t\tuniform mat4 uTransform; // Orthographic projection\n\ \t\t// A generic uniform that shaders can optionally use to configure\n\ \t\t// an operation mode for this batch.\n\ - \t\tuniform int uMode;\n\ \t}};\n", DESCRIPTOR_SET_LOCALS )); diff --git a/webrender/res/base_gfx.glsl b/webrender/res/base_gfx.glsl index 211e54fcc5..4c465fb80e 100644 --- a/webrender/res/base_gfx.glsl +++ b/webrender/res/base_gfx.glsl @@ -9,6 +9,7 @@ layout(constant_id = 3) const bool dithering = false; layout(constant_id = 4) const bool debug_overdraw = false; layout(constant_id = 5) const bool repetition = false; layout(constant_id = 6) const bool antialiasing = false; +layout(constant_id = 7) const int uMode = 0; #if defined(GL_ES) #if GL_ES == 1 diff --git a/webrender/src/device/gfx/descriptor.rs b/webrender/src/device/gfx/descriptor.rs index fda1cc0601..82fbdef24e 100644 --- a/webrender/src/device/gfx/descriptor.rs +++ b/webrender/src/device/gfx/descriptor.rs @@ -140,7 +140,6 @@ impl From for DescriptorGroup { #[allow(non_snake_case)] pub(super) struct Locals { pub(super) uTransform: [[f32; 4]; 4], - pub(super) uMode: i32, } impl Locals { @@ -152,13 +151,12 @@ impl Locals { impl Hash for Locals { fn hash(&self, state: &mut H) { self.transform_as_u32_slice().hash(state); - self.uMode.hash(state); } } impl PartialEq for Locals { fn eq(&self, other: &Locals) -> bool { - self.uTransform == other.uTransform && self.uMode == other.uMode + self.uTransform == other.uTransform } } diff --git a/webrender/src/device/gfx/device.rs b/webrender/src/device/gfx/device.rs index 4f694caf69..7a8059367d 100644 --- a/webrender/src/device/gfx/device.rs +++ b/webrender/src/device/gfx/device.rs @@ -1591,8 +1591,6 @@ impl Device { self.shader_is_ready = false; } self.reset_state(); - self.switch_mode(0); - self.frame_id } @@ -2746,15 +2744,8 @@ impl Device { external.id = 0; } - pub fn switch_mode(&mut self, mode: i32) { + pub fn switch_mode(&mut self, _mode: i32) { debug_assert!(self.inside_frame); - if self.bound_locals.uMode == mode { - return; - } - let mut new_locals = self.bound_locals; - new_locals.uMode = mode; - self.bind_uniforms(new_locals); - self.bound_locals = new_locals; } pub fn create_pbo(&mut self) -> PBO { diff --git a/webrender/src/device/gfx/program.rs b/webrender/src/device/gfx/program.rs index d7a5ecd06d..1100315144 100644 --- a/webrender/src/device/gfx/program.rs +++ b/webrender/src/device/gfx/program.rs @@ -3,6 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use api::ImageFormat; +use arrayvec::ArrayVec; use hal::{self, device::Device as BackendDevice}; use hal::command::CommandBuffer; use crate::internal_types::FastHashMap; @@ -18,7 +19,7 @@ use super::super::super::shader_source; const ENTRY_NAME: &str = "main"; // The number of specialization constants in each shader. -const SPECIALIZATION_CONSTANT_COUNT: usize = 7; +const SPECIALIZATION_CONSTANT_COUNT: usize = 8; // Size of a specialization constant variable in bytes. const SPECIALIZATION_CONSTANT_SIZE: usize = 4; const SPECIALIZATION_FEATURES: &'static [&'static str] = &[ @@ -69,6 +70,11 @@ impl Program { pipeline_cache: Option<&B::PipelineCache>, surface_format: ImageFormat, ) -> Program { + use hal::pso::{BlendState, EntryPoint, GraphicsShaderSet, Specialization, SpecializationConstant}; + use super::blend_state::*; + use super::{LESS_EQUAL_TEST, LESS_EQUAL_WRITE}; + use self::RenderPassDepthState as RPDS; + if !shader_modules.contains_key(shader_name) { let vs_file = format!("{}.vert.spv", shader_name); let vs_module = unsafe { @@ -94,54 +100,82 @@ impl Program { let (vs_module, fs_module) = shader_modules.get(shader_name).unwrap(); - let mut specialization_data = - vec![0; (SPECIALIZATION_CONSTANT_COUNT - 1) * SPECIALIZATION_CONSTANT_SIZE]; - let constants = SPECIALIZATION_FEATURES - .iter() - .zip(specialization_data.chunks_mut(SPECIALIZATION_CONSTANT_SIZE)) + let mut specialization_data = vec![]; + let program_modes = if let ShaderKind::Text = shader_kind { + // 0 default uMode + // 3 uMode for ShaderColorMode::SubpixelWithBgColorPass0 + // 4 uMode for ShaderColorMode::SubpixelWithBgColorPass1 + // 5 uMode for ShaderColorMode::SubpixelWithBgColorPass2 + [0, 3, 4, 5].into_iter() + } else { + [0].into_iter() + }; + let constant_setups: ArrayVec<[ArrayVec<[_; SPECIALIZATION_CONSTANT_COUNT]>; 4]> = + program_modes .enumerate() - .map(|(i, (feature, out_data))| { - out_data[0] = features.contains(feature) as u8; - hal::pso::SpecializationConstant { - id: i as _, - range: (SPECIALIZATION_CONSTANT_SIZE * i) as _ - ..(SPECIALIZATION_CONSTANT_SIZE * (i + 1)) as _, + .map(|(i, mode)| { + specialization_data.push(vec![0; (SPECIALIZATION_CONSTANT_COUNT - 1) * SPECIALIZATION_CONSTANT_SIZE]); + let mut constants: ArrayVec<[_; SPECIALIZATION_CONSTANT_COUNT]> = SPECIALIZATION_FEATURES + .iter() + .zip(specialization_data[i].chunks_mut(SPECIALIZATION_CONSTANT_SIZE)) + .enumerate() + .map(|(j, (feature, out_data))| { + out_data[0] = features.contains(feature) as u8; + SpecializationConstant { + id: j as _, + range: (SPECIALIZATION_CONSTANT_SIZE * j) as _ + ..(SPECIALIZATION_CONSTANT_SIZE * (j + 1)) as _, + } + }) + .collect(); + if *mode != 0 { + constants.push(SpecializationConstant { + id: (SPECIALIZATION_CONSTANT_COUNT - 1) as _, + range: { + let from = (SPECIALIZATION_CONSTANT_COUNT - 1) * SPECIALIZATION_CONSTANT_SIZE; + let to = from + SPECIALIZATION_CONSTANT_SIZE; + from as _..to as _ + }, + }); + specialization_data[i].extend_from_slice(&[*mode as u8, 0, 0, 0]); } - }) - .collect::>(); + constants + }).collect(); let pipelines = { - let (vs_entry, fs_entry) = ( - hal::pso::EntryPoint:: { - entry: ENTRY_NAME, - module: &vs_module, - specialization: hal::pso::Specialization { - constants: Borrowed(&constants), - data: Borrowed(&specialization_data.as_slice()), - }, - }, - hal::pso::EntryPoint:: { - entry: ENTRY_NAME, - module: &fs_module, - specialization: hal::pso::Specialization { - constants: Borrowed(&constants), - data: Borrowed(&specialization_data.as_slice()), - }, - }, - ); - - let shader_entries = hal::pso::GraphicsShaderSet { - vertex: vs_entry, - hull: None, - domain: None, - geometry: None, - fragment: Some(fs_entry), - }; + let shader_entries: ArrayVec<[GraphicsShaderSet; 4]> = + constant_setups + .iter() + .zip(specialization_data.iter()) + .map(|(constants, spec_data)| { + let (vs_entry, fs_entry) = ( + EntryPoint:: { + entry: ENTRY_NAME, + module: &vs_module, + specialization: Specialization { + constants: Borrowed(&constants), + data: Borrowed(&spec_data.as_slice()), + }, + }, + EntryPoint:: { + entry: ENTRY_NAME, + module: &fs_module, + specialization: Specialization { + constants: Borrowed(&constants), + data: Borrowed(&spec_data.as_slice()), + }, + }, + ); - use hal::pso::{BlendState}; - use super::blend_state::*; - use super::{LESS_EQUAL_TEST, LESS_EQUAL_WRITE}; - use self::RenderPassDepthState as RPDS; + GraphicsShaderSet { + vertex: vs_entry, + hull: None, + domain: None, + geometry: None, + fragment: Some(fs_entry), + } + }) + .collect(); let pipeline_states = match shader_kind { ShaderKind::Cache(VertexArrayKind::Gradient) => { @@ -497,7 +531,12 @@ impl Program { main_pass: render_passes.render_pass(format, depth_enabled, false), }; let mut pipeline_descriptor = hal::pso::GraphicsPipelineDesc::new( - shader_entries.clone(), + match blend_state { + Some(SUBPIXEL_WITH_BG_COLOR_PASS0) => shader_entries[1].clone(), + Some(SUBPIXEL_WITH_BG_COLOR_PASS1) => shader_entries[2].clone(), + Some(SUBPIXEL_WITH_BG_COLOR_PASS2) => shader_entries[3].clone(), + _ => shader_entries[0].clone(), + }, hal::pso::Primitive::TriangleList, hal::pso::Rasterizer::FILL, &pipeline_layout, From c4376915ceb3a8f528155ac15f7dbbdee68d2bfa Mon Sep 17 00:00:00 2001 From: Zakor Gyula Date: Sat, 21 Dec 2019 20:17:29 +0100 Subject: [PATCH 3/6] Fix texture delete in Device::deinit --- webrender/src/device/gfx/device.rs | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/webrender/src/device/gfx/device.rs b/webrender/src/device/gfx/device.rs index 7a8059367d..6e055d45ea 100644 --- a/webrender/src/device/gfx/device.rs +++ b/webrender/src/device/gfx/device.rs @@ -2676,12 +2676,7 @@ impl Device { } } - fn free_texture(&mut self, mut texture: Texture) { - if texture.still_in_flight(self.frame_id, self.frame_count) { - self.retained_textures.push(texture); - return; - } - + fn free_texture_unconditionaly(&mut self, mut texture: Texture) { if texture.supports_depth() { self.release_depth_target(texture.get_dimensions()); } @@ -2718,6 +2713,14 @@ impl Device { texture.id = 0; } + fn free_texture(&mut self, texture: Texture) { + if texture.still_in_flight(self.frame_id, self.frame_count) { + self.retained_textures.push(texture); + return; + } + self.free_texture_unconditionaly(texture); + } + fn delete_retained_textures(&mut self) { let textures: SmallVec<[Texture; 16]> = self.retained_textures.drain(..).collect(); for texture in textures { @@ -2725,9 +2728,9 @@ impl Device { } } - pub fn delete_texture(&mut self, texture: Texture) { - //debug_assert!(self.inside_frame); - if texture.size.width + texture.size.height == 0 { + pub fn delete_texture(&mut self, mut texture: Texture) { + if texture.size_in_bytes() == 0 { + texture.id = 0; return; } @@ -3705,10 +3708,10 @@ impl Device { pub fn deinit(mut self) { self.device.wait_idle().unwrap(); for texture in self.retained_textures.drain(..).collect::>() { - self.free_texture(texture); + self.free_texture_unconditionaly(texture); } for texture in self.readback_textures.drain(..).collect::>() { - self.free_texture(texture); + self.free_texture_unconditionaly(texture); } unsafe { if self.save_cache && self.cache_path.is_some() { From 7b49d04dd5e8a427a073d79fbb2f06af017859c4 Mon Sep 17 00:00:00 2001 From: Zakor Gyula Date: Wed, 15 Jan 2020 15:38:54 +0100 Subject: [PATCH 4/6] Remove tracking projection in descriptors --- webrender/src/device/gfx/buffer.rs | 66 +++++--- webrender/src/device/gfx/descriptor.rs | 211 ++++++++++++++++--------- webrender/src/device/gfx/device.rs | 85 ++++------ webrender/src/device/gfx/mod.rs | 3 + 4 files changed, 208 insertions(+), 157 deletions(-) diff --git a/webrender/src/device/gfx/buffer.rs b/webrender/src/device/gfx/buffer.rs index 0dea021ed8..64e336d278 100644 --- a/webrender/src/device/gfx/buffer.rs +++ b/webrender/src/device/gfx/buffer.rs @@ -2,6 +2,7 @@ * 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/. */ +use arrayvec::ArrayVec; use hal; use hal::device::Device as BackendDevice; use rendy_memory::{Block, Heaps, Kind, MappedRange, MemoryBlock, MemoryUsage, MemoryUsageValue, Write}; @@ -10,6 +11,8 @@ use std::cell::Cell; use std::sync::Arc; use std::mem; +use super::{MAX_FRAME_COUNT, PROJECTION_PER_FRAME}; + pub const DOWNLOAD_BUFFER_SIZE: usize = 10 << 20; // 10MB #[derive(MallocSizeOf)] @@ -704,10 +707,9 @@ impl VertexBufferHandler { } pub(super) struct UniformBufferHandler { - buffers: Vec>, - offset: usize, - buffer_usage: hal::buffer::Usage, - data_stride: usize, + buffers: ArrayVec<[Buffer; MAX_FRAME_COUNT]>, + offsets: ArrayVec<[usize; MAX_FRAME_COUNT]>, + last_update_size: usize, pitch_alignment_mask: usize, } @@ -716,38 +718,50 @@ impl UniformBufferHandler { buffer_usage: hal::buffer::Usage, data_stride: usize, pitch_alignment_mask: usize, + frame_count: usize, + device: &B::Device, + heaps: &mut Heaps ) -> Self { - UniformBufferHandler { - buffers: vec![], - offset: 0, - buffer_usage, - data_stride, - pitch_alignment_mask, - } - } - - pub(super) fn add(&mut self, device: &B::Device, data: &[T], heaps: &mut Heaps) { - if self.buffers.len() == self.offset { - self.buffers.push(Buffer::new( + let mut buffers = ArrayVec::new() ; + let mut offsets = ArrayVec::new() ; + for _ in 0..frame_count { + buffers.push(Buffer::new( device, heaps, MemoryUsageValue::Dynamic, - self.buffer_usage, - self.pitch_alignment_mask, - data.len(), - self.data_stride, + buffer_usage, + pitch_alignment_mask, + PROJECTION_PER_FRAME, + data_stride, )); + offsets.push(0); + } + UniformBufferHandler { + buffers, + offsets, + last_update_size: 0, + pitch_alignment_mask, } - self.buffers[self.offset].update_all(device, data, self.pitch_alignment_mask as u64); - self.offset += 1; } - pub(super) fn buffer(&self) -> &Buffer { - &self.buffers[self.offset - 1] + pub(super) fn add( + &mut self, + device: &B::Device, + data: &[T], + next_id: usize, + ) { + let update_size = self.buffers[next_id].update(device, data, self.offsets[next_id], self.pitch_alignment_mask as u64); + self.last_update_size = update_size; + self.offsets[next_id] += 1; } - pub(super) fn reset(&mut self) { - self.offset = 0; + pub(super) fn buffer(&self, next_id: usize) -> (&B::Buffer, u64) { + let ref buffer = self.buffers[next_id]; + (&buffer.buffer, ((self.offsets[next_id] - 1) * buffer.stride) as u64) + } + + pub(super) fn reset(&mut self, next_id: usize) { + self.offsets[next_id] = 0; } pub(super) fn deinit(self, device: &B::Device, heaps: &mut Heaps) { diff --git a/webrender/src/device/gfx/descriptor.rs b/webrender/src/device/gfx/descriptor.rs index 82fbdef24e..ae3db9f932 100644 --- a/webrender/src/device/gfx/descriptor.rs +++ b/webrender/src/device/gfx/descriptor.rs @@ -3,20 +3,20 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use arrayvec::ArrayVec; +use euclid::default; use hal::device::Device; use hal::pso::{DescriptorSetLayoutBinding, DescriptorType as DT, ShaderStageFlags as SSF}; use crate::internal_types::FastHashMap; use rendy_descriptor::{DescriptorAllocator, DescriptorRanges, DescriptorSet}; -use rendy_memory::Heaps; use smallvec::SmallVec; use std::clone::Clone; use std::cmp::Eq; use std::fmt::Debug; -use std::hash::{Hash, Hasher}; +use std::hash::Hash; use std::marker::Copy; -use super::buffer::UniformBufferHandler; +use super::buffer::{UniformBufferHandler}; use super::image::Image; -use super::TextureId; +use super::{TextureId, MAX_FRAME_COUNT, PROJECTION_PER_FRAME}; use super::super::{ShaderKind, TextureFilter, VertexArrayKind}; pub(super) const DESCRIPTOR_SET_PER_PASS: usize = 0; @@ -66,7 +66,7 @@ pub(super) const COMMON_SET_2: &'static [DescriptorSetLayoutBinding] = &[ ]; pub(super) const COMMON_SET_3: &'static [DescriptorSetLayoutBinding] = &[ - // Locals + // Projection matrix descriptor_set_layout_binding(0, DT::UniformBuffer, SSF::VERTEX, false), ]; @@ -136,32 +136,6 @@ impl From for DescriptorGroup { } } -#[derive(Clone, Copy, Debug, Default)] -#[allow(non_snake_case)] -pub(super) struct Locals { - pub(super) uTransform: [[f32; 4]; 4], -} - -impl Locals { - fn transform_as_u32_slice(&self) -> &[u32; 16] { - unsafe { std::mem::transmute::<&[[f32; 4]; 4], &[u32; 16]>(&self.uTransform) } - } -} - -impl Hash for Locals { - fn hash(&self, state: &mut H) { - self.transform_as_u32_slice().hash(state); - } -} - -impl PartialEq for Locals { - fn eq(&self, other: &Locals) -> bool { - self.uTransform == other.uTransform - } -} - -impl Eq for Locals {} - #[derive(Clone, Copy, Eq, PartialEq, Hash, Debug, Default)] pub(super) struct PerDrawBindings( pub [TextureId; PER_DRAW_TEXTURE_COUNT], @@ -279,8 +253,6 @@ impl DescGroupKey for PerPassBindings { } } -impl DescGroupKey for Locals {} - pub(super) struct DescriptorSetHandler { free_sets: F, descriptor_bindings: FastHashMap>, @@ -433,54 +405,143 @@ where unsafe { device.write_descriptor_sets(descriptor_writes) }; new_set } +} + +struct BoundDecsriptor { + descriptor: DescriptorSet, + bound: bool, +} + +struct DecsriptorBundle { + descriptors: ArrayVec<[BoundDecsriptor; PROJECTION_PER_FRAME]>, + next_id: usize, +} + +impl DecsriptorBundle { + fn from_vec(descriptors: &mut Vec>) -> Self { + let descriptors = descriptors.drain(0..PROJECTION_PER_FRAME).map(|descriptor| BoundDecsriptor { + bound: false, + descriptor, + }).collect(); + DecsriptorBundle { + descriptors, + next_id: 0, + } + } - pub(super) fn bind_locals( + fn reset(&mut self) { + self.next_id = 0; + } + + fn step(&mut self) { + self.next_id += 1; + } + + fn current_descriptor_set(&self) -> &B::DescriptorSet { + &self.descriptors[self.next_id - 1].descriptor.raw() + } + + fn next_descriptor(&self) -> &BoundDecsriptor { + &self.descriptors[self.next_id] + } + + fn bind_next_descriptor(&mut self) { + self.descriptors[self.next_id].bound = true; + self.step(); + } + + unsafe fn write_descriptor_set<'a>( &mut self, - bindings: K, device: &B::Device, - desc_allocator: &mut DescriptorAllocator, + descriptor: hal::pso::Descriptor<'a, B> + ) { + device.write_descriptor_sets(Some(hal::pso::DescriptorSetWrite { + set: self.next_descriptor().descriptor.raw(), + binding: 0, + array_offset: 0, + descriptors: Some(descriptor), + })); + self.bind_next_descriptor(); + assert!(self.next_id < PROJECTION_PER_FRAME) + } + + unsafe fn free(self, allocator: &mut DescriptorAllocator) { + allocator.free(self.descriptors.into_iter().map(|d| d.descriptor)); + } +} + +pub(super) struct SimpleDescriptorSetHandler { + bundles: ArrayVec<[DecsriptorBundle; MAX_FRAME_COUNT]>, +} + +impl SimpleDescriptorSetHandler { + pub(super) fn new( + device: &B::Device, + descriptor_allocator: &mut DescriptorAllocator, group_data: &DescriptorData, - locals_buffer: &mut UniformBufferHandler, - heaps: &mut Heaps, - ) -> DescriptorSet { - let desc_set = match self.descriptor_bindings.remove(&bindings) { - Some(set) => return set, - None => { - locals_buffer.add(&device, &[bindings], heaps); - let free_sets = self.free_sets.get_mut(&DescriptorGroup::Default); - match free_sets.pop() { - Some(ds) => ds, - None => { - unsafe { - desc_allocator.allocate( - device, - group_data.descriptor_layout( - &DescriptorGroup::Default, - DESCRIPTOR_SET_LOCALS, - ), - group_data.ranges(&DescriptorGroup::Default, DESCRIPTOR_SET_LOCALS), - DESCRIPTOR_COUNT, - free_sets, - ) - } - .expect("Allocate descriptor sets failed"); - free_sets.pop().unwrap() - } - } - } - }; + group: &DescriptorGroup, + set_index: usize, + frame_count: usize, + ) -> Self { + debug_assert!(frame_count <= MAX_FRAME_COUNT); + let mut descriptors = Vec::new(); + unsafe { + descriptor_allocator.allocate( + device, + group_data.descriptor_layout(group, set_index), + group_data.ranges(group, set_index), + (frame_count * PROJECTION_PER_FRAME) as u32, + &mut descriptors, + ) + } + .expect("Allocate descriptor sets failed"); + let mut bundles = ArrayVec::new(); + for _ in 0..frame_count { + bundles.push(DecsriptorBundle::from_vec(&mut descriptors)); + } + SimpleDescriptorSetHandler { + bundles, + } + } + pub(super) fn reset(&mut self, next_id: usize) { + self.bundles[next_id].reset() + } + + pub(super) fn bind_projection( + &mut self, + projection: default::Transform3D, + device: &B::Device, + locals_buffer: &mut UniformBufferHandler, + next_id: usize, + ) { + locals_buffer.add(&device, &[projection], next_id); + if self.bundles[next_id].next_descriptor().bound { + self.bundles[next_id].step(); + return; + } unsafe { - device.write_descriptor_sets(Some(hal::pso::DescriptorSetWrite { - set: desc_set.raw(), - binding: 0, - array_offset: 0, - descriptors: Some(hal::pso::Descriptor::Buffer( - &locals_buffer.buffer().buffer, - Some(0)..None, - )), - })); + let (buffer, offset) = locals_buffer.buffer(next_id); + self.bundles[next_id].write_descriptor_set( + device, + hal::pso::Descriptor::Buffer( + buffer, + Some(offset)..Some(offset + std::mem::size_of::>() as u64), + ) + ) + } + } + + pub(super) fn descriptor_set( + &self, + next_id: usize, + ) -> &B::DescriptorSet { + self.bundles[next_id].current_descriptor_set() + } + + pub(super) unsafe fn free(self, allocator: &mut DescriptorAllocator) { + for bundle in self.bundles { + bundle.free(allocator); } - desc_set } } diff --git a/webrender/src/device/gfx/device.rs b/webrender/src/device/gfx/device.rs index 6e055d45ea..8390bc4a7b 100644 --- a/webrender/src/device/gfx/device.rs +++ b/webrender/src/device/gfx/device.rs @@ -12,7 +12,7 @@ use api::TextureTarget; #[cfg(feature = "capture")] use api::ImageDescriptor; use arrayvec::ArrayVec; -use euclid::Transform3D; +use euclid::default; use crate::internal_types::{FastHashMap, RenderTargetInfo, Swizzle, SwizzleSettings}; use rand::{self, Rng}; use rendy_memory::{Block, DynamicConfig, Heaps, HeapsConfig, LinearConfig, MemoryUsageValue}; @@ -40,7 +40,7 @@ use super::image::*; use super::program::{Program, RenderPassDepthState}; use super::render_pass::*; use super::{PipelineRequirements, PrimitiveType, TextureId}; -use super::{LESS_EQUAL_TEST, LESS_EQUAL_WRITE}; +use super::{LESS_EQUAL_TEST, LESS_EQUAL_WRITE, MAX_FRAME_COUNT}; use super::vertex_types; use super::super::{BoundPBO, Capabilities}; @@ -73,8 +73,6 @@ pub const DEFAULT_READ_FBO: FBOId = FBOId(0); pub const DEFAULT_DRAW_FBO: FBOId = FBOId(1); pub const DEBUG_READ_FBO: FBOId = FBOId(2); -// Frame count if present mode is mailbox -const MAX_FRAME_COUNT: usize = 3; const HEADLESS_FRAME_COUNT: usize = 1; const SURFACE_FORMAT: hal::format::Format = hal::format::Format::Bgra8Unorm; const DEPTH_FORMAT: hal::format::Format = hal::format::Format::D32Sfloat; @@ -288,9 +286,9 @@ pub struct Device { bound_per_group_descriptors: [Option>; 3], // Locals related things - locals_descriptors: DescriptorSetHandler>>, - bound_locals: Locals, - bound_locals_descriptor: Option>, + locals_descriptors: SimpleDescriptorSetHandler, + locals_buffer: UniformBufferHandler, + bound_projection: default::Transform3D, descriptor_data: DescriptorData, bound_textures: [u32; RENDERER_TEXTURE_COUNT], @@ -305,7 +303,6 @@ pub struct Device { device_pixel_ratio: f32, depth_available: bool, upload_method: UploadMethod, - locals_buffer: UniformBufferHandler, quad_buffer: VertexBufferHandler, instance_buffers: ArrayVec<[InstanceBufferHandler; MAX_FRAME_COUNT]>, free_instance_buffers: Vec>, @@ -548,8 +545,11 @@ impl Device { let locals_buffer = UniformBufferHandler::new( hal::buffer::Usage::UNIFORM, - mem::size_of::(), + mem::size_of::>(), (limits.min_uniform_buffer_offset_alignment - 1) as usize, + frame_count, + &device, + &mut heaps, ); let quad_buffer = VertexBufferHandler::new( @@ -683,14 +683,13 @@ impl Device { Vec::new(), ); - let locals_descriptors = DescriptorSetHandler::new( + let locals_descriptors = SimpleDescriptorSetHandler::new( &device, &mut desc_allocator, &descriptor_data, &DescriptorGroup::Default, DESCRIPTOR_SET_LOCALS, - descriptor_count.unwrap_or(DESCRIPTOR_COUNT), - Vec::new(), + frame_count, ); let pipeline_cache = if let Some(ref path) = cache_path { @@ -774,8 +773,7 @@ impl Device { bound_per_group_descriptors: [None, None, None], locals_descriptors, - bound_locals: Locals::default(), - bound_locals_descriptor: None, + bound_projection: Default::default(), descriptor_data, bound_textures: [0; RENDERER_TEXTURE_COUNT], @@ -1005,14 +1003,8 @@ impl Device { } Self::reset(&mut self.bound_per_group_textures, &mut self.per_group_descriptors); - Self::push_back_and_reset( - &mut self.bound_locals_descriptor, - None, - &mut self.bound_locals, - &mut self.locals_descriptors, - ); - - self.locals_buffer.reset(); + self.locals_descriptors.reset(self.next_id); + self.locals_buffer.reset(self.next_id); let (frame_depth, surface_format, dimensions, _frame_count) = Self::init_drawables( self.device.as_ref(), @@ -1177,6 +1169,9 @@ impl Device { } Self::begin_cmd_buffer(&mut self.command_buffer); } + self.bound_projection = Default::default(); + self.locals_descriptors.reset(self.next_id); + self.locals_buffer.reset(self.next_id); self.staging_buffer_pool[self.next_id].reset(); self.instance_buffers[self.next_id].reset(&mut self.free_instance_buffers); self.delete_retained_textures(); @@ -1312,35 +1307,20 @@ impl Device { } } - fn bind_uniforms(&mut self, locals: Locals) { - let descriptor = self.locals_descriptors.bind_locals( - locals, - self.device.as_ref(), - &mut self.desc_allocator, - &self.descriptor_data, - &mut self.locals_buffer, - &mut *self.heaps.lock().unwrap(), - ); - - Self::push_back( - &mut self.bound_locals_descriptor, - Some(descriptor), - &self.bound_locals, - &mut self.locals_descriptors, - ) - } - pub fn set_uniforms( &mut self, _program_id: &ProgramId, - projection: &Transform3D, + projection: &default::Transform3D, ) { - let projection = projection.to_row_arrays(); - if self.bound_locals.uTransform != projection { - let mut new_locals = self.bound_locals; - new_locals.uTransform = projection; - self.bind_uniforms(new_locals); - self.bound_locals = new_locals; + //let projection = projection.to_row_arrays(); + if self.bound_projection != *projection { + self.locals_descriptors.bind_projection( + *projection, + self.device.as_ref(), + &mut self.locals_buffer, + self.next_id, + ); + self.bound_projection = *projection; } } @@ -1574,7 +1554,7 @@ impl Device { self.bound_per_draw_descriptor.as_ref().unwrap().raw(), desc_set_per_pass, desc_set_per_group, - self.bound_locals_descriptor.as_ref().unwrap().raw(), + self.locals_descriptors.descriptor_set(self.next_id), self.next_id, self.descriptor_data.pipeline_layout(&descriptor_group), &self.quad_buffer, @@ -2445,7 +2425,7 @@ impl Device { descriptor.raw(), None, desc_set_per_group, - self.bound_locals_descriptor.as_ref().unwrap().raw(), + self.locals_descriptors.descriptor_set(self.next_id), self.next_id, self.descriptor_data.pipeline_layout(&descriptor_group), &self.quad_buffer, @@ -3776,13 +3756,6 @@ impl Device { ); } - Self::push_back( - &mut self.bound_locals_descriptor, - None, - &self.bound_locals, - &mut self.locals_descriptors, - ); - let mut heaps = Arc::try_unwrap(self.heaps).unwrap().into_inner().unwrap(); self.command_pools[self.next_id].return_cmd_buffer(self.command_buffer); diff --git a/webrender/src/device/gfx/mod.rs b/webrender/src/device/gfx/mod.rs index 77134534d7..96e68a5136 100644 --- a/webrender/src/device/gfx/mod.rs +++ b/webrender/src/device/gfx/mod.rs @@ -30,6 +30,9 @@ pub const LESS_EQUAL_WRITE: hal::pso::DepthTest = hal::pso::DepthTest { write: true, }; +pub const MAX_FRAME_COUNT: usize = 3; +pub const PROJECTION_PER_FRAME: usize = 32; + #[derive(Clone, Deserialize)] pub struct PipelineRequirements { pub attribute_descriptors: Vec, From a9a24c5589bb0748466c0bf02f93c4659fa4b9e5 Mon Sep 17 00:00:00 2001 From: Zakor Gyula Date: Fri, 17 Jan 2020 14:42:54 +0100 Subject: [PATCH 5/6] Use dynamic uniform buffers --- webrender/build_gfx.rs | 10 +- webrender/src/device/gfx/buffer.rs | 152 +++++++++++++++++------ webrender/src/device/gfx/descriptor.rs | 161 ++----------------------- webrender/src/device/gfx/device.rs | 60 ++++----- webrender/src/device/gfx/mod.rs | 1 - webrender/src/device/gfx/program.rs | 13 +- 6 files changed, 164 insertions(+), 233 deletions(-) diff --git a/webrender/build_gfx.rs b/webrender/build_gfx.rs index 5ae4a8421c..c7205fd736 100644 --- a/webrender/build_gfx.rs +++ b/webrender/build_gfx.rs @@ -29,8 +29,8 @@ const MAX_INPUT_ATTRIBUTES: u32 = 16; const DESCRIPTOR_SET_PER_PASS: u32 = 0; const DESCRIPTOR_SET_PER_GROUP: u32 = 1; -const DESCRIPTOR_SET_PER_DRAW: u32 = 2; -const DESCRIPTOR_SET_LOCALS: u32 = 3; +const DESCRIPTOR_SET_PER_TARGET: u32 = 2; +const DESCRIPTOR_SET_PER_DRAW: u32 = 3; #[derive(Deserialize)] struct Shader { @@ -332,12 +332,10 @@ fn extend_sampler_definition( fn replace_non_sampler_uniforms(new_data: &mut String) { new_data.push_str(&format!( - "\tlayout(set = {}, binding = 0) uniform Locals {{\n\ + "\tlayout(set = {}, binding = 0) uniform Projection {{\n\ \t\tuniform mat4 uTransform; // Orthographic projection\n\ - \t\t// A generic uniform that shaders can optionally use to configure\n\ - \t\t// an operation mode for this batch.\n\ \t}};\n", - DESCRIPTOR_SET_LOCALS + DESCRIPTOR_SET_PER_TARGET )); } diff --git a/webrender/src/device/gfx/buffer.rs b/webrender/src/device/gfx/buffer.rs index 64e336d278..e0942f700e 100644 --- a/webrender/src/device/gfx/buffer.rs +++ b/webrender/src/device/gfx/buffer.rs @@ -5,15 +5,21 @@ use arrayvec::ArrayVec; use hal; use hal::device::Device as BackendDevice; +use rendy_descriptor::{DescriptorAllocator, DescriptorSet}; use rendy_memory::{Block, Heaps, Kind, MappedRange, MemoryBlock, MemoryUsage, MemoryUsageValue, Write}; use std::cell::Cell; use std::sync::Arc; use std::mem; -use super::{MAX_FRAME_COUNT, PROJECTION_PER_FRAME}; +use super::{MAX_FRAME_COUNT}; +use super::descriptor::{DescriptorData, DescriptorGroup}; pub const DOWNLOAD_BUFFER_SIZE: usize = 10 << 20; // 10MB +// Maximum number of bound projections per frame. +// Projections are bound on a per render target basis, so those should fit in the 96 limit. +// We need this limit to define a fixed size for our uniform buffers. +pub const PROJECTION_PER_FRAME: usize = 96; #[derive(MallocSizeOf)] pub struct BufferMemorySlice { @@ -328,6 +334,7 @@ impl Buffer { let size = (data.len() * self.stride) as u64; let range = offset..((offset + size + non_coherent_atom_size_mask) & !non_coherent_atom_size_mask); + unsafe { let mut mapped = self .memory_block @@ -336,7 +343,7 @@ impl Buffer { mapped .write(device, 0..size) .expect("Writer creation failed") - .write(&data); + .write(data); } self.memory_block.unmap(device); size as usize @@ -706,41 +713,118 @@ impl VertexBufferHandler { } } +struct DynamicBufferBundle { + buffer: Buffer, + buffer_offset: u32, + descriptor_set: DescriptorSet, +} + +impl DynamicBufferBundle { + unsafe fn new( + buffer_usage: hal::buffer::Usage, + data_stride: usize, + min_uniform_buffer_offset_alignment_mask: usize, + device: &B::Device, + heaps: &mut Heaps, + descriptor_set: DescriptorSet + ) -> Self { + debug_assert!(data_stride.is_power_of_two()); + let data_stride = ((data_stride - 1) | min_uniform_buffer_offset_alignment_mask) + 1; + let buffer = Buffer::new( + device, + heaps, + MemoryUsageValue::Dynamic, + buffer_usage, + min_uniform_buffer_offset_alignment_mask, + PROJECTION_PER_FRAME, + data_stride, + ); + device.write_descriptor_sets(Some(hal::pso::DescriptorSetWrite { + set: descriptor_set.raw(), + binding: 0, + array_offset: 0, + descriptors: Some(hal::pso::Descriptor::Buffer( + &buffer.buffer, + Some(0)..None, + )), + })); + DynamicBufferBundle { + buffer, + buffer_offset: 0, + descriptor_set, + } + + } + + fn add( + &mut self, + device: &B::Device, + data: &[T], + non_coherent_atom_size_mask: u64, + ) { + debug_assert!(self.buffer_offset < PROJECTION_PER_FRAME as _); + let _ = self.buffer.update(device, data, self.buffer_offset as usize, non_coherent_atom_size_mask); + self.buffer_offset += 1; + } + + fn last_update_start_offset(&self) -> u32 { + // buffer_offset points to the end of the last update, but we need the starting offset + (self.buffer_offset - 1) * self.buffer.stride as u32 + } + + fn reset(&mut self) { + self.buffer_offset = 0; + } + + unsafe fn deinit(self, device: &B::Device, heaps: &mut Heaps, allocator: &mut DescriptorAllocator) { + self.buffer.deinit(device, heaps); + allocator.free(std::iter::once(self.descriptor_set)); + } +} + pub(super) struct UniformBufferHandler { - buffers: ArrayVec<[Buffer; MAX_FRAME_COUNT]>, - offsets: ArrayVec<[usize; MAX_FRAME_COUNT]>, - last_update_size: usize, - pitch_alignment_mask: usize, + buffer_bundles: ArrayVec<[DynamicBufferBundle; MAX_FRAME_COUNT]>, + min_uniform_buffer_offset_alignment_mask: usize, } impl UniformBufferHandler { pub(super) fn new( - buffer_usage: hal::buffer::Usage, data_stride: usize, - pitch_alignment_mask: usize, + min_uniform_buffer_offset_alignment_mask: usize, frame_count: usize, device: &B::Device, - heaps: &mut Heaps + heaps: &mut Heaps, + descriptor_allocator: &mut DescriptorAllocator, + group_data: &DescriptorData, + group: &DescriptorGroup, + set_index: usize, ) -> Self { - let mut buffers = ArrayVec::new() ; - let mut offsets = ArrayVec::new() ; - for _ in 0..frame_count { - buffers.push(Buffer::new( + debug_assert!(frame_count <= MAX_FRAME_COUNT); + let mut descriptors = Vec::new(); + let mut buffer_bundles = ArrayVec::new(); + unsafe { + descriptor_allocator.allocate( device, - heaps, - MemoryUsageValue::Dynamic, - buffer_usage, - pitch_alignment_mask, - PROJECTION_PER_FRAME, - data_stride, - )); - offsets.push(0); + group_data.descriptor_layout(group, set_index), + group_data.ranges(group, set_index), + frame_count as u32, + &mut descriptors, + ).expect("Allocate descriptor sets failed"); + for _ in 0..frame_count { + buffer_bundles.push(DynamicBufferBundle::new( + hal::buffer::Usage::UNIFORM, + data_stride, + min_uniform_buffer_offset_alignment_mask, + device, + heaps, + descriptors.pop().unwrap(), + )); + } } + UniformBufferHandler { - buffers, - offsets, - last_update_size: 0, - pitch_alignment_mask, + buffer_bundles, + min_uniform_buffer_offset_alignment_mask, } } @@ -750,23 +834,21 @@ impl UniformBufferHandler { data: &[T], next_id: usize, ) { - let update_size = self.buffers[next_id].update(device, data, self.offsets[next_id], self.pitch_alignment_mask as u64); - self.last_update_size = update_size; - self.offsets[next_id] += 1; + self.buffer_bundles[next_id].add(device, data, self.min_uniform_buffer_offset_alignment_mask as u64); } - pub(super) fn buffer(&self, next_id: usize) -> (&B::Buffer, u64) { - let ref buffer = self.buffers[next_id]; - (&buffer.buffer, ((self.offsets[next_id] - 1) * buffer.stride) as u64) + pub(super) fn buffer_info(&self, next_id: usize) -> (&B::DescriptorSet, u32) { + let ref buffer = self.buffer_bundles[next_id]; + (buffer.descriptor_set.raw(), buffer.last_update_start_offset()) } pub(super) fn reset(&mut self, next_id: usize) { - self.offsets[next_id] = 0; + self.buffer_bundles[next_id].reset() } - pub(super) fn deinit(self, device: &B::Device, heaps: &mut Heaps) { - for buffer in self.buffers { - buffer.deinit(device, heaps); + pub(super) unsafe fn deinit(self, device: &B::Device, heaps: &mut Heaps, allocator: &mut DescriptorAllocator) { + for bundle in self.buffer_bundles { + bundle.deinit(device, heaps, allocator); } } } diff --git a/webrender/src/device/gfx/descriptor.rs b/webrender/src/device/gfx/descriptor.rs index ae3db9f932..395f46713b 100644 --- a/webrender/src/device/gfx/descriptor.rs +++ b/webrender/src/device/gfx/descriptor.rs @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use arrayvec::ArrayVec; -use euclid::default; use hal::device::Device; use hal::pso::{DescriptorSetLayoutBinding, DescriptorType as DT, ShaderStageFlags as SSF}; use crate::internal_types::FastHashMap; @@ -14,15 +13,14 @@ use std::cmp::Eq; use std::fmt::Debug; use std::hash::Hash; use std::marker::Copy; -use super::buffer::{UniformBufferHandler}; use super::image::Image; -use super::{TextureId, MAX_FRAME_COUNT, PROJECTION_PER_FRAME}; +use super::TextureId; use super::super::{ShaderKind, TextureFilter, VertexArrayKind}; pub(super) const DESCRIPTOR_SET_PER_PASS: usize = 0; pub(super) const DESCRIPTOR_SET_PER_GROUP: usize = 1; -pub(super) const DESCRIPTOR_SET_PER_DRAW: usize = 2; -pub(super) const DESCRIPTOR_SET_LOCALS: usize = 3; +pub(super) const DESCRIPTOR_SET_PER_TARGET: usize = 2; +pub(super) const DESCRIPTOR_SET_PER_DRAW: usize = 3; pub(super) const DESCRIPTOR_COUNT: u32 = 96; pub(super) const PER_DRAW_TEXTURE_COUNT: usize = 3; // Color0, Color1, Color2 @@ -57,6 +55,11 @@ pub(super) const DEFAULT_SET_1: &'static [DescriptorSetLayoutBinding] = &[ ]; pub(super) const COMMON_SET_2: &'static [DescriptorSetLayoutBinding] = &[ + // Projection matrix + descriptor_set_layout_binding(0, DT::UniformBufferDynamic, SSF::VERTEX, false), +]; + +pub(super) const COMMON_SET_3: &'static [DescriptorSetLayoutBinding] = &[ // Color0 descriptor_set_layout_binding(0, DT::CombinedImageSampler, SSF::ALL, false), // Color1 @@ -65,11 +68,6 @@ pub(super) const COMMON_SET_2: &'static [DescriptorSetLayoutBinding] = &[ descriptor_set_layout_binding(2, DT::CombinedImageSampler, SSF::ALL, false), ]; -pub(super) const COMMON_SET_3: &'static [DescriptorSetLayoutBinding] = &[ - // Projection matrix - descriptor_set_layout_binding(0, DT::UniformBuffer, SSF::VERTEX, false), -]; - pub(super) const CLIP_SET_1: &'static [DescriptorSetLayoutBinding] = &[ // GpuCache descriptor_set_layout_binding(5, DT::StorageBuffer, SSF::ALL, false), @@ -159,7 +157,7 @@ pub(super) struct DescriptorData( ); impl DescriptorData { - fn descriptor_layout( + pub(super) fn descriptor_layout( &self, group: &DescriptorGroup, group_idx: usize, @@ -167,7 +165,7 @@ impl DescriptorData { &self.0[group].set_layouts[group_idx] } - fn ranges(&self, group: &DescriptorGroup, group_idx: usize) -> DescriptorRanges { + pub(super) fn ranges(&self, group: &DescriptorGroup, group_idx: usize) -> DescriptorRanges { self.0[group].ranges[group_idx] } @@ -406,142 +404,3 @@ where new_set } } - -struct BoundDecsriptor { - descriptor: DescriptorSet, - bound: bool, -} - -struct DecsriptorBundle { - descriptors: ArrayVec<[BoundDecsriptor; PROJECTION_PER_FRAME]>, - next_id: usize, -} - -impl DecsriptorBundle { - fn from_vec(descriptors: &mut Vec>) -> Self { - let descriptors = descriptors.drain(0..PROJECTION_PER_FRAME).map(|descriptor| BoundDecsriptor { - bound: false, - descriptor, - }).collect(); - DecsriptorBundle { - descriptors, - next_id: 0, - } - } - - fn reset(&mut self) { - self.next_id = 0; - } - - fn step(&mut self) { - self.next_id += 1; - } - - fn current_descriptor_set(&self) -> &B::DescriptorSet { - &self.descriptors[self.next_id - 1].descriptor.raw() - } - - fn next_descriptor(&self) -> &BoundDecsriptor { - &self.descriptors[self.next_id] - } - - fn bind_next_descriptor(&mut self) { - self.descriptors[self.next_id].bound = true; - self.step(); - } - - unsafe fn write_descriptor_set<'a>( - &mut self, - device: &B::Device, - descriptor: hal::pso::Descriptor<'a, B> - ) { - device.write_descriptor_sets(Some(hal::pso::DescriptorSetWrite { - set: self.next_descriptor().descriptor.raw(), - binding: 0, - array_offset: 0, - descriptors: Some(descriptor), - })); - self.bind_next_descriptor(); - assert!(self.next_id < PROJECTION_PER_FRAME) - } - - unsafe fn free(self, allocator: &mut DescriptorAllocator) { - allocator.free(self.descriptors.into_iter().map(|d| d.descriptor)); - } -} - -pub(super) struct SimpleDescriptorSetHandler { - bundles: ArrayVec<[DecsriptorBundle; MAX_FRAME_COUNT]>, -} - -impl SimpleDescriptorSetHandler { - pub(super) fn new( - device: &B::Device, - descriptor_allocator: &mut DescriptorAllocator, - group_data: &DescriptorData, - group: &DescriptorGroup, - set_index: usize, - frame_count: usize, - ) -> Self { - debug_assert!(frame_count <= MAX_FRAME_COUNT); - let mut descriptors = Vec::new(); - unsafe { - descriptor_allocator.allocate( - device, - group_data.descriptor_layout(group, set_index), - group_data.ranges(group, set_index), - (frame_count * PROJECTION_PER_FRAME) as u32, - &mut descriptors, - ) - } - .expect("Allocate descriptor sets failed"); - let mut bundles = ArrayVec::new(); - for _ in 0..frame_count { - bundles.push(DecsriptorBundle::from_vec(&mut descriptors)); - } - SimpleDescriptorSetHandler { - bundles, - } - } - - pub(super) fn reset(&mut self, next_id: usize) { - self.bundles[next_id].reset() - } - - pub(super) fn bind_projection( - &mut self, - projection: default::Transform3D, - device: &B::Device, - locals_buffer: &mut UniformBufferHandler, - next_id: usize, - ) { - locals_buffer.add(&device, &[projection], next_id); - if self.bundles[next_id].next_descriptor().bound { - self.bundles[next_id].step(); - return; - } - unsafe { - let (buffer, offset) = locals_buffer.buffer(next_id); - self.bundles[next_id].write_descriptor_set( - device, - hal::pso::Descriptor::Buffer( - buffer, - Some(offset)..Some(offset + std::mem::size_of::>() as u64), - ) - ) - } - } - - pub(super) fn descriptor_set( - &self, - next_id: usize, - ) -> &B::DescriptorSet { - self.bundles[next_id].current_descriptor_set() - } - - pub(super) unsafe fn free(self, allocator: &mut DescriptorAllocator) { - for bundle in self.bundles { - bundle.free(allocator); - } - } -} diff --git a/webrender/src/device/gfx/device.rs b/webrender/src/device/gfx/device.rs index 8390bc4a7b..ac279d32d6 100644 --- a/webrender/src/device/gfx/device.rs +++ b/webrender/src/device/gfx/device.rs @@ -286,8 +286,7 @@ pub struct Device { bound_per_group_descriptors: [Option>; 3], // Locals related things - locals_descriptors: SimpleDescriptorSetHandler, - locals_buffer: UniformBufferHandler, + uniform_buffer_handler: UniformBufferHandler, bound_projection: default::Transform3D, descriptor_data: DescriptorData, @@ -543,15 +542,6 @@ impl Device { // Start recording for the 1st frame unsafe { Self::begin_cmd_buffer(&mut command_buffer) }; - let locals_buffer = UniformBufferHandler::new( - hal::buffer::Usage::UNIFORM, - mem::size_of::>(), - (limits.min_uniform_buffer_offset_alignment - 1) as usize, - frame_count, - &device, - &mut heaps, - ); - let quad_buffer = VertexBufferHandler::new( &device, &mut heaps, @@ -683,13 +673,16 @@ impl Device { Vec::new(), ); - let locals_descriptors = SimpleDescriptorSetHandler::new( + let uniform_buffer_handler = UniformBufferHandler::new( + mem::size_of::>(), + (limits.min_uniform_buffer_offset_alignment - 1) as usize, + frame_count, &device, + &mut heaps, &mut desc_allocator, &descriptor_data, &DescriptorGroup::Default, - DESCRIPTOR_SET_LOCALS, - frame_count, + DESCRIPTOR_SET_PER_TARGET, ); let pipeline_cache = if let Some(ref path) = cache_path { @@ -772,7 +765,6 @@ impl Device { bound_per_group_textures: PerGroupBindings::default(), bound_per_group_descriptors: [None, None, None], - locals_descriptors, bound_projection: Default::default(), descriptor_data, @@ -797,7 +789,7 @@ impl Device { cache_path, save_cache, - locals_buffer, + uniform_buffer_handler, quad_buffer, instance_buffers, free_instance_buffers: Vec::new(), @@ -1003,8 +995,7 @@ impl Device { } Self::reset(&mut self.bound_per_group_textures, &mut self.per_group_descriptors); - self.locals_descriptors.reset(self.next_id); - self.locals_buffer.reset(self.next_id); + self.uniform_buffer_handler.reset(self.next_id); let (frame_depth, surface_format, dimensions, _frame_count) = Self::init_drawables( self.device.as_ref(), @@ -1170,8 +1161,7 @@ impl Device { Self::begin_cmd_buffer(&mut self.command_buffer); } self.bound_projection = Default::default(); - self.locals_descriptors.reset(self.next_id); - self.locals_buffer.reset(self.next_id); + self.uniform_buffer_handler.reset(self.next_id); self.staging_buffer_pool[self.next_id].reset(); self.instance_buffers[self.next_id].reset(&mut self.free_instance_buffers); self.delete_retained_textures(); @@ -1312,15 +1302,13 @@ impl Device { _program_id: &ProgramId, projection: &default::Transform3D, ) { - //let projection = projection.to_row_arrays(); if self.bound_projection != *projection { - self.locals_descriptors.bind_projection( - *projection, + self.bound_projection = *projection; + self.uniform_buffer_handler.add( self.device.as_ref(), - &mut self.locals_buffer, - self.next_id, + &[self.bound_projection], + self.next_id ); - self.bound_projection = *projection; } } @@ -1546,20 +1534,23 @@ impl Device { _ => None, }; + let(desc_set_per_target, dynamic_offset) = self.uniform_buffer_handler.buffer_info(self.next_id); + self.programs .get_mut(&self.bound_program) .expect("Program not found") .submit( &mut self.command_buffer, - self.bound_per_draw_descriptor.as_ref().unwrap().raw(), - desc_set_per_pass, desc_set_per_group, - self.locals_descriptors.descriptor_set(self.next_id), + desc_set_per_pass, + desc_set_per_target, + self.bound_per_draw_descriptor.as_ref().unwrap().raw(), self.next_id, self.descriptor_data.pipeline_layout(&descriptor_group), &self.quad_buffer, &self.instance_buffers[self.next_id], self.instance_buffer_range.clone(), + dynamic_offset, ); } @@ -2419,18 +2410,20 @@ impl Device { ); } + let(desc_set_per_target, dynamic_offset) = self.uniform_buffer_handler.buffer_info(self.next_id); program.submit( &mut self.command_buffer, - descriptor.raw(), - None, desc_set_per_group, - self.locals_descriptors.descriptor_set(self.next_id), + None, + desc_set_per_target, + descriptor.raw(), self.next_id, self.descriptor_data.pipeline_layout(&descriptor_group), &self.quad_buffer, &self.instance_buffers[self.next_id], self.instance_buffer_range.clone(), + dynamic_offset, ); unsafe { self.command_buffer.set_viewports(0, &[self.viewport.clone()]) }; self.per_draw_descriptors.push_back_descriptor_set(per_draw_bindings, descriptor); @@ -3807,10 +3800,9 @@ impl Device { self.per_draw_descriptors.free(&mut self.desc_allocator); self.per_group_descriptors.free(&mut self.desc_allocator); self.per_pass_descriptors.free(&mut self.desc_allocator); - self.locals_descriptors.free(&mut self.desc_allocator); + self.uniform_buffer_handler.deinit(self.device.as_ref(), &mut heaps, &mut self.desc_allocator); self.desc_allocator.dispose(self.device.as_ref()); - self.locals_buffer.deinit(self.device.as_ref(), &mut heaps); for (_, program) in self.programs { program.deinit(self.device.as_ref(), &mut heaps) } diff --git a/webrender/src/device/gfx/mod.rs b/webrender/src/device/gfx/mod.rs index 96e68a5136..a36dbcbe27 100644 --- a/webrender/src/device/gfx/mod.rs +++ b/webrender/src/device/gfx/mod.rs @@ -31,7 +31,6 @@ pub const LESS_EQUAL_WRITE: hal::pso::DepthTest = hal::pso::DepthTest { }; pub const MAX_FRAME_COUNT: usize = 3; -pub const PROJECTION_PER_FRAME: usize = 32; #[derive(Clone, Deserialize)] pub struct PipelineRequirements { diff --git a/webrender/src/device/gfx/program.rs b/webrender/src/device/gfx/program.rs index 1100315144..50b9a816f6 100644 --- a/webrender/src/device/gfx/program.rs +++ b/webrender/src/device/gfx/program.rs @@ -634,15 +634,16 @@ impl Program { pub(super) fn submit( &mut self, cmd_buffer: &mut B::CommandBuffer, - desc_set_per_draw: &B::DescriptorSet, - desc_set_per_pass: Option<&B::DescriptorSet>, desc_set_per_frame: &B::DescriptorSet, - desc_set_locals: &B::DescriptorSet, + desc_set_per_pass: Option<&B::DescriptorSet>, + desc_set_per_target: &B::DescriptorSet, + desc_set_per_draw: &B::DescriptorSet, next_id: usize, pipeline_layout: &B::PipelineLayout, vertex_buffer: &VertexBufferHandler, instance_buffer: &InstanceBufferHandler, instance_buffer_range: std::ops::Range, + dynamic_offset: u32, ) { if self.shader_kind.is_debug() { if self.last_frame_used != next_id { @@ -663,9 +664,9 @@ impl Program { desc_set_per_pass .into_iter() .chain(iter::once(desc_set_per_frame)) - .chain(iter::once(desc_set_per_draw)) - .chain(iter::once(desc_set_locals)), - &[], + .chain(iter::once(desc_set_per_target)) + .chain(iter::once(desc_set_per_draw)), + &[dynamic_offset], ); match &self.index_buffer { From 3f1c571ddfeb6e1cb75f4015baffaa8cb53a6102 Mon Sep 17 00:00:00 2001 From: Zakor Gyula Date: Tue, 21 Jan 2020 19:21:26 +0100 Subject: [PATCH 6/6] Set projection on a per rendertarget basis --- webrender/src/debug_render.rs | 4 +++ webrender/src/device/gfx/device.rs | 45 ++++++++++++++++++++---------- webrender/src/renderer.rs | 20 ++++++++++++- webrender/src/shade.rs | 12 ++------ 4 files changed, 55 insertions(+), 26 deletions(-) diff --git a/webrender/src/debug_render.rs b/webrender/src/debug_render.rs index dd8a7920c2..df7f8ffa9c 100644 --- a/webrender/src/debug_render.rs +++ b/webrender/src/debug_render.rs @@ -387,6 +387,10 @@ impl DebugRenderer { true, ); + #[cfg(not(feature = "gl"))] + { + device.reset_draw_target(Some(&projection)); + } // Triangles if !self.tri_vertices.is_empty() { device.bind_program(&self.color_program); diff --git a/webrender/src/device/gfx/device.rs b/webrender/src/device/gfx/device.rs index ac279d32d6..92b644a8a8 100644 --- a/webrender/src/device/gfx/device.rs +++ b/webrender/src/device/gfx/device.rs @@ -1302,14 +1302,7 @@ impl Device { _program_id: &ProgramId, projection: &default::Transform3D, ) { - if self.bound_projection != *projection { - self.bound_projection = *projection; - self.uniform_buffer_handler.add( - self.device.as_ref(), - &[self.bound_projection], - self.next_id - ); - } + assert_eq!(self.bound_projection, *projection); } unsafe fn begin_cmd_buffer(cmd_buffer: &mut B::CommandBuffer) { @@ -1625,9 +1618,26 @@ impl Device { self.bound_read_texture = (texture_id, layer_id); } - fn bind_draw_target_impl(&mut self, fbo_id: FBOId, usage: DrawTargetUsage) { + fn bind_draw_target_impl( + &mut self, + fbo_id: FBOId, + usage: DrawTargetUsage, + projection: Option<&default::Transform3D>, + ) { debug_assert!(self.inside_frame); + if let Some(projection) = projection { + // This check here can save us a bunch of buffer update + if self.bound_projection != *projection { + self.bound_projection = *projection; + self.uniform_buffer_handler.add( + self.device.as_ref(), + &[self.bound_projection], + self.next_id + ) + } + } + let fbo_id = if fbo_id == DEFAULT_DRAW_FBO && self.headless_mode() { self.readback_textures[self.next_id].fbos_with_depth[0] } else { @@ -1669,13 +1679,18 @@ impl Device { self.bind_read_target_impl(DEFAULT_READ_FBO); } - pub fn reset_draw_target(&mut self) { - self.bind_draw_target_impl(DEFAULT_DRAW_FBO, DrawTargetUsage::Draw); + pub fn reset_draw_target(&mut self, projection: Option<&default::Transform3D>) { + self.bind_draw_target_impl(DEFAULT_DRAW_FBO, DrawTargetUsage::Draw, projection); self.depth_available = true; self.render_pass_depth_state = RenderPassDepthState::Enabled; } - pub fn bind_draw_target(&mut self, texture_target: DrawTarget, usage: DrawTargetUsage) { + pub fn bind_draw_target( + &mut self, + texture_target: DrawTarget, + usage: DrawTargetUsage, + projection: Option<&default::Transform3D>, + ) { let (fbo_id, rect, depth_available) = match texture_target { DrawTarget::Default { rect, .. } => { if let DrawTargetUsage::CopyOnly = usage { @@ -1762,7 +1777,7 @@ impl Device { true => RenderPassDepthState::Enabled, false => RenderPassDepthState::Disabled, }; - self.bind_draw_target_impl(fbo_id, usage); + self.bind_draw_target_impl(fbo_id, usage, projection); self.viewport.rect = hal::pso::Rect { x: rect.origin.x as i16, y: rect.origin.y as i16, @@ -2597,7 +2612,7 @@ impl Device { debug_assert!(self.inside_frame); self.bind_read_target(src_target); if !self.inside_render_pass { - self.bind_draw_target(dest_target, DrawTargetUsage::Draw); + self.bind_draw_target(dest_target, DrawTargetUsage::Draw, None); } self.blit_render_target_impl(src_rect, dest_rect, filter); } @@ -3138,7 +3153,7 @@ impl Device { } pub fn end_frame(&mut self) { - self.reset_draw_target(); + self.reset_draw_target(None); self.reset_read_target(); debug_assert!(self.inside_frame); diff --git a/webrender/src/renderer.rs b/webrender/src/renderer.rs index 658e2ea7ac..adb9b6273a 100644 --- a/webrender/src/renderer.rs +++ b/webrender/src/renderer.rs @@ -3573,6 +3573,8 @@ impl Renderer { draw_target, #[cfg(not(feature="gl"))] DrawTargetUsage::Draw, + #[cfg(not(feature="gl"))] + None, ); self.device.clear_target( Some(TEXTURE_CACHE_DBG_CLEAR_COLOR), @@ -3754,6 +3756,8 @@ impl Renderer { draw_target, #[cfg(not(feature="gl"))] DrawTargetUsage::Draw, + #[cfg(not(feature="gl"))] + None, ); self.device.reset_read_target(); @@ -3899,6 +3903,8 @@ impl Renderer { draw_target, #[cfg(not(feature="gl"))] DrawTargetUsage::Draw, + #[cfg(not(feature="gl"))] + Some(&projection), ); self.device.disable_depth(); self.device.enable_depth_write(); @@ -4325,6 +4331,8 @@ impl Renderer { draw_target, #[cfg(not(feature="gl"))] DrawTargetUsage::Draw, + #[cfg(not(feature="gl"))] + Some(&projection), ); self.device.enable_depth(); self.device.enable_depth_write(); @@ -4532,6 +4540,8 @@ impl Renderer { draw_target, #[cfg(not(feature="gl"))] DrawTargetUsage::Draw, + #[cfg(not(feature="gl"))] + Some(&projection), ); self.device.disable_depth(); self.set_blend(false, framebuffer_kind); @@ -4821,6 +4831,8 @@ impl Renderer { draw_target, #[cfg(not(feature="gl"))] DrawTargetUsage::Draw, + #[cfg(not(feature="gl"))] + Some(&projection), ); self.device.disable_depth(); self.device.disable_depth_write(); @@ -5010,6 +5022,8 @@ impl Renderer { draw_target, #[cfg(not(feature="gl"))] DrawTargetUsage::Draw, + #[cfg(not(feature="gl"))] + Some(&projection), ); self.device.disable_depth(); @@ -5491,8 +5505,8 @@ impl Renderer { let clear_color = self.clear_color.map(|color| color.to_array()); self.device.bind_draw_target( draw_target_read_back, - #[cfg(not(feature="gl"))] DrawTargetUsage::Draw, + Some(&projection), ); self.device.enable_depth_write(); self.device.clear_target( @@ -5526,6 +5540,8 @@ impl Renderer { draw_target, #[cfg(not(feature="gl"))] DrawTargetUsage::Draw, + #[cfg(not(feature="gl"))] + Some(&projection) ); self.device.enable_depth_write(); self.device.clear_target( @@ -6353,6 +6369,8 @@ impl Renderer { ), #[cfg(not(feature="gl"))] DrawTargetUsage::Draw, + #[cfg(not(feature="gl"))] + None, ); self.device.clear_target( Some(color), diff --git a/webrender/src/shade.rs b/webrender/src/shade.rs index 1d5ff6e3de..627db32361 100644 --- a/webrender/src/shade.rs +++ b/webrender/src/shade.rs @@ -125,16 +125,8 @@ impl LazilyCompiledShader { let update_projection = self.cached_projection != *projection; match self.get_internal(device, ShaderPrecacheFlags::FULL_COMPILE) { Ok(program) => { - #[cfg(feature = "gl")] - { - device.bind_program(program); - if update_projection { - device.set_uniforms(program, projection); - } - } - #[cfg(not(feature = "gl"))] - { - device.bind_program(program); + device.bind_program(program); + if update_projection { device.set_uniforms(program, projection); } },