Skip to main content

surfman/
renderbuffers.rs

1//! A utility module for backends that wrap surfaces in OpenGL FBOs.
2
3use crate::context::{ContextAttributeFlags, ContextAttributes};
4use crate::gl;
5use crate::Gl;
6use std::thread;
7
8use euclid::default::Size2D;
9use gl::Renderbuffer;
10use glow::HasContext;
11
12pub(crate) enum Renderbuffers {
13    IndividualDepthStencil {
14        depth: Option<Renderbuffer>,
15        stencil: Option<Renderbuffer>,
16    },
17    CombinedDepthStencil(Option<Renderbuffer>),
18}
19
20impl Drop for Renderbuffers {
21    fn drop(&mut self) {
22        match *self {
23            Renderbuffers::IndividualDepthStencil {
24                depth: None,
25                stencil: None,
26            }
27            | Renderbuffers::CombinedDepthStencil(None) => {}
28            _ => {
29                if !thread::panicking() {
30                    panic!("Should have destroyed the FBO renderbuffers with `destroy()`!")
31                }
32            }
33        }
34    }
35}
36
37impl Renderbuffers {
38    pub(crate) fn new(
39        gl: &Gl,
40        size: &Size2D<i32>,
41        attributes: &ContextAttributes,
42    ) -> Renderbuffers {
43        unsafe {
44            if attributes
45                .flags
46                .contains(ContextAttributeFlags::DEPTH | ContextAttributeFlags::STENCIL)
47            {
48                let renderbuffer = gl.create_renderbuffer().unwrap();
49                gl.bind_renderbuffer(gl::RENDERBUFFER, Some(renderbuffer));
50                gl.renderbuffer_storage(
51                    gl::RENDERBUFFER,
52                    gl::DEPTH24_STENCIL8,
53                    size.width,
54                    size.height,
55                );
56                gl.bind_renderbuffer(gl::RENDERBUFFER, None);
57                return Renderbuffers::CombinedDepthStencil(Some(renderbuffer));
58            }
59
60            let (mut depth_renderbuffer, mut stencil_renderbuffer) = (None, None);
61            if attributes.flags.contains(ContextAttributeFlags::DEPTH) {
62                depth_renderbuffer = Some(gl.create_renderbuffer().unwrap());
63                gl.bind_renderbuffer(gl::RENDERBUFFER, depth_renderbuffer);
64                gl.renderbuffer_storage(
65                    gl::RENDERBUFFER,
66                    gl::DEPTH_COMPONENT24,
67                    size.width,
68                    size.height,
69                );
70            }
71            if attributes.flags.contains(ContextAttributeFlags::STENCIL) {
72                stencil_renderbuffer = Some(gl.create_renderbuffer().unwrap());
73                gl.bind_renderbuffer(gl::RENDERBUFFER, stencil_renderbuffer);
74                gl.renderbuffer_storage(
75                    gl::RENDERBUFFER,
76                    gl::STENCIL_INDEX8,
77                    size.width,
78                    size.height,
79                );
80            }
81            gl.bind_renderbuffer(gl::RENDERBUFFER, None);
82
83            Renderbuffers::IndividualDepthStencil {
84                depth: depth_renderbuffer,
85                stencil: stencil_renderbuffer,
86            }
87        }
88    }
89
90    pub(crate) fn bind_to_current_framebuffer(&self, gl: &Gl) {
91        unsafe {
92            match *self {
93                Renderbuffers::CombinedDepthStencil(renderbuffer) => {
94                    if renderbuffer.is_some() {
95                        gl.framebuffer_renderbuffer(
96                            gl::FRAMEBUFFER,
97                            gl::DEPTH_STENCIL_ATTACHMENT,
98                            gl::RENDERBUFFER,
99                            renderbuffer,
100                        );
101                    }
102                }
103                Renderbuffers::IndividualDepthStencil {
104                    depth: depth_renderbuffer,
105                    stencil: stencil_renderbuffer,
106                } => {
107                    if depth_renderbuffer.is_some() {
108                        gl.framebuffer_renderbuffer(
109                            gl::FRAMEBUFFER,
110                            gl::DEPTH_ATTACHMENT,
111                            gl::RENDERBUFFER,
112                            depth_renderbuffer,
113                        );
114                    }
115                    if stencil_renderbuffer.is_some() {
116                        gl.framebuffer_renderbuffer(
117                            gl::FRAMEBUFFER,
118                            gl::STENCIL_ATTACHMENT,
119                            gl::RENDERBUFFER,
120                            stencil_renderbuffer,
121                        );
122                    }
123                }
124            }
125        }
126    }
127
128    pub(crate) fn destroy(&mut self, gl: &Gl) {
129        unsafe {
130            gl.bind_renderbuffer(gl::RENDERBUFFER, None);
131
132            match *self {
133                Renderbuffers::CombinedDepthStencil(ref mut renderbuffer) => {
134                    if let Some(renderbuffer) = renderbuffer.take() {
135                        gl.delete_renderbuffer(renderbuffer);
136                    }
137                }
138                Renderbuffers::IndividualDepthStencil {
139                    depth: ref mut depth_renderbuffer,
140                    stencil: ref mut stencil_renderbuffer,
141                } => {
142                    if let Some(stencil_renderbuffer) = stencil_renderbuffer.take() {
143                        gl.delete_renderbuffer(stencil_renderbuffer);
144                    }
145                    if let Some(depth_renderbuffer) = depth_renderbuffer.take() {
146                        gl.delete_renderbuffer(depth_renderbuffer);
147                    }
148                }
149            }
150        }
151    }
152}