From 5e720e7e7e8be20017e331b515024586e1a88c52 Mon Sep 17 00:00:00 2001 From: Tim Foley Date: Thu, 22 Mar 2018 11:21:45 -0700 Subject: Add support for DirectX Raytracing (DXR) (#451) * Add support for DirectX Raytracing (DXR) This is an initial pass to add support to Slang for the shader stages introduced by DirectX Raytracing (DXR). * Add declarations for DXR intrinsic types and functions to the Slang standard library. The way our compilation works, these will then get propagated through the IR as intrinsics and get spit back out again as-is during HLSL code emission. * Declare the DXR-related stages. This is the main work that affects the compiler's C++ implementation rather than being something we can add via the standard library today. * Switch around the encoding of the `Profile` type so that the stage is in the low bits, allowing API users to pass an ordinary `SlangStage` to operations that expect a `SlangProfileID`. - This represents a direction I'd like to push in long term, where the user specifies stage and "feature level" separately rather than using composite profiles like `vs_6_0`. The introduction of these new stages seems like a good point to try and make a clean break here and not introduce, e.g., `rgs_6_1` for ray generatin shaders. * Upgrade "effective profile" computation so that it advances the required version based on the specified stage (e.g., DXR stages seem to require at least shader model 6.1). - This is a bit of a kludge overall, but ideally we don't want a typical user to have to think about "feature level" stuff much at all. The ideal workflow is that they just hand us a source file and we work out entry points and their required feature levels in the compiler (and let the user query it when we are done). Until we implement that for real, stopgaps like this are required. Overall these are relatively small changes for supporting some major new API behavior. Slang's design helps out here, by allowing a lot of things to be specified in the stdlib (including generic intrinsic functions), but some of this is also owed to the DXIL-influenced design of DXR - e.g., the use of global functions in place of `SV_*` semantics. * fixup: typos * Fixup: use `pixel` instead of `fragment` as primary stage name This is to match HLSL conventions when generating output code, even if the Slang project officially favors the more correct term "fragment shader." --- source/slang/check.cpp | 16 +++--- source/slang/emit.cpp | 25 +++++----- source/slang/hlsl.meta.slang | 109 +++++++++++++++++++++++++++++++++++++++++ source/slang/hlsl.meta.slang.h | 109 +++++++++++++++++++++++++++++++++++++++++ source/slang/profile-defs.h | 33 +++++++++++-- source/slang/profile.h | 11 +++-- source/slang/slang.cpp | 35 +++++++++++++ 7 files changed, 308 insertions(+), 30 deletions(-) (limited to 'source') diff --git a/source/slang/check.cpp b/source/slang/check.cpp index 070d4c606..dbd9b37b7 100644 --- a/source/slang/check.cpp +++ b/source/slang/check.cpp @@ -1488,15 +1488,13 @@ namespace Slang Stage stage; } kStages[] = { - { "vertex", Stage::Vertex }, - { "hull", Stage::Hull }, - { "domain", Stage::Domain }, - { "geometry", Stage::Geometry }, - { "fragment", Stage::Fragment }, - { "compute", Stage::Compute }, - - // Allow `pixel` as an alias of `fragment` - { "pixel", Stage::Fragment }, + #define PROFILE_STAGE(ID, NAME, ENUM) \ + { #NAME, Stage::ID }, + + #define PROFILE_STAGE_ALIAS(ID, NAME, VAL) \ + { #NAME, Stage::ID }, + + #include "profile-defs.h" }; for(auto entry : kStages) diff --git a/source/slang/emit.cpp b/source/slang/emit.cpp index ace8a1559..98ce61b74 100644 --- a/source/slang/emit.cpp +++ b/source/slang/emit.cpp @@ -127,7 +127,7 @@ struct SharedEmitContext // The "effective" profile that is being used to emit code, // combining information from the target and entry point. - Profile effctiveProfile; + Profile effectiveProfile; }; struct EmitContext @@ -4368,10 +4368,10 @@ struct EmitVisitor } #endif - auto effctiveProfile = context->shared->effctiveProfile; - if(effctiveProfile.getFamily() == ProfileFamily::GLSL) + auto effectiveProfile = context->shared->effectiveProfile; + if(effectiveProfile.getFamily() == ProfileFamily::GLSL) { - requireGLSLVersion(effctiveProfile.GetVersion()); + requireGLSLVersion(effectiveProfile.GetVersion()); } // HACK: We aren't picking GLSL versions carefully right now, @@ -6746,10 +6746,10 @@ emitDeclImpl(decl, nullptr); } void emitIREntryPointAttributes_HLSL( - EmitContext* /*ctx*/, + EmitContext* ctx, EntryPointLayout* entryPointLayout) { - auto profile = entryPointLayout->profile; + auto profile = ctx->shared->effectiveProfile; auto stage = profile.GetStage(); if(profile.getFamily() == ProfileFamily::DX) @@ -6759,12 +6759,11 @@ emitDeclImpl(decl, nullptr); char const* stageName = nullptr; switch(stage) { - case Stage::Compute: stageName = "compute"; - case Stage::Vertex: stageName = "vertex"; - case Stage::Hull: stageName = "hull"; - case Stage::Domain: stageName = "domain"; - case Stage::Geometry: stageName = "geometry"; - case Stage::Fragment: stageName = "pixel"; + #define PROFILE_STAGE(ID, NAME, ENUM) \ + case Stage::ID: stageName = #NAME; break; + + #include "profile-defs.h" + default: break; } @@ -8230,7 +8229,7 @@ String emitEntryPoint( sharedContext.target = target; sharedContext.finalTarget = targetRequest->target; sharedContext.entryPoint = entryPoint; - sharedContext.effctiveProfile = getEffectiveProfile(entryPoint, targetRequest); + sharedContext.effectiveProfile = getEffectiveProfile(entryPoint, targetRequest); if (entryPoint) { diff --git a/source/slang/hlsl.meta.slang b/source/slang/hlsl.meta.slang index 15579e512..7356eccbe 100644 --- a/source/slang/hlsl.meta.slang +++ b/source/slang/hlsl.meta.slang @@ -1121,3 +1121,112 @@ for (int aa = 0; aa < kBaseBufferAccessLevelCount; ++aa) sb << "};\n"; } }}}} + + +// DirectX Raytracing (DXR) Support +// +// The following is based on the experimental DXR SDK v0.09.01. +// +// Numbering follows the sections in the "D3D12 Raytracing Functional Spec" v0.09 (2018-03-12) +// + +// 10.1.1 - Ray Flags + +typedef uint RAY_FLAG; + +static const RAY_FLAG RAY_FLAG_NONE = 0x00; +static const RAY_FLAG RAY_FLAG_FORCE_OPAQUE = 0x01; +static const RAY_FLAG RAY_FLAG_FORCE_NON_OPAQUE = 0x02; +static const RAY_FLAG RAY_FLAG_ACCEPT_FIRST_HIT_AND_END_SEARCH = 0x04; +static const RAY_FLAG RAY_FLAG_SKIP_CLOSEST_HIT_SHADER = 0x08; +static const RAY_FLAG RAY_FLAG_CULL_BACK_FACING_TRIANGLES = 0x10; +static const RAY_FLAG RAY_FLAG_CULL_FRONT_FACING_TRIANGLES = 0x20; +static const RAY_FLAG RAY_FLAG_CULL_OPAQUE = 0x40; +static const RAY_FLAG RAY_FLAG_CULL_NON_OPAQUE = 0x80; + +// 10.1.2 - Ray Description Structure + +__builtin struct RayDesc +{ + float3 Origin; + float TMin; + float3 Direction; + float TMax; +}; + +// 10.1.3 - Ray Acceleration Structure + +__builtin __magic_type(UntypedBufferResourceType) +struct RaytracingAccelerationStructure {}; + +// 10.1.4 - Subobject Definitions + +// TODO: We may decide to support these, but their reliance on C++ implicit +// constructor call syntax (`SomeType someVar(arg0, arg1);`) makes them +// annoying for the current Slang parsing strategy, and using global variables +// for this stuff comes across as a kludge rather than the best possible design. + +// 10.1.5 - Intersection Attributes Structure + +__builtin struct BuiltInTriangleIntersectionAttributes +{ + float2 barycentrics; +}; + +// 10.2 Shaders + +// Right now new shader stages need to be added directly to the compiler +// implementation, rather than being something that can be declared in the stdlib. + +// 10.3 - Intrinsics + +// 10.3.1 +void CallShader(uint ShaderIndex, inout param_t Parameter); + +// 10.3.2 +void TraceRay( + RaytracingAccelerationStructure AccelerationStructure, + uint RayFlags, + uint InstanceInclusionMask, + uint RayContributionToHitGroupIndex, + uint MultiplierForGeometryContributionToHitGroupIndex, + uint MissShaderIndex, + RayDesc Ray, + inout payload_t Payload); + +// 10.3.3 +bool ReportHit(float THit, uint HitKind, attr_t Attributes); + +// 10.3.4 +void IgnoreHit(); + +// 10.3.5 +void AcceptHitAndEndSearch(); + +// 10.4 - System Values and Special Semantics + +// TODO: Many of these functions need to be restricted so that +// they can only be accessed from specific stages. + +// 10.4.1 - Ray Dispatch System Values +uint2 DispatchRaysIndex(); +uint2 DispatchRaysDimensions(); + +// 10.4.2 - Ray System Values +float3 WorldRayOrigin(); +float3 WorldRayDirection(); +float RayTMin(); +float RayTCurrent(); +uint RayFlags(); + +// 10.4.3 - Primitive/Object Space System Values +uint InstanceIndex(); +uint InstanceID(); +uint PrimitiveIndex(); +float3 ObjectRayOrigin(); +float3 ObjectRayDirection(); +float3x4 ObjectToWorld(); +float3x4 WorldToObject(); + +// 10.4.4 - Hit Specific System values +uint HitKind(); diff --git a/source/slang/hlsl.meta.slang.h b/source/slang/hlsl.meta.slang.h index d35f96ba3..134a3172f 100644 --- a/source/slang/hlsl.meta.slang.h +++ b/source/slang/hlsl.meta.slang.h @@ -1127,3 +1127,112 @@ for (int aa = 0; aa < kBaseBufferAccessLevelCount; ++aa) sb << "};\n"; } SLANG_RAW("\n") +SLANG_RAW("\n") +SLANG_RAW("\n") +SLANG_RAW("// DirectX Raytracing (DXR) Support\n") +SLANG_RAW("//\n") +SLANG_RAW("// The following is based on the experimental DXR SDK v0.09.01.\n") +SLANG_RAW("//\n") +SLANG_RAW("// Numbering follows the sections in the \"D3D12 Raytracing Functional Spec\" v0.09 (2018-03-12)\n") +SLANG_RAW("//\n") +SLANG_RAW("\n") +SLANG_RAW("// 10.1.1 - Ray Flags\n") +SLANG_RAW("\n") +SLANG_RAW("typedef uint RAY_FLAG;\n") +SLANG_RAW("\n") +SLANG_RAW("static const RAY_FLAG RAY_FLAG_NONE = 0x00;\n") +SLANG_RAW("static const RAY_FLAG RAY_FLAG_FORCE_OPAQUE = 0x01;\n") +SLANG_RAW("static const RAY_FLAG RAY_FLAG_FORCE_NON_OPAQUE = 0x02;\n") +SLANG_RAW("static const RAY_FLAG RAY_FLAG_ACCEPT_FIRST_HIT_AND_END_SEARCH = 0x04;\n") +SLANG_RAW("static const RAY_FLAG RAY_FLAG_SKIP_CLOSEST_HIT_SHADER = 0x08;\n") +SLANG_RAW("static const RAY_FLAG RAY_FLAG_CULL_BACK_FACING_TRIANGLES = 0x10;\n") +SLANG_RAW("static const RAY_FLAG RAY_FLAG_CULL_FRONT_FACING_TRIANGLES = 0x20;\n") +SLANG_RAW("static const RAY_FLAG RAY_FLAG_CULL_OPAQUE = 0x40;\n") +SLANG_RAW("static const RAY_FLAG RAY_FLAG_CULL_NON_OPAQUE = 0x80;\n") +SLANG_RAW("\n") +SLANG_RAW("// 10.1.2 - Ray Description Structure\n") +SLANG_RAW("\n") +SLANG_RAW("__builtin struct RayDesc\n") +SLANG_RAW("{\n") +SLANG_RAW(" float3 Origin;\n") +SLANG_RAW(" float TMin;\n") +SLANG_RAW(" float3 Direction;\n") +SLANG_RAW(" float TMax;\n") +SLANG_RAW("};\n") +SLANG_RAW("\n") +SLANG_RAW("// 10.1.3 - Ray Acceleration Structure\n") +SLANG_RAW("\n") +SLANG_RAW("__builtin __magic_type(UntypedBufferResourceType)\n") +SLANG_RAW("struct RaytracingAccelerationStructure {};\n") +SLANG_RAW("\n") +SLANG_RAW("// 10.1.4 - Subobject Definitions\n") +SLANG_RAW("\n") +SLANG_RAW("// TODO: We may decide to support these, but their reliance on C++ implicit\n") +SLANG_RAW("// constructor call syntax (`SomeType someVar(arg0, arg1);`) makes them\n") +SLANG_RAW("// annoying for the current Slang parsing strategy, and using global variables\n") +SLANG_RAW("// for this stuff comes across as a kludge rather than the best possible design.\n") +SLANG_RAW("\n") +SLANG_RAW("// 10.1.5 - Intersection Attributes Structure\n") +SLANG_RAW("\n") +SLANG_RAW("__builtin struct BuiltInTriangleIntersectionAttributes\n") +SLANG_RAW("{\n") +SLANG_RAW(" float2 barycentrics;\n") +SLANG_RAW("};\n") +SLANG_RAW("\n") +SLANG_RAW("// 10.2 Shaders\n") +SLANG_RAW("\n") +SLANG_RAW("// Right now new shader stages need to be added directly to the compiler\n") +SLANG_RAW("// implementation, rather than being something that can be declared in the stdlib.\n") +SLANG_RAW("\n") +SLANG_RAW("// 10.3 - Intrinsics\n") +SLANG_RAW("\n") +SLANG_RAW("// 10.3.1\n") +SLANG_RAW("void CallShader(uint ShaderIndex, inout param_t Parameter);\n") +SLANG_RAW("\n") +SLANG_RAW("// 10.3.2\n") +SLANG_RAW("void TraceRay(\n") +SLANG_RAW(" RaytracingAccelerationStructure AccelerationStructure,\n") +SLANG_RAW(" uint RayFlags,\n") +SLANG_RAW(" uint InstanceInclusionMask,\n") +SLANG_RAW(" uint RayContributionToHitGroupIndex,\n") +SLANG_RAW(" uint MultiplierForGeometryContributionToHitGroupIndex,\n") +SLANG_RAW(" uint MissShaderIndex,\n") +SLANG_RAW(" RayDesc Ray,\n") +SLANG_RAW(" inout payload_t Payload);\n") +SLANG_RAW("\n") +SLANG_RAW("// 10.3.3\n") +SLANG_RAW("bool ReportHit(float THit, uint HitKind, attr_t Attributes);\n") +SLANG_RAW("\n") +SLANG_RAW("// 10.3.4\n") +SLANG_RAW("void IgnoreHit();\n") +SLANG_RAW("\n") +SLANG_RAW("// 10.3.5\n") +SLANG_RAW("void AcceptHitAndEndSearch();\n") +SLANG_RAW("\n") +SLANG_RAW("// 10.4 - System Values and Special Semantics\n") +SLANG_RAW("\n") +SLANG_RAW("// TODO: Many of these functions need to be restricted so that\n") +SLANG_RAW("// they can only be accessed from specific stages.\n") +SLANG_RAW("\n") +SLANG_RAW("// 10.4.1 - Ray Dispatch System Values\n") +SLANG_RAW("uint2 DispatchRaysIndex();\n") +SLANG_RAW("uint2 DispatchRaysDimensions();\n") +SLANG_RAW("\n") +SLANG_RAW("// 10.4.2 - Ray System Values\n") +SLANG_RAW("float3 WorldRayOrigin();\n") +SLANG_RAW("float3 WorldRayDirection();\n") +SLANG_RAW("float RayTMin();\n") +SLANG_RAW("float RayTCurrent();\n") +SLANG_RAW("uint RayFlags();\n") +SLANG_RAW("\n") +SLANG_RAW("// 10.4.3 - Primitive/Object Space System Values\n") +SLANG_RAW("uint InstanceIndex();\n") +SLANG_RAW("uint InstanceID();\n") +SLANG_RAW("uint PrimitiveIndex();\n") +SLANG_RAW("float3 ObjectRayOrigin();\n") +SLANG_RAW("float3 ObjectRayDirection();\n") +SLANG_RAW("float3x4 ObjectToWorld();\n") +SLANG_RAW("float3x4 WorldToObject();\n") +SLANG_RAW("\n") +SLANG_RAW("// 10.4.4 - Hit Specific System values\n") +SLANG_RAW("uint HitKind();\n") diff --git a/source/slang/profile-defs.h b/source/slang/profile-defs.h index 177c4a0c5..e7000bfa2 100644 --- a/source/slang/profile-defs.h +++ b/source/slang/profile-defs.h @@ -23,7 +23,7 @@ #endif #ifndef PROFILE_STAGE_ALIAS -#define PROFILE_STAGE_ALIAS(TAG, NAME) /* empty */ +#define PROFILE_STAGE_ALIAS(TAG, NAME, VAL) /* empty */ #endif @@ -57,10 +57,25 @@ PROFILE_STAGE(Vertex, vertex, SLANG_STAGE_VERTEX) PROFILE_STAGE(Hull, hull, SLANG_STAGE_HULL) PROFILE_STAGE(Domain, domain, SLANG_STAGE_DOMAIN) PROFILE_STAGE(Geometry, geometry, SLANG_STAGE_GEOMETRY) -PROFILE_STAGE(Fragment, fragment, SLANG_STAGE_FRAGMENT) +PROFILE_STAGE(Pixel, pixel, SLANG_STAGE_FRAGMENT) PROFILE_STAGE(Compute, compute, SLANG_STAGE_COMPUTE) -PROFILE_STAGE_ALIAS(Fragment, pixel) +PROFILE_STAGE(RayGeneration, raygeneration, SLANG_STAGE_RAY_GENERATION) +PROFILE_STAGE(Intersection, intersection, SLANG_STAGE_INTERSECTION) +PROFILE_STAGE(AnyHit, anyhit, SLANG_STAGE_ANY_HIT) +PROFILE_STAGE(ClosestHit, closesthit, SLANG_STAGE_CLOSEST_HIT) +PROFILE_STAGE(Miss, miss, SLANG_STAGE_MISS) +PROFILE_STAGE(Callable, callable, SLANG_STAGE_CALLABLE) + + +// Note: HLSL and Direct3D convention erroneously uses the term "Pixel Shader" +// for the thing that shades *fragments*. Slang strives to treat the more correct +// term "Fragment Shader" as the primary one, but in order to be compatible with +// existing HLSL conventions, we need to treat `pixel` as the official stage +// name and `fragment` as an alias for it here, because the lower-case stage +// names are used to drive output HLSL generation. +// +PROFILE_STAGE_ALIAS(Fragment, fragment, Pixel) // Profile families @@ -151,6 +166,18 @@ PROFILE(DX_Vertex_6_0, vs_6_0, Vertex, DX_6_0) PROFILE(DX_Vertex_6_1, vs_6_1, Vertex, DX_6_1) PROFILE(DX_Vertex_6_2, vs_6_2, Vertex, DX_6_2) +// TODO: consider making `lib_*_*` alias these... +PROFILE(DX_None_4_0, sm_4_0, Unknown, DX_4_0) +PROFILE(DX_None_4_0_Level_9_0, sm_4_0_level_9_0, Unknown, DX_4_0_Level_9_0) +PROFILE(DX_None_4_0_Level_9_1, sm_4_0_level_9_1, Unknown, DX_4_0_Level_9_1) +PROFILE(DX_None_4_0_Level_9_3, sm_4_0_level_9_3, Unknown, DX_4_0_Level_9_3) +PROFILE(DX_None_4_1, sm_4_1, Unknown, DX_4_1) +PROFILE(DX_None_5_0, sm_5_0, Unknown, DX_5_0) +PROFILE(DX_None_5_1, sm_5_1, Unknown, DX_5_1) +PROFILE(DX_None_6_0, sm_6_0, Unknown, DX_6_0) +PROFILE(DX_None_6_1, sm_6_1, Unknown, DX_6_1) +PROFILE(DX_None_6_2, sm_6_2, Unknown, DX_6_2) + // Define all the GLSL profiles #define P(UPPER, LOWER, VERSION) \ diff --git a/source/slang/profile.h b/source/slang/profile.h index d6a2a39af..ceccf20a9 100644 --- a/source/slang/profile.h +++ b/source/slang/profile.h @@ -41,6 +41,7 @@ namespace Slang { Unknown = SLANG_STAGE_NONE, #define PROFILE_STAGE(TAG, NAME, VAL) TAG = VAL, +#define PROFILE_STAGE_ALIAS(TAG, NAME, VAL) TAG = VAL, #include "profile-defs.h" }; @@ -53,7 +54,7 @@ namespace Slang { Unknown, -#define PROFILE(TAG, NAME, STAGE, VERSION) TAG = (uint32_t(Stage::STAGE) << 16) | uint32_t(ProfileVersion::VERSION), +#define PROFILE(TAG, NAME, STAGE, VERSION) TAG = (uint32_t(ProfileVersion::VERSION) << 16) | uint32_t(Stage::STAGE), #define PROFILE_ALIAS(TAG, DEF, NAME) TAG = DEF, #include "profile-defs.h" }; @@ -66,16 +67,16 @@ namespace Slang bool operator==(Profile const& other) const { return raw == other.raw; } bool operator!=(Profile const& other) const { return raw != other.raw; } - Stage GetStage() const { return Stage((uint32_t(raw) >> 16) & 0xFFFF); } + Stage GetStage() const { return Stage(uint32_t(raw) & 0xFFFF); } void setStage(Stage stage) { - raw = (raw & 0x0000FFFF) | (uint32_t(stage) << 16); + raw = (raw & ~0xFFFF) | uint32_t(stage); } - ProfileVersion GetVersion() const { return ProfileVersion(uint32_t(raw) & 0xFFFF); } + ProfileVersion GetVersion() const { return ProfileVersion((uint32_t(raw) >> 16) & 0xFFFF); } void setVersion(ProfileVersion version) { - raw = (raw & ~0xFFFF) | uint32_t(version); + raw = (raw & 0x0000FFFF) | (uint32_t(version) << 16); } ProfileFamily getFamily() const { return getProfileFamily(GetVersion()); } diff --git a/source/slang/slang.cpp b/source/slang/slang.cpp index 4fa6f5130..2861b82ca 100644 --- a/source/slang/slang.cpp +++ b/source/slang/slang.cpp @@ -138,6 +138,41 @@ Profile getEffectiveProfile(EntryPointRequest* entryPoint, TargetRequest* target } } + // Now consider the possibility that the chosen stage might force an "upgrade" + // to the profile level. + ProfileVersion stageMinVersion = ProfileVersion::Unknown; + switch( effectiveProfile.getFamily() ) + { + case ProfileFamily::DX: + switch(effectiveProfile.GetStage()) + { + default: + break; + + case Stage::RayGeneration: + case Stage::Intersection: + case Stage::ClosestHit: + case Stage::AnyHit: + case Stage::Miss: + case Stage::Callable: + stageMinVersion = ProfileVersion::DX_6_1; + break; + + // TODO: Add equivalent logic for geometry, tessellation, and compute stages. + } + break; + + // TODO: Add equivalent logic for the GL/VK case. + + default: + break; + } + + if( stageMinVersion > effectiveProfile.GetVersion() ) + { + effectiveProfile.setVersion(stageMinVersion); + } + return effectiveProfile; } -- cgit v1.2.3