hal/gles: fix dirty vertex buffers that are unused

This commit is contained in:
Dzmitry Malyshau 2022-01-28 00:54:41 -05:00
parent 36ce638381
commit 9219489894

View File

@ -28,6 +28,7 @@ pub(super) struct State {
has_pass_label: bool, has_pass_label: bool,
instance_vbuf_mask: usize, instance_vbuf_mask: usize,
dirty_vbuf_mask: usize, dirty_vbuf_mask: usize,
active_first_instance: u32,
push_offset_to_uniform: ArrayVec<super::UniformDesc, { super::MAX_PUSH_CONSTANTS }>, push_offset_to_uniform: ArrayVec<super::UniformDesc, { super::MAX_PUSH_CONSTANTS }>,
} }
@ -91,34 +92,44 @@ impl super::CommandEncoder {
.private_caps .private_caps
.contains(super::PrivateCapabilities::VERTEX_BUFFER_LAYOUT) .contains(super::PrivateCapabilities::VERTEX_BUFFER_LAYOUT)
{ {
for (index, &(ref vb_desc, ref vb)) in self.state.vertex_buffers.iter().enumerate() { for (index, pair) in self.state.vertex_buffers.iter().enumerate() {
if self.state.dirty_vbuf_mask & (1 << index) == 0 { if self.state.dirty_vbuf_mask & (1 << index) == 0 {
continue; continue;
} }
let vb = vb.as_ref().unwrap(); let (buffer_desc, vb) = match *pair {
let instance_offset = match vb_desc.step { // Not all dirty bindings are necessarily filled. Some may be unused.
wgt::VertexStepMode::Vertex => 0, (_, None) => continue,
wgt::VertexStepMode::Instance => first_instance * vb_desc.stride, (ref vb_desc, Some(ref vb)) => (vb_desc.clone(), vb),
}; };
let instance_offset = match buffer_desc.step {
wgt::VertexStepMode::Vertex => 0,
wgt::VertexStepMode::Instance => first_instance * buffer_desc.stride,
};
self.cmd_buffer.commands.push(C::SetVertexBuffer { self.cmd_buffer.commands.push(C::SetVertexBuffer {
index: index as u32, index: index as u32,
buffer: super::BufferBinding { buffer: super::BufferBinding {
raw: vb.raw, raw: vb.raw,
offset: vb.offset + instance_offset as wgt::BufferAddress, offset: vb.offset + instance_offset as wgt::BufferAddress,
}, },
buffer_desc: vb_desc.clone(), buffer_desc,
}); });
self.state.dirty_vbuf_mask ^= 1 << index;
} }
} else { } else {
let mut vbuf_mask = 0;
for attribute in self.state.vertex_attributes.iter() { for attribute in self.state.vertex_attributes.iter() {
if self.state.dirty_vbuf_mask & (1 << attribute.buffer_index) == 0 { if self.state.dirty_vbuf_mask & (1 << attribute.buffer_index) == 0 {
continue; continue;
} }
let (buffer_desc, buffer) = let (buffer_desc, vb) =
self.state.vertex_buffers[attribute.buffer_index as usize].clone(); match self.state.vertex_buffers[attribute.buffer_index as usize] {
// Not all dirty bindings are necessarily filled. Some may be unused.
(_, None) => continue,
(ref vb_desc, Some(ref vb)) => (vb_desc.clone(), vb),
};
let mut attribute_desc = attribute.clone(); let mut attribute_desc = attribute.clone();
let vb = buffer.unwrap();
attribute_desc.offset += vb.offset as u32; attribute_desc.offset += vb.offset as u32;
if buffer_desc.step == wgt::VertexStepMode::Instance { if buffer_desc.step == wgt::VertexStepMode::Instance {
attribute_desc.offset += buffer_desc.stride * first_instance; attribute_desc.offset += buffer_desc.stride * first_instance;
@ -129,7 +140,9 @@ impl super::CommandEncoder {
buffer_desc, buffer_desc,
attribute_desc, attribute_desc,
}); });
vbuf_mask |= 1 << attribute.buffer_index;
} }
self.state.dirty_vbuf_mask ^= vbuf_mask;
} }
} }
@ -151,13 +164,13 @@ impl super::CommandEncoder {
} }
fn prepare_draw(&mut self, first_instance: u32) { fn prepare_draw(&mut self, first_instance: u32) {
if first_instance != 0 { if first_instance != self.state.active_first_instance {
// rebind all per-instance buffers on first-instance change
self.state.dirty_vbuf_mask |= self.state.instance_vbuf_mask; self.state.dirty_vbuf_mask |= self.state.instance_vbuf_mask;
self.state.active_first_instance = first_instance;
} }
if self.state.dirty_vbuf_mask != 0 { if self.state.dirty_vbuf_mask != 0 {
self.rebind_vertex_data(first_instance); self.rebind_vertex_data(first_instance);
let vertex_rate_mask = self.state.dirty_vbuf_mask & !self.state.instance_vbuf_mask;
self.state.dirty_vbuf_mask ^= vertex_rate_mask;
} }
} }
@ -539,6 +552,7 @@ impl crate::CommandEncoder<super::Api> for super::CommandEncoder {
} }
self.state.instance_vbuf_mask = 0; self.state.instance_vbuf_mask = 0;
self.state.dirty_vbuf_mask = 0; self.state.dirty_vbuf_mask = 0;
self.state.active_first_instance = 0;
self.state.color_targets.clear(); self.state.color_targets.clear();
self.state.vertex_attributes.clear(); self.state.vertex_attributes.clear();
self.state.primitive = super::PrimitiveState::default(); self.state.primitive = super::PrimitiveState::default();