diff --git a/.gitmodules b/.gitmodules index 783bccb..40a432e 100644 --- a/.gitmodules +++ b/.gitmodules @@ -13,9 +13,12 @@ [submodule "thirdparty/gli"] path = thirdparty/gli url = https://github.com/g-truc/gli.git -[submodule "thirdparty/tinygltf"] - path = thirdparty/tinygltf - url = https://github.com/syoyo/tinygltf.git [submodule "thirdparty/stb"] path = thirdparty/stb url = https://github.com/nothings/stb.git +[submodule "thirdparty/Vulkan-Headers"] + path = thirdparty/Vulkan-Headers + url = https://github.com/KhronosGroup/Vulkan-Headers.git +[submodule "thirdparty/glslang"] + path = thirdparty/glslang + url = https://github.com/KhronosGroup/glslang.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 2b6bf7c..a120fe6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.26.4) +cmake_minimum_required(VERSION 3.12) project(FoxFury CXX) set(CMAKE_CXX_STANDARD 20) @@ -20,16 +20,48 @@ add_library(${PROJECT_NAME} STATIC "include/main.cpp" ) +option(BUILD_TESTS "Build tests" OFF) +option(BUILD_EXAMPLES "Build examples" OFF) + + +## Vulkan headers +add_subdirectory("thirdparty/Vulkan-Headers") +## Volk +include_directories("thirdparty/Vulkan-Headers/include") add_subdirectory("thirdparty/volk") +## VMA add_subdirectory("thirdparty/VulkanMemoryAllocator") +## Glsl lang +set(ENABLE_OPT 0)#disable optimizations for HLSL +set(BUILD_SHARED_LIBS 0) +add_subdirectory("thirdparty/glslang") + +if(BUILD_EXAMPLES) +## GLFW +set(GLFW_BUILD_EXAMPLES OFF CACHE BOOL "GLFW_BUILD_EXAMPLES" FORCE) +set(GLFW_BUILD_TESTS OFF CACHE BOOL "GLFW_BUILD_TESTS" FORCE) add_subdirectory("thirdparty/glfw") +# GLM add_subdirectory("thirdparty/glm") +# GLI +set(GLI_TEST_ENABLED OFF CACHE BOOL "" FORCE) add_subdirectory("thirdparty/gli") -set(TINYGLTF_HEADER_ONLY ON CACHE INTERNAL "" FORCE) -set(TINYGLTF_INSTALL OFF CACHE INTERNAL "" FORCE) -add_subdirectory("thirdparty/tinygltf") +# TINYGLTF +set(TINYGLTF_HEADER_ONLY ON CACHE BOOL "" FORCE) +set(TINYGLTF_INSTALL OFF CACHE BOOL "" FORCE) +# Fetch tinygltf from GitHub +include(FetchContent) # once in the project to include the module +FetchContent_Declare( +tinygltf +GIT_REPOSITORY https://github.com/syoyo/tinygltf.git +GIT_TAG v2.8.19 +) -target_link_libraries(${PROJECT_NAME} PRIVATE volk VulkanMemoryAllocator) + # Fetch the content and add it to your CMake project + FetchContent_MakeAvailable(tinygltf) +endif() + +target_link_libraries(${PROJECT_NAME} Vulkan-Headers volk VulkanMemoryAllocator GenericCodeGen OSDependent MachineIndependent glslang glslang-default-resource-limits) # Set custom output directories - to have same behaviour accross different compilers # On linux with make it doesn't work, no debug or release folders @@ -98,11 +130,6 @@ target_sources(${PROJECT_NAME} PRIVATE "${SRC_DIR}/backend/vulkan/VulkanDevice13.cpp" ) - - -option(BUILD_TESTS "Build tests" ON) -option(BUILD_EXAMPLES "Build examples" ON) - if(BUILD_EXAMPLES) set(LIB_INCLUDE_DIR "${CMAKE_SOURCE_DIR}/include") FILE(REAL_PATH "thirdparty/stb" STB_INCLUDE_DIR) @@ -115,4 +142,4 @@ endif() if(BUILD_TESTS) add_subdirectory("tests") -endif() \ No newline at end of file +endif() diff --git a/examples/App.cpp b/examples/App.cpp index 1bd56d6..30e7b7b 100644 --- a/examples/App.cpp +++ b/examples/App.cpp @@ -49,11 +49,17 @@ App::App() throw std::runtime_error("Failed to CreateSwapchain"); } } + + // Create graphics queue + { + _graphicsQueue = _ctx->FindQueue(Fox::EQueueType::QUEUE_GRAPHICS); + } + // Create per frame data for (uint32_t i = 0; i < MAX_FRAMES; i++) { _frameData[i].Fence = _ctx->CreateFence(true); // already signaled - _frameData[i].CmdPool = _ctx->CreateCommandPool(); + _frameData[i].CmdPool = _ctx->CreateCommandPool(_graphicsQueue); _frameData[i].Cmd = _ctx->CreateCommandBuffer(_frameData[i].CmdPool); _frameData[i].ImageAvailableSemaphore = _ctx->CreateGpuSemaphore(); _frameData[i].WorkFinishedSemaphore = _ctx->CreateGpuSemaphore(); @@ -124,8 +130,8 @@ App::Run() Draw(data.Cmd, w, h); _ctx->ResetFence(data.Fence); - _ctx->QueueSubmit({ data.ImageAvailableSemaphore }, { data.WorkFinishedSemaphore }, { data.Cmd }, data.Fence); + _ctx->QueueSubmit(_graphicsQueue, { data.ImageAvailableSemaphore }, { data.WorkFinishedSemaphore }, { data.Cmd }, data.Fence); - _ctx->QueuePresent(_swapchain, _swapchainImageIndex, { data.WorkFinishedSemaphore }); + _ctx->QueuePresent(_graphicsQueue, _swapchain, _swapchainImageIndex, { data.WorkFinishedSemaphore }); } } \ No newline at end of file diff --git a/examples/App.h b/examples/App.h index 5398ab4..e106323 100644 --- a/examples/App.h +++ b/examples/App.h @@ -34,7 +34,7 @@ class App Fox::EFormat format = Fox::EFormat::B8G8R8A8_UNORM; uint32_t _swapchain{}; uint32_t _swapchainImageIndex{}; - + uint32_t _graphicsQueue{}; struct PerFrameData { uint32_t Fence{}; diff --git a/examples/DepthBuffer/CMakeLists.txt b/examples/DepthBuffer/CMakeLists.txt deleted file mode 100644 index 1b8c49b..0000000 --- a/examples/DepthBuffer/CMakeLists.txt +++ /dev/null @@ -1,18 +0,0 @@ -cmake_minimum_required(VERSION 3.26.4) -project(DepthBuffer CXX) - -add_executable(${PROJECT_NAME} -"DepthBuffer.cpp" -) - - -target_link_libraries(${PROJECT_NAME} PRIVATE FoxFury glfw glm) - -set_target_properties(${PROJECT_NAME} PROPERTIES - RUNTIME_OUTPUT_DIRECTORY "bin" -) - -#Set the debug working directory -set_target_properties(${PROJECT_NAME} PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}") - -include_directories(${LIB_INCLUDE_DIR}) \ No newline at end of file diff --git a/examples/DepthBuffer/DepthBuffer.cpp b/examples/DepthBuffer/DepthBuffer.cpp deleted file mode 100644 index 1c16333..0000000 --- a/examples/DepthBuffer/DepthBuffer.cpp +++ /dev/null @@ -1,381 +0,0 @@ -// Copyright RedFox Studio 2022 - -#include - -#include "IContext.h" -#include "backend/vulkan/VulkanContextFactory.h" - -#include - -#define GLFW_INCLUDE_NONE // makes the GLFW header not include any OpenGL or -// OpenGL ES API header.This is useful in combination with an extension loading library. -#include - -#define GLFW_EXPOSE_NATIVE_WIN32 -#include - -#define GLM_DEPTH_ZERO_TO_ONE -#include -#include - -#include -#include -#include - -void -Log(const char* msg) -{ - std::cout << msg << std::endl; -}; - -constexpr uint32_t imageWidth = 32; -constexpr uint32_t imageHeight = 32; -// converter https://notisrac.github.io/FileToCArray/ -// clang-format off -constexpr uint8_t image[] = {0x41, 0x3c, 0x38, 0xff, 0x3a, 0x48, 0x48, 0xff, 0x3a, 0x3f, 0x45, 0xff, 0x40, 0x41, 0x39, 0xff, 0x42, 0x42, 0x44, 0xff, 0x3f, 0x3d, 0x40, 0xff, 0x3c, 0x41, 0x44, 0xff, 0x42, 0x41, 0x3f, 0xff, - 0x3b, 0x43, 0x46, 0xff, 0x47, 0x3e, 0x3f, 0xff, 0x45, 0x3c, 0x35, 0xff, 0x3b, 0x41, 0x3d, 0xff, 0x3c, 0x3f, 0x48, 0xff, 0x3b, 0x40, 0x43, 0xff, 0x44, 0x45, 0x3f, 0xff, 0x43, 0x3b, 0x38, 0xff, - 0x3d, 0x3f, 0x3e, 0xff, 0x43, 0x42, 0x3d, 0xff, 0x44, 0x3f, 0x43, 0xff, 0x3d, 0x43, 0x41, 0xff, 0x40, 0x3d, 0x44, 0xff, 0x40, 0x40, 0x36, 0xff, 0x44, 0x40, 0x3f, 0xff, 0x3c, 0x42, 0x42, 0xff, - 0x3d, 0x42, 0x3e, 0xff, 0x38, 0x42, 0x44, 0xff, 0x3f, 0x3e, 0x3c, 0xff, 0x3f, 0x40, 0x42, 0xff, 0x3d, 0x3e, 0x40, 0xff, 0x3e, 0x43, 0x46, 0xff, 0x3f, 0x3e, 0x3a, 0xff, 0x43, 0x40, 0x3b, 0xff, - 0x48, 0x43, 0x3f, 0xff, 0x32, 0x3e, 0x3e, 0xff, 0x60, 0x3c, 0x26, 0xff, 0x5a, 0x36, 0x14, 0xff, 0x5a, 0x36, 0x1e, 0xff, 0x5e, 0x36, 0x1d, 0xff, 0x5d, 0x3b, 0x20, 0xff, 0x5f, 0x37, 0x1d, 0xff, - 0x5c, 0x3a, 0x21, 0xff, 0x5e, 0x34, 0x1c, 0xff, 0x62, 0x37, 0x17, 0xff, 0x60, 0x3d, 0x1f, 0xff, 0x5d, 0x38, 0x25, 0xff, 0x5b, 0x38, 0x22, 0xff, 0x59, 0x35, 0x15, 0xff, 0x67, 0x3b, 0x20, 0xff, - 0x62, 0x3d, 0x22, 0xff, 0x5a, 0x35, 0x18, 0xff, 0x5c, 0x33, 0x1d, 0xff, 0x5c, 0x3a, 0x1f, 0xff, 0x5e, 0x35, 0x21, 0xff, 0x61, 0x3a, 0x19, 0xff, 0x59, 0x34, 0x1a, 0xff, 0x5e, 0x3c, 0x21, 0xff, - 0x5a, 0x35, 0x18, 0xff, 0x58, 0x3c, 0x26, 0xff, 0x61, 0x3a, 0x1d, 0xff, 0x5c, 0x38, 0x20, 0xff, 0x5f, 0x37, 0x1e, 0xff, 0x5c, 0x39, 0x23, 0xff, 0x40, 0x3e, 0x3f, 0xff, 0x43, 0x42, 0x3e, 0xff, - 0x45, 0x3d, 0x3a, 0xff, 0x3c, 0x46, 0x48, 0xff, 0xe3, 0x6e, 0x21, 0xff, 0xe4, 0x76, 0x1f, 0xff, 0xe2, 0x74, 0x27, 0xff, 0xe0, 0x71, 0x20, 0xff, 0xe1, 0x73, 0x1e, 0xff, 0xde, 0x6f, 0x20, 0xff, - 0xe4, 0x6f, 0x1f, 0xff, 0xe2, 0x72, 0x2a, 0xff, 0xe1, 0x71, 0x1f, 0xff, 0xe4, 0x6f, 0x1f, 0xff, 0xe2, 0x73, 0x21, 0xff, 0xe0, 0x70, 0x24, 0xff, 0xe0, 0x71, 0x1f, 0xff, 0xe0, 0x70, 0x24, 0xff, - 0xe3, 0x6f, 0x1c, 0xff, 0xe3, 0x74, 0x25, 0xff, 0xe2, 0x72, 0x28, 0xff, 0xe4, 0x73, 0x23, 0xff, 0xe2, 0x72, 0x28, 0xff, 0xdf, 0x6f, 0x1d, 0xff, 0xde, 0x72, 0x29, 0xff, 0xde, 0x70, 0x21, 0xff, - 0xe6, 0x72, 0x1f, 0xff, 0xde, 0x74, 0x28, 0xff, 0xe1, 0x6d, 0x18, 0xff, 0xe2, 0x74, 0x27, 0xff, 0xe7, 0x6e, 0x1f, 0xff, 0xdd, 0x6e, 0x26, 0xff, 0x40, 0x3e, 0x43, 0xff, 0x3d, 0x41, 0x42, 0xff, - 0x45, 0x3d, 0x3a, 0xff, 0x37, 0x3e, 0x44, 0xff, 0xff, 0x67, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xfb, 0x68, 0x01, 0xff, 0xfd, 0x69, 0x00, 0xff, 0xff, 0x6b, 0x00, 0xff, 0xff, 0x6a, 0x04, 0xff, - 0xff, 0x6a, 0x00, 0xff, 0xf9, 0x67, 0x04, 0xff, 0xff, 0x6d, 0x05, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfc, 0x68, 0x00, 0xff, 0xff, 0x6a, 0x04, 0xff, 0xfc, 0x68, 0x00, 0xff, 0xfe, 0x69, 0x03, 0xff, - 0xff, 0x69, 0x00, 0xff, 0xfe, 0x69, 0x02, 0xff, 0xfa, 0x68, 0x03, 0xff, 0xff, 0x67, 0x00, 0xff, 0xff, 0x6a, 0x03, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfe, 0x6c, 0x07, 0xff, 0xff, 0x6c, 0x02, 0xff, - 0xff, 0x64, 0x00, 0xff, 0xff, 0x6e, 0x09, 0xff, 0xff, 0x6a, 0x00, 0xff, 0xfd, 0x68, 0x01, 0xff, 0xff, 0x67, 0x00, 0xff, 0xff, 0x6a, 0x06, 0xff, 0x43, 0x40, 0x49, 0xff, 0x3c, 0x40, 0x43, 0xff, - 0x46, 0x41, 0x3b, 0xff, 0x3a, 0x43, 0x4a, 0xff, 0xff, 0x65, 0x00, 0xff, 0xfc, 0x69, 0x01, 0xff, 0xfd, 0x6a, 0x02, 0xff, 0xff, 0x6b, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfb, 0x67, 0x03, 0xff, - 0xfb, 0x66, 0x00, 0xff, 0xfd, 0x6b, 0x06, 0xff, 0xfa, 0x65, 0x00, 0xff, 0xff, 0x6b, 0x00, 0xff, 0xfd, 0x69, 0x05, 0xff, 0xfe, 0x6c, 0x05, 0xff, 0xff, 0x6c, 0x03, 0xff, 0xff, 0x69, 0x00, 0xff, - 0xff, 0x68, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfd, 0x6f, 0x0b, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xfb, 0x68, 0x00, 0xff, 0xfe, 0x6c, 0x00, 0xff, 0xfb, 0x67, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, - 0xff, 0x6a, 0x04, 0xff, 0xf9, 0x64, 0x00, 0xff, 0xff, 0x6d, 0x08, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfc, 0x68, 0x00, 0xff, 0xff, 0x6c, 0x00, 0xff, 0x3e, 0x3d, 0x42, 0xff, 0x40, 0x3e, 0x3f, 0xff, - 0x3d, 0x3c, 0x38, 0xff, 0x3f, 0x44, 0x4a, 0xff, 0xff, 0x67, 0x02, 0xff, 0xff, 0x6a, 0x03, 0xff, 0xff, 0x69, 0x01, 0xff, 0xfd, 0x6a, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xff, 0x6c, 0x08, 0xff, - 0xfc, 0x6a, 0x03, 0xff, 0xff, 0x6a, 0x01, 0xff, 0xf0, 0x6e, 0x18, 0xff, 0xf2, 0x73, 0x16, 0xff, 0xec, 0x6a, 0x16, 0xff, 0xfb, 0x6a, 0x01, 0xff, 0xf0, 0x6b, 0x0e, 0xff, 0xf3, 0x6d, 0x0e, 0xff, - 0xfd, 0x6a, 0x03, 0xff, 0xff, 0x67, 0x00, 0xff, 0xfd, 0x6b, 0x04, 0xff, 0xf0, 0x6e, 0x0e, 0xff, 0xff, 0x6b, 0x01, 0xff, 0xf0, 0x71, 0x14, 0xff, 0xff, 0x68, 0x00, 0xff, 0xf2, 0x6f, 0x14, 0xff, - 0xee, 0x6b, 0x11, 0xff, 0xe2, 0x70, 0x27, 0xff, 0xfa, 0x68, 0x03, 0xff, 0xff, 0x6b, 0x00, 0xff, 0xfe, 0x6b, 0x01, 0xff, 0xfb, 0x67, 0x00, 0xff, 0x41, 0x42, 0x46, 0xff, 0x45, 0x41, 0x40, 0xff, - 0x39, 0x42, 0x3f, 0xff, 0x44, 0x40, 0x3f, 0xff, 0xfa, 0x67, 0x00, 0xff, 0xfe, 0x65, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfc, 0x6c, 0x00, 0xff, 0xfc, 0x69, 0x01, 0xff, 0xfb, 0x6a, 0x01, 0xff, - 0xf8, 0x6b, 0x01, 0xff, 0xff, 0x66, 0x00, 0xff, 0x86, 0x31, 0x00, 0xff, 0x7e, 0x2b, 0x00, 0xff, 0x8a, 0x2c, 0x00, 0xff, 0xff, 0x6c, 0x02, 0xff, 0x8b, 0x2b, 0x00, 0xff, 0x8b, 0x2f, 0x00, 0xff, - 0xf7, 0x6b, 0x0a, 0xff, 0xff, 0x69, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0x8c, 0x30, 0x00, 0xff, 0xf9, 0x65, 0x00, 0xff, 0x86, 0x2f, 0x00, 0xff, 0xff, 0x65, 0x00, 0xff, 0x86, 0x29, 0x00, 0xff, - 0x86, 0x2d, 0x00, 0xff, 0x61, 0x3b, 0x26, 0xff, 0xff, 0x6b, 0x01, 0xff, 0xfa, 0x65, 0x00, 0xff, 0xff, 0x6f, 0x03, 0xff, 0xfb, 0x6b, 0x00, 0xff, 0x3a, 0x42, 0x45, 0xff, 0x3e, 0x3d, 0x38, 0xff, - 0x3b, 0x44, 0x43, 0xff, 0x44, 0x3f, 0x3c, 0xff, 0xfd, 0x6b, 0x04, 0xff, 0xff, 0x68, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xf9, 0x6b, 0x00, 0xff, 0xfd, 0x6b, 0x04, 0xff, 0xfc, 0x6a, 0x00, 0xff, - 0xf8, 0x6b, 0x01, 0xff, 0xff, 0x68, 0x00, 0xff, 0xcc, 0x74, 0x34, 0xff, 0xce, 0x79, 0x38, 0xff, 0xd6, 0x77, 0x37, 0xff, 0xfd, 0x66, 0x00, 0xff, 0xd4, 0x77, 0x2a, 0xff, 0xcf, 0x75, 0x39, 0xff, - 0xfb, 0x6c, 0x0c, 0xff, 0xff, 0x69, 0x00, 0xff, 0xff, 0x66, 0x00, 0xff, 0xd1, 0x76, 0x2f, 0xff, 0xff, 0x69, 0x02, 0xff, 0xcf, 0x78, 0x35, 0xff, 0xff, 0x67, 0x00, 0xff, 0xd1, 0x77, 0x3b, 0xff, - 0xd1, 0x75, 0x32, 0xff, 0x3f, 0x3e, 0x46, 0xff, 0xff, 0x68, 0x00, 0xff, 0xff, 0x6d, 0x05, 0xff, 0xfc, 0x64, 0x00, 0xff, 0xfe, 0x6c, 0x00, 0xff, 0x3b, 0x43, 0x46, 0xff, 0x42, 0x3f, 0x3a, 0xff, - 0x40, 0x41, 0x3c, 0xff, 0x3e, 0x40, 0x3b, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfc, 0x6b, 0x00, 0xff, 0xff, 0x6a, 0x03, 0xff, 0xfb, 0x6a, 0x01, 0xff, 0xfc, 0x6b, 0x02, 0xff, 0xff, 0x6a, 0x00, 0xff, - 0xfc, 0x6b, 0x00, 0xff, 0xff, 0x67, 0x00, 0xff, 0xef, 0x6e, 0x10, 0xff, 0xee, 0x6f, 0x0e, 0xff, 0xf2, 0x6d, 0x12, 0xff, 0xff, 0x68, 0x00, 0xff, 0xef, 0x6f, 0x0c, 0xff, 0xec, 0x6e, 0x1a, 0xff, - 0xff, 0x69, 0x02, 0xff, 0xff, 0x6a, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xeb, 0x70, 0x10, 0xff, 0xfd, 0x6a, 0x03, 0xff, 0xec, 0x70, 0x0e, 0xff, 0xff, 0x68, 0x00, 0xff, 0xee, 0x6e, 0x13, 0xff, - 0xf0, 0x6b, 0x0e, 0xff, 0x43, 0x43, 0x4b, 0xff, 0xf6, 0x68, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xff, 0x6d, 0x00, 0xff, 0xfc, 0x69, 0x00, 0xff, 0x3f, 0x3f, 0x47, 0xff, 0x42, 0x3f, 0x3a, 0xff, - 0x47, 0x42, 0x3f, 0xff, 0x3c, 0x42, 0x3e, 0xff, 0xff, 0x68, 0x00, 0xff, 0xf8, 0x6b, 0x01, 0xff, 0xfe, 0x69, 0x03, 0xff, 0xff, 0x6b, 0x05, 0xff, 0xfc, 0x6a, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, - 0xfc, 0x6b, 0x02, 0xff, 0xff, 0x67, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfd, 0x6b, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfd, 0x6b, 0x00, 0xff, 0xfc, 0x69, 0x09, 0xff, - 0xff, 0x68, 0x00, 0xff, 0xff, 0x6a, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xf7, 0x6d, 0x02, 0xff, 0xfd, 0x6a, 0x03, 0xff, 0xfd, 0x6b, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfd, 0x6a, 0x02, 0xff, - 0xff, 0x6c, 0x05, 0xff, 0x5c, 0x36, 0x21, 0xff, 0xfd, 0x6c, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xfd, 0x65, 0x00, 0xff, 0xfe, 0x6b, 0x04, 0xff, 0x40, 0x3d, 0x44, 0xff, 0x48, 0x43, 0x40, 0xff, - 0x44, 0x3e, 0x40, 0xff, 0x38, 0x43, 0x3f, 0xff, 0xff, 0x6a, 0x03, 0xff, 0xfa, 0x6c, 0x00, 0xff, 0xff, 0x69, 0x02, 0xff, 0xff, 0x68, 0x06, 0xff, 0xff, 0x6c, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, - 0xfa, 0x6b, 0x05, 0xff, 0xff, 0x69, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xf9, 0x6c, 0x02, 0xff, 0xff, 0x67, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfe, 0x69, 0x02, 0xff, - 0xfd, 0x6a, 0x02, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xf7, 0x6c, 0x03, 0xff, 0xfc, 0x6b, 0x02, 0xff, 0xff, 0x6a, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfd, 0x6b, 0x00, 0xff, - 0xf7, 0x69, 0x03, 0xff, 0xe8, 0x72, 0x1b, 0xff, 0xfe, 0x68, 0x00, 0xff, 0xff, 0x6a, 0x03, 0xff, 0xff, 0x6c, 0x07, 0xff, 0xfd, 0x6b, 0x08, 0xff, 0x40, 0x3e, 0x43, 0xff, 0x3f, 0x3e, 0x3c, 0xff, - 0x44, 0x3d, 0x44, 0xff, 0x37, 0x40, 0x3b, 0xff, 0xff, 0x6a, 0x09, 0xff, 0xfd, 0x6c, 0x00, 0xff, 0xff, 0x69, 0x02, 0xff, 0xf3, 0x68, 0x15, 0xff, 0xff, 0x6a, 0x00, 0xff, 0xfd, 0x68, 0x01, 0xff, - 0xfa, 0x6a, 0x07, 0xff, 0xff, 0x69, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfa, 0x6b, 0x03, 0xff, 0xff, 0x67, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfe, 0x69, 0x02, 0xff, - 0xfe, 0x69, 0x02, 0xff, 0xfe, 0x69, 0x02, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xf9, 0x6b, 0x05, 0xff, 0xfe, 0x69, 0x02, 0xff, 0xff, 0x69, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, - 0xf8, 0x6a, 0x04, 0xff, 0xff, 0x66, 0x00, 0xff, 0xff, 0x6b, 0x00, 0xff, 0xfb, 0x68, 0x01, 0xff, 0xfd, 0x68, 0x04, 0xff, 0xfb, 0x6c, 0x06, 0xff, 0x44, 0x3f, 0x43, 0xff, 0x40, 0x3e, 0x3f, 0xff, - 0x42, 0x3f, 0x46, 0xff, 0x3f, 0x40, 0x3a, 0xff, 0xfc, 0x68, 0x08, 0xff, 0xfc, 0x6a, 0x00, 0xff, 0xfc, 0x69, 0x01, 0xff, 0xd3, 0x73, 0x39, 0xff, 0xff, 0x71, 0x03, 0xff, 0xfc, 0x69, 0x02, 0xff, - 0xfa, 0x6b, 0x03, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfc, 0x6b, 0x00, 0xff, 0xfd, 0x6a, 0x02, 0xff, - 0xff, 0x68, 0x00, 0xff, 0xff, 0x69, 0x02, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfc, 0x6a, 0x07, 0xff, 0xff, 0x68, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfe, 0x69, 0x02, 0xff, - 0xff, 0x6e, 0x01, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfe, 0x69, 0x02, 0xff, 0xfe, 0x6c, 0x05, 0xff, 0xff, 0x6f, 0x04, 0xff, 0xfa, 0x69, 0x00, 0xff, 0x3f, 0x3e, 0x3c, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x40, 0x3f, 0x44, 0xff, 0x43, 0x42, 0x3e, 0xff, 0xfd, 0x69, 0x07, 0xff, 0xff, 0x6b, 0x00, 0xff, 0xff, 0x70, 0x06, 0xff, 0x65, 0x2d, 0x0c, 0xff, 0xf8, 0x69, 0x00, 0xff, 0xfc, 0x67, 0x01, 0xff, - 0xfd, 0x6a, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfd, 0x6b, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfc, 0x6b, 0x02, 0xff, 0xfe, 0x69, 0x02, 0xff, 0xfc, 0x6b, 0x00, 0xff, 0xfe, 0x69, 0x02, 0xff, - 0xff, 0x67, 0x00, 0xff, 0xff, 0x69, 0x02, 0xff, 0xff, 0x68, 0x02, 0xff, 0xfd, 0x69, 0x05, 0xff, 0xff, 0x67, 0x00, 0xff, 0xfe, 0x69, 0x02, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfd, 0x6a, 0x02, 0xff, - 0xfd, 0x66, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xfa, 0x67, 0x00, 0xff, 0xfd, 0x6c, 0x03, 0xff, 0xfb, 0x69, 0x00, 0xff, 0xff, 0x6e, 0x00, 0xff, 0x40, 0x40, 0x40, 0xff, 0x40, 0x40, 0x42, 0xff, - 0x3e, 0x3d, 0x3b, 0xff, 0x41, 0x41, 0x43, 0xff, 0xfe, 0x6b, 0x03, 0xff, 0xfe, 0x68, 0x00, 0xff, 0xfc, 0x64, 0x00, 0xff, 0x52, 0x46, 0x38, 0xff, 0xfc, 0x69, 0x00, 0xff, 0xff, 0x6b, 0x00, 0xff, - 0xfd, 0x6b, 0x00, 0xff, 0xff, 0x68, 0x02, 0xff, 0xfc, 0x6b, 0x02, 0xff, 0xfe, 0x6b, 0x00, 0xff, 0xfa, 0x6a, 0x09, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, - 0xfd, 0x6a, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xfd, 0x69, 0x07, 0xff, 0xfc, 0x6b, 0x00, 0xff, 0xff, 0x67, 0x00, 0xff, 0xfc, 0x6b, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfc, 0x6b, 0x00, 0xff, - 0xff, 0x6a, 0x02, 0xff, 0xfd, 0x6b, 0x06, 0xff, 0xff, 0x6c, 0x02, 0xff, 0xff, 0x68, 0x00, 0xff, 0xff, 0x6d, 0x00, 0xff, 0xfa, 0x66, 0x00, 0xff, 0x3e, 0x42, 0x45, 0xff, 0x3f, 0x40, 0x3a, 0xff, - 0x42, 0x41, 0x3c, 0xff, 0x41, 0x40, 0x46, 0xff, 0xfd, 0x69, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xff, 0x6b, 0x00, 0xff, 0x39, 0x3f, 0x3d, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, - 0xfe, 0x6a, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfd, 0x6a, 0x03, 0xff, 0xfd, 0x6b, 0x00, 0xff, 0xfa, 0x6a, 0x0a, 0xff, 0xff, 0x69, 0x00, 0xff, 0xff, 0x6a, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, - 0xfd, 0x6a, 0x00, 0xff, 0xfd, 0x6b, 0x00, 0xff, 0xfc, 0x6a, 0x07, 0xff, 0xfc, 0x6c, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfa, 0x6c, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfd, 0x6b, 0x00, 0xff, - 0xff, 0x68, 0x00, 0xff, 0xfb, 0x69, 0x06, 0xff, 0xfe, 0x6b, 0x01, 0xff, 0xff, 0x6b, 0x00, 0xff, 0xff, 0x64, 0x00, 0xff, 0xfe, 0x6c, 0x00, 0xff, 0x40, 0x41, 0x43, 0xff, 0x41, 0x41, 0x3f, 0xff, - 0x42, 0x3e, 0x3b, 0xff, 0x41, 0x41, 0x43, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfd, 0x68, 0x01, 0xff, 0xfd, 0x6b, 0x00, 0xff, 0x39, 0x3f, 0x3d, 0xff, 0xfe, 0x6e, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, - 0xfc, 0x6b, 0x02, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfd, 0x6a, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xf7, 0x6c, 0x07, 0xff, 0xff, 0x6a, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xfd, 0x6b, 0x00, 0xff, - 0xfd, 0x6b, 0x00, 0xff, 0xf9, 0x6c, 0x02, 0xff, 0xfd, 0x6a, 0x00, 0xff, 0xfd, 0x6b, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xf9, 0x6c, 0x02, 0xff, 0xff, 0x6a, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, - 0xff, 0x68, 0x00, 0xff, 0xfc, 0x6a, 0x03, 0xff, 0xfc, 0x69, 0x00, 0xff, 0xfc, 0x6b, 0x02, 0xff, 0xff, 0x6b, 0x00, 0xff, 0xf7, 0x6b, 0x00, 0xff, 0x45, 0x40, 0x3a, 0xff, 0x3c, 0x3d, 0x42, 0xff, - 0x40, 0x40, 0x3e, 0xff, 0x43, 0x42, 0x47, 0xff, 0xff, 0x67, 0x00, 0xff, 0xfe, 0x69, 0x03, 0xff, 0xfe, 0x6b, 0x03, 0xff, 0x5f, 0x3d, 0x21, 0xff, 0xfa, 0x6a, 0x00, 0xff, 0xff, 0x6b, 0x04, 0xff, - 0xfc, 0x6a, 0x03, 0xff, 0xff, 0x68, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xf9, 0x6b, 0x05, 0xff, 0xff, 0x69, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfd, 0x6a, 0x02, 0xff, - 0xff, 0x69, 0x00, 0xff, 0xfa, 0x6b, 0x05, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfa, 0x6b, 0x03, 0xff, 0xfd, 0x6a, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, - 0xff, 0x6b, 0x00, 0xff, 0xec, 0x6b, 0x10, 0xff, 0xff, 0x6b, 0x01, 0xff, 0xfe, 0x6b, 0x04, 0xff, 0xff, 0x65, 0x00, 0xff, 0xf8, 0x6e, 0x03, 0xff, 0x49, 0x42, 0x3c, 0xff, 0x43, 0x41, 0x4c, 0xff, - 0x39, 0x3f, 0x3f, 0xff, 0x3e, 0x41, 0x46, 0xff, 0xff, 0x6b, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xff, 0x6b, 0x00, 0xff, 0xdd, 0x6e, 0x1d, 0xff, 0xfe, 0x6c, 0x00, 0xff, 0xfe, 0x66, 0x01, 0xff, - 0xfd, 0x6a, 0x02, 0xff, 0xff, 0x68, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xff, 0x69, 0x02, 0xff, 0xfc, 0x6a, 0x07, 0xff, 0xff, 0x67, 0x00, 0xff, 0xff, 0x69, 0x02, 0xff, 0xfd, 0x69, 0x05, 0xff, - 0xff, 0x67, 0x00, 0xff, 0xfe, 0x69, 0x05, 0xff, 0xff, 0x68, 0x03, 0xff, 0xff, 0x68, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfa, 0x6b, 0x05, 0xff, 0xfc, 0x6a, 0x03, 0xff, 0xff, 0x68, 0x00, 0xff, - 0xf9, 0x68, 0x00, 0xff, 0x91, 0x32, 0x00, 0xff, 0xfc, 0x68, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xff, 0x6a, 0x05, 0xff, 0xf7, 0x68, 0x00, 0xff, 0x42, 0x3e, 0x3b, 0xff, 0x42, 0x3d, 0x43, 0xff, - 0x40, 0x45, 0x49, 0xff, 0x3f, 0x40, 0x45, 0xff, 0xff, 0x69, 0x00, 0xff, 0xff, 0x6b, 0x00, 0xff, 0xfd, 0x66, 0x00, 0xff, 0xe3, 0x72, 0x22, 0xff, 0xfe, 0x68, 0x00, 0xff, 0xff, 0x6b, 0x07, 0xff, - 0xfd, 0x6a, 0x02, 0xff, 0xff, 0x69, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfe, 0x69, 0x03, 0xff, 0xfd, 0x69, 0x05, 0xff, 0xff, 0x67, 0x00, 0xff, 0xff, 0x68, 0x02, 0xff, 0xfe, 0x68, 0x07, 0xff, - 0xff, 0x67, 0x00, 0xff, 0xff, 0x67, 0x03, 0xff, 0xff, 0x68, 0x05, 0xff, 0xff, 0x67, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xfd, 0x6a, 0x03, 0xff, 0xfa, 0x6b, 0x05, 0xff, 0xff, 0x69, 0x00, 0xff, - 0xfb, 0x6a, 0x00, 0xff, 0xb6, 0x7a, 0x56, 0xff, 0xff, 0x6d, 0x02, 0xff, 0xff, 0x66, 0x00, 0xff, 0xff, 0x67, 0x06, 0xff, 0xfc, 0x69, 0x02, 0xff, 0x43, 0x43, 0x43, 0xff, 0x41, 0x3c, 0x40, 0xff, - 0x3b, 0x39, 0x44, 0xff, 0x40, 0x3f, 0x3d, 0xff, 0xff, 0x68, 0x00, 0xff, 0xff, 0x69, 0x02, 0xff, 0xff, 0x6c, 0x08, 0xff, 0x5c, 0x37, 0x1d, 0xff, 0xff, 0x6a, 0x00, 0xff, 0xf9, 0x6a, 0x02, 0xff, - 0xfc, 0x6b, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xff, 0x6a, 0x00, 0xff, 0xfd, 0x6a, 0x02, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfd, 0x69, 0x05, 0xff, - 0xfe, 0x6a, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xfd, 0x6a, 0x03, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfd, 0x6a, 0x02, 0xff, 0xfd, 0x6a, 0x00, 0xff, 0xfa, 0x6b, 0x03, 0xff, 0xff, 0x69, 0x00, 0xff, - 0xff, 0x6c, 0x00, 0xff, 0x4c, 0x38, 0x31, 0xff, 0xfd, 0x65, 0x00, 0xff, 0xff, 0x68, 0x01, 0xff, 0xff, 0x67, 0x07, 0xff, 0xfe, 0x6b, 0x01, 0xff, 0x39, 0x3f, 0x3f, 0xff, 0x3d, 0x41, 0x40, 0xff, - 0x44, 0x41, 0x4a, 0xff, 0x43, 0x3f, 0x40, 0xff, 0xfc, 0x69, 0x01, 0xff, 0xff, 0x6b, 0x06, 0xff, 0xfe, 0x68, 0x07, 0xff, 0x53, 0x3c, 0x34, 0xff, 0xff, 0x66, 0x00, 0xff, 0xf8, 0x69, 0x01, 0xff, - 0xfc, 0x6b, 0x00, 0xff, 0xfd, 0x6b, 0x00, 0xff, 0xff, 0x6a, 0x00, 0xff, 0xfc, 0x6b, 0x02, 0xff, 0xff, 0x6a, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfd, 0x6a, 0x02, 0xff, - 0xfd, 0x6b, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xfd, 0x6a, 0x03, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfd, 0x6a, 0x02, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfc, 0x6a, 0x03, 0xff, 0xff, 0x69, 0x00, 0xff, - 0xfd, 0x67, 0x00, 0xff, 0x43, 0x40, 0x47, 0xff, 0xff, 0x6f, 0x01, 0xff, 0xff, 0x68, 0x00, 0xff, 0xff, 0x67, 0x05, 0xff, 0xfd, 0x68, 0x01, 0xff, 0x40, 0x44, 0x43, 0xff, 0x3f, 0x43, 0x42, 0xff, - 0x3d, 0x3d, 0x3f, 0xff, 0x43, 0x41, 0x46, 0xff, 0xfb, 0x6e, 0x02, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfc, 0x65, 0x00, 0xff, 0x72, 0x36, 0x12, 0xff, 0xff, 0x69, 0x00, 0xff, 0xff, 0x6c, 0x08, 0xff, - 0xfd, 0x6a, 0x02, 0xff, 0xfd, 0x6a, 0x02, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfd, 0x6a, 0x02, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfd, 0x6b, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, - 0xfc, 0x6c, 0x00, 0xff, 0xfe, 0x6b, 0x00, 0xff, 0xfd, 0x6a, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfd, 0x6a, 0x02, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfd, 0x6a, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, - 0xff, 0x69, 0x00, 0xff, 0x41, 0x3f, 0x42, 0xff, 0xf7, 0x6a, 0x00, 0xff, 0xfb, 0x6a, 0x00, 0xff, 0xff, 0x68, 0x03, 0xff, 0xfc, 0x6b, 0x02, 0xff, 0x44, 0x3f, 0x39, 0xff, 0x3f, 0x3e, 0x3c, 0xff, - 0x41, 0x42, 0x3d, 0xff, 0x3f, 0x40, 0x44, 0xff, 0xf6, 0x6c, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xb5, 0x7b, 0x56, 0xff, 0xfd, 0x6b, 0x00, 0xff, 0xff, 0x68, 0x03, 0xff, - 0xfe, 0x69, 0x02, 0xff, 0xfe, 0x69, 0x03, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfc, 0x6b, 0x00, 0xff, 0xff, 0x6a, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, - 0xfc, 0x6b, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfe, 0x69, 0x02, 0xff, 0xff, 0x69, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, - 0xff, 0x6b, 0x00, 0xff, 0x50, 0x3c, 0x31, 0xff, 0xf8, 0x6c, 0x00, 0xff, 0xfc, 0x6e, 0x02, 0xff, 0xff, 0x65, 0x00, 0xff, 0xfd, 0x6c, 0x03, 0xff, 0x43, 0x3e, 0x3a, 0xff, 0x44, 0x40, 0x3f, 0xff, - 0x43, 0x3f, 0x34, 0xff, 0x3e, 0x43, 0x3d, 0xff, 0xf8, 0x6d, 0x04, 0xff, 0xff, 0x6a, 0x00, 0xff, 0xff, 0x6b, 0x00, 0xff, 0x4d, 0x3d, 0x2e, 0xff, 0xfb, 0x67, 0x00, 0xff, 0xff, 0x6d, 0x03, 0xff, - 0xff, 0x68, 0x00, 0xff, 0xff, 0x6b, 0x04, 0xff, 0xfc, 0x67, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xff, 0x6a, 0x00, 0xff, 0xf9, 0x6b, 0x05, 0xff, 0xfb, 0x68, 0x00, 0xff, 0xfe, 0x6d, 0x02, 0xff, - 0xfc, 0x69, 0x00, 0xff, 0xff, 0x6a, 0x00, 0xff, 0xff, 0x69, 0x01, 0xff, 0xf9, 0x67, 0x04, 0xff, 0xfd, 0x6b, 0x04, 0xff, 0xfd, 0x69, 0x00, 0xff, 0xff, 0x6c, 0x00, 0xff, 0xff, 0x6b, 0x00, 0xff, - 0xff, 0x69, 0x00, 0xff, 0x6e, 0x34, 0x0f, 0xff, 0xf7, 0x6d, 0x00, 0xff, 0xfc, 0x6e, 0x02, 0xff, 0xff, 0x66, 0x00, 0xff, 0xfe, 0x6b, 0x01, 0xff, 0x39, 0x3f, 0x3d, 0xff, 0x41, 0x42, 0x3d, 0xff, - 0x45, 0x41, 0x38, 0xff, 0x3a, 0x3f, 0x3b, 0xff, 0xfa, 0x6b, 0x03, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfd, 0x67, 0x00, 0xff, 0x50, 0x43, 0x32, 0xff, 0xed, 0x6e, 0x11, 0xff, 0xfd, 0x66, 0x00, 0xff, - 0xf5, 0x6e, 0x12, 0xff, 0xed, 0x6b, 0x13, 0xff, 0xff, 0x6a, 0x03, 0xff, 0xf3, 0x6e, 0x11, 0xff, 0xfa, 0x66, 0x00, 0xff, 0xfe, 0x6c, 0x05, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xfd, 0x6a, 0x02, 0xff, - 0xfd, 0x69, 0x00, 0xff, 0xfc, 0x6a, 0x03, 0xff, 0xff, 0x67, 0x01, 0xff, 0xfd, 0x69, 0x07, 0xff, 0xff, 0x6d, 0x06, 0xff, 0xf3, 0x6e, 0x0f, 0xff, 0xef, 0x6d, 0x0b, 0xff, 0xee, 0x6d, 0x0f, 0xff, - 0xf3, 0x70, 0x18, 0xff, 0xd1, 0x73, 0x35, 0xff, 0xf9, 0x6d, 0x00, 0xff, 0xfa, 0x6b, 0x03, 0xff, 0xff, 0x63, 0x00, 0xff, 0xff, 0x6e, 0x02, 0xff, 0x3d, 0x43, 0x43, 0xff, 0x41, 0x41, 0x41, 0xff, - 0x3f, 0x41, 0x3e, 0xff, 0x40, 0x41, 0x46, 0xff, 0xfb, 0x68, 0x00, 0xff, 0xff, 0x68, 0x02, 0xff, 0xfc, 0x6e, 0x02, 0xff, 0x67, 0x31, 0x05, 0xff, 0x85, 0x31, 0x00, 0xff, 0xff, 0x6c, 0x03, 0xff, - 0x89, 0x2b, 0x00, 0xff, 0x88, 0x2f, 0x00, 0xff, 0xf9, 0x65, 0x00, 0xff, 0x88, 0x2e, 0x00, 0xff, 0xf9, 0x70, 0x10, 0xff, 0xff, 0x69, 0x00, 0xff, 0xff, 0x67, 0x00, 0xff, 0xfa, 0x67, 0x00, 0xff, - 0xff, 0x6a, 0x00, 0xff, 0xf6, 0x6d, 0x0d, 0xff, 0xfc, 0x6a, 0x05, 0xff, 0xff, 0x6b, 0x00, 0xff, 0xf9, 0x66, 0x00, 0xff, 0x89, 0x24, 0x00, 0xff, 0x8c, 0x34, 0x00, 0xff, 0x86, 0x2a, 0x00, 0xff, - 0x85, 0x27, 0x00, 0xff, 0xf4, 0x73, 0x15, 0xff, 0xfe, 0x6c, 0x00, 0xff, 0xfd, 0x6b, 0x06, 0xff, 0xff, 0x69, 0x09, 0xff, 0xfe, 0x63, 0x00, 0xff, 0x45, 0x44, 0x42, 0xff, 0x3a, 0x3d, 0x42, 0xff, - 0x3d, 0x3f, 0x3e, 0xff, 0x40, 0x40, 0x4a, 0xff, 0xff, 0x6d, 0x00, 0xff, 0xff, 0x67, 0x03, 0xff, 0xf8, 0x69, 0x01, 0xff, 0xd3, 0x76, 0x30, 0xff, 0xcf, 0x7b, 0x35, 0xff, 0xfd, 0x64, 0x00, 0xff, - 0xd6, 0x77, 0x33, 0xff, 0xc9, 0x73, 0x38, 0xff, 0xff, 0x6b, 0x00, 0xff, 0xce, 0x74, 0x38, 0xff, 0xf5, 0x6c, 0x0c, 0xff, 0xff, 0x66, 0x00, 0xff, 0xff, 0x6a, 0x00, 0xff, 0xff, 0x6a, 0x03, 0xff, - 0xff, 0x6b, 0x00, 0xff, 0xf4, 0x6b, 0x0b, 0xff, 0xfb, 0x69, 0x04, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfd, 0x69, 0x00, 0xff, 0xe2, 0x7c, 0x34, 0xff, 0xca, 0x71, 0x35, 0xff, 0xd3, 0x75, 0x37, 0xff, - 0xd5, 0x79, 0x38, 0xff, 0xfc, 0x68, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfd, 0x6b, 0x08, 0xff, 0xff, 0x69, 0x0b, 0xff, 0xff, 0x67, 0x00, 0xff, 0x41, 0x40, 0x3e, 0xff, 0x41, 0x40, 0x46, 0xff, - 0x42, 0x41, 0x3f, 0xff, 0x39, 0x40, 0x46, 0xff, 0xff, 0x6b, 0x00, 0xff, 0xfe, 0x65, 0x00, 0xff, 0xff, 0x6b, 0x04, 0xff, 0xef, 0x6d, 0x0b, 0xff, 0xf1, 0x6e, 0x13, 0xff, 0xff, 0x6b, 0x07, 0xff, - 0xee, 0x6e, 0x0d, 0xff, 0xea, 0x71, 0x18, 0xff, 0xff, 0x6b, 0x00, 0xff, 0xef, 0x6f, 0x14, 0xff, 0xff, 0x6b, 0x04, 0xff, 0xff, 0x68, 0x00, 0xff, 0xff, 0x66, 0x00, 0xff, 0xfd, 0x66, 0x00, 0xff, - 0xfd, 0x69, 0x00, 0xff, 0xf9, 0x6a, 0x01, 0xff, 0xff, 0x6a, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xf2, 0x6d, 0x10, 0xff, 0xed, 0x6b, 0x13, 0xff, 0xf4, 0x6e, 0x17, 0xff, - 0xf0, 0x6f, 0x13, 0xff, 0xff, 0x69, 0x00, 0xff, 0xff, 0x6c, 0x00, 0xff, 0xfc, 0x6d, 0x07, 0xff, 0xfd, 0x65, 0x02, 0xff, 0xff, 0x6b, 0x00, 0xff, 0x3d, 0x41, 0x40, 0xff, 0x43, 0x3f, 0x3e, 0xff, - 0x41, 0x40, 0x3e, 0xff, 0x39, 0x41, 0x43, 0xff, 0xe5, 0x6e, 0x1a, 0xff, 0xe3, 0x72, 0x24, 0xff, 0xe1, 0x70, 0x24, 0xff, 0xe4, 0x76, 0x21, 0xff, 0xde, 0x6d, 0x1f, 0xff, 0xe2, 0x6e, 0x23, 0xff, - 0xe2, 0x73, 0x22, 0xff, 0xda, 0x70, 0x24, 0xff, 0xe4, 0x6e, 0x17, 0xff, 0xe3, 0x74, 0x25, 0xff, 0xe4, 0x6f, 0x1f, 0xff, 0xe5, 0x6e, 0x1e, 0xff, 0xe3, 0x73, 0x29, 0xff, 0xe4, 0x73, 0x25, 0xff, - 0xde, 0x71, 0x1f, 0xff, 0xe4, 0x73, 0x23, 0xff, 0xe5, 0x72, 0x22, 0xff, 0xe3, 0x70, 0x1f, 0xff, 0xe3, 0x72, 0x22, 0xff, 0xe1, 0x72, 0x23, 0xff, 0xe2, 0x71, 0x23, 0xff, 0xe1, 0x6d, 0x22, 0xff, - 0xe0, 0x71, 0x22, 0xff, 0xe5, 0x72, 0x21, 0xff, 0xe2, 0x72, 0x20, 0xff, 0xd9, 0x6e, 0x20, 0xff, 0xe7, 0x73, 0x26, 0xff, 0xe3, 0x75, 0x1e, 0xff, 0x39, 0x42, 0x41, 0xff, 0x46, 0x40, 0x40, 0xff, - 0x3f, 0x3f, 0x3d, 0xff, 0x3e, 0x42, 0x41, 0xff, 0x5c, 0x38, 0x18, 0xff, 0x5d, 0x39, 0x23, 0xff, 0x60, 0x38, 0x1f, 0xff, 0x5e, 0x39, 0x1c, 0xff, 0x57, 0x39, 0x1d, 0xff, 0x5f, 0x3a, 0x1d, 0xff, - 0x5f, 0x3c, 0x20, 0xff, 0x58, 0x38, 0x21, 0xff, 0x60, 0x37, 0x19, 0xff, 0x5e, 0x39, 0x1c, 0xff, 0x5d, 0x38, 0x1b, 0xff, 0x5b, 0x34, 0x15, 0xff, 0x5c, 0x3e, 0x26, 0xff, 0x5a, 0x36, 0x1c, 0xff, - 0x5d, 0x39, 0x21, 0xff, 0x60, 0x39, 0x1c, 0xff, 0x5c, 0x38, 0x1e, 0xff, 0x5c, 0x35, 0x18, 0xff, 0x58, 0x38, 0x1f, 0xff, 0x5e, 0x3a, 0x1a, 0xff, 0x5c, 0x39, 0x1d, 0xff, 0x61, 0x39, 0x1f, 0xff, - 0x5d, 0x39, 0x1f, 0xff, 0x5f, 0x37, 0x1e, 0xff, 0x59, 0x3a, 0x1e, 0xff, 0x5f, 0x3a, 0x1d, 0xff, 0x60, 0x39, 0x1c, 0xff, 0x5b, 0x3a, 0x19, 0xff, 0x3a, 0x40, 0x3c, 0xff, 0x40, 0x3b, 0x3f, 0xff, - 0x3e, 0x40, 0x3f, 0xff, 0x3e, 0x40, 0x3d, 0xff, 0x41, 0x43, 0x3e, 0xff, 0x3d, 0x40, 0x45, 0xff, 0x3f, 0x3d, 0x40, 0xff, 0x3f, 0x3f, 0x3d, 0xff, 0x3c, 0x46, 0x45, 0xff, 0x3f, 0x40, 0x3b, 0xff, - 0x3d, 0x3d, 0x3d, 0xff, 0x40, 0x44, 0x47, 0xff, 0x42, 0x3e, 0x3b, 0xff, 0x40, 0x3f, 0x3b, 0xff, 0x40, 0x40, 0x3e, 0xff, 0x42, 0x41, 0x3d, 0xff, 0x38, 0x42, 0x44, 0xff, 0x3d, 0x41, 0x40, 0xff, - 0x40, 0x41, 0x45, 0xff, 0x43, 0x3f, 0x3e, 0xff, 0x3e, 0x3f, 0x43, 0xff, 0x41, 0x40, 0x3c, 0xff, 0x3b, 0x43, 0x45, 0xff, 0x3f, 0x40, 0x3a, 0xff, 0x3d, 0x3f, 0x3c, 0xff, 0x42, 0x41, 0x3f, 0xff, - 0x3f, 0x3f, 0x41, 0xff, 0x41, 0x3f, 0x42, 0xff, 0x3b, 0x43, 0x45, 0xff, 0x3f, 0x3e, 0x39, 0xff, 0x42, 0x3f, 0x3a, 0xff, 0x3d, 0x43, 0x3f, 0xff, 0x3d, 0x43, 0x3f, 0xff, 0x42, 0x3f, 0x46, 0xff}; - -// clang-format on - -inline std::vector -ReadBlobUnsafe(const std::string& filename) -{ - std::ifstream file(filename, std::ios::binary | std::ios::ate); - - if (!file.is_open()) - return {}; - - std::ifstream::pos_type pos = file.tellg(); - - // What happens if the OS supports really big files. - // It may be larger than 32 bits? - // This will silently truncate the value/ - std::streamoff length = pos; - - std::vector bytes(length); - if (pos > 0) - { // Manuall memory management. - // Not a good idea use a container/. - file.seekg(0, std::ios::beg); - file.read((char*)bytes.data(), length); - } - file.close(); - return bytes; -}; - -int -main() -{ - - Fox::DContextConfig config; - config.logOutputFunction = &Log; - config.warningFunction = &Log; - - Fox::IContext* context = Fox::CreateVulkanContext(&config); - - { - if (!glfwInit()) - { - throw std::runtime_error("Failed to glfwInit"); - } - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); // as Vulkan, there is no need to create a context - GLFWwindow* window = glfwCreateWindow(640, 480, "My Title", NULL, NULL); - if (!window) - { - throw std::runtime_error("Failed to glfwCreateWindow"); - } - Fox::WindowData windowData; - windowData._hwnd = glfwGetWin32Window(window); - windowData._instance = GetModuleHandle(NULL); - - Fox::DSwapchain swapchain; - auto presentMode = Fox::EPresentMode::IMMEDIATE_KHR; - auto format = Fox::EFormat::B8G8R8A8_UNORM; - if (!context->CreateSwapchain(&windowData, presentMode, format, &swapchain)) - { - throw std::runtime_error("Failed to CreateSwapchain"); - } - - // Create vertex layout - Fox::VertexLayoutInfo position("SV_POSITION", Fox::EFormat::R32G32B32_FLOAT, 0, Fox::EVertexInputClassification::PER_VERTEX_DATA); - Fox::VertexLayoutInfo color("Color0", Fox::EFormat::R32G32B32A32_FLOAT, 3 * sizeof(float), Fox::EVertexInputClassification::PER_VERTEX_DATA); - Fox::DVertexInputLayout vertexLayout = context->CreateVertexLayout({ position, color }); - constexpr uint32_t stride = 7 * sizeof(float); - - Fox::ShaderSource shaderSource; - shaderSource.VertexLayout = vertexLayout; - shaderSource.VertexStride = stride; - shaderSource.SourceCode.VertexShader = ReadBlobUnsafe("vertex.spv"); - shaderSource.SourceCode.PixelShader = ReadBlobUnsafe("fragment.spv"); - - shaderSource.SetsLayout.SetsLayout[0].insert({ 0, Fox::ShaderDescriptorBindings("Camera", Fox::EBindingType::UNIFORM_BUFFER_OBJECT, sizeof(float) * 16, 1, Fox::EShaderStage::VERTEX) }); - shaderSource.SetsLayout.SetsLayout[1].insert({ 0, Fox::ShaderDescriptorBindings("MatrixUbo", Fox::EBindingType::UNIFORM_BUFFER_OBJECT, sizeof(float) * 16, 1, Fox::EShaderStage::VERTEX) }); - shaderSource.SetsLayout.SetsLayout[2].insert({ 0, Fox::ShaderDescriptorBindings("MyTexture", Fox::EBindingType::SAMPLER, 1, 1, Fox::EShaderStage::FRAGMENT) }); - - shaderSource.ColorAttachments.push_back({ format }); - shaderSource.DepthStencilAttachment = Fox::EFormat::DEPTH32_FLOAT; - - Fox::DShader shader = context->CreateShader(shaderSource); - - // clang-format off - constexpr std::array ndcQuad{ - -1, -1, -1,//pos - 0, 1, 0, 1,// color - 1, -1, -1,//pos - 0, 0, 1, 1,// color - 1, 1, -1,//pos - 0, 1, 1, 1,// color - //----------------// - -1, -1, -1,//pos - 0, 1, 0, 1,// color - 1, 1, -1,//pos - 0, 0, 1, 1,// color - -1, 1, -1,//pos - 0, 1, 1, 1,// color - //----------------// - -1, -1, 1,//pos - 0, 1, 0, 1,// color - 1, -1, 1,//pos - 0, 0, 1, 1,// color - 1, 1, 1,//pos - 0, 1, 1, 1,// color - //----------------// - -1, -1, 1,//pos - 0, 1, 0, 1,// color - 1, 1, 1,//pos - 0, 0, 1, 1,// color - -1, 1, 1,//pos - 0, 1, 1, 1,// color - }; - // clang-format on - constexpr size_t bufSize = sizeof(float) * ndcQuad.size(); - Fox::DBuffer quad = context->CreateVertexBuffer(bufSize); - - Fox::CopyDataCommand copy; - copy.CopyVertex(quad, 0, (void*)ndcQuad.data(), bufSize); - context->SubmitCopy(std::move(copy)); - - Fox::DImage depthBuffer = context->CreateImage(Fox::EFormat::DEPTH32_FLOAT, 640, 480, 1); - Fox::DFramebuffer swapchainFbo = context->CreateSwapchainFramebuffer_DEPRECATED(swapchain, depthBuffer); - - Fox::DRenderPassAttachment colorAttachment(format, - Fox::ESampleBit::COUNT_1_BIT, - Fox::ERenderPassLoad::Clear, - Fox::ERenderPassStore::Store, - Fox::ERenderPassLayout::Undefined, - Fox::ERenderPassLayout::Present, - Fox::EAttachmentReference::COLOR_ATTACHMENT); - Fox::DRenderPassAttachments renderPass; - renderPass.Attachments.push_back(colorAttachment); - - Fox::DRenderPassAttachment depthAttachment(Fox::EFormat::DEPTH32_FLOAT, - Fox::ESampleBit::COUNT_1_BIT, - Fox::ERenderPassLoad::Clear, - Fox::ERenderPassStore::Store, - Fox::ERenderPassLayout::Undefined, - Fox::ERenderPassLayout::Present, - Fox::EAttachmentReference::DEPTH_STENCIL_ATTACHMENT); - renderPass.Attachments.push_back(depthAttachment); - - Fox::DBuffer transformUniformBuffer = context->CreateUniformBuffer(sizeof(float) * 16); - float yaw{ 0 }; - - Fox::DImage texture = context->CreateImage(Fox::EFormat::R8G8B8A8_UNORM, imageWidth, imageHeight, 1); - { - Fox::CopyDataCommand copy; - copy.CopyImageMipMap(texture, 0, (void*)image, imageWidth, imageHeight, 0, sizeof(image)); - context->SubmitCopy(std::move(copy)); - } - - const auto perspective = glm::perspective(glm::radians(60.f), 1.f, 0.f, 1.f); - const auto view = glm::translate(glm::mat4(1.f), glm::vec3(0, 0, -5)); - glm::mat4 cameraProjection = perspective * view; - Fox::DBuffer cameraUniformBuffer = context->CreateUniformBuffer(sizeof(float) * 16); - { - Fox::CopyDataCommand copy; - copy.CopyUniformBuffer(cameraUniformBuffer, glm::value_ptr(cameraProjection), sizeof(float) * 16); - context->SubmitCopy(std::move(copy)); - } - - while (!glfwWindowShouldClose(window)) - { - // Keep running - glfwPollEvents(); - - int w, h; - glfwGetWindowSize(window, &w, &h); - Fox::DViewport viewport{ 0, 0, w, h, 0.f, 1.f }; - - { - yaw += 0.001f; - const float sinA = std::sin(yaw); - const float cosA = std::cos(yaw); - - float matrix[4][4]{ { cosA, 0, -sinA, 0 }, { 0, 1, 0, 0 }, { sinA, 0, cosA, 0 }, { 0, 0, 0, 1 } }; - Fox::CopyDataCommand copy; - copy.CopyUniformBuffer(transformUniformBuffer, &matrix[0][0], sizeof(float) * 16); - context->SubmitCopy(std::move(copy)); - } - - Fox::RenderPassData draw(swapchainFbo, viewport, renderPass); - draw.ClearColor(1, 0, 0, 1); - draw.ClearDepthStencil(0, 0); - - { - Fox::DrawCommand drawTriangle(shader); - drawTriangle.BindBufferUniformBuffer(0, 0, cameraUniformBuffer); - drawTriangle.BindBufferUniformBuffer(1, 0, transformUniformBuffer); - drawTriangle.BindImageArray(2, 0, { texture }); - drawTriangle.Draw(quad, 0, 12); - draw.AddDrawCommand(std::move(drawTriangle)); - } - - context->SubmitPass(std::move(draw)); - - context->AdvanceFrame(); - } - - context->DestroyShader(shader); - context->DestroyImage(texture); - context->DestroyImage(depthBuffer); - context->DestroyVertexBuffer(quad); - context->DestroyUniformBuffer(transformUniformBuffer); - context->DestroyUniformBuffer(cameraUniformBuffer); - context->_destroyFramebuffer(swapchainFbo); - context->DestroySwapchain(swapchain); - - glfwDestroyWindow(window); - - glfwTerminate(); - } - - delete context; - - return 0; -} \ No newline at end of file diff --git a/examples/DepthBuffer/buildShaders.bat b/examples/DepthBuffer/buildShaders.bat deleted file mode 100644 index 890d4a2..0000000 --- a/examples/DepthBuffer/buildShaders.bat +++ /dev/null @@ -1,3 +0,0 @@ -C:\VulkanSDK\1.3.261.1\Bin\glslc.exe -fshader-stage=vert vertex.glsl -o vertex.spv -C:\VulkanSDK\1.3.261.1\Bin\glslc.exe -fshader-stage=frag fragment.glsl -o fragment.spv -pause \ No newline at end of file diff --git a/examples/DepthBuffer/fragment.glsl b/examples/DepthBuffer/fragment.glsl deleted file mode 100644 index e7d06f8..0000000 --- a/examples/DepthBuffer/fragment.glsl +++ /dev/null @@ -1,20 +0,0 @@ -#version 450 - -layout(location = 0) in vec2 pos; -layout(location = 0) out vec4 outColor; - -layout(set =2, binding = 0) uniform sampler2D MyTexture; - -vec2 CorrectUv(vec2 uv) -{ -return vec2(uv.x, 1-uv.y); -} -vec2 xCorrectUv(vec2 uv) -{ -return uv; -} - -void main() { - vec4 texColor = texture(MyTexture, pos); - outColor = texColor; -} \ No newline at end of file diff --git a/examples/DepthBuffer/fragment.spv b/examples/DepthBuffer/fragment.spv deleted file mode 100644 index be6eb1b..0000000 Binary files a/examples/DepthBuffer/fragment.spv and /dev/null differ diff --git a/examples/DepthBuffer/two spinning cubes in cirlce.txt b/examples/DepthBuffer/two spinning cubes in cirlce.txt deleted file mode 100644 index e69de29..0000000 diff --git a/examples/DepthBuffer/vertex.glsl b/examples/DepthBuffer/vertex.glsl deleted file mode 100644 index 2b20546..0000000 --- a/examples/DepthBuffer/vertex.glsl +++ /dev/null @@ -1,21 +0,0 @@ -#version 450 - -layout(location = 0) in vec3 position; -layout(location = 1) in vec4 color; - -layout(location = 0) out vec2 pos; - -layout (set = 0, binding =0) uniform Camera -{ - mat4 Matrix; -}projection; - -layout (set= 1, binding =0) uniform Model -{ - mat4 Matrix; -}ubo; - -void main() { - gl_Position = projection.Matrix * ubo.Matrix * vec4(position.xyz, 1.0); - pos = position.xy; -} \ No newline at end of file diff --git a/examples/DepthBuffer/vertex.spv b/examples/DepthBuffer/vertex.spv deleted file mode 100644 index e98c801..0000000 Binary files a/examples/DepthBuffer/vertex.spv and /dev/null differ diff --git a/examples/Rendering/Rendering.cpp b/examples/Rendering/Rendering.cpp index fe7073b..40bfb92 100644 --- a/examples/Rendering/Rendering.cpp +++ b/examples/Rendering/Rendering.cpp @@ -250,6 +250,10 @@ class TriangleApp : public App public: TriangleApp() { + // Find graphics queue + _graphicsQueue = _ctx->FindQueue(Fox::EQueueType::QUEUE_GRAPHICS); + assert(_graphicsQueue > 0); + // Create vertex layout Fox::VertexLayoutInfo position("SV_POSITION", Fox::EFormat::R32G32B32_FLOAT, 0, Fox::EVertexInputClassification::PER_VERTEX_DATA); Fox::VertexLayoutInfo color("Color0", Fox::EFormat::R32G32B32A32_FLOAT, 4 * sizeof(float), Fox::EVertexInputClassification::PER_VERTEX_DATA); @@ -749,6 +753,7 @@ class TriangleApp : public App }; protected: + uint32_t _graphicsQueue{}; uint32_t _depthRt{}; uint32_t _shader{}; uint32_t _pipeline{}; @@ -822,7 +827,7 @@ class TriangleApp : public App _ctx->EndCommandBuffer(cmd); - _ctx->QueueSubmit({}, {}, { cmd }, NULL); + _ctx->QueueSubmit(_graphicsQueue, {}, {}, { cmd }, NULL); _ctx->WaitDeviceIdle(); _ctx->DestroyBuffer(tmpBuf); diff --git a/examples/SpinningTriangle/CMakeLists.txt b/examples/SpinningTriangle/CMakeLists.txt deleted file mode 100644 index 960d388..0000000 --- a/examples/SpinningTriangle/CMakeLists.txt +++ /dev/null @@ -1,18 +0,0 @@ -cmake_minimum_required(VERSION 3.26.4) -project(SpinningTriangle CXX) - -add_executable(${PROJECT_NAME} -"SpinningTriangle.cpp" -) - - -target_link_libraries(${PROJECT_NAME} PRIVATE FoxFury glfw) - -set_target_properties(${PROJECT_NAME} PROPERTIES - RUNTIME_OUTPUT_DIRECTORY "bin" -) - -#Set the debug working directory -set_target_properties(${PROJECT_NAME} PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}") - -include_directories(${LIB_INCLUDE_DIR}) \ No newline at end of file diff --git a/examples/SpinningTriangle/SpinningTriangle.cpp b/examples/SpinningTriangle/SpinningTriangle.cpp deleted file mode 100644 index 6abb622..0000000 --- a/examples/SpinningTriangle/SpinningTriangle.cpp +++ /dev/null @@ -1,182 +0,0 @@ -// Copyright RedFox Studio 2022 - -#include - -#include "IContext.h" -#include "backend/vulkan/VulkanContextFactory.h" - -#include - -#define GLFW_INCLUDE_NONE // makes the GLFW header not include any OpenGL or -// OpenGL ES API header.This is useful in combination with an extension loading library. -#include - -#define GLFW_EXPOSE_NATIVE_WIN32 -#include - -#include -#include -#include - -void -Log(const char* msg) -{ - std::cout << msg << std::endl; -}; - -inline std::vector -ReadBlobUnsafe(const std::string& filename) -{ - std::ifstream file(filename, std::ios::binary | std::ios::ate); - - if (!file.is_open()) - return {}; - - std::ifstream::pos_type pos = file.tellg(); - - // What happens if the OS supports really big files. - // It may be larger than 32 bits? - // This will silently truncate the value/ - std::streamoff length = pos; - - std::vector bytes(length); - if (pos > 0) - { // Manuall memory management. - // Not a good idea use a container/. - file.seekg(0, std::ios::beg); - file.read((char*)bytes.data(), length); - } - file.close(); - return bytes; -}; - -int -main() -{ - - Fox::DContextConfig config; - config.logOutputFunction = &Log; - config.warningFunction = &Log; - - Fox::IContext* context = Fox::CreateVulkanContext(&config); - - { - if (!glfwInit()) - { - throw std::runtime_error("Failed to glfwInit"); - } - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); // as Vulkan, there is no need to create a context - GLFWwindow* window = glfwCreateWindow(640, 480, "My Title", NULL, NULL); - if (!window) - { - throw std::runtime_error("Failed to glfwCreateWindow"); - } - Fox::WindowData windowData; - windowData._hwnd = glfwGetWin32Window(window); - windowData._instance = GetModuleHandle(NULL); - - Fox::DSwapchain swapchain; - auto presentMode = Fox::EPresentMode::IMMEDIATE_KHR; - auto format = Fox::EFormat::B8G8R8A8_UNORM; - if (!context->CreateSwapchain(&windowData, presentMode, format, &swapchain)) - { - throw std::runtime_error("Failed to CreateSwapchain"); - } - - // Create vertex layout - Fox::VertexLayoutInfo position("SV_POSITION", Fox::EFormat::R32G32B32_FLOAT, 0, Fox::EVertexInputClassification::PER_VERTEX_DATA); - Fox::VertexLayoutInfo color("Color0", Fox::EFormat::R32G32B32A32_FLOAT, 3 * sizeof(float), Fox::EVertexInputClassification::PER_VERTEX_DATA); - Fox::DVertexInputLayout vertexLayout = context->CreateVertexLayout({ position, color }); - constexpr uint32_t stride = 7 * sizeof(float); - - Fox::ShaderSource shaderSource; - shaderSource.VertexLayout = vertexLayout; - shaderSource.VertexStride = stride; - shaderSource.SourceCode.VertexShader = ReadBlobUnsafe("vertex.spv"); - shaderSource.SourceCode.PixelShader = ReadBlobUnsafe("fragment.spv"); - shaderSource.ColorAttachments.push_back(format); - - shaderSource.SetsLayout.SetsLayout[0].insert({ 0, Fox::ShaderDescriptorBindings("MatrixUbo", Fox::EBindingType::UNIFORM_BUFFER_OBJECT, sizeof(float) * 16, 1, Fox::EShaderStage::VERTEX) }); - - Fox::DShader shader = context->CreateShader(shaderSource); - - // clang-format off - constexpr std::array ndcTriangle{ - -1, -1, 0.5,//pos - 0, 1, 0, 1,// color - 1, -1, 0.5,//pos - 0, 0, 1, 1,// color - 0, 1, 0.5,//pos - 0, 1, 1, 1// color - }; - // clang-format on - constexpr size_t bufSize = sizeof(float) * ndcTriangle.size(); - Fox::DBuffer triangle = context->CreateVertexBuffer(bufSize); - - Fox::CopyDataCommand copy; - copy.CopyVertex(triangle, 0, (void*)ndcTriangle.data(), bufSize); - context->SubmitCopy(std::move(copy)); - - Fox::DFramebuffer swapchainFbo = context->CreateSwapchainFramebuffer_DEPRECATED(swapchain); - - Fox::DRenderPassAttachment colorAttachment(format, - Fox::ESampleBit::COUNT_1_BIT, - Fox::ERenderPassLoad::Clear, - Fox::ERenderPassStore::Store, - Fox::ERenderPassLayout::Undefined, - Fox::ERenderPassLayout::Present, - Fox::EAttachmentReference::COLOR_ATTACHMENT); - Fox::DRenderPassAttachments renderPass; - renderPass.Attachments.push_back(colorAttachment); - - Fox::DBuffer transformUniformBuffer = context->CreateUniformBuffer(sizeof(float) * 16); - float yaw{ 0 }; - - while (!glfwWindowShouldClose(window)) - { - // Keep running - glfwPollEvents(); - - int w, h; - glfwGetWindowSize(window, &w, &h); - Fox::DViewport viewport{ 0, 0, w, h, 0.f, 1.f }; - - { - yaw += 0.01f; - const float sinA = std::sin(yaw); - const float cosA = std::cos(yaw); - - float matrix[4][4]{ { cosA, 0, -sinA, 0 }, { 0, 1, 0, 0 }, { sinA, 0, cosA, 0 }, { 0, 0, 0, 1 } }; - Fox::CopyDataCommand copy; - copy.CopyUniformBuffer(transformUniformBuffer, &matrix[0][0], sizeof(float) * 16); - context->SubmitCopy(std::move(copy)); - } - - Fox::RenderPassData draw(swapchainFbo, viewport, renderPass); - draw.ClearColor(1, 0, 0, 1); - - Fox::DrawCommand drawTriangle(shader); - drawTriangle.BindBufferUniformBuffer(0, 0, transformUniformBuffer); - drawTriangle.Draw(triangle, 0, 3); - - draw.AddDrawCommand(std::move(drawTriangle)); - - context->SubmitPass(std::move(draw)); - - context->AdvanceFrame(); - } - context->DestroyShader(shader); - context->DestroyVertexBuffer(triangle); - context->DestroyUniformBuffer(transformUniformBuffer); - - context->DestroySwapchain(swapchain); - - glfwDestroyWindow(window); - - glfwTerminate(); - } - - delete context; - - return 0; -} \ No newline at end of file diff --git a/examples/SpinningTriangle/buildShaders.bat b/examples/SpinningTriangle/buildShaders.bat deleted file mode 100644 index 890d4a2..0000000 --- a/examples/SpinningTriangle/buildShaders.bat +++ /dev/null @@ -1,3 +0,0 @@ -C:\VulkanSDK\1.3.261.1\Bin\glslc.exe -fshader-stage=vert vertex.glsl -o vertex.spv -C:\VulkanSDK\1.3.261.1\Bin\glslc.exe -fshader-stage=frag fragment.glsl -o fragment.spv -pause \ No newline at end of file diff --git a/examples/SpinningTriangle/fragment.glsl b/examples/SpinningTriangle/fragment.glsl deleted file mode 100644 index 1ba594f..0000000 --- a/examples/SpinningTriangle/fragment.glsl +++ /dev/null @@ -1,18 +0,0 @@ -#version 450 - -layout(location = 0) in vec4 fragColor; -layout(location = 0) out vec4 outColor; - - -vec2 CorrectUv(vec2 uv) -{ -return vec2(uv.x, 1-uv.y); -} -vec2 xCorrectUv(vec2 uv) -{ -return uv; -} - -void main() { - outColor = fragColor; -} \ No newline at end of file diff --git a/examples/SpinningTriangle/fragment.spv b/examples/SpinningTriangle/fragment.spv deleted file mode 100644 index 5696c4a..0000000 Binary files a/examples/SpinningTriangle/fragment.spv and /dev/null differ diff --git a/examples/SpinningTriangle/vertex.glsl b/examples/SpinningTriangle/vertex.glsl deleted file mode 100644 index a829209..0000000 --- a/examples/SpinningTriangle/vertex.glsl +++ /dev/null @@ -1,16 +0,0 @@ -#version 450 - -layout(location = 0) in vec3 position; -layout(location = 1) in vec4 color; - -layout(location = 0) out vec4 fragColor; - -layout (binding =0) uniform MyMatrix -{ - mat4 Matrix; -}ubo; - -void main() { - gl_Position = ubo.Matrix * vec4(position.xyz, 1.0); - fragColor = color; -} \ No newline at end of file diff --git a/examples/SpinningTriangle/vertex.spv b/examples/SpinningTriangle/vertex.spv deleted file mode 100644 index 3c51e37..0000000 Binary files a/examples/SpinningTriangle/vertex.spv and /dev/null differ diff --git a/examples/TexturedQuad/CMakeLists.txt b/examples/TexturedQuad/CMakeLists.txt deleted file mode 100644 index 63897ef..0000000 --- a/examples/TexturedQuad/CMakeLists.txt +++ /dev/null @@ -1,18 +0,0 @@ -cmake_minimum_required(VERSION 3.26.4) -project(TexturedQuad CXX) - -add_executable(${PROJECT_NAME} -"TexturedQuad.cpp" -) - - -target_link_libraries(${PROJECT_NAME} PRIVATE FoxFury glfw) - -set_target_properties(${PROJECT_NAME} PROPERTIES - RUNTIME_OUTPUT_DIRECTORY "bin" -) - -#Set the debug working directory -set_target_properties(${PROJECT_NAME} PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}") - -include_directories(${LIB_INCLUDE_DIR}) \ No newline at end of file diff --git a/examples/TexturedQuad/TexturedQuad.cpp b/examples/TexturedQuad/TexturedQuad.cpp deleted file mode 100644 index e520473..0000000 --- a/examples/TexturedQuad/TexturedQuad.cpp +++ /dev/null @@ -1,345 +0,0 @@ -// Copyright RedFox Studio 2022 - -#include - -#include "IContext.h" -#include "backend/vulkan/VulkanContextFactory.h" - -#include - -#define GLFW_INCLUDE_NONE // makes the GLFW header not include any OpenGL or -// OpenGL ES API header.This is useful in combination with an extension loading library. -#include - -#define GLFW_EXPOSE_NATIVE_WIN32 -#include - -#include -#include -#include - -void -Log(const char* msg) -{ - std::cout << msg << std::endl; -}; - -constexpr uint32_t imageWidth = 32; -constexpr uint32_t imageHeight = 32; -// converter https://notisrac.github.io/FileToCArray/ -// clang-format off -constexpr uint8_t image[] = {0x41, 0x3c, 0x38, 0xff, 0x3a, 0x48, 0x48, 0xff, 0x3a, 0x3f, 0x45, 0xff, 0x40, 0x41, 0x39, 0xff, 0x42, 0x42, 0x44, 0xff, 0x3f, 0x3d, 0x40, 0xff, 0x3c, 0x41, 0x44, 0xff, 0x42, 0x41, 0x3f, 0xff, - 0x3b, 0x43, 0x46, 0xff, 0x47, 0x3e, 0x3f, 0xff, 0x45, 0x3c, 0x35, 0xff, 0x3b, 0x41, 0x3d, 0xff, 0x3c, 0x3f, 0x48, 0xff, 0x3b, 0x40, 0x43, 0xff, 0x44, 0x45, 0x3f, 0xff, 0x43, 0x3b, 0x38, 0xff, - 0x3d, 0x3f, 0x3e, 0xff, 0x43, 0x42, 0x3d, 0xff, 0x44, 0x3f, 0x43, 0xff, 0x3d, 0x43, 0x41, 0xff, 0x40, 0x3d, 0x44, 0xff, 0x40, 0x40, 0x36, 0xff, 0x44, 0x40, 0x3f, 0xff, 0x3c, 0x42, 0x42, 0xff, - 0x3d, 0x42, 0x3e, 0xff, 0x38, 0x42, 0x44, 0xff, 0x3f, 0x3e, 0x3c, 0xff, 0x3f, 0x40, 0x42, 0xff, 0x3d, 0x3e, 0x40, 0xff, 0x3e, 0x43, 0x46, 0xff, 0x3f, 0x3e, 0x3a, 0xff, 0x43, 0x40, 0x3b, 0xff, - 0x48, 0x43, 0x3f, 0xff, 0x32, 0x3e, 0x3e, 0xff, 0x60, 0x3c, 0x26, 0xff, 0x5a, 0x36, 0x14, 0xff, 0x5a, 0x36, 0x1e, 0xff, 0x5e, 0x36, 0x1d, 0xff, 0x5d, 0x3b, 0x20, 0xff, 0x5f, 0x37, 0x1d, 0xff, - 0x5c, 0x3a, 0x21, 0xff, 0x5e, 0x34, 0x1c, 0xff, 0x62, 0x37, 0x17, 0xff, 0x60, 0x3d, 0x1f, 0xff, 0x5d, 0x38, 0x25, 0xff, 0x5b, 0x38, 0x22, 0xff, 0x59, 0x35, 0x15, 0xff, 0x67, 0x3b, 0x20, 0xff, - 0x62, 0x3d, 0x22, 0xff, 0x5a, 0x35, 0x18, 0xff, 0x5c, 0x33, 0x1d, 0xff, 0x5c, 0x3a, 0x1f, 0xff, 0x5e, 0x35, 0x21, 0xff, 0x61, 0x3a, 0x19, 0xff, 0x59, 0x34, 0x1a, 0xff, 0x5e, 0x3c, 0x21, 0xff, - 0x5a, 0x35, 0x18, 0xff, 0x58, 0x3c, 0x26, 0xff, 0x61, 0x3a, 0x1d, 0xff, 0x5c, 0x38, 0x20, 0xff, 0x5f, 0x37, 0x1e, 0xff, 0x5c, 0x39, 0x23, 0xff, 0x40, 0x3e, 0x3f, 0xff, 0x43, 0x42, 0x3e, 0xff, - 0x45, 0x3d, 0x3a, 0xff, 0x3c, 0x46, 0x48, 0xff, 0xe3, 0x6e, 0x21, 0xff, 0xe4, 0x76, 0x1f, 0xff, 0xe2, 0x74, 0x27, 0xff, 0xe0, 0x71, 0x20, 0xff, 0xe1, 0x73, 0x1e, 0xff, 0xde, 0x6f, 0x20, 0xff, - 0xe4, 0x6f, 0x1f, 0xff, 0xe2, 0x72, 0x2a, 0xff, 0xe1, 0x71, 0x1f, 0xff, 0xe4, 0x6f, 0x1f, 0xff, 0xe2, 0x73, 0x21, 0xff, 0xe0, 0x70, 0x24, 0xff, 0xe0, 0x71, 0x1f, 0xff, 0xe0, 0x70, 0x24, 0xff, - 0xe3, 0x6f, 0x1c, 0xff, 0xe3, 0x74, 0x25, 0xff, 0xe2, 0x72, 0x28, 0xff, 0xe4, 0x73, 0x23, 0xff, 0xe2, 0x72, 0x28, 0xff, 0xdf, 0x6f, 0x1d, 0xff, 0xde, 0x72, 0x29, 0xff, 0xde, 0x70, 0x21, 0xff, - 0xe6, 0x72, 0x1f, 0xff, 0xde, 0x74, 0x28, 0xff, 0xe1, 0x6d, 0x18, 0xff, 0xe2, 0x74, 0x27, 0xff, 0xe7, 0x6e, 0x1f, 0xff, 0xdd, 0x6e, 0x26, 0xff, 0x40, 0x3e, 0x43, 0xff, 0x3d, 0x41, 0x42, 0xff, - 0x45, 0x3d, 0x3a, 0xff, 0x37, 0x3e, 0x44, 0xff, 0xff, 0x67, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xfb, 0x68, 0x01, 0xff, 0xfd, 0x69, 0x00, 0xff, 0xff, 0x6b, 0x00, 0xff, 0xff, 0x6a, 0x04, 0xff, - 0xff, 0x6a, 0x00, 0xff, 0xf9, 0x67, 0x04, 0xff, 0xff, 0x6d, 0x05, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfc, 0x68, 0x00, 0xff, 0xff, 0x6a, 0x04, 0xff, 0xfc, 0x68, 0x00, 0xff, 0xfe, 0x69, 0x03, 0xff, - 0xff, 0x69, 0x00, 0xff, 0xfe, 0x69, 0x02, 0xff, 0xfa, 0x68, 0x03, 0xff, 0xff, 0x67, 0x00, 0xff, 0xff, 0x6a, 0x03, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfe, 0x6c, 0x07, 0xff, 0xff, 0x6c, 0x02, 0xff, - 0xff, 0x64, 0x00, 0xff, 0xff, 0x6e, 0x09, 0xff, 0xff, 0x6a, 0x00, 0xff, 0xfd, 0x68, 0x01, 0xff, 0xff, 0x67, 0x00, 0xff, 0xff, 0x6a, 0x06, 0xff, 0x43, 0x40, 0x49, 0xff, 0x3c, 0x40, 0x43, 0xff, - 0x46, 0x41, 0x3b, 0xff, 0x3a, 0x43, 0x4a, 0xff, 0xff, 0x65, 0x00, 0xff, 0xfc, 0x69, 0x01, 0xff, 0xfd, 0x6a, 0x02, 0xff, 0xff, 0x6b, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfb, 0x67, 0x03, 0xff, - 0xfb, 0x66, 0x00, 0xff, 0xfd, 0x6b, 0x06, 0xff, 0xfa, 0x65, 0x00, 0xff, 0xff, 0x6b, 0x00, 0xff, 0xfd, 0x69, 0x05, 0xff, 0xfe, 0x6c, 0x05, 0xff, 0xff, 0x6c, 0x03, 0xff, 0xff, 0x69, 0x00, 0xff, - 0xff, 0x68, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfd, 0x6f, 0x0b, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xfb, 0x68, 0x00, 0xff, 0xfe, 0x6c, 0x00, 0xff, 0xfb, 0x67, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, - 0xff, 0x6a, 0x04, 0xff, 0xf9, 0x64, 0x00, 0xff, 0xff, 0x6d, 0x08, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfc, 0x68, 0x00, 0xff, 0xff, 0x6c, 0x00, 0xff, 0x3e, 0x3d, 0x42, 0xff, 0x40, 0x3e, 0x3f, 0xff, - 0x3d, 0x3c, 0x38, 0xff, 0x3f, 0x44, 0x4a, 0xff, 0xff, 0x67, 0x02, 0xff, 0xff, 0x6a, 0x03, 0xff, 0xff, 0x69, 0x01, 0xff, 0xfd, 0x6a, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xff, 0x6c, 0x08, 0xff, - 0xfc, 0x6a, 0x03, 0xff, 0xff, 0x6a, 0x01, 0xff, 0xf0, 0x6e, 0x18, 0xff, 0xf2, 0x73, 0x16, 0xff, 0xec, 0x6a, 0x16, 0xff, 0xfb, 0x6a, 0x01, 0xff, 0xf0, 0x6b, 0x0e, 0xff, 0xf3, 0x6d, 0x0e, 0xff, - 0xfd, 0x6a, 0x03, 0xff, 0xff, 0x67, 0x00, 0xff, 0xfd, 0x6b, 0x04, 0xff, 0xf0, 0x6e, 0x0e, 0xff, 0xff, 0x6b, 0x01, 0xff, 0xf0, 0x71, 0x14, 0xff, 0xff, 0x68, 0x00, 0xff, 0xf2, 0x6f, 0x14, 0xff, - 0xee, 0x6b, 0x11, 0xff, 0xe2, 0x70, 0x27, 0xff, 0xfa, 0x68, 0x03, 0xff, 0xff, 0x6b, 0x00, 0xff, 0xfe, 0x6b, 0x01, 0xff, 0xfb, 0x67, 0x00, 0xff, 0x41, 0x42, 0x46, 0xff, 0x45, 0x41, 0x40, 0xff, - 0x39, 0x42, 0x3f, 0xff, 0x44, 0x40, 0x3f, 0xff, 0xfa, 0x67, 0x00, 0xff, 0xfe, 0x65, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfc, 0x6c, 0x00, 0xff, 0xfc, 0x69, 0x01, 0xff, 0xfb, 0x6a, 0x01, 0xff, - 0xf8, 0x6b, 0x01, 0xff, 0xff, 0x66, 0x00, 0xff, 0x86, 0x31, 0x00, 0xff, 0x7e, 0x2b, 0x00, 0xff, 0x8a, 0x2c, 0x00, 0xff, 0xff, 0x6c, 0x02, 0xff, 0x8b, 0x2b, 0x00, 0xff, 0x8b, 0x2f, 0x00, 0xff, - 0xf7, 0x6b, 0x0a, 0xff, 0xff, 0x69, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0x8c, 0x30, 0x00, 0xff, 0xf9, 0x65, 0x00, 0xff, 0x86, 0x2f, 0x00, 0xff, 0xff, 0x65, 0x00, 0xff, 0x86, 0x29, 0x00, 0xff, - 0x86, 0x2d, 0x00, 0xff, 0x61, 0x3b, 0x26, 0xff, 0xff, 0x6b, 0x01, 0xff, 0xfa, 0x65, 0x00, 0xff, 0xff, 0x6f, 0x03, 0xff, 0xfb, 0x6b, 0x00, 0xff, 0x3a, 0x42, 0x45, 0xff, 0x3e, 0x3d, 0x38, 0xff, - 0x3b, 0x44, 0x43, 0xff, 0x44, 0x3f, 0x3c, 0xff, 0xfd, 0x6b, 0x04, 0xff, 0xff, 0x68, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xf9, 0x6b, 0x00, 0xff, 0xfd, 0x6b, 0x04, 0xff, 0xfc, 0x6a, 0x00, 0xff, - 0xf8, 0x6b, 0x01, 0xff, 0xff, 0x68, 0x00, 0xff, 0xcc, 0x74, 0x34, 0xff, 0xce, 0x79, 0x38, 0xff, 0xd6, 0x77, 0x37, 0xff, 0xfd, 0x66, 0x00, 0xff, 0xd4, 0x77, 0x2a, 0xff, 0xcf, 0x75, 0x39, 0xff, - 0xfb, 0x6c, 0x0c, 0xff, 0xff, 0x69, 0x00, 0xff, 0xff, 0x66, 0x00, 0xff, 0xd1, 0x76, 0x2f, 0xff, 0xff, 0x69, 0x02, 0xff, 0xcf, 0x78, 0x35, 0xff, 0xff, 0x67, 0x00, 0xff, 0xd1, 0x77, 0x3b, 0xff, - 0xd1, 0x75, 0x32, 0xff, 0x3f, 0x3e, 0x46, 0xff, 0xff, 0x68, 0x00, 0xff, 0xff, 0x6d, 0x05, 0xff, 0xfc, 0x64, 0x00, 0xff, 0xfe, 0x6c, 0x00, 0xff, 0x3b, 0x43, 0x46, 0xff, 0x42, 0x3f, 0x3a, 0xff, - 0x40, 0x41, 0x3c, 0xff, 0x3e, 0x40, 0x3b, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfc, 0x6b, 0x00, 0xff, 0xff, 0x6a, 0x03, 0xff, 0xfb, 0x6a, 0x01, 0xff, 0xfc, 0x6b, 0x02, 0xff, 0xff, 0x6a, 0x00, 0xff, - 0xfc, 0x6b, 0x00, 0xff, 0xff, 0x67, 0x00, 0xff, 0xef, 0x6e, 0x10, 0xff, 0xee, 0x6f, 0x0e, 0xff, 0xf2, 0x6d, 0x12, 0xff, 0xff, 0x68, 0x00, 0xff, 0xef, 0x6f, 0x0c, 0xff, 0xec, 0x6e, 0x1a, 0xff, - 0xff, 0x69, 0x02, 0xff, 0xff, 0x6a, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xeb, 0x70, 0x10, 0xff, 0xfd, 0x6a, 0x03, 0xff, 0xec, 0x70, 0x0e, 0xff, 0xff, 0x68, 0x00, 0xff, 0xee, 0x6e, 0x13, 0xff, - 0xf0, 0x6b, 0x0e, 0xff, 0x43, 0x43, 0x4b, 0xff, 0xf6, 0x68, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xff, 0x6d, 0x00, 0xff, 0xfc, 0x69, 0x00, 0xff, 0x3f, 0x3f, 0x47, 0xff, 0x42, 0x3f, 0x3a, 0xff, - 0x47, 0x42, 0x3f, 0xff, 0x3c, 0x42, 0x3e, 0xff, 0xff, 0x68, 0x00, 0xff, 0xf8, 0x6b, 0x01, 0xff, 0xfe, 0x69, 0x03, 0xff, 0xff, 0x6b, 0x05, 0xff, 0xfc, 0x6a, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, - 0xfc, 0x6b, 0x02, 0xff, 0xff, 0x67, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfd, 0x6b, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfd, 0x6b, 0x00, 0xff, 0xfc, 0x69, 0x09, 0xff, - 0xff, 0x68, 0x00, 0xff, 0xff, 0x6a, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xf7, 0x6d, 0x02, 0xff, 0xfd, 0x6a, 0x03, 0xff, 0xfd, 0x6b, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfd, 0x6a, 0x02, 0xff, - 0xff, 0x6c, 0x05, 0xff, 0x5c, 0x36, 0x21, 0xff, 0xfd, 0x6c, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xfd, 0x65, 0x00, 0xff, 0xfe, 0x6b, 0x04, 0xff, 0x40, 0x3d, 0x44, 0xff, 0x48, 0x43, 0x40, 0xff, - 0x44, 0x3e, 0x40, 0xff, 0x38, 0x43, 0x3f, 0xff, 0xff, 0x6a, 0x03, 0xff, 0xfa, 0x6c, 0x00, 0xff, 0xff, 0x69, 0x02, 0xff, 0xff, 0x68, 0x06, 0xff, 0xff, 0x6c, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, - 0xfa, 0x6b, 0x05, 0xff, 0xff, 0x69, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xf9, 0x6c, 0x02, 0xff, 0xff, 0x67, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfe, 0x69, 0x02, 0xff, - 0xfd, 0x6a, 0x02, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xf7, 0x6c, 0x03, 0xff, 0xfc, 0x6b, 0x02, 0xff, 0xff, 0x6a, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfd, 0x6b, 0x00, 0xff, - 0xf7, 0x69, 0x03, 0xff, 0xe8, 0x72, 0x1b, 0xff, 0xfe, 0x68, 0x00, 0xff, 0xff, 0x6a, 0x03, 0xff, 0xff, 0x6c, 0x07, 0xff, 0xfd, 0x6b, 0x08, 0xff, 0x40, 0x3e, 0x43, 0xff, 0x3f, 0x3e, 0x3c, 0xff, - 0x44, 0x3d, 0x44, 0xff, 0x37, 0x40, 0x3b, 0xff, 0xff, 0x6a, 0x09, 0xff, 0xfd, 0x6c, 0x00, 0xff, 0xff, 0x69, 0x02, 0xff, 0xf3, 0x68, 0x15, 0xff, 0xff, 0x6a, 0x00, 0xff, 0xfd, 0x68, 0x01, 0xff, - 0xfa, 0x6a, 0x07, 0xff, 0xff, 0x69, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfa, 0x6b, 0x03, 0xff, 0xff, 0x67, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfe, 0x69, 0x02, 0xff, - 0xfe, 0x69, 0x02, 0xff, 0xfe, 0x69, 0x02, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xf9, 0x6b, 0x05, 0xff, 0xfe, 0x69, 0x02, 0xff, 0xff, 0x69, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, - 0xf8, 0x6a, 0x04, 0xff, 0xff, 0x66, 0x00, 0xff, 0xff, 0x6b, 0x00, 0xff, 0xfb, 0x68, 0x01, 0xff, 0xfd, 0x68, 0x04, 0xff, 0xfb, 0x6c, 0x06, 0xff, 0x44, 0x3f, 0x43, 0xff, 0x40, 0x3e, 0x3f, 0xff, - 0x42, 0x3f, 0x46, 0xff, 0x3f, 0x40, 0x3a, 0xff, 0xfc, 0x68, 0x08, 0xff, 0xfc, 0x6a, 0x00, 0xff, 0xfc, 0x69, 0x01, 0xff, 0xd3, 0x73, 0x39, 0xff, 0xff, 0x71, 0x03, 0xff, 0xfc, 0x69, 0x02, 0xff, - 0xfa, 0x6b, 0x03, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfc, 0x6b, 0x00, 0xff, 0xfd, 0x6a, 0x02, 0xff, - 0xff, 0x68, 0x00, 0xff, 0xff, 0x69, 0x02, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfc, 0x6a, 0x07, 0xff, 0xff, 0x68, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfe, 0x69, 0x02, 0xff, - 0xff, 0x6e, 0x01, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfe, 0x69, 0x02, 0xff, 0xfe, 0x6c, 0x05, 0xff, 0xff, 0x6f, 0x04, 0xff, 0xfa, 0x69, 0x00, 0xff, 0x3f, 0x3e, 0x3c, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x40, 0x3f, 0x44, 0xff, 0x43, 0x42, 0x3e, 0xff, 0xfd, 0x69, 0x07, 0xff, 0xff, 0x6b, 0x00, 0xff, 0xff, 0x70, 0x06, 0xff, 0x65, 0x2d, 0x0c, 0xff, 0xf8, 0x69, 0x00, 0xff, 0xfc, 0x67, 0x01, 0xff, - 0xfd, 0x6a, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfd, 0x6b, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfc, 0x6b, 0x02, 0xff, 0xfe, 0x69, 0x02, 0xff, 0xfc, 0x6b, 0x00, 0xff, 0xfe, 0x69, 0x02, 0xff, - 0xff, 0x67, 0x00, 0xff, 0xff, 0x69, 0x02, 0xff, 0xff, 0x68, 0x02, 0xff, 0xfd, 0x69, 0x05, 0xff, 0xff, 0x67, 0x00, 0xff, 0xfe, 0x69, 0x02, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfd, 0x6a, 0x02, 0xff, - 0xfd, 0x66, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xfa, 0x67, 0x00, 0xff, 0xfd, 0x6c, 0x03, 0xff, 0xfb, 0x69, 0x00, 0xff, 0xff, 0x6e, 0x00, 0xff, 0x40, 0x40, 0x40, 0xff, 0x40, 0x40, 0x42, 0xff, - 0x3e, 0x3d, 0x3b, 0xff, 0x41, 0x41, 0x43, 0xff, 0xfe, 0x6b, 0x03, 0xff, 0xfe, 0x68, 0x00, 0xff, 0xfc, 0x64, 0x00, 0xff, 0x52, 0x46, 0x38, 0xff, 0xfc, 0x69, 0x00, 0xff, 0xff, 0x6b, 0x00, 0xff, - 0xfd, 0x6b, 0x00, 0xff, 0xff, 0x68, 0x02, 0xff, 0xfc, 0x6b, 0x02, 0xff, 0xfe, 0x6b, 0x00, 0xff, 0xfa, 0x6a, 0x09, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, - 0xfd, 0x6a, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xfd, 0x69, 0x07, 0xff, 0xfc, 0x6b, 0x00, 0xff, 0xff, 0x67, 0x00, 0xff, 0xfc, 0x6b, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfc, 0x6b, 0x00, 0xff, - 0xff, 0x6a, 0x02, 0xff, 0xfd, 0x6b, 0x06, 0xff, 0xff, 0x6c, 0x02, 0xff, 0xff, 0x68, 0x00, 0xff, 0xff, 0x6d, 0x00, 0xff, 0xfa, 0x66, 0x00, 0xff, 0x3e, 0x42, 0x45, 0xff, 0x3f, 0x40, 0x3a, 0xff, - 0x42, 0x41, 0x3c, 0xff, 0x41, 0x40, 0x46, 0xff, 0xfd, 0x69, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xff, 0x6b, 0x00, 0xff, 0x39, 0x3f, 0x3d, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, - 0xfe, 0x6a, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfd, 0x6a, 0x03, 0xff, 0xfd, 0x6b, 0x00, 0xff, 0xfa, 0x6a, 0x0a, 0xff, 0xff, 0x69, 0x00, 0xff, 0xff, 0x6a, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, - 0xfd, 0x6a, 0x00, 0xff, 0xfd, 0x6b, 0x00, 0xff, 0xfc, 0x6a, 0x07, 0xff, 0xfc, 0x6c, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfa, 0x6c, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfd, 0x6b, 0x00, 0xff, - 0xff, 0x68, 0x00, 0xff, 0xfb, 0x69, 0x06, 0xff, 0xfe, 0x6b, 0x01, 0xff, 0xff, 0x6b, 0x00, 0xff, 0xff, 0x64, 0x00, 0xff, 0xfe, 0x6c, 0x00, 0xff, 0x40, 0x41, 0x43, 0xff, 0x41, 0x41, 0x3f, 0xff, - 0x42, 0x3e, 0x3b, 0xff, 0x41, 0x41, 0x43, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfd, 0x68, 0x01, 0xff, 0xfd, 0x6b, 0x00, 0xff, 0x39, 0x3f, 0x3d, 0xff, 0xfe, 0x6e, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, - 0xfc, 0x6b, 0x02, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfd, 0x6a, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xf7, 0x6c, 0x07, 0xff, 0xff, 0x6a, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xfd, 0x6b, 0x00, 0xff, - 0xfd, 0x6b, 0x00, 0xff, 0xf9, 0x6c, 0x02, 0xff, 0xfd, 0x6a, 0x00, 0xff, 0xfd, 0x6b, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xf9, 0x6c, 0x02, 0xff, 0xff, 0x6a, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, - 0xff, 0x68, 0x00, 0xff, 0xfc, 0x6a, 0x03, 0xff, 0xfc, 0x69, 0x00, 0xff, 0xfc, 0x6b, 0x02, 0xff, 0xff, 0x6b, 0x00, 0xff, 0xf7, 0x6b, 0x00, 0xff, 0x45, 0x40, 0x3a, 0xff, 0x3c, 0x3d, 0x42, 0xff, - 0x40, 0x40, 0x3e, 0xff, 0x43, 0x42, 0x47, 0xff, 0xff, 0x67, 0x00, 0xff, 0xfe, 0x69, 0x03, 0xff, 0xfe, 0x6b, 0x03, 0xff, 0x5f, 0x3d, 0x21, 0xff, 0xfa, 0x6a, 0x00, 0xff, 0xff, 0x6b, 0x04, 0xff, - 0xfc, 0x6a, 0x03, 0xff, 0xff, 0x68, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xf9, 0x6b, 0x05, 0xff, 0xff, 0x69, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfd, 0x6a, 0x02, 0xff, - 0xff, 0x69, 0x00, 0xff, 0xfa, 0x6b, 0x05, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfa, 0x6b, 0x03, 0xff, 0xfd, 0x6a, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, - 0xff, 0x6b, 0x00, 0xff, 0xec, 0x6b, 0x10, 0xff, 0xff, 0x6b, 0x01, 0xff, 0xfe, 0x6b, 0x04, 0xff, 0xff, 0x65, 0x00, 0xff, 0xf8, 0x6e, 0x03, 0xff, 0x49, 0x42, 0x3c, 0xff, 0x43, 0x41, 0x4c, 0xff, - 0x39, 0x3f, 0x3f, 0xff, 0x3e, 0x41, 0x46, 0xff, 0xff, 0x6b, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xff, 0x6b, 0x00, 0xff, 0xdd, 0x6e, 0x1d, 0xff, 0xfe, 0x6c, 0x00, 0xff, 0xfe, 0x66, 0x01, 0xff, - 0xfd, 0x6a, 0x02, 0xff, 0xff, 0x68, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xff, 0x69, 0x02, 0xff, 0xfc, 0x6a, 0x07, 0xff, 0xff, 0x67, 0x00, 0xff, 0xff, 0x69, 0x02, 0xff, 0xfd, 0x69, 0x05, 0xff, - 0xff, 0x67, 0x00, 0xff, 0xfe, 0x69, 0x05, 0xff, 0xff, 0x68, 0x03, 0xff, 0xff, 0x68, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfa, 0x6b, 0x05, 0xff, 0xfc, 0x6a, 0x03, 0xff, 0xff, 0x68, 0x00, 0xff, - 0xf9, 0x68, 0x00, 0xff, 0x91, 0x32, 0x00, 0xff, 0xfc, 0x68, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xff, 0x6a, 0x05, 0xff, 0xf7, 0x68, 0x00, 0xff, 0x42, 0x3e, 0x3b, 0xff, 0x42, 0x3d, 0x43, 0xff, - 0x40, 0x45, 0x49, 0xff, 0x3f, 0x40, 0x45, 0xff, 0xff, 0x69, 0x00, 0xff, 0xff, 0x6b, 0x00, 0xff, 0xfd, 0x66, 0x00, 0xff, 0xe3, 0x72, 0x22, 0xff, 0xfe, 0x68, 0x00, 0xff, 0xff, 0x6b, 0x07, 0xff, - 0xfd, 0x6a, 0x02, 0xff, 0xff, 0x69, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfe, 0x69, 0x03, 0xff, 0xfd, 0x69, 0x05, 0xff, 0xff, 0x67, 0x00, 0xff, 0xff, 0x68, 0x02, 0xff, 0xfe, 0x68, 0x07, 0xff, - 0xff, 0x67, 0x00, 0xff, 0xff, 0x67, 0x03, 0xff, 0xff, 0x68, 0x05, 0xff, 0xff, 0x67, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xfd, 0x6a, 0x03, 0xff, 0xfa, 0x6b, 0x05, 0xff, 0xff, 0x69, 0x00, 0xff, - 0xfb, 0x6a, 0x00, 0xff, 0xb6, 0x7a, 0x56, 0xff, 0xff, 0x6d, 0x02, 0xff, 0xff, 0x66, 0x00, 0xff, 0xff, 0x67, 0x06, 0xff, 0xfc, 0x69, 0x02, 0xff, 0x43, 0x43, 0x43, 0xff, 0x41, 0x3c, 0x40, 0xff, - 0x3b, 0x39, 0x44, 0xff, 0x40, 0x3f, 0x3d, 0xff, 0xff, 0x68, 0x00, 0xff, 0xff, 0x69, 0x02, 0xff, 0xff, 0x6c, 0x08, 0xff, 0x5c, 0x37, 0x1d, 0xff, 0xff, 0x6a, 0x00, 0xff, 0xf9, 0x6a, 0x02, 0xff, - 0xfc, 0x6b, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xff, 0x6a, 0x00, 0xff, 0xfd, 0x6a, 0x02, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfd, 0x69, 0x05, 0xff, - 0xfe, 0x6a, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xfd, 0x6a, 0x03, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfd, 0x6a, 0x02, 0xff, 0xfd, 0x6a, 0x00, 0xff, 0xfa, 0x6b, 0x03, 0xff, 0xff, 0x69, 0x00, 0xff, - 0xff, 0x6c, 0x00, 0xff, 0x4c, 0x38, 0x31, 0xff, 0xfd, 0x65, 0x00, 0xff, 0xff, 0x68, 0x01, 0xff, 0xff, 0x67, 0x07, 0xff, 0xfe, 0x6b, 0x01, 0xff, 0x39, 0x3f, 0x3f, 0xff, 0x3d, 0x41, 0x40, 0xff, - 0x44, 0x41, 0x4a, 0xff, 0x43, 0x3f, 0x40, 0xff, 0xfc, 0x69, 0x01, 0xff, 0xff, 0x6b, 0x06, 0xff, 0xfe, 0x68, 0x07, 0xff, 0x53, 0x3c, 0x34, 0xff, 0xff, 0x66, 0x00, 0xff, 0xf8, 0x69, 0x01, 0xff, - 0xfc, 0x6b, 0x00, 0xff, 0xfd, 0x6b, 0x00, 0xff, 0xff, 0x6a, 0x00, 0xff, 0xfc, 0x6b, 0x02, 0xff, 0xff, 0x6a, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfd, 0x6a, 0x02, 0xff, - 0xfd, 0x6b, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xfd, 0x6a, 0x03, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfd, 0x6a, 0x02, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfc, 0x6a, 0x03, 0xff, 0xff, 0x69, 0x00, 0xff, - 0xfd, 0x67, 0x00, 0xff, 0x43, 0x40, 0x47, 0xff, 0xff, 0x6f, 0x01, 0xff, 0xff, 0x68, 0x00, 0xff, 0xff, 0x67, 0x05, 0xff, 0xfd, 0x68, 0x01, 0xff, 0x40, 0x44, 0x43, 0xff, 0x3f, 0x43, 0x42, 0xff, - 0x3d, 0x3d, 0x3f, 0xff, 0x43, 0x41, 0x46, 0xff, 0xfb, 0x6e, 0x02, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfc, 0x65, 0x00, 0xff, 0x72, 0x36, 0x12, 0xff, 0xff, 0x69, 0x00, 0xff, 0xff, 0x6c, 0x08, 0xff, - 0xfd, 0x6a, 0x02, 0xff, 0xfd, 0x6a, 0x02, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfd, 0x6a, 0x02, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfd, 0x6b, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, - 0xfc, 0x6c, 0x00, 0xff, 0xfe, 0x6b, 0x00, 0xff, 0xfd, 0x6a, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfd, 0x6a, 0x02, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfd, 0x6a, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, - 0xff, 0x69, 0x00, 0xff, 0x41, 0x3f, 0x42, 0xff, 0xf7, 0x6a, 0x00, 0xff, 0xfb, 0x6a, 0x00, 0xff, 0xff, 0x68, 0x03, 0xff, 0xfc, 0x6b, 0x02, 0xff, 0x44, 0x3f, 0x39, 0xff, 0x3f, 0x3e, 0x3c, 0xff, - 0x41, 0x42, 0x3d, 0xff, 0x3f, 0x40, 0x44, 0xff, 0xf6, 0x6c, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xb5, 0x7b, 0x56, 0xff, 0xfd, 0x6b, 0x00, 0xff, 0xff, 0x68, 0x03, 0xff, - 0xfe, 0x69, 0x02, 0xff, 0xfe, 0x69, 0x03, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfc, 0x6b, 0x00, 0xff, 0xff, 0x6a, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, - 0xfc, 0x6b, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfe, 0x69, 0x02, 0xff, 0xff, 0x69, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, - 0xff, 0x6b, 0x00, 0xff, 0x50, 0x3c, 0x31, 0xff, 0xf8, 0x6c, 0x00, 0xff, 0xfc, 0x6e, 0x02, 0xff, 0xff, 0x65, 0x00, 0xff, 0xfd, 0x6c, 0x03, 0xff, 0x43, 0x3e, 0x3a, 0xff, 0x44, 0x40, 0x3f, 0xff, - 0x43, 0x3f, 0x34, 0xff, 0x3e, 0x43, 0x3d, 0xff, 0xf8, 0x6d, 0x04, 0xff, 0xff, 0x6a, 0x00, 0xff, 0xff, 0x6b, 0x00, 0xff, 0x4d, 0x3d, 0x2e, 0xff, 0xfb, 0x67, 0x00, 0xff, 0xff, 0x6d, 0x03, 0xff, - 0xff, 0x68, 0x00, 0xff, 0xff, 0x6b, 0x04, 0xff, 0xfc, 0x67, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xff, 0x6a, 0x00, 0xff, 0xf9, 0x6b, 0x05, 0xff, 0xfb, 0x68, 0x00, 0xff, 0xfe, 0x6d, 0x02, 0xff, - 0xfc, 0x69, 0x00, 0xff, 0xff, 0x6a, 0x00, 0xff, 0xff, 0x69, 0x01, 0xff, 0xf9, 0x67, 0x04, 0xff, 0xfd, 0x6b, 0x04, 0xff, 0xfd, 0x69, 0x00, 0xff, 0xff, 0x6c, 0x00, 0xff, 0xff, 0x6b, 0x00, 0xff, - 0xff, 0x69, 0x00, 0xff, 0x6e, 0x34, 0x0f, 0xff, 0xf7, 0x6d, 0x00, 0xff, 0xfc, 0x6e, 0x02, 0xff, 0xff, 0x66, 0x00, 0xff, 0xfe, 0x6b, 0x01, 0xff, 0x39, 0x3f, 0x3d, 0xff, 0x41, 0x42, 0x3d, 0xff, - 0x45, 0x41, 0x38, 0xff, 0x3a, 0x3f, 0x3b, 0xff, 0xfa, 0x6b, 0x03, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfd, 0x67, 0x00, 0xff, 0x50, 0x43, 0x32, 0xff, 0xed, 0x6e, 0x11, 0xff, 0xfd, 0x66, 0x00, 0xff, - 0xf5, 0x6e, 0x12, 0xff, 0xed, 0x6b, 0x13, 0xff, 0xff, 0x6a, 0x03, 0xff, 0xf3, 0x6e, 0x11, 0xff, 0xfa, 0x66, 0x00, 0xff, 0xfe, 0x6c, 0x05, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xfd, 0x6a, 0x02, 0xff, - 0xfd, 0x69, 0x00, 0xff, 0xfc, 0x6a, 0x03, 0xff, 0xff, 0x67, 0x01, 0xff, 0xfd, 0x69, 0x07, 0xff, 0xff, 0x6d, 0x06, 0xff, 0xf3, 0x6e, 0x0f, 0xff, 0xef, 0x6d, 0x0b, 0xff, 0xee, 0x6d, 0x0f, 0xff, - 0xf3, 0x70, 0x18, 0xff, 0xd1, 0x73, 0x35, 0xff, 0xf9, 0x6d, 0x00, 0xff, 0xfa, 0x6b, 0x03, 0xff, 0xff, 0x63, 0x00, 0xff, 0xff, 0x6e, 0x02, 0xff, 0x3d, 0x43, 0x43, 0xff, 0x41, 0x41, 0x41, 0xff, - 0x3f, 0x41, 0x3e, 0xff, 0x40, 0x41, 0x46, 0xff, 0xfb, 0x68, 0x00, 0xff, 0xff, 0x68, 0x02, 0xff, 0xfc, 0x6e, 0x02, 0xff, 0x67, 0x31, 0x05, 0xff, 0x85, 0x31, 0x00, 0xff, 0xff, 0x6c, 0x03, 0xff, - 0x89, 0x2b, 0x00, 0xff, 0x88, 0x2f, 0x00, 0xff, 0xf9, 0x65, 0x00, 0xff, 0x88, 0x2e, 0x00, 0xff, 0xf9, 0x70, 0x10, 0xff, 0xff, 0x69, 0x00, 0xff, 0xff, 0x67, 0x00, 0xff, 0xfa, 0x67, 0x00, 0xff, - 0xff, 0x6a, 0x00, 0xff, 0xf6, 0x6d, 0x0d, 0xff, 0xfc, 0x6a, 0x05, 0xff, 0xff, 0x6b, 0x00, 0xff, 0xf9, 0x66, 0x00, 0xff, 0x89, 0x24, 0x00, 0xff, 0x8c, 0x34, 0x00, 0xff, 0x86, 0x2a, 0x00, 0xff, - 0x85, 0x27, 0x00, 0xff, 0xf4, 0x73, 0x15, 0xff, 0xfe, 0x6c, 0x00, 0xff, 0xfd, 0x6b, 0x06, 0xff, 0xff, 0x69, 0x09, 0xff, 0xfe, 0x63, 0x00, 0xff, 0x45, 0x44, 0x42, 0xff, 0x3a, 0x3d, 0x42, 0xff, - 0x3d, 0x3f, 0x3e, 0xff, 0x40, 0x40, 0x4a, 0xff, 0xff, 0x6d, 0x00, 0xff, 0xff, 0x67, 0x03, 0xff, 0xf8, 0x69, 0x01, 0xff, 0xd3, 0x76, 0x30, 0xff, 0xcf, 0x7b, 0x35, 0xff, 0xfd, 0x64, 0x00, 0xff, - 0xd6, 0x77, 0x33, 0xff, 0xc9, 0x73, 0x38, 0xff, 0xff, 0x6b, 0x00, 0xff, 0xce, 0x74, 0x38, 0xff, 0xf5, 0x6c, 0x0c, 0xff, 0xff, 0x66, 0x00, 0xff, 0xff, 0x6a, 0x00, 0xff, 0xff, 0x6a, 0x03, 0xff, - 0xff, 0x6b, 0x00, 0xff, 0xf4, 0x6b, 0x0b, 0xff, 0xfb, 0x69, 0x04, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfd, 0x69, 0x00, 0xff, 0xe2, 0x7c, 0x34, 0xff, 0xca, 0x71, 0x35, 0xff, 0xd3, 0x75, 0x37, 0xff, - 0xd5, 0x79, 0x38, 0xff, 0xfc, 0x68, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfd, 0x6b, 0x08, 0xff, 0xff, 0x69, 0x0b, 0xff, 0xff, 0x67, 0x00, 0xff, 0x41, 0x40, 0x3e, 0xff, 0x41, 0x40, 0x46, 0xff, - 0x42, 0x41, 0x3f, 0xff, 0x39, 0x40, 0x46, 0xff, 0xff, 0x6b, 0x00, 0xff, 0xfe, 0x65, 0x00, 0xff, 0xff, 0x6b, 0x04, 0xff, 0xef, 0x6d, 0x0b, 0xff, 0xf1, 0x6e, 0x13, 0xff, 0xff, 0x6b, 0x07, 0xff, - 0xee, 0x6e, 0x0d, 0xff, 0xea, 0x71, 0x18, 0xff, 0xff, 0x6b, 0x00, 0xff, 0xef, 0x6f, 0x14, 0xff, 0xff, 0x6b, 0x04, 0xff, 0xff, 0x68, 0x00, 0xff, 0xff, 0x66, 0x00, 0xff, 0xfd, 0x66, 0x00, 0xff, - 0xfd, 0x69, 0x00, 0xff, 0xf9, 0x6a, 0x01, 0xff, 0xff, 0x6a, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xf2, 0x6d, 0x10, 0xff, 0xed, 0x6b, 0x13, 0xff, 0xf4, 0x6e, 0x17, 0xff, - 0xf0, 0x6f, 0x13, 0xff, 0xff, 0x69, 0x00, 0xff, 0xff, 0x6c, 0x00, 0xff, 0xfc, 0x6d, 0x07, 0xff, 0xfd, 0x65, 0x02, 0xff, 0xff, 0x6b, 0x00, 0xff, 0x3d, 0x41, 0x40, 0xff, 0x43, 0x3f, 0x3e, 0xff, - 0x41, 0x40, 0x3e, 0xff, 0x39, 0x41, 0x43, 0xff, 0xe5, 0x6e, 0x1a, 0xff, 0xe3, 0x72, 0x24, 0xff, 0xe1, 0x70, 0x24, 0xff, 0xe4, 0x76, 0x21, 0xff, 0xde, 0x6d, 0x1f, 0xff, 0xe2, 0x6e, 0x23, 0xff, - 0xe2, 0x73, 0x22, 0xff, 0xda, 0x70, 0x24, 0xff, 0xe4, 0x6e, 0x17, 0xff, 0xe3, 0x74, 0x25, 0xff, 0xe4, 0x6f, 0x1f, 0xff, 0xe5, 0x6e, 0x1e, 0xff, 0xe3, 0x73, 0x29, 0xff, 0xe4, 0x73, 0x25, 0xff, - 0xde, 0x71, 0x1f, 0xff, 0xe4, 0x73, 0x23, 0xff, 0xe5, 0x72, 0x22, 0xff, 0xe3, 0x70, 0x1f, 0xff, 0xe3, 0x72, 0x22, 0xff, 0xe1, 0x72, 0x23, 0xff, 0xe2, 0x71, 0x23, 0xff, 0xe1, 0x6d, 0x22, 0xff, - 0xe0, 0x71, 0x22, 0xff, 0xe5, 0x72, 0x21, 0xff, 0xe2, 0x72, 0x20, 0xff, 0xd9, 0x6e, 0x20, 0xff, 0xe7, 0x73, 0x26, 0xff, 0xe3, 0x75, 0x1e, 0xff, 0x39, 0x42, 0x41, 0xff, 0x46, 0x40, 0x40, 0xff, - 0x3f, 0x3f, 0x3d, 0xff, 0x3e, 0x42, 0x41, 0xff, 0x5c, 0x38, 0x18, 0xff, 0x5d, 0x39, 0x23, 0xff, 0x60, 0x38, 0x1f, 0xff, 0x5e, 0x39, 0x1c, 0xff, 0x57, 0x39, 0x1d, 0xff, 0x5f, 0x3a, 0x1d, 0xff, - 0x5f, 0x3c, 0x20, 0xff, 0x58, 0x38, 0x21, 0xff, 0x60, 0x37, 0x19, 0xff, 0x5e, 0x39, 0x1c, 0xff, 0x5d, 0x38, 0x1b, 0xff, 0x5b, 0x34, 0x15, 0xff, 0x5c, 0x3e, 0x26, 0xff, 0x5a, 0x36, 0x1c, 0xff, - 0x5d, 0x39, 0x21, 0xff, 0x60, 0x39, 0x1c, 0xff, 0x5c, 0x38, 0x1e, 0xff, 0x5c, 0x35, 0x18, 0xff, 0x58, 0x38, 0x1f, 0xff, 0x5e, 0x3a, 0x1a, 0xff, 0x5c, 0x39, 0x1d, 0xff, 0x61, 0x39, 0x1f, 0xff, - 0x5d, 0x39, 0x1f, 0xff, 0x5f, 0x37, 0x1e, 0xff, 0x59, 0x3a, 0x1e, 0xff, 0x5f, 0x3a, 0x1d, 0xff, 0x60, 0x39, 0x1c, 0xff, 0x5b, 0x3a, 0x19, 0xff, 0x3a, 0x40, 0x3c, 0xff, 0x40, 0x3b, 0x3f, 0xff, - 0x3e, 0x40, 0x3f, 0xff, 0x3e, 0x40, 0x3d, 0xff, 0x41, 0x43, 0x3e, 0xff, 0x3d, 0x40, 0x45, 0xff, 0x3f, 0x3d, 0x40, 0xff, 0x3f, 0x3f, 0x3d, 0xff, 0x3c, 0x46, 0x45, 0xff, 0x3f, 0x40, 0x3b, 0xff, - 0x3d, 0x3d, 0x3d, 0xff, 0x40, 0x44, 0x47, 0xff, 0x42, 0x3e, 0x3b, 0xff, 0x40, 0x3f, 0x3b, 0xff, 0x40, 0x40, 0x3e, 0xff, 0x42, 0x41, 0x3d, 0xff, 0x38, 0x42, 0x44, 0xff, 0x3d, 0x41, 0x40, 0xff, - 0x40, 0x41, 0x45, 0xff, 0x43, 0x3f, 0x3e, 0xff, 0x3e, 0x3f, 0x43, 0xff, 0x41, 0x40, 0x3c, 0xff, 0x3b, 0x43, 0x45, 0xff, 0x3f, 0x40, 0x3a, 0xff, 0x3d, 0x3f, 0x3c, 0xff, 0x42, 0x41, 0x3f, 0xff, - 0x3f, 0x3f, 0x41, 0xff, 0x41, 0x3f, 0x42, 0xff, 0x3b, 0x43, 0x45, 0xff, 0x3f, 0x3e, 0x39, 0xff, 0x42, 0x3f, 0x3a, 0xff, 0x3d, 0x43, 0x3f, 0xff, 0x3d, 0x43, 0x3f, 0xff, 0x42, 0x3f, 0x46, 0xff}; - -// clang-format on - -inline std::vector -ReadBlobUnsafe(const std::string& filename) -{ - std::ifstream file(filename, std::ios::binary | std::ios::ate); - - if (!file.is_open()) - return {}; - - std::ifstream::pos_type pos = file.tellg(); - - // What happens if the OS supports really big files. - // It may be larger than 32 bits? - // This will silently truncate the value/ - std::streamoff length = pos; - - std::vector bytes(length); - if (pos > 0) - { // Manuall memory management. - // Not a good idea use a container/. - file.seekg(0, std::ios::beg); - file.read((char*)bytes.data(), length); - } - file.close(); - return bytes; -}; - -int -main() -{ - - Fox::DContextConfig config; - config.logOutputFunction = &Log; - config.warningFunction = &Log; - - Fox::IContext* context = Fox::CreateVulkanContext(&config); - - { - if (!glfwInit()) - { - throw std::runtime_error("Failed to glfwInit"); - } - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); // as Vulkan, there is no need to create a context - GLFWwindow* window = glfwCreateWindow(640, 480, "My Title", NULL, NULL); - if (!window) - { - throw std::runtime_error("Failed to glfwCreateWindow"); - } - Fox::WindowData windowData; - windowData._hwnd = glfwGetWin32Window(window); - windowData._instance = GetModuleHandle(NULL); - - Fox::SwapchainId swapchain; - auto presentMode = Fox::EPresentMode::IMMEDIATE_KHR; - auto format = Fox::EFormat::B8G8R8A8_UNORM; - swapchain = context->CreateSwapchain(&windowData, presentMode, format); - if (swapchain == NULL) - { - throw std::runtime_error("Failed to CreateSwapchain"); - } - - // Create vertex layout - Fox::VertexLayoutInfo position("SV_POSITION", Fox::EFormat::R32G32B32_FLOAT, 0, Fox::EVertexInputClassification::PER_VERTEX_DATA); - Fox::VertexLayoutInfo color("Color0", Fox::EFormat::R32G32B32A32_FLOAT, 3 * sizeof(float), Fox::EVertexInputClassification::PER_VERTEX_DATA); - Fox::VertexInputLayoutId vertexLayout = context->CreateVertexLayout({ position, color }); - constexpr uint32_t stride = 7 * sizeof(float); - - Fox::ShaderSource shaderSource; - shaderSource.VertexLayout = vertexLayout; - shaderSource.VertexStride = stride; - shaderSource.SourceCode.VertexShader = ReadBlobUnsafe("vertex.spv"); - shaderSource.SourceCode.PixelShader = ReadBlobUnsafe("fragment.spv"); - - shaderSource.SetsLayout.SetsLayout[0].insert({ 0, Fox::ShaderDescriptorBindings("MatrixUbo", Fox::EBindingType::UNIFORM_BUFFER_OBJECT, sizeof(float) * 16, 1, Fox::EShaderStage::VERTEX) }); - shaderSource.SetsLayout.SetsLayout[1].insert({ 0, Fox::ShaderDescriptorBindings("MyTexture", Fox::EBindingType::SAMPLER, 1, 1, Fox::EShaderStage::FRAGMENT) }); - - shaderSource.ColorAttachments = 1; - shaderSource.DepthStencilAttachment = false; - - Fox::ShaderId shader = context->CreateShader(shaderSource); - - // clang-format off - constexpr std::array ndcQuad{ - -1, -1, 0.5,//pos - 0, 1, 0, 1,// color - 1, -1, 0.5,//pos - 0, 0, 1, 1,// color - 1, 1, 0.5,//pos - 0, 1, 1, 1,// color - //----------------// - -1, -1, 0.5,//pos - 0, 1, 0, 1,// color - 1, 1, 0.5,//pos - 0, 0, 1, 1,// color - -1, 1, 0.5,//pos - 0, 1, 1, 1// color - }; - // clang-format on - constexpr size_t bufSize = sizeof(float) * ndcQuad.size(); - Fox::BufferId quad = context->CreateVertexBuffer(bufSize); - - Fox::CopyDataCommand copy; - copy.CopyVertex(quad, 0, (void*)ndcQuad.data(), bufSize); - context->SubmitCopy(std::move(copy)); - - Fox::FramebufferId swapchainFbo = context->CreateSwapchainFramebuffer_DEPRECATED(swapchain); - - Fox::DRenderPassAttachment colorAttachment(format, - Fox::ESampleBit::COUNT_1_BIT, - Fox::ERenderPassLoad::Clear, - Fox::ERenderPassStore::Store, - Fox::ERenderPassLayout::Undefined, - Fox::ERenderPassLayout::Present, - Fox::EAttachmentReference::COLOR_ATTACHMENT); - Fox::DRenderPassAttachments renderPass; - renderPass.Attachments.push_back(colorAttachment); - - Fox::BufferId transformUniformBuffer = context->CreateUniformBuffer(sizeof(float) * 16); - float yaw{ 0 }; - - Fox::ImageId texture = context->CreateImage(Fox::EFormat::R8G8B8A8_UNORM, imageWidth, imageHeight, 1); - { - Fox::CopyDataCommand copy; - copy.CopyImageMipMap(texture, 0, (void*)image, imageWidth, imageHeight, 0, sizeof(image)); - context->SubmitCopy(std::move(copy)); - } - - bool wireFrame{}; - while (!glfwWindowShouldClose(window)) - { - // Keep running - glfwPollEvents(); - - if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS) - { - wireFrame = !wireFrame; - } - - int w, h; - glfwGetWindowSize(window, &w, &h); - Fox::DViewport viewport{ 0, 0, w, h, 0.f, 1.f }; - - { - // yaw += 0.01f; - const float sinA = std::sin(yaw); - const float cosA = std::cos(yaw); - - float matrix[4][4]{ { cosA, 0, -sinA, 0 }, { 0, 1, 0, 0 }, { sinA, 0, cosA, 0 }, { 0, 0, 0, 1 } }; - Fox::CopyDataCommand copy; - copy.CopyUniformBuffer(transformUniformBuffer, &matrix[0][0], sizeof(float) * 16); - context->SubmitCopy(std::move(copy)); - } - - Fox::RenderPassData draw(swapchainFbo, viewport, renderPass); - draw.ClearColor(1, 0, 0, 1); - - Fox::DrawCommand drawTriangle(shader); - drawTriangle.PipelineFormat.FillMode = wireFrame ? Fox::EFillMode::LINE : Fox::EFillMode::FILL; - drawTriangle.BindBufferUniformBuffer(0, 0, transformUniformBuffer); - drawTriangle.BindImageArray(1, 0, { texture }); - drawTriangle.Draw(quad, 0, 6); - - draw.AddDrawCommand(std::move(drawTriangle)); - - context->SubmitPass(std::move(draw)); - - context->AdvanceFrame(); - } - - context->DestroyShader(shader); - context->DestroyImage(texture); - context->DestroyBuffer(quad); - context->DestroyBuffer(transformUniformBuffer); - context->_destroyFramebuffer(swapchainFbo); - context->DestroySwapchain(swapchain); - - glfwDestroyWindow(window); - - glfwTerminate(); - } - - delete context; - - return 0; -} \ No newline at end of file diff --git a/examples/TexturedQuad/buildShaders.bat b/examples/TexturedQuad/buildShaders.bat deleted file mode 100644 index 890d4a2..0000000 --- a/examples/TexturedQuad/buildShaders.bat +++ /dev/null @@ -1,3 +0,0 @@ -C:\VulkanSDK\1.3.261.1\Bin\glslc.exe -fshader-stage=vert vertex.glsl -o vertex.spv -C:\VulkanSDK\1.3.261.1\Bin\glslc.exe -fshader-stage=frag fragment.glsl -o fragment.spv -pause \ No newline at end of file diff --git a/examples/TexturedQuad/fragment.glsl b/examples/TexturedQuad/fragment.glsl deleted file mode 100644 index 4dc4738..0000000 --- a/examples/TexturedQuad/fragment.glsl +++ /dev/null @@ -1,20 +0,0 @@ -#version 450 - -layout(location = 0) in vec2 pos; -layout(location = 0) out vec4 outColor; - -layout(set =1, binding = 0) uniform sampler2D MyTexture; - -vec2 CorrectUv(vec2 uv) -{ -return vec2(uv.x, 1-uv.y); -} -vec2 xCorrectUv(vec2 uv) -{ -return uv; -} - -void main() { - vec4 texColor = texture(MyTexture, pos); - outColor = texColor; -} \ No newline at end of file diff --git a/examples/TexturedQuad/fragment.spv b/examples/TexturedQuad/fragment.spv deleted file mode 100644 index e2bcebc..0000000 Binary files a/examples/TexturedQuad/fragment.spv and /dev/null differ diff --git a/examples/TexturedQuad/screenshot.jpg b/examples/TexturedQuad/screenshot.jpg deleted file mode 100644 index 84d461a..0000000 Binary files a/examples/TexturedQuad/screenshot.jpg and /dev/null differ diff --git a/examples/TexturedQuad/vertex.glsl b/examples/TexturedQuad/vertex.glsl deleted file mode 100644 index f1882f8..0000000 --- a/examples/TexturedQuad/vertex.glsl +++ /dev/null @@ -1,16 +0,0 @@ -#version 450 - -layout(location = 0) in vec3 position; -layout(location = 1) in vec4 color; - -layout(location = 0) out vec2 pos; - -layout (binding =0) uniform MyMatrix -{ - mat4 Matrix; -}ubo; - -void main() { - gl_Position = ubo.Matrix * vec4(position.xyz, 1.0); - pos = position.xy; -} \ No newline at end of file diff --git a/examples/TexturedQuad/vertex.spv b/examples/TexturedQuad/vertex.spv deleted file mode 100644 index 61c0eea..0000000 Binary files a/examples/TexturedQuad/vertex.spv and /dev/null differ diff --git a/include/IContext.h b/include/IContext.h index 42efadb..8a9a669 100644 --- a/include/IContext.h +++ b/include/IContext.h @@ -3,12 +3,15 @@ #pragma once #include +#include #include #include #include #include +#ifndef NOMINMAX #define NOMINMAX +#endif #if defined(_WIN32) || defined(WIN32) || defined(_WIN64) || defined(WIN64) #define WIN32_LEAN_AND_MEAN @@ -32,7 +35,7 @@ enum EResourceType : uint8_t SWAPCHAIN = 5, FRAMEBUFFER = 6, IMAGE = 7, - GRAPHICS_PIPELINE = 8, + PIPELINE = 8, COMMAND_POOL = 9, COMMAND_BUFFER = 10, FENCE = 11, @@ -42,9 +45,33 @@ enum EResourceType : uint8_t DESCRIPTOR_SET = 15, SAMPLER = 16, INDIRECT_DRAW_COMMAND = 17, + QUEUE = 18, + STORAGE_BUFFER = 19, }; // SHOULD BE PRIVATE +enum class EFilter : uint8_t +{ + NEAREST, + LINEAR, + CUBIC, // May not be supported on all hardware +}; + +enum class ESamplerAddressMode +{ + REPEAT, + MIRRORED_REPEAT, + CLAMP_TO_EDGE, + CLAMP_TO_BORDER, + MIRROR_CLAMP_TO_EDGE, // not all implementations could support it, +}; + +enum class ESamplerMipmapMode +{ + NEAREST, + LINEAR, +}; + struct DContextConfig { uint32_t stagingBufferSize{ 64 * 1024 * 1024 }; // 64mb @@ -126,6 +153,26 @@ enum class EFormat SINT32, }; +inline bool +IsFormatDepth(EFormat format) +{ + return format == EFormat::DEPTH16_UNORM || format == EFormat::DEPTH32_FLOAT || format == EFormat::DEPTH16_UNORM_STENCIL8_UINT || format == EFormat::DEPTH24_UNORM_STENCIL8_UINT || + format == EFormat::DEPTH24_UNORM_STENCIL8_UINT || format == EFormat::DEPTH32_FLOAT_STENCIL8_UINT; +}; + +inline bool +isFormatColor(EFormat format) +{ + return !IsFormatDepth(format); +}; + +inline bool +IsFormatStencil(EFormat format) +{ + return format == EFormat::DEPTH16_UNORM_STENCIL8_UINT || format == EFormat::DEPTH24_UNORM_STENCIL8_UINT || format == EFormat::DEPTH24_UNORM_STENCIL8_UINT || + format == EFormat::DEPTH32_FLOAT_STENCIL8_UINT; +}; + enum class EVertexInputClassification { PER_VERTEX_DATA, @@ -163,14 +210,39 @@ enum class ECullMode BACK }; -enum class EDepthTest +enum class EStencilOp +{ + KEEP = 0, + ZERO = 1, + REPLACE = 2, + INCREMENT_AND_CLAMP = 3, + DECREMENT_AND_CLAMP = 4, + INVERT = 5, + INCREMENT_AND_WRAP = 6, + DECREMENT_AND_WRAP = 7, +}; + +enum class ECompareOp +{ + NEVER = 0, + LESS = 1, + EQUAL = 2, + LESS_OR_EQUAL = 3, + GREATER = 4, + NOT_EQUAL = 5, + GREATER_OR_EQUAL = 6, + ALWAYS = 7, +}; + +struct DStencilOpState { - ALWAYS, - NEVER, - LESS, - LESS_OR_EQUAL, - GREATER, - GREATER_OR_EQUAL + EStencilOp FailOp{ EStencilOp::KEEP }; + EStencilOp PassOp{ EStencilOp::REPLACE }; + EStencilOp DepthFailOp{ EStencilOp::KEEP }; + ECompareOp CompareOp{ ECompareOp::GREATER_OR_EQUAL }; + uint32_t CompareMask{ 0xff }; + uint32_t WriteMask{ 0xff }; + uint32_t Reference{}; }; enum ERIBlendMode @@ -186,9 +258,10 @@ struct PipelineFormat ECullMode CullMode{ ECullMode::NONE }; bool DepthTest{ false }; bool DepthWrite{ false }; - EDepthTest DepthTestMode{ EDepthTest::ALWAYS }; + ECompareOp DepthTestMode{ ECompareOp::LESS_OR_EQUAL }; bool StencilTest{ false }; ERIBlendMode BlendMode{ ERIBlendMode::DefaultBlendMode }; + float LineWidth{ 1.f }; }; struct PipelineFormatHashFn @@ -390,6 +463,7 @@ enum class EBindingType UNIFORM_BUFFER_OBJECT, STORAGE_BUFFER_OBJECT, TEXTURE, + STORAGE_IMAGE, SAMPLER, COMBINED_IMAGE_SAMPLER, }; @@ -398,6 +472,7 @@ enum class EShaderStage { VERTEX, FRAGMENT, + COMPUTE, ALL }; @@ -476,9 +551,18 @@ class RIShaderDescriptorBindingsEqualFn } }; +struct PushConstantRange +{ + /*Does not affect the stage; do not use the Stage variable*/ + EShaderStage Stage{ EShaderStage::ALL }; + uint32_t Offset{}; + uint32_t Size{}; +}; + struct ShaderLayout { std::map> SetsLayout; + std::vector PushConstants; }; struct ShaderByteCode @@ -486,6 +570,7 @@ struct ShaderByteCode // Compiled shader raw binary data std::vector VertexShader; std::vector PixelShader; + std::vector ComputeShader; }; struct ShaderSource @@ -503,6 +588,17 @@ struct DFramebufferAttachments static constexpr uint32_t MAX_ATTACHMENTS = 10; std::array RenderTargets{}; uint32_t DepthStencil{}; + + inline bool HasColorAttachment(uint32_t id) const + { + for (size_t i = 0; i < DFramebufferAttachments::MAX_ATTACHMENTS; i++) + { + if (RenderTargets[i] == id) + return true; + } + return false; + }; + bool operator==(const DFramebufferAttachments& rhs) const { return memcmp(&RenderTargets[0], &rhs.RenderTargets[0], sizeof(uint32_t) * MAX_ATTACHMENTS) == 0 && DepthStencil == rhs.DepthStencil; }; }; struct DPipelineAttachments @@ -543,13 +639,15 @@ struct DFramebufferAttachmentEqualFn struct DLoadOpPass { - ERenderPassLoad LoadColor[DFramebufferAttachments::MAX_ATTACHMENTS]; - ERenderPassLoad LoadDepth; + ERenderPassLoad LoadColor[DFramebufferAttachments::MAX_ATTACHMENTS]; + ERenderPassLoad LoadDepth; + /*CURRENTLY NOT USED, USE LoadDepth to control both*/ ERenderPassLoad LoadStencil; DClearValue ClearColor[DFramebufferAttachments::MAX_ATTACHMENTS]; DClearValue ClearDepthStencil; ERenderPassStore StoreActionsColor[DFramebufferAttachments::MAX_ATTACHMENTS]; ERenderPassStore StoreDepth; + /*CURRENTLY NOT USED, USE LoadDepth to control both*/ ERenderPassStore StoreStencil; }; @@ -576,12 +674,11 @@ enum class EResourceState SHADING_RATE_SOURCE = 0x8000, }; -enum class EQueueType +enum EQueueType { - GRAPHICS = 0, - TRANSFER, - COMPUTE, - MAX_QUEUE_TYPE + QUEUE_GRAPHICS = 0x1, + QUEUE_TRANSFER = 0x2, + QUEUE_COMPUTE = 0x4, }; enum class EPipelineType @@ -612,6 +709,7 @@ enum class ERIShaderStage { VERTEX, FRAGMENT, + COMPUTE, ALL }; @@ -625,28 +723,35 @@ struct DescriptorSetDesc ERIShaderStage Stage; }; +enum ETransferOwnership : uint8_t +{ + NONE = 0, + ACQUIRE, + RELEASE +}; + typedef struct BufferBarrier { - uint32_t BufferId; - EResourceState CurrentState; - EResourceState NewState; - uint8_t BeginOnly : 1; - uint8_t EndOnly : 1; - uint8_t Acquire : 1; - uint8_t Release : 1; - uint8_t QueueType : 5; + uint32_t BufferId; + EResourceState CurrentState; + EResourceState NewState; + uint8_t BeginOnly : 1; + uint8_t EndOnly : 1; + ETransferOwnership TransferOwnership{ ETransferOwnership::NONE }; + uint32_t SrcQueue{}; + uint32_t DstQueue{}; } BufferBarrier; typedef struct TextureBarrier { - uint32_t ImageId; - EResourceState CurrentState; - EResourceState NewState; - uint8_t BeginOnly : 1; - uint8_t EndOnly : 1; - uint8_t Acquire : 1; - uint8_t Release : 1; - uint8_t QueueType : 5; + uint32_t ImageId; + EResourceState CurrentState; + EResourceState NewState; + uint8_t BeginOnly : 1; + uint8_t EndOnly : 1; + ETransferOwnership TransferOwnership{ ETransferOwnership::NONE }; + uint32_t SrcQueue{}; + uint32_t DstQueue{}; /// Specifiy whether following barrier targets particular subresource uint8_t mSubresourceBarrier : 1; /// Following values are ignored if mSubresourceBarrier is false @@ -656,27 +761,32 @@ typedef struct TextureBarrier typedef struct RenderTargetBarrier { - uint32_t RenderTarget; - EResourceState mCurrentState; - EResourceState mNewState; - uint8_t mBeginOnly : 1; - uint8_t mEndOnly : 1; - uint8_t mAcquire : 1; - uint8_t mRelease : 1; - uint8_t mQueueType : 5; + uint32_t RenderTarget{}; + EResourceState mCurrentState; + EResourceState mNewState; + uint8_t mBeginOnly : 1; + uint8_t mEndOnly : 1; + ETransferOwnership TransferOwnership{ ETransferOwnership::NONE }; + uint32_t SrcQueue{}; + uint32_t DstQueue{}; /// Specifiy whether following barrier targets particular subresource uint8_t mSubresourceBarrier : 1; /// Following values are ignored if mSubresourceBarrier is false uint8_t mMipLevel : 7; - uint16_t mArrayLayer; + uint16_t mArrayLayer{}; } RenderTargetBarrier; typedef struct DescriptorData { const char* pName; + uint32_t SetIndex{}; uint32_t Count{}; uint32_t ArrayOffset{}; uint32_t Index{}; + uint32_t BufferOffset{}; + uint32_t BufferRange{}; + uint32_t MipMapIndex{}; + uint32_t MipMapCount{ 1 }; union { @@ -699,49 +809,85 @@ class IContext { public: virtual ~IContext(){}; - virtual void WaitDeviceIdle() = 0; - virtual uint32_t CreateSwapchain(const WindowData* windowData, EPresentMode& presentMode, EFormat& outFormat, uint32_t* width = nullptr, uint32_t* height = nullptr) = 0; - virtual std::vector GetSwapchainRenderTargets(uint32_t swapchainId) = 0; - virtual bool SwapchainAcquireNextImageIndex(uint32_t swapchainId, uint64_t timeoutNanoseconds, uint32_t sempahoreid, uint32_t* outImageIndex) = 0; - virtual void DestroySwapchain(uint32_t swapchainId) = 0; - - virtual uint32_t CreateBuffer(uint32_t size, EResourceType type, EMemoryUsage usage) = 0; - virtual void* BeginMapBuffer(uint32_t buffer) = 0; - virtual void EndMapBuffer(uint32_t buffer) = 0; - virtual void DestroyBuffer(uint32_t buffer) = 0; - virtual ImageId CreateImage(EFormat format, uint32_t width, uint32_t height, uint32_t mipMapCount) = 0; - virtual EFormat GetImageFormat(ImageId) const = 0; - virtual void DestroyImage(ImageId imageId) = 0; - virtual uint32_t CreateVertexLayout(const std::vector& info) = 0; - virtual uint32_t CreateShader(const ShaderSource& source) = 0; - virtual void DestroyShader(const uint32_t shader) = 0; - virtual uint32_t CreatePipeline(const uint32_t shader, uint32_t rootSignatureId, const DPipelineAttachments& attachments, const PipelineFormat& format) = 0; - virtual void DestroyPipeline(uint32_t pipelineId) = 0; - virtual uint32_t CreateRootSignature(const ShaderLayout& layout) = 0; - virtual void DestroyRootSignature(uint32_t rootSignatureId) = 0; - virtual uint32_t CreateDescriptorSets(uint32_t rootSignatureId, EDescriptorFrequency frequency, uint32_t count) = 0; - virtual void DestroyDescriptorSet(uint32_t descriptorSetId) = 0; - virtual void UpdateDescriptorSet(uint32_t descriptorSetId, uint32_t setIndex, uint32_t paramCount, DescriptorData* params) = 0; - virtual uint32_t CreateSampler(uint32_t minLod, uint32_t maxLod) = 0; - - virtual uint32_t CreateCommandPool() = 0; - virtual void DestroyCommandPool(uint32_t commandPoolId) = 0; - virtual void ResetCommandPool(uint32_t commandPoolId) = 0; - virtual uint32_t CreateCommandBuffer(uint32_t commandPoolId) = 0; - virtual void DestroyCommandBuffer(uint32_t commandBufferId) = 0; - virtual void BeginCommandBuffer(uint32_t commandBufferId) = 0; - virtual void EndCommandBuffer(uint32_t commandBufferId) = 0; - virtual void BindRenderTargets(uint32_t commandBufferId, const DFramebufferAttachments& attachments, const DLoadOpPass& loadOP) = 0; - virtual void SetViewport(uint32_t commandBufferId, uint32_t x, uint32_t y, uint32_t width, uint32_t height, float znear, float zfar) = 0; - virtual void SetScissor(uint32_t commandBufferId, uint32_t x, uint32_t y, uint32_t width, uint32_t height) = 0; - virtual void BindPipeline(uint32_t commandBufferId, uint32_t pipeline) = 0; - virtual void BindVertexBuffer(uint32_t commandBufferId, uint32_t bufferId) = 0; - virtual void BindIndexBuffer(uint32_t commandBufferId, uint32_t bufferId) = 0; - virtual void Draw(uint32_t commandBufferId, uint32_t firstVertex, uint32_t count) = 0; - virtual void DrawIndexed(uint32_t commandBufferId, uint32_t index_count, uint32_t first_index, uint32_t first_vertex) = 0; - virtual void DrawIndexedIndirect(uint32_t commandBufferId, uint32_t buffer, uint32_t offset, uint32_t drawCount, uint32_t stride) = 0; - virtual void BindDescriptorSet(uint32_t commandBufferId, uint32_t setIndex, uint32_t descriptorSetId) = 0; - virtual void CopyImage(uint32_t commandId, uint32_t imageId, uint32_t width, uint32_t height, uint32_t mipMapIndex, uint32_t stagingBufferId, uint32_t stagingBufferOffset) = 0; + virtual bool CompileNativeShader(const std::vector& blob, std::vector& outShader, EShaderStage shaderStage, std::string& errorMgs) = 0; + + virtual void WaitDeviceIdle() = 0; + virtual uint32_t CreateSwapchain(const WindowData* windowData, EPresentMode& presentMode, EFormat& outFormat, uint32_t* width = nullptr, uint32_t* height = nullptr) = 0; + /** + * /brief Returns a list of render targers for each frame (1 single buffered, 2 double buffered) + * /param swapchainId the swapchain id + * /return List of render targer ids if swapchain is in valid state or empty vector otherwise + */ + virtual std::vector GetSwapchainRenderTargets(uint32_t swapchainId) = 0; + virtual bool SwapchainAcquireNextImageIndex(uint32_t swapchainId, uint64_t timeoutNanoseconds, uint32_t sempahoreid, uint32_t* outImageIndex) = 0; + virtual bool SwapchainHasValidSurface(SwapchainId swapchainId) = 0; + virtual void DestroySwapchain(uint32_t swapchainId) = 0; + + /** + * \brief If exists will return a specialized queue, otherwise if exists will return a queue with that feature, otherwise it will return a general purpose queue that supports that feature. If no + * queue with requested feature are available it will return 0. It will return as many queues as there are available, after it will return always a general purpose queue with same id. Don't loose + * the queue id because specialized queues return only once. + * \param queueTypeFlag + * \return A queue with the requested feature + */ + virtual uint32_t FindQueue(EQueueType queueType) = 0; + + virtual uint32_t CreateBuffer(uint32_t size, EResourceType type, EMemoryUsage usage) = 0; + virtual void* BeginMapBuffer(uint32_t buffer) = 0; + virtual void EndMapBuffer(uint32_t buffer) = 0; + virtual void DestroyBuffer(uint32_t buffer) = 0; + virtual ImageId CreateImage(EFormat format, uint32_t width, uint32_t height, uint32_t mipMapCount, bool isDepth = false, bool isStencil = false) = 0; + virtual ImageId CreateStorageImage(EFormat format, uint32_t width, uint32_t height, uint32_t mipMapCount, bool isDepth = false, bool isStencil = false) = 0; + virtual EFormat GetImageFormat(ImageId) const = 0; + virtual void DestroyImage(ImageId imageId) = 0; + virtual uint32_t CreateVertexLayout(const std::vector& info) = 0; + virtual uint32_t CreateShader(const ShaderSource& source) = 0; + virtual void DestroyShader(const uint32_t shader) = 0; + virtual uint32_t CreateComputePipeline(const uint32_t shader, const uint32_t rootSignatureId) = 0; + virtual uint32_t CreatePipeline(const uint32_t shader, uint32_t rootSignatureId, const DPipelineAttachments& attachments, const PipelineFormat& format) = 0; + virtual void DestroyPipeline(uint32_t pipelineId) = 0; + virtual uint32_t CreateRootSignature(const ShaderLayout& layout) = 0; + virtual void DestroyRootSignature(uint32_t rootSignatureId) = 0; + virtual uint32_t CreateDescriptorSets(uint32_t rootSignatureId, EDescriptorFrequency frequency, uint32_t count) = 0; + virtual void DestroyDescriptorSet(uint32_t descriptorSetId) = 0; + virtual void UpdateDescriptorSet(uint32_t descriptorSetId, uint32_t paramCount, DescriptorData* params) = 0; + virtual uint32_t CreateSampler(uint32_t minLod, + uint32_t maxLod, + EFilter minFilter, + EFilter magFilter, + ESamplerAddressMode addressMode, + ESamplerMipmapMode mipMapMode, + bool anisotropicFiltering, + float anisotropicFilter = 16.f) = 0; + virtual void DestroySampler(uint32_t samplerId) = 0; + + virtual uint32_t CreateCommandPool(uint32_t queueId) = 0; + virtual void DestroyCommandPool(uint32_t commandPoolId) = 0; + virtual void ResetCommandPool(uint32_t commandPoolId) = 0; + virtual uint32_t CreateCommandBuffer(uint32_t commandPoolId) = 0; + virtual void DestroyCommandBuffer(uint32_t commandBufferId) = 0; + virtual void BeginCommandBuffer(uint32_t commandBufferId) = 0; + virtual void EndCommandBuffer(uint32_t commandBufferId) = 0; + virtual void BindRenderTargets(uint32_t commandBufferId, const DFramebufferAttachments& attachments, const DLoadOpPass& loadOP) = 0; + virtual void SetViewport(uint32_t commandBufferId, uint32_t x, uint32_t y, uint32_t width, uint32_t height, float znear, float zfar) = 0; + virtual void SetScissor(uint32_t commandBufferId, uint32_t x, uint32_t y, uint32_t width, uint32_t height) = 0; + virtual void BindPipeline(uint32_t commandBufferId, uint32_t pipeline) = 0; + virtual void BindVertexBuffer(uint32_t commandBufferId, uint32_t bufferId) = 0; + virtual void BindIndexBuffer(uint32_t commandBufferId, uint32_t bufferId) = 0; + virtual void Draw(uint32_t commandBufferId, uint32_t firstVertex, uint32_t count) = 0; + virtual void DrawIndexed(uint32_t commandBufferId, uint32_t index_count, uint32_t first_index, uint32_t first_vertex) = 0; + virtual void DrawIndexedIndirect(uint32_t commandBufferId, uint32_t buffer, uint32_t offset, uint32_t drawCount, uint32_t stride) = 0; + virtual void BindDescriptorSet(uint32_t commandBufferId, uint32_t setIndex, uint32_t descriptorSetId) = 0; + virtual void CopyImage(uint32_t commandId, uint32_t destImage, uint32_t width, uint32_t height, uint32_t mipMapIndex, uint32_t mipMapCount, uint32_t sourceImage) = 0; + virtual void CopyBufferToImage(uint32_t commandId, uint32_t imageId, uint32_t width, uint32_t height, uint32_t mipMapIndex, uint32_t stagingBufferId, uint32_t stagingBufferOffset) = 0; + virtual void CopyBuffer(uint32_t commandId, uint32_t bufferId, uint32_t offset, uint32_t bytes, uint32_t stagingBufferId, uint32_t stagingBufferOffset) = 0; + virtual void SetStencilTest(uint32_t commandId, bool enable, const DStencilOpState* frontFace, const DStencilOpState* backFace) = 0; + virtual void SetDepthTestCompareOp(uint32_t commandId, bool enabled, bool depthWrite, ECompareOp compareOp) = 0; + virtual void SetPrimitiveTopology(uint32_t commandId, ETopology primitiveTopology) = 0; + virtual void SetLineWidth(uint32_t commandId, float lineWidth) = 0; + virtual void DispatchCompute(uint32_t commandId, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ) = 0; + virtual void ComputeWorkGroupCount(uint32_t* groupCountX, uint32_t* groupCountY, uint32_t* groupCountZ) = 0; + virtual void PushConstant(uint32_t commandId, EShaderStage stage, uint32_t offset, uint32_t size, void* data) = 0; virtual uint32_t CreateRenderTarget(EFormat format, ESampleBit samples, bool isDepth, uint32_t width, uint32_t height, uint32_t arrayLength, uint32_t mipMapCount, EResourceState initialState) = 0; virtual void DestroyRenderTarget(uint32_t renderTargetId) = 0; @@ -759,15 +905,23 @@ class IContext virtual void WaitForFence(uint32_t fenceId, uint64_t timeoutNanoseconds) = 0; virtual void ResetFence(uint32_t fenceId) = 0; - virtual void QueueSubmit(const std::vector& waitSemaphore, const std::vector& finishSemaphore, const std::vector& cmdIds, uint32_t fenceId) = 0; - virtual void QueuePresent(uint32_t swapchainId, uint32_t imageIndex, const std::vector& waitSemaphore) = 0; + /** + * \brief Must be externally synchronized if called from multiple threads + * \param waitSemaphore + * \param finishSemaphore + * \param cmdIds + * \param fenceId + */ + virtual void QueueSubmit(uint32_t queueId, const std::vector& waitSemaphore, const std::vector& finishSemaphore, const std::vector& cmdIds, uint32_t fenceId) = 0; + virtual void QueuePresent(uint32_t queueId, uint32_t swapchainId, uint32_t imageIndex, const std::vector& waitSemaphore) = 0; virtual uint32_t CreateGpuSemaphore() = 0; virtual void DestroyGpuSemaphore(uint32_t semaphoreId) = 0; virtual void FlushDeletedBuffers() = 0; - virtual unsigned char* GetAdapterDescription() const = 0; - virtual size_t GetAdapterDedicatedVideoMemory() const = 0; + virtual unsigned char* GetAdapterDescription() const = 0; + virtual size_t GetAdapterDedicatedVideoMemory() const = 0; + virtual float GetMaxAnisotropyFiltering(bool* isSupported = nullptr) const = 0; }; } \ No newline at end of file diff --git a/include/backend/vulkan/VulkanContextFactory.h b/include/backend/vulkan/VulkanContextFactory.h index 4c552a0..4d64bfd 100644 --- a/include/backend/vulkan/VulkanContextFactory.h +++ b/include/backend/vulkan/VulkanContextFactory.h @@ -4,7 +4,13 @@ #include "IContext.h" +#ifdef FURY_EXPORT +#define FURY_API __declspec(dllexport) +#else +#define FURY_API __declspec(dllimport) +#endif + namespace Fox { -IContext* CreateVulkanContext(DContextConfig const*const config); +IContext* CreateVulkanContext(DContextConfig const* const config); } \ No newline at end of file diff --git a/src/asserts.h b/src/Asserts.h similarity index 92% rename from src/asserts.h rename to src/Asserts.h index 3f0335e..a4a3ea9 100644 --- a/src/asserts.h +++ b/src/Asserts.h @@ -45,16 +45,16 @@ inline void _fprint(const char* _condition, const char* file, const int line) { - std::cerr << "check(" << _condition << ") IN FILE " << file << " LINE " << line << "\n" << std::flush; + std::cerr << "furyassert(" << _condition << ") IN FILE " << file << " LINE " << line << "\n" << std::flush; }; #define ERRORLOG(msg) std::cerr << "Error:" << msg << " IN FILE " << __FILE__ << " LINE " << __LINE__ << "\n" << std::flush; -// Use check only to trigger an exception in debug mode +// Use furyassert only to trigger an exception in debug mode // if condition = false then the debugger will stop // clang-format off #if defined(_DEBUG) -#define check(condition) \ +#define furyassert(condition) \ { \ if (!(condition)) \ { \ @@ -63,7 +63,7 @@ _fprint(const char* _condition, const char* file, const int line) } \ }; #else -#define check(condition) +#define furyassert(condition) #endif // Use critical it will throw a runtime error if the condition is false even in release builds diff --git a/src/AtomicCounter.h b/src/AtomicCounter.h index 31f531f..191fe33 100644 --- a/src/AtomicCounter.h +++ b/src/AtomicCounter.h @@ -2,7 +2,7 @@ #pragma once -#include "asserts.h" +#include "Asserts.h" #include @@ -14,7 +14,7 @@ class CAtomicCounter inline void IncreaseCounter() { _counter.store(_counter.load() + 1); }; inline void DecreaseCounter() { - check(_counter.load() > 0); // count can't be negative + furyassert(_counter.load() > 0); // count can't be negative _counter.store(_counter.load() - 1); }; inline uint32_t Count() const { return _counter.load(); }; diff --git a/src/DescriptorPool.h b/src/DescriptorPool.h index 6067092..d37d518 100644 --- a/src/DescriptorPool.h +++ b/src/DescriptorPool.h @@ -2,13 +2,12 @@ #pragma once -#include "asserts.h" +#include "Asserts.h" -#include "backend/vulkan/UtilsVK.h" +#include "backend/vulkan/UtilsVk.h" #include -#define VK_USE_PLATFORM_WIN32_KHR #include namespace Fox @@ -43,7 +42,7 @@ namespace Fox // // void BindCombinedImageSamplerArray(uint32_t bindingIndex, const std::vector>& imageToSamplerArray) // { -// check(imageToSamplerArray.size() > 0); +// furyassert(imageToSamplerArray.size() > 0); // // _imageInfo.push_back({}); // diff --git a/src/RICacheMap.h b/src/RICacheMap.h index 93f3c8c..ee2ce6f 100644 --- a/src/RICacheMap.h +++ b/src/RICacheMap.h @@ -2,7 +2,7 @@ #pragma once -#include "asserts.h" +#include "Asserts.h" #include @@ -16,7 +16,7 @@ class RICacheMap public: void Add(const Key& key, const Value value) { - check(Find(key) == nullptr); // element is already contained + furyassert(Find(key) == nullptr); // element is already contained auto pair = std::make_pair(key, value); _map.insert(std::move(pair)); } @@ -41,7 +41,7 @@ class RICacheMap return; } } - check(0); // element is not contained + furyassert(0); // element is not contained } size_t Size() const { return _map.size(); } diff --git a/src/RIComponents.cpp b/src/RIComponents.cpp index 8574158..7a83e4d 100644 --- a/src/RIComponents.cpp +++ b/src/RIComponents.cpp @@ -1,6 +1,6 @@ #include "RIComponents.h" -#include "RenderInterface/vulkan/UtilsVK.h" +#include "RenderInterface/vulkan/UtilsVk.h" namespace Fox { diff --git a/src/RIContextVk.cpp b/src/RIContextVk.cpp index 6cab522..f7c3417 100644 --- a/src/RIContextVk.cpp +++ b/src/RIContextVk.cpp @@ -1,7 +1,7 @@ // Copyright RedFox Studio 2022 #include "RIContextVk.h" -#include "ResourceTransfer.h" +#include "backend/vulkan/ResourceTransfer.h" #include namespace Fox diff --git a/src/RIContextVk.inl b/src/RIContextVk.inl index fc121f7..aa515d7 100644 --- a/src/RIContextVk.inl +++ b/src/RIContextVk.inl @@ -5,7 +5,7 @@ #if defined(FOX_USE_VULKAN) #include "RIContextVk.h" -#include "RenderInterface/vulkan/UtilsVK.h" +#include "RenderInterface/vulkan/UtilsVk.h" #include #include diff --git a/src/RICoreVk.inl b/src/RICoreVk.inl index 02bd46c..7a3fbdf 100644 --- a/src/RICoreVk.inl +++ b/src/RICoreVk.inl @@ -3,7 +3,7 @@ #pragma once #include "RICoreVk.h" -#include "UtilsVK.h" +#include "UtilsVk.h" #include #include diff --git a/src/RIFactoryVk.h b/src/RIFactoryVk.h index d17ec7a..155b428 100644 --- a/src/RIFactoryVk.h +++ b/src/RIFactoryVk.h @@ -9,7 +9,7 @@ #include "Core/memory/RingBufferManager.h" #include "Core/window/WindowBase.h" #include "DescriptorPool.h" -#include "UtilsVK.h" +#include "UtilsVk.h" #include #include diff --git a/src/RIFactoryVk.inl b/src/RIFactoryVk.inl index 3b73e0b..54e5952 100644 --- a/src/RIFactoryVk.inl +++ b/src/RIFactoryVk.inl @@ -10,7 +10,7 @@ #include "Core/utils/Filter.h" #include "Core/utils/Fox_Assert.h" #include "RenderInterface/vulkan/RIFactoryVk.h" -#include "RenderInterface/vulkan/UtilsVK.h" +#include "RenderInterface/vulkan/UtilsVk.h" namespace Fox { diff --git a/src/ResourceId.h b/src/ResourceId.h index e6dcac8..ba539df 100644 --- a/src/ResourceId.h +++ b/src/ResourceId.h @@ -2,7 +2,9 @@ #pragma once +#include #include +#include namespace Fox { @@ -30,6 +32,22 @@ class ResourceId _data.Decompose.Second = second; _data.Decompose.Value = value; }; + ResourceId(uint8_t first, uint8_t second, uint32_t value) + { + _data.Decompose.First = first; + _data.Decompose.Second = second; + _data.Decompose.Value = static_cast(value); + + assert(value < std::numeric_limits().max()); + }; + ResourceId(uint8_t first, uint8_t second, size_t value) + { + _data.Decompose.First = first; + _data.Decompose.Second = second; + _data.Decompose.Value = static_cast(value); + + assert(value < std::numeric_limits().max()); + }; uint16_t Value() const { return _data.Decompose.Value; }; diff --git a/src/RingBufferManager.h b/src/RingBufferManager.h index b9f3a57..90fc6f8 100644 --- a/src/RingBufferManager.h +++ b/src/RingBufferManager.h @@ -2,7 +2,7 @@ #pragma once -#include "asserts.h" +#include "Asserts.h" namespace Fox { @@ -19,13 +19,13 @@ struct RingBufferManager // Must receive the same number of pop with the same length as the number of time Push was called void Pop(uint32_t length) { - check(length, MaxSize); + furyassert(length > MaxSize); #if defined(_DEBUG) if (!Full && Tail != Head) { if (Tail < Head) { - check(Tail + length <= Head); + furyassert(Tail + length <= Head); } } #endif @@ -45,7 +45,7 @@ struct RingBufferManager Tail = 0; } - check(Tail >= 0 && Tail <= MaxSize); + furyassert(Tail >= 0 && Tail <= MaxSize); Full = false; // When Pop is called it means the we're not full anymore } @@ -95,23 +95,23 @@ struct RingBufferManager uint32_t Push(void* data, uint32_t length) { // Must not be full - check(!Full); + furyassert(!Full); // Allocation can be more than max size - check(length <= MaxSize); + furyassert(length <= MaxSize); // Check capacity - check(Capacity() >= length); + furyassert(Capacity() >= length); #if defined(_DEBUG) if (Head != Tail) { if (Head < Tail) { // If head < tail cannot go beyond tail - check(Head + length <= Tail); + furyassert(Head + length <= Tail); } // else if (_shouldWrapAround(Head + length)) // { // // If head > tail and wrap arounds can't go beyond tail - // check(length <= Tail);//no Capacity left + // furyassert(length <= Tail);//no Capacity left // } } #endif @@ -133,7 +133,7 @@ struct RingBufferManager } const uint32_t dataStart = Head - length; - check(_isInsideRange(dataStart, length)); + furyassert(_isInsideRange(dataStart, length)); if (data != nullptr) { unsigned char* addressWithOffset = static_cast(Mapped) + dataStart; diff --git a/src/backend/vulkan/ResourceTransfer.cpp b/src/backend/vulkan/ResourceTransfer.cpp index 3902432..c561ffa 100644 --- a/src/backend/vulkan/ResourceTransfer.cpp +++ b/src/backend/vulkan/ResourceTransfer.cpp @@ -1,14 +1,14 @@ // Copyright RedFox Studio 2022 #include "ResourceTransfer.h" -#include "asserts.h" +#include "../../Asserts.h" #include namespace Fox { CResourceTransfer::CResourceTransfer(VkCommandBuffer command) : _command(command) { - check(_command); + furyassert(_command); VkCommandBufferBeginInfo beginInfo{}; beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; @@ -23,7 +23,7 @@ CResourceTransfer::CResourceTransfer(VkCommandBuffer command) : _command(command // std::vector barriersTransfer; // std::vector barriersSampler; // -// check(beginOffset < std::numeric_limits::max()); +// furyassert(beginOffset < std::numeric_limits::max()); // uint32_t offset = (uint32_t)beginOffset; // uint32_t mipWidth = image.Width; // uint32_t mipHeight = image.Height; @@ -94,7 +94,7 @@ CResourceTransfer::CResourceTransfer(VkCommandBuffer command) : _command(command // } void -CResourceTransfer::CopyMipMap(VkBuffer sourceBuffer, VkImage destination, VkExtent2D extent, uint32_t mipIndex, uint32_t internalOffset, size_t sourceOffset) +CResourceTransfer::CopyMipMap(VkBuffer sourceBuffer, VkImage destination, VkExtent2D extent, uint32_t mipIndex, uint32_t, size_t sourceOffset) { VkBufferImageCopy region{}; { diff --git a/src/backend/vulkan/UtilsVK.h b/src/backend/vulkan/UtilsVk.h similarity index 70% rename from src/backend/vulkan/UtilsVK.h rename to src/backend/vulkan/UtilsVk.h index 8973b27..a49d054 100644 --- a/src/backend/vulkan/UtilsVK.h +++ b/src/backend/vulkan/UtilsVk.h @@ -2,13 +2,21 @@ #pragma once +#include "Asserts.h" #include "IContext.h" -#include "asserts.h" +#if defined(_WIN32) || defined(WIN32) || defined(_WIN64) || defined(WIN64) #define VK_USE_PLATFORM_WIN32_KHR +// #include // Include the Win32-specific extension header +#elif defined(__linux__) +#define VK_USE_PLATFORM_XLIB_KHR +// #include +#endif + #include #include +#include #include #include #include @@ -81,6 +89,9 @@ VkErrorString(enum VkResult result) case VK_ERROR_UNKNOWN: return "VK_ERROR_UNKNOWN"; break; + case VK_ERROR_SURFACE_LOST_KHR: + return "VK_ERROR_SURFACE_LOST_KHR"; + break; default: return "UNKNOWN VK ERROR"; break; @@ -102,7 +113,7 @@ convertPresentMode(const Fox::EPresentMode mode) case Fox::EPresentMode::FIFO_RELAXED: return VkPresentModeKHR::VK_PRESENT_MODE_FIFO_RELAXED_KHR; } - check(0); + furyassert(0); return VkPresentModeKHR::VK_PRESENT_MODE_MAX_ENUM_KHR; }; @@ -149,7 +160,7 @@ convertVkFormat(const VkFormat format) return Fox::EFormat::SINT32; } - check(0); + furyassert(0); return Fox::EFormat::R8_UNORM; }; @@ -196,7 +207,7 @@ convertFormat(const Fox::EFormat format) return VK_FORMAT_R32_SINT; } - check(0); + furyassert(0); return VK_FORMAT_UNDEFINED; }; @@ -222,7 +233,7 @@ convertVkSampleCount(const Fox::ESampleBit sample) return VK_SAMPLE_COUNT_64_BIT; } - check(0); + furyassert(0); return VK_SAMPLE_COUNT_1_BIT; } @@ -237,7 +248,7 @@ convertAttachmentLoadOp(const Fox::ERenderPassLoad load) return VK_ATTACHMENT_LOAD_OP_LOAD; } - check(0); + furyassert(0); return VK_ATTACHMENT_LOAD_OP_CLEAR; } @@ -252,7 +263,7 @@ convertAttachmentStoreOp(const Fox::ERenderPassStore store) return VK_ATTACHMENT_STORE_OP_STORE; } - check(0); + furyassert(0); return VK_ATTACHMENT_STORE_OP_STORE; } @@ -311,7 +322,7 @@ convertRenderPassLayout(const Fox::ERenderPassLayout layout, bool isColor = true return VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; } - check(0); + furyassert(0); return VK_IMAGE_LAYOUT_UNDEFINED; } @@ -487,7 +498,7 @@ convertAttachmentReferenceLayout(const Fox::EAttachmentReference& att) return VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; } - check(0); + furyassert(0); return VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL; } @@ -524,6 +535,9 @@ convertDescriptorBindings(const std::map& byteCode, VkShaderModule* shaderModule) { - check(device); - check(byteCode.size() > 0); - check(shaderModule && !*shaderModule); + furyassert(device); + furyassert(byteCode.size() > 0); + furyassert(shaderModule && !*shaderModule); VkShaderModuleCreateInfo createInfo{}; createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; @@ -607,8 +624,8 @@ inline VkPipelineShaderStageCreateInfo createShaderStageInfo(VkShaderStageFlagBits stage, VkShaderModule shaderModule) { constexpr const char* PENTRYPOINTNAME{ "main" }; - check(shaderModule); - check(stage == VK_SHADER_STAGE_VERTEX_BIT || stage == VK_SHADER_STAGE_FRAGMENT_BIT); + furyassert(shaderModule); + furyassert(stage == VK_SHADER_STAGE_VERTEX_BIT || stage == VK_SHADER_STAGE_FRAGMENT_BIT || stage == VK_SHADER_STAGE_COMPUTE_BIT); VkPipelineShaderStageCreateInfo stageInfo{}; stageInfo.pNext = nullptr; @@ -630,7 +647,7 @@ determinePipelineStageFlags(VkAccessFlags accessFlags, Fox::EQueueType queueType switch (queueType) { - case Fox::EQueueType::GRAPHICS: + case Fox::EQueueType::QUEUE_GRAPHICS: { if ((accessFlags & (VK_ACCESS_INDEX_READ_BIT | VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT)) != 0) flags |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT; @@ -672,7 +689,7 @@ determinePipelineStageFlags(VkAccessFlags accessFlags, Fox::EQueueType queueType #endif break; } - case Fox::EQueueType::COMPUTE: + case Fox::EQueueType::QUEUE_COMPUTE: { if ((accessFlags & (VK_ACCESS_INDEX_READ_BIT | VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT)) != 0 || (accessFlags & VK_ACCESS_INPUT_ATTACHMENT_READ_BIT) != 0 || (accessFlags & (VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT)) != 0 || @@ -684,7 +701,7 @@ determinePipelineStageFlags(VkAccessFlags accessFlags, Fox::EQueueType queueType break; } - case Fox::EQueueType::TRANSFER: + case Fox::EQueueType::QUEUE_TRANSFER: return VK_PIPELINE_STAGE_ALL_COMMANDS_BIT; default: break; @@ -850,8 +867,276 @@ convertResourceStateToImageLayout(Fox::EResourceState state, bool isDepth) break; } - check(0); + furyassert(0); return VK_IMAGE_LAYOUT_UNDEFINED; } +inline const char* +VkImageLayoutToString(VkImageLayout layout) +{ + switch (layout) + { + CASE(VK_IMAGE_LAYOUT_UNDEFINED, "VK_IMAGE_LAYOUT_UNDEFINED"); + CASE(VK_IMAGE_LAYOUT_GENERAL, "VK_IMAGE_LAYOUT_GENERAL"); + CASE(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, "VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL"); + CASE(VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, "VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL"); + CASE(VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL, "VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL"); + CASE(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, "VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL"); + CASE(VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, "VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL"); + CASE(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, "VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL"); + CASE(VK_IMAGE_LAYOUT_PREINITIALIZED, "VK_IMAGE_LAYOUT_PREINITIALIZED"); + CASE(VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL, "VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL"); + CASE(VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL, "VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL"); + CASE(VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL, "VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL"); + CASE(VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_OPTIMAL, "VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_OPTIMAL"); + CASE(VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_OPTIMAL, "VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_OPTIMAL"); + CASE(VK_IMAGE_LAYOUT_STENCIL_READ_ONLY_OPTIMAL, "VK_IMAGE_LAYOUT_STENCIL_READ_ONLY_OPTIMAL"); + CASE(VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL, "VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL"); + CASE(VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL, "VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL"); + CASE(VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, "VK_IMAGE_LAYOUT_PRESENT_SRC_KHR"); + CASE(VK_IMAGE_LAYOUT_VIDEO_DECODE_DST_KHR, "VK_IMAGE_LAYOUT_VIDEO_DECODE_DST_KHR"); + CASE(VK_IMAGE_LAYOUT_VIDEO_DECODE_SRC_KHR, "VK_IMAGE_LAYOUT_VIDEO_DECODE_SRC_KHR"); + CASE(VK_IMAGE_LAYOUT_VIDEO_DECODE_DPB_KHR, "VK_IMAGE_LAYOUT_VIDEO_DECODE_DPB_KHR"); + CASE(VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR, "VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR"); + CASE(VK_IMAGE_LAYOUT_FRAGMENT_DENSITY_MAP_OPTIMAL_EXT, "VK_IMAGE_LAYOUT_FRAGMENT_DENSITY_MAP_OPTIMAL_EXT"); + CASE(VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR, "VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR"); + CASE(VK_IMAGE_LAYOUT_RENDERING_LOCAL_READ_KHR, "VK_IMAGE_LAYOUT_RENDERING_LOCAL_READ_KHR"); + CASE(VK_IMAGE_LAYOUT_VIDEO_ENCODE_DST_KHR, "VK_IMAGE_LAYOUT_VIDEO_ENCODE_DST_KHR"); + CASE(VK_IMAGE_LAYOUT_VIDEO_ENCODE_SRC_KHR, "VK_IMAGE_LAYOUT_VIDEO_ENCODE_SRC_KHR"); + CASE(VK_IMAGE_LAYOUT_VIDEO_ENCODE_DPB_KHR, "VK_IMAGE_LAYOUT_VIDEO_ENCODE_DPB_KHR"); + CASE(VK_IMAGE_LAYOUT_ATTACHMENT_FEEDBACK_LOOP_OPTIMAL_EXT, "VK_IMAGE_LAYOUT_ATTACHMENT_FEEDBACK_LOOP_OPTIMAL_EXT"); + + default: + furyassert(false); + break; // Invalid enum + } + + return "UNKNOWN_VK_LAYOUT"; +}; + +inline VkFlags +convertQueueTypeToVkFlags(uint32_t queueTypeFlag) +{ + using namespace Fox; + uint32_t vkFlags{}; + if (queueTypeFlag & EQueueType::QUEUE_GRAPHICS) + { + vkFlags |= VK_QUEUE_GRAPHICS_BIT; + } + if (queueTypeFlag & EQueueType::QUEUE_COMPUTE) + { + vkFlags |= VK_QUEUE_COMPUTE_BIT; + } + if (queueTypeFlag & EQueueType::QUEUE_TRANSFER) + { + vkFlags |= VK_QUEUE_TRANSFER_BIT; + } + + return vkFlags; +} + +/** + * @brief Return a graphics flagged queue if requestedFlags is only graphics. If requested flags is only transfer or only compute it returns a dedicated queue with that flag only if available on + * hardware otherwise will return a non dedicated queue with also other flags. If no dedicated queue is found it will return the first queue that supports the requested flags; + * @param device The vulkan device + * @param outFamilyIndex out the family index found + * @param outQueueIndex out the queue index to use + * @param requestedFlags the queue flags requested + * @param queueFamilyPropertiesPtr a pointer to an array of VkQueueFamilyProperties + * @param queueFamilyPropertiesCount number of elements in queueFamilyPropertiesPtr + * @param queueFamilyIndexCreatedCount Array of int32 to count how many queues are used for each family. Length must be at least queueFamilyPropertiesCount + * @return The queue family index the has at least the requestedFlags. + */ +inline bool +findQueueWithFlags(uint32_t* outFamilyIndex, +uint32_t* outQueueIndex, +VkFlags requestedFlags, +const VkQueueFamilyProperties* const queueFamilyPropertiesPtr, +uint32_t queueFamilyPropertiesCount, +uint32_t* queueFamilyIndexCreatedCount) +{ + using namespace Fox; + + bool found{ false }; + *outFamilyIndex = 0; + *outQueueIndex = 0; + + for (uint32_t i = 0; i < queueFamilyPropertiesCount; i++) + { + const VkQueueFamilyProperties* const queueFamily = queueFamilyPropertiesPtr + i; + const bool isGraphics = (queueFamily->queueFlags & VK_QUEUE_GRAPHICS_BIT) ? true : false; + // If has the required flags but is also graphics and has unused queues + if (requestedFlags & VK_QUEUE_GRAPHICS_BIT && isGraphics) + { + found = true; + *outFamilyIndex = i; + // User can query as many graphics queue as it can, we will return always the same since there is no benefit of using multiple ones + break; + } + // if requested is specialized queue with only the flag requested + if (queueFamily->queueFlags & requestedFlags && (queueFamily->queueFlags & ~requestedFlags) == 0 && queueFamilyIndexCreatedCount[i] < queueFamily->queueCount) + { + found = true; + *outFamilyIndex = i; + *outQueueIndex = queueFamilyIndexCreatedCount[i]++; + + break; + } + uint32_t orRequestedFlags = (queueFamily->queueFlags & requestedFlags); + // Should return a queue with requestedFlag but is not general purpose nor specialized + if (queueFamily->queueFlags & orRequestedFlags && !isGraphics && queueFamilyIndexCreatedCount[i] < queueFamily->queueCount) + { + found = true; + *outFamilyIndex = i; + *outQueueIndex = queueFamilyIndexCreatedCount[i]++; + break; + } + } + + // Find a any queue with the requested queueTypeFlags + if (!found) + { + for (uint32_t i = 0; i < queueFamilyPropertiesCount; i++) + { + const VkQueueFamilyProperties* const queueFamily = queueFamilyPropertiesPtr + i; + if (queueFamily->queueFlags & requestedFlags) + { + found = true; + *outFamilyIndex = i; + break; + } + } + } + + furyassert(found == true); + return found; +} + +inline VkStencilOp +VkStencilOpFromStencilOp(Fox::EStencilOp stencilOp) +{ + switch (stencilOp) + { + CASE(Fox::EStencilOp::KEEP, VK_STENCIL_OP_KEEP); + CASE(Fox::EStencilOp::ZERO, VK_STENCIL_OP_ZERO); + CASE(Fox::EStencilOp::REPLACE, VK_STENCIL_OP_REPLACE); + CASE(Fox::EStencilOp::INCREMENT_AND_CLAMP, VK_STENCIL_OP_INCREMENT_AND_CLAMP); + CASE(Fox::EStencilOp::DECREMENT_AND_CLAMP, VK_STENCIL_OP_DECREMENT_AND_CLAMP); + CASE(Fox::EStencilOp::INVERT, VK_STENCIL_OP_INVERT); + CASE(Fox::EStencilOp::INCREMENT_AND_WRAP, VK_STENCIL_OP_INCREMENT_AND_WRAP); + CASE(Fox::EStencilOp::DECREMENT_AND_WRAP, VK_STENCIL_OP_DECREMENT_AND_WRAP); + default: + furyassert(false); + break; // Invalid enum + } + + return VK_STENCIL_OP_KEEP; +}; + +inline VkCompareOp +VkCompareOpFromCompareOp(Fox::ECompareOp compareOp) +{ + switch (compareOp) + { + CASE(Fox::ECompareOp::NEVER, VK_COMPARE_OP_NEVER); + CASE(Fox::ECompareOp::LESS, VK_COMPARE_OP_LESS); + CASE(Fox::ECompareOp::EQUAL, VK_COMPARE_OP_EQUAL); + CASE(Fox::ECompareOp::LESS_OR_EQUAL, VK_COMPARE_OP_LESS_OR_EQUAL); + CASE(Fox::ECompareOp::GREATER, VK_COMPARE_OP_GREATER); + CASE(Fox::ECompareOp::NOT_EQUAL, VK_COMPARE_OP_NOT_EQUAL); + CASE(Fox::ECompareOp::GREATER_OR_EQUAL, VK_COMPARE_OP_GREATER_OR_EQUAL); + CASE(Fox::ECompareOp::ALWAYS, VK_COMPARE_OP_ALWAYS); + default: + furyassert(false); + break; // Invalid enum + } + + return VK_COMPARE_OP_NEVER; +}; + +inline VkPrimitiveTopology +VkPrimitiveTopologyFromTopology(Fox::ETopology topology) +{ + switch (topology) + { + CASE(Fox::ETopology::TRIANGLE_LIST, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST); + CASE(Fox::ETopology::LINES_LIST, VK_PRIMITIVE_TOPOLOGY_LINE_LIST); + default: + furyassert(false); + break; // Invalid enum + } + + return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; +}; + +inline const char* +ERenderPassLayoutToString(Fox::ERenderPassLayout layout) +{ + switch (layout) + { + CASE(Fox::ERenderPassLayout::AsAttachment, "AsAttachment"); + CASE(Fox::ERenderPassLayout::Present, "Present"); + CASE(Fox::ERenderPassLayout::ShaderReadOnly, "ShaderReadOnly"); + CASE(Fox::ERenderPassLayout::Undefined, "Undefined"); + default: + furyassert(false); + break; // Invalid enum + } + + return "UNKNOWN_LAYOUT"; +}; + +inline VkFilter +convertEFilterToVkFilter(Fox::EFilter filter) +{ + switch (filter) + { + CASE(Fox::EFilter::NEAREST, VK_FILTER_NEAREST); + CASE(Fox::EFilter::LINEAR, VK_FILTER_LINEAR); + CASE(Fox::EFilter::CUBIC, VK_FILTER_CUBIC_EXT); + default: + furyassert(false); + break; // Invalid enum + } + + furyassert(false); + return VkFilter(NULL); +}; + +inline VkSamplerAddressMode +convertESamplerAddressModeToVkSamplerAddressMode(Fox::ESamplerAddressMode addressMode) +{ + switch (addressMode) + { + CASE(Fox::ESamplerAddressMode::REPEAT, VK_SAMPLER_ADDRESS_MODE_REPEAT); + CASE(Fox::ESamplerAddressMode::MIRRORED_REPEAT, VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT); + CASE(Fox::ESamplerAddressMode::CLAMP_TO_EDGE, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE); + CASE(Fox::ESamplerAddressMode::CLAMP_TO_BORDER, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER); + CASE(Fox::ESamplerAddressMode::MIRROR_CLAMP_TO_EDGE, VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE); + default: + furyassert(false); + break; // Invalid enum + } + + furyassert(false); + return VkSamplerAddressMode(NULL); +}; + +inline VkSamplerMipmapMode +convertESamplerMipmapModeToVkSamplerMipmapMode(Fox::ESamplerMipmapMode mipMapMode) +{ + switch (mipMapMode) + { + CASE(Fox::ESamplerMipmapMode::NEAREST, VK_SAMPLER_MIPMAP_MODE_NEAREST); + CASE(Fox::ESamplerMipmapMode::LINEAR, VK_SAMPLER_MIPMAP_MODE_LINEAR); + + default: + furyassert(false); + break; // Invalid enum + } + + furyassert(false); + return VkSamplerMipmapMode(NULL); +}; + } \ No newline at end of file diff --git a/src/backend/vulkan/VulkanContext.cpp b/src/backend/vulkan/VulkanContext.cpp index b166452..198ae82 100644 --- a/src/backend/vulkan/VulkanContext.cpp +++ b/src/backend/vulkan/VulkanContext.cpp @@ -4,12 +4,30 @@ #include "ResourceId.h" #include "ResourceTransfer.h" -#include "UtilsVK.h" +#include "UtilsVk.h" #include #include #include #include +#include + +// Thirdparty +#pragma warning(push) +#pragma warning(disable : 4996) +#pragma warning(disable : 4458) +#pragma warning(disable : 4244) +#pragma warning(disable : 4389) +#pragma warning(disable : 4457) +#pragma warning(disable : 4456) +#pragma warning(disable : 4267) +#pragma warning(disable : 4702) +#include "glslang/Include/glslang_c_interface.h" +#include "glslang/Public/ResourceLimits.h" +#include "glslang/Public/ShaderLang.h" +// #include "glslang/SPIRV/GlslangToSpv.h" +#include "../../thirdparty/glslang/SPIRV/GlslangToSpv.h" +#pragma warning(pop) namespace Fox { @@ -27,13 +45,13 @@ template inline T& GetResource(std::array& container, uint32_t id) { - check(id != NULL); // Uninitialized ID + furyassert(id != NULL); // Uninitialized ID const auto resourceId = ResourceId(id); - check(resourceId.First() == type); // Invalid resource id - check(resourceId.Value() < maxSize); // Must be less than array size + furyassert(resourceId.First() == type); // Invalid resource id + furyassert(resourceId.Value() < maxSize); // Must be less than array size T& element = container.at(resourceId.Value()); - check(IsValidId(element.Id)); // The object must be in valid state - check(element.Id == resourceId.Second()); // The object must have not been destroyed previously and reallocated + furyassert(IsValidId(element.Id)); // The object must be in valid state + furyassert(element.Id == resourceId.Second()); // The object must have not been destroyed previously and reallocated return element; }; @@ -42,11 +60,11 @@ inline const T& GetResource(const std::array& container, uint32_t id) { const auto resourceId = ResourceId(id); - check(resourceId.First() == type); // Invalid resource id - check(resourceId.Value() < maxSize); // Must be less than array size + furyassert(resourceId.First() == type); // Invalid resource id + furyassert(resourceId.Value() < maxSize); // Must be less than array size const T& element = container.at(resourceId.Value()); - check(IsValidId(element.Id)); // The object must be in valid state - check(element.Id == resourceId.Second()); // The object must have not been destroyed previously and reallocated + furyassert(IsValidId(element.Id)); // The object must be in valid state + furyassert(element.Id == resourceId.Second()); // The object must have not been destroyed previously and reallocated return element; }; @@ -55,8 +73,8 @@ inline T& GetResourceUnsafe(std::array& container, uint32_t id) { const auto resourceId = ResourceId(id); - check(resourceId.First() == type); // Invalid resource id - check(resourceId.Value() < maxSize); // Must be less than array size + furyassert(resourceId.First() == type); // Invalid resource id + furyassert(resourceId.Value() < maxSize); // Must be less than array size T& element = container.at(resourceId.Value()); return element; }; @@ -76,9 +94,13 @@ GenIdentifier() a = (a ^ 61) ^ (a >> 16); return a; }; - static size_t counter = 0; - const auto value = hash(counter++); - check(value != 0); // must not be 0 + static uint32_t counter{}; + auto value{ hash(counter++) }; + while (value == 0) + { + value = hash(counter++); + } + furyassert(value != 0); // must not be 0 return (uint8_t)value; } @@ -96,14 +118,14 @@ AllocResource(std::array& container) { element.Id = GenIdentifier(); } // Messy but makes sure that id is never NULL - check(element.Id != FREE); - check(element.Id != PENDING_DESTROY); + furyassert(element.Id != FREE); + furyassert(element.Id != PENDING_DESTROY); return i; } } - throw std::runtime_error("Failed to allocate!"); - return {}; + furyassert(0); // Possible memory leak, or bad usage of allocations + throw std::runtime_error(std::string("Rendering context run out of resource to allocate max") + std::to_string(container.size()) + " for " + std::type_index(typeid(T)).name()); } DRenderPassAttachments @@ -111,8 +133,8 @@ VulkanContext::_createGenericRenderPassAttachments(const DFramebufferAttachments { DRenderPassAttachments rp; - const auto attachmentCount = DFramebufferAttachments::MAX_ATTACHMENTS - std::count(att.RenderTargets.begin(), att.RenderTargets.end(), NULL); - for (size_t i = 0; i < attachmentCount; i++) + const auto attachmentCount = DFramebufferAttachments::MAX_ATTACHMENTS - std::count(att.RenderTargets.begin(), att.RenderTargets.end(), (uint32_t)0); + for (int64_t i = 0; i < attachmentCount; i++) { const auto& renderTargetRef = GetResource(_renderTargets, att.RenderTargets[i]); @@ -154,7 +176,7 @@ VulkanContext::_createGenericRenderPassAttachmentsFromPipelineAttachments(const DRenderPassAttachments rp; const auto attachmentCount = DFramebufferAttachments::MAX_ATTACHMENTS - std::count(att.RenderTargets.begin(), att.RenderTargets.end(), EFormat::INVALID); - for (size_t i = 0; i < attachmentCount; i++) + for (uint32_t i = 0; i < attachmentCount; i++) { DRenderPassAttachment o(att.RenderTargets[i], ESampleBit::COUNT_1_BIT, @@ -193,35 +215,50 @@ VulkanContext::VulkanContext(const DContextConfig* const config) : _warningOutpu _initializeDebugger(); _initializeVersion(); _initializeDevice(); - _initializeStagingBuffer(config->stagingBufferSize); + //_initializeStagingBuffer(config->stagingBufferSize); // Initialize per frame pipeline layout map to descriptor pool manager _pipelineLayoutToDescriptorPool.resize(NUM_OF_FRAMES_IN_FLIGHT); _deletionQueue.reserve(MAX_RESOURCES); - _emptyUbo.Buffer = Device.CreateBufferHostVisible(4, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT); + _emptyUbo.Buffer = Device.CreateBufferHostVisible(4, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT); + _emptySsbo.Buffer = Device.CreateBufferHostVisible(4, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); _emptyImageId = CreateImage(EFormat::R8G8B8A8_UNORM, 1, 1, 1); _emptyImage = &GetResource(_images, _emptyImageId); + _emptyStorageImageId = CreateStorageImage(EFormat::R8G8B8A8_UNORM, 1, 1, 1); + _emptyStorageImage = &GetResource(_images, _emptyStorageImageId); _emptySampler.Sampler = Device.CreateSampler(VK_FILTER_NEAREST, VK_FILTER_LINEAR, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, 0, 1, VK_SAMPLER_MIPMAP_MODE_NEAREST, false, 0.f); { // Transition to attachment optimal - const auto pool = CreateCommandPool(); + const auto graphicsQueue = FindQueue(EQueueType::QUEUE_GRAPHICS); + + const auto pool = CreateCommandPool(graphicsQueue); const auto cmd = CreateCommandBuffer(pool); BeginCommandBuffer(cmd); - TextureBarrier barrier; + TextureBarrier barrier{}; barrier.ImageId = _emptyImageId; barrier.CurrentState = EResourceState::UNDEFINED; barrier.NewState = EResourceState::SHADER_RESOURCE; ResourceBarrier(cmd, 0, nullptr, 1, &barrier, 0, nullptr); + barrier.ImageId = _emptyStorageImageId; + barrier.CurrentState = EResourceState::UNDEFINED; + barrier.NewState = EResourceState::UNORDERED_ACCESS; + ResourceBarrier(cmd, 0, nullptr, 1, &barrier, 0, nullptr); EndCommandBuffer(cmd); const auto fence = CreateFence(false); - QueueSubmit({}, {}, { cmd }, fence); + QueueSubmit(graphicsQueue, {}, {}, { cmd }, fence); WaitForFence(fence, 0xFFFFFFFF); DestroyFence(fence); DestroyCommandBuffer(cmd); DestroyCommandPool(pool); + + // DestroyQueue(graphicsQueue); + } + { + const std::string out = "Vulkan initialized"; + Log(out); } } @@ -235,6 +272,7 @@ VulkanContext::_initializeVolk() Log("Failed to initialize volk"); throw std::runtime_error("Failed to initialize volk"); } + Log("Intialized Volk"); } void @@ -249,16 +287,14 @@ VulkanContext::_initializeInstance() { throw std::runtime_error("Could not create a vulkan instance" + std::string(VkUtils::VkErrorString(result))); } + Log("Intialized vulkan instance"); } VKAPI_ATTR VkBool32 VKAPI_CALL -VulkanContext::_vulkanDebugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, -VkDebugUtilsMessageTypeFlagsEXT messageType, -const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, -void* pUserData) +VulkanContext::_vulkanDebugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT, const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, void* pUserData) { VulkanContext* context = static_cast(pUserData); - check(context); + furyassert(context); if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) { @@ -277,7 +313,7 @@ void* pUser context->Log("Validation layer[INFO]: " + std::string(pCallbackData->pMessage)); } - // check(false); + // furyassert(false); return VK_FALSE; } @@ -290,37 +326,41 @@ VulkanContext::_initializeDebugger() { Warning("Failed to create vulkan debug utils messenger"); } + Log("Intialized vulkan debugger"); #endif } void VulkanContext::_initializeVersion() { - auto FN_vkEnumerateInstanceVersion = PFN_vkEnumerateInstanceVersion(vkGetInstanceProcAddr(nullptr, "vkEnumerateInstanceVersion")); + if (vkEnumerateInstanceVersion == nullptr) + { + // Manually getting function + vkEnumerateInstanceVersion = PFN_vkEnumerateInstanceVersion(vkGetInstanceProcAddr(nullptr, "vkEnumerateInstanceVersion")); + } + if (vkEnumerateInstanceVersion == nullptr) { Warning("Failed to vkGetInstanceProcAddr for vkEnumerateInstanceVersion"); } + + uint32_t instanceVersion = VK_API_VERSION_1_0; + const VkResult result = vkEnumerateInstanceVersion(&instanceVersion); + if (VKFAILED(result)) + { + const std::string out = "Failed to vkEnumerateInstanceVersion because:" + std::string(VkUtils::VkErrorString(result)); + Warning(out); + } else { - uint32_t instanceVersion = VK_API_VERSION_1_0; - const VkResult result = vkEnumerateInstanceVersion(&instanceVersion); - if (VKFAILED(result)) - { - const std::string out = "Failed to vkEnumerateInstanceVersion because:" + std::string(VkUtils::VkErrorString(result)); - Warning(out); - } - else - { - // Extract version info - uint32_t major, minor, patch; - major = VK_API_VERSION_MAJOR(instanceVersion); - minor = VK_API_VERSION_MINOR(instanceVersion); - patch = VK_API_VERSION_PATCH(instanceVersion); - - const std::string out = "Vulkan version:" + std::to_string(major) + "." + std::to_string(minor) + "." + std::to_string(patch); - Log(out); - } + // Extract version info + uint32_t major, minor, patch; + major = VK_API_VERSION_MAJOR(instanceVersion); + minor = VK_API_VERSION_MINOR(instanceVersion); + patch = VK_API_VERSION_PATCH(instanceVersion); + + const std::string out = "Vulkan version:" + std::to_string(major) + "." + std::to_string(minor) + "." + std::to_string(patch); + Log(out); } } @@ -348,15 +388,19 @@ VulkanContext::_initializeDevice() // binding flags for textures, uniforms, and buffers // are required for our extension critical(descriptorIndexingFeatures.shaderSampledImageArrayNonUniformIndexing); - critical(descriptorIndexingFeatures.descriptorBindingSampledImageUpdateAfterBind); + // critical(descriptorIndexingFeatures.descriptorBindingSampledImageUpdateAfterBind); critical(descriptorIndexingFeatures.shaderUniformBufferArrayNonUniformIndexing); - critical(descriptorIndexingFeatures.descriptorBindingUniformBufferUpdateAfterBind); + // critical(descriptorIndexingFeatures.descriptorBindingUniformBufferUpdateAfterBind); critical(descriptorIndexingFeatures.shaderStorageBufferArrayNonUniformIndexing); - critical(descriptorIndexingFeatures.descriptorBindingStorageBufferUpdateAfterBind); + // critical(descriptorIndexingFeatures.descriptorBindingStorageBufferUpdateAfterBind); - // Check validation layers and extensions support for the device +// Check validation layers and extensions support for the device +#if _DEBUG auto validDeviceValidationLayers = _getDeviceSupportedValidationLayers(physicalDevice, _validationLayers); - auto validDeviceExtensions = _getDeviceSupportedExtensions(physicalDevice, _deviceExtensionNames); +#else + const std::vector validDeviceValidationLayers{}; +#endif + auto validDeviceExtensions = _getDeviceSupportedExtensions(physicalDevice, _deviceExtensionNames); // Create device const auto result = Device.Create(Instance, (void*)&pDeviceFeatures, physicalDevice, validDeviceExtensions, nullptr, validDeviceValidationLayers); @@ -367,6 +411,27 @@ VulkanContext::_initializeDevice() // replacing global function pointers with functions retrieved with vkGetDeviceProcAddr volkLoadDevice(Device.Device); + + // track count of queue instantiated from each family; + std::fill(_queueFamilyIndexCreatedCount.begin(), _queueFamilyIndexCreatedCount.end(), 0); + + Log("Intialized vulkan device"); + + if (validDeviceValidationLayers.size()) + { + std::string buf{ "Enabled device validation layers:\n" }; + + for (const auto& layer : validDeviceValidationLayers) + { + buf += layer; + buf += "\n"; + } + Log(buf); + } + + VkPhysicalDeviceProperties deviceProperties; + vkGetPhysicalDeviceProperties(Device.PhysicalDevice, &deviceProperties); + Log(std::string("Device: ") + deviceProperties.deviceName); } void @@ -399,23 +464,53 @@ VulkanContext::~VulkanContext() fbo.Id = FREE; } + Device.DestroyBuffer(_emptyUbo.Buffer); + Device.DestroyBuffer(_emptySsbo.Buffer); + DestroyImage(_emptyImageId); + DestroyImage(_emptyStorageImageId); + Device.DestroySampler(_emptySampler.Sampler); + #if _DEBUG - const auto validSwapchainsCount = std::count_if(_swapchains.begin(), _swapchains.end(), [](const DSwapchainVulkan& swapchain) { return IsValidId(swapchain.Id); }); - check(validSwapchainsCount == 0); - const auto validVertexBufferCount = std::count_if(_vertexBuffers.begin(), _vertexBuffers.end(), [](const DBufferVulkan& buffer) { return IsValidId(buffer.Id); }); - check(validVertexBufferCount == 0); - const auto validUniformBufferCount = std::count_if(_uniformBuffers.begin(), _uniformBuffers.end(), [](const DBufferVulkan& buffer) { return IsValidId(buffer.Id); }); - check(validUniformBufferCount == 0); - const auto validFramebufferCount = std::count_if(_framebuffers.begin(), _framebuffers.end(), [](const DFramebufferVulkan& buffer) { return IsValidId(buffer.Id); }); - check(validFramebufferCount == 0); - const auto validShaderCount = std::count_if(_shaders.begin(), _shaders.end(), [](const DShaderVulkan& shader) { return IsValidId(shader.Id); }); - check(validShaderCount == 0); + const auto validVertexBufferCount = std::count_if(_vertexBuffers.begin(), _vertexBuffers.end(), [](const DBufferVulkan& e) { return IsValidId(e.Id); }); + const auto validTransferBufferCount = std::count_if(_transferBuffers.begin(), _transferBuffers.end(), [](const DBufferVulkan& e) { return IsValidId(e.Id); }); + const auto validUboCount = std::count_if(_uniformBuffers.begin(), _uniformBuffers.end(), [](const DBufferVulkan& e) { return IsValidId(e.Id); }); + const auto validIndirectBufferCount = std::count_if(_indirectBuffers.begin(), _indirectBuffers.end(), [](const DBufferVulkan& e) { return IsValidId(e.Id); }); + const auto validSwapchainsCount = std::count_if(_swapchains.begin(), _swapchains.end(), [](const DSwapchainVulkan& swapchain) { return IsValidId(swapchain.Id); }); + const auto validFramebufferCount = std::count_if(_framebuffers.begin(), _framebuffers.end(), [](const DFramebufferVulkan& buffer) { return IsValidId(buffer.Id); }); + const auto validShaderCount = std::count_if(_shaders.begin(), _shaders.end(), [](const DShaderVulkan& shader) { return IsValidId(shader.Id); }); + const auto validImageCount = std::count_if(_images.begin(), _images.end(), [](const DImageVulkan& e) { return IsValidId(e.Id); }); + const auto validPipelineCount = std::count_if(_pipelines.begin(), _pipelines.end(), [](const DPipelineVulkan& e) { return IsValidId(e.Id); }); + const auto validFenceCount = std::count_if(_fences.begin(), _fences.end(), [](const DFenceVulkan& e) { return IsValidId(e.Id); }); + const auto validSamplerCount = std::count_if(_samplers.begin(), _samplers.end(), [](const DSamplerVulkan& e) { return IsValidId(e.Id); }); + const auto validCmdPoolCount = std::count_if(_commandPools.begin(), _commandPools.end(), [](const DCommandPoolVulkan& e) { return IsValidId(e.Id); }); + const auto validRootSigCount = std::count_if(_rootSignatures.begin(), _rootSignatures.end(), [](const DRootSignature& e) { return IsValidId(e.Id); }); + const auto validRTCount = std::count_if(_renderTargets.begin(), _renderTargets.end(), [](const DRenderTargetVulkan& e) { return IsValidId(e.Id); }); + const auto validDescSetCount = std::count_if(_descriptorSets.begin(), _descriptorSets.end(), [](const DDescriptorSet& e) { return IsValidId(e.Id); }); + const auto validCmdBufCount = std::count_if(_commandBuffers.begin(), _commandBuffers.end(), [](const DCommandBufferVulkan& e) { return IsValidId(e.Id); }); + + furyassert(validVertexBufferCount == 0); + furyassert(validTransferBufferCount == 0); + furyassert(validUboCount == 0); + furyassert(validIndirectBufferCount == 0); + furyassert(validSwapchainsCount == 0); + furyassert(validFramebufferCount == 0); + furyassert(validShaderCount == 0); + furyassert(validImageCount == 0); + furyassert(validPipelineCount == 0); + furyassert(validFenceCount == 0); + furyassert(validSamplerCount == 0); + furyassert(validCmdPoolCount == 0); + furyassert(validRootSigCount == 0); + furyassert(validRTCount == 0); + furyassert(validDescSetCount == 0); + furyassert(validCmdBufCount == 0); + #endif // Destroy all descriptor pools managers _pipelineLayoutToDescriptorPool.clear(); - _deinitializeStagingBuffer(); + //_deinitializeStagingBuffer(); FlushDeletedBuffers(); @@ -429,6 +524,68 @@ VulkanContext::~VulkanContext() Instance.Deinit(); } +bool +VulkanContext::CompileNativeShader(const std::vector& blob, std::vector& outShader, EShaderStage shaderStage, std::string& errorMgs) +{ + // spirv_cross::CompilerGLSL compilerGLSL(reinterpret_cast(blob.data()), blob.size() / sizeof(uint32_t)); + + //// Compile the GLSL code into SPIR-V + // spirv_cross::CompilerGLSL::Options options; + // options.version = 450; // Set GLSL version (e.g., 450 for GLSL 4.50) + // compilerGLSL.set_common_options(options); + // auto spirv = compilerGLSL.compile(); + + // Initialize glslang + glslang::InitializeProcess(); + + EShLanguage language{ EShLangVertex }; + switch (shaderStage) + { + case EShaderStage::VERTEX: + language = EShLangVertex; + break; + case EShaderStage::FRAGMENT: + language = EShLangFragment; + break; + case EShaderStage::COMPUTE: + language = EShLangCompute; + break; + default: + furyassert(0); // Invalid shader stage choice + break; + } + + // Create glslang compiler + const char* shaderSource{ reinterpret_cast(blob.data()) }; + const int l{ (int)blob.size() }; + glslang::TShader* shader(new glslang::TShader(language)); + + shader->setStringsWithLengths(&shaderSource, &l, 1); + shader->setEntryPoint("main"); + if (!shader->parse(GetDefaultResources(), 100, false, (EShMessages)(EShMsgSpvRules | EShMsgVulkanRules))) + { + errorMgs = shader->getInfoLog(); + return false; + } + + glslang::TProgram* program{ new glslang::TProgram() }; + program->addShader(shader); + + if (!program->link((EShMessages)(EShMsgSpvRules | EShMsgVulkanRules))) + { + errorMgs = shader->getInfoLog(); + return false; + } + + glslang::GlslangToSpv(*program->getIntermediate(language), outShader); + + delete program; + delete shader; + glslang::FinalizeProcess(); + + return true; +} + void VulkanContext::WaitDeviceIdle() { @@ -440,12 +597,14 @@ VulkanContext::CreateSwapchain(const WindowData* windowData, EPresentMode& prese { const auto index = AllocResource(_swapchains); DSwapchainVulkan& swapchain = _swapchains.at(index); + swapchain.Surface = nullptr; + swapchain.Swapchain = nullptr; _createSwapchain(swapchain, windowData, presentMode, outFormat); if (width != nullptr) { - check(height != nullptr); + furyassert(height != nullptr); *width = swapchain.Capabilities.currentExtent.width; *height = swapchain.Capabilities.currentExtent.height; } @@ -466,6 +625,20 @@ VulkanContext::_createSwapchain(DSwapchainVulkan& swapchain, const WindowData* w } } + // Find presentable graphics queue + /* + { + uint32_t queueIndexCount[16]{}; + const auto foundGraphicsQueueId{ VkUtils::findQueueWithFlags( + &swapchain.QueueFamilyIndex, &swapchain.QueueIndex, VK_QUEUE_GRAPHICS_BIT, Device.QueueFamilies.data(), (uint32_t)Device.QueueFamilies.size(), queueIndexCount) }; + const bool supportPresentation{ Device.SurfaceSupportPresentationOnQueueFamilyIndex(surface, swapchain.QueueFamilyIndex) }; + if (!supportPresentation) + { + throw std::runtime_error("Vulkan graphics queue does not support presentation to this surface!"); + } + } + */ + // Query formats present mode and capabilities const auto formats = Device.GetSurfaceFormats(surface); outFormat = VkUtils::convertVkFormat(formats.front().format); @@ -482,14 +655,17 @@ VulkanContext::_createSwapchain(DSwapchainVulkan& swapchain, const WindowData* w const auto capabilities = Device.GetSurfaceCapabilities(surface); // Create swapchain object + furyassert(swapchain.Swapchain == nullptr); VkSwapchainKHR vkSwapchain{}; - { - const auto result = Device.CreateSwapchainFromSurface(surface, formats.at(0), vkPresentMode, capabilities, &vkSwapchain); - if (VKFAILED(result)) - { - throw std::runtime_error("Failed to create swapchain " + std::string(VkUtils::VkErrorString(result))); - } - } + // Only create swapchain when extent is meaningful as > 0px + if (capabilities.currentExtent.width > 0 && capabilities.currentExtent.height > 0) + { + const auto result = Device.CreateSwapchainFromSurface(surface, formats.at(0), vkPresentMode, capabilities, &swapchain.QueueFamilyIndex, 1, &vkSwapchain); + if (VKFAILED(result)) + { + throw std::runtime_error("Failed to create swapchain " + std::string(VkUtils::VkErrorString(result))); + } + } // Setup new object swapchain.Surface = surface; swapchain.Capabilities = capabilities; @@ -497,30 +673,42 @@ VulkanContext::_createSwapchain(DSwapchainVulkan& swapchain, const WindowData* w swapchain.PresentMode = vkPresentMode; swapchain.Swapchain = vkSwapchain; - const auto swapchainImages = Device.GetSwapchainImages(vkSwapchain); - swapchain.ImagesCount = swapchainImages.size(); - for (size_t i = 0; i < swapchainImages.size(); i++) + // Reset the images/render targers ids + for (size_t i = 0; i < DSwapchainVulkan::MAX_IMAGE_COUNT; i++) { - swapchain.ImagesId[i] = _createImageFromVkImage(swapchainImages.at(i), swapchain.Format.format, swapchain.Capabilities.currentExtent.width, swapchain.Capabilities.currentExtent.height); + swapchain.ImagesId[i] = 0; + swapchain.RenderTargetsId[i] = 0; } - // Create render targets - for (size_t i = 0; i < swapchainImages.size(); i++) + // Only create image views and render targets when a swapchain was created + if (vkSwapchain != NULL) { - const auto index = AllocResource(_renderTargets); - auto& renderTargetRef = _renderTargets.at(index); - - const auto& imageRef = GetResource(_images, swapchain.ImagesId[i]); - renderTargetRef.Image = imageRef.Image; - renderTargetRef.ImageAspect = imageRef.ImageAspect; - - const auto result = Device.CreateImageView(imageRef.Image.Format, imageRef.Image.Image, imageRef.ImageAspect, 0, 1, &renderTargetRef.View); - if (VKFAILED(result)) + const auto swapchainImages = Device.GetSwapchainImages(vkSwapchain); + swapchain.ImagesCount = (uint32_t)swapchainImages.size(); + for (size_t i = 0; i < swapchainImages.size(); i++) { - throw std::runtime_error("Failed to create swapchain imageView " + std::string(VkUtils::VkErrorString(result))); + swapchain.ImagesId[i] = + _createImageFromVkImage(swapchainImages.at(i), swapchain.Format.format, swapchain.Capabilities.currentExtent.width, swapchain.Capabilities.currentExtent.height); } - swapchain.RenderTargetsId[i] = *ResourceId(EResourceType::RENDER_TARGET, renderTargetRef.Id, index); + // Create render targets + for (size_t i = 0; i < swapchainImages.size(); i++) + { + const auto index = AllocResource(_renderTargets); + auto& renderTargetRef = _renderTargets.at(index); + + const auto& imageRef = GetResource(_images, swapchain.ImagesId[i]); + renderTargetRef.Image = imageRef.Image; + renderTargetRef.ImageAspect = imageRef.ImageAspect; + + const auto result = Device.CreateImageView(imageRef.Image.Format, imageRef.Image.Image, imageRef.ImageAspect, 0, 1, &renderTargetRef.View); + if (VKFAILED(result)) + { + throw std::runtime_error("Failed to create swapchain imageView " + std::string(VkUtils::VkErrorString(result))); + } + + swapchain.RenderTargetsId[i] = *ResourceId(EResourceType::RENDER_TARGET, renderTargetRef.Id, index); + } } } @@ -529,19 +717,139 @@ VulkanContext::GetSwapchainRenderTargets(SwapchainId swapchainId) { ResourceId resource(swapchainId); - check(resource.First() == EResourceType::SWAPCHAIN); + furyassert(resource.First() == EResourceType::SWAPCHAIN); DSwapchainVulkan& swapchain = GetResource(_swapchains, swapchainId); - std::vector images; - images.resize(swapchain.ImagesCount); + // If has no swapchain return none + if (swapchain.Swapchain == NULL) + { + return {}; + } + + std::vector rts; + rts.resize(swapchain.ImagesCount); for (size_t i = 0; i < swapchain.ImagesCount; i++) { - images[i] = swapchain.RenderTargetsId[i]; + rts[i] = swapchain.RenderTargetsId[i]; } - return images; + return rts; +} + +bool +VulkanContext::SwapchainHasValidSurface(SwapchainId swapchainId) +{ + DSwapchainVulkan& swapchain = GetResource(_swapchains, swapchainId); + swapchain.Capabilities = Device.GetSurfaceCapabilities(swapchain.Surface); + + if (swapchain.Capabilities.currentExtent.width == 0 || swapchain.Capabilities.currentExtent.height == 0) + { + // Destroy swapchain and imaged and RT + if (swapchain.Swapchain) + { + Device.DestroySwapchain(swapchain.Swapchain); + swapchain.Swapchain = nullptr; + + for (uint32_t i = 0; i < swapchain.ImagesCount; i++) + { + auto& imageRef = GetResource(_images, swapchain.ImagesId[i]); + + for (auto it = imageRef.ImageViews.begin(); it != imageRef.ImageViews.end(); it++) + { + Device.DestroyImageView(it->second); + } + + imageRef.Id = FREE; + + const auto renderTargetId{ swapchain.RenderTargetsId[i] }; + auto& renderTargetRef = GetResource(_renderTargets, renderTargetId); + + Device.DestroyImageView(renderTargetRef.View); + renderTargetRef.Id = FREE; + + // Must destroy all framebuffers that reference this render target @TODO find a better algorithm without iterating over the array multiple times + const auto referenceCount = std::count_if(_framebuffers.begin(), _framebuffers.end(), [renderTargetId](const DFramebufferVulkan& fbo) { + for (uint32_t j = 0; j < DFramebufferAttachments::MAX_ATTACHMENTS; j++) + { + if (fbo.Attachments.RenderTargets[j] == renderTargetId) + { + return true; + } + } + return false; + }); + for (uint32_t j = 0; j < referenceCount; j++) + { + auto foundFbo = std::find_if(_framebuffers.begin(), _framebuffers.end(), [renderTargetId](const DFramebufferVulkan& fbo) { + for (uint32_t k = 0; k < DFramebufferAttachments::MAX_ATTACHMENTS; k++) + { + if (fbo.Attachments.RenderTargets[k] == renderTargetId) + { + return true; + } + } + return false; + }); + + Device._destroyFramebuffer(foundFbo->Framebuffer); + foundFbo->Id = FREE; + } + } + + std::fill(swapchain.ImagesId.begin(), swapchain.ImagesId.end(), 0); + std::fill(swapchain.RenderTargetsId, swapchain.RenderTargetsId + DSwapchainVulkan::MAX_IMAGE_COUNT, 0); + } + + return false; + } + + if (swapchain.Swapchain != NULL) + { + return true; + } + + // Create swapchain object + { + const auto result = Device.CreateSwapchainFromSurface(swapchain.Surface, swapchain.Format, swapchain.PresentMode, swapchain.Capabilities, &swapchain.QueueFamilyIndex, 1, &swapchain.Swapchain); + if (VKFAILED(result)) + { + throw std::runtime_error("Failed to create swapchain " + std::string(VkUtils::VkErrorString(result))); + } + } + + // Recreate images and RTs + { + const auto swapchainImages = Device.GetSwapchainImages(swapchain.Swapchain); + swapchain.ImagesCount = (uint32_t)swapchainImages.size(); + for (size_t i = 0; i < swapchainImages.size(); i++) + { + swapchain.ImagesId[i] = + _createImageFromVkImage(swapchainImages.at(i), swapchain.Format.format, swapchain.Capabilities.currentExtent.width, swapchain.Capabilities.currentExtent.height); + } + + // Create render targets + for (size_t i = 0; i < swapchainImages.size(); i++) + { + const auto index = AllocResource(_renderTargets); + auto& renderTargetRef = _renderTargets.at(index); + + const auto& imageRef = GetResource(_images, swapchain.ImagesId[i]); + renderTargetRef.Image = imageRef.Image; + renderTargetRef.ImageAspect = imageRef.ImageAspect; + + const auto result = Device.CreateImageView(imageRef.Image.Format, imageRef.Image.Image, imageRef.ImageAspect, 0, 1, &renderTargetRef.View); + if (VKFAILED(result)) + { + throw std::runtime_error("Failed to create swapchain imageView " + std::string(VkUtils::VkErrorString(result))); + } + + swapchain.RenderTargetsId[i] = *ResourceId(EResourceType::RENDER_TARGET, renderTargetRef.Id, index); + } + } + + return true; } bool @@ -550,6 +858,11 @@ VulkanContext::SwapchainAcquireNextImageIndex(SwapchainId swapchainId, uint64_t DSwapchainVulkan& swapchain = GetResource(_swapchains, swapchainId); DSemaphoreVulkan& semaphoreRef = GetResource(_semaphores, sempahoreid); + if (swapchain.Swapchain == NULL) + { + return false; + } + const VkResult result = Device.AcquireNextImage(swapchain.Swapchain, timeoutNanoseconds, outImageIndex, semaphoreRef.Semaphore, VK_NULL_HANDLE); /*Spec: https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/vkQueueSubmit.html*/ /* @@ -610,13 +923,6 @@ VulkanContext::_createImageFromVkImage(VkImage vkimage, VkFormat format, uint32_ // Create renderTargetRef view image.ImageAspect = VkUtils::isColorFormat(format) ? VK_IMAGE_ASPECT_COLOR_BIT : VK_IMAGE_ASPECT_DEPTH_BIT; - { - const VkResult result = Device.CreateImageView(format, image.Image.Image, image.ImageAspect, 0, 1, &image.View); - if (VKFAILED(result)) - { - throw std::runtime_error(VkUtils::VkErrorString(result)); - } - } return *ResourceId(EResourceType::IMAGE, image.Id, index); } @@ -626,60 +932,110 @@ VulkanContext::DestroySwapchain(SwapchainId swapchainId) { ResourceId resource(swapchainId); - check(resource.First() == EResourceType::SWAPCHAIN); + furyassert(resource.First() == EResourceType::SWAPCHAIN); DSwapchainVulkan& swapchain = GetResource(_swapchains, swapchainId); + if (swapchain.Swapchain) + { + Device.DestroySwapchain(swapchain.Swapchain); - Device.DestroySwapchain(swapchain.Swapchain); - Instance.DestroySurface(swapchain.Surface); + for (uint32_t i = 0; i < swapchain.ImagesCount; i++) + { + auto& imageRef = GetResource(_images, swapchain.ImagesId[i]); - swapchain.Id = FREE; + for (auto it = imageRef.ImageViews.begin(); it != imageRef.ImageViews.end(); it++) + { + Device.DestroyImageView(it->second); + } - for (uint32_t i = 0; i < swapchain.ImagesCount; i++) - { - auto& imageRef = GetResource(_images, swapchain.ImagesId[i]); - Device.DestroyImageView(imageRef.View); - imageRef.Id = FREE; + imageRef.Id = FREE; - const auto renderTargetId{ swapchain.RenderTargetsId[i] }; - auto& renderTargetRef = GetResource(_renderTargets, renderTargetId); + const auto renderTargetId{ swapchain.RenderTargetsId[i] }; + auto& renderTargetRef = GetResource(_renderTargets, renderTargetId); - Device.DestroyImageView(renderTargetRef.View); - renderTargetRef.Id = FREE; + Device.DestroyImageView(renderTargetRef.View); + renderTargetRef.Id = FREE; - // Must destroy all framebuffers that reference this render target @TODO find a better algorithm without iterating over the array multiple times - const auto referenceCount = std::count_if(_framebuffers.begin(), _framebuffers.end(), [renderTargetId](const DFramebufferVulkan& fbo) { - for (size_t i = 0; i < DFramebufferAttachments::MAX_ATTACHMENTS; i++) - { - if (fbo.Attachments.RenderTargets[i] == renderTargetId) - { - return true; - } - } - return false; - }); - for (uint32_t i = 0; i < referenceCount; i++) - { - auto foundFbo = std::find_if(_framebuffers.begin(), _framebuffers.end(), [renderTargetId](const DFramebufferVulkan& fbo) { - for (size_t i = 0; i < DFramebufferAttachments::MAX_ATTACHMENTS; i++) + // Must destroy all framebuffers that reference this render target @TODO find a better algorithm without iterating over the array multiple times + const auto referenceCount = std::count_if(_framebuffers.begin(), _framebuffers.end(), [renderTargetId](const DFramebufferVulkan& fbo) { + for (size_t j = 0; j < DFramebufferAttachments::MAX_ATTACHMENTS; j++) { - if (fbo.Attachments.RenderTargets[i] == renderTargetId) + if (fbo.Attachments.RenderTargets[j] == renderTargetId) { return true; } } return false; }); + for (uint32_t j = 0; j < referenceCount; j++) + { + auto foundFbo = std::find_if(_framebuffers.begin(), _framebuffers.end(), [renderTargetId](const DFramebufferVulkan& fbo) { + for (size_t k = 0; k < DFramebufferAttachments::MAX_ATTACHMENTS; k++) + { + if (fbo.Attachments.RenderTargets[k] == renderTargetId) + { + return true; + } + } + return false; + }); - Device._destroyFramebuffer(foundFbo->Framebuffer); - foundFbo->Id = FREE; + Device._destroyFramebuffer(foundFbo->Framebuffer); + foundFbo->Id = FREE; + } } } + + // Destroy surface always after the swapchain + Instance.DestroySurface(swapchain.Surface); swapchain.ImagesCount = 0; swapchain.Id = FREE; } +uint32_t +VulkanContext::FindQueue(EQueueType queueType) +{ + uint32_t familyIndex{}; + uint32_t queueIndex{}; + + const uint32_t vkFlags{ VkUtils::convertQueueTypeToVkFlags(queueType) }; + const bool found{ VkUtils::findQueueWithFlags(&familyIndex, &queueIndex, vkFlags, Device.QueueFamilies.data(), (uint32_t)Device.QueueFamilies.size(), _queueFamilyIndexCreatedCount.data()) }; + + if (!found) + { + // No queue family has this flag. + return 0; + } + + // Find already allocated queue object + for (uint32_t i = 0; i < MAX_RESOURCES; i++) + { + const auto& queueRef = _queues.at(i); + if (queueRef.Id == FREE) + { + break; + } + + if (queueRef.QueueFamilyIndex == familyIndex && queueRef.QueueIndex == queueIndex) + { + return *ResourceId(EResourceType::QUEUE, queueRef.Id, i); + } + } + + // Allocate new queue object + { + const auto index = AllocResource(_queues); + auto& queueRef = _queues.at(index); + queueRef.QueueFamilyIndex = familyIndex; + queueRef.QueueIndex = queueIndex; + vkGetDeviceQueue(Device.Device, familyIndex, queueIndex, &queueRef.QueuePtr); + queueRef.Type = queueType; + + return *ResourceId(EResourceType::QUEUE, queueRef.Id, index); + } +} + BufferId VulkanContext::CreateBuffer(uint32_t size, EResourceType type, EMemoryUsage usage) { @@ -693,6 +1049,11 @@ VulkanContext::CreateBuffer(uint32_t size, EResourceType type, EMemoryUsage usag index = AllocResource(_uniformBuffers); buffer = &_uniformBuffers.at(index); break; + case EResourceType::STORAGE_BUFFER: + usageFlags = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; + index = AllocResource(_storageBuffers); + buffer = &_storageBuffers.at(index); + break; case EResourceType::VERTEX_INDEX_BUFFER: index = AllocResource(_vertexBuffers); usageFlags = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT; @@ -709,11 +1070,12 @@ VulkanContext::CreateBuffer(uint32_t size, EResourceType type, EMemoryUsage usag buffer = &_indirectBuffers.at(index); break; default: - check(0); // Invalid type + furyassert(0); // Invalid type break; } buffer->Size = size; + furyassert(usageFlags != 0); switch (usage) { @@ -733,7 +1095,7 @@ VulkanContext::CreateBuffer(uint32_t size, EResourceType type, EMemoryUsage usag } break; default: - check(0); // invalid usage + furyassert(0); // invalid usage break; } @@ -752,6 +1114,9 @@ VulkanContext::BeginMapBuffer(BufferId buffer) case EResourceType::UNIFORM_BUFFER: bufferPtr = &_uniformBuffers.at(index); break; + case EResourceType::STORAGE_BUFFER: + bufferPtr = &_storageBuffers.at(index); + break; case EResourceType::VERTEX_INDEX_BUFFER: bufferPtr = &_vertexBuffers.at(index); break; @@ -762,11 +1127,11 @@ VulkanContext::BeginMapBuffer(BufferId buffer) bufferPtr = &_indirectBuffers.at(index); break; default: - check(0); // Invalid type + furyassert(0); // Invalid type break; } - check(bufferPtr->Buffer.IsMappable); // Must be mappable flag + furyassert(bufferPtr->Buffer.IsMappable); // Must be mappable flag return Device.MapBuffer(bufferPtr->Buffer); } @@ -782,6 +1147,9 @@ VulkanContext::EndMapBuffer(BufferId buffer) case EResourceType::UNIFORM_BUFFER: bufferPtr = &_uniformBuffers.at(index); break; + case EResourceType::STORAGE_BUFFER: + bufferPtr = &_storageBuffers.at(index); + break; case EResourceType::VERTEX_INDEX_BUFFER: bufferPtr = &_vertexBuffers.at(index); break; @@ -792,18 +1160,17 @@ VulkanContext::EndMapBuffer(BufferId buffer) bufferPtr = &_indirectBuffers.at(index); break; default: - check(0); // Invalid type + furyassert(0); // Invalid type break; } - check(bufferPtr->Buffer.IsMappable); // Must be mappable flag + furyassert(bufferPtr->Buffer.IsMappable); // Must be mappable flag return Device.UnmapBuffer(bufferPtr->Buffer); } void VulkanContext::DestroyBuffer(BufferId buffer) { - const auto resourceType = ResourceId(buffer).First(); const auto index = ResourceId(buffer).Value(); DBufferVulkan* bufferPtr{}; @@ -813,6 +1180,9 @@ VulkanContext::DestroyBuffer(BufferId buffer) case EResourceType::UNIFORM_BUFFER: bufferPtr = &_uniformBuffers.at(index); break; + case EResourceType::STORAGE_BUFFER: + bufferPtr = &_storageBuffers.at(index); + break; case EResourceType::VERTEX_INDEX_BUFFER: bufferPtr = &_vertexBuffers.at(index); break; @@ -820,16 +1190,16 @@ VulkanContext::DestroyBuffer(BufferId buffer) bufferPtr = &_transferBuffers.at(index); break; default: - check(0); // Invalid type + furyassert(0); // Invalid type break; } - check(IsValidId(bufferPtr->Id)); + furyassert(IsValidId(bufferPtr->Id)); bufferPtr->Id = FREE; Device.DestroyBuffer(bufferPtr->Buffer); } ImageId -VulkanContext::CreateImage(EFormat format, uint32_t width, uint32_t height, uint32_t mipMapCount) +VulkanContext::CreateImage(EFormat format, uint32_t width, uint32_t height, uint32_t mipMapCount, bool isDepth, bool isStencil) { const auto index = AllocResource(_images); @@ -846,16 +1216,44 @@ VulkanContext::CreateImage(EFormat format, uint32_t width, uint32_t height, uint VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_LAYOUT_UNDEFINED); - image.ImageAspect = VkUtils::isColorFormat(vkFormat) ? VK_IMAGE_ASPECT_COLOR_BIT : VK_IMAGE_ASPECT_DEPTH_BIT; + image.ImageAspect = VkUtils::isColorFormat(vkFormat) && (!isDepth && !isStencil) ? VK_IMAGE_ASPECT_COLOR_BIT : VK_IMAGE_ASPECT_DEPTH_BIT; + if (VkUtils::formatHasStencil(vkFormat) || isStencil) + { + image.ImageAspect |= VK_IMAGE_ASPECT_STENCIL_BIT; + } - const VkResult result = Device.CreateImageView(vkFormat, image.Image.Image, image.ImageAspect, 0, mipMapCount, &image.View); - if (VKFAILED(result)) + // Create default sampler + image.Sampler = Device.CreateSampler(VK_FILTER_NEAREST, VK_FILTER_LINEAR, VK_SAMPLER_ADDRESS_MODE_REPEAT, (float)0, (float)mipMapCount, VK_SAMPLER_MIPMAP_MODE_NEAREST, true, 16); + + return *ResourceId(EResourceType::IMAGE, image.Id, index); +} + +ImageId +VulkanContext::CreateStorageImage(EFormat format, uint32_t width, uint32_t height, uint32_t mipMapCount, bool isDepth, bool isStencil) +{ + + const auto index = AllocResource(_images); + DImageVulkan& image = _images.at(index); + + const auto vkFormat = VkUtils::convertFormat(format); + + const VkImageUsageFlags fomatAttachment = 0; // VkUtils::isColorFormat(vkFormat) ? VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT : VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; + image.Image = Device.CreateImageDeviceLocal(width, + height, + mipMapCount, + vkFormat, + VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | fomatAttachment | VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, + VK_IMAGE_TILING_OPTIMAL, + VK_IMAGE_LAYOUT_UNDEFINED); + + image.ImageAspect = VkUtils::isColorFormat(vkFormat) ? VK_IMAGE_ASPECT_COLOR_BIT : VK_IMAGE_ASPECT_DEPTH_BIT; + if (VkUtils::formatHasStencil(vkFormat)) { - throw std::runtime_error(VkUtils::VkErrorString(result)); + image.ImageAspect |= VK_IMAGE_ASPECT_STENCIL_BIT; } // Create default sampler - image.Sampler = Device.CreateSampler(VK_FILTER_NEAREST, VK_FILTER_LINEAR, VK_SAMPLER_ADDRESS_MODE_REPEAT, 0, mipMapCount, VK_SAMPLER_MIPMAP_MODE_NEAREST, true, 16); + image.Sampler = Device.CreateSampler(VK_FILTER_NEAREST, VK_FILTER_LINEAR, VK_SAMPLER_ADDRESS_MODE_REPEAT, (float)0, (float)mipMapCount, VK_SAMPLER_MIPMAP_MODE_NEAREST, true, 16); return *ResourceId(EResourceType::IMAGE, image.Id, index); } @@ -872,18 +1270,28 @@ void VulkanContext::DestroyImage(ImageId imageId) { auto& resource = GetResourceUnsafe(_images, imageId); - check(IsValidId(resource.Id)); + furyassert(IsValidId(resource.Id)); resource.Id = PENDING_DESTROY; - _deferDestruction([this, imageId]() { - auto& resource = GetResourceUnsafe(_images, imageId); + //_deferDestruction([this, imageId]() { + // auto& resource = GetResourceUnsafe(_images, imageId); - Device.DestroyImageView(resource.View); - Device.DestroyImage(resource.Image); - Device.DestroySampler(resource.Sampler); + // Device.DestroyImageView(resource.View); + // Device.DestroyImage(resource.Image); + // Device.DestroySampler(resource.Sampler); - resource.Id = FREE; - }); + // resource.Id = FREE; + //}); + + for (auto it = resource.ImageViews.begin(); it != resource.ImageViews.end(); it++) + { + Device.DestroyImageView(it->second); + } + + Device.DestroyImage(resource.Image); + Device.DestroySampler(resource.Sampler); + resource.Id = FREE; + resource = {}; } VertexInputLayoutId @@ -912,11 +1320,10 @@ VulkanContext::CreateVertexLayout(const std::vector& info) ShaderId VulkanContext::CreateShader(const ShaderSource& source) { - check(source.ColorAttachments > 0); + // furyassert(source.ColorAttachments > 0); const auto index = AllocResource(_shaders); DShaderVulkan& shader = _shaders.at(index); - shader.Id = GenIdentifier(); _createShader(source, _shaders.at(index)); @@ -926,8 +1333,6 @@ VulkanContext::CreateShader(const ShaderSource& source) void VulkanContext::_createShader(const ShaderSource& source, DShaderVulkan& shader) { - constexpr uint32_t MAX_SETS_PER_POOL = 100; // Temporary, should not have a limit pool of pools - shader.VertexLayout = source.VertexLayout; shader.VertexStride = source.VertexStride; shader.ColorAttachments = source.ColorAttachments; @@ -935,56 +1340,142 @@ VulkanContext::_createShader(const ShaderSource& source, DShaderVulkan& shader) // Create the shaders { + if (source.SourceCode.VertexShader.size()) + { + const VkResult result = VkUtils::createShaderModule(Device.Device, source.SourceCode.VertexShader, &shader.VertexShaderModule); + if (VKFAILED(result)) + { + throw std::runtime_error(VkUtils::VkErrorString(result)); + } + shader.ShaderStageCreateInfo.push_back(VkUtils::createShaderStageInfo(VkShaderStageFlagBits::VK_SHADER_STAGE_VERTEX_BIT, shader.VertexShaderModule)); + } + if (source.SourceCode.ComputeShader.size()) + { - { - const VkResult result = VkUtils::createShaderModule(Device.Device, source.SourceCode.VertexShader, &shader.VertexShaderModule); - if (VKFAILED(result)) - { - throw std::runtime_error(VkUtils::VkErrorString(result)); - } - shader.ShaderStageCreateInfo.push_back(VkUtils::createShaderStageInfo(VkShaderStageFlagBits::VK_SHADER_STAGE_VERTEX_BIT, shader.VertexShaderModule)); - } + const VkResult result = VkUtils::createShaderModule(Device.Device, source.SourceCode.ComputeShader, &shader.ComputeShaderModule); + if (VKFAILED(result)) + { + throw std::runtime_error(VkUtils::VkErrorString(result)); + } + shader.ShaderStageCreateInfo.push_back(VkUtils::createShaderStageInfo(VkShaderStageFlagBits::VK_SHADER_STAGE_COMPUTE_BIT, shader.ComputeShaderModule)); + } - { + if (source.SourceCode.PixelShader.size()) + { - const VkResult result = VkUtils::createShaderModule(Device.Device, source.SourceCode.PixelShader, &shader.PixelShaderModule); - if (VKFAILED(result)) - { - throw std::runtime_error(VkUtils::VkErrorString(result)); - } - shader.ShaderStageCreateInfo.push_back(VkUtils::createShaderStageInfo(VkShaderStageFlagBits::VK_SHADER_STAGE_FRAGMENT_BIT, shader.PixelShaderModule)); - } + const VkResult result = VkUtils::createShaderModule(Device.Device, source.SourceCode.PixelShader, &shader.PixelShaderModule); + if (VKFAILED(result)) + { + throw std::runtime_error(VkUtils::VkErrorString(result)); + } + shader.ShaderStageCreateInfo.push_back(VkUtils::createShaderStageInfo(VkShaderStageFlagBits::VK_SHADER_STAGE_FRAGMENT_BIT, shader.PixelShaderModule)); + } } } void VulkanContext::DestroyShader(const ShaderId shader) { - check(ResourceId(shader).First() == EResourceType::SHADER); + furyassert(ResourceId(shader).First() == EResourceType::SHADER); const auto index = ResourceId(shader).Value(); - check(IsValidId(_shaders.at(index).Id)); + furyassert(IsValidId(_shaders.at(index).Id)); _shaders.at(index).Id = PENDING_DESTROY; _deferDestruction([this, index]() { DShaderVulkan& shaderVulkan = _shaders.at(index); vkDestroyShaderModule(Device.Device, shaderVulkan.VertexShaderModule, nullptr); + vkDestroyShaderModule(Device.Device, shaderVulkan.ComputeShaderModule, nullptr); vkDestroyShaderModule(Device.Device, shaderVulkan.PixelShaderModule, nullptr); _shaders.at(index).Id = FREE; }); } uint32_t -VulkanContext::CreateSampler(uint32_t minLod, uint32_t maxLod) +VulkanContext::CreateSampler(uint32_t minLod, +uint32_t maxLod, +EFilter minFilter, +EFilter magFilter, +ESamplerAddressMode addressMode, +ESamplerMipmapMode mipMapMode, +bool anisotropicFiltering, +float anisotropicFilter) { const auto index = AllocResource(_samplers); DSamplerVulkan& samplerRef = _samplers.at(index); +#if _DEBUG + if (anisotropicFiltering) + { + furyassert(anisotropicFilter > 0.f); + } +#endif - samplerRef.Sampler = Device.CreateSampler(VkFilter::VK_FILTER_NEAREST, VK_FILTER_LINEAR, VK_SAMPLER_ADDRESS_MODE_REPEAT, minLod, maxLod, VK_SAMPLER_MIPMAP_MODE_LINEAR, true, 16); + samplerRef.Sampler = Device.CreateSampler(VkUtils::convertEFilterToVkFilter(minFilter), + VkUtils::convertEFilterToVkFilter(magFilter), + VkUtils::convertESamplerAddressModeToVkSamplerAddressMode(addressMode), + (float)minLod, + (float)maxLod, + VkUtils::convertESamplerMipmapModeToVkSamplerMipmapMode(mipMapMode), + anisotropicFiltering, + anisotropicFilter); + + // samplerRef.Sampler = Device.CreateSampler(VkFilter::VK_FILTER_NEAREST, VK_FILTER_NEAREST, VK_SAMPLER_ADDRESS_MODE_REPEAT, (float)minLod, (float)maxLod, //VK_SAMPLER_MIPMAP_MODE_NEAREST, false, + // 0); + // + // samplerRef.Sampler = Device.CreateSampler(VkFilter::VK_FILTER_LINEAR, VK_FILTER_LINEAR, VK_SAMPLER_ADDRESS_MODE_REPEAT, (float)minLod, (float)maxLod, VK_SAMPLER_MIPMAP_MODE_LINEAR, true, 16); return *ResourceId(EResourceType::SAMPLER, samplerRef.Id, index); } +void +VulkanContext::DestroySampler(uint32_t samplerId) +{ + DSamplerVulkan& sampler = GetResource(_samplers, samplerId); + + Device.DestroySampler(sampler.Sampler); + + sampler.Id = FREE; + sampler.Sampler = nullptr; +} + +uint32_t +VulkanContext::CreateComputePipeline(const uint32_t shader, const uint32_t rootSignatureId) +{ + const auto& shaderRef = GetResource(_shaders, shader); + const DRootSignature& rootSignature = GetResource(_rootSignatures, rootSignatureId); + + VkPipelineShaderStageCreateInfo stageinfo{}; + stageinfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + stageinfo.pNext = nullptr; + stageinfo.stage = VK_SHADER_STAGE_COMPUTE_BIT; + stageinfo.module = shaderRef.ComputeShaderModule; + stageinfo.pName = "main"; + + VkComputePipelineCreateInfo createInfo{}; + createInfo.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO; + createInfo.pNext = nullptr; + createInfo.flags = 0; + createInfo.stage = stageinfo; + createInfo.layout = rootSignature.PipelineLayout; + createInfo.basePipelineHandle = VK_NULL_HANDLE; // unused + createInfo.basePipelineIndex = NULL; // unused + + VkPipeline pipeline{}; + const VkResult result{ vkCreateComputePipelines(Device.Device, VK_NULL_HANDLE, 1, &createInfo, nullptr, &pipeline) }; + if (VKFAILED(result)) + { + throw std::runtime_error(VkUtils::VkErrorString(result)); + } + + const auto index = AllocResource(_pipelines); + DPipelineVulkan& pso = _pipelines.at(index); + pso.Pipeline = pipeline; + pso.PipelineLayout = &rootSignature.PipelineLayout; + pso.Type = EPipelineType::COMPUTE; + + return *ResourceId(EResourceType::PIPELINE, pso.Id, index); +} + uint32_t VulkanContext::CreatePipeline(const ShaderId shader, uint32_t rootSignatureId, const DPipelineAttachments& attachments, const PipelineFormat& format) { @@ -1000,23 +1491,34 @@ VulkanContext::CreatePipeline(const ShaderId shader, uint32_t rootSignatureId, c auto renderPassVk = _createRenderPass(rpAttachments); auto& vertexLayout = GetResource(_vertexLayouts, shaderRef.VertexLayout); pso.Pipeline = _createPipeline(rootSignature.PipelineLayout, renderPassVk, shaderRef.ShaderStageCreateInfo, format, vertexLayout, shaderRef.VertexStride); + pso.Type = EPipelineType::GRAPHICS; - return *ResourceId(EResourceType::GRAPHICS_PIPELINE, pso.Id, index); + return *ResourceId(EResourceType::PIPELINE, pso.Id, index); } void VulkanContext::DestroyPipeline(uint32_t pipelineId) { - auto& pipelineRef = GetResource(_pipelines, pipelineId); + auto& pipelineRef = GetResource(_pipelines, pipelineId); + switch (pipelineRef.Type) + { + case EPipelineType::GRAPHICS: + Device.DestroyPipeline(pipelineRef.Pipeline); + break; + case EPipelineType::COMPUTE: + vkDestroyPipeline(Device.Device, pipelineRef.Pipeline, nullptr); + break; + } - Device.DestroyPipeline(pipelineRef.Pipeline); - pipelineRef.Id = FREE; + pipelineRef.Pipeline = nullptr; + pipelineRef.PipelineLayout = nullptr; + pipelineRef.Id = FREE; } uint32_t VulkanContext::CreateRootSignature(const ShaderLayout& layout) { - check(layout.SetsLayout.size() < (uint32_t)EDescriptorFrequency::MAX_COUNT); + furyassert(layout.SetsLayout.size() < (uint32_t)EDescriptorFrequency::MAX_COUNT); const auto index = AllocResource(_rootSignatures); DRootSignature& rootSignature = _rootSignatures.at(index); @@ -1025,7 +1527,8 @@ VulkanContext::CreateRootSignature(const ShaderLayout& layout) std::map setIndexToSetLayout; for (const auto& setPair : layout.SetsLayout) { - const auto descriptorSetBindings = VkUtils::convertDescriptorBindings(setPair.second); + const auto descriptorSetBindings = VkUtils::convertDescriptorBindings(setPair.second); + // Can return already cached DescriptorSet layout if exists rootSignature.DescriptorSetLayouts[setPair.first] = Device.CreateDescriptorSetLayout(descriptorSetBindings); descriptorSetLayout.push_back(rootSignature.DescriptorSetLayouts[setPair.first]); @@ -1035,8 +1538,17 @@ VulkanContext::CreateRootSignature(const ShaderLayout& layout) rootSignature.PoolSizes[setPair.first] = VkUtils::computeDescriptorSetsPoolSize(setBindings); } + // Convert push constants + std::vector pushConstants; + for (const auto& p : layout.PushConstants) + { +#pragma message "Warning:src/backend/vulkan/VulkanContext.cpp: line 1528 : p.Stage is not used!" + p.Stage; + pushConstants.push_back(VkPushConstantRange{ VK_SHADER_STAGE_ALL_GRAPHICS, p.Offset, p.Size }); + }; + // Can return already cached pipeline layout if exists - rootSignature.PipelineLayout = Device.CreatePipelineLayout(descriptorSetLayout, {}); + rootSignature.PipelineLayout = Device.CreatePipelineLayout(descriptorSetLayout, pushConstants); rootSignature.SetsBindings = layout.SetsLayout; @@ -1069,24 +1581,31 @@ VulkanContext::CreateRootSignature(const ShaderLayout& layout) uint32_t imageInfoCount{}; uint32_t bufferInfoCount{}; - for (const auto index : rootSignature.SetsBindings[i]) + for (const auto bindingIndex : rootSignature.SetsBindings[i]) { - check(index.second.Count < 8196); + furyassert(bindingIndex.second.Count < 8196); - const uint32_t descriptorCount = std::max(1u, index.second.Count); + const uint32_t descriptorCount = std::max(1u, bindingIndex.second.Count); VkWriteDescriptorSet* writeSet = &write[writeSetCount++]; writeSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; writeSet->pNext = NULL; writeSet->descriptorCount = descriptorCount; - const ShaderDescriptorBindings& bindingDesc = index.second; + const ShaderDescriptorBindings& bindingDesc = bindingIndex.second; switch (bindingDesc.StorageType) { case EBindingType::STORAGE_BUFFER_OBJECT: { writeSet->descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; - check(0); // UNSUPPORTED YET + writeSet->pBufferInfo = &bufferInfo[bufferInfoCount]; + for (uint32_t j = 0; j < descriptorCount; j++) + { + VkDescriptorBufferInfo& buf = bufferInfo[bufferInfoCount++]; + buf.buffer = _emptySsbo.Buffer.Buffer; + buf.offset = 0; + buf.range = VK_WHOLE_SIZE; + } } break; case EBindingType::UNIFORM_BUFFER_OBJECT: @@ -1107,11 +1626,25 @@ VulkanContext::CreateRootSignature(const ShaderLayout& layout) writeSet->descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; writeSet->pImageInfo = &imageInfo[imageInfoCount]; - for (uint32_t i = 0; i < descriptorCount; i++) + for (uint32_t j = 0; j < descriptorCount; j++) { VkDescriptorImageInfo& img = imageInfo[imageInfoCount++]; - img.imageView = _emptyImage->View; + img.imageView = _emptyImage->GetImageView(0, 1, Device); img.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + img.sampler = _emptyImage->Sampler; + } + } + break; + case EBindingType::STORAGE_IMAGE: + { + writeSet->descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; + writeSet->pImageInfo = &imageInfo[imageInfoCount]; + + for (uint32_t j = 0; j < descriptorCount; j++) + { + VkDescriptorImageInfo& img = imageInfo[imageInfoCount++]; + img.imageView = _emptyStorageImage->GetImageView(0, 1, Device); + img.imageLayout = VK_IMAGE_LAYOUT_GENERAL; img.sampler = NULL; } } @@ -1121,7 +1654,7 @@ VulkanContext::CreateRootSignature(const ShaderLayout& layout) writeSet->descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER; writeSet->pImageInfo = &imageInfo[imageInfoCount]; - for (uint32_t i = 0; i < descriptorCount; i++) + for (uint32_t j = 0; j < descriptorCount; j++) { VkDescriptorImageInfo& img = imageInfo[imageInfoCount++]; img.imageView = 0; @@ -1130,10 +1663,14 @@ VulkanContext::CreateRootSignature(const ShaderLayout& layout) } } break; + + default: + furyassert(0); // Unhandled case + break; } writeSet->dstArrayElement = 0; - writeSet->dstBinding = index.first; + writeSet->dstBinding = bindingIndex.first; writeSet->dstSet = rootSignature.EmptySet[i]; } vkUpdateDescriptorSets(Device.Device, writeSetCount, write.data(), 0, nullptr); @@ -1148,17 +1685,61 @@ VulkanContext::DestroyRootSignature(uint32_t rootSignatureId) { DRootSignature& rootSignature = GetResource(_rootSignatures, rootSignatureId); - Device.DestroyPipelineLayout(rootSignature.PipelineLayout); - - for (uint32_t i = 0; i < (uint32_t)EDescriptorFrequency::MAX_COUNT; i++) + // Check if the pipeline layout is not shared among other root signatures + const auto count{ std::count_if( + _rootSignatures.begin(), _rootSignatures.end(), [rootSignature](const DRootSignature& sig) { return IsValidId(sig.Id) && sig.PipelineLayout == rootSignature.PipelineLayout; }) }; + if (count == 1) { - if (rootSignature.DescriptorSetLayouts[i] != nullptr) + Device.DestroyPipelineLayout(rootSignature.PipelineLayout); + + // Only destroy non shared rootSignatures when pipeline layout can be destroyed + for (uint32_t i = 0; i < (uint32_t)EDescriptorFrequency::MAX_COUNT; i++) { - Device.DestroyDescriptorSetLayout(rootSignature.DescriptorSetLayouts[i]); + if (rootSignature.DescriptorSetLayouts[i] != nullptr) + { + // Check if the descriptor set layout is not shared among other root signatures + const auto usageCount{ std::count_if( + _rootSignatures.begin(), _rootSignatures.end(), [descriptorSetLayout = rootSignature.DescriptorSetLayouts[i]](const DRootSignature& sig) { + for (uint32_t i = 0; i < (uint32_t)EDescriptorFrequency::MAX_COUNT; i++) + { + if (sig.DescriptorSetLayouts[i] == descriptorSetLayout) + { + return true; + } + } + return false; + }) }; + // If not referenced in other root signatures + if (usageCount == 1) + { + Device.DestroyDescriptorSetLayout(rootSignature.DescriptorSetLayouts[i]); + + // if the same descriptor set layout is used multiple times set the pointers to nullptr + for (uint32_t j = 0; j < (uint32_t)EDescriptorFrequency::MAX_COUNT; j++) + { + if (i != j && rootSignature.DescriptorSetLayouts[j] == rootSignature.DescriptorSetLayouts[i]) + { + rootSignature.DescriptorSetLayouts[j] = nullptr; + } + } + rootSignature.DescriptorSetLayouts[i] = nullptr; + } + } } } - rootSignature.Id = FREE; + // Destroy descriptor pools + for (uint32_t i = 0; i < (uint32_t)EDescriptorFrequency::MAX_COUNT; i++) + { + //@TODO shorten loop + if (rootSignature.EmptyPool[i] == nullptr) + continue; + + Device.DestroyDescriptorPool(rootSignature.EmptyPool[i]); + } + + rootSignature.Id = FREE; + rootSignature.PipelineLayout = nullptr; memset(rootSignature.DescriptorSetLayouts, NULL, sizeof(rootSignature.DescriptorSetLayouts)); for (auto it = 0; it < (uint32_t)EDescriptorFrequency::MAX_COUNT; it++) { @@ -1182,7 +1763,7 @@ VulkanContext::CreateDescriptorSets(uint32_t rootSignatureId, EDescriptorFrequen descriptorSetRef.Sets.resize(count); descriptorSetRef.Frequency = frequency; - check(count < 8196); + furyassert(count < 8196); std::array descriptorSetLayouts; std::fill(descriptorSetLayouts.begin(), descriptorSetLayouts.begin() + count, rootSignature.DescriptorSetLayouts[(uint32_t)frequency]); { @@ -1211,24 +1792,31 @@ VulkanContext::CreateDescriptorSets(uint32_t rootSignatureId, EDescriptorFrequen uint32_t imageInfoCount{}; uint32_t bufferInfoCount{}; - for (const auto index : setBinding) + for (const auto bindingIndex : setBinding) { - check(index.second.Count < 8196); + furyassert(bindingIndex.second.Count < 8196); - const uint32_t descriptorCount = std::max(1u, index.second.Count); + const uint32_t descriptorCount = std::max(1u, bindingIndex.second.Count); VkWriteDescriptorSet* writeSet = &write[writeSetCount++]; writeSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; writeSet->pNext = NULL; writeSet->descriptorCount = descriptorCount; - const ShaderDescriptorBindings& bindingDesc = index.second; + const ShaderDescriptorBindings& bindingDesc = bindingIndex.second; switch (bindingDesc.StorageType) { case EBindingType::STORAGE_BUFFER_OBJECT: { writeSet->descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; - check(0); // UNSUPPORTED YET + writeSet->pBufferInfo = &bufferInfo[bufferInfoCount]; + for (uint32_t j = 0; j < descriptorCount; j++) + { + VkDescriptorBufferInfo& buf = bufferInfo[bufferInfoCount++]; + buf.buffer = _emptySsbo.Buffer.Buffer; + buf.offset = 0; + buf.range = VK_WHOLE_SIZE; + } } break; case EBindingType::UNIFORM_BUFFER_OBJECT: @@ -1252,12 +1840,26 @@ VulkanContext::CreateDescriptorSets(uint32_t rootSignatureId, EDescriptorFrequen for (uint32_t i = 0; i < descriptorCount; i++) { VkDescriptorImageInfo& img = imageInfo[imageInfoCount++]; - img.imageView = _emptyImage->View; + img.imageView = _emptyImage->GetImageView(0, 1, Device); img.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; img.sampler = NULL; } } break; + case EBindingType::STORAGE_IMAGE: + { + writeSet->descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; + writeSet->pImageInfo = &imageInfo[imageInfoCount]; + + for (uint32_t i = 0; i < descriptorCount; i++) + { + VkDescriptorImageInfo& img = imageInfo[imageInfoCount++]; + img.imageView = _emptyStorageImage->GetImageView(0, 1, Device); + img.imageLayout = VK_IMAGE_LAYOUT_GENERAL; + img.sampler = NULL; + } + } + break; case EBindingType::SAMPLER: { writeSet->descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER; @@ -1275,7 +1877,7 @@ VulkanContext::CreateDescriptorSets(uint32_t rootSignatureId, EDescriptorFrequen } writeSet->dstArrayElement = 0; - writeSet->dstBinding = index.first; + writeSet->dstBinding = bindingIndex.first; writeSet->dstSet = set; } vkUpdateDescriptorSets(Device.Device, writeSetCount, write.data(), 0, nullptr); @@ -1296,11 +1898,11 @@ VulkanContext::DestroyDescriptorSet(uint32_t descriptorSetId) } void -VulkanContext::UpdateDescriptorSet(uint32_t descriptorSetId, uint32_t setIndex, uint32_t paramCount, DescriptorData* params) +VulkanContext::UpdateDescriptorSet(uint32_t descriptorSetId, uint32_t paramCount, DescriptorData* params) { const DDescriptorSet& descriptorSetRef = GetResource(_descriptorSets, descriptorSetId); - check(paramCount < 8196); + furyassert(paramCount < 8196); std::array write; std::array imageInfo; std::array bufferInfo; @@ -1323,22 +1925,30 @@ VulkanContext::UpdateDescriptorSet(uint32_t descriptorSetId, uint32_t setIndex, case EBindingType::STORAGE_BUFFER_OBJECT: { writeSet->descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; - check(0); // UNSUPPORTED YET + writeSet->pBufferInfo = &bufferInfo[bufferInfoCount]; + + for (uint32_t j = 0; j < descriptorCount; j++) + { + VkDescriptorBufferInfo& buf = bufferInfo[bufferInfoCount++]; + const DBufferVulkan& bufRef = GetResource(_storageBuffers, param->Buffers[j]); + buf.buffer = bufRef.Buffer.Buffer; + buf.offset = param->BufferOffset; + buf.range = param->BufferRange; + } } break; case EBindingType::UNIFORM_BUFFER_OBJECT: { writeSet->descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - - writeSet->pBufferInfo = &bufferInfo[bufferInfoCount]; + writeSet->pBufferInfo = &bufferInfo[bufferInfoCount]; for (uint32_t j = 0; j < descriptorCount; j++) { VkDescriptorBufferInfo& buf = bufferInfo[bufferInfoCount++]; const DBufferVulkan& bufRef = GetResource(_uniformBuffers, param->Buffers[j]); buf.buffer = bufRef.Buffer.Buffer; - buf.offset = 0; - buf.range = VK_WHOLE_SIZE; + buf.offset = param->BufferOffset; + buf.range = param->BufferRange; } } break; @@ -1347,13 +1957,68 @@ VulkanContext::UpdateDescriptorSet(uint32_t descriptorSetId, uint32_t setIndex, writeSet->descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; writeSet->pImageInfo = &imageInfo[imageInfoCount]; - for (uint32_t i = 0; i < descriptorCount; i++) + for (uint32_t j = 0; j < descriptorCount; j++) + { + VkDescriptorImageInfo& img = imageInfo[imageInfoCount++]; + const auto resourceType{ static_cast(ResourceId(param->Textures[j]).First()) }; + switch (resourceType) + { + case EResourceType::IMAGE: + { + const DImageVulkan& imageRef = GetResource(_images, param->Textures[j]); + img.imageView = imageRef.GetImageView(param->MipMapIndex, param->MipMapCount, Device); + img.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + img.sampler = NULL; + } + break; + case EResourceType::RENDER_TARGET: + { + const DRenderTargetVulkan& imageRef = + GetResource(_renderTargets, param->Textures[j]); + img.imageView = imageRef.View; + img.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + img.sampler = NULL; + } + break; + default: + furyassert(0); // Invalid resource type, must be a image or render target + break; + } + } + } + break; + case EBindingType::STORAGE_IMAGE: + { + writeSet->descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; + writeSet->pImageInfo = &imageInfo[imageInfoCount]; + + for (uint32_t j = 0; j < descriptorCount; j++) { - VkDescriptorImageInfo& img = imageInfo[imageInfoCount++]; - const DImageVulkan& imageRef = GetResource(_images, param->Textures[i]); - img.imageView = imageRef.View; - img.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - img.sampler = NULL; + VkDescriptorImageInfo& img = imageInfo[imageInfoCount++]; + const auto resourceType{ static_cast(ResourceId(param->Textures[j]).First()) }; + switch (resourceType) + { + case EResourceType::IMAGE: + { + const DImageVulkan& imageRef = GetResource(_images, param->Textures[j]); + img.imageView = imageRef.GetImageView(param->MipMapIndex, param->MipMapCount, Device); + img.imageLayout = VK_IMAGE_LAYOUT_GENERAL; + img.sampler = NULL; + } + break; + case EResourceType::RENDER_TARGET: + { + const DRenderTargetVulkan& imageRef = + GetResource(_renderTargets, param->Textures[j]); + img.imageView = imageRef.View; + img.imageLayout = VK_IMAGE_LAYOUT_GENERAL; + img.sampler = NULL; + } + break; + default: + furyassert(0); // Invalid resource type, must be a image or render target + break; + } } } break; @@ -1362,21 +2027,25 @@ VulkanContext::UpdateDescriptorSet(uint32_t descriptorSetId, uint32_t setIndex, writeSet->descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER; writeSet->pImageInfo = &imageInfo[imageInfoCount]; - for (uint32_t i = 0; i < descriptorCount; i++) + for (uint32_t j = 0; j < descriptorCount; j++) { VkDescriptorImageInfo& img = imageInfo[imageInfoCount++]; - const DSamplerVulkan& samplerRef = GetResource(_samplers, param->Samplers[i]); + const DSamplerVulkan& samplerRef = GetResource(_samplers, param->Samplers[j]); img.imageView = 0; img.imageLayout = VK_IMAGE_LAYOUT_UNDEFINED; img.sampler = samplerRef.Sampler; } } break; + + default: + furyassert(0); + break; } writeSet->dstArrayElement = param->ArrayOffset; writeSet->dstBinding = param->Index; - writeSet->dstSet = descriptorSetRef.Sets.at(setIndex); + writeSet->dstSet = descriptorSetRef.Sets.at(param->SetIndex); } vkUpdateDescriptorSets(Device.Device, writeSetCount, write.data(), 0, nullptr); @@ -1392,29 +2061,40 @@ VulkanContext::_createFramebuffer(const DFramebufferAttachments& attachments) const auto vkRenderPass = _createRenderPass(rpAttachments); // Extrapolate all the renderTargetRef views - const auto depthAttachmentCount = (uint32_t)(attachments.DepthStencil != 0); - const auto attachmentCount = DFramebufferAttachments::MAX_ATTACHMENTS - std::count(attachments.RenderTargets.begin(), attachments.RenderTargets.end(), NULL) + depthAttachmentCount; - check(attachmentCount > 0); // Must have at least one attachment + const uint32_t depthAttachmentCount = (uint32_t)(attachments.DepthStencil != 0); + const int64_t attachmentCount = DFramebufferAttachments::MAX_ATTACHMENTS - std::count(attachments.RenderTargets.begin(), attachments.RenderTargets.end(), (uint32_t)0) + depthAttachmentCount; + furyassert(attachmentCount > 0); // Must have at least one attachment std::vector imageViewsAttachments; - imageViewsAttachments.resize(attachmentCount); + imageViewsAttachments.resize((size_t)attachmentCount); - { - // First attachment must always exists - const auto& renderTargetRef = GetResource(_renderTargets, attachments.RenderTargets[0]); - framebufferRef.Width = renderTargetRef.Image.Width; - framebufferRef.Height = renderTargetRef.Image.Height; - } - - for (size_t i = 0; i < attachmentCount - depthAttachmentCount; i++) + if (attachments.RenderTargets[0] != 0) { - check(attachments.RenderTargets[i] != NULL); - const auto& renderTargetRef = GetResource(_renderTargets, attachments.RenderTargets[i]); - imageViewsAttachments[i] = renderTargetRef.View; + // Attachments must be specifies from 0 to max without gaps + { + const auto& renderTargetRef = GetResource(_renderTargets, attachments.RenderTargets[0]); + framebufferRef.Width = renderTargetRef.Image.Width; + framebufferRef.Height = renderTargetRef.Image.Height; + } + for (uint32_t i = 0; i < attachmentCount - depthAttachmentCount; i++) + { + furyassert(attachments.RenderTargets[i] != NULL); + const auto& renderTargetRef = GetResource(_renderTargets, attachments.RenderTargets[i]); + imageViewsAttachments[i] = renderTargetRef.View; - check(renderTargetRef.Image.Width == framebufferRef.Width); // All images must have the same width - check(renderTargetRef.Image.Height == framebufferRef.Height); // All images must have the same height - check(renderTargetRef.Image.MipLevels == 1); // Must have only 1 layer + furyassert(renderTargetRef.Image.Width == framebufferRef.Width); // All images must have the same width + furyassert(renderTargetRef.Image.Height == framebufferRef.Height); // All images must have the same height + furyassert(renderTargetRef.Image.MipLevels == 1); // Must have only 1 layer (Vulkan requirement) + } + } + else + { + if (depthAttachmentCount) + { + const auto& renderTargetRef = GetResource(_renderTargets, attachments.DepthStencil); + framebufferRef.Width = renderTargetRef.Image.Width; + framebufferRef.Height = renderTargetRef.Image.Height; + } } if (depthAttachmentCount) @@ -1422,9 +2102,14 @@ VulkanContext::_createFramebuffer(const DFramebufferAttachments& attachments) const auto& renderTargetRef = GetResource(_renderTargets, attachments.DepthStencil); imageViewsAttachments.back() = renderTargetRef.View; - check(renderTargetRef.Image.Width == framebufferRef.Width); // All images must have the same width - check(renderTargetRef.Image.Height == framebufferRef.Height); // All images must have the same height - check(renderTargetRef.Image.MipLevels == 1); // Must have only 1 layer +#if _DEBUG + furyassert(renderTargetRef.Image.MipLevels == 1); // Must have only 1 layer (Vulkan requirement) + if (attachmentCount >= depthAttachmentCount) + { + furyassert(renderTargetRef.Image.Width == framebufferRef.Width); // All images must have the same width + furyassert(renderTargetRef.Image.Height == framebufferRef.Height); // All images must have the same height + } +#endif } framebufferRef.Framebuffer = Device._createFramebuffer(imageViewsAttachments, framebufferRef.Width, framebufferRef.Height, vkRenderPass); @@ -1444,12 +2129,17 @@ VulkanContext::_destroyFramebuffer(uint32_t framebufferId) } uint32_t -VulkanContext::CreateCommandPool() +VulkanContext::CreateCommandPool(uint32_t queueId) { const auto index = AllocResource(_commandPools); auto& commandPoolRef = _commandPools.at(index); - commandPoolRef.Pool = Device.CreateCommandPool2(Device.GetQueueFamilyIndex()); + { + const auto& queueRef = GetResource(_queues, queueId); + commandPoolRef.Pool = Device.CreateCommandPool2(queueRef.QueueFamilyIndex); + commandPoolRef.QueueFamilyIndex = queueRef.QueueFamilyIndex; + commandPoolRef.Type = queueRef.Type; + } return *ResourceId(EResourceType::COMMAND_POOL, commandPoolRef.Id, index); } @@ -1479,12 +2169,17 @@ VulkanContext::CreateCommandBuffer(uint32_t commandPoolId) // Reset internals { - commandBufferRef.ActiveRenderPass = nullptr; - commandBufferRef.IsRecording = false; + commandBufferRef.ActiveRenderPass = nullptr; + commandBufferRef.IsRecording = false; + commandBufferRef.BoundFramebuffer = nullptr; + commandBufferRef.BoundPipeline = nullptr; + commandBufferRef.BoundPipelineLayout = nullptr; } auto& commandPoolRef = GetResource(_commandPools, commandPoolId); + commandBufferRef.Type = commandPoolRef.Type; + VkCommandBufferAllocateInfo info{}; info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; info.pNext = NULL; @@ -1506,7 +2201,7 @@ void VulkanContext::DestroyCommandBuffer(uint32_t commandBufferId) { auto& commandBufferRef = GetResource(_commandBuffers, commandBufferId); - check(!commandBufferRef.IsRecording); // Must not be in recording state + furyassert(!commandBufferRef.IsRecording); // Must not be in recording state commandBufferRef.Id = FREE; } @@ -1514,8 +2209,13 @@ void VulkanContext::BeginCommandBuffer(uint32_t commandBufferId) { auto& commandBufferRef = GetResource(_commandBuffers, commandBufferId); - check(!commandBufferRef.IsRecording); // Must not be in recording state - commandBufferRef.IsRecording = true; + furyassert(!commandBufferRef.IsRecording); // Must not be in recording state + commandBufferRef.IsRecording = true; + commandBufferRef.BoundPipeline = {}; + commandBufferRef.CurrentScissor = {}; + commandBufferRef.CurrentVertexBuffer = {}; + commandBufferRef.CurrentIndexBuffer = {}; + commandBufferRef.StencilTestActive = {}; VkCommandBufferBeginInfo beginInfo{}; beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; @@ -1528,7 +2228,7 @@ VulkanContext::EndCommandBuffer(uint32_t commandBufferId) { auto& commandBufferRef = GetResource(_commandBuffers, commandBufferId); - check(commandBufferRef.IsRecording); // Must be in recording state + furyassert(commandBufferRef.IsRecording); // Must be in recording state commandBufferRef.IsRecording = false; // If previous active render pass end it @@ -1536,6 +2236,7 @@ VulkanContext::EndCommandBuffer(uint32_t commandBufferId) { vkCmdEndRenderPass(commandBufferRef.Cmd); commandBufferRef.ActiveRenderPass = nullptr; + commandBufferRef.BoundFramebuffer = nullptr; } vkEndCommandBuffer(commandBufferRef.Cmd); @@ -1547,10 +2248,11 @@ VulkanContext::BindRenderTargets(uint32_t commandBufferId, const DFramebufferAtt // Find existing framebuffer auto framebufferIt = std::find_if(_framebuffers.begin(), _framebuffers.end(), [colorAttachments](const DFramebufferVulkan& fbo) { - if (fbo.Id == FREE || fbo.Id == PENDING_DESTROY) - return false; + if (fbo.Id != FREE && fbo.Id != PENDING_DESTROY && fbo.Attachments == colorAttachments) + return true; - return DFramebufferAttachmentEqualFn{}(fbo.Attachments, colorAttachments); + return false; + /*return DFramebufferAttachmentEqualFn{}(fbo.Attachments, colorAttachments);*/ }); DFramebufferVulkan* framebufferPtr{}; @@ -1615,6 +2317,26 @@ VulkanContext::BindRenderTargets(uint32_t commandBufferId, const DFramebufferAtt } } +#if _DEBUG && DEBUG_RT_TRANSITIONS 1 + for (size_t i = 0; i < renderPassAttachments.Attachments.size(); i++) + { + if (VkUtils::isColorFormat(VkUtils::convertFormat(renderPassAttachments.Attachments.at(i).Format))) + { + const auto* rt = &GetResource(_renderTargets, framebufferPtr->Attachments.RenderTargets[i]); + std::cout << "Begin Render Pass for image:" << rt->Image.Image + << " from layout:" << VkUtils::VkImageLayoutToString(VkUtils::convertRenderPassLayout(renderPassAttachments.Attachments.at(i).InitialLayout)) << " to " + << VkUtils::VkImageLayoutToString(VkUtils::convertRenderPassLayout(renderPassAttachments.Attachments.at(i).FinalLayout)) << std::endl; + } + else + { + const auto* rt = &GetResource(_renderTargets, framebufferPtr->Attachments.DepthStencil); + std::cout << "Begin Render Pass for image:" << rt->Image.Image + << " from layout:" << VkUtils::VkImageLayoutToString(VkUtils::convertRenderPassLayout(renderPassAttachments.Attachments.at(i).InitialLayout)) << " to " + << VkUtils::VkImageLayoutToString(VkUtils::convertRenderPassLayout(renderPassAttachments.Attachments.at(i).FinalLayout)) << std::endl; + } + } +#endif + VkRenderPass renderPass = _createRenderPass(renderPassAttachments); VkRenderPassBeginInfo renderPassInfo{}; @@ -1627,25 +2349,25 @@ VulkanContext::BindRenderTargets(uint32_t commandBufferId, const DFramebufferAtt renderPassInfo.pClearValues = clearValues; auto& commandBufferRef = GetResource(_commandBuffers, commandBufferId); - check(commandBufferRef.IsRecording); // Must be in recording state + furyassert(commandBufferRef.IsRecording); // Must be in recording state // If previous active render pass end it if (commandBufferRef.ActiveRenderPass) { vkCmdEndRenderPass(commandBufferRef.Cmd); - commandBufferRef.ActiveRenderPass = nullptr; + commandBufferRef.BoundFramebuffer = nullptr; } + commandBufferRef.ActiveRenderPass = renderPass; + commandBufferRef.BoundFramebuffer = framebufferPtr->Framebuffer; vkCmdBeginRenderPass(commandBufferRef.Cmd, &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE); - - commandBufferRef.ActiveRenderPass = renderPass; } void VulkanContext::SetViewport(uint32_t commandBufferId, uint32_t x, uint32_t y, uint32_t width, uint32_t height, float znear, float zfar) { auto& commandBufferRef = GetResource(_commandBuffers, commandBufferId); - check(commandBufferRef.IsRecording); // Must be in recording state - check(commandBufferRef.ActiveRenderPass); // Must be in a render pass + furyassert(commandBufferRef.IsRecording); // Must be in recording state + furyassert(commandBufferRef.ActiveRenderPass); // Must be in a render pass // Invert viewport on Y VkViewport viewport{ static_cast(x), static_cast(y) + static_cast(height), static_cast(width), -static_cast(height), znear, zfar }; @@ -1657,57 +2379,114 @@ void VulkanContext::SetScissor(uint32_t commandBufferId, uint32_t x, uint32_t y, uint32_t width, uint32_t height) { auto& commandBufferRef = GetResource(_commandBuffers, commandBufferId); - check(commandBufferRef.IsRecording); // Must be in recording state - check(commandBufferRef.ActiveRenderPass); // Must be in a render pass + furyassert(commandBufferRef.IsRecording); // Must be in recording state + furyassert(commandBufferRef.ActiveRenderPass); // Must be in a render pass - VkRect2D rect{ x, y, width, height }; - vkCmdSetScissor(commandBufferRef.Cmd, 0, 1, &rect); + furyassert((int32_t)(x + width) <= std::numeric_limits().max()); // sum must not overflow int32_t + furyassert((int32_t)(y + height) <= std::numeric_limits().max()); // sum must not overflow int32_t + + auto areRect2dEqual = [](const VkRect2D& a, const VkRect2D& b) { + return a.extent.width == b.extent.width && a.extent.height == b.extent.height && a.offset.x == b.offset.x && a.offset.y == b.offset.y; + }; + furyassert(x < std::numeric_limits().max()); + furyassert(y < std::numeric_limits().max()); + + VkRect2D rect{ (int32_t)x, (int32_t)y, width, height }; + if (!areRect2dEqual(commandBufferRef.CurrentScissor, rect)) + { + commandBufferRef.CurrentScissor = rect; + vkCmdSetScissor(commandBufferRef.Cmd, 0, 1, &rect); + } } void VulkanContext::BindPipeline(uint32_t commandBufferId, uint32_t pipeline) { auto& commandBufferRef = GetResource(_commandBuffers, commandBufferId); - check(commandBufferRef.IsRecording); // Must be in recording state - check(commandBufferRef.ActiveRenderPass); // Must be in a render pass + furyassert(commandBufferRef.IsRecording); // Must be in recording state + auto& pipelineRef = GetResource(_pipelines, pipeline); + +#if _DEBUG + { + if (pipelineRef.Type == EPipelineType::GRAPHICS) + { + furyassert(commandBufferRef.ActiveRenderPass); // Must be in a render pass + } + else if (pipelineRef.Type == EPipelineType::COMPUTE) + { + furyassert(!commandBufferRef.ActiveRenderPass); // Must not be in a render pass + } + } +#endif - auto& pipelineRef = GetResource(_pipelines, pipeline); + if (commandBufferRef.BoundPipeline != pipelineRef.Pipeline) + { + // If binding a compute pipeline after a graphics pipeline must end any active render passes before binding + if (pipelineRef.Type == EPipelineType::COMPUTE && commandBufferRef.ActiveRenderPass != nullptr) + { + vkCmdEndRenderPass(commandBufferRef.Cmd); + commandBufferRef.ActiveRenderPass = {}; + } + // Update current pipeline + commandBufferRef.BoundPipeline = pipelineRef.Pipeline; + commandBufferRef.BoundPipelineLayout = pipelineRef.PipelineLayout; + commandBufferRef.BoundPipelineType = pipelineRef.Type; - vkCmdBindPipeline(commandBufferRef.Cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineRef.Pipeline); + switch (pipelineRef.Type) + { + case EPipelineType::GRAPHICS: + vkCmdBindPipeline(commandBufferRef.Cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineRef.Pipeline); + break; + case EPipelineType::COMPUTE: + vkCmdBindPipeline(commandBufferRef.Cmd, VK_PIPELINE_BIND_POINT_COMPUTE, pipelineRef.Pipeline); + break; + default: + furyassert(0); + break; + } + } } void VulkanContext::BindVertexBuffer(uint32_t commandBufferId, uint32_t bufferId) { auto& commandBufferRef = GetResource(_commandBuffers, commandBufferId); - check(commandBufferRef.IsRecording); // Must be in recording state - check(commandBufferRef.ActiveRenderPass); // Must be in a render pass + furyassert(commandBufferRef.IsRecording); // Must be in recording state + furyassert(commandBufferRef.ActiveRenderPass); // Must be in a render pass auto& vertexBufRef = GetResource(_vertexBuffers, bufferId); - VkDeviceSize offset{}; - vkCmdBindVertexBuffers(commandBufferRef.Cmd, 0, 1, &vertexBufRef.Buffer.Buffer, &offset); + if (commandBufferRef.CurrentVertexBuffer != vertexBufRef.Buffer.Buffer) + { + commandBufferRef.CurrentVertexBuffer = vertexBufRef.Buffer.Buffer; + VkDeviceSize offset{}; + vkCmdBindVertexBuffers(commandBufferRef.Cmd, 0, 1, &vertexBufRef.Buffer.Buffer, &offset); + } } void VulkanContext::BindIndexBuffer(uint32_t commandBufferId, uint32_t bufferId) { auto& commandBufferRef = GetResource(_commandBuffers, commandBufferId); - check(commandBufferRef.IsRecording); // Must be in recording state - check(commandBufferRef.ActiveRenderPass); // Must be in a render pass + furyassert(commandBufferRef.IsRecording); // Must be in recording state + furyassert(commandBufferRef.ActiveRenderPass); // Must be in a render pass auto& indexBufRef = GetResource(_vertexBuffers, bufferId); - VkDeviceSize offset{}; - vkCmdBindIndexBuffer(commandBufferRef.Cmd, indexBufRef.Buffer.Buffer, offset, VK_INDEX_TYPE_UINT32); + if (commandBufferRef.CurrentIndexBuffer != indexBufRef.Buffer.Buffer) + { + commandBufferRef.CurrentIndexBuffer = indexBufRef.Buffer.Buffer; + VkDeviceSize offset{}; + vkCmdBindIndexBuffer(commandBufferRef.Cmd, indexBufRef.Buffer.Buffer, offset, VK_INDEX_TYPE_UINT32); + } } void VulkanContext::Draw(uint32_t commandBufferId, uint32_t firstVertex, uint32_t count) { auto& commandBufferRef = GetResource(_commandBuffers, commandBufferId); - check(commandBufferRef.IsRecording); // Must be in recording state - check(commandBufferRef.ActiveRenderPass); // Must be in a render pass + furyassert(commandBufferRef.IsRecording); // Must be in recording state + furyassert(commandBufferRef.ActiveRenderPass); // Must be in a render pass vkCmdDraw(commandBufferRef.Cmd, count, 1, firstVertex, 0); } @@ -1716,8 +2495,8 @@ void VulkanContext::DrawIndexed(uint32_t commandBufferId, uint32_t index_count, uint32_t first_index, uint32_t first_vertex) { auto& commandBufferRef = GetResource(_commandBuffers, commandBufferId); - check(commandBufferRef.IsRecording); // Must be in recording state - check(commandBufferRef.ActiveRenderPass); // Must be in a render pass + furyassert(commandBufferRef.IsRecording); // Must be in recording state + furyassert(commandBufferRef.ActiveRenderPass); // Must be in a render pass vkCmdDrawIndexed(commandBufferRef.Cmd, index_count, 1, first_index, first_vertex, 0); } @@ -1726,8 +2505,8 @@ void VulkanContext::DrawIndexedIndirect(uint32_t commandBufferId, uint32_t buffer, uint32_t offset, uint32_t drawCount, uint32_t stride) { auto& commandBufferRef = GetResource(_commandBuffers, commandBufferId); - check(commandBufferRef.IsRecording); // Must be in recording state - check(commandBufferRef.ActiveRenderPass); // Must be in a render pass + furyassert(commandBufferRef.IsRecording); // Must be in recording state + furyassert(commandBufferRef.ActiveRenderPass); // Must be in a render pass auto& indirectBufferRef = GetResource(_indirectBuffers, buffer); @@ -1739,21 +2518,123 @@ void VulkanContext::BindDescriptorSet(uint32_t commandBufferId, uint32_t setIndex, uint32_t descriptorSetId) { auto& commandBufferRef = GetResource(_commandBuffers, commandBufferId); - check(commandBufferRef.IsRecording); // Must be in recording state - check(commandBufferRef.ActiveRenderPass); // Must be in a render pass + furyassert(commandBufferRef.IsRecording); // Must be in recording state + +#if _DEBUG + if (commandBufferRef.BoundPipelineType != EPipelineType::COMPUTE) + { + furyassert(commandBufferRef.ActiveRenderPass); // Must be in a render pass + } +#endif const DDescriptorSet& descriptorSetRef = GetResource(_descriptorSets, descriptorSetId); - vkCmdBindDescriptorSets( - commandBufferRef.Cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, descriptorSetRef.RootSignature->PipelineLayout, (uint32_t)descriptorSetRef.Frequency, 1, &descriptorSetRef.Sets[setIndex], 0, nullptr); + furyassert(setIndex < descriptorSetRef.Sets.size()); + + VkPipelineBindPoint bindPoint{ VK_PIPELINE_BIND_POINT_GRAPHICS }; + switch (commandBufferRef.BoundPipelineType) + { + case EPipelineType::GRAPHICS: + bindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + break; + case EPipelineType::COMPUTE: + bindPoint = VK_PIPELINE_BIND_POINT_COMPUTE; + break; + default: + furyassert(0); + break; + } + + vkCmdBindDescriptorSets(commandBufferRef.Cmd, bindPoint, descriptorSetRef.RootSignature->PipelineLayout, (uint32_t)descriptorSetRef.Frequency, 1, &descriptorSetRef.Sets[setIndex], 0, nullptr); +} + +void +VulkanContext::CopyImage(uint32_t commandId, uint32_t destImage, uint32_t width, uint32_t height, uint32_t mipMapIndex, uint32_t mipMapCount, uint32_t sourceImage) +{ + const auto& commandBufferRef = GetResource(_commandBuffers, commandId); + furyassert(commandBufferRef.IsRecording); // Must be in recording state + furyassert(!commandBufferRef.ActiveRenderPass); // Must be in a render pass + + VkImageCopy region{}; + // region.srcSubresource.aspectMask = sourceImageRef.ImageAspect; + region.srcSubresource.mipLevel = mipMapIndex; + region.srcSubresource.baseArrayLayer = 0; + region.srcSubresource.layerCount = mipMapCount; + region.srcOffset.x; + region.srcOffset.y; + region.srcOffset.z; + // region.dstSubresource.aspectMask = destImageRef.ImageAspect; + region.dstSubresource.mipLevel = mipMapIndex; + region.dstSubresource.baseArrayLayer = 0; + region.dstSubresource.layerCount = mipMapCount; + region.dstOffset.x; + region.dstOffset.y; + region.dstOffset.z; + region.extent.width = width; + region.extent.height = height; + region.extent.depth = 1; + + VkImage srcImage{}; + VkImage dstImage{}; + + switch ((EResourceType)ResourceId(sourceImage).First()) + { + case EResourceType::IMAGE: + { + const auto& sourceImageRef = GetResource(_images, sourceImage); + region.srcSubresource.aspectMask = sourceImageRef.ImageAspect; + srcImage = sourceImageRef.Image.Image; + } + break; + case EResourceType::RENDER_TARGET: + { + const auto& sourceImageRef = GetResource(_renderTargets, sourceImage); + region.srcSubresource.aspectMask = sourceImageRef.ImageAspect; + srcImage = sourceImageRef.Image.Image; + } + break; + + default: + furyassert(0); + break; + }; + + switch ((EResourceType)ResourceId(destImage).First()) + { + case EResourceType::IMAGE: + { + const auto& destImageRef = GetResource(_images, destImage); + region.dstSubresource.aspectMask = destImageRef.ImageAspect; + dstImage = destImageRef.Image.Image; + } + break; + case EResourceType::RENDER_TARGET: + { + const auto& destImageRef = GetResource(_renderTargets, destImage); + region.dstSubresource.aspectMask = destImageRef.ImageAspect; + dstImage = destImageRef.Image.Image; + } + break; + + default: + furyassert(0); + break; + }; + + furyassert(srcImage); + furyassert(dstImage); + + const VkImageLayout sourceLayout{ VkImageLayout::VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL }; + const VkImageLayout destLayout{ VkImageLayout::VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL }; + vkCmdCopyImage(commandBufferRef.Cmd, srcImage, sourceLayout, dstImage, destLayout, 1, ®ion); } void -VulkanContext::CopyImage(uint32_t commandId, uint32_t imageId, uint32_t width, uint32_t height, uint32_t mipMapIndex, uint32_t stagingBufferId, uint32_t stagingBufferOffset) +VulkanContext::CopyBufferToImage(uint32_t commandId, uint32_t imageId, uint32_t width, uint32_t height, uint32_t mipMapIndex, uint32_t stagingBufferId, uint32_t stagingBufferOffset) { auto& commandBufferRef = GetResource(_commandBuffers, commandId); - check(commandBufferRef.IsRecording); // Must be in recording state - check(!commandBufferRef.ActiveRenderPass); // Must be in a render pass + furyassert(commandBufferRef.IsRecording); // Must be in recording state + furyassert(!commandBufferRef.ActiveRenderPass); // Must be in a render pass auto& imageRef = GetResource(_images, imageId); auto& buffRef = GetResource(_transferBuffers, stagingBufferId); @@ -1777,7 +2658,154 @@ VulkanContext::CopyImage(uint32_t commandId, uint32_t imageId, uint32_t width, u } void -VulkanContext::QueueSubmit(const std::vector& waitSemaphore, const std::vector& finishSemaphore, const std::vector& cmdIds, uint32_t fenceId) +VulkanContext::CopyBuffer(uint32_t commandId, uint32_t bufferId, uint32_t offset, uint32_t bytes, uint32_t stagingBufferId, uint32_t stagingBufferOffset) +{ + auto& commandBufferRef = GetResource(_commandBuffers, commandId); + furyassert(commandBufferRef.IsRecording); // Must be in recording state + furyassert(!commandBufferRef.ActiveRenderPass); // Must be in a render pass + + auto& vertexRef = GetResource(_vertexBuffers, bufferId); + auto& buffRef = GetResource(_transferBuffers, stagingBufferId); + + VkBufferCopy copy{}; + copy.dstOffset = offset; + copy.size = bytes; + copy.srcOffset = stagingBufferOffset; + + vkCmdCopyBuffer(commandBufferRef.Cmd, buffRef.Buffer.Buffer, vertexRef.Buffer.Buffer, 1, ©); +} + +void +Fox::VulkanContext::SetStencilTest(uint32_t commandId, bool enable, const DStencilOpState* frontFace, const DStencilOpState* backFace) +{ + auto& commandBufferRef = GetResource(_commandBuffers, commandId); + furyassert(commandBufferRef.IsRecording); // Must be in recording state + furyassert(commandBufferRef.ActiveRenderPass); // Must be in a render pass +#if _DEBUG + if (enable) + { + furyassert(enable && frontFace && backFace); + } +#endif + + vkCmdSetStencilTestEnable(commandBufferRef.Cmd, static_cast(enable)); + + DStencilOpState defaultStencilState{}; + if (!frontFace) + { + frontFace = &defaultStencilState; + } + if (!backFace) + { + backFace = &defaultStencilState; + } + + // If has same stencil op for back and front do optimization + if (frontFace == backFace) + { + const VkStencilOp failOp{ VkUtils::VkStencilOpFromStencilOp(frontFace->FailOp) }; + const VkStencilOp passOp{ VkUtils::VkStencilOpFromStencilOp(frontFace->PassOp) }; + const VkStencilOp depthFailOp{ VkUtils::VkStencilOpFromStencilOp(frontFace->DepthFailOp) }; + const VkCompareOp compareOp{ VkUtils::VkCompareOpFromCompareOp(frontFace->CompareOp) }; + vkCmdSetStencilOp(commandBufferRef.Cmd, VkStencilFaceFlagBits::VK_STENCIL_FACE_FRONT_AND_BACK, failOp, passOp, depthFailOp, compareOp); + + vkCmdSetStencilReference(commandBufferRef.Cmd, VkStencilFaceFlagBits::VK_STENCIL_FACE_FRONT_AND_BACK, frontFace->Reference); + vkCmdSetStencilCompareMask(commandBufferRef.Cmd, VkStencilFaceFlagBits::VK_STENCIL_FACE_FRONT_AND_BACK, frontFace->CompareMask); + vkCmdSetStencilWriteMask(commandBufferRef.Cmd, VkStencilFaceFlagBits::VK_STENCIL_FACE_FRONT_AND_BACK, frontFace->WriteMask); + } + else + // Separate for front and back + { + { + // Front face + const VkStencilOp failOp{ VkUtils::VkStencilOpFromStencilOp(frontFace->FailOp) }; + const VkStencilOp passOp{ VkUtils::VkStencilOpFromStencilOp(frontFace->PassOp) }; + const VkStencilOp depthFailOp{ VkUtils::VkStencilOpFromStencilOp(frontFace->DepthFailOp) }; + const VkCompareOp compareOp{ VkUtils::VkCompareOpFromCompareOp(frontFace->CompareOp) }; + vkCmdSetStencilOp(commandBufferRef.Cmd, VkStencilFaceFlagBits::VK_STENCIL_FACE_FRONT_BIT, failOp, passOp, depthFailOp, compareOp); + + vkCmdSetStencilReference(commandBufferRef.Cmd, VkStencilFaceFlagBits::VK_STENCIL_FACE_FRONT_BIT, frontFace->Reference); + vkCmdSetStencilCompareMask(commandBufferRef.Cmd, VkStencilFaceFlagBits::VK_STENCIL_FACE_FRONT_BIT, frontFace->CompareMask); + vkCmdSetStencilWriteMask(commandBufferRef.Cmd, VkStencilFaceFlagBits::VK_STENCIL_FACE_FRONT_BIT, frontFace->WriteMask); + } + { + // Back face + const VkStencilOp failOp{ VkUtils::VkStencilOpFromStencilOp(backFace->FailOp) }; + const VkStencilOp passOp{ VkUtils::VkStencilOpFromStencilOp(backFace->PassOp) }; + const VkStencilOp depthFailOp{ VkUtils::VkStencilOpFromStencilOp(backFace->DepthFailOp) }; + const VkCompareOp compareOp{ VkUtils::VkCompareOpFromCompareOp(backFace->CompareOp) }; + vkCmdSetStencilOp(commandBufferRef.Cmd, VkStencilFaceFlagBits::VK_STENCIL_FACE_BACK_BIT, failOp, passOp, depthFailOp, compareOp); + + vkCmdSetStencilReference(commandBufferRef.Cmd, VkStencilFaceFlagBits::VK_STENCIL_FACE_BACK_BIT, backFace->Reference); + vkCmdSetStencilCompareMask(commandBufferRef.Cmd, VkStencilFaceFlagBits::VK_STENCIL_FACE_BACK_BIT, backFace->CompareMask); + vkCmdSetStencilWriteMask(commandBufferRef.Cmd, VkStencilFaceFlagBits::VK_STENCIL_FACE_BACK_BIT, backFace->WriteMask); + } + } +} + +void +VulkanContext::SetDepthTestCompareOp(uint32_t commandId, bool enabled, bool depthWrite, ECompareOp compareOp) +{ + auto& commandBufferRef = GetResource(_commandBuffers, commandId); + furyassert(commandBufferRef.IsRecording); // Must be in recording state + furyassert(commandBufferRef.ActiveRenderPass); // Must be in a render pass + + vkCmdSetDepthTestEnable(commandBufferRef.Cmd, static_cast(enabled)); + vkCmdSetDepthWriteEnable(commandBufferRef.Cmd, static_cast(depthWrite)); + const VkCompareOp compareOpVk{ VkUtils::VkCompareOpFromCompareOp(compareOp) }; + vkCmdSetDepthCompareOp(commandBufferRef.Cmd, compareOpVk); +} + +void +VulkanContext::SetPrimitiveTopology(uint32_t commandId, ETopology primitiveTopology) +{ + auto& commandBufferRef = GetResource(_commandBuffers, commandId); + furyassert(commandBufferRef.IsRecording); // Must be in recording state + furyassert(commandBufferRef.ActiveRenderPass); // Must be in a render pass + + const auto topology{ VkUtils::VkPrimitiveTopologyFromTopology(primitiveTopology) }; + vkCmdSetPrimitiveTopology(commandBufferRef.Cmd, topology); +} + +void +VulkanContext::SetLineWidth(uint32_t commandId, float lineWidth) +{ + auto& commandBufferRef = GetResource(_commandBuffers, commandId); + furyassert(commandBufferRef.IsRecording); // Must be in recording state + furyassert(commandBufferRef.ActiveRenderPass); // Must be in a render pass + + vkCmdSetLineWidth(commandBufferRef.Cmd, lineWidth); +} + +void +VulkanContext::DispatchCompute(uint32_t commandId, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ) +{ + auto& commandBufferRef = GetResource(_commandBuffers, commandId); + furyassert(commandBufferRef.IsRecording); // Must be in recording state + + vkCmdDispatch(commandBufferRef.Cmd, groupCountX, groupCountY, groupCountZ); +} + +void +VulkanContext::ComputeWorkGroupCount(uint32_t* groupCountX, uint32_t* groupCountY, uint32_t* groupCountZ) +{ + *groupCountX = Device.DeviceProperties.limits.maxComputeWorkGroupCount[0]; + *groupCountY = Device.DeviceProperties.limits.maxComputeWorkGroupCount[1]; + *groupCountZ = Device.DeviceProperties.limits.maxComputeWorkGroupCount[2]; +} + +void +VulkanContext::PushConstant(uint32_t commandId, EShaderStage stage, uint32_t offset, uint32_t size, void* data) +{ + auto& commandBufferRef = GetResource(_commandBuffers, commandId); + furyassert(commandBufferRef.IsRecording); // Must be in recording state + furyassert(commandBufferRef.ActiveRenderPass); // Must be in a render pass + + vkCmdPushConstants(commandBufferRef.Cmd, *commandBufferRef.BoundPipelineLayout, VK_SHADER_STAGE_ALL_GRAPHICS, offset, size, data); +} + +void +VulkanContext::QueueSubmit(uint32_t queueId, const std::vector& waitSemaphore, const std::vector& finishSemaphore, const std::vector& cmdIds, uint32_t fenceId) { std::vector commandBuffers; for (auto cmdId : cmdIds) @@ -1819,7 +2847,9 @@ VulkanContext::QueueSubmit(const std::vector& waitSemaphore, const std submitInfo.signalSemaphoreCount = (uint32_t)finishSemaphores.size(); submitInfo.pSignalSemaphores = finishSemaphores.data(); - const VkResult result = vkQueueSubmit(Device.MainQueue, 1, &submitInfo, fenceRef != nullptr ? fenceRef->Fence : VK_NULL_HANDLE); + const auto& queueRef = GetResource(_queues, queueId); + + const VkResult result = vkQueueSubmit(queueRef.QueuePtr, 1, &submitInfo, fenceRef != nullptr ? fenceRef->Fence : VK_NULL_HANDLE); if (VKFAILED(result)) { throw std::runtime_error(VkUtils::VkErrorString(result)); @@ -1827,16 +2857,17 @@ VulkanContext::QueueSubmit(const std::vector& waitSemaphore, const std } void -VulkanContext::QueuePresent(uint32_t swapchainId, uint32_t imageIndex, const std::vector& waitSemaphore) +VulkanContext::QueuePresent(uint32_t queueId, uint32_t swapchainId, uint32_t imageIndex, const std::vector& waitSemaphore) { - std::vector waitSemaphores; + static std::vector waitSemaphores(10); + waitSemaphores.clear(); for (auto semaphoreId : waitSemaphore) { auto& semaphoreRef = GetResource(_semaphores, semaphoreId); waitSemaphores.push_back(semaphoreRef.Semaphore); } - auto& swapchainRef = GetResource(_swapchains, swapchainId); + const auto& swapchainRef = GetResource(_swapchains, swapchainId); VkPresentInfoKHR presentInfo{}; presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; @@ -1847,8 +2878,10 @@ VulkanContext::QueuePresent(uint32_t swapchainId, uint32_t imageIndex, const std presentInfo.pImageIndices = &imageIndex; presentInfo.pResults = nullptr; - const VkResult result = vkQueuePresentKHR(Device.MainQueue, &presentInfo); - if (result == VK_SUCCESS || VK_SUBOPTIMAL_KHR) + const auto& queueRef = GetResource(_queues, queueId); + + const VkResult result = vkQueuePresentKHR(queueRef.QueuePtr, &presentInfo); + if (result == VK_SUCCESS || result == VK_SUBOPTIMAL_KHR) { return; } @@ -1949,7 +2982,7 @@ VulkanContext::DestroyGpuSemaphore(uint32_t semaphoreId) uint32_t VulkanContext::CreateRenderTarget(EFormat format, ESampleBit samples, bool isDepth, uint32_t width, uint32_t height, uint32_t arrayLength, uint32_t mipMapCount, EResourceState initialState) { - check(samples == ESampleBit::COUNT_1_BIT); + furyassert(samples == ESampleBit::COUNT_1_BIT); VkImageUsageFlags usageFlags{}; @@ -1984,8 +3017,8 @@ VulkanContext::CreateRenderTarget(EFormat format, ESampleBit samples, bool isDep } break; case EResourceState::UNORDERED_ACCESS: - initialLayout = VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL; // Valid? - check(0); // Verify is correct + initialLayout = VK_IMAGE_LAYOUT_GENERAL; // Valid? + // furyassert(0); // Verify is correct break; case EResourceState::DEPTH_WRITE: initialLayout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL; @@ -2027,13 +3060,14 @@ VulkanContext::CreateRenderTarget(EFormat format, ESampleBit samples, bool isDep case EResourceState::RAYTRACING_ACCELERATION_STRUCTURE: case EResourceState::SHADING_RATE_SOURCE: default: - check(0); + furyassert(0); break; } const auto index = AllocResource(_renderTargets); auto& renderTargetRef = _renderTargets.at(index); - renderTargetRef.Image = Device.CreateImageDeviceLocal(width, height, mipMapCount, vkFormat, usageFlags, VK_IMAGE_TILING_OPTIMAL, initialLayout); + renderTargetRef.Image = + Device.CreateImageDeviceLocal(width, height, mipMapCount, vkFormat, VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | usageFlags, VK_IMAGE_TILING_OPTIMAL, initialLayout); renderTargetRef.ImageAspect = VkUtils::isColorFormat(vkFormat) ? VK_IMAGE_ASPECT_COLOR_BIT : VK_IMAGE_ASPECT_DEPTH_BIT; if (VkUtils::formatHasStencil(vkFormat)) @@ -2057,6 +3091,29 @@ VulkanContext::DestroyRenderTarget(uint32_t renderTargetId) { auto& renderTargetRef = GetResource(_renderTargets, renderTargetId); + // Must destroy all framebuffers that reference this render target @TODO find a better algorithm without iterating over the array multiple times + for (uint32_t i = 0; i < _framebuffers.size(); i++) + { + DFramebufferVulkan& fbo{ _framebuffers[i] }; + if (fbo.Id == FREE || fbo.Id == PENDING_DESTROY) + continue; + + if (fbo.Attachments.DepthStencil == renderTargetId) + { + Device._destroyFramebuffer(fbo.Framebuffer); + fbo.Framebuffer = nullptr; + fbo.Id = FREE; + break; + } + else if (fbo.Attachments.HasColorAttachment(renderTargetId)) + { + Device._destroyFramebuffer(fbo.Framebuffer); + fbo.Framebuffer = nullptr; + fbo.Id = FREE; + break; + } + } + Device.DestroyImageView(renderTargetRef.View); Device.DestroyImage(renderTargetRef.Image); @@ -2076,11 +3133,91 @@ RenderTargetBarrier* p_rt_barriers) std::vector imageBarriers; imageBarriers.resize(rt_barrier_count + texture_barrier_count); + memset(imageBarriers.data(), 0, sizeof(VkImageMemoryBarrier) * imageBarriers.size()); uint32_t imageBarrierCount{}; + std::vector bufferBarriers; + bufferBarriers.resize(buffer_barrier_count); + memset(bufferBarriers.data(), 0, sizeof(VkBufferMemoryBarrier) * bufferBarriers.size()); + uint32_t bufferBarrierCount{}; + VkAccessFlags srcAccessFlags = 0; VkAccessFlags dstAccessFlags = 0; + for (uint32_t i = 0; i < buffer_barrier_count; ++i) + { + BufferBarrier* pTrans = &p_buffer_barriers[i]; + + const auto resourceType = ResourceId(pTrans->BufferId).First(); + const auto index = ResourceId(pTrans->BufferId).Value(); + DBufferVulkan* bufferPtr{}; + switch (resourceType) + { + case EResourceType::UNIFORM_BUFFER: + bufferPtr = &_uniformBuffers.at(index); + break; + case EResourceType::VERTEX_INDEX_BUFFER: + bufferPtr = &_vertexBuffers.at(index); + break; + case EResourceType::TRANSFER: + bufferPtr = &_transferBuffers.at(index); + break; + default: + furyassert(0); // Invalid type + break; + } + VkBuffer pBuffer = bufferPtr->Buffer.Buffer; + VkBufferMemoryBarrier* pBufferBarrier = NULL; + + if (EResourceState::UNORDERED_ACCESS == pTrans->CurrentState && EResourceState::UNORDERED_ACCESS == pTrans->NewState) + { + pBufferBarrier = &bufferBarriers[bufferBarrierCount++]; //-V522 + pBufferBarrier->sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER; //-V522 + pBufferBarrier->pNext = NULL; + + pBufferBarrier->srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT; + pBufferBarrier->dstAccessMask = VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT; + } + else + { + pBufferBarrier = &bufferBarriers[bufferBarrierCount++]; + pBufferBarrier->sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER; + pBufferBarrier->pNext = NULL; + + pBufferBarrier->srcAccessMask = VkUtils::resourceStateToAccessFlag(pTrans->CurrentState); + pBufferBarrier->dstAccessMask = VkUtils::resourceStateToAccessFlag(pTrans->NewState); + } + + if (pBufferBarrier) + { + pBufferBarrier->buffer = pBuffer; + pBufferBarrier->size = VK_WHOLE_SIZE; + pBufferBarrier->offset = 0; + + switch (pTrans->TransferOwnership) + { + default: + case ETransferOwnership::NONE: + pBufferBarrier->srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + pBufferBarrier->dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + break; + case ETransferOwnership::ACQUIRE: + case ETransferOwnership::RELEASE: + { + furyassert(pTrans->SrcQueue > 0); + const auto& srcQueueRef = GetResource(_queues, pTrans->SrcQueue); + pBufferBarrier->srcQueueFamilyIndex = srcQueueRef.QueueFamilyIndex; + const auto& dstQueueRef = GetResource(_queues, pTrans->DstQueue); + pBufferBarrier->dstQueueFamilyIndex = dstQueueRef.QueueFamilyIndex; + break; + } + } + + srcAccessFlags |= pBufferBarrier->srcAccessMask; + dstAccessFlags |= pBufferBarrier->dstAccessMask; + } + } + for (uint32_t i = 0; i < texture_barrier_count; ++i) { TextureBarrier* pTrans = &p_texture_barriers[i]; @@ -2104,10 +3241,11 @@ RenderTargetBarrier* p_rt_barriers) pImageBarrier->sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; pImageBarrier->pNext = NULL; - pImageBarrier->srcAccessMask = VkUtils::resourceStateToAccessFlag(pTrans->CurrentState); - pImageBarrier->dstAccessMask = VkUtils::resourceStateToAccessFlag(pTrans->NewState); - pImageBarrier->oldLayout = VkUtils::resourceStateToImageLayout(pTrans->CurrentState); - pImageBarrier->newLayout = VkUtils::resourceStateToImageLayout(pTrans->NewState); + pImageBarrier->subresourceRange.aspectMask = (VkImageAspectFlags)imageRef.ImageAspect; + pImageBarrier->srcAccessMask = VkUtils::resourceStateToAccessFlag(pTrans->CurrentState); + pImageBarrier->dstAccessMask = VkUtils::resourceStateToAccessFlag(pTrans->NewState); + pImageBarrier->oldLayout = VkUtils::resourceStateToImageLayout(pTrans->CurrentState); + pImageBarrier->newLayout = VkUtils::resourceStateToImageLayout(pTrans->NewState); } if (pImageBarrier) @@ -2119,21 +3257,24 @@ RenderTargetBarrier* p_rt_barriers) pImageBarrier->subresourceRange.baseArrayLayer = pTrans->mSubresourceBarrier ? pTrans->mArrayLayer : 0; pImageBarrier->subresourceRange.layerCount = pTrans->mSubresourceBarrier ? 1 : VK_REMAINING_ARRAY_LAYERS; - // if (pTrans->mAcquire && pTrans->mCurrentState != RESOURCE_STATE_UNDEFINED) - // { - // pImageBarrier->srcQueueFamilyIndex = pCmd->pRenderer->mVulkan.mQueueFamilyIndices[pTrans->mQueueType]; - // pImageBarrier->dstQueueFamilyIndex = pCmd->pQueue->mVulkan.mVkQueueFamilyIndex; - // } - // else if (pTrans->mRelease && pTrans->mCurrentState != RESOURCE_STATE_UNDEFINED) - // { - // pImageBarrier->srcQueueFamilyIndex = pCmd->pQueue->mVulkan.mVkQueueFamilyIndex; - // pImageBarrier->dstQueueFamilyIndex = pCmd->pRenderer->mVulkan.mQueueFamilyIndices[pTrans->mQueueType]; - // } - // else - { - pImageBarrier->srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - pImageBarrier->dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - } + switch (pTrans->TransferOwnership) + { + default: + case ETransferOwnership::NONE: + pImageBarrier->srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + pImageBarrier->dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + break; + case ETransferOwnership::ACQUIRE: + case ETransferOwnership::RELEASE: + { + furyassert(pTrans->SrcQueue > 0); + const auto& srcQueueRef = GetResource(_queues, pTrans->SrcQueue); + pImageBarrier->srcQueueFamilyIndex = srcQueueRef.QueueFamilyIndex; + const auto& dstQueueRef = GetResource(_queues, pTrans->DstQueue); + pImageBarrier->dstQueueFamilyIndex = dstQueueRef.QueueFamilyIndex; + break; + } + } srcAccessFlags |= pImageBarrier->srcAccessMask; dstAccessFlags |= pImageBarrier->dstAccessMask; @@ -2167,6 +3308,7 @@ RenderTargetBarrier* p_rt_barriers) pImageBarrier->dstAccessMask = VkUtils::resourceStateToAccessFlag(pTrans->mNewState); pImageBarrier->oldLayout = VkUtils::resourceStateToImageLayout(pTrans->mCurrentState); pImageBarrier->newLayout = VkUtils::resourceStateToImageLayout(pTrans->mNewState); + furyassert(pImageBarrier->newLayout != VK_IMAGE_LAYOUT_UNDEFINED && pImageBarrier->newLayout != VK_IMAGE_LAYOUT_PREINITIALIZED); } if (pImageBarrier) @@ -2178,39 +3320,51 @@ RenderTargetBarrier* p_rt_barriers) pImageBarrier->subresourceRange.baseArrayLayer = pTrans->mSubresourceBarrier ? pTrans->mArrayLayer : 0; pImageBarrier->subresourceRange.layerCount = pTrans->mSubresourceBarrier ? 1 : VK_REMAINING_ARRAY_LAYERS; - // if (pTrans->mAcquire && pTrans->mCurrentState != EResourceState::UNDEFINED) - // { - // pImageBarrier->srcQueueFamilyIndex = pCmd->pRenderer->mVulkan.mQueueFamilyIndices[pTrans->mQueueType]; - // pImageBarrier->dstQueueFamilyIndex = pCmd->pQueue->mVulkan.mVkQueueFamilyIndex; - // } - // else if (pTrans->mRelease && pTrans->mCurrentState != EResourceState::UNDEFINED) - // { - // pImageBarrier->srcQueueFamilyIndex = pCmd->pQueue->mVulkan.mVkQueueFamilyIndex; - // pImageBarrier->dstQueueFamilyIndex = pCmd->pRenderer->mVulkan.mQueueFamilyIndices[pTrans->mQueueType]; - // } - // else - { - pImageBarrier->srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - pImageBarrier->dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - } + switch (pTrans->TransferOwnership) + { + default: + case ETransferOwnership::NONE: + pImageBarrier->srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + pImageBarrier->dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + break; + case ETransferOwnership::ACQUIRE: + case ETransferOwnership::RELEASE: + { + furyassert(pTrans->SrcQueue > 0); + const auto& srcQueueRef = GetResource(_queues, pTrans->SrcQueue); + pImageBarrier->srcQueueFamilyIndex = srcQueueRef.QueueFamilyIndex; + const auto& dstQueueRef = GetResource(_queues, pTrans->DstQueue); + pImageBarrier->dstQueueFamilyIndex = dstQueueRef.QueueFamilyIndex; + break; + } + } srcAccessFlags |= pImageBarrier->srcAccessMask; dstAccessFlags |= pImageBarrier->dstAccessMask; } } - VkPipelineStageFlags srcStageMask = VkUtils::determinePipelineStageFlags(srcAccessFlags, EQueueType::GRAPHICS); - VkPipelineStageFlags dstStageMask = VkUtils::determinePipelineStageFlags(dstAccessFlags, EQueueType::GRAPHICS); + auto& commandBufferRef = GetResource(_commandBuffers, commandBufferId); + VkPipelineStageFlags srcStageMask = VkUtils::determinePipelineStageFlags(srcAccessFlags, commandBufferRef.Type); + VkPipelineStageFlags dstStageMask = VkUtils::determinePipelineStageFlags(dstAccessFlags, commandBufferRef.Type); { - auto& commandBufferRef = GetResource(_commandBuffers, commandBufferId); - check(commandBufferRef.IsRecording); // Must be in recording state + furyassert(commandBufferRef.IsRecording); // Must be in recording state // If previous active render pass end it if (commandBufferRef.ActiveRenderPass) { vkCmdEndRenderPass(commandBufferRef.Cmd); commandBufferRef.ActiveRenderPass = nullptr; + commandBufferRef.BoundFramebuffer = nullptr; + } + +#if _DEBUG && DEBUG_RT_TRANSITIONS 1 + for (size_t i = 0; i < imageBarriers.size(); i++) + { + std::cout << "Explicit Image barrier for VkImage:" << imageBarriers.at(i).image << " from layout:" << VkUtils::VkImageLayoutToString(imageBarriers.at(i).oldLayout) << " to " + << VkUtils::VkImageLayoutToString(imageBarriers.at(i).newLayout) << std::endl; } +#endif vkCmdPipelineBarrier(commandBufferRef.Cmd, srcStageMask, dstStageMask, 0, 0, NULL, 0, NULL, (uint32_t)imageBarriers.size(), imageBarriers.data()); } @@ -2256,7 +3410,8 @@ uint32_t stride) RIVulkanPipelineBuilder pipe(shaderStages, { inputBinding }, vertexInputAttributes, pipelineLayout, renderPass); pipe.AddViewport({}); pipe.AddScissor({}); - pipe.SetDynamicState({ VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR }); + pipe.SetLineWidth(format.LineWidth); + // pipe.SetDynamicState({ VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR }); switch (format.FillMode) { case EFillMode::FILL: @@ -2266,7 +3421,7 @@ uint32_t stride) pipe.SetPolygonMode(VK_POLYGON_MODE_LINE); break; default: - check(0); + furyassert(0); break; } switch (format.CullMode) @@ -2281,34 +3436,11 @@ uint32_t stride) pipe.SetCulling(VK_CULL_MODE_BACK_BIT); break; default: - check(0); - break; - } - switch (format.DepthTestMode) - { - case EDepthTest::ALWAYS: - pipe.SetDepthTestingOp(VK_COMPARE_OP_ALWAYS); - break; - case EDepthTest::NEVER: - pipe.SetDepthTestingOp(VK_COMPARE_OP_NEVER); - break; - case EDepthTest::LESS: - pipe.SetDepthTestingOp(VK_COMPARE_OP_LESS); - break; - case EDepthTest::LESS_OR_EQUAL: - pipe.SetDepthTestingOp(VK_COMPARE_OP_LESS_OR_EQUAL); - break; - case EDepthTest::GREATER: - pipe.SetDepthTestingOp(VK_COMPARE_OP_GREATER); - break; - case EDepthTest::GREATER_OR_EQUAL: - pipe.SetDepthTestingOp(VK_COMPARE_OP_GREATER_OR_EQUAL); - break; - default: - pipe.SetDepthTestingOp(VK_COMPARE_OP_LESS_OR_EQUAL); - critical(0); + furyassert(0); break; } + const auto vkCompareOpValue{ VkUtils::VkCompareOpFromCompareOp(format.DepthTestMode) }; + pipe.SetDepthTestingOp(vkCompareOpValue); pipe.SetDepthTesting(format.DepthTest, format.DepthWrite); pipe.SetDepthStencil(format.StencilTest); pipe.SetDepthStencilOp(VkStencilOpState{ VK_STENCIL_OP_KEEP, VK_STENCIL_OP_KEEP, VK_STENCIL_OP_KEEP, VK_COMPARE_OP_LESS_OR_EQUAL, 0, 0, 0 }); @@ -2356,6 +3488,31 @@ VulkanContext::GetAdapterDedicatedVideoMemory() const return 0; } +float +VulkanContext::GetMaxAnisotropyFiltering(bool* isSupported) const +{ + VkPhysicalDeviceFeatures deviceFeatures{}; + vkGetPhysicalDeviceFeatures(Device.PhysicalDevice, &deviceFeatures); + + if (deviceFeatures.samplerAnisotropy) + { + VkPhysicalDeviceProperties deviceProperties{}; + vkGetPhysicalDeviceProperties(Device.PhysicalDevice, &deviceProperties); + + const float maxAnisotropy = deviceProperties.limits.maxSamplerAnisotropy; + if (isSupported) + { + *isSupported = true; + } + return maxAnisotropy; + } + if (isSupported) + { + *isSupported = false; + } + return 0.0f; +} + void VulkanContext::Warning(const std::string& error) { @@ -2444,19 +3601,19 @@ VulkanContext::_getInstanceSupportedExtensions(const std::vector& e const auto validExtentionsNames = VkUtils::convertExtensionPropertiesToNames(validExtensions); std::vector supportedExtensions = VkUtils::filterInclusive(extentions, validExtentionsNames); { - const std::string out = "Available extensions requested:" + std::to_string(supportedExtensions.size()) + "/" + std::to_string(extentions.size()); - Log(out); + // const std::string out = "Available extensions requested:" + std::to_string(supportedExtensions.size()) + "/" + std::to_string(extentions.size()); + // Log(out); // Print not supported validation layers - if (supportedExtensions.size() != extentions.size()) - { - Log("Unsupported instance extensions"); - std::vector unsupportedExtensions = VkUtils::filterExclusive(validExtentionsNames, extentions); - for (const char* extensionName : unsupportedExtensions) - { - Log(extensionName); - } - } + // if (supportedExtensions.size() != extentions.size()) + // { + // Log("Unsupported instance extensions"); + // std::vector unsupportedExtensions = VkUtils::filterExclusive(validExtentionsNames, extentions); + // for (const char* extensionName : unsupportedExtensions) + // { + // Log(extensionName); + // } + // } } return supportedExtensions; } @@ -2469,19 +3626,19 @@ VulkanContext::_getInstanceSupportedValidationLayers(const std::vector supportedValidationLayers = VkUtils::filterInclusive(validationLayers, layerNames); { - const std::string out = "Available validation layers requested:" + std::to_string(supportedValidationLayers.size()) + "/" + std::to_string(validationLayers.size()); - Log(out); - // Print not supported validation layers - if (supportedValidationLayers.size() != validationLayers.size()) - { - Log("Unsupported instance validation layers:"); - - std::vector unsupportedValidationLayers = VkUtils::filterExclusive(layerNames, validationLayers); - for (const char* layerName : unsupportedValidationLayers) - { - Log(layerName); - } - } + // const std::string out = "Available validation layers requested:" + std::to_string(supportedValidationLayers.size()) + "/" + std::to_string(validationLayers.size()); + // Log(out); + // Print not supported validation layers + // if (supportedValidationLayers.size() != validationLayers.size()) + // { + // Log("Unsupported instance validation layers:"); + + // std::vector unsupportedValidationLayers = VkUtils::filterExclusive(layerNames, validationLayers); + // for (const char* layerName : unsupportedValidationLayers) + // { + // Log(layerName); + // } + // } } return supportedValidationLayers; @@ -2510,18 +3667,18 @@ VulkanContext::_getDeviceSupportedExtensions(VkPhysicalDevice physicalDevice, co const auto extensionNames = VkUtils::convertExtensionPropertiesToNames(validExtensions); std::vector deviceSupportedExtensions = VkUtils::filterInclusive(extentions, extensionNames); - const std::string out = "Available device extensions requested:" + std::to_string(deviceSupportedExtensions.size()) + "/" + std::to_string(extentions.size()); - Log(out); + // const std::string out = "Available device extensions requested:" + std::to_string(deviceSupportedExtensions.size()) + "/" + std::to_string(extentions.size()); + // Log(out); // Print not supported validation layers if (deviceSupportedExtensions.size() != extentions.size()) { - Log("Unsupported device extensions:"); - std::vector deviceUnsupportedExtensions = VkUtils::filterExclusive(extensionNames, extentions); - for (const char* extensionName : deviceUnsupportedExtensions) - { - Log(extensionName); - } + // Log("Unsupported device extensions:"); + // std::vector deviceUnsupportedExtensions = VkUtils::filterExclusive(extensionNames, extentions); + // for (const char* extensionName : deviceUnsupportedExtensions) + // { + // Log(extensionName); + // } } return deviceSupportedExtensions; @@ -2530,22 +3687,22 @@ VulkanContext::_getDeviceSupportedExtensions(VkPhysicalDevice physicalDevice, co std::vector VulkanContext::_getDeviceSupportedValidationLayers(VkPhysicalDevice physicalDevice, const std::vector& validationLayers) { - const auto validExtentions = VkUtils::getDeviceExtensionProperties(physicalDevice); - const auto validExtentionsNames = VkUtils::convertExtensionPropertiesToNames(validExtentions); - std::vector deviceSupportedValidationLayers = VkUtils::filterInclusive(validationLayers, validExtentionsNames); + const auto validlayers = VkUtils::getDeviceLayerProperties(physicalDevice); + const auto validLayerNames = VkUtils::convertLayerPropertiesToNames(validlayers); + std::vector deviceSupportedValidationLayers = VkUtils::filterInclusive(validationLayers, validLayerNames); - const std::string out = "Available device validation layers requested:" + std::to_string(deviceSupportedValidationLayers.size()) + "/" + std::to_string(validationLayers.size()); - Log(out); + // const std::string out = "Available device validation layers requested:" + std::to_string(deviceSupportedValidationLayers.size()) + "/" + std::to_string(validationLayers.size()); + // Log(out); // Print not supported validation layers if (deviceSupportedValidationLayers.size() != validationLayers.size()) { - Log("Unsupported device validation layers:"); - std::vector deviceUnsupportedValidationLayers = VkUtils::filterExclusive(validExtentionsNames, validationLayers); - for (const char* layerName : deviceUnsupportedValidationLayers) - { - Log(layerName); - } + // Log("Unsupported device validation layers:"); + // std::vector deviceUnsupportedValidationLayers = VkUtils::filterExclusive(validExtentionsNames, validationLayers); + // for (const char* layerName : deviceUnsupportedValidationLayers) + // { + // Log(layerName); + // } } return deviceSupportedValidationLayers; @@ -2582,7 +3739,7 @@ ConvertRenderPassAttachmentsToRIVkRenderPassInfo(const DRenderPassAttachments& a info.DepthStencilAttachmentReference.emplace_back(ref); break; default: - check(0); + furyassert(0); break; } @@ -2591,9 +3748,9 @@ ConvertRenderPassAttachmentsToRIVkRenderPassInfo(const DRenderPassAttachments& a desc.samples = VkUtils::convertVkSampleCount(att.Samples); desc.loadOp = VkUtils::convertAttachmentLoadOp(att.LoadOP); desc.storeOp = VkUtils::convertAttachmentStoreOp(att.StoreOP); - // Stencil not used right now - desc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - desc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + // Stencil behave same as depth + desc.stencilLoadOp = desc.loadOp; + desc.stencilStoreOp = desc.storeOp; desc.initialLayout = VkUtils::convertRenderPassLayout(att.InitialLayout, VkUtils::isColorFormat(desc.format)); desc.finalLayout = VkUtils::convertRenderPassLayout(att.FinalLayout, VkUtils::isColorFormat(desc.format)); diff --git a/src/backend/vulkan/VulkanContext.h b/src/backend/vulkan/VulkanContext.h index 401458d..d1827e9 100644 --- a/src/backend/vulkan/VulkanContext.h +++ b/src/backend/vulkan/VulkanContext.h @@ -4,17 +4,21 @@ #include "IContext.h" +#include "VulkanInstance.h" //This first because it defines macros for vulkan platform + #include "DescriptorPool.h" #include "RingBufferManager.h" #include "VulkanDevice13.h" -#include "VulkanInstance.h" #include #include #include +#include #include #include +#define DEBUG_RT_TRANSITIONS 0 + namespace Fox { @@ -31,10 +35,49 @@ struct DBufferVulkan : public DResource struct DImageVulkan : public DResource { - RIVulkanImage Image; - VkImageView View{}; - VkImageAspectFlags ImageAspect{}; - VkSampler Sampler{}; + struct DMipMapRange + { + uint32_t First, Count; + }; + + struct DMipMapRangeHashFn + { + size_t operator()(const DMipMapRange& range) const + { + size_t hash{}; + hash += std::hash{}(range.First); + hash += (71 * hash + (size_t)std::hash{}(range.Count)) % 5; + return hash; + }; + }; + + struct DMipMapRangeEqualFn + { + bool operator()(const DMipMapRange& lhs, const DMipMapRange& rhs) const { return lhs.First == rhs.First && lhs.Count == rhs.Count; }; + }; + + inline static constexpr size_t MAX_IMAGE_VIEWS{ 32 }; + RIVulkanImage Image; + mutable std::unordered_map ImageViews{}; + VkImageAspectFlags ImageAspect{}; + VkSampler Sampler{}; + + VkImageView GetImageView(uint32_t mipMapIndex, uint32_t count, RIVulkanDevice13& device) const + { + const auto found{ ImageViews.find(DMipMapRange{ mipMapIndex, count }) }; + if (found != ImageViews.end()) + { + return found->second; + } + VkImageView newImageView{}; + const VkResult result = device.CreateImageView(Image.Format, Image.Image, ImageAspect, mipMapIndex, count, &newImageView); + if (VKFAILED(result)) + { + throw std::runtime_error(VkUtils::VkErrorString(result)); + } + ImageViews[DMipMapRange{ mipMapIndex, count }] = newImageView; + return newImageView; + } }; struct DRenderTargetVulkan : public DResource @@ -49,6 +92,8 @@ struct DFramebufferVulkan : public DResource VkFramebuffer Framebuffer{}; uint32_t Width{}, Height{}; DFramebufferAttachments Attachments; // Used for comparing framebuffers + + bool operator==(const DFramebufferVulkan& rhs) const { return Framebuffer == rhs.Framebuffer && Width == rhs.Width && Height == rhs.Height && Attachments == rhs.Attachments; }; }; struct DSwapchainVulkan : public DResource @@ -58,6 +103,8 @@ struct DSwapchainVulkan : public DResource VkSurfaceCapabilitiesKHR Capabilities; VkSurfaceFormatKHR Format; VkPresentModeKHR PresentMode; + uint32_t QueueFamilyIndex{}; + uint32_t QueueIndex{}; VkSwapchainKHR Swapchain{}; uint32_t ImagesCount{}; std::array ImagesId; @@ -79,19 +126,33 @@ struct DPipelineVulkan_DEPRECATED : public DPipeline_T struct DPipelineVulkan : public DResource { VkPipeline Pipeline{}; + EPipelineType Type{}; const VkPipelineLayout* PipelineLayout{}; }; struct DCommandPoolVulkan : public DResource { VkCommandPool Pool{}; + EQueueType Type; + uint32_t QueueFamilyIndex{}; + EQueueType QueueType{}; }; struct DCommandBufferVulkan : public DResource { - VkCommandBuffer Cmd{}; - bool IsRecording{}; - VkRenderPass ActiveRenderPass{}; + VkCommandBuffer Cmd{}; + EQueueType Type{}; + uint32_t QueueFamilyIndex{}; + bool IsRecording{}; + VkRenderPass ActiveRenderPass{}; + VkFramebuffer BoundFramebuffer{}; + VkPipeline BoundPipeline{}; + const VkPipelineLayout* BoundPipelineLayout{}; + EPipelineType BoundPipelineType{}; + VkRect2D CurrentScissor{}; + VkBuffer CurrentVertexBuffer{}; + VkBuffer CurrentIndexBuffer{}; + bool StencilTestActive{}; }; struct DFenceVulkan : public DResource @@ -110,6 +171,7 @@ struct DShaderVulkan : public DResource VertexInputLayoutId VertexLayout{}; uint32_t VertexStride{}; VkShaderModule VertexShaderModule{}; + VkShaderModule ComputeShaderModule{}; VkShaderModule PixelShaderModule{}; std::vector ShaderStageCreateInfo; uint32_t ColorAttachments{ 1 }; @@ -143,6 +205,14 @@ struct DSamplerVulkan : public DResource VkSampler Sampler{}; }; +struct DQueueVulkan : public DResource +{ + uint32_t QueueFamilyIndex{}; + uint32_t QueueIndex{}; + VkQueue QueuePtr{}; + EQueueType Type{}; +}; + class VulkanContext final : public IContext { inline static constexpr uint32_t NUM_OF_FRAMES_IN_FLIGHT{ 2 }; @@ -150,33 +220,49 @@ class VulkanContext final : public IContext public: VulkanContext(const DContextConfig* const config); ~VulkanContext(); + + bool CompileNativeShader(const std::vector& blob, std::vector& outShader, EShaderStage shaderStage, std::string& errorMgs) override; + void WaitDeviceIdle() override; SwapchainId CreateSwapchain(const WindowData* windowData, EPresentMode& presentMode, EFormat& outFormat, uint32_t* width = nullptr, uint32_t* height = nullptr) override; std::vector GetSwapchainRenderTargets(SwapchainId swapchainId) override; + bool SwapchainHasValidSurface(SwapchainId swapchainId) override; bool SwapchainAcquireNextImageIndex(SwapchainId swapchainId, uint64_t timeoutNanoseconds, uint32_t sempahoreid, uint32_t* outImageIndex) override; void DestroySwapchain(SwapchainId swapchainId) override; + uint32_t FindQueue(EQueueType queueType) override; + BufferId CreateBuffer(uint32_t size, EResourceType type, EMemoryUsage usage) override; void* BeginMapBuffer(BufferId buffer) override; void EndMapBuffer(BufferId buffer) override; void DestroyBuffer(BufferId buffer) override; - ImageId CreateImage(EFormat format, uint32_t width, uint32_t height, uint32_t mipMapCount) override; + ImageId CreateImage(EFormat format, uint32_t width, uint32_t height, uint32_t mipMapCount, bool isDepth = false, bool isStencil = false) override; + ImageId CreateStorageImage(EFormat format, uint32_t width, uint32_t height, uint32_t mipMapCount, bool isDepth = false, bool isStencil = false) override; EFormat GetImageFormat(ImageId) const override; void DestroyImage(ImageId imageId) override; VertexInputLayoutId CreateVertexLayout(const std::vector& info) override; ShaderId CreateShader(const ShaderSource& source) override; void DestroyShader(const ShaderId shader) override; - uint32_t CreateSampler(uint32_t minLod, uint32_t maxLod) override; - + uint32_t CreateSampler(uint32_t minLod, + uint32_t maxLod, + EFilter minFilter, + EFilter magFilter, + ESamplerAddressMode addressMode, + ESamplerMipmapMode mipMapMode, + bool anisotropicFiltering, + float anisotropicFilter = 16.f) override; + void DestroySampler(uint32_t samplerId) override; + + uint32_t CreateComputePipeline(const uint32_t shader, const uint32_t rootSignatureId) override; uint32_t CreatePipeline(const ShaderId shader, uint32_t rootSignatureId, const DPipelineAttachments& attachments, const PipelineFormat& format) override; void DestroyPipeline(uint32_t pipelineId) override; uint32_t CreateRootSignature(const ShaderLayout& layout) override; void DestroyRootSignature(uint32_t rootSignatureId) override; uint32_t CreateDescriptorSets(uint32_t rootSignatureId, EDescriptorFrequency frequency, uint32_t count) override; void DestroyDescriptorSet(uint32_t descriptorSetId) override; - void UpdateDescriptorSet(uint32_t descriptorSetId, uint32_t setIndex, uint32_t paramCount, DescriptorData* params) override; + void UpdateDescriptorSet(uint32_t descriptorSetId, uint32_t paramCount, DescriptorData* params) override; - uint32_t CreateCommandPool() override; + uint32_t CreateCommandPool(uint32_t queueId) override; void DestroyCommandPool(uint32_t commandPoolId) override; void ResetCommandPool(uint32_t commandPoolId) override; @@ -195,7 +281,16 @@ class VulkanContext final : public IContext void DrawIndexed(uint32_t commandBufferId, uint32_t index_count, uint32_t first_index, uint32_t first_vertex) override; void DrawIndexedIndirect(uint32_t commandBufferId, uint32_t buffer, uint32_t offset, uint32_t drawCount, uint32_t stride) override; void BindDescriptorSet(uint32_t commandBufferId, uint32_t setIndex, uint32_t descriptorSetId) override; - void CopyImage(uint32_t commandId, uint32_t imageId, uint32_t width, uint32_t height, uint32_t mipMapIndex, uint32_t stagingBufferId, uint32_t stagingBufferOffset) override; + void CopyImage(uint32_t commandId, uint32_t destImage, uint32_t width, uint32_t height, uint32_t mipMapIndex, uint32_t mipMapCount, uint32_t sourceImage) override; + void CopyBufferToImage(uint32_t commandId, uint32_t imageId, uint32_t width, uint32_t height, uint32_t mipMapIndex, uint32_t stagingBufferId, uint32_t stagingBufferOffset) override; + void CopyBuffer(uint32_t commandId, uint32_t bufferId, uint32_t offset, uint32_t bytes, uint32_t stagingBufferId, uint32_t stagingBufferOffset) override; + void SetStencilTest(uint32_t commandId, bool enable, const DStencilOpState* frontFace, const DStencilOpState* backFace) override; + void SetDepthTestCompareOp(uint32_t commandId, bool enabled, bool depthWrite, ECompareOp compareOp) override; + void SetPrimitiveTopology(uint32_t commandId, ETopology primitiveTopology) override; + void SetLineWidth(uint32_t commandId, float lineWidth) override; + void DispatchCompute(uint32_t commandId, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ) override; + void ComputeWorkGroupCount(uint32_t* groupCountX, uint32_t* groupCountY, uint32_t* groupCountZ) override; + void PushConstant(uint32_t commandId, EShaderStage stage, uint32_t offset, uint32_t size, void* data) override; uint32_t CreateFence(bool signaled) override; void DestroyFence(uint32_t fenceId) override; @@ -220,18 +315,18 @@ class VulkanContext final : public IContext void FlushDeletedBuffers() override; - void QueueSubmit(const std::vector& waitSemaphore, const std::vector& finishSemaphore, const std::vector& cmdIds, uint32_t fenceId) override; - void QueuePresent(uint32_t swapchainId, uint32_t imageIndex, const std::vector& waitSemaphore) override; + void QueueSubmit(uint32_t queueId, const std::vector& waitSemaphore, const std::vector& finishSemaphore, const std::vector& cmdIds, uint32_t fenceId) override; + void QueuePresent(uint32_t queueId, uint32_t swapchainId, uint32_t imageIndex, const std::vector& waitSemaphore) override; unsigned char* GetAdapterDescription() const override; size_t GetAdapterDedicatedVideoMemory() const override; - + float GetMaxAnisotropyFiltering(bool* isSupported = nullptr) const override; #pragma region Utility RIVulkanDevice13& GetDevice() { return Device; } #pragma endregion private: - static constexpr uint32_t MAX_RESOURCES = 1024; // Change this number to increase number of allocations per resource + static constexpr uint32_t MAX_RESOURCES = 1024 * 4; // Change this number to increase number of allocations per resource static constexpr uint64_t MAX_FENCE_TIMEOUT = 0xffff; // 0xffffffffffffffff; // nanoseconds RIVulkanInstance Instance; RIVulkanDevice13 Device; @@ -240,21 +335,25 @@ class VulkanContext final : public IContext void (*_logOutput)(const char*); DBufferVulkan _emptyUbo; + DBufferVulkan _emptySsbo; uint32_t _emptyImageId{}; DImageVulkan* _emptyImage; + uint32_t _emptyStorageImageId{}; + DImageVulkan* _emptyStorageImage; DSamplerVulkan _emptySampler; std::array _swapchains; - std::array _vertexBuffers; - std::array _transferBuffers; - std::array _uniformBuffers; - std::array _indirectBuffers; + /*Vertex and index buffers pool*/ + std::array _vertexBuffers; + std::array _transferBuffers; + std::array _uniformBuffers; + std::array _storageBuffers; + std::array _indirectBuffers; /*Whenever a render target gets deleted remove also framebuffers that have that image id as attachment*/ std::array _framebuffers; std::array _shaders; std::array _vertexLayouts; std::array _images; std::array _pipelines; - std::array _commandPools_DEPRECATED; std::array _fences; std::array _samplers; std::array _semaphores; @@ -263,7 +362,12 @@ class VulkanContext final : public IContext std::array _renderTargets; std::array _rootSignatures; std::array _descriptorSets; - std::unordered_set _renderPasses; + /*Since queues are never deallocated, we are sure that there is no fragmentation*/ + std::array _queues; + /*No gpu can have more than 16 queue families*/ + std::array _queueFamilyIndexCreatedCount; + + std::unordered_set _renderPasses; using DeleteFn = std::function; using FramesWaitToDeletionList = std::pair>; @@ -280,7 +384,8 @@ class VulkanContext final : public IContext /*Per frame map of per pipeline layout to descriptor pool, we can allocate descriptor sets per pipeline layout*/ std::vector>> _pipelineLayoutToDescriptorPool; - const std::vector _validationLayers = { +#if _DEBUG + const std::vector _validationLayers{ "VK_LAYER_KHRONOS_validation", "VK_LAYER_GOOGLE_threading", "VK_LAYER_LUNARG_parameter_validation", @@ -288,16 +393,19 @@ class VulkanContext final : public IContext "VK_LAYER_LUNARG_core_validation", "VK_LAYER_GOOGLE_unique_objects", }; +#else + const std::vector _validationLayers{}; +#endif #if FOX_PLATFORM == FOX_PLATFORM_WINDOWS32 - const std::vector _instanceExtensionNames = { "VK_EXT_debug_utils", + const std::vector _instanceExtensionNames{ "VK_EXT_debug_utils", "VK_KHR_surface", "VK_KHR_win32_surface", "VK_KHR_external_semaphore_capabilities", VK_KHR_SHADER_DRAW_PARAMETERS_EXTENSION_NAME, VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME }; #elif FOX_PLATFORM == FOX_PLATFORM_LINUX - const std::vector _instanceExtensionNames = { + const std::vector _instanceExtensionNames{ "VK_EXT_debug_utils", "VK_KHR_surface", "VK_KHR_wayland_surface", @@ -312,10 +420,13 @@ class VulkanContext final : public IContext const std::vector _deviceExtensionNames = { VK_KHR_SWAPCHAIN_EXTENSION_NAME, VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME, + VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME, + "VK_EXT_extended_dynamic_state2 ", "VK_KHR_Maintenance1", // passing negative viewport heights "VK_KHR_maintenance4", "VK_KHR_dedicated_allocation", - "VK_KHR_bind_memory2" }; + "VK_KHR_bind_memory2", + "VK_EXT_shader_atomic_float2" }; void Warning(const std::string& error); void Log(const std::string& error); diff --git a/src/backend/vulkan/VulkanDevice.cpp b/src/backend/vulkan/VulkanDevice.cpp index 7f1e583..5fb973c 100644 --- a/src/backend/vulkan/VulkanDevice.cpp +++ b/src/backend/vulkan/VulkanDevice.cpp @@ -1,10 +1,12 @@ // Copyright RedFox Studio 2022 #include "VulkanDevice.h" -#include "UtilsVK.h" -#include "asserts.h" +#include "Asserts.h" +#include "UtilsVk.h" #define VMA_IMPLEMENTATION +#define VMA_STATIC_VULKAN_FUNCTIONS VK_TRUE +#define VMA_DYNAMIC_VULKAN_FUNCTIONS VK_TRUE #pragma warning(push) #pragma warning(disable : 4100) #pragma warning(disable : 4127) @@ -23,8 +25,8 @@ namespace Fox RIVulkanDevice::~RIVulkanDevice() { - check(PhysicalDevice == nullptr); - check(Device == nullptr); + furyassert(PhysicalDevice == nullptr); + furyassert(Device == nullptr); }; VkResult @@ -35,35 +37,63 @@ std::vector extensions, VkPhysicalDeviceFeatures* optDeviceFeatures, std::vector validationLayers) { - check(PhysicalDevice == nullptr); - check(Device == nullptr); + furyassert(PhysicalDevice == nullptr); + furyassert(Device == nullptr); PhysicalDevice = hardwareDevice; - _queueFamilyIndex = _queryGraphicsAndTransferQueueIndex(); - // Get it's physical properties vkGetPhysicalDeviceProperties(PhysicalDevice, &DeviceProperties); // It's memory properties vkGetPhysicalDeviceMemoryProperties(PhysicalDevice, &DeviceMemory); - const float queuePriority = 1.f; + std::array queuePriorities; + std::fill(queuePriorities.begin(), queuePriorities.end(), 1.f); + + uint32_t queueFamiliesCount{}; + vkGetPhysicalDeviceQueueFamilyProperties(PhysicalDevice, &queueFamiliesCount, NULL); + QueueFamilies.resize(queueFamiliesCount); + vkGetPhysicalDeviceQueueFamilyProperties(PhysicalDevice, &queueFamiliesCount, QueueFamilies.data()); + + // Find graphics queue + { + int32_t graphicsFamilyIndex{ -1 }; + for (uint32_t i = 0; i < queueFamiliesCount; i++) + { + VkQueueFamilyProperties* queue = &QueueFamilies[i]; + if (queue->queueFlags & VK_QUEUE_GRAPHICS_BIT) + { + graphicsFamilyIndex = i; + break; + } + } + + if (graphicsFamilyIndex < 0) + { + throw std::runtime_error("No vulkan graphics queue available!"); + } + } - VkDeviceQueueCreateInfo queueCreateInfo{}; - queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; - queueCreateInfo.queueFamilyIndex = _queueFamilyIndex; - queueCreateInfo.queueCount = 1; - queueCreateInfo.flags = 0; - queueCreateInfo.pNext = NULL; - queueCreateInfo.pQueuePriorities = &queuePriority; + // Create all queues up front + std::vector queueCreateInfos; + for (uint32_t i = 0; i < queueFamiliesCount; i++) + { + VkDeviceQueueCreateInfo queueCreateInfo{}; + queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; + queueCreateInfo.queueFamilyIndex = i; + queueCreateInfo.queueCount = QueueFamilies[i].queueCount; + queueCreateInfo.flags = 0; + queueCreateInfo.pNext = NULL; + queueCreateInfo.pQueuePriorities = queuePriorities.data(); // must be a valid pointer to an array of queueCount float values + queueCreateInfos.emplace_back(std::move(queueCreateInfo)); + } VkDeviceCreateInfo deviceInfo{}; deviceInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; deviceInfo.pNext = pNext; - deviceInfo.enabledExtensionCount = 0; - deviceInfo.pQueueCreateInfos = &queueCreateInfo; - deviceInfo.queueCreateInfoCount = 1; + deviceInfo.pQueueCreateInfos = queueCreateInfos.data(); + deviceInfo.queueCreateInfoCount = (uint32_t)queueCreateInfos.size(); deviceInfo.pEnabledFeatures = pNext ? nullptr : (optDeviceFeatures ? optDeviceFeatures : nullptr); deviceInfo.enabledExtensionCount = (uint32_t)extensions.size(); deviceInfo.ppEnabledExtensionNames = extensions.data(); @@ -106,41 +136,77 @@ std::vector validationLayers) vma_vulkan_func.vkBindBufferMemory2KHR = vkBindBufferMemory2KHR; vma_vulkan_func.vkBindImageMemory2KHR = vkBindImageMemory2KHR; - check(vma_vulkan_func.vkGetPhysicalDeviceMemoryProperties2KHR); - check(vma_vulkan_func.vkGetBufferMemoryRequirements2KHR); - check(vma_vulkan_func.vkGetImageMemoryRequirements2KHR); - check(vma_vulkan_func.vkBindBufferMemory2KHR); - check(vma_vulkan_func.vkBindImageMemory2KHR); + furyassert(vma_vulkan_func.vkGetInstanceProcAddr); + furyassert(vma_vulkan_func.vkGetDeviceProcAddr); + furyassert(vma_vulkan_func.vkAllocateMemory); + furyassert(vma_vulkan_func.vkBindBufferMemory); + furyassert(vma_vulkan_func.vkBindImageMemory); + furyassert(vma_vulkan_func.vkCreateBuffer); + furyassert(vma_vulkan_func.vkCreateImage); + furyassert(vma_vulkan_func.vkDestroyBuffer); + furyassert(vma_vulkan_func.vkDestroyImage); + furyassert(vma_vulkan_func.vkFlushMappedMemoryRanges); + furyassert(vma_vulkan_func.vkFreeMemory); + furyassert(vma_vulkan_func.vkGetBufferMemoryRequirements); + furyassert(vma_vulkan_func.vkGetImageMemoryRequirements); + furyassert(vma_vulkan_func.vkGetPhysicalDeviceMemoryProperties); + furyassert(vma_vulkan_func.vkGetPhysicalDeviceProperties); + furyassert(vma_vulkan_func.vkInvalidateMappedMemoryRanges); + furyassert(vma_vulkan_func.vkMapMemory); + furyassert(vma_vulkan_func.vkUnmapMemory); + furyassert(vma_vulkan_func.vkCmdCopyBuffer); + furyassert(vma_vulkan_func.vkGetPhysicalDeviceMemoryProperties2KHR); + furyassert(vma_vulkan_func.vkGetBufferMemoryRequirements2KHR); + furyassert(vma_vulkan_func.vkGetImageMemoryRequirements2KHR); + furyassert(vma_vulkan_func.vkBindBufferMemory2KHR); + furyassert(vma_vulkan_func.vkBindImageMemory2KHR); VmaAllocatorCreateInfo allocatorCreateInfo = {}; - allocatorCreateInfo.vulkanApiVersion = VK_API_VERSION_1_1; + allocatorCreateInfo.vulkanApiVersion = VK_MAKE_VERSION(1,3,0); allocatorCreateInfo.physicalDevice = PhysicalDevice; allocatorCreateInfo.device = Device; allocatorCreateInfo.instance = instance.Instance; - allocatorCreateInfo.pVulkanFunctions = &vma_vulkan_func; + // allocatorCreateInfo.pVulkanFunctions = &vma_vulkan_func; { - const VkResult result = vmaCreateAllocator(&allocatorCreateInfo, &VmaAllocator); + const VkResult result = vmaCreateAllocator(&allocatorCreateInfo, &VmaAllocatorObject); if (result != VK_SUCCESS) { // std::runtime_error("Failed to initialize VMA"); return result; } + + furyassert(VmaAllocatorObject->GetVulkanFunctions().vkGetDeviceProcAddr); + furyassert(VmaAllocatorObject->GetVulkanFunctions().vkGetPhysicalDeviceProperties); + furyassert(VmaAllocatorObject->GetVulkanFunctions().vkGetPhysicalDeviceMemoryProperties); + furyassert(VmaAllocatorObject->GetVulkanFunctions().vkAllocateMemory); + furyassert(VmaAllocatorObject->GetVulkanFunctions().vkFreeMemory); + furyassert(VmaAllocatorObject->GetVulkanFunctions().vkMapMemory); + furyassert(VmaAllocatorObject->GetVulkanFunctions().vkUnmapMemory); + furyassert(VmaAllocatorObject->GetVulkanFunctions().vkFlushMappedMemoryRanges); + furyassert(VmaAllocatorObject->GetVulkanFunctions().vkInvalidateMappedMemoryRanges); + furyassert(VmaAllocatorObject->GetVulkanFunctions().vkBindBufferMemory); + furyassert(VmaAllocatorObject->GetVulkanFunctions().vkBindImageMemory); + furyassert(VmaAllocatorObject->GetVulkanFunctions().vkGetBufferMemoryRequirements); + furyassert(VmaAllocatorObject->GetVulkanFunctions().vkGetImageMemoryRequirements); + furyassert(VmaAllocatorObject->GetVulkanFunctions().vkCreateBuffer); + furyassert(VmaAllocatorObject->GetVulkanFunctions().vkDestroyBuffer); + furyassert(VmaAllocatorObject->GetVulkanFunctions().vkCreateImage); + furyassert(VmaAllocatorObject->GetVulkanFunctions().vkDestroyImage); + furyassert(VmaAllocatorObject->GetVulkanFunctions().vkCmdCopyBuffer); } } - vkGetDeviceQueue(Device, _queueFamilyIndex, 0, &MainQueue); - return VK_SUCCESS; } void RIVulkanDevice::Deinit() { - check(PhysicalDevice != nullptr); - check(Device != nullptr); + furyassert(PhysicalDevice != nullptr); + furyassert(Device != nullptr); - vmaDestroyAllocator(VmaAllocator); + vmaDestroyAllocator(VmaAllocatorObject); vkDestroyDevice(Device, nullptr); diff --git a/src/backend/vulkan/VulkanDevice.h b/src/backend/vulkan/VulkanDevice.h index 89214eb..a0e20de 100644 --- a/src/backend/vulkan/VulkanDevice.h +++ b/src/backend/vulkan/VulkanDevice.h @@ -3,7 +3,7 @@ #pragma once #define VK_NO_PROTOTYPES -#define VMA_VULKAN_VERSION 1002000 // Vulkan 1.2 +#define VMA_VULKAN_VERSION 1003000 // Vulkan 1.3 #define VMA_DYNAMIC_VULKAN_FUNCTIONS 1 // define 1 for custom func ptr from volk #define VMA_STATIC_VULKAN_FUNCTIONS 0 // define 0 for custom func ptr from volk #include "vk_mem_alloc.h" @@ -17,6 +17,13 @@ namespace Fox { +struct RIVulkanQueue +{ + uint32_t Flags{}; + uint32_t FamilyIndex{}; + uint32_t QueueIndex{}; +}; + class RIVulkanDevice { public: @@ -29,18 +36,18 @@ class RIVulkanDevice std::vector validationLayers); void Deinit(); - inline int32_t GetQueueFamilyIndex() const { return _queueFamilyIndex; }; + std::vector QueueFamilies; inline int32_t GetMaxImageAllocations() const { return 4096; } VkPhysicalDevice PhysicalDevice{}; /* GPU chosen as the default device */ VkDevice Device{}; /* Logical device */ - VmaAllocator VmaAllocator; + VmaAllocator VmaAllocatorObject; VkPhysicalDeviceProperties DeviceProperties{}; /*Properties of the physical device*/ VkPhysicalDeviceMemoryProperties DeviceMemory{}; /*Properties about the physical device memory*/ - VkQueue MainQueue{}; /* Graphics and Transfer queue*/ + private: - uint32_t _queueFamilyIndex; + uint32_t _queryGraphicsAndTransferQueueIndex() const; }; diff --git a/src/backend/vulkan/VulkanDevice10.cpp b/src/backend/vulkan/VulkanDevice10.cpp index 946f498..e0a87de 100644 --- a/src/backend/vulkan/VulkanDevice10.cpp +++ b/src/backend/vulkan/VulkanDevice10.cpp @@ -2,9 +2,9 @@ #include "VulkanDevice10.h" -#include "asserts.h" +#include "Asserts.h" -#include "UtilsVK.h" +#include "UtilsVk.h" namespace Fox { @@ -14,9 +14,19 @@ const std::vector& const std::vector& vertexInputAttributes, VkPipelineLayout pipelineLayout, VkRenderPass renderPass) - : DynamicStates{ VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR } + : DynamicStates{ VK_DYNAMIC_STATE_VIEWPORT, + VK_DYNAMIC_STATE_SCISSOR, + VK_DYNAMIC_STATE_LINE_WIDTH, + VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK, + VK_DYNAMIC_STATE_STENCIL_WRITE_MASK, + VK_DYNAMIC_STATE_STENCIL_REFERENCE, + VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY, + VK_DYNAMIC_STATE_STENCIL_TEST_ENABLE, + VK_DYNAMIC_STATE_DEPTH_WRITE_ENABLE, + VK_DYNAMIC_STATE_DEPTH_COMPARE_OP, + VK_DYNAMIC_STATE_DEPTH_TEST_ENABLE, + VK_DYNAMIC_STATE_STENCIL_OP } { - PipelineShaderStages = shaders; InputBindings = vertexInputBinding; VertexInputAttributes = vertexInputAttributes; @@ -131,6 +141,12 @@ RIVulkanPipelineBuilder::SetTopology(VkPrimitiveTopology topology) PipelineInputAssembly.topology = topology; } +void +RIVulkanPipelineBuilder::SetLineWidth(float w) +{ + PipelineRasterization.lineWidth = w; +} + void RIVulkanPipelineBuilder::SetAlphaBlending() { @@ -140,7 +156,7 @@ RIVulkanPipelineBuilder::SetAlphaBlending() } VkPipelineColorBlendAttachmentState colorBlendAttachment{}; - colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; + colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT; // | VK_COLOR_COMPONENT_A_BIT; colorBlendAttachment.blendEnable = VK_TRUE; colorBlendAttachment.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; colorBlendAttachment.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; @@ -157,6 +173,7 @@ RIVulkanPipelineBuilder::SetAlphaBlending() void RIVulkanPipelineBuilder::SetDynamicState(const std::vector& states) { + furyassert(0); DynamicStates = states; _fillDynamicState(); } @@ -245,7 +262,7 @@ RIVulkanPipelineBuilder::_fillViewportState() PipelineViewportState.pScissors = Scissors.data(); } -RIVulkanDevice10::~RIVulkanDevice10(){ check(_pipelines.size() == 0) } +RIVulkanDevice10::~RIVulkanDevice10(){ furyassert(_pipelines.size() == 0) } VkPipeline RIVulkanDevice10::CreatePipeline(const VkGraphicsPipelineCreateInfo* info) { @@ -264,8 +281,8 @@ VkPipeline RIVulkanDevice10::CreatePipeline(const VkGraphicsPipelineCreateInfo* void RIVulkanDevice10::DestroyPipeline(VkPipeline pipeline) { - check(pipeline); - check(_pipelines.size() > 0); + furyassert(pipeline); + furyassert(_pipelines.size() > 0); vkDestroyPipeline(Device, pipeline, nullptr); _pipelines.erase(_pipelines.find(pipeline)); @@ -323,7 +340,7 @@ RIVulkanDevice10::DestroyPipeline(VkPipeline pipeline) // VkViewport // RIVulkanDevice10::CreateViewport(uint32_t width, uint32_t height, float znear, float zfar) //{ -// check(zfar < 1.1f); // range 0 - 1 +// furyassert(zfar < 1.1f); // range 0 - 1 // // VkViewport v{}; // v.width = width; diff --git a/src/backend/vulkan/VulkanDevice10.h b/src/backend/vulkan/VulkanDevice10.h index 65a4c98..fa5d7f5 100644 --- a/src/backend/vulkan/VulkanDevice10.h +++ b/src/backend/vulkan/VulkanDevice10.h @@ -22,6 +22,7 @@ struct RIVulkanPipelineBuilder void AddViewport(VkViewport viewport); void AddScissor(VkRect2D); void SetTopology(VkPrimitiveTopology topology); + void SetLineWidth(float w); void SetAlphaBlending(); void SetDynamicState(const std::vector& states); void SetDepthTesting(bool testDepth, bool writeDepth); diff --git a/src/backend/vulkan/VulkanDevice11.cpp b/src/backend/vulkan/VulkanDevice11.cpp index cd679af..c467569 100644 --- a/src/backend/vulkan/VulkanDevice11.cpp +++ b/src/backend/vulkan/VulkanDevice11.cpp @@ -2,14 +2,14 @@ #include "VulkanDevice11.h" -#include "asserts.h" +#include "Asserts.h" -#include "UtilsVK.h" +#include "UtilsVk.h" namespace Fox { -RIVulkanDevice11::~RIVulkanDevice11() { check(_descriptorPools.size() == 0); } +RIVulkanDevice11::~RIVulkanDevice11() { furyassert(_descriptorPools.size() == 0); } VkDescriptorSet RIDescriptorPoolManager::CreateDescriptorSet(VkDescriptorSetLayout descriptorSetLayout) @@ -131,7 +131,7 @@ RIDescriptorSetBinder::BindCombinedImageSamplerArray(uint32_t bindingIndex, cons void RIDescriptorSetBinder::BindDescriptorSet(VkCommandBuffer cmd, VkPipelineLayout pipelineLayout, VkDescriptorSetLayout descriptorSetLayout, uint32_t setIndex) { - check(_currentUpdate.has_value()); + furyassert(_currentUpdate.has_value()); VkDescriptorSet set = QueryOrMakeDescriptorSet(descriptorSetLayout); vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, setIndex, 1, &set, (uint32_t)_dynamicOffsets.size(), _dynamicOffsets.data()); @@ -142,7 +142,7 @@ RIDescriptorSetBinder::BindDescriptorSet(VkCommandBuffer cmd, VkPipelineLayout p VkDescriptorSet RIDescriptorSetBinder::QueryOrMakeDescriptorSet(VkDescriptorSetLayout descriptorSetLayout) { - check(_currentUpdate.has_value()); // You must bind something first + furyassert(_currentUpdate.has_value()); // You must bind something first VkDescriptorSet set = _queryDescriptorSet(descriptorSetLayout, _currentUpdate.value()); if (!set) @@ -154,7 +154,7 @@ RIDescriptorSetBinder::QueryOrMakeDescriptorSet(VkDescriptorSetLayout descriptor _cachedDescriptorSets[descriptorSetLayout][_currentUpdate.value()] = set; } - check(set != nullptr); + furyassert(set != nullptr); return set; } @@ -200,9 +200,9 @@ void RIVulkanDevice11::DestroyDescriptorPool(VkDescriptorPool pool) { vkDestroyDescriptorPool(Device, pool, nullptr); - check(_descriptorPools.size() > 0); + furyassert(_descriptorPools.size() > 0); const auto found = _descriptorPools.find(pool); - check(found != _descriptorPools.end()); + furyassert(found != _descriptorPools.end()); _descriptorPools.erase(found); } @@ -227,8 +227,7 @@ RIVulkanDevice11::CreateDescriptorSet(VkDescriptorPool pool, VkDescriptorSetLayo RIDescriptorPoolManager* RIVulkanDevice11::CreateDescriptorPool2(const std::vector& poolDimensions, uint32_t maxSets) { - check(0); - VkDescriptorPool descriptorPool = CreateDescriptorPool(poolDimensions, maxSets); + furyassert(0); RIDescriptorPoolManager* pool = new RIDescriptorPoolManager(Device, poolDimensions, maxSets); return pool; } diff --git a/src/backend/vulkan/VulkanDevice11.h b/src/backend/vulkan/VulkanDevice11.h index 337a388..c91d1c9 100644 --- a/src/backend/vulkan/VulkanDevice11.h +++ b/src/backend/vulkan/VulkanDevice11.h @@ -3,7 +3,7 @@ #pragma once #include "RIResource.h" -#include "UtilsVK.h" +#include "UtilsVk.h" #include "VulkanDevice10.h" #include @@ -11,6 +11,7 @@ #include #include #include +#include #include namespace Fox diff --git a/src/backend/vulkan/VulkanDevice12.cpp b/src/backend/vulkan/VulkanDevice12.cpp index 8b02611..eaee419 100644 --- a/src/backend/vulkan/VulkanDevice12.cpp +++ b/src/backend/vulkan/VulkanDevice12.cpp @@ -2,16 +2,16 @@ #include "VulkanDevice12.h" -#include "asserts.h" +#include "Asserts.h" -#include "UtilsVK.h" +#include "UtilsVk.h" #include namespace Fox { -RIVulkanDevice12::~RIVulkanDevice12() { check(_cachedPools.size() == 0); } +RIVulkanDevice12::~RIVulkanDevice12() { furyassert(_cachedPools.size() == 0); } RICommandBuffer* RICommandPool::Allocate() @@ -38,7 +38,7 @@ RICommandPool::Allocate() void RICommandPool::Reset() { - check(_poolManager); // has beed moved, invalid state + furyassert(_poolManager); // has beed moved, invalid state vkResetCommandPool(_device, _poolManager, VK_COMMAND_POOL_RESET_RELEASE_RESOURCES_BIT); std::for_each(_cachedCmds.begin(), _cachedCmds.end(), [](RICommandBuffer& cmd) { @@ -46,19 +46,19 @@ RICommandPool::Reset() { cmd.DecreaseCounter(); } - check(cmd.Count() == 0); + furyassert(cmd.Count() == 0); }); } RICommandPool* -RIVulkanDevice12::CreateCommandPool() +RIVulkanDevice12::CreateCommandPool(uint32_t queueFamilyIndex) { VkCommandPool commandPool{}; { VkCommandPoolCreateInfo poolInfo{}; poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; poolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; /*Allow command buffers to be rerecorded individually, without this flag they all have to be reset together*/ - poolInfo.queueFamilyIndex = GetQueueFamilyIndex(); + poolInfo.queueFamilyIndex = queueFamilyIndex; const VkResult result = vkCreateCommandPool(Device, &poolInfo, nullptr, &commandPool); if (VKFAILED(result)) @@ -133,7 +133,7 @@ RIVulkanDevice12::DestroyCommandPool2(VkCommandPool commandPool) } void -RIVulkanDevice12::SubmitToMainQueue(const std::vector& cmds, const std::vector& waitSemaphore, VkSemaphore finishSemaphore, VkFence fence) +RIVulkanDevice12::SubmitToMainQueue(VkQueue queue, const std::vector& cmds, const std::vector& waitSemaphore, VkSemaphore finishSemaphore, VkFence fence) { std::for_each(cmds.begin(), cmds.end(), [](RICommandBuffer* cmd) { cmd->IncreaseCounter(); }); @@ -144,7 +144,7 @@ RIVulkanDevice12::SubmitToMainQueue(const std::vector& cmds, c std::transform(cmds.begin(), cmds.end(), commandBuffers.begin(), [](const RICommandBuffer* cmd) { return cmd->Cmd; }); - check(commandBuffers.size() == cmds.size()); + furyassert(commandBuffers.size() == cmds.size()); VkSubmitInfo submitInfo{}; submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; @@ -156,7 +156,7 @@ RIVulkanDevice12::SubmitToMainQueue(const std::vector& cmds, c submitInfo.signalSemaphoreCount = finishSemaphore ? 1 : 0; submitInfo.pSignalSemaphores = finishSemaphore ? &finishSemaphore : nullptr; - const VkResult result = vkQueueSubmit(MainQueue, 1, &submitInfo, fence); + const VkResult result = vkQueueSubmit(queue, 1, &submitInfo, fence); if (VKFAILED(result)) { throw std::runtime_error(VkUtils::VkErrorString(result)); diff --git a/src/backend/vulkan/VulkanDevice12.h b/src/backend/vulkan/VulkanDevice12.h index a6dd1e6..5141e34 100644 --- a/src/backend/vulkan/VulkanDevice12.h +++ b/src/backend/vulkan/VulkanDevice12.h @@ -91,16 +91,16 @@ class RIVulkanDevice12 : public RIVulkanDevice11 { public: /*don't delete pointer, is managed by a pool*/ - RICommandPool* CreateCommandPool(); + RICommandPool* CreateCommandPool(uint32_t queueFamilyIndex); /*This is explicit deletion, will be deleted in destructor automatically*/ void DestroyCommandPool(RICommandPool*); - void SubmitToMainQueue(const std::vector& cmds, const std::vector& waitSemaphore, VkSemaphore finishSemaphore, VkFence fence); - + void SubmitToMainQueue(VkQueue queue, const std::vector& cmds, const std::vector& waitSemaphore, VkSemaphore finishSemaphore, VkFence fence); VkCommandPool CreateCommandPool2(uint32_t queueFamilyIndex); void DestroyCommandPool2(VkCommandPool commandPool); void ResetCommandPool2(VkCommandPool commandPool); + public: virtual ~RIVulkanDevice12(); diff --git a/src/backend/vulkan/VulkanDevice13.cpp b/src/backend/vulkan/VulkanDevice13.cpp index c782e53..73da156 100644 --- a/src/backend/vulkan/VulkanDevice13.cpp +++ b/src/backend/vulkan/VulkanDevice13.cpp @@ -2,14 +2,14 @@ #include "VulkanDevice13.h" -#include "asserts.h" +#include "Asserts.h" -#include "UtilsVK.h" +#include "UtilsVk.h" namespace Fox { -RIVulkanDevice13::~RIVulkanDevice13(){ check(_renderPassMap.Size() == 0) } +RIVulkanDevice13::~RIVulkanDevice13(){ furyassert(_renderPassMap.Size() == 0) } VkResult RIVulkanDevice13::CreateRenderPass(const RIVkRenderPassInfo& info, VkRenderPass* renderPass) { diff --git a/src/backend/vulkan/VulkanDevice13.h b/src/backend/vulkan/VulkanDevice13.h index 618f106..7b3cf23 100644 --- a/src/backend/vulkan/VulkanDevice13.h +++ b/src/backend/vulkan/VulkanDevice13.h @@ -6,6 +6,7 @@ #include "RIResource.h" #include "VulkanDevice12.h" + #include #include @@ -84,11 +85,11 @@ struct VkSubpassDescriptionHashFn seed ^= std::hash{}(subpassDesc.flags) ^ 0x9e3779b9; seed += std::hash{}(subpassDesc.pipelineBindPoint) ^ 0x9e3779b1; seed ^= std::hash{}(subpassDesc.inputAttachmentCount); - // for (uint32_t i = 0; i < subpassDesc.inputAttachmentCount; i++) - // { - // const VkAttachmentReference* ref = subpassDesc.pInputAttachments + i; - // seed ^= VkAttachmentReferenceHashFn{}(*ref); - // } + for (uint32_t i = 0; i < subpassDesc.inputAttachmentCount; i++) + { + const VkAttachmentReference* ref = subpassDesc.pInputAttachments + i; + seed ^= VkAttachmentReferenceHashFn{}(*ref); + } seed += std::hash{}(subpassDesc.colorAttachmentCount) ^ 0x9e3779b9; // for (uint32_t i = 0; i < subpassDesc.colorAttachmentCount; i++) // { diff --git a/src/backend/vulkan/VulkanDevice2.cpp b/src/backend/vulkan/VulkanDevice2.cpp index e377795..70ea3aa 100644 --- a/src/backend/vulkan/VulkanDevice2.cpp +++ b/src/backend/vulkan/VulkanDevice2.cpp @@ -2,22 +2,22 @@ #include "VulkanDevice2.h" -#include "UtilsVK.h" -#include "asserts.h" +#include "UtilsVk.h" +#include "Asserts.h" #include namespace Fox { -RIVulkanDevice2::~RIVulkanDevice2() { check(_swapchains.size() == 0); } +RIVulkanDevice2::~RIVulkanDevice2() { furyassert(_swapchains.size() == 0); } bool -RIVulkanDevice2::SurfaceSupportPresentationOnCurrentQueueFamily(VkSurfaceKHR surface) +RIVulkanDevice2::SurfaceSupportPresentationOnQueueFamilyIndex(VkSurfaceKHR surface, uint32_t queueFamilyIndex) { uint32_t supportPresentation = VK_FALSE; // To determine whether a queue family of a physical device supports presentation to a given surface - const VkResult result = vkGetPhysicalDeviceSurfaceSupportKHR(PhysicalDevice, GetQueueFamilyIndex(), surface, &supportPresentation); + const VkResult result = vkGetPhysicalDeviceSurfaceSupportKHR(PhysicalDevice, queueFamilyIndex, surface, &supportPresentation); if (VKFAILED(result)) { throw std::runtime_error(VkUtils::VkErrorString(result)); @@ -45,7 +45,7 @@ RIVulkanDevice2::GetSurfaceFormats(VkSurfaceKHR surface) return formats; } } - check(0); + furyassert(0); return {}; } @@ -90,10 +90,12 @@ RIVulkanDevice2::CreateSwapchainFromSurface(VkSurfaceKHR surface, const VkSurfaceFormatKHR& format, const VkPresentModeKHR& presentMode, const VkSurfaceCapabilitiesKHR& capabilities, +uint32_t* queueFamilyIndices, +uint32_t queueFamilyIndicesCount, VkSwapchainKHR* outSwapchain, VkSwapchainKHR oldSwapchain) { - uint32_t queueFamilyIndices[] = { (uint32_t)GetQueueFamilyIndex() }; + furyassert(queueFamilyIndices != nullptr); critical(capabilities.minImageCount >= MAX_IMAGE_COUNT); VkSwapchainCreateInfoKHR swapchainInfo = {}; @@ -105,8 +107,10 @@ VkSwapchainKHR oldSwapchain) swapchainInfo.imageFormat = format.format; swapchainInfo.imageColorSpace = format.colorSpace; - check(capabilities.currentExtent.width <= capabilities.maxImageExtent.width); - check(capabilities.currentExtent.height <= capabilities.maxImageExtent.height); + furyassert(capabilities.currentExtent.width > 0); // imageExtent members width and height must both be non-zero + furyassert(capabilities.currentExtent.height > 0); // imageExtent members width and height must both be non-zero + furyassert(capabilities.currentExtent.width <= capabilities.maxImageExtent.width); + furyassert(capabilities.currentExtent.height <= capabilities.maxImageExtent.height); swapchainInfo.imageExtent = capabilities.currentExtent; swapchainInfo.imageArrayLayers = capabilities.maxImageArrayLayers; @@ -144,7 +148,7 @@ RIVulkanDevice2::GetSwapchainImages(VkSwapchainKHR swapchain) uint32_t imageCount = 0; vkGetSwapchainImagesKHR(Device, swapchain, &imageCount, nullptr); - check(imageCount >= MAX_IMAGE_COUNT); + furyassert(imageCount >= MAX_IMAGE_COUNT); images.resize(imageCount); vkGetSwapchainImagesKHR(Device, swapchain, &imageCount, images.data()); @@ -182,11 +186,11 @@ RIVulkanDevice2::AcquireNextImage(VkSwapchainKHR swapchain, uint64_t timeoutNano } std::vector -RIVulkanDevice2::Present(std::vector> swapchainImageIndex, std::vector waitSemaphores) +RIVulkanDevice2::Present(VkQueue queue, std::vector> swapchainImageIndex, std::vector waitSemaphores) { std::vector results(swapchainImageIndex.size(), VK_SUCCESS); - check(results.size() == swapchainImageIndex.size()); + furyassert(results.size() == swapchainImageIndex.size()); std::vector swapchains(swapchainImageIndex.size()); std::vector imageIndices(swapchainImageIndex.size()); @@ -194,8 +198,8 @@ RIVulkanDevice2::Present(std::vector> swapch std::transform(swapchainImageIndex.begin(), swapchainImageIndex.end(), swapchains.begin(), [](const std::pair& p) { return p.first; }); std::transform(swapchainImageIndex.begin(), swapchainImageIndex.end(), imageIndices.begin(), [](const std::pair& p) { return p.second; }); - check(swapchains.size() == swapchainImageIndex.size()); - check(swapchains.size() == imageIndices.size()); + furyassert(swapchains.size() == swapchainImageIndex.size()); + furyassert(swapchains.size() == imageIndices.size()); VkPresentInfoKHR presentInfo{}; presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; @@ -207,7 +211,7 @@ RIVulkanDevice2::Present(std::vector> swapch presentInfo.pResults = results.data(); { - [[maybe_unused]] const VkResult result = vkQueuePresentKHR(MainQueue, &presentInfo); + [[maybe_unused]] const VkResult result = vkQueuePresentKHR(queue, &presentInfo); } return results; } diff --git a/src/backend/vulkan/VulkanDevice2.h b/src/backend/vulkan/VulkanDevice2.h index cabb368..6495041 100644 --- a/src/backend/vulkan/VulkanDevice2.h +++ b/src/backend/vulkan/VulkanDevice2.h @@ -18,7 +18,7 @@ class RIVulkanDevice2 : public RIVulkanDevice public: virtual ~RIVulkanDevice2(); - bool SurfaceSupportPresentationOnCurrentQueueFamily(VkSurfaceKHR surface); + bool SurfaceSupportPresentationOnQueueFamilyIndex(VkSurfaceKHR surface, uint32_t queueFamilyIndex); std::vector GetSurfaceFormats(VkSurfaceKHR surface); VkSurfaceCapabilitiesKHR GetSurfaceCapabilities(VkSurfaceKHR surface); std::vector GetSurfacePresentModes(VkSurfaceKHR surface); @@ -32,11 +32,13 @@ class RIVulkanDevice2 : public RIVulkanDevice * @return */ VkResult CreateSwapchainFromSurface(VkSurfaceKHR surface, - const VkSurfaceFormatKHR& format, - const VkPresentModeKHR& presentMode, - const VkSurfaceCapabilitiesKHR& capabilities, - VkSwapchainKHR* outSwapchain, - VkSwapchainKHR oldSwapchain = nullptr); + const VkSurfaceFormatKHR& format, + const VkPresentModeKHR& presentMode, + const VkSurfaceCapabilitiesKHR& capabilities, + uint32_t* queueFamilyIndices, + uint32_t queueFamilyIndicesCount, + VkSwapchainKHR* outSwapchain, + VkSwapchainKHR oldSwapchain = nullptr); /** * @brief Must be externally synchronized * @param swapchain Swapchain to destroy @@ -47,7 +49,7 @@ class RIVulkanDevice2 : public RIVulkanDevice VkResult AcquireNextImage(VkSwapchainKHR swapchain, uint64_t timeoutNanoseconds, uint32_t* imageIndex, VkSemaphore imageAvailableSempahore, VkFence fence = VK_NULL_HANDLE); - std::vector Present(std::vector> swapchainImageIndex, std::vector waitSemaphores); + std::vector Present(VkQueue queue, std::vector> swapchainImageIndex, std::vector waitSemaphores); private: std::unordered_set _swapchains; diff --git a/src/backend/vulkan/VulkanDevice3.cpp b/src/backend/vulkan/VulkanDevice3.cpp index b4a5e85..7472f9a 100644 --- a/src/backend/vulkan/VulkanDevice3.cpp +++ b/src/backend/vulkan/VulkanDevice3.cpp @@ -2,17 +2,17 @@ #include "VulkanDevice3.h" -#include "asserts.h" +#include "Asserts.h" -#include "UtilsVK.h" +#include "UtilsVk.h" namespace Fox { RIVulkanDevice3::~RIVulkanDevice3() { - check(_fences.size() == 0); - check(_semaphores.size() == 0); + furyassert(_fences.size() == 0); + furyassert(_semaphores.size() == 0); } VkSemaphore diff --git a/src/backend/vulkan/VulkanDevice4.cpp b/src/backend/vulkan/VulkanDevice4.cpp index c963544..de99c0a 100644 --- a/src/backend/vulkan/VulkanDevice4.cpp +++ b/src/backend/vulkan/VulkanDevice4.cpp @@ -2,14 +2,14 @@ #include "VulkanDevice4.h" -#include "asserts.h" +#include "Asserts.h" -#include "UtilsVK.h" +#include "UtilsVk.h" namespace Fox { -RIVulkanDevice4::~RIVulkanDevice4() { check(_buffers.size() == 0); } +RIVulkanDevice4::~RIVulkanDevice4() { furyassert(_buffers.size() == 0); } RIVulkanBuffer RIVulkanDevice4::CreateBufferHostVisible(uint32_t size, VkBufferUsageFlags usage) @@ -24,10 +24,9 @@ RIVulkanDevice4::CreateBufferHostVisible(uint32_t size, VkBufferUsageFlags usage allocInfo.usage = VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE; allocInfo.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT; - RIVulkanBuffer buf; + RIVulkanBuffer buf{}; buf.IsMappable = true; - - const VkResult result = vmaCreateBuffer(VmaAllocator, &bufferInfo, &allocInfo, &buf.Buffer, &buf.Allocation, nullptr); + const VkResult result = vmaCreateBuffer(VmaAllocatorObject, &bufferInfo, &allocInfo, &buf.Buffer, &buf.Allocation, nullptr); if (VKFAILED(result)) { throw std::runtime_error(VkUtils::VkErrorString(result)); @@ -53,7 +52,7 @@ RIVulkanDevice4::CreateBufferDeviceLocalTransferBit(uint32_t size, VkBufferUsage RIVulkanBuffer buf; - const VkResult result = vmaCreateBuffer(VmaAllocator, &bufferInfo, &allocInfo, &buf.Buffer, &buf.Allocation, nullptr); + const VkResult result = vmaCreateBuffer(VmaAllocatorObject, &bufferInfo, &allocInfo, &buf.Buffer, &buf.Allocation, nullptr); if (VKFAILED(result)) { throw std::runtime_error(VkUtils::VkErrorString(result)); @@ -67,7 +66,7 @@ RIVulkanDevice4::CreateBufferDeviceLocalTransferBit(uint32_t size, VkBufferUsage void RIVulkanDevice4::DestroyBuffer(const RIVulkanBuffer& buffer) { - vmaDestroyBuffer(VmaAllocator, buffer.Buffer, buffer.Allocation); + vmaDestroyBuffer(VmaAllocatorObject, buffer.Buffer, buffer.Allocation); _buffers.erase(_buffers.find(buffer)); } @@ -75,7 +74,7 @@ void* RIVulkanDevice4::MapBuffer(const RIVulkanBuffer& buffer) { void* gpuVirtualAddress{}; - const VkResult result = vmaMapMemory(VmaAllocator, buffer.Allocation, &gpuVirtualAddress); + const VkResult result = vmaMapMemory(VmaAllocatorObject, buffer.Allocation, &gpuVirtualAddress); if (VKFAILED(result)) { throw std::runtime_error(VkUtils::VkErrorString(result)); @@ -86,7 +85,7 @@ RIVulkanDevice4::MapBuffer(const RIVulkanBuffer& buffer) void RIVulkanDevice4::UnmapBuffer(const RIVulkanBuffer& buffer) { - vmaUnmapMemory(VmaAllocator, buffer.Allocation); + vmaUnmapMemory(VmaAllocatorObject, buffer.Allocation); } } \ No newline at end of file diff --git a/src/backend/vulkan/VulkanDevice5.cpp b/src/backend/vulkan/VulkanDevice5.cpp index 224c814..3c32e10 100644 --- a/src/backend/vulkan/VulkanDevice5.cpp +++ b/src/backend/vulkan/VulkanDevice5.cpp @@ -2,23 +2,23 @@ #include "VulkanDevice5.h" -#include "asserts.h" +#include "Asserts.h" -#include "UtilsVK.h" +#include "UtilsVk.h" namespace Fox { RIVulkanDevice5::~RIVulkanDevice5() { - check(_images.size() == 0); - check(_imageViews.size() == 0); + furyassert(_images.size() == 0); + furyassert(_imageViews.size() == 0); } RIVulkanImage RIVulkanDevice5::CreateImageDeviceLocal(uint32_t width, uint32_t height, uint32_t mipLevels, VkFormat format, VkImageUsageFlags usage, VkImageTiling tiling, VkImageLayout initialLayout) { - + furyassert(width > 0 && height > 0); VkImageCreateInfo imageInfo{ VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO }; imageInfo.imageType = VK_IMAGE_TYPE_2D; imageInfo.extent.width = width; @@ -37,7 +37,7 @@ RIVulkanDevice5::CreateImageDeviceLocal(uint32_t width, uint32_t height, uint32_ allocInfo.usage = VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE; RIVulkanImage image{}; - const VkResult result = vmaCreateImage(VmaAllocator, &imageInfo, &allocInfo, &image.Image, &image.Allocation, nullptr); + const VkResult result = vmaCreateImage(VmaAllocatorObject, &imageInfo, &allocInfo, &image.Image, &image.Allocation, nullptr); if (VKFAILED(result)) { throw std::runtime_error(VkUtils::VkErrorString(result)); @@ -77,7 +77,7 @@ RIVulkanDevice5::CreateImageHostVisible(uint32_t width, uint32_t height, uint32_ allocInfo.usage = VMA_MEMORY_USAGE_AUTO_PREFER_HOST; RIVulkanImage image{}; - const VkResult result = vmaCreateImage(VmaAllocator, &imageInfo, &allocInfo, &image.Image, &image.Allocation, nullptr); + const VkResult result = vmaCreateImage(VmaAllocatorObject, &imageInfo, &allocInfo, &image.Image, &image.Allocation, nullptr); if (VKFAILED(result)) { throw std::runtime_error(VkUtils::VkErrorString(result)); @@ -97,7 +97,7 @@ RIVulkanDevice5::CreateImageHostVisible(uint32_t width, uint32_t height, uint32_ void RIVulkanDevice5::DestroyImage(const RIVulkanImage& image) { - vmaDestroyImage(VmaAllocator, image.Image, image.Allocation); + vmaDestroyImage(VmaAllocatorObject, image.Image, image.Allocation); _images.erase(_images.find(image)); } @@ -121,10 +121,9 @@ RIVulkanDevice5::CreateImageView_DEPRECATED(VkFormat format, const RIVulkanImage if (VKFAILED(result)) { throw std::runtime_error(VkUtils::VkErrorString(result)); - return nullptr; } } - check(imageView); + furyassert(imageView); _imageViews.insert(imageView); @@ -153,7 +152,7 @@ RIVulkanDevice5::CreateImageView(VkFormat format, VkImage image, VkImageAspectFl return result; } } - check(*outImageView); + furyassert(*outImageView); _imageViews.insert(*outImageView); @@ -171,7 +170,7 @@ void* RIVulkanDevice5::MapImage(const RIVulkanImage& image) { void* gpuVirtualAddress{}; - const VkResult result = vmaMapMemory(VmaAllocator, image.Allocation, &gpuVirtualAddress); + const VkResult result = vmaMapMemory(VmaAllocatorObject, image.Allocation, &gpuVirtualAddress); if (VKFAILED(result)) { throw std::runtime_error(VkUtils::VkErrorString(result)); @@ -182,7 +181,7 @@ RIVulkanDevice5::MapImage(const RIVulkanImage& image) void RIVulkanDevice5::UnmapImage(const RIVulkanImage& image) { - vmaUnmapMemory(VmaAllocator, image.Allocation); + vmaUnmapMemory(VmaAllocatorObject, image.Allocation); } } \ No newline at end of file diff --git a/src/backend/vulkan/VulkanDevice6.cpp b/src/backend/vulkan/VulkanDevice6.cpp index 76ae188..d38893f 100644 --- a/src/backend/vulkan/VulkanDevice6.cpp +++ b/src/backend/vulkan/VulkanDevice6.cpp @@ -2,14 +2,14 @@ #include "VulkanDevice6.h" -#include "asserts.h" +#include "Asserts.h" -#include "UtilsVK.h" +#include "UtilsVk.h" namespace Fox { -RIVulkanDevice6::~RIVulkanDevice6() { check(_samplers.size() == 0); } +RIVulkanDevice6::~RIVulkanDevice6() { furyassert(_samplers.size() == 0); } VkSampler RIVulkanDevice6::CreateSampler(VkFilter minFilter, VkFilter magFilter, VkSamplerAddressMode mode, float minLod, float maxLod, VkSamplerMipmapMode mipmapMode, bool anisotropy, float maxAnisotropy) @@ -30,7 +30,7 @@ RIVulkanDevice6::CreateSampler(VkFilter minFilter, VkFilter magFilter, VkSampler samplerInfo.unnormalizedCoordinates = VK_FALSE; samplerInfo.compareEnable = VK_FALSE; samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS; - samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; + samplerInfo.mipmapMode = mipmapMode; samplerInfo.mipLodBias = 0.f; samplerInfo.minLod = minLod; samplerInfo.maxLod = maxLod; @@ -39,7 +39,6 @@ RIVulkanDevice6::CreateSampler(VkFilter minFilter, VkFilter magFilter, VkSampler if (VKFAILED(result)) { throw std::runtime_error(VkUtils::VkErrorString(result)); - return nullptr; } } diff --git a/src/backend/vulkan/VulkanDevice7.cpp b/src/backend/vulkan/VulkanDevice7.cpp index 13ba239..e9773de 100644 --- a/src/backend/vulkan/VulkanDevice7.cpp +++ b/src/backend/vulkan/VulkanDevice7.cpp @@ -2,14 +2,14 @@ #include "VulkanDevice7.h" -#include "asserts.h" +#include "Asserts.h" -#include "UtilsVK.h" +#include "UtilsVk.h" namespace Fox { -RIVulkanDevice7::~RIVulkanDevice7() { check(_framebuffers_DEPRECATED.size() == 0); } +RIVulkanDevice7::~RIVulkanDevice7() { furyassert(_framebuffers_DEPRECATED.size() == 0); } VkFramebuffer RIVulkanDevice7::_createFramebuffer(const std::vector& imageViews, uint32_t width, uint32_t height, VkRenderPass renderpass) @@ -30,7 +30,7 @@ RIVulkanDevice7::_createFramebuffer(const std::vector& imageViews, throw std::runtime_error(VkUtils::VkErrorString(result)); } - _framebuffers_DEPRECATED.insert(framebuffer); + //_framebuffers_DEPRECATED.insert(framebuffer); return framebuffer; } @@ -39,7 +39,7 @@ void RIVulkanDevice7::_destroyFramebuffer(VkFramebuffer framebuffer) { vkDestroyFramebuffer(Device, framebuffer, nullptr); - _framebuffers_DEPRECATED.erase(_framebuffers_DEPRECATED.find(framebuffer)); + //_framebuffers_DEPRECATED.erase(_framebuffers_DEPRECATED.find(framebuffer)); } } \ No newline at end of file diff --git a/src/backend/vulkan/VulkanDevice8.cpp b/src/backend/vulkan/VulkanDevice8.cpp index 0e5ef9f..5b8906a 100644 --- a/src/backend/vulkan/VulkanDevice8.cpp +++ b/src/backend/vulkan/VulkanDevice8.cpp @@ -2,14 +2,14 @@ #include "VulkanDevice8.h" -#include "asserts.h" +#include "Asserts.h" -#include "UtilsVK.h" +#include "UtilsVk.h" namespace Fox { -RIVulkanDevice8::~RIVulkanDevice8() { check(_descriptorSetLayoutCache.size() == 0); } +RIVulkanDevice8::~RIVulkanDevice8() { furyassert(_descriptorSetLayoutCache.size() == 0); } VkDescriptorSetLayoutBinding RIVulkanDevice8::CreateDescriptorSetLayoutBindingUniformBufferDynamic(uint32_t binding, uint32_t descriptorCount, VkShaderStageFlags stages) diff --git a/src/backend/vulkan/VulkanDevice9.cpp b/src/backend/vulkan/VulkanDevice9.cpp index c6f883d..f297553 100644 --- a/src/backend/vulkan/VulkanDevice9.cpp +++ b/src/backend/vulkan/VulkanDevice9.cpp @@ -2,14 +2,14 @@ #include "VulkanDevice9.h" -#include "asserts.h" +#include "Asserts.h" -#include "UtilsVK.h" +#include "UtilsVk.h" namespace Fox { -RIVulkanDevice9::~RIVulkanDevice9() { check(_pipelineLayoutCache.Size() == 0); } +RIVulkanDevice9::~RIVulkanDevice9() { furyassert(_pipelineLayoutCache.Size() == 0); } VkPipelineLayout RIVulkanDevice9::CreatePipelineLayout(const std::vector& descriptorSetLayout, const std::vector& pushConstantRange) diff --git a/src/backend/vulkan/VulkanInstance.cpp b/src/backend/vulkan/VulkanInstance.cpp index 2a57b1e..ac94ba5 100644 --- a/src/backend/vulkan/VulkanInstance.cpp +++ b/src/backend/vulkan/VulkanInstance.cpp @@ -2,8 +2,8 @@ #include "VulkanInstance.h" -#include "UtilsVK.h" -#include "asserts.h" +#include "UtilsVk.h" +#include "Asserts.h" #define VOLK_IMPLEMENTATION // defined only once #include "volk.h" @@ -14,12 +14,12 @@ namespace Fox VkResult RIVulkanInstance::Init(const char* applicationName, std::vector validationLayers, std::vector extensions) { - check(Instance == nullptr); + furyassert(Instance == nullptr); VkApplicationInfo applicationInfo = {}; applicationInfo.pNext = NULL; applicationInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; - applicationInfo.apiVersion = VK_API_VERSION_1_2; + applicationInfo.apiVersion = VK_API_VERSION_1_3; applicationInfo.applicationVersion = 1; applicationInfo.pApplicationName = applicationName; applicationInfo.pEngineName = "RedFox Game Engine"; @@ -54,7 +54,7 @@ RIVulkanInstance::Deinit() _destroyDebugUtilsMessenger(); } #endif - check(Instance != nullptr); + furyassert(Instance != nullptr); vkDestroyInstance(Instance, nullptr); } @@ -77,15 +77,12 @@ RIVulkanInstance::CreateSurfaceFromWindow(const WindowData& windowData, VkSurfac } #elif defined(__linux__) { - Fox::WindowPlatformLinuxSDL* win = static_cast(window); - check(win); - VkXlibSurfaceCreateInfoKHR createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; createInfo.pNext = NULL; createInfo.dpy = windowData._display; createInfo.window = windowData._window; - const VkResult result = vkCreateXlibSurfaceKHR(_vkInstance, &createInfo, NULL, surface); + const VkResult result = vkCreateXlibSurfaceKHR(Instance, &createInfo, NULL, surface); if (VKFAILED(result)) { return result; @@ -116,7 +113,7 @@ RIVulkanInstance::CreateDebugUtilsMessenger(PFN_vkDebugUtilsMessengerCallbackEXT dbgInfo.pUserData = userData; // Optional auto func = (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(Instance, "vkCreateDebugUtilsMessengerEXT"); - check(func); + furyassert(func); if (func != nullptr) { const VkResult result = func(Instance, &dbgInfo, nullptr, &_debugMessenger); @@ -130,7 +127,7 @@ void RIVulkanInstance::_destroyDebugUtilsMessenger() { auto func = (PFN_vkDestroyDebugUtilsMessengerEXT)vkGetInstanceProcAddr(Instance, "vkDestroyDebugUtilsMessengerEXT"); - check(func); + furyassert(func); if (func != nullptr) { func(Instance, _debugMessenger, nullptr); diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index c6e0eff..502ddbd 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -16,6 +16,7 @@ set(SOURCES "integration/vulkan/VertexBufferUpload.test.cpp" "integration/vulkan/UniformBufferUpload.test.cpp" "integration/vulkan/ImageUpload.test.cpp" + "integration/vulkan/AcquireAndRelease.test.cpp" ) @@ -36,7 +37,7 @@ add_executable(tests target_sources(tests PRIVATE ${GTEST_DIR} ${GTEST_DIR_INCLUDE}${SOURCES}) -target_link_libraries(tests FoxFury GTest::gtest_main GTest::gmock volk VulkanMemoryAllocator glfw) +target_link_libraries(tests FoxFury GTest::gtest_main volk VulkanMemoryAllocator glfw) set_target_properties(tests PROPERTIES RUNTIME_OUTPUT_DIRECTORY "bin" diff --git a/tests/integration/vulkan/AcquireAndRelease.test.cpp b/tests/integration/vulkan/AcquireAndRelease.test.cpp new file mode 100644 index 0000000..1e91e8f --- /dev/null +++ b/tests/integration/vulkan/AcquireAndRelease.test.cpp @@ -0,0 +1,139 @@ +#include "WindowFixture.h" + +#include "ExtractImage.h" +#include "backend/vulkan/ResourceTransfer.h" +#include "backend/vulkan/VulkanContext.h" +#include "backend/vulkan/VulkanContextFactory.h" +#include "backend/vulkan/VulkanDevice13.h" + +#include + +TEST_F(WindowFixture, ShouldCorrectlyReleaseAndAcquireResources) +{ + constexpr std::array data{ + 0xff, + 0, + 0, + 0xff, + 0, + 0xff, + 0, + 0xff, + 0xff, + 0, + 0, + 0xff, + 0, + 0xff, + 0, + 0xff, + }; + + Fox::DContextConfig config; + config.warningFunction = &WarningAssert; + config.stagingBufferSize = 10 * 1024 * 1024; // 10mb + + Fox::IContext* context = Fox::CreateVulkanContext(&config); + ASSERT_NE(context, nullptr); + const auto graphicsQueue = context->FindQueue(Fox::EQueueType::QUEUE_GRAPHICS); + const auto transferQueue = context->FindQueue(Fox::EQueueType::QUEUE_TRANSFER); + ASSERT_NE(graphicsQueue, transferQueue); + + uint32_t img = context->CreateImage(Fox::EFormat::R8G8B8A8_UNORM, 2, 2, 1); + uint32_t buf = context->CreateBuffer(12, Fox::EResourceType::VERTEX_INDEX_BUFFER, Fox::EMemoryUsage::RESOURCE_MEMORY_USAGE_GPU_ONLY); + + { + uint32_t stagingBuf = context->CreateBuffer(data.size(), Fox::EResourceType::TRANSFER, Fox::EMemoryUsage::RESOURCE_MEMORY_USAGE_CPU_TO_GPU); + + // Upload something to img and buf - so the ownership is acquired for the transfer queue + { + const auto pool = context->CreateCommandPool(transferQueue); + const auto cmd = context->CreateCommandBuffer(pool); + + context->BeginCommandBuffer(cmd); + { + Fox::TextureBarrier barrier{}; + barrier.ImageId = img; + barrier.CurrentState = Fox::EResourceState::UNDEFINED; + barrier.NewState = Fox::EResourceState::COPY_DEST; + + Fox::BufferBarrier bufBarrier{}; + bufBarrier.BufferId = buf; + bufBarrier.CurrentState = Fox::EResourceState::UNDEFINED; + bufBarrier.NewState = Fox::EResourceState::COPY_DEST; + context->ResourceBarrier(cmd, 1, &bufBarrier, 1, &barrier, 0, nullptr); + + context->CopyImage(cmd, img, 2, 2, 0, stagingBuf, 0); + } + { + // Release ownership + Fox::TextureBarrier barrier{}; + barrier.ImageId = img; + barrier.CurrentState = Fox::EResourceState::COPY_DEST; + barrier.NewState = Fox::EResourceState::PIXEL_SHADER_RESOURCE; + barrier.TransferOwnership = Fox::ETransferOwnership::RELEASE; + barrier.SrcQueue = transferQueue; + barrier.DstQueue = graphicsQueue; + + Fox::BufferBarrier bufBarrier{}; + bufBarrier.BufferId = buf; + bufBarrier.CurrentState = Fox::EResourceState::COPY_DEST; + bufBarrier.NewState = Fox::EResourceState::VERTEX_AND_CONSTANT_BUFFER; + bufBarrier.TransferOwnership = Fox::ETransferOwnership::RELEASE; + bufBarrier.SrcQueue = transferQueue; + bufBarrier.DstQueue = graphicsQueue; + context->ResourceBarrier(cmd, 1, &bufBarrier, 1, &barrier, 0, nullptr); + } + + context->EndCommandBuffer(cmd); + + const auto fence = context->CreateFence(false); + context->QueueSubmit(transferQueue, {}, {}, { cmd }, fence); + context->WaitForFence(fence, 0xFFFFFFFF); + context->DestroyCommandBuffer(cmd); + context->DestroyCommandPool(pool); + context->DestroyFence(fence); + } + + // Acquire on the graphics queue + { + const auto pool = context->CreateCommandPool(graphicsQueue); + const auto cmd = context->CreateCommandBuffer(pool); + context->BeginCommandBuffer(cmd); + + Fox::TextureBarrier imgBarrier{}; + imgBarrier.ImageId = img; + imgBarrier.CurrentState = Fox::EResourceState::COPY_DEST; + imgBarrier.NewState = Fox::EResourceState::PIXEL_SHADER_RESOURCE; + imgBarrier.TransferOwnership = Fox::ACQUIRE; + imgBarrier.SrcQueue = transferQueue; + imgBarrier.DstQueue = graphicsQueue; + + Fox::BufferBarrier bufBarrier{}; + bufBarrier.BufferId = buf; + bufBarrier.CurrentState = Fox::EResourceState::COPY_DEST; + bufBarrier.NewState = Fox::EResourceState::VERTEX_AND_CONSTANT_BUFFER; + bufBarrier.TransferOwnership = Fox::ACQUIRE; + bufBarrier.SrcQueue = transferQueue; + bufBarrier.DstQueue = graphicsQueue; + + context->ResourceBarrier(cmd, 1, &bufBarrier, 1, &imgBarrier, 0, nullptr); + context->EndCommandBuffer(cmd); + + const auto fence = context->CreateFence(false); + context->QueueSubmit(graphicsQueue, {}, {}, { cmd }, fence); + context->WaitForFence(fence, 0xFFFFFFFF); + + context->DestroyCommandBuffer(cmd); + context->DestroyCommandPool(pool); + context->DestroyFence(fence); + } + + context->DestroyBuffer(stagingBuf); + } + + context->DestroyBuffer(buf); + context->DestroyImage(img); + + delete context; +} diff --git a/tests/integration/vulkan/ImageUpload.test.cpp b/tests/integration/vulkan/ImageUpload.test.cpp index dd015bc..daf65da 100644 --- a/tests/integration/vulkan/ImageUpload.test.cpp +++ b/tests/integration/vulkan/ImageUpload.test.cpp @@ -36,26 +36,41 @@ TEST_F(WindowFixture, ShouldCorrectlyUploadImage) Fox::IContext* context = Fox::CreateVulkanContext(&config); ASSERT_NE(context, nullptr); - Fox::DImage img = context->CreateImage(Fox::EFormat::R8G8B8A8_UNORM, 2, 2, 1); + uint32_t img = context->CreateImage(Fox::EFormat::R8G8B8A8_UNORM, 2, 2, 1); - ASSERT_NE(img, nullptr); + //{ + // uint32_t stagingBuf = context->CreateBuffer(data.size(), Fox::EResourceType::TRANSFER, Fox::EMemoryUsage::RESOURCE_MEMORY_USAGE_CPU_TO_GPU); + // const auto transferQueue = context->FindQueue(Fox::EQueueType::QUEUE_TRANSFER); - Fox::CopyDataCommand cmd; - cmd.CopyImageMipMap(img, 0, (void*)data.data(), 2, 2, 0, data.size()); + // const auto pool = context->CreateCommandPool(transferQueue); + // const auto cmd = context->CreateCommandBuffer(pool); + // context->BeginCommandBuffer(cmd); + // Fox::TextureBarrier barrier; + // barrier.ImageId = img; + // barrier.CurrentState = Fox::EResourceState::UNDEFINED; + // barrier.NewState = Fox::EResourceState::COPY_DEST; + // context->ResourceBarrier(cmd, 0, nullptr, 1, &barrier, 0, nullptr); + // context->CopyImage(cmd, img, 2, 2, 0, stagingBuf, 0); + // context->EndCommandBuffer(cmd); - context->SubmitCopy(std::move(cmd)); + // const auto fence = context->CreateFence(false); + // context->QueueSubmit({}, {}, { cmd }, fence); + // context->WaitForFence(fence, 0xFFFFFFFF); + // context->DestroyFence(fence); + // context->DestroyCommandBuffer(cmd); + // context->DestroyCommandPool(pool); + // context->DestroyBuffer(stagingBuf); + //} - context->AdvanceFrame(); + //ASSERT_NE(img, 0); - { - Fox::VulkanContext* vkContext = static_cast(context); - vkContext->WaitDeviceIdle(); // wait copy operations to finish + //{ + // Fox::VulkanContext* vkContext = static_cast(context); + // std::array expected; + // ExtractImage(vkContext, img, 2, 2, 1, VK_FORMAT_R8G8B8A8_UNORM, data.size(), (void*)expected.data()); - std::array expected; - ExtractImage(vkContext, img, 2, 2, 1, VK_FORMAT_R8G8B8A8_UNORM, data.size(), (void*)expected.data()); - - EXPECT_EQ(data, expected); - } + // EXPECT_EQ(data, expected); + //} context->DestroyImage(img); diff --git a/tests/integration/vulkan/SwapchainCreationDestruction.test.cpp b/tests/integration/vulkan/SwapchainCreationDestruction.test.cpp index 4bd5e4e..8d275be 100644 --- a/tests/integration/vulkan/SwapchainCreationDestruction.test.cpp +++ b/tests/integration/vulkan/SwapchainCreationDestruction.test.cpp @@ -20,11 +20,11 @@ TEST_F(WindowFixture, ShouldCreateAndDestroySwapchain) windowData._window; #endif - Fox::DSwapchain swapchain; - auto presentMode = Fox::EPresentMode::IMMEDIATE_KHR; - auto format = Fox::EFormat::B8G8R8A8_UNORM; - ASSERT_EQ(context->CreateSwapchain(&windowData, presentMode, format, &swapchain), true); - ASSERT_NE(swapchain, nullptr); + uint32_t swapchain{}; + auto presentMode = Fox::EPresentMode::IMMEDIATE_KHR; + auto format = Fox::EFormat::B8G8R8A8_UNORM; + swapchain = context->CreateSwapchain(&windowData, presentMode, format); + ASSERT_NE(swapchain, 0); context->DestroySwapchain(swapchain); diff --git a/tests/integration/vulkan/UniformBufferUpload.test.cpp b/tests/integration/vulkan/UniformBufferUpload.test.cpp index 597d722..5e61bfa 100644 --- a/tests/integration/vulkan/UniformBufferUpload.test.cpp +++ b/tests/integration/vulkan/UniformBufferUpload.test.cpp @@ -10,40 +10,40 @@ #include -TEST_F(WindowFixture, ShouldCorrectlyUploadUniformBuffer) -{ - constexpr std::array data{ -1, -1, 3, -1, -1, 3 }; - constexpr size_t bufSize = sizeof(float) * data.size(); - - Fox::DContextConfig config; - config.warningFunction = &WarningAssert; - config.stagingBufferSize = bufSize; - - Fox::IContext* context = Fox::CreateVulkanContext(&config); - ASSERT_NE(context, nullptr); - - Fox::DBuffer buf = context->CreateUniformBuffer(bufSize); - - ASSERT_NE(buf, nullptr); - - Fox::CopyDataCommand cmd; - cmd.CopyUniformBuffer(buf, (void*)data.data(), bufSize); - - context->SubmitCopy(std::move(cmd)); - - context->AdvanceFrame(); - - { - Fox::VulkanContext* vkContext = static_cast(context); - vkContext->WaitDeviceIdle(); // wait copy operations to finish - - std::array expected; - ExtractBuffer(vkContext, buf, bufSize, expected.data()); - - EXPECT_EQ(data, expected); - } - - context->DestroyUniformBuffer(buf); - - delete context; -} +//TEST_F(WindowFixture, ShouldCorrectlyUploadUniformBuffer) +//{ +// constexpr std::array data{ -1, -1, 3, -1, -1, 3 }; +// constexpr size_t bufSize = sizeof(float) * data.size(); +// +// Fox::DContextConfig config; +// config.warningFunction = &WarningAssert; +// config.stagingBufferSize = bufSize; +// +// Fox::IContext* context = Fox::CreateVulkanContext(&config); +// ASSERT_NE(context, nullptr); +// +// Fox::DBuffer buf = context->CreateUniformBuffer(bufSize); +// +// ASSERT_NE(buf, nullptr); +// +// Fox::CopyDataCommand cmd; +// cmd.CopyUniformBuffer(buf, (void*)data.data(), bufSize); +// +// context->SubmitCopy(std::move(cmd)); +// +// context->AdvanceFrame(); +// +// { +// Fox::VulkanContext* vkContext = static_cast(context); +// vkContext->WaitDeviceIdle(); // wait copy operations to finish +// +// std::array expected; +// ExtractBuffer(vkContext, buf, bufSize, expected.data()); +// +// EXPECT_EQ(data, expected); +// } +// +// context->DestroyUniformBuffer(buf); +// +// delete context; +//} diff --git a/tests/integration/vulkan/VertexBufferCreationDestruction.test.cpp b/tests/integration/vulkan/VertexBufferCreationDestruction.test.cpp index 6a9e322..878baba 100644 --- a/tests/integration/vulkan/VertexBufferCreationDestruction.test.cpp +++ b/tests/integration/vulkan/VertexBufferCreationDestruction.test.cpp @@ -2,21 +2,21 @@ #include "backend/vulkan/VulkanContextFactory.h" -TEST_F(WindowFixture, ShouldCreateAndDestroyAVertexBuffer) -{ - - Fox::DContextConfig config; - config.warningFunction = &WarningAssert; - - Fox::IContext* context = Fox::CreateVulkanContext(&config); - ASSERT_NE(context, nullptr); - - Fox::DBuffer buf = context->CreateVertexBuffer(10 * 1024 * 1024); // 10mb - - ASSERT_NE(buf, nullptr); - EXPECT_EQ(buf->Type, Fox::EBufferType::VERTEX_INDEX_BUFFER); - - context->DestroyVertexBuffer(buf); - - delete context; -} +//TEST_F(WindowFixture, ShouldCreateAndDestroyAVertexBuffer) +//{ +// +// Fox::DContextConfig config; +// config.warningFunction = &WarningAssert; +// +// Fox::IContext* context = Fox::CreateVulkanContext(&config); +// ASSERT_NE(context, nullptr); +// +// Fox::DBuffer buf = context->CreateVertexBuffer(10 * 1024 * 1024); // 10mb +// +// ASSERT_NE(buf, nullptr); +// EXPECT_EQ(buf->Type, Fox::EBufferType::VERTEX_INDEX_BUFFER); +// +// context->DestroyVertexBuffer(buf); +// +// delete context; +//} diff --git a/tests/integration/vulkan/VertexBufferUpload.test.cpp b/tests/integration/vulkan/VertexBufferUpload.test.cpp index 9e5a5c3..34bd23d 100644 --- a/tests/integration/vulkan/VertexBufferUpload.test.cpp +++ b/tests/integration/vulkan/VertexBufferUpload.test.cpp @@ -9,107 +9,107 @@ #include -TEST_F(WindowFixture, ShouldCorrectlyUploadVertexBuffer) -{ - constexpr std::array ndcTriangle{ -1, -1, 3, -1, -1, 3 }; - constexpr size_t bufSize = sizeof(float) * ndcTriangle.size(); - - Fox::DContextConfig config; - config.warningFunction = &WarningAssert; - config.stagingBufferSize = bufSize; - - Fox::IContext* context = Fox::CreateVulkanContext(&config); - ASSERT_NE(context, nullptr); - - Fox::DBuffer buf = context->CreateVertexBuffer(bufSize); - - ASSERT_NE(buf, nullptr); - - Fox::CopyDataCommand cmd; - cmd.CopyVertex(buf, 0, (void*)ndcTriangle.data(), bufSize); - - context->SubmitCopy(std::move(cmd)); - - context->AdvanceFrame(); - - { - Fox::VulkanContext* vkContext = static_cast(context); - vkContext->WaitDeviceIdle(); // wait copy operations to finish - - std::array expected; - ExtractBuffer(vkContext, buf, bufSize, expected.data()); - - EXPECT_EQ(ndcTriangle, expected); - } - - context->DestroyVertexBuffer(buf); - - delete context; -} - -TEST_F(WindowFixture, ShouldCorrectlyUploadMultipleVertexBuffer) -{ - - constexpr std::array ndcTriangle{ -1, -1, 3, -1, -1, 3 }; - constexpr size_t triangleSize = sizeof(float) * ndcTriangle.size(); - - constexpr std::array data{ 1, 2, 3, 4, 5, 5, 6, 7, 8, 9 }; - constexpr size_t dataSize = sizeof(float) * data.size(); - - constexpr std::array data2{ 1, 2, 3, 4 }; - constexpr size_t data2Size = sizeof(float) * data2.size(); - - Fox::DContextConfig config; - config.warningFunction = &WarningAssert; - config.stagingBufferSize = triangleSize + dataSize + data2Size; - - Fox::IContext* context = Fox::CreateVulkanContext(&config); - ASSERT_NE(context, nullptr); - - Fox::DBuffer buf = context->CreateVertexBuffer(triangleSize); - ASSERT_NE(buf, nullptr); - Fox::CopyDataCommand cmd; - cmd.CopyVertex(buf, 0, (void*)ndcTriangle.data(), triangleSize); - context->SubmitCopy(std::move(cmd)); - - Fox::DBuffer buf1 = context->CreateVertexBuffer(dataSize); - ASSERT_NE(buf1, nullptr); - Fox::CopyDataCommand cmd1; - cmd1.CopyVertex(buf1, 0, (void*)data.data(), dataSize); - context->SubmitCopy(std::move(cmd1)); - - Fox::DBuffer buf2 = context->CreateVertexBuffer(data2Size); - ASSERT_NE(buf2, nullptr); - Fox::CopyDataCommand cmd2; - cmd2.CopyVertex(buf2, 0, (void*)data2.data(), data2Size); - context->SubmitCopy(std::move(cmd2)); - - context->AdvanceFrame(); - - { - Fox::VulkanContext* vkContext = static_cast(context); - vkContext->WaitDeviceIdle(); // wait copy operations to finish - - { - std::array output; - ExtractBuffer(vkContext, buf, triangleSize, output.data()); - EXPECT_EQ(ndcTriangle, output); - } - { - std::array output; - ExtractBuffer(vkContext, buf1, dataSize, output.data()); - EXPECT_EQ(data, output); - } - { - std::array output; - ExtractBuffer(vkContext, buf2, data2Size, output.data()); - EXPECT_EQ(data2, output); - } - } - - context->DestroyVertexBuffer(buf); - context->DestroyVertexBuffer(buf1); - context->DestroyVertexBuffer(buf2); - - delete context; -} +//TEST_F(WindowFixture, ShouldCorrectlyUploadVertexBuffer) +//{ +// constexpr std::array ndcTriangle{ -1, -1, 3, -1, -1, 3 }; +// constexpr size_t bufSize = sizeof(float) * ndcTriangle.size(); +// +// Fox::DContextConfig config; +// config.warningFunction = &WarningAssert; +// config.stagingBufferSize = bufSize; +// +// Fox::IContext* context = Fox::CreateVulkanContext(&config); +// ASSERT_NE(context, nullptr); +// +// Fox::DBuffer buf = context->CreateVertexBuffer(bufSize); +// +// ASSERT_NE(buf, nullptr); +// +// Fox::CopyDataCommand cmd; +// cmd.CopyVertex(buf, 0, (void*)ndcTriangle.data(), bufSize); +// +// context->SubmitCopy(std::move(cmd)); +// +// context->AdvanceFrame(); +// +// { +// Fox::VulkanContext* vkContext = static_cast(context); +// vkContext->WaitDeviceIdle(); // wait copy operations to finish +// +// std::array expected; +// ExtractBuffer(vkContext, buf, bufSize, expected.data()); +// +// EXPECT_EQ(ndcTriangle, expected); +// } +// +// context->DestroyVertexBuffer(buf); +// +// delete context; +//} +// +//TEST_F(WindowFixture, ShouldCorrectlyUploadMultipleVertexBuffer) +//{ +// +// constexpr std::array ndcTriangle{ -1, -1, 3, -1, -1, 3 }; +// constexpr size_t triangleSize = sizeof(float) * ndcTriangle.size(); +// +// constexpr std::array data{ 1, 2, 3, 4, 5, 5, 6, 7, 8, 9 }; +// constexpr size_t dataSize = sizeof(float) * data.size(); +// +// constexpr std::array data2{ 1, 2, 3, 4 }; +// constexpr size_t data2Size = sizeof(float) * data2.size(); +// +// Fox::DContextConfig config; +// config.warningFunction = &WarningAssert; +// config.stagingBufferSize = triangleSize + dataSize + data2Size; +// +// Fox::IContext* context = Fox::CreateVulkanContext(&config); +// ASSERT_NE(context, nullptr); +// +// Fox::DBuffer buf = context->CreateVertexBuffer(triangleSize); +// ASSERT_NE(buf, nullptr); +// Fox::CopyDataCommand cmd; +// cmd.CopyVertex(buf, 0, (void*)ndcTriangle.data(), triangleSize); +// context->SubmitCopy(std::move(cmd)); +// +// Fox::DBuffer buf1 = context->CreateVertexBuffer(dataSize); +// ASSERT_NE(buf1, nullptr); +// Fox::CopyDataCommand cmd1; +// cmd1.CopyVertex(buf1, 0, (void*)data.data(), dataSize); +// context->SubmitCopy(std::move(cmd1)); +// +// Fox::DBuffer buf2 = context->CreateVertexBuffer(data2Size); +// ASSERT_NE(buf2, nullptr); +// Fox::CopyDataCommand cmd2; +// cmd2.CopyVertex(buf2, 0, (void*)data2.data(), data2Size); +// context->SubmitCopy(std::move(cmd2)); +// +// context->AdvanceFrame(); +// +// { +// Fox::VulkanContext* vkContext = static_cast(context); +// vkContext->WaitDeviceIdle(); // wait copy operations to finish +// +// { +// std::array output; +// ExtractBuffer(vkContext, buf, triangleSize, output.data()); +// EXPECT_EQ(ndcTriangle, output); +// } +// { +// std::array output; +// ExtractBuffer(vkContext, buf1, dataSize, output.data()); +// EXPECT_EQ(data, output); +// } +// { +// std::array output; +// ExtractBuffer(vkContext, buf2, data2Size, output.data()); +// EXPECT_EQ(data2, output); +// } +// } +// +// context->DestroyVertexBuffer(buf); +// context->DestroyVertexBuffer(buf1); +// context->DestroyVertexBuffer(buf2); +// +// delete context; +//} diff --git a/tests/unit/vulkan/RIRenderPassAttachmentsConversion.test.cpp b/tests/unit/vulkan/RIRenderPassAttachmentsConversion.test.cpp index bba353c..a8b0f0c 100644 --- a/tests/unit/vulkan/RIRenderPassAttachmentsConversion.test.cpp +++ b/tests/unit/vulkan/RIRenderPassAttachmentsConversion.test.cpp @@ -1,5 +1,5 @@ #include "IContext.h" -#include "backend/vulkan/UtilsVK.h" +#include "backend/vulkan/UtilsVk.h" #include "backend/vulkan/VulkanContext.h" #include diff --git a/tests/unit/vulkan/VkUtils.test.cpp b/tests/unit/vulkan/VkUtils.test.cpp index e5fa60e..a34639b 100644 --- a/tests/unit/vulkan/VkUtils.test.cpp +++ b/tests/unit/vulkan/VkUtils.test.cpp @@ -1,4 +1,4 @@ -#include "backend/vulkan/UtilsVK.h" +#include "backend/vulkan/UtilsVk.h" #include @@ -37,4 +37,177 @@ TEST(UnitFilterExclusive, ShouldFilterAsExpected) const auto found = std::find_if(onlyIncluded.begin(), onlyIncluded.end(), [&source](const char* a) { return strcmp(a, source[2]) == 0; }); ASSERT_NE(found, onlyIncluded.end()); } -} \ No newline at end of file +} + +TEST(UnitConvertQueueTypeToVkFlags, ShouldConvertCorrectlyFlags) +{ + using namespace Fox; + + { + const VkFlags flag = convertQueueTypeToVkFlags(EQueueType::QUEUE_GRAPHICS); + ASSERT_TRUE(flag & VK_QUEUE_GRAPHICS_BIT && (~flag & VK_QUEUE_GRAPHICS_BIT) == 0); + } + { + const VkFlags flag = convertQueueTypeToVkFlags(EQueueType::QUEUE_COMPUTE); + ASSERT_TRUE(flag & VK_QUEUE_COMPUTE_BIT && (~flag & VK_QUEUE_COMPUTE_BIT) == 0); + } + { + const VkFlags flag = convertQueueTypeToVkFlags(EQueueType::QUEUE_TRANSFER); + ASSERT_TRUE(flag & VK_QUEUE_TRANSFER_BIT && (~flag & VK_QUEUE_TRANSFER_BIT) == 0); + } +} + +TEST(UnitFindQueueFromQueueFlags, ShouldReturnCorrectQueueFamilyAndIndex) +{ + using namespace Fox; + + { + // NVIDIA GeForce GTX 750 Ti GPU queue families + VkQueueFamilyProperties families[3]{}; + families[0].queueFlags = VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT; + families[0].queueCount = 16; + + families[1].queueFlags = VK_QUEUE_TRANSFER_BIT | VK_QUEUE_SPARSE_BINDING_BIT; + families[1].queueCount = 1; + + families[2].queueFlags = VK_QUEUE_TRANSFER_BIT | VK_QUEUE_VIDEO_DECODE_BIT_KHR; + families[2].queueCount = 1; + + uint32_t queueIndexCreatedCount[3]{}; + { + uint32_t queueFamily{}; + uint32_t queueIndex{}; + const bool found = findQueueWithFlags(&queueFamily, &queueIndex, VK_QUEUE_GRAPHICS_BIT, families, sizeof(families) / sizeof(families[0]), queueIndexCreatedCount); + ASSERT_TRUE(found); + ASSERT_EQ(queueFamily, 0); + ASSERT_EQ(queueIndex, 0); + } + { + uint32_t queueFamily{}; + uint32_t queueIndex{}; + const bool found = findQueueWithFlags(&queueFamily, &queueIndex, VK_QUEUE_COMPUTE_BIT, families, sizeof(families) / sizeof(families[0]), queueIndexCreatedCount); + ASSERT_TRUE(found); + ASSERT_EQ(queueFamily, 0); + ASSERT_EQ(queueIndex, 0); + } + { + uint32_t queueFamily{}; + uint32_t queueIndex{}; + const bool found = findQueueWithFlags(&queueFamily, &queueIndex, VK_QUEUE_TRANSFER_BIT, families, sizeof(families) / sizeof(families[0]), queueIndexCreatedCount); + ASSERT_TRUE(found); + ASSERT_EQ(queueFamily, 1); + ASSERT_EQ(queueIndex, 0); + } + // Since previous call the queue index was taken now it should return second family that has transfer flag + { + uint32_t queueFamily{}; + uint32_t queueIndex{}; + const bool found = findQueueWithFlags(&queueFamily, &queueIndex, VK_QUEUE_TRANSFER_BIT, families, sizeof(families) / sizeof(families[0]), queueIndexCreatedCount); + ASSERT_TRUE(found); + ASSERT_EQ(queueFamily, 2); + ASSERT_EQ(queueIndex, 0); + } + // Since previous call the queue index was taken now it should return general purpose queue + { + uint32_t queueFamily{}; + uint32_t queueIndex{}; + const bool found = findQueueWithFlags(&queueFamily, &queueIndex, VK_QUEUE_TRANSFER_BIT, families, sizeof(families) / sizeof(families[0]), queueIndexCreatedCount); + ASSERT_TRUE(found); + ASSERT_EQ(queueFamily, 0); + ASSERT_EQ(queueIndex, 0); + } + } + + { + // NVIDIA GeForce GTX 1080 Ti GPU queue families + VkQueueFamilyProperties families[3]{}; + families[0].queueFlags = VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT; + families[0].queueCount = 16; + + families[1].queueFlags = VK_QUEUE_TRANSFER_BIT; + families[1].queueCount = 2; + + families[2].queueFlags = VK_QUEUE_COMPUTE_BIT; + families[2].queueCount = 8; + + uint32_t queueIndexCreatedCount[3]{}; + { + uint32_t queueFamily{}; + uint32_t queueIndex{}; + const bool found = findQueueWithFlags(&queueFamily, &queueIndex, VK_QUEUE_GRAPHICS_BIT, families, sizeof(families) / sizeof(families[0]), queueIndexCreatedCount); + ASSERT_TRUE(found); + ASSERT_EQ(queueFamily, 0); + ASSERT_EQ(queueIndex, 0); + } + /*Should enumerate all queue indices*/ + for (uint32_t i = 0; i < families[2].queueCount; i++) + { + uint32_t queueFamily{}; + uint32_t queueIndex{}; + const bool found = findQueueWithFlags(&queueFamily, &queueIndex, VK_QUEUE_COMPUTE_BIT, families, sizeof(families) / sizeof(families[0]), queueIndexCreatedCount); + ASSERT_TRUE(found); + ASSERT_EQ(queueFamily, 2); + ASSERT_EQ(queueIndex, i); + } + /*Should enumerate all queue indices*/ + for (uint32_t i = 0; i < families[1].queueCount; i++) + { + uint32_t queueFamily{}; + uint32_t queueIndex{}; + const bool found = findQueueWithFlags(&queueFamily, &queueIndex, VK_QUEUE_TRANSFER_BIT, families, sizeof(families) / sizeof(families[0]), queueIndexCreatedCount); + ASSERT_TRUE(found); + ASSERT_EQ(queueFamily, 1); + ASSERT_EQ(queueIndex, i); + } + // Should return general purpose queue because we already queries all queues of this type + { + uint32_t queueFamily{}; + uint32_t queueIndex{}; + const bool found = findQueueWithFlags(&queueFamily, &queueIndex, VK_QUEUE_TRANSFER_BIT, families, sizeof(families) / sizeof(families[0]), queueIndexCreatedCount); + ASSERT_TRUE(found); + ASSERT_EQ(queueFamily, 0); + ASSERT_EQ(queueIndex, 0); + } + } + + { + // Intel(R) UHD Graphic GPU queue families + VkQueueFamilyProperties families[1]{}; + families[0].queueFlags = VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT | VK_QUEUE_SPARSE_BINDING_BIT; + families[0].queueCount = 1; + + uint32_t queueIndexCreatedCount[1]{}; + { + uint32_t queueFamily{}; + uint32_t queueIndex{}; + const bool found = findQueueWithFlags(&queueFamily, &queueIndex, VK_QUEUE_GRAPHICS_BIT, families, 1, queueIndexCreatedCount); + ASSERT_TRUE(found); + ASSERT_EQ(queueFamily, 0); + ASSERT_EQ(queueIndex, 0); + } + { + uint32_t queueFamily{}; + uint32_t queueIndex{}; + const bool found = findQueueWithFlags(&queueFamily, &queueIndex, VK_QUEUE_COMPUTE_BIT, families, 1, queueIndexCreatedCount); + ASSERT_TRUE(found); + ASSERT_EQ(queueFamily, 0); + ASSERT_EQ(queueIndex, 0); + } + { + uint32_t queueFamily{}; + uint32_t queueIndex{}; + const bool found = findQueueWithFlags(&queueFamily, &queueIndex, VK_QUEUE_TRANSFER_BIT, families, 1, queueIndexCreatedCount); + ASSERT_TRUE(found); + ASSERT_EQ(queueFamily, 0); + ASSERT_EQ(queueIndex, 0); + } + { + uint32_t queueFamily{}; + uint32_t queueIndex{}; + const bool found = findQueueWithFlags(&queueFamily, &queueIndex, VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT, families, 1, queueIndexCreatedCount); + ASSERT_TRUE(found); + ASSERT_EQ(queueFamily, 0); + ASSERT_EQ(queueIndex, 0); + } + } +} diff --git a/tests/utilities/ExtractBuffer.h b/tests/utilities/ExtractBuffer.h index b205bd8..d13f0cf 100644 --- a/tests/utilities/ExtractBuffer.h +++ b/tests/utilities/ExtractBuffer.h @@ -5,29 +5,29 @@ #include "backend/vulkan/VulkanContextFactory.h" #include "backend/vulkan/VulkanDevice13.h" -static void -ExtractBuffer(Fox::VulkanContext* vkContext, Fox::DBuffer src, uint32_t bytes, void* outData) -{ - Fox::DBufferVulkan* vkSrcBuf = static_cast(src); - - Fox::RIVulkanDevice13& device = vkContext->GetDevice(); - auto outBuf = device.CreateBufferHostVisible(bytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT); - - auto cmdPool = device.CreateCommandPool(); - auto cmdBuffer = cmdPool->Allocate(); - Fox::CResourceTransfer transfer(cmdBuffer->Cmd); - transfer.CopyBuffer(vkSrcBuf->Buffer.Buffer, outBuf.Buffer, bytes, 0); - transfer.FinishCommandBuffer(); - - const std::vector cmds{ cmdBuffer }; - device.SubmitToMainQueue(cmds, {}, VK_NULL_HANDLE, VK_NULL_HANDLE); - vkContext->WaitDeviceIdle(); // wait copy operations to finish - - void* outputPtr = device.MapBuffer(outBuf); - memcpy(outData, outputPtr, bytes); - device.UnmapBuffer(outBuf); - - // cleanup - device.DestroyBuffer(outBuf); - device.DestroyCommandPool(cmdPool); -}; \ No newline at end of file +//static void +//ExtractBuffer(Fox::VulkanContext* vkContext, uint32_t src, uint32_t bytes, void* outData) +//{ +// Fox::DBufferVulkan* vkSrcBuf = static_cast(src); +// +// Fox::RIVulkanDevice13& device = vkContext->GetDevice(); +// auto outBuf = device.CreateBufferHostVisible(bytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT); +// +// auto cmdPool = device.CreateCommandPool(); +// auto cmdBuffer = cmdPool->Allocate(); +// Fox::CResourceTransfer transfer(cmdBuffer->Cmd); +// transfer.CopyBuffer(vkSrcBuf->Buffer.Buffer, outBuf.Buffer, bytes, 0); +// transfer.FinishCommandBuffer(); +// +// const std::vector cmds{ cmdBuffer }; +// device.SubmitToMainQueue(cmds, {}, VK_NULL_HANDLE, VK_NULL_HANDLE); +// vkContext->WaitDeviceIdle(); // wait copy operations to finish +// +// void* outputPtr = device.MapBuffer(outBuf); +// memcpy(outData, outputPtr, bytes); +// device.UnmapBuffer(outBuf); +// +// // cleanup +// device.DestroyBuffer(outBuf); +// device.DestroyCommandPool(cmdPool); +//}; \ No newline at end of file diff --git a/tests/utilities/ExtractImage.h b/tests/utilities/ExtractImage.h index bc11c29..0a360b0 100644 --- a/tests/utilities/ExtractImage.h +++ b/tests/utilities/ExtractImage.h @@ -5,32 +5,32 @@ #include "backend/vulkan/VulkanContextFactory.h" #include "backend/vulkan/VulkanDevice13.h" -static void -ExtractImage(Fox::VulkanContext* vkContext, Fox::DImage src, uint32_t width, uint32_t height, uint32_t mipLevels, VkFormat format, uint32_t bytes, void* outData) -{ - Fox::DImageVulkan* vkSrcImg = static_cast(src); - - Fox::RIVulkanDevice13& device = vkContext->GetDevice(); - - auto cmdPool = device.CreateCommandPool(); - auto cmdBuffer = cmdPool->Allocate(); - Fox::CResourceTransfer transfer(cmdBuffer->Cmd); - - auto outImg = device.CreateBufferHostVisible(16, VK_IMAGE_USAGE_TRANSFER_DST_BIT); - - transfer.CopyImageToBuffer(outImg.Buffer, vkSrcImg->Image.Image, { width, height }, 0); - - transfer.FinishCommandBuffer(); - - const std::vector cmds{ cmdBuffer }; - device.SubmitToMainQueue(cmds, {}, VK_NULL_HANDLE, VK_NULL_HANDLE); - vkContext->WaitDeviceIdle(); // wait copy operations to finish - - void* outputPtr = device.MapBuffer(outImg); - memcpy(outData, outputPtr, bytes); - device.UnmapBuffer(outImg); - - //// cleanup - device.DestroyBuffer(outImg); - device.DestroyCommandPool(cmdPool); -}; \ No newline at end of file +//static void +//ExtractImage(Fox::VulkanContext* vkContext, Fox::DImage src, uint32_t width, uint32_t height, uint32_t mipLevels, VkFormat format, uint32_t bytes, void* outData) +//{ +// Fox::DImageVulkan* vkSrcImg = static_cast(src); +// +// Fox::RIVulkanDevice13& device = vkContext->GetDevice(); +// +// auto cmdPool = device.CreateCommandPool(); +// auto cmdBuffer = cmdPool->Allocate(); +// Fox::CResourceTransfer transfer(cmdBuffer->Cmd); +// +// auto outImg = device.CreateBufferHostVisible(16, VK_IMAGE_USAGE_TRANSFER_DST_BIT); +// +// transfer.CopyImageToBuffer(outImg.Buffer, vkSrcImg->Image.Image, { width, height }, 0); +// +// transfer.FinishCommandBuffer(); +// +// const std::vector cmds{ cmdBuffer }; +// device.SubmitToMainQueue(cmds, {}, VK_NULL_HANDLE, VK_NULL_HANDLE); +// vkContext->WaitDeviceIdle(); // wait copy operations to finish +// +// void* outputPtr = device.MapBuffer(outImg); +// memcpy(outData, outputPtr, bytes); +// device.UnmapBuffer(outImg); +// +// //// cleanup +// device.DestroyBuffer(outImg); +// device.DestroyCommandPool(cmdPool); +//}; \ No newline at end of file diff --git a/thirdparty/Vulkan-Headers b/thirdparty/Vulkan-Headers new file mode 160000 index 0000000..5a5c9a6 --- /dev/null +++ b/thirdparty/Vulkan-Headers @@ -0,0 +1 @@ +Subproject commit 5a5c9a643484d888873e32c5d7d484fae8e71d3d diff --git a/thirdparty/VulkanMemoryAllocator b/thirdparty/VulkanMemoryAllocator index cb08556..98c4f34 160000 --- a/thirdparty/VulkanMemoryAllocator +++ b/thirdparty/VulkanMemoryAllocator @@ -1 +1 @@ -Subproject commit cb085560229fa35254b2d7d36f9f61b572b8ac4c +Subproject commit 98c4f3414b015432c6b040bdb53b5ba0c5d6c680 diff --git a/thirdparty/glslang b/thirdparty/glslang new file mode 160000 index 0000000..022aea4 --- /dev/null +++ b/thirdparty/glslang @@ -0,0 +1 @@ +Subproject commit 022aea431c462f351c1120cb0b4a2144aa237a50 diff --git a/thirdparty/tinygltf b/thirdparty/tinygltf deleted file mode 160000 index 5e8a7fd..0000000 --- a/thirdparty/tinygltf +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 5e8a7fd602af22aa9619ccd3baeaeeaff0ecb6f3 diff --git a/thirdparty/volk b/thirdparty/volk index 48dbfa8..692bef4 160000 --- a/thirdparty/volk +++ b/thirdparty/volk @@ -1 +1 @@ -Subproject commit 48dbfa81a03ec3b994cc2eec6f57c60d3994fbf5 +Subproject commit 692bef4349111d5a1e24fa0fed79eee41496a09f