1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
use std::{ops::Range, thread::ThreadId};

use crate::profiler::{
    GpuTimerQueryTreeHandle, QueryPairUsageState, ReservedTimerQueryPair, ROOT_QUERY_HANDLE,
};

/// The result of a gpu timer scope.
#[derive(Debug, Clone)]
pub struct GpuTimerQueryResult {
    /// Label that was specified when opening the scope.
    pub label: String,

    /// The process id of the process that opened this scope.
    pub pid: u32,

    /// The thread id of the thread that opened this scope.
    pub tid: ThreadId,

    /// Time range of this scope in seconds.
    ///
    /// Meaning of absolute value is not defined.
    pub time: Range<f64>,

    /// Scopes that were opened while this scope was open.
    pub nested_queries: Vec<GpuTimerQueryResult>,
}

/// An inflight query for the profiler.
///
/// If timer queries are enabled, this represents a reserved timer query pair on
/// one of the profiler's query sets.
/// *Must* be closed by calling [`GpuProfiler::end_query`].
///
/// Emitted by [`GpuProfiler::begin_query`]/[`GpuProfiler::begin_pass_query`] and consumed by [`GpuProfiler::end_query`].
pub struct GpuProfilerQuery {
    /// The label assigned to this query.
    /// Will be moved into [`GpuProfilerQuery::label`] once the query is fully processed.
    pub label: String,

    /// The process id of the process that opened this query.
    pub pid: u32,

    /// The thread id of the thread that opened this query.
    pub tid: ThreadId,

    /// The actual query on a query pool if any (none if disabled for this type of query).
    pub(crate) timer_query_pair: Option<ReservedTimerQueryPair>,

    /// Handle which identifies this query, used for building the tree of queries.
    pub(crate) handle: GpuTimerQueryTreeHandle,

    /// Which query this query is a child of.
    pub(crate) parent_handle: GpuTimerQueryTreeHandle,

    /// Whether a debug group was opened for this scope.
    pub(crate) has_debug_group: bool,

    #[cfg(feature = "tracy")]
    pub(crate) tracy_scope: Option<tracy_client::GpuSpan>,
}

impl GpuProfilerQuery {
    /// Use the reserved query for render pass timestamp writes if any.
    ///
    /// Use this only for a single render/compute pass, otherwise results will be overwritten.
    /// Only ever returns `Some` for queries that were created using [`GpuProfiler::begin_pass_query`].
    pub fn render_pass_timestamp_writes(&self) -> Option<wgpu::RenderPassTimestampWrites> {
        self.timer_query_pair.as_ref().and_then(|query| {
            (query.usage_state == QueryPairUsageState::ReservedForPassTimestampWrites).then(|| {
                wgpu::RenderPassTimestampWrites {
                    query_set: &query.pool.query_set,
                    beginning_of_pass_write_index: Some(query.start_query_idx),
                    end_of_pass_write_index: Some(query.start_query_idx + 1),
                }
            })
        })
    }

    /// Use the reserved query for compute pass timestamp writes if any.
    ///
    /// Use this only for a single render/compute pass, otherwise results will be overwritten.
    /// Only ever returns `Some` for queries that were created using [`GpuProfiler::begin_pass_query`].
    pub fn compute_pass_timestamp_writes(&self) -> Option<wgpu::ComputePassTimestampWrites> {
        self.timer_query_pair.as_ref().and_then(|query| {
            (query.usage_state == QueryPairUsageState::ReservedForPassTimestampWrites).then(|| {
                wgpu::ComputePassTimestampWrites {
                    query_set: &query.pool.query_set,
                    beginning_of_pass_write_index: Some(query.start_query_idx),
                    end_of_pass_write_index: Some(query.start_query_idx + 1),
                }
            })
        })
    }

    /// Makes this scope a child of the passed scope.
    #[inline]
    pub fn with_parent(self, parent: Option<&GpuProfilerQuery>) -> Self {
        Self {
            parent_handle: parent.map_or(ROOT_QUERY_HANDLE, |p| p.handle),
            ..self
        }
    }
}