-
Notifications
You must be signed in to change notification settings - Fork 722
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
[SPIR-V] Invalid spir-v generated when using nointerpolation keyword #5270
Comments
@ShchchowAMD this appears to have started happening with commit cd3b40b Going through more of our shader builds and it definitely seems to affect everywhere we use nointerpolation, with results varying from something like the above to straight up crashing inside the optimizer in spvtools. |
Thanks for reporting this issue. Ref to comment in the commit: #4638 (comment) For latest KHR extension, following SV_BaryCentrics description in wiki (https://github.com/microsoft/DirectXShaderCompiler/wiki/SV_Barycentrics):
So I think an inputs decorated with 'nointerpolation' should be treated as it has an extra dimension, indicating which vertices it mapped to. For the error reported here, its type is treated as an int[3] now. @s-perron @Keenuts I'm not sure whether above case is legal in KHR extension, like the case in discussion before:
If we could make sure it should only be used in such intrinsics, I'll add error message in compile result info. |
Yes, we did discuss this before. This case cannot be handled in Vulkan because the spir-v cannot correctly represent it. The spir-v validator message is not useful. If we can, we should try to add an error message before we generate the spir-v. @ShchchowAMD Are you able to do that? |
Yea. I'll make a new commit for this. |
Also been getting issues due to inappropriate usage of nointerpolation but from an LLVM assert // dxc.exe -T ps_6_0 -E MainPs -spirv
// Internal compiler error: LLVM Assert
struct PS_INPUT
{
nointerpolation uint nView : TEXCOORD12;
};
Texture2D g_tBlueNoise : register( t0 );
uint2 TextureDimensions2D( Texture2D tex, uint nMipLevel )
{
uint2 nDim;
uint nLevels;
tex.GetDimensions( nMipLevel, nDim.x, nDim.y, nLevels );
return nDim;
}
float4 MainPs( PS_INPUT i ) : SV_Target0
{
uint nView = i.nView;
TextureDimensions2D( g_tBlueNoise, 0 );
return float4( 1.0, 1.0, 1.0, 1.0 );
} |
@handsomematt @s-perron - I might not be fully understanding the discussion here, but can you confirm you will be fixing the regression with the case @handsomematt mentions above. We have this in our shaders too, and this has worked for a very long time, so I presume this is just a regression due to your change? I presume nointerpolation on a PS input should just map to the SPIR-V Flat decoration as it always has - should be fully represenable in SPIR-V? |
I cannot find what HLSL is supposed to do if you access a nointerpolation input without using GetAttributeAtVertex. Is there anything that specifies what it does? This is all that I could find. |
The case that regressed is a PS input, not VS input. It should be a Flat interpolation modifier. I don’t think there is any ambiguity about that? It used to work. |
@danginsburg From the spec, GetAttributeAtVertex is used in PS. We now support this intrinsic so nointerpolation input will be treated as an array. Its index will represent VertexID, indicating where this value comes from / which vertex it is representing now. We are assuming it won't be used outside this intrinsics. @handsomematt I'll check this. Another question for this example is just as first comment to @danginsburg here. |
Ok. I am confused. The SV_Barycentric proposal changes the meaning of nointerpolation PS inputs for all shader models? Shouldn’t it be opt in somehow? This has been supported since SM5 and has been in the spir-v backend for a long time https://github.com/microsoft/DirectXShaderCompiler/blob/main/docs/SPIR-V.rst#id66 |
Just for further clarity here's the expected output of this code before cd3b40b and the error we're getting after, the assert I posted earlier is an additional error with the same root problem. struct PS_INPUT
{
nointerpolation uint nView : TEXCOORD12;
};
uint MainPs( PS_INPUT i ) : SV_Target0
{
return i.nView;
}
// Before cd3b40b
// dxc.exe -T ps_6_0 -E MainPs -spirv
// ...
// OpName %MainPs "MainPs"
// OpDecorate %in_var_TEXCOORD12 Flat
// OpDecorate %in_var_TEXCOORD12 Location 0
// ...
// After cd3b40b
// dxc.exe -T ps_6_0 -E MainPs -spirv
// fatal error: generated SPIR-V is invalid: Expected Result Type to be a composite type
// %17 = OpCompositeConstruct %uint %16 %11 %11 |
I'll review the specs, and get back to you. |
Here are some observations I have from poking at it:
I would propose, therefore, that for the purposes of SPIR-V:
That seems to be what DX12 is doing from what I can tell. |
I have a better idea of what is going on. @ShchchowAMD sorry for the bad advice earlier. I was not familiar enough with how TL/DR: When a nointerpolation input is used in a PS without @ShchchowAMD Let me know if this seems reasonable to implement. I'm still not very familiar with how DXC is structured. This will be a long explanation because I want to document how we ended up here, and why it is done this way. nointerpolation before barycentricsBefore the barycentrics were implemented, a variable marked with nointerpolation was simply decorated as The HLSL specification does not define the nointerpolation keyword precisely. All it says is "Do not interpolate the outputs of a vertex shader before passing them to a pixel shader.". They probably end up using the value from the provoking vertex, but that is not specificed. Regardless of what the HLSL spec says, the syntax is legal in HLSL, and the SPIR-V backend implemented a particular behaviour is the only reasonable implementation (my opinion). nointerpolation after barycentricsWhen barycentrics were added, the pixel shader potentially needs access the uninterpolated values for each vertex. In HLSL this is done by using the At this point, we had a decision to make: What is the type of a The first implementation tried to identify if the input is used in When considering a new design, I suggested that we always turn the input into an array. This would eliminate the need to look at the uses to determine the type of the variable. I made a mistake when I suggested that we consider a use without Now I realize that the uses without The extra capabilityIn general, we do not want to add a capability to the shader when it is not strictly needed. This will needlessly limit the HW on which the shader can run. As I mentioned above, I want to keep the code generation in DXC simple. The code generation should not have to trace uses to get the type. It can become arbitrarily complicated when the input can be passed as a parameter to other functions. The would be to only use make the input an array if and only the |
I think I agree but with respect to this statement I think it's a little confusing:
I would say "That is, treat it as if it was |
@danginsburg @s-perron Just a simple repeat to make sure I understand right, with a simple example here:
I think this would make sense to me. both for type meaning and implementation ways. PS. The reason why using type redeclare in current impl is that in DXC HLSL-SPV trans level, it would use two variables to represent an input. One for stage IO, another for param var in 'main' block, loading data from related stage IO, I just want to make impl more simple. If above understanding is right, it would reduce workload as we don't need to check and modify result type in all statements in any blocks, related to nointerpolated inputs. |
This should definitely not be done. You should not generate SPIR-V that requires SPV_KHR_fragment_shader_barycentric and it shouldn't require additional PS inputs. It should just generate the code it used to generate:
|
I'll try to clarify my TL/DR above. I was suggesting the following pseudo code:
If generating the code both ways leads to a lot of if-statements in DXC, we could write a spirv-opt pass that removes the PerVertexKHR decoration when the only vertex used is the provoking vertex. I could write the spirv-opt pass. |
Thanks, now I know the meanings. I'll have a try locally, it may take some time and I'll update ASAP. |
I've recently also upgraded DXC, and started running into compiler issues with a vertex shader containing The following two asserts occur inside
On the following shader: struct VsOut {
nointerpolation uint someIndex : TEXCOORD1;
};
struct BindingsOffset {
uint someData;
};
[[vk::binding(0, 0)]] ByteAddressBuffer g_ByteAddressBuffer[10];
ConstantBuffer<BindingsOffset> g_bindingsOffset : register(b0, space0);
VsOut main(uint vertexIndex : SV_VertexID) {
ByteAddressBuffer buf = g_ByteAddressBuffer[0];
VsOut vOut = (VsOut)0;
vOut.someIndex = g_bindingsOffset.someData;
return vOut;
} Compiled with: dxc -E main -T vs_6_6 repro.hlsl -spirv If I remove Apologies for not really catching up on the context above, but we're not doing anything with |
@MarijnS95 Thanks for sharing this test case. I'm working locally to fix above cases. For the first issue: BTW, thanks very much for providing a nice test case, It may take me some time to refine current codes. |
@ShchchowAMD Any update? |
I've moved type redecl to intrinsic process part and now usage of old pass or new intrinsic separately would work fine now. Still working with spirv instructions' type replacement (it may be called in other instructions) and adding a GetAttributeAtVertex(v, 0) for mixed usage, also the special case for Boolean input now. This may introduce two interfaces (may be refined later):
I'll try my best to finish it next week ASAP. |
Great! Thanks. |
@ShchchowAMD Sorry, but I will be on you a lot about this. People keep reporting new issues related to this. This is a serious regression. If we cannot get the fix soon, should we revert your change? Then you can put it back in when you have to fix ready. |
Yeah, we are stuck not being able to take newer version of DXC until this gets fixed. I don't want to make extra work, but if it's not going to be addressed soon I agree it should be reverted. I wouldn't want this to go into an official release. It's broken for most of our pixel shaders, and I imagine many other people's as well. |
Hi perron, |
Are there any autotests to prevent such breaking changes in the future? |
Thanks everyone for your responses, I would also agree that this change should probably be reverted - even if a fix is forthcoming, it seems like it might be a better idea to instead have some test coverage (as suggested by @Goshido above) alongside a fixed version of the original change instead? |
@s-perron Please revert my previous commit. Current fix spent more time than expected. I'll add more test coverages before making a new PR. Sorry for this regression again. |
@Keenuts @cassiebeckley I'm off today can one of you take care of the revert? If not I'll do it tomorrow. |
Sure, but everybody is OOO for the next 2 days (except me in Europe 🙃) so might not get the approvals for revert before Wednesday. |
DirectX Shader Compiler v1.7.2212.10216 Thanks 👍 |
Thanks all |
Hello, when compiling the following drastically reduced HLSL example to spir-v with
dxc.exe -spirv -fspv-target-env=vulkan1.1 -fvk-use-dx-layout -O3 -T ps_6_0 -E psMain nointerpolationbug.hlsl
:I get the following error:
This occurs on the current latest nightly build against commit e0a2965, it does not occur using an earlier build against commit 740dd09.
The text was updated successfully, but these errors were encountered: