librashader/librashader-runtime-gl/src/gl/gl46/framebuffer.rs

251 lines
7.3 KiB
Rust
Raw Normal View History

2022-11-29 23:56:10 -05:00
use gl::types::{GLenum, GLint, GLsizei, GLuint};
use librashader_common::{FilterMode, ImageFormat, Size, WrapMode};
use librashader_presets::Scale2D;
2022-11-30 00:39:42 -05:00
use crate::framebuffer::{GLImage, Viewport};
2022-11-29 23:56:10 -05:00
use crate::error::{FilterChainError, Result};
use crate::gl::Framebuffer;
use crate::texture::Texture;
#[derive(Debug)]
pub struct Gl46Framebuffer {
2022-11-30 00:39:42 -05:00
image: GLuint,
handle: GLuint,
size: Size<u32>,
format: GLenum,
max_levels: u32,
levels: u32,
2022-11-29 23:56:10 -05:00
is_raw: bool,
}
impl Framebuffer for Gl46Framebuffer {
2022-11-30 00:39:42 -05:00
fn handle(&self) -> GLuint {
self.handle
}
fn size(&self) -> Size<u32> {
self.size
}
fn image(&self) -> GLuint {
self.image
}
fn format(&self) -> GLenum {
self.format
}
2022-11-29 23:56:10 -05:00
fn new(max_levels: u32) -> Gl46Framebuffer {
let mut framebuffer = 0;
unsafe {
2022-11-30 00:39:42 -05:00
gl::CreateFramebuffers(1, &mut framebuffer);
2022-11-29 23:56:10 -05:00
}
Gl46Framebuffer {
image: 0,
size: Size {
width: 1,
height: 1,
},
format: 0,
max_levels,
2022-11-30 00:39:42 -05:00
levels: 0,
2022-11-29 23:56:10 -05:00
handle: framebuffer,
is_raw: false,
}
}
fn new_from_raw(
texture: GLuint,
handle: GLuint,
format: GLenum,
size: Size<u32>,
miplevels: u32,
) -> Gl46Framebuffer {
Gl46Framebuffer {
image: texture,
size,
format,
max_levels: miplevels,
2022-11-30 00:39:42 -05:00
levels: miplevels,
2022-11-29 23:56:10 -05:00
handle,
is_raw: true,
}
}
fn as_texture(&self, filter: FilterMode, wrap_mode: WrapMode) -> Texture {
Texture {
2022-11-30 00:39:42 -05:00
image: GLImage {
2022-11-29 23:56:10 -05:00
handle: self.image,
format: self.format,
size: self.size,
padded_size: Default::default(),
},
filter,
mip_filter: filter,
wrap_mode,
}
}
fn scale(
&mut self,
scaling: Scale2D,
format: ImageFormat,
2022-11-30 00:39:42 -05:00
viewport: &Viewport<Self>,
2022-11-29 23:56:10 -05:00
_original: &Texture,
source: &Texture,
) -> Result<Size<u32>> {
if self.is_raw {
return Ok(self.size);
}
let size = librashader_runtime::scaling::scale(scaling, source.image.size, viewport.output.size);
if self.size != size {
self.size = size;
self.init(
size,
if format == ImageFormat::Unknown {
ImageFormat::R8G8B8A8Unorm
} else {
format
},
)?;
}
Ok(size)
}
fn clear<const REBIND: bool>(&self) {
unsafe {
2022-11-30 00:39:42 -05:00
gl::ClearNamedFramebufferfv(self.handle,
gl::COLOR, 0,
[0.0f32, 0.0, 0.0, 0.0].as_ptr().cast());
2022-11-29 23:56:10 -05:00
}
}
2022-11-30 00:39:42 -05:00
fn copy_from(&mut self, image: &GLImage) -> Result<()> {
2022-11-29 23:56:10 -05:00
// todo: may want to use a shader and draw a quad to be faster.
if image.size != self.size || image.format != self.format {
self.init(image.size, image.format)?;
}
unsafe {
2022-11-30 00:39:42 -05:00
// gl::NamedFramebufferDrawBuffer(self.handle, gl::COLOR_ATTACHMENT1);
gl::NamedFramebufferReadBuffer(image.handle, gl::COLOR_ATTACHMENT0);
gl::NamedFramebufferDrawBuffer(self.handle, gl::COLOR_ATTACHMENT1);
2022-11-29 23:56:10 -05:00
2022-11-30 00:39:42 -05:00
gl::BlitNamedFramebuffer(image.handle, self.handle,
0, 0, image.size.width as GLint, image.size.height as GLint,
0, 0, self.size.width as GLint, self.size.height as GLint,
gl::COLOR_BUFFER_BIT, gl::NEAREST);
2022-11-29 23:56:10 -05:00
}
Ok(())
}
fn init(&mut self, mut size: Size<u32>, format: impl Into<GLenum>) -> Result<()> {
if self.is_raw {
return Ok(());
}
self.format = format.into();
self.size = size;
unsafe {
// reset the framebuffer image
if self.image != 0 {
2022-11-30 00:39:42 -05:00
gl::NamedFramebufferTexture(
self.handle,
2022-11-29 23:56:10 -05:00
gl::COLOR_ATTACHMENT0,
0,
0,
);
gl::DeleteTextures(1, &self.image);
}
2022-11-30 00:39:42 -05:00
gl::CreateTextures(gl::TEXTURE_2D,1, &mut self.image);
2022-11-29 23:56:10 -05:00
if size.width == 0 {
size.width = 1;
}
if size.height == 0 {
size.height = 1;
}
2022-11-30 00:39:42 -05:00
self.levels = librashader_runtime::scaling::calc_miplevel(size);
if self.levels > self.max_levels {
self.levels = self.max_levels;
2022-11-29 23:56:10 -05:00
}
2022-11-30 00:39:42 -05:00
if self.levels == 0 {
self.levels = 1;
2022-11-29 23:56:10 -05:00
}
2022-11-30 00:39:42 -05:00
gl::TextureStorage2D(
self.image,
self.levels as GLsizei,
2022-11-29 23:56:10 -05:00
self.format,
size.width as GLsizei,
size.height as GLsizei,
);
2022-11-30 00:39:42 -05:00
gl::NamedFramebufferTexture(
self.handle,
2022-11-29 23:56:10 -05:00
gl::COLOR_ATTACHMENT0,
self.image,
0,
);
let status = gl::CheckFramebufferStatus(gl::FRAMEBUFFER);
if status != gl::FRAMEBUFFER_COMPLETE {
match status {
gl::FRAMEBUFFER_UNSUPPORTED => {
eprintln!("unsupported fbo");
2022-11-30 00:39:42 -05:00
gl::NamedFramebufferTexture(
self.handle,
2022-11-29 23:56:10 -05:00
gl::COLOR_ATTACHMENT0,
0,
0,
);
gl::DeleteTextures(1, &self.image);
2022-11-30 00:39:42 -05:00
gl::CreateTextures(gl::TEXTURE_2D, 1, &mut self.image);
2022-11-29 23:56:10 -05:00
2022-11-30 00:39:42 -05:00
self.levels = librashader_runtime::scaling::calc_miplevel(size);
if self.levels > self.max_levels {
self.levels = self.max_levels;
2022-11-29 23:56:10 -05:00
}
2022-11-30 00:39:42 -05:00
if self.levels == 0 {
self.levels = 1;
2022-11-29 23:56:10 -05:00
}
2022-11-30 00:39:42 -05:00
gl::TextureStorage2D(
self.image,
self.levels as GLsizei,
2022-11-29 23:56:10 -05:00
ImageFormat::R8G8B8A8Unorm.into(),
size.width as GLsizei,
size.height as GLsizei,
);
2022-11-30 00:39:42 -05:00
gl::NamedFramebufferTexture(
self.handle,
2022-11-29 23:56:10 -05:00
gl::COLOR_ATTACHMENT0,
self.image,
0,
);
// self.init =
// gl::CheckFramebufferStatus(gl::FRAMEBUFFER) == gl::FRAMEBUFFER_COMPLETE;
}
_ => return Err(FilterChainError::FramebufferInit(status))
}
}
}
Ok(())
}
}
impl Drop for Gl46Framebuffer {
fn drop(&mut self) {
unsafe {
if self.handle != 0 {
gl::DeleteFramebuffers(1, &self.handle);
}
if self.image != 0 {
gl::DeleteTextures(1, &self.image);
}
}
}
}