diff --git a/wgpu-hal/src/gles/adapter.rs b/wgpu-hal/src/gles/adapter.rs index d2c22d6c4..25e55b8ad 100644 --- a/wgpu-hal/src/gles/adapter.rs +++ b/wgpu-hal/src/gles/adapter.rs @@ -279,7 +279,7 @@ impl super::Adapter { impl crate::Adapter for super::Adapter { unsafe fn open( &self, - features: wgt::Features, + _features: wgt::Features, ) -> Result, crate::DeviceError> { let gl = &self.shared.context; gl.pixel_store_i32(glow::UNPACK_ALIGNMENT, 1); @@ -294,8 +294,8 @@ impl crate::Adapter for super::Adapter { }, queue: super::Queue { shared: Arc::clone(&self.shared), - features, copy_fbo: gl.create_framebuffer().unwrap(), + temp_query_results: Vec::new(), }, }) } diff --git a/wgpu-hal/src/gles/command.rs b/wgpu-hal/src/gles/command.rs index b4ca8c0ac..fcbad747d 100644 --- a/wgpu-hal/src/gles/command.rs +++ b/wgpu-hal/src/gles/command.rs @@ -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 { - 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 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) {} + 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) { + //TODO: what do we do here? + } unsafe fn copy_query_results( &mut self, - set: &Resource, + set: &super::QuerySet, range: Range, 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 diff --git a/wgpu-hal/src/gles/device.rs b/wgpu-hal/src/gles/device.rs index 56f39feb3..b442f461c 100644 --- a/wgpu-hal/src/gles/device.rs +++ b/wgpu-hal/src/gles/device.rs @@ -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 for super::Device { unsafe fn create_query_set( &self, desc: &wgt::QuerySetDescriptor, - ) -> Result { - Ok(Resource) + ) -> Result { + 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 { - 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 { + 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 { - 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 { - 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 { diff --git a/wgpu-hal/src/gles/mod.rs b/wgpu-hal/src/gles/mod.rs index 6fae71f5c..172b22839 100644 --- a/wgpu-hal/src/gles/mod.rs +++ b/wgpu-hal/src/gles/mod.rs @@ -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, - features: wgt::Features, copy_fbo: glow::Framebuffer, + temp_query_results: Vec, } #[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, + dst: glow::Buffer, + dst_target: BindTarget, + dst_offset: wgt::BufferAddress, + }, InsertDebugMarker(Range), PushDebugGroup(Range), PopDebugGroup, @@ -428,7 +474,8 @@ enum Command { pub struct CommandBuffer { label: Option, commands: Vec, - data: Vec, + data_bytes: Vec, + data_words: Vec, } #[derive(Default)] diff --git a/wgpu-hal/src/gles/queue.rs b/wgpu-hal/src/gles/queue.rs index 94e607f7d..0e7ec7a09 100644 --- a/wgpu-hal/src/gles/queue.rs +++ b/wgpu-hal/src/gles/queue.rs @@ -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::(), + ); + 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 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(()) }