vg/renderer/opengl/
framebuffer.rs1use 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_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_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 }
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}