glium/program/
compute.rs

1use crate::gl;
2
3use crate::context::CommandContext;
4use crate::backend::Facade;
5
6use std::fmt;
7use std::collections::hash_map::{self, HashMap};
8use std::os::raw;
9use std::hash::BuildHasherDefault;
10
11use fnv::FnvHasher;
12
13use crate::CapabilitiesSource;
14use crate::GlObject;
15use crate::ProgramExt;
16use crate::Handle;
17use crate::RawUniformValue;
18
19use crate::program::{COMPILER_GLOBAL_LOCK, ProgramCreationError, Binary, GetBinaryError, SpirvEntryPoint};
20
21use crate::program::reflection::{Uniform, UniformBlock};
22use crate::program::reflection::{ShaderStage, SubroutineData};
23use crate::program::shader::{build_shader, build_spirv_shader, check_shader_type_compatibility};
24
25use crate::program::raw::RawProgram;
26
27use crate::buffer::BufferSlice;
28use crate::uniforms::Uniforms;
29
30/// A combination of compute shaders linked together.
31pub struct ComputeShader {
32    raw: RawProgram,
33}
34
35impl ComputeShader {
36    /// Returns true if the backend supports compute shaders.
37    #[inline]
38    pub fn is_supported<C: ?Sized>(ctxt: &C) -> bool where C: CapabilitiesSource {
39        check_shader_type_compatibility(ctxt, gl::COMPUTE_SHADER)
40    }
41
42    /// Builds a new compute shader from some source code.
43    #[inline]
44    pub fn from_source<F: ?Sized>(facade: &F, src: &str) -> Result<ComputeShader, ProgramCreationError>
45                          where F: Facade
46    {
47        let _lock = COMPILER_GLOBAL_LOCK.lock();
48
49        let shader = build_shader(facade, gl::COMPUTE_SHADER, src)?;
50
51        Ok(ComputeShader {
52            raw: RawProgram::from_shaders(facade, &[shader], false, false, false, None)?
53        })
54    }
55
56    /// Builds a new compute shader from SPIR-V module.
57    #[inline]
58    pub fn from_spirv<F: ?Sized>(facade: &F, spirv: &SpirvEntryPoint) -> Result<ComputeShader, ProgramCreationError>
59                          where F: Facade
60    {
61        let _lock = COMPILER_GLOBAL_LOCK.lock();
62
63        let shader = build_spirv_shader(facade, gl::COMPUTE_SHADER, spirv)?;
64
65        Ok(ComputeShader {
66            raw: RawProgram::from_shaders(facade, &[shader], false, false, false, None)?
67        })
68    }
69
70    /// Builds a new compute shader from some binary.
71    #[inline]
72    pub fn from_binary<F: ?Sized>(facade: &F, data: Binary) -> Result<ComputeShader, ProgramCreationError>
73                          where F: Facade
74    {
75        let _lock = COMPILER_GLOBAL_LOCK.lock();
76
77        Ok(ComputeShader {
78            raw: RawProgram::from_binary(facade, data)?
79        })
80    }
81
82    /// Executes the compute shader.
83    ///
84    /// `x * y * z` work groups will be started. The current work group can be retrieved with
85    /// `gl_WorkGroupID`. Inside each work group, additional local work groups can be started
86    /// depending on the attributes of the compute shader itself.
87    #[inline]
88    pub fn execute<U>(&self, uniforms: U, x: u32, y: u32, z: u32) where U: Uniforms {
89        unsafe { self.raw.dispatch_compute(uniforms, x, y, z) }.unwrap();       // FIXME: return error
90    }
91
92    /// Executes the compute shader.
93    ///
94    /// This is similar to `execute`, except that the parameters are stored in a buffer.
95    #[inline]
96    pub fn execute_indirect<U>(&self, uniforms: U, buffer: BufferSlice<'_, ComputeCommand>)
97                               where U: Uniforms
98    {
99        unsafe { self.raw.dispatch_compute_indirect(uniforms, buffer) }.unwrap();       // FIXME: return error
100    }
101
102    /// Returns the program's compiled binary.
103    ///
104    /// You can store the result in a file, then reload it later. This avoids having to compile
105    /// the source code every time.
106    #[inline]
107    pub fn get_binary(&self) -> Result<Binary, GetBinaryError> {
108        self.raw.get_binary()
109    }
110
111    /// Returns informations about a uniform variable, if it exists.
112    #[inline]
113    pub fn get_uniform(&self, name: &str) -> Option<&Uniform> {
114        self.raw.get_uniform(name)
115    }
116
117    /// Returns an iterator to the list of uniforms.
118    ///
119    /// ## Example
120    ///
121    /// ```no_run
122    /// # fn example(program: glium::Program) {
123    /// for (name, uniform) in program.uniforms() {
124    ///     println!("Name: {} - Type: {:?}", name, uniform.ty);
125    /// }
126    /// # }
127    /// ```
128    #[inline]
129    pub fn uniforms(&self) -> hash_map::Iter<'_, String, Uniform> {
130        self.raw.uniforms()
131    }
132
133    /// Returns a list of uniform blocks.
134    ///
135    /// ## Example
136    ///
137    /// ```no_run
138    /// # fn example(program: glium::Program) {
139    /// for (name, uniform) in program.get_uniform_blocks() {
140    ///     println!("Name: {}", name);
141    /// }
142    /// # }
143    /// ```
144    #[inline]
145    pub fn get_uniform_blocks(&self)
146                              -> &HashMap<String, UniformBlock, BuildHasherDefault<FnvHasher>> {
147        self.raw.get_uniform_blocks()
148    }
149
150    /// Returns the list of shader storage blocks.
151    ///
152    /// ## Example
153    ///
154    /// ```no_run
155    /// fn example(program: glium::Program) {
156    /// for (name, uniform) in program.get_shader_storage_blocks() {
157    ///     println!("Name: {}", name);
158    /// }
159    /// # }
160    /// ```
161    #[inline]
162    pub fn get_shader_storage_blocks(&self)
163            -> &HashMap<String, UniformBlock, BuildHasherDefault<FnvHasher>> {
164        self.raw.get_shader_storage_blocks()
165    }
166}
167
168impl fmt::Debug for ComputeShader {
169    #[inline]
170    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
171        write!(formatter, "{:?}", self.raw)
172    }
173}
174
175impl GlObject for ComputeShader {
176    type Id = Handle;
177
178    #[inline]
179    fn get_id(&self) -> Handle {
180        self.raw.get_id()
181    }
182}
183
184impl ProgramExt for ComputeShader {
185    #[inline]
186    fn use_program(&self, ctxt: &mut CommandContext<'_>) {
187        self.raw.use_program(ctxt)
188    }
189
190    #[inline]
191    fn set_uniform(&self, ctxt: &mut CommandContext<'_>, uniform_location: gl::types::GLint,
192                   value: &RawUniformValue)
193    {
194        self.raw.set_uniform(ctxt, uniform_location, value)
195    }
196
197    #[inline]
198    fn set_uniform_block_binding(&self, ctxt: &mut CommandContext<'_>, block_location: gl::types::GLuint,
199                                 value: gl::types::GLuint)
200    {
201        self.raw.set_uniform_block_binding(ctxt, block_location, value)
202    }
203
204    #[inline]
205    fn set_shader_storage_block_binding(&self, ctxt: &mut CommandContext<'_>,
206                                        block_location: gl::types::GLuint,
207                                        value: gl::types::GLuint)
208    {
209        self.raw.set_shader_storage_block_binding(ctxt, block_location, value)
210    }
211
212    #[inline]
213    fn set_subroutine_uniforms_for_stage(&self, ctxt: &mut CommandContext<'_>,
214                                         stage: ShaderStage,
215                                         indices: &[gl::types::GLuint])
216    {
217        self.raw.set_subroutine_uniforms_for_stage(ctxt, stage, indices);
218    }
219
220    #[inline]
221    fn get_uniform(&self, name: &str) -> Option<&Uniform> {
222        self.raw.get_uniform(name)
223    }
224
225    #[inline]
226    fn get_uniform_blocks(&self) -> &HashMap<String, UniformBlock, BuildHasherDefault<FnvHasher>> {
227        self.raw.get_uniform_blocks()
228    }
229
230    #[inline]
231    fn get_shader_storage_blocks(&self)
232                                 -> &HashMap<String, UniformBlock, BuildHasherDefault<FnvHasher>> {
233        self.raw.get_shader_storage_blocks()
234    }
235
236    #[inline]
237    fn get_atomic_counters(&self)
238                                 -> &HashMap<String, UniformBlock, BuildHasherDefault<FnvHasher>> {
239        self.raw.get_atomic_counters()
240    }
241
242    #[inline]
243    fn get_subroutine_data(&self) -> &SubroutineData {
244        self.raw.get_subroutine_data()
245    }
246}
247
248/// Represents a compute shader command waiting to be dispatched.
249#[repr(C)]
250#[derive(Debug, Copy, Clone)]
251pub struct ComputeCommand {
252    /// Number of X groups.
253    pub num_groups_x: raw::c_uint,
254    /// Number of Y groups.
255    pub num_groups_y: raw::c_uint,
256    /// Number of Z groups.
257    pub num_groups_z: raw::c_uint,
258}
259
260implement_uniform_block!(ComputeCommand, num_groups_x, num_groups_y, num_groups_z);