From c58d94f3fda40f215254008ec105aeab56085b0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Wed, 26 Feb 2020 12:52:30 +0100 Subject: [PATCH] Avoid creating a vertex buffer every frame --- wgpu/src/image.rs | 105 +++++++++++++++++++++------------ wgpu/src/image/raster.rs | 2 - wgpu/src/shader/image.vert | 2 +- wgpu/src/shader/image.vert.spv | Bin 2472 -> 2504 bytes wgpu/src/texture/atlas.rs | 12 ++-- 5 files changed, 73 insertions(+), 48 deletions(-) diff --git a/wgpu/src/image.rs b/wgpu/src/image.rs index e14b3024..afff52a6 100644 --- a/wgpu/src/image.rs +++ b/wgpu/src/image.rs @@ -22,6 +22,7 @@ pub struct Pipeline { uniforms: wgpu::Buffer, vertices: wgpu::Buffer, indices: wgpu::Buffer, + instances: wgpu::Buffer, constants: wgpu::BindGroup, texture: wgpu::BindGroup, texture_version: usize, @@ -188,7 +189,7 @@ impl Pipeline { }, wgpu::VertexAttributeDescriptor { shader_location: 5, - format: wgpu::VertexFormat::Float, + format: wgpu::VertexFormat::Uint, offset: 4 * 8, }, ], @@ -207,6 +208,11 @@ impl Pipeline { .create_buffer_mapped(QUAD_INDICES.len(), wgpu::BufferUsage::INDEX) .fill_from_slice(&QUAD_INDICES); + let instances = device.create_buffer(&wgpu::BufferDescriptor { + size: mem::size_of::() as u64 * Instance::MAX as u64, + usage: wgpu::BufferUsage::VERTEX | wgpu::BufferUsage::COPY_DST, + }); + let texture_atlas = texture::Atlas::new(device); let texture = device.create_bind_group(&wgpu::BindGroupDescriptor { @@ -230,6 +236,7 @@ impl Pipeline { uniforms: uniforms_buffer, vertices, indices, + instances, constants: constant_bind_group, texture, texture_version: texture_atlas.layer_count(), @@ -341,49 +348,67 @@ impl Pipeline { ); let instances_buffer = device - .create_buffer_mapped(instances.len(), wgpu::BufferUsage::VERTEX) + .create_buffer_mapped(instances.len(), wgpu::BufferUsage::COPY_SRC) .fill_from_slice(&instances); - let mut render_pass = - encoder.begin_render_pass(&wgpu::RenderPassDescriptor { - color_attachments: &[ - wgpu::RenderPassColorAttachmentDescriptor { - attachment: target, - resolve_target: None, - load_op: wgpu::LoadOp::Load, - store_op: wgpu::StoreOp::Store, - clear_color: wgpu::Color { - r: 0.0, - g: 0.0, - b: 0.0, - a: 0.0, + let mut i = 0; + let total = instances.len(); + + while i < total { + let end = (i + Instance::MAX).min(total); + let amount = end - i; + + encoder.copy_buffer_to_buffer( + &instances_buffer, + (i * std::mem::size_of::()) as u64, + &self.instances, + 0, + (amount * std::mem::size_of::()) as u64, + ); + + let mut render_pass = + encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + color_attachments: &[ + wgpu::RenderPassColorAttachmentDescriptor { + attachment: target, + resolve_target: None, + load_op: wgpu::LoadOp::Load, + store_op: wgpu::StoreOp::Store, + clear_color: wgpu::Color { + r: 0.0, + g: 0.0, + b: 0.0, + a: 0.0, + }, }, - }, - ], - depth_stencil_attachment: None, - }); + ], + depth_stencil_attachment: None, + }); - render_pass.set_pipeline(&self.pipeline); - render_pass.set_bind_group(0, &self.constants, &[]); - render_pass.set_bind_group(1, &self.texture, &[]); - render_pass.set_index_buffer(&self.indices, 0); - render_pass.set_vertex_buffers( - 0, - &[(&self.vertices, 0), (&instances_buffer, 0)], - ); + render_pass.set_pipeline(&self.pipeline); + render_pass.set_bind_group(0, &self.constants, &[]); + render_pass.set_bind_group(1, &self.texture, &[]); + render_pass.set_index_buffer(&self.indices, 0); + render_pass.set_vertex_buffers( + 0, + &[(&self.vertices, 0), (&self.instances, 0)], + ); - render_pass.set_scissor_rect( - bounds.x, - bounds.y, - bounds.width, - bounds.height, - ); + render_pass.set_scissor_rect( + bounds.x, + bounds.y, + bounds.width, + bounds.height, + ); - render_pass.draw_indexed( - 0..QUAD_INDICES.len() as u32, - 0, - 0..instances.len() as u32, - ); + render_pass.draw_indexed( + 0..QUAD_INDICES.len() as u32, + 0, + 0..amount as u32, + ); + + i += Instance::MAX; + } } pub fn trim_cache(&mut self) { @@ -439,6 +464,10 @@ struct Instance { _layer: u32, } +impl Instance { + pub const MAX: usize = 1_000; +} + #[repr(C)] #[derive(Debug, Clone, Copy)] struct Uniforms { diff --git a/wgpu/src/image/raster.rs b/wgpu/src/image/raster.rs index 071d53c8..8d2f342e 100644 --- a/wgpu/src/image/raster.rs +++ b/wgpu/src/image/raster.rs @@ -86,8 +86,6 @@ impl Cache { let allocation = atlas.upload(width, height, &image, device, encoder)?; - dbg!("Uploaded"); - *memory = Memory::Device(allocation); } diff --git a/wgpu/src/shader/image.vert b/wgpu/src/shader/image.vert index 0ce7dd6b..dab53cfe 100644 --- a/wgpu/src/shader/image.vert +++ b/wgpu/src/shader/image.vert @@ -5,7 +5,7 @@ layout(location = 1) in vec2 i_Pos; layout(location = 2) in vec2 i_Scale; layout(location = 3) in vec2 i_Atlas_Pos; layout(location = 4) in vec2 i_Atlas_Scale; -layout(location = 5) in float i_Layer; +layout(location = 5) in uint i_Layer; layout (set = 0, binding = 0) uniform Globals { mat4 u_Transform; diff --git a/wgpu/src/shader/image.vert.spv b/wgpu/src/shader/image.vert.spv index 192bf6c3ac4ed329b18f92d019217a113f520ca2..21f5db2d2f3104a67387dbd296d65d1763bfd727 100644 GIT binary patch literal 2504 zcmZQ(Qf6mhU}WH6;9!VhfB-=TCI&_Z1_o{hHZbk(6YQf`T#}+^Vrl?V!N(z~IHez`)GF%)rFJ zz;K9>fq|8Qg#lSFh!4`AA0JuLx$$ZeTWlR$bv?#x88 z&x3)1Aw4HPAhjqgwWuVu0^}|>1~vweIEW3B%P-C>$;{7VU}Inhi-W=sES{NH5}a8D zaw1#~w{5)^URf1_lP07)Tx@2BKkNATvN>AiH2xv@)C$I%D}=P0(A?>$sqGY89=$10W1#E58{L3 z45S`pzYNrVPe@ z!r%^dJIFjaXubov9b_g*4unB&@`T0#C|`oi0r4T_4Fdxx%)Fst1~M1qCJ^5T>?Q^V zIR;4j0QnzemLCHo-a+XIWEO}IN;9zd3xLYQ)JH+>2D!_Offbx)Kw%3q9+U=tFfcKI z(ksX;P*{V?Ay9bRGO#d!(g3Iw1;sy%&krp>TNzlv@}M*fQUel)sS$#fuZ>VO!qBu1 z5(lXP#eq1q{4HQ$0jEC+1_lO@SRex{m@mn|zyQ(*awkko3MvK)rvPxt#K0iUz`y`f z3z7qwVaLD>E>l3_jtr~}p!5LBf1or2N+%%uLGh!)z`y_!4}iwG8Uq6ZNDLI$FbvbL z0gWF}Jj3*BGB7ZJ#9{iiplJpq4$}`(3kpL$XdMIdhdu)X14sOHqRC+hHRc40|NsnJdn+^hl(Ma z=KvK$HqQ|%1~Ly8Urr1R44^Osg&8P}Kw$!tb7o**0EGw0{~-T@{0EbBVPIeY`3>Y3 zklR6Sg~_=xFff4J333<69Uyx_a-h8E#=yV;vJ+%B$P9>DW^la^k^`kRP~Ht>U;x*T zp!^R?KOnt93=9k)aTq_CfdQ;<5(6u^ybNJrU;wEBiG$RD(p)ICtpkhSFa`z&kQj3K zg+s+a;RkXjsEmkUU|;~L1fq|8Qg#lSFh!4`AA0JuLx$$ZeTWlR$bv?#x88 z&y9hBAw4HPAhjqgwWuVu0^}|>1~vweIEW3B%P-C>$;{7VU}Inhi-W=sES{NH5}a8D zaw1#~7r+ z5`(yh8EhU%od*L81I)i5w}8~c_{vCj!Nk}Z7#IY=Ze|AS1DOGGFDPu3pz2|KMJQjG zfeD;G6~QT$0n8R-U}j)rU|>*SU|hBLd*oI2k}911d<2Y zCk3?+6n+v6EDX{N3=AMK5Feyph5_PMkT^&`$bMM-i88P-$V2@K3KDHBe30K^;SG~l zg}MpE2gz%KG&3~V>oBl`?bc#oU;ya>VUQe%hS?2DKOncuFt9MVLfsBBPY#;TKyC+_ z36cY0kRRNkVGhcNAag)`NcjRPb66NWp?(0F3vv^P?*(=fs62wC2ax|kX8ABc;u(}~ zKxTpXpfm!DFF&X}Onn5@Zjigo7+Aq+1QfO)<3Vx$gMo%K0 zGcYiK)PdXu6O(|7fx;yKT=Fn5NP^Qf0|Q77WQH9BGq}tEi90f|GJw(-D1U&`2q+K0 z>;vT?kaz$zj#U^K7(im6xP@Vuel=)40E$A9Suij#fbtEpd6rNyWb>?` zV#wxML&cEIvteLh0EGv#dA3k7Wb^ExV#wy%L&ZSm!Q#t-fq?-OhM+J5g%K!BU~-NO z3=E*~0Qn!}Uy%P`a!w2k3?RRO`~q@2$gMCrX9flakUK%{0=WZZFGvoQ_gokl7(jM{ z%m$eOQVU9}p!@}r1En=kUiD{S0M~z@{0>S#AiV($3=AM~7(bAK0o)###J~zJAA=Ye z7(i-3;vhAkG#3nQ%fR9{gn@wpB!(P*p-?eU_<`IBDigvO7#KimL2|G(H<5uATn>ga mFff4Z0;vJH7gUx+g6l{I29SF}{sHkp>i#k?GFUJ$G5`Q=-jz}S diff --git a/wgpu/src/texture/atlas.rs b/wgpu/src/texture/atlas.rs index b950e59b..bf528dc9 100644 --- a/wgpu/src/texture/atlas.rs +++ b/wgpu/src/texture/atlas.rs @@ -67,24 +67,22 @@ impl Atlas { where C: Copy + 'static, { - let memory = { + let entry = { let current_size = self.layers.len(); - let memory = self.allocate(width, height)?; + let entry = self.allocate(width, height)?; // We grow the internal texture after allocating if necessary let new_layers = self.layers.len() - current_size; self.grow(new_layers, device, encoder); - memory + entry }; - dbg!(&memory); - let buffer = device .create_buffer_mapped(data.len(), wgpu::BufferUsage::COPY_SRC) .fill_from_slice(data); - match &memory { + match &entry { Entry::Contiguous(allocation) => { self.upload_texture(&buffer, 0, &allocation, encoder); } @@ -105,7 +103,7 @@ impl Atlas { } } - Some(memory) + Some(entry) } fn allocate(&mut self, width: u32, height: u32) -> Option {