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

Fixes for fma function #1580

Merged
merged 7 commits into from
Dec 22, 2021
Merged

Fixes for fma function #1580

merged 7 commits into from
Dec 22, 2021

Conversation

parasyte
Copy link
Contributor

@parasyte parasyte commented Dec 7, 2021

- This should be enough because we only support f32 for now.
- Adds a new test for WGSL functions, in the spirit of operators.wgsl.
- Closes gfx-rs#1579
@@ -0,0 +1,15 @@
fn test_fma() -> vec2<f32> {
Copy link
Member

Choose a reason for hiding this comment

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

we should probably move a few things from operators.wgsl into here

@kvark
Copy link
Member

kvark commented Dec 7, 2021

You've got a fun SPIR-V error:

ERROR: 0:13: 'fma' : required extension not requested: Possible extensions include:
GL_EXT_gpu_shader5
GL_OES_gpu_shader5

So, the first approximation should probably just generate the multiply-add instructions as is.
Then we can add the check for one of those extensions and use the specific opcode.

@parasyte
Copy link
Contributor Author

parasyte commented Dec 7, 2021

I was just looking into that, hoping it was going to be adding a shader model 5 extension to glslangValidator, but that doesn't appear to be the case.

- I think this is right. Just iterate all known expressions in all
  functions and entry points to locate any `fma` function call.
  Should not need to walk the statement DAG.
@parasyte
Copy link
Contributor Author

parasyte commented Dec 7, 2021

I added the extension for GLES outputs when the fma function exists in the module. That fixes the test! I'm happy with it if you are.

@parasyte
Copy link
Contributor Author

parasyte commented Dec 7, 2021

Hmm! That still isn't enough for WebGL 2. Old error, prior to this patch:

panicked at 'wgpu error: Validation Error

Caused by:
    In Device::create_render_pipeline
      note: label = `pixels_scaling_renderer_pipeline`
    Internal error in VERTEX shader: ERROR: 0:21: 'fma' : no matching overloaded function found
ERROR: 0:21: '=' : dimension mismatch
ERROR: 0:21: 'assign' : cannot convert from 'const mediump float' to 'highp 2-component vector of float'

New error:

panicked at 'wgpu error: Validation Error

Caused by:
    In Device::create_render_pipeline
      note: label = `pixels_scaling_renderer_pipeline`
    Internal error in VERTEX shader: The selected version doesn't support FMA

It may be better to output the separate multiply and add ops, but I don't know where to start with that.

Copy link
Member

@kvark kvark left a comment

Choose a reason for hiding this comment

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

Sorry, looks like we have one more thing to do here

src/back/glsl/features.rs Outdated Show resolved Hide resolved
@parasyte parasyte marked this pull request as draft December 7, 2021 18:37
@kvark
Copy link
Member

kvark commented Dec 16, 2021

@parasyte is this still WIP?

@kvark kvark mentioned this pull request Dec 17, 2021
@parasyte
Copy link
Contributor Author

It is. I haven't attempted to do the transformation for GLSL.

@parasyte parasyte marked this pull request as ready for review December 18, 2021 23:34
@parasyte
Copy link
Contributor Author

@kvark Ok, I think I got this one working. The GLSL writer can do the transformation and it works on WebGL 2.0.

@parasyte parasyte changed the title [hlsl-out] Write mad intrinsic for fma function Fixes for fma function Dec 18, 2021
Copy link
Member

@kvark kvark left a comment

Choose a reason for hiding this comment

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

Thank you!
Got a few notes here

src/back/glsl/features.rs Outdated Show resolved Hide resolved
@@ -33,6 +33,8 @@ bitflags::bitflags! {
/// Arrays with a dynamic length
const DYNAMIC_ARRAY_SIZE = 1 << 16;
const MULTI_VIEW = 1 << 17;
/// Adds support for fused multiply-add
const FMA = 1 << 18;
Copy link
Member

Choose a reason for hiding this comment

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

Why do we need thus flag? If FMA isn't natively supported, we are emulating it anyway. So it seems to me that this flag isn't getting us anything.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

For one thing, I'm following precedent with existing features that need extensions, and fma is only supported on GLES 3.1+ with:

#version 310 es
#extension GL_EXT_gpu_shader5 : require

This PR does not emulate fma on GLSL in every case, but decides if it must emulate it or else it requests the extension when necessary. This fixes that unusual validation error you noted earlier: https://github.com/gfx-rs/naga/runs/4446174291?check_suite_focus=true

ERROR: 0:13: 'fma' : required extension not requested: Possible extensions include:
GL_EXT_gpu_shader5
GL_OES_gpu_shader5

I chose to use the existing feature flag infrastructure to write this extension, rather than coming up with something unique just for this case. Is there something better I could have done here?

The FMA feature flag name is probably too narrow, honestly. GL_EXT_gpu_shader5 enables a lot more than just the fma function, and the feature flag can be used to support all of it on GLES.

Copy link
Member

Choose a reason for hiding this comment

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

The capability flags in GLSL backend are meant to be requirements. I.e. shader requires A, B, C, and we want to check if we can work with this shader at all.
The case for FMA is different. The backend always supports FMA instruction. The only thing different is a code path taken. Therefore, there is no case where GLSL backend would check for this capability and report it missing. It's not a real capability.

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 think I understand what you mean. Let me try to rephrase it; The fma function from the frontend is always supported by the backend (GLSL) even if it has to fallback to an arithmetic transformation (i.e., "emulated"). This PR uses a feature flag (capability) in another sense, that it can enable the use of the GLSL fma function on particular versions of the backend. Which are not how feature flags are used elsewhere.

Would that be an accurate way to describe the situation?

I'll have to think on it if I need to use some other mechanism to enable the extension for GLES. I do see an extension enabled that is not controlled by feature flags:

naga/src/back/glsl/mod.rs

Lines 442 to 450 in 7c8bedc

// Write the additional extensions
if self
.options
.writer_flags
.contains(WriterFlags::TEXTURE_SHADOW_LOD)
{
// https://www.khronos.org/registry/OpenGL/extensions/EXT/EXT_texture_shadow_lod.txt
writeln!(self.out, "#extension GL_EXT_texture_shadow_lod : require")?;
}
I suppose that would be an appropriate place to put this?

src/back/glsl/mod.rs Outdated Show resolved Hide resolved
@kvark kvark merged commit 924ab17 into gfx-rs:master Dec 22, 2021
@parasyte parasyte deleted the fix/hlsl-fma-f32 branch December 22, 2021 23:48
@kvark kvark added the can backport PR that can be back-ported to a release branch label Dec 29, 2021
kvark pushed a commit to kvark/naga that referenced this pull request Dec 29, 2021
* [hlsl-out] Write `mad` intrinsic for `fma` function

- This should be enough because we only support f32 for now.
- Adds a new test for WGSL functions, in the spirit of operators.wgsl.
- Closes gfx-rs#1579

* Add FMA feature to glsl backend

- I think this is right. Just iterate all known expressions in all
  functions and entry points to locate any `fma` function call.
  Should not need to walk the statement DAG.

* Transform GLSL fma function into an airthmetic expression when necessary

* Add tests for GLSL fma function tranformation

* Remove the hazard comment from the webgl test input

* Add helper method for fma function support checks

* Address review comment
@kvark kvark mentioned this pull request Dec 29, 2021
@kvark
Copy link
Member

kvark commented Dec 29, 2021

published in 0.8.1

@kvark kvark removed the can backport PR that can be back-ported to a release branch label Dec 29, 2021
kvark pushed a commit that referenced this pull request Dec 29, 2021
* [hlsl-out] Write `mad` intrinsic for `fma` function

- This should be enough because we only support f32 for now.
- Adds a new test for WGSL functions, in the spirit of operators.wgsl.
- Closes #1579

* Add FMA feature to glsl backend

- I think this is right. Just iterate all known expressions in all
  functions and entry points to locate any `fma` function call.
  Should not need to walk the statement DAG.

* Transform GLSL fma function into an airthmetic expression when necessary

* Add tests for GLSL fma function tranformation

* Remove the hazard comment from the webgl test input

* Add helper method for fma function support checks

* Address review comment
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.

[hlsl-out] fma function should use mad for single-precision floats
2 participants