use native webgl2 buffers for MAP_READ usage (#2201)

* use native gl buffers for map_read

* Buffer refactor

* lint
This commit is contained in:
Mariusz Kryński
2021-11-23 23:16:26 +01:00
committed by GitHub
parent 5864b776a4
commit dde73ed236
4 changed files with 113 additions and 102 deletions

View File

@@ -201,10 +201,9 @@ impl crate::CommandEncoder<super::Api> for super::CommandEncoder {
if !bar.usage.start.contains(crate::BufferUses::STORAGE_WRITE) {
continue;
}
self.cmd_buffer.commands.push(C::BufferBarrier(
bar.buffer.inner.as_native().unwrap(),
bar.usage.end,
));
self.cmd_buffer
.commands
.push(C::BufferBarrier(bar.buffer.raw.unwrap(), bar.usage.end));
}
}
@@ -239,7 +238,7 @@ impl crate::CommandEncoder<super::Api> for super::CommandEncoder {
unsafe fn clear_buffer(&mut self, buffer: &super::Buffer, range: crate::MemoryRange) {
self.cmd_buffer.commands.push(C::ClearBuffer {
dst: buffer.inner.clone(),
dst: buffer.clone(),
dst_target: buffer.target,
range,
});
@@ -260,9 +259,9 @@ impl crate::CommandEncoder<super::Api> for super::CommandEncoder {
};
for copy in regions {
self.cmd_buffer.commands.push(C::CopyBufferToBuffer {
src: src.inner.clone(),
src: src.clone(),
src_target,
dst: dst.inner.clone(),
dst: dst.clone(),
dst_target,
copy,
})
@@ -305,7 +304,7 @@ impl crate::CommandEncoder<super::Api> for super::CommandEncoder {
for mut copy in regions {
copy.clamp_size_to_virtual(&dst.copy_size);
self.cmd_buffer.commands.push(C::CopyBufferToTexture {
src: src.inner.clone(),
src: src.clone(),
src_target: src.target,
dst: dst_raw,
dst_target,
@@ -331,7 +330,7 @@ impl crate::CommandEncoder<super::Api> for super::CommandEncoder {
src: src_raw,
src_target,
src_format: src.format,
dst: dst.inner.clone(),
dst: dst.clone(),
dst_target: dst.target,
copy,
})
@@ -368,7 +367,7 @@ impl crate::CommandEncoder<super::Api> for super::CommandEncoder {
let query_range = start as u32..self.cmd_buffer.queries.len() as u32;
self.cmd_buffer.commands.push(C::CopyQueryResults {
query_range,
dst: buffer.inner.clone(),
dst: buffer.clone(),
dst_target: buffer.target,
dst_offset: offset,
});
@@ -742,7 +741,7 @@ impl crate::CommandEncoder<super::Api> for super::CommandEncoder {
self.state.index_format = format;
self.cmd_buffer
.commands
.push(C::SetIndexBuffer(binding.buffer.inner.as_native().unwrap()));
.push(C::SetIndexBuffer(binding.buffer.raw.unwrap()));
}
unsafe fn set_vertex_buffer<'a>(
&mut self,
@@ -752,7 +751,7 @@ impl crate::CommandEncoder<super::Api> for super::CommandEncoder {
self.state.dirty_vbuf_mask |= 1 << index;
let (_, ref mut vb) = self.state.vertex_buffers[index as usize];
*vb = Some(super::BufferBinding {
raw: binding.buffer.inner.as_native().unwrap(),
raw: binding.buffer.raw.unwrap(),
offset: binding.offset,
});
}
@@ -834,7 +833,7 @@ impl crate::CommandEncoder<super::Api> for super::CommandEncoder {
offset + draw * mem::size_of::<wgt::DrawIndirectArgs>() as wgt::BufferAddress;
self.cmd_buffer.commands.push(C::DrawIndirect {
topology: self.state.topology,
indirect_buf: buffer.inner.as_native().unwrap(),
indirect_buf: buffer.raw.unwrap(),
indirect_offset,
});
}
@@ -856,7 +855,7 @@ impl crate::CommandEncoder<super::Api> for super::CommandEncoder {
self.cmd_buffer.commands.push(C::DrawIndexedIndirect {
topology: self.state.topology,
index_type,
indirect_buf: buffer.inner.as_native().unwrap(),
indirect_buf: buffer.raw.unwrap(),
indirect_offset,
});
}
@@ -907,7 +906,7 @@ impl crate::CommandEncoder<super::Api> for super::CommandEncoder {
}
unsafe fn dispatch_indirect(&mut self, buffer: &super::Buffer, offset: wgt::BufferAddress) {
self.cmd_buffer.commands.push(C::DispatchIndirect {
indirect_buf: buffer.inner.as_native().unwrap(),
indirect_buf: buffer.raw.unwrap(),
indirect_offset: offset,
});
}

View File

@@ -1,7 +1,11 @@
use super::{conv, BufferInner};
use super::conv;
use crate::auxil::map_naga_stage;
use glow::HasContext;
use std::{convert::TryInto, iter, ptr, sync::Arc};
use std::{
convert::TryInto,
iter, ptr,
sync::{Arc, Mutex},
};
#[cfg(not(target_arch = "wasm32"))]
use std::mem;
@@ -329,16 +333,13 @@ impl crate::Device<super::Api> for super::Device {
.private_caps
.contains(super::PrivateCapabilities::BUFFER_ALLOCATION);
if emulate_map
&& desc
.usage
.intersects(crate::BufferUses::MAP_WRITE | crate::BufferUses::MAP_READ)
{
if emulate_map && desc.usage.intersects(crate::BufferUses::MAP_WRITE) {
return Ok(super::Buffer {
inner: BufferInner::data_with_capacity(desc.size),
raw: None,
target,
size: desc.size,
map_flags: 0,
data: Some(Arc::new(Mutex::new(vec![0; desc.size as usize]))),
});
}
@@ -365,8 +366,8 @@ impl crate::Device<super::Api> for super::Device {
map_flags |= glow::MAP_WRITE_BIT;
}
let raw = gl.create_buffer().unwrap();
gl.bind_buffer(target, Some(raw));
let raw = Some(gl.create_buffer().unwrap());
gl.bind_buffer(target, raw);
let raw_size = desc
.size
.try_into()
@@ -412,15 +413,22 @@ impl crate::Device<super::Api> for super::Device {
}
}
let data = if emulate_map && desc.usage.contains(crate::BufferUses::MAP_READ) {
Some(Arc::new(Mutex::new(vec![0; desc.size as usize])))
} else {
None
};
Ok(super::Buffer {
inner: BufferInner::Buffer(raw),
raw,
target,
size: desc.size,
map_flags,
data,
})
}
unsafe fn destroy_buffer(&self, buffer: super::Buffer) {
if let BufferInner::Buffer(raw) = buffer.inner {
if let Some(raw) = buffer.raw {
let gl = &self.shared.context.lock();
gl.delete_buffer(raw);
}
@@ -432,21 +440,28 @@ impl crate::Device<super::Api> for super::Device {
range: crate::MemoryRange,
) -> Result<crate::BufferMapping, crate::DeviceError> {
let is_coherent = buffer.map_flags & glow::MAP_COHERENT_BIT != 0;
let ptr = match buffer.inner {
BufferInner::Data(ref data) => {
let mut vec = data.lock().unwrap();
let ptr = match buffer.raw {
None => {
let mut vec = buffer.data.as_ref().unwrap().lock().unwrap();
let slice = &mut vec.as_mut_slice()[range.start as usize..range.end as usize];
slice.as_mut_ptr()
}
BufferInner::Buffer(raw) => {
Some(raw) => {
let gl = &self.shared.context.lock();
gl.bind_buffer(buffer.target, Some(raw));
let ptr = gl.map_buffer_range(
buffer.target,
range.start as i32,
(range.end - range.start) as i32,
buffer.map_flags,
);
let ptr = if let Some(ref map_read_allocation) = buffer.data {
let mut guard = map_read_allocation.lock().unwrap();
let slice = guard.as_mut_slice();
gl.get_buffer_sub_data(buffer.target, 0, slice);
slice.as_mut_ptr()
} else {
gl.map_buffer_range(
buffer.target,
range.start as i32,
(range.end - range.start) as i32,
buffer.map_flags,
)
};
gl.bind_buffer(buffer.target, None);
ptr
}
@@ -457,11 +472,17 @@ impl crate::Device<super::Api> for super::Device {
})
}
unsafe fn unmap_buffer(&self, buffer: &super::Buffer) -> Result<(), crate::DeviceError> {
if let BufferInner::Buffer(raw) = buffer.inner {
let gl = &self.shared.context.lock();
gl.bind_buffer(buffer.target, Some(raw));
gl.unmap_buffer(buffer.target);
gl.bind_buffer(buffer.target, None);
if let Some(raw) = buffer.raw {
if !self
.shared
.workarounds
.contains(super::Workarounds::EMULATE_BUFFER_MAP)
{
let gl = &self.shared.context.lock();
gl.bind_buffer(buffer.target, Some(raw));
gl.unmap_buffer(buffer.target);
gl.bind_buffer(buffer.target, None);
}
}
Ok(())
}
@@ -469,7 +490,7 @@ impl crate::Device<super::Api> for super::Device {
where
I: Iterator<Item = crate::MemoryRange>,
{
if let BufferInner::Buffer(raw) = buffer.inner {
if let Some(raw) = buffer.raw {
let gl = &self.shared.context.lock();
gl.bind_buffer(buffer.target, Some(raw));
for range in ranges {
@@ -862,7 +883,7 @@ impl crate::Device<super::Api> for super::Device {
wgt::BindingType::Buffer { .. } => {
let bb = &desc.buffers[entry.resource_index as usize];
super::RawBinding::Buffer {
raw: bb.buffer.inner.as_native().unwrap(),
raw: bb.buffer.raw.unwrap(),
offset: bb.offset as i32,
size: match bb.size {
Some(s) => s.get() as i32,
@@ -1094,15 +1115,25 @@ impl crate::Device<super::Api> for super::Device {
wait_value: crate::FenceValue,
timeout_ms: u32,
) -> Result<bool, crate::DeviceError> {
if cfg!(not(target_arch = "wasm32")) && fence.last_completed < wait_value {
if fence.last_completed < wait_value {
let gl = &self.shared.context.lock();
let timeout_ns = (timeout_ms as u64 * 1_000_000).min(!0u32 as u64);
let timeout_ns = if cfg!(target_arch = "wasm32") {
0
} else {
(timeout_ms as u64 * 1_000_000).min(!0u32 as u64)
};
let &(_, sync) = fence
.pending
.iter()
.find(|&&(value, _)| value >= wait_value)
.unwrap();
match gl.client_wait_sync(sync, glow::SYNC_FLUSH_COMMANDS_BIT, timeout_ns as i32) {
// for some reason firefox returns WAIT_FAILED, to investigate
#[cfg(target_arch = "wasm32")]
glow::WAIT_FAILED => {
log::warn!("wait failed!");
Ok(false)
}
glow::TIMEOUT_EXPIRED => Ok(false),
glow::CONDITION_SATISFIED | glow::ALREADY_SIGNALED => Ok(true),
_ => Err(crate::DeviceError::Lost),

View File

@@ -210,30 +210,13 @@ pub struct Queue {
current_index_buffer: Option<glow::Buffer>,
}
#[derive(Debug, Clone)]
pub enum BufferInner {
Buffer(glow::Buffer),
Data(Arc<std::sync::Mutex<Vec<u8>>>),
}
impl BufferInner {
pub fn data_with_capacity(size: u64) -> BufferInner {
BufferInner::Data(Arc::new(std::sync::Mutex::new(vec![0; size as usize])))
}
pub fn as_native(&self) -> Option<glow::Buffer> {
match *self {
BufferInner::Buffer(ref buffer) => Some(*buffer),
BufferInner::Data(_) => None,
}
}
}
#[derive(Debug)]
#[derive(Clone, Debug)]
pub struct Buffer {
inner: BufferInner,
raw: Option<glow::Buffer>,
target: BindTarget,
size: wgt::BufferAddress,
map_flags: u32,
data: Option<Arc<std::sync::Mutex<Vec<u8>>>>,
}
// Safe: WASM doesn't have threads
@@ -584,14 +567,14 @@ enum Command {
indirect_offset: wgt::BufferAddress,
},
ClearBuffer {
dst: BufferInner,
dst: Buffer,
dst_target: BindTarget,
range: crate::MemoryRange,
},
CopyBufferToBuffer {
src: BufferInner,
src: Buffer,
src_target: BindTarget,
dst: BufferInner,
dst: Buffer,
dst_target: BindTarget,
copy: crate::BufferCopy,
},
@@ -603,7 +586,7 @@ enum Command {
copy: crate::TextureCopy,
},
CopyBufferToTexture {
src: BufferInner,
src: Buffer,
#[allow(unused)]
src_target: BindTarget,
dst: glow::Texture,
@@ -615,7 +598,7 @@ enum Command {
src: glow::Texture,
src_target: BindTarget,
src_format: wgt::TextureFormat,
dst: BufferInner,
dst: Buffer,
#[allow(unused)]
dst_target: BindTarget,
copy: crate::BufferTextureCopy,
@@ -625,7 +608,7 @@ enum Command {
EndQuery(BindTarget),
CopyQueryResults {
query_range: Range<u32>,
dst: BufferInner,
dst: Buffer,
dst_target: BindTarget,
dst_offset: wgt::BufferAddress,
},

View File

@@ -205,8 +205,8 @@ impl super::Queue {
ref dst,
dst_target,
ref range,
} => match *dst {
super::BufferInner::Buffer(buffer) => {
} => match dst.raw {
Some(buffer) => {
gl.bind_buffer(glow::COPY_READ_BUFFER, Some(self.zero_buffer));
gl.bind_buffer(dst_target, Some(buffer));
let mut dst_offset = range.start;
@@ -222,8 +222,9 @@ impl super::Queue {
dst_offset += size;
}
}
super::BufferInner::Data(ref data) => {
data.lock().unwrap().as_mut_slice()[range.start as usize..range.end as usize]
None => {
dst.data.as_ref().unwrap().lock().unwrap().as_mut_slice()
[range.start as usize..range.end as usize]
.fill(0);
}
},
@@ -249,11 +250,8 @@ impl super::Queue {
glow::COPY_WRITE_BUFFER
};
let size = copy.size.get() as usize;
match (src, dst) {
(
&super::BufferInner::Buffer(ref src),
&super::BufferInner::Buffer(ref dst),
) => {
match (src.raw, dst.raw) {
(Some(ref src), Some(ref dst)) => {
gl.bind_buffer(copy_src_target, Some(*src));
gl.bind_buffer(copy_dst_target, Some(*dst));
gl.copy_buffer_sub_data(
@@ -264,16 +262,16 @@ impl super::Queue {
copy.size.get() as _,
);
}
(&super::BufferInner::Buffer(src), &super::BufferInner::Data(ref data)) => {
let mut data = data.lock().unwrap();
(Some(src), None) => {
let mut data = dst.data.as_ref().unwrap().lock().unwrap();
let dst_data = &mut data.as_mut_slice()
[copy.dst_offset as usize..copy.dst_offset as usize + size];
gl.bind_buffer(copy_src_target, Some(src));
gl.get_buffer_sub_data(copy_src_target, copy.src_offset as i32, dst_data);
}
(&super::BufferInner::Data(ref data), &super::BufferInner::Buffer(dst)) => {
let data = data.lock().unwrap();
(None, Some(dst)) => {
let data = src.data.as_ref().unwrap().lock().unwrap();
let src_data = &data.as_slice()
[copy.src_offset as usize..copy.src_offset as usize + size];
gl.bind_buffer(copy_dst_target, Some(dst));
@@ -283,7 +281,7 @@ impl super::Queue {
src_data,
);
}
(&super::BufferInner::Data(_), &super::BufferInner::Data(_)) => {
(None, None) => {
todo!()
}
}
@@ -374,14 +372,14 @@ impl super::Queue {
let mut unbind_unpack_buffer = false;
if format_info.block_dimensions == (1, 1) {
let buffer_data;
let unpack_data = match *src {
super::BufferInner::Buffer(buffer) => {
let unpack_data = match src.raw {
Some(buffer) => {
gl.bind_buffer(glow::PIXEL_UNPACK_BUFFER, Some(buffer));
unbind_unpack_buffer = true;
glow::PixelUnpackData::BufferOffset(copy.buffer_layout.offset as u32)
}
super::BufferInner::Data(ref data) => {
buffer_data = data.lock().unwrap();
None => {
buffer_data = src.data.as_ref().unwrap().lock().unwrap();
let src_data =
&buffer_data.as_slice()[copy.buffer_layout.offset as usize..];
glow::PixelUnpackData::Slice(src_data)
@@ -454,16 +452,16 @@ impl super::Queue {
let offset = copy.buffer_layout.offset as u32;
let buffer_data;
let unpack_data = match *src {
super::BufferInner::Buffer(buffer) => {
let unpack_data = match src.raw {
Some(buffer) => {
gl.bind_buffer(glow::PIXEL_UNPACK_BUFFER, Some(buffer));
unbind_unpack_buffer = true;
glow::CompressedPixelUnpackData::BufferRange(
offset..offset + bytes_per_image,
)
}
super::BufferInner::Data(ref data) => {
buffer_data = data.lock().unwrap();
None => {
buffer_data = src.data.as_ref().unwrap().lock().unwrap();
let src_data = &buffer_data.as_slice()
[(offset as usize)..(offset + bytes_per_image) as usize];
glow::CompressedPixelUnpackData::Slice(src_data)
@@ -578,14 +576,14 @@ impl super::Queue {
);
}
let mut buffer_data;
let unpack_data = match *dst {
super::BufferInner::Buffer(buffer) => {
let unpack_data = match dst.raw {
Some(buffer) => {
gl.pixel_store_i32(glow::PACK_ROW_LENGTH, row_texels as i32);
gl.bind_buffer(glow::PIXEL_PACK_BUFFER, Some(buffer));
glow::PixelPackData::BufferOffset(copy.buffer_layout.offset as u32)
}
super::BufferInner::Data(ref data) => {
buffer_data = data.lock().unwrap();
None => {
buffer_data = dst.data.as_ref().unwrap().lock().unwrap();
let dst_data =
&mut buffer_data.as_mut_slice()[copy.buffer_layout.offset as usize..];
glow::PixelPackData::Slice(dst_data)
@@ -626,13 +624,13 @@ impl super::Queue {
self.temp_query_results.as_ptr() as *const u8,
self.temp_query_results.len() * mem::size_of::<u64>(),
);
match *dst {
super::BufferInner::Buffer(buffer) => {
match dst.raw {
Some(buffer) => {
gl.bind_buffer(dst_target, Some(buffer));
gl.buffer_sub_data_u8_slice(dst_target, dst_offset as i32, query_data);
}
super::BufferInner::Data(ref data) => {
let data = &mut *data.lock().unwrap();
None => {
let data = &mut dst.data.as_ref().unwrap().lock().unwrap();
let len = query_data.len().min(data.len());
data[..len].copy_from_slice(&query_data[..len]);
}