Skip to content

Commit 41353ac

Browse files
committed
rt(gl): remove need for explicit external FBO object
Replaced with an internal FBO that is state tracked so as to not recreate it every frame, but will update if necessary
1 parent 4d790e7 commit 41353ac

File tree

16 files changed

+282
-139
lines changed

16 files changed

+282
-139
lines changed

include/librashader.h

+37-52
Large diffs are not rendered by default.

include/librashader_ld.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ libra_error_t __librashader__noop_gl_filter_chain_create(
204204

205205
libra_error_t __librashader__noop_gl_filter_chain_frame(
206206
libra_gl_filter_chain_t *chain, size_t frame_count,
207-
struct libra_source_image_gl_t image, struct libra_output_framebuffer_gl_t out,
207+
struct libra_image_gl_t image, struct libra_image_gl_t out,
208208
const struct libra_viewport_t *viewport, const float *mvp,
209209
const struct frame_gl_opt_t *opt) {
210210
return NULL;

librashader-capi/src/runtime/gl/filter_chain.rs

+16-42
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,8 @@ use crate::ctypes::{
44
use crate::error::{assert_non_null, assert_some_ptr, LibrashaderError};
55
use crate::ffi::extern_fn;
66
use crate::LIBRASHADER_API_VERSION;
7-
use librashader::runtime::gl::error::FilterChainError;
87
use librashader::runtime::gl::{
9-
FilterChain, FilterChainOptions, FrameOptions, GLFramebuffer, GLImage,
8+
FilterChain, FilterChainOptions, FrameOptions, GLImage,
109
};
1110
use librashader::runtime::FilterChainParameters;
1211
use librashader::runtime::{Size, Viewport};
@@ -21,36 +20,21 @@ use std::sync::Arc;
2120
/// A GL function loader that librashader needs to be initialized with.
2221
pub type libra_gl_loader_t = unsafe extern "system" fn(*const c_char) -> *const c_void;
2322

24-
/// OpenGL parameters for the source image.
23+
/// OpenGL parameters for an image.
2524
#[repr(C)]
26-
pub struct libra_source_image_gl_t {
27-
/// A texture GLuint to the source image.
25+
pub struct libra_image_gl_t {
26+
/// A texture GLuint to the texture.
2827
pub handle: u32,
29-
/// The format of the source image.
28+
/// The format of the texture.
3029
pub format: u32,
31-
/// The width of the source image.
30+
/// The width of the texture.
3231
pub width: u32,
33-
/// The height of the source image.
32+
/// The height of the texture.
3433
pub height: u32,
3534
}
3635

37-
/// OpenGL parameters for the output framebuffer.
38-
#[repr(C)]
39-
pub struct libra_output_framebuffer_gl_t {
40-
/// A framebuffer GLuint to the output framebuffer.
41-
pub fbo: u32,
42-
/// A texture GLuint to the logical buffer of the output framebuffer.
43-
pub texture: u32,
44-
/// The format of the output framebuffer.
45-
pub format: u32,
46-
/// The width of the output image.
47-
pub width: u32,
48-
/// The height of the output image.
49-
pub height: u32,
50-
}
51-
52-
impl From<libra_source_image_gl_t> for GLImage {
53-
fn from(value: libra_source_image_gl_t) -> Self {
36+
impl From<libra_image_gl_t> for GLImage {
37+
fn from(value: libra_image_gl_t) -> Self {
5438
let handle = NonZeroU32::try_from(value.handle)
5539
.ok()
5640
.map(glow::NativeTexture);
@@ -166,7 +150,7 @@ extern_fn! {
166150
///
167151
/// - `chain` is a handle to the filter chain.
168152
/// - `frame_count` is the number of frames passed to the shader
169-
/// - `image` is a `libra_source_image_gl_t`, containing the name of a Texture, format, and size information to
153+
/// - `image` is a `libra_image_gl_t`, containing the name of a Texture, format, and size information to
170154
/// to an image that will serve as the source image for the frame.
171155
/// - `out` is a `libra_output_framebuffer_gl_t`, containing the name of a Framebuffer, the name of a Texture, format,
172156
/// and size information for the render target of the frame.
@@ -193,14 +177,16 @@ extern_fn! {
193177
nopanic fn libra_gl_filter_chain_frame(
194178
chain: *mut libra_gl_filter_chain_t,
195179
frame_count: usize,
196-
image: libra_source_image_gl_t,
197-
out: libra_output_framebuffer_gl_t,
180+
image: libra_image_gl_t,
181+
out: libra_image_gl_t,
198182
viewport: *const libra_viewport_t,
199183
mvp: *const f32,
200184
opt: *const MaybeUninit<frame_gl_opt_t>,
201185
) mut |chain| {
202186
assert_some_ptr!(mut chain);
203187
let image: GLImage = image.into();
188+
let out: GLImage = out.into();
189+
204190
let mvp = if mvp.is_null() {
205191
None
206192
} else {
@@ -214,26 +200,14 @@ extern_fn! {
214200

215201
let opt = opt.map(FromUninit::from_uninit);
216202

217-
let texture = NonZeroU32::try_from(out.texture)
218-
.ok()
219-
.map(glow::NativeTexture);
220-
221-
let fbo = NonZeroU32::try_from(out.fbo)
222-
.ok()
223-
.map(glow::NativeFramebuffer)
224-
.ok_or(FilterChainError::GlInvalidFramebuffer)?;
225-
226-
let framebuffer = GLFramebuffer::new_from_raw(Arc::clone(chain.get_context()),
227-
texture, fbo, out.format, Size::new(out.width, out.height), 1);
228-
229203
let viewport = if viewport.is_null() {
230-
Viewport::new_render_target_sized_origin(&framebuffer, mvp)?
204+
Viewport::new_render_target_sized_origin(&out, mvp)?
231205
} else {
232206
let viewport = unsafe { viewport.read() };
233207
Viewport {
234208
x: viewport.x,
235209
y: viewport.y,
236-
output: &framebuffer,
210+
output: &out,
237211
size: Size {
238212
height: viewport.height,
239213
width: viewport.width

librashader-runtime-gl/src/filter_chain/chain.rs

+12-3
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ use crate::binding::{GlUniformStorage, UniformLocation, VariableLocation};
22
use crate::error::FilterChainError;
33
use crate::filter_pass::{FilterPass, UniformOffset};
44
use crate::gl::{
5-
CompileProgram, DrawQuad, FramebufferInterface, GLFramebuffer, GLInterface, LoadLut, UboRing,
5+
CompileProgram, DrawQuad, FramebufferInterface, GLFramebuffer, GLInterface, LoadLut,
6+
OutputFramebuffer, UboRing,
67
};
78
use crate::options::{FilterChainOptionsGL, FrameOptionsGL};
89
use crate::samplers::SamplerSet;
@@ -39,6 +40,7 @@ pub(crate) struct FilterChainImpl<T: GLInterface> {
3940
output_framebuffers: Box<[GLFramebuffer]>,
4041
feedback_framebuffers: Box<[GLFramebuffer]>,
4142
history_framebuffers: VecDeque<GLFramebuffer>,
43+
render_target: OutputFramebuffer,
4244
default_options: FrameOptionsGL,
4345
draw_last_pass_feedback: bool,
4446
}
@@ -183,6 +185,8 @@ impl<T: GLInterface> FilterChainImpl<T> {
183185
// create vertex objects
184186
let draw_quad = T::DrawQuad::new(&context)?;
185187

188+
let output = OutputFramebuffer::new(&context);
189+
186190
Ok(FilterChainImpl {
187191
draw_last_pass_feedback: framebuffer_init.uses_final_pass_as_feedback(),
188192
passes: filters,
@@ -201,6 +205,7 @@ impl<T: GLInterface> FilterChainImpl<T> {
201205
context,
202206
},
203207
default_options: Default::default(),
208+
render_target: output,
204209
})
205210
}
206211

@@ -278,7 +283,7 @@ impl<T: GLInterface> FilterChainImpl<T> {
278283
pub unsafe fn frame(
279284
&mut self,
280285
frame_count: usize,
281-
viewport: &Viewport<&GLFramebuffer>,
286+
viewport: &Viewport<&GLImage>,
282287
input: &GLImage,
283288
options: Option<&FrameOptionsGL>,
284289
) -> error::Result<()> {
@@ -385,6 +390,10 @@ impl<T: GLInterface> FilterChainImpl<T> {
385390
assert_eq!(last.len(), 1);
386391
if let Some(pass) = last.iter_mut().next() {
387392
let index = passes_len - 1;
393+
let final_viewport = self
394+
.render_target
395+
.ensure::<T::FramebufferInterface>(viewport.output)?;
396+
388397
source.filter = pass.config.filter;
389398
source.mip_filter = pass.config.filter;
390399
source.wrap_mode = pass.config.wrap_mode;
@@ -411,7 +420,7 @@ impl<T: GLInterface> FilterChainImpl<T> {
411420
viewport,
412421
&original,
413422
&source,
414-
RenderTarget::viewport(viewport),
423+
RenderTarget::viewport_with_output(final_viewport, viewport),
415424
);
416425
self.common.output_textures[passes_len - 1] = viewport
417426
.output

librashader-runtime-gl/src/filter_chain/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use crate::error::{FilterChainError, Result};
22
use crate::filter_chain::chain::FilterChainImpl;
33
use crate::filter_chain::inner::FilterChainDispatch;
44
use crate::options::{FilterChainOptionsGL, FrameOptionsGL};
5-
use crate::{GLFramebuffer, GLImage};
5+
use crate::GLImage;
66
use librashader_presets::ShaderPreset;
77
use std::panic::catch_unwind;
88
use std::path::Path;
@@ -63,7 +63,7 @@ impl FilterChainGL {
6363
pub unsafe fn frame(
6464
&mut self,
6565
input: &GLImage,
66-
viewport: &Viewport<&GLFramebuffer>,
66+
viewport: &Viewport<&GLImage>,
6767
frame_count: usize,
6868
options: Option<&FrameOptionsGL>,
6969
) -> Result<()> {

librashader-runtime-gl/src/filter_pass.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,10 @@ use librashader_runtime::render_target::RenderTarget;
1212

1313
use crate::binding::{GlUniformBinder, GlUniformStorage, UniformLocation, VariableLocation};
1414
use crate::filter_chain::FilterCommon;
15-
use crate::gl::{BindTexture, GLInterface, UboRing};
15+
use crate::gl::{BindTexture, GLFramebuffer, GLInterface, UboRing};
1616
use crate::options::FrameOptionsGL;
1717
use crate::samplers::SamplerSet;
18-
use crate::GLFramebuffer;
18+
use crate::GLImage;
1919

2020
use crate::texture::InputTexture;
2121

@@ -82,7 +82,7 @@ impl<T: GLInterface> FilterPass<T> {
8282
parent: &FilterCommon,
8383
frame_count: u32,
8484
options: &FrameOptionsGL,
85-
viewport: &Viewport<&GLFramebuffer>,
85+
viewport: &Viewport<&GLImage>,
8686
original: &InputTexture,
8787
source: &InputTexture,
8888
output: RenderTarget<GLFramebuffer, i32>,
@@ -177,7 +177,7 @@ impl<T: GLInterface> FilterPass<T> {
177177
frame_count: u32,
178178
options: &FrameOptionsGL,
179179
fb_size: Size<u32>,
180-
viewport: &Viewport<&GLFramebuffer>,
180+
viewport: &Viewport<&GLImage>,
181181
original: &InputTexture,
182182
source: &InputTexture,
183183
) {

librashader-runtime-gl/src/framebuffer.rs

+21-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
use librashader_common::{GetSize, Size};
1+
use crate::texture::InputTexture;
2+
use librashader_common::{FilterMode, GetSize, Size, WrapMode};
23

34
/// A handle to an OpenGL texture with format and size information.
45
///
@@ -13,10 +14,29 @@ pub struct GLImage {
1314
pub size: Size<u32>,
1415
}
1516

17+
impl GLImage {
18+
pub(crate) fn as_texture(&self, filter: FilterMode, wrap_mode: WrapMode) -> InputTexture {
19+
InputTexture {
20+
image: *self,
21+
filter,
22+
mip_filter: filter,
23+
wrap_mode,
24+
}
25+
}
26+
}
27+
1628
impl GetSize<u32> for GLImage {
1729
type Error = std::convert::Infallible;
1830

1931
fn size(&self) -> Result<Size<u32>, Self::Error> {
2032
Ok(self.size)
2133
}
2234
}
35+
36+
impl GetSize<u32> for &GLImage {
37+
type Error = std::convert::Infallible;
38+
39+
fn size(&self) -> Result<Size<u32>, Self::Error> {
40+
Ok(self.size)
41+
}
42+
}

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

+50-6
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ pub struct GLFramebuffer {
1919
pub(crate) format: u32,
2020
pub(crate) max_levels: u32,
2121
pub(crate) mip_levels: u32,
22-
pub(crate) is_raw: bool,
22+
pub(crate) is_extern_image: bool,
2323
pub(crate) ctx: Arc<glow::Context>,
2424
}
2525

@@ -42,7 +42,7 @@ impl GLFramebuffer {
4242
max_levels: miplevels,
4343
mip_levels: miplevels,
4444
fbo,
45-
is_raw: true,
45+
is_extern_image: true,
4646
ctx,
4747
}
4848
}
@@ -89,14 +89,58 @@ impl GLFramebuffer {
8989
}
9090
}
9191

92-
impl Drop for GLFramebuffer {
93-
fn drop(&mut self) {
94-
if self.is_raw {
95-
return;
92+
/// A state-checked wrapper around a raw framebuffer, used exclusively for output images.
93+
pub struct OutputFramebuffer {
94+
framebuffer: Option<GLFramebuffer>,
95+
ctx: Arc<glow::Context>,
96+
}
97+
98+
impl OutputFramebuffer {
99+
pub fn new(ctx: &Arc<glow::Context>) -> Self {
100+
OutputFramebuffer {
101+
ctx: Arc::clone(ctx),
102+
framebuffer: None,
96103
}
104+
}
105+
106+
/// Ensure that the renderbuffer is up to date.
107+
pub fn ensure<T: FramebufferInterface>(&mut self, image: &GLImage) -> Result<&GLFramebuffer> {
108+
let texture = image.handle;
109+
let size = image.size;
110+
let format = image.format;
111+
112+
let Some(framebuffer) = self.framebuffer.as_mut() else {
113+
self.framebuffer = Some(T::new_raw(&self.ctx, texture, size, format, 1)?);
114+
return Ok(self.framebuffer.as_ref().unwrap());
115+
};
116+
117+
assert!(
118+
framebuffer.is_extern_image,
119+
"Somehow an internal image got into the renderbuffer!"
120+
);
121+
122+
if framebuffer.image == texture && framebuffer.size == size && framebuffer.format == format
123+
{
124+
// Problem Case #3 :cry:
125+
return Ok(self.framebuffer.as_ref().unwrap());
126+
};
97127

128+
// Replace with a new framebuffer.
129+
let new = T::new_raw(&self.ctx, texture, size, format, 1)?;
130+
std::mem::swap(&mut self.framebuffer, &mut Some(new));
131+
Ok(self.framebuffer.as_ref().unwrap())
132+
}
133+
}
134+
135+
impl Drop for GLFramebuffer {
136+
fn drop(&mut self) {
98137
unsafe {
99138
self.ctx.delete_framebuffer(self.fbo);
139+
140+
if self.is_extern_image {
141+
return;
142+
}
143+
100144
if let Some(image) = self.image {
101145
self.ctx.delete_texture(image);
102146
}

0 commit comments

Comments
 (0)