yum-mirror/slang
Making it easier to work with shaders
git clone https://git.yummers.dev/yum-mirror/slang
43d0c2100
master
1#include "core/slang-basic.h" 2#include "core/slang-blob.h" 3#include "core/slang-memory-file-system.h" 4#include "gfx-test-util.h" 5#include "slang-rhi.h" 6#include "slang-rhi/shader-cursor.h" 7#include "unit-test/slang-unit-test.h" 8 9using namespace rhi ; 10 11namespace gfx_test 12{ 13static Slang ::Result precompileProgram ( 14IDevice * device , 15ISlangMutableFileSystem * fileSys , 16const char * shaderModuleName ) 17{ 18Slang ::ComPtr < slang::ISession > slangSession ; 19SLANG_RETURN_ON_FAIL (device -> getSlangSession (slangSession .writeRef ())); 20 slang::SessionDesc sessionDesc = {}; 21auto searchPaths = getSlangSearchPaths (); 22sessionDesc .searchPathCount = searchPaths .getCount (); 23sessionDesc .searchPaths = searchPaths .getBuffer (); 24auto globalSession = slangSession -> getGlobalSession (); 25globalSession -> createSession (sessionDesc ,slangSession .writeRef ()); 26 27Slang ::ComPtr < slang::IBlob > diagnosticsBlob ; 28 slang::IModule * module = slangSession -> loadModule (shaderModuleName ,diagnosticsBlob .writeRef ()); 29diagnoseIfNeeded (diagnosticsBlob ); 30if (!module ) 31return SLANG_FAIL ; 32 33// Write loaded modules to memory file system. 34for (SlangInt i = 0 ;i < slangSession -> getLoadedModuleCount ();i ++ ) 35 { 36auto module = slangSession -> getLoadedModule (i ); 37auto path = module -> getFilePath (); 38if (path ) 39 { 40auto name = module -> getName (); 41ComPtr < ISlangBlob > outBlob ; 42module -> serialize (outBlob .writeRef ()); 43fileSys -> saveFileBlob ((Slang ::String (name )+ ".slang-module" ).getBuffer (),outBlob ); 44 } 45 } 46return SLANG_OK ; 47} 48 49void precompiledModuleTestImpl (IDevice * device ,UnitTestContext * context ) 50{ 51// First, load and compile the slang source. 52ComPtr < ISlangMutableFileSystem > memoryFileSystem = 53ComPtr < ISlangMutableFileSystem > (new Slang ::MemoryFileSystem ()); 54 55ComPtr < IShaderProgram > shaderProgram ; 56 slang::ProgramLayout * slangReflection ; 57GFX_CHECK_CALL_ABORT (precompileProgram (device ,memoryFileSystem .get (),"precompiled-module" )); 58 59// Next, load the precompiled slang program. 60Slang ::ComPtr < slang::ISession > slangSession ; 61device -> getSlangSession (slangSession .writeRef ()); 62 slang::SessionDesc sessionDesc = {}; 63sessionDesc .targetCount = 1 ; 64 slang::TargetDesc targetDesc = {}; 65switch (device -> getInfo ().deviceType ) 66 { 67case DeviceType ::D3D12 : 68targetDesc .format = SLANG_DXIL ; 69targetDesc .profile = device -> getSlangSession ()-> getGlobalSession ()-> findProfile ("sm_6_1" ); 70break ; 71case DeviceType ::Vulkan : 72targetDesc .format = SLANG_SPIRV ; 73targetDesc .profile = device -> getSlangSession ()-> getGlobalSession ()-> findProfile ("GLSL_460" ); 74break ; 75 } 76sessionDesc .targets = & targetDesc ; 77sessionDesc .fileSystem = memoryFileSystem .get (); 78auto globalSession = slangSession -> getGlobalSession (); 79globalSession -> createSession (sessionDesc ,slangSession .writeRef ()); 80GFX_CHECK_CALL_ABORT (loadComputeProgram ( 81device , 82slangSession , 83shaderProgram , 84"precompiled-module" , 85"computeMain" , 86slangReflection )); 87 88ComputePipelineDesc pipelineDesc = {}; 89pipelineDesc .program = shaderProgram .get (); 90ComPtr < IComputePipeline > pipelineState ; 91GFX_CHECK_CALL_ABORT (device -> createComputePipeline (pipelineDesc ,pipelineState .writeRef ())); 92 93const int numberCount = 4 ; 94float initialData []= {0.0f ,0.0f ,0.0f ,0.0f }; 95BufferDesc bufferDesc = {}; 96bufferDesc .size = numberCount * sizeof (float ); 97bufferDesc .format = Format ::Undefined ; 98bufferDesc .elementSize = sizeof (float ); 99bufferDesc .usage = BufferUsage ::ShaderResource |BufferUsage ::UnorderedAccess | 100BufferUsage ::CopyDestination |BufferUsage ::CopySource ; 101bufferDesc .defaultState = ResourceState ::UnorderedAccess ; 102bufferDesc .memoryType = MemoryType ::DeviceLocal ; 103 104ComPtr < IBuffer > numbersBuffer ; 105GFX_CHECK_CALL_ABORT ( 106device -> createBuffer (bufferDesc , (void * )initialData ,numbersBuffer .writeRef ())); 107 108// We have done all the set up work, now it is time to start recording a command buffer for 109// GPU execution. 110 { 111auto queue = device -> getQueue (QueueType ::Graphics ); 112auto commandEncoder = queue -> createCommandEncoder (); 113 { 114auto encoder = commandEncoder -> beginComputePass (); 115auto rootObject = encoder -> bindPipeline (pipelineState ); 116 117ShaderCursor entryPointCursor ( 118rootObject -> getEntryPoint (0 ));// get a cursor the the first entry-point. 119// Bind buffer directly to the entry point. 120entryPointCursor .getPath ("buffer" ).setBinding (Binding (numbersBuffer )); 121 122encoder -> dispatchCompute (1 ,1 ,1 ); 123encoder -> end (); 124 } 125 126auto commandBuffer = commandEncoder -> finish (); 127queue -> submit (commandBuffer ); 128queue -> waitOnHost (); 129 } 130 131compareComputeResult (device ,numbersBuffer , std::array {3.0f ,3.0f ,3.0f ,3.0f }); 132} 133 134SLANG_UNIT_TEST (precompiledModuleD3D12 ) 135{ 136runTestImpl (precompiledModuleTestImpl ,unitTestContext ,DeviceType ::D3D12 ); 137} 138 139SLANG_UNIT_TEST (precompiledModuleVulkan ) 140{ 141runTestImpl (precompiledModuleTestImpl ,unitTestContext ,DeviceType ::Vulkan ); 142} 143 144}// namespace gfx_test