Skip to content
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

Sketch simple shaders #14

Closed
wants to merge 2 commits into from
Closed

Sketch simple shaders #14

wants to merge 2 commits into from

Conversation

Jasper-Bekkers
Copy link
Contributor

@Jasper-Bekkers Jasper-Bekkers commented Aug 19, 2020

These are GLSL shaders we're using in Ark and versions converted into pseudo-rust.

I didn't touch on bindings yet, because I think that'll be something we can debate endlessly about.

This uses a glam-rs inspired math library since it seems most likely that we'll use something like that.

None of this compiles / builds, but it should give a bit of an overview of how these shaders will end up looking. I think many things can be improved so I'll go through and comment on a bunch of things.

Part of #4

Comment on lines +63 to +71
fn degamma(v: Vec4) -> Vec4 {
decode_srgb(v.xyz).extend(v.w)
}

fn hsv_to_rgb(c: Vec3) -> Vec3 {
let K = Vec4::new(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
let p = ((c.xxx + K.xyz).fract() * 6.0 - K.www).abs();
c.z * lerp(K.xxx, (p - K.xxx).clamp(0.0, 1.0), c.y)
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like I copy 'n pasted swizzles inhere. Can remove.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like glam-rs will need Add<f32> and Sub<f32> implemented for it's vector types.

@@ -0,0 +1,131 @@
use lighting;

bitflags! {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be quite nice to use this.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can also try https://crates.io/crates/enumflags2, I find it even more ergonomic but it is a proc-macro instead so slower to build

world_pos: Vec3,
opacity: Vec3,

#[flat]
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure what kind of shape these attributes will end up taking, but this is an example.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alternative syntax: #[spriv_attr(flat)] or something like this.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as this is fragment shader input/layout it would likely have some attribute on the struct as as well including that name, so then this flat keyword ideally share namespace / part of the naming here also to make it explicit.

not too common to use though, but need to be supported

Comment on lines +34 to +35
constants: Constants,
inputs: Inputs,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably should talk about bindings in a new issue / PR.

Comment on lines +18 to +19
env_params: lighting::EnvParams,
view_params: lighting::ViewParams,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be nice to just use our own types here instead of what the GLSL thing does (raw vec4's).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yup for sure, will be interesting what repr we will end up on the structs with, and if this top level struct has a repr here, can it also enforce (I hope so) that all the structs and types inside it also has it

Comment on lines +52 to +54
lighting::ark_light(surface_params, constants.view_params, constants.env_params).extend(input.opacity)
} else {
(input.diffuse_color.truncate() * input.diffuse_color.w()).extend(input.opacity)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These .extend and .truncate calls are kind of fine, but they do get tiresome after a while.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it is rather cryptic of what does it even mean to truncate a diffuse color? may be other options than having an rgba color stored in a Vec4 with the glam naming here. the GLSL/HLSL swizzles and alias of rgba/xyzw is nice and more familar (just as the original code was diffuse_color.rgb which is very clear).

Could simply have diffuse_color.xyz() function in the math library instead of truncate here

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

don't look the wording of .extend() either, also cryptic

let scale = extract_conservative_scale_from_transform(object_to_world);
object_to_world = Mat4::from_mat3(
if spirv::view_index() == 0 {
global_uniforms.view_to_world.to_mat3()
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I invented glam-rs functions to_mat3 and from_mat3 here.

Comment on lines +110 to +111
if instance.flags.contains(ALPHA_BLENDING_ENABLE | PREMULTIPLIED_ALPHA_ENABLE) {
if instance.flags.contains(PREMULTIPLIED_ALPHA_ENABLE) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Somehow complex match patterns on bitflags! isn't ideal.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

think this is pretty fine though, somewhat cleaner and less error prone to read than the GLSL switch statement with bitwise logic in it me thinks.
and for other cases Rust's match will be really good

diffuse_color.a = 1.0;
}

let position = if spirv::view_index() == 0 {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I figured we could have a bunch of these builtins in core::arch::spirv similar to how _mm_set_p1 for example lives in core::arch::x86_64


position.set_y(-position.y())

position
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The GLSL function sets more interpolators then just position; we should find a way of setting this reliably between shader stages so that we can safely match then up. Potentially without all regular shader language magic around these.

@Jasper-Bekkers
Copy link
Contributor Author

From @h3r2tic

lighting.rs looks rather good I think -- except the swizzles which you noticed yourself
would structs need a #repr(C) or similar? I'm not sure at which stage any reordering might happen -- if the frontend messes with field order, it could be annoying


#[vertex_shader]
fn main() -> Vec4 {
let instance = instance_data[spirv::instance_index()]; // gl_InstanceIndex
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

spirv::instance_index looks a bit weird -- as in, the namespace sounds weird. I would expect the instance_index to be in some draw context, not in a namespace related to the instruction set. It's almost as if having x86_64::current_thread

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agreed. probably should be a decorated parameter to the main function that you declare that you want to have the instance index. GLSL is not a good base here with loose globals, prefer the explicit inputs & outputs of HLSL and think that would fit better in explicit Rust land also

let hsv = rgb_to_hsv(rgb);

let hsv = Vec3::new(
(hsv.x() + instance.hsv_transform_data.x()).fract(),
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The .x() etc could probably become just .x. I believe glam uses methods since internally it uses SIMD types that we don't need on the GPU. With different vector types we can have just .x

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good point, that would be nice

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not needing SIMD types isn't entirely true, unfortunately - NVIDIA still has massive performance losses when they non-SIMD types are used for loads and stores instead of the SIMD types.

Now, if we want that to impact our std-lib design is another question, because a load-store-vectorizer optimization pass can take care of that just as well.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not needing SIMD types isn't entirely true, unfortunately - NVIDIA still has massive performance losses when they non-SIMD types are used for loads and stores instead of the SIMD types

It is also possible to just map types to spir-v types. I have been doing that in rlsl, although reusing rusts simd types probably makes more sense.

It looks like this

#[spirv(Vec4)]
#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Vec4<T> {
    pub x: T,
    pub y: T,
    pub z: T,
    pub w: T,
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

although reusing rusts simd types probably makes more sense.

Looked up the tracking issue for #[repr(simd)], looks like it's quite intense. Anyway, I believe the current WIP would automatically compile it to a spir-v SIMD type, I'm guessing it shows up as an Abi::Vector which just straight dumps to a spir-v vector (probably want to deopt in a couple cases that aren't supported eventually, but anyway, first draft)

Copy link
Contributor

@repi repi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work!

@@ -0,0 +1,131 @@
use lighting;

bitflags! {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can also try https://crates.io/crates/enumflags2, I find it even more ergonomic but it is a proc-macro instead so slower to build

Comment on lines +18 to +19
env_params: lighting::EnvParams,
view_params: lighting::ViewParams,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yup for sure, will be interesting what repr we will end up on the structs with, and if this top level struct has a repr here, can it also enforce (I hope so) that all the structs and types inside it also has it

world_pos: Vec3,
opacity: Vec3,

#[flat]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as this is fragment shader input/layout it would likely have some attribute on the struct as as well including that name, so then this flat keyword ideally share namespace / part of the naming here also to make it explicit.

not too common to use though, but need to be supported

Comment on lines +52 to +54
lighting::ark_light(surface_params, constants.view_params, constants.env_params).extend(input.opacity)
} else {
(input.diffuse_color.truncate() * input.diffuse_color.w()).extend(input.opacity)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it is rather cryptic of what does it even mean to truncate a diffuse color? may be other options than having an rgba color stored in a Vec4 with the glam naming here. the GLSL/HLSL swizzles and alias of rgba/xyzw is nice and more familar (just as the original code was diffuse_color.rgb which is very clear).

Could simply have diffuse_color.xyz() function in the math library instead of truncate here

Comment on lines +52 to +54
lighting::ark_light(surface_params, constants.view_params, constants.env_params).extend(input.opacity)
} else {
(input.diffuse_color.truncate() * input.diffuse_color.w()).extend(input.opacity)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

don't look the wording of .extend() either, also cryptic


#[vertex_shader]
fn main() -> Vec4 {
let instance = instance_data[spirv::instance_index()]; // gl_InstanceIndex
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agreed. probably should be a decorated parameter to the main function that you declare that you want to have the instance index. GLSL is not a good base here with loose globals, prefer the explicit inputs & outputs of HLSL and think that would fit better in explicit Rust land also

if instance.flags.contains(BILLBOARD_ENABLE) {
let scale = extract_conservative_scale_from_transform(object_to_world);
object_to_world = Mat4::from_mat3(
if spirv::view_index() == 0 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here with spirv::view_index (gl_ViewIndex), think let's try doing it as an explicit function parameter/input instead

Comment on lines +110 to +111
if instance.flags.contains(ALPHA_BLENDING_ENABLE | PREMULTIPLIED_ALPHA_ENABLE) {
if instance.flags.contains(PREMULTIPLIED_ALPHA_ENABLE) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

think this is pretty fine though, somewhat cleaner and less error prone to read than the GLSL switch statement with bitwise logic in it me thinks.
and for other cases Rust's match will be really good

@Jasper-Bekkers
Copy link
Contributor Author

@repi your comments appear duplicated, any way to collapse them?

@repi
Copy link
Contributor

repi commented Aug 20, 2020

Oh that is very odd, I think it happened somehow because I left comments in existing comments while I was doing my review, and GitHub somehow duplicates that, odd. Doesn't seem to be a way to remove it.

I probably shouldn't have choosen "Request changes", but instead just "Add comments". Think it lists them as the changes I requested

@repi repi mentioned this pull request Aug 20, 2020
@repi
Copy link
Contributor

repi commented Aug 26, 2020

@Jasper-Bekkers think we could merge this in and file some follow up issues around the specific larger syntax discussions here? Then one can iterate further on it in future PRs

@repi repi mentioned this pull request Sep 18, 2020
@Jasper-Bekkers
Copy link
Contributor Author

Now that we have specific shaders to test with, we should probably close this issue and address ergonomics on a case-by-case basis.

@khyperia khyperia removed their request for review January 11, 2021 09:59
@XAMPPRocky XAMPPRocky deleted the sketch-shaders branch April 30, 2021 07:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants