yum-mirror/slang
Making it easier to work with shaders
git clone https://git.yummers.dev/yum-mirror/slang
13dd01489
master
1// main.cpp 2 3// This file implements an example of hardware ray-tracing using 4// Slang shaders and the `slang-rhi` graphics API. 5 6#include "core/slang-basic.h" 7#include "examples/example-base/example-base.h" 8#include "platform/vector-math.h" 9#include "platform/window.h" 10#include "slang-com-ptr.h" 11#include "slang-rhi.h" 12#include "slang-rhi/acceleration-structure-utils.h" 13#include "slang-rhi/shader-cursor.h" 14#include "slang.h" 15 16using namespace rhi ; 17using namespace Slang ; 18 19static const ExampleResources resourceBase ("ray-tracing" ); 20 21struct Uniforms 22{ 23float screenWidth ,screenHeight ; 24float focalLength = 24.0f ,frameHeight = 24.0f ; 25float cameraDir [4 ]; 26float cameraUp [4 ]; 27float cameraRight [4 ]; 28float cameraPosition [4 ]; 29float lightDir [4 ]; 30}; 31 32struct Vertex 33{ 34float position [3 ]; 35}; 36 37// Define geometry data for our test scene. 38// The scene contains a floor plane, and a cube placed on top of it at the center. 39static const int kVertexCount = 24 ; 40static const Vertex kVertexData [kVertexCount ]= { 41// Floor plane 42 {{-100.0f ,0 ,100.0f }}, 43 {{100.0f ,0 ,100.0f }}, 44 {{100.0f ,0 ,-100.0f }}, 45 {{-100.0f ,0 ,-100.0f }}, 46// Cube face (+y). 47 {{-1.0f ,2.0 ,1.0f }}, 48 {{1.0f ,2.0 ,1.0f }}, 49 {{1.0f ,2.0 ,-1.0f }}, 50 {{-1.0f ,2.0 ,-1.0f }}, 51// Cube face (+z). 52 {{-1.0f ,0.0 ,1.0f }}, 53 {{1.0f ,0.0 ,1.0f }}, 54 {{1.0f ,2.0 ,1.0f }}, 55 {{-1.0f ,2.0 ,1.0f }}, 56// Cube face (-z). 57 {{-1.0f ,0.0 ,-1.0f }}, 58 {{-1.0f ,2.0 ,-1.0f }}, 59 {{1.0f ,2.0 ,-1.0f }}, 60 {{1.0f ,0.0 ,-1.0f }}, 61// Cube face (-x). 62 {{-1.0f ,0.0 ,-1.0f }}, 63 {{-1.0f ,0.0 ,1.0f }}, 64 {{-1.0f ,2.0 ,1.0f }}, 65 {{-1.0f ,2.0 ,-1.0f }}, 66// Cube face (+x). 67 {{1.0f ,2.0 ,-1.0f }}, 68 {{1.0f ,2.0 ,1.0f }}, 69 {{1.0f ,0.0 ,1.0f }}, 70 {{1.0f ,0.0 ,-1.0f }}, 71}; 72static const int kIndexCount = 36 ; 73static const int kIndexData [kIndexCount ]= {0 ,1 ,2 ,0 ,2 ,3 ,4 ,5 ,6 ,4 ,6 ,7 , 748 ,9 ,10 ,8 ,10 ,11 ,12 ,13 ,14 ,12 ,14 ,15 , 7516 ,17 ,18 ,16 ,18 ,19 ,20 ,21 ,22 ,20 ,22 ,23 }; 76 77struct Primitive 78{ 79float data [4 ]; 80float color [4 ]; 81}; 82static const int kPrimitiveCount = 12 ; 83static const Primitive kPrimitiveData [kPrimitiveCount ]= { 84 {{0.0f ,1.0f ,0.0f ,0.0f }, {0.75f ,0.8f ,0.85f ,1.0f }}, 85 {{0.0f ,1.0f ,0.0f ,0.0f }, {0.75f ,0.8f ,0.85f ,1.0f }}, 86 {{0.0f ,1.0f ,0.0f ,0.0f }, {0.95f ,0.85f ,0.05f ,1.0f }}, 87 {{0.0f ,1.0f ,0.0f ,0.0f }, {0.95f ,0.85f ,0.05f ,1.0f }}, 88 {{0.0f ,0.0f ,1.0f ,0.0f }, {0.95f ,0.85f ,0.05f ,1.0f }}, 89 {{0.0f ,0.0f ,1.0f ,0.0f }, {0.95f ,0.85f ,0.05f ,1.0f }}, 90 {{0.0f ,0.0f ,-1.0f ,0.0f }, {0.95f ,0.85f ,0.05f ,1.0f }}, 91 {{0.0f ,0.0f ,-1.0f ,0.0f }, {0.95f ,0.85f ,0.05f ,1.0f }}, 92 {{-1.0f ,0.0f ,0.0f ,0.0f }, {0.95f ,0.85f ,0.05f ,1.0f }}, 93 {{-1.0f ,0.0f ,0.0f ,0.0f }, {0.95f ,0.85f ,0.05f ,1.0f }}, 94 {{1.0f ,0.0f ,0.0f ,0.0f }, {0.95f ,0.85f ,0.05f ,1.0f }}, 95 {{1.0f ,0.0f ,0.0f ,0.0f }, {0.95f ,0.85f ,0.05f ,1.0f }}, 96}; 97 98 99// We need to use a rasterization pipeline to copy the ray-traced image 100// to the swapchain. To do so we need to render a full-screen triangle. 101// We will define a small helper type that defines the data for such a triangle. 102// 103struct FullScreenTriangle 104{ 105struct Vertex 106 { 107float position [2 ]; 108 }; 109 110enum 111 { 112kVertexCount = 3 113 }; 114 115static const Vertex kVertices [kVertexCount ]; 116}; 117const FullScreenTriangle ::Vertex FullScreenTriangle ::kVertices [FullScreenTriangle ::kVertexCount ]= { 118 {{-1 ,-1 }}, 119 {{-1 ,3 }}, 120 {{3 ,-1 }}, 121}; 122 123// The example application will be implemented as a `struct`, so that 124// we can scope the resources it allocates without using global variables. 125// 126struct RayTracing :public WindowedAppBase 127{ 128 129 130Uniforms gUniforms = {}; 131 132 133// Many Slang API functions return detailed diagnostic information 134// (error messages, warnings, etc.) as a "blob" of data, or return 135// a null blob pointer instead if there were no issues. 136// 137// For convenience, we define a subroutine that will dump the information 138// in a diagnostic blob if one is produced, and skip it otherwise. 139// 140void diagnoseIfNeeded (slang::IBlob * diagnosticsBlob ) 141 { 142if (diagnosticsBlob != nullptr ) 143 { 144printf ("%s" , (const char * )diagnosticsBlob -> getBufferPointer ()); 145#ifdef _WIN32 146_Win32OutputDebugString ((const char * )diagnosticsBlob -> getBufferPointer ()); 147#endif 148 } 149 } 150 151// Load and compile shader code from souce. 152Result loadShaderProgram (IDevice * device ,bool isComputePipeline ,IShaderProgram ** outProgram ) 153 { 154ComPtr < slang::ISession > slangSession ; 155slangSession = device -> getSlangSession (); 156 157ComPtr < slang::IBlob > diagnosticsBlob ; 158Slang ::String path = resourceBase .resolveResource ("shaders.slang" ); 159 slang::IModule * module = 160slangSession -> loadModule (path .getBuffer (),diagnosticsBlob .writeRef ()); 161diagnoseIfNeeded (diagnosticsBlob ); 162if (!module ) 163return SLANG_FAIL ; 164 165Slang ::List < slang::IComponentType *> componentTypes ; 166componentTypes .add (module ); 167if (isComputePipeline ) 168 { 169ComPtr < slang::IEntryPoint > computeEntryPoint ; 170SLANG_RETURN_ON_FAIL ( 171module -> findEntryPointByName ("computeMain" ,computeEntryPoint .writeRef ())); 172componentTypes .add (computeEntryPoint ); 173 } 174else 175 { 176ComPtr < slang::IEntryPoint > entryPoint ; 177SLANG_RETURN_ON_FAIL (module -> findEntryPointByName ("vertexMain" ,entryPoint .writeRef ())); 178componentTypes .add (entryPoint ); 179SLANG_RETURN_ON_FAIL ( 180module -> findEntryPointByName ("fragmentMain" ,entryPoint .writeRef ())); 181componentTypes .add (entryPoint ); 182 } 183 184ComPtr < slang::IComponentType > linkedProgram ; 185SlangResult result = slangSession -> createCompositeComponentType ( 186componentTypes .getBuffer (), 187componentTypes .getCount (), 188linkedProgram .writeRef (), 189diagnosticsBlob .writeRef ()); 190diagnoseIfNeeded (diagnosticsBlob ); 191SLANG_RETURN_ON_FAIL (result ); 192 193if (isTestMode ()) 194 { 195printEntrypointHashes (componentTypes .getCount ()- 1 ,1 ,linkedProgram ); 196 } 197 198ShaderProgramDesc programDesc = {}; 199programDesc .slangGlobalScope = linkedProgram ; 200SLANG_RETURN_ON_FAIL (device -> createShaderProgram (programDesc ,outProgram )); 201 202return SLANG_OK ; 203 } 204 205ComPtr < IRenderPipeline > gPresentPipeline ; 206ComPtr < IComputePipeline > gRenderPipeline ; 207ComPtr < IBuffer > gFullScreenVertexBuffer ; 208ComPtr < IBuffer > gVertexBuffer ; 209ComPtr < IBuffer > gIndexBuffer ; 210ComPtr < IBuffer > gPrimitiveBuffer ; 211ComPtr < IBuffer > gTransformBuffer ; 212ComPtr < IBuffer > gInstanceBuffer ; 213ComPtr < IAccelerationStructure > gBLAS ; 214ComPtr < IAccelerationStructure > gTLAS ; 215ComPtr < ITexture > gResultTexture ; 216 217uint64_t lastTime = 0 ; 218 219// glm::vec3 lightDir = normalize(glm::vec3(10, 10, 10)); 220// glm::vec3 lightColor = glm::vec3(1, 1, 1); 221 222 glm::vec3 cameraPosition = glm::vec3 (-2.53f ,2.72f ,4.3f ); 223float cameraOrientationAngles [2 ]= {-0.475f ,-0.35f };// Spherical angles (theta, phi). 224 225float translationScale = 0.5f ; 226float rotationScale = 0.01f ; 227 228// In order to control camera movement, we will 229// use good old WASD 230bool wPressed = false; 231bool aPressed = false; 232bool sPressed = false; 233bool dPressed = false; 234 235bool isMouseDown = false; 236float lastMouseX = 0.0f ; 237float lastMouseY = 0.0f ; 238 239void setKeyState (platform::KeyCode key ,bool state ) 240 { 241switch (key ) 242 { 243default : 244break ; 245case platform::KeyCode ::W : 246wPressed = state ; 247break ; 248case platform::KeyCode ::A : 249aPressed = state ; 250break ; 251case platform::KeyCode ::S : 252sPressed = state ; 253break ; 254case platform::KeyCode ::D : 255dPressed = state ; 256break ; 257 } 258 } 259void onKeyDown (platform::KeyEventArgs args ) {setKeyState (args .key , true); } 260void onKeyUp (platform::KeyEventArgs args ) {setKeyState (args .key , false); } 261 262void onMouseDown (platform::MouseEventArgs args ) 263 { 264isMouseDown = true; 265lastMouseX = (float )args .x ; 266lastMouseY = (float )args .y ; 267 } 268 269void onMouseMove (platform::MouseEventArgs args ) 270 { 271if (isMouseDown ) 272 { 273float deltaX = args .x - lastMouseX ; 274float deltaY = args .y - lastMouseY ; 275 276cameraOrientationAngles [0 ]+= - deltaX * rotationScale ; 277cameraOrientationAngles [1 ]+= - deltaY * rotationScale ; 278lastMouseX = (float )args .x ; 279lastMouseY = (float )args .y ; 280 } 281 } 282void onMouseUp (platform::MouseEventArgs args ) {isMouseDown = false; } 283 284Slang ::Result initialize () 285 { 286SLANG_RETURN_ON_FAIL (initializeBase ("Ray Tracing" ,1024 ,768 ,getDeviceType ())); 287 288if (!isTestMode ()) 289 { 290gWindow -> events .mouseMove = [this ](const platform::MouseEventArgs & e ) 291 {onMouseMove (e ); }; 292gWindow -> events .mouseUp = [this ](const platform::MouseEventArgs & e ) {onMouseUp (e ); }; 293gWindow -> events .mouseDown = [this ](const platform::MouseEventArgs & e ) 294 {onMouseDown (e ); }; 295gWindow -> events .keyDown = [this ](const platform::KeyEventArgs & e ) {onKeyDown (e ); }; 296gWindow -> events .keyUp = [this ](const platform::KeyEventArgs & e ) {onKeyUp (e ); }; 297 } 298 299BufferDesc vertexBufferDesc ; 300vertexBufferDesc .size = kVertexCount * sizeof (Vertex ); 301vertexBufferDesc .usage = BufferUsage ::AccelerationStructureBuildInput ; 302vertexBufferDesc .defaultState = ResourceState ::AccelerationStructureBuildInput ; 303gVertexBuffer = gDevice -> createBuffer (vertexBufferDesc ,& kVertexData [0 ]); 304if (!gVertexBuffer ) 305return SLANG_FAIL ; 306 307BufferDesc indexBufferDesc ; 308indexBufferDesc .size = kIndexCount * sizeof (int32_t ); 309indexBufferDesc .usage = BufferUsage ::AccelerationStructureBuildInput ; 310indexBufferDesc .defaultState = ResourceState ::AccelerationStructureBuildInput ; 311gIndexBuffer = gDevice -> createBuffer (indexBufferDesc ,& kIndexData [0 ]); 312if (!gIndexBuffer ) 313return SLANG_FAIL ; 314 315BufferDesc primitiveBufferDesc ; 316primitiveBufferDesc .size = kPrimitiveCount * sizeof (Primitive ); 317primitiveBufferDesc .elementSize = sizeof (Primitive ); 318primitiveBufferDesc .usage = BufferUsage ::ShaderResource ; 319primitiveBufferDesc .defaultState = ResourceState ::ShaderResource ; 320gPrimitiveBuffer = gDevice -> createBuffer (primitiveBufferDesc ,& kPrimitiveData [0 ]); 321if (!gPrimitiveBuffer ) 322return SLANG_FAIL ; 323 324BufferDesc transformBufferDesc ; 325transformBufferDesc .size = sizeof (float )* 12 ; 326transformBufferDesc .usage = BufferUsage ::AccelerationStructureBuildInput ; 327transformBufferDesc .defaultState = ResourceState ::AccelerationStructureBuildInput ; 328float transformData [12 ]= 329 {1.0f ,0.0f ,0.0f ,0.0f ,0.0f ,1.0f ,0.0f ,0.0f ,0.0f ,0.0f ,1.0f ,0.0f }; 330gTransformBuffer = gDevice -> createBuffer (transformBufferDesc ,& transformData ); 331if (!gTransformBuffer ) 332return SLANG_FAIL ; 333// Build bottom level acceleration structure. 334 { 335AccelerationStructureBuildInput buildInput = {}; 336buildInput .type = AccelerationStructureBuildInputType ::Triangles ; 337buildInput .triangles .vertexBuffers [0 ]= gVertexBuffer ; 338buildInput .triangles .vertexBufferCount = 1 ; 339buildInput .triangles .vertexFormat = Format ::RGB32Float ; 340buildInput .triangles .vertexCount = kVertexCount ; 341buildInput .triangles .vertexStride = sizeof (Vertex ); 342buildInput .triangles .indexBuffer = gIndexBuffer ; 343buildInput .triangles .indexFormat = IndexFormat ::Uint32 ; 344buildInput .triangles .indexCount = kIndexCount ; 345buildInput .triangles .preTransformBuffer = gTransformBuffer ; 346buildInput .triangles .flags = AccelerationStructureGeometryFlags ::Opaque ; 347 348AccelerationStructureBuildDesc buildDesc = {}; 349buildDesc .inputs = & buildInput ; 350buildDesc .inputCount = 1 ; 351buildDesc .flags = AccelerationStructureBuildFlags ::AllowCompaction ; 352 353// Query buffer size for acceleration structure build. 354AccelerationStructureSizes sizes ; 355SLANG_RETURN_ON_FAIL (gDevice -> getAccelerationStructureSizes (buildDesc ,& sizes )); 356 357// Allocate buffers for acceleration structure. 358BufferDesc scratchBufferDesc ; 359scratchBufferDesc .usage = BufferUsage ::UnorderedAccess ; 360scratchBufferDesc .defaultState = ResourceState ::UnorderedAccess ; 361scratchBufferDesc .size = sizes .scratchSize ; 362ComPtr < IBuffer > scratchBuffer = gDevice -> createBuffer (scratchBufferDesc ); 363if (!scratchBuffer ) 364return SLANG_FAIL ; 365 366// Build acceleration structure. 367ComPtr < IQueryPool > compactedSizeQuery ; 368QueryPoolDesc queryPoolDesc ; 369queryPoolDesc .count = 1 ; 370queryPoolDesc .type = QueryType ::AccelerationStructureCompactedSize ; 371SLANG_RETURN_ON_FAIL ( 372gDevice -> createQueryPool (queryPoolDesc ,compactedSizeQuery .writeRef ())); 373 374ComPtr < IAccelerationStructure > draftAS ; 375AccelerationStructureDesc draftCreateDesc ; 376draftCreateDesc .size = sizes .accelerationStructureSize ; 377SLANG_RETURN_ON_FAIL ( 378gDevice -> createAccelerationStructure (draftCreateDesc ,draftAS .writeRef ())); 379 380compactedSizeQuery -> reset (); 381 382auto commandEncoder = gQueue -> createCommandEncoder (); 383AccelerationStructureQueryDesc compactedSizeQueryDesc = {}; 384compactedSizeQueryDesc .queryPool = compactedSizeQuery ; 385compactedSizeQueryDesc .queryType = QueryType ::AccelerationStructureCompactedSize ; 386commandEncoder -> buildAccelerationStructure ( 387buildDesc , 388draftAS , 389nullptr , 390scratchBuffer , 3911 , 392& compactedSizeQueryDesc ); 393gQueue -> submit (commandEncoder -> finish ()); 394gQueue -> waitOnHost (); 395 396uint64_t compactedSize = 0 ; 397compactedSizeQuery -> getResult (0 ,1 ,& compactedSize ); 398AccelerationStructureDesc createDesc ; 399createDesc .size = compactedSize ; 400gDevice -> createAccelerationStructure (createDesc ,gBLAS .writeRef ()); 401 402commandEncoder = gQueue -> createCommandEncoder (); 403commandEncoder -> copyAccelerationStructure ( 404gBLAS , 405draftAS , 406AccelerationStructureCopyMode ::Compact ); 407gQueue -> submit (commandEncoder -> finish ()); 408gQueue -> waitOnHost (); 409 } 410 411// Build top level acceleration structure. 412 { 413AccelerationStructureInstanceDescType nativeInstanceDescType = 414getAccelerationStructureInstanceDescType (gDevice ); 415Size nativeInstanceDescSize = 416getAccelerationStructureInstanceDescSize (nativeInstanceDescType ); 417 418 std::vector < AccelerationStructureInstanceDescGeneric > instanceDescs ; 419instanceDescs .resize (1 ); 420float transformMatrix []= 421 {1.0f ,0.0f ,0.0f ,0.0f ,0.0f ,1.0f ,0.0f ,0.0f ,0.0f ,0.0f ,1.0f ,0.0f }; 422memcpy (& instanceDescs [0 ].transform [0 ][0 ],transformMatrix ,sizeof (float )* 12 ); 423 424instanceDescs [0 ].instanceID = 0 ; 425instanceDescs [0 ].instanceMask = 0xFF ; 426instanceDescs [0 ].instanceContributionToHitGroupIndex = 0 ; 427instanceDescs [0 ].flags = AccelerationStructureInstanceFlags ::TriangleFacingCullDisable ; 428instanceDescs [0 ].accelerationStructure = gBLAS -> getHandle (); 429 430 std::vector < uint8_t > nativeInstanceDescs (instanceDescs .size ()* nativeInstanceDescSize ); 431convertAccelerationStructureInstanceDescs ( 432instanceDescs .size (), 433nativeInstanceDescType , 434nativeInstanceDescs .data (), 435nativeInstanceDescSize , 436instanceDescs .data (), 437sizeof (AccelerationStructureInstanceDescGeneric )); 438 439BufferDesc instanceBufferDesc ; 440instanceBufferDesc .size = 441instanceDescs .size ()* sizeof (AccelerationStructureInstanceDescGeneric ); 442instanceBufferDesc .usage = BufferUsage ::ShaderResource ; 443instanceBufferDesc .defaultState = ResourceState ::ShaderResource ; 444gInstanceBuffer = gDevice -> createBuffer (instanceBufferDesc ,nativeInstanceDescs .data ()); 445if (!gInstanceBuffer ) 446return SLANG_FAIL ; 447 448AccelerationStructureBuildInput buildInput = {}; 449buildInput .type = AccelerationStructureBuildInputType ::Instances ; 450buildInput .instances .instanceBuffer = gInstanceBuffer ; 451buildInput .instances .instanceCount = 1 ; 452buildInput .instances .instanceStride = nativeInstanceDescSize ; 453 454AccelerationStructureBuildDesc buildDesc = {}; 455buildDesc .inputs = & buildInput ; 456buildDesc .inputCount = 1 ; 457 458// Query buffer size for acceleration structure build. 459AccelerationStructureSizes sizes ; 460SLANG_RETURN_ON_FAIL (gDevice -> getAccelerationStructureSizes (buildDesc ,& sizes )); 461 462BufferDesc scratchBufferDesc ; 463scratchBufferDesc .usage = BufferUsage ::UnorderedAccess ; 464scratchBufferDesc .defaultState = ResourceState ::UnorderedAccess ; 465scratchBufferDesc .size = sizes .scratchSize ; 466ComPtr < IBuffer > scratchBuffer = gDevice -> createBuffer (scratchBufferDesc ); 467 468AccelerationStructureDesc createDesc ; 469createDesc .size = sizes .accelerationStructureSize ; 470SLANG_RETURN_ON_FAIL ( 471gDevice -> createAccelerationStructure (createDesc ,gTLAS .writeRef ())); 472 473auto commandEncoder = gQueue -> createCommandEncoder (); 474commandEncoder 475-> buildAccelerationStructure (buildDesc ,gTLAS ,nullptr ,scratchBuffer ,0 ,nullptr ); 476gQueue -> submit (commandEncoder -> finish ()); 477gQueue -> waitOnHost (); 478 } 479 480BufferDesc fullScreenVertexBufferDesc ; 481fullScreenVertexBufferDesc .size = 482FullScreenTriangle ::kVertexCount * sizeof (FullScreenTriangle ::Vertex ); 483fullScreenVertexBufferDesc .usage = BufferUsage ::VertexBuffer ; 484fullScreenVertexBufferDesc .defaultState = ResourceState ::VertexBuffer ; 485gFullScreenVertexBuffer = 486gDevice -> createBuffer (fullScreenVertexBufferDesc ,& FullScreenTriangle ::kVertices [0 ]); 487if (!gFullScreenVertexBuffer ) 488return SLANG_FAIL ; 489 490InputElementDesc inputElements []= { 491 {"POSITION" ,0 ,Format ::RG32Float , offsetof(FullScreenTriangle ::Vertex ,position )}, 492 }; 493auto inputLayout = gDevice -> createInputLayout ( 494sizeof (FullScreenTriangle ::Vertex ), 495& inputElements [0 ], 496SLANG_COUNT_OF (inputElements )); 497if (!inputLayout ) 498return SLANG_FAIL ; 499 500ComPtr < IShaderProgram > shaderProgram ; 501SLANG_RETURN_ON_FAIL (loadShaderProgram (gDevice , false,shaderProgram .writeRef ())); 502ColorTargetDesc colorTarget ; 503colorTarget .format = Format ::RGBA16Float ; 504RenderPipelineDesc desc ; 505desc .inputLayout = inputLayout ; 506desc .program = shaderProgram ; 507desc .targetCount = 1 ; 508desc .targets = & colorTarget ; 509desc .depthStencil .depthTestEnable = false; 510desc .depthStencil .depthWriteEnable = false; 511desc .primitiveTopology = PrimitiveTopology ::TriangleList ; 512gPresentPipeline = gDevice -> createRenderPipeline (desc ); 513if (!gPresentPipeline ) 514return SLANG_FAIL ; 515 516ComPtr < IShaderProgram > computeProgram ; 517SLANG_RETURN_ON_FAIL (loadShaderProgram (gDevice , true,computeProgram .writeRef ())); 518ComputePipelineDesc computeDesc ; 519computeDesc .program = computeProgram ; 520gRenderPipeline = gDevice -> createComputePipeline (computeDesc ); 521if (!gRenderPipeline ) 522return SLANG_FAIL ; 523 524createResultTexture (); 525return SLANG_OK ; 526 } 527 528void createResultTexture () 529 { 530TextureDesc resultTextureDesc = {}; 531resultTextureDesc .type = TextureType ::Texture2D ; 532resultTextureDesc .mipCount = 1 ; 533resultTextureDesc .size .width = windowWidth ; 534resultTextureDesc .size .height = windowHeight ; 535resultTextureDesc .size .depth = 1 ; 536resultTextureDesc .usage = TextureUsage ::UnorderedAccess |TextureUsage ::ShaderResource ; 537resultTextureDesc .defaultState = ResourceState ::UnorderedAccess ; 538resultTextureDesc .format = Format ::RGBA16Float ; 539gResultTexture = gDevice -> createTexture (resultTextureDesc ); 540 } 541 542virtual void windowSizeChanged ()override 543 { 544WindowedAppBase ::windowSizeChanged (); 545createResultTexture (); 546 } 547 548 glm::vec3 getVectorFromSphericalAngles (float theta ,float phi ) 549 { 550auto sinTheta = sin (theta ); 551auto cosTheta = cos (theta ); 552auto sinPhi = sin (phi ); 553auto cosPhi = cos (phi ); 554return glm::vec3 (- sinTheta * cosPhi ,sinPhi ,- cosTheta * cosPhi ); 555 } 556void updateUniforms () 557 { 558gUniforms .screenWidth = (float )windowWidth ; 559gUniforms .screenHeight = (float )windowHeight ; 560if (!lastTime ) 561lastTime = getCurrentTime (); 562uint64_t currentTime = getCurrentTime (); 563float deltaTime = float (double (currentTime - lastTime ) /double (getTimerFrequency ())); 564lastTime = currentTime ; 565 566auto camDir = 567getVectorFromSphericalAngles (cameraOrientationAngles [0 ],cameraOrientationAngles [1 ]); 568auto camUp = getVectorFromSphericalAngles ( 569cameraOrientationAngles [0 ], 570cameraOrientationAngles [1 ]+ glm::pi < float > ()* 0.5f ); 571auto camRight = glm::cross (camDir ,camUp ); 572 573 glm::vec3 movement = glm::vec3 (0 ); 574if (wPressed ) 575movement += camDir ; 576if (sPressed ) 577movement -= camDir ; 578if (aPressed ) 579movement -= camRight ; 580if (dPressed ) 581movement += camRight ; 582 583cameraPosition += deltaTime * translationScale * movement ; 584 585memcpy (gUniforms .cameraDir ,& camDir ,sizeof (float )* 3 ); 586memcpy (gUniforms .cameraUp ,& camUp ,sizeof (float )* 3 ); 587memcpy (gUniforms .cameraRight ,& camRight ,sizeof (float )* 3 ); 588memcpy (gUniforms .cameraPosition ,& cameraPosition ,sizeof (float )* 3 ); 589auto lightDir = glm::normalize (glm::vec3 (1.0f ,3.0f ,2.0f )); 590memcpy (gUniforms .lightDir ,& lightDir ,sizeof (float )* 3 ); 591 } 592 593virtual void renderFrame (ITexture * texture )override 594 { 595updateUniforms (); 596 { 597auto commandEncoder = gQueue -> createCommandEncoder (); 598auto computePassEncoder = commandEncoder -> beginComputePass (); 599auto rootObject = computePassEncoder -> bindPipeline (gRenderPipeline ); 600auto cursor = ShaderCursor (rootObject ); 601cursor ["resultTexture" ].setBinding (gResultTexture ); 602cursor ["uniforms" ].setData (& gUniforms ,sizeof (Uniforms )); 603cursor ["sceneBVH" ].setBinding (gTLAS ); 604cursor ["primitiveBuffer" ].setBinding (gPrimitiveBuffer ); 605computePassEncoder -> dispatchCompute ( 606 (windowWidth + 15 ) /16 , 607 (windowHeight + 15 ) /16 , 6081 ); 609computePassEncoder -> end (); 610gQueue -> submit (commandEncoder -> finish ()); 611 } 612 613 { 614auto commandEncoder = gQueue -> createCommandEncoder (); 615 616ComPtr < ITextureView > textureView = gDevice -> createTextureView (texture , {}); 617RenderPassColorAttachment colorAttachment = {}; 618colorAttachment .view = textureView ; 619colorAttachment .loadOp = LoadOp ::Clear ; 620 621RenderPassDesc renderPassDesc = {}; 622renderPassDesc .colorAttachments = & colorAttachment ; 623renderPassDesc .colorAttachmentCount = 1 ; 624 625auto renderPassEncoder = commandEncoder -> beginRenderPass (renderPassDesc ); 626 627RenderState renderState = {}; 628renderState .viewports [0 ]= Viewport ::fromSize (windowWidth ,windowHeight ); 629renderState .viewportCount = 1 ; 630renderState .scissorRects [0 ]= ScissorRect ::fromSize (windowWidth ,windowHeight ); 631renderState .scissorRectCount = 1 ; 632renderState .vertexBuffers [0 ]= gFullScreenVertexBuffer ; 633renderState .vertexBufferCount = 1 ; 634renderPassEncoder -> setRenderState (renderState ); 635 636auto rootObject = renderPassEncoder -> bindPipeline (gPresentPipeline ); 637auto cursor = ShaderCursor (rootObject ); 638cursor ["t" ].setBinding (gResultTexture ); 639 640DrawArguments drawArgs = {}; 641drawArgs .vertexCount = 3 ; 642renderPassEncoder -> draw (drawArgs ); 643renderPassEncoder -> end (); 644gQueue -> submit (commandEncoder -> finish ()); 645 } 646 647if (!isTestMode ()) 648 { 649// With that, we are done drawing for one frame, and ready for the next. 650// 651gSurface -> present (); 652 } 653 } 654}; 655 656// This macro instantiates an appropriate main function to 657// run the application defined above. 658EXAMPLE_MAIN (innerMain < RayTracing > );