hadronized / glsl

GLSL parser for Rust
191 stars 27 forks source link

Generate Type-Safe Bindings for OpenGL? #106

Closed TannerRogalsky closed 4 years ago

TannerRogalsky commented 4 years ago

I ask this question knowing that it's beyond the scope of this crate. It just seems like the best to ask in case someone else is wondering the same thing.

Is there a project to use this crate to generate type-safe bindings for communication with OpenGL shaders? If not, have you thought about if that is feasible/what that might look like?

I ask this because of your work on luminance-derive and on this crate. Thanks in advance!

hadronized commented 4 years ago

What do you have in mind exactly? I had, in cheddar and spectra, some stuff that would drive pipelines from shaders, but I gave up on that as it was really convoluted.

TannerRogalsky commented 4 years ago

I'm definitely more interested in a developer-facing interface generation than driving a pipeline (although I don't pretend they're completely separate). I'm going to try to make something rather than bikeshedding from a position of such limited experience in procedural macros. I'll request your thoughts when I have something that I think illustrates what I have in mind and you can feel free to comment or not. :D

hadronized commented 4 years ago

Sure I will! Feel free to share what you have on mind. What kind of bindings are you talking about?

And also, the more people use glsl, the happier I am. :slightly_smiling_face:

TannerRogalsky commented 4 years ago

Okay, I have something in place so I feel a little more comfortable commenting. The most basic thing that I think would still be useful is generating, from shader source, type-safe (and cached) bindings to uniforms.

Given something like this:

uniform mat4 projection;

I'd like to generate something like this:

struct MyShader {
    projection: [f32; 16],
    projection_location: u32,
}

impl MyShader {
    pub fn new() -> Self {
        // create & compile shader, get uniform locations, etc
    }
}

pub fn set_projection(&mut self, projection: [f32; 16]) {
    if self.projection != projection {
        unsafe { glUniformMatrix4fv(self.location, 1, false, projection.as_ptr()) }; 
        self.projection = projection;
    }
}

pub fn get_projection(&self) -> [f32; 16] {
    &self.projection
}

There's a lot left out of this. Ensuring this program is active, error handling, other stuff. But this, I think, is the core.

I don't think I'm settled on what the best fit for the macro is yet but this feels the best so far:

#[derive_shader(("./shader.vert", "./shader.frag"))]
struct ShaderTest;

All of this is far from settled but it seems eminently possible and would be useful at least to me.

Thoughts? Ideas? Suggestions?

hadronized commented 4 years ago

Ooookay, now I get it. That’s 100% possible, but that would depend on the backend.

For the last point, let me explain. I tend to see uniforms as a set of GPU variables exposed via a shader program to the host program (i.e. running on a CPU thread). The main problem is how we map from one to another. You have two possibilities:

Because I do a lot of data-oriented rendering, I prefer the second option as it’s more flexible, especially when you’re loading shaders on the fly. However, what you want might be useful too, yeah. I’m not sure how to make that backend-agnostic, though.

TannerRogalsky commented 4 years ago

You raise some good points. Particularly, I hadn't been thinking about source of truth and how that related to this prospect.

I still think it would be lovely to have more compile-time validation of GLSL (which, really, was the primary goal here) but as that relates to creating a Rust type around the bindings, I'm not sure it's even possible in the way I imagined it. That shaders are compiled at runtime and variables can be optimized away means that a type generated from the GLSL source wouldn't necessarily behave like you'd think.

The joys of OpenGL. :P

Thanks again for your insight and for this crate. This has been illuminating.