diff options
| author | Tim Foley <tfoleyNV@users.noreply.github.com> | 2020-02-19 08:56:46 -0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-02-19 08:56:46 -0800 |
| commit | 1d9152bd2d0b1234680ce6a9f7ef940d7f179e9a (patch) | |
| tree | a4672a712ddc9217ac44fc98fcefcaccc04244e8 | |
| parent | 45d1a680634c59d1081ed09dddaa444695296492 (diff) | |
Fixes for DXR 1.1 RayQuery type (#1227)
The previous change that added `RayQuery` to the standard library didn't mark it as any kind of intrinsic, so the first fix here was to add the appopriate attribtue to the stdlib declaration of `RayQuery`.
Next I found that the legalization pass was obliterating the `RayQuery` type because it had no members, and thus looked like an empty `struct` (which we eliminate for a variety of reasons). I fixed that by adding a check for a target-intrinsic decoration in type legalization.
Next I found that the type wasn't emitted correctly because our generic specialization was turning `RayQuery<0>` into a new type `RayQuery_0` (which is what our specialization is designed to do, after all).
I then disabled generic specialization for types that are marked as target intrinsics (which probably renders the preceding fix moot).
Finally, I found that the emit logic for types in HLSL wasn't handling the case of a generic intrinsic type that didn't also use its own dedicated opcode. I fixes that up by adding a specific case for `IRSpecialize` as a late catch-all.
After all these changes, a declaration of a `RayQuery` variable seems to Just Work (even without any new/improved behavior for handling default constructors).
One potential gotcha looking forward is that my checks for `IRTargetIntrinsicDecoration` aren't checking what target the decoration is for. This is fine for now because there are only two types using the decoration right now (`RayDesc` and `RayQuery`), and the special cases above are reasonable for both of them. If/when we have more target-intrinsic types with this decoration, and some of them are only intrinsic for specific targets, then we will need to revisit this choice and either:
* make these checks perform filtering based on the "current" target (similar to what the emit logic has today), or
* (more likely) make the linking and target-specialization step strip out any target-intrinsic decorations that aren't the right one(s) for the current target
Note that this change doesn't include a test case yet because I don't have a DXR 1.1 ready version of dxc to test against. I have manually confirmed that appropriate Slang input seems to be producing reasonable HLSL output when using these functions, but I cannot yet try to check that in (using an HLSL file for the expected output would be quite fragile).
| -rw-r--r-- | source/slang/hlsl.meta.slang | 10 | ||||
| -rw-r--r-- | source/slang/hlsl.meta.slang.h | 11 | ||||
| -rw-r--r-- | source/slang/slang-emit-hlsl.cpp | 16 | ||||
| -rw-r--r-- | source/slang/slang-ir-specialize.cpp | 12 | ||||
| -rw-r--r-- | source/slang/slang-legalize-types.cpp | 8 |
5 files changed, 55 insertions, 2 deletions
diff --git a/source/slang/hlsl.meta.slang b/source/slang/hlsl.meta.slang index f7707cc6d..8fd2a272a 100644 --- a/source/slang/hlsl.meta.slang +++ b/source/slang/hlsl.meta.slang @@ -1869,6 +1869,10 @@ int dot4add_i8packed(uint left, uint right, int acc); float dot2add(float2 left, float2 right, float acc); // +// Shader Model 6.5 +// + +// // Mesh Shaders // @@ -1888,6 +1892,9 @@ void DispatchMesh<P>(uint threadGroupCountX, uint threadGroupCountY, uint thread // DXR 1.1 and `TraceRayInline` support // +// Get the index of the geometry that was hit in an intersection, any-hit, or closest-hit shader +uint GeometryIndex(); + // Status of whether a (closest) hit has been committed in a `RayQuery`. typedef uint COMMITTED_STATUS; @@ -1927,7 +1934,8 @@ static const CANDIDATE_TYPE CANDIDATE_PROCEDURAL_PRIMITIVE = 1; // code can resume to continue tracing the ray, and which yields // back to the user code at interesting events along the ray. // -struct RayQuery<let rayFlags : RAY_FLAG = RAY_FLAG_NONE> +__target_intrinsic(hlsl, RayQuery) +struct RayQuery <let rayFlags : RAY_FLAG = RAY_FLAG_NONE> { // Initialize a ray-tracing query. // diff --git a/source/slang/hlsl.meta.slang.h b/source/slang/hlsl.meta.slang.h index c0b875df5..c72374786 100644 --- a/source/slang/hlsl.meta.slang.h +++ b/source/slang/hlsl.meta.slang.h @@ -1949,6 +1949,10 @@ SLANG_RAW("// May not produce infinities or NaNs for intermediate results that o SLANG_RAW("float dot2add(float2 left, float2 right, float acc);\n") SLANG_RAW("\n") SLANG_RAW("//\n") +SLANG_RAW("// Shader Model 6.5\n") +SLANG_RAW("//\n") +SLANG_RAW("\n") +SLANG_RAW("//\n") SLANG_RAW("// Mesh Shaders\n") SLANG_RAW("//\n") SLANG_RAW("\n") @@ -1968,6 +1972,9 @@ SLANG_RAW("//\n") SLANG_RAW("// DXR 1.1 and `TraceRayInline` support\n") SLANG_RAW("//\n") SLANG_RAW("\n") +SLANG_RAW("// Get the index of the geometry that was hit in an intersection, any-hit, or closest-hit shader\n") +SLANG_RAW("uint GeometryIndex();\n") +SLANG_RAW("\n") SLANG_RAW("// Status of whether a (closest) hit has been committed in a `RayQuery`.\n") SLANG_RAW("typedef uint COMMITTED_STATUS;\n") SLANG_RAW("\n") @@ -2007,7 +2014,9 @@ SLANG_RAW("// The ray query is effectively a coroutine that user shader\n") SLANG_RAW("// code can resume to continue tracing the ray, and which yields\n") SLANG_RAW("// back to the user code at interesting events along the ray.\n") SLANG_RAW("//\n") -SLANG_RAW("struct RayQuery<let rayFlags : RAY_FLAG = RAY_FLAG_NONE>\n") +SLANG_RAW("//__generic<let rayFlags : RAY_FLAG = RAY_FLAG_NONE>\n") +SLANG_RAW("__target_intrinsic(hlsl, RayQuery)\n") +SLANG_RAW("struct RayQuery <let rayFlags : RAY_FLAG = RAY_FLAG_NONE>\n") SLANG_RAW("{\n") SLANG_RAW(" // Initialize a ray-tracing query.\n") SLANG_RAW(" //\n") diff --git a/source/slang/slang-emit-hlsl.cpp b/source/slang/slang-emit-hlsl.cpp index 4225b1bf3..1d4b6a317 100644 --- a/source/slang/slang-emit-hlsl.cpp +++ b/source/slang/slang-emit-hlsl.cpp @@ -659,6 +659,22 @@ void HLSLSourceEmitter::emitSimpleTypeImpl(IRType* type) return; } + else if(auto specializedType = as<IRSpecialize>(type)) + { + // If a `specialize` instruction made it this far, then + // it represents an intrinsic generic type. + // + emitSimpleType((IRType*) getSpecializedValue(specializedType)); + m_writer->emit("<"); + UInt argCount = specializedType->getArgCount(); + for (UInt ii = 0; ii < argCount; ++ii) + { + if (ii != 0) m_writer->emit(", "); + emitVal(specializedType->getArg(ii), getInfo(EmitOp::General)); + } + m_writer->emit(" >"); + return; + } // HACK: As a fallback for HLSL targets, assume that the name of the // instruction being used is the same as the name of the HLSL type. diff --git a/source/slang/slang-ir-specialize.cpp b/source/slang/slang-ir-specialize.cpp index 5f84da478..6baf8fca5 100644 --- a/source/slang/slang-ir-specialize.cpp +++ b/source/slang/slang-ir-specialize.cpp @@ -283,6 +283,18 @@ struct SpecializationContext continue; } + // We should never specialize intrinsic types. + // + // TODO: This logic assumes that having *any* target + // intrinsic decoration makes a type skip specialization, + // even if the decoration isn't applicable to the + // current target. This should be made true in practice + // by having the linking step strip/skip decorations + // that aren't applicable to the chosen target at link time. + // + if(as<IRStructType>(val) && val->findDecoration<IRTargetIntrinsicDecoration>()) + return false; + // Once we've found the leaf value that will be produced // after all specialization is complete, we can check // whether it looks like a definition or not. diff --git a/source/slang/slang-legalize-types.cpp b/source/slang/slang-legalize-types.cpp index cc729e1cf..ad4ec46cd 100644 --- a/source/slang/slang-legalize-types.cpp +++ b/source/slang/slang-legalize-types.cpp @@ -1095,6 +1095,14 @@ LegalType legalizeTypeImpl( if(!type) return LegalType::simple(nullptr); + // It might be that the type we are looking at is + // an intrinsic type on our chosen target, in which + // case we should never legalize it, figuring that + // the target defines its semantics fully. + // + if(type->findDecoration<IRTargetIntrinsicDecoration>()) + return LegalType::simple(type); + context->builder->setInsertBefore(type); if (auto uniformBufferType = as<IRUniformParameterGroupType>(type)) |
