-
Notifications
You must be signed in to change notification settings - Fork 543
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Find a solution for shader language support #71
Comments
One idea is to just query for the backend in use and have the user themselves supply a shader per API. |
Another is to use a single shader language and translate to whatever the backend needs. HLSL might be a mature choice here. (Valve has a tool available but I'm not sure how quality it is, and it only supports Shader Model 3.) |
Another is to make our own shading language, but that just sounds like a bad idea. |
A HM typed concatenative language! jk. |
I'm currently toying around with a "umbrella" struct for providing the source of the same logical shader in different languages. Nothing fancy, something like this: pub enum DeviceShader {
StaticBytes(&'static [u8]),
OwnedBytes(Vec<u8>),
NotProvided
}
pub struct ShaderSource {
pub glsl_120: DeviceShader,
pub glsl_150: DeviceShader,
hlsl_sm_3: DeviceShader
...
}
...
static VERTEX_SRC: ShaderSource = shaders! {
GLSL_120: b"
#version 120
attribute vec2 a_Pos;
varying vec4 v_Color;
void main() {
v_Color = vec4(a_Pos+0.5, 1.0, 1.0);
gl_Position = vec4(a_Pos, 0.0, 1.0);
}
"
GLSL_150: b"
#version 150 core
in vec2 a_Pos;
out vec4 v_Color;
void main() {
v_Color = vec4(a_Pos+0.5, 0.0, 1.0);
gl_Position = vec4(a_Pos, 0.0, 1.0);
}
"
}; That should at least make it possible to hack some legacy compatibility into the libs without giving up on the newer shader versions at all. |
#72 gets us some of the way there. |
Found a good link for that: Cross Platform Shaders in 2014 |
I think what we have today is as good as we are going to get. Anything else can be built on top of it, externally, and possibly merged back in. |
Shaders become one of the major usability bottleneck of gfx-rs. Let's continue this discussion, even if the code for it will end up in a separate library. |
This might be worth looking at: https://github.com/kmcallister/glassful |
Something to also think about is whether we want to support recompiling of shaders at runtime. |
I would very much like that feature. |
Inspired by Glassful and @csherratt's example code from Reddit, I tried to develop it further. Here is an example of what I'd like to use (very roughly): /// uniforms
struct MyParams {
color: vec4,
}
/// vertex buffer 1
struct MyBuf1 {
pos: vec2,
}
/// vertex buffer 2
struct MyBuf2 {
tc: vec2,
}
let technique = glassful! {
struct Varying {
tc: vec2,
}
// @Position is a special vertex output, not sure if we can make it more sound
fn vertex(_params: MyParams, buf1: MyBuf1, buf2: MyBuf2) -> (@Position, Varying) {
(vec4(buf1.pos, 0.0, 1.0), Varying { tc: buf2.tc })
}
fn fragment(params: MyParams, _var: Varying) -> vec4 {
params.color
}
static pass0 = pass(vertex, fragment);
};
...
let program = device.link_program(&technique.pass0).unwrap(); The implementation doesn't seem trivial. Here are the biggest problems that I see:
Any ideas, feedback, suggestions - please let me know. |
I have been playing around with this a bit in rusterize. I'm not sure we even need @position, we could just require the vertex sharer to fill slot 0 of the tuple with the position. If it is not a // Placing a variable in a Flat<T> makes the compiler place a flat property around it for the fragment shader
fn vertex(_params: MyParams, buf1: MyBuf1, buf2: MyBuf2) -> (vec4, Flat<vec4>) {
(vec4(buf1.pos, 0.0, 1.0), buf2)
}
fn fragment(params: MyParams, (position, color): (vec4, vec4)) -> vec4 {
color
} This can be a bit hairy of you add to many varying: // Placing a variable in a Flat<T> makes the compiler place a flat property around it for the fragment shader
fn vertex(_params: MyParams, buf1: MyBuf1, buf2: MyBuf2) -> (vec4, vec3, vec2) {
(vec4(buf1.pos, 0.0, 1.0), buf1.normal, buf1.texture)
}
fn fragment(params: MyParams, (position, normal, color): (vec4, vec3, vec2)) -> vec4 {
color
} The strategy I have for I don't image traits are going to be a nice way to actually implement this for |
@csherratt so your vertex output position is implicit. We can't extend this approach to other special inputs/outputs, because many of them are optional (like. |
There are quite a few you are right: https://www.opengl.org/wiki/Built-in_Variable_%28GLSL%29 The idea of using custom types for these works well in my mind. If you add one to the tuple, output struct we can easily find it. I guess for input it would not be much harder, but we do lose a bit of the input struct is the output struct. |
Something from g-truck about SPIR-V: http://www.g-truc.net/post-0714.html |
I so really want Vulcan/SPIR-V now!!! |
Note that SPIR-V specification is available, so while we are not able to test anything, we could start writing a translator. |
Current state of the SPIR-V ecosystem:
With the upcoming Vulkan backend a SPIR-V based shader compilation pipeline (e.g. GLSL -> SPIR-V -> backend(+ metadata)) might be interesting. |
bgfx has a solution using a C preprocessor to generate HLSL and GLSL (and thus SPIR-V) from a GLSL-like language -- it might be worth looking into. See https://bkaradzic.github.io/bgfx/tools.html#shader-compiler-shaderc |
This initiative on 3d portability from the Khronos Group can be interesting: |
I've found an SPIR-V 1.1 implementation in rust: https://github.com/google/rspirv This would allow to easily create some macros to write shaders in rust that generate SPIR-V, and from there to the final shader language. For that last step, there is already an experimental tool: Update: Include the cross tool |
Experience from inspirv-rust: The goal of this project is/was to generate SPIR-V binaries from Rust via MIR. What worked: example
Issues:
Future possibilities: |
FWIW we want to fix these problems and ship a Cretonne backend within a year, hopefully. It'd be nice to have more discussions and organization on these issues, but we (the Rust compiler team) have been spread thin for a while and it's showing. |
@eddyb Thanks for chiming in! |
For structured CFG, the Relooper algorithm emscripten uses (used?) is probably a good starting point - not sure if SPIR-V is better than JS at this but at least it's still a CFG. |
triaged: still important to provide a nice shading language that would compile to SPIR-V, likely as a separate library. |
The ecosystem issue has been raised in rust-gamedev/wg#23 |
3445: [mtl] experimental Naga support r=grovesNL a=kvark First humble steps towards #71 ... Naga is an optional github dependency (obviously will need to be switched to crates upon release). If it fails, we fall back to spirv-cross. Extra steps are taking to ensure that shader modules compiled by Naga and SPIRV-Cross can still link together. PR checklist: - [x] `make` succeeds (on *nix) - [ ] `make reftests` succeeds - [x] tested examples with the following backends: Metal Co-authored-by: Dzmitry Malyshau <[email protected]>
71: Shadow example r=grovesNL a=kvark ~~I believe all the nuts and bolts are in place, just figuring out some details of making the shadow match between the rendering and sampling (hence the WIP).~~ Most importantly, this PR includes crucial fixes and improvements of our resource tracking, plus a few fixes in the bind group and texture creation code. Co-authored-by: Dzmitry Malyshau <[email protected]>
Different graphics APIs have their own shading languages or ideas for what a shading language should be. In our quest to support multiple backend APIs, we need a way to unify these.
The text was updated successfully, but these errors were encountered: