yum-mirror/slang
Making it easier to work with shaders
git clone https://git.yummers.dev/yum-mirror/slang
20bd48659
master
1// trace-ray-inline.slang 2 3//TEST:CROSS_COMPILE:-target dxil-asm -stage compute -profile sm_6_5 -entry main -line-directive-mode none 4//TEST:SIMPLE(filecheck=CHECK):-target spirv-asm -stage compute -profile glsl_460+GL_EXT_ray_query -entry main -line-directive-mode none 5 6// CHECK: OpCapability RayQueryKHR 7// CHECK: OpExtension "SPV_KHR_ray_query" 8// CHECK: OpRayQueryInitializeKHR 9// CHECK: OpRayQueryProceedKHR 10// CHECK: OpRayQueryGetIntersectionTypeKHR 11// CHECK: OpRayQueryConfirmIntersectionKHR 12 13// The goal of this shader is to use all the main pieces 14// of functionality in DXR 1.1's `TraceRayInline` feature, 15// to ensure that they survive translation to HLSL. 16 17// In order to trace rays, we need an acceleration structure. 18// 19RaytracingAccelerationStructure myAccelerationStructure; 20 21// We also need to decide what to do with hits/misses. 22// The `TraceRayInline` approach eschews separate shader 23// stages for RT, and instead expects users to write 24// those operations as subroutines instead. 25// 26// We will mimic the style and naming of DXR 1.0 here 27// to try and make the parallels clear. 28// 29// We start with a ray "payload" type that will be 30// used for input/output on hit and miss shaders 31// 32 33struct MyRayPayload 34{ 35 int value; 36}; 37 38// The first and simplest shader is the miss shader. 39// 40void myMiss(inout MyRayPayload payload) 41{ 42 payload.value = 0; 43} 44 45// Next, up is a closest hit shader for opaque triangles. 46// 47void myTriangleClosestHit(inout MyRayPayload payload) 48{ 49 payload.value = 1; 50} 51 52// In order to support alpha testing, we need an any-hit 53// shader for triangles. 54// 55// In this case, the return value is used to specify 56// whether the hit should be accepted (true) or ignored (false). 57// 58bool myTriangleAnyHit(inout MyRayPayload payload) 59{ 60 unmodified(payload); 61 return true; 62} 63 64// Procedural primitives are different than triangles 65// in that they need user-defined hit attributes. 66// 67struct MyProceduralHitAttrs { int value; } 68 69// Otherwise, the closest- and any-hit shaders 70// for procedural primitives are similar to those 71// for triangles. 72// 73void myProceduralClosestHit(inout MyRayPayload payload, MyProceduralHitAttrs attrs) 74{ 75 payload.value = attrs.value; 76} 77bool myProceduralAnyHit(inout MyRayPayload payload) 78{ 79 unmodified(payload); 80 return true; 81} 82 83// The new piece of the puzzle for procedural primitives 84// is the intersection shader, which should be able to 85// report zero or more intersections. 86// 87// For now we will only deal with the single-intersection 88// case. 89// 90bool myProceduralIntersection(inout float tHit, inout MyProceduralHitAttrs hitAttrs) 91{ 92 unmodified(tHit); 93 unmodified(hitAttrs); 94 return true; 95} 96 97RWStructuredBuffer<int> resultBuffer; 98 99// In order to kick of tracing we need the properties of a ray 100// query to trace, so we will pipe those in via a constant buffer. 101// 102cbuffer C 103{ 104 float3 origin; 105 float tMin; 106 float3 direction; 107 float tMax; 108 uint rayFlags; 109 uint instanceMask; 110 uint shouldStopAtFirstHit; 111} 112 113// The actual tracing is handled by a compute shader, 114// which here takes on the role of a ray generation shader. 115// 116void main(uint3 tid : SV_DispatchThreadID) 117{ 118 uint index = tid.x; 119 120 RayQuery<RAY_FLAG_SKIP_PROCEDURAL_PRIMITIVES> query; 121 MyProceduralHitAttrs committedProceduralAttrs; 122 123 MyRayPayload payload = { -1 }; 124 RayDesc ray = { origin, tMin, direction, tMax }; 125 query.TraceRayInline( 126 myAccelerationStructure, 127 rayFlags, 128 instanceMask, 129 ray); 130 131 132 for(;;) 133 { 134 if(!query.Proceed()) break; 135 136 switch(query.CandidateType()) 137 { 138 case CANDIDATE_PROCEDURAL_PRIMITIVE: 139 { 140 MyProceduralHitAttrs candidateProceduralAttrs = { 0 }; 141 float tHit = 0.0f; 142 if(myProceduralIntersection(tHit, candidateProceduralAttrs)) 143 { 144 if(myProceduralAnyHit(payload)) 145 { 146 query.CommitProceduralPrimitiveHit(tHit); 147 committedProceduralAttrs = candidateProceduralAttrs; 148 if(shouldStopAtFirstHit != 0) 149 query.Abort(); 150 } 151 } 152 } 153 break; 154 155 case CANDIDATE_NON_OPAQUE_TRIANGLE: 156 { 157 if(myTriangleAnyHit(payload)) 158 { 159 query.CommitNonOpaqueTriangleHit(); 160 if(shouldStopAtFirstHit != 0) 161 query.Abort(); 162 } 163 } 164 break; 165 166 } 167 168 169 } 170 171 switch(query.CommittedStatus()) 172 { 173 case COMMITTED_TRIANGLE_HIT: 174 myTriangleClosestHit(payload); 175 break; 176 177 case COMMITTED_PROCEDURAL_PRIMITIVE_HIT: 178 myProceduralClosestHit(payload, committedProceduralAttrs); 179 break; 180 181 case COMMITTED_NOTHING: 182 myMiss(payload); 183 break; 184 } 185 186 resultBuffer[index] = payload.value; 187}