surfman/
renderbuffers.rs

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