-
Notifications
You must be signed in to change notification settings - Fork 194
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
[spv-out] Add multiply instructions #219
Conversation
c9e4ffd
to
aa98d5f
Compare
src/back/spv/writer.rs
Outdated
let left_load_id = self.generate_id(); | ||
let right_load_id = self.generate_id(); | ||
|
||
block.body.push(super::instructions::instruction_load( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why are there load
instructions here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That is, because the values are from an OpVariable
for instance, and to use an OpVariable
, you have to load them through OpLoad
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hmm, but there isn't any check here about whether the target is OpVariable or not. So how do we know that unconditionally "load"-ing is the right thing to do?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That is true, but as far as I know there are only two ways to use binary instructions at high level: via pointers, and via constants.
I have done some research at http://shader-playground.timjones.io/, and when doing it via pointers, there is always an OpLoad
needed.
GLSL:
void main()
{
vec2 vec_1 = vec2(1.0, 1.0);
float float_1 = vec_1.x * vec_1.y;
float float_3 = float_1 * float_1;
}
This will always translate back to OpLoad
, whether it is via an OpAccessChain
or OpVariable
. There probably are more ways of accessing value via pointers, but all pointers always need to be loaded in via OpLoad
to be useful (as far as I know).
What is good to see, is that when I am using constants, instead of variables at the shader playground, it pre-calculates the value, and uses it directly (which is allowed).
GLSL:
void main()
{
float float_1 = 1.0 * 2.0;
}
However, because of the pre-calculation, the resulting SPIR-V output does not even contain a binary instruction, as it is already calculated.
I think it is safe to say for now to always use OpLoad
here, but maybe you think about a case where this might not be, please let me know, so we can reconsider this piece of code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can't always use OpLoad
there. It should only happen if the target expression is a variable. Once it's a different expression, there should be no load. For example, if you do float x = 2 * (y + 1);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah yes, I understand what you mean. I have a rough idea, and will try to implement it tomorrow: what if we never check for the specific Expression::LocalVariable
, but let the match arm of Expression::LocalVariable
always create and return an OpLoad
?
That should fix this issue, and the rest of the code will be cleaner, as Expression::Return
, and Expression::Store
have a specific match for if the id of the expression is of the expression type Expression::LocalVariable
. This is pretty dirty to be honest, but I didn't see that back then.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, both LocalVariable
and GlobalVariable
variants need to generate OpLoad
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed and now it supports even "unlimited" expression nesting:
var float_1: f32 = 2.0 * (2.0 * (4.0 * 2.0));
Giving the predicted result without an OpLoad
, like you said (and correctly validates):
%5 = OpVariable %_ptr_Function_float Function
%13 = OpFMul %float %float_4 %float_2
%12 = OpFMul %float %float_2 %13
%11 = OpFMul %float %float_2 %12
OpStore %5 %11 None
aa98d5f
to
e6d2021
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just one concern
src/back/spv/writer.rs
Outdated
let left_load_id = self.generate_id(); | ||
let right_load_id = self.generate_id(); | ||
|
||
block.body.push(super::instructions::instruction_load( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hmm, but there isn't any check here about whether the target is OpVariable or not. So how do we know that unconditionally "load"-ing is the right thing to do?
e6d2021
to
af02f49
Compare
Add support for the long-awaited multiply instructions:
Tested with the following WGSL: