From f55ac81fe4f9ed74daa5c5618400225bd898ab02 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Mon, 1 Jun 2026 14:19:09 +0200 Subject: [PATCH] Update to the latest Vulkan SDK `1.4.350` Update Vulkan API to `1.2` on Windows Update Vulkan API to `1.1` on Android --- .github/actions/vulkan/action.yml | 2 +- Source/Editor/Cooker/Steps/CookAssetsStep.cpp | 2 +- .../Shaders/Cache/ShaderAssetBase.cpp | 3 + .../Shaders/Cache/ShaderCacheManager.cpp | 3 + .../Vulkan/Android/AndroidVulkanPlatform.cpp | 2 +- .../Vulkan/Android/AndroidVulkanPlatform.h | 5 +- .../Vulkan/GPUContextVulkan.cpp | 102 ++++++++++++++---- .../GraphicsDevice/Vulkan/GPUContextVulkan.h | 12 ++- .../Vulkan/GPUDeviceVulkan.Layers.cpp | 70 +----------- .../GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp | 69 ++++++++---- .../GraphicsDevice/Vulkan/GPUDeviceVulkan.h | 2 +- .../GraphicsDevice/Vulkan/GPUShaderVulkan.cpp | 11 ++ .../Vulkan/GPUTextureVulkan.cpp | 6 ++ .../Vulkan/VulkanPlatformBase.h | 2 +- .../Vulkan/Win32/Win32VulkanPlatform.h | 1 + Source/Engine/Renderer/GBufferPass.cpp | 5 +- .../Vulkan/ShaderCompilerVulkan.cpp | 36 ++++++- Source/Engine/Threading/ThreadLocal.h | 6 ++ 18 files changed, 222 insertions(+), 117 deletions(-) diff --git a/.github/actions/vulkan/action.yml b/.github/actions/vulkan/action.yml index 4ab4adb59..e53fab14e 100644 --- a/.github/actions/vulkan/action.yml +++ b/.github/actions/vulkan/action.yml @@ -3,7 +3,7 @@ description: Downloads and installs Vulkan SDK. inputs: vulkan-version: description: 'Vulkan SDK release version (e.g. 1.2.198.1).' - default: '1.3.290.0' + default: '1.4.350.0' required: false runs: using: "composite" diff --git a/Source/Editor/Cooker/Steps/CookAssetsStep.cpp b/Source/Editor/Cooker/Steps/CookAssetsStep.cpp index 5fd61e39c..6e3e7501e 100644 --- a/Source/Editor/Cooker/Steps/CookAssetsStep.cpp +++ b/Source/Editor/Cooker/Steps/CookAssetsStep.cpp @@ -433,6 +433,7 @@ bool ProcessShaderBase(CookAssetsStep::AssetCookData& data, ShaderAssetBase* ass options.GenerateDebugData = data.Cache.Settings.Global.ShadersGenerateDebugData; options.TreatWarningsAsErrors = false; options.Output = &cacheStream; + options.Platform = data.Data.Tools->GetPlatform(); Array includes; #define COMPILE_PROFILE(profile, cacheChunk) \ @@ -535,7 +536,6 @@ bool ProcessShaderBase(CookAssetsStep::AssetCookData& data, ShaderAssetBase* ass #if PLATFORM_TOOLS_XBOX_SCARLETT case BuildPlatform::XboxScarlett: { - options.Platform = PlatformType::XboxScarlett; const char* platformDefineName = "PLATFORM_XBOX_SCARLETT"; COMPILE_PROFILE(DirectX_SM6, SHADER_FILE_CHUNK_INTERNAL_D3D_SM6_CACHE); break; diff --git a/Source/Engine/Graphics/Shaders/Cache/ShaderAssetBase.cpp b/Source/Engine/Graphics/Shaders/Cache/ShaderAssetBase.cpp index 4bec6440e..becaf6cc4 100644 --- a/Source/Engine/Graphics/Shaders/Cache/ShaderAssetBase.cpp +++ b/Source/Engine/Graphics/Shaders/Cache/ShaderAssetBase.cpp @@ -264,10 +264,13 @@ bool ShaderAssetBase::LoadShaderCache(ShaderCacheResult& result) auto& platformDefine = options.Macros.AddOne(); #if PLATFORM_WINDOWS platformDefine.Name = "PLATFORM_WINDOWS"; + options.Platform = PlatformType::Windows; #elif PLATFORM_LINUX platformDefine.Name = "PLATFORM_LINUX"; + options.Platform = PlatformType::Linux; #elif PLATFORM_MAC platformDefine.Name = "PLATFORM_MAC"; + options.Platform = PlatformType::Mac; #else #error "Unknown platform." #endif diff --git a/Source/Engine/Graphics/Shaders/Cache/ShaderCacheManager.cpp b/Source/Engine/Graphics/Shaders/Cache/ShaderCacheManager.cpp index 7fcac839b..d989065b0 100644 --- a/Source/Engine/Graphics/Shaders/Cache/ShaderCacheManager.cpp +++ b/Source/Engine/Graphics/Shaders/Cache/ShaderCacheManager.cpp @@ -188,6 +188,7 @@ bool ShaderCacheManagerService::Init() int32 ShaderCacheVersion = -1; int32 MaterialGraphVersion = -1; int32 ParticleGraphVersion = -1; + int32 Platform = -1; union { struct @@ -210,6 +211,7 @@ bool ShaderCacheManagerService::Init() ShaderCacheVersion = GPU_SHADER_CACHE_VERSION; MaterialGraphVersion = MATERIAL_GRAPH_VERSION; ParticleGraphVersion = PARTICLE_GPU_GRAPH_VERSION; + Platform = (int32)PLATFORM_TYPE; Flags = 0; #if USE_EDITOR ShaderDebug = CommandLine::Options.ShaderDebug.IsTrue(); @@ -235,6 +237,7 @@ bool ShaderCacheManagerService::Init() || cacheVersion.ShaderCacheVersion != cacheVersionDefault.ShaderCacheVersion || cacheVersion.MaterialGraphVersion != cacheVersionDefault.MaterialGraphVersion || cacheVersion.ParticleGraphVersion != cacheVersionDefault.ParticleGraphVersion + || cacheVersion.Platform != cacheVersionDefault.Platform || cacheVersion.Flags != cacheVersionDefault.Flags ) { diff --git a/Source/Engine/GraphicsDevice/Vulkan/Android/AndroidVulkanPlatform.cpp b/Source/Engine/GraphicsDevice/Vulkan/Android/AndroidVulkanPlatform.cpp index 3d4183be0..d2e81cb4c 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/Android/AndroidVulkanPlatform.cpp +++ b/Source/Engine/GraphicsDevice/Vulkan/Android/AndroidVulkanPlatform.cpp @@ -12,7 +12,7 @@ void AndroidVulkanPlatform::GetInstanceExtensions(Array& extensions extensions.Add(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME); } -void AndroidVulkanPlatform::GetDeviceExtensions(Array& extensions, Array& layers) +void AndroidVulkanPlatform::GetDeviceExtensions(Array& extensions) { extensions.Add(VK_KHR_SURFACE_EXTENSION_NAME); extensions.Add(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME); diff --git a/Source/Engine/GraphicsDevice/Vulkan/Android/AndroidVulkanPlatform.h b/Source/Engine/GraphicsDevice/Vulkan/Android/AndroidVulkanPlatform.h index 30f7f5206..9bd57c1d6 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/Android/AndroidVulkanPlatform.h +++ b/Source/Engine/GraphicsDevice/Vulkan/Android/AndroidVulkanPlatform.h @@ -6,6 +6,9 @@ #if GRAPHICS_API_VULKAN && PLATFORM_ANDROID +// Android has 99.4% of Vulkan 1.1 and API level 29 (Android 10.0) +#define VULKAN_API_VERSION VK_API_VERSION_1_1 + // Support more backbuffers in case driver decides to use more #define VULKAN_BACK_BUFFERS_COUNT_MAX 8 @@ -16,7 +19,7 @@ class AndroidVulkanPlatform : public VulkanPlatformBase { public: static void GetInstanceExtensions(Array& extensions, Array& layers); - static void GetDeviceExtensions(Array& extensions, Array& layers); + static void GetDeviceExtensions(Array& extensions); static void CreateSurface(Window* window, GPUDeviceVulkan* device, VkInstance instance, VkSurfaceKHR* surface); }; diff --git a/Source/Engine/GraphicsDevice/Vulkan/GPUContextVulkan.cpp b/Source/Engine/GraphicsDevice/Vulkan/GPUContextVulkan.cpp index 0aded637a..de6ab9e46 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/GPUContextVulkan.cpp +++ b/Source/Engine/GraphicsDevice/Vulkan/GPUContextVulkan.cpp @@ -210,7 +210,11 @@ void GPUContextVulkan::AddImageBarrier(GPUTextureViewVulkan* handle, VkImageLayo range.baseMipLevel = 0; range.levelCount = mipLevels; range.baseArrayLayer = 0; +#if VK_KHR_maintenance1 + range.layerCount = VK_REMAINING_ARRAY_LAYERS; // maintenance9 could be enabled for per-layer masking +#else range.layerCount = handle->Owner->ArraySlices; +#endif AddImageBarrier(handle->Image, srcLayout, dstLayout, range, handle); state.SetResourceState(dstLayout); } @@ -229,6 +233,10 @@ void GPUContextVulkan::AddImageBarrier(GPUTextureViewVulkan* handle, VkImageLayo range.levelCount = 1; range.baseArrayLayer = i / mipLevels; range.layerCount = 1; +#if VK_KHR_maintenance1 + if (handle->Owner->ArraySlices == 1) + range.layerCount = VK_REMAINING_ARRAY_LAYERS; // maintenance9 could be enabled for per-layer masking +#endif AddImageBarrier(handle->Image, srcLayout, dstLayout, range, handle); state.SetSubresourceState(i, dstLayout); } @@ -264,6 +272,10 @@ void GPUContextVulkan::AddImageBarrier(GPUTextureVulkan* texture, int32 mipSlice range.levelCount = 1; range.baseArrayLayer = arraySlice; range.layerCount = 1; +#if VK_KHR_maintenance1 + if (texture->IsVolume()) + range.layerCount = VK_REMAINING_ARRAY_LAYERS; // maintenance9 could be enabled for per-layer masking +#endif AddImageBarrier(texture->GetHandle(), srcLayout, dstLayout, range, nullptr); state.SetSubresourceState(subresourceIndex, dstLayout); } @@ -285,6 +297,10 @@ void GPUContextVulkan::AddImageBarrier(GPUTextureVulkan* texture, VkImageLayout range.levelCount = texture->MipLevels(); range.baseArrayLayer = 0; range.layerCount = texture->ArraySize(); +#if VK_KHR_maintenance1 + if (texture->IsVolume()) + range.layerCount = VK_REMAINING_ARRAY_LAYERS; // maintenance9 could be enabled for per-layer masking +#endif AddImageBarrier(texture->GetHandle(), srcLayout, dstLayout, range, nullptr); state.SetResourceState(dstLayout); } @@ -431,7 +447,7 @@ void GPUContextVulkan::BeginRenderPass() PendingClear clear; for (int32 i = 0; i < GPU_MAX_RT_BINDED; i++) { - auto handle = _rtHandles[i]; + auto handle = _rtTargets[i]; if (handle) { layout.RTVsFormats[i] = handle->GetFormat(); @@ -490,7 +506,7 @@ void GPUContextVulkan::BeginRenderPass() } else { - handle = _rtHandles[0]; + handle = _rtTargets[0]; #if !BUILD_RELEASE if (!handle) { @@ -507,9 +523,8 @@ void GPUContextVulkan::BeginRenderPass() layout.Layers = handle->Layers; // Clear textures that are not bind to the render pass - for (auto& e : _pendingClears) - ManualClear(e); - _pendingClears.Clear(); + if (_pendingClears.HasItems()) + FlushManualClears(); // Get or create objects auto renderPass = _device->GetOrCreateRenderPass(layout); @@ -569,6 +584,17 @@ void GPUContextVulkan::ManualClear(const PendingClear& clear) } } +void GPUContextVulkan::FlushManualClears() +{ + // Batch barriers + for (auto& clear : _pendingClears) + AddImageBarrier(clear.View, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + + for (auto& clear : _pendingClears) + ManualClear(clear); + _pendingClears.Clear(); +} + void GPUContextVulkan::UpdateDescriptorSets(const SpirvShaderDescriptorInfo& descriptorInfo, DescriptorSetWriterVulkan& dsWriter, bool& needsWrite) { for (uint32 i = 0; i < descriptorInfo.DescriptorTypesCount; i++) @@ -736,6 +762,27 @@ void GPUContextVulkan::OnDrawCall() ASSERT(pipelineState && pipelineState->IsValid()); const auto cmdBuffer = _cmdBufferManager->GetCmdBuffer(); + // Flush pending image clears before binding descriptors but skip ones that are going to be used as render targets + // (they will be cleared in the render pass with proper loadOp and without extra barriers) + if (_pendingClears.HasItems()) + { + auto rtHandles = ToSpan(_rtHandles, ARRAY_COUNT(_rtHandles)); + for (auto& clear : _pendingClears) + { + if (!SpanContains(rtHandles, clear.View)) + AddImageBarrier(clear.View, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + } + for (int32 i = 0; i < _pendingClears.Count(); i++) + { + auto& clear = _pendingClears.Get()[i]; + if (!SpanContains(rtHandles, clear.View)) + { + ManualClear(clear); + _pendingClears.RemoveAtKeepOrder(i--); + } + } + } + // End previous render pass if render targets layout was modified if (_rtDirtyFlag && cmdBuffer->IsInsideRenderPass()) EndRenderPass(); @@ -837,7 +884,6 @@ void GPUContextVulkan::FrameBegin() _currentState = nullptr; _currentCompute = nullptr; _vertexLayout = nullptr; - _rtDepth = nullptr; Platform::MemoryClear(_rtHandles, sizeof(_rtHandles)); Platform::MemoryClear(_cbHandles, sizeof(_cbHandles)); Platform::MemoryClear(_srHandles, sizeof(_srHandles)); @@ -918,6 +964,17 @@ bool GPUContextVulkan::IsDepthBufferBinded() void GPUContextVulkan::Clear(GPUTextureView* rt, const Color& color) { + for (auto& e : _pendingClears) + { + if (e.View == rt) + { + // Use existing slot + Platform::MemoryCopy(e.Value.color.float32, color.Raw, sizeof(color.Raw)); + return; + } + } + + // Add a new entry auto& clear = _pendingClears.AddOne(); clear.View = (GPUTextureViewVulkan*)rt; Platform::MemoryCopy(clear.Value.color.float32, color.Raw, sizeof(color.Raw)); @@ -925,6 +982,18 @@ void GPUContextVulkan::Clear(GPUTextureView* rt, const Color& color) void GPUContextVulkan::ClearDepth(GPUTextureView* depthBuffer, float depthValue, uint8 stencilValue) { + for (auto& e : _pendingClears) + { + if (e.View == depthBuffer) + { + // Use existing slot + e.Value.depthStencil.depth = depthValue; + e.Value.depthStencil.stencil = stencilValue; + return; + } + } + + // Add a new entry auto& clear = _pendingClears.AddOne(); clear.View = (GPUTextureViewVulkan*)depthBuffer; clear.Value.depthStencil.depth = depthValue; @@ -1001,7 +1070,6 @@ void GPUContextVulkan::ResetRenderTarget() _rtDirtyFlag = true; _psDirtyFlag = true; _rtCount = 0; - _rtDepth = nullptr; Platform::MemoryClear(_rtHandles, sizeof(_rtHandles)); const auto cmdBuffer = _cmdBufferManager->GetActiveCmdBuffer(); @@ -1014,13 +1082,13 @@ void GPUContextVulkan::SetRenderTarget(GPUTextureView* rt) { const auto rtVulkan = static_cast(rt); - if (_rtDepth != nullptr || _rtCount != 1 || _rtHandles[0] != rtVulkan) + if (_rtDepth != nullptr || _rtCount != 1 || _rtTargets[0] != rtVulkan) { _rtDirtyFlag = true; _psDirtyFlag = true; _rtCount = 1; _rtDepth = nullptr; - _rtHandles[0] = rtVulkan; + _rtTargets[0] = rtVulkan; } } @@ -1030,13 +1098,13 @@ void GPUContextVulkan::SetRenderTarget(GPUTextureView* depthBuffer, GPUTextureVi const auto depthBufferVulkan = static_cast(depthBuffer); const auto rtCount = rtVulkan ? 1 : 0; - if (_rtDepth != depthBufferVulkan || _rtCount != rtCount || _rtHandles[0] != rtVulkan) + if (_rtDepth != depthBufferVulkan || _rtCount != rtCount || _rtTargets[0] != rtVulkan) { _rtDirtyFlag = true; _psDirtyFlag = true; _rtCount = rtCount; _rtDepth = depthBufferVulkan; - _rtHandles[0] = rtVulkan; + _rtTargets[0] = rtVulkan; } } @@ -1053,13 +1121,13 @@ void GPUContextVulkan::SetRenderTarget(GPUTextureView* depthBuffer, const SpanIsInsideRenderPass()) EndRenderPass(); - // Flush pending clears - for (auto& clear : _pendingClears) - ManualClear(clear); - _pendingClears.Clear(); - + FlushManualClears(); FlushBarriers(); } @@ -2012,7 +2076,7 @@ void GPUContextVulkan::BeginDrawPass(GPUDrawPass& pass) _drawPassCanClear = true; _rtCount = pass.RenderTargetsCount; _rtDepth = (GPUTextureViewVulkan*)pass.DepthBuffer; - Platform::MemoryCopy(_rtHandles, pass.RenderTargets, pass.RenderTargetsCount * sizeof(void*)); + Platform::MemoryCopy(_rtTargets, pass.RenderTargets, pass.RenderTargetsCount * sizeof(void*)); } void GPUContextVulkan::EndDrawPass() diff --git a/Source/Engine/GraphicsDevice/Vulkan/GPUContextVulkan.h b/Source/Engine/GraphicsDevice/Vulkan/GPUContextVulkan.h index 2a1847098..89bc58426 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/GPUContextVulkan.h +++ b/Source/Engine/GraphicsDevice/Vulkan/GPUContextVulkan.h @@ -96,8 +96,15 @@ private: GPUPipelineStateVulkan* _currentState; GPUShaderProgramCSVulkan* _currentCompute; GPUVertexLayoutVulkan* _vertexLayout; - GPUTextureViewVulkan* _rtDepth; - GPUTextureViewVulkan* _rtHandles[GPU_MAX_RT_BINDED]; + union + { + struct + { + GPUTextureViewVulkan* _rtDepth; + GPUTextureViewVulkan* _rtTargets[GPU_MAX_RT_BINDED]; + }; + GPUTextureViewVulkan* _rtHandles[GPU_MAX_RT_BINDED + 1]; + }; DescriptorOwnerResourceVulkan* _cbHandles[GPU_MAX_CB_BINDED]; DescriptorOwnerResourceVulkan* _srHandles[GPU_MAX_SR_BINDED]; DescriptorOwnerResourceVulkan* _uaHandles[GPU_MAX_UA_BINDED]; @@ -157,6 +164,7 @@ public: private: bool FindClear(const GPUTextureViewVulkan* view, PendingClear& clear); void ManualClear(const PendingClear& clear); + void FlushManualClears(); void UpdateDescriptorSets(const struct SpirvShaderDescriptorInfo& descriptorInfo, class DescriptorSetWriterVulkan& dsWriter, bool& needsWrite); void UpdateDescriptorSets(ComputePipelineStateVulkan* pipelineState); void OnDrawCall(); diff --git a/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.Layers.cpp b/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.Layers.cpp index 136524562..fdc65d5c9 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.Layers.cpp +++ b/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.Layers.cpp @@ -434,7 +434,7 @@ void GPUDeviceVulkan::GetInstanceLayersAndExtensions(Array& outInst } } -void GPUDeviceVulkan::GetDeviceExtensionsAndLayers(VkPhysicalDevice gpu, Array& outDeviceExtensions, Array& outDeviceLayers) +void GPUDeviceVulkan::GetDeviceExtensions(VkPhysicalDevice gpu, Array& outDeviceExtensions) { Array deviceLayerExtensions; deviceLayerExtensions.AddDefault(1); @@ -495,70 +495,19 @@ void GPUDeviceVulkan::GetDeviceExtensionsAndLayers(VkPhysicalDevice gpu, Array availableExtensions; + availableExtensions.Resize(deviceLayerExtensions[0].Extensions.Count()); + for (int32 i = 0; i < deviceLayerExtensions[0].Extensions.Count(); i++) { - for (int32 i = 0; i < deviceLayerExtensions[0].Extensions.Count(); i++) - { - availableExtensions.Add(deviceLayerExtensions[0].Extensions[i].extensionName); - } - - for (int32 layerIndex = 0; layerIndex < outDeviceLayers.Count(); layerIndex++) - { - int32 findLayerIndex; - for (findLayerIndex = 1; findLayerIndex < deviceLayerExtensions.Count(); findLayerIndex++) - { - if (!StringUtils::Compare(deviceLayerExtensions[findLayerIndex].Layer.layerName, outDeviceLayers[layerIndex])) - { - break; - } - } - - if (findLayerIndex < deviceLayerExtensions.Count()) - { - deviceLayerExtensions[findLayerIndex].GetExtensions(availableExtensions); - } - } + availableExtensions[i] = deviceLayerExtensions[0].Extensions[i].extensionName; } TrimDuplicates(availableExtensions); // Pick extensions to use Array platformExtensions; - VulkanPlatform::GetDeviceExtensions(platformExtensions, outDeviceLayers); + VulkanPlatform::GetDeviceExtensions(platformExtensions); for (const char* extension : platformExtensions) { if (ListContains(availableExtensions, extension)) @@ -583,15 +532,6 @@ void GPUDeviceVulkan::GetDeviceExtensionsAndLayers(VkPhysicalDevice gpu, Array& deviceExtensions) diff --git a/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp b/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp index 3f00ca798..140ca1a12 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp +++ b/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp @@ -130,6 +130,11 @@ static VKAPI_ATTR VkBool32 VKAPI_PTR DebugReportFunction(VkDebugReportFlagsEXT m #if VK_EXT_debug_utils +#if GPU_ENABLE_DEBUG_LAYER +#include "Engine/Threading/ThreadLocal.h" +extern ThreadLocal CurrentVulkanShaderLoading; +#endif + static VKAPI_ATTR VkBool32 VKAPI_PTR DebugUtilsCallback(VkDebugUtilsMessageSeverityFlagBitsEXT msgSeverity, VkDebugUtilsMessageTypeFlagsEXT msgType, const VkDebugUtilsMessengerCallbackDataEXT* callbackData, void* userData) { // Ignore some errors @@ -149,6 +154,7 @@ static VKAPI_ATTR VkBool32 VKAPI_PTR DebugUtilsCallback(VkDebugUtilsMessageSever case -1539028524: // SortedIndices is null so Vulkan backend sets it to default R32_SFLOAT format which is not good for UINT format of the buffer case -1810835948: // SortedIndices is null so Vulkan backend sets it to default R32_SFLOAT format which is not good for UINT format of the buffer case -1621360350: // VkFramebufferCreateInfo attachment #0 has a layer count (1) smaller than the corresponding framebuffer layer count (64). The Vulkan spec states: If flags does not include VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT, each element of pAttachments that is used as an input, color, resolve, or depth/stencil attachment by renderPass must have been created with a VkImageViewCreateInfo::subresourceRange.layerCount greater than or equal to layers + case -1744492148: // pCreateInfos[0] Inside [VK_SHADER_STAGE_FRAGMENT_BIT], it writes to [Output variable, Location 3], but there is no VkSubpassDescription::pColorAttachments[3] and this write is unused. return VK_FALSE; } break; @@ -158,6 +164,7 @@ static VKAPI_ATTR VkBool32 VKAPI_PTR DebugUtilsCallback(VkDebugUtilsMessageSever case 0: // Vertex shader writes to output location 0.0 which is not consumed by fragment shader case 558591440: // preTransform doesn't match the currentTransform returned by vkGetPhysicalDeviceSurfaceCapabilitiesKHR, the presentation engine will transform the image content as part of the presentation operation. TODO: implement preTransform for Android to improve swapchain presentation performance case 101294395: // Vertex shader writes to output location 0.0 which is not consumed by fragment shader + case -937765618: // pCreateInfos[0] (SPIR-V Interface) [VK_SHADER_STAGE_VERTEX_BIT] has an Output value declared at Location 1 Component 0, but there is no corresponding Input declared in [VK_SHADER_STAGE_FRAGMENT_BIT]. return VK_FALSE; } break; @@ -240,10 +247,14 @@ static VKAPI_ATTR VkBool32 VKAPI_PTR DebugUtilsCallback(VkDebugUtilsMessageSever LOG(Info, "[Vulkan] {0} {1}:{2} {3}", type, severity, callbackData->messageIdNumber, message); } -#if !BUILD_RELEASE +#if GPU_ENABLE_DEBUG_LAYER if (GPUDevice::Instance) { - if (auto* context = (GPUContextVulkan*)GPUDevice::Instance->GetMainContext()) + if (auto* shaderInitializer = CurrentVulkanShaderLoading.Get()) + { + LOG(Warning, "[Vulkan] Error during loading shader '{}' from '{}'", String(shaderInitializer->Name), String(shaderInitializer->Owner->GetName())); + } + else if (auto* context = (GPUContextVulkan*)GPUDevice::Instance->GetMainContext()) { if (auto* state = (GPUPipelineStateVulkan*)context->GetState()) { @@ -999,13 +1010,13 @@ GPUDeviceVulkan::GPUDeviceVulkan(ShaderProfile shaderProfile, GPUAdapterVulkan* GPUDevice* GPUDeviceVulkan::Create() { #if !USE_EDITOR && (PLATFORM_WINDOWS || PLATFORM_LINUX) - auto settings = PlatformSettings::Get(); - if (!settings->SupportVulkan) - { - // Skip if there is no support - LOG(Warning, "Cannot use Vulkan (support disabled)."); - return nullptr; - } + auto settings = PlatformSettings::Get(); + if (!settings->SupportVulkan) + { + // Skip if there is no support + LOG(Warning, "Cannot use Vulkan (support disabled)."); + return nullptr; + } #endif VkResult result; @@ -1225,10 +1236,19 @@ GPUDevice* GPUDeviceVulkan::Create() } } } - ASSERT(adapters[selectedAdapterIndex].IsValid()); + GPUAdapterVulkan& selectedAdapter = adapters[selectedAdapterIndex]; + ASSERT(selectedAdapter.IsValid()); + if (VK_VERSION_MAJOR(selectedAdapter.GpuProps.apiVersion) < VK_VERSION_MAJOR(VULKAN_API_VERSION) || VK_VERSION_MINOR(selectedAdapter.GpuProps.apiVersion) < VK_VERSION_MINOR(VULKAN_API_VERSION)) + { +#if PLATFORM_DESKTOP + LOG(Fatal, "Failed to use GPU '{}' with Vulkan API {}.{} which is lower than required {}.{}.\nCheck your video driver version for update to the latest one.", selectedAdapter.Description, VK_VERSION_MAJOR(selectedAdapter.GpuProps.apiVersion), VK_VERSION_MINOR(selectedAdapter.GpuProps.apiVersion), VK_VERSION_MAJOR(VULKAN_API_VERSION), VK_VERSION_MINOR(VULKAN_API_VERSION)); +#else + LOG(Fatal, "Failed to use GPU '{}' with Vulkan API {}.{} which is lower than required {}.{}.\nCheck your system for updates.", selectedAdapter.Description, VK_VERSION_MAJOR(selectedAdapter.GpuProps.apiVersion), VK_VERSION_MINOR(selectedAdapter.GpuProps.apiVersion), VK_VERSION_MAJOR(VULKAN_API_VERSION), VK_VERSION_MINOR(VULKAN_API_VERSION)); +#endif + } // Create device - auto device = New(ShaderProfile::Vulkan_SM5, New(adapters[selectedAdapterIndex])); + auto device = New(ShaderProfile::Vulkan_SM5, New(selectedAdapter)); if (device->Init()) { LOG(Warning, "Graphics Device init failed"); @@ -1616,8 +1636,7 @@ bool GPUDeviceVulkan::Init() // Get extensions and layers Array deviceExtensions; - Array validationLayers; - GetDeviceExtensionsAndLayers(gpu, deviceExtensions, validationLayers); + GetDeviceExtensions(gpu, deviceExtensions); ParseOptionalDeviceExtensions(deviceExtensions); // Setup device info @@ -1625,8 +1644,6 @@ bool GPUDeviceVulkan::Init() RenderToolsVulkan::ZeroStruct(deviceInfo, VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO); deviceInfo.enabledExtensionCount = deviceExtensions.Count(); deviceInfo.ppEnabledExtensionNames = deviceExtensions.Get(); - deviceInfo.enabledLayerCount = validationLayers.Count(); - deviceInfo.ppEnabledLayerNames = deviceInfo.enabledLayerCount > 0 ? validationLayers.Get() : nullptr; // Setup queues info Array queueFamilyInfos; @@ -1769,7 +1786,7 @@ bool GPUDeviceVulkan::Init() limits.HasInstancing = true; limits.HasVolumeTextureRendering = true; limits.HasDrawIndirect = PhysicalDeviceLimits.maxDrawIndirectCount >= 1; - limits.HasAppendConsumeBuffers = false; // TODO: add Append Consume buffers support for Vulkan + limits.HasAppendConsumeBuffers = false; limits.HasDepthClip = PhysicalDeviceFeatures.depthClamp; limits.HasDepthBounds = PhysicalDeviceFeatures.depthBounds; limits.HasDepthAsSRV = true; @@ -1877,7 +1894,9 @@ bool GPUDeviceVulkan::Init() // Initialize memory allocator { VmaVulkanFunctions vulkanFunctions; + Platform::MemoryClear(&vulkanFunctions, sizeof(vulkanFunctions)); #define INIT_FUNC(name) vulkanFunctions.name = name +#define INIT_FUNC_EXTENSION(name, extension) vulkanFunctions.name = name; if (!vulkanFunctions.name) vulkanFunctions.name = extension INIT_FUNC(vkGetPhysicalDeviceProperties); INIT_FUNC(vkGetPhysicalDeviceMemoryProperties); INIT_FUNC(vkAllocateMemory); @@ -1895,16 +1914,28 @@ bool GPUDeviceVulkan::Init() INIT_FUNC(vkCreateImage); INIT_FUNC(vkDestroyImage); INIT_FUNC(vkCmdCopyBuffer); -#if VMA_DEDICATED_ALLOCATION #if PLATFORM_SWITCH vulkanFunctions.vkGetBufferMemoryRequirements2KHR = vkGetBufferMemoryRequirements2; vulkanFunctions.vkGetImageMemoryRequirements2KHR = vkGetImageMemoryRequirements2; #else - INIT_FUNC(vkGetBufferMemoryRequirements2KHR); - INIT_FUNC(vkGetImageMemoryRequirements2KHR); +#if VMA_DEDICATED_ALLOCATION || VMA_VULKAN_VERSION >= 1001000 + INIT_FUNC_EXTENSION(vkGetBufferMemoryRequirements2KHR, vkGetBufferMemoryRequirements2); + INIT_FUNC_EXTENSION(vkGetImageMemoryRequirements2KHR, vkGetImageMemoryRequirements2); +#endif +#if VMA_BIND_MEMORY2 || VMA_VULKAN_VERSION >= 1001000 + INIT_FUNC_EXTENSION(vkBindBufferMemory2KHR, vkBindBufferMemory2); + INIT_FUNC_EXTENSION(vkBindImageMemory2KHR, vkBindImageMemory2); +#endif +#if VMA_MEMORY_BUDGET || VMA_VULKAN_VERSION >= 1001000 + INIT_FUNC_EXTENSION(vkGetPhysicalDeviceMemoryProperties2KHR, vkGetPhysicalDeviceMemoryProperties2); +#endif +#if VMA_KHR_MAINTENANCE4 || VMA_VULKAN_VERSION >= 1003000 + INIT_FUNC_EXTENSION(vkGetDeviceBufferMemoryRequirements, vkGetDeviceBufferMemoryRequirementsKHR); + INIT_FUNC_EXTENSION(vkGetDeviceImageMemoryRequirements, vkGetDeviceImageMemoryRequirementsKHR); #endif #endif #undef INIT_FUNC +#undef INIT_FUNC_EXTENSION VmaAllocatorCreateInfo allocatorInfo = {}; allocatorInfo.vulkanApiVersion = VULKAN_API_VERSION; allocatorInfo.physicalDevice = gpu; diff --git a/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.h b/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.h index a1de50c2d..156ec67e6 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.h +++ b/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.h @@ -396,7 +396,7 @@ public: private: static void GetInstanceLayersAndExtensions(Array& outInstanceExtensions, Array& outInstanceLayers, bool& outDebugUtils, bool useDebugLayer = false); - void GetDeviceExtensionsAndLayers(VkPhysicalDevice gpu, Array& outDeviceExtensions, Array& outDeviceLayers); + void GetDeviceExtensions(VkPhysicalDevice gpu, Array& outDeviceExtensions); static void ParseOptionalDeviceExtensions(const Array& deviceExtensions); public: diff --git a/Source/Engine/GraphicsDevice/Vulkan/GPUShaderVulkan.cpp b/Source/Engine/GraphicsDevice/Vulkan/GPUShaderVulkan.cpp index 021c6a651..11f34bfda 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/GPUShaderVulkan.cpp +++ b/Source/Engine/GraphicsDevice/Vulkan/GPUShaderVulkan.cpp @@ -101,6 +101,11 @@ void UniformBufferUploaderVulkan::OnReleaseGPU() } } +#if GPU_ENABLE_DEBUG_LAYER +#include "Engine/Threading/ThreadLocal.h" +ThreadLocal CurrentVulkanShaderLoading; +#endif + GPUShaderProgram* GPUShaderVulkan::CreateGPUShaderProgram(ShaderStage type, const GPUShaderProgramInitializer& initializer, Span bytecode, MemoryReadStream& stream) { // Extract the SPIR-V shader header from the cache @@ -146,8 +151,14 @@ GPUShaderProgram* GPUShaderVulkan::CreateGPUShaderProgram(ShaderStage type, cons validationInfo.validationCache = _device->ValidationCache; createInfo.pNext = &validationInfo; } +#endif +#if GPU_ENABLE_DEBUG_LAYER + CurrentVulkanShaderLoading = &initializer; #endif VALIDATE_VULKAN_RESULT(vkCreateShaderModule(_device->Device, &createInfo, nullptr, &shaderModule)); +#if GPU_ENABLE_DEBUG_LAYER + CurrentVulkanShaderLoading = nullptr; +#endif #if GPU_ENABLE_RESOURCE_NAMING VK_SET_DEBUG_NAME(_device, shaderModule, VK_OBJECT_TYPE_SHADER_MODULE, initializer.Name.GetText()); #endif diff --git a/Source/Engine/GraphicsDevice/Vulkan/GPUTextureVulkan.cpp b/Source/Engine/GraphicsDevice/Vulkan/GPUTextureVulkan.cpp index 311ac9220..5a7d17f3f 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/GPUTextureVulkan.cpp +++ b/Source/Engine/GraphicsDevice/Vulkan/GPUTextureVulkan.cpp @@ -94,6 +94,11 @@ void GPUTextureViewVulkan::Init(GPUDeviceVulkan* device, ResourceOwnerVulkan* ow } VALIDATE_VULKAN_RESULT(vkCreateImageView(device->Device, &Info, nullptr, &View)); + +#if VK_KHR_maintenance1 + if (arraySize == 1 && extent.depth > 1) + range.layerCount = VK_REMAINING_ARRAY_LAYERS; // without maintenance9 for per-layer masking all layers need to be enabled with a special value +#endif } VkImageView GPUTextureViewVulkan::GetFramebufferView() @@ -119,6 +124,7 @@ VkImageView GPUTextureViewVulkan::GetFramebufferView() // Use an additional view for that case with modified level count to 1. VkImageViewCreateInfo createInfo = Info; createInfo.subresourceRange.levelCount = 1; + createInfo.subresourceRange.layerCount = 1; VALIDATE_VULKAN_RESULT(vkCreateImageView(Device->Device, &createInfo, nullptr, &ViewFramebuffer)); } else diff --git a/Source/Engine/GraphicsDevice/Vulkan/VulkanPlatformBase.h b/Source/Engine/GraphicsDevice/Vulkan/VulkanPlatformBase.h index 3095472ee..d611ee4de 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/VulkanPlatformBase.h +++ b/Source/Engine/GraphicsDevice/Vulkan/VulkanPlatformBase.h @@ -29,7 +29,7 @@ public: { } - static void GetDeviceExtensions(Array& extensions, Array& layers) + static void GetDeviceExtensions(Array& extensions) { } diff --git a/Source/Engine/GraphicsDevice/Vulkan/Win32/Win32VulkanPlatform.h b/Source/Engine/GraphicsDevice/Vulkan/Win32/Win32VulkanPlatform.h index 96dbf2e18..baa44c880 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/Win32/Win32VulkanPlatform.h +++ b/Source/Engine/GraphicsDevice/Vulkan/Win32/Win32VulkanPlatform.h @@ -6,6 +6,7 @@ #if GRAPHICS_API_VULKAN && PLATFORM_WIN32 +#define VULKAN_API_VERSION VK_API_VERSION_1_2 #define VULKAN_USE_PLATFORM_WIN32_KHR 1 #define VULKAN_USE_PLATFORM_WIN32_KHX 1 #define VULKAN_USE_CREATE_WIN32_SURFACE 1 diff --git a/Source/Engine/Renderer/GBufferPass.cpp b/Source/Engine/Renderer/GBufferPass.cpp index 14e7ad1c3..8b5927ceb 100644 --- a/Source/Engine/Renderer/GBufferPass.cpp +++ b/Source/Engine/Renderer/GBufferPass.cpp @@ -189,12 +189,9 @@ void GBufferPass::Fill(RenderContext& renderContext, GPUTexture* lightBuffer) context->Clear(renderContext.Buffers->GBuffer3->View(), Color::Transparent); } - // Ensure to have valid data + // Skip when resources are not loaded yet if (checkIfSkipPass()) - { - // Resources are missing. Do not perform rendering. return; - } #if USE_EDITOR // Special debug drawing diff --git a/Source/Engine/ShadersCompilation/Vulkan/ShaderCompilerVulkan.cpp b/Source/Engine/ShadersCompilation/Vulkan/ShaderCompilerVulkan.cpp index 9f4db5c8a..4932e0eb1 100644 --- a/Source/Engine/ShadersCompilation/Vulkan/ShaderCompilerVulkan.cpp +++ b/Source/Engine/ShadersCompilation/Vulkan/ShaderCompilerVulkan.cpp @@ -945,13 +945,45 @@ bool ShaderCompilerVulkan::OnCompileBegin() void ShaderCompilerVulkan::InitParsing(ShaderCompilationContext* context, glslang::TShader& shader) { + // Pick Vulkan version based on target platform + // Based on: https://docs.vulkan.org/guide/latest/versions.html#_spir_v + glslang::EShTargetClientVersion targetVulkan; + glslang::EShTargetLanguageVersion targetLang; + switch (context->Options->Platform) + { + case PlatformType::Windows: + // TODO: update glslang and try Vulkan 1.2 with SPIR-V 1.5 + targetVulkan = glslang::EShTargetVulkan_1_1; + targetLang = glslang::EShTargetSpv_1_2; + break; + case PlatformType::Android: + targetVulkan = glslang::EShTargetVulkan_1_1; + targetLang = glslang::EShTargetSpv_1_2; + break; + case PlatformType::Switch: + // TODO: update glslang and try Vulkan 1.3 with SPIR-V 1.6 + targetVulkan = glslang::EShTargetVulkan_1_1; + targetLang = glslang::EShTargetSpv_1_2; + break; + case PlatformType::Mac: + case PlatformType::iOS: + // TODO: update glslang and try Vulkan 1.4 with SPIR-V 1.6 + targetVulkan = glslang::EShTargetVulkan_1_1; + targetLang = glslang::EShTargetSpv_1_2; + break; + default: + targetVulkan = glslang::EShTargetVulkan_1_0; + targetLang = glslang::EShTargetSpv_1_0; + break; + } + shader.setInvertY(true); //shader.setAutoMapLocations(true); //shader.setAutoMapBindings(true); //shader.setShiftBinding(glslang::TResourceType::EResUav, 500); shader.setHlslIoMapping(true); - shader.setEnvClient(glslang::EShClientVulkan, glslang::EShTargetVulkan_1_0); - shader.setEnvTarget(glslang::EShTargetSpv, glslang::EShTargetSpv_1_0); + shader.setEnvClient(glslang::EShClientVulkan, targetVulkan); + shader.setEnvTarget(glslang::EShTargetSpv, targetLang); } void ShaderCompilerVulkan::InitCodegen(ShaderCompilationContext* context, glslang::SpvOptions& spvOptions) diff --git a/Source/Engine/Threading/ThreadLocal.h b/Source/Engine/Threading/ThreadLocal.h index 728662b00..526405763 100644 --- a/Source/Engine/Threading/ThreadLocal.h +++ b/Source/Engine/Threading/ThreadLocal.h @@ -54,6 +54,12 @@ public: GetBucket().Value = value; } + FORCE_INLINE ThreadLocal& operator=(const T& value) + { + GetBucket().Value = value; + return *this; + } + int32 Count() const { int32 result = 0;