diff options
| author | Tim Foley <tfoleyNV@users.noreply.github.com> | 2018-10-04 16:05:23 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2018-10-04 16:05:23 -0700 |
| commit | 4cb2a19ef192424c0a4eb205a773624563222383 (patch) | |
| tree | d2b6853ec7f22afbe69c62d48b283443443f175e /tests | |
| parent | 84a48475067af70c9acccc9816dd60e623714328 (diff) | |
Support cross-compilation of ray tracing shaders to Vulkan (#663)
* Move to newer glslang
* Support cross-compilation of ray tracing shaders to Vulkan
This change allows HLSL shaders authored for DirectX Raytracing (DXR) to be cross-compiled to run with the experimental `GL_NVX_raytracing` extension (aka "VKRay").
* The GLSL extension spec is marked as experimental, so that any shaders written using this support should be ready for breaking changes when the spec is finalized.
* "Callable shaders" are not exposed throug the GLSL extension, so this feature of DXR will not be cross-compiled.
* The experimental Vulkan raytracing extension does not have an equivalent to DXR's "local root signature" concept. This does not visibly impact shader translation (because the local/global root signature mapping is handled outside of the HLSL code), but in practice it means that applications which rely on local root signatures on their DXR path will not be able to use the translation in this change as-is; more work will be needed.
The simplest part of the implementation was to go into the Slang standard library and start adding GLSL translations for the various DXR operations.
In some cases, like mapping `IgnoreHit()` to `ignoreIntersectionNVX()` this is almost trivial.
The various functions to query system-provided values (e.g., `RayTMin()`) were also easy, with the only gotcha being that they map to variables rather than function calls in GLSL, and our handling of `__target_intrinsic` assumes that a bare identifier represents a replacement function name, and not a full expression, so we have to wrap these definitions in parentheses.
The tricky operations are then `TraceRay<P>()` and `ReportHit<A>()`, because these two are generics/templates in HLSL.
GLSL doesn't support generics, even for "standard library" functions, so the raytracing extension implements a slightly complex workaround: the matching operations `traceNVX()` and `reportIntersectionNVX()` pass the payload/attributes argument data via a global variable.
That is, shader code for the GLSL extensions writes to the global variable and then calls the intrinsic function.
The linkage between the call site and the global is established by a modifier keyword (`rayPayloadNVX` and `hitAttributeNVX`, respectively) and in the case of ray payload also uses `location` number to identify which payload global to use (since a single shader can trace rays with multiple payload types).
Our translation strategy in Slang tries to leverage standard language mechanisms instead of special-case logic.
For example, to translate the `ReportHit<A>()` function, we provide both a default declaration that will work for HLSL (where the operation is built-in with the signature given), and a *definition* marked with the `__specialized_for_target(glsl)` modifier.
The GLSL definition declares a function `static` variable that will fill the role of the required global, and then does what the GLSL spec requires: assigns to the global, and then calls the `reportIntersectionNVX` builtin (which we declare as a separate builtin).
Our ordinary lowering process will turn that `static` variable into an ordinary global in the IR, and the `[__vulkanHitAttributes]` attribute on the variable will be emitted as `hitAttributeNVX` in the output.
There is no additional cross-compilation logic in Slang specific to `ReportHit<A>()` - the target-specific definition in the standard library Just Works.
The case for `TraceRay<P>()` is a bit more complicated, simply because the GLSL `traceNVX()` function needs to be passed the `location` for the payload global.
We implement the payload global as a function-`static` variable, with the knowledge that every unique specialization of `TraceRay<P>()` will generate a unique global variable of type `P` to implement our function-`static` variable.
We then add a slightly magical builtin function `__rayPayloadLocation()` that can map such a variable to its generated `location`; the logic for this is implemented in `emit.cpp` and described below.
We also changed the `RayDesc` and `BuiltinTriangleIntersectionAttributes` types from "magic" intrinsic types over to ordinary types (because the GLSL output needs to declare them as ordinary `struct` types).
This ends up removing some cases in the AST and IR type representations.
By itself this change would break HLSL emit, because in that case the types really are intrinsic.
We added a `__target_intrinsic` modifier to these types to make them intrinsic for HLSL, and then updated the downstream passes to handle the notion of target-intrinsic types.
The logic for binding/layout of entry point inputs and outputs was updated so that raytracing stages don't follow the default logic for varying input/output parameters.
This is because the input/output parameters of a raytracing entry point aren't really "varying" in the same sense as those in the rasterization pipeline.
In particular, the SPIR-V model for raytracing input and output treats "ray payload" and "hit attributes" parameters as being in a distinct storage class from `in` or `out` parameters.
We also detect cases where a ray tracing stage declares inputs/outputs that it shouldn't have. This logic could conceivably be extended to other stages (e.g., to give an error on a compute shader with user-defined varying input/output).
The type layout logic added cases for handling raytracing payload and hit-attribute data, but this is currently just a stub implementation that follows the same logic as for varying `in` and `out` parameters (it cannot give meaningful byte sizes/offsets right now).
To my knowledge the GLSL spec doesn't currently specify anything about layout, and I haven't read the DXR spec language carefully enough to know what it says about layout.
A future change should update the layout logic to allow for byte-based layout of ray payloads, etc. so that we can query this information via reflection.
The GLSL legalization logic in `ir.cpp` was updated to factor out the per-entry-point-parameter code into its own function, and then that function was updated to special-case the input/output of a ray-tracing shader.
While for rasterization stages we typically want to take the user-declared input/output and "scalarize" it for use in GLSL (in part to deal with language limitations, and in part to tease system values apart from user-defined input/output), the GLSL spec for raytracing requires payload and hit attribute parameters to be declared as single variables. There is also the issue that even for an `in out` parameter, a ray payload parameter should only turn into a single global, whereas the handling for varying `in out` parameters generates both an `in` and an `out` global for the GLSL case.
Other than the handling of entry point parameters, the GLSL legalization pass doesn't need to do anything special for ray tracing shaders.
The trickiest change in the `emit.cpp` logic is that we now generate `location`s for ray payload arguments (the outgoing from a `TraceRay()` call) on demand during code generation.
This is a bit hacky, and it would be nice to handle it as a separate pass on the IR rather than clutter up the emit logic, but this approach was expedient.
Basically, any of the global variables that got generated from the `static` declarations in the standard library implementation of `TraceRay()` will trigger the logic to assign them a `location`.
The logic for emitting intrinsic operations added a few new `$`-based escape sequences. The `$XP` case handles emitting the location of a generated ray payload variable; this is how we emit the matching location at the site where we call `traceNVX`. The `$XT` case emits the appropriate translation for `RayTCurrent()` in HLSL, because it maps to something different depending on the target stage.
All of the test cases here consist of a pair of an HLSL/Slang shader written to the DXR spec, plus a matching GLSL shader for a baseline.
The GLSL shaders are carefully designed so that when fed into glslang they will produce the same SPIR-V as our cross-compilation process.
This kind of testing is quite fragile, but it seems to be the best we can do until our testing framework code supports *both* DXR and VKRay.
A bunch of the core changes ended up being blocked on issues in the rest of the compiler, so some additional features go implemented or fixed along the way:
The first big wall this work ran into was that the `__specialized_for_target` modifier hasn't actually been working correctly for a while.
It turns out that for the one function that is using it, `saturate()`, we have been outputting the workaround GLSL function in *all* cases (including for HLSL output) rather than only on GLSL targets.
The problem here is that for a generic function with a `__specialized_for_target` modifier or a `__target_intrinsic` modifier, the IR-level decoration will end up attached to the `IRFunc` instruction nested in the `IRGeneric`, but the logic for comparing IR declarations to see which is more specialized (via `getTargetSpecializationLevel()`) was looking only at decorations on the top-level value (the generic).
The quick (hacky) fix here is to make `getTargetSpecializationLevel()` try to look at the return value of a generic rather than the generic itself, so that it can see the decorations that indicate target-specific functions.
A more refined fix would be to attach target-specificity decorations to the outer-most generic (to simplify the "linking" logic).
The only reason not to fold that into the current fix is that the `__target_intrinsic` modifier currently serves double-duty as a marker of target specialization *and* information to drive emit logic. The latter (the emit-related stuff) currently needs to live on the `IRFunc`, and moving it to the generic could easily break a lot of code.
This needs more work in a follow-on fix, but for now target specialization should again be working.
The other big gotcha that the simple "just use the standard library" strategy ran into was that function-`static` variables weren't actually implemented yet, and in particular function-`static` variables inside of generic functions required some careful coding.
The logic in `lower-to-ir.cpp` has this `emitOuterGenerics()` function that is supposed to take a declaration that might be nested inside of zero or more levels of AST generics, and emit corresponding IR generics for all those levels.
This is needed because two different AST functions nested inside a single generic `struct` declaration should turn into distinct `IRFunc`s nested in distinct `IRGeneric`s.
The tricky bit to making that all work is that the same AST-level generic type parameter will then map to *different* IR-level instructions (the parameters of distinct `IRGeneric`s) when lowering each function.
The existing logic handled this in an idiomatic way by making "sub-builders" and "sub-contexts."
This change refactors some of the repeated logic into a `NestedContext` type to help simplify the pattern, and applies it consistently throughout the `lower-to-ir.cpp` file.
Besides that cleanup, the major change is `lowerFunctionStaticVarDecl` which, unsurprisingly, handles lower of function-`static` variables to IR globals.
The careful handling of nested contexts here is needed because if we are in the middle of lowering a generic function, then a `static` variable should turn into its *own* `IRGeneric` wrapping an `IRGlobalVar`. The body of the function should refer to the global variable by specializing the global variable's `IRGeneric` to the parameters of the *functions* `IRGeneric`. This tricky detail is handled by `defaultSpecializeOuterGenerics`.
An additional subtlety not actually required for this raytracing work (and thus not properly tested right now) is handling function-`static` variables with initializers.
These can't just be lowered to globals with initializers, because HLSL follows the C rule that function-`static` variables are initialized when the declaration statement is first executed (and this could be visible in the presence of side-effects).
The lowering strategy here translates any `static` variable with an initializer into *two* globals: one for the actual storage, plus a second `bool` variable to track whether it has been initialized yet.
There are some opportunities to optimize this case, especially for `static const` data, but that will need to wait for future changes.
We've slowly been shifting away from the model where a user thinks of a "profile" as including both a stage and a feature level.
Instead, the user should think about selecting a profile that only describes a feature level (e.g., `sm_6_1`, `glsl_450`, etc.), and then separately specifying a stage (`vertex`, `raygeneration, etc.) for each entry point.
The challenge here is that the command-line processing still only had a single `-profile` switch, and no way to specify the stage.
Adding the `-stage` option was relatively easy, but making it work with the existing validation logic for command-line arguments was tricky, because of the complex model that `slangc` supports for compiling multiple entry points in a single pass.
* In `slang.h` add new reflection parameter categories for ray payloads and hit attributes, as part of entry point input/output signatures.
* A previous change already updated our copy of glslang to one that supports the `GL_NVX_raytracing` extension, so in `slang-glslang.cpp` we just needed to map Slang's `enum` values for the raytracing stage names to their equivalents in the glslang code.
* Moved the logic for looking up a stage by name (`findStageByName()`) out of `check.cpp` and into `compiler.cpp`, with a declaration in `profile.h`
* Added a `$z` suffix to the GLSL translation of `Texture*.SampleLevel()`, to handle cases where the texture element type is not a 4-component vector. Note that this fix should actually be applied to *all* these texture-sampling operations, but I didn't want to add a bunch of changes that are (clearly) not being tested right now.
* The layout logic for entry points was updated to correctly skip producing a `TypeLayout` for an entry point result of type `void`, which meant that the related emit logic now needs to guard against a null value for the result layout.
* In `ir.cpp`, dump decorations on every instruction instead of just selected ones, so that our IR dump output is more complete.
* Added a command-line `-line-directive-mode` option so that we can easily turn off `#line` directives in the output when debugging. Not all cases where plumbed through because the `none` case is realistically the most important.
* Parser was fixed to properly initialize parent links for "scope" declarations used for statements, so that we can walk backwards from a function-scope variable (including a `static`) and see the outer function/generics/etc.
* Added GLSL 460 profile, since it is required for ray tracing. Also updated the logic for computing the "effective" profile to use to recognize that GLSL raytracing stages require GLSL 460.
* Added some conventional ray-tracing shader suffixes to the handling in `slang-test`. This code isn't actually used, but was relevant when I started by copy-pasting some existing VKRay shaders as the starting point for my testing.
* Fixup: typos
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/vkray/anyhit.slang | 41 | ||||
| -rw-r--r-- | tests/vkray/anyhit.slang.glsl | 58 | ||||
| -rw-r--r-- | tests/vkray/closesthit.slang | 25 | ||||
| -rw-r--r-- | tests/vkray/closesthit.slang.glsl | 46 | ||||
| -rw-r--r-- | tests/vkray/intersection.slang | 47 | ||||
| -rw-r--r-- | tests/vkray/intersection.slang.glsl | 86 | ||||
| -rw-r--r-- | tests/vkray/miss.slang | 11 | ||||
| -rw-r--r-- | tests/vkray/miss.slang.glsl | 18 | ||||
| -rw-r--r-- | tests/vkray/raygen.slang | 116 | ||||
| -rw-r--r-- | tests/vkray/raygen.slang.glsl | 200 |
10 files changed, 648 insertions, 0 deletions
diff --git a/tests/vkray/anyhit.slang b/tests/vkray/anyhit.slang new file mode 100644 index 000000000..6959efc9c --- /dev/null +++ b/tests/vkray/anyhit.slang @@ -0,0 +1,41 @@ +// closesthit.slang +//TEST:CROSS_COMPILE: -profile sm_6_3 -stage anyhit -entry main -target spirv-assembly + +struct SphereHitAttributes +{ + float3 normal; +}; + + +struct ShadowRay +{ + float4 hitDistance; +}; + +struct Params +{ + Texture2D<float> alphaMap; + SamplerState sampler; + int mode; +} +ParameterBlock<Params> gParams; + +void main( + SphereHitAttributes attributes, + in out ShadowRay ioPayload) +{ + if(gParams.mode) + { + float val = gParams.alphaMap.SampleLevel( + gParams.sampler, + attributes.normal.xy, 0); + if(val > 0) + { + AcceptHitAndEndSearch(); + } + else + { + IgnoreHit(); + } + } +} diff --git a/tests/vkray/anyhit.slang.glsl b/tests/vkray/anyhit.slang.glsl new file mode 100644 index 000000000..7fb9ac553 --- /dev/null +++ b/tests/vkray/anyhit.slang.glsl @@ -0,0 +1,58 @@ +// anyhit.slang.glsl +#version 460 +#extension GL_NVX_raytracing : require + +struct Params_0 +{ + int mode_0; +}; + +layout(binding = 0) +layout(std140) uniform _S1 +{ + Params_0 gParams_0; +}; + +layout(binding = 1) +uniform texture2D gParams_alphaMap_0; + +layout(binding = 2) +uniform sampler gParams_sampler_0; + +struct SphereHitAttributes_0 +{ + vec3 normal_0; +}; +hitAttributeNVX SphereHitAttributes_0 _S2; + +struct ShadowRay_0 +{ + vec4 hitDistance_0; +}; +rayPayloadInNVX ShadowRay_0 _S3; + +void main() +{ + SphereHitAttributes_0 _S4 = _S2; + + if(bool(gParams_0.mode_0)) + { + float val_0 = textureLod( + sampler2D(gParams_alphaMap_0, gParams_sampler_0), + _S4.normal_0.xy, + float(0)).x; + + + if(val_0 > float(0)) + { + terminateRayNVX(); + } + else + { + ignoreIntersectionNVX(); + } + } + + return; +} + diff --git a/tests/vkray/closesthit.slang b/tests/vkray/closesthit.slang new file mode 100644 index 000000000..12f2dcd4a --- /dev/null +++ b/tests/vkray/closesthit.slang @@ -0,0 +1,25 @@ +// closesthit.slang +//TEST:CROSS_COMPILE: -profile sm_6_3 -stage closesthit -entry main -target spirv-assembly + +struct ReflectionRay +{ + float4 color; +}; + +StructuredBuffer<float4> colors; + +void main( + BuiltInTriangleIntersectionAttributes attributes, + in out ReflectionRay ioPayload) +{ + uint materialID = InstanceIndex() + + InstanceID() + + PrimitiveIndex() + + HitKind(); + + float4 color = colors[materialID]; + + color *= RayTCurrent() - RayTMin(); + + ioPayload.color = color; +} diff --git a/tests/vkray/closesthit.slang.glsl b/tests/vkray/closesthit.slang.glsl new file mode 100644 index 000000000..2db319a7f --- /dev/null +++ b/tests/vkray/closesthit.slang.glsl @@ -0,0 +1,46 @@ +// closesthit.slang.glsl +#version 460 +#extension GL_NVX_raytracing : require + +layout(std430) buffer _S1 +{ + vec4 colors_0[]; +}; + +struct BuiltInTriangleIntersectionAttributes_0 +{ + vec2 barycentrics_0; +}; + +hitAttributeNVX BuiltInTriangleIntersectionAttributes_0 _S2; + +struct ReflectionRay_0 +{ + vec4 color_0; +}; + +rayPayloadInNVX ReflectionRay_0 _S3; + +void main() +{ + BuiltInTriangleIntersectionAttributes_0 _S4 = _S2; + + uint _S5 = gl_InstanceCustomIndexNVX; + uint _S6 = gl_InstanceID; + + uint _S7 = _S5 + _S6; + uint _S8 = gl_PrimitiveID; + + uint _S9 = _S7 + _S8; + uint _S10 = gl_HitKindNVX; + + vec4 color_1 = colors_0[_S9 + _S10]; + + float _S11 = gl_HitTNVX; + float _S12 = gl_RayTminNVX; + + _S3.color_0 = color_1 * (_S11 - _S12); + + return; +} + diff --git a/tests/vkray/intersection.slang b/tests/vkray/intersection.slang new file mode 100644 index 000000000..e69ccdbfb --- /dev/null +++ b/tests/vkray/intersection.slang @@ -0,0 +1,47 @@ +// intersection.slang +//TEST:CROSS_COMPILE: -profile sm_6_3 -stage intersection -entry main -target spirv-assembly + +struct Sphere +{ + float3 position; + float radius; +}; + +struct SphereHitAttributes +{ + float3 normal; +}; + +bool rayIntersectsSphere( + RayDesc ray, + Sphere sphere, + out float tHit, + out SphereHitAttributes attrs) +{ + // HACK: this is obviously incorrect, + // but we just need some code for testing + tHit = sphere.radius; + attrs.normal = sphere.position; + return tHit >= ray.TMin; +} + +cbuffer U +{ + Sphere gSphere; +} + +void main() +{ + RayDesc ray; + ray.Origin = ObjectRayOrigin(); + ray.Direction = ObjectRayDirection(); + ray.TMin = RayTMin(); + ray.TMax = RayTCurrent(); + + float tHit; + SphereHitAttributes attrs; + if(rayIntersectsSphere(ray, gSphere, tHit, attrs)) + { + ReportHit(tHit, 0, attrs); + } +} diff --git a/tests/vkray/intersection.slang.glsl b/tests/vkray/intersection.slang.glsl new file mode 100644 index 000000000..2fb999947 --- /dev/null +++ b/tests/vkray/intersection.slang.glsl @@ -0,0 +1,86 @@ +//TEST_IGNORE_FILE: +#version 460 + +#extension GL_NVX_raytracing : require + +struct Sphere_0 +{ + vec3 position_0; + float radius_0; +}; + +layout(binding = 0) +layout(std140) +uniform U_0 +{ + Sphere_0 gSphere_0; +}; + +struct RayDesc_0 +{ + vec3 Origin_0; + float TMin_0; + vec3 Direction_0; + float TMax_0; +}; + +struct SphereHitAttributes_0 +{ + vec3 normal_0; +}; + +bool rayIntersectsSphere_0( + RayDesc_0 ray_0, + Sphere_0 sphere_0, + out float tHit_0, + out SphereHitAttributes_0 attrs_0) +{ + tHit_0 = sphere_0.radius_0; + attrs_0.normal_0 = sphere_0.position_0; + return tHit_0 >= ray_0.TMin_0; +} + +hitAttributeNVX SphereHitAttributes_0 a_0; + +bool ReportHit_0(float tHit_1, uint hitKind_0, SphereHitAttributes_0 attributes_0) +{ + a_0 = attributes_0; + bool _S1 = reportIntersectionNVX(tHit_1, hitKind_0); + return _S1; +} + +void main() +{ + RayDesc_0 ray_1; + vec3 _S2 = gl_ObjectRayOriginNVX; + + ray_1.Origin_0 = _S2; + vec3 _S3 = gl_ObjectRayDirectionNVX; + + ray_1.Direction_0 = _S3; + float _S4 = gl_RayTminNVX; + + ray_1.TMin_0 = _S4; + float _S5 = gl_RayTmaxNVX; + + ray_1.TMax_0 = _S5; + + RayDesc_0 _S6 = ray_1; + + Sphere_0 _S7 = gSphere_0; + + float _S8; + SphereHitAttributes_0 _S9; + bool _S10 = rayIntersectsSphere_0(_S6, _S7, _S8, _S9); + + float tHit_2 = _S8; + SphereHitAttributes_0 attrs_1 = _S9; + + if(_S10) + { + bool _S11 = ReportHit_0(tHit_2, (uint((0))), attrs_1); + } + + return; +} + diff --git a/tests/vkray/miss.slang b/tests/vkray/miss.slang new file mode 100644 index 000000000..c99518150 --- /dev/null +++ b/tests/vkray/miss.slang @@ -0,0 +1,11 @@ +//TEST:CROSS_COMPILE: -profile sm_6_3 -stage miss -entry main -target spirv-assembly + +struct ShadowRay +{ + float hitDistance; +}; + +void main(in out ShadowRay ray) +{ + ray.hitDistance = 10000.0f; +} diff --git a/tests/vkray/miss.slang.glsl b/tests/vkray/miss.slang.glsl new file mode 100644 index 000000000..7ced92c24 --- /dev/null +++ b/tests/vkray/miss.slang.glsl @@ -0,0 +1,18 @@ +//TEST_IGNORE_FILE: +#version 460 + +#extension GL_NVX_raytracing : require + +struct ShadowRay_0 +{ + float hitDistance_0; +}; + +rayPayloadInNVX ShadowRay_0 _S1; + +void main() +{ + (_S1.hitDistance_0) = 10000.0f; + return; +} +
\ No newline at end of file diff --git a/tests/vkray/raygen.slang b/tests/vkray/raygen.slang new file mode 100644 index 000000000..ad377938f --- /dev/null +++ b/tests/vkray/raygen.slang @@ -0,0 +1,116 @@ +//TEST:CROSS_COMPILE: -profile glsl_460 -stage raygeneration -entry main -target spirv-assembly + +#define TRACING_EPSILON 1e-6 + +Texture2D samplerPosition; +Texture2D samplerNormal; +SamplerState sampler; + +struct Light { + float4 position; + float4 color; +}; + +struct Uniforms +{ + Light light; + float4 viewPos; + float4x4 view; + float4x4 model; +}; +ConstantBuffer<Uniforms> ubo; + + +layout(rgba8); +RWTexture2D<float4> outputImage; + +RaytracingAccelerationStructure as; + +struct ShadowRay +{ + float hitDistance; +}; + +struct ReflectionRay +{ + float color; +}; + +#define gl_LaunchIDNV DispatchRaysIndex() +#define gl_LaunchSizeNV DispatchRaysDimensions() + +void main() +{ + float2 inUV = float2( + (float(gl_LaunchIDNV.x) + 0.5f) / float(gl_LaunchSizeNV.x), + (float(gl_LaunchIDNV.y) + 0.5f) / float(gl_LaunchSizeNV.y) + ); + + float3 P = samplerPosition.Sample(sampler, inUV).rgb; + float3 N = samplerNormal.Sample(sampler, inUV).rgb * 2.0 - 1.0; + + float3 lightPos = ubo.light.position.xyz; + float3 lightDelta = lightPos - P; + float lightDist = length(lightDelta); + float3 L = normalize(lightDelta); + float atten = 1.0f / (lightDist*lightDist); + + RayDesc ray; + ray.Origin = P; + ray.TMin = TRACING_EPSILON; + ray.Direction = lightDelta; + ray.TMax = lightDist; + + { + ShadowRay shadowRay; + shadowRay.hitDistance = 0; + + TraceRay(as, + // ray flags + 1, + // cull mask + 0xff, + // sbt record offset + 0, + // sbt record stride + 0, + // missIndex + 2, + // ray + ray, + // payload + shadowRay); + + if (shadowRay.hitDistance < lightDist) + { + atten = 0.f; + } + } + + float3 color = ubo.light.color.xyz * saturate(dot(N,L)) * atten; + + + { + ReflectionRay reflectionRay; + TraceRay(as, + // ray flags + 1, + // cull mask + 0xff, + // sbt record offset + 0, + // sbt record stride + 0, + // missIndex + 2, + // ray + ray, + // payload + reflectionRay); + + + color = color + reflectionRay.color; + } + + outputImage[int2(gl_LaunchIDNV.xy)] = float4(color, 1.0); +} diff --git a/tests/vkray/raygen.slang.glsl b/tests/vkray/raygen.slang.glsl new file mode 100644 index 000000000..2df4b9219 --- /dev/null +++ b/tests/vkray/raygen.slang.glsl @@ -0,0 +1,200 @@ +//TEST_IGNORE_FILE: +#version 460 + +#extension GL_NVX_raytracing : require + +#define TRACING_EPSILON 1e-6 + +layout(binding = 0) uniform texture2D samplerPosition_0; +layout(binding = 2) uniform sampler sampler_0; +layout(binding = 1) uniform texture2D samplerNormal_0; + +struct Light_0 +{ + vec4 position_0; + vec4 color_0; +}; + +#define NUM_LIGHTS 17 + +layout(binding = 3) +layout(std140) uniform ubo_0 +{ + Light_0 light_0; + vec4 viewPos_0; + layout(row_major) mat4x4 view_0; + layout(row_major) mat4x4 model_0; +}; + +layout(binding = 5) uniform accelerationStructureNVX as_0; + +struct ShadowRay_0 +{ + float hitDistance_0; +}; +layout(location = 0) rayPayloadNVX ShadowRay_0 p_0; + +struct ReflectionRay_0 +{ + float color_1; +}; +layout(location = 1) rayPayloadNVX ReflectionRay_0 p_1; + +layout(rgba32f) layout(binding = 4) uniform image2D outputImage_0; + +struct RayDesc_0 +{ + vec3 Origin_0; + float TMin_0; + vec3 Direction_0; + float TMax_0; +}; + +void TraceRay_0( + accelerationStructureNVX AccelerationStructure_0, + uint RayFlags_0, + uint InstanceInclusionMask_0, + uint RayContributionToHitGroupIndex_0, + uint MultiplierForGeometryContributionToHitGroupIndex_0, + uint MissShaderIndex_0, + RayDesc_0 Ray_0, + inout ShadowRay_0 Payload_0) +{ + p_0 = Payload_0; + vec3 _S1 = Ray_0.Origin_0; + float _S2 = Ray_0.TMin_0; + vec3 _S3 = Ray_0.Direction_0; + float _S4 = Ray_0.TMax_0; + int _S5 = 0; + traceNVX( + AccelerationStructure_0, + RayFlags_0, + InstanceInclusionMask_0, + RayContributionToHitGroupIndex_0, + MultiplierForGeometryContributionToHitGroupIndex_0, + MissShaderIndex_0, + _S1, + _S2, + _S3, + _S4, + _S5); + Payload_0 = p_0; + return; +} + +float saturate_0(float x_0) +{ + float _S6 = clamp(x_0, float(0), float(1)); + return _S6; +} + +void TraceRay_1( + accelerationStructureNVX AccelerationStructure_1, + uint RayFlags_1, + uint InstanceInclusionMask_1, + uint RayContributionToHitGroupIndex_1, + uint MultiplierForGeometryContributionToHitGroupIndex_1, + uint MissShaderIndex_1, + RayDesc_0 Ray_1, + inout ReflectionRay_0 Payload_1) +{ + p_1 = Payload_1; + vec3 _S7 = Ray_1.Origin_0; + float _S8 = Ray_1.TMin_0; + vec3 _S9 = Ray_1.Direction_0; + float _S10 = Ray_1.TMax_0; + int _S11 = 1; + traceNVX( + AccelerationStructure_1, + RayFlags_1, + InstanceInclusionMask_1, + RayContributionToHitGroupIndex_1, + MultiplierForGeometryContributionToHitGroupIndex_1, + MissShaderIndex_1, + _S7, + _S8, + _S9, + _S10, + _S11); + Payload_1 = p_1; + return; +} + +void main() +{ + float atten_0; + + uvec3 _S12 = uvec3(gl_LaunchIDNVX, 0); + float _S13 = float(_S12.x) + 0.5; + uvec3 _S14 = uvec3(gl_LaunchSizeNVX, 0); + float _S15 = _S13 / float(_S14.x); + uvec3 _S16 = uvec3(gl_LaunchIDNVX, 0); + float _S17 = float(_S16.y) + 0.5; + uvec3 _S18 = uvec3(gl_LaunchSizeNVX, 0); + float _S19 = _S17 / float(_S18.y); + vec2 inUV_0 = vec2(_S15, _S19); + + vec4 _S20 = texture(sampler2D(samplerPosition_0, sampler_0), inUV_0); + vec3 P_0 = _S20.xyz; + + vec4 _S21 = texture(sampler2D(samplerNormal_0, sampler_0), inUV_0); + vec3 N_0 = _S21.xyz * 2.0 - 1.0; + + vec3 lightDelta_0 = light_0.position_0.xyz - P_0; + float lightDist_0 = length(lightDelta_0); + vec3 L_0 = normalize(lightDelta_0); + + float _S22 = 1.0 / (lightDist_0 * lightDist_0); + + RayDesc_0 ray_0; + ray_0.Origin_0 = P_0; + ray_0.TMin_0 = TRACING_EPSILON; + ray_0.Direction_0 = lightDelta_0; + ray_0.TMax_0 = lightDist_0; + + ShadowRay_0 shadowRay_0; + shadowRay_0.hitDistance_0 = float(0); + const uint _S23 = uint(1); + const uint _S24 = uint(0xFF); + const uint _S25 = uint(0); + const uint _S26 = uint(0); + const uint _S27 = uint(2); + + RayDesc_0 _S28 = ray_0; + ShadowRay_0 _S29; + _S29 = shadowRay_0; + TraceRay_0(as_0, _S23, _S24, _S25, _S26, _S27, _S28, _S29); + shadowRay_0 = _S29; + + bool _S30 = shadowRay_0.hitDistance_0 < lightDist_0; + ReflectionRay_0 reflectionRay_0; + if(_S30) + { + atten_0 = (0.00000000000000000000); + } + else + { + atten_0 = _S22; + } + + vec3 _S31 = light_0.color_0.xyz; + float _S32 = dot(N_0, L_0); + float _S33 = saturate_0(_S32); + vec3 color_2 = (_S31 * _S33) * atten_0; + + const uint _S34 = uint(1); + const uint _S35 = uint(255); + const uint _S36 = uint(0); + const uint _S37 = uint(0); + const uint _S38 = uint(2); + RayDesc_0 _S39 = ray_0; + ReflectionRay_0 _S40; + _S40 = reflectionRay_0; + TraceRay_1(as_0, _S34, _S35, _S36, _S37, _S38, _S39, _S40); + + vec3 color_3 = color_2 + _S40.color_1; + + uvec3 _S41 = uvec3(gl_LaunchIDNVX, 0); + imageStore(outputImage_0, ivec2(uvec2(ivec2(_S41.xy))), vec4(color_3, 1.0)); + return; +} |
