From 1bdadaa4493c1b441d4d3dccbfb4614779d41f4a Mon Sep 17 00:00:00 2001 From: chyyran Date: Mon, 5 Feb 2024 18:39:01 -0500 Subject: [PATCH] rt(gl): port to OpenGL runtime to glow --- Cargo.lock | 18 +- Cargo.toml | 2 +- librashader-common/Cargo.toml | 4 +- librashader-common/src/gl.rs | 90 ++-- librashader-reflect/src/reflect/cross/glsl.rs | 2 +- librashader-runtime-gl/Cargo.toml | 4 +- librashader-runtime-gl/src/binding.rs | 67 +-- librashader-runtime-gl/src/error.rs | 9 +- .../filter_chain/{filter_impl.rs => chain.rs} | 57 ++- .../src/filter_chain/inner.rs | 2 +- .../src/filter_chain/mod.rs | 28 +- .../src/filter_chain/parameters.rs | 2 +- librashader-runtime-gl/src/filter_pass.rs | 68 +-- librashader-runtime-gl/src/framebuffer.rs | 5 +- librashader-runtime-gl/src/gl/framebuffer.rs | 28 +- .../src/gl/gl3/compile_program.rs | 53 +- .../src/gl/gl3/draw_quad.rs | 136 +++--- .../src/gl/gl3/framebuffer.rs | 251 +++++----- librashader-runtime-gl/src/gl/gl3/lut_load.rs | 75 +-- .../src/gl/gl3/texture_bind.rs | 27 +- librashader-runtime-gl/src/gl/gl3/ubo_ring.rs | 88 ++-- .../src/gl/gl46/compile_program.rs | 145 +++--- .../src/gl/gl46/draw_quad.rs | 101 ++-- .../src/gl/gl46/framebuffer.rs | 188 +++---- .../src/gl/gl46/lut_load.rs | 67 ++- .../src/gl/gl46/texture_bind.rs | 22 +- .../src/gl/gl46/ubo_ring.rs | 80 ++- librashader-runtime-gl/src/gl/mod.rs | 69 ++- librashader-runtime-gl/src/samplers.rs | 47 +- librashader-runtime-gl/src/texture.rs | 2 +- librashader-runtime-gl/src/util.rs | 50 +- .../tests/hello_triangle/gl3.rs | 459 +++++++----------- .../tests/hello_triangle/gl46.rs | 436 ++++++----------- .../tests/hello_triangle/mod.rs | 49 ++ librashader-runtime-gl/tests/triangle.rs | 21 +- librashader-runtime/src/ringbuffer.rs | 9 + 36 files changed, 1388 insertions(+), 1373 deletions(-) rename librashader-runtime-gl/src/filter_chain/{filter_impl.rs => chain.rs} (88%) diff --git a/Cargo.lock b/Cargo.lock index cb57890..eefd138 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1118,6 +1118,17 @@ dependencies = [ "web-sys", ] +[[package]] +name = "glow" +version = "0.14.0" +source = "git+https://github.com/grovesNL/glow/#eb44a878a756d5ddce8505158690ec9bd272be8f" +dependencies = [ + "js-sys", + "slotmap", + "wasm-bindgen", + "web-sys", +] + [[package]] name = "glslang" version = "0.4.0" @@ -1537,7 +1548,7 @@ name = "librashader-common" version = "0.4.5" dependencies = [ "ash", - "gl", + "glow 0.14.0", "halfbrown", "num-traits", "objc2-metal", @@ -1678,8 +1689,8 @@ name = "librashader-runtime-gl" version = "0.4.5" dependencies = [ "bytemuck", - "gl", "glfw 0.47.0", + "glow 0.14.0", "librashader-cache", "librashader-common", "librashader-preprocess", @@ -1688,7 +1699,6 @@ dependencies = [ "librashader-runtime", "rayon", "spirv-cross2", - "sptr", "thiserror", ] @@ -3500,7 +3510,7 @@ dependencies = [ "cfg_aliases", "core-graphics-types", "d3d12", - "glow", + "glow 0.13.1", "glutin_wgl_sys", "gpu-alloc", "gpu-allocator 0.26.0", diff --git a/Cargo.toml b/Cargo.toml index a24e553..2b373a0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,7 +23,7 @@ ash = "0.38" spirv-cross2 = { version = "0.4", default-features = false } objc2-metal = { version = "0.2" } objc2 = { version = "0.5.0" } - +glow = { version = "0.14", git = "https://github.com/grovesNL/glow/" } wgpu = { version = "22", default-features = false } wgpu-types = { version = "22" } diff --git a/librashader-common/Cargo.toml b/librashader-common/Cargo.toml index 1010397..55db363 100644 --- a/librashader-common/Cargo.toml +++ b/librashader-common/Cargo.toml @@ -13,7 +13,7 @@ description = "RetroArch shaders for all." [features] default = [] -opengl = ["gl"] +opengl = ["glow"] d3d9 = ["windows"] d3d11 = ["windows", "dxgi"] d3d12 = ["windows", "dxgi"] @@ -28,7 +28,7 @@ rustc-hash = "2.0.0" halfbrown = "0.2.4" smartstring = "1.0" -gl = { version = "0.14", optional = true } +glow = { workspace = true, optional = true } ash = { workspace = true, optional = true } wgpu-types = { workspace = true, optional = true } diff --git a/librashader-common/src/gl.rs b/librashader-common/src/gl.rs index 0389eb9..42a59bb 100644 --- a/librashader-common/src/gl.rs +++ b/librashader-common/src/gl.rs @@ -1,71 +1,71 @@ use crate::{FilterMode, ImageFormat, WrapMode}; -impl From for gl::types::GLenum { +impl From for u32 { fn from(format: ImageFormat) -> Self { match format { - ImageFormat::Unknown => 0 as gl::types::GLenum, - ImageFormat::R8Unorm => gl::R8, - ImageFormat::R8Uint => gl::R8UI, - ImageFormat::R8Sint => gl::R8I, - ImageFormat::R8G8Unorm => gl::RG8, - ImageFormat::R8G8Uint => gl::RG8UI, - ImageFormat::R8G8Sint => gl::RG8I, - ImageFormat::R8G8B8A8Unorm => gl::RGBA8, - ImageFormat::R8G8B8A8Uint => gl::RGBA8UI, - ImageFormat::R8G8B8A8Sint => gl::RGBA8I, - ImageFormat::R8G8B8A8Srgb => gl::SRGB8_ALPHA8, - ImageFormat::A2B10G10R10UnormPack32 => gl::RGB10_A2, - ImageFormat::A2B10G10R10UintPack32 => gl::RGB10_A2UI, - ImageFormat::R16Uint => gl::R16UI, - ImageFormat::R16Sint => gl::R16I, - ImageFormat::R16Sfloat => gl::R16F, - ImageFormat::R16G16Uint => gl::RG16UI, - ImageFormat::R16G16Sint => gl::RG16I, - ImageFormat::R16G16Sfloat => gl::RG16F, - ImageFormat::R16G16B16A16Uint => gl::RGBA16UI, - ImageFormat::R16G16B16A16Sint => gl::RGBA16I, - ImageFormat::R16G16B16A16Sfloat => gl::RGBA16F, - ImageFormat::R32Uint => gl::R32UI, - ImageFormat::R32Sint => gl::R32I, - ImageFormat::R32Sfloat => gl::R32F, - ImageFormat::R32G32Uint => gl::RG32UI, - ImageFormat::R32G32Sint => gl::RG32I, - ImageFormat::R32G32Sfloat => gl::RG32F, - ImageFormat::R32G32B32A32Uint => gl::RGBA32UI, - ImageFormat::R32G32B32A32Sint => gl::RGBA32I, - ImageFormat::R32G32B32A32Sfloat => gl::RGBA32F, + ImageFormat::Unknown => 0, + ImageFormat::R8Unorm => glow::R8, + ImageFormat::R8Uint => glow::R8UI, + ImageFormat::R8Sint => glow::R8I, + ImageFormat::R8G8Unorm => glow::RG8, + ImageFormat::R8G8Uint => glow::RG8UI, + ImageFormat::R8G8Sint => glow::RG8I, + ImageFormat::R8G8B8A8Unorm => glow::RGBA8, + ImageFormat::R8G8B8A8Uint => glow::RGBA8UI, + ImageFormat::R8G8B8A8Sint => glow::RGBA8I, + ImageFormat::R8G8B8A8Srgb => glow::SRGB8_ALPHA8, + ImageFormat::A2B10G10R10UnormPack32 => glow::RGB10_A2, + ImageFormat::A2B10G10R10UintPack32 => glow::RGB10_A2UI, + ImageFormat::R16Uint => glow::R16UI, + ImageFormat::R16Sint => glow::R16I, + ImageFormat::R16Sfloat => glow::R16F, + ImageFormat::R16G16Uint => glow::RG16UI, + ImageFormat::R16G16Sint => glow::RG16I, + ImageFormat::R16G16Sfloat => glow::RG16F, + ImageFormat::R16G16B16A16Uint => glow::RGBA16UI, + ImageFormat::R16G16B16A16Sint => glow::RGBA16I, + ImageFormat::R16G16B16A16Sfloat => glow::RGBA16F, + ImageFormat::R32Uint => glow::R32UI, + ImageFormat::R32Sint => glow::R32I, + ImageFormat::R32Sfloat => glow::R32F, + ImageFormat::R32G32Uint => glow::RG32UI, + ImageFormat::R32G32Sint => glow::RG32I, + ImageFormat::R32G32Sfloat => glow::RG32F, + ImageFormat::R32G32B32A32Uint => glow::RGBA32UI, + ImageFormat::R32G32B32A32Sint => glow::RGBA32I, + ImageFormat::R32G32B32A32Sfloat => glow::RGBA32F, } } } -impl From for gl::types::GLenum { +impl From for i32 { fn from(value: WrapMode) -> Self { match value { - WrapMode::ClampToBorder => gl::CLAMP_TO_BORDER, - WrapMode::ClampToEdge => gl::CLAMP_TO_EDGE, - WrapMode::Repeat => gl::REPEAT, - WrapMode::MirroredRepeat => gl::MIRRORED_REPEAT, + WrapMode::ClampToBorder => glow::CLAMP_TO_BORDER as i32, + WrapMode::ClampToEdge => glow::CLAMP_TO_EDGE as i32, + WrapMode::Repeat => glow::REPEAT as i32, + WrapMode::MirroredRepeat => glow::MIRRORED_REPEAT as i32, } } } -impl From for gl::types::GLenum { +impl From for i32 { fn from(value: FilterMode) -> Self { match value { - FilterMode::Linear => gl::LINEAR, - _ => gl::NEAREST, + FilterMode::Linear => glow::LINEAR as i32, + _ => glow::NEAREST as i32, } } } impl FilterMode { /// Get the mipmap filtering mode for the given combination. - pub fn gl_mip(&self, mip: FilterMode) -> gl::types::GLenum { + pub fn gl_mip(&self, mip: FilterMode) -> u32 { match (self, mip) { - (FilterMode::Linear, FilterMode::Linear) => gl::LINEAR_MIPMAP_LINEAR, - (FilterMode::Linear, FilterMode::Nearest) => gl::LINEAR_MIPMAP_NEAREST, - (FilterMode::Nearest, FilterMode::Linear) => gl::NEAREST_MIPMAP_LINEAR, - _ => gl::NEAREST_MIPMAP_NEAREST, + (FilterMode::Linear, FilterMode::Linear) => glow::LINEAR_MIPMAP_LINEAR, + (FilterMode::Linear, FilterMode::Nearest) => glow::LINEAR_MIPMAP_NEAREST, + (FilterMode::Nearest, FilterMode::Linear) => glow::NEAREST_MIPMAP_LINEAR, + _ => glow::NEAREST_MIPMAP_NEAREST, } } } diff --git a/librashader-reflect/src/reflect/cross/glsl.rs b/librashader-reflect/src/reflect/cross/glsl.rs index ce214fc..7a04c8b 100644 --- a/librashader-reflect/src/reflect/cross/glsl.rs +++ b/librashader-reflect/src/reflect/cross/glsl.rs @@ -145,7 +145,7 @@ impl CompileShader for CrossReflect { )?; self.fragment .set_decoration(res.id, Decoration::Binding, DecorationValue::unset())?; - let mut name = res.name.to_string(); + let name = res.name.to_string(); texture_fixups.push((name, binding)); } diff --git a/librashader-runtime-gl/Cargo.toml b/librashader-runtime-gl/Cargo.toml index 528f170..86afa29 100644 --- a/librashader-runtime-gl/Cargo.toml +++ b/librashader-runtime-gl/Cargo.toml @@ -20,13 +20,11 @@ librashader-runtime = { path = "../librashader-runtime" , version = "0.4.5" } librashader-cache = { path = "../librashader-cache", version = "0.4.5" } spirv-cross2 = { workspace = true, features = ["glsl"] } -gl = "0.14.0" +glow = { workspace = true} bytemuck = { version = "1.12.3", features = ["derive"] } thiserror = "1.0.37" rayon = "1.6.1" -sptr = "0.3" - [features] stable = ["librashader-reflect/stable"] diff --git a/librashader-runtime-gl/src/binding.rs b/librashader-runtime-gl/src/binding.rs index 40eaad3..8c037a6 100644 --- a/librashader-runtime-gl/src/binding.rs +++ b/librashader-runtime-gl/src/binding.rs @@ -1,15 +1,19 @@ -use gl::types::GLint; +use glow::HasContext; use librashader_reflect::reflect::semantics::{BindingStage, UniformMemberBlock}; use librashader_runtime::uniforms::{BindUniform, UniformScalar, UniformStorage}; +use std::fmt::Display; #[derive(Debug, Copy, Clone)] pub struct VariableLocation { - pub(crate) ubo: Option>, - pub(crate) push: Option>, + pub(crate) ubo: Option>>, + pub(crate) push: Option>>, } impl VariableLocation { - pub fn location(&self, offset_type: UniformMemberBlock) -> Option> { + pub fn location( + &self, + offset_type: UniformMemberBlock, + ) -> Option>> { match offset_type { UniformMemberBlock::Ubo => self.ubo, UniformMemberBlock::PushConstant => self.push, @@ -23,16 +27,13 @@ pub struct UniformLocation { pub fragment: T, } -impl UniformLocation { +impl UniformLocation> { + #[allow(unused_comparisons)] 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 + // since glow::UniformLocation is None or NonZeroU32, + // is_some is sufficient for validity + (stage.contains(BindingStage::FRAGMENT) && self.fragment.is_some()) + || (stage.contains(BindingStage::VERTEX) && self.vertex.is_some()) } pub fn bindable(&self) -> bool { @@ -40,26 +41,30 @@ impl UniformLocation { } } -pub(crate) type GlUniformStorage = UniformStorage; +pub(crate) type GlUniformStorage = + UniformStorage, Box<[u8]>, glow::Context>; -pub trait GlUniformScalar: UniformScalar { - const FACTORY: unsafe fn(GLint, Self) -> (); +pub trait GlUniformScalar: UniformScalar + Display { + const FACTORY: unsafe fn(&glow::Context, Option<&glow::UniformLocation>, Self) -> (); } impl GlUniformScalar for f32 { - const FACTORY: unsafe fn(GLint, Self) -> () = gl::Uniform1f; + const FACTORY: unsafe fn(&glow::Context, Option<&glow::UniformLocation>, Self) -> () = + glow::Context::uniform_1_f32; } impl GlUniformScalar for i32 { - const FACTORY: unsafe fn(GLint, Self) -> () = gl::Uniform1i; + const FACTORY: unsafe fn(&glow::Context, Option<&glow::UniformLocation>, Self) -> () = + glow::Context::uniform_1_i32; } impl GlUniformScalar for u32 { - const FACTORY: unsafe fn(GLint, Self) -> () = gl::Uniform1ui; + const FACTORY: unsafe fn(&glow::Context, Option<&glow::UniformLocation>, Self) -> () = + glow::Context::uniform_1_u32; } pub(crate) struct GlUniformBinder; -impl BindUniform for GlUniformBinder +impl BindUniform for GlUniformBinder where T: GlUniformScalar, { @@ -67,7 +72,7 @@ where block: UniformMemberBlock, value: T, location: VariableLocation, - _: &(), + device: &glow::Context, ) -> Option<()> { if let Some(location) = location .location(block) @@ -75,12 +80,12 @@ where { if location.is_valid(BindingStage::VERTEX) { unsafe { - T::FACTORY(location.vertex, value); + T::FACTORY(device, location.vertex.as_ref(), value); } } if location.is_valid(BindingStage::FRAGMENT) { unsafe { - T::FACTORY(location.fragment, value); + T::FACTORY(device, location.fragment.as_ref(), value); } } Some(()) @@ -90,12 +95,12 @@ where } } -impl BindUniform for GlUniformBinder { +impl BindUniform for GlUniformBinder { fn bind_uniform( block: UniformMemberBlock, vec4: &[f32; 4], location: VariableLocation, - _: &(), + device: &glow::Context, ) -> Option<()> { if let Some(location) = location .location(block) @@ -103,10 +108,10 @@ impl BindUniform for GlUniformBinder { { unsafe { if location.is_valid(BindingStage::VERTEX) { - gl::Uniform4fv(location.vertex, 1, vec4.as_ptr()); + device.uniform_4_f32_slice(location.vertex.as_ref(), vec4); } if location.is_valid(BindingStage::FRAGMENT) { - gl::Uniform4fv(location.fragment, 1, vec4.as_ptr()); + device.uniform_4_f32_slice(location.fragment.as_ref(), vec4); } } Some(()) @@ -116,12 +121,12 @@ impl BindUniform for GlUniformBinder { } } -impl BindUniform for GlUniformBinder { +impl BindUniform for GlUniformBinder { fn bind_uniform( block: UniformMemberBlock, mat4: &[f32; 16], location: VariableLocation, - _: &(), + device: &glow::Context, ) -> Option<()> { if let Some(location) = location .location(block) @@ -129,10 +134,10 @@ impl BindUniform for GlUniformBinder { { unsafe { if location.is_valid(BindingStage::VERTEX) { - gl::UniformMatrix4fv(location.vertex, 1, gl::FALSE, mat4.as_ptr()); + device.uniform_matrix_4_f32_slice(location.vertex.as_ref(), false, mat4); } if location.is_valid(BindingStage::FRAGMENT) { - gl::UniformMatrix4fv(location.fragment, 1, gl::FALSE, mat4.as_ptr()); + device.uniform_matrix_4_f32_slice(location.fragment.as_ref(), false, mat4); } } Some(()) diff --git a/librashader-runtime-gl/src/error.rs b/librashader-runtime-gl/src/error.rs index 1b6da96..299b09d 100644 --- a/librashader-runtime-gl/src/error.rs +++ b/librashader-runtime-gl/src/error.rs @@ -1,6 +1,5 @@ //! OpenGL shader runtime errors. -use gl::types::GLenum; use librashader_preprocess::PreprocessError; use librashader_presets::ParsePresetError; use librashader_reflect::error::{ShaderCompileError, ShaderReflectError}; @@ -11,7 +10,7 @@ use thiserror::Error; #[derive(Error, Debug)] pub enum FilterChainError { #[error("fbo initialization error")] - FramebufferInit(GLenum), + FramebufferInit(u32), #[error("SPIRV reflection error")] SpirvCrossReflectError(#[from] spirv_cross2::SpirvCrossError), #[error("shader preset parse error")] @@ -30,6 +29,12 @@ pub enum FilterChainError { GLLinkError, #[error("opengl could not compile program")] GlCompileError, + #[error("opengl could not create samplers")] + GlSamplerError, + #[error("opengl could not create samplers")] + GlProgramError, + #[error("opengl error: {0}")] + GlError(String), } /// Result type for OpenGL filter chains. diff --git a/librashader-runtime-gl/src/filter_chain/filter_impl.rs b/librashader-runtime-gl/src/filter_chain/chain.rs similarity index 88% rename from librashader-runtime-gl/src/filter_chain/filter_impl.rs rename to librashader-runtime-gl/src/filter_chain/chain.rs index f17154b..3b066cb 100644 --- a/librashader-runtime-gl/src/filter_chain/filter_impl.rs +++ b/librashader-runtime-gl/src/filter_chain/chain.rs @@ -9,7 +9,6 @@ use crate::samplers::SamplerSet; use crate::texture::InputTexture; use crate::util::{gl_get_version, gl_u16_to_version}; use crate::{error, GLImage}; -use gl::types::GLuint; use librashader_common::Viewport; use librashader_presets::{ShaderPassConfig, ShaderPreset, TextureConfig}; @@ -19,6 +18,7 @@ use librashader_reflect::back::{CompileReflectShader, CompileShader}; use librashader_reflect::front::SpirvCompilation; use librashader_reflect::reflect::semantics::{ShaderSemantics, UniformMeta}; +use glow::HasContext; use librashader_cache::CachedCompilation; use librashader_common::map::FastHashMap; use librashader_reflect::reflect::cross::SpirvCross; @@ -30,6 +30,7 @@ use librashader_runtime::quad::QuadType; use librashader_runtime::render_target::RenderTarget; use librashader_runtime::scaling::ScaleFramebuffer; use std::collections::VecDeque; +use std::sync::Arc; pub(crate) struct FilterChainImpl { pub(crate) common: FilterCommon, @@ -51,10 +52,15 @@ pub(crate) struct FilterCommon { pub feedback_textures: Box<[InputTexture]>, pub history_textures: Box<[InputTexture]>, pub disable_mipmaps: bool, + pub context: Arc, } impl FilterChainImpl { - fn reflect_uniform_location(pipeline: GLuint, meta: &dyn UniformMeta) -> VariableLocation { + fn reflect_uniform_location( + ctx: &glow::Context, + pipeline: glow::Program, + meta: &dyn UniformMeta, + ) -> VariableLocation { let mut location = VariableLocation { ubo: None, push: None, @@ -66,9 +72,8 @@ impl FilterChainImpl { let vert_name = format!("LIBRA_UBO_VERTEX_INSTANCE.{}", meta.id()); let frag_name = format!("LIBRA_UBO_FRAGMENT_INSTANCE.{}", meta.id()); unsafe { - let vertex = gl::GetUniformLocation(pipeline, vert_name.as_ptr().cast()); - let fragment = gl::GetUniformLocation(pipeline, frag_name.as_ptr().cast()); - + let vertex = ctx.get_uniform_location(pipeline, &vert_name); + let fragment = ctx.get_uniform_location(pipeline, &frag_name); location.ubo = Some(UniformLocation { vertex, fragment }) } } @@ -77,9 +82,8 @@ impl FilterChainImpl { let vert_name = format!("LIBRA_PUSH_VERTEX_INSTANCE.{}", meta.id()); let frag_name = format!("LIBRA_PUSH_FRAGMENT_INSTANCE.{}", meta.id()); unsafe { - let vertex = gl::GetUniformLocation(pipeline, vert_name.as_ptr().cast()); - let fragment = gl::GetUniformLocation(pipeline, frag_name.as_ptr().cast()); - + let vertex = ctx.get_uniform_location(pipeline, &vert_name); + let fragment = ctx.get_uniform_location(pipeline, &frag_name); location.push = Some(UniformLocation { vertex, fragment }) } } @@ -128,14 +132,18 @@ impl FilterChainImpl { /// Load a filter chain from a pre-parsed `ShaderPreset`. pub(crate) unsafe fn load_from_preset( preset: ShaderPreset, + context: glow::Context, options: Option<&FilterChainOptionsGL>, ) -> error::Result { let disable_cache = options.map_or(false, |o| o.disable_cache); let (passes, semantics) = compile_passes(preset.shaders, &preset.textures, disable_cache)?; - let version = options.map_or_else(gl_get_version, |o| gl_u16_to_version(o.glsl_version)); + let version = options.map_or_else( + || gl_get_version(&context), + |o| gl_u16_to_version(&context, o.glsl_version), + ); // initialize passes - let filters = Self::init_passes(version, passes, &semantics, disable_cache)?; + let filters = Self::init_passes(&context, version, passes, &semantics, disable_cache)?; let default_filter = filters.first().map(|f| f.config.filter).unwrap_or_default(); let default_wrap = filters @@ -143,12 +151,13 @@ impl FilterChainImpl { .map(|f| f.config.wrap_mode) .unwrap_or_default(); - let samplers = SamplerSet::new(); + let samplers = SamplerSet::new(&context)?; // load luts - let luts = T::LoadLut::load_luts(&preset.textures)?; + let luts = T::LoadLut::load_luts(&context, &preset.textures)?; - let framebuffer_gen = || Ok::<_, FilterChainError>(T::FramebufferInterface::new(1)); + let context = Arc::new(context); + let framebuffer_gen = || T::FramebufferInterface::new(&context, 1); let input_gen = || InputTexture { image: Default::default(), filter: default_filter, @@ -173,7 +182,7 @@ impl FilterChainImpl { let (history_framebuffers, history_textures) = framebuffer_init.init_history()?; // create vertex objects - let draw_quad = T::DrawQuad::new(); + let draw_quad = T::DrawQuad::new(&context)?; Ok(FilterChainImpl { draw_last_pass_feedback: framebuffer_init.uses_final_pass_as_feedback(), @@ -190,12 +199,14 @@ impl FilterChainImpl { output_textures, feedback_textures, history_textures, + context, }, default_options: Default::default(), }) } fn init_passes( + context: &glow::Context, version: GlslVersion, passes: Vec, semantics: &ShaderSemantics, @@ -208,10 +219,11 @@ impl FilterChainImpl { let reflection = reflect.reflect(index, semantics)?; let glsl = reflect.compile(version)?; - let (program, ubo_location) = T::CompileShader::compile_program(glsl, !disable_cache)?; + let (program, ubo_location) = + T::CompileShader::compile_program(context, glsl, !disable_cache)?; let ubo_ring = if let Some(ubo) = &reflection.ubo { - let ring = UboRing::new(ubo.size); + let ring = T::UboRing::new(&context, ubo.size)?; Some(ring) } else { None @@ -227,7 +239,7 @@ impl FilterChainImpl { let uniform_bindings = reflection.meta.create_binding_map(|param| { UniformOffset::new( - Self::reflect_uniform_location(program, param), + Self::reflect_uniform_location(&context, program, param), param.offset(), ) }); @@ -290,7 +302,8 @@ impl FilterChainImpl { // do not need to rebind FBO 0 here since first `draw` will // bind automatically. - self.draw_quad.bind_vertices(QuadType::Offscreen); + self.draw_quad + .bind_vertices(&self.common.context, QuadType::Offscreen); let filter = passes[0].config.filter; let wrap_mode = passes[0].config.wrap_mode; @@ -343,7 +356,8 @@ impl FilterChainImpl { let passes_len = passes.len(); let (pass, last) = passes.split_at_mut(passes_len - 1); - self.draw_quad.bind_vertices(QuadType::Offscreen); + self.draw_quad + .bind_vertices(&self.common.context, QuadType::Offscreen); for (index, pass) in pass.iter_mut().enumerate() { let target = &self.output_framebuffers[index]; source.filter = pass.config.filter; @@ -366,7 +380,8 @@ impl FilterChainImpl { source = target; } - self.draw_quad.bind_vertices(QuadType::Final); + self.draw_quad + .bind_vertices(&self.common.context, QuadType::Final); // try to hint the optimizer assert_eq!(last.len(), 1); if let Some(pass) = last.iter_mut().next() { @@ -412,7 +427,7 @@ impl FilterChainImpl { self.push_history(input)?; - self.draw_quad.unbind_vertices(); + self.draw_quad.unbind_vertices(&self.common.context); Ok(()) } diff --git a/librashader-runtime-gl/src/filter_chain/inner.rs b/librashader-runtime-gl/src/filter_chain/inner.rs index 84394ca..18bf253 100644 --- a/librashader-runtime-gl/src/filter_chain/inner.rs +++ b/librashader-runtime-gl/src/filter_chain/inner.rs @@ -1,4 +1,4 @@ -use crate::filter_chain::filter_impl::FilterChainImpl; +use crate::filter_chain::chain::FilterChainImpl; pub(in crate::filter_chain) enum FilterChainDispatch { DirectStateAccess(FilterChainImpl), diff --git a/librashader-runtime-gl/src/filter_chain/mod.rs b/librashader-runtime-gl/src/filter_chain/mod.rs index 2d9b38c..2ca8cf0 100644 --- a/librashader-runtime-gl/src/filter_chain/mod.rs +++ b/librashader-runtime-gl/src/filter_chain/mod.rs @@ -1,18 +1,18 @@ -use std::panic::catch_unwind; -use std::path::Path; - use crate::error::{FilterChainError, Result}; -use crate::filter_chain::filter_impl::FilterChainImpl; +use crate::filter_chain::chain::FilterChainImpl; use crate::filter_chain::inner::FilterChainDispatch; use crate::options::{FilterChainOptionsGL, FrameOptionsGL}; use crate::{GLFramebuffer, GLImage}; use librashader_presets::ShaderPreset; +use std::panic::catch_unwind; +use std::path::Path; +use std::sync::Arc; -mod filter_impl; +mod chain; mod inner; mod parameters; -pub(crate) use filter_impl::FilterCommon; +pub(crate) use chain::FilterCommon; use librashader_common::Viewport; use librashader_presets::context::VideoDriver; @@ -24,6 +24,7 @@ pub struct FilterChainGL { impl FilterChainGL { /// Load a filter chain from a pre-parsed `ShaderPreset`. pub unsafe fn load_from_preset( + ctx: glow::Context, preset: ShaderPreset, options: Option<&FilterChainOptionsGL>, ) -> Result { @@ -31,13 +32,13 @@ impl FilterChainGL { if options.is_some_and(|options| options.use_dsa) { return Ok(Self { filter: FilterChainDispatch::DirectStateAccess(unsafe { - FilterChainImpl::load_from_preset(preset, options)? + FilterChainImpl::load_from_preset(preset, ctx, options)? }), }); } Ok(Self { filter: FilterChainDispatch::Compatibility(unsafe { - FilterChainImpl::load_from_preset(preset, options)? + FilterChainImpl::load_from_preset(preset, ctx, options)? }), }) }); @@ -46,12 +47,13 @@ impl FilterChainGL { /// Load the shader preset at the given path into a filter chain. pub unsafe fn load_from_path( + ctx: glow::Context, path: impl AsRef, options: Option<&FilterChainOptionsGL>, ) -> Result { // load passes from preset let preset = ShaderPreset::try_parse_with_driver_context(path, VideoDriver::GlCore)?; - unsafe { Self::load_from_preset(preset, options) } + unsafe { Self::load_from_preset(ctx, preset, options) } } /// Process a frame with the input image. @@ -74,4 +76,12 @@ impl FilterChainGL { }, } } + + /// Get the GL context associated with this filter chain + pub fn get_context(&self) -> &Arc { + match &self.filter { + FilterChainDispatch::DirectStateAccess(p) => &p.common.context, + FilterChainDispatch::Compatibility(p) => &p.common.context, + } + } } diff --git a/librashader-runtime-gl/src/filter_chain/parameters.rs b/librashader-runtime-gl/src/filter_chain/parameters.rs index e6eb793..b4f2e99 100644 --- a/librashader-runtime-gl/src/filter_chain/parameters.rs +++ b/librashader-runtime-gl/src/filter_chain/parameters.rs @@ -1,4 +1,4 @@ -use crate::filter_chain::filter_impl::FilterChainImpl; +use crate::filter_chain::chain::FilterChainImpl; use crate::filter_chain::inner::FilterChainDispatch; use crate::gl::GLInterface; use crate::FilterChainGL; diff --git a/librashader-runtime-gl/src/filter_pass.rs b/librashader-runtime-gl/src/filter_pass.rs index 4c5d487..071bef2 100644 --- a/librashader-runtime-gl/src/filter_pass.rs +++ b/librashader-runtime-gl/src/filter_pass.rs @@ -1,4 +1,4 @@ -use gl::types::{GLint, GLsizei, GLuint}; +use glow::HasContext; use librashader_reflect::reflect::ShaderReflection; use librashader_common::map::FastHashMap; @@ -32,8 +32,8 @@ impl UniformOffset { pub(crate) struct FilterPass { pub reflection: ShaderReflection, - pub program: GLuint, - pub ubo_location: UniformLocation, + pub program: glow::Program, + pub ubo_location: UniformLocation>, pub ubo_ring: Option, pub(crate) uniform_storage: GlUniformStorage, pub uniform_bindings: FastHashMap, @@ -47,7 +47,7 @@ impl TextureInput for InputTexture { } } -impl ContextOffset for UniformOffset { +impl ContextOffset for UniformOffset { fn offset(&self) -> MemberOffset { self.offset } @@ -61,7 +61,7 @@ impl BindSemantics for Filter type InputTexture = InputTexture; type SamplerSet = SamplerSet; type DescriptorSet<'a> = (); - type DeviceContext = (); + type DeviceContext = glow::Context; type UniformOffset = UniformOffset; fn bind_texture<'a>( @@ -69,9 +69,9 @@ impl BindSemantics for Filter samplers: &Self::SamplerSet, binding: &TextureBinding, texture: &Self::InputTexture, - _device: &Self::DeviceContext, + device: &Self::DeviceContext, ) { - T::BindTexture::bind_texture(samplers, binding, texture); + T::BindTexture::bind_texture(device, samplers, binding, texture); } } @@ -85,17 +85,19 @@ impl FilterPass { viewport: &Viewport<&GLFramebuffer>, original: &InputTexture, source: &InputTexture, - output: RenderTarget, + output: RenderTarget, ) { let framebuffer = output.output; if self.config.mipmap_input && !parent.disable_mipmaps { - T::BindTexture::gen_mipmaps(source); + T::BindTexture::gen_mipmaps(&parent.context, source); } unsafe { - gl::BindFramebuffer(gl::FRAMEBUFFER, framebuffer.fbo); - gl::UseProgram(self.program); + parent + .context + .bind_framebuffer(glow::FRAMEBUFFER, Some(framebuffer.fbo)); + parent.context.use_program(Some(self.program)); } self.build_semantics( @@ -110,38 +112,48 @@ impl FilterPass { source, ); - if self.ubo_location.vertex != gl::INVALID_INDEX - && self.ubo_location.fragment != gl::INVALID_INDEX + if self + .ubo_location + .vertex + .is_some_and(|index| index != glow::INVALID_INDEX) + && self + .ubo_location + .fragment + .is_some_and(|index| index != glow::INVALID_INDEX) { if let (Some(ubo), Some(ring)) = (&self.reflection.ubo, &mut self.ubo_ring) { - ring.bind_for_frame(ubo, &self.ubo_location, &self.uniform_storage) + ring.bind_for_frame( + &parent.context, + ubo, + &self.ubo_location, + &self.uniform_storage, + ) } } unsafe { framebuffer.clear::(); - let framebuffer_size = framebuffer.size; - gl::Viewport( + parent.context.viewport( output.x, output.y, - framebuffer_size.width as GLsizei, - framebuffer_size.height as GLsizei, + framebuffer_size.width as i32, + framebuffer_size.height as i32, ); - if framebuffer.format == gl::SRGB8_ALPHA8 { - gl::Enable(gl::FRAMEBUFFER_SRGB); + if framebuffer.format == glow::SRGB8_ALPHA8 { + parent.context.enable(glow::FRAMEBUFFER_SRGB); } else { - gl::Disable(gl::FRAMEBUFFER_SRGB); + parent.context.disable(glow::FRAMEBUFFER_SRGB); } - gl::Disable(gl::CULL_FACE); - gl::Disable(gl::BLEND); - gl::Disable(gl::DEPTH_TEST); + parent.context.disable(glow::CULL_FACE); + parent.context.disable(glow::BLEND); + parent.context.disable(glow::DEPTH_TEST); - gl::DrawArrays(gl::TRIANGLE_STRIP, 0, 4); - gl::Disable(gl::FRAMEBUFFER_SRGB); - gl::BindFramebuffer(gl::FRAMEBUFFER, 0); + parent.context.draw_arrays(glow::TRIANGLE_STRIP, 0, 4); + parent.context.disable(glow::FRAMEBUFFER_SRGB); + parent.context.bind_framebuffer(glow::FRAMEBUFFER, None); } } } @@ -171,7 +183,7 @@ impl FilterPass { source: &InputTexture, ) { Self::bind_semantics( - &(), + &parent.context, &parent.samplers, &mut self.uniform_storage, &mut (), diff --git a/librashader-runtime-gl/src/framebuffer.rs b/librashader-runtime-gl/src/framebuffer.rs index 74a04ab..dd737a6 100644 --- a/librashader-runtime-gl/src/framebuffer.rs +++ b/librashader-runtime-gl/src/framebuffer.rs @@ -1,4 +1,3 @@ -use gl::types::{GLenum, GLuint}; use librashader_common::Size; /// A handle to an OpenGL texture with format and size information. @@ -7,9 +6,9 @@ use librashader_common::Size; #[derive(Default, Debug, Copy, Clone)] pub struct GLImage { /// A GLuint to the texture. - pub handle: GLuint, + pub handle: Option, /// The format of the texture. - pub format: GLenum, + pub format: u32, /// The size of the texture. pub size: Size, } diff --git a/librashader-runtime-gl/src/gl/framebuffer.rs b/librashader-runtime-gl/src/gl/framebuffer.rs index a8d31ea..2bde540 100644 --- a/librashader-runtime-gl/src/gl/framebuffer.rs +++ b/librashader-runtime-gl/src/gl/framebuffer.rs @@ -2,23 +2,25 @@ use crate::error::{FilterChainError, Result}; use crate::framebuffer::GLImage; use crate::gl::FramebufferInterface; use crate::texture::InputTexture; -use gl::types::{GLenum, GLuint}; +use glow::HasContext; use librashader_common::{FilterMode, ImageFormat, Size, WrapMode}; use librashader_presets::Scale2D; use librashader_runtime::scaling::ScaleFramebuffer; +use std::sync::Arc; /// A handle to an OpenGL FBO and its backing texture with format and size information. /// /// Generally for use as render targets. #[derive(Debug)] pub struct GLFramebuffer { - pub(crate) image: GLuint, - pub(crate) fbo: GLuint, + pub(crate) image: Option, + pub(crate) fbo: glow::Framebuffer, pub(crate) size: Size, - pub(crate) format: GLenum, + pub(crate) format: u32, pub(crate) max_levels: u32, pub(crate) mip_levels: u32, pub(crate) is_raw: bool, + pub(crate) ctx: Arc, } impl GLFramebuffer { @@ -26,9 +28,10 @@ impl GLFramebuffer { /// /// The framebuffer will not be deleted when this struct is dropped. pub fn new_from_raw( - texture: GLuint, - fbo: GLuint, - format: GLenum, + ctx: Arc, + texture: Option, + fbo: glow::Framebuffer, + format: u32, size: Size, miplevels: u32, ) -> GLFramebuffer { @@ -38,8 +41,9 @@ impl GLFramebuffer { format, max_levels: miplevels, mip_levels: miplevels, - fbo: fbo, + fbo, is_raw: true, + ctx, } } @@ -92,11 +96,9 @@ impl Drop for GLFramebuffer { } unsafe { - if self.fbo != 0 { - gl::DeleteFramebuffers(1, &self.fbo); - } - if self.image != 0 { - gl::DeleteTextures(1, &self.image); + self.ctx.delete_framebuffer(self.fbo); + if let Some(image) = self.image { + self.ctx.delete_texture(image); } } } diff --git a/librashader-runtime-gl/src/gl/gl3/compile_program.rs b/librashader-runtime-gl/src/gl/gl3/compile_program.rs index abb7aa0..7183f73 100644 --- a/librashader-runtime-gl/src/gl/gl3/compile_program.rs +++ b/librashader-runtime-gl/src/gl/gl3/compile_program.rs @@ -1,8 +1,9 @@ use crate::binding::UniformLocation; +use crate::error; use crate::error::FilterChainError; use crate::gl::CompileProgram; use crate::util; -use gl::types::{GLint, GLuint}; +use glow::HasContext; use librashader_reflect::back::glsl::CrossGlslContext; use librashader_reflect::back::ShaderCompilerOutput; use spirv_cross2::reflect::ResourceType; @@ -12,18 +13,20 @@ pub struct Gl3CompileProgram; impl CompileProgram for Gl3CompileProgram { fn compile_program( + ctx: &glow::Context, glsl: ShaderCompilerOutput, _cache: bool, - ) -> crate::error::Result<(GLuint, UniformLocation)> { + ) -> error::Result<(glow::Program, UniformLocation>)> { let vertex_resources = glsl.context.artifact.vertex.shader_resources()?; 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 vertex = util::gl_compile_shader(ctx, glow::VERTEX_SHADER, glsl.vertex.as_str())?; + let fragment = + util::gl_compile_shader(ctx, glow::FRAGMENT_SHADER, glsl.fragment.as_str())?; - let program = gl::CreateProgram(); - gl::AttachShader(program, vertex); - gl::AttachShader(program, fragment); + let program = ctx.create_program().map_err(FilterChainError::GlError)?; + ctx.attach_shader(program, vertex); + ctx.attach_shader(program, fragment); for res in vertex_resources.resources_for_type(ResourceType::StageInput)? { let Some(loc) = glsl @@ -36,43 +39,33 @@ impl CompileProgram for Gl3CompileProgram { continue; }; - let mut name = res.name.to_string(); - name.push('\0'); - - gl::BindAttribLocation(program, loc, name.as_str().as_ptr().cast()) + ctx.bind_attrib_location(program, loc, &res.name.as_ref()); } - gl::LinkProgram(program); - gl::DeleteShader(vertex); - gl::DeleteShader(fragment); - let mut status = 0; - gl::GetProgramiv(program, gl::LINK_STATUS, &mut status); - if status != 1 { + ctx.link_program(program); + ctx.delete_shader(vertex); + ctx.delete_shader(fragment); + + if !ctx.get_program_link_status(program) { return Err(FilterChainError::GLLinkError); } - gl::UseProgram(program); + ctx.use_program(Some(program)); for (name, binding) in &glsl.context.sampler_bindings { - let location = gl::GetUniformLocation(program, name.as_str().as_ptr().cast()); - if location >= 0 { + let location = ctx.get_uniform_location(program, name); + if let Some(location) = location { // eprintln!("setting sampler {location} to sample from {binding}"); - gl::Uniform1i(location, *binding as GLint); + ctx.uniform_1_i32(Some(&location), *binding as i32); } } - gl::UseProgram(0); + ctx.use_program(None); ( 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(), - ), + vertex: ctx.get_uniform_block_index(program, "LIBRA_UBO_VERTEX"), + fragment: ctx.get_uniform_block_index(program, "LIBRA_UBO_FRAGMENT"), }, ) }; diff --git a/librashader-runtime-gl/src/gl/gl3/draw_quad.rs b/librashader-runtime-gl/src/gl/gl3/draw_quad.rs index 1a1a62f..b2dc603 100644 --- a/librashader-runtime-gl/src/gl/gl3/draw_quad.rs +++ b/librashader-runtime-gl/src/gl/gl3/draw_quad.rs @@ -1,102 +1,110 @@ -use crate::gl::DrawQuad; -use crate::gl::{FINAL_VBO_DATA, OFFSCREEN_VBO_DATA}; +use crate::error; +use crate::error::FilterChainError; +use crate::gl::{DrawQuad, FINAL_VBO_DATA, OFFSCREEN_VBO_DATA}; use bytemuck::offset_of; -use gl::types::{GLsizei, GLsizeiptr, GLuint}; +use glow::HasContext; use librashader_runtime::quad::{QuadType, VertexInput}; + pub struct Gl3DrawQuad { - vbo: [GLuint; 2], - vao: GLuint, + vbo: [glow::Buffer; 2], + vao: glow::VertexArray, } impl DrawQuad for Gl3DrawQuad { - fn new() -> Gl3DrawQuad { - let mut vbo = [0, 0]; - let mut vao = 0; + fn new(ctx: &glow::Context) -> error::Result { + let vbo; + let vao; unsafe { - gl::GenBuffers(2, vbo.as_mut_ptr()); - gl::BindBuffer(gl::ARRAY_BUFFER, vbo[0]); - gl::BufferData( - gl::ARRAY_BUFFER, - std::mem::size_of_val(OFFSCREEN_VBO_DATA) as GLsizeiptr, - OFFSCREEN_VBO_DATA.as_ptr().cast(), - gl::STATIC_DRAW, + vbo = [ + ctx.create_buffer() + .map_err(FilterChainError::GlError)?, + ctx.create_buffer() + .map_err(FilterChainError::GlError)?, + ]; + + ctx.bind_buffer(glow::ARRAY_BUFFER, Some(vbo[0])); + ctx.buffer_data_u8_slice( + glow::ARRAY_BUFFER, + bytemuck::cast_slice(OFFSCREEN_VBO_DATA), + glow::STATIC_DRAW, ); - gl::BindBuffer(gl::ARRAY_BUFFER, vbo[1]); - gl::BufferData( - gl::ARRAY_BUFFER, - std::mem::size_of_val(FINAL_VBO_DATA) as GLsizeiptr, - FINAL_VBO_DATA.as_ptr().cast(), - gl::STATIC_DRAW, + ctx.bind_buffer(glow::ARRAY_BUFFER, Some(vbo[1])); + + ctx.buffer_data_u8_slice( + glow::ARRAY_BUFFER, + bytemuck::cast_slice(FINAL_VBO_DATA), + glow::STATIC_DRAW, ); - gl::BindBuffer(gl::ARRAY_BUFFER, 0); - gl::GenVertexArrays(1, &mut vao); + ctx.bind_buffer(glow::ARRAY_BUFFER, None); + + vao = ctx + .create_vertex_array() + .map_err(FilterChainError::GlError)?; } - Self { vbo, vao } + Ok(Self { vbo, vao }) } - fn bind_vertices(&self, quad_type: QuadType) { + fn bind_vertices(&self, ctx: &glow::Context, quad_type: QuadType) { let buffer_index = match quad_type { QuadType::Offscreen => 0, QuadType::Final => 1, }; unsafe { - gl::BindVertexArray(self.vao); - gl::EnableVertexAttribArray(0); - gl::EnableVertexAttribArray(1); + ctx.bind_vertex_array(Some(self.vao)); + ctx.enable_vertex_attrib_array(0); + ctx.enable_vertex_attrib_array(1); - gl::BindBuffer(gl::ARRAY_BUFFER, self.vbo[buffer_index]); + ctx.bind_buffer(glow::ARRAY_BUFFER, Some(self.vbo[buffer_index])); - // the provided pointers are of OpenGL provenance with respect to the buffer bound to quad_vbo, - // and not a known provenance to the Rust abstract machine, therefore we give it invalid pointers. - // that are inexpressible in Rust - gl::VertexAttribPointer( + ctx.vertex_attrib_pointer_f32( 0, 4, - gl::FLOAT, - gl::FALSE, - std::mem::size_of::() as GLsizei, - sptr::invalid(offset_of!(VertexInput, position)), + glow::FLOAT, + false, + std::mem::size_of::() as i32, + offset_of!(VertexInput, position) as i32, ); - gl::VertexAttribPointer( + + ctx.vertex_attrib_pointer_f32( 1, 2, - gl::FLOAT, - gl::FALSE, - std::mem::size_of::() as GLsizei, - sptr::invalid(offset_of!(VertexInput, texcoord)), + glow::FLOAT, + false, + std::mem::size_of::() as i32, + offset_of!(VertexInput, texcoord) as i32, ); } } - fn unbind_vertices(&self) { + fn unbind_vertices(&self, ctx: &glow::Context) { unsafe { - gl::DisableVertexAttribArray(0); - gl::DisableVertexAttribArray(1); - gl::BindVertexArray(0); - gl::BindBuffer(gl::ARRAY_BUFFER, 0); + ctx.disable_vertex_attrib_array(0); + ctx.disable_vertex_attrib_array(1); + ctx.bind_vertex_array(None); + ctx.bind_buffer(glow::ARRAY_BUFFER, None); } } } -impl Drop for Gl3DrawQuad { - fn drop(&mut self) { - unsafe { - if self.vbo[0] != 0 { - gl::DeleteBuffers(1, &self.vbo[0]); - } - - if self.vbo[1] != 0 { - gl::DeleteBuffers(1, &self.vbo[1]); - } - - if self.vao != 0 { - gl::DeleteVertexArrays(1, &self.vao) - } - } - } -} +// impl Drop for Gl3DrawQuad { +// fn drop(&mut self) { +// unsafe { +// if let Some(vbo) = self.vbo { +// glow::DeleteBuffers(1, &self.vbo[0]); +// } +// +// if self.vbo[1] != 0 { +// glow::DeleteBuffers(1, &self.vbo[1]); +// } +// +// if self.vao != 0 { +// glow::DeleteVertexArrays(1, &self.vao) +// } +// } +// } +// } diff --git a/librashader-runtime-gl/src/gl/gl3/framebuffer.rs b/librashader-runtime-gl/src/gl/gl3/framebuffer.rs index 8b55809..eecdecd 100644 --- a/librashader-runtime-gl/src/gl/gl3/framebuffer.rs +++ b/librashader-runtime-gl/src/gl/gl3/framebuffer.rs @@ -1,82 +1,51 @@ +use crate::error; use crate::error::{FilterChainError, Result}; use crate::framebuffer::GLImage; use crate::gl::framebuffer::GLFramebuffer; use crate::gl::FramebufferInterface; -use gl::types::{GLenum, GLint, GLsizei}; +use glow::HasContext; use librashader_common::{ImageFormat, Size}; -use librashader_presets::Scale2D; -use librashader_runtime::scaling::{MipmapSize, ViewportSize}; +use librashader_runtime::scaling::MipmapSize; +use std::sync::Arc; #[derive(Debug)] pub struct Gl3Framebuffer; impl FramebufferInterface for Gl3Framebuffer { - fn new(max_levels: u32) -> GLFramebuffer { - let mut framebuffer = 0; + fn new(ctx: &Arc, max_levels: u32) -> error::Result { unsafe { - gl::GenFramebuffers(1, &mut framebuffer); - gl::BindFramebuffer(gl::FRAMEBUFFER, framebuffer); - gl::BindFramebuffer(gl::FRAMEBUFFER, 0); - } + let framebuffer = ctx + .create_framebuffer() + .map_err(FilterChainError::GlError)?; + ctx.bind_framebuffer(glow::FRAMEBUFFER, Some(framebuffer)); + ctx.bind_framebuffer(glow::FRAMEBUFFER, None); - GLFramebuffer { - image: 0, - size: Size { - width: 1, - height: 1, - }, - format: 0, - max_levels, - mip_levels: 0, - fbo: framebuffer, - is_raw: false, - } - } - - fn scale( - fb: &mut GLFramebuffer, - scaling: Scale2D, - format: ImageFormat, - viewport_size: &Size, - source_size: &Size, - original_size: &Size, - mipmap: bool, - ) -> Result> { - if fb.is_raw { - return Ok(fb.size); - } - - let size = source_size.scale_viewport(scaling, *viewport_size, *original_size); - - if fb.size != size || (mipmap && fb.max_levels == 1) || (!mipmap && fb.max_levels != 1) { - fb.size = size; - if mipmap { - fb.max_levels = u32::MAX; - } else { - fb.max_levels = 1 - } - Self::init( - fb, - size, - if format == ImageFormat::Unknown { - ImageFormat::R8G8B8A8Unorm - } else { - format + Ok(GLFramebuffer { + image: None, + size: Size { + width: 1, + height: 1, }, - )?; + format: 0, + max_levels, + mip_levels: 0, + fbo: framebuffer, + is_raw: false, + ctx: Arc::clone(&ctx), + }) } - Ok(size) } + fn clear(fb: &GLFramebuffer) { unsafe { if REBIND { - gl::BindFramebuffer(gl::FRAMEBUFFER, fb.fbo); + fb.ctx.bind_framebuffer(glow::FRAMEBUFFER, Some(fb.fbo)); } - 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); + fb.ctx.color_mask(true, true, true, true); + fb.ctx.clear_color(0.0, 0.0, 0.0, 0.0); + fb.ctx.clear(glow::COLOR_BUFFER_BIT); if REBIND { - gl::BindFramebuffer(gl::FRAMEBUFFER, 0); + fb.ctx.bind_framebuffer(glow::FRAMEBUFFER, None); } } } @@ -87,70 +56,70 @@ impl FramebufferInterface for Gl3Framebuffer { } unsafe { - gl::BindFramebuffer(gl::FRAMEBUFFER, fb.fbo); + fb.ctx.bind_framebuffer(glow::FRAMEBUFFER, Some(fb.fbo)); - gl::FramebufferTexture2D( - gl::READ_FRAMEBUFFER, - gl::COLOR_ATTACHMENT0, - gl::TEXTURE_2D, + fb.ctx.framebuffer_texture_2d( + glow::READ_FRAMEBUFFER, + glow::COLOR_ATTACHMENT0, + glow::TEXTURE_2D, image.handle, 0, ); - - gl::FramebufferTexture2D( - gl::DRAW_FRAMEBUFFER, - gl::COLOR_ATTACHMENT1, - gl::TEXTURE_2D, + fb.ctx.framebuffer_texture_2d( + glow::DRAW_FRAMEBUFFER, + glow::COLOR_ATTACHMENT1, + glow::TEXTURE_2D, fb.image, 0, ); - gl::ReadBuffer(gl::COLOR_ATTACHMENT0); - gl::DrawBuffer(gl::COLOR_ATTACHMENT1); - gl::BlitFramebuffer( + + fb.ctx.read_buffer(glow::COLOR_ATTACHMENT0); + fb.ctx.draw_buffer(glow::COLOR_ATTACHMENT1); + + fb.ctx.blit_framebuffer( 0, 0, - fb.size.width as GLint, - fb.size.height as GLint, + fb.size.width as i32, + fb.size.height as i32, 0, 0, - fb.size.width as GLint, - fb.size.height as GLint, - gl::COLOR_BUFFER_BIT, - gl::NEAREST, + fb.size.width as i32, + fb.size.height as i32, + glow::COLOR_BUFFER_BIT, + glow::NEAREST, ); // cleanup after ourselves. - gl::FramebufferTexture2D( - gl::READ_FRAMEBUFFER, - gl::COLOR_ATTACHMENT0, - gl::TEXTURE_2D, - 0, + fb.ctx.framebuffer_texture_2d( + glow::READ_FRAMEBUFFER, + glow::COLOR_ATTACHMENT0, + glow::TEXTURE_2D, + None, 0, ); - - gl::FramebufferTexture2D( - gl::DRAW_FRAMEBUFFER, - gl::COLOR_ATTACHMENT1, - gl::TEXTURE_2D, - 0, + fb.ctx.framebuffer_texture_2d( + glow::DRAW_FRAMEBUFFER, + glow::COLOR_ATTACHMENT1, + glow::TEXTURE_2D, + None, 0, ); // set this back to color_attachment 0 - gl::FramebufferTexture2D( - gl::FRAMEBUFFER, - gl::COLOR_ATTACHMENT0, - gl::TEXTURE_2D, + fb.ctx.framebuffer_texture_2d( + glow::FRAMEBUFFER, + glow::COLOR_ATTACHMENT0, + glow::TEXTURE_2D, fb.image, 0, ); - gl::BindFramebuffer(gl::FRAMEBUFFER, 0); + fb.ctx.bind_framebuffer(glow::FRAMEBUFFER, None); } Ok(()) } - fn init(fb: &mut GLFramebuffer, mut size: Size, format: impl Into) -> Result<()> { + fn init(fb: &mut GLFramebuffer, mut size: Size, format: impl Into) -> Result<()> { if fb.is_raw { return Ok(()); } @@ -158,22 +127,23 @@ impl FramebufferInterface for Gl3Framebuffer { fb.size = size; unsafe { - gl::BindFramebuffer(gl::FRAMEBUFFER, fb.fbo); + fb.ctx.bind_framebuffer(glow::FRAMEBUFFER, Some(fb.fbo)); // reset the framebuffer image - if fb.image != 0 { - gl::FramebufferTexture2D( - gl::FRAMEBUFFER, - gl::COLOR_ATTACHMENT0, - gl::TEXTURE_2D, - 0, + if let Some(image) = fb.image { + fb.ctx.framebuffer_texture_2d( + glow::FRAMEBUFFER, + glow::COLOR_ATTACHMENT0, + glow::TEXTURE_2D, + None, 0, ); - gl::DeleteTextures(1, &fb.image); + + fb.ctx.delete_texture(image); } - gl::GenTextures(1, &mut fb.image); - gl::BindTexture(gl::TEXTURE_2D, fb.image); + fb.image = Some(fb.ctx.create_texture().map_err(FilterChainError::GlError)?); + fb.ctx.bind_texture(glow::TEXTURE_2D, fb.image); if size.width == 0 { size.width = 1; @@ -190,36 +160,41 @@ impl FramebufferInterface for Gl3Framebuffer { fb.mip_levels = 1; } - gl::TexStorage2D( - gl::TEXTURE_2D, - fb.mip_levels as GLsizei, + fb.ctx.tex_storage_2d( + glow::TEXTURE_2D, + fb.mip_levels as i32, fb.format, - size.width as GLsizei, - size.height as GLsizei, + size.width as i32, + size.height as i32, ); - gl::FramebufferTexture2D( - gl::FRAMEBUFFER, - gl::COLOR_ATTACHMENT0, - gl::TEXTURE_2D, + fb.ctx.framebuffer_texture_2d( + glow::FRAMEBUFFER, + glow::COLOR_ATTACHMENT0, + glow::TEXTURE_2D, fb.image, 0, ); - let status = gl::CheckFramebufferStatus(gl::FRAMEBUFFER); - if status != gl::FRAMEBUFFER_COMPLETE { + let status = fb.ctx.check_framebuffer_status(glow::FRAMEBUFFER); + if status != glow::FRAMEBUFFER_COMPLETE { match status { - gl::FRAMEBUFFER_UNSUPPORTED => { - gl::FramebufferTexture2D( - gl::FRAMEBUFFER, - gl::COLOR_ATTACHMENT0, - gl::TEXTURE_2D, - 0, + glow::FRAMEBUFFER_UNSUPPORTED => { + fb.ctx.framebuffer_texture_2d( + glow::FRAMEBUFFER, + glow::COLOR_ATTACHMENT0, + glow::TEXTURE_2D, + None, 0, ); - gl::DeleteTextures(1, &fb.image); - gl::GenTextures(1, &mut fb.image); - gl::BindTexture(gl::TEXTURE_2D, fb.image); + + if let Some(image) = fb.image { + fb.ctx.delete_texture(image); + } + + fb.image = + Some(fb.ctx.create_texture().map_err(FilterChainError::GlError)?); + fb.ctx.bind_texture(glow::TEXTURE_2D, fb.image); fb.mip_levels = size.calculate_miplevels(); if fb.mip_levels > fb.max_levels { @@ -229,29 +204,31 @@ impl FramebufferInterface for Gl3Framebuffer { fb.mip_levels = 1; } - gl::TexStorage2D( - gl::TEXTURE_2D, - fb.mip_levels as GLsizei, + fb.ctx.tex_storage_2d( + glow::TEXTURE_2D, + fb.mip_levels as i32, ImageFormat::R8G8B8A8Unorm.into(), - size.width as GLsizei, - size.height as GLsizei, + size.width as i32, + size.height as i32, ); - gl::FramebufferTexture2D( - gl::FRAMEBUFFER, - gl::COLOR_ATTACHMENT0, - gl::TEXTURE_2D, + + fb.ctx.framebuffer_texture_2d( + glow::FRAMEBUFFER, + glow::COLOR_ATTACHMENT0, + glow::TEXTURE_2D, fb.image, 0, ); + // fb.init = - // gl::CheckFramebufferStatus(gl::FRAMEBUFFER) == gl::FRAMEBUFFER_COMPLETE; + // glow::CheckFramebufferStatus(glow::FRAMEBUFFER) == glow::FRAMEBUFFER_COMPLETE; } _ => return Err(FilterChainError::FramebufferInit(status)), } } - gl::BindFramebuffer(gl::FRAMEBUFFER, 0); - gl::BindTexture(gl::TEXTURE_2D, 0); + fb.ctx.bind_framebuffer(glow::FRAMEBUFFER, None); + fb.ctx.bind_texture(glow::TEXTURE_2D, None); } Ok(()) diff --git a/librashader-runtime-gl/src/gl/gl3/lut_load.rs b/librashader-runtime-gl/src/gl/gl3/lut_load.rs index d785e99..9284a80 100644 --- a/librashader-runtime-gl/src/gl/gl3/lut_load.rs +++ b/librashader-runtime-gl/src/gl/gl3/lut_load.rs @@ -1,23 +1,23 @@ -use crate::error::Result; +use crate::error::{FilterChainError, Result}; use crate::framebuffer::GLImage; use crate::gl::LoadLut; use crate::texture::InputTexture; -use gl::types::{GLsizei, GLuint}; +use glow::{HasContext, PixelUnpackData}; use librashader_common::map::FastHashMap; use librashader_presets::TextureConfig; use librashader_runtime::image::{Image, ImageError, UVDirection}; use librashader_runtime::scaling::MipmapSize; use rayon::prelude::*; +use std::num::NonZeroU32; pub struct Gl3LutLoad; impl LoadLut for Gl3LutLoad { - fn load_luts(textures: &[TextureConfig]) -> Result> { + fn load_luts( + ctx: &glow::Context, + textures: &[TextureConfig], + ) -> Result> { let mut luts = FastHashMap::default(); - let pixel_unpack = unsafe { - let mut binding = 0; - gl::GetIntegerv(gl::PIXEL_UNPACK_BUFFER_BINDING, &mut binding); - binding - }; + let pixel_unpack = unsafe { ctx.get_parameter_i32(glow::PIXEL_UNPACK_BUFFER_BINDING) }; let images = textures .par_iter() @@ -31,47 +31,49 @@ impl LoadLut for Gl3LutLoad { 1u32 }; - let mut handle = 0; - unsafe { - gl::GenTextures(1, &mut handle); - gl::BindTexture(gl::TEXTURE_2D, handle); - gl::TexStorage2D( - gl::TEXTURE_2D, - levels as GLsizei, - gl::RGBA8, - image.size.width as GLsizei, - image.size.height as GLsizei, + let handle = unsafe { + let handle = ctx.create_texture().map_err(FilterChainError::GlError)?; + + ctx.bind_texture(glow::TEXTURE_2D, Some(handle)); + ctx.tex_storage_2d( + glow::TEXTURE_2D, + levels as i32, + glow::RGBA8, + image.size.width as i32, + image.size.height as i32, ); - gl::PixelStorei(gl::UNPACK_ROW_LENGTH, 0); - gl::PixelStorei(gl::UNPACK_ALIGNMENT, 4); - gl::BindBuffer(gl::PIXEL_UNPACK_BUFFER, 0); - gl::TexSubImage2D( - gl::TEXTURE_2D, + ctx.pixel_store_i32(glow::UNPACK_ROW_LENGTH, 0); + ctx.pixel_store_i32(glow::UNPACK_ALIGNMENT, 4); + ctx.bind_buffer(glow::PIXEL_UNPACK_BUFFER, None); + + ctx.tex_sub_image_2d( + glow::TEXTURE_2D, 0, 0, 0, - image.size.width as GLsizei, - image.size.height as GLsizei, - gl::RGBA, - gl::UNSIGNED_BYTE, - image.bytes.as_ptr().cast(), + image.size.width as i32, + image.size.height as i32, + glow::RGBA, + glow::UNSIGNED_BYTE, + PixelUnpackData::Slice(&image.bytes), ); let mipmap = levels > 1; if mipmap { - gl::GenerateMipmap(gl::TEXTURE_2D); + ctx.generate_mipmap(glow::TEXTURE_2D); } - gl::BindTexture(gl::TEXTURE_2D, 0); - } + ctx.bind_texture(glow::TEXTURE_2D, None); + handle + }; luts.insert( index, InputTexture { image: GLImage { - handle, - format: gl::RGBA8, + handle: Some(handle), + format: glow::RGBA8, size: image.size, }, filter: texture.filter_mode, @@ -82,7 +84,12 @@ impl LoadLut for Gl3LutLoad { } unsafe { - gl::BindBuffer(gl::PIXEL_UNPACK_BUFFER, pixel_unpack as GLuint); + // todo: webgl doesn't support this. + let pixel_unpack = NonZeroU32::try_from(pixel_unpack as u32) + .ok() + .map(glow::NativeBuffer); + + ctx.bind_buffer(glow::PIXEL_UNPACK_BUFFER, pixel_unpack); }; Ok(luts) } diff --git a/librashader-runtime-gl/src/gl/gl3/texture_bind.rs b/librashader-runtime-gl/src/gl/gl3/texture_bind.rs index 73e8cdd..3987f37 100644 --- a/librashader-runtime-gl/src/gl/gl3/texture_bind.rs +++ b/librashader-runtime-gl/src/gl/gl3/texture_bind.rs @@ -1,29 +1,34 @@ use crate::gl::BindTexture; use crate::samplers::SamplerSet; use crate::texture::InputTexture; +use glow::HasContext; use librashader_reflect::reflect::semantics::TextureBinding; pub struct Gl3BindTexture; impl BindTexture for Gl3BindTexture { - fn bind_texture(samplers: &SamplerSet, binding: &TextureBinding, texture: &InputTexture) { + fn bind_texture( + ctx: &glow::Context, + samplers: &SamplerSet, + binding: &TextureBinding, + texture: &InputTexture, + ) { unsafe { - // eprintln!("setting {} to texunit {}", texture.image.handle, binding.binding); - gl::ActiveTexture(gl::TEXTURE0 + binding.binding); - - gl::BindTexture(gl::TEXTURE_2D, texture.image.handle); - gl::BindSampler( + // eprintln!("setting {} to texunit {}", texture.image.handle, binding.binding);; + ctx.active_texture(glow::TEXTURE0 + binding.binding); + ctx.bind_texture(glow::TEXTURE_2D, texture.image.handle); + ctx.bind_sampler( binding.binding, - samplers.get(texture.wrap_mode, texture.filter, texture.mip_filter), + Some(samplers.get(texture.wrap_mode, texture.filter, texture.mip_filter)), ); } } - fn gen_mipmaps(texture: &InputTexture) { + fn gen_mipmaps(ctx: &glow::Context, texture: &InputTexture) { unsafe { - gl::BindTexture(gl::TEXTURE_2D, texture.image.handle); - gl::GenerateMipmap(gl::TEXTURE_2D); - gl::BindTexture(gl::TEXTURE_2D, 0); + ctx.bind_texture(glow::TEXTURE_2D, texture.image.handle); + ctx.generate_mipmap(glow::TEXTURE_2D); + ctx.bind_texture(glow::TEXTURE_2D, None); } } } diff --git a/librashader-runtime-gl/src/gl/gl3/ubo_ring.rs b/librashader-runtime-gl/src/gl/gl3/ubo_ring.rs index a89ef00..e4731b5 100644 --- a/librashader-runtime-gl/src/gl/gl3/ubo_ring.rs +++ b/librashader-runtime-gl/src/gl/gl3/ubo_ring.rs @@ -1,58 +1,88 @@ use crate::binding::UniformLocation; +use crate::error; +use crate::error::FilterChainError; use crate::gl::UboRing; -use gl::types::{GLsizei, GLsizeiptr, GLuint}; +use glow::HasContext; use librashader_reflect::reflect::semantics::BufferReflection; use librashader_runtime::ringbuffer::InlineRingBuffer; use librashader_runtime::ringbuffer::RingBuffer; use librashader_runtime::uniforms::UniformStorageAccess; +use std::mem::MaybeUninit; pub struct Gl3UboRing { - ring: InlineRingBuffer, + ring: InlineRingBuffer, +} + +impl Gl3UboRing { + const _ASSERT_TRANSMUTABLE: () = assert!( + std::mem::size_of::<[glow::Buffer; SIZE]>() + == std::mem::size_of::<[MaybeUninit; SIZE]>() + ); } impl UboRing for Gl3UboRing { - fn new(buffer_size: u32) -> Self { - let mut ring: InlineRingBuffer = InlineRingBuffer::new(); - unsafe { - gl::GenBuffers(SIZE as GLsizei, ring.items_mut().as_mut_ptr()); - for buffer in ring.items() { - gl::BindBuffer(gl::UNIFORM_BUFFER, *buffer); - gl::BufferData( - gl::UNIFORM_BUFFER, - buffer_size as GLsizeiptr, - std::ptr::null(), - gl::STREAM_DRAW, - ); + fn new(ctx: &glow::Context, buffer_size: u32) -> error::Result { + // TODO: array::try_from_fn whenever that gets stabilized + // this is basically blocking on try_trait_v2 + let mut items: [MaybeUninit; SIZE] = [MaybeUninit::zeroed(); SIZE]; + for items in items.iter_mut() { + unsafe { + let buffer = ctx + .create_buffer() + .map(|buffer| { + ctx.bind_buffer(glow::UNIFORM_BUFFER, Some(buffer)); + ctx.buffer_data_size( + glow::UNIFORM_BUFFER, + buffer_size as i32, + glow::STREAM_DRAW, + ); + ctx.bind_buffer(glow::UNIFORM_BUFFER, None); + buffer + }) + .map_err(FilterChainError::GlError)?; + + *items = MaybeUninit::new(buffer) } - gl::BindBuffer(gl::UNIFORM_BUFFER, 0); } - Gl3UboRing { ring } + + // SAFETY: everything was initialized above. + // MaybeUninit and glow::Buffer have the same size. + let items: [glow::Buffer; SIZE] = unsafe { std::mem::transmute_copy(&items) }; + + let ring: InlineRingBuffer = InlineRingBuffer::from_array(items); + + Ok(Gl3UboRing { ring }) } fn bind_for_frame( &mut self, + ctx: &glow::Context, ubo: &BufferReflection, - ubo_location: &UniformLocation, + ubo_location: &UniformLocation>, storage: &impl UniformStorageAccess, ) { - let size = ubo.size; - let buffer = self.ring.current(); + let buffer = *self.ring.current(); unsafe { - gl::BindBuffer(gl::UNIFORM_BUFFER, *buffer); - gl::BufferSubData( - gl::UNIFORM_BUFFER, + ctx.bind_buffer(glow::UNIFORM_BUFFER, Some(buffer)); + ctx.buffer_sub_data_u8_slice( + glow::UNIFORM_BUFFER, 0, - size as GLsizeiptr, - storage.ubo_pointer().cast(), + &storage.ubo_slice()[0..ubo.size as usize], ); - gl::BindBuffer(gl::UNIFORM_BUFFER, 0); + ctx.bind_buffer(glow::UNIFORM_BUFFER, None); - if ubo_location.vertex != gl::INVALID_INDEX { - gl::BindBufferBase(gl::UNIFORM_BUFFER, ubo_location.vertex, *buffer); + if let Some(vertex) = ubo_location + .vertex + .filter(|vertex| *vertex != glow::INVALID_INDEX) + { + ctx.bind_buffer_base(glow::UNIFORM_BUFFER, vertex, Some(buffer)); } - if ubo_location.fragment != gl::INVALID_INDEX { - gl::BindBufferBase(gl::UNIFORM_BUFFER, ubo_location.fragment, *buffer); + if let Some(fragment) = ubo_location + .fragment + .filter(|fragment| *fragment != glow::INVALID_INDEX) + { + ctx.bind_buffer_base(glow::UNIFORM_BUFFER, fragment, Some(buffer)); } } self.ring.next() diff --git a/librashader-runtime-gl/src/gl/gl46/compile_program.rs b/librashader-runtime-gl/src/gl/gl46/compile_program.rs index b058331..172925a 100644 --- a/librashader-runtime-gl/src/gl/gl46/compile_program.rs +++ b/librashader-runtime-gl/src/gl/gl46/compile_program.rs @@ -2,7 +2,7 @@ use crate::binding::UniformLocation; use crate::error::FilterChainError; use crate::gl::CompileProgram; use crate::util; -use gl::types::{GLint, GLsizei, GLuint}; +use glow::HasContext; use librashader_cache::Cacheable; use librashader_reflect::back::glsl::CrossGlslContext; use librashader_reflect::back::ShaderCompilerOutput; @@ -11,10 +11,7 @@ use spirv_cross2::spirv::Decoration; pub struct Gl4CompileProgram; -struct GlProgramBinary { - program: Vec, - format: GLuint, -} +struct GlProgramBinary(Option); impl Cacheable for GlProgramBinary { fn from_bytes(cached: &[u8]) -> Option @@ -23,45 +20,52 @@ impl Cacheable for GlProgramBinary { { let mut cached = Vec::from(cached); let format = cached.split_off(cached.len() - std::mem::size_of::()); - let format: Option<&GLuint> = bytemuck::try_from_bytes(&format).ok(); + let format: Option<&u32> = bytemuck::try_from_bytes(&format).ok(); let Some(format) = format else { return None; }; - return Some(GlProgramBinary { - program: cached, + return Some(GlProgramBinary(Some(glow::ProgramBinary { + buffer: cached, format: *format, - }); + }))); } fn to_bytes(&self) -> Option> { - let mut slice = self.program.clone(); - slice.extend(bytemuck::bytes_of(&self.format)); + let Some(binary) = &self.0 else { return None }; + + let mut slice = binary.buffer.clone(); + slice.extend(bytemuck::bytes_of(&binary.format)); Some(slice) } } impl CompileProgram for Gl4CompileProgram { fn compile_program( + context: &glow::Context, glsl: ShaderCompilerOutput, cache: bool, - ) -> crate::error::Result<(GLuint, UniformLocation)> { - let vertex_resources = glsl.context.artifact.vertex.shader_resources()?; + ) -> crate::error::Result<(glow::Program, UniformLocation>)> { + fn compile_shader( + context: &glow::Context, + resources: &CrossGlslContext, + vertex: &str, + fragment: &str, + ) -> crate::error::Result { + unsafe { + let vertex_resources = resources.artifact.vertex.shader_resources()?; + let vertex = util::gl_compile_shader(context, glow::VERTEX_SHADER, vertex)?; + let fragment = util::gl_compile_shader(context, glow::FRAGMENT_SHADER, fragment)?; - let program = librashader_cache::cache_shader_object( - "opengl4", - &[glsl.vertex.as_str(), glsl.fragment.as_str()], - |&[vertex, fragment]| unsafe { - let vertex = util::gl_compile_shader(gl::VERTEX_SHADER, vertex)?; - let fragment = util::gl_compile_shader(gl::FRAGMENT_SHADER, fragment)?; + let program = context + .create_program() + .map_err(|_| FilterChainError::GlProgramError)?; - let program = gl::CreateProgram(); - gl::AttachShader(program, vertex); - gl::AttachShader(program, fragment); + context.attach_shader(program, vertex); + context.attach_shader(program, fragment); for res in vertex_resources.resources_for_type(ResourceType::StageInput)? { - let Some(loc) = glsl - .context + let Some(loc) = resources .artifact .vertex .decoration(res.id, Decoration::Location)? @@ -70,60 +74,48 @@ impl CompileProgram for Gl4CompileProgram { continue; }; - let mut name = res.name.to_string(); - name.push('\0'); - - gl::BindAttribLocation(program, loc, name.as_str().as_ptr().cast()) + context.bind_attrib_location(program, loc, &res.name); } - gl::LinkProgram(program); - gl::DeleteShader(vertex); - gl::DeleteShader(fragment); + context.program_binary_retrievable_hint(program, true); + context.link_program(program); + context.delete_shader(vertex); + context.delete_shader(fragment); - let mut status = 0; - gl::GetProgramiv(program, gl::LINK_STATUS, &mut status); - if status != 1 { + if !context.get_program_link_status(program) { return Err(FilterChainError::GLLinkError); } + Ok(program) + } + } - let mut length = 0; - gl::GetProgramiv(program, gl::PROGRAM_BINARY_LENGTH, &mut length); - - let mut binary = vec![0; length as usize]; - let mut format = 0; - gl::GetProgramBinary( - program, - length, - std::ptr::null_mut(), - &mut format, - binary.as_mut_ptr().cast(), - ); - gl::DeleteProgram(program); - Ok(GlProgramBinary { - program: binary, - format, - }) + let program = librashader_cache::cache_shader_object( + "opengl4", + &[glsl.vertex.as_str(), glsl.fragment.as_str()], + |&[vertex, fragment]| unsafe { + let program = compile_shader(context, &glsl.context, vertex, fragment)?; + let program_binary = context.get_program_binary(program); + context.delete_program(program); + Ok(GlProgramBinary(program_binary)) }, - |GlProgramBinary { - program: blob, - format, - }| { - let program = unsafe { - let program = gl::CreateProgram(); - gl::ProgramBinary(program, format, blob.as_ptr().cast(), blob.len() as GLsizei); - program - }; + |binary| unsafe { + let program = context + .create_program() + .map_err(|_| FilterChainError::GlProgramError)?; - unsafe { - let mut status = 0; - gl::GetProgramiv(program, gl::LINK_STATUS, &mut status); - if status != 1 { - return Err(FilterChainError::GLLinkError); - } - - if gl::GetError() == gl::INVALID_ENUM { - return Err(FilterChainError::GLLinkError); - } + if let Some(binary) = &binary.0 { + context.program_binary(program, binary); } + + if !context.get_program_link_status(program) { + context.delete_program(program); + return compile_shader( + context, + &glsl.context, + glsl.vertex.as_str(), + glsl.fragment.as_str(), + ); + } + return Ok(program); }, !cache, @@ -131,18 +123,15 @@ impl CompileProgram for Gl4CompileProgram { let ubo_location = unsafe { for (name, binding) in &glsl.context.sampler_bindings { - let location = gl::GetUniformLocation(program, name.as_str().as_ptr().cast()); - if location >= 0 { - gl::ProgramUniform1i(program, location, *binding as GLint); + let location = context.get_uniform_location(program, name.as_str()); + if let Some(location) = location { + context.program_uniform_1_i32(program, Some(&location), *binding as i32); } } 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(), - ), + vertex: context.get_uniform_block_index(program, "LIBRA_UBO_VERTEX"), + fragment: context.get_uniform_block_index(program, "LIBRA_UBO_FRAGMENT"), } }; diff --git a/librashader-runtime-gl/src/gl/gl46/draw_quad.rs b/librashader-runtime-gl/src/gl/gl46/draw_quad.rs index 757d1e3..1f768b8 100644 --- a/librashader-runtime-gl/src/gl/gl46/draw_quad.rs +++ b/librashader-runtime-gl/src/gl/gl46/draw_quad.rs @@ -1,104 +1,95 @@ +use crate::error; +use crate::error::FilterChainError; use crate::gl::DrawQuad; use crate::gl::{FINAL_VBO_DATA, OFFSCREEN_VBO_DATA}; use bytemuck::offset_of; -use gl::types::{GLint, GLsizeiptr, GLuint}; +use glow::HasContext; use librashader_runtime::quad::{QuadType, VertexInput}; pub struct Gl46DrawQuad { - vbo: [GLuint; 2], - vao: GLuint, + vbo: [glow::Buffer; 2], + vao: glow::VertexArray, } impl DrawQuad for Gl46DrawQuad { - fn new() -> Self { - let mut vbo = [0, 0]; - let mut vao = 0; + fn new(context: &glow::Context) -> error::Result { + let vbo; + let vao; unsafe { - gl::CreateBuffers(2, vbo.as_mut_ptr()); - gl::NamedBufferData( + vbo = [ + context + .create_named_buffer() + .map_err(FilterChainError::GlError)?, + context + .create_named_buffer() + .map_err(FilterChainError::GlError)?, + ]; + + context.named_buffer_data_u8_slice( vbo[0], - std::mem::size_of_val(OFFSCREEN_VBO_DATA) as GLsizeiptr, - OFFSCREEN_VBO_DATA.as_ptr().cast(), - gl::STATIC_DRAW, + bytemuck::cast_slice(OFFSCREEN_VBO_DATA), + glow::STATIC_DRAW, ); - gl::NamedBufferData( + context.named_buffer_data_u8_slice( vbo[1], - std::mem::size_of_val(FINAL_VBO_DATA) as GLsizeiptr, - FINAL_VBO_DATA.as_ptr().cast(), - gl::STATIC_DRAW, + bytemuck::cast_slice(FINAL_VBO_DATA), + glow::STATIC_DRAW, ); - gl::CreateVertexArrays(1, &mut vao); + vao = context + .create_named_vertex_array() + .map_err(FilterChainError::GlError)?; + context.enable_vertex_array_attrib(vao, 0); + context.enable_vertex_array_attrib(vao, 1); - gl::EnableVertexArrayAttrib(vao, 0); - gl::EnableVertexArrayAttrib(vao, 1); - - gl::VertexArrayAttribFormat( + context.vertex_array_attrib_format_f32( vao, 0, 4, - gl::FLOAT, - gl::FALSE, - offset_of!(VertexInput, position) as GLuint, + glow::FLOAT, + false, + offset_of!(VertexInput, position) as u32, ); - gl::VertexArrayAttribFormat( + context.vertex_array_attrib_format_f32( vao, 1, 2, - gl::FLOAT, - gl::FALSE, - offset_of!(VertexInput, texcoord) as GLuint, + glow::FLOAT, + false, + offset_of!(VertexInput, texcoord) as u32, ); - gl::VertexArrayAttribBinding(vao, 0, 0); - gl::VertexArrayAttribBinding(vao, 1, 0); + context.vertex_array_attrib_binding_f32(vao, 0, 0); + context.vertex_array_attrib_binding_f32(vao, 1, 0); } - Self { vbo, vao } + Ok(Self { vbo, vao }) } - fn bind_vertices(&self, quad_type: QuadType) { + fn bind_vertices(&self, context: &glow::Context, quad_type: QuadType) { let buffer_index = match quad_type { QuadType::Offscreen => 0, QuadType::Final => 1, }; unsafe { - gl::VertexArrayVertexBuffer( + context.vertex_array_vertex_buffer( self.vao, 0, - self.vbo[buffer_index], + Some(self.vbo[buffer_index]), 0, - std::mem::size_of::() as GLint, + std::mem::size_of::() as i32, ); - gl::BindVertexArray(self.vao); + context.bind_vertex_array(Some(self.vao)) } } - fn unbind_vertices(&self) { + fn unbind_vertices(&self, context: &glow::Context) { unsafe { - gl::BindVertexArray(0); - } - } -} - -impl Drop for Gl46DrawQuad { - fn drop(&mut self) { - unsafe { - if self.vbo[0] != 0 { - gl::DeleteBuffers(1, &self.vbo[0]); - } - - if self.vbo[1] != 0 { - gl::DeleteBuffers(1, &self.vbo[1]); - } - - if self.vao != 0 { - gl::DeleteVertexArrays(1, &self.vao) - } + context.bind_vertex_array(None); } } } diff --git a/librashader-runtime-gl/src/gl/gl46/framebuffer.rs b/librashader-runtime-gl/src/gl/gl46/framebuffer.rs index 07c919e..5b1a5b0 100644 --- a/librashader-runtime-gl/src/gl/gl46/framebuffer.rs +++ b/librashader-runtime-gl/src/gl/gl46/framebuffer.rs @@ -1,24 +1,26 @@ +use crate::error; use crate::error::{FilterChainError, Result}; use crate::framebuffer::GLImage; use crate::gl::framebuffer::GLFramebuffer; use crate::gl::FramebufferInterface; -use gl::types::{GLenum, GLint, GLsizei}; +use glow::HasContext; use librashader_common::{ImageFormat, Size}; -use librashader_presets::Scale2D; -use librashader_runtime::scaling::{MipmapSize, ViewportSize}; +use librashader_runtime::scaling::MipmapSize; +use std::sync::Arc; #[derive(Debug)] pub struct Gl46Framebuffer; impl FramebufferInterface for Gl46Framebuffer { - fn new(max_levels: u32) -> GLFramebuffer { - let mut framebuffer = 0; - unsafe { - gl::CreateFramebuffers(1, &mut framebuffer); - } + fn new(context: &Arc, max_levels: u32) -> error::Result { + let framebuffer = unsafe { + context + .create_named_framebuffer() + .map_err(FilterChainError::GlError)? + }; - GLFramebuffer { - image: 0, + Ok(GLFramebuffer { + image: None, size: Size { width: 1, height: 1, @@ -28,92 +30,66 @@ impl FramebufferInterface for Gl46Framebuffer { mip_levels: 0, fbo: framebuffer, is_raw: false, - } + ctx: Arc::clone(&context), + }) } - fn scale( - fb: &mut GLFramebuffer, - scaling: Scale2D, - format: ImageFormat, - viewport_size: &Size, - source_size: &Size, - original_size: &Size, - mipmap: bool, - ) -> Result> { - if fb.is_raw { - return Ok(fb.size); - } - - let size = source_size.scale_viewport(scaling, *viewport_size, *original_size); - - if fb.size != size || (mipmap && fb.max_levels == 1) || (!mipmap && fb.max_levels != 1) { - fb.size = size; - - if mipmap { - fb.max_levels = u32::MAX; - } else { - fb.max_levels = 1 - } - - Self::init( - fb, - size, - if format == ImageFormat::Unknown { - ImageFormat::R8G8B8A8Unorm - } else { - format - }, - )?; - } - Ok(size) - } fn clear(fb: &GLFramebuffer) { unsafe { - gl::ClearNamedFramebufferfv( - fb.fbo, - gl::COLOR, + fb.ctx.clear_named_framebuffer_f32_slice( + Some(fb.fbo), + glow::COLOR, 0, - [0.0f32, 0.0, 0.0, 0.0].as_ptr().cast(), + &[0.0f32, 0.0, 0.0, 0.0], ); } } fn copy_from(fb: &mut GLFramebuffer, image: &GLImage) -> Result<()> { // todo: confirm this behaviour for unbound image. + if image.handle == None { + return Ok(()); + } + + // todo: may want to use a shader and draw a quad to be faster. if image.size != fb.size || image.format != fb.format { Self::init(fb, image.size, image.format)?; } - if image.handle == 0 { - return Ok(()); - } - unsafe { - // gl::NamedFramebufferDrawBuffer(fb.handle, gl::COLOR_ATTACHMENT1); - gl::NamedFramebufferReadBuffer(fb.fbo, gl::COLOR_ATTACHMENT0); - gl::NamedFramebufferDrawBuffer(fb.fbo, gl::COLOR_ATTACHMENT1); + // glow::NamedFramebufferDrawBuffer(fb.handle, glow::COLOR_ATTACHMENT1); + fb.ctx + .named_framebuffer_read_buffer(Some(fb.fbo), glow::COLOR_ATTACHMENT0); + fb.ctx + .named_framebuffer_draw_buffer(Some(fb.fbo), glow::COLOR_ATTACHMENT1); - gl::NamedFramebufferTexture(fb.fbo, gl::COLOR_ATTACHMENT0, image.handle, 0); - gl::NamedFramebufferTexture(fb.fbo, gl::COLOR_ATTACHMENT1, fb.image, 0); + fb.ctx.named_framebuffer_texture( + Some(fb.fbo), + glow::COLOR_ATTACHMENT0, + image.handle, + 0, + ); + fb.ctx + .named_framebuffer_texture(Some(fb.fbo), glow::COLOR_ATTACHMENT1, fb.image, 0); - gl::BlitNamedFramebuffer( - fb.fbo, - fb.fbo, + fb.ctx.blit_named_framebuffer( + Some(fb.fbo), + Some(fb.fbo), 0, 0, - image.size.width as GLint, - image.size.height as GLint, + image.size.width as i32, + image.size.height as i32, 0, 0, - fb.size.width as GLint, - fb.size.height as GLint, - gl::COLOR_BUFFER_BIT, - gl::NEAREST, + fb.size.width as i32, + fb.size.height as i32, + glow::COLOR_BUFFER_BIT, + glow::NEAREST, ); } Ok(()) } - fn init(fb: &mut GLFramebuffer, mut size: Size, format: impl Into) -> Result<()> { + fn init(fb: &mut GLFramebuffer, mut size: Size, format: impl Into) -> Result<()> { if fb.is_raw { return Ok(()); } @@ -122,12 +98,16 @@ impl FramebufferInterface for Gl46Framebuffer { unsafe { // reset the framebuffer image - if fb.image != 0 { - gl::NamedFramebufferTexture(fb.fbo, gl::COLOR_ATTACHMENT0, 0, 0); - gl::DeleteTextures(1, &fb.image); + if let Some(image) = fb.image { + fb.ctx + .named_framebuffer_texture(Some(fb.fbo), glow::COLOR_ATTACHMENT0, None, 0); + fb.ctx.delete_texture(image); } - gl::CreateTextures(gl::TEXTURE_2D, 1, &mut fb.image); + let image = fb + .ctx + .create_named_texture(glow::TEXTURE_2D) + .map_err(FilterChainError::GlError)?; if size.width == 0 { size.width = 1; @@ -144,23 +124,37 @@ impl FramebufferInterface for Gl46Framebuffer { fb.mip_levels = 1; } - gl::TextureStorage2D( - fb.image, - fb.mip_levels as GLsizei, + fb.ctx.texture_storage_2d( + image, + fb.mip_levels as i32, fb.format, - size.width as GLsizei, - size.height as GLsizei, + size.width as i32, + size.height as i32, ); - gl::NamedFramebufferTexture(fb.fbo, gl::COLOR_ATTACHMENT0, fb.image, 0); + fb.image = Some(image); - let status = gl::CheckFramebufferStatus(gl::FRAMEBUFFER); - if status != gl::FRAMEBUFFER_COMPLETE { + fb.ctx + .named_framebuffer_texture(Some(fb.fbo), glow::COLOR_ATTACHMENT0, fb.image, 0); + + let status = fb + .ctx + .check_named_framebuffer_status(Some(fb.fbo), glow::FRAMEBUFFER); + if status != glow::FRAMEBUFFER_COMPLETE { match status { - gl::FRAMEBUFFER_UNSUPPORTED => { - gl::NamedFramebufferTexture(fb.fbo, gl::COLOR_ATTACHMENT0, 0, 0); - gl::DeleteTextures(1, &fb.image); - gl::CreateTextures(gl::TEXTURE_2D, 1, &mut fb.image); + glow::FRAMEBUFFER_UNSUPPORTED => { + fb.ctx.named_framebuffer_texture( + Some(fb.fbo), + glow::COLOR_ATTACHMENT0, + None, + 0, + ); + fb.ctx.delete_texture(image); + + let image = fb + .ctx + .create_named_texture(glow::TEXTURE_2D) + .map_err(FilterChainError::GlError)?; fb.mip_levels = size.calculate_miplevels(); if fb.mip_levels > fb.max_levels { @@ -170,16 +164,22 @@ impl FramebufferInterface for Gl46Framebuffer { fb.mip_levels = 1; } - gl::TextureStorage2D( - fb.image, - fb.mip_levels as GLsizei, + fb.ctx.texture_storage_2d( + image, + fb.mip_levels as i32, ImageFormat::R8G8B8A8Unorm.into(), - size.width as GLsizei, - size.height as GLsizei, + size.width as i32, + size.height as i32, + ); + + fb.image = Some(image); + + fb.ctx.named_framebuffer_texture( + Some(fb.fbo), + glow::COLOR_ATTACHMENT0, + fb.image, + 0, ); - gl::NamedFramebufferTexture(fb.fbo, gl::COLOR_ATTACHMENT0, fb.image, 0); - // fb.init = - // gl::CheckFramebufferStatus(gl::FRAMEBUFFER) == gl::FRAMEBUFFER_COMPLETE; } _ => return Err(FilterChainError::FramebufferInit(status)), } diff --git a/librashader-runtime-gl/src/gl/gl46/lut_load.rs b/librashader-runtime-gl/src/gl/gl46/lut_load.rs index 04e33cc..5636298 100644 --- a/librashader-runtime-gl/src/gl/gl46/lut_load.rs +++ b/librashader-runtime-gl/src/gl/gl46/lut_load.rs @@ -1,8 +1,8 @@ -use crate::error::Result; +use crate::error::{FilterChainError, Result}; use crate::framebuffer::GLImage; use crate::gl::LoadLut; use crate::texture::InputTexture; -use gl::types::{GLsizei, GLuint}; +use glow::{HasContext, PixelUnpackData}; use librashader_common::map::FastHashMap; use librashader_presets::TextureConfig; use librashader_runtime::image::{Image, ImageError, UVDirection}; @@ -11,17 +11,13 @@ use rayon::prelude::*; pub struct Gl46LutLoad; impl LoadLut for Gl46LutLoad { - fn load_luts(textures: &[TextureConfig]) -> Result> { + fn load_luts( + context: &glow::Context, + textures: &[TextureConfig], + ) -> Result> { let mut luts = FastHashMap::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); - } + // don't need this for texture DSA api. let images = textures .par_iter() @@ -35,45 +31,48 @@ impl LoadLut for Gl46LutLoad { 1u32 }; - let mut handle = 0; - unsafe { - gl::CreateTextures(gl::TEXTURE_2D, 1, &mut handle); + let handle = unsafe { + let handle = context + .create_named_texture(glow::TEXTURE_2D) + .map_err(FilterChainError::GlError)?; - gl::TextureStorage2D( + context.texture_storage_2d( handle, - levels as GLsizei, - gl::RGBA8, - image.size.width as GLsizei, - image.size.height as GLsizei, + levels as i32, + glow::RGBA8, + image.size.width as i32, + image.size.height as i32, ); - gl::PixelStorei(gl::UNPACK_ROW_LENGTH, 0); - gl::PixelStorei(gl::UNPACK_ALIGNMENT, 4); + context.pixel_store_i32(glow::UNPACK_ROW_LENGTH, 0); + context.pixel_store_i32(glow::UNPACK_ALIGNMENT, 4); - gl::TextureSubImage2D( + context.texture_sub_image_2d( handle, 0, 0, 0, - image.size.width as GLsizei, - image.size.height as GLsizei, - gl::RGBA, - gl::UNSIGNED_BYTE, - image.bytes.as_ptr().cast(), + image.size.width as i32, + image.size.height as i32, + glow::RGBA, + glow::UNSIGNED_BYTE, + PixelUnpackData::Slice(&image.bytes), ); let mipmap = levels > 1; if mipmap { - gl::GenerateTextureMipmap(handle); + context.generate_texture_mipmap(handle); } - } + + handle + }; luts.insert( index, InputTexture { image: GLImage { - handle, - format: gl::RGBA8, + handle: Some(handle), + format: glow::RGBA8, size: image.size, }, filter: texture.filter_mode, @@ -83,9 +82,9 @@ impl LoadLut for Gl46LutLoad { ); } - unsafe { - gl::BindBuffer(gl::PIXEL_UNPACK_BUFFER, pixel_unpack as GLuint); - }; + // unsafe { + // context.bind_buffer(glow::PIXEL_UNPACK_BUFFER, pixel_unpack); + // }; Ok(luts) } } diff --git a/librashader-runtime-gl/src/gl/gl46/texture_bind.rs b/librashader-runtime-gl/src/gl/gl46/texture_bind.rs index 276accb..5f2cb4b 100644 --- a/librashader-runtime-gl/src/gl/gl46/texture_bind.rs +++ b/librashader-runtime-gl/src/gl/gl46/texture_bind.rs @@ -1,23 +1,31 @@ use crate::gl::BindTexture; use crate::samplers::SamplerSet; use crate::texture::InputTexture; +use glow::HasContext; use librashader_reflect::reflect::semantics::TextureBinding; pub struct Gl46BindTexture; impl BindTexture for Gl46BindTexture { - fn bind_texture(samplers: &SamplerSet, binding: &TextureBinding, texture: &InputTexture) { + fn bind_texture( + context: &glow::Context, + samplers: &SamplerSet, + binding: &TextureBinding, + texture: &InputTexture, + ) { unsafe { // eprintln!("setting {} to texunit {}", texture.image.handle, binding.binding); - gl::BindTextureUnit(binding.binding, texture.image.handle); - gl::BindSampler( + context.bind_texture_unit(binding.binding, texture.image.handle); + context.bind_sampler( binding.binding, - samplers.get(texture.wrap_mode, texture.filter, texture.mip_filter), - ); + Some(samplers.get(texture.wrap_mode, texture.filter, texture.mip_filter)), + ) } } - fn gen_mipmaps(texture: &InputTexture) { - unsafe { gl::GenerateTextureMipmap(texture.image.handle) } + fn gen_mipmaps(context: &glow::Context, texture: &InputTexture) { + if let Some(texture) = texture.image.handle { + unsafe { context.generate_texture_mipmap(texture) } + } } } diff --git a/librashader-runtime-gl/src/gl/gl46/ubo_ring.rs b/librashader-runtime-gl/src/gl/gl46/ubo_ring.rs index 4ae402d..9e02bfc 100644 --- a/librashader-runtime-gl/src/gl/gl46/ubo_ring.rs +++ b/librashader-runtime-gl/src/gl/gl46/ubo_ring.rs @@ -1,50 +1,82 @@ use crate::binding::UniformLocation; +use crate::error; +use crate::error::FilterChainError; use crate::gl::UboRing; -use gl::types::{GLsizei, GLsizeiptr, GLuint}; +use glow::HasContext; use librashader_reflect::reflect::semantics::BufferReflection; use librashader_runtime::ringbuffer::InlineRingBuffer; use librashader_runtime::ringbuffer::RingBuffer; use librashader_runtime::uniforms::UniformStorageAccess; +use std::mem::MaybeUninit; pub struct Gl46UboRing { - ring: InlineRingBuffer, + ring: InlineRingBuffer, +} + +impl Gl46UboRing { + const _ASSERT_TRANSMUTABLE: () = assert!( + std::mem::size_of::<[glow::Buffer; SIZE]>() + == std::mem::size_of::<[MaybeUninit; SIZE]>() + ); } impl UboRing for Gl46UboRing { - fn new(buffer_size: u32) -> Self { - let mut ring: InlineRingBuffer = InlineRingBuffer::new(); - unsafe { - gl::CreateBuffers(SIZE as GLsizei, ring.items_mut().as_mut_ptr()); - for buffer in ring.items() { - gl::NamedBufferData( - *buffer, - buffer_size as GLsizeiptr, - std::ptr::null(), - gl::STREAM_DRAW, - ); - } - }; + fn new(context: &glow::Context, buffer_size: u32) -> error::Result { + // TODO: array::try_from_fn whenever that gets stabilized + // this is basically blocking on try_trait_v2 + let mut items: [MaybeUninit; SIZE] = [MaybeUninit::zeroed(); SIZE]; + for items in items.iter_mut() { + unsafe { + let buffer = context + .create_named_buffer() + .map(|buffer| { + context.named_buffer_data_size( + buffer, + buffer_size as i32, + glow::STREAM_DRAW, + ); + buffer + }) + .map_err(FilterChainError::GlError)?; - Gl46UboRing { ring } + *items = MaybeUninit::new(buffer) + } + } + + // SAFETY: everything was initialized above. + let items: [glow::Buffer; SIZE] = unsafe { std::mem::transmute_copy(&items) }; + let ring: InlineRingBuffer = InlineRingBuffer::from_array(items); + + Ok(Gl46UboRing { ring }) } fn bind_for_frame( &mut self, + context: &glow::Context, ubo: &BufferReflection, - ubo_location: &UniformLocation, + ubo_location: &UniformLocation>, storage: &impl UniformStorageAccess, ) { - let size = ubo.size; - let buffer = self.ring.current(); + let buffer = *self.ring.current(); unsafe { - gl::NamedBufferSubData(*buffer, 0, size as GLsizeiptr, storage.ubo_pointer().cast()); + context.named_buffer_sub_data_u8_slice( + buffer, + 0, + &storage.ubo_slice()[0..ubo.size as usize], + ); - if ubo_location.vertex != gl::INVALID_INDEX { - gl::BindBufferBase(gl::UNIFORM_BUFFER, ubo_location.vertex, *buffer); + if let Some(vertex) = ubo_location + .vertex + .filter(|vertex| *vertex != glow::INVALID_INDEX) + { + context.bind_buffer_base(glow::UNIFORM_BUFFER, vertex, Some(buffer)); } - if ubo_location.fragment != gl::INVALID_INDEX { - gl::BindBufferBase(gl::UNIFORM_BUFFER, ubo_location.fragment, *buffer); + if let Some(fragment) = ubo_location + .fragment + .filter(|fragment| *fragment != glow::INVALID_INDEX) + { + context.bind_buffer_base(glow::UNIFORM_BUFFER, fragment, Some(buffer)); } } self.ring.next() diff --git a/librashader-runtime-gl/src/gl/mod.rs b/librashader-runtime-gl/src/gl/mod.rs index d7d7531..2286867 100644 --- a/librashader-runtime-gl/src/gl/mod.rs +++ b/librashader-runtime-gl/src/gl/mod.rs @@ -8,7 +8,6 @@ use crate::framebuffer::GLImage; use crate::samplers::SamplerSet; use crate::texture::InputTexture; pub use framebuffer::GLFramebuffer; -use gl::types::{GLenum, GLuint}; use librashader_common::map::FastHashMap; use librashader_common::{ImageFormat, Size}; use librashader_presets::{Scale2D, TextureConfig}; @@ -16,7 +15,9 @@ use librashader_reflect::back::glsl::CrossGlslContext; use librashader_reflect::back::ShaderCompilerOutput; use librashader_reflect::reflect::semantics::{BufferReflection, TextureBinding}; use librashader_runtime::quad::{QuadType, VertexInput}; +use librashader_runtime::scaling::ViewportSize; use librashader_runtime::uniforms::UniformStorageAccess; +use std::sync::Arc; static OFFSCREEN_VBO_DATA: &[VertexInput; 4] = &[ VertexInput { @@ -57,34 +58,43 @@ static FINAL_VBO_DATA: &[VertexInput; 4] = &[ ]; pub(crate) trait LoadLut { - fn load_luts(textures: &[TextureConfig]) -> Result>; + fn load_luts( + context: &glow::Context, + textures: &[TextureConfig], + ) -> Result>; } pub(crate) trait CompileProgram { fn compile_program( + context: &glow::Context, shader: ShaderCompilerOutput, cache: bool, - ) -> Result<(GLuint, UniformLocation)>; + ) -> Result<(glow::Program, UniformLocation>)>; } pub(crate) trait DrawQuad { - fn new() -> Self; - fn bind_vertices(&self, quad_type: QuadType); - fn unbind_vertices(&self); + fn new(context: &glow::Context) -> Result + where + Self: Sized; + fn bind_vertices(&self, context: &glow::Context, quad_type: QuadType); + fn unbind_vertices(&self, context: &glow::Context); } pub(crate) trait UboRing { - fn new(buffer_size: u32) -> Self; + fn new(context: &glow::Context, buffer_size: u32) -> Result + where + Self: Sized; fn bind_for_frame( &mut self, + context: &glow::Context, ubo: &BufferReflection, - ubo_location: &UniformLocation, + ubo_location: &UniformLocation>, storage: &impl UniformStorageAccess, ); } pub(crate) trait FramebufferInterface { - fn new(max_levels: u32) -> GLFramebuffer; + fn new(context: &Arc, max_levels: u32) -> Result; fn scale( fb: &mut GLFramebuffer, scaling: Scale2D, @@ -93,15 +103,48 @@ pub(crate) trait FramebufferInterface { source_size: &Size, original_size: &Size, mipmap: bool, - ) -> Result>; + ) -> Result> { + if fb.is_raw { + return Ok(fb.size); + } + + let size = source_size.scale_viewport(scaling, *viewport_size, *original_size); + + if fb.size != size || (mipmap && fb.max_levels == 1) || (!mipmap && fb.max_levels != 1) { + fb.size = size; + + if mipmap { + fb.max_levels = u32::MAX; + } else { + fb.max_levels = 1 + } + + Self::init( + fb, + size, + if format == ImageFormat::Unknown { + ImageFormat::R8G8B8A8Unorm + } else { + format + }, + )?; + } + Ok(size) + } + fn clear(fb: &GLFramebuffer); fn copy_from(fb: &mut GLFramebuffer, image: &GLImage) -> Result<()>; - fn init(fb: &mut GLFramebuffer, size: Size, format: impl Into) -> Result<()>; + fn init(fb: &mut GLFramebuffer, size: Size, format: impl Into) -> Result<()>; } pub(crate) trait BindTexture { - fn bind_texture(samplers: &SamplerSet, binding: &TextureBinding, texture: &InputTexture); - fn gen_mipmaps(texture: &InputTexture); + fn bind_texture( + context: &glow::Context, + samplers: &SamplerSet, + binding: &TextureBinding, + texture: &InputTexture, + ); + fn gen_mipmaps(context: &glow::Context, texture: &InputTexture); } pub(crate) trait GLInterface { diff --git a/librashader-runtime-gl/src/samplers.rs b/librashader-runtime-gl/src/samplers.rs index c3a1e4c..42348e9 100644 --- a/librashader-runtime-gl/src/samplers.rs +++ b/librashader-runtime-gl/src/samplers.rs @@ -1,15 +1,17 @@ -use gl::types::{GLenum, GLint, GLuint}; +use crate::error; +use crate::error::FilterChainError; +use glow::HasContext; use librashader_common::map::FastHashMap; use librashader_common::{FilterMode, WrapMode}; pub struct SamplerSet { // todo: may need to deal with differences in mip filter. - samplers: FastHashMap<(WrapMode, FilterMode, FilterMode), GLuint>, + samplers: FastHashMap<(WrapMode, FilterMode, FilterMode), glow::Sampler>, } impl SamplerSet { #[inline(always)] - pub fn get(&self, wrap: WrapMode, filter: FilterMode, mipmap: FilterMode) -> GLuint { + pub fn get(&self, wrap: WrapMode, filter: FilterMode, mipmap: FilterMode) -> glow::Sampler { // SAFETY: the sampler set is complete for the matrix // wrap x filter x mipmap unsafe { @@ -20,21 +22,26 @@ impl SamplerSet { } } - fn make_sampler(sampler: GLuint, wrap: WrapMode, filter: FilterMode, mip: FilterMode) { + fn make_sampler( + context: &glow::Context, + sampler: glow::Sampler, + 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( + context.sampler_parameter_i32(sampler, glow::TEXTURE_WRAP_S, wrap.into()); + context.sampler_parameter_i32(sampler, glow::TEXTURE_WRAP_T, wrap.into()); + context.sampler_parameter_i32(sampler, glow::TEXTURE_MAG_FILTER, filter.into()); + context.sampler_parameter_i32( sampler, - gl::TEXTURE_MAG_FILTER, - GLenum::from(filter) as GLint, + glow::TEXTURE_MIN_FILTER, + filter.gl_mip(mip) as i32, ); - - gl::SamplerParameteri(sampler, gl::TEXTURE_MIN_FILTER, filter.gl_mip(mip) as GLint); } } - pub fn new() -> SamplerSet { + pub fn new(context: &glow::Context) -> error::Result { let mut samplers = FastHashMap::default(); let wrap_modes = &[ WrapMode::ClampToBorder, @@ -45,10 +52,18 @@ impl SamplerSet { for wrap_mode in wrap_modes { for filter_mode in &[FilterMode::Linear, FilterMode::Nearest] { for mip_filter in &[FilterMode::Linear, FilterMode::Nearest] { - let mut sampler = 0; unsafe { - gl::GenSamplers(1, &mut sampler); - SamplerSet::make_sampler(sampler, *wrap_mode, *filter_mode, *mip_filter); + let sampler = context + .create_sampler() + .map_err(|_| FilterChainError::GlSamplerError)?; + + SamplerSet::make_sampler( + context, + sampler, + *wrap_mode, + *filter_mode, + *mip_filter, + ); samplers.insert((*wrap_mode, *filter_mode, *mip_filter), sampler); } @@ -58,6 +73,6 @@ impl SamplerSet { // assert all samplers were created. assert_eq!(samplers.len(), wrap_modes.len() * 2 * 2); - SamplerSet { samplers } + Ok(SamplerSet { samplers }) } } diff --git a/librashader-runtime-gl/src/texture.rs b/librashader-runtime-gl/src/texture.rs index cc9fe5f..b013c36 100644 --- a/librashader-runtime-gl/src/texture.rs +++ b/librashader-runtime-gl/src/texture.rs @@ -13,7 +13,7 @@ pub(crate) struct InputTexture { /// An OpenGL texture bound as a shader resource. impl InputTexture { pub fn is_bound(&self) -> bool { - self.image.handle != 0 + self.image.handle.is_some() } /// Returns a reference to itself if the texture is bound. diff --git a/librashader-runtime-gl/src/util.rs b/librashader-runtime-gl/src/util.rs index bfd3fe4..e6b6280 100644 --- a/librashader-runtime-gl/src/util.rs +++ b/librashader-runtime-gl/src/util.rs @@ -1,34 +1,36 @@ -use gl::types::{GLenum, GLint, GLuint}; +use glow::HasContext; use crate::error; use crate::error::FilterChainError; use librashader_reflect::back::glsl::GlslVersion; -pub unsafe fn gl_compile_shader(stage: GLenum, source: &str) -> error::Result { - let (shader, compile_status) = unsafe { - let lens = [source.len() as GLint]; - let shader = gl::CreateShader(stage); - gl::ShaderSource(shader, 1, &source.as_ptr().cast(), lens.as_ptr()); - gl::CompileShader(shader); - let mut compile_status = 0; - gl::GetShaderiv(shader, gl::COMPILE_STATUS, &mut compile_status); - (shader, compile_status) - }; +pub fn gl_compile_shader( + context: &glow::Context, + stage: u32, + source: &str, +) -> error::Result { + unsafe { + let shader = context + .create_shader(stage) + .map_err(|_| FilterChainError::GlCompileError)?; - if compile_status == 0 { - Err(FilterChainError::GlCompileError) - } else { - Ok(shader) + context.shader_source(shader, &source); + context.compile_shader(shader); + let compile_status = context.get_shader_compile_status(shader); + + if !compile_status { + Err(FilterChainError::GlCompileError) + } else { + Ok(shader) + } } } -pub fn gl_get_version() -> GlslVersion { - 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); - } +pub fn gl_get_version(context: &glow::Context) -> GlslVersion { + let version = context.version(); + + let maj_ver = version.major; + let min_ver = version.minor; match maj_ver { 3 => match min_ver { @@ -52,9 +54,9 @@ pub fn gl_get_version() -> GlslVersion { } } -pub fn gl_u16_to_version(version: u16) -> GlslVersion { +pub fn gl_u16_to_version(context: &glow::Context, version: u16) -> GlslVersion { match version { - 0 => gl_get_version(), + 0 => gl_get_version(context), 300 => GlslVersion::Glsl130, 310 => GlslVersion::Glsl140, 320 => GlslVersion::Glsl150, diff --git a/librashader-runtime-gl/tests/hello_triangle/gl3.rs b/librashader-runtime-gl/tests/hello_triangle/gl3.rs index f08acd9..440dab1 100644 --- a/librashader-runtime-gl/tests/hello_triangle/gl3.rs +++ b/librashader-runtime-gl/tests/hello_triangle/gl3.rs @@ -1,111 +1,25 @@ -use std::convert::TryInto; -use std::ffi::{c_void, CStr}; use std::sync::mpsc::Receiver; +use std::sync::Arc; use glfw::{Context, Glfw, Window, WindowEvent}; -use gl::types::{GLchar, GLenum, GLint, GLsizei, GLuint}; +use glow::HasContext; use librashader_common::{Size, Viewport}; use librashader_runtime_gl::{FilterChainGL, GLFramebuffer, GLImage}; const WIDTH: u32 = 800; const HEIGHT: u32 = 600; -const TITLE: &str = "librashader OpenGL"; +const TITLE: &str = "librashader OpenGL 3.3"; -pub fn compile_program(vertex: &str, fragment: &str) -> GLuint { - let vertex_shader = unsafe { gl::CreateShader(gl::VERTEX_SHADER) }; - unsafe { - gl::ShaderSource( - vertex_shader, - 1, - &vertex.as_bytes().as_ptr().cast(), - &vertex.len().try_into().unwrap(), - ); - gl::CompileShader(vertex_shader); - - let mut success = 0; - gl::GetShaderiv(vertex_shader, gl::COMPILE_STATUS, &mut success); - if success == 0 { - let mut log_len = 0_i32; - // gl::GetShaderiv(vertex_shader, gl::INFO_LOG_LENGTH, &mut log_len); - // let mut v: Vec = Vec::with_capacity(log_len as usize); - // gl::GetShaderInfoLog(vertex_shader, log_len, &mut log_len, v.as_mut_ptr().cast()); - let mut v: Vec = Vec::with_capacity(1024); - gl::GetShaderInfoLog(vertex_shader, 1024, &mut log_len, v.as_mut_ptr().cast()); - v.set_len(log_len.try_into().unwrap()); - panic!( - "Vertex Shader Compile Error: {}", - String::from_utf8_lossy(&v) - ); - } - } - - let fragment_shader = unsafe { gl::CreateShader(gl::FRAGMENT_SHADER) }; - unsafe { - gl::ShaderSource( - fragment_shader, - 1, - &fragment.as_bytes().as_ptr().cast(), - &fragment.len().try_into().unwrap(), - ); - gl::CompileShader(fragment_shader); - - let mut success = 0; - gl::GetShaderiv(fragment_shader, gl::COMPILE_STATUS, &mut success); - if success == 0 { - let mut v: Vec = Vec::with_capacity(1024); - let mut log_len = 0_i32; - gl::GetShaderInfoLog(fragment_shader, 1024, &mut log_len, v.as_mut_ptr().cast()); - v.set_len(log_len.try_into().unwrap()); - panic!( - "Fragment Shader Compile Error: {}", - String::from_utf8_lossy(&v) - ); - } - } - - let shader_program = unsafe { gl::CreateProgram() }; - unsafe { - gl::AttachShader(shader_program, vertex_shader); - gl::AttachShader(shader_program, fragment_shader); - gl::LinkProgram(shader_program); - - let mut success = 0; - gl::GetProgramiv(shader_program, gl::LINK_STATUS, &mut success); - if success == 0 { - let mut v: Vec = Vec::with_capacity(1024); - let mut log_len = 0_i32; - gl::GetProgramInfoLog(shader_program, 1024, &mut log_len, v.as_mut_ptr().cast()); - v.set_len(log_len.try_into().unwrap()); - panic!("Program Link Error: {}", String::from_utf8_lossy(&v)); - } - - gl::DetachShader(shader_program, vertex_shader); - gl::DetachShader(shader_program, fragment_shader); - gl::DeleteShader(vertex_shader); - gl::DeleteShader(fragment_shader); - } - - shader_program -} - -extern "system" fn debug_callback( - _source: GLenum, - _err_type: GLenum, - _id: GLuint, - _severity: GLenum, - _length: GLsizei, - message: *const GLchar, - _user: *mut c_void, +pub fn setup() -> ( + Glfw, + Window, + Receiver<(f64, WindowEvent)>, + glow::Program, + glow::VertexArray, + Arc, ) { - unsafe { - let message = CStr::from_ptr(message); - println!("[gl] {message:?}"); - } -} - -pub fn setup() -> (Glfw, Window, Receiver<(f64, WindowEvent)>, GLuint, GLuint) { let mut glfw = glfw::init(glfw::FAIL_ON_ERRORS).unwrap(); glfw.window_hint(glfw::WindowHint::ContextVersion(3, 3)); glfw.window_hint(glfw::WindowHint::OpenGlProfile( @@ -122,26 +36,20 @@ pub fn setup() -> (Glfw, Window, Receiver<(f64, WindowEvent)>, GLuint, GLuint) { window.make_current(); window.set_key_polling(true); - gl::load_with(|ptr| window.get_proc_address(ptr) as *const _); + let mut gl = unsafe { glow::Context::from_loader_function(|ptr| window.get_proc_address(ptr)) }; unsafe { - gl::Enable(gl::DEBUG_OUTPUT); - gl::Enable(gl::DEBUG_OUTPUT_SYNCHRONOUS); + gl.enable(glow::DEBUG_OUTPUT); + gl.enable(glow::DEBUG_OUTPUT_SYNCHRONOUS); - gl::DebugMessageCallback(Some(debug_callback), std::ptr::null_mut()); - gl::DebugMessageControl( - gl::DONT_CARE, - gl::DONT_CARE, - gl::DONT_CARE, - 0, - std::ptr::null(), - gl::TRUE, - ); + gl.debug_message_callback(super::debug_callback); + + gl.debug_message_control(glow::DONT_CARE, glow::DONT_CARE, glow::DONT_CARE, &[], true); } unsafe { - gl::Viewport(0, 0, screen_width, screen_height); - clear_color(Color(0.4, 0.4, 0.4, 1.0)); + gl.viewport(0, 0, screen_width, screen_height); + gl.clear_color(0.4, 0.4, 0.4, 1.0); } // ------------------------------------------- @@ -172,11 +80,11 @@ void main() { Color = vec4(IN.Color, 1.0f); }"; - let shader_program = compile_program(VERT_SHADER, FRAG_SHADER); + let shader_program = super::compile_program(&gl, VERT_SHADER, FRAG_SHADER); // unsafe { - // gl::ObjectLabel( - // gl::SHADER, + // glow::ObjectLabel( + // glow::SHADER, // shader_program, // -1, // b"color_shader\0".as_ptr().cast(), @@ -189,150 +97,161 @@ void main() -0.5, -0.5, 0.0, 0.0, 1.0, 0.0, // bottom left 0.0, 0.5, 0.0, 0.0, 0.0, 1.0, // top ]; - let mut vbo: gl::types::GLuint = 0; + let vbo; unsafe { - gl::GenBuffers(1, &mut vbo); - // gl::ObjectLabel(gl::BUFFER, vbo, -1, b"triangle_vbo\0".as_ptr().cast()); + vbo = gl.create_buffer().unwrap(); + // glow::ObjectLabel(glow::BUFFER, vbo, -1, b"triangle_vbo\0".as_ptr().cast()); } unsafe { - gl::BindBuffer(gl::ARRAY_BUFFER, vbo); - gl::BufferData( - gl::ARRAY_BUFFER, // target - (vertices.len() * std::mem::size_of::()) as gl::types::GLsizeiptr, // size of data in bytes - vertices.as_ptr() as *const gl::types::GLvoid, // pointer to data - gl::STATIC_DRAW, // usage + gl.bind_buffer(glow::ARRAY_BUFFER, Some(vbo)); + gl.buffer_data_u8_slice( + glow::ARRAY_BUFFER, // target + bytemuck::cast_slice(vertices), + glow::STATIC_DRAW, // usage ); - gl::BindBuffer(gl::ARRAY_BUFFER, 0); + gl.bind_buffer(glow::ARRAY_BUFFER, None); } // set up vertex array object - let mut vao: gl::types::GLuint = 0; + let vao; unsafe { - gl::GenVertexArrays(1, &mut vao); - // gl::ObjectLabel(gl::VERTEX_ARRAY, vao, -1, b"triangle_vao\0".as_ptr().cast()); + vao = gl.create_vertex_array().unwrap(); + // glow::ObjectLabel(glow::VERTEX_ARRAY, vao, -1, b"triangle_vao\0".as_ptr().cast()); } unsafe { - gl::BindVertexArray(vao); - gl::BindBuffer(gl::ARRAY_BUFFER, vbo); + gl.bind_vertex_array(Some(vao)); + gl.bind_buffer(glow::ARRAY_BUFFER, Some(vbo)); - gl::EnableVertexAttribArray(0); // this is "layout (location = 0)" in vertex shader - gl::VertexAttribPointer( - 0, // index of the generic vertex attribute ("layout (location = 0)") - 3, // the number of components per generic vertex attribute - gl::FLOAT, // data type - gl::FALSE, // normalized (int-to-float conversion) - (6 * std::mem::size_of::()) as gl::types::GLint, // stride (byte offset between consecutive attributes) - std::ptr::null(), // offset of the first component + gl.enable_vertex_attrib_array(0); // this is "layout (location = 0)" in vertex shader + gl.vertex_attrib_pointer_f32( + 0, // index of the generic vertex attribute ("layout (location = 0)") + 3, // the number of components per generic vertex attribute + glow::FLOAT, // data type + false, // normalized (int-to-float conversion) + (6 * std::mem::size_of::()) as i32, // stride (byte offset between consecutive attributes) + 0, // offset of the first component ); - gl::EnableVertexAttribArray(1); // this is "layout (location = 0)" in vertex shader - gl::VertexAttribPointer( - 1, // index of the generic vertex attribute ("layout (location = 0)") - 3, // the number of components per generic vertex attribute - gl::FLOAT, // data type - gl::FALSE, // normalized (int-to-float conversion) - (6 * std::mem::size_of::()) as gl::types::GLint, // stride (byte offset between consecutive attributes) - (3 * std::mem::size_of::()) as *const gl::types::GLvoid, // offset of the first component + gl.enable_vertex_attrib_array(1); + + gl.vertex_attrib_pointer_f32( + 1, // index of the generic vertex attribute ("layout (location = 0)") + 3, // the number of components per generic vertex attribute + glow::FLOAT, // data type + false, // normalized (int-to-float conversion) + (6 * std::mem::size_of::()) as i32, // stride (byte offset between consecutive attributes) + (3 * std::mem::size_of::()) as i32, // offset of the first component ); - gl::BindBuffer(gl::ARRAY_BUFFER, 0); - gl::BindVertexArray(0); + gl.bind_buffer(glow::ARRAY_BUFFER, None); + gl.bind_vertex_array(None); } // set up shared state for window unsafe { - gl::Viewport(0, 0, 900, 700); - gl::ClearColor(0.3, 0.3, 0.5, 1.0); + gl.viewport(0, 0, 900, 700); + gl.clear_color(0.3, 0.3, 0.5, 1.0); } - // ------------------------------------------- - println!("OpenGL version: {}", gl_get_string(gl::VERSION)); - println!( - "GLSL version: {}", - gl_get_string(gl::SHADING_LANGUAGE_VERSION) - ); + unsafe { + // ------------------------------------------- + println!("OpenGL version: {}", gl.get_parameter_string(glow::VERSION)); + println!( + "GLSL version: {}", + gl.get_parameter_string(glow::SHADING_LANGUAGE_VERSION) + ); + } - (glfw, window, events, shader_program, vao) + (glfw, window, events, shader_program, vao, Arc::new(gl)) } pub fn do_loop( + gl: &Arc, mut glfw: Glfw, mut window: Window, events: Receiver<(f64, WindowEvent)>, - triangle_program: GLuint, - triangle_vao: GLuint, + triangle_program: glow::Program, + triangle_vao: glow::VertexArray, filter: &mut FilterChainGL, ) { let mut framecount = 0; - let mut rendered_framebuffer = 0; - let mut rendered_texture = 0; - let mut quad_vbuf = 0; + let rendered_framebuffer; + let rendered_texture; + let quad_vbuf; - let mut output_texture = 0; - let mut output_framebuffer_handle = 0; - let mut output_quad_vbuf = 0; + let output_texture; + let output_framebuffer_handle; + let output_quad_vbuf; unsafe { // do frmaebuffer - gl::GenFramebuffers(1, &mut rendered_framebuffer); - gl::BindFramebuffer(gl::FRAMEBUFFER, rendered_framebuffer); + rendered_framebuffer = gl.create_framebuffer().unwrap(); - // gl::ObjectLabel( - // gl::FRAMEBUFFER, + gl.bind_framebuffer(glow::FRAMEBUFFER, Some(rendered_framebuffer)); + + // glow::ObjectLabel( + // glow::FRAMEBUFFER, // rendered_framebuffer, // -1, // b"rendered_framebuffer\0".as_ptr().cast(), // ); // make tetxure - gl::GenTextures(1, &mut rendered_texture); - gl::BindTexture(gl::TEXTURE_2D, rendered_texture); + rendered_texture = gl.create_texture().unwrap(); + gl.bind_texture(glow::TEXTURE_2D, Some(rendered_texture)); - // gl::ObjectLabel( - // gl::TEXTURE, + // glow::ObjectLabel( + // glow::TEXTURE, // rendered_texture, // -1, // b"rendered_texture\0".as_ptr().cast(), // ); // empty image - gl::TexStorage2D( - gl::TEXTURE_2D, + gl.tex_storage_2d( + glow::TEXTURE_2D, 1, - gl::RGBA8, - WIDTH as GLsizei, - HEIGHT as GLsizei, + glow::RGBA8, + WIDTH as i32, + HEIGHT as i32, ); - gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::NEAREST as GLint); - gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::NEAREST as GLint); - gl::TexParameteri( - gl::TEXTURE_2D, - gl::TEXTURE_WRAP_S, - gl::CLAMP_TO_EDGE as GLint, + gl.tex_parameter_i32( + glow::TEXTURE_2D, + glow::TEXTURE_MAG_FILTER, + glow::NEAREST as i32, ); - gl::TexParameteri( - gl::TEXTURE_2D, - gl::TEXTURE_WRAP_T, - gl::CLAMP_TO_EDGE as GLint, + gl.tex_parameter_i32( + glow::TEXTURE_2D, + glow::TEXTURE_MIN_FILTER, + glow::NEAREST as i32, + ); + gl.tex_parameter_i32( + glow::TEXTURE_2D, + glow::TEXTURE_WRAP_S, + glow::CLAMP_TO_EDGE as i32, + ); + gl.tex_parameter_i32( + glow::TEXTURE_2D, + glow::TEXTURE_WRAP_T, + glow::CLAMP_TO_EDGE as i32, ); // set color attachment - gl::FramebufferTexture2D( - gl::FRAMEBUFFER, - gl::COLOR_ATTACHMENT0, - gl::TEXTURE_2D, - rendered_texture, + gl.framebuffer_texture_2d( + glow::FRAMEBUFFER, + glow::COLOR_ATTACHMENT0, + glow::TEXTURE_2D, + Some(rendered_texture), 0, ); - let buffers = [gl::COLOR_ATTACHMENT0]; - gl::DrawBuffers(1, buffers.as_ptr()); + gl.draw_buffer(glow::COLOR_ATTACHMENT0); - if gl::CheckFramebufferStatus(gl::FRAMEBUFFER) != gl::FRAMEBUFFER_COMPLETE { + if gl.check_framebuffer_status(glow::FRAMEBUFFER) != glow::FRAMEBUFFER_COMPLETE { panic!("failed to create fbo") } @@ -341,74 +260,80 @@ pub fn do_loop( 1.0, 1.0, 0.0, ]; - gl::GenBuffers(1, &mut quad_vbuf); - gl::BindBuffer(gl::ARRAY_BUFFER, quad_vbuf); - gl::BufferData( - gl::ARRAY_BUFFER, // target - (fullscreen_fbo.len() * std::mem::size_of::()) as gl::types::GLsizeiptr, // size of data in bytes - fullscreen_fbo.as_ptr() as *const gl::types::GLvoid, // pointer to data - gl::STATIC_DRAW, // usage + quad_vbuf = gl.create_buffer().unwrap(); + gl.bind_buffer(glow::ARRAY_BUFFER, Some(quad_vbuf)); + gl.buffer_data_u8_slice( + glow::ARRAY_BUFFER, + bytemuck::cast_slice(&fullscreen_fbo), + glow::STATIC_DRAW, ); } unsafe { // do frmaebuffer - gl::GenFramebuffers(1, &mut output_framebuffer_handle); - gl::BindFramebuffer(gl::FRAMEBUFFER, output_framebuffer_handle); + output_framebuffer_handle = gl.create_framebuffer().unwrap(); - // gl::ObjectLabel( - // gl::FRAMEBUFFER, + gl.bind_framebuffer(glow::FRAMEBUFFER, Some(output_framebuffer_handle)); + + // glow::ObjectLabel( + // glow::FRAMEBUFFER, // output_framebuffer_handle, // -1, // b"output_framebuffer\0".as_ptr().cast(), // ); // make tetxure - gl::GenTextures(1, &mut output_texture); - gl::BindTexture(gl::TEXTURE_2D, output_texture); + output_texture = gl.create_texture().unwrap(); + gl.bind_texture(glow::TEXTURE_2D, Some(output_texture)); - // gl::ObjectLabel( - // gl::TEXTURE, + // glow::ObjectLabel( + // glow::TEXTURE, // output_texture, // -1, // b"output_texture\0".as_ptr().cast(), // ); // empty image - gl::TexStorage2D( - gl::TEXTURE_2D, + gl.tex_storage_2d( + glow::TEXTURE_2D, 1, - gl::RGBA8, - WIDTH as GLsizei, - HEIGHT as GLsizei, + glow::RGBA8, + WIDTH as i32, + HEIGHT as i32, ); - gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::NEAREST as GLint); - gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::NEAREST as GLint); - gl::TexParameteri( - gl::TEXTURE_2D, - gl::TEXTURE_WRAP_S, - gl::CLAMP_TO_EDGE as GLint, + gl.tex_parameter_i32( + glow::TEXTURE_2D, + glow::TEXTURE_MAG_FILTER, + glow::NEAREST as i32, ); - gl::TexParameteri( - gl::TEXTURE_2D, - gl::TEXTURE_WRAP_T, - gl::CLAMP_TO_EDGE as GLint, + gl.tex_parameter_i32( + glow::TEXTURE_2D, + glow::TEXTURE_MIN_FILTER, + glow::NEAREST as i32, + ); + gl.tex_parameter_i32( + glow::TEXTURE_2D, + glow::TEXTURE_WRAP_S, + glow::CLAMP_TO_EDGE as i32, + ); + gl.tex_parameter_i32( + glow::TEXTURE_2D, + glow::TEXTURE_WRAP_T, + glow::CLAMP_TO_EDGE as i32, ); // set color attachment - gl::FramebufferTexture2D( - gl::FRAMEBUFFER, - gl::COLOR_ATTACHMENT0, - gl::TEXTURE_2D, - output_texture, + gl.framebuffer_texture_2d( + glow::FRAMEBUFFER, + glow::COLOR_ATTACHMENT0, + glow::TEXTURE_2D, + Some(output_texture), 0, ); - let buffers = [gl::COLOR_ATTACHMENT0]; - gl::DrawBuffers(1, buffers.as_ptr()); - - if gl::CheckFramebufferStatus(gl::FRAMEBUFFER) != gl::FRAMEBUFFER_COMPLETE { + gl.draw_buffer(glow::COLOR_ATTACHMENT0); + if gl.check_framebuffer_status(glow::FRAMEBUFFER) != glow::FRAMEBUFFER_COMPLETE { panic!("failed to create fbo") } @@ -417,13 +342,12 @@ pub fn do_loop( 1.0, 1.0, 0.0, ]; - gl::GenBuffers(1, &mut output_quad_vbuf); - gl::BindBuffer(gl::ARRAY_BUFFER, output_quad_vbuf); - gl::BufferData( - gl::ARRAY_BUFFER, // target - (fullscreen_fbo.len() * std::mem::size_of::()) as gl::types::GLsizeiptr, // size of data in bytes - fullscreen_fbo.as_ptr() as *const gl::types::GLvoid, // pointer to data - gl::STATIC_DRAW, // usage + output_quad_vbuf = gl.create_buffer().unwrap(); + gl.bind_buffer(glow::ARRAY_BUFFER, Some(output_quad_vbuf)); + gl.buffer_data_u8_slice( + glow::ARRAY_BUFFER, // target + bytemuck::cast_slice(&fullscreen_fbo), + glow::STATIC_DRAW, // usage ); } @@ -452,19 +376,20 @@ void main() color=texture(texSampler, v_tex); }"; - let quad_programid = compile_program(VERT_SHADER, FRAG_SHADER); - let mut quad_vao = 0; + let quad_programid = super::compile_program(gl, VERT_SHADER, FRAG_SHADER); + let quad_vao; unsafe { - gl::GenVertexArrays(1, &mut quad_vao); + quad_vao = gl.create_vertex_array().unwrap(); } let (fb_width, fb_height) = window.get_framebuffer_size(); let (vp_width, vp_height) = window.get_size(); let output = GLFramebuffer::new_from_raw( - output_texture, + Arc::clone(gl), + Some(output_texture), output_framebuffer_handle, - gl::RGBA8, + glow::RGBA8, Size::new(vp_width as u32, vp_height as u32), 1, ); @@ -477,26 +402,26 @@ void main() unsafe { // render to fb - gl::BindFramebuffer(gl::FRAMEBUFFER, rendered_framebuffer); - gl::Viewport(0, 0, vp_width, vp_height); + gl.bind_framebuffer(glow::FRAMEBUFFER, Some(rendered_framebuffer)); + gl.viewport(0, 0, vp_width, vp_height); // clear color - clear_color(Color(0.3, 0.4, 0.6, 1.0)); - gl::Clear(gl::COLOR_BUFFER_BIT); + gl.clear_color(0.3, 0.4, 0.6, 1.0); + gl.clear(glow::COLOR_BUFFER_BIT); // do the drawing - gl::UseProgram(triangle_program); + gl.use_program(Some(triangle_program)); // select vertices - gl::BindVertexArray(triangle_vao); + gl.bind_vertex_array(Some(triangle_vao)); // draw to bound target - gl::DrawArrays(gl::TRIANGLES, 0, 3); + gl.draw_arrays(glow::TRIANGLES, 0, 3); // unselect vertices - gl::BindVertexArray(0); + gl.bind_vertex_array(None); // unselect fbo - gl::BindFramebuffer(gl::FRAMEBUFFER, 0); + gl.bind_framebuffer(glow::FRAMEBUFFER, None); } let viewport = Viewport { @@ -507,8 +432,8 @@ void main() }; let rendered = GLImage { - handle: rendered_texture, - format: gl::RGBA8, + handle: Some(rendered_texture), + format: glow::RGBA8, size: Size { width: fb_width as u32, height: fb_height as u32, @@ -524,13 +449,13 @@ void main() unsafe { // texture is done now. // draw quad to screen - gl::UseProgram(quad_programid); + gl.use_program(Some(quad_programid)); - gl::ActiveTexture(gl::TEXTURE0); - gl::BindTexture(gl::TEXTURE_2D, output_texture); + gl.active_texture(glow::TEXTURE0); + gl.bind_texture(glow::TEXTURE_2D, Some(output_texture)); - gl::BindVertexArray(quad_vao); - gl::DrawArrays(gl::TRIANGLE_STRIP, 0, 4); + gl.bind_vertex_array(Some(quad_vao)); + gl.draw_arrays(glow::TRIANGLE_STRIP, 0, 4); } framecount += 1; @@ -538,18 +463,6 @@ void main() } } -pub struct Color(f32, f32, f32, f32); - -pub fn clear_color(c: Color) { - unsafe { gl::ClearColor(c.0, c.1, c.2, c.3) } -} - -pub fn gl_get_string<'a>(name: gl::types::GLenum) -> &'a str { - let v = unsafe { gl::GetString(name) }; - let v: &std::ffi::CStr = unsafe { std::ffi::CStr::from_ptr(v as *const i8) }; - v.to_str().unwrap() -} - fn glfw_handle_event(window: &mut glfw::Window, event: glfw::WindowEvent) { use glfw::Action; use glfw::Key; diff --git a/librashader-runtime-gl/tests/hello_triangle/gl46.rs b/librashader-runtime-gl/tests/hello_triangle/gl46.rs index fab9a75..cd77e05 100644 --- a/librashader-runtime-gl/tests/hello_triangle/gl46.rs +++ b/librashader-runtime-gl/tests/hello_triangle/gl46.rs @@ -1,10 +1,9 @@ -use std::convert::TryInto; -use std::ffi::{c_void, CStr}; use std::sync::mpsc::Receiver; +use std::sync::Arc; use glfw::{Context, Glfw, Window, WindowEvent}; -use gl::types::{GLchar, GLenum, GLint, GLsizei, GLuint}; +use glow::HasContext; use librashader_common::{Size, Viewport}; use librashader_runtime_gl::{FilterChainGL, GLFramebuffer, GLImage}; @@ -13,101 +12,16 @@ const WIDTH: u32 = 800; const HEIGHT: u32 = 600; const TITLE: &str = "librashader OpenGL 4.6"; -pub fn compile_program(vertex: &str, fragment: &str) -> GLuint { - let vertex_shader = unsafe { gl::CreateShader(gl::VERTEX_SHADER) }; - unsafe { - gl::ShaderSource( - vertex_shader, - 1, - &vertex.as_bytes().as_ptr().cast(), - &vertex.len().try_into().unwrap(), - ); - gl::CompileShader(vertex_shader); - - let mut success = 0; - gl::GetShaderiv(vertex_shader, gl::COMPILE_STATUS, &mut success); - if success == 0 { - let mut log_len = 0_i32; - // gl::GetShaderiv(vertex_shader, gl::INFO_LOG_LENGTH, &mut log_len); - // let mut v: Vec = Vec::with_capacity(log_len as usize); - // gl::GetShaderInfoLog(vertex_shader, log_len, &mut log_len, v.as_mut_ptr().cast()); - let mut v: Vec = Vec::with_capacity(1024); - gl::GetShaderInfoLog(vertex_shader, 1024, &mut log_len, v.as_mut_ptr().cast()); - v.set_len(log_len.try_into().unwrap()); - panic!( - "Vertex Shader Compile Error: {}", - String::from_utf8_lossy(&v) - ); - } - } - - let fragment_shader = unsafe { gl::CreateShader(gl::FRAGMENT_SHADER) }; - unsafe { - gl::ShaderSource( - fragment_shader, - 1, - &fragment.as_bytes().as_ptr().cast(), - &fragment.len().try_into().unwrap(), - ); - gl::CompileShader(fragment_shader); - - let mut success = 0; - gl::GetShaderiv(fragment_shader, gl::COMPILE_STATUS, &mut success); - if success == 0 { - let mut v: Vec = Vec::with_capacity(1024); - let mut log_len = 0_i32; - gl::GetShaderInfoLog(fragment_shader, 1024, &mut log_len, v.as_mut_ptr().cast()); - v.set_len(log_len.try_into().unwrap()); - panic!( - "Fragment Shader Compile Error: {}", - String::from_utf8_lossy(&v) - ); - } - } - - let shader_program = unsafe { gl::CreateProgram() }; - unsafe { - gl::AttachShader(shader_program, vertex_shader); - gl::AttachShader(shader_program, fragment_shader); - gl::LinkProgram(shader_program); - - let mut success = 0; - gl::GetProgramiv(shader_program, gl::LINK_STATUS, &mut success); - if success == 0 { - let mut v: Vec = Vec::with_capacity(1024); - let mut log_len = 0_i32; - gl::GetProgramInfoLog(shader_program, 1024, &mut log_len, v.as_mut_ptr().cast()); - v.set_len(log_len.try_into().unwrap()); - panic!("Program Link Error: {}", String::from_utf8_lossy(&v)); - } - - gl::DetachShader(shader_program, vertex_shader); - gl::DetachShader(shader_program, fragment_shader); - gl::DeleteShader(vertex_shader); - gl::DeleteShader(fragment_shader); - } - - shader_program -} - -extern "system" fn debug_callback( - _source: GLenum, - _err_type: GLenum, - _id: GLuint, - _severity: GLenum, - _length: GLsizei, - message: *const GLchar, - _user: *mut c_void, +pub fn setup() -> ( + Glfw, + Window, + Receiver<(f64, WindowEvent)>, + glow::Program, + glow::VertexArray, + Arc, ) { - unsafe { - let message = CStr::from_ptr(message); - println!("[gl] {message:?}"); - } -} - -pub fn setup() -> (Glfw, Window, Receiver<(f64, WindowEvent)>, GLuint, GLuint) { let mut glfw = glfw::init(glfw::FAIL_ON_ERRORS).unwrap(); - glfw.window_hint(glfw::WindowHint::ContextVersion(3, 3)); + glfw.window_hint(glfw::WindowHint::ContextVersion(4, 6)); glfw.window_hint(glfw::WindowHint::OpenGlProfile( glfw::OpenGlProfileHint::Core, )); @@ -122,26 +36,20 @@ pub fn setup() -> (Glfw, Window, Receiver<(f64, WindowEvent)>, GLuint, GLuint) { window.make_current(); window.set_key_polling(true); - gl::load_with(|ptr| window.get_proc_address(ptr) as *const _); + let mut gl = unsafe { glow::Context::from_loader_function(|ptr| window.get_proc_address(ptr)) }; unsafe { - gl::Enable(gl::DEBUG_OUTPUT); - gl::Enable(gl::DEBUG_OUTPUT_SYNCHRONOUS); + gl.enable(glow::DEBUG_OUTPUT); + gl.enable(glow::DEBUG_OUTPUT_SYNCHRONOUS); - gl::DebugMessageCallback(Some(debug_callback), std::ptr::null_mut()); - gl::DebugMessageControl( - gl::DONT_CARE, - gl::DONT_CARE, - gl::DONT_CARE, - 0, - std::ptr::null(), - gl::TRUE, - ); + gl.debug_message_callback(super::debug_callback); + + gl.debug_message_control(glow::DONT_CARE, glow::DONT_CARE, glow::DONT_CARE, &[], true); } unsafe { - gl::Viewport(0, 0, screen_width, screen_height); - clear_color(Color(0.4, 0.4, 0.4, 1.0)); + gl.viewport(0, 0, screen_width, screen_height); + gl.clear_color(0.4, 0.4, 0.4, 1.0); } // ------------------------------------------- @@ -172,15 +80,10 @@ void main() { Color = vec4(IN.Color, 1.0f); }"; - let shader_program = compile_program(VERT_SHADER, FRAG_SHADER); + let shader_program = super::compile_program(&gl, VERT_SHADER, FRAG_SHADER); unsafe { - gl::ObjectLabel( - gl::SHADER, - shader_program, - -1, - b"color_shader\0".as_ptr().cast(), - ); + gl.object_label(glow::SHADER, shader_program.0.get(), Some("color_shader")); } let vertices = &[ @@ -189,146 +92,143 @@ void main() -0.5, -0.5, 0.0, 0.0, 1.0, 0.0, // bottom left 0.0, 0.5, 0.0, 0.0, 0.0, 1.0, // top ]; - let mut vbo: gl::types::GLuint = 0; + let vbo = unsafe { gl.create_named_buffer().unwrap() }; + unsafe { - gl::CreateBuffers(1, &mut vbo); - gl::ObjectLabel(gl::BUFFER, vbo, -1, b"triangle_vbo\0".as_ptr().cast()); + gl.object_label(glow::BUFFER, vbo.0.get(), Some("triangle_vbo")); } unsafe { - gl::NamedBufferData( + gl.named_buffer_data_u8_slice( vbo, - (vertices.len() * std::mem::size_of::()) as gl::types::GLsizeiptr, // size of data in bytes - vertices.as_ptr() as *const gl::types::GLvoid, // pointer to data - gl::STATIC_DRAW, // usage + bytemuck::cast_slice(vertices), + glow::STATIC_DRAW, // usage ); } // set up vertex array object - let mut vao: gl::types::GLuint = 0; + let vao = unsafe { gl.create_named_vertex_array().unwrap() }; // todo: figure this shit out unsafe { - gl::CreateVertexArrays(1, &mut vao); - gl::ObjectLabel(gl::VERTEX_ARRAY, vao, -1, b"triangle_vao\0".as_ptr().cast()); + // gl.object_label(glow::VERTEX_ARRAY, vao.0.get(), Some("triangle_vao")); - gl::VertexArrayVertexBuffer(vao, 0, vbo, 0, 6 * std::mem::size_of::() as GLint); + gl.vertex_array_vertex_buffer(vao, 0, Some(vbo), 0, 6 * std::mem::size_of::() as i32); - gl::EnableVertexArrayAttrib(vao, 0); // this is "layout (location = 0)" in vertex shader - gl::VertexArrayAttribFormat(vao, 0, 3, gl::FLOAT, gl::FALSE, 0); + gl.enable_vertex_array_attrib(vao, 0); // this is "layout (location = 0)" in vertex shader + gl.vertex_array_attrib_format_f32(vao, 0, 3, glow::FLOAT, false, 0); - gl::EnableVertexArrayAttrib(vao, 1); - gl::VertexArrayAttribFormat( + gl.enable_vertex_array_attrib(vao, 1); + gl.vertex_array_attrib_format_f32( vao, 1, 3, - gl::FLOAT, - gl::FALSE, - 3 * std::mem::size_of::() as GLuint, + glow::FLOAT, + false, + 3 * std::mem::size_of::() as u32, ); - gl::VertexArrayAttribBinding(vao, 0, 0); - gl::VertexArrayAttribBinding(vao, 1, 0); + gl.vertex_array_attrib_binding_f32(vao, 0, 0); + gl.vertex_array_attrib_binding_f32(vao, 1, 0); } // set up shared state for window unsafe { - gl::Viewport(0, 0, 900, 700); - gl::ClearColor(0.3, 0.3, 0.5, 1.0); + gl.viewport(0, 0, 900, 700); + gl.clear_color(0.3, 0.3, 0.5, 1.0); } - // ------------------------------------------- - println!("OpenGL version: {}", gl_get_string(gl::VERSION)); - println!( - "GLSL version: {}", - gl_get_string(gl::SHADING_LANGUAGE_VERSION) - ); + unsafe { + // ------------------------------------------- + println!("OpenGL version: {}", gl.get_parameter_string(glow::VERSION)); + println!( + "GLSL version: {}", + gl.get_parameter_string(glow::SHADING_LANGUAGE_VERSION) + ); + } - (glfw, window, events, shader_program, vao) + (glfw, window, events, shader_program, vao, Arc::new(gl)) } pub fn do_loop( + gl: &Arc, mut glfw: Glfw, mut window: Window, events: Receiver<(f64, WindowEvent)>, - triangle_program: GLuint, - triangle_vao: GLuint, + triangle_program: glow::Program, + triangle_vao: glow::VertexArray, filter: &mut FilterChainGL, ) { let mut framecount = 0; - let mut rendered_framebuffer = 0; - let mut rendered_texture = 0; - let mut quad_vbuf = 0; + let rendered_framebuffer; + let rendered_texture; + let quad_vbuf; - let mut output_texture = 0; - let mut output_framebuffer_handle = 0; - let mut output_quad_vbuf = 0; + let output_texture; + let output_framebuffer_handle; + let output_quad_vbuf; unsafe { // do frmaebuffer - gl::CreateFramebuffers(1, &mut rendered_framebuffer); - - gl::ObjectLabel( - gl::FRAMEBUFFER, - rendered_framebuffer, - -1, - b"rendered_framebuffer\0".as_ptr().cast(), + rendered_framebuffer = gl.create_named_framebuffer().unwrap(); + gl.object_label( + glow::FRAMEBUFFER, + rendered_framebuffer.0.get(), + Some("rendered_framebuffer"), ); - // make tetxure - gl::CreateTextures(gl::TEXTURE_2D, 1, &mut rendered_texture); - - gl::ObjectLabel( - gl::TEXTURE, - rendered_texture, - -1, - b"rendered_texture\0".as_ptr().cast(), + rendered_texture = gl.create_named_texture(glow::TEXTURE_2D).unwrap(); + gl.object_label( + glow::TEXTURE, + rendered_texture.0.get(), + Some("rendered_texture"), ); // empty image - gl::TextureStorage2D( + gl.texture_storage_2d( rendered_texture, 1, - gl::RGBA8, - WIDTH as GLsizei, - HEIGHT as GLsizei, + glow::RGBA8, + WIDTH as i32, + HEIGHT as i32, ); - gl::TextureParameteri( + gl.texture_parameter_i32( rendered_texture, - gl::TEXTURE_MAG_FILTER, - gl::NEAREST as GLint, + glow::TEXTURE_MAG_FILTER, + glow::NEAREST as i32, ); - gl::TextureParameteri( + gl.texture_parameter_i32( rendered_texture, - gl::TEXTURE_MIN_FILTER, - gl::NEAREST as GLint, + glow::TEXTURE_MIN_FILTER, + glow::NEAREST as i32, ); - gl::TextureParameteri( + gl.texture_parameter_i32( rendered_texture, - gl::TEXTURE_WRAP_S, - gl::CLAMP_TO_EDGE as GLint, + glow::TEXTURE_WRAP_S, + glow::CLAMP_TO_EDGE as i32, ); - gl::TextureParameteri( + gl.texture_parameter_i32( rendered_texture, - gl::TEXTURE_WRAP_T, - gl::CLAMP_TO_EDGE as GLint, + glow::TEXTURE_WRAP_T, + glow::CLAMP_TO_EDGE as i32, ); // set color attachment - gl::NamedFramebufferTexture( - rendered_framebuffer, - gl::COLOR_ATTACHMENT0, - rendered_texture, + gl.named_framebuffer_texture( + Some(rendered_framebuffer), + glow::COLOR_ATTACHMENT0, + Some(rendered_texture), 0, ); - let buffers = [gl::COLOR_ATTACHMENT0]; - gl::NamedFramebufferDrawBuffers(rendered_framebuffer, 1, buffers.as_ptr()); + gl.named_framebuffer_draw_buffer(Some(rendered_framebuffer), glow::COLOR_ATTACHMENT0); - if gl::CheckFramebufferStatus(gl::FRAMEBUFFER) != gl::FRAMEBUFFER_COMPLETE { + if gl.check_named_framebuffer_status(Some(rendered_framebuffer), glow::FRAMEBUFFER) + != glow::FRAMEBUFFER_COMPLETE + { panic!("failed to create fbo") } @@ -337,70 +237,70 @@ pub fn do_loop( 1.0, 1.0, 0.0, ]; - gl::CreateBuffers(1, &mut quad_vbuf); - gl::NamedBufferData( - quad_vbuf, // target - (fullscreen_fbo.len() * std::mem::size_of::()) as gl::types::GLsizeiptr, // size of data in bytes - fullscreen_fbo.as_ptr() as *const gl::types::GLvoid, // pointer to data - gl::STATIC_DRAW, // usage + quad_vbuf = gl.create_named_buffer().unwrap(); + + gl.named_buffer_data_u8_slice( + quad_vbuf, + bytemuck::cast_slice(&fullscreen_fbo), + glow::STATIC_DRAW, ); } unsafe { // do frmaebuffer - gl::CreateFramebuffers(1, &mut output_framebuffer_handle); + output_framebuffer_handle = gl.create_named_framebuffer().unwrap(); - gl::ObjectLabel( - gl::FRAMEBUFFER, - output_framebuffer_handle, - -1, - b"output_framebuffer\0".as_ptr().cast(), + gl.object_label( + glow::FRAMEBUFFER, + output_framebuffer_handle.0.get(), + Some("output_framebuffer"), ); // make tetxure - gl::CreateTextures(gl::TEXTURE_2D, 1, &mut output_texture); - - gl::ObjectLabel( - gl::TEXTURE, - output_texture, - -1, - b"output_texture\0".as_ptr().cast(), + output_texture = gl.create_named_texture(glow::TEXTURE_2D).unwrap(); + // + gl.object_label( + glow::TEXTURE, + output_texture.0.get(), + Some("output_texture"), ); - // empty image - gl::TextureStorage2D( - output_texture, - 1, - gl::RGBA8, - WIDTH as GLsizei, - HEIGHT as GLsizei, - ); + gl.texture_storage_2d(output_texture, 1, glow::RGBA8, WIDTH as i32, HEIGHT as i32); - gl::TextureParameteri(output_texture, gl::TEXTURE_MAG_FILTER, gl::NEAREST as GLint); - gl::TextureParameteri(output_texture, gl::TEXTURE_MIN_FILTER, gl::NEAREST as GLint); - gl::TextureParameteri( + gl.texture_parameter_i32( output_texture, - gl::TEXTURE_WRAP_S, - gl::CLAMP_TO_EDGE as GLint, + glow::TEXTURE_MAG_FILTER, + glow::NEAREST as i32, ); - gl::TextureParameteri( + gl.texture_parameter_i32( output_texture, - gl::TEXTURE_WRAP_T, - gl::CLAMP_TO_EDGE as GLint, + glow::TEXTURE_MIN_FILTER, + glow::NEAREST as i32, + ); + gl.texture_parameter_i32( + output_texture, + glow::TEXTURE_WRAP_S, + glow::CLAMP_TO_EDGE as i32, + ); + gl.texture_parameter_i32( + output_texture, + glow::TEXTURE_WRAP_T, + glow::CLAMP_TO_EDGE as i32, ); // set color attachment - gl::NamedFramebufferTexture( - output_framebuffer_handle, - gl::COLOR_ATTACHMENT0, - output_texture, + gl.named_framebuffer_texture( + Some(output_framebuffer_handle), + glow::COLOR_ATTACHMENT0, + Some(output_texture), 0, ); - let buffers = [gl::COLOR_ATTACHMENT0]; - gl::NamedFramebufferDrawBuffers(output_framebuffer_handle, 1, buffers.as_ptr()); + gl.named_framebuffer_draw_buffer(Some(output_framebuffer_handle), glow::COLOR_ATTACHMENT0); - if gl::CheckFramebufferStatus(gl::FRAMEBUFFER) != gl::FRAMEBUFFER_COMPLETE { + if gl.check_named_framebuffer_status(Some(output_framebuffer_handle), glow::FRAMEBUFFER) + != glow::FRAMEBUFFER_COMPLETE + { panic!("failed to create fbo") } @@ -409,12 +309,11 @@ pub fn do_loop( 1.0, 1.0, 0.0, ]; - gl::CreateBuffers(1, &mut output_quad_vbuf); - gl::NamedBufferData( + output_quad_vbuf = gl.create_named_buffer().unwrap(); + gl.named_buffer_data_u8_slice( output_quad_vbuf, - (fullscreen_fbo.len() * std::mem::size_of::()) as gl::types::GLsizeiptr, // size of data in bytes - fullscreen_fbo.as_ptr() as *const gl::types::GLvoid, // pointer to data - gl::STATIC_DRAW, // usage + bytemuck::cast_slice(&fullscreen_fbo), + glow::STATIC_DRAW, ); } @@ -443,19 +342,17 @@ void main() color=texture(texSampler, v_tex); }"; - let quad_programid = compile_program(VERT_SHADER, FRAG_SHADER); - let mut quad_vao = 0; - unsafe { - gl::CreateVertexArrays(1, &mut quad_vao); - } + let quad_programid = super::compile_program(gl, VERT_SHADER, FRAG_SHADER); + let quad_vao = unsafe { gl.create_named_vertex_array().unwrap() }; let (fb_width, fb_height) = window.get_framebuffer_size(); let (vp_width, vp_height) = window.get_size(); let output = GLFramebuffer::new_from_raw( - output_texture, + Arc::clone(gl), + Some(output_texture), output_framebuffer_handle, - gl::RGBA8, + glow::RGBA8, Size::new(vp_width as u32, vp_height as u32), 1, ); @@ -469,28 +366,28 @@ void main() unsafe { // render to fb - gl::ClearNamedFramebufferfv( - rendered_framebuffer, - gl::COLOR, + gl.clear_named_framebuffer_f32_slice( + Some(rendered_framebuffer), + glow::COLOR, 0, - [0.3f32, 0.4, 0.6, 1.0].as_ptr().cast(), + &[0.3f32, 0.4, 0.6, 1.0], ); - gl::BindFramebuffer(gl::FRAMEBUFFER, rendered_framebuffer); - gl::Viewport(0, 0, vp_width, vp_height); + gl.bind_framebuffer(glow::FRAMEBUFFER, Some(rendered_framebuffer)); + gl.viewport(0, 0, vp_width, vp_height); // do the drawing - gl::UseProgram(triangle_program); + gl.use_program(Some(triangle_program)); // select vertices - gl::BindVertexArray(triangle_vao); + gl.bind_vertex_array(Some(triangle_vao)); // draw to bound target - gl::DrawArrays(gl::TRIANGLES, 0, 3); + gl.draw_arrays(glow::TRIANGLES, 0, 3); // unselect vertices - gl::BindVertexArray(0); + gl.bind_vertex_array(None); // unselect fbo - gl::BindFramebuffer(gl::FRAMEBUFFER, 0); + gl.bind_framebuffer(glow::FRAMEBUFFER, None); } let viewport = Viewport { @@ -501,8 +398,8 @@ void main() }; let rendered = GLImage { - handle: rendered_texture, - format: gl::RGBA8, + handle: Some(rendered_texture), + format: glow::RGBA8, size: Size { width: fb_width as u32, height: fb_height as u32, @@ -518,31 +415,18 @@ void main() unsafe { // texture is done now. // draw quad to screen - gl::UseProgram(quad_programid); + gl.use_program(Some(quad_programid)); - gl::BindTextureUnit(0, output_texture); + gl.bind_texture_unit(0, Some(output_texture)); - gl::BindVertexArray(quad_vao); - gl::DrawArrays(gl::TRIANGLE_STRIP, 0, 4); + gl.bind_vertex_array(Some(quad_vao)); + gl.draw_arrays(glow::TRIANGLE_STRIP, 0, 4); } framecount += 1; window.swap_buffers(); } } - -pub struct Color(f32, f32, f32, f32); - -pub fn clear_color(c: Color) { - unsafe { gl::ClearColor(c.0, c.1, c.2, c.3) } -} - -pub fn gl_get_string<'a>(name: gl::types::GLenum) -> &'a str { - let v = unsafe { gl::GetString(name) }; - let v: &std::ffi::CStr = unsafe { std::ffi::CStr::from_ptr(v as *const i8) }; - v.to_str().unwrap() -} - fn glfw_handle_event(window: &mut glfw::Window, event: glfw::WindowEvent) { use glfw::Action; use glfw::Key; diff --git a/librashader-runtime-gl/tests/hello_triangle/mod.rs b/librashader-runtime-gl/tests/hello_triangle/mod.rs index 1cd16ba..753c71d 100644 --- a/librashader-runtime-gl/tests/hello_triangle/mod.rs +++ b/librashader-runtime-gl/tests/hello_triangle/mod.rs @@ -1,2 +1,51 @@ +use glow::HasContext; + pub mod gl3; pub mod gl46; + +pub fn compile_program(gl: &glow::Context, vertex: &str, fragment: &str) -> glow::Program { + let vertex_shader = unsafe { gl.create_shader(glow::VERTEX_SHADER).unwrap() }; + unsafe { + gl.shader_source(vertex_shader, &vertex); + gl.compile_shader(vertex_shader); + + if !gl.get_shader_compile_status(vertex_shader) { + let error = gl.get_shader_info_log(vertex_shader); + panic!("Vertex Shader Compile Error: {error}",); + } + } + + let fragment_shader = unsafe { gl.create_shader(glow::FRAGMENT_SHADER).unwrap() }; + unsafe { + gl.shader_source(fragment_shader, &fragment); + gl.compile_shader(fragment_shader); + + if !gl.get_shader_compile_status(fragment_shader) { + let error = gl.get_shader_info_log(fragment_shader); + panic!("Fragment Shader Compile Error: {error}",); + } + } + + let shader_program = unsafe { gl.create_program().unwrap() }; + unsafe { + gl.attach_shader(shader_program, vertex_shader); + gl.attach_shader(shader_program, fragment_shader); + gl.link_program(shader_program); + + if !gl.get_program_link_status(shader_program) { + let error = gl.get_program_info_log(shader_program); + panic!("Program Link Error: {error}",); + } + + gl.detach_shader(shader_program, vertex_shader); + gl.detach_shader(shader_program, fragment_shader); + gl.delete_shader(vertex_shader); + gl.delete_shader(fragment_shader); + } + + shader_program +} + +fn debug_callback(_source: u32, _err_type: u32, _id: u32, _severity: u32, message: &str) { + println!("[gl] {message:?}"); +} diff --git a/librashader-runtime-gl/tests/triangle.rs b/librashader-runtime-gl/tests/triangle.rs index 559493b..39bec3c 100644 --- a/librashader-runtime-gl/tests/triangle.rs +++ b/librashader-runtime-gl/tests/triangle.rs @@ -2,14 +2,17 @@ mod hello_triangle; use librashader_runtime_gl::options::FilterChainOptionsGL; use librashader_runtime_gl::FilterChainGL; +use std::sync::Arc; #[test] fn triangle_gl() { - let (glfw, window, events, shader, vao) = hello_triangle::gl3::setup(); + let (glfw, window, events, shader, vao, context) = hello_triangle::gl3::setup(); unsafe { let mut filter = FilterChainGL::load_from_path( - "../test/shaders_slang/test/feedback.slangp", + Arc::clone(&context), + // "../test/basic.slangp", + "../test/shaders_slang/crt/crt-royale.slangp", Some(&FilterChainOptionsGL { glsl_version: 0, use_dsa: false, @@ -19,21 +22,23 @@ fn triangle_gl() { ) // FilterChain::load_from_path("../test/slang-shaders/bezel/Mega_Bezel/Presets/MBZ__0__SMOOTH-ADV.slangp", None) .unwrap(); - hello_triangle::gl3::do_loop(glfw, window, events, shader, vao, &mut filter); + hello_triangle::gl3::do_loop(&context, glfw, window, events, shader, vao, &mut filter); } } #[test] fn triangle_gl46() { - let (glfw, window, events, shader, vao) = hello_triangle::gl46::setup(); + let (glfw, window, events, shader, vao, context) = hello_triangle::gl46::setup(); unsafe { let mut filter = FilterChainGL::load_from_path( + Arc::clone(&context), // "../test/slang-shaders/vhs/VHSPro.slangp", // "../test/slang-shaders/test/history.slangp", - // "../test/shaders_slang/crt/crt-royale.slangp", - "../test/shaders_slang/bezel/Mega_Bezel/Presets/MBZ__0__SMOOTH-ADV.slangp", + // "../test/basic.slangp", + "../test/shaders_slang/crt/crt-royale.slangp", + // "../test/shadersslang/bezel/Mega_Bezel/Presets/MBZ__0__SMOOTH-ADV.slangp", Some(&FilterChainOptionsGL { - glsl_version: 0, + glsl_version: 330, use_dsa: true, force_no_mipmaps: false, disable_cache: false, @@ -41,6 +46,6 @@ fn triangle_gl46() { ) // FilterChain::load_from_path("../test/slang-shaders/bezel/Mega_Bezel/Presets/MBZ__0__SMOOTH-ADV.slangp", None) .unwrap(); - hello_triangle::gl46::do_loop(glfw, window, events, shader, vao, &mut filter); + hello_triangle::gl46::do_loop(&context, glfw, window, events, shader, vao, &mut filter); } } diff --git a/librashader-runtime/src/ringbuffer.rs b/librashader-runtime/src/ringbuffer.rs index 7fd5635..a07d434 100644 --- a/librashader-runtime/src/ringbuffer.rs +++ b/librashader-runtime/src/ringbuffer.rs @@ -50,6 +50,15 @@ where index: 0, } } +} + +impl InlineRingBuffer +where + T: Copy, +{ + pub fn from_array(items: [T; SIZE]) -> Self { + Self { items, index: 0 } + } /// Get a borrow to all the items in this ring buffer. pub fn items(&self) -> &[T; SIZE] {