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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
use crate::__gl;
use crate::__gl::types::GLuint;

use crate::device::Device;

///
#[repr(u32)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum QueryType {
    ///
    Timestamp = __gl::TIMESTAMP,
    ///
    TimeElapsed = __gl::TIME_ELAPSED,
    ///
    Occlusion = __gl::ANY_SAMPLES_PASSED,
    ///
    OcclusionConservative = __gl::ANY_SAMPLES_PASSED_CONSERVATIVE,
    ///
    OcclusionPrecision = __gl::SAMPLES_PASSED,
    ///
    InputAssemblyVertices = __gl::VERTICES_SUBMITTED,
    ///
    InputAssemblyPrimitives = __gl::PRIMITIVES_SUBMITTED,
    /// Number of vertex shader invocations.
    VertexShaderInvocations = __gl::VERTEX_SHADER_INVOCATIONS,
    /// Number of geometry shader invocations.
    GeometryShaderInvocations = __gl::GEOMETRY_SHADER_INVOCATIONS,
    ///
    GeometryShaderPrimitives = __gl::GEOMETRY_SHADER_PRIMITIVES_EMITTED,
    ///
    TransformFeedbackPrimitivesWritten = __gl::TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN,
    ///
    TransformFeedbackOverflow = __gl::TRANSFORM_FEEDBACK_OVERFLOW,
    ///
    TransformFeedbackStreamOverflow = __gl::TRANSFORM_FEEDBACK_STREAM_OVERFLOW,
    /// Number of input primitives for the primitive clipping stage.
    ClippingInvocations = __gl::CLIPPING_INPUT_PRIMITIVES,
    /// Number of output primitives for the primitive clipping stage.
    ClippingPrimitives = __gl::CLIPPING_OUTPUT_PRIMITIVES,
    /// Number of fragment shader invocations.
    FragmentShaderInvocations = __gl::FRAGMENT_SHADER_INVOCATIONS,
    /// Number of patches processed by tessellation control shader.
    TessellationControlShaderPatches = __gl::TESS_CONTROL_SHADER_PATCHES,
    /// Number of tessellation evaluation shader invocations.
    TessellationEvaluationShaderInvocations = __gl::TESS_EVALUATION_SHADER_INVOCATIONS,
    /// Number of compute shader invocations.
    ComputeShaderInvocations = __gl::COMPUTE_SHADER_INVOCATIONS,
}

bitflags!(
    pub struct QueryResultFlags: u8 {
        const WAIT = 0x1;
    }
);

///
#[repr(u32)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum ConditionalMode {
    ///
    NoWait = __gl::QUERY_NO_WAIT,
    ///
    NoWaitInverted = __gl::QUERY_NO_WAIT_INVERTED,
    /// Wait for query results available.
    Wait = __gl::QUERY_WAIT,
    /// Wait for query results available (inverted condition).
    WaitInverted = __gl::QUERY_WAIT_INVERTED,
    ///
    WaitByRegion = __gl::QUERY_BY_REGION_WAIT,
    ///
    WaitByRegionInverted = __gl::QUERY_BY_REGION_WAIT_INVERTED,
}

#[derive(Clone, Copy)]
pub struct Query {
    raw: GLuint,
    ty: QueryType,
}

impl Device {
    pub unsafe fn create_query(&self, ty: QueryType) -> Query {
        let mut query = 0;
        self.0.CreateQueries(ty as _, 1, &mut query as *mut _);
        Query { raw: query, ty }
    }

    pub unsafe fn begin_query(&self, query: Query) {
        #[allow(clippy::match_single_binding)]
        let index = match query.ty {
            _ => 0,
        };

        self.0.BeginQueryIndexed(query.ty as _, index, query.raw);
    }

    pub unsafe fn end_query(&self, query: Query) {
        #[allow(clippy::match_single_binding)]
        let index = match query.ty {
            _ => 0,
        };

        self.0.EndQueryIndexed(query.ty as _, index);
    }

    pub unsafe fn write_timestamp(&self, query: Query) {
        self.0.QueryCounter(query.raw, __gl::TIMESTAMP);
    }

    pub unsafe fn get_query_result_u32(&self, query: Query, flags: QueryResultFlags) -> u32 {
        let mut result = 0;
        let flags = if flags.contains(QueryResultFlags::WAIT) {
            __gl::QUERY_RESULT
        } else {
            __gl::QUERY_RESULT_NO_WAIT
        };
        self.0.GetQueryObjectuiv(query.raw, flags, &mut result);
        result
    }

    pub unsafe fn get_query_result_u64(&self, query: Query, flags: QueryResultFlags) -> u64 {
        let mut result = 0;
        let flags = if flags.contains(QueryResultFlags::WAIT) {
            __gl::QUERY_RESULT
        } else {
            __gl::QUERY_RESULT_NO_WAIT
        };
        self.0.GetQueryObjectui64v(query.raw, flags, &mut result);
        result
    }

    pub unsafe fn begin_conditional_rendering(&self, query: Query, mode: ConditionalMode) {
        self.0.BeginConditionalRender(query.raw, mode as _);
    }

    pub unsafe fn end_conditional_rendering(&self) {
        self.0.EndConditionalRender();
    }
}