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

190 lines
5.9 KiB
Rust
Raw Normal View History

2022-11-29 23:56:10 -05:00
use crate::error::{FilterChainError, Result};
2022-11-30 19:05:24 -05:00
use crate::framebuffer::GLImage;
use crate::gl::framebuffer::Framebuffer;
use crate::gl::FramebufferInterface;
2023-01-13 17:59:22 -05:00
use gl::types::{GLenum, GLint, GLsizei};
2023-01-13 02:54:16 -05:00
use librashader_common::{ImageFormat, Size, Viewport};
2022-11-30 01:38:05 -05:00
use librashader_presets::Scale2D;
2022-12-21 21:13:35 -05:00
use librashader_runtime::scaling::{MipmapSize, ViewportSize};
2022-11-29 23:56:10 -05:00
#[derive(Debug)]
pub struct Gl46Framebuffer;
2022-11-30 00:39:42 -05:00
impl FramebufferInterface for Gl46Framebuffer {
fn new(max_levels: u32) -> Framebuffer {
2022-11-29 23:56:10 -05:00
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
}
Framebuffer {
2022-11-29 23:56:10 -05:00
image: 0,
size: Size {
width: 1,
height: 1,
},
format: 0,
max_levels,
mip_levels: 0,
2022-11-29 23:56:10 -05:00
handle: framebuffer,
is_raw: false,
}
}
2023-01-13 02:54:16 -05:00
2022-11-29 23:56:10 -05:00
fn scale(
fb: &mut Framebuffer,
2022-11-29 23:56:10 -05:00
scaling: Scale2D,
format: ImageFormat,
2023-01-13 02:54:16 -05:00
viewport: &Viewport<&Framebuffer>,
source_size: &Size<u32>,
mipmap: bool,
2022-11-29 23:56:10 -05:00
) -> Result<Size<u32>> {
if fb.is_raw {
return Ok(fb.size);
2022-11-29 23:56:10 -05:00
}
2023-01-29 21:26:34 -05:00
let size = source_size.scale_viewport(scaling, viewport.output.size);
2022-11-29 23:56:10 -05:00
if fb.size != size || (mipmap && fb.max_levels == 1) || (!mipmap && fb.max_levels != 1) {
fb.size = size;
2022-11-29 23:56:10 -05:00
if mipmap {
fb.max_levels = u32::MAX;
} else {
fb.max_levels = 1
}
Self::init(
fb,
2022-11-29 23:56:10 -05:00
size,
if format == ImageFormat::Unknown {
ImageFormat::R8G8B8A8Unorm
} else {
format
},
)?;
}
Ok(size)
}
fn clear<const REBIND: bool>(fb: &Framebuffer) {
2022-11-29 23:56:10 -05:00
unsafe {
2022-11-30 01:38:05 -05:00
gl::ClearNamedFramebufferfv(
fb.handle,
2022-11-30 01:38:05 -05:00
gl::COLOR,
0,
[0.0f32, 0.0, 0.0, 0.0].as_ptr().cast(),
);
2022-11-29 23:56:10 -05:00
}
}
fn copy_from(fb: &mut Framebuffer, image: &GLImage) -> Result<()> {
2022-11-30 17:59:55 -05:00
// todo: confirm this behaviour for unbound image.
if image.handle == 0 {
2022-11-30 19:05:24 -05:00
return Ok(());
2022-11-30 17:59:55 -05:00
}
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 != fb.size || image.format != fb.format {
2022-11-30 19:05:24 -05:00
Self::init(fb, image.size, image.format)?;
2022-11-29 23:56:10 -05:00
}
unsafe {
// gl::NamedFramebufferDrawBuffer(fb.handle, gl::COLOR_ATTACHMENT1);
2022-11-30 00:39:42 -05:00
gl::NamedFramebufferReadBuffer(image.handle, gl::COLOR_ATTACHMENT0);
gl::NamedFramebufferDrawBuffer(fb.handle, gl::COLOR_ATTACHMENT0);
2022-11-29 23:56:10 -05:00
2022-11-30 01:38:05 -05:00
gl::BlitNamedFramebuffer(
image.handle,
fb.handle,
2022-11-30 01:38:05 -05:00
0,
0,
image.size.width as GLint,
image.size.height as GLint,
0,
0,
fb.size.width as GLint,
fb.size.height as GLint,
2022-11-30 01:38:05 -05:00
gl::COLOR_BUFFER_BIT,
gl::NEAREST,
);
2022-11-29 23:56:10 -05:00
}
Ok(())
}
fn init(fb: &mut Framebuffer, mut size: Size<u32>, format: impl Into<GLenum>) -> Result<()> {
if fb.is_raw {
2022-11-29 23:56:10 -05:00
return Ok(());
}
fb.format = format.into();
fb.size = size;
2022-11-29 23:56:10 -05:00
unsafe {
// reset the framebuffer image
if fb.image != 0 {
gl::NamedFramebufferTexture(fb.handle, gl::COLOR_ATTACHMENT0, 0, 0);
gl::DeleteTextures(1, &fb.image);
2022-11-29 23:56:10 -05:00
}
gl::CreateTextures(gl::TEXTURE_2D, 1, &mut fb.image);
2022-11-29 23:56:10 -05:00
if size.width == 0 {
size.width = 1;
}
if size.height == 0 {
size.height = 1;
}
2022-12-21 21:13:35 -05:00
fb.mip_levels = size.calculate_miplevels();
if fb.mip_levels > fb.max_levels {
fb.mip_levels = fb.max_levels;
2022-11-29 23:56:10 -05:00
}
if fb.mip_levels == 0 {
fb.mip_levels = 1;
2022-11-29 23:56:10 -05:00
}
2022-11-30 00:39:42 -05:00
gl::TextureStorage2D(
fb.image,
fb.mip_levels as GLsizei,
fb.format,
2022-11-29 23:56:10 -05:00
size.width as GLsizei,
size.height as GLsizei,
);
gl::NamedFramebufferTexture(fb.handle, gl::COLOR_ATTACHMENT0, fb.image, 0);
2022-11-29 23:56:10 -05:00
let status = gl::CheckFramebufferStatus(gl::FRAMEBUFFER);
if status != gl::FRAMEBUFFER_COMPLETE {
match status {
gl::FRAMEBUFFER_UNSUPPORTED => {
eprintln!("unsupported fbo");
gl::NamedFramebufferTexture(fb.handle, gl::COLOR_ATTACHMENT0, 0, 0);
gl::DeleteTextures(1, &fb.image);
gl::CreateTextures(gl::TEXTURE_2D, 1, &mut fb.image);
2022-11-29 23:56:10 -05:00
2022-12-21 21:13:35 -05:00
fb.mip_levels = size.calculate_miplevels();
if fb.mip_levels > fb.max_levels {
fb.mip_levels = fb.max_levels;
2022-11-29 23:56:10 -05:00
}
if fb.mip_levels == 0 {
fb.mip_levels = 1;
2022-11-29 23:56:10 -05:00
}
2022-11-30 00:39:42 -05:00
gl::TextureStorage2D(
fb.image,
fb.mip_levels as GLsizei,
2022-11-29 23:56:10 -05:00
ImageFormat::R8G8B8A8Unorm.into(),
size.width as GLsizei,
size.height as GLsizei,
);
gl::NamedFramebufferTexture(fb.handle, gl::COLOR_ATTACHMENT0, fb.image, 0);
// fb.init =
2022-11-29 23:56:10 -05:00
// gl::CheckFramebufferStatus(gl::FRAMEBUFFER) == gl::FRAMEBUFFER_COMPLETE;
}
2022-11-30 01:38:05 -05:00
_ => return Err(FilterChainError::FramebufferInit(status)),
2022-11-29 23:56:10 -05:00
}
}
}
Ok(())
}
}