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
This commit is contained in:
chyyran 2024-09-08 01:03:43 -04:00 committed by Ronny Chan
parent 4d790e7a7b
commit 41353ac9c4
16 changed files with 282 additions and 139 deletions

View file

@ -194,33 +194,17 @@ typedef struct _filter_chain_gl *libra_gl_filter_chain_t;
#endif
#if defined(LIBRA_RUNTIME_OPENGL)
/// OpenGL parameters for the source image.
typedef struct libra_source_image_gl_t {
/// A texture GLuint to the source image.
/// OpenGL parameters for an image.
typedef struct libra_image_gl_t {
/// A texture GLuint to the texture.
uint32_t handle;
/// The format of the source image.
/// The format of the texture.
uint32_t format;
/// The width of the source image.
/// The width of the texture.
uint32_t width;
/// The height of the source image.
/// The height of the texture.
uint32_t height;
} libra_source_image_gl_t;
#endif
#if defined(LIBRA_RUNTIME_OPENGL)
/// OpenGL parameters for the output framebuffer.
typedef struct libra_output_framebuffer_gl_t {
/// A framebuffer GLuint to the output framebuffer.
uint32_t fbo;
/// A texture GLuint to the logical buffer of the output framebuffer.
uint32_t texture;
/// The format of the output framebuffer.
uint32_t format;
/// The width of the output image.
uint32_t width;
/// The height of the output image.
uint32_t height;
} libra_output_framebuffer_gl_t;
} libra_image_gl_t;
#endif
/// Defines the output origin for a rendered frame.
@ -269,7 +253,7 @@ typedef struct libra_device_vk_t {
/// for the device attached to the instance that will perform rendering.
VkDevice device;
/// The queue to use, if this is `NULL`, then
/// a suitable queue will be chosen.
/// a suitable queue will be chosen. This must be a graphics queue.
VkQueue queue;
/// The entry loader for the Vulkan library.
PFN_vkGetInstanceProcAddr entry;
@ -642,8 +626,8 @@ typedef libra_error_t (*PFN_libra_gl_filter_chain_create)(libra_shader_preset_t
///libra_gl_filter_chain_frame
typedef libra_error_t (*PFN_libra_gl_filter_chain_frame)(libra_gl_filter_chain_t *chain,
size_t frame_count,
struct libra_source_image_gl_t image,
struct libra_output_framebuffer_gl_t out,
struct libra_image_gl_t image,
struct libra_image_gl_t out,
const struct libra_viewport_t *viewport,
const float *mvp,
const struct frame_gl_opt_t *opt);
@ -660,7 +644,7 @@ typedef libra_error_t (*PFN_libra_gl_filter_chain_set_param)(libra_gl_filter_cha
#if defined(LIBRA_RUNTIME_OPENGL)
/// Function pointer definition for
///libra_gl_filter_chain_get_param
typedef libra_error_t (*PFN_libra_gl_filter_chain_get_param)(libra_gl_filter_chain_t *chain,
typedef libra_error_t (*PFN_libra_gl_filter_chain_get_param)(const libra_gl_filter_chain_t *chain,
const char *param_name,
float *out);
#endif
@ -728,7 +712,7 @@ typedef libra_error_t (*PFN_libra_vk_filter_chain_set_param)(libra_vk_filter_cha
#if defined(LIBRA_RUNTIME_VULKAN)
/// Function pointer definition for
///libra_vk_filter_chain_get_param
typedef libra_error_t (*PFN_libra_vk_filter_chain_get_param)(libra_vk_filter_chain_t *chain,
typedef libra_error_t (*PFN_libra_vk_filter_chain_get_param)(const libra_vk_filter_chain_t *chain,
const char *param_name,
float *out);
#endif
@ -743,7 +727,7 @@ typedef libra_error_t (*PFN_libra_vk_filter_chain_set_active_pass_count)(libra_v
#if defined(LIBRA_RUNTIME_VULKAN)
/// Function pointer definition for
///libra_vk_filter_chain_get_active_pass_count
typedef libra_error_t (*PFN_libra_vk_filter_chain_get_active_pass_count)(libra_vk_filter_chain_t *chain,
typedef libra_error_t (*PFN_libra_vk_filter_chain_get_active_pass_count)(const libra_vk_filter_chain_t *chain,
uint32_t *out);
#endif
@ -796,7 +780,7 @@ typedef libra_error_t (*PFN_libra_d3d11_filter_chain_set_param)(libra_d3d11_filt
#if (defined(_WIN32) && defined(LIBRA_RUNTIME_D3D11))
/// Function pointer definition for
///libra_d3d11_filter_chain_get_param
typedef libra_error_t (*PFN_libra_d3d11_filter_chain_get_param)(libra_d3d11_filter_chain_t *chain,
typedef libra_error_t (*PFN_libra_d3d11_filter_chain_get_param)(const libra_d3d11_filter_chain_t *chain,
const char *param_name,
float *out);
#endif
@ -811,7 +795,7 @@ typedef libra_error_t (*PFN_libra_d3d11_filter_chain_set_active_pass_count)(libr
#if (defined(_WIN32) && defined(LIBRA_RUNTIME_D3D11))
/// Function pointer definition for
///libra_d3d11_filter_chain_get_active_pass_count
typedef libra_error_t (*PFN_libra_d3d11_filter_chain_get_active_pass_count)(libra_d3d11_filter_chain_t *chain,
typedef libra_error_t (*PFN_libra_d3d11_filter_chain_get_active_pass_count)(const libra_d3d11_filter_chain_t *chain,
uint32_t *out);
#endif
@ -853,7 +837,7 @@ typedef libra_error_t (*PFN_libra_d3d9_filter_chain_set_param)(libra_d3d9_filter
#if (defined(_WIN32) && defined(LIBRA_RUNTIME_D3D9))
/// Function pointer definition for
///libra_d3d9_filter_chain_get_param
typedef libra_error_t (*PFN_libra_d3d9_filter_chain_get_param)(libra_d3d9_filter_chain_t *chain,
typedef libra_error_t (*PFN_libra_d3d9_filter_chain_get_param)(const libra_d3d9_filter_chain_t *chain,
const char *param_name,
float *out);
#endif
@ -868,7 +852,7 @@ typedef libra_error_t (*PFN_libra_d3d9_filter_chain_set_active_pass_count)(libra
#if (defined(_WIN32) && defined(LIBRA_RUNTIME_D3D9))
/// Function pointer definition for
///libra_d3d9_filter_chain_get_active_pass_count
typedef libra_error_t (*PFN_libra_d3d9_filter_chain_get_active_pass_count)(libra_d3d9_filter_chain_t *chain,
typedef libra_error_t (*PFN_libra_d3d9_filter_chain_get_active_pass_count)(const libra_d3d9_filter_chain_t *chain,
uint32_t *out);
#endif
@ -921,7 +905,7 @@ typedef libra_error_t (*PFN_libra_d3d12_filter_chain_set_param)(libra_d3d12_filt
#if (defined(_WIN32) && defined(LIBRA_RUNTIME_D3D12))
/// Function pointer definition for
///libra_d3d12_filter_chain_get_param
typedef libra_error_t (*PFN_libra_d3d12_filter_chain_get_param)(libra_d3d12_filter_chain_t *chain,
typedef libra_error_t (*PFN_libra_d3d12_filter_chain_get_param)(const libra_d3d12_filter_chain_t *chain,
const char *param_name,
float *out);
#endif
@ -936,7 +920,7 @@ typedef libra_error_t (*PFN_libra_d3d12_filter_chain_set_active_pass_count)(libr
#if (defined(_WIN32) && defined(LIBRA_RUNTIME_D3D12))
/// Function pointer definition for
///libra_d3d12_filter_chain_get_active_pass_count
typedef libra_error_t (*PFN_libra_d3d12_filter_chain_get_active_pass_count)(libra_d3d12_filter_chain_t *chain,
typedef libra_error_t (*PFN_libra_d3d12_filter_chain_get_active_pass_count)(const libra_d3d12_filter_chain_t *chain,
uint32_t *out);
#endif
@ -989,7 +973,7 @@ typedef libra_error_t (*PFN_libra_mtl_filter_chain_set_param)(libra_mtl_filter_c
#if (defined(__APPLE__) && defined(LIBRA_RUNTIME_METAL) && defined(__OBJC__))
/// Function pointer definition for
///libra_mtl_filter_chain_get_param
typedef libra_error_t (*PFN_libra_mtl_filter_chain_get_param)(libra_mtl_filter_chain_t *chain,
typedef libra_error_t (*PFN_libra_mtl_filter_chain_get_param)(const libra_mtl_filter_chain_t *chain,
const char *param_name,
float *out);
#endif
@ -1004,7 +988,7 @@ typedef libra_error_t (*PFN_libra_mtl_filter_chain_set_active_pass_count)(libra_
#if (defined(__APPLE__) && defined(LIBRA_RUNTIME_METAL) && defined(__OBJC__))
/// Function pointer definition for
///libra_mtl_filter_chain_get_active_pass_count
typedef libra_error_t (*PFN_libra_mtl_filter_chain_get_active_pass_count)(libra_mtl_filter_chain_t *chain,
typedef libra_error_t (*PFN_libra_mtl_filter_chain_get_active_pass_count)(const libra_mtl_filter_chain_t *chain,
uint32_t *out);
#endif
@ -1037,6 +1021,7 @@ typedef libra_error_t (*PFN_libra_mtl_filter_chain_free)(libra_mtl_filter_chain_
/// ABI versions are not backwards compatible. It is not
/// valid to load a librashader C API instance for any ABI
/// version not equal to LIBRASHADER_CURRENT_ABI.
///
/// ## ABI Versions
/// - ABI version 0: null instance (unloaded)
/// - ABI version 1: 0.1.0
@ -1205,7 +1190,7 @@ libra_error_t libra_gl_filter_chain_create(libra_shader_preset_t *preset,
///
/// - `chain` is a handle to the filter chain.
/// - `frame_count` is the number of frames passed to the shader
/// - `image` is a `libra_source_image_gl_t`, containing the name of a Texture, format, and size information to
/// - `image` is a `libra_image_gl_t`, containing the name of a Texture, format, and size information to
/// to an image that will serve as the source image for the frame.
/// - `out` is a `libra_output_framebuffer_gl_t`, containing the name of a Framebuffer, the name of a Texture, format,
/// and size information for the render target of the frame.
@ -1231,8 +1216,8 @@ libra_error_t libra_gl_filter_chain_create(libra_shader_preset_t *preset,
/// the filter chain.
libra_error_t libra_gl_filter_chain_frame(libra_gl_filter_chain_t *chain,
size_t frame_count,
struct libra_source_image_gl_t image,
struct libra_output_framebuffer_gl_t out,
struct libra_image_gl_t image,
struct libra_image_gl_t out,
const struct libra_viewport_t *viewport,
const float *mvp,
const struct frame_gl_opt_t *opt);
@ -1257,7 +1242,7 @@ libra_error_t libra_gl_filter_chain_set_param(libra_gl_filter_chain_t *chain,
/// ## Safety
/// - `chain` must be either null or a valid and aligned pointer to an initialized `libra_gl_filter_chain_t`.
/// - `param_name` must be either null or a null terminated string.
libra_error_t libra_gl_filter_chain_get_param(libra_gl_filter_chain_t *chain,
libra_error_t libra_gl_filter_chain_get_param(const libra_gl_filter_chain_t *chain,
const char *param_name,
float *out);
#endif
@ -1402,7 +1387,7 @@ libra_error_t libra_vk_filter_chain_set_param(libra_vk_filter_chain_t *chain,
/// ## Safety
/// - `chain` must be either null or a valid and aligned pointer to an initialized `libra_vk_filter_chain_t`.
/// - `param_name` must be either null or a null terminated string.
libra_error_t libra_vk_filter_chain_get_param(libra_vk_filter_chain_t *chain,
libra_error_t libra_vk_filter_chain_get_param(const libra_vk_filter_chain_t *chain,
const char *param_name,
float *out);
#endif
@ -1421,7 +1406,7 @@ libra_error_t libra_vk_filter_chain_set_active_pass_count(libra_vk_filter_chain_
///
/// ## Safety
/// - `chain` must be either null or a valid and aligned pointer to an initialized `libra_vk_filter_chain_t`.
libra_error_t libra_vk_filter_chain_get_active_pass_count(libra_vk_filter_chain_t *chain,
libra_error_t libra_vk_filter_chain_get_active_pass_count(const libra_vk_filter_chain_t *chain,
uint32_t *out);
#endif
@ -1550,7 +1535,7 @@ libra_error_t libra_d3d11_filter_chain_set_param(libra_d3d11_filter_chain_t *cha
/// ## Safety
/// - `chain` must be either null or a valid and aligned pointer to an initialized `libra_d3d11_filter_chain_t`.
/// - `param_name` must be either null or a null terminated string.
libra_error_t libra_d3d11_filter_chain_get_param(libra_d3d11_filter_chain_t *chain,
libra_error_t libra_d3d11_filter_chain_get_param(const libra_d3d11_filter_chain_t *chain,
const char *param_name,
float *out);
#endif
@ -1569,7 +1554,7 @@ libra_error_t libra_d3d11_filter_chain_set_active_pass_count(libra_d3d11_filter_
///
/// ## Safety
/// - `chain` must be either null or a valid and aligned pointer to an initialized `libra_d3d11_filter_chain_t`.
libra_error_t libra_d3d11_filter_chain_get_active_pass_count(libra_d3d11_filter_chain_t *chain,
libra_error_t libra_d3d11_filter_chain_get_active_pass_count(const libra_d3d11_filter_chain_t *chain,
uint32_t *out);
#endif
@ -1656,7 +1641,7 @@ libra_error_t libra_d3d9_filter_chain_set_param(libra_d3d9_filter_chain_t *chain
/// ## Safety
/// - `chain` must be either null or a valid and aligned pointer to an initialized `libra_d3d9_filter_chain_t`.
/// - `param_name` must be either null or a null terminated string.
libra_error_t libra_d3d9_filter_chain_get_param(libra_d3d9_filter_chain_t *chain,
libra_error_t libra_d3d9_filter_chain_get_param(const libra_d3d9_filter_chain_t *chain,
const char *param_name,
float *out);
#endif
@ -1675,7 +1660,7 @@ libra_error_t libra_d3d9_filter_chain_set_active_pass_count(libra_d3d9_filter_ch
///
/// ## Safety
/// - `chain` must be either null or a valid and aligned pointer to an initialized `libra_d3d9_filter_chain_t`.
libra_error_t libra_d3d9_filter_chain_get_active_pass_count(libra_d3d9_filter_chain_t *chain,
libra_error_t libra_d3d9_filter_chain_get_active_pass_count(const libra_d3d9_filter_chain_t *chain,
uint32_t *out);
#endif
@ -1800,7 +1785,7 @@ libra_error_t libra_d3d12_filter_chain_set_param(libra_d3d12_filter_chain_t *cha
/// ## Safety
/// - `chain` must be either null or a valid and aligned pointer to an initialized `libra_d3d12_filter_chain_t`.
/// - `param_name` must be either null or a null terminated string.
libra_error_t libra_d3d12_filter_chain_get_param(libra_d3d12_filter_chain_t *chain,
libra_error_t libra_d3d12_filter_chain_get_param(const libra_d3d12_filter_chain_t *chain,
const char *param_name,
float *out);
#endif
@ -1819,7 +1804,7 @@ libra_error_t libra_d3d12_filter_chain_set_active_pass_count(libra_d3d12_filter_
///
/// ## Safety
/// - `chain` must be either null or a valid and aligned pointer to an initialized `libra_d3d12_filter_chain_t`.
libra_error_t libra_d3d12_filter_chain_get_active_pass_count(libra_d3d12_filter_chain_t *chain,
libra_error_t libra_d3d12_filter_chain_get_active_pass_count(const libra_d3d12_filter_chain_t *chain,
uint32_t *out);
#endif
@ -1936,7 +1921,7 @@ libra_error_t libra_mtl_filter_chain_set_param(libra_mtl_filter_chain_t *chain,
/// ## Safety
/// - `chain` must be either null or a valid and aligned pointer to an initialized `libra_mtl_filter_chain_t`.
/// - `param_name` must be either null or a null terminated string.
libra_error_t libra_mtl_filter_chain_get_param(libra_mtl_filter_chain_t *chain,
libra_error_t libra_mtl_filter_chain_get_param(const libra_mtl_filter_chain_t *chain,
const char *param_name,
float *out);
#endif
@ -1955,7 +1940,7 @@ libra_error_t libra_mtl_filter_chain_set_active_pass_count(libra_mtl_filter_chai
///
/// ## Safety
/// - `chain` must be either null or a valid and aligned pointer to an initialized `libra_mtl_filter_chain_t`.
libra_error_t libra_mtl_filter_chain_get_active_pass_count(libra_mtl_filter_chain_t *chain,
libra_error_t libra_mtl_filter_chain_get_active_pass_count(const libra_mtl_filter_chain_t *chain,
uint32_t *out);
#endif
@ -1984,7 +1969,7 @@ LIBRASHADER_API_VERSION libra_instance_api_version(void);
///
/// These automatically inferred variables, as well as all other variables can be overridden with
/// `libra_preset_ctx_set_param`, but the expected string values must be provided.
/// See https://github.com/libretro/RetroArch/pull/15023 for a list of expected string values.
/// See <https://github.com/libretro/RetroArch/pull/15023> for a list of expected string values.
///
/// No variables can be removed once added to the context, however subsequent calls to set the same
/// variable will overwrite the expected variable.

View file

@ -204,7 +204,7 @@ libra_error_t __librashader__noop_gl_filter_chain_create(
libra_error_t __librashader__noop_gl_filter_chain_frame(
libra_gl_filter_chain_t *chain, size_t frame_count,
struct libra_source_image_gl_t image, struct libra_output_framebuffer_gl_t out,
struct libra_image_gl_t image, struct libra_image_gl_t out,
const struct libra_viewport_t *viewport, const float *mvp,
const struct frame_gl_opt_t *opt) {
return NULL;

View file

@ -4,9 +4,8 @@ use crate::ctypes::{
use crate::error::{assert_non_null, assert_some_ptr, LibrashaderError};
use crate::ffi::extern_fn;
use crate::LIBRASHADER_API_VERSION;
use librashader::runtime::gl::error::FilterChainError;
use librashader::runtime::gl::{
FilterChain, FilterChainOptions, FrameOptions, GLFramebuffer, GLImage,
FilterChain, FilterChainOptions, FrameOptions, GLImage,
};
use librashader::runtime::FilterChainParameters;
use librashader::runtime::{Size, Viewport};
@ -21,36 +20,21 @@ use std::sync::Arc;
/// A GL function loader that librashader needs to be initialized with.
pub type libra_gl_loader_t = unsafe extern "system" fn(*const c_char) -> *const c_void;
/// OpenGL parameters for the source image.
/// OpenGL parameters for an image.
#[repr(C)]
pub struct libra_source_image_gl_t {
/// A texture GLuint to the source image.
pub struct libra_image_gl_t {
/// A texture GLuint to the texture.
pub handle: u32,
/// The format of the source image.
/// The format of the texture.
pub format: u32,
/// The width of the source image.
/// The width of the texture.
pub width: u32,
/// The height of the source image.
/// The height of the texture.
pub height: u32,
}
/// OpenGL parameters for the output framebuffer.
#[repr(C)]
pub struct libra_output_framebuffer_gl_t {
/// A framebuffer GLuint to the output framebuffer.
pub fbo: u32,
/// A texture GLuint to the logical buffer of the output framebuffer.
pub texture: u32,
/// The format of the output framebuffer.
pub format: u32,
/// The width of the output image.
pub width: u32,
/// The height of the output image.
pub height: u32,
}
impl From<libra_source_image_gl_t> for GLImage {
fn from(value: libra_source_image_gl_t) -> Self {
impl From<libra_image_gl_t> for GLImage {
fn from(value: libra_image_gl_t) -> Self {
let handle = NonZeroU32::try_from(value.handle)
.ok()
.map(glow::NativeTexture);
@ -166,7 +150,7 @@ extern_fn! {
///
/// - `chain` is a handle to the filter chain.
/// - `frame_count` is the number of frames passed to the shader
/// - `image` is a `libra_source_image_gl_t`, containing the name of a Texture, format, and size information to
/// - `image` is a `libra_image_gl_t`, containing the name of a Texture, format, and size information to
/// to an image that will serve as the source image for the frame.
/// - `out` is a `libra_output_framebuffer_gl_t`, containing the name of a Framebuffer, the name of a Texture, format,
/// and size information for the render target of the frame.
@ -193,14 +177,16 @@ extern_fn! {
nopanic fn libra_gl_filter_chain_frame(
chain: *mut libra_gl_filter_chain_t,
frame_count: usize,
image: libra_source_image_gl_t,
out: libra_output_framebuffer_gl_t,
image: libra_image_gl_t,
out: libra_image_gl_t,
viewport: *const libra_viewport_t,
mvp: *const f32,
opt: *const MaybeUninit<frame_gl_opt_t>,
) mut |chain| {
assert_some_ptr!(mut chain);
let image: GLImage = image.into();
let out: GLImage = out.into();
let mvp = if mvp.is_null() {
None
} else {
@ -214,26 +200,14 @@ extern_fn! {
let opt = opt.map(FromUninit::from_uninit);
let texture = NonZeroU32::try_from(out.texture)
.ok()
.map(glow::NativeTexture);
let fbo = NonZeroU32::try_from(out.fbo)
.ok()
.map(glow::NativeFramebuffer)
.ok_or(FilterChainError::GlInvalidFramebuffer)?;
let framebuffer = GLFramebuffer::new_from_raw(Arc::clone(chain.get_context()),
texture, fbo, out.format, Size::new(out.width, out.height), 1);
let viewport = if viewport.is_null() {
Viewport::new_render_target_sized_origin(&framebuffer, mvp)?
Viewport::new_render_target_sized_origin(&out, mvp)?
} else {
let viewport = unsafe { viewport.read() };
Viewport {
x: viewport.x,
y: viewport.y,
output: &framebuffer,
output: &out,
size: Size {
height: viewport.height,
width: viewport.width

View file

@ -2,7 +2,8 @@ use crate::binding::{GlUniformStorage, UniformLocation, VariableLocation};
use crate::error::FilterChainError;
use crate::filter_pass::{FilterPass, UniformOffset};
use crate::gl::{
CompileProgram, DrawQuad, FramebufferInterface, GLFramebuffer, GLInterface, LoadLut, UboRing,
CompileProgram, DrawQuad, FramebufferInterface, GLFramebuffer, GLInterface, LoadLut,
OutputFramebuffer, UboRing,
};
use crate::options::{FilterChainOptionsGL, FrameOptionsGL};
use crate::samplers::SamplerSet;
@ -39,6 +40,7 @@ pub(crate) struct FilterChainImpl<T: GLInterface> {
output_framebuffers: Box<[GLFramebuffer]>,
feedback_framebuffers: Box<[GLFramebuffer]>,
history_framebuffers: VecDeque<GLFramebuffer>,
render_target: OutputFramebuffer,
default_options: FrameOptionsGL,
draw_last_pass_feedback: bool,
}
@ -183,6 +185,8 @@ impl<T: GLInterface> FilterChainImpl<T> {
// create vertex objects
let draw_quad = T::DrawQuad::new(&context)?;
let output = OutputFramebuffer::new(&context);
Ok(FilterChainImpl {
draw_last_pass_feedback: framebuffer_init.uses_final_pass_as_feedback(),
passes: filters,
@ -201,6 +205,7 @@ impl<T: GLInterface> FilterChainImpl<T> {
context,
},
default_options: Default::default(),
render_target: output,
})
}
@ -278,7 +283,7 @@ impl<T: GLInterface> FilterChainImpl<T> {
pub unsafe fn frame(
&mut self,
frame_count: usize,
viewport: &Viewport<&GLFramebuffer>,
viewport: &Viewport<&GLImage>,
input: &GLImage,
options: Option<&FrameOptionsGL>,
) -> error::Result<()> {
@ -385,6 +390,10 @@ impl<T: GLInterface> FilterChainImpl<T> {
assert_eq!(last.len(), 1);
if let Some(pass) = last.iter_mut().next() {
let index = passes_len - 1;
let final_viewport = self
.render_target
.ensure::<T::FramebufferInterface>(viewport.output)?;
source.filter = pass.config.filter;
source.mip_filter = pass.config.filter;
source.wrap_mode = pass.config.wrap_mode;
@ -411,7 +420,7 @@ impl<T: GLInterface> FilterChainImpl<T> {
viewport,
&original,
&source,
RenderTarget::viewport(viewport),
RenderTarget::viewport_with_output(final_viewport, viewport),
);
self.common.output_textures[passes_len - 1] = viewport
.output

View file

@ -2,7 +2,7 @@ use crate::error::{FilterChainError, Result};
use crate::filter_chain::chain::FilterChainImpl;
use crate::filter_chain::inner::FilterChainDispatch;
use crate::options::{FilterChainOptionsGL, FrameOptionsGL};
use crate::{GLFramebuffer, GLImage};
use crate::GLImage;
use librashader_presets::ShaderPreset;
use std::panic::catch_unwind;
use std::path::Path;
@ -63,7 +63,7 @@ impl FilterChainGL {
pub unsafe fn frame(
&mut self,
input: &GLImage,
viewport: &Viewport<&GLFramebuffer>,
viewport: &Viewport<&GLImage>,
frame_count: usize,
options: Option<&FrameOptionsGL>,
) -> Result<()> {

View file

@ -12,10 +12,10 @@ use librashader_runtime::render_target::RenderTarget;
use crate::binding::{GlUniformBinder, GlUniformStorage, UniformLocation, VariableLocation};
use crate::filter_chain::FilterCommon;
use crate::gl::{BindTexture, GLInterface, UboRing};
use crate::gl::{BindTexture, GLFramebuffer, GLInterface, UboRing};
use crate::options::FrameOptionsGL;
use crate::samplers::SamplerSet;
use crate::GLFramebuffer;
use crate::GLImage;
use crate::texture::InputTexture;
@ -82,7 +82,7 @@ impl<T: GLInterface> FilterPass<T> {
parent: &FilterCommon,
frame_count: u32,
options: &FrameOptionsGL,
viewport: &Viewport<&GLFramebuffer>,
viewport: &Viewport<&GLImage>,
original: &InputTexture,
source: &InputTexture,
output: RenderTarget<GLFramebuffer, i32>,
@ -177,7 +177,7 @@ impl<T: GLInterface> FilterPass<T> {
frame_count: u32,
options: &FrameOptionsGL,
fb_size: Size<u32>,
viewport: &Viewport<&GLFramebuffer>,
viewport: &Viewport<&GLImage>,
original: &InputTexture,
source: &InputTexture,
) {

View file

@ -1,4 +1,5 @@
use librashader_common::{GetSize, Size};
use crate::texture::InputTexture;
use librashader_common::{FilterMode, GetSize, Size, WrapMode};
/// A handle to an OpenGL texture with format and size information.
///
@ -13,6 +14,17 @@ pub struct GLImage {
pub size: Size<u32>,
}
impl GLImage {
pub(crate) fn as_texture(&self, filter: FilterMode, wrap_mode: WrapMode) -> InputTexture {
InputTexture {
image: *self,
filter,
mip_filter: filter,
wrap_mode,
}
}
}
impl GetSize<u32> for GLImage {
type Error = std::convert::Infallible;
@ -20,3 +32,11 @@ impl GetSize<u32> for GLImage {
Ok(self.size)
}
}
impl GetSize<u32> for &GLImage {
type Error = std::convert::Infallible;
fn size(&self) -> Result<Size<u32>, Self::Error> {
Ok(self.size)
}
}

View file

@ -19,7 +19,7 @@ pub struct GLFramebuffer {
pub(crate) format: u32,
pub(crate) max_levels: u32,
pub(crate) mip_levels: u32,
pub(crate) is_raw: bool,
pub(crate) is_extern_image: bool,
pub(crate) ctx: Arc<glow::Context>,
}
@ -42,7 +42,7 @@ impl GLFramebuffer {
max_levels: miplevels,
mip_levels: miplevels,
fbo,
is_raw: true,
is_extern_image: true,
ctx,
}
}
@ -89,14 +89,58 @@ impl GLFramebuffer {
}
}
/// A state-checked wrapper around a raw framebuffer, used exclusively for output images.
pub struct OutputFramebuffer {
framebuffer: Option<GLFramebuffer>,
ctx: Arc<glow::Context>,
}
impl OutputFramebuffer {
pub fn new(ctx: &Arc<glow::Context>) -> Self {
OutputFramebuffer {
ctx: Arc::clone(ctx),
framebuffer: None,
}
}
/// Ensure that the renderbuffer is up to date.
pub fn ensure<T: FramebufferInterface>(&mut self, image: &GLImage) -> Result<&GLFramebuffer> {
let texture = image.handle;
let size = image.size;
let format = image.format;
let Some(framebuffer) = self.framebuffer.as_mut() else {
self.framebuffer = Some(T::new_raw(&self.ctx, texture, size, format, 1)?);
return Ok(self.framebuffer.as_ref().unwrap());
};
assert!(
framebuffer.is_extern_image,
"Somehow an internal image got into the renderbuffer!"
);
if framebuffer.image == texture && framebuffer.size == size && framebuffer.format == format
{
// Problem Case #3 :cry:
return Ok(self.framebuffer.as_ref().unwrap());
};
// Replace with a new framebuffer.
let new = T::new_raw(&self.ctx, texture, size, format, 1)?;
std::mem::swap(&mut self.framebuffer, &mut Some(new));
Ok(self.framebuffer.as_ref().unwrap())
}
}
impl Drop for GLFramebuffer {
fn drop(&mut self) {
if self.is_raw {
unsafe {
self.ctx.delete_framebuffer(self.fbo);
if self.is_extern_image {
return;
}
unsafe {
self.ctx.delete_framebuffer(self.fbo);
if let Some(image) = self.image {
self.ctx.delete_texture(image);
}

View file

@ -30,12 +30,69 @@ impl FramebufferInterface for Gl3Framebuffer {
max_levels,
mip_levels: 0,
fbo: framebuffer,
is_raw: false,
is_extern_image: false,
ctx: Arc::clone(&ctx),
})
}
}
fn new_raw(
ctx: &Arc<glow::Context>,
image: Option<glow::Texture>,
mut size: Size<u32>,
format: u32,
miplevels: u32,
) -> Result<GLFramebuffer> {
let framebuffer = unsafe {
ctx.create_framebuffer()
.map_err(FilterChainError::GlError)?
};
if size.width == 0 {
size.width = 1;
}
if size.height == 0 {
size.height = 1;
}
if size.width > librashader_runtime::scaling::MAX_TEXEL_SIZE as u32 {
size.width = librashader_runtime::scaling::MAX_TEXEL_SIZE as u32 - 1;
}
if size.height > librashader_runtime::scaling::MAX_TEXEL_SIZE as u32 {
size.height = librashader_runtime::scaling::MAX_TEXEL_SIZE as u32 - 1;
}
let status = unsafe {
ctx.bind_framebuffer(glow::FRAMEBUFFER, Some(framebuffer));
ctx.framebuffer_texture_2d(
glow::FRAMEBUFFER,
glow::COLOR_ATTACHMENT0,
glow::TEXTURE_2D,
image,
0,
);
ctx.check_framebuffer_status(glow::FRAMEBUFFER)
};
if status != glow::FRAMEBUFFER_COMPLETE {
return Err(FilterChainError::FramebufferInit(status));
}
Ok(GLFramebuffer {
image,
size,
format,
max_levels: miplevels,
mip_levels: miplevels,
fbo: framebuffer,
is_extern_image: true,
ctx: Arc::clone(&ctx),
})
}
fn clear<const REBIND: bool>(fb: &GLFramebuffer) {
unsafe {
if REBIND {
@ -120,7 +177,7 @@ impl FramebufferInterface for Gl3Framebuffer {
Ok(())
}
fn init(fb: &mut GLFramebuffer, mut size: Size<u32>, format: impl Into<u32>) -> Result<()> {
if fb.is_raw {
if fb.is_extern_image {
return Ok(());
}
fb.format = format.into();

View file

@ -29,11 +29,60 @@ impl FramebufferInterface for Gl46Framebuffer {
max_levels,
mip_levels: 0,
fbo: framebuffer,
is_raw: false,
is_extern_image: false,
ctx: Arc::clone(&context),
})
}
fn new_raw(
ctx: &Arc<glow::Context>,
image: Option<glow::Texture>,
mut size: Size<u32>,
format: u32,
miplevels: u32,
) -> Result<GLFramebuffer> {
let framebuffer = unsafe {
ctx.create_named_framebuffer()
.map_err(FilterChainError::GlError)?
};
if size.width == 0 {
size.width = 1;
}
if size.height == 0 {
size.height = 1;
}
if size.width > librashader_runtime::scaling::MAX_TEXEL_SIZE as u32 {
size.width = librashader_runtime::scaling::MAX_TEXEL_SIZE as u32 - 1;
}
if size.height > librashader_runtime::scaling::MAX_TEXEL_SIZE as u32 {
size.height = librashader_runtime::scaling::MAX_TEXEL_SIZE as u32 - 1;
}
let status = unsafe {
ctx.named_framebuffer_texture(Some(framebuffer), glow::COLOR_ATTACHMENT0, image, 0);
ctx.check_named_framebuffer_status(Some(framebuffer), glow::FRAMEBUFFER)
};
if status != glow::FRAMEBUFFER_COMPLETE {
return Err(FilterChainError::FramebufferInit(status));
}
Ok(GLFramebuffer {
image,
size,
format,
max_levels: miplevels,
mip_levels: miplevels,
fbo: framebuffer,
is_extern_image: true,
ctx: Arc::clone(&ctx),
})
}
fn clear<const REBIND: bool>(fb: &GLFramebuffer) {
unsafe {
fb.ctx.clear_named_framebuffer_f32_slice(
@ -90,7 +139,7 @@ impl FramebufferInterface for Gl46Framebuffer {
Ok(())
}
fn init(fb: &mut GLFramebuffer, mut size: Size<u32>, format: impl Into<u32>) -> Result<()> {
if fb.is_raw {
if fb.is_extern_image {
return Ok(());
}
fb.format = format.into();

View file

@ -95,6 +95,16 @@ pub(crate) trait UboRing<const SIZE: usize> {
pub(crate) trait FramebufferInterface {
fn new(context: &Arc<glow::Context>, max_levels: u32) -> Result<GLFramebuffer>;
/// Create a new raw framebuffer for the given image, size, format, and miplevels.
fn new_raw(
context: &Arc<glow::Context>,
image: Option<glow::Texture>,
size: Size<u32>,
format: u32,
miplevels: u32,
) -> Result<GLFramebuffer>;
fn scale(
fb: &mut GLFramebuffer,
scaling: Scale2D,
@ -104,7 +114,7 @@ pub(crate) trait FramebufferInterface {
original_size: &Size<u32>,
mipmap: bool,
) -> Result<Size<u32>> {
if fb.is_raw {
if fb.is_extern_image {
return Ok(fb.size);
}
@ -155,3 +165,5 @@ pub(crate) trait GLInterface {
type BindTexture: BindTexture;
type CompileShader: CompileProgram;
}
pub(crate) use framebuffer::OutputFramebuffer;

View file

@ -18,6 +18,5 @@ mod texture;
pub mod error;
pub mod options;
pub use crate::gl::GLFramebuffer;
pub use filter_chain::FilterChainGL;
pub use framebuffer::GLImage;

View file

@ -6,7 +6,7 @@ use glfw::{Context, Glfw, Window, WindowEvent};
use glow::HasContext;
use librashader_common::{GetSize, Size, Viewport};
use librashader_runtime_gl::{FilterChainGL, GLFramebuffer, GLImage};
use librashader_runtime_gl::{FilterChainGL, GLImage};
const WIDTH: u32 = 800;
const HEIGHT: u32 = 600;
@ -385,14 +385,11 @@ void main()
let (fb_width, fb_height) = window.get_framebuffer_size();
let (vp_width, vp_height) = window.get_size();
let output = GLFramebuffer::new_from_raw(
Arc::clone(gl),
Some(output_texture),
output_framebuffer_handle,
glow::RGBA8,
Size::new(vp_width as u32, vp_height as u32),
1,
);
let output = GLImage {
handle: Some(output_texture),
format: glow::RGBA8,
size: Size::new(vp_width as u32, vp_height as u32),
};
while !window.should_close() {
glfw.poll_events();

View file

@ -6,7 +6,7 @@ use glfw::{Context, Glfw, Window, WindowEvent};
use glow::HasContext;
use librashader_common::{GetSize, Size, Viewport};
use librashader_runtime_gl::{FilterChainGL, GLFramebuffer, GLImage};
use librashader_runtime_gl::{FilterChainGL, GLImage};
const WIDTH: u32 = 800;
const HEIGHT: u32 = 600;
@ -348,14 +348,11 @@ void main()
let (fb_width, fb_height) = window.get_framebuffer_size();
let (vp_width, vp_height) = window.get_size();
let output = GLFramebuffer::new_from_raw(
Arc::clone(gl),
Some(output_texture),
output_framebuffer_handle,
glow::RGBA8,
Size::new(vp_width as u32, vp_height as u32),
1,
);
let output = GLImage {
handle: Some(output_texture),
format: glow::RGBA8,
size: Size::new(vp_width as u32, vp_height as u32),
};
while !window.should_close() {
glfw.poll_events();

View file

@ -12,7 +12,7 @@ fn triangle_gl() {
let mut filter = FilterChainGL::load_from_path(
Arc::clone(&context),
// "../test/basic.slangp",
"../test/shaders_slang/crt/crt-royale.slangp",
"../test/shaders_slang/test/feedback.slangp",
Some(&FilterChainOptionsGL {
glsl_version: 0,
use_dsa: false,
@ -35,8 +35,8 @@ fn triangle_gl46() {
// "../test/slang-shaders/vhs/VHSPro.slangp",
// "../test/slang-shaders/test/history.slangp",
// "../test/basic.slangp",
"../test/shaders_slang/crt/crt-royale.slangp",
// "../test/shadersslang/bezel/Mega_Bezel/Presets/MBZ__0__SMOOTH-ADV.slangp",
// "../test/shaders_slang/crt/crt-royale.slangp",
"../test/shaders_slang/bezel/Mega_Bezel/Presets/MBZ__0__SMOOTH-ADV.slangp",
Some(&FilterChainOptionsGL {
glsl_version: 330,
use_dsa: true,

View file

@ -263,7 +263,7 @@ pub mod runtime {
pub use librashader_runtime_gl::{
error,
options::{FilterChainOptionsGL as FilterChainOptions, FrameOptionsGL as FrameOptions},
FilterChainGL as FilterChain, GLFramebuffer, GLImage,
FilterChainGL as FilterChain, GLImage,
};
}