1use std::{ cmp, mem, fmt };
53use std::error::Error;
54use std::cell::RefCell;
55use std::marker::PhantomData;
56use std::hash::BuildHasherDefault;
57use std::collections::HashMap;
58
59use fnv::FnvHasher;
60use smallvec::SmallVec;
61
62use crate::CapabilitiesSource;
63use crate::GlObject;
64use crate::TextureExt;
65
66use crate::texture::CubeLayer;
67use crate::texture::TextureAnyImage;
68use crate::texture::TextureAnyMipmap;
69use crate::texture::TextureKind;
70use crate::framebuffer::RenderBufferAny;
71
72use crate::gl;
73use crate::context::CommandContext;
74use crate::version::Version;
75use crate::version::Api;
76
77pub fn is_dimensions_mismatch_supported<C: ?Sized>(context: &C) -> bool where C: CapabilitiesSource {
83 context.get_version() >= &Version(Api::Gl, 3, 0) ||
84 context.get_version() >= &Version(Api::GlEs, 2, 0) ||
85 context.get_extensions().gl_arb_framebuffer_object
86}
87
88#[derive(Clone)]
90pub enum FramebufferAttachments<'a> {
91 Regular(FramebufferSpecificAttachments<RegularAttachment<'a>>),
93
94 Layered(FramebufferSpecificAttachments<LayeredAttachment<'a>>),
96
97 Empty {
99 width: u32,
100 height: u32,
101 layers: Option<u32>,
102 samples: Option<u32>,
103 fixed_samples: bool,
104 },
105}
106
107#[derive(Copy, Clone)]
109pub enum RegularAttachment<'a> {
110 Texture(TextureAnyImage<'a>),
112 RenderBuffer(&'a RenderBufferAny),
114}
115
116impl<'a> RegularAttachment<'a> {
117 #[inline]
119 pub fn kind(&self) -> TextureKind {
120 match self {
121 RegularAttachment::Texture(t) => t.get_texture().kind(),
122 RegularAttachment::RenderBuffer(rb) => rb.kind(),
123 }
124 }
125}
126
127#[derive(Copy, Clone)]
129pub struct LayeredAttachment<'a>(TextureAnyMipmap<'a>);
130
131#[derive(Copy, Clone)]
133pub enum DepthStencilAttachments<T> {
134 None,
136
137 DepthAttachment(T),
139
140 StencilAttachment(T),
142
143 DepthAndStencilAttachments(T, T),
145
146 DepthStencilAttachment(T),
148}
149
150#[derive(Clone)]
152pub struct FramebufferSpecificAttachments<T> {
153 pub colors: SmallVec<[(u32, T); 5]>,
156
157 pub depth_stencil: DepthStencilAttachments<T>,
159}
160
161impl<'a> FramebufferAttachments<'a> {
162 #[inline]
165 pub fn validate<C: ?Sized>(self, context: &C) -> Result<ValidatedAttachments<'a>, ValidationError>
166 where C: CapabilitiesSource
167 {
168 match self {
169 FramebufferAttachments::Regular(a) => FramebufferAttachments::validate_regular(context, a),
170 FramebufferAttachments::Layered(a) => FramebufferAttachments::validate_layered(context, a),
171
172 FramebufferAttachments::Empty { width, height, layers, samples, fixed_samples } => {
173 if context.get_version() >= &Version(Api::Gl, 4, 3) ||
174 context.get_version() >= &Version(Api::GlEs, 3, 1) ||
175 context.get_extensions().gl_arb_framebuffer_no_attachments
176 {
177 assert!(width >= 1);
178 assert!(height >= 1);
179 if let Some(layers) = layers { assert!(layers >= 1); }
180 if let Some(samples) = samples { assert!(samples >= 1); }
181
182 if width > context.get_capabilities().max_framebuffer_width.unwrap_or(0) as u32 ||
183 height > context.get_capabilities().max_framebuffer_height.unwrap_or(0) as u32 ||
184 samples.unwrap_or(0) > context.get_capabilities()
185 .max_framebuffer_samples.unwrap_or(0) as u32 ||
186 layers.unwrap_or(0) > context.get_capabilities()
187 .max_framebuffer_layers.unwrap_or(0) as u32
188 {
189 return Err(ValidationError::EmptyFramebufferUnsupportedDimensions);
190 }
191
192 Ok(ValidatedAttachments {
193 raw: RawAttachments {
194 color: Vec::new(),
195 depth: None,
196 stencil: None,
197 depth_stencil: None,
198 default_width: Some(width),
199 default_height: Some(height),
200 default_layers: if context.get_version() <= &Version(Api::GlEs, 3, 1) { None } else { Some(layers.unwrap_or(0)) },
201 default_samples: Some(samples.unwrap_or(0)),
202 default_samples_fixed: Some(fixed_samples),
203 },
204 dimensions: (width, height),
205 layers,
206 depth_buffer_bits: None,
207 stencil_buffer_bits: None,
208 marker: PhantomData,
209 })
210
211 } else {
212 Err(ValidationError::EmptyFramebufferObjectsNotSupported)
213 }
214 },
215 }
216 }
217
218 fn validate_layered<C: ?Sized>(context: &C, FramebufferSpecificAttachments { colors, depth_stencil }:
219 FramebufferSpecificAttachments<LayeredAttachment<'a>>)
220 -> Result<ValidatedAttachments<'a>, ValidationError>
221 where C: CapabilitiesSource
222 {
223 macro_rules! handle_tex {
226 ($tex:ident, $dim:ident, $samples:ident, $num_bits:ident) => ({
227 $num_bits = Some($tex.get_texture().get_internal_format()
228 .map(|f| f.get_total_bits()).ok().unwrap_or(24) as u16); handle_tex!($tex, $dim, $samples)
230 });
231
232 ($tex:ident, $dim:ident, $samples:ident) => ({
233 let context = $tex.get_texture().get_context();
235
236 match &mut $samples {
237 &mut Some(samples) => {
238 if samples != $tex.get_samples().unwrap_or(0) {
239 return Err(ValidationError::SamplesCountMismatch);
240 }
241 },
242 s @ &mut None => {
243 *s = Some($tex.get_samples().unwrap_or(0));
244 }
245 }
246
247 match &mut $dim {
248 &mut Some((ref mut w, ref mut h)) => {
249 let height = $tex.get_height().unwrap_or(1);
250 if *w != $tex.get_width() || *h != height {
251 *w = cmp::min(*w, $tex.get_width());
252 *h = cmp::min(*h, height);
253
254 if !is_dimensions_mismatch_supported(context) {
256 return Err(ValidationError::DimensionsMismatchNotSupported);
257 }
258 }
259 },
260
261 dim @ &mut None => {
262 *dim = Some(($tex.get_width(), $tex.get_height().unwrap_or(1)));
263 },
264 }
265
266 RawAttachment::Texture {
267 texture: $tex.get_texture().get_id(),
268 bind_point: $tex.get_texture().get_bind_point(),
269 layer: None,
270 level: $tex.get_level(),
271 cubemap_layer: None,
272 }
273 });
274 }
275
276 let max_color_attachments = context.get_capabilities().max_color_attachments;
277 if colors.len() > max_color_attachments as usize {
278 return Err(ValidationError::TooManyColorAttachments{
279 maximum: max_color_attachments as usize,
280 obtained: colors.len(),
281 });
282 }
283
284 let mut raw_attachments = RawAttachments {
285 color: Vec::with_capacity(colors.len()),
286 depth: None,
287 stencil: None,
288 depth_stencil: None,
289 default_width: None,
290 default_height: None,
291 default_layers: None,
292 default_samples: None,
293 default_samples_fixed: None,
294 };
295
296 let mut dimensions = None;
297 let mut depth_bits = None;
298 let mut stencil_bits = None;
299 let mut samples = None; for &(index, LayeredAttachment(ref attachment)) in colors.iter() {
302 if index >= max_color_attachments as u32 {
303 return Err(ValidationError::TooManyColorAttachments{
304 maximum: max_color_attachments as usize,
305 obtained: index as usize,
306 });
307 }
308 raw_attachments.color.push((index, handle_tex!(attachment, dimensions, samples)));
309 }
310
311 match depth_stencil {
312 DepthStencilAttachments::None => (),
313 DepthStencilAttachments::DepthAttachment(LayeredAttachment(ref d)) => {
314 raw_attachments.depth = Some(handle_tex!(d, dimensions, samples, depth_bits));
315 },
316 DepthStencilAttachments::StencilAttachment(LayeredAttachment(ref s)) => {
317 raw_attachments.stencil = Some(handle_tex!(s, dimensions, samples, stencil_bits));
318 },
319 DepthStencilAttachments::DepthAndStencilAttachments(LayeredAttachment(ref d),
320 LayeredAttachment(ref s))
321 => {
322 raw_attachments.depth = Some(handle_tex!(d, dimensions, samples, depth_bits));
323 raw_attachments.stencil = Some(handle_tex!(s, dimensions, samples, stencil_bits));
324 },
325 DepthStencilAttachments::DepthStencilAttachment(LayeredAttachment(ref ds)) => {
326 let depth_stencil_bits = ds.get_texture().get_depth_stencil_bits();
327 depth_bits = Some(depth_stencil_bits.0);
328 stencil_bits = Some(depth_stencil_bits.1);
329 raw_attachments.depth_stencil = Some(handle_tex!(ds, dimensions, samples));
330 },
331 }
332
333 let dimensions = if let Some(dimensions) = dimensions {
334 if dimensions.0 * dimensions.1 == 0 {
335 return Err(ValidationError::EmptyFramebufferUnsupportedDimensions);
336 }
337 dimensions
338 } else {
339 return Err(ValidationError::EmptyFramebufferObjectsNotSupported);
341 };
342
343 Ok(ValidatedAttachments {
344 raw: raw_attachments,
345 dimensions,
346 layers: None, depth_buffer_bits: depth_bits,
348 stencil_buffer_bits: stencil_bits,
349 marker: PhantomData,
350 })
351 }
352
353 fn validate_regular<C: ?Sized>(context: &C, FramebufferSpecificAttachments { colors, depth_stencil }:
354 FramebufferSpecificAttachments<RegularAttachment<'a>>)
355 -> Result<ValidatedAttachments<'a>, ValidationError>
356 where C: CapabilitiesSource
357 {
358 macro_rules! handle_tex {
359 ($tex:ident, $dim:ident, $samples:ident, $num_bits:ident) => ({
360 $num_bits = Some($tex.get_texture().get_internal_format()
361 .map(|f| f.get_total_bits()).ok().unwrap_or(24) as u16); handle_tex!($tex, $dim, $samples)
363 });
364
365 ($tex:ident, $dim:ident, $samples:ident) => ({
366 let context = $tex.get_texture().get_context();
368
369 match &mut $samples {
370 &mut Some(samples) => {
371 if samples != $tex.get_samples().unwrap_or(0) {
372 return Err(ValidationError::SamplesCountMismatch);
373 }
374 },
375 s @ &mut None => {
376 *s = Some($tex.get_samples().unwrap_or(0));
377 }
378 }
379
380 match &mut $dim {
381 &mut Some((ref mut w, ref mut h)) => {
382 let height = $tex.get_height().unwrap_or(1);
383 if *w != $tex.get_width() || *h != height {
384 *w = cmp::min(*w, $tex.get_width());
385 *h = cmp::min(*h, height);
386
387 if !is_dimensions_mismatch_supported(context) {
389 return Err(ValidationError::DimensionsMismatchNotSupported);
390 }
391 }
392 },
393
394 dim @ &mut None => {
395 *dim = Some(($tex.get_width(), $tex.get_height().unwrap_or(1)));
396 },
397 }
398
399 RawAttachment::Texture {
400 texture: $tex.get_texture().get_id(),
401 bind_point: $tex.get_texture().get_bind_point(),
402 layer: Some($tex.get_layer()),
403 level: $tex.get_level(),
404 cubemap_layer: $tex.get_cubemap_layer(),
405 }
406 });
407 }
408
409 macro_rules! handle_rb {
410 ($rb:ident, $dim:ident, $samples:ident, $num_bits:ident) => ({
411 $num_bits = Some(24); handle_rb!($rb, $dim, $samples)
413 });
414
415 ($rb:ident, $dim:ident, $samples:ident) => ({
416 let context = $rb.get_context();
418 let dimensions = $rb.get_dimensions();
419
420 match &mut $samples {
421 &mut Some(samples) => {
422 if samples != $rb.get_samples().unwrap_or(0) {
423 return Err(ValidationError::SamplesCountMismatch);
424 }
425 },
426 s @ &mut None => {
427 *s = Some($rb.get_samples().unwrap_or(0));
428 }
429 }
430
431 match &mut $dim {
432 &mut Some((ref mut w, ref mut h)) => {
433 if *w != dimensions.0 || *h != dimensions.1 {
434 *w = cmp::min(*w, dimensions.0);
435 *h = cmp::min(*h, dimensions.1);
436
437 if !is_dimensions_mismatch_supported(context) {
439 return Err(ValidationError::DimensionsMismatchNotSupported);
440 }
441 }
442 },
443
444 dim @ &mut None => {
445 *dim = Some((dimensions.0, dimensions.1));
446 },
447 }
448
449 RawAttachment::RenderBuffer($rb.get_id())
450 });
451 }
452
453 macro_rules! handle_atch {
454 ($atch:ident, $($t:tt)*) => (
455 match $atch {
456 &RegularAttachment::Texture(ref tex) => handle_tex!(tex, $($t)*),
457 &RegularAttachment::RenderBuffer(ref rb) => handle_rb!(rb, $($t)*),
458 }
459 );
460 }
461
462 let max_color_attachments = context.get_capabilities().max_color_attachments;
463 if colors.len() > max_color_attachments as usize {
464 return Err(ValidationError::TooManyColorAttachments{
465 maximum: max_color_attachments as usize,
466 obtained: colors.len(),
467 });
468 }
469
470 let mut raw_attachments = RawAttachments {
471 color: Vec::with_capacity(colors.len()),
472 depth: None,
473 stencil: None,
474 depth_stencil: None,
475 default_width: None,
476 default_height: None,
477 default_layers: None,
478 default_samples: None,
479 default_samples_fixed: None,
480 };
481
482 let mut dimensions = None;
483 let mut depth_bits = None;
484 let mut stencil_bits = None;
485 let mut samples = None; for &(index, ref attachment) in colors.iter() {
488 if index >= max_color_attachments as u32 {
489 return Err(ValidationError::TooManyColorAttachments{
490 maximum: max_color_attachments as usize,
491 obtained: index as usize,
492 });
493 }
494 raw_attachments.color.push((index, handle_atch!(attachment, dimensions, samples)));
495 }
496
497 match depth_stencil {
498 DepthStencilAttachments::None => (),
499 DepthStencilAttachments::DepthAttachment(ref d) => {
500 raw_attachments.depth = Some(handle_atch!(d, dimensions, samples, depth_bits));
501 },
502 DepthStencilAttachments::StencilAttachment(ref s) => {
503 raw_attachments.stencil = Some(handle_atch!(s, dimensions, samples, stencil_bits));
504 },
505 DepthStencilAttachments::DepthAndStencilAttachments(ref d, ref s) => {
506 raw_attachments.depth = Some(handle_atch!(d, dimensions, samples, depth_bits));
507 raw_attachments.stencil = Some(handle_atch!(s, dimensions, samples, stencil_bits));
508 },
509 DepthStencilAttachments::DepthStencilAttachment(ref ds) => {
510 let depth_stencil_bits = match ds {
511 RegularAttachment::Texture(ref tex) =>
512 tex.get_texture().get_depth_stencil_bits(),
513 RegularAttachment::RenderBuffer(ref rb) =>
514 rb.get_depth_stencil_bits(),
515 };
516 depth_bits = Some(depth_stencil_bits.0);
517 stencil_bits = Some(depth_stencil_bits.1);
518 raw_attachments.depth_stencil = Some(handle_atch!(ds, dimensions, samples));
519 },
520 }
521
522 let dimensions = if let Some(dimensions) = dimensions {
523 if dimensions.0 * dimensions.1 == 0 {
524 return Err(ValidationError::EmptyFramebufferUnsupportedDimensions);
525 }
526 dimensions
527 } else {
528 return Err(ValidationError::EmptyFramebufferObjectsNotSupported);
530 };
531
532 Ok(ValidatedAttachments {
533 raw: raw_attachments,
534 dimensions,
535 layers: None,
536 depth_buffer_bits: depth_bits,
537 stencil_buffer_bits: stencil_bits,
538 marker: PhantomData,
539 })
540 }
541}
542
543#[derive(Clone)]
545pub struct ValidatedAttachments<'a> {
546 raw: RawAttachments,
547 dimensions: (u32, u32),
548 layers: Option<u32>,
549 depth_buffer_bits: Option<u16>,
550 stencil_buffer_bits: Option<u16>,
551 marker: PhantomData<&'a ()>,
552}
553
554impl<'a> ValidatedAttachments<'a> {
555 #[inline]
557 pub fn is_layered(&self) -> bool {
558 self.layers.is_some()
559 }
560
561 #[inline]
563 pub fn get_dimensions(&self) -> (u32, u32) {
564 self.dimensions
565 }
566
567 #[inline]
570 pub fn get_depth_buffer_bits(&self) -> Option<u16> {
571 self.depth_buffer_bits
572 }
573
574 #[inline]
577 pub fn get_stencil_buffer_bits(&self) -> Option<u16> {
578 self.stencil_buffer_bits
579 }
580}
581
582#[derive(Copy, Clone, Debug, PartialEq, Eq)]
584pub enum ValidationError {
585 EmptyFramebufferObjectsNotSupported,
587
588 EmptyFramebufferUnsupportedDimensions,
590
591 DimensionsMismatchNotSupported,
596
597 SamplesCountMismatch,
599
600 TooManyColorAttachments {
602 maximum: usize,
604 obtained: usize,
606 },
607}
608
609impl fmt::Display for ValidationError {
610 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
611 use self::ValidationError::*;
612 let desc = match self {
613 EmptyFramebufferObjectsNotSupported =>
614 "You requested an empty framebuffer object, but they are not supported",
615 EmptyFramebufferUnsupportedDimensions =>
616 "The requested characteristics of an empty framebuffer object are out of range",
617 DimensionsMismatchNotSupported =>
618 "The backend doesn't support attachments with various dimensions",
619 SamplesCountMismatch =>
620 "All attachments must have the same number of samples",
621 TooManyColorAttachments {..} =>
622 "Backends only support a certain number of color attachments",
623 };
624 match self {
625 TooManyColorAttachments{ ref maximum, ref obtained } =>
626 write!(fmt, "{}: found {}, maximum: {}", desc, obtained, maximum),
627 _ =>
628 fmt.write_str(desc),
629 }
630 }
631}
632
633impl Error for ValidationError {}
634
635#[derive(Hash, Clone, Eq, PartialEq)]
639struct RawAttachments {
640 color: Vec<(u32, RawAttachment)>,
642 depth: Option<RawAttachment>,
643 stencil: Option<RawAttachment>,
644 depth_stencil: Option<RawAttachment>,
645
646 default_width: Option<u32>,
648 default_height: Option<u32>,
649 default_layers: Option<u32>,
650 default_samples: Option<u32>,
651 default_samples_fixed: Option<bool>,
652}
653
654#[derive(Hash, Copy, Clone, Eq, PartialEq)]
656enum RawAttachment {
657 Texture {
659 bind_point: gl::types::GLenum, texture: gl::types::GLuint,
663 layer: Option<u32>,
666 level: u32,
668 cubemap_layer: Option<CubeLayer>,
670 },
671
672 RenderBuffer(gl::types::GLuint),
674}
675
676#[derive(Debug, Copy, Clone)]
678pub enum ClearBufferData {
679 Float([f32; 4]),
681 Integral([i32; 4]),
683 Unsigned([u32; 4]),
685 Depth(f32),
687 Stencil(i32),
689 DepthStencil(f32, i32),
691}
692
693impl From<[f32; 4]> for ClearBufferData {
694 #[inline]
695 fn from(data: [f32; 4]) -> ClearBufferData {
696 ClearBufferData::Float(data)
697 }
698}
699
700impl From<[i32; 4]> for ClearBufferData {
701 #[inline]
702 fn from(data: [i32; 4]) -> ClearBufferData {
703 ClearBufferData::Integral(data)
704 }
705}
706
707impl From<[u32; 4]> for ClearBufferData {
708 #[inline]
709 fn from(data: [u32; 4]) -> ClearBufferData {
710 ClearBufferData::Unsigned(data)
711 }
712}
713
714pub struct FramebuffersContainer {
718 framebuffers: RefCell<HashMap<RawAttachments, FrameBufferObject, BuildHasherDefault<FnvHasher>>>,
719}
720
721impl FramebuffersContainer {
722 #[inline]
724 pub fn new() -> FramebuffersContainer {
725 FramebuffersContainer {
726 framebuffers: RefCell::new(HashMap::with_hasher(Default::default())),
727 }
728 }
729
730 pub fn purge_all(ctxt: &mut CommandContext<'_>) {
732 let mut other = HashMap::with_hasher(Default::default());
733 mem::swap(&mut *ctxt.framebuffer_objects.framebuffers.borrow_mut(), &mut other);
734
735 for (_, obj) in other.into_iter() {
736 obj.destroy(ctxt);
737 }
738 }
739
740 #[inline]
742 pub fn purge_texture(ctxt: &mut CommandContext<'_>, texture: gl::types::GLuint) {
743 FramebuffersContainer::purge_if(ctxt, |a| {
744 matches!(a, &RawAttachment::Texture { texture: id, .. } if id == texture)
745 });
746 }
747
748 #[inline]
750 pub fn purge_renderbuffer(ctxt: &mut CommandContext<'_>, renderbuffer: gl::types::GLuint) {
751 FramebuffersContainer::purge_if(ctxt, |a| a == &RawAttachment::RenderBuffer(renderbuffer));
752 }
753
754 fn purge_if<F>(ctxt: &mut CommandContext<'_>, condition: F)
756 where F: Fn(&RawAttachment) -> bool
757 {
758 let mut framebuffers = ctxt.framebuffer_objects.framebuffers.borrow_mut();
759
760 let mut attachments = Vec::with_capacity(0);
761 for (key, _) in framebuffers.iter() {
762 if key.color.iter().any(|&(_, ref id)| condition(id)) {
763 attachments.push(key.clone());
764 continue;
765 }
766
767 if let Some(ref atch) = key.depth {
768 if condition(atch) {
769 attachments.push(key.clone());
770 continue;
771 }
772 }
773
774 if let Some(ref atch) = key.stencil {
775 if condition(atch) {
776 attachments.push(key.clone());
777 continue;
778 }
779 }
780
781 if let Some(ref atch) = key.depth_stencil {
782 if condition(atch) {
783 attachments.push(key.clone());
784 continue;
785 }
786 }
787 }
788
789 for atch in attachments.into_iter() {
790 framebuffers.remove(&atch).unwrap().destroy(ctxt);
791 }
792 }
793
794 pub fn cleanup(ctxt: &mut CommandContext<'_>) {
799 let mut other = HashMap::with_hasher(Default::default());
800 mem::swap(&mut *ctxt.framebuffer_objects.framebuffers.borrow_mut(), &mut other);
801
802 for (_, obj) in other.into_iter() {
803 obj.destroy(ctxt);
804 }
805 }
806
807 #[inline]
813 pub fn get_framebuffer_for_drawing(ctxt: &mut CommandContext<'_>,
814 attachments: Option<&ValidatedAttachments<'_>>)
815 -> gl::types::GLuint
816 {
817 if let Some(attachments) = attachments {
818 FramebuffersContainer::get_framebuffer(ctxt, attachments)
819 } else {
820 0
821 }
822 }
823
824 #[inline]
828 pub fn bind_default_framebuffer_for_reading(ctxt: &mut CommandContext<'_>,
829 read_buffer: gl::types::GLenum)
830 {
831 unsafe { bind_framebuffer(ctxt, 0, false, true) };
832 unsafe { ctxt.gl.ReadBuffer(read_buffer) }; }
834
835 pub unsafe fn bind_framebuffer_for_reading(ctxt: &mut CommandContext<'_>, attachment: &RegularAttachment<'_>) {
843 let attachments = FramebufferAttachments::Regular(FramebufferSpecificAttachments {
853 colors: { let mut v = SmallVec::new(); v.push((0, *attachment)); v },
854 depth_stencil: DepthStencilAttachments::None,
855 }).validate(ctxt).unwrap();
856
857 let framebuffer = FramebuffersContainer::get_framebuffer_for_drawing(ctxt, Some(&attachments));
858 bind_framebuffer(ctxt, framebuffer, false, true);
859 ctxt.gl.ReadBuffer(gl::COLOR_ATTACHMENT0); }
861
862 pub unsafe fn clear_buffer<D>(ctxt: &mut CommandContext<'_>, attachment: &RegularAttachment<'_>,
873 data: D)
874 where D: Into<ClearBufferData>
875 {
876 let data = data.into();
879
880 let fb = FramebufferAttachments::Regular(FramebufferSpecificAttachments {
881 colors: { let mut v = SmallVec::new(); v.push((0, *attachment)); v },
882 depth_stencil: DepthStencilAttachments::None,
883 }).validate(ctxt).unwrap();
884 let fb = FramebuffersContainer::get_framebuffer_for_drawing(ctxt, Some(&fb));
885
886 bind_framebuffer(ctxt, fb, true, false);
890
891 match (attachment.kind(), data) {
892 (TextureKind::Float, ClearBufferData::Float(data)) => {
893 ctxt.gl.ClearBufferfv(gl::COLOR, 0, data.as_ptr());
894 },
895 (TextureKind::Integral, ClearBufferData::Integral(data)) => {
896 ctxt.gl.ClearBufferiv(gl::COLOR, 0, data.as_ptr());
897 },
898 (TextureKind::Unsigned, ClearBufferData::Unsigned(data)) => {
899 ctxt.gl.ClearBufferuiv(gl::COLOR, 0, data.as_ptr());
900 },
901 (TextureKind::Depth, _) => {
902 unimplemented!() },
904 (TextureKind::Stencil, _) => {
905 unimplemented!() },
907 (TextureKind::DepthStencil, _) => {
908 unimplemented!() },
910 _ => {
911 panic!("The data passed to `clear_buffer` does not match the kind of attachment");
912 }
913 }
914 }
915
916 fn get_framebuffer(ctxt: &mut CommandContext<'_>, attachments: &ValidatedAttachments<'_>)
922 -> gl::types::GLuint
923 {
924 let mut framebuffers = ctxt.framebuffer_objects.framebuffers.borrow_mut();
926 if let Some(value) = framebuffers.get(&attachments.raw) {
927 return value.id;
928 }
929
930 let new_fbo = FrameBufferObject::new(ctxt, &attachments.raw);
931 let new_fbo_id = new_fbo.id;
932 framebuffers.insert(attachments.raw.clone(), new_fbo);
933 new_fbo_id
934 }
935}
936
937impl Drop for FramebuffersContainer {
938 #[inline]
939 fn drop(&mut self) {
940 if self.framebuffers.borrow().len() != 0 {
941 panic!()
942 }
943 }
944}
945
946struct FrameBufferObject {
948 id: gl::types::GLuint,
949 current_read_buffer: gl::types::GLenum,
950}
951
952impl FrameBufferObject {
953 fn new(mut ctxt: &mut CommandContext<'_>, attachments: &RawAttachments) -> FrameBufferObject {
960 if attachments.color.len() > ctxt.capabilities.max_draw_buffers as usize {
961 panic!("Trying to attach {} color buffers, but the hardware only supports {}",
962 attachments.color.len(), ctxt.capabilities.max_draw_buffers);
963 }
964
965 let id = unsafe {
967 let mut id = 0;
968
969 if ctxt.version >= &Version(Api::Gl, 4, 5) ||
970 ctxt.extensions.gl_arb_direct_state_access
971 {
972 ctxt.gl.CreateFramebuffers(1, &mut id);
973
974 } else if ctxt.version >= &Version(Api::Gl, 3, 0) ||
975 ctxt.version >= &Version(Api::GlEs, 2, 0) ||
976 ctxt.extensions.gl_arb_framebuffer_object
977 {
978 ctxt.gl.GenFramebuffers(1, &mut id);
979 bind_framebuffer(&mut ctxt, id, true, false);
980
981 } else if ctxt.extensions.gl_ext_framebuffer_object {
982 ctxt.gl.GenFramebuffersEXT(1, &mut id);
983 bind_framebuffer(&mut ctxt, id, true, false);
984
985 } else {
986 unreachable!();
988 }
989
990 id
991 };
992
993 if let Some(width) = attachments.default_width {
996 unsafe { bind_framebuffer(&mut ctxt, id, true, false) }; if ctxt.version >= &Version(Api::Gl, 4, 3) || ctxt.version >= &Version(Api::GlEs, 3, 1) ||
998 ctxt.extensions.gl_arb_framebuffer_no_attachments
999 {
1000 unsafe {
1001 ctxt.gl.FramebufferParameteri(gl::DRAW_FRAMEBUFFER, gl::FRAMEBUFFER_DEFAULT_WIDTH,
1002 width as gl::types::GLint);
1003 }
1004 } else {
1005 unreachable!();
1006 }
1007 }
1008 if let Some(height) = attachments.default_height {
1009 unsafe { bind_framebuffer(&mut ctxt, id, true, false) }; if ctxt.version >= &Version(Api::Gl, 4, 3) || ctxt.version >= &Version(Api::GlEs, 3, 1) ||
1011 ctxt.extensions.gl_arb_framebuffer_no_attachments
1012 {
1013 unsafe {
1014 ctxt.gl.FramebufferParameteri(gl::DRAW_FRAMEBUFFER, gl::FRAMEBUFFER_DEFAULT_HEIGHT,
1015 height as gl::types::GLint);
1016 }
1017 } else {
1018 unreachable!();
1019 }
1020 }
1021 if let Some(layers) = attachments.default_layers {
1022 unsafe { bind_framebuffer(&mut ctxt, id, true, false) }; if ctxt.version >= &Version(Api::Gl, 4, 3) || ctxt.version >= &Version(Api::GlEs, 3, 2) ||
1024 ctxt.extensions.gl_arb_framebuffer_no_attachments
1025 {
1026 unsafe {
1027 ctxt.gl.FramebufferParameteri(gl::DRAW_FRAMEBUFFER, gl::FRAMEBUFFER_DEFAULT_LAYERS,
1028 layers as gl::types::GLint);
1029 }
1030 } else {
1031 unreachable!();
1032 }
1033 }
1034 if let Some(samples) = attachments.default_samples {
1035 unsafe { bind_framebuffer(&mut ctxt, id, true, false) }; if ctxt.version >= &Version(Api::Gl, 4, 3) || ctxt.version >= &Version(Api::GlEs, 3, 1) ||
1037 ctxt.extensions.gl_arb_framebuffer_no_attachments
1038 {
1039 unsafe {
1040 ctxt.gl.FramebufferParameteri(gl::DRAW_FRAMEBUFFER, gl::FRAMEBUFFER_DEFAULT_SAMPLES,
1041 samples as gl::types::GLint);
1042 }
1043 } else {
1044 unreachable!();
1045 }
1046 }
1047 if let Some(samples_fixed) = attachments.default_samples_fixed {
1048 unsafe { bind_framebuffer(&mut ctxt, id, true, false) }; if ctxt.version >= &Version(Api::Gl, 4, 3) || ctxt.version >= &Version(Api::GlEs, 3, 1) ||
1050 ctxt.extensions.gl_arb_framebuffer_no_attachments
1051 {
1052 unsafe {
1053 ctxt.gl.FramebufferParameteri(gl::DRAW_FRAMEBUFFER, gl::FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS,
1054 if samples_fixed { 1 } else { 0 });
1055 }
1056 } else {
1057 unreachable!();
1058 }
1059 }
1060
1061 let mut raw_attachments = Vec::with_capacity(attachments.color.len());
1063 for (attachment_pos, &(pos_in_drawbuffers, atchmnt)) in attachments.color.iter().enumerate() {
1064 if attachment_pos >= ctxt.capabilities.max_color_attachments as usize {
1065 panic!("Trying to attach a color buffer to slot {}, but the hardware only supports {} bind points",
1066 attachment_pos, ctxt.capabilities.max_color_attachments);
1067 }
1068 unsafe { attach(&mut ctxt, gl::COLOR_ATTACHMENT0 + attachment_pos as u32, id, atchmnt) };
1069
1070 while raw_attachments.len() <= pos_in_drawbuffers as usize { raw_attachments.push(gl::NONE); }
1071 raw_attachments[pos_in_drawbuffers as usize] = gl::COLOR_ATTACHMENT0 + attachment_pos as u32;
1072 }
1073 if let Some(depth) = attachments.depth {
1074 unsafe { attach(&mut ctxt, gl::DEPTH_ATTACHMENT, id, depth) };
1075 }
1076 if let Some(stencil) = attachments.stencil {
1077 unsafe { attach(&mut ctxt, gl::STENCIL_ATTACHMENT, id, stencil) };
1078 }
1079 if let Some(depth_stencil) = attachments.depth_stencil {
1080 unsafe { attach(&mut ctxt, gl::DEPTH_STENCIL_ATTACHMENT, id, depth_stencil) };
1081 }
1082
1083 if raw_attachments != &[gl::COLOR_ATTACHMENT0] {
1085 if ctxt.version >= &Version(Api::Gl, 4, 5) ||
1086 ctxt.extensions.gl_arb_direct_state_access
1087 {
1088 unsafe {
1089 ctxt.gl.NamedFramebufferDrawBuffers(id, raw_attachments.len()
1090 as gl::types::GLsizei,
1091 raw_attachments.as_ptr());
1092 }
1093
1094 } else if ctxt.version >= &Version(Api::Gl, 2, 0) ||
1095 ctxt.version >= &Version(Api::GlEs, 3, 0)
1096 {
1097 unsafe {
1098 bind_framebuffer(&mut ctxt, id, true, false);
1099 ctxt.gl.DrawBuffers(raw_attachments.len() as gl::types::GLsizei,
1100 raw_attachments.as_ptr());
1101 }
1102
1103 } else if ctxt.extensions.gl_arb_draw_buffers {
1104 unsafe {
1105 bind_framebuffer(&mut ctxt, id, true, false);
1106 ctxt.gl.DrawBuffersARB(raw_attachments.len() as gl::types::GLsizei,
1107 raw_attachments.as_ptr());
1108 }
1109
1110 } else if ctxt.extensions.gl_ati_draw_buffers {
1111 unsafe {
1112 bind_framebuffer(&mut ctxt, id, true, false);
1113 ctxt.gl.DrawBuffersATI(raw_attachments.len() as gl::types::GLsizei,
1114 raw_attachments.as_ptr());
1115 }
1116
1117 } else {
1118 panic!("Using more than one attachment is not supported by the backend");
1120 }
1121 }
1122
1123
1124 FrameBufferObject {
1125 id,
1126 current_read_buffer: gl::BACK,
1127 }
1128 }
1129
1130 fn destroy(self, ctxt: &mut CommandContext<'_>) {
1132 if ctxt.state.draw_framebuffer == self.id {
1134 ctxt.state.draw_framebuffer = 0;
1135 }
1136
1137 if ctxt.state.read_framebuffer == self.id {
1138 ctxt.state.read_framebuffer = 0;
1139 }
1140
1141 if ctxt.version >= &Version(Api::Gl, 3, 0) ||
1143 ctxt.version >= &Version(Api::GlEs, 2, 0) ||
1144 ctxt.extensions.gl_arb_framebuffer_object
1145 {
1146 unsafe { ctxt.gl.DeleteFramebuffers(1, [ self.id ].as_ptr()) };
1147 } else if ctxt.extensions.gl_ext_framebuffer_object {
1148 unsafe { ctxt.gl.DeleteFramebuffersEXT(1, [ self.id ].as_ptr()) };
1149 } else {
1150 unreachable!();
1151 }
1152 }
1153}
1154
1155impl GlObject for FrameBufferObject {
1156 type Id = gl::types::GLuint;
1157
1158 #[inline]
1159 fn get_id(&self) -> gl::types::GLuint {
1160 self.id
1161 }
1162}
1163
1164pub unsafe fn bind_framebuffer(ctxt: &mut CommandContext<'_>, fbo_id: gl::types::GLuint,
1171 draw: bool, read: bool)
1172{
1173 if draw && read {
1174 if ctxt.state.draw_framebuffer != fbo_id || ctxt.state.read_framebuffer != fbo_id {
1175 if ctxt.version >= &Version(Api::Gl, 3, 0) ||
1176 ctxt.version >= &Version(Api::GlEs, 2, 0) ||
1177 ctxt.extensions.gl_arb_framebuffer_object
1178 {
1179 ctxt.gl.BindFramebuffer(gl::FRAMEBUFFER, fbo_id);
1180 ctxt.state.draw_framebuffer = fbo_id;
1181 ctxt.state.read_framebuffer = fbo_id;
1182 } else if ctxt.extensions.gl_ext_framebuffer_object {
1183 ctxt.gl.BindFramebufferEXT(gl::FRAMEBUFFER_EXT, fbo_id);
1184 ctxt.state.draw_framebuffer = fbo_id;
1185 ctxt.state.read_framebuffer = fbo_id;
1186 } else {
1187 unreachable!();
1188 }
1189 }
1190
1191
1192 } else {
1193
1194 if draw && ctxt.state.draw_framebuffer != fbo_id {
1195 if ctxt.version >= &Version(Api::Gl, 3, 0) ||
1196 ctxt.extensions.gl_arb_framebuffer_object
1197 {
1198 ctxt.gl.BindFramebuffer(gl::DRAW_FRAMEBUFFER, fbo_id);
1199 ctxt.state.draw_framebuffer = fbo_id;
1200 } else if ctxt.version >= &Version(Api::GlEs, 2, 0) {
1201 ctxt.gl.BindFramebuffer(gl::FRAMEBUFFER, fbo_id);
1202 ctxt.state.draw_framebuffer = fbo_id;
1203 ctxt.state.read_framebuffer = fbo_id;
1204 } else if ctxt.extensions.gl_ext_framebuffer_object {
1205 ctxt.gl.BindFramebufferEXT(gl::FRAMEBUFFER_EXT, fbo_id);
1206 ctxt.state.draw_framebuffer = fbo_id;
1207 ctxt.state.read_framebuffer = fbo_id;
1208 } else {
1209 unreachable!();
1210 }
1211 }
1212
1213 if read && ctxt.state.read_framebuffer != fbo_id {
1214 if ctxt.version >= &Version(Api::Gl, 3, 0) ||
1215 ctxt.extensions.gl_arb_framebuffer_object
1216 {
1217 ctxt.gl.BindFramebuffer(gl::READ_FRAMEBUFFER, fbo_id);
1218 ctxt.state.read_framebuffer = fbo_id;
1219 } else if ctxt.version >= &Version(Api::GlEs, 2, 0) {
1220 ctxt.gl.BindFramebuffer(gl::FRAMEBUFFER, fbo_id);
1221 ctxt.state.draw_framebuffer = fbo_id;
1222 ctxt.state.read_framebuffer = fbo_id;
1223 } else if ctxt.extensions.gl_ext_framebuffer_object {
1224 ctxt.gl.BindFramebufferEXT(gl::FRAMEBUFFER_EXT, fbo_id);
1225 ctxt.state.draw_framebuffer = fbo_id;
1226 ctxt.state.read_framebuffer = fbo_id;
1227 } else {
1228 unreachable!();
1229 }
1230 }
1231
1232 }
1233}
1234
1235unsafe fn attach(ctxt: &mut CommandContext<'_>, slot: gl::types::GLenum,
1248 id: gl::types::GLuint, attachment: RawAttachment)
1249{
1250 match attachment {
1251 RawAttachment::Texture { texture: tex_id, level, layer, bind_point, cubemap_layer } => {
1252 match bind_point {
1253 gl::TEXTURE_2D | gl::TEXTURE_2D_MULTISAMPLE | gl::TEXTURE_1D |
1255 gl::TEXTURE_RECTANGLE =>
1256 {
1257 assert_eq!(layer, Some(0));
1258 debug_assert!(cubemap_layer.is_none());
1259
1260 if ctxt.version >= &Version(Api::Gl, 4, 5) ||
1261 ctxt.extensions.gl_arb_direct_state_access
1262 {
1263 ctxt.gl.NamedFramebufferTexture(id, slot, tex_id,
1264 level as gl::types::GLint);
1265
1266 } else if ctxt.extensions.gl_ext_direct_state_access &&
1267 ctxt.extensions.gl_ext_geometry_shader4
1268 {
1269 ctxt.gl.NamedFramebufferTextureEXT(id, slot, tex_id,
1270 level as gl::types::GLint);
1271
1272 } else if ctxt.version >= &Version(Api::Gl, 3, 2) {
1273 bind_framebuffer(ctxt, id, true, false);
1274 ctxt.gl.FramebufferTexture(gl::DRAW_FRAMEBUFFER,
1275 slot, tex_id, level as gl::types::GLint);
1276
1277 } else if ctxt.version >= &Version(Api::Gl, 3, 0) ||
1278 ctxt.extensions.gl_arb_framebuffer_object
1279 {
1280 bind_framebuffer(ctxt, id, true, false);
1281
1282 match bind_point {
1283 gl::TEXTURE_1D | gl::TEXTURE_RECTANGLE => {
1284 ctxt.gl.FramebufferTexture1D(gl::DRAW_FRAMEBUFFER,
1285 slot, bind_point, tex_id,
1286 level as gl::types::GLint);
1287 },
1288 gl::TEXTURE_2D | gl::TEXTURE_2D_MULTISAMPLE => {
1289 ctxt.gl.FramebufferTexture2D(gl::DRAW_FRAMEBUFFER,
1290 slot, bind_point, tex_id,
1291 level as gl::types::GLint);
1292 },
1293 _ => unreachable!()
1294 }
1295
1296 } else if ctxt.version >= &Version(Api::GlEs, 2, 0) {
1297 bind_framebuffer(ctxt, id, true, true);
1298 assert!(bind_point == gl::TEXTURE_2D);
1299 ctxt.gl.FramebufferTexture2D(gl::FRAMEBUFFER, slot, bind_point, tex_id,
1300 level as gl::types::GLint);
1301
1302 } else if ctxt.extensions.gl_ext_framebuffer_object {
1303 bind_framebuffer(ctxt, id, true, true);
1304
1305 match bind_point {
1306 gl::TEXTURE_1D | gl::TEXTURE_RECTANGLE => {
1307 ctxt.gl.FramebufferTexture1DEXT(gl::FRAMEBUFFER_EXT,
1308 slot, bind_point, tex_id,
1309 level as gl::types::GLint);
1310 },
1311 gl::TEXTURE_2D | gl::TEXTURE_2D_MULTISAMPLE => {
1312 ctxt.gl.FramebufferTexture2DEXT(gl::FRAMEBUFFER_EXT,
1313 slot, bind_point, tex_id,
1314 level as gl::types::GLint);
1315 },
1316 _ => unreachable!()
1317 }
1318
1319 } else {
1320 unreachable!();
1322 }
1323 },
1324
1325 gl::TEXTURE_1D_ARRAY | gl::TEXTURE_2D_ARRAY | gl::TEXTURE_2D_MULTISAMPLE_ARRAY |
1327 gl::TEXTURE_3D | gl::TEXTURE_CUBE_MAP_ARRAY if layer.is_some() =>
1328 {
1329 let layer = if bind_point == gl::TEXTURE_CUBE_MAP_ARRAY {
1330 layer.unwrap() * 6 + cubemap_layer.unwrap().get_layer_index()
1331 as gl::types::GLenum
1332 } else {
1333 layer.unwrap()
1334 };
1335
1336 if ctxt.version >= &Version(Api::Gl, 4, 5) ||
1337 ctxt.extensions.gl_arb_direct_state_access
1338 {
1339 ctxt.gl.NamedFramebufferTextureLayer(id, slot, tex_id,
1340 level as gl::types::GLint,
1341 layer as gl::types::GLint);
1342
1343 } else if ctxt.extensions.gl_ext_direct_state_access &&
1344 ctxt.extensions.gl_ext_geometry_shader4
1345 {
1346 ctxt.gl.NamedFramebufferTextureLayerEXT(id, slot, tex_id,
1347 level as gl::types::GLint,
1348 layer as gl::types::GLint);
1349
1350 } else if ctxt.version >= &Version(Api::Gl, 3, 0) ||
1351 ctxt.extensions.gl_arb_framebuffer_object
1352 {
1353 bind_framebuffer(ctxt, id, true, false);
1354
1355 match bind_point {
1356 gl::TEXTURE_1D_ARRAY | gl::TEXTURE_2D_ARRAY |
1357 gl::TEXTURE_2D_MULTISAMPLE_ARRAY => {
1358 ctxt.gl.FramebufferTextureLayer(gl::DRAW_FRAMEBUFFER,
1359 slot, tex_id,
1360 level as gl::types::GLint,
1361 layer as gl::types::GLint);
1362
1363 },
1364
1365 gl::TEXTURE_3D => {
1366 ctxt.gl.FramebufferTexture3D(gl::DRAW_FRAMEBUFFER,
1367 slot, bind_point, tex_id,
1368 level as gl::types::GLint,
1369 layer as gl::types::GLint);
1370 },
1371
1372 _ => unreachable!()
1373 }
1374
1375 } else if ctxt.extensions.gl_ext_framebuffer_object &&
1376 bind_point == gl::TEXTURE_3D
1377 {
1378 bind_framebuffer(ctxt, id, true, true);
1379 ctxt.gl.FramebufferTexture3DEXT(gl::FRAMEBUFFER_EXT,
1380 slot, bind_point, tex_id,
1381 level as gl::types::GLint,
1382 layer as gl::types::GLint);
1383
1384 } else if ctxt.extensions.gl_ext_texture_array &&
1385 bind_point == gl::TEXTURE_1D_ARRAY ||
1386 bind_point == gl::TEXTURE_2D_ARRAY ||
1387 bind_point == gl::TEXTURE_2D_MULTISAMPLE_ARRAY
1388 {
1389 bind_framebuffer(ctxt, id, true, false);
1390 ctxt.gl.FramebufferTextureLayerEXT(gl::DRAW_FRAMEBUFFER,
1391 slot, tex_id,
1392 level as gl::types::GLint,
1393 layer as gl::types::GLint);
1394
1395 } else {
1396 panic!("Attaching a texture array is not supported");
1397 }
1398 },
1399
1400 gl::TEXTURE_1D_ARRAY | gl::TEXTURE_2D_ARRAY | gl::TEXTURE_2D_MULTISAMPLE_ARRAY |
1402 gl::TEXTURE_3D | gl::TEXTURE_CUBE_MAP_ARRAY if layer.is_none() =>
1403 {
1404 if ctxt.version >= &Version(Api::Gl, 4, 5) ||
1405 ctxt.extensions.gl_arb_direct_state_access
1406 {
1407 ctxt.gl.NamedFramebufferTexture(id, slot, tex_id,
1408 level as gl::types::GLint);
1409
1410 } else if ctxt.extensions.gl_ext_direct_state_access &&
1411 ctxt.extensions.gl_ext_geometry_shader4
1412 {
1413 ctxt.gl.NamedFramebufferTextureEXT(id, slot, tex_id,
1414 level as gl::types::GLint);
1415
1416 } else if ctxt.version >= &Version(Api::Gl, 3, 2) {
1417 bind_framebuffer(ctxt, id, true, false);
1418 ctxt.gl.FramebufferTexture(gl::DRAW_FRAMEBUFFER,
1419 slot, tex_id, level as gl::types::GLint);
1420
1421 } else {
1422 panic!("Layered framebuffers are not supported");
1424 }
1425 },
1426
1427 gl::TEXTURE_CUBE_MAP if layer.is_some() => {
1429 let bind_point = gl::TEXTURE_CUBE_MAP_POSITIVE_X +
1430 cubemap_layer.unwrap().get_layer_index() as gl::types::GLenum;
1431
1432 if ctxt.version >= &Version(Api::Gl, 3, 0) ||
1433 ctxt.extensions.gl_arb_framebuffer_object
1434 {
1435 bind_framebuffer(ctxt, id, true, false);
1436 ctxt.gl.FramebufferTexture2D(gl::DRAW_FRAMEBUFFER,
1437 slot, bind_point, tex_id,
1438 level as gl::types::GLint);
1439
1440 } else if ctxt.version >= &Version(Api::GlEs, 2, 0) {
1441 bind_framebuffer(ctxt, id, true, true);
1442 ctxt.gl.FramebufferTexture2D(gl::FRAMEBUFFER, slot, bind_point, tex_id,
1443 level as gl::types::GLint);
1444
1445 } else if ctxt.extensions.gl_ext_framebuffer_object {
1446 bind_framebuffer(ctxt, id, true, true);
1447 ctxt.gl.FramebufferTexture2DEXT(gl::FRAMEBUFFER_EXT,
1448 slot, bind_point, tex_id,
1449 level as gl::types::GLint);
1450
1451 } else {
1452 unreachable!();
1454 }
1455 },
1456
1457 gl::TEXTURE_CUBE_MAP if layer.is_none() => {
1459 if ctxt.version >= &Version(Api::Gl, 4, 5) ||
1460 ctxt.extensions.gl_arb_direct_state_access
1461 {
1462 ctxt.gl.NamedFramebufferTexture(id, slot, tex_id,
1463 level as gl::types::GLint);
1464
1465 } else if ctxt.extensions.gl_ext_direct_state_access &&
1466 ctxt.extensions.gl_ext_geometry_shader4
1467 {
1468 ctxt.gl.NamedFramebufferTextureEXT(id, slot, tex_id,
1469 level as gl::types::GLint);
1470
1471 } else if ctxt.version >= &Version(Api::Gl, 3, 2) {
1472 bind_framebuffer(ctxt, id, true, false);
1473 ctxt.gl.FramebufferTexture(gl::DRAW_FRAMEBUFFER,
1474 slot, tex_id, level as gl::types::GLint);
1475
1476 } else {
1477 panic!("Layered framebuffers are not supported");
1479 }
1480 },
1481
1482 _ => unreachable!()
1483 }
1484 },
1485
1486 RawAttachment::RenderBuffer(renderbuffer) => {
1488 if ctxt.version >= &Version(Api::Gl, 4, 5) ||
1489 ctxt.extensions.gl_arb_direct_state_access
1490 {
1491 ctxt.gl.NamedFramebufferRenderbuffer(id, slot, gl::RENDERBUFFER, renderbuffer);
1492
1493 } else if ctxt.extensions.gl_ext_direct_state_access &&
1494 ctxt.extensions.gl_ext_geometry_shader4
1495 {
1496 ctxt.gl.NamedFramebufferRenderbufferEXT(id, slot, gl::RENDERBUFFER, renderbuffer);
1497
1498 } else if ctxt.version >= &Version(Api::Gl, 3, 0) ||
1499 ctxt.extensions.gl_arb_framebuffer_object
1500 {
1501 bind_framebuffer(ctxt, id, true, false);
1502 ctxt.gl.FramebufferRenderbuffer(gl::DRAW_FRAMEBUFFER, slot,
1503 gl::RENDERBUFFER, renderbuffer);
1504
1505 } else if ctxt.version >= &Version(Api::GlEs, 2, 0) {
1506 bind_framebuffer(ctxt, id, true, true);
1507 ctxt.gl.FramebufferRenderbuffer(gl::DRAW_FRAMEBUFFER, slot,
1508 gl::RENDERBUFFER, renderbuffer);
1509
1510 } else if ctxt.extensions.gl_ext_framebuffer_object {
1511 bind_framebuffer(ctxt, id, true, true);
1512 ctxt.gl.FramebufferRenderbufferEXT(gl::DRAW_FRAMEBUFFER, slot,
1513 gl::RENDERBUFFER, renderbuffer);
1514
1515 } else {
1516 unreachable!();
1518 }
1519 },
1520 }
1521}