grr/
framebuffer.rs

1//! Framebuffers
2
3use crate::__gl;
4use crate::__gl::types::{GLenum, GLuint};
5
6use crate::debug::{Object, ObjectType};
7use crate::device::Device;
8use crate::error::Result;
9use crate::{Format, ImageView, Region};
10
11/// Attachment clearing description.
12pub enum ClearAttachment {
13    ColorInt(usize, [i32; 4]),
14    ColorUint(usize, [u32; 4]),
15    ColorFloat(usize, [f32; 4]),
16    Depth(f32),
17    Stencil(i32),
18    DepthStencil(f32, i32),
19}
20
21/// Attachment reference.
22#[derive(Copy, Clone, Debug)]
23pub enum Attachment {
24    Color(usize),
25    Depth,
26    Stencil,
27    DepthStencil,
28}
29
30impl Attachment {
31    fn target(&self) -> GLenum {
32        match *self {
33            Attachment::Color(slot) => __gl::COLOR_ATTACHMENT0 + slot as u32,
34            Attachment::Depth => __gl::DEPTH_ATTACHMENT,
35            Attachment::Stencil => __gl::STENCIL_ATTACHMENT,
36            Attachment::DepthStencil => __gl::DEPTH_STENCIL_ATTACHMENT,
37        }
38    }
39}
40
41///
42pub enum AttachmentView {
43    Image(ImageView),
44    Renderbuffer(Renderbuffer),
45}
46
47/// Framebuffer handle.
48#[repr(transparent)]
49#[derive(Clone, Copy)]
50pub struct Framebuffer(pub(crate) GLuint);
51
52impl Framebuffer {
53    /// Default framebuffer handle.
54    ///
55    /// Thie is the base framebuffer associated with the context.
56    /// It also represents the internal swapchain for presentation.
57    pub const DEFAULT: Self = Framebuffer(0);
58}
59
60impl Object for Framebuffer {
61    const TYPE: ObjectType = ObjectType::Framebuffer;
62    fn handle(&self) -> GLuint {
63        self.0
64    }
65}
66
67/// Renderbuffer handle.
68#[repr(transparent)]
69#[derive(Clone, Copy)]
70pub struct Renderbuffer(GLuint);
71
72impl Object for Renderbuffer {
73    const TYPE: ObjectType = ObjectType::Renderbuffer;
74    fn handle(&self) -> GLuint {
75        self.0
76    }
77}
78
79impl Device {
80    /// Create a new framebuffer.
81    pub unsafe fn create_framebuffer(&self) -> Result<Framebuffer> {
82        let mut framebuffer = 0;
83        self.0.CreateFramebuffers(1, &mut framebuffer);
84        self.get_error()?;
85
86        Ok(Framebuffer(framebuffer))
87    }
88
89    /// Delete a framebuffer.
90    pub unsafe fn delete_framebuffer(&self, framebuffer: Framebuffer) {
91        self.delete_framebuffers(&[framebuffer])
92    }
93
94    /// Delete multiple framebuffers.
95    pub unsafe fn delete_framebuffers(&self, framebuffers: &[Framebuffer]) {
96        self.0.DeleteFramebuffers(
97            framebuffers.len() as _,
98            framebuffers.as_ptr() as *const _, // newtype
99        );
100    }
101
102    /// Create a new framebuffer.
103    pub unsafe fn create_renderbuffer(
104        &self,
105        format: Format,
106        width: u32,
107        height: u32,
108        samples: u32,
109    ) -> Result<Renderbuffer> {
110        let mut renderbuffer = 0;
111        self.0.CreateRenderbuffers(1, &mut renderbuffer);
112        self.get_error()?;
113
114        if samples > 1 {
115            self.0.NamedRenderbufferStorageMultisample(
116                renderbuffer,
117                samples as _,
118                format as _,
119                width as _,
120                height as _,
121            );
122        } else {
123            self.0
124                .NamedRenderbufferStorage(renderbuffer, format as _, width as _, height as _);
125        }
126
127        Ok(Renderbuffer(renderbuffer))
128    }
129
130    /// Delete a renderbuffer.
131    pub unsafe fn delete_renderbuffer(&self, renderbuffer: Renderbuffer) {
132        self.delete_renderbuffers(&[renderbuffer])
133    }
134
135    /// Delete multiple renderbuffers.
136    pub unsafe fn delete_renderbuffers(&self, renderbuffers: &[Renderbuffer]) {
137        self.0.DeleteRenderbuffers(
138            renderbuffers.len() as _,
139            renderbuffers.as_ptr() as *const _, // newtype
140        );
141    }
142
143    /// Clear framebuffer attachment.
144    pub unsafe fn clear_attachment(&self, fb: Framebuffer, cv: ClearAttachment) {
145        match cv {
146            ClearAttachment::ColorInt(id, color) => {
147                self.0
148                    .ClearNamedFramebufferiv(fb.0, __gl::COLOR, id as _, color.as_ptr());
149            }
150            ClearAttachment::ColorUint(id, color) => {
151                self.0
152                    .ClearNamedFramebufferuiv(fb.0, __gl::COLOR, id as _, color.as_ptr());
153            }
154            ClearAttachment::ColorFloat(id, color) => {
155                self.0
156                    .ClearNamedFramebufferfv(fb.0, __gl::COLOR, id as _, color.as_ptr());
157            }
158            ClearAttachment::Depth(depth) => {
159                self.0
160                    .ClearNamedFramebufferfv(fb.0, __gl::DEPTH, 0, &depth as *const _);
161            }
162            ClearAttachment::Stencil(stencil) => {
163                self.0
164                    .ClearNamedFramebufferiv(fb.0, __gl::STENCIL, 0, &stencil as *const _);
165            }
166            ClearAttachment::DepthStencil(depth, stencil) => {
167                self.0
168                    .ClearNamedFramebufferfi(fb.0, __gl::DEPTH_STENCIL, 0, depth, stencil);
169            }
170        }
171    }
172
173    ///
174    pub unsafe fn invalidate_attachments(
175        &self,
176        framebuffer: Framebuffer,
177        attachments: &[Attachment],
178        region: Region,
179    ) {
180        let attachments = attachments
181            .iter()
182            .map(|att| att.target())
183            .collect::<Vec<_>>();
184
185        self.0.InvalidateNamedFramebufferSubData(
186            framebuffer.0,
187            attachments.len() as _,
188            attachments.as_ptr(),
189            region.x,
190            region.y,
191            region.w,
192            region.h,
193        )
194    }
195
196    /// Bind a framebuffer for draw and read commands.
197    ///
198    /// This will overwrite both (draw and read) binding points.
199    pub unsafe fn bind_framebuffer(&self, framebuffer: Framebuffer) {
200        self.0.BindFramebuffer(__gl::FRAMEBUFFER, framebuffer.0);
201    }
202
203    /// Bind a framebuffer for draw commands.
204    pub unsafe fn bind_draw_framebuffer(&self, framebuffer: Framebuffer) {
205        self.0
206            .BindFramebuffer(__gl::DRAW_FRAMEBUFFER, framebuffer.0);
207    }
208
209    /// Bind a framebuffer for read commands.
210    pub unsafe fn bind_read_framebuffer(&self, framebuffer: Framebuffer) {
211        self.0
212            .BindFramebuffer(__gl::READ_FRAMEBUFFER, framebuffer.0);
213    }
214
215    /// Bind attachments to the framebuffer.
216    ///
217    /// All previously bound attachments become invalid.
218    pub unsafe fn bind_attachments(
219        &self,
220        framebuffer: Framebuffer,
221        attachments: &[(Attachment, AttachmentView)],
222    ) {
223        assert_ne!(
224            framebuffer.0, 0,
225            "The default framebuffer can't be changed."
226        );
227
228        for (attachment, view) in attachments {
229            let target = attachment.target();
230            match *view {
231                AttachmentView::Image(image) => {
232                    self.0
233                        .NamedFramebufferTexture(framebuffer.0, target, image.0, 0);
234                }
235                AttachmentView::Renderbuffer(renderbuffer) => {
236                    self.0.NamedFramebufferRenderbuffer(
237                        framebuffer.0,
238                        target,
239                        __gl::RENDERBUFFER,
240                        renderbuffer.0,
241                    );
242                }
243            }
244        }
245    }
246
247    /// Specify color attachments.
248    ///
249    /// Defines the color render targets for the next draw calls.
250    /// This builds the link between fragment outputs in the fragment shader
251    /// and attachments bound on the framebuffer.
252    pub unsafe fn set_color_attachments(&self, framebuffer: Framebuffer, attachments: &[u32]) {
253        assert_ne!(
254            framebuffer.0, 0,
255            "The default framebuffer can't be changed."
256        );
257
258        let attachments = attachments
259            .iter()
260            .map(|i| i + __gl::COLOR_ATTACHMENT0)
261            .collect::<Vec<_>>();
262        self.0.NamedFramebufferDrawBuffers(
263            framebuffer.0,
264            attachments.len() as _,
265            attachments.as_ptr(),
266        );
267    }
268
269    /// Specify read attachment.
270    pub unsafe fn set_read_attachment(&self, framebuffer: Framebuffer, attachment: u32) {
271        assert_ne!(
272            framebuffer.0, 0,
273            "The default framebuffer can't be changed."
274        );
275
276        self.0
277            .NamedFramebufferReadBuffer(framebuffer.0, __gl::COLOR_ATTACHMENT0 + attachment);
278    }
279}