Skip to content

Commit

Permalink
gles: GPU timing support
Browse files Browse the repository at this point in the history
  • Loading branch information
kvark committed Sep 27, 2024
1 parent 9ad225c commit 3f78a0b
Show file tree
Hide file tree
Showing 4 changed files with 132 additions and 22 deletions.
74 changes: 67 additions & 7 deletions blade-graphics/src/gles/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,19 +81,72 @@ impl crate::ShaderBindable for super::AccelerationStructure {
}

impl super::CommandEncoder {
fn begin_pass(&mut self, label: &str) {
if let Some(ref mut timing_datas) = self.timing_datas {
let td = timing_datas.first_mut().unwrap();
let id = td.pass_names.len();
self.commands.push(super::Command::QueryCounter {
query: td.queries[id],
});
td.pass_names.push(label.to_string());
}
}

pub fn start(&mut self) {
self.commands.clear();
self.plain_data.clear();
self.has_present = false;
}

pub(super) fn finish(&mut self, gl: &glow::Context) {
use glow::HasContext as _;
#[allow(trivial_casts)]
if let Some(ref mut timing_datas) = self.timing_datas {
{
let td = timing_datas.first_mut().unwrap();
let id = td.pass_names.len();
self.commands.push(super::Command::QueryCounter {
query: td.queries[id],
});
}

timing_datas.rotate_left(1);
self.timings.clear();
let td = timing_datas.first_mut().unwrap();
if !td.pass_names.is_empty() {
let mut prev = 0;
unsafe {
gl.get_query_parameter_u64_with_offset(
td.queries[0],
glow::QUERY_RESULT,
&mut prev as *mut _ as usize,
);
}
for (pass_name, &query) in td.pass_names.drain(..).zip(td.queries[1..].iter()) {
let mut result: u64 = 0;
unsafe {
gl.get_query_parameter_u64_with_offset(
query,
glow::QUERY_RESULT,
&mut result as *mut _ as usize,
);
}
let time = Duration::from_nanos(result - prev);
self.timings.push((pass_name, time));
prev = result
}
}
}
}

pub fn init_texture(&mut self, _texture: super::Texture) {}

pub fn present(&mut self, _frame: super::Frame) {
self.has_present = true;
}

pub fn transfer(&mut self, _label: &str) -> super::PassEncoder<()> {
pub fn transfer(&mut self, label: &str) -> super::PassEncoder<()> {
self.begin_pass(label);
super::PassEncoder {
commands: &mut self.commands,
plain_data: &mut self.plain_data,
Expand All @@ -108,7 +161,8 @@ impl super::CommandEncoder {
unimplemented!()
}

pub fn compute(&mut self, _label: &str) -> super::PassEncoder<super::ComputePipeline> {
pub fn compute(&mut self, label: &str) -> super::PassEncoder<super::ComputePipeline> {
self.begin_pass(label);
super::PassEncoder {
commands: &mut self.commands,
plain_data: &mut self.plain_data,
Expand All @@ -121,9 +175,11 @@ impl super::CommandEncoder {

pub fn render(
&mut self,
_label: &str,
label: &str,
targets: crate::RenderTargetSet,
) -> super::PassEncoder<super::RenderPipeline> {
self.begin_pass(label);

let mut target_size = [0u16; 2];
let mut invalidate_attachments = Vec::new();
for (i, rt) in targets.colors.iter().enumerate() {
Expand Down Expand Up @@ -205,7 +261,7 @@ impl super::CommandEncoder {
}

pub fn timings(&self) -> &[(String, Duration)] {
&[]
&self.timings
}
}

Expand Down Expand Up @@ -400,6 +456,7 @@ impl crate::traits::RenderPipelineEncoder for super::PipelineEncoder<'_> {
}

fn bind_vertex(&mut self, index: u32, vertex_buf: crate::BufferPiece) {
assert_eq!(index, 0);
self.commands.push(super::Command::BindVertex {
buffer: vertex_buf.buffer.raw,
});
Expand Down Expand Up @@ -612,9 +669,9 @@ impl super::Command {
gl.dispatch_compute_indirect(indirect_buf.offset as i32);
}
Self::FillBuffer {
ref dst,
size,
value,
dst: ref _dst,
size: _size,
value: _value,
} => unimplemented!(),
Self::CopyBufferToBuffer {
ref src,
Expand Down Expand Up @@ -988,6 +1045,9 @@ impl super::Command {
gl.bind_sampler(slot, None);
}
}
Self::QueryCounter { query } => {
gl.query_counter(query, glow::TIMESTAMP);
}
}
}
}
Expand Down
28 changes: 16 additions & 12 deletions blade-graphics/src/gles/egl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -775,18 +775,22 @@ impl EglContext {
.get_proc_address(name)
.map_or(ptr::null(), |p| p as *const _)
});
if desc.validation && gl.supports_debug() {
log::info!("Enabling GLES debug output");
gl.enable(glow::DEBUG_OUTPUT);
gl.debug_message_callback(gl_debug_message_callback);
for &(level, severity) in LOG_LEVEL_SEVERITY.iter() {
gl.debug_message_control(
glow::DONT_CARE,
glow::DONT_CARE,
severity,
&[],
level <= log::max_level(),
);
if desc.validation {
if gl.supports_debug() {
log::info!("Enabling GLES debug output");
gl.enable(glow::DEBUG_OUTPUT);
gl.debug_message_callback(gl_debug_message_callback);
for &(level, severity) in LOG_LEVEL_SEVERITY.iter() {
gl.debug_message_control(
glow::DONT_CARE,
glow::DONT_CARE,
severity,
&[],
level <= log::max_level(),
);
}
} else {
log::warn!("Can't enable validation");
}
}

Expand Down
50 changes: 48 additions & 2 deletions blade-graphics/src/gles/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,18 @@ mod pipeline;
mod platform;
mod resource;

use std::{marker::PhantomData, ops::Range};
use std::{marker::PhantomData, ops::Range, time::Duration};

type BindTarget = u32;
const DEBUG_ID: u32 = 0;
const MAX_TIMEOUT: u64 = 1_000_000_000; // MAX_CLIENT_WAIT_TIMEOUT_WEBGL;
const MAX_QUERIES: usize = crate::limits::PASS_COUNT + 1;

bitflags::bitflags! {
struct Capabilities: u32 {
const BUFFER_STORAGE = 1 << 0;
const DRAW_BUFFERS_INDEXED = 1 << 1;
const DISJOINT_TIMER_QUERY = 1 << 2;
}
}

Expand Down Expand Up @@ -344,6 +346,14 @@ enum Command {
binding: ImageBinding,
},
ResetAllSamplers,
QueryCounter {
query: glow::Query,
},
}

struct TimingData {
pass_names: Vec<String>,
queries: Box<[glow::Query]>,
}

pub struct CommandEncoder {
Expand All @@ -352,6 +362,8 @@ pub struct CommandEncoder {
plain_data: Vec<u8>,
has_present: bool,
limits: Limits,
timing_datas: Option<Box<[TimingData]>>,
timings: Vec<(String, Duration)>,
}

enum PassKind {
Expand Down Expand Up @@ -428,22 +440,56 @@ impl crate::traits::CommandDevice for Context {
type SyncPoint = SyncPoint;

fn create_command_encoder(&self, desc: super::CommandEncoderDesc) -> CommandEncoder {
use glow::HasContext as _;

let timing_datas = if self.toggles.timing {
let gl = self.lock();
let mut array = Vec::new();
// Allocating one extra set of timers because we are resolving them
// in submit() as opposed to start().
for _ in 0..desc.buffer_count + 1 {
array.push(TimingData {
pass_names: Vec::new(),
queries: (0..MAX_QUERIES)
.map(|_| unsafe { gl.create_query().unwrap() })
.collect(),
});
}
Some(array.into_boxed_slice())
} else {
None
};
CommandEncoder {
name: desc.name.to_string(),
commands: Vec::new(),
plain_data: Vec::new(),
has_present: false,
limits: self.limits.clone(),
timing_datas,
timings: Vec::new(),
}
}

fn destroy_command_encoder(&self, _command_encoder: &mut CommandEncoder) {}
fn destroy_command_encoder(&self, encoder: &mut CommandEncoder) {
use glow::HasContext as _;

if let Some(timing_datas) = encoder.timing_datas.take() {
let gl = self.lock();
for td in timing_datas {
for query in td.queries {
unsafe { gl.delete_query(query) };
}
}
}
}

fn submit(&self, encoder: &mut CommandEncoder) -> SyncPoint {
use glow::HasContext as _;

let fence = {
let gl = self.lock();
encoder.finish(&gl);

let push_group = !encoder.name.is_empty() && gl.supports_debug();
let ec = unsafe {
if push_group {
Expand Down
2 changes: 1 addition & 1 deletion examples/particle/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ impl Example {
gpu::ContextDesc {
validation: cfg!(debug_assertions),
timing: true,
capture: false,
capture: true,
overlay: false,
},
)
Expand Down

0 comments on commit 3f78a0b

Please sign in to comment.