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
30pub struct ComputeShader {
32 raw: RawProgram,
33}
34
35impl ComputeShader {
36 #[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 #[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 #[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 #[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 #[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(); }
91
92 #[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(); }
101
102 #[inline]
107 pub fn get_binary(&self) -> Result<Binary, GetBinaryError> {
108 self.raw.get_binary()
109 }
110
111 #[inline]
113 pub fn get_uniform(&self, name: &str) -> Option<&Uniform> {
114 self.raw.get_uniform(name)
115 }
116
117 #[inline]
129 pub fn uniforms(&self) -> hash_map::Iter<'_, String, Uniform> {
130 self.raw.uniforms()
131 }
132
133 #[inline]
145 pub fn get_uniform_blocks(&self)
146 -> &HashMap<String, UniformBlock, BuildHasherDefault<FnvHasher>> {
147 self.raw.get_uniform_blocks()
148 }
149
150 #[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#[repr(C)]
250#[derive(Debug, Copy, Clone)]
251pub struct ComputeCommand {
252 pub num_groups_x: raw::c_uint,
254 pub num_groups_y: raw::c_uint,
256 pub num_groups_z: raw::c_uint,
258}
259
260implement_uniform_block!(ComputeCommand, num_groups_x, num_groups_y, num_groups_z);