vg/renderer/opengl/
framebuffer.rs

1use std::rc::Rc;
2
3use super::GlTexture;
4
5use glow::HasContext;
6
7use crate::ErrorKind;
8
9pub struct Framebuffer {
10    context: Rc<glow::Context>,
11    fbo: <glow::Context as glow::HasContext>::Framebuffer,
12    stencil_rbo: Option<<glow::Context as glow::HasContext>::Renderbuffer>,
13}
14
15impl Framebuffer {
16    pub fn from_external(context: &Rc<glow::Context>, fbo: <glow::Context as glow::HasContext>::Framebuffer) -> Self {
17        Framebuffer {
18            context: context.clone(),
19            fbo,
20            stencil_rbo: None,
21        }
22    }
23    pub fn new(context: &Rc<glow::Context>, texture: &GlTexture) -> Result<Self, ErrorKind> {
24        let fbo = unsafe { context.create_framebuffer().unwrap() };
25        unsafe {
26            context.bind_framebuffer(glow::FRAMEBUFFER, Some(fbo));
27        }
28
29        let width = texture.info().width() as u32;
30        let height = texture.info().height() as u32;
31
32        unsafe {
33            context.framebuffer_texture_2d(
34                glow::FRAMEBUFFER,
35                glow::COLOR_ATTACHMENT0,
36                glow::TEXTURE_2D,
37                Some(texture.id()),
38                0,
39            );
40        };
41
42        let stencil_rbo = unsafe { context.create_renderbuffer().unwrap() };
43        unsafe {
44            context.bind_renderbuffer(glow::RENDERBUFFER, Some(stencil_rbo));
45            context.renderbuffer_storage(glow::RENDERBUFFER, glow::STENCIL_INDEX8, width as i32, height as i32);
46            context.bind_renderbuffer(glow::RENDERBUFFER, None);
47
48            context.framebuffer_renderbuffer(
49                glow::FRAMEBUFFER,
50                glow::STENCIL_ATTACHMENT,
51                glow::RENDERBUFFER,
52                Some(stencil_rbo),
53            );
54
55            let status = context.check_framebuffer_status(glow::FRAMEBUFFER);
56
57            if status != glow::FRAMEBUFFER_COMPLETE {
58                let reason = match status {
59                    glow::FRAMEBUFFER_INCOMPLETE_ATTACHMENT => {
60                        format!("({}) Framebuffer incomplete attachment", status)
61                    }
62                    //glow::FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER => format!("({}) Framebuffer incomplete draw buffer", status),
63                    //glow::FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS => format!("({}) Framebuffer incomplete layer targets", status),
64                    //FIXME: will be in next glow release: glow::FRAMEBUFFER_INCOMPLETE_DIMENSIONS => format!("({}) Framebuffer incomplete dimensions", status),
65                    glow::FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT => {
66                        format!("({}) Framebuffer incomplete missing attachment", status)
67                    }
68                    glow::FRAMEBUFFER_INCOMPLETE_MULTISAMPLE => {
69                        format!("({}) Framebuffer incomplete multisample", status)
70                    }
71                    //glow::FRAMEBUFFER_INCOMPLETE_READ_BUFFER => format!("({}) Framebuffer incomplete read buffer", status),
72                    glow::FRAMEBUFFER_UNSUPPORTED => format!("({}) Framebuffer unsupported", status),
73                    _ => format!("({}) Framebuffer not complete!", status),
74                };
75
76                return Err(ErrorKind::RenderTargetError(reason));
77            }
78
79            context.bind_framebuffer(glow::FRAMEBUFFER, None);
80        }
81
82        Ok(Framebuffer {
83            context: context.clone(),
84            fbo,
85            stencil_rbo: Some(stencil_rbo),
86        })
87    }
88
89    pub fn bind(&self) {
90        unsafe {
91            self.context.bind_framebuffer(glow::FRAMEBUFFER, Some(self.fbo));
92        }
93    }
94
95    pub fn unbind(context: &Rc<glow::Context>) {
96        unsafe {
97            context.bind_framebuffer(glow::FRAMEBUFFER, None);
98        }
99    }
100
101    // pub fn blit_to_texture(&self, texture: &GlTexture) {
102    //     let dest_fbo = Self::new(texture);
103
104    //     unsafe {
105    //         glow::BindFramebuffer(glow::READ_FRAMEBUFFER, self.fbo);
106    //         glow::BindFramebuffer(glow::DRAW_FRAMEBUFFER, dest_fbo.fbo);
107
108    //         glow::BlitFramebuffer(
109    //             0,
110    //             0,
111    //             self.width as i32,
112    //             self.height as i32,
113    //             0,
114    //             0,
115    //             dest_fbo.width as i32,
116    //             dest_fbo.height as i32,
117    //             glow::COLOR_BUFFER_BIT,
118    //             glow::NEAREST
119    //         );
120
121    //         glow::BindFramebuffer(glow::READ_FRAMEBUFFER, 0);
122    //         glow::BindFramebuffer(glow::DRAW_FRAMEBUFFER, 0);
123    //     }
124    // }
125}
126
127impl Drop for Framebuffer {
128    fn drop(&mut self) {
129        unsafe {
130            self.context.delete_framebuffer(self.fbo);
131            if let Some(stencil_rbo) = self.stencil_rbo {
132                self.context.delete_renderbuffer(stencil_rbo);
133            }
134        }
135    }
136}