gl: abstract away gl3 and dsa
This commit is contained in:
parent
c4f1abd411
commit
538672e355
2
Cargo.lock
generated
2
Cargo.lock
generated
|
@ -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",
|
||||
]
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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(())
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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]>,
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
305
librashader-runtime-gl/src/gl/gl3/framebuffer.rs
Normal file
305
librashader-runtime-gl/src/gl/gl3/framebuffer.rs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
85
librashader-runtime-gl/src/gl/gl3/lut_load.rs
Normal file
85
librashader-runtime-gl/src/gl/gl3/lut_load.rs
Normal 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)
|
||||
}
|
||||
}
|
11
librashader-runtime-gl/src/gl/gl3/mod.rs
Normal file
11
librashader-runtime-gl/src/gl/gl3/mod.rs
Normal 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::*;
|
19
librashader-runtime-gl/src/gl/gl3/texture_bind.rs
Normal file
19
librashader-runtime-gl/src/gl/gl3/texture_bind.rs
Normal 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));
|
||||
}
|
||||
}
|
||||
}
|
59
librashader-runtime-gl/src/gl/gl3/ubo_ring.rs
Normal file
59
librashader-runtime-gl/src/gl/gl3/ubo_ring.rs
Normal 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()
|
||||
}
|
||||
}
|
||||
|
||||
|
64
librashader-runtime-gl/src/gl/gl46/draw_quad.rs
Normal file
64
librashader-runtime-gl/src/gl/gl46/draw_quad.rs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
305
librashader-runtime-gl/src/gl/gl46/framebuffer.rs
Normal file
305
librashader-runtime-gl/src/gl/gl46/framebuffer.rs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
85
librashader-runtime-gl/src/gl/gl46/lut_load.rs
Normal file
85
librashader-runtime-gl/src/gl/gl46/lut_load.rs
Normal 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)
|
||||
}
|
||||
}
|
11
librashader-runtime-gl/src/gl/gl46/mod.rs
Normal file
11
librashader-runtime-gl/src/gl/gl46/mod.rs
Normal 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::*;
|
17
librashader-runtime-gl/src/gl/gl46/texture_bind.rs
Normal file
17
librashader-runtime-gl/src/gl/gl46/texture_bind.rs
Normal 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));
|
||||
}
|
||||
}
|
||||
}
|
56
librashader-runtime-gl/src/gl/gl46/ubo_ring.rs
Normal file
56
librashader-runtime-gl/src/gl/gl46/ubo_ring.rs
Normal 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()
|
||||
}
|
||||
}
|
||||
|
||||
|
56
librashader-runtime-gl/src/gl/mod.rs
Normal file
56
librashader-runtime-gl/src/gl/mod.rs
Normal 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);
|
||||
}
|
|
@ -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,
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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"
|
|
@ -1,2 +1,3 @@
|
|||
pub mod semantics;
|
||||
pub mod uniforms;
|
||||
pub mod scaling;
|
||||
|
|
58
librashader-runtime/src/scaling.rs
Normal file
58
librashader-runtime/src/scaling.rs
Normal 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
|
||||
}
|
|
@ -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]>,
|
||||
|
|
Loading…
Reference in a new issue