From 41353ac9c47a403dea8094cc4d6f59d52caf85e4 Mon Sep 17 00:00:00 2001 From: chyyran Date: Sun, 8 Sep 2024 01:03:43 -0400 Subject: [PATCH] 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 --- include/librashader.h | 89 ++++++++----------- include/librashader_ld.h | 2 +- .../src/runtime/gl/filter_chain.rs | 58 ++++-------- .../src/filter_chain/chain.rs | 15 +++- .../src/filter_chain/mod.rs | 4 +- librashader-runtime-gl/src/filter_pass.rs | 8 +- librashader-runtime-gl/src/framebuffer.rs | 22 ++++- librashader-runtime-gl/src/gl/framebuffer.rs | 56 ++++++++++-- .../src/gl/gl3/framebuffer.rs | 61 ++++++++++++- .../src/gl/gl46/framebuffer.rs | 53 ++++++++++- librashader-runtime-gl/src/gl/mod.rs | 14 ++- librashader-runtime-gl/src/lib.rs | 1 - .../tests/hello_triangle/gl3.rs | 15 ++-- .../tests/hello_triangle/gl46.rs | 15 ++-- librashader-runtime-gl/tests/triangle.rs | 6 +- librashader/src/lib.rs | 2 +- 16 files changed, 282 insertions(+), 139 deletions(-) diff --git a/include/librashader.h b/include/librashader.h index 8fb4d85..2c1c6c8 100644 --- a/include/librashader.h +++ b/include/librashader.h @@ -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 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. diff --git a/include/librashader_ld.h b/include/librashader_ld.h index f9b1f4e..7f22622 100644 --- a/include/librashader_ld.h +++ b/include/librashader_ld.h @@ -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; diff --git a/librashader-capi/src/runtime/gl/filter_chain.rs b/librashader-capi/src/runtime/gl/filter_chain.rs index 1905c12..3a729ef 100644 --- a/librashader-capi/src/runtime/gl/filter_chain.rs +++ b/librashader-capi/src/runtime/gl/filter_chain.rs @@ -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 for GLImage { - fn from(value: libra_source_image_gl_t) -> Self { +impl From 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, ) 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 diff --git a/librashader-runtime-gl/src/filter_chain/chain.rs b/librashader-runtime-gl/src/filter_chain/chain.rs index d750ac4..5e71e3b 100644 --- a/librashader-runtime-gl/src/filter_chain/chain.rs +++ b/librashader-runtime-gl/src/filter_chain/chain.rs @@ -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 { output_framebuffers: Box<[GLFramebuffer]>, feedback_framebuffers: Box<[GLFramebuffer]>, history_framebuffers: VecDeque, + render_target: OutputFramebuffer, default_options: FrameOptionsGL, draw_last_pass_feedback: bool, } @@ -183,6 +185,8 @@ impl FilterChainImpl { // 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 FilterChainImpl { context, }, default_options: Default::default(), + render_target: output, }) } @@ -278,7 +283,7 @@ impl FilterChainImpl { 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 FilterChainImpl { 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::(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 FilterChainImpl { viewport, &original, &source, - RenderTarget::viewport(viewport), + RenderTarget::viewport_with_output(final_viewport, viewport), ); self.common.output_textures[passes_len - 1] = viewport .output diff --git a/librashader-runtime-gl/src/filter_chain/mod.rs b/librashader-runtime-gl/src/filter_chain/mod.rs index cc477cd..5461290 100644 --- a/librashader-runtime-gl/src/filter_chain/mod.rs +++ b/librashader-runtime-gl/src/filter_chain/mod.rs @@ -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<()> { diff --git a/librashader-runtime-gl/src/filter_pass.rs b/librashader-runtime-gl/src/filter_pass.rs index 7a52072..3dee311 100644 --- a/librashader-runtime-gl/src/filter_pass.rs +++ b/librashader-runtime-gl/src/filter_pass.rs @@ -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 FilterPass { parent: &FilterCommon, frame_count: u32, options: &FrameOptionsGL, - viewport: &Viewport<&GLFramebuffer>, + viewport: &Viewport<&GLImage>, original: &InputTexture, source: &InputTexture, output: RenderTarget, @@ -177,7 +177,7 @@ impl FilterPass { frame_count: u32, options: &FrameOptionsGL, fb_size: Size, - viewport: &Viewport<&GLFramebuffer>, + viewport: &Viewport<&GLImage>, original: &InputTexture, source: &InputTexture, ) { diff --git a/librashader-runtime-gl/src/framebuffer.rs b/librashader-runtime-gl/src/framebuffer.rs index 50ef287..6c0fee7 100644 --- a/librashader-runtime-gl/src/framebuffer.rs +++ b/librashader-runtime-gl/src/framebuffer.rs @@ -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, } +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 for GLImage { type Error = std::convert::Infallible; @@ -20,3 +32,11 @@ impl GetSize for GLImage { Ok(self.size) } } + +impl GetSize for &GLImage { + type Error = std::convert::Infallible; + + fn size(&self) -> Result, Self::Error> { + Ok(self.size) + } +} diff --git a/librashader-runtime-gl/src/gl/framebuffer.rs b/librashader-runtime-gl/src/gl/framebuffer.rs index d1ac97f..6095135 100644 --- a/librashader-runtime-gl/src/gl/framebuffer.rs +++ b/librashader-runtime-gl/src/gl/framebuffer.rs @@ -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, } @@ -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, + ctx: Arc, +} + +impl OutputFramebuffer { + pub fn new(ctx: &Arc) -> Self { + OutputFramebuffer { + ctx: Arc::clone(ctx), + framebuffer: None, + } + } + + /// Ensure that the renderbuffer is up to date. + pub fn ensure(&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 { - return; - } - unsafe { self.ctx.delete_framebuffer(self.fbo); + + if self.is_extern_image { + return; + } + if let Some(image) = self.image { self.ctx.delete_texture(image); } diff --git a/librashader-runtime-gl/src/gl/gl3/framebuffer.rs b/librashader-runtime-gl/src/gl/gl3/framebuffer.rs index eecdecd..d78237c 100644 --- a/librashader-runtime-gl/src/gl/gl3/framebuffer.rs +++ b/librashader-runtime-gl/src/gl/gl3/framebuffer.rs @@ -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, + image: Option, + mut size: Size, + format: u32, + miplevels: u32, + ) -> Result { + 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(fb: &GLFramebuffer) { unsafe { if REBIND { @@ -120,7 +177,7 @@ impl FramebufferInterface for Gl3Framebuffer { Ok(()) } fn init(fb: &mut GLFramebuffer, mut size: Size, format: impl Into) -> Result<()> { - if fb.is_raw { + if fb.is_extern_image { return Ok(()); } fb.format = format.into(); diff --git a/librashader-runtime-gl/src/gl/gl46/framebuffer.rs b/librashader-runtime-gl/src/gl/gl46/framebuffer.rs index 5b1a5b0..f3d69da 100644 --- a/librashader-runtime-gl/src/gl/gl46/framebuffer.rs +++ b/librashader-runtime-gl/src/gl/gl46/framebuffer.rs @@ -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, + image: Option, + mut size: Size, + format: u32, + miplevels: u32, + ) -> Result { + 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(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, format: impl Into) -> Result<()> { - if fb.is_raw { + if fb.is_extern_image { return Ok(()); } fb.format = format.into(); diff --git a/librashader-runtime-gl/src/gl/mod.rs b/librashader-runtime-gl/src/gl/mod.rs index 2286867..cded543 100644 --- a/librashader-runtime-gl/src/gl/mod.rs +++ b/librashader-runtime-gl/src/gl/mod.rs @@ -95,6 +95,16 @@ pub(crate) trait UboRing { pub(crate) trait FramebufferInterface { fn new(context: &Arc, max_levels: u32) -> Result; + + /// Create a new raw framebuffer for the given image, size, format, and miplevels. + fn new_raw( + context: &Arc, + image: Option, + size: Size, + format: u32, + miplevels: u32, + ) -> Result; + fn scale( fb: &mut GLFramebuffer, scaling: Scale2D, @@ -104,7 +114,7 @@ pub(crate) trait FramebufferInterface { original_size: &Size, mipmap: bool, ) -> Result> { - 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; diff --git a/librashader-runtime-gl/src/lib.rs b/librashader-runtime-gl/src/lib.rs index fd3b0ab..f0049f3 100644 --- a/librashader-runtime-gl/src/lib.rs +++ b/librashader-runtime-gl/src/lib.rs @@ -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; diff --git a/librashader-runtime-gl/tests/hello_triangle/gl3.rs b/librashader-runtime-gl/tests/hello_triangle/gl3.rs index 8e990f0..d170004 100644 --- a/librashader-runtime-gl/tests/hello_triangle/gl3.rs +++ b/librashader-runtime-gl/tests/hello_triangle/gl3.rs @@ -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(); diff --git a/librashader-runtime-gl/tests/hello_triangle/gl46.rs b/librashader-runtime-gl/tests/hello_triangle/gl46.rs index b4fe040..875e66e 100644 --- a/librashader-runtime-gl/tests/hello_triangle/gl46.rs +++ b/librashader-runtime-gl/tests/hello_triangle/gl46.rs @@ -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(); diff --git a/librashader-runtime-gl/tests/triangle.rs b/librashader-runtime-gl/tests/triangle.rs index 39bec3c..38c7eaf 100644 --- a/librashader-runtime-gl/tests/triangle.rs +++ b/librashader-runtime-gl/tests/triangle.rs @@ -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, diff --git a/librashader/src/lib.rs b/librashader/src/lib.rs index 9660943..29a74dd 100644 --- a/librashader/src/lib.rs +++ b/librashader/src/lib.rs @@ -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, }; }