diff --git a/examples/computeheadless/computeheadless.cpp b/examples/computeheadless/computeheadless.cpp index 334504fd..d0805037 100644 --- a/examples/computeheadless/computeheadless.cpp +++ b/examples/computeheadless/computeheadless.cpp @@ -82,6 +82,8 @@ public: VkDebugReportCallbackEXT debugReportCallback{}; + std::string shaderDir = "glsl"; + VkResult createBuffer(VkBufferUsageFlags usageFlags, VkMemoryPropertyFlags memoryPropertyFlags, VkBuffer *buffer, VkDeviceMemory *memory, VkDeviceSize size, void *data = nullptr) { // Create the buffer handle @@ -132,11 +134,19 @@ public: vks::android::loadVulkanLibrary(); #endif + if (commandLineParser.isSet("shaders")) { + shaderDir = commandLineParser.getValueAsString("shaders", "glsl"); + } + VkApplicationInfo appInfo = {}; appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; appInfo.pApplicationName = "Vulkan headless example"; appInfo.pEngineName = "VulkanExample"; appInfo.apiVersion = VK_API_VERSION_1_0; + // Shaders generated by Slang require a certain SPIR-V environment that can't be satisfied by Vulkan 1.0, so we need to expliclity up that to at least 1.1 and enable some required extensions + if (shaderDir == "slang") { + appInfo.apiVersion = VK_API_VERSION_1_1; + } /* Vulkan instance creation (without surface extensions) @@ -159,7 +169,7 @@ public: bool layersAvailable = true; for (auto layerName : validationLayers) { bool layerAvailable = false; - for (auto instanceLayer : instanceLayers) { + for (auto& instanceLayer : instanceLayers) { if (strcmp(instanceLayer.layerName, layerName) == 0) { layerAvailable = true; break; @@ -260,8 +270,15 @@ public: deviceCreateInfo.queueCreateInfoCount = 1; deviceCreateInfo.pQueueCreateInfos = &queueCreateInfo; std::vector deviceExtensions = {}; + + // Shaders generated by Slang require a certain SPIR-V environment that can't be satisfied by Vulkan 1.0, so we need to expliclity up that to at least 1.1 and enable some required extensions + if (shaderDir == "slang") { + deviceExtensions.push_back(VK_KHR_SPIRV_1_4_EXTENSION_NAME); + deviceExtensions.push_back(VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME); + } + #if (defined(VK_USE_PLATFORM_MACOS_MVK) || defined(VK_USE_PLATFORM_METAL_EXT)) && defined(VK_KHR_portability_subset) - // SRS - When running on macOS with MoltenVK and VK_KHR_portability_subset is defined and supported by the device, enable the extension + // When running on macOS with MoltenVK and VK_KHR_portability_subset is defined and supported by the device, enable the extension uint32_t deviceExtCount = 0; vkEnumerateDeviceExtensionProperties(physicalDevice, nullptr, &deviceExtCount, nullptr); if (deviceExtCount > 0) @@ -410,10 +427,6 @@ public: VkSpecializationMapEntry specializationMapEntry = vks::initializers::specializationMapEntry(0, 0, sizeof(uint32_t)); VkSpecializationInfo specializationInfo = vks::initializers::specializationInfo(1, &specializationMapEntry, sizeof(SpecializationData), &specializationData); - std::string shaderDir = "glsl"; - if (commandLineParser.isSet("shaders")) { - shaderDir = commandLineParser.getValueAsString("shaders", "glsl"); - } const std::string shadersPath = getShaderBasePath() + shaderDir + "/computeheadless/"; VkPipelineShaderStageCreateInfo shaderStage = {}; diff --git a/examples/renderheadless/renderheadless.cpp b/examples/renderheadless/renderheadless.cpp index 6b2fa20e..59dbbac1 100644 --- a/examples/renderheadless/renderheadless.cpp +++ b/examples/renderheadless/renderheadless.cpp @@ -97,6 +97,8 @@ public: VkDebugReportCallbackEXT debugReportCallback{}; + std::string shaderDir = "glsl"; + uint32_t getMemoryTypeIndex(uint32_t typeBits, VkMemoryPropertyFlags properties) { VkPhysicalDeviceMemoryProperties deviceMemoryProperties; vkGetPhysicalDeviceMemoryProperties(physicalDevice, &deviceMemoryProperties); @@ -163,11 +165,19 @@ public: vks::android::loadVulkanLibrary(); #endif + if (commandLineParser.isSet("shaders")) { + shaderDir = commandLineParser.getValueAsString("shaders", "glsl"); + } + VkApplicationInfo appInfo = {}; appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; appInfo.pApplicationName = "Vulkan headless example"; appInfo.pEngineName = "VulkanExample"; appInfo.apiVersion = VK_API_VERSION_1_0; + // Shaders generated by Slang require a certain SPIR-V environment that can't be satisfied by Vulkan 1.0, so we need to expliclity up that to at least 1.1 and enable some required extensions + if (shaderDir == "slang") { + appInfo.apiVersion = VK_API_VERSION_1_1; + } /* Vulkan instance creation (without surface extensions) @@ -190,7 +200,7 @@ public: bool layersAvailable = true; for (auto layerName : validationLayers) { bool layerAvailable = false; - for (auto instanceLayer : instanceLayers) { + for (auto& instanceLayer : instanceLayers) { if (strcmp(instanceLayer.layerName, layerName) == 0) { layerAvailable = true; break; @@ -290,8 +300,15 @@ public: deviceCreateInfo.queueCreateInfoCount = 1; deviceCreateInfo.pQueueCreateInfos = &queueCreateInfo; std::vector deviceExtensions = {}; + + // Shaders generated by Slang require a certain SPIR-V environment that can't be satisfied by Vulkan 1.0, so we need to expliclity up that to at least 1.1 and enable some required extensions + if (shaderDir == "slang") { + deviceExtensions.push_back(VK_KHR_SPIRV_1_4_EXTENSION_NAME); + deviceExtensions.push_back(VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME); + } + #if (defined(VK_USE_PLATFORM_MACOS_MVK) || defined(VK_USE_PLATFORM_METAL_EXT)) && defined(VK_KHR_portability_subset) - // SRS - When running on macOS with MoltenVK and VK_KHR_portability_subset is defined and supported by the device, enable the extension + // When running on macOS with MoltenVK and VK_KHR_portability_subset is defined and supported by the device, enable the extension uint32_t deviceExtCount = 0; vkEnumerateDeviceExtensionProperties(physicalDevice, nullptr, &deviceExtCount, nullptr); if (deviceExtCount > 0) @@ -643,7 +660,6 @@ public: pipelineCreateInfo.pVertexInputState = &vertexInputState; - std::string shaderDir = "glsl"; if (commandLineParser.isSet("shaders")) { shaderDir = commandLineParser.getValueAsString("shaders", "glsl"); } diff --git a/shaders/slang/computeheadless/headless.slang b/shaders/slang/computeheadless/headless.slang new file mode 100644 index 00000000..7f5db02a --- /dev/null +++ b/shaders/slang/computeheadless/headless.slang @@ -0,0 +1,34 @@ +/* Copyright (c) 2025, Sascha Willems + * + * SPDX-License-Identifier: MIT + * + */ + +RWStructuredBuffer values; + +[[SpecializationConstant]] const uint BUFFER_ELEMENTS = 32; + +uint fibonacci(uint n) { + if(n <= 1){ + return n; + } + uint curr = 1; + uint prev = 1; + for(uint i = 2; i < n; ++i) { + uint temp = curr; + curr += prev; + prev = temp; + } + return curr; +} + +[numthreads(1, 1, 1)] +[shader("compute")] +void computeMain(uint3 GlobalInvocationID : SV_DispatchThreadID) +{ + uint index = GlobalInvocationID.x; + if (index >= BUFFER_ELEMENTS) + return; + values[index] = fibonacci(values[index]); +} + diff --git a/shaders/slang/renderheadless/triangle.slang b/shaders/slang/renderheadless/triangle.slang new file mode 100644 index 00000000..11fc0630 --- /dev/null +++ b/shaders/slang/renderheadless/triangle.slang @@ -0,0 +1,32 @@ +/* Copyright (c) 2025, Sascha Willems + * + * SPDX-License-Identifier: MIT + * + */ + +struct VSInput +{ + float3 Pos; + float3 Color; +}; + +struct VSOutput +{ + float4 Pos : SV_POSITION; + float3 Color; +}; + +[shader("vertex")] +VSOutput vertexMain(VSInput input, uniform float4x4 mvp) +{ + VSOutput output; + output.Color = input.Color; + output.Pos = mul(mvp, float4(input.Pos.xyz, 1.0)); + return output; +} + +[shader("fragment")] +float4 fragmentMain(VSOutput input) +{ + return float4(input.Color, 1.0); +} \ No newline at end of file