rt(gl): port to OpenGL runtime to glow
This commit is contained in:
parent
77b957bf5e
commit
1bdadaa449
18
Cargo.lock
generated
18
Cargo.lock
generated
|
@ -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",
|
||||
|
|
|
@ -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" }
|
||||
|
||||
|
|
|
@ -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 }
|
||||
|
||||
|
|
|
@ -1,71 +1,71 @@
|
|||
use crate::{FilterMode, ImageFormat, WrapMode};
|
||||
|
||||
impl From<ImageFormat> for gl::types::GLenum {
|
||||
impl From<ImageFormat> 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<WrapMode> for gl::types::GLenum {
|
||||
impl From<WrapMode> 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<FilterMode> for gl::types::GLenum {
|
||||
impl From<FilterMode> 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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -145,7 +145,7 @@ impl CompileShader<GLSL> for CrossReflect<targets::Glsl> {
|
|||
)?;
|
||||
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));
|
||||
}
|
||||
|
||||
|
|
|
@ -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"]
|
||||
|
||||
|
|
|
@ -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<UniformLocation<GLint>>,
|
||||
pub(crate) push: Option<UniformLocation<GLint>>,
|
||||
pub(crate) ubo: Option<UniformLocation<Option<glow::UniformLocation>>>,
|
||||
pub(crate) push: Option<UniformLocation<Option<glow::UniformLocation>>>,
|
||||
}
|
||||
|
||||
impl VariableLocation {
|
||||
pub fn location(&self, offset_type: UniformMemberBlock) -> Option<UniformLocation<GLint>> {
|
||||
pub fn location(
|
||||
&self,
|
||||
offset_type: UniformMemberBlock,
|
||||
) -> Option<UniformLocation<Option<glow::UniformLocation>>> {
|
||||
match offset_type {
|
||||
UniformMemberBlock::Ubo => self.ubo,
|
||||
UniformMemberBlock::PushConstant => self.push,
|
||||
|
@ -23,16 +27,13 @@ pub struct UniformLocation<T> {
|
|||
pub fragment: T,
|
||||
}
|
||||
|
||||
impl UniformLocation<GLint> {
|
||||
impl UniformLocation<Option<glow::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<GLint> {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) type GlUniformStorage = UniformStorage<GlUniformBinder, VariableLocation>;
|
||||
pub(crate) type GlUniformStorage =
|
||||
UniformStorage<GlUniformBinder, VariableLocation, Box<[u8]>, 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<T> BindUniform<VariableLocation, T, ()> for GlUniformBinder
|
||||
impl<T> BindUniform<VariableLocation, T, glow::Context> 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<VariableLocation, &[f32; 4], ()> for GlUniformBinder {
|
||||
impl BindUniform<VariableLocation, &[f32; 4], glow::Context> 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<VariableLocation, &[f32; 4], ()> 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<VariableLocation, &[f32; 4], ()> for GlUniformBinder {
|
|||
}
|
||||
}
|
||||
|
||||
impl BindUniform<VariableLocation, &[f32; 16], ()> for GlUniformBinder {
|
||||
impl BindUniform<VariableLocation, &[f32; 16], glow::Context> 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<VariableLocation, &[f32; 16], ()> 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(())
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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<T: GLInterface> {
|
||||
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<glow::Context>,
|
||||
}
|
||||
|
||||
impl<T: GLInterface> FilterChainImpl<T> {
|
||||
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<T: GLInterface> FilterChainImpl<T> {
|
|||
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<T: GLInterface> FilterChainImpl<T> {
|
|||
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<T: GLInterface> FilterChainImpl<T> {
|
|||
/// 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<Self> {
|
||||
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<T: GLInterface> FilterChainImpl<T> {
|
|||
.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<T: GLInterface> FilterChainImpl<T> {
|
|||
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<T: GLInterface> FilterChainImpl<T> {
|
|||
output_textures,
|
||||
feedback_textures,
|
||||
history_textures,
|
||||
context,
|
||||
},
|
||||
default_options: Default::default(),
|
||||
})
|
||||
}
|
||||
|
||||
fn init_passes(
|
||||
context: &glow::Context,
|
||||
version: GlslVersion,
|
||||
passes: Vec<ShaderPassMeta>,
|
||||
semantics: &ShaderSemantics,
|
||||
|
@ -208,10 +219,11 @@ impl<T: GLInterface> FilterChainImpl<T> {
|
|||
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<T: GLInterface> FilterChainImpl<T> {
|
|||
|
||||
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<T: GLInterface> FilterChainImpl<T> {
|
|||
|
||||
// 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<T: GLInterface> FilterChainImpl<T> {
|
|||
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<T: GLInterface> FilterChainImpl<T> {
|
|||
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<T: GLInterface> FilterChainImpl<T> {
|
|||
|
||||
self.push_history(input)?;
|
||||
|
||||
self.draw_quad.unbind_vertices();
|
||||
self.draw_quad.unbind_vertices(&self.common.context);
|
||||
|
||||
Ok(())
|
||||
}
|
|
@ -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<crate::gl::gl46::DirectStateAccessGL>),
|
||||
|
|
|
@ -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<Self> {
|
||||
|
@ -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<Path>,
|
||||
options: Option<&FilterChainOptionsGL>,
|
||||
) -> Result<Self> {
|
||||
// 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<glow::Context> {
|
||||
match &self.filter {
|
||||
FilterChainDispatch::DirectStateAccess(p) => &p.common.context,
|
||||
FilterChainDispatch::Compatibility(p) => &p.common.context,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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<T: GLInterface> {
|
||||
pub reflection: ShaderReflection,
|
||||
pub program: GLuint,
|
||||
pub ubo_location: UniformLocation<GLuint>,
|
||||
pub program: glow::Program,
|
||||
pub ubo_location: UniformLocation<Option<u32>>,
|
||||
pub ubo_ring: Option<T::UboRing>,
|
||||
pub(crate) uniform_storage: GlUniformStorage,
|
||||
pub uniform_bindings: FastHashMap<UniformBinding, UniformOffset>,
|
||||
|
@ -47,7 +47,7 @@ impl TextureInput for InputTexture {
|
|||
}
|
||||
}
|
||||
|
||||
impl ContextOffset<GlUniformBinder, VariableLocation> for UniformOffset {
|
||||
impl ContextOffset<GlUniformBinder, VariableLocation, glow::Context> for UniformOffset {
|
||||
fn offset(&self) -> MemberOffset {
|
||||
self.offset
|
||||
}
|
||||
|
@ -61,7 +61,7 @@ impl<T: GLInterface> BindSemantics<GlUniformBinder, VariableLocation> 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<T: GLInterface> BindSemantics<GlUniformBinder, VariableLocation> 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<T: GLInterface> FilterPass<T> {
|
|||
viewport: &Viewport<&GLFramebuffer>,
|
||||
original: &InputTexture,
|
||||
source: &InputTexture,
|
||||
output: RenderTarget<GLFramebuffer, GLint>,
|
||||
output: RenderTarget<GLFramebuffer, i32>,
|
||||
) {
|
||||
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<T: GLInterface> FilterPass<T> {
|
|||
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::<T::FramebufferInterface, false>();
|
||||
|
||||
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<T: GLInterface> FilterPass<T> {
|
|||
source: &InputTexture,
|
||||
) {
|
||||
Self::bind_semantics(
|
||||
&(),
|
||||
&parent.context,
|
||||
&parent.samplers,
|
||||
&mut self.uniform_storage,
|
||||
&mut (),
|
||||
|
|
|
@ -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<glow::Texture>,
|
||||
/// The format of the texture.
|
||||
pub format: GLenum,
|
||||
pub format: u32,
|
||||
/// The size of the texture.
|
||||
pub size: Size<u32>,
|
||||
}
|
||||
|
|
|
@ -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<glow::Texture>,
|
||||
pub(crate) fbo: glow::Framebuffer,
|
||||
pub(crate) size: Size<u32>,
|
||||
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<glow::Context>,
|
||||
}
|
||||
|
||||
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<glow::Context>,
|
||||
texture: Option<glow::Texture>,
|
||||
fbo: glow::Framebuffer,
|
||||
format: u32,
|
||||
size: Size<u32>,
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<String, CrossGlslContext>,
|
||||
_cache: bool,
|
||||
) -> crate::error::Result<(GLuint, UniformLocation<GLuint>)> {
|
||||
) -> error::Result<(glow::Program, UniformLocation<Option<u32>>)> {
|
||||
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"),
|
||||
},
|
||||
)
|
||||
};
|
||||
|
|
|
@ -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<Self> {
|
||||
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::<VertexInput>() as GLsizei,
|
||||
sptr::invalid(offset_of!(VertexInput, position)),
|
||||
glow::FLOAT,
|
||||
false,
|
||||
std::mem::size_of::<VertexInput>() 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::<VertexInput>() as GLsizei,
|
||||
sptr::invalid(offset_of!(VertexInput, texcoord)),
|
||||
glow::FLOAT,
|
||||
false,
|
||||
std::mem::size_of::<VertexInput>() 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)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
|
|
@ -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<glow::Context>, max_levels: u32) -> error::Result<GLFramebuffer> {
|
||||
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<u32>,
|
||||
source_size: &Size<u32>,
|
||||
original_size: &Size<u32>,
|
||||
mipmap: bool,
|
||||
) -> Result<Size<u32>> {
|
||||
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<const REBIND: bool>(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<u32>, format: impl Into<GLenum>) -> Result<()> {
|
||||
fn init(fb: &mut GLFramebuffer, mut size: Size<u32>, format: impl Into<u32>) -> 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(())
|
||||
|
|
|
@ -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<FastHashMap<usize, InputTexture>> {
|
||||
fn load_luts(
|
||||
ctx: &glow::Context,
|
||||
textures: &[TextureConfig],
|
||||
) -> Result<FastHashMap<usize, InputTexture>> {
|
||||
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)
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<const SIZE: usize> {
|
||||
ring: InlineRingBuffer<GLuint, SIZE>,
|
||||
ring: InlineRingBuffer<glow::Buffer, SIZE>,
|
||||
}
|
||||
|
||||
impl<const SIZE: usize> Gl3UboRing<SIZE> {
|
||||
const _ASSERT_TRANSMUTABLE: () = assert!(
|
||||
std::mem::size_of::<[glow::Buffer; SIZE]>()
|
||||
== std::mem::size_of::<[MaybeUninit<glow::Buffer>; SIZE]>()
|
||||
);
|
||||
}
|
||||
|
||||
impl<const SIZE: usize> UboRing<SIZE> for Gl3UboRing<SIZE> {
|
||||
fn new(buffer_size: u32) -> Self {
|
||||
let mut ring: InlineRingBuffer<GLuint, SIZE> = InlineRingBuffer::new();
|
||||
unsafe {
|
||||
gl::GenBuffers(SIZE as GLsizei, ring.items_mut().as_mut_ptr());
|
||||
for buffer in ring.items() {
|
||||
gl::BindBuffer(gl::UNIFORM_BUFFER, *buffer);
|
||||
gl::BufferData(
|
||||
gl::UNIFORM_BUFFER,
|
||||
buffer_size as GLsizeiptr,
|
||||
std::ptr::null(),
|
||||
gl::STREAM_DRAW,
|
||||
);
|
||||
fn new(ctx: &glow::Context, buffer_size: u32) -> error::Result<Self> {
|
||||
// TODO: array::try_from_fn whenever that gets stabilized
|
||||
// this is basically blocking on try_trait_v2
|
||||
let mut items: [MaybeUninit<glow::Buffer>; 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<glow::Buffer> and glow::Buffer have the same size.
|
||||
let items: [glow::Buffer; SIZE] = unsafe { std::mem::transmute_copy(&items) };
|
||||
|
||||
let ring: InlineRingBuffer<glow::Buffer, SIZE> = InlineRingBuffer::from_array(items);
|
||||
|
||||
Ok(Gl3UboRing { ring })
|
||||
}
|
||||
|
||||
fn bind_for_frame(
|
||||
&mut self,
|
||||
ctx: &glow::Context,
|
||||
ubo: &BufferReflection<u32>,
|
||||
ubo_location: &UniformLocation<GLuint>,
|
||||
ubo_location: &UniformLocation<Option<u32>>,
|
||||
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()
|
||||
|
|
|
@ -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<u8>,
|
||||
format: GLuint,
|
||||
}
|
||||
struct GlProgramBinary(Option<glow::ProgramBinary>);
|
||||
|
||||
impl Cacheable for GlProgramBinary {
|
||||
fn from_bytes(cached: &[u8]) -> Option<Self>
|
||||
|
@ -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::<u32>());
|
||||
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<Vec<u8>> {
|
||||
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<String, CrossGlslContext>,
|
||||
cache: bool,
|
||||
) -> crate::error::Result<(GLuint, UniformLocation<GLuint>)> {
|
||||
let vertex_resources = glsl.context.artifact.vertex.shader_resources()?;
|
||||
) -> crate::error::Result<(glow::Program, UniformLocation<Option<u32>>)> {
|
||||
fn compile_shader(
|
||||
context: &glow::Context,
|
||||
resources: &CrossGlslContext,
|
||||
vertex: &str,
|
||||
fragment: &str,
|
||||
) -> crate::error::Result<glow::Program> {
|
||||
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"),
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -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<Self> {
|
||||
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::<VertexInput>() as GLint,
|
||||
std::mem::size_of::<VertexInput>() 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<glow::Context>, max_levels: u32) -> error::Result<GLFramebuffer> {
|
||||
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<u32>,
|
||||
source_size: &Size<u32>,
|
||||
original_size: &Size<u32>,
|
||||
mipmap: bool,
|
||||
) -> Result<Size<u32>> {
|
||||
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<const REBIND: bool>(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<u32>, format: impl Into<GLenum>) -> Result<()> {
|
||||
fn init(fb: &mut GLFramebuffer, mut size: Size<u32>, format: impl Into<u32>) -> 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)),
|
||||
}
|
||||
|
|
|
@ -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<FastHashMap<usize, InputTexture>> {
|
||||
fn load_luts(
|
||||
context: &glow::Context,
|
||||
textures: &[TextureConfig],
|
||||
) -> Result<FastHashMap<usize, InputTexture>> {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<const SIZE: usize> {
|
||||
ring: InlineRingBuffer<GLuint, SIZE>,
|
||||
ring: InlineRingBuffer<glow::Buffer, SIZE>,
|
||||
}
|
||||
|
||||
impl<const SIZE: usize> Gl46UboRing<SIZE> {
|
||||
const _ASSERT_TRANSMUTABLE: () = assert!(
|
||||
std::mem::size_of::<[glow::Buffer; SIZE]>()
|
||||
== std::mem::size_of::<[MaybeUninit<glow::Buffer>; SIZE]>()
|
||||
);
|
||||
}
|
||||
|
||||
impl<const SIZE: usize> UboRing<SIZE> for Gl46UboRing<SIZE> {
|
||||
fn new(buffer_size: u32) -> Self {
|
||||
let mut ring: InlineRingBuffer<GLuint, SIZE> = InlineRingBuffer::new();
|
||||
unsafe {
|
||||
gl::CreateBuffers(SIZE as GLsizei, ring.items_mut().as_mut_ptr());
|
||||
for buffer in ring.items() {
|
||||
gl::NamedBufferData(
|
||||
*buffer,
|
||||
buffer_size as GLsizeiptr,
|
||||
std::ptr::null(),
|
||||
gl::STREAM_DRAW,
|
||||
);
|
||||
}
|
||||
};
|
||||
fn new(context: &glow::Context, buffer_size: u32) -> error::Result<Self> {
|
||||
// TODO: array::try_from_fn whenever that gets stabilized
|
||||
// this is basically blocking on try_trait_v2
|
||||
let mut items: [MaybeUninit<glow::Buffer>; 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<glow::Buffer, SIZE> = InlineRingBuffer::from_array(items);
|
||||
|
||||
Ok(Gl46UboRing { ring })
|
||||
}
|
||||
|
||||
fn bind_for_frame(
|
||||
&mut self,
|
||||
context: &glow::Context,
|
||||
ubo: &BufferReflection<u32>,
|
||||
ubo_location: &UniformLocation<GLuint>,
|
||||
ubo_location: &UniformLocation<Option<u32>>,
|
||||
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()
|
||||
|
|
|
@ -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<FastHashMap<usize, InputTexture>>;
|
||||
fn load_luts(
|
||||
context: &glow::Context,
|
||||
textures: &[TextureConfig],
|
||||
) -> Result<FastHashMap<usize, InputTexture>>;
|
||||
}
|
||||
|
||||
pub(crate) trait CompileProgram {
|
||||
fn compile_program(
|
||||
context: &glow::Context,
|
||||
shader: ShaderCompilerOutput<String, CrossGlslContext>,
|
||||
cache: bool,
|
||||
) -> Result<(GLuint, UniformLocation<GLuint>)>;
|
||||
) -> Result<(glow::Program, UniformLocation<Option<u32>>)>;
|
||||
}
|
||||
|
||||
pub(crate) trait DrawQuad {
|
||||
fn new() -> Self;
|
||||
fn bind_vertices(&self, quad_type: QuadType);
|
||||
fn unbind_vertices(&self);
|
||||
fn new(context: &glow::Context) -> Result<Self>
|
||||
where
|
||||
Self: Sized;
|
||||
fn bind_vertices(&self, context: &glow::Context, quad_type: QuadType);
|
||||
fn unbind_vertices(&self, context: &glow::Context);
|
||||
}
|
||||
|
||||
pub(crate) trait UboRing<const SIZE: usize> {
|
||||
fn new(buffer_size: u32) -> Self;
|
||||
fn new(context: &glow::Context, buffer_size: u32) -> Result<Self>
|
||||
where
|
||||
Self: Sized;
|
||||
fn bind_for_frame(
|
||||
&mut self,
|
||||
context: &glow::Context,
|
||||
ubo: &BufferReflection<u32>,
|
||||
ubo_location: &UniformLocation<GLuint>,
|
||||
ubo_location: &UniformLocation<Option<u32>>,
|
||||
storage: &impl UniformStorageAccess,
|
||||
);
|
||||
}
|
||||
|
||||
pub(crate) trait FramebufferInterface {
|
||||
fn new(max_levels: u32) -> GLFramebuffer;
|
||||
fn new(context: &Arc<glow::Context>, max_levels: u32) -> Result<GLFramebuffer>;
|
||||
fn scale(
|
||||
fb: &mut GLFramebuffer,
|
||||
scaling: Scale2D,
|
||||
|
@ -93,15 +103,48 @@ pub(crate) trait FramebufferInterface {
|
|||
source_size: &Size<u32>,
|
||||
original_size: &Size<u32>,
|
||||
mipmap: bool,
|
||||
) -> Result<Size<u32>>;
|
||||
) -> Result<Size<u32>> {
|
||||
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<const REBIND: bool>(fb: &GLFramebuffer);
|
||||
fn copy_from(fb: &mut GLFramebuffer, image: &GLImage) -> Result<()>;
|
||||
fn init(fb: &mut GLFramebuffer, size: Size<u32>, format: impl Into<GLenum>) -> Result<()>;
|
||||
fn init(fb: &mut GLFramebuffer, size: Size<u32>, format: impl Into<u32>) -> 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 {
|
||||
|
|
|
@ -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<SamplerSet> {
|
||||
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 })
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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<GLuint> {
|
||||
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<glow::Shader> {
|
||||
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,
|
||||
|
|
|
@ -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<u8> = 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<u8> = 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<u8> = 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<u8> = 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<glow::Context>,
|
||||
) {
|
||||
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::<f32>()) 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::<f32>()) 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::<f32>()) 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::<f32>()) as gl::types::GLint, // stride (byte offset between consecutive attributes)
|
||||
(3 * std::mem::size_of::<f32>()) 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::<f32>()) as i32, // stride (byte offset between consecutive attributes)
|
||||
(3 * std::mem::size_of::<f32>()) 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<glow::Context>,
|
||||
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::<f32>()) 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::<f32>()) 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;
|
||||
|
|
|
@ -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<u8> = 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<u8> = 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<u8> = 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<u8> = 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<glow::Context>,
|
||||
) {
|
||||
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::<f32>()) 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::<f32>() as GLint);
|
||||
gl.vertex_array_vertex_buffer(vao, 0, Some(vbo), 0, 6 * std::mem::size_of::<f32>() 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::<f32>() as GLuint,
|
||||
glow::FLOAT,
|
||||
false,
|
||||
3 * std::mem::size_of::<f32>() 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<glow::Context>,
|
||||
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::<f32>()) 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::<f32>()) 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;
|
||||
|
|
|
@ -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:?}");
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -50,6 +50,15 @@ where
|
|||
index: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, const SIZE: usize> InlineRingBuffer<T, SIZE>
|
||||
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] {
|
||||
|
|
Loading…
Reference in a new issue