gl: abstract away gl3 and dsa

This commit is contained in:
chyyran 2022-11-29 23:56:10 -05:00
parent c4f1abd411
commit 538672e355
27 changed files with 1206 additions and 553 deletions

2
Cargo.lock generated
View file

@ -472,9 +472,11 @@ name = "librashader-runtime"
version = "0.1.0"
dependencies = [
"bytemuck",
"librashader-common",
"librashader-preprocess",
"librashader-presets",
"librashader-reflect",
"num-traits",
"rustc-hash",
]

View file

@ -47,43 +47,7 @@ impl OwnedFramebuffer {
return Ok(self.size);
}
let width;
let height;
match scaling.x {
Scaling {
scale_type: ScaleType::Input,
factor,
} => width = source.view.size.width * factor,
Scaling {
scale_type: ScaleType::Absolute,
factor,
} => width = factor.into(),
Scaling {
scale_type: ScaleType::Viewport,
factor,
} => width = viewport_size.width * factor,
};
match scaling.y {
Scaling {
scale_type: ScaleType::Input,
factor,
} => height = source.view.size.height * factor,
Scaling {
scale_type: ScaleType::Absolute,
factor,
} => height = factor.into(),
Scaling {
scale_type: ScaleType::Viewport,
factor,
} => height = viewport_size.height * factor,
};
let size = Size {
width: width.round() as u32,
height: height.round() as u32,
};
let size = librashader_runtime::scaling::scale(scaling, source.view.size, *viewport_size);
if self.size != size {
self.size = size;

View file

@ -166,13 +166,3 @@ pub fn d3d11_create_input_layout(device: &ID3D11Device, desc: &[D3D11_INPUT_ELEM
// todo: d3d11.c 2097
pub type Result<T> = std::result::Result<T, Box<dyn Error>>;
pub fn calc_miplevel(size: Size<u32>) -> u32 {
let mut size = std::cmp::max(size.width, size.height);
let mut levels = 0;
while size != 0 {
levels += 1;
size >>= 1;
}
levels
}

View file

@ -1,7 +1,8 @@
use crate::binding::{UniformLocation, VariableLocation};
use crate::filter_pass::FilterPass;
use crate::framebuffer::{Framebuffer, GlImage, Viewport};
use crate::quad_render::DrawQuad;
use crate::framebuffer::{GlImage, Viewport};
use crate::gl::gl3::Gl3Framebuffer;
use crate::gl::gl3::{Gl3DrawQuad, Gl3LutLoad, Gl3UboRing};
use crate::render_target::RenderTarget;
use crate::util;
use crate::util::{gl_get_version, gl_u16_to_version, InlineRingBuffer};
@ -26,14 +27,15 @@ use crate::options::{FilterChainOptions, FrameOptions};
use crate::samplers::SamplerSet;
use crate::texture::Texture;
use crate::binding::BufferStorage;
use crate::gl::{DrawQuad, Framebuffer, LoadLut, UboRing};
pub struct FilterChain {
passes: Box<[FilterPass]>,
common: FilterCommon,
pub(crate) draw_quad: DrawQuad,
output_framebuffers: Box<[Framebuffer]>,
feedback_framebuffers: Box<[Framebuffer]>,
history_framebuffers: VecDeque<Framebuffer>,
pub(crate) draw_quad: Gl3DrawQuad,
output_framebuffers: Box<[Gl3Framebuffer]>,
feedback_framebuffers: Box<[Gl3Framebuffer]>,
history_framebuffers: VecDeque<Gl3Framebuffer>,
}
pub struct FilterCommon {
@ -109,24 +111,24 @@ impl FilterChain {
// initialize output framebuffers
let mut output_framebuffers = Vec::new();
output_framebuffers.resize_with(filters.len(), || Framebuffer::new(1));
output_framebuffers.resize_with(filters.len(), || Gl3Framebuffer::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(), || Gl3Framebuffer::new(1));
let mut feedback_textures = Vec::new();
feedback_textures.resize_with(filters.len(), Texture::default);
// load luts
let luts = FilterChain::load_luts(&preset.textures)?;
let luts = Gl3LutLoad::load_luts(&preset.textures)?;
let (history_framebuffers, history_textures) =
FilterChain::init_history(&filters, default_filter, default_wrap);
// create vertex objects
let draw_quad = DrawQuad::new();
let draw_quad = Gl3DrawQuad::new();
Ok(FilterChain {
passes: filters,
@ -207,79 +209,6 @@ impl FilterChain {
Ok((passes, semantics))
}
fn load_luts(textures: &[TextureConfig]) -> Result<FxHashMap<usize, Texture>> {
let mut luts = FxHashMap::default();
let pixel_unpack = unsafe {
let mut binding = 0;
gl::GetIntegerv(gl::PIXEL_UNPACK_BUFFER_BINDING, &mut binding);
binding
};
for (index, texture) in textures.iter().enumerate() {
let image = Image::load(&texture.path)?;
let levels = if texture.mipmap {
util::calc_miplevel(image.size)
} else {
1u32
};
let mut handle = 0;
unsafe {
gl::GenTextures(1, &mut handle);
gl::BindTexture(gl::TEXTURE_2D, handle);
gl::TexStorage2D(
gl::TEXTURE_2D,
levels as GLsizei,
gl::RGBA8,
image.size.width as GLsizei,
image.size.height as GLsizei,
);
gl::PixelStorei(gl::UNPACK_ROW_LENGTH, 0);
gl::PixelStorei(gl::UNPACK_ALIGNMENT, 4);
gl::BindBuffer(gl::PIXEL_UNPACK_BUFFER, 0);
gl::TexSubImage2D(
gl::TEXTURE_2D,
0,
0,
0,
image.size.width as GLsizei,
image.size.height as GLsizei,
gl::RGBA,
gl::UNSIGNED_BYTE,
image.bytes.as_ptr().cast(),
);
let mipmap = levels > 1;
if mipmap {
gl::GenerateMipmap(gl::TEXTURE_2D);
}
gl::BindTexture(gl::TEXTURE_2D, 0);
}
luts.insert(
index,
Texture {
image: GlImage {
handle,
format: gl::RGBA8,
size: image.size,
padded_size: Size::default(),
},
filter: texture.filter_mode,
mip_filter: texture.filter_mode,
wrap_mode: texture.wrap_mode,
},
);
}
unsafe {
gl::BindBuffer(gl::PIXEL_UNPACK_BUFFER, pixel_unpack as GLuint);
};
Ok(luts)
}
fn init_passes(
version: GlVersion,
passes: Vec<ShaderPassMeta>,
@ -352,21 +281,7 @@ impl FilterChain {
};
let ubo_ring = if let Some(ubo) = &reflection.ubo {
let size = ubo.size;
let mut ring: InlineRingBuffer<GLuint, 16> = InlineRingBuffer::new();
unsafe {
gl::GenBuffers(16, ring.items_mut().as_mut_ptr());
for buffer in ring.items() {
gl::BindBuffer(gl::UNIFORM_BUFFER, *buffer);
gl::BufferData(
gl::UNIFORM_BUFFER,
size as GLsizeiptr,
std::ptr::null(),
gl::STREAM_DRAW,
);
}
gl::BindBuffer(gl::UNIFORM_BUFFER, 0);
}
let ring = Gl3UboRing::new(ubo.size);
Some(ring)
} else {
None
@ -445,7 +360,7 @@ impl FilterChain {
filters: &[FilterPass],
filter: FilterMode,
wrap_mode: WrapMode,
) -> (VecDeque<Framebuffer>, Box<[Texture]>) {
) -> (VecDeque<Gl3Framebuffer>, Box<[Texture]>) {
let mut required_images = 0;
for pass in filters {
@ -479,7 +394,7 @@ impl FilterChain {
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, || Gl3Framebuffer::new(1));
let mut history_textures = Vec::new();
history_textures.resize_with(required_images, || Texture {
@ -516,7 +431,7 @@ impl FilterChain {
if let Some(options) = options {
if options.clear_history {
for framebuffer in &self.history_framebuffers {
framebuffer.clear()
framebuffer.clear::<true>()
}
}
}
@ -527,7 +442,7 @@ impl FilterChain {
// do not need to rebind FBO 0 here since first `draw` will
// bind automatically.
self.draw_quad.bind_vao();
self.draw_quad.bind_vertices();
let filter = passes[0].config.filter;
let wrap_mode = passes[0].config.wrap_mode;
@ -641,7 +556,7 @@ impl FilterChain {
self.push_history(input)?;
self.draw_quad.unbind_vao();
self.draw_quad.unbind_vertices();
Ok(())
}

View file

@ -14,6 +14,8 @@ use librashader_runtime::uniforms::UniformStorage;
use crate::binding::{BufferStorage, GlUniformBinder, UniformLocation, VariableLocation};
use crate::filter_chain::FilterCommon;
use crate::framebuffer::Viewport;
use crate::gl::gl3::{Gl3BindTexture, Gl3UboRing};
use crate::gl::{BindTexture, Framebuffer, UboRing};
use crate::render_target::RenderTarget;
use crate::samplers::SamplerSet;
use crate::texture::Texture;
@ -25,7 +27,7 @@ pub struct FilterPass {
pub compiled: ShaderCompilerOutput<String, GlslangGlslContext>,
pub program: GLuint,
pub ubo_location: UniformLocation<GLuint>,
pub ubo_ring: Option<InlineRingBuffer<GLuint, 16>>,
pub ubo_ring: Option<Gl3UboRing<16>>,
pub(crate) uniform_storage: BufferStorage,
pub uniform_bindings: FxHashMap<UniformBinding, (VariableLocation, MemberOffset)>,
pub source: ShaderSource,
@ -34,7 +36,7 @@ pub struct FilterPass {
impl FilterPass {
// todo: fix rendertargets (i.e. non-final pass is internal, final pass is user provided fbo)
pub fn draw(
pub(crate) fn draw(
&mut self,
pass_index: usize,
parent: &FilterCommon,
@ -68,36 +70,14 @@ impl FilterPass {
&& self.ubo_location.fragment != gl::INVALID_INDEX
{
if let (Some(ubo), Some(ring)) = (&self.reflection.ubo, &mut self.ubo_ring) {
let size = ubo.size;
let buffer = ring.current();
unsafe {
gl::BindBuffer(gl::UNIFORM_BUFFER, *buffer);
gl::BufferSubData(
gl::UNIFORM_BUFFER,
0,
size as GLsizeiptr,
self.uniform_storage.ubo.as_ptr().cast(),
);
gl::BindBuffer(gl::UNIFORM_BUFFER, 0);
if self.ubo_location.vertex != gl::INVALID_INDEX {
gl::BindBufferBase(gl::UNIFORM_BUFFER, self.ubo_location.vertex, *buffer);
}
if self.ubo_location.fragment != gl::INVALID_INDEX {
gl::BindBufferBase(gl::UNIFORM_BUFFER, self.ubo_location.fragment, *buffer);
}
}
ring.next()
ring.bind_for_frame(ubo, &self.ubo_location, &self.uniform_storage)
}
}
unsafe {
// can't use framebuffer.clear because it will unbind.
gl::ColorMask(gl::TRUE, gl::TRUE, gl::TRUE, gl::TRUE);
gl::ClearColor(0.0f32, 0.0f32, 0.0f32, 0.0f32);
gl::Clear(gl::COLOR_BUFFER_BIT);
//
framebuffer.clear::<false>();
gl::Viewport(
output.x,
output.y,
@ -122,14 +102,7 @@ impl FilterPass {
}
fn bind_texture(samplers: &SamplerSet, binding: &TextureBinding, texture: &Texture) {
unsafe {
// eprintln!("setting {} to texunit {}", texture.image.handle, binding.binding);
gl::ActiveTexture(gl::TEXTURE0 + binding.binding);
gl::BindTexture(gl::TEXTURE_2D, texture.image.handle);
gl::BindSampler(binding.binding,
samplers.get(texture.wrap_mode, texture.filter, texture.mip_filter));
}
Gl3BindTexture::bind_texture(samplers, binding, texture)
}
}

View file

@ -5,347 +5,14 @@ use librashader_common::{FilterMode, ImageFormat, Size, WrapMode};
use librashader_presets::{Scale2D, ScaleType, Scaling};
use crate::error::FilterChainError;
use crate::error::Result;
#[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,
is_raw: bool,
}
impl Framebuffer {
pub fn new(max_levels: u32) -> Framebuffer {
let mut framebuffer = 0;
unsafe {
gl::GenFramebuffers(1, &mut framebuffer);
gl::BindFramebuffer(gl::FRAMEBUFFER, framebuffer);
gl::BindFramebuffer(gl::FRAMEBUFFER, 0);
}
Framebuffer {
image: 0,
size: Size {
width: 1,
height: 1,
},
format: 0,
max_levels,
mip_levels: 0,
handle: framebuffer,
is_raw: false,
}
}
pub fn new_from_raw(
texture: GLuint,
handle: GLuint,
format: GLenum,
size: Size<u32>,
miplevels: u32,
) -> Framebuffer {
Framebuffer {
image: texture,
size,
format,
max_levels: miplevels,
mip_levels: miplevels,
handle,
is_raw: true,
}
}
pub(crate) 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,
}
}
pub(crate) fn scale(
&mut self,
scaling: Scale2D,
format: ImageFormat,
viewport: &Viewport,
_original: &Texture,
source: &Texture,
) -> Result<Size<u32>> {
if self.is_raw {
return Ok(self.size);
}
let width;
let height;
match scaling.x {
Scaling {
scale_type: ScaleType::Input,
factor,
} => width = source.image.size.width * factor,
Scaling {
scale_type: ScaleType::Absolute,
factor,
} => width = factor.into(),
Scaling {
scale_type: ScaleType::Viewport,
factor,
} => width = viewport.output.size.width * factor,
};
match scaling.y {
Scaling {
scale_type: ScaleType::Input,
factor,
} => height = source.image.size.height * factor,
Scaling {
scale_type: ScaleType::Absolute,
factor,
} => height = factor.into(),
Scaling {
scale_type: ScaleType::Viewport,
factor,
} => height = viewport.output.size.height * factor,
};
let size = Size {
width: width.round() as u32,
height: height.round() as u32,
};
if self.size != size {
self.size = size;
self.init(
size,
if format == ImageFormat::Unknown {
ImageFormat::R8G8B8A8Unorm
} else {
format
},
)?;
}
Ok(size)
}
pub(crate) fn clear(&self) {
unsafe {
gl::BindFramebuffer(gl::FRAMEBUFFER, self.handle);
gl::ColorMask(gl::TRUE, gl::TRUE, gl::TRUE, gl::TRUE);
gl::ClearColor(0.0, 0.0, 0.0, 0.0);
gl::Clear(gl::COLOR_BUFFER_BIT);
gl::BindFramebuffer(gl::FRAMEBUFFER, 0);
}
}
pub(crate) fn copy_from(&mut self, 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)?;
}
unsafe {
gl::BindFramebuffer(gl::FRAMEBUFFER, self.handle);
gl::FramebufferTexture2D(
gl::READ_FRAMEBUFFER,
gl::COLOR_ATTACHMENT0,
gl::TEXTURE_2D,
image.handle,
0,
);
gl::FramebufferTexture2D(
gl::DRAW_FRAMEBUFFER,
gl::COLOR_ATTACHMENT1,
gl::TEXTURE_2D,
self.image,
0,
);
gl::ReadBuffer(gl::COLOR_ATTACHMENT0);
gl::DrawBuffer(gl::COLOR_ATTACHMENT1);
gl::BlitFramebuffer(
0,
0,
self.size.width as GLint,
self.size.height as GLint,
0,
0,
self.size.width as GLint,
self.size.height as GLint,
gl::COLOR_BUFFER_BIT,
gl::NEAREST,
);
// cleanup after ourselves.
gl::FramebufferTexture2D(
gl::READ_FRAMEBUFFER,
gl::COLOR_ATTACHMENT0,
gl::TEXTURE_2D,
0,
0,
);
gl::FramebufferTexture2D(
gl::DRAW_FRAMEBUFFER,
gl::COLOR_ATTACHMENT1,
gl::TEXTURE_2D,
0,
0,
);
// set this back to color_attachment 0
gl::FramebufferTexture2D(
gl::FRAMEBUFFER,
gl::COLOR_ATTACHMENT0,
gl::TEXTURE_2D,
self.image,
0,
);
gl::BindFramebuffer(gl::FRAMEBUFFER, 0);
}
Ok(())
}
pub(crate) fn init(&mut self, mut size: Size<u32>, format: impl Into<GLenum>) -> Result<()> {
if self.is_raw {
return Ok(());
}
self.format = format.into();
self.size = size;
unsafe {
gl::BindFramebuffer(gl::FRAMEBUFFER, self.handle);
// reset the framebuffer image
if self.image != 0 {
gl::FramebufferTexture2D(
gl::FRAMEBUFFER,
gl::COLOR_ATTACHMENT0,
gl::TEXTURE_2D,
0,
0,
);
gl::DeleteTextures(1, &self.image);
}
gl::GenTextures(1, &mut self.image);
gl::BindTexture(gl::TEXTURE_2D, self.image);
if size.width == 0 {
size.width = 1;
}
if size.height == 0 {
size.height = 1;
}
self.mip_levels = util::calc_miplevel(size);
if self.mip_levels > self.max_levels {
self.mip_levels = self.max_levels;
}
if self.mip_levels == 0 {
self.mip_levels = 1;
}
gl::TexStorage2D(
gl::TEXTURE_2D,
self.mip_levels as GLsizei,
self.format,
size.width as GLsizei,
size.height as GLsizei,
);
gl::FramebufferTexture2D(
gl::FRAMEBUFFER,
gl::COLOR_ATTACHMENT0,
gl::TEXTURE_2D,
self.image,
0,
);
let status = gl::CheckFramebufferStatus(gl::FRAMEBUFFER);
if status != gl::FRAMEBUFFER_COMPLETE {
match status {
gl::FRAMEBUFFER_UNSUPPORTED => {
eprintln!("unsupported fbo");
gl::FramebufferTexture2D(
gl::FRAMEBUFFER,
gl::COLOR_ATTACHMENT0,
gl::TEXTURE_2D,
0,
0,
);
gl::DeleteTextures(1, &self.image);
gl::GenTextures(1, &mut self.image);
gl::BindTexture(gl::TEXTURE_2D, self.image);
self.mip_levels = util::calc_miplevel(size);
if self.mip_levels > self.max_levels {
self.mip_levels = self.max_levels;
}
if self.mip_levels == 0 {
self.mip_levels = 1;
}
gl::TexStorage2D(
gl::TEXTURE_2D,
self.mip_levels as GLsizei,
ImageFormat::R8G8B8A8Unorm.into(),
size.width as GLsizei,
size.height as GLsizei,
);
gl::FramebufferTexture2D(
gl::FRAMEBUFFER,
gl::COLOR_ATTACHMENT0,
gl::TEXTURE_2D,
self.image,
0,
);
// self.init =
// gl::CheckFramebufferStatus(gl::FRAMEBUFFER) == gl::FRAMEBUFFER_COMPLETE;
}
_ => return Err(FilterChainError::FramebufferInit(status))
}
}
gl::BindFramebuffer(gl::FRAMEBUFFER, 0);
gl::BindTexture(gl::TEXTURE_2D, 0);
}
Ok(())
}
}
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);
}
}
}
}
use crate::gl::Framebuffer;
use crate::gl::gl3::Gl3Framebuffer;
#[derive(Debug, Copy, Clone)]
pub struct Viewport<'a> {
pub x: i32,
pub y: i32,
pub output: &'a Framebuffer,
pub output: &'a Gl3Framebuffer,
pub mvp: Option<&'a [f32; 16]>,
}

View file

@ -1,4 +1,5 @@
use gl::types::{GLsizei, GLsizeiptr, GLuint};
use crate::gl::DrawQuad;
#[rustfmt::skip]
static QUAD_VBO_DATA: &[f32; 16] = &[
@ -8,13 +9,13 @@ static QUAD_VBO_DATA: &[f32; 16] = &[
1.0f32, 1.0f32, 1.0f32, 1.0f32,
];
pub struct DrawQuad {
pub struct Gl3DrawQuad {
vbo: GLuint,
vao: GLuint,
}
impl DrawQuad {
pub fn new() -> DrawQuad {
impl DrawQuad for Gl3DrawQuad {
fn new() -> Gl3DrawQuad {
let mut vbo = 0;
let mut vao = 0;
@ -31,11 +32,10 @@ impl DrawQuad {
gl::GenVertexArrays(1, &mut vao);
}
DrawQuad { vbo, vao }
Self { vbo, vao }
}
pub fn bind_vao(&self) {
fn bind_vertices(&self) {
unsafe {
gl::BindVertexArray(self.vao);
gl::EnableVertexAttribArray(0);
@ -65,7 +65,7 @@ impl DrawQuad {
}
}
pub fn unbind_vao(&self) {
fn unbind_vertices(&self) {
unsafe {
gl::BindVertexArray(0);
gl::BindBuffer(gl::ARRAY_BUFFER, 0);
@ -74,3 +74,4 @@ impl DrawQuad {
}
}
}

View file

@ -0,0 +1,305 @@
use gl::types::{GLenum, GLint, GLsizei, GLuint};
use librashader_common::{FilterMode, ImageFormat, Size, WrapMode};
use librashader_presets::Scale2D;
use crate::{GlImage, Viewport};
use crate::error::{FilterChainError, Result};
use crate::gl::Framebuffer;
use crate::texture::Texture;
#[derive(Debug)]
pub struct Gl3Framebuffer {
pub image: GLuint,
pub handle: GLuint,
pub size: Size<u32>,
pub format: GLenum,
pub max_levels: u32,
pub mip_levels: u32,
is_raw: bool,
}
impl Framebuffer for Gl3Framebuffer {
fn new(max_levels: u32) -> Gl3Framebuffer {
let mut framebuffer = 0;
unsafe {
gl::GenFramebuffers(1, &mut framebuffer);
gl::BindFramebuffer(gl::FRAMEBUFFER, framebuffer);
gl::BindFramebuffer(gl::FRAMEBUFFER, 0);
}
Gl3Framebuffer {
image: 0,
size: Size {
width: 1,
height: 1,
},
format: 0,
max_levels,
mip_levels: 0,
handle: framebuffer,
is_raw: false,
}
}
fn new_from_raw(
texture: GLuint,
handle: GLuint,
format: GLenum,
size: Size<u32>,
miplevels: u32,
) -> Gl3Framebuffer {
Gl3Framebuffer {
image: texture,
size,
format,
max_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,
scaling: Scale2D,
format: ImageFormat,
viewport: &Viewport,
_original: &Texture,
source: &Texture,
) -> Result<Size<u32>> {
if self.is_raw {
return Ok(self.size);
}
let size = librashader_runtime::scaling::scale(scaling, source.image.size, viewport.output.size);
if self.size != size {
self.size = size;
self.init(
size,
if format == ImageFormat::Unknown {
ImageFormat::R8G8B8A8Unorm
} else {
format
},
)?;
}
Ok(size)
}
fn clear<const REBIND: bool>(&self) {
unsafe {
if REBIND {
gl::BindFramebuffer(gl::FRAMEBUFFER, self.handle);
}
gl::ColorMask(gl::TRUE, gl::TRUE, gl::TRUE, gl::TRUE);
gl::ClearColor(0.0, 0.0, 0.0, 0.0);
gl::Clear(gl::COLOR_BUFFER_BIT);
if REBIND {
gl::BindFramebuffer(gl::FRAMEBUFFER, 0);
}
}
}
fn copy_from(&mut self, 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)?;
}
unsafe {
gl::BindFramebuffer(gl::FRAMEBUFFER, self.handle);
gl::FramebufferTexture2D(
gl::READ_FRAMEBUFFER,
gl::COLOR_ATTACHMENT0,
gl::TEXTURE_2D,
image.handle,
0,
);
gl::FramebufferTexture2D(
gl::DRAW_FRAMEBUFFER,
gl::COLOR_ATTACHMENT1,
gl::TEXTURE_2D,
self.image,
0,
);
gl::ReadBuffer(gl::COLOR_ATTACHMENT0);
gl::DrawBuffer(gl::COLOR_ATTACHMENT1);
gl::BlitFramebuffer(
0,
0,
self.size.width as GLint,
self.size.height as GLint,
0,
0,
self.size.width as GLint,
self.size.height as GLint,
gl::COLOR_BUFFER_BIT,
gl::NEAREST,
);
// cleanup after ourselves.
gl::FramebufferTexture2D(
gl::READ_FRAMEBUFFER,
gl::COLOR_ATTACHMENT0,
gl::TEXTURE_2D,
0,
0,
);
gl::FramebufferTexture2D(
gl::DRAW_FRAMEBUFFER,
gl::COLOR_ATTACHMENT1,
gl::TEXTURE_2D,
0,
0,
);
// set this back to color_attachment 0
gl::FramebufferTexture2D(
gl::FRAMEBUFFER,
gl::COLOR_ATTACHMENT0,
gl::TEXTURE_2D,
self.image,
0,
);
gl::BindFramebuffer(gl::FRAMEBUFFER, 0);
}
Ok(())
}
fn init(&mut self, mut size: Size<u32>, format: impl Into<GLenum>) -> Result<()> {
if self.is_raw {
return Ok(());
}
self.format = format.into();
self.size = size;
unsafe {
gl::BindFramebuffer(gl::FRAMEBUFFER, self.handle);
// reset the framebuffer image
if self.image != 0 {
gl::FramebufferTexture2D(
gl::FRAMEBUFFER,
gl::COLOR_ATTACHMENT0,
gl::TEXTURE_2D,
0,
0,
);
gl::DeleteTextures(1, &self.image);
}
gl::GenTextures(1, &mut self.image);
gl::BindTexture(gl::TEXTURE_2D, self.image);
if size.width == 0 {
size.width = 1;
}
if size.height == 0 {
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;
}
if self.mip_levels == 0 {
self.mip_levels = 1;
}
gl::TexStorage2D(
gl::TEXTURE_2D,
self.mip_levels as GLsizei,
self.format,
size.width as GLsizei,
size.height as GLsizei,
);
gl::FramebufferTexture2D(
gl::FRAMEBUFFER,
gl::COLOR_ATTACHMENT0,
gl::TEXTURE_2D,
self.image,
0,
);
let status = gl::CheckFramebufferStatus(gl::FRAMEBUFFER);
if status != gl::FRAMEBUFFER_COMPLETE {
match status {
gl::FRAMEBUFFER_UNSUPPORTED => {
eprintln!("unsupported fbo");
gl::FramebufferTexture2D(
gl::FRAMEBUFFER,
gl::COLOR_ATTACHMENT0,
gl::TEXTURE_2D,
0,
0,
);
gl::DeleteTextures(1, &self.image);
gl::GenTextures(1, &mut self.image);
gl::BindTexture(gl::TEXTURE_2D, self.image);
self.mip_levels = librashader_runtime::scaling::calc_miplevel(size);
if self.mip_levels > self.max_levels {
self.mip_levels = self.max_levels;
}
if self.mip_levels == 0 {
self.mip_levels = 1;
}
gl::TexStorage2D(
gl::TEXTURE_2D,
self.mip_levels as GLsizei,
ImageFormat::R8G8B8A8Unorm.into(),
size.width as GLsizei,
size.height as GLsizei,
);
gl::FramebufferTexture2D(
gl::FRAMEBUFFER,
gl::COLOR_ATTACHMENT0,
gl::TEXTURE_2D,
self.image,
0,
);
// self.init =
// gl::CheckFramebufferStatus(gl::FRAMEBUFFER) == gl::FRAMEBUFFER_COMPLETE;
}
_ => return Err(FilterChainError::FramebufferInit(status))
}
}
gl::BindFramebuffer(gl::FRAMEBUFFER, 0);
gl::BindTexture(gl::TEXTURE_2D, 0);
}
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

@ -0,0 +1,85 @@
use gl::types::{GLsizei, GLuint};
use rustc_hash::FxHashMap;
use librashader_common::image::Image;
use librashader_common::Size;
use librashader_presets::TextureConfig;
use crate::gl::LoadLut;
use crate::{GlImage, util};
use crate::texture::Texture;
use crate::error::Result;
pub struct Gl3LutLoad;
impl LoadLut for Gl3LutLoad {
fn load_luts(textures: &[TextureConfig]) -> Result<FxHashMap<usize, Texture>> {
let mut luts = FxHashMap::default();
let pixel_unpack = unsafe {
let mut binding = 0;
gl::GetIntegerv(gl::PIXEL_UNPACK_BUFFER_BINDING, &mut binding);
binding
};
for (index, texture) in textures.iter().enumerate() {
let image = Image::load(&texture.path)?;
let levels = if texture.mipmap {
librashader_runtime::scaling::calc_miplevel(image.size)
} else {
1u32
};
let mut handle = 0;
unsafe {
gl::GenTextures(1, &mut handle);
gl::BindTexture(gl::TEXTURE_2D, handle);
gl::TexStorage2D(
gl::TEXTURE_2D,
levels as GLsizei,
gl::RGBA8,
image.size.width as GLsizei,
image.size.height as GLsizei,
);
gl::PixelStorei(gl::UNPACK_ROW_LENGTH, 0);
gl::PixelStorei(gl::UNPACK_ALIGNMENT, 4);
gl::BindBuffer(gl::PIXEL_UNPACK_BUFFER, 0);
gl::TexSubImage2D(
gl::TEXTURE_2D,
0,
0,
0,
image.size.width as GLsizei,
image.size.height as GLsizei,
gl::RGBA,
gl::UNSIGNED_BYTE,
image.bytes.as_ptr().cast(),
);
let mipmap = levels > 1;
if mipmap {
gl::GenerateMipmap(gl::TEXTURE_2D);
}
gl::BindTexture(gl::TEXTURE_2D, 0);
}
luts.insert(
index,
Texture {
image: GlImage {
handle,
format: gl::RGBA8,
size: image.size,
padded_size: Size::default(),
},
filter: texture.filter_mode,
mip_filter: texture.filter_mode,
wrap_mode: texture.wrap_mode,
},
);
}
unsafe {
gl::BindBuffer(gl::PIXEL_UNPACK_BUFFER, pixel_unpack as GLuint);
};
Ok(luts)
}
}

View file

@ -0,0 +1,11 @@
mod lut_load;
mod draw_quad;
mod ubo_ring;
mod framebuffer;
mod texture_bind;
pub use lut_load::*;
pub use draw_quad::*;
pub use ubo_ring::*;
pub use framebuffer::*;
pub use texture_bind::*;

View file

@ -0,0 +1,19 @@
use librashader_reflect::reflect::semantics::TextureBinding;
use crate::gl::BindTexture;
use crate::samplers::SamplerSet;
use crate::texture::Texture;
pub struct Gl3BindTexture;
impl BindTexture for Gl3BindTexture {
fn bind_texture(samplers: &SamplerSet, binding: &TextureBinding, texture: &Texture) {
unsafe {
// eprintln!("setting {} to texunit {}", texture.image.handle, binding.binding);
gl::ActiveTexture(gl::TEXTURE0 + binding.binding);
gl::BindTexture(gl::TEXTURE_2D, texture.image.handle);
gl::BindSampler(binding.binding,
samplers.get(texture.wrap_mode, texture.filter, texture.mip_filter));
}
}
}

View file

@ -0,0 +1,59 @@
use gl::types::{GLsizei, GLsizeiptr, GLuint};
use librashader_reflect::reflect::semantics::UboReflection;
use librashader_runtime::uniforms::{UniformStorage, UniformStorageAccess};
use crate::binding::UniformLocation;
use crate::gl::UboRing;
use crate::util::{InlineRingBuffer, RingBuffer};
pub struct Gl3UboRing<const SIZE: usize> {
ring: InlineRingBuffer<GLuint, SIZE>
}
impl <const SIZE: usize> UboRing<SIZE> for Gl3UboRing<SIZE> {
fn new(buffer_size: u32) -> Self {
let mut ring: InlineRingBuffer<GLuint, SIZE> = InlineRingBuffer::new();
unsafe {
gl::GenBuffers(SIZE as GLsizei, ring.items_mut().as_mut_ptr());
for buffer in ring.items() {
gl::BindBuffer(gl::UNIFORM_BUFFER, *buffer);
gl::BufferData(
gl::UNIFORM_BUFFER,
buffer_size as GLsizeiptr,
std::ptr::null(),
gl::STREAM_DRAW,
);
}
gl::BindBuffer(gl::UNIFORM_BUFFER, 0);
}
Gl3UboRing {
ring
}
}
fn bind_for_frame(&mut self, ubo: &UboReflection, ubo_location: &UniformLocation<GLuint>, storage: &impl UniformStorageAccess) {
let size = ubo.size;
let buffer = self.ring.current();
unsafe {
gl::BindBuffer(gl::UNIFORM_BUFFER, *buffer);
gl::BufferSubData(
gl::UNIFORM_BUFFER,
0,
size as GLsizeiptr,
storage.ubo_pointer().cast(),
);
gl::BindBuffer(gl::UNIFORM_BUFFER, 0);
if ubo_location.vertex != gl::INVALID_INDEX {
gl::BindBufferBase(gl::UNIFORM_BUFFER, ubo_location.vertex, *buffer);
}
if ubo_location.fragment != gl::INVALID_INDEX {
gl::BindBufferBase(gl::UNIFORM_BUFFER, ubo_location.fragment, *buffer);
}
}
self.ring.next()
}
}

View file

@ -0,0 +1,64 @@
use gl::types::{GLint, GLsizei, GLsizeiptr, GLuint};
use crate::gl::DrawQuad;
#[rustfmt::skip]
static QUAD_VBO_DATA: &[f32; 16] = &[
0.0f32, 0.0f32, 0.0f32, 0.0f32,
1.0f32, 0.0f32, 1.0f32, 0.0f32,
0.0f32, 1.0f32, 0.0f32, 1.0f32,
1.0f32, 1.0f32, 1.0f32, 1.0f32,
];
pub struct Gl46DrawQuad {
vbo: GLuint,
vao: GLuint,
}
impl DrawQuad for Gl46DrawQuad {
fn new() -> Self {
let mut vbo = 0;
let mut vao = 0;
unsafe {
gl::CreateBuffers(1, &mut vbo);
gl::NamedBufferData(
vbo,
std::mem::size_of_val(QUAD_VBO_DATA) as GLsizeiptr,
QUAD_VBO_DATA.as_ptr().cast(),
gl::STATIC_DRAW,
);
gl::CreateVertexArrays(1, &mut vao);
gl::EnableVertexArrayAttrib(vao, 0);
gl::EnableVertexArrayAttrib(vao, 1);
gl::VertexArrayVertexBuffer(vao, 0,
vbo, 0, 4 * std::mem::size_of::<f32>() as GLint
);
gl::VertexArrayAttribFormat(vao, 0, 2,
gl::FLOAT, gl::FALSE, 0);
gl::VertexArrayAttribFormat(vao, 1, 2,
gl::FLOAT, gl::FALSE,
2 * std::mem::size_of::<f32>() as GLuint);
gl::VertexArrayAttribBinding(vao, 0, 0);
gl::VertexArrayAttribBinding(vao, 1, 0);
}
Self { vbo, vao }
}
fn bind_vertices(&self) {
unsafe {
gl::BindVertexArray(self.vao);
}
}
fn unbind_vertices(&self) {
unsafe {
gl::BindVertexArray(0);
}
}
}

View file

@ -0,0 +1,305 @@
use gl::types::{GLenum, GLint, GLsizei, GLuint};
use librashader_common::{FilterMode, ImageFormat, Size, WrapMode};
use librashader_presets::Scale2D;
use crate::{GlImage, Viewport};
use crate::error::{FilterChainError, Result};
use crate::gl::Framebuffer;
use crate::texture::Texture;
#[derive(Debug)]
pub struct Gl46Framebuffer {
pub image: GLuint,
pub handle: GLuint,
pub size: Size<u32>,
pub format: GLenum,
pub max_levels: u32,
pub mip_levels: u32,
is_raw: bool,
}
impl Framebuffer for Gl46Framebuffer {
fn new(max_levels: u32) -> Gl46Framebuffer {
let mut framebuffer = 0;
unsafe {
gl::GenFramebuffers(1, &mut framebuffer);
gl::BindFramebuffer(gl::FRAMEBUFFER, framebuffer);
gl::BindFramebuffer(gl::FRAMEBUFFER, 0);
}
Gl46Framebuffer {
image: 0,
size: Size {
width: 1,
height: 1,
},
format: 0,
max_levels,
mip_levels: 0,
handle: framebuffer,
is_raw: false,
}
}
fn new_from_raw(
texture: GLuint,
handle: GLuint,
format: GLenum,
size: Size<u32>,
miplevels: u32,
) -> Gl46Framebuffer {
Gl46Framebuffer {
image: texture,
size,
format,
max_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,
scaling: Scale2D,
format: ImageFormat,
viewport: &Viewport,
_original: &Texture,
source: &Texture,
) -> Result<Size<u32>> {
if self.is_raw {
return Ok(self.size);
}
let size = librashader_runtime::scaling::scale(scaling, source.image.size, viewport.output.size);
if self.size != size {
self.size = size;
self.init(
size,
if format == ImageFormat::Unknown {
ImageFormat::R8G8B8A8Unorm
} else {
format
},
)?;
}
Ok(size)
}
fn clear<const REBIND: bool>(&self) {
unsafe {
if REBIND {
gl::BindFramebuffer(gl::FRAMEBUFFER, self.handle);
}
gl::ColorMask(gl::TRUE, gl::TRUE, gl::TRUE, gl::TRUE);
gl::ClearColor(0.0, 0.0, 0.0, 0.0);
gl::Clear(gl::COLOR_BUFFER_BIT);
if REBIND {
gl::BindFramebuffer(gl::FRAMEBUFFER, 0);
}
}
}
fn copy_from(&mut self, 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)?;
}
unsafe {
gl::BindFramebuffer(gl::FRAMEBUFFER, self.handle);
gl::FramebufferTexture2D(
gl::READ_FRAMEBUFFER,
gl::COLOR_ATTACHMENT0,
gl::TEXTURE_2D,
image.handle,
0,
);
gl::FramebufferTexture2D(
gl::DRAW_FRAMEBUFFER,
gl::COLOR_ATTACHMENT1,
gl::TEXTURE_2D,
self.image,
0,
);
gl::ReadBuffer(gl::COLOR_ATTACHMENT0);
gl::DrawBuffer(gl::COLOR_ATTACHMENT1);
gl::BlitFramebuffer(
0,
0,
self.size.width as GLint,
self.size.height as GLint,
0,
0,
self.size.width as GLint,
self.size.height as GLint,
gl::COLOR_BUFFER_BIT,
gl::NEAREST,
);
// cleanup after ourselves.
gl::FramebufferTexture2D(
gl::READ_FRAMEBUFFER,
gl::COLOR_ATTACHMENT0,
gl::TEXTURE_2D,
0,
0,
);
gl::FramebufferTexture2D(
gl::DRAW_FRAMEBUFFER,
gl::COLOR_ATTACHMENT1,
gl::TEXTURE_2D,
0,
0,
);
// set this back to color_attachment 0
gl::FramebufferTexture2D(
gl::FRAMEBUFFER,
gl::COLOR_ATTACHMENT0,
gl::TEXTURE_2D,
self.image,
0,
);
gl::BindFramebuffer(gl::FRAMEBUFFER, 0);
}
Ok(())
}
fn init(&mut self, mut size: Size<u32>, format: impl Into<GLenum>) -> Result<()> {
if self.is_raw {
return Ok(());
}
self.format = format.into();
self.size = size;
unsafe {
gl::BindFramebuffer(gl::FRAMEBUFFER, self.handle);
// reset the framebuffer image
if self.image != 0 {
gl::FramebufferTexture2D(
gl::FRAMEBUFFER,
gl::COLOR_ATTACHMENT0,
gl::TEXTURE_2D,
0,
0,
);
gl::DeleteTextures(1, &self.image);
}
gl::GenTextures(1, &mut self.image);
gl::BindTexture(gl::TEXTURE_2D, self.image);
if size.width == 0 {
size.width = 1;
}
if size.height == 0 {
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;
}
if self.mip_levels == 0 {
self.mip_levels = 1;
}
gl::TexStorage2D(
gl::TEXTURE_2D,
self.mip_levels as GLsizei,
self.format,
size.width as GLsizei,
size.height as GLsizei,
);
gl::FramebufferTexture2D(
gl::FRAMEBUFFER,
gl::COLOR_ATTACHMENT0,
gl::TEXTURE_2D,
self.image,
0,
);
let status = gl::CheckFramebufferStatus(gl::FRAMEBUFFER);
if status != gl::FRAMEBUFFER_COMPLETE {
match status {
gl::FRAMEBUFFER_UNSUPPORTED => {
eprintln!("unsupported fbo");
gl::FramebufferTexture2D(
gl::FRAMEBUFFER,
gl::COLOR_ATTACHMENT0,
gl::TEXTURE_2D,
0,
0,
);
gl::DeleteTextures(1, &self.image);
gl::GenTextures(1, &mut self.image);
gl::BindTexture(gl::TEXTURE_2D, self.image);
self.mip_levels = librashader_runtime::scaling::calc_miplevel(size);
if self.mip_levels > self.max_levels {
self.mip_levels = self.max_levels;
}
if self.mip_levels == 0 {
self.mip_levels = 1;
}
gl::TexStorage2D(
gl::TEXTURE_2D,
self.mip_levels as GLsizei,
ImageFormat::R8G8B8A8Unorm.into(),
size.width as GLsizei,
size.height as GLsizei,
);
gl::FramebufferTexture2D(
gl::FRAMEBUFFER,
gl::COLOR_ATTACHMENT0,
gl::TEXTURE_2D,
self.image,
0,
);
// self.init =
// gl::CheckFramebufferStatus(gl::FRAMEBUFFER) == gl::FRAMEBUFFER_COMPLETE;
}
_ => return Err(FilterChainError::FramebufferInit(status))
}
}
gl::BindFramebuffer(gl::FRAMEBUFFER, 0);
gl::BindTexture(gl::TEXTURE_2D, 0);
}
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

@ -0,0 +1,85 @@
use gl::types::{GLsizei, GLuint};
use rustc_hash::FxHashMap;
use librashader_common::image::Image;
use librashader_common::Size;
use librashader_presets::TextureConfig;
use crate::gl::LoadLut;
use crate::{GlImage, util};
use crate::texture::Texture;
use crate::error::Result;
pub struct Gl46LutLoad;
impl LoadLut for Gl46LutLoad {
fn load_luts(textures: &[TextureConfig]) -> Result<FxHashMap<usize, Texture>> {
let mut luts = FxHashMap::default();
let pixel_unpack = unsafe {
let mut binding = 0;
gl::GetIntegerv(gl::PIXEL_UNPACK_BUFFER_BINDING, &mut binding);
binding
};
unsafe {
gl::BindBuffer(gl::PIXEL_UNPACK_BUFFER, 0);
}
for (index, texture) in textures.iter().enumerate() {
let image = Image::load(&texture.path)?;
let levels = if texture.mipmap {
librashader_runtime::scaling::calc_miplevel(image.size)
} else {
1u32
};
let mut handle = 0;
unsafe {
gl::CreateTextures(gl::TEXTURE_2D,1, &mut handle);
gl::TextureStorage2D(
handle,
levels as GLsizei,
gl::RGBA8,
image.size.width as GLsizei,
image.size.height as GLsizei,
);
gl::PixelStorei(gl::UNPACK_ROW_LENGTH, 0);
gl::PixelStorei(gl::UNPACK_ALIGNMENT, 4);
gl::TextureSubImage2D(
handle,
0, 0, 0,
image.size.width as GLsizei,
image.size.height as GLsizei,
gl::RGBA,
gl::UNSIGNED_BYTE,
image.bytes.as_ptr().cast(),
);
let mipmap = levels > 1;
if mipmap {
gl::GenerateTextureMipmap(handle);
}
}
luts.insert(
index,
Texture {
image: GlImage {
handle,
format: gl::RGBA8,
size: image.size,
padded_size: Size::default(),
},
filter: texture.filter_mode,
mip_filter: texture.filter_mode,
wrap_mode: texture.wrap_mode,
},
);
}
unsafe {
gl::BindBuffer(gl::PIXEL_UNPACK_BUFFER, pixel_unpack as GLuint);
};
Ok(luts)
}
}

View file

@ -0,0 +1,11 @@
mod lut_load;
mod draw_quad;
mod ubo_ring;
mod framebuffer;
mod texture_bind;
pub use lut_load::*;
pub use draw_quad::*;
pub use ubo_ring::*;
pub use framebuffer::*;
pub use texture_bind::*;

View file

@ -0,0 +1,17 @@
use librashader_reflect::reflect::semantics::TextureBinding;
use crate::gl::BindTexture;
use crate::samplers::SamplerSet;
use crate::texture::Texture;
pub struct Gl46BindTexture;
impl BindTexture for Gl46BindTexture {
fn bind_texture(samplers: &SamplerSet, binding: &TextureBinding, texture: &Texture) {
unsafe {
// eprintln!("setting {} to texunit {}", texture.image.handle, binding.binding);
gl::BindTextureUnit(binding.binding, texture.image.handle);
gl::BindSampler(binding.binding,
samplers.get(texture.wrap_mode, texture.filter, texture.mip_filter));
}
}
}

View file

@ -0,0 +1,56 @@
use gl::types::{GLsizei, GLsizeiptr, GLuint};
use librashader_reflect::reflect::semantics::UboReflection;
use librashader_runtime::uniforms::{UniformStorage, UniformStorageAccess};
use crate::binding::UniformLocation;
use crate::gl::UboRing;
use crate::util::{InlineRingBuffer, RingBuffer};
pub struct Gl46UboRing<const SIZE: usize> {
ring: InlineRingBuffer<GLuint, SIZE>
}
impl <const SIZE: usize> UboRing<SIZE> for Gl46UboRing<SIZE> {
fn new(buffer_size: u32) -> Self {
let mut ring: InlineRingBuffer<GLuint, SIZE> = InlineRingBuffer::new();
unsafe {
gl::CreateBuffers(SIZE as GLsizei, ring.items_mut().as_mut_ptr());
for buffer in ring.items() {
gl::NamedBufferData(
*buffer,
buffer_size as GLsizeiptr,
std::ptr::null(),
gl::STREAM_DRAW,
);
}
};
Gl46UboRing {
ring
}
}
fn bind_for_frame(&mut self, ubo: &UboReflection, ubo_location: &UniformLocation<GLuint>, storage: &impl UniformStorageAccess) {
let size = ubo.size;
let buffer = self.ring.current();
unsafe {
gl::NamedBufferSubData(
*buffer,
0,
size as GLsizeiptr,
storage.ubo_pointer().cast(),
);
if ubo_location.vertex != gl::INVALID_INDEX {
gl::BindBufferBase(gl::UNIFORM_BUFFER, ubo_location.vertex, *buffer);
}
if ubo_location.fragment != gl::INVALID_INDEX {
gl::BindBufferBase(gl::UNIFORM_BUFFER, ubo_location.fragment, *buffer);
}
}
self.ring.next()
}
}

View file

@ -0,0 +1,56 @@
pub(crate) mod gl3;
mod gl46;
use gl::types::{GLenum, GLint, GLsizei, GLuint};
use rustc_hash::FxHashMap;
use librashader_common::{FilterMode, ImageFormat, Size, WrapMode};
use librashader_presets::{Scale2D, TextureConfig};
use librashader_reflect::reflect::semantics::{TextureBinding, UboReflection};
use librashader_runtime::uniforms::{UniformStorage, UniformStorageAccess};
use crate::binding::UniformLocation;
use crate::texture::Texture;
use crate::error::{FilterChainError, Result};
use crate::{GlImage, Viewport};
use crate::samplers::SamplerSet;
pub trait LoadLut {
fn load_luts(textures: &[TextureConfig]) -> Result<FxHashMap<usize, Texture>>;
}
pub trait DrawQuad {
fn new() -> Self;
fn bind_vertices(&self);
fn unbind_vertices(&self);
}
pub trait UboRing<const SIZE: usize> {
fn new(buffer_size: u32) -> Self;
fn bind_for_frame(&mut self, ubo: &UboReflection, ubo_location: &UniformLocation<GLuint>, storage: &impl UniformStorageAccess);
}
pub trait Framebuffer {
fn new(max_levels: u32) -> Self;
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;
fn scale(
&mut self,
scaling: Scale2D,
format: ImageFormat,
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<()>;
}
pub trait BindTexture {
fn bind_texture(samplers: &SamplerSet, binding: &TextureBinding, texture: &Texture);
}

View file

@ -8,7 +8,9 @@ use gl::types::{GLchar, GLenum, GLint, GLsizei, GLuint};
use librashader_common::Size;
use crate::filter_chain::FilterChain;
use crate::framebuffer::{Framebuffer, GlImage, Viewport};
use crate::framebuffer::{GlImage, Viewport};
use crate::gl::Framebuffer;
use crate::gl::gl3::Gl3Framebuffer;
const WIDTH: u32 = 900;
const HEIGHT: u32 = 700;
@ -462,7 +464,7 @@ void main()
let (fb_width, fb_height) = window.get_framebuffer_size();
let (vp_width, vp_height) = window.get_size();
let output = Framebuffer::new_from_raw(
let output = Gl3Framebuffer::new_from_raw(
output_texture,
output_framebuffer_handle,
gl::RGBA8,

View file

@ -5,7 +5,6 @@ mod binding;
mod filter_chain;
mod filter_pass;
mod framebuffer;
mod quad_render;
mod render_target;
mod util;
pub mod error;
@ -13,14 +12,14 @@ pub mod error;
mod samplers;
pub use filter_chain::FilterChain;
pub use framebuffer::Framebuffer;
pub use framebuffer::GlImage;
pub use framebuffer::Viewport;
#[cfg(test)]
mod hello_triangle;
mod gl3_hello_triangle;
mod texture;
mod options;
mod gl;
#[cfg(test)]
mod tests {
@ -29,11 +28,11 @@ mod tests {
#[test]
fn triangle_gl() {
let (glfw, window, events, shader, vao) = hello_triangle::setup();
let (glfw, window, events, shader, vao) = 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/bezel/Mega_Bezel/Presets/MBZ__0__SMOOTH-ADV.slangp", None)
FilterChain::load_from_path("../test/slang-shaders/vhs/VHSPro.slangp", None)
// FilterChain::load_from_path("../test/slang-shaders/bezel/Mega_Bezel/Presets/MBZ__0__SMOOTH-ADV.slangp", None)
.unwrap();
hello_triangle::do_loop(glfw, window, events, shader, vao, &mut filter);
gl3_hello_triangle::do_loop(glfw, window, events, shader, vao, &mut filter);
}
}

View file

@ -1,4 +1,6 @@
use crate::framebuffer::{Framebuffer, Viewport};
use crate::framebuffer::Viewport;
use crate::gl::Framebuffer;
use crate::gl::gl3::Gl3Framebuffer;
#[rustfmt::skip]
static DEFAULT_MVP: &[f32; 16] = &[
@ -9,15 +11,15 @@ static DEFAULT_MVP: &[f32; 16] = &[
];
#[derive(Debug, Copy, Clone)]
pub struct RenderTarget<'a> {
pub(crate) struct RenderTarget<'a> {
pub mvp: &'a [f32; 16],
pub framebuffer: &'a Framebuffer,
pub framebuffer: &'a Gl3Framebuffer,
pub x: i32,
pub y: i32
}
impl<'a> RenderTarget<'a> {
pub fn new(backbuffer: &'a Framebuffer, mvp: Option<&'a [f32; 16]>, x: i32, y: i32) -> Self {
pub fn new(backbuffer: &'a Gl3Framebuffer, mvp: Option<&'a [f32; 16]>, x: i32, y: i32) -> Self {
if let Some(mvp) = mvp {
RenderTarget {
framebuffer: backbuffer,

View file

@ -5,17 +5,6 @@ use librashader_reflect::reflect::semantics::BindingStage;
use librashader_runtime::uniforms::{BindUniform, UniformStorage, UniformScalar};
use crate::binding::UniformLocation;
pub fn calc_miplevel(size: Size<u32>) -> u32 {
let mut size = std::cmp::max(size.width, size.height);
let mut levels = 0;
while size != 0 {
levels += 1;
size >>= 1;
}
levels
}
pub trait RingBuffer<T> {
fn current(&self) -> &T;
fn current_mut(&mut self) -> &mut T;

View file

@ -6,8 +6,10 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
librashader-common = { path = "../librashader-common" }
librashader-presets = { path = "../librashader-presets" }
librashader-preprocess = { path = "../librashader-preprocess" }
librashader-reflect = { path = "../librashader-reflect" }
bytemuck = "1.12.3"
rustc-hash = "1.1.0"
num-traits = "0.2.15"

View file

@ -1,2 +1,3 @@
pub mod semantics;
pub mod uniforms;
pub mod scaling;

View file

@ -0,0 +1,58 @@
use std::ops::Mul;
use librashader_common::Size;
use librashader_presets::{Scale2D, ScaleFactor, ScaleType, Scaling};
use num_traits::AsPrimitive;
pub fn scale<T>(scaling: Scale2D, source: Size<T>, viewport: Size<T>) -> Size<T>
where T: Mul<ScaleFactor, Output=f32> + Copy + 'static,
f32: AsPrimitive<T>,
{
let width: f32;
let height: f32;
match scaling.x {
Scaling {
scale_type: ScaleType::Input,
factor,
} => width = source.width * factor,
Scaling {
scale_type: ScaleType::Absolute,
factor,
} => width = factor.into(),
Scaling {
scale_type: ScaleType::Viewport,
factor,
} => width = viewport.width * factor,
};
match scaling.y {
Scaling {
scale_type: ScaleType::Input,
factor,
} => height = source.height * factor,
Scaling {
scale_type: ScaleType::Absolute,
factor,
} => height = factor.into(),
Scaling {
scale_type: ScaleType::Viewport,
factor,
} => height = viewport.height * factor,
};
Size {
width: width.round().as_(),
height: height.round().as_(),
}
}
pub fn calc_miplevel(size: Size<u32>) -> u32 {
let mut size = std::cmp::max(size.width, size.height);
let mut levels = 0;
while size != 0 {
levels += 1;
size >>= 1;
}
levels
}

View file

@ -17,6 +17,21 @@ pub trait BindUniform<C, T> {
fn bind_uniform(value: T, ctx: C) -> Option<()>;
}
pub trait UniformStorageAccess {
fn ubo_pointer(&self) -> *const u8;
fn push_pointer(&self) -> *const u8;
}
impl <T, H> UniformStorageAccess for UniformStorage<T, H> {
fn ubo_pointer(&self) -> *const u8 {
self.ubo.as_ptr()
}
fn push_pointer(&self) -> *const u8 {
self.push.as_ptr()
}
}
pub struct UniformStorage<H=NoUniformBinder, C = Option<()>> {
pub ubo: Box<[u8]>,
pub push: Box<[u8]>,