glium/framebuffer/
mod.rs

1/*!
2Framebuffers allow you to customize the color, depth and stencil buffers you will draw on.
3
4In order to draw on a texture, use a `SimpleFrameBuffer`. This framebuffer is compatible with
5shaders that write to `gl_FragColor`.
6
7```no_run
8# use glium::texture::Texture2d;
9# use glutin::surface::{ResizeableSurface, SurfaceTypeTrait};
10# fn example<T>(display: glium::Display<T>, texture: Texture2d)
11#     where T: SurfaceTypeTrait + ResizeableSurface {
12let framebuffer = glium::framebuffer::SimpleFrameBuffer::new(&display, &texture);
13// framebuffer.draw(...);    // draws over `texture`
14# }
15```
16
17If, however, your shader wants to write to multiple color buffers at once, you must use
18a `MultiOutputFrameBuffer`.
19
20```no_run
21# use glium::texture::Texture2d;
22# use glutin::surface::{ResizeableSurface, SurfaceTypeTrait};
23# fn example<T>(display: glium::Display<T>, texture1: Texture2d, texture2: Texture2d)
24#     where T: SurfaceTypeTrait + ResizeableSurface {
25let output = [ ("output1", &texture1), ("output2", &texture2) ];
26let framebuffer = glium::framebuffer::MultiOutputFrameBuffer::new(&display, output.iter().cloned());
27// framebuffer.draw(...);
28
29// example shader:
30//
31//     out vec4 output1;
32//     out vec4 output2;
33//
34//     void main() {
35//         output1 = vec4(0.0, 0.0, 0.5, 1.0);
36//         output2 = vec4(1.0, 0.7, 1.0, 1.0);
37//     }
38# }
39```
40
41**Note**: depth-stencil attachments are not yet implemented.
42
43# A note on restrictions
44
45Some restrictions apply when you use framebuffers:
46
47 - All textures must have an internal format that is renderable. Not all formats are supported.
48
49 - All attachments must have the same number of samples, or must all have multisampling disabled.
50   For example you can't create a texture with 4x multisampling, another texture with 2x
51   multisampling, and draw on them simultaneously.
52
53 - On old hardware all the framebuffer attachments must have the same dimensions (on more recent
54   hardware the intersection between all the attachments is taken if all attachments don't have
55   the same dimensions). You can use the `is_dimensions_mismatch_supported` function to check
56   what the hardware supports.
57
58 - You will get undefined results if you try to sample to a texture mipmap attached to the
59   framebuffer that you are using. This is not enforced by glium as it depends on your shader's
60   source code.
61
62# Empty framebuffers
63
64Modern OpenGL implementations support empty framebuffers. This is handled by glium with the
65`EmptyFrameBuffer` struct.
66
67You can check whether they are supported by calling `EmptyFrameBuffer::is_supported(&display)`.
68
69# Layered framebuffers
70
71Not yet supported
72
73*/
74use std::rc::Rc;
75use smallvec::SmallVec;
76
77use crate::texture::TextureAnyImage;
78
79use crate::backend::Facade;
80use crate::context::Context;
81use crate::{CapabilitiesSource, BlitMask};
82use crate::version::Version;
83use crate::version::Api;
84
85use crate::FboAttachments;
86use crate::Rect;
87use crate::BlitTarget;
88use crate::ContextExt;
89use crate::ToGlEnum;
90use crate::ops;
91use crate::uniforms;
92
93use crate::{Program, Surface};
94use crate::DrawError;
95
96use crate::fbo;
97
98pub use self::default_fb::{DefaultFramebufferAttachment, DefaultFramebuffer};
99pub use self::render_buffer::{RenderBuffer, RenderBufferAny, DepthRenderBuffer};
100pub use self::render_buffer::{StencilRenderBuffer, DepthStencilRenderBuffer};
101pub use self::render_buffer::CreationError as RenderBufferCreationError;
102pub use crate::fbo::is_dimensions_mismatch_supported;
103pub use crate::fbo::ValidationError;
104use crate::uniforms::MagnifySamplerFilter;
105
106mod default_fb;
107mod render_buffer;
108
109/// A framebuffer which has only one color attachment.
110pub struct SimpleFrameBuffer<'a> {
111    context: Rc<Context>,
112    attachments: fbo::ValidatedAttachments<'a>,
113}
114
115impl<'a> SimpleFrameBuffer<'a> {
116    /// Creates a `SimpleFrameBuffer` with a single color attachment and no depth
117    /// nor stencil buffer.
118    #[inline]
119    pub fn new<F: ?Sized, C>(facade: &F, color: C) -> Result<SimpleFrameBuffer<'a>, ValidationError>
120                     where C: ToColorAttachment<'a>, F: Facade
121    {
122        SimpleFrameBuffer::new_impl(facade, Some(color.to_color_attachment()), None, None, None)
123    }
124
125    /// Creates a `SimpleFrameBuffer` with a single color attachment and a depth
126    /// buffer, but no stencil buffer.
127    #[inline]
128    pub fn with_depth_buffer<F: ?Sized, C, D>(facade: &F, color: C, depth: D)
129                                      -> Result<SimpleFrameBuffer<'a>, ValidationError>
130                                      where C: ToColorAttachment<'a>,
131                                            D: ToDepthAttachment<'a>, F: Facade
132    {
133        SimpleFrameBuffer::new_impl(facade, Some(color.to_color_attachment()),
134                                    Some(depth.to_depth_attachment()), None, None)
135    }
136
137    /// Creates a `SimpleFrameBuffer` with a depth buffer and no color attachment
138    /// nor stencil buffer.
139    #[inline]
140    pub fn depth_only<F: ?Sized, D>(facade: &F, depth: D)
141                            -> Result<SimpleFrameBuffer<'a>, ValidationError>
142        where D: ToDepthAttachment<'a>, F: Facade
143    {
144        SimpleFrameBuffer::new_impl(facade, None, Some(depth.to_depth_attachment()), None, None)
145    }
146
147    /// Creates a `SimpleFrameBuffer` with a single color attachment, a depth
148    /// buffer, and a stencil buffer.
149    #[inline]
150    pub fn with_depth_and_stencil_buffer<F: ?Sized, C, D, S>(facade: &F, color: C, depth: D,
151                                                     stencil: S)
152                                                     -> Result<SimpleFrameBuffer<'a>,
153                                                               ValidationError>
154                                                     where C: ToColorAttachment<'a>,
155                                                           D: ToDepthAttachment<'a>,
156                                                           S: ToStencilAttachment<'a>, F: Facade
157    {
158        SimpleFrameBuffer::new_impl(facade, Some(color.to_color_attachment()),
159                                    Some(depth.to_depth_attachment()),
160                                    Some(stencil.to_stencil_attachment()), None)
161    }
162
163    /// Creates a `SimpleFrameBuffer` with a depth buffer and a stencil buffer,
164    /// but no color attachment.
165    #[inline]
166    pub fn depth_and_stencil_only<F: ?Sized, D, S>(facade: &F, depth: D, stencil: S)
167                                           -> Result<SimpleFrameBuffer<'a>, ValidationError>
168        where D: ToDepthAttachment<'a>,
169              S: ToStencilAttachment<'a>, F: Facade
170    {
171        SimpleFrameBuffer::new_impl(facade, None, Some(depth.to_depth_attachment()),
172                                    Some(stencil.to_stencil_attachment()), None)
173    }
174
175    /// Creates a `SimpleFrameBuffer` with a single color attachment and a stencil
176    /// buffer, but no depth buffer.
177    #[inline]
178    pub fn with_stencil_buffer<F: ?Sized, C, S>(facade: &F, color: C, stencil: S)
179                                        -> Result<SimpleFrameBuffer<'a>, ValidationError>
180                                        where C: ToColorAttachment<'a>, S: ToStencilAttachment<'a>,
181                                              F: Facade
182    {
183        SimpleFrameBuffer::new_impl(facade, Some(color.to_color_attachment()), None,
184                                    Some(stencil.to_stencil_attachment()), None)
185    }
186
187    /// Creates a `SimpleFrameBuffer` with a stencil buffer and no color attachment
188    /// nor depth buffer.
189    #[inline]
190    pub fn stencil_only<F: ?Sized, S>(facade: &F, stencil: S)
191                              -> Result<SimpleFrameBuffer<'a>, ValidationError>
192        where S: ToStencilAttachment<'a>, F: Facade
193    {
194        SimpleFrameBuffer::new_impl(facade, None, None, Some(stencil.to_stencil_attachment()),
195                                    None)
196    }
197
198    /// Creates a `SimpleFrameBuffer` with a single color attachment and a depth-stencil buffer.
199    #[inline]
200    pub fn with_depth_stencil_buffer<F: ?Sized, C, D>(facade: &F, color: C, depthstencil: D)
201                                              -> Result<SimpleFrameBuffer<'a>, ValidationError>
202                                              where C: ToColorAttachment<'a>,
203                                                    D: ToDepthStencilAttachment<'a>, F: Facade
204    {
205        SimpleFrameBuffer::new_impl(facade, Some(color.to_color_attachment()), None, None,
206                                    Some(depthstencil.to_depth_stencil_attachment()))
207    }
208
209    /// Creates a `SimpleFrameBuffer` with a depth-stencil buffer and no color attachment.
210    #[inline]
211    pub fn depth_stencil_only<F: ?Sized, D>(facade: &F, depthstencil: D)
212                                    -> Result<SimpleFrameBuffer<'a>, ValidationError>
213        where D: ToDepthStencilAttachment<'a>, F: Facade
214    {
215        SimpleFrameBuffer::new_impl(facade, None, None, None,
216                                    Some(depthstencil.to_depth_stencil_attachment()))
217    }
218
219
220    fn new_impl<F: ?Sized>(facade: &F, color: Option<ColorAttachment<'a>>,
221                   depth: Option<DepthAttachment<'a>>, stencil: Option<StencilAttachment<'a>>,
222                   depthstencil: Option<DepthStencilAttachment<'a>>)
223                   -> Result<SimpleFrameBuffer<'a>, ValidationError> where F: Facade
224    {
225        let color = color.map(|color| match color {
226            ColorAttachment::Texture(tex) => fbo::RegularAttachment::Texture(tex),
227            ColorAttachment::RenderBuffer(buffer) => fbo::RegularAttachment::RenderBuffer(buffer),
228        });
229
230        let depth = depth.map(|depth| match depth {
231            DepthAttachment::Texture(tex) => fbo::RegularAttachment::Texture(tex),
232            DepthAttachment::RenderBuffer(buffer) => fbo::RegularAttachment::RenderBuffer(buffer),
233        });
234
235        let stencil = stencil.map(|stencil|  match stencil {
236            StencilAttachment::Texture(tex) => fbo::RegularAttachment::Texture(tex),
237            StencilAttachment::RenderBuffer(buffer) => fbo::RegularAttachment::RenderBuffer(buffer),
238        });
239
240        let depthstencil = depthstencil.map(|depthstencil| match depthstencil {
241            DepthStencilAttachment::Texture(tex) => fbo::RegularAttachment::Texture(tex),
242            DepthStencilAttachment::RenderBuffer(buffer) => fbo::RegularAttachment::RenderBuffer(buffer),
243        });
244
245        let attachments = fbo::FramebufferAttachments::Regular(fbo::FramebufferSpecificAttachments {
246            colors: if let Some(color) = color {
247                let mut v = SmallVec::new(); v.push((0, color)); v
248            } else {
249                SmallVec::new()
250            },
251            depth_stencil: if let (Some(depth), Some(stencil)) = (depth, stencil) {
252                fbo::DepthStencilAttachments::DepthAndStencilAttachments(depth, stencil)
253            } else if let Some(depth) = depth {
254                fbo::DepthStencilAttachments::DepthAttachment(depth)
255            } else if let Some(stencil) = stencil {
256                fbo::DepthStencilAttachments::StencilAttachment(stencil)
257            } else if let Some(depthstencil) = depthstencil {
258                fbo::DepthStencilAttachments::DepthStencilAttachment(depthstencil)
259            } else {
260                fbo::DepthStencilAttachments::None
261            }
262        });
263
264        let attachments = attachments.validate(facade)?;
265
266        Ok(SimpleFrameBuffer {
267            context: facade.get_context().clone(),
268            attachments,
269        })
270    }
271}
272
273impl<'a> Surface for SimpleFrameBuffer<'a> {
274    #[inline]
275    fn clear(&mut self, rect: Option<&Rect>, color: Option<(f32, f32, f32, f32)>, color_srgb: bool,
276             depth: Option<f32>, stencil: Option<i32>)
277    {
278        ops::clear(&self.context, Some(&self.attachments), rect, color, color_srgb, depth, stencil);
279    }
280
281    #[inline]
282    fn get_dimensions(&self) -> (u32, u32) {
283        self.attachments.get_dimensions()
284    }
285
286    #[inline]
287    fn get_depth_buffer_bits(&self) -> Option<u16> {
288        self.attachments.get_depth_buffer_bits()
289    }
290
291    #[inline]
292    fn get_stencil_buffer_bits(&self) -> Option<u16> {
293        self.attachments.get_stencil_buffer_bits()
294    }
295
296    fn draw<'b, 'v, V, I, U>(&mut self, vb: V, ib: I, program: &crate::Program,
297        uniforms: &U, draw_parameters: &crate::DrawParameters<'_>) -> Result<(), DrawError>
298        where I: Into<crate::index::IndicesSource<'b>>, U: crate::uniforms::Uniforms,
299        V: crate::vertex::MultiVerticesSource<'v>
300    {
301        if !self.has_depth_buffer() && (draw_parameters.depth.test.requires_depth_buffer() ||
302                        draw_parameters.depth.write)
303        {
304            return Err(DrawError::NoDepthBuffer);
305        }
306
307        if let Some(viewport) = draw_parameters.viewport {
308            if viewport.width > self.context.capabilities().max_viewport_dims.0
309                    as u32
310            {
311                return Err(DrawError::ViewportTooLarge);
312            }
313            if viewport.height > self.context.capabilities().max_viewport_dims.1
314                    as u32
315            {
316                return Err(DrawError::ViewportTooLarge);
317            }
318        }
319
320        ops::draw(&self.context, Some(&self.attachments), vb,
321                  ib.into(), program, uniforms, draw_parameters, self.get_dimensions())
322    }
323
324    #[inline]
325    fn blit_color<S>(&self, source_rect: &Rect, target: &S, target_rect: &BlitTarget,
326                     filter: uniforms::MagnifySamplerFilter) where S: Surface
327    {
328        target.blit_from_simple_framebuffer(self, source_rect, target_rect, filter)
329    }
330
331    #[inline]
332    fn blit_buffers_from_frame(&self, source_rect: &Rect, target_rect: &BlitTarget, filter: MagnifySamplerFilter, mask: BlitMask) {
333        ops::blit(&self.context, None, self.get_attachments(),
334                  mask.to_glenum(), source_rect, target_rect, filter.to_glenum())
335    }
336
337    #[inline]
338    fn blit_buffers_from_simple_framebuffer(&self, source: &SimpleFrameBuffer<'_>, source_rect: &Rect, target_rect: &BlitTarget, filter: MagnifySamplerFilter, mask: BlitMask) {
339        ops::blit(&self.context, source.get_attachments(), self.get_attachments(),
340                  mask.to_glenum(), source_rect, target_rect, filter.to_glenum())
341    }
342
343    #[inline]
344    fn blit_buffers_from_multioutput_framebuffer(&self, source: &MultiOutputFrameBuffer<'_>, source_rect: &Rect, target_rect: &BlitTarget, filter: MagnifySamplerFilter, mask: BlitMask) {
345        ops::blit(&self.context, source.get_attachments(), self.get_attachments(),
346                  mask.to_glenum(), source_rect, target_rect, filter.to_glenum())
347    }
348}
349
350impl<'a> FboAttachments for SimpleFrameBuffer<'a> {
351    #[inline]
352    fn get_attachments(&self) -> Option<&fbo::ValidatedAttachments<'_>> {
353        Some(&self.attachments)
354    }
355}
356
357/// A framebuffer which has multiple color attachments.
358pub struct MultiOutputFrameBuffer<'a> {
359    context: Rc<Context>,
360    example_attachments: fbo::ValidatedAttachments<'a>,
361    color_attachments: Vec<(String, fbo::RegularAttachment<'a>)>,
362    depth_stencil_attachments: fbo::DepthStencilAttachments<fbo::RegularAttachment<'a>>,
363}
364
365impl<'a> MultiOutputFrameBuffer<'a> {
366    /// Creates a new `MultiOutputFrameBuffer`.
367    ///
368    /// # Panic
369    ///
370    /// Panics if all attachments don't have the same dimensions.
371    #[inline]
372    pub fn new<F: ?Sized, I, A>(facade: &F, color_attachments: I)
373                        -> Result<MultiOutputFrameBuffer<'a>, ValidationError>
374        where F: Facade,
375              I: IntoIterator<Item = (&'a str, A)>,
376              A: ToColorAttachment<'a>,
377    {
378        MultiOutputFrameBuffer::new_impl(facade, color_attachments, None, None, None)
379    }
380
381    /// Creates a `MultiOutputFrameBuffer` with a depth buffer.
382    ///
383    /// # Panic
384    ///
385    /// Panics if all attachments don't have the same dimensions.
386    #[inline]
387    pub fn with_depth_buffer<F: ?Sized, D, I, A>(facade: &F, color_attachments: I, depth: D)
388                                         -> Result<MultiOutputFrameBuffer<'a>, ValidationError>
389        where F: Facade,
390              D: ToDepthAttachment<'a>,
391              I: IntoIterator<Item = (&'a str, A)>,
392              A: ToColorAttachment<'a>,
393    {
394        MultiOutputFrameBuffer::new_impl(facade, color_attachments,
395                                         Some(depth.to_depth_attachment()), None, None)
396    }
397
398    /// Creates a `MultiOutputFrameBuffer` with a depth buffer, and a stencil buffer.
399    ///
400    /// # Panic
401    ///
402    /// Panics if all attachments don't have the same dimensions.
403    #[inline]
404    pub fn with_depth_and_stencil_buffer<A, F: ?Sized, I, D, S>(facade: &F, color: I, depth: D, stencil: S)
405                                                        -> Result<MultiOutputFrameBuffer<'a>,
406                                                                  ValidationError>
407        where D: ToDepthAttachment<'a>,
408              I: IntoIterator<Item = (&'a str, A)>,
409              S: ToStencilAttachment<'a>,
410              A: ToColorAttachment<'a>,
411              F: Facade
412    {
413        MultiOutputFrameBuffer::new_impl(facade, color,
414                                         Some(depth.to_depth_attachment()),
415                                         Some(stencil.to_stencil_attachment()), None)
416    }
417
418    /// Creates a `MultiOutputFrameBuffer` with a stencil buffer, but no depth buffer.
419    ///
420    /// # Panic
421    ///
422    /// Panics if all attachments don't have the same dimensions.
423    #[inline]
424    pub fn with_stencil_buffer<A, F: ?Sized, I, S>(facade: &F, color: I, stencil: S)
425                                           -> Result<MultiOutputFrameBuffer<'a>, ValidationError>
426        where S: ToStencilAttachment<'a>,
427              F: Facade,
428              I: IntoIterator<Item = (&'a str, A)>,
429              A: ToColorAttachment<'a>,
430    {
431        MultiOutputFrameBuffer::new_impl(facade, color, None,
432                                         Some(stencil.to_stencil_attachment()), None)
433    }
434
435    /// Creates a `MultiOutputFrameBuffer` with a depth-stencil buffer.
436    ///
437    /// # Panic
438    ///
439    /// Panics if all attachments don't have the same dimensions.
440    #[inline]
441    pub fn with_depth_stencil_buffer<A, F: ?Sized, I, D>(facade: &F, color: I, depthstencil: D)
442                                                 -> Result<MultiOutputFrameBuffer<'a>, ValidationError>
443        where D: ToDepthStencilAttachment<'a>, F: Facade,
444              I: IntoIterator<Item = (&'a str, A)>,
445              A: ToColorAttachment<'a>,
446    {
447        MultiOutputFrameBuffer::new_impl(facade, color, None, None,
448                                    Some(depthstencil.to_depth_stencil_attachment()))
449    }
450
451    fn new_impl<F: ?Sized, I, A>(facade: &F, color: I, depth: Option<DepthAttachment<'a>>,
452                         stencil: Option<StencilAttachment<'a>>,
453                         depthstencil: Option<DepthStencilAttachment<'a>>)
454                         -> Result<MultiOutputFrameBuffer<'a>, ValidationError>
455        where F: Facade,
456              I: IntoIterator<Item = (&'a str, A)>,
457              A: ToColorAttachment<'a>,
458    {
459        let color = color.into_iter().map(|(name, tex)| {
460            let atch = tex.to_color_attachment();
461            let atch = if let ColorAttachment::Texture(t) = atch { t } else { panic!() };
462            (name.to_owned(), fbo::RegularAttachment::Texture(atch))
463        }).collect::<Vec<_>>();
464
465        let example_color = {
466            let mut v = SmallVec::new();
467            for e in color.iter().enumerate().map(|(index, &(_, tex))| { (index as u32, tex) }) {
468                v.push(e);
469            }
470            v
471        };
472
473        let depth = depth.map(|depth| match depth {
474            DepthAttachment::Texture(tex) => fbo::RegularAttachment::Texture(tex),
475            DepthAttachment::RenderBuffer(buffer) => fbo::RegularAttachment::RenderBuffer(buffer),
476        });
477
478        let stencil = stencil.map(|stencil|  match stencil {
479            StencilAttachment::Texture(tex) => fbo::RegularAttachment::Texture(tex),
480            StencilAttachment::RenderBuffer(buffer) => fbo::RegularAttachment::RenderBuffer(buffer),
481        });
482
483        let depthstencil = depthstencil.map(|depthstencil| match depthstencil {
484            DepthStencilAttachment::Texture(tex) => fbo::RegularAttachment::Texture(tex),
485            DepthStencilAttachment::RenderBuffer(buffer) => fbo::RegularAttachment::RenderBuffer(buffer),
486        });
487
488        let depth_stencil_attachments = if let (Some(depth), Some(stencil)) = (depth, stencil) {
489            fbo::DepthStencilAttachments::DepthAndStencilAttachments(depth, stencil)
490        } else if let Some(depth) = depth {
491            fbo::DepthStencilAttachments::DepthAttachment(depth)
492        } else if let Some(stencil) = stencil {
493            fbo::DepthStencilAttachments::StencilAttachment(stencil)
494        } else if let Some(depthstencil) = depthstencil {
495            fbo::DepthStencilAttachments::DepthStencilAttachment(depthstencil)
496        } else {
497            fbo::DepthStencilAttachments::None
498        };
499
500        let example_attachments = fbo::FramebufferAttachments::Regular(fbo::FramebufferSpecificAttachments {
501            colors: example_color,
502            depth_stencil: depth_stencil_attachments,
503        }).validate(facade)?;
504
505        Ok(MultiOutputFrameBuffer {
506            context: facade.get_context().clone(),
507            example_attachments,
508            color_attachments: color,
509            depth_stencil_attachments,
510        })
511    }
512
513    fn build_attachments(&self, program: &Program) -> fbo::ValidatedAttachments<'_> {
514        let mut colors = SmallVec::new();
515
516        for &(ref name, attachment) in self.color_attachments.iter() {
517            let location = match program.get_frag_data_location(&name) {
518                Some(l) => l,
519                None => panic!("The fragment output `{}` was not found in the program", name)
520            };
521
522            colors.push((location, attachment));
523        }
524
525        fbo::FramebufferAttachments::Regular(fbo::FramebufferSpecificAttachments {
526            colors,
527            depth_stencil: self.depth_stencil_attachments,
528        }).validate(&self.context).unwrap()
529    }
530}
531
532impl<'a> Surface for MultiOutputFrameBuffer<'a> {
533    #[inline]
534    fn clear(&mut self, rect: Option<&Rect>, color: Option<(f32, f32, f32, f32)>, color_srgb: bool,
535             depth: Option<f32>, stencil: Option<i32>)
536    {
537        ops::clear(&self.context, Some(&self.example_attachments), rect,
538                   color, color_srgb, depth, stencil);
539    }
540
541    #[inline]
542    fn get_dimensions(&self) -> (u32, u32) {
543        self.example_attachments.get_dimensions()
544    }
545
546    #[inline]
547    fn get_depth_buffer_bits(&self) -> Option<u16> {
548        self.example_attachments.get_depth_buffer_bits()
549    }
550
551    #[inline]
552    fn get_stencil_buffer_bits(&self) -> Option<u16> {
553        self.example_attachments.get_stencil_buffer_bits()
554    }
555
556    fn draw<'i, 'v, V, I, U>(&mut self, vb: V, ib: I, program: &crate::Program,
557        uniforms: &U, draw_parameters: &crate::DrawParameters<'_>) -> Result<(), DrawError>
558        where I: Into<crate::index::IndicesSource<'i>>,
559        U: crate::uniforms::Uniforms, V: crate::vertex::MultiVerticesSource<'v>
560    {
561        if !self.has_depth_buffer() && (draw_parameters.depth.test.requires_depth_buffer() ||
562                draw_parameters.depth.write)
563        {
564            return Err(DrawError::NoDepthBuffer);
565        }
566
567        if let Some(viewport) = draw_parameters.viewport {
568            if viewport.width > self.context.capabilities().max_viewport_dims.0
569                    as u32
570            {
571                return Err(DrawError::ViewportTooLarge);
572            }
573            if viewport.height > self.context.capabilities().max_viewport_dims.1
574                    as u32
575            {
576                return Err(DrawError::ViewportTooLarge);
577            }
578        }
579
580        ops::draw(&self.context, Some(&self.build_attachments(program)), vb,
581                  ib.into(), program, uniforms, draw_parameters, self.get_dimensions())
582    }
583
584    #[inline]
585    fn blit_color<S>(&self, source_rect: &Rect, target: &S, target_rect: &BlitTarget,
586                     filter: uniforms::MagnifySamplerFilter) where S: Surface
587    {
588        target.blit_from_multioutput_framebuffer(self, source_rect, target_rect, filter)
589    }
590
591    #[inline]
592    fn blit_buffers_from_frame(&self, source_rect: &Rect, target_rect: &BlitTarget, filter: MagnifySamplerFilter, mask: BlitMask) {
593        ops::blit(&self.context, None, self.get_attachments(),
594                  mask.to_glenum(), source_rect, target_rect, filter.to_glenum())
595    }
596
597    #[inline]
598    fn blit_buffers_from_simple_framebuffer(&self, source: &SimpleFrameBuffer<'_>, source_rect: &Rect, target_rect: &BlitTarget, filter: MagnifySamplerFilter, mask: BlitMask) {
599        ops::blit(&self.context, source.get_attachments(), self.get_attachments(),
600                  mask.to_glenum(), source_rect, target_rect, filter.to_glenum())
601    }
602
603    #[inline]
604    fn blit_buffers_from_multioutput_framebuffer(&self, source: &MultiOutputFrameBuffer<'_>, source_rect: &Rect, target_rect: &BlitTarget, filter: MagnifySamplerFilter, mask: BlitMask) {
605        ops::blit(&self.context, source.get_attachments(), self.get_attachments(),
606                  mask.to_glenum(), source_rect, target_rect, filter.to_glenum())
607    }
608}
609
610impl<'a> FboAttachments for MultiOutputFrameBuffer<'a> {
611    #[inline]
612    fn get_attachments(&self) -> Option<&fbo::ValidatedAttachments<'_>> {
613        unimplemented!();
614    }
615}
616
617/// A framebuffer with no attachment at all.
618///
619/// Note that this is only supported on recent hardware.
620pub struct EmptyFrameBuffer {
621    context: Rc<Context>,
622    attachments: fbo::ValidatedAttachments<'static>,
623}
624
625impl<'a> EmptyFrameBuffer {
626    /// Returns true if empty framebuffers are supported by the backend.
627    pub fn is_supported<C: ?Sized>(context: &C) -> bool where C: CapabilitiesSource {
628        context.get_version() >= &Version(Api::Gl, 4, 3) ||
629        context.get_version() >= &Version(Api::GlEs, 3, 1) ||
630        context.get_extensions().gl_arb_framebuffer_no_attachments
631    }
632
633    /// Returns true if layered empty framebuffers are supported by the backend.
634    pub fn is_layered_supported<C: ?Sized>(context: &C) -> bool where C: CapabilitiesSource {
635        context.get_version() >= &Version(Api::Gl, 4, 3) ||
636        context.get_version() >= &Version(Api::GlEs, 3, 2) ||
637        context.get_extensions().gl_arb_framebuffer_no_attachments
638    }
639
640    /// Returns the maximum width of empty framebuffers that the backend supports, or `None` if
641    /// empty framebuffers are not supported.
642    pub fn get_max_supported_width<C: ?Sized>(context: &C) -> Option<u32> where C: CapabilitiesSource {
643        context.get_capabilities().max_framebuffer_width.map(|v| v as u32)
644    }
645
646    /// Returns the maximum height of empty framebuffers that the backend supports, or `None` if
647    /// empty framebuffers are not supported.
648    pub fn get_max_supported_height<C: ?Sized>(context: &C) -> Option<u32> where C: CapabilitiesSource {
649        context.get_capabilities().max_framebuffer_height.map(|v| v as u32)
650    }
651
652    /// Returns the maximum number of samples of empty framebuffers that the backend supports,
653    /// or `None` if empty framebuffers are not supported.
654    pub fn get_max_supported_samples<C: ?Sized>(context: &C) -> Option<u32> where C: CapabilitiesSource {
655        context.get_capabilities().max_framebuffer_samples.map(|v| v as u32)
656    }
657
658    /// Returns the maximum number of layers of empty framebuffers that the backend supports,
659    /// or `None` if layered empty framebuffers are not supported.
660    pub fn get_max_supported_layers<C: ?Sized>(context: &C) -> Option<u32> where C: CapabilitiesSource {
661        context.get_capabilities().max_framebuffer_layers.map(|v| v as u32)
662    }
663
664    /// Creates a `EmptyFrameBuffer`.
665    ///
666    /// # Panic
667    ///
668    /// Panics if `layers` or `samples` is equal to `Some(0)`.
669    ///
670    #[inline]
671    pub fn new<F: ?Sized>(facade: &F, width: u32, height: u32, layers: Option<u32>,
672                  samples: Option<u32>, fixed_samples: bool)
673                  -> Result<EmptyFrameBuffer, ValidationError> where F: Facade
674    {
675        let context = facade.get_context();
676
677        let attachments = fbo::FramebufferAttachments::Empty {
678            width,
679            height,
680            layers,
681            samples,
682            fixed_samples,
683        };
684
685        let attachments = attachments.validate(context)?;
686
687        Ok(EmptyFrameBuffer {
688            context: context.clone(),
689            attachments,
690        })
691    }
692}
693
694impl Surface for EmptyFrameBuffer {
695    #[inline]
696    fn clear(&mut self, rect: Option<&Rect>, color: Option<(f32, f32, f32, f32)>, color_srgb: bool,
697             depth: Option<f32>, stencil: Option<i32>)
698    {
699        ops::clear(&self.context, Some(&self.attachments), rect, color, color_srgb, depth, stencil);
700    }
701
702    #[inline]
703    fn get_dimensions(&self) -> (u32, u32) {
704        self.attachments.get_dimensions()
705    }
706
707    #[inline]
708    fn get_depth_buffer_bits(&self) -> Option<u16> {
709        None
710    }
711
712    #[inline]
713    fn get_stencil_buffer_bits(&self) -> Option<u16> {
714        None
715    }
716
717    fn draw<'b, 'v, V, I, U>(&mut self, vb: V, ib: I, program: &crate::Program,
718        uniforms: &U, draw_parameters: &crate::DrawParameters<'_>) -> Result<(), DrawError>
719        where I: Into<crate::index::IndicesSource<'b>>, U: crate::uniforms::Uniforms,
720        V: crate::vertex::MultiVerticesSource<'v>
721    {
722        if !self.has_depth_buffer() && (draw_parameters.depth.test.requires_depth_buffer() ||
723                        draw_parameters.depth.write)
724        {
725            return Err(DrawError::NoDepthBuffer);
726        }
727
728        if let Some(viewport) = draw_parameters.viewport {
729            if viewport.width > self.context.capabilities().max_viewport_dims.0
730                    as u32
731            {
732                return Err(DrawError::ViewportTooLarge);
733            }
734            if viewport.height > self.context.capabilities().max_viewport_dims.1
735                    as u32
736            {
737                return Err(DrawError::ViewportTooLarge);
738            }
739        }
740
741        ops::draw(&self.context, Some(&self.attachments), vb,
742                  ib.into(), program, uniforms, draw_parameters, self.get_dimensions())
743    }
744
745    #[inline]
746    fn blit_color<S>(&self, source_rect: &Rect, target: &S, target_rect: &BlitTarget,
747                     filter: uniforms::MagnifySamplerFilter) where S: Surface
748    {
749        unimplemented!()        // TODO:
750    }
751
752    #[inline]
753    fn blit_buffers_from_frame(&self, source_rect: &Rect, target_rect: &BlitTarget,
754                       filter: uniforms::MagnifySamplerFilter, mask: BlitMask)
755    {
756        ops::blit(&self.context, None, self.get_attachments(),
757                  mask.to_glenum(), source_rect, target_rect, filter.to_glenum())
758    }
759
760    #[inline]
761    fn blit_buffers_from_simple_framebuffer(&self, source: &SimpleFrameBuffer<'_>,
762                                    source_rect: &Rect, target_rect: &BlitTarget,
763                                    filter: uniforms::MagnifySamplerFilter, mask: BlitMask)
764    {
765        ops::blit(&self.context, source.get_attachments(), self.get_attachments(),
766                  mask.to_glenum(), source_rect, target_rect, filter.to_glenum())
767    }
768
769    #[inline]
770    fn blit_buffers_from_multioutput_framebuffer(&self, source: &MultiOutputFrameBuffer<'_>,
771                                         source_rect: &Rect, target_rect: &BlitTarget,
772                                         filter: uniforms::MagnifySamplerFilter,
773                                         mask: BlitMask)
774    {
775        ops::blit(&self.context, source.get_attachments(), self.get_attachments(),
776                  mask.to_glenum(), source_rect, target_rect, filter.to_glenum())
777    }
778}
779
780impl FboAttachments for EmptyFrameBuffer {
781    #[inline]
782    fn get_attachments(&self) -> Option<&fbo::ValidatedAttachments<'_>> {
783        Some(&self.attachments)
784    }
785}
786
787/// Describes an attachment for a color buffer.
788#[derive(Copy, Clone)]
789pub enum ColorAttachment<'a> {
790    /// A texture.
791    Texture(TextureAnyImage<'a>),
792    /// A render buffer.
793    RenderBuffer(&'a RenderBuffer),
794}
795
796/// Trait for objects that can be used as color attachments.
797pub trait ToColorAttachment<'a> {
798    /// Builds the `ColorAttachment`.
799    fn to_color_attachment(self) -> ColorAttachment<'a>;
800}
801
802impl<'a> ToColorAttachment<'a> for ColorAttachment<'a> {
803    #[inline]
804    fn to_color_attachment(self) -> ColorAttachment<'a> {
805        self
806    }
807}
808
809/// Describes an attachment for a depth buffer.
810#[derive(Copy, Clone)]
811pub enum DepthAttachment<'a> {
812    /// A texture.
813    Texture(TextureAnyImage<'a>),
814    /// A render buffer.
815    RenderBuffer(&'a DepthRenderBuffer),
816}
817
818/// Trait for objects that can be used as depth attachments.
819pub trait ToDepthAttachment<'a> {
820    /// Builds the `DepthAttachment`.
821    fn to_depth_attachment(self) -> DepthAttachment<'a>;
822}
823
824impl<'a> ToDepthAttachment<'a> for DepthAttachment<'a> {
825    #[inline]
826    fn to_depth_attachment(self) -> DepthAttachment<'a> {
827        self
828    }
829}
830
831/// Describes an attachment for a stencil buffer.
832#[derive(Copy, Clone)]
833pub enum StencilAttachment<'a> {
834    /// A texture.
835    Texture(TextureAnyImage<'a>),
836    /// A render buffer.
837    RenderBuffer(&'a StencilRenderBuffer),
838}
839
840/// Trait for objects that can be used as stencil attachments.
841pub trait ToStencilAttachment<'a> {
842    /// Builds the `StencilAttachment`.
843    fn to_stencil_attachment(self) -> StencilAttachment<'a>;
844}
845
846impl<'a> ToStencilAttachment<'a> for StencilAttachment<'a> {
847    #[inline]
848    fn to_stencil_attachment(self) -> StencilAttachment<'a> {
849        self
850    }
851}
852
853/// Describes an attachment for a depth and stencil buffer.
854#[derive(Copy, Clone)]
855pub enum DepthStencilAttachment<'a> {
856    /// A texture.
857    Texture(TextureAnyImage<'a>),
858    /// A render buffer.
859    RenderBuffer(&'a DepthStencilRenderBuffer),
860}
861
862/// Trait for objects that can be used as depth and stencil attachments.
863pub trait ToDepthStencilAttachment<'a> {
864    /// Builds the `DepthStencilAttachment`.
865    fn to_depth_stencil_attachment(self) -> DepthStencilAttachment<'a>;
866}
867
868impl<'a> ToDepthStencilAttachment<'a> for DepthStencilAttachment<'a> {
869    #[inline]
870    fn to_depth_stencil_attachment(self) -> DepthStencilAttachment<'a> {
871        self
872    }
873}