1use std::ffi::CString;
2
3use crate::{window, ResourceManager};
4
5mod cache;
6
7use super::*;
8use cache::*;
9
10pub mod raw_gl {
14 use super::*;
15
16 #[doc(inline)]
17 pub use crate::native::gl::*;
18
19 pub fn texture_format_into_gl(format: TextureFormat) -> (GLenum, GLenum, GLenum) {
20 format.into()
21 }
22}
23
24#[derive(Clone, Copy, Debug)]
25struct Buffer {
26 gl_buf: GLuint,
27 buffer_type: BufferType,
28 size: usize,
29 index_type: Option<u32>,
33}
34
35#[derive(Debug)]
36struct ShaderUniform {
37 gl_loc: UniformLocation,
38 uniform_type: UniformType,
39 array_count: i32,
40}
41
42struct ShaderInternal {
43 program: GLuint,
44 images: Vec<ShaderImage>,
45 uniforms: Vec<ShaderUniform>,
46}
47
48#[derive(Clone, Copy, Debug)]
49enum TextureOrRenderbuffer {
50 Texture(GLuint),
51 Renderbuffer(GLuint),
52}
53impl TextureOrRenderbuffer {
54 fn texture(&self) -> Option<GLuint> {
55 match self {
56 TextureOrRenderbuffer::Texture(id) => Some(*id),
57 _ => None,
58 }
59 }
60 fn renderbuffer(&self) -> Option<GLuint> {
61 match self {
62 TextureOrRenderbuffer::Renderbuffer(id) => Some(*id),
63 _ => None,
64 }
65 }
66}
67
68#[derive(Clone, Copy, Debug)]
69struct Texture {
70 raw: TextureOrRenderbuffer,
71 params: TextureParams,
72}
73
74impl TextureFormat {
75 fn sized_internal_format(&self) -> GLenum {
76 match self {
77 TextureFormat::RGB8 => GL_RGB8,
78 TextureFormat::RGBA8 => GL_RGBA8,
79 TextureFormat::RGBA16F => GL_RGBA16F,
80 TextureFormat::Depth => GL_DEPTH_COMPONENT16,
81 TextureFormat::Depth32 => GL_DEPTH_COMPONENT32,
82 #[cfg(target_arch = "wasm32")]
83 TextureFormat::Alpha => GL_ALPHA,
84 #[cfg(not(target_arch = "wasm32"))]
85 TextureFormat::Alpha => GL_R8,
86 }
87 }
88}
89
90impl From<TextureFormat> for (GLenum, GLenum, GLenum) {
92 fn from(format: TextureFormat) -> Self {
93 match format {
94 TextureFormat::RGB8 => (GL_RGB, GL_RGB, GL_UNSIGNED_BYTE),
95 TextureFormat::RGBA8 => (GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE),
96 TextureFormat::RGBA16F => (GL_RGBA16F, GL_RGBA, GL_FLOAT),
97 TextureFormat::Depth => (GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT),
98 TextureFormat::Depth32 => (GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, GL_FLOAT),
99 #[cfg(target_arch = "wasm32")]
100 TextureFormat::Alpha => (GL_ALPHA, GL_ALPHA, GL_UNSIGNED_BYTE),
101 #[cfg(not(target_arch = "wasm32"))]
102 TextureFormat::Alpha => (GL_R8, GL_RED, GL_UNSIGNED_BYTE), }
104 }
105}
106
107impl From<TextureKind> for GLuint {
108 fn from(kind: TextureKind) -> GLuint {
109 match kind {
110 TextureKind::Texture2D => GL_TEXTURE_2D,
111 TextureKind::CubeMap => GL_TEXTURE_CUBE_MAP,
112 }
113 }
114}
115impl From<Equation> for GLenum {
116 fn from(eq: Equation) -> Self {
117 match eq {
118 Equation::Add => GL_FUNC_ADD,
119 Equation::Subtract => GL_FUNC_SUBTRACT,
120 Equation::ReverseSubtract => GL_FUNC_REVERSE_SUBTRACT,
121 }
122 }
123}
124
125impl From<BlendFactor> for GLenum {
126 fn from(factor: BlendFactor) -> GLenum {
127 match factor {
128 BlendFactor::Zero => GL_ZERO,
129 BlendFactor::One => GL_ONE,
130 BlendFactor::Value(BlendValue::SourceColor) => GL_SRC_COLOR,
131 BlendFactor::Value(BlendValue::SourceAlpha) => GL_SRC_ALPHA,
132 BlendFactor::Value(BlendValue::DestinationColor) => GL_DST_COLOR,
133 BlendFactor::Value(BlendValue::DestinationAlpha) => GL_DST_ALPHA,
134 BlendFactor::OneMinusValue(BlendValue::SourceColor) => GL_ONE_MINUS_SRC_COLOR,
135 BlendFactor::OneMinusValue(BlendValue::SourceAlpha) => GL_ONE_MINUS_SRC_ALPHA,
136 BlendFactor::OneMinusValue(BlendValue::DestinationColor) => GL_ONE_MINUS_DST_COLOR,
137 BlendFactor::OneMinusValue(BlendValue::DestinationAlpha) => GL_ONE_MINUS_DST_ALPHA,
138 BlendFactor::SourceAlphaSaturate => GL_SRC_ALPHA_SATURATE,
139 }
140 }
141}
142
143impl From<StencilOp> for GLenum {
144 fn from(op: StencilOp) -> Self {
145 match op {
146 StencilOp::Keep => GL_KEEP,
147 StencilOp::Zero => GL_ZERO,
148 StencilOp::Replace => GL_REPLACE,
149 StencilOp::IncrementClamp => GL_INCR,
150 StencilOp::DecrementClamp => GL_DECR,
151 StencilOp::Invert => GL_INVERT,
152 StencilOp::IncrementWrap => GL_INCR_WRAP,
153 StencilOp::DecrementWrap => GL_DECR_WRAP,
154 }
155 }
156}
157
158impl From<CompareFunc> for GLenum {
159 fn from(cf: CompareFunc) -> Self {
160 match cf {
161 CompareFunc::Always => GL_ALWAYS,
162 CompareFunc::Never => GL_NEVER,
163 CompareFunc::Less => GL_LESS,
164 CompareFunc::Equal => GL_EQUAL,
165 CompareFunc::LessOrEqual => GL_LEQUAL,
166 CompareFunc::Greater => GL_GREATER,
167 CompareFunc::NotEqual => GL_NOTEQUAL,
168 CompareFunc::GreaterOrEqual => GL_GEQUAL,
169 }
170 }
171}
172
173impl Texture {
174 pub fn new(
175 ctx: &mut GlContext,
176 access: TextureAccess,
177 source: TextureSource,
178 params: TextureParams,
179 ) -> Texture {
180 if let TextureSource::Bytes(bytes_data) = source {
181 assert_eq!(
182 params.format.size(params.width, params.height) as usize,
183 bytes_data.len()
184 );
185 }
186 if access != TextureAccess::RenderTarget {
187 assert!(
188 params.sample_count <= 1,
189 "Multisampling is only supported for render textures"
190 );
191 }
192 let (internal_format, format, pixel_type) = params.format.into();
193
194 if access == TextureAccess::RenderTarget && params.sample_count > 1 {
195 let mut renderbuffer: u32 = 0;
196 unsafe {
197 glGenRenderbuffers(1, &mut renderbuffer as *mut _);
198 glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer as _);
199 let internal_format = params.format.sized_internal_format();
200 glRenderbufferStorageMultisample(
201 GL_RENDERBUFFER,
202 params.sample_count,
203 internal_format,
204 params.width as _,
205 params.height as _,
206 );
207 }
208 return Texture {
209 raw: TextureOrRenderbuffer::Renderbuffer(renderbuffer),
210 params,
211 };
212 }
213
214 ctx.cache.store_texture_binding(0);
215
216 let mut texture: GLuint = 0;
217
218 unsafe {
219 glGenTextures(1, &mut texture as *mut _);
220 ctx.cache.bind_texture(0, params.kind.into(), texture);
221 glPixelStorei(GL_UNPACK_ALIGNMENT, 1); if cfg!(not(target_arch = "wasm32")) {
224 if params.format == TextureFormat::Alpha {
226 glTexParameteri(params.kind.into(), GL_TEXTURE_SWIZZLE_A, GL_RED as _);
229 } else {
230 glTexParameteri(params.kind.into(), GL_TEXTURE_SWIZZLE_A, GL_ALPHA as _);
232 }
233 }
234
235 match source {
236 TextureSource::Empty => {
237 glTexImage2D(
240 GL_TEXTURE_2D,
241 0,
242 internal_format as i32,
243 params.width as i32,
244 params.height as i32,
245 0,
246 format,
247 pixel_type,
248 std::ptr::null() as _,
249 );
250 }
251 TextureSource::Bytes(source) => {
252 assert!(params.kind == TextureKind::Texture2D, "incompatible TextureKind and TextureSource. Cubemaps require TextureSource::Array of 6 textures.");
253 glTexImage2D(
254 GL_TEXTURE_2D,
255 0,
256 internal_format as i32,
257 params.width as i32,
258 params.height as i32,
259 0,
260 format,
261 pixel_type,
262 source.as_ptr() as *const _,
263 );
264 }
265 TextureSource::Array(array) => {
266 if params.kind == TextureKind::CubeMap {
267 assert!(
268 array.len() == 6,
269 "Cubemaps require TextureSource::Array of 6 textures."
270 );
271 }
272 for (cubemap_face, mipmaps) in array.iter().enumerate() {
273 if mipmaps.len() != 1 {
274 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
275 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, array.len() as _);
276 }
277 for (mipmap_level, bytes) in mipmaps.iter().enumerate() {
278 let target = match params.kind {
279 TextureKind::Texture2D => GL_TEXTURE_2D,
280 TextureKind::CubeMap => {
281 GL_TEXTURE_CUBE_MAP_POSITIVE_X + cubemap_face as u32
282 }
283 };
284 glTexImage2D(
285 target,
286 mipmap_level as _,
287 internal_format as i32,
288 params.width as i32,
289 params.height as i32,
290 0,
291 format,
292 pixel_type,
293 bytes.as_ptr() as *const _,
294 );
295 }
296 }
297 }
298 }
299
300 let wrap = match params.wrap {
301 TextureWrap::Repeat => GL_REPEAT,
302 TextureWrap::Mirror => GL_MIRRORED_REPEAT,
303 TextureWrap::Clamp => GL_CLAMP_TO_EDGE,
304 };
305
306 let min_filter = Self::gl_filter(params.min_filter, params.mipmap_filter);
307 let mag_filter = match params.mag_filter {
308 FilterMode::Nearest => GL_NEAREST,
309 FilterMode::Linear => GL_LINEAR,
310 };
311
312 glTexParameteri(params.kind.into(), GL_TEXTURE_WRAP_S, wrap as i32);
313 glTexParameteri(params.kind.into(), GL_TEXTURE_WRAP_T, wrap as i32);
314 glTexParameteri(params.kind.into(), GL_TEXTURE_MIN_FILTER, min_filter as i32);
315 glTexParameteri(params.kind.into(), GL_TEXTURE_MAG_FILTER, mag_filter as i32);
316 }
317 ctx.cache.restore_texture_binding(0);
318
319 Texture {
320 raw: TextureOrRenderbuffer::Texture(texture),
321 params,
322 }
323 }
324
325 pub fn resize(&mut self, ctx: &mut GlContext, width: u32, height: u32, source: Option<&[u8]>) {
326 let raw = self
327 .raw
328 .texture()
329 .expect("Resize not yet implemented for RenderBuffer(multisampled) textures");
330 ctx.cache.store_texture_binding(0);
331 ctx.cache.bind_texture(0, self.params.kind.into(), raw);
332
333 let (internal_format, format, pixel_type) = self.params.format.into();
334
335 self.params.width = width;
336 self.params.height = height;
337
338 unsafe {
339 glTexImage2D(
340 GL_TEXTURE_2D,
341 0,
342 internal_format as i32,
343 self.params.width as i32,
344 self.params.height as i32,
345 0,
346 format,
347 pixel_type,
348 match source {
349 Some(source) => source.as_ptr() as *const _,
350 Option::None => std::ptr::null(),
351 },
352 );
353 }
354
355 ctx.cache.restore_texture_binding(0);
356 }
357
358 pub fn update_texture_part(
359 &self,
360 ctx: &mut GlContext,
361 x_offset: i32,
362 y_offset: i32,
363 width: i32,
364 height: i32,
365 source: &[u8],
366 ) {
367 assert_eq!(self.size(width as _, height as _), source.len());
368 assert!(x_offset + width <= self.params.width as _);
369 assert!(y_offset + height <= self.params.height as _);
370 let raw = self.raw.texture().expect(
371 "update_texture_part not yet implemented for RenderBuffer(multisampled) textures",
372 );
373
374 ctx.cache.store_texture_binding(0);
375 ctx.cache.bind_texture(0, self.params.kind.into(), raw);
376
377 let (_, format, pixel_type) = self.params.format.into();
378
379 unsafe {
380 glPixelStorei(GL_UNPACK_ALIGNMENT, 1); if cfg!(not(target_arch = "wasm32")) {
383 if self.params.format == TextureFormat::Alpha {
385 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, GL_RED as _);
388 } else {
389 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, GL_ALPHA as _);
391 }
392 }
393
394 glTexSubImage2D(
395 GL_TEXTURE_2D,
396 0,
397 x_offset as _,
398 y_offset as _,
399 width as _,
400 height as _,
401 format,
402 pixel_type,
403 source.as_ptr() as *const _,
404 );
405 }
406
407 ctx.cache.restore_texture_binding(0);
408 }
409
410 pub fn read_pixels(&self, bytes: &mut [u8]) {
412 let raw = self
413 .raw
414 .texture()
415 .expect("read_pixels not yet implemented for RenderBuffer(multisampled) textures");
416
417 let (_, format, pixel_type) = self.params.format.into();
418
419 let mut fbo = 0;
420 unsafe {
421 let mut binded_fbo: i32 = 0;
422 glGetIntegerv(gl::GL_DRAW_FRAMEBUFFER_BINDING, &mut binded_fbo);
423 glGenFramebuffers(1, &mut fbo);
424 glBindFramebuffer(gl::GL_FRAMEBUFFER, fbo);
425 glFramebufferTexture2D(
426 gl::GL_FRAMEBUFFER,
427 gl::GL_COLOR_ATTACHMENT0,
428 gl::GL_TEXTURE_2D,
429 raw,
430 0,
431 );
432
433 glReadPixels(
434 0,
435 0,
436 self.params.width as _,
437 self.params.height as _,
438 format,
439 pixel_type,
440 bytes.as_mut_ptr() as _,
441 );
442
443 glBindFramebuffer(gl::GL_FRAMEBUFFER, binded_fbo as _);
444 glDeleteFramebuffers(1, &fbo);
445 }
446 }
447
448 #[inline]
449 fn size(&self, width: u32, height: u32) -> usize {
450 self.params.format.size(width, height) as usize
451 }
452
453 fn gl_filter(filter: FilterMode, mipmap_filter: MipmapFilterMode) -> GLenum {
454 match filter {
455 FilterMode::Nearest => match mipmap_filter {
456 MipmapFilterMode::None => GL_NEAREST,
457 MipmapFilterMode::Nearest => GL_NEAREST_MIPMAP_NEAREST,
458 MipmapFilterMode::Linear => GL_NEAREST_MIPMAP_LINEAR,
459 },
460 FilterMode::Linear => match mipmap_filter {
461 MipmapFilterMode::None => GL_LINEAR,
462 MipmapFilterMode::Nearest => GL_LINEAR_MIPMAP_NEAREST,
463 MipmapFilterMode::Linear => GL_LINEAR_MIPMAP_LINEAR,
464 },
465 }
466 }
467}
468
469pub(crate) struct PipelineInternal {
470 layout: Vec<Option<VertexAttributeInternal>>,
471 shader: ShaderId,
472 params: PipelineParams,
473}
474
475type UniformLocation = Option<GLint>;
476
477pub struct ShaderImage {
478 gl_loc: UniformLocation,
479}
480
481fn get_uniform_location(program: GLuint, name: &str) -> Option<i32> {
482 let cname = CString::new(name).unwrap_or_else(|e| panic!("{}", e));
483 let location = unsafe { glGetUniformLocation(program, cname.as_ptr()) };
484
485 if location == -1 {
486 return None;
487 }
488
489 Some(location)
490}
491
492pub(crate) struct RenderPassInternal {
493 gl_fb: GLuint,
494 color_textures: Vec<TextureId>,
495 resolves: Option<Vec<(u32, TextureId)>>,
496 depth_texture: Option<TextureId>,
497}
498
499struct Textures(Vec<Texture>);
500impl Textures {
501 fn get(&self, texture: TextureId) -> Texture {
502 match texture.0 {
503 TextureIdInner::Raw(RawId::OpenGl(texture)) => Texture {
504 raw: TextureOrRenderbuffer::Texture(texture),
505 params: Default::default(),
506 },
507 #[cfg(target_vendor = "apple")]
508 TextureIdInner::Raw(RawId::Metal(..)) => panic!("Metal texture in OpenGL context!"),
509 TextureIdInner::Managed(texture) => self.0[texture],
510 }
511 }
512}
513pub struct GlContext {
514 shaders: ResourceManager<ShaderInternal>,
515 pipelines: ResourceManager<PipelineInternal>,
516 passes: ResourceManager<RenderPassInternal>,
517 buffers: ResourceManager<Buffer>,
518 textures: Textures,
519 default_framebuffer: GLuint,
520 pub(crate) cache: GlCache,
521 pub(crate) info: ContextInfo,
522}
523
524impl Default for GlContext {
525 fn default() -> Self {
526 Self::new()
527 }
528}
529
530impl GlContext {
531 pub fn new() -> GlContext {
532 unsafe {
533 let mut default_framebuffer: GLuint = 0;
534 glGetIntegerv(
535 GL_FRAMEBUFFER_BINDING,
536 &mut default_framebuffer as *mut _ as *mut _,
537 );
538 let mut vao = 0;
539
540 glGenVertexArrays(1, &mut vao as *mut _);
541 glBindVertexArray(vao);
542 let info = gl_info();
543 GlContext {
544 default_framebuffer,
545 shaders: ResourceManager::default(),
546 pipelines: ResourceManager::default(),
547 passes: ResourceManager::default(),
548 buffers: ResourceManager::default(),
549 textures: Textures(vec![]),
550 info,
551 cache: GlCache {
552 stored_index_buffer: 0,
553 stored_index_type: None,
554 stored_vertex_buffer: 0,
555 index_buffer: 0,
556 index_type: None,
557 vertex_buffer: 0,
558 cur_pipeline: None,
559 cur_pass: None,
560 color_blend: None,
561 alpha_blend: None,
562 stencil: None,
563 color_write: (true, true, true, true),
564 cull_face: CullFace::Nothing,
565 stored_texture: 0,
566 stored_target: 0,
567 textures: [CachedTexture {
568 target: 0,
569 texture: 0,
570 }; MAX_SHADERSTAGE_IMAGES],
571 attributes: [None; MAX_VERTEX_ATTRIBUTES],
572 },
573 }
574 }
575 }
576
577 pub fn features(&self) -> &Features {
578 &self.info.features
579 }
580}
581
582fn load_shader_internal(
583 vertex_shader: &str,
584 fragment_shader: &str,
585 meta: ShaderMeta,
586) -> Result<ShaderInternal, ShaderError> {
587 unsafe {
588 let vertex_shader = load_shader(GL_VERTEX_SHADER, vertex_shader)?;
589 let fragment_shader = load_shader(GL_FRAGMENT_SHADER, fragment_shader)?;
590
591 let program = glCreateProgram();
592 glAttachShader(program, vertex_shader);
593 glAttachShader(program, fragment_shader);
594 glLinkProgram(program);
595
596 glDetachShader(program, vertex_shader);
598 glDeleteShader(vertex_shader);
599 glDeleteShader(fragment_shader);
600
601 let mut link_status = 0;
602 glGetProgramiv(program, GL_LINK_STATUS, &mut link_status as *mut _);
603 if link_status == 0 {
604 let mut max_length: i32 = 0;
605 glGetProgramiv(program, GL_INFO_LOG_LENGTH, &mut max_length as *mut _);
606
607 let mut error_message = vec![0u8; max_length as usize + 1];
608 glGetProgramInfoLog(
609 program,
610 max_length,
611 &mut max_length as *mut _,
612 error_message.as_mut_ptr() as *mut _,
613 );
614 assert!(max_length >= 1);
615 let error_message =
616 std::string::String::from_utf8_lossy(&error_message[0..max_length as usize - 1]);
617 return Err(ShaderError::LinkError(error_message.to_string()));
618 }
619
620 glUseProgram(program);
621
622 #[rustfmt::skip]
623 let images = meta.images.iter().map(|name| ShaderImage {
624 gl_loc: get_uniform_location(program, name),
625 }).collect();
626
627 #[rustfmt::skip]
628 let uniforms = meta.uniforms.uniforms.iter().scan(0, |offset, uniform| {
629 let res = ShaderUniform {
630 gl_loc: get_uniform_location(program, &uniform.name),
631 uniform_type: uniform.uniform_type,
632 array_count: uniform.array_count as _,
633 };
634 *offset += uniform.uniform_type.size() * uniform.array_count;
635 Some(res)
636 }).collect();
637
638 Ok(ShaderInternal {
639 program,
640 images,
641 uniforms,
642 })
643 }
644}
645
646pub fn load_shader(shader_type: GLenum, source: &str) -> Result<GLuint, ShaderError> {
647 unsafe {
648 let shader = glCreateShader(shader_type);
649 assert!(shader != 0);
650
651 let cstring = CString::new(source)?;
652 let csource = [cstring];
653 glShaderSource(shader, 1, csource.as_ptr() as *const _, std::ptr::null());
654 glCompileShader(shader);
655
656 let mut is_compiled = 0;
657 glGetShaderiv(shader, GL_COMPILE_STATUS, &mut is_compiled as *mut _);
658 if is_compiled == 0 {
659 let mut max_length: i32 = 0;
660 glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &mut max_length as *mut _);
661
662 let mut error_message = vec![0u8; max_length as usize + 1];
663 glGetShaderInfoLog(
664 shader,
665 max_length,
666 &mut max_length as *mut _,
667 error_message.as_mut_ptr() as *mut _,
668 );
669
670 assert!(max_length >= 1);
671 let mut error_message =
672 std::string::String::from_utf8_lossy(&error_message[0..max_length as usize - 1])
673 .into_owned();
674
675 if error_message.ends_with('\0') {
677 error_message.pop();
678 }
679
680 return Err(ShaderError::CompilationError {
681 shader_type: match shader_type {
682 GL_VERTEX_SHADER => ShaderType::Vertex,
683 GL_FRAGMENT_SHADER => ShaderType::Fragment,
684 _ => unreachable!(),
685 },
686 error_message,
687 });
688 }
689
690 Ok(shader)
691 }
692}
693
694impl GlContext {
695 fn set_blend(&mut self, color_blend: Option<BlendState>, alpha_blend: Option<BlendState>) {
696 if color_blend.is_none() && alpha_blend.is_some() {
697 panic!("AlphaBlend without ColorBlend");
698 }
699 if self.cache.color_blend == color_blend && self.cache.alpha_blend == alpha_blend {
700 return;
701 }
702
703 unsafe {
704 if let Some(color_blend) = color_blend {
705 if self.cache.color_blend.is_none() {
706 glEnable(GL_BLEND);
707 }
708
709 let BlendState {
710 equation: eq_rgb,
711 sfactor: src_rgb,
712 dfactor: dst_rgb,
713 } = color_blend;
714
715 if let Some(BlendState {
716 equation: eq_alpha,
717 sfactor: src_alpha,
718 dfactor: dst_alpha,
719 }) = alpha_blend
720 {
721 glBlendFuncSeparate(
722 src_rgb.into(),
723 dst_rgb.into(),
724 src_alpha.into(),
725 dst_alpha.into(),
726 );
727 glBlendEquationSeparate(eq_rgb.into(), eq_alpha.into());
728 } else {
729 glBlendFunc(src_rgb.into(), dst_rgb.into());
730 glBlendEquationSeparate(eq_rgb.into(), eq_rgb.into());
731 }
732 } else if self.cache.color_blend.is_some() {
733 glDisable(GL_BLEND);
734 }
735 }
736
737 self.cache.color_blend = color_blend;
738 self.cache.alpha_blend = alpha_blend;
739 }
740
741 fn set_stencil(&mut self, stencil_test: Option<StencilState>) {
742 if self.cache.stencil == stencil_test {
743 return;
744 }
745 unsafe {
746 if let Some(stencil) = stencil_test {
747 if self.cache.stencil.is_none() {
748 glEnable(GL_STENCIL_TEST);
749 }
750
751 let front = &stencil.front;
752 glStencilOpSeparate(
753 GL_FRONT,
754 front.fail_op.into(),
755 front.depth_fail_op.into(),
756 front.pass_op.into(),
757 );
758 glStencilFuncSeparate(
759 GL_FRONT,
760 front.test_func.into(),
761 front.test_ref,
762 front.test_mask,
763 );
764 glStencilMaskSeparate(GL_FRONT, front.write_mask);
765
766 let back = &stencil.back;
767 glStencilOpSeparate(
768 GL_BACK,
769 back.fail_op.into(),
770 back.depth_fail_op.into(),
771 back.pass_op.into(),
772 );
773 glStencilFuncSeparate(
774 GL_BACK,
775 back.test_func.into(),
776 back.test_ref,
777 back.test_mask,
778 );
779 glStencilMaskSeparate(GL_BACK, back.write_mask);
780 } else if self.cache.stencil.is_some() {
781 glDisable(GL_STENCIL_TEST);
782 }
783 }
784
785 self.cache.stencil = stencil_test;
786 }
787
788 fn set_cull_face(&mut self, cull_face: CullFace) {
789 if self.cache.cull_face == cull_face {
790 return;
791 }
792
793 match cull_face {
794 CullFace::Nothing => unsafe {
795 glDisable(GL_CULL_FACE);
796 },
797 CullFace::Front => unsafe {
798 glEnable(GL_CULL_FACE);
799 glCullFace(GL_FRONT);
800 },
801 CullFace::Back => unsafe {
802 glEnable(GL_CULL_FACE);
803 glCullFace(GL_BACK);
804 },
805 }
806 self.cache.cull_face = cull_face;
807 }
808
809 fn set_color_write(&mut self, color_write: ColorMask) {
810 if self.cache.color_write == color_write {
811 return;
812 }
813 let (r, g, b, a) = color_write;
814 unsafe { glColorMask(r as _, g as _, b as _, a as _) }
815 self.cache.color_write = color_write;
816 }
817}
818
819#[allow(clippy::field_reassign_with_default)]
820fn gl_info() -> ContextInfo {
821 let version_string = unsafe { glGetString(super::gl::GL_VERSION) };
822 let gl_version_string = unsafe { std::ffi::CStr::from_ptr(version_string as _) }
823 .to_str()
824 .unwrap()
825 .to_string();
826 let gl2 = gl_version_string.is_empty()
829 || gl_version_string.starts_with("2")
830 || gl_version_string.starts_with("OpenGL ES 2");
831 let webgl1 = gl_version_string == "WebGL 1.0";
832
833 let features = Features {
834 instancing: !gl2,
835 resolve_attachments: !webgl1 && !gl2,
836 };
837
838 let mut glsl_support = GlslSupport::default();
839
840 glsl_support.v100 = true;
844
845 #[cfg(target_arch = "wasm32")]
847 {
848 glsl_support.v100_ext = true;
850
851 let webgl2 = gl_version_string.contains("WebGL 2.0");
852 if webgl2 {
853 glsl_support.v300es = true;
854 }
855 }
856
857 #[cfg(not(target_arch = "wasm32"))]
858 {
859 let gles3 = gl_version_string.contains("OpenGL ES 3");
860
861 if gles3 {
862 glsl_support.v300es = true;
863 }
864 }
865
866 if gl_version_string.starts_with("3.2") {
868 glsl_support.v150 = true; } else if gl_version_string.starts_with("4") || gl_version_string.starts_with("3.3") {
870 glsl_support.v330 = true;
871 } else if gl_version_string.starts_with("3") {
873 glsl_support.v130 = true;
874 }
875
876 ContextInfo {
877 backend: Backend::OpenGl,
878 gl_version_string,
879 glsl_support,
880 features,
881 }
882}
883
884impl RenderingBackend for GlContext {
885 fn info(&self) -> ContextInfo {
886 self.info.clone()
887 }
888
889 fn new_shader(
890 &mut self,
891 shader: ShaderSource,
892 meta: ShaderMeta,
893 ) -> Result<ShaderId, ShaderError> {
894 let (fragment, vertex) = match shader {
895 ShaderSource::Glsl { fragment, vertex } => (fragment, vertex),
896 _ => panic!("Metal source on OpenGl context"),
897 };
898 let shader = load_shader_internal(vertex, fragment, meta)?;
899 Ok(ShaderId(self.shaders.add(shader)))
900 }
901
902 fn new_texture(
903 &mut self,
904 access: TextureAccess,
905 source: TextureSource,
906 params: TextureParams,
907 ) -> TextureId {
908 let texture = Texture::new(self, access, source, params);
909 self.textures.0.push(texture);
910 TextureId(TextureIdInner::Managed(self.textures.0.len() - 1))
911 }
912
913 fn delete_texture(&mut self, texture: TextureId) {
914 let t = self.textures.get(texture);
917 match &t.raw {
918 TextureOrRenderbuffer::Texture(raw) => unsafe {
919 glDeleteTextures(1, raw as *const _);
920 },
921 TextureOrRenderbuffer::Renderbuffer(raw) => unsafe {
922 glDeleteRenderbuffers(1, raw as *const _);
923 },
924 }
925 }
926
927 fn delete_shader(&mut self, program: ShaderId) {
928 unsafe { glDeleteProgram(self.shaders[program.0].program) };
929 self.shaders.remove(program.0);
930 self.cache.cur_pipeline = None;
931 }
932
933 fn delete_pipeline(&mut self, pipeline: Pipeline) {
934 self.pipelines.remove(pipeline.0);
935 }
936
937 fn texture_set_wrap(&mut self, texture: TextureId, wrap_x: TextureWrap, wrap_y: TextureWrap) {
938 let t = self.textures.get(texture);
939 let raw = t
940 .raw
941 .texture()
942 .expect("texture_set_wrap not yet implemented for RenderBuffer(multisampled) textures");
943
944 self.cache.store_texture_binding(0);
945 self.cache.bind_texture(0, t.params.kind.into(), raw);
946 let wrap_x = match wrap_x {
947 TextureWrap::Repeat => GL_REPEAT,
948 TextureWrap::Mirror => GL_MIRRORED_REPEAT,
949 TextureWrap::Clamp => GL_CLAMP_TO_EDGE,
950 };
951
952 let wrap_y = match wrap_y {
953 TextureWrap::Repeat => GL_REPEAT,
954 TextureWrap::Mirror => GL_MIRRORED_REPEAT,
955 TextureWrap::Clamp => GL_CLAMP_TO_EDGE,
956 };
957
958 unsafe {
959 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap_x as i32);
960 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap_y as i32);
961 }
962 self.cache.restore_texture_binding(0);
963 }
964
965 fn texture_set_min_filter(
966 &mut self,
967 texture: TextureId,
968 filter: FilterMode,
969 mipmap_filter: MipmapFilterMode,
970 ) {
971 let t = self.textures.get(texture);
972 let raw = t.raw.texture().expect(
973 "texture_set_min_filter not yet implemented for RenderBuffer(multisampled) textures",
974 );
975
976 self.cache.store_texture_binding(0);
977 self.cache.bind_texture(0, t.params.kind.into(), raw);
978
979 let filter = Texture::gl_filter(filter, mipmap_filter);
980 unsafe {
981 glTexParameteri(t.params.kind.into(), GL_TEXTURE_MIN_FILTER, filter as i32);
982 }
983 self.cache.restore_texture_binding(0);
984 }
985 fn texture_set_mag_filter(&mut self, texture: TextureId, filter: FilterMode) {
986 let t = self.textures.get(texture);
987 let raw = t
988 .raw
989 .texture()
990 .expect("texture_set_wrap not yet implemented for RenderBuffer(multisampled) textures");
991
992 self.cache.store_texture_binding(0);
993 self.cache.bind_texture(0, t.params.kind.into(), raw);
994
995 let filter = match filter {
996 FilterMode::Nearest => GL_NEAREST,
997 FilterMode::Linear => GL_LINEAR,
998 };
999 unsafe {
1000 glTexParameteri(t.params.kind.into(), GL_TEXTURE_MAG_FILTER, filter as i32);
1001 }
1002 self.cache.restore_texture_binding(0);
1003 }
1004 fn texture_resize(
1005 &mut self,
1006 texture: TextureId,
1007 width: u32,
1008 height: u32,
1009 source: Option<&[u8]>,
1010 ) {
1011 let mut t = self.textures.get(texture);
1012 t.resize(self, width, height, source);
1013 if let TextureIdInner::Managed(tex_id) = texture.0 {
1014 self.textures.0[tex_id].params = t.params;
1015 };
1016 }
1017 fn texture_read_pixels(&mut self, texture: TextureId, source: &mut [u8]) {
1018 let t = self.textures.get(texture);
1019 t.read_pixels(source);
1020 }
1021 fn texture_generate_mipmaps(&mut self, texture: TextureId) {
1022 let t = self.textures.get(texture);
1023 let raw = t.raw.texture().expect(
1024 "texture_generate_mipmaps not yet implemented for RenderBuffer(multisampled) textures",
1025 );
1026
1027 self.cache.store_texture_binding(0);
1028 self.cache.bind_texture(0, t.params.kind.into(), raw);
1029 unsafe {
1030 glGenerateMipmap(t.params.kind.into());
1031 }
1032 self.cache.restore_texture_binding(0);
1033 }
1034 fn texture_update_part(
1035 &mut self,
1036 texture: TextureId,
1037 x_offset: i32,
1038 y_offset: i32,
1039 width: i32,
1040 height: i32,
1041 source: &[u8],
1042 ) {
1043 let t = self.textures.get(texture);
1044 t.update_texture_part(self, x_offset, y_offset, width, height, source);
1045 }
1046 fn texture_params(&self, texture: TextureId) -> TextureParams {
1047 let texture = self.textures.get(texture);
1048 texture.params
1049 }
1050 unsafe fn texture_raw_id(&self, texture: TextureId) -> RawId {
1051 let texture = self.textures.get(texture);
1052 let raw = texture
1053 .raw
1054 .texture()
1055 .expect("For multisampled texture raw_id is not supported");
1056
1057 RawId::OpenGl(raw)
1058 }
1059
1060 fn new_render_pass_mrt(
1061 &mut self,
1062 color_img: &[TextureId],
1063 resolve_img: Option<&[TextureId]>,
1064 depth_img: Option<TextureId>,
1065 ) -> RenderPass {
1066 if color_img.is_empty() && depth_img.is_none() {
1067 panic!("Render pass should have at least one non-none target");
1068 }
1069 let mut gl_fb = 0;
1070
1071 let mut resolves = None;
1072 unsafe {
1073 glGenFramebuffers(1, &mut gl_fb as *mut _);
1074 glBindFramebuffer(GL_FRAMEBUFFER, gl_fb);
1075 for (i, color_img) in color_img.iter().enumerate() {
1076 let texture = self.textures.get(*color_img);
1077 if texture.params.sample_count > 1 {
1078 let raw = texture.raw.renderbuffer().unwrap();
1079 glFramebufferRenderbuffer(
1080 GL_FRAMEBUFFER,
1081 GL_COLOR_ATTACHMENT0 + i as u32,
1082 GL_RENDERBUFFER,
1083 raw,
1084 );
1085 } else {
1086 let raw = texture.raw.texture().unwrap();
1087 glFramebufferTexture2D(
1088 GL_FRAMEBUFFER,
1089 GL_COLOR_ATTACHMENT0 + i as u32,
1090 GL_TEXTURE_2D,
1091 raw,
1092 0,
1093 );
1094 }
1095 }
1096 if let Some(depth_img) = depth_img {
1097 let texture = self.textures.get(depth_img);
1098 if texture.params.sample_count > 1 {
1099 let raw = texture.raw.texture().unwrap();
1100 glFramebufferRenderbuffer(
1101 GL_FRAMEBUFFER,
1102 GL_DEPTH_ATTACHMENT,
1103 GL_RENDERBUFFER,
1104 raw,
1105 );
1106 } else {
1107 let raw = texture.raw.texture().unwrap();
1108 glFramebufferTexture2D(
1109 GL_FRAMEBUFFER,
1110 GL_DEPTH_ATTACHMENT,
1111 GL_TEXTURE_2D,
1112 raw,
1113 0,
1114 );
1115 }
1116 }
1117 let mut attachments = vec![];
1118 for i in 0..color_img.len() {
1119 attachments.push(GL_COLOR_ATTACHMENT0 + i as u32);
1120 }
1121
1122 if color_img.len() > 1 {
1123 glDrawBuffers(color_img.len() as _, attachments.as_ptr() as _);
1124 }
1125
1126 if let Some(resolve_img) = resolve_img {
1127 resolves = Some(vec![]);
1128 let resolves = resolves.as_mut().unwrap();
1129 for (i, resolve_img) in resolve_img.iter().enumerate() {
1130 let mut resolve_fb = 0;
1131 glGenFramebuffers(1, &mut resolve_fb as *mut _);
1132 glBindFramebuffer(GL_FRAMEBUFFER, resolve_fb);
1133 resolves.push((resolve_fb, *resolve_img));
1134 let texture = self.textures.get(*resolve_img);
1135 let raw = texture.raw.texture().unwrap();
1136 glFramebufferTexture2D(
1137 GL_FRAMEBUFFER,
1138 GL_COLOR_ATTACHMENT0 + i as u32,
1139 GL_TEXTURE_2D,
1140 raw,
1141 0,
1142 );
1143 let fb_status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
1144 assert!(fb_status != 0);
1145 glDrawBuffers(1, attachments.as_ptr() as _);
1146 }
1147 }
1148 glBindFramebuffer(GL_FRAMEBUFFER, self.default_framebuffer);
1149 }
1150 let pass = RenderPassInternal {
1151 gl_fb,
1152 color_textures: color_img.to_vec(),
1153 resolves,
1154 depth_texture: depth_img,
1155 };
1156
1157 RenderPass(self.passes.add(pass))
1158 }
1159 fn render_pass_color_attachments(&self, render_pass: RenderPass) -> &[TextureId] {
1160 &self.passes[render_pass.0].color_textures
1161 }
1162 fn delete_render_pass(&mut self, render_pass: RenderPass) {
1163 let pass_id = render_pass.0;
1164
1165 let render_pass = self.passes.remove(pass_id);
1166
1167 unsafe { glDeleteFramebuffers(1, &render_pass.gl_fb as *const _) }
1168
1169 for color_texture in &render_pass.color_textures {
1170 self.delete_texture(*color_texture);
1171 }
1172 if let Some(depth_texture) = render_pass.depth_texture {
1173 self.delete_texture(depth_texture);
1174 }
1175 }
1176
1177 fn new_pipeline(
1178 &mut self,
1179 buffer_layout: &[BufferLayout],
1180 attributes: &[VertexAttribute],
1181 shader: ShaderId,
1182 params: PipelineParams,
1183 ) -> Pipeline {
1184 #[derive(Clone, Copy, Default)]
1185 struct BufferCacheData {
1186 stride: i32,
1187 offset: i64,
1188 }
1189
1190 let mut buffer_cache: Vec<BufferCacheData> =
1191 vec![BufferCacheData::default(); buffer_layout.len()];
1192
1193 for VertexAttribute {
1194 format,
1195 buffer_index,
1196 ..
1197 } in attributes
1198 {
1199 let layout = buffer_layout.get(*buffer_index).unwrap_or_else(|| panic!());
1200 let cache = buffer_cache
1201 .get_mut(*buffer_index)
1202 .unwrap_or_else(|| panic!());
1203
1204 if layout.stride == 0 {
1205 cache.stride += format.size_bytes();
1206 } else {
1207 cache.stride = layout.stride;
1208 }
1209 assert!(cache.stride <= 255);
1211 }
1212
1213 let program = self.shaders[shader.0].program;
1214
1215 let attributes_len = attributes
1216 .iter()
1217 .map(|layout| match layout.format {
1218 VertexFormat::Mat4 => 4,
1219 _ => 1,
1220 })
1221 .sum();
1222
1223 let mut vertex_layout: Vec<Option<VertexAttributeInternal>> = vec![None; attributes_len];
1224
1225 for VertexAttribute {
1226 name,
1227 format,
1228 buffer_index,
1229 gl_pass_as_float,
1230 } in attributes
1231 {
1232 let buffer_data = &mut buffer_cache
1233 .get_mut(*buffer_index)
1234 .unwrap_or_else(|| panic!());
1235 let layout = buffer_layout.get(*buffer_index).unwrap_or_else(|| panic!());
1236
1237 let cname = CString::new(*name).unwrap_or_else(|e| panic!("{}", e));
1238 let attr_loc = unsafe { glGetAttribLocation(program, cname.as_ptr() as *const _) };
1239 let attr_loc = if attr_loc == -1 { None } else { Some(attr_loc) };
1240 let divisor = if layout.step_func == VertexStep::PerVertex {
1241 0
1242 } else {
1243 layout.step_rate
1244 };
1245
1246 let mut attributes_count: usize = 1;
1247 let mut format = *format;
1248
1249 if format == VertexFormat::Mat4 {
1250 format = VertexFormat::Float4;
1251 attributes_count = 4;
1252 }
1253 for i in 0..attributes_count {
1254 if let Some(attr_loc) = attr_loc {
1255 let attr_loc = attr_loc as GLuint + i as GLuint;
1256
1257 let attr = VertexAttributeInternal {
1258 attr_loc,
1259 size: format.components(),
1260 type_: format.type_(),
1261 offset: buffer_data.offset,
1262 stride: buffer_data.stride,
1263 buffer_index: *buffer_index,
1264 divisor,
1265 gl_pass_as_float: *gl_pass_as_float,
1266 };
1267
1268 assert!(
1269 attr_loc < vertex_layout.len() as u32,
1270 "attribute: {} outside of allocated attributes array len: {}",
1271 name,
1272 vertex_layout.len()
1273 );
1274 vertex_layout[attr_loc as usize] = Some(attr);
1275 }
1276 buffer_data.offset += format.size_bytes() as i64
1277 }
1278 }
1279
1280 let pipeline = PipelineInternal {
1281 layout: vertex_layout,
1282 shader,
1283 params,
1284 };
1285
1286 Pipeline(self.pipelines.add(pipeline))
1287 }
1288
1289 fn apply_pipeline(&mut self, pipeline: &Pipeline) {
1290 self.cache.cur_pipeline = Some(*pipeline);
1291
1292 {
1293 let pipeline = &self.pipelines[pipeline.0];
1294 let shader = &self.shaders[pipeline.shader.0];
1295 unsafe {
1296 glUseProgram(shader.program);
1297 }
1298
1299 unsafe {
1300 glEnable(GL_SCISSOR_TEST);
1301 }
1302
1303 if pipeline.params.depth_write {
1304 unsafe {
1305 glEnable(GL_DEPTH_TEST);
1306 glDepthFunc(pipeline.params.depth_test.into())
1307 }
1308 } else {
1309 unsafe {
1310 glDisable(GL_DEPTH_TEST);
1311 }
1312 }
1313
1314 match pipeline.params.front_face_order {
1315 FrontFaceOrder::Clockwise => unsafe {
1316 glFrontFace(GL_CW);
1317 },
1318 FrontFaceOrder::CounterClockwise => unsafe {
1319 glFrontFace(GL_CCW);
1320 },
1321 }
1322 }
1323
1324 self.set_cull_face(self.pipelines[pipeline.0].params.cull_face);
1325 self.set_blend(
1326 self.pipelines[pipeline.0].params.color_blend,
1327 self.pipelines[pipeline.0].params.alpha_blend,
1328 );
1329
1330 self.set_stencil(self.pipelines[pipeline.0].params.stencil_test);
1331 self.set_color_write(self.pipelines[pipeline.0].params.color_write);
1332 }
1333
1334 fn new_buffer(
1335 &mut self,
1336 type_: BufferType,
1337 usage: BufferUsage,
1338 data: BufferSource,
1339 ) -> BufferId {
1340 let gl_target = gl_buffer_target(&type_);
1341 let gl_usage = gl_usage(&usage);
1342 let (size, element_size) = match &data {
1343 BufferSource::Slice(data) => (data.size, data.element_size),
1344 BufferSource::Empty { size, element_size } => (*size, *element_size),
1345 };
1346 let index_type = match type_ {
1347 BufferType::IndexBuffer
1348 if element_size == 1 || element_size == 2 || element_size == 4 =>
1349 {
1350 Some(element_size as u32)
1351 }
1352 BufferType::IndexBuffer => panic!("unsupported index buffer dimension"),
1353 BufferType::VertexBuffer => None,
1354 };
1355 let mut gl_buf: u32 = 0;
1356
1357 unsafe {
1358 glGenBuffers(1, &mut gl_buf as *mut _);
1359 self.cache.store_buffer_binding(gl_target);
1360 self.cache.bind_buffer(gl_target, gl_buf, index_type);
1361
1362 glBufferData(gl_target, size as _, std::ptr::null() as *const _, gl_usage);
1363 if let BufferSource::Slice(data) = data {
1364 debug_assert!(data.is_slice);
1365 glBufferSubData(gl_target, 0, size as _, data.ptr as _);
1366 }
1367 self.cache.restore_buffer_binding(gl_target);
1368 }
1369
1370 let buffer = Buffer {
1371 gl_buf,
1372 buffer_type: type_,
1373 size,
1374 index_type,
1375 };
1376
1377 BufferId(self.buffers.add(buffer))
1378 }
1379
1380 fn buffer_update(&mut self, buffer: BufferId, data: BufferSource) {
1381 let data = match data {
1382 BufferSource::Slice(data) => data,
1383 _ => panic!("buffer_update expects BufferSource::slice"),
1384 };
1385 debug_assert!(data.is_slice);
1386 let buffer = &self.buffers[buffer.0];
1387
1388 if matches!(buffer.buffer_type, BufferType::IndexBuffer) {
1389 assert!(buffer.index_type.is_some());
1390 assert!(data.element_size as u32 == buffer.index_type.unwrap());
1391 };
1392
1393 let size = data.size;
1394
1395 assert!(size <= buffer.size);
1396
1397 let gl_target = gl_buffer_target(&buffer.buffer_type);
1398 self.cache.store_buffer_binding(gl_target);
1399 self.cache
1400 .bind_buffer(gl_target, buffer.gl_buf, buffer.index_type);
1401 unsafe { glBufferSubData(gl_target, 0, size as _, data.ptr as _) };
1402 self.cache.restore_buffer_binding(gl_target);
1403 }
1404
1405 fn buffer_size(&mut self, buffer: BufferId) -> usize {
1407 self.buffers[buffer.0].size
1408 }
1409
1410 fn delete_buffer(&mut self, buffer: BufferId) {
1418 unsafe { glDeleteBuffers(1, &self.buffers[buffer.0].gl_buf as *const _) }
1419 self.cache.clear_buffer_bindings();
1420 self.cache.clear_vertex_attributes();
1421 self.buffers.remove(buffer.0);
1422 }
1423
1424 fn apply_viewport(&mut self, x: i32, y: i32, w: i32, h: i32) {
1427 unsafe {
1428 glViewport(x, y, w, h);
1429 }
1430 }
1431
1432 fn apply_scissor_rect(&mut self, x: i32, y: i32, w: i32, h: i32) {
1435 unsafe {
1436 glScissor(x, y, w, h);
1437 }
1438 }
1439
1440 fn apply_bindings_from_slice(
1441 &mut self,
1442 vertex_buffers: &[BufferId],
1443 index_buffer: BufferId,
1444 textures: &[TextureId],
1445 ) {
1446 let pip = &self.pipelines[self.cache.cur_pipeline.unwrap().0];
1447 let shader = &self.shaders[pip.shader.0];
1448
1449 for (n, shader_image) in shader.images.iter().enumerate() {
1450 let bindings_image = textures
1451 .get(n)
1452 .unwrap_or_else(|| panic!("Image count in bindings and shader did not match!"));
1453 if let Some(gl_loc) = shader_image.gl_loc {
1454 let texture = self.textures.get(*bindings_image);
1455 let raw = match texture.raw {
1456 TextureOrRenderbuffer::Texture(id) => id,
1457 TextureOrRenderbuffer::Renderbuffer(id) => id,
1458 };
1459 unsafe {
1460 self.cache.bind_texture(n, texture.params.kind.into(), raw);
1461 glUniform1i(gl_loc, n as i32);
1462 }
1463 }
1464 }
1465
1466 self.cache.bind_buffer(
1467 GL_ELEMENT_ARRAY_BUFFER,
1468 self.buffers[index_buffer.0].gl_buf,
1469 self.buffers[index_buffer.0].index_type,
1470 );
1471
1472 let pip = &self.pipelines[self.cache.cur_pipeline.unwrap().0];
1473
1474 for attr_index in 0..MAX_VERTEX_ATTRIBUTES {
1475 let cached_attr = &mut self.cache.attributes[attr_index];
1476
1477 let pip_attribute = pip.layout.get(attr_index).copied();
1478
1479 if let Some(Some(attribute)) = pip_attribute {
1480 assert!(
1481 attribute.buffer_index < vertex_buffers.len(),
1482 "Attribute index outside of vertex_buffers length"
1483 );
1484 let vb = vertex_buffers[attribute.buffer_index];
1485 let vb = self.buffers[vb.0];
1486
1487 if cached_attr.map_or(true, |cached_attr| {
1488 attribute != cached_attr.attribute || cached_attr.gl_vbuf != vb.gl_buf
1489 }) {
1490 self.cache
1491 .bind_buffer(GL_ARRAY_BUFFER, vb.gl_buf, vb.index_type);
1492
1493 unsafe {
1494 match attribute.type_ {
1495 GL_INT | GL_UNSIGNED_INT | GL_SHORT | GL_UNSIGNED_SHORT
1496 | GL_UNSIGNED_BYTE | GL_BYTE
1497 if !attribute.gl_pass_as_float =>
1498 {
1499 glVertexAttribIPointer(
1500 attr_index as GLuint,
1501 attribute.size,
1502 attribute.type_,
1503 attribute.stride,
1504 attribute.offset as *mut _,
1505 )
1506 }
1507 _ => glVertexAttribPointer(
1508 attr_index as GLuint,
1509 attribute.size,
1510 attribute.type_,
1511 GL_FALSE as u8,
1512 attribute.stride,
1513 attribute.offset as *mut _,
1514 ),
1515 }
1516 if self.info.features.instancing {
1517 glVertexAttribDivisor(attr_index as GLuint, attribute.divisor as u32);
1518 }
1519 glEnableVertexAttribArray(attr_index as GLuint);
1520 };
1521
1522 let cached_attr = &mut self.cache.attributes[attr_index];
1523 *cached_attr = Some(CachedAttribute {
1524 attribute,
1525 gl_vbuf: vb.gl_buf,
1526 });
1527 }
1528 } else if cached_attr.is_some() {
1529 unsafe {
1530 glDisableVertexAttribArray(attr_index as GLuint);
1531 }
1532 *cached_attr = None;
1533 }
1534 }
1535 }
1536
1537 fn apply_uniforms_from_bytes(&mut self, uniform_ptr: *const u8, size: usize) {
1538 let pip = &self.pipelines[self.cache.cur_pipeline.unwrap().0];
1539 let shader = &self.shaders[pip.shader.0];
1540
1541 let mut offset = 0;
1542
1543 for uniform in shader.uniforms.iter() {
1544 use UniformType::*;
1545
1546 assert!(
1547 offset as i32 <= size as i32 - uniform.uniform_type.size() as i32 / 4,
1548 "Uniforms struct does not match shader uniforms layout"
1549 );
1550
1551 unsafe {
1552 let data = (uniform_ptr as *const f32).add(offset);
1553 let data_int = (uniform_ptr as *const i32).add(offset);
1554
1555 if let Some(gl_loc) = uniform.gl_loc {
1556 match uniform.uniform_type {
1557 Float1 => {
1558 glUniform1fv(gl_loc, uniform.array_count, data);
1559 }
1560 Float2 => {
1561 glUniform2fv(gl_loc, uniform.array_count, data);
1562 }
1563 Float3 => {
1564 glUniform3fv(gl_loc, uniform.array_count, data);
1565 }
1566 Float4 => {
1567 glUniform4fv(gl_loc, uniform.array_count, data);
1568 }
1569 Int1 => {
1570 glUniform1iv(gl_loc, uniform.array_count, data_int);
1571 }
1572 Int2 => {
1573 glUniform2iv(gl_loc, uniform.array_count, data_int);
1574 }
1575 Int3 => {
1576 glUniform3iv(gl_loc, uniform.array_count, data_int);
1577 }
1578 Int4 => {
1579 glUniform4iv(gl_loc, uniform.array_count, data_int);
1580 }
1581 Mat4 => {
1582 glUniformMatrix4fv(gl_loc, uniform.array_count, 0, data);
1583 }
1584 }
1585 }
1586 }
1587 offset += uniform.uniform_type.size() / 4 * uniform.array_count as usize;
1588 }
1589 }
1590
1591 fn clear(
1592 &mut self,
1593 color: Option<(f32, f32, f32, f32)>,
1594 depth: Option<f32>,
1595 stencil: Option<i32>,
1596 ) {
1597 let mut bits = 0;
1598 if let Some((r, g, b, a)) = color {
1599 bits |= GL_COLOR_BUFFER_BIT;
1600 unsafe {
1601 glClearColor(r, g, b, a);
1602 }
1603 }
1604
1605 if let Some(v) = depth {
1606 bits |= GL_DEPTH_BUFFER_BIT;
1607 unsafe {
1608 glClearDepthf(v);
1609 }
1610 }
1611
1612 if let Some(v) = stencil {
1613 bits |= GL_STENCIL_BUFFER_BIT;
1614 unsafe {
1615 glClearStencil(v);
1616 }
1617 }
1618
1619 if bits != 0 {
1620 unsafe {
1621 glClear(bits);
1622 }
1623 }
1624 }
1625
1626 fn begin_default_pass(&mut self, action: PassAction) {
1627 self.begin_pass(None, action);
1628 }
1629
1630 fn begin_pass(&mut self, pass: Option<RenderPass>, action: PassAction) {
1631 self.cache.cur_pass = pass;
1632 let (framebuffer, w, h) = match pass {
1633 None => {
1634 let (screen_width, screen_height) = window::screen_size();
1635
1636 (
1637 self.default_framebuffer,
1638 screen_width as i32,
1639 screen_height as i32,
1640 )
1641 }
1642 Some(pass) => {
1643 let pass = &self.passes[pass.0];
1644 let texture = pass
1647 .color_textures
1648 .first()
1649 .copied()
1650 .or(pass.depth_texture)
1651 .unwrap();
1652 (
1653 pass.gl_fb,
1654 self.textures.get(texture).params.width as i32,
1655 self.textures.get(texture).params.height as i32,
1656 )
1657 }
1658 };
1659 unsafe {
1660 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
1661 glViewport(0, 0, w, h);
1662 glScissor(0, 0, w, h);
1663 }
1664 match action {
1665 PassAction::Nothing => {}
1666 PassAction::Clear {
1667 color,
1668 depth,
1669 stencil,
1670 } => {
1671 self.clear(color, depth, stencil);
1672 }
1673 }
1674 }
1675
1676 fn end_render_pass(&mut self) {
1677 unsafe {
1678 if let Some(pass) = self.cache.cur_pass.take() {
1679 let pass = &self.passes[pass.0];
1680 if let Some(resolves) = &pass.resolves {
1681 glBindFramebuffer(GL_READ_FRAMEBUFFER, pass.gl_fb);
1682 for (i, (resolve_fb, resolve_img)) in resolves.iter().enumerate() {
1683 let texture = self.textures.get(*resolve_img);
1684 let w = texture.params.width;
1685 let h = texture.params.height;
1686 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, *resolve_fb);
1687 glReadBuffer(GL_COLOR_ATTACHMENT0 + i as u32);
1688 glBlitFramebuffer(
1689 0,
1690 0,
1691 w as _,
1692 h as _,
1693 0,
1694 0,
1695 w as _,
1696 h as _,
1697 GL_COLOR_BUFFER_BIT,
1698 GL_NEAREST,
1699 );
1700 }
1701 }
1702 }
1703 glBindFramebuffer(GL_FRAMEBUFFER, self.default_framebuffer);
1704 self.cache.bind_buffer(GL_ARRAY_BUFFER, 0, None);
1705 self.cache.bind_buffer(GL_ELEMENT_ARRAY_BUFFER, 0, None);
1706 }
1707 }
1708
1709 fn commit_frame(&mut self) {
1710 self.cache.clear_buffer_bindings();
1711 self.cache.clear_texture_bindings();
1712 }
1713
1714 fn draw(&self, base_element: i32, num_elements: i32, num_instances: i32) {
1715 assert!(
1716 self.cache.cur_pipeline.is_some(),
1717 "Drawing without any binded pipeline"
1718 );
1719
1720 if !self.info.features.instancing && num_instances != 1 {
1721 eprintln!("Instanced rendering is not supported by the GPU");
1722 eprintln!("Ignoring this draw call");
1723 return;
1724 }
1725
1726 let pip = &self.pipelines[self.cache.cur_pipeline.unwrap().0];
1727 let primitive_type = pip.params.primitive_type.into();
1728 let index_type = self.cache.index_type.expect("Unset index buffer type");
1729
1730 unsafe {
1731 glDrawElementsInstanced(
1732 primitive_type,
1733 num_elements,
1734 match index_type {
1735 1 => GL_UNSIGNED_BYTE,
1736 2 => GL_UNSIGNED_SHORT,
1737 4 => GL_UNSIGNED_INT,
1738 _ => panic!("Unsupported index buffer type!"),
1739 },
1740 (index_type as i32 * base_element) as *mut _,
1741 num_instances,
1742 );
1743 }
1744 }
1745}