From 36d22d82aa202bb199967e9512281e9a53db42c9 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 21:33:14 +0200 Subject: Adding upstream version 115.7.0esr. Signed-off-by: Daniel Baumann --- gfx/wr/webrender/src/device/query_gl.rs | 318 ++++++++++++++++++++++++++++++++ 1 file changed, 318 insertions(+) create mode 100644 gfx/wr/webrender/src/device/query_gl.rs (limited to 'gfx/wr/webrender/src/device/query_gl.rs') diff --git a/gfx/wr/webrender/src/device/query_gl.rs b/gfx/wr/webrender/src/device/query_gl.rs new file mode 100644 index 0000000000..c7fd9a9070 --- /dev/null +++ b/gfx/wr/webrender/src/device/query_gl.rs @@ -0,0 +1,318 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use gleam::gl; +use std::mem; +use std::rc::Rc; + +use crate::device::GpuFrameId; +use crate::profiler::GpuProfileTag; + +#[derive(Copy, Clone, Debug)] +pub enum GpuDebugMethod { + None, + MarkerEXT, + KHR, +} + +#[derive(Debug, Clone)] +pub struct GpuTimer { + pub tag: GpuProfileTag, + pub time_ns: u64, +} + +#[derive(Debug, Clone)] +pub struct GpuSampler { + pub tag: GpuProfileTag, + pub count: u64, +} + +pub struct QuerySet { + set: Vec, + data: Vec, + pending: gl::GLuint, +} + +impl QuerySet { + fn new() -> Self { + QuerySet { + set: Vec::new(), + data: Vec::new(), + pending: 0, + } + } + + fn reset(&mut self) { + self.data.clear(); + self.pending = 0; + } + + fn add(&mut self, value: T) -> Option { + assert_eq!(self.pending, 0); + self.set.get(self.data.len()).cloned().map(|query_id| { + self.data.push(value); + self.pending = query_id; + query_id + }) + } + + fn take(&mut self, fun: F) -> Vec { + let mut data = mem::replace(&mut self.data, Vec::new()); + for (value, &query) in data.iter_mut().zip(self.set.iter()) { + fun(value, query) + } + data + } +} + +pub struct GpuFrameProfile { + gl: Rc, + timers: QuerySet, + samplers: QuerySet, + frame_id: GpuFrameId, + inside_frame: bool, + debug_method: GpuDebugMethod, +} + +impl GpuFrameProfile { + fn new(gl: Rc, debug_method: GpuDebugMethod) -> Self { + GpuFrameProfile { + gl, + timers: QuerySet::new(), + samplers: QuerySet::new(), + frame_id: GpuFrameId::new(0), + inside_frame: false, + debug_method + } + } + + fn enable_timers(&mut self, count: i32) { + self.timers.set = self.gl.gen_queries(count); + } + + fn disable_timers(&mut self) { + if !self.timers.set.is_empty() { + self.gl.delete_queries(&self.timers.set); + } + self.timers.set = Vec::new(); + } + + fn enable_samplers(&mut self, count: i32) { + self.samplers.set = self.gl.gen_queries(count); + } + + fn disable_samplers(&mut self) { + if !self.samplers.set.is_empty() { + self.gl.delete_queries(&self.samplers.set); + } + self.samplers.set = Vec::new(); + } + + fn begin_frame(&mut self, frame_id: GpuFrameId) { + self.frame_id = frame_id; + self.timers.reset(); + self.samplers.reset(); + self.inside_frame = true; + } + + fn end_frame(&mut self) { + self.finish_timer(); + self.finish_sampler(); + self.inside_frame = false; + } + + fn finish_timer(&mut self) { + debug_assert!(self.inside_frame); + if self.timers.pending != 0 { + self.gl.end_query(gl::TIME_ELAPSED); + self.timers.pending = 0; + } + } + + fn finish_sampler(&mut self) { + debug_assert!(self.inside_frame); + if self.samplers.pending != 0 { + self.gl.end_query(gl::SAMPLES_PASSED); + self.samplers.pending = 0; + } + } + + fn start_timer(&mut self, tag: GpuProfileTag) -> GpuTimeQuery { + self.finish_timer(); + + let marker = GpuMarker::new(&self.gl, tag.label, self.debug_method); + + if let Some(query) = self.timers.add(GpuTimer { tag, time_ns: 0 }) { + self.gl.begin_query(gl::TIME_ELAPSED, query); + } + + GpuTimeQuery(marker) + } + + fn start_sampler(&mut self, tag: GpuProfileTag) -> GpuSampleQuery { + self.finish_sampler(); + + if let Some(query) = self.samplers.add(GpuSampler { tag, count: 0 }) { + self.gl.begin_query(gl::SAMPLES_PASSED, query); + } + + GpuSampleQuery + } + + fn build_samples(&mut self) -> (GpuFrameId, Vec, Vec) { + debug_assert!(!self.inside_frame); + let gl = &self.gl; + + ( + self.frame_id, + self.timers.take(|timer, query| { + timer.time_ns = gl.get_query_object_ui64v(query, gl::QUERY_RESULT) + }), + self.samplers.take(|sampler, query| { + sampler.count = gl.get_query_object_ui64v(query, gl::QUERY_RESULT) + }), + ) + } +} + +impl Drop for GpuFrameProfile { + fn drop(&mut self) { + self.disable_timers(); + self.disable_samplers(); + } +} + +const NUM_PROFILE_FRAMES: usize = 4; + +pub struct GpuProfiler { + gl: Rc, + frames: [GpuFrameProfile; NUM_PROFILE_FRAMES], + next_frame: usize, + debug_method: GpuDebugMethod +} + +impl GpuProfiler { + pub fn new(gl: Rc, debug_method: GpuDebugMethod) -> Self { + let f = || GpuFrameProfile::new(Rc::clone(&gl), debug_method); + + let frames = [f(), f(), f(), f()]; + GpuProfiler { + gl, + next_frame: 0, + frames, + debug_method + } + } + + pub fn enable_timers(&mut self) { + const MAX_TIMERS_PER_FRAME: i32 = 256; + + for frame in &mut self.frames { + frame.enable_timers(MAX_TIMERS_PER_FRAME); + } + } + + pub fn disable_timers(&mut self) { + for frame in &mut self.frames { + frame.disable_timers(); + } + } + + pub fn enable_samplers(&mut self) { + const MAX_SAMPLERS_PER_FRAME: i32 = 16; + if cfg!(target_os = "macos") { + warn!("Expect macOS driver bugs related to sample queries") + } + + for frame in &mut self.frames { + frame.enable_samplers(MAX_SAMPLERS_PER_FRAME); + } + } + + pub fn disable_samplers(&mut self) { + for frame in &mut self.frames { + frame.disable_samplers(); + } + } + + pub fn build_samples(&mut self) -> (GpuFrameId, Vec, Vec) { + self.frames[self.next_frame].build_samples() + } + + pub fn begin_frame(&mut self, frame_id: GpuFrameId) { + self.frames[self.next_frame].begin_frame(frame_id); + } + + pub fn end_frame(&mut self) { + self.frames[self.next_frame].end_frame(); + self.next_frame = (self.next_frame + 1) % self.frames.len(); + } + + pub fn start_timer(&mut self, tag: GpuProfileTag) -> GpuTimeQuery { + self.frames[self.next_frame].start_timer(tag) + } + + pub fn start_sampler(&mut self, tag: GpuProfileTag) -> GpuSampleQuery { + self.frames[self.next_frame].start_sampler(tag) + } + + pub fn finish_sampler(&mut self, _sampler: GpuSampleQuery) { + self.frames[self.next_frame].finish_sampler() + } + + pub fn start_marker(&mut self, label: &str) -> GpuMarker { + GpuMarker::new(&self.gl, label, self.debug_method) + } + + pub fn place_marker(&mut self, label: &str) { + GpuMarker::fire(&self.gl, label, self.debug_method) + } +} + +#[must_use] +pub struct GpuMarker { + gl: Option<(Rc, GpuDebugMethod)>, +} + +impl GpuMarker { + fn new(gl: &Rc, message: &str, debug_method: GpuDebugMethod) -> Self { + let gl = match debug_method { + GpuDebugMethod::KHR => { + gl.push_debug_group_khr(gl::DEBUG_SOURCE_APPLICATION, 0, message); + Some((Rc::clone(gl), debug_method)) + }, + GpuDebugMethod::MarkerEXT => { + gl.push_group_marker_ext(message); + Some((Rc::clone(gl), debug_method)) + }, + GpuDebugMethod::None => None, + }; + GpuMarker { gl } + } + + fn fire(gl: &Rc, message: &str, debug_method: GpuDebugMethod) { + match debug_method { + GpuDebugMethod::KHR => gl.debug_message_insert_khr(gl::DEBUG_SOURCE_APPLICATION, gl::DEBUG_TYPE_MARKER, 0, gl::DEBUG_SEVERITY_NOTIFICATION, message), + GpuDebugMethod::MarkerEXT => gl.insert_event_marker_ext(message), + GpuDebugMethod::None => {} + }; + } +} + +impl Drop for GpuMarker { + fn drop(&mut self) { + if let Some((ref gl, debug_method)) = self.gl { + match debug_method { + GpuDebugMethod::KHR => gl.pop_debug_group_khr(), + GpuDebugMethod::MarkerEXT => gl.pop_group_marker_ext(), + GpuDebugMethod::None => {} + }; + } + } +} + +#[must_use] +pub struct GpuTimeQuery(GpuMarker); +#[must_use] +pub struct GpuSampleQuery; -- cgit v1.2.3