gl46: implement DSA version of gl runtime

This commit is contained in:
chyyran 2022-11-28 18:56:35 -05:00
parent 7b2721aa19
commit 5078015605
12 changed files with 157 additions and 190 deletions

View file

@ -13,6 +13,7 @@
<sourceFolder url="file://$MODULE_DIR$/librashader-compiler/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/librashader-common/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/librashader-runtime-d3d11/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/librashader-runtime-gl46/src" isTestSource="false" />
<excludeFolder url="file://$MODULE_DIR$/target" />
</content>
<orderEntry type="inheritedJdk" />

17
Cargo.lock generated
View file

@ -418,6 +418,7 @@ dependencies = [
"librashader-reflect",
"librashader-runtime-d3d11",
"librashader-runtime-gl",
"librashader-runtime-gl46",
]
[[package]]
@ -496,6 +497,22 @@ dependencies = [
"thiserror",
]
[[package]]
name = "librashader-runtime-gl46"
version = "0.1.0"
dependencies = [
"bytemuck",
"gl",
"glfw",
"librashader-common",
"librashader-preprocess",
"librashader-presets",
"librashader-reflect",
"rustc-hash",
"spirv_cross",
"thiserror",
]
[[package]]
name = "lock_api"
version = "0.4.9"

View file

@ -7,4 +7,5 @@ members = [
"librashader-reflect",
"librashader-runtime-d3d11",
"librashader-runtime-gl",
"librashader-runtime-gl46",
]

View file

@ -9,12 +9,13 @@ librashader (*/ˈli:brəʃeɪdɚ/*) is a preprocessor, compiler, and runtime for
Heavily WIP.
## Supported Render APIs
librashader supports OpenGL 3, Vulkan, DirectX 11, and DirectX 12. Support is WIP for all runtimes except OpenGL 3. Older versions
librashader supports OpenGL 3, OpenGL 4.6, Vulkan, DirectX 11, and DirectX 12. Support is WIP for all runtimes except OpenGL 3. Older versions
of DirectX and OpenGL, as well as Metal, are not supported (but pull-requests are welcome).
| **API** | **Status** | **`librashader` feature** |
|-------------|------------|---------------------------|
| OpenGL 3.3+ | ✔ | `gl` |
| OpenGL 4.6 | ✔ | `gl46` |
| Vulkan | 🚧 | `vk` |
| Direct3D11 | 🚧 | `d3d11` |
| Direct3D12 | 🚧 | `d3d12` |
@ -54,11 +55,17 @@ Please report an issue if you run into a shader that works in RetroArch, but not
* Sampler objects are used rather than `glTexParameter`.
* Sampler inputs and outputs are not renamed. This is useful for debugging shaders in RenderDoc.
* UBO and Push Constant Buffer sizes are padded to 16-byte boundaries.
*
* OpenGL 4.6+
* All caveats from the OpenGL 3.3+ section should be considered.
* Should work on OpenGL 4.5 but this is not guaranteed. The OpenGL 4.6 runtime may eventually switch to using `ARB_spirv_extensions` for loading shaders, and this will not be marked as a breaking change.
* The OpenGL 4.6 runtime uses Direct State Access to minimize changes to the OpenGL state. For recent GPUs, this may improve performance.
* Direct3D 11
* The staging buffer is not kept around when loading static textures (LUTs).
* HDR10 support is not part of the shader runtime and is not supported.
Most, if not all shader presets should work fine on librashader. The runtime specific differences should not affect the output,
and are more a heads-up for integrating librashader into your project.
## License
The core parts of librashader such as the preprocessor, the preset parser,
the reflection library, and the runtimes, are all licensed under the Mozilla Public License version 2.0.

View file

@ -183,6 +183,7 @@ impl FilterPass {
}
unsafe {
// can't use framebuffer.clear because it will unbind.
gl::ColorMask(gl::TRUE, gl::TRUE, gl::TRUE, gl::TRUE);
gl::ClearColor(0.0f32, 0.0f32, 0.0f32, 0.0f32);
gl::Clear(gl::COLOR_BUFFER_BIT);

View file

@ -29,7 +29,7 @@ use crate::texture::Texture;
pub struct FilterChain {
passes: Box<[FilterPass]>,
common: FilterCommon,
filter_vao: GLuint,
pub(crate) draw_quad: DrawQuad,
output_framebuffers: Box<[Framebuffer]>,
feedback_framebuffers: Box<[Framebuffer]>,
history_framebuffers: VecDeque<Framebuffer>,
@ -43,7 +43,6 @@ pub struct FilterCommon {
pub output_textures: Box<[Texture]>,
pub feedback_textures: Box<[Texture]>,
pub history_textures: Box<[Texture]>,
pub(crate) draw_quad: DrawQuad,
}
pub struct FilterMutable {
@ -177,17 +176,12 @@ impl FilterChain {
// create VBO objects
let draw_quad = DrawQuad::new();
let mut filter_vao = 0;
unsafe {
gl::GenVertexArrays(1, &mut filter_vao);
}
Ok(FilterChain {
passes: filters,
output_framebuffers: output_framebuffers.into_boxed_slice(),
feedback_framebuffers: feedback_framebuffers.into_boxed_slice(),
history_framebuffers,
filter_vao,
draw_quad,
common: FilterCommon {
config: FilterMutable {
passes_enabled: preset.shader_count as usize,
@ -199,7 +193,6 @@ impl FilterChain {
output_textures: output_textures.into_boxed_slice(),
feedback_textures: feedback_textures.into_boxed_slice(),
history_textures,
draw_quad,
},
})
}
@ -279,6 +272,15 @@ impl FilterChain {
fn load_luts(textures: &[TextureConfig]) -> Result<FxHashMap<usize, Texture>> {
let mut luts = FxHashMap::default();
let pixel_unpack = unsafe {
let mut binding = 0;
gl::GetIntegerv(gl::PIXEL_UNPACK_BUFFER_BINDING, &mut binding);
binding
};
unsafe {
gl::BindBuffer(gl::PIXEL_UNPACK_BUFFER, 0);
}
for (index, texture) in textures.iter().enumerate() {
let image = Image::load(&texture.path)?;
@ -290,10 +292,10 @@ impl FilterChain {
let mut handle = 0;
unsafe {
gl::GenTextures(1, &mut handle);
gl::BindTexture(gl::TEXTURE_2D, handle);
gl::TexStorage2D(
gl::TEXTURE_2D,
gl::CreateTextures(gl::TEXTURE_2D,1, &mut handle);
gl::TextureStorage2D(
handle,
levels as GLsizei,
gl::RGBA8,
image.size.width as GLsizei,
@ -302,12 +304,10 @@ impl FilterChain {
gl::PixelStorei(gl::UNPACK_ROW_LENGTH, 0);
gl::PixelStorei(gl::UNPACK_ALIGNMENT, 4);
gl::BindBuffer(gl::PIXEL_UNPACK_BUFFER, 0);
gl::TexSubImage2D(
gl::TEXTURE_2D,
0,
0,
0,
gl::TextureSubImage2D(
handle,
0, 0, 0,
image.size.width as GLsizei,
image.size.height as GLsizei,
gl::RGBA,
@ -317,10 +317,8 @@ impl FilterChain {
let mipmap = levels > 1;
if mipmap {
gl::GenerateMipmap(gl::TEXTURE_2D);
gl::GenerateTextureMipmap(handle);
}
gl::BindTexture(gl::TEXTURE_2D, 0);
}
luts.insert(
@ -338,6 +336,10 @@ impl FilterChain {
},
);
}
unsafe {
gl::BindBuffer(gl::PIXEL_UNPACK_BUFFER, pixel_unpack as GLuint);
};
Ok(luts)
}
@ -416,17 +418,15 @@ impl FilterChain {
let size = ubo.size;
let mut ring: InlineRingBuffer<GLuint, 16> = InlineRingBuffer::new();
unsafe {
gl::GenBuffers(16, ring.items_mut().as_mut_ptr());
gl::CreateBuffers(16, ring.items_mut().as_mut_ptr());
for buffer in ring.items() {
gl::BindBuffer(gl::UNIFORM_BUFFER, *buffer);
gl::BufferData(
gl::UNIFORM_BUFFER,
gl::NamedBufferData(
*buffer,
size as GLsizeiptr,
std::ptr::null(),
gl::STREAM_DRAW,
);
}
gl::BindBuffer(gl::UNIFORM_BUFFER, 0);
}
Some(ring)
} else {
@ -593,11 +593,9 @@ impl FilterChain {
return Ok(());
}
unsafe {
// do not need to rebind FBO 0 here since first `draw` will
// bind automatically.
gl::BindVertexArray(self.filter_vao);
}
// do not need to rebind FBO 0 here since first `draw` will
// bind automatically.
self.draw_quad.bind_vao();
let filter = passes[0].config.filter;
let wrap_mode = passes[0].config.wrap_mode;
@ -710,10 +708,9 @@ impl FilterChain {
self.push_history(input)?;
// pass.draw should return framebuffer bound to 0.
unsafe {
gl::BindVertexArray(0);
}
// do not need to rebind FBO 0 here since first `draw` will
// bind automatically.
self.draw_quad.unbind_vao();
Ok(())
}

View file

@ -104,9 +104,7 @@ impl FilterPass {
fn bind_texture(samplers: &SamplerSet, binding: &TextureBinding, texture: &Texture) {
unsafe {
// eprintln!("setting {} to texunit {}", texture.image.handle, binding.binding);
gl::ActiveTexture(gl::TEXTURE0 + binding.binding);
gl::BindTexture(gl::TEXTURE_2D, texture.image.handle);
gl::BindTextureUnit(binding.binding, texture.image.handle);
gl::BindSampler(binding.binding,
samplers.get(texture.wrap_mode, texture.filter, texture.mip_filter));
}
@ -137,7 +135,7 @@ impl FilterPass {
let framebuffer = output.framebuffer;
unsafe {
gl::BindFramebuffer(gl::FRAMEBUFFER, framebuffer.handle);
// gl::BindFramebuffer(gl::FRAMEBUFFER, framebuffer.handle);
gl::UseProgram(self.program);
}
@ -162,14 +160,12 @@ impl FilterPass {
let buffer = ring.current();
unsafe {
gl::BindBuffer(gl::UNIFORM_BUFFER, *buffer);
gl::BufferSubData(
gl::UNIFORM_BUFFER,
gl::NamedBufferSubData(
*buffer,
0,
size as GLsizeiptr,
self.uniform_buffer.as_ptr().cast(),
);
gl::BindBuffer(gl::UNIFORM_BUFFER, 0);
if self.ubo_location.vertex != gl::INVALID_INDEX {
gl::BindBufferBase(gl::UNIFORM_BUFFER, self.ubo_location.vertex, *buffer);
@ -183,10 +179,9 @@ impl FilterPass {
}
unsafe {
gl::ColorMask(gl::TRUE, gl::TRUE, gl::TRUE, gl::TRUE);
gl::ClearColor(0.0f32, 0.0f32, 0.0f32, 0.0f32);
gl::Clear(gl::COLOR_BUFFER_BIT);
//
// can use because DSA
framebuffer.clear();
gl::BindFramebuffer(gl::FRAMEBUFFER, framebuffer.handle);
gl::Viewport(
output.x,
output.y,
@ -204,36 +199,7 @@ impl FilterPass {
gl::Disable(gl::BLEND);
gl::Disable(gl::DEPTH_TEST);
gl::EnableVertexAttribArray(0);
gl::EnableVertexAttribArray(1);
gl::BindBuffer(gl::ARRAY_BUFFER, parent.draw_quad.vbo);
// 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(
0,
2,
gl::FLOAT,
gl::FALSE,
(4 * std::mem::size_of::<f32>()) as GLsizei,
std::ptr::invalid(0),
);
gl::VertexAttribPointer(
1,
2,
gl::FLOAT,
gl::FALSE,
(4 * std::mem::size_of::<f32>()) as GLsizei,
std::ptr::invalid(2 * std::mem::size_of::<f32>()),
);
gl::DrawArrays(gl::TRIANGLE_STRIP, 0, 4);
gl::BindBuffer(gl::ARRAY_BUFFER, 0);
gl::DisableVertexAttribArray(0);
gl::DisableVertexAttribArray(1);
gl::Disable(gl::FRAMEBUFFER_SRGB);
gl::BindFramebuffer(gl::FRAMEBUFFER, 0);
}
@ -483,12 +449,12 @@ impl FilterPass {
// bind float parameters
for (id, (location, offset)) in
self.uniform_bindings
.iter()
.filter_map(|(binding, value)| match binding {
UniformBinding::Parameter(id) => Some((id, value)),
_ => None,
})
self.uniform_bindings
.iter()
.filter_map(|(binding, value)| match binding {
UniformBinding::Parameter(id) => Some((id, value)),
_ => None,
})
{
let id = id.as_str();
let (buffer, offset) = match offset {

View file

@ -21,9 +21,7 @@ impl Framebuffer {
pub fn new(max_levels: u32) -> Framebuffer {
let mut framebuffer = 0;
unsafe {
gl::GenFramebuffers(1, &mut framebuffer);
gl::BindFramebuffer(gl::FRAMEBUFFER, framebuffer);
gl::BindFramebuffer(gl::FRAMEBUFFER, 0);
gl::CreateFramebuffers(1, &mut framebuffer);
}
Framebuffer {
@ -139,11 +137,9 @@ impl Framebuffer {
pub(crate) fn clear(&self) {
unsafe {
gl::BindFramebuffer(gl::FRAMEBUFFER, self.handle);
gl::ColorMask(gl::TRUE, gl::TRUE, gl::TRUE, gl::TRUE);
gl::ClearColor(0.0, 0.0, 0.0, 0.0);
gl::Clear(gl::COLOR_BUFFER_BIT);
gl::BindFramebuffer(gl::FRAMEBUFFER, 0);
gl::ClearNamedFramebufferfv(self.handle,
gl::COLOR, 0,
[0.0f32, 0.0, 0.0, 0.0].as_ptr().cast());
}
}
@ -154,64 +150,15 @@ impl Framebuffer {
}
unsafe {
gl::BindFramebuffer(gl::FRAMEBUFFER, self.handle);
// gl::NamedFramebufferDrawBuffer(self.handle, gl::COLOR_ATTACHMENT1);
gl::NamedFramebufferReadBuffer(image.handle, gl::COLOR_ATTACHMENT0);
gl::NamedFramebufferDrawBuffer(self.handle, gl::COLOR_ATTACHMENT1);
gl::FramebufferTexture2D(
gl::READ_FRAMEBUFFER,
gl::COLOR_ATTACHMENT0,
gl::TEXTURE_2D,
image.handle,
0,
);
gl::BlitNamedFramebuffer(image.handle, self.handle,
0, 0, image.size.width as GLint, image.size.height as GLint,
0, 0, self.size.width as GLint, self.size.height as GLint,
gl::COLOR_BUFFER_BIT, gl::NEAREST);
gl::FramebufferTexture2D(
gl::DRAW_FRAMEBUFFER,
gl::COLOR_ATTACHMENT1,
gl::TEXTURE_2D,
self.image,
0,
);
gl::DrawBuffer(gl::COLOR_ATTACHMENT1);
gl::BlitFramebuffer(
0,
0,
self.size.width as GLint,
self.size.height as GLint,
0,
0,
self.size.width as GLint,
self.size.height as GLint,
gl::COLOR_BUFFER_BIT,
gl::NEAREST,
);
// cleanup after ourselves.
gl::FramebufferTexture2D(
gl::READ_FRAMEBUFFER,
gl::COLOR_ATTACHMENT0,
gl::TEXTURE_2D,
0,
0,
);
gl::FramebufferTexture2D(
gl::DRAW_FRAMEBUFFER,
gl::COLOR_ATTACHMENT1,
gl::TEXTURE_2D,
0,
0,
);
// set this back to color_attachment 0
gl::FramebufferTexture2D(
gl::FRAMEBUFFER,
gl::COLOR_ATTACHMENT0,
gl::TEXTURE_2D,
self.image,
0,
);
gl::BindFramebuffer(gl::FRAMEBUFFER, 0);
}
Ok(())
@ -225,22 +172,18 @@ impl Framebuffer {
self.size = size;
unsafe {
gl::BindFramebuffer(gl::FRAMEBUFFER, self.handle);
// reset the framebuffer image
if self.image != 0 {
gl::FramebufferTexture2D(
gl::FRAMEBUFFER,
gl::NamedFramebufferTexture(
self.handle,
gl::COLOR_ATTACHMENT0,
gl::TEXTURE_2D,
0,
0,
);
gl::DeleteTextures(1, &self.image);
}
gl::GenTextures(1, &mut self.image);
gl::BindTexture(gl::TEXTURE_2D, self.image);
gl::CreateTextures(gl::TEXTURE_2D,1, &mut self.image);
if size.width == 0 {
size.width = 1;
@ -257,18 +200,17 @@ impl Framebuffer {
self.levels = 1;
}
gl::TexStorage2D(
gl::TEXTURE_2D,
gl::TextureStorage2D(
self.image,
self.levels as GLsizei,
self.format,
size.width as GLsizei,
size.height as GLsizei,
);
gl::FramebufferTexture2D(
gl::FRAMEBUFFER,
gl::NamedFramebufferTexture(
self.handle,
gl::COLOR_ATTACHMENT0,
gl::TEXTURE_2D,
self.image,
0,
);
@ -279,16 +221,14 @@ impl Framebuffer {
gl::FRAMEBUFFER_UNSUPPORTED => {
eprintln!("unsupported fbo");
gl::FramebufferTexture2D(
gl::FRAMEBUFFER,
gl::NamedFramebufferTexture(
self.handle,
gl::COLOR_ATTACHMENT0,
gl::TEXTURE_2D,
0,
0,
);
gl::DeleteTextures(1, &self.image);
gl::GenTextures(1, &mut self.image);
gl::BindTexture(1, self.image);
gl::CreateTextures(gl::TEXTURE_2D, 1, &mut self.image);
self.levels = util::calc_miplevel(size);
if self.levels > self.max_levels {
@ -298,17 +238,16 @@ impl Framebuffer {
self.levels = 1;
}
gl::TexStorage2D(
gl::TEXTURE_2D,
gl::TextureStorage2D(
self.image,
self.levels as GLsizei,
ShaderFormat::R8G8B8A8Unorm.into(),
size.width as GLsizei,
size.height as GLsizei,
);
gl::FramebufferTexture2D(
gl::FRAMEBUFFER,
gl::NamedFramebufferTexture(
self.handle,
gl::COLOR_ATTACHMENT0,
gl::TEXTURE_2D,
self.image,
0,
);
@ -318,9 +257,6 @@ impl Framebuffer {
_ => return Err(FilterChainError::FramebufferInit(status))
}
}
gl::BindFramebuffer(gl::FRAMEBUFFER, 0);
gl::BindTexture(gl::TEXTURE_2D, 0);
}
Ok(())

View file

@ -12,7 +12,7 @@ use crate::framebuffer::{Framebuffer, GlImage, Viewport};
const WIDTH: u32 = 900;
const HEIGHT: u32 = 700;
const TITLE: &str = "librashader OpenGL";
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) };
@ -215,7 +215,7 @@ void main()
gl::ObjectLabel(gl::VERTEX_ARRAY, vao, -1, b"triangle_vao\0".as_ptr().cast());
gl::VertexArrayVertexBuffer(vao, 0,
vbo, 0, (6 * std::mem::size_of::<f32>()) as GLint
vbo, 0, 6 * std::mem::size_of::<f32>() as GLint
);
gl::EnableVertexArrayAttrib(vao, 0); // this is "layout (location = 0)" in vertex shader
@ -226,7 +226,7 @@ void main()
gl::EnableVertexArrayAttrib(vao, 1);
gl::VertexArrayAttribFormat(vao, 1, 3,
gl::FLOAT, gl::FALSE, (3 * std::mem::size_of::<f32>() as GLuint));
gl::FLOAT, gl::FALSE, 3 * std::mem::size_of::<f32>() as GLuint);
gl::VertexArrayAttribBinding(vao, 0, 0);
@ -461,13 +461,11 @@ void main()
unsafe {
// render to fb
gl::ClearNamedFramebufferfv(rendered_framebuffer, gl::COLOR, 0, [0.3f32, 0.4, 0.6, 1.0].as_ptr().cast());
gl::BindFramebuffer(gl::FRAMEBUFFER, 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);
// do the drawing
gl::UseProgram(triangle_program);
// select vertices

View file

@ -1,4 +1,4 @@
use gl::types::{GLsizeiptr, GLuint};
use gl::types::{GLint, GLsizei, GLsizeiptr, GLuint};
#[rustfmt::skip]
static QUAD_VBO_DATA: &[f32; 16] = &[
@ -9,24 +9,55 @@ static QUAD_VBO_DATA: &[f32; 16] = &[
];
pub struct DrawQuad {
pub vbo: GLuint,
vbo: GLuint,
vao: GLuint,
}
impl DrawQuad {
pub fn new() -> DrawQuad {
let mut vbo = 0;
let mut vao = 0;
unsafe {
gl::GenBuffers(1, &mut vbo);
gl::BindBuffer(gl::ARRAY_BUFFER, vbo);
gl::BufferData(
gl::ARRAY_BUFFER,
gl::CreateBuffers(1, &mut vbo);
gl::NamedBufferData(
vbo,
std::mem::size_of_val(QUAD_VBO_DATA) as GLsizeiptr,
QUAD_VBO_DATA.as_ptr().cast(),
gl::STATIC_DRAW,
);
gl::BindBuffer(gl::ARRAY_BUFFER, 0);
gl::CreateVertexArrays(1, &mut vao);
gl::EnableVertexArrayAttrib(vao, 0);
gl::EnableVertexArrayAttrib(vao, 1);
gl::VertexArrayVertexBuffer(vao, 0,
vbo, 0, 4 * std::mem::size_of::<f32>() as GLint
);
gl::VertexArrayAttribFormat(vao, 0, 2,
gl::FLOAT, gl::FALSE, 0);
gl::VertexArrayAttribFormat(vao, 1, 2,
gl::FLOAT, gl::FALSE,
2 * std::mem::size_of::<f32>() as GLuint);
gl::VertexArrayAttribBinding(vao, 0, 0);
gl::VertexArrayAttribBinding(vao, 1, 0);
}
DrawQuad { vbo }
DrawQuad { vbo, vao }
}
pub fn bind_vao(&self) {
unsafe {
gl::BindVertexArray(self.vao);
}
}
pub fn unbind_vao(&self) {
unsafe {
gl::BindVertexArray(0);
}
}
}

View file

@ -11,6 +11,7 @@ librashader-preprocess = { path = "../librashader-preprocess" }
librashader-reflect = { path = "../librashader-reflect" }
librashader-runtime-d3d11 = { path = "../librashader-runtime-d3d11" }
librashader-runtime-gl = { path = "../librashader-runtime-gl" }
librashader-runtime-gl46 = { path = "../librashader-runtime-gl46" }
[features]

View file

@ -27,7 +27,7 @@ pub mod reflect {
}
pub mod targets {
/// Shader compiler targets and runtime for OpenGL.
/// Shader compiler targets and runtime for OpenGL 3.3+.
pub mod gl {
/// Shader compiler target for GLSL.
pub use librashader_reflect::back::targets::GLSL;
@ -38,6 +38,17 @@ pub mod targets {
}
}
/// Shader compiler targets and runtime for OpenGL 4.6.
pub mod gl46 {
/// Shader compiler target for GLSL.
pub use librashader_reflect::back::targets::GLSL;
/// Shader runtime for OpenGL.
pub mod runtime {
pub use librashader_runtime_gl46::*;
}
}
/// Shader compiler targets and runtime for DirectX.
pub mod dx {
/// Shader compiler target for HLSL.