1use std::rc::Rc;
11use std::ops::{Deref, DerefMut};
12use std::fmt;
13use std::error::Error;
14
15use crate::framebuffer::{ColorAttachment, ToColorAttachment};
16use crate::framebuffer::{DepthAttachment, ToDepthAttachment};
17use crate::framebuffer::{StencilAttachment, ToStencilAttachment};
18use crate::framebuffer::{DepthStencilAttachment, ToDepthStencilAttachment};
19use crate::texture::{UncompressedFloatFormat, DepthFormat, StencilFormat, DepthStencilFormat, TextureKind};
20
21use crate::image_format;
22
23use crate::gl;
24use crate::GlObject;
25use crate::fbo::FramebuffersContainer;
26use crate::backend::Facade;
27use crate::context::Context;
28use crate::ContextExt;
29use crate::version::Version;
30use crate::version::Api;
31
32#[derive(Copy, Clone, Debug)]
34pub enum CreationError {
35 FormatNotSupported,
37}
38
39impl fmt::Display for CreationError {
40 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
41 use self::CreationError::*;
42 let desc = match *self {
43 FormatNotSupported => "The requested format is not supported",
44 };
45 fmt.write_str(desc)
46 }
47}
48
49impl Error for CreationError {}
50
51impl From<image_format::FormatNotSupportedError> for CreationError {
52 fn from(_: image_format::FormatNotSupportedError) -> CreationError {
53 CreationError::FormatNotSupported
54 }
55}
56
57pub struct RenderBuffer {
61 buffer: RenderBufferAny,
62}
63
64impl RenderBuffer {
65 pub fn new<F: ?Sized>(facade: &F, format: UncompressedFloatFormat, width: u32, height: u32)
67 -> Result<RenderBuffer, CreationError> where F: Facade
68 {
69 let format = image_format::TextureFormatRequest::Specific(image_format::TextureFormat::UncompressedFloat(format));
70 let format = image_format::format_request_to_glenum(&facade.get_context(), format, image_format::RequestType::Renderbuffer)?;
71
72 Ok(RenderBuffer {
73 buffer: RenderBufferAny::new(facade, format, TextureKind::Float, width, height, None)
74 })
75 }
76 pub fn new_multisample<F: ?Sized>(facade: &F, format: UncompressedFloatFormat, width: u32, height: u32, samples: u32)
78 -> Result<RenderBuffer, CreationError> where F: Facade
79 {
80 let format = image_format::TextureFormatRequest::Specific(image_format::TextureFormat::UncompressedFloat(format));
81 let format = image_format::format_request_to_glenum(&facade.get_context(), format, image_format::RequestType::Renderbuffer)?;
82
83 Ok(RenderBuffer {
84 buffer: RenderBufferAny::new(facade, format, TextureKind::Float, width, height, Some(samples))
85 })
86 }
87}
88
89impl<'a> ToColorAttachment<'a> for &'a RenderBuffer {
90 #[inline]
91 fn to_color_attachment(self) -> ColorAttachment<'a> {
92 ColorAttachment::RenderBuffer(self)
93 }
94}
95
96impl Deref for RenderBuffer {
97 type Target = RenderBufferAny;
98
99 #[inline]
100 fn deref(&self) -> &RenderBufferAny {
101 &self.buffer
102 }
103}
104
105impl DerefMut for RenderBuffer {
106 #[inline]
107 fn deref_mut(&mut self) -> &mut RenderBufferAny {
108 &mut self.buffer
109 }
110}
111
112impl GlObject for RenderBuffer {
113 type Id = gl::types::GLuint;
114
115 #[inline]
116 fn get_id(&self) -> gl::types::GLuint {
117 self.buffer.get_id()
118 }
119}
120
121pub struct DepthRenderBuffer {
125 buffer: RenderBufferAny,
126}
127
128impl DepthRenderBuffer {
129 pub fn new<F: ?Sized>(facade: &F, format: DepthFormat, width: u32, height: u32)
131 -> Result<DepthRenderBuffer, CreationError> where F: Facade
132 {
133 let format = image_format::TextureFormatRequest::Specific(image_format::TextureFormat::DepthFormat(format));
134 let format = image_format::format_request_to_glenum(&facade.get_context(), format, image_format::RequestType::Renderbuffer)?;
135
136 Ok(DepthRenderBuffer {
137 buffer: RenderBufferAny::new(facade, format, TextureKind::Depth, width, height, None)
138 })
139 }
140 pub fn new_multisample<F: ?Sized>(facade: &F, format: DepthFormat, width: u32, height: u32, samples: u32)
142 -> Result<DepthRenderBuffer, CreationError> where F: Facade
143 {
144 let format = image_format::TextureFormatRequest::Specific(image_format::TextureFormat::DepthFormat(format));
145 let format = image_format::format_request_to_glenum(&facade.get_context(), format, image_format::RequestType::Renderbuffer)?;
146
147 Ok(DepthRenderBuffer {
148 buffer: RenderBufferAny::new(facade, format, TextureKind::Depth, width, height, Some(samples))
149 })
150 }
151}
152
153impl<'a> ToDepthAttachment<'a> for &'a DepthRenderBuffer {
154 fn to_depth_attachment(self) -> DepthAttachment<'a> {
155 DepthAttachment::RenderBuffer(self)
156 }
157}
158
159impl Deref for DepthRenderBuffer {
160 type Target = RenderBufferAny;
161
162 #[inline]
163 fn deref(&self) -> &RenderBufferAny {
164 &self.buffer
165 }
166}
167
168impl DerefMut for DepthRenderBuffer {
169 #[inline]
170 fn deref_mut(&mut self) -> &mut RenderBufferAny {
171 &mut self.buffer
172 }
173}
174
175impl GlObject for DepthRenderBuffer {
176 type Id = gl::types::GLuint;
177
178 #[inline]
179 fn get_id(&self) -> gl::types::GLuint {
180 self.buffer.get_id()
181 }
182}
183
184pub struct StencilRenderBuffer {
188 buffer: RenderBufferAny,
189}
190
191impl StencilRenderBuffer {
192 pub fn new<F: ?Sized>(facade: &F, format: StencilFormat, width: u32, height: u32)
194 -> Result<StencilRenderBuffer, CreationError> where F: Facade
195 {
196 let format = image_format::TextureFormatRequest::Specific(image_format::TextureFormat::StencilFormat(format));
197 let format = image_format::format_request_to_glenum(&facade.get_context(), format, image_format::RequestType::Renderbuffer)?;
198
199 Ok(StencilRenderBuffer {
200 buffer: RenderBufferAny::new(facade, format, TextureKind::Stencil, width, height, None)
201 })
202 }
203 pub fn new_multisample<F: ?Sized>(facade: &F, format: StencilFormat, width: u32, height: u32, samples: u32)
205 -> Result<StencilRenderBuffer, CreationError> where F: Facade
206 {
207 let format = image_format::TextureFormatRequest::Specific(image_format::TextureFormat::StencilFormat(format));
208 let format = image_format::format_request_to_glenum(&facade.get_context(), format, image_format::RequestType::Renderbuffer)?;
209
210 Ok(StencilRenderBuffer {
211 buffer: RenderBufferAny::new(facade, format, TextureKind::Stencil, width, height, Some(samples))
212 })
213 }
214}
215
216impl<'a> ToStencilAttachment<'a> for &'a StencilRenderBuffer {
217 #[inline]
218 fn to_stencil_attachment(self) -> StencilAttachment<'a> {
219 StencilAttachment::RenderBuffer(self)
220 }
221}
222
223impl Deref for StencilRenderBuffer {
224 type Target = RenderBufferAny;
225
226 #[inline]
227 fn deref(&self) -> &RenderBufferAny {
228 &self.buffer
229 }
230}
231
232impl DerefMut for StencilRenderBuffer {
233 #[inline]
234 fn deref_mut(&mut self) -> &mut RenderBufferAny {
235 &mut self.buffer
236 }
237}
238
239impl GlObject for StencilRenderBuffer {
240 type Id = gl::types::GLuint;
241
242 #[inline]
243 fn get_id(&self) -> gl::types::GLuint {
244 self.buffer.get_id()
245 }
246}
247
248pub struct DepthStencilRenderBuffer {
252 buffer: RenderBufferAny,
253}
254
255impl DepthStencilRenderBuffer {
256 pub fn new<F: ?Sized>(facade: &F, format: DepthStencilFormat, width: u32, height: u32)
258 -> Result<DepthStencilRenderBuffer, CreationError> where F: Facade
259 {
260 let format = image_format::TextureFormatRequest::Specific(image_format::TextureFormat::DepthStencilFormat(format));
261 let format = image_format::format_request_to_glenum(&facade.get_context(), format, image_format::RequestType::Renderbuffer)?;
262
263 Ok(DepthStencilRenderBuffer {
264 buffer: RenderBufferAny::new(facade, format, TextureKind::DepthStencil, width, height, None)
265 })
266 }
267 pub fn new_multisample<F: ?Sized>(facade: &F, format: DepthStencilFormat, width: u32, height: u32, samples: u32)
269 -> Result<DepthStencilRenderBuffer, CreationError> where F: Facade
270 {
271 let format = image_format::TextureFormatRequest::Specific(image_format::TextureFormat::DepthStencilFormat(format));
272 let format = image_format::format_request_to_glenum(&facade.get_context(), format, image_format::RequestType::Renderbuffer)?;
273
274 Ok(DepthStencilRenderBuffer {
275 buffer: RenderBufferAny::new(facade, format, TextureKind::DepthStencil, width, height, Some(samples))
276 })
277 }
278}
279
280impl<'a> ToDepthStencilAttachment<'a> for &'a DepthStencilRenderBuffer {
281 #[inline]
282 fn to_depth_stencil_attachment(self) -> DepthStencilAttachment<'a> {
283 DepthStencilAttachment::RenderBuffer(self)
284 }
285}
286
287impl Deref for DepthStencilRenderBuffer {
288 type Target = RenderBufferAny;
289
290 #[inline]
291 fn deref(&self) -> &RenderBufferAny {
292 &self.buffer
293 }
294}
295
296impl DerefMut for DepthStencilRenderBuffer {
297 #[inline]
298 fn deref_mut(&mut self) -> &mut RenderBufferAny {
299 &mut self.buffer
300 }
301}
302
303impl GlObject for DepthStencilRenderBuffer {
304 type Id = gl::types::GLuint;
305
306 #[inline]
307 fn get_id(&self) -> gl::types::GLuint {
308 self.buffer.get_id()
309 }
310}
311
312pub struct RenderBufferAny {
314 context: Rc<Context>,
315 id: gl::types::GLuint,
316 width: u32,
317 height: u32,
318 samples: Option<u32>,
319 kind: TextureKind,
320}
321
322impl RenderBufferAny {
323 fn new<F: ?Sized>(facade: &F, format: gl::types::GLenum, kind: TextureKind, width: u32, height: u32,
325 samples: Option<u32>) -> RenderBufferAny
326 where F: Facade
327 {
328 unsafe {
329 let mut ctxt = facade.get_context().make_current();
332 let mut id = 0;
333
334 if ctxt.version >= &Version(Api::Gl, 4, 5) ||
335 ctxt.extensions.gl_arb_direct_state_access
336 {
337 ctxt.gl.CreateRenderbuffers(1, &mut id);
338 if let Some(samples) = samples {
339 ctxt.gl.NamedRenderbufferStorageMultisample(id, samples as gl::types::GLsizei,
340 format, width as gl::types::GLsizei,
341 height as gl::types::GLsizei);
342 } else {
343 ctxt.gl.NamedRenderbufferStorage(id, format, width as gl::types::GLsizei,
344 height as gl::types::GLsizei);
345 }
346
347 } else if samples.is_some() && (ctxt.version >= &Version(Api::Gl, 3, 0) ||
348 ctxt.version >= &Version(Api::GlEs, 3, 0) ||
349 ctxt.extensions.gl_apple_framebuffer_multisample ||
350 ctxt.extensions.gl_angle_framebuffer_multisample ||
351 ctxt.extensions.gl_ext_multisampled_render_to_texture ||
352 ctxt.extensions.gl_nv_framebuffer_multisample)
353 {
354 ctxt.gl.GenRenderbuffers(1, &mut id);
355 ctxt.gl.BindRenderbuffer(gl::RENDERBUFFER, id);
356 ctxt.state.renderbuffer = id;
357
358 let samples = samples.unwrap();
359
360 if ctxt.version >= &Version(Api::Gl, 3, 0) ||
361 ctxt.version >= &Version(Api::GlEs, 3, 0)
362 {
363 ctxt.gl.RenderbufferStorageMultisample(gl::RENDERBUFFER,
364 samples as gl::types::GLsizei,
365 format,
366 width as gl::types::GLsizei,
367 height as gl::types::GLsizei);
368
369 } else if ctxt.extensions.gl_apple_framebuffer_multisample {
370 ctxt.gl.RenderbufferStorageMultisampleAPPLE(gl::RENDERBUFFER,
371 samples as gl::types::GLsizei,
372 format,
373 width as gl::types::GLsizei,
374 height as gl::types::GLsizei);
375
376 } else if ctxt.extensions.gl_angle_framebuffer_multisample {
377 ctxt.gl.RenderbufferStorageMultisampleANGLE(gl::RENDERBUFFER,
378 samples as gl::types::GLsizei,
379 format,
380 width as gl::types::GLsizei,
381 height as gl::types::GLsizei);
382
383 } else if ctxt.extensions.gl_ext_multisampled_render_to_texture {
384 ctxt.gl.RenderbufferStorageMultisampleEXT(gl::RENDERBUFFER,
385 samples as gl::types::GLsizei,
386 format,
387 width as gl::types::GLsizei,
388 height as gl::types::GLsizei);
389
390 } else if ctxt.extensions.gl_nv_framebuffer_multisample {
391 ctxt.gl.RenderbufferStorageMultisampleNV(gl::RENDERBUFFER,
392 samples as gl::types::GLsizei,
393 format,
394 width as gl::types::GLsizei,
395 height as gl::types::GLsizei);
396
397 } else {
398 unreachable!();
399 }
400
401 } else if samples.is_none() && (ctxt.version >= &Version(Api::Gl, 3, 0) ||
402 ctxt.version >= &Version(Api::GlEs, 2, 0))
403 {
404 ctxt.gl.GenRenderbuffers(1, &mut id);
405 ctxt.gl.BindRenderbuffer(gl::RENDERBUFFER, id);
406 ctxt.state.renderbuffer = id;
407 ctxt.gl.RenderbufferStorage(gl::RENDERBUFFER, format,
408 width as gl::types::GLsizei,
409 height as gl::types::GLsizei);
410
411 } else if samples.is_some() && ctxt.extensions.gl_ext_framebuffer_object &&
412 ctxt.extensions.gl_ext_framebuffer_multisample
413 {
414 ctxt.gl.GenRenderbuffersEXT(1, &mut id);
415 ctxt.gl.BindRenderbufferEXT(gl::RENDERBUFFER_EXT, id);
416 ctxt.state.renderbuffer = id;
417
418 let samples = samples.unwrap();
419 ctxt.gl.RenderbufferStorageMultisampleEXT(gl::RENDERBUFFER_EXT,
420 samples as gl::types::GLsizei,
421 format,
422 width as gl::types::GLsizei,
423 height as gl::types::GLsizei);
424
425 } else if samples.is_none() && ctxt.extensions.gl_ext_framebuffer_object {
426 ctxt.gl.GenRenderbuffersEXT(1, &mut id);
427 ctxt.gl.BindRenderbufferEXT(gl::RENDERBUFFER_EXT, id);
428 ctxt.state.renderbuffer = id;
429 ctxt.gl.RenderbufferStorageEXT(gl::RENDERBUFFER_EXT, format,
430 width as gl::types::GLsizei,
431 height as gl::types::GLsizei);
432
433 } else {
434 unreachable!();
435 }
436
437 RenderBufferAny {
438 context: facade.get_context().clone(),
439 id,
440 width,
441 height,
442 samples,
443 kind,
444 }
445 }
446 }
447
448 #[inline]
450 pub fn get_dimensions(&self) -> (u32, u32) {
451 (self.width, self.height)
452 }
453
454 #[inline]
457 pub fn get_samples(&self) -> Option<u32> {
458 self.samples
459 }
460
461 #[inline]
463 pub fn get_context(&self) -> &Rc<Context> {
464 &self.context
465 }
466
467 #[inline]
469 pub fn kind(&self) -> TextureKind {
470 self.kind
471 }
472
473 pub fn get_depth_stencil_bits(&self) -> (u16, u16) {
475 unsafe {
476 let ctxt = self.context.make_current();
477 let mut depth_bits: gl::types::GLint = 0;
478 let mut stencil_bits: gl::types::GLint = 0;
479 ctxt.gl.BindRenderbuffer(gl::RENDERBUFFER, self.id);
480 ctxt.gl.GetRenderbufferParameteriv(gl::RENDERBUFFER, gl::RENDERBUFFER_DEPTH_SIZE, &mut depth_bits);
482 ctxt.gl.GetRenderbufferParameteriv(gl::RENDERBUFFER, gl::RENDERBUFFER_STENCIL_SIZE, &mut stencil_bits);
483 ctxt.gl.BindRenderbuffer(gl::RENDERBUFFER, 0);
484 (depth_bits as u16, stencil_bits as u16)
485 }
486 }
487}
488
489impl Drop for RenderBufferAny {
490 fn drop(&mut self) {
491 unsafe {
492 let mut ctxt = self.context.make_current();
493
494 FramebuffersContainer::purge_renderbuffer(&mut ctxt, self.id);
496
497 if ctxt.version >= &Version(Api::Gl, 3, 0) ||
498 ctxt.version >= &Version(Api::GlEs, 2, 0)
499 {
500 if ctxt.state.renderbuffer == self.id {
501 ctxt.state.renderbuffer = 0;
502 }
503
504 ctxt.gl.DeleteRenderbuffers(1, [ self.id ].as_ptr());
505
506 } else if ctxt.extensions.gl_ext_framebuffer_object {
507 if ctxt.state.renderbuffer == self.id {
508 ctxt.state.renderbuffer = 0;
509 }
510
511 ctxt.gl.DeleteRenderbuffersEXT(1, [ self.id ].as_ptr());
512
513 } else {
514 unreachable!();
515 }
516 }
517 }
518}
519
520impl GlObject for RenderBufferAny {
521 type Id = gl::types::GLuint;
522
523 #[inline]
524 fn get_id(&self) -> gl::types::GLuint {
525 self.id
526 }
527}