gl: very not nicely make dsa a runtime prop

This commit is contained in:
chyyran 2022-11-30 17:21:32 -05:00
parent 8d940d6f79
commit 759cd4bc28
16 changed files with 333 additions and 324 deletions

View file

@ -9,7 +9,7 @@ use crate::util::{gl_get_version, gl_u16_to_version};
use gl::types::{GLint, GLuint};
use crate::binding::BufferStorage;
use crate::gl::{DrawQuad, Framebuffer, GLInterface, LoadLut, UboRing};
use crate::gl::{DrawQuad, Framebuffer, FramebufferInterface, GLInterface, LoadLut, UboRing};
use crate::options::{FilterChainOptions, FrameOptions};
use crate::samplers::SamplerSet;
use crate::texture::Texture;
@ -30,20 +30,75 @@ use spirv_cross::spirv::Decoration;
use std::collections::VecDeque;
use std::path::Path;
pub struct FilterChain<T: GLInterface> {
pub struct FilterChain {
filter: FilterChainInner
}
impl FilterChain {
pub fn load_from_preset(
preset: ShaderPreset,
options: Option<&FilterChainOptions>,
) -> Result<Self> {
if let Some(options) = options && options.use_dsa {
return Ok(Self {
filter: FilterChainInner::DSA(FilterChainImpl::load_from_preset(preset, Some(options))?)
})
}
return Ok(Self {
filter: FilterChainInner::Compatibility(FilterChainImpl::load_from_preset(preset, options)?)
})
}
/// Load the shader preset at the given path into a filter chain.
pub fn load_from_path(
path: impl AsRef<Path>,
options: Option<&FilterChainOptions>,
) -> Result<Self> {
// load passes from preset
let preset = ShaderPreset::try_parse(path)?;
Self::load_from_preset(preset, options)
}
/// Process a frame with the input image.
///
/// When this frame returns, GL_FRAMEBUFFER is bound to 0.
pub fn frame(
&mut self,
count: usize,
viewport: &Viewport,
input: &GLImage,
options: Option<&FrameOptions>,
) -> Result<()> {
match &mut self.filter {
FilterChainInner::DSA(p) => {
p.frame(count, viewport, input, options)
}
FilterChainInner::Compatibility(p) => {
p.frame(count, viewport, input, options)
}
}
}
}
enum FilterChainInner {
DSA(FilterChainImpl<crate::gl::gl46::DirectStateAccessGL>),
Compatibility(FilterChainImpl<crate::gl::gl3::CompatibilityGL>)
}
struct FilterChainImpl<T: GLInterface> {
passes: Box<[FilterPass<T>]>,
common: FilterCommon,
pub(crate) draw_quad: T::DrawQuad,
output_framebuffers: Box<[T::Framebuffer]>,
feedback_framebuffers: Box<[T::Framebuffer]>,
history_framebuffers: VecDeque<T::Framebuffer>,
output_framebuffers: Box<[Framebuffer]>,
feedback_framebuffers: Box<[Framebuffer]>,
history_framebuffers: VecDeque<Framebuffer>,
}
pub struct FilterCommon {
pub(crate) struct FilterCommon {
// semantics: ReflectSemantics,
pub(crate) config: FilterMutable,
pub(crate) luts: FxHashMap<usize, Texture>,
pub(crate) samplers: SamplerSet,
pub config: FilterMutable,
pub luts: FxHashMap<usize, Texture>,
pub samplers: SamplerSet,
pub output_textures: Box<[Texture]>,
pub feedback_textures: Box<[Texture]>,
pub history_textures: Box<[Texture]>,
@ -54,7 +109,7 @@ pub struct FilterMutable {
pub(crate) parameters: FxHashMap<String, f32>,
}
impl<T: GLInterface> FilterChain<T> {
impl<T: GLInterface> FilterChainImpl<T> {
fn reflect_uniform_location(pipeline: GLuint, meta: &impl UniformMeta) -> VariableLocation {
// todo: support both ubo and pushco
// todo: fix this.
@ -91,9 +146,9 @@ type ShaderPassMeta = (
>,
);
impl<T: GLInterface> FilterChain<T> {
impl<T: GLInterface> FilterChainImpl<T> {
/// Load a filter chain from a pre-parsed `ShaderPreset`.
pub fn load_from_preset(
pub(crate) fn load_from_preset(
preset: ShaderPreset,
options: Option<&FilterChainOptions>,
) -> Result<Self> {
@ -116,13 +171,13 @@ impl<T: GLInterface> FilterChain<T> {
// initialize output framebuffers
let mut output_framebuffers = Vec::new();
output_framebuffers.resize_with(filters.len(), || Framebuffer::new(1));
output_framebuffers.resize_with(filters.len(), || T::FramebufferInterface::new(1));
let mut output_textures = Vec::new();
output_textures.resize_with(filters.len(), Texture::default);
// initialize feedback framebuffers
let mut feedback_framebuffers = Vec::new();
feedback_framebuffers.resize_with(filters.len(), || Framebuffer::new(1));
feedback_framebuffers.resize_with(filters.len(), || T::FramebufferInterface::new(1));
let mut feedback_textures = Vec::new();
feedback_textures.resize_with(filters.len(), Texture::default);
@ -130,12 +185,12 @@ impl<T: GLInterface> FilterChain<T> {
let luts = T::LoadLut::load_luts(&preset.textures)?;
let (history_framebuffers, history_textures) =
FilterChain::init_history(&filters, default_filter, default_wrap);
FilterChainImpl::init_history(&filters, default_filter, default_wrap);
// create vertex objects
let draw_quad = T::DrawQuad::new();
Ok(FilterChain {
Ok(FilterChainImpl {
passes: filters,
output_framebuffers: output_framebuffers.into_boxed_slice(),
feedback_framebuffers: feedback_framebuffers.into_boxed_slice(),
@ -159,16 +214,6 @@ impl<T: GLInterface> FilterChain<T> {
})
}
/// Load the shader preset at the given path into a filter chain.
pub fn load_from_path(
path: impl AsRef<Path>,
options: Option<&FilterChainOptions>,
) -> Result<Self> {
// load passes from preset
let preset = ShaderPreset::try_parse(path)?;
Self::load_from_preset(preset, options)
}
fn load_preset(
passes: Vec<ShaderPassConfig>,
textures: &[TextureConfig],
@ -363,7 +408,7 @@ impl<T: GLInterface> FilterChain<T> {
filters: &[FilterPass<T>],
filter: FilterMode,
wrap_mode: WrapMode,
) -> (VecDeque<T::Framebuffer>, Box<[Texture]>) {
) -> (VecDeque<Framebuffer>, Box<[Texture]>) {
let mut required_images = 0;
for pass in filters {
@ -397,7 +442,7 @@ impl<T: GLInterface> FilterChain<T> {
eprintln!("[history] using frame history with {required_images} images");
let mut framebuffers = VecDeque::with_capacity(required_images);
framebuffers.resize_with(required_images, || Framebuffer::new(1));
framebuffers.resize_with(required_images, || T::FramebufferInterface::new(1));
let mut history_textures = Vec::new();
history_textures.resize_with(required_images, || Texture {
@ -412,12 +457,12 @@ impl<T: GLInterface> FilterChain<T> {
fn push_history(&mut self, input: &GLImage) -> Result<()> {
if let Some(mut back) = self.history_framebuffers.pop_back() {
if back.size() != input.size || (input.format != 0 && input.format != back.format()) {
if back.size != input.size || (input.format != 0 && input.format != back.format) {
eprintln!("[history] resizing");
back.init(input.size, input.format)?;
T::FramebufferInterface::init(&mut back, input.size, input.format)?;
}
back.copy_from(input)?;
back.copy_from::<T::FramebufferInterface>(input)?;
self.history_framebuffers.push_front(back)
}
@ -431,7 +476,7 @@ impl<T: GLInterface> FilterChain<T> {
pub fn frame(
&mut self,
count: usize,
viewport: &Viewport<T::Framebuffer>,
viewport: &Viewport,
input: &GLImage,
options: Option<&FrameOptions>,
) -> Result<()> {
@ -440,7 +485,7 @@ impl<T: GLInterface> FilterChain<T> {
if let Some(options) = options {
if options.clear_history {
for framebuffer in &self.history_framebuffers {
framebuffer.clear::<true>()
framebuffer.clear::<T::FramebufferInterface, true>()
}
}
}
@ -490,7 +535,7 @@ impl<T: GLInterface> FilterChain<T> {
// rescale render buffers to ensure all bindings are valid.
for (index, pass) in passes.iter_mut().enumerate() {
self.output_framebuffers[index].scale(
self.output_framebuffers[index].scale::<T::FramebufferInterface>(
pass.config.scaling.clone(),
pass.get_format(),
viewport,
@ -498,7 +543,7 @@ impl<T: GLInterface> FilterChain<T> {
&source,
)?;
self.feedback_framebuffers[index].scale(
self.feedback_framebuffers[index].scale::<T::FramebufferInterface>(
pass.config.scaling.clone(),
pass.get_format(),
viewport,

View file

@ -14,7 +14,7 @@ use rustc_hash::FxHashMap;
use crate::binding::{BufferStorage, UniformLocation, VariableLocation};
use crate::filter_chain::FilterCommon;
use crate::framebuffer::Viewport;
use crate::gl::{BindTexture, Framebuffer, GLInterface, UboRing};
use crate::gl::{BindTexture, FramebufferInterface, GLInterface, UboRing};
use crate::render_target::RenderTarget;
use crate::texture::Texture;
@ -39,15 +39,15 @@ impl<T: GLInterface> FilterPass<T> {
parent: &FilterCommon,
frame_count: u32,
frame_direction: i32,
viewport: &Viewport<T::Framebuffer>,
viewport: &Viewport,
original: &Texture,
source: &Texture,
output: RenderTarget<T::Framebuffer>,
output: RenderTarget,
) {
let framebuffer = output.framebuffer;
unsafe {
gl::BindFramebuffer(gl::FRAMEBUFFER, framebuffer.handle());
gl::BindFramebuffer(gl::FRAMEBUFFER, framebuffer.handle);
gl::UseProgram(self.program);
}
@ -57,7 +57,7 @@ impl<T: GLInterface> FilterPass<T> {
output.mvp,
frame_count,
frame_direction,
framebuffer.size(),
framebuffer.size,
viewport,
original,
source,
@ -73,9 +73,9 @@ impl<T: GLInterface> FilterPass<T> {
unsafe {
// can't use framebuffer.clear because it will unbind.
framebuffer.clear::<false>();
framebuffer.clear::<T::FramebufferInterface, false>();
let framebuffer_size = framebuffer.size();
let framebuffer_size = framebuffer.size;
gl::Viewport(
output.x,
output.y,
@ -83,7 +83,7 @@ impl<T: GLInterface> FilterPass<T> {
framebuffer_size.height as GLsizei,
);
if framebuffer.format() == gl::SRGB8_ALPHA8 {
if framebuffer.format == gl::SRGB8_ALPHA8 {
gl::Enable(gl::FRAMEBUFFER_SRGB);
} else {
gl::Disable(gl::FRAMEBUFFER_SRGB);
@ -120,7 +120,7 @@ impl<T: GLInterface> FilterPass<T> {
frame_count: u32,
frame_direction: i32,
fb_size: Size<u32>,
viewport: &Viewport<T::Framebuffer>,
viewport: &Viewport,
original: &Texture,
source: &Texture,
) {
@ -145,7 +145,7 @@ impl<T: GLInterface> FilterPass<T> {
.get(&VariableSemantics::FinalViewport.into())
{
self.uniform_storage
.bind_vec4(*offset, viewport.output.size(), location.location());
.bind_vec4(*offset, viewport.output.size, location.location());
}
// bind FrameCount

View file

@ -1,13 +1,13 @@
use gl::types::{GLenum, GLuint};
use librashader_common::Size;
use crate::gl::Framebuffer;
use crate::gl::{Framebuffer, FramebufferInterface};
#[derive(Debug, Copy, Clone)]
pub struct Viewport<'a, T: Framebuffer + ?Sized> {
pub struct Viewport<'a> {
pub x: i32,
pub y: i32,
pub output: &'a T,
pub output: &'a Framebuffer,
pub mvp: Option<&'a [f32; 16]>,
}

View file

@ -0,0 +1,81 @@
use crate::error::Result;
use crate::framebuffer::GLImage;
use crate::gl::FramebufferInterface;
use crate::texture::Texture;
use crate::Viewport;
use gl::types::{GLenum, GLuint};
use librashader_common::{FilterMode, ImageFormat, Size, WrapMode};
use librashader_presets::Scale2D;
#[derive(Debug)]
pub struct Framebuffer {
pub image: GLuint,
pub handle: GLuint,
pub size: Size<u32>,
pub format: GLenum,
pub max_levels: u32,
pub mip_levels: u32,
pub is_raw: bool,
}
impl Framebuffer {
pub fn new<T: FramebufferInterface>(max_levels: u32) -> Self {
T::new(max_levels)
}
pub fn new_from_raw<T: FramebufferInterface>(
texture: GLuint,
handle: GLuint,
format: GLenum,
size: Size<u32>,
mip_levels: u32,
) -> Self {
T::new_from_raw(texture, handle, format, size, mip_levels)
}
pub fn clear<T: FramebufferInterface, const REBIND: bool>(&self) {
T::clear::<REBIND>(&self)
}
pub fn scale<T: FramebufferInterface>(
&mut self,
scaling: Scale2D,
format: ImageFormat,
viewport: &Viewport,
original: &Texture,
source: &Texture,
) -> Result<Size<u32>> {
T::scale(self, scaling, format, viewport, original, source)
}
pub fn copy_from<T: FramebufferInterface>(&mut self, image: &GLImage) -> Result<()> {
T::copy_from(self, image)
}
pub fn as_texture(&self, filter: FilterMode, wrap_mode: WrapMode) -> Texture {
Texture {
image: GLImage {
handle: self.image,
format: self.format,
size: self.size,
padded_size: Default::default(),
},
filter,
mip_filter: filter,
wrap_mode,
}
}
}
impl Drop for Framebuffer {
fn drop(&mut self) {
unsafe {
if self.handle != 0 {
gl::DeleteFramebuffers(1, &self.handle);
}
if self.image != 0 {
gl::DeleteTextures(1, &self.image);
}
}
}
}

View file

@ -1,40 +1,17 @@
use crate::error::{FilterChainError, Result};
use crate::framebuffer::{GLImage, Viewport};
use crate::gl::Framebuffer;
use crate::gl::framebuffer::Framebuffer;
use crate::gl::FramebufferInterface;
use crate::texture::Texture;
use gl::types::{GLenum, GLint, GLsizei, GLuint};
use librashader_common::{FilterMode, ImageFormat, Size, WrapMode};
use librashader_presets::Scale2D;
#[derive(Debug)]
pub struct Gl3Framebuffer {
image: GLuint,
handle: GLuint,
size: Size<u32>,
format: GLenum,
max_levels: u32,
mip_levels: u32,
is_raw: bool,
}
pub struct Gl3Framebuffer;
impl Framebuffer for Gl3Framebuffer {
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
}
fn new(max_levels: u32) -> Gl3Framebuffer {
impl FramebufferInterface for Gl3Framebuffer {
fn new(max_levels: u32) -> Framebuffer {
let mut framebuffer = 0;
unsafe {
gl::GenFramebuffers(1, &mut framebuffer);
@ -42,7 +19,7 @@ impl Framebuffer for Gl3Framebuffer {
gl::BindFramebuffer(gl::FRAMEBUFFER, 0);
}
Gl3Framebuffer {
Framebuffer {
image: 0,
size: Size {
width: 1,
@ -61,8 +38,8 @@ impl Framebuffer for Gl3Framebuffer {
format: GLenum,
size: Size<u32>,
miplevels: u32,
) -> Gl3Framebuffer {
Gl3Framebuffer {
) -> Framebuffer {
Framebuffer {
image: texture,
size,
format,
@ -72,38 +49,27 @@ impl Framebuffer for Gl3Framebuffer {
is_raw: true,
}
}
fn as_texture(&self, filter: FilterMode, wrap_mode: WrapMode) -> Texture {
Texture {
image: GLImage {
handle: self.image,
format: self.format,
size: self.size,
padded_size: Default::default(),
},
filter,
mip_filter: filter,
wrap_mode,
}
}
fn scale(
&mut self,
fb: &mut Framebuffer,
scaling: Scale2D,
format: ImageFormat,
viewport: &Viewport<Self>,
viewport: &Viewport,
_original: &Texture,
source: &Texture,
) -> Result<Size<u32>> {
if self.is_raw {
return Ok(self.size);
if fb.is_raw {
return Ok(fb.size);
}
let size =
librashader_runtime::scaling::scale(scaling, source.image.size, viewport.output.size);
if self.size != size {
self.size = size;
if fb.size != size {
fb.size = size;
self.init(
Self::init(
fb,
size,
if format == ImageFormat::Unknown {
ImageFormat::R8G8B8A8Unorm
@ -114,10 +80,10 @@ impl Framebuffer for Gl3Framebuffer {
}
Ok(size)
}
fn clear<const REBIND: bool>(&self) {
fn clear<const REBIND: bool>(fb: &Framebuffer) {
unsafe {
if REBIND {
gl::BindFramebuffer(gl::FRAMEBUFFER, self.handle);
gl::BindFramebuffer(gl::FRAMEBUFFER, fb.handle);
}
gl::ColorMask(gl::TRUE, gl::TRUE, gl::TRUE, gl::TRUE);
gl::ClearColor(0.0, 0.0, 0.0, 0.0);
@ -127,14 +93,15 @@ impl Framebuffer for Gl3Framebuffer {
}
}
}
fn copy_from(&mut self, image: &GLImage) -> Result<()> {
fn copy_from(fb: &mut Framebuffer, image: &GLImage) -> Result<()> {
// 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)?;
if image.size != fb.size || image.format != fb.format {
Self::init(
fb,image.size, image.format)?;
}
unsafe {
gl::BindFramebuffer(gl::FRAMEBUFFER, self.handle);
gl::BindFramebuffer(gl::FRAMEBUFFER, fb.handle);
gl::FramebufferTexture2D(
gl::READ_FRAMEBUFFER,
@ -148,7 +115,7 @@ impl Framebuffer for Gl3Framebuffer {
gl::DRAW_FRAMEBUFFER,
gl::COLOR_ATTACHMENT1,
gl::TEXTURE_2D,
self.image,
fb.image,
0,
);
gl::ReadBuffer(gl::COLOR_ATTACHMENT0);
@ -156,12 +123,12 @@ impl Framebuffer for Gl3Framebuffer {
gl::BlitFramebuffer(
0,
0,
self.size.width as GLint,
self.size.height as GLint,
fb.size.width as GLint,
fb.size.height as GLint,
0,
0,
self.size.width as GLint,
self.size.height as GLint,
fb.size.width as GLint,
fb.size.height as GLint,
gl::COLOR_BUFFER_BIT,
gl::NEAREST,
);
@ -188,7 +155,7 @@ impl Framebuffer for Gl3Framebuffer {
gl::FRAMEBUFFER,
gl::COLOR_ATTACHMENT0,
gl::TEXTURE_2D,
self.image,
fb.image,
0,
);
@ -197,18 +164,18 @@ impl Framebuffer for Gl3Framebuffer {
Ok(())
}
fn init(&mut self, mut size: Size<u32>, format: impl Into<GLenum>) -> Result<()> {
if self.is_raw {
fn init(fb: &mut Framebuffer, mut size: Size<u32>, format: impl Into<GLenum>) -> Result<()> {
if fb.is_raw {
return Ok(());
}
self.format = format.into();
self.size = size;
fb.format = format.into();
fb.size = size;
unsafe {
gl::BindFramebuffer(gl::FRAMEBUFFER, self.handle);
gl::BindFramebuffer(gl::FRAMEBUFFER, fb.handle);
// reset the framebuffer image
if self.image != 0 {
if fb.image != 0 {
gl::FramebufferTexture2D(
gl::FRAMEBUFFER,
gl::COLOR_ATTACHMENT0,
@ -216,11 +183,11 @@ impl Framebuffer for Gl3Framebuffer {
0,
0,
);
gl::DeleteTextures(1, &self.image);
gl::DeleteTextures(1, &fb.image);
}
gl::GenTextures(1, &mut self.image);
gl::BindTexture(gl::TEXTURE_2D, self.image);
gl::GenTextures(1, &mut fb.image);
gl::BindTexture(gl::TEXTURE_2D, fb.image);
if size.width == 0 {
size.width = 1;
@ -229,18 +196,18 @@ impl Framebuffer for Gl3Framebuffer {
size.height = 1;
}
self.mip_levels = librashader_runtime::scaling::calc_miplevel(size);
if self.mip_levels > self.max_levels {
self.mip_levels = self.max_levels;
fb.mip_levels = librashader_runtime::scaling::calc_miplevel(size);
if fb.mip_levels > fb.max_levels {
fb.mip_levels = fb.max_levels;
}
if self.mip_levels == 0 {
self.mip_levels = 1;
if fb.mip_levels == 0 {
fb.mip_levels = 1;
}
gl::TexStorage2D(
gl::TEXTURE_2D,
self.mip_levels as GLsizei,
self.format,
fb.mip_levels as GLsizei,
fb.format,
size.width as GLsizei,
size.height as GLsizei,
);
@ -249,7 +216,7 @@ impl Framebuffer for Gl3Framebuffer {
gl::FRAMEBUFFER,
gl::COLOR_ATTACHMENT0,
gl::TEXTURE_2D,
self.image,
fb.image,
0,
);
@ -266,21 +233,21 @@ impl Framebuffer for Gl3Framebuffer {
0,
0,
);
gl::DeleteTextures(1, &self.image);
gl::GenTextures(1, &mut self.image);
gl::BindTexture(gl::TEXTURE_2D, self.image);
gl::DeleteTextures(1, &fb.image);
gl::GenTextures(1, &mut fb.image);
gl::BindTexture(gl::TEXTURE_2D, fb.image);
self.mip_levels = librashader_runtime::scaling::calc_miplevel(size);
if self.mip_levels > self.max_levels {
self.mip_levels = self.max_levels;
fb.mip_levels = librashader_runtime::scaling::calc_miplevel(size);
if fb.mip_levels > fb.max_levels {
fb.mip_levels = fb.max_levels;
}
if self.mip_levels == 0 {
self.mip_levels = 1;
if fb.mip_levels == 0 {
fb.mip_levels = 1;
}
gl::TexStorage2D(
gl::TEXTURE_2D,
self.mip_levels as GLsizei,
fb.mip_levels as GLsizei,
ImageFormat::R8G8B8A8Unorm.into(),
size.width as GLsizei,
size.height as GLsizei,
@ -289,10 +256,10 @@ impl Framebuffer for Gl3Framebuffer {
gl::FRAMEBUFFER,
gl::COLOR_ATTACHMENT0,
gl::TEXTURE_2D,
self.image,
fb.image,
0,
);
// self.init =
// fb.init =
// gl::CheckFramebufferStatus(gl::FRAMEBUFFER) == gl::FRAMEBUFFER_COMPLETE;
}
_ => return Err(FilterChainError::FramebufferInit(status)),
@ -306,16 +273,3 @@ impl Framebuffer for Gl3Framebuffer {
Ok(())
}
}
impl Drop for Gl3Framebuffer {
fn drop(&mut self) {
unsafe {
if self.handle != 0 {
gl::DeleteFramebuffers(1, &self.handle);
}
if self.image != 0 {
gl::DeleteTextures(1, &self.image);
}
}
}
}

View file

@ -10,7 +10,7 @@ use librashader_common::Size;
use crate::filter_chain::FilterChain;
use crate::framebuffer::{GLImage, Viewport};
use crate::gl::gl3::CompatibilityGL;
use crate::gl::{Framebuffer, GLInterface};
use crate::gl::{FramebufferInterface, GLInterface};
const WIDTH: u32 = 900;
const HEIGHT: u32 = 700;
@ -267,7 +267,7 @@ pub fn do_loop(
events: Receiver<(f64, WindowEvent)>,
triangle_program: GLuint,
triangle_vao: GLuint,
filter: &mut FilterChain<CompatibilityGL>,
filter: &mut FilterChain,
) {
let mut framecount = 0;
let mut rendered_framebuffer = 0;
@ -464,7 +464,7 @@ void main()
let (fb_width, fb_height) = window.get_framebuffer_size();
let (vp_width, vp_height) = window.get_size();
let output = <CompatibilityGL as GLInterface>::Framebuffer::new_from_raw(
let output = <CompatibilityGL as GLInterface>::FramebufferInterface::new_from_raw(
output_texture,
output_framebuffer_handle,
gl::RGBA8,

View file

@ -15,7 +15,7 @@ use ubo_ring::*;
pub struct CompatibilityGL;
impl GLInterface for CompatibilityGL {
type Framebuffer = Gl3Framebuffer;
type FramebufferInterface = Gl3Framebuffer;
type UboRing = Gl3UboRing<16>;
type DrawQuad = Gl3DrawQuad;
type LoadLut = Gl3LutLoad;

View file

@ -1,46 +1,23 @@
use crate::error::{FilterChainError, Result};
use crate::framebuffer::{GLImage, Viewport};
use crate::gl::Framebuffer;
use crate::gl::framebuffer::Framebuffer;
use crate::gl::FramebufferInterface;
use crate::texture::Texture;
use gl::types::{GLenum, GLint, GLsizei, GLuint};
use librashader_common::{FilterMode, ImageFormat, Size, WrapMode};
use librashader_presets::Scale2D;
#[derive(Debug)]
pub struct Gl46Framebuffer {
image: GLuint,
handle: GLuint,
size: Size<u32>,
format: GLenum,
max_levels: u32,
levels: u32,
is_raw: bool,
}
pub struct Gl46Framebuffer;
impl Framebuffer for Gl46Framebuffer {
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
}
fn new(max_levels: u32) -> Gl46Framebuffer {
impl FramebufferInterface for Gl46Framebuffer {
fn new(max_levels: u32) -> Framebuffer {
let mut framebuffer = 0;
unsafe {
gl::CreateFramebuffers(1, &mut framebuffer);
}
Gl46Framebuffer {
Framebuffer {
image: 0,
size: Size {
width: 1,
@ -48,7 +25,7 @@ impl Framebuffer for Gl46Framebuffer {
},
format: 0,
max_levels,
levels: 0,
mip_levels: 0,
handle: framebuffer,
is_raw: false,
}
@ -59,49 +36,38 @@ impl Framebuffer for Gl46Framebuffer {
format: GLenum,
size: Size<u32>,
miplevels: u32,
) -> Gl46Framebuffer {
Gl46Framebuffer {
) -> Framebuffer {
Framebuffer {
image: texture,
size,
format,
max_levels: miplevels,
levels: miplevels,
mip_levels: miplevels,
handle,
is_raw: true,
}
}
fn as_texture(&self, filter: FilterMode, wrap_mode: WrapMode) -> Texture {
Texture {
image: GLImage {
handle: self.image,
format: self.format,
size: self.size,
padded_size: Default::default(),
},
filter,
mip_filter: filter,
wrap_mode,
}
}
fn scale(
&mut self,
fb: &mut Framebuffer,
scaling: Scale2D,
format: ImageFormat,
viewport: &Viewport<Self>,
viewport: &Viewport,
_original: &Texture,
source: &Texture,
) -> Result<Size<u32>> {
if self.is_raw {
return Ok(self.size);
if fb.is_raw {
return Ok(fb.size);
}
let size =
librashader_runtime::scaling::scale(scaling, source.image.size, viewport.output.size);
if self.size != size {
self.size = size;
if fb.size != size {
fb.size = size;
self.init(
Self::init(
fb,
size,
if format == ImageFormat::Unknown {
ImageFormat::R8G8B8A8Unorm
@ -112,38 +78,40 @@ impl Framebuffer for Gl46Framebuffer {
}
Ok(size)
}
fn clear<const REBIND: bool>(&self) {
fn clear<const REBIND: bool>(fb: &Framebuffer) {
unsafe {
gl::ClearNamedFramebufferfv(
self.handle,
fb.handle,
gl::COLOR,
0,
[0.0f32, 0.0, 0.0, 0.0].as_ptr().cast(),
);
}
}
fn copy_from(&mut self, image: &GLImage) -> Result<()> {
fn copy_from(fb: &mut Framebuffer, image: &GLImage) -> Result<()> {
// 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)?;
if image.size != fb.size || image.format != fb.format {
Self::init(
fb,
image.size, image.format)?;
}
unsafe {
// gl::NamedFramebufferDrawBuffer(self.handle, gl::COLOR_ATTACHMENT1);
// gl::NamedFramebufferDrawBuffer(fb.handle, gl::COLOR_ATTACHMENT1);
gl::NamedFramebufferReadBuffer(image.handle, gl::COLOR_ATTACHMENT0);
gl::NamedFramebufferDrawBuffer(self.handle, gl::COLOR_ATTACHMENT1);
gl::NamedFramebufferDrawBuffer(fb.handle, gl::COLOR_ATTACHMENT1);
gl::BlitNamedFramebuffer(
image.handle,
self.handle,
fb.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,
fb.size.width as GLint,
fb.size.height as GLint,
gl::COLOR_BUFFER_BIT,
gl::NEAREST,
);
@ -151,21 +119,21 @@ impl Framebuffer for Gl46Framebuffer {
Ok(())
}
fn init(&mut self, mut size: Size<u32>, format: impl Into<GLenum>) -> Result<()> {
if self.is_raw {
fn init(fb: &mut Framebuffer, mut size: Size<u32>, format: impl Into<GLenum>) -> Result<()> {
if fb.is_raw {
return Ok(());
}
self.format = format.into();
self.size = size;
fb.format = format.into();
fb.size = size;
unsafe {
// reset the framebuffer image
if self.image != 0 {
gl::NamedFramebufferTexture(self.handle, gl::COLOR_ATTACHMENT0, 0, 0);
gl::DeleteTextures(1, &self.image);
if fb.image != 0 {
gl::NamedFramebufferTexture(fb.handle, gl::COLOR_ATTACHMENT0, 0, 0);
gl::DeleteTextures(1, &fb.image);
}
gl::CreateTextures(gl::TEXTURE_2D, 1, &mut self.image);
gl::CreateTextures(gl::TEXTURE_2D, 1, &mut fb.image);
if size.width == 0 {
size.width = 1;
@ -174,23 +142,23 @@ impl Framebuffer for Gl46Framebuffer {
size.height = 1;
}
self.levels = librashader_runtime::scaling::calc_miplevel(size);
if self.levels > self.max_levels {
self.levels = self.max_levels;
fb.mip_levels = librashader_runtime::scaling::calc_miplevel(size);
if fb.mip_levels > fb.max_levels {
fb.mip_levels = fb.max_levels;
}
if self.levels == 0 {
self.levels = 1;
if fb.mip_levels == 0 {
fb.mip_levels = 1;
}
gl::TextureStorage2D(
self.image,
self.levels as GLsizei,
self.format,
fb.image,
fb.mip_levels as GLsizei,
fb.format,
size.width as GLsizei,
size.height as GLsizei,
);
gl::NamedFramebufferTexture(self.handle, gl::COLOR_ATTACHMENT0, self.image, 0);
gl::NamedFramebufferTexture(fb.handle, gl::COLOR_ATTACHMENT0, fb.image, 0);
let status = gl::CheckFramebufferStatus(gl::FRAMEBUFFER);
if status != gl::FRAMEBUFFER_COMPLETE {
@ -198,32 +166,27 @@ impl Framebuffer for Gl46Framebuffer {
gl::FRAMEBUFFER_UNSUPPORTED => {
eprintln!("unsupported fbo");
gl::NamedFramebufferTexture(self.handle, gl::COLOR_ATTACHMENT0, 0, 0);
gl::DeleteTextures(1, &self.image);
gl::CreateTextures(gl::TEXTURE_2D, 1, &mut self.image);
gl::NamedFramebufferTexture(fb.handle, gl::COLOR_ATTACHMENT0, 0, 0);
gl::DeleteTextures(1, &fb.image);
gl::CreateTextures(gl::TEXTURE_2D, 1, &mut fb.image);
self.levels = librashader_runtime::scaling::calc_miplevel(size);
if self.levels > self.max_levels {
self.levels = self.max_levels;
fb.mip_levels = librashader_runtime::scaling::calc_miplevel(size);
if fb.mip_levels > fb.max_levels {
fb.mip_levels = fb.max_levels;
}
if self.levels == 0 {
self.levels = 1;
if fb.mip_levels == 0 {
fb.mip_levels = 1;
}
gl::TextureStorage2D(
self.image,
self.levels as GLsizei,
fb.image,
fb.mip_levels as GLsizei,
ImageFormat::R8G8B8A8Unorm.into(),
size.width as GLsizei,
size.height as GLsizei,
);
gl::NamedFramebufferTexture(
self.handle,
gl::COLOR_ATTACHMENT0,
self.image,
0,
);
// self.init =
gl::NamedFramebufferTexture(fb.handle, gl::COLOR_ATTACHMENT0, fb.image, 0);
// fb.init =
// gl::CheckFramebufferStatus(gl::FRAMEBUFFER) == gl::FRAMEBUFFER_COMPLETE;
}
_ => return Err(FilterChainError::FramebufferInit(status)),
@ -233,16 +196,3 @@ impl Framebuffer for Gl46Framebuffer {
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);
}
}
}
}

View file

@ -10,7 +10,7 @@ use librashader_common::Size;
use crate::filter_chain::FilterChain;
use crate::framebuffer::{GLImage, Viewport};
use crate::gl::gl46::DirectStateAccessGL;
use crate::gl::{Framebuffer, GLInterface};
use crate::gl::{FramebufferInterface, GLInterface};
const WIDTH: u32 = 900;
const HEIGHT: u32 = 700;
@ -258,7 +258,7 @@ pub fn do_loop(
events: Receiver<(f64, WindowEvent)>,
triangle_program: GLuint,
triangle_vao: GLuint,
filter: &mut FilterChain<DirectStateAccessGL>,
filter: &mut FilterChain,
) {
let mut framecount = 0;
let mut rendered_framebuffer = 0;
@ -455,7 +455,7 @@ void main()
let (fb_width, fb_height) = window.get_framebuffer_size();
let (vp_width, vp_height) = window.get_size();
let output = <DirectStateAccessGL as GLInterface>::Framebuffer::new_from_raw(
let output = <DirectStateAccessGL as GLInterface>::FramebufferInterface::new_from_raw(
output_texture,
output_framebuffer_handle,
gl::RGBA8,

View file

@ -16,7 +16,7 @@ use ubo_ring::*;
pub struct DirectStateAccessGL;
impl GLInterface for DirectStateAccessGL {
type Framebuffer = Gl46Framebuffer;
type FramebufferInterface = Gl46Framebuffer;
type UboRing = Gl46UboRing<16>;
type DrawQuad = Gl46DrawQuad;
type LoadLut = Gl46LutLoad;

View file

@ -1,3 +1,4 @@
mod framebuffer;
pub(crate) mod gl3;
pub(crate) mod gl46;
@ -6,6 +7,7 @@ use crate::error::Result;
use crate::framebuffer::{GLImage, Viewport};
use crate::samplers::SamplerSet;
use crate::texture::Texture;
pub use framebuffer::Framebuffer;
use gl::types::{GLenum, GLuint};
use librashader_common::{FilterMode, ImageFormat, Size, WrapMode};
use librashader_presets::{Scale2D, TextureConfig};
@ -33,31 +35,26 @@ pub trait UboRing<const SIZE: usize> {
);
}
pub trait Framebuffer {
fn new(max_levels: u32) -> Self;
pub trait FramebufferInterface {
fn new(max_levels: u32) -> Framebuffer;
fn new_from_raw(
texture: GLuint,
handle: GLuint,
format: GLenum,
size: Size<u32>,
miplevels: u32,
) -> Self;
fn as_texture(&self, filter: FilterMode, wrap_mode: WrapMode) -> Texture;
) -> Framebuffer;
fn scale(
&mut self,
fb: &mut Framebuffer,
scaling: Scale2D,
format: ImageFormat,
viewport: &Viewport<Self>,
viewport: &Viewport,
_original: &Texture,
source: &Texture,
) -> Result<Size<u32>>;
fn clear<const REBIND: bool>(&self);
fn copy_from(&mut self, image: &GLImage) -> Result<()>;
fn init(&mut self, size: Size<u32>, format: impl Into<GLenum>) -> Result<()>;
fn handle(&self) -> GLuint;
fn image(&self) -> GLuint;
fn size(&self) -> Size<u32>;
fn format(&self) -> GLenum;
fn clear<const REBIND: bool>(fb: &Framebuffer);
fn copy_from(fb: &mut Framebuffer, image: &GLImage) -> Result<()>;
fn init(fb: &mut Framebuffer, size: Size<u32>, format: impl Into<GLenum>) -> Result<()>;
}
pub trait BindTexture {
@ -65,7 +62,7 @@ pub trait BindTexture {
}
pub trait GLInterface {
type Framebuffer: Framebuffer;
type FramebufferInterface: FramebufferInterface;
type UboRing: UboRing<16>;
type DrawQuad: DrawQuad;
type LoadLut: LoadLut;

View file

@ -1,5 +1,6 @@
#![feature(strict_provenance)]
#![feature(type_alias_impl_trait)]
#![feature(let_chains)]
mod binding;
mod filter_chain;
@ -9,42 +10,29 @@ mod render_target;
mod util;
mod gl;
pub mod options;
mod samplers;
mod texture;
pub mod options;
pub mod error;
pub use filter_chain::FilterChain;
pub use framebuffer::Viewport;
pub mod gl3 {
pub use super::framebuffer::GLImage;
pub type FilterChain = super::filter_chain::FilterChain<super::gl::gl3::CompatibilityGL>;
pub type Viewport<'a> = super::framebuffer::Viewport<
'a,
<super::gl::gl3::CompatibilityGL as super::gl::GLInterface>::Framebuffer,
>;
}
pub mod gl46 {
pub use super::framebuffer::GLImage;
pub type FilterChain = super::filter_chain::FilterChain<super::gl::gl46::DirectStateAccessGL>;
pub type Viewport<'a> = super::framebuffer::Viewport<
'a,
<super::gl::gl46::DirectStateAccessGL as super::gl::GLInterface>::Framebuffer,
>;
}
pub use framebuffer::GLImage;
#[cfg(test)]
mod tests {
use super::*;
use crate::filter_chain::FilterChain;
use crate::options::FilterChainOptions;
#[test]
fn triangle_gl() {
let (glfw, window, events, shader, vao) = gl::gl3::hello_triangle::setup();
let mut filter =
FilterChain::load_from_path("../test/slang-shaders/vhs/VHSPro.slangp", None)
FilterChain::load_from_path("../test/slang-shaders/vhs/VHSPro.slangp", Some(&FilterChainOptions {
gl_version: 0,
use_dsa: false,
}))
// FilterChain::load_from_path("../test/slang-shaders/bezel/Mega_Bezel/Presets/MBZ__0__SMOOTH-ADV.slangp", None)
.unwrap();
gl::gl3::hello_triangle::do_loop(glfw, window, events, shader, vao, &mut filter);
@ -54,7 +42,10 @@ mod tests {
fn triangle_gl46() {
let (glfw, window, events, shader, vao) = gl::gl46::hello_triangle::setup();
let mut filter =
FilterChain::load_from_path("../test/slang-shaders/vhs/VHSPro.slangp", None)
FilterChain::load_from_path("../test/slang-shaders/vhs/VHSPro.slangp", Some(&FilterChainOptions {
gl_version: 0,
use_dsa: true,
}))
// FilterChain::load_from_path("../test/slang-shaders/bezel/Mega_Bezel/Presets/MBZ__0__SMOOTH-ADV.slangp", None)
.unwrap();
gl::gl46::hello_triangle::do_loop(glfw, window, events, shader, vao, &mut filter);

View file

@ -8,4 +8,5 @@ pub struct FrameOptions {
#[derive(Debug, Clone)]
pub struct FilterChainOptions {
pub gl_version: u16,
pub use_dsa: bool
}

View file

@ -1,5 +1,5 @@
use crate::framebuffer::Viewport;
use crate::gl::Framebuffer;
use crate::gl::{Framebuffer, FramebufferInterface};
#[rustfmt::skip]
static DEFAULT_MVP: &[f32; 16] = &[
@ -10,15 +10,15 @@ static DEFAULT_MVP: &[f32; 16] = &[
];
#[derive(Debug, Copy, Clone)]
pub(crate) struct RenderTarget<'a, T: Framebuffer> {
pub(crate) struct RenderTarget<'a> {
pub mvp: &'a [f32; 16],
pub framebuffer: &'a T,
pub framebuffer: &'a Framebuffer,
pub x: i32,
pub y: i32,
}
impl<'a, T: Framebuffer> RenderTarget<'a, T> {
pub fn new(backbuffer: &'a T, mvp: Option<&'a [f32; 16]>, x: i32, y: i32) -> Self {
impl<'a> RenderTarget<'a> {
pub fn new(backbuffer: &'a Framebuffer, mvp: Option<&'a [f32; 16]>, x: i32, y: i32) -> Self {
if let Some(mvp) = mvp {
RenderTarget {
framebuffer: backbuffer,
@ -37,8 +37,8 @@ impl<'a, T: Framebuffer> RenderTarget<'a, T> {
}
}
impl<'a, T: Framebuffer> From<&Viewport<'a, T>> for RenderTarget<'a, T> {
fn from(value: &Viewport<'a, T>) -> Self {
impl<'a> From<&Viewport<'a>> for RenderTarget<'a> {
fn from(value: &Viewport<'a>) -> Self {
RenderTarget::new(value.output, value.mvp, value.x, value.y)
}
}

View file

@ -101,6 +101,7 @@ pub fn gl_get_version() -> GlVersion {
pub fn gl_u16_to_version(version: u16) -> GlVersion {
match version {
0 => gl_get_version(),
300 => GlVersion::V1_30,
310 => GlVersion::V1_40,
320 => GlVersion::V1_50,

View file

@ -31,18 +31,7 @@ pub mod targets {
/// Shader runtime for OpenGL.
pub mod runtime {
pub use librashader_runtime_gl::error;
pub use librashader_runtime_gl::options::*;
pub use librashader_runtime_gl::FilterChain;
pub use librashader_runtime_gl::Viewport;
pub mod gl3 {
pub use librashader_runtime_gl::gl3::*;
}
pub mod gl46 {
pub use librashader_runtime_gl::gl46::*;
}
pub use librashader_runtime_gl::*;
}
}