Skip to content

Commit

Permalink
Add timestamp support to OpenGL (#4267)
Browse files Browse the repository at this point in the history
  • Loading branch information
Zoxc authored Oct 24, 2023
1 parent 9dc5761 commit 3bdad8b
Show file tree
Hide file tree
Showing 11 changed files with 183 additions and 50 deletions.
4 changes: 2 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion wgpu-hal/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ rustc-hash = "1.1"
log = "0.4"

# backend: Gles
glow = { version = "0.12.3", optional = true }
glow = { version = "0.13", optional = true }

[dependencies.wgt]
package = "wgpu-types"
Expand Down
54 changes: 32 additions & 22 deletions wgpu-hal/src/gles/adapter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,28 @@ impl super::Adapter {
return None;
}

if let Some(es_ver) = es_ver {
if es_ver < (3, 0) {
log::warn!(
"Returned GLES context is {}.{}, when 3.0+ was requested",
es_ver.0,
es_ver.1
);
return None;
}
}

if let Some(full_ver) = full_ver {
if full_ver < (3, 3) {
log::warn!(
"Returned GL context is {}.{}, when 3.3+ is needed",
full_ver.0,
full_ver.1
);
return None;
}
}

let shading_language_version = {
let sl_version = unsafe { gl.get_parameter_string(glow::SHADING_LANGUAGE_VERSION) };
log::trace!("SL version: {}", &sl_version);
Expand All @@ -251,28 +273,6 @@ impl super::Adapter {

log::trace!("Supported GL Extensions: {:#?}", extensions);

if let Some(es_ver) = es_ver {
if es_ver < (3, 0) {
log::warn!(
"Returned GLES context is {}.{}, when 3.0+ was requested",
es_ver.0,
es_ver.1
);
return None;
}
}

if let Some(full_ver) = full_ver {
if full_ver < (3, 3) {
log::warn!(
"Returned GL context is {}.{}, when 3.3+ is needed",
full_ver.0,
full_ver.1
);
return None;
}
}

let supported = |(req_es_major, req_es_minor), (req_full_major, req_full_minor)| {
let es_supported = es_ver
.map(|es_ver| es_ver >= (req_es_major, req_es_minor))
Expand Down Expand Up @@ -411,6 +411,11 @@ impl super::Adapter {
wgt::DownlevelFlags::MULTISAMPLED_SHADING,
supported((3, 2), (4, 0)) || extensions.contains("OES_sample_variables"),
);
let query_buffers = extensions.contains("GL_ARB_query_buffer_object")
|| extensions.contains("GL_AMD_query_buffer_object");
if query_buffers {
downlevel_flags.set(wgt::DownlevelFlags::NONBLOCKING_QUERY_RESOLVE, true);
}

let mut features = wgt::Features::empty()
| wgt::Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES
Expand Down Expand Up @@ -450,6 +455,10 @@ impl super::Adapter {
supported((3, 1), (4, 2)) || extensions.contains("GL_ARB_shader_image_load_store"),
);
features.set(wgt::Features::SHADER_UNUSED_VERTEX_OUTPUT, true);
if extensions.contains("GL_ARB_timer_query") {
features.set(wgt::Features::TIMESTAMP_QUERY, true);
features.set(wgt::Features::TIMESTAMP_QUERY_INSIDE_PASSES, true);
}
let gl_bcn_exts = [
"GL_EXT_texture_compression_s3tc",
"GL_EXT_texture_compression_rgtc",
Expand Down Expand Up @@ -574,6 +583,7 @@ impl super::Adapter {
extensions.contains("OES_texture_float_linear")
},
);
private_caps.set(super::PrivateCapabilities::QUERY_BUFFERS, query_buffers);

let max_texture_size = unsafe { gl.get_parameter_i32(glow::MAX_TEXTURE_SIZE) } as u32;
let max_texture_3d_size = unsafe { gl.get_parameter_i32(glow::MAX_3D_TEXTURE_SIZE) } as u32;
Expand Down
34 changes: 32 additions & 2 deletions wgpu-hal/src/gles/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ pub(super) struct State {
dirty_vbuf_mask: usize,
active_first_instance: u32,
push_offset_to_uniform: ArrayVec<super::UniformDesc, { super::MAX_PUSH_CONSTANTS }>,
end_of_pass_timestamp: Option<glow::Query>,
}

impl super::CommandBuffer {
Expand Down Expand Up @@ -409,8 +410,9 @@ impl crate::CommandEncoder<super::Api> for super::CommandEncoder {
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 write_timestamp(&mut self, set: &super::QuerySet, index: u32) {
let query = set.queries[index as usize];
self.cmd_buffer.commands.push(C::TimestampQuery(query));
}
unsafe fn reset_queries(&mut self, _set: &super::QuerySet, _range: Range<u32>) {
//TODO: what do we do here?
Expand Down Expand Up @@ -439,6 +441,16 @@ impl crate::CommandEncoder<super::Api> for super::CommandEncoder {
// render

unsafe fn begin_render_pass(&mut self, desc: &crate::RenderPassDescriptor<super::Api>) {
debug_assert!(self.state.end_of_pass_timestamp.is_none());
if let Some(ref t) = desc.timestamp_writes {
if let Some(index) = t.beginning_of_pass_write_index {
unsafe { self.write_timestamp(t.query_set, index) }
}
self.state.end_of_pass_timestamp = t
.end_of_pass_write_index
.map(|index| t.query_set.queries[index as usize]);
}

self.state.render_size = desc.extent;
self.state.resolve_attachments.clear();
self.state.invalidate_attachments.clear();
Expand Down Expand Up @@ -623,6 +635,10 @@ impl crate::CommandEncoder<super::Api> for super::CommandEncoder {
}
self.state.vertex_attributes.clear();
self.state.primitive = super::PrimitiveState::default();

if let Some(query) = self.state.end_of_pass_timestamp.take() {
self.cmd_buffer.commands.push(C::TimestampQuery(query));
}
}

unsafe fn set_bind_group(
Expand Down Expand Up @@ -1030,6 +1046,16 @@ impl crate::CommandEncoder<super::Api> for super::CommandEncoder {
// compute

unsafe fn begin_compute_pass(&mut self, desc: &crate::ComputePassDescriptor<super::Api>) {
debug_assert!(self.state.end_of_pass_timestamp.is_none());
if let Some(ref t) = desc.timestamp_writes {
if let Some(index) = t.beginning_of_pass_write_index {
unsafe { self.write_timestamp(t.query_set, index) }
}
self.state.end_of_pass_timestamp = t
.end_of_pass_write_index
.map(|index| t.query_set.queries[index as usize]);
}

if let Some(label) = desc.label {
let range = self.cmd_buffer.add_marker(label);
self.cmd_buffer.commands.push(C::PushDebugGroup(range));
Expand All @@ -1041,6 +1067,10 @@ impl crate::CommandEncoder<super::Api> for super::CommandEncoder {
self.cmd_buffer.commands.push(C::PopDebugGroup);
self.state.has_pass_label = false;
}

if let Some(query) = self.state.end_of_pass_timestamp.take() {
self.cmd_buffer.commands.push(C::TimestampQuery(query));
}
}

unsafe fn set_compute_pipeline(&mut self, pipeline: &super::ComputePipeline) {
Expand Down
9 changes: 9 additions & 0 deletions wgpu-hal/src/gles/device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1224,6 +1224,14 @@ impl crate::Device<super::Api> for super::Device {
if gl.supports_debug() {
use std::fmt::Write;

// Initialize the query so we can label it
match desc.ty {
wgt::QueryType::Timestamp => unsafe {
gl.query_counter(query, glow::TIMESTAMP)
},
_ => (),
}

if let Some(label) = desc.label {
temp_string.clear();
let _ = write!(temp_string, "{label}[{i}]");
Expand All @@ -1238,6 +1246,7 @@ impl crate::Device<super::Api> for super::Device {
queries: queries.into_boxed_slice(),
target: match desc.ty {
wgt::QueryType::Occlusion => glow::ANY_SAMPLES_PASSED_CONSERVATIVE,
wgt::QueryType::Timestamp => glow::TIMESTAMP,
_ => unimplemented!(),
},
})
Expand Down
2 changes: 1 addition & 1 deletion wgpu-hal/src/gles/egl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -946,7 +946,7 @@ impl crate::Instance<super::Api> for Instance {
let inner = self.inner.lock();
inner.egl.make_current();

let gl = unsafe {
let mut gl = unsafe {
glow::Context::from_loader_function(|name| {
inner
.egl
Expand Down
3 changes: 3 additions & 0 deletions wgpu-hal/src/gles/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,8 @@ bitflags::bitflags! {
const COLOR_BUFFER_FLOAT = 1 << 9;
/// Supports linear flitering `f32` textures.
const TEXTURE_FLOAT_LINEAR = 1 << 10;
/// Supports query buffer objects.
const QUERY_BUFFERS = 1 << 11;
}
}

Expand Down Expand Up @@ -775,6 +777,7 @@ enum Command {
SetIndexBuffer(glow::Buffer),
BeginQuery(glow::Query, BindTarget),
EndQuery(BindTarget),
TimestampQuery(glow::Query),
CopyQueryResults {
query_range: Range<u32>,
dst: Buffer,
Expand Down
103 changes: 83 additions & 20 deletions wgpu-hal/src/gles/queue.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use super::{conv::is_layered_target, Command as C};
use super::{conv::is_layered_target, Command as C, PrivateCapabilities};
use arrayvec::ArrayVec;
use glow::HasContext;
use std::{mem, slice, sync::Arc};
Expand Down Expand Up @@ -808,34 +808,97 @@ impl super::Queue {
C::EndQuery(target) => {
unsafe { gl.end_query(target) };
}
C::TimestampQuery(query) => {
unsafe { gl.query_counter(query, glow::TIMESTAMP) };
}
C::CopyQueryResults {
ref query_range,
ref dst,
dst_target,
dst_offset,
} => {
self.temp_query_results.clear();
for &query in queries[query_range.start as usize..query_range.end as usize].iter() {
let result = unsafe { gl.get_query_parameter_u32(query, glow::QUERY_RESULT) };
self.temp_query_results.push(result as u64);
}
let query_data = unsafe {
slice::from_raw_parts(
self.temp_query_results.as_ptr() as *const u8,
self.temp_query_results.len() * mem::size_of::<u64>(),
)
};
match dst.raw {
Some(buffer) => {
unsafe { gl.bind_buffer(dst_target, Some(buffer)) };
if self
.shared
.private_caps
.contains(PrivateCapabilities::QUERY_BUFFERS)
&& dst.raw.is_some()
{
unsafe {
// We're assuming that the only relevant queries are 8 byte timestamps or
// occlusion tests.
let query_size = 8;

let query_range_size = query_size * query_range.len();

let buffer = gl.create_buffer().ok();
gl.bind_buffer(glow::QUERY_BUFFER, buffer);
gl.buffer_data_size(
glow::QUERY_BUFFER,
query_range_size as _,
glow::STREAM_COPY,
);

for (i, &query) in queries
[query_range.start as usize..query_range.end as usize]
.iter()
.enumerate()
{
gl.get_query_parameter_u64_with_offset(
query,
glow::QUERY_RESULT,
query_size * i,
)
}
gl.bind_buffer(dst_target, dst.raw);
gl.copy_buffer_sub_data(
glow::QUERY_BUFFER,
dst_target,
0,
dst_offset as _,
query_range_size as _,
);
if let Some(buffer) = buffer {
gl.delete_buffer(buffer)
}
}
} else {
self.temp_query_results.clear();
for &query in
queries[query_range.start as usize..query_range.end as usize].iter()
{
let mut result: u64 = 0;
unsafe {
gl.buffer_sub_data_u8_slice(dst_target, dst_offset as i32, query_data)
let result: *mut u64 = &mut result;
gl.get_query_parameter_u64_with_offset(
query,
glow::QUERY_RESULT,
result as usize,
)
};
self.temp_query_results.push(result);
}
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]);
let query_data = unsafe {
slice::from_raw_parts(
self.temp_query_results.as_ptr() as *const u8,
self.temp_query_results.len() * mem::size_of::<u64>(),
)
};
match dst.raw {
Some(buffer) => {
unsafe { gl.bind_buffer(dst_target, Some(buffer)) };
unsafe {
gl.buffer_sub_data_u8_slice(
dst_target,
dst_offset as i32,
query_data,
)
};
}
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]);
}
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion wgpu-hal/src/gles/wgl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -387,7 +387,7 @@ impl crate::Instance<super::Api> for Instance {
)
})?;

let gl = unsafe {
let mut gl = unsafe {
glow::Context::from_loader_function(|name| load_gl_func(name, Some(opengl_module)))
};

Expand Down
3 changes: 2 additions & 1 deletion wgpu-hal/src/vulkan/adapter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,8 @@ impl PhysicalDeviceFeatures {
| Df::UNRESTRICTED_INDEX_BUFFER
| Df::INDIRECT_EXECUTION
| Df::VIEW_FORMATS
| Df::UNRESTRICTED_EXTERNAL_TEXTURE_COPIES;
| Df::UNRESTRICTED_EXTERNAL_TEXTURE_COPIES
| Df::NONBLOCKING_QUERY_RESOLVE;

dl_flags.set(
Df::SURFACE_VIEW_FORMATS,
Expand Down
Loading

0 comments on commit 3bdad8b

Please sign in to comment.