1use super::buffer::{Buffer, BufferError};
4use crate::webgl2::{state::WebGL2State, WebGL2};
5use luminance::{
6 backend::shader::{Shader, ShaderData, Uniformable},
7 pipeline::{ShaderDataBinding, TextureBinding},
8 pixel::{SamplerType, Type as PixelType},
9 shader::{
10 types::{Arr, Mat22, Mat33, Mat44, Vec2, Vec3, Vec4},
11 ProgramError, ShaderDataError, StageError, StageType, TessellationStages, Uniform, UniformType,
12 UniformWarning, VertexAttribWarning,
13 },
14 texture::{Dim, Dimensionable},
15 vertex::Semantics,
16};
17use luminance_std140::{ArrElem, Std140};
18use std::{cell::RefCell, collections::HashMap, mem, rc::Rc};
19use web_sys::{WebGl2RenderingContext, WebGlProgram, WebGlShader, WebGlUniformLocation};
20
21#[derive(Debug)]
22pub struct Stage {
23 handle: WebGlShader,
24 ty: StageType,
25 state: Rc<RefCell<WebGL2State>>,
26}
27
28impl Drop for Stage {
29 fn drop(&mut self) {
30 self.state.borrow().ctx.delete_shader(Some(&self.handle));
31 }
32}
33
34impl Stage {
35 fn new(webgl2: &mut WebGL2, ty: StageType, src: &str) -> Result<Self, StageError> {
36 let state = webgl2.state.borrow();
37
38 let shader_ty = webgl_shader_type(ty)
39 .ok_or_else(|| StageError::CompilationFailed(ty, "unsupported shader type".to_owned()))?;
40
41 let handle = state.ctx.create_shader(shader_ty).ok_or_else(|| {
42 StageError::CompilationFailed(ty, "unable to create shader stage".to_owned())
43 })?;
44
45 state.ctx.shader_source(&handle, &patch_shader_src(src));
46 state.ctx.compile_shader(&handle);
47
48 let compiled = state
49 .ctx
50 .get_shader_parameter(&handle, WebGl2RenderingContext::COMPILE_STATUS)
51 .as_bool()
52 .ok_or_else(|| {
53 StageError::CompilationFailed(ty, "cannot determine compilation status".to_owned())
54 })?;
55
56 if compiled {
57 Ok(Stage {
58 handle,
59 ty,
60 state: webgl2.state.clone(),
61 })
62 } else {
63 let log = state
64 .ctx
65 .get_shader_info_log(&handle)
66 .ok_or_else(|| StageError::CompilationFailed(ty, "no compilation error".to_owned()))?;
67
68 state.ctx.delete_shader(Some(&handle));
69
70 Err(StageError::compilation_failed(ty, log))
71 }
72 }
73
74 fn handle(&self) -> &WebGlShader {
75 &self.handle
76 }
77}
78
79type LocationMap = HashMap<i32, WebGlUniformLocation>;
84
85#[derive(Debug)]
86pub struct Program {
87 pub(crate) handle: WebGlProgram,
88 location_map: Rc<RefCell<LocationMap>>,
89 state: Rc<RefCell<WebGL2State>>,
90}
91
92impl Drop for Program {
93 fn drop(&mut self) {
94 self.state.borrow().ctx.delete_program(Some(&self.handle));
95 }
96}
97
98impl Program {
99 fn new(
100 webgl2: &mut WebGL2,
101 vertex: &Stage,
102 tess: Option<TessellationStages<Stage>>,
103 geometry: Option<&Stage>,
104 fragment: &Stage,
105 ) -> Result<Self, ProgramError> {
106 let state = webgl2.state.borrow();
107
108 let handle = state.ctx.create_program().ok_or_else(|| {
109 ProgramError::CreationFailed("unable to allocate GPU shader program".to_owned())
110 })?;
111
112 if let Some(TessellationStages {
113 control,
114 evaluation,
115 }) = tess
116 {
117 state.ctx.attach_shader(&handle, control.handle());
118 state.ctx.attach_shader(&handle, evaluation.handle());
119 }
120
121 state.ctx.attach_shader(&handle, vertex.handle());
122
123 if let Some(geometry) = geometry {
124 state.ctx.attach_shader(&handle, geometry.handle());
125 }
126
127 state.ctx.attach_shader(&handle, fragment.handle());
128
129 let location_map = Rc::new(RefCell::new(HashMap::new()));
130 let state = webgl2.state.clone();
131 let program = Program {
132 handle,
133 location_map,
134 state,
135 };
136
137 program.link().map(move |_| program)
138 }
139
140 fn link(&self) -> Result<(), ProgramError> {
141 let handle = &self.handle;
142 let state = self.state.borrow();
143
144 state.ctx.link_program(handle);
145
146 let linked = state
147 .ctx
148 .get_program_parameter(handle, WebGl2RenderingContext::LINK_STATUS)
149 .as_bool()
150 .ok_or_else(|| ProgramError::LinkFailed("unknown link status".to_owned()))?;
151
152 if linked {
153 Ok(())
154 } else {
155 let log = state
156 .ctx
157 .get_program_info_log(handle)
158 .unwrap_or("unknown link error".to_owned());
159 Err(ProgramError::link_failed(log))
160 }
161 }
162
163 fn handle(&self) -> &WebGlProgram {
164 &self.handle
165 }
166}
167
168pub struct UniformBuilder {
169 handle: WebGlProgram,
170 location_map: Rc<RefCell<LocationMap>>,
171 state: Rc<RefCell<WebGL2State>>,
172}
173
174impl UniformBuilder {
175 fn new(program: &Program) -> Self {
176 UniformBuilder {
177 handle: program.handle.clone(),
178 location_map: program.location_map.clone(),
179 state: program.state.clone(),
180 }
181 }
182
183 fn ask_uniform<T>(
184 &mut self,
185 name: &str,
186 ty: UniformType,
187 size: usize,
188 ) -> Result<Uniform<T>, UniformWarning>
189 where
190 WebGL2: for<'a> Uniformable<'a, T>,
191 {
192 let location = self
193 .state
194 .borrow()
195 .ctx
196 .get_uniform_location(&self.handle, name);
197
198 match location {
199 Some(location) => {
200 let mut location_map = self.location_map.borrow_mut();
203 let idx = location_map.len() as i32;
204 location_map.insert(idx, location);
205
206 uniform_type_match(
208 &self.state.borrow(),
209 &self.handle,
210 name,
211 idx as u32,
212 ty,
213 size,
214 )?;
215
216 Ok(unsafe { Uniform::new(idx) })
217 }
218
219 None => Err(UniformWarning::inactive(name)),
220 }
221 }
222
223 fn ask_uniform_block<T>(&self, name: &str) -> Result<Uniform<T>, UniformWarning>
224 where
225 WebGL2: for<'a> Uniformable<'a, T>,
226 {
227 let location = self
228 .state
229 .borrow()
230 .ctx
231 .get_uniform_block_index(&self.handle, name);
232
233 if location == WebGl2RenderingContext::INVALID_INDEX {
234 Err(UniformWarning::inactive(name))
235 } else {
236 Ok(unsafe { Uniform::new(location as _) })
237 }
238 }
239}
240
241unsafe impl Shader for WebGL2 {
242 type StageRepr = Stage;
243
244 type ProgramRepr = Program;
245
246 type UniformBuilderRepr = UniformBuilder;
247
248 unsafe fn new_stage(&mut self, ty: StageType, src: &str) -> Result<Self::StageRepr, StageError> {
249 Stage::new(self, ty, src)
250 }
251
252 unsafe fn new_program(
253 &mut self,
254 vertex: &Self::StageRepr,
255 tess: Option<TessellationStages<Self::StageRepr>>,
256 geometry: Option<&Self::StageRepr>,
257 fragment: &Self::StageRepr,
258 ) -> Result<Self::ProgramRepr, ProgramError> {
259 Program::new(self, vertex, tess, geometry, fragment)
260 }
261
262 unsafe fn apply_semantics<Sem>(
263 program: &mut Self::ProgramRepr,
264 ) -> Result<Vec<VertexAttribWarning>, ProgramError>
265 where
266 Sem: Semantics,
267 {
268 let warnings = {
269 let state = program.state.borrow();
270 bind_vertex_attribs_locations::<Sem>(&state, program)
271 };
272
273 program.link()?;
275 Ok(warnings)
276 }
277
278 unsafe fn new_uniform_builder(
279 program: &mut Self::ProgramRepr,
280 ) -> Result<Self::UniformBuilderRepr, ProgramError> {
281 Ok(UniformBuilder::new(&program))
282 }
283
284 unsafe fn ask_uniform<T>(
285 uniform_builder: &mut Self::UniformBuilderRepr,
286 name: &str,
287 ) -> Result<Uniform<T>, UniformWarning>
288 where
289 Self: for<'a> Uniformable<'a, T>,
290 {
291 let ty = Self::ty();
292 let uniform = match ty {
293 UniformType::ShaderDataBinding => uniform_builder.ask_uniform_block(name)?,
294 _ => uniform_builder.ask_uniform(name, ty, Self::SIZE)?,
295 };
296
297 Ok(uniform)
298 }
299
300 unsafe fn unbound<T>(_: &mut Self::UniformBuilderRepr) -> Uniform<T>
301 where
302 Self: for<'a> Uniformable<'a, T>,
303 {
304 Uniform::new(-1)
305 }
306}
307
308fn webgl_shader_type(ty: StageType) -> Option<u32> {
309 match ty {
310 StageType::VertexShader => Some(WebGl2RenderingContext::VERTEX_SHADER),
311 StageType::FragmentShader => Some(WebGl2RenderingContext::FRAGMENT_SHADER),
312 _ => None,
313 }
314}
315
316const GLSL_PRAGMA: &str = "#version 300 es\n\
317 precision highp float;\n\
318 precision highp int;
319 layout(std140) uniform;\n";
320
321fn patch_shader_src(src: &str) -> String {
322 let mut pragma = String::from(GLSL_PRAGMA);
323 pragma.push_str(src);
324 pragma
325}
326
327fn uniform_type_match(
328 state: &WebGL2State,
329 program: &WebGlProgram,
330 name: &str,
331 location: u32,
332 ty: UniformType,
333 size: usize,
334) -> Result<(), UniformWarning> {
335 let index = if ty == UniformType::ShaderDataBinding {
338 location
339 } else {
340 let name_array = js_sys::Array::new();
342 name_array.push(&name.into()); state
347 .ctx
348 .get_uniform_indices(program, name_array.as_ref())
349 .ok_or_else(|| UniformWarning::TypeMismatch("cannot retrieve uniform index".to_owned(), ty))?
350 .get(0)
351 .as_f64()
352 .map(|x| x as u32)
353 .ok_or_else(|| {
354 UniformWarning::TypeMismatch("wrong type when retrieving uniform".to_owned(), ty)
355 })?
356 };
357
358 let info = state
360 .ctx
361 .get_active_uniform(program, index)
362 .ok_or_else(|| UniformWarning::TypeMismatch("cannot retrieve active uniform".to_owned(), ty))?;
363
364 let found_size = info.size() as usize;
365 if size > 0 && found_size != size {
366 return Err(UniformWarning::size_mismatch(name, size, found_size));
367 }
368
369 check_types_match(name, ty, info.type_())
370}
371
372#[allow(clippy::cognitive_complexity)]
373fn check_types_match(name: &str, ty: UniformType, glty: u32) -> Result<(), UniformWarning> {
374 macro_rules! milkcheck {
376 ($ty:expr, $( ( $v:tt, $t:tt ) ),* $(,)?) => {
377 match $ty {
378 $(
379 UniformType::$v => {
380 if glty == WebGl2RenderingContext::$t {
381 Ok(())
382 } else {
383 Err(UniformWarning::type_mismatch(name, ty))
384 }
385 }
386 )*
387
388 _ => Err(UniformWarning::unsupported_type(name, ty))
389 }
390 }
391 }
392
393 milkcheck!(
394 ty,
395 (Int, INT),
397 (UInt, UNSIGNED_INT),
398 (Float, FLOAT),
399 (Bool, BOOL),
400 (IVec2, INT_VEC2),
402 (IVec3, INT_VEC3),
403 (IVec4, INT_VEC4),
404 (UIVec2, UNSIGNED_INT_VEC2),
405 (UIVec3, UNSIGNED_INT_VEC3),
406 (UIVec4, UNSIGNED_INT_VEC4),
407 (Vec2, FLOAT_VEC2),
408 (Vec3, FLOAT_VEC3),
409 (Vec4, FLOAT_VEC4),
410 (BVec2, BOOL_VEC2),
411 (BVec3, BOOL_VEC3),
412 (BVec4, BOOL_VEC4),
413 (M22, FLOAT_MAT2),
415 (M33, FLOAT_MAT3),
416 (M44, FLOAT_MAT4),
417 (ISampler2D, INT_SAMPLER_2D),
419 (ISampler3D, INT_SAMPLER_3D),
420 (ISampler2DArray, INT_SAMPLER_2D_ARRAY),
421 (UISampler2D, UNSIGNED_INT_SAMPLER_2D),
422 (UISampler3D, UNSIGNED_INT_SAMPLER_3D),
423 (UISampler2DArray, UNSIGNED_INT_SAMPLER_2D_ARRAY),
424 (Sampler2D, SAMPLER_2D),
425 (Sampler3D, SAMPLER_3D),
426 (Sampler2DArray, SAMPLER_2D_ARRAY),
427 (ICubemap, INT_SAMPLER_CUBE),
428 (UICubemap, UNSIGNED_INT_SAMPLER_CUBE),
429 (Cubemap, SAMPLER_CUBE),
430 )
431}
432
433fn bind_vertex_attribs_locations<Sem>(
434 state: &WebGL2State,
435 program: &Program,
436) -> Vec<VertexAttribWarning>
437where
438 Sem: Semantics,
439{
440 let mut warnings = Vec::new();
441
442 for desc in Sem::semantics_set() {
443 match get_vertex_attrib_location(state, program, &desc.name) {
444 Ok(_) => {
445 let index = desc.index as u32;
446 state
447 .ctx
448 .bind_attrib_location(program.handle(), index, &desc.name);
449 }
450
451 Err(warning) => warnings.push(warning),
452 }
453 }
454
455 warnings
456}
457
458fn get_vertex_attrib_location(
459 state: &WebGL2State,
460 program: &Program,
461 name: &str,
462) -> Result<i32, VertexAttribWarning> {
463 let location = state.ctx.get_attrib_location(program.handle(), name);
464
465 if location < 0 {
466 Err(VertexAttribWarning::inactive(name))
467 } else {
468 Ok(location)
469 }
470}
471
472macro_rules! impl_Uniformable {
477 (vec arr $q:ident $t:ty, $size:expr, $uty:tt, $f:tt) => {
478 unsafe impl<'a, const N: usize> Uniformable<'a, Arr<$q<$t>, N>> for WebGL2 {
479 type Target = &'a [$q<$t>; N];
480
481 const SIZE: usize = N;
482
483 unsafe fn ty() -> UniformType {
484 UniformType::$uty
485 }
486
487 unsafe fn update(
488 program: &mut Program,
489 uniform: &'a Uniform<Arr<$q<$t>, N>>,
490 value: Self::Target,
491 ) {
492 let len = value.len();
493 let data = flatten_slice!(value: $t, len = $size * N);
494
495 program.state.borrow().ctx.$f(
496 program.location_map.borrow().get(&uniform.index()),
497 data,
498 0, len as _,
500 );
501 }
502 }
503 };
504
505 (arr $t:ty , $uty:tt, $f:tt) => {
506 unsafe impl<'a, const N: usize> Uniformable<'a, Arr<$t, N>> for WebGL2 {
507 type Target = &'a [$t; N];
508
509 const SIZE: usize = N;
510
511 unsafe fn ty() -> UniformType {
512 UniformType::$uty
513 }
514
515 unsafe fn update(
516 program: &mut Program,
517 uniform: &'a Uniform<Arr<$t, N>>,
518 value: Self::Target,
519 ) {
520 program
521 .state
522 .borrow()
523 .ctx
524 .$f(program.location_map.borrow().get(&uniform.index()), value);
525 }
526 }
527 };
528
529 (vec $t:ty, $uty:tt, $f:tt) => {
530 unsafe impl<'a> Uniformable<'a, $t> for WebGL2 {
531 type Target = $t;
532
533 const SIZE: usize = 1;
534
535 unsafe fn ty() -> UniformType {
536 UniformType::$uty
537 }
538
539 unsafe fn update(program: &mut Program, uniform: &'a Uniform<$t>, value: Self::Target) {
540 program.state.borrow().ctx.$f(
541 program.location_map.borrow().get(&uniform.index()),
542 value.as_ref(),
543 );
544 }
545 }
546 };
547
548 ($t:ty, $uty:tt, $f:tt) => {
549 unsafe impl<'a> Uniformable<'a, $t> for WebGL2 {
550 type Target = $t;
551
552 const SIZE: usize = 1;
553
554 unsafe fn ty() -> UniformType {
555 UniformType::$uty
556 }
557
558 unsafe fn update(program: &mut Program, uniform: &'a Uniform<$t>, value: Self::Target) {
559 program
560 .state
561 .borrow()
562 .ctx
563 .$f(program.location_map.borrow().get(&uniform.index()), value);
564 }
565 }
566 };
567
568 (mat arr $q:ident $t:ty, $size:expr, $uty:tt, $f:tt) => {
570 unsafe impl<'a, const N: usize> Uniformable<'a, Arr<$q<$t>, N>> for WebGL2 {
571 type Target = &'a [$q<$t>; N];
572
573 const SIZE: usize = N;
574
575 unsafe fn ty() -> UniformType {
576 UniformType::$uty
577 }
578
579 unsafe fn update(
580 program: &mut Program,
581 uniform: &'a Uniform<Arr<$q<$t>, N>>,
582 value: Self::Target,
583 ) {
584 let data = flatten_slice!(value: $t, len = $size * N);
585
586 program.state.borrow().ctx.$f(
587 program.location_map.borrow().get(&uniform.index()),
588 false,
589 data,
590 0,
591 value.len() as u32,
592 );
593 }
594 }
595 };
596
597 (mat $q:ident $t:ty, $size:expr, $uty:tt, $f:tt) => {
598 unsafe impl<'a> Uniformable<'a, $q<$t>> for WebGL2 {
599 type Target = $q<$t>;
600
601 const SIZE: usize = 1;
602
603 unsafe fn ty() -> UniformType {
604 UniformType::$uty
605 }
606
607 unsafe fn update(program: &mut Program, uniform: &'a Uniform<$q<$t>>, value: Self::Target) {
608 let data = flatten_slice!(value: $t, len = $size);
609
610 program.state.borrow().ctx.$f(
611 program.location_map.borrow().get(&uniform.index()),
612 false,
613 data,
614 );
615 }
616 }
617 };
618}
619
620impl_Uniformable!(i32, Int, uniform1i);
622impl_Uniformable!(vec Vec2<i32>, IVec2, uniform2iv_with_i32_array);
623impl_Uniformable!(vec Vec3<i32>, IVec3, uniform3iv_with_i32_array);
624impl_Uniformable!(vec Vec4<i32>, IVec4, uniform4iv_with_i32_array);
625impl_Uniformable!(arr i32, Int, uniform1iv_with_i32_array);
626impl_Uniformable!(
627 vec arr Vec2 i32,
628 2,
629 IVec2,
630 uniform2iv_with_i32_array_and_src_offset_and_src_length
631);
632impl_Uniformable!(
633 vec arr Vec3 i32,
634 3,
635 IVec3,
636 uniform3iv_with_i32_array_and_src_offset_and_src_length
637);
638impl_Uniformable!(
639 vec arr Vec4 i32,
640 4,
641 IVec4,
642 uniform4iv_with_i32_array_and_src_offset_and_src_length
643);
644
645impl_Uniformable!(u32, UInt, uniform1ui);
646impl_Uniformable!(vec Vec2<u32>, UIVec2, uniform2uiv_with_u32_array);
647impl_Uniformable!(vec Vec3<u32>, UIVec3, uniform3uiv_with_u32_array);
648impl_Uniformable!(vec Vec4<u32>, UIVec4, uniform4uiv_with_u32_array);
649impl_Uniformable!(arr u32, UInt, uniform1uiv_with_u32_array);
650impl_Uniformable!(
651 vec arr Vec2 u32,
652 2,
653 UIVec2,
654 uniform2uiv_with_u32_array_and_src_offset_and_src_length
655);
656impl_Uniformable!(
657 vec arr Vec3 u32,
658 3,
659 UIVec3,
660 uniform3uiv_with_u32_array_and_src_offset_and_src_length
661);
662impl_Uniformable!(
663 vec arr Vec4 u32,
664 4,
665 UIVec4,
666 uniform4uiv_with_u32_array_and_src_offset_and_src_length
667);
668
669impl_Uniformable!(f32, Float, uniform1f);
670impl_Uniformable!(vec Vec2<f32>, Vec2, uniform2fv_with_f32_array);
671impl_Uniformable!(vec Vec3<f32>, Vec3, uniform3fv_with_f32_array);
672impl_Uniformable!(vec Vec4<f32>, Vec4, uniform4fv_with_f32_array);
673impl_Uniformable!(arr f32, Float, uniform1fv_with_f32_array);
674impl_Uniformable!(
675 vec arr Vec2 f32,
676 2,
677 Vec2,
678 uniform2fv_with_f32_array_and_src_offset_and_src_length
679);
680impl_Uniformable!(
681 vec arr Vec3 f32,
682 3,
683 Vec3,
684 uniform3fv_with_f32_array_and_src_offset_and_src_length
685);
686impl_Uniformable!(
687 vec arr Vec4 f32,
688 4,
689 Vec4,
690 uniform4fv_with_f32_array_and_src_offset_and_src_length
691);
692
693impl_Uniformable!(mat Mat22 f32, 4, M22, uniform_matrix2fv_with_f32_array);
695impl_Uniformable!(mat arr Mat22 f32, 4, M22, uniform_matrix2fv_with_f32_array_and_src_offset_and_src_length);
696
697impl_Uniformable!(mat Mat33 f32, 9, M33, uniform_matrix3fv_with_f32_array);
698impl_Uniformable!(mat arr Mat33 f32, 9, M33, uniform_matrix3fv_with_f32_array_and_src_offset_and_src_length);
699
700impl_Uniformable!(mat Mat44 f32, 16, M44, uniform_matrix4fv_with_f32_array);
701impl_Uniformable!(mat arr Mat44 f32, 16, M44, uniform_matrix4fv_with_f32_array_and_src_offset_and_src_length);
702
703unsafe impl<'a> Uniformable<'a, bool> for WebGL2 {
710 type Target = bool;
711
712 const SIZE: usize = 1;
713
714 unsafe fn ty() -> UniformType {
715 UniformType::Bool
716 }
717
718 unsafe fn update(program: &mut Program, uniform: &'a Uniform<bool>, value: Self::Target) {
719 program.state.borrow().ctx.uniform1ui(
720 program.location_map.borrow().get(&uniform.index()),
721 value as u32,
722 );
723 }
724}
725
726unsafe impl<'a> Uniformable<'a, Vec2<bool>> for WebGL2 {
727 type Target = Vec2<bool>;
728
729 const SIZE: usize = 1;
730
731 unsafe fn ty() -> UniformType {
732 UniformType::BVec2
733 }
734
735 unsafe fn update(program: &mut Program, uniform: &'a Uniform<Vec2<bool>>, value: Self::Target) {
736 let v = [value[0] as u32, value[1] as u32];
737
738 program
739 .state
740 .borrow()
741 .ctx
742 .uniform2uiv_with_u32_array(program.location_map.borrow().get(&uniform.index()), &v);
743 }
744}
745
746unsafe impl<'a> Uniformable<'a, Vec3<bool>> for WebGL2 {
747 type Target = Vec3<bool>;
748
749 const SIZE: usize = 1;
750
751 unsafe fn ty() -> UniformType {
752 UniformType::BVec3
753 }
754
755 unsafe fn update(program: &mut Program, uniform: &'a Uniform<Vec3<bool>>, value: Self::Target) {
756 let v = [value[0] as u32, value[1] as u32, value[2] as u32];
757
758 program
759 .state
760 .borrow()
761 .ctx
762 .uniform3uiv_with_u32_array(program.location_map.borrow().get(&uniform.index()), &v);
763 }
764}
765
766unsafe impl<'a> Uniformable<'a, Vec4<bool>> for WebGL2 {
767 type Target = Vec4<bool>;
768
769 const SIZE: usize = 1;
770
771 unsafe fn ty() -> UniformType {
772 UniformType::BVec4
773 }
774
775 unsafe fn update(program: &mut Program, uniform: &'a Uniform<Vec4<bool>>, value: Self::Target) {
776 let v = [
777 value[0] as u32,
778 value[1] as u32,
779 value[2] as u32,
780 value[3] as u32,
781 ];
782
783 program
784 .state
785 .borrow()
786 .ctx
787 .uniform4uiv_with_u32_array(program.location_map.borrow().get(&uniform.index()), &v);
788 }
789}
790
791static mut BOOL_CACHE: Vec<u32> = Vec::new();
793
794unsafe impl<'a, const N: usize> Uniformable<'a, Arr<bool, N>> for WebGL2 {
795 type Target = &'a [bool; N];
796
797 const SIZE: usize = N;
798
799 unsafe fn ty() -> UniformType {
800 UniformType::Bool
801 }
802
803 unsafe fn update(program: &mut Program, uniform: &'a Uniform<Arr<bool, N>>, value: Self::Target) {
804 BOOL_CACHE.clear();
805 BOOL_CACHE.extend(value.iter().map(|x| *x as u32));
806
807 program.state.borrow().ctx.uniform1uiv_with_u32_array(
808 program.location_map.borrow().get(&uniform.index()),
809 &BOOL_CACHE,
810 );
811 }
812}
813
814unsafe impl<'a, const N: usize> Uniformable<'a, Arr<Vec2<bool>, N>> for WebGL2 {
815 type Target = &'a [Vec2<bool>; N];
816
817 const SIZE: usize = N;
818
819 unsafe fn ty() -> UniformType {
820 UniformType::BVec2
821 }
822
823 unsafe fn update(
824 program: &mut Program,
825 uniform: &'a Uniform<Arr<Vec2<bool>, N>>,
826 value: Self::Target,
827 ) {
828 BOOL_CACHE.clear();
829 BOOL_CACHE.extend(value.iter().flat_map(|x| [x[0] as u32, x[1] as u32]));
830
831 program.state.borrow().ctx.uniform2uiv_with_u32_array(
832 program.location_map.borrow().get(&uniform.index()),
833 &BOOL_CACHE,
834 );
835 }
836}
837
838unsafe impl<'a, const N: usize> Uniformable<'a, Arr<Vec3<bool>, N>> for WebGL2 {
839 type Target = &'a [Vec3<bool>; N];
840
841 const SIZE: usize = N;
842
843 unsafe fn ty() -> UniformType {
844 UniformType::BVec3
845 }
846
847 unsafe fn update(
848 program: &mut Program,
849 uniform: &'a Uniform<Arr<Vec3<bool>, N>>,
850 value: Self::Target,
851 ) {
852 BOOL_CACHE.clear();
853 BOOL_CACHE.extend(
854 value
855 .iter()
856 .flat_map(|x| [x[0] as u32, x[1] as u32, x[2] as u32]),
857 );
858
859 program.state.borrow().ctx.uniform3uiv_with_u32_array(
860 program.location_map.borrow().get(&uniform.index()),
861 &BOOL_CACHE,
862 );
863 }
864}
865
866unsafe impl<'a, const N: usize> Uniformable<'a, Arr<Vec4<bool>, N>> for WebGL2 {
867 type Target = &'a [Vec4<bool>; N];
868
869 const SIZE: usize = N;
870
871 unsafe fn ty() -> UniformType {
872 UniformType::BVec4
873 }
874
875 unsafe fn update(
876 program: &mut Program,
877 uniform: &'a Uniform<Arr<Vec4<bool>, N>>,
878 value: Self::Target,
879 ) {
880 BOOL_CACHE.clear();
881 BOOL_CACHE.extend(
882 value
883 .iter()
884 .flat_map(|x| [x[0] as u32, x[1] as u32, x[2] as u32, x[3] as u32]),
885 );
886
887 program.state.borrow().ctx.uniform4uiv_with_u32_array(
888 program.location_map.borrow().get(&uniform.index()),
889 &BOOL_CACHE,
890 );
891 }
892}
893
894unsafe impl<'a, T> Uniformable<'a, ShaderDataBinding<T>> for WebGL2
895where
896 T: 'a,
897{
898 type Target = ShaderDataBinding<T>;
899
900 const SIZE: usize = 0;
901
902 unsafe fn ty() -> UniformType {
903 UniformType::ShaderDataBinding
904 }
905
906 unsafe fn update(
907 program: &mut Program,
908 uniform: &'a Uniform<ShaderDataBinding<T>>,
909 value: Self::Target,
910 ) {
911 program.state.borrow().ctx.uniform_block_binding(
912 &program.handle,
913 uniform.index() as u32,
914 value.binding(),
915 );
916 }
917}
918
919unsafe impl<'a, D, S> Uniformable<'a, TextureBinding<D, S>> for WebGL2
920where
921 D: 'a + Dimensionable,
922 S: 'a + SamplerType,
923{
924 type Target = TextureBinding<D, S>;
925
926 const SIZE: usize = 0;
927
928 unsafe fn ty() -> UniformType {
929 match (S::sample_type(), D::dim()) {
930 (PixelType::NormIntegral, Dim::Dim1) => UniformType::Sampler1D,
931 (PixelType::NormUnsigned, Dim::Dim1) => UniformType::Sampler1D,
932 (PixelType::Integral, Dim::Dim1) => UniformType::ISampler1D,
933 (PixelType::Unsigned, Dim::Dim1) => UniformType::UISampler1D,
934 (PixelType::Floating, Dim::Dim1) => UniformType::Sampler1D,
935
936 (PixelType::NormIntegral, Dim::Dim2) => UniformType::Sampler2D,
937 (PixelType::NormUnsigned, Dim::Dim2) => UniformType::Sampler2D,
938 (PixelType::Integral, Dim::Dim2) => UniformType::ISampler2D,
939 (PixelType::Unsigned, Dim::Dim2) => UniformType::UISampler2D,
940 (PixelType::Floating, Dim::Dim2) => UniformType::Sampler2D,
941
942 (PixelType::NormIntegral, Dim::Dim3) => UniformType::Sampler3D,
943 (PixelType::NormUnsigned, Dim::Dim3) => UniformType::Sampler3D,
944 (PixelType::Integral, Dim::Dim3) => UniformType::ISampler3D,
945 (PixelType::Unsigned, Dim::Dim3) => UniformType::UISampler3D,
946 (PixelType::Floating, Dim::Dim3) => UniformType::Sampler3D,
947
948 (PixelType::NormIntegral, Dim::Cubemap) => UniformType::Cubemap,
949 (PixelType::NormUnsigned, Dim::Cubemap) => UniformType::Cubemap,
950 (PixelType::Integral, Dim::Cubemap) => UniformType::ICubemap,
951 (PixelType::Unsigned, Dim::Cubemap) => UniformType::UICubemap,
952 (PixelType::Floating, Dim::Cubemap) => UniformType::Cubemap,
953
954 (PixelType::NormIntegral, Dim::Dim1Array) => UniformType::Sampler1DArray,
955 (PixelType::NormUnsigned, Dim::Dim1Array) => UniformType::Sampler1DArray,
956 (PixelType::Integral, Dim::Dim1Array) => UniformType::ISampler1DArray,
957 (PixelType::Unsigned, Dim::Dim1Array) => UniformType::UISampler1DArray,
958 (PixelType::Floating, Dim::Dim1Array) => UniformType::Sampler1DArray,
959
960 (PixelType::NormIntegral, Dim::Dim2Array) => UniformType::Sampler2DArray,
961 (PixelType::NormUnsigned, Dim::Dim2Array) => UniformType::Sampler2DArray,
962 (PixelType::Integral, Dim::Dim2Array) => UniformType::ISampler2DArray,
963 (PixelType::Unsigned, Dim::Dim2Array) => UniformType::UISampler2DArray,
964 (PixelType::Floating, Dim::Dim2Array) => UniformType::Sampler2DArray,
965 }
966 }
967
968 unsafe fn update(
969 program: &mut Program,
970 uniform: &'a Uniform<TextureBinding<D, S>>,
971 value: Self::Target,
972 ) {
973 program.state.borrow().ctx.uniform1i(
974 program.location_map.borrow().get(&uniform.index()),
975 value.binding() as i32,
976 );
977 }
978}
979
980unsafe impl<T> ShaderData<T> for WebGL2
981where
982 T: Std140,
983{
984 type ShaderDataRepr =
985 Buffer<<ArrElem<T> as Std140>::Encoded, { WebGl2RenderingContext::UNIFORM_BUFFER }>;
986
987 unsafe fn new_shader_data(
988 &mut self,
989 values: impl Iterator<Item = T>,
990 ) -> Result<Self::ShaderDataRepr, ShaderDataError> {
991 Buffer::from_vec(
992 self,
993 values
994 .into_iter()
995 .map(|x| ArrElem(x).std140_encode())
996 .collect(),
997 )
998 .map_err(|BufferError::CannotCreate| ShaderDataError::CannotCreate)
999 }
1000
1001 unsafe fn get_shader_data_at(
1002 shader_data: &Self::ShaderDataRepr,
1003 i: usize,
1004 ) -> Result<T, ShaderDataError> {
1005 shader_data
1006 .buf
1007 .get(i)
1008 .map(|&x| <ArrElem<T> as Std140>::std140_decode(x).0)
1009 .ok_or_else(|| ShaderDataError::OutOfBounds { index: i })
1010 }
1011
1012 unsafe fn set_shader_data_at(
1013 shader_data: &mut Self::ShaderDataRepr,
1014 i: usize,
1015 x: T,
1016 ) -> Result<T, ShaderDataError> {
1017 let prev = mem::replace(
1018 &mut shader_data.slice_buffer_mut()[i],
1019 ArrElem(x).std140_encode(),
1020 );
1021
1022 Ok(<ArrElem<T> as Std140>::std140_decode(prev).0)
1023 }
1024
1025 unsafe fn set_shader_data_values(
1026 shader_data: &mut Self::ShaderDataRepr,
1027 values: impl Iterator<Item = T>,
1028 ) -> Result<(), ShaderDataError> {
1029 let mut slice = shader_data.slice_buffer_mut();
1030
1031 for (item, value) in slice.iter_mut().zip(values) {
1032 *item = ArrElem(value).std140_encode();
1033 }
1034
1035 Ok(())
1036 }
1037}