hal/gles: fences and queries

This commit is contained in:
Dzmitry Malyshau 2021-06-23 21:00:00 -04:00 committed by Dzmitry Malyshau
parent d3d2ed5a9e
commit 91f9806831
5 changed files with 185 additions and 37 deletions

View File

@ -279,7 +279,7 @@ impl super::Adapter {
impl crate::Adapter<super::Api> for super::Adapter {
unsafe fn open(
&self,
features: wgt::Features,
_features: wgt::Features,
) -> Result<crate::OpenDevice<super::Api>, crate::DeviceError> {
let gl = &self.shared.context;
gl.pixel_store_i32(glow::UNPACK_ALIGNMENT, 1);
@ -294,8 +294,8 @@ impl crate::Adapter<super::Api> for super::Adapter {
},
queue: super::Queue {
shared: Arc::clone(&self.shared),
features,
copy_fbo: gl.create_framebuffer().unwrap(),
temp_query_results: Vec::new(),
},
})
}

View File

@ -1,4 +1,3 @@
use super::Resource; //TEMP
use super::{conv, Command as C};
use std::{mem, ops::Range};
@ -6,13 +5,14 @@ impl super::CommandBuffer {
fn clear(&mut self) {
self.label = None;
self.commands.clear();
self.data.clear();
self.data_bytes.clear();
self.data_words.clear();
}
fn add_marker(&mut self, marker: &str) -> Range<u32> {
let start = self.data.len() as u32;
self.data.extend(marker.as_bytes());
start..self.data.len() as u32
let start = self.data_bytes.len() as u32;
self.data_bytes.extend(marker.as_bytes());
start..self.data_bytes.len() as u32
}
}
@ -153,17 +153,39 @@ impl crate::CommandEncoder<super::Api> for super::CommandEncoder {
}
}
unsafe fn begin_query(&mut self, set: &Resource, index: u32) {}
unsafe fn end_query(&mut self, set: &Resource, index: u32) {}
unsafe fn write_timestamp(&mut self, set: &Resource, index: u32) {}
unsafe fn reset_queries(&mut self, set: &Resource, range: Range<u32>) {}
unsafe fn begin_query(&mut self, set: &super::QuerySet, index: u32) {
let query = set.queries[index as usize];
self.cmd_buffer
.commands
.push(C::BeginQuery(query, set.target));
}
unsafe fn end_query(&mut self, set: &super::QuerySet, _index: u32) {
self.cmd_buffer.commands.push(C::EndQuery(set.target));
}
unsafe fn write_timestamp(&mut self, _set: &super::QuerySet, _index: u32) {
unimplemented!()
}
unsafe fn reset_queries(&mut self, _set: &super::QuerySet, _range: Range<u32>) {
//TODO: what do we do here?
}
unsafe fn copy_query_results(
&mut self,
set: &Resource,
set: &super::QuerySet,
range: Range<u32>,
buffer: &super::Buffer,
offset: wgt::BufferAddress,
) {
let start = self.cmd_buffer.data_words.len();
self.cmd_buffer
.data_words
.extend_from_slice(&set.queries[range.start as usize..range.end as usize]);
let query_range = start as u32..self.cmd_buffer.data_words.len() as u32;
self.cmd_buffer.commands.push(C::CopyQueryResults {
query_range,
dst: buffer.raw,
dst_target: buffer.target,
dst_offset: offset,
});
}
// render

View File

@ -1,5 +1,4 @@
use super::conv;
use super::Resource; //TEMP
use crate::util::map_naga_stage;
use glow::HasContext;
use std::{convert::TryInto, iter, ptr::NonNull, sync::Arc};
@ -713,27 +712,71 @@ impl crate::Device<super::Api> for super::Device {
unsafe fn create_query_set(
&self,
desc: &wgt::QuerySetDescriptor<crate::Label>,
) -> Result<Resource, crate::DeviceError> {
Ok(Resource)
) -> Result<super::QuerySet, crate::DeviceError> {
let gl = &self.shared.context;
let mut queries = Vec::with_capacity(desc.count as usize);
for _ in 0..desc.count {
let query = gl
.create_query()
.map_err(|_| crate::DeviceError::OutOfMemory)?;
queries.push(query);
}
Ok(super::QuerySet {
queries: queries.into_boxed_slice(),
target: match desc.ty {
wgt::QueryType::Occlusion => glow::ANY_SAMPLES_PASSED,
_ => unimplemented!(),
},
})
}
unsafe fn destroy_query_set(&self, set: Resource) {}
unsafe fn create_fence(&self) -> Result<Resource, crate::DeviceError> {
Ok(Resource)
unsafe fn destroy_query_set(&self, set: super::QuerySet) {
let gl = &self.shared.context;
for &query in set.queries.iter() {
gl.delete_query(query);
}
}
unsafe fn create_fence(&self) -> Result<super::Fence, crate::DeviceError> {
Ok(super::Fence {
last_completed: 0,
pending: Vec::new(),
})
}
unsafe fn destroy_fence(&self, fence: super::Fence) {
let gl = &self.shared.context;
for (_, sync) in fence.pending {
gl.delete_sync(sync);
}
}
unsafe fn destroy_fence(&self, fence: Resource) {}
unsafe fn get_fence_value(
&self,
fence: &Resource,
fence: &super::Fence,
) -> Result<crate::FenceValue, crate::DeviceError> {
Ok(0)
Ok(fence.get_latest(&self.shared.context))
}
unsafe fn wait(
&self,
fence: &Resource,
value: crate::FenceValue,
fence: &super::Fence,
wait_value: crate::FenceValue,
timeout_ms: u32,
) -> Result<bool, crate::DeviceError> {
Ok(true)
if fence.last_completed < wait_value {
let gl = &self.shared.context;
let timeout_ns = (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) {
glow::TIMEOUT_EXPIRED => Ok(false),
glow::CONDITION_SATISFIED | glow::ALREADY_SIGNALED => Ok(true),
_ => Err(crate::DeviceError::Lost),
}
} else {
Ok(true)
}
}
unsafe fn start_capture(&self) -> bool {

View File

@ -18,12 +18,9 @@ use std::{ops::Range, sync::Arc};
#[derive(Clone)]
pub struct Api;
#[derive(Debug)]
pub struct Resource;
//Note: we can support more samplers if not every one of them is used at a time,
// but it probably doesn't worth it.
const MAX_SAMPLER_SLOTS: usize = 16;
const MAX_TEXTURE_SLOTS: usize = 16;
impl crate::Api for Api {
@ -41,8 +38,8 @@ impl crate::Api for Api {
type SurfaceTexture = Texture;
type TextureView = TextureView;
type Sampler = Sampler;
type QuerySet = Resource;
type Fence = Resource;
type QuerySet = QuerySet;
type Fence = Fence;
type BindGroupLayout = BindGroupLayout;
type BindGroup = BindGroup;
@ -184,8 +181,8 @@ pub struct Device {
pub struct Queue {
shared: Arc<AdapterShared>,
features: wgt::Features,
copy_fbo: glow::Framebuffer,
temp_query_results: Vec<u64>,
}
#[derive(Debug)]
@ -344,6 +341,47 @@ pub struct ComputePipeline {
inner: PipelineInner,
}
#[derive(Debug)]
pub struct QuerySet {
queries: Box<[glow::Query]>,
target: BindTarget,
}
#[derive(Debug)]
pub struct Fence {
last_completed: crate::FenceValue,
pending: Vec<(crate::FenceValue, glow::Fence)>,
}
unsafe impl Send for Fence {}
unsafe impl Sync for Fence {}
impl Fence {
fn get_latest(&self, gl: &glow::Context) -> crate::FenceValue {
let mut max_value = self.last_completed;
for &(value, sync) in self.pending.iter() {
let status = unsafe { gl.get_sync_status(sync) };
if status == glow::SIGNALED {
max_value = value;
}
}
max_value
}
fn maintain(&mut self, gl: &glow::Context) {
let latest = self.get_latest(gl);
for &(value, sync) in self.pending.iter() {
if value <= latest {
unsafe {
gl.delete_sync(sync);
}
}
}
self.pending.retain(|&(value, _)| value > latest);
self.last_completed = latest;
}
}
#[derive(Debug)]
struct TextureCopyInfo {
external_format: u32,
@ -419,6 +457,14 @@ enum Command {
copy: crate::BufferTextureCopy,
},
SetIndexBuffer(glow::Buffer),
BeginQuery(glow::Query, BindTarget),
EndQuery(BindTarget),
CopyQueryResults {
query_range: Range<u32>,
dst: glow::Buffer,
dst_target: BindTarget,
dst_offset: wgt::BufferAddress,
},
InsertDebugMarker(Range<u32>),
PushDebugGroup(Range<u32>),
PopDebugGroup,
@ -428,7 +474,8 @@ enum Command {
pub struct CommandBuffer {
label: Option<String>,
commands: Vec<Command>,
data: Vec<u8>,
data_bytes: Vec<u8>,
data_words: Vec<u32>,
}
#[derive(Default)]

View File

@ -1,6 +1,6 @@
use super::Command as C;
use glow::HasContext;
use std::ops::Range;
use std::{mem, ops::Range, slice};
const DEBUG_ID: u32 = 0;
@ -16,7 +16,7 @@ fn is_3d_target(target: super::BindTarget) -> bool {
}
impl super::Queue {
unsafe fn process(&mut self, command: &C, data: &[u8]) {
unsafe fn process(&mut self, command: &C, data_bytes: &[u8], data_words: &[u32]) {
let gl = &self.shared.context;
match *command {
C::Draw {
@ -265,8 +265,34 @@ impl super::Queue {
C::SetIndexBuffer(buffer) => {
gl.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, Some(buffer));
}
C::BeginQuery(query, target) => {
gl.begin_query(target, query);
}
C::EndQuery(target) => {
gl.end_query(target);
}
C::CopyQueryResults {
ref query_range,
dst,
dst_target,
dst_offset,
} => {
self.temp_query_results.clear();
for &query in
data_words[query_range.start as usize..query_range.end as usize].iter()
{
let result = gl.get_query_parameter_u32(query, glow::QUERY_RESULT);
self.temp_query_results.push(result as u64);
}
let query_data = slice::from_raw_parts(
self.temp_query_results.as_ptr() as *const u8,
self.temp_query_results.len() * mem::size_of::<u64>(),
);
gl.bind_buffer(dst_target, Some(dst));
gl.buffer_sub_data_u8_slice(dst_target, dst_offset as i32, query_data);
}
C::InsertDebugMarker(ref range) => {
let marker = extract_marker(data, range);
let marker = extract_marker(data_bytes, range);
gl.debug_message_insert(
glow::DEBUG_SOURCE_APPLICATION,
glow::DEBUG_TYPE_MARKER,
@ -276,7 +302,7 @@ impl super::Queue {
);
}
C::PushDebugGroup(ref range) => {
let marker = extract_marker(data, range);
let marker = extract_marker(data_bytes, range);
gl.push_debug_group(glow::DEBUG_SOURCE_APPLICATION, DEBUG_ID, marker);
}
C::PopDebugGroup => {
@ -290,13 +316,23 @@ impl crate::Queue<super::Api> for super::Queue {
unsafe fn submit(
&mut self,
command_buffers: &[&super::CommandBuffer],
signal_fence: Option<(&mut super::Resource, crate::FenceValue)>,
signal_fence: Option<(&mut super::Fence, crate::FenceValue)>,
) -> Result<(), crate::DeviceError> {
for cmd_buf in command_buffers.iter() {
for command in cmd_buf.commands.iter() {
self.process(command, &cmd_buf.data);
self.process(command, &cmd_buf.data_bytes, &cmd_buf.data_words);
}
}
if let Some((fence, value)) = signal_fence {
let gl = &self.shared.context;
fence.maintain(gl);
let sync = gl
.fence_sync(glow::SYNC_GPU_COMMANDS_COMPLETE, 0)
.map_err(|_| crate::DeviceError::OutOfMemory)?;
fence.pending.push((value, sync));
}
Ok(())
}