gl: clean up visibility in some APIs
This commit is contained in:
parent
df03fdc5eb
commit
4124ae3955
7 changed files with 123 additions and 117 deletions
|
@ -1,15 +1,15 @@
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use crate::binding::{UniformBinding, UniformLocation, VariableLocation};
|
use crate::binding::{UniformBinding, UniformLocation, VariableLocation};
|
||||||
use crate::filter_pass::FilterPass;
|
use crate::filter_pass::FilterPass;
|
||||||
use crate::framebuffer::Framebuffer;
|
use crate::framebuffer::{Framebuffer, GlImage, Size, Viewport};
|
||||||
use crate::render_target::RenderTarget;
|
use crate::render_target::RenderTarget;
|
||||||
use crate::util;
|
use crate::util;
|
||||||
use crate::util::{GlImage, InlineRingBuffer, Size, Texture, Viewport};
|
use crate::util::{InlineRingBuffer, Texture};
|
||||||
use gl::types::{GLenum, GLint, GLsizei, GLsizeiptr, GLuint};
|
use gl::types::{GLenum, GLint, GLsizei, GLsizeiptr, GLuint};
|
||||||
use librashader::image::Image;
|
use librashader::image::Image;
|
||||||
use librashader::{FilterMode, ShaderSource, WrapMode};
|
use librashader::{FilterMode, ShaderSource, WrapMode};
|
||||||
use librashader_presets::{ScaleType, ShaderPassConfig, ShaderPreset, TextureConfig};
|
use librashader_presets::{ScaleType, ShaderPassConfig, ShaderPreset, TextureConfig};
|
||||||
use librashader_reflect::back::cross::{GlVersion, GlslangGlslContext};
|
use librashader_reflect::back::cross::{GlslangGlslContext, GlVersion};
|
||||||
use librashader_reflect::back::targets::{CompilerBackend, FromCompilation, GLSL};
|
use librashader_reflect::back::targets::{CompilerBackend, FromCompilation, GLSL};
|
||||||
use librashader_reflect::back::CompileShader;
|
use librashader_reflect::back::CompileShader;
|
||||||
use librashader_reflect::reflect::semantics::{
|
use librashader_reflect::reflect::semantics::{
|
||||||
|
@ -131,6 +131,68 @@ type ShaderPassMeta<'a> = (
|
||||||
);
|
);
|
||||||
|
|
||||||
impl FilterChain {
|
impl FilterChain {
|
||||||
|
/// Load a filter chain from a pre-parsed `ShaderPreset`.
|
||||||
|
pub fn load_from_preset(preset: ShaderPreset) -> Result<FilterChain, Box<dyn Error>> {
|
||||||
|
let (passes, semantics) = FilterChain::load_preset(&preset);
|
||||||
|
|
||||||
|
// initialize passes
|
||||||
|
let filters = FilterChain::init_passes(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();
|
||||||
|
|
||||||
|
// 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();
|
||||||
|
|
||||||
|
let mut filter_vao = 0;
|
||||||
|
unsafe {
|
||||||
|
gl::GenVertexArrays(1, &mut filter_vao);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(FilterChain {
|
||||||
|
passes: filters,
|
||||||
|
output_framebuffers: output_framebuffers.into_boxed_slice(),
|
||||||
|
feedback_framebuffers: feedback_framebuffers.into_boxed_slice(),
|
||||||
|
history_framebuffers,
|
||||||
|
filter_vao,
|
||||||
|
common: FilterCommon {
|
||||||
|
semantics,
|
||||||
|
preset,
|
||||||
|
luts,
|
||||||
|
output_textures: output_textures.into_boxed_slice(),
|
||||||
|
feedback_textures: feedback_textures.into_boxed_slice(),
|
||||||
|
history_textures,
|
||||||
|
draw_quad,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Load the shader preset at the given path into a filter chain.
|
||||||
|
pub fn load_from_path(path: impl AsRef<Path>) -> Result<FilterChain, Box<dyn Error>> {
|
||||||
|
// load passes from preset
|
||||||
|
let preset = ShaderPreset::try_parse(path)?;
|
||||||
|
Self::load_from_preset(preset)
|
||||||
|
}
|
||||||
|
|
||||||
fn load_preset(preset: &ShaderPreset) -> (Vec<ShaderPassMeta>, ReflectSemantics) {
|
fn load_preset(preset: &ShaderPreset) -> (Vec<ShaderPassMeta>, ReflectSemantics) {
|
||||||
let mut uniform_semantics: FxHashMap<String, UniformSemantic> = Default::default();
|
let mut uniform_semantics: FxHashMap<String, UniformSemantic> = Default::default();
|
||||||
let mut texture_semantics: FxHashMap<String, SemanticMap<TextureSemantics>> =
|
let mut texture_semantics: FxHashMap<String, SemanticMap<TextureSemantics>> =
|
||||||
|
@ -300,7 +362,7 @@ impl FilterChain {
|
||||||
Ok(luts)
|
Ok(luts)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init_passes(
|
fn init_passes(
|
||||||
passes: Vec<ShaderPassMeta>,
|
passes: Vec<ShaderPassMeta>,
|
||||||
semantics: &ReflectSemantics,
|
semantics: &ReflectSemantics,
|
||||||
) -> Result<Box<[FilterPass]>, Box<dyn Error>> {
|
) -> Result<Box<[FilterPass]>, Box<dyn Error>> {
|
||||||
|
@ -467,7 +529,7 @@ impl FilterChain {
|
||||||
Ok(filters.into_boxed_slice())
|
Ok(filters.into_boxed_slice())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init_history(filters: &[FilterPass], filter: FilterMode, wrap_mode: WrapMode) -> (VecDeque<Framebuffer>, Box<[Texture]>) {
|
fn init_history(filters: &[FilterPass], filter: FilterMode, wrap_mode: WrapMode) -> (VecDeque<Framebuffer>, Box<[Texture]>) {
|
||||||
let mut required_images = 0;
|
let mut required_images = 0;
|
||||||
|
|
||||||
for pass in filters {
|
for pass in filters {
|
||||||
|
@ -514,68 +576,7 @@ impl FilterChain {
|
||||||
(framebuffers, history_textures.into_boxed_slice())
|
(framebuffers, history_textures.into_boxed_slice())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load(path: impl AsRef<Path>) -> Result<FilterChain, Box<dyn Error>> {
|
fn push_history(&mut self, input: &GlImage) {
|
||||||
// load passes from preset
|
|
||||||
let preset = ShaderPreset::try_parse(path)?;
|
|
||||||
let (passes, semantics) = FilterChain::load_preset(&preset);
|
|
||||||
|
|
||||||
// initialize passes
|
|
||||||
let filters = FilterChain::init_passes(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();
|
|
||||||
|
|
||||||
// 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();
|
|
||||||
|
|
||||||
let mut filter_vao = 0;
|
|
||||||
unsafe {
|
|
||||||
gl::GenVertexArrays(1, &mut filter_vao);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(FilterChain {
|
|
||||||
passes: filters,
|
|
||||||
output_framebuffers: output_framebuffers.into_boxed_slice(),
|
|
||||||
feedback_framebuffers: feedback_framebuffers.into_boxed_slice(),
|
|
||||||
history_framebuffers,
|
|
||||||
filter_vao,
|
|
||||||
common: FilterCommon {
|
|
||||||
semantics,
|
|
||||||
preset,
|
|
||||||
luts,
|
|
||||||
output_textures: output_textures.into_boxed_slice(),
|
|
||||||
feedback_textures: feedback_textures.into_boxed_slice(),
|
|
||||||
history_textures,
|
|
||||||
draw_quad,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn get_output_texture(&self, index: usize) -> Texture {
|
|
||||||
let config = &self.passes[index].config;
|
|
||||||
self.output_framebuffers[index].as_texture(config.filter, config.wrap_mode)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn push_history(&mut self, input: &GlImage) {
|
|
||||||
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
|
if back.size != input.size
|
||||||
|
@ -584,9 +585,7 @@ impl FilterChain {
|
||||||
back.init(input.size, input.format);
|
back.init(input.size, input.format);
|
||||||
}
|
}
|
||||||
|
|
||||||
if back.is_initialized() {
|
|
||||||
back.copy_from(&input);
|
back.copy_from(&input);
|
||||||
}
|
|
||||||
|
|
||||||
self.history_framebuffers.push_front(back)
|
self.history_framebuffers.push_front(back)
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,8 +12,9 @@ use rustc_hash::FxHashMap;
|
||||||
|
|
||||||
use crate::binding::{UniformBinding, UniformLocation, VariableLocation};
|
use crate::binding::{UniformBinding, UniformLocation, VariableLocation};
|
||||||
use crate::filter_chain::FilterCommon;
|
use crate::filter_chain::FilterCommon;
|
||||||
|
use crate::framebuffer::{Size, Viewport};
|
||||||
use crate::render_target::RenderTarget;
|
use crate::render_target::RenderTarget;
|
||||||
use crate::util::{InlineRingBuffer, RingBuffer, Size, Texture, Viewport};
|
use crate::util::{InlineRingBuffer, RingBuffer, Texture};
|
||||||
|
|
||||||
pub struct FilterPass {
|
pub struct FilterPass {
|
||||||
pub reflection: ShaderReflection,
|
pub reflection: ShaderReflection,
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::util;
|
use crate::util;
|
||||||
use crate::util::{GlImage, Size, Texture, Viewport};
|
use crate::util::Texture;
|
||||||
use gl::types::{GLenum, GLint, GLsizei, GLuint};
|
use gl::types::{GLenum, GLint, GLsizei, GLuint};
|
||||||
use librashader::{FilterMode, ShaderFormat, WrapMode};
|
use librashader::{FilterMode, ShaderFormat, WrapMode};
|
||||||
use librashader_presets::{Scale2D, ScaleType, Scaling};
|
use librashader_presets::{Scale2D, ScaleType, Scaling};
|
||||||
|
@ -7,12 +7,12 @@ use librashader_presets::{Scale2D, ScaleType, Scaling};
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Framebuffer {
|
pub struct Framebuffer {
|
||||||
pub image: GLuint,
|
pub image: GLuint,
|
||||||
|
pub handle: GLuint,
|
||||||
pub size: Size,
|
pub size: Size,
|
||||||
pub format: GLenum,
|
pub format: GLenum,
|
||||||
pub max_levels: u32,
|
pub max_levels: u32,
|
||||||
pub levels: u32,
|
pub levels: u32,
|
||||||
pub handle: GLuint,
|
is_raw: bool,
|
||||||
pub init: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Framebuffer {
|
impl Framebuffer {
|
||||||
|
@ -34,7 +34,7 @@ impl Framebuffer {
|
||||||
max_levels,
|
max_levels,
|
||||||
levels: 0,
|
levels: 0,
|
||||||
handle: framebuffer,
|
handle: framebuffer,
|
||||||
init: false,
|
is_raw: false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,11 +52,11 @@ impl Framebuffer {
|
||||||
max_levels: miplevels,
|
max_levels: miplevels,
|
||||||
levels: miplevels,
|
levels: miplevels,
|
||||||
handle,
|
handle,
|
||||||
init: true,
|
is_raw: true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_texture(&self, filter: FilterMode, wrap_mode: WrapMode) -> Texture {
|
pub(crate) fn as_texture(&self, filter: FilterMode, wrap_mode: WrapMode) -> Texture {
|
||||||
Texture {
|
Texture {
|
||||||
image: GlImage {
|
image: GlImage {
|
||||||
handle: self.image,
|
handle: self.image,
|
||||||
|
@ -70,7 +70,7 @@ impl Framebuffer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn scale(
|
pub(crate) fn scale(
|
||||||
&mut self,
|
&mut self,
|
||||||
scaling: Scale2D,
|
scaling: Scale2D,
|
||||||
format: ShaderFormat,
|
format: ShaderFormat,
|
||||||
|
@ -78,6 +78,10 @@ impl Framebuffer {
|
||||||
_original: &Texture,
|
_original: &Texture,
|
||||||
source: &Texture,
|
source: &Texture,
|
||||||
) -> Size {
|
) -> Size {
|
||||||
|
if self.is_raw {
|
||||||
|
return self.size;
|
||||||
|
}
|
||||||
|
|
||||||
let mut width = 0f32;
|
let mut width = 0f32;
|
||||||
let mut height = 0f32;
|
let mut height = 0f32;
|
||||||
|
|
||||||
|
@ -131,11 +135,7 @@ impl Framebuffer {
|
||||||
size
|
size
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn is_initialized(&self) -> bool {
|
pub(crate) fn clear(&self) {
|
||||||
self.init
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn clear(&self) {
|
|
||||||
unsafe {
|
unsafe {
|
||||||
gl::BindFramebuffer(gl::FRAMEBUFFER, self.handle);
|
gl::BindFramebuffer(gl::FRAMEBUFFER, self.handle);
|
||||||
gl::ColorMask(gl::TRUE, gl::TRUE, gl::TRUE, gl::TRUE);
|
gl::ColorMask(gl::TRUE, gl::TRUE, gl::TRUE, gl::TRUE);
|
||||||
|
@ -145,7 +145,7 @@ impl Framebuffer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn copy_from(&mut self, image: &GlImage) {
|
pub(crate) fn copy_from(&mut self, image: &GlImage) {
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
@ -190,9 +190,12 @@ impl Framebuffer {
|
||||||
gl::BindFramebuffer(gl::FRAMEBUFFER, 0);
|
gl::BindFramebuffer(gl::FRAMEBUFFER, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo: fix panic
|
// todo: fix panic
|
||||||
pub(crate) fn init(&mut self, mut size: Size, format: impl Into<GLenum>) {
|
pub(crate) fn init(&mut self, mut size: Size, format: impl Into<GLenum>) {
|
||||||
self.init = false;
|
if self.is_raw {
|
||||||
|
return;
|
||||||
|
}
|
||||||
self.format = format.into();
|
self.format = format.into();
|
||||||
self.size = size;
|
self.size = size;
|
||||||
|
|
||||||
|
@ -283,13 +286,11 @@ impl Framebuffer {
|
||||||
self.image,
|
self.image,
|
||||||
0,
|
0,
|
||||||
);
|
);
|
||||||
self.init =
|
// self.init =
|
||||||
gl::CheckFramebufferStatus(gl::FRAMEBUFFER) == gl::FRAMEBUFFER_COMPLETE;
|
// gl::CheckFramebufferStatus(gl::FRAMEBUFFER) == gl::FRAMEBUFFER_COMPLETE;
|
||||||
}
|
}
|
||||||
_ => panic!("failed to complete: {status:x}"),
|
_ => panic!("failed to complete: {status:x}"),
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
self.init = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gl::BindFramebuffer(gl::FRAMEBUFFER, 0);
|
gl::BindFramebuffer(gl::FRAMEBUFFER, 0);
|
||||||
|
@ -310,3 +311,25 @@ impl Drop for Framebuffer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
pub struct Viewport<'a> {
|
||||||
|
pub x: i32,
|
||||||
|
pub y: i32,
|
||||||
|
pub output: &'a Framebuffer,
|
||||||
|
pub mvp: Option<&'a [f32]>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
|
||||||
|
pub struct Size {
|
||||||
|
pub width: u32,
|
||||||
|
pub height: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Debug, Copy, Clone)]
|
||||||
|
pub struct GlImage {
|
||||||
|
pub handle: GLuint,
|
||||||
|
pub format: GLenum,
|
||||||
|
pub size: Size,
|
||||||
|
pub padded_size: Size,
|
||||||
|
}
|
||||||
|
|
|
@ -7,8 +7,7 @@ use glfw::{Context, Glfw, Window, WindowEvent};
|
||||||
use gl::types::{GLchar, GLenum, GLint, GLsizei, GLuint};
|
use gl::types::{GLchar, GLenum, GLint, GLsizei, GLuint};
|
||||||
|
|
||||||
use crate::filter_chain::FilterChain;
|
use crate::filter_chain::FilterChain;
|
||||||
use crate::framebuffer::Framebuffer;
|
use crate::framebuffer::{Framebuffer, GlImage, Size, Viewport};
|
||||||
use crate::util::{GlImage, Size, Viewport};
|
|
||||||
|
|
||||||
const WIDTH: u32 = 900;
|
const WIDTH: u32 = 900;
|
||||||
const HEIGHT: u32 = 700;
|
const HEIGHT: u32 = 700;
|
||||||
|
|
|
@ -10,6 +10,12 @@ mod render_target;
|
||||||
mod util;
|
mod util;
|
||||||
mod quad_render;
|
mod quad_render;
|
||||||
|
|
||||||
|
pub use filter_chain::FilterChain;
|
||||||
|
pub use framebuffer::Viewport;
|
||||||
|
pub use framebuffer::GlImage;
|
||||||
|
pub use framebuffer::Size;
|
||||||
|
pub use framebuffer::Framebuffer;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
@ -18,7 +24,7 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn triangle() {
|
fn triangle() {
|
||||||
let (glfw, window, events, shader, vao) = hello_triangle::setup();
|
let (glfw, window, events, shader, vao) = hello_triangle::setup();
|
||||||
let mut filter = FilterChain::load("../test/slang-shaders/crt/crt-royale-fake-bloom.slangp").unwrap();
|
let mut filter = FilterChain::load_from_path("../test/slang-shaders/crt/crt-royale-fake-bloom.slangp").unwrap();
|
||||||
|
|
||||||
// FilterChain::load("../test/slang-shaders/crt/crt-royale.slangp").unwrap();
|
// FilterChain::load("../test/slang-shaders/crt/crt-royale.slangp").unwrap();
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::framebuffer::Framebuffer;
|
use crate::framebuffer::{Framebuffer, Viewport};
|
||||||
use crate::util::{Texture, Viewport};
|
use crate::util::Texture;
|
||||||
|
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
static DEFAULT_MVP: &[f32] = &[
|
static DEFAULT_MVP: &[f32] = &[
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::framebuffer::Framebuffer;
|
use crate::framebuffer::{Framebuffer, GlImage};
|
||||||
use gl::types::{GLenum, GLuint};
|
use gl::types::{GLenum, GLuint};
|
||||||
use librashader::{FilterMode, WrapMode};
|
use librashader::{FilterMode, WrapMode};
|
||||||
|
|
||||||
|
@ -21,28 +21,6 @@ pub struct Texture {
|
||||||
pub wrap_mode: WrapMode,
|
pub wrap_mode: WrapMode,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone)]
|
|
||||||
pub struct Viewport<'a> {
|
|
||||||
pub x: i32,
|
|
||||||
pub y: i32,
|
|
||||||
pub output: &'a Framebuffer,
|
|
||||||
pub mvp: Option<&'a [f32]>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
|
|
||||||
pub struct Size {
|
|
||||||
pub width: u32,
|
|
||||||
pub height: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default, Debug, Copy, Clone)]
|
|
||||||
pub struct GlImage {
|
|
||||||
pub handle: GLuint,
|
|
||||||
pub format: GLenum,
|
|
||||||
pub size: Size,
|
|
||||||
pub padded_size: Size,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait RingBuffer<T> {
|
pub trait RingBuffer<T> {
|
||||||
fn current(&self) -> &T;
|
fn current(&self) -> &T;
|
||||||
fn current_mut(&mut self) -> &mut T;
|
fn current_mut(&mut self) -> &mut T;
|
||||||
|
|
Loading…
Add table
Reference in a new issue