gl: merge gl46 back into gl crate
This commit is contained in:
parent
538672e355
commit
a091cff6ae
29 changed files with 261 additions and 2101 deletions
|
@ -1,8 +1,6 @@
|
||||||
use crate::binding::{UniformLocation, VariableLocation};
|
use crate::binding::{UniformLocation, VariableLocation};
|
||||||
use crate::filter_pass::FilterPass;
|
use crate::filter_pass::FilterPass;
|
||||||
use crate::framebuffer::{GlImage, Viewport};
|
use crate::framebuffer::{GLImage, Viewport};
|
||||||
use crate::gl::gl3::Gl3Framebuffer;
|
|
||||||
use crate::gl::gl3::{Gl3DrawQuad, Gl3LutLoad, Gl3UboRing};
|
|
||||||
use crate::render_target::RenderTarget;
|
use crate::render_target::RenderTarget;
|
||||||
use crate::util;
|
use crate::util;
|
||||||
use crate::util::{gl_get_version, gl_u16_to_version, InlineRingBuffer};
|
use crate::util::{gl_get_version, gl_u16_to_version, InlineRingBuffer};
|
||||||
|
@ -27,15 +25,15 @@ use crate::options::{FilterChainOptions, FrameOptions};
|
||||||
use crate::samplers::SamplerSet;
|
use crate::samplers::SamplerSet;
|
||||||
use crate::texture::Texture;
|
use crate::texture::Texture;
|
||||||
use crate::binding::BufferStorage;
|
use crate::binding::BufferStorage;
|
||||||
use crate::gl::{DrawQuad, Framebuffer, LoadLut, UboRing};
|
use crate::gl::{DrawQuad, Framebuffer, GLInterface, LoadLut, UboRing};
|
||||||
|
|
||||||
pub struct FilterChain {
|
pub struct FilterChain<T: GLInterface> {
|
||||||
passes: Box<[FilterPass]>,
|
passes: Box<[FilterPass<T>]>,
|
||||||
common: FilterCommon,
|
common: FilterCommon,
|
||||||
pub(crate) draw_quad: Gl3DrawQuad,
|
pub(crate) draw_quad: T::DrawQuad,
|
||||||
output_framebuffers: Box<[Gl3Framebuffer]>,
|
output_framebuffers: Box<[T::Framebuffer]>,
|
||||||
feedback_framebuffers: Box<[Gl3Framebuffer]>,
|
feedback_framebuffers: Box<[T::Framebuffer]>,
|
||||||
history_framebuffers: VecDeque<Gl3Framebuffer>,
|
history_framebuffers: VecDeque<T::Framebuffer>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct FilterCommon {
|
pub struct FilterCommon {
|
||||||
|
@ -53,7 +51,7 @@ pub struct FilterMutable {
|
||||||
pub(crate) parameters: FxHashMap<String, f32>
|
pub(crate) parameters: FxHashMap<String, f32>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FilterChain {
|
impl <T: GLInterface> FilterChain<T> {
|
||||||
fn reflect_uniform_location(pipeline: GLuint, meta: &impl UniformMeta) -> VariableLocation {
|
fn reflect_uniform_location(pipeline: GLuint, meta: &impl UniformMeta) -> VariableLocation {
|
||||||
// todo: support both ubo and pushco
|
// todo: support both ubo and pushco
|
||||||
// todo: fix this.
|
// todo: fix this.
|
||||||
|
@ -90,16 +88,16 @@ type ShaderPassMeta = (
|
||||||
>,
|
>,
|
||||||
);
|
);
|
||||||
|
|
||||||
impl FilterChain {
|
impl <T: GLInterface> FilterChain<T> {
|
||||||
/// Load a filter chain from a pre-parsed `ShaderPreset`.
|
/// Load a filter chain from a pre-parsed `ShaderPreset`.
|
||||||
pub fn load_from_preset(preset: ShaderPreset, options: Option<&FilterChainOptions>) -> Result<FilterChain> {
|
pub fn load_from_preset(preset: ShaderPreset, options: Option<&FilterChainOptions>) -> Result<Self> {
|
||||||
let (passes, semantics) = FilterChain::load_preset(preset.shaders, &preset.textures)?;
|
let (passes, semantics) = Self::load_preset(preset.shaders, &preset.textures)?;
|
||||||
|
|
||||||
let version = options.map(|o| gl_u16_to_version(o.gl_version))
|
let version = options.map(|o| gl_u16_to_version(o.gl_version))
|
||||||
.unwrap_or_else(|| gl_get_version());
|
.unwrap_or_else(|| gl_get_version());
|
||||||
|
|
||||||
// initialize passes
|
// initialize passes
|
||||||
let filters = FilterChain::init_passes(version, passes, &semantics)?;
|
let filters = Self::init_passes(version, passes, &semantics)?;
|
||||||
|
|
||||||
let default_filter = filters.first().map(|f| f.config.filter).unwrap_or_default();
|
let default_filter = filters.first().map(|f| f.config.filter).unwrap_or_default();
|
||||||
let default_wrap = filters
|
let default_wrap = filters
|
||||||
|
@ -111,24 +109,24 @@ impl FilterChain {
|
||||||
|
|
||||||
// initialize output framebuffers
|
// initialize output framebuffers
|
||||||
let mut output_framebuffers = Vec::new();
|
let mut output_framebuffers = Vec::new();
|
||||||
output_framebuffers.resize_with(filters.len(), || Gl3Framebuffer::new(1));
|
output_framebuffers.resize_with(filters.len(), || Framebuffer::new(1));
|
||||||
let mut output_textures = Vec::new();
|
let mut output_textures = Vec::new();
|
||||||
output_textures.resize_with(filters.len(), Texture::default);
|
output_textures.resize_with(filters.len(), Texture::default);
|
||||||
|
|
||||||
// initialize feedback framebuffers
|
// initialize feedback framebuffers
|
||||||
let mut feedback_framebuffers = Vec::new();
|
let mut feedback_framebuffers = Vec::new();
|
||||||
feedback_framebuffers.resize_with(filters.len(), || Gl3Framebuffer::new(1));
|
feedback_framebuffers.resize_with(filters.len(), || Framebuffer::new(1));
|
||||||
let mut feedback_textures = Vec::new();
|
let mut feedback_textures = Vec::new();
|
||||||
feedback_textures.resize_with(filters.len(), Texture::default);
|
feedback_textures.resize_with(filters.len(), Texture::default);
|
||||||
|
|
||||||
// load luts
|
// load luts
|
||||||
let luts = Gl3LutLoad::load_luts(&preset.textures)?;
|
let luts = T::LoadLut::load_luts(&preset.textures)?;
|
||||||
|
|
||||||
let (history_framebuffers, history_textures) =
|
let (history_framebuffers, history_textures) =
|
||||||
FilterChain::init_history(&filters, default_filter, default_wrap);
|
FilterChain::init_history(&filters, default_filter, default_wrap);
|
||||||
|
|
||||||
// create vertex objects
|
// create vertex objects
|
||||||
let draw_quad = Gl3DrawQuad::new();
|
let draw_quad = T::DrawQuad::new();
|
||||||
|
|
||||||
Ok(FilterChain {
|
Ok(FilterChain {
|
||||||
passes: filters,
|
passes: filters,
|
||||||
|
@ -152,7 +150,7 @@ impl FilterChain {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Load the shader preset at the given path into a filter chain.
|
/// Load the shader preset at the given path into a filter chain.
|
||||||
pub fn load_from_path(path: impl AsRef<Path>, options: Option<&FilterChainOptions>) -> Result<FilterChain> {
|
pub fn load_from_path(path: impl AsRef<Path>, options: Option<&FilterChainOptions>) -> Result<Self> {
|
||||||
// load passes from preset
|
// load passes from preset
|
||||||
let preset = ShaderPreset::try_parse(path)?;
|
let preset = ShaderPreset::try_parse(path)?;
|
||||||
Self::load_from_preset(preset, options)
|
Self::load_from_preset(preset, options)
|
||||||
|
@ -213,7 +211,7 @@ impl FilterChain {
|
||||||
version: GlVersion,
|
version: GlVersion,
|
||||||
passes: Vec<ShaderPassMeta>,
|
passes: Vec<ShaderPassMeta>,
|
||||||
semantics: &ReflectSemantics,
|
semantics: &ReflectSemantics,
|
||||||
) -> Result<Box<[FilterPass]>> {
|
) -> Result<Box<[FilterPass<T>]>> {
|
||||||
let mut filters = Vec::new();
|
let mut filters = Vec::new();
|
||||||
|
|
||||||
// initialize passes
|
// initialize passes
|
||||||
|
@ -281,7 +279,7 @@ impl FilterChain {
|
||||||
};
|
};
|
||||||
|
|
||||||
let ubo_ring = if let Some(ubo) = &reflection.ubo {
|
let ubo_ring = if let Some(ubo) = &reflection.ubo {
|
||||||
let ring = Gl3UboRing::new(ubo.size);
|
let ring = UboRing::new(ubo.size);
|
||||||
Some(ring)
|
Some(ring)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
@ -305,7 +303,7 @@ impl FilterChain {
|
||||||
uniform_bindings.insert(
|
uniform_bindings.insert(
|
||||||
UniformBinding::Parameter(param.id.clone()),
|
UniformBinding::Parameter(param.id.clone()),
|
||||||
(
|
(
|
||||||
FilterChain::reflect_uniform_location(program, param),
|
Self::reflect_uniform_location(program, param),
|
||||||
param.offset,
|
param.offset,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -315,7 +313,7 @@ impl FilterChain {
|
||||||
uniform_bindings.insert(
|
uniform_bindings.insert(
|
||||||
UniformBinding::SemanticVariable(*semantics),
|
UniformBinding::SemanticVariable(*semantics),
|
||||||
(
|
(
|
||||||
FilterChain::reflect_uniform_location(program, param),
|
Self::reflect_uniform_location(program, param),
|
||||||
param.offset,
|
param.offset,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -325,7 +323,7 @@ impl FilterChain {
|
||||||
uniform_bindings.insert(
|
uniform_bindings.insert(
|
||||||
UniformBinding::TextureSize(*semantics),
|
UniformBinding::TextureSize(*semantics),
|
||||||
(
|
(
|
||||||
FilterChain::reflect_uniform_location(program, param),
|
Self::reflect_uniform_location(program, param),
|
||||||
param.offset,
|
param.offset,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -357,10 +355,10 @@ impl FilterChain {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init_history(
|
fn init_history(
|
||||||
filters: &[FilterPass],
|
filters: &[FilterPass<T>],
|
||||||
filter: FilterMode,
|
filter: FilterMode,
|
||||||
wrap_mode: WrapMode,
|
wrap_mode: WrapMode,
|
||||||
) -> (VecDeque<Gl3Framebuffer>, Box<[Texture]>) {
|
) -> (VecDeque<T::Framebuffer>, Box<[Texture]>) {
|
||||||
let mut required_images = 0;
|
let mut required_images = 0;
|
||||||
|
|
||||||
for pass in filters {
|
for pass in filters {
|
||||||
|
@ -394,7 +392,7 @@ impl FilterChain {
|
||||||
|
|
||||||
eprintln!("[history] using frame history with {required_images} images");
|
eprintln!("[history] using frame history with {required_images} images");
|
||||||
let mut framebuffers = VecDeque::with_capacity(required_images);
|
let mut framebuffers = VecDeque::with_capacity(required_images);
|
||||||
framebuffers.resize_with(required_images, || Gl3Framebuffer::new(1));
|
framebuffers.resize_with(required_images, || Framebuffer::new(1));
|
||||||
|
|
||||||
let mut history_textures = Vec::new();
|
let mut history_textures = Vec::new();
|
||||||
history_textures.resize_with(required_images, || Texture {
|
history_textures.resize_with(required_images, || Texture {
|
||||||
|
@ -407,9 +405,9 @@ impl FilterChain {
|
||||||
(framebuffers, history_textures.into_boxed_slice())
|
(framebuffers, history_textures.into_boxed_slice())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push_history(&mut self, input: &GlImage) -> Result<()> {
|
fn push_history(&mut self, input: &GLImage) -> Result<()> {
|
||||||
if let Some(mut back) = self.history_framebuffers.pop_back() {
|
if let Some(mut back) = self.history_framebuffers.pop_back() {
|
||||||
if back.size != input.size || (input.format != 0 && input.format != back.format) {
|
if back.size() != input.size || (input.format != 0 && input.format != back.format()) {
|
||||||
eprintln!("[history] resizing");
|
eprintln!("[history] resizing");
|
||||||
back.init(input.size, input.format)?;
|
back.init(input.size, input.format)?;
|
||||||
}
|
}
|
||||||
|
@ -425,7 +423,7 @@ impl FilterChain {
|
||||||
/// Process a frame with the input image.
|
/// Process a frame with the input image.
|
||||||
///
|
///
|
||||||
/// When this frame returns, GL_FRAMEBUFFER is bound to 0.
|
/// When this frame returns, GL_FRAMEBUFFER is bound to 0.
|
||||||
pub fn frame(&mut self, count: usize, viewport: &Viewport, input: &GlImage, options: Option<&FrameOptions>) -> Result<()> {
|
pub fn frame(&mut self, count: usize, viewport: &Viewport<T::Framebuffer>, input: &GLImage, options: Option<&FrameOptions>) -> Result<()> {
|
||||||
// limit number of passes to those enabled.
|
// limit number of passes to those enabled.
|
||||||
let passes = &mut self.passes[0..self.common.config.passes_enabled];
|
let passes = &mut self.passes[0..self.common.config.passes_enabled];
|
||||||
if let Some(options) = options {
|
if let Some(options) = options {
|
||||||
|
|
|
@ -14,27 +14,26 @@ use librashader_runtime::uniforms::UniformStorage;
|
||||||
use crate::binding::{BufferStorage, GlUniformBinder, UniformLocation, VariableLocation};
|
use crate::binding::{BufferStorage, GlUniformBinder, UniformLocation, VariableLocation};
|
||||||
use crate::filter_chain::FilterCommon;
|
use crate::filter_chain::FilterCommon;
|
||||||
use crate::framebuffer::Viewport;
|
use crate::framebuffer::Viewport;
|
||||||
use crate::gl::gl3::{Gl3BindTexture, Gl3UboRing};
|
use crate::gl::{BindTexture, Framebuffer, GLInterface, UboRing};
|
||||||
use crate::gl::{BindTexture, Framebuffer, UboRing};
|
|
||||||
use crate::render_target::RenderTarget;
|
use crate::render_target::RenderTarget;
|
||||||
use crate::samplers::SamplerSet;
|
use crate::samplers::SamplerSet;
|
||||||
use crate::texture::Texture;
|
use crate::texture::Texture;
|
||||||
use crate::util::{InlineRingBuffer, RingBuffer};
|
use crate::util::{InlineRingBuffer, RingBuffer};
|
||||||
|
|
||||||
|
|
||||||
pub struct FilterPass {
|
pub struct FilterPass<T: GLInterface> {
|
||||||
pub reflection: ShaderReflection,
|
pub reflection: ShaderReflection,
|
||||||
pub compiled: ShaderCompilerOutput<String, GlslangGlslContext>,
|
pub compiled: ShaderCompilerOutput<String, GlslangGlslContext>,
|
||||||
pub program: GLuint,
|
pub program: GLuint,
|
||||||
pub ubo_location: UniformLocation<GLuint>,
|
pub ubo_location: UniformLocation<GLuint>,
|
||||||
pub ubo_ring: Option<Gl3UboRing<16>>,
|
pub ubo_ring: Option<T::UboRing>,
|
||||||
pub(crate) uniform_storage: BufferStorage,
|
pub(crate) uniform_storage: BufferStorage,
|
||||||
pub uniform_bindings: FxHashMap<UniformBinding, (VariableLocation, MemberOffset)>,
|
pub uniform_bindings: FxHashMap<UniformBinding, (VariableLocation, MemberOffset)>,
|
||||||
pub source: ShaderSource,
|
pub source: ShaderSource,
|
||||||
pub config: ShaderPassConfig,
|
pub config: ShaderPassConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FilterPass {
|
impl<T:GLInterface> FilterPass<T> {
|
||||||
// todo: fix rendertargets (i.e. non-final pass is internal, final pass is user provided fbo)
|
// todo: fix rendertargets (i.e. non-final pass is internal, final pass is user provided fbo)
|
||||||
pub(crate) fn draw(
|
pub(crate) fn draw(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
@ -42,15 +41,15 @@ impl FilterPass {
|
||||||
parent: &FilterCommon,
|
parent: &FilterCommon,
|
||||||
frame_count: u32,
|
frame_count: u32,
|
||||||
frame_direction: i32,
|
frame_direction: i32,
|
||||||
viewport: &Viewport,
|
viewport: &Viewport<T::Framebuffer>,
|
||||||
original: &Texture,
|
original: &Texture,
|
||||||
source: &Texture,
|
source: &Texture,
|
||||||
output: RenderTarget
|
output: RenderTarget<T::Framebuffer>
|
||||||
) {
|
) {
|
||||||
let framebuffer = output.framebuffer;
|
let framebuffer = output.framebuffer;
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
gl::BindFramebuffer(gl::FRAMEBUFFER, framebuffer.handle);
|
gl::BindFramebuffer(gl::FRAMEBUFFER, framebuffer.handle());
|
||||||
gl::UseProgram(self.program);
|
gl::UseProgram(self.program);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,7 +59,7 @@ impl FilterPass {
|
||||||
output.mvp,
|
output.mvp,
|
||||||
frame_count,
|
frame_count,
|
||||||
frame_direction,
|
frame_direction,
|
||||||
framebuffer.size,
|
framebuffer.size(),
|
||||||
viewport,
|
viewport,
|
||||||
original,
|
original,
|
||||||
source,
|
source,
|
||||||
|
@ -78,14 +77,15 @@ impl FilterPass {
|
||||||
// can't use framebuffer.clear because it will unbind.
|
// can't use framebuffer.clear because it will unbind.
|
||||||
framebuffer.clear::<false>();
|
framebuffer.clear::<false>();
|
||||||
|
|
||||||
|
let framebuffer_size = framebuffer.size();
|
||||||
gl::Viewport(
|
gl::Viewport(
|
||||||
output.x,
|
output.x,
|
||||||
output.y,
|
output.y,
|
||||||
framebuffer.size.width as GLsizei,
|
framebuffer_size.width as GLsizei,
|
||||||
framebuffer.size.height as GLsizei,
|
framebuffer_size.height as GLsizei,
|
||||||
);
|
);
|
||||||
|
|
||||||
if framebuffer.format == gl::SRGB8_ALPHA8 {
|
if framebuffer.format() == gl::SRGB8_ALPHA8 {
|
||||||
gl::Enable(gl::FRAMEBUFFER_SRGB);
|
gl::Enable(gl::FRAMEBUFFER_SRGB);
|
||||||
} else {
|
} else {
|
||||||
gl::Disable(gl::FRAMEBUFFER_SRGB);
|
gl::Disable(gl::FRAMEBUFFER_SRGB);
|
||||||
|
@ -100,14 +100,10 @@ impl FilterPass {
|
||||||
gl::BindFramebuffer(gl::FRAMEBUFFER, 0);
|
gl::BindFramebuffer(gl::FRAMEBUFFER, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bind_texture(samplers: &SamplerSet, binding: &TextureBinding, texture: &Texture) {
|
|
||||||
Gl3BindTexture::bind_texture(samplers, binding, texture)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl FilterPass {
|
impl <T: GLInterface> FilterPass<T> {
|
||||||
pub fn get_format(&self) -> ImageFormat {
|
pub fn get_format(&self) -> ImageFormat {
|
||||||
let mut fb_format = ImageFormat::R8G8B8A8Unorm;
|
let mut fb_format = ImageFormat::R8G8B8A8Unorm;
|
||||||
if self.config.srgb_framebuffer {
|
if self.config.srgb_framebuffer {
|
||||||
|
@ -127,7 +123,7 @@ impl FilterPass {
|
||||||
frame_count: u32,
|
frame_count: u32,
|
||||||
frame_direction: i32,
|
frame_direction: i32,
|
||||||
fb_size: Size<u32>,
|
fb_size: Size<u32>,
|
||||||
viewport: &Viewport,
|
viewport: &Viewport<T::Framebuffer>,
|
||||||
original: &Texture,
|
original: &Texture,
|
||||||
source: &Texture,
|
source: &Texture,
|
||||||
) {
|
) {
|
||||||
|
@ -151,7 +147,7 @@ impl FilterPass {
|
||||||
.uniform_bindings
|
.uniform_bindings
|
||||||
.get(&VariableSemantics::FinalViewport.into())
|
.get(&VariableSemantics::FinalViewport.into())
|
||||||
{
|
{
|
||||||
self.uniform_storage.bind_vec4(*offset,viewport.output.size, location.location());
|
self.uniform_storage.bind_vec4(*offset,viewport.output.size(), location.location());
|
||||||
}
|
}
|
||||||
|
|
||||||
// bind FrameCount
|
// bind FrameCount
|
||||||
|
@ -177,7 +173,7 @@ impl FilterPass {
|
||||||
.texture_meta
|
.texture_meta
|
||||||
.get(&TextureSemantics::Original.semantics(0))
|
.get(&TextureSemantics::Original.semantics(0))
|
||||||
{
|
{
|
||||||
Self::bind_texture(&parent.samplers, binding, original);
|
T::BindTexture::bind_texture(&parent.samplers, binding, original);
|
||||||
}
|
}
|
||||||
|
|
||||||
// bind OriginalSize
|
// bind OriginalSize
|
||||||
|
@ -197,7 +193,7 @@ impl FilterPass {
|
||||||
.get(&TextureSemantics::Source.semantics(0))
|
.get(&TextureSemantics::Source.semantics(0))
|
||||||
{
|
{
|
||||||
// eprintln!("setting source binding to {}", binding.binding);
|
// eprintln!("setting source binding to {}", binding.binding);
|
||||||
Self::bind_texture(&parent.samplers, binding, source);
|
T::BindTexture::bind_texture(&parent.samplers, binding, source);
|
||||||
}
|
}
|
||||||
|
|
||||||
// bind SourceSize
|
// bind SourceSize
|
||||||
|
@ -215,7 +211,7 @@ impl FilterPass {
|
||||||
.texture_meta
|
.texture_meta
|
||||||
.get(&TextureSemantics::OriginalHistory.semantics(0))
|
.get(&TextureSemantics::OriginalHistory.semantics(0))
|
||||||
{
|
{
|
||||||
Self::bind_texture(&parent.samplers, binding, original);
|
T::BindTexture::bind_texture(&parent.samplers, binding, original);
|
||||||
}
|
}
|
||||||
if let Some((location, offset)) = self
|
if let Some((location, offset)) = self
|
||||||
.uniform_bindings
|
.uniform_bindings
|
||||||
|
@ -235,7 +231,7 @@ impl FilterPass {
|
||||||
.texture_meta
|
.texture_meta
|
||||||
.get(&TextureSemantics::OriginalHistory.semantics(index + 1))
|
.get(&TextureSemantics::OriginalHistory.semantics(index + 1))
|
||||||
{
|
{
|
||||||
Self::bind_texture(&parent.samplers, binding, output);
|
T::BindTexture::bind_texture(&parent.samplers, binding, output);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some((location, offset)) = self.uniform_bindings.get(
|
if let Some((location, offset)) = self.uniform_bindings.get(
|
||||||
|
@ -259,7 +255,7 @@ impl FilterPass {
|
||||||
.texture_meta
|
.texture_meta
|
||||||
.get(&TextureSemantics::PassOutput.semantics(index))
|
.get(&TextureSemantics::PassOutput.semantics(index))
|
||||||
{
|
{
|
||||||
Self::bind_texture(&parent.samplers, binding, output);
|
T::BindTexture::bind_texture(&parent.samplers, binding, output);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some((location, offset)) = self
|
if let Some((location, offset)) = self
|
||||||
|
@ -282,10 +278,7 @@ impl FilterPass {
|
||||||
.texture_meta
|
.texture_meta
|
||||||
.get(&TextureSemantics::PassFeedback.semantics(index))
|
.get(&TextureSemantics::PassFeedback.semantics(index))
|
||||||
{
|
{
|
||||||
if feedback.image.handle == 0 {
|
T::BindTexture::bind_texture(&parent.samplers, binding, feedback);
|
||||||
eprintln!("[WARNING] trying to bind PassFeedback: {index} which has texture 0 to slot {} in pass {pass_index}", binding.binding)
|
|
||||||
}
|
|
||||||
Self::bind_texture(&parent.samplers, binding, feedback);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some((location, offset)) = self
|
if let Some((location, offset)) = self
|
||||||
|
@ -334,7 +327,7 @@ impl FilterPass {
|
||||||
.texture_meta
|
.texture_meta
|
||||||
.get(&TextureSemantics::User.semantics(*index))
|
.get(&TextureSemantics::User.semantics(*index))
|
||||||
{
|
{
|
||||||
Self::bind_texture(&parent.samplers, binding, lut);
|
T::BindTexture::bind_texture(&parent.samplers, binding, lut);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some((location, offset)) = self
|
if let Some((location, offset)) = self
|
||||||
|
|
|
@ -6,18 +6,17 @@ use librashader_presets::{Scale2D, ScaleType, Scaling};
|
||||||
use crate::error::FilterChainError;
|
use crate::error::FilterChainError;
|
||||||
use crate::error::Result;
|
use crate::error::Result;
|
||||||
use crate::gl::Framebuffer;
|
use crate::gl::Framebuffer;
|
||||||
use crate::gl::gl3::Gl3Framebuffer;
|
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
pub struct Viewport<'a> {
|
pub struct Viewport<'a, T: Framebuffer + ?Sized> {
|
||||||
pub x: i32,
|
pub x: i32,
|
||||||
pub y: i32,
|
pub y: i32,
|
||||||
pub output: &'a Gl3Framebuffer,
|
pub output: &'a T,
|
||||||
pub mvp: Option<&'a [f32; 16]>,
|
pub mvp: Option<&'a [f32; 16]>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Debug, Copy, Clone)]
|
#[derive(Default, Debug, Copy, Clone)]
|
||||||
pub struct GlImage {
|
pub struct GLImage {
|
||||||
pub handle: GLuint,
|
pub handle: GLuint,
|
||||||
pub format: GLenum,
|
pub format: GLenum,
|
||||||
pub size: Size<u32>,
|
pub size: Size<u32>,
|
||||||
|
|
|
@ -1,24 +1,39 @@
|
||||||
use gl::types::{GLenum, GLint, GLsizei, GLuint};
|
use gl::types::{GLenum, GLint, GLsizei, GLuint};
|
||||||
use librashader_common::{FilterMode, ImageFormat, Size, WrapMode};
|
use librashader_common::{FilterMode, ImageFormat, Size, WrapMode};
|
||||||
use librashader_presets::Scale2D;
|
use librashader_presets::Scale2D;
|
||||||
use crate::{GlImage, Viewport};
|
use crate::framebuffer::{GLImage, Viewport};
|
||||||
use crate::error::{FilterChainError, Result};
|
use crate::error::{FilterChainError, Result};
|
||||||
use crate::gl::Framebuffer;
|
use crate::gl::Framebuffer;
|
||||||
use crate::texture::Texture;
|
use crate::texture::Texture;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Gl3Framebuffer {
|
pub struct Gl3Framebuffer {
|
||||||
pub image: GLuint,
|
image: GLuint,
|
||||||
pub handle: GLuint,
|
handle: GLuint,
|
||||||
pub size: Size<u32>,
|
size: Size<u32>,
|
||||||
pub format: GLenum,
|
format: GLenum,
|
||||||
pub max_levels: u32,
|
max_levels: u32,
|
||||||
pub mip_levels: u32,
|
mip_levels: u32,
|
||||||
is_raw: bool,
|
is_raw: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl Framebuffer for Gl3Framebuffer {
|
impl Framebuffer for Gl3Framebuffer {
|
||||||
|
fn handle(&self) -> GLuint {
|
||||||
|
self.handle
|
||||||
|
}
|
||||||
|
|
||||||
|
fn size(&self) -> Size<u32> {
|
||||||
|
self.size
|
||||||
|
}
|
||||||
|
|
||||||
|
fn image(&self) -> GLuint {
|
||||||
|
self.image
|
||||||
|
}
|
||||||
|
|
||||||
|
fn format(&self) -> GLenum {
|
||||||
|
self.format
|
||||||
|
}
|
||||||
|
|
||||||
fn new(max_levels: u32) -> Gl3Framebuffer {
|
fn new(max_levels: u32) -> Gl3Framebuffer {
|
||||||
let mut framebuffer = 0;
|
let mut framebuffer = 0;
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -59,7 +74,7 @@ impl Framebuffer for Gl3Framebuffer {
|
||||||
}
|
}
|
||||||
fn as_texture(&self, filter: FilterMode, wrap_mode: WrapMode) -> Texture {
|
fn as_texture(&self, filter: FilterMode, wrap_mode: WrapMode) -> Texture {
|
||||||
Texture {
|
Texture {
|
||||||
image: GlImage {
|
image: GLImage {
|
||||||
handle: self.image,
|
handle: self.image,
|
||||||
format: self.format,
|
format: self.format,
|
||||||
size: self.size,
|
size: self.size,
|
||||||
|
@ -74,7 +89,7 @@ impl Framebuffer for Gl3Framebuffer {
|
||||||
&mut self,
|
&mut self,
|
||||||
scaling: Scale2D,
|
scaling: Scale2D,
|
||||||
format: ImageFormat,
|
format: ImageFormat,
|
||||||
viewport: &Viewport,
|
viewport: &Viewport<Self>,
|
||||||
_original: &Texture,
|
_original: &Texture,
|
||||||
source: &Texture,
|
source: &Texture,
|
||||||
) -> Result<Size<u32>> {
|
) -> Result<Size<u32>> {
|
||||||
|
@ -111,7 +126,7 @@ impl Framebuffer for Gl3Framebuffer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn copy_from(&mut self, image: &GlImage) -> Result<()> {
|
fn copy_from(&mut self, image: &GLImage) -> Result<()> {
|
||||||
// todo: may want to use a shader and draw a quad to be faster.
|
// todo: may want to use a shader and draw a quad to be faster.
|
||||||
if image.size != self.size || image.format != self.format {
|
if image.size != self.size || image.format != self.format {
|
||||||
self.init(image.size, image.format)?;
|
self.init(image.size, image.format)?;
|
||||||
|
|
|
@ -8,9 +8,9 @@ use gl::types::{GLchar, GLenum, GLint, GLsizei, GLuint};
|
||||||
use librashader_common::Size;
|
use librashader_common::Size;
|
||||||
|
|
||||||
use crate::filter_chain::FilterChain;
|
use crate::filter_chain::FilterChain;
|
||||||
use crate::framebuffer::{GlImage, Viewport};
|
use crate::framebuffer::{GLImage, Viewport};
|
||||||
use crate::gl::Framebuffer;
|
use crate::gl::{Framebuffer, GLInterface};
|
||||||
use crate::gl::gl3::Gl3Framebuffer;
|
use crate::gl::gl3::CompatibilityGL;
|
||||||
|
|
||||||
const WIDTH: u32 = 900;
|
const WIDTH: u32 = 900;
|
||||||
const HEIGHT: u32 = 700;
|
const HEIGHT: u32 = 700;
|
||||||
|
@ -267,7 +267,7 @@ pub fn do_loop(
|
||||||
events: Receiver<(f64, WindowEvent)>,
|
events: Receiver<(f64, WindowEvent)>,
|
||||||
triangle_program: GLuint,
|
triangle_program: GLuint,
|
||||||
triangle_vao: GLuint,
|
triangle_vao: GLuint,
|
||||||
filter: &mut FilterChain,
|
filter: &mut FilterChain<CompatibilityGL>,
|
||||||
) {
|
) {
|
||||||
let mut framecount = 0;
|
let mut framecount = 0;
|
||||||
let mut rendered_framebuffer = 0;
|
let mut rendered_framebuffer = 0;
|
||||||
|
@ -464,7 +464,7 @@ void main()
|
||||||
let (fb_width, fb_height) = window.get_framebuffer_size();
|
let (fb_width, fb_height) = window.get_framebuffer_size();
|
||||||
let (vp_width, vp_height) = window.get_size();
|
let (vp_width, vp_height) = window.get_size();
|
||||||
|
|
||||||
let output = Gl3Framebuffer::new_from_raw(
|
let output = <CompatibilityGL as GLInterface>::Framebuffer::new_from_raw(
|
||||||
output_texture,
|
output_texture,
|
||||||
output_framebuffer_handle,
|
output_framebuffer_handle,
|
||||||
gl::RGBA8,
|
gl::RGBA8,
|
||||||
|
@ -509,7 +509,7 @@ void main()
|
||||||
mvp: None,
|
mvp: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let rendered = GlImage {
|
let rendered = GLImage {
|
||||||
handle: rendered_texture,
|
handle: rendered_texture,
|
||||||
format: gl::RGBA8,
|
format: gl::RGBA8,
|
||||||
size: Size {
|
size: Size {
|
|
@ -4,7 +4,7 @@ use librashader_common::image::Image;
|
||||||
use librashader_common::Size;
|
use librashader_common::Size;
|
||||||
use librashader_presets::TextureConfig;
|
use librashader_presets::TextureConfig;
|
||||||
use crate::gl::LoadLut;
|
use crate::gl::LoadLut;
|
||||||
use crate::{GlImage, util};
|
use crate::framebuffer::{GLImage, Viewport};
|
||||||
use crate::texture::Texture;
|
use crate::texture::Texture;
|
||||||
use crate::error::Result;
|
use crate::error::Result;
|
||||||
|
|
||||||
|
@ -64,7 +64,7 @@ impl LoadLut for Gl3LutLoad {
|
||||||
luts.insert(
|
luts.insert(
|
||||||
index,
|
index,
|
||||||
Texture {
|
Texture {
|
||||||
image: GlImage {
|
image: GLImage {
|
||||||
handle,
|
handle,
|
||||||
format: gl::RGBA8,
|
format: gl::RGBA8,
|
||||||
size: image.size,
|
size: image.size,
|
||||||
|
|
|
@ -3,9 +3,21 @@ mod draw_quad;
|
||||||
mod ubo_ring;
|
mod ubo_ring;
|
||||||
mod framebuffer;
|
mod framebuffer;
|
||||||
mod texture_bind;
|
mod texture_bind;
|
||||||
|
#[cfg(test)]
|
||||||
|
pub mod hello_triangle;
|
||||||
|
|
||||||
pub use lut_load::*;
|
use lut_load::*;
|
||||||
pub use draw_quad::*;
|
use draw_quad::*;
|
||||||
pub use ubo_ring::*;
|
use ubo_ring::*;
|
||||||
pub use framebuffer::*;
|
use framebuffer::*;
|
||||||
pub use texture_bind::*;
|
use texture_bind::*;
|
||||||
|
use crate::gl::GLInterface;
|
||||||
|
|
||||||
|
pub struct CompatibilityGL;
|
||||||
|
impl GLInterface for CompatibilityGL {
|
||||||
|
type Framebuffer = Gl3Framebuffer;
|
||||||
|
type UboRing = Gl3UboRing<16>;
|
||||||
|
type DrawQuad = Gl3DrawQuad;
|
||||||
|
type LoadLut = Gl3LutLoad;
|
||||||
|
type BindTexture = Gl3BindTexture;
|
||||||
|
}
|
||||||
|
|
|
@ -1,30 +1,44 @@
|
||||||
use gl::types::{GLenum, GLint, GLsizei, GLuint};
|
use gl::types::{GLenum, GLint, GLsizei, GLuint};
|
||||||
use librashader_common::{FilterMode, ImageFormat, Size, WrapMode};
|
use librashader_common::{FilterMode, ImageFormat, Size, WrapMode};
|
||||||
use librashader_presets::Scale2D;
|
use librashader_presets::Scale2D;
|
||||||
use crate::{GlImage, Viewport};
|
use crate::framebuffer::{GLImage, Viewport};
|
||||||
use crate::error::{FilterChainError, Result};
|
use crate::error::{FilterChainError, Result};
|
||||||
use crate::gl::Framebuffer;
|
use crate::gl::Framebuffer;
|
||||||
use crate::texture::Texture;
|
use crate::texture::Texture;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Gl46Framebuffer {
|
pub struct Gl46Framebuffer {
|
||||||
pub image: GLuint,
|
image: GLuint,
|
||||||
pub handle: GLuint,
|
handle: GLuint,
|
||||||
pub size: Size<u32>,
|
size: Size<u32>,
|
||||||
pub format: GLenum,
|
format: GLenum,
|
||||||
pub max_levels: u32,
|
max_levels: u32,
|
||||||
pub mip_levels: u32,
|
levels: u32,
|
||||||
is_raw: bool,
|
is_raw: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl Framebuffer for Gl46Framebuffer {
|
impl Framebuffer for Gl46Framebuffer {
|
||||||
|
fn handle(&self) -> GLuint {
|
||||||
|
self.handle
|
||||||
|
}
|
||||||
|
|
||||||
|
fn size(&self) -> Size<u32> {
|
||||||
|
self.size
|
||||||
|
}
|
||||||
|
|
||||||
|
fn image(&self) -> GLuint {
|
||||||
|
self.image
|
||||||
|
}
|
||||||
|
|
||||||
|
fn format(&self) -> GLenum {
|
||||||
|
self.format
|
||||||
|
}
|
||||||
|
|
||||||
fn new(max_levels: u32) -> Gl46Framebuffer {
|
fn new(max_levels: u32) -> Gl46Framebuffer {
|
||||||
let mut framebuffer = 0;
|
let mut framebuffer = 0;
|
||||||
unsafe {
|
unsafe {
|
||||||
gl::GenFramebuffers(1, &mut framebuffer);
|
gl::CreateFramebuffers(1, &mut framebuffer);
|
||||||
gl::BindFramebuffer(gl::FRAMEBUFFER, framebuffer);
|
|
||||||
gl::BindFramebuffer(gl::FRAMEBUFFER, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Gl46Framebuffer {
|
Gl46Framebuffer {
|
||||||
|
@ -35,7 +49,7 @@ impl Framebuffer for Gl46Framebuffer {
|
||||||
},
|
},
|
||||||
format: 0,
|
format: 0,
|
||||||
max_levels,
|
max_levels,
|
||||||
mip_levels: 0,
|
levels: 0,
|
||||||
handle: framebuffer,
|
handle: framebuffer,
|
||||||
is_raw: false,
|
is_raw: false,
|
||||||
}
|
}
|
||||||
|
@ -52,14 +66,14 @@ impl Framebuffer for Gl46Framebuffer {
|
||||||
size,
|
size,
|
||||||
format,
|
format,
|
||||||
max_levels: miplevels,
|
max_levels: miplevels,
|
||||||
mip_levels: miplevels,
|
levels: miplevels,
|
||||||
handle,
|
handle,
|
||||||
is_raw: true,
|
is_raw: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn as_texture(&self, filter: FilterMode, wrap_mode: WrapMode) -> Texture {
|
fn as_texture(&self, filter: FilterMode, wrap_mode: WrapMode) -> Texture {
|
||||||
Texture {
|
Texture {
|
||||||
image: GlImage {
|
image: GLImage {
|
||||||
handle: self.image,
|
handle: self.image,
|
||||||
format: self.format,
|
format: self.format,
|
||||||
size: self.size,
|
size: self.size,
|
||||||
|
@ -74,7 +88,7 @@ impl Framebuffer for Gl46Framebuffer {
|
||||||
&mut self,
|
&mut self,
|
||||||
scaling: Scale2D,
|
scaling: Scale2D,
|
||||||
format: ImageFormat,
|
format: ImageFormat,
|
||||||
viewport: &Viewport,
|
viewport: &Viewport<Self>,
|
||||||
_original: &Texture,
|
_original: &Texture,
|
||||||
source: &Texture,
|
source: &Texture,
|
||||||
) -> Result<Size<u32>> {
|
) -> Result<Size<u32>> {
|
||||||
|
@ -100,83 +114,27 @@ impl Framebuffer for Gl46Framebuffer {
|
||||||
}
|
}
|
||||||
fn clear<const REBIND: bool>(&self) {
|
fn clear<const REBIND: bool>(&self) {
|
||||||
unsafe {
|
unsafe {
|
||||||
if REBIND {
|
gl::ClearNamedFramebufferfv(self.handle,
|
||||||
gl::BindFramebuffer(gl::FRAMEBUFFER, self.handle);
|
gl::COLOR, 0,
|
||||||
}
|
[0.0f32, 0.0, 0.0, 0.0].as_ptr().cast());
|
||||||
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<()> {
|
fn copy_from(&mut self, image: &GLImage) -> Result<()> {
|
||||||
// todo: may want to use a shader and draw a quad to be faster.
|
// todo: may want to use a shader and draw a quad to be faster.
|
||||||
if image.size != self.size || image.format != self.format {
|
if image.size != self.size || image.format != self.format {
|
||||||
self.init(image.size, image.format)?;
|
self.init(image.size, image.format)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
gl::BindFramebuffer(gl::FRAMEBUFFER, self.handle);
|
// gl::NamedFramebufferDrawBuffer(self.handle, gl::COLOR_ATTACHMENT1);
|
||||||
|
gl::NamedFramebufferReadBuffer(image.handle, gl::COLOR_ATTACHMENT0);
|
||||||
|
gl::NamedFramebufferDrawBuffer(self.handle, gl::COLOR_ATTACHMENT1);
|
||||||
|
|
||||||
gl::FramebufferTexture2D(
|
gl::BlitNamedFramebuffer(image.handle, self.handle,
|
||||||
gl::READ_FRAMEBUFFER,
|
0, 0, image.size.width as GLint, image.size.height as GLint,
|
||||||
gl::COLOR_ATTACHMENT0,
|
0, 0, self.size.width as GLint, self.size.height as GLint,
|
||||||
gl::TEXTURE_2D,
|
gl::COLOR_BUFFER_BIT, gl::NEAREST);
|
||||||
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(())
|
Ok(())
|
||||||
|
@ -189,22 +147,18 @@ impl Framebuffer for Gl46Framebuffer {
|
||||||
self.size = size;
|
self.size = size;
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
gl::BindFramebuffer(gl::FRAMEBUFFER, self.handle);
|
|
||||||
|
|
||||||
// reset the framebuffer image
|
// reset the framebuffer image
|
||||||
if self.image != 0 {
|
if self.image != 0 {
|
||||||
gl::FramebufferTexture2D(
|
gl::NamedFramebufferTexture(
|
||||||
gl::FRAMEBUFFER,
|
self.handle,
|
||||||
gl::COLOR_ATTACHMENT0,
|
gl::COLOR_ATTACHMENT0,
|
||||||
gl::TEXTURE_2D,
|
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
);
|
);
|
||||||
gl::DeleteTextures(1, &self.image);
|
gl::DeleteTextures(1, &self.image);
|
||||||
}
|
}
|
||||||
|
|
||||||
gl::GenTextures(1, &mut self.image);
|
gl::CreateTextures(gl::TEXTURE_2D,1, &mut self.image);
|
||||||
gl::BindTexture(gl::TEXTURE_2D, self.image);
|
|
||||||
|
|
||||||
if size.width == 0 {
|
if size.width == 0 {
|
||||||
size.width = 1;
|
size.width = 1;
|
||||||
|
@ -213,26 +167,25 @@ impl Framebuffer for Gl46Framebuffer {
|
||||||
size.height = 1;
|
size.height = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.mip_levels = librashader_runtime::scaling::calc_miplevel(size);
|
self.levels = librashader_runtime::scaling::calc_miplevel(size);
|
||||||
if self.mip_levels > self.max_levels {
|
if self.levels > self.max_levels {
|
||||||
self.mip_levels = self.max_levels;
|
self.levels = self.max_levels;
|
||||||
}
|
}
|
||||||
if self.mip_levels == 0 {
|
if self.levels == 0 {
|
||||||
self.mip_levels = 1;
|
self.levels = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
gl::TexStorage2D(
|
gl::TextureStorage2D(
|
||||||
gl::TEXTURE_2D,
|
self.image,
|
||||||
self.mip_levels as GLsizei,
|
self.levels as GLsizei,
|
||||||
self.format,
|
self.format,
|
||||||
size.width as GLsizei,
|
size.width as GLsizei,
|
||||||
size.height as GLsizei,
|
size.height as GLsizei,
|
||||||
);
|
);
|
||||||
|
|
||||||
gl::FramebufferTexture2D(
|
gl::NamedFramebufferTexture(
|
||||||
gl::FRAMEBUFFER,
|
self.handle,
|
||||||
gl::COLOR_ATTACHMENT0,
|
gl::COLOR_ATTACHMENT0,
|
||||||
gl::TEXTURE_2D,
|
|
||||||
self.image,
|
self.image,
|
||||||
0,
|
0,
|
||||||
);
|
);
|
||||||
|
@ -243,36 +196,33 @@ impl Framebuffer for Gl46Framebuffer {
|
||||||
gl::FRAMEBUFFER_UNSUPPORTED => {
|
gl::FRAMEBUFFER_UNSUPPORTED => {
|
||||||
eprintln!("unsupported fbo");
|
eprintln!("unsupported fbo");
|
||||||
|
|
||||||
gl::FramebufferTexture2D(
|
gl::NamedFramebufferTexture(
|
||||||
gl::FRAMEBUFFER,
|
self.handle,
|
||||||
gl::COLOR_ATTACHMENT0,
|
gl::COLOR_ATTACHMENT0,
|
||||||
gl::TEXTURE_2D,
|
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
);
|
);
|
||||||
gl::DeleteTextures(1, &self.image);
|
gl::DeleteTextures(1, &self.image);
|
||||||
gl::GenTextures(1, &mut self.image);
|
gl::CreateTextures(gl::TEXTURE_2D, 1, &mut self.image);
|
||||||
gl::BindTexture(gl::TEXTURE_2D, self.image);
|
|
||||||
|
|
||||||
self.mip_levels = librashader_runtime::scaling::calc_miplevel(size);
|
self.levels = librashader_runtime::scaling::calc_miplevel(size);
|
||||||
if self.mip_levels > self.max_levels {
|
if self.levels > self.max_levels {
|
||||||
self.mip_levels = self.max_levels;
|
self.levels = self.max_levels;
|
||||||
}
|
}
|
||||||
if self.mip_levels == 0 {
|
if self.levels == 0 {
|
||||||
self.mip_levels = 1;
|
self.levels = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
gl::TexStorage2D(
|
gl::TextureStorage2D(
|
||||||
gl::TEXTURE_2D,
|
self.image,
|
||||||
self.mip_levels as GLsizei,
|
self.levels as GLsizei,
|
||||||
ImageFormat::R8G8B8A8Unorm.into(),
|
ImageFormat::R8G8B8A8Unorm.into(),
|
||||||
size.width as GLsizei,
|
size.width as GLsizei,
|
||||||
size.height as GLsizei,
|
size.height as GLsizei,
|
||||||
);
|
);
|
||||||
gl::FramebufferTexture2D(
|
gl::NamedFramebufferTexture(
|
||||||
gl::FRAMEBUFFER,
|
self.handle,
|
||||||
gl::COLOR_ATTACHMENT0,
|
gl::COLOR_ATTACHMENT0,
|
||||||
gl::TEXTURE_2D,
|
|
||||||
self.image,
|
self.image,
|
||||||
0,
|
0,
|
||||||
);
|
);
|
||||||
|
@ -282,11 +232,7 @@ impl Framebuffer for Gl46Framebuffer {
|
||||||
_ => return Err(FilterChainError::FramebufferInit(status))
|
_ => return Err(FilterChainError::FramebufferInit(status))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
gl::BindFramebuffer(gl::FRAMEBUFFER, 0);
|
|
||||||
gl::BindTexture(gl::TEXTURE_2D, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,9 @@ use gl::types::{GLchar, GLenum, GLint, GLsizei, GLuint};
|
||||||
use librashader_common::Size;
|
use librashader_common::Size;
|
||||||
|
|
||||||
use crate::filter_chain::FilterChain;
|
use crate::filter_chain::FilterChain;
|
||||||
use crate::framebuffer::{Framebuffer, GlImage, Viewport};
|
use crate::framebuffer::{GLImage, Viewport};
|
||||||
|
use crate::gl::{Framebuffer, GLInterface};
|
||||||
|
use crate::gl::gl46::DirectStateAccessGL;
|
||||||
|
|
||||||
const WIDTH: u32 = 900;
|
const WIDTH: u32 = 900;
|
||||||
const HEIGHT: u32 = 700;
|
const HEIGHT: u32 = 700;
|
||||||
|
@ -256,7 +258,7 @@ pub fn do_loop(
|
||||||
events: Receiver<(f64, WindowEvent)>,
|
events: Receiver<(f64, WindowEvent)>,
|
||||||
triangle_program: GLuint,
|
triangle_program: GLuint,
|
||||||
triangle_vao: GLuint,
|
triangle_vao: GLuint,
|
||||||
filter: &mut FilterChain,
|
filter: &mut FilterChain<DirectStateAccessGL>,
|
||||||
) {
|
) {
|
||||||
let mut framecount = 0;
|
let mut framecount = 0;
|
||||||
let mut rendered_framebuffer = 0;
|
let mut rendered_framebuffer = 0;
|
||||||
|
@ -445,7 +447,7 @@ void main()
|
||||||
let (fb_width, fb_height) = window.get_framebuffer_size();
|
let (fb_width, fb_height) = window.get_framebuffer_size();
|
||||||
let (vp_width, vp_height) = window.get_size();
|
let (vp_width, vp_height) = window.get_size();
|
||||||
|
|
||||||
let output = Framebuffer::new_from_raw(
|
let output = <DirectStateAccessGL as GLInterface>::Framebuffer::new_from_raw(
|
||||||
output_texture,
|
output_texture,
|
||||||
output_framebuffer_handle,
|
output_framebuffer_handle,
|
||||||
gl::RGBA8,
|
gl::RGBA8,
|
||||||
|
@ -488,7 +490,7 @@ void main()
|
||||||
mvp: None,
|
mvp: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let rendered = GlImage {
|
let rendered = GLImage {
|
||||||
handle: rendered_texture,
|
handle: rendered_texture,
|
||||||
format: gl::RGBA8,
|
format: gl::RGBA8,
|
||||||
size: Size {
|
size: Size {
|
|
@ -4,7 +4,7 @@ use librashader_common::image::Image;
|
||||||
use librashader_common::Size;
|
use librashader_common::Size;
|
||||||
use librashader_presets::TextureConfig;
|
use librashader_presets::TextureConfig;
|
||||||
use crate::gl::LoadLut;
|
use crate::gl::LoadLut;
|
||||||
use crate::{GlImage, util};
|
use crate::framebuffer::{GLImage, Viewport};
|
||||||
use crate::texture::Texture;
|
use crate::texture::Texture;
|
||||||
use crate::error::Result;
|
use crate::error::Result;
|
||||||
|
|
||||||
|
@ -64,7 +64,7 @@ impl LoadLut for Gl46LutLoad {
|
||||||
luts.insert(
|
luts.insert(
|
||||||
index,
|
index,
|
||||||
Texture {
|
Texture {
|
||||||
image: GlImage {
|
image: GLImage {
|
||||||
handle,
|
handle,
|
||||||
format: gl::RGBA8,
|
format: gl::RGBA8,
|
||||||
size: image.size,
|
size: image.size,
|
||||||
|
|
|
@ -4,8 +4,21 @@ mod ubo_ring;
|
||||||
mod framebuffer;
|
mod framebuffer;
|
||||||
mod texture_bind;
|
mod texture_bind;
|
||||||
|
|
||||||
pub use lut_load::*;
|
#[cfg(test)]
|
||||||
pub use draw_quad::*;
|
pub mod hello_triangle;
|
||||||
pub use ubo_ring::*;
|
|
||||||
pub use framebuffer::*;
|
use lut_load::*;
|
||||||
pub use texture_bind::*;
|
use draw_quad::*;
|
||||||
|
use ubo_ring::*;
|
||||||
|
use framebuffer::*;
|
||||||
|
use texture_bind::*;
|
||||||
|
use crate::gl::GLInterface;
|
||||||
|
|
||||||
|
pub struct DirectStateAccessGL;
|
||||||
|
impl GLInterface for DirectStateAccessGL {
|
||||||
|
type Framebuffer = Gl46Framebuffer;
|
||||||
|
type UboRing = Gl46UboRing<16>;
|
||||||
|
type DrawQuad = Gl46DrawQuad;
|
||||||
|
type LoadLut = Gl46LutLoad;
|
||||||
|
type BindTexture = Gl46BindTexture;
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
pub(crate) mod gl3;
|
pub(crate) mod gl3;
|
||||||
mod gl46;
|
pub(crate) mod gl46;
|
||||||
|
|
||||||
use gl::types::{GLenum, GLint, GLsizei, GLuint};
|
use gl::types::{GLenum, GLint, GLsizei, GLuint};
|
||||||
use rustc_hash::FxHashMap;
|
use rustc_hash::FxHashMap;
|
||||||
|
@ -10,7 +10,7 @@ use librashader_runtime::uniforms::{UniformStorage, UniformStorageAccess};
|
||||||
use crate::binding::UniformLocation;
|
use crate::binding::UniformLocation;
|
||||||
use crate::texture::Texture;
|
use crate::texture::Texture;
|
||||||
use crate::error::{FilterChainError, Result};
|
use crate::error::{FilterChainError, Result};
|
||||||
use crate::{GlImage, Viewport};
|
use crate::framebuffer::{GLImage, Viewport};
|
||||||
use crate::samplers::SamplerSet;
|
use crate::samplers::SamplerSet;
|
||||||
|
|
||||||
pub trait LoadLut {
|
pub trait LoadLut {
|
||||||
|
@ -42,15 +42,27 @@ pub trait Framebuffer {
|
||||||
&mut self,
|
&mut self,
|
||||||
scaling: Scale2D,
|
scaling: Scale2D,
|
||||||
format: ImageFormat,
|
format: ImageFormat,
|
||||||
viewport: &Viewport,
|
viewport: &Viewport<Self>,
|
||||||
_original: &Texture,
|
_original: &Texture,
|
||||||
source: &Texture,
|
source: &Texture,
|
||||||
) -> Result<Size<u32>>;
|
) -> Result<Size<u32>>;
|
||||||
fn clear<const REBIND: bool>(&self);
|
fn clear<const REBIND: bool>(&self);
|
||||||
fn copy_from(&mut self, image: &GlImage) -> Result<()>;
|
fn copy_from(&mut self, image: &GLImage) -> Result<()>;
|
||||||
fn init(&mut self, size: Size<u32>, format: impl Into<GLenum>) -> Result<()>;
|
fn init(&mut self, size: Size<u32>, format: impl Into<GLenum>) -> Result<()>;
|
||||||
|
fn handle(&self) -> GLuint;
|
||||||
|
fn image(&self) -> GLuint;
|
||||||
|
fn size(&self) -> Size<u32>;
|
||||||
|
fn format(&self) -> GLenum;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait BindTexture {
|
pub trait BindTexture {
|
||||||
fn bind_texture(samplers: &SamplerSet, binding: &TextureBinding, texture: &Texture);
|
fn bind_texture(samplers: &SamplerSet, binding: &TextureBinding, texture: &Texture);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait GLInterface {
|
||||||
|
type Framebuffer: Framebuffer;
|
||||||
|
type UboRing: UboRing<16>;
|
||||||
|
type DrawQuad: DrawQuad;
|
||||||
|
type LoadLut: LoadLut;
|
||||||
|
type BindTexture: BindTexture;
|
||||||
}
|
}
|
|
@ -7,19 +7,28 @@ mod filter_pass;
|
||||||
mod framebuffer;
|
mod framebuffer;
|
||||||
mod render_target;
|
mod render_target;
|
||||||
mod util;
|
mod util;
|
||||||
pub mod error;
|
|
||||||
|
|
||||||
mod samplers;
|
mod samplers;
|
||||||
|
mod texture;
|
||||||
|
pub mod options;
|
||||||
|
mod gl;
|
||||||
|
|
||||||
|
|
||||||
|
pub mod error;
|
||||||
pub use filter_chain::FilterChain;
|
pub use filter_chain::FilterChain;
|
||||||
pub use framebuffer::GlImage;
|
|
||||||
pub use framebuffer::Viewport;
|
pub use framebuffer::Viewport;
|
||||||
|
|
||||||
#[cfg(test)]
|
pub mod gl3 {
|
||||||
mod gl3_hello_triangle;
|
pub use super::framebuffer::GLImage;
|
||||||
mod texture;
|
pub type FilterChain = super::filter_chain::FilterChain<super::gl::gl3::CompatibilityGL>;
|
||||||
mod options;
|
pub type Viewport<'a> = super::framebuffer::Viewport<'a, <super::gl::gl3::CompatibilityGL as super::gl::GLInterface>::Framebuffer>;
|
||||||
mod gl;
|
}
|
||||||
|
|
||||||
|
pub mod gl46 {
|
||||||
|
pub use super::framebuffer::GLImage;
|
||||||
|
pub type FilterChain = super::filter_chain::FilterChain<super::gl::gl46::DirectStateAccessGL>;
|
||||||
|
pub type Viewport<'a> = super::framebuffer::Viewport<'a, <super::gl::gl46::DirectStateAccessGL as super::gl::GLInterface>::Framebuffer>;
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
@ -28,11 +37,21 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn triangle_gl() {
|
fn triangle_gl() {
|
||||||
let (glfw, window, events, shader, vao) = gl3_hello_triangle::setup();
|
let (glfw, window, events, shader, vao) = gl::gl3::hello_triangle::setup();
|
||||||
let mut filter =
|
let mut filter =
|
||||||
FilterChain::load_from_path("../test/slang-shaders/vhs/VHSPro.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)
|
// FilterChain::load_from_path("../test/slang-shaders/bezel/Mega_Bezel/Presets/MBZ__0__SMOOTH-ADV.slangp", None)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
gl3_hello_triangle::do_loop(glfw, window, events, shader, vao, &mut filter);
|
gl::gl3::hello_triangle::do_loop(glfw, window, events, shader, vao, &mut filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn triangle_gl46() {
|
||||||
|
let (glfw, window, events, shader, vao) = gl::gl46::hello_triangle::setup();
|
||||||
|
let mut filter =
|
||||||
|
FilterChain::load_from_path("../test/slang-shaders/vhs/VHSPro.slangp", None)
|
||||||
|
// FilterChain::load_from_path("../test/slang-shaders/bezel/Mega_Bezel/Presets/MBZ__0__SMOOTH-ADV.slangp", None)
|
||||||
|
.unwrap();
|
||||||
|
gl::gl46::hello_triangle::do_loop(glfw, window, events, shader, vao, &mut filter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
use crate::framebuffer::Viewport;
|
use crate::framebuffer::Viewport;
|
||||||
use crate::gl::Framebuffer;
|
use crate::gl::Framebuffer;
|
||||||
use crate::gl::gl3::Gl3Framebuffer;
|
|
||||||
|
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
static DEFAULT_MVP: &[f32; 16] = &[
|
static DEFAULT_MVP: &[f32; 16] = &[
|
||||||
|
@ -11,15 +10,15 @@ static DEFAULT_MVP: &[f32; 16] = &[
|
||||||
];
|
];
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
pub(crate) struct RenderTarget<'a> {
|
pub(crate) struct RenderTarget<'a, T: Framebuffer> {
|
||||||
pub mvp: &'a [f32; 16],
|
pub mvp: &'a [f32; 16],
|
||||||
pub framebuffer: &'a Gl3Framebuffer,
|
pub framebuffer: &'a T,
|
||||||
pub x: i32,
|
pub x: i32,
|
||||||
pub y: i32
|
pub y: i32
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> RenderTarget<'a> {
|
impl<'a, T: Framebuffer> RenderTarget<'a, T> {
|
||||||
pub fn new(backbuffer: &'a Gl3Framebuffer, mvp: Option<&'a [f32; 16]>, x: i32, y: i32) -> Self {
|
pub fn new(backbuffer: &'a T, mvp: Option<&'a [f32; 16]>, x: i32, y: i32) -> Self {
|
||||||
if let Some(mvp) = mvp {
|
if let Some(mvp) = mvp {
|
||||||
RenderTarget {
|
RenderTarget {
|
||||||
framebuffer: backbuffer,
|
framebuffer: backbuffer,
|
||||||
|
@ -38,8 +37,8 @@ impl<'a> RenderTarget<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> From<&Viewport<'a>> for RenderTarget<'a> {
|
impl<'a, T: Framebuffer> From<&Viewport<'a, T>> for RenderTarget<'a, T> {
|
||||||
fn from(value: &Viewport<'a>) -> Self {
|
fn from(value: &Viewport<'a, T>) -> Self {
|
||||||
RenderTarget::new(value.output, value.mvp, value.x, value.y)
|
RenderTarget::new(value.output, value.mvp, value.x, value.y)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
use librashader_common::{FilterMode, WrapMode};
|
use librashader_common::{FilterMode, WrapMode};
|
||||||
use crate::GlImage;
|
use crate::framebuffer::GLImage;
|
||||||
|
|
||||||
#[derive(Default, Debug, Copy, Clone)]
|
#[derive(Default, Debug, Copy, Clone)]
|
||||||
pub struct Texture {
|
pub struct Texture {
|
||||||
pub image: GlImage,
|
pub image: GLImage,
|
||||||
pub filter: FilterMode,
|
pub filter: FilterMode,
|
||||||
pub mip_filter: FilterMode,
|
pub mip_filter: FilterMode,
|
||||||
pub wrap_mode: WrapMode,
|
pub wrap_mode: WrapMode,
|
||||||
|
|
|
@ -1,25 +0,0 @@
|
||||||
[package]
|
|
||||||
name = "librashader-runtime-gl46"
|
|
||||||
version = "0.1.0"
|
|
||||||
edition = "2021"
|
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
librashader-common = { path = "../librashader-common", features = ["opengl"] }
|
|
||||||
librashader-presets = { path = "../librashader-presets" }
|
|
||||||
librashader-preprocess = { path = "../librashader-preprocess" }
|
|
||||||
librashader-reflect = { path = "../librashader-reflect" }
|
|
||||||
librashader-runtime = { path = "../librashader-runtime" }
|
|
||||||
|
|
||||||
spirv_cross = "0.23.1"
|
|
||||||
rustc-hash = "1.1.0"
|
|
||||||
gl = "0.14.0"
|
|
||||||
bytemuck = "1.12.3"
|
|
||||||
thiserror = "1.0.37"
|
|
||||||
|
|
||||||
[dev-dependencies]
|
|
||||||
glfw = "0.47.0"
|
|
||||||
|
|
||||||
[features]
|
|
||||||
gl4 = []
|
|
|
@ -1,112 +0,0 @@
|
||||||
use gl::types::GLint;
|
|
||||||
use librashader_reflect::reflect::semantics::BindingStage;
|
|
||||||
use librashader_runtime::uniforms::{BindUniform, UniformStorage, UniformScalar};
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum VariableLocation {
|
|
||||||
Ubo(UniformLocation<GLint>),
|
|
||||||
Push(UniformLocation<GLint>),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl VariableLocation {
|
|
||||||
pub fn location(&self) -> UniformLocation<GLint> {
|
|
||||||
match self {
|
|
||||||
VariableLocation::Ubo(l) | VariableLocation::Push(l) => *l,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone)]
|
|
||||||
pub struct UniformLocation<T> {
|
|
||||||
pub vertex: T,
|
|
||||||
pub fragment: T,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl UniformLocation<GLint> {
|
|
||||||
pub fn is_valid(&self, stage: BindingStage) -> bool {
|
|
||||||
let mut validity = false;
|
|
||||||
if stage.contains(BindingStage::FRAGMENT) {
|
|
||||||
validity = validity || self.fragment >= 0;
|
|
||||||
}
|
|
||||||
if stage.contains(BindingStage::VERTEX) {
|
|
||||||
validity = validity || self.vertex >= 0;
|
|
||||||
}
|
|
||||||
validity
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) type BufferStorage = UniformStorage<GlUniformBinder, UniformLocation<GLint>>;
|
|
||||||
|
|
||||||
|
|
||||||
pub trait GlUniformScalar: UniformScalar {
|
|
||||||
const FACTORY: unsafe fn(GLint, Self) -> ();
|
|
||||||
}
|
|
||||||
|
|
||||||
impl GlUniformScalar for f32 {
|
|
||||||
const FACTORY: unsafe fn(GLint, Self) -> () = gl::Uniform1f;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl GlUniformScalar for i32 {
|
|
||||||
const FACTORY: unsafe fn(GLint, Self) -> () = gl::Uniform1i;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl GlUniformScalar for u32 {
|
|
||||||
const FACTORY: unsafe fn(GLint, Self) -> () = gl::Uniform1ui;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) struct GlUniformBinder;
|
|
||||||
impl<T> BindUniform<UniformLocation<GLint>, T> for GlUniformBinder
|
|
||||||
where T: GlUniformScalar
|
|
||||||
{
|
|
||||||
fn bind_uniform(value: T, location: UniformLocation<GLint>) -> Option<()> {
|
|
||||||
if location.is_valid(BindingStage::VERTEX | BindingStage::FRAGMENT) {
|
|
||||||
unsafe {
|
|
||||||
if location.is_valid(BindingStage::VERTEX) {
|
|
||||||
T::FACTORY(location.vertex, value);
|
|
||||||
}
|
|
||||||
if location.is_valid(BindingStage::FRAGMENT) {
|
|
||||||
T::FACTORY(location.fragment, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Some(())
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BindUniform<UniformLocation<GLint>, &[f32; 4]> for GlUniformBinder {
|
|
||||||
fn bind_uniform(vec4: &[f32; 4], location: UniformLocation<GLint>) -> Option<()> {
|
|
||||||
if location.is_valid(BindingStage::VERTEX | BindingStage::FRAGMENT) {
|
|
||||||
unsafe {
|
|
||||||
if location.is_valid(BindingStage::VERTEX) {
|
|
||||||
gl::Uniform4fv(location.vertex, 1, vec4.as_ptr());
|
|
||||||
}
|
|
||||||
if location.is_valid(BindingStage::FRAGMENT) {
|
|
||||||
gl::Uniform4fv(location.fragment, 1, vec4.as_ptr());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Some(())
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BindUniform<UniformLocation<GLint>, &[f32; 16]> for GlUniformBinder {
|
|
||||||
fn bind_uniform(mat4: &[f32; 16], location: UniformLocation<GLint>) -> Option<()> {
|
|
||||||
if location.is_valid(BindingStage::VERTEX | BindingStage::FRAGMENT) {
|
|
||||||
unsafe {
|
|
||||||
if location.is_valid(BindingStage::VERTEX) {
|
|
||||||
gl::UniformMatrix4fv(location.vertex, 1, gl::FALSE, mat4.as_ptr());
|
|
||||||
}
|
|
||||||
if location.is_valid(BindingStage::FRAGMENT) {
|
|
||||||
gl::UniformMatrix4fv(location.fragment, 1, gl::FALSE, mat4.as_ptr());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Some(())
|
|
||||||
}else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,26 +0,0 @@
|
||||||
use gl::types::GLenum;
|
|
||||||
use librashader_common::image::ImageError;
|
|
||||||
use librashader_preprocess::PreprocessError;
|
|
||||||
use librashader_presets::ParsePresetError;
|
|
||||||
use librashader_reflect::error::{ShaderCompileError, ShaderReflectError};
|
|
||||||
use thiserror::Error;
|
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
|
||||||
pub enum FilterChainError {
|
|
||||||
#[error("fbo initialization error")]
|
|
||||||
FramebufferInit(GLenum),
|
|
||||||
#[error("SPIRV reflection error")]
|
|
||||||
SpirvCrossReflectError(#[from] spirv_cross::ErrorCode),
|
|
||||||
#[error("shader preset parse error")]
|
|
||||||
ShaderPresetError(#[from] ParsePresetError),
|
|
||||||
#[error("shader preprocess error")]
|
|
||||||
ShaderPreprocessError(#[from] PreprocessError),
|
|
||||||
#[error("shader compile error")]
|
|
||||||
ShaderCompileError(#[from] ShaderCompileError),
|
|
||||||
#[error("shader reflect error")]
|
|
||||||
ShaderReflectError(#[from] ShaderReflectError),
|
|
||||||
#[error("lut loading error")]
|
|
||||||
LutLoadError(#[from] ImageError)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub type Result<T> = std::result::Result<T, FilterChainError>;
|
|
|
@ -1,645 +0,0 @@
|
||||||
use crate::binding::{BufferStorage, UniformLocation, VariableLocation};
|
|
||||||
use crate::filter_pass::FilterPass;
|
|
||||||
use crate::framebuffer::{Framebuffer, GlImage, Viewport};
|
|
||||||
use crate::quad_render::DrawQuad;
|
|
||||||
use crate::render_target::RenderTarget;
|
|
||||||
use crate::util;
|
|
||||||
use crate::util::{gl_get_version, gl_u16_to_version, InlineRingBuffer};
|
|
||||||
use crate::error::{FilterChainError, Result};
|
|
||||||
|
|
||||||
use gl::types::{GLint, GLsizei, GLsizeiptr, GLuint};
|
|
||||||
use librashader_common::image::Image;
|
|
||||||
use librashader_common::{FilterMode, Size, WrapMode};
|
|
||||||
use librashader_preprocess::ShaderSource;
|
|
||||||
use librashader_presets::{ShaderPassConfig, ShaderPreset, TextureConfig};
|
|
||||||
use librashader_reflect::back::cross::{GlslangGlslContext, GlVersion};
|
|
||||||
use librashader_reflect::back::targets::GLSL;
|
|
||||||
use librashader_reflect::reflect::semantics::{MemberOffset, ReflectSemantics, SemanticMap, TextureSemantics, UniformBinding, UniformMeta, UniformSemantic, VariableSemantics};
|
|
||||||
use librashader_reflect::reflect::ReflectShader;
|
|
||||||
use rustc_hash::FxHashMap;
|
|
||||||
use spirv_cross::spirv::Decoration;
|
|
||||||
use std::collections::VecDeque;
|
|
||||||
use std::path::Path;
|
|
||||||
use librashader_reflect::back::{CompilerBackend, CompileShader, FromCompilation};
|
|
||||||
use librashader_reflect::front::shaderc::GlslangCompilation;
|
|
||||||
use crate::options::{FilterChainOptions, FrameOptions};
|
|
||||||
use crate::samplers::SamplerSet;
|
|
||||||
use crate::texture::Texture;
|
|
||||||
|
|
||||||
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 struct FilterCommon {
|
|
||||||
// semantics: ReflectSemantics,
|
|
||||||
pub(crate) config: FilterMutable,
|
|
||||||
pub(crate) luts: FxHashMap<usize, Texture>,
|
|
||||||
pub(crate) samplers: SamplerSet,
|
|
||||||
pub output_textures: Box<[Texture]>,
|
|
||||||
pub feedback_textures: Box<[Texture]>,
|
|
||||||
pub history_textures: Box<[Texture]>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct FilterMutable {
|
|
||||||
pub(crate) passes_enabled: usize,
|
|
||||||
pub(crate) parameters: FxHashMap<String, f32>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FilterChain {
|
|
||||||
fn reflect_uniform_location(pipeline: GLuint, meta: &impl UniformMeta) -> VariableLocation {
|
|
||||||
// todo: support both ubo and pushco
|
|
||||||
// todo: fix this.
|
|
||||||
match meta.offset() {
|
|
||||||
MemberOffset::Ubo(_) => {
|
|
||||||
let vert_name = format!("LIBRA_UBO_VERTEX_INSTANCE.{}\0", meta.id());
|
|
||||||
let frag_name = format!("LIBRA_UBO_FRAGMENT_INSTANCE.{}\0", meta.id());
|
|
||||||
unsafe {
|
|
||||||
let vertex = gl::GetUniformLocation(pipeline, vert_name.as_ptr().cast());
|
|
||||||
let fragment = gl::GetUniformLocation(pipeline, frag_name.as_ptr().cast());
|
|
||||||
|
|
||||||
VariableLocation::Ubo(UniformLocation { vertex, fragment })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
MemberOffset::PushConstant(_) => {
|
|
||||||
let vert_name = format!("LIBRA_PUSH_VERTEX_INSTANCE.{}\0", meta.id());
|
|
||||||
let frag_name = format!("LIBRA_PUSH_FRAGMENT_INSTANCE.{}\0", meta.id());
|
|
||||||
unsafe {
|
|
||||||
let vertex = gl::GetUniformLocation(pipeline, vert_name.as_ptr().cast());
|
|
||||||
let fragment = gl::GetUniformLocation(pipeline, frag_name.as_ptr().cast());
|
|
||||||
|
|
||||||
VariableLocation::Push(UniformLocation { vertex, fragment })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type ShaderPassMeta = (
|
|
||||||
ShaderPassConfig,
|
|
||||||
ShaderSource,
|
|
||||||
CompilerBackend<
|
|
||||||
impl CompileShader<GLSL, Options = GlVersion, Context = GlslangGlslContext> + ReflectShader,
|
|
||||||
>,
|
|
||||||
);
|
|
||||||
|
|
||||||
impl FilterChain {
|
|
||||||
/// Load a filter chain from a pre-parsed `ShaderPreset`.
|
|
||||||
pub fn load_from_preset(preset: ShaderPreset, options: Option<&FilterChainOptions>) -> Result<FilterChain> {
|
|
||||||
let (passes, semantics) = FilterChain::load_preset(preset.shaders, &preset.textures)?;
|
|
||||||
|
|
||||||
let version = options.map(|o| gl_u16_to_version(o.gl_version))
|
|
||||||
.unwrap_or_else(|| gl_get_version());
|
|
||||||
|
|
||||||
// initialize passes
|
|
||||||
let filters = FilterChain::init_passes(version, passes, &semantics)?;
|
|
||||||
|
|
||||||
let default_filter = filters.first().map(|f| f.config.filter).unwrap_or_default();
|
|
||||||
let default_wrap = filters
|
|
||||||
.first()
|
|
||||||
.map(|f| f.config.wrap_mode)
|
|
||||||
.unwrap_or_default();
|
|
||||||
|
|
||||||
let samplers = SamplerSet::new();
|
|
||||||
|
|
||||||
// initialize output framebuffers
|
|
||||||
let mut output_framebuffers = Vec::new();
|
|
||||||
output_framebuffers.resize_with(filters.len(), || Framebuffer::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));
|
|
||||||
let mut feedback_textures = Vec::new();
|
|
||||||
feedback_textures.resize_with(filters.len(), Texture::default);
|
|
||||||
|
|
||||||
// load luts
|
|
||||||
let luts = FilterChain::load_luts(&preset.textures)?;
|
|
||||||
|
|
||||||
let (history_framebuffers, history_textures) =
|
|
||||||
FilterChain::init_history(&filters, default_filter, default_wrap);
|
|
||||||
|
|
||||||
// create VBO objects
|
|
||||||
let draw_quad = DrawQuad::new();
|
|
||||||
|
|
||||||
Ok(FilterChain {
|
|
||||||
passes: filters,
|
|
||||||
output_framebuffers: output_framebuffers.into_boxed_slice(),
|
|
||||||
feedback_framebuffers: feedback_framebuffers.into_boxed_slice(),
|
|
||||||
history_framebuffers,
|
|
||||||
draw_quad,
|
|
||||||
common: FilterCommon {
|
|
||||||
config: FilterMutable {
|
|
||||||
passes_enabled: preset.shader_count as usize,
|
|
||||||
parameters: preset.parameters.into_iter()
|
|
||||||
.map(|param| (param.name, param.value)).collect(),
|
|
||||||
},
|
|
||||||
luts,
|
|
||||||
samplers,
|
|
||||||
output_textures: output_textures.into_boxed_slice(),
|
|
||||||
feedback_textures: feedback_textures.into_boxed_slice(),
|
|
||||||
history_textures,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Load the shader preset at the given path into a filter chain.
|
|
||||||
pub fn load_from_path(path: impl AsRef<Path>, options: Option<&FilterChainOptions>) -> Result<FilterChain> {
|
|
||||||
// load passes from preset
|
|
||||||
let preset = ShaderPreset::try_parse(path)?;
|
|
||||||
Self::load_from_preset(preset, options)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn load_preset(
|
|
||||||
passes: Vec<ShaderPassConfig>,
|
|
||||||
textures: &[TextureConfig]
|
|
||||||
) -> Result<(Vec<ShaderPassMeta>, ReflectSemantics)> {
|
|
||||||
let mut uniform_semantics: FxHashMap<String, UniformSemantic> = Default::default();
|
|
||||||
let mut texture_semantics: FxHashMap<String, SemanticMap<TextureSemantics>> =
|
|
||||||
Default::default();
|
|
||||||
|
|
||||||
let passes = passes
|
|
||||||
.into_iter()
|
|
||||||
.map(|shader| {
|
|
||||||
eprintln!("[gl] loading {}", &shader.name.display());
|
|
||||||
let source: ShaderSource = ShaderSource::load(&shader.name)?;
|
|
||||||
|
|
||||||
let spirv = GlslangCompilation::compile(&source)?;
|
|
||||||
let reflect = GLSL::from_compilation(spirv)?;
|
|
||||||
|
|
||||||
for parameter in source.parameters.iter() {
|
|
||||||
uniform_semantics.insert(
|
|
||||||
parameter.id.clone(),
|
|
||||||
UniformSemantic::Variable(SemanticMap {
|
|
||||||
semantics: VariableSemantics::FloatParameter,
|
|
||||||
index: (),
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
Ok::<_, FilterChainError>((shader, source, reflect))
|
|
||||||
})
|
|
||||||
.into_iter()
|
|
||||||
.collect::<Result<Vec<(ShaderPassConfig, ShaderSource, CompilerBackend<_>)>>>()?;
|
|
||||||
|
|
||||||
for details in &passes {
|
|
||||||
librashader_runtime::semantics::insert_pass_semantics(
|
|
||||||
&mut uniform_semantics,
|
|
||||||
&mut texture_semantics,
|
|
||||||
&details.0,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// add lut params
|
|
||||||
librashader_runtime::semantics::insert_lut_semantics(textures,
|
|
||||||
&mut uniform_semantics,
|
|
||||||
&mut texture_semantics);
|
|
||||||
let semantics = ReflectSemantics {
|
|
||||||
uniform_semantics,
|
|
||||||
texture_semantics,
|
|
||||||
};
|
|
||||||
|
|
||||||
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
|
|
||||||
};
|
|
||||||
|
|
||||||
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 {
|
|
||||||
util::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)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn init_passes(
|
|
||||||
version: GlVersion,
|
|
||||||
passes: Vec<ShaderPassMeta>,
|
|
||||||
semantics: &ReflectSemantics,
|
|
||||||
) -> Result<Box<[FilterPass]>> {
|
|
||||||
let mut filters = Vec::new();
|
|
||||||
|
|
||||||
// initialize passes
|
|
||||||
for (index, (config, source, mut reflect)) in passes.into_iter().enumerate() {
|
|
||||||
let reflection = reflect.reflect(index, semantics)?;
|
|
||||||
let glsl = reflect.compile(version)?;
|
|
||||||
|
|
||||||
let vertex_resources = glsl.context.compiler.vertex.get_shader_resources()?;
|
|
||||||
|
|
||||||
// todo: split this out.
|
|
||||||
let (program, ubo_location) = unsafe {
|
|
||||||
let vertex = util::gl_compile_shader(gl::VERTEX_SHADER, glsl.vertex.as_str());
|
|
||||||
let fragment = util::gl_compile_shader(gl::FRAGMENT_SHADER, glsl.fragment.as_str());
|
|
||||||
|
|
||||||
let program = gl::CreateProgram();
|
|
||||||
gl::AttachShader(program, vertex);
|
|
||||||
gl::AttachShader(program, fragment);
|
|
||||||
|
|
||||||
for res in vertex_resources.stage_inputs {
|
|
||||||
let loc = glsl
|
|
||||||
.context
|
|
||||||
.compiler
|
|
||||||
.vertex
|
|
||||||
.get_decoration(res.id, Decoration::Location)?;
|
|
||||||
let mut name = res.name;
|
|
||||||
name.push('\0');
|
|
||||||
|
|
||||||
gl::BindAttribLocation(program, loc, name.as_str().as_ptr().cast())
|
|
||||||
}
|
|
||||||
gl::LinkProgram(program);
|
|
||||||
gl::DeleteShader(vertex);
|
|
||||||
gl::DeleteShader(fragment);
|
|
||||||
|
|
||||||
let mut status = 0;
|
|
||||||
gl::GetProgramiv(program, gl::LINK_STATUS, &mut status);
|
|
||||||
if status != 1 {
|
|
||||||
panic!("failed to link program")
|
|
||||||
}
|
|
||||||
|
|
||||||
gl::UseProgram(program);
|
|
||||||
|
|
||||||
for (name, binding) in &glsl.context.sampler_bindings {
|
|
||||||
let location =
|
|
||||||
gl::GetUniformLocation(program, name.as_str().as_ptr().cast());
|
|
||||||
if location >= 0 {
|
|
||||||
// eprintln!("setting sampler {location} to sample from {binding}");
|
|
||||||
gl::Uniform1i(location, *binding as GLint);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
gl::UseProgram(0);
|
|
||||||
(
|
|
||||||
program,
|
|
||||||
UniformLocation {
|
|
||||||
vertex: gl::GetUniformBlockIndex(
|
|
||||||
program,
|
|
||||||
b"LIBRA_UBO_VERTEX\0".as_ptr().cast(),
|
|
||||||
),
|
|
||||||
fragment: gl::GetUniformBlockIndex(
|
|
||||||
program,
|
|
||||||
b"LIBRA_UBO_FRAGMENT\0".as_ptr().cast(),
|
|
||||||
),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
let ubo_ring = if let Some(ubo) = &reflection.ubo {
|
|
||||||
let size = ubo.size;
|
|
||||||
let mut ring: InlineRingBuffer<GLuint, 16> = InlineRingBuffer::new();
|
|
||||||
unsafe {
|
|
||||||
gl::CreateBuffers(16, ring.items_mut().as_mut_ptr());
|
|
||||||
for buffer in ring.items() {
|
|
||||||
gl::NamedBufferData(
|
|
||||||
*buffer,
|
|
||||||
size as GLsizeiptr,
|
|
||||||
std::ptr::null(),
|
|
||||||
gl::STREAM_DRAW,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Some(ring)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
let uniform_storage = BufferStorage::new(reflection
|
|
||||||
.ubo
|
|
||||||
.as_ref()
|
|
||||||
.map(|ubo| ubo.size as usize)
|
|
||||||
.unwrap_or(0),
|
|
||||||
reflection
|
|
||||||
.push_constant
|
|
||||||
.as_ref()
|
|
||||||
.map(|push| push.size as usize)
|
|
||||||
.unwrap_or(0)
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut uniform_bindings = FxHashMap::default();
|
|
||||||
for param in reflection.meta.parameter_meta.values() {
|
|
||||||
uniform_bindings.insert(
|
|
||||||
UniformBinding::Parameter(param.id.clone()),
|
|
||||||
(
|
|
||||||
FilterChain::reflect_uniform_location(program, param),
|
|
||||||
param.offset,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (semantics, param) in &reflection.meta.variable_meta {
|
|
||||||
uniform_bindings.insert(
|
|
||||||
UniformBinding::SemanticVariable(*semantics),
|
|
||||||
(
|
|
||||||
FilterChain::reflect_uniform_location(program, param),
|
|
||||||
param.offset,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (semantics, param) in &reflection.meta.texture_size_meta {
|
|
||||||
uniform_bindings.insert(
|
|
||||||
UniformBinding::TextureSize(*semantics),
|
|
||||||
(
|
|
||||||
FilterChain::reflect_uniform_location(program, param),
|
|
||||||
param.offset,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// eprintln!("{:#?}", reflection.meta.texture_meta);
|
|
||||||
// eprintln!("{:#?}", reflection.meta);
|
|
||||||
// eprintln!("{:#?}", locations);
|
|
||||||
// eprintln!("{:#?}", reflection.push_constant);
|
|
||||||
// eprintln!("====fragment====");
|
|
||||||
// eprintln!("{:#}", glsl.fragment);
|
|
||||||
// eprintln!("====vertex====");
|
|
||||||
// eprintln!("{:#}", glsl.vertex);
|
|
||||||
|
|
||||||
filters.push(FilterPass {
|
|
||||||
reflection,
|
|
||||||
compiled: glsl,
|
|
||||||
program,
|
|
||||||
ubo_location,
|
|
||||||
ubo_ring,
|
|
||||||
uniform_storage,
|
|
||||||
uniform_bindings,
|
|
||||||
source,
|
|
||||||
config
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(filters.into_boxed_slice())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn init_history(
|
|
||||||
filters: &[FilterPass],
|
|
||||||
filter: FilterMode,
|
|
||||||
wrap_mode: WrapMode,
|
|
||||||
) -> (VecDeque<Framebuffer>, Box<[Texture]>) {
|
|
||||||
let mut required_images = 0;
|
|
||||||
|
|
||||||
for pass in filters {
|
|
||||||
// If a shader uses history size, but not history, we still need to keep the texture.
|
|
||||||
let texture_count = pass
|
|
||||||
.reflection
|
|
||||||
.meta
|
|
||||||
.texture_meta
|
|
||||||
.iter()
|
|
||||||
.filter(|(semantics, _)| semantics.semantics == TextureSemantics::OriginalHistory)
|
|
||||||
.count();
|
|
||||||
let texture_size_count = pass
|
|
||||||
.reflection
|
|
||||||
.meta
|
|
||||||
.texture_size_meta
|
|
||||||
.iter()
|
|
||||||
.filter(|(semantics, _)| semantics.semantics == TextureSemantics::OriginalHistory)
|
|
||||||
.count();
|
|
||||||
|
|
||||||
required_images = std::cmp::max(required_images, texture_count);
|
|
||||||
required_images = std::cmp::max(required_images, texture_size_count);
|
|
||||||
}
|
|
||||||
|
|
||||||
// not using frame history;
|
|
||||||
if required_images <= 1 {
|
|
||||||
println!("[history] not using frame history");
|
|
||||||
return (VecDeque::new(), Box::new([]));
|
|
||||||
}
|
|
||||||
|
|
||||||
// history0 is aliased with the original
|
|
||||||
|
|
||||||
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));
|
|
||||||
|
|
||||||
let mut history_textures = Vec::new();
|
|
||||||
history_textures.resize_with(required_images, || Texture {
|
|
||||||
image: Default::default(),
|
|
||||||
filter,
|
|
||||||
mip_filter: filter,
|
|
||||||
wrap_mode,
|
|
||||||
});
|
|
||||||
|
|
||||||
(framebuffers, history_textures.into_boxed_slice())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn push_history(&mut self, input: &GlImage) -> Result<()> {
|
|
||||||
if let Some(mut back) = self.history_framebuffers.pop_back() {
|
|
||||||
if back.size != input.size || (input.format != 0 && input.format != back.format) {
|
|
||||||
eprintln!("[history] resizing");
|
|
||||||
back.init(input.size, input.format)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
back.copy_from(input)?;
|
|
||||||
|
|
||||||
self.history_framebuffers.push_front(back)
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Process a frame with the input image.
|
|
||||||
///
|
|
||||||
/// When this frame returns, GL_FRAMEBUFFER is bound to 0.
|
|
||||||
pub fn frame(&mut self, count: usize, viewport: &Viewport, input: &GlImage, options: Option<&FrameOptions>) -> Result<()> {
|
|
||||||
// limit number of passes to those enabled.
|
|
||||||
let passes = &mut self.passes[0..self.common.config.passes_enabled];
|
|
||||||
if let Some(options) = options {
|
|
||||||
if options.clear_history {
|
|
||||||
for framebuffer in &self.history_framebuffers {
|
|
||||||
framebuffer.clear()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if passes.is_empty() {
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
|
|
||||||
// do not need to rebind FBO 0 here since first `draw` will
|
|
||||||
// bind automatically.
|
|
||||||
self.draw_quad.bind_vao();
|
|
||||||
|
|
||||||
let filter = passes[0].config.filter;
|
|
||||||
let wrap_mode = passes[0].config.wrap_mode;
|
|
||||||
|
|
||||||
// update history
|
|
||||||
for (texture, fbo) in self
|
|
||||||
.common
|
|
||||||
.history_textures
|
|
||||||
.iter_mut()
|
|
||||||
.zip(self.history_framebuffers.iter())
|
|
||||||
{
|
|
||||||
texture.image = fbo.as_texture(filter, wrap_mode).image;
|
|
||||||
}
|
|
||||||
|
|
||||||
for ((texture, fbo), pass) in self
|
|
||||||
.common
|
|
||||||
.feedback_textures
|
|
||||||
.iter_mut()
|
|
||||||
.zip(self.feedback_framebuffers.iter())
|
|
||||||
.zip(passes.iter())
|
|
||||||
{
|
|
||||||
texture.image = fbo
|
|
||||||
.as_texture(pass.config.filter, pass.config.wrap_mode)
|
|
||||||
.image;
|
|
||||||
}
|
|
||||||
|
|
||||||
// shader_gl3: 2067
|
|
||||||
let original = Texture {
|
|
||||||
image: *input,
|
|
||||||
filter,
|
|
||||||
mip_filter: filter,
|
|
||||||
wrap_mode,
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut source = original;
|
|
||||||
|
|
||||||
// rescale render buffers to ensure all bindings are valid.
|
|
||||||
for (index, pass) in passes.iter_mut().enumerate() {
|
|
||||||
self.output_framebuffers[index].scale(
|
|
||||||
pass.config.scaling.clone(),
|
|
||||||
pass.get_format(),
|
|
||||||
viewport,
|
|
||||||
&original,
|
|
||||||
&source,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
self.feedback_framebuffers[index].scale(
|
|
||||||
pass.config.scaling.clone(),
|
|
||||||
pass.get_format(),
|
|
||||||
viewport,
|
|
||||||
&original,
|
|
||||||
&source,
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
let passes_len = passes.len();
|
|
||||||
let (pass, last) = passes.split_at_mut(passes_len - 1);
|
|
||||||
|
|
||||||
for (index, pass) in pass.iter_mut().enumerate() {
|
|
||||||
let target = &self.output_framebuffers[index];
|
|
||||||
pass.draw(
|
|
||||||
index,
|
|
||||||
&self.common,
|
|
||||||
if pass.config.frame_count_mod > 0 {
|
|
||||||
count % pass.config.frame_count_mod as usize
|
|
||||||
} else {
|
|
||||||
count
|
|
||||||
} as u32,
|
|
||||||
1,
|
|
||||||
viewport,
|
|
||||||
&original,
|
|
||||||
&source,
|
|
||||||
RenderTarget::new(target, None, 0, 0),
|
|
||||||
);
|
|
||||||
|
|
||||||
let target = target.as_texture(pass.config.filter, pass.config.wrap_mode);
|
|
||||||
self.common.output_textures[index] = target;
|
|
||||||
source = target;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert_eq!(last.len(), 1);
|
|
||||||
for pass in last {
|
|
||||||
source.filter = pass.config.filter;
|
|
||||||
source.mip_filter = pass.config.filter;
|
|
||||||
|
|
||||||
pass.draw(
|
|
||||||
passes_len - 1,
|
|
||||||
&self.common,
|
|
||||||
if pass.config.frame_count_mod > 0 {
|
|
||||||
count % pass.config.frame_count_mod as usize
|
|
||||||
} else {
|
|
||||||
count
|
|
||||||
} as u32,
|
|
||||||
1,
|
|
||||||
viewport,
|
|
||||||
&original,
|
|
||||||
&source,
|
|
||||||
RenderTarget::new(viewport.output, viewport.mvp, viewport.x, viewport.y),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// swap feedback framebuffers with output
|
|
||||||
for (output, feedback) in self
|
|
||||||
.output_framebuffers
|
|
||||||
.iter_mut()
|
|
||||||
.zip(self.feedback_framebuffers.iter_mut())
|
|
||||||
{
|
|
||||||
std::mem::swap(output, feedback);
|
|
||||||
}
|
|
||||||
|
|
||||||
self.push_history(input)?;
|
|
||||||
|
|
||||||
// do not need to rebind FBO 0 here since first `draw` will
|
|
||||||
// bind automatically.
|
|
||||||
self.draw_quad.unbind_vao();
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,365 +0,0 @@
|
||||||
use gl::types::{GLint, GLsizei, GLsizeiptr, GLuint};
|
|
||||||
use librashader_reflect::back::cross::GlslangGlslContext;
|
|
||||||
use librashader_reflect::back::ShaderCompilerOutput;
|
|
||||||
use librashader_reflect::reflect::ShaderReflection;
|
|
||||||
|
|
||||||
use librashader_common::{ImageFormat, Size};
|
|
||||||
use librashader_preprocess::ShaderSource;
|
|
||||||
use librashader_presets::ShaderPassConfig;
|
|
||||||
use librashader_reflect::reflect::semantics::{BindingStage, MemberOffset, TextureBinding, TextureSemantics, UniformBinding, VariableSemantics};
|
|
||||||
use rustc_hash::FxHashMap;
|
|
||||||
|
|
||||||
use crate::binding::{BufferStorage, UniformLocation, VariableLocation};
|
|
||||||
use crate::filter_chain::FilterCommon;
|
|
||||||
use crate::framebuffer::Viewport;
|
|
||||||
use crate::render_target::RenderTarget;
|
|
||||||
use crate::samplers::SamplerSet;
|
|
||||||
use crate::texture::Texture;
|
|
||||||
use crate::util::{InlineRingBuffer, RingBuffer};
|
|
||||||
|
|
||||||
pub struct FilterPass {
|
|
||||||
pub reflection: ShaderReflection,
|
|
||||||
pub compiled: ShaderCompilerOutput<String, GlslangGlslContext>,
|
|
||||||
pub program: GLuint,
|
|
||||||
pub ubo_location: UniformLocation<GLuint>,
|
|
||||||
pub ubo_ring: Option<InlineRingBuffer<GLuint, 16>>,
|
|
||||||
pub(crate) uniform_storage: BufferStorage,
|
|
||||||
pub uniform_bindings: FxHashMap<UniformBinding, (VariableLocation, MemberOffset)>,
|
|
||||||
pub source: ShaderSource,
|
|
||||||
pub config: ShaderPassConfig,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FilterPass {
|
|
||||||
// todo: fix rendertargets (i.e. non-final pass is internal, final pass is user provided fbo)
|
|
||||||
pub fn draw(
|
|
||||||
&mut self,
|
|
||||||
pass_index: usize,
|
|
||||||
parent: &FilterCommon,
|
|
||||||
frame_count: u32,
|
|
||||||
frame_direction: i32,
|
|
||||||
viewport: &Viewport,
|
|
||||||
original: &Texture,
|
|
||||||
source: &Texture,
|
|
||||||
output: RenderTarget,
|
|
||||||
) {
|
|
||||||
let framebuffer = output.framebuffer;
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
gl::UseProgram(self.program);
|
|
||||||
}
|
|
||||||
|
|
||||||
self.build_semantics(
|
|
||||||
pass_index,
|
|
||||||
parent,
|
|
||||||
output.mvp,
|
|
||||||
frame_count,
|
|
||||||
frame_direction,
|
|
||||||
framebuffer.size,
|
|
||||||
viewport,
|
|
||||||
original,
|
|
||||||
source,
|
|
||||||
);
|
|
||||||
|
|
||||||
if self.ubo_location.vertex != gl::INVALID_INDEX
|
|
||||||
&& 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::NamedBufferSubData(
|
|
||||||
*buffer,
|
|
||||||
0,
|
|
||||||
size as GLsizeiptr,
|
|
||||||
self.uniform_storage.ubo.as_ptr().cast(),
|
|
||||||
);
|
|
||||||
|
|
||||||
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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
// can use because DSA
|
|
||||||
framebuffer.clear();
|
|
||||||
gl::BindFramebuffer(gl::FRAMEBUFFER, framebuffer.handle);
|
|
||||||
gl::Viewport(
|
|
||||||
output.x,
|
|
||||||
output.y,
|
|
||||||
framebuffer.size.width as GLsizei,
|
|
||||||
framebuffer.size.height as GLsizei,
|
|
||||||
);
|
|
||||||
|
|
||||||
if framebuffer.format == gl::SRGB8_ALPHA8 {
|
|
||||||
gl::Enable(gl::FRAMEBUFFER_SRGB);
|
|
||||||
} else {
|
|
||||||
gl::Disable(gl::FRAMEBUFFER_SRGB);
|
|
||||||
}
|
|
||||||
|
|
||||||
gl::Disable(gl::CULL_FACE);
|
|
||||||
gl::Disable(gl::BLEND);
|
|
||||||
gl::Disable(gl::DEPTH_TEST);
|
|
||||||
|
|
||||||
gl::DrawArrays(gl::TRIANGLE_STRIP, 0, 4);
|
|
||||||
gl::Disable(gl::FRAMEBUFFER_SRGB);
|
|
||||||
gl::BindFramebuffer(gl::FRAMEBUFFER, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FilterPass {
|
|
||||||
pub fn get_format(&self) -> ImageFormat {
|
|
||||||
let mut fb_format = ImageFormat::R8G8B8A8Unorm;
|
|
||||||
if self.config.srgb_framebuffer {
|
|
||||||
fb_format = ImageFormat::R8G8B8A8Srgb;
|
|
||||||
} else if self.config.float_framebuffer {
|
|
||||||
fb_format = ImageFormat::R16G16B16A16Sfloat;
|
|
||||||
}
|
|
||||||
fb_format
|
|
||||||
}
|
|
||||||
|
|
||||||
// framecount should be pre-modded
|
|
||||||
fn build_semantics(
|
|
||||||
&mut self,
|
|
||||||
pass_index: usize,
|
|
||||||
parent: &FilterCommon,
|
|
||||||
mvp: &[f32; 16],
|
|
||||||
frame_count: u32,
|
|
||||||
frame_direction: i32,
|
|
||||||
fb_size: Size<u32>,
|
|
||||||
viewport: &Viewport,
|
|
||||||
original: &Texture,
|
|
||||||
source: &Texture,
|
|
||||||
) {
|
|
||||||
// Bind MVP
|
|
||||||
if let Some((location, offset)) =
|
|
||||||
self.uniform_bindings.get(&VariableSemantics::MVP.into())
|
|
||||||
{
|
|
||||||
self.uniform_storage.bind_mat4(*offset, mvp, location.location());
|
|
||||||
}
|
|
||||||
|
|
||||||
// bind OutputSize
|
|
||||||
if let Some((location, offset)) = self
|
|
||||||
.uniform_bindings
|
|
||||||
.get(&VariableSemantics::Output.into())
|
|
||||||
{
|
|
||||||
self.uniform_storage.bind_vec4(*offset, fb_size, location.location());
|
|
||||||
}
|
|
||||||
|
|
||||||
// bind FinalViewportSize
|
|
||||||
if let Some((location, offset)) = self
|
|
||||||
.uniform_bindings
|
|
||||||
.get(&VariableSemantics::FinalViewport.into())
|
|
||||||
{
|
|
||||||
self.uniform_storage.bind_vec4(*offset,viewport.output.size, location.location());
|
|
||||||
}
|
|
||||||
|
|
||||||
// bind FrameCount
|
|
||||||
if let Some((location, offset)) = self
|
|
||||||
.uniform_bindings
|
|
||||||
.get(&VariableSemantics::FrameCount.into())
|
|
||||||
{
|
|
||||||
self.uniform_storage.bind_scalar(*offset, frame_count, location.location());
|
|
||||||
}
|
|
||||||
|
|
||||||
// bind FrameDirection
|
|
||||||
if let Some((location, offset)) = self
|
|
||||||
.uniform_bindings
|
|
||||||
.get(&VariableSemantics::FrameDirection.into())
|
|
||||||
{
|
|
||||||
self.uniform_storage.bind_scalar(*offset, frame_direction, location.location());
|
|
||||||
}
|
|
||||||
|
|
||||||
// bind Original sampler
|
|
||||||
if let Some(binding) = self
|
|
||||||
.reflection
|
|
||||||
.meta
|
|
||||||
.texture_meta
|
|
||||||
.get(&TextureSemantics::Original.semantics(0))
|
|
||||||
{
|
|
||||||
FilterPass::bind_texture(&parent.samplers, binding, original);
|
|
||||||
}
|
|
||||||
|
|
||||||
// bind OriginalSize
|
|
||||||
if let Some((location, offset)) = self
|
|
||||||
.uniform_bindings
|
|
||||||
.get(&TextureSemantics::Original.semantics(0).into())
|
|
||||||
{
|
|
||||||
self.uniform_storage
|
|
||||||
.bind_vec4(*offset,original.image.size, location.location());
|
|
||||||
}
|
|
||||||
|
|
||||||
// bind Source sampler
|
|
||||||
if let Some(binding) = self
|
|
||||||
.reflection
|
|
||||||
.meta
|
|
||||||
.texture_meta
|
|
||||||
.get(&TextureSemantics::Source.semantics(0))
|
|
||||||
{
|
|
||||||
// eprintln!("setting source binding to {}", binding.binding);
|
|
||||||
FilterPass::bind_texture(&parent.samplers, binding, source);
|
|
||||||
}
|
|
||||||
|
|
||||||
// bind SourceSize
|
|
||||||
if let Some((location, offset)) = self
|
|
||||||
.uniform_bindings
|
|
||||||
.get(&TextureSemantics::Source.semantics(0).into())
|
|
||||||
{
|
|
||||||
self.uniform_storage.bind_vec4(*offset,
|
|
||||||
source.image.size, location.location());
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(binding) = self
|
|
||||||
.reflection
|
|
||||||
.meta
|
|
||||||
.texture_meta
|
|
||||||
.get(&TextureSemantics::OriginalHistory.semantics(0))
|
|
||||||
{
|
|
||||||
FilterPass::bind_texture(&parent.samplers, binding, original);
|
|
||||||
}
|
|
||||||
if let Some((location, offset)) = self
|
|
||||||
.uniform_bindings
|
|
||||||
.get(&TextureSemantics::OriginalHistory.semantics(0).into())
|
|
||||||
{
|
|
||||||
self.uniform_storage
|
|
||||||
.bind_vec4(*offset,original.image.size, location.location());
|
|
||||||
}
|
|
||||||
|
|
||||||
for (index, output) in parent.history_textures.iter().enumerate() {
|
|
||||||
if !output.is_bound() {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if let Some(binding) = self
|
|
||||||
.reflection
|
|
||||||
.meta
|
|
||||||
.texture_meta
|
|
||||||
.get(&TextureSemantics::OriginalHistory.semantics(index + 1))
|
|
||||||
{
|
|
||||||
FilterPass::bind_texture(&parent.samplers, binding, output);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some((location, offset)) = self.uniform_bindings.get(
|
|
||||||
&TextureSemantics::OriginalHistory
|
|
||||||
.semantics(index + 1)
|
|
||||||
.into(),
|
|
||||||
) {
|
|
||||||
self.uniform_storage
|
|
||||||
.bind_vec4(*offset,output.image.size, location.location());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// PassOutput
|
|
||||||
for (index, output) in parent.output_textures.iter().enumerate() {
|
|
||||||
if !output.is_bound() {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if let Some(binding) = self
|
|
||||||
.reflection
|
|
||||||
.meta
|
|
||||||
.texture_meta
|
|
||||||
.get(&TextureSemantics::PassOutput.semantics(index))
|
|
||||||
{
|
|
||||||
FilterPass::bind_texture(&parent.samplers, binding, output);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some((location, offset)) = self
|
|
||||||
.uniform_bindings
|
|
||||||
.get(&TextureSemantics::PassOutput.semantics(index).into())
|
|
||||||
{
|
|
||||||
self.uniform_storage
|
|
||||||
.bind_vec4(*offset,output.image.size, location.location());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// PassFeedback
|
|
||||||
for (index, feedback) in parent.feedback_textures.iter().enumerate() {
|
|
||||||
if !feedback.is_bound() {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if let Some(binding) = self
|
|
||||||
.reflection
|
|
||||||
.meta
|
|
||||||
.texture_meta
|
|
||||||
.get(&TextureSemantics::PassFeedback.semantics(index))
|
|
||||||
{
|
|
||||||
if feedback.image.handle == 0 {
|
|
||||||
eprintln!("[WARNING] trying to bind PassFeedback: {index} which has texture 0 to slot {} in pass {pass_index}", binding.binding)
|
|
||||||
}
|
|
||||||
FilterPass::bind_texture(&parent.samplers, binding, feedback);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some((location, offset)) = self
|
|
||||||
.uniform_bindings
|
|
||||||
.get(&TextureSemantics::PassFeedback.semantics(index).into())
|
|
||||||
{
|
|
||||||
self.uniform_storage
|
|
||||||
.bind_vec4(*offset,feedback.image.size, location.location());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// bind float parameters
|
|
||||||
for (id, (location, offset)) in
|
|
||||||
self.uniform_bindings
|
|
||||||
.iter()
|
|
||||||
.filter_map(|(binding, value)| match binding {
|
|
||||||
UniformBinding::Parameter(id) => Some((id, value)),
|
|
||||||
_ => None,
|
|
||||||
})
|
|
||||||
{
|
|
||||||
let id = id.as_str();
|
|
||||||
// presets override params
|
|
||||||
let default = self
|
|
||||||
.source
|
|
||||||
.parameters
|
|
||||||
.iter()
|
|
||||||
.find(|&p| p.id == id)
|
|
||||||
.map(|f| f.initial)
|
|
||||||
.unwrap_or(0f32);
|
|
||||||
|
|
||||||
let value = *parent
|
|
||||||
.config
|
|
||||||
.parameters
|
|
||||||
.get(id)
|
|
||||||
.unwrap_or(&default);
|
|
||||||
|
|
||||||
self.uniform_storage
|
|
||||||
.bind_scalar(*offset, value, location.location());
|
|
||||||
}
|
|
||||||
|
|
||||||
// bind luts
|
|
||||||
for (index, lut) in &parent.luts {
|
|
||||||
if let Some(binding) = self
|
|
||||||
.reflection
|
|
||||||
.meta
|
|
||||||
.texture_meta
|
|
||||||
.get(&TextureSemantics::User.semantics(*index))
|
|
||||||
{
|
|
||||||
FilterPass::bind_texture(&parent.samplers, binding, lut);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some((location, offset)) = self
|
|
||||||
.uniform_bindings
|
|
||||||
.get(&TextureSemantics::User.semantics(*index).into())
|
|
||||||
{
|
|
||||||
self.uniform_storage
|
|
||||||
.bind_vec4(*offset, lut.image.size, location.location());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,293 +0,0 @@
|
||||||
use crate::util;
|
|
||||||
use crate::texture::Texture;
|
|
||||||
use gl::types::{GLenum, GLint, GLsizei, GLuint};
|
|
||||||
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 levels: u32,
|
|
||||||
is_raw: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Framebuffer {
|
|
||||||
pub fn new(max_levels: u32) -> Framebuffer {
|
|
||||||
let mut framebuffer = 0;
|
|
||||||
unsafe {
|
|
||||||
gl::CreateFramebuffers(1, &mut framebuffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
Framebuffer {
|
|
||||||
image: 0,
|
|
||||||
size: Size {
|
|
||||||
width: 1,
|
|
||||||
height: 1,
|
|
||||||
},
|
|
||||||
format: 0,
|
|
||||||
max_levels,
|
|
||||||
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,
|
|
||||||
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::ClearNamedFramebufferfv(self.handle,
|
|
||||||
gl::COLOR, 0,
|
|
||||||
[0.0f32, 0.0, 0.0, 0.0].as_ptr().cast());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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::NamedFramebufferDrawBuffer(self.handle, gl::COLOR_ATTACHMENT1);
|
|
||||||
gl::NamedFramebufferReadBuffer(image.handle, gl::COLOR_ATTACHMENT0);
|
|
||||||
gl::NamedFramebufferDrawBuffer(self.handle, gl::COLOR_ATTACHMENT1);
|
|
||||||
|
|
||||||
gl::BlitNamedFramebuffer(image.handle, self.handle,
|
|
||||||
0, 0, image.size.width as GLint, image.size.height as GLint,
|
|
||||||
0, 0, self.size.width as GLint, self.size.height as GLint,
|
|
||||||
gl::COLOR_BUFFER_BIT, gl::NEAREST);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
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 {
|
|
||||||
// reset the framebuffer image
|
|
||||||
if self.image != 0 {
|
|
||||||
gl::NamedFramebufferTexture(
|
|
||||||
self.handle,
|
|
||||||
gl::COLOR_ATTACHMENT0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
);
|
|
||||||
gl::DeleteTextures(1, &self.image);
|
|
||||||
}
|
|
||||||
|
|
||||||
gl::CreateTextures(gl::TEXTURE_2D,1, &mut self.image);
|
|
||||||
|
|
||||||
if size.width == 0 {
|
|
||||||
size.width = 1;
|
|
||||||
}
|
|
||||||
if size.height == 0 {
|
|
||||||
size.height = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.levels = util::calc_miplevel(size);
|
|
||||||
if self.levels > self.max_levels {
|
|
||||||
self.levels = self.max_levels;
|
|
||||||
}
|
|
||||||
if self.levels == 0 {
|
|
||||||
self.levels = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
gl::TextureStorage2D(
|
|
||||||
self.image,
|
|
||||||
self.levels as GLsizei,
|
|
||||||
self.format,
|
|
||||||
size.width as GLsizei,
|
|
||||||
size.height as GLsizei,
|
|
||||||
);
|
|
||||||
|
|
||||||
gl::NamedFramebufferTexture(
|
|
||||||
self.handle,
|
|
||||||
gl::COLOR_ATTACHMENT0,
|
|
||||||
self.image,
|
|
||||||
0,
|
|
||||||
);
|
|
||||||
|
|
||||||
let status = gl::CheckFramebufferStatus(gl::FRAMEBUFFER);
|
|
||||||
if status != gl::FRAMEBUFFER_COMPLETE {
|
|
||||||
match status {
|
|
||||||
gl::FRAMEBUFFER_UNSUPPORTED => {
|
|
||||||
eprintln!("unsupported fbo");
|
|
||||||
|
|
||||||
gl::NamedFramebufferTexture(
|
|
||||||
self.handle,
|
|
||||||
gl::COLOR_ATTACHMENT0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
);
|
|
||||||
gl::DeleteTextures(1, &self.image);
|
|
||||||
gl::CreateTextures(gl::TEXTURE_2D, 1, &mut self.image);
|
|
||||||
|
|
||||||
self.levels = util::calc_miplevel(size);
|
|
||||||
if self.levels > self.max_levels {
|
|
||||||
self.levels = self.max_levels;
|
|
||||||
}
|
|
||||||
if self.levels == 0 {
|
|
||||||
self.levels = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
gl::TextureStorage2D(
|
|
||||||
self.image,
|
|
||||||
self.levels as GLsizei,
|
|
||||||
ImageFormat::R8G8B8A8Unorm.into(),
|
|
||||||
size.width as GLsizei,
|
|
||||||
size.height as GLsizei,
|
|
||||||
);
|
|
||||||
gl::NamedFramebufferTexture(
|
|
||||||
self.handle,
|
|
||||||
gl::COLOR_ATTACHMENT0,
|
|
||||||
self.image,
|
|
||||||
0,
|
|
||||||
);
|
|
||||||
// self.init =
|
|
||||||
// gl::CheckFramebufferStatus(gl::FRAMEBUFFER) == gl::FRAMEBUFFER_COMPLETE;
|
|
||||||
}
|
|
||||||
_ => return Err(FilterChainError::FramebufferInit(status))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone)]
|
|
||||||
pub struct Viewport<'a> {
|
|
||||||
pub x: i32,
|
|
||||||
pub y: i32,
|
|
||||||
pub output: &'a Framebuffer,
|
|
||||||
pub mvp: Option<&'a [f32; 16]>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default, Debug, Copy, Clone)]
|
|
||||||
pub struct GlImage {
|
|
||||||
pub handle: GLuint,
|
|
||||||
pub format: GLenum,
|
|
||||||
pub size: Size<u32>,
|
|
||||||
pub padded_size: Size<u32>,
|
|
||||||
}
|
|
|
@ -1,38 +0,0 @@
|
||||||
#![feature(strict_provenance)]
|
|
||||||
#![feature(type_alias_impl_trait)]
|
|
||||||
|
|
||||||
mod binding;
|
|
||||||
mod filter_chain;
|
|
||||||
mod filter_pass;
|
|
||||||
mod framebuffer;
|
|
||||||
mod quad_render;
|
|
||||||
mod render_target;
|
|
||||||
mod util;
|
|
||||||
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 texture;
|
|
||||||
mod options;
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
use crate::filter_chain::FilterChain;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn triangle_gl46() {
|
|
||||||
let (glfw, window, events, shader, vao) = hello_triangle::setup();
|
|
||||||
let mut filter =
|
|
||||||
FilterChain::load_from_path("../test/slang-shaders/vhs/VHSPro.slangp", None)
|
|
||||||
.unwrap();
|
|
||||||
hello_triangle::do_loop(glfw, window, events, shader, vao, &mut filter);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,11 +0,0 @@
|
||||||
#[repr(C)]
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct FrameOptions {
|
|
||||||
pub clear_history: bool
|
|
||||||
}
|
|
||||||
|
|
||||||
#[repr(C)]
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct FilterChainOptions {
|
|
||||||
pub gl_version: u16
|
|
||||||
}
|
|
|
@ -1,63 +0,0 @@
|
||||||
use gl::types::{GLint, GLsizei, GLsizeiptr, GLuint};
|
|
||||||
|
|
||||||
#[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 DrawQuad {
|
|
||||||
vbo: GLuint,
|
|
||||||
vao: GLuint,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DrawQuad {
|
|
||||||
pub fn new() -> DrawQuad {
|
|
||||||
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);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
DrawQuad { vbo, vao }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn bind_vao(&self) {
|
|
||||||
unsafe {
|
|
||||||
gl::BindVertexArray(self.vao);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn unbind_vao(&self) {
|
|
||||||
unsafe {
|
|
||||||
gl::BindVertexArray(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,43 +0,0 @@
|
||||||
use crate::framebuffer::{Framebuffer, Viewport};
|
|
||||||
|
|
||||||
#[rustfmt::skip]
|
|
||||||
static DEFAULT_MVP: &[f32; 16] = &[
|
|
||||||
2f32, 0.0, 0.0, 0.0,
|
|
||||||
0.0, 2.0, 0.0, 0.0,
|
|
||||||
0.0, 0.0, 2.0, 0.0,
|
|
||||||
-1.0, -1.0, 0.0, 1.0,
|
|
||||||
];
|
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone)]
|
|
||||||
pub struct RenderTarget<'a> {
|
|
||||||
pub mvp: &'a [f32; 16],
|
|
||||||
pub framebuffer: &'a Framebuffer,
|
|
||||||
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 {
|
|
||||||
if let Some(mvp) = mvp {
|
|
||||||
RenderTarget {
|
|
||||||
framebuffer: backbuffer,
|
|
||||||
x,
|
|
||||||
mvp,
|
|
||||||
y,
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
RenderTarget {
|
|
||||||
framebuffer: backbuffer,
|
|
||||||
x,
|
|
||||||
mvp: DEFAULT_MVP,
|
|
||||||
y,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> From<&Viewport<'a>> for RenderTarget<'a> {
|
|
||||||
fn from(value: &Viewport<'a>) -> Self {
|
|
||||||
RenderTarget::new(value.output, value.mvp, value.x, value.y)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,83 +0,0 @@
|
||||||
use gl::types::{GLenum, GLint, GLuint};
|
|
||||||
use rustc_hash::FxHashMap;
|
|
||||||
use librashader_common::{FilterMode, WrapMode};
|
|
||||||
|
|
||||||
pub struct SamplerSet {
|
|
||||||
// todo: may need to deal with differences in mip filter.
|
|
||||||
samplers: FxHashMap<(WrapMode, FilterMode, FilterMode), GLuint>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SamplerSet {
|
|
||||||
pub fn get(&self, wrap: WrapMode, filter: FilterMode, mip: FilterMode) -> GLuint {
|
|
||||||
|
|
||||||
// eprintln!("{wrap}, {filter}, {mip}");
|
|
||||||
*self.samplers.get(&(wrap, filter, mip))
|
|
||||||
.unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn make_sampler(sampler: GLuint, wrap: WrapMode, filter: FilterMode, mip: FilterMode) {
|
|
||||||
unsafe {
|
|
||||||
gl::SamplerParameteri(
|
|
||||||
sampler,
|
|
||||||
gl::TEXTURE_WRAP_S,
|
|
||||||
GLenum::from(wrap) as GLint,
|
|
||||||
);
|
|
||||||
gl::SamplerParameteri(
|
|
||||||
sampler,
|
|
||||||
gl::TEXTURE_WRAP_T,
|
|
||||||
GLenum::from(wrap) as GLint,
|
|
||||||
);
|
|
||||||
gl::SamplerParameteri(
|
|
||||||
sampler,
|
|
||||||
gl::TEXTURE_MAG_FILTER,
|
|
||||||
GLenum::from(filter) as GLint,
|
|
||||||
);
|
|
||||||
|
|
||||||
gl::SamplerParameteri(
|
|
||||||
sampler,
|
|
||||||
gl::TEXTURE_MIN_FILTER,
|
|
||||||
GLenum::from(filter.gl_mip(mip)) as GLint,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new() -> SamplerSet {
|
|
||||||
let mut samplers = FxHashMap::default();
|
|
||||||
let wrap_modes =
|
|
||||||
&[WrapMode::ClampToBorder, WrapMode::ClampToEdge, WrapMode::Repeat, WrapMode::MirroredRepeat];
|
|
||||||
for wrap_mode in wrap_modes {
|
|
||||||
unsafe {
|
|
||||||
let mut linear_linear = 0;
|
|
||||||
let mut linear_nearest = 0;
|
|
||||||
|
|
||||||
let mut nearest_nearest = 0;
|
|
||||||
let mut nearest_linear = 0;
|
|
||||||
gl::GenSamplers(1, &mut linear_linear);
|
|
||||||
gl::GenSamplers(1, &mut linear_nearest);
|
|
||||||
gl::GenSamplers(1, &mut nearest_linear);
|
|
||||||
gl::GenSamplers(1, &mut nearest_nearest);
|
|
||||||
|
|
||||||
SamplerSet::make_sampler(linear_linear, *wrap_mode,
|
|
||||||
FilterMode::Linear, FilterMode::Linear);
|
|
||||||
SamplerSet::make_sampler(linear_nearest, *wrap_mode,
|
|
||||||
FilterMode::Linear, FilterMode::Nearest);
|
|
||||||
SamplerSet::make_sampler(nearest_linear, *wrap_mode,
|
|
||||||
FilterMode::Nearest, FilterMode::Linear);
|
|
||||||
SamplerSet::make_sampler(nearest_nearest, *wrap_mode,
|
|
||||||
FilterMode::Nearest, FilterMode::Nearest);
|
|
||||||
|
|
||||||
|
|
||||||
samplers.insert((*wrap_mode, FilterMode::Linear, FilterMode::Linear), linear_linear);
|
|
||||||
samplers.insert((*wrap_mode, FilterMode::Linear, FilterMode::Nearest), linear_nearest);
|
|
||||||
|
|
||||||
samplers.insert((*wrap_mode, FilterMode::Nearest, FilterMode::Nearest), nearest_nearest);
|
|
||||||
samplers.insert((*wrap_mode, FilterMode::Nearest, FilterMode::Linear), nearest_linear);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SamplerSet {
|
|
||||||
samplers
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,16 +0,0 @@
|
||||||
use librashader_common::{FilterMode, WrapMode};
|
|
||||||
use crate::GlImage;
|
|
||||||
|
|
||||||
#[derive(Default, Debug, Copy, Clone)]
|
|
||||||
pub struct Texture {
|
|
||||||
pub image: GlImage,
|
|
||||||
pub filter: FilterMode,
|
|
||||||
pub mip_filter: FilterMode,
|
|
||||||
pub wrap_mode: WrapMode,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Texture {
|
|
||||||
pub fn is_bound(&self) -> bool {
|
|
||||||
return self.image.handle != 0
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,129 +0,0 @@
|
||||||
use gl::types::{GLenum, GLuint};
|
|
||||||
use librashader_common::Size;
|
|
||||||
use librashader_reflect::back::cross::GlVersion;
|
|
||||||
|
|
||||||
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;
|
|
||||||
fn next(&mut self);
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T, const SIZE: usize> RingBuffer<T> for InlineRingBuffer<T, SIZE> {
|
|
||||||
fn current(&self) -> &T {
|
|
||||||
&self.items[self.index]
|
|
||||||
}
|
|
||||||
|
|
||||||
fn current_mut(&mut self) -> &mut T {
|
|
||||||
&mut self.items[self.index]
|
|
||||||
}
|
|
||||||
|
|
||||||
fn next(&mut self) {
|
|
||||||
self.index += 1;
|
|
||||||
if self.index >= SIZE {
|
|
||||||
self.index = 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct InlineRingBuffer<T, const SIZE: usize> {
|
|
||||||
items: [T; SIZE],
|
|
||||||
index: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T, const SIZE: usize> InlineRingBuffer<T, SIZE>
|
|
||||||
where
|
|
||||||
T: Copy,
|
|
||||||
T: Default,
|
|
||||||
{
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
items: [T::default(); SIZE],
|
|
||||||
index: 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn items(&self) -> &[T; SIZE] {
|
|
||||||
&self.items
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn items_mut(&mut self) -> &mut [T; SIZE] {
|
|
||||||
&mut self.items
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub unsafe fn gl_compile_shader(stage: GLenum, source: &str) -> GLuint {
|
|
||||||
let shader = gl::CreateShader(stage);
|
|
||||||
gl::ShaderSource(
|
|
||||||
shader,
|
|
||||||
1,
|
|
||||||
&source.as_bytes().as_ptr().cast(),
|
|
||||||
std::ptr::null(),
|
|
||||||
);
|
|
||||||
gl::CompileShader(shader);
|
|
||||||
let mut compile_status = 0;
|
|
||||||
gl::GetShaderiv(shader, gl::COMPILE_STATUS, &mut compile_status);
|
|
||||||
|
|
||||||
if compile_status == 0 {
|
|
||||||
panic!("failed to compile")
|
|
||||||
}
|
|
||||||
shader
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn gl_get_version() -> GlVersion {
|
|
||||||
let mut maj_ver = 0;
|
|
||||||
let mut min_ver = 0;
|
|
||||||
unsafe {
|
|
||||||
gl::GetIntegerv(gl::MAJOR_VERSION, &mut maj_ver);
|
|
||||||
gl::GetIntegerv(gl::MINOR_VERSION, &mut min_ver);
|
|
||||||
}
|
|
||||||
|
|
||||||
match maj_ver {
|
|
||||||
3 => match min_ver {
|
|
||||||
3 => GlVersion::V3_30,
|
|
||||||
2 => GlVersion::V1_50,
|
|
||||||
1 => GlVersion::V1_40,
|
|
||||||
0 => GlVersion::V1_30,
|
|
||||||
_ => GlVersion::V1_50,
|
|
||||||
}
|
|
||||||
4 => match min_ver {
|
|
||||||
6 => GlVersion::V4_60,
|
|
||||||
5 => GlVersion::V4_50,
|
|
||||||
4 => GlVersion::V4_40,
|
|
||||||
3 => GlVersion::V4_30,
|
|
||||||
2 => GlVersion::V4_20,
|
|
||||||
1 => GlVersion::V4_10,
|
|
||||||
0 => GlVersion::V4_00,
|
|
||||||
_ => GlVersion::V1_50
|
|
||||||
}
|
|
||||||
_ => GlVersion::V1_50
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn gl_u16_to_version(version: u16) -> GlVersion {
|
|
||||||
match version {
|
|
||||||
300 => GlVersion::V1_30,
|
|
||||||
310 => GlVersion::V1_40,
|
|
||||||
320 => GlVersion::V1_50,
|
|
||||||
330 => GlVersion::V3_30,
|
|
||||||
400 => GlVersion::V4_00,
|
|
||||||
410 => GlVersion::V4_10,
|
|
||||||
420 => GlVersion::V4_20,
|
|
||||||
430 => GlVersion::V4_30,
|
|
||||||
440 => GlVersion::V4_40,
|
|
||||||
450 => GlVersion::V4_50,
|
|
||||||
460 => GlVersion::V4_60,
|
|
||||||
_ => GlVersion::V1_50
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -32,25 +32,26 @@ pub mod targets {
|
||||||
/// Shader compiler target for GLSL.
|
/// Shader compiler target for GLSL.
|
||||||
pub use librashader_reflect::back::targets::GLSL;
|
pub use librashader_reflect::back::targets::GLSL;
|
||||||
|
|
||||||
/// Shader runtime for OpenGL.
|
|
||||||
pub mod runtime {
|
|
||||||
pub use librashader_runtime_gl::*;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Shader compiler targets and runtime for OpenGL 4.6.
|
|
||||||
pub mod gl46 {
|
|
||||||
/// Shader compiler target for GLSL.
|
|
||||||
pub use librashader_reflect::back::targets::GLSL;
|
|
||||||
|
|
||||||
/// Shader runtime for OpenGL.
|
/// Shader runtime for OpenGL.
|
||||||
pub mod runtime {
|
pub mod runtime {
|
||||||
pub use librashader_runtime_gl46::*;
|
pub use librashader_runtime_gl::options::*;
|
||||||
|
pub use librashader_runtime_gl::error;
|
||||||
|
pub use librashader_runtime_gl::FilterChain;
|
||||||
|
pub use librashader_runtime_gl::Viewport;
|
||||||
|
|
||||||
|
pub mod gl3 {
|
||||||
|
pub use librashader_runtime_gl::gl3::*;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod gl46 {
|
||||||
|
pub use librashader_runtime_gl::gl46::*;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Shader compiler targets and runtime for DirectX.
|
/// Shader compiler targets and runtime for DirectX.
|
||||||
pub mod dx {
|
pub mod d3d {
|
||||||
/// Shader compiler target for HLSL.
|
/// Shader compiler target for HLSL.
|
||||||
pub use librashader_reflect::back::targets::HLSL;
|
pub use librashader_reflect::back::targets::HLSL;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue