From 9ace79a4d26d55ff5edb4f9fc409d7badb576bcf Mon Sep 17 00:00:00 2001 From: squidbus <175574877+squidbus@users.noreply.github.com> Date: Sun, 3 Aug 2025 09:52:08 -0700 Subject: [PATCH] Switch to upstream plume. (#1645) --- .gitmodules | 15 +- CMakeLists.txt | 8 + UnleashedRecomp/CMakeLists.txt | 18 +- UnleashedRecomp/gpu/rhi/LICENSE | 21 - UnleashedRecomp/gpu/rhi/plume_d3d12.cpp | 3924 --------------- UnleashedRecomp/gpu/rhi/plume_d3d12.h | 481 -- .../gpu/rhi/plume_render_interface.h | 262 - .../gpu/rhi/plume_render_interface_builders.h | 281 -- .../gpu/rhi/plume_render_interface_types.h | 1824 ------- UnleashedRecomp/gpu/rhi/plume_vulkan.cpp | 4474 ----------------- UnleashedRecomp/gpu/rhi/plume_vulkan.h | 463 -- UnleashedRecomp/gpu/video.cpp | 30 +- UnleashedRecomp/gpu/video.h | 2 +- UnleashedRecomp/ui/game_window.cpp | 2 +- UnleashedRecomp/ui/game_window.h | 2 +- thirdparty/CMakeLists.txt | 1 + thirdparty/D3D12MemoryAllocator | 1 - thirdparty/MoltenVK/CMakeLists.txt | 2 +- thirdparty/Vulkan-Headers | 1 - thirdparty/VulkanMemoryAllocator | 1 - thirdparty/plume | 1 + thirdparty/volk | 1 - 22 files changed, 33 insertions(+), 11782 deletions(-) delete mode 100644 UnleashedRecomp/gpu/rhi/LICENSE delete mode 100644 UnleashedRecomp/gpu/rhi/plume_d3d12.cpp delete mode 100644 UnleashedRecomp/gpu/rhi/plume_d3d12.h delete mode 100644 UnleashedRecomp/gpu/rhi/plume_render_interface.h delete mode 100644 UnleashedRecomp/gpu/rhi/plume_render_interface_builders.h delete mode 100644 UnleashedRecomp/gpu/rhi/plume_render_interface_types.h delete mode 100644 UnleashedRecomp/gpu/rhi/plume_vulkan.cpp delete mode 100644 UnleashedRecomp/gpu/rhi/plume_vulkan.h delete mode 160000 thirdparty/D3D12MemoryAllocator delete mode 160000 thirdparty/Vulkan-Headers delete mode 160000 thirdparty/VulkanMemoryAllocator create mode 160000 thirdparty/plume delete mode 160000 thirdparty/volk diff --git a/.gitmodules b/.gitmodules index fa8706a..b4b2dba 100644 --- a/.gitmodules +++ b/.gitmodules @@ -16,21 +16,9 @@ [submodule "thirdparty/vcpkg"] path = thirdparty/vcpkg url = https://github.com/microsoft/vcpkg -[submodule "thirdparty/volk"] - path = thirdparty/volk - url = https://github.com/zeux/volk [submodule "thirdparty/SDL"] path = thirdparty/SDL url = https://github.com/libsdl-org/SDL.git -[submodule "thirdparty/Vulkan-Headers"] - path = thirdparty/Vulkan-Headers - url = https://github.com/KhronosGroup/Vulkan-Headers.git -[submodule "thirdparty/VulkanMemoryAllocator"] - path = thirdparty/VulkanMemoryAllocator - url = https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git -[submodule "thirdparty/D3D12MemoryAllocator"] - path = thirdparty/D3D12MemoryAllocator - url = https://github.com/GPUOpen-LibrariesAndSDKs/D3D12MemoryAllocator.git [submodule "thirdparty/stb"] path = thirdparty/stb url = https://github.com/nothings/stb.git @@ -67,3 +55,6 @@ [submodule "thirdparty/MoltenVK/SPIRV-Cross"] path = thirdparty/MoltenVK/SPIRV-Cross url = https://github.com/KhronosGroup/SPIRV-Cross.git +[submodule "thirdparty/plume"] + path = thirdparty/plume + url = https://github.com/renderbag/plume.git diff --git a/CMakeLists.txt b/CMakeLists.txt index b41ae44..da6b28d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,6 +19,14 @@ set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") project("UnleashedRecomp-ALL") +if (APPLE) + enable_language(OBJC OBJCXX) +endif() + +if (CMAKE_SYSTEM_NAME MATCHES "Linux") + set(SDL_VULKAN_ENABLED ON CACHE BOOL "") +endif() + if (CMAKE_OSX_ARCHITECTURES) set(UNLEASHED_RECOMP_ARCHITECTURE ${CMAKE_OSX_ARCHITECTURES}) elseif(CMAKE_SYSTEM_PROCESSOR) diff --git a/UnleashedRecomp/CMakeLists.txt b/UnleashedRecomp/CMakeLists.txt index 48908bf..b966989 100644 --- a/UnleashedRecomp/CMakeLists.txt +++ b/UnleashedRecomp/CMakeLists.txt @@ -116,15 +116,8 @@ set(UNLEASHED_RECOMP_GPU_CXX_SOURCES "gpu/imgui/imgui_common.cpp" "gpu/imgui/imgui_font_builder.cpp" "gpu/imgui/imgui_snapshot.cpp" - "gpu/rhi/plume_vulkan.cpp" ) -if (UNLEASHED_RECOMP_D3D12) - list(APPEND UNLEASHED_RECOMP_GPU_CXX_SOURCES - "gpu/rhi/plume_d3d12.cpp" - ) -endif() - set(UNLEASHED_RECOMP_APU_CXX_SOURCES "apu/audio.cpp" "apu/embedded_player.cpp" @@ -221,18 +214,10 @@ set(UNLEASHED_RECOMP_THIRDPARTY_INCLUDES "${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/magic_enum/include" "${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/stb" "${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/unordered_dense/include" - "${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/volk" - "${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/Vulkan-Headers/include" - "${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/VulkanMemoryAllocator/include" "${UNLEASHED_RECOMP_TOOLS_ROOT}/bc_diff" "${UNLEASHED_RECOMP_TOOLS_ROOT}/XenosRecomp/thirdparty/smol-v/source" ) -if (UNLEASHED_RECOMP_D3D12) - list(APPEND UNLEASHED_RECOMP_THIRDPARTY_INCLUDES "${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/D3D12MemoryAllocator/include") - list(APPEND UNLEASHED_RECOMP_THIRDPARTY_SOURCES "${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/D3D12MemoryAllocator/src/D3D12MemAlloc.cpp") -endif() - set_source_files_properties(${UNLEASHED_RECOMP_THIRDPARTY_SOURCES} PROPERTIES SKIP_PRECOMPILE_HEADERS ON) set(UNLEASHED_RECOMP_CXX_SOURCES @@ -377,7 +362,7 @@ if (UNLEASHED_RECOMP_D3D12) ) endif() -if (CMAKE_SYSTEM_NAME MATCHES "Linux") +if (SDL_VULKAN_ENABLED) target_compile_definitions(UnleashedRecomp PRIVATE SDL_VULKAN_ENABLED) endif() @@ -428,6 +413,7 @@ target_link_libraries(UnleashedRecomp PRIVATE UnleashedRecompLib xxHash::xxhash CURL::libcurl + plume ) target_include_directories(UnleashedRecomp PRIVATE diff --git a/UnleashedRecomp/gpu/rhi/LICENSE b/UnleashedRecomp/gpu/rhi/LICENSE deleted file mode 100644 index b05f241..0000000 --- a/UnleashedRecomp/gpu/rhi/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2024 renderbag and contributors - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/UnleashedRecomp/gpu/rhi/plume_d3d12.cpp b/UnleashedRecomp/gpu/rhi/plume_d3d12.cpp deleted file mode 100644 index 04102c0..0000000 --- a/UnleashedRecomp/gpu/rhi/plume_d3d12.cpp +++ /dev/null @@ -1,3924 +0,0 @@ -// -// plume -// -// Copyright (c) 2024 renderbag and contributors. All rights reserved. -// Licensed under the MIT license. See LICENSE file for details. -// - -#include "plume_d3d12.h" - -#include - -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wtautological-undefined-compare" -#pragma clang diagnostic ignored "-Wswitch" -#endif - -#ifdef __clang__ -#pragma clang diagnostic pop -#endif - -#ifndef NDEBUG -# define D3D12_DEBUG_LAYER_ENABLED -# define D3D12_DEBUG_LAYER_BREAK_ON_ERROR true -# define D3D12_DEBUG_LAYER_BREAK_ON_WARNING false -# define D3D12_DEBUG_LAYER_SUPRESS_SAMPLE_POSITIONS_ERROR // Supress error message that's been fixed in newer Agility SDK versions. -//# define D3D12_DEBUG_LAYER_GPU_BASED_VALIDATION_ENABLED -#endif - -//#define D3D12_DEBUG_SET_STABLE_POWER_STATE - -// Old Windows SDK versions don't provide this macro, so we workaround it by making sure it is defined. -#ifndef D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE -#define D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE (D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE | D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE) -#endif - -extern "C" { - __declspec(dllexport) extern const UINT D3D12SDKVersion = D3D12_SDK_VERSION; - __declspec(dllexport) extern const char* D3D12SDKPath = ".\\D3D12\\"; -} - -namespace plume { - static const uint32_t ShaderDescriptorHeapSize = 65536; - static const uint32_t SamplerDescriptorHeapSize = 1024; - static const uint32_t TargetDescriptorHeapSize = 16384; - - // Common functions. - - static std::wstring Utf8ToUtf16(const std::string_view& value) { - std::wstring wideStr; - wideStr.resize(MultiByteToWideChar(CP_UTF8, 0, value.data(), value.size(), nullptr, 0)); - MultiByteToWideChar(CP_UTF8, 0, value.data(), value.size(), wideStr.data(), wideStr.size()); - return wideStr; - } - - static std::string Utf16ToUtf8(const std::wstring_view& value) { - std::string multiByteStr; - multiByteStr.resize(WideCharToMultiByte(CP_UTF8, 0, value.data(), value.size(), nullptr, 0, nullptr, FALSE)); - WideCharToMultiByte(CP_UTF8, 0, value.data(), value.size(), multiByteStr.data(), multiByteStr.size(), nullptr, FALSE); - return multiByteStr; - } - - static uint32_t roundUp(uint32_t value, uint32_t powerOf2Alignment) { - return (value + powerOf2Alignment - 1) & ~(powerOf2Alignment - 1); - } - - static uint64_t roundUp(uint64_t value, uint64_t powerOf2Alignment) { - return (value + powerOf2Alignment - 1) & ~(powerOf2Alignment - 1); - } - - static DXGI_FORMAT toDXGI(RenderFormat format) { - switch (format) { - case RenderFormat::UNKNOWN: - return DXGI_FORMAT_UNKNOWN; - case RenderFormat::R32G32B32A32_TYPELESS: - return DXGI_FORMAT_R32G32B32A32_TYPELESS; - case RenderFormat::R32G32B32A32_FLOAT: - return DXGI_FORMAT_R32G32B32A32_FLOAT; - case RenderFormat::R32G32B32A32_UINT: - return DXGI_FORMAT_R32G32B32A32_UINT; - case RenderFormat::R32G32B32A32_SINT: - return DXGI_FORMAT_R32G32B32A32_SINT; - case RenderFormat::R32G32B32_TYPELESS: - return DXGI_FORMAT_R32G32B32_TYPELESS; - case RenderFormat::R32G32B32_FLOAT: - return DXGI_FORMAT_R32G32B32_FLOAT; - case RenderFormat::R32G32B32_UINT: - return DXGI_FORMAT_R32G32B32_UINT; - case RenderFormat::R32G32B32_SINT: - return DXGI_FORMAT_R32G32B32_SINT; - case RenderFormat::R16G16B16A16_TYPELESS: - return DXGI_FORMAT_R16G16B16A16_TYPELESS; - case RenderFormat::R16G16B16A16_FLOAT: - return DXGI_FORMAT_R16G16B16A16_FLOAT; - case RenderFormat::R16G16B16A16_UNORM: - return DXGI_FORMAT_R16G16B16A16_UNORM; - case RenderFormat::R16G16B16A16_UINT: - return DXGI_FORMAT_R16G16B16A16_UINT; - case RenderFormat::R16G16B16A16_SNORM: - return DXGI_FORMAT_R16G16B16A16_SNORM; - case RenderFormat::R16G16B16A16_SINT: - return DXGI_FORMAT_R16G16B16A16_SINT; - case RenderFormat::R32G32_TYPELESS: - return DXGI_FORMAT_R32G32_TYPELESS; - case RenderFormat::R32G32_FLOAT: - return DXGI_FORMAT_R32G32_FLOAT; - case RenderFormat::R32G32_UINT: - return DXGI_FORMAT_R32G32_UINT; - case RenderFormat::R32G32_SINT: - return DXGI_FORMAT_R32G32_SINT; - case RenderFormat::R8G8B8A8_TYPELESS: - return DXGI_FORMAT_R8G8B8A8_TYPELESS; - case RenderFormat::R8G8B8A8_UNORM: - return DXGI_FORMAT_R8G8B8A8_UNORM; - case RenderFormat::R8G8B8A8_UINT: - return DXGI_FORMAT_R8G8B8A8_UINT; - case RenderFormat::R8G8B8A8_SNORM: - return DXGI_FORMAT_R8G8B8A8_SNORM; - case RenderFormat::R8G8B8A8_SINT: - return DXGI_FORMAT_R8G8B8A8_SINT; - case RenderFormat::B8G8R8A8_UNORM: - return DXGI_FORMAT_B8G8R8A8_UNORM; - case RenderFormat::R16G16_TYPELESS: - return DXGI_FORMAT_R16G16_TYPELESS; - case RenderFormat::R16G16_FLOAT: - return DXGI_FORMAT_R16G16_FLOAT; - case RenderFormat::R16G16_UNORM: - return DXGI_FORMAT_R16G16_UNORM; - case RenderFormat::R16G16_UINT: - return DXGI_FORMAT_R16G16_UINT; - case RenderFormat::R16G16_SNORM: - return DXGI_FORMAT_R16G16_SNORM; - case RenderFormat::R16G16_SINT: - return DXGI_FORMAT_R16G16_SINT; - case RenderFormat::R32_TYPELESS: - return DXGI_FORMAT_R32_TYPELESS; - case RenderFormat::D32_FLOAT: - return DXGI_FORMAT_D32_FLOAT; - case RenderFormat::R32_FLOAT: - return DXGI_FORMAT_R32_FLOAT; - case RenderFormat::R32_UINT: - return DXGI_FORMAT_R32_UINT; - case RenderFormat::R32_SINT: - return DXGI_FORMAT_R32_SINT; - case RenderFormat::R8G8_TYPELESS: - return DXGI_FORMAT_R8G8_TYPELESS; - case RenderFormat::R8G8_UNORM: - return DXGI_FORMAT_R8G8_UNORM; - case RenderFormat::R8G8_UINT: - return DXGI_FORMAT_R8G8_UINT; - case RenderFormat::R8G8_SNORM: - return DXGI_FORMAT_R8G8_SNORM; - case RenderFormat::R8G8_SINT: - return DXGI_FORMAT_R8G8_SINT; - case RenderFormat::R16_TYPELESS: - return DXGI_FORMAT_R16_TYPELESS; - case RenderFormat::R16_FLOAT: - return DXGI_FORMAT_R16_FLOAT; - case RenderFormat::D16_UNORM: - return DXGI_FORMAT_D16_UNORM; - case RenderFormat::R16_UNORM: - return DXGI_FORMAT_R16_UNORM; - case RenderFormat::R16_UINT: - return DXGI_FORMAT_R16_UINT; - case RenderFormat::R16_SNORM: - return DXGI_FORMAT_R16_SNORM; - case RenderFormat::R16_SINT: - return DXGI_FORMAT_R16_SINT; - case RenderFormat::R8_TYPELESS: - return DXGI_FORMAT_R8_TYPELESS; - case RenderFormat::R8_UNORM: - return DXGI_FORMAT_R8_UNORM; - case RenderFormat::R8_UINT: - return DXGI_FORMAT_R8_UINT; - case RenderFormat::R8_SNORM: - return DXGI_FORMAT_R8_SNORM; - case RenderFormat::R8_SINT: - return DXGI_FORMAT_R8_SINT; - case RenderFormat::BC1_TYPELESS: - return DXGI_FORMAT_BC1_TYPELESS; - case RenderFormat::BC1_UNORM: - return DXGI_FORMAT_BC1_UNORM; - case RenderFormat::BC1_UNORM_SRGB: - return DXGI_FORMAT_BC1_UNORM_SRGB; - case RenderFormat::BC2_TYPELESS: - return DXGI_FORMAT_BC2_TYPELESS; - case RenderFormat::BC2_UNORM: - return DXGI_FORMAT_BC2_UNORM; - case RenderFormat::BC2_UNORM_SRGB: - return DXGI_FORMAT_BC2_UNORM_SRGB; - case RenderFormat::BC3_TYPELESS: - return DXGI_FORMAT_BC3_TYPELESS; - case RenderFormat::BC3_UNORM: - return DXGI_FORMAT_BC3_UNORM; - case RenderFormat::BC3_UNORM_SRGB: - return DXGI_FORMAT_BC3_UNORM_SRGB; - case RenderFormat::BC4_TYPELESS: - return DXGI_FORMAT_BC4_TYPELESS; - case RenderFormat::BC4_UNORM: - return DXGI_FORMAT_BC4_UNORM; - case RenderFormat::BC4_SNORM: - return DXGI_FORMAT_BC4_SNORM; - case RenderFormat::BC5_TYPELESS: - return DXGI_FORMAT_BC5_TYPELESS; - case RenderFormat::BC5_UNORM: - return DXGI_FORMAT_BC5_UNORM; - case RenderFormat::BC5_SNORM: - return DXGI_FORMAT_BC5_SNORM; - case RenderFormat::BC6H_TYPELESS: - return DXGI_FORMAT_BC6H_TYPELESS; - case RenderFormat::BC6H_UF16: - return DXGI_FORMAT_BC6H_UF16; - case RenderFormat::BC6H_SF16: - return DXGI_FORMAT_BC6H_SF16; - case RenderFormat::BC7_TYPELESS: - return DXGI_FORMAT_BC7_TYPELESS; - case RenderFormat::BC7_UNORM: - return DXGI_FORMAT_BC7_UNORM; - case RenderFormat::BC7_UNORM_SRGB: - return DXGI_FORMAT_BC7_UNORM_SRGB; - default: - assert(false && "Unknown format."); - return DXGI_FORMAT_FORCE_UINT; - } - } - - static D3D12_BLEND toD3D12(RenderBlend blend) { - switch (blend) { - case RenderBlend::ZERO: - return D3D12_BLEND_ZERO; - case RenderBlend::ONE: - return D3D12_BLEND_ONE; - case RenderBlend::SRC_COLOR: - return D3D12_BLEND_SRC_COLOR; - case RenderBlend::INV_SRC_COLOR: - return D3D12_BLEND_INV_SRC_COLOR; - case RenderBlend::SRC_ALPHA: - return D3D12_BLEND_SRC_ALPHA; - case RenderBlend::INV_SRC_ALPHA: - return D3D12_BLEND_INV_SRC_ALPHA; - case RenderBlend::DEST_ALPHA: - return D3D12_BLEND_DEST_ALPHA; - case RenderBlend::INV_DEST_ALPHA: - return D3D12_BLEND_INV_DEST_ALPHA; - case RenderBlend::DEST_COLOR: - return D3D12_BLEND_DEST_COLOR; - case RenderBlend::INV_DEST_COLOR: - return D3D12_BLEND_INV_DEST_COLOR; - case RenderBlend::SRC_ALPHA_SAT: - return D3D12_BLEND_SRC_ALPHA_SAT; - case RenderBlend::BLEND_FACTOR: - return D3D12_BLEND_BLEND_FACTOR; - case RenderBlend::INV_BLEND_FACTOR: - return D3D12_BLEND_INV_BLEND_FACTOR; - case RenderBlend::SRC1_COLOR: - return D3D12_BLEND_SRC1_COLOR; - case RenderBlend::INV_SRC1_COLOR: - return D3D12_BLEND_INV_SRC1_COLOR; - case RenderBlend::SRC1_ALPHA: - return D3D12_BLEND_SRC1_ALPHA; - case RenderBlend::INV_SRC1_ALPHA: - return D3D12_BLEND_INV_SRC1_ALPHA; - default: - assert(false && "Unknown blend."); - return D3D12_BLEND_ZERO; - } - } - - static D3D12_BLEND_OP toD3D12(RenderBlendOperation operation) { - switch (operation) { - case RenderBlendOperation::ADD: - return D3D12_BLEND_OP_ADD; - case RenderBlendOperation::SUBTRACT: - return D3D12_BLEND_OP_SUBTRACT; - case RenderBlendOperation::REV_SUBTRACT: - return D3D12_BLEND_OP_REV_SUBTRACT; - case RenderBlendOperation::MIN: - return D3D12_BLEND_OP_MIN; - case RenderBlendOperation::MAX: - return D3D12_BLEND_OP_MAX; - default: - assert(false && "Unknown blend operation."); - return D3D12_BLEND_OP_ADD; - } - } - - static D3D12_COLOR_WRITE_ENABLE toD3D12(RenderColorWriteEnable enable) { - return D3D12_COLOR_WRITE_ENABLE( - ((uint32_t(enable) & uint32_t(RenderColorWriteEnable::RED)) ? D3D12_COLOR_WRITE_ENABLE_RED : 0x0) | - ((uint32_t(enable) & uint32_t(RenderColorWriteEnable::GREEN)) ? D3D12_COLOR_WRITE_ENABLE_GREEN : 0x0) | - ((uint32_t(enable) & uint32_t(RenderColorWriteEnable::BLUE)) ? D3D12_COLOR_WRITE_ENABLE_BLUE : 0x0) | - ((uint32_t(enable) & uint32_t(RenderColorWriteEnable::ALPHA)) ? D3D12_COLOR_WRITE_ENABLE_ALPHA : 0x0) - ); - } - - static D3D12_LOGIC_OP toD3D12(RenderLogicOperation operation) { - switch (operation) { - case RenderLogicOperation::CLEAR: - return D3D12_LOGIC_OP_CLEAR; - case RenderLogicOperation::SET: - return D3D12_LOGIC_OP_SET; - case RenderLogicOperation::COPY: - return D3D12_LOGIC_OP_COPY; - case RenderLogicOperation::COPY_INVERTED: - return D3D12_LOGIC_OP_COPY_INVERTED; - case RenderLogicOperation::NOOP: - return D3D12_LOGIC_OP_NOOP; - case RenderLogicOperation::INVERT: - return D3D12_LOGIC_OP_INVERT; - case RenderLogicOperation::AND: - return D3D12_LOGIC_OP_AND; - case RenderLogicOperation::NAND: - return D3D12_LOGIC_OP_NAND; - case RenderLogicOperation::OR: - return D3D12_LOGIC_OP_OR; - case RenderLogicOperation::NOR: - return D3D12_LOGIC_OP_NOR; - case RenderLogicOperation::XOR: - return D3D12_LOGIC_OP_XOR; - case RenderLogicOperation::EQUIV: - return D3D12_LOGIC_OP_EQUIV; - case RenderLogicOperation::AND_REVERSE: - return D3D12_LOGIC_OP_AND_REVERSE; - case RenderLogicOperation::AND_INVERTED: - return D3D12_LOGIC_OP_AND_INVERTED; - case RenderLogicOperation::OR_REVERSE: - return D3D12_LOGIC_OP_OR_REVERSE; - case RenderLogicOperation::OR_INVERTED: - return D3D12_LOGIC_OP_OR_INVERTED; - default: - assert(false && "Unknown logic operation."); - return D3D12_LOGIC_OP_CLEAR; - } - } - - static D3D12_FILTER toFilter(RenderFilter minFilter, RenderFilter magFilter, RenderMipmapMode mipmapMode, bool anisotropyEnabled, bool comparisonEnabled) { - assert(minFilter != RenderFilter::UNKNOWN); - assert(magFilter != RenderFilter::UNKNOWN); - assert(mipmapMode != RenderMipmapMode::UNKNOWN); - - if (anisotropyEnabled) { - return comparisonEnabled ? D3D12_FILTER_COMPARISON_ANISOTROPIC : D3D12_FILTER_ANISOTROPIC; - } - else { - uint32_t filterInt = 0; - filterInt |= (mipmapMode == RenderMipmapMode::LINEAR) ? 0x1 : 0x0; - filterInt |= (magFilter == RenderFilter::LINEAR) ? 0x4 : 0x0; - filterInt |= (minFilter == RenderFilter::LINEAR) ? 0x10 : 0x0; - filterInt |= comparisonEnabled ? 0x80 : 0x0; - return D3D12_FILTER(filterInt); - } - } - - static D3D12_TEXTURE_ADDRESS_MODE toD3D12(RenderTextureAddressMode addressMode) { - switch (addressMode) { - case RenderTextureAddressMode::WRAP: - return D3D12_TEXTURE_ADDRESS_MODE_WRAP; - case RenderTextureAddressMode::MIRROR: - return D3D12_TEXTURE_ADDRESS_MODE_MIRROR; - case RenderTextureAddressMode::CLAMP: - return D3D12_TEXTURE_ADDRESS_MODE_CLAMP; - case RenderTextureAddressMode::BORDER: - return D3D12_TEXTURE_ADDRESS_MODE_BORDER; - case RenderTextureAddressMode::MIRROR_ONCE: - return D3D12_TEXTURE_ADDRESS_MODE_MIRROR_ONCE; - default: - assert(false && "Unknown texture address mode."); - return D3D12_TEXTURE_ADDRESS_MODE_WRAP; - } - } - - static D3D12_STATIC_BORDER_COLOR toStaticBorderColor(RenderBorderColor borderColor) { - switch (borderColor) { - case RenderBorderColor::TRANSPARENT_BLACK: - return D3D12_STATIC_BORDER_COLOR_TRANSPARENT_BLACK; - case RenderBorderColor::OPAQUE_BLACK: - return D3D12_STATIC_BORDER_COLOR_OPAQUE_BLACK; - case RenderBorderColor::OPAQUE_WHITE: - return D3D12_STATIC_BORDER_COLOR_OPAQUE_WHITE; - default: - assert(false && "Unknown static border color."); - return D3D12_STATIC_BORDER_COLOR_TRANSPARENT_BLACK; - } - } - - static D3D12_SHADER_VISIBILITY toD3D12(RenderShaderVisibility visibility) { - switch (visibility) { - case RenderShaderVisibility::ALL: - return D3D12_SHADER_VISIBILITY_ALL; - case RenderShaderVisibility::VERTEX: - return D3D12_SHADER_VISIBILITY_VERTEX; - case RenderShaderVisibility::GEOMETRY: - return D3D12_SHADER_VISIBILITY_GEOMETRY; - case RenderShaderVisibility::PIXEL: - return D3D12_SHADER_VISIBILITY_PIXEL; - default: - assert(false && "Unknown shader visibility."); - return D3D12_SHADER_VISIBILITY_ALL; - } - } - - static D3D12_INPUT_CLASSIFICATION toD3D12(RenderInputSlotClassification classification) { - switch (classification) { - case RenderInputSlotClassification::PER_VERTEX_DATA: - return D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA; - case RenderInputSlotClassification::PER_INSTANCE_DATA: - return D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA; - default: - assert(false && "Unknown input classification."); - return D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA; - } - } - - static D3D12_DESCRIPTOR_RANGE_TYPE toRangeType(RenderDescriptorRangeType type) { - switch (type) { - case RenderDescriptorRangeType::FORMATTED_BUFFER: - case RenderDescriptorRangeType::TEXTURE: - case RenderDescriptorRangeType::STRUCTURED_BUFFER: - case RenderDescriptorRangeType::BYTE_ADDRESS_BUFFER: - case RenderDescriptorRangeType::ACCELERATION_STRUCTURE: - return D3D12_DESCRIPTOR_RANGE_TYPE_SRV; - case RenderDescriptorRangeType::READ_WRITE_FORMATTED_BUFFER: - case RenderDescriptorRangeType::READ_WRITE_TEXTURE: - case RenderDescriptorRangeType::READ_WRITE_STRUCTURED_BUFFER: - case RenderDescriptorRangeType::READ_WRITE_BYTE_ADDRESS_BUFFER: - return D3D12_DESCRIPTOR_RANGE_TYPE_UAV; - case RenderDescriptorRangeType::CONSTANT_BUFFER: - return D3D12_DESCRIPTOR_RANGE_TYPE_CBV; - case RenderDescriptorRangeType::SAMPLER: - return D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER; - default: - assert(false && "Unknown descriptor range type."); - return D3D12_DESCRIPTOR_RANGE_TYPE_SRV; - } - } - - static D3D12_HEAP_TYPE toD3D12(RenderHeapType type) { - switch (type) { - case RenderHeapType::DEFAULT: - return D3D12_HEAP_TYPE_DEFAULT; - case RenderHeapType::UPLOAD: - return D3D12_HEAP_TYPE_UPLOAD; - case RenderHeapType::READBACK: - return D3D12_HEAP_TYPE_READBACK; - case RenderHeapType::GPU_UPLOAD: - return D3D12_HEAP_TYPE_GPU_UPLOAD; - default: - assert(false && "Unknown heap type."); - return D3D12_HEAP_TYPE_DEFAULT; - } - } - - static D3D12_COMPARISON_FUNC toD3D12(RenderComparisonFunction function) { - switch (function) { - case RenderComparisonFunction::NEVER: - return D3D12_COMPARISON_FUNC_NEVER; - case RenderComparisonFunction::LESS: - return D3D12_COMPARISON_FUNC_LESS; - case RenderComparisonFunction::EQUAL: - return D3D12_COMPARISON_FUNC_EQUAL; - case RenderComparisonFunction::LESS_EQUAL: - return D3D12_COMPARISON_FUNC_LESS_EQUAL; - case RenderComparisonFunction::GREATER: - return D3D12_COMPARISON_FUNC_GREATER; - case RenderComparisonFunction::NOT_EQUAL: - return D3D12_COMPARISON_FUNC_NOT_EQUAL; - case RenderComparisonFunction::GREATER_EQUAL: - return D3D12_COMPARISON_FUNC_GREATER_EQUAL; - case RenderComparisonFunction::ALWAYS: - return D3D12_COMPARISON_FUNC_ALWAYS; - default: - assert(false && "Unknown comparison function."); - return D3D12_COMPARISON_FUNC_NEVER; - } - } - - static D3D12_PRIMITIVE_TOPOLOGY toD3D12(RenderPrimitiveTopology topology) { - switch (topology) { - case RenderPrimitiveTopology::POINT_LIST: - return D3D_PRIMITIVE_TOPOLOGY_POINTLIST; - case RenderPrimitiveTopology::LINE_LIST: - return D3D_PRIMITIVE_TOPOLOGY_LINELIST; - case RenderPrimitiveTopology::LINE_STRIP: - return D3D_PRIMITIVE_TOPOLOGY_LINESTRIP; - case RenderPrimitiveTopology::TRIANGLE_LIST: - return D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST; - case RenderPrimitiveTopology::TRIANGLE_STRIP: - return D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP; - case RenderPrimitiveTopology::TRIANGLE_FAN: - return D3D_PRIMITIVE_TOPOLOGY_TRIANGLEFAN; - default: - assert(false && "Unknown primitive topology."); - return D3D_PRIMITIVE_TOPOLOGY_UNDEFINED; - } - } - - static D3D12_PRIMITIVE_TOPOLOGY_TYPE toTopologyType(RenderPrimitiveTopology topologyType) { - switch (topologyType) { - case RenderPrimitiveTopology::POINT_LIST: - return D3D12_PRIMITIVE_TOPOLOGY_TYPE_POINT; - case RenderPrimitiveTopology::LINE_LIST: - case RenderPrimitiveTopology::LINE_STRIP: - return D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE; - case RenderPrimitiveTopology::TRIANGLE_LIST: - case RenderPrimitiveTopology::TRIANGLE_STRIP: - case RenderPrimitiveTopology::TRIANGLE_FAN: - return D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; - default: - assert(false && "Unknown primitive topology type."); - return D3D12_PRIMITIVE_TOPOLOGY_TYPE_UNDEFINED; - } - } - - static D3D12_RESOURCE_DIMENSION toD3D12(RenderTextureDimension dimension) { - switch (dimension) { - case RenderTextureDimension::UNKNOWN: - return D3D12_RESOURCE_DIMENSION_UNKNOWN; - case RenderTextureDimension::TEXTURE_1D: - return D3D12_RESOURCE_DIMENSION_TEXTURE1D; - case RenderTextureDimension::TEXTURE_2D: - return D3D12_RESOURCE_DIMENSION_TEXTURE2D; - case RenderTextureDimension::TEXTURE_3D: - return D3D12_RESOURCE_DIMENSION_TEXTURE3D; - default: - assert(false && "Unknown resource dimension."); - return D3D12_RESOURCE_DIMENSION_UNKNOWN; - } - } - - static D3D12_TEXTURE_LAYOUT toD3D12(RenderTextureArrangement arrangement) { - switch (arrangement) { - case RenderTextureArrangement::UNKNOWN: - return D3D12_TEXTURE_LAYOUT_UNKNOWN; - case RenderTextureArrangement::ROW_MAJOR: - return D3D12_TEXTURE_LAYOUT_ROW_MAJOR; - default: - assert(false && "Unknown texture arrangement."); - return D3D12_TEXTURE_LAYOUT_UNKNOWN; - } - } - - static D3D12_RESOURCE_STATES toBufferState(RenderBarrierStages stages, RenderBufferAccessBits accessBits, RenderBufferFlags bufferFlags) { - // The only allowed state for acceleration structures. - if (bufferFlags & RenderBufferFlag::ACCELERATION_STRUCTURE) { - return D3D12_RESOURCE_STATE_RAYTRACING_ACCELERATION_STRUCTURE; - } - - // Use copy-optimized states. - if (stages == RenderBarrierStage::COPY) { - if (accessBits == RenderBufferAccess::WRITE) { - return D3D12_RESOURCE_STATE_COPY_DEST; - } - else if (accessBits == RenderBufferAccess::READ) { - return D3D12_RESOURCE_STATE_COPY_SOURCE; - } - } - - // Use unordered access state if the buffer supports it and writing is enabled. - if ((accessBits & RenderBufferAccess::WRITE) && (bufferFlags & RenderBufferFlag::UNORDERED_ACCESS)) { - return D3D12_RESOURCE_STATE_UNORDERED_ACCESS; - } - - // If both stages are required and the buffer is read-only, use the all shader resource state. - if (stages == (RenderBarrierStage::GRAPHICS | RenderBarrierStage::COMPUTE)) { - if (accessBits == RenderBufferAccess::READ) { - return D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE; - } - } - - // Use graphics pipeline states. - if (stages == RenderBarrierStage::GRAPHICS) { - if (accessBits == RenderBufferAccess::READ) { - if (bufferFlags & (RenderBufferFlag::VERTEX | RenderBufferFlag::CONSTANT)) { - return D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER; - } - - if (bufferFlags & RenderBufferFlag::INDEX) { - return D3D12_RESOURCE_STATE_INDEX_BUFFER; - } - - return D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE; - } - } - - // Fall back to common state. - return D3D12_RESOURCE_STATE_COMMON; - } - - static D3D12_RESOURCE_STATES toTextureState(RenderBarrierStages stages, RenderTextureLayout textureLayout, RenderTextureFlags textureFlags) { - switch (textureLayout) { - case RenderTextureLayout::GENERAL: - return (textureFlags & RenderTextureFlag::UNORDERED_ACCESS) ? D3D12_RESOURCE_STATE_UNORDERED_ACCESS : D3D12_RESOURCE_STATE_COMMON; - case RenderTextureLayout::SHADER_READ: - switch (stages) { - case RenderBarrierStage::GRAPHICS: - return D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE; - case RenderBarrierStage::COMPUTE: - return D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE; - default: - return D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE; - } - case RenderTextureLayout::COLOR_WRITE: - return D3D12_RESOURCE_STATE_RENDER_TARGET; - case RenderTextureLayout::DEPTH_WRITE: - return D3D12_RESOURCE_STATE_DEPTH_WRITE; - case RenderTextureLayout::DEPTH_READ: - return D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE | D3D12_RESOURCE_STATE_DEPTH_READ; - case RenderTextureLayout::COPY_SOURCE: - return D3D12_RESOURCE_STATE_COPY_SOURCE; - case RenderTextureLayout::COPY_DEST: - return D3D12_RESOURCE_STATE_COPY_DEST; - case RenderTextureLayout::RESOLVE_SOURCE: - return D3D12_RESOURCE_STATE_RESOLVE_SOURCE; - case RenderTextureLayout::RESOLVE_DEST: - return D3D12_RESOURCE_STATE_RESOLVE_DEST; - case RenderTextureLayout::PRESENT: - return D3D12_RESOURCE_STATE_PRESENT; - default: - assert(false && "Unknown texture layout."); - return D3D12_RESOURCE_STATE_COMMON; - } - } - - static D3D12_TEXTURE_COPY_LOCATION toD3D12(const RenderTextureCopyLocation &location) { - D3D12_TEXTURE_COPY_LOCATION loc; - switch (location.type) { - case RenderTextureCopyType::SUBRESOURCE: { - const D3D12Texture *interfaceTexture = static_cast(location.texture); - loc.pResource = (interfaceTexture != nullptr) ? interfaceTexture->d3d : nullptr; - loc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; - loc.SubresourceIndex = location.subresource.index; - break; - } - case RenderTextureCopyType::PLACED_FOOTPRINT: { - const D3D12Buffer *interfaceBuffer = static_cast(location.buffer); - const uint32_t blockWidth = RenderFormatBlockWidth(location.placedFootprint.format); - const uint32_t blockCount = (location.placedFootprint.rowWidth + blockWidth - 1) / blockWidth; - loc.pResource = (interfaceBuffer != nullptr) ? interfaceBuffer->d3d : nullptr; - loc.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; - loc.PlacedFootprint.Offset = location.placedFootprint.offset; - loc.PlacedFootprint.Footprint.Format = toDXGI(location.placedFootprint.format); - loc.PlacedFootprint.Footprint.Width = ((location.placedFootprint.width + blockWidth - 1) / blockWidth) * blockWidth; - loc.PlacedFootprint.Footprint.Height = ((location.placedFootprint.height + blockWidth - 1) / blockWidth) * blockWidth; - loc.PlacedFootprint.Footprint.Depth = location.placedFootprint.depth; - loc.PlacedFootprint.Footprint.RowPitch = blockCount * RenderFormatSize(location.placedFootprint.format); - - // Test for conditions that might not be reported if the hardware doesn't complain about them. - assert(((loc.PlacedFootprint.Offset % D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT) == 0) && "Resulting offset must be aligned to 512 bytes in D3D12."); - assert(((loc.PlacedFootprint.Footprint.RowPitch % D3D12_TEXTURE_DATA_PITCH_ALIGNMENT) == 0) && "Resulting row pitch must be aligned to 256 bytes in D3D12."); - - break; - } - default: { - assert(false && "Unknown texture copy type."); - } - } - - return loc; - } - - static D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAGS toRTASBuildFlags(bool preferFastBuild, bool preferFastTrace) { - D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAGS flags = D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_NONE; - flags |= preferFastBuild ? D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_PREFER_FAST_BUILD : D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_NONE; - flags |= preferFastTrace ? D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_PREFER_FAST_TRACE : D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_NONE; - return flags; - } - - static UINT toD3D12(RenderSwizzle swizzle, UINT identity) { - switch (swizzle) { - case RenderSwizzle::IDENTITY: - return identity; - case RenderSwizzle::ZERO: - return D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_0; - case RenderSwizzle::ONE: - return D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_1; - case RenderSwizzle::R: - return D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_0; - case RenderSwizzle::G: - return D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_1; - case RenderSwizzle::B: - return D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_2; - case RenderSwizzle::A: - return D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_3; - default: - assert(false && "Unknown swizzle type."); - return identity; - } - } - - static UINT toD3D12(const RenderComponentMapping &componentMapping) { - return D3D12_ENCODE_SHADER_4_COMPONENT_MAPPING( - toD3D12(componentMapping.r, D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_0), - toD3D12(componentMapping.g, D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_1), - toD3D12(componentMapping.b, D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_2), - toD3D12(componentMapping.a, D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_3) - ); - } - - static D3D12_RESOLVE_MODE toD3D12(RenderResolveMode resolveMode) { - switch (resolveMode) { - case RenderResolveMode::MIN: - return D3D12_RESOLVE_MODE_MIN; - case RenderResolveMode::MAX: - return D3D12_RESOLVE_MODE_MAX; - case RenderResolveMode::AVERAGE: - return D3D12_RESOLVE_MODE_AVERAGE; - default: - assert(false && "Unknown resolve mode."); - return D3D12_RESOLVE_MODE_AVERAGE; - } - } - - static void setObjectName(ID3D12Object *object, const std::string &name) { - const std::wstring wideCharName = Utf8ToUtf16(name); - object->SetName(wideCharName.c_str()); - } - - // D3D12DescriptorHeapAllocator - - D3D12DescriptorHeapAllocator::D3D12DescriptorHeapAllocator(D3D12Device *device, uint32_t heapSize, D3D12_DESCRIPTOR_HEAP_TYPE heapType) { - assert(device != nullptr); - assert(heapSize > 0); - - this->device = device; - this->heapSize = heapSize; - this->freeSize = heapSize; - - D3D12_DESCRIPTOR_HEAP_DESC heapDesc = {}; - heapDesc.NumDescriptors = heapSize; - heapDesc.Type = heapType; - descriptorHandleIncrement = device->d3d->GetDescriptorHandleIncrementSize(heapDesc.Type); - - const bool shaderVisible = (heapType == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV) || (heapType == D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER); - if (shaderVisible) { - heapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; - } - - HRESULT res = device->d3d->CreateDescriptorHeap(&heapDesc, IID_PPV_ARGS(&heap)); - if (FAILED(res)) { - fprintf(stderr, "CreateDescriptorHeap failed with error code 0x%lX.\n", res); - return; - } - - cpuDescriptorHandle = heap->GetCPUDescriptorHandleForHeapStart(); - - if (shaderVisible) { - gpuDescriptorHandle = heap->GetGPUDescriptorHandleForHeapStart(); - } - - addFreeBlock(0, heapSize); - } - - D3D12DescriptorHeapAllocator::~D3D12DescriptorHeapAllocator() { - if (heap != nullptr) { - heap->Release(); - } - } - - void D3D12DescriptorHeapAllocator::addFreeBlock(uint32_t offset, uint32_t size) { - OffsetFreeBlockMap::iterator blockOffsetIt = offsetFreeBlockMap.emplace(offset, size).first; - SizeFreeBlockMap::iterator blockSizeIt = sizeFreeBlockMap.emplace(size, blockOffsetIt); - blockOffsetIt->second.sizeMapIterator = blockSizeIt; - } - - uint32_t D3D12DescriptorHeapAllocator::allocate(uint32_t size) { - const std::scoped_lock lock(allocationMutex); - if (freeSize < size) { - return INVALID_OFFSET; - } - - SizeFreeBlockMap::iterator blockSizeIt = sizeFreeBlockMap.lower_bound(size); - if (blockSizeIt == sizeFreeBlockMap.end()) { - return INVALID_OFFSET; - } - - OffsetFreeBlockMap::iterator blockOffsetIt = blockSizeIt->second; - uint32_t retOffset = blockOffsetIt->first; - uint32_t newOffset = retOffset + size; - uint32_t newSize = blockOffsetIt->second.size - size; - sizeFreeBlockMap.erase(blockSizeIt); - offsetFreeBlockMap.erase(blockOffsetIt); - if (newSize > 0) { - addFreeBlock(newOffset, newSize); - } - - freeSize -= size; - return retOffset; - } - - void D3D12DescriptorHeapAllocator::free(uint32_t offset, uint32_t size) { - const std::scoped_lock lock(allocationMutex); - OffsetFreeBlockMap::iterator nextBlockIt = offsetFreeBlockMap.upper_bound(offset); - OffsetFreeBlockMap::iterator prevBlockIt = nextBlockIt; - if (prevBlockIt != offsetFreeBlockMap.begin()) { - prevBlockIt--; - } - else { - prevBlockIt = offsetFreeBlockMap.end(); - } - - freeSize += size; - - // The previous free block is contiguous. - if ((prevBlockIt != offsetFreeBlockMap.end()) && (offset == (prevBlockIt->first + prevBlockIt->second.size))) { - size = prevBlockIt->second.size + size; - offset = prevBlockIt->first; - sizeFreeBlockMap.erase(prevBlockIt->second.sizeMapIterator); - offsetFreeBlockMap.erase(prevBlockIt); - } - - // The next free block is contiguous. - if ((nextBlockIt != offsetFreeBlockMap.end()) && ((offset + size) == nextBlockIt->first)) { - size = size + nextBlockIt->second.size; - sizeFreeBlockMap.erase(nextBlockIt->second.sizeMapIterator); - offsetFreeBlockMap.erase(nextBlockIt); - } - - addFreeBlock(offset, size); - } - - D3D12_CPU_DESCRIPTOR_HANDLE D3D12DescriptorHeapAllocator::getCPUHandleAt(uint32_t index) const { - assert(index < heapSize); - assert(cpuDescriptorHandle.ptr > 0); - return { cpuDescriptorHandle.ptr + uint64_t(index) * descriptorHandleIncrement }; - } - - D3D12_GPU_DESCRIPTOR_HANDLE D3D12DescriptorHeapAllocator::getGPUHandleAt(uint32_t index) const { - assert(index < heapSize); - assert(gpuDescriptorHandle.ptr > 0); - return { gpuDescriptorHandle.ptr + uint64_t(index) * descriptorHandleIncrement }; - } - - // D3D12DescriptorSet - - D3D12DescriptorSet::D3D12DescriptorSet(D3D12Device *device, const RenderDescriptorSetDesc &desc) { - assert(device != nullptr); - - this->device = device; - - // Figure out the total amount of entries that will be required. - uint32_t rangeCount = desc.descriptorRangesCount; - uint32_t viewDescriptorCount = 0; - uint32_t samplerDescriptorCount = 0; - auto addDescriptor = [&](const RenderDescriptorRange &range, uint32_t descriptorCount) { - descriptorTypes.emplace_back(range.type); - - bool isDynamicSampler = (range.type == RenderDescriptorRangeType::SAMPLER) && (range.immutableSampler == nullptr); - if (isDynamicSampler) { - descriptorHeapIndices.emplace_back(samplerDescriptorCount); - samplerDescriptorCount += descriptorCount; - } - else { - descriptorHeapIndices.emplace_back(viewDescriptorCount); - viewDescriptorCount += descriptorCount; - } - }; - - if (desc.lastRangeIsBoundless) { - assert((desc.descriptorRangesCount > 0) && "There must be at least one descriptor set to define the last range as boundless."); - rangeCount--; - } - - for (uint32_t i = 0; i < rangeCount; i++) { - const RenderDescriptorRange &range = desc.descriptorRanges[i]; - for (uint32_t j = 0; j < range.count; j++) { - addDescriptor(range, 1); - } - } - - if (desc.lastRangeIsBoundless) { - const RenderDescriptorRange &lastDescriptorRange = desc.descriptorRanges[desc.descriptorRangesCount - 1]; - addDescriptor(lastDescriptorRange, desc.boundlessRangeSize); - } - - if (!descriptorTypes.empty()) { - descriptorTypeMaxIndex = uint32_t(descriptorTypes.size()) - 1; - } - - if (viewDescriptorCount > 0) { - viewAllocation.offset = device->viewHeapAllocator->allocate(viewDescriptorCount); - if (viewAllocation.offset == D3D12DescriptorHeapAllocator::INVALID_OFFSET) { - fprintf(stderr, "Allocator was unable to find free space for the set."); - return; - } - - viewAllocation.count = viewDescriptorCount; - } - - if (samplerDescriptorCount > 0) { - samplerAllocation.offset = device->samplerHeapAllocator->allocate(samplerDescriptorCount); - if (samplerAllocation.offset == D3D12DescriptorHeapAllocator::INVALID_OFFSET) { - fprintf(stderr, "Allocator was unable to find free space for the set."); - return; - } - - samplerAllocation.count = samplerDescriptorCount; - } - } - - D3D12DescriptorSet::~D3D12DescriptorSet() { - if (viewAllocation.count > 0) { - device->viewHeapAllocator->free(viewAllocation.offset, viewAllocation.count); - } - - if (samplerAllocation.count > 0) { - device->samplerHeapAllocator->free(samplerAllocation.offset, samplerAllocation.count); - } - } - - void D3D12DescriptorSet::setBuffer(uint32_t descriptorIndex, const RenderBuffer *buffer, uint64_t bufferSize, const RenderBufferStructuredView *bufferStructuredView, const RenderBufferFormattedView *bufferFormattedView) { - const D3D12Buffer *interfaceBuffer = static_cast(buffer); - ID3D12Resource *nativeResource = (interfaceBuffer != nullptr) ? interfaceBuffer->d3d : nullptr; - uint32_t descriptorIndexClamped = std::min(descriptorIndex, descriptorTypeMaxIndex); - RenderDescriptorRangeType descriptorType = descriptorTypes[descriptorIndexClamped]; - switch (descriptorType) { - case RenderDescriptorRangeType::CONSTANT_BUFFER: { - uint64_t bufferViewSize = bufferSize; - if ((bufferSize == 0) && (interfaceBuffer != nullptr)) { - bufferViewSize = interfaceBuffer->desc.size; - } - - setCBV(descriptorIndex, nativeResource, bufferViewSize); - break; - } - case RenderDescriptorRangeType::FORMATTED_BUFFER: { - assert((bufferStructuredView == nullptr) && "Can't use structured view on texture buffers."); - if (nativeResource != nullptr) { - assert((bufferFormattedView != nullptr) && "A view must be provided for formatted buffers."); - const D3D12BufferFormattedView *interfaceBufferFormattedView = static_cast(bufferFormattedView); - D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {}; - srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; - srvDesc.ViewDimension = D3D12_SRV_DIMENSION_BUFFER; - srvDesc.Format = toDXGI(interfaceBufferFormattedView->format); - srvDesc.Buffer.Flags = (descriptorType == RenderDescriptorRangeType::BYTE_ADDRESS_BUFFER) ? D3D12_BUFFER_SRV_FLAG_RAW : D3D12_BUFFER_SRV_FLAG_NONE; - - // Figure out the number of elements from the format. - const uint64_t bufferViewSize = (bufferSize > 0) ? bufferSize : interfaceBuffer->desc.size; - srvDesc.Buffer.NumElements = UINT(bufferViewSize / RenderFormatSize(interfaceBufferFormattedView->format)); - setSRV(descriptorIndex, nativeResource, &srvDesc); - } - else { - setSRV(descriptorIndex, nullptr, nullptr); - } - - break; - } - case RenderDescriptorRangeType::STRUCTURED_BUFFER: - case RenderDescriptorRangeType::BYTE_ADDRESS_BUFFER: { - assert((bufferFormattedView == nullptr) && "Can't use formatted view on byte or structured buffers."); - if (nativeResource != nullptr) { - D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {}; - srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; - srvDesc.ViewDimension = D3D12_SRV_DIMENSION_BUFFER; - - const uint64_t bufferViewSize = (bufferSize > 0) ? bufferSize : interfaceBuffer->desc.size; - if (descriptorType == RenderDescriptorRangeType::BYTE_ADDRESS_BUFFER) { - srvDesc.Format = DXGI_FORMAT_R32_TYPELESS; - srvDesc.Buffer.NumElements = UINT(bufferViewSize / 4); - srvDesc.Buffer.Flags = D3D12_BUFFER_SRV_FLAG_RAW; - } - else { - assert((bufferStructuredView != nullptr) && "A view must be provided for structured buffers."); - assert(bufferStructuredView->structureByteStride > 0); - srvDesc.Buffer.FirstElement = bufferStructuredView->firstElement; - srvDesc.Buffer.StructureByteStride = bufferStructuredView->structureByteStride; - srvDesc.Buffer.NumElements = UINT(bufferViewSize / bufferStructuredView->structureByteStride); - } - - setSRV(descriptorIndex, nativeResource, &srvDesc); - } - else { - setSRV(descriptorIndex, nullptr, nullptr); - } - - break; - } - case RenderDescriptorRangeType::READ_WRITE_FORMATTED_BUFFER: { - assert((bufferStructuredView == nullptr) && "Can't use structured view on texture buffers."); - if (nativeResource != nullptr) { - assert((bufferFormattedView != nullptr) && "A view must be provided for formatted buffers."); - const D3D12BufferFormattedView *interfaceBufferFormatView = static_cast(bufferFormattedView); - D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {}; - uavDesc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER; - uavDesc.Format = toDXGI(interfaceBufferFormatView->format); - uavDesc.Buffer.Flags = (descriptorType == RenderDescriptorRangeType::READ_WRITE_BYTE_ADDRESS_BUFFER) ? D3D12_BUFFER_UAV_FLAG_RAW : D3D12_BUFFER_UAV_FLAG_NONE; - - // Figure out the number of elements from the format. - const uint64_t bufferViewSize = (bufferSize > 0) ? bufferSize : interfaceBuffer->desc.size; - uavDesc.Buffer.NumElements = UINT(bufferViewSize / RenderFormatSize(interfaceBufferFormatView->format)); - setUAV(descriptorIndex, nativeResource, &uavDesc); - } - else { - setUAV(descriptorIndex, nullptr, nullptr); - } - - break; - } - case RenderDescriptorRangeType::READ_WRITE_STRUCTURED_BUFFER: - case RenderDescriptorRangeType::READ_WRITE_BYTE_ADDRESS_BUFFER: { - assert((bufferFormattedView == nullptr) && "Can't use formatted view on byte or structured buffers."); - if (nativeResource != nullptr) { - D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {}; - uavDesc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER; - - const uint64_t bufferViewSize = (bufferSize > 0) ? bufferSize : interfaceBuffer->desc.size; - if (descriptorType == RenderDescriptorRangeType::READ_WRITE_BYTE_ADDRESS_BUFFER) { - uavDesc.Format = DXGI_FORMAT_R32_TYPELESS; - uavDesc.Buffer.NumElements = UINT(bufferViewSize / 4); - uavDesc.Buffer.Flags = D3D12_BUFFER_UAV_FLAG_RAW; - } - else { - assert((bufferStructuredView != nullptr) && "A view must be provided for structured buffers."); - assert(bufferStructuredView->structureByteStride > 0); - uavDesc.Buffer.FirstElement = bufferStructuredView->firstElement; - uavDesc.Buffer.StructureByteStride = bufferStructuredView->structureByteStride; - uavDesc.Buffer.NumElements = UINT(bufferViewSize / bufferStructuredView->structureByteStride); - } - - setUAV(descriptorIndex, nativeResource, &uavDesc); - } - else { - setUAV(descriptorIndex, nullptr, nullptr); - } - - break; - } - case RenderDescriptorRangeType::TEXTURE: - case RenderDescriptorRangeType::READ_WRITE_TEXTURE: - case RenderDescriptorRangeType::SAMPLER: - case RenderDescriptorRangeType::ACCELERATION_STRUCTURE: - assert(false && "Incompatible descriptor type."); - break; - default: - assert(false && "Unknown descriptor type."); - break; - } - } - - void D3D12DescriptorSet::setTexture(uint32_t descriptorIndex, const RenderTexture *texture, const RenderTextureLayout textureLayout, const RenderTextureView *textureView) { - // Texture state is ignored by D3D12 because image layout information is not required. - - const D3D12Texture *interfaceTexture = static_cast(texture); - ID3D12Resource *nativeResource = (interfaceTexture != nullptr) ? interfaceTexture->d3d : nullptr; - uint32_t descriptorIndexClamped = std::min(descriptorIndex, descriptorTypeMaxIndex); - RenderDescriptorRangeType descriptorType = descriptorTypes[descriptorIndexClamped]; - switch (descriptorType) { - case RenderDescriptorRangeType::TEXTURE: { - if ((nativeResource != nullptr) && (textureView != nullptr)) { - const D3D12TextureView *interfaceTextureView = static_cast(textureView); - D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {}; - srvDesc.Shader4ComponentMapping = interfaceTextureView->shader4ComponentMapping; - srvDesc.Format = interfaceTextureView->format; - - const bool isMSAA = (interfaceTextureView->texture->desc.multisampling.sampleCount > RenderSampleCount::COUNT_1); - switch (interfaceTextureView->dimension) { - case RenderTextureViewDimension::TEXTURE_1D: - srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE1D; - srvDesc.Texture1D.MipLevels = interfaceTextureView->mipLevels; - break; - case RenderTextureViewDimension::TEXTURE_2D: - if (isMSAA) { - srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DMS; - } - else { - srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D; - srvDesc.Texture2D.MipLevels = interfaceTextureView->mipLevels; - } - - break; - case RenderTextureViewDimension::TEXTURE_3D: - srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE3D; - srvDesc.Texture3D.MipLevels = interfaceTextureView->mipLevels; - break; - case RenderTextureViewDimension::TEXTURE_CUBE: - srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBE; - srvDesc.TextureCube.MipLevels = interfaceTextureView->mipLevels; - break; - default: - assert(false && "Unknown texture dimension."); - break; - } - - setSRV(descriptorIndex, nativeResource, &srvDesc); - } - else if (nativeResource != nullptr) { - setSRV(descriptorIndex, nativeResource, nullptr); - } - else { - D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {}; - srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D; - srvDesc.Format = DXGI_FORMAT_R32_FLOAT; - srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; - setSRV(descriptorIndex, nullptr, &srvDesc); - } - - break; - } - case RenderDescriptorRangeType::READ_WRITE_TEXTURE: { - if ((nativeResource != nullptr) && (textureView != nullptr)) { - const D3D12TextureView *interfaceTextureView = static_cast(textureView); - D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {}; - uavDesc.Format = interfaceTextureView->format; - - switch (interfaceTextureView->dimension) { - case RenderTextureViewDimension::TEXTURE_1D: - uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE1D; - uavDesc.Texture1D.MipSlice = interfaceTextureView->mipSlice; - break; - case RenderTextureViewDimension::TEXTURE_2D: - uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2D; - uavDesc.Texture2D.MipSlice = interfaceTextureView->mipSlice; - break; - case RenderTextureViewDimension::TEXTURE_3D: - uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE3D; - uavDesc.Texture3D.MipSlice = interfaceTextureView->mipSlice; - break; - default: - assert(false && "Unknown texture dimension."); - break; - } - - setUAV(descriptorIndex, nativeResource, &uavDesc); - } - else { - setUAV(descriptorIndex, nativeResource, nullptr); - } - - break; - } - case RenderDescriptorRangeType::CONSTANT_BUFFER: - case RenderDescriptorRangeType::FORMATTED_BUFFER: - case RenderDescriptorRangeType::READ_WRITE_FORMATTED_BUFFER: - case RenderDescriptorRangeType::STRUCTURED_BUFFER: - case RenderDescriptorRangeType::BYTE_ADDRESS_BUFFER: - case RenderDescriptorRangeType::READ_WRITE_STRUCTURED_BUFFER: - case RenderDescriptorRangeType::READ_WRITE_BYTE_ADDRESS_BUFFER: - case RenderDescriptorRangeType::SAMPLER: - case RenderDescriptorRangeType::ACCELERATION_STRUCTURE: - assert(false && "Incompatible descriptor type."); - break; - default: - assert(false && "Unknown descriptor type."); - break; - } - } - - void D3D12DescriptorSet::setSampler(uint32_t descriptorIndex, const RenderSampler *sampler) { - if (sampler != nullptr) { - const D3D12Sampler *interfaceSampler = static_cast(sampler); - uint32_t descriptorIndexClamped = std::min(descriptorIndex, descriptorTypeMaxIndex); - uint32_t descriptorIndexRelative = (descriptorIndex - descriptorIndexClamped); - uint32_t descriptorHeapIndex = descriptorHeapIndices[descriptorIndexClamped]; - const D3D12_CPU_DESCRIPTOR_HANDLE cpuHandle = device->samplerHeapAllocator->getCPUHandleAt(samplerAllocation.offset + descriptorHeapIndex + descriptorIndexRelative); - device->d3d->CreateSampler(&interfaceSampler->samplerDesc, cpuHandle); - } - } - - void D3D12DescriptorSet::setAccelerationStructure(uint32_t descriptorIndex, const RenderAccelerationStructure *accelerationStructure) { - const D3D12AccelerationStructure *interfaceAccelerationStructure = static_cast(accelerationStructure); - uint32_t descriptorIndexClamped = std::min(descriptorIndex, descriptorTypeMaxIndex); - RenderDescriptorRangeType descriptorType = descriptorTypes[descriptorIndexClamped]; - assert((descriptorType == RenderDescriptorRangeType::ACCELERATION_STRUCTURE) && "Incompatible descriptor type."); - - if (interfaceAccelerationStructure != nullptr) { - D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {}; - srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; - srvDesc.ViewDimension = D3D12_SRV_DIMENSION_RAYTRACING_ACCELERATION_STRUCTURE; - srvDesc.RaytracingAccelerationStructure.Location = interfaceAccelerationStructure->buffer->d3d->GetGPUVirtualAddress(); - setSRV(descriptorIndex, nullptr, &srvDesc); - } - else { - setSRV(descriptorIndex, nullptr, nullptr); - } - } - - void D3D12DescriptorSet::setSRV(uint32_t descriptorIndex, ID3D12Resource *resource, const D3D12_SHADER_RESOURCE_VIEW_DESC *viewDesc) { - if ((resource != nullptr) || (viewDesc != nullptr)) { - uint32_t descriptorIndexClamped = std::min(descriptorIndex, descriptorTypeMaxIndex); - uint32_t descriptorIndexRelative = (descriptorIndex - descriptorIndexClamped); - uint32_t descriptorHeapIndex = descriptorHeapIndices[descriptorIndexClamped]; - const D3D12_CPU_DESCRIPTOR_HANDLE cpuHandle = device->viewHeapAllocator->getCPUHandleAt(viewAllocation.offset + descriptorHeapIndex + descriptorIndexRelative); - device->d3d->CreateShaderResourceView(resource, viewDesc, cpuHandle); - } - } - - void D3D12DescriptorSet::setUAV(uint32_t descriptorIndex, ID3D12Resource *resource, const D3D12_UNORDERED_ACCESS_VIEW_DESC *viewDesc) { - if ((resource != nullptr) || (viewDesc != nullptr)) { - uint32_t descriptorIndexClamped = std::min(descriptorIndex, descriptorTypeMaxIndex); - uint32_t descriptorIndexRelative = (descriptorIndex - descriptorIndexClamped); - uint32_t descriptorHeapIndex = descriptorHeapIndices[descriptorIndexClamped]; - const D3D12_CPU_DESCRIPTOR_HANDLE cpuHandle = device->viewHeapAllocator->getCPUHandleAt(viewAllocation.offset + descriptorHeapIndex + descriptorIndexRelative); - device->d3d->CreateUnorderedAccessView(resource, nullptr, viewDesc, cpuHandle); - } - } - - void D3D12DescriptorSet::setCBV(uint32_t descriptorIndex, ID3D12Resource *resource, uint64_t bufferSize) { - if (resource != nullptr) { - D3D12_CONSTANT_BUFFER_VIEW_DESC viewDesc = {}; - viewDesc.BufferLocation = resource->GetGPUVirtualAddress(); - viewDesc.SizeInBytes = UINT(roundUp(bufferSize, D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT)); - - uint32_t descriptorIndexClamped = std::min(descriptorIndex, descriptorTypeMaxIndex); - uint32_t descriptorIndexRelative = (descriptorIndex - descriptorIndexClamped); - uint32_t descriptorHeapIndex = descriptorHeapIndices[descriptorIndexClamped]; - const D3D12_CPU_DESCRIPTOR_HANDLE cpuHandle = device->viewHeapAllocator->getCPUHandleAt(viewAllocation.offset + descriptorHeapIndex + descriptorIndexRelative); - device->d3d->CreateConstantBufferView(&viewDesc, cpuHandle); - } - } - - // D3D12SwapChain - - D3D12SwapChain::D3D12SwapChain(D3D12CommandQueue *commandQueue, RenderWindow renderWindow, uint32_t textureCount, RenderFormat format, uint32_t maxFrameLatency) { - assert(commandQueue != nullptr); - assert(renderWindow != 0); - - this->commandQueue = commandQueue; - this->renderWindow = renderWindow; - this->textureCount = textureCount; - this->format = format; - this->maxFrameLatency = maxFrameLatency; - - // Store the native format representation. - nativeFormat = toDXGI(format); - - getWindowSize(width, height); - - DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {}; - swapChainDesc.BufferCount = textureCount; - swapChainDesc.Width = width; - swapChainDesc.Height = height; - swapChainDesc.Format = nativeFormat; - swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; - swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; - swapChainDesc.SampleDesc.Count = 1; - swapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT | DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING; - - IDXGISwapChain1 *swapChain1; - IDXGIFactory4 *dxgiFactory = commandQueue->device->renderInterface->dxgiFactory; - HRESULT res = dxgiFactory->CreateSwapChainForHwnd(commandQueue->d3d, renderWindow, &swapChainDesc, nullptr, nullptr, &swapChain1); - if (FAILED(res)) { - fprintf(stderr, "CreateSwapChainForHwnd failed with error code 0x%lX.\n", res); - return; - } - - res = dxgiFactory->MakeWindowAssociation(renderWindow, DXGI_MWA_NO_ALT_ENTER); - if (FAILED(res)) { - fprintf(stderr, "MakeWindowAssociation failed with error code 0x%lX.\n", res); - return; - } - - d3d = static_cast(swapChain1); - d3d->SetMaximumFrameLatency(maxFrameLatency); - waitableObject = d3d->GetFrameLatencyWaitableObject(); - - textures.resize(textureCount); - - for (uint32_t i = 0; i < textureCount; i++) { - textures[i].device = commandQueue->device; - textures[i].desc.dimension = RenderTextureDimension::TEXTURE_2D; - textures[i].desc.format = format; - textures[i].desc.depth = 1; - textures[i].desc.mipLevels = 1; - textures[i].desc.arraySize = 1; - textures[i].desc.flags = RenderTextureFlag::RENDER_TARGET; - } - - setTextures(); - } - - D3D12SwapChain::~D3D12SwapChain() { - for (uint32_t i = 0; i < textureCount; i++) { - textures[i].releaseTargetHeap(); - - if (textures[i].d3d != nullptr) { - textures[i].d3d->Release(); - textures[i].d3d = nullptr; - } - } - - if (d3d != nullptr) { - d3d->Release(); - } - } - - bool D3D12SwapChain::present(uint32_t textureIndex, RenderCommandSemaphore **waitSemaphores, uint32_t waitSemaphoreCount) { - UINT syncInterval = vsyncEnabled ? 1 : 0; - UINT flags = !vsyncEnabled ? DXGI_PRESENT_ALLOW_TEARING : 0; - HRESULT res = d3d->Present(syncInterval, flags); - return SUCCEEDED(res); - } - - void D3D12SwapChain::wait() { - if (waitableObject != NULL) { - WaitForSingleObject(waitableObject, INFINITE); - } - } - - bool D3D12SwapChain::resize() { - getWindowSize(width, height); - - // Don't resize the swap chain at all if the window doesn't have a valid size. - if ((width == 0) || (height == 0)) { - return false; - } - - for (uint32_t i = 0; i < textureCount; i++) { - textures[i].releaseTargetHeap(); - textures[i].d3d->Release(); - textures[i].d3d = nullptr; - } - - HRESULT res = d3d->ResizeBuffers(0, 0, 0, DXGI_FORMAT_UNKNOWN, DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT | DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING); - if (FAILED(res)) { - fprintf(stderr, "ResizeBuffers failed with error code 0x%lX.\n", res); - return false; - } - - setTextures(); - return true; - } - - bool D3D12SwapChain::needsResize() const { - uint32_t windowWidth, windowHeight; - getWindowSize(windowWidth, windowHeight); - return (d3d == nullptr) || (windowWidth != width) || (windowHeight != height); - } - - void D3D12SwapChain::setVsyncEnabled(bool vsyncEnabled) { - this->vsyncEnabled = vsyncEnabled; - } - - bool D3D12SwapChain::isVsyncEnabled() const { - return vsyncEnabled; - } - - uint32_t D3D12SwapChain::getWidth() const { - return width; - } - - uint32_t D3D12SwapChain::getHeight() const { - return height; - } - - void D3D12SwapChain::getWindowSize(uint32_t &dstWidth, uint32_t &dstHeight) const { - RECT rect; - GetClientRect(renderWindow, &rect); - dstWidth = rect.right - rect.left; - dstHeight = rect.bottom - rect.top; - } - - void D3D12SwapChain::setTextures() { - assert(textureCount == textures.size()); - - for (uint32_t i = 0; i < textureCount; i++) { - d3d->GetBuffer(i, IID_PPV_ARGS(&textures[i].d3d)); - - textures[i].desc.width = width; - textures[i].desc.height = height; - textures[i].resourceStates = D3D12_RESOURCE_STATE_PRESENT; - textures[i].layout = RenderTextureLayout::PRESENT; - textures[i].createRenderTargetHeap(); - } - } - - RenderTexture *D3D12SwapChain::getTexture(uint32_t textureIndex) { - return &textures[textureIndex]; - } - - uint32_t D3D12SwapChain::getTextureCount() const { - return textureCount; - } - - bool D3D12SwapChain::acquireTexture(RenderCommandSemaphore *signalSemaphore, uint32_t *textureIndex) { - assert(textureIndex != nullptr); - *textureIndex = d3d->GetCurrentBackBufferIndex(); - return true; - } - - RenderWindow D3D12SwapChain::getWindow() const { - return renderWindow; - } - - bool D3D12SwapChain::isEmpty() const { - return (d3d == nullptr) || (width == 0) || (height == 0); - } - - uint32_t D3D12SwapChain::getRefreshRate() const { - return 0; - } - - // D3D12Framebuffer - - D3D12Framebuffer::D3D12Framebuffer(D3D12Device *device, const RenderFramebufferDesc &desc) { - assert(device != nullptr); - - this->device = device; - - if (desc.colorAttachmentsCount > 0) { - for (uint32_t i = 0; i < desc.colorAttachmentsCount; i++) { - const D3D12Texture *interfaceTexture = static_cast(desc.colorAttachments[i]); - assert((interfaceTexture->desc.flags & RenderTextureFlag::RENDER_TARGET) && "Color attachment must be a render target."); - colorTargets.emplace_back(interfaceTexture); - colorHandles.emplace_back(device->colorTargetHeapAllocator->getCPUHandleAt(interfaceTexture->targetAllocatorOffset)); - - if (i == 0) { - width = interfaceTexture->desc.width; - height = interfaceTexture->desc.height; - } - } - } - - if (desc.depthAttachment != nullptr) { - const D3D12Texture *interfaceTexture = static_cast(desc.depthAttachment); - assert((interfaceTexture->desc.flags & RenderTextureFlag::DEPTH_TARGET) && "Depth attachment must be a depth target."); - depthTarget = interfaceTexture; - - // The read-only handle is on the second slot on the DSV heap. - if (desc.depthAttachmentReadOnly) { - depthHandle = device->depthTargetHeapAllocator->getCPUHandleAt(interfaceTexture->targetAllocatorOffset + 1); - } - else { - depthHandle = device->depthTargetHeapAllocator->getCPUHandleAt(interfaceTexture->targetAllocatorOffset); - } - - if (desc.colorAttachmentsCount == 0) { - width = interfaceTexture->desc.width; - height = interfaceTexture->desc.height; - } - } - } - - D3D12Framebuffer::~D3D12Framebuffer() { } - - uint32_t D3D12Framebuffer::getWidth() const { - return width; - } - - uint32_t D3D12Framebuffer::getHeight() const { - return height; - } - - // D3D12QueryPool - - D3D12QueryPool::D3D12QueryPool(D3D12Device *device, uint32_t queryCount) { - assert(device != nullptr); - assert(queryCount > 0); - - this->device = device; - - D3D12_QUERY_HEAP_DESC queryHeapDesc = {}; - queryHeapDesc.Type = D3D12_QUERY_HEAP_TYPE_TIMESTAMP; - queryHeapDesc.Count = queryCount; - - HRESULT res = device->d3d->CreateQueryHeap(&queryHeapDesc, IID_PPV_ARGS(&d3d)); - if (FAILED(res)) { - fprintf(stderr, "CreateQueryHeap failed with error code 0x%lX.\n", res); - return; - } - - readbackBuffer = device->createBuffer(RenderBufferDesc::ReadbackBuffer(sizeof(uint64_t) * queryCount)); - results.resize(queryCount); - } - - D3D12QueryPool::~D3D12QueryPool() { - if (d3d != nullptr) { - d3d->Release(); - } - } - - void D3D12QueryPool::queryResults() { - void *readbackData = readbackBuffer->map(); - memcpy(results.data(), readbackData, sizeof(uint64_t) * results.size()); - readbackBuffer->unmap(); - - for (uint64_t &result : results) { - result = result / double(device->timestampFrequency) * 1000000000.0; - } - } - - const uint64_t *D3D12QueryPool::getResults() const { - return results.data(); - } - - uint32_t D3D12QueryPool::getCount() const { - return uint32_t(results.size()); - } - - // D3D12CommandList - - D3D12CommandList::D3D12CommandList(D3D12Device *device, RenderCommandListType type) { - assert(device != nullptr); - - this->device = device; - this->type = type; - - D3D12_COMMAND_LIST_TYPE commandListType; - switch (type) { - case RenderCommandListType::DIRECT: - commandListType = D3D12_COMMAND_LIST_TYPE_DIRECT; - break; - case RenderCommandListType::COMPUTE: - commandListType = D3D12_COMMAND_LIST_TYPE_COMPUTE; - break; - case RenderCommandListType::COPY: - commandListType = D3D12_COMMAND_LIST_TYPE_COPY; - break; - default: - assert(false && "Unknown command list type."); - return; - } - - HRESULT res = device->d3d->CreateCommandAllocator(commandListType, IID_PPV_ARGS(&commandAllocator)); - if (FAILED(res)) { - fprintf(stderr, "CreateCommandAllocator failed with error code 0x%lX.\n", res); - return; - } - - res = device->d3d->CreateCommandList(0, commandListType, commandAllocator, nullptr, IID_PPV_ARGS(&d3d)); - if (FAILED(res)) { - fprintf(stderr, "CreateCommandList failed with error code 0x%lX.\n", res); - return; - } - - d3d->Close(); - } - - D3D12CommandList::~D3D12CommandList() { - if (d3d != nullptr) { - d3d->Release(); - } - - if (commandAllocator != nullptr) { - commandAllocator->Release(); - } - } - - void D3D12CommandList::begin() { - assert(!open); - - commandAllocator->Reset(); - d3d->Reset(commandAllocator, nullptr); - open = true; - } - - void D3D12CommandList::end() { - assert(open); - - // It's required to reset the sample positions before the command list ends. - resetSamplePositions(); - - d3d->Close(); - open = false; - targetFramebuffer = nullptr; - targetFramebufferSamplePositionsSet = false; - activeComputePipelineLayout = nullptr; - activeGraphicsPipelineLayout = nullptr; - activeGraphicsPipeline = nullptr; - activeTopology = D3D_PRIMITIVE_TOPOLOGY_UNDEFINED; - descriptorHeapsSet = false; - } - - void D3D12CommandList::barriers(RenderBarrierStages stages, const RenderBufferBarrier *bufferBarriers, uint32_t bufferBarriersCount, const RenderTextureBarrier *textureBarriers, uint32_t textureBarriersCount) { - thread_local std::vector barrierVector; - barrierVector.clear(); - - auto makeBarrier = [&](ID3D12Resource *resource, D3D12_RESOURCE_STATES stateBefore, D3D12_RESOURCE_STATES stateAfter, bool supportsUAV, D3D12_RESOURCE_BARRIER &resourceBarrier) { - resourceBarrier = {}; - - if (stateBefore != stateAfter) { - resourceBarrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; - resourceBarrier.Transition.StateBefore = stateBefore; - resourceBarrier.Transition.StateAfter = stateAfter; - resourceBarrier.Transition.pResource = resource; - resourceBarrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; - return true; - } - else if (supportsUAV) { - resourceBarrier.Type = D3D12_RESOURCE_BARRIER_TYPE_UAV; - resourceBarrier.UAV.pResource = resource; - return true; - } - else { - return false; - } - }; - - D3D12_RESOURCE_BARRIER resourceBarrier; - const RenderBufferFlags bufferUAVMask = RenderBufferFlag::UNORDERED_ACCESS | RenderBufferFlag::ACCELERATION_STRUCTURE; - for (uint32_t i = 0; i < bufferBarriersCount; i++) { - const RenderBufferBarrier &bufferBarrier = bufferBarriers[i]; - D3D12Buffer *interfaceBuffer = static_cast(bufferBarrier.buffer); - D3D12_RESOURCE_STATES stateBefore = interfaceBuffer->resourceStates; - D3D12_RESOURCE_STATES stateAfter = toBufferState(stages, bufferBarrier.accessBits, interfaceBuffer->desc.flags); - if (makeBarrier(interfaceBuffer->d3d, stateBefore, stateAfter, interfaceBuffer->desc.flags & bufferUAVMask, resourceBarrier)) { - barrierVector.emplace_back(resourceBarrier); - } - - interfaceBuffer->resourceStates = stateAfter; - } - - bool resetSamplePositionsRequired = false; - for (uint32_t i = 0; i < textureBarriersCount; i++) { - const RenderTextureBarrier &textureBarrier = textureBarriers[i]; - D3D12Texture *interfaceTexture = static_cast(textureBarrier.texture); - D3D12_RESOURCE_STATES stateBefore = interfaceTexture->resourceStates; - D3D12_RESOURCE_STATES stateAfter = toTextureState(stages, textureBarrier.layout, interfaceTexture->desc.flags); - bool madeBarrier = makeBarrier(interfaceTexture->d3d, stateBefore, stateAfter, interfaceTexture->desc.flags & RenderTextureFlag::UNORDERED_ACCESS, resourceBarrier); - interfaceTexture->resourceStates = stateAfter; - interfaceTexture->layout = textureBarrier.layout; - if (!madeBarrier) { - continue; - } - - // MSAA Depth targets with multisampling require separate barriers. - const bool msaaDepthTarget = (interfaceTexture->desc.flags & RenderTextureFlag::DEPTH_TARGET) && (interfaceTexture->desc.multisampling.sampleCount > 1); - if (msaaDepthTarget && interfaceTexture->desc.multisampling.sampleLocationsEnabled) { - setSamplePositions(interfaceTexture); - d3d->ResourceBarrier(1, &resourceBarrier); - resetSamplePositionsRequired = true; - } - else { - barrierVector.emplace_back(resourceBarrier); - } - } - - if (resetSamplePositionsRequired) { - resetSamplePositions(); - } - - if (!barrierVector.empty()) { - d3d->ResourceBarrier(UINT(barrierVector.size()), barrierVector.data()); - } - } - - void D3D12CommandList::dispatch(uint32_t threadGroupCountX, uint32_t threadGroupCountY, uint32_t threadGroupCountZ) { - d3d->Dispatch(threadGroupCountX, threadGroupCountY, threadGroupCountZ); - } - - void D3D12CommandList::traceRays(uint32_t width, uint32_t height, uint32_t depth, RenderBufferReference shaderBindingTable, const RenderShaderBindingGroupsInfo &shaderBindingGroupsInfo) { - const D3D12Buffer *interfaceBuffer = static_cast(shaderBindingTable.ref); - assert(interfaceBuffer != nullptr); - assert((interfaceBuffer->desc.flags & RenderBufferFlag::SHADER_BINDING_TABLE) && "Buffer must allow being used as a shader binding table."); - - D3D12_GPU_VIRTUAL_ADDRESS tableAddress = interfaceBuffer->d3d->GetGPUVirtualAddress() + shaderBindingTable.offset; - const RenderShaderBindingGroupInfo &rayGen = shaderBindingGroupsInfo.rayGen; - const RenderShaderBindingGroupInfo &miss = shaderBindingGroupsInfo.miss; - const RenderShaderBindingGroupInfo &hitGroup = shaderBindingGroupsInfo.hitGroup; - const RenderShaderBindingGroupInfo &callable = shaderBindingGroupsInfo.callable; - D3D12_DISPATCH_RAYS_DESC desc; - desc.RayGenerationShaderRecord.StartAddress = (rayGen.size > 0) ? (tableAddress + rayGen.offset + rayGen.startIndex * rayGen.stride) : 0; - desc.RayGenerationShaderRecord.SizeInBytes = rayGen.size; - desc.MissShaderTable.StartAddress = (miss.size > 0) ? (tableAddress + miss.offset + miss.startIndex * miss.stride) : 0; - desc.MissShaderTable.SizeInBytes = miss.size; - desc.MissShaderTable.StrideInBytes = miss.stride; - desc.HitGroupTable.StartAddress = (hitGroup.size > 0) ? (tableAddress + hitGroup.offset + hitGroup.startIndex * hitGroup.stride) : 0; - desc.HitGroupTable.SizeInBytes = hitGroup.size; - desc.HitGroupTable.StrideInBytes = hitGroup.stride; - desc.CallableShaderTable.StartAddress = (callable.size > 0) ? (tableAddress + callable.offset + callable.startIndex * callable.stride) : 0; - desc.CallableShaderTable.SizeInBytes = callable.size; - desc.CallableShaderTable.StrideInBytes = callable.stride; - desc.Width = width; - desc.Height = height; - desc.Depth = depth; - d3d->DispatchRays(&desc); - } - - void D3D12CommandList::drawInstanced(uint32_t vertexCountPerInstance, uint32_t instanceCount, uint32_t startVertexLocation, uint32_t startInstanceLocation) { - checkTopology(); - checkFramebufferSamplePositions(); - d3d->DrawInstanced(vertexCountPerInstance, instanceCount, startVertexLocation, startInstanceLocation); - } - - void D3D12CommandList::drawIndexedInstanced(uint32_t indexCountPerInstance, uint32_t instanceCount, uint32_t startIndexLocation, int32_t baseVertexLocation, uint32_t startInstanceLocation) { - checkTopology(); - checkFramebufferSamplePositions(); - d3d->DrawIndexedInstanced(indexCountPerInstance, instanceCount, startIndexLocation, baseVertexLocation, startInstanceLocation); - } - - void D3D12CommandList::setPipeline(const RenderPipeline *pipeline) { - assert(pipeline != nullptr); - - const D3D12Pipeline *interfacePipeline = static_cast(pipeline); - switch (interfacePipeline->type) { - case D3D12Pipeline::Type::Compute: { - const D3D12ComputePipeline *computePipeline = static_cast(interfacePipeline); - d3d->SetPipelineState(computePipeline->d3d); - break; - } - case D3D12Pipeline::Type::Graphics: { - const D3D12GraphicsPipeline *graphicsPipeline = static_cast(interfacePipeline); - d3d->SetPipelineState(graphicsPipeline->d3d); - activeGraphicsPipeline = graphicsPipeline; - break; - } - case D3D12Pipeline::Type::Raytracing: { - const D3D12RaytracingPipeline *raytracingPipeline = static_cast(interfacePipeline); - d3d->SetPipelineState1(raytracingPipeline->stateObject); - break; - } - default: - assert(false && "Unknown pipeline type."); - break; - } - } - - void D3D12CommandList::setComputePipelineLayout(const RenderPipelineLayout *pipelineLayout) { - assert(pipelineLayout != nullptr); - - const D3D12PipelineLayout *interfacePipelineLayout = static_cast(pipelineLayout); - d3d->SetComputeRootSignature(interfacePipelineLayout->rootSignature); - activeComputePipelineLayout = interfacePipelineLayout; - } - - void D3D12CommandList::setComputePushConstants(uint32_t rangeIndex, const void *data, uint32_t offset, uint32_t size) { - assert(activeComputePipelineLayout != nullptr); - assert(rangeIndex < activeComputePipelineLayout->pushConstantRanges.size()); - - const RenderPushConstantRange &range = activeComputePipelineLayout->pushConstantRanges[rangeIndex]; - assert((range.offset == 0) && "Offset behavior should be verified when compared to Vulkan."); - - if (size == 0) { - size = range.size; - } - - d3d->SetComputeRoot32BitConstants(rangeIndex, (size + sizeof(uint32_t) - 1) / sizeof(uint32_t), data, (offset + sizeof(uint32_t) - 1) / sizeof(uint32_t)); - } - - void D3D12CommandList::setComputeDescriptorSet(RenderDescriptorSet *descriptorSet, uint32_t setIndex) { - setDescriptorSet(activeComputePipelineLayout, descriptorSet, setIndex, true); - } - - void D3D12CommandList::setGraphicsPipelineLayout(const RenderPipelineLayout *pipelineLayout) { - assert(pipelineLayout != nullptr); - - const D3D12PipelineLayout *interfacePipelineLayout = static_cast(pipelineLayout); - d3d->SetGraphicsRootSignature(interfacePipelineLayout->rootSignature); - activeGraphicsPipelineLayout = interfacePipelineLayout; - } - - void D3D12CommandList::setGraphicsPushConstants(uint32_t rangeIndex, const void *data, uint32_t offset, uint32_t size) { - assert(activeGraphicsPipelineLayout != nullptr); - assert(rangeIndex < activeGraphicsPipelineLayout->pushConstantRanges.size()); - - const RenderPushConstantRange &range = activeGraphicsPipelineLayout->pushConstantRanges[rangeIndex]; - assert((range.offset == 0) && "Offset behavior should be verified when compared to Vulkan."); - - if (size == 0) { - size = range.size; - } - - d3d->SetGraphicsRoot32BitConstants(rangeIndex, (size + sizeof(uint32_t) - 1) / sizeof(uint32_t), data, (offset + sizeof(uint32_t) - 1) / sizeof(uint32_t)); - } - - void D3D12CommandList::setGraphicsDescriptorSet(RenderDescriptorSet *descriptorSet, uint32_t setIndex) { - setDescriptorSet(activeGraphicsPipelineLayout, descriptorSet, setIndex, false); - } - - void D3D12CommandList::setGraphicsRootDescriptor(RenderBufferReference bufferReference, uint32_t rootDescriptorIndex) { - setRootDescriptor(activeGraphicsPipelineLayout, bufferReference, rootDescriptorIndex, false); - } - - void D3D12CommandList::setRaytracingPipelineLayout(const RenderPipelineLayout *pipelineLayout) { - setComputePipelineLayout(pipelineLayout); - } - - void D3D12CommandList::setRaytracingPushConstants(uint32_t rangeIndex, const void *data, uint32_t offset, uint32_t size) { - setComputePushConstants(rangeIndex, data, offset, size); - } - - void D3D12CommandList::setRaytracingDescriptorSet(RenderDescriptorSet *descriptorSet, uint32_t setIndex) { - setComputeDescriptorSet(descriptorSet, setIndex); - } - - void D3D12CommandList::setIndexBuffer(const RenderIndexBufferView *view) { - if (view != nullptr) { - const D3D12Buffer *interfaceBuffer = static_cast(view->buffer.ref); - D3D12_INDEX_BUFFER_VIEW bufferView; - bufferView.BufferLocation = (interfaceBuffer != nullptr) ? (interfaceBuffer->d3d->GetGPUVirtualAddress() + view->buffer.offset) : 0; - bufferView.Format = toDXGI(view->format); - bufferView.SizeInBytes = view->size; - d3d->IASetIndexBuffer(&bufferView); - } - else { - d3d->IASetIndexBuffer(nullptr); - } - } - - void D3D12CommandList::setVertexBuffers(uint32_t startSlot, const RenderVertexBufferView *views, uint32_t viewCount, const RenderInputSlot *inputSlots) { - if (views != nullptr) { - assert(inputSlots != nullptr); - - thread_local std::vector bufferViewVector; - bufferViewVector.resize(viewCount, {}); - for (uint32_t i = 0; i < viewCount; i++) { - const RenderVertexBufferView &renderView = views[i]; - const D3D12Buffer *interfaceBuffer = static_cast(renderView.buffer.ref); - bufferViewVector[i].BufferLocation = (interfaceBuffer != nullptr) ? (interfaceBuffer->d3d->GetGPUVirtualAddress() + renderView.buffer.offset) : 0; - bufferViewVector[i].SizeInBytes = renderView.size; - - bool slotFound = false; - for (uint32_t j = 0; j < viewCount; j++) { - if (inputSlots[j].index == (startSlot + i)) { - bufferViewVector[i].StrideInBytes = inputSlots[j].stride; - slotFound = true; - break; - } - } - - assert(slotFound && "Input slots must contain a slot with the same index as the view."); - } - - d3d->IASetVertexBuffers(startSlot, viewCount, bufferViewVector.data()); - } - else { - d3d->IASetVertexBuffers(startSlot, viewCount, nullptr); - } - } - - void D3D12CommandList::setViewports(const RenderViewport *viewports, uint32_t count) { - if (count > 1) { - thread_local std::vector viewportVector; - viewportVector.clear(); - for (uint32_t i = 0; i < count; i++) { - viewportVector.emplace_back(D3D12_VIEWPORT{ viewports[i].x, viewports[i].y, viewports[i].width, viewports[i].height, viewports[i].minDepth, viewports[i].maxDepth }); - } - - if (!viewportVector.empty()) { - d3d->RSSetViewports(UINT(viewportVector.size()), viewportVector.data()); - } - } - else { - // Single element fast path. - D3D12_VIEWPORT viewport = D3D12_VIEWPORT{ viewports[0].x, viewports[0].y, viewports[0].width, viewports[0].height, viewports[0].minDepth, viewports[0].maxDepth }; - d3d->RSSetViewports(1, &viewport); - } - } - - void D3D12CommandList::setScissors(const RenderRect *scissorRects, uint32_t count) { - if (count > 1) { - thread_local std::vector rectVector; - rectVector.clear(); - for (uint32_t i = 0; i < count; i++) { - rectVector.emplace_back(D3D12_RECT{ scissorRects[i].left, scissorRects[i].top, scissorRects[i].right, scissorRects[i].bottom }); - } - - if (!rectVector.empty()) { - d3d->RSSetScissorRects(UINT(rectVector.size()), rectVector.data()); - } - } - else { - // Single element fast path. - D3D12_RECT scissor = D3D12_RECT{ scissorRects[0].left, scissorRects[0].top, scissorRects[0].right, scissorRects[0].bottom }; - d3d->RSSetScissorRects(1, &scissor); - } - } - - void D3D12CommandList::setFramebuffer(const RenderFramebuffer *framebuffer) { - if (framebuffer != nullptr) { - const D3D12Framebuffer *interfaceFramebuffer = static_cast(framebuffer); - for (const D3D12Texture *target : interfaceFramebuffer->colorTargets) { - assert((target->layout == RenderTextureLayout::COLOR_WRITE) && "Color targets must be in color write layout when setting the framebuffer."); - } - - if (interfaceFramebuffer->depthTarget != nullptr) { - const bool depthReadLayout = (interfaceFramebuffer->depthTarget->layout == RenderTextureLayout::DEPTH_READ); - const bool depthWriteLayout = (interfaceFramebuffer->depthTarget->layout == RenderTextureLayout::DEPTH_WRITE); - assert((depthReadLayout || depthWriteLayout) && "Depth target must be in depth read or write layout when setting the framebuffer."); - } - - const D3D12_CPU_DESCRIPTOR_HANDLE *colorDescriptors = !interfaceFramebuffer->colorHandles.empty() ? interfaceFramebuffer->colorHandles.data() : nullptr; - const D3D12_CPU_DESCRIPTOR_HANDLE *depthDescriptor = (interfaceFramebuffer->depthHandle.ptr != 0) ? &interfaceFramebuffer->depthHandle : nullptr; - d3d->OMSetRenderTargets(UINT(interfaceFramebuffer->colorHandles.size()), colorDescriptors, false, depthDescriptor); - targetFramebuffer = interfaceFramebuffer; - targetFramebufferSamplePositionsSet = false; - } - else { - d3d->OMSetRenderTargets(0, nullptr, false, nullptr); - targetFramebuffer = nullptr; - } - } - - void D3D12CommandList::setDepthBias(float depthBias, float depthBiasClamp, float slopeScaledDepthBias) { - assert(device->capabilities.dynamicDepthBias && "Dynamic depth bias is unsupported on this device."); - d3d->RSSetDepthBias(depthBias, depthBiasClamp, slopeScaledDepthBias); - } - - void D3D12CommandList::clearColor(uint32_t attachmentIndex, RenderColor colorValue, const RenderRect *clearRects, uint32_t clearRectsCount) { - assert(targetFramebuffer != nullptr); - assert(attachmentIndex < targetFramebuffer->colorTargets.size()); - assert((clearRectsCount == 0) || (clearRects != nullptr)); - - checkFramebufferSamplePositions(); - - thread_local std::vector rectVector; - if (clearRectsCount > 0) { - rectVector.clear(); - for (uint32_t i = 0; i < clearRectsCount; i++) { - rectVector.emplace_back(D3D12_RECT{ clearRects[i].left, clearRects[i].top, clearRects[i].right, clearRects[i].bottom }); - } - } - - d3d->ClearRenderTargetView(targetFramebuffer->colorHandles[attachmentIndex], colorValue.rgba, clearRectsCount, (clearRectsCount > 0) ? rectVector.data() : nullptr); - } - - void D3D12CommandList::clearDepth(bool clearDepth, float depthValue, const RenderRect *clearRects, uint32_t clearRectsCount) { - assert(targetFramebuffer != nullptr); - assert(targetFramebuffer->depthHandle.ptr != 0); - assert((clearRectsCount == 0) || (clearRects != nullptr)); - - checkFramebufferSamplePositions(); - - thread_local std::vector rectVector; - if (clearRectsCount > 0) { - rectVector.clear(); - for (uint32_t i = 0; i < clearRectsCount; i++) { - rectVector.emplace_back(D3D12_RECT{ clearRects[i].left, clearRects[i].top, clearRects[i].right, clearRects[i].bottom }); - } - } - - D3D12_CLEAR_FLAGS clearFlags = {}; - clearFlags |= clearDepth ? D3D12_CLEAR_FLAG_DEPTH : D3D12_CLEAR_FLAGS(0); - d3d->ClearDepthStencilView(targetFramebuffer->depthHandle, clearFlags, depthValue, 0, clearRectsCount, (clearRectsCount > 0) ? rectVector.data() : nullptr); - } - - void D3D12CommandList::copyBufferRegion(RenderBufferReference dstBuffer, RenderBufferReference srcBuffer, uint64_t size) { - assert(dstBuffer.ref != nullptr); - assert(srcBuffer.ref != nullptr); - - const D3D12Buffer *interfaceDstBuffer = static_cast(dstBuffer.ref); - const D3D12Buffer *interfaceSrcBuffer = static_cast(srcBuffer.ref); - d3d->CopyBufferRegion(interfaceDstBuffer->d3d, dstBuffer.offset, interfaceSrcBuffer->d3d, srcBuffer.offset, size); - } - - void D3D12CommandList::copyTextureRegion(const RenderTextureCopyLocation &dstLocation, const RenderTextureCopyLocation &srcLocation, uint32_t dstX, uint32_t dstY, uint32_t dstZ, const RenderBox *srcBox) { - D3D12_BOX copyBox; - if (srcBox != nullptr) { - copyBox.left = srcBox->left; - copyBox.top = srcBox->top; - copyBox.front = srcBox->front; - copyBox.right = srcBox->right; - copyBox.bottom = srcBox->bottom; - copyBox.back = srcBox->back; - } - - const D3D12_TEXTURE_COPY_LOCATION copyDstLocation = toD3D12(dstLocation); - const D3D12_TEXTURE_COPY_LOCATION copySrcLocation = toD3D12(srcLocation); - setSamplePositions(dstLocation.texture); - d3d->CopyTextureRegion(©DstLocation, dstX, dstY, dstZ, ©SrcLocation, (srcBox != nullptr) ? ©Box : nullptr); - resetSamplePositions(); - } - - void D3D12CommandList::copyBuffer(const RenderBuffer *dstBuffer, const RenderBuffer *srcBuffer) { - assert(dstBuffer != nullptr); - assert(srcBuffer != nullptr); - - const D3D12Buffer *interfaceDstBuffer = static_cast(dstBuffer); - const D3D12Buffer *interfaceSrcBuffer = static_cast(srcBuffer); - d3d->CopyResource(interfaceDstBuffer->d3d, interfaceSrcBuffer->d3d); - } - - void D3D12CommandList::copyTexture(const RenderTexture *dstTexture, const RenderTexture *srcTexture) { - assert(dstTexture != nullptr); - assert(srcTexture != nullptr); - - const D3D12Texture *interfaceDstTexture = static_cast(dstTexture); - const D3D12Texture *interfaceSrcTexture = static_cast(srcTexture); - setSamplePositions(interfaceDstTexture); - d3d->CopyResource(interfaceDstTexture->d3d, interfaceSrcTexture->d3d); - resetSamplePositions(); - } - - void D3D12CommandList::resolveTexture(const RenderTexture *dstTexture, const RenderTexture *srcTexture) { - assert(dstTexture != nullptr); - assert(srcTexture != nullptr); - - const D3D12Texture *interfaceDstTexture = static_cast(dstTexture); - const D3D12Texture *interfaceSrcTexture = static_cast(srcTexture); - setSamplePositions(interfaceDstTexture); - d3d->ResolveSubresource(interfaceDstTexture->d3d, 0, interfaceSrcTexture->d3d, 0, toDXGI(interfaceDstTexture->desc.format)); - resetSamplePositions(); - } - - void D3D12CommandList::resolveTextureRegion(const RenderTexture *dstTexture, uint32_t dstX, uint32_t dstY, const RenderTexture *srcTexture, const RenderRect *srcRect, RenderResolveMode resolveMode) { - assert(dstTexture != nullptr); - assert(srcTexture != nullptr); - - const D3D12Texture *interfaceDstTexture = static_cast(dstTexture); - const D3D12Texture *interfaceSrcTexture = static_cast(srcTexture); - D3D12_RECT rect; - if (srcRect != nullptr) { - rect.left = srcRect->left; - rect.top = srcRect->top; - rect.right = srcRect->right; - rect.bottom = srcRect->bottom; - } - - setSamplePositions(interfaceDstTexture); - d3d->ResolveSubresourceRegion(interfaceDstTexture->d3d, 0, dstX, dstY, interfaceSrcTexture->d3d, 0, (srcRect != nullptr) ? &rect : nullptr, toDXGI(interfaceDstTexture->desc.format), toD3D12(resolveMode)); - resetSamplePositions(); - } - - void D3D12CommandList::buildBottomLevelAS(const RenderAccelerationStructure *dstAccelerationStructure, RenderBufferReference scratchBuffer, const RenderBottomLevelASBuildInfo &buildInfo) { - assert(dstAccelerationStructure != nullptr); - assert(scratchBuffer.ref != nullptr); - - const D3D12AccelerationStructure *interfaceAccelerationStructure = static_cast(dstAccelerationStructure); - assert(interfaceAccelerationStructure->type == RenderAccelerationStructureType::BOTTOM_LEVEL); - - const D3D12Buffer *interfaceScratchBuffer = static_cast(scratchBuffer.ref); - assert((interfaceScratchBuffer->desc.flags & RenderBufferFlag::ACCELERATION_STRUCTURE_SCRATCH) && "Scratch buffer must be allowed."); - - D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_DESC buildDesc = {}; - buildDesc.Inputs.Type = D3D12_RAYTRACING_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL; - buildDesc.Inputs.DescsLayout = D3D12_ELEMENTS_LAYOUT_ARRAY; - buildDesc.Inputs.NumDescs = buildInfo.meshCount; - buildDesc.Inputs.pGeometryDescs = reinterpret_cast(buildInfo.buildData.data()); - buildDesc.Inputs.Flags = toRTASBuildFlags(buildInfo.preferFastBuild, buildInfo.preferFastTrace); - buildDesc.DestAccelerationStructureData = interfaceAccelerationStructure->buffer->d3d->GetGPUVirtualAddress() + interfaceAccelerationStructure->offset; - buildDesc.ScratchAccelerationStructureData = interfaceScratchBuffer->d3d->GetGPUVirtualAddress() + scratchBuffer.offset; - - d3d->BuildRaytracingAccelerationStructure(&buildDesc, 0, nullptr); - } - - void D3D12CommandList::buildTopLevelAS(const RenderAccelerationStructure *dstAccelerationStructure, RenderBufferReference scratchBuffer, RenderBufferReference instancesBuffer, const RenderTopLevelASBuildInfo &buildInfo) { - assert(dstAccelerationStructure != nullptr); - assert(scratchBuffer.ref != nullptr); - assert(instancesBuffer.ref != nullptr); - - const D3D12AccelerationStructure *interfaceAccelerationStructure = static_cast(dstAccelerationStructure); - assert(interfaceAccelerationStructure->type == RenderAccelerationStructureType::TOP_LEVEL);; - - const D3D12Buffer *interfaceScratchBuffer = static_cast(scratchBuffer.ref); - assert((interfaceScratchBuffer->desc.flags & RenderBufferFlag::ACCELERATION_STRUCTURE_SCRATCH) && "Scratch buffer must be allowed."); - - const D3D12Buffer *interfaceInstancesBuffer = static_cast(instancesBuffer.ref); - assert((interfaceInstancesBuffer->desc.flags & RenderBufferFlag::ACCELERATION_STRUCTURE_INPUT) && "Acceleration structure input must be allowed."); - - D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_DESC buildDesc = {}; - buildDesc.Inputs.Type = D3D12_RAYTRACING_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL; - buildDesc.Inputs.DescsLayout = D3D12_ELEMENTS_LAYOUT_ARRAY; - buildDesc.Inputs.NumDescs = buildInfo.instanceCount; - buildDesc.Inputs.InstanceDescs = interfaceInstancesBuffer->d3d->GetGPUVirtualAddress() + instancesBuffer.offset; - buildDesc.Inputs.Flags = toRTASBuildFlags(buildInfo.preferFastBuild, buildInfo.preferFastTrace); - buildDesc.DestAccelerationStructureData = interfaceAccelerationStructure->buffer->d3d->GetGPUVirtualAddress() + interfaceAccelerationStructure->offset; - buildDesc.ScratchAccelerationStructureData = interfaceScratchBuffer->d3d->GetGPUVirtualAddress() + scratchBuffer.offset; - - d3d->BuildRaytracingAccelerationStructure(&buildDesc, 0, nullptr); - } - - void D3D12CommandList::discardTexture(const RenderTexture* texture) { - const D3D12Texture* interfaceTexture = static_cast(texture); - d3d->DiscardResource(interfaceTexture->d3d, nullptr); - } - - void D3D12CommandList::resetQueryPool(const RenderQueryPool *queryPool, uint32_t queryFirstIndex, uint32_t queryCount) { - // Do nothing. - } - - void D3D12CommandList::writeTimestamp(const RenderQueryPool *queryPool, uint32_t queryIndex) { - assert(queryPool != nullptr); - - const D3D12QueryPool *interfaceQueryPool = static_cast(queryPool); - const D3D12Buffer *readbackBuffer = static_cast(interfaceQueryPool->readbackBuffer.get()); - d3d->EndQuery(interfaceQueryPool->d3d, D3D12_QUERY_TYPE_TIMESTAMP, queryIndex); - d3d->ResolveQueryData(interfaceQueryPool->d3d, D3D12_QUERY_TYPE_TIMESTAMP, queryIndex, 1, readbackBuffer->d3d, queryIndex * sizeof(uint64_t)); - } - - void D3D12CommandList::checkDescriptorHeaps() { - if (!descriptorHeapsSet) { - ID3D12DescriptorHeap *descriptorHeaps[] = { device->viewHeapAllocator->heap, device->samplerHeapAllocator->heap }; - d3d->SetDescriptorHeaps(std::size(descriptorHeaps), descriptorHeaps); - descriptorHeapsSet = true; - } - } - - void D3D12CommandList::notifyDescriptorHeapWasChangedExternally() { - descriptorHeapsSet = false; - } - - void D3D12CommandList::checkTopology() { - assert(activeGraphicsPipeline != nullptr); - assert(activeGraphicsPipeline->type == D3D12Pipeline::Type::Graphics); - - const D3D12GraphicsPipeline *graphicsPipeline = static_cast(activeGraphicsPipeline); - if (activeTopology != graphicsPipeline->topology) { - d3d->IASetPrimitiveTopology(graphicsPipeline->topology); - activeTopology = graphicsPipeline->topology; - } - } - - void D3D12CommandList::checkFramebufferSamplePositions() { - if (!targetFramebufferSamplePositionsSet && (targetFramebuffer != nullptr)) { - if (targetFramebuffer->depthTarget != nullptr) { - setSamplePositions(targetFramebuffer->depthTarget); - } - - targetFramebufferSamplePositionsSet = true; - } - } - - void D3D12CommandList::setSamplePositions(const RenderTexture *texture) { - assert(texture != nullptr); - - const D3D12Texture *interfaceTexture = static_cast(texture); - if (interfaceTexture->desc.multisampling.sampleLocationsEnabled) { - thread_local std::vector samplePositions; - samplePositions.resize(interfaceTexture->desc.multisampling.sampleCount); - for (uint32_t i = 0; i < interfaceTexture->desc.multisampling.sampleCount; i++) { - const RenderMultisamplingLocation &location = interfaceTexture->desc.multisampling.sampleLocations[i]; - samplePositions[i].X = location.x; - samplePositions[i].Y = location.y; - } - - d3d->SetSamplePositions(uint32_t(samplePositions.size()), 1, samplePositions.data()); - activeSamplePositions = true; - } - else { - resetSamplePositions(); - } - } - - void D3D12CommandList::resetSamplePositions() { - if (activeSamplePositions) { - d3d->SetSamplePositions(0, 0, nullptr); - activeSamplePositions = false; - targetFramebufferSamplePositionsSet = false; - } - } - - - void D3D12CommandList::setDescriptorSet(const D3D12PipelineLayout *activePipelineLayout, RenderDescriptorSet *descriptorSet, uint32_t setIndex, bool setCompute) { - assert(descriptorSet != nullptr); - assert(activePipelineLayout != nullptr); - assert(setIndex < activePipelineLayout->setCount); - - checkDescriptorHeaps(); - - D3D12DescriptorSet *interfaceDescriptorSet = static_cast(descriptorSet); - setRootDescriptorTable(device->viewHeapAllocator.get(), interfaceDescriptorSet->viewAllocation, activePipelineLayout->setViewRootIndices[setIndex], setCompute); - setRootDescriptorTable(device->samplerHeapAllocator.get(), interfaceDescriptorSet->samplerAllocation, activePipelineLayout->setSamplerRootIndices[setIndex], setCompute); - } - - void D3D12CommandList::setRootDescriptorTable(D3D12DescriptorHeapAllocator *heapAllocator, D3D12DescriptorSet::HeapAllocation &heapAllocation, uint32_t rootIndex, bool setCompute) { - if (heapAllocation.count == 0) { - return; - } - - const D3D12_GPU_DESCRIPTOR_HANDLE gpuHandle = heapAllocator->getGPUHandleAt(heapAllocation.offset); - if (setCompute) { - d3d->SetComputeRootDescriptorTable(rootIndex, gpuHandle); - } - else { - d3d->SetGraphicsRootDescriptorTable(rootIndex, gpuHandle); - } - } - - void D3D12CommandList::setRootDescriptor(const D3D12PipelineLayout* activePipelineLayout, RenderBufferReference bufferReference, uint32_t rootDescriptorIndex, bool setCompute) { - assert(rootDescriptorIndex < activePipelineLayout->rootDescriptorRootIndicesAndTypes.size()); - - D3D12_GPU_VIRTUAL_ADDRESS gpuVA = static_cast(bufferReference.ref)->d3d->GetGPUVirtualAddress() + bufferReference.offset; - const auto& [rootParamIndex, type] = activePipelineLayout->rootDescriptorRootIndicesAndTypes[rootDescriptorIndex]; - - if (setCompute) { - switch (type) { - case RenderRootDescriptorType::CONSTANT_BUFFER: - d3d->SetComputeRootConstantBufferView(rootParamIndex, gpuVA); - break; - case RenderRootDescriptorType::SHADER_RESOURCE: - d3d->SetComputeRootShaderResourceView(rootParamIndex, gpuVA); - break; - case RenderRootDescriptorType::UNORDERED_ACCESS: - d3d->SetComputeRootUnorderedAccessView(rootParamIndex, gpuVA); - break; - default: - assert(false && "Unknown root descriptor type."); - break; - } - } - else { - switch (type) { - case RenderRootDescriptorType::CONSTANT_BUFFER: - d3d->SetGraphicsRootConstantBufferView(rootParamIndex, gpuVA); - break; - case RenderRootDescriptorType::SHADER_RESOURCE: - d3d->SetGraphicsRootShaderResourceView(rootParamIndex, gpuVA); - break; - case RenderRootDescriptorType::UNORDERED_ACCESS: - d3d->SetGraphicsRootUnorderedAccessView(rootParamIndex, gpuVA); - break; - default: - assert(false && "Unknown root descriptor type."); - break; - } - } - } - - // D3D12CommandFence - - D3D12CommandFence::D3D12CommandFence(D3D12Device *device) { - assert(device != nullptr); - - this->device = device; - - HRESULT res = device->d3d->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&d3d)); - if (FAILED(res)) { - fprintf(stderr, "CreateFence failed with error code 0x%lX.\n", res); - return; - } - - fenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr); - fenceValue = 1; - } - - D3D12CommandFence::~D3D12CommandFence() { - if (d3d != nullptr) { - d3d->Release(); - } - - if (fenceEvent != 0) { - CloseHandle(fenceEvent); - } - } - - // D3D12CommandSemaphore - - D3D12CommandSemaphore::D3D12CommandSemaphore(D3D12Device *device) { - assert(device != nullptr); - - this->device = device; - - HRESULT res = device->d3d->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&d3d)); - if (FAILED(res)) { - fprintf(stderr, "CreateFence failed with error code 0x%lX.\n", res); - return; - } - } - - D3D12CommandSemaphore::~D3D12CommandSemaphore() { - if (d3d != nullptr) { - d3d->Release(); - } - } - - // D3D12CommandQueue - - D3D12CommandQueue::D3D12CommandQueue(D3D12Device *device, RenderCommandListType type) { - assert(device != nullptr); - - this->device = device; - this->type = type; - - D3D12_COMMAND_QUEUE_DESC queueDesc = { }; - queueDesc.Priority = D3D12_COMMAND_QUEUE_PRIORITY_NORMAL; - queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE; - queueDesc.NodeMask = 0; - - switch (type) { - case RenderCommandListType::DIRECT: - queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; - break; - case RenderCommandListType::COMPUTE: - queueDesc.Type = D3D12_COMMAND_LIST_TYPE_COMPUTE; - break; - case RenderCommandListType::COPY: - queueDesc.Type = D3D12_COMMAND_LIST_TYPE_COPY; - break; - default: - assert(false && "Unknown command list type."); - return; - } - - HRESULT res = device->d3d->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&d3d)); - if (FAILED(res)) { - fprintf(stderr, "CreateCommandQueue failed with error code 0x%lX.\n", res); - return; - } - } - - D3D12CommandQueue::~D3D12CommandQueue() { - if (d3d != nullptr) { - d3d->Release(); - } - } - - std::unique_ptr D3D12CommandQueue::createSwapChain(RenderWindow renderWindow, uint32_t bufferCount, RenderFormat format, uint32_t maxFrameLatency) { - return std::make_unique(this, renderWindow, bufferCount, format, maxFrameLatency); - } - - void D3D12CommandQueue::executeCommandLists(const RenderCommandList **commandLists, uint32_t commandListCount, RenderCommandSemaphore **waitSemaphores, uint32_t waitSemaphoreCount, RenderCommandSemaphore **signalSemaphores, uint32_t signalSemaphoreCount, RenderCommandFence *signalFence) { - for (uint32_t i = 0; i < waitSemaphoreCount; i++) { - D3D12CommandSemaphore *interfaceSemaphore = static_cast(waitSemaphores[i]); - d3d->Wait(interfaceSemaphore->d3d, interfaceSemaphore->semaphoreValue); - } - - thread_local std::vector executionVector; - executionVector.clear(); - for (uint32_t i = 0; i < commandListCount; i++) { - const D3D12CommandList *interfaceCommandList = static_cast(commandLists[i]); - executionVector.emplace_back(static_cast(interfaceCommandList->d3d)); - } - - if (!executionVector.empty()) { - d3d->ExecuteCommandLists(UINT(executionVector.size()), executionVector.data()); - } - - for (uint32_t i = 0; i < signalSemaphoreCount; i++) { - D3D12CommandSemaphore *interfaceSemaphore = static_cast(signalSemaphores[i]); - interfaceSemaphore->semaphoreValue++; - d3d->Signal(interfaceSemaphore->d3d, interfaceSemaphore->semaphoreValue); - } - - if (signalFence != nullptr) { - D3D12CommandFence *interfaceFence = static_cast(signalFence); - d3d->Signal(interfaceFence->d3d, interfaceFence->fenceValue); - interfaceFence->d3d->SetEventOnCompletion(interfaceFence->fenceValue, interfaceFence->fenceEvent); - interfaceFence->fenceValue++; - } - } - - void D3D12CommandQueue::waitForCommandFence(RenderCommandFence *fence) { - assert(fence != nullptr); - - D3D12CommandFence *interfaceFence = static_cast(fence); - WaitForSingleObjectEx(interfaceFence->fenceEvent, INFINITE, FALSE); - } - - // D3D12Buffer - - D3D12Buffer::D3D12Buffer(D3D12Device *device, D3D12Pool *pool, const RenderBufferDesc &desc) { - assert(device != nullptr); - - this->device = device; - this->pool = pool; - this->desc = desc; - - D3D12_RESOURCE_DESC resourceDesc = {}; - resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; - resourceDesc.Width = desc.size; - resourceDesc.Height = 1; - resourceDesc.DepthOrArraySize = 1; - resourceDesc.MipLevels = 1; - resourceDesc.Format = DXGI_FORMAT_UNKNOWN; - resourceDesc.SampleDesc.Count = 1; - resourceDesc.SampleDesc.Quality = 0; - resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; - - const uint32_t unorderedAccessMask = RenderBufferFlag::ACCELERATION_STRUCTURE | RenderBufferFlag::ACCELERATION_STRUCTURE_SCRATCH | RenderBufferFlag::UNORDERED_ACCESS; - resourceDesc.Flags |= (desc.flags & unorderedAccessMask) ? D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS : D3D12_RESOURCE_FLAG_NONE; - - // Default to acceleration structure state if allowed. - if ((desc.flags & RenderBufferFlag::ACCELERATION_STRUCTURE)) { - resourceStates |= D3D12_RESOURCE_STATE_RAYTRACING_ACCELERATION_STRUCTURE; - } - - // Resources on upload heap require generic read during creation. - if (desc.heapType == RenderHeapType::UPLOAD) { - resourceStates |= D3D12_RESOURCE_STATE_GENERIC_READ; - } - // Resources on readback heap require copy dest during creation. - else if (desc.heapType == RenderHeapType::READBACK) { - resourceStates |= D3D12_RESOURCE_STATE_COPY_DEST; - } - - D3D12MA::ALLOCATION_DESC allocationDesc = {}; - allocationDesc.Flags = desc.committed ? D3D12MA::ALLOCATION_FLAG_COMMITTED : D3D12MA::ALLOCATION_FLAG_NONE; - allocationDesc.HeapType = toD3D12(desc.heapType); - allocationDesc.CustomPool = (pool != nullptr) ? pool->d3d : nullptr; - - HRESULT res = device->allocator->CreateResource(&allocationDesc, &resourceDesc, resourceStates, nullptr, &allocation, IID_PPV_ARGS(&d3d)); - if (FAILED(res)) { - fprintf(stderr, "CreateResource failed with error code 0x%lX.\n", res); - return; - } - } - - D3D12Buffer::~D3D12Buffer() { - if (allocation != nullptr) { - d3d->Release(); - allocation->Release(); - } - } - - void *D3D12Buffer::map(uint32_t subresource, const RenderRange *readRange) { - D3D12_RANGE range; - if (readRange != nullptr) { - range.Begin = readRange->begin; - range.End = readRange->end; - } - - void *outputData = nullptr; - d3d->Map(subresource, (readRange != nullptr) ? &range : nullptr, &outputData); - return outputData; - } - - void D3D12Buffer::unmap(uint32_t subresource, const RenderRange *writtenRange) { - D3D12_RANGE range; - if (writtenRange != nullptr) { - range.Begin = writtenRange->begin; - range.End = writtenRange->end; - } - - d3d->Unmap(subresource, (writtenRange != nullptr) ? &range : nullptr); - } - - std::unique_ptr D3D12Buffer::createBufferFormattedView(RenderFormat format) { - return std::make_unique(this, format); - } - - void D3D12Buffer::setName(const std::string &name) { - setObjectName(d3d, name); - } - - uint64_t D3D12Buffer::getDeviceAddress() const { - return d3d->GetGPUVirtualAddress(); - } - - // D3D12BufferFormattedView - - D3D12BufferFormattedView::D3D12BufferFormattedView(D3D12Buffer *buffer, RenderFormat format) { - assert(buffer != nullptr); - assert((buffer->desc.flags & RenderBufferFlag::FORMATTED) && "Buffer must allow formatted views."); - - this->buffer = buffer; - this->format = format; - } - - D3D12BufferFormattedView::~D3D12BufferFormattedView() { } - - // D3D12TextureView - - D3D12TextureView::D3D12TextureView(D3D12Texture *texture, const RenderTextureViewDesc &desc) { - assert(texture != nullptr); - - this->texture = texture; - this->format = toDXGI(desc.format); - this->dimension = desc.dimension; - this->mipLevels = desc.mipLevels; - this->mipSlice = desc.mipSlice; - this->shader4ComponentMapping = toD3D12(desc.componentMapping); - - // D3D12 and Vulkan disagree on whether D32 is usable as a texture view format. We just make D3D12 use R32 instead. - if (format == DXGI_FORMAT_D32_FLOAT) { - format = DXGI_FORMAT_R32_FLOAT; - } - } - - D3D12TextureView::~D3D12TextureView() { } - - // D3D12Texture - - D3D12Texture::D3D12Texture(D3D12Device *device, D3D12Pool *pool, const RenderTextureDesc &desc) { - assert(device != nullptr); - - this->device = device; - this->pool = pool; - this->desc = desc; - - const bool renderTarget = (desc.flags & RenderTextureFlag::RENDER_TARGET); - const bool depthTarget = (desc.flags & RenderTextureFlag::DEPTH_TARGET); - D3D12_RESOURCE_DESC resourceDesc = {}; - resourceDesc.Dimension = toD3D12(desc.dimension); - resourceDesc.Width = desc.width; - resourceDesc.Height = desc.height; - resourceDesc.DepthOrArraySize = desc.dimension == RenderTextureDimension::TEXTURE_3D ? desc.depth : desc.arraySize; - resourceDesc.MipLevels = desc.mipLevels; - resourceDesc.Format = toDXGI(desc.format); - resourceDesc.SampleDesc.Count = desc.multisampling.sampleCount; - resourceDesc.Layout = toD3D12(desc.textureArrangement); - resourceDesc.Flags |= renderTarget ? D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET : D3D12_RESOURCE_FLAG_NONE; - resourceDesc.Flags |= depthTarget ? D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL : D3D12_RESOURCE_FLAG_NONE; - resourceDesc.Flags |= (desc.flags & RenderTextureFlag::UNORDERED_ACCESS) ? D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS : D3D12_RESOURCE_FLAG_NONE; - - D3D12MA::ALLOCATION_DESC allocationDesc = {}; - allocationDesc.Flags = desc.committed ? D3D12MA::ALLOCATION_FLAG_COMMITTED : D3D12MA::ALLOCATION_FLAG_NONE; - allocationDesc.HeapType = D3D12_HEAP_TYPE_DEFAULT; - allocationDesc.CustomPool = (pool != nullptr) ? pool->d3d : nullptr; - - D3D12_CLEAR_VALUE optimizedClearValue; - if (desc.optimizedClearValue != nullptr) { - optimizedClearValue.Format = toDXGI(desc.optimizedClearValue->format); - memcpy(optimizedClearValue.Color, desc.optimizedClearValue->color.rgba, sizeof(optimizedClearValue.Color)); - } - - HRESULT res = device->allocator->CreateResource(&allocationDesc, &resourceDesc, resourceStates, (desc.optimizedClearValue != nullptr) ? &optimizedClearValue : nullptr, &allocation, IID_PPV_ARGS(&d3d)); - if (FAILED(res)) { - fprintf(stderr, "CreateResource failed with error code 0x%lX.\n", res); - return; - } - - if (renderTarget) { - createRenderTargetHeap(); - } - else if (depthTarget) { - createDepthStencilHeap(); - } - } - - D3D12Texture::~D3D12Texture() { - releaseTargetHeap(); - - if (allocation != nullptr) { - d3d->Release(); - allocation->Release(); - } - } - - std::unique_ptr D3D12Texture::createTextureView(const RenderTextureViewDesc &desc) { - return std::make_unique(this, desc); - } - - void D3D12Texture::setName(const std::string &name) { - setObjectName(d3d, name); - } - - void D3D12Texture::createRenderTargetHeap() { - targetAllocatorOffset = device->colorTargetHeapAllocator->allocate(1); - if (targetAllocatorOffset == D3D12DescriptorHeapAllocator::INVALID_OFFSET) { - fprintf(stderr, "Allocator was unable to find free space for the set."); - return; - } - - targetEntryCount = 1; - targetHeapDepth = false; - - D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {}; - rtvDesc.Format = toDXGI(desc.format); - - const bool isMSAA = (desc.multisampling.sampleCount > RenderSampleCount::COUNT_1); - switch (desc.dimension) { - case RenderTextureDimension::TEXTURE_1D: - rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE1D; - rtvDesc.Texture1D.MipSlice = 0; - break; - case RenderTextureDimension::TEXTURE_2D: - if (isMSAA) { - rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DMS; - } - else { - rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D; - rtvDesc.Texture2D.MipSlice = 0; - rtvDesc.Texture2D.PlaneSlice = 0; - } - - break; - case RenderTextureDimension::TEXTURE_3D: - rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE3D; - rtvDesc.Texture3D.MipSlice = 0; - rtvDesc.Texture3D.FirstWSlice = 0; - rtvDesc.Texture3D.WSize = 1; - break; - default: - assert(false && "Unsupported texture dimension for render target."); - break; - } - - const D3D12_CPU_DESCRIPTOR_HANDLE cpuHandle = device->colorTargetHeapAllocator->getCPUHandleAt(targetAllocatorOffset); - device->d3d->CreateRenderTargetView(d3d, &rtvDesc, cpuHandle); - } - - void D3D12Texture::createDepthStencilHeap() { - targetAllocatorOffset = device->depthTargetHeapAllocator->allocate(2); - if (targetAllocatorOffset == D3D12DescriptorHeapAllocator::INVALID_OFFSET) { - fprintf(stderr, "Allocator was unable to find free space for the set."); - return; - } - - targetEntryCount = 2; - targetHeapDepth = true; - - D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc = {}; - dsvDesc.Format = toDXGI(desc.format); - - const bool isMSAA = (desc.multisampling.sampleCount > RenderSampleCount::COUNT_1); - switch (desc.dimension) { - case RenderTextureDimension::TEXTURE_1D: - dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE1D; - dsvDesc.Texture1D.MipSlice = 0; - break; - case RenderTextureDimension::TEXTURE_2D: - if (isMSAA) { - dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2DMS; - } - else { - dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D; - dsvDesc.Texture2D.MipSlice = 0; - } - - break; - default: - assert(false && "Unsupported texture dimension for depth target."); - break; - } - - const D3D12_CPU_DESCRIPTOR_HANDLE writeHandle = device->depthTargetHeapAllocator->getCPUHandleAt(targetAllocatorOffset); - const D3D12_CPU_DESCRIPTOR_HANDLE readOnlyHandle = device->depthTargetHeapAllocator->getCPUHandleAt(targetAllocatorOffset + 1); - device->d3d->CreateDepthStencilView(d3d, &dsvDesc, writeHandle); - - dsvDesc.Flags = D3D12_DSV_FLAG_READ_ONLY_DEPTH; - device->d3d->CreateDepthStencilView(d3d, &dsvDesc, readOnlyHandle); - } - - void D3D12Texture::releaseTargetHeap() { - if (targetEntryCount > 0) { - if (targetHeapDepth) { - device->depthTargetHeapAllocator->free(targetAllocatorOffset, targetEntryCount); - } - else { - device->colorTargetHeapAllocator->free(targetAllocatorOffset, targetEntryCount); - } - - targetEntryCount = 0; - } - } - - // D3D12AccelerationStructure - - D3D12AccelerationStructure::D3D12AccelerationStructure(D3D12Device *device, const RenderAccelerationStructureDesc &desc) { - assert(device != nullptr); - assert(desc.buffer.ref != nullptr); - - this->device = device; - this->buffer = static_cast(desc.buffer.ref); - this->offset = desc.buffer.offset; - this->size = desc.size; - this->type = desc.type; - - assert((buffer->desc.flags & RenderBufferFlag::ACCELERATION_STRUCTURE) && "Buffer must be enabled for acceleration structures."); - } - - D3D12AccelerationStructure::~D3D12AccelerationStructure() { } - - // D3D12Pool - - D3D12Pool::D3D12Pool(D3D12Device *device, const RenderPoolDesc &desc, bool gpuUploadHeapFallback) { - assert(device != nullptr); - - this->device = device; - this->desc = desc; - - D3D12MA::POOL_DESC poolDesc = {}; - - // When using an UMA architecture without explicit support for GPU Upload heaps, we instead just make a custom heap with the same properties as Upload heaps. - if ((desc.heapType == RenderHeapType::GPU_UPLOAD) && gpuUploadHeapFallback) { - poolDesc.HeapProperties = device->d3d->GetCustomHeapProperties(0, D3D12_HEAP_TYPE_UPLOAD); - } - else { - poolDesc.HeapProperties.Type = toD3D12(desc.heapType); - } - - poolDesc.MinBlockCount = desc.minBlockCount; - poolDesc.MaxBlockCount = desc.maxBlockCount; - poolDesc.Flags |= desc.useLinearAlgorithm ? D3D12MA::POOL_FLAG_ALGORITHM_LINEAR : D3D12MA::POOL_FLAG_NONE; - poolDesc.HeapFlags |= desc.allowOnlyBuffers ? D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS : D3D12_HEAP_FLAG_NONE; - - HRESULT res = device->allocator->CreatePool(&poolDesc, &d3d); - if (FAILED(res)) { - fprintf(stderr, "CreatePool failed with error code 0x%lX.\n", res); - return; - } - } - - D3D12Pool::~D3D12Pool() { - if (d3d != nullptr) { - d3d->Release(); - } - } - - std::unique_ptr D3D12Pool::createBuffer(const RenderBufferDesc &desc) { - return std::make_unique(device, this, desc); - } - - std::unique_ptr D3D12Pool::createTexture(const RenderTextureDesc &desc) { - return std::make_unique(device, this, desc); - } - - // D3D12Shader - - D3D12Shader::D3D12Shader(D3D12Device *device, const void *data, uint64_t size, const char *entryPointName, RenderShaderFormat format) { - assert(device != nullptr); - assert(data != nullptr); - assert(size > 0); - assert(format != RenderShaderFormat::UNKNOWN); - assert(format == RenderShaderFormat::DXIL); - - this->data = data; - this->size = size; - this->device = device; - this->format = format; - this->entryPointName = (entryPointName != nullptr) ? std::string(entryPointName) : std::string(); - } - - D3D12Shader::~D3D12Shader() { } - - // D3D12Sampler - - D3D12Sampler::D3D12Sampler(D3D12Device *device, const RenderSamplerDesc &desc) { - assert(device != nullptr); - - this->device = device; - this->borderColor = desc.borderColor; - this->shaderVisibility = desc.shaderVisibility; - - samplerDesc.Filter = toFilter(desc.minFilter, desc.magFilter, desc.mipmapMode, desc.anisotropyEnabled, desc.comparisonEnabled); - samplerDesc.AddressU = toD3D12(desc.addressU); - samplerDesc.AddressV = toD3D12(desc.addressV); - samplerDesc.AddressW = toD3D12(desc.addressW); - samplerDesc.MipLODBias = desc.mipLODBias; - samplerDesc.MaxAnisotropy = desc.anisotropyEnabled ? desc.maxAnisotropy : 1; - samplerDesc.ComparisonFunc = desc.comparisonEnabled ? toD3D12(desc.comparisonFunc) : D3D12_COMPARISON_FUNC_NEVER; - samplerDesc.MinLOD = desc.minLOD; - samplerDesc.MaxLOD = desc.maxLOD; - - float *dstColor = samplerDesc.BorderColor; - switch (desc.borderColor) { - case RenderBorderColor::TRANSPARENT_BLACK: - dstColor[0] = 0.0f; - dstColor[1] = 0.0f; - dstColor[2] = 0.0f; - dstColor[3] = 0.0f; - break; - case RenderBorderColor::OPAQUE_BLACK: - dstColor[0] = 0.0f; - dstColor[1] = 0.0f; - dstColor[2] = 0.0f; - dstColor[3] = 1.0f; - break; - case RenderBorderColor::OPAQUE_WHITE: - dstColor[0] = 1.0f; - dstColor[1] = 1.0f; - dstColor[2] = 1.0f; - dstColor[3] = 1.0f; - break; - default: - assert(false && "Unknown border color."); - break; - } - } - - D3D12Sampler::~D3D12Sampler() { } - - // D3D12Pipeline - - D3D12Pipeline::D3D12Pipeline(D3D12Device *device, Type type) { - assert(device != nullptr); - - this->device = device; - this->type = type; - } - - D3D12Pipeline::~D3D12Pipeline() { } - - // D3D12ComputePipeline - - D3D12ComputePipeline::D3D12ComputePipeline(D3D12Device *device, const RenderComputePipelineDesc &desc) : D3D12Pipeline(device, Type::Compute) { - assert(desc.pipelineLayout != nullptr); - - const D3D12PipelineLayout *rootSignature = static_cast(desc.pipelineLayout); - const D3D12Shader *computeShader = static_cast(desc.computeShader); - D3D12_COMPUTE_PIPELINE_STATE_DESC psoDesc = {}; - psoDesc.pRootSignature = rootSignature->rootSignature; - psoDesc.CS.pShaderBytecode = computeShader->data; - psoDesc.CS.BytecodeLength = computeShader->size; - device->d3d->CreateComputePipelineState(&psoDesc, IID_PPV_ARGS(&d3d)); - } - - D3D12ComputePipeline::~D3D12ComputePipeline() { - if (d3d != nullptr) { - d3d->Release(); - } - } - - void D3D12ComputePipeline::setName(const std::string& name) const { - setObjectName(d3d, name); - } - - RenderPipelineProgram D3D12ComputePipeline::getProgram(const std::string &name) const { - assert(false && "Compute pipelines can't retrieve shader programs."); - return RenderPipelineProgram(); - } - - // D3D12GraphicsPipeline - - D3D12GraphicsPipeline::D3D12GraphicsPipeline(D3D12Device *device, const RenderGraphicsPipelineDesc &desc) : D3D12Pipeline(device, Type::Graphics) { - assert(desc.pipelineLayout != nullptr); - - topology = toD3D12(desc.primitiveTopology); - - const D3D12PipelineLayout *pipelineLayout = static_cast(desc.pipelineLayout); - const D3D12Shader *vertexShader = static_cast(desc.vertexShader); - const D3D12Shader *geometryShader = static_cast(desc.geometryShader); - const D3D12Shader *pixelShader = static_cast(desc.pixelShader); - D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {}; - psoDesc.pRootSignature = pipelineLayout->rootSignature; - psoDesc.VS.pShaderBytecode = (vertexShader != nullptr) ? vertexShader->data : nullptr; - psoDesc.VS.BytecodeLength = (vertexShader != nullptr) ? vertexShader->size : 0; - psoDesc.GS.pShaderBytecode = (geometryShader != nullptr) ? geometryShader->data : nullptr; - psoDesc.GS.BytecodeLength = (geometryShader != nullptr) ? geometryShader->size : 0; - psoDesc.PS.pShaderBytecode = (pixelShader != nullptr) ? pixelShader->data : nullptr; - psoDesc.PS.BytecodeLength = (pixelShader != nullptr) ? pixelShader->size : 0; - psoDesc.SampleMask = UINT_MAX; - psoDesc.SampleDesc.Count = desc.multisampling.sampleCount; - if (desc.primitiveTopology == RenderPrimitiveTopology::LINE_STRIP || desc.primitiveTopology == RenderPrimitiveTopology::TRIANGLE_STRIP) { - psoDesc.IBStripCutValue = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFF; - } - psoDesc.PrimitiveTopologyType = toTopologyType(desc.primitiveTopology); - psoDesc.RasterizerState.FillMode = D3D12_FILL_MODE_SOLID; - psoDesc.RasterizerState.DepthClipEnable = desc.depthClipEnabled; - psoDesc.RasterizerState.DepthBias = desc.depthBias; - psoDesc.RasterizerState.SlopeScaledDepthBias = desc.slopeScaledDepthBias; - - if (desc.dynamicDepthBiasEnabled) { - psoDesc.Flags |= D3D12_PIPELINE_STATE_FLAG_DYNAMIC_DEPTH_BIAS; - } - - switch (desc.cullMode) { - case RenderCullMode::NONE: - psoDesc.RasterizerState.CullMode = D3D12_CULL_MODE_NONE; - break; - case RenderCullMode::FRONT: - psoDesc.RasterizerState.CullMode = D3D12_CULL_MODE_FRONT; - break; - case RenderCullMode::BACK: - psoDesc.RasterizerState.CullMode = D3D12_CULL_MODE_BACK; - break; - default: - assert(false && "Unknown cull mode."); - return; - } - - psoDesc.DepthStencilState.DepthEnable = desc.depthEnabled; - psoDesc.DepthStencilState.DepthWriteMask = desc.depthWriteEnabled ? D3D12_DEPTH_WRITE_MASK_ALL : D3D12_DEPTH_WRITE_MASK_ZERO; - psoDesc.DepthStencilState.DepthFunc = toD3D12(desc.depthFunction); - psoDesc.NumRenderTargets = desc.renderTargetCount; - psoDesc.BlendState.AlphaToCoverageEnable = desc.alphaToCoverageEnabled; - - for (uint32_t i = 0; i < desc.renderTargetCount; i++) { - psoDesc.RTVFormats[i] = toDXGI(desc.renderTargetFormat[i]); - - const RenderBlendDesc &renderDesc = desc.renderTargetBlend[i]; - D3D12_RENDER_TARGET_BLEND_DESC &targetDesc = psoDesc.BlendState.RenderTarget[i]; - targetDesc.BlendEnable = renderDesc.blendEnabled; - targetDesc.LogicOpEnable = desc.logicOpEnabled; - targetDesc.SrcBlend = toD3D12(renderDesc.srcBlend); - targetDesc.DestBlend = toD3D12(renderDesc.dstBlend); - targetDesc.BlendOp = toD3D12(renderDesc.blendOp); - targetDesc.SrcBlendAlpha = toD3D12(renderDesc.srcBlendAlpha); - targetDesc.DestBlendAlpha = toD3D12(renderDesc.dstBlendAlpha); - targetDesc.BlendOpAlpha = toD3D12(renderDesc.blendOpAlpha); - targetDesc.LogicOp = toD3D12(desc.logicOp); - targetDesc.RenderTargetWriteMask = renderDesc.renderTargetWriteMask; - } - - psoDesc.DSVFormat = toDXGI(desc.depthTargetFormat); - - std::vector inputElements; - for (uint32_t i = 0; i < desc.inputElementsCount; i++) { - const RenderInputElement &renderElement = desc.inputElements[i]; - D3D12_INPUT_ELEMENT_DESC inputElement; - inputElement.SemanticName = renderElement.semanticName; - inputElement.SemanticIndex = renderElement.semanticIndex; - inputElement.Format = toDXGI(renderElement.format); - inputElement.InputSlot = renderElement.slotIndex; - inputElement.AlignedByteOffset = renderElement.alignedByteOffset; - - // Read the corresponding input slot to find the input classification and instance data step rate. - bool foundInputSlot = false; - D3D12_INPUT_CLASSIFICATION inputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA; - uint32_t instanceDataStepRate = 0; - for (uint32_t j = 0; j < desc.inputSlotsCount; j++) { - if (renderElement.slotIndex == desc.inputSlots[j].index) { - inputSlotClass = toD3D12(desc.inputSlots[j].classification); - instanceDataStepRate = (inputSlotClass == D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA) ? 1 : 0; - foundInputSlot = true; - break; - } - } - - assert(foundInputSlot && "The slot index specified in the input element must exist in the input slots."); - inputElement.InputSlotClass = inputSlotClass; - inputElement.InstanceDataStepRate = instanceDataStepRate; - inputElements.emplace_back(inputElement); - } - - for (uint32_t i = 0; i < desc.inputSlotsCount; i++) { - inputSlots.emplace_back(desc.inputSlots[i]); - } - - psoDesc.InputLayout = { inputElements.data(), UINT(inputElements.size()) }; - - device->d3d->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&d3d)); - } - - D3D12GraphicsPipeline::~D3D12GraphicsPipeline() { - if (d3d != nullptr) { - d3d->Release(); - } - } - - void D3D12GraphicsPipeline::setName(const std::string& name) const { - setObjectName(d3d, name); - } - - RenderPipelineProgram D3D12GraphicsPipeline::getProgram(const std::string &name) const { - assert(false && "Graphics pipelines can't retrieve shader programs."); - return RenderPipelineProgram(); - } - - // D3D12RaytracingPipeline - - D3D12RaytracingPipeline::D3D12RaytracingPipeline(D3D12Device *device, const RenderRaytracingPipelineDesc &desc, const RenderPipeline *previousPipeline) : D3D12Pipeline(device, Type::Raytracing) { - assert(desc.librariesCount > 0); - assert(desc.pipelineLayout != nullptr); - - uint32_t subobjectCount = desc.librariesCount + desc.hitGroupsCount + 8; - uint32_t exportSymbolsCount = 0; - for (uint32_t i = 0; i < desc.librariesCount; i++) { - exportSymbolsCount += desc.libraries[i].symbolsCount; - } - - assert((exportSymbolsCount > 0) && "At least one symbol must be exported from the libraries."); - - std::vector subobjects(subobjectCount); - std::vector libraryDescs(desc.librariesCount); - std::vector hitGroupDescs(desc.hitGroupsCount); - std::vector exportDescs(exportSymbolsCount); - std::vector exportNames(exportSymbolsCount); - std::vector exportRenames(exportSymbolsCount); - std::unordered_set exportAssociationSet; - D3D12_SUBOBJECT_TO_EXPORTS_ASSOCIATION subobjectToExportsAssociation; - - uint32_t subobjectIndex = 0; - uint32_t exportsIndex = 0; - for (uint32_t i = 0; i < desc.librariesCount; i++) { - uint32_t exportsIndexStart = exportsIndex; - const RenderRaytracingPipelineLibrary &renderLibrary = desc.libraries[i]; - for (uint32_t j = 0; j < renderLibrary.symbolsCount; j++) { - D3D12_EXPORT_DESC &exportDesc = exportDescs[exportsIndex]; - std::wstring &exportName = exportNames[exportsIndex]; - std::wstring &exportRename = exportRenames[exportsIndex]; - exportName = Utf8ToUtf16(std::string(renderLibrary.symbols[j].importName)); - exportRename = (renderLibrary.symbols[j].exportName != nullptr) ? Utf8ToUtf16(std::string(renderLibrary.symbols[j].exportName)) : exportName; - exportDesc.Name = exportName.c_str(); - exportDesc.ExportToRename = exportRename.c_str(); - exportDesc.Flags = D3D12_EXPORT_FLAG_NONE; - exportAssociationSet.insert(exportRename); - exportsIndex++; - } - - const D3D12Shader *libraryShader = static_cast(renderLibrary.shader); - assert(libraryShader != nullptr); - - D3D12_DXIL_LIBRARY_DESC &libraryDesc = libraryDescs[i]; - libraryDesc.DXILLibrary.pShaderBytecode = libraryShader->data; - libraryDesc.DXILLibrary.BytecodeLength = libraryShader->size; - libraryDesc.pExports = &exportDescs[exportsIndexStart]; - libraryDesc.NumExports = exportsIndex - exportsIndexStart; - - D3D12_STATE_SUBOBJECT &subobject = subobjects[subobjectIndex++]; - subobject.Type = D3D12_STATE_SUBOBJECT_TYPE_DXIL_LIBRARY; - subobject.pDesc = &libraryDescs[i]; - } - - auto fillHitGroupString = [&exportAssociationSet](LPCWSTR &dstPtr, std::wstring &dstString, const char *srcString, bool associateToSet) { - if (srcString != nullptr) { - dstString = Utf8ToUtf16(srcString); - dstPtr = dstString.c_str(); - } - else { - dstPtr = nullptr; - } - - if (associateToSet) { - exportAssociationSet.insert(dstString); - } - else { - exportAssociationSet.erase(dstString); - } - }; - - std::vector hitGroupNames(desc.hitGroupsCount * 4); - uint32_t hitGroupNameIndex = 0; - for (uint32_t i = 0; i < desc.hitGroupsCount; i++) { - const RenderRaytracingPipelineHitGroup &renderHitGroup = desc.hitGroups[i]; - assert(renderHitGroup.hitGroupName != nullptr); - - D3D12_HIT_GROUP_DESC &hitGroupDesc = hitGroupDescs[i]; - hitGroupDesc.Type = D3D12_HIT_GROUP_TYPE_TRIANGLES; - fillHitGroupString(hitGroupDesc.HitGroupExport, hitGroupNames[hitGroupNameIndex++], renderHitGroup.hitGroupName, true); - fillHitGroupString(hitGroupDesc.ClosestHitShaderImport, hitGroupNames[hitGroupNameIndex++], renderHitGroup.closestHitName, false); - fillHitGroupString(hitGroupDesc.AnyHitShaderImport, hitGroupNames[hitGroupNameIndex++], renderHitGroup.anyHitName, false); - fillHitGroupString(hitGroupDesc.IntersectionShaderImport, hitGroupNames[hitGroupNameIndex++], renderHitGroup.intersectionName, false); - - D3D12_STATE_SUBOBJECT &subobject = subobjects[subobjectIndex++]; - subobject.Type = D3D12_STATE_SUBOBJECT_TYPE_HIT_GROUP; - subobject.pDesc = &hitGroupDescs[i]; - } - - D3D12_RAYTRACING_SHADER_CONFIG shaderDesc = {}; - shaderDesc.MaxPayloadSizeInBytes = desc.maxPayloadSize; - shaderDesc.MaxAttributeSizeInBytes = desc.maxAttributeSize; - - D3D12_STATE_SUBOBJECT &shaderConfigSubobject = subobjects[subobjectIndex++]; - shaderConfigSubobject.Type = D3D12_STATE_SUBOBJECT_TYPE_RAYTRACING_SHADER_CONFIG; - shaderConfigSubobject.pDesc = &shaderDesc; - - std::vector exportPointers; - exportPointers.reserve(exportAssociationSet.size()); - for (const std::wstring &exportAssociation : exportAssociationSet) { - exportPointers.emplace_back(exportAssociation.c_str()); - } - - D3D12_SUBOBJECT_TO_EXPORTS_ASSOCIATION exportsAssociation = {}; - exportsAssociation.pExports = exportPointers.data(); - exportsAssociation.NumExports = static_cast(exportPointers.size()); - exportsAssociation.pSubobjectToAssociate = &shaderConfigSubobject; - - D3D12_STATE_SUBOBJECT &exportAssociationSubobject = subobjects[subobjectIndex++]; - exportAssociationSubobject.Type = D3D12_STATE_SUBOBJECT_TYPE_SUBOBJECT_TO_EXPORTS_ASSOCIATION; - exportAssociationSubobject.pDesc = &exportsAssociation; - - std::vector associatedSymbolsNames(exportSymbolsCount); - std::vector associatedSymbolsNamesPointers(exportSymbolsCount); - uint32_t associatedSymbolCount = 0; - for (uint32_t i = 0; i < desc.librariesCount; i++) { - const RenderRaytracingPipelineLibrary &renderLibrary = desc.libraries[i]; - for (uint32_t j = 0; j < renderLibrary.symbolsCount; j++) { - const char *symbolName = (renderLibrary.symbols[j].exportName != nullptr) ? renderLibrary.symbols[j].exportName : renderLibrary.symbols[j].importName; - associatedSymbolsNames[associatedSymbolCount] = Utf8ToUtf16(symbolName); - associatedSymbolsNamesPointers[associatedSymbolCount] = associatedSymbolsNames[associatedSymbolCount].c_str(); - associatedSymbolCount++; - } - } - - pipelineLayout = static_cast(desc.pipelineLayout); - - D3D12_STATE_SUBOBJECT &rootSignatureSubobject = subobjects[subobjectIndex++]; - rootSignatureSubobject.Type = D3D12_STATE_SUBOBJECT_TYPE_LOCAL_ROOT_SIGNATURE; - rootSignatureSubobject.pDesc = &pipelineLayout->rootSignature; - - subobjectToExportsAssociation.pExports = associatedSymbolsNamesPointers.data(); - subobjectToExportsAssociation.NumExports = associatedSymbolCount; - subobjectToExportsAssociation.pSubobjectToAssociate = &rootSignatureSubobject; - - D3D12_STATE_SUBOBJECT &rootSignatureAssocationSubobject = subobjects[subobjectIndex++]; - rootSignatureAssocationSubobject.Type = D3D12_STATE_SUBOBJECT_TYPE_SUBOBJECT_TO_EXPORTS_ASSOCIATION; - rootSignatureAssocationSubobject.pDesc = &subobjectToExportsAssociation; - - const D3D12PipelineLayout *interfaceGlobalPipelineLayout = static_cast(device->rtDummyGlobalPipelineLayout.get()); - D3D12_STATE_SUBOBJECT &globalRootSignatureSubobject = subobjects[subobjectIndex++]; - globalRootSignatureSubobject.Type = D3D12_STATE_SUBOBJECT_TYPE_GLOBAL_ROOT_SIGNATURE; - globalRootSignatureSubobject.pDesc = &interfaceGlobalPipelineLayout->rootSignature; - - const D3D12PipelineLayout *interfaceLocalPipelineLayout = static_cast(device->rtDummyLocalPipelineLayout.get()); - D3D12_STATE_SUBOBJECT &localRootSignatureSubobject = subobjects[subobjectIndex++]; - localRootSignatureSubobject.Type = D3D12_STATE_SUBOBJECT_TYPE_LOCAL_ROOT_SIGNATURE; - localRootSignatureSubobject.pDesc = &interfaceLocalPipelineLayout->rootSignature; - - D3D12_STATE_OBJECT_CONFIG stateConfig; - stateConfig.Flags = desc.stateUpdateEnabled ? D3D12_STATE_OBJECT_FLAG_ALLOW_STATE_OBJECT_ADDITIONS : D3D12_STATE_OBJECT_FLAG_NONE; - - D3D12_STATE_SUBOBJECT &stateConfigSubobject = subobjects[subobjectIndex++]; - stateConfigSubobject.Type = D3D12_STATE_SUBOBJECT_TYPE_STATE_OBJECT_CONFIG; - stateConfigSubobject.pDesc = &stateConfig; - - D3D12_RAYTRACING_PIPELINE_CONFIG pipelineConfig = {}; - pipelineConfig.MaxTraceRecursionDepth = desc.maxRecursionDepth; - - D3D12_STATE_SUBOBJECT &pipelineConfigSubobject = subobjects[subobjectIndex++]; - pipelineConfigSubobject.Type = D3D12_STATE_SUBOBJECT_TYPE_RAYTRACING_PIPELINE_CONFIG; - pipelineConfigSubobject.pDesc = &pipelineConfig; - - assert(uint32_t(subobjects.size()) == subobjectIndex); - - D3D12_STATE_OBJECT_DESC pipelineDesc = {}; - pipelineDesc.Type = D3D12_STATE_OBJECT_TYPE_RAYTRACING_PIPELINE; - pipelineDesc.pSubobjects = subobjects.data(); - pipelineDesc.NumSubobjects = UINT(subobjects.size()); - - if (desc.stateUpdateEnabled && (previousPipeline != nullptr)) { - assert(static_cast(previousPipeline)->type == Type::Raytracing); - const D3D12RaytracingPipeline *previousRaytracingPipeline = static_cast(previousPipeline); - HRESULT res = device->d3d->AddToStateObject(&pipelineDesc, previousRaytracingPipeline->stateObject, IID_PPV_ARGS(&stateObject)); - if (FAILED(res)) { - fprintf(stderr, "AddToStateObject failed with error code 0x%lX.\n", res); - return; - } - } - else { - HRESULT res = device->d3d->CreateStateObject(&pipelineDesc, IID_PPV_ARGS(&stateObject)); - if (FAILED(res)) { - fprintf(stderr, "CreateStateObject failed with error code 0x%lX.\n", res); - return; - } - } - - HRESULT res = stateObject->QueryInterface(IID_PPV_ARGS(&stateObjectProperties)); - if (FAILED(res)) { - fprintf(stderr, "QueryInterface failed with error code 0x%lX.\n", res); - return; - } - - // Cache all the programs compiled into the PSO into a name map. - programShaderIdentifiers.reserve(exportAssociationSet.size()); - for (const std::wstring &exportAssociation : exportAssociationSet) { - void *shaderIdentifier = stateObjectProperties->GetShaderIdentifier(exportAssociation.c_str()); - const std::string exportName = Utf16ToUtf8(exportAssociation); - uint32_t programIndex = uint32_t(programShaderIdentifiers.size()); - programShaderIdentifiers.emplace_back(shaderIdentifier); - nameProgramMap[exportName] = { programIndex }; - } - } - - D3D12RaytracingPipeline::~D3D12RaytracingPipeline() { - if (stateObjectProperties != nullptr) { - stateObjectProperties->Release(); - } - - if (stateObject != nullptr) { - stateObject->Release(); - } - } - - void D3D12RaytracingPipeline::setName(const std::string& name) const { - setObjectName(stateObject, name); - } - - RenderPipelineProgram D3D12RaytracingPipeline::getProgram(const std::string &name) const { - auto it = nameProgramMap.find(name); - assert((it != nameProgramMap.end()) && "Program must exist in the PSO."); - return it->second; - } - - // D3D12PipelineLayout - - D3D12PipelineLayout::D3D12PipelineLayout(D3D12Device *device, const RenderPipelineLayoutDesc &desc) { - assert(device != nullptr); - - this->device = device; - this->setCount = desc.descriptorSetDescsCount; - - thread_local std::vector rootParameters; - thread_local std::vector staticSamplers; - rootParameters.clear(); - staticSamplers.clear(); - - // Push constants will be the first root parameters of the signature. - for (uint32_t i = 0; i < desc.pushConstantRangesCount; i++) { - const RenderPushConstantRange &range = desc.pushConstantRanges[i]; - D3D12_ROOT_PARAMETER rootParameter = {}; - rootParameter.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; - rootParameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS; - rootParameter.Constants.ShaderRegister = range.binding; - rootParameter.Constants.RegisterSpace = range.set; - rootParameter.Constants.Num32BitValues = (range.size + sizeof(uint32_t) - 1) / sizeof(uint32_t); - rootParameters.emplace_back(rootParameter); - pushConstantRanges.emplace_back(range); - } - - // Figure out the total size of ranges that will be needed first. - uint32_t viewRangesCount = 0; - uint32_t samplerRangesCount = 0; - for (uint32_t i = 0; i < desc.descriptorSetDescsCount; i++) { - const RenderDescriptorSetDesc &descriptorSetDesc = desc.descriptorSetDescs[i]; - for (uint32_t j = 0; j < descriptorSetDesc.descriptorRangesCount; j++) { - const RenderDescriptorRange &renderRange = descriptorSetDesc.descriptorRanges[j]; - if (renderRange.immutableSampler != nullptr) { - continue; - } - else if (renderRange.type == RenderDescriptorRangeType::SAMPLER) { - samplerRangesCount++; - } - else { - viewRangesCount++; - } - } - } - - thread_local std::vector viewRanges; - thread_local std::vector samplerRanges; - uint32_t viewRangeIndex = 0; - uint32_t samplerRangeIndex = 0; - viewRanges.resize(viewRangesCount); - samplerRanges.resize(samplerRangesCount); - - // Descriptor sets will be created as descriptor table parameters. - for (uint32_t i = 0; i < desc.descriptorSetDescsCount; i++) { - uint32_t viewTableOffset = 0; - uint32_t viewTableSize = 0; - uint32_t samplerTableOffset = 0; - uint32_t samplerTableSize = 0; - const RenderDescriptorSetDesc &descriptorSetDesc = desc.descriptorSetDescs[i]; - for (uint32_t j = 0; j < descriptorSetDesc.descriptorRangesCount; j++) { - // D3D12 requires specifying boundless arrays by setting the descriptor count to UINT_MAX. - const RenderDescriptorRange &renderRange = descriptorSetDesc.descriptorRanges[j]; - const bool isRangeBoundless = (descriptorSetDesc.lastRangeIsBoundless && (j == (descriptorSetDesc.descriptorRangesCount - 1))); - - // Immutable samplers are converted to static samplers and filtered out of the table entirely. - if (renderRange.immutableSampler != nullptr) { - for (uint32_t k = 0; k < renderRange.count; k++) { - const D3D12Sampler *sampler = static_cast(renderRange.immutableSampler[k]); - const D3D12_SAMPLER_DESC &samplerDesc = sampler->samplerDesc; - D3D12_STATIC_SAMPLER_DESC staticSampler = {}; - staticSampler.Filter = samplerDesc.Filter; - staticSampler.AddressU = samplerDesc.AddressU; - staticSampler.AddressV = samplerDesc.AddressV; - staticSampler.AddressW = samplerDesc.AddressW; - staticSampler.MipLODBias = samplerDesc.MipLODBias; - staticSampler.MaxAnisotropy = samplerDesc.MaxAnisotropy; - staticSampler.ComparisonFunc = samplerDesc.ComparisonFunc; - staticSampler.BorderColor = toStaticBorderColor(sampler->borderColor); - staticSampler.MinLOD = samplerDesc.MinLOD; - staticSampler.MaxLOD = samplerDesc.MaxLOD; - staticSampler.ShaderRegister = renderRange.binding; - staticSampler.RegisterSpace = i; - staticSampler.ShaderVisibility = toD3D12(sampler->shaderVisibility); - staticSamplers.emplace_back(staticSampler); - } - } - // Dynamic samplers must use a different type of heap. - else if (renderRange.type == RenderDescriptorRangeType::SAMPLER) { - D3D12_DESCRIPTOR_RANGE &descriptorRange = samplerRanges[samplerRangeIndex + samplerTableSize]; - descriptorRange.RangeType = toRangeType(renderRange.type); - descriptorRange.NumDescriptors = isRangeBoundless ? UINT_MAX : renderRange.count; - descriptorRange.BaseShaderRegister = renderRange.binding; - descriptorRange.RegisterSpace = i; - descriptorRange.OffsetInDescriptorsFromTableStart = samplerTableOffset; - samplerTableSize++; - samplerTableOffset += renderRange.count; - } - else { - D3D12_DESCRIPTOR_RANGE &descriptorRange = viewRanges[viewRangeIndex + viewTableSize]; - descriptorRange.RangeType = toRangeType(renderRange.type); - descriptorRange.NumDescriptors = isRangeBoundless ? UINT_MAX : renderRange.count; - descriptorRange.BaseShaderRegister = renderRange.binding; - descriptorRange.RegisterSpace = i; - descriptorRange.OffsetInDescriptorsFromTableStart = viewTableOffset; - viewTableSize++; - viewTableOffset += renderRange.count; - } - } - - setViewRootIndices.emplace_back(uint32_t(rootParameters.size())); - - if (viewTableSize > 0) { - D3D12_ROOT_PARAMETER rootParameter = {}; - rootParameter.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; - rootParameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; - rootParameter.DescriptorTable.pDescriptorRanges = &viewRanges[viewRangeIndex]; - rootParameter.DescriptorTable.NumDescriptorRanges = viewTableSize; - rootParameters.emplace_back(rootParameter); - viewRangeIndex += viewTableSize; - } - - setSamplerRootIndices.emplace_back(uint32_t(rootParameters.size())); - - if (samplerTableSize > 0) { - D3D12_ROOT_PARAMETER rootParameter = {}; - rootParameter.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; - rootParameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; - rootParameter.DescriptorTable.pDescriptorRanges = &samplerRanges[samplerRangeIndex]; - rootParameter.DescriptorTable.NumDescriptorRanges = samplerTableSize; - rootParameters.emplace_back(rootParameter); - samplerRangeIndex += samplerTableSize; - } - } - - // Add root descriptors last. - for (uint32_t i = 0; i < desc.rootDescriptorDescsCount; i++) { - const RenderRootDescriptorDesc& rootDescriptorDesc = desc.rootDescriptorDescs[i]; - - D3D12_ROOT_PARAMETER rootParameter = {}; - rootParameter.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; - rootParameter.Descriptor.ShaderRegister = rootDescriptorDesc.shaderRegister; - rootParameter.Descriptor.RegisterSpace = rootDescriptorDesc.registerSpace; - - switch (rootDescriptorDesc.type) { - case RenderRootDescriptorType::CONSTANT_BUFFER: - rootParameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV; - break; - case RenderRootDescriptorType::SHADER_RESOURCE: - rootParameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_SRV; - break; - case RenderRootDescriptorType::UNORDERED_ACCESS: - rootParameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_UAV; - break; - default: - assert(false && "Invalid root descriptor type."); - break; - } - - rootDescriptorRootIndicesAndTypes.emplace_back(uint32_t(rootParameters.size()), rootDescriptorDesc.type); - rootParameters.push_back(rootParameter); - } - - // Store the total amount of root parameters. - rootCount = rootParameters.size(); - - // Fill root signature desc. - D3D12_ROOT_SIGNATURE_DESC rootSignatureDesc = {}; - rootSignatureDesc.Flags |= desc.isLocal ? D3D12_ROOT_SIGNATURE_FLAG_LOCAL_ROOT_SIGNATURE : D3D12_ROOT_SIGNATURE_FLAG_NONE; - rootSignatureDesc.Flags |= desc.allowInputLayout ? D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT : D3D12_ROOT_SIGNATURE_FLAG_NONE; - rootSignatureDesc.pParameters = !rootParameters.empty() ? rootParameters.data() : nullptr; - rootSignatureDesc.NumParameters = UINT(rootParameters.size()); - rootSignatureDesc.pStaticSamplers = !staticSamplers.empty() ? staticSamplers.data() : nullptr; - rootSignatureDesc.NumStaticSamplers = UINT(staticSamplers.size()); - - // Serialize the root signature. - ID3DBlob *signatureBlob; - ID3DBlob *errorBlob; - HRESULT res = D3D12SerializeRootSignature(&rootSignatureDesc, D3D_ROOT_SIGNATURE_VERSION_1_0, &signatureBlob, &errorBlob); - if (FAILED(res)) { - fprintf(stderr, "%s\n", (char *)(errorBlob->GetBufferPointer())); - return; - } - - res = device->d3d->CreateRootSignature(0, signatureBlob->GetBufferPointer(), signatureBlob->GetBufferSize(), IID_PPV_ARGS(&rootSignature)); - if (FAILED(res)) { - fprintf(stderr, "CreateRootSignature failed with error code 0x%lX.\n", res); - return; - } - } - - D3D12PipelineLayout::~D3D12PipelineLayout() { - if (rootSignature != nullptr) { - rootSignature->Release(); - } - } - - // D3D12Device - - D3D12Device::D3D12Device(D3D12Interface *renderInterface, const std::string &preferredDeviceName) { - assert(renderInterface != nullptr); - - this->renderInterface = renderInterface; - - // Detect adapter to use that will offer the best performance and features. - HRESULT res; - UINT adapterIndex = 0; - IDXGIAdapter1 *adapterOption = nullptr; - while (renderInterface->dxgiFactory->EnumAdapters1(adapterIndex++, &adapterOption) != DXGI_ERROR_NOT_FOUND) { - DXGI_ADAPTER_DESC1 adapterDesc; - adapterOption->GetDesc1(&adapterDesc); - - // Ignore remote or software adapters. - if (adapterDesc.Flags & (DXGI_ADAPTER_FLAG_REMOTE | DXGI_ADAPTER_FLAG_SOFTWARE)) { - adapterOption->Release(); - continue; - } - - ID3D12Device8 *deviceOption = nullptr; - res = D3D12CreateDevice(adapterOption, D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&deviceOption)); - if (FAILED(res)) { - adapterOption->Release(); - continue; - } - - // Determine the shader model supported by the device. -# if SM_5_1_SUPPORTED - const D3D_SHADER_MODEL supportedShaderModels[] = { D3D_SHADER_MODEL_6_0, D3D_SHADER_MODEL_5_1 }; -# else - const D3D_SHADER_MODEL supportedShaderModels[] = { D3D_SHADER_MODEL_6_0 }; -# endif - D3D12_FEATURE_DATA_SHADER_MODEL dataShaderModel = {}; - for (uint32_t i = 0; i < _countof(supportedShaderModels); i++) { - dataShaderModel.HighestShaderModel = supportedShaderModels[i]; - res = deviceOption->CheckFeatureSupport(D3D12_FEATURE_SHADER_MODEL, &dataShaderModel, sizeof(dataShaderModel)); - if (res != E_INVALIDARG) { - if (FAILED(res)) { - deviceOption->Release(); - adapterOption->Release(); - continue; - } - - break; - } - } - - // Determine if the device supports sample locations. - bool samplePositionsOption = false; - D3D12_FEATURE_DATA_D3D12_OPTIONS2 d3d12Options2 = {}; - res = deviceOption->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS2, &d3d12Options2, sizeof(d3d12Options2)); - if (SUCCEEDED(res)) { - samplePositionsOption = d3d12Options2.ProgrammableSamplePositionsTier >= D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER_1; - } - - // Determine if the device supports raytracing. - bool rtSupportOption = false; - bool rtStateUpdateSupportOption = false; - D3D12_FEATURE_DATA_D3D12_OPTIONS5 d3d12Options5 = {}; - res = deviceOption->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS5, &d3d12Options5, sizeof(d3d12Options5)); - if (SUCCEEDED(res)) { - rtSupportOption = d3d12Options5.RaytracingTier >= D3D12_RAYTRACING_TIER_1_0; - rtStateUpdateSupportOption = d3d12Options5.RaytracingTier >= D3D12_RAYTRACING_TIER_1_1; - } - - // Check if triangle fan is supported. - bool triangleFanSupportOption = false; - D3D12_FEATURE_DATA_D3D12_OPTIONS15 d3d12Options15 = {}; - res = deviceOption->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS15, &d3d12Options15, sizeof(d3d12Options15)); - if (SUCCEEDED(res)) { - triangleFanSupportOption = d3d12Options15.TriangleFanSupported; - } - - // Check if dynamic depth bias and GPU upload heap are supported. - bool dynamicDepthBiasOption = false; - bool gpuUploadHeapOption = false; - D3D12_FEATURE_DATA_D3D12_OPTIONS16 d3d12Options16 = {}; - res = deviceOption->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS16, &d3d12Options16, sizeof(d3d12Options16)); - if (SUCCEEDED(res)) { - dynamicDepthBiasOption = d3d12Options16.DynamicDepthBiasSupported; - gpuUploadHeapOption = d3d12Options16.GPUUploadHeapSupported; - } - - // Check if the architecture has UMA. - bool uma = false; - D3D12_FEATURE_DATA_ARCHITECTURE1 architecture1 = {}; - res = deviceOption->CheckFeatureSupport(D3D12_FEATURE_ARCHITECTURE1, &architecture1, sizeof(architecture1)); - if (SUCCEEDED(res)) { - uma = architecture1.UMA; - } - - // Pick this adapter and device if it has better feature support than the current one. - std::string deviceName = Utf16ToUtf8(adapterDesc.Description); - bool preferOverNothing = (adapter == nullptr) || (d3d == nullptr); - bool preferVideoMemory = adapterDesc.DedicatedVideoMemory > description.dedicatedVideoMemory; - bool preferUserChoice = preferredDeviceName == deviceName; - bool preferOption = preferOverNothing || preferVideoMemory || preferUserChoice; - if (preferOption) { - if (d3d != nullptr) { - d3d->Release(); - } - - if (adapter != nullptr) { - adapter->Release(); - } - - adapter = adapterOption; - d3d = deviceOption; - shaderModel = dataShaderModel.HighestShaderModel; - capabilities.geometryShader = true; - capabilities.raytracing = rtSupportOption; - capabilities.raytracingStateUpdate = rtStateUpdateSupportOption; - capabilities.sampleLocations = samplePositionsOption; - capabilities.triangleFan = triangleFanSupportOption; - capabilities.dynamicDepthBias = dynamicDepthBiasOption; - capabilities.uma = uma; - - // Pretend GPU Upload heaps are supported if UMA is supported, as the backend has a workaround using a custom pool for it. - capabilities.gpuUploadHeap = uma || gpuUploadHeapOption; - gpuUploadHeapFallback = uma && !gpuUploadHeapOption; - - description.name = deviceName; - description.dedicatedVideoMemory = adapterDesc.DedicatedVideoMemory; - description.vendor = RenderDeviceVendor(adapterDesc.VendorId); - - LARGE_INTEGER adapterVersion = {}; - res = adapter->CheckInterfaceSupport(__uuidof(IDXGIDevice), &adapterVersion); - if (SUCCEEDED(res)) { - description.driverVersion = adapterVersion.QuadPart; - } - - if (preferUserChoice) { - break; - } - } - else { - deviceOption->Release(); - adapterOption->Release(); - } - } - - if (d3d == nullptr) { - fprintf(stderr, "Unable to create a D3D12 device with the required features.\n"); - return; - } - - #ifdef D3D12_DEBUG_SET_STABLE_POWER_STATE - d3d->SetStablePowerState(TRUE); - #endif - - D3D12MA::ALLOCATOR_DESC allocatorDesc = {}; - allocatorDesc.pDevice = d3d; - allocatorDesc.pAdapter = adapter; - allocatorDesc.Flags = D3D12MA::ALLOCATOR_FLAG_DEFAULT_POOLS_NOT_ZEROED | - D3D12MA::ALLOCATOR_FLAG_MSAA_TEXTURES_ALWAYS_COMMITTED | D3D12MA::ALLOCATOR_FLAG_DONT_PREFER_SMALL_BUFFERS_COMMITTED; - - res = D3D12MA::CreateAllocator(&allocatorDesc, &allocator); - if (FAILED(res)) { - fprintf(stderr, "D3D12MA::CreateAllocator failed with error code 0x%lX.\n", res); - release(); - return; - } - - if (capabilities.raytracing) { - RenderPipelineLayoutDesc pipelineLayoutDesc; - rtDummyGlobalPipelineLayout = createPipelineLayout(pipelineLayoutDesc); - - pipelineLayoutDesc.isLocal = true; - rtDummyLocalPipelineLayout = createPipelineLayout(pipelineLayoutDesc); - } - -# ifdef D3D12_DEBUG_LAYER_ENABLED - // Add it to the debug layer info queue if available. - ID3D12InfoQueue *infoQueue; - res = d3d->QueryInterface(IID_PPV_ARGS(&infoQueue)); - if (SUCCEEDED(res)) { - D3D12_MESSAGE_SEVERITY severities[] = { - D3D12_MESSAGE_SEVERITY_INFO - }; - - D3D12_MESSAGE_ID denyIds[] = { - D3D12_MESSAGE_ID_COMMAND_LIST_DRAW_VERTEX_BUFFER_NOT_SET, - D3D12_MESSAGE_ID_CLEARRENDERTARGETVIEW_MISMATCHINGCLEARVALUE, - D3D12_MESSAGE_ID_CLEARDEPTHSTENCILVIEW_MISMATCHINGCLEARVALUE, - D3D12_MESSAGE_ID_DRAW_EMPTY_SCISSOR_RECTANGLE, - D3D12_MESSAGE_ID_HEAP_ADDRESS_RANGE_INTERSECTS_MULTIPLE_BUFFERS, - D3D12_MESSAGE_ID_CREATEGRAPHICSPIPELINESTATE_RENDERTARGETVIEW_NOT_SET, -# ifdef D3D12_DEBUG_LAYER_SUPRESS_SAMPLE_POSITIONS_ERROR - D3D12_MESSAGE_ID_SAMPLEPOSITIONS_MISMATCH_RECORDTIME_ASSUMEDFROMCLEAR, - D3D12_MESSAGE_ID_SAMPLEPOSITIONS_MISMATCH_DEFERRED, -# endif - }; - - D3D12_INFO_QUEUE_FILTER newFilter = {}; - newFilter.DenyList.NumSeverities = _countof(severities); - newFilter.DenyList.pSeverityList = severities; - newFilter.DenyList.NumIDs = _countof(denyIds); - newFilter.DenyList.pIDList = denyIds; - infoQueue->PushStorageFilter(&newFilter); - - infoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_CORRUPTION, true); - infoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_ERROR, D3D12_DEBUG_LAYER_BREAK_ON_ERROR); - infoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_WARNING, D3D12_DEBUG_LAYER_BREAK_ON_WARNING); - } -# endif - - // Fill capabilities. - capabilities.descriptorIndexing = true; - capabilities.scalarBlockLayout = true; - capabilities.presentWait = true; - capabilities.preferHDR = description.dedicatedVideoMemory > (512 * 1024 * 1024); - - // Create descriptor heaps allocator. - viewHeapAllocator = std::make_unique(this, ShaderDescriptorHeapSize, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); - samplerHeapAllocator = std::make_unique(this, SamplerDescriptorHeapSize, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER); - colorTargetHeapAllocator = std::make_unique(this, TargetDescriptorHeapSize, D3D12_DESCRIPTOR_HEAP_TYPE_RTV); - depthTargetHeapAllocator = std::make_unique(this, TargetDescriptorHeapSize, D3D12_DESCRIPTOR_HEAP_TYPE_DSV); - - // Create the custom upload pool that will be used as the fallback when using an UMA architecture without explicit support for GPU Upload heaps. - if (gpuUploadHeapFallback) { - RenderPoolDesc poolDesc; - poolDesc.heapType = RenderHeapType::GPU_UPLOAD; - customUploadPool = std::make_unique(this, poolDesc, true); - } - - // Create a command queue only for retrieving the timestamp frequency. Delete it immediately afterwards. - std::unique_ptr timestampCommandQueue = std::make_unique(this, RenderCommandListType::DIRECT); - res = timestampCommandQueue->d3d->GetTimestampFrequency(×tampFrequency); - if (FAILED(res)) { - fprintf(stderr, "GetTimestampFrequency failed with error code 0x%lX. Timestamps will be inaccurate.\n", res); - } - } - - D3D12Device::~D3D12Device() { - viewHeapAllocator.reset(); - samplerHeapAllocator.reset(); - rtDummyGlobalPipelineLayout.reset(); - rtDummyLocalPipelineLayout.reset(); - release(); - } - - std::unique_ptr D3D12Device::createCommandList(RenderCommandListType type) { - return std::make_unique(this, type); - } - - std::unique_ptr D3D12Device::createDescriptorSet(const RenderDescriptorSetDesc &desc) { - return std::make_unique(this, desc); - } - - std::unique_ptr D3D12Device::createShader(const void *data, uint64_t size, const char *entryPointName, RenderShaderFormat format) { - return std::make_unique(this, data, size, entryPointName, format); - } - - std::unique_ptr D3D12Device::createSampler(const RenderSamplerDesc &desc) { - return std::make_unique(this, desc); - } - - std::unique_ptr D3D12Device::createComputePipeline(const RenderComputePipelineDesc &desc) { - return std::make_unique(this, desc); - } - - std::unique_ptr D3D12Device::createGraphicsPipeline(const RenderGraphicsPipelineDesc &desc) { - return std::make_unique(this, desc); - } - - std::unique_ptr D3D12Device::createRaytracingPipeline(const RenderRaytracingPipelineDesc &desc, const RenderPipeline *previousPipeline) { - return std::make_unique(this, desc, previousPipeline); - } - - std::unique_ptr D3D12Device::createCommandQueue(RenderCommandListType type) { - return std::make_unique(this, type); - } - - std::unique_ptr D3D12Device::createBuffer(const RenderBufferDesc &desc) { - if ((desc.heapType == RenderHeapType::GPU_UPLOAD) && gpuUploadHeapFallback) { - return std::make_unique(this, customUploadPool.get(), desc); - } - else { - return std::make_unique(this, nullptr, desc); - } - } - - std::unique_ptr D3D12Device::createTexture(const RenderTextureDesc &desc) { - return std::make_unique(this, nullptr, desc); - } - - std::unique_ptr D3D12Device::createAccelerationStructure(const RenderAccelerationStructureDesc &desc) { - return std::make_unique(this, desc); - } - - std::unique_ptr D3D12Device::createPool(const RenderPoolDesc &desc) { - return std::make_unique(this, desc, gpuUploadHeapFallback); - } - - std::unique_ptr D3D12Device::createPipelineLayout(const RenderPipelineLayoutDesc &desc) { - return std::make_unique(this, desc); - } - - std::unique_ptr D3D12Device::createCommandFence() { - return std::make_unique(this); - } - - std::unique_ptr D3D12Device::createCommandSemaphore() { - return std::make_unique(this); - } - - std::unique_ptr D3D12Device::createFramebuffer(const RenderFramebufferDesc &desc) { - return std::make_unique(this, desc); - } - - std::unique_ptr D3D12Device::createQueryPool(uint32_t queryCount) { - return std::make_unique(this, queryCount); - } - - void D3D12Device::setBottomLevelASBuildInfo(RenderBottomLevelASBuildInfo &buildInfo, const RenderBottomLevelASMesh *meshes, uint32_t meshCount, bool preferFastBuild, bool preferFastTrace) { - assert(meshes != nullptr); - assert(meshCount > 0); - - buildInfo.buildData.resize(sizeof(D3D12_RAYTRACING_GEOMETRY_DESC) * meshCount, 0); - - D3D12_RAYTRACING_GEOMETRY_DESC *geometryDescs = reinterpret_cast(buildInfo.buildData.data()); - for (uint32_t i = 0; i < meshCount; i++) { - const RenderBottomLevelASMesh &mesh = meshes[i]; - const D3D12Buffer *interfaceIndexBuffer = static_cast(mesh.indexBuffer.ref); - const D3D12Buffer *interfaceVertexBuffer = static_cast(mesh.vertexBuffer.ref); - assert((interfaceIndexBuffer == nullptr) || ((interfaceIndexBuffer->desc.flags & RenderBufferFlag::ACCELERATION_STRUCTURE_INPUT) && "Acceleration structure input must be allowed on index buffer.")); - assert((interfaceVertexBuffer == nullptr) || ((interfaceVertexBuffer->desc.flags & RenderBufferFlag::ACCELERATION_STRUCTURE_INPUT) && "Acceleration structure input must be allowed on vertex buffer.")); - - D3D12_RAYTRACING_GEOMETRY_DESC &geometryDesc = geometryDescs[i]; - geometryDesc.Type = D3D12_RAYTRACING_GEOMETRY_TYPE_TRIANGLES; - geometryDesc.Flags = D3D12_RAYTRACING_GEOMETRY_FLAG_NO_DUPLICATE_ANYHIT_INVOCATION; - geometryDesc.Flags |= mesh.isOpaque ? D3D12_RAYTRACING_GEOMETRY_FLAG_OPAQUE : D3D12_RAYTRACING_GEOMETRY_FLAG_NONE; - geometryDesc.Triangles.Transform3x4 = 0; - geometryDesc.Triangles.IndexFormat = toDXGI(mesh.indexFormat); - geometryDesc.Triangles.VertexFormat = toDXGI(mesh.vertexFormat); - geometryDesc.Triangles.IndexCount = mesh.indexCount; - geometryDesc.Triangles.VertexCount = mesh.vertexCount; - geometryDesc.Triangles.IndexBuffer = (interfaceIndexBuffer != nullptr) ? (interfaceIndexBuffer->d3d->GetGPUVirtualAddress() + mesh.indexBuffer.offset) : 0; - geometryDesc.Triangles.VertexBuffer.StartAddress = (interfaceVertexBuffer != nullptr) ? (interfaceVertexBuffer->d3d->GetGPUVirtualAddress() + mesh.vertexBuffer.offset) : 0; - geometryDesc.Triangles.VertexBuffer.StrideInBytes = mesh.vertexStride; - } - - D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_INPUTS inputs = {}; - inputs.Type = D3D12_RAYTRACING_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL; - inputs.DescsLayout = D3D12_ELEMENTS_LAYOUT_ARRAY; - inputs.NumDescs = meshCount; - inputs.Flags = toRTASBuildFlags(preferFastBuild, preferFastTrace); - inputs.pGeometryDescs = geometryDescs; - - D3D12_RAYTRACING_ACCELERATION_STRUCTURE_PREBUILD_INFO info = {}; - d3d->GetRaytracingAccelerationStructurePrebuildInfo(&inputs, &info); - - buildInfo.meshCount = meshCount; - buildInfo.preferFastBuild = preferFastBuild; - buildInfo.preferFastTrace = preferFastTrace; - buildInfo.scratchSize = roundUp(info.ScratchDataSizeInBytes, D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT); - buildInfo.accelerationStructureSize = roundUp(info.ResultDataMaxSizeInBytes, D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT); - } - - void D3D12Device::setTopLevelASBuildInfo(RenderTopLevelASBuildInfo &buildInfo, const RenderTopLevelASInstance *instances, uint32_t instanceCount, bool preferFastBuild, bool preferFastTrace) { - assert(instances != nullptr); - assert(instanceCount > 0); - - uint64_t bufferSize = roundUp(sizeof(D3D12_RAYTRACING_INSTANCE_DESC) * instanceCount, D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT); - buildInfo.instancesBufferData.resize(bufferSize, 0); - - D3D12_RAYTRACING_INSTANCE_DESC *instanceDescs = reinterpret_cast(buildInfo.instancesBufferData.data()); - for (uint32_t i = 0; i < instanceCount; i++) { - const RenderTopLevelASInstance &instance = instances[i]; - const D3D12Buffer *interfaceBottomLevelAS = static_cast(instance.bottomLevelAS.ref); - assert(interfaceBottomLevelAS != nullptr); - - D3D12_RAYTRACING_INSTANCE_DESC &instanceDesc = instanceDescs[i]; - instanceDesc.InstanceID = instance.instanceID; - instanceDesc.InstanceMask = instance.instanceMask; - instanceDesc.InstanceContributionToHitGroupIndex = instance.instanceContributionToHitGroupIndex; - instanceDesc.Flags = instance.cullDisable ? D3D12_RAYTRACING_INSTANCE_FLAG_TRIANGLE_CULL_DISABLE : D3D12_RAYTRACING_INSTANCE_FLAG_NONE; - instanceDesc.AccelerationStructure = interfaceBottomLevelAS->d3d->GetGPUVirtualAddress() + instance.bottomLevelAS.offset; - memcpy(instanceDesc.Transform, instance.transform.m, sizeof(instanceDesc.Transform)); - } - - D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_INPUTS inputs = {}; - inputs.Type = D3D12_RAYTRACING_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL; - inputs.DescsLayout = D3D12_ELEMENTS_LAYOUT_ARRAY; - inputs.Flags = toRTASBuildFlags(preferFastBuild, preferFastTrace); - inputs.NumDescs = instanceCount; - - D3D12_RAYTRACING_ACCELERATION_STRUCTURE_PREBUILD_INFO info = {}; - d3d->GetRaytracingAccelerationStructurePrebuildInfo(&inputs, &info); - - buildInfo.instanceCount = instanceCount; - buildInfo.preferFastBuild = preferFastBuild; - buildInfo.preferFastTrace = preferFastTrace; - buildInfo.scratchSize = roundUp(info.ScratchDataSizeInBytes, D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT); - buildInfo.accelerationStructureSize = roundUp(info.ResultDataMaxSizeInBytes, D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT); - } - - void D3D12Device::setShaderBindingTableInfo(RenderShaderBindingTableInfo &tableInfo, const RenderShaderBindingGroups &groups, const RenderPipeline *pipeline, RenderDescriptorSet **descriptorSets, uint32_t descriptorSetCount) { - assert(pipeline != nullptr); - assert(descriptorSets != nullptr); - - const D3D12RaytracingPipeline *raytracingPipeline = static_cast(pipeline); - assert((raytracingPipeline->type == D3D12Pipeline::Type::Raytracing) && "Only raytracing pipelines can be used to build shader binding tables."); - assert((raytracingPipeline->pipelineLayout->setCount <= descriptorSetCount) && "There must be enough descriptor sets available for the pipeline."); - - uint64_t tableSize = 0; - auto setGroup = [&](RenderShaderBindingGroupInfo &groupInfo, const RenderShaderBindingGroup &renderGroup) { - groupInfo.startIndex = 0; - - if (renderGroup.pipelineProgramsCount == 0) { - groupInfo.stride = 0; - groupInfo.offset = 0; - groupInfo.size = 0; - } - else { - groupInfo.stride = roundUp(D3D12_RAYTRACING_SHADER_RECORD_BYTE_ALIGNMENT + sizeof(UINT64) * raytracingPipeline->pipelineLayout->rootCount, D3D12_RAYTRACING_SHADER_TABLE_BYTE_ALIGNMENT); - groupInfo.offset = tableSize; - groupInfo.size = groupInfo.stride * renderGroup.pipelineProgramsCount; - tableSize += groupInfo.size; - } - }; - - setGroup(tableInfo.groups.rayGen, groups.rayGen); - setGroup(tableInfo.groups.miss, groups.miss); - setGroup(tableInfo.groups.hitGroup, groups.hitGroup); - setGroup(tableInfo.groups.callable, groups.callable); - - tableSize = roundUp(tableSize, D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT); - - tableInfo.tableBufferData.clear(); - tableInfo.tableBufferData.resize(tableSize, 0); - - thread_local std::vector descriptorHandles; - descriptorHandles.clear(); - descriptorHandles.resize(raytracingPipeline->pipelineLayout->rootCount, 0); - - for (uint32_t i = 0; i < raytracingPipeline->pipelineLayout->setCount; i++) { - const D3D12DescriptorSet *interfaceDescriptorSet = static_cast(descriptorSets[i]); - if (interfaceDescriptorSet != nullptr) { - if (interfaceDescriptorSet->viewAllocation.count > 0) { - uint32_t viewRootIndex = raytracingPipeline->pipelineLayout->setViewRootIndices[i]; - descriptorHandles[viewRootIndex] = viewHeapAllocator->getGPUHandleAt(interfaceDescriptorSet->viewAllocation.offset).ptr; - } - - if (interfaceDescriptorSet->samplerAllocation.count > 0) { - uint32_t samplerRootIndex = raytracingPipeline->pipelineLayout->setSamplerRootIndices[i]; - descriptorHandles[samplerRootIndex] = samplerHeapAllocator->getGPUHandleAt(interfaceDescriptorSet->samplerAllocation.offset).ptr; - } - } - } - - auto copyGroupData = [&](RenderShaderBindingGroupInfo &groupInfo, const RenderShaderBindingGroup &renderGroup) { - for (uint32_t i = 0; i < renderGroup.pipelineProgramsCount; i++) { - void *shaderId = raytracingPipeline->programShaderIdentifiers[renderGroup.pipelinePrograms[i].programIndex]; - uint64_t tableOffset = groupInfo.offset + i * groupInfo.stride; - memcpy(&tableInfo.tableBufferData[tableOffset], shaderId, D3D12_RAYTRACING_SHADER_RECORD_BYTE_ALIGNMENT); - - if (raytracingPipeline->pipelineLayout->rootCount > 0) { - UINT64 *tableDescriptorHandles = reinterpret_cast(&tableInfo.tableBufferData[tableOffset + D3D12_RAYTRACING_SHADER_RECORD_BYTE_ALIGNMENT]); - memcpy(tableDescriptorHandles, descriptorHandles.data(), sizeof(UINT64) * raytracingPipeline->pipelineLayout->rootCount); - } - } - }; - - copyGroupData(tableInfo.groups.rayGen, groups.rayGen); - copyGroupData(tableInfo.groups.miss, groups.miss); - copyGroupData(tableInfo.groups.hitGroup, groups.hitGroup); - copyGroupData(tableInfo.groups.callable, groups.callable); - } - - const RenderDeviceCapabilities &D3D12Device::getCapabilities() const { - return capabilities; - } - - const RenderDeviceDescription &D3D12Device::getDescription() const { - return description; - } - - RenderSampleCounts D3D12Device::getSampleCountsSupported(RenderFormat format) const { - HRESULT res; - RenderSampleCounts countsSupported = RenderSampleCount::COUNT_0; - D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS multisampleLevel = {}; - RenderSampleCounts testCount = RenderSampleCount::COUNT_1; - while (testCount <= RenderSampleCount::COUNT_MAX) { - multisampleLevel.SampleCount = testCount; - multisampleLevel.Format = toDXGI(format); - - res = d3d->CheckFeatureSupport(D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS, &multisampleLevel, sizeof(multisampleLevel)); - if (SUCCEEDED(res)) { - if (multisampleLevel.NumQualityLevels > 0) { - countsSupported |= testCount; - } - } - - testCount = testCount << 1; - } - - return countsSupported; - } - - void D3D12Device::waitIdle() const { - assert(false && "Use fences to replicate wait idle behavior on D3D12."); - } - - void D3D12Device::release() { - if (d3d != nullptr) { - d3d->Release(); - d3d = nullptr; - } - - if (adapter != nullptr) { - adapter->Release(); - adapter = nullptr; - } - } - - bool D3D12Device::isValid() const { - return d3d != nullptr; - } - - // D3D12Interface - - D3D12Interface::D3D12Interface() { - // Create DXGI Factory. - UINT dxgiFactoryFlags = 0; - -# ifdef D3D12_DEBUG_LAYER_ENABLED - ID3D12Debug1 *debugController; - if (SUCCEEDED(D3D12GetDebugInterface(IID_PPV_ARGS(&debugController)))) { - debugController->EnableDebugLayer(); -# ifdef D3D12_DEBUG_LAYER_GPU_BASED_VALIDATION_ENABLED - debugController->SetEnableGPUBasedValidation(TRUE); -# endif - - // Enable additional debug layers. - dxgiFactoryFlags |= DXGI_CREATE_FACTORY_DEBUG; - } -# endif - - HRESULT res = CreateDXGIFactory2(dxgiFactoryFlags, IID_PPV_ARGS(&dxgiFactory)); - if (FAILED(res)) { - fprintf(stderr, "CreateDXGIFactory2 failed with error code 0x%lX.\n", res); - return; - } - - // Fill capabilities. - capabilities.shaderFormat = RenderShaderFormat::DXIL; - - // Fill device names. - UINT adapterIndex = 0; - IDXGIAdapter1 *adapterOption = nullptr; - while (dxgiFactory->EnumAdapters1(adapterIndex++, &adapterOption) != DXGI_ERROR_NOT_FOUND) { - DXGI_ADAPTER_DESC1 adapterDesc; - adapterOption->GetDesc1(&adapterDesc); - - // Ignore remote or software adapters. - if ((adapterDesc.Flags & (DXGI_ADAPTER_FLAG_REMOTE | DXGI_ADAPTER_FLAG_SOFTWARE)) == 0) { - deviceNames.emplace_back(Utf16ToUtf8(adapterDesc.Description)); - } - - adapterOption->Release(); - } - } - - D3D12Interface::~D3D12Interface() { - if (dxgiFactory != nullptr) { - dxgiFactory->Release(); - } - } - - std::unique_ptr D3D12Interface::createDevice(const std::string &preferredDeviceName) { - std::unique_ptr createdDevice = std::make_unique(this, preferredDeviceName); - return createdDevice->isValid() ? std::move(createdDevice) : nullptr; - } - - const RenderInterfaceCapabilities &D3D12Interface::getCapabilities() const { - return capabilities; - } - - const std::vector &D3D12Interface::getDeviceNames() const { - return deviceNames; - } - - bool D3D12Interface::isValid() const { - return dxgiFactory != nullptr; - } - - // Global creation function. - - std::unique_ptr CreateD3D12Interface() { - std::unique_ptr createdInterface = std::make_unique(); - return createdInterface->isValid() ? std::move(createdInterface) : nullptr; - } -}; diff --git a/UnleashedRecomp/gpu/rhi/plume_d3d12.h b/UnleashedRecomp/gpu/rhi/plume_d3d12.h deleted file mode 100644 index 34461c0..0000000 --- a/UnleashedRecomp/gpu/rhi/plume_d3d12.h +++ /dev/null @@ -1,481 +0,0 @@ -// -// plume -// -// Copyright (c) 2024 renderbag and contributors. All rights reserved. -// Licensed under the MIT license. See LICENSE file for details. -// - -#pragma once - -#include "plume_render_interface.h" - -#include -#include -#include - -#include -#include - -#include "D3D12MemAlloc.h" - -namespace plume { - struct D3D12Buffer; - struct D3D12CommandQueue; - struct D3D12Device; - struct D3D12GraphicsPipeline; - struct D3D12Interface; - struct D3D12Pipeline; - struct D3D12Pool; - struct D3D12PipelineLayout; - struct D3D12Texture; - - struct D3D12DescriptorHeapAllocator { - enum : uint32_t { - INVALID_OFFSET = 0xFFFFFFFFU - }; - - // Reference implementation http://diligentgraphics.com/diligent-engine/architecture/d3d12/variable-size-memory-allocations-manager/ - struct FreeBlock; - - typedef std::map OffsetFreeBlockMap; - typedef std::multimap SizeFreeBlockMap; - - struct FreeBlock { - uint32_t size; - SizeFreeBlockMap::iterator sizeMapIterator; - - FreeBlock(uint32_t size) { - this->size = size; - } - }; - - ID3D12DescriptorHeap *heap = nullptr; - uint32_t heapSize = 0; - uint32_t freeSize = 0; - D3D12Device *device = nullptr; - D3D12_CPU_DESCRIPTOR_HANDLE cpuDescriptorHandle = {}; - D3D12_GPU_DESCRIPTOR_HANDLE gpuDescriptorHandle = {}; - UINT descriptorHandleIncrement = 0; - OffsetFreeBlockMap offsetFreeBlockMap; - SizeFreeBlockMap sizeFreeBlockMap; - std::mutex allocationMutex; - - D3D12DescriptorHeapAllocator(D3D12Device *device, uint32_t heapSize, D3D12_DESCRIPTOR_HEAP_TYPE heapType); - ~D3D12DescriptorHeapAllocator(); - void addFreeBlock(uint32_t offset, uint32_t size); - uint32_t allocate(uint32_t size); - void free(uint32_t offset, uint32_t size); - D3D12_CPU_DESCRIPTOR_HANDLE getCPUHandleAt(uint32_t index) const; - D3D12_GPU_DESCRIPTOR_HANDLE getGPUHandleAt(uint32_t index) const; - }; - - struct D3D12DescriptorSet : RenderDescriptorSet { - D3D12Device *device = nullptr; - - struct HeapAllocation { - uint32_t offset = 0; - uint32_t count = 0; - }; - - HeapAllocation viewAllocation; - HeapAllocation samplerAllocation; - std::vector descriptorTypes; - std::vector descriptorHeapIndices; - uint32_t descriptorTypeMaxIndex = 0; - - D3D12DescriptorSet(D3D12Device *device, const RenderDescriptorSetDesc &desc); - ~D3D12DescriptorSet() override; - void setBuffer(uint32_t descriptorIndex, const RenderBuffer *buffer, uint64_t bufferSize, const RenderBufferStructuredView *bufferStructuredView, const RenderBufferFormattedView *bufferFormattedView) override; - void setTexture(uint32_t descriptorIndex, const RenderTexture *texture, RenderTextureLayout textureLayout, const RenderTextureView *textureView) override; - void setSampler(uint32_t descriptorIndex, const RenderSampler *sampler) override; - void setAccelerationStructure(uint32_t descriptorIndex, const RenderAccelerationStructure *accelerationStructure) override; - void setSRV(uint32_t descriptorIndex, ID3D12Resource *resource, const D3D12_SHADER_RESOURCE_VIEW_DESC *viewDesc); - void setUAV(uint32_t descriptorIndex, ID3D12Resource *resource, const D3D12_UNORDERED_ACCESS_VIEW_DESC *viewDesc); - void setCBV(uint32_t descriptorIndex, ID3D12Resource *resource, uint64_t bufferSize); - }; - - struct D3D12SwapChain : RenderSwapChain { - IDXGISwapChain3 *d3d = nullptr; - HANDLE waitableObject = 0; - D3D12CommandQueue *commandQueue = nullptr; - RenderWindow renderWindow = {}; - std::vector textures; - uint32_t textureCount = 0; - RenderFormat format = RenderFormat::UNKNOWN; - DXGI_FORMAT nativeFormat = DXGI_FORMAT_UNKNOWN; - uint32_t width = 0; - uint32_t height = 0; - uint32_t refreshRate = 0; - bool vsyncEnabled = true; - uint32_t maxFrameLatency = 0; - - D3D12SwapChain(D3D12CommandQueue *commandQueue, RenderWindow renderWindow, uint32_t textureCount, RenderFormat format, uint32_t maxFrameLatency); - ~D3D12SwapChain() override; - bool present(uint32_t textureIndex, RenderCommandSemaphore **waitSemaphores, uint32_t waitSemaphoreCount) override; - void wait() override; - bool resize() override; - bool needsResize() const override; - void setVsyncEnabled(bool vsyncEnabled) override; - bool isVsyncEnabled() const override; - uint32_t getWidth() const override; - uint32_t getHeight() const override; - RenderTexture *getTexture(uint32_t textureIndex) override; - uint32_t getTextureCount() const override; - bool acquireTexture(RenderCommandSemaphore *signalSemaphore, uint32_t *textureIndex) override; - RenderWindow getWindow() const override; - bool isEmpty() const override; - uint32_t getRefreshRate() const override; - void getWindowSize(uint32_t &dstWidth, uint32_t &dstHeight) const; - void setTextures(); - }; - - struct D3D12Framebuffer : RenderFramebuffer { - D3D12Device *device = nullptr; - uint32_t width = 0; - uint32_t height = 0; - std::vector colorTargets; - const D3D12Texture *depthTarget = nullptr; - std::vector colorHandles; - D3D12_CPU_DESCRIPTOR_HANDLE depthHandle = {}; - - D3D12Framebuffer(D3D12Device *device, const RenderFramebufferDesc &desc); - ~D3D12Framebuffer() override; - uint32_t getWidth() const override; - uint32_t getHeight() const override; - }; - - struct D3D12QueryPool : RenderQueryPool { - D3D12Device *device = nullptr; - ID3D12QueryHeap *d3d = nullptr; - std::vector results; - std::unique_ptr readbackBuffer; - - D3D12QueryPool(D3D12Device *device, uint32_t queryCount); - virtual ~D3D12QueryPool() override; - virtual void queryResults() override; - virtual const uint64_t *getResults() const override; - virtual uint32_t getCount() const override; - }; - - struct D3D12CommandList : RenderCommandList { - ID3D12GraphicsCommandList9 *d3d = nullptr; - ID3D12CommandAllocator *commandAllocator = nullptr; - D3D12Device *device = nullptr; - RenderCommandListType type = RenderCommandListType::UNKNOWN; - const D3D12Framebuffer *targetFramebuffer = nullptr; - bool targetFramebufferSamplePositionsSet = false; - bool open = false; - const D3D12PipelineLayout *activeComputePipelineLayout = nullptr; - const D3D12PipelineLayout *activeGraphicsPipelineLayout = nullptr; - const D3D12GraphicsPipeline *activeGraphicsPipeline = nullptr; - bool descriptorHeapsSet = false; - D3D12_PRIMITIVE_TOPOLOGY activeTopology = D3D_PRIMITIVE_TOPOLOGY_UNDEFINED; - bool activeSamplePositions = false; - - D3D12CommandList(D3D12Device *device, RenderCommandListType type); - ~D3D12CommandList() override; - void begin() override; - void end() override; - void barriers(RenderBarrierStages stages, const RenderBufferBarrier *bufferBarriers, uint32_t bufferBarriersCount, const RenderTextureBarrier *textureBarriers, uint32_t textureBarriersCount) override; - void dispatch(uint32_t threadGroupCountX, uint32_t threadGroupCountY, uint32_t threadGroupCountZ) override; - void traceRays(uint32_t width, uint32_t height, uint32_t depth, RenderBufferReference shaderBindingTable, const RenderShaderBindingGroupsInfo &shaderBindingGroupsInfo) override; - void drawInstanced(uint32_t vertexCountPerInstance, uint32_t instanceCount, uint32_t startVertexLocation, uint32_t startInstanceLocation) override; - void drawIndexedInstanced(uint32_t indexCountPerInstance, uint32_t instanceCount, uint32_t startIndexLocation, int32_t baseVertexLocation, uint32_t startInstanceLocation) override; - void setPipeline(const RenderPipeline *pipeline) override; - void setComputePipelineLayout(const RenderPipelineLayout *pipelineLayout) override; - void setComputePushConstants(uint32_t rangeIndex, const void *data, uint32_t offset = 0, uint32_t size = 0) override; - void setComputeDescriptorSet(RenderDescriptorSet *descriptorSet, uint32_t setIndex) override; - void setGraphicsPipelineLayout(const RenderPipelineLayout *pipelineLayout) override; - void setGraphicsPushConstants(uint32_t rangeIndex, const void *data, uint32_t offset = 0, uint32_t size = 0) override; - void setGraphicsDescriptorSet(RenderDescriptorSet *descriptorSet, uint32_t setIndex) override; - void setGraphicsRootDescriptor(RenderBufferReference bufferReference, uint32_t rootDescriptorIndex) override; - void setRaytracingPipelineLayout(const RenderPipelineLayout *pipelineLayout) override; - void setRaytracingPushConstants(uint32_t rangeIndex, const void *data, uint32_t offset = 0, uint32_t size = 0) override; - void setRaytracingDescriptorSet(RenderDescriptorSet *descriptorSet, uint32_t setIndex) override; - void setIndexBuffer(const RenderIndexBufferView *view) override; - void setVertexBuffers(uint32_t startSlot, const RenderVertexBufferView *views, uint32_t viewCount, const RenderInputSlot *inputSlots) override; - void setViewports(const RenderViewport *viewports, uint32_t count) override; - void setScissors(const RenderRect *scissorRects, uint32_t count) override; - void setFramebuffer(const RenderFramebuffer *framebuffer) override; - void setDepthBias(float depthBias, float depthBiasClamp, float slopeScaledDepthBias) override; - void clearColor(uint32_t attachmentIndex, RenderColor colorValue, const RenderRect *clearRects, uint32_t clearRectsCount) override; - void clearDepth(bool clearDepth, float depthValue, const RenderRect *clearRects, uint32_t clearRectsCount) override; - void copyBufferRegion(RenderBufferReference dstBuffer, RenderBufferReference srcBuffer, uint64_t size) override; - void copyTextureRegion(const RenderTextureCopyLocation &dstLocation, const RenderTextureCopyLocation &srcLocation, uint32_t dstX, uint32_t dstY, uint32_t dstZ, const RenderBox *srcBox) override; - void copyBuffer(const RenderBuffer *dstBuffer, const RenderBuffer *srcBuffer) override; - void copyTexture(const RenderTexture *dstTexture, const RenderTexture *srcTexture) override; - void resolveTexture(const RenderTexture *dstTexture, const RenderTexture *srcTexture) override; - void resolveTextureRegion(const RenderTexture *dstTexture, uint32_t dstX, uint32_t dstY, const RenderTexture *srcTexture, const RenderRect *srcRect, RenderResolveMode resolveMode) override; - void buildBottomLevelAS(const RenderAccelerationStructure *dstAccelerationStructure, RenderBufferReference scratchBuffer, const RenderBottomLevelASBuildInfo &buildInfo) override; - void buildTopLevelAS(const RenderAccelerationStructure *dstAccelerationStructure, RenderBufferReference scratchBuffer, RenderBufferReference instancesBuffer, const RenderTopLevelASBuildInfo &buildInfo) override; - void discardTexture(const RenderTexture* texture) override; - void resetQueryPool(const RenderQueryPool *queryPool, uint32_t queryFirstIndex, uint32_t queryCount) override; - void writeTimestamp(const RenderQueryPool *queryPool, uint32_t queryIndex) override; - void checkDescriptorHeaps(); - void notifyDescriptorHeapWasChangedExternally(); - void checkTopology(); - void checkFramebufferSamplePositions(); - void setSamplePositions(const RenderTexture *texture); - void resetSamplePositions(); - void setDescriptorSet(const D3D12PipelineLayout *activePipelineLayout, RenderDescriptorSet *descriptorSet, uint32_t setIndex, bool setCompute); - void setRootDescriptorTable(D3D12DescriptorHeapAllocator *heapAllocator, D3D12DescriptorSet::HeapAllocation &heapAllocation, uint32_t rootIndex, bool setCompute); - void setRootDescriptor(const D3D12PipelineLayout *activePipelineLayout, RenderBufferReference bufferReference, uint32_t setIndex, bool setCompute); - }; - - struct D3D12CommandFence : RenderCommandFence { - ID3D12Fence *d3d = nullptr; - D3D12Device *device = nullptr; - HANDLE fenceEvent = 0; - UINT64 fenceValue = 0; - - D3D12CommandFence(D3D12Device *device); - ~D3D12CommandFence() override; - }; - - struct D3D12CommandSemaphore : RenderCommandSemaphore { - ID3D12Fence *d3d = nullptr; - D3D12Device *device = nullptr; - UINT64 semaphoreValue = 0; - - D3D12CommandSemaphore(D3D12Device *device); - ~D3D12CommandSemaphore() override; - }; - - struct D3D12CommandQueue : RenderCommandQueue { - ID3D12CommandQueue *d3d = nullptr; - D3D12Device *device = nullptr; - RenderCommandListType type = RenderCommandListType::UNKNOWN; - - D3D12CommandQueue(D3D12Device *device, RenderCommandListType type); - ~D3D12CommandQueue() override; - std::unique_ptr createSwapChain(RenderWindow renderWindow, uint32_t textureCount, RenderFormat format, uint32_t newFrameLatency) override; - void executeCommandLists(const RenderCommandList **commandLists, uint32_t commandListCount, RenderCommandSemaphore **waitSemaphores, uint32_t waitSemaphoreCount, RenderCommandSemaphore **signalSemaphores, uint32_t signalSemaphoreCount, RenderCommandFence *signalFence) override; - void waitForCommandFence(RenderCommandFence *fence) override; - }; - - struct D3D12Buffer : RenderBuffer { - ID3D12Resource *d3d = nullptr; - D3D12_RESOURCE_STATES resourceStates = D3D12_RESOURCE_STATE_COMMON; - D3D12Device *device = nullptr; - D3D12MA::Allocation *allocation = nullptr; - D3D12Pool *pool = nullptr; - RenderBufferDesc desc; - - D3D12Buffer() = default; - D3D12Buffer(D3D12Device *device, D3D12Pool *pool, const RenderBufferDesc &desc); - ~D3D12Buffer() override; - void *map(uint32_t subresource, const RenderRange *readRange) override; - void unmap(uint32_t subresource, const RenderRange *writtenRange) override; - std::unique_ptr createBufferFormattedView(RenderFormat format) override; - void setName(const std::string &name) override; - uint64_t getDeviceAddress() const override; - }; - - struct D3D12BufferFormattedView : RenderBufferFormattedView { - RenderFormat format = RenderFormat::UNKNOWN; - D3D12Buffer *buffer = nullptr; - - D3D12BufferFormattedView(D3D12Buffer *buffer, RenderFormat format); - ~D3D12BufferFormattedView() override; - }; - - struct D3D12Texture : RenderTexture { - ID3D12Resource *d3d = nullptr; - D3D12_RESOURCE_STATES resourceStates = D3D12_RESOURCE_STATE_COMMON; - RenderTextureLayout layout = RenderTextureLayout::UNKNOWN; - D3D12Device *device = nullptr; - D3D12MA::Allocation *allocation = nullptr; - D3D12Pool *pool = nullptr; - RenderTextureDesc desc; - uint32_t targetAllocatorOffset = 0; - uint32_t targetEntryCount = 0; - bool targetHeapDepth = false; - - D3D12Texture() = default; - D3D12Texture(D3D12Device *device, D3D12Pool *pool, const RenderTextureDesc &desc); - ~D3D12Texture() override; - std::unique_ptr createTextureView(const RenderTextureViewDesc &desc) override; - void setName(const std::string &name) override; - void createRenderTargetHeap(); - void createDepthStencilHeap(); - void releaseTargetHeap(); - }; - - struct D3D12TextureView : RenderTextureView { - DXGI_FORMAT format = DXGI_FORMAT_UNKNOWN; - D3D12Texture *texture = nullptr; - RenderTextureViewDimension dimension = RenderTextureViewDimension::UNKNOWN; - uint32_t mipLevels = 0; - uint32_t mipSlice = 0; - uint32_t shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; - - D3D12TextureView(D3D12Texture *texture, const RenderTextureViewDesc &desc); - ~D3D12TextureView() override; - }; - - struct D3D12AccelerationStructure :RenderAccelerationStructure { - D3D12Device *device = nullptr; - const D3D12Buffer *buffer = nullptr; - uint64_t offset = 0; - uint64_t size = 0; - RenderAccelerationStructureType type = RenderAccelerationStructureType::UNKNOWN; - - D3D12AccelerationStructure(D3D12Device *device, const RenderAccelerationStructureDesc &desc); - ~D3D12AccelerationStructure() override; - }; - - struct D3D12Pool : RenderPool { - D3D12MA::Pool *d3d = nullptr; - D3D12Device *device = nullptr; - RenderPoolDesc desc; - - D3D12Pool(D3D12Device *device, const RenderPoolDesc &desc, bool gpuUploadHeapFallback); - ~D3D12Pool() override; - std::unique_ptr createBuffer(const RenderBufferDesc &desc) override; - std::unique_ptr createTexture(const RenderTextureDesc &desc) override; - }; - - struct D3D12Shader : RenderShader { - const void* data = nullptr; - uint64_t size = 0; - std::string entryPointName; - D3D12Device *device = nullptr; - RenderShaderFormat format = RenderShaderFormat::UNKNOWN; - - D3D12Shader(D3D12Device *device, const void *data, uint64_t size, const char *entryPointName, RenderShaderFormat format); - ~D3D12Shader() override; - }; - - struct D3D12Sampler : RenderSampler { - D3D12_SAMPLER_DESC samplerDesc = {}; - D3D12Device *device = nullptr; - RenderBorderColor borderColor = RenderBorderColor::UNKNOWN; - RenderShaderVisibility shaderVisibility = RenderShaderVisibility::UNKNOWN; - - D3D12Sampler(D3D12Device *device, const RenderSamplerDesc &desc); - ~D3D12Sampler() override; - }; - - struct D3D12Pipeline : RenderPipeline { - enum class Type { - Unknown, - Compute, - Graphics, - Raytracing - }; - - D3D12Device *device = nullptr; - Type type = Type::Unknown; - - D3D12Pipeline(D3D12Device *device, Type type); - virtual ~D3D12Pipeline() override; - }; - - struct D3D12ComputePipeline : D3D12Pipeline { - ID3D12PipelineState *d3d = nullptr; - - D3D12ComputePipeline(D3D12Device *device, const RenderComputePipelineDesc &desc); - ~D3D12ComputePipeline() override; - virtual void setName(const std::string& name) const override; - virtual RenderPipelineProgram getProgram(const std::string &name) const override; - }; - - struct D3D12GraphicsPipeline : D3D12Pipeline { - ID3D12PipelineState *d3d = nullptr; - std::vector inputSlots; - D3D12_PRIMITIVE_TOPOLOGY topology = D3D_PRIMITIVE_TOPOLOGY_UNDEFINED; - - D3D12GraphicsPipeline(D3D12Device *device, const RenderGraphicsPipelineDesc &desc); - ~D3D12GraphicsPipeline() override; - virtual void setName(const std::string& name) const override; - virtual RenderPipelineProgram getProgram(const std::string &name) const override; - }; - - struct D3D12RaytracingPipeline : D3D12Pipeline { - ID3D12StateObject *stateObject = nullptr; - ID3D12StateObjectProperties *stateObjectProperties = nullptr; - std::vector programShaderIdentifiers; - std::unordered_map nameProgramMap; - const D3D12PipelineLayout *pipelineLayout = nullptr; - - D3D12RaytracingPipeline(D3D12Device *device, const RenderRaytracingPipelineDesc &desc, const RenderPipeline *previousPipeline); - ~D3D12RaytracingPipeline() override; - virtual void setName(const std::string& name) const override; - virtual RenderPipelineProgram getProgram(const std::string &name) const override; - }; - - struct D3D12PipelineLayout : RenderPipelineLayout { - ID3D12RootSignature *rootSignature = nullptr; - D3D12Device *device = nullptr; - std::vector pushConstantRanges; - std::vector setViewRootIndices; - std::vector setSamplerRootIndices; - std::vector> rootDescriptorRootIndicesAndTypes; - uint32_t setCount = 0; - uint32_t rootCount = 0; - - D3D12PipelineLayout(D3D12Device *device, const RenderPipelineLayoutDesc &desc); - ~D3D12PipelineLayout() override; - }; - - struct D3D12Device : RenderDevice { - ID3D12Device8 *d3d = nullptr; - D3D12Interface *renderInterface = nullptr; - IDXGIAdapter1 *adapter = nullptr; - D3D12MA::Allocator *allocator = nullptr; - D3D_SHADER_MODEL shaderModel = D3D_SHADER_MODEL(0); - std::unique_ptr rtDummyGlobalPipelineLayout; - std::unique_ptr rtDummyLocalPipelineLayout; - std::unique_ptr viewHeapAllocator; - std::unique_ptr samplerHeapAllocator; - std::unique_ptr colorTargetHeapAllocator; - std::unique_ptr depthTargetHeapAllocator; - std::unique_ptr customUploadPool; - RenderDeviceCapabilities capabilities; - RenderDeviceDescription description; - uint64_t timestampFrequency = 1; - bool gpuUploadHeapFallback = false; - - D3D12Device(D3D12Interface *renderInterface, const std::string &preferredDeviceName); - ~D3D12Device() override; - std::unique_ptr createCommandList(RenderCommandListType type) override; - std::unique_ptr createDescriptorSet(const RenderDescriptorSetDesc &desc) override; - std::unique_ptr createShader(const void *data, uint64_t size, const char *entryPointName, RenderShaderFormat format) override; - std::unique_ptr createSampler(const RenderSamplerDesc &desc) override; - std::unique_ptr createComputePipeline(const RenderComputePipelineDesc &desc) override; - std::unique_ptr createGraphicsPipeline(const RenderGraphicsPipelineDesc &desc) override; - std::unique_ptr createRaytracingPipeline(const RenderRaytracingPipelineDesc &desc, const RenderPipeline *previousPipeline) override; - std::unique_ptr createCommandQueue(RenderCommandListType type) override; - std::unique_ptr createBuffer(const RenderBufferDesc &desc) override; - std::unique_ptr createTexture(const RenderTextureDesc &desc) override; - std::unique_ptr createAccelerationStructure(const RenderAccelerationStructureDesc &desc) override; - std::unique_ptr createPool(const RenderPoolDesc &desc) override; - std::unique_ptr createPipelineLayout(const RenderPipelineLayoutDesc &desc) override; - std::unique_ptr createCommandFence() override; - std::unique_ptr createCommandSemaphore() override; - std::unique_ptr createFramebuffer(const RenderFramebufferDesc &desc) override; - std::unique_ptr createQueryPool(uint32_t queryCount) override; - void setBottomLevelASBuildInfo(RenderBottomLevelASBuildInfo &buildInfo, const RenderBottomLevelASMesh *meshes, uint32_t meshCount, bool preferFastBuild, bool preferFastTrace) override; - void setTopLevelASBuildInfo(RenderTopLevelASBuildInfo &buildInfo, const RenderTopLevelASInstance *instances, uint32_t instanceCount, bool preferFastBuild, bool preferFastTrace) override; - void setShaderBindingTableInfo(RenderShaderBindingTableInfo &tableInfo, const RenderShaderBindingGroups &groups, const RenderPipeline *pipeline, RenderDescriptorSet **descriptorSets, uint32_t descriptorSetCount) override; - const RenderDeviceCapabilities &getCapabilities() const override; - const RenderDeviceDescription &getDescription() const override; - RenderSampleCounts getSampleCountsSupported(RenderFormat format) const override; - void waitIdle() const override; - void release(); - bool isValid() const; - }; - - struct D3D12Interface : RenderInterface { - IDXGIFactory4 *dxgiFactory = nullptr; - RenderInterfaceCapabilities capabilities; - std::vector deviceNames; - - D3D12Interface(); - ~D3D12Interface() override; - std::unique_ptr createDevice(const std::string &preferredDeviceName) override; - const RenderInterfaceCapabilities &getCapabilities() const override; - const std::vector &getDeviceNames() const override; - bool isValid() const; - }; -}; diff --git a/UnleashedRecomp/gpu/rhi/plume_render_interface.h b/UnleashedRecomp/gpu/rhi/plume_render_interface.h deleted file mode 100644 index e62db05..0000000 --- a/UnleashedRecomp/gpu/rhi/plume_render_interface.h +++ /dev/null @@ -1,262 +0,0 @@ -// -// plume -// -// Copyright (c) 2024 renderbag and contributors. All rights reserved. -// Licensed under the MIT license. See LICENSE file for details. -// - -#pragma once - -#include - -#include "plume_render_interface_types.h" - -namespace plume { - // Interfaces. - - struct RenderBufferFormattedView { - virtual ~RenderBufferFormattedView() { } - }; - - struct RenderBuffer { - virtual ~RenderBuffer() { } - virtual void *map(uint32_t subresource = 0, const RenderRange *readRange = nullptr) = 0; - virtual void unmap(uint32_t subresource = 0, const RenderRange *writtenRange = nullptr) = 0; - virtual std::unique_ptr createBufferFormattedView(RenderFormat format) = 0; - virtual void setName(const std::string &name) = 0; - virtual uint64_t getDeviceAddress() const = 0; - - // Concrete implementation shortcuts. - inline RenderBufferReference at(uint64_t offset) const { - return RenderBufferReference(this, offset); - } - }; - - struct RenderTextureView { - virtual ~RenderTextureView() { } - }; - - struct RenderTexture { - virtual ~RenderTexture() { } - virtual std::unique_ptr createTextureView(const RenderTextureViewDesc &desc) = 0; - virtual void setName(const std::string &name) = 0; - }; - - struct RenderAccelerationStructure { - virtual ~RenderAccelerationStructure() { } - }; - - struct RenderShader { - virtual ~RenderShader() { } - }; - - struct RenderSampler { - virtual ~RenderSampler() { } - }; - - struct RenderPipeline { - virtual ~RenderPipeline() { } - virtual void setName(const std::string& name) const = 0; - virtual RenderPipelineProgram getProgram(const std::string &name) const = 0; - }; - - struct RenderPipelineLayout { - virtual ~RenderPipelineLayout() { } - }; - - struct RenderCommandFence { - virtual ~RenderCommandFence() { } - }; - - struct RenderCommandSemaphore { - virtual ~RenderCommandSemaphore() { } - }; - - struct RenderDescriptorSet { - // Descriptor indices correspond to the index assuming the descriptor set is one contiguous array. They DO NOT correspond to the bindings, which can be sparse. - // User code should derive these indices on its own by looking at the order the bindings were assigned during set creation along with the descriptor count and - // assume it was all allocated in one contiguous array. This allows efficient mapping between Vulkan and D3D12's descriptor models. - - virtual ~RenderDescriptorSet() { } - virtual void setBuffer(uint32_t descriptorIndex, const RenderBuffer *buffer, uint64_t bufferSize = 0, const RenderBufferStructuredView *bufferStructuredView = nullptr, const RenderBufferFormattedView *bufferFormattedView = nullptr) = 0; - virtual void setTexture(uint32_t descriptorIndex, const RenderTexture *texture, RenderTextureLayout textureLayout, const RenderTextureView *textureView = nullptr) = 0; - virtual void setSampler(uint32_t descriptorIndex, const RenderSampler *sampler) = 0; - virtual void setAccelerationStructure(uint32_t descriptorIndex, const RenderAccelerationStructure *accelerationStructure) = 0; - }; - - struct RenderSwapChain { - virtual ~RenderSwapChain() { } - virtual bool present(uint32_t textureIndex, RenderCommandSemaphore **waitSemaphores, uint32_t waitSemaphoreCount) = 0; - virtual void wait() = 0; - virtual bool resize() = 0; - virtual bool needsResize() const = 0; - virtual void setVsyncEnabled(bool vsyncEnabled) = 0; - virtual bool isVsyncEnabled() const = 0; - virtual uint32_t getWidth() const = 0; - virtual uint32_t getHeight() const = 0; - virtual RenderTexture *getTexture(uint32_t textureIndex) = 0; - virtual uint32_t getTextureCount() const = 0; - virtual bool acquireTexture(RenderCommandSemaphore *signalSemaphore, uint32_t *textureIndex) = 0; - virtual RenderWindow getWindow() const = 0; - virtual bool isEmpty() const = 0; - - // Only valid if displayTiming is enabled in capabilities. - virtual uint32_t getRefreshRate() const = 0; - }; - - struct RenderFramebuffer { - virtual ~RenderFramebuffer() { } - virtual uint32_t getWidth() const = 0; - virtual uint32_t getHeight() const = 0; - }; - - struct RenderCommandList { - virtual ~RenderCommandList() { } - virtual void begin() = 0; - virtual void end() = 0; - virtual void barriers(RenderBarrierStages stages, const RenderBufferBarrier *bufferBarriers, uint32_t bufferBarriersCount, const RenderTextureBarrier *textureBarriers, uint32_t textureBarriersCount) = 0; - virtual void dispatch(uint32_t threadGroupCountX, uint32_t threadGroupCountY, uint32_t threadGroupCountZ) = 0; - virtual void traceRays(uint32_t width, uint32_t height, uint32_t depth, RenderBufferReference shaderBindingTable, const RenderShaderBindingGroupsInfo &shaderBindingGroupsInfo) = 0; - virtual void drawInstanced(uint32_t vertexCountPerInstance, uint32_t instanceCount, uint32_t startVertexLocation, uint32_t startInstanceLocation) = 0; - virtual void drawIndexedInstanced(uint32_t indexCountPerInstance, uint32_t instanceCount, uint32_t startIndexLocation, int32_t baseVertexLocation, uint32_t startInstanceLocation) = 0; - virtual void setPipeline(const RenderPipeline *pipeline) = 0; - virtual void setComputePipelineLayout(const RenderPipelineLayout *pipelineLayout) = 0; - virtual void setComputePushConstants(uint32_t rangeIndex, const void *data, uint32_t offset = 0, uint32_t size = 0) = 0; - virtual void setComputeDescriptorSet(RenderDescriptorSet *descriptorSet, uint32_t setIndex) = 0; - virtual void setGraphicsPipelineLayout(const RenderPipelineLayout *pipelineLayout) = 0; - virtual void setGraphicsPushConstants(uint32_t rangeIndex, const void *data, uint32_t offset = 0, uint32_t size = 0) = 0; - virtual void setGraphicsDescriptorSet(RenderDescriptorSet *descriptorSet, uint32_t setIndex) = 0; - virtual void setGraphicsRootDescriptor(RenderBufferReference bufferReference, uint32_t rootDescriptorIndex) = 0; - virtual void setRaytracingPipelineLayout(const RenderPipelineLayout *pipelineLayout) = 0; - virtual void setRaytracingPushConstants(uint32_t rangeIndex, const void *data, uint32_t offset = 0, uint32_t size = 0) = 0; - virtual void setRaytracingDescriptorSet(RenderDescriptorSet *descriptorSet, uint32_t setIndex) = 0; - virtual void setIndexBuffer(const RenderIndexBufferView *view) = 0; - virtual void setVertexBuffers(uint32_t startSlot, const RenderVertexBufferView *views, uint32_t viewCount, const RenderInputSlot *inputSlots) = 0; - virtual void setViewports(const RenderViewport *viewports, uint32_t count) = 0; - virtual void setScissors(const RenderRect *scissorRects, uint32_t count) = 0; - virtual void setFramebuffer(const RenderFramebuffer *framebuffer) = 0; - virtual void setDepthBias(float depthBias, float depthBiasClamp, float slopeScaledDepthBias) = 0; - virtual void clearColor(uint32_t attachmentIndex = 0, RenderColor colorValue = RenderColor(), const RenderRect *clearRects = nullptr, uint32_t clearRectsCount = 0) = 0; - virtual void clearDepth(bool clearDepth = true, float depthValue = 1.0f, const RenderRect *clearRects = nullptr, uint32_t clearRectsCount = 0) = 0; - virtual void copyBufferRegion(RenderBufferReference dstBuffer, RenderBufferReference srcBuffer, uint64_t size) = 0; - virtual void copyTextureRegion(const RenderTextureCopyLocation &dstLocation, const RenderTextureCopyLocation &srcLocation, uint32_t dstX = 0, uint32_t dstY = 0, uint32_t dstZ = 0, const RenderBox *srcBox = nullptr) = 0; - virtual void copyBuffer(const RenderBuffer *dstBuffer, const RenderBuffer *srcBuffer) = 0; - virtual void copyTexture(const RenderTexture *dstTexture, const RenderTexture *srcTexture) = 0; - virtual void resolveTexture(const RenderTexture *dstTexture, const RenderTexture *srcTexture) = 0; - virtual void resolveTextureRegion(const RenderTexture *dstTexture, uint32_t dstX, uint32_t dstY, const RenderTexture *srcTexture, const RenderRect *srcRect = nullptr, RenderResolveMode resolveMode = RenderResolveMode::AVERAGE) = 0; - virtual void buildBottomLevelAS(const RenderAccelerationStructure *dstAccelerationStructure, RenderBufferReference scratchBuffer, const RenderBottomLevelASBuildInfo &buildInfo) = 0; - virtual void buildTopLevelAS(const RenderAccelerationStructure *dstAccelerationStructure, RenderBufferReference scratchBuffer, RenderBufferReference instancesBuffer, const RenderTopLevelASBuildInfo &buildInfo) = 0; - virtual void discardTexture(const RenderTexture* texture) = 0; // D3D12 only. - virtual void resetQueryPool(const RenderQueryPool *queryPool, uint32_t queryFirstIndex, uint32_t queryCount) = 0; - virtual void writeTimestamp(const RenderQueryPool *queryPool, uint32_t queryIndex) = 0; - - // Concrete implementation shortcuts. - inline void barriers(RenderBarrierStages stages, const RenderBufferBarrier &barrier) { - barriers(stages, &barrier, 1, nullptr, 0); - } - - inline void barriers(RenderBarrierStages stages, const RenderTextureBarrier &barrier) { - barriers(stages, nullptr, 0, &barrier, 1); - } - - inline void barriers(RenderBarrierStages stages, const RenderBufferBarrier &bufferBarrier, const RenderTextureBarrier &textureBarrier) { - barriers(stages, &bufferBarrier, 1, &textureBarrier, 1); - } - - inline void barriers(RenderBarrierStages stages, const RenderBufferBarrier *bufferBarriers, uint32_t bufferBarriersCount) { - barriers(stages, bufferBarriers, bufferBarriersCount, nullptr, 0); - } - - inline void barriers(RenderBarrierStages stages, const std::vector &bufferBarriers) { - barriers(stages, bufferBarriers.data(), uint32_t(bufferBarriers.size()), nullptr, 0); - } - - inline void barriers(RenderBarrierStages stages, const RenderTextureBarrier *textureBarriers, uint32_t textureBarriersCount) { - barriers(stages, nullptr, 0, textureBarriers, textureBarriersCount); - } - - inline void barriers(RenderBarrierStages stages, const std::vector &textureBarriers) { - barriers(stages, nullptr, 0, textureBarriers.data(), uint32_t(textureBarriers.size())); - } - - inline void barriers(RenderBarrierStages stages, const std::vector &bufferBarriers, const std::vector &textureBarriers) { - barriers(stages, bufferBarriers.data(), uint32_t(bufferBarriers.size()), textureBarriers.data(), uint32_t(textureBarriers.size())); - } - - inline void setViewports(const RenderViewport &viewport) { - setViewports(&viewport, 1); - } - - inline void setScissors(const RenderRect &scissorRect) { - setScissors(&scissorRect, 1); - } - }; - - struct RenderCommandQueue { - virtual ~RenderCommandQueue() { } - virtual std::unique_ptr createSwapChain(RenderWindow renderWindow, uint32_t textureCount, RenderFormat format, uint32_t maxFrameLatency) = 0; - virtual void executeCommandLists(const RenderCommandList **commandLists, uint32_t commandListCount, RenderCommandSemaphore **waitSemaphores = nullptr, uint32_t waitSemaphoreCount = 0, RenderCommandSemaphore **signalSemaphores = nullptr, uint32_t signalSemaphoreCount = 0, RenderCommandFence *signalFence = nullptr) = 0; - virtual void waitForCommandFence(RenderCommandFence *fence) = 0; - - // Concrete implementation shortcuts. - inline void executeCommandLists(const RenderCommandList *commandList, RenderCommandFence *signalFence = nullptr) { - executeCommandLists(commandList != nullptr ? &commandList : nullptr, commandList != nullptr ? 1 : 0, nullptr, 0, nullptr, 0, signalFence); - } - }; - - struct RenderPool { - virtual ~RenderPool() { } - virtual std::unique_ptr createBuffer(const RenderBufferDesc &desc) = 0; - virtual std::unique_ptr createTexture(const RenderTextureDesc &desc) = 0; - }; - - struct RenderQueryPool { - virtual ~RenderQueryPool() { } - virtual void queryResults() = 0; - virtual const uint64_t *getResults() const = 0; - virtual uint32_t getCount() const = 0; - }; - - struct RenderDevice { - virtual ~RenderDevice() { } - virtual std::unique_ptr createCommandList(RenderCommandListType type) = 0; - virtual std::unique_ptr createDescriptorSet(const RenderDescriptorSetDesc &desc) = 0; - virtual std::unique_ptr createShader(const void *data, uint64_t size, const char *entryPointName, RenderShaderFormat format) = 0; - virtual std::unique_ptr createSampler(const RenderSamplerDesc &desc) = 0; - virtual std::unique_ptr createComputePipeline(const RenderComputePipelineDesc &desc) = 0; - virtual std::unique_ptr createGraphicsPipeline(const RenderGraphicsPipelineDesc &desc) = 0; - virtual std::unique_ptr createRaytracingPipeline(const RenderRaytracingPipelineDesc &desc, const RenderPipeline *previousPipeline = nullptr) = 0; - virtual std::unique_ptr createCommandQueue(RenderCommandListType type) = 0; - virtual std::unique_ptr createBuffer(const RenderBufferDesc &desc) = 0; - virtual std::unique_ptr createTexture(const RenderTextureDesc &desc) = 0; - virtual std::unique_ptr createAccelerationStructure(const RenderAccelerationStructureDesc &desc) = 0; - virtual std::unique_ptr createPool(const RenderPoolDesc &desc) = 0; - virtual std::unique_ptr createPipelineLayout(const RenderPipelineLayoutDesc &desc) = 0; - virtual std::unique_ptr createCommandFence() = 0; - virtual std::unique_ptr createCommandSemaphore() = 0; - virtual std::unique_ptr createFramebuffer(const RenderFramebufferDesc &desc) = 0; - virtual std::unique_ptr createQueryPool(uint32_t queryCount) = 0; - virtual void setBottomLevelASBuildInfo(RenderBottomLevelASBuildInfo &buildInfo, const RenderBottomLevelASMesh *meshes, uint32_t meshCount, bool preferFastBuild = true, bool preferFastTrace = false) = 0; - virtual void setTopLevelASBuildInfo(RenderTopLevelASBuildInfo &buildInfo, const RenderTopLevelASInstance *instances, uint32_t instanceCount, bool preferFastBuild = true, bool preferFastTrace = false) = 0; - virtual void setShaderBindingTableInfo(RenderShaderBindingTableInfo &tableInfo, const RenderShaderBindingGroups &groups, const RenderPipeline *pipeline, RenderDescriptorSet **descriptorSets, uint32_t descriptorSetCount) = 0; - virtual const RenderDeviceCapabilities &getCapabilities() const = 0; - virtual const RenderDeviceDescription &getDescription() const = 0; - virtual RenderSampleCounts getSampleCountsSupported(RenderFormat format) const = 0; - virtual void waitIdle() const = 0; - }; - - struct RenderInterface { - virtual ~RenderInterface() { } - virtual std::unique_ptr createDevice(const std::string &preferredDeviceName = "") = 0; - virtual const std::vector &getDeviceNames() const = 0; - virtual const RenderInterfaceCapabilities &getCapabilities() const = 0; - }; - - extern void RenderInterfaceTest(RenderInterface *renderInterface); - extern void TestInitialize(RenderInterface* renderInterface, RenderWindow window); - extern void TestDraw(); - extern void TestResize(); - extern void TestShutdown(); -}; - -#include "plume_render_interface_builders.h" diff --git a/UnleashedRecomp/gpu/rhi/plume_render_interface_builders.h b/UnleashedRecomp/gpu/rhi/plume_render_interface_builders.h deleted file mode 100644 index acfedce..0000000 --- a/UnleashedRecomp/gpu/rhi/plume_render_interface_builders.h +++ /dev/null @@ -1,281 +0,0 @@ -// -// plume -// -// Copyright (c) 2024 renderbag and contributors. All rights reserved. -// Licensed under the MIT license. See LICENSE file for details. -// - -#pragma once - -#include - -namespace plume { - struct RenderDescriptorSetBuilder { - std::list> samplerPointerVectorList; - std::vector descriptorRanges; - RenderDescriptorSetDesc descriptorSetDesc; - bool open = false; - uint32_t setIndex = 0; - - RenderDescriptorSetBuilder() = default; - - void begin() { - assert(!open && "Builder must be closed."); - - descriptorSetDesc = RenderDescriptorSetDesc(); - - samplerPointerVectorList.clear(); - descriptorRanges.clear(); - - open = true; - setIndex = 0; - } - - uint32_t addConstantBuffer(uint32_t binding, uint32_t count = 1) { - return addRange(RenderDescriptorRange(RenderDescriptorRangeType::CONSTANT_BUFFER, binding, count, nullptr)); - } - - uint32_t addFormattedBuffer(uint32_t binding, uint32_t count = 1) { - return addRange(RenderDescriptorRange(RenderDescriptorRangeType::FORMATTED_BUFFER, binding, count, nullptr)); - } - - uint32_t addReadWriteFormattedBuffer(uint32_t binding, uint32_t count = 1) { - return addRange(RenderDescriptorRange(RenderDescriptorRangeType::READ_WRITE_FORMATTED_BUFFER, binding, count, nullptr)); - } - - uint32_t addTexture(uint32_t binding, uint32_t count = 1) { - return addRange(RenderDescriptorRange(RenderDescriptorRangeType::TEXTURE, binding, count, nullptr)); - } - - uint32_t addReadWriteTexture(uint32_t binding, uint32_t count = 1) { - return addRange(RenderDescriptorRange(RenderDescriptorRangeType::READ_WRITE_TEXTURE, binding, count, nullptr)); - } - - uint32_t addSampler(uint32_t binding, uint32_t count = 1) { - return addRange(RenderDescriptorRange(RenderDescriptorRangeType::SAMPLER, binding, count, nullptr)); - } - - uint32_t addImmutableSampler(uint32_t binding, const RenderSampler *immutableSampler) { - assert(immutableSampler != nullptr); - - return addImmutableSampler(binding, &immutableSampler); - } - - uint32_t addImmutableSampler(uint32_t binding, const RenderSampler **immutableSampler, uint32_t count = 1) { - assert(immutableSampler != nullptr); - - samplerPointerVectorList.emplace_back(std::vector(immutableSampler, immutableSampler + count)); - return addRange(RenderDescriptorRange(RenderDescriptorRangeType::SAMPLER, binding, count, samplerPointerVectorList.back().data())); - } - - uint32_t addStructuredBuffer(uint32_t binding, uint32_t count = 1) { - return addRange(RenderDescriptorRange(RenderDescriptorRangeType::STRUCTURED_BUFFER, binding, count, nullptr)); - } - - uint32_t addReadWriteStructuredBuffer(uint32_t binding, uint32_t count = 1) { - return addRange(RenderDescriptorRange(RenderDescriptorRangeType::READ_WRITE_STRUCTURED_BUFFER, binding, count, nullptr)); - } - - uint32_t addByteAddressBuffer(uint32_t binding, uint32_t count = 1) { - return addRange(RenderDescriptorRange(RenderDescriptorRangeType::BYTE_ADDRESS_BUFFER, binding, count, nullptr)); - } - - uint32_t addReadWriteByteAddressBuffer(uint32_t binding, uint32_t count = 1) { - return addRange(RenderDescriptorRange(RenderDescriptorRangeType::READ_WRITE_BYTE_ADDRESS_BUFFER, binding, count, nullptr)); - } - - uint32_t addAccelerationStructure(uint32_t binding, uint32_t count = 1) { - return addRange(RenderDescriptorRange(RenderDescriptorRangeType::ACCELERATION_STRUCTURE, binding, count, nullptr)); - } - - uint32_t addRange(const RenderDescriptorRange &range) { - assert(open && "Builder must be open."); - - uint32_t returnValue = setIndex; - descriptorRanges.emplace_back(range); - descriptorSetDesc.descriptorRangesCount++; - setIndex += range.count; - return returnValue; - } - - void end(bool lastRangeIsBoundless = false, uint32_t boundlessRangeSize = 0) { - assert(open && "Builder must be open."); - - descriptorSetDesc.lastRangeIsBoundless = lastRangeIsBoundless; - descriptorSetDesc.boundlessRangeSize = boundlessRangeSize; - descriptorSetDesc.descriptorRanges = descriptorRanges.data(); - open = false; - } - - std::unique_ptr create(RenderDevice *device) const { - assert(!open && "Builder must be closed."); - - return device->createDescriptorSet(descriptorSetDesc); - } - }; - - struct RenderDescriptorSetBase { - RenderDescriptorSetBuilder builder; - std::unique_ptr descriptorSet; - - void create(RenderDevice *device) { - descriptorSet = builder.create(device); - } - - RenderDescriptorSet *get() const { - return descriptorSet.get(); - } - - void setBuffer(uint32_t descriptorIndex, const RenderBuffer *buffer, uint64_t bufferSize = 0, const RenderBufferStructuredView *bufferStructuredView = nullptr, const RenderBufferFormattedView *bufferFormattedView = nullptr) { - descriptorSet->setBuffer(descriptorIndex, buffer, bufferSize, bufferStructuredView, bufferFormattedView); - } - - void setBuffer(uint32_t descriptorIndex, const RenderBuffer *buffer, uint64_t bufferSize, const RenderBufferStructuredView &bufferStructuredView) { - descriptorSet->setBuffer(descriptorIndex, buffer, bufferSize, &bufferStructuredView); - } - - void setBuffer(uint32_t descriptorIndex, const RenderBuffer *buffer, uint64_t bufferSize, const RenderBufferFormattedView *bufferFormattedView) { - descriptorSet->setBuffer(descriptorIndex, buffer, bufferSize, nullptr, bufferFormattedView); - } - - void setBuffer(uint32_t descriptorIndex, const RenderBuffer *buffer, const RenderBufferStructuredView &bufferStructuredView) { - descriptorSet->setBuffer(descriptorIndex, buffer, 0, &bufferStructuredView); - } - - void setBuffer(uint32_t descriptorIndex, const RenderBuffer *buffer, const RenderBufferFormattedView *bufferFormattedView) { - descriptorSet->setBuffer(descriptorIndex, buffer, 0, nullptr, bufferFormattedView); - } - - void setTexture(uint32_t descriptorIndex, const RenderTexture *texture, const RenderTextureLayout textureLayout, const RenderTextureView *textureView = nullptr) { - descriptorSet->setTexture(descriptorIndex, texture, textureLayout, textureView); - } - - void setSampler(uint32_t descriptorIndex, const RenderSampler *sampler) { - descriptorSet->setSampler(descriptorIndex, sampler); - } - - void setAccelerationStructure(uint32_t descriptorIndex, const RenderAccelerationStructure *accelerationStructure) { - descriptorSet->setAccelerationStructure(descriptorIndex, accelerationStructure); - } - }; - - struct RenderDescriptorSetInclusionFilter { - const uint32_t *bindings = nullptr; - uint32_t bindingsCount = 0; - }; - - struct RenderPipelineLayoutBuilder { - std::vector pushConstantRanges; - std::list> samplerPointerVectorList; - std::vector descriptorRanges; - std::vector descriptorSetDescs; - std::vector descriptorRangeIndexPerSet; - std::vector rootDescriptorDescs; - RenderPipelineLayoutDesc layoutDesc; - bool open = false; - - // Start filling the description. - void begin(bool isLocal = false, bool allowInputLayout = false) { - assert(!open && "Builder must be closed."); - - layoutDesc = RenderPipelineLayoutDesc(); - layoutDesc.isLocal = isLocal; - layoutDesc.allowInputLayout = allowInputLayout; - - pushConstantRanges.clear(); - samplerPointerVectorList.clear(); - descriptorRanges.clear(); - descriptorSetDescs.clear(); - descriptorRangeIndexPerSet.clear(); - rootDescriptorDescs.clear(); - - open = true; - } - - // Returns push constant index. - uint32_t addPushConstant(uint32_t binding, uint32_t set, uint32_t size, RenderShaderStageFlags stageFlags, uint32_t offset = 0) { - assert(open && "Builder must be open."); - - uint32_t returnValue = layoutDesc.pushConstantRangesCount; - pushConstantRanges.emplace_back(RenderPushConstantRange(binding, set, offset, size, stageFlags)); - layoutDesc.pushConstantRangesCount++; - return returnValue; - } - - // Returns set index. - uint32_t addDescriptorSet(const RenderDescriptorSetDesc &descriptorSetDesc) { - assert(open && "Builder must be open."); - - uint32_t returnValue = layoutDesc.descriptorSetDescsCount; - descriptorRangeIndexPerSet.emplace_back(uint32_t(descriptorRanges.size())); - descriptorSetDescs.emplace_back(descriptorSetDesc); - - for (uint32_t j = 0; j < descriptorSetDesc.descriptorRangesCount; j++) { - descriptorRanges.emplace_back(descriptorSetDesc.descriptorRanges[j]); - - // Copy the immutable sampler pointers to a local vector list. - if (descriptorRanges.back().immutableSampler != nullptr) { - const RenderSampler **immutableSampler = descriptorRanges.back().immutableSampler; - samplerPointerVectorList.emplace_back(std::vector(immutableSampler, immutableSampler + descriptorRanges.back().count)); - descriptorRanges.back().immutableSampler = samplerPointerVectorList.back().data(); - } - } - - layoutDesc.descriptorSetDescsCount++; - - return returnValue; - } - - // Returns set index. - uint32_t addDescriptorSet(const RenderDescriptorSetBuilder &descriptorSetBuilder) { - return addDescriptorSet(descriptorSetBuilder.descriptorSetDesc); - } - - // Returns set index. - uint32_t addDescriptorSet(const RenderDescriptorSetBase &descriptorSetBase) { - return addDescriptorSet(descriptorSetBase.builder); - } - - // Returns root descriptor index. D3D12 only. - uint32_t addRootDescriptor(uint32_t shaderRegister, uint32_t registerSpace, RenderRootDescriptorType type) { - assert(open && "Builder must be open."); - - uint32_t returnValue = layoutDesc.rootDescriptorDescsCount; - rootDescriptorDescs.emplace_back(shaderRegister, registerSpace, type); - ++layoutDesc.rootDescriptorDescsCount; - - return returnValue; - } - - // Finish the description. - void end() { - assert(open && "Builder must be open."); - - if (layoutDesc.pushConstantRangesCount > 0) { - layoutDesc.pushConstantRanges = pushConstantRanges.data(); - } - - if (layoutDesc.descriptorSetDescsCount > 0) { - for (uint32_t i = 0; i < layoutDesc.descriptorSetDescsCount; i++) { - const uint32_t rangeIndex = descriptorRangeIndexPerSet[i]; - descriptorSetDescs[i].descriptorRanges = &descriptorRanges[rangeIndex]; - } - - layoutDesc.descriptorSetDescs = descriptorSetDescs.data(); - } - - if (layoutDesc.rootDescriptorDescsCount > 0) { - layoutDesc.rootDescriptorDescs = rootDescriptorDescs.data(); - } - - open = false; - } - - // Create a pipeline layout with the final description. - std::unique_ptr create(RenderDevice *device) const { - assert(!open && "Builder must be closed."); - - return device->createPipelineLayout(layoutDesc); - } - }; -} diff --git a/UnleashedRecomp/gpu/rhi/plume_render_interface_types.h b/UnleashedRecomp/gpu/rhi/plume_render_interface_types.h deleted file mode 100644 index 315274b..0000000 --- a/UnleashedRecomp/gpu/rhi/plume_render_interface_types.h +++ /dev/null @@ -1,1824 +0,0 @@ -// -// plume -// -// Copyright (c) 2024 renderbag and contributors. All rights reserved. -// Licensed under the MIT license. See LICENSE file for details. -// - -#pragma once - -#include -#include -#include -#include -#include -#include - -#if defined(_WIN64) -#include -#elif defined(__ANDROID__) -#include "android/native_window.h" -#elif defined(__linux__) -#include "X11/Xlib.h" -#undef None -#undef Status -#undef LockMask -#undef ControlMask -#undef Success -#elif defined(__APPLE__) -#include -#endif - -#ifdef SDL_VULKAN_ENABLED -#include -#endif - -namespace plume { -#if defined(_WIN64) - // Native HWND handle to the target window. - typedef HWND RenderWindow; -#elif defined(__ANDROID__) - typedef ANativeWindow* RenderWindow; -#elif defined(SDL_VULKAN_ENABLED) - typedef SDL_Window *RenderWindow; -#elif defined(__linux__) - struct RenderWindow { - Display* display; - Window window; - bool operator==(const struct RenderWindow& rhs) const { - return display == rhs.display && window == rhs.window; - } - bool operator!=(const struct RenderWindow& rhs) const { return !(*this == rhs); } - }; -#elif defined(__APPLE__) - struct RenderWindow { - SDL_Window* window; - void* view; - - bool operator==(const struct RenderWindow& rhs) const { - return window == rhs.window; - } - bool operator!=(const struct RenderWindow& rhs) const { return !(*this == rhs); } - }; -#else - static_assert(false, "RenderWindow was not defined for this platform."); -#endif - - struct RenderBuffer; - struct RenderDescriptorSet; - struct RenderPipeline; - struct RenderPipelineLayout; - struct RenderSampler; - struct RenderShader; - struct RenderTexture; - struct RenderQueryPool; - - // Enums. - - enum class RenderDeviceVendor { - UNKNOWN = 0x0, - AMD = 0x1002, - NVIDIA = 0x10DE, - INTEL = 0x8086 - }; - - enum class RenderFormat { - UNKNOWN, - R32G32B32A32_TYPELESS, - R32G32B32A32_FLOAT, - R32G32B32A32_UINT, - R32G32B32A32_SINT, - R32G32B32_TYPELESS, - R32G32B32_FLOAT, - R32G32B32_UINT, - R32G32B32_SINT, - R16G16B16A16_TYPELESS, - R16G16B16A16_FLOAT, - R16G16B16A16_UNORM, - R16G16B16A16_UINT, - R16G16B16A16_SNORM, - R16G16B16A16_SINT, - R32G32_TYPELESS, - R32G32_FLOAT, - R32G32_UINT, - R32G32_SINT, - R8G8B8A8_TYPELESS, - R8G8B8A8_UNORM, - R8G8B8A8_UINT, - R8G8B8A8_SNORM, - R8G8B8A8_SINT, - B8G8R8A8_UNORM, - R16G16_TYPELESS, - R16G16_FLOAT, - R16G16_UNORM, - R16G16_UINT, - R16G16_SNORM, - R16G16_SINT, - R32_TYPELESS, - D32_FLOAT, - R32_FLOAT, - R32_UINT, - R32_SINT, - R8G8_TYPELESS, - R8G8_UNORM, - R8G8_UINT, - R8G8_SNORM, - R8G8_SINT, - R16_TYPELESS, - R16_FLOAT, - D16_UNORM, - R16_UNORM, - R16_UINT, - R16_SNORM, - R16_SINT, - R8_TYPELESS, - R8_UNORM, - R8_UINT, - R8_SNORM, - R8_SINT, - BC1_TYPELESS, - BC1_UNORM, - BC1_UNORM_SRGB, - BC2_TYPELESS, - BC2_UNORM, - BC2_UNORM_SRGB, - BC3_TYPELESS, - BC3_UNORM, - BC3_UNORM_SRGB, - BC4_TYPELESS, - BC4_UNORM, - BC4_SNORM, - BC5_TYPELESS, - BC5_UNORM, - BC5_SNORM, - BC6H_TYPELESS, - BC6H_UF16, - BC6H_SF16, - BC7_TYPELESS, - BC7_UNORM, - BC7_UNORM_SRGB - }; - - enum class RenderTextureDimension { - UNKNOWN, - TEXTURE_1D, - TEXTURE_2D, - TEXTURE_3D - }; - - enum class RenderTextureViewDimension { - UNKNOWN, - TEXTURE_1D, - TEXTURE_2D, - TEXTURE_3D, - TEXTURE_CUBE - }; - - enum class RenderCommandListType { - UNKNOWN, - DIRECT, - COMPUTE, - COPY - }; - - enum class RenderPrimitiveTopology { - UNKNOWN, - POINT_LIST, - LINE_LIST, - LINE_STRIP, - TRIANGLE_LIST, - TRIANGLE_STRIP, - TRIANGLE_FAN - }; - - enum class RenderSRVType { - UNKNOWN, - BUFFER, - TEXTURE_1D, - TEXTURE_2D, - TEXTURE_3D - }; - - enum class RenderUAVType { - UNKNOWN, - BUFFER, - TEXTURE_1D, - TEXTURE_2D, - TEXTURE_3D - }; - - enum class RenderCullMode { - UNKNOWN, - NONE, - FRONT, - BACK - }; - - enum class RenderComparisonFunction { - UNKNOWN, - NEVER, - LESS, - EQUAL, - LESS_EQUAL, - GREATER, - NOT_EQUAL, - GREATER_EQUAL, - ALWAYS - }; - - enum class RenderInputSlotClassification { - UNKNOWN, - PER_VERTEX_DATA, - PER_INSTANCE_DATA - }; - - enum class RenderBlend { - UNKNOWN, - ZERO, - ONE, - SRC_COLOR, - INV_SRC_COLOR, - SRC_ALPHA, - INV_SRC_ALPHA, - DEST_ALPHA, - INV_DEST_ALPHA, - DEST_COLOR, - INV_DEST_COLOR, - SRC_ALPHA_SAT, - BLEND_FACTOR, - INV_BLEND_FACTOR, - SRC1_COLOR, - INV_SRC1_COLOR, - SRC1_ALPHA, - INV_SRC1_ALPHA - }; - - enum class RenderBlendOperation { - UNKNOWN, - ADD, - SUBTRACT, - REV_SUBTRACT, - MIN, - MAX - }; - - enum class RenderColorWriteEnable : uint8_t { - UNKNOWN = 0x0, - RED = 0x1, - GREEN = 0x2, - BLUE = 0x4, - ALPHA = 0x8, - ALL = RED | GREEN | BLUE | ALPHA - }; - - enum class RenderLogicOperation { - UNKNOWN, - CLEAR, - SET, - COPY, - COPY_INVERTED, - NOOP, - INVERT, - AND, - NAND, - OR, - NOR, - XOR, - EQUIV, - AND_REVERSE, - AND_INVERTED, - OR_REVERSE, - OR_INVERTED - }; - - enum class RenderFilter { - UNKNOWN, - NEAREST, - LINEAR - }; - - enum class RenderMipmapMode { - UNKNOWN, - NEAREST, - LINEAR - }; - - enum class RenderTextureAddressMode { - UNKNOWN, - WRAP, - MIRROR, - CLAMP, - BORDER, - MIRROR_ONCE - }; - - enum class RenderBorderColor { - UNKNOWN, - TRANSPARENT_BLACK, - OPAQUE_BLACK, - OPAQUE_WHITE - }; - - enum class RenderShaderVisibility { - UNKNOWN, - ALL, - VERTEX, - GEOMETRY, - PIXEL - }; - - enum class RenderDescriptorRangeType { - UNKNOWN, - CONSTANT_BUFFER, - FORMATTED_BUFFER, - READ_WRITE_FORMATTED_BUFFER, - TEXTURE, - READ_WRITE_TEXTURE, - SAMPLER, - STRUCTURED_BUFFER, - READ_WRITE_STRUCTURED_BUFFER, - BYTE_ADDRESS_BUFFER, - READ_WRITE_BYTE_ADDRESS_BUFFER, - ACCELERATION_STRUCTURE - }; - - enum class RenderRootDescriptorType { - UNKNOWN, - CONSTANT_BUFFER, - SHADER_RESOURCE, - UNORDERED_ACCESS - }; - - enum class RenderHeapType { - UNKNOWN, - DEFAULT, - UPLOAD, - READBACK, - GPU_UPLOAD - }; - - enum class RenderTextureArrangement { - UNKNOWN, - ROW_MAJOR - }; - - enum class RenderShaderFormat { - UNKNOWN, - DXIL, - SPIRV - }; - - enum class RenderRaytracingPipelineLibrarySymbolType { - UNKNOWN, - RAYGEN, - MISS, - CLOSEST_HIT, - ANY_HIT, - INTERSECTION, - CALLABLE - }; - - enum class RenderAccelerationStructureType { - UNKNOWN, - TOP_LEVEL, - BOTTOM_LEVEL - }; - - namespace RenderShaderStageFlag { - enum Bits : uint32_t { - NONE = 0U, - VERTEX = 1U << 0, - GEOMETRY = 1U << 1, - PIXEL = 1U << 2, - COMPUTE = 1U << 3, - RAYGEN = 1U << 4, - ANY_HIT = 1U << 5, - CLOSEST_HIT = 1U << 6, - MISS = 1U << 7, - INTERSECTION = 1U << 8, - CALLABLE = 1U << 9 - }; - }; - - typedef uint32_t RenderShaderStageFlags; - - namespace RenderBufferFlag { - enum Bits : uint32_t { - NONE = 0U, - VERTEX = 1U << 0, - INDEX = 1U << 1, - STORAGE = 1U << 2, - CONSTANT = 1U << 3, - FORMATTED = 1U << 4, - ACCELERATION_STRUCTURE = 1U << 5, - ACCELERATION_STRUCTURE_INPUT = 1U << 6, - ACCELERATION_STRUCTURE_SCRATCH = 1U << 7, - SHADER_BINDING_TABLE = 1U << 8, - UNORDERED_ACCESS = 1U << 9 - }; - }; - - typedef uint32_t RenderBufferFlags; - - namespace RenderTextureFlag { - enum Bits : uint32_t { - NONE = 0U, - RENDER_TARGET = 1U << 0, - DEPTH_TARGET = 1U << 1, - STORAGE = 1U << 2, - UNORDERED_ACCESS = 1U << 3, - CUBE = 1U << 4 - }; - }; - - typedef uint32_t RenderTextureFlags; - - namespace RenderBarrierStage { - enum Bits : uint32_t { - NONE = 0U, - GRAPHICS = 1U << 0, - COMPUTE = 1U << 1, - COPY = 1U << 2, - GRAPHICS_AND_COMPUTE = GRAPHICS | COMPUTE, - ALL = GRAPHICS | COMPUTE | COPY - }; - }; - - typedef uint32_t RenderBarrierStages; - - namespace RenderBufferAccess { - enum Bits : uint32_t { - NONE = 0U, - READ = 1U << 0, - WRITE = 1U << 1 - }; - }; - - typedef uint32_t RenderBufferAccessBits; - - enum class RenderTextureLayout { - UNKNOWN, - GENERAL, - SHADER_READ, - COLOR_WRITE, - DEPTH_WRITE, - DEPTH_READ, - COPY_SOURCE, - COPY_DEST, - RESOLVE_SOURCE, - RESOLVE_DEST, - PRESENT - }; - - namespace RenderSampleCount { - enum Bits : uint32_t { - COUNT_0 = 0x0, - COUNT_1 = 0x1, - COUNT_2 = 0x2, - COUNT_4 = 0x4, - COUNT_8 = 0x8, - COUNT_16 = 0x10, - COUNT_32 = 0x20, - COUNT_64 = 0x40, - COUNT_MAX = COUNT_64 - }; - }; - - typedef uint32_t RenderSampleCounts; - - enum class RenderDeviceType { - UNKNOWN, - INTEGRATED, - DISCRETE, - VIRTUAL, - CPU - }; - - enum class RenderResolveMode { - MIN, - MAX, - AVERAGE - }; - - // Global functions. - - constexpr uint32_t RenderFormatSize(RenderFormat format) { - switch (format) { - case RenderFormat::R32G32B32A32_TYPELESS: - case RenderFormat::R32G32B32A32_FLOAT: - case RenderFormat::R32G32B32A32_UINT: - case RenderFormat::R32G32B32A32_SINT: - return 16; - case RenderFormat::R32G32B32_TYPELESS: - case RenderFormat::R32G32B32_FLOAT: - case RenderFormat::R32G32B32_UINT: - case RenderFormat::R32G32B32_SINT: - return 12; - case RenderFormat::R16G16B16A16_TYPELESS: - case RenderFormat::R16G16B16A16_FLOAT: - case RenderFormat::R16G16B16A16_UNORM: - case RenderFormat::R16G16B16A16_UINT: - case RenderFormat::R16G16B16A16_SNORM: - case RenderFormat::R16G16B16A16_SINT: - case RenderFormat::R32G32_TYPELESS: - case RenderFormat::R32G32_FLOAT: - case RenderFormat::R32G32_UINT: - case RenderFormat::R32G32_SINT: - return 8; - case RenderFormat::R8G8B8A8_TYPELESS: - case RenderFormat::R8G8B8A8_UNORM: - case RenderFormat::R8G8B8A8_UINT: - case RenderFormat::R8G8B8A8_SNORM: - case RenderFormat::R8G8B8A8_SINT: - case RenderFormat::B8G8R8A8_UNORM: - case RenderFormat::R16G16_TYPELESS: - case RenderFormat::R16G16_FLOAT: - case RenderFormat::R16G16_UNORM: - case RenderFormat::R16G16_UINT: - case RenderFormat::R16G16_SNORM: - case RenderFormat::R16G16_SINT: - case RenderFormat::R32_TYPELESS: - case RenderFormat::D32_FLOAT: - case RenderFormat::R32_FLOAT: - case RenderFormat::R32_UINT: - case RenderFormat::R32_SINT: - return 4; - case RenderFormat::R8G8_TYPELESS: - case RenderFormat::R8G8_UNORM: - case RenderFormat::R8G8_UINT: - case RenderFormat::R8G8_SNORM: - case RenderFormat::R8G8_SINT: - case RenderFormat::R16_TYPELESS: - case RenderFormat::R16_FLOAT: - case RenderFormat::D16_UNORM: - case RenderFormat::R16_UNORM: - case RenderFormat::R16_UINT: - case RenderFormat::R16_SNORM: - case RenderFormat::R16_SINT: - return 2; - case RenderFormat::R8_TYPELESS: - case RenderFormat::R8_UNORM: - case RenderFormat::R8_UINT: - case RenderFormat::R8_SNORM: - case RenderFormat::R8_SINT: - return 1; - case RenderFormat::BC1_UNORM: - case RenderFormat::BC1_UNORM_SRGB: - case RenderFormat::BC1_TYPELESS: - case RenderFormat::BC4_UNORM: - case RenderFormat::BC4_SNORM: - case RenderFormat::BC4_TYPELESS: - return 8; - case RenderFormat::BC2_UNORM: - case RenderFormat::BC2_UNORM_SRGB: - case RenderFormat::BC2_TYPELESS: - case RenderFormat::BC3_UNORM: - case RenderFormat::BC3_UNORM_SRGB: - case RenderFormat::BC3_TYPELESS: - case RenderFormat::BC5_UNORM: - case RenderFormat::BC5_SNORM: - case RenderFormat::BC6H_UF16: - case RenderFormat::BC6H_SF16: - case RenderFormat::BC7_UNORM: - case RenderFormat::BC7_UNORM_SRGB: - return 16; - default: - assert(false && "Unknown format."); - return 1; - } - } - - constexpr uint32_t RenderFormatBlockWidth(RenderFormat format) { - switch (format) { - case RenderFormat::R32G32B32A32_TYPELESS: - case RenderFormat::R32G32B32A32_FLOAT: - case RenderFormat::R32G32B32A32_UINT: - case RenderFormat::R32G32B32A32_SINT: - case RenderFormat::R32G32B32_TYPELESS: - case RenderFormat::R32G32B32_FLOAT: - case RenderFormat::R32G32B32_UINT: - case RenderFormat::R32G32B32_SINT: - case RenderFormat::R16G16B16A16_TYPELESS: - case RenderFormat::R16G16B16A16_FLOAT: - case RenderFormat::R16G16B16A16_UNORM: - case RenderFormat::R16G16B16A16_UINT: - case RenderFormat::R16G16B16A16_SNORM: - case RenderFormat::R16G16B16A16_SINT: - case RenderFormat::R32G32_TYPELESS: - case RenderFormat::R32G32_FLOAT: - case RenderFormat::R32G32_UINT: - case RenderFormat::R32G32_SINT: - case RenderFormat::R8G8B8A8_TYPELESS: - case RenderFormat::R8G8B8A8_UNORM: - case RenderFormat::R8G8B8A8_UINT: - case RenderFormat::R8G8B8A8_SNORM: - case RenderFormat::R8G8B8A8_SINT: - case RenderFormat::B8G8R8A8_UNORM: - case RenderFormat::R16G16_TYPELESS: - case RenderFormat::R16G16_FLOAT: - case RenderFormat::R16G16_UNORM: - case RenderFormat::R16G16_UINT: - case RenderFormat::R16G16_SNORM: - case RenderFormat::R16G16_SINT: - case RenderFormat::R32_TYPELESS: - case RenderFormat::D32_FLOAT: - case RenderFormat::R32_FLOAT: - case RenderFormat::R32_UINT: - case RenderFormat::R32_SINT: - case RenderFormat::R8G8_TYPELESS: - case RenderFormat::R8G8_UNORM: - case RenderFormat::R8G8_UINT: - case RenderFormat::R8G8_SNORM: - case RenderFormat::R8G8_SINT: - case RenderFormat::R16_TYPELESS: - case RenderFormat::R16_FLOAT: - case RenderFormat::D16_UNORM: - case RenderFormat::R16_UNORM: - case RenderFormat::R16_UINT: - case RenderFormat::R16_SNORM: - case RenderFormat::R16_SINT: - case RenderFormat::R8_TYPELESS: - case RenderFormat::R8_UNORM: - case RenderFormat::R8_UINT: - case RenderFormat::R8_SNORM: - case RenderFormat::R8_SINT: - return 1; - case RenderFormat::BC1_TYPELESS: - case RenderFormat::BC1_UNORM: - case RenderFormat::BC1_UNORM_SRGB: - case RenderFormat::BC2_TYPELESS: - case RenderFormat::BC2_UNORM: - case RenderFormat::BC2_UNORM_SRGB: - case RenderFormat::BC3_TYPELESS: - case RenderFormat::BC3_UNORM: - case RenderFormat::BC3_UNORM_SRGB: - case RenderFormat::BC4_TYPELESS: - case RenderFormat::BC4_UNORM: - case RenderFormat::BC4_SNORM: - case RenderFormat::BC5_TYPELESS: - case RenderFormat::BC5_UNORM: - case RenderFormat::BC5_SNORM: - case RenderFormat::BC6H_TYPELESS: - case RenderFormat::BC6H_UF16: - case RenderFormat::BC6H_SF16: - case RenderFormat::BC7_TYPELESS: - case RenderFormat::BC7_UNORM: - case RenderFormat::BC7_UNORM_SRGB: - return 4; - default: - assert(false && "Unknown format."); - return 1; - } - }; - - // Concrete structs. - - struct RenderColor { - union { - struct { - float rgba[4]; - }; - - struct { - float r; - float g; - float b; - float a; - }; - }; - - RenderColor() { - r = 0.0f; - g = 0.0f; - b = 0.0f; - a = 1.0f; - } - - RenderColor(float r, float g, float b, float a = 1.0f) { - this->r = r; - this->g = g; - this->b = b; - this->a = a; - } - }; - - struct RenderAffineTransform { - float m[3][4] = {}; - - RenderAffineTransform() { - m[0][0] = 1.0f; - m[1][1] = 1.0f; - m[2][2] = 1.0f; - } - }; - - struct RenderDepth { - float depth = 1.0f; - - RenderDepth() = default; - - RenderDepth(float depth) { - this->depth = depth; - } - }; - - struct RenderMultisamplingLocation { - // Valid range is [-8, 7]. - int8_t x = 0; - int8_t y = 0; - }; - - struct RenderMultisampling { - RenderSampleCounts sampleCount = RenderSampleCount::COUNT_1; - RenderMultisamplingLocation sampleLocations[16] = {}; - bool sampleLocationsEnabled = false; - - RenderMultisampling() = default; - - RenderMultisampling(RenderSampleCounts sampleCount) { - this->sampleCount = sampleCount; - } - }; - - struct RenderBufferReference { - const RenderBuffer *ref = nullptr; - uint64_t offset = 0; - - RenderBufferReference() = default; - - RenderBufferReference(const RenderBuffer *ref) { - this->ref = ref; - offset = 0; - } - - RenderBufferReference(const RenderBuffer *ref, uint64_t offset) { - this->ref = ref; - this->offset = offset; - } - - bool operator==(const RenderBufferReference& rhs) const { - return ref == rhs.ref && offset == rhs.offset; - } - - bool operator!=(const RenderBufferReference& rhs) const { - return !(*this == rhs); - } - }; - - struct RenderBufferBarrier { - RenderBuffer *buffer = nullptr; - RenderBufferAccessBits accessBits = RenderBufferAccess::NONE; - - RenderBufferBarrier() = default; - - RenderBufferBarrier(RenderBuffer *buffer, RenderBufferAccessBits accessBits) { - this->buffer = buffer; - this->accessBits = accessBits; - } - }; - - struct RenderBufferStructuredView { - uint32_t structureByteStride = 0; - uint32_t firstElement = 0; - - RenderBufferStructuredView() = default; - - RenderBufferStructuredView(uint32_t structureByteStride, uint32_t firstElement = 0) { - this->structureByteStride = structureByteStride; - this->firstElement = firstElement; - } - }; - - struct RenderTextureBarrier { - RenderTexture *texture = nullptr; - RenderTextureLayout layout = RenderTextureLayout::UNKNOWN; - - RenderTextureBarrier() = default; - - RenderTextureBarrier(RenderTexture *texture, RenderTextureLayout layout) { - this->texture = texture; - this->layout = layout; - } - }; - - struct RenderClearValue { - RenderFormat format = RenderFormat::UNKNOWN; - union { - RenderColor color; - RenderDepth depth; - }; - - RenderClearValue() : color{} {} - - static RenderClearValue Color(RenderColor color, RenderFormat format) { - RenderClearValue clear = {}; - clear.format = format; - clear.color = color; - return clear; - } - - static RenderClearValue Depth(RenderDepth depth, RenderFormat format) { - RenderClearValue clear = {}; - clear.format = format; - clear.depth = depth; - return clear; - } - }; - - struct RenderBufferDesc { - uint64_t size = 0; - RenderHeapType heapType = RenderHeapType::UNKNOWN; - RenderBufferFlags flags = RenderBufferFlag::NONE; - bool committed = false; - - RenderBufferDesc() = default; - - static RenderBufferDesc DefaultBuffer(uint64_t size, RenderBufferFlags flags = RenderBufferFlag::NONE) { - RenderBufferDesc desc; - desc.size = size; - desc.heapType = RenderHeapType::DEFAULT; - desc.flags = flags; - return desc; - } - - static RenderBufferDesc UploadBuffer(uint64_t size, RenderBufferFlags flags = RenderBufferFlag::NONE) { - RenderBufferDesc desc; - desc.heapType = RenderHeapType::UPLOAD; - desc.size = size; - desc.flags = flags; - return desc; - } - - static RenderBufferDesc ReadbackBuffer(uint64_t size, RenderBufferFlags flags = RenderBufferFlag::NONE) { - RenderBufferDesc desc; - desc.heapType = RenderHeapType::READBACK; - desc.size = size; - desc.flags = flags; - return desc; - } - - static RenderBufferDesc VertexBuffer(uint64_t size, RenderHeapType heapType, RenderBufferFlags flags = RenderBufferFlag::NONE) { - RenderBufferDesc desc; - desc.size = size; - desc.heapType = heapType; - desc.flags = flags | RenderBufferFlag::VERTEX; - return desc; - } - - static RenderBufferDesc IndexBuffer(uint64_t size, RenderHeapType heapType, RenderBufferFlags flags = RenderBufferFlag::NONE) { - RenderBufferDesc desc; - desc.size = size; - desc.heapType = heapType; - desc.flags = flags | RenderBufferFlag::INDEX; - return desc; - } - - static RenderBufferDesc AccelerationStructureBuffer(uint64_t size) { - RenderBufferDesc desc; - desc.size = size; - desc.heapType = RenderHeapType::DEFAULT; - desc.flags = RenderBufferFlag::ACCELERATION_STRUCTURE; - return desc; - } - }; - - struct RenderTextureDesc { - RenderTextureDimension dimension = RenderTextureDimension::UNKNOWN; - uint32_t width = 0; - uint32_t height = 0; - uint16_t depth = 0; - uint16_t mipLevels = 0; - uint16_t arraySize = 0; - RenderMultisampling multisampling; - RenderFormat format = RenderFormat::UNKNOWN; - RenderTextureArrangement textureArrangement = RenderTextureArrangement::UNKNOWN; - const RenderClearValue *optimizedClearValue = nullptr; - RenderTextureFlags flags = RenderTextureFlag::NONE; - bool committed = false; - - RenderTextureDesc() = default; - - static RenderTextureDesc Texture(RenderTextureDimension dimension, uint32_t width, uint32_t height, uint16_t depth, uint16_t mipLevels, uint16_t arraySize, RenderFormat format, RenderTextureFlags flags = RenderTextureFlag::NONE) { - RenderTextureDesc desc; - desc.dimension = dimension; - desc.width = width; - desc.height = height; - desc.depth = depth; - desc.mipLevels = mipLevels; - desc.arraySize = arraySize; - desc.format = format; - desc.flags = flags; - return desc; - } - - static RenderTextureDesc Texture1D(uint32_t width, uint16_t mipLevels, RenderFormat format, RenderTextureFlags flags = RenderTextureFlag::NONE) { - return Texture(RenderTextureDimension::TEXTURE_1D, width, 1, 1, mipLevels, 1, format, flags); - } - - static RenderTextureDesc Texture2D(uint32_t width, uint32_t height, uint16_t mipLevels, RenderFormat format, RenderTextureFlags flags = RenderTextureFlag::NONE) { - return Texture(RenderTextureDimension::TEXTURE_2D, width, height, 1, mipLevels, 1, format, flags); - } - - static RenderTextureDesc Texture3D(uint32_t width, uint32_t height, uint32_t depth, uint16_t mipLevels, RenderFormat format, RenderTextureFlags flags = RenderTextureFlag::NONE) { - return Texture(RenderTextureDimension::TEXTURE_3D, width, height, depth, mipLevels, 1, format, flags); - } - - static RenderTextureDesc ColorTarget(uint32_t width, uint32_t height, RenderFormat format, RenderMultisampling multisampling = RenderMultisampling(), const RenderClearValue *optimizedClearValue = nullptr, RenderTextureFlags flags = RenderTextureFlag::NONE) { - RenderTextureDesc desc; - desc.committed = true; - desc.dimension = RenderTextureDimension::TEXTURE_2D; - desc.width = width; - desc.height = height; - desc.depth = 1; - desc.mipLevels = 1; - desc.arraySize = 1; - desc.format = format; - desc.multisampling = multisampling; - desc.flags = flags | RenderTextureFlag::RENDER_TARGET; - desc.optimizedClearValue = optimizedClearValue; - return desc; - } - - static RenderTextureDesc DepthTarget(uint32_t width, uint32_t height, RenderFormat format, RenderMultisampling multisampling = RenderMultisampling(), const RenderClearValue *optimizedClearValue = nullptr, RenderTextureFlags flags = RenderTextureFlag::NONE) { - RenderTextureDesc desc; - desc.committed = true; - desc.dimension = RenderTextureDimension::TEXTURE_2D; - desc.width = width; - desc.height = height; - desc.depth = 1; - desc.mipLevels = 1; - desc.arraySize = 1; - desc.format = format; - desc.multisampling = multisampling; - desc.flags = flags | RenderTextureFlag::DEPTH_TARGET; - desc.optimizedClearValue = optimizedClearValue; - return desc; - } - }; - - enum class RenderSwizzle : uint8_t - { - IDENTITY = 0, - ZERO = 1, - ONE = 2, - R = 3, - G = 4, - B = 5, - A = 6 - }; - - struct RenderComponentMapping - { - RenderSwizzle r = RenderSwizzle::IDENTITY; - RenderSwizzle g = RenderSwizzle::IDENTITY; - RenderSwizzle b = RenderSwizzle::IDENTITY; - RenderSwizzle a = RenderSwizzle::IDENTITY; - - RenderComponentMapping() = default; - RenderComponentMapping(RenderSwizzle r, RenderSwizzle g, RenderSwizzle b, RenderSwizzle a) : r(r), g(g), b(b), a(a) {} - }; - - struct RenderTextureViewDesc { - RenderFormat format = RenderFormat::UNKNOWN; - RenderTextureViewDimension dimension = RenderTextureViewDimension::UNKNOWN; - uint32_t mipLevels = 0; - uint32_t mipSlice = 0; - RenderComponentMapping componentMapping; - - RenderTextureViewDesc() = default; - - static RenderTextureViewDesc Texture1D(RenderFormat format, uint32_t mipLevels = 1) { - RenderTextureViewDesc viewDesc; - viewDesc.format = format; - viewDesc.dimension = RenderTextureViewDimension::TEXTURE_1D; - viewDesc.mipLevels = mipLevels; - return viewDesc; - } - - static RenderTextureViewDesc Texture2D(RenderFormat format, uint32_t mipLevels = 1) { - RenderTextureViewDesc viewDesc; - viewDesc.format = format; - viewDesc.dimension = RenderTextureViewDimension::TEXTURE_2D; - viewDesc.mipLevels = mipLevels; - return viewDesc; - } - - static RenderTextureViewDesc Texture3D(RenderFormat format, uint32_t mipLevels = 1) { - RenderTextureViewDesc viewDesc; - viewDesc.format = format; - viewDesc.dimension = RenderTextureViewDimension::TEXTURE_3D; - viewDesc.mipLevels = mipLevels; - return viewDesc; - } - - static RenderTextureViewDesc TextureCube(RenderFormat format, uint32_t mipLevels = 1) { - RenderTextureViewDesc viewDesc; - viewDesc.format = format; - viewDesc.dimension = RenderTextureViewDimension::TEXTURE_CUBE; - viewDesc.mipLevels = mipLevels; - return viewDesc; - } - }; - - struct RenderAccelerationStructureDesc { - RenderAccelerationStructureType type = RenderAccelerationStructureType::UNKNOWN; - RenderBufferReference buffer; - uint64_t size = 0; - - RenderAccelerationStructureDesc() = default; - - RenderAccelerationStructureDesc(RenderAccelerationStructureType type, RenderBufferReference buffer, uint64_t size) { - this->type = type; - this->buffer = buffer; - this->size = size; - } - }; - - enum class RenderTextureCopyType { - UNKNOWN, - SUBRESOURCE, - PLACED_FOOTPRINT - }; - - struct RenderTextureCopyLocation { - const RenderTexture *texture = nullptr; - const RenderBuffer *buffer = nullptr; - RenderTextureCopyType type = RenderTextureCopyType::UNKNOWN; - - union { - struct { - RenderFormat format; - uint32_t width; - uint32_t height; - uint32_t depth; - uint32_t rowWidth; - uint64_t offset; - } placedFootprint; - - struct { - uint32_t index; - } subresource; - }; - - static RenderTextureCopyLocation PlacedFootprint(const RenderBuffer *buffer, RenderFormat format, uint32_t width, uint32_t height, uint32_t depth, uint32_t rowWidth, uint64_t offset = 0) { - RenderTextureCopyLocation loc; - loc.buffer = buffer; - loc.type = RenderTextureCopyType::PLACED_FOOTPRINT; - loc.placedFootprint.format = format; - loc.placedFootprint.width = width; - loc.placedFootprint.height = height; - loc.placedFootprint.depth = depth; - loc.placedFootprint.rowWidth = rowWidth; - loc.placedFootprint.offset = offset; - return loc; - } - - static RenderTextureCopyLocation Subresource(const RenderTexture *texture, uint32_t index = 0) { - RenderTextureCopyLocation loc; - loc.texture = texture; - loc.type = RenderTextureCopyType::SUBRESOURCE; - loc.subresource.index = index; - return loc; - } - }; - - struct RenderPoolDesc { - RenderHeapType heapType = RenderHeapType::UNKNOWN; - uint32_t minBlockCount = 0; - uint32_t maxBlockCount = 0; - bool useLinearAlgorithm = false; - bool allowOnlyBuffers = false; - }; - - struct RenderInputSlot { - uint32_t index = 0; - uint32_t stride = 0; - RenderInputSlotClassification classification = RenderInputSlotClassification::UNKNOWN; - - RenderInputSlot() = default; - - RenderInputSlot(uint32_t index, uint32_t stride, RenderInputSlotClassification classification = RenderInputSlotClassification::PER_VERTEX_DATA) { - this->index = index; - this->stride = stride; - this->classification = classification; - } - }; - - struct RenderInputElement { - // Semantic name and index and location must be specified for both backends, but each attribute will only be read by the backend that uses them. - const char *semanticName = nullptr; - uint32_t semanticIndex = 0; - uint32_t location = 0; - RenderFormat format = RenderFormat::UNKNOWN; - uint32_t slotIndex = 0; - uint32_t alignedByteOffset = 0; - - RenderInputElement() = default; - - RenderInputElement(const char *semanticName, uint32_t semanticIndex, uint32_t location, RenderFormat format, uint32_t slotIndex, uint32_t alignedByteOffset) { - this->semanticName = semanticName; - this->semanticIndex = semanticIndex; - this->location = location; - this->format = format; - this->slotIndex = slotIndex; - this->alignedByteOffset = alignedByteOffset; - } - }; - - struct RenderBlendDesc { - bool blendEnabled = false; - RenderBlend srcBlend = RenderBlend::UNKNOWN; - RenderBlend dstBlend = RenderBlend::UNKNOWN; - RenderBlendOperation blendOp = RenderBlendOperation::UNKNOWN; - RenderBlend srcBlendAlpha = RenderBlend::UNKNOWN; - RenderBlend dstBlendAlpha = RenderBlend::UNKNOWN; - RenderBlendOperation blendOpAlpha = RenderBlendOperation::UNKNOWN; - uint8_t renderTargetWriteMask = uint8_t(RenderColorWriteEnable::ALL); - - static RenderBlendDesc Copy() { - RenderBlendDesc desc; - desc.srcBlend = RenderBlend::ONE; - desc.dstBlend = RenderBlend::ZERO; - desc.blendOp = RenderBlendOperation::ADD; - desc.srcBlendAlpha = RenderBlend::ONE; - desc.dstBlendAlpha = RenderBlend::ZERO; - desc.blendOpAlpha = RenderBlendOperation::ADD; - return desc; - } - - static RenderBlendDesc AlphaBlend() { - RenderBlendDesc desc; - desc.blendEnabled = true; - desc.srcBlend = RenderBlend::SRC_ALPHA; - desc.dstBlend = RenderBlend::INV_SRC_ALPHA; - desc.blendOp = RenderBlendOperation::ADD; - desc.srcBlendAlpha = RenderBlend::SRC_ALPHA; - desc.dstBlendAlpha = RenderBlend::INV_SRC_ALPHA; - desc.blendOpAlpha = RenderBlendOperation::ADD; - return desc; - } - }; - - struct RenderSpecConstant { - uint32_t index = 0; - uint32_t value = 0; - - RenderSpecConstant() = default; - - RenderSpecConstant(uint32_t index, uint32_t value) { - this->index = index; - this->value = value; - } - }; - - struct RenderComputePipelineDesc { - const RenderPipelineLayout *pipelineLayout = nullptr; - const RenderShader *computeShader = nullptr; - const RenderSpecConstant *specConstants = nullptr; - uint32_t specConstantsCount = 0; - - RenderComputePipelineDesc() = default; - - RenderComputePipelineDesc(const RenderPipelineLayout *pipelineLayout, const RenderShader *computeShader) { - this->pipelineLayout = pipelineLayout; - this->computeShader = computeShader; - } - }; - - struct RenderGraphicsPipelineDesc { - static const uint32_t MaxRenderTargets = 8; - - const RenderPipelineLayout *pipelineLayout = nullptr; - const RenderShader *vertexShader = nullptr; - const RenderShader *geometryShader = nullptr; - const RenderShader *pixelShader = nullptr; - RenderComparisonFunction depthFunction = RenderComparisonFunction::NEVER; - bool depthClipEnabled = false; - int32_t depthBias = 0; - float slopeScaledDepthBias = 0.0f; - bool dynamicDepthBiasEnabled = false; - bool depthEnabled = false; - bool depthWriteEnabled = false; - RenderMultisampling multisampling; - bool alphaToCoverageEnabled = false; - RenderPrimitiveTopology primitiveTopology = RenderPrimitiveTopology::TRIANGLE_LIST; - RenderCullMode cullMode = RenderCullMode::NONE; - RenderFormat renderTargetFormat[MaxRenderTargets] = {}; - RenderBlendDesc renderTargetBlend[MaxRenderTargets] = {}; - uint32_t renderTargetCount = 0; - bool logicOpEnabled = false; - RenderLogicOperation logicOp = RenderLogicOperation::NOOP; - RenderFormat depthTargetFormat = RenderFormat::UNKNOWN; - const RenderInputSlot *inputSlots = nullptr; - uint32_t inputSlotsCount = 0; - const RenderInputElement *inputElements = nullptr; - uint32_t inputElementsCount = 0; - const RenderSpecConstant *specConstants = nullptr; - uint32_t specConstantsCount = 0; - }; - - struct RenderRaytracingPipelineLibrarySymbol { - const char *importName = nullptr; - RenderRaytracingPipelineLibrarySymbolType type = RenderRaytracingPipelineLibrarySymbolType::UNKNOWN; - const char *exportName = nullptr; - const RenderSpecConstant *specConstants = nullptr; - uint32_t specConstantsCount = 0; - - RenderRaytracingPipelineLibrarySymbol() = default; - - RenderRaytracingPipelineLibrarySymbol(const char *importName, RenderRaytracingPipelineLibrarySymbolType type, const char *exportName = nullptr, const RenderSpecConstant *specConstants = nullptr, uint32_t specConstantsCount = 0) { - this->importName = importName; - this->type = type; - this->specConstants = specConstants; - this->exportName = exportName; - this->specConstantsCount = specConstantsCount; - } - }; - - struct RenderRaytracingPipelineLibrary { - const RenderShader *shader = nullptr; - const RenderRaytracingPipelineLibrarySymbol *symbols = nullptr; - uint32_t symbolsCount = 0; - - RenderRaytracingPipelineLibrary() = default; - - RenderRaytracingPipelineLibrary(const RenderShader *shader, const RenderRaytracingPipelineLibrarySymbol *symbols, uint32_t symbolsCount) { - this->shader = shader; - this->symbols = symbols; - this->symbolsCount = symbolsCount; - } - }; - - struct RenderRaytracingPipelineHitGroup { - const char *hitGroupName = nullptr; - const char *closestHitName = nullptr; - const char *anyHitName = nullptr; - const char *intersectionName = nullptr; - - RenderRaytracingPipelineHitGroup() = default; - - RenderRaytracingPipelineHitGroup(const char *hitGroupName, const char *closestHitName = nullptr, const char *anyHitName = nullptr, const char *intersectionName = nullptr) { - this->hitGroupName = hitGroupName; - this->closestHitName = closestHitName; - this->anyHitName = anyHitName; - this->intersectionName = intersectionName; - } - }; - - struct RenderRaytracingPipelineDesc { - const RenderRaytracingPipelineLibrary *libraries = nullptr; - uint32_t librariesCount = 0; - const RenderRaytracingPipelineHitGroup *hitGroups = nullptr; - uint32_t hitGroupsCount = 0; - const RenderPipelineLayout *pipelineLayout = nullptr; - uint32_t maxPayloadSize = 0; - uint32_t maxAttributeSize = 2 * sizeof(float); - uint32_t maxRecursionDepth = 1; - - // IMPORTANT: State update support must be true for this option to work. The pipeline creation will not work if this option - // is enabled and the device doesn't support it. This option is only supported by Raytracing Tier 1.1 devices. - bool stateUpdateEnabled = false; - }; - - struct RenderPipelineProgram { - uint32_t programIndex = 0; - - RenderPipelineProgram() = default; - - RenderPipelineProgram(uint32_t programIndex) { - this->programIndex = programIndex; - } - }; - - struct RenderSamplerDesc { - RenderFilter minFilter = RenderFilter::LINEAR; - RenderFilter magFilter = RenderFilter::LINEAR; - RenderMipmapMode mipmapMode = RenderMipmapMode::LINEAR; - RenderTextureAddressMode addressU = RenderTextureAddressMode::CLAMP; - RenderTextureAddressMode addressV = RenderTextureAddressMode::CLAMP; - RenderTextureAddressMode addressW = RenderTextureAddressMode::CLAMP; - float mipLODBias = 0.0f; - uint32_t maxAnisotropy = 16; - bool anisotropyEnabled = false; - RenderComparisonFunction comparisonFunc = RenderComparisonFunction::NEVER; - bool comparisonEnabled = false; - RenderBorderColor borderColor = RenderBorderColor::OPAQUE_BLACK; - float minLOD = 0.0f; - float maxLOD = FLT_MAX; - RenderShaderVisibility shaderVisibility = RenderShaderVisibility::ALL; - - RenderSamplerDesc() = default; - }; - - struct RenderDescriptorRange { - // The type of descriptor range. The descriptor can't change this during its lifetime. - RenderDescriptorRangeType type = RenderDescriptorRangeType::UNKNOWN; - - // How many descriptors should be assigned and allocated for this range. When the range - // is boundless (see RenderDescriptorSetDesc::lastRangeIsBoundless), this indicates the upper - // bound of the variable sized array (TBD if this implies additional memory consumption). - uint32_t count = 0; - - // The shader binding number the descriptor will correspond to. - uint32_t binding = 0; - - // An optional immutable sampler to build in statically into the pipeline layout. - const RenderSampler **immutableSampler = nullptr; - - RenderDescriptorRange() = default; - - RenderDescriptorRange(RenderDescriptorRangeType type, uint32_t binding, uint32_t count, const RenderSampler **immutableSampler = nullptr) { - this->type = type; - this->binding = binding; - this->count = count; - this->immutableSampler = immutableSampler; - } - }; - - struct RenderDescriptorSetDesc { - const RenderDescriptorRange *descriptorRanges = nullptr; - uint32_t descriptorRangesCount = 0; - bool lastRangeIsBoundless = false; - uint32_t boundlessRangeSize = 0; - - RenderDescriptorSetDesc() = default; - - RenderDescriptorSetDesc(const RenderDescriptorRange *descriptorRanges, uint32_t descriptorRangesCount, bool lastRangeIsBoundless = false, uint32_t boundlessRangeSize = 0) { - this->descriptorRanges = descriptorRanges; - this->descriptorRangesCount = descriptorRangesCount; - this->lastRangeIsBoundless = lastRangeIsBoundless; - this->boundlessRangeSize = boundlessRangeSize; - } - }; - - struct RenderPushConstantRange { - uint32_t binding = 0; - uint32_t set = 0; - uint32_t offset = 0; // Must be aligned to 4-bytes for DX12. - uint32_t size = 0; - RenderShaderStageFlags stageFlags = RenderShaderStageFlag::NONE; - - RenderPushConstantRange() = default; - - RenderPushConstantRange(uint32_t binding, uint32_t set, uint32_t offset, uint32_t size, RenderShaderStageFlags stageFlags) { - this->binding = binding; - this->set = set; - this->offset = offset; - this->size = size; - this->stageFlags = stageFlags; - } - }; - - // D3D12 only. - struct RenderRootDescriptorDesc { - uint32_t shaderRegister = 0; - uint32_t registerSpace = 0; - RenderRootDescriptorType type = RenderRootDescriptorType::UNKNOWN; - - RenderRootDescriptorDesc() = default; - - RenderRootDescriptorDesc(uint32_t shaderRegister, uint32_t registerSpace, RenderRootDescriptorType type) { - this->shaderRegister = shaderRegister; - this->registerSpace = registerSpace; - this->type = type; - } - }; - - struct RenderPipelineLayoutDesc { - const RenderPushConstantRange *pushConstantRanges = nullptr; - uint32_t pushConstantRangesCount = 0; - const RenderDescriptorSetDesc *descriptorSetDescs = nullptr; - uint32_t descriptorSetDescsCount = 0; - const RenderRootDescriptorDesc* rootDescriptorDescs = nullptr; - uint32_t rootDescriptorDescsCount = 0; - bool isLocal = false; - bool allowInputLayout = false; - - RenderPipelineLayoutDesc() = default; - - RenderPipelineLayoutDesc(const RenderPushConstantRange *pushConstantRanges, uint32_t pushConstantRangesCount, const RenderDescriptorSetDesc *descriptorSetDescs, uint32_t descriptorSetDescsCount, bool isLocal = false, bool allowInputLayout = false) { - this->pushConstantRanges = pushConstantRanges; - this->pushConstantRangesCount = pushConstantRangesCount; - this->descriptorSetDescs = descriptorSetDescs; - this->descriptorSetDescsCount = descriptorSetDescsCount; - this->isLocal = isLocal; - this->allowInputLayout = allowInputLayout; - } - }; - - struct RenderIndexBufferView { - RenderBufferReference buffer; - uint32_t size = 0; - RenderFormat format = RenderFormat::UNKNOWN; - - RenderIndexBufferView() = default; - - RenderIndexBufferView(RenderBufferReference buffer, uint32_t size, RenderFormat format) { - this->buffer = buffer; - this->size = size; - this->format = format; - } - }; - - struct RenderVertexBufferView { - RenderBufferReference buffer; - uint32_t size = 0; - - RenderVertexBufferView() = default; - - RenderVertexBufferView(RenderBufferReference buffer, uint32_t size) { - this->buffer = buffer; - this->size = size; - } - }; - - struct RenderSRV { - RenderSRVType type = RenderSRVType::UNKNOWN; - RenderFormat format = RenderFormat::UNKNOWN; - - union { - struct { - uint32_t firstElement; - uint32_t structureByteStride; - bool raw; - } buffer; - - struct { - uint32_t mipLevels; - } texture; - }; - - RenderSRV() = default; - - RenderSRV(RenderSRVType type, RenderFormat format) { - this->type = type; - this->format = format; - } - - static RenderSRV Buffer(RenderFormat format, uint32_t firstElement = 0, bool raw = false) { - RenderSRV srv(RenderSRVType::BUFFER, format); - srv.buffer.firstElement = firstElement; - srv.buffer.structureByteStride = 0; - srv.buffer.raw = raw; - return srv; - } - - static RenderSRV StructuredBuffer(uint32_t strideInBytes, uint32_t firstElement = 0, bool raw = false) { - RenderSRV srv(RenderSRVType::BUFFER, RenderFormat::UNKNOWN); - srv.buffer.firstElement = firstElement; - srv.buffer.structureByteStride = strideInBytes; - srv.buffer.raw = raw; - return srv; - } - - static RenderSRV Texture1D(RenderFormat format = RenderFormat::UNKNOWN, uint32_t mipLevels = 1) { - RenderSRV srv(RenderSRVType::TEXTURE_1D, format); - srv.texture.mipLevels = mipLevels; - return srv; - } - - static RenderSRV Texture2D(RenderFormat format = RenderFormat::UNKNOWN, uint32_t mipLevels = 1) { - RenderSRV srv(RenderSRVType::TEXTURE_2D, format); - srv.texture.mipLevels = mipLevels; - return srv; - } - - static RenderSRV Texture3D(RenderFormat format = RenderFormat::UNKNOWN, uint32_t mipLevels = 1) { - RenderSRV srv(RenderSRVType::TEXTURE_3D, format); - srv.texture.mipLevels = mipLevels; - return srv; - } - }; - - struct RenderUAV { - RenderUAVType type = RenderUAVType::UNKNOWN; - RenderFormat format = RenderFormat::UNKNOWN; - - union { - struct { - uint32_t firstElement; - uint32_t structureByteStride; - bool raw; - } buffer; - - struct { - uint32_t mipSlice; - } texture; - }; - - RenderUAV() = default; - - RenderUAV(RenderUAVType type, RenderFormat format) { - this->type = type; - this->format = format; - } - - static RenderUAV Buffer(RenderFormat format, uint32_t firstElement = 0, bool raw = false) { - RenderUAV uav(RenderUAVType::BUFFER, format); - uav.buffer.firstElement = firstElement; - uav.buffer.structureByteStride = 0; - uav.buffer.raw = raw; - return uav; - } - - static RenderUAV StructuredBuffer(uint32_t strideInBytes, uint32_t firstElement = 0, bool raw = false) { - RenderUAV uav(RenderUAVType::BUFFER, RenderFormat::UNKNOWN); - uav.buffer.firstElement = firstElement; - uav.buffer.structureByteStride = strideInBytes; - uav.buffer.raw = raw; - return uav; - } - - static RenderUAV Texture1D(RenderFormat format = RenderFormat::UNKNOWN, uint32_t mipSlice = 0) { - RenderUAV uav(RenderUAVType::TEXTURE_1D, format); - uav.texture.mipSlice = mipSlice; - return uav; - } - - static RenderUAV Texture2D(RenderFormat format = RenderFormat::UNKNOWN, uint32_t mipSlice = 0) { - RenderUAV uav(RenderUAVType::TEXTURE_2D, format); - uav.texture.mipSlice = mipSlice; - return uav; - } - - static RenderUAV Texture3D(RenderFormat format = RenderFormat::UNKNOWN, uint32_t mipSlice = 0) { - RenderUAV uav(RenderUAVType::TEXTURE_3D, format); - uav.texture.mipSlice = mipSlice; - return uav; - } - }; - - struct RenderViewport { - float x = 0.0f; - float y = 0.0f; - float width = 0.0f; - float height = 0.0f; - float minDepth = 0.0f; - float maxDepth = 1.0f; - - RenderViewport() = default; - - RenderViewport(float x, float y, float width, float height, float minDepth = 0.0f, float maxDepth = 1.0f) { - this->x = x; - this->y = y; - this->width = width; - this->height = height; - this->minDepth = minDepth; - this->maxDepth = maxDepth; - } - - bool operator==(const RenderViewport &v) const { - return (x == v.x) && (y == v.y) && (width == v.width) && (height == v.height) && (minDepth == v.minDepth) && (maxDepth == v.maxDepth); - } - - bool operator!=(const RenderViewport &v) const { - return (x != v.x) || (y != v.y) || (width != v.width) || (height != v.height) || (minDepth != v.minDepth) || (maxDepth != v.maxDepth); - } - - bool isEmpty() const { - return (width <= 0.0f) || (height <= 0.0f); - } - }; - - struct RenderRect { - int32_t left = 0; - int32_t top = 0; - int32_t right = 0; - int32_t bottom = 0; - - RenderRect() = default; - - RenderRect(int32_t left, int32_t top, int32_t right, int32_t bottom) { - this->left = left; - this->top = top; - this->right = right; - this->bottom = bottom; - } - - bool operator==(const RenderRect &v) const { - return (left == v.left) && (top == v.top) && (right == v.right) && (bottom == v.bottom); - } - - bool operator!=(const RenderRect &v) const { - return (left != v.left) || (top != v.top) || (right != v.right) || (bottom != v.bottom); - } - - bool isEmpty() const { - return (left >= right) || (top >= bottom); - } - }; - - struct RenderBox { - int32_t left = 0; - int32_t top = 0; - int32_t front = 0; - int32_t right = 0; - int32_t bottom = 0; - int32_t back = 0; - - RenderBox() = default; - - RenderBox(int32_t left, int32_t top, int32_t right, int32_t bottom, int32_t front = 0, int32_t back = 1) { - this->left = left; - this->top = top; - this->front = front; - this->right = right; - this->bottom = bottom; - this->back = back; - } - }; - - struct RenderRange { - uint64_t begin = 0; - uint64_t end = 0; - - RenderRange() = default; - - RenderRange(uint64_t begin, uint64_t end) { - this->begin = begin; - this->end = end; - } - }; - - struct RenderFramebufferDesc { - const RenderTexture **colorAttachments = nullptr; - uint32_t colorAttachmentsCount = 0; - const RenderTexture *depthAttachment = nullptr; - bool depthAttachmentReadOnly = false; - - RenderFramebufferDesc() = default; - - RenderFramebufferDesc(const RenderTexture **colorAttachments, uint32_t colorAttachmentsCount, const RenderTexture *depthAttachment = nullptr, bool depthAttachmentReadOnly = false) { - this->colorAttachments = colorAttachments; - this->colorAttachmentsCount = colorAttachmentsCount; - this->depthAttachment = depthAttachment; - this->depthAttachmentReadOnly = depthAttachmentReadOnly; - } - }; - - struct RenderBottomLevelASMesh { - RenderBufferReference indexBuffer; - RenderBufferReference vertexBuffer; - RenderFormat indexFormat = RenderFormat::UNKNOWN; - RenderFormat vertexFormat = RenderFormat::UNKNOWN; - uint32_t indexCount = 0; - uint32_t vertexCount = 0; - uint32_t vertexStride = 0; - bool isOpaque = false; - - RenderBottomLevelASMesh() = default; - - RenderBottomLevelASMesh(RenderBufferReference indexBuffer, RenderBufferReference vertexBuffer, RenderFormat indexFormat, RenderFormat vertexFormat, uint32_t indexCount, uint32_t vertexCount, uint32_t vertexStride, bool isOpaque) { - this->indexBuffer = indexBuffer; - this->vertexBuffer = vertexBuffer; - this->indexFormat = indexFormat; - this->vertexFormat = vertexFormat; - this->indexCount = indexCount; - this->vertexCount = vertexCount; - this->vertexStride = vertexStride; - this->isOpaque = isOpaque; - } - }; - - struct RenderBottomLevelASBuildInfo { - uint32_t meshCount = 0; - uint32_t primitiveCount = 0; - bool preferFastBuild = false; - bool preferFastTrace = false; - uint64_t scratchSize = 0; - uint64_t accelerationStructureSize = 0; - - // Private backend data. Can go unused. - std::vector buildData; - }; - - struct RenderTopLevelASInstance { - RenderBufferReference bottomLevelAS; - uint32_t instanceID = 0; - uint32_t instanceMask = 0; - uint32_t instanceContributionToHitGroupIndex = 0; - bool cullDisable = false; - RenderAffineTransform transform; - - RenderTopLevelASInstance() = default; - - RenderTopLevelASInstance(RenderBufferReference bottomLevelAS, uint32_t instanceID, uint32_t instanceMask, uint32_t instanceContributionToHitGroupIndex, bool cullDisable, RenderAffineTransform transform) { - this->bottomLevelAS = bottomLevelAS; - this->instanceID = instanceID; - this->instanceMask = instanceMask; - this->instanceContributionToHitGroupIndex = instanceContributionToHitGroupIndex; - this->cullDisable = cullDisable; - this->transform = transform; - } - }; - - struct RenderTopLevelASBuildInfo { - // The instances buffer data must be uploaded to the GPU by the API user. - std::vector instancesBufferData; - uint32_t instanceCount = 0; - bool preferFastBuild = false; - bool preferFastTrace = false; - uint64_t scratchSize = 0; - uint64_t accelerationStructureSize = 0; - - // Private backend data. Can go unused. - std::vector buildData; - }; - - struct RenderShaderBindingGroup { - const RenderPipelineProgram *pipelinePrograms = nullptr; - uint32_t pipelineProgramsCount = 0; - - RenderShaderBindingGroup() = default; - - RenderShaderBindingGroup(const RenderPipelineProgram *pipelinePrograms, uint32_t pipelineProgramsCount) { - this->pipelinePrograms = pipelinePrograms; - this->pipelineProgramsCount = pipelineProgramsCount; - } - }; - - struct RenderShaderBindingGroups { - RenderShaderBindingGroup rayGen; - RenderShaderBindingGroup miss; - RenderShaderBindingGroup hitGroup; - RenderShaderBindingGroup callable; - - RenderShaderBindingGroups() = default; - - RenderShaderBindingGroups(RenderShaderBindingGroup rayGen, RenderShaderBindingGroup miss, RenderShaderBindingGroup hitGroup, RenderShaderBindingGroup callable = RenderShaderBindingGroup()) { - this->rayGen = rayGen; - this->miss = miss; - this->hitGroup = hitGroup; - this->callable = callable; - } - }; - - struct RenderShaderBindingGroupInfo { - uint64_t offset = 0; - uint64_t size = 0; - uint32_t stride = 0; - - // Convenience index for selecting a different binding in the table. offset must add startIndex * stride. - uint32_t startIndex = 0; - }; - - struct RenderShaderBindingGroupsInfo { - RenderShaderBindingGroupInfo rayGen; - RenderShaderBindingGroupInfo miss; - RenderShaderBindingGroupInfo hitGroup; - RenderShaderBindingGroupInfo callable; - }; - - struct RenderShaderBindingTableInfo { - // The table buffer data must be uploaded to the GPU by the API user and submitted to dispatchRays(). - std::vector tableBufferData; - - // This info will be requested by dispatchRays(). - RenderShaderBindingGroupsInfo groups; - }; - - struct RenderDeviceDescription { - std::string name = "Unknown"; - RenderDeviceType type = RenderDeviceType::UNKNOWN; - RenderDeviceVendor vendor = RenderDeviceVendor::UNKNOWN; - uint64_t driverVersion = 0; - uint64_t dedicatedVideoMemory = 0; - }; - - struct RenderDeviceCapabilities { - // Geometry shaders. - bool geometryShader = false; - - // Raytracing. - bool raytracing = false; - bool raytracingStateUpdate = false; - - // MSAA. - bool sampleLocations = false; - - // Bindless resources. - bool descriptorIndexing = false; - bool scalarBlockLayout = false; - - // Present. - bool presentWait = false; - bool displayTiming = false; - - // HDR. - bool preferHDR = false; - - // Draw. - bool triangleFan = false; - bool dynamicDepthBias = false; - - // UMA. - bool uma = false; - - // GPU Upload heap. - bool gpuUploadHeap = false; - }; - - struct RenderInterfaceCapabilities { - RenderShaderFormat shaderFormat = RenderShaderFormat::UNKNOWN; - }; -}; diff --git a/UnleashedRecomp/gpu/rhi/plume_vulkan.cpp b/UnleashedRecomp/gpu/rhi/plume_vulkan.cpp deleted file mode 100644 index 8613481..0000000 --- a/UnleashedRecomp/gpu/rhi/plume_vulkan.cpp +++ /dev/null @@ -1,4474 +0,0 @@ -// -// plume -// -// Copyright (c) 2024 renderbag and contributors. All rights reserved. -// Licensed under the MIT license. See LICENSE file for details. -// - -#define VMA_IMPLEMENTATION -#define VOLK_IMPLEMENTATION - -#include "plume_vulkan.h" - -#include -#include -#include -#include - -#if DLSS_ENABLED -# include "render/plume_dlss.h" -#endif - -#ifndef NDEBUG -# define VULKAN_VALIDATION_LAYER_ENABLED -//# define VULKAN_OBJECT_NAMES_ENABLED -#endif - -// TODO: -// - Fix resource pools. - -namespace plume { - // Backend constants. - - // Required buffer alignment for acceleration structures. - static const uint64_t AccelerationStructureBufferAlignment = 256; - - // Required buffer alignment for shader binding table. - static const uint64_t ShaderBindingTableAlignment = 256; - - // Controls the maximum amount of native queues the backend will create per queue family. - // Command queues are created as virtual queues on top of the native queues provided by Vulkan, - // so they're not under the limit set by the the device or the backend. - static const uint32_t MaxQueuesPerFamilyCount = 4; - - // Required extensions. - - static const std::unordered_set RequiredInstanceExtensions = { - VK_KHR_SURFACE_EXTENSION_NAME, -# if defined(_WIN64) - VK_KHR_WIN32_SURFACE_EXTENSION_NAME, -# elif defined(__ANDROID__) - VK_KHR_ANDROID_SURFACE_EXTENSION_NAME, -# elif defined(__linux__) - VK_KHR_XLIB_SURFACE_EXTENSION_NAME, -# elif defined(__APPLE__) - VK_EXT_METAL_SURFACE_EXTENSION_NAME, -# endif - }; - - static const std::unordered_set OptionalInstanceExtensions = { -# if defined(__APPLE__) - // Tells the system Vulkan loader to enumerate portability drivers, if supported. - VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME, -# endif - }; - - static const std::unordered_set RequiredDeviceExtensions = { - VK_KHR_SWAPCHAIN_EXTENSION_NAME, - VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME, - VK_EXT_ROBUSTNESS_2_EXTENSION_NAME, - VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME, - VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_EXTENSION_NAME, -# ifdef VULKAN_OBJECT_NAMES_ENABLED - VK_EXT_DEBUG_UTILS_EXTENSION_NAME -# endif - }; - - static const std::unordered_set OptionalDeviceExtensions = { - VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, - VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, - VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME, - VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME, - VK_EXT_SAMPLE_LOCATIONS_EXTENSION_NAME, - VK_EXT_LOAD_STORE_OP_NONE_EXTENSION_NAME, - VK_KHR_PRESENT_ID_EXTENSION_NAME, - VK_KHR_PRESENT_WAIT_EXTENSION_NAME, - VK_GOOGLE_DISPLAY_TIMING_EXTENSION_NAME, - // Vulkan spec requires this to be enabled if supported by the driver. - VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME, - }; - - // Common functions. - - static uint32_t roundUp(uint32_t value, uint32_t powerOf2Alignment) { - return (value + powerOf2Alignment - 1) & ~(powerOf2Alignment - 1); - } - - static uint64_t roundUp(uint64_t value, uint64_t powerOf2Alignment) { - return (value + powerOf2Alignment - 1) & ~(powerOf2Alignment - 1); - } - - VkFormat toVk(RenderFormat format) { - switch (format) { - case RenderFormat::UNKNOWN: - return VK_FORMAT_UNDEFINED; - case RenderFormat::R32G32B32A32_TYPELESS: - return VK_FORMAT_R32G32B32A32_SFLOAT; - case RenderFormat::R32G32B32A32_FLOAT: - return VK_FORMAT_R32G32B32A32_SFLOAT; - case RenderFormat::R32G32B32A32_UINT: - return VK_FORMAT_R32G32B32A32_UINT; - case RenderFormat::R32G32B32A32_SINT: - return VK_FORMAT_R32G32B32A32_SINT; - case RenderFormat::R32G32B32_TYPELESS: - return VK_FORMAT_R32G32B32_SFLOAT; - case RenderFormat::R32G32B32_FLOAT: - return VK_FORMAT_R32G32B32_SFLOAT; - case RenderFormat::R32G32B32_UINT: - return VK_FORMAT_R32G32B32_UINT; - case RenderFormat::R32G32B32_SINT: - return VK_FORMAT_R32G32B32_SINT; - case RenderFormat::R16G16B16A16_TYPELESS: - return VK_FORMAT_R16G16B16A16_SFLOAT; - case RenderFormat::R16G16B16A16_FLOAT: - return VK_FORMAT_R16G16B16A16_SFLOAT; - case RenderFormat::R16G16B16A16_UNORM: - return VK_FORMAT_R16G16B16A16_UNORM; - case RenderFormat::R16G16B16A16_UINT: - return VK_FORMAT_R16G16B16A16_UINT; - case RenderFormat::R16G16B16A16_SNORM: - return VK_FORMAT_R16G16B16A16_SNORM; - case RenderFormat::R16G16B16A16_SINT: - return VK_FORMAT_R16G16B16A16_SINT; - case RenderFormat::R32G32_TYPELESS: - return VK_FORMAT_R32G32_SFLOAT; - case RenderFormat::R32G32_FLOAT: - return VK_FORMAT_R32G32_SFLOAT; - case RenderFormat::R8G8B8A8_TYPELESS: - return VK_FORMAT_R8G8B8A8_UNORM; - case RenderFormat::R8G8B8A8_UNORM: - return VK_FORMAT_R8G8B8A8_UNORM; - case RenderFormat::R8G8B8A8_UINT: - return VK_FORMAT_R8G8B8A8_UINT; - case RenderFormat::R8G8B8A8_SNORM: - return VK_FORMAT_R8G8B8A8_SNORM; - case RenderFormat::R8G8B8A8_SINT: - return VK_FORMAT_R8G8B8A8_SINT; - case RenderFormat::B8G8R8A8_UNORM: - return VK_FORMAT_B8G8R8A8_UNORM; - case RenderFormat::R16G16_TYPELESS: - return VK_FORMAT_R16G16_SFLOAT; - case RenderFormat::R16G16_FLOAT: - return VK_FORMAT_R16G16_SFLOAT; - case RenderFormat::R16G16_UNORM: - return VK_FORMAT_R16G16_UNORM; - case RenderFormat::R16G16_UINT: - return VK_FORMAT_R16G16_UINT; - case RenderFormat::R16G16_SNORM: - return VK_FORMAT_R16G16_SNORM; - case RenderFormat::R16G16_SINT: - return VK_FORMAT_R16G16_SINT; - case RenderFormat::R32_TYPELESS: - return VK_FORMAT_R32_SFLOAT; - case RenderFormat::D32_FLOAT: - return VK_FORMAT_D32_SFLOAT; - case RenderFormat::R32_FLOAT: - return VK_FORMAT_R32_SFLOAT; - case RenderFormat::R32_UINT: - return VK_FORMAT_R32_UINT; - case RenderFormat::R32_SINT: - return VK_FORMAT_R32_SINT; - case RenderFormat::R8G8_TYPELESS: - return VK_FORMAT_R8G8_UNORM; - case RenderFormat::R8G8_UNORM: - return VK_FORMAT_R8G8_UNORM; - case RenderFormat::R8G8_UINT: - return VK_FORMAT_R8G8_UINT; - case RenderFormat::R8G8_SNORM: - return VK_FORMAT_R8G8_SNORM; - case RenderFormat::R8G8_SINT: - return VK_FORMAT_R8G8_SINT; - case RenderFormat::R16_TYPELESS: - return VK_FORMAT_R16_SFLOAT; - case RenderFormat::R16_FLOAT: - return VK_FORMAT_R16_SFLOAT; - case RenderFormat::D16_UNORM: - return VK_FORMAT_D16_UNORM; - case RenderFormat::R16_UNORM: - return VK_FORMAT_R16_UNORM; - case RenderFormat::R16_UINT: - return VK_FORMAT_R16_UINT; - case RenderFormat::R16_SNORM: - return VK_FORMAT_R16_SNORM; - case RenderFormat::R16_SINT: - return VK_FORMAT_R16_SINT; - case RenderFormat::R8_TYPELESS: - return VK_FORMAT_R8_UNORM; - case RenderFormat::R8_UNORM: - return VK_FORMAT_R8_UNORM; - case RenderFormat::R8_UINT: - return VK_FORMAT_R8_UINT; - case RenderFormat::R8_SNORM: - return VK_FORMAT_R8_SNORM; - case RenderFormat::R8_SINT: - return VK_FORMAT_R8_SINT; - case RenderFormat::BC1_TYPELESS: - return VK_FORMAT_BC1_RGBA_UNORM_BLOCK; - case RenderFormat::BC1_UNORM: - return VK_FORMAT_BC1_RGBA_UNORM_BLOCK; - case RenderFormat::BC1_UNORM_SRGB: - return VK_FORMAT_BC1_RGBA_SRGB_BLOCK; - case RenderFormat::BC2_TYPELESS: - return VK_FORMAT_BC2_UNORM_BLOCK; - case RenderFormat::BC2_UNORM: - return VK_FORMAT_BC2_UNORM_BLOCK; - case RenderFormat::BC2_UNORM_SRGB: - return VK_FORMAT_BC2_SRGB_BLOCK; - case RenderFormat::BC3_TYPELESS: - return VK_FORMAT_BC3_UNORM_BLOCK; - case RenderFormat::BC3_UNORM: - return VK_FORMAT_BC3_UNORM_BLOCK; - case RenderFormat::BC3_UNORM_SRGB: - return VK_FORMAT_BC3_SRGB_BLOCK; - case RenderFormat::BC4_TYPELESS: - return VK_FORMAT_BC4_UNORM_BLOCK; - case RenderFormat::BC4_UNORM: - return VK_FORMAT_BC4_UNORM_BLOCK; - case RenderFormat::BC4_SNORM: - return VK_FORMAT_BC4_SNORM_BLOCK; - case RenderFormat::BC5_TYPELESS: - return VK_FORMAT_BC5_UNORM_BLOCK; - case RenderFormat::BC5_UNORM: - return VK_FORMAT_BC5_UNORM_BLOCK; - case RenderFormat::BC5_SNORM: - return VK_FORMAT_BC5_SNORM_BLOCK; - case RenderFormat::BC6H_TYPELESS: - return VK_FORMAT_BC6H_UFLOAT_BLOCK; - case RenderFormat::BC6H_UF16: - return VK_FORMAT_BC6H_UFLOAT_BLOCK; - case RenderFormat::BC6H_SF16: - return VK_FORMAT_BC6H_SFLOAT_BLOCK; - case RenderFormat::BC7_TYPELESS: - return VK_FORMAT_BC7_UNORM_BLOCK; - case RenderFormat::BC7_UNORM: - return VK_FORMAT_BC7_UNORM_BLOCK; - case RenderFormat::BC7_UNORM_SRGB: - return VK_FORMAT_BC7_SRGB_BLOCK; - default: - assert(false && "Unknown format."); - return VK_FORMAT_UNDEFINED; - } - } - - static VkImageType toImageType(RenderTextureDimension dimension) { - switch (dimension) { - case RenderTextureDimension::TEXTURE_1D: - return VK_IMAGE_TYPE_1D; - case RenderTextureDimension::TEXTURE_2D: - return VK_IMAGE_TYPE_2D; - case RenderTextureDimension::TEXTURE_3D: - return VK_IMAGE_TYPE_3D; - default: - assert(false && "Unknown resource dimension."); - return VK_IMAGE_TYPE_MAX_ENUM; - } - } - - static VkImageViewType toImageViewType(RenderTextureDimension dimension) { - switch (dimension) { - case RenderTextureDimension::TEXTURE_1D: - return VK_IMAGE_VIEW_TYPE_1D; - case RenderTextureDimension::TEXTURE_2D: - return VK_IMAGE_VIEW_TYPE_2D; - case RenderTextureDimension::TEXTURE_3D: - return VK_IMAGE_VIEW_TYPE_3D; - default: - assert(false && "Unknown resource dimension."); - return VK_IMAGE_VIEW_TYPE_MAX_ENUM; - } - } - - static VkImageViewType toImageViewType(RenderTextureViewDimension dimension) { - switch (dimension) { - case RenderTextureViewDimension::TEXTURE_1D: - return VK_IMAGE_VIEW_TYPE_1D; - case RenderTextureViewDimension::TEXTURE_2D: - return VK_IMAGE_VIEW_TYPE_2D; - case RenderTextureViewDimension::TEXTURE_3D: - return VK_IMAGE_VIEW_TYPE_3D; - case RenderTextureViewDimension::TEXTURE_CUBE: - return VK_IMAGE_VIEW_TYPE_CUBE; - default: - assert(false && "Unknown resource dimension."); - return VK_IMAGE_VIEW_TYPE_MAX_ENUM; - } - } - - static VkImageTiling toVk(RenderTextureArrangement arrangement) { - switch (arrangement) { - case RenderTextureArrangement::UNKNOWN: - return VkImageTiling::VK_IMAGE_TILING_OPTIMAL; - case RenderTextureArrangement::ROW_MAJOR: - return VkImageTiling::VK_IMAGE_TILING_LINEAR; - default: - assert(false && "Unknown texture arrangement."); - return VkImageTiling::VK_IMAGE_TILING_MAX_ENUM; - } - } - - static VkVertexInputRate toVk(RenderInputSlotClassification classification) { - switch (classification) { - case RenderInputSlotClassification::PER_VERTEX_DATA: - return VK_VERTEX_INPUT_RATE_VERTEX; - case RenderInputSlotClassification::PER_INSTANCE_DATA: - return VK_VERTEX_INPUT_RATE_INSTANCE; - default: - assert(false && "Unknown input slot classification."); - return VK_VERTEX_INPUT_RATE_MAX_ENUM; - } - } - - static VkCullModeFlags toVk(RenderCullMode cullMode) { - switch (cullMode) { - case RenderCullMode::NONE: - return VK_CULL_MODE_NONE; - case RenderCullMode::FRONT: - return VK_CULL_MODE_FRONT_BIT; - case RenderCullMode::BACK: - return VK_CULL_MODE_BACK_BIT; - default: - assert(false && "Unknown cull mode."); - return VK_CULL_MODE_FLAG_BITS_MAX_ENUM; - } - } - - static VkPrimitiveTopology toVk(RenderPrimitiveTopology topology) { - switch (topology) { - case RenderPrimitiveTopology::POINT_LIST: - return VK_PRIMITIVE_TOPOLOGY_POINT_LIST; - case RenderPrimitiveTopology::LINE_LIST: - return VK_PRIMITIVE_TOPOLOGY_LINE_LIST; - case RenderPrimitiveTopology::LINE_STRIP: - return VK_PRIMITIVE_TOPOLOGY_LINE_STRIP; - case RenderPrimitiveTopology::TRIANGLE_LIST: - return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; - case RenderPrimitiveTopology::TRIANGLE_STRIP: - return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP; - case RenderPrimitiveTopology::TRIANGLE_FAN: - return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN; - default: - assert(false && "Unknown primitive topology type."); - return VK_PRIMITIVE_TOPOLOGY_MAX_ENUM; - } - } - - static VkBlendFactor toVk(RenderBlend blend) { - switch (blend) { - case RenderBlend::ZERO: - return VK_BLEND_FACTOR_ZERO; - case RenderBlend::ONE: - return VK_BLEND_FACTOR_ONE; - case RenderBlend::SRC_COLOR: - return VK_BLEND_FACTOR_SRC_COLOR; - case RenderBlend::INV_SRC_COLOR: - return VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR; - case RenderBlend::SRC_ALPHA: - return VK_BLEND_FACTOR_SRC_ALPHA; - case RenderBlend::INV_SRC_ALPHA: - return VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; - case RenderBlend::DEST_ALPHA: - return VK_BLEND_FACTOR_DST_ALPHA; - case RenderBlend::INV_DEST_ALPHA: - return VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA; - case RenderBlend::DEST_COLOR: - return VK_BLEND_FACTOR_DST_COLOR; - case RenderBlend::INV_DEST_COLOR: - return VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR; - case RenderBlend::SRC_ALPHA_SAT: - return VK_BLEND_FACTOR_SRC_ALPHA_SATURATE; - case RenderBlend::BLEND_FACTOR: - return VK_BLEND_FACTOR_CONSTANT_COLOR; - case RenderBlend::INV_BLEND_FACTOR: - return VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR; - case RenderBlend::SRC1_COLOR: - return VK_BLEND_FACTOR_SRC1_COLOR; - case RenderBlend::INV_SRC1_COLOR: - return VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR; - case RenderBlend::SRC1_ALPHA: - return VK_BLEND_FACTOR_SRC1_ALPHA; - case RenderBlend::INV_SRC1_ALPHA: - return VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA; - default: - assert(false && "Unknown blend factor."); - return VK_BLEND_FACTOR_MAX_ENUM; - } - } - - static VkBlendOp toVk(RenderBlendOperation operation) { - switch (operation) { - case RenderBlendOperation::ADD: - return VK_BLEND_OP_ADD; - case RenderBlendOperation::SUBTRACT: - return VK_BLEND_OP_SUBTRACT; - case RenderBlendOperation::REV_SUBTRACT: - return VK_BLEND_OP_REVERSE_SUBTRACT; - case RenderBlendOperation::MIN: - return VK_BLEND_OP_MIN; - case RenderBlendOperation::MAX: - return VK_BLEND_OP_MAX; - default: - assert(false && "Unknown blend operation."); - return VK_BLEND_OP_MAX_ENUM; - } - } - - static VkLogicOp toVk(RenderLogicOperation operation) { - switch (operation) { - case RenderLogicOperation::CLEAR: - return VK_LOGIC_OP_CLEAR; - case RenderLogicOperation::SET: - return VK_LOGIC_OP_SET; - case RenderLogicOperation::COPY: - return VK_LOGIC_OP_COPY; - case RenderLogicOperation::COPY_INVERTED: - return VK_LOGIC_OP_COPY_INVERTED; - case RenderLogicOperation::NOOP: - return VK_LOGIC_OP_NO_OP; - case RenderLogicOperation::INVERT: - return VK_LOGIC_OP_INVERT; - case RenderLogicOperation::AND: - return VK_LOGIC_OP_AND; - case RenderLogicOperation::NAND: - return VK_LOGIC_OP_NAND; - case RenderLogicOperation::OR: - return VK_LOGIC_OP_OR; - case RenderLogicOperation::NOR: - return VK_LOGIC_OP_NOR; - case RenderLogicOperation::XOR: - return VK_LOGIC_OP_XOR; - case RenderLogicOperation::EQUIV: - return VK_LOGIC_OP_EQUIVALENT; - case RenderLogicOperation::AND_REVERSE: - return VK_LOGIC_OP_AND_REVERSE; - case RenderLogicOperation::AND_INVERTED: - return VK_LOGIC_OP_AND_INVERTED; - case RenderLogicOperation::OR_REVERSE: - return VK_LOGIC_OP_OR_REVERSE; - case RenderLogicOperation::OR_INVERTED: - return VK_LOGIC_OP_OR_INVERTED; - default: - assert(false && "Unknown logic operation."); - return VK_LOGIC_OP_MAX_ENUM; - } - } - - static VkCompareOp toVk(RenderComparisonFunction function) { - switch (function) { - case RenderComparisonFunction::NEVER: - return VK_COMPARE_OP_NEVER; - case RenderComparisonFunction::LESS: - return VK_COMPARE_OP_LESS; - case RenderComparisonFunction::EQUAL: - return VK_COMPARE_OP_EQUAL; - case RenderComparisonFunction::LESS_EQUAL: - return VK_COMPARE_OP_LESS_OR_EQUAL; - case RenderComparisonFunction::GREATER: - return VK_COMPARE_OP_GREATER; - case RenderComparisonFunction::NOT_EQUAL: - return VK_COMPARE_OP_NOT_EQUAL; - case RenderComparisonFunction::GREATER_EQUAL: - return VK_COMPARE_OP_GREATER_OR_EQUAL; - case RenderComparisonFunction::ALWAYS: - return VK_COMPARE_OP_ALWAYS; - default: - assert(false && "Unknown comparison function."); - return VK_COMPARE_OP_MAX_ENUM; - } - } - - static VkDescriptorType toVk(RenderDescriptorRangeType type) { - switch (type) { - case RenderDescriptorRangeType::CONSTANT_BUFFER: - return VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - case RenderDescriptorRangeType::FORMATTED_BUFFER: - return VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER; - case RenderDescriptorRangeType::READ_WRITE_FORMATTED_BUFFER: - return VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER; - case RenderDescriptorRangeType::TEXTURE: - return VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; - case RenderDescriptorRangeType::READ_WRITE_TEXTURE: - return VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; - case RenderDescriptorRangeType::SAMPLER: - return VK_DESCRIPTOR_TYPE_SAMPLER; - case RenderDescriptorRangeType::STRUCTURED_BUFFER: - return VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; - case RenderDescriptorRangeType::READ_WRITE_STRUCTURED_BUFFER: - return VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; - case RenderDescriptorRangeType::BYTE_ADDRESS_BUFFER: - return VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; - case RenderDescriptorRangeType::READ_WRITE_BYTE_ADDRESS_BUFFER: - return VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; - case RenderDescriptorRangeType::ACCELERATION_STRUCTURE: - return VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR; - default: - assert(false && "Unknown descriptor range type."); - return VK_DESCRIPTOR_TYPE_MAX_ENUM; - } - } - - static VkFilter toVk(RenderFilter filter) { - switch (filter) { - case RenderFilter::NEAREST: - return VK_FILTER_NEAREST; - case RenderFilter::LINEAR: - return VK_FILTER_LINEAR; - default: - assert(false && "Unknown filter."); - return VK_FILTER_MAX_ENUM; - } - } - - static VkSamplerMipmapMode toVk(RenderMipmapMode mode) { - switch (mode) { - case RenderMipmapMode::NEAREST: - return VK_SAMPLER_MIPMAP_MODE_NEAREST; - case RenderMipmapMode::LINEAR: - return VK_SAMPLER_MIPMAP_MODE_LINEAR; - default: - assert(false && "Unknown mipmap mode."); - return VK_SAMPLER_MIPMAP_MODE_MAX_ENUM; - } - } - - static VkSamplerAddressMode toVk(RenderTextureAddressMode mode) { - switch (mode) { - case RenderTextureAddressMode::WRAP: - return VK_SAMPLER_ADDRESS_MODE_REPEAT; - case RenderTextureAddressMode::MIRROR: - return VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT; - case RenderTextureAddressMode::CLAMP: - return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; - case RenderTextureAddressMode::BORDER: - return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; - case RenderTextureAddressMode::MIRROR_ONCE: - return VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE; - default: - assert(false && "Unknown texture address mode."); - return VK_SAMPLER_ADDRESS_MODE_MAX_ENUM; - } - } - - static VkBorderColor toVk(RenderBorderColor color) { - switch (color) { - case RenderBorderColor::TRANSPARENT_BLACK: - return VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK; - case RenderBorderColor::OPAQUE_BLACK: - return VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK; - case RenderBorderColor::OPAQUE_WHITE: - return VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE; - default: - assert(false && "Unknown border color."); - return VK_BORDER_COLOR_MAX_ENUM; - } - } - - static VkAccelerationStructureTypeKHR toVk(RenderAccelerationStructureType type) { - switch (type) { - case RenderAccelerationStructureType::TOP_LEVEL: - return VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR; - case RenderAccelerationStructureType::BOTTOM_LEVEL: - return VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR; - default: - assert(false && "Unknown acceleration structure type."); - return VK_ACCELERATION_STRUCTURE_TYPE_MAX_ENUM_KHR; - } - } - - static VkPipelineStageFlags toStageFlags(RenderBarrierStages stages, bool geometrySupported, bool rtSupported) { - VkPipelineStageFlags flags = 0; - - if (stages & RenderBarrierStage::GRAPHICS) { - flags |= VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT; - flags |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT; - flags |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT; - if (geometrySupported) { - flags |= VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT; - } - flags |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; - flags |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT; - flags |= VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; - flags |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - } - - if (stages & RenderBarrierStage::COMPUTE) { - flags |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; - - if (rtSupported) { - flags |= VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR; - flags |= VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR; - } - } - - if (stages & RenderBarrierStage::COPY) { - flags |= VK_PIPELINE_STAGE_TRANSFER_BIT; - flags |= VK_PIPELINE_STAGE_HOST_BIT; - } - - return flags; - } - - static VkShaderStageFlagBits toStage(RenderRaytracingPipelineLibrarySymbolType type) { - switch (type) { - case RenderRaytracingPipelineLibrarySymbolType::RAYGEN: - return VK_SHADER_STAGE_RAYGEN_BIT_KHR; - case RenderRaytracingPipelineLibrarySymbolType::MISS: - return VK_SHADER_STAGE_MISS_BIT_KHR; - case RenderRaytracingPipelineLibrarySymbolType::CLOSEST_HIT: - return VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR; - case RenderRaytracingPipelineLibrarySymbolType::ANY_HIT: - return VK_SHADER_STAGE_ANY_HIT_BIT_KHR; - case RenderRaytracingPipelineLibrarySymbolType::INTERSECTION: - return VK_SHADER_STAGE_INTERSECTION_BIT_KHR; - case RenderRaytracingPipelineLibrarySymbolType::CALLABLE: - return VK_SHADER_STAGE_CALLABLE_BIT_KHR; - default: - assert(false && "Unknown raytracing pipeline library symbol type."); - return VkShaderStageFlagBits(0); - } - } - - static uint32_t toFamilyIndex(RenderCommandListType type) { - switch (type) { - case RenderCommandListType::DIRECT: - return 0; - case RenderCommandListType::COMPUTE: - return 1; - case RenderCommandListType::COPY: - return 2; - default: - assert(false && "Unknown command list type."); - return 0; - } - } - - static VkIndexType toIndexType(RenderFormat format) { - switch (format) { - case RenderFormat::R8_UINT: - return VK_INDEX_TYPE_UINT8_EXT; - case RenderFormat::R16_UINT: - return VK_INDEX_TYPE_UINT16; - case RenderFormat::R32_UINT: - return VK_INDEX_TYPE_UINT32; - default: - assert(false && "Format is not supported as an index type."); - return VK_INDEX_TYPE_MAX_ENUM; - } - } - - static VkBuildAccelerationStructureFlagsKHR toRTASBuildFlags(bool preferFastBuild, bool preferFastTrace) { - VkBuildAccelerationStructureFlagsKHR flags = 0; - flags |= preferFastBuild ? VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_KHR : 0; - flags |= preferFastTrace ? VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR : 0; - return flags; - } - - static VkImageLayout toImageLayout(RenderTextureLayout layout) { - switch (layout) { - case RenderTextureLayout::UNKNOWN: - return VK_IMAGE_LAYOUT_UNDEFINED; - case RenderTextureLayout::GENERAL: - return VK_IMAGE_LAYOUT_GENERAL; - case RenderTextureLayout::SHADER_READ: - return VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - case RenderTextureLayout::COLOR_WRITE: - return VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - case RenderTextureLayout::DEPTH_WRITE: - return VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - case RenderTextureLayout::DEPTH_READ: - return VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL; - case RenderTextureLayout::COPY_SOURCE: - return VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; - case RenderTextureLayout::COPY_DEST: - return VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; - case RenderTextureLayout::RESOLVE_SOURCE: - return VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; - case RenderTextureLayout::RESOLVE_DEST: - return VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; - case RenderTextureLayout::PRESENT: - return VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; - default: - assert(false && "Unknown texture layout."); - return VK_IMAGE_LAYOUT_UNDEFINED; - } - } - - static VkComponentSwizzle toVk(RenderSwizzle swizzle) { - switch (swizzle) { - case RenderSwizzle::IDENTITY: - return VK_COMPONENT_SWIZZLE_IDENTITY; - case RenderSwizzle::ZERO: - return VK_COMPONENT_SWIZZLE_ZERO; - case RenderSwizzle::ONE: - return VK_COMPONENT_SWIZZLE_ONE; - case RenderSwizzle::R: - return VK_COMPONENT_SWIZZLE_R; - case RenderSwizzle::G: - return VK_COMPONENT_SWIZZLE_G; - case RenderSwizzle::B: - return VK_COMPONENT_SWIZZLE_B; - case RenderSwizzle::A: - return VK_COMPONENT_SWIZZLE_A; - default: - assert(false && "Unknown swizzle type."); - return VK_COMPONENT_SWIZZLE_IDENTITY; - } - } - - static RenderDeviceType toDeviceType(VkPhysicalDeviceType type) { - switch (type) { - case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU: - return RenderDeviceType::INTEGRATED; - case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU: - return RenderDeviceType::DISCRETE; - case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU: - return RenderDeviceType::VIRTUAL; - case VK_PHYSICAL_DEVICE_TYPE_CPU: - return RenderDeviceType::CPU; - default: - return RenderDeviceType::UNKNOWN; - } - } - - static void setObjectName(VkDevice device, VkDebugReportObjectTypeEXT objectType, uint64_t object, const std::string &name) { -# ifdef VULKAN_OBJECT_NAMES_ENABLED - VkDebugMarkerObjectNameInfoEXT nameInfo = {}; - nameInfo.sType = VK_STRUCTURE_TYPE_DEBUG_MARKER_OBJECT_NAME_INFO_EXT; - nameInfo.objectType = objectType; - nameInfo.object = object; - nameInfo.pObjectName = name.c_str(); - VkResult res = vkDebugMarkerSetObjectNameEXT(device, &nameInfo); - if (res != VK_SUCCESS) { - fprintf(stderr, "vkDebugMarkerSetObjectNameEXT failed with error code 0x%X.\n", res); - return; - } -# endif - } - - static void fillSpecInfo(const RenderSpecConstant *specConstants, uint32_t specConstantsCount, - VkSpecializationInfo &specInfo, VkSpecializationMapEntry *specEntries, uint32_t *specData) - { - for (uint32_t i = 0; i < specConstantsCount; i++) { - VkSpecializationMapEntry &entry = specEntries[i]; - entry.constantID = specConstants[i].index; - entry.offset = i * sizeof(uint32_t); - entry.size = sizeof(uint32_t); - specData[i] = specConstants[i].value; - } - - specInfo.mapEntryCount = specConstantsCount; - specInfo.pMapEntries = specEntries; - specInfo.dataSize = specConstantsCount * sizeof(uint32_t); - specInfo.pData = specData; - } - - // Underlying implementation for popcount - // https://stackoverflow.com/questions/109023/how-to-count-the-number-of-set-bits-in-a-32-bit-integer - static int numberOfSetBits(uint32_t i) { - i = i - ((i >> 1) & 0x55555555); - i = (i & 0x33333333) + ((i >> 2) & 0x33333333); - return (((i + (i >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24; - } - - // VulkanBuffer - - VulkanBuffer::VulkanBuffer(VulkanDevice *device, VulkanPool *pool, const RenderBufferDesc &desc) { - assert(device != nullptr); - - this->device = device; - this->pool = pool; - this->desc = desc; - - const RenderBufferFlags storageFormattedMask = (RenderBufferFlag::STORAGE | RenderBufferFlag::FORMATTED); - VkBufferCreateInfo bufferInfo = {}; - bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; - bufferInfo.size = desc.size; - bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - bufferInfo.usage |= (desc.flags & RenderBufferFlag::VERTEX) ? VK_BUFFER_USAGE_VERTEX_BUFFER_BIT : 0; - bufferInfo.usage |= (desc.flags & RenderBufferFlag::INDEX) ? VK_BUFFER_USAGE_INDEX_BUFFER_BIT : 0; - bufferInfo.usage |= (desc.flags & RenderBufferFlag::STORAGE) ? VK_BUFFER_USAGE_STORAGE_BUFFER_BIT : 0; - bufferInfo.usage |= (desc.flags & RenderBufferFlag::CONSTANT) ? VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT : 0; - bufferInfo.usage |= (desc.flags & RenderBufferFlag::FORMATTED) ? VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT : 0; - bufferInfo.usage |= ((desc.flags & storageFormattedMask) == storageFormattedMask) ? VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT : 0; - bufferInfo.usage |= (desc.flags & RenderBufferFlag::ACCELERATION_STRUCTURE) ? VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR : 0; - bufferInfo.usage |= (desc.flags & RenderBufferFlag::ACCELERATION_STRUCTURE_SCRATCH) ? VK_BUFFER_USAGE_STORAGE_BUFFER_BIT : 0; - bufferInfo.usage |= (desc.flags & RenderBufferFlag::ACCELERATION_STRUCTURE_INPUT) ? VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR : 0; - bufferInfo.usage |= (desc.flags & RenderBufferFlag::SHADER_BINDING_TABLE) ? VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR : 0; - - const uint32_t deviceAddressMask = RenderBufferFlag::CONSTANT | RenderBufferFlag::ACCELERATION_STRUCTURE | RenderBufferFlag::ACCELERATION_STRUCTURE_SCRATCH | RenderBufferFlag::ACCELERATION_STRUCTURE_INPUT | RenderBufferFlag::SHADER_BINDING_TABLE; - bufferInfo.usage |= (desc.flags & deviceAddressMask) ? VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT : 0; - - VmaAllocationCreateInfo createInfo = {}; - /* TODO: Debug pools. - createInfo.pool = (pool != nullptr) ? pool->vk : VK_NULL_HANDLE; - */ - createInfo.usage = VMA_MEMORY_USAGE_AUTO; - - switch (desc.heapType) { - case RenderHeapType::DEFAULT: - bufferInfo.usage |= VK_BUFFER_USAGE_TRANSFER_SRC_BIT; - bufferInfo.usage |= VK_BUFFER_USAGE_TRANSFER_DST_BIT; - createInfo.preferredFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; - break; - case RenderHeapType::UPLOAD: - bufferInfo.usage |= VK_BUFFER_USAGE_TRANSFER_SRC_BIT; - createInfo.flags |= VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT; - break; - case RenderHeapType::READBACK: - bufferInfo.usage |= VK_BUFFER_USAGE_TRANSFER_DST_BIT; - createInfo.flags |= VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT; - break; - case RenderHeapType::GPU_UPLOAD: - bufferInfo.usage |= VK_BUFFER_USAGE_TRANSFER_SRC_BIT; - bufferInfo.usage |= VK_BUFFER_USAGE_TRANSFER_DST_BIT; - createInfo.flags |= VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT; - createInfo.requiredFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT; - break; - default: - assert(false && "Unknown heap type."); - break; - } - - if (desc.committed) { - createInfo.flags |= VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT; - } - - VkDeviceSize minAlignment = 0; - - // The specification imposes an alignment requirement for SBTs. - if (desc.flags & RenderBufferFlag::SHADER_BINDING_TABLE) { - minAlignment = device->rtPipelineProperties.shaderGroupBaseAlignment; - } - - VkResult res; - if (minAlignment > 0) { - res = vmaCreateBufferWithAlignment(device->allocator, &bufferInfo, &createInfo, minAlignment, &vk, &allocation, &allocationInfo); - } - else { - res = vmaCreateBuffer(device->allocator, &bufferInfo, &createInfo, &vk, &allocation, &allocationInfo); - } - - if (res != VK_SUCCESS) { - fprintf(stderr, "vmaCreateBuffer failed with error code 0x%X.\n", res); - return; - } - } - - VulkanBuffer::~VulkanBuffer() { - if (vk != VK_NULL_HANDLE) { - vmaDestroyBuffer(device->allocator, vk, allocation); - } - } - - void *VulkanBuffer::map(uint32_t subresource, const RenderRange *readRange) { - void *data = nullptr; - VkResult res = vmaMapMemory(device->allocator, allocation, &data); - if (res != VK_SUCCESS) { - fprintf(stderr, "vmaMapMemory failed with error code 0x%X.\n", res); - return nullptr; - } - - return data; - } - - void VulkanBuffer::unmap(uint32_t subresource, const RenderRange *writtenRange) { - vmaUnmapMemory(device->allocator, allocation); - } - - std::unique_ptr VulkanBuffer::createBufferFormattedView(RenderFormat format) { - return std::make_unique(this, format); - } - - void VulkanBuffer::setName(const std::string &name) { - setObjectName(device->vk, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, uint64_t(vk), name); - } - - uint64_t VulkanBuffer::getDeviceAddress() const { - VkBufferDeviceAddressInfo info; - info.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO; - info.pNext = nullptr; - info.buffer = vk; - return vkGetBufferDeviceAddress(device->vk, &info); - } - - // VulkanBufferFormattedView - - VulkanBufferFormattedView::VulkanBufferFormattedView(VulkanBuffer *buffer, RenderFormat format) { - assert(buffer != nullptr); - assert((buffer->desc.flags & RenderBufferFlag::FORMATTED) && "Buffer must allow formatted views."); - - this->buffer = buffer; - - VkBufferViewCreateInfo createInfo = {}; - createInfo.sType = VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO; - createInfo.buffer = buffer->vk; - createInfo.format = toVk(format); - createInfo.offset = 0; - createInfo.range = buffer->desc.size; - - VkResult res = vkCreateBufferView(buffer->device->vk, &createInfo, nullptr, &vk); - if (res != VK_SUCCESS) { - fprintf(stderr, "vkCreateBufferView failed with error code 0x%X.\n", res); - return; - } - } - - VulkanBufferFormattedView::~VulkanBufferFormattedView() { - if (vk != VK_NULL_HANDLE) { - vkDestroyBufferView(buffer->device->vk, vk, nullptr); - } - } - - // VulkanTexture - - VulkanTexture::VulkanTexture(VulkanDevice *device, VulkanPool *pool, const RenderTextureDesc &desc) { - assert(device != nullptr); - - this->device = device; - this->pool = pool; - this->desc = desc; - this->ownership = true; - - VkImageCreateInfo imageInfo = {}; - imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; - imageInfo.imageType = toImageType(desc.dimension); - imageInfo.format = toVk(desc.format); - imageInfo.extent.width = uint32_t(desc.width); - imageInfo.extent.height = desc.height; - imageInfo.extent.depth = desc.depth; - imageInfo.mipLevels = desc.mipLevels; - imageInfo.arrayLayers = desc.arraySize; - imageInfo.samples = VkSampleCountFlagBits(desc.multisampling.sampleCount); - imageInfo.tiling = toVk(desc.textureArrangement); - imageInfo.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; - imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - imageInfo.usage |= (desc.flags & RenderTextureFlag::RENDER_TARGET) ? VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT : 0; - imageInfo.usage |= (desc.flags & RenderTextureFlag::DEPTH_TARGET) ? VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT : 0; - imageInfo.usage |= (desc.flags & RenderTextureFlag::STORAGE) ? VK_IMAGE_USAGE_STORAGE_BIT : 0; - - if (desc.multisampling.sampleLocationsEnabled && (desc.flags & RenderTextureFlag::DEPTH_TARGET)) { - imageInfo.flags |= VK_IMAGE_CREATE_SAMPLE_LOCATIONS_COMPATIBLE_DEPTH_BIT_EXT; - } - - if (desc.flags & RenderTextureFlag::CUBE) { - imageInfo.flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT; - } - - imageFormat = imageInfo.format; - fillSubresourceRange(); - - VmaAllocationCreateInfo createInfo = {}; - createInfo.pool = (pool != nullptr) ? pool->vk : VK_NULL_HANDLE; - createInfo.preferredFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; - - if (desc.committed) { - createInfo.flags |= VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT; - } - - VkResult res = vmaCreateImage(device->allocator, &imageInfo, &createInfo, &vk, &allocation, &allocationInfo); - if (res != VK_SUCCESS) { - fprintf(stderr, "vmaCreateImage failed with error code 0x%X.\n", res); - return; - } - - createImageView(imageInfo.format); - } - - VulkanTexture::VulkanTexture(VulkanDevice *device, VkImage image) { - assert(device != nullptr); - assert(image != VK_NULL_HANDLE); - - this->device = device; - vk = image; - } - - VulkanTexture::~VulkanTexture() { - if (imageView != VK_NULL_HANDLE) { - vkDestroyImageView(device->vk, imageView, nullptr); - } - - if (ownership && (vk != VK_NULL_HANDLE)) { - vmaDestroyImage(device->allocator, vk, allocation); - } - } - - void VulkanTexture::createImageView(VkFormat format) { - VkImageView view = VK_NULL_HANDLE; - VkImageViewCreateInfo viewInfo = {}; - viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; - viewInfo.image = vk; - viewInfo.viewType = toImageViewType(desc.dimension); - viewInfo.format = format; - viewInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY; - viewInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY; - viewInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY; - viewInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY; - viewInfo.subresourceRange = imageSubresourceRange; - - VkResult res = vkCreateImageView(device->vk, &viewInfo, nullptr, &imageView); - if (res != VK_SUCCESS) { - fprintf(stderr, "vkCreateImageView failed with error code 0x%X.\n", res); - return; - } - } - - std::unique_ptr VulkanTexture::createTextureView(const RenderTextureViewDesc &desc) { - return std::make_unique(this, desc); - } - - void VulkanTexture::setName(const std::string &name) { - setObjectName(device->vk, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, uint64_t(vk), name); - } - - void VulkanTexture::fillSubresourceRange() { - imageSubresourceRange.aspectMask = (desc.flags & RenderTextureFlag::DEPTH_TARGET) ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT; - imageSubresourceRange.baseMipLevel = 0; - imageSubresourceRange.levelCount = desc.mipLevels; - imageSubresourceRange.baseArrayLayer = 0; - imageSubresourceRange.layerCount = 1; - } - - // VulkanTextureView - - VulkanTextureView::VulkanTextureView(VulkanTexture *texture, const RenderTextureViewDesc &desc) { - assert(texture != nullptr); - - this->texture = texture; - - VkImageViewCreateInfo viewInfo = {}; - viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; - viewInfo.image = texture->vk; - viewInfo.viewType = toImageViewType(desc.dimension); - viewInfo.format = toVk(desc.format); - viewInfo.components.r = toVk(desc.componentMapping.r); - viewInfo.components.g = toVk(desc.componentMapping.g); - viewInfo.components.b = toVk(desc.componentMapping.b); - viewInfo.components.a = toVk(desc.componentMapping.a); - viewInfo.subresourceRange.aspectMask = (texture->desc.flags & RenderTextureFlag::DEPTH_TARGET) ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT; - viewInfo.subresourceRange.baseMipLevel = desc.mipSlice; - viewInfo.subresourceRange.levelCount = desc.mipLevels; - viewInfo.subresourceRange.baseArrayLayer = 0; - viewInfo.subresourceRange.layerCount = texture->desc.arraySize; - - VkResult res = vkCreateImageView(texture->device->vk, &viewInfo, nullptr, &vk); - if (res != VK_SUCCESS) { - fprintf(stderr, "vkCreateImageView failed with error code 0x%X.\n", res); - return; - } - } - - VulkanTextureView::~VulkanTextureView() { - if (vk != VK_NULL_HANDLE) { - vkDestroyImageView(texture->device->vk, vk, nullptr); - } - } - - // VulkanAccelerationStructure - - VulkanAccelerationStructure::VulkanAccelerationStructure(VulkanDevice *device, const RenderAccelerationStructureDesc &desc) { - assert(device != nullptr); - assert(desc.buffer.ref != nullptr); - - this->device = device; - this->type = desc.type; - - const VulkanBuffer *interfaceBuffer = static_cast(desc.buffer.ref); - VkAccelerationStructureCreateInfoKHR createInfo = {}; - createInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_KHR; - createInfo.buffer = interfaceBuffer->vk; - createInfo.offset = desc.buffer.offset; - createInfo.size = desc.size; - createInfo.type = toVk(desc.type); - - VkResult res = vkCreateAccelerationStructureKHR(device->vk, &createInfo, nullptr, &vk); - if (res != VK_SUCCESS) { - fprintf(stderr, "vkCreateAccelerationStructureKHR failed with error code 0x%X.\n", res); - return; - } - } - - VulkanAccelerationStructure::~VulkanAccelerationStructure() { - if (vk != VK_NULL_HANDLE) { - vkDestroyAccelerationStructureKHR(device->vk, vk, nullptr); - } - } - - // VulkanDescriptorSetLayout - - VulkanDescriptorSetLayout::VulkanDescriptorSetLayout(VulkanDevice *device, const RenderDescriptorSetDesc &descriptorSetDesc) { - assert(device != nullptr); - - this->device = device; - - // Gather immutable sampler handles. - thread_local std::vector samplerHandles; - samplerHandles.clear(); - - for (uint32_t i = 0; i < descriptorSetDesc.descriptorRangesCount; i++) { - const RenderDescriptorRange &srcRange = descriptorSetDesc.descriptorRanges[i]; - if (srcRange.immutableSampler != nullptr) { - for (uint32_t j = 0; j < srcRange.count; j++) { - const VulkanSampler *interfaceSampler = static_cast(srcRange.immutableSampler[j]); - assert(interfaceSampler != nullptr); - samplerHandles.emplace_back(interfaceSampler->vk); - } - } - } - - // Create bindings. - uint32_t immutableSamplerIndex = 0; - for (uint32_t i = 0; i < descriptorSetDesc.descriptorRangesCount; i++) { - const RenderDescriptorRange &srcRange = descriptorSetDesc.descriptorRanges[i]; - VkDescriptorSetLayoutBinding dstBinding = {}; - dstBinding.binding = srcRange.binding; - dstBinding.descriptorCount = srcRange.count; - dstBinding.stageFlags = VK_SHADER_STAGE_ALL; - dstBinding.descriptorType = toVk(srcRange.type); - if (srcRange.immutableSampler != nullptr) { - dstBinding.pImmutableSamplers = &samplerHandles[immutableSamplerIndex]; - immutableSamplerIndex += srcRange.count; - } - - uint32_t indexBase = uint32_t(descriptorIndexBases.size()); - uint32_t bindingIndex = uint32_t(setBindings.size()); - for (uint32_t j = 0; j < srcRange.count; j++) { - descriptorIndexBases.emplace_back(indexBase); - descriptorBindingIndices.emplace_back(bindingIndex); - } - - setBindings.emplace_back(dstBinding); - } - - VkDescriptorSetLayoutCreateInfo setLayoutInfo = {}; - setLayoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; - setLayoutInfo.pBindings = !setBindings.empty() ? setBindings.data() : nullptr; - setLayoutInfo.bindingCount = uint32_t(setBindings.size()); - - thread_local std::vector bindingFlags; - VkDescriptorSetLayoutBindingFlagsCreateInfo flagsInfo = {}; - if (descriptorSetDesc.lastRangeIsBoundless && (descriptorSetDesc.descriptorRangesCount > 0)) { - bindingFlags.clear(); - bindingFlags.resize(descriptorSetDesc.descriptorRangesCount, 0); - bindingFlags[descriptorSetDesc.descriptorRangesCount - 1] = VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT | VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT | VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT; - - flagsInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO; - flagsInfo.pBindingFlags = bindingFlags.data(); - flagsInfo.bindingCount = uint32_t(bindingFlags.size()); - - setLayoutInfo.pNext = &flagsInfo; - setLayoutInfo.flags = VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT; - } - - VkResult res = vkCreateDescriptorSetLayout(device->vk, &setLayoutInfo, nullptr, &vk); - if (res != VK_SUCCESS) { - fprintf(stderr, "vkCreateDescriptorSetLayout failed with error code 0x%X.\n", res); - return; - } - } - - VulkanDescriptorSetLayout::~VulkanDescriptorSetLayout() { - if (vk != VK_NULL_HANDLE) { - vkDestroyDescriptorSetLayout(device->vk, vk, nullptr); - } - } - - // VulkanPipelineLayout - - VulkanPipelineLayout::VulkanPipelineLayout(VulkanDevice *device, const RenderPipelineLayoutDesc &desc) { - assert(device != nullptr); - - this->device = device; - - VkPipelineLayoutCreateInfo layoutInfo = {}; - layoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; - - for (uint32_t i = 0; i < desc.pushConstantRangesCount; i++) { - const RenderPushConstantRange &srcRange = desc.pushConstantRanges[i]; - VkPushConstantRange dstRange = {}; - dstRange.size = srcRange.size; - dstRange.offset = srcRange.offset; - dstRange.stageFlags |= (srcRange.stageFlags & RenderShaderStageFlag::VERTEX) ? VK_SHADER_STAGE_VERTEX_BIT : 0; - dstRange.stageFlags |= (srcRange.stageFlags & RenderShaderStageFlag::GEOMETRY) ? VK_SHADER_STAGE_GEOMETRY_BIT : 0; - dstRange.stageFlags |= (srcRange.stageFlags & RenderShaderStageFlag::PIXEL) ? VK_SHADER_STAGE_FRAGMENT_BIT : 0; - dstRange.stageFlags |= (srcRange.stageFlags & RenderShaderStageFlag::COMPUTE) ? VK_SHADER_STAGE_COMPUTE_BIT : 0; - dstRange.stageFlags |= (srcRange.stageFlags & RenderShaderStageFlag::RAYGEN) ? VK_SHADER_STAGE_RAYGEN_BIT_KHR : 0; - dstRange.stageFlags |= (srcRange.stageFlags & RenderShaderStageFlag::ANY_HIT) ? VK_SHADER_STAGE_ANY_HIT_BIT_KHR : 0; - dstRange.stageFlags |= (srcRange.stageFlags & RenderShaderStageFlag::CLOSEST_HIT) ? VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR : 0; - dstRange.stageFlags |= (srcRange.stageFlags & RenderShaderStageFlag::MISS) ? VK_SHADER_STAGE_MISS_BIT_KHR : 0; - dstRange.stageFlags |= (srcRange.stageFlags & RenderShaderStageFlag::CALLABLE) ? VK_SHADER_STAGE_CALLABLE_BIT_KHR : 0; - pushConstantRanges.emplace_back(dstRange); - } - - layoutInfo.pPushConstantRanges = !pushConstantRanges.empty() ? pushConstantRanges.data() : nullptr; - layoutInfo.pushConstantRangeCount = uint32_t(pushConstantRanges.size()); - - thread_local std::vector setLayoutHandles; - setLayoutHandles.clear(); - - for (uint32_t i = 0; i < desc.descriptorSetDescsCount; i++) { - VulkanDescriptorSetLayout *setLayout = new VulkanDescriptorSetLayout(device, desc.descriptorSetDescs[i]); - descriptorSetLayouts.emplace_back(setLayout); - setLayoutHandles.emplace_back(setLayout->vk); - } - - layoutInfo.pSetLayouts = !setLayoutHandles.empty() ? setLayoutHandles.data() : nullptr; - layoutInfo.setLayoutCount = uint32_t(setLayoutHandles.size()); - - VkResult res = vkCreatePipelineLayout(device->vk, &layoutInfo, nullptr, &vk); - if (res != VK_SUCCESS) { - fprintf(stderr, "vkCreatePipelineLayout failed with error code 0x%X.\n", res); - return; - } - } - - VulkanPipelineLayout::~VulkanPipelineLayout() { - if (vk != VK_NULL_HANDLE) { - vkDestroyPipelineLayout(device->vk, vk, nullptr); - } - - for (VulkanDescriptorSetLayout *setLayout : descriptorSetLayouts) { - delete setLayout; - } - } - - // VulkanShader - - VulkanShader::VulkanShader(VulkanDevice *device, const void *data, uint64_t size, const char *entryPointName, RenderShaderFormat format) { - assert(device != nullptr); - assert(data != nullptr); - assert(size > 0); - assert(format != RenderShaderFormat::UNKNOWN); - assert(format == RenderShaderFormat::SPIRV); - - this->device = device; - this->format = format; - this->entryPointName = (entryPointName != nullptr) ? std::string(entryPointName) : std::string(); - - VkShaderModuleCreateInfo shaderInfo = {}; - shaderInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; - shaderInfo.pCode = reinterpret_cast(data); - shaderInfo.codeSize = size; - VkResult res = vkCreateShaderModule(device->vk, &shaderInfo, nullptr, &vk); - if (res != VK_SUCCESS) { - fprintf(stderr, "vkCreateShaderModule failed with error code 0x%X.\n", res); - return; - } - } - - VulkanShader::~VulkanShader() { - if (vk != VK_NULL_HANDLE) { - vkDestroyShaderModule(device->vk, vk, nullptr); - } - } - - // VulkanSampler - - VulkanSampler::VulkanSampler(VulkanDevice *device, const RenderSamplerDesc &desc) { - assert(device != nullptr); - - this->device = device; - - VkSamplerCreateInfo samplerInfo = {}; - samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; - samplerInfo.minFilter = toVk(desc.minFilter); - samplerInfo.magFilter = toVk(desc.magFilter); - samplerInfo.mipmapMode = toVk(desc.mipmapMode); - samplerInfo.addressModeU = toVk(desc.addressU); - samplerInfo.addressModeV = toVk(desc.addressV); - samplerInfo.addressModeW = toVk(desc.addressW); - samplerInfo.mipLodBias = desc.mipLODBias; - samplerInfo.anisotropyEnable = desc.anisotropyEnabled; - samplerInfo.maxAnisotropy = float(desc.maxAnisotropy); - samplerInfo.compareEnable = desc.comparisonEnabled; - samplerInfo.compareOp = toVk(desc.comparisonFunc); - samplerInfo.minLod = desc.minLOD; - samplerInfo.maxLod = desc.maxLOD; - samplerInfo.borderColor = toVk(desc.borderColor); - samplerInfo.unnormalizedCoordinates = VK_FALSE; - - VkResult res = vkCreateSampler(device->vk, &samplerInfo, nullptr, &vk); - if (res != VK_SUCCESS) { - fprintf(stderr, "vkCreateSampler failed with error code 0x%X.\n", res); - return; - } - } - - VulkanSampler::~VulkanSampler() { - if (vk != VK_NULL_HANDLE) { - vkDestroySampler(device->vk, vk, nullptr); - } - } - - // VulkanPipeline - - VulkanPipeline::VulkanPipeline(VulkanDevice *device, Type type) { - assert(device != nullptr); - assert(type != Type::Unknown); - - this->device = device; - this->type = type; - } - - VulkanPipeline::~VulkanPipeline() { } - - // VulkanComputePipeline - - VulkanComputePipeline::VulkanComputePipeline(VulkanDevice *device, const RenderComputePipelineDesc &desc) : VulkanPipeline(device, Type::Compute) { - assert(desc.computeShader != nullptr); - assert(desc.pipelineLayout != nullptr); - - std::vector specEntries(desc.specConstantsCount); - std::vector specData(desc.specConstantsCount); - VkSpecializationInfo specInfo = {}; - fillSpecInfo(desc.specConstants, desc.specConstantsCount, specInfo, specEntries.data(), specData.data()); - - const VulkanShader *computeShader = static_cast(desc.computeShader); - VkPipelineShaderStageCreateInfo stageInfo = {}; - stageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; - stageInfo.stage = VK_SHADER_STAGE_COMPUTE_BIT; - stageInfo.module = computeShader->vk; - stageInfo.pName = computeShader->entryPointName.c_str(); - stageInfo.pSpecializationInfo = (specInfo.mapEntryCount > 0) ? &specInfo : nullptr; - - const VulkanPipelineLayout *pipelineLayout = static_cast(desc.pipelineLayout); - VkComputePipelineCreateInfo pipelineInfo = {}; - pipelineInfo.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO; - pipelineInfo.layout = pipelineLayout->vk; - pipelineInfo.stage = stageInfo; - - VkResult res = vkCreateComputePipelines(device->vk, VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &vk); - if (res != VK_SUCCESS) { - fprintf(stderr, "vkCreateComputePipelines failed with error code 0x%X.\n", res); - return; - } - } - - VulkanComputePipeline::~VulkanComputePipeline() { - if (vk != VK_NULL_HANDLE) { - vkDestroyPipeline(device->vk, vk, nullptr); - } - } - - void VulkanComputePipeline::setName(const std::string& name) const { - setObjectName(device->vk, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT, uint64_t(vk), name); - } - - RenderPipelineProgram VulkanComputePipeline::getProgram(const std::string &name) const { - assert(false && "Compute pipelines can't retrieve shader programs."); - return RenderPipelineProgram(); - } - - // VulkanGraphicsPipeline - - VulkanGraphicsPipeline::VulkanGraphicsPipeline(VulkanDevice *device, const RenderGraphicsPipelineDesc &desc) : VulkanPipeline(device, Type::Graphics) { - assert(desc.pipelineLayout != nullptr); - - thread_local std::vector stages; - stages.clear(); - - std::vector specEntries(desc.specConstantsCount); - std::vector specData(desc.specConstantsCount); - VkSpecializationInfo specInfo = {}; - fillSpecInfo(desc.specConstants, desc.specConstantsCount, specInfo, specEntries.data(), specData.data()); - - const VkSpecializationInfo *pSpecInfo = (specInfo.mapEntryCount > 0) ? &specInfo : nullptr; - if (desc.vertexShader != nullptr) { - const VulkanShader *vertexShader = static_cast(desc.vertexShader); - VkPipelineShaderStageCreateInfo stageInfo = {}; - stageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; - stageInfo.stage = VK_SHADER_STAGE_VERTEX_BIT; - stageInfo.module = vertexShader->vk; - stageInfo.pName = vertexShader->entryPointName.c_str(); - stageInfo.pSpecializationInfo = pSpecInfo; - stages.emplace_back(stageInfo); - } - - if (desc.geometryShader != nullptr) { - const VulkanShader *geometryShader = static_cast(desc.geometryShader); - VkPipelineShaderStageCreateInfo stageInfo = {}; - stageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; - stageInfo.stage = VK_SHADER_STAGE_GEOMETRY_BIT; - stageInfo.module = geometryShader->vk; - stageInfo.pName = geometryShader->entryPointName.c_str(); - stageInfo.pSpecializationInfo = pSpecInfo; - stages.emplace_back(stageInfo); - } - - if (desc.pixelShader != nullptr) { - const VulkanShader *pixelShader = static_cast(desc.pixelShader); - VkPipelineShaderStageCreateInfo stageInfo = {}; - stageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; - stageInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT; - stageInfo.module = pixelShader->vk; - stageInfo.pName = pixelShader->entryPointName.c_str(); - stageInfo.pSpecializationInfo = pSpecInfo; - stages.emplace_back(stageInfo); - } - - thread_local std::vector vertexBindings; - thread_local std::vector vertexAttributes; - vertexBindings.clear(); - vertexAttributes.clear(); - - for (uint32_t i = 0; i < desc.inputSlotsCount; i++) { - const RenderInputSlot &inputSlot = desc.inputSlots[i]; - VkVertexInputBindingDescription binding = {}; - binding.binding = inputSlot.index; - binding.stride = inputSlot.stride; - binding.inputRate = toVk(inputSlot.classification); - vertexBindings.emplace_back(binding); - } - - for (uint32_t i = 0; i < desc.inputElementsCount; i++) { - const RenderInputElement &inputElement = desc.inputElements[i]; - VkVertexInputAttributeDescription attribute = {}; - attribute.location = inputElement.location; - attribute.binding = inputElement.slotIndex; - attribute.format = toVk(inputElement.format); - attribute.offset = inputElement.alignedByteOffset; - vertexAttributes.emplace_back(attribute); - } - - VkPipelineVertexInputStateCreateInfo vertexInput = {}; - vertexInput.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; - vertexInput.pVertexBindingDescriptions = !vertexBindings.empty() ? vertexBindings.data() : nullptr; - vertexInput.vertexBindingDescriptionCount = uint32_t(vertexBindings.size()); - vertexInput.pVertexAttributeDescriptions = !vertexAttributes.empty() ? vertexAttributes.data() : nullptr; - vertexInput.vertexAttributeDescriptionCount = uint32_t(vertexAttributes.size()); - - VkPipelineInputAssemblyStateCreateInfo inputAssembly = {}; - inputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; - inputAssembly.topology = toVk(desc.primitiveTopology); - if (desc.primitiveTopology == RenderPrimitiveTopology::LINE_STRIP || desc.primitiveTopology == RenderPrimitiveTopology::TRIANGLE_STRIP) { - inputAssembly.primitiveRestartEnable = VK_TRUE; - } - - uint32_t renderTargetCount = desc.renderTargetCount; - if (renderTargetCount == 0 && desc.depthTargetFormat != RenderFormat::UNKNOWN) { - renderTargetCount = 1; - } - - VkPipelineViewportStateCreateInfo viewportState = {}; - viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; - viewportState.viewportCount = renderTargetCount; - viewportState.scissorCount = renderTargetCount; - - VkPipelineRasterizationStateCreateInfo rasterization = {}; - rasterization.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; - rasterization.depthClampEnable = !desc.depthClipEnabled; - rasterization.rasterizerDiscardEnable = VK_FALSE; - rasterization.polygonMode = VK_POLYGON_MODE_FILL; - rasterization.lineWidth = 1.0f; - rasterization.cullMode = toVk(desc.cullMode); - rasterization.frontFace = VK_FRONT_FACE_CLOCKWISE; - - if (desc.dynamicDepthBiasEnabled) { - rasterization.depthBiasEnable = true; - } - else if (desc.depthBias != 0 || desc.slopeScaledDepthBias != 0.0f) { - rasterization.depthBiasEnable = true; - rasterization.depthBiasConstantFactor = float(desc.depthBias); - rasterization.depthBiasSlopeFactor = desc.slopeScaledDepthBias; - } - - thread_local std::vector sampleLocationVector; - VkSampleLocationsInfoEXT sampleLocationsInfo = {}; - VkPipelineSampleLocationsStateCreateInfoEXT sampleLocations = {}; - const void *multisamplingNext = nullptr; - if (desc.multisampling.sampleLocationsEnabled) { - const float *coordinateRange = device->sampleLocationProperties.sampleLocationCoordinateRange; - const float coordinateBase = coordinateRange[0]; - const float coordinateSpace = (coordinateRange[1] - coordinateRange[0]) / 15.0f; - sampleLocationVector.resize(desc.multisampling.sampleCount); - for (uint32_t i = 0; i < desc.multisampling.sampleCount; i++) { - const RenderMultisamplingLocation &location = desc.multisampling.sampleLocations[i]; - sampleLocationVector[i].x = coordinateBase + (location.x + 8) * coordinateSpace; - sampleLocationVector[i].y = coordinateBase + (location.y + 8) * coordinateSpace; - } - - sampleLocationsInfo.sType = VK_STRUCTURE_TYPE_SAMPLE_LOCATIONS_INFO_EXT; - sampleLocationsInfo.sampleLocationsPerPixel = VkSampleCountFlagBits(desc.multisampling.sampleCount); - sampleLocationsInfo.sampleLocationGridSize.width = 1; - sampleLocationsInfo.sampleLocationGridSize.height = 1; - sampleLocationsInfo.sampleLocationsCount = uint32_t(sampleLocationVector.size()); - sampleLocationsInfo.pSampleLocations = sampleLocationVector.data(); - - sampleLocations.sType = VK_STRUCTURE_TYPE_PIPELINE_SAMPLE_LOCATIONS_STATE_CREATE_INFO_EXT; - sampleLocations.sampleLocationsEnable = true; - sampleLocations.sampleLocationsInfo = sampleLocationsInfo; - multisamplingNext = &sampleLocations; - } - - VkPipelineMultisampleStateCreateInfo multisampling = {}; - multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; - multisampling.pNext = multisamplingNext; - multisampling.rasterizationSamples = VkSampleCountFlagBits(desc.multisampling.sampleCount); - multisampling.alphaToCoverageEnable = desc.alphaToCoverageEnabled; - - thread_local std::vector colorBlendAttachments; - colorBlendAttachments.clear(); - - for (uint32_t i = 0; i < desc.renderTargetCount; i++) { - VkPipelineColorBlendAttachmentState attachment = {}; - const RenderBlendDesc &blendDesc = desc.renderTargetBlend[i]; - attachment.blendEnable = blendDesc.blendEnabled; - attachment.srcColorBlendFactor = toVk(blendDesc.srcBlend); - attachment.dstColorBlendFactor = toVk(blendDesc.dstBlend); - attachment.colorBlendOp = toVk(blendDesc.blendOp); - attachment.srcAlphaBlendFactor = toVk(blendDesc.srcBlendAlpha); - attachment.dstAlphaBlendFactor = toVk(blendDesc.dstBlendAlpha); - attachment.alphaBlendOp = toVk(blendDesc.blendOpAlpha); - attachment.colorWriteMask = blendDesc.renderTargetWriteMask; - colorBlendAttachments.emplace_back(attachment); - } - - VkPipelineColorBlendStateCreateInfo colorBlend = {}; - colorBlend.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; - colorBlend.logicOpEnable = desc.logicOpEnabled; - colorBlend.logicOp = toVk(desc.logicOp); - colorBlend.pAttachments = !colorBlendAttachments.empty() ? colorBlendAttachments.data() : nullptr; - colorBlend.attachmentCount = uint32_t(colorBlendAttachments.size()); - - VkPipelineDepthStencilStateCreateInfo depthStencil = {}; - depthStencil.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; - depthStencil.depthTestEnable = desc.depthEnabled; - depthStencil.depthWriteEnable = desc.depthWriteEnabled; - depthStencil.depthCompareOp = toVk(desc.depthFunction); - depthStencil.depthBoundsTestEnable = VK_FALSE; - depthStencil.minDepthBounds = 0.0f; - depthStencil.maxDepthBounds = 1.0f; - - thread_local std::vector dynamicStates; - dynamicStates.clear(); - dynamicStates.emplace_back(VK_DYNAMIC_STATE_VIEWPORT); - dynamicStates.emplace_back(VK_DYNAMIC_STATE_SCISSOR); - - if (desc.dynamicDepthBiasEnabled) { - dynamicStates.emplace_back(VK_DYNAMIC_STATE_DEPTH_BIAS); - } - - VkPipelineDynamicStateCreateInfo dynamicState = {}; - dynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; - dynamicState.pDynamicStates = dynamicStates.data(); - dynamicState.dynamicStateCount = static_cast(dynamicStates.size()); - - thread_local std::vector renderTargetFormats; - renderTargetFormats.resize(desc.renderTargetCount); - for (uint32_t i = 0; i < desc.renderTargetCount; i++) { - renderTargetFormats[i] = toVk(desc.renderTargetFormat[i]); - } - - renderPass = createRenderPass(device, renderTargetFormats.data(), desc.renderTargetCount, toVk(desc.depthTargetFormat), VkSampleCountFlagBits(desc.multisampling.sampleCount)); - if (renderPass == VK_NULL_HANDLE) { - return; - } - - const VulkanPipelineLayout *pipelineLayout = static_cast(desc.pipelineLayout); - VkGraphicsPipelineCreateInfo pipelineInfo = {}; - pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; - pipelineInfo.pStages = stages.data(); - pipelineInfo.stageCount = uint32_t(stages.size()); - pipelineInfo.pVertexInputState = &vertexInput; - pipelineInfo.pInputAssemblyState = &inputAssembly; - pipelineInfo.pViewportState = &viewportState; - pipelineInfo.pRasterizationState = &rasterization; - pipelineInfo.pMultisampleState = &multisampling; - pipelineInfo.pColorBlendState = &colorBlend; - pipelineInfo.pDepthStencilState = &depthStencil; - pipelineInfo.pDynamicState = &dynamicState; - pipelineInfo.layout = pipelineLayout->vk; - pipelineInfo.renderPass = renderPass; - - VkResult res = vkCreateGraphicsPipelines(device->vk, VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &vk); - if (res != VK_SUCCESS) { - fprintf(stderr, "vkCreateGraphicsPipelines failed with error code 0x%X.\n", res); - return; - } - } - - VulkanGraphicsPipeline::~VulkanGraphicsPipeline() { - if (vk != VK_NULL_HANDLE) { - vkDestroyPipeline(device->vk, vk, nullptr); - } - - if (renderPass != VK_NULL_HANDLE) { - vkDestroyRenderPass(device->vk, renderPass, nullptr); - } - } - - void VulkanGraphicsPipeline::setName(const std::string& name) const { - setObjectName(device->vk, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT, uint64_t(vk), name); - } - - RenderPipelineProgram VulkanGraphicsPipeline::getProgram(const std::string &name) const { - assert(false && "Graphics pipelines can't retrieve shader programs."); - return RenderPipelineProgram(); - } - - VkRenderPass VulkanGraphicsPipeline::createRenderPass(VulkanDevice *device, const VkFormat *renderTargetFormat, uint32_t renderTargetCount, VkFormat depthTargetFormat, VkSampleCountFlagBits sampleCount) { - VkRenderPass renderPass = VK_NULL_HANDLE; - VkSubpassDescription subpass = {}; - VkAttachmentReference depthReference = {}; - subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; - - thread_local std::vector attachments; - thread_local std::vector colorReferences; - attachments.clear(); - colorReferences.clear(); - for (uint32_t i = 0; i < renderTargetCount; i++) { - VkAttachmentReference reference = {}; - reference.attachment = uint32_t(attachments.size()); - reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - colorReferences.emplace_back(reference); - - VkAttachmentDescription attachment = {}; - attachment.format = renderTargetFormat[i]; - attachment.samples = sampleCount; - attachment.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; - attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; - attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - attachment.initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - attachment.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - attachments.emplace_back(attachment); - } - - subpass.pColorAttachments = !colorReferences.empty() ? colorReferences.data() : nullptr; - subpass.colorAttachmentCount = uint32_t(colorReferences.size()); - - if (depthTargetFormat != VK_FORMAT_UNDEFINED) { - depthReference.attachment = uint32_t(attachments.size()); - depthReference.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - subpass.pDepthStencilAttachment = &depthReference; - - VkAttachmentDescription attachment = {}; - attachment.format = depthTargetFormat; - attachment.samples = sampleCount; - attachment.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; - attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; - attachment.stencilLoadOp = attachment.loadOp; - attachment.stencilStoreOp = attachment.storeOp; - attachment.initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - attachment.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - attachments.emplace_back(attachment); - } - - VkRenderPassCreateInfo passInfo = {}; - passInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; - passInfo.pAttachments = !attachments.empty() ? attachments.data() : nullptr; - passInfo.attachmentCount = uint32_t(attachments.size()); - passInfo.pSubpasses = &subpass; - passInfo.subpassCount = 1; - - VkResult res = vkCreateRenderPass(device->vk, &passInfo, nullptr, &renderPass); - if (res == VK_SUCCESS) { - return renderPass; - } - else { - fprintf(stderr, "vkCreateRenderPass failed with error code 0x%X.\n", res); - return VK_NULL_HANDLE; - } - } - - // VulkanRaytracingPipeline - - VulkanRaytracingPipeline::VulkanRaytracingPipeline(VulkanDevice *device, const RenderRaytracingPipelineDesc &desc, const RenderPipeline *previousPipeline) : VulkanPipeline(device, VulkanPipeline::Type::Raytracing) { - assert(desc.pipelineLayout != nullptr); - assert(!desc.stateUpdateEnabled && "State updates are not supported."); - - std::vector shaderStages; - std::vector shaderGroups; - std::unordered_map shaderIndices; - - // Prepare all the vectors for the spec constants beforehand so they're not re-allocated. - std::vector specEntries; - std::vector specData; - std::vector specInfo; - for (uint32_t i = 0; i < desc.librariesCount; i++) { - const RenderRaytracingPipelineLibrary &library = desc.libraries[i]; - for (uint32_t j = 0; j < library.symbolsCount; j++) { - const RenderRaytracingPipelineLibrarySymbol &symbol = library.symbols[j]; - if (symbol.specConstantsCount == 0) { - continue; - } - - for (uint32_t i = 0; i < symbol.specConstantsCount; i++) { - specEntries.emplace_back(); - specData.emplace_back(); - } - - specInfo.emplace_back(); - } - } - - uint32_t specConstantIndex = 0; - uint32_t specConstantCursor = 0; - for (uint32_t i = 0; i < desc.librariesCount; i++) { - const RenderRaytracingPipelineLibrary &library = desc.libraries[i]; - assert(library.shader != nullptr); - - const VulkanShader *interfaceShader = static_cast(library.shader); - for (uint32_t j = 0; j < library.symbolsCount; j++) { - const RenderRaytracingPipelineLibrarySymbol &symbol = library.symbols[j]; - const bool isRaygen = (symbol.type == RenderRaytracingPipelineLibrarySymbolType::RAYGEN); - const bool isMiss = (symbol.type == RenderRaytracingPipelineLibrarySymbolType::MISS); - const uint32_t shaderStageIndex = uint32_t(shaderStages.size()); - const char *exportName = (symbol.exportName != nullptr) ? symbol.exportName : symbol.importName; - if (isRaygen || isMiss) { - VkRayTracingShaderGroupCreateInfoKHR groupInfo = {}; - groupInfo.sType = VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR; - groupInfo.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; - groupInfo.closestHitShader = VK_SHADER_UNUSED_KHR; - groupInfo.anyHitShader = VK_SHADER_UNUSED_KHR; - groupInfo.intersectionShader = VK_SHADER_UNUSED_KHR; - groupInfo.generalShader = shaderStageIndex; - nameProgramMap[std::string(exportName)] = uint32_t(shaderGroups.size()); - shaderGroups.emplace_back(groupInfo); - } - - VkPipelineShaderStageCreateInfo stageInfo = {}; - stageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; - stageInfo.pName = symbol.importName; - stageInfo.module = interfaceShader->vk; - stageInfo.stage = toStage(symbol.type); - - if (symbol.specConstantsCount > 0) { - stageInfo.pSpecializationInfo = &specInfo[specConstantIndex]; - fillSpecInfo(symbol.specConstants, symbol.specConstantsCount, specInfo[specConstantIndex], &specEntries[specConstantCursor], &specData[specConstantCursor]); - specConstantCursor += symbol.specConstantsCount; - specConstantIndex++; - } - - shaderIndices[std::string(exportName)] = uint32_t(shaderStages.size()); - shaderStages.emplace_back(stageInfo); - } - } - - for (uint32_t i = 0; i < desc.hitGroupsCount; i++) { - auto getShaderIndex = [&](const char *name) { - if (name != nullptr) { - auto it = shaderIndices.find(std::string(name)); - assert(it != shaderIndices.end()); - return it->second; - } - else { - return uint32_t(VK_SHADER_UNUSED_KHR); - } - }; - - const RenderRaytracingPipelineHitGroup &hitGroup = desc.hitGroups[i]; - VkRayTracingShaderGroupCreateInfoKHR groupInfo = {}; - groupInfo.sType = VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR; - groupInfo.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR; - groupInfo.generalShader = VK_SHADER_UNUSED_KHR; - groupInfo.closestHitShader = getShaderIndex(hitGroup.closestHitName); - groupInfo.anyHitShader = getShaderIndex(hitGroup.anyHitName); - groupInfo.intersectionShader = getShaderIndex(hitGroup.intersectionName); - nameProgramMap[std::string(hitGroup.hitGroupName)] = uint32_t(shaderGroups.size()); - shaderGroups.emplace_back(groupInfo); - } - - VkRayTracingPipelineInterfaceCreateInfoKHR interfaceInfo = {}; - interfaceInfo.sType = VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_INTERFACE_CREATE_INFO_KHR; - interfaceInfo.maxPipelineRayPayloadSize = desc.maxPayloadSize; - interfaceInfo.maxPipelineRayHitAttributeSize = desc.maxAttributeSize; - - const VulkanPipelineLayout *pipelineLayout = static_cast(desc.pipelineLayout); - VkRayTracingPipelineCreateInfoKHR pipelineInfo = {}; - pipelineInfo.sType = VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR; - pipelineInfo.pStages = shaderStages.data(); - pipelineInfo.stageCount = static_cast(shaderStages.size()); - pipelineInfo.pGroups = shaderGroups.data(); - pipelineInfo.groupCount = static_cast(shaderGroups.size()); - pipelineInfo.maxPipelineRayRecursionDepth = desc.maxRecursionDepth; - pipelineInfo.layout = pipelineLayout->vk; - - this->descriptorSetCount = uint32_t(pipelineLayout->descriptorSetLayouts.size()); - - VkResult res = vkCreateRayTracingPipelinesKHR(device->vk, nullptr, nullptr, 1, &pipelineInfo, nullptr, &vk); - if (res != VK_SUCCESS) { - fprintf(stderr, "vkCreateRayTracingPipelinesKHR failed with error code 0x%X.\n", res); - return; - } - - groupCount = pipelineInfo.groupCount; - } - - VulkanRaytracingPipeline::~VulkanRaytracingPipeline() { - if (vk != VK_NULL_HANDLE) { - vkDestroyPipeline(device->vk, vk, nullptr); - } - } - - void VulkanRaytracingPipeline::setName(const std::string& name) const { - setObjectName(device->vk, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT, uint64_t(vk), name); - } - - RenderPipelineProgram VulkanRaytracingPipeline::getProgram(const std::string &name) const { - auto it = nameProgramMap.find(name); - assert((it != nameProgramMap.end()) && "Program must exist in the PSO."); - return it->second; - } - - // VulkanDescriptorSet - - VulkanDescriptorSet::VulkanDescriptorSet(VulkanDevice *device, const RenderDescriptorSetDesc &desc) { - assert(device != nullptr); - - this->device = device; - - thread_local std::unordered_map typeCounts; - typeCounts.clear(); - - uint32_t boundlessRangeSize = 0; - uint32_t rangeCount = desc.descriptorRangesCount; - if (desc.lastRangeIsBoundless) { - assert((desc.descriptorRangesCount > 0) && "There must be at least one descriptor set to define the last range as boundless."); - - // Ensure at least one entry is created for boundless ranges. - boundlessRangeSize = std::max(desc.boundlessRangeSize, 1U); - - const RenderDescriptorRange &lastDescriptorRange = desc.descriptorRanges[desc.descriptorRangesCount - 1]; - typeCounts[toVk(lastDescriptorRange.type)] += boundlessRangeSize; - rangeCount--; - } - - for (uint32_t i = 0; i < rangeCount; i++) { - const RenderDescriptorRange &descriptorRange = desc.descriptorRanges[i]; - typeCounts[toVk(descriptorRange.type)] += descriptorRange.count; - } - - setLayout = new VulkanDescriptorSetLayout(device, desc); - - descriptorPool = createDescriptorPool(device, typeCounts, desc.lastRangeIsBoundless); - if (descriptorPool == VK_NULL_HANDLE) { - return; - } - - VkDescriptorSetAllocateInfo allocateInfo = {}; - allocateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; - allocateInfo.descriptorPool = descriptorPool; - allocateInfo.pSetLayouts = &setLayout->vk; - allocateInfo.descriptorSetCount = 1; - - VkDescriptorSetVariableDescriptorCountAllocateInfo countInfo = {}; - if (desc.lastRangeIsBoundless) { - countInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_ALLOCATE_INFO; - countInfo.pDescriptorCounts = &boundlessRangeSize; - countInfo.descriptorSetCount = 1; - allocateInfo.pNext = &countInfo; - } - - VkResult res = vkAllocateDescriptorSets(device->vk, &allocateInfo, &vk); - if (res != VK_SUCCESS) { - fprintf(stderr, "vkAllocateDescriptorSets failed with error code 0x%X.\n", res); - return; - } - } - - VulkanDescriptorSet::~VulkanDescriptorSet() { - if (descriptorPool != VK_NULL_HANDLE) { - vkDestroyDescriptorPool(device->vk, descriptorPool, nullptr); - } - - delete setLayout; - } - - void VulkanDescriptorSet::setBuffer(uint32_t descriptorIndex, const RenderBuffer *buffer, uint64_t bufferSize, const RenderBufferStructuredView *bufferStructuredView, const RenderBufferFormattedView *bufferFormattedView) { - if (buffer == nullptr) { - return; - } - - const VulkanBuffer *interfaceBuffer = static_cast(buffer); - const VkBufferView *bufferView = nullptr; - VkDescriptorBufferInfo bufferInfo = {}; - bufferInfo.buffer = interfaceBuffer->vk; - bufferInfo.range = (bufferSize > 0) ? bufferSize : interfaceBuffer->desc.size; - - if (bufferFormattedView != nullptr) { - assert((bufferStructuredView == nullptr) && "Can't use structured views and formatted views at the same time."); - - const VulkanBufferFormattedView *interfaceBufferFormattedView = static_cast(bufferFormattedView); - bufferView = &interfaceBufferFormattedView->vk; - } - else if (bufferStructuredView != nullptr) { - assert((bufferFormattedView == nullptr) && "Can't use structured views and formatted views at the same time."); - assert(bufferStructuredView->structureByteStride > 0); - - bufferInfo.offset = bufferStructuredView->firstElement * bufferStructuredView->structureByteStride; - } - else { - bufferInfo.offset = 0; - } - - setDescriptor(descriptorIndex, &bufferInfo, nullptr, bufferView, nullptr); - } - - void VulkanDescriptorSet::setTexture(uint32_t descriptorIndex, const RenderTexture *texture, const RenderTextureLayout textureLayout, const RenderTextureView *textureView) { - if (texture == nullptr) { - return; - } - - const VulkanTexture *interfaceTexture = static_cast(texture); - VkDescriptorImageInfo imageInfo = {}; - imageInfo.imageLayout = toImageLayout(textureLayout); - - if (textureView != nullptr) { - const VulkanTextureView *interfaceTextureView = static_cast(textureView); - imageInfo.imageView = interfaceTextureView->vk; - } - else { - imageInfo.imageView = (interfaceTexture != nullptr) ? interfaceTexture->imageView : VK_NULL_HANDLE; - } - - setDescriptor(descriptorIndex, nullptr, &imageInfo, nullptr, nullptr); - } - - void VulkanDescriptorSet::setSampler(uint32_t descriptorIndex, const RenderSampler *sampler) { - if (sampler == nullptr) { - return; - } - - const VulkanSampler *interfaceSampler = static_cast(sampler); - VkDescriptorImageInfo imageInfo = {}; - imageInfo.sampler = interfaceSampler->vk; - setDescriptor(descriptorIndex, nullptr, &imageInfo, nullptr, nullptr); - } - - void VulkanDescriptorSet::setAccelerationStructure(uint32_t descriptorIndex, const RenderAccelerationStructure *accelerationStructure) { - if (accelerationStructure == nullptr) { - return; - } - - const VulkanAccelerationStructure *interfaceAccelerationStructure = static_cast(accelerationStructure); - VkWriteDescriptorSetAccelerationStructureKHR setAccelerationStructure = {}; - setAccelerationStructure.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR; - setAccelerationStructure.pAccelerationStructures = &interfaceAccelerationStructure->vk; - setAccelerationStructure.accelerationStructureCount = 1; - setDescriptor(descriptorIndex, nullptr, nullptr, nullptr, &setAccelerationStructure); - } - - void VulkanDescriptorSet::setDescriptor(uint32_t descriptorIndex, const VkDescriptorBufferInfo *bufferInfo, const VkDescriptorImageInfo *imageInfo, const VkBufferView *texelBufferView, void *pNext) { - assert(descriptorIndex < setLayout->descriptorBindingIndices.size()); - - const uint32_t indexBase = setLayout->descriptorIndexBases[descriptorIndex]; - const uint32_t bindingIndex = setLayout->descriptorBindingIndices[descriptorIndex]; - const VkDescriptorSetLayoutBinding &setLayoutBinding = setLayout->setBindings[bindingIndex]; - VkWriteDescriptorSet writeDescriptor = {}; - writeDescriptor.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - writeDescriptor.pNext = pNext; - writeDescriptor.dstSet = vk; - writeDescriptor.dstBinding = setLayoutBinding.binding; - writeDescriptor.dstArrayElement = descriptorIndex - indexBase; - writeDescriptor.descriptorCount = 1; - writeDescriptor.descriptorType = setLayoutBinding.descriptorType; - writeDescriptor.pBufferInfo = bufferInfo; - writeDescriptor.pImageInfo = imageInfo; - writeDescriptor.pTexelBufferView = texelBufferView; - - vkUpdateDescriptorSets(device->vk, 1, &writeDescriptor, 0, nullptr); - } - - VkDescriptorPool VulkanDescriptorSet::createDescriptorPool(VulkanDevice *device, const std::unordered_map &typeCounts, bool lastRangeIsBoundless) { - thread_local std::vector poolSizes; - poolSizes.clear(); - - VkDescriptorPool descriptorPool; - for (auto it : typeCounts) { - VkDescriptorPoolSize poolSize = {}; - poolSize.type = it.first; - poolSize.descriptorCount = it.second; - poolSizes.emplace_back(poolSize); - } - - VkDescriptorPoolCreateInfo poolInfo = {}; - poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; - poolInfo.maxSets = 1; - poolInfo.pPoolSizes = !poolSizes.empty() ? poolSizes.data() : nullptr; - poolInfo.poolSizeCount = uint32_t(poolSizes.size()); - - if (lastRangeIsBoundless) { - poolInfo.flags = VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT; - } - - VkResult res = vkCreateDescriptorPool(device->vk, &poolInfo, nullptr, &descriptorPool); - if (res == VK_SUCCESS) { - return descriptorPool; - } - else { - fprintf(stderr, "vkCreateDescriptorPool failed with error code 0x%X.\n", res); - return VK_NULL_HANDLE; - } - } - - // VulkanSwapChain - - VulkanSwapChain::VulkanSwapChain(VulkanCommandQueue *commandQueue, RenderWindow renderWindow, uint32_t textureCount, RenderFormat format, uint32_t maxFrameLatency) { - assert(commandQueue != nullptr); - assert(textureCount > 0); - - this->commandQueue = commandQueue; - this->renderWindow = renderWindow; - this->format = format; - this->maxFrameLatency = maxFrameLatency; - - VkResult res; - -# ifdef _WIN64 - assert(renderWindow != 0); - VkWin32SurfaceCreateInfoKHR surfaceCreateInfo = {}; - surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; - surfaceCreateInfo.hwnd = HWND(renderWindow); - surfaceCreateInfo.hinstance = GetModuleHandle(nullptr); - - VulkanInterface *renderInterface = commandQueue->device->renderInterface; - res = vkCreateWin32SurfaceKHR(renderInterface->instance, &surfaceCreateInfo, nullptr, &surface); - if (res != VK_SUCCESS) { - fprintf(stderr, "vkCreateWin32SurfaceKHR failed with error code 0x%X.\n", res); - return; - } -# elif defined(SDL_VULKAN_ENABLED) - VulkanInterface *renderInterface = commandQueue->device->renderInterface; - SDL_bool sdlRes = SDL_Vulkan_CreateSurface(renderWindow, renderInterface->instance, &surface); - if (sdlRes == SDL_FALSE) { - fprintf(stderr, "SDL_Vulkan_CreateSurface failed with error %s.\n", SDL_GetError()); - return; - } -# elif defined(__ANDROID__) - assert(renderWindow != nullptr); - VkAndroidSurfaceCreateInfoKHR surfaceCreateInfo = {}; - surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR; - surfaceCreateInfo.window = renderWindow; - - VulkanInterface *renderInterface = commandQueue->device->renderInterface; - res = vkCreateAndroidSurfaceKHR(renderInterface->instance, &surfaceCreateInfo, nullptr, &surface); - if (res != VK_SUCCESS) { - fprintf(stderr, "vkCreateAndroidSurfaceKHR failed with error code 0x%X.\n", res); - return; - } -# elif defined(__linux__) - assert(renderWindow.display != 0); - assert(renderWindow.window != 0); - VkXlibSurfaceCreateInfoKHR surfaceCreateInfo = {}; - surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR; - surfaceCreateInfo.dpy = renderWindow.display; - surfaceCreateInfo.window = renderWindow.window; - - VulkanInterface *renderInterface = commandQueue->device->renderInterface; - res = vkCreateXlibSurfaceKHR(renderInterface->instance, &surfaceCreateInfo, nullptr, &surface); - if (res != VK_SUCCESS) { - fprintf(stderr, "vkCreateXlibSurfaceKHR failed with error code 0x%X.\n", res); - return; - } -# elif defined(__APPLE__) - assert(renderWindow.window != 0); - assert(renderWindow.view != 0); - VkMetalSurfaceCreateInfoEXT surfaceCreateInfo = {}; - surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT; - surfaceCreateInfo.pLayer = renderWindow.view; - - VulkanInterface *renderInterface = commandQueue->device->renderInterface; - res = vkCreateMetalSurfaceEXT(renderInterface->instance, &surfaceCreateInfo, nullptr, &surface); - if (res != VK_SUCCESS) { - fprintf(stderr, "vkCreateMetalSurfaceEXT failed with error code 0x%X.\n", res); - return; - } -# endif - - VkBool32 presentSupported = false; - VkPhysicalDevice physicalDevice = commandQueue->device->physicalDevice; - res = vkGetPhysicalDeviceSurfaceSupportKHR(physicalDevice, commandQueue->familyIndex, surface, &presentSupported); - if (res != VK_SUCCESS) { - fprintf(stderr, "vkGetPhysicalDeviceSurfaceSupportKHR failed with error code 0x%X.\n", res); - return; - } - - if (!presentSupported) { - fprintf(stderr, "Command queue does not support present.\n"); - return; - } - - VkSurfaceCapabilitiesKHR surfaceCapabilities = {}; - vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, surface, &surfaceCapabilities); - - // Pick an alpha compositing mode - if (surfaceCapabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR) { - pickedAlphaFlag = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; - } - else if (surfaceCapabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR) { - pickedAlphaFlag = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR; - } - else { - fprintf(stderr, "No known supported alpha compositing mode\n"); - return; - } - - // Make sure maxImageCount is never below minImageCount, as it's allowed to be zero. - surfaceCapabilities.maxImageCount = std::max(surfaceCapabilities.minImageCount, surfaceCapabilities.maxImageCount); - - // Clamp the requested buffer count between the bounds of the surface capabilities. - this->textureCount = std::clamp(textureCount, surfaceCapabilities.minImageCount, surfaceCapabilities.maxImageCount); - - uint32_t surfaceFormatCount = 0; - vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &surfaceFormatCount, nullptr); - - std::vector surfaceFormats(surfaceFormatCount); - vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &surfaceFormatCount, surfaceFormats.data()); - - uint32_t presentModeCount = 0; - vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, &presentModeCount, nullptr); - - std::vector presentModes(presentModeCount); - vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, &presentModeCount, presentModes.data()); - immediatePresentModeSupported = std::find(presentModes.begin(), presentModes.end(), VK_PRESENT_MODE_IMMEDIATE_KHR) != presentModes.end(); - - // Check if the format we requested is part of the supported surface formats. - std::vector compatibleSurfaceFormats; - VkFormat requestedFormat = toVk(format); - for (uint32_t i = 0; i < surfaceFormatCount; i++) { - if (surfaceFormats[i].format == requestedFormat) { - compatibleSurfaceFormats.emplace_back(surfaceFormats[i]); - break; - } - } - - if (compatibleSurfaceFormats.empty()) { - fprintf(stderr, "No compatible surface formats were found.\n"); - return; - } - - // Pick the preferred color space, if not available, pick whatever first shows up on the list. - for (const VkSurfaceFormatKHR &surfaceFormat : compatibleSurfaceFormats) { - if (surfaceFormat.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) { - pickedSurfaceFormat = surfaceFormat; - break; - } - } - - if (pickedSurfaceFormat.format == VK_FORMAT_UNDEFINED) { - pickedSurfaceFormat = compatibleSurfaceFormats[0]; - } - - // FIFO is guaranteed to be supported. - requiredPresentMode = VK_PRESENT_MODE_FIFO_KHR; - - // Pick an alpha compositing mode, prefer opaque over inherit. - if (surfaceCapabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR) { - pickedAlphaFlag = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; - } - else if (surfaceCapabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR) { - pickedAlphaFlag = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR; - } - else { - fprintf(stderr, "No supported alpha compositing mode was found.\n"); - return; - } - - // Parent command queue should track this swap chain. - commandQueue->swapChains.insert(this); - } - - VulkanSwapChain::~VulkanSwapChain() { - releaseImageViews(); - releaseSwapChain(); - - if (surface != VK_NULL_HANDLE) { - VulkanInterface *renderInterface = commandQueue->device->renderInterface; - vkDestroySurfaceKHR(renderInterface->instance, surface, nullptr); - } - - // Remove tracking from the parent command queue. - commandQueue->swapChains.erase(this); - } - - bool VulkanSwapChain::present(uint32_t textureIndex, RenderCommandSemaphore **waitSemaphores, uint32_t waitSemaphoreCount) { - thread_local std::vector waitSemaphoresVector; - waitSemaphoresVector.clear(); - for (uint32_t i = 0; i < waitSemaphoreCount; i++) { - VulkanCommandSemaphore *interfaceSemaphore = (VulkanCommandSemaphore *)(waitSemaphores[i]); - waitSemaphoresVector.emplace_back(interfaceSemaphore->vk); - } - - VkPresentInfoKHR presentInfo = {}; - presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; - presentInfo.pSwapchains = &vk; - presentInfo.swapchainCount = 1; - presentInfo.pImageIndices = &textureIndex; - presentInfo.pWaitSemaphores = !waitSemaphoresVector.empty() ? waitSemaphoresVector.data() : nullptr; - presentInfo.waitSemaphoreCount = uint32_t(waitSemaphoresVector.size()); - - VkPresentIdKHR presentId = {}; - if (commandQueue->device->capabilities.presentWait) { - currentPresentId++; - presentId.sType = VK_STRUCTURE_TYPE_PRESENT_ID_KHR; - presentId.pPresentIds = ¤tPresentId; - presentId.swapchainCount = 1; - presentInfo.pNext = &presentId; - } - - VkResult res; - { - const std::scoped_lock queueLock(*commandQueue->queue->mutex); - res = vkQueuePresentKHR(commandQueue->queue->vk, &presentInfo); - } - - // Handle the error silently. -#if defined(__APPLE__) - // Under MoltenVK, VK_SUBOPTIMAL_KHR does not result in a valid state for rendering. We intentionally - // only check for this error during present to avoid having to synchronize manually against the semaphore - // signalled by vkAcquireNextImageKHR. - if (res != VK_SUCCESS) { -#else - if ((res != VK_SUCCESS) && (res != VK_SUBOPTIMAL_KHR)) { -#endif - return false; - } - - return true; - } - - void VulkanSwapChain::wait() { - if (commandQueue->device->capabilities.presentWait && (currentPresentId >= maxFrameLatency)) { - constexpr uint64_t waitTimeout = 100000000; - vkWaitForPresentKHR(commandQueue->device->vk, vk, currentPresentId - (maxFrameLatency - 1), waitTimeout); - } - } - - bool VulkanSwapChain::resize() { - getWindowSize(width, height); - - // Don't recreate the swap chain at all if the window doesn't have a valid size. - if ((width == 0) || (height == 0)) { - return false; - } - - // Destroy any image view references to the current swap chain. - releaseImageViews(); - - // We don't actually need to query the surface capabilities but the validation layer seems to cache the valid extents from this call. - VkSurfaceCapabilitiesKHR surfaceCapabilities = {}; - vkGetPhysicalDeviceSurfaceCapabilitiesKHR(commandQueue->device->physicalDevice, surface, &surfaceCapabilities); - - createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; - createInfo.surface = surface; - createInfo.minImageCount = textureCount; - createInfo.imageFormat = pickedSurfaceFormat.format; - createInfo.imageColorSpace = pickedSurfaceFormat.colorSpace; - createInfo.imageExtent.width = width; - createInfo.imageExtent.height = height; - createInfo.imageArrayLayers = 1; - createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; - createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; - createInfo.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; - createInfo.compositeAlpha = pickedAlphaFlag; - createInfo.presentMode = requiredPresentMode; - createInfo.clipped = VK_TRUE; - createInfo.oldSwapchain = vk; - - VkResult res = vkCreateSwapchainKHR(commandQueue->device->vk, &createInfo, nullptr, &vk); - if (res != VK_SUCCESS) { - fprintf(stderr, "vkCreateSwapchainKHR failed with error code 0x%X.\n", res); - return false; - } - - // Store the chosen present mode to identify later whether the swapchain needs to be recreated. - createdPresentMode = requiredPresentMode; - - // Reset present counter. - presentCount = 1; - - if (createInfo.oldSwapchain != VK_NULL_HANDLE) { - vkDestroySwapchainKHR(commandQueue->device->vk, createInfo.oldSwapchain, nullptr); - } - - uint32_t retrievedImageCount = 0; - vkGetSwapchainImagesKHR(commandQueue->device->vk, vk, &retrievedImageCount, nullptr); - if (retrievedImageCount < textureCount) { - releaseSwapChain(); - fprintf(stderr, "Image count differs from the texture count.\n"); - return false; - } - - textureCount = retrievedImageCount; - - std::vector images(textureCount); - res = vkGetSwapchainImagesKHR(commandQueue->device->vk, vk, &textureCount, images.data()); - if (res != VK_SUCCESS) { - releaseSwapChain(); - fprintf(stderr, "vkGetSwapchainImagesKHR failed with error code 0x%X.\n", res); - return false; - } - - // Assign the swap chain images to the buffer resources. - textures.resize(textureCount); - - for (uint32_t i = 0; i < textureCount; i++) { - textures[i] = VulkanTexture(commandQueue->device, images[i]); - textures[i].desc.dimension = RenderTextureDimension::TEXTURE_2D; - textures[i].desc.format = format; - textures[i].desc.width = width; - textures[i].desc.height = height; - textures[i].desc.depth = 1; - textures[i].desc.mipLevels = 1; - textures[i].desc.arraySize = 1; - textures[i].desc.flags = RenderTextureFlag::RENDER_TARGET; - textures[i].fillSubresourceRange(); - textures[i].createImageView(pickedSurfaceFormat.format); - } - - return true; - } - - bool VulkanSwapChain::needsResize() const { - uint32_t windowWidth, windowHeight; - getWindowSize(windowWidth, windowHeight); - return (vk == VK_NULL_HANDLE) || (windowWidth != width) || (windowHeight != height) || (requiredPresentMode != createdPresentMode); - } - - void VulkanSwapChain::setVsyncEnabled(bool vsyncEnabled) { - // Immediate mode must be supported and the presentation mode will only be used on the next resize. - // needsResize() will return as true as long as the created and required present mode do not match. - if (immediatePresentModeSupported) { - requiredPresentMode = vsyncEnabled ? VK_PRESENT_MODE_FIFO_KHR : VK_PRESENT_MODE_IMMEDIATE_KHR; - } - } - - bool VulkanSwapChain::isVsyncEnabled() const { - return createdPresentMode == VK_PRESENT_MODE_FIFO_KHR; - } - - uint32_t VulkanSwapChain::getWidth() const { - return width; - } - - uint32_t VulkanSwapChain::getHeight() const { - return height; - } - - RenderTexture *VulkanSwapChain::getTexture(uint32_t textureIndex) { - return &textures[textureIndex]; - } - - uint32_t VulkanSwapChain::getTextureCount() const { - return textureCount; - } - - RenderWindow VulkanSwapChain::getWindow() const { - return renderWindow; - } - - bool VulkanSwapChain::isEmpty() const { - return (vk == VK_NULL_HANDLE) || (width == 0) || (height == 0); - } - - uint32_t VulkanSwapChain::getRefreshRate() const { - VkRefreshCycleDurationGOOGLE refreshCycle = {}; - VkResult res = vkGetRefreshCycleDurationGOOGLE(commandQueue->device->vk, vk, &refreshCycle); - if (res != VK_SUCCESS) { - fprintf(stderr, "vkGetRefreshCycleDurationGOOGLE failed with error code 0x%X.\n", res); - return 0; - } - - return std::lround(1000000000.0 / refreshCycle.refreshDuration); - } - - void VulkanSwapChain::getWindowSize(uint32_t &dstWidth, uint32_t &dstHeight) const { -# if defined(_WIN64) - RECT rect; - GetClientRect(renderWindow, &rect); - dstWidth = rect.right - rect.left; - dstHeight = rect.bottom - rect.top; -# elif defined(SDL_VULKAN_ENABLED) - SDL_GetWindowSizeInPixels(renderWindow, (int *)(&dstWidth), (int *)(&dstHeight)); -# elif defined(__ANDROID__) - dstWidth = ANativeWindow_getWidth(renderWindow); - dstHeight = ANativeWindow_getHeight(renderWindow); -# elif defined(__linux__) - XWindowAttributes attributes; - XGetWindowAttributes(renderWindow.display, renderWindow.window, &attributes); - // The attributes width and height members do not include the border. - dstWidth = attributes.width; - dstHeight = attributes.height; -# elif defined(__APPLE__) - SDL_GetWindowSizeInPixels(renderWindow.window, (int *)(&dstWidth), (int *)(&dstHeight)); -# endif - } - - bool VulkanSwapChain::acquireTexture(RenderCommandSemaphore *signalSemaphore, uint32_t *textureIndex) { - assert(signalSemaphore != nullptr); - - VulkanCommandSemaphore *interfaceSemaphore = static_cast(signalSemaphore); - VkResult res = vkAcquireNextImageKHR(commandQueue->device->vk, vk, UINT64_MAX, interfaceSemaphore->vk, VK_NULL_HANDLE, textureIndex); - if ((res != VK_SUCCESS) && (res != VK_SUBOPTIMAL_KHR)) { - return false; - } - - return true; - } - - void VulkanSwapChain::releaseSwapChain() { - if (vk != VK_NULL_HANDLE) { - vkDestroySwapchainKHR(commandQueue->device->vk, vk, nullptr); - vk = VK_NULL_HANDLE; - } - } - - void VulkanSwapChain::releaseImageViews() { - for (VulkanTexture &texture : textures) { - if (texture.imageView != VK_NULL_HANDLE) { - vkDestroyImageView(commandQueue->device->vk, texture.imageView, nullptr); - texture.imageView = VK_NULL_HANDLE; - } - } - } - - // VulkanFramebuffer - - VulkanFramebuffer::VulkanFramebuffer(VulkanDevice *device, const RenderFramebufferDesc &desc) { - assert(device != nullptr); - - this->device = device; - depthAttachmentReadOnly = desc.depthAttachmentReadOnly; - - VkResult res; - std::vector attachments; - std::vector colorReferences; - std::vector imageViews; - VkAttachmentReference depthReference = {}; - for (uint32_t i = 0; i < desc.colorAttachmentsCount; i++) { - const VulkanTexture *colorAttachment = static_cast(desc.colorAttachments[i]); - assert((colorAttachment->desc.flags & RenderTextureFlag::RENDER_TARGET) && "Color attachment must be a render target."); - colorAttachments.emplace_back(colorAttachment); - imageViews.emplace_back(colorAttachment->imageView); - - if (i == 0) { - width = uint32_t(colorAttachment->desc.width); - height = colorAttachment->desc.height; - } - - VkAttachmentReference reference = {}; - reference.attachment = uint32_t(attachments.size()); - reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - colorReferences.emplace_back(reference); - - VkAttachmentDescription attachment = {}; - attachment.format = toVk(colorAttachment->desc.format); - attachment.samples = VkSampleCountFlagBits(colorAttachment->desc.multisampling.sampleCount); - attachment.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; - attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; - attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - attachment.initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - attachment.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - attachments.emplace_back(attachment); - } - - if (desc.depthAttachment != nullptr) { - depthAttachment = static_cast(desc.depthAttachment); - assert((depthAttachment->desc.flags & RenderTextureFlag::DEPTH_TARGET) && "Depth attachment must be a depth target."); - imageViews.emplace_back(depthAttachment->imageView); - - if (desc.colorAttachmentsCount == 0) { - width = uint32_t(depthAttachment->desc.width); - height = depthAttachment->desc.height; - } - - depthReference.attachment = uint32_t(attachments.size()); - depthReference.layout = desc.depthAttachmentReadOnly ? VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL : VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - - // Upgrade the operations to NONE if supported. Fixes the following validation issue: https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/2349 - // We prefer to just ignore this potential hazard on older Vulkan versions as it just seems to be an edge case for some hardware. - const bool preferNoneForReadOnly = desc.depthAttachmentReadOnly && device->loadStoreOpNoneSupported; - VkAttachmentDescription attachment = {}; - attachment.format = toVk(depthAttachment->desc.format); - attachment.samples = VkSampleCountFlagBits(depthAttachment->desc.multisampling.sampleCount); - attachment.loadOp = preferNoneForReadOnly ? VK_ATTACHMENT_LOAD_OP_NONE_EXT : VK_ATTACHMENT_LOAD_OP_LOAD; - attachment.storeOp = preferNoneForReadOnly ? VK_ATTACHMENT_STORE_OP_NONE_EXT : VK_ATTACHMENT_STORE_OP_STORE; - attachment.stencilLoadOp = attachment.loadOp; - attachment.stencilStoreOp = attachment.storeOp; - attachment.initialLayout = depthReference.layout; - attachment.finalLayout = depthReference.layout; - attachments.emplace_back(attachment); - } - - VkSubpassDescription subpass = {}; - subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; - subpass.pColorAttachments = !colorReferences.empty() ? colorReferences.data() : nullptr; - subpass.colorAttachmentCount = uint32_t(colorReferences.size()); - - if (desc.depthAttachment != nullptr) { - subpass.pDepthStencilAttachment = &depthReference; - } - - VkRenderPassCreateInfo passInfo = {}; - passInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; - passInfo.pAttachments = attachments.data(); - passInfo.attachmentCount = uint32_t(attachments.size()); - passInfo.pSubpasses = &subpass; - passInfo.subpassCount = 1; - - res = vkCreateRenderPass(device->vk, &passInfo, nullptr, &renderPass); - if (res != VK_SUCCESS) { - fprintf(stderr, "vkCreateRenderPass failed with error code 0x%X.\n", res); - return; - } - - VkFramebufferCreateInfo fbInfo = {}; - fbInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; - fbInfo.renderPass = renderPass; - fbInfo.pAttachments = imageViews.data(); - fbInfo.attachmentCount = uint32_t(imageViews.size()); - fbInfo.width = width; - fbInfo.height = height; - fbInfo.layers = 1; - - res = vkCreateFramebuffer(device->vk, &fbInfo, nullptr, &vk); - if (res != VK_SUCCESS) { - fprintf(stderr, "vkCreateFramebuffer failed with error code 0x%X.\n", res); - return; - } - } - - VulkanFramebuffer::~VulkanFramebuffer() { - if (vk != VK_NULL_HANDLE) { - vkDestroyFramebuffer(device->vk, vk, nullptr); - } - - if (renderPass != VK_NULL_HANDLE) { - vkDestroyRenderPass(device->vk, renderPass, nullptr); - } - } - - uint32_t VulkanFramebuffer::getWidth() const { - return width; - } - - uint32_t VulkanFramebuffer::getHeight() const { - return height; - } - - bool VulkanFramebuffer::contains(const VulkanTexture *attachment) const { - assert(attachment != nullptr); - - for (uint32_t i = 0; i < colorAttachments.size(); i++) { - if (colorAttachments[i] == attachment) { - return true; - } - } - - return (depthAttachment == attachment); - } - - // VulkanQueryPool - - VulkanQueryPool::VulkanQueryPool(VulkanDevice *device, uint32_t queryCount) { - assert(device != nullptr); - assert(queryCount > 0); - - this->device = device; - - VkQueryPoolCreateInfo createInfo = {}; - createInfo.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO; - createInfo.queryType = VK_QUERY_TYPE_TIMESTAMP; - createInfo.queryCount = queryCount; - - VkResult res = vkCreateQueryPool(device->vk, &createInfo, nullptr, &vk); - if (res != VK_SUCCESS) { - fprintf(stderr, "vkCreateQueryPool failed with error code 0x%X.\n", res); - return; - } - - results.resize(queryCount); - } - - VulkanQueryPool::~VulkanQueryPool() { - vkDestroyQueryPool(device->vk, vk, nullptr); - } - - void VulkanQueryPool::queryResults() { - VkResult res = vkGetQueryPoolResults(device->vk, vk, 0, uint32_t(results.size()), sizeof(uint64_t) * results.size(), results.data(), sizeof(uint64_t), VK_QUERY_RESULT_64_BIT); - if (res != VK_SUCCESS) { - fprintf(stderr, "vkGetQueryPoolResults failed with error code 0x%X.\n", res); - return; - } - - // Conversion sourced from Godot Engine's Vulkan Rendering Driver. - auto mult64to128 = [](uint64_t u, uint64_t v, uint64_t &h, uint64_t &l) { - uint64_t u1 = (u & 0xffffffff); - uint64_t v1 = (v & 0xffffffff); - uint64_t t = (u1 * v1); - uint64_t w3 = (t & 0xffffffff); - uint64_t k = (t >> 32); - - u >>= 32; - t = (u * v1) + k; - k = (t & 0xffffffff); - uint64_t w1 = (t >> 32); - - v >>= 32; - t = (u1 * v) + k; - k = (t >> 32); - - h = (u * v) + w1 + k; - l = (t << 32) + w3; - }; - - // Convert results to timestamps. - constexpr uint64_t shift_bits = 16; - double timestampPeriod = double(device->physicalDeviceProperties.limits.timestampPeriod); - uint64_t h = 0, l = 0; - for (uint64_t &result : results) { - mult64to128(result, uint64_t(timestampPeriod * double(1 << shift_bits)), h, l); - result = l; - result >>= shift_bits; - result |= h << (64 - shift_bits); - } - } - - const uint64_t *VulkanQueryPool::getResults() const { - return results.data(); - } - - uint32_t VulkanQueryPool::getCount() const { - return uint32_t(results.size()); - } - - // VulkanCommandList - - VulkanCommandList::VulkanCommandList(VulkanDevice *device, RenderCommandListType type) { - assert(device != nullptr); - assert(type != RenderCommandListType::UNKNOWN); - - this->device = device; - this->type = type; - - VkCommandPoolCreateInfo poolInfo = {}; - poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; - poolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; - poolInfo.queueFamilyIndex = device->queueFamilyIndices[toFamilyIndex(type)]; - - VkResult res = vkCreateCommandPool(device->vk, &poolInfo, nullptr, &commandPool); - if (res != VK_SUCCESS) { - fprintf(stderr, "vkCreateCommandPool failed with error code 0x%X.\n", res); - return; - } - - VkCommandBufferAllocateInfo allocateInfo = {}; - allocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; - allocateInfo.commandPool = commandPool; - allocateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; - allocateInfo.commandBufferCount = 1; - - res = vkAllocateCommandBuffers(device->vk, &allocateInfo, &vk); - if (res != VK_SUCCESS) { - fprintf(stderr, "vkAllocateCommandBuffers failed with error code 0x%X.\n", res); - return; - } - } - - VulkanCommandList::~VulkanCommandList() { - if (vk != VK_NULL_HANDLE) { - vkFreeCommandBuffers(device->vk, commandPool, 1, &vk); - } - - if (commandPool != VK_NULL_HANDLE) { - vkDestroyCommandPool(device->vk, commandPool, nullptr); - } - } - - void VulkanCommandList::begin() { - vkResetCommandBuffer(vk, 0); - - VkCommandBufferBeginInfo beginInfo = {}; - beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - - VkResult res = vkBeginCommandBuffer(vk, &beginInfo); - if (res != VK_SUCCESS) { - fprintf(stderr, "vkBeginCommandBuffer failed with error code 0x%X.\n", res); - return; - } - } - - void VulkanCommandList::end() { - endActiveRenderPass(); - - VkResult res = vkEndCommandBuffer(vk); - if (res != VK_SUCCESS) { - fprintf(stderr, "vkEndCommandBuffer failed with error code 0x%X.\n", res); - return; - } - - targetFramebuffer = nullptr; - activeComputePipelineLayout = nullptr; - activeGraphicsPipelineLayout = nullptr; - activeRaytracingPipelineLayout = nullptr; - } - - void VulkanCommandList::barriers(RenderBarrierStages stages, const RenderBufferBarrier *bufferBarriers, uint32_t bufferBarriersCount, const RenderTextureBarrier *textureBarriers, uint32_t textureBarriersCount) { - assert((bufferBarriersCount == 0) || (bufferBarriers != nullptr)); - assert((textureBarriersCount == 0) || (textureBarriers != nullptr)); - - if ((bufferBarriersCount == 0) && (textureBarriersCount == 0)) { - return; - } - - endActiveRenderPass(); - - const bool geometryEnabled = device->capabilities.geometryShader; - const bool rtEnabled = device->capabilities.raytracing; - VkPipelineStageFlags srcStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; - VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT | toStageFlags(stages, geometryEnabled, rtEnabled); - thread_local std::vector bufferMemoryBarriers; - thread_local std::vector imageMemoryBarriers; - bufferMemoryBarriers.clear(); - imageMemoryBarriers.clear(); - - for (uint32_t i = 0; i < bufferBarriersCount; i++) { - const RenderBufferBarrier &bufferBarrier = bufferBarriers[i]; - VulkanBuffer *interfaceBuffer = static_cast(bufferBarrier.buffer); - VkBufferMemoryBarrier bufferMemoryBarrier = {}; - bufferMemoryBarrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER; - bufferMemoryBarrier.srcAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT; // TODO - bufferMemoryBarrier.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT; // TODO - bufferMemoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - bufferMemoryBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - bufferMemoryBarrier.buffer = interfaceBuffer->vk; - bufferMemoryBarrier.offset = 0; - bufferMemoryBarrier.size = interfaceBuffer->desc.size; - bufferMemoryBarriers.emplace_back(bufferMemoryBarrier); - srcStageMask |= toStageFlags(interfaceBuffer->barrierStages, geometryEnabled, rtEnabled); - interfaceBuffer->barrierStages = stages; - } - - for (uint32_t i = 0; i < textureBarriersCount; i++) { - const RenderTextureBarrier &textureBarrier = textureBarriers[i]; - VulkanTexture *interfaceTexture = static_cast(textureBarrier.texture); - VkImageMemoryBarrier imageMemoryBarrier = {}; - imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - imageMemoryBarrier.image = interfaceTexture->vk; - imageMemoryBarrier.srcAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT; // TODO - imageMemoryBarrier.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT; // TODO - imageMemoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - imageMemoryBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - imageMemoryBarrier.oldLayout = toImageLayout(interfaceTexture->textureLayout); - imageMemoryBarrier.newLayout = toImageLayout(textureBarrier.layout); - imageMemoryBarrier.subresourceRange.levelCount = interfaceTexture->desc.mipLevels; - imageMemoryBarrier.subresourceRange.layerCount = interfaceTexture->desc.arraySize; - imageMemoryBarrier.subresourceRange.aspectMask = (interfaceTexture->desc.flags & RenderTextureFlag::DEPTH_TARGET) ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT; - imageMemoryBarriers.emplace_back(imageMemoryBarrier); - srcStageMask |= toStageFlags(interfaceTexture->barrierStages, geometryEnabled, rtEnabled); - interfaceTexture->textureLayout = textureBarrier.layout; - interfaceTexture->barrierStages = stages; - } - - if (bufferMemoryBarriers.empty() && imageMemoryBarriers.empty()) { - return; - } - - vkCmdPipelineBarrier(vk, srcStageMask, dstStageMask, 0, 0, nullptr, uint32_t(bufferMemoryBarriers.size()), bufferMemoryBarriers.data(), uint32_t(imageMemoryBarriers.size()), imageMemoryBarriers.data()); - } - - void VulkanCommandList::dispatch(uint32_t threadGroupCountX, uint32_t threadGroupCountY, uint32_t threadGroupCountZ) { - vkCmdDispatch(vk, threadGroupCountX, threadGroupCountY, threadGroupCountZ); - } - - void VulkanCommandList::traceRays(uint32_t width, uint32_t height, uint32_t depth, RenderBufferReference shaderBindingTable, const RenderShaderBindingGroupsInfo &shaderBindingGroupsInfo) { - const VulkanBuffer *interfaceBuffer = static_cast(shaderBindingTable.ref); - assert(interfaceBuffer != nullptr); - assert((interfaceBuffer->desc.flags & RenderBufferFlag::SHADER_BINDING_TABLE) && "Buffer must allow being used as a shader binding table."); - - VkBufferDeviceAddressInfo tableAddressInfo = {}; - tableAddressInfo.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO; - tableAddressInfo.buffer = interfaceBuffer->vk; - - const VkDeviceAddress tableAddress = vkGetBufferDeviceAddress(device->vk, &tableAddressInfo) + shaderBindingTable.offset; - const RenderShaderBindingGroupInfo &rayGen = shaderBindingGroupsInfo.rayGen; - const RenderShaderBindingGroupInfo &miss = shaderBindingGroupsInfo.miss; - const RenderShaderBindingGroupInfo &hitGroup = shaderBindingGroupsInfo.hitGroup; - const RenderShaderBindingGroupInfo &callable = shaderBindingGroupsInfo.callable; - VkStridedDeviceAddressRegionKHR rayGenSbt = {}; - VkStridedDeviceAddressRegionKHR missSbt = {}; - VkStridedDeviceAddressRegionKHR hitSbt = {}; - VkStridedDeviceAddressRegionKHR callableSbt = {}; - rayGenSbt.deviceAddress = (rayGen.size > 0) ? (tableAddress + rayGen.offset + rayGen.startIndex * rayGen.stride) : 0; - rayGenSbt.size = rayGen.stride; // RayGen is a special case where the size must be the same as the stride. - rayGenSbt.stride = rayGen.stride; - missSbt.deviceAddress = (miss.size > 0) ? (tableAddress + miss.offset + miss.startIndex * miss.stride) : 0; - missSbt.size = miss.size; - missSbt.stride = miss.stride; - hitSbt.deviceAddress = (hitGroup.size > 0) ? (tableAddress + hitGroup.offset + hitGroup.startIndex * hitGroup.stride) : 0; - hitSbt.size = hitGroup.size; - hitSbt.stride = hitGroup.stride; - callableSbt.deviceAddress = (callable.size > 0) ? (tableAddress + callable.offset + callable.startIndex * callable.stride) : 0; - callableSbt.size = callable.size; - callableSbt.stride = callable.stride; - vkCmdTraceRaysKHR(vk, &rayGenSbt, &missSbt, &hitSbt, &callableSbt, width, height, depth); - } - - void VulkanCommandList::drawInstanced(uint32_t vertexCountPerInstance, uint32_t instanceCount, uint32_t startVertexLocation, uint32_t startInstanceLocation) { - checkActiveRenderPass(); - - vkCmdDraw(vk, vertexCountPerInstance, instanceCount, startVertexLocation, startInstanceLocation); - } - - void VulkanCommandList::drawIndexedInstanced(uint32_t indexCountPerInstance, uint32_t instanceCount, uint32_t startIndexLocation, int32_t baseVertexLocation, uint32_t startInstanceLocation) { - checkActiveRenderPass(); - - vkCmdDrawIndexed(vk, indexCountPerInstance, instanceCount, startIndexLocation, baseVertexLocation, startInstanceLocation); - } - - void VulkanCommandList::setPipeline(const RenderPipeline *pipeline) { - assert(pipeline != nullptr); - - const VulkanPipeline *interfacePipeline = static_cast(pipeline); - switch (interfacePipeline->type) { - case VulkanPipeline::Type::Compute: { - const VulkanComputePipeline *computePipeline = static_cast(interfacePipeline); - vkCmdBindPipeline(vk, VK_PIPELINE_BIND_POINT_COMPUTE, computePipeline->vk); - break; - } - case VulkanPipeline::Type::Graphics: { - const VulkanGraphicsPipeline *graphicsPipeline = static_cast(interfacePipeline); - vkCmdBindPipeline(vk, VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipeline->vk); - break; - } - case VulkanPipeline::Type::Raytracing: { - const VulkanRaytracingPipeline *raytracingPipeline = static_cast(interfacePipeline); - vkCmdBindPipeline(vk, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, raytracingPipeline->vk); - break; - } - default: - assert(false && "Unknown pipeline type."); - break; - } - } - - void VulkanCommandList::setComputePipelineLayout(const RenderPipelineLayout *pipelineLayout) { - assert(pipelineLayout != nullptr); - - activeComputePipelineLayout = static_cast(pipelineLayout); - } - - void VulkanCommandList::setComputePushConstants(uint32_t rangeIndex, const void *data, uint32_t offset, uint32_t size) { - assert(activeComputePipelineLayout != nullptr); - assert(rangeIndex < activeComputePipelineLayout->pushConstantRanges.size()); - - const VkPushConstantRange &range = activeComputePipelineLayout->pushConstantRanges[rangeIndex]; - vkCmdPushConstants(vk, activeComputePipelineLayout->vk, range.stageFlags & VK_SHADER_STAGE_COMPUTE_BIT, range.offset + offset, size == 0 ? range.size : size, data); - } - - void VulkanCommandList::setComputeDescriptorSet(RenderDescriptorSet *descriptorSet, uint32_t setIndex) { - setDescriptorSet(VK_PIPELINE_BIND_POINT_COMPUTE, activeComputePipelineLayout, descriptorSet, setIndex); - } - - void VulkanCommandList::setGraphicsPipelineLayout(const RenderPipelineLayout *pipelineLayout) { - assert(pipelineLayout != nullptr); - - activeGraphicsPipelineLayout = static_cast(pipelineLayout); - } - - void VulkanCommandList::setGraphicsPushConstants(uint32_t rangeIndex, const void *data, uint32_t offset, uint32_t size) { - assert(activeGraphicsPipelineLayout != nullptr); - assert(rangeIndex < activeGraphicsPipelineLayout->pushConstantRanges.size()); - - const VkPushConstantRange &range = activeGraphicsPipelineLayout->pushConstantRanges[rangeIndex]; - vkCmdPushConstants(vk, activeGraphicsPipelineLayout->vk, range.stageFlags & VK_SHADER_STAGE_ALL_GRAPHICS, range.offset + offset, size == 0 ? range.size : size, data); - } - - void VulkanCommandList::setGraphicsDescriptorSet(RenderDescriptorSet *descriptorSet, uint32_t setIndex) { - setDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, activeGraphicsPipelineLayout, descriptorSet, setIndex); - } - - void VulkanCommandList::setGraphicsRootDescriptor(RenderBufferReference bufferReference, uint32_t rootDescriptorIndex) { - assert(false && "Root descriptors are not supported in Vulkan."); - } - - void VulkanCommandList::setRaytracingPipelineLayout(const RenderPipelineLayout *pipelineLayout) { - assert(pipelineLayout != nullptr); - - activeRaytracingPipelineLayout = static_cast(pipelineLayout); - } - - void VulkanCommandList::setRaytracingPushConstants(uint32_t rangeIndex, const void *data, uint32_t offset, uint32_t size) { - assert(activeRaytracingPipelineLayout != nullptr); - assert(rangeIndex < activeRaytracingPipelineLayout->pushConstantRanges.size()); - - const VkPushConstantRange &range = activeRaytracingPipelineLayout->pushConstantRanges[rangeIndex]; - const VkShaderStageFlags raytracingStageFlags = VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_ANY_HIT_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | - VK_SHADER_STAGE_MISS_BIT_KHR | VK_SHADER_STAGE_INTERSECTION_BIT_KHR | VK_SHADER_STAGE_CALLABLE_BIT_KHR; - - vkCmdPushConstants(vk, activeRaytracingPipelineLayout->vk, range.stageFlags & raytracingStageFlags, range.offset + offset, size == 0 ? range.size : size, data); - } - - void VulkanCommandList::setRaytracingDescriptorSet(RenderDescriptorSet *descriptorSet, uint32_t setIndex) { - setDescriptorSet(VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, activeRaytracingPipelineLayout, descriptorSet, setIndex); - } - - void VulkanCommandList::setIndexBuffer(const RenderIndexBufferView *view) { - if (view != nullptr) { - const VulkanBuffer *interfaceBuffer = static_cast(view->buffer.ref); - vkCmdBindIndexBuffer(vk, (interfaceBuffer != nullptr) ? interfaceBuffer->vk : VK_NULL_HANDLE, view->buffer.offset, toIndexType(view->format)); - } - } - - void VulkanCommandList::setVertexBuffers(uint32_t startSlot, const RenderVertexBufferView *views, uint32_t viewCount, const RenderInputSlot *inputSlots) { - if ((views != nullptr) && (viewCount > 0)) { - // Input slots aren't actually used by Vulkan as the stride is baked into the pipeline, but we validate it for the sake of consistency with D3D12. - assert(inputSlots != nullptr); - - thread_local std::vector bufferVector; - thread_local std::vector offsetVector; - bufferVector.clear(); - offsetVector.clear(); - for (uint32_t i = 0; i < viewCount; i++) { - const VulkanBuffer *interfaceBuffer = static_cast(views[i].buffer.ref); - if (interfaceBuffer == nullptr && !device->nullDescriptorSupported) { - interfaceBuffer = static_cast(device->nullBuffer.get()); - } - bufferVector.emplace_back((interfaceBuffer != nullptr) ? interfaceBuffer->vk : VK_NULL_HANDLE); - offsetVector.emplace_back(views[i].buffer.offset); - } - - vkCmdBindVertexBuffers(vk, startSlot, viewCount, bufferVector.data(), offsetVector.data()); - } - } - - void VulkanCommandList::setViewports(const RenderViewport *viewports, uint32_t count) { - if (count > 1) { - thread_local std::vector viewportVector; - viewportVector.clear(); - - for (uint32_t i = 0; i < count; i++) { - viewportVector.emplace_back(VkViewport{ viewports[i].x, viewports[i].y, viewports[i].width, viewports[i].height, viewports[i].minDepth, viewports[i].maxDepth }); - } - - if (!viewportVector.empty()) { - vkCmdSetViewport(vk, 0, uint32_t(viewportVector.size()), viewportVector.data()); - } - } - else { - // Single element fast path. - VkViewport viewport = VkViewport{ viewports[0].x, viewports[0].y, viewports[0].width, viewports[0].height, viewports[0].minDepth, viewports[0].maxDepth }; - vkCmdSetViewport(vk, 0, 1, &viewport); - } - } - - void VulkanCommandList::setScissors(const RenderRect *scissorRects, uint32_t count) { - if (count > 1) { - thread_local std::vector scissorVector; - scissorVector.clear(); - - for (uint32_t i = 0; i < count; i++) { - scissorVector.emplace_back(VkRect2D{ VkOffset2D{ scissorRects[i].left, scissorRects[i].top }, VkExtent2D{ uint32_t(scissorRects[i].right - scissorRects[i].left), uint32_t(scissorRects[i].bottom - scissorRects[i].top) } }); - } - - if (!scissorVector.empty()) { - vkCmdSetScissor(vk, 0, uint32_t(scissorVector.size()), scissorVector.data()); - } - } - else { - // Single element fast path. - VkRect2D scissor = VkRect2D{ VkOffset2D{ scissorRects[0].left, scissorRects[0].top }, VkExtent2D{ uint32_t(scissorRects[0].right - scissorRects[0].left), uint32_t(scissorRects[0].bottom - scissorRects[0].top) } }; - vkCmdSetScissor(vk, 0, 1, &scissor); - } - } - - void VulkanCommandList::setFramebuffer(const RenderFramebuffer *framebuffer) { - endActiveRenderPass(); - - if (framebuffer != nullptr) { - const VulkanFramebuffer *interfaceFramebuffer = static_cast(framebuffer); - targetFramebuffer = interfaceFramebuffer; - } - else { - targetFramebuffer = nullptr; - } - } - - void VulkanCommandList::setDepthBias(float depthBias, float depthBiasClamp, float slopeScaledDepthBias) { - vkCmdSetDepthBias(vk, depthBias, depthBiasClamp, slopeScaledDepthBias); - } - - static void clearCommonRectVector(uint32_t width, uint32_t height, const RenderRect *clearRects, uint32_t clearRectsCount, std::vector &rectVector) { - rectVector.clear(); - - if (clearRectsCount > 0) { - for (uint32_t i = 0; i < clearRectsCount; i++) { - VkClearRect clearRect; - clearRect.rect.offset.x = clearRects[i].left; - clearRect.rect.offset.y = clearRects[i].top; - clearRect.rect.extent.width = clearRects[i].right - clearRects[i].left; - clearRect.rect.extent.height = clearRects[i].bottom - clearRects[i].top; - clearRect.baseArrayLayer = 0; - clearRect.layerCount = 1; - rectVector.emplace_back(clearRect); - } - } - else { - VkClearRect clearRect; - clearRect.rect.offset.x = 0; - clearRect.rect.offset.y = 0; - clearRect.rect.extent.width = width; - clearRect.rect.extent.height = height; - clearRect.baseArrayLayer = 0; - clearRect.layerCount = 1; - rectVector.emplace_back(clearRect); - } - } - - void VulkanCommandList::clearColor(uint32_t attachmentIndex, RenderColor colorValue, const RenderRect *clearRects, uint32_t clearRectsCount) { - assert(targetFramebuffer != nullptr); - assert(attachmentIndex < targetFramebuffer->colorAttachments.size()); - assert((clearRectsCount == 0) || (clearRects != nullptr)); - - checkActiveRenderPass(); - - thread_local std::vector rectVector; - clearCommonRectVector(targetFramebuffer->getWidth(), targetFramebuffer->getHeight(), clearRects, clearRectsCount, rectVector); - - VkClearAttachment attachment = {}; - auto &rgba = attachment.clearValue.color.float32; - rgba[0] = colorValue.r; - rgba[1] = colorValue.g; - rgba[2] = colorValue.b; - rgba[3] = colorValue.a; - attachment.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - attachment.colorAttachment = attachmentIndex; - vkCmdClearAttachments(vk, 1, &attachment, uint32_t(rectVector.size()), rectVector.data()); - } - - void VulkanCommandList::clearDepth(bool clearDepth, float depthValue, const RenderRect *clearRects, uint32_t clearRectsCount) { - assert(targetFramebuffer != nullptr); - assert((clearRectsCount == 0) || (clearRects != nullptr)); - - checkActiveRenderPass(); - - thread_local std::vector rectVector; - clearCommonRectVector(targetFramebuffer->getWidth(), targetFramebuffer->getHeight(), clearRects, clearRectsCount, rectVector); - - VkClearAttachment attachment = {}; - attachment.clearValue.depthStencil.depth = depthValue; - - if (clearDepth) { - attachment.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; - } - - vkCmdClearAttachments(vk, 1, &attachment, uint32_t(rectVector.size()), rectVector.data()); - } - - void VulkanCommandList::copyBufferRegion(RenderBufferReference dstBuffer, RenderBufferReference srcBuffer, uint64_t size) { - endActiveRenderPass(); - - assert(dstBuffer.ref != nullptr); - assert(srcBuffer.ref != nullptr); - - const VulkanBuffer *interfaceDstBuffer = static_cast(dstBuffer.ref); - const VulkanBuffer *interfaceSrcBuffer = static_cast(srcBuffer.ref); - VkBufferCopy bufferCopy = {}; - bufferCopy.dstOffset = dstBuffer.offset; - bufferCopy.srcOffset = srcBuffer.offset; - bufferCopy.size = size; - vkCmdCopyBuffer(vk, interfaceSrcBuffer->vk, interfaceDstBuffer->vk, 1, &bufferCopy); - } - - void VulkanCommandList::copyTextureRegion(const RenderTextureCopyLocation &dstLocation, const RenderTextureCopyLocation &srcLocation, uint32_t dstX, uint32_t dstY, uint32_t dstZ, const RenderBox *srcBox) { - endActiveRenderPass(); - - assert(dstLocation.type != RenderTextureCopyType::UNKNOWN); - assert(srcLocation.type != RenderTextureCopyType::UNKNOWN); - - const VulkanTexture *dstTexture = static_cast(dstLocation.texture); - const VulkanTexture *srcTexture = static_cast(srcLocation.texture); - const VulkanBuffer *dstBuffer = static_cast(dstLocation.buffer); - const VulkanBuffer *srcBuffer = static_cast(srcLocation.buffer); - if ((dstLocation.type == RenderTextureCopyType::SUBRESOURCE) && (srcLocation.type == RenderTextureCopyType::PLACED_FOOTPRINT)) { - assert(dstTexture != nullptr); - assert(srcBuffer != nullptr); - - const uint32_t blockWidth = RenderFormatBlockWidth(dstTexture->desc.format); - VkBufferImageCopy imageCopy = {}; - imageCopy.bufferOffset = srcLocation.placedFootprint.offset; - imageCopy.bufferRowLength = ((srcLocation.placedFootprint.rowWidth + blockWidth - 1) / blockWidth) * blockWidth; - imageCopy.bufferImageHeight = ((srcLocation.placedFootprint.height + blockWidth - 1) / blockWidth) * blockWidth; - imageCopy.imageSubresource.aspectMask = (dstTexture->desc.flags & RenderTextureFlag::DEPTH_TARGET) ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT; - imageCopy.imageSubresource.baseArrayLayer = dstLocation.subresource.index / dstTexture->desc.mipLevels; - imageCopy.imageSubresource.layerCount = 1; - imageCopy.imageSubresource.mipLevel = dstLocation.subresource.index % dstTexture->desc.mipLevels; - imageCopy.imageOffset.x = dstX; - imageCopy.imageOffset.y = dstY; - imageCopy.imageOffset.z = dstZ; - imageCopy.imageExtent.width = srcLocation.placedFootprint.width; - imageCopy.imageExtent.height = srcLocation.placedFootprint.height; - imageCopy.imageExtent.depth = srcLocation.placedFootprint.depth; - vkCmdCopyBufferToImage(vk, srcBuffer->vk, dstTexture->vk, toImageLayout(dstTexture->textureLayout), 1, &imageCopy); - } - else { - VkImageCopy imageCopy = {}; - imageCopy.srcSubresource.aspectMask = (srcTexture->desc.flags & RenderTextureFlag::DEPTH_TARGET) ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT; - imageCopy.srcSubresource.baseArrayLayer = 0; - imageCopy.srcSubresource.layerCount = 1; - imageCopy.srcSubresource.mipLevel = srcLocation.subresource.index; - imageCopy.dstSubresource.aspectMask = (dstTexture->desc.flags & RenderTextureFlag::DEPTH_TARGET) ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT; - imageCopy.dstSubresource.baseArrayLayer = 0; - imageCopy.dstSubresource.layerCount = 1; - imageCopy.dstSubresource.mipLevel = dstLocation.subresource.index; - imageCopy.dstOffset.x = dstX; - imageCopy.dstOffset.y = dstY; - imageCopy.dstOffset.z = dstZ; - - if (srcBox != nullptr) { - imageCopy.srcOffset.x = srcBox->left; - imageCopy.srcOffset.y = srcBox->top; - imageCopy.srcOffset.z = srcBox->front; - imageCopy.extent.width = srcBox->right - srcBox->left; - imageCopy.extent.height = srcBox->bottom - srcBox->top; - imageCopy.extent.depth = srcBox->back - srcBox->front; - } - else { - imageCopy.srcOffset.x = 0; - imageCopy.srcOffset.y = 0; - imageCopy.srcOffset.z = 0; - imageCopy.extent.width = srcTexture->desc.width; - imageCopy.extent.height = srcTexture->desc.height; - imageCopy.extent.depth = srcTexture->desc.depth; - } - - vkCmdCopyImage(vk, srcTexture->vk, toImageLayout(srcTexture->textureLayout), dstTexture->vk, toImageLayout(dstTexture->textureLayout), 1, &imageCopy); - } - } - - void VulkanCommandList::copyBuffer(const RenderBuffer *dstBuffer, const RenderBuffer *srcBuffer) { - endActiveRenderPass(); - - assert(dstBuffer != nullptr); - assert(srcBuffer != nullptr); - - const VulkanBuffer *interfaceDstBuffer = static_cast(dstBuffer); - const VulkanBuffer *interfaceSrcBuffer = static_cast(srcBuffer); - VkBufferCopy bufferCopy = {}; - bufferCopy.dstOffset = 0; - bufferCopy.srcOffset = 0; - bufferCopy.size = interfaceDstBuffer->desc.size; - vkCmdCopyBuffer(vk, interfaceSrcBuffer->vk, interfaceDstBuffer->vk, 1, &bufferCopy); - } - - void VulkanCommandList::copyTexture(const RenderTexture *dstTexture, const RenderTexture *srcTexture) { - endActiveRenderPass(); - - assert(dstTexture != nullptr); - assert(srcTexture != nullptr); - - thread_local std::vector imageCopies; - imageCopies.clear(); - - const VulkanTexture *dst = static_cast(dstTexture); - const VulkanTexture *src = static_cast(srcTexture); - VkImageLayout srcLayout = toImageLayout(src->textureLayout); - VkImageLayout dstLayout = toImageLayout(dst->textureLayout); - VkImageCopy imageCopy = {}; - imageCopy.srcSubresource.aspectMask = (src->desc.flags & RenderTextureFlag::DEPTH_TARGET) ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT; - imageCopy.srcSubresource.baseArrayLayer = 0; - imageCopy.srcSubresource.layerCount = 1; - imageCopy.dstSubresource.aspectMask = (dst->desc.flags & RenderTextureFlag::DEPTH_TARGET) ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT; - imageCopy.dstSubresource.baseArrayLayer = 0; - imageCopy.dstSubresource.layerCount = 1; - imageCopy.extent.width = uint32_t(dst->desc.width); - imageCopy.extent.height = dst->desc.height; - imageCopy.extent.depth = dst->desc.depth; - - assert(dst->desc.mipLevels > 0); - assert(src->desc.mipLevels == dst->desc.mipLevels); - - for (uint32_t i = 0; i < dst->desc.mipLevels; i++) { - imageCopy.srcSubresource.mipLevel = i; - imageCopy.dstSubresource.mipLevel = i; - imageCopies.emplace_back(imageCopy); - } - - vkCmdCopyImage(vk, src->vk, srcLayout, dst->vk, dstLayout, uint32_t(imageCopies.size()), imageCopies.data()); - } - - void VulkanCommandList::resolveTexture(const RenderTexture *dstTexture, const RenderTexture *srcTexture) { - resolveTextureRegion(dstTexture, 0, 0, srcTexture, nullptr, RenderResolveMode::AVERAGE); - } - - void VulkanCommandList::resolveTextureRegion(const RenderTexture *dstTexture, uint32_t dstX, uint32_t dstY, const RenderTexture *srcTexture, const RenderRect *srcRect, RenderResolveMode resolveMode) { - assert(dstTexture != nullptr); - assert(srcTexture != nullptr); - assert(resolveMode == RenderResolveMode::AVERAGE && "Vulkan only supports AVERAGE resolve mode."); - - thread_local std::vector imageResolves; - imageResolves.clear(); - - const VulkanTexture *dst = static_cast(dstTexture); - const VulkanTexture *src = static_cast(srcTexture); - VkImageLayout srcLayout = toImageLayout(src->textureLayout); - VkImageLayout dstLayout = toImageLayout(dst->textureLayout); - VkImageResolve imageResolve = {}; - imageResolve.srcSubresource.aspectMask = (src->desc.flags & RenderTextureFlag::DEPTH_TARGET) ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT; - imageResolve.srcSubresource.baseArrayLayer = 0; - imageResolve.srcSubresource.layerCount = 1; - imageResolve.dstOffset.x = dstX; - imageResolve.dstOffset.y = dstY; - imageResolve.dstSubresource.aspectMask = (dst->desc.flags & RenderTextureFlag::DEPTH_TARGET) ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT; - imageResolve.dstSubresource.baseArrayLayer = 0; - imageResolve.dstSubresource.layerCount = 1; - imageResolve.extent.depth = dst->desc.depth; - - if (srcRect != nullptr) { - imageResolve.srcOffset.x = srcRect->left; - imageResolve.srcOffset.y = srcRect->top; - imageResolve.extent.width = (srcRect->right - srcRect->left); - imageResolve.extent.height = (srcRect->bottom - srcRect->top); - } - else { - imageResolve.extent.width = uint32_t(dst->desc.width); - imageResolve.extent.height = dst->desc.height; - } - - assert(dst->desc.mipLevels > 0); - assert(src->desc.mipLevels == dst->desc.mipLevels); - - for (uint32_t i = 0; i < dst->desc.mipLevels; i++) { - imageResolve.srcSubresource.mipLevel = i; - imageResolve.dstSubresource.mipLevel = i; - imageResolves.emplace_back(imageResolve); - } - - vkCmdResolveImage(vk, src->vk, srcLayout, dst->vk, dstLayout, uint32_t(imageResolves.size()), imageResolves.data()); - } - - void VulkanCommandList::buildBottomLevelAS(const RenderAccelerationStructure *dstAccelerationStructure, RenderBufferReference scratchBuffer, const RenderBottomLevelASBuildInfo &buildInfo) { - assert(dstAccelerationStructure != nullptr); - assert(scratchBuffer.ref != nullptr); - - const VulkanAccelerationStructure *interfaceAccelerationStructure = static_cast(dstAccelerationStructure); - assert(interfaceAccelerationStructure->type == RenderAccelerationStructureType::BOTTOM_LEVEL); - - const VulkanBuffer *interfaceScratchBuffer = static_cast(scratchBuffer.ref); - assert((interfaceScratchBuffer->desc.flags & RenderBufferFlag::ACCELERATION_STRUCTURE_SCRATCH) && "Scratch buffer must be allowed."); - - VkBufferDeviceAddressInfo scratchAddressInfo = {}; - scratchAddressInfo.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO; - scratchAddressInfo.buffer = interfaceScratchBuffer->vk; - - VkAccelerationStructureBuildGeometryInfoKHR buildGeometryInfo = {}; - buildGeometryInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR; - buildGeometryInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR; - buildGeometryInfo.flags = toRTASBuildFlags(buildInfo.preferFastBuild, buildInfo.preferFastTrace); - buildGeometryInfo.mode = VK_BUILD_ACCELERATION_STRUCTURE_MODE_BUILD_KHR; - buildGeometryInfo.dstAccelerationStructure = interfaceAccelerationStructure->vk; - buildGeometryInfo.scratchData.deviceAddress = vkGetBufferDeviceAddress(device->vk, &scratchAddressInfo) + scratchBuffer.offset; - buildGeometryInfo.pGeometries = reinterpret_cast(buildInfo.buildData.data()); - buildGeometryInfo.geometryCount = buildInfo.meshCount; - - VkAccelerationStructureBuildRangeInfoKHR buildRangeInfo = {}; - buildRangeInfo.primitiveCount = buildInfo.primitiveCount; - buildRangeInfo.primitiveOffset = 0; - buildRangeInfo.firstVertex = 0; - buildRangeInfo.transformOffset = 0; - - VkAccelerationStructureBuildRangeInfoKHR *buildRangeInfoPtr = &buildRangeInfo; - vkCmdBuildAccelerationStructuresKHR(vk, 1, &buildGeometryInfo, &buildRangeInfoPtr); - } - - void VulkanCommandList::buildTopLevelAS(const RenderAccelerationStructure *dstAccelerationStructure, RenderBufferReference scratchBuffer, RenderBufferReference instancesBuffer, const RenderTopLevelASBuildInfo &buildInfo) { - assert(dstAccelerationStructure != nullptr); - assert(scratchBuffer.ref != nullptr); - assert(instancesBuffer.ref != nullptr); - - const VulkanAccelerationStructure *interfaceAccelerationStructure = static_cast(dstAccelerationStructure); - assert(interfaceAccelerationStructure->type == RenderAccelerationStructureType::TOP_LEVEL); - - const VulkanBuffer *interfaceScratchBuffer = static_cast(scratchBuffer.ref); - assert((interfaceScratchBuffer->desc.flags & RenderBufferFlag::ACCELERATION_STRUCTURE_SCRATCH) && "Scratch buffer must be allowed."); - - VkBufferDeviceAddressInfo scratchAddressInfo = {}; - scratchAddressInfo.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO; - scratchAddressInfo.buffer = interfaceScratchBuffer->vk; - - const VulkanBuffer *interfaceInstancesBuffer = static_cast(instancesBuffer.ref); - assert((interfaceInstancesBuffer->desc.flags & RenderBufferFlag::ACCELERATION_STRUCTURE_INPUT) && "Acceleration structure input must be allowed."); - - VkBufferDeviceAddressInfo instancesAddressInfo = {}; - instancesAddressInfo.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO; - instancesAddressInfo.buffer = interfaceInstancesBuffer->vk; - - VkAccelerationStructureGeometryKHR topGeometry = {}; - topGeometry.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR; - topGeometry.geometryType = VK_GEOMETRY_TYPE_INSTANCES_KHR; - - VkAccelerationStructureGeometryInstancesDataKHR &instancesData = topGeometry.geometry.instances; - instancesData.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_INSTANCES_DATA_KHR; - instancesData.data.deviceAddress = vkGetBufferDeviceAddress(device->vk, &instancesAddressInfo) + instancesBuffer.offset; - - VkAccelerationStructureBuildGeometryInfoKHR buildGeometryInfo = {}; - buildGeometryInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR; - buildGeometryInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR; - buildGeometryInfo.mode = VK_BUILD_ACCELERATION_STRUCTURE_MODE_BUILD_KHR; - buildGeometryInfo.dstAccelerationStructure = interfaceAccelerationStructure->vk; - buildGeometryInfo.scratchData.deviceAddress = vkGetBufferDeviceAddress(device->vk, &scratchAddressInfo) + scratchBuffer.offset; - buildGeometryInfo.pGeometries = &topGeometry; - buildGeometryInfo.geometryCount = 1; - - VkAccelerationStructureBuildRangeInfoKHR buildRangeInfo = {}; - buildRangeInfo.primitiveCount = buildInfo.instanceCount; - buildRangeInfo.primitiveOffset = 0; - buildRangeInfo.firstVertex = 0; - buildRangeInfo.transformOffset = 0; - - VkAccelerationStructureBuildRangeInfoKHR *buildRangeInfoPtr = &buildRangeInfo; - vkCmdBuildAccelerationStructuresKHR(vk, 1, &buildGeometryInfo, &buildRangeInfoPtr); - } - - void VulkanCommandList::discardTexture(const RenderTexture* texture) { - // Not required in Vulkan. - } - - void VulkanCommandList::resetQueryPool(const RenderQueryPool *queryPool, uint32_t queryFirstIndex, uint32_t queryCount) { - assert(queryPool != nullptr); - - const VulkanQueryPool *interfaceQueryPool = static_cast(queryPool); - vkCmdResetQueryPool(vk, interfaceQueryPool->vk, queryFirstIndex, queryCount); - } - - void VulkanCommandList::writeTimestamp(const RenderQueryPool *queryPool, uint32_t queryIndex) { - assert(queryPool != nullptr); - - const VulkanQueryPool *interfaceQueryPool = static_cast(queryPool); - vkCmdWriteTimestamp(vk, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, interfaceQueryPool->vk, queryIndex); - } - - void VulkanCommandList::checkActiveRenderPass() { - assert(targetFramebuffer != nullptr); - - if (activeRenderPass == VK_NULL_HANDLE) { - VkRenderPassBeginInfo beginInfo = {}; - beginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; - beginInfo.renderPass = targetFramebuffer->renderPass; - beginInfo.framebuffer = targetFramebuffer->vk; - beginInfo.renderArea.extent.width = targetFramebuffer->width; - beginInfo.renderArea.extent.height = targetFramebuffer->height; - vkCmdBeginRenderPass(vk, &beginInfo, VkSubpassContents::VK_SUBPASS_CONTENTS_INLINE); - activeRenderPass = targetFramebuffer->renderPass; - } - } - - void VulkanCommandList::endActiveRenderPass() { - if (activeRenderPass != VK_NULL_HANDLE) { - vkCmdEndRenderPass(vk); - activeRenderPass = VK_NULL_HANDLE; - } - } - - void VulkanCommandList::setDescriptorSet(VkPipelineBindPoint bindPoint, const VulkanPipelineLayout *pipelineLayout, const RenderDescriptorSet *descriptorSet, uint32_t setIndex) { - assert(pipelineLayout != nullptr); - assert(descriptorSet != nullptr); - assert(setIndex < pipelineLayout->descriptorSetLayouts.size()); - - const VulkanDescriptorSet *interfaceSet = static_cast(descriptorSet); - vkCmdBindDescriptorSets(vk, bindPoint, pipelineLayout->vk, setIndex, 1, &interfaceSet->vk, 0, nullptr); - } - - // VulkanCommandFence - - VulkanCommandFence::VulkanCommandFence(VulkanDevice *device) { - assert(device != nullptr); - - this->device = device; - - VkFenceCreateInfo fenceInfo = {}; - fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; - - VkResult res = vkCreateFence(device->vk, &fenceInfo, nullptr, &vk); - if (res != VK_SUCCESS) { - fprintf(stderr, "vkCreateFence failed with error code 0x%X.\n", res); - return; - } - } - - VulkanCommandFence::~VulkanCommandFence() { - if (vk != VK_NULL_HANDLE) { - vkDestroyFence(device->vk, vk, nullptr); - } - } - - // VulkanCommandSemaphore - - VulkanCommandSemaphore::VulkanCommandSemaphore(VulkanDevice *device) { - assert(device != nullptr); - - this->device = device; - - VkSemaphoreCreateInfo semaphoreInfo = {}; - semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; - - VkResult res = vkCreateSemaphore(device->vk, &semaphoreInfo, nullptr, &vk); - if (res != VK_SUCCESS) { - fprintf(stderr, "vkCreateSemaphore failed with error code 0x%X.\n", res); - return; - } - } - - VulkanCommandSemaphore::~VulkanCommandSemaphore() { - if (vk != VK_NULL_HANDLE) { - vkDestroySemaphore(device->vk, vk, nullptr); - } - } - - // VulkanCommandQueue - - VulkanCommandQueue::VulkanCommandQueue(VulkanDevice *device, RenderCommandListType commandListType) { - assert(device != nullptr); - assert(commandListType != RenderCommandListType::UNKNOWN); - - this->device = device; - - familyIndex = device->queueFamilyIndices[toFamilyIndex(commandListType)]; - device->queueFamilies[familyIndex].add(this); - } - - VulkanCommandQueue::~VulkanCommandQueue() { - device->queueFamilies[familyIndex].remove(this); - } - - std::unique_ptr VulkanCommandQueue::createSwapChain(RenderWindow renderWindow, uint32_t bufferCount, RenderFormat format, uint32_t maxFrameLatency) { - return std::make_unique(this, renderWindow, bufferCount, format, maxFrameLatency); - } - - void VulkanCommandQueue::executeCommandLists(const RenderCommandList **commandLists, uint32_t commandListCount, RenderCommandSemaphore **waitSemaphores, uint32_t waitSemaphoreCount, RenderCommandSemaphore **signalSemaphores, uint32_t signalSemaphoreCount, RenderCommandFence *signalFence) { - assert(commandLists != nullptr); - assert(commandListCount > 0); - - thread_local std::vector waitSemaphoreVector; - thread_local std::vector signalSemaphoreVector; - thread_local std::vector commandBuffers; - waitSemaphoreVector.clear(); - signalSemaphoreVector.clear(); - commandBuffers.clear(); - - for (uint32_t i = 0; i < waitSemaphoreCount; i++) { - VulkanCommandSemaphore *interfaceSemaphore = static_cast(waitSemaphores[i]); - waitSemaphoreVector.emplace_back(interfaceSemaphore->vk); - } - - for (uint32_t i = 0; i < signalSemaphoreCount; i++) { - VulkanCommandSemaphore *interfaceSemaphore = static_cast(signalSemaphores[i]); - signalSemaphoreVector.emplace_back(interfaceSemaphore->vk); - } - - for (uint32_t i = 0; i < commandListCount; i++) { - assert(commandLists[i] != nullptr); - - const VulkanCommandList *interfaceCommandList = static_cast(commandLists[i]); - commandBuffers.emplace_back(interfaceCommandList->vk); - } - - VkSubmitInfo submitInfo = {}; - submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - submitInfo.pCommandBuffers = commandBuffers.data(); - submitInfo.commandBufferCount = uint32_t(commandBuffers.size()); - - const VkPipelineStageFlags waitStages = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - if (!waitSemaphoreVector.empty()) { - submitInfo.pWaitSemaphores = waitSemaphoreVector.data(); - submitInfo.waitSemaphoreCount = uint32_t(waitSemaphoreVector.size()); - submitInfo.pWaitDstStageMask = &waitStages; - } - - if (!signalSemaphoreVector.empty()) { - submitInfo.pSignalSemaphores = signalSemaphoreVector.data(); - submitInfo.signalSemaphoreCount = uint32_t(signalSemaphoreVector.size()); - } - - VkFence submitFence = VK_NULL_HANDLE; - if (signalFence != nullptr) { - VulkanCommandFence *interfaceFence = static_cast(signalFence); - submitFence = interfaceFence->vk; - } - - VkResult res; - { - const std::scoped_lock queueLock(*queue->mutex); - res = vkQueueSubmit(queue->vk, 1, &submitInfo, submitFence); - } - - if (res != VK_SUCCESS) { - fprintf(stderr, "vkQueueSubmit failed with error code 0x%X.\n", res); - return; - } - } - - void VulkanCommandQueue::waitForCommandFence(RenderCommandFence *fence) { - assert(fence != nullptr); - - VulkanCommandFence *interfaceFence = static_cast(fence); - VkResult res = vkWaitForFences(device->vk, 1, &interfaceFence->vk, VK_TRUE, UINT64_MAX); - if (res != VK_SUCCESS) { - fprintf(stderr, "vkWaitForFences failed with error code 0x%X.\n", res); - return; - } - - vkResetFences(device->vk, 1, &interfaceFence->vk); - } - - // VulkanPool - - VulkanPool::VulkanPool(VulkanDevice *device, const RenderPoolDesc &desc) { - assert(device != nullptr); - - this->device = device; - - VmaAllocationCreateInfo memoryInfo = {}; - switch (desc.heapType) { - case RenderHeapType::DEFAULT: - memoryInfo.preferredFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; - break; - case RenderHeapType::UPLOAD: - memoryInfo.flags |= VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT; - break; - case RenderHeapType::READBACK: - memoryInfo.flags |= VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT; - break; - default: - assert(false && "Unknown heap type."); - break; - } - - uint32_t memoryTypeIndex = 0; - VkResult res = vmaFindMemoryTypeIndex(device->allocator, UINT32_MAX, &memoryInfo, &memoryTypeIndex); - if (res != VK_SUCCESS) { - fprintf(stderr, "vmaFindMemoryTypeIndex failed with error code 0x%X.\n", res); - return; - } - - VmaPoolCreateInfo createInfo = {}; - createInfo.memoryTypeIndex = memoryTypeIndex; - createInfo.minBlockCount = desc.minBlockCount; - createInfo.maxBlockCount = desc.maxBlockCount; - createInfo.flags |= desc.useLinearAlgorithm ? VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT : 0; - - res = vmaCreatePool(device->allocator, &createInfo, &vk); - if (res != VK_SUCCESS) { - fprintf(stderr, "vmaCreatePool failed with error code 0x%X.\n", res); - return; - } - } - - VulkanPool::~VulkanPool() { - if (vk != VK_NULL_HANDLE) { - vmaDestroyPool(device->allocator, vk); - } - } - - std::unique_ptr VulkanPool::createBuffer(const RenderBufferDesc &desc) { - return std::make_unique(device, this, desc); - } - - std::unique_ptr VulkanPool::createTexture(const RenderTextureDesc &desc) { - return std::make_unique(device, this, desc); - } - - // VulkanQueueFamily - - void VulkanQueueFamily::add(VulkanCommandQueue *virtualQueue) { - assert(virtualQueue != nullptr); - - // Insert virtual queue into the queue with the least amount of virtual queues. - uint32_t queueIndex = 0; - uint32_t lowestCount = UINT_MAX; - for (uint32_t i = 0; i < queues.size(); i++) { - uint32_t virtualQueueCount = uint32_t(queues[i].virtualQueues.size()); - if (virtualQueueCount < lowestCount) { - queueIndex = i; - lowestCount = virtualQueueCount; - } - } - - if (queues[queueIndex].mutex == nullptr) { - queues[queueIndex].mutex = std::make_unique(); - } - - virtualQueue->queue = &queues[queueIndex]; - virtualQueue->queueIndex = queueIndex; - queues[queueIndex].virtualQueues.insert(virtualQueue); - } - - void VulkanQueueFamily::remove(VulkanCommandQueue *virtualQueue) { - assert(virtualQueue != nullptr); - - queues[virtualQueue->queueIndex].virtualQueues.erase(virtualQueue); - } - - // VulkanDevice - - VulkanDevice::VulkanDevice(VulkanInterface *renderInterface, const std::string &preferredDeviceName) { - assert(renderInterface != nullptr); - - this->renderInterface = renderInterface; - - uint32_t deviceCount = 0; - vkEnumeratePhysicalDevices(renderInterface->instance, &deviceCount, nullptr); - if (deviceCount == 0) { - fprintf(stderr, "Unable to find devices that support Vulkan.\n"); - return; - } - - std::vector physicalDevices(deviceCount); - vkEnumeratePhysicalDevices(renderInterface->instance, &deviceCount, physicalDevices.data()); - - uint32_t currentDeviceTypeScore = 0; - uint32_t deviceTypeScoreTable[] = { - 0, // VK_PHYSICAL_DEVICE_TYPE_OTHER - 3, // VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU - 4, // VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU - 2, // VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU - 1 // VK_PHYSICAL_DEVICE_TYPE_CPU - }; - - for (uint32_t i = 0; i < deviceCount; i++) { - VkPhysicalDeviceProperties deviceProperties; - vkGetPhysicalDeviceProperties(physicalDevices[i], &deviceProperties); - - uint32_t deviceTypeIndex = deviceProperties.deviceType; - if (deviceTypeIndex > 4) { - continue; - } - - std::string deviceName(deviceProperties.deviceName); - uint32_t deviceTypeScore = deviceTypeScoreTable[deviceTypeIndex]; - bool preferDeviceTypeScore = (deviceTypeScore > currentDeviceTypeScore); - bool preferUserChoice = preferredDeviceName == deviceName; - bool preferOption = preferDeviceTypeScore || preferUserChoice; - if (preferOption) { - physicalDevice = physicalDevices[i]; - description.name = deviceName; - description.type = toDeviceType(deviceProperties.deviceType); - description.driverVersion = deviceProperties.driverVersion; - description.vendor = RenderDeviceVendor(deviceProperties.vendorID); - currentDeviceTypeScore = deviceTypeScore; - - if (preferUserChoice) { - break; - } - } - } - - if (physicalDevice == VK_NULL_HANDLE) { - fprintf(stderr, "Unable to find a device with the required features.\n"); - return; - } - - // Check for extensions. - uint32_t extensionCount; - vkEnumerateDeviceExtensionProperties(physicalDevice, nullptr, &extensionCount, nullptr); - - std::vector availableExtensions(extensionCount); - vkEnumerateDeviceExtensionProperties(physicalDevice, nullptr, &extensionCount, availableExtensions.data()); - - std::unordered_set missingRequiredExtensions = RequiredDeviceExtensions; - std::unordered_set supportedOptionalExtensions; -# if DLSS_ENABLED - const std::unordered_set dlssExtensions = DLSS::getRequiredDeviceExtensionsVulkan(this); -# endif - for (uint32_t i = 0; i < extensionCount; i++) { - const std::string extensionName(availableExtensions[i].extensionName); - missingRequiredExtensions.erase(extensionName); - - if (OptionalDeviceExtensions.find(extensionName) != OptionalDeviceExtensions.end()) { - supportedOptionalExtensions.insert(extensionName); - } -# if DLSS_ENABLED - else if (dlssExtensions.find(extensionName) != dlssExtensions.end()) { - supportedOptionalExtensions.insert(extensionName); - } -# endif - } - - if (!missingRequiredExtensions.empty()) { - for (const std::string &extension : missingRequiredExtensions) { - fprintf(stderr, "Missing required extension: %s.\n", extension.c_str()); - } - - fprintf(stderr, "Unable to create device. Required extensions are missing.\n"); - return; - } - - // Store properties. - vkGetPhysicalDeviceProperties(physicalDevice, &physicalDeviceProperties); - - // Check for supported features. - void *featuresChain = nullptr; - VkPhysicalDeviceDescriptorIndexingFeatures indexingFeatures = {}; - indexingFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES; - featuresChain = &indexingFeatures; - - VkPhysicalDeviceScalarBlockLayoutFeatures layoutFeatures = {}; - layoutFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SCALAR_BLOCK_LAYOUT_FEATURES; - layoutFeatures.pNext = featuresChain; - featuresChain = &layoutFeatures; - - VkPhysicalDevicePresentIdFeaturesKHR presentIdFeatures = {}; - VkPhysicalDevicePresentWaitFeaturesKHR presentWaitFeatures = {}; - const bool presentWaitSupported = supportedOptionalExtensions.find(VK_KHR_PRESENT_ID_EXTENSION_NAME) != supportedOptionalExtensions.end() && supportedOptionalExtensions.find(VK_KHR_PRESENT_WAIT_EXTENSION_NAME) != supportedOptionalExtensions.end(); - if (presentWaitSupported) { - presentIdFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_ID_FEATURES_KHR; - presentIdFeatures.pNext = featuresChain; - featuresChain = &presentIdFeatures; - - presentWaitFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_WAIT_FEATURES_KHR; - presentWaitFeatures.pNext = featuresChain; - featuresChain = &presentWaitFeatures; - } - - VkPhysicalDeviceRobustness2FeaturesEXT robustnessFeatures = {}; - robustnessFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_FEATURES_EXT; - robustnessFeatures.pNext = featuresChain; - featuresChain = &robustnessFeatures; - - VkPhysicalDeviceBufferDeviceAddressFeatures bufferDeviceAddressFeatures = {}; - bufferDeviceAddressFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES; - bufferDeviceAddressFeatures.pNext = featuresChain; - featuresChain = &bufferDeviceAddressFeatures; - - VkPhysicalDevicePortabilitySubsetFeaturesKHR portabilityFeatures = {}; - portabilityFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PORTABILITY_SUBSET_FEATURES_KHR; - portabilityFeatures.pNext = featuresChain; - featuresChain = &portabilityFeatures; - - VkPhysicalDeviceFeatures2 deviceFeatures = {}; - deviceFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; - deviceFeatures.pNext = featuresChain; - vkGetPhysicalDeviceFeatures2(physicalDevice, &deviceFeatures); - - void *createDeviceChain = nullptr; - VkPhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeatures = {}; - VkPhysicalDeviceAccelerationStructureFeaturesKHR accelerationStructureFeatures = {}; - const bool rtSupported = supportedOptionalExtensions.find(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME) != supportedOptionalExtensions.end(); - if (rtSupported) { - rtPipelineProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR; - - VkPhysicalDeviceProperties2 deviceProperties2 = {}; - deviceProperties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; - deviceProperties2.pNext = &rtPipelineProperties; - vkGetPhysicalDeviceProperties2(physicalDevice, &deviceProperties2); - - rtPipelineFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR; - rtPipelineFeatures.rayTracingPipeline = true; - createDeviceChain = &rtPipelineFeatures; - - accelerationStructureFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR; - accelerationStructureFeatures.pNext = createDeviceChain; - accelerationStructureFeatures.accelerationStructure = true; - createDeviceChain = &accelerationStructureFeatures; - } - - const bool sampleLocationsSupported = supportedOptionalExtensions.find(VK_EXT_SAMPLE_LOCATIONS_EXTENSION_NAME) != supportedOptionalExtensions.end(); - if (sampleLocationsSupported) { - sampleLocationProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLE_LOCATIONS_PROPERTIES_EXT; - - VkPhysicalDeviceProperties2 deviceProperties2 = {}; - deviceProperties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; - deviceProperties2.pNext = &sampleLocationProperties; - vkGetPhysicalDeviceProperties2(physicalDevice, &deviceProperties2); - } - - const bool descriptorIndexing = indexingFeatures.descriptorBindingPartiallyBound && indexingFeatures.descriptorBindingVariableDescriptorCount && indexingFeatures.runtimeDescriptorArray; - if (descriptorIndexing) { - indexingFeatures.pNext = createDeviceChain; - createDeviceChain = &indexingFeatures; - } - - const bool scalarBlockLayout = layoutFeatures.scalarBlockLayout; - if (scalarBlockLayout) { - layoutFeatures.pNext = createDeviceChain; - createDeviceChain = &layoutFeatures; - } - - const bool presentWait = presentIdFeatures.presentId && presentWaitFeatures.presentWait; - if (presentWait) { - presentIdFeatures.pNext = createDeviceChain; - createDeviceChain = &presentIdFeatures; - - presentWaitFeatures.pNext = createDeviceChain; - createDeviceChain = &presentWaitFeatures; - } - - const bool nullDescriptor = robustnessFeatures.nullDescriptor; - if (nullDescriptor) { - robustnessFeatures.pNext = createDeviceChain; - createDeviceChain = &robustnessFeatures; - } - - const bool bufferDeviceAddress = bufferDeviceAddressFeatures.bufferDeviceAddress; - if (bufferDeviceAddress) { - bufferDeviceAddressFeatures.pNext = createDeviceChain; - createDeviceChain = &bufferDeviceAddressFeatures; - } - - const bool portabilitySubset = supportedOptionalExtensions.find(VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME) != supportedOptionalExtensions.end(); - if (portabilitySubset) { - portabilityFeatures.pNext = createDeviceChain; - createDeviceChain = &portabilityFeatures; - } - - // Retrieve the information for the queue families. - uint32_t queueFamilyCount = 0; - vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamilyCount, nullptr); - - std::vector queueFamilyProperties(queueFamilyCount); - std::vector queueFamilyUsed(queueFamilyCount, false); - vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamilyCount, queueFamilyProperties.data()); - - auto pickFamilyQueue = [&](RenderCommandListType type, VkQueueFlags flags) { - uint32_t familyIndex = 0; - uint32_t familySetBits = sizeof(uint32_t) * 8; - uint32_t familyQueueCount = 0; - bool familyUsed = false; - for (uint32_t i = 0; i < queueFamilyCount; i++) { - const VkQueueFamilyProperties &props = queueFamilyProperties[i]; - - // The family queue flags must contain all the flags required by the command list type. - if ((props.queueFlags & flags) != flags) { - continue; - } - - // Prefer picking the queues with the least amount of bits set that match the mask we're looking for. - // If the queue families have matching capabilities but one is already used, prefer the unused one. - uint32_t setBits = numberOfSetBits(props.queueFlags); - bool used = queueFamilyUsed[i]; - if ((setBits < familySetBits) || ((setBits == familySetBits) && ((props.queueCount > familyQueueCount) || (familyUsed && !used)))) { - familyIndex = i; - familySetBits = setBits; - familyQueueCount = props.queueCount; - familyUsed = used; - } - } - - queueFamilyIndices[toFamilyIndex(type)] = familyIndex; - queueFamilyUsed[familyIndex] = true; - }; - - // Pick the family queues for each type of command list. - pickFamilyQueue(RenderCommandListType::DIRECT, VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT); - pickFamilyQueue(RenderCommandListType::COMPUTE, VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT); - pickFamilyQueue(RenderCommandListType::COPY, VK_QUEUE_TRANSFER_BIT); - - // Create the struct to store the virtual queues. - queueFamilies.resize(queueFamilyCount); - - // Create the logical device with the desired family queues. - std::vector queueCreateInfos; - std::vector queuePriorities(MaxQueuesPerFamilyCount, 1.0f); - queueCreateInfos.reserve(queueFamilyCount); - for (uint32_t i = 0; i < queueFamilyCount; i++) { - if (queueFamilyUsed[i]) { - VkDeviceQueueCreateInfo queueCreateInfo = {}; - queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; - queueCreateInfo.queueCount = std::min(queueFamilyProperties[i].queueCount, MaxQueuesPerFamilyCount); - queueCreateInfo.queueFamilyIndex = i; - queueCreateInfo.pQueuePriorities = queuePriorities.data(); - queueCreateInfos.emplace_back(queueCreateInfo); - queueFamilies[i].queues.resize(queueCreateInfo.queueCount); - } - } - - std::vector enabledExtensions; - for (const std::string &extension : RequiredDeviceExtensions) { - enabledExtensions.push_back(extension.c_str()); - } - - for (const std::string &extension : supportedOptionalExtensions) { - enabledExtensions.push_back(extension.c_str()); - } - - VkDeviceCreateInfo createInfo = {}; - createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; - createInfo.pNext = createDeviceChain; - createInfo.pQueueCreateInfos = queueCreateInfos.data(); - createInfo.queueCreateInfoCount = uint32_t(queueCreateInfos.size()); - createInfo.ppEnabledExtensionNames = enabledExtensions.data(); - createInfo.enabledExtensionCount = uint32_t(enabledExtensions.size()); - createInfo.pEnabledFeatures = &deviceFeatures.features; - - VkResult res = vkCreateDevice(physicalDevice, &createInfo, nullptr, &vk); - if (res != VK_SUCCESS) { - fprintf(stderr, "vkCreateDevice failed with error code 0x%X.\n", res); - return; - } - - for (uint32_t i = 0; i < queueFamilyCount; i++) { - for (uint32_t j = 0; j < queueFamilies[i].queues.size(); j++) { - vkGetDeviceQueue(vk, i, j, &queueFamilies[i].queues[j].vk); - } - } - - VmaVulkanFunctions vmaFunctions = {}; - vmaFunctions.vkGetInstanceProcAddr = vkGetInstanceProcAddr; - vmaFunctions.vkGetDeviceProcAddr = vkGetDeviceProcAddr; - vmaFunctions.vkAllocateMemory = vkAllocateMemory; - vmaFunctions.vkBindBufferMemory = vkBindBufferMemory; - vmaFunctions.vkBindImageMemory = vkBindImageMemory; - vmaFunctions.vkCreateBuffer = vkCreateBuffer; - vmaFunctions.vkCreateImage = vkCreateImage; - vmaFunctions.vkDestroyBuffer = vkDestroyBuffer; - vmaFunctions.vkDestroyImage = vkDestroyImage; - vmaFunctions.vkFlushMappedMemoryRanges = vkFlushMappedMemoryRanges; - vmaFunctions.vkFreeMemory = vkFreeMemory; - vmaFunctions.vkGetBufferMemoryRequirements = vkGetBufferMemoryRequirements; - vmaFunctions.vkGetImageMemoryRequirements = vkGetImageMemoryRequirements; - vmaFunctions.vkGetPhysicalDeviceMemoryProperties = vkGetPhysicalDeviceMemoryProperties; - vmaFunctions.vkGetPhysicalDeviceProperties = vkGetPhysicalDeviceProperties; - vmaFunctions.vkInvalidateMappedMemoryRanges = vkInvalidateMappedMemoryRanges; - vmaFunctions.vkMapMemory = vkMapMemory; - vmaFunctions.vkUnmapMemory = vkUnmapMemory; - vmaFunctions.vkCmdCopyBuffer = vkCmdCopyBuffer; - - VmaAllocatorCreateInfo allocatorInfo = {}; - allocatorInfo.flags |= bufferDeviceAddress ? VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT : 0; - allocatorInfo.physicalDevice = physicalDevice; - allocatorInfo.device = vk; - allocatorInfo.pVulkanFunctions = &vmaFunctions; - allocatorInfo.instance = renderInterface->instance; - allocatorInfo.vulkanApiVersion = renderInterface->appInfo.apiVersion; - - res = vmaCreateAllocator(&allocatorInfo, &allocator); - if (res != VK_SUCCESS) { - fprintf(stderr, "vmaCreateAllocator failed with error code 0x%X.\n", res); - release(); - return; - } - - // Find the biggest device local memory available on the device. - VkDeviceSize memoryHeapSize = 0; - const VkPhysicalDeviceMemoryProperties *memoryProps = nullptr; - vmaGetMemoryProperties(allocator, &memoryProps); - - constexpr VkMemoryPropertyFlags uploadHeapPropertyFlags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; - bool hasHostVisibleDeviceLocalMemory = false; - for (uint32_t i = 0; i < memoryProps->memoryTypeCount; i++) { - if ((memoryProps->memoryTypes[i].propertyFlags & uploadHeapPropertyFlags) == uploadHeapPropertyFlags) { - hasHostVisibleDeviceLocalMemory = true; - } - } - - for (uint32_t i = 0; i < memoryProps->memoryHeapCount; i++) { - if (memoryProps->memoryHeaps[i].flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) { - memoryHeapSize = std::max(memoryProps->memoryHeaps[i].size, memoryHeapSize); - } - } - - // Fill description. - description.dedicatedVideoMemory = memoryHeapSize; - - // Fill capabilities. - capabilities.geometryShader = deviceFeatures.features.geometryShader; - capabilities.raytracing = rtSupported; - capabilities.raytracingStateUpdate = false; - capabilities.sampleLocations = sampleLocationsSupported; - capabilities.descriptorIndexing = descriptorIndexing; - capabilities.scalarBlockLayout = scalarBlockLayout; - capabilities.presentWait = presentWait; - capabilities.displayTiming = supportedOptionalExtensions.find(VK_GOOGLE_DISPLAY_TIMING_EXTENSION_NAME) != supportedOptionalExtensions.end(); - capabilities.preferHDR = memoryHeapSize > (512 * 1024 * 1024); -#if defined(__APPLE__) - // MoltenVK supports triangle fans but does so via compute shaders to translate to lists, since it has to - // support all cases including indirect draw. This results in renderpass restarts that can harm performance, - // so force disable native triangle fan support and rely on the game to emulate fans if needed. - capabilities.triangleFan = false; -#else - capabilities.triangleFan = true; -#endif - capabilities.dynamicDepthBias = true; - capabilities.uma = (description.type == RenderDeviceType::INTEGRATED) && hasHostVisibleDeviceLocalMemory; - capabilities.gpuUploadHeap = capabilities.uma; - - // Fill Vulkan-only capabilities. - loadStoreOpNoneSupported = supportedOptionalExtensions.find(VK_EXT_LOAD_STORE_OP_NONE_EXTENSION_NAME) != supportedOptionalExtensions.end(); - nullDescriptorSupported = nullDescriptor; - - if (!nullDescriptorSupported) { - nullBuffer = createBuffer(RenderBufferDesc::DefaultBuffer(16, RenderBufferFlag::VERTEX)); - } - } - - VulkanDevice::~VulkanDevice() { - release(); - } - - std::unique_ptr VulkanDevice::createCommandList(RenderCommandListType type) { - return std::make_unique(this, type); - } - - std::unique_ptr VulkanDevice::createDescriptorSet(const RenderDescriptorSetDesc &desc) { - return std::make_unique(this, desc); - } - - std::unique_ptr VulkanDevice::createShader(const void *data, uint64_t size, const char *entryPointName, RenderShaderFormat format) { - return std::make_unique(this, data, size, entryPointName, format); - } - - std::unique_ptr VulkanDevice::createSampler(const RenderSamplerDesc &desc) { - return std::make_unique(this, desc); - } - - std::unique_ptr VulkanDevice::createComputePipeline(const RenderComputePipelineDesc &desc) { - return std::make_unique(this, desc); - } - - std::unique_ptr VulkanDevice::createGraphicsPipeline(const RenderGraphicsPipelineDesc &desc) { - return std::make_unique(this, desc); - } - - std::unique_ptr VulkanDevice::createRaytracingPipeline(const RenderRaytracingPipelineDesc &desc, const RenderPipeline *previousPipeline) { - return std::make_unique(this, desc, previousPipeline); - } - - std::unique_ptr VulkanDevice::createCommandQueue(RenderCommandListType type) { - return std::make_unique(this, type); - } - - std::unique_ptr VulkanDevice::createBuffer(const RenderBufferDesc &desc) { - return std::make_unique(this, nullptr, desc); - } - - std::unique_ptr VulkanDevice::createTexture(const RenderTextureDesc &desc) { - return std::make_unique(this, nullptr, desc); - } - - std::unique_ptr VulkanDevice::createAccelerationStructure(const RenderAccelerationStructureDesc &desc) { - return std::make_unique(this, desc); - } - - std::unique_ptr VulkanDevice::createPool(const RenderPoolDesc &desc) { - return std::make_unique(this, desc); - } - - std::unique_ptr VulkanDevice::createPipelineLayout(const RenderPipelineLayoutDesc &desc) { - return std::make_unique(this, desc); - } - - std::unique_ptr VulkanDevice::createCommandFence() { - return std::make_unique(this); - } - - std::unique_ptr VulkanDevice::createCommandSemaphore() { - return std::make_unique(this); - } - - std::unique_ptr VulkanDevice::createFramebuffer(const RenderFramebufferDesc &desc) { - return std::make_unique(this, desc); - } - - std::unique_ptr VulkanDevice::createQueryPool(uint32_t queryCount) { - return std::make_unique(this, queryCount); - } - - void VulkanDevice::setBottomLevelASBuildInfo(RenderBottomLevelASBuildInfo &buildInfo, const RenderBottomLevelASMesh *meshes, uint32_t meshCount, bool preferFastBuild, bool preferFastTrace) { - assert(meshes != nullptr); - assert(meshCount > 0); - - uint32_t primitiveCount = 0; - thread_local std::vector geometryPrimitiveCounts; - geometryPrimitiveCounts.resize(meshCount); - - buildInfo.buildData.resize(sizeof(VkAccelerationStructureGeometryKHR) * meshCount); - VkAccelerationStructureGeometryKHR *geometries = reinterpret_cast(buildInfo.buildData.data()); - for (uint32_t i = 0; i < meshCount; i++) { - const RenderBottomLevelASMesh &mesh = meshes[i]; - VkAccelerationStructureGeometryKHR &geometry = geometries[i]; - geometry = {}; - geometry.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR; - geometry.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR; - geometry.flags = VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_KHR; - geometry.flags |= mesh.isOpaque ? VK_GEOMETRY_OPAQUE_BIT_KHR : 0; - - const VulkanBuffer *interfaceVertexBuffer = static_cast(mesh.vertexBuffer.ref); - const VulkanBuffer *interfaceIndexBuffer = static_cast(mesh.indexBuffer.ref); - assert((interfaceIndexBuffer == nullptr) || ((interfaceIndexBuffer->desc.flags & RenderBufferFlag::ACCELERATION_STRUCTURE_INPUT) && "Acceleration structure input allowed on index buffer.")); - assert((interfaceVertexBuffer == nullptr) || ((interfaceVertexBuffer->desc.flags & RenderBufferFlag::ACCELERATION_STRUCTURE_INPUT) && "Acceleration structure input allowed on vertex buffer.")); - - VkAccelerationStructureGeometryTrianglesDataKHR &triangles = geometry.geometry.triangles; - triangles = {}; - triangles.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR; - triangles.vertexFormat = toVk(mesh.vertexFormat); - triangles.vertexStride = mesh.vertexStride; - triangles.maxVertex = mesh.vertexCount - 1; - - if (interfaceVertexBuffer != nullptr) { - VkBufferDeviceAddressInfo vertexAddressInfo = {}; - vertexAddressInfo.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO; - vertexAddressInfo.buffer = interfaceVertexBuffer->vk; - triangles.vertexData.deviceAddress = vkGetBufferDeviceAddress(vk, &vertexAddressInfo) + mesh.vertexBuffer.offset; - } - - if (interfaceIndexBuffer != nullptr) { - triangles.indexType = toIndexType(mesh.indexFormat); - - VkBufferDeviceAddressInfo indexAddressInfo = {}; - indexAddressInfo.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO; - indexAddressInfo.buffer = interfaceIndexBuffer->vk; - triangles.indexData.deviceAddress = vkGetBufferDeviceAddress(vk, &indexAddressInfo) + mesh.indexBuffer.offset; - geometryPrimitiveCounts[i] = mesh.indexCount / 3; - } - else { - triangles.indexType = VK_INDEX_TYPE_NONE_KHR; - geometryPrimitiveCounts[i] = mesh.vertexCount / 3; - } - - primitiveCount += geometryPrimitiveCounts[i]; - } - - VkAccelerationStructureBuildGeometryInfoKHR buildGeometryInfo = {}; - buildGeometryInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR; - buildGeometryInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR; - buildGeometryInfo.flags = toRTASBuildFlags(preferFastBuild, preferFastTrace); - buildGeometryInfo.mode = VK_BUILD_ACCELERATION_STRUCTURE_MODE_BUILD_KHR; - buildGeometryInfo.pGeometries = geometries; - buildGeometryInfo.geometryCount = meshCount; - - VkAccelerationStructureBuildSizesInfoKHR buildSizesInfo = {}; - buildSizesInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_SIZES_INFO_KHR; - vkGetAccelerationStructureBuildSizesKHR(vk, VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR, &buildGeometryInfo, geometryPrimitiveCounts.data(), &buildSizesInfo); - - buildInfo.meshCount = meshCount; - buildInfo.primitiveCount = primitiveCount; - buildInfo.preferFastBuild = preferFastBuild; - buildInfo.preferFastTrace = preferFastTrace; - buildInfo.scratchSize = roundUp(buildSizesInfo.buildScratchSize, AccelerationStructureBufferAlignment); - buildInfo.accelerationStructureSize = roundUp(buildSizesInfo.accelerationStructureSize, AccelerationStructureBufferAlignment); - } - - void VulkanDevice::setTopLevelASBuildInfo(RenderTopLevelASBuildInfo &buildInfo, const RenderTopLevelASInstance *instances, uint32_t instanceCount, bool preferFastBuild, bool preferFastTrace) { - assert(instances != nullptr); - assert(instanceCount > 0); - - // Build the instance data to be uploaded. - buildInfo.instancesBufferData.resize(sizeof(VkAccelerationStructureInstanceKHR) * instanceCount, 0); - VkAccelerationStructureInstanceKHR *bufferInstances = reinterpret_cast(buildInfo.instancesBufferData.data()); - for (uint32_t i = 0; i < instanceCount; i++) { - const RenderTopLevelASInstance &instance = instances[i]; - const VulkanBuffer *interfaceBottomLevelAS = static_cast(instance.bottomLevelAS.ref); - assert(interfaceBottomLevelAS != nullptr); - - VkAccelerationStructureInstanceKHR &bufferInstance = bufferInstances[i]; - bufferInstance.instanceCustomIndex = instance.instanceID; - bufferInstance.mask = instance.instanceMask; - bufferInstance.instanceShaderBindingTableRecordOffset = instance.instanceContributionToHitGroupIndex; - bufferInstance.flags = instance.cullDisable ? VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR : 0; - memcpy(bufferInstance.transform.matrix, instance.transform.m, sizeof(bufferInstance.transform.matrix)); - - VkBufferDeviceAddressInfo blasAddressInfo = {}; - blasAddressInfo.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO; - blasAddressInfo.buffer = interfaceBottomLevelAS->vk; - bufferInstance.accelerationStructureReference = vkGetBufferDeviceAddress(vk, &blasAddressInfo) + instance.bottomLevelAS.offset; - } - - // Retrieve the size the TLAS will require. - VkAccelerationStructureGeometryKHR topGeometry = {}; - topGeometry.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR; - topGeometry.geometryType = VK_GEOMETRY_TYPE_INSTANCES_KHR; - - VkAccelerationStructureGeometryInstancesDataKHR &instancesData = topGeometry.geometry.instances; - instancesData.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_INSTANCES_DATA_KHR; - - VkAccelerationStructureBuildGeometryInfoKHR buildGeometryInfo = {}; - buildGeometryInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR; - buildGeometryInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR; - buildGeometryInfo.flags = toRTASBuildFlags(preferFastBuild, preferFastTrace); - buildGeometryInfo.mode = VK_BUILD_ACCELERATION_STRUCTURE_MODE_BUILD_KHR; - buildGeometryInfo.pGeometries = &topGeometry; - buildGeometryInfo.geometryCount = 1; - - VkAccelerationStructureBuildSizesInfoKHR buildSizesInfo = {}; - buildSizesInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_SIZES_INFO_KHR; - vkGetAccelerationStructureBuildSizesKHR(vk, VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR, &buildGeometryInfo, &instanceCount, &buildSizesInfo); - - buildInfo.instanceCount = instanceCount; - buildInfo.preferFastBuild = preferFastBuild; - buildInfo.preferFastTrace = preferFastTrace; - buildInfo.scratchSize = roundUp(buildSizesInfo.buildScratchSize, AccelerationStructureBufferAlignment); - buildInfo.accelerationStructureSize = roundUp(buildSizesInfo.accelerationStructureSize, AccelerationStructureBufferAlignment); - } - - void VulkanDevice::setShaderBindingTableInfo(RenderShaderBindingTableInfo &tableInfo, const RenderShaderBindingGroups &groups, const RenderPipeline *pipeline, RenderDescriptorSet **descriptorSets, uint32_t descriptorSetCount) { - assert(pipeline != nullptr); - assert((descriptorSets != nullptr) && "Vulkan doesn't require descriptor sets, but they should be passed to keep consistency with D3D12."); - - const VulkanRaytracingPipeline *raytracingPipeline = static_cast(pipeline); - assert((raytracingPipeline->type == VulkanPipeline::Type::Raytracing) && "Only raytracing pipelines can be used to build shader binding tables."); - assert((raytracingPipeline->descriptorSetCount <= descriptorSetCount) && "There must be enough descriptor sets available for the pipeline."); - - const uint32_t handleSize = rtPipelineProperties.shaderGroupHandleSize; - thread_local std::vector groupHandles; - groupHandles.clear(); - groupHandles.resize(raytracingPipeline->groupCount * handleSize, 0); - VkResult res = vkGetRayTracingShaderGroupHandlesKHR(vk, raytracingPipeline->vk, 0, raytracingPipeline->groupCount, groupHandles.size(), groupHandles.data()); - if (res != VK_SUCCESS) { - fprintf(stderr, "vkGetRayTracingShaderGroupHandlesKHR failed with error code 0x%X.\n", res); - return; - } - - const uint32_t handleSizeAligned = roundUp(handleSize, rtPipelineProperties.shaderGroupHandleAlignment); - const uint32_t regionAlignment = roundUp(handleSizeAligned, rtPipelineProperties.shaderGroupBaseAlignment); - uint64_t tableSize = 0; - - auto setGroup = [&](RenderShaderBindingGroupInfo &groupInfo, const RenderShaderBindingGroup &renderGroup) { - groupInfo.startIndex = 0; - - if (renderGroup.pipelineProgramsCount == 0) { - groupInfo.stride = 0; - groupInfo.offset = 0; - groupInfo.size = 0; - } - else { - groupInfo.stride = regionAlignment; - groupInfo.offset = tableSize; - groupInfo.size = groupInfo.stride * renderGroup.pipelineProgramsCount; - tableSize += groupInfo.size; - } - }; - - setGroup(tableInfo.groups.rayGen, groups.rayGen); - setGroup(tableInfo.groups.miss, groups.miss); - setGroup(tableInfo.groups.hitGroup, groups.hitGroup); - setGroup(tableInfo.groups.callable, groups.callable); - - tableSize = roundUp(tableSize, ShaderBindingTableAlignment); - tableInfo.tableBufferData.clear(); - tableInfo.tableBufferData.resize(tableSize, 0); - - auto copyGroupData = [&](RenderShaderBindingGroupInfo &groupInfo, const RenderShaderBindingGroup &renderGroup) { - for (uint32_t i = 0; i < renderGroup.pipelineProgramsCount; i++) { - const uint8_t *shaderId = groupHandles.data() + renderGroup.pipelinePrograms[i].programIndex * handleSize; - const uint64_t tableOffset = groupInfo.offset + i * groupInfo.stride; - memcpy(&tableInfo.tableBufferData[tableOffset], shaderId, handleSize); - } - }; - - copyGroupData(tableInfo.groups.rayGen, groups.rayGen); - copyGroupData(tableInfo.groups.miss, groups.miss); - copyGroupData(tableInfo.groups.hitGroup, groups.hitGroup); - copyGroupData(tableInfo.groups.callable, groups.callable); - } - - const RenderDeviceCapabilities &VulkanDevice::getCapabilities() const { - return capabilities; - } - - const RenderDeviceDescription &VulkanDevice::getDescription() const { - return description; - } - - RenderSampleCounts VulkanDevice::getSampleCountsSupported(RenderFormat format) const { - const bool isDepthFormat = (format == RenderFormat::D16_UNORM) || (format == RenderFormat::D32_FLOAT); - if (isDepthFormat) { - return RenderSampleCounts(physicalDeviceProperties.limits.framebufferDepthSampleCounts); - } - else { - return RenderSampleCounts(physicalDeviceProperties.limits.framebufferColorSampleCounts); - } - } - - void VulkanDevice::waitIdle() const { - vkDeviceWaitIdle(vk); - } - - void VulkanDevice::release() { - if (allocator != VK_NULL_HANDLE) { - vmaDestroyAllocator(allocator); - allocator = VK_NULL_HANDLE; - } - - if (vk != VK_NULL_HANDLE) { - vkDestroyDevice(vk, nullptr); - vk = VK_NULL_HANDLE; - } - } - - bool VulkanDevice::isValid() const { - return vk != nullptr; - } - - // VulkanInterface - -#if SDL_VULKAN_ENABLED - VulkanInterface::VulkanInterface(RenderWindow sdlWindow) { -#else - VulkanInterface::VulkanInterface() { -#endif - VkResult res = volkInitialize(); - if (res != VK_SUCCESS) { - fprintf(stderr, "volkInitialize failed with error code 0x%X.\n", res); - return; - } - - appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; - appInfo.pApplicationName = "plume"; - appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0); - appInfo.pEngineName = "plume"; - appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0); - appInfo.apiVersion = VK_API_VERSION_1_2; - - VkInstanceCreateInfo createInfo = {}; - createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; - createInfo.pApplicationInfo = &appInfo; - createInfo.ppEnabledLayerNames = nullptr; - createInfo.enabledLayerCount = 0; - -# ifdef __APPLE__ - createInfo.flags |= VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR; -# endif - - // Check for extensions. - uint32_t extensionCount; - vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, nullptr); - - std::vector availableExtensions(extensionCount); - vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, availableExtensions.data()); - - std::unordered_set requiredExtensions = RequiredInstanceExtensions; - std::unordered_set supportedOptionalExtensions; -# if DLSS_ENABLED - const std::unordered_set dlssExtensions = DLSS::getRequiredInstanceExtensionsVulkan(); -# endif - -# if SDL_VULKAN_ENABLED - // Push the extensions specified by SDL as required. - // SDL2 has this awkward requirement for the window to pull the extensions from. - // This can be removed when upgrading to SDL3. - if (sdlWindow != nullptr) { - uint32_t sdlVulkanExtensionCount = 0; - if (SDL_Vulkan_GetInstanceExtensions(sdlWindow, &sdlVulkanExtensionCount, nullptr)) { - std::vector sdlVulkanExtensions; - sdlVulkanExtensions.resize(sdlVulkanExtensionCount); - if (SDL_Vulkan_GetInstanceExtensions(sdlWindow, &sdlVulkanExtensionCount, (const char **)(sdlVulkanExtensions.data()))) { - for (char *sdlVulkanExtension : sdlVulkanExtensions) { - requiredExtensions.insert(sdlVulkanExtension); - } - } - } - } -# endif - - std::unordered_set missingRequiredExtensions = requiredExtensions; - for (uint32_t i = 0; i < extensionCount; i++) { - const std::string extensionName(availableExtensions[i].extensionName); - missingRequiredExtensions.erase(extensionName); - - if (OptionalInstanceExtensions.find(extensionName) != OptionalInstanceExtensions.end()) { - supportedOptionalExtensions.insert(extensionName); - } -# if DLSS_ENABLED - else if (dlssExtensions.find(extensionName) != dlssExtensions.end()) { - supportedOptionalExtensions.insert(extensionName); - } -# endif - } - - if (!missingRequiredExtensions.empty()) { - for (const std::string &extension : missingRequiredExtensions) { - fprintf(stderr, "Missing required extension: %s.\n", extension.c_str()); - } - - fprintf(stderr, "Unable to create instance. Required extensions are missing.\n"); - return; - } - - std::vector enabledExtensions; - for (const std::string &extension : requiredExtensions) { - enabledExtensions.push_back(extension.c_str()); - } - - for (const std::string &extension : supportedOptionalExtensions) { - enabledExtensions.push_back(extension.c_str()); - } - - createInfo.ppEnabledExtensionNames = enabledExtensions.data(); - createInfo.enabledExtensionCount = uint32_t(enabledExtensions.size()); - -# ifdef VULKAN_VALIDATION_LAYER_ENABLED - // Search for validation layer and enabled it. - uint32_t layerCount; - vkEnumerateInstanceLayerProperties(&layerCount, nullptr); - - std::vector availableLayers(layerCount); - vkEnumerateInstanceLayerProperties(&layerCount, availableLayers.data()); - - const char validationLayerName[] = "VK_LAYER_KHRONOS_validation"; - const char *enabledLayerNames[] = { validationLayerName }; - for (const VkLayerProperties &layerProperties : availableLayers) { - if (strcmp(layerProperties.layerName, validationLayerName) == 0) { - createInfo.ppEnabledLayerNames = enabledLayerNames; - createInfo.enabledLayerCount = 1; - break; - } - } -# endif - - res = vkCreateInstance(&createInfo, nullptr, &instance); - if (res != VK_SUCCESS) { - fprintf(stderr, "vkCreateInstance failed with error code 0x%X.\n", res); - return; - } - - volkLoadInstance(instance); - - // Fill capabilities. - capabilities.shaderFormat = RenderShaderFormat::SPIRV; - - // Fill device names. - uint32_t deviceCount = 0; - vkEnumeratePhysicalDevices(instance, &deviceCount, nullptr); - if (deviceCount > 0) { - std::vector physicalDevices(deviceCount); - vkEnumeratePhysicalDevices(instance, &deviceCount, physicalDevices.data()); - - for (uint32_t i = 0; i < deviceCount; i++) { - VkPhysicalDeviceProperties deviceProperties; - vkGetPhysicalDeviceProperties(physicalDevices[i], &deviceProperties); - uint32_t deviceTypeIndex = deviceProperties.deviceType; - if (deviceTypeIndex <= 4) { - deviceNames.emplace_back(deviceProperties.deviceName); - } - } - } - } - - VulkanInterface::~VulkanInterface() { - if (instance != nullptr) { - vkDestroyInstance(instance, nullptr); - } - } - - std::unique_ptr VulkanInterface::createDevice(const std::string &preferredDeviceName) { - std::unique_ptr createdDevice = std::make_unique(this, preferredDeviceName); - return createdDevice->isValid() ? std::move(createdDevice) : nullptr; - } - - const RenderInterfaceCapabilities &VulkanInterface::getCapabilities() const { - return capabilities; - } - - const std::vector &VulkanInterface::getDeviceNames() const { - return deviceNames; - } - - bool VulkanInterface::isValid() const { - return instance != nullptr; - } - - // Global creation function. - -#if SDL_VULKAN_ENABLED - std::unique_ptr CreateVulkanInterface(RenderWindow sdlWindow) { - std::unique_ptr createdInterface = std::make_unique(sdlWindow); - return createdInterface->isValid() ? std::move(createdInterface) : nullptr; - } -#else - std::unique_ptr CreateVulkanInterface() { - std::unique_ptr createdInterface = std::make_unique(); - return createdInterface->isValid() ? std::move(createdInterface) : nullptr; - } -#endif -}; diff --git a/UnleashedRecomp/gpu/rhi/plume_vulkan.h b/UnleashedRecomp/gpu/rhi/plume_vulkan.h deleted file mode 100644 index bbdd62c..0000000 --- a/UnleashedRecomp/gpu/rhi/plume_vulkan.h +++ /dev/null @@ -1,463 +0,0 @@ -// -// plume -// -// Copyright (c) 2024 renderbag and contributors. All rights reserved. -// Licensed under the MIT license. See LICENSE file for details. -// - -#pragma once - -#include "plume_render_interface.h" - -#include -#include -#include -#include - -#if defined(_WIN64) -#define VK_USE_PLATFORM_WIN32_KHR -#elif defined(__ANDROID__) -#define VK_USE_PLATFORM_ANDROID_KHR -#elif defined(__linux__) -#define VK_USE_PLATFORM_XLIB_KHR -#elif defined(__APPLE__) -#define VK_USE_PLATFORM_METAL_EXT -#endif - -// For VK_KHR_portability_subset -#define VK_ENABLE_BETA_EXTENSIONS - -#include - -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wnullability-completeness" -#endif - -#include - -#ifdef __clang__ -#pragma clang diagnostic pop -#endif - -namespace plume { - struct VulkanCommandQueue; - struct VulkanDevice; - struct VulkanInterface; - struct VulkanPool; - struct VulkanQueue; - - struct VulkanBuffer : RenderBuffer { - VkBuffer vk = VK_NULL_HANDLE; - VulkanDevice *device = nullptr; - VulkanPool *pool = nullptr; - VmaAllocation allocation = VK_NULL_HANDLE; - VmaAllocationInfo allocationInfo = {}; - RenderBufferDesc desc; - RenderBarrierStages barrierStages = RenderBarrierStage::NONE; - - VulkanBuffer() = default; - VulkanBuffer(VulkanDevice *device, VulkanPool *pool, const RenderBufferDesc &desc); - ~VulkanBuffer() override; - void *map(uint32_t subresource, const RenderRange *readRange) override; - void unmap(uint32_t subresource, const RenderRange *writtenRange) override; - std::unique_ptr createBufferFormattedView(RenderFormat format) override; - void setName(const std::string &name) override; - uint64_t getDeviceAddress() const override; - }; - - struct VulkanBufferFormattedView : RenderBufferFormattedView { - VkBufferView vk = VK_NULL_HANDLE; - VulkanBuffer *buffer = nullptr; - - VulkanBufferFormattedView(VulkanBuffer *buffer, RenderFormat format); - ~VulkanBufferFormattedView() override; - }; - - struct VulkanTexture : RenderTexture { - VkImage vk = VK_NULL_HANDLE; - VkImageView imageView = VK_NULL_HANDLE; - VkFormat imageFormat = VK_FORMAT_UNDEFINED; - VkImageSubresourceRange imageSubresourceRange = {}; - VulkanDevice *device = nullptr; - VulkanPool *pool = nullptr; - VmaAllocation allocation = VK_NULL_HANDLE; - VmaAllocationInfo allocationInfo = {}; - RenderTextureLayout textureLayout = RenderTextureLayout::UNKNOWN; - RenderBarrierStages barrierStages = RenderBarrierStage::NONE; - bool ownership = false; - RenderTextureDesc desc; - - VulkanTexture() = default; - VulkanTexture(VulkanDevice *device, VulkanPool *pool, const RenderTextureDesc &desc); - VulkanTexture(VulkanDevice *device, VkImage image); - ~VulkanTexture() override; - void createImageView(VkFormat format); - std::unique_ptr createTextureView(const RenderTextureViewDesc &desc) override; - void setName(const std::string &name) override; - void fillSubresourceRange(); - }; - - struct VulkanTextureView : RenderTextureView { - VkImageView vk = VK_NULL_HANDLE; - VulkanTexture *texture = nullptr; - - VulkanTextureView(VulkanTexture *texture, const RenderTextureViewDesc &desc); - ~VulkanTextureView() override; - }; - - struct VulkanAccelerationStructure : RenderAccelerationStructure { - VkAccelerationStructureKHR vk = VK_NULL_HANDLE; - VulkanDevice *device = nullptr; - RenderAccelerationStructureType type = RenderAccelerationStructureType::UNKNOWN; - - VulkanAccelerationStructure(VulkanDevice *device, const RenderAccelerationStructureDesc &desc); - ~VulkanAccelerationStructure() override; - }; - - struct VulkanDescriptorSetLayout { - VkDescriptorSetLayout vk = VK_NULL_HANDLE; - std::vector setBindings; - std::vector descriptorIndexBases; - std::vector descriptorBindingIndices; - VulkanDevice *device = nullptr; - - VulkanDescriptorSetLayout(VulkanDevice *device, const RenderDescriptorSetDesc &descriptorSetDesc); - ~VulkanDescriptorSetLayout(); - }; - - struct VulkanPipelineLayout : RenderPipelineLayout { - VkPipelineLayout vk = VK_NULL_HANDLE; - std::vector pushConstantRanges; - std::vector descriptorSetLayouts; - VulkanDevice *device = nullptr; - - VulkanPipelineLayout(VulkanDevice *device, const RenderPipelineLayoutDesc &desc); - ~VulkanPipelineLayout() override; - }; - - struct VulkanShader : RenderShader { - VkShaderModule vk = VK_NULL_HANDLE; - std::string entryPointName; - VulkanDevice *device = nullptr; - RenderShaderFormat format = RenderShaderFormat::UNKNOWN; - - VulkanShader(VulkanDevice *device, const void *data, uint64_t size, const char *entryPointName, RenderShaderFormat format); - ~VulkanShader() override; - }; - - struct VulkanSampler : RenderSampler { - VkSampler vk = VK_NULL_HANDLE; - VulkanDevice *device = nullptr; - - VulkanSampler(VulkanDevice *device, const RenderSamplerDesc &desc); - ~VulkanSampler(); - }; - - struct VulkanPipeline : RenderPipeline { - enum class Type { - Unknown, - Compute, - Graphics, - Raytracing - }; - - VulkanDevice *device = nullptr; - Type type = Type::Unknown; - - VulkanPipeline(VulkanDevice *device, Type type); - virtual ~VulkanPipeline() override; - }; - - struct VulkanComputePipeline : VulkanPipeline { - VkPipeline vk = VK_NULL_HANDLE; - VkPipelineLayout pipelineLayout = VK_NULL_HANDLE; - - VulkanComputePipeline(VulkanDevice *device, const RenderComputePipelineDesc &desc); - ~VulkanComputePipeline() override; - void setName(const std::string& name) const override; - RenderPipelineProgram getProgram(const std::string &name) const override; - }; - - struct VulkanGraphicsPipeline : VulkanPipeline { - VkPipeline vk = VK_NULL_HANDLE; - VkRenderPass renderPass = VK_NULL_HANDLE; - - VulkanGraphicsPipeline(VulkanDevice *device, const RenderGraphicsPipelineDesc &desc); - ~VulkanGraphicsPipeline() override; - void setName(const std::string& name) const override; - RenderPipelineProgram getProgram(const std::string &name) const override; - static VkRenderPass createRenderPass(VulkanDevice *device, const VkFormat *renderTargetFormat, uint32_t renderTargetCount, VkFormat depthTargetFormat, VkSampleCountFlagBits sampleCount); - }; - - struct VulkanRaytracingPipeline : VulkanPipeline { - VkPipeline vk = VK_NULL_HANDLE; - std::unordered_map nameProgramMap; - uint32_t groupCount = 0; - uint32_t descriptorSetCount = 0; - - VulkanRaytracingPipeline(VulkanDevice *device, const RenderRaytracingPipelineDesc &desc, const RenderPipeline *previousPipeline); - ~VulkanRaytracingPipeline() override; - void setName(const std::string& name) const override; - RenderPipelineProgram getProgram(const std::string &name) const override; - }; - - struct VulkanDescriptorSet : RenderDescriptorSet { - VkDescriptorSet vk = VK_NULL_HANDLE; - VulkanDescriptorSetLayout *setLayout = nullptr; - VkDescriptorPool descriptorPool = VK_NULL_HANDLE; - VulkanDevice *device = nullptr; - - VulkanDescriptorSet(VulkanDevice *device, const RenderDescriptorSetDesc &desc); - ~VulkanDescriptorSet() override; - void setBuffer(uint32_t descriptorIndex, const RenderBuffer *buffer, uint64_t bufferSize, const RenderBufferStructuredView *bufferStructuredView, const RenderBufferFormattedView *bufferFormattedView) override; - void setTexture(uint32_t descriptorIndex, const RenderTexture *texture, RenderTextureLayout textureLayout, const RenderTextureView *textureView) override; - void setSampler(uint32_t descriptorIndex, const RenderSampler *sampler) override; - void setAccelerationStructure(uint32_t descriptorIndex, const RenderAccelerationStructure *accelerationStructure) override; - void setDescriptor(uint32_t descriptorIndex, const VkDescriptorBufferInfo *bufferInfo, const VkDescriptorImageInfo *imageInfo, const VkBufferView *texelBufferView, void *pNext); - static VkDescriptorPool createDescriptorPool(VulkanDevice *device, const std::unordered_map &typeCounts, bool lastRangeIsBoundless); - }; - - struct VulkanSwapChain : RenderSwapChain { - VkSwapchainKHR vk = VK_NULL_HANDLE; - VulkanCommandQueue *commandQueue = nullptr; - VkSurfaceKHR surface = VK_NULL_HANDLE; - RenderWindow renderWindow = {}; - uint32_t textureCount = 0; - uint64_t presentCount = 0; - RenderFormat format = RenderFormat::UNKNOWN; - uint32_t width = 0; - uint32_t height = 0; - VkSwapchainCreateInfoKHR createInfo = {}; - VkSurfaceFormatKHR pickedSurfaceFormat = {}; - VkPresentModeKHR createdPresentMode = VK_PRESENT_MODE_FIFO_KHR; - VkPresentModeKHR requiredPresentMode = VK_PRESENT_MODE_FIFO_KHR; - VkCompositeAlphaFlagBitsKHR pickedAlphaFlag = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; - std::vector textures; - uint64_t currentPresentId = 0; - bool immediatePresentModeSupported = false; - uint32_t maxFrameLatency = 0; - - VulkanSwapChain(VulkanCommandQueue *commandQueue, RenderWindow renderWindow, uint32_t textureCount, RenderFormat format, uint32_t maxFrameLatency); - ~VulkanSwapChain() override; - bool present(uint32_t textureIndex, RenderCommandSemaphore **waitSemaphores, uint32_t waitSemaphoreCount) override; - void wait() override; - bool resize() override; - bool needsResize() const override; - void setVsyncEnabled(bool vsyncEnabled) override; - bool isVsyncEnabled() const override; - uint32_t getWidth() const override; - uint32_t getHeight() const override; - RenderTexture *getTexture(uint32_t textureIndex) override; - uint32_t getTextureCount() const override; - bool acquireTexture(RenderCommandSemaphore *signalSemaphore, uint32_t *textureIndex) override; - RenderWindow getWindow() const override; - bool isEmpty() const override; - uint32_t getRefreshRate() const override; - void getWindowSize(uint32_t &dstWidth, uint32_t &dstHeight) const; - void releaseSwapChain(); - void releaseImageViews(); - }; - - struct VulkanFramebuffer : RenderFramebuffer { - VulkanDevice *device = nullptr; - VkFramebuffer vk = VK_NULL_HANDLE; - VkRenderPass renderPass = VK_NULL_HANDLE; - std::vector colorAttachments; - const VulkanTexture *depthAttachment = nullptr; - bool depthAttachmentReadOnly = false; - uint32_t width = 0; - uint32_t height = 0; - - VulkanFramebuffer(VulkanDevice *device, const RenderFramebufferDesc &desc); - ~VulkanFramebuffer() override; - uint32_t getWidth() const override; - uint32_t getHeight() const override; - bool contains(const VulkanTexture *attachment) const; - }; - - struct VulkanQueryPool : RenderQueryPool { - VulkanDevice *device = nullptr; - std::vector results; - VkQueryPool vk = VK_NULL_HANDLE; - - VulkanQueryPool(VulkanDevice *device, uint32_t queryCount); - virtual ~VulkanQueryPool() override; - virtual void queryResults() override; - virtual const uint64_t *getResults() const override; - virtual uint32_t getCount() const override; - }; - - struct VulkanCommandList : RenderCommandList { - VkCommandBuffer vk = VK_NULL_HANDLE; - VkCommandPool commandPool = VK_NULL_HANDLE; - VulkanDevice *device = nullptr; - RenderCommandListType type = RenderCommandListType::UNKNOWN; - const VulkanFramebuffer *targetFramebuffer = nullptr; - const VulkanPipelineLayout *activeComputePipelineLayout = nullptr; - const VulkanPipelineLayout *activeGraphicsPipelineLayout = nullptr; - const VulkanPipelineLayout *activeRaytracingPipelineLayout = nullptr; - VkRenderPass activeRenderPass = VK_NULL_HANDLE; - - VulkanCommandList(VulkanDevice *device, RenderCommandListType type); - ~VulkanCommandList() override; - void begin() override; - void end() override; - void barriers(RenderBarrierStages stages, const RenderBufferBarrier *bufferBarriers, uint32_t bufferBarriersCount, const RenderTextureBarrier *textureBarriers, uint32_t textureBarriersCount) override; - void dispatch(uint32_t threadGroupCountX, uint32_t threadGroupCountY, uint32_t threadGroupCountZ) override; - void traceRays(uint32_t width, uint32_t height, uint32_t depth, RenderBufferReference shaderBindingTable, const RenderShaderBindingGroupsInfo &shaderBindingGroupsInfo) override; - void drawInstanced(uint32_t vertexCountPerInstance, uint32_t instanceCount, uint32_t startVertexLocation, uint32_t startInstanceLocation) override; - void drawIndexedInstanced(uint32_t indexCountPerInstance, uint32_t instanceCount, uint32_t startIndexLocation, int32_t baseVertexLocation, uint32_t startInstanceLocation) override; - void setPipeline(const RenderPipeline *pipeline) override; - void setComputePipelineLayout(const RenderPipelineLayout *pipelineLayout) override; - void setComputePushConstants(uint32_t rangeIndex, const void *data, uint32_t offset = 0, uint32_t size = 0) override; - void setComputeDescriptorSet(RenderDescriptorSet *descriptorSet, uint32_t setIndex) override; - void setGraphicsPipelineLayout(const RenderPipelineLayout *pipelineLayout) override; - void setGraphicsPushConstants(uint32_t rangeIndex, const void *data, uint32_t offset = 0, uint32_t size = 0) override; - void setGraphicsDescriptorSet(RenderDescriptorSet *descriptorSet, uint32_t setIndex) override; - void setGraphicsRootDescriptor(RenderBufferReference bufferReference, uint32_t rootDescriptorIndex) override; - void setRaytracingPipelineLayout(const RenderPipelineLayout *pipelineLayout) override; - void setRaytracingPushConstants(uint32_t rangeIndex, const void *data, uint32_t offset = 0, uint32_t size = 0) override; - void setRaytracingDescriptorSet(RenderDescriptorSet *descriptorSet, uint32_t setIndex) override; - void setIndexBuffer(const RenderIndexBufferView *view) override; - void setVertexBuffers(uint32_t startSlot, const RenderVertexBufferView *views, uint32_t viewCount, const RenderInputSlot *inputSlots) override; - void setViewports(const RenderViewport *viewports, uint32_t count) override; - void setScissors(const RenderRect *scissorRects, uint32_t count) override; - void setFramebuffer(const RenderFramebuffer *framebuffer) override; - void setDepthBias(float depthBias, float depthBiasClamp, float slopeScaledDepthBias) override; - void clearColor(uint32_t attachmentIndex, RenderColor colorValue, const RenderRect *clearRects, uint32_t clearRectsCount) override; - void clearDepth(bool clearDepth, float depthValue, const RenderRect *clearRects, uint32_t clearRectsCount) override; - void copyBufferRegion(RenderBufferReference dstBuffer, RenderBufferReference srcBuffer, uint64_t size) override; - void copyTextureRegion(const RenderTextureCopyLocation &dstLocation, const RenderTextureCopyLocation &srcLocation, uint32_t dstX, uint32_t dstY, uint32_t dstZ, const RenderBox *srcBox) override; - void copyBuffer(const RenderBuffer *dstBuffer, const RenderBuffer *srcBuffer) override; - void copyTexture(const RenderTexture *dstTexture, const RenderTexture *srcTexture) override; - void resolveTexture(const RenderTexture *dstTexture, const RenderTexture *srcTexture) override; - void resolveTextureRegion(const RenderTexture *dstTexture, uint32_t dstX, uint32_t dstY, const RenderTexture *srcTexture, const RenderRect *srcRect, RenderResolveMode resolveMode) override; - void buildBottomLevelAS(const RenderAccelerationStructure *dstAccelerationStructure, RenderBufferReference scratchBuffer, const RenderBottomLevelASBuildInfo &buildInfo) override; - void buildTopLevelAS(const RenderAccelerationStructure *dstAccelerationStructure, RenderBufferReference scratchBuffer, RenderBufferReference instancesBuffer, const RenderTopLevelASBuildInfo &buildInfo) override; - void discardTexture(const RenderTexture* texture) override; - void resetQueryPool(const RenderQueryPool *queryPool, uint32_t queryFirstIndex, uint32_t queryCount) override; - void writeTimestamp(const RenderQueryPool *queryPool, uint32_t queryIndex) override; - void checkActiveRenderPass(); - void endActiveRenderPass(); - void setDescriptorSet(VkPipelineBindPoint bindPoint, const VulkanPipelineLayout *pipelineLayout, const RenderDescriptorSet *descriptorSet, uint32_t setIndex); - }; - - struct VulkanCommandFence : RenderCommandFence { - VkFence vk = VK_NULL_HANDLE; - VulkanDevice *device = nullptr; - - VulkanCommandFence(VulkanDevice *device); - ~VulkanCommandFence() override; - }; - - struct VulkanCommandSemaphore : RenderCommandSemaphore { - VkSemaphore vk = VK_NULL_HANDLE; - VulkanDevice *device = nullptr; - - VulkanCommandSemaphore(VulkanDevice *device); - ~VulkanCommandSemaphore() override; - }; - - struct VulkanCommandQueue : RenderCommandQueue { - VulkanQueue *queue = nullptr; - VulkanDevice *device = nullptr; - uint32_t familyIndex = 0; - uint32_t queueIndex = 0; - std::unordered_set swapChains; - - VulkanCommandQueue(VulkanDevice *device, RenderCommandListType commandListType); - ~VulkanCommandQueue() override; - std::unique_ptr createSwapChain(RenderWindow renderWindow, uint32_t bufferCount, RenderFormat format, uint32_t maxFrameLatency) override; - void executeCommandLists(const RenderCommandList **commandLists, uint32_t commandListCount, RenderCommandSemaphore **waitSemaphores, uint32_t waitSemaphoreCount, RenderCommandSemaphore **signalSemaphores, uint32_t signalSemaphoreCount, RenderCommandFence *signalFence) override; - void waitForCommandFence(RenderCommandFence *fence) override; - }; - - struct VulkanPool : RenderPool { - VmaPool vk = VK_NULL_HANDLE; - VulkanDevice *device = nullptr; - - VulkanPool(VulkanDevice *device, const RenderPoolDesc &desc); - ~VulkanPool() override; - std::unique_ptr createBuffer(const RenderBufferDesc &desc) override; - std::unique_ptr createTexture(const RenderTextureDesc &desc) override; - }; - - struct VulkanQueue { - VkQueue vk; - std::unique_ptr mutex; - std::unordered_set virtualQueues; - }; - - struct VulkanQueueFamily { - std::vector queues; - - void add(VulkanCommandQueue *virtualQueue); - void remove(VulkanCommandQueue *virtualQueue); - }; - - struct VulkanDevice : RenderDevice { - VkDevice vk = VK_NULL_HANDLE; - VulkanInterface *renderInterface = nullptr; - VkPhysicalDevice physicalDevice = VK_NULL_HANDLE; - VkPhysicalDeviceProperties physicalDeviceProperties = {}; - VmaAllocator allocator = VK_NULL_HANDLE; - uint32_t queueFamilyIndices[3] = {}; - std::vector queueFamilies; - RenderDeviceCapabilities capabilities; - RenderDeviceDescription description; - VkPhysicalDeviceRayTracingPipelinePropertiesKHR rtPipelineProperties = {}; - VkPhysicalDeviceSampleLocationsPropertiesEXT sampleLocationProperties = {}; - std::unique_ptr nullBuffer = nullptr; - bool loadStoreOpNoneSupported = false; - bool nullDescriptorSupported = false; - - VulkanDevice(VulkanInterface *renderInterface, const std::string &preferredDeviceName); - ~VulkanDevice() override; - std::unique_ptr createCommandList(RenderCommandListType type) override; - std::unique_ptr createDescriptorSet(const RenderDescriptorSetDesc &desc) override; - std::unique_ptr createShader(const void *data, uint64_t size, const char *entryPointName, RenderShaderFormat format) override; - std::unique_ptr createSampler(const RenderSamplerDesc &desc) override; - std::unique_ptr createComputePipeline(const RenderComputePipelineDesc &desc) override; - std::unique_ptr createGraphicsPipeline(const RenderGraphicsPipelineDesc &desc) override; - std::unique_ptr createRaytracingPipeline(const RenderRaytracingPipelineDesc &desc, const RenderPipeline *previousPipeline) override; - std::unique_ptr createCommandQueue(RenderCommandListType type) override; - std::unique_ptr createBuffer(const RenderBufferDesc &desc) override; - std::unique_ptr createTexture(const RenderTextureDesc &desc) override; - std::unique_ptr createAccelerationStructure(const RenderAccelerationStructureDesc &desc) override; - std::unique_ptr createPool(const RenderPoolDesc &desc) override; - std::unique_ptr createPipelineLayout(const RenderPipelineLayoutDesc &desc) override; - std::unique_ptr createCommandFence() override; - std::unique_ptr createCommandSemaphore() override; - std::unique_ptr createFramebuffer(const RenderFramebufferDesc &desc) override; - std::unique_ptr createQueryPool(uint32_t queryCount) override; - void setBottomLevelASBuildInfo(RenderBottomLevelASBuildInfo &buildInfo, const RenderBottomLevelASMesh *meshes, uint32_t meshCount, bool preferFastBuild, bool preferFastTrace) override; - void setTopLevelASBuildInfo(RenderTopLevelASBuildInfo &buildInfo, const RenderTopLevelASInstance *instances, uint32_t instanceCount, bool preferFastBuild, bool preferFastTrace) override; - void setShaderBindingTableInfo(RenderShaderBindingTableInfo &tableInfo, const RenderShaderBindingGroups &groups, const RenderPipeline *pipeline, RenderDescriptorSet **descriptorSets, uint32_t descriptorSetCount) override; - const RenderDeviceCapabilities &getCapabilities() const override; - const RenderDeviceDescription &getDescription() const override; - RenderSampleCounts getSampleCountsSupported(RenderFormat format) const override; - void waitIdle() const override; - void release(); - bool isValid() const; - }; - - struct VulkanInterface : RenderInterface { - VkInstance instance = VK_NULL_HANDLE; - VkApplicationInfo appInfo = {}; - RenderInterfaceCapabilities capabilities; - std::vector deviceNames; - -# if SDL_VULKAN_ENABLED - VulkanInterface(RenderWindow sdlWindow); -# else - VulkanInterface(); -# endif - - ~VulkanInterface() override; - std::unique_ptr createDevice(const std::string &preferredDeviceName) override; - const RenderInterfaceCapabilities &getCapabilities() const override; - const std::vector &getDeviceNames() const override; - bool isValid() const; - }; -}; diff --git a/UnleashedRecomp/gpu/video.cpp b/UnleashedRecomp/gpu/video.cpp index 64f6513..a9edd0b 100644 --- a/UnleashedRecomp/gpu/video.cpp +++ b/UnleashedRecomp/gpu/video.cpp @@ -1838,7 +1838,7 @@ bool Video::CreateHostDevice(const char *sdlVideoDriver, bool graphicsApiRetry) g_queue = g_device->createCommandQueue(RenderCommandListType::DIRECT); for (auto& commandList : g_commandLists) - commandList = g_device->createCommandList(RenderCommandListType::DIRECT); + commandList = g_queue->createCommandList(); for (auto& commandFence : g_commandFences) commandFence = g_device->createCommandFence(); @@ -1847,7 +1847,7 @@ bool Video::CreateHostDevice(const char *sdlVideoDriver, bool graphicsApiRetry) queryPool = g_device->createQueryPool(NUM_QUERIES); g_copyQueue = g_device->createCommandQueue(RenderCommandListType::COPY); - g_copyCommandList = g_device->createCommandList(RenderCommandListType::COPY); + g_copyCommandList = g_copyQueue->createCommandList(); g_copyCommandFence = g_device->createCommandFence(); uint32_t bufferCount = 2; @@ -2075,23 +2075,21 @@ void Video::WaitForGPU() { g_waitForGPUCount++; - if (g_vulkan) + // Wait for all queued frames to finish. + for (size_t i = 0; i < NUM_FRAMES; i++) { - g_device->waitIdle(); - } - else - { - for (size_t i = 0; i < NUM_FRAMES; i++) + if (g_commandListStates[i]) { - if (g_commandListStates[i]) - { - g_queue->waitForCommandFence(g_commandFences[i].get()); - g_commandListStates[i] = false; - } + g_queue->waitForCommandFence(g_commandFences[i].get()); + g_commandListStates[i] = false; } - g_queue->executeCommandLists(nullptr, g_commandFences[0].get()); - g_queue->waitForCommandFence(g_commandFences[0].get()); } + + // Execute an empty command list and wait for it to end to guarantee that any remaining presentation has finished. + g_commandLists[0]->begin(); + g_commandLists[0]->end(); + g_queue->executeCommandLists(g_commandLists[0].get(), g_commandFences[0].get()); + g_queue->waitForCommandFence(g_commandFences[0].get()); } static uint32_t CreateDevice(uint32_t a1, uint32_t a2, uint32_t a3, uint32_t a4, uint32_t a5, be* a6) @@ -5737,7 +5735,7 @@ static bool LoadTexture(GuestTexture& texture, const uint8_t* data, size_t dataS auto copyTextureRegion = [&](Slice& slice, uint32_t subresourceIndex) { g_copyCommandList->copyTextureRegion( - RenderTextureCopyLocation::Subresource(texture.texture, subresourceIndex), + RenderTextureCopyLocation::Subresource(texture.texture, subresourceIndex % ddsDesc.numMips, subresourceIndex / ddsDesc.numMips), RenderTextureCopyLocation::PlacedFootprint(uploadBuffer.get(), desc.format, slice.width, slice.height, slice.depth, (slice.dstRowPitch * 8) / ddsDesc.bitsPerPixelOrBlock * ddsDesc.blockWidth, slice.dstOffset)); }; diff --git a/UnleashedRecomp/gpu/video.h b/UnleashedRecomp/gpu/video.h index b07169b..6c24d30 100644 --- a/UnleashedRecomp/gpu/video.h +++ b/UnleashedRecomp/gpu/video.h @@ -4,7 +4,7 @@ /////////////////////////////////////////////////////////////////////#define PSO_CACHING //#define PSO_CACHING_CLEANUP -#include "rhi/plume_render_interface.h" +#include #define D3DCLEAR_TARGET 0x1 #define D3DCLEAR_ZBUFFER 0x10 diff --git a/UnleashedRecomp/ui/game_window.cpp b/UnleashedRecomp/ui/game_window.cpp index 6ae7081..d15aac6 100644 --- a/UnleashedRecomp/ui/game_window.cpp +++ b/UnleashedRecomp/ui/game_window.cpp @@ -218,7 +218,7 @@ void GameWindow::Init(const char* sdlVideoDriver) #elif defined(__linux__) s_renderWindow = { info.info.x11.display, info.info.x11.window }; #elif defined(__APPLE__) - s_renderWindow.window = s_pWindow; + s_renderWindow.window = info.info.cocoa.window; s_renderWindow.view = SDL_Metal_GetLayer(SDL_Metal_CreateView(s_pWindow)); #else static_assert(false, "Unknown platform."); diff --git a/UnleashedRecomp/ui/game_window.h b/UnleashedRecomp/ui/game_window.h index bd0cb9a..b666f4b 100644 --- a/UnleashedRecomp/ui/game_window.h +++ b/UnleashedRecomp/ui/game_window.h @@ -1,6 +1,6 @@ #pragma once -#include +#include #include #include diff --git a/thirdparty/CMakeLists.txt b/thirdparty/CMakeLists.txt index 94f009b..5faee46 100644 --- a/thirdparty/CMakeLists.txt +++ b/thirdparty/CMakeLists.txt @@ -20,6 +20,7 @@ add_subdirectory("${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/nativefiledialog-extended" add_subdirectory("${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/o1heap") add_subdirectory("${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/SDL") add_subdirectory("${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/SDL_mixer") +add_subdirectory("${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/plume") if (APPLE) add_subdirectory("${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/MoltenVK") diff --git a/thirdparty/D3D12MemoryAllocator b/thirdparty/D3D12MemoryAllocator deleted file mode 160000 index e00c4a7..0000000 --- a/thirdparty/D3D12MemoryAllocator +++ /dev/null @@ -1 +0,0 @@ -Subproject commit e00c4a7c85cf9c28c6f4a6cc75032736f416410f diff --git a/thirdparty/MoltenVK/CMakeLists.txt b/thirdparty/MoltenVK/CMakeLists.txt index 7c28217..c7ef4f9 100644 --- a/thirdparty/MoltenVK/CMakeLists.txt +++ b/thirdparty/MoltenVK/CMakeLists.txt @@ -75,7 +75,7 @@ file(GLOB_RECURSE MVK_SOURCES CONFIGURE_DEPENDS file(GLOB MVK_SRC_INCLUDES LIST_DIRECTORIES ON ${MVK_DIR}/MoltenVK/*) set(MVK_INCLUDES ${MVK_SRC_INCLUDES} ${MVK_GENERATED_INCLUDES} ${MVK_DIR}/include - ${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/Vulkan-Headers/include) + ${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/plume/contrib/Vulkan-Headers/include) add_library(MoltenVK SHARED ${MVK_SOURCES}) target_include_directories(MoltenVK PRIVATE ${MVK_INCLUDES}) diff --git a/thirdparty/Vulkan-Headers b/thirdparty/Vulkan-Headers deleted file mode 160000 index 75ad707..0000000 --- a/thirdparty/Vulkan-Headers +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 75ad707a587e1469fb53a901b9b68fe9f6fbc11f diff --git a/thirdparty/VulkanMemoryAllocator b/thirdparty/VulkanMemoryAllocator deleted file mode 160000 index 1c35ba9..0000000 --- a/thirdparty/VulkanMemoryAllocator +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 1c35ba99ce775f8342d87a83a3f0f696f99c2a39 diff --git a/thirdparty/plume b/thirdparty/plume new file mode 160000 index 0000000..fffeb35 --- /dev/null +++ b/thirdparty/plume @@ -0,0 +1 @@ +Subproject commit fffeb35f836d8c945697ec82b735e77db401e2de diff --git a/thirdparty/volk b/thirdparty/volk deleted file mode 160000 index 447e21b..0000000 --- a/thirdparty/volk +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 447e21b5d92ed8d5271b0d39b071f938fcfa875f