diff --git a/.gitmodules b/.gitmodules index 347b3728..42caa0fb 100644 --- a/.gitmodules +++ b/.gitmodules @@ -2,6 +2,3 @@ path = MojoShader url = https://github.com/icculus/mojoshader branch = main -[submodule "Vulkan-Headers"] - path = Vulkan-Headers - url = https://github.com/KhronosGroup/Vulkan-Headers diff --git a/CMakeLists.txt b/CMakeLists.txt index 480fe56d..4d2e1a87 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -48,7 +48,6 @@ endif() # Defines add_definitions( - -DFNA3D_DRIVER_VULKAN -DFNA3D_DRIVER_OPENGL ) if(BUILD_SDL3) @@ -85,9 +84,6 @@ else() endif() if(EMSCRIPTEN) - remove_definitions( - -DFNA3D_DRIVER_VULKAN - ) add_definitions( -DSUPPORT_PROFILE_GLSPIRV=0 -DSUPPORT_PROFILE_SPIRV=0 @@ -103,19 +99,13 @@ add_library(FNA3D src/FNA3D_Driver.h src/FNA3D_Driver_OpenGL.h src/FNA3D_Driver_OpenGL_glfuncs.h - src/FNA3D_Driver_Vulkan_vkfuncs.h - src/FNA3D_CommandBuffer.h - src/FNA3D_Memory.h src/FNA3D_PipelineCache.h # Source Files src/FNA3D.c src/FNA3D_Driver_D3D11.c src/FNA3D_Driver_OpenGL.c src/FNA3D_Driver_SDL.c - src/FNA3D_Driver_Vulkan.c src/FNA3D_Image.c - src/FNA3D_CommandBuffer.c - src/FNA3D_Memory.c src/FNA3D_PipelineCache.c src/FNA3D_Tracing.c ) @@ -125,7 +115,6 @@ add_library(mojoshader STATIC MojoShader/mojoshader_common.c MojoShader/mojoshader_d3d11.c MojoShader/mojoshader_opengl.c - MojoShader/mojoshader_vulkan.c MojoShader/mojoshader_sdlgpu.c MojoShader/profiles/mojoshader_profile_common.c MojoShader/profiles/mojoshader_profile_glsl.c @@ -152,7 +141,6 @@ endif() target_include_directories(FNA3D PUBLIC $ $ - $ ) if(BUILD_DXVK_NATIVE) add_definitions(-DFNA3D_DXVK_NATIVE) @@ -161,7 +149,6 @@ if(BUILD_DXVK_NATIVE) endif() target_include_directories(mojoshader PUBLIC $ - $ ) # MinGW builds should statically link libgcc diff --git a/README b/README index db096fdd..3cfd5d77 100644 --- a/README +++ b/README @@ -10,8 +10,8 @@ About FNA3D ----------- FNA3D was written to be used for FNA's Graphics namespace. It carries the same API design as XNA 4.0, with various implementations available at runtime -(including Vulkan, OpenGL, Metal via MoltenVK, and Direct3D). For shaders, -we support Direct3D 9 Effect Framework binaries via MojoShader. +(including SDL_GPU, OpenGL, and Direct3D). For shaders, we support Direct3D 9 +Effect Framework binaries via MojoShader. Note that while FNA is the main consumer of FNA3D, we do NOT provide separate C# bindings. If you want to use FNA3D in C#, simply use FNA instead; it's the same diff --git a/Vulkan-Headers b/Vulkan-Headers deleted file mode 160000 index 85470b32..00000000 --- a/Vulkan-Headers +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 85470b32ad5d0d7d67fdf411b6e7b502c09c9c52 diff --git a/Xcode/FNA3D.xcodeproj/project.pbxproj b/Xcode/FNA3D.xcodeproj/project.pbxproj index 23bea2df..3ecc8fc8 100644 --- a/Xcode/FNA3D.xcodeproj/project.pbxproj +++ b/Xcode/FNA3D.xcodeproj/project.pbxproj @@ -7,10 +7,6 @@ objects = { /* Begin PBXBuildFile section */ - 021FF3972A4A764500A63B55 /* FNA3D_Memory.c in Sources */ = {isa = PBXBuildFile; fileRef = 021FF3962A4A764500A63B55 /* FNA3D_Memory.c */; }; - 021FF3982A4A764500A63B55 /* FNA3D_Memory.c in Sources */ = {isa = PBXBuildFile; fileRef = 021FF3962A4A764500A63B55 /* FNA3D_Memory.c */; }; - 02FD608F2A7B227300E1D7A5 /* FNA3D_CommandBuffer.c in Sources */ = {isa = PBXBuildFile; fileRef = 02FD608E2A7B227300E1D7A5 /* FNA3D_CommandBuffer.c */; }; - 02FD60902A7B227300E1D7A5 /* FNA3D_CommandBuffer.c in Sources */ = {isa = PBXBuildFile; fileRef = 02FD608E2A7B227300E1D7A5 /* FNA3D_CommandBuffer.c */; }; 7B8B6CBE24452690001C08D6 /* mojoshader_common.c in Sources */ = {isa = PBXBuildFile; fileRef = 7B8B6CB824452690001C08D6 /* mojoshader_common.c */; }; 7B8B6CBF24452690001C08D6 /* mojoshader_common.c in Sources */ = {isa = PBXBuildFile; fileRef = 7B8B6CB824452690001C08D6 /* mojoshader_common.c */; }; 7B8B6CC224452690001C08D6 /* mojoshader.c in Sources */ = {isa = PBXBuildFile; fileRef = 7B8B6CBA24452690001C08D6 /* mojoshader.c */; }; @@ -25,15 +21,11 @@ 7BC01C072B4348F300941563 /* mojoshader_profile_spirv.c in Sources */ = {isa = PBXBuildFile; fileRef = 7BF94B9F275C046100050413 /* mojoshader_profile_spirv.c */; }; 7BC01C082B4348F300941563 /* mojoshader.c in Sources */ = {isa = PBXBuildFile; fileRef = 7B8B6CBA24452690001C08D6 /* mojoshader.c */; }; 7BC01C092B4348F300941563 /* mojoshader_common.c in Sources */ = {isa = PBXBuildFile; fileRef = 7B8B6CB824452690001C08D6 /* mojoshader_common.c */; }; - 7BC01C0A2B4348F300941563 /* mojoshader_vulkan.c in Sources */ = {isa = PBXBuildFile; fileRef = 7BF94B9C275C044E00050413 /* mojoshader_vulkan.c */; }; 7BC01C0B2B4348F300941563 /* mojoshader_profile_common.c in Sources */ = {isa = PBXBuildFile; fileRef = 7B8B6CC6244526A7001C08D6 /* mojoshader_profile_common.c */; }; 7BC01C0C2B4348F300941563 /* mojoshader_effects.c in Sources */ = {isa = PBXBuildFile; fileRef = 7B8B6CBB24452690001C08D6 /* mojoshader_effects.c */; }; - 7BC01C0D2B4348F700941563 /* FNA3D_Driver_Vulkan.c in Sources */ = {isa = PBXBuildFile; fileRef = 7BF94B99275C042200050413 /* FNA3D_Driver_Vulkan.c */; }; - 7BC01C0E2B4348F700941563 /* FNA3D_CommandBuffer.c in Sources */ = {isa = PBXBuildFile; fileRef = 02FD608E2A7B227300E1D7A5 /* FNA3D_CommandBuffer.c */; }; 7BC01C0F2B4348F700941563 /* FNA3D_Image.c in Sources */ = {isa = PBXBuildFile; fileRef = 7BF8206C2445254300736AB0 /* FNA3D_Image.c */; }; 7BC01C102B4348F700941563 /* FNA3D_PipelineCache.c in Sources */ = {isa = PBXBuildFile; fileRef = 7BF8206E2445254300736AB0 /* FNA3D_PipelineCache.c */; }; 7BC01C112B4348F700941563 /* FNA3D.c in Sources */ = {isa = PBXBuildFile; fileRef = 7BF820682445254300736AB0 /* FNA3D.c */; }; - 7BC01C122B4348F700941563 /* FNA3D_Memory.c in Sources */ = {isa = PBXBuildFile; fileRef = 021FF3962A4A764500A63B55 /* FNA3D_Memory.c */; }; 7BC01C142B43490100941563 /* FNA3D_Driver_OpenGL.c in Sources */ = {isa = PBXBuildFile; fileRef = 7BC01C132B43490100941563 /* FNA3D_Driver_OpenGL.c */; }; 7BF820702445254300736AB0 /* FNA3D.c in Sources */ = {isa = PBXBuildFile; fileRef = 7BF820682445254300736AB0 /* FNA3D.c */; }; 7BF820712445254300736AB0 /* FNA3D.c in Sources */ = {isa = PBXBuildFile; fileRef = 7BF820682445254300736AB0 /* FNA3D.c */; }; @@ -41,10 +33,6 @@ 7BF820792445254300736AB0 /* FNA3D_Image.c in Sources */ = {isa = PBXBuildFile; fileRef = 7BF8206C2445254300736AB0 /* FNA3D_Image.c */; }; 7BF8207C2445254300736AB0 /* FNA3D_PipelineCache.c in Sources */ = {isa = PBXBuildFile; fileRef = 7BF8206E2445254300736AB0 /* FNA3D_PipelineCache.c */; }; 7BF8207D2445254300736AB0 /* FNA3D_PipelineCache.c in Sources */ = {isa = PBXBuildFile; fileRef = 7BF8206E2445254300736AB0 /* FNA3D_PipelineCache.c */; }; - 7BF94B9A275C042200050413 /* FNA3D_Driver_Vulkan.c in Sources */ = {isa = PBXBuildFile; fileRef = 7BF94B99275C042200050413 /* FNA3D_Driver_Vulkan.c */; }; - 7BF94B9B275C042200050413 /* FNA3D_Driver_Vulkan.c in Sources */ = {isa = PBXBuildFile; fileRef = 7BF94B99275C042200050413 /* FNA3D_Driver_Vulkan.c */; }; - 7BF94B9D275C044E00050413 /* mojoshader_vulkan.c in Sources */ = {isa = PBXBuildFile; fileRef = 7BF94B9C275C044E00050413 /* mojoshader_vulkan.c */; }; - 7BF94B9E275C044E00050413 /* mojoshader_vulkan.c in Sources */ = {isa = PBXBuildFile; fileRef = 7BF94B9C275C044E00050413 /* mojoshader_vulkan.c */; }; 7BF94BA0275C046100050413 /* mojoshader_profile_spirv.c in Sources */ = {isa = PBXBuildFile; fileRef = 7BF94B9F275C046100050413 /* mojoshader_profile_spirv.c */; }; 7BF94BA1275C046100050413 /* mojoshader_profile_spirv.c in Sources */ = {isa = PBXBuildFile; fileRef = 7BF94B9F275C046100050413 /* mojoshader_profile_spirv.c */; }; /* End PBXBuildFile section */ @@ -151,9 +139,6 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ - 021FF3962A4A764500A63B55 /* FNA3D_Memory.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = FNA3D_Memory.c; path = ../src/FNA3D_Memory.c; sourceTree = ""; }; - 02FD608D2A7B226300E1D7A5 /* FNA3D_CommandBuffer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = FNA3D_CommandBuffer.h; path = ../src/FNA3D_CommandBuffer.h; sourceTree = ""; }; - 02FD608E2A7B227300E1D7A5 /* FNA3D_CommandBuffer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = FNA3D_CommandBuffer.c; path = ../src/FNA3D_CommandBuffer.c; sourceTree = ""; }; 7B1CDD452190C0A200175C7B /* libFNA3D.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libFNA3D.a; sourceTree = BUILT_PRODUCTS_DIR; }; 7B7E140D2190E0CB00616654 /* libFNA3D.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libFNA3D.a; sourceTree = BUILT_PRODUCTS_DIR; }; 7B81CE172B434A04007EC76D /* SDL.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = SDL.xcodeproj; path = ../../SDL2/Xcode/SDL/SDL.xcodeproj; sourceTree = ""; }; @@ -171,8 +156,6 @@ 7BF820682445254300736AB0 /* FNA3D.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = FNA3D.c; path = ../src/FNA3D.c; sourceTree = ""; }; 7BF8206C2445254300736AB0 /* FNA3D_Image.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = FNA3D_Image.c; path = ../src/FNA3D_Image.c; sourceTree = ""; }; 7BF8206E2445254300736AB0 /* FNA3D_PipelineCache.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = FNA3D_PipelineCache.c; path = ../src/FNA3D_PipelineCache.c; sourceTree = ""; }; - 7BF94B99275C042200050413 /* FNA3D_Driver_Vulkan.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = FNA3D_Driver_Vulkan.c; path = ../src/FNA3D_Driver_Vulkan.c; sourceTree = ""; }; - 7BF94B9C275C044E00050413 /* mojoshader_vulkan.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mojoshader_vulkan.c; path = ../MojoShader/mojoshader_vulkan.c; sourceTree = ""; }; 7BF94B9F275C046100050413 /* mojoshader_profile_spirv.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mojoshader_profile_spirv.c; path = ../MojoShader/profiles/mojoshader_profile_spirv.c; sourceTree = ""; }; /* End PBXFileReference section */ @@ -227,9 +210,6 @@ 7B1CDDA62190C50300175C7B /* Library Source */ = { isa = PBXGroup; children = ( - 02FD608E2A7B227300E1D7A5 /* FNA3D_CommandBuffer.c */, - 021FF3962A4A764500A63B55 /* FNA3D_Memory.c */, - 7BF94B99275C042200050413 /* FNA3D_Driver_Vulkan.c */, 7BC01C132B43490100941563 /* FNA3D_Driver_OpenGL.c */, 7BF8206C2445254300736AB0 /* FNA3D_Image.c */, 7BF8206E2445254300736AB0 /* FNA3D_PipelineCache.c */, @@ -241,7 +221,6 @@ 7B1CDDA72190C52900175C7B /* Public Headers */ = { isa = PBXGroup; children = ( - 02FD608D2A7B226300E1D7A5 /* FNA3D_CommandBuffer.h */, 7BF820652445251D00736AB0 /* FNA3D_SysRenderer.h */, 7BF820662445251D00736AB0 /* FNA3D_Image.h */, 7BF820672445251D00736AB0 /* FNA3D.h */, @@ -273,7 +252,6 @@ 7BC01C052B4348EC00941563 /* mojoshader_profile_glsl.c */, 7BC01C032B4348CD00941563 /* mojoshader_opengl.c */, 7BF94B9F275C046100050413 /* mojoshader_profile_spirv.c */, - 7BF94B9C275C044E00050413 /* mojoshader_vulkan.c */, 7B8B6CC6244526A7001C08D6 /* mojoshader_profile_common.c */, 7B8B6CB824452690001C08D6 /* mojoshader_common.c */, 7B8B6CBB24452690001C08D6 /* mojoshader_effects.c */, @@ -483,14 +461,10 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 021FF3972A4A764500A63B55 /* FNA3D_Memory.c in Sources */, 7BF94BA0275C046100050413 /* mojoshader_profile_spirv.c in Sources */, 7B8B6CC9244526A7001C08D6 /* mojoshader_profile_common.c in Sources */, - 7BF94B9A275C042200050413 /* FNA3D_Driver_Vulkan.c in Sources */, 7B8B6CC224452690001C08D6 /* mojoshader.c in Sources */, 7B8B6CC424452690001C08D6 /* mojoshader_effects.c in Sources */, - 02FD608F2A7B227300E1D7A5 /* FNA3D_CommandBuffer.c in Sources */, - 7BF94B9D275C044E00050413 /* mojoshader_vulkan.c in Sources */, 7BF820702445254300736AB0 /* FNA3D.c in Sources */, 7B8B6CBE24452690001C08D6 /* mojoshader_common.c in Sources */, 7BF8207C2445254300736AB0 /* FNA3D_PipelineCache.c in Sources */, @@ -502,14 +476,10 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 021FF3982A4A764500A63B55 /* FNA3D_Memory.c in Sources */, 7BF94BA1275C046100050413 /* mojoshader_profile_spirv.c in Sources */, 7B8B6CCA244526A7001C08D6 /* mojoshader_profile_common.c in Sources */, - 7BF94B9B275C042200050413 /* FNA3D_Driver_Vulkan.c in Sources */, 7B8B6CC324452690001C08D6 /* mojoshader.c in Sources */, 7B8B6CC524452690001C08D6 /* mojoshader_effects.c in Sources */, - 02FD60902A7B227300E1D7A5 /* FNA3D_CommandBuffer.c in Sources */, - 7BF94B9E275C044E00050413 /* mojoshader_vulkan.c in Sources */, 7BF820712445254300736AB0 /* FNA3D.c in Sources */, 7B8B6CBF24452690001C08D6 /* mojoshader_common.c in Sources */, 7BF8207D2445254300736AB0 /* FNA3D_PipelineCache.c in Sources */, @@ -523,18 +493,14 @@ files = ( 7BC01C0C2B4348F300941563 /* mojoshader_effects.c in Sources */, 7BC01C0B2B4348F300941563 /* mojoshader_profile_common.c in Sources */, - 7BC01C0E2B4348F700941563 /* FNA3D_CommandBuffer.c in Sources */, 7BC01C112B4348F700941563 /* FNA3D.c in Sources */, 7BC01C0F2B4348F700941563 /* FNA3D_Image.c in Sources */, - 7BC01C122B4348F700941563 /* FNA3D_Memory.c in Sources */, 7BC01C042B4348CD00941563 /* mojoshader_opengl.c in Sources */, 7BC01C082B4348F300941563 /* mojoshader.c in Sources */, - 7BC01C0D2B4348F700941563 /* FNA3D_Driver_Vulkan.c in Sources */, 7BC01C142B43490100941563 /* FNA3D_Driver_OpenGL.c in Sources */, 7BC01C102B4348F700941563 /* FNA3D_PipelineCache.c in Sources */, 7BC01C062B4348ED00941563 /* mojoshader_profile_glsl.c in Sources */, 7BC01C072B4348F300941563 /* mojoshader_profile_spirv.c in Sources */, - 7BC01C0A2B4348F300941563 /* mojoshader_vulkan.c in Sources */, 7BC01C092B4348F300941563 /* mojoshader_common.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -584,7 +550,6 @@ GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( - FNA3D_DRIVER_VULKAN, MOJOSHADER_NO_VERSION_INCLUDE, MOJOSHADER_USE_SDL_STDLIB, MOJOSHADER_EFFECT_SUPPORT, @@ -610,7 +575,6 @@ HEADER_SEARCH_PATHS = ( ../../SDL2/include, ../mojoshader/, - "../Vulkan-Headers/include", ); IPHONEOS_DEPLOYMENT_TARGET = 11.0; MACOSX_DEPLOYMENT_TARGET = 10.9; @@ -661,7 +625,6 @@ GCC_C_LANGUAGE_STANDARD = gnu11; GCC_NO_COMMON_BLOCKS = YES; GCC_PREPROCESSOR_DEFINITIONS = ( - FNA3D_DRIVER_VULKAN, MOJOSHADER_NO_VERSION_INCLUDE, MOJOSHADER_USE_SDL_STDLIB, MOJOSHADER_EFFECT_SUPPORT, @@ -687,7 +650,6 @@ HEADER_SEARCH_PATHS = ( ../../SDL2/include, ../mojoshader/, - "../Vulkan-Headers/include", ); IPHONEOS_DEPLOYMENT_TARGET = 11.0; MACOSX_DEPLOYMENT_TARGET = 10.9; diff --git a/include/FNA3D_SysRenderer.h b/include/FNA3D_SysRenderer.h index cd5c6ec1..33566ef2 100644 --- a/include/FNA3D_SysRenderer.h +++ b/include/FNA3D_SysRenderer.h @@ -44,7 +44,7 @@ extern "C" { typedef enum FNA3D_SysRendererTypeEXT { FNA3D_RENDERER_TYPE_OPENGL_EXT, - FNA3D_RENDERER_TYPE_VULKAN_EXT, + FNA3D_RENDERER_TYPE_VULKAN_EXT, /* REMOVED, DO NOT USE */ FNA3D_RENDERER_TYPE_D3D11_EXT, FNA3D_RENDERER_TYPE_METAL_EXT, /* REMOVED, DO NOT USE */ FNA3D_RENDERER_TYPE_SDL_GPU_EXT, diff --git a/src/FNA3D_CommandBuffer.c b/src/FNA3D_CommandBuffer.c deleted file mode 100644 index 9bd35586..00000000 --- a/src/FNA3D_CommandBuffer.c +++ /dev/null @@ -1,879 +0,0 @@ -/* FNA3D - 3D Graphics Library for FNA - * - * Copyright (c) 2020-2024 Ethan Lee - * - * This software is provided 'as-is', without any express or implied warranty. - * In no event will the authors be held liable for any damages arising from - * the use of this software. - * - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you must not - * claim that you wrote the original software. If you use this software in a - * product, an acknowledgment in the product documentation would be - * appreciated but is not required. - * - * 2. Altered source versions must be plainly marked as such, and must not be - * misrepresented as being the original software. - * - * 3. This notice may not be removed or altered from any source distribution. - * - * Ethan "flibitijibibo" Lee - * - */ - -#include "FNA3D_CommandBuffer.h" - -#ifdef USE_SDL3 -#include -#else -#include -#define SDL_Mutex SDL_mutex -#endif - -#define STARTING_TRANSFER_BUFFER_SIZE 8000000 /* 8MB */ -#define FAST_TRANSFER_SIZE 64000000 /* 64MB */ - -typedef struct FNA3D_TransferBufferPool -{ - FNA3D_TransferBuffer *fastTransferBuffer; - uint8_t fastTransferBufferAvailable; - - FNA3D_TransferBuffer **availableSlowTransferBuffers; - uint32_t availableSlowTransferBufferCount; - uint32_t availableSlowTransferBufferCapacity; -} FNA3D_TransferBufferPool; - -/* Command buffers have various resources associated with them - * that can be freed after the command buffer is fully processed. - */ -typedef struct FNA3D_CommandBufferContainer -{ - FNA3D_CommandBuffer *handle; - - FNA3D_TransferBuffer **transferBuffers; - uint32_t transferBufferCount; - uint32_t transferBufferCapacity; - - FNA3D_BufferHandle **boundBuffers; - uint32_t boundBufferCount; - uint32_t boundBufferCapacity; - - FNA3D_Renderbuffer **renderbuffersToDestroy; - uint32_t renderbuffersToDestroyCount; - uint32_t renderbuffersToDestroyCapacity; - - FNA3D_BufferHandle **buffersToDestroy; - uint32_t buffersToDestroyCount; - uint32_t buffersToDestroyCapacity; - - FNA3D_Effect **effectsToDestroy; - uint32_t effectsToDestroyCount; - uint32_t effectsToDestroyCapacity; - - FNA3D_Texture **texturesToDestroy; - uint32_t texturesToDestroyCount; - uint32_t texturesToDestroyCapacity; -} FNA3D_CommandBufferContainer; - -struct FNA3D_CommandBufferManager -{ - FNA3D_CommandBufferDriver driver; - - FNA3D_CommandBufferContainer **inactiveCommandBufferContainers; - uint32_t inactiveCommandBufferContainerCount; - uint32_t inactiveCommandBufferContainerCapacity; - - FNA3D_CommandBufferContainer **submittedCommandBufferContainers; - uint32_t submittedCommandBufferContainerCount; - uint32_t submittedCommandBufferContainerCapacity; - - uint32_t currentCommandCount; - FNA3D_CommandBufferContainer *currentCommandBufferContainer; - - /* Special command buffer for performing defrag copies */ - FNA3D_CommandBufferContainer *defragCommandBufferContainer; - - FNA3D_TransferBufferPool transferBufferPool; - - SDL_Mutex *commandLock; - SDL_Mutex *transferLock; -}; - -static FNA3D_CommandBufferContainer* FNA3D_INTERNAL_CreateCommandBufferContainer( - FNA3D_CommandBufferManager *manager, - uint8_t fenceSignaled -) { - FNA3D_CommandBufferContainer *result = (FNA3D_CommandBufferContainer*) SDL_malloc( - sizeof(FNA3D_CommandBufferContainer) - ); - - result->handle = manager->driver.AllocCommandBuffer( - manager->driver.driverData, - fenceSignaled - ); - - /* Transfer buffer tracking */ - - result->transferBufferCapacity = 0; - result->transferBufferCount = 0; - result->transferBuffers = NULL; - - /* Bound buffer tracking */ - - result->boundBufferCapacity = 4; - result->boundBufferCount = 0; - result->boundBuffers = (FNA3D_BufferHandle**) SDL_malloc( - result->boundBufferCapacity * sizeof(FNA3D_BufferHandle*) - ); - - /* Destroyed resources tracking */ - - result->renderbuffersToDestroyCapacity = 16; - result->renderbuffersToDestroyCount = 0; - - result->renderbuffersToDestroy = (FNA3D_Renderbuffer**) SDL_malloc( - sizeof(FNA3D_Renderbuffer*) * - result->renderbuffersToDestroyCapacity - ); - - result->buffersToDestroyCapacity = 16; - result->buffersToDestroyCount = 0; - - result->buffersToDestroy = (FNA3D_BufferHandle**) SDL_malloc( - sizeof(FNA3D_BufferHandle*) * - result->buffersToDestroyCapacity - ); - - result->effectsToDestroyCapacity = 16; - result->effectsToDestroyCount = 0; - - result->effectsToDestroy = (FNA3D_Effect**) SDL_malloc( - sizeof(FNA3D_Effect*) * - result->effectsToDestroyCapacity - ); - - result->texturesToDestroyCapacity = 16; - result->texturesToDestroyCount = 0; - - result->texturesToDestroy = (FNA3D_Texture**) SDL_malloc( - sizeof(FNA3D_Texture*) * - result->texturesToDestroyCapacity - ); - - return result; -} - -static void FNA3D_CommandBuffer_CleanContainer( - FNA3D_CommandBufferManager *manager, - FNA3D_CommandBufferContainer *container -) { - FNA3D_TransferBuffer* transferBuffer; - uint32_t i; - - /* Reset bound buffers */ - for (i = 0; i < container->boundBufferCount; i += 1) - { - if (container->boundBuffers[i] != NULL) - { - manager->driver.DecBufferRef( - manager->driver.driverData, - container->boundBuffers[i] - ); - } - } - container->boundBufferCount = 0; - - /* Destroy resources marked for destruction */ - - for (i = 0; i < container->renderbuffersToDestroyCount; i += 1) - { - manager->driver.DestroyRenderbuffer( - manager->driver.driverData, - container->renderbuffersToDestroy[i] - ); - } - container->renderbuffersToDestroyCount = 0; - - for (i = 0; i < container->buffersToDestroyCount; i += 1) - { - manager->driver.DestroyBuffer( - manager->driver.driverData, - container->buffersToDestroy[i] - ); - } - container->buffersToDestroyCount = 0; - - for (i = 0; i < container->effectsToDestroyCount; i += 1) - { - manager->driver.DestroyEffect( - manager->driver.driverData, - container->effectsToDestroy[i] - ); - } - container->effectsToDestroyCount = 0; - - for (i = 0; i < container->texturesToDestroyCount; i += 1) - { - manager->driver.DestroyTexture( - manager->driver.driverData, - container->texturesToDestroy[i] - ); - } - container->texturesToDestroyCount = 0; - - /* Return the transfer buffers to the pool */ - for (i = 0; i < container->transferBufferCount; i += 1) - { - transferBuffer = container->transferBuffers[i]; - transferBuffer->offset = 0; - - if (transferBuffer == manager->transferBufferPool.fastTransferBuffer) - { - manager->transferBufferPool.fastTransferBufferAvailable = 1; - } - else - { - if (manager->transferBufferPool.availableSlowTransferBufferCount == manager->transferBufferPool.availableSlowTransferBufferCapacity) - { - manager->transferBufferPool.availableSlowTransferBufferCapacity += 1; - manager->transferBufferPool.availableSlowTransferBuffers = SDL_realloc( - manager->transferBufferPool.availableSlowTransferBuffers, - manager->transferBufferPool.availableSlowTransferBufferCapacity * sizeof(FNA3D_TransferBuffer*) - ); - } - - manager->transferBufferPool.availableSlowTransferBuffers[manager->transferBufferPool.availableSlowTransferBufferCount] = transferBuffer; - manager->transferBufferPool.availableSlowTransferBufferCount += 1; - } - } - container->transferBufferCount = 0; - - SDL_LockMutex(manager->commandLock); - - manager->driver.Reset( - manager->driver.driverData, - container->handle - ); - - SDL_UnlockMutex(manager->commandLock); - - /* Remove this command buffer from the submitted list */ - for (i = 0; i < manager->submittedCommandBufferContainerCount; i += 1) - { - if (manager->submittedCommandBufferContainers[i] == container) - { - manager->submittedCommandBufferContainers[i] = manager->submittedCommandBufferContainers[manager->submittedCommandBufferContainerCount - 1]; - manager->submittedCommandBufferContainerCount -= 1; - break; - } - } - - /* Add this command buffer to the inactive list */ - if (manager->inactiveCommandBufferContainerCount + 1 > manager->inactiveCommandBufferContainerCapacity) - { - manager->inactiveCommandBufferContainerCapacity = manager->inactiveCommandBufferContainerCount + 1; - manager->inactiveCommandBufferContainers = SDL_realloc( - manager->inactiveCommandBufferContainers, - manager->inactiveCommandBufferContainerCapacity * sizeof(FNA3D_CommandBufferContainer*) - ); - } - - manager->inactiveCommandBufferContainers[manager->inactiveCommandBufferContainerCount] = container; - manager->inactiveCommandBufferContainerCount += 1; -} - -/* Public Functions */ - -FNA3D_CommandBufferManager* FNA3D_CreateCommandBufferManager( - FNA3D_CommandBufferDriver *driver -) { - FNA3D_CommandBufferManager *manager = (FNA3D_CommandBufferManager*) SDL_malloc( - sizeof(FNA3D_CommandBufferManager) - ); - SDL_memcpy(&manager->driver, driver, sizeof(FNA3D_CommandBufferDriver)); - - manager->commandLock = SDL_CreateMutex(); - manager->transferLock = SDL_CreateMutex(); - - manager->inactiveCommandBufferContainerCapacity = 1; - manager->inactiveCommandBufferContainers = (FNA3D_CommandBufferContainer**) SDL_malloc( - sizeof(FNA3D_CommandBufferContainer*) - ); - manager->inactiveCommandBufferContainerCount = 0; - manager->currentCommandCount = 0; - - manager->submittedCommandBufferContainerCapacity = 1; - manager->submittedCommandBufferContainers = (FNA3D_CommandBufferContainer**) SDL_malloc( - sizeof(FNA3D_CommandBufferContainer*) - ); - manager->submittedCommandBufferContainerCount = 0; - - manager->defragCommandBufferContainer = FNA3D_INTERNAL_CreateCommandBufferContainer( - manager, - 1 - ); - - /* - * Initialize buffer space - */ - - manager->transferBufferPool.fastTransferBuffer = (FNA3D_TransferBuffer*) SDL_malloc( - sizeof(FNA3D_TransferBuffer) - ); - manager->transferBufferPool.fastTransferBuffer->offset = 0; - manager->transferBufferPool.fastTransferBuffer->buffer = manager->driver.CreateTransferBuffer( - manager->driver.driverData, - FAST_TRANSFER_SIZE, - 1 - ); - manager->transferBufferPool.fastTransferBufferAvailable = 1; - - manager->transferBufferPool.availableSlowTransferBufferCapacity = 4; - manager->transferBufferPool.availableSlowTransferBufferCount = 0; - manager->transferBufferPool.availableSlowTransferBuffers = (FNA3D_TransferBuffer**) SDL_malloc( - manager->transferBufferPool.availableSlowTransferBufferCapacity * sizeof(FNA3D_TransferBuffer*) - ); - - return manager; -} - -void FNA3D_DestroyCommandBufferManager( - FNA3D_CommandBufferManager *manager -) { - FNA3D_CommandBufferContainer *commandBufferContainer; - uint32_t i; - - if (manager->inactiveCommandBufferContainerCount + 1 > manager->inactiveCommandBufferContainerCapacity) - { - manager->inactiveCommandBufferContainerCapacity = manager->inactiveCommandBufferContainerCount + 1; - manager->inactiveCommandBufferContainers = SDL_realloc( - manager->inactiveCommandBufferContainers, - manager->inactiveCommandBufferContainerCapacity * sizeof(FNA3D_CommandBufferContainer*) - ); - } - - manager->inactiveCommandBufferContainers[manager->inactiveCommandBufferContainerCount] = manager->currentCommandBufferContainer; - manager->inactiveCommandBufferContainerCount += 1; - - manager->inactiveCommandBufferContainerCapacity += 1; - manager->inactiveCommandBufferContainers = SDL_realloc( - manager->inactiveCommandBufferContainers, - sizeof(FNA3D_CommandBufferContainer*) * manager->inactiveCommandBufferContainerCapacity - ); - - manager->inactiveCommandBufferContainers[manager->inactiveCommandBufferContainerCount] = manager->defragCommandBufferContainer; - manager->inactiveCommandBufferContainerCount += 1; - - for (i = 0; i < manager->inactiveCommandBufferContainerCount; i += 1) - { - commandBufferContainer = manager->inactiveCommandBufferContainers[i]; - - manager->driver.FreeCommandBuffer( - manager->driver.driverData, - commandBufferContainer->handle - ); - - SDL_free(commandBufferContainer->transferBuffers); - SDL_free(commandBufferContainer->boundBuffers); - - SDL_free(commandBufferContainer->renderbuffersToDestroy); - SDL_free(commandBufferContainer->buffersToDestroy); - SDL_free(commandBufferContainer->effectsToDestroy); - SDL_free(commandBufferContainer->texturesToDestroy); - - SDL_free(commandBufferContainer); - } - - manager->driver.DestroyBuffer( - manager->driver.driverData, - manager->transferBufferPool.fastTransferBuffer->buffer - ); - SDL_free(manager->transferBufferPool.fastTransferBuffer); - - for (i = 0; i < manager->transferBufferPool.availableSlowTransferBufferCount; i += 1) - { - manager->driver.DestroyBuffer( - manager->driver.driverData, - manager->transferBufferPool.availableSlowTransferBuffers[i]->buffer - ); - - SDL_free(manager->transferBufferPool.availableSlowTransferBuffers[i]); - } - SDL_free(manager->transferBufferPool.availableSlowTransferBuffers); - - SDL_DestroyMutex(manager->commandLock); - SDL_DestroyMutex(manager->transferLock); - - SDL_free(manager->inactiveCommandBufferContainers); - SDL_free(manager->submittedCommandBufferContainers); - SDL_free(manager); -} - -void FNA3D_CommandBuffer_BeginRecording(FNA3D_CommandBufferManager *manager) -{ - SDL_LockMutex(manager->commandLock); - - /* If we are out of unused command buffers, allocate some more */ - if (manager->inactiveCommandBufferContainerCount == 0) - { - manager->inactiveCommandBufferContainers[manager->inactiveCommandBufferContainerCount] = - FNA3D_INTERNAL_CreateCommandBufferContainer(manager, 0); - - manager->inactiveCommandBufferContainerCount += 1; - } - - manager->currentCommandBufferContainer = - manager->inactiveCommandBufferContainers[manager->inactiveCommandBufferContainerCount - 1]; - - manager->inactiveCommandBufferContainerCount -= 1; - - manager->driver.BeginRecording( - manager->driver.driverData, - manager->currentCommandBufferContainer->handle - ); - - SDL_UnlockMutex(manager->commandLock); -} - -void FNA3D_CommandBuffer_EndRecording(FNA3D_CommandBufferManager *manager) -{ - SDL_LockMutex(manager->commandLock); - - manager->driver.EndRecording( - manager->driver.driverData, - manager->currentCommandBufferContainer->handle - ); - - SDL_UnlockMutex(manager->commandLock); -} - -void FNA3D_CommandBuffer_Finish(FNA3D_CommandBufferManager *manager) -{ - int32_t i; - FNA3D_CommandBuffer **commandBuffers = SDL_stack_alloc( - FNA3D_CommandBuffer*, - manager->submittedCommandBufferContainerCount - ); - - for (i = 0; i < manager->submittedCommandBufferContainerCount; i += 1) - { - commandBuffers[i] = manager->submittedCommandBufferContainers[i]->handle; - } - - manager->driver.WaitForFences( - manager->driver.driverData, - commandBuffers, - manager->submittedCommandBufferContainerCount - ); - - for (i = manager->submittedCommandBufferContainerCount - 1; i >= 0; i -= 1) - { - FNA3D_CommandBuffer_CleanContainer( - manager, - manager->submittedCommandBufferContainers[i] - ); - } - - SDL_stack_free(commandBuffers); -} - -void FNA3D_CommandBuffer_LockForRendering(FNA3D_CommandBufferManager *manager) -{ - SDL_LockMutex(manager->commandLock); - if (manager->currentCommandBufferContainer == NULL) - { - FNA3D_CommandBuffer_BeginRecording(manager); - } -} - -void FNA3D_CommandBuffer_UnlockFromRendering(FNA3D_CommandBufferManager *manager) -{ - SDL_UnlockMutex(manager->commandLock); -} - -void FNA3D_CommandBuffer_LockForDefrag(FNA3D_CommandBufferManager *manager) -{ - SDL_LockMutex(manager->commandLock); - - /* FIXME: This is a kludge! */ - manager->currentCommandBufferContainer = manager->defragCommandBufferContainer; -} - -void FNA3D_CommandBuffer_UnlockFromDefrag(FNA3D_CommandBufferManager *manager) -{ - /* FIXME: This is a kludge! */ - manager->currentCommandBufferContainer = NULL; - - SDL_UnlockMutex(manager->commandLock); -} - -void FNA3D_CommandBuffer_LockForTransfer(FNA3D_CommandBufferManager *manager) -{ - SDL_LockMutex(manager->transferLock); -} - -void FNA3D_CommandBuffer_UnlockFromTransfer(FNA3D_CommandBufferManager *manager) -{ - SDL_UnlockMutex(manager->transferLock); -} - -void FNA3D_CommandBuffer_LockForSubmit(FNA3D_CommandBufferManager *manager) -{ - SDL_LockMutex(manager->commandLock); - SDL_LockMutex(manager->transferLock); -} - -void FNA3D_CommandBuffer_UnlockFromSubmit(FNA3D_CommandBufferManager *manager) -{ - SDL_UnlockMutex(manager->commandLock); - SDL_UnlockMutex(manager->transferLock); -} - -void FNA3D_CommandBuffer_AddDisposeTexture( - FNA3D_CommandBufferManager *manager, - FNA3D_Texture *texture -) { - FNA3D_CommandBufferContainer *container; - - SDL_LockMutex(manager->commandLock); - - container = manager->currentCommandBufferContainer; - - if (container->texturesToDestroyCount + 1 >= container->texturesToDestroyCapacity) - { - container->texturesToDestroyCapacity *= 2; - - container->texturesToDestroy = SDL_realloc( - container->texturesToDestroy, - sizeof(FNA3D_Texture*) * container->texturesToDestroyCapacity - ); - } - container->texturesToDestroy[container->texturesToDestroyCount] = texture; - container->texturesToDestroyCount += 1; - - SDL_UnlockMutex(manager->commandLock); -} - -void FNA3D_CommandBuffer_AddDisposeRenderbuffer( - FNA3D_CommandBufferManager *manager, - FNA3D_Renderbuffer *renderbuffer -) { - FNA3D_CommandBufferContainer *container; - - SDL_LockMutex(manager->commandLock); - - container = manager->currentCommandBufferContainer; - - if (container->renderbuffersToDestroyCount + 1 >= container->renderbuffersToDestroyCapacity) - { - container->renderbuffersToDestroyCapacity *= 2; - - container->renderbuffersToDestroy = SDL_realloc( - container->renderbuffersToDestroy, - sizeof(FNA3D_Renderbuffer*) * container->renderbuffersToDestroyCapacity - ); - } - container->renderbuffersToDestroy[container->renderbuffersToDestroyCount] = renderbuffer; - container->renderbuffersToDestroyCount += 1; - - SDL_UnlockMutex(manager->commandLock); -} - -void FNA3D_CommandBuffer_AddDisposeEffect( - FNA3D_CommandBufferManager *manager, - FNA3D_Effect *effect -) { - FNA3D_CommandBufferContainer *container; - - SDL_LockMutex(manager->commandLock); - - container = manager->currentCommandBufferContainer; - - if (container->effectsToDestroyCount + 1 >= container->effectsToDestroyCapacity) - { - container->effectsToDestroyCapacity *= 2; - - container->effectsToDestroy = SDL_realloc( - container->effectsToDestroy, - sizeof(FNA3D_Effect*) * container->effectsToDestroyCapacity - ); - } - container->effectsToDestroy[container->effectsToDestroyCount] = effect; - container->effectsToDestroyCount += 1; - - SDL_UnlockMutex(manager->commandLock); -} - -void FNA3D_CommandBuffer_AddDisposeBuffers( - FNA3D_CommandBufferManager *manager, - FNA3D_BufferHandle **handles, - size_t handleCount -) { - FNA3D_CommandBufferContainer *container; - size_t i; - - /* Queue buffer for destruction */ - SDL_LockMutex(manager->commandLock); - container = manager->currentCommandBufferContainer; - - /* FIXME: This is a lazy way of adding each buffer, do a memcpy instead */ - for (i = 0; i < handleCount; i += 1) - { - if (container->buffersToDestroyCount + 1 >= container->buffersToDestroyCapacity) - { - container->buffersToDestroyCapacity *= 2; - - container->buffersToDestroy = SDL_realloc( - container->buffersToDestroy, - sizeof(FNA3D_BufferHandle*) * container->buffersToDestroyCapacity - ); - } - - container->buffersToDestroy[ - container->buffersToDestroyCount - ] = handles[i]; - container->buffersToDestroyCount += 1; - } - SDL_UnlockMutex(manager->commandLock); -} - -uint8_t FNA3D_CommandBuffer_PerformCleanups(FNA3D_CommandBufferManager *manager) -{ - uint8_t result = 0; - int32_t i; - for (i = manager->submittedCommandBufferContainerCount - 1; i >= 0; i -= 1) - { - if (manager->driver.QueryFence( - manager->driver.driverData, - manager->submittedCommandBufferContainers[i]->handle - )) { - FNA3D_CommandBuffer_CleanContainer( - manager, - manager->submittedCommandBufferContainers[i] - ); - - result = 1; - } - } - - return result; -} - -void FNA3D_CommandBuffer_SubmitCurrent(FNA3D_CommandBufferManager *manager) -{ - if (manager->submittedCommandBufferContainerCount >= manager->submittedCommandBufferContainerCapacity) - { - manager->submittedCommandBufferContainerCapacity *= 2; - manager->submittedCommandBufferContainers = SDL_realloc( - manager->submittedCommandBufferContainers, - manager->submittedCommandBufferContainerCapacity * sizeof(FNA3D_CommandBufferContainer*) - ); - } - - manager->submittedCommandBufferContainers[manager->submittedCommandBufferContainerCount] = - manager->currentCommandBufferContainer; - manager->submittedCommandBufferContainerCount += 1; - manager->currentCommandBufferContainer = NULL; -} - -FNA3D_CommandBuffer* FNA3D_CommandBuffer_GetCurrent(FNA3D_CommandBufferManager *manager) -{ - return manager->currentCommandBufferContainer->handle; -} - -FNA3D_CommandBuffer* FNA3D_CommandBuffer_GetDefragBuffer(FNA3D_CommandBufferManager *manager) -{ - return manager->defragCommandBufferContainer->handle; -} - -void FNA3D_CommandBuffer_MarkBufferAsBound( - FNA3D_CommandBufferManager *manager, - FNA3D_BufferHandle *buffer -) { - uint32_t i; - - for (i = 0; i < manager->currentCommandBufferContainer->boundBufferCount; i += 1) - { - if (buffer == manager->currentCommandBufferContainer->boundBuffers[i]) - { - /* Buffer is already referenced, nothing to do */ - return; - } - } - - manager->driver.IncBufferRef( - manager->driver.driverData, - buffer - ); - - if (manager->currentCommandBufferContainer->boundBufferCount >= manager->currentCommandBufferContainer->boundBufferCapacity) - { - manager->currentCommandBufferContainer->boundBufferCapacity *= 2; - manager->currentCommandBufferContainer->boundBuffers = SDL_realloc( - manager->currentCommandBufferContainer->boundBuffers, - manager->currentCommandBufferContainer->boundBufferCapacity * sizeof(FNA3D_BufferHandle*) - ); - } - - manager->currentCommandBufferContainer->boundBuffers[manager->currentCommandBufferContainer->boundBufferCount] = buffer; - manager->currentCommandBufferContainer->boundBufferCount += 1; -} - -FNA3D_TransferBuffer* FNA3D_CommandBuffer_AcquireTransferBuffer( - FNA3D_CommandBufferManager *manager, - size_t requiredSize, - size_t alignment -) { - FNA3D_TransferBuffer *transferBuffer; - size_t parentBufferSize; - uint32_t i; - size_t size; - size_t offset; - FNA3D_CommandBufferContainer *commandBufferContainer = - manager->currentCommandBufferContainer; - - /* Search the command buffer's current transfer buffers */ - - for (i = 0; i < commandBufferContainer->transferBufferCount; i += 1) - { - transferBuffer = commandBufferContainer->transferBuffers[i]; - parentBufferSize = manager->driver.GetBufferSize( - manager->driver.driverData, - transferBuffer->buffer - ); - offset = transferBuffer->offset + alignment - (transferBuffer->offset % alignment); - - if (offset + requiredSize <= parentBufferSize) - { - transferBuffer->offset = offset; - return transferBuffer; - } - } - - /* Nothing fits so let's get a transfer buffer from the pool */ - - if (commandBufferContainer->transferBufferCount == commandBufferContainer->transferBufferCapacity) - { - commandBufferContainer->transferBufferCapacity += 1; - commandBufferContainer->transferBuffers = SDL_realloc( - commandBufferContainer->transferBuffers, - commandBufferContainer->transferBufferCapacity * sizeof(FNA3D_TransferBuffer*) - ); - } - - /* Is the fast transfer buffer available? */ - if ( manager->transferBufferPool.fastTransferBufferAvailable && - requiredSize < FAST_TRANSFER_SIZE ) - { - transferBuffer = manager->transferBufferPool.fastTransferBuffer; - manager->transferBufferPool.fastTransferBufferAvailable = 0; - - commandBufferContainer->transferBuffers[commandBufferContainer->transferBufferCount] = transferBuffer; - commandBufferContainer->transferBufferCount += 1; - - /* If the fast transfer buffer is available, the offset is always zero */ - return transferBuffer; - } - - /* Nope, let's get a slow buffer */ - for (i = 0; i < manager->transferBufferPool.availableSlowTransferBufferCount; i += 1) - { - transferBuffer = manager->transferBufferPool.availableSlowTransferBuffers[i]; - parentBufferSize = manager->driver.GetBufferSize( - manager->driver.driverData, - transferBuffer->buffer - ); - offset = transferBuffer->offset + alignment - (transferBuffer->offset % alignment); - - if (offset + requiredSize <= parentBufferSize) - { - commandBufferContainer->transferBuffers[commandBufferContainer->transferBufferCount] = transferBuffer; - commandBufferContainer->transferBufferCount += 1; - - manager->transferBufferPool.availableSlowTransferBuffers[i] = manager->transferBufferPool.availableSlowTransferBuffers[manager->transferBufferPool.availableSlowTransferBufferCount - 1]; - manager->transferBufferPool.availableSlowTransferBufferCount -= 1; - - transferBuffer->offset = offset; - return transferBuffer; - } - } - - /* Nothing fits still, so let's create a new transfer buffer */ - - size = STARTING_TRANSFER_BUFFER_SIZE; - - while (size < requiredSize) - { - size *= 2; - } - - transferBuffer = SDL_malloc(sizeof(FNA3D_TransferBuffer)); - transferBuffer->offset = 0; - transferBuffer->buffer = manager->driver.CreateTransferBuffer( - manager->driver.driverData, - size, - 0 - ); - - if (transferBuffer->buffer == NULL) - { - FNA3D_LogError("Failed to allocate transfer buffer!"); - return NULL; - } - - if (commandBufferContainer->transferBufferCount == commandBufferContainer->transferBufferCapacity) - { - commandBufferContainer->transferBufferCapacity += 1; - commandBufferContainer->transferBuffers = SDL_realloc( - commandBufferContainer->transferBuffers, - commandBufferContainer->transferBufferCapacity * sizeof(FNA3D_TransferBuffer*) - ); - } - - commandBufferContainer->transferBuffers[commandBufferContainer->transferBufferCount] = transferBuffer; - commandBufferContainer->transferBufferCount += 1; - - return transferBuffer; -} - -void FNA3D_CommandBuffer_ClearDestroyedBuffer( - FNA3D_CommandBufferManager *manager, - FNA3D_BufferHandle *buffer -) { - uint32_t i, j; - - /* Don't unbind destroyed buffers! */ - for (i = 0; i < manager->submittedCommandBufferContainerCount; i += 1) - { - for (j = 0; j < manager->submittedCommandBufferContainers[i]->boundBufferCount; j += 1) - { - if (buffer == manager->submittedCommandBufferContainers[i]->boundBuffers[j]) - { - manager->submittedCommandBufferContainers[i]->boundBuffers[j] = NULL; - } - } - } -} - -void FNA3D_CommandBuffer_ForEachSubmittedBuffer( - FNA3D_CommandBufferManager *manager, - void (*callback)( - FNA3D_Renderer *driverData, - FNA3D_CommandBuffer *handle, - void* callbackData - ), - void* callbackData -) { - uint32_t i; - for (i = 0; i < manager->submittedCommandBufferContainerCount; i += 1) - { - callback( - manager->driver.driverData, - manager->submittedCommandBufferContainers[i]->handle, - callbackData - ); - } -} diff --git a/src/FNA3D_CommandBuffer.h b/src/FNA3D_CommandBuffer.h deleted file mode 100644 index a7aae42e..00000000 --- a/src/FNA3D_CommandBuffer.h +++ /dev/null @@ -1,220 +0,0 @@ -/* FNA3D - 3D Graphics Library for FNA - * - * Copyright (c) 2020-2024 Ethan Lee - * - * This software is provided 'as-is', without any express or implied warranty. - * In no event will the authors be held liable for any damages arising from - * the use of this software. - * - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you must not - * claim that you wrote the original software. If you use this software in a - * product, an acknowledgment in the product documentation would be - * appreciated but is not required. - * - * 2. Altered source versions must be plainly marked as such, and must not be - * misrepresented as being the original software. - * - * 3. This notice may not be removed or altered from any source distribution. - * - * Ethan "flibitijibibo" Lee - * - */ - -#ifndef FNA3D_COMMANDBUFFER_H -#define FNA3D_COMMANDBUFFER_H - -#include "FNA3D_Driver.h" -#include "FNA3D_Memory.h" - -/* Driver-defined command buffer structures */ - -typedef struct FNA3D_CommandBuffer FNA3D_CommandBuffer; - -/* Renderers will contain a command buffer driver, so we can call back into the - * renderer to do platform-specific things that don't have to do with the - * high-level command buffer management - */ - -typedef struct FNA3D_CommandBufferDriver -{ - FNA3D_CommandBuffer* (*AllocCommandBuffer)( - FNA3D_Renderer *driverData, - uint8_t fenceSignaled - ); - void (*FreeCommandBuffer)( - FNA3D_Renderer *driverData, - FNA3D_CommandBuffer *handle - ); - - void (*BeginRecording)( - FNA3D_Renderer *driverData, - FNA3D_CommandBuffer *handle - ); - void (*EndRecording)( - FNA3D_Renderer *driverData, - FNA3D_CommandBuffer *handle - ); - void (*Reset)( - FNA3D_Renderer *driverData, - FNA3D_CommandBuffer *handle - ); - uint8_t (*QueryFence)( - FNA3D_Renderer *driverData, - FNA3D_CommandBuffer *handle - ); - void (*WaitForFences)( - FNA3D_Renderer *driverData, - FNA3D_CommandBuffer **handles, - size_t handleCount - ); - - FNA3D_BufferHandle* (*CreateTransferBuffer)( - FNA3D_Renderer *driverData, - size_t size, - uint8_t preferDeviceLocal - ); - - void (*IncBufferRef)( - FNA3D_Renderer *renderer, - FNA3D_BufferHandle *handle - ); - void (*DecBufferRef)( - FNA3D_Renderer *renderer, - FNA3D_BufferHandle *handle - ); - size_t (*GetBufferSize)( - FNA3D_Renderer *driverData, - FNA3D_BufferHandle *handle - ); - - void (*DestroyTexture)( - FNA3D_Renderer *driverData, - FNA3D_Texture *texture - ); - void (*DestroyBuffer)( - FNA3D_Renderer *driverData, - FNA3D_BufferHandle *buffer - ); - void (*DestroyRenderbuffer)( - FNA3D_Renderer *driverData, - FNA3D_Renderbuffer *renderbuffer - ); - void (*DestroyEffect)( - FNA3D_Renderer *driverData, - FNA3D_Effect *effect - ); - - FNA3D_Renderer *driverData; -} FNA3D_CommandBufferDriver; - -#define ASSIGN_COMMANDBUFFER_DRIVER_FUNC(func, name) \ - commandBufferDriver.func = name##_CommandBuffer_##func; -#define ASSIGN_COMMANDBUFFER_DRIVER(name) \ - commandBufferDriver.driverData = (FNA3D_Renderer*) renderer; \ - ASSIGN_COMMANDBUFFER_DRIVER_FUNC(AllocCommandBuffer, name) \ - ASSIGN_COMMANDBUFFER_DRIVER_FUNC(FreeCommandBuffer, name) \ - ASSIGN_COMMANDBUFFER_DRIVER_FUNC(BeginRecording, name) \ - ASSIGN_COMMANDBUFFER_DRIVER_FUNC(EndRecording, name) \ - ASSIGN_COMMANDBUFFER_DRIVER_FUNC(Reset, name) \ - ASSIGN_COMMANDBUFFER_DRIVER_FUNC(QueryFence, name) \ - ASSIGN_COMMANDBUFFER_DRIVER_FUNC(WaitForFences, name) \ - ASSIGN_COMMANDBUFFER_DRIVER_FUNC(CreateTransferBuffer, name) \ - ASSIGN_COMMANDBUFFER_DRIVER_FUNC(IncBufferRef, name) \ - ASSIGN_COMMANDBUFFER_DRIVER_FUNC(DecBufferRef, name) \ - ASSIGN_COMMANDBUFFER_DRIVER_FUNC(GetBufferSize, name) \ - ASSIGN_COMMANDBUFFER_DRIVER_FUNC(DestroyTexture, name) \ - ASSIGN_COMMANDBUFFER_DRIVER_FUNC(DestroyBuffer, name) \ - ASSIGN_COMMANDBUFFER_DRIVER_FUNC(DestroyRenderbuffer, name) \ - ASSIGN_COMMANDBUFFER_DRIVER_FUNC(DestroyEffect, name) - -/* - * Command Buffer Interface - */ - -typedef struct FNA3D_CommandBufferManager FNA3D_CommandBufferManager; - -/* Renderers will receive this struct, perform the transfer, then update the - * offset value for future AcquireTransferBuffer calls - */ -typedef struct FNA3D_TransferBuffer -{ - FNA3D_BufferHandle *buffer; - size_t offset; -} FNA3D_TransferBuffer; - -FNA3D_SHAREDINTERNAL FNA3D_CommandBufferManager* FNA3D_CreateCommandBufferManager( - FNA3D_CommandBufferDriver *driver -); -FNA3D_SHAREDINTERNAL void FNA3D_DestroyCommandBufferManager(FNA3D_CommandBufferManager *manager); - -FNA3D_SHAREDINTERNAL void FNA3D_CommandBuffer_BeginRecording(FNA3D_CommandBufferManager *manager); -FNA3D_SHAREDINTERNAL void FNA3D_CommandBuffer_EndRecording(FNA3D_CommandBufferManager *manager); -FNA3D_SHAREDINTERNAL void FNA3D_CommandBuffer_Finish(FNA3D_CommandBufferManager *manager); - -FNA3D_SHAREDINTERNAL void FNA3D_CommandBuffer_LockForRendering(FNA3D_CommandBufferManager *manager); -FNA3D_SHAREDINTERNAL void FNA3D_CommandBuffer_UnlockFromRendering(FNA3D_CommandBufferManager *manager); - -FNA3D_SHAREDINTERNAL void FNA3D_CommandBuffer_LockForDefrag(FNA3D_CommandBufferManager *manager); -FNA3D_SHAREDINTERNAL void FNA3D_CommandBuffer_UnlockFromDefrag(FNA3D_CommandBufferManager *manager); - -FNA3D_SHAREDINTERNAL void FNA3D_CommandBuffer_LockForTransfer(FNA3D_CommandBufferManager *manager); -FNA3D_SHAREDINTERNAL void FNA3D_CommandBuffer_UnlockFromTransfer(FNA3D_CommandBufferManager *manager); - -FNA3D_SHAREDINTERNAL void FNA3D_CommandBuffer_LockForSubmit(FNA3D_CommandBufferManager *manager); -FNA3D_SHAREDINTERNAL void FNA3D_CommandBuffer_UnlockFromSubmit(FNA3D_CommandBufferManager *manager); - -FNA3D_SHAREDINTERNAL void FNA3D_CommandBuffer_AddDisposeTexture( - FNA3D_CommandBufferManager *manager, - FNA3D_Texture *texture -); -FNA3D_SHAREDINTERNAL void FNA3D_CommandBuffer_AddDisposeRenderbuffer( - FNA3D_CommandBufferManager *manager, - FNA3D_Renderbuffer *renderbuffer -); -FNA3D_SHAREDINTERNAL void FNA3D_CommandBuffer_AddDisposeEffect( - FNA3D_CommandBufferManager *manager, - FNA3D_Effect *effect -); -FNA3D_SHAREDINTERNAL void FNA3D_CommandBuffer_AddDisposeBuffers( - FNA3D_CommandBufferManager *manager, - FNA3D_BufferHandle **handles, - size_t handleCount -); - -FNA3D_SHAREDINTERNAL uint8_t FNA3D_CommandBuffer_PerformCleanups(FNA3D_CommandBufferManager *manager); - -FNA3D_SHAREDINTERNAL void FNA3D_CommandBuffer_SubmitCurrent(FNA3D_CommandBufferManager *manager); -FNA3D_SHAREDINTERNAL FNA3D_CommandBuffer* FNA3D_CommandBuffer_GetCurrent(FNA3D_CommandBufferManager *manager); -FNA3D_SHAREDINTERNAL FNA3D_CommandBuffer* FNA3D_CommandBuffer_GetDefragBuffer(FNA3D_CommandBufferManager *manager); - -FNA3D_SHAREDINTERNAL void FNA3D_CommandBuffer_MarkBufferAsBound( - FNA3D_CommandBufferManager *manager, - FNA3D_BufferHandle *buffer -); -FNA3D_SHAREDINTERNAL FNA3D_TransferBuffer* FNA3D_CommandBuffer_AcquireTransferBuffer( - FNA3D_CommandBufferManager *manager, - size_t requiredSize, - size_t alignment -); - -FNA3D_SHAREDINTERNAL void FNA3D_CommandBuffer_ClearDestroyedBuffer( - FNA3D_CommandBufferManager *manager, - FNA3D_BufferHandle *buffer -); - -/* FIXME: This is kind of a kludge -flibit */ -FNA3D_SHAREDINTERNAL void FNA3D_CommandBuffer_ForEachSubmittedBuffer( - FNA3D_CommandBufferManager *manager, - void (*callback)( - FNA3D_Renderer *driverData, - FNA3D_CommandBuffer *handle, - void* callbackData - ), - void* callbackData -); - -#endif /* FNA3D_COMMANDBUFFER_H */ diff --git a/src/FNA3D_Driver.h b/src/FNA3D_Driver.h index f2496330..2c41c4e9 100644 --- a/src/FNA3D_Driver.h +++ b/src/FNA3D_Driver.h @@ -825,11 +825,9 @@ typedef struct FNA3D_Driver ); } FNA3D_Driver; -FNA3D_SHAREDINTERNAL FNA3D_Driver VulkanDriver; FNA3D_SHAREDINTERNAL FNA3D_Driver D3D11Driver; FNA3D_SHAREDINTERNAL FNA3D_Driver OpenGLDriver; FNA3D_SHAREDINTERNAL FNA3D_Driver SDLGPUDriver; -FNA3D_SHAREDINTERNAL FNA3D_Driver GNMXDriver; #endif /* FNA3D_DRIVER_H */ diff --git a/src/FNA3D_Driver_Vulkan.c b/src/FNA3D_Driver_Vulkan.c deleted file mode 100644 index eec47ca5..00000000 --- a/src/FNA3D_Driver_Vulkan.c +++ /dev/null @@ -1,12114 +0,0 @@ -/* FNA3D - 3D Graphics Library for FNA - * - * Copyright (c) 2020-2024 Ethan Lee - * - * This software is provided 'as-is', without any express or implied warranty. - * In no event will the authors be held liable for any damages arising from - * the use of this software. - * - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you must not - * claim that you wrote the original software. If you use this software in a - * product, an acknowledgment in the product documentation would be - * appreciated but is not required. - * - * 2. Altered source versions must be plainly marked as such, and must not be - * misrepresented as being the original software. - * - * 3. This notice may not be removed or altered from any source distribution. - * - * Ethan "flibitijibibo" Lee - * - */ - -#if FNA3D_DRIVER_VULKAN - -/* Needed for VK_KHR_portability_subset */ -#define VK_ENABLE_BETA_EXTENSIONS - -#define VK_NO_PROTOTYPES -#include "vulkan/vulkan.h" - -#include "FNA3D_Driver.h" -#include "FNA3D_Memory.h" -#include "FNA3D_CommandBuffer.h" -#include "FNA3D_PipelineCache.h" - -#ifdef USE_SDL3 -#include -#include - -#undef SDL_FALSE -#define SDL_FALSE false -#else -#include -#include -#define SDL_AtomicInt SDL_atomic_t -#define SDL_Mutex SDL_mutex -#define SDL_IOStream SDL_RWops -#define SDL_IOFromFile SDL_RWFromFile -#define SDL_WriteIO(file, data, size) \ - file->write( \ - file, \ - data, \ - sizeof(uint8_t), \ - size \ - ) -#define SDL_CloseIO(file) file->close(file) -#define SDL_CreateWindow(title, w, h, flags) SDL_CreateWindow(title, 0, 0, w, h, flags) -#define SDL_Vulkan_CreateSurface(windowHandle, instance, callbacks, surface) SDL_Vulkan_CreateSurface(windowHandle, instance, surface) -#define SDL_GetAtomicInt SDL_AtomicGet -#define SDL_SetAtomicInt SDL_AtomicSet -#endif - -#define VULKAN_INTERNAL_clamp(val, min, max) SDL_max(min, SDL_min(val, max)) - -/* Global Vulkan Loader Entry Points */ - -static PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = NULL; - -#define VULKAN_GLOBAL_FUNCTION(name) \ - static PFN_##name name = NULL; -#include "FNA3D_Driver_Vulkan_vkfuncs.h" - -/* Vulkan Extensions */ - -typedef struct VulkanExtensions -{ - /* These extensions are required! */ - - /* Globally supported */ - uint8_t KHR_swapchain; - /* Core since 1.1, needed for negative VkViewport::height */ - uint8_t KHR_maintenance1; - - /* These extensions are optional! */ - - /* Core since 1.2, but requires annoying paperwork to implement */ - uint8_t KHR_driver_properties; - /* EXT, probably not going to be Core */ - uint8_t EXT_vertex_attribute_divisor; - /* Only required for special implementations (i.e. MoltenVK) */ - uint8_t KHR_portability_subset; - /* Vendor-specific extensions */ - uint8_t GGP_frame_token; -} VulkanExtensions; - -static inline uint8_t CheckDeviceExtensions( - VkExtensionProperties *extensions, - uint32_t numExtensions, - VulkanExtensions *supports -) { - uint32_t i; - - SDL_memset(supports, '\0', sizeof(VulkanExtensions)); - for (i = 0; i < numExtensions; i += 1) - { - const char *name = extensions[i].extensionName; - #define CHECK(ext) \ - if (SDL_strcmp(name, "VK_" #ext) == 0) \ - { \ - supports->ext = 1; \ - } - CHECK(KHR_swapchain) - else CHECK(KHR_maintenance1) - else CHECK(KHR_driver_properties) - else CHECK(EXT_vertex_attribute_divisor) - else CHECK(KHR_portability_subset) - else CHECK(GGP_frame_token) - #undef CHECK - } - - return ( supports->KHR_swapchain && - supports->KHR_maintenance1 ); -} - -static inline uint32_t GetDeviceExtensionCount(VulkanExtensions *supports) -{ - return ( - supports->KHR_swapchain + - supports->KHR_maintenance1 + - supports->KHR_driver_properties + - supports->EXT_vertex_attribute_divisor + - supports->KHR_portability_subset + - supports->GGP_frame_token - ); -} - -static inline void CreateDeviceExtensionArray( - VulkanExtensions *supports, - const char **extensions -) { - uint8_t cur = 0; - #define CHECK(ext) \ - if (supports->ext) \ - { \ - extensions[cur++] = "VK_" #ext; \ - } - CHECK(KHR_swapchain) - CHECK(KHR_maintenance1) - CHECK(KHR_driver_properties) - CHECK(EXT_vertex_attribute_divisor) - CHECK(KHR_portability_subset) - CHECK(GGP_frame_token) - #undef CHECK -} - -/* Constants/Limits */ - -#define TEXTURE_COUNT MAX_TOTAL_SAMPLERS -#define MAX_MULTISAMPLE_MASK_SIZE 2 -#define MAX_QUERIES 16 -#define MAX_UNIFORM_DESCRIPTOR_SETS 1024 - -/* Should be equivalent to the number of values in FNA3D_PrimitiveType */ -#define PRIMITIVE_TYPES_COUNT 5 - -#define STARTING_SAMPLER_DESCRIPTOR_POOL_SIZE 16 - -#define DEFAULT_PIPELINE_CACHE_FILE_NAME "FNA3D_Vulkan_PipelineCache.blob" - -#define WINDOW_SWAPCHAIN_DATA "FNA3D_VulkanSwapchain" - -#define IDENTITY_SWIZZLE \ -{ \ - VK_COMPONENT_SWIZZLE_IDENTITY, \ - VK_COMPONENT_SWIZZLE_IDENTITY, \ - VK_COMPONENT_SWIZZLE_IDENTITY, \ - VK_COMPONENT_SWIZZLE_IDENTITY \ -} - -static const VkComponentMapping RGBA_SWIZZLE = -{ - VK_COMPONENT_SWIZZLE_R, - VK_COMPONENT_SWIZZLE_G, - VK_COMPONENT_SWIZZLE_B, - VK_COMPONENT_SWIZZLE_A -}; - -static const uint8_t DEVICE_PRIORITY[] = -{ - 0, /* VK_PHYSICAL_DEVICE_TYPE_OTHER */ - 3, /* VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU */ - 4, /* VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU */ - 2, /* VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU */ - 1 /* VK_PHYSICAL_DEVICE_TYPE_CPU */ -}; - -/* Enumerations */ - -typedef enum VulkanResourceAccessType -{ - /* Reads */ - RESOURCE_ACCESS_NONE, /* For initialization */ - RESOURCE_ACCESS_INDEX_BUFFER, - RESOURCE_ACCESS_VERTEX_BUFFER, - RESOURCE_ACCESS_VERTEX_SHADER_READ_UNIFORM_BUFFER, - RESOURCE_ACCESS_VERTEX_SHADER_READ_SAMPLED_IMAGE, - RESOURCE_ACCESS_FRAGMENT_SHADER_READ_UNIFORM_BUFFER, - RESOURCE_ACCESS_FRAGMENT_SHADER_READ_SAMPLED_IMAGE, - RESOURCE_ACCESS_FRAGMENT_SHADER_READ_COLOR_ATTACHMENT, - RESOURCE_ACCESS_FRAGMENT_SHADER_READ_DEPTH_STENCIL_ATTACHMENT, - RESOURCE_ACCESS_ANY_SHADER_READ_SAMPLED_IMAGE, - RESOURCE_ACCESS_COLOR_ATTACHMENT_READ, - RESOURCE_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ, - RESOURCE_ACCESS_TRANSFER_READ, - RESOURCE_ACCESS_HOST_READ, - RESOURCE_ACCESS_PRESENT, - RESOURCE_ACCESS_END_OF_READ, - - /* Writes */ - RESOURCE_ACCESS_VERTEX_SHADER_WRITE, - RESOURCE_ACCESS_FRAGMENT_SHADER_WRITE, - RESOURCE_ACCESS_COLOR_ATTACHMENT_WRITE, - RESOURCE_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE, - RESOURCE_ACCESS_TRANSFER_WRITE, - RESOURCE_ACCESS_HOST_WRITE, - - /* Read-Writes */ - RESOURCE_ACCESS_COLOR_ATTACHMENT_READ_WRITE, - RESOURCE_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_WRITE, - RESOURCE_ACCESS_MEMORY_TRANSFER_READ_WRITE, - RESOURCE_ACCESS_GENERAL, - - /* Count */ - RESOURCE_ACCESS_TYPES_COUNT -} VulkanResourceAccessType; - -typedef enum CreateSwapchainResult -{ - CREATE_SWAPCHAIN_FAIL, - CREATE_SWAPCHAIN_SUCCESS, - CREATE_SWAPCHAIN_SURFACE_ZERO, -} CreateSwapchainResult; - -/* Image Barriers */ - -typedef struct VulkanResourceAccessInfo -{ - VkPipelineStageFlags stageMask; - VkAccessFlags accessMask; - VkImageLayout imageLayout; -} VulkanResourceAccessInfo; - -static const VulkanResourceAccessInfo AccessMap[RESOURCE_ACCESS_TYPES_COUNT] = -{ - /* RESOURCE_ACCESS_NONE */ - { - 0, - 0, - VK_IMAGE_LAYOUT_UNDEFINED - }, - - /* RESOURCE_ACCESS_INDEX_BUFFER */ - { - VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, - VK_ACCESS_INDEX_READ_BIT, - VK_IMAGE_LAYOUT_UNDEFINED - }, - - /* RESOURCE_ACCESS_VERTEX_BUFFER */ - { - VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, - VK_ACCESS_INDEX_READ_BIT, - VK_IMAGE_LAYOUT_UNDEFINED - }, - - /* RESOURCE_ACCESS_VERTEX_SHADER_READ_UNIFORM_BUFFER */ - { - VK_PIPELINE_STAGE_VERTEX_SHADER_BIT, - VK_ACCESS_SHADER_READ_BIT, - VK_IMAGE_LAYOUT_UNDEFINED - }, - - /* RESOURCE_ACCESS_VERTEX_SHADER_READ_SAMPLED_IMAGE */ - { - VK_PIPELINE_STAGE_VERTEX_SHADER_BIT, - VK_ACCESS_SHADER_READ_BIT, - VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL - }, - - /* RESOURCE_ACCESS_FRAGMENT_SHADER_READ_UNIFORM_BUFFER */ - { - VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, - VK_ACCESS_UNIFORM_READ_BIT, - VK_IMAGE_LAYOUT_UNDEFINED - }, - - /* RESOURCE_ACCESS_FRAGMENT_SHADER_READ_SAMPLED_IMAGE */ - { - VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, - VK_ACCESS_SHADER_READ_BIT, - VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL - }, - - /* RESOURCE_ACCESS_FRAGMENT_SHADER_READ_COLOR_ATTACHMENT */ - { - VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, - VK_ACCESS_INPUT_ATTACHMENT_READ_BIT, - VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL - }, - - /* RESOURCE_ACCESS_FRAGMENT_SHADER_READ_DEPTH_STENCIL_ATTACHMENT */ - { - VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, - VK_ACCESS_INPUT_ATTACHMENT_READ_BIT, - VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL - }, - - /* RESOURCE_ACCESS_ANY_SHADER_READ_SAMPLED_IMAGE */ - { - VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, - VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_INPUT_ATTACHMENT_READ_BIT, - VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL - }, - - /* RESOURCE_ACCESS_COLOR_ATTACHMENT_READ */ - { - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, - VK_ACCESS_COLOR_ATTACHMENT_READ_BIT, - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL - }, - - /* RESOURCE_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ */ - { - VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, - VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT, - VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL - }, - - /* RESOURCE_ACCESS_TRANSFER_READ */ - { - VK_PIPELINE_STAGE_TRANSFER_BIT, - VK_ACCESS_TRANSFER_READ_BIT, - VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL - }, - - /* RESOURCE_ACCESS_HOST_READ */ - { - VK_PIPELINE_STAGE_HOST_BIT, - VK_ACCESS_HOST_READ_BIT, - VK_IMAGE_LAYOUT_GENERAL - }, - - /* RESOURCE_ACCESS_PRESENT */ - { - 0, - 0, - VK_IMAGE_LAYOUT_PRESENT_SRC_KHR - }, - - /* RESOURCE_ACCESS_END_OF_READ */ - { - 0, - 0, - VK_IMAGE_LAYOUT_UNDEFINED - }, - - /* RESOURCE_ACCESS_VERTEX_SHADER_WRITE */ - { - VK_PIPELINE_STAGE_VERTEX_SHADER_BIT, - VK_ACCESS_SHADER_WRITE_BIT, - VK_IMAGE_LAYOUT_GENERAL - }, - - /* RESOURCE_ACCESS_FRAGMENT_SHADER_WRITE */ - { - VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, - VK_ACCESS_SHADER_WRITE_BIT, - VK_IMAGE_LAYOUT_GENERAL - }, - - /* RESOURCE_ACCESS_COLOR_ATTACHMENT_WRITE */ - { - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, - VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL - }, - - /* RESOURCE_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE */ - { - VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, - VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, - VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL - }, - - /* RESOURCE_ACCESS_TRANSFER_WRITE */ - { - VK_PIPELINE_STAGE_TRANSFER_BIT, - VK_ACCESS_TRANSFER_WRITE_BIT, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL - }, - - /* RESOURCE_ACCESS_HOST_WRITE */ - { - VK_PIPELINE_STAGE_HOST_BIT, - VK_ACCESS_HOST_WRITE_BIT, - VK_IMAGE_LAYOUT_GENERAL - }, - - /* RESOURCE_ACCESS_COLOR_ATTACHMENT_READ_WRITE */ - { - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, - VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL - }, - - /* RESOURCE_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_WRITE */ - { - VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, - VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, - VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL - }, - - /* RESOURCE_ACCESS_MEMORY_TRANSFER_READ_WRITE */ - { - VK_PIPELINE_STAGE_TRANSFER_BIT, - VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT, - VK_IMAGE_LAYOUT_UNDEFINED - }, - - /* RESOURCE_ACCESS_GENERAL */ - { - VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, - VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT, - VK_IMAGE_LAYOUT_GENERAL - } -}; - -/* Shader Resources */ - -typedef struct ShaderResources -{ - VkDescriptorPool *samplerDescriptorPools; - uint32_t samplerDescriptorPoolCount; - uint32_t nextPoolSize; - - VkDescriptorSetLayout samplerLayout; - uint8_t *samplerBindingIndices; - uint32_t samplerCount; - - VkDescriptorSet *inactiveDescriptorSets; - uint32_t inactiveDescriptorSetCount; - uint32_t inactiveDescriptorSetCapacity; - - VkDescriptorSet uniformDescriptorSet; - VkDescriptorBufferInfo uniformBufferInfo; - - /* VK_NULL_HANDLE unless samplerCount is 0 */ - VkDescriptorSet dummySamplerDescriptorSet; -} ShaderResources; - -typedef struct ShaderResourcesHashMap -{ - MOJOSHADER_vkShader *key; - ShaderResources *value; -} ShaderResourcesHashMap; - -typedef struct ShaderResourcesHashArray -{ - ShaderResourcesHashMap *elements; - int32_t count; - int32_t capacity; -} ShaderResourcesHashArray; - -#define NUM_SHADER_RESOURCES_BUCKETS 1031 - -typedef struct ShaderResourcesHashTable -{ - ShaderResourcesHashArray buckets[NUM_SHADER_RESOURCES_BUCKETS]; -} ShaderResourcesHashTable; - -static inline ShaderResources *ShaderResourcesHashTable_Fetch( - ShaderResourcesHashTable *table, - MOJOSHADER_vkShader *key -) { - int32_t i; - uint64_t hashcode = (uint64_t) (size_t) key; - ShaderResourcesHashArray *arr = &table->buckets[hashcode % NUM_SHADER_RESOURCES_BUCKETS]; - - for (i = 0; i < arr->count; i += 1) - { - const MOJOSHADER_vkShader *e = arr->elements[i].key; - if (key == e) - { - return arr->elements[i].value; - } - } - - return NULL; -} - -static inline void ShaderResourcesHashTable_Insert( - ShaderResourcesHashTable *table, - MOJOSHADER_vkShader *key, - ShaderResources *value -) { - uint64_t hashcode = (uint64_t) (size_t) key; - ShaderResourcesHashArray *arr = &table->buckets[hashcode % NUM_SHADER_RESOURCES_BUCKETS]; - - ShaderResourcesHashMap map; - map.key = key; - map.value = value; - - EXPAND_ARRAY_IF_NEEDED(arr, 2, ShaderResourcesHashMap) - - arr->elements[arr->count] = map; - arr->count += 1; -} - -/* Internal Structures */ - -typedef struct SwapChainSupportDetails -{ - VkSurfaceCapabilitiesKHR capabilities; - VkSurfaceFormatKHR *formats; - uint32_t formatsLength; - VkPresentModeKHR *presentModes; - uint32_t presentModesLength; -} SwapChainSupportDetails; - -/* FIXME: This could be packed better */ -typedef struct PipelineHash -{ - PackedState blendState; - PackedState rasterizerState; - PackedState depthStencilState; - uint32_t vertexBufferBindingsIndex; - FNA3D_PrimitiveType primitiveType; - VkSampleMask sampleMask; - MOJOSHADER_vkShader *vertShader; - MOJOSHADER_vkShader *fragShader; - /* Pipelines have to be compatible with a render pass */ - VkRenderPass renderPass; -} PipelineHash; - -typedef struct PipelineHashMap -{ - PipelineHash key; - VkPipeline value; -} PipelineHashMap; - -typedef struct PipelineHashArray -{ - PipelineHashMap *elements; - int32_t count; - int32_t capacity; -} PipelineHashArray; - -#define NUM_PIPELINE_HASH_BUCKETS 1031 - -typedef struct PipelineHashTable -{ - PipelineHashArray buckets[NUM_PIPELINE_HASH_BUCKETS]; -} PipelineHashTable; - -static inline uint64_t PipelineHashTable_GetHashCode(PipelineHash hash) -{ - /* The algorithm for this hashing function - * is taken from Josh Bloch's "Effective Java". - * (https://stackoverflow.com/a/113600/12492383) - */ - const uint64_t HASH_FACTOR = 97; - uint64_t result = 1; - result = result * HASH_FACTOR + hash.blendState.a; - result = result * HASH_FACTOR + hash.blendState.b; - result = result * HASH_FACTOR + hash.rasterizerState.a; - result = result * HASH_FACTOR + hash.rasterizerState.b; - result = result * HASH_FACTOR + hash.depthStencilState.a; - result = result * HASH_FACTOR + hash.depthStencilState.b; - result = result * HASH_FACTOR + hash.vertexBufferBindingsIndex; - result = result * HASH_FACTOR + hash.primitiveType; - result = result * HASH_FACTOR + hash.sampleMask; - result = result * HASH_FACTOR + (uint64_t) (size_t) hash.vertShader; - result = result * HASH_FACTOR + (uint64_t) (size_t) hash.fragShader; - result = result * HASH_FACTOR + (uint64_t) (size_t) hash.renderPass; - return result; -} - -static inline VkPipeline PipelineHashTable_Fetch( - PipelineHashTable *table, - PipelineHash key -) { - int32_t i; - uint64_t hashcode = PipelineHashTable_GetHashCode(key); - PipelineHashArray *arr = &table->buckets[hashcode % NUM_PIPELINE_HASH_BUCKETS]; - - for (i = 0; i < arr->count; i += 1) - { - const PipelineHash *e = &arr->elements[i].key; - if ( key.blendState.a == e->blendState.a && - key.blendState.b == e->blendState.b && - key.rasterizerState.a == e->rasterizerState.a && - key.rasterizerState.b == e->rasterizerState.b && - key.depthStencilState.a == e->depthStencilState.a && - key.depthStencilState.b == e->depthStencilState.b && - key.vertexBufferBindingsIndex == e->vertexBufferBindingsIndex && - key.primitiveType == e->primitiveType && - key.sampleMask == e->sampleMask && - key.vertShader == e->vertShader && - key.fragShader == e->fragShader && - key.renderPass == e->renderPass ) - { - return arr->elements[i].value; - } - } - - return VK_NULL_HANDLE; -} - -static inline void PipelineHashTable_Insert( - PipelineHashTable *table, - PipelineHash key, - VkPipeline value -) { - uint64_t hashcode = PipelineHashTable_GetHashCode(key); - PipelineHashArray *arr = &table->buckets[hashcode % NUM_PIPELINE_HASH_BUCKETS]; - PipelineHashMap map; - map.key = key; - map.value = value; - - EXPAND_ARRAY_IF_NEEDED(arr, 2, PipelineHashMap) - - arr->elements[arr->count] = map; - arr->count += 1; -} - -typedef struct RenderPassHash -{ - VkFormat colorAttachmentFormatOne; - VkFormat colorAttachmentFormatTwo; - VkFormat colorAttachmentFormatThree; - VkFormat colorAttachmentFormatFour; - VkFormat depthStencilAttachmentFormat; - uint32_t width; - uint32_t height; - uint32_t multiSampleCount; - uint8_t clearColor; - uint8_t clearDepth; - uint8_t clearStencil; - uint8_t preserveTargetContents; -} RenderPassHash; - -typedef struct RenderPassHashMap -{ - RenderPassHash key; - VkRenderPass value; -} RenderPassHashMap; - -typedef struct RenderPassHashArray -{ - RenderPassHashMap *elements; - int32_t count; - int32_t capacity; -} RenderPassHashArray; - -static inline VkRenderPass RenderPassHashArray_Fetch( - RenderPassHashArray *arr, - RenderPassHash key -) { - int32_t i; - - for (i = 0; i < arr->count; i += 1) - { - const RenderPassHash *e = &arr->elements[i].key; - if ( key.colorAttachmentFormatOne == e->colorAttachmentFormatOne && - key.colorAttachmentFormatTwo == e->colorAttachmentFormatTwo && - key.colorAttachmentFormatThree == e->colorAttachmentFormatThree && - key.colorAttachmentFormatFour == e->colorAttachmentFormatFour && - key.depthStencilAttachmentFormat == e->depthStencilAttachmentFormat && - key.width == e->width && - key.height == e->height && - key.multiSampleCount == e->multiSampleCount && - key.clearColor == e->clearColor && - key.clearDepth == e->clearDepth && - key.clearStencil == e->clearStencil && - key.preserveTargetContents == e->preserveTargetContents ) - { - return arr->elements[i].value; - } - } - - return VK_NULL_HANDLE; -} - -static inline void RenderPassHashArray_Insert( - RenderPassHashArray *arr, - RenderPassHash key, - VkRenderPass value -) { - RenderPassHashMap map; - - map.key = key; - map.value = value; - - EXPAND_ARRAY_IF_NEEDED(arr, 4, RenderPassHashMap) - - arr->elements[arr->count] = map; - arr->count += 1; -} - -typedef struct FramebufferHash -{ - VkImageView colorAttachmentViews[MAX_RENDERTARGET_BINDINGS]; - VkImageView colorMultiSampleAttachmentViews[MAX_RENDERTARGET_BINDINGS]; - VkImageView depthStencilAttachmentView; - uint32_t width; - uint32_t height; -} FramebufferHash; - -typedef struct FramebufferHashMap -{ - FramebufferHash key; - VkFramebuffer value; -} FramebufferHashMap; - -typedef struct FramebufferHashArray -{ - FramebufferHashMap *elements; - int32_t count; - int32_t capacity; -} FramebufferHashArray; - -static inline VkFramebuffer FramebufferHashArray_Fetch( - FramebufferHashArray *arr, - FramebufferHash key -) { - int32_t i; - - for (i = 0; i < arr->count; i += 1) - { - const FramebufferHash *e = &arr->elements[i].key; - if ( SDL_memcmp(key.colorAttachmentViews, e->colorAttachmentViews, sizeof(key.colorAttachmentViews)) == 0 && - SDL_memcmp(key.colorAttachmentViews, e->colorAttachmentViews, sizeof(key.colorAttachmentViews)) == 0 && - key.depthStencilAttachmentView == e->depthStencilAttachmentView && - key.width == e->width && - key.height == e->height ) - { - return arr->elements[i].value; - } - } - - return VK_NULL_HANDLE; -} - -static inline void FramebufferHashArray_Insert( - FramebufferHashArray *arr, - FramebufferHash key, - VkFramebuffer value -) { - FramebufferHashMap map; - map.key = key; - map.value = value; - - EXPAND_ARRAY_IF_NEEDED(arr, 4, FramebufferHashMap) - - arr->elements[arr->count] = map; - arr->count += 1; -} - -static inline void FramebufferHashArray_Remove( - FramebufferHashArray *arr, - uint32_t index -) { - if (index != arr->count - 1) - { - arr->elements[index] = arr->elements[arr->count - 1]; - } - - arr->count -= 1; -} - -typedef struct SamplerStateHashMap -{ - PackedState key; - VkSampler value; -} SamplerStateHashMap; - -typedef struct SamplerStateHashArray -{ - SamplerStateHashMap *elements; - int32_t count; - int32_t capacity; -} SamplerStateHashArray; - -static inline VkSampler SamplerStateHashArray_Fetch( - SamplerStateHashArray *arr, - PackedState key -) { - int32_t i; - - for (i = 0; i < arr->count; i += 1) - { - if ( key.a == arr->elements[i].key.a && - key.b == arr->elements[i].key.b ) - { - return arr->elements[i].value; - } - } - - return VK_NULL_HANDLE; -} - -static inline void SamplerStateHashArray_Insert( - SamplerStateHashArray *arr, - PackedState key, - VkSampler value -) { - SamplerStateHashMap map; - map.key.a = key.a; - map.key.b = key.b; - map.value = value; - - EXPAND_ARRAY_IF_NEEDED(arr, 4, SamplerStateHashMap) - - arr->elements[arr->count] = map; - arr->count += 1; -} - -typedef struct DescriptorSetLayoutHash -{ - VkDescriptorType descriptorType; - uint16_t bitmask; - VkShaderStageFlagBits stageFlag; -} DescriptorSetLayoutHash; - -typedef struct DescriptorSetLayoutHashMap -{ - DescriptorSetLayoutHash key; - VkDescriptorSetLayout value; -} DescriptorSetLayoutHashMap; - -typedef struct DescriptorSetLayoutHashArray -{ - DescriptorSetLayoutHashMap *elements; - int32_t count; - int32_t capacity; -} DescriptorSetLayoutHashArray; - -#define NUM_DESCRIPTOR_SET_LAYOUT_BUCKETS 1031 - -typedef struct DescriptorSetLayoutHashTable -{ - DescriptorSetLayoutHashArray buckets[NUM_DESCRIPTOR_SET_LAYOUT_BUCKETS]; -} DescriptorSetLayoutHashTable; - -static inline uint64_t DescriptorSetLayoutHashTable_GetHashCode(DescriptorSetLayoutHash key) -{ - const uint64_t HASH_FACTOR = 97; - uint64_t result = 1; - result = result * HASH_FACTOR + key.descriptorType; - result = result * HASH_FACTOR + key.bitmask; - result = result * HASH_FACTOR + key.stageFlag; - return result; -} - -static inline VkDescriptorSetLayout DescriptorSetLayoutHashTable_Fetch( - DescriptorSetLayoutHashTable *table, - DescriptorSetLayoutHash key -) { - int32_t i; - uint64_t hashcode = DescriptorSetLayoutHashTable_GetHashCode(key); - DescriptorSetLayoutHashArray *arr = &table->buckets[hashcode % NUM_DESCRIPTOR_SET_LAYOUT_BUCKETS]; - - for (i = 0; i < arr->count; i += 1) - { - const DescriptorSetLayoutHash *e = &arr->elements[i].key; - if ( key.descriptorType == e->descriptorType && - key.bitmask == e->bitmask && - key.stageFlag == e->stageFlag ) - { - return arr->elements[i].value; - } - } - - return VK_NULL_HANDLE; -} - -static inline void DescriptorSetLayoutHashTable_Insert( - DescriptorSetLayoutHashTable *table, - DescriptorSetLayoutHash key, - VkDescriptorSetLayout value -) { - uint64_t hashcode = DescriptorSetLayoutHashTable_GetHashCode(key); - DescriptorSetLayoutHashArray *arr = &table->buckets[hashcode % NUM_DESCRIPTOR_SET_LAYOUT_BUCKETS]; - - DescriptorSetLayoutHashMap map; - map.key = key; - map.value = value; - - EXPAND_ARRAY_IF_NEEDED(arr, 4, DescriptorSetLayoutHashMap); - - arr->elements[arr->count] = map; - arr->count += 1; -} - -typedef struct PipelineLayoutHash -{ - VkDescriptorSetLayout vertexSamplerLayout; - VkDescriptorSetLayout fragSamplerLayout; - VkDescriptorSetLayout vertexUniformLayout; - VkDescriptorSetLayout fragUniformLayout; -} PipelineLayoutHash; - -typedef struct PipelineLayoutHashMap -{ - PipelineLayoutHash key; - VkPipelineLayout value; -} PipelineLayoutHashMap; - -typedef struct PipelineLayoutHashArray -{ - PipelineLayoutHashMap *elements; - int32_t count; - int32_t capacity; -} PipelineLayoutHashArray; - -#define NUM_PIPELINE_LAYOUT_BUCKETS 1031 - -typedef struct PipelineLayoutHashTable -{ - PipelineLayoutHashArray buckets[NUM_PIPELINE_LAYOUT_BUCKETS]; -} PipelineLayoutHashTable; - -static inline uint64_t PipelineLayoutHashTable_GetHashCode(PipelineLayoutHash key) -{ - const uint64_t HASH_FACTOR = 97; - uint64_t result = 1; - result = result * HASH_FACTOR + (uint64_t) key.vertexSamplerLayout; - result = result * HASH_FACTOR + (uint64_t) key.fragSamplerLayout; - result = result * HASH_FACTOR + (uint64_t) key.vertexUniformLayout; - result = result * HASH_FACTOR + (uint64_t) key.fragUniformLayout; - return result; -} - -static inline VkPipelineLayout PipelineLayoutHashArray_Fetch( - PipelineLayoutHashTable *table, - PipelineLayoutHash key -) { - int32_t i; - uint64_t hashcode = PipelineLayoutHashTable_GetHashCode(key); - PipelineLayoutHashArray *arr = &table->buckets[hashcode % NUM_PIPELINE_LAYOUT_BUCKETS]; - - for (i = 0; i < arr->count; i += 1) - { - const PipelineLayoutHash *e = &arr->elements[i].key; - if ( key.vertexSamplerLayout == e->vertexSamplerLayout && - key.fragSamplerLayout == e->fragSamplerLayout && - key.vertexUniformLayout == e->vertexUniformLayout && - key.fragUniformLayout == e->fragUniformLayout ) - { - return arr->elements[i].value; - } - } - - return VK_NULL_HANDLE; -} - -static inline void PipelineLayoutHashArray_Insert( - PipelineLayoutHashTable *table, - PipelineLayoutHash key, - VkPipelineLayout value -) { - uint64_t hashcode = PipelineLayoutHashTable_GetHashCode(key); - PipelineLayoutHashArray *arr = &table->buckets[hashcode % NUM_PIPELINE_HASH_BUCKETS]; - - PipelineLayoutHashMap map; - map.key = key; - map.value = value; - - EXPAND_ARRAY_IF_NEEDED(arr, 4, PipelineLayoutHashMap) - - arr->elements[arr->count] = map; - arr->count += 1; -} - -typedef struct VulkanSwapchainData -{ - /* Window surface */ - VkSurfaceKHR surface; - VkSurfaceFormatKHR surfaceFormat; - void *windowHandle; - - /* Swapchain for window surface */ - VkSwapchainKHR swapchain; - VkFormat swapchainFormat; - VkComponentMapping swapchainSwizzle; - VkPresentModeKHR presentMode; - - /* Swapchain images */ - VkExtent2D extent; - VkImage *images; - VkImageView *views; - VulkanResourceAccessType *resourceAccessTypes; - uint32_t imageCount; - - /* Synchronization */ - VkSemaphore imageAvailableSemaphore; - VkSemaphore renderFinishedSemaphore; - VkFence fence; /* owned by command buffer container */ -} VulkanSwapchainData; - -typedef struct VulkanBuffer VulkanBuffer; -typedef struct VulkanTexture VulkanTexture; - -struct VulkanTexture /* Cast from FNA3D_Texture* */ -{ - FNA3D_MemoryUsedRegion *usedRegion; - VkImage image; - VkImageView view; - VkImageView rtViews[6]; - VkExtent2D dimensions; - uint32_t depth; - uint8_t external; - VkFormat surfaceFormat; - uint32_t layerCount; - uint32_t levelCount; - uint8_t isRenderTarget; - VulkanResourceAccessType resourceAccessType; - VkImageCreateInfo imageCreateInfo; /* used for resource copy */ - VkImageViewCreateInfo viewCreateInfo; /* used for resource copy */ - FNA3DNAMELESS union - { - FNA3D_SurfaceFormat colorFormat; - FNA3D_DepthFormat depthStencilFormat; - }; -}; - -static VulkanTexture NullTexture = -{ - (FNA3D_MemoryUsedRegion*) 0, - (VkImage) 0, - (VkImageView) 0, - { 0, 0, 0, 0, 0, 0 }, - {0, 0}, - 0, - 0, - VK_FORMAT_UNDEFINED, - 0, - RESOURCE_ACCESS_NONE -}; - -struct VulkanBuffer -{ - VkDeviceSize size; - FNA3D_MemoryUsedRegion *usedRegion; - VkBuffer buffer; - VulkanResourceAccessType resourceAccessType; - VkBufferCreateInfo bufferCreateInfo; /* used for resource copy */ - VkBufferUsageFlags usage; - uint8_t preferDeviceLocal; - uint8_t isTransferBuffer; - SDL_AtomicInt refcount; -}; - -typedef struct VulkanColorBuffer -{ - VulkanTexture *handle; - VulkanTexture *multiSampleTexture; - uint32_t multiSampleCount; -} VulkanColorBuffer; - -typedef struct VulkanDepthStencilBuffer -{ - VulkanTexture *handle; -} VulkanDepthStencilBuffer; - -typedef struct VulkanRenderbuffer /* Cast from FNA3D_Renderbuffer* */ -{ - VulkanColorBuffer *colorBuffer; - VulkanDepthStencilBuffer *depthBuffer; -} VulkanRenderbuffer; - -typedef struct VulkanEffect /* Cast from FNA3D_Effect* */ -{ - MOJOSHADER_effect *effect; -} VulkanEffect; - -typedef struct VulkanQuery /* Cast from FNA3D_Query* */ -{ - uint32_t index; -} VulkanQuery; - -typedef struct DescriptorSetData -{ - VkDescriptorSet descriptorSet; - ShaderResources *parent; -} DescriptorSetData; - -typedef struct VulkanCommandBuffer -{ - VkCommandBuffer commandBuffer; - VkFence inFlightFence; - - DescriptorSetData *usedDescriptorSetDatas; - uint32_t usedDescriptorSetDataCount; - uint32_t usedDescriptorSetDataCapacity; -} VulkanCommandBuffer; - -typedef struct VulkanRenderer -{ - FNA3D_Device *parentDevice; - FNA3D_MemoryAllocator *allocator; - - VkInstance instance; - VkPhysicalDevice physicalDevice; - VkPhysicalDeviceProperties2 physicalDeviceProperties; - VkPhysicalDeviceDriverPropertiesKHR physicalDeviceDriverProperties; - VkDevice logicalDevice; - uint8_t unifiedMemoryWarning; - - uint32_t queueFamilyIndex; - VkQueue unifiedQueue; - - VulkanSwapchainData** swapchainDatas; - uint32_t swapchainDataCount; - uint32_t swapchainDataCapacity; - - PackedVertexBufferBindingsArray vertexBufferBindingsCache; - VkPipelineCache pipelineCache; - - VkRenderPass renderPass; - VkPipeline currentPipeline; - VkPipelineLayout currentPipelineLayout; - int32_t currentVertexBufferBindingsIndex; - - /* Command Buffers */ - VkCommandPool commandPool; - FNA3D_CommandBufferManager *commandBuffers; - - /* Queries */ - VkQueryPool queryPool; - int8_t freeQueryIndexStack[MAX_QUERIES]; - int8_t freeQueryIndexStackHead; - - FNA3D_SurfaceFormat backbufferFormat; - FNA3D_PresentInterval presentInterval; - - VulkanColorBuffer fauxBackbufferColor; - VulkanTexture *fauxBackbufferMultiSampleColor; - VulkanDepthStencilBuffer fauxBackbufferDepthStencil; - VkFramebuffer fauxBackbufferFramebuffer; - uint32_t fauxBackbufferWidth; - uint32_t fauxBackbufferHeight; - uint32_t fauxBackbufferMultiSampleCount; - - VulkanTexture *colorAttachments[MAX_RENDERTARGET_BINDINGS]; - VulkanTexture *colorMultiSampleAttachments[MAX_RENDERTARGET_BINDINGS]; - FNA3D_CubeMapFace attachmentCubeFaces[MAX_RENDERTARGET_BINDINGS]; - uint32_t multiSampleCount; - uint32_t colorAttachmentCount; - - VulkanTexture *depthStencilAttachment; - FNA3D_DepthFormat currentDepthFormat; - - /* Separating the future render pass setting from the current one*/ - VulkanTexture *nextRenderPassColorAttachments[MAX_RENDERTARGET_BINDINGS]; - VulkanTexture *nextRenderPassColorMultiSampleAttachments[MAX_RENDERTARGET_BINDINGS]; - FNA3D_CubeMapFace nextRenderPassAttachmentCubeFaces[MAX_RENDERTARGET_BINDINGS]; - uint32_t nextRenderPassMultiSampleCount; - uint32_t nextRenderPassColorAttachmentCount; - - VulkanTexture *nextRenderPassDepthStencilAttachment; - FNA3D_DepthFormat nextRenderPassDepthFormat; - uint8_t nextRenderPassPreserveTargetContents; - - FNA3D_Viewport viewport; - FNA3D_Rect scissorRect; - - VkSampleMask multiSampleMask[MAX_MULTISAMPLE_MASK_SIZE]; - FNA3D_BlendState blendState; - - FNA3D_DepthStencilState depthStencilState; - FNA3D_RasterizerState rasterizerState; - FNA3D_PrimitiveType currentPrimitiveType; - - VkPhysicalDeviceMemoryProperties memoryProperties; - VkDeviceSize maxDeviceLocalHeapUsage; - VkDeviceSize deviceLocalHeapUsage; - - uint32_t numVertexBindings; - FNA3D_VertexBufferBinding vertexBindings[MAX_BOUND_VERTEX_BUFFERS]; - FNA3D_VertexElement vertexElements[MAX_BOUND_VERTEX_BUFFERS][MAX_VERTEX_ATTRIBUTES]; - VkBuffer boundVertexBuffers[MAX_BOUND_VERTEX_BUFFERS]; - VkDeviceSize boundVertexBufferOffsets[MAX_BOUND_VERTEX_BUFFERS]; - - int32_t stencilRef; - - int32_t numTextureSlots; - int32_t numVertexTextureSlots; - - VulkanTexture *textures[TEXTURE_COUNT]; - VkSampler samplers[TEXTURE_COUNT]; - uint8_t textureNeedsUpdate[TEXTURE_COUNT]; - uint8_t samplerNeedsUpdate[TEXTURE_COUNT]; - - VulkanBuffer *dummyVertUniformBuffer; - VulkanBuffer *dummyFragUniformBuffer; - - VkSampler dummyVertSamplerState; - VkSampler dummyVertSampler3DState; - VkSampler dummyVertSamplerCubeState; - VkSampler dummyFragSamplerState; - VkSampler dummyFragSampler3DState; - VkSampler dummyFragSamplerCubeState; - - VulkanTexture *dummyVertTexture; - VulkanTexture *dummyVertTexture3D; - VulkanTexture *dummyVertTextureCube; - VulkanTexture *dummyFragTexture; - VulkanTexture *dummyFragTexture3D; - VulkanTexture *dummyFragTextureCube; - - VkDescriptorPool uniformBufferDescriptorPool; - VkDescriptorSetLayout vertexUniformBufferDescriptorSetLayout; - VkDescriptorSetLayout fragUniformBufferDescriptorSetLayout; - VkDescriptorSet dummyVertexUniformBufferDescriptorSet; - VkDescriptorSet dummyFragUniformBufferDescriptorSet; - - uint8_t vertexSamplerDescriptorSetDataNeedsUpdate; - uint8_t fragSamplerDescriptorSetDataNeedsUpdate; - - VkDescriptorSet currentVertexSamplerDescriptorSet; - VkDescriptorSet currentFragSamplerDescriptorSet; - - ShaderResourcesHashTable shaderResourcesHashTable; - DescriptorSetLayoutHashTable descriptorSetLayoutTable; - PipelineLayoutHashTable pipelineLayoutTable; - PipelineHashTable pipelineHashTable; - RenderPassHashArray renderPassArray; - FramebufferHashArray framebufferArray; - SamplerStateHashArray samplerStateArray; - - VkSemaphore defragSemaphore; - - uint8_t bufferDefragInProgress; - uint8_t needDefrag; - uint32_t defragTimer; - uint8_t resourceFreed; - - VkBuffer *defragmentedBuffersToDestroy; - uint32_t defragmentedBuffersToDestroyCount; - uint32_t defragmentedBuffersToDestroyCapacity; - - VkImage *defragmentedImagesToDestroy; - uint32_t defragmentedImagesToDestroyCount; - uint32_t defragmentedImagesToDestroyCapacity; - - VkImageView *defragmentedImageViewsToDestroy; - uint32_t defragmentedImageViewsToDestroyCount; - uint32_t defragmentedImageViewsToDestroyCapacity; - - /* MojoShader Interop */ - MOJOSHADER_vkContext *mojoshaderContext; - MOJOSHADER_effect *currentEffect; - const MOJOSHADER_effectTechnique *currentTechnique; - uint32_t currentPass; - - VkShaderModule currentVertShader; - VkShaderModule currentFragShader; - - uint8_t renderPassInProgress; - uint8_t needNewRenderPass; - uint8_t renderTargetBound; - uint8_t needNewPipeline; - - uint8_t shouldClearColorOnBeginPass; - uint8_t shouldClearDepthOnBeginPass; - uint8_t shouldClearStencilOnBeginPass; - uint8_t drawCallMadeThisPass; - - VkClearColorValue clearColorValue; - VkClearDepthStencilValue clearDepthStencilValue; - - /* Depth Formats (may not match the format implied by the name!) */ - VkFormat D16Format; - VkFormat D24Format; - VkFormat D24S8Format; - - /* Capabilities */ - uint8_t supportsDxt1; - uint8_t supportsS3tc; - uint8_t supportsBc7; - uint8_t supportsDebugUtils; - uint8_t supportsDeviceProperties2; - uint8_t supportsSRGBRenderTarget; - uint8_t supportsPreciseOcclusionQueries; - uint8_t supportsBaseVertex; - uint8_t debugMode; - VulkanExtensions supports; - - uint8_t submitCounter; /* used so we don't clobber data being used by GPU */ - - /* Threading */ - SDL_Mutex *passLock; - SDL_Mutex *disposeLock; - - #define VULKAN_INSTANCE_FUNCTION(name) \ - PFN_##name name; - #define VULKAN_DEVICE_FUNCTION(name) \ - PFN_##name name; - #include "FNA3D_Driver_Vulkan_vkfuncs.h" -} VulkanRenderer; - -/* Command Buffer Recording Macro */ - -#define RECORD_CMD(cmdCall) \ - FNA3D_CommandBuffer_LockForRendering(renderer->commandBuffers); \ - cmdCall; \ - FNA3D_CommandBuffer_UnlockFromRendering(renderer->commandBuffers); - -/* XNA->Vulkan Translation Arrays */ - -static VkIndexType XNAToVK_IndexType[] = -{ - VK_INDEX_TYPE_UINT16, /* FNA3D_INDEXELEMENTSIZE_16BIT */ - VK_INDEX_TYPE_UINT32 /* FNA3D_INDEXELEMENTSIZE_32BIT */ -}; - -static inline VkSampleCountFlagBits XNAToVK_SampleCount(int32_t sampleCount) -{ - if (sampleCount <= 1) - { - return VK_SAMPLE_COUNT_1_BIT; - } - else if (sampleCount == 2) - { - return VK_SAMPLE_COUNT_2_BIT; - } - else if (sampleCount <= 4) - { - return VK_SAMPLE_COUNT_4_BIT; - } - else if (sampleCount <= 8) - { - return VK_SAMPLE_COUNT_8_BIT; - } - else if (sampleCount <= 16) - { - return VK_SAMPLE_COUNT_16_BIT; - } - else if (sampleCount <= 32) - { - return VK_SAMPLE_COUNT_32_BIT; - } - else if (sampleCount <= 64) - { - return VK_SAMPLE_COUNT_64_BIT; - } - else - { - FNA3D_LogWarn("Unexpected sample count: %d", sampleCount); - return VK_SAMPLE_COUNT_1_BIT; - } -} - -static VkComponentMapping XNAToVK_SurfaceSwizzle[] = -{ - IDENTITY_SWIZZLE, /* SurfaceFormat.Color */ - { /* SurfaceFormat.Bgr565 */ - VK_COMPONENT_SWIZZLE_B, - VK_COMPONENT_SWIZZLE_G, - VK_COMPONENT_SWIZZLE_R, - VK_COMPONENT_SWIZZLE_ONE - }, - IDENTITY_SWIZZLE, /* SurfaceFormat.Bgra5551 */ - IDENTITY_SWIZZLE, /* SurfaceFormat.Bgra4444 */ - IDENTITY_SWIZZLE, /* SurfaceFormat.Dxt1 */ - IDENTITY_SWIZZLE, /* SurfaceFormat.Dxt3 */ - IDENTITY_SWIZZLE, /* SurfaceFormat.Dxt5 */ - { /* SurfaceFormat.NormalizedByte2 */ - VK_COMPONENT_SWIZZLE_R, - VK_COMPONENT_SWIZZLE_G, - VK_COMPONENT_SWIZZLE_ONE, - VK_COMPONENT_SWIZZLE_ONE - }, - IDENTITY_SWIZZLE, /* SurfaceFormat.NormalizedByte4 */ - IDENTITY_SWIZZLE, /* SurfaceFormat.Rgba1010102 */ - { /* SurfaceFormat.Rg32 */ - VK_COMPONENT_SWIZZLE_R, - VK_COMPONENT_SWIZZLE_G, - VK_COMPONENT_SWIZZLE_ONE, - VK_COMPONENT_SWIZZLE_ONE - }, - IDENTITY_SWIZZLE, /* SurfaceFormat.Rgba64 */ - { /* SurfaceFormat.Alpha8 */ - VK_COMPONENT_SWIZZLE_ZERO, - VK_COMPONENT_SWIZZLE_ZERO, - VK_COMPONENT_SWIZZLE_ZERO, - VK_COMPONENT_SWIZZLE_R - }, - { /* SurfaceFormat.Single */ - VK_COMPONENT_SWIZZLE_R, - VK_COMPONENT_SWIZZLE_ONE, - VK_COMPONENT_SWIZZLE_ONE, - VK_COMPONENT_SWIZZLE_ONE - }, - { /* SurfaceFormat.Vector2 */ - VK_COMPONENT_SWIZZLE_R, - VK_COMPONENT_SWIZZLE_G, - VK_COMPONENT_SWIZZLE_ONE, - VK_COMPONENT_SWIZZLE_ONE - }, - IDENTITY_SWIZZLE, /* SurfaceFormat.Vector4 */ - { /* SurfaceFormat.HalfSingle */ - VK_COMPONENT_SWIZZLE_R, - VK_COMPONENT_SWIZZLE_ONE, - VK_COMPONENT_SWIZZLE_ONE, - VK_COMPONENT_SWIZZLE_ONE - }, - { /* SurfaceFormat.HalfVector2 */ - VK_COMPONENT_SWIZZLE_R, - VK_COMPONENT_SWIZZLE_G, - VK_COMPONENT_SWIZZLE_ONE, - VK_COMPONENT_SWIZZLE_ONE - }, - IDENTITY_SWIZZLE, /* SurfaceFormat.HalfVector4 */ - IDENTITY_SWIZZLE, /* SurfaceFormat.HdrBlendable */ - IDENTITY_SWIZZLE, /* SurfaceFormat.ColorBgraEXT */ - IDENTITY_SWIZZLE, /* SurfaceFormat.ColorSrgbEXT */ - IDENTITY_SWIZZLE, /* SurfaceFormat.Dxt5SrgbEXT */ - IDENTITY_SWIZZLE, /* SurfaceFormat.Bc7EXT */ - IDENTITY_SWIZZLE, /* SurfaceFormat.Bc7SrgbEXT */ -}; - -static VkFormat XNAToVK_SurfaceFormat[] = -{ - VK_FORMAT_R8G8B8A8_UNORM, /* SurfaceFormat.Color */ - VK_FORMAT_R5G6B5_UNORM_PACK16, /* SurfaceFormat.Bgr565 */ - VK_FORMAT_A1R5G5B5_UNORM_PACK16, /* SurfaceFormat.Bgra5551 */ - VK_FORMAT_B4G4R4A4_UNORM_PACK16, /* SurfaceFormat.Bgra4444 */ - VK_FORMAT_BC1_RGBA_UNORM_BLOCK, /* SurfaceFormat.Dxt1 */ - VK_FORMAT_BC2_UNORM_BLOCK, /* SurfaceFormat.Dxt3 */ - VK_FORMAT_BC3_UNORM_BLOCK, /* SurfaceFormat.Dxt5 */ - VK_FORMAT_R8G8_SNORM, /* SurfaceFormat.NormalizedByte2 */ - VK_FORMAT_R8G8B8A8_SNORM, /* SurfaceFormat.NormalizedByte4 */ - VK_FORMAT_A2R10G10B10_UNORM_PACK32, /* SurfaceFormat.Rgba1010102 */ - VK_FORMAT_R16G16_UNORM, /* SurfaceFormat.Rg32 */ - VK_FORMAT_R16G16B16A16_UNORM, /* SurfaceFormat.Rgba64 */ - VK_FORMAT_R8_UNORM, /* SurfaceFormat.Alpha8 */ - VK_FORMAT_R32_SFLOAT, /* SurfaceFormat.Single */ - VK_FORMAT_R32G32_SFLOAT, /* SurfaceFormat.Vector2 */ - VK_FORMAT_R32G32B32A32_SFLOAT, /* SurfaceFormat.Vector4 */ - VK_FORMAT_R16_SFLOAT, /* SurfaceFormat.HalfSingle */ - VK_FORMAT_R16G16_SFLOAT, /* SurfaceFormat.HalfVector2 */ - VK_FORMAT_R16G16B16A16_SFLOAT, /* SurfaceFormat.HalfVector4 */ - VK_FORMAT_R16G16B16A16_SFLOAT, /* SurfaceFormat.HdrBlendable */ - VK_FORMAT_B8G8R8A8_UNORM, /* SurfaceFormat.ColorBgraEXT */ - VK_FORMAT_R8G8B8A8_SRGB, /* SurfaceFormat.ColorSrgbEXT */ - VK_FORMAT_BC3_SRGB_BLOCK, /* SurfaceFormat.Dxt5SrgbEXT */ - VK_FORMAT_BC7_UNORM_BLOCK, /* SurfaceFormat.Bc7EXT */ - VK_FORMAT_BC7_SRGB_BLOCK, /* SurfaceFormat.Bc7SrgbEXT */ -}; - -static inline VkFormat XNAToVK_DepthFormat( - VulkanRenderer *renderer, - FNA3D_DepthFormat format -) { - switch (format) - { - case FNA3D_DEPTHFORMAT_D16: - return renderer->D16Format; - case FNA3D_DEPTHFORMAT_D24: - return renderer->D24Format; - case FNA3D_DEPTHFORMAT_D24S8: - return renderer->D24S8Format; - default: - return VK_FORMAT_UNDEFINED; - } -} - -static inline float XNAToVK_DepthBiasScale(VkFormat format) -{ - switch (format) - { - case VK_FORMAT_D16_UNORM: - return (float) ((1 << 16) - 1); - - case VK_FORMAT_D24_UNORM_S8_UINT: - return (float) ((1 << 24) - 1); - - case VK_FORMAT_D32_SFLOAT: - case VK_FORMAT_D32_SFLOAT_S8_UINT: - return (float) ((1 << 23) - 1); - - default: - return 0.0f; - } -} - -static inline uint8_t DepthFormatContainsStencil(VkFormat format) -{ - switch (format) - { - case VK_FORMAT_D16_UNORM: - case VK_FORMAT_D32_SFLOAT: - return 0; - case VK_FORMAT_D24_UNORM_S8_UINT: - case VK_FORMAT_D32_SFLOAT_S8_UINT: - return 1; - default: - SDL_assert(0 && "Invalid depth pixel format"); - return 0; - } -} - -static inline uint8_t IsDepthFormat(VkFormat format) -{ - return - format == VK_FORMAT_D16_UNORM || - format == VK_FORMAT_D16_UNORM_S8_UINT || - format == VK_FORMAT_D24_UNORM_S8_UINT || - format == VK_FORMAT_D32_SFLOAT || - format == VK_FORMAT_D32_SFLOAT_S8_UINT; -} - -static VkBlendFactor XNAToVK_BlendFactor[] = -{ - VK_BLEND_FACTOR_ONE, /* FNA3D_BLEND_ONE */ - VK_BLEND_FACTOR_ZERO, /* FNA3D_BLEND_ZERO */ - VK_BLEND_FACTOR_SRC_COLOR, /* FNA3D_BLEND_SOURCECOLOR */ - VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR, /* FNA3D_BLEND_INVERSESOURCECOLOR */ - VK_BLEND_FACTOR_SRC_ALPHA, /* FNA3D_BLEND_SOURCEALPHA */ - VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, /* FNA3D_BLEND_INVERSESOURCEALPHA */ - VK_BLEND_FACTOR_DST_COLOR, /* FNA3D_BLEND_DESTINATIONCOLOR */ - VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR, /* FNA3D_BLEND_INVERSEDESTINATIONCOLOR */ - VK_BLEND_FACTOR_DST_ALPHA, /* FNA3D_BLEND_DESTINATIONALPHA */ - VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA, /* FNA3D_BLEND_INVERSEDESTINATIONALPHA */ - VK_BLEND_FACTOR_CONSTANT_COLOR, /* FNA3D_BLEND_BLENDFACTOR */ - VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR, /* FNA3D_BLEND_INVERSEBLENDFACTOR */ - VK_BLEND_FACTOR_SRC_ALPHA_SATURATE /* FNA3D_BLEND_SOURCEALPHASATURATION */ -}; - -static VkBlendOp XNAToVK_BlendOp[] = -{ - VK_BLEND_OP_ADD, /* FNA3D_BLENDFUNCTION_ADD */ - VK_BLEND_OP_SUBTRACT, /* FNA3D_BLENDFUNCTION_SUBTRACT */ - VK_BLEND_OP_REVERSE_SUBTRACT, /* FNA3D_BLENDFUNCTION_REVERSESUBTRACT */ - VK_BLEND_OP_MAX, /* FNA3D_BLENDFUNCTION_MAX */ - VK_BLEND_OP_MIN /* FNA3D_BLENDFUNCTION_MIN */ -}; - -static VkPolygonMode XNAToVK_PolygonMode[] = -{ - VK_POLYGON_MODE_FILL, /* FNA3D_FILLMODE_SOLID */ - VK_POLYGON_MODE_LINE /* FNA3D_FILLMODE_WIREFRAME */ -}; - -static VkCullModeFlags XNAToVK_CullMode[] = -{ - VK_CULL_MODE_NONE, /* FNA3D_CULLMODE_NONE */ - VK_CULL_MODE_FRONT_BIT, /* FNA3D_CULLMODE_CULLCLOCKWISEFACE */ - VK_CULL_MODE_BACK_BIT /* FNA3D_CULLMODE_CULLCOUNTERCLOCKWISEFACE */ -}; - -static VkPrimitiveTopology XNAToVK_Topology[] = -{ - VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, /* FNA3D_PRIMITIVETYPE_TRIANGLELIST */ - VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, /* FNA3D_PRIMITIVETYPE_TRIANGLESTRIP */ - VK_PRIMITIVE_TOPOLOGY_LINE_LIST, /* FNA3D_PRIMITIVETYPE_LINELIST */ - VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, /* FNA3D_PRIMITIVETYPE_LINESTRIP */ - VK_PRIMITIVE_TOPOLOGY_POINT_LIST /* FNA3D_PRIMITIVETYPE_POINTLIST_EXT */ -}; - -static VkSamplerAddressMode XNAToVK_SamplerAddressMode[] = -{ - VK_SAMPLER_ADDRESS_MODE_REPEAT, /* FNA3D_TEXTUREADDRESSMODE_WRAP */ - VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, /* FNA3D_TEXTUREADDRESSMODE_CLAMP */ - VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT /* FNA3D_TEXTUREADDRESSMODE_MIRROR */ -}; - -static VkFilter XNAToVK_MagFilter[] = -{ - VK_FILTER_LINEAR, /* FNA3D_TEXTUREFILTER_LINEAR */ - VK_FILTER_NEAREST, /* FNA3D_TEXTUREFILTER_POINT */ - VK_FILTER_LINEAR, /* FNA3D_TEXTUREFILTER_ANISOTROPIC */ - VK_FILTER_LINEAR, /* FNA3D_TEXTUREFILTER_LINEAR_MIPPOINT */ - VK_FILTER_NEAREST, /* FNA3D_TEXTUREFILTER_POINT_MIPLINEAR */ - VK_FILTER_NEAREST, /* FNA3D_TEXTUREFILTER_MINLINEAR_MAGPOINT_MIPLINEAR */ - VK_FILTER_NEAREST, /* FNA3D_TEXTUREFILTER_MINLINEAR_MAGPOINT_MIPPOINT */ - VK_FILTER_LINEAR, /* FNA3D_TEXTUREFILTER_MINPOINT_MAGLINEAR_MIPLINEAR */ - VK_FILTER_LINEAR, /* FNA3D_TEXTUREFILTER_MINPOINT_MAGLINEAR_MIPPOINT */ -}; - -static VkSamplerMipmapMode XNAToVK_MipFilter[] = -{ - VK_SAMPLER_MIPMAP_MODE_LINEAR, /* FNA3D_TEXTUREFILTER_LINEAR */ - VK_SAMPLER_MIPMAP_MODE_NEAREST, /* FNA3D_TEXTUREFILTER_POINT */ - VK_SAMPLER_MIPMAP_MODE_LINEAR, /* FNA3D_TEXTUREFILTER_ANISOTROPIC */ - VK_SAMPLER_MIPMAP_MODE_NEAREST, /* FNA3D_TEXTUREFILTER_LINEAR_MIPPOINT */ - VK_SAMPLER_MIPMAP_MODE_LINEAR, /* FNA3D_TEXTUREFILTER_POINT_MIPLINEAR */ - VK_SAMPLER_MIPMAP_MODE_LINEAR, /* FNA3D_TEXTUREFILTER_MINLINEAR_MAGPOINT_MIPLINEAR */ - VK_SAMPLER_MIPMAP_MODE_NEAREST, /* FNA3D_TEXTUREFILTER_MINLINEAR_MAGPOINT_MIPPOINT */ - VK_SAMPLER_MIPMAP_MODE_LINEAR, /* FNA3D_TEXTUREFILTER_MINPOINT_MAGLINEAR_MIPLINEAR */ - VK_SAMPLER_MIPMAP_MODE_NEAREST, /* FNA3D_TEXTUREFILTER_MINPOINT_MAGLINEAR_MIPPOINT */ -}; - -static VkFilter XNAToVK_MinFilter[] = -{ - VK_FILTER_LINEAR, /* FNA3D_TEXTUREFILTER_LINEAR */ - VK_FILTER_NEAREST, /* FNA3D_TEXTUREFILTER_POINT */ - VK_FILTER_LINEAR, /* FNA3D_TEXTUREFILTER_ANISOTROPIC */ - VK_FILTER_LINEAR, /* FNA3D_TEXTUREFILTER_LINEAR_MIPPOINT */ - VK_FILTER_NEAREST, /* FNA3D_TEXTUREFILTER_POINT_MIPLINEAR */ - VK_FILTER_LINEAR, /* FNA3D_TEXTUREFILTER_MINLINEAR_MAGPOINT_MIPLINEAR */ - VK_FILTER_LINEAR, /* FNA3D_TEXTUREFILTER_MINLINEAR_MAGPOINT_MIPPOINT */ - VK_FILTER_NEAREST, /* FNA3D_TEXTUREFILTER_MINPOINT_MAGLINEAR_MIPLINEAR */ - VK_FILTER_NEAREST, /* FNA3D_TEXTUREFILTER_MINPOINT_MAGLINEAR_MIPPOINT */ -}; - -static VkCompareOp XNAToVK_CompareOp[] = -{ - VK_COMPARE_OP_ALWAYS, /* FNA3D_COMPAREFUNCTION_ALWAYS */ - VK_COMPARE_OP_NEVER, /* FNA3D_COMPAREFUNCTION_NEVER */ - VK_COMPARE_OP_LESS, /* FNA3D_COMPAREFUNCTION_LESS */ - VK_COMPARE_OP_LESS_OR_EQUAL, /* FNA3D_COMPAREFUNCTION_LESSEQUAL */ - VK_COMPARE_OP_EQUAL, /* FNA3D_COMPAREFUNCTION_EQUAL */ - VK_COMPARE_OP_GREATER_OR_EQUAL, /* FNA3D_COMPAREFUNCTION_GREATEREQUAL */ - VK_COMPARE_OP_GREATER, /* FNA3D_COMPAREFUNCTION_GREATER */ - VK_COMPARE_OP_NOT_EQUAL /* FNA3D_COMPAREFUNCTION_NOTEQUAL */ -}; - -static VkStencilOp XNAToVK_StencilOp[] = -{ - VK_STENCIL_OP_KEEP, /* FNA3D_STENCILOPERATION_KEEP */ - VK_STENCIL_OP_ZERO, /* FNA3D_STENCILOPERATION_ZERO */ - VK_STENCIL_OP_REPLACE, /* FNA3D_STENCILOPERATION_REPLACE */ - VK_STENCIL_OP_INCREMENT_AND_WRAP, /* FNA3D_STENCILOPERATION_INCREMENT */ - VK_STENCIL_OP_DECREMENT_AND_WRAP, /* FNA3D_STENCILOPERATION_DECREMENT */ - VK_STENCIL_OP_INCREMENT_AND_CLAMP, /* FNA3D_STENCILOPERATION_INCREMENTSATURATION */ - VK_STENCIL_OP_DECREMENT_AND_CLAMP, /* FNA3D_STENCILOPERATION_DECREMENTSATURATION */ - VK_STENCIL_OP_INVERT /* FNA3D_STENCILOPERATION_INVERT */ -}; - -static VkFormat XNAToVK_VertexAttribType[] = -{ - VK_FORMAT_R32_SFLOAT, /* FNA3D_VERTEXELEMENTFORMAT_SINGLE */ - VK_FORMAT_R32G32_SFLOAT, /* FNA3D_VERTEXELEMENTFORMAT_VECTOR2 */ - VK_FORMAT_R32G32B32_SFLOAT, /* FNA3D_VERTEXELEMENTFORMAT_VECTOR3 */ - VK_FORMAT_R32G32B32A32_SFLOAT, /* FNA3D_VERTEXELEMENTFORMAT_VECTOR4 */ - VK_FORMAT_R8G8B8A8_UNORM, /* FNA3D_VERTEXELEMENTFORMAT_COLOR */ - VK_FORMAT_R8G8B8A8_USCALED, /* FNA3D_VERTEXELEMENTFORMAT_BYTE4 */ - VK_FORMAT_R16G16_SSCALED, /* FNA3D_VERTEXELEMENTFORMAT_SHORT2 */ - VK_FORMAT_R16G16B16A16_SSCALED, /* FNA3D_VERTEXELEMENTFORMAT_SHORT4 */ - VK_FORMAT_R16G16_SNORM, /* FNA3D_VERTEXELEMENTFORMAT_NORMALIZEDSHORT2 */ - VK_FORMAT_R16G16B16A16_SNORM, /* FNA3D_VERTEXELEMENTFORMAT_NORMALIZEDSHORT4 */ - VK_FORMAT_R16G16_SFLOAT, /* FNA3D_VERTEXELEMENTFORMAT_HALFVECTOR2 */ - VK_FORMAT_R16G16B16A16_SFLOAT /* FNA3D_VERTEXELEMENTFORMAT_HALFVECTOR4 */ -}; - -/* Error Handling */ - -static inline const char* VkErrorMessages(VkResult code) -{ - #define ERR_TO_STR(e) \ - case e: return #e; - switch (code) - { - ERR_TO_STR(VK_ERROR_OUT_OF_HOST_MEMORY) - ERR_TO_STR(VK_ERROR_OUT_OF_DEVICE_MEMORY) - ERR_TO_STR(VK_ERROR_FRAGMENTED_POOL) - ERR_TO_STR(VK_ERROR_OUT_OF_POOL_MEMORY) - ERR_TO_STR(VK_ERROR_INITIALIZATION_FAILED) - ERR_TO_STR(VK_ERROR_LAYER_NOT_PRESENT) - ERR_TO_STR(VK_ERROR_EXTENSION_NOT_PRESENT) - ERR_TO_STR(VK_ERROR_FEATURE_NOT_PRESENT) - ERR_TO_STR(VK_ERROR_TOO_MANY_OBJECTS) - ERR_TO_STR(VK_ERROR_DEVICE_LOST) - ERR_TO_STR(VK_ERROR_INCOMPATIBLE_DRIVER) - ERR_TO_STR(VK_ERROR_OUT_OF_DATE_KHR) - ERR_TO_STR(VK_ERROR_SURFACE_LOST_KHR) - ERR_TO_STR(VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT) - ERR_TO_STR(VK_SUBOPTIMAL_KHR) - default: return "Unhandled VkResult!"; - } - #undef ERR_TO_STR -} - -#define VULKAN_ERROR_CHECK(res, fn, ret) \ - if (res != VK_SUCCESS) \ - { \ - FNA3D_LogError("%s %s", #fn, VkErrorMessages(res)); \ - return ret; \ - } - -/* Forward Declarations */ - -static CreateSwapchainResult VULKAN_INTERNAL_CreateSwapchain(VulkanRenderer* renderer, void* windowHandle); -static void VULKAN_INTERNAL_RecreateSwapchain(VulkanRenderer *renderer, void *windowHandle); - -static void VULKAN_INTERNAL_MaybeEndRenderPass(VulkanRenderer *renderer); - -/* Vulkan: Internal Implementation */ - -/* Vulkan: Extensions */ - -static inline uint8_t SupportsInstanceExtension( - const char *ext, - VkExtensionProperties *availableExtensions, - uint32_t numAvailableExtensions -) { - uint32_t i; - for (i = 0; i < numAvailableExtensions; i += 1) - { - if (SDL_strcmp(ext, availableExtensions[i].extensionName) == 0) - { - return 1; - } - } - return 0; -} - -static uint8_t VULKAN_INTERNAL_CheckInstanceExtensions( - uint8_t debugMode, - const char **requiredExtensions, - uint32_t requiredExtensionsLength, - uint8_t *supportsDeviceProperties2, - uint8_t *supportsDebugUtils -) { - uint32_t extensionCount, i; - VkExtensionProperties *availableExtensions; - uint8_t allExtensionsSupported = 1; - - vkEnumerateInstanceExtensionProperties( - NULL, - &extensionCount, - NULL - ); - availableExtensions = SDL_malloc( - extensionCount * sizeof(VkExtensionProperties) - ); - vkEnumerateInstanceExtensionProperties( - NULL, - &extensionCount, - availableExtensions - ); - - for (i = 0; i < requiredExtensionsLength; i += 1) - { - if (!SupportsInstanceExtension( - requiredExtensions[i], - availableExtensions, - extensionCount - )) { - allExtensionsSupported = 0; - break; - } - } - - /* These are optional, but nice to have! */ - *supportsDeviceProperties2 = SupportsInstanceExtension( - VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, - availableExtensions, - extensionCount - ); - *supportsDebugUtils = debugMode && SupportsInstanceExtension( - VK_EXT_DEBUG_UTILS_EXTENSION_NAME, - availableExtensions, - extensionCount - ); - - SDL_free(availableExtensions); - return allExtensionsSupported; -} - -static uint8_t VULKAN_INTERNAL_CheckDeviceExtensions( - VulkanRenderer *renderer, - VkPhysicalDevice physicalDevice, - VulkanExtensions *physicalDeviceExtensions -) { - uint32_t extensionCount; - VkExtensionProperties *availableExtensions; - uint8_t allExtensionsSupported; - - renderer->vkEnumerateDeviceExtensionProperties( - physicalDevice, - NULL, - &extensionCount, - NULL - ); - availableExtensions = (VkExtensionProperties*) SDL_malloc( - extensionCount * sizeof(VkExtensionProperties) - ); - renderer->vkEnumerateDeviceExtensionProperties( - physicalDevice, - NULL, - &extensionCount, - availableExtensions - ); - - allExtensionsSupported = CheckDeviceExtensions( - availableExtensions, - extensionCount, - physicalDeviceExtensions - ); - - SDL_free(availableExtensions); - return allExtensionsSupported; -} - -/* Vulkan: Validation Layers */ - -static uint8_t VULKAN_INTERNAL_CheckValidationLayers( - const char** validationLayers, - uint32_t validationLayersLength -) { - uint32_t layerCount; - VkLayerProperties *availableLayers; - uint32_t i, j; - uint8_t layerFound; - - vkEnumerateInstanceLayerProperties(&layerCount, NULL); - availableLayers = (VkLayerProperties*) SDL_malloc( - layerCount * sizeof(VkLayerProperties) - ); - vkEnumerateInstanceLayerProperties(&layerCount, availableLayers); - - for (i = 0; i < validationLayersLength; i += 1) - { - layerFound = 0; - - for (j = 0; j < layerCount; j += 1) - { - if (SDL_strcmp(validationLayers[i], availableLayers[j].layerName) == 0) - { - layerFound = 1; - break; - } - } - - if (!layerFound) - { - break; - } - } - - SDL_free(availableLayers); - return layerFound; -} - -/* Vulkan: Device Feature Queries */ - -static uint8_t VULKAN_INTERNAL_QuerySwapChainSupport( - VulkanRenderer *renderer, - VkPhysicalDevice physicalDevice, - VkSurfaceKHR surface, - SwapChainSupportDetails *outputDetails -) { - VkResult result; - VkBool32 supportsPresent; - - renderer->vkGetPhysicalDeviceSurfaceSupportKHR( - physicalDevice, - renderer->queueFamilyIndex, - surface, - &supportsPresent - ); - - /* Initialize these in case anything fails */ - outputDetails->formatsLength = 0; - outputDetails->presentModesLength = 0; - - if (!supportsPresent) - { - FNA3D_LogWarn("This surface does not support presenting!"); - return 0; - } - - /* Run the device surface queries */ - result = renderer->vkGetPhysicalDeviceSurfaceCapabilitiesKHR( - physicalDevice, - surface, - &outputDetails->capabilities - ); - VULKAN_ERROR_CHECK(result, vkGetPhysicalDeviceSurfaceCapabilitiesKHR, 0) - - if (!(outputDetails->capabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR)) - { - FNA3D_LogWarn("Opaque presentation unsupported! Expect weird transparency bugs!"); - } - - result = renderer->vkGetPhysicalDeviceSurfaceFormatsKHR( - physicalDevice, - surface, - &outputDetails->formatsLength, - NULL - ); - VULKAN_ERROR_CHECK(result, vkGetPhysicalDeviceSurfaceFormatsKHR, 0) - result = renderer->vkGetPhysicalDeviceSurfacePresentModesKHR( - physicalDevice, - surface, - &outputDetails->presentModesLength, - NULL - ); - VULKAN_ERROR_CHECK(result, vkGetPhysicalDeviceSurfacePresentModesKHR, 0) - - /* Generate the arrays, if applicable */ - if (outputDetails->formatsLength != 0) - { - outputDetails->formats = (VkSurfaceFormatKHR*) SDL_malloc( - sizeof(VkSurfaceFormatKHR) * outputDetails->formatsLength - ); - - if (!outputDetails->formats) - { - SDL_OutOfMemory(); - return 0; - } - - result = renderer->vkGetPhysicalDeviceSurfaceFormatsKHR( - physicalDevice, - surface, - &outputDetails->formatsLength, - outputDetails->formats - ); - if (result != VK_SUCCESS) - { - FNA3D_LogError( - "vkGetPhysicalDeviceSurfaceFormatsKHR: %s", - VkErrorMessages(result) - ); - - SDL_free(outputDetails->formats); - return 0; - } - } - if (outputDetails->presentModesLength != 0) - { - outputDetails->presentModes = (VkPresentModeKHR*) SDL_malloc( - sizeof(VkPresentModeKHR) * outputDetails->presentModesLength - ); - - if (!outputDetails->presentModes) - { - SDL_OutOfMemory(); - return 0; - } - - result = renderer->vkGetPhysicalDeviceSurfacePresentModesKHR( - physicalDevice, - surface, - &outputDetails->presentModesLength, - outputDetails->presentModes - ); - if (result != VK_SUCCESS) - { - FNA3D_LogError( - "vkGetPhysicalDeviceSurfacePresentModesKHR: %s", - VkErrorMessages(result) - ); - - SDL_free(outputDetails->formats); - SDL_free(outputDetails->presentModes); - return 0; - } - } - - /* If we made it here, all the queries were successfull. This does NOT - * necessarily mean there are any supported formats or present modes! - */ - return 1; -} - -static uint8_t VULKAN_INTERNAL_ChooseSwapSurfaceFormat( - VkFormat desiredFormat, - VkSurfaceFormatKHR *availableFormats, - uint32_t availableFormatsLength, - VkSurfaceFormatKHR *outputFormat -) { - uint32_t i; - VkColorSpaceKHR colorSpace; - - if (SDL_GetHintBoolean("FNA3D_ENABLE_HDR_COLORSPACE", SDL_FALSE)) - { - if ( desiredFormat == VK_FORMAT_A2R10G10B10_UNORM_PACK32 || - desiredFormat == VK_FORMAT_A2B10G10R10_UNORM_PACK32 ) - { - colorSpace = VK_COLOR_SPACE_HDR10_ST2084_EXT; - } - else if (desiredFormat == VK_FORMAT_R16G16B16A16_SFLOAT) - { - colorSpace = VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT; - } - else - { - colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; - } - } - else - { - colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; - } - - for (i = 0; i < availableFormatsLength; i += 1) - { - if ( availableFormats[i].format == desiredFormat && - availableFormats[i].colorSpace == colorSpace ) - { - *outputFormat = availableFormats[i]; - return 1; - } - } - return 0; -} - -static uint8_t VULKAN_INTERNAL_ChooseSwapPresentMode( - FNA3D_PresentInterval desiredPresentInterval, - VkPresentModeKHR *availablePresentModes, - uint32_t availablePresentModesLength, - VkPresentModeKHR *outputPresentMode -) { - #define CHECK_MODE(m) \ - for (i = 0; i < availablePresentModesLength; i += 1) \ - { \ - if (availablePresentModes[i] == m) \ - { \ - *outputPresentMode = m; \ - FNA3D_LogInfo("Using " #m "!"); \ - return 1; \ - } \ - } \ - FNA3D_LogInfo(#m " unsupported."); - - uint32_t i; - if ( desiredPresentInterval == FNA3D_PRESENTINTERVAL_DEFAULT || - desiredPresentInterval == FNA3D_PRESENTINTERVAL_ONE ) - { - if (SDL_GetHintBoolean("FNA3D_ENABLE_LATESWAPTEAR", 0)) - { - CHECK_MODE(VK_PRESENT_MODE_FIFO_RELAXED_KHR) - } - else if (SDL_GetHintBoolean("FNA3D_VULKAN_FORCE_MAILBOX_VSYNC", 0)) - { - CHECK_MODE(VK_PRESENT_MODE_MAILBOX_KHR) - } - else - { - *outputPresentMode = VK_PRESENT_MODE_FIFO_KHR; - return 1; - } - } - else if (desiredPresentInterval == FNA3D_PRESENTINTERVAL_IMMEDIATE) - { - CHECK_MODE(VK_PRESENT_MODE_IMMEDIATE_KHR) - - /* Some implementations have mailbox in place of immediate. */ - FNA3D_LogInfo("Fall back to VK_PRESENT_MODE_MAILBOX_KHR."); - CHECK_MODE(VK_PRESENT_MODE_MAILBOX_KHR) - } - else if (desiredPresentInterval == FNA3D_PRESENTINTERVAL_TWO) - { - FNA3D_LogError("FNA3D_PRESENTINTERVAL_TWO not supported in Vulkan"); - return 0; - } - else - { - FNA3D_LogError( - "Unrecognized PresentInterval: %d", - desiredPresentInterval - ); - return 0; - } - - #undef CHECK_MODE - - FNA3D_LogInfo("Fall back to VK_PRESENT_MODE_FIFO_KHR."); - *outputPresentMode = VK_PRESENT_MODE_FIFO_KHR; - return 1; -} - -static uint8_t VULKAN_INTERNAL_FindMemoryType( - VulkanRenderer *renderer, - uint32_t typeFilter, - VkMemoryPropertyFlags requiredProperties, - VkMemoryPropertyFlags ignoredProperties, - uint32_t *memoryTypeIndex -) { - uint32_t i; - - for (i = *memoryTypeIndex; i < renderer->memoryProperties.memoryTypeCount; i += 1) - { - if ( (typeFilter & (1 << i)) && - (renderer->memoryProperties.memoryTypes[i].propertyFlags & requiredProperties) == requiredProperties && - (renderer->memoryProperties.memoryTypes[i].propertyFlags & ignoredProperties) == 0 ) - { - *memoryTypeIndex = i; - return 1; - } - } - - FNA3D_LogWarn( - "Failed to find memory type %X, required %X, ignored %X", - typeFilter, - requiredProperties, - ignoredProperties - ); - return 0; -} - -static uint8_t VULKAN_INTERNAL_IsDeviceSuitable( - VulkanRenderer *renderer, - VkPhysicalDevice physicalDevice, - VulkanExtensions *physicalDeviceExtensions, - VkSurfaceKHR surface, - uint32_t *queueFamilyIndex, - uint8_t *deviceRank -) { - uint32_t queueFamilyCount, queueFamilyRank, queueFamilyBest; - SwapChainSupportDetails swapchainSupportDetails; - VkQueueFamilyProperties *queueProps; - VkBool32 supportsPresent; - uint8_t querySuccess; - VkPhysicalDeviceProperties deviceProperties; - uint32_t i; - - /* Get the device rank before doing any checks, in case one fails. - * Note: If no dedicated device exists, one that supports our features - * would be fine - */ - renderer->vkGetPhysicalDeviceProperties( - physicalDevice, - &deviceProperties - ); - if (*deviceRank < DEVICE_PRIORITY[deviceProperties.deviceType]) - { - /* This device outranks the best device we've found so far! - * This includes a dedicated GPU that has less features than an - * integrated GPU, because this is a freak case that is almost - * never intentionally desired by the end user - */ - *deviceRank = DEVICE_PRIORITY[deviceProperties.deviceType]; - } - else if (*deviceRank > DEVICE_PRIORITY[deviceProperties.deviceType]) - { - /* Device is outranked by a previous device, don't even try to - * run a query and reset the rank to avoid overwrites - */ - *deviceRank = 0; - return 0; - } - - if (!VULKAN_INTERNAL_CheckDeviceExtensions( - renderer, - physicalDevice, - physicalDeviceExtensions - )) { - return 0; - } - - renderer->vkGetPhysicalDeviceQueueFamilyProperties( - physicalDevice, - &queueFamilyCount, - NULL - ); - - queueProps = (VkQueueFamilyProperties*) SDL_stack_alloc( - VkQueueFamilyProperties, - queueFamilyCount - ); - renderer->vkGetPhysicalDeviceQueueFamilyProperties( - physicalDevice, - &queueFamilyCount, - queueProps - ); - - queueFamilyBest = 0; - *queueFamilyIndex = UINT32_MAX; - for (i = 0; i < queueFamilyCount; i += 1) - { - renderer->vkGetPhysicalDeviceSurfaceSupportKHR( - physicalDevice, - i, - surface, - &supportsPresent - ); - if ( !supportsPresent || - !(queueProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) ) - { - /* Not a graphics family, ignore. */ - continue; - } - - /* The queue family bitflags are kind of annoying. - * - * We of course need a graphics family, but we ideally want the - * _primary_ graphics family. The spec states that at least one - * graphics family must also be a compute family, so generally - * drivers make that the first one. But hey, maybe something - * genuinely can't do compute or something, and FNA doesn't - * need it, so we'll be open to a non-compute queue family. - * - * Additionally, it's common to see the primary queue family - * have the transfer bit set, which is great! But this is - * actually optional; it's impossible to NOT have transfers in - * graphics/compute but it _is_ possible for a graphics/compute - * family, even the primary one, to just decide not to set the - * bitflag. Admittedly, a driver may want to isolate transfer - * queues to a dedicated family so that queues made solely for - * transfers can have an optimized DMA queue. - * - * That, or the driver author got lazy and decided not to set - * the bit. Looking at you, Android. - * - * -flibit - */ - if (queueProps[i].queueFlags & VK_QUEUE_COMPUTE_BIT) - { - if (queueProps[i].queueFlags & VK_QUEUE_TRANSFER_BIT) - { - /* Has all attribs! */ - queueFamilyRank = 3; - } - else - { - /* Probably has a DMA transfer queue family */ - queueFamilyRank = 2; - } - } - else - { - /* Just a graphics family, probably has something better */ - queueFamilyRank = 1; - } - if (queueFamilyRank > queueFamilyBest) - { - *queueFamilyIndex = i; - queueFamilyBest = queueFamilyRank; - } - } - - SDL_stack_free(queueProps); - - if (*queueFamilyIndex == UINT32_MAX) - { - /* Somehow no graphics queues existed. Compute-only device? */ - return 0; - } - - /* FIXME: Need better structure for checking vs storing support details */ - querySuccess = VULKAN_INTERNAL_QuerySwapChainSupport( - renderer, - physicalDevice, - surface, - &swapchainSupportDetails - ); - if (swapchainSupportDetails.formatsLength > 0) - { - SDL_free(swapchainSupportDetails.formats); - } - if (swapchainSupportDetails.presentModesLength > 0) - { - SDL_free(swapchainSupportDetails.presentModes); - } - - return ( querySuccess && - swapchainSupportDetails.formatsLength > 0 && - swapchainSupportDetails.presentModesLength > 0 ); -} - -/* Vulkan: vkInstance/vkDevice Creation */ - -static VkBool32 VKAPI_PTR VULKAN_INTERNAL_DebugCallback( - VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, - VkDebugUtilsMessageTypeFlagsEXT messageTypes, - const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData, - void* pUserData -) { - void (*logFunc)(const char *fmt, ...); - if (messageSeverity >= VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) - { - logFunc = FNA3D_LogError; - } - else if (messageSeverity >= VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) - { - logFunc = FNA3D_LogWarn; - } - else - { - logFunc = FNA3D_LogInfo; - } - logFunc("VULKAN DEBUG: %s", pCallbackData->pMessage); - return VK_FALSE; -} - -static uint8_t VULKAN_INTERNAL_CreateInstance( - VulkanRenderer *renderer, - FNA3D_PresentationParameters *presentationParameters -) { - VkResult vulkanResult; - VkApplicationInfo appInfo; -#if SDL_MAJOR_VERSION >= 3 - char const* const* inferredExtensionNames; -#endif - const char **instanceExtensionNames; - uint32_t instanceExtensionCount; - VkInstanceCreateInfo createInfo; - VkDebugUtilsMessengerCreateInfoEXT debugMessengerCreateInfo; - static const char *layerNames[] = { "VK_LAYER_KHRONOS_validation" }; - - appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; - appInfo.pNext = NULL; - appInfo.pApplicationName = NULL; - appInfo.applicationVersion = 0; - appInfo.pEngineName = "FNA3D"; - appInfo.engineVersion = FNA3D_COMPILED_VERSION; - appInfo.apiVersion = VK_MAKE_VERSION(1, 0, 0); - -#if SDL_MAJOR_VERSION >= 3 - inferredExtensionNames = SDL_Vulkan_GetInstanceExtensions(&instanceExtensionCount); - - if (inferredExtensionNames == NULL) - { - FNA3D_LogWarn( - "SDL_Vulkan_GetInstanceExtensions(): %s", - SDL_GetError() - ); - goto create_instance_fail; - } - - /* Extra space for the following extensions: - * VK_KHR_get_physical_device_properties2 - * VK_EXT_debug_utils - */ - instanceExtensionNames = SDL_stack_alloc( - const char*, - instanceExtensionCount + 2 - ); - - for (uint32_t i = 0; i < instanceExtensionCount; i += 1) - { - instanceExtensionNames[i] = inferredExtensionNames[i]; - } -#else - if (!SDL_Vulkan_GetInstanceExtensions( - (SDL_Window*) presentationParameters->deviceWindowHandle, - &instanceExtensionCount, - NULL - )) { - FNA3D_LogWarn( - "SDL_Vulkan_GetInstanceExtensions(): getExtensionCount: %s", - SDL_GetError() - ); - - return 0; - } - - /* Extra space for the following extensions: - * VK_KHR_get_physical_device_properties2 - * VK_EXT_debug_utils - */ - instanceExtensionNames = SDL_stack_alloc( - const char*, - instanceExtensionCount + 2 - ); - - if (!SDL_Vulkan_GetInstanceExtensions( - (SDL_Window*) presentationParameters->deviceWindowHandle, - &instanceExtensionCount, - instanceExtensionNames - )) { - FNA3D_LogWarn( - "SDL_Vulkan_GetInstanceExtensions(): %s", - SDL_GetError() - ); - goto create_instance_fail; - } -#endif - - if (!VULKAN_INTERNAL_CheckInstanceExtensions( - renderer->debugMode, - instanceExtensionNames, - instanceExtensionCount, - &renderer->supportsDeviceProperties2, - &renderer->supportsDebugUtils - )) { - FNA3D_LogWarn( - "Required Vulkan instance extensions not supported" - ); - goto create_instance_fail; - } - - if (renderer->supportsDeviceProperties2) - { - instanceExtensionNames[instanceExtensionCount++] = - VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME; - } - else - { - FNA3D_LogWarn( - "%s is not supported!", - VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME - ); - } - - if (renderer->supportsDebugUtils) - { - instanceExtensionNames[instanceExtensionCount++] = - VK_EXT_DEBUG_UTILS_EXTENSION_NAME; - } - else if (renderer->debugMode) - { - FNA3D_LogWarn( - "%s is not supported!", - VK_EXT_DEBUG_UTILS_EXTENSION_NAME - ); - } - - createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; - createInfo.pNext = NULL; - createInfo.flags = 0; - createInfo.pApplicationInfo = &appInfo; - createInfo.ppEnabledLayerNames = layerNames; - createInfo.enabledExtensionCount = instanceExtensionCount; - createInfo.ppEnabledExtensionNames = instanceExtensionNames; - if (renderer->debugMode) - { - createInfo.enabledLayerCount = SDL_arraysize(layerNames); - if (VULKAN_INTERNAL_CheckValidationLayers( - layerNames, - createInfo.enabledLayerCount - )) { - FNA3D_LogInfo("Vulkan validation enabled! Expect debug-level performance!"); - } - else - { - FNA3D_LogWarn("Validation layers not found, continuing without validation"); - createInfo.enabledLayerCount = 0; - } - } - else - { - createInfo.enabledLayerCount = 0; - } - if (renderer->supportsDebugUtils) - { - debugMessengerCreateInfo.sType = - VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT; - debugMessengerCreateInfo.pNext = NULL; - debugMessengerCreateInfo.flags = 0; - debugMessengerCreateInfo.messageSeverity = ( - VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | - VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT | - VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | - VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT - ); - debugMessengerCreateInfo.messageType = ( - VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | - VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | - VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT - ); - debugMessengerCreateInfo.pfnUserCallback = VULKAN_INTERNAL_DebugCallback; - debugMessengerCreateInfo.pUserData = NULL; - - createInfo.pNext = &debugMessengerCreateInfo; - } - - vulkanResult = vkCreateInstance(&createInfo, NULL, &renderer->instance); - if (vulkanResult != VK_SUCCESS) - { - FNA3D_LogWarn( - "vkCreateInstance failed: %s", - VkErrorMessages(vulkanResult) - ); - goto create_instance_fail; - } - - SDL_stack_free((char*) instanceExtensionNames); - return 1; - -create_instance_fail: - SDL_stack_free((char*) instanceExtensionNames); - return 0; -} - -static uint8_t VULKAN_INTERNAL_DeterminePhysicalDevice(VulkanRenderer *renderer, VkSurfaceKHR surface) -{ - VkResult vulkanResult; - VkPhysicalDevice *physicalDevices; - VulkanExtensions *physicalDeviceExtensions; - uint32_t physicalDeviceCount, i, suitableIndex; - uint32_t queueFamilyIndex, suitableQueueFamilyIndex; - VkDeviceSize deviceLocalHeapSize; - const char *deviceLocalHeapUsageFactorStr; - float deviceLocalHeapUsageFactor = 1.0f; - uint8_t deviceRank, highestRank; - - vulkanResult = renderer->vkEnumeratePhysicalDevices( - renderer->instance, - &physicalDeviceCount, - NULL - ); - VULKAN_ERROR_CHECK(vulkanResult, vkEnumeratePhysicalDevices, 0) - - if (physicalDeviceCount == 0) - { - FNA3D_LogWarn("Failed to find any GPUs with Vulkan support"); - return 0; - } - - physicalDevices = SDL_stack_alloc(VkPhysicalDevice, physicalDeviceCount); - physicalDeviceExtensions = SDL_stack_alloc(VulkanExtensions, physicalDeviceCount); - - vulkanResult = renderer->vkEnumeratePhysicalDevices( - renderer->instance, - &physicalDeviceCount, - physicalDevices - ); - - /* This should be impossible to hit, but from what I can tell this can - * be triggerd not because the array is too small, but because there - * were drivers that turned out to be bogus, so this is the loader's way - * of telling us that the list is now smaller than expected :shrug: - */ - if (vulkanResult == VK_INCOMPLETE) - { - FNA3D_LogWarn("vkEnumeratePhysicalDevices returned VK_INCOMPLETE, will keep trying anyway..."); - vulkanResult = VK_SUCCESS; - } - - if (vulkanResult != VK_SUCCESS) - { - FNA3D_LogWarn( - "vkEnumeratePhysicalDevices failed: %s", - VkErrorMessages(vulkanResult) - ); - SDL_stack_free(physicalDevices); - SDL_stack_free(physicalDeviceExtensions); - return 0; - } - - /* Any suitable device will do, but we'd like the best */ - suitableIndex = -1; - highestRank = 0; - for (i = 0; i < physicalDeviceCount; i += 1) - { - deviceRank = highestRank; - if (VULKAN_INTERNAL_IsDeviceSuitable( - renderer, - physicalDevices[i], - &physicalDeviceExtensions[i], - surface, - &queueFamilyIndex, - &deviceRank - )) { - /* Use this for rendering. - * Note that this may override a previous device that - * supports rendering, but shares the same device rank. - */ - suitableIndex = i; - suitableQueueFamilyIndex = queueFamilyIndex; - highestRank = deviceRank; - } - else if (deviceRank > highestRank) - { - /* In this case, we found a... "realer?" GPU, - * but it doesn't actually support our Vulkan. - * We should disqualify all devices below as a - * result, because if we don't we end up - * ignoring real hardware and risk using - * something like LLVMpipe instead! - * -flibit - */ - suitableIndex = -1; - highestRank = deviceRank; - } - } - - if (suitableIndex != -1) - { - renderer->supports = physicalDeviceExtensions[suitableIndex]; - renderer->physicalDevice = physicalDevices[suitableIndex]; - renderer->queueFamilyIndex = suitableQueueFamilyIndex; - } - else - { - SDL_stack_free(physicalDevices); - SDL_stack_free(physicalDeviceExtensions); - return 0; - } - - if ( renderer->supportsDeviceProperties2 && - renderer->supports.KHR_driver_properties ) - { - renderer->physicalDeviceProperties.sType = - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; - renderer->physicalDeviceProperties.pNext = - &renderer->physicalDeviceDriverProperties; - - renderer->physicalDeviceDriverProperties.sType = - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES_KHR; - renderer->physicalDeviceDriverProperties.pNext = NULL; - - renderer->vkGetPhysicalDeviceProperties2KHR( - renderer->physicalDevice, - &renderer->physicalDeviceProperties - ); - } - else - { - /* These won't be used, just initialize them to something */ - renderer->physicalDeviceProperties.sType = ~0; - renderer->physicalDeviceProperties.pNext = NULL; - - renderer->vkGetPhysicalDeviceProperties( - renderer->physicalDevice, - &renderer->physicalDeviceProperties.properties - ); - } - - renderer->vkGetPhysicalDeviceMemoryProperties( - renderer->physicalDevice, - &renderer->memoryProperties - ); - - deviceLocalHeapUsageFactorStr = SDL_GetHint("FNA3D_VULKAN_DEVICE_LOCAL_HEAP_USAGE_FACTOR"); - if (deviceLocalHeapUsageFactorStr != NULL) - { - double factor = SDL_atof(deviceLocalHeapUsageFactorStr); - if (factor > 0.0 && factor < 1.0) - { - deviceLocalHeapUsageFactor = factor; - } - - deviceLocalHeapSize = 0; - for (i = 0; i < renderer->memoryProperties.memoryHeapCount; i += 1) - { - if ( renderer->memoryProperties.memoryHeaps[i].flags & - VK_MEMORY_HEAP_DEVICE_LOCAL_BIT ) - { - if (renderer->memoryProperties.memoryHeaps[i].size > deviceLocalHeapSize) - { - deviceLocalHeapSize = renderer->memoryProperties.memoryHeaps[i].size; - } - } - } - - renderer->maxDeviceLocalHeapUsage = deviceLocalHeapSize * deviceLocalHeapUsageFactor; - } - else - { - /* Don't even attempt to track this, let the driver do the work */ - renderer->maxDeviceLocalHeapUsage = UINT64_MAX; - } - - renderer->deviceLocalHeapUsage = 0; - - SDL_stack_free(physicalDevices); - SDL_stack_free(physicalDeviceExtensions); - return 1; -} - -static uint8_t VULKAN_INTERNAL_CreateLogicalDevice(VulkanRenderer *renderer) -{ - VkResult vulkanResult; - VkDeviceCreateInfo deviceCreateInfo; - VkPhysicalDeviceFeatures deviceFeatures; - VkPhysicalDevicePortabilitySubsetFeaturesKHR portabilityFeatures; - const char **deviceExtensions; - - VkDeviceQueueCreateInfo queueCreateInfo; - float queuePriority = 1.0f; - - queueCreateInfo.sType = - VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; - queueCreateInfo.pNext = NULL; - queueCreateInfo.flags = 0; - queueCreateInfo.queueFamilyIndex = renderer->queueFamilyIndex; - queueCreateInfo.queueCount = 1; - queueCreateInfo.pQueuePriorities = &queuePriority; - - /* specifying used device features */ - - SDL_zero(deviceFeatures); - deviceFeatures.occlusionQueryPrecise = renderer->supportsPreciseOcclusionQueries; - deviceFeatures.fillModeNonSolid = VK_TRUE; - deviceFeatures.samplerAnisotropy = VK_TRUE; - - /* Creating the logical device */ - - deviceCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; - if (renderer->supports.KHR_portability_subset) - { - portabilityFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PORTABILITY_SUBSET_FEATURES_KHR; - portabilityFeatures.pNext = NULL; - portabilityFeatures.constantAlphaColorBlendFactors = VK_FALSE; - portabilityFeatures.events = VK_FALSE; - portabilityFeatures.imageViewFormatReinterpretation = VK_FALSE; - portabilityFeatures.imageViewFormatSwizzle = VK_TRUE; - portabilityFeatures.imageView2DOn3DImage = VK_FALSE; - portabilityFeatures.multisampleArrayImage = VK_FALSE; - portabilityFeatures.mutableComparisonSamplers = VK_FALSE; - portabilityFeatures.pointPolygons = VK_FALSE; - portabilityFeatures.samplerMipLodBias = VK_FALSE; /* Technically should be true, but eh */ - portabilityFeatures.separateStencilMaskRef = VK_FALSE; - portabilityFeatures.shaderSampleRateInterpolationFunctions = VK_FALSE; - portabilityFeatures.tessellationIsolines = VK_FALSE; - portabilityFeatures.tessellationPointMode = VK_FALSE; - portabilityFeatures.triangleFans = VK_FALSE; - portabilityFeatures.vertexAttributeAccessBeyondStride = VK_FALSE; - deviceCreateInfo.pNext = &portabilityFeatures; - } - else - { - deviceCreateInfo.pNext = NULL; - } - deviceCreateInfo.flags = 0; - deviceCreateInfo.queueCreateInfoCount = 1; - deviceCreateInfo.pQueueCreateInfos = &queueCreateInfo; - deviceCreateInfo.enabledLayerCount = 0; - deviceCreateInfo.ppEnabledLayerNames = NULL; - deviceCreateInfo.enabledExtensionCount = GetDeviceExtensionCount( - &renderer->supports - ); - deviceExtensions = SDL_stack_alloc( - const char*, - deviceCreateInfo.enabledExtensionCount - ); - CreateDeviceExtensionArray(&renderer->supports, deviceExtensions); - deviceCreateInfo.ppEnabledExtensionNames = deviceExtensions; - deviceCreateInfo.pEnabledFeatures = &deviceFeatures; - - vulkanResult = renderer->vkCreateDevice( - renderer->physicalDevice, - &deviceCreateInfo, - NULL, - &renderer->logicalDevice - ); - SDL_stack_free(deviceExtensions); - VULKAN_ERROR_CHECK(vulkanResult, vkCreateDevice, 0) - - /* Load vkDevice entry points */ - - #define VULKAN_DEVICE_FUNCTION(name) \ - renderer->name = (PFN_##name) \ - renderer->vkGetDeviceProcAddr( \ - renderer->logicalDevice, \ - #name \ - ); - #include "FNA3D_Driver_Vulkan_vkfuncs.h" - - renderer->vkGetDeviceQueue( - renderer->logicalDevice, - renderer->queueFamilyIndex, - 0, - &renderer->unifiedQueue - ); - - return 1; -} - -/* Vulkan: Memory Allocation */ - -static uint8_t VULKAN_INTERNAL_FindBufferMemoryRequirements( - VulkanRenderer *renderer, - VkBuffer buffer, - VkMemoryPropertyFlags requiredMemoryProperties, - VkMemoryPropertyFlags ignoredMemoryProperties, - VkMemoryRequirements *pMemoryRequirements, - uint32_t *pMemoryTypeIndex -) { - renderer->vkGetBufferMemoryRequirements( - renderer->logicalDevice, - buffer, - pMemoryRequirements - ); - - return VULKAN_INTERNAL_FindMemoryType( - renderer, - pMemoryRequirements->memoryTypeBits, - requiredMemoryProperties, - ignoredMemoryProperties, - pMemoryTypeIndex - ); -} - -static uint8_t VULKAN_INTERNAL_FindImageMemoryRequirements( - VulkanRenderer *renderer, - VkImage image, - VkMemoryPropertyFlags requiredMemoryPropertyFlags, - VkMemoryPropertyFlags ignoredMemoryPropertyFlags, - VkMemoryRequirements *pMemoryRequirements, - uint32_t *pMemoryTypeIndex -) { - renderer->vkGetImageMemoryRequirements( - renderer->logicalDevice, - image, - pMemoryRequirements - ); - - return VULKAN_INTERNAL_FindMemoryType( - renderer, - pMemoryRequirements->memoryTypeBits, - requiredMemoryPropertyFlags, - ignoredMemoryPropertyFlags, - pMemoryTypeIndex - ); -} - -static uint8_t VULKAN_INTERNAL_BindMemoryForImage( - VulkanRenderer* renderer, - VkImage image, - VulkanTexture *imageHandle, - uint8_t isRenderTarget, - FNA3D_MemoryUsedRegion** usedRegion -) { - uint8_t bindResult = 0; - uint32_t memoryTypeIndex = 0; - VkMemoryPropertyFlags requiredMemoryPropertyFlags; - VkMemoryPropertyFlags ignoredMemoryPropertyFlags; - VkMemoryRequirements memoryRequirements; - - /* Prefer GPU allocation */ - requiredMemoryPropertyFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; - ignoredMemoryPropertyFlags = 0; - - while (VULKAN_INTERNAL_FindImageMemoryRequirements( - renderer, - image, - requiredMemoryPropertyFlags, - ignoredMemoryPropertyFlags, - &memoryRequirements, - &memoryTypeIndex - )) { - bindResult = FNA3D_Memory_BindResource( - renderer->allocator, - memoryTypeIndex, - memoryRequirements.size, - memoryRequirements.alignment, - (renderer->memoryProperties.memoryTypes[memoryTypeIndex].propertyFlags & - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0, - (renderer->memoryProperties.memoryTypes[memoryTypeIndex].propertyFlags & - VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) != 0, - isRenderTarget, - memoryRequirements.size, - 1, - (FNA3D_MemoryPlatformHandle) (size_t) image, - imageHandle, - usedRegion - ); - - if (bindResult == 1) - { - break; - } - else /* Bind failed, try the next device-local heap */ - { - memoryTypeIndex += 1; - } - } - - /* Bind _still_ failed, try again without device local */ - if (bindResult != 1) - { - memoryTypeIndex = 0; - requiredMemoryPropertyFlags = 0; - ignoredMemoryPropertyFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; - - if (isRenderTarget) - { - FNA3D_LogWarn("RenderTarget is allocated in host memory, pre-allocate your targets!"); - } - - FNA3D_LogWarn("Out of device local memory, falling back to host memory"); - - while (VULKAN_INTERNAL_FindImageMemoryRequirements( - renderer, - image, - requiredMemoryPropertyFlags, - ignoredMemoryPropertyFlags, - &memoryRequirements, - &memoryTypeIndex - )) { - bindResult = FNA3D_Memory_BindResource( - renderer->allocator, - memoryTypeIndex, - memoryRequirements.size, - memoryRequirements.alignment, - (renderer->memoryProperties.memoryTypes[memoryTypeIndex].propertyFlags & - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0, - (renderer->memoryProperties.memoryTypes[memoryTypeIndex].propertyFlags & - VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) != 0, - isRenderTarget, - memoryRequirements.size, - 1, - (FNA3D_MemoryPlatformHandle) (size_t) image, - imageHandle, - usedRegion - ); - - if (bindResult == 1) - { - break; - } - else /* Bind failed, try the next heap */ - { - memoryTypeIndex += 1; - } - } - } - - return bindResult; -} - -static uint8_t VULKAN_INTERNAL_BindMemoryForBuffer( - VulkanRenderer* renderer, - VkBuffer buffer, - VulkanBuffer *bufferHandle, - VkDeviceSize size, - uint8_t preferDeviceLocal, - uint8_t isTransferBuffer, - FNA3D_MemoryUsedRegion** usedRegion -) { - uint8_t bindResult = 0; - uint32_t memoryTypeIndex = 0; - VkMemoryPropertyFlags requiredMemoryPropertyFlags; - VkMemoryPropertyFlags ignoredMemoryPropertyFlags; - VkMemoryRequirements memoryRequirements; - - requiredMemoryPropertyFlags = - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | - VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; - - if (preferDeviceLocal) - { - requiredMemoryPropertyFlags |= - VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; - } - ignoredMemoryPropertyFlags = 0; - - while (VULKAN_INTERNAL_FindBufferMemoryRequirements( - renderer, - buffer, - requiredMemoryPropertyFlags, - ignoredMemoryPropertyFlags, - &memoryRequirements, - &memoryTypeIndex - )) { - bindResult = FNA3D_Memory_BindResource( - renderer->allocator, - memoryTypeIndex, - memoryRequirements.size, - memoryRequirements.alignment, - (renderer->memoryProperties.memoryTypes[memoryTypeIndex].propertyFlags & - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0, - (renderer->memoryProperties.memoryTypes[memoryTypeIndex].propertyFlags & - VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) != 0, - isTransferBuffer, - size, - 0, - (FNA3D_MemoryPlatformHandle) (size_t) buffer, - bufferHandle, - usedRegion - ); - - if (bindResult == 1) - { - break; - } - else /* Bind failed, try the next device-local heap */ - { - memoryTypeIndex += 1; - } - } - - /* Bind failed, try again if originally preferred device local */ - if (bindResult != 1 && preferDeviceLocal) - { - memoryTypeIndex = 0; - requiredMemoryPropertyFlags = - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | - VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; - - /* Follow-up for the warning logged by FindMemoryType */ - if (!renderer->unifiedMemoryWarning) - { - FNA3D_LogWarn("No unified memory found, falling back to host memory"); - renderer->unifiedMemoryWarning = 1; - } - - while (VULKAN_INTERNAL_FindBufferMemoryRequirements( - renderer, - buffer, - requiredMemoryPropertyFlags, - ignoredMemoryPropertyFlags, - &memoryRequirements, - &memoryTypeIndex - )) { - bindResult = FNA3D_Memory_BindResource( - renderer->allocator, - memoryTypeIndex, - memoryRequirements.size, - memoryRequirements.alignment, - (renderer->memoryProperties.memoryTypes[memoryTypeIndex].propertyFlags & - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0, - (renderer->memoryProperties.memoryTypes[memoryTypeIndex].propertyFlags & - VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) != 0, - isTransferBuffer, - size, - 0, - (FNA3D_MemoryPlatformHandle) (size_t) buffer, - bufferHandle, - usedRegion - ); - - if (bindResult == 1) - { - break; - } - else /* Bind failed, try the next heap */ - { - memoryTypeIndex += 1; - } - } - } - - return bindResult; -} - -/* Vulkan: Resource Disposal */ - -static void VULKAN_INTERNAL_DestroyBuffer( - VulkanRenderer *renderer, - VulkanBuffer *buffer -) { - renderer->vkDestroyBuffer( - renderer->logicalDevice, - buffer->buffer, - NULL - ); - - renderer->needDefrag |= FNA3D_INTERNAL_RemoveMemoryUsedRegion( - renderer->allocator, - buffer->usedRegion - ); - renderer->resourceFreed = 1; - - FNA3D_CommandBuffer_ClearDestroyedBuffer( - renderer->commandBuffers, - (FNA3D_BufferHandle*) buffer - ); - - SDL_free(buffer); -} - -static void VULKAN_INTERNAL_DestroyImageView( - VulkanRenderer* renderer, - VkImageView imageView -) { - renderer->vkDestroyImageView( - renderer->logicalDevice, - imageView, - NULL - ); -} - -/* When a render target image view is destroyed we need to invalidate - * the framebuffers that reference it */ -static void VULKAN_INTERNAL_RemoveViewFramebuffer( - VulkanRenderer *renderer, - VkImageView imageView -) { - int32_t i, j; - - for (i = renderer->framebufferArray.count - 1; i >= 0; i -= 1) - { - if (renderer->framebufferArray.elements[i].key.depthStencilAttachmentView == imageView) - { - renderer->vkDestroyFramebuffer( - renderer->logicalDevice, - renderer->framebufferArray.elements[i].value, - NULL - ); - - FramebufferHashArray_Remove( - &renderer->framebufferArray, - i - ); - } - else - { - for (j = 0; j < MAX_RENDERTARGET_BINDINGS; j += 1) - { - if ( - renderer->framebufferArray.elements[i].key.colorAttachmentViews[j] == imageView || - renderer->framebufferArray.elements[i].key.colorMultiSampleAttachmentViews[j] == imageView - ) - { - renderer->vkDestroyFramebuffer( - renderer->logicalDevice, - renderer->framebufferArray.elements[i].value, - NULL - ); - - FramebufferHashArray_Remove( - &renderer->framebufferArray, - i - ); - - break; - } - } - } - } - - VULKAN_INTERNAL_DestroyImageView( - renderer, - imageView - ); -} - -static void VULKAN_INTERNAL_DestroyTexture( - VulkanRenderer *renderer, - VulkanTexture *texture -) { - int32_t i; - - if (texture->external) - { - SDL_free(texture); - return; - } - - VULKAN_INTERNAL_DestroyImageView( - renderer, - texture->view - ); - - if (texture->isRenderTarget) - { - if (texture->rtViews[0] != texture->view) - { - VULKAN_INTERNAL_RemoveViewFramebuffer( - renderer, - texture->rtViews[0] - ); - } - - if (texture->rtViews[1] != VK_NULL_HANDLE) - { - /* Free all the other cube RT views */ - for (i = 1; i < 6; i += 1) - { - VULKAN_INTERNAL_RemoveViewFramebuffer( - renderer, - texture->rtViews[i] - ); - } - } - } - - renderer->vkDestroyImage( - renderer->logicalDevice, - texture->image, - NULL - ); - - renderer->needDefrag |= FNA3D_INTERNAL_RemoveMemoryUsedRegion( - renderer->allocator, - texture->usedRegion - ); - renderer->resourceFreed = 1; - - SDL_free(texture); -} - -/* Vulkan: Memory Barriers */ - -static void VULKAN_INTERNAL_BufferMemoryBarrier( - VulkanRenderer *renderer, - VulkanResourceAccessType nextResourceAccessType, - VkBuffer buffer, - VulkanResourceAccessType *resourceAccessType -) { - VulkanCommandBuffer *commandBuffer; - VkPipelineStageFlags srcStages = 0; - VkPipelineStageFlags dstStages = 0; - VkBufferMemoryBarrier memoryBarrier; - VulkanResourceAccessType prevAccess, nextAccess; - const VulkanResourceAccessInfo *prevAccessInfo, *nextAccessInfo; - - SDL_LockMutex(renderer->passLock); - - memoryBarrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER; - memoryBarrier.pNext = NULL; - memoryBarrier.srcAccessMask = 0; - memoryBarrier.dstAccessMask = 0; - memoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - memoryBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - memoryBarrier.buffer = buffer; - memoryBarrier.offset = 0; - memoryBarrier.size = VK_WHOLE_SIZE; - - prevAccess = *resourceAccessType; - prevAccessInfo = &AccessMap[prevAccess]; - - srcStages |= prevAccessInfo->stageMask; - - if (prevAccess > RESOURCE_ACCESS_END_OF_READ) - { - memoryBarrier.srcAccessMask |= prevAccessInfo->accessMask; - } - - nextAccess = nextResourceAccessType; - nextAccessInfo = &AccessMap[nextAccess]; - - dstStages |= nextAccessInfo->stageMask; - - if (memoryBarrier.srcAccessMask != 0) - { - memoryBarrier.dstAccessMask |= nextAccessInfo->accessMask; - } - - if (srcStages == 0) - { - srcStages = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; - } - if (dstStages == 0) - { - dstStages = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; - } - - VULKAN_INTERNAL_MaybeEndRenderPass(renderer); - renderer->needNewRenderPass = 1; - - commandBuffer = (VulkanCommandBuffer*) FNA3D_CommandBuffer_GetCurrent( - renderer->commandBuffers - ); - RECORD_CMD(renderer->vkCmdPipelineBarrier( - commandBuffer->commandBuffer, - srcStages, - dstStages, - 0, - 0, - NULL, - 1, - &memoryBarrier, - 0, - NULL - )); - - *resourceAccessType = nextResourceAccessType; - - SDL_UnlockMutex(renderer->passLock); -} - -static void VULKAN_INTERNAL_ImageMemoryBarrier( - VulkanRenderer *renderer, - VulkanResourceAccessType nextAccess, - VkImageAspectFlags aspectMask, - uint32_t baseLayer, - uint32_t layerCount, - uint32_t baseLevel, - uint32_t levelCount, - uint8_t discardContents, - VkImage image, - VulkanResourceAccessType *resourceAccessType -) { - VulkanCommandBuffer *commandBuffer; - VkPipelineStageFlags srcStages = 0; - VkPipelineStageFlags dstStages = 0; - VkImageMemoryBarrier memoryBarrier; - VulkanResourceAccessType prevAccess; - const VulkanResourceAccessInfo *pPrevAccessInfo, *pNextAccessInfo; - - SDL_LockMutex(renderer->passLock); - - memoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - memoryBarrier.pNext = NULL; - memoryBarrier.srcAccessMask = 0; - memoryBarrier.dstAccessMask = 0; - memoryBarrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; - memoryBarrier.newLayout = VK_IMAGE_LAYOUT_UNDEFINED; - memoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - memoryBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - memoryBarrier.image = image; - memoryBarrier.subresourceRange.aspectMask = aspectMask; - memoryBarrier.subresourceRange.baseArrayLayer = baseLayer; - memoryBarrier.subresourceRange.layerCount = layerCount; - memoryBarrier.subresourceRange.baseMipLevel = baseLevel; - memoryBarrier.subresourceRange.levelCount = levelCount; - - prevAccess = *resourceAccessType; - pPrevAccessInfo = &AccessMap[prevAccess]; - - srcStages |= pPrevAccessInfo->stageMask; - - if (prevAccess > RESOURCE_ACCESS_END_OF_READ) - { - memoryBarrier.srcAccessMask |= pPrevAccessInfo->accessMask; - } - - if (discardContents) - { - memoryBarrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; - } - else - { - memoryBarrier.oldLayout = pPrevAccessInfo->imageLayout; - } - - pNextAccessInfo = &AccessMap[nextAccess]; - - dstStages |= pNextAccessInfo->stageMask; - - memoryBarrier.dstAccessMask |= pNextAccessInfo->accessMask; - memoryBarrier.newLayout = pNextAccessInfo->imageLayout; - - if (srcStages == 0) - { - srcStages = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; - } - if (dstStages == 0) - { - dstStages = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; - } - - VULKAN_INTERNAL_MaybeEndRenderPass(renderer); - renderer->needNewRenderPass = 1; - - commandBuffer = (VulkanCommandBuffer*) FNA3D_CommandBuffer_GetCurrent( - renderer->commandBuffers - ); - RECORD_CMD(renderer->vkCmdPipelineBarrier( - commandBuffer->commandBuffer, - srcStages, - dstStages, - 0, - 0, - NULL, - 0, - NULL, - 1, - &memoryBarrier - )); - - *resourceAccessType = nextAccess; - - SDL_UnlockMutex(renderer->passLock); -} - -/* Allocator functions */ - -static VulkanBuffer* VULKAN_INTERNAL_CreateBuffer( - VulkanRenderer *renderer, - VkDeviceSize size, - VulkanResourceAccessType resourceAccessType, - VkBufferUsageFlags usage, - uint8_t preferDeviceLocal, - uint8_t isTransferBuffer -) { - VkBufferCreateInfo bufferCreateInfo; - VkResult vulkanResult; - uint8_t bindResult = 0; - VulkanBuffer *buffer = SDL_malloc(sizeof(VulkanBuffer)); - - buffer->size = size; - buffer->resourceAccessType = resourceAccessType; - buffer->usage = usage | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; - buffer->preferDeviceLocal = preferDeviceLocal; - buffer->isTransferBuffer = isTransferBuffer; - SDL_SetAtomicInt(&buffer->refcount, 0); - - bufferCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; - bufferCreateInfo.pNext = NULL; - bufferCreateInfo.flags = 0; - bufferCreateInfo.size = buffer->size; - bufferCreateInfo.usage = buffer->usage; - bufferCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - bufferCreateInfo.queueFamilyIndexCount = 1; - bufferCreateInfo.pQueueFamilyIndices = &renderer->queueFamilyIndex; - - vulkanResult = renderer->vkCreateBuffer( - renderer->logicalDevice, - &bufferCreateInfo, - NULL, - &buffer->buffer - ); - VULKAN_ERROR_CHECK(vulkanResult, vkCreateBuffer, NULL) - - buffer->bufferCreateInfo = bufferCreateInfo; - - bindResult = VULKAN_INTERNAL_BindMemoryForBuffer( - renderer, - buffer->buffer, - buffer, - buffer->size, - buffer->preferDeviceLocal, - buffer->isTransferBuffer, - &buffer->usedRegion - ); - - /* Binding failed, bail out! */ - if (bindResult != 1) - { - renderer->vkDestroyBuffer( - renderer->logicalDevice, - buffer->buffer, - NULL); - - return NULL; - } - - return buffer; -} - -/* Transfer buffer functions */ - -static inline VkDeviceSize VULKAN_INTERNAL_NextHighestAlignment( - VkDeviceSize n, - VkDeviceSize align -) { - return align * ((n + align - 1) / align); -} - -static void VULKAN_INTERNAL_CopyToTransferBuffer( - VulkanRenderer *renderer, - void* data, - uint32_t uploadLength, - uint32_t copyLength, - VulkanBuffer **pTransferBuffer, - VkDeviceSize *pOffset, - VkDeviceSize alignment -) { - FNA3D_TransferBuffer *transferBuffer; - VulkanBuffer *parentBuffer; - uint8_t *transferBufferPointer; - VkDeviceSize fmtAlignment = VULKAN_INTERNAL_NextHighestAlignment( - alignment, - renderer->physicalDeviceProperties.properties.limits.optimalBufferCopyOffsetAlignment - ); - - transferBuffer = FNA3D_CommandBuffer_AcquireTransferBuffer( - renderer->commandBuffers, - uploadLength, - fmtAlignment - ); - parentBuffer = (VulkanBuffer*) transferBuffer->buffer; - - transferBufferPointer = FNA3D_Memory_GetHostPointer( - parentBuffer->usedRegion, - transferBuffer->offset - ); - - SDL_memcpy( - transferBufferPointer, - data, - copyLength - ); - - *pTransferBuffer = (VulkanBuffer*) transferBuffer->buffer; - *pOffset = transferBuffer->offset; - - transferBuffer->offset += copyLength; -} - -static void VULKAN_INTERNAL_PrepareCopyFromTransferBuffer( - VulkanRenderer *renderer, - VkDeviceSize dataLength, - VkDeviceSize alignment, - FNA3D_TransferBuffer **pTransferBuffer, - void **pTransferBufferPointer -) { - VkDeviceSize fmtAlignment = VULKAN_INTERNAL_NextHighestAlignment( - alignment, - renderer->physicalDeviceProperties.properties.limits.optimalBufferCopyOffsetAlignment - ); - - FNA3D_TransferBuffer *transferBuffer = FNA3D_CommandBuffer_AcquireTransferBuffer( - renderer->commandBuffers, - dataLength, - fmtAlignment - ); - VulkanBuffer *parentBuffer = (VulkanBuffer*) transferBuffer->buffer; - - *pTransferBuffer = transferBuffer; - *pTransferBufferPointer = FNA3D_Memory_GetHostPointer( - parentBuffer->usedRegion, - transferBuffer->offset - ); -} - -/* Vulkan: Descriptor Set Logic */ - -static uint8_t VULKAN_INTERNAL_CreateDescriptorPool( - VulkanRenderer *renderer, - VkDescriptorType descriptorType, - uint32_t descriptorSetCount, - uint32_t descriptorCount, - VkDescriptorPool *pDescriptorPool -) { - VkResult vulkanResult; - - VkDescriptorPoolSize descriptorPoolSize; - VkDescriptorPoolCreateInfo descriptorPoolInfo; - - descriptorPoolSize.type = descriptorType; - descriptorPoolSize.descriptorCount = descriptorCount; - - descriptorPoolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; - descriptorPoolInfo.pNext = NULL; - descriptorPoolInfo.flags = 0; - descriptorPoolInfo.maxSets = descriptorSetCount; - descriptorPoolInfo.poolSizeCount = 1; - descriptorPoolInfo.pPoolSizes = &descriptorPoolSize; - - vulkanResult = renderer->vkCreateDescriptorPool( - renderer->logicalDevice, - &descriptorPoolInfo, - NULL, - pDescriptorPool - ); - VULKAN_ERROR_CHECK(vulkanResult, vkCreateDescriptorPool, 0) - - return 1; -} - -static uint8_t VULKAN_INTERNAL_AllocateDescriptorSets( - VulkanRenderer *renderer, - VkDescriptorPool descriptorPool, - VkDescriptorSetLayout descriptorSetLayout, - uint32_t descriptorSetCount, - VkDescriptorSet *descriptorSetArray -) { - VkResult vulkanResult; - uint32_t i; - VkDescriptorSetAllocateInfo descriptorSetAllocateInfo; - VkDescriptorSetLayout *descriptorSetLayouts = SDL_stack_alloc(VkDescriptorSetLayout, descriptorSetCount); - - for (i = 0; i < descriptorSetCount; i += 1) - { - descriptorSetLayouts[i] = descriptorSetLayout; - } - - descriptorSetAllocateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; - descriptorSetAllocateInfo.pNext = NULL; - descriptorSetAllocateInfo.descriptorPool = descriptorPool; - descriptorSetAllocateInfo.descriptorSetCount = descriptorSetCount; - descriptorSetAllocateInfo.pSetLayouts = descriptorSetLayouts; - - vulkanResult = renderer->vkAllocateDescriptorSets( - renderer->logicalDevice, - &descriptorSetAllocateInfo, - descriptorSetArray - ); - - SDL_stack_free(descriptorSetLayouts); - - VULKAN_ERROR_CHECK(vulkanResult, vkAllocateDescriptorSets, 0) - - return 1; -} - -static uint16_t VULKAN_INTERNAL_FetchSamplerBitmask( - MOJOSHADER_vkShader *shader -) { - const MOJOSHADER_parseData *parseData = MOJOSHADER_vkGetShaderParseData(shader); - uint16_t bitmask = 0; - uint8_t i; - - for (i = 0; i < parseData->sampler_count; i += 1) - { - bitmask |= (1 << parseData->samplers[i].index); - } - - return bitmask; -} - -static VkDescriptorSetLayout VULKAN_INTERNAL_FetchSamplerDescriptorSetLayout( - VulkanRenderer *renderer, - MOJOSHADER_vkShader *shader, - VkShaderStageFlagBits stageFlag -) { - DescriptorSetLayoutHash descriptorSetLayoutHash; - VkDescriptorSetLayout descriptorSetLayout; - - VkDescriptorSetLayoutBinding setLayoutBindings[MAX_TEXTURE_SAMPLERS]; - VkDescriptorSetLayoutCreateInfo setLayoutCreateInfo; - - uint32_t samplerCount = MOJOSHADER_vkGetShaderParseData(shader)->sampler_count; - MOJOSHADER_sampler *samplerInfos = MOJOSHADER_vkGetShaderParseData(shader)->samplers; - - VkResult vulkanResult; - uint32_t i; - - descriptorSetLayoutHash.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - descriptorSetLayoutHash.stageFlag = stageFlag; - descriptorSetLayoutHash.bitmask = VULKAN_INTERNAL_FetchSamplerBitmask(shader); - - descriptorSetLayout = DescriptorSetLayoutHashTable_Fetch(&renderer->descriptorSetLayoutTable, descriptorSetLayoutHash); - - if (descriptorSetLayout != VK_NULL_HANDLE) - { - return descriptorSetLayout; - } - - if (samplerCount == 0) /* dummy sampler case */ - { - setLayoutBindings[0].binding = 0; - setLayoutBindings[0].descriptorCount = 1; - setLayoutBindings[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - setLayoutBindings[0].stageFlags = stageFlag; - setLayoutBindings[0].pImmutableSamplers = NULL; - } - else - { - for (i = 0; i < samplerCount; i += 1) - { - setLayoutBindings[i].binding = samplerInfos[i].index; - setLayoutBindings[i].descriptorCount = 1; - setLayoutBindings[i].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - setLayoutBindings[i].stageFlags = stageFlag; - setLayoutBindings[i].pImmutableSamplers = NULL; - } - } - - setLayoutCreateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; - setLayoutCreateInfo.pNext = NULL; - setLayoutCreateInfo.flags = 0; - setLayoutCreateInfo.bindingCount = SDL_max(samplerCount, 1); - setLayoutCreateInfo.pBindings = setLayoutBindings; - - vulkanResult = renderer->vkCreateDescriptorSetLayout( - renderer->logicalDevice, - &setLayoutCreateInfo, - NULL, - &descriptorSetLayout - ); - VULKAN_ERROR_CHECK(vulkanResult, vkCreateDescriptorSetLayout, VK_NULL_HANDLE) - - DescriptorSetLayoutHashTable_Insert( - &renderer->descriptorSetLayoutTable, - descriptorSetLayoutHash, - descriptorSetLayout - ); - - return descriptorSetLayout; -} - -static void VULKAN_INTERNAL_ClearDescriptorSets( - FNA3D_Renderer *driverData, - FNA3D_CommandBuffer *handle, - void* callbackData -) { - VulkanCommandBuffer *commandBuffer = (VulkanCommandBuffer*) handle; - ShaderResources *shaderResources = (ShaderResources*) callbackData; - uint32_t i; - - for (i = 0; i < commandBuffer->usedDescriptorSetDataCount; i += 1) - { - if (commandBuffer->usedDescriptorSetDatas[i].parent == shaderResources) - { - commandBuffer->usedDescriptorSetDatas[i].descriptorSet = VK_NULL_HANDLE; - } - } -} - -static void ShaderResources_Destroy( - VulkanRenderer *renderer, - ShaderResources *shaderResources -) { - uint32_t i; - for (i = 0; i < shaderResources->samplerDescriptorPoolCount; i += 1) - { - renderer->vkDestroyDescriptorPool( - renderer->logicalDevice, - shaderResources->samplerDescriptorPools[i], - NULL - ); - } - - /* Don't return descriptor sets allocated from this shader resource to the inactive pool! */ - FNA3D_CommandBuffer_ForEachSubmittedBuffer( - renderer->commandBuffers, - VULKAN_INTERNAL_ClearDescriptorSets, - shaderResources - ); - - SDL_free(shaderResources->samplerDescriptorPools); - SDL_free(shaderResources->samplerBindingIndices); - SDL_free(shaderResources->inactiveDescriptorSets); - - SDL_free(shaderResources); -} - -static ShaderResources *ShaderResources_Init( - VulkanRenderer *renderer, - MOJOSHADER_vkShader *shader, - VkShaderStageFlagBits shaderStageFlag -) { - uint32_t i; - VkBuffer vUniform, fUniform; - VkWriteDescriptorSet writeDescriptorSet; - VkDescriptorImageInfo imageInfo; - unsigned long long vOff, fOff, vSize, fSize; - uint32_t descriptorPoolSize = STARTING_SAMPLER_DESCRIPTOR_POOL_SIZE; - ShaderResources *shaderResources = SDL_malloc(sizeof(ShaderResources)); - - /* - * Lock to prevent mojoshader resources - * from being overwritten during initialization - */ - SDL_LockMutex(renderer->passLock); - - shaderResources->samplerLayout = VULKAN_INTERNAL_FetchSamplerDescriptorSetLayout(renderer, shader, shaderStageFlag); - shaderResources->samplerCount = MOJOSHADER_vkGetShaderParseData(shader)->sampler_count; - - shaderResources->samplerDescriptorPools = SDL_malloc(sizeof(VkDescriptorPool)); - shaderResources->samplerDescriptorPoolCount = 1; - - if (shaderResources->samplerCount == 0) - { - descriptorPoolSize = 1; - } - - VULKAN_INTERNAL_CreateDescriptorPool( - renderer, - VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, - descriptorPoolSize, - descriptorPoolSize * SDL_max(shaderResources->samplerCount, 1), /* in case of dummy data */ - &shaderResources->samplerDescriptorPools[0] - ); - - shaderResources->nextPoolSize = STARTING_SAMPLER_DESCRIPTOR_POOL_SIZE * 2; - - shaderResources->samplerBindingIndices = SDL_malloc(sizeof(uint8_t) * shaderResources->samplerCount); - - for (i = 0; i < shaderResources->samplerCount; i += 1) - { - shaderResources->samplerBindingIndices[i] = MOJOSHADER_vkGetShaderParseData(shader)->samplers[i].index; - } - - if (shaderResources->samplerCount > 0) - { - shaderResources->inactiveDescriptorSetCapacity = STARTING_SAMPLER_DESCRIPTOR_POOL_SIZE; - shaderResources->inactiveDescriptorSetCount = STARTING_SAMPLER_DESCRIPTOR_POOL_SIZE - 1; - shaderResources->inactiveDescriptorSets = SDL_malloc(sizeof(VkDescriptorSet) * STARTING_SAMPLER_DESCRIPTOR_POOL_SIZE); - - VULKAN_INTERNAL_AllocateDescriptorSets( - renderer, - shaderResources->samplerDescriptorPools[0], - shaderResources->samplerLayout, - STARTING_SAMPLER_DESCRIPTOR_POOL_SIZE, - shaderResources->inactiveDescriptorSets - ); - } - else - { - shaderResources->inactiveDescriptorSetCapacity = 0; - shaderResources->inactiveDescriptorSetCount = 0; - shaderResources->inactiveDescriptorSets = NULL; - - /* Set up the dummy descriptor set */ - VULKAN_INTERNAL_AllocateDescriptorSets( - renderer, - shaderResources->samplerDescriptorPools[0], - shaderResources->samplerLayout, - 1, - &shaderResources->dummySamplerDescriptorSet - ); - - imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - - if (shaderStageFlag == VK_SHADER_STAGE_VERTEX_BIT) - { - imageInfo.imageView = renderer->dummyVertTexture->view; - imageInfo.sampler = renderer->dummyVertSamplerState; - } - else - { - imageInfo.imageView = renderer->dummyFragTexture->view; - imageInfo.sampler = renderer->dummyFragSamplerState; - } - - writeDescriptorSet.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - writeDescriptorSet.pNext = NULL; - writeDescriptorSet.descriptorCount = 1; - writeDescriptorSet.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - writeDescriptorSet.dstArrayElement = 0; - writeDescriptorSet.dstBinding = 0; - writeDescriptorSet.dstSet = shaderResources->dummySamplerDescriptorSet; - writeDescriptorSet.pBufferInfo = NULL; - writeDescriptorSet.pImageInfo = &imageInfo; - writeDescriptorSet.pTexelBufferView = NULL; - - renderer->vkUpdateDescriptorSets( - renderer->logicalDevice, - 1, - &writeDescriptorSet, - 0, - NULL - ); - } - - MOJOSHADER_vkGetUniformBuffers( - renderer->mojoshaderContext, - &vUniform, &vOff, &vSize, - &fUniform, &fOff, &fSize - ); - - if (shaderStageFlag == VK_SHADER_STAGE_VERTEX_BIT) - { - VULKAN_INTERNAL_AllocateDescriptorSets( - renderer, - renderer->uniformBufferDescriptorPool, - renderer->vertexUniformBufferDescriptorSetLayout, - 1, - &shaderResources->uniformDescriptorSet - ); - - shaderResources->uniformBufferInfo.buffer = vUniform; - shaderResources->uniformBufferInfo.offset = 0; - shaderResources->uniformBufferInfo.range = vSize; - } - else - { - VULKAN_INTERNAL_AllocateDescriptorSets( - renderer, - renderer->uniformBufferDescriptorPool, - renderer->fragUniformBufferDescriptorSetLayout, - 1, - &shaderResources->uniformDescriptorSet - ); - - shaderResources->uniformBufferInfo.buffer = fUniform; - shaderResources->uniformBufferInfo.offset = 0; - shaderResources->uniformBufferInfo.range = fSize; - } - - if (shaderResources->uniformBufferInfo.buffer != VK_NULL_HANDLE) - { - writeDescriptorSet.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - writeDescriptorSet.pNext = NULL; - writeDescriptorSet.descriptorCount = 1; - writeDescriptorSet.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; - writeDescriptorSet.dstArrayElement = 0; - writeDescriptorSet.dstBinding = 0; - writeDescriptorSet.dstSet = shaderResources->uniformDescriptorSet; - writeDescriptorSet.pBufferInfo = &shaderResources->uniformBufferInfo; - writeDescriptorSet.pImageInfo = NULL; - - renderer->vkUpdateDescriptorSets( - renderer->logicalDevice, - 1, - &writeDescriptorSet, - 0, - NULL - ); - } - - SDL_UnlockMutex(renderer->passLock); - - return shaderResources; -} - -static ShaderResources* VULKAN_INTERNAL_FetchShaderResources( - VulkanRenderer *renderer, - MOJOSHADER_vkShader *shader, - VkShaderStageFlagBits shaderStageFlag -) { - ShaderResources *shaderResources = ShaderResourcesHashTable_Fetch(&renderer->shaderResourcesHashTable, shader); - - if (shaderResources == VK_NULL_HANDLE) - { - shaderResources = ShaderResources_Init(renderer, shader, shaderStageFlag); - ShaderResourcesHashTable_Insert(&renderer->shaderResourcesHashTable, shader, shaderResources); - } - - return shaderResources; -} - -/* Fetches or creates a new descriptor set based on data */ -static VkDescriptorSet ShaderResources_FetchDescriptorSet( - VulkanRenderer *renderer, - ShaderResources *shaderResources -) { - VkDescriptorSet newDescriptorSet; - - /* If no inactive descriptor sets remain, create a new pool and allocate new inactive sets */ - - if (shaderResources->inactiveDescriptorSetCount == 0) - { - shaderResources->samplerDescriptorPoolCount += 1; - shaderResources->samplerDescriptorPools = SDL_realloc( - shaderResources->samplerDescriptorPools, - sizeof(VkDescriptorPool) * shaderResources->samplerDescriptorPoolCount - ); - - VULKAN_INTERNAL_CreateDescriptorPool( - renderer, - VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, - shaderResources->nextPoolSize, - shaderResources->nextPoolSize * SDL_max(shaderResources->samplerCount, 1), /* dont want 0 in case of dummy data */ - &shaderResources->samplerDescriptorPools[shaderResources->samplerDescriptorPoolCount - 1] - ); - - shaderResources->inactiveDescriptorSetCapacity += shaderResources->nextPoolSize; - - shaderResources->inactiveDescriptorSets = SDL_realloc( - shaderResources->inactiveDescriptorSets, - sizeof(VkDescriptorSet) * shaderResources->inactiveDescriptorSetCapacity - ); - - VULKAN_INTERNAL_AllocateDescriptorSets( - renderer, - shaderResources->samplerDescriptorPools[shaderResources->samplerDescriptorPoolCount - 1], - shaderResources->samplerLayout, - shaderResources->nextPoolSize, - shaderResources->inactiveDescriptorSets - ); - - shaderResources->inactiveDescriptorSetCount = shaderResources->nextPoolSize; - - shaderResources->nextPoolSize *= 2; - } - - newDescriptorSet = shaderResources->inactiveDescriptorSets[shaderResources->inactiveDescriptorSetCount - 1]; - shaderResources->inactiveDescriptorSetCount -= 1; - - return newDescriptorSet; -} - -static void VULKAN_INTERNAL_RegisterUsedDescriptorSet( - VulkanRenderer *renderer, - ShaderResources *parent, - VkDescriptorSet descriptorSet -) { - VulkanCommandBuffer *commandBuffer = (VulkanCommandBuffer*) FNA3D_CommandBuffer_GetCurrent( - renderer->commandBuffers - ); - - if (commandBuffer->usedDescriptorSetDataCount >= commandBuffer->usedDescriptorSetDataCapacity) - { - commandBuffer->usedDescriptorSetDataCapacity *= 2; - commandBuffer->usedDescriptorSetDatas = SDL_realloc( - commandBuffer->usedDescriptorSetDatas, - commandBuffer->usedDescriptorSetDataCapacity * sizeof(DescriptorSetData) - ); - } - - commandBuffer->usedDescriptorSetDatas[commandBuffer->usedDescriptorSetDataCount].descriptorSet = descriptorSet; - commandBuffer->usedDescriptorSetDatas[commandBuffer->usedDescriptorSetDataCount].parent = parent; - commandBuffer->usedDescriptorSetDataCount += 1; -} - -/* Must take an array of descriptor sets of size 4 */ -static void VULKAN_INTERNAL_FetchDescriptorSetDataAndOffsets( - VulkanRenderer *renderer, - ShaderResources *vertShaderResources, - ShaderResources *fragShaderResources, - VkDescriptorSet *descriptorSets, - uint32_t *dynamicOffsets -) { - VkBuffer vUniform, fUniform; - unsigned long long vOff, fOff, vSize, fSize; /* MojoShader type */ - - MOJOSHADER_vkShader *vertShader, *fragShader; - MOJOSHADER_samplerType samplerType; - VkWriteDescriptorSet writeDescriptorSets[MAX_TEXTURE_SAMPLERS]; - VkDescriptorImageInfo imageInfos[MAX_TEXTURE_SAMPLERS]; - - uint32_t i; - - MOJOSHADER_vkGetBoundShaders(renderer->mojoshaderContext, &vertShader, &fragShader); - - if (renderer->vertexSamplerDescriptorSetDataNeedsUpdate) - { - if (vertShaderResources->samplerCount == 0) - { - renderer->currentVertexSamplerDescriptorSet = vertShaderResources->dummySamplerDescriptorSet; - } - else - { - renderer->currentVertexSamplerDescriptorSet = ShaderResources_FetchDescriptorSet( - renderer, - vertShaderResources - ); - - for (i = 0; i < vertShaderResources->samplerCount; i += 1) - { - if (renderer->textures[MAX_TEXTURE_SAMPLERS + vertShaderResources->samplerBindingIndices[i]] != &NullTexture) - { - imageInfos[i].imageView = renderer->textures[MAX_TEXTURE_SAMPLERS + vertShaderResources->samplerBindingIndices[i]]->view; - imageInfos[i].sampler = renderer->samplers[MAX_TEXTURE_SAMPLERS + vertShaderResources->samplerBindingIndices[i]]; - imageInfos[i].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - } - else - { - samplerType = MOJOSHADER_vkGetShaderParseData(vertShader)->samplers[i].type; - if (samplerType == MOJOSHADER_SAMPLER_2D) - { - imageInfos[i].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - imageInfos[i].imageView = renderer->dummyVertTexture->view; - imageInfos[i].sampler = renderer->dummyVertSamplerState; - } - else if (samplerType == MOJOSHADER_SAMPLER_VOLUME) - { - imageInfos[i].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - imageInfos[i].imageView = renderer->dummyVertTexture3D->view; - imageInfos[i].sampler = renderer->dummyVertSampler3DState; - } - else if (samplerType == MOJOSHADER_SAMPLER_CUBE) - { - imageInfos[i].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - imageInfos[i].imageView = renderer->dummyVertTextureCube->view; - imageInfos[i].sampler = renderer->dummyVertSamplerCubeState; - } - } - - writeDescriptorSets[i].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - writeDescriptorSets[i].pNext = NULL; - writeDescriptorSets[i].descriptorCount = 1; - writeDescriptorSets[i].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - writeDescriptorSets[i].dstArrayElement = 0; - writeDescriptorSets[i].dstBinding = vertShaderResources->samplerBindingIndices[i]; - writeDescriptorSets[i].dstSet = renderer->currentVertexSamplerDescriptorSet; - writeDescriptorSets[i].pBufferInfo = NULL; - writeDescriptorSets[i].pImageInfo = &imageInfos[i]; - writeDescriptorSets[i].pTexelBufferView = NULL; - } - - renderer->vkUpdateDescriptorSets( - renderer->logicalDevice, - vertShaderResources->samplerCount, - writeDescriptorSets, - 0, - NULL - ); - - VULKAN_INTERNAL_RegisterUsedDescriptorSet( - renderer, - vertShaderResources, - renderer->currentVertexSamplerDescriptorSet - ); - } - } - - if (renderer->fragSamplerDescriptorSetDataNeedsUpdate) - { - if (fragShaderResources->samplerCount == 0) - { - renderer->currentFragSamplerDescriptorSet = fragShaderResources->dummySamplerDescriptorSet; - } - else - { - renderer->currentFragSamplerDescriptorSet = ShaderResources_FetchDescriptorSet( - renderer, - fragShaderResources - ); - - for (i = 0; i < fragShaderResources->samplerCount; i += 1) - { - if (renderer->textures[fragShaderResources->samplerBindingIndices[i]] != &NullTexture) - { - imageInfos[i].imageView = renderer->textures[fragShaderResources->samplerBindingIndices[i]]->view; - imageInfos[i].sampler = renderer->samplers[fragShaderResources->samplerBindingIndices[i]]; - imageInfos[i].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - } - else - { - - samplerType = MOJOSHADER_vkGetShaderParseData(fragShader)->samplers[i].type; - if (samplerType == MOJOSHADER_SAMPLER_2D) - { - imageInfos[i].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - imageInfos[i].imageView = renderer->dummyFragTexture->view; - imageInfos[i].sampler = renderer->dummyFragSamplerState; - } - else if (samplerType == MOJOSHADER_SAMPLER_VOLUME) - { - imageInfos[i].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - imageInfos[i].imageView = renderer->dummyFragTexture3D->view; - imageInfos[i].sampler = renderer->dummyFragSampler3DState; - } - else if (samplerType == MOJOSHADER_SAMPLER_CUBE) - { - imageInfos[i].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - imageInfos[i].imageView = renderer->dummyFragTextureCube->view; - imageInfos[i].sampler = renderer->dummyFragSamplerCubeState; - } - } - - writeDescriptorSets[i].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - writeDescriptorSets[i].pNext = NULL; - writeDescriptorSets[i].descriptorCount = 1; - writeDescriptorSets[i].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - writeDescriptorSets[i].dstArrayElement = 0; - writeDescriptorSets[i].dstBinding = fragShaderResources->samplerBindingIndices[i]; - writeDescriptorSets[i].dstSet = renderer->currentFragSamplerDescriptorSet; - writeDescriptorSets[i].pBufferInfo = NULL; - writeDescriptorSets[i].pImageInfo = &imageInfos[i]; - writeDescriptorSets[i].pTexelBufferView = NULL; - } - - renderer->vkUpdateDescriptorSets( - renderer->logicalDevice, - fragShaderResources->samplerCount, - writeDescriptorSets, - 0, - NULL - ); - - VULKAN_INTERNAL_RegisterUsedDescriptorSet( - renderer, - fragShaderResources, - renderer->currentFragSamplerDescriptorSet - ); - } - } - - renderer->vertexSamplerDescriptorSetDataNeedsUpdate = 0; - renderer->fragSamplerDescriptorSetDataNeedsUpdate = 0; - - descriptorSets[0] = renderer->currentVertexSamplerDescriptorSet; - descriptorSets[1] = vertShaderResources->uniformDescriptorSet; - descriptorSets[2] = renderer->currentFragSamplerDescriptorSet; - descriptorSets[3] = fragShaderResources->uniformDescriptorSet; - - MOJOSHADER_vkGetUniformBuffers( - renderer->mojoshaderContext, - &vUniform, &vOff, &vSize, - &fUniform, &fOff, &fSize - ); - - dynamicOffsets[0] = vOff; - dynamicOffsets[1] = fOff; -} - -/* Vulkan: Command Submission */ - -static void VULKAN_INTERNAL_SwapChainBlit( - VulkanRenderer *renderer, - VulkanSwapchainData *swapchainData, - FNA3D_Rect * sourceRectangle, - FNA3D_Rect *destinationRectangle, - uint32_t swapchainImageIndex -) { - VulkanCommandBuffer *commandBuffer; - FNA3D_Rect srcRect; - FNA3D_Rect dstRect; - VkImageBlit blit; - - if (sourceRectangle != NULL) - { - srcRect = *sourceRectangle; - } - else - { - srcRect.x = 0; - srcRect.y = 0; - srcRect.w = renderer->fauxBackbufferWidth; - srcRect.h = renderer->fauxBackbufferHeight; - } - - if (destinationRectangle != NULL) - { - dstRect = *destinationRectangle; - } - else - { - dstRect.x = 0; - dstRect.y = 0; - dstRect.w = swapchainData->extent.width; - dstRect.h = swapchainData->extent.height; - } - - /* Blit the framebuffer! */ - - VULKAN_INTERNAL_ImageMemoryBarrier( - renderer, - RESOURCE_ACCESS_TRANSFER_READ, - VK_IMAGE_ASPECT_COLOR_BIT, - 0, - 1, - 0, - 1, - 0, - renderer->fauxBackbufferColor.handle->image, - &renderer->fauxBackbufferColor.handle->resourceAccessType - ); - - VULKAN_INTERNAL_ImageMemoryBarrier( - renderer, - RESOURCE_ACCESS_TRANSFER_WRITE, - VK_IMAGE_ASPECT_COLOR_BIT, - 0, - 1, - 0, - 1, - 0, - swapchainData->images[swapchainImageIndex], - &swapchainData->resourceAccessTypes[swapchainImageIndex] - ); - - blit.srcOffsets[0].x = srcRect.x; - blit.srcOffsets[0].y = srcRect.y; - blit.srcOffsets[0].z = 0; - blit.srcOffsets[1].x = srcRect.x + srcRect.w; - blit.srcOffsets[1].y = srcRect.y + srcRect.h; - blit.srcOffsets[1].z = 1; - - blit.srcSubresource.mipLevel = 0; - blit.srcSubresource.baseArrayLayer = 0; - blit.srcSubresource.layerCount = 1; - blit.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - - blit.dstOffsets[0].x = dstRect.x; - blit.dstOffsets[0].y = dstRect.y; - blit.dstOffsets[0].z = 0; - blit.dstOffsets[1].x = dstRect.x + dstRect.w; - blit.dstOffsets[1].y = dstRect.y + dstRect.h; - blit.dstOffsets[1].z = 1; - - blit.dstSubresource.mipLevel = 0; - blit.dstSubresource.baseArrayLayer = 0; - blit.dstSubresource.layerCount = 1; - blit.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - - commandBuffer = (VulkanCommandBuffer*) FNA3D_CommandBuffer_GetCurrent( - renderer->commandBuffers - ); - RECORD_CMD(renderer->vkCmdBlitImage( - commandBuffer->commandBuffer, - renderer->fauxBackbufferColor.handle->image, - VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - swapchainData->images[swapchainImageIndex], - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - 1, - &blit, - VK_FILTER_LINEAR - )); - - VULKAN_INTERNAL_ImageMemoryBarrier( - renderer, - RESOURCE_ACCESS_PRESENT, - VK_IMAGE_ASPECT_COLOR_BIT, - 0, - 1, - 0, - 1, - 0, - swapchainData->images[swapchainImageIndex], - &swapchainData->resourceAccessTypes[swapchainImageIndex] - ); - - VULKAN_INTERNAL_ImageMemoryBarrier( - renderer, - RESOURCE_ACCESS_COLOR_ATTACHMENT_READ_WRITE, - VK_IMAGE_ASPECT_COLOR_BIT, - 0, - 1, - 0, - 1, - 0, - renderer->fauxBackbufferColor.handle->image, - &renderer->fauxBackbufferColor.handle->resourceAccessType - ); -} - -static void VULKAN_INTERNAL_CleanDefrag(VulkanRenderer *renderer) -{ - uint32_t i; - - FNA3D_Memory_LockAllocator(renderer->allocator); - - /* Destroy old resources that were copied on defragment */ - - for (i = 0; i < renderer->defragmentedBuffersToDestroyCount; i += 1) - { - renderer->vkDestroyBuffer( - renderer->logicalDevice, - renderer->defragmentedBuffersToDestroy[i], - NULL - ); - } - - renderer->defragmentedBuffersToDestroyCount = 0; - - for (i = 0; i < renderer->defragmentedImagesToDestroyCount; i += 1) - { - renderer->vkDestroyImage( - renderer->logicalDevice, - renderer->defragmentedImagesToDestroy[i], - NULL - ); - } - - renderer->defragmentedImagesToDestroyCount = 0; - - for (i = 0; i < renderer->defragmentedImageViewsToDestroyCount; i += 1) - { - VULKAN_INTERNAL_DestroyImageView( - renderer, - renderer->defragmentedImageViewsToDestroy[i] - ); - } - - renderer->defragmentedImageViewsToDestroyCount = 0; - - renderer->needDefrag |= FNA3D_Memory_DestroyDefragmentedRegions( - renderer->allocator - ); - renderer->resourceFreed = 1; - - FNA3D_Memory_UnlockAllocator(renderer->allocator); -} - -static void VULKAN_INTERNAL_SubmitCommands( - VulkanRenderer *renderer, - uint8_t present, - FNA3D_Rect *sourceRectangle, /* ignored if present is false */ - FNA3D_Rect *destinationRectangle, /* ignored if present is false */ - void *windowHandle /* ignored if present is false */ -) { - VkSemaphore semaphores[2]; - VkFence fences[2]; - uint32_t fenceCount = 0; - VkSubmitInfo submitInfo; - VkResult result; - VkResult acquireResult = VK_SUCCESS; - VkResult presentResult = VK_SUCCESS; - uint8_t acquireSuccess = 0; - uint8_t performDefrag = 0; - uint8_t createSwapchainResult = 0; - uint8_t validSwapchainExists = 0; - VulkanSwapchainData *swapchainData = NULL; - uint32_t swapchainImageIndex; - VulkanCommandBuffer *commandBufferToSubmit; - - SDL_DisplayMode mode; - - VkPipelineStageFlags waitStages = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - VkPresentInfoKHR presentInfo; - struct - { - VkStructureType sType; - const void *pNext; - uint64_t frameToken; - } presentInfoGGP; - - /* Must end render pass before ending command buffer */ - VULKAN_INTERNAL_MaybeEndRenderPass(renderer); - - if (present) - { -#if SDL_MAJOR_VERSION >= 3 - const SDL_DisplayMode *curMode = SDL_GetCurrentDisplayMode( - SDL_GetDisplayForWindow( - (SDL_Window*) windowHandle - ) - ); - SDL_memcpy(&mode, curMode, sizeof(SDL_DisplayMode)); - -#else - SDL_GetCurrentDisplayMode( - SDL_GetWindowDisplayIndex( - (SDL_Window*) windowHandle - ), - &mode - ); -#endif - - if (mode.refresh_rate == 0) - { - /* Needs to be _something_ */ - mode.refresh_rate = 60; - } - -#if SDL_MAJOR_VERSION >= 3 - swapchainData = (VulkanSwapchainData*) SDL_GetPointerProperty( - SDL_GetWindowProperties(windowHandle), - WINDOW_SWAPCHAIN_DATA, - NULL - ); -#else - swapchainData = (VulkanSwapchainData*) SDL_GetWindowData( - windowHandle, - WINDOW_SWAPCHAIN_DATA - ); -#endif - - - if (swapchainData == NULL) - { - createSwapchainResult = VULKAN_INTERNAL_CreateSwapchain(renderer, windowHandle); - - if (createSwapchainResult == CREATE_SWAPCHAIN_FAIL) - { - FNA3D_LogError("Failed to create swapchain for window handle: %p", windowHandle); - } - else if (createSwapchainResult == CREATE_SWAPCHAIN_SURFACE_ZERO) - { - FNA3D_LogInfo("Surface for window handle: %p is size zero, canceling present", windowHandle); - } - else - { -#if SDL_MAJOR_VERSION >= 3 - swapchainData = (VulkanSwapchainData *)SDL_GetPointerProperty(SDL_GetWindowProperties(windowHandle), WINDOW_SWAPCHAIN_DATA, NULL); -#else - swapchainData = (VulkanSwapchainData*) SDL_GetWindowData(windowHandle, WINDOW_SWAPCHAIN_DATA); -#endif - validSwapchainExists = 1; - } - } - else - { - validSwapchainExists = 1; - } - - if (validSwapchainExists) - { - /* Begin next frame */ - acquireResult = renderer->vkAcquireNextImageKHR( - renderer->logicalDevice, - swapchainData->swapchain, - 10000000000 / mode.refresh_rate, /* ~10 frames, so we'll progress even if throttled to zero. */ - swapchainData->imageAvailableSemaphore, - VK_NULL_HANDLE, - &swapchainImageIndex - ); - - if (acquireResult == VK_SUCCESS || acquireResult == VK_SUBOPTIMAL_KHR) - { - VULKAN_INTERNAL_SwapChainBlit( - renderer, - swapchainData, - sourceRectangle, - destinationRectangle, - swapchainImageIndex - ); - - acquireSuccess = 1; - } - } - } - - commandBufferToSubmit = (VulkanCommandBuffer*) FNA3D_CommandBuffer_GetCurrent( - renderer->commandBuffers - ); - - if (renderer->renderPassInProgress) - { - VULKAN_INTERNAL_MaybeEndRenderPass(renderer); - renderer->needNewRenderPass = 1; - } - - FNA3D_CommandBuffer_EndRecording(renderer->commandBuffers); - - /* TODO: Figure out how to properly submit commands mid-frame */ - - fences[fenceCount] = ((VulkanCommandBuffer*) FNA3D_CommandBuffer_GetDefragBuffer(renderer->commandBuffers))->inFlightFence; - fenceCount += 1; - - if (validSwapchainExists && swapchainData->fence != VK_NULL_HANDLE) - { - fences[fenceCount] = swapchainData->fence; - fenceCount += 1; - } - - /* Wait for the defrag to complete */ - result = renderer->vkWaitForFences( - renderer->logicalDevice, - fenceCount, - fences, - VK_TRUE, - UINT64_MAX - ); - - /* This may return an error on exit, so just quietly bail if waiting - * fails for any reason - */ - if (result != VK_SUCCESS) - { - FNA3D_LogWarn("vkWaitForFences: %s", VkErrorMessages(result)); - return; - } - - if (validSwapchainExists) - { - swapchainData->fence = VK_NULL_HANDLE; - } - - VULKAN_INTERNAL_CleanDefrag(renderer); - - /* Check if we can perform any cleanups */ - if (FNA3D_CommandBuffer_PerformCleanups(renderer->commandBuffers)) - { - FNA3D_Memory_FreeEmptyAllocations( - renderer->allocator - ); - } - - renderer->bufferDefragInProgress = 0; - - /* Decide if we will be defragmenting */ - if (renderer->resourceFreed) - { - renderer->defragTimer = 0; - } - renderer->resourceFreed = 0; - - if (renderer->needDefrag) - { - renderer->defragTimer += 1; - - if (renderer->defragTimer > 5) - { - performDefrag = 1; - } - } - - /* Prepare command submission */ - submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - submitInfo.pNext = NULL; - submitInfo.commandBufferCount = 1; - submitInfo.pCommandBuffers = &commandBufferToSubmit->commandBuffer; - submitInfo.signalSemaphoreCount = 0; - - if (present && acquireSuccess) - { - submitInfo.waitSemaphoreCount = 1; - submitInfo.pWaitSemaphores = &swapchainData->imageAvailableSemaphore; - submitInfo.pWaitDstStageMask = &waitStages; - semaphores[submitInfo.signalSemaphoreCount] = swapchainData->renderFinishedSemaphore; - submitInfo.signalSemaphoreCount += 1; - } - else - { - submitInfo.waitSemaphoreCount = 0; - submitInfo.pWaitSemaphores = NULL; - submitInfo.pWaitDstStageMask = NULL; - } - - if (performDefrag) - { - semaphores[submitInfo.signalSemaphoreCount] = renderer->defragSemaphore; - submitInfo.signalSemaphoreCount += 1; - } - - submitInfo.pSignalSemaphores = semaphores; - - renderer->vkResetFences( - renderer->logicalDevice, - 1, - &commandBufferToSubmit->inFlightFence - ); - - /* Submit the commands, finally. */ - result = renderer->vkQueueSubmit( - renderer->unifiedQueue, - 1, - &submitInfo, - commandBufferToSubmit->inFlightFence - ); - VULKAN_ERROR_CHECK(result, vkQueueSubmit,) - - if (validSwapchainExists) - { - swapchainData->fence = commandBufferToSubmit->inFlightFence; - } - - FNA3D_CommandBuffer_SubmitCurrent(renderer->commandBuffers); - - /* Rotate the UBOs */ - MOJOSHADER_vkEndFrame(renderer->mojoshaderContext); - - /* Present, if applicable */ - if (present && acquireSuccess) - { - if (renderer->supports.GGP_frame_token) - { -#if SDL_MAJOR_VERSION >= 3 - const void *token = SDL_GetPointerProperty( - SDL_GetWindowProperties(windowHandle), - "GgpFrameToken", - NULL - ); -#else - const void *token = SDL_GetWindowData( - (SDL_Window*) windowHandle, - "GgpFrameToken" - ); -#endif - presentInfoGGP.sType = VK_STRUCTURE_TYPE_PRESENT_FRAME_TOKEN_GGP; - presentInfoGGP.pNext = NULL; - presentInfoGGP.frameToken = (uint64_t) (size_t) token; - presentInfo.pNext = &presentInfoGGP; - } - else - { - presentInfo.pNext = NULL; - } - presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; - presentInfo.pNext = NULL; - presentInfo.waitSemaphoreCount = 1; - presentInfo.pWaitSemaphores = - &swapchainData->renderFinishedSemaphore; - presentInfo.swapchainCount = 1; - presentInfo.pSwapchains = &swapchainData->swapchain; - presentInfo.pImageIndices = &swapchainImageIndex; - presentInfo.pResults = NULL; - - presentResult = renderer->vkQueuePresentKHR( - renderer->unifiedQueue, - &presentInfo - ); - } - - /* Now that commands are totally done, check if we need new swapchain */ - if (present) - { - if ( !validSwapchainExists || - acquireResult == VK_ERROR_OUT_OF_DATE_KHR || - acquireResult == VK_SUBOPTIMAL_KHR || - presentResult == VK_ERROR_OUT_OF_DATE_KHR || - presentResult == VK_SUBOPTIMAL_KHR ) - { - VULKAN_INTERNAL_RecreateSwapchain(renderer, windowHandle); - } - - /* This can technically happen anywhere, but this is the nicest - * place for it to happen so we try to log it here. - */ - if ( acquireResult == VK_ERROR_DEVICE_LOST || - presentResult == VK_ERROR_DEVICE_LOST ) - { - FNA3D_LogError("Vulkan device was lost!"); - } - - if (!acquireSuccess) - { - FNA3D_LogInfo("Failed to acquire swapchain image, not presenting"); - } - } - - if (performDefrag) - { - FNA3D_Memory_Defragment( - renderer->allocator - ); - } - - /* Activate the next command buffer */ - FNA3D_CommandBuffer_BeginRecording(renderer->commandBuffers); -} - -static void VULKAN_INTERNAL_FlushCommands(VulkanRenderer *renderer, uint8_t sync) -{ - VkResult result; - - SDL_LockMutex(renderer->passLock); - FNA3D_CommandBuffer_LockForSubmit(renderer->commandBuffers); - - VULKAN_INTERNAL_SubmitCommands(renderer, 0, NULL, NULL, NULL); - - if (sync) - { - result = renderer->vkDeviceWaitIdle(renderer->logicalDevice); - - if (result != VK_SUCCESS) - { - FNA3D_LogWarn("vkDeviceWaitIdle: %s", VkErrorMessages(result)); - } - - renderer->bufferDefragInProgress = 0; - } - - SDL_UnlockMutex(renderer->passLock); - FNA3D_CommandBuffer_UnlockFromSubmit(renderer->commandBuffers); -} - -static void VULKAN_INTERNAL_FlushCommandsAndPresent( - VulkanRenderer *renderer, - FNA3D_Rect *sourceRectangle, - FNA3D_Rect *destinationRectangle, - void* overrideWindowHandle -) { - SDL_LockMutex(renderer->passLock); - FNA3D_CommandBuffer_LockForSubmit(renderer->commandBuffers); - - VULKAN_INTERNAL_SubmitCommands( - renderer, - 1, - sourceRectangle, - destinationRectangle, - overrideWindowHandle - ); - - SDL_UnlockMutex(renderer->passLock); - FNA3D_CommandBuffer_UnlockFromSubmit(renderer->commandBuffers); -} - -/* Vulkan: Swapchain */ - -static CreateSwapchainResult VULKAN_INTERNAL_CreateSwapchain( - VulkanRenderer *renderer, - void *windowHandle -) { - VkResult vulkanResult; - uint32_t i; - VulkanSwapchainData *swapchainData; - VkSwapchainCreateInfoKHR swapchainCreateInfo; - VkImageViewCreateInfo imageViewCreateInfo; - VkSemaphoreCreateInfo semaphoreCreateInfo; - SwapChainSupportDetails swapchainSupportDetails; - uint8_t swapchainSupport; - int32_t drawableWidth, drawableHeight; - - swapchainData = SDL_malloc(sizeof(VulkanSwapchainData)); - swapchainData->windowHandle = windowHandle; - - /* Each swapchain must have its own surface. */ - if (!SDL_Vulkan_CreateSurface( - (SDL_Window*) windowHandle, - renderer->instance, - NULL, /* FIXME: VAllocationCallbacks */ - &swapchainData->surface - )) { - SDL_free(swapchainData); - FNA3D_LogError( - "SDL_Vulkan_CreateSurface failed: %s", - SDL_GetError() - ); - return CREATE_SWAPCHAIN_FAIL; - } - - swapchainSupport = VULKAN_INTERNAL_QuerySwapChainSupport( - renderer, - renderer->physicalDevice, - swapchainData->surface, - &swapchainSupportDetails - ); - - if (swapchainSupport == 0) - { - renderer->vkDestroySurfaceKHR( - renderer->instance, - swapchainData->surface, - NULL - ); - if (swapchainSupportDetails.formatsLength > 0) - { - SDL_free(swapchainSupportDetails.formats); - } - if (swapchainSupportDetails.presentModesLength > 0) - { - SDL_free(swapchainSupportDetails.presentModes); - } - SDL_free(swapchainData); - FNA3D_LogError("Surface does not support swapchain creation!"); - return CREATE_SWAPCHAIN_FAIL; - } - - if ( swapchainSupportDetails.capabilities.currentExtent.width == 0 || - swapchainSupportDetails.capabilities.currentExtent.height == 0) - { - renderer->vkDestroySurfaceKHR( - renderer->instance, - swapchainData->surface, - NULL - ); - if (swapchainSupportDetails.formatsLength > 0) - { - SDL_free(swapchainSupportDetails.formats); - } - if (swapchainSupportDetails.presentModesLength > 0) - { - SDL_free(swapchainSupportDetails.presentModes); - } - SDL_free(swapchainData); - return CREATE_SWAPCHAIN_SURFACE_ZERO; - } - - swapchainData->swapchainFormat = XNAToVK_SurfaceFormat[renderer->backbufferFormat]; - swapchainData->swapchainSwizzle.r = VK_COMPONENT_SWIZZLE_IDENTITY; - swapchainData->swapchainSwizzle.g = VK_COMPONENT_SWIZZLE_IDENTITY; - swapchainData->swapchainSwizzle.b = VK_COMPONENT_SWIZZLE_IDENTITY; - swapchainData->swapchainSwizzle.a = VK_COMPONENT_SWIZZLE_IDENTITY; - - if (!VULKAN_INTERNAL_ChooseSwapSurfaceFormat( - swapchainData->swapchainFormat, - swapchainSupportDetails.formats, - swapchainSupportDetails.formatsLength, - &swapchainData->surfaceFormat - )) { - FNA3D_LogWarn("RGBA swapchain unsupported, falling back to BGRA with swizzle"); - if (renderer->backbufferFormat == FNA3D_SURFACEFORMAT_RGBA1010102) - { - swapchainData->swapchainFormat = VK_FORMAT_A2B10G10R10_UNORM_PACK32; - } - else if (renderer->backbufferFormat == FNA3D_SURFACEFORMAT_COLORSRGB_EXT) - { - swapchainData->swapchainFormat = VK_FORMAT_B8G8R8A8_SRGB; - } - else if (renderer->backbufferFormat == FNA3D_SURFACEFORMAT_COLOR) - { - swapchainData->swapchainFormat = VK_FORMAT_B8G8R8A8_UNORM; - } - else - { - FNA3D_LogWarn("Unrecognized swapchain format"); - } - swapchainData->swapchainSwizzle.r = VK_COMPONENT_SWIZZLE_B; - swapchainData->swapchainSwizzle.g = VK_COMPONENT_SWIZZLE_G; - swapchainData->swapchainSwizzle.b = VK_COMPONENT_SWIZZLE_R; - swapchainData->swapchainSwizzle.a = VK_COMPONENT_SWIZZLE_A; - - if (!VULKAN_INTERNAL_ChooseSwapSurfaceFormat( - swapchainData->swapchainFormat, - swapchainSupportDetails.formats, - swapchainSupportDetails.formatsLength, - &swapchainData->surfaceFormat - )) { - renderer->vkDestroySurfaceKHR( - renderer->instance, - swapchainData->surface, - NULL - ); - if (swapchainSupportDetails.formatsLength > 0) - { - SDL_free(swapchainSupportDetails.formats); - } - if (swapchainSupportDetails.presentModesLength > 0) - { - SDL_free(swapchainSupportDetails.presentModes); - } - SDL_free(swapchainData); - FNA3D_LogError("Device does not support swap chain format"); - return CREATE_SWAPCHAIN_FAIL; - } - } - - if (!VULKAN_INTERNAL_ChooseSwapPresentMode( - renderer->presentInterval, - swapchainSupportDetails.presentModes, - swapchainSupportDetails.presentModesLength, - &swapchainData->presentMode - )) { - renderer->vkDestroySurfaceKHR( - renderer->instance, - swapchainData->surface, - NULL - ); - if (swapchainSupportDetails.formatsLength > 0) - { - SDL_free(swapchainSupportDetails.formats); - } - if (swapchainSupportDetails.presentModesLength > 0) - { - SDL_free(swapchainSupportDetails.presentModes); - } - SDL_free(swapchainData); - FNA3D_LogError("Device does not support swap chain present mode"); - return CREATE_SWAPCHAIN_FAIL; - } - - SDL_GetWindowSizeInPixels( - (SDL_Window*) windowHandle, - &drawableWidth, - &drawableHeight - ); - - if ( drawableWidth < swapchainSupportDetails.capabilities.minImageExtent.width || - drawableWidth > swapchainSupportDetails.capabilities.maxImageExtent.width || - drawableHeight < swapchainSupportDetails.capabilities.minImageExtent.height || - drawableHeight > swapchainSupportDetails.capabilities.maxImageExtent.height ) - { - FNA3D_LogWarn("Drawable size not possible for this VkSurface!"); - - if (swapchainSupportDetails.capabilities.currentExtent.width != UINT32_MAX) - { - FNA3D_LogWarn("Falling back to an acceptable swapchain extent."); - drawableWidth = VULKAN_INTERNAL_clamp( - drawableWidth, - swapchainSupportDetails.capabilities.minImageExtent.width, - swapchainSupportDetails.capabilities.maxImageExtent.width - ); - drawableHeight = VULKAN_INTERNAL_clamp( - drawableHeight, - swapchainSupportDetails.capabilities.minImageExtent.height, - swapchainSupportDetails.capabilities.maxImageExtent.height - ); - } - else - { - renderer->vkDestroySurfaceKHR( - renderer->instance, - swapchainData->surface, - NULL - ); - if (swapchainSupportDetails.formatsLength > 0) - { - SDL_free(swapchainSupportDetails.formats); - } - if (swapchainSupportDetails.presentModesLength > 0) - { - SDL_free(swapchainSupportDetails.presentModes); - } - SDL_free(swapchainData); - FNA3D_LogError("No fallback swapchain size available!"); - return CREATE_SWAPCHAIN_FAIL; - } - } - - swapchainData->extent.width = drawableWidth; - swapchainData->extent.height = drawableHeight; - - swapchainData->imageCount = swapchainSupportDetails.capabilities.minImageCount + 1; - - if ( swapchainSupportDetails.capabilities.maxImageCount > 0 && - swapchainData->imageCount > swapchainSupportDetails.capabilities.maxImageCount ) - { - swapchainData->imageCount = swapchainSupportDetails.capabilities.maxImageCount; - } - - if (swapchainData->presentMode == VK_PRESENT_MODE_MAILBOX_KHR) - { - /* Required for proper triple-buffering. - * Note that this is below the above maxImageCount check! - * If the driver advertises MAILBOX but does not support 3 swap - * images, it's not real mailbox support, so let it fail hard. - * -flibit - */ - swapchainData->imageCount = SDL_max(swapchainData->imageCount, 3); - } - - swapchainCreateInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; - swapchainCreateInfo.pNext = NULL; - swapchainCreateInfo.flags = 0; - swapchainCreateInfo.surface = swapchainData->surface; - swapchainCreateInfo.minImageCount = swapchainData->imageCount; - swapchainCreateInfo.imageFormat = swapchainData->surfaceFormat.format; - swapchainCreateInfo.imageColorSpace = swapchainData->surfaceFormat.colorSpace; - swapchainCreateInfo.imageExtent = swapchainData->extent; - swapchainCreateInfo.imageArrayLayers = 1; - swapchainCreateInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; - swapchainCreateInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; - swapchainCreateInfo.queueFamilyIndexCount = 0; - swapchainCreateInfo.pQueueFamilyIndices = NULL; - swapchainCreateInfo.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; - swapchainCreateInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; - swapchainCreateInfo.presentMode = swapchainData->presentMode; - swapchainCreateInfo.clipped = VK_TRUE; - swapchainCreateInfo.oldSwapchain = VK_NULL_HANDLE; - - vulkanResult = renderer->vkCreateSwapchainKHR( - renderer->logicalDevice, - &swapchainCreateInfo, - NULL, - &swapchainData->swapchain - ); - - VULKAN_ERROR_CHECK(vulkanResult, vkCreateSwapchainKHR, CREATE_SWAPCHAIN_FAIL) - - renderer->vkGetSwapchainImagesKHR( - renderer->logicalDevice, - swapchainData->swapchain, - &swapchainData->imageCount, - NULL - ); - - swapchainData->images = (VkImage*) SDL_malloc( - sizeof(VkImage) * swapchainData->imageCount - ); - if (!swapchainData->images) - { - SDL_OutOfMemory(); - renderer->vkDestroySurfaceKHR( - renderer->instance, - swapchainData->surface, - NULL - ); - if (swapchainSupportDetails.formatsLength > 0) - { - SDL_free(swapchainSupportDetails.formats); - } - if (swapchainSupportDetails.presentModesLength > 0) - { - SDL_free(swapchainSupportDetails.presentModes); - } - SDL_free(swapchainData); - return CREATE_SWAPCHAIN_FAIL; - } - - swapchainData->views = (VkImageView*) SDL_malloc( - sizeof(VkImageView) * swapchainData->imageCount - ); - if (!swapchainData->views) - { - SDL_OutOfMemory(); - renderer->vkDestroySurfaceKHR( - renderer->instance, - swapchainData->surface, - NULL - ); - if (swapchainSupportDetails.formatsLength > 0) - { - SDL_free(swapchainSupportDetails.formats); - } - if (swapchainSupportDetails.presentModesLength > 0) - { - SDL_free(swapchainSupportDetails.presentModes); - } - SDL_free(swapchainData); - return CREATE_SWAPCHAIN_FAIL; - } - - swapchainData->resourceAccessTypes = (VulkanResourceAccessType*) SDL_malloc( - sizeof(VulkanResourceAccessType) * swapchainData->imageCount - ); - if (!swapchainData->resourceAccessTypes) - { - SDL_OutOfMemory(); - renderer->vkDestroySurfaceKHR( - renderer->instance, - swapchainData->surface, - NULL - ); - if (swapchainSupportDetails.formatsLength > 0) - { - SDL_free(swapchainSupportDetails.formats); - } - if (swapchainSupportDetails.presentModesLength > 0) - { - SDL_free(swapchainSupportDetails.presentModes); - } - SDL_free(swapchainData); - return CREATE_SWAPCHAIN_FAIL; - } - - renderer->vkGetSwapchainImagesKHR( - renderer->logicalDevice, - swapchainData->swapchain, - &swapchainData->imageCount, - swapchainData->images - ); - - imageViewCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; - imageViewCreateInfo.pNext = NULL; - imageViewCreateInfo.flags = 0; - imageViewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; - imageViewCreateInfo.format = swapchainData->surfaceFormat.format; - imageViewCreateInfo.components = swapchainData->swapchainSwizzle; - imageViewCreateInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - imageViewCreateInfo.subresourceRange.baseMipLevel = 0; - imageViewCreateInfo.subresourceRange.levelCount = 1; - imageViewCreateInfo.subresourceRange.baseArrayLayer = 0; - imageViewCreateInfo.subresourceRange.layerCount = 1; - for (i = 0; i < swapchainData->imageCount; i += 1) - { - imageViewCreateInfo.image = swapchainData->images[i]; - - vulkanResult = renderer->vkCreateImageView( - renderer->logicalDevice, - &imageViewCreateInfo, - NULL, - &swapchainData->views[i] - ); - - if (vulkanResult != VK_SUCCESS) - { - renderer->vkDestroySurfaceKHR( - renderer->instance, - swapchainData->surface, - NULL - ); - if (swapchainSupportDetails.formatsLength > 0) - { - SDL_free(swapchainSupportDetails.formats); - } - if (swapchainSupportDetails.presentModesLength > 0) - { - SDL_free(swapchainSupportDetails.presentModes); - } - SDL_free(swapchainData); - FNA3D_LogError("vkCreateImageView: %s", VkErrorMessages(vulkanResult)); - return CREATE_SWAPCHAIN_FAIL; - } - - swapchainData->resourceAccessTypes[i] = RESOURCE_ACCESS_NONE; - } - - semaphoreCreateInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; - semaphoreCreateInfo.pNext = NULL; - semaphoreCreateInfo.flags = 0; - - renderer->vkCreateSemaphore( - renderer->logicalDevice, - &semaphoreCreateInfo, - NULL, - &swapchainData->imageAvailableSemaphore - ); - - renderer->vkCreateSemaphore( - renderer->logicalDevice, - &semaphoreCreateInfo, - NULL, - &swapchainData->renderFinishedSemaphore - ); - - swapchainData->fence = VK_NULL_HANDLE; - -#if SDL_MAJOR_VERSION >= 3 - SDL_SetPointerProperty(SDL_GetWindowProperties(windowHandle), WINDOW_SWAPCHAIN_DATA, swapchainData); -#else - SDL_SetWindowData(windowHandle, WINDOW_SWAPCHAIN_DATA, swapchainData); -#endif - - if (renderer->swapchainDataCount >= renderer->swapchainDataCapacity) - { - renderer->swapchainDataCapacity *= 2; - renderer->swapchainDatas = SDL_realloc( - renderer->swapchainDatas, - renderer->swapchainDataCapacity * sizeof(VulkanSwapchainData*) - ); - } - renderer->swapchainDatas[renderer->swapchainDataCount] = swapchainData; - renderer->swapchainDataCount += 1; - - if (swapchainSupportDetails.formatsLength > 0) - { - SDL_free(swapchainSupportDetails.formats); - } - if (swapchainSupportDetails.presentModesLength > 0) - { - SDL_free(swapchainSupportDetails.presentModes); - } - - return CREATE_SWAPCHAIN_SUCCESS; -} - -static void VULKAN_INTERNAL_DestroySwapchain( - VulkanRenderer *renderer, - void *windowHandle -) { - uint32_t i; - VulkanSwapchainData *swapchainData; - -#if SDL_MAJOR_VERSION >= 3 - swapchainData = (VulkanSwapchainData*) SDL_GetPointerProperty(SDL_GetWindowProperties(windowHandle), WINDOW_SWAPCHAIN_DATA, NULL); -#else - swapchainData = (VulkanSwapchainData*) SDL_GetWindowData(windowHandle, WINDOW_SWAPCHAIN_DATA); -#endif - - if (swapchainData == NULL) - { - return; - } - - for (i = 0; i < renderer->framebufferArray.count; i += 1) - { - renderer->vkDestroyFramebuffer( - renderer->logicalDevice, - renderer->framebufferArray.elements[i].value, - NULL - ); - } - SDL_free(renderer->framebufferArray.elements); - renderer->framebufferArray.elements = NULL; - renderer->framebufferArray.count = 0; - renderer->framebufferArray.capacity = 0; - - for (i = 0; i < swapchainData->imageCount; i += 1) - { - renderer->vkDestroyImageView( - renderer->logicalDevice, - swapchainData->views[i], - NULL - ); - } - - SDL_free(swapchainData->images); - SDL_free(swapchainData->views); - SDL_free(swapchainData->resourceAccessTypes); - - renderer->vkDestroySwapchainKHR( - renderer->logicalDevice, - swapchainData->swapchain, - NULL - ); - - renderer->vkDestroySurfaceKHR( - renderer->instance, - swapchainData->surface, - NULL - ); - - renderer->vkDestroySemaphore( - renderer->logicalDevice, - swapchainData->imageAvailableSemaphore, - NULL - ); - - renderer->vkDestroySemaphore( - renderer->logicalDevice, - swapchainData->renderFinishedSemaphore, - NULL - ); - - for (i = 0; i < renderer->swapchainDataCount; i += 1) - { - if (windowHandle == renderer->swapchainDatas[i]->windowHandle) - { - renderer->swapchainDatas[i] = renderer->swapchainDatas[renderer->swapchainDataCount - 1]; - renderer->swapchainDataCount -= 1; - break; - } - } - -#if SDL_MAJOR_VERSION >= 3 - SDL_ClearProperty(SDL_GetWindowProperties(windowHandle), WINDOW_SWAPCHAIN_DATA); -#else - SDL_SetWindowData(windowHandle, WINDOW_SWAPCHAIN_DATA, NULL); -#endif - - SDL_free(swapchainData); -} - -static void VULKAN_INTERNAL_RecreateSwapchain( - VulkanRenderer *renderer, - void *windowHandle -) { - CreateSwapchainResult createSwapchainResult; - - renderer->vkDeviceWaitIdle(renderer->logicalDevice); - - VULKAN_INTERNAL_DestroySwapchain(renderer, windowHandle); - createSwapchainResult = VULKAN_INTERNAL_CreateSwapchain(renderer, windowHandle); - - if (createSwapchainResult == CREATE_SWAPCHAIN_FAIL) - { - return; - } - - renderer->vkDeviceWaitIdle(renderer->logicalDevice); -} - -/* Vulkan: Buffer Objects */ - -/* This function is EXTREMELY sensitive. Change this at your own peril. -cosmonaut */ -static void VULKAN_INTERNAL_SetBufferData( - FNA3D_Renderer *driverData, - FNA3D_Buffer *buffer, - int32_t offsetInBytes, - void* data, - int32_t dataLength, - FNA3D_SetDataOptions options -) { - VulkanRenderer *renderer = (VulkanRenderer*) driverData; - FNA3D_BufferContainer *container = (FNA3D_BufferContainer*) buffer; - VulkanCommandBuffer *commandBuffer; - VulkanBuffer *vulkanBuffer; - VulkanBuffer *transferBuffer; - VkDeviceSize transferOffset; - VkBufferCopy bufferCopy; - VulkanResourceAccessType accessType; - - vulkanBuffer = (VulkanBuffer*) FNA3D_Memory_GetActiveBuffer(container); - accessType = vulkanBuffer->resourceAccessType; - - if ( options == FNA3D_SETDATAOPTIONS_NONE && - dataLength == vulkanBuffer->size ) - { - /* Setting the whole buffer is basically just discard */ - options = FNA3D_SETDATAOPTIONS_DISCARD; - } - - if (options == FNA3D_SETDATAOPTIONS_NONE) - { - /* If NONE is set, we need to do a buffered copy. - * The barriers will synchronize on the GPU so the data isn't overwritten - * before it needs to be used. - */ - - VULKAN_INTERNAL_MaybeEndRenderPass(renderer); - - SDL_LockMutex(renderer->passLock); - - FNA3D_CommandBuffer_LockForTransfer(renderer->commandBuffers); - - VULKAN_INTERNAL_CopyToTransferBuffer( - renderer, - data, - dataLength, - dataLength, - &transferBuffer, - &transferOffset, - renderer->physicalDeviceProperties.properties.limits.optimalBufferCopyOffsetAlignment - ); - - VULKAN_INTERNAL_BufferMemoryBarrier( - renderer, - RESOURCE_ACCESS_TRANSFER_READ, - transferBuffer->buffer, - &transferBuffer->resourceAccessType - ); - - VULKAN_INTERNAL_BufferMemoryBarrier( - renderer, - RESOURCE_ACCESS_TRANSFER_WRITE, - vulkanBuffer->buffer, - &vulkanBuffer->resourceAccessType - ); - - bufferCopy.srcOffset = transferOffset; - bufferCopy.dstOffset = offsetInBytes; - bufferCopy.size = (VkDeviceSize)dataLength; - - commandBuffer = (VulkanCommandBuffer*) FNA3D_CommandBuffer_GetCurrent( - renderer->commandBuffers - ); - RECORD_CMD(renderer->vkCmdCopyBuffer( - commandBuffer->commandBuffer, - transferBuffer->buffer, - vulkanBuffer->buffer, - 1, - &bufferCopy - )); - - VULKAN_INTERNAL_BufferMemoryBarrier( - renderer, - accessType, - vulkanBuffer->buffer, - &vulkanBuffer->resourceAccessType - ); - - FNA3D_CommandBuffer_UnlockFromTransfer(renderer->commandBuffers); - SDL_UnlockMutex(renderer->passLock); - } - else - { - if (options == FNA3D_SETDATAOPTIONS_DISCARD && SDL_GetAtomicInt(&vulkanBuffer->refcount) > 0) - { - /* If DISCARD is set and the buffer was bound, - * we have to replace the buffer pointer. - */ - - vulkanBuffer = (VulkanBuffer*) FNA3D_Memory_DiscardActiveBuffer( - renderer->allocator, - container - ); - } - - /* If this is a defrag frame and NoOverwrite is set, wait for defrag to avoid data race */ - if (options == FNA3D_SETDATAOPTIONS_NOOVERWRITE && renderer->bufferDefragInProgress) - { - commandBuffer = (VulkanCommandBuffer*) FNA3D_CommandBuffer_GetDefragBuffer( - renderer->commandBuffers - ); - renderer->vkWaitForFences( - renderer->logicalDevice, - 1, - &commandBuffer->inFlightFence, - VK_TRUE, - UINT64_MAX - ); - - renderer->bufferDefragInProgress = 0; - } - - SDL_memcpy( - FNA3D_Memory_GetHostPointer( - vulkanBuffer->usedRegion, - offsetInBytes - ), - data, - dataLength - ); - } -} - -/* Vulkan: Texture Objects */ - -static uint8_t VULKAN_INTERNAL_CreateTexture( - VulkanRenderer *renderer, - uint32_t width, - uint32_t height, - uint32_t depth, - uint8_t isCube, - uint8_t isRenderTarget, - VkSampleCountFlagBits samples, - uint32_t levelCount, - VkFormat format, - VkComponentMapping swizzle, - VkImageAspectFlags aspectMask, - VkImageType imageType, - VkImageUsageFlags usage, - VulkanTexture *texture -) { - VkResult result; - uint8_t bindResult = 0; - VkImageCreateInfo imageCreateInfo; - VkImageViewCreateInfo imageViewCreateInfo; - uint8_t layerCount = isCube ? 6 : 1; - uint32_t i; - - imageCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; - imageCreateInfo.pNext = NULL; - imageCreateInfo.flags = isCube ? VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT : 0; - imageCreateInfo.imageType = imageType; - imageCreateInfo.format = format; - imageCreateInfo.extent.width = width; - imageCreateInfo.extent.height = height; - imageCreateInfo.extent.depth = depth; - imageCreateInfo.mipLevels = levelCount; - imageCreateInfo.arrayLayers = layerCount; - imageCreateInfo.samples = samples; - imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL; - imageCreateInfo.usage = usage; - imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - imageCreateInfo.queueFamilyIndexCount = 0; - imageCreateInfo.pQueueFamilyIndices = NULL; - imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - - result = renderer->vkCreateImage( - renderer->logicalDevice, - &imageCreateInfo, - NULL, - &texture->image - ); - VULKAN_ERROR_CHECK(result, vkCreateImage, 0) - - texture->isRenderTarget = isRenderTarget; - texture->imageCreateInfo = imageCreateInfo; - - bindResult = VULKAN_INTERNAL_BindMemoryForImage( - renderer, - texture->image, - texture, - isRenderTarget, - &texture->usedRegion - ); - - /* Binding failed, bail out! */ - if (bindResult != 1) - { - renderer->vkDestroyImage( - renderer->logicalDevice, - texture->image, - NULL - ); - - return bindResult; - } - - imageViewCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; - imageViewCreateInfo.pNext = NULL; - imageViewCreateInfo.flags = 0; - imageViewCreateInfo.image = texture->image; - imageViewCreateInfo.format = format; - imageViewCreateInfo.components = swizzle; - imageViewCreateInfo.subresourceRange.aspectMask = aspectMask; - imageViewCreateInfo.subresourceRange.baseMipLevel = 0; - imageViewCreateInfo.subresourceRange.levelCount = levelCount; - imageViewCreateInfo.subresourceRange.baseArrayLayer = 0; - imageViewCreateInfo.subresourceRange.layerCount = layerCount; - - if (isCube) - { - imageViewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_CUBE; - } - else if (imageType == VK_IMAGE_TYPE_2D) - { - imageViewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; - } - else if (imageType == VK_IMAGE_TYPE_3D) - { - imageViewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_3D; - } - else - { - FNA3D_LogError("Invalid image type: %u", imageType); - } - - result = renderer->vkCreateImageView( - renderer->logicalDevice, - &imageViewCreateInfo, - NULL, - &texture->view - ); - VULKAN_ERROR_CHECK(result, vkCreateImageView, 0) - - texture->viewCreateInfo = imageViewCreateInfo; - - /* FIXME: Reduce this memset to the minimum necessary for init! */ - SDL_memset(texture->rtViews, '\0', sizeof(texture->rtViews)); - if (isRenderTarget) - { - if (!isCube) - { - /* Framebuffer views don't like swizzling */ - imageViewCreateInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY; - imageViewCreateInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY; - imageViewCreateInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY; - imageViewCreateInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY; - - /* The view should only contain one level */ - imageViewCreateInfo.subresourceRange.levelCount = 1; - - result = renderer->vkCreateImageView( - renderer->logicalDevice, - &imageViewCreateInfo, - NULL, - &texture->rtViews[0] - ); - VULKAN_ERROR_CHECK(result, vkCreateImageView, 0) - } - else - { - /* Create a framebuffer-compatible view for each layer */ - for (i = 0; i < layerCount; i += 1) - { - imageViewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; - imageViewCreateInfo.subresourceRange.levelCount = 1; - imageViewCreateInfo.subresourceRange.layerCount = 1; - imageViewCreateInfo.subresourceRange.baseArrayLayer = i; - imageViewCreateInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY; - imageViewCreateInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY; - imageViewCreateInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY; - imageViewCreateInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY; - - result = renderer->vkCreateImageView( - renderer->logicalDevice, - &imageViewCreateInfo, - NULL, - &texture->rtViews[i] - ); - VULKAN_ERROR_CHECK(result, vkCreateImageView, 0) - } - } - } - - texture->dimensions.width = width; - texture->dimensions.height = height; - texture->depth = depth; - texture->surfaceFormat = format; - texture->levelCount = levelCount; - texture->layerCount = layerCount; - texture->resourceAccessType = RESOURCE_ACCESS_NONE; - texture->external = 0; - - return 1; -} - -static void VULKAN_INTERNAL_GetTextureData( - FNA3D_Renderer *driverData, - FNA3D_Texture *texture, - int32_t x, - int32_t y, - int32_t w, - int32_t h, - int32_t level, - int32_t layer, - void* data, - int32_t dataLength -) { - VulkanRenderer *renderer = (VulkanRenderer*) driverData; - VulkanTexture *vulkanTexture = (VulkanTexture*) texture; - VulkanCommandBuffer *commandBuffer; - FNA3D_TransferBuffer *transferBuffer; - VulkanResourceAccessType prevResourceAccess; - VkBufferImageCopy imageCopy; - uint8_t *dataPtr = (uint8_t*) data; - uint8_t *transferBufferPointer; - - VULKAN_INTERNAL_MaybeEndRenderPass(renderer); - - SDL_LockMutex(renderer->passLock); - FNA3D_CommandBuffer_LockForTransfer(renderer->commandBuffers); - - VULKAN_INTERNAL_PrepareCopyFromTransferBuffer( - renderer, - dataLength, - /* The Vulkan spec states: bufferOffset must be a multiple of 4 - * https://vulkan.lunarg.com/doc/view/1.2.141.0/windows/1.2-extensions/vkspec.html#VUID-VkBufferImageCopy-bufferOffset-00194 - */ - (VkDeviceSize)SDL_max(Texture_GetFormatSize(vulkanTexture->colorFormat), 4), - &transferBuffer, - (void**) &transferBufferPointer - ); - - /* Cache this so we can restore it later */ - prevResourceAccess = vulkanTexture->resourceAccessType; - - VULKAN_INTERNAL_ImageMemoryBarrier( - renderer, - RESOURCE_ACCESS_TRANSFER_READ, - VK_IMAGE_ASPECT_COLOR_BIT, - 0, - vulkanTexture->layerCount, - 0, - vulkanTexture->levelCount, - 0, - vulkanTexture->image, - &vulkanTexture->resourceAccessType - ); - - /* Save texture data to transfer buffer */ - - imageCopy.imageExtent.width = w; - imageCopy.imageExtent.height = h; - imageCopy.imageExtent.depth = 1; - imageCopy.imageOffset.x = x; - imageCopy.imageOffset.y = y; - imageCopy.imageOffset.z = 0; - imageCopy.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - imageCopy.imageSubresource.baseArrayLayer = layer; - imageCopy.imageSubresource.layerCount = 1; - imageCopy.imageSubresource.mipLevel = level; - imageCopy.bufferOffset = transferBuffer->offset; - imageCopy.bufferRowLength = w; - imageCopy.bufferImageHeight = h; - - commandBuffer = (VulkanCommandBuffer*) FNA3D_CommandBuffer_GetCurrent( - renderer->commandBuffers - ); - RECORD_CMD(renderer->vkCmdCopyImageToBuffer( - commandBuffer->commandBuffer, - vulkanTexture->image, - AccessMap[vulkanTexture->resourceAccessType].imageLayout, - ((VulkanBuffer*) transferBuffer->buffer)->buffer, - 1, - &imageCopy - )); - - /* Restore the image layout and wait for completion of the render pass */ - - VULKAN_INTERNAL_ImageMemoryBarrier( - renderer, - prevResourceAccess, - VK_IMAGE_ASPECT_COLOR_BIT, - 0, - vulkanTexture->layerCount, - 0, - vulkanTexture->levelCount, - 0, - vulkanTexture->image, - &vulkanTexture->resourceAccessType - ); - - VULKAN_INTERNAL_FlushCommands(renderer, 1); - - /* Read from transfer buffer */ - - SDL_memcpy( - dataPtr, - transferBufferPointer, - BytesPerImage(w, h, vulkanTexture->colorFormat) - ); - - FNA3D_CommandBuffer_UnlockFromTransfer(renderer->commandBuffers); - SDL_UnlockMutex(renderer->passLock); -} - -/* Vulkan: Mutable State Commands */ - -static void VULKAN_INTERNAL_SetViewportCommand(VulkanRenderer *renderer) -{ - VulkanCommandBuffer *commandBuffer; - VkViewport vulkanViewport; - - /* Flipping the viewport for compatibility with D3D */ - vulkanViewport.x = (float) renderer->viewport.x; - vulkanViewport.width = (float) renderer->viewport.w; - vulkanViewport.minDepth = renderer->viewport.minDepth; - vulkanViewport.maxDepth = renderer->viewport.maxDepth; -#ifdef __APPLE__ - /* For MoltenVK we just disable viewport flipping, bypassing the Vulkan spec */ - vulkanViewport.y = (float) renderer->viewport.y; - vulkanViewport.height = (float) renderer->viewport.h; -#else - /* For everyone else, we have KHR_maintenance1 to do the flipping for us */ - vulkanViewport.y = (float) (renderer->viewport.y + renderer->viewport.h); - vulkanViewport.height = (float) -renderer->viewport.h; -#endif - - commandBuffer = (VulkanCommandBuffer*) FNA3D_CommandBuffer_GetCurrent( - renderer->commandBuffers - ); - RECORD_CMD(renderer->vkCmdSetViewport( - commandBuffer->commandBuffer, - 0, - 1, - &vulkanViewport - )); -} - -static void VULKAN_INTERNAL_SetScissorRectCommand(VulkanRenderer *renderer) -{ - VulkanCommandBuffer *commandBuffer; - VkOffset2D offset; - VkExtent2D extent; - VkRect2D vulkanScissorRect; - - if (renderer->renderPassInProgress) - { - if (!renderer->rasterizerState.scissorTestEnable) - { - offset.x = 0; - offset.y = 0; - extent = renderer->colorAttachments[0]->dimensions; - } - else - { - offset.x = renderer->scissorRect.x; - offset.y = renderer->scissorRect.y; - extent.width = renderer->scissorRect.w; - extent.height = renderer->scissorRect.h; - } - - vulkanScissorRect.offset = offset; - vulkanScissorRect.extent = extent; - - commandBuffer = (VulkanCommandBuffer*) FNA3D_CommandBuffer_GetCurrent( - renderer->commandBuffers - ); - RECORD_CMD(renderer->vkCmdSetScissor( - commandBuffer->commandBuffer, - 0, - 1, - &vulkanScissorRect - )); - } -} - -static void VULKAN_INTERNAL_SetStencilReferenceValueCommand( - VulkanRenderer *renderer -) { - VulkanCommandBuffer *commandBuffer; - if (renderer->renderPassInProgress) - { - commandBuffer = (VulkanCommandBuffer*) FNA3D_CommandBuffer_GetCurrent( - renderer->commandBuffers - ); - RECORD_CMD(renderer->vkCmdSetStencilReference( - commandBuffer->commandBuffer, - VK_STENCIL_FRONT_AND_BACK, - renderer->stencilRef - )); - } -} - -static void VULKAN_INTERNAL_SetDepthBiasCommand(VulkanRenderer *renderer) -{ - VulkanCommandBuffer *commandBuffer; - if (renderer->renderPassInProgress) - { - commandBuffer = (VulkanCommandBuffer*) FNA3D_CommandBuffer_GetCurrent( - renderer->commandBuffers - ); - RECORD_CMD(renderer->vkCmdSetDepthBias( - commandBuffer->commandBuffer, - renderer->rasterizerState.depthBias, - 0.0f, /* no clamp */ - renderer->rasterizerState.slopeScaleDepthBias - )); - } -} - -/* Vulkan: Pipeline State Objects */ - -static VkPipelineLayout VULKAN_INTERNAL_FetchPipelineLayout( - VulkanRenderer *renderer, - MOJOSHADER_vkShader *vertShader, - MOJOSHADER_vkShader *fragShader -) { - VkDescriptorSetLayout setLayouts[4]; - - PipelineLayoutHash pipelineLayoutHash; - VkPipelineLayoutCreateInfo layoutCreateInfo; - VkPipelineLayout layout; - VkResult vulkanResult; - - pipelineLayoutHash.vertexSamplerLayout = VULKAN_INTERNAL_FetchSamplerDescriptorSetLayout(renderer, vertShader, VK_SHADER_STAGE_VERTEX_BIT); - pipelineLayoutHash.fragSamplerLayout = VULKAN_INTERNAL_FetchSamplerDescriptorSetLayout(renderer, fragShader, VK_SHADER_STAGE_FRAGMENT_BIT); - pipelineLayoutHash.vertexUniformLayout = renderer->vertexUniformBufferDescriptorSetLayout; - pipelineLayoutHash.fragUniformLayout = renderer->fragUniformBufferDescriptorSetLayout; - - layout = PipelineLayoutHashArray_Fetch( - &renderer->pipelineLayoutTable, - pipelineLayoutHash - ); - - if (layout != VK_NULL_HANDLE) - { - return layout; - } - - setLayouts[0] = pipelineLayoutHash.vertexSamplerLayout; - setLayouts[1] = pipelineLayoutHash.fragSamplerLayout; - setLayouts[2] = renderer->vertexUniformBufferDescriptorSetLayout; - setLayouts[3] = renderer->fragUniformBufferDescriptorSetLayout; - - layoutCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; - layoutCreateInfo.pNext = NULL; - layoutCreateInfo.flags = 0; - layoutCreateInfo.setLayoutCount = 4; - layoutCreateInfo.pSetLayouts = setLayouts; - layoutCreateInfo.pushConstantRangeCount = 0; - layoutCreateInfo.pPushConstantRanges = NULL; - - vulkanResult = renderer->vkCreatePipelineLayout( - renderer->logicalDevice, - &layoutCreateInfo, - NULL, - &layout - ); - VULKAN_ERROR_CHECK(vulkanResult, vkCreatePipelineLayout, VK_NULL_HANDLE) - - PipelineLayoutHashArray_Insert( - &renderer->pipelineLayoutTable, - pipelineLayoutHash, - layout - ); - return layout; -} - -static void VULKAN_INTERNAL_GenerateVertexInputInfo( - VulkanRenderer *renderer, - VkVertexInputBindingDescription *bindingDescriptions, - VkVertexInputAttributeDescription* attributeDescriptions, - uint32_t *attributeDescriptionCount, - VkVertexInputBindingDivisorDescriptionEXT *divisorDescriptions, - uint32_t *divisorDescriptionCount -) { - MOJOSHADER_vkShader *vertexShader, *blah; - uint8_t attrUse[MOJOSHADER_USAGE_TOTAL][16]; - uint32_t attributeDescriptionCounter = 0; - uint32_t divisorDescriptionCounter = 0; - int32_t i, j, k; - FNA3D_VertexDeclaration vertexDeclaration; - FNA3D_VertexElement element; - FNA3D_VertexElementUsage usage; - int32_t index, attribLoc; - VkVertexInputAttributeDescription vInputAttribDescription; - VkVertexInputBindingDescription vertexInputBindingDescription; - VkVertexInputBindingDivisorDescriptionEXT divisorDescription; - - MOJOSHADER_vkGetBoundShaders(renderer->mojoshaderContext, &vertexShader, &blah); - - SDL_memset(attrUse, '\0', sizeof(attrUse)); - for (i = 0; i < (int32_t) renderer->numVertexBindings; i += 1) - { - vertexDeclaration = - renderer->vertexBindings[i].vertexDeclaration; - - for (j = 0; j < vertexDeclaration.elementCount; j += 1) - { - element = vertexDeclaration.elements[j]; - usage = element.vertexElementUsage; - index = element.usageIndex; - - if (attrUse[usage][index]) - { - index = -1; - - for (k = 0; k < MAX_VERTEX_ATTRIBUTES; k += 1) - { - if (!attrUse[usage][k]) - { - index = k; - break; - } - } - - if (index < 0) - { - FNA3D_LogError( - "Vertex usage collision!" - ); - } - } - - attrUse[usage][index] = 1; - - attribLoc = MOJOSHADER_vkGetVertexAttribLocation( - vertexShader, - VertexAttribUsage(usage), - index - ); - - if (attribLoc == -1) - { - /* Stream not in use! */ - continue; - } - - vInputAttribDescription.location = attribLoc; - vInputAttribDescription.format = XNAToVK_VertexAttribType[ - element.vertexElementFormat - ]; - vInputAttribDescription.offset = element.offset; - vInputAttribDescription.binding = i; - - attributeDescriptions[attributeDescriptionCounter] = - vInputAttribDescription; - attributeDescriptionCounter += 1; - } - - vertexInputBindingDescription.binding = i; - vertexInputBindingDescription.stride = - vertexDeclaration.vertexStride; - - if (renderer->vertexBindings[i].instanceFrequency > 0) - { - vertexInputBindingDescription.inputRate = - VK_VERTEX_INPUT_RATE_INSTANCE; - - divisorDescription.binding = i; - divisorDescription.divisor = - renderer->vertexBindings[i].instanceFrequency; - - divisorDescriptions[divisorDescriptionCounter] = - divisorDescription; - divisorDescriptionCounter += 1; - } - else - { - vertexInputBindingDescription.inputRate = - VK_VERTEX_INPUT_RATE_VERTEX; - } - - bindingDescriptions[i] = vertexInputBindingDescription; - } - - *attributeDescriptionCount = attributeDescriptionCounter; - *divisorDescriptionCount = divisorDescriptionCounter; -} - -static VkPipeline VULKAN_INTERNAL_FetchPipeline(VulkanRenderer *renderer) -{ - VkResult vulkanResult; - VkPipeline pipeline; - VkPipelineViewportStateCreateInfo viewportStateInfo; - VkPipelineInputAssemblyStateCreateInfo inputAssemblyInfo; - VkVertexInputBindingDescription *bindingDescriptions; - VkVertexInputAttributeDescription *attributeDescriptions; - uint32_t attributeDescriptionCount; - VkVertexInputBindingDivisorDescriptionEXT *divisorDescriptions; - uint32_t divisorDescriptionCount; - VkPipelineVertexInputStateCreateInfo vertexInputInfo; - VkPipelineVertexInputDivisorStateCreateInfoEXT divisorStateInfo; - VkPipelineRasterizationStateCreateInfo rasterizerInfo; - VkPipelineMultisampleStateCreateInfo multisamplingInfo; - VkPipelineColorBlendAttachmentState colorBlendAttachments[MAX_RENDERTARGET_BINDINGS]; - VkPipelineColorBlendStateCreateInfo colorBlendStateInfo; - VkStencilOpState frontStencilState, backStencilState; - VkPipelineDepthStencilStateCreateInfo depthStencilStateInfo; - static const VkDynamicState dynamicStates[] = - { - VK_DYNAMIC_STATE_VIEWPORT, - VK_DYNAMIC_STATE_SCISSOR, - VK_DYNAMIC_STATE_BLEND_CONSTANTS, - VK_DYNAMIC_STATE_STENCIL_REFERENCE, - VK_DYNAMIC_STATE_DEPTH_BIAS - }; - VkPipelineDynamicStateCreateInfo dynamicStateInfo; - MOJOSHADER_vkShader *vertShader, *fragShader; - VkPipelineShaderStageCreateInfo stageInfos[2]; - VkGraphicsPipelineCreateInfo pipelineCreateInfo; - - PipelineHash hash; - hash.blendState = GetPackedBlendState(renderer->blendState); - hash.rasterizerState = GetPackedRasterizerState( - renderer->rasterizerState, - renderer->rasterizerState.depthBias * XNAToVK_DepthBiasScale( - XNAToVK_DepthFormat( - renderer, - renderer->currentDepthFormat - ) - ) - ); - hash.depthStencilState = GetPackedDepthStencilState( - renderer->depthStencilState - ); - hash.vertexBufferBindingsIndex = renderer->currentVertexBufferBindingsIndex; - hash.primitiveType = renderer->currentPrimitiveType; - hash.sampleMask = renderer->multiSampleMask[0]; - MOJOSHADER_vkGetBoundShaders(renderer->mojoshaderContext, &vertShader, &fragShader); - hash.vertShader = vertShader; - hash.fragShader = fragShader; - hash.renderPass = renderer->renderPass; - - renderer->currentPipelineLayout = VULKAN_INTERNAL_FetchPipelineLayout( - renderer, - vertShader, - fragShader - ); - - pipeline = PipelineHashTable_Fetch(&renderer->pipelineHashTable, hash); - if (pipeline != VK_NULL_HANDLE) - { - return pipeline; - } - - /* Viewport / Scissor */ - - /* NOTE: because viewport and scissor are dynamic, - * values must be set using the command buffer - */ - viewportStateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; - viewportStateInfo.pNext = NULL; - viewportStateInfo.flags = 0; - viewportStateInfo.viewportCount = 1; - viewportStateInfo.pViewports = NULL; - viewportStateInfo.scissorCount = 1; - viewportStateInfo.pScissors = NULL; - - /* Input Assembly */ - - inputAssemblyInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; - inputAssemblyInfo.pNext = NULL; - inputAssemblyInfo.flags = 0; - inputAssemblyInfo.topology = XNAToVK_Topology[ - renderer->currentPrimitiveType - ]; - inputAssemblyInfo.primitiveRestartEnable = VK_FALSE; - - /* Vertex Input */ - - bindingDescriptions = (VkVertexInputBindingDescription*) SDL_malloc( - renderer->numVertexBindings * - sizeof(VkVertexInputBindingDescription) - ); - attributeDescriptions = (VkVertexInputAttributeDescription*) SDL_malloc( - renderer->numVertexBindings * - MAX_VERTEX_ATTRIBUTES * - sizeof(VkVertexInputAttributeDescription) - ); - divisorDescriptions = (VkVertexInputBindingDivisorDescriptionEXT*) SDL_malloc( - renderer->numVertexBindings * - sizeof(VkVertexInputBindingDivisorDescriptionEXT) - ); - - VULKAN_INTERNAL_GenerateVertexInputInfo( - renderer, - bindingDescriptions, - attributeDescriptions, - &attributeDescriptionCount, - divisorDescriptions, - &divisorDescriptionCount - ); - - vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; - if (divisorDescriptionCount > 0) - { - divisorStateInfo.sType = - VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT; - divisorStateInfo.pNext = NULL; - divisorStateInfo.vertexBindingDivisorCount = - divisorDescriptionCount; - divisorStateInfo.pVertexBindingDivisors = divisorDescriptions; - vertexInputInfo.pNext = &divisorStateInfo; - } - else - { - vertexInputInfo.pNext = NULL; - } - - vertexInputInfo.flags = 0; - vertexInputInfo.vertexBindingDescriptionCount = - renderer->numVertexBindings; - vertexInputInfo.pVertexBindingDescriptions = bindingDescriptions; - vertexInputInfo.vertexAttributeDescriptionCount = - attributeDescriptionCount; - vertexInputInfo.pVertexAttributeDescriptions = attributeDescriptions; - - /* Rasterizer */ - - rasterizerInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; - rasterizerInfo.pNext = NULL; - rasterizerInfo.flags = 0; - rasterizerInfo.depthClampEnable = VK_FALSE; - rasterizerInfo.rasterizerDiscardEnable = VK_FALSE; - rasterizerInfo.polygonMode = XNAToVK_PolygonMode[ - renderer->rasterizerState.fillMode - ]; - rasterizerInfo.cullMode = XNAToVK_CullMode[ - renderer->rasterizerState.cullMode - ]; - /* This is reversed because we are flipping the viewport -cosmonaut */ - rasterizerInfo.frontFace = VK_FRONT_FACE_CLOCKWISE; - rasterizerInfo.depthBiasEnable = VK_TRUE; - rasterizerInfo.depthBiasConstantFactor = 0.0f; - rasterizerInfo.depthBiasClamp = 0.0f; - rasterizerInfo.depthBiasSlopeFactor = 0.0f; - rasterizerInfo.lineWidth = 1.0f; - - /* Multisample */ - - multisamplingInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; - multisamplingInfo.pNext = NULL; - multisamplingInfo.flags = 0; - multisamplingInfo.rasterizationSamples = XNAToVK_SampleCount( - renderer->multiSampleCount - ); - multisamplingInfo.sampleShadingEnable = VK_FALSE; - multisamplingInfo.minSampleShading = 1.0f; - multisamplingInfo.pSampleMask = renderer->multiSampleMask; - multisamplingInfo.alphaToCoverageEnable = VK_FALSE; - multisamplingInfo.alphaToOneEnable = VK_FALSE; - - /* Blend */ - - colorBlendAttachments[0].blendEnable = !( - renderer->blendState.colorSourceBlend == FNA3D_BLEND_ONE && - renderer->blendState.colorDestinationBlend == FNA3D_BLEND_ZERO && - renderer->blendState.alphaSourceBlend == FNA3D_BLEND_ONE && - renderer->blendState.alphaDestinationBlend == FNA3D_BLEND_ZERO - ); - if (colorBlendAttachments[0].blendEnable) - { - colorBlendAttachments[0].srcColorBlendFactor = XNAToVK_BlendFactor[ - renderer->blendState.colorSourceBlend - ]; - colorBlendAttachments[0].srcAlphaBlendFactor = XNAToVK_BlendFactor[ - renderer->blendState.alphaSourceBlend - ]; - colorBlendAttachments[0].dstColorBlendFactor = XNAToVK_BlendFactor[ - renderer->blendState.colorDestinationBlend - ]; - colorBlendAttachments[0].dstAlphaBlendFactor = XNAToVK_BlendFactor[ - renderer->blendState.alphaDestinationBlend - ]; - - colorBlendAttachments[0].colorBlendOp = XNAToVK_BlendOp[ - renderer->blendState.colorBlendFunction - ]; - colorBlendAttachments[0].alphaBlendOp = XNAToVK_BlendOp[ - renderer->blendState.alphaBlendFunction - ]; - } - else - { - colorBlendAttachments[0].srcColorBlendFactor = VK_BLEND_FACTOR_ONE; - colorBlendAttachments[0].srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; - colorBlendAttachments[0].dstColorBlendFactor = VK_BLEND_FACTOR_ZERO; - colorBlendAttachments[0].dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; - colorBlendAttachments[0].colorBlendOp = VK_BLEND_OP_ADD; - colorBlendAttachments[0].alphaBlendOp = VK_BLEND_OP_ADD; - } - colorBlendAttachments[1] = colorBlendAttachments[0]; - colorBlendAttachments[2] = colorBlendAttachments[0]; - colorBlendAttachments[3] = colorBlendAttachments[0]; - - colorBlendAttachments[0].colorWriteMask = - renderer->blendState.colorWriteEnable; - colorBlendAttachments[1].colorWriteMask = - renderer->blendState.colorWriteEnable1; - colorBlendAttachments[2].colorWriteMask = - renderer->blendState.colorWriteEnable2; - colorBlendAttachments[3].colorWriteMask = - renderer->blendState.colorWriteEnable3; - - colorBlendStateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; - colorBlendStateInfo.pNext = NULL; - colorBlendStateInfo.flags = 0; - colorBlendStateInfo.logicOpEnable = VK_FALSE; - colorBlendStateInfo.logicOp = VK_LOGIC_OP_COPY; - colorBlendStateInfo.attachmentCount = renderer->colorAttachmentCount; - colorBlendStateInfo.pAttachments = colorBlendAttachments; - colorBlendStateInfo.blendConstants[0] = 0.0f; - colorBlendStateInfo.blendConstants[1] = 0.0f; - colorBlendStateInfo.blendConstants[2] = 0.0f; - colorBlendStateInfo.blendConstants[3] = 0.0f; - - /* Stencil */ - - frontStencilState.failOp = XNAToVK_StencilOp[ - renderer->depthStencilState.stencilFail - ]; - frontStencilState.passOp = XNAToVK_StencilOp[ - renderer->depthStencilState.stencilPass - ]; - frontStencilState.depthFailOp = XNAToVK_StencilOp[ - renderer->depthStencilState.stencilDepthBufferFail - ]; - frontStencilState.compareOp = XNAToVK_CompareOp[ - renderer->depthStencilState.stencilFunction - ]; - frontStencilState.compareMask = renderer->depthStencilState.stencilMask; - frontStencilState.writeMask = renderer->depthStencilState.stencilWriteMask; - frontStencilState.reference = renderer->depthStencilState.referenceStencil; - - if (renderer->depthStencilState.twoSidedStencilMode) - { - backStencilState.failOp = XNAToVK_StencilOp[ - renderer->depthStencilState.ccwStencilFail - ]; - backStencilState.passOp = XNAToVK_StencilOp[ - renderer->depthStencilState.ccwStencilPass - ]; - backStencilState.depthFailOp = XNAToVK_StencilOp[ - renderer->depthStencilState.ccwStencilDepthBufferFail - ]; - backStencilState.compareOp = XNAToVK_CompareOp[ - renderer->depthStencilState.ccwStencilFunction - ]; - backStencilState.compareMask = renderer->depthStencilState.stencilMask; - backStencilState.writeMask = renderer->depthStencilState.stencilWriteMask; - backStencilState.reference = renderer->depthStencilState.referenceStencil; - } - else - { - backStencilState = frontStencilState; - } - - /* Depth Stencil */ - - depthStencilStateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; - depthStencilStateInfo.pNext = NULL; - depthStencilStateInfo.flags = 0; /* Unused */ - depthStencilStateInfo.depthTestEnable = - renderer->depthStencilState.depthBufferEnable; - depthStencilStateInfo.depthWriteEnable = - renderer->depthStencilState.depthBufferWriteEnable; - depthStencilStateInfo.depthCompareOp = XNAToVK_CompareOp[ - renderer->depthStencilState.depthBufferFunction - ]; - depthStencilStateInfo.depthBoundsTestEnable = 0; /* Unused */ - depthStencilStateInfo.stencilTestEnable = - renderer->depthStencilState.stencilEnable; - depthStencilStateInfo.front = frontStencilState; - depthStencilStateInfo.back = backStencilState; - depthStencilStateInfo.minDepthBounds = 0; /* Unused */ - depthStencilStateInfo.maxDepthBounds = 0; /* Unused */ - - /* Dynamic State */ - - dynamicStateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; - dynamicStateInfo.pNext = NULL; - dynamicStateInfo.flags = 0; - dynamicStateInfo.dynamicStateCount = SDL_arraysize(dynamicStates); - dynamicStateInfo.pDynamicStates = dynamicStates; - - /* Shaders */ - - stageInfos[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; - stageInfos[0].pNext = NULL; - stageInfos[0].flags = 0; - stageInfos[0].stage = VK_SHADER_STAGE_VERTEX_BIT; - stageInfos[0].pName = MOJOSHADER_vkGetShaderParseData(vertShader)->mainfn; - stageInfos[0].pSpecializationInfo = NULL; - - stageInfos[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; - stageInfos[1].pNext = NULL; - stageInfos[1].flags = 0; - stageInfos[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT; - stageInfos[1].pName = MOJOSHADER_vkGetShaderParseData(fragShader)->mainfn; - stageInfos[1].pSpecializationInfo = NULL; - - MOJOSHADER_vkGetShaderModules( - renderer->mojoshaderContext, - &stageInfos[0].module, - &stageInfos[1].module - ); - - /* Pipeline */ - - pipelineCreateInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; - pipelineCreateInfo.pNext = NULL; - pipelineCreateInfo.flags = 0; - pipelineCreateInfo.stageCount = 2; - pipelineCreateInfo.pStages = stageInfos; - pipelineCreateInfo.pVertexInputState = &vertexInputInfo; - pipelineCreateInfo.pInputAssemblyState = &inputAssemblyInfo; - pipelineCreateInfo.pTessellationState = NULL; - pipelineCreateInfo.pViewportState = &viewportStateInfo; - pipelineCreateInfo.pRasterizationState = &rasterizerInfo; - pipelineCreateInfo.pMultisampleState = &multisamplingInfo; - pipelineCreateInfo.pDepthStencilState = &depthStencilStateInfo; - pipelineCreateInfo.pColorBlendState = &colorBlendStateInfo; - pipelineCreateInfo.pDynamicState = &dynamicStateInfo; - pipelineCreateInfo.layout = renderer->currentPipelineLayout; - pipelineCreateInfo.renderPass = renderer->renderPass; - pipelineCreateInfo.subpass = 0; - pipelineCreateInfo.basePipelineHandle = VK_NULL_HANDLE; - pipelineCreateInfo.basePipelineIndex = 0; - - vulkanResult = renderer->vkCreateGraphicsPipelines( - renderer->logicalDevice, - renderer->pipelineCache, - 1, - &pipelineCreateInfo, - NULL, - &pipeline - ); - VULKAN_ERROR_CHECK(vulkanResult, vkCreateGraphicsPipelines, VK_NULL_HANDLE) - - SDL_free(bindingDescriptions); - SDL_free(attributeDescriptions); - SDL_free(divisorDescriptions); - - PipelineHashTable_Insert(&renderer->pipelineHashTable, hash, pipeline); - return pipeline; -} - -static void VULKAN_INTERNAL_BindPipeline(VulkanRenderer *renderer) -{ - VulkanCommandBuffer *commandBuffer; - VkShaderModule vertShader, fragShader; - MOJOSHADER_vkGetShaderModules(renderer->mojoshaderContext, &vertShader, &fragShader); - - if ( renderer->needNewPipeline || - renderer->currentVertShader != vertShader || - renderer->currentFragShader != fragShader ) - { - VkPipeline pipeline = VULKAN_INTERNAL_FetchPipeline(renderer); - - if (pipeline != renderer->currentPipeline) - { - commandBuffer = (VulkanCommandBuffer*) FNA3D_CommandBuffer_GetCurrent( - renderer->commandBuffers - ); - RECORD_CMD(renderer->vkCmdBindPipeline( - commandBuffer->commandBuffer, - VK_PIPELINE_BIND_POINT_GRAPHICS, - pipeline - )); - renderer->currentPipeline = pipeline; - renderer->fragSamplerDescriptorSetDataNeedsUpdate = 1; - renderer->vertexSamplerDescriptorSetDataNeedsUpdate = 1; - } - - renderer->needNewPipeline = 0; - renderer->currentVertShader = vertShader; - renderer->currentFragShader = fragShader; - } -} - -/* Vulkan: The Faux-Backbuffer */ - -static uint8_t VULKAN_INTERNAL_CreateFauxBackbuffer( - VulkanRenderer *renderer, - FNA3D_PresentationParameters *presentationParameters -) { - VkFormat vulkanDepthStencilFormat; - VkImageAspectFlags depthAspectFlags = VK_IMAGE_ASPECT_DEPTH_BIT; - VkFormat format; - VkComponentMapping swizzle; - - renderer->backbufferFormat = presentationParameters->backBufferFormat; - renderer->presentInterval = presentationParameters->presentationInterval; - - format = XNAToVK_SurfaceFormat[renderer->backbufferFormat]; - - swizzle.r = VK_COMPONENT_SWIZZLE_IDENTITY; - swizzle.g = VK_COMPONENT_SWIZZLE_IDENTITY; - swizzle.b = VK_COMPONENT_SWIZZLE_IDENTITY; - swizzle.a = VK_COMPONENT_SWIZZLE_IDENTITY; - - renderer->fauxBackbufferColor.handle = (VulkanTexture*) SDL_malloc(sizeof(VulkanTexture)); - - if (!VULKAN_INTERNAL_CreateTexture( - renderer, - presentationParameters->backBufferWidth, - presentationParameters->backBufferHeight, - 1, - 0, - 1, - VK_SAMPLE_COUNT_1_BIT, - 1, - format, - swizzle, - VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_TYPE_2D, - /* FIXME: Transfer bit probably only needs to be set on 0? */ - ( - VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | - VK_IMAGE_USAGE_TRANSFER_SRC_BIT | - VK_IMAGE_USAGE_TRANSFER_DST_BIT - ), - renderer->fauxBackbufferColor.handle - )) { - FNA3D_LogError("Failed to create faux backbuffer colorbuffer"); - return 0; - } - renderer->fauxBackbufferColor.handle->colorFormat = renderer->backbufferFormat; - - renderer->fauxBackbufferWidth = presentationParameters->backBufferWidth; - renderer->fauxBackbufferHeight = presentationParameters->backBufferHeight; - - VULKAN_INTERNAL_ImageMemoryBarrier( - renderer, - RESOURCE_ACCESS_COLOR_ATTACHMENT_READ_WRITE, - VK_IMAGE_ASPECT_COLOR_BIT, - 0, - renderer->fauxBackbufferColor.handle->layerCount, - 0, - renderer->fauxBackbufferColor.handle->levelCount, - 0, - renderer->fauxBackbufferColor.handle->image, - &renderer->fauxBackbufferColor.handle->resourceAccessType - ); - - renderer->fauxBackbufferMultiSampleCount = - presentationParameters->multiSampleCount; - renderer->fauxBackbufferMultiSampleColor = NULL; - - if (renderer->fauxBackbufferMultiSampleCount > 0) - { - renderer->fauxBackbufferMultiSampleColor = (VulkanTexture*) SDL_malloc( - sizeof(VulkanTexture) - ); - - VULKAN_INTERNAL_CreateTexture( - renderer, - presentationParameters->backBufferWidth, - presentationParameters->backBufferHeight, - 1, - 0, - 1, - XNAToVK_SampleCount(presentationParameters->multiSampleCount), - 1, - format, - swizzle, - VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_TYPE_2D, - VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, - renderer->fauxBackbufferMultiSampleColor - ); - /* FIXME: Swapchain format may not be an FNA3D_SurfaceFormat! */ - renderer->fauxBackbufferMultiSampleColor->colorFormat = renderer->backbufferFormat; - - VULKAN_INTERNAL_ImageMemoryBarrier( - renderer, - RESOURCE_ACCESS_COLOR_ATTACHMENT_READ_WRITE, - VK_IMAGE_ASPECT_COLOR_BIT, - 0, - renderer->fauxBackbufferMultiSampleColor->layerCount, - 0, - renderer->fauxBackbufferMultiSampleColor->levelCount, - 0, - renderer->fauxBackbufferMultiSampleColor->image, - &renderer->fauxBackbufferMultiSampleColor->resourceAccessType - ); - } - - /* Create faux backbuffer depth stencil image */ - - renderer->fauxBackbufferDepthStencil.handle = NULL; - if (presentationParameters->depthStencilFormat != FNA3D_DEPTHFORMAT_NONE) - { - renderer->fauxBackbufferDepthStencil.handle = (VulkanTexture*) SDL_malloc( - sizeof(VulkanTexture) - ); - - vulkanDepthStencilFormat = XNAToVK_DepthFormat( - renderer, - presentationParameters->depthStencilFormat - ); - - if (DepthFormatContainsStencil(vulkanDepthStencilFormat)) - { - depthAspectFlags |= VK_IMAGE_ASPECT_STENCIL_BIT; - } - - if (!VULKAN_INTERNAL_CreateTexture( - renderer, - presentationParameters->backBufferWidth, - presentationParameters->backBufferHeight, - 1, - 0, - 1, - XNAToVK_SampleCount( - presentationParameters->multiSampleCount - ), - 1, - vulkanDepthStencilFormat, - RGBA_SWIZZLE, - depthAspectFlags, - VK_IMAGE_TYPE_2D, - ( - VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | - VK_IMAGE_USAGE_TRANSFER_DST_BIT - ), - renderer->fauxBackbufferDepthStencil.handle - )) { - FNA3D_LogError("Failed to create depth stencil image"); - return 0; - } - renderer->fauxBackbufferDepthStencil.handle->depthStencilFormat = - presentationParameters->depthStencilFormat; - - /* Layout transition if required */ - - VULKAN_INTERNAL_ImageMemoryBarrier( - renderer, - RESOURCE_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_WRITE, - depthAspectFlags, - 0, - renderer->fauxBackbufferDepthStencil.handle->layerCount, - 0, - renderer->fauxBackbufferDepthStencil.handle->levelCount, - 0, - renderer->fauxBackbufferDepthStencil.handle->image, - &renderer->fauxBackbufferDepthStencil.handle->resourceAccessType - ); - - if (!renderer->renderTargetBound) - { - renderer->nextRenderPassDepthStencilAttachment = - renderer->fauxBackbufferDepthStencil.handle; - - renderer->nextRenderPassDepthFormat = - presentationParameters->depthStencilFormat; - } - } - - if (!renderer->renderTargetBound) - { - renderer->nextRenderPassColorAttachments[0] = - renderer->fauxBackbufferColor.handle; - renderer->nextRenderPassColorAttachmentCount = 1; - - if (renderer->fauxBackbufferMultiSampleCount > 0) - { - renderer->nextRenderPassColorMultiSampleAttachments[0] = - renderer->fauxBackbufferMultiSampleColor; - renderer->nextRenderPassMultiSampleCount = - renderer->fauxBackbufferMultiSampleCount; - } - } - - return 1; -} - -static void VULKAN_INTERNAL_DestroyFauxBackbuffer(VulkanRenderer *renderer) -{ - renderer->vkDestroyFramebuffer( - renderer->logicalDevice, - renderer->fauxBackbufferFramebuffer, - NULL - ); - - VULKAN_INTERNAL_DestroyTexture( - renderer, - renderer->fauxBackbufferColor.handle - ); - - if (renderer->fauxBackbufferMultiSampleColor != NULL) - { - VULKAN_INTERNAL_DestroyTexture( - renderer, - renderer->fauxBackbufferMultiSampleColor - ); - } - - if (renderer->fauxBackbufferDepthStencil.handle != NULL) - { - VULKAN_INTERNAL_DestroyTexture( - renderer, - renderer->fauxBackbufferDepthStencil.handle - ); - } -} - -/* Vulkan: Render Passes */ - -static VkRenderPass VULKAN_INTERNAL_FetchRenderPass(VulkanRenderer *renderer) -{ - VkResult vulkanResult; - VkRenderPass renderPass; - VkAttachmentDescription attachmentDescriptions[2 * MAX_RENDERTARGET_BINDINGS + 1]; - uint32_t attachmentDescriptionsCount = 0; - uint32_t i; - VkAttachmentReference colorAttachmentReferences[MAX_RENDERTARGET_BINDINGS]; - uint32_t colorAttachmentReferenceCount = 0; - VkAttachmentReference resolveReferences[MAX_RENDERTARGET_BINDINGS + 1]; - uint32_t resolveReferenceCount = 0; - VkAttachmentReference depthStencilAttachmentReference; - VkSubpassDescription subpass; - VkRenderPassCreateInfo renderPassCreateInfo; - - RenderPassHash hash; - hash.colorAttachmentFormatOne = renderer->colorAttachments[0]->surfaceFormat; - hash.colorAttachmentFormatTwo = renderer->colorAttachments[1] != NULL ? - renderer->colorAttachments[1]->surfaceFormat : - VK_FORMAT_UNDEFINED; - hash.colorAttachmentFormatThree = renderer->colorAttachments[2] != NULL ? - renderer->colorAttachments[2]->surfaceFormat : - VK_FORMAT_UNDEFINED; - hash.colorAttachmentFormatFour = renderer->colorAttachments[3] != NULL ? - renderer->colorAttachments[3]->surfaceFormat : - VK_FORMAT_UNDEFINED; - hash.depthStencilAttachmentFormat = renderer->depthStencilAttachment != NULL ? - renderer->depthStencilAttachment->surfaceFormat : - VK_FORMAT_UNDEFINED; - hash.clearColor = renderer->shouldClearColorOnBeginPass; - hash.clearDepth = renderer->shouldClearDepthOnBeginPass; - hash.clearStencil = renderer->shouldClearStencilOnBeginPass; - hash.preserveTargetContents = renderer->nextRenderPassPreserveTargetContents; - - hash.width = renderer->colorAttachments[0]->dimensions.width; - hash.height = renderer->colorAttachments[0]->dimensions.height; - hash.multiSampleCount = renderer->multiSampleCount; - - /* The render pass is already cached, can return it */ - renderPass = RenderPassHashArray_Fetch( - &renderer->renderPassArray, - hash - ); - if (renderPass != VK_NULL_HANDLE) - { - return renderPass; - } - - /* - * FIXME: We have to always store just in case changing render state - * breaks the render pass. Otherwise we risk discarding necessary data. - * The only way to avoid this would be to buffer draw calls so we can - * ensure that only the final render pass before switching render targets - * may be discarded. - */ - - for (i = 0; i < renderer->colorAttachmentCount; i += 1) - { - if (renderer->multiSampleCount > 0) - { - /* Resolve attachment and multisample attachment */ - - attachmentDescriptions[attachmentDescriptionsCount].flags = 0; - attachmentDescriptions[attachmentDescriptionsCount].format = - renderer->colorAttachments[i]->surfaceFormat; - attachmentDescriptions[attachmentDescriptionsCount].samples = - VK_SAMPLE_COUNT_1_BIT; - attachmentDescriptions[attachmentDescriptionsCount].loadOp = - hash.clearColor ? - VK_ATTACHMENT_LOAD_OP_CLEAR : - VK_ATTACHMENT_LOAD_OP_LOAD; - attachmentDescriptions[attachmentDescriptionsCount].storeOp = - VK_ATTACHMENT_STORE_OP_STORE; - attachmentDescriptions[attachmentDescriptionsCount].stencilLoadOp = - VK_ATTACHMENT_LOAD_OP_DONT_CARE; - attachmentDescriptions[attachmentDescriptionsCount].stencilStoreOp = - VK_ATTACHMENT_STORE_OP_DONT_CARE; - attachmentDescriptions[attachmentDescriptionsCount].initialLayout = - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - attachmentDescriptions[attachmentDescriptionsCount].finalLayout = - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - - resolveReferences[resolveReferenceCount].attachment = - attachmentDescriptionsCount; - resolveReferences[resolveReferenceCount].layout = - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - - attachmentDescriptionsCount += 1; - resolveReferenceCount += 1; - - attachmentDescriptions[attachmentDescriptionsCount].flags = 0; - attachmentDescriptions[attachmentDescriptionsCount].format = - renderer->colorMultiSampleAttachments[i]->surfaceFormat; - attachmentDescriptions[attachmentDescriptionsCount].samples = - XNAToVK_SampleCount(renderer->multiSampleCount); - attachmentDescriptions[attachmentDescriptionsCount].loadOp = - hash.clearColor ? - VK_ATTACHMENT_LOAD_OP_CLEAR : - VK_ATTACHMENT_LOAD_OP_LOAD; - attachmentDescriptions[attachmentDescriptionsCount].storeOp = - VK_ATTACHMENT_STORE_OP_STORE; - /* - * Once above FIXME is resolved: - * hash.preserveTargetContents ? - * VK_ATTACHMENT_STORE_OP_STORE : - * VK_ATTACHMENT_STORE_OP_DONT_CARE; - */ - attachmentDescriptions[attachmentDescriptionsCount].stencilLoadOp = - VK_ATTACHMENT_LOAD_OP_DONT_CARE; - attachmentDescriptions[attachmentDescriptionsCount].stencilStoreOp = - VK_ATTACHMENT_STORE_OP_DONT_CARE; - attachmentDescriptions[attachmentDescriptionsCount].initialLayout = - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - attachmentDescriptions[attachmentDescriptionsCount].finalLayout = - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - - colorAttachmentReferences[colorAttachmentReferenceCount].attachment = - attachmentDescriptionsCount; - colorAttachmentReferences[colorAttachmentReferenceCount].layout = - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - - attachmentDescriptionsCount += 1; - colorAttachmentReferenceCount += 1; - } - else - { - /* Regular old attachment */ - - attachmentDescriptions[attachmentDescriptionsCount].flags = 0; - attachmentDescriptions[attachmentDescriptionsCount].format = - renderer->colorAttachments[i]->surfaceFormat; - attachmentDescriptions[attachmentDescriptionsCount].samples = - VK_SAMPLE_COUNT_1_BIT; - attachmentDescriptions[attachmentDescriptionsCount].loadOp = - hash.clearColor ? - VK_ATTACHMENT_LOAD_OP_CLEAR : - VK_ATTACHMENT_LOAD_OP_LOAD; - attachmentDescriptions[attachmentDescriptionsCount].storeOp = - VK_ATTACHMENT_STORE_OP_STORE; - attachmentDescriptions[attachmentDescriptionsCount].stencilLoadOp = - VK_ATTACHMENT_LOAD_OP_DONT_CARE; - attachmentDescriptions[attachmentDescriptionsCount].stencilStoreOp = - VK_ATTACHMENT_STORE_OP_DONT_CARE; - attachmentDescriptions[attachmentDescriptionsCount].initialLayout = - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - attachmentDescriptions[attachmentDescriptionsCount].finalLayout = - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - - attachmentDescriptionsCount += 1; - - colorAttachmentReferences[colorAttachmentReferenceCount].attachment = i; - colorAttachmentReferences[colorAttachmentReferenceCount].layout = - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - - colorAttachmentReferenceCount += 1; - } - } - - subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; - subpass.flags = 0; - subpass.inputAttachmentCount = 0; - subpass.pInputAttachments = NULL; - subpass.colorAttachmentCount = renderer->colorAttachmentCount; - subpass.pColorAttachments = colorAttachmentReferences; - subpass.preserveAttachmentCount = 0; - subpass.pPreserveAttachments = NULL; - - if (renderer->depthStencilAttachment == NULL) - { - subpass.pDepthStencilAttachment = NULL; - } - else - { - attachmentDescriptions[attachmentDescriptionsCount].flags = 0; - attachmentDescriptions[attachmentDescriptionsCount].format = - renderer->depthStencilAttachment->surfaceFormat; - attachmentDescriptions[attachmentDescriptionsCount].samples = - XNAToVK_SampleCount(renderer->multiSampleCount); - attachmentDescriptions[attachmentDescriptionsCount].loadOp = - hash.clearDepth ? - VK_ATTACHMENT_LOAD_OP_CLEAR : - VK_ATTACHMENT_LOAD_OP_LOAD; - attachmentDescriptions[attachmentDescriptionsCount].storeOp = - VK_ATTACHMENT_STORE_OP_STORE; - /* - * Once above FIXME is resolved: - * hash.preserveTargetContents ? - * VK_ATTACHMENT_STORE_OP_STORE : - * VK_ATTACHMENT_STORE_OP_DONT_CARE; - */ - attachmentDescriptions[attachmentDescriptionsCount].stencilLoadOp = - hash.clearStencil ? - VK_ATTACHMENT_LOAD_OP_CLEAR : - VK_ATTACHMENT_LOAD_OP_LOAD; - attachmentDescriptions[attachmentDescriptionsCount].stencilStoreOp = - VK_ATTACHMENT_STORE_OP_STORE; - /* - * Once above FIXME is resolved: - * hash.preserveTargetContents ? - * VK_ATTACHMENT_STORE_OP_STORE : - * VK_ATTACHMENT_STORE_OP_DONT_CARE; - */ - attachmentDescriptions[attachmentDescriptionsCount].initialLayout = - VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - attachmentDescriptions[attachmentDescriptionsCount].finalLayout = - VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - - depthStencilAttachmentReference.attachment = - attachmentDescriptionsCount; - depthStencilAttachmentReference.layout = - VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - - subpass.pDepthStencilAttachment = - &depthStencilAttachmentReference; - - attachmentDescriptionsCount += 1; - } - - if (renderer->multiSampleCount > 0) - { - subpass.pResolveAttachments = resolveReferences; - } - else - { - subpass.pResolveAttachments = NULL; - } - - renderPassCreateInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; - renderPassCreateInfo.pNext = NULL; - renderPassCreateInfo.flags = 0; - renderPassCreateInfo.attachmentCount = attachmentDescriptionsCount; - renderPassCreateInfo.pAttachments = attachmentDescriptions; - renderPassCreateInfo.subpassCount = 1; - renderPassCreateInfo.pSubpasses = &subpass; - renderPassCreateInfo.dependencyCount = 0; - renderPassCreateInfo.pDependencies = NULL; - - vulkanResult = renderer->vkCreateRenderPass( - renderer->logicalDevice, - &renderPassCreateInfo, - NULL, - &renderPass - ); - VULKAN_ERROR_CHECK(vulkanResult, vkCreateRenderPass, VK_NULL_HANDLE) - - RenderPassHashArray_Insert( - &renderer->renderPassArray, - hash, - renderPass - ); - return renderPass; -} - -static VkFramebuffer VULKAN_INTERNAL_FetchFramebuffer( - VulkanRenderer *renderer, - VkRenderPass renderPass -) { - VkFramebuffer framebuffer; - VkImageView imageViewAttachments[2 * MAX_RENDERTARGET_BINDINGS + 1]; - uint32_t i, attachmentCount; - VkFramebufferCreateInfo framebufferInfo; - VkResult vulkanResult; - - FramebufferHash hash; - for (i = 0; i < MAX_RENDERTARGET_BINDINGS; i += 1) - { - hash.colorAttachmentViews[i] = ( - renderer->colorAttachments[i] != NULL ? - renderer->colorAttachments[i]->rtViews[ - renderer->attachmentCubeFaces[i] - ] : - VK_NULL_HANDLE - ); - hash.colorMultiSampleAttachmentViews[i] = ( - renderer->colorMultiSampleAttachments[i] != NULL ? - renderer->colorMultiSampleAttachments[i]->rtViews[ - renderer->attachmentCubeFaces[i] - ] : - VK_NULL_HANDLE - ); - } - hash.depthStencilAttachmentView = ( - renderer->depthStencilAttachment != NULL ? - renderer->depthStencilAttachment->rtViews[0] : - VK_NULL_HANDLE - ); - hash.width = renderer->colorAttachments[0]->dimensions.width; - hash.height = renderer->colorAttachments[0]->dimensions.height; - - /* Framebuffer is cached, can return it */ - framebuffer = FramebufferHashArray_Fetch( - &renderer->framebufferArray, - hash - ); - if (framebuffer != VK_NULL_HANDLE) - { - return framebuffer; - } - - /* Otherwise make a new one */ - - attachmentCount = 0; - - for (i = 0; i < renderer->colorAttachmentCount; i += 1) - { - imageViewAttachments[attachmentCount] = - renderer->colorAttachments[i]->rtViews[ - renderer->attachmentCubeFaces[i] - ]; - attachmentCount += 1; - - if (renderer->multiSampleCount > 0) - { - imageViewAttachments[attachmentCount] = - renderer->colorMultiSampleAttachments[i]->rtViews[ - renderer->attachmentCubeFaces[i] - ]; - attachmentCount += 1; - } - } - if (renderer->depthStencilAttachment != NULL) - { - imageViewAttachments[attachmentCount] = - renderer->depthStencilAttachment->rtViews[0]; - attachmentCount += 1; - } - - framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; - framebufferInfo.pNext = NULL; - framebufferInfo.flags = 0; - framebufferInfo.renderPass = renderPass; - framebufferInfo.attachmentCount = attachmentCount; - framebufferInfo.pAttachments = imageViewAttachments; - framebufferInfo.width = renderer->colorAttachments[0]->dimensions.width; - framebufferInfo.height = renderer->colorAttachments[0]->dimensions.height; - framebufferInfo.layers = 1; - - vulkanResult = renderer->vkCreateFramebuffer( - renderer->logicalDevice, - &framebufferInfo, - NULL, - &framebuffer - ); - VULKAN_ERROR_CHECK(vulkanResult, vkCreateFramebuffer, VK_NULL_HANDLE) - - FramebufferHashArray_Insert( - &renderer->framebufferArray, - hash, - framebuffer - ); - return framebuffer; -} - -static void VULKAN_INTERNAL_MaybeEndRenderPass( - VulkanRenderer *renderer -) { - int32_t i; - VulkanTexture *currentTexture; - VulkanCommandBuffer *commandBuffer; - - SDL_LockMutex(renderer->passLock); - - if (renderer->renderPassInProgress) - { - commandBuffer = (VulkanCommandBuffer*) FNA3D_CommandBuffer_GetCurrent( - renderer->commandBuffers - ); - RECORD_CMD(renderer->vkCmdEndRenderPass(commandBuffer->commandBuffer)); - - renderer->renderPassInProgress = 0; - renderer->needNewRenderPass = 1; - renderer->drawCallMadeThisPass = 0; - renderer->currentPipeline = VK_NULL_HANDLE; - renderer->needNewPipeline = 1; - - for (i = 0; i < renderer->colorAttachmentCount; i += 1) - { - currentTexture = renderer->colorAttachments[i]; - - /* If the render target can be sampled, transition to sampler layout */ - if (currentTexture->imageCreateInfo.usage & VK_IMAGE_USAGE_SAMPLED_BIT) - { - VULKAN_INTERNAL_ImageMemoryBarrier( - renderer, - RESOURCE_ACCESS_ANY_SHADER_READ_SAMPLED_IMAGE, - VK_IMAGE_ASPECT_COLOR_BIT, - 0, - currentTexture->layerCount, - 0, - currentTexture->levelCount, - 0, - currentTexture->image, - ¤tTexture->resourceAccessType - ); - } - } - - /* Unlocking long-term lock */ - SDL_UnlockMutex(renderer->passLock); - } - - SDL_UnlockMutex(renderer->passLock); -} - -static void VULKAN_INTERNAL_BeginRenderPass( - VulkanRenderer *renderer -) { - VulkanCommandBuffer *commandBuffer; - VkRenderPassBeginInfo renderPassBeginInfo; - VkFramebuffer framebuffer; - VkImageAspectFlags depthAspectFlags; - float blendConstants[4]; - VkClearValue clearValues[2 * MAX_RENDERTARGET_BINDINGS + 1]; - VkClearColorValue clearColorValue; - uint32_t clearValueCount = 0; - uint32_t i; - - if (!renderer->needNewRenderPass) - { - return; - } - - VULKAN_INTERNAL_MaybeEndRenderPass(renderer); - - SDL_LockMutex(renderer->passLock); - - for (i = 0; i < renderer->nextRenderPassColorAttachmentCount; i += 1) - { - renderer->colorAttachments[i] = renderer->nextRenderPassColorAttachments[i]; - renderer->attachmentCubeFaces[i] = renderer->nextRenderPassAttachmentCubeFaces[i]; - renderer->colorMultiSampleAttachments[i] = renderer->nextRenderPassColorMultiSampleAttachments[i]; /* may be NULL */ - } - for (; i < MAX_RENDERTARGET_BINDINGS; i += 1) - { - renderer->colorAttachments[i] = NULL; - renderer->attachmentCubeFaces[i] = 0; - renderer->colorMultiSampleAttachments[i] = NULL; - } - - renderer->colorAttachmentCount = renderer->nextRenderPassColorAttachmentCount; - renderer->multiSampleCount = renderer->nextRenderPassMultiSampleCount; - - renderer->depthStencilAttachment = renderer->nextRenderPassDepthStencilAttachment; - renderer->currentDepthFormat = renderer->nextRenderPassDepthFormat; - - renderer->renderTargetBound = (renderer->nextRenderPassColorAttachments[0] != renderer->fauxBackbufferColor.handle); - - renderer->renderPass = VULKAN_INTERNAL_FetchRenderPass(renderer); - framebuffer = VULKAN_INTERNAL_FetchFramebuffer( - renderer, - renderer->renderPass - ); - - renderer->needNewPipeline = 1; - - renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; - renderPassBeginInfo.pNext = NULL; - renderPassBeginInfo.renderPass = renderer->renderPass; - renderPassBeginInfo.framebuffer = framebuffer; - renderPassBeginInfo.renderArea.offset.x = 0; - renderPassBeginInfo.renderArea.offset.y = 0; - renderPassBeginInfo.renderArea.extent.width = - renderer->colorAttachments[0]->dimensions.width; - renderPassBeginInfo.renderArea.extent.height = - renderer->colorAttachments[0]->dimensions.height; - - for (i = 0; i < renderer->colorAttachmentCount; i += 1) - { - VULKAN_INTERNAL_ImageMemoryBarrier( - renderer, - RESOURCE_ACCESS_COLOR_ATTACHMENT_READ_WRITE, - VK_IMAGE_ASPECT_COLOR_BIT, - 0, - renderer->colorAttachments[i]->layerCount, - 0, - renderer->colorAttachments[i]->levelCount, - 0, - renderer->colorAttachments[i]->image, - &renderer->colorAttachments[i]->resourceAccessType - ); - - /* - * In MRT scenarios we need to provide as many clearValue structs - * as RTs in the current framebuffer even if they aren't cleared - */ - - if (renderer->shouldClearColorOnBeginPass) - { - clearColorValue = renderer->clearColorValue; - } - else - { - clearColorValue.float32[0] = 0; - clearColorValue.float32[1] = 0; - clearColorValue.float32[2] = 0; - clearColorValue.float32[3] = 0; - } - - clearValues[clearValueCount].color.float32[0] = clearColorValue.float32[0]; - clearValues[clearValueCount].color.float32[1] = clearColorValue.float32[1]; - clearValues[clearValueCount].color.float32[2] = clearColorValue.float32[2]; - clearValues[clearValueCount].color.float32[3] = clearColorValue.float32[3]; - clearValueCount += 1; - - if (renderer->colorMultiSampleAttachments[i] != NULL) - { - clearValues[clearValueCount].color.float32[0] = clearColorValue.float32[0]; - clearValues[clearValueCount].color.float32[1] = clearColorValue.float32[1]; - clearValues[clearValueCount].color.float32[2] = clearColorValue.float32[2]; - clearValues[clearValueCount].color.float32[3] = clearColorValue.float32[3]; - clearValueCount += 1; - } - } - - if (renderer->depthStencilAttachment != NULL) - { - depthAspectFlags = VK_IMAGE_ASPECT_DEPTH_BIT; - if (DepthFormatContainsStencil( - renderer->depthStencilAttachment->surfaceFormat - )) { - depthAspectFlags |= VK_IMAGE_ASPECT_STENCIL_BIT; - } - - VULKAN_INTERNAL_ImageMemoryBarrier( - renderer, - RESOURCE_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_WRITE, - depthAspectFlags, - 0, - renderer->depthStencilAttachment->layerCount, - 0, - renderer->depthStencilAttachment->levelCount, - 0, - renderer->depthStencilAttachment->image, - &renderer->depthStencilAttachment->resourceAccessType - ); - - if (renderer->shouldClearDepthOnBeginPass || renderer->shouldClearStencilOnBeginPass) - { - clearValues[clearValueCount].depthStencil.depth = renderer->clearDepthStencilValue.depth; - clearValues[clearValueCount].depthStencil.stencil = renderer->clearDepthStencilValue.stencil; - clearValueCount += 1; - } - } - - renderPassBeginInfo.clearValueCount = clearValueCount; - renderPassBeginInfo.pClearValues = clearValues; - - commandBuffer = (VulkanCommandBuffer*) FNA3D_CommandBuffer_GetCurrent( - renderer->commandBuffers - ); - RECORD_CMD(renderer->vkCmdBeginRenderPass( - commandBuffer->commandBuffer, - &renderPassBeginInfo, - VK_SUBPASS_CONTENTS_INLINE - )); - - renderer->renderPassInProgress = 1; - - VULKAN_INTERNAL_SetViewportCommand(renderer); - VULKAN_INTERNAL_SetScissorRectCommand(renderer); - VULKAN_INTERNAL_SetStencilReferenceValueCommand(renderer); - VULKAN_INTERNAL_SetDepthBiasCommand(renderer); - - blendConstants[0] = renderer->blendState.blendFactor.r / 255.0f; - blendConstants[1] = renderer->blendState.blendFactor.g / 255.0f; - blendConstants[2] = renderer->blendState.blendFactor.b / 255.0f; - blendConstants[3] = renderer->blendState.blendFactor.a / 255.0f; - - RECORD_CMD(renderer->vkCmdSetBlendConstants( - commandBuffer->commandBuffer, - blendConstants - )); - - /* Reset bindings for the current frame in flight */ - - for (i = 0; i < MAX_TOTAL_SAMPLERS; i += 1) - { - if (renderer->textures[i] != &NullTexture) - { - renderer->textureNeedsUpdate[i] = 1; - } - if (renderer->samplers[i] != VK_NULL_HANDLE) - { - renderer->samplerNeedsUpdate[i] = 1; - } - } - - renderer->currentPipeline = VK_NULL_HANDLE; - renderer->needNewPipeline = 1; - - renderer->needNewRenderPass = 0; - renderer->shouldClearColorOnBeginPass = 0; - renderer->shouldClearDepthOnBeginPass = 0; - renderer->shouldClearStencilOnBeginPass = 0; -} - -static void VULKAN_INTERNAL_BeginRenderPassClear( - VulkanRenderer *renderer, - FNA3D_Vec4 *color, - float depth, - int32_t stencil, - uint8_t clearColor, - uint8_t clearDepth, - uint8_t clearStencil -) { - if (!clearColor && !clearDepth && !clearStencil) - { - return; - } - - renderer->shouldClearColorOnBeginPass |= clearColor; - renderer->shouldClearDepthOnBeginPass |= clearDepth; - renderer->shouldClearStencilOnBeginPass |= clearStencil; - - if (clearColor) - { - renderer->clearColorValue.float32[0] = color->x; - renderer->clearColorValue.float32[1] = color->y; - renderer->clearColorValue.float32[2] = color->z; - renderer->clearColorValue.float32[3] = color->w; - } - - if (clearDepth) - { - if (depth < 0.0f) - { - depth = 0.0f; - } - else if (depth > 1.0f) - { - depth = 1.0f; - } - - renderer->clearDepthStencilValue.depth = depth; - } - - if (clearStencil) - { - renderer->clearDepthStencilValue.stencil = stencil; - } - - renderer->needNewRenderPass = 1; -} - -static void VULKAN_INTERNAL_MidRenderPassClear( - VulkanRenderer *renderer, - FNA3D_Vec4 *color, - float depth, - int32_t stencil, - uint8_t clearColor, - uint8_t clearDepth, - uint8_t clearStencil -) { - VulkanCommandBuffer *commandBuffer; - VkClearAttachment clearAttachments[2 * MAX_RENDERTARGET_BINDINGS + 1]; - VkClearRect clearRect; - VkClearValue clearValue = - {{{ - color->x, - color->y, - color->z, - color->w - }}}; - uint8_t shouldClearDepthStencil = ( - (clearDepth || clearStencil) && - renderer->depthStencilAttachment != NULL - ); - uint32_t i, attachmentCount; - - if (!clearColor && !shouldClearDepthStencil) - { - return; - } - - attachmentCount = 0; - - clearRect.baseArrayLayer = 0; - clearRect.layerCount = 1; - clearRect.rect.offset.x = 0; - clearRect.rect.offset.y = 0; - clearRect.rect.extent.width = renderer->colorAttachments[0]->dimensions.width; - clearRect.rect.extent.height = renderer->colorAttachments[0]->dimensions.height; - - if (clearColor) - { - for (i = 0; i < renderer->colorAttachmentCount; i += 1) - { - clearAttachments[attachmentCount].aspectMask = - VK_IMAGE_ASPECT_COLOR_BIT; - clearAttachments[attachmentCount].colorAttachment = - attachmentCount; - clearAttachments[attachmentCount].clearValue = - clearValue; - attachmentCount += 1; - - /* Do NOT clear the multisample image here! - * Vulkan treats them both as the same color attachment. - * Vulkan is a very good and not confusing at all API. - */ - } - } - - if (shouldClearDepthStencil) - { - clearAttachments[attachmentCount].aspectMask = 0; - clearAttachments[attachmentCount].colorAttachment = 0; - if (clearDepth) - { - if (depth < 0.0f) - { - depth = 0.0f; - } - else if (depth > 1.0f) - { - depth = 1.0f; - } - clearAttachments[attachmentCount].aspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT; - clearAttachments[attachmentCount].clearValue.depthStencil.depth = depth; - } - else - { - clearAttachments[attachmentCount].clearValue.depthStencil.depth = 0.0f; - } - if (clearStencil) - { - clearAttachments[attachmentCount].aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT; - clearAttachments[attachmentCount].clearValue.depthStencil.stencil = stencil; - } - else - { - clearAttachments[attachmentCount].clearValue.depthStencil.stencil = 0; - } - - attachmentCount += 1; - } - - commandBuffer = (VulkanCommandBuffer*) FNA3D_CommandBuffer_GetCurrent( - renderer->commandBuffers - ); - RECORD_CMD(renderer->vkCmdClearAttachments( - commandBuffer->commandBuffer, - attachmentCount, - clearAttachments, - 1, - &clearRect - )); -} - -/* Vulkan: Sampler State */ - -static VkSampler VULKAN_INTERNAL_FetchSamplerState( - VulkanRenderer *renderer, - FNA3D_SamplerState *samplerState, - uint32_t levelCount -) { - VkSamplerCreateInfo createInfo; - VkSampler state; - VkResult result; - - PackedState hash = GetPackedSamplerState(*samplerState); - state = SamplerStateHashArray_Fetch( - &renderer->samplerStateArray, - hash - ); - if (state != VK_NULL_HANDLE) - { - return state; - } - - createInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; - createInfo.pNext = NULL; - createInfo.flags = 0; - createInfo.magFilter = XNAToVK_MagFilter[samplerState->filter]; - createInfo.minFilter = XNAToVK_MinFilter[samplerState->filter]; - createInfo.mipmapMode = XNAToVK_MipFilter[samplerState->filter]; - createInfo.addressModeU = XNAToVK_SamplerAddressMode[ - samplerState->addressU - ]; - createInfo.addressModeV = XNAToVK_SamplerAddressMode[ - samplerState->addressV - ]; - createInfo.addressModeW = XNAToVK_SamplerAddressMode[ - samplerState->addressW - ]; - createInfo.mipLodBias = samplerState->mipMapLevelOfDetailBias; - createInfo.anisotropyEnable = (samplerState->filter == FNA3D_TEXTUREFILTER_ANISOTROPIC); - createInfo.maxAnisotropy = SDL_min( - (float) SDL_max(1, samplerState->maxAnisotropy), - renderer->physicalDeviceProperties.properties.limits.maxSamplerAnisotropy - ); - createInfo.compareEnable = 0; - createInfo.compareOp = 0; - createInfo.minLod = (float) samplerState->maxMipLevel; - createInfo.maxLod = VK_LOD_CLAMP_NONE; - createInfo.borderColor = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK; - createInfo.unnormalizedCoordinates = 0; - - result = renderer->vkCreateSampler( - renderer->logicalDevice, - &createInfo, - NULL, - &state - ); - VULKAN_ERROR_CHECK(result, vkCreateSampler, 0) - - SamplerStateHashArray_Insert( - &renderer->samplerStateArray, - hash, - state - ); - - return state; -} - -/* Renderer Implementation */ - -/* Quit */ - -static void VULKAN_DestroyDevice(FNA3D_Device *device) -{ - VulkanRenderer *renderer = (VulkanRenderer*) device->driverData; - ShaderResources *shaderResources; - PipelineHashArray hashArray; - int32_t i, j; - VkResult pipelineCacheResult; - size_t pipelineCacheSize; - uint8_t *pipelineCacheData; - SDL_IOStream *pipelineCacheFile; - const char *pipelineCacheFileName; - - VULKAN_INTERNAL_FlushCommands(renderer, 1); - - FNA3D_CommandBuffer_Finish(renderer->commandBuffers); - - /* Save the pipeline cache to disk */ - - pipelineCacheResult = renderer->vkGetPipelineCacheData( - renderer->logicalDevice, - renderer->pipelineCache, - &pipelineCacheSize, - NULL - ); - - if (pipelineCacheResult == VK_SUCCESS) - { - pipelineCacheFileName = SDL_GetHint("FNA3D_VULKAN_PIPELINE_CACHE_FILE_NAME"); - if (pipelineCacheFileName == NULL) - { - pipelineCacheFileName = DEFAULT_PIPELINE_CACHE_FILE_NAME; - } - if (pipelineCacheFileName[0] == '\0') - { - /* For intentionally empty file names, assume caching is disabled */ - pipelineCacheFile = NULL; - } - else - { - pipelineCacheFile = SDL_IOFromFile(pipelineCacheFileName, "wb"); - } - - if (pipelineCacheFile != NULL) - { - pipelineCacheData = SDL_malloc(pipelineCacheSize); - - renderer->vkGetPipelineCacheData( - renderer->logicalDevice, - renderer->pipelineCache, - &pipelineCacheSize, - pipelineCacheData - ); - - SDL_WriteIO( - pipelineCacheFile, - pipelineCacheData, - pipelineCacheSize - ); - SDL_CloseIO(pipelineCacheFile); - - SDL_free(pipelineCacheData); - } - else - { - FNA3D_LogWarn("Could not open pipeline cache file for writing!"); - } - } - else - { - FNA3D_LogWarn("vkGetPipelineCacheData: %s", VkErrorMessages(pipelineCacheResult)); - FNA3D_LogWarn("Error getting data from pipeline cache, aborting save!"); - } - - /* Clean up! */ - - VULKAN_INTERNAL_DestroyBuffer(renderer, renderer->dummyVertUniformBuffer); - VULKAN_INTERNAL_DestroyBuffer(renderer, renderer->dummyFragUniformBuffer); - - VULKAN_INTERNAL_DestroyTexture(renderer, renderer->dummyVertTexture); - VULKAN_INTERNAL_DestroyTexture(renderer, renderer->dummyVertTexture3D); - VULKAN_INTERNAL_DestroyTexture(renderer, renderer->dummyVertTextureCube); - - VULKAN_INTERNAL_DestroyTexture(renderer, renderer->dummyFragTexture); - VULKAN_INTERNAL_DestroyTexture(renderer, renderer->dummyFragTexture3D); - VULKAN_INTERNAL_DestroyTexture(renderer, renderer->dummyFragTextureCube); - - MOJOSHADER_vkDestroyContext(renderer->mojoshaderContext); - VULKAN_INTERNAL_DestroyFauxBackbuffer(renderer); - - renderer->vkDestroySemaphore( - renderer->logicalDevice, - renderer->defragSemaphore, - NULL - ); - - renderer->vkDestroyQueryPool( - renderer->logicalDevice, - renderer->queryPool, - NULL - ); - - FNA3D_DestroyCommandBufferManager(renderer->commandBuffers); - renderer->vkDestroyCommandPool( - renderer->logicalDevice, - renderer->commandPool, - NULL - ); - - for (i = 0; i < NUM_PIPELINE_HASH_BUCKETS; i += 1) - { - hashArray = renderer->pipelineHashTable.buckets[i]; - for (j = 0; j < hashArray.count; j += 1) - { - renderer->vkDestroyPipeline( - renderer->logicalDevice, - renderer->pipelineHashTable.buckets[i].elements[j].value, - NULL - ); - } - if (hashArray.elements != NULL) - { - SDL_free(hashArray.elements); - } - } - - for (i = 0; i < NUM_SHADER_RESOURCES_BUCKETS; i += 1) - { - for (j = 0; j < renderer->shaderResourcesHashTable.buckets[i].count; j += 1) - { - shaderResources = renderer->shaderResourcesHashTable.buckets[i].elements[j].value; - ShaderResources_Destroy(renderer, shaderResources); - } - - SDL_free(renderer->shaderResourcesHashTable.buckets[i].elements); - } - - renderer->vkDestroyDescriptorPool( - renderer->logicalDevice, - renderer->uniformBufferDescriptorPool, - NULL - ); - - for (i = 0; i < NUM_DESCRIPTOR_SET_LAYOUT_BUCKETS; i += 1) - { - for (j = 0; j < renderer->descriptorSetLayoutTable.buckets[i].count; j += 1) - { - renderer->vkDestroyDescriptorSetLayout( - renderer->logicalDevice, - renderer->descriptorSetLayoutTable.buckets[i].elements[j].value, - NULL - ); - } - - SDL_free(renderer->descriptorSetLayoutTable.buckets[i].elements); - } - - renderer->vkDestroyDescriptorSetLayout( - renderer->logicalDevice, - renderer->vertexUniformBufferDescriptorSetLayout, - NULL - ); - - renderer->vkDestroyDescriptorSetLayout( - renderer->logicalDevice, - renderer->fragUniformBufferDescriptorSetLayout, - NULL - ); - - for (i = 0; i < NUM_PIPELINE_LAYOUT_BUCKETS; i += 1) - { - for (j = 0; j < renderer->pipelineLayoutTable.buckets[i].count; j += 1) - { - renderer->vkDestroyPipelineLayout( - renderer->logicalDevice, - renderer->pipelineLayoutTable.buckets[i].elements[j].value, - NULL - ); - } - - SDL_free(renderer->pipelineLayoutTable.buckets[i].elements); - } - - renderer->vkDestroyPipelineCache( - renderer->logicalDevice, - renderer->pipelineCache, - NULL - ); - - for (i = 0; i < renderer->renderPassArray.count; i += 1) - { - renderer->vkDestroyRenderPass( - renderer->logicalDevice, - renderer->renderPassArray.elements[i].value, - NULL - ); - } - - for (i = 0; i < renderer->samplerStateArray.count; i += 1) - { - renderer->vkDestroySampler( - renderer->logicalDevice, - renderer->samplerStateArray.elements[i].value, - NULL - ); - } - - renderer->vkDestroySampler( - renderer->logicalDevice, - renderer->dummyVertSamplerState, - NULL - ); - renderer->vkDestroySampler( - renderer->logicalDevice, - renderer->dummyVertSampler3DState, - NULL - ); - renderer->vkDestroySampler( - renderer->logicalDevice, - renderer->dummyVertSamplerCubeState, - NULL - ); - - renderer->vkDestroySampler( - renderer->logicalDevice, - renderer->dummyFragSamplerState, - NULL - ); - renderer->vkDestroySampler( - renderer->logicalDevice, - renderer->dummyFragSampler3DState, - NULL - ); - renderer->vkDestroySampler( - renderer->logicalDevice, - renderer->dummyFragSamplerCubeState, - NULL - ); - - for (j = renderer->swapchainDataCount - 1; j >= 0; j -= 1) - { - VULKAN_INTERNAL_DestroySwapchain(renderer, renderer->swapchainDatas[j]->windowHandle); - } - SDL_free(renderer->swapchainDatas); - - FNA3D_DestroyMemoryAllocator(renderer->allocator); - - SDL_DestroyMutex(renderer->passLock); - SDL_DestroyMutex(renderer->disposeLock); - - renderer->vkDestroyDevice(renderer->logicalDevice, NULL); - renderer->vkDestroyInstance(renderer->instance, NULL); - - SDL_free(renderer->defragmentedBuffersToDestroy); - SDL_free(renderer->defragmentedImagesToDestroy); - SDL_free(renderer->defragmentedImageViewsToDestroy); - - SDL_free(renderer->renderPassArray.elements); - SDL_free(renderer->samplerStateArray.elements); - SDL_free(renderer->vertexBufferBindingsCache.elements); - - SDL_free(renderer); - SDL_free(device); -} - -/* Presentation */ - -static void VULKAN_SwapBuffers( - FNA3D_Renderer *driverData, - FNA3D_Rect *sourceRectangle, - FNA3D_Rect *destinationRectangle, - void* overrideWindowHandle -) { - VulkanRenderer *renderer = (VulkanRenderer*) driverData; - - /* Perform any pending clears before presenting */ - if ( renderer->shouldClearColorOnBeginPass || - renderer->shouldClearDepthOnBeginPass || - renderer->shouldClearStencilOnBeginPass ) - { - VULKAN_INTERNAL_BeginRenderPass(renderer); - } - - VULKAN_INTERNAL_FlushCommandsAndPresent( - renderer, - sourceRectangle, - destinationRectangle, - overrideWindowHandle - ); - - renderer->needNewRenderPass = 1; -} - -/* Drawing */ - -static void VULKAN_Clear( - FNA3D_Renderer *driverData, - FNA3D_ClearOptions options, - FNA3D_Vec4 *color, - float depth, - int32_t stencil -) { - VulkanRenderer *renderer = (VulkanRenderer*) driverData; - uint8_t clearColor = (options & FNA3D_CLEAROPTIONS_TARGET) == FNA3D_CLEAROPTIONS_TARGET; - uint8_t clearDepth = (options & FNA3D_CLEAROPTIONS_DEPTHBUFFER) == FNA3D_CLEAROPTIONS_DEPTHBUFFER; - uint8_t clearStencil = (options & FNA3D_CLEAROPTIONS_STENCIL) == FNA3D_CLEAROPTIONS_STENCIL; - - if (renderer->renderPassInProgress && renderer->drawCallMadeThisPass && !renderer->needNewRenderPass) - { - VULKAN_INTERNAL_MidRenderPassClear( - renderer, - color, - depth, - stencil, - clearColor, - clearDepth, - clearStencil - ); - } - else - { - VULKAN_INTERNAL_BeginRenderPassClear( - renderer, - color, - depth, - stencil, - clearColor, - clearDepth, - clearStencil - ); - } -} - -static void VULKAN_DrawInstancedPrimitives( - FNA3D_Renderer *driverData, - FNA3D_PrimitiveType primitiveType, - int32_t baseVertex, - int32_t minVertexIndex, - int32_t numVertices, - int32_t startIndex, - int32_t primitiveCount, - int32_t instanceCount, - FNA3D_Buffer *indices, - FNA3D_IndexElementSize indexElementSize -) { - VulkanRenderer *renderer = (VulkanRenderer*) driverData; - VulkanCommandBuffer *commandBuffer; - VulkanBuffer *indexBuffer; - VkDescriptorSet descriptorSets[4]; - MOJOSHADER_vkShader *vertShader, *fragShader; - ShaderResources *vertShaderResources, *fragShaderResources; - uint32_t dynamicOffsets[2]; - - /* Note that minVertexIndex/numVertices are NOT used! */ - - indexBuffer = (VulkanBuffer*) FNA3D_Memory_GetActiveBuffer( - (FNA3D_BufferContainer*) indices - ); - - FNA3D_CommandBuffer_MarkBufferAsBound( - renderer->commandBuffers, - (FNA3D_BufferHandle*) indexBuffer - ); - - if (primitiveType != renderer->currentPrimitiveType) - { - renderer->currentPrimitiveType = primitiveType; - renderer->needNewPipeline = 1; - } - - VULKAN_INTERNAL_BeginRenderPass(renderer); - VULKAN_INTERNAL_BindPipeline(renderer); - - commandBuffer = (VulkanCommandBuffer*) FNA3D_CommandBuffer_GetCurrent( - renderer->commandBuffers - ); - - if (renderer->numVertexBindings > 0) - { - /* FIXME: State shadowing for vertex buffers? -flibit */ - RECORD_CMD(renderer->vkCmdBindVertexBuffers( - commandBuffer->commandBuffer, - 0, - renderer->numVertexBindings, - renderer->boundVertexBuffers, - renderer->boundVertexBufferOffsets - )); - } - /* FIXME: State shadowing for index buffers? -flibit */ - RECORD_CMD(renderer->vkCmdBindIndexBuffer( - commandBuffer->commandBuffer, - indexBuffer->buffer, - 0, - XNAToVK_IndexType[indexElementSize] - )); - - MOJOSHADER_vkGetBoundShaders(renderer->mojoshaderContext, &vertShader, &fragShader); - vertShaderResources = VULKAN_INTERNAL_FetchShaderResources( - renderer, - vertShader, - VK_SHADER_STAGE_VERTEX_BIT - ); - fragShaderResources = VULKAN_INTERNAL_FetchShaderResources( - renderer, - fragShader, - VK_SHADER_STAGE_FRAGMENT_BIT - ); - - if ( renderer->vertexSamplerDescriptorSetDataNeedsUpdate || - renderer->fragSamplerDescriptorSetDataNeedsUpdate ) - { - VULKAN_INTERNAL_FetchDescriptorSetDataAndOffsets( - renderer, - vertShaderResources, - fragShaderResources, - descriptorSets, - dynamicOffsets - ); - - RECORD_CMD(renderer->vkCmdBindDescriptorSets( - commandBuffer->commandBuffer, - VK_PIPELINE_BIND_POINT_GRAPHICS, - renderer->currentPipelineLayout, - 0, - 4, - descriptorSets, - 2, - dynamicOffsets - )); - } - - - RECORD_CMD(renderer->vkCmdDrawIndexed( - commandBuffer->commandBuffer, - PrimitiveVerts(primitiveType, primitiveCount), - instanceCount, - startIndex, - renderer->supportsBaseVertex ? baseVertex : 0, - 0 - )); - - renderer->drawCallMadeThisPass = 1; -} - -static void VULKAN_DrawIndexedPrimitives( - FNA3D_Renderer *driverData, - FNA3D_PrimitiveType primitiveType, - int32_t baseVertex, - int32_t minVertexIndex, - int32_t numVertices, - int32_t startIndex, - int32_t primitiveCount, - FNA3D_Buffer *indices, - FNA3D_IndexElementSize indexElementSize -) { - VULKAN_DrawInstancedPrimitives( - driverData, - primitiveType, - baseVertex, - minVertexIndex, - numVertices, - startIndex, - primitiveCount, - 1, - indices, - indexElementSize - ); -} - -static void VULKAN_DrawPrimitives( - FNA3D_Renderer *driverData, - FNA3D_PrimitiveType primitiveType, - int32_t vertexStart, - int32_t primitiveCount -) { - VulkanRenderer *renderer = (VulkanRenderer*) driverData; - VulkanCommandBuffer *commandBuffer; - VkDescriptorSet descriptorSets[4]; - MOJOSHADER_vkShader *vertShader, *fragShader; - ShaderResources *vertShaderResources, *fragShaderResources; - uint32_t dynamicOffsets[2]; - - if (primitiveType != renderer->currentPrimitiveType) - { - renderer->currentPrimitiveType = primitiveType; - renderer->needNewPipeline = 1; - } - VULKAN_INTERNAL_BeginRenderPass(renderer); - VULKAN_INTERNAL_BindPipeline(renderer); - - commandBuffer = (VulkanCommandBuffer*) FNA3D_CommandBuffer_GetCurrent( - renderer->commandBuffers - ); - - if (renderer->numVertexBindings > 0) - { - /* FIXME: State shadowing for vertex buffers? -flibit */ - RECORD_CMD(renderer->vkCmdBindVertexBuffers( - commandBuffer->commandBuffer, - 0, - renderer->numVertexBindings, - renderer->boundVertexBuffers, - renderer->boundVertexBufferOffsets - )); - } - - MOJOSHADER_vkGetBoundShaders(renderer->mojoshaderContext, &vertShader, &fragShader); - vertShaderResources = VULKAN_INTERNAL_FetchShaderResources( - renderer, - vertShader, - VK_SHADER_STAGE_VERTEX_BIT - ); - fragShaderResources = VULKAN_INTERNAL_FetchShaderResources( - renderer, - fragShader, - VK_SHADER_STAGE_FRAGMENT_BIT - ); - - if ( renderer->vertexSamplerDescriptorSetDataNeedsUpdate || - renderer->fragSamplerDescriptorSetDataNeedsUpdate ) - { - VULKAN_INTERNAL_FetchDescriptorSetDataAndOffsets( - renderer, - vertShaderResources, - fragShaderResources, - descriptorSets, - dynamicOffsets - ); - - RECORD_CMD(renderer->vkCmdBindDescriptorSets( - commandBuffer->commandBuffer, - VK_PIPELINE_BIND_POINT_GRAPHICS, - renderer->currentPipelineLayout, - 0, - 4, - descriptorSets, - 2, - dynamicOffsets - )); - } - - RECORD_CMD(renderer->vkCmdDraw( - commandBuffer->commandBuffer, - PrimitiveVerts(primitiveType, primitiveCount), - 1, - vertexStart, - 0 - )); - - renderer->drawCallMadeThisPass = 1; -} - -/* Mutable Render States */ - -static void VULKAN_SetViewport( - FNA3D_Renderer *driverData, - FNA3D_Viewport *viewport -) { - VulkanRenderer *renderer = (VulkanRenderer*) driverData; - - if ( viewport->x != renderer->viewport.x || - viewport->y != renderer->viewport.y || - viewport->w != renderer->viewport.w || - viewport->h != renderer->viewport.h || - viewport->minDepth != renderer->viewport.minDepth || - viewport->maxDepth != renderer->viewport.maxDepth ) - { - renderer->viewport = *viewport; - VULKAN_INTERNAL_SetViewportCommand(renderer); - } -} - -static void VULKAN_SetScissorRect( - FNA3D_Renderer *driverData, - FNA3D_Rect *scissor -) { - VulkanRenderer *renderer = (VulkanRenderer*) driverData; - - if ( scissor->x != renderer->scissorRect.x || - scissor->y != renderer->scissorRect.y || - scissor->w != renderer->scissorRect.w || - scissor->h != renderer->scissorRect.h ) - { - renderer->scissorRect = *scissor; - VULKAN_INTERNAL_SetScissorRectCommand(renderer); - } -} - -static void VULKAN_GetBlendFactor( - FNA3D_Renderer *driverData, - FNA3D_Color *blendFactor -) { - VulkanRenderer *renderer = (VulkanRenderer*) driverData; - SDL_memcpy( - blendFactor, - &renderer->blendState.blendFactor, - sizeof(FNA3D_Color) - ); -} - -static void VULKAN_SetBlendFactor( - FNA3D_Renderer *driverData, - FNA3D_Color *blendFactor -) { - VulkanRenderer *renderer = (VulkanRenderer*) driverData; - VulkanCommandBuffer *commandBuffer; - const float blendConstants[] = - { - blendFactor->r, - blendFactor->g, - blendFactor->b, - blendFactor->a - }; - - if ( blendFactor->r != renderer->blendState.blendFactor.r || - blendFactor->g != renderer->blendState.blendFactor.g || - blendFactor->b != renderer->blendState.blendFactor.b || - blendFactor->a != renderer->blendState.blendFactor.a ) - { - renderer->blendState.blendFactor = *blendFactor; - renderer->needNewPipeline = 1; - - commandBuffer = (VulkanCommandBuffer*) FNA3D_CommandBuffer_GetCurrent( - renderer->commandBuffers - ); - RECORD_CMD(renderer->vkCmdSetBlendConstants( - commandBuffer->commandBuffer, - blendConstants - )); - } -} - -static int32_t VULKAN_GetMultiSampleMask(FNA3D_Renderer *driverData) -{ - VulkanRenderer *renderer = (VulkanRenderer*) driverData; - return renderer->multiSampleMask[0]; -} - -static void VULKAN_SetMultiSampleMask(FNA3D_Renderer *driverData, int32_t mask) -{ - VulkanRenderer *renderer = (VulkanRenderer*) driverData; - if (renderer->debugMode && renderer->multiSampleCount> 32) { - FNA3D_LogWarn( - "Using a 32-bit multisample mask for a 64-sample rasterizer." - " Last 32 bits of the mask will all be 1." - ); - } - if (renderer->multiSampleMask[0] != mask) - { - renderer->multiSampleMask[0] = mask; - renderer->needNewPipeline = 1; - } -} - -static int32_t VULKAN_GetReferenceStencil(FNA3D_Renderer *driverData) -{ - VulkanRenderer *renderer = (VulkanRenderer*) driverData; - return renderer->stencilRef; -} - -static void VULKAN_SetReferenceStencil(FNA3D_Renderer *driverData, int32_t ref) -{ - VulkanRenderer *renderer = (VulkanRenderer*) driverData; - if (renderer->stencilRef != ref) - { - renderer->stencilRef = ref; - VULKAN_INTERNAL_SetStencilReferenceValueCommand(renderer); - } -} - -/* Immutable Render States */ - -static void VULKAN_SetBlendState( - FNA3D_Renderer *driverData, - FNA3D_BlendState *blendState -) { - VulkanRenderer *renderer = (VulkanRenderer*) driverData; - - VULKAN_SetBlendFactor( - driverData, - &blendState->blendFactor - ); - - VULKAN_SetMultiSampleMask( - driverData, - blendState->multiSampleMask - ); - - if (SDL_memcmp(&renderer->blendState, blendState, sizeof(FNA3D_BlendState)) != 0) - { - SDL_memcpy(&renderer->blendState, blendState, sizeof(FNA3D_BlendState)); - renderer->needNewPipeline = 1; - } -} - -static void VULKAN_SetDepthStencilState( - FNA3D_Renderer *driverData, - FNA3D_DepthStencilState *depthStencilState -) { - VulkanRenderer *renderer = (VulkanRenderer*) driverData; - - /* TODO: Arrange these checks in an optimized priority */ - if ( renderer->depthStencilState.depthBufferEnable != depthStencilState->depthBufferEnable || - renderer->depthStencilState.depthBufferWriteEnable != depthStencilState->depthBufferWriteEnable || - renderer->depthStencilState.depthBufferFunction != depthStencilState->depthBufferFunction || - renderer->depthStencilState.stencilEnable != depthStencilState->stencilEnable || - renderer->depthStencilState.stencilMask != depthStencilState->stencilMask || - renderer->depthStencilState.stencilWriteMask != depthStencilState->stencilWriteMask || - renderer->depthStencilState.twoSidedStencilMode != depthStencilState->twoSidedStencilMode || - renderer->depthStencilState.stencilFail != depthStencilState->stencilFail || - renderer->depthStencilState.stencilDepthBufferFail != depthStencilState->stencilDepthBufferFail || - renderer->depthStencilState.stencilPass != depthStencilState->stencilPass || - renderer->depthStencilState.stencilFunction != depthStencilState->stencilFunction || - renderer->depthStencilState.ccwStencilFail != depthStencilState->ccwStencilFail || - renderer->depthStencilState.ccwStencilDepthBufferFail != depthStencilState->ccwStencilDepthBufferFail || - renderer->depthStencilState.ccwStencilPass != depthStencilState->ccwStencilPass || - renderer->depthStencilState.ccwStencilFunction != depthStencilState->ccwStencilFunction || - renderer->depthStencilState.referenceStencil != depthStencilState->referenceStencil ) - { - renderer->needNewPipeline = 1; - - SDL_memcpy( - &renderer->depthStencilState, - depthStencilState, - sizeof(FNA3D_DepthStencilState) - ); - } - - /* Dynamic state */ - VULKAN_SetReferenceStencil( - driverData, - depthStencilState->referenceStencil - ); -} - -static void VULKAN_ApplyRasterizerState( - FNA3D_Renderer *driverData, - FNA3D_RasterizerState *rasterizerState -) { - VulkanRenderer *renderer = (VulkanRenderer*) driverData; - float realDepthBias; - - if (rasterizerState->scissorTestEnable != renderer->rasterizerState.scissorTestEnable) - { - renderer->rasterizerState.scissorTestEnable = rasterizerState->scissorTestEnable; - VULKAN_INTERNAL_SetScissorRectCommand(renderer); - renderer->needNewPipeline = 1; - } - - realDepthBias = rasterizerState->depthBias * XNAToVK_DepthBiasScale( - XNAToVK_DepthFormat( - renderer, - renderer->currentDepthFormat - ) - ); - - if ( realDepthBias != renderer->rasterizerState.depthBias || - rasterizerState->slopeScaleDepthBias != renderer->rasterizerState.slopeScaleDepthBias ) - { - renderer->rasterizerState.depthBias = realDepthBias; - renderer->rasterizerState.slopeScaleDepthBias = rasterizerState->slopeScaleDepthBias; - VULKAN_INTERNAL_SetDepthBiasCommand(renderer); - renderer->needNewPipeline = 1; - } - - if ( rasterizerState->cullMode != renderer->rasterizerState.cullMode || - rasterizerState->fillMode != renderer->rasterizerState.fillMode || - rasterizerState->multiSampleAntiAlias != renderer->rasterizerState.multiSampleAntiAlias ) - { - renderer->rasterizerState.cullMode = rasterizerState->cullMode; - renderer->rasterizerState.fillMode = rasterizerState->fillMode; - renderer->rasterizerState.multiSampleAntiAlias = rasterizerState->multiSampleAntiAlias; - renderer->needNewPipeline = 1; - } -} - -static void VULKAN_VerifySampler( - FNA3D_Renderer *driverData, - int32_t index, - FNA3D_Texture *texture, - FNA3D_SamplerState *sampler -) { - VulkanRenderer *renderer = (VulkanRenderer*) driverData; - VulkanTexture *vulkanTexture = (VulkanTexture*) texture; - VkSampler vkSamplerState; - - if (texture == NULL) - { - if (renderer->textures[index] != &NullTexture) - { - renderer->textures[index] = &NullTexture; - renderer->textureNeedsUpdate[index] = 1; - } - - if (renderer->samplers[index] == VK_NULL_HANDLE) - { - vkSamplerState = VULKAN_INTERNAL_FetchSamplerState( - renderer, - sampler, - 0 - ); - - renderer->samplers[index] = vkSamplerState; - renderer->samplerNeedsUpdate[index] = 1; - } - - return; - } - - if (vulkanTexture != renderer->textures[index]) - { - renderer->textures[index] = vulkanTexture; - renderer->textureNeedsUpdate[index] = 1; - - if (index >= MAX_TEXTURE_SAMPLERS) - { - renderer->vertexSamplerDescriptorSetDataNeedsUpdate = 1; - } - else - { - renderer->fragSamplerDescriptorSetDataNeedsUpdate = 1; - } - } - - vkSamplerState = VULKAN_INTERNAL_FetchSamplerState( - renderer, - sampler, - vulkanTexture->levelCount - ); - - if (vkSamplerState != renderer->samplers[index]) - { - renderer->samplers[index] = vkSamplerState; - renderer->samplerNeedsUpdate[index] = 1; - - if (index >= MAX_TEXTURE_SAMPLERS) - { - renderer->vertexSamplerDescriptorSetDataNeedsUpdate = 1; - } - else - { - renderer->fragSamplerDescriptorSetDataNeedsUpdate = 1; - } - } -} - -static void VULKAN_VerifyVertexSampler( - FNA3D_Renderer *driverData, - int32_t index, - FNA3D_Texture *texture, - FNA3D_SamplerState *sampler -) { - VULKAN_VerifySampler( - driverData, - MAX_TEXTURE_SAMPLERS + index, - texture, - sampler - ); -} - -static void VULKAN_ApplyVertexBufferBindings( - FNA3D_Renderer *driverData, - FNA3D_VertexBufferBinding *bindings, - int32_t numBindings, - uint8_t bindingsUpdated, - int32_t baseVertex -) { - VulkanRenderer *renderer = (VulkanRenderer*) driverData; - MOJOSHADER_vkShader *vertexShader, *blah; - int32_t i, bindingsIndex; - uint32_t hash; - void* bindingsResult; - FNA3D_VertexBufferBinding *src, *dst; - VulkanBuffer *vertexBuffer; - VkDeviceSize offset; - - if (renderer->supportsBaseVertex) - { - baseVertex = 0; - } - - /* Check VertexBufferBindings */ - MOJOSHADER_vkGetBoundShaders(renderer->mojoshaderContext, &vertexShader, &blah); - bindingsResult = PackedVertexBufferBindingsArray_Fetch( - renderer->vertexBufferBindingsCache, - bindings, - numBindings, - vertexShader, - &bindingsIndex, - &hash - ); - if (bindingsResult == NULL) - { - PackedVertexBufferBindingsArray_Insert( - &renderer->vertexBufferBindingsCache, - bindings, - numBindings, - vertexShader, - (void*) 69420 - ); - } - - if (bindingsUpdated) - { - renderer->numVertexBindings = numBindings; - for (i = 0; i < renderer->numVertexBindings; i += 1) - { - src = &bindings[i]; - dst = &renderer->vertexBindings[i]; - dst->vertexBuffer = src->vertexBuffer; - dst->vertexOffset = src->vertexOffset; - dst->instanceFrequency = src->instanceFrequency; - dst->vertexDeclaration.vertexStride = src->vertexDeclaration.vertexStride; - dst->vertexDeclaration.elementCount = src->vertexDeclaration.elementCount; - SDL_memcpy( - dst->vertexDeclaration.elements, - src->vertexDeclaration.elements, - sizeof(FNA3D_VertexElement) * src->vertexDeclaration.elementCount - ); - } - } - - if (bindingsIndex != renderer->currentVertexBufferBindingsIndex) - { - renderer->currentVertexBufferBindingsIndex = bindingsIndex; - renderer->needNewPipeline = 1; - } - - for (i = 0; i < numBindings; i += 1) - { - vertexBuffer = (VulkanBuffer*) FNA3D_Memory_GetActiveBuffer( - (FNA3D_BufferContainer*) bindings[i].vertexBuffer - ); - if (vertexBuffer == NULL) - { - continue; - } - - offset = - (bindings[i].vertexOffset + baseVertex) * - bindings[i].vertexDeclaration.vertexStride - ; - - renderer->boundVertexBuffers[i] = vertexBuffer->buffer; - renderer->boundVertexBufferOffsets[i] = offset; - - FNA3D_CommandBuffer_MarkBufferAsBound( - renderer->commandBuffers, - (FNA3D_BufferHandle*) vertexBuffer - ); - } -} - -/* Render Targets */ - -static void VULKAN_SetRenderTargets( - FNA3D_Renderer *driverData, - FNA3D_RenderTargetBinding *renderTargets, - int32_t numRenderTargets, - FNA3D_Renderbuffer *depthStencilBuffer, - FNA3D_DepthFormat depthFormat, - uint8_t preserveTargetContents -) { - VulkanRenderer *renderer = (VulkanRenderer*) driverData; - VulkanColorBuffer *cb; - VulkanTexture *tex; - int32_t i; - - /* Perform any pending clears before switching render targets */ - if ( renderer->shouldClearColorOnBeginPass || - renderer->shouldClearDepthOnBeginPass || - renderer->shouldClearStencilOnBeginPass ) - { - VULKAN_INTERNAL_BeginRenderPass(renderer); - } - - renderer->nextRenderPassPreserveTargetContents = preserveTargetContents; - - for (i = 0; i < MAX_RENDERTARGET_BINDINGS; i += 1) - { - renderer->nextRenderPassColorAttachments[i] = NULL; - renderer->nextRenderPassColorMultiSampleAttachments[i] = NULL; - } - - renderer->nextRenderPassDepthStencilAttachment = NULL; - renderer->nextRenderPassMultiSampleCount = renderer->fauxBackbufferMultiSampleCount; - - if (numRenderTargets <= 0) - { - renderer->nextRenderPassColorAttachments[0] = renderer->fauxBackbufferColor.handle; - renderer->nextRenderPassAttachmentCubeFaces[0] = (FNA3D_CubeMapFace) 0; - renderer->nextRenderPassColorAttachmentCount = 1; - - if (renderer->fauxBackbufferMultiSampleCount > 1) - { - renderer->nextRenderPassColorMultiSampleAttachments[0] = - renderer->fauxBackbufferMultiSampleColor; - } - renderer->nextRenderPassDepthStencilAttachment = - renderer->fauxBackbufferDepthStencil.handle; - } - else - { - for (i = 0; i < numRenderTargets; i += 1) - { - renderer->nextRenderPassAttachmentCubeFaces[i] = ( - renderTargets[i].type == FNA3D_RENDERTARGET_TYPE_CUBE ? - renderTargets[i].cube.face : - (FNA3D_CubeMapFace) 0 - ); - - if (renderTargets[i].colorBuffer != NULL) - { - cb = ((VulkanRenderbuffer*) renderTargets[i].colorBuffer)->colorBuffer; - renderer->nextRenderPassColorAttachments[i] = cb->handle; - renderer->nextRenderPassMultiSampleCount = cb->multiSampleCount; - - if (cb->multiSampleCount > 0) - { - renderer->nextRenderPassColorMultiSampleAttachments[i] = cb->multiSampleTexture; - } - } - else - { - tex = (VulkanTexture*) renderTargets[i].texture; - renderer->nextRenderPassColorAttachments[i] = tex; - renderer->nextRenderPassMultiSampleCount = 0; - } - } - - renderer->nextRenderPassColorAttachmentCount = numRenderTargets; - - /* update depth stencil buffer */ - - if (depthStencilBuffer != NULL) - { - renderer->nextRenderPassDepthStencilAttachment = ((VulkanRenderbuffer*) depthStencilBuffer)->depthBuffer->handle; - renderer->nextRenderPassDepthFormat = depthFormat; - } - else - { - renderer->nextRenderPassDepthStencilAttachment = NULL; - } - } - - renderer->needNewRenderPass = 1; -} - -static void VULKAN_ResolveTarget( - FNA3D_Renderer *driverData, - FNA3D_RenderTargetBinding *target -) { - VulkanRenderer *renderer = (VulkanRenderer*) driverData; - VulkanTexture *vulkanTexture = (VulkanTexture*) target->texture; - VulkanCommandBuffer *commandBuffer; - int32_t layerCount = (target->type == FNA3D_RENDERTARGET_TYPE_CUBE) ? 6 : 1; - int32_t level; - VulkanResourceAccessType *levelAccessType; - VkImageBlit blit; - - /* The target is resolved during the render pass */ - - /* If the target has mipmaps, regenerate them now */ - if (target->levelCount > 1) - { - VULKAN_INTERNAL_MaybeEndRenderPass(renderer); - - /* Store the original image layout... */ - levelAccessType = SDL_stack_alloc( - VulkanResourceAccessType, - target->levelCount - ); - for (level = 0; level < target->levelCount; level += 1) - { - levelAccessType[level] = vulkanTexture->resourceAccessType; - } - - /* Blit each mip sequentially. Barriers, barriers everywhere! */ - for (level = 1; level < target->levelCount; level += 1) - { - blit.srcOffsets[0].x = 0; - blit.srcOffsets[0].y = 0; - blit.srcOffsets[0].z = 0; - - blit.srcOffsets[1].x = vulkanTexture->dimensions.width >> (level - 1); - blit.srcOffsets[1].y = vulkanTexture->dimensions.height >> (level - 1); - blit.srcOffsets[1].z = 1; - - blit.dstOffsets[0].x = 0; - blit.dstOffsets[0].y = 0; - blit.dstOffsets[0].z = 0; - - blit.dstOffsets[1].x = vulkanTexture->dimensions.width >> level; - blit.dstOffsets[1].y = vulkanTexture->dimensions.height >> level; - blit.dstOffsets[1].z = 1; - - blit.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - blit.srcSubresource.baseArrayLayer = 0; - blit.srcSubresource.layerCount = layerCount; - blit.srcSubresource.mipLevel = level - 1; - - blit.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - blit.dstSubresource.baseArrayLayer = 0; - blit.dstSubresource.layerCount = layerCount; - blit.dstSubresource.mipLevel = level; - - VULKAN_INTERNAL_ImageMemoryBarrier( - renderer, - RESOURCE_ACCESS_TRANSFER_READ, - VK_IMAGE_ASPECT_COLOR_BIT, - 0, - layerCount, - level - 1, - 1, - 0, - vulkanTexture->image, - &levelAccessType[level - 1] - ); - - VULKAN_INTERNAL_ImageMemoryBarrier( - renderer, - RESOURCE_ACCESS_TRANSFER_WRITE, - VK_IMAGE_ASPECT_COLOR_BIT, - 0, - layerCount, - level, - 1, - 1, - vulkanTexture->image, - &levelAccessType[level] - ); - - commandBuffer = (VulkanCommandBuffer*) FNA3D_CommandBuffer_GetCurrent( - renderer->commandBuffers - ); - RECORD_CMD(renderer->vkCmdBlitImage( - commandBuffer->commandBuffer, - vulkanTexture->image, - VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - vulkanTexture->image, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - 1, - &blit, - VK_FILTER_LINEAR - )); - } - - /* Transition final level to READ */ - VULKAN_INTERNAL_ImageMemoryBarrier( - renderer, - RESOURCE_ACCESS_TRANSFER_READ, - VK_IMAGE_ASPECT_COLOR_BIT, - 0, - layerCount, - target->levelCount - 1, - 1, - 1, - vulkanTexture->image, - &levelAccessType[target->levelCount - 1] - ); - - /* The whole texture is in READ layout now, so set the access type on the texture */ - vulkanTexture->resourceAccessType = RESOURCE_ACCESS_TRANSFER_READ; - - /* Transition to sampler read if necessary */ - if (vulkanTexture->imageCreateInfo.usage & VK_IMAGE_USAGE_SAMPLED_BIT) - { - VULKAN_INTERNAL_ImageMemoryBarrier( - renderer, - RESOURCE_ACCESS_ANY_SHADER_READ_SAMPLED_IMAGE, - VK_IMAGE_ASPECT_COLOR_BIT, - 0, - layerCount, - 0, - target->levelCount, - 0, - vulkanTexture->image, - &vulkanTexture->resourceAccessType - ); - } - - SDL_stack_free(levelAccessType); - } -} - -/* Backbuffer Functions */ - -static void VULKAN_ResetBackbuffer( - FNA3D_Renderer *driverData, - FNA3D_PresentationParameters *presentationParameters -) { - int32_t i; - VulkanRenderer *renderer = (VulkanRenderer*) driverData; - uint8_t recreateSwapchains = - (presentationParameters->backBufferWidth != renderer->fauxBackbufferWidth || - presentationParameters->backBufferHeight != renderer->fauxBackbufferHeight); - - VULKAN_INTERNAL_FlushCommands(renderer, 1); - - VULKAN_INTERNAL_DestroyFauxBackbuffer(renderer); - VULKAN_INTERNAL_CreateFauxBackbuffer( - renderer, - presentationParameters - ); - - VULKAN_INTERNAL_FlushCommands(renderer, 1); - - if (recreateSwapchains) - { - for (i = renderer->swapchainDataCount - 1; i >= 0; i -= 1) - { - VULKAN_INTERNAL_RecreateSwapchain(renderer, renderer->swapchainDatas[i]->windowHandle); - } - } -} - -static void VULKAN_ReadBackbuffer( - FNA3D_Renderer *driverData, - int32_t x, - int32_t y, - int32_t w, - int32_t h, - void* data, - int32_t dataLength -) { - VulkanRenderer *renderer = (VulkanRenderer*) driverData; - - VULKAN_INTERNAL_GetTextureData( - driverData, - (FNA3D_Texture*) renderer->fauxBackbufferColor.handle, - x, - y, - w, - h, - 0, - 0, - data, - dataLength - ); -} - -static void VULKAN_GetBackbufferSize( - FNA3D_Renderer *driverData, - int32_t *w, - int32_t *h -) { - VulkanRenderer *renderer = (VulkanRenderer*) driverData; - *w = renderer->fauxBackbufferWidth; - *h = renderer->fauxBackbufferHeight; -} - -static FNA3D_SurfaceFormat VULKAN_GetBackbufferSurfaceFormat( - FNA3D_Renderer *driverData -) { - VulkanRenderer *renderer = (VulkanRenderer*) driverData; - return renderer->fauxBackbufferColor.handle->colorFormat; -} - -static FNA3D_DepthFormat VULKAN_GetBackbufferDepthFormat( - FNA3D_Renderer *driverData -) { - VulkanRenderer *renderer = (VulkanRenderer*) driverData; - if (renderer->fauxBackbufferDepthStencil.handle == NULL) - { - return FNA3D_DEPTHFORMAT_NONE; - } - return renderer->fauxBackbufferDepthStencil.handle->depthStencilFormat; -} - -static int32_t VULKAN_GetBackbufferMultiSampleCount(FNA3D_Renderer *driverData) -{ - VulkanRenderer *renderer = (VulkanRenderer*) driverData; - return renderer->fauxBackbufferMultiSampleCount; -} - -/* Textures */ - -static FNA3D_Texture* VULKAN_CreateTexture2D( - FNA3D_Renderer *driverData, - FNA3D_SurfaceFormat format, - int32_t width, - int32_t height, - int32_t levelCount, - uint8_t isRenderTarget -) { - VulkanRenderer *renderer = (VulkanRenderer*) driverData; - VulkanTexture *result; - uint32_t usageFlags = ( - VK_IMAGE_USAGE_SAMPLED_BIT | - VK_IMAGE_USAGE_TRANSFER_DST_BIT | - VK_IMAGE_USAGE_TRANSFER_SRC_BIT - ); - - result = (VulkanTexture*) SDL_malloc(sizeof(VulkanTexture)); - - if (isRenderTarget) - { - usageFlags |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; - } - - VULKAN_INTERNAL_CreateTexture( - renderer, - width, - height, - 1, - 0, - isRenderTarget, - VK_SAMPLE_COUNT_1_BIT, - levelCount, - XNAToVK_SurfaceFormat[format], - XNAToVK_SurfaceSwizzle[format], - VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_TYPE_2D, - usageFlags, - result - ); - result->colorFormat = format; - - return (FNA3D_Texture*) result; -} - -static FNA3D_Texture* VULKAN_CreateTexture3D( - FNA3D_Renderer *driverData, - FNA3D_SurfaceFormat format, - int32_t width, - int32_t height, - int32_t depth, - int32_t levelCount -) { - VulkanRenderer *renderer = (VulkanRenderer*) driverData; - VulkanTexture *result; - uint32_t usageFlags = ( - VK_IMAGE_USAGE_SAMPLED_BIT | - VK_IMAGE_USAGE_TRANSFER_DST_BIT | - VK_IMAGE_USAGE_TRANSFER_SRC_BIT - ); - - result = (VulkanTexture*) SDL_malloc(sizeof(VulkanTexture)); - - VULKAN_INTERNAL_CreateTexture( - renderer, - width, - height, - depth, - 0, - 0, - VK_SAMPLE_COUNT_1_BIT, - levelCount, - XNAToVK_SurfaceFormat[format], - XNAToVK_SurfaceSwizzle[format], - VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_TYPE_3D, - usageFlags, - result - ); - result->colorFormat = format; - - return (FNA3D_Texture*) result; -} - -static FNA3D_Texture* VULKAN_CreateTextureCube( - FNA3D_Renderer *driverData, - FNA3D_SurfaceFormat format, - int32_t size, - int32_t levelCount, - uint8_t isRenderTarget -) { - VulkanRenderer *renderer = (VulkanRenderer*) driverData; - VulkanTexture *result; - uint32_t usageFlags = ( - VK_IMAGE_USAGE_SAMPLED_BIT | - VK_IMAGE_USAGE_TRANSFER_DST_BIT | - VK_IMAGE_USAGE_TRANSFER_SRC_BIT - ); - - result = (VulkanTexture*) SDL_malloc(sizeof(VulkanTexture)); - - if (isRenderTarget) - { - usageFlags |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; - } - - VULKAN_INTERNAL_CreateTexture( - renderer, - size, - size, - 1, - 1, - isRenderTarget, - VK_SAMPLE_COUNT_1_BIT, - levelCount, - XNAToVK_SurfaceFormat[format], - XNAToVK_SurfaceSwizzle[format], - VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_TYPE_2D, - usageFlags, - result - ); - result->colorFormat = format; - - return (FNA3D_Texture*) result; -} - -static void VULKAN_AddDisposeTexture( - FNA3D_Renderer *driverData, - FNA3D_Texture *texture -) { - VulkanRenderer *renderer = (VulkanRenderer*) driverData; - VulkanTexture *vulkanTexture = (VulkanTexture*) texture; - uint32_t i; - - for (i = 0; i < MAX_RENDERTARGET_BINDINGS; i += 1) - { - if (renderer->colorAttachments[i] != NULL) - { - if (vulkanTexture->view == renderer->colorAttachments[i]->rtViews[renderer->attachmentCubeFaces[i]]) - { - renderer->colorAttachments[i] = NULL; - } - } - } - - for (i = 0; i < TEXTURE_COUNT; i += 1) - { - if (vulkanTexture == renderer->textures[i]) - { - renderer->textures[i] = &NullTexture; - renderer->textureNeedsUpdate[i] = 1; - } - } - - /* Queue texture for destruction */ - FNA3D_CommandBuffer_AddDisposeTexture( - renderer->commandBuffers, - (FNA3D_Texture*) vulkanTexture - ); -} - -static void VULKAN_INTERNAL_SetTextureData( - VulkanRenderer *renderer, - VulkanTexture *texture, - int32_t x, - int32_t y, - int32_t z, - int32_t w, - int32_t h, - int32_t d, - int32_t level, - int32_t layer, - void *data, - int32_t dataLength -) { - VulkanCommandBuffer *commandBuffer; - VkBufferImageCopy imageCopy; - int32_t uploadLength = BytesPerImage(w, h, texture->colorFormat) * d; - int32_t copyLength = SDL_min(dataLength, uploadLength); - VulkanBuffer *transferBuffer; - VkDeviceSize offset; - int32_t bufferRowLength = w; - int32_t bufferImageHeight = h; - int32_t blockSize = Texture_GetBlockSize(texture->colorFormat); - - if (blockSize > 1) - { - bufferRowLength = (bufferRowLength + blockSize - 1) & ~(blockSize - 1); - bufferImageHeight = (bufferImageHeight + blockSize - 1) & ~(blockSize - 1); - } - - if (dataLength > uploadLength) - { - FNA3D_LogWarn( - "dataLength %i too long for texture upload, w: %i, h: %i, max upload length: %i", - dataLength, - w, - h, - uploadLength - ); - } - - VULKAN_INTERNAL_MaybeEndRenderPass(renderer); - - SDL_LockMutex(renderer->passLock); - FNA3D_CommandBuffer_LockForTransfer(renderer->commandBuffers); - - VULKAN_INTERNAL_CopyToTransferBuffer( - renderer, - data, - uploadLength, - copyLength, - &transferBuffer, - &offset, - (VkDeviceSize)Texture_GetFormatSize(texture->colorFormat) - ); - - VULKAN_INTERNAL_BufferMemoryBarrier( - renderer, - RESOURCE_ACCESS_TRANSFER_READ, - transferBuffer->buffer, - &transferBuffer->resourceAccessType - ); - - VULKAN_INTERNAL_ImageMemoryBarrier( - renderer, - RESOURCE_ACCESS_TRANSFER_WRITE, - VK_IMAGE_ASPECT_COLOR_BIT, - 0, - texture->layerCount, - 0, - texture->levelCount, - 0, - texture->image, - &texture->resourceAccessType - ); - - /* Block compressed texture buffers must be at least 1 block in width and height */ - bufferRowLength = SDL_max(blockSize, bufferRowLength); - bufferImageHeight = SDL_max(blockSize, bufferImageHeight); - - imageCopy.imageExtent.width = w; - imageCopy.imageExtent.height = h; - imageCopy.imageExtent.depth = d; - imageCopy.imageOffset.x = x; - imageCopy.imageOffset.y = y; - imageCopy.imageOffset.z = z; - imageCopy.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - imageCopy.imageSubresource.baseArrayLayer = layer; - imageCopy.imageSubresource.layerCount = 1; - imageCopy.imageSubresource.mipLevel = level; - imageCopy.bufferOffset = offset; - imageCopy.bufferRowLength = bufferRowLength; - imageCopy.bufferImageHeight = bufferImageHeight; - - commandBuffer = (VulkanCommandBuffer*) FNA3D_CommandBuffer_GetCurrent( - renderer->commandBuffers - ); - RECORD_CMD(renderer->vkCmdCopyBufferToImage( - commandBuffer->commandBuffer, - transferBuffer->buffer, - texture->image, - AccessMap[texture->resourceAccessType].imageLayout, - 1, - &imageCopy - )); - - if (texture->imageCreateInfo.usage & VK_IMAGE_USAGE_SAMPLED_BIT) - { - VULKAN_INTERNAL_ImageMemoryBarrier( - renderer, - RESOURCE_ACCESS_ANY_SHADER_READ_SAMPLED_IMAGE, - VK_IMAGE_ASPECT_COLOR_BIT, - 0, - texture->layerCount, - 0, - texture->levelCount, - 0, - texture->image, - &texture->resourceAccessType - ); - } - - FNA3D_CommandBuffer_UnlockFromTransfer(renderer->commandBuffers); - SDL_UnlockMutex(renderer->passLock); -} - -static void VULKAN_SetTextureData2D( - FNA3D_Renderer *driverData, - FNA3D_Texture *texture, - int32_t x, - int32_t y, - int32_t w, - int32_t h, - int32_t level, - void* data, - int32_t dataLength -) { - VULKAN_INTERNAL_SetTextureData( - (VulkanRenderer*) driverData, - (VulkanTexture*) texture, - x, - y, - 0, - w, - h, - 1, - level, - 0, - data, - dataLength - ); -} - -static void VULKAN_SetTextureData3D( - FNA3D_Renderer *driverData, - FNA3D_Texture *texture, - int32_t x, - int32_t y, - int32_t z, - int32_t w, - int32_t h, - int32_t d, - int32_t level, - void* data, - int32_t dataLength -) { - VULKAN_INTERNAL_SetTextureData( - (VulkanRenderer*) driverData, - (VulkanTexture*) texture, - x, - y, - z, - w, - h, - d, - level, - 0, - data, - dataLength - ); -} - -static void VULKAN_SetTextureDataCube( - FNA3D_Renderer *driverData, - FNA3D_Texture *texture, - int32_t x, - int32_t y, - int32_t w, - int32_t h, - FNA3D_CubeMapFace cubeMapFace, - int32_t level, - void* data, - int32_t dataLength -) { - VULKAN_INTERNAL_SetTextureData( - (VulkanRenderer*) driverData, - (VulkanTexture*) texture, - x, - y, - 0, - w, - h, - 1, - level, - cubeMapFace, - data, - dataLength - ); -} - -static void VULKAN_SetTextureDataYUV( - FNA3D_Renderer *driverData, - FNA3D_Texture *y, - FNA3D_Texture *u, - FNA3D_Texture *v, - int32_t yWidth, - int32_t yHeight, - int32_t uvWidth, - int32_t uvHeight, - void* data, - int32_t dataLength -) { - VulkanRenderer *renderer = (VulkanRenderer*) driverData; - VulkanCommandBuffer *commandBuffer; - VulkanTexture *tex; - VulkanBuffer *transferBuffer; - int32_t yDataLength = BytesPerImage(yWidth, yHeight, FNA3D_SURFACEFORMAT_ALPHA8); - int32_t uvDataLength = BytesPerImage(uvWidth, uvHeight, FNA3D_SURFACEFORMAT_ALPHA8); - int32_t uploadLength = yDataLength + uvDataLength * 2; - int32_t copyLength = SDL_min(dataLength, uploadLength); - VkBufferImageCopy imageCopy; - VkDeviceSize offset; - - if (dataLength > uploadLength) - { - FNA3D_LogWarn( - "dataLength %i too long for texture upload, max upload length: %i", - dataLength, - uploadLength - ); - } - - VULKAN_INTERNAL_MaybeEndRenderPass(renderer); - - SDL_LockMutex(renderer->passLock); - FNA3D_CommandBuffer_LockForTransfer(renderer->commandBuffers); - - VULKAN_INTERNAL_CopyToTransferBuffer( - renderer, - data, - uploadLength, - copyLength, - &transferBuffer, - &offset, - (VkDeviceSize)Texture_GetFormatSize(FNA3D_SURFACEFORMAT_ALPHA8) - ); - - VULKAN_INTERNAL_BufferMemoryBarrier( - renderer, - RESOURCE_ACCESS_TRANSFER_READ, - transferBuffer->buffer, - &transferBuffer->resourceAccessType - ); - - /* Initialize values that are the same for Y, U, and V */ - - imageCopy.imageExtent.depth = 1; - imageCopy.imageOffset.x = 0; - imageCopy.imageOffset.y = 0; - imageCopy.imageOffset.z = 0; - imageCopy.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - imageCopy.imageSubresource.baseArrayLayer = 0; - imageCopy.imageSubresource.layerCount = 1; - imageCopy.imageSubresource.mipLevel = 0; - - /* Y */ - - tex = (VulkanTexture*) y; - - VULKAN_INTERNAL_ImageMemoryBarrier( - renderer, - RESOURCE_ACCESS_TRANSFER_WRITE, - VK_IMAGE_ASPECT_COLOR_BIT, - 0, - tex->layerCount, - 0, - tex->levelCount, - 0, - tex->image, - &tex->resourceAccessType - ); - - imageCopy.imageExtent.width = yWidth; - imageCopy.imageExtent.height = yHeight; - imageCopy.bufferOffset = offset; - imageCopy.bufferRowLength = yWidth; - imageCopy.bufferImageHeight = yHeight; - - commandBuffer = (VulkanCommandBuffer*) FNA3D_CommandBuffer_GetCurrent( - renderer->commandBuffers - ); - RECORD_CMD(renderer->vkCmdCopyBufferToImage( - commandBuffer->commandBuffer, - transferBuffer->buffer, - tex->image, - AccessMap[tex->resourceAccessType].imageLayout, - 1, - &imageCopy - )); - - if (tex->imageCreateInfo.usage & VK_IMAGE_USAGE_SAMPLED_BIT) - { - VULKAN_INTERNAL_ImageMemoryBarrier( - renderer, - RESOURCE_ACCESS_ANY_SHADER_READ_SAMPLED_IMAGE, - VK_IMAGE_ASPECT_COLOR_BIT, - 0, - tex->layerCount, - 0, - tex->levelCount, - 0, - tex->image, - &tex->resourceAccessType - ); - } - - /* These apply to both U and V */ - - imageCopy.imageExtent.width = uvWidth; - imageCopy.imageExtent.height = uvHeight; - imageCopy.bufferRowLength = uvWidth; - imageCopy.bufferImageHeight = uvHeight; - - /* U */ - - imageCopy.bufferOffset = offset + yDataLength; - - tex = (VulkanTexture*) u; - - VULKAN_INTERNAL_ImageMemoryBarrier( - renderer, - RESOURCE_ACCESS_TRANSFER_WRITE, - VK_IMAGE_ASPECT_COLOR_BIT, - 0, - tex->layerCount, - 0, - tex->levelCount, - 0, - tex->image, - &tex->resourceAccessType - ); - - RECORD_CMD(renderer->vkCmdCopyBufferToImage( - commandBuffer->commandBuffer, - transferBuffer->buffer, - tex->image, - AccessMap[tex->resourceAccessType].imageLayout, - 1, - &imageCopy - )); - - if (tex->imageCreateInfo.usage & VK_IMAGE_USAGE_SAMPLED_BIT) - { - VULKAN_INTERNAL_ImageMemoryBarrier( - renderer, - RESOURCE_ACCESS_ANY_SHADER_READ_SAMPLED_IMAGE, - VK_IMAGE_ASPECT_COLOR_BIT, - 0, - tex->layerCount, - 0, - tex->levelCount, - 0, - tex->image, - &tex->resourceAccessType - ); - } - - /* V */ - - imageCopy.bufferOffset = offset + yDataLength + uvDataLength; - - tex = (VulkanTexture*) v; - - VULKAN_INTERNAL_ImageMemoryBarrier( - renderer, - RESOURCE_ACCESS_TRANSFER_WRITE, - VK_IMAGE_ASPECT_COLOR_BIT, - 0, - tex->layerCount, - 0, - tex->levelCount, - 0, - tex->image, - &tex->resourceAccessType - ); - - RECORD_CMD(renderer->vkCmdCopyBufferToImage( - commandBuffer->commandBuffer, - transferBuffer->buffer, - tex->image, - AccessMap[tex->resourceAccessType].imageLayout, - 1, - &imageCopy - )); - - if (tex->imageCreateInfo.usage & VK_IMAGE_USAGE_SAMPLED_BIT) - { - VULKAN_INTERNAL_ImageMemoryBarrier( - renderer, - RESOURCE_ACCESS_ANY_SHADER_READ_SAMPLED_IMAGE, - VK_IMAGE_ASPECT_COLOR_BIT, - 0, - tex->layerCount, - 0, - tex->levelCount, - 0, - tex->image, - &tex->resourceAccessType - ); - } - - FNA3D_CommandBuffer_UnlockFromTransfer(renderer->commandBuffers); - SDL_UnlockMutex(renderer->passLock); -} - -static void VULKAN_GetTextureData2D( - FNA3D_Renderer *driverData, - FNA3D_Texture *texture, - int32_t x, - int32_t y, - int32_t w, - int32_t h, - int32_t level, - void* data, - int32_t dataLength -) { - VULKAN_INTERNAL_GetTextureData( - driverData, - texture, - x, - y, - w, - h, - level, - 0, - data, - dataLength - ); -} - -static void VULKAN_GetTextureData3D( - FNA3D_Renderer *driverData, - FNA3D_Texture *texture, - int32_t x, - int32_t y, - int32_t z, - int32_t w, - int32_t h, - int32_t d, - int32_t level, - void* data, - int32_t dataLength -) { - FNA3D_LogError( - "GetTextureData3D is unsupported!" - ); -} - -static void VULKAN_GetTextureDataCube( - FNA3D_Renderer *driverData, - FNA3D_Texture *texture, - int32_t x, - int32_t y, - int32_t w, - int32_t h, - FNA3D_CubeMapFace cubeMapFace, - int32_t level, - void* data, - int32_t dataLength -) { - VULKAN_INTERNAL_GetTextureData( - driverData, - texture, - x, - y, - w, - h, - level, - cubeMapFace, - data, - dataLength - ); -} - -/* Renderbuffers */ - -static FNA3D_Renderbuffer* VULKAN_GenColorRenderbuffer( - FNA3D_Renderer *driverData, - int32_t width, - int32_t height, - FNA3D_SurfaceFormat format, - int32_t multiSampleCount, - FNA3D_Texture *texture -) { - VulkanRenderer *renderer = (VulkanRenderer*) driverData; - VulkanTexture *vlkTexture = (VulkanTexture*) texture; - VulkanRenderbuffer *renderbuffer; - - /* Create and return the renderbuffer */ - renderbuffer = (VulkanRenderbuffer*) SDL_malloc(sizeof(VulkanRenderbuffer)); - renderbuffer->depthBuffer = NULL; - renderbuffer->colorBuffer = (VulkanColorBuffer*) SDL_malloc( - sizeof(VulkanColorBuffer) - ); - renderbuffer->colorBuffer->handle = vlkTexture; - renderbuffer->colorBuffer->multiSampleTexture = NULL; - renderbuffer->colorBuffer->multiSampleCount = 0; - - if (multiSampleCount > 1) - { - renderbuffer->colorBuffer->multiSampleTexture = - (VulkanTexture*) SDL_malloc(sizeof(VulkanTexture)); - VULKAN_INTERNAL_CreateTexture( - renderer, - width, - height, - 1, - 0, - 1, - XNAToVK_SampleCount(multiSampleCount), - 1, - XNAToVK_SurfaceFormat[format], - XNAToVK_SurfaceSwizzle[format], - VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_TYPE_2D, - VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, - renderbuffer->colorBuffer->multiSampleTexture - ); - renderbuffer->colorBuffer->multiSampleTexture->colorFormat = format; - - renderbuffer->colorBuffer->multiSampleCount = multiSampleCount; - - VULKAN_INTERNAL_ImageMemoryBarrier( - renderer, - RESOURCE_ACCESS_COLOR_ATTACHMENT_READ_WRITE, - VK_IMAGE_ASPECT_COLOR_BIT, - 0, - renderbuffer->colorBuffer->multiSampleTexture->layerCount, - 0, - renderbuffer->colorBuffer->multiSampleTexture->levelCount, - 0, - renderbuffer->colorBuffer->multiSampleTexture->image, - &renderbuffer->colorBuffer->multiSampleTexture->resourceAccessType - ); - } - - return (FNA3D_Renderbuffer*) renderbuffer; -} - -static FNA3D_Renderbuffer* VULKAN_GenDepthStencilRenderbuffer( - FNA3D_Renderer *driverData, - int32_t width, - int32_t height, - FNA3D_DepthFormat format, - int32_t multiSampleCount -) { - VulkanRenderer *renderer = (VulkanRenderer*) driverData; - VulkanRenderbuffer *renderbuffer; - VkImageAspectFlags depthAspectFlags = VK_IMAGE_ASPECT_DEPTH_BIT; - VkFormat depthFormat = XNAToVK_DepthFormat(renderer, format); - - if (DepthFormatContainsStencil(depthFormat)) - { - depthAspectFlags |= VK_IMAGE_ASPECT_STENCIL_BIT; - } - - renderbuffer = (VulkanRenderbuffer*) SDL_malloc( - sizeof(VulkanRenderbuffer) - ); - renderbuffer->colorBuffer = NULL; - renderbuffer->depthBuffer = (VulkanDepthStencilBuffer*) SDL_malloc( - sizeof(VulkanDepthStencilBuffer) - ); - - renderbuffer->depthBuffer->handle = (VulkanTexture*) SDL_malloc( - sizeof(VulkanTexture) - ); - if (!VULKAN_INTERNAL_CreateTexture( - renderer, - width, - height, - 1, - 0, - 1, - XNAToVK_SampleCount(multiSampleCount), - 1, - depthFormat, - RGBA_SWIZZLE, - depthAspectFlags, - VK_IMAGE_TYPE_2D, - VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, - renderbuffer->depthBuffer->handle - )) { - FNA3D_LogError("Failed to create depth stencil image"); - return NULL; - } - renderbuffer->depthBuffer->handle->depthStencilFormat = format; - - VULKAN_INTERNAL_ImageMemoryBarrier( - renderer, - RESOURCE_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_WRITE, - depthAspectFlags, - 0, - renderbuffer->depthBuffer->handle->layerCount, - 0, - renderbuffer->depthBuffer->handle->levelCount, - 0, - renderbuffer->depthBuffer->handle->image, - &renderbuffer->depthBuffer->handle->resourceAccessType - ); - - return (FNA3D_Renderbuffer*) renderbuffer; -} - -static void VULKAN_AddDisposeRenderbuffer( - FNA3D_Renderer *driverData, - FNA3D_Renderbuffer *renderbuffer -) { - VulkanRenderer *renderer = (VulkanRenderer*) driverData; - VulkanRenderbuffer *vlkRenderBuffer = (VulkanRenderbuffer*) renderbuffer; - uint8_t isDepthStencil = (vlkRenderBuffer->colorBuffer == NULL); - uint32_t i; - - if (isDepthStencil) - { - if (renderer->depthStencilAttachment == vlkRenderBuffer->depthBuffer->handle) - { - renderer->depthStencilAttachment = NULL; - } - } - else - { - /* Iterate through color attachments */ - for (i = 0; i < MAX_RENDERTARGET_BINDINGS; i += 1) - { - if (renderer->colorAttachments[i] == vlkRenderBuffer->colorBuffer->handle) - { - renderer->colorAttachments[i] = NULL; - } - - } - } - - FNA3D_CommandBuffer_AddDisposeRenderbuffer( - renderer->commandBuffers, - (FNA3D_Renderbuffer*) vlkRenderBuffer - ); -} - -/* Buffers */ - -static FNA3D_Buffer* VULKAN_GenVertexBuffer( - FNA3D_Renderer *driverData, - uint8_t dynamic, - FNA3D_BufferUsage usage, - int32_t sizeInBytes -) { - VulkanRenderer *renderer = (VulkanRenderer*) driverData; - return (FNA3D_Buffer*) FNA3D_Memory_CreateBufferContainer( - renderer->allocator, - 1, - sizeInBytes - ); -} - -static void VULKAN_AddDisposeVertexBuffer( - FNA3D_Renderer *driverData, - FNA3D_Buffer *buffer -) { - VulkanRenderer *renderer = (VulkanRenderer*) driverData; - FNA3D_Memory_DestroyBufferContainer( - renderer->allocator, - (FNA3D_BufferContainer*) buffer - ); -} - -static void VULKAN_SetVertexBufferData( - FNA3D_Renderer *driverData, - FNA3D_Buffer *buffer, - int32_t offsetInBytes, - void* data, - int32_t elementCount, - int32_t elementSizeInBytes, - int32_t vertexStride, - FNA3D_SetDataOptions options -) { - /* FIXME: use transfer buffer for elementSizeInBytes < vertexStride */ - VULKAN_INTERNAL_SetBufferData( - driverData, - buffer, - offsetInBytes, - data, - elementCount * vertexStride, - options - ); -} - -static void VULKAN_GetVertexBufferData( - FNA3D_Renderer *driverData, - FNA3D_Buffer *buffer, - int32_t offsetInBytes, - void* data, - int32_t elementCount, - int32_t elementSizeInBytes, - int32_t vertexStride -) { - VulkanRenderer *renderer = (VulkanRenderer*) driverData; - VulkanBuffer *vulkanBuffer; - uint8_t *dataBytes, *cpy, *src, *dst; - uint8_t useTransferBuffer; - int32_t i; - - vulkanBuffer = (VulkanBuffer*) FNA3D_Memory_GetActiveBuffer( - (FNA3D_BufferContainer*) buffer - ); - dataBytes = (uint8_t*) data; - useTransferBuffer = elementSizeInBytes < vertexStride; - - if (useTransferBuffer) - { - cpy = (uint8_t*) SDL_malloc(elementCount * vertexStride); - } - else - { - cpy = dataBytes; - } - - VULKAN_INTERNAL_BufferMemoryBarrier( - renderer, - RESOURCE_ACCESS_TRANSFER_READ, - vulkanBuffer->buffer, - &vulkanBuffer->resourceAccessType - ); - - SDL_memcpy( - cpy, - FNA3D_Memory_GetHostPointer( - vulkanBuffer->usedRegion, - offsetInBytes - ), - elementCount * vertexStride - ); - - if (useTransferBuffer) - { - src = cpy; - dst = dataBytes; - for (i = 0; i < elementCount; i += 1) - { - SDL_memcpy(dst, src, elementSizeInBytes); - dst += elementSizeInBytes; - src += vertexStride; - } - SDL_free(cpy); - } - - VULKAN_INTERNAL_BufferMemoryBarrier( - renderer, - RESOURCE_ACCESS_VERTEX_BUFFER, - vulkanBuffer->buffer, - &vulkanBuffer->resourceAccessType - ); -} - -static FNA3D_Buffer* VULKAN_GenIndexBuffer( - FNA3D_Renderer *driverData, - uint8_t dynamic, - FNA3D_BufferUsage usage, - int32_t sizeInBytes -) { - VulkanRenderer *renderer = (VulkanRenderer*) driverData; - return (FNA3D_Buffer*) FNA3D_Memory_CreateBufferContainer( - renderer->allocator, - 0, - sizeInBytes - ); -} - -static void VULKAN_AddDisposeIndexBuffer( - FNA3D_Renderer *driverData, - FNA3D_Buffer *buffer -) { - VulkanRenderer *renderer = (VulkanRenderer*) driverData; - FNA3D_Memory_DestroyBufferContainer( - renderer->allocator, - (FNA3D_BufferContainer*) buffer - ); -} - -static void VULKAN_SetIndexBufferData( - FNA3D_Renderer *driverData, - FNA3D_Buffer *buffer, - int32_t offsetInBytes, - void* data, - int32_t dataLength, - FNA3D_SetDataOptions options -) { - VULKAN_INTERNAL_SetBufferData( - driverData, - buffer, - offsetInBytes, - data, - dataLength, - options - ); -} - -static void VULKAN_GetIndexBufferData( - FNA3D_Renderer *driverData, - FNA3D_Buffer *buffer, - int32_t offsetInBytes, - void* data, - int32_t dataLength -) { - VulkanRenderer *renderer = (VulkanRenderer*) driverData; - VulkanBuffer *vulkanBuffer; - - vulkanBuffer = (VulkanBuffer*) FNA3D_Memory_GetActiveBuffer( - (FNA3D_BufferContainer*) buffer - ); - - VULKAN_INTERNAL_BufferMemoryBarrier( - renderer, - RESOURCE_ACCESS_TRANSFER_READ, - vulkanBuffer->buffer, - &vulkanBuffer->resourceAccessType - ); - - SDL_memcpy( - data, - FNA3D_Memory_GetHostPointer( - vulkanBuffer->usedRegion, - offsetInBytes - ), - dataLength - ); - - VULKAN_INTERNAL_BufferMemoryBarrier( - renderer, - RESOURCE_ACCESS_INDEX_BUFFER, - vulkanBuffer->buffer, - &vulkanBuffer->resourceAccessType - ); -} - -/* Effects */ - -static inline void ShaderResourcesHashTable_Remove( - VulkanRenderer *renderer, - MOJOSHADER_vkShader *key -) { - int32_t i; - uint64_t hashcode = (uint64_t) (size_t) key; - ShaderResourcesHashArray *arr = - &renderer->shaderResourcesHashTable.buckets[hashcode % NUM_SHADER_RESOURCES_BUCKETS]; - ShaderResourcesHashMap *element; - - for (i = arr->count - 1; i >= 0; i -= 1) - { - element = &arr->elements[i]; - if (element->key == key) - { - ShaderResources_Destroy(renderer, element->value); - - SDL_memmove( - arr->elements + i, - arr->elements + i + 1, - sizeof(ShaderResourcesHashMap) * (arr->count - i - 1) - ); - - arr->count -= 1; - } - } -} - -static void VULKAN_INTERNAL_DeleteShader(const void *shaderContext, void* shader) -{ - MOJOSHADER_vkShader *vkShader = (MOJOSHADER_vkShader*) shader; - const MOJOSHADER_parseData *pd; - VulkanRenderer *renderer; - PipelineHashArray *pipelineHashArray; - int32_t i, j; - - pd = MOJOSHADER_vkGetShaderParseData(vkShader); - renderer = (VulkanRenderer*) pd->malloc_data; - - if (MOJOSHADER_vkGetShaderRefCount(vkShader) > 1) - { - /* Other effects are using this shader, just decrement the refcount */ - MOJOSHADER_vkDeleteShader(renderer->mojoshaderContext, vkShader); - return; - } - - ShaderResourcesHashTable_Remove(renderer, vkShader); - - /* invalidate any pipeline containing shader */ - for (i = 0; i < NUM_PIPELINE_HASH_BUCKETS; i += 1) - { - pipelineHashArray = &renderer->pipelineHashTable.buckets[i]; - for (j = pipelineHashArray->count - 1; j >= 0; j -= 1) - { - if ( pipelineHashArray->elements[j].key.vertShader == vkShader || - pipelineHashArray->elements[j].key.fragShader == vkShader ) - { - renderer->vkDestroyPipeline( - renderer->logicalDevice, - pipelineHashArray->elements[j].value, - NULL - ); - - SDL_memmove( - pipelineHashArray->elements + j, - pipelineHashArray->elements + j + 1, - sizeof(PipelineHashMap) * (pipelineHashArray->count - j - 1) - ); - - pipelineHashArray->count -= 1; - } - } - } - - MOJOSHADER_vkDeleteShader(renderer->mojoshaderContext, vkShader); -} - -static void VULKAN_CreateEffect( - FNA3D_Renderer *driverData, - uint8_t *effectCode, - uint32_t effectCodeLength, - FNA3D_Effect **effect, - MOJOSHADER_effect **effectData -) { - VulkanRenderer *renderer = (VulkanRenderer*) driverData; - MOJOSHADER_effectShaderContext shaderBackend; - VulkanEffect *result; - int32_t i; - - shaderBackend.shaderContext = renderer->mojoshaderContext; - shaderBackend.compileShader = (MOJOSHADER_compileShaderFunc) MOJOSHADER_vkCompileShader; - shaderBackend.shaderAddRef = (MOJOSHADER_shaderAddRefFunc) MOJOSHADER_vkShaderAddRef; - shaderBackend.deleteShader = VULKAN_INTERNAL_DeleteShader; - shaderBackend.getParseData = (MOJOSHADER_getParseDataFunc) MOJOSHADER_vkGetShaderParseData; - shaderBackend.bindShaders = (MOJOSHADER_bindShadersFunc) MOJOSHADER_vkBindShaders; - shaderBackend.getBoundShaders = (MOJOSHADER_getBoundShadersFunc) MOJOSHADER_vkGetBoundShaders; - shaderBackend.mapUniformBufferMemory = (MOJOSHADER_mapUniformBufferMemoryFunc) MOJOSHADER_vkMapUniformBufferMemory; - shaderBackend.unmapUniformBufferMemory = (MOJOSHADER_unmapUniformBufferMemoryFunc) MOJOSHADER_vkUnmapUniformBufferMemory; - shaderBackend.getError = (MOJOSHADER_getErrorFunc) MOJOSHADER_vkGetError; - shaderBackend.m = NULL; - shaderBackend.f = NULL; - shaderBackend.malloc_data = driverData; - - *effectData = MOJOSHADER_compileEffect( - effectCode, - effectCodeLength, - NULL, - 0, - NULL, - 0, - &shaderBackend - ); - - for (i = 0; i < (*effectData)->error_count; i += 1) - { - FNA3D_LogError( - "MOJOSHADER_compileEffect Error: %s", - (*effectData)->errors[i].error - ); - } - - result = (VulkanEffect*) SDL_malloc(sizeof(VulkanEffect)); - result->effect = *effectData; - *effect = (FNA3D_Effect*) result; -} - -static void VULKAN_CloneEffect( - FNA3D_Renderer *driverData, - FNA3D_Effect *cloneSource, - FNA3D_Effect **effect, - MOJOSHADER_effect **effectData -) { - VulkanRenderer *renderer = (VulkanRenderer*) driverData; - VulkanEffect *vulkanCloneSource = (VulkanEffect*) cloneSource; - VulkanEffect *result; - - *effectData = MOJOSHADER_cloneEffect(vulkanCloneSource->effect); - if (*effectData == NULL) - { - FNA3D_LogError(MOJOSHADER_vkGetError(renderer->mojoshaderContext)); - } - - result = (VulkanEffect*) SDL_malloc(sizeof(VulkanEffect)); - result->effect = *effectData; - *effect = (FNA3D_Effect*) result; -} - -static void VULKAN_AddDisposeEffect( - FNA3D_Renderer *driverData, - FNA3D_Effect *effect -) { - VulkanRenderer *renderer = (VulkanRenderer*) driverData; - - FNA3D_CommandBuffer_AddDisposeEffect(renderer->commandBuffers, effect); -} - -static void VULKAN_SetEffectTechnique( - FNA3D_Renderer *driverData, - FNA3D_Effect *effect, - MOJOSHADER_effectTechnique *technique -) { - VulkanEffect *vkEffect = (VulkanEffect*) effect; - MOJOSHADER_effectSetTechnique(vkEffect->effect, technique); -} - -static void VULKAN_ApplyEffect( - FNA3D_Renderer *driverData, - FNA3D_Effect *effect, - uint32_t pass, - MOJOSHADER_effectStateChanges *stateChanges -) { - VulkanRenderer *renderer = (VulkanRenderer*) driverData; - VulkanEffect *fnaEffect = (VulkanEffect*) effect; - MOJOSHADER_effect *effectData = fnaEffect->effect; - const MOJOSHADER_effectTechnique *technique = fnaEffect->effect->current_technique; - uint32_t numPasses; - - /* - * Lock to prevent mojoshader from overwriting resource data - * while resources are initialized - */ - SDL_LockMutex(renderer->passLock); - - renderer->vertexSamplerDescriptorSetDataNeedsUpdate = 1; - renderer->fragSamplerDescriptorSetDataNeedsUpdate = 1; - renderer->needNewPipeline = 1; - - if (effectData == renderer->currentEffect) - { - if ( technique == renderer->currentTechnique && - pass == renderer->currentPass ) - { - MOJOSHADER_effectCommitChanges( - renderer->currentEffect - ); - - SDL_UnlockMutex(renderer->passLock); - return; - } - MOJOSHADER_effectEndPass(renderer->currentEffect); - MOJOSHADER_effectBeginPass(renderer->currentEffect, pass); - renderer->currentTechnique = technique; - renderer->currentPass = pass; - - SDL_UnlockMutex(renderer->passLock); - return; - } - else if (renderer->currentEffect != NULL) - { - MOJOSHADER_effectEndPass(renderer->currentEffect); - MOJOSHADER_effectEnd(renderer->currentEffect); - } - - MOJOSHADER_effectBegin( - effectData, - &numPasses, - 0, - stateChanges - ); - - MOJOSHADER_effectBeginPass(effectData, pass); - renderer->currentEffect = effectData; - renderer->currentTechnique = technique; - renderer->currentPass = pass; - - SDL_UnlockMutex(renderer->passLock); -} - -static void VULKAN_BeginPassRestore( - FNA3D_Renderer *driverData, - FNA3D_Effect *effect, - MOJOSHADER_effectStateChanges *stateChanges -) { - MOJOSHADER_effect *effectData = ((VulkanEffect *) effect)->effect; - uint32_t whatever; - - MOJOSHADER_effectBegin( - effectData, - &whatever, - 1, - stateChanges - ); - MOJOSHADER_effectBeginPass(effectData, 0); -} - -static void VULKAN_EndPassRestore( - FNA3D_Renderer *driverData, - FNA3D_Effect *effect -) { - MOJOSHADER_effect *effectData = ((VulkanEffect *) effect)->effect; - MOJOSHADER_effectEndPass(effectData); - MOJOSHADER_effectEnd(effectData); -} - -/* Queries */ - -static FNA3D_Query* VULKAN_CreateQuery(FNA3D_Renderer *driverData) -{ - VulkanRenderer *renderer = (VulkanRenderer *) driverData; - VulkanQuery *query = (VulkanQuery*) SDL_malloc(sizeof(VulkanQuery)); - - if (renderer->freeQueryIndexStackHead == -1) - { - FNA3D_LogError( - "Query limit of %d has been exceeded!", - MAX_QUERIES - ); - return NULL; - } - - query->index = renderer->freeQueryIndexStackHead; - renderer->freeQueryIndexStackHead = renderer->freeQueryIndexStack[renderer->freeQueryIndexStackHead]; - return (FNA3D_Query *) query; -} - -static void VULKAN_AddDisposeQuery( - FNA3D_Renderer *driverData, - FNA3D_Query *query -) { - VulkanRenderer *renderer = (VulkanRenderer*) driverData; - VulkanQuery *vulkanQuery = (VulkanQuery*) query; - - /* Push the now-free index to the stack */ - SDL_LockMutex(renderer->disposeLock); - renderer->freeQueryIndexStack[vulkanQuery->index] = - renderer->freeQueryIndexStackHead; - renderer->freeQueryIndexStackHead = vulkanQuery->index; - SDL_UnlockMutex(renderer->disposeLock); - - SDL_free(vulkanQuery); -} - -static void VULKAN_QueryBegin(FNA3D_Renderer *driverData, FNA3D_Query *query) -{ - VulkanRenderer *renderer = (VulkanRenderer*) driverData; - VulkanQuery *vulkanQuery = (VulkanQuery*) query; - VulkanCommandBuffer *commandBuffer; - - /* Need to do this between passes */ - VULKAN_INTERNAL_MaybeEndRenderPass(renderer); - - commandBuffer = (VulkanCommandBuffer*) FNA3D_CommandBuffer_GetCurrent( - renderer->commandBuffers - ); - - RECORD_CMD(renderer->vkCmdResetQueryPool( - commandBuffer->commandBuffer, - renderer->queryPool, - vulkanQuery->index, - 1 - )); - - RECORD_CMD(renderer->vkCmdBeginQuery( - commandBuffer->commandBuffer, - renderer->queryPool, - vulkanQuery->index, - renderer->supportsPreciseOcclusionQueries ? - VK_QUERY_CONTROL_PRECISE_BIT : - 0 - )); -} - -static void VULKAN_QueryEnd(FNA3D_Renderer *driverData, FNA3D_Query *query) -{ - VulkanRenderer *renderer = (VulkanRenderer*) driverData; - VulkanQuery *vulkanQuery = (VulkanQuery*) query; - VulkanCommandBuffer *commandBuffer; - - /* Assume that the user is calling this in - * the same pass as they started it - */ - - commandBuffer = (VulkanCommandBuffer*) FNA3D_CommandBuffer_GetCurrent( - renderer->commandBuffers - ); - RECORD_CMD(renderer->vkCmdEndQuery( - commandBuffer->commandBuffer, - renderer->queryPool, - vulkanQuery->index - )); -} - -static uint8_t VULKAN_QueryComplete( - FNA3D_Renderer *driverData, - FNA3D_Query *query -) { - VulkanRenderer *renderer = (VulkanRenderer*) driverData; - VulkanQuery *vulkanQuery = (VulkanQuery*) query; - VkResult vulkanResult; - uint32_t queryResult; - - vulkanResult = renderer->vkGetQueryPoolResults( - renderer->logicalDevice, - renderer->queryPool, - vulkanQuery->index, - 1, - sizeof(queryResult), - &queryResult, - 0, - 0 - ); - - return vulkanResult == VK_SUCCESS; -} - -static int32_t VULKAN_QueryPixelCount( - FNA3D_Renderer *driverData, - FNA3D_Query *query -) { - VulkanRenderer *renderer = (VulkanRenderer*) driverData; - VulkanQuery *vulkanQuery = (VulkanQuery*) query; - VkResult vulkanResult; - uint32_t queryResult; - - vulkanResult = renderer->vkGetQueryPoolResults( - renderer->logicalDevice, - renderer->queryPool, - vulkanQuery->index, - 1, - sizeof(queryResult), - &queryResult, - 0, - 0 - ); - VULKAN_ERROR_CHECK(vulkanResult, vkGetQueryPoolResults, 0) - - /* FIXME maybe signed/unsigned integer problems? */ - return queryResult; -} - -/* Feature Queries */ - -static uint8_t VULKAN_SupportsDXT1(FNA3D_Renderer *driverData) -{ - VulkanRenderer *renderer = (VulkanRenderer*) driverData; - return renderer->supportsDxt1; -} - -static uint8_t VULKAN_SupportsS3TC(FNA3D_Renderer *driverData) -{ - VulkanRenderer *renderer = (VulkanRenderer*) driverData; - return renderer->supportsS3tc; -} - -static uint8_t VULKAN_SupportsBC7(FNA3D_Renderer *driverData) -{ - VulkanRenderer *renderer = (VulkanRenderer*) driverData; - return renderer->supportsBc7; -} - -static uint8_t VULKAN_SupportsHardwareInstancing(FNA3D_Renderer *driverData) -{ - VulkanRenderer *renderer = (VulkanRenderer*) driverData; - return renderer->supports.EXT_vertex_attribute_divisor; -} - -static uint8_t VULKAN_SupportsNoOverwrite(FNA3D_Renderer *driverData) -{ - return 1; -} - -static uint8_t VULKAN_SupportsSRGBRenderTargets(FNA3D_Renderer *driverData) -{ - VulkanRenderer *renderer = (VulkanRenderer*) driverData; - return renderer->supportsSRGBRenderTarget; -} - -static void VULKAN_GetMaxTextureSlots( - FNA3D_Renderer *driverData, - int32_t *textures, - int32_t *vertexTextures -) { - VulkanRenderer *renderer = (VulkanRenderer*) driverData; - *textures = renderer->numTextureSlots; - *vertexTextures = renderer->numVertexTextureSlots; -} - -static int32_t VULKAN_GetMaxMultiSampleCount( - FNA3D_Renderer *driverData, - FNA3D_SurfaceFormat format, - int32_t multiSampleCount -) { - VulkanRenderer *renderer = (VulkanRenderer*) driverData; - VkSampleCountFlags flags = renderer->physicalDeviceProperties.properties.limits.framebufferColorSampleCounts; - int32_t maxSupported = 1; - - if (flags & VK_SAMPLE_COUNT_64_BIT) - { - maxSupported = 64; - } - else if (flags & VK_SAMPLE_COUNT_32_BIT) - { - maxSupported = 32; - } - else if (flags & VK_SAMPLE_COUNT_16_BIT) - { - maxSupported = 16; - } - else if (flags & VK_SAMPLE_COUNT_8_BIT) - { - maxSupported = 8; - } - else if (flags & VK_SAMPLE_COUNT_4_BIT) - { - maxSupported = 4; - } - else if (flags & VK_SAMPLE_COUNT_2_BIT) - { - maxSupported = 2; - } - - return SDL_min(multiSampleCount, maxSupported); -} - -/* Debugging */ - -static void VULKAN_SetStringMarker(FNA3D_Renderer *driverData, const char *text) -{ - VulkanRenderer *renderer = (VulkanRenderer*) driverData; - VulkanCommandBuffer *commandBuffer; - VkDebugUtilsLabelEXT labelInfo; - - if (renderer->supportsDebugUtils) - { - labelInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT; - labelInfo.pNext = NULL; - labelInfo.pLabelName = text; - - commandBuffer = (VulkanCommandBuffer*) FNA3D_CommandBuffer_GetCurrent( - renderer->commandBuffers - ); - RECORD_CMD(renderer->vkCmdInsertDebugUtilsLabelEXT( - commandBuffer->commandBuffer, - &labelInfo - )); - } -} - -static void VULKAN_SetTextureName(FNA3D_Renderer* driverData, FNA3D_Texture* texture, const char* text) -{ - VulkanRenderer* renderer = (VulkanRenderer*)driverData; - VulkanTexture* vkTexture = (VulkanTexture*)texture; - VkDebugUtilsObjectNameInfoEXT nameInfo; - - if (renderer->supportsDebugUtils) - { - nameInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT; - nameInfo.pNext = NULL; - nameInfo.pObjectName = text; - nameInfo.objectType = VK_OBJECT_TYPE_IMAGE; - nameInfo.objectHandle = (uint64_t) vkTexture->image; - - renderer->vkSetDebugUtilsObjectNameEXT( - renderer->logicalDevice, - &nameInfo - ); - } -} - -/* External Interop */ - -static void VULKAN_GetSysRenderer( - FNA3D_Renderer *driverData, - FNA3D_SysRendererEXT *sysrenderer -) { - VulkanRenderer* renderer = (VulkanRenderer*) driverData; - - sysrenderer->rendererType = FNA3D_RENDERER_TYPE_VULKAN_EXT; - sysrenderer->renderer.vulkan.instance = renderer->instance; - sysrenderer->renderer.vulkan.physicalDevice = renderer->physicalDevice; - sysrenderer->renderer.vulkan.logicalDevice = renderer->logicalDevice; - sysrenderer->renderer.vulkan.queueFamilyIndex = renderer->queueFamilyIndex; -} - -static FNA3D_Texture* VULKAN_CreateSysTexture( - FNA3D_Renderer *driverData, - FNA3D_SysTextureEXT *systexture -) { - VulkanTexture *texture; - - if (systexture->rendererType != FNA3D_RENDERER_TYPE_VULKAN_EXT) - { - return NULL; - } - - texture = (VulkanTexture*) SDL_malloc(sizeof(VulkanTexture)); - - texture->image = (VkImage) systexture->texture.vulkan.image; - texture->view = (VkImageView) systexture->texture.vulkan.view; - texture->external = 1; - - /* unused by external */ - texture->usedRegion = NULL; - texture->colorFormat = 0; - texture->depth = 0; - texture->depthStencilFormat = 0; - texture->dimensions.width = 0; - texture->dimensions.height = 0; - texture->layerCount = 0; - texture->levelCount = 0; - texture->resourceAccessType = RESOURCE_ACCESS_NONE; - texture->rtViews[0] = VK_NULL_HANDLE; - texture->rtViews[1] = VK_NULL_HANDLE; - texture->rtViews[2] = VK_NULL_HANDLE; - texture->rtViews[3] = VK_NULL_HANDLE; - texture->rtViews[4] = VK_NULL_HANDLE; - texture->rtViews[5] = VK_NULL_HANDLE; - texture->surfaceFormat = 0; - - return (FNA3D_Texture*) texture; -} - -/* Memory Driver */ - -static uint8_t VULKAN_Memory_AllocDeviceMemory( - FNA3D_Renderer *driverData, - size_t subAllocatorIndex, - size_t memorySize, - uint8_t deviceLocal, - uint8_t hostVisible, - FNA3D_MemoryPlatformHandle* driverMemory, - uint8_t** mapPointer -) { - VulkanRenderer *renderer = (VulkanRenderer*) driverData; - VkMemoryAllocateInfo allocInfo; - VkResult result; - - if ( deviceLocal && - (renderer->deviceLocalHeapUsage + memorySize > renderer->maxDeviceLocalHeapUsage) ) - { - /* we are oversubscribing device local memory */ - return 0; - } - - allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; - allocInfo.pNext = NULL; - allocInfo.memoryTypeIndex = subAllocatorIndex; - allocInfo.allocationSize = memorySize; - - result = renderer->vkAllocateMemory( - renderer->logicalDevice, - &allocInfo, - NULL, - (VkDeviceMemory*) driverMemory /* FIXME: This should be a struct... */ - ); - - if (result != VK_SUCCESS) - { - FNA3D_LogWarn("vkAllocateMemory: %s", VkErrorMessages(result)); - return 0; - } - - /* Tracking device-local usage, mostly for debugging purposes */ - if (deviceLocal) - { - renderer->deviceLocalHeapUsage += memorySize; - } - - /* Persistent mapping for host memory */ - if (hostVisible) - { - result = renderer->vkMapMemory( - renderer->logicalDevice, - (VkDeviceMemory) *driverMemory, - 0, - VK_WHOLE_SIZE, - 0, - (void**) mapPointer - ); - VULKAN_ERROR_CHECK(result, vkMapMemory, 0) - } - else - { - *mapPointer = NULL; - } - - return 1; -} - -static void VULKAN_Memory_FreeDeviceMemory( - FNA3D_Renderer *driverData, - FNA3D_MemoryPlatformHandle driverMemory, - size_t memorySize, - size_t subAllocatorIndex -) { - VulkanRenderer *renderer = (VulkanRenderer*) driverData; - uint8_t isDeviceLocal = - (renderer->memoryProperties.memoryTypes[subAllocatorIndex].propertyFlags & - VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) != 0; - - renderer->vkFreeMemory( - renderer->logicalDevice, - (VkDeviceMemory) driverMemory, /* FIXME: This should be a struct... */ - NULL - ); - - if (isDeviceLocal) - { - renderer->deviceLocalHeapUsage -= memorySize; - } -} - -static uint8_t VULKAN_Memory_BindBufferMemory( - FNA3D_Renderer *driverData, - FNA3D_MemoryPlatformHandle deviceMemory, - size_t alignedOffset, - FNA3D_MemoryPlatformHandle buffer -) { - VulkanRenderer *renderer = (VulkanRenderer*) driverData; - VkResult vulkanResult = renderer->vkBindBufferMemory( - renderer->logicalDevice, - (VkBuffer) buffer, - (VkDeviceMemory) deviceMemory, /* FIXME: This should be a struct... */ - alignedOffset - ); - VULKAN_ERROR_CHECK(vulkanResult, vkBindBufferMemory, 0) - return 1; -} - -static uint8_t VULKAN_Memory_BindImageMemory( - FNA3D_Renderer *driverData, - FNA3D_MemoryPlatformHandle deviceMemory, - size_t alignedOffset, - FNA3D_MemoryPlatformHandle image -) { - VulkanRenderer *renderer = (VulkanRenderer*) driverData; - VkResult vulkanResult = renderer->vkBindImageMemory( - renderer->logicalDevice, - (VkImage) image, - (VkDeviceMemory) deviceMemory, /* FIXME: This should be a struct... */ - alignedOffset - ); - VULKAN_ERROR_CHECK(vulkanResult, vkBindBufferMemory, 0) - return 1; -} - -static void VULKAN_Memory_BeginDefragCommands(FNA3D_Renderer *driverData) -{ - VulkanRenderer *renderer = (VulkanRenderer*) driverData; - VulkanCommandBuffer *commandBuffer; - VkCommandBufferBeginInfo beginInfo; - - FNA3D_CommandBuffer_LockForDefrag(renderer->commandBuffers); - - beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - beginInfo.pNext = NULL; - beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; - beginInfo.pInheritanceInfo = NULL; - - commandBuffer = (VulkanCommandBuffer*) FNA3D_CommandBuffer_GetDefragBuffer( - renderer->commandBuffers - ); - renderer->vkBeginCommandBuffer( - commandBuffer->commandBuffer, - &beginInfo - ); - - renderer->needDefrag = 0; -} - -static void VULKAN_Memory_EndDefragCommands(FNA3D_Renderer *driverData) -{ - VulkanRenderer *renderer = (VulkanRenderer*) driverData; - VulkanCommandBuffer *commandBuffer; - VkPipelineStageFlags waitFlags = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT; - VkSubmitInfo submitInfo; - VkResult result; - - commandBuffer = (VulkanCommandBuffer*) FNA3D_CommandBuffer_GetDefragBuffer( - renderer->commandBuffers - ); - - renderer->vkEndCommandBuffer( - commandBuffer->commandBuffer - ); - - submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - submitInfo.pNext = NULL; - submitInfo.commandBufferCount = 1; - submitInfo.pCommandBuffers = &commandBuffer->commandBuffer; - submitInfo.waitSemaphoreCount = 1; - submitInfo.pWaitSemaphores = &renderer->defragSemaphore; - submitInfo.pWaitDstStageMask = &waitFlags; - submitInfo.signalSemaphoreCount = 0; - submitInfo.pSignalSemaphores = NULL; - - result = renderer->vkResetFences( - renderer->logicalDevice, - 1, - &commandBuffer->inFlightFence - ); - if (result != VK_SUCCESS) - { - FNA3D_LogError("vkResetFences: %s", VkErrorMessages(result)); - return; - } - - result = renderer->vkQueueSubmit( - renderer->unifiedQueue, - 1, - &submitInfo, - commandBuffer->inFlightFence - ); - if (result != VK_SUCCESS) - { - FNA3D_LogError("vkQueueSubmit: %s", VkErrorMessages(result)); - return; - } - - renderer->defragTimer = 0; - - FNA3D_CommandBuffer_UnlockFromDefrag(renderer->commandBuffers); -} - -static uint8_t VULKAN_Memory_DefragBuffer( - FNA3D_Renderer *driverData, - void* resource, - size_t resourceSize -) { - VulkanRenderer *renderer = (VulkanRenderer*) driverData; - VulkanBuffer *vulkanBuffer = (VulkanBuffer*) resource; - VulkanCommandBuffer *commandBuffer; - VulkanResourceAccessType originalResourceAccessType; - VulkanResourceAccessType copyResourceAccessType = RESOURCE_ACCESS_NONE; - FNA3D_MemoryUsedRegion *newRegion; - VkBufferCopy bufferCopy; - VkBuffer copyBuffer; - VkResult result; - - vulkanBuffer->bufferCreateInfo.usage |= VK_BUFFER_USAGE_TRANSFER_DST_BIT; - - result = renderer->vkCreateBuffer( - renderer->logicalDevice, - &vulkanBuffer->bufferCreateInfo, - NULL, - ©Buffer - ); - VULKAN_ERROR_CHECK(result, vkCreateBuffer, 0) - - if ( - VULKAN_INTERNAL_BindMemoryForBuffer( - renderer, - copyBuffer, - vulkanBuffer, - resourceSize, - vulkanBuffer->preferDeviceLocal, - 0, - &newRegion - ) != 1) - { - /* Out of memory, abort */ - renderer->vkDestroyBuffer( - renderer->logicalDevice, - copyBuffer, - NULL - ); - return 0; - } - - originalResourceAccessType = vulkanBuffer->resourceAccessType; - - VULKAN_INTERNAL_BufferMemoryBarrier( - renderer, - RESOURCE_ACCESS_TRANSFER_READ, - vulkanBuffer->buffer, - &vulkanBuffer->resourceAccessType - ); - - VULKAN_INTERNAL_BufferMemoryBarrier( - renderer, - RESOURCE_ACCESS_TRANSFER_WRITE, - copyBuffer, - ©ResourceAccessType - ); - - bufferCopy.srcOffset = 0; - bufferCopy.dstOffset = 0; - bufferCopy.size = resourceSize; - - commandBuffer = (VulkanCommandBuffer*) FNA3D_CommandBuffer_GetDefragBuffer( - renderer->commandBuffers - ); - - renderer->vkCmdCopyBuffer( - commandBuffer->commandBuffer, - vulkanBuffer->buffer, - copyBuffer, - 1, - &bufferCopy - ); - - VULKAN_INTERNAL_BufferMemoryBarrier( - renderer, - originalResourceAccessType, - copyBuffer, - ©ResourceAccessType - ); - - if (renderer->defragmentedBuffersToDestroyCount >= renderer->defragmentedBuffersToDestroyCapacity) - { - renderer->defragmentedBuffersToDestroyCapacity *= 2; - renderer->defragmentedBuffersToDestroy = SDL_realloc( - renderer->defragmentedBuffersToDestroy, - sizeof(VkBuffer) * renderer->defragmentedBuffersToDestroyCapacity - ); - } - - renderer->defragmentedBuffersToDestroy[ - renderer->defragmentedBuffersToDestroyCount - ] = vulkanBuffer->buffer; - - renderer->defragmentedBuffersToDestroyCount += 1; - - vulkanBuffer->usedRegion = newRegion; /* lol */ - vulkanBuffer->buffer = copyBuffer; - vulkanBuffer->resourceAccessType = copyResourceAccessType; - - /* Binding prevents data race when using SetBufferData with Discard option */ - FNA3D_CommandBuffer_MarkBufferAsBound( - renderer->commandBuffers, - (FNA3D_BufferHandle*) vulkanBuffer - ); - - renderer->needDefrag = 1; - renderer->bufferDefragInProgress = 1; - - return 1; -} - -static uint8_t VULKAN_Memory_DefragImage( - FNA3D_Renderer *driverData, - void* resource, - size_t resourceSize -) { - VulkanRenderer *renderer = (VulkanRenderer*) driverData; - VulkanTexture *vulkanTexture = (VulkanTexture*) resource; - VulkanCommandBuffer *commandBuffer; - VulkanResourceAccessType originalResourceAccessType; - VulkanResourceAccessType copyResourceAccessType = RESOURCE_ACCESS_NONE; - FNA3D_MemoryUsedRegion *newRegion; - VkImageAspectFlags aspectFlags; - VkImageCopy *imageCopyRegions; - VkImage copyImage; - VkResult result; - uint32_t level; - - result = renderer->vkCreateImage( - renderer->logicalDevice, - &vulkanTexture->imageCreateInfo, - NULL, - ©Image - ); - - VULKAN_ERROR_CHECK(result, vkCreateImage, 0) - - if (VULKAN_INTERNAL_BindMemoryForImage( - renderer, - copyImage, - vulkanTexture, - 0, - &newRegion - ) != 1) - { - /* Out of memory, abort */ - renderer->vkDestroyImage( - renderer->logicalDevice, - copyImage, - NULL - ); - - return 0; - } - - if (IsDepthFormat(vulkanTexture->surfaceFormat)) - { - aspectFlags = VK_IMAGE_ASPECT_DEPTH_BIT; - - if (DepthFormatContainsStencil(vulkanTexture->surfaceFormat)) - { - aspectFlags |= VK_IMAGE_ASPECT_STENCIL_BIT; - } - } - else - { - aspectFlags = VK_IMAGE_ASPECT_COLOR_BIT; - } - - originalResourceAccessType = vulkanTexture->resourceAccessType; - - VULKAN_INTERNAL_ImageMemoryBarrier( - renderer, - RESOURCE_ACCESS_TRANSFER_READ, - aspectFlags, - 0, - vulkanTexture->layerCount, - 0, - vulkanTexture->levelCount, - 0, - vulkanTexture->image, - &vulkanTexture->resourceAccessType - ); - - VULKAN_INTERNAL_ImageMemoryBarrier( - renderer, - RESOURCE_ACCESS_TRANSFER_WRITE, - aspectFlags, - 0, - vulkanTexture->layerCount, - 0, - vulkanTexture->levelCount, - 0, - copyImage, - ©ResourceAccessType - ); - - imageCopyRegions = SDL_stack_alloc(VkImageCopy, vulkanTexture->levelCount); - - for (level = 0; level < vulkanTexture->levelCount; level += 1) - { - imageCopyRegions[level].srcOffset.x = 0; - imageCopyRegions[level].srcOffset.y = 0; - imageCopyRegions[level].srcOffset.z = 0; - imageCopyRegions[level].srcSubresource.aspectMask = aspectFlags; - imageCopyRegions[level].srcSubresource.baseArrayLayer = 0; - imageCopyRegions[level].srcSubresource.layerCount = vulkanTexture->layerCount; - imageCopyRegions[level].srcSubresource.mipLevel = level; - imageCopyRegions[level].extent.width = SDL_max(1, vulkanTexture->dimensions.width >> level); - imageCopyRegions[level].extent.height = SDL_max(1, vulkanTexture->dimensions.height >> level); - imageCopyRegions[level].extent.depth = vulkanTexture->depth; - imageCopyRegions[level].dstOffset.x = 0; - imageCopyRegions[level].dstOffset.y = 0; - imageCopyRegions[level].dstOffset.z = 0; - imageCopyRegions[level].dstSubresource.aspectMask = aspectFlags; - imageCopyRegions[level].dstSubresource.baseArrayLayer = 0; - imageCopyRegions[level].dstSubresource.layerCount = vulkanTexture->layerCount; - imageCopyRegions[level].dstSubresource.mipLevel = level; - } - - commandBuffer = (VulkanCommandBuffer*) FNA3D_CommandBuffer_GetDefragBuffer( - renderer->commandBuffers - ); - renderer->vkCmdCopyImage( - commandBuffer->commandBuffer, - vulkanTexture->image, - AccessMap[vulkanTexture->resourceAccessType].imageLayout, - copyImage, - AccessMap[copyResourceAccessType].imageLayout, - vulkanTexture->levelCount, - imageCopyRegions - ); - - VULKAN_INTERNAL_ImageMemoryBarrier( - renderer, - originalResourceAccessType, - aspectFlags, - 0, - vulkanTexture->layerCount, - 0, - vulkanTexture->levelCount, - 0, - copyImage, - ©ResourceAccessType - ); - - SDL_stack_free(imageCopyRegions); - - if (renderer->defragmentedImagesToDestroyCount >= renderer->defragmentedImagesToDestroyCapacity) - { - renderer->defragmentedImagesToDestroyCapacity *= 2; - renderer->defragmentedImagesToDestroy = SDL_realloc( - renderer->defragmentedImagesToDestroy, - sizeof(VkImage) * renderer->defragmentedImagesToDestroyCapacity - ); - } - - if (renderer->defragmentedImageViewsToDestroyCount >= renderer->defragmentedImageViewsToDestroyCapacity) - { - renderer->defragmentedImageViewsToDestroyCapacity *= 2; - renderer->defragmentedImageViewsToDestroy = SDL_realloc( - renderer->defragmentedImageViewsToDestroy, - sizeof(VkImageView) * renderer->defragmentedImageViewsToDestroyCapacity - ); - } - - renderer->defragmentedImagesToDestroy[ - renderer->defragmentedImagesToDestroyCount - ] = vulkanTexture->image; - - renderer->defragmentedImagesToDestroyCount += 1; - - renderer->defragmentedImageViewsToDestroy[ - renderer->defragmentedImageViewsToDestroyCount - ] = vulkanTexture->view; - - renderer->defragmentedImageViewsToDestroyCount += 1; - - vulkanTexture->viewCreateInfo.image = copyImage; - - renderer->vkCreateImageView( - renderer->logicalDevice, - &vulkanTexture->viewCreateInfo, - NULL, - &vulkanTexture->view - ); - - vulkanTexture->usedRegion = newRegion; /* lol */ - vulkanTexture->image = copyImage; - vulkanTexture->resourceAccessType = copyResourceAccessType; - - renderer->needDefrag = 1; - - return 1; -} - -static FNA3D_BufferHandle* VULKAN_Memory_CreateBufferHandle( - FNA3D_Renderer *driverData, - uint8_t isVertexData, - size_t sizeInBytes -) { - return (FNA3D_BufferHandle*) VULKAN_INTERNAL_CreateBuffer( - (VulkanRenderer*) driverData, - sizeInBytes, - isVertexData ? - RESOURCE_ACCESS_VERTEX_BUFFER : - RESOURCE_ACCESS_INDEX_BUFFER, - isVertexData ? - VK_BUFFER_USAGE_VERTEX_BUFFER_BIT : - VK_BUFFER_USAGE_INDEX_BUFFER_BIT, - 0, - 0 - ); -} - -static FNA3D_BufferHandle* VULKAN_Memory_CloneBufferHandle( - FNA3D_Renderer *driverData, - FNA3D_BufferHandle *buffer -) { - VulkanRenderer *renderer = (VulkanRenderer*) driverData; - VulkanBuffer *vulkanBuffer = (VulkanBuffer*) buffer; - VulkanBuffer *result = VULKAN_INTERNAL_CreateBuffer( - renderer, - vulkanBuffer->size, - vulkanBuffer->resourceAccessType, - vulkanBuffer->usage, - vulkanBuffer->preferDeviceLocal, - vulkanBuffer->isTransferBuffer - ); - if (result != NULL) - { - VULKAN_INTERNAL_BufferMemoryBarrier( - renderer, - result->resourceAccessType, - result->buffer, - &result->resourceAccessType - ); - } - - return (FNA3D_BufferHandle*) result; -} - -static void VULKAN_Memory_MarkBufferHandlesForDestroy( - FNA3D_Renderer *driverData, - FNA3D_BufferHandle **buffers, - size_t bufferCount -) { - VulkanRenderer *renderer = (VulkanRenderer*) driverData; - - FNA3D_CommandBuffer_AddDisposeBuffers( - renderer->commandBuffers, - buffers, - bufferCount - ); -} - -static uint8_t VULKAN_Memory_BufferHandleInUse( - FNA3D_Renderer *driverData, - FNA3D_BufferHandle *buffer -) { - VulkanBuffer *vulkanBuffer = (VulkanBuffer*) buffer; - return SDL_GetAtomicInt(&vulkanBuffer->refcount) > 0; -} - -/* Command Buffer Driver */ - -static FNA3D_CommandBuffer* VULKAN_CommandBuffer_AllocCommandBuffer( - FNA3D_Renderer *driverData, - uint8_t fenceSignaled -) { - VkCommandBufferAllocateInfo allocateInfo; - VkFenceCreateInfo fenceCreateInfo; - VkResult vulkanResult; - VulkanRenderer *renderer = (VulkanRenderer*) driverData; - VulkanCommandBuffer *commandBuffer = (VulkanCommandBuffer*) SDL_malloc( - sizeof(VulkanCommandBuffer) - ); - - allocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; - allocateInfo.pNext = NULL; - allocateInfo.commandPool = renderer->commandPool; - allocateInfo.commandBufferCount = 1; - allocateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; - - vulkanResult = renderer->vkAllocateCommandBuffers( - renderer->logicalDevice, - &allocateInfo, - &commandBuffer->commandBuffer - ); - VULKAN_ERROR_CHECK(vulkanResult, vkAllocateCommandBuffers, NULL) - - fenceCreateInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; - fenceCreateInfo.pNext = NULL; - fenceCreateInfo.flags = fenceSignaled ? VK_FENCE_CREATE_SIGNALED_BIT : 0; - - renderer->vkCreateFence( - renderer->logicalDevice, - &fenceCreateInfo, - NULL, - &commandBuffer->inFlightFence - ); - - /* Descriptor set tracking */ - - commandBuffer->usedDescriptorSetDataCapacity = 16; - commandBuffer->usedDescriptorSetDataCount = 0; - commandBuffer->usedDescriptorSetDatas = SDL_malloc( - commandBuffer->usedDescriptorSetDataCapacity * sizeof(DescriptorSetData) - ); - - return (FNA3D_CommandBuffer*) commandBuffer; -} - -static void VULKAN_CommandBuffer_FreeCommandBuffer( - FNA3D_Renderer *driverData, - FNA3D_CommandBuffer *handle -) { - VulkanRenderer *renderer = (VulkanRenderer*) driverData; - VulkanCommandBuffer *commandBuffer = (VulkanCommandBuffer*) handle; - - renderer->vkDestroyFence( - renderer->logicalDevice, - commandBuffer->inFlightFence, - NULL - ); - SDL_free(commandBuffer->usedDescriptorSetDatas); - SDL_free(commandBuffer); -} - -static void VULKAN_CommandBuffer_BeginRecording( - FNA3D_Renderer *driverData, - FNA3D_CommandBuffer *handle -) { - VulkanRenderer *renderer = (VulkanRenderer*) driverData; - VulkanCommandBuffer *commandBuffer = (VulkanCommandBuffer*) handle; - VkCommandBufferBeginInfo beginInfo; - VkResult result; - - beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - beginInfo.pNext = NULL; - beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; - beginInfo.pInheritanceInfo = NULL; - - result = renderer->vkBeginCommandBuffer( - commandBuffer->commandBuffer, - &beginInfo - ); - - VULKAN_ERROR_CHECK(result, vkBeginCommandBuffer,) -} - -static void VULKAN_CommandBuffer_EndRecording( - FNA3D_Renderer *driverData, - FNA3D_CommandBuffer *handle -) { - VulkanRenderer *renderer = (VulkanRenderer*) driverData; - VulkanCommandBuffer *commandBuffer = (VulkanCommandBuffer*) handle; - VkResult result = renderer->vkEndCommandBuffer( - commandBuffer->commandBuffer - ); - VULKAN_ERROR_CHECK(result, vkEndCommandBuffer,) -} - -static void VULKAN_CommandBuffer_Reset( - FNA3D_Renderer *driverData, - FNA3D_CommandBuffer *handle -) { - VulkanRenderer *renderer = (VulkanRenderer*) driverData; - VulkanCommandBuffer *commandBuffer = (VulkanCommandBuffer*) handle; - DescriptorSetData *descriptorSetData; - uint32_t i; - - /* Mark used descriptor sets as inactive */ - for (i = 0; i < commandBuffer->usedDescriptorSetDataCount; i += 1) - { - descriptorSetData = &commandBuffer->usedDescriptorSetDatas[i]; - - if (descriptorSetData->descriptorSet != VK_NULL_HANDLE) - { - descriptorSetData->parent->inactiveDescriptorSets[descriptorSetData->parent->inactiveDescriptorSetCount] = descriptorSetData->descriptorSet; - descriptorSetData->parent->inactiveDescriptorSetCount += 1; - } - } - commandBuffer->usedDescriptorSetDataCount = 0; - - /* Reset the command buffer */ - renderer->vkResetCommandBuffer( - commandBuffer->commandBuffer, - VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT - ); -} - -static uint8_t VULKAN_CommandBuffer_QueryFence( - FNA3D_Renderer *driverData, - FNA3D_CommandBuffer *handle -) { - VulkanRenderer *renderer = (VulkanRenderer*) driverData; - VulkanCommandBuffer *commandBuffer = (VulkanCommandBuffer*) handle; - - /* If we set a timeout of 0, we can query the command buffer state */ - return renderer->vkWaitForFences( - renderer->logicalDevice, - 1, - &commandBuffer->inFlightFence, - VK_TRUE, - 0 - ) == VK_SUCCESS; -} - -static void VULKAN_CommandBuffer_WaitForFences( - FNA3D_Renderer *driverData, - FNA3D_CommandBuffer **handles, - size_t handleCount -) { - VulkanRenderer *renderer = (VulkanRenderer*) driverData; - VulkanCommandBuffer **commandBuffers = (VulkanCommandBuffer**) handles; - VkFence *fences; - uint32_t i; - - fences = SDL_stack_alloc(VkFence, handleCount); - for (i = 0; i < handleCount; i += 1) - { - fences[i] = commandBuffers[i]->inFlightFence; - } - - renderer->vkWaitForFences( - renderer->logicalDevice, - handleCount, - fences, - VK_TRUE, - UINT64_MAX - ); - - SDL_stack_free(fences); -} - -static FNA3D_BufferHandle* VULKAN_CommandBuffer_CreateTransferBuffer( - FNA3D_Renderer *driverData, - size_t size, - uint8_t preferDeviceLocal -) { - return (FNA3D_BufferHandle*) VULKAN_INTERNAL_CreateBuffer( - (VulkanRenderer*) driverData, - size, - RESOURCE_ACCESS_MEMORY_TRANSFER_READ_WRITE, - VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, - preferDeviceLocal, - 1 - ); -} - -static void VULKAN_CommandBuffer_IncBufferRef( - FNA3D_Renderer *driverData, - FNA3D_BufferHandle *handle -) { - VulkanBuffer *vulkanBuffer = (VulkanBuffer*) handle; - SDL_AtomicIncRef(&vulkanBuffer->refcount); -} - -static void VULKAN_CommandBuffer_DecBufferRef( - FNA3D_Renderer *driverData, - FNA3D_BufferHandle *handle -) { - VulkanBuffer *vulkanBuffer = (VulkanBuffer*) handle; - SDL_AtomicDecRef(&vulkanBuffer->refcount); -} - -static size_t VULKAN_CommandBuffer_GetBufferSize( - FNA3D_Renderer *driverData, - FNA3D_BufferHandle *handle -) { - VulkanBuffer *vulkanBuffer = (VulkanBuffer*) handle; - return vulkanBuffer->size; -} - -static void VULKAN_CommandBuffer_DestroyTexture( - FNA3D_Renderer *driverData, - FNA3D_Texture *texture -) { - VULKAN_INTERNAL_DestroyTexture( - (VulkanRenderer*) driverData, - (VulkanTexture*) texture - ); -} - -static void VULKAN_CommandBuffer_DestroyBuffer( - FNA3D_Renderer *driverData, - FNA3D_BufferHandle *buffer -) { - VULKAN_INTERNAL_DestroyBuffer( - (VulkanRenderer*) driverData, - (VulkanBuffer*) buffer - ); -} - -static void VULKAN_CommandBuffer_DestroyRenderbuffer( - FNA3D_Renderer *driverData, - FNA3D_Renderbuffer *renderbuffer -) { - VulkanRenderer *renderer = (VulkanRenderer*) driverData; - VulkanRenderbuffer *vkRenderbuffer = (VulkanRenderbuffer*) renderbuffer; - uint8_t isDepthStencil = (vkRenderbuffer->colorBuffer == NULL); - - if (isDepthStencil) - { - VULKAN_INTERNAL_DestroyTexture( - renderer, - vkRenderbuffer->depthBuffer->handle - ); - SDL_free(vkRenderbuffer->depthBuffer); - } - else - { - if (vkRenderbuffer->colorBuffer->multiSampleTexture != NULL) - { - VULKAN_INTERNAL_DestroyTexture( - renderer, - vkRenderbuffer->colorBuffer->multiSampleTexture - ); - } - - /* The image is owned by the texture it's from, - * so we don't free it here. - */ - SDL_free(vkRenderbuffer->colorBuffer); - } - - SDL_free(vkRenderbuffer); -} - -static void VULKAN_CommandBuffer_DestroyEffect( - FNA3D_Renderer *driverData, - FNA3D_Effect *effect -) { - VulkanRenderer *renderer = (VulkanRenderer*) driverData; - VulkanEffect *vulkanEffect = (VulkanEffect*) effect; - MOJOSHADER_effect *effectData = vulkanEffect->effect; - - if (effectData == renderer->currentEffect) - { - MOJOSHADER_effectEndPass(renderer->currentEffect); - MOJOSHADER_effectEnd(renderer->currentEffect); - renderer->currentEffect = NULL; - renderer->currentTechnique = NULL; - renderer->currentPass = 0; - } - MOJOSHADER_deleteEffect(effectData); - SDL_free(vulkanEffect); -} - -/* Driver */ - -static uint8_t VULKAN_PrepareWindowAttributes(uint32_t *flags) -{ - SDL_Window *dummyWindowHandle; - VkSurfaceKHR surface; - FNA3D_PresentationParameters presentationParameters; - VulkanRenderer *renderer; - uint8_t result; - - /* Required for MoltenVK support */ -#ifdef USE_SDL3 - SDL_setenv_unsafe("MVK_CONFIG_FULL_IMAGE_VIEW_SWIZZLE", "1", 1); - SDL_setenv_unsafe("MVK_CONFIG_SHADER_CONVERSION_FLIP_VERTEX_Y", "0", 1); -#else - SDL_setenv("MVK_CONFIG_FULL_IMAGE_VIEW_SWIZZLE", "1", 1); - SDL_setenv("MVK_CONFIG_SHADER_CONVERSION_FLIP_VERTEX_Y", "0", 1); -#endif - -#ifdef USE_SDL3 - if (!SDL_Vulkan_LoadLibrary(NULL)) -#else - if (SDL_Vulkan_LoadLibrary(NULL) < 0) -#endif - { - FNA3D_LogWarn("Vulkan: SDL_Vulkan_LoadLibrary failed!"); - return 0; - } - -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wpedantic" - vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr) SDL_Vulkan_GetVkGetInstanceProcAddr(); -#pragma GCC diagnostic pop - if (vkGetInstanceProcAddr == NULL) - { - FNA3D_LogWarn( - "SDL_Vulkan_GetVkGetInstanceProcAddr(): %s", - SDL_GetError() - ); - return 0; - } - - #define VULKAN_GLOBAL_FUNCTION(name) \ - name = (PFN_##name) vkGetInstanceProcAddr(VK_NULL_HANDLE, #name); \ - if (name == NULL) \ - { \ - FNA3D_LogWarn("vkGetInstanceProcAddr(VK_NULL_HANDLE, \"" #name "\") failed"); \ - return 0; \ - } - #include "FNA3D_Driver_Vulkan_vkfuncs.h" - - /* Test if we can create a vulkan device */ - - /* Create a dummy window, otherwise we cannot query swapchain support */ - dummyWindowHandle = SDL_CreateWindow( - "FNA3D Vulkan", - 128, 128, - SDL_WINDOW_VULKAN | SDL_WINDOW_HIDDEN - ); - - if (dummyWindowHandle == NULL) - { - FNA3D_LogWarn("Vulkan: Could not create dummy window"); - return 0; - } - - presentationParameters.deviceWindowHandle = dummyWindowHandle; - - /* partially set up VulkanRenderer so we can fall back in case of device non-compliance */ - renderer = (VulkanRenderer*) SDL_malloc(sizeof(VulkanRenderer)); - SDL_memset(renderer, '\0', sizeof(VulkanRenderer)); - - if (!VULKAN_INTERNAL_CreateInstance(renderer, &presentationParameters)) - { - SDL_DestroyWindow(dummyWindowHandle); - SDL_free(renderer); - FNA3D_LogWarn("Vulkan: Could not create Vulkan instance"); - return 0; - } - - if (!SDL_Vulkan_CreateSurface( - (SDL_Window*) presentationParameters.deviceWindowHandle, - renderer->instance, - NULL, /* FIXME: VAllocationCallbacks */ - &surface - )) { - SDL_DestroyWindow(dummyWindowHandle); - SDL_free(renderer); - FNA3D_LogWarn( - "SDL_Vulkan_CreateSurface failed: %s", - SDL_GetError() - ); - return 0; - } - - #define VULKAN_INSTANCE_FUNCTION(name) \ - renderer->name = (PFN_##name) vkGetInstanceProcAddr(renderer->instance, #name); - #include "FNA3D_Driver_Vulkan_vkfuncs.h" - - result = VULKAN_INTERNAL_DeterminePhysicalDevice(renderer, surface); - - renderer->vkDestroySurfaceKHR( - renderer->instance, - surface, - NULL - ); - renderer->vkDestroyInstance(renderer->instance, NULL); - SDL_DestroyWindow(dummyWindowHandle); - SDL_free(renderer); - - if (!result) - { - FNA3D_LogWarn("Vulkan: Failed to determine a suitable physical device"); - } - else - { - *flags = SDL_WINDOW_VULKAN; - } - return result; -} - -static FNA3D_Device* VULKAN_CreateDevice( - FNA3D_PresentationParameters *presentationParameters, - uint8_t debugMode -) { - uint32_t i; - VkResult vulkanResult; - - /* Variables: Create the FNA3D_Device */ - FNA3D_Device *result; - VulkanRenderer *renderer; - - /* Variables: Initialize memory allocator */ - FNA3D_MemoryDriver memoryDriver; - - /* Variables: Choose depth formats */ - VkImageFormatProperties imageFormatProperties; - - /* Variables: Create command pool and command buffer */ - VkCommandPoolCreateInfo commandPoolCreateInfo; - FNA3D_CommandBufferDriver commandBufferDriver; - - /* Variables: Create semaphores */ - VkSemaphoreCreateInfo semaphoreInfo; - - /* Variables: Create pipeline cache */ - VkPipelineCacheCreateInfo pipelineCacheCreateInfo; - const char *pipelineCacheFileName; - size_t pipelineCacheSize; - uint8_t *pipelineCacheBytes; - - /* Variables: Create descriptor set layouts */ - VkDescriptorSetLayoutBinding layoutBinding; - VkDescriptorSetLayoutCreateInfo layoutCreateInfo; - - /* Variables: Check for DXT1/S3TC Support */ - VkFormatProperties formatPropsBC1, formatPropsBC2, formatPropsBC3, formatPropsBC7; - - /* Variables: Check for SRGB Render Target Support */ - VkFormatProperties formatPropsSrgbRT; - - /* Variables: Check for Precise Occlusion Query Support */ - VkPhysicalDeviceFeatures physicalDeviceFeatures; - - /* Variables: Create query pool */ - VkQueryPoolCreateInfo queryPoolCreateInfo; - - /* Variables: Create dummy data */ - VkSamplerCreateInfo samplerCreateInfo; - - /* Variables: Create UBO pool and dummy UBO descriptor sets */ - VkDescriptorPoolSize descriptorPoolSize; - VkDescriptorPoolCreateInfo descriptorPoolInfo; - VkDescriptorSetAllocateInfo descriptorSetAllocateInfo; - VkWriteDescriptorSet writeDescriptorSets[2]; - VkDescriptorBufferInfo bufferInfos[2]; - - /* Variables: Create dummy surface for initialization */ - VkSurfaceKHR surface; - - /* - * Create the FNA3D_Device - */ - - result = (FNA3D_Device*) SDL_malloc(sizeof(FNA3D_Device)); - ASSIGN_DRIVER(VULKAN) - - renderer = (VulkanRenderer*) SDL_malloc(sizeof(VulkanRenderer)); - SDL_memset(renderer, '\0', sizeof(VulkanRenderer)); - renderer->debugMode = debugMode; - renderer->parentDevice = result; - result->driverData = (FNA3D_Renderer*) renderer; - - /* - * Initialize memory allocator - */ - - ASSIGN_MEMORY_DRIVER(VULKAN) - renderer->allocator = FNA3D_CreateMemoryAllocator( - &memoryDriver, - VK_MAX_MEMORY_TYPES - ); - - /* - * Create the vkInstance - */ - - if (!VULKAN_INTERNAL_CreateInstance(renderer, presentationParameters)) - { - FNA3D_LogError("Error creating vulkan instance"); - return NULL; - } - - /* - * Create the dummy surface - */ - - if (!SDL_Vulkan_CreateSurface( - (SDL_Window*) presentationParameters->deviceWindowHandle, - renderer->instance, - NULL, /* FIXME: VAllocationCallbacks */ - &surface - )) { - FNA3D_LogError( - "SDL_Vulkan_CreateSurface failed: %s", - SDL_GetError() - ); - return NULL; - } - - /* - * Get vkInstance entry points - */ - - #define VULKAN_INSTANCE_FUNCTION(name) \ - renderer->name = (PFN_##name) vkGetInstanceProcAddr(renderer->instance, #name); - #include "FNA3D_Driver_Vulkan_vkfuncs.h" - - /* - * Choose/Create vkDevice - */ - - if (!VULKAN_INTERNAL_DeterminePhysicalDevice(renderer, surface)) - { - FNA3D_LogError("Failed to determine a suitable physical device"); - return NULL; - } - - renderer->vkDestroySurfaceKHR(renderer->instance, surface, NULL); - - FNA3D_LogInfo("FNA3D Driver: Vulkan"); - FNA3D_LogInfo( - "Vulkan Device: %s", - renderer->physicalDeviceProperties.properties.deviceName - ); - if ( renderer->supportsDeviceProperties2 && - renderer->supports.KHR_driver_properties ) - { - FNA3D_LogInfo( - "Vulkan Driver: %s %s", - renderer->physicalDeviceDriverProperties.driverName, - renderer->physicalDeviceDriverProperties.driverInfo - ); - FNA3D_LogInfo( - "Vulkan Conformance: %u.%u.%u", - renderer->physicalDeviceDriverProperties.conformanceVersion.major, - renderer->physicalDeviceDriverProperties.conformanceVersion.minor, - renderer->physicalDeviceDriverProperties.conformanceVersion.patch - ); - } - else - { - FNA3D_LogInfo("KHR_driver_properties unsupported! Bother your vendor about this!"); - } - - if (!VULKAN_INTERNAL_CreateLogicalDevice(renderer)) - { - FNA3D_LogError("Failed to create logical device"); - return NULL; - } - - /* - * Choose depth formats - */ - - vulkanResult = renderer->vkGetPhysicalDeviceImageFormatProperties( - renderer->physicalDevice, - VK_FORMAT_D16_UNORM, - VK_IMAGE_TYPE_2D, - VK_IMAGE_TILING_OPTIMAL, - VK_IMAGE_ASPECT_DEPTH_BIT, - 0, - &imageFormatProperties - ); - - if (vulkanResult == VK_ERROR_FORMAT_NOT_SUPPORTED) - { - renderer->D16Format = VK_FORMAT_D32_SFLOAT; - } - else - { - renderer->D16Format = VK_FORMAT_D16_UNORM; - } - - /* Vulkan doesn't even have plain D24 in the spec! */ - renderer->D24Format = VK_FORMAT_D32_SFLOAT; - - vulkanResult = renderer->vkGetPhysicalDeviceImageFormatProperties( - renderer->physicalDevice, - VK_FORMAT_D24_UNORM_S8_UINT, - VK_IMAGE_TYPE_2D, - VK_IMAGE_TILING_OPTIMAL, - VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT, - 0, - &imageFormatProperties - ); - - if (vulkanResult == VK_ERROR_FORMAT_NOT_SUPPORTED) - { - renderer->D24S8Format = VK_FORMAT_D32_SFLOAT_S8_UINT; - } - else - { - renderer->D24S8Format = VK_FORMAT_D24_UNORM_S8_UINT; - } - - /* - * Create MojoShader context - */ - - renderer->mojoshaderContext = MOJOSHADER_vkCreateContext( - &renderer->instance, - &renderer->physicalDevice, - &renderer->logicalDevice, - (PFN_MOJOSHADER_vkGetInstanceProcAddr) vkGetInstanceProcAddr, - (PFN_MOJOSHADER_vkGetDeviceProcAddr) renderer->vkGetDeviceProcAddr, - renderer->queueFamilyIndex, - renderer->physicalDeviceProperties.properties.limits.maxUniformBufferRange, - renderer->physicalDeviceProperties.properties.limits.minUniformBufferOffsetAlignment, - NULL, - NULL, - renderer - ); - if (renderer->mojoshaderContext == NULL) - { - FNA3D_LogError("Failed to create MojoShader context"); - return NULL; - } - - semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; - semaphoreInfo.pNext = NULL; - semaphoreInfo.flags = 0; - - vulkanResult = renderer->vkCreateSemaphore( - renderer->logicalDevice, - &semaphoreInfo, - NULL, - &renderer->defragSemaphore - ); - VULKAN_ERROR_CHECK(vulkanResult, vkCreateSemaphore, NULL) - - /* - * Create command pool and buffers - */ - - commandPoolCreateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; - commandPoolCreateInfo.pNext = NULL; - commandPoolCreateInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; - commandPoolCreateInfo.queueFamilyIndex = renderer->queueFamilyIndex; - vulkanResult = renderer->vkCreateCommandPool( - renderer->logicalDevice, - &commandPoolCreateInfo, - NULL, - &renderer->commandPool - ); - VULKAN_ERROR_CHECK(vulkanResult, vkCreateCommandPool, NULL) - - ASSIGN_COMMANDBUFFER_DRIVER(VULKAN) - renderer->commandBuffers = FNA3D_CreateCommandBufferManager(&commandBufferDriver); - FNA3D_CommandBuffer_BeginRecording(renderer->commandBuffers); - - /* - * Create the initial faux-backbuffer - */ - - if (!VULKAN_INTERNAL_CreateFauxBackbuffer(renderer, presentationParameters)) - { - FNA3D_LogError("Failed to create faux backbuffer"); - return NULL; - } - - /* - * Create initial swapchain - */ - - renderer->swapchainDataCapacity = 1; - renderer->swapchainDataCount = 0; - renderer->swapchainDatas = SDL_malloc(renderer->swapchainDataCapacity * sizeof(VulkanSwapchainData*)); - - if (VULKAN_INTERNAL_CreateSwapchain(renderer, presentationParameters->deviceWindowHandle) != CREATE_SWAPCHAIN_SUCCESS) - { - FNA3D_LogError("Failed to create swap chain"); - return NULL; - } - - /* - * Create the pipeline cache - */ - - pipelineCacheCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO; - pipelineCacheCreateInfo.pNext = NULL; - pipelineCacheCreateInfo.flags = 0; - - pipelineCacheFileName = SDL_GetHint("FNA3D_VULKAN_PIPELINE_CACHE_FILE_NAME"); - if (pipelineCacheFileName == NULL) - { - pipelineCacheFileName = DEFAULT_PIPELINE_CACHE_FILE_NAME; - } - if (pipelineCacheFileName[0] == '\0') - { - /* For intentionally empty file names, assume caching is disabled */ - pipelineCacheBytes = NULL; - } - else - { - pipelineCacheBytes = SDL_LoadFile(pipelineCacheFileName, &pipelineCacheSize); - } - - if (pipelineCacheBytes != NULL) - { - FNA3D_LogInfo("Pipeline cache found, loading..."); - pipelineCacheCreateInfo.pInitialData = pipelineCacheBytes; - pipelineCacheCreateInfo.initialDataSize = pipelineCacheSize; - } - else - { - pipelineCacheCreateInfo.initialDataSize = 0; - pipelineCacheCreateInfo.pInitialData = NULL; - } - - vulkanResult = renderer->vkCreatePipelineCache( - renderer->logicalDevice, - &pipelineCacheCreateInfo, - NULL, - &renderer->pipelineCache - ); - - if (pipelineCacheBytes != NULL) - { - SDL_free(pipelineCacheBytes); - - /* The pipeline cache was invalid, try again with no input data */ - if (vulkanResult != VK_SUCCESS) - { - FNA3D_LogWarn("Pipeline cache preload failed, ignoring"); - pipelineCacheCreateInfo.initialDataSize = 0; - pipelineCacheCreateInfo.pInitialData = NULL; - vulkanResult = renderer->vkCreatePipelineCache( - renderer->logicalDevice, - &pipelineCacheCreateInfo, - NULL, - &renderer->pipelineCache - ); - } - } - - VULKAN_ERROR_CHECK(vulkanResult, vkCreatePipelineCache, NULL) - - /* - * Define sampler counts - */ - - renderer->numTextureSlots = SDL_min( - renderer->physicalDeviceProperties.properties.limits.maxPerStageDescriptorSamplers, - MAX_TEXTURE_SAMPLERS - ); - renderer->numVertexTextureSlots = SDL_min( - renderer->physicalDeviceProperties.properties.limits.maxPerStageDescriptorSamplers, - MAX_VERTEXTEXTURE_SAMPLERS - ); - - /* Define vertex UBO set layout */ - layoutBinding.binding = 0; - layoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; - layoutBinding.descriptorCount = 1; - layoutBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT; - layoutBinding.pImmutableSamplers = NULL; - - layoutCreateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; - layoutCreateInfo.pNext = NULL; - layoutCreateInfo.flags = 0; - layoutCreateInfo.bindingCount = 1; - layoutCreateInfo.pBindings = &layoutBinding; - - vulkanResult = renderer->vkCreateDescriptorSetLayout( - renderer->logicalDevice, - &layoutCreateInfo, - NULL, - &renderer->vertexUniformBufferDescriptorSetLayout - ); - VULKAN_ERROR_CHECK(vulkanResult, vkCreateDescriptorSetLayout, NULL) - - /* Define frag UBO set layout */ - layoutBinding.binding = 0; - layoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; - layoutBinding.descriptorCount = 1; - layoutBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; - layoutBinding.pImmutableSamplers = NULL; - - layoutCreateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; - layoutCreateInfo.pNext = NULL; - layoutCreateInfo.flags = 0; - layoutCreateInfo.bindingCount = 1; - layoutCreateInfo.pBindings = &layoutBinding; - - vulkanResult = renderer->vkCreateDescriptorSetLayout( - renderer->logicalDevice, - &layoutCreateInfo, - NULL, - &renderer->fragUniformBufferDescriptorSetLayout - ); - VULKAN_ERROR_CHECK(vulkanResult, vkCreateDescriptorSetLayout, NULL) - - renderer->vertexSamplerDescriptorSetDataNeedsUpdate = 1; - renderer->fragSamplerDescriptorSetDataNeedsUpdate = 1; - - /* - * Init various renderer properties - */ - - renderer->currentDepthFormat = presentationParameters->depthStencilFormat; - renderer->currentPipeline = VK_NULL_HANDLE; - renderer->needNewRenderPass = 1; - renderer->needNewPipeline = 1; - - /* - * Check for DXT1/S3TC support - */ - - renderer->vkGetPhysicalDeviceFormatProperties( - renderer->physicalDevice, - XNAToVK_SurfaceFormat[FNA3D_SURFACEFORMAT_DXT1], - &formatPropsBC1 - ); - renderer->vkGetPhysicalDeviceFormatProperties( - renderer->physicalDevice, - XNAToVK_SurfaceFormat[FNA3D_SURFACEFORMAT_DXT3], - &formatPropsBC2 - ); - renderer->vkGetPhysicalDeviceFormatProperties( - renderer->physicalDevice, - XNAToVK_SurfaceFormat[FNA3D_SURFACEFORMAT_DXT5], - &formatPropsBC3 - ); - renderer->vkGetPhysicalDeviceFormatProperties( - renderer->physicalDevice, - XNAToVK_SurfaceFormat[FNA3D_SURFACEFORMAT_COLORSRGB_EXT], - &formatPropsSrgbRT - ); - renderer->vkGetPhysicalDeviceFormatProperties( - renderer->physicalDevice, - XNAToVK_SurfaceFormat[FNA3D_SURFACEFORMAT_BC7_EXT], - &formatPropsBC7 - ); - - #define SUPPORTED_FORMAT(fmt) \ - ((fmt.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) && \ - (fmt.optimalTilingFeatures & VK_FORMAT_FEATURE_TRANSFER_DST_BIT)) - renderer->supportsDxt1 = SUPPORTED_FORMAT(formatPropsBC1); - renderer->supportsS3tc = ( - SUPPORTED_FORMAT(formatPropsBC2) || - SUPPORTED_FORMAT(formatPropsBC3) - ); - renderer->supportsBc7 = SUPPORTED_FORMAT(formatPropsBC7); - - renderer->supportsSRGBRenderTarget = ( - SUPPORTED_FORMAT(formatPropsSrgbRT) && (formatPropsSrgbRT.optimalTilingFeatures & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT) - ); - - renderer->vkGetPhysicalDeviceFeatures( - renderer->physicalDevice, - &physicalDeviceFeatures - ); - renderer->supportsPreciseOcclusionQueries = physicalDeviceFeatures.occlusionQueryPrecise; - -#ifdef __APPLE__ - /* The iOS/tvOS simulator and some older (~A8) devices don't support base vertex, - * and unfortunately that's not a queryable Vulkan device feature/property. - * However, according to the Metal Feature Set tables, any device that supports - * "counting occlusion queries" also supports base vertex. So we'll check for that. - * -caleb - */ - renderer->supportsBaseVertex = renderer->supportsPreciseOcclusionQueries; -#else - renderer->supportsBaseVertex = 1; -#endif - - /* - * Initialize renderer members not covered by SDL_memset('\0') - */ - - SDL_memset( - renderer->multiSampleMask, - -1, - sizeof(renderer->multiSampleMask) /* AKA 0xFFFFFFFF */ - ); - for (i = 0; i < MAX_BOUND_VERTEX_BUFFERS; i += 1) - { - renderer->vertexBindings[i].vertexDeclaration.elements = - renderer->vertexElements[i]; - } - - /* - * Create query pool - */ - - queryPoolCreateInfo.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO; - queryPoolCreateInfo.pNext = NULL; - queryPoolCreateInfo.flags = 0; - queryPoolCreateInfo.queryType = VK_QUERY_TYPE_OCCLUSION; - queryPoolCreateInfo.queryCount = MAX_QUERIES; - queryPoolCreateInfo.pipelineStatistics = 0; - vulkanResult = renderer->vkCreateQueryPool( - renderer->logicalDevice, - &queryPoolCreateInfo, - NULL, - &renderer->queryPool - ); - VULKAN_ERROR_CHECK(vulkanResult, vkCreateQueryPool, NULL) - - /* Set up the stack, the value at each index is the next available - * index, or -1 if no such index exists. - */ - for (i = 0; i < MAX_QUERIES - 1; i += 1) - { - renderer->freeQueryIndexStack[i] = i + 1; - } - renderer->freeQueryIndexStack[MAX_QUERIES - 1] = -1; - - /* Initialize hash tables */ - - for (i = 0; i < NUM_SHADER_RESOURCES_BUCKETS; i += 1) - { - renderer->shaderResourcesHashTable.buckets[i].elements = NULL; - renderer->shaderResourcesHashTable.buckets[i].count = 0; - renderer->shaderResourcesHashTable.buckets[i].capacity = 0; - } - - for (i = 0; i < NUM_DESCRIPTOR_SET_LAYOUT_BUCKETS; i += 1) - { - renderer->descriptorSetLayoutTable.buckets[i].elements = NULL; - renderer->descriptorSetLayoutTable.buckets[i].count = 0; - renderer->descriptorSetLayoutTable.buckets[i].capacity = 0; - } - /* - * Create dummy data - */ - - renderer->dummyVertTexture = (VulkanTexture*) VULKAN_CreateTexture2D( - (FNA3D_Renderer*) renderer, - FNA3D_SURFACEFORMAT_COLOR, - 1, - 1, - 1, - 1 - ); - renderer->dummyVertTexture3D = (VulkanTexture*) VULKAN_CreateTexture3D( - (FNA3D_Renderer*) renderer, - FNA3D_SURFACEFORMAT_COLOR, - 1, - 1, - 1, - 1 - ); - renderer->dummyVertTextureCube = (VulkanTexture*) VULKAN_CreateTextureCube( - (FNA3D_Renderer*) renderer, - FNA3D_SURFACEFORMAT_COLOR, - 1, - 1, - 0 - ); - renderer->dummyFragTexture = (VulkanTexture*) VULKAN_CreateTexture2D( - (FNA3D_Renderer*) renderer, - FNA3D_SURFACEFORMAT_COLOR, - 1, - 1, - 1, - 1 - ); - renderer->dummyFragTexture3D = (VulkanTexture*) VULKAN_CreateTexture3D( - (FNA3D_Renderer*) renderer, - FNA3D_SURFACEFORMAT_COLOR, - 1, - 1, - 1, - 1 - ); - renderer->dummyFragTextureCube = (VulkanTexture*) VULKAN_CreateTextureCube( - (FNA3D_Renderer*) renderer, - FNA3D_SURFACEFORMAT_COLOR, - 1, - 1, - 0 - ); - VULKAN_INTERNAL_ImageMemoryBarrier( - renderer, - RESOURCE_ACCESS_VERTEX_SHADER_READ_SAMPLED_IMAGE, - VK_IMAGE_ASPECT_COLOR_BIT, - 0, - 1, - 0, - 1, - 1, - renderer->dummyVertTexture->image, - &renderer->dummyVertTexture->resourceAccessType - ); - VULKAN_INTERNAL_ImageMemoryBarrier( - renderer, - RESOURCE_ACCESS_VERTEX_SHADER_READ_SAMPLED_IMAGE, - VK_IMAGE_ASPECT_COLOR_BIT, - 0, - 1, - 0, - 1, - 1, - renderer->dummyVertTexture3D->image, - &renderer->dummyVertTexture3D->resourceAccessType - ); - VULKAN_INTERNAL_ImageMemoryBarrier( - renderer, - RESOURCE_ACCESS_VERTEX_SHADER_READ_SAMPLED_IMAGE, - VK_IMAGE_ASPECT_COLOR_BIT, - 0, - 6, - 0, - 1, - 1, - renderer->dummyVertTextureCube->image, - &renderer->dummyVertTextureCube->resourceAccessType - ); - VULKAN_INTERNAL_ImageMemoryBarrier( - renderer, - RESOURCE_ACCESS_FRAGMENT_SHADER_READ_SAMPLED_IMAGE, - VK_IMAGE_ASPECT_COLOR_BIT, - 0, - 1, - 0, - 1, - 1, - renderer->dummyFragTexture->image, - &renderer->dummyFragTexture->resourceAccessType - ); - VULKAN_INTERNAL_ImageMemoryBarrier( - renderer, - RESOURCE_ACCESS_FRAGMENT_SHADER_READ_SAMPLED_IMAGE, - VK_IMAGE_ASPECT_COLOR_BIT, - 0, - 1, - 0, - 1, - 1, - renderer->dummyFragTexture3D->image, - &renderer->dummyFragTexture3D->resourceAccessType - ); - VULKAN_INTERNAL_ImageMemoryBarrier( - renderer, - RESOURCE_ACCESS_FRAGMENT_SHADER_READ_SAMPLED_IMAGE, - VK_IMAGE_ASPECT_COLOR_BIT, - 0, - 6, - 0, - 1, - 1, - renderer->dummyFragTextureCube->image, - &renderer->dummyFragTextureCube->resourceAccessType - ); - - renderer->dummyVertUniformBuffer = (VulkanBuffer*) VULKAN_INTERNAL_CreateBuffer( - renderer, - 1, - RESOURCE_ACCESS_VERTEX_SHADER_READ_UNIFORM_BUFFER, - VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, - 0, - 0 - ); - SDL_memset( - FNA3D_Memory_GetHostPointer( - renderer->dummyVertUniformBuffer->usedRegion, - 0 - ), - 0, - 1 - ); - - renderer->dummyFragUniformBuffer = (VulkanBuffer*) VULKAN_INTERNAL_CreateBuffer( - renderer, - 1, - RESOURCE_ACCESS_FRAGMENT_SHADER_READ_UNIFORM_BUFFER, - VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, - 0, - 0 - ); - SDL_memset( - FNA3D_Memory_GetHostPointer( - renderer->dummyFragUniformBuffer->usedRegion, - 0 - ), - 0, - 1 - ); - - samplerCreateInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; - samplerCreateInfo.pNext = NULL; - samplerCreateInfo.flags = 0; - samplerCreateInfo.magFilter = VK_FILTER_LINEAR; - samplerCreateInfo.minFilter = VK_FILTER_LINEAR; - samplerCreateInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST; - samplerCreateInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT; - samplerCreateInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT; - samplerCreateInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT; - samplerCreateInfo.mipLodBias = 0; - samplerCreateInfo.anisotropyEnable = 0; - samplerCreateInfo.maxAnisotropy = 1; - samplerCreateInfo.compareEnable = 0; - samplerCreateInfo.compareOp = 0; - samplerCreateInfo.minLod = 0; - samplerCreateInfo.maxLod = 1; - samplerCreateInfo.borderColor = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK; - samplerCreateInfo.unnormalizedCoordinates = 0; - renderer->vkCreateSampler( - renderer->logicalDevice, - &samplerCreateInfo, - NULL, - &renderer->dummyVertSamplerState - ); - renderer->vkCreateSampler( - renderer->logicalDevice, - &samplerCreateInfo, - NULL, - &renderer->dummyVertSampler3DState - ); - renderer->vkCreateSampler( - renderer->logicalDevice, - &samplerCreateInfo, - NULL, - &renderer->dummyVertSamplerCubeState - ); - renderer->vkCreateSampler( - renderer->logicalDevice, - &samplerCreateInfo, - NULL, - &renderer->dummyFragSamplerState - ); - renderer->vkCreateSampler( - renderer->logicalDevice, - &samplerCreateInfo, - NULL, - &renderer->dummyFragSampler3DState - ); - renderer->vkCreateSampler( - renderer->logicalDevice, - &samplerCreateInfo, - NULL, - &renderer->dummyFragSamplerCubeState - ); - - descriptorPoolSize.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; - descriptorPoolSize.descriptorCount = MAX_UNIFORM_DESCRIPTOR_SETS; - - descriptorPoolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; - descriptorPoolInfo.pNext = NULL; - descriptorPoolInfo.flags = 0; - descriptorPoolInfo.maxSets = MAX_UNIFORM_DESCRIPTOR_SETS; - descriptorPoolInfo.poolSizeCount = 1; - descriptorPoolInfo.pPoolSizes = &descriptorPoolSize; - - vulkanResult = renderer->vkCreateDescriptorPool( - renderer->logicalDevice, - &descriptorPoolInfo, - NULL, - &renderer->uniformBufferDescriptorPool - ); - VULKAN_ERROR_CHECK(vulkanResult, vkCreateDescriptorPool, 0) - - descriptorSetAllocateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; - descriptorSetAllocateInfo.pNext = NULL; - descriptorSetAllocateInfo.descriptorPool = renderer->uniformBufferDescriptorPool; - descriptorSetAllocateInfo.descriptorSetCount = 1; - descriptorSetAllocateInfo.pSetLayouts = &renderer->vertexUniformBufferDescriptorSetLayout; - - vulkanResult = renderer->vkAllocateDescriptorSets( - renderer->logicalDevice, - &descriptorSetAllocateInfo, - &renderer->dummyVertexUniformBufferDescriptorSet - ); - VULKAN_ERROR_CHECK(vulkanResult, vkAllocateDescriptorSets, 0) - - descriptorSetAllocateInfo.pSetLayouts = &renderer->fragUniformBufferDescriptorSetLayout; - - vulkanResult = renderer->vkAllocateDescriptorSets( - renderer->logicalDevice, - &descriptorSetAllocateInfo, - &renderer->dummyFragUniformBufferDescriptorSet - ); - VULKAN_ERROR_CHECK(vulkanResult, vkAllocateDescriptorSets, 0) - - bufferInfos[0].buffer = renderer->dummyVertUniformBuffer->buffer; - bufferInfos[0].offset = 0; - bufferInfos[0].range = renderer->dummyVertUniformBuffer->size; - - writeDescriptorSets[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - writeDescriptorSets[0].pNext = NULL; - writeDescriptorSets[0].descriptorCount = 1; - writeDescriptorSets[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; - writeDescriptorSets[0].dstArrayElement = 0; - writeDescriptorSets[0].dstBinding = 0; - writeDescriptorSets[0].dstSet = renderer->dummyVertexUniformBufferDescriptorSet; - writeDescriptorSets[0].pBufferInfo = &bufferInfos[0]; - writeDescriptorSets[0].pImageInfo = NULL; - writeDescriptorSets[0].pTexelBufferView = NULL; - - bufferInfos[1].buffer = renderer->dummyFragUniformBuffer->buffer; - bufferInfos[1].offset = 0; - bufferInfos[1].range = renderer->dummyFragUniformBuffer->size; - - writeDescriptorSets[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - writeDescriptorSets[1].pNext = NULL; - writeDescriptorSets[1].descriptorCount = 1; - writeDescriptorSets[1].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; - writeDescriptorSets[1].dstArrayElement = 0; - writeDescriptorSets[1].dstBinding = 0; - writeDescriptorSets[1].dstSet = renderer->dummyFragUniformBufferDescriptorSet; - writeDescriptorSets[1].pBufferInfo = &bufferInfos[1]; - writeDescriptorSets[1].pImageInfo = NULL; - writeDescriptorSets[1].pTexelBufferView = NULL; - - renderer->vkUpdateDescriptorSets( - renderer->logicalDevice, - 2, - writeDescriptorSets, - 0, - NULL - ); - - /* init texture storage */ - - for (i = 0; i < MAX_TEXTURE_SAMPLERS; i += 1) - { - renderer->textures[i] = &NullTexture; - renderer->samplers[i] = renderer->dummyFragSamplerState; - } - - for (i = 0; i < MAX_VERTEXTEXTURE_SAMPLERS; i += 1) - { - renderer->textures[MAX_TEXTURE_SAMPLERS + i] = &NullTexture; - renderer->samplers[MAX_TEXTURE_SAMPLERS + i] = renderer->dummyVertSamplerState; - } - - renderer->bufferDefragInProgress = 0; - renderer->needDefrag = 0; - renderer->defragTimer = 0; - renderer->resourceFreed = 0; - - renderer->defragmentedBuffersToDestroyCapacity = 16; - renderer->defragmentedBuffersToDestroyCount = 0; - - renderer->defragmentedBuffersToDestroy = (VkBuffer*) SDL_malloc( - sizeof(VkBuffer) * - renderer->defragmentedBuffersToDestroyCapacity - ); - - renderer->defragmentedImagesToDestroyCapacity = 16; - renderer->defragmentedImagesToDestroyCount = 0; - - renderer->defragmentedImagesToDestroy = (VkImage*) SDL_malloc( - sizeof(VkImage) * - renderer->defragmentedImagesToDestroyCapacity - ); - - renderer->defragmentedImageViewsToDestroyCapacity = 16; - renderer->defragmentedImageViewsToDestroyCount = 0; - - renderer->defragmentedImageViewsToDestroy = (VkImageView*) SDL_malloc( - sizeof(VkImageView) * - renderer->defragmentedImageViewsToDestroyCapacity - ); - - renderer->passLock = SDL_CreateMutex(); - renderer->disposeLock = SDL_CreateMutex(); - - return result; -} - -FNA3D_Driver VulkanDriver = { - "Vulkan", - VULKAN_PrepareWindowAttributes, - VULKAN_CreateDevice -}; - -#else - -extern int this_tu_is_empty; - -#endif /* FNA3D_DRIVER_VULKAN */ diff --git a/src/FNA3D_Driver_Vulkan_vkfuncs.h b/src/FNA3D_Driver_Vulkan_vkfuncs.h deleted file mode 100644 index 67de2905..00000000 --- a/src/FNA3D_Driver_Vulkan_vkfuncs.h +++ /dev/null @@ -1,179 +0,0 @@ -/* FNA3D - 3D Graphics Library for FNA - * - * Copyright (c) 2020-2024 Ethan Lee - * - * This software is provided 'as-is', without any express or implied warranty. - * In no event will the authors be held liable for any damages arising from - * the use of this software. - * - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you must not - * claim that you wrote the original software. If you use this software in a - * product, an acknowledgment in the product documentation would be - * appreciated but is not required. - * - * 2. Altered source versions must be plainly marked as such, and must not be - * misrepresented as being the original software. - * - * 3. This notice may not be removed or altered from any source distribution. - * - * Ethan "flibitijibibo" Lee - * - */ - -/* - * Global functions from the Vulkan Loader - */ - -#ifndef VULKAN_GLOBAL_FUNCTION -#define VULKAN_GLOBAL_FUNCTION(name) -#endif -VULKAN_GLOBAL_FUNCTION(vkCreateInstance) -VULKAN_GLOBAL_FUNCTION(vkEnumerateInstanceExtensionProperties) -VULKAN_GLOBAL_FUNCTION(vkEnumerateInstanceLayerProperties) - -/* - * vkInstance, created by global vkCreateInstance function - */ - -#ifndef VULKAN_INSTANCE_FUNCTION -#define VULKAN_INSTANCE_FUNCTION(name) -#endif - -/* Vulkan 1.0 */ -VULKAN_INSTANCE_FUNCTION(vkGetDeviceProcAddr) -VULKAN_INSTANCE_FUNCTION(vkCreateDevice) -VULKAN_INSTANCE_FUNCTION(vkDestroyInstance) -VULKAN_INSTANCE_FUNCTION(vkEnumerateDeviceExtensionProperties) -VULKAN_INSTANCE_FUNCTION(vkEnumeratePhysicalDevices) -VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceFeatures) -VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceQueueFamilyProperties) -VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceFormatProperties) -VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceImageFormatProperties) -VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceMemoryProperties) -VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceProperties) - -/* VK_KHR_get_physical_device_properties2, needed for KHR_driver_properties */ -VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceProperties2KHR) - -/* VK_KHR_surface */ -VULKAN_INSTANCE_FUNCTION(vkDestroySurfaceKHR) -VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceSurfaceCapabilitiesKHR) -VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceSurfaceFormatsKHR) -VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceSurfacePresentModesKHR) -VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceSurfaceSupportKHR) - -/* VK_EXT_debug_utils, Optional debug feature used by SetStringMarker */ -VULKAN_INSTANCE_FUNCTION(vkCmdInsertDebugUtilsLabelEXT) -VULKAN_INSTANCE_FUNCTION(vkSetDebugUtilsObjectNameEXT) - -/* - * vkDevice, created by a vkInstance - */ - -#ifndef VULKAN_DEVICE_FUNCTION -#define VULKAN_DEVICE_FUNCTION(name) -#endif - -/* Vulkan 1.0 */ -VULKAN_DEVICE_FUNCTION(vkAllocateCommandBuffers) -VULKAN_DEVICE_FUNCTION(vkAllocateDescriptorSets) -VULKAN_DEVICE_FUNCTION(vkAllocateMemory) -VULKAN_DEVICE_FUNCTION(vkBeginCommandBuffer) -VULKAN_DEVICE_FUNCTION(vkBindBufferMemory) -VULKAN_DEVICE_FUNCTION(vkBindImageMemory) -VULKAN_DEVICE_FUNCTION(vkCmdBeginRenderPass) -VULKAN_DEVICE_FUNCTION(vkCmdBindDescriptorSets) -VULKAN_DEVICE_FUNCTION(vkCmdBindIndexBuffer) -VULKAN_DEVICE_FUNCTION(vkCmdBindPipeline) -VULKAN_DEVICE_FUNCTION(vkCmdBindVertexBuffers) -VULKAN_DEVICE_FUNCTION(vkCmdBlitImage) -VULKAN_DEVICE_FUNCTION(vkCmdClearAttachments) -VULKAN_DEVICE_FUNCTION(vkCmdClearColorImage) -VULKAN_DEVICE_FUNCTION(vkCmdClearDepthStencilImage) -VULKAN_DEVICE_FUNCTION(vkCmdCopyBuffer) -VULKAN_DEVICE_FUNCTION(vkCmdCopyImage) -VULKAN_DEVICE_FUNCTION(vkCmdCopyBufferToImage) -VULKAN_DEVICE_FUNCTION(vkCmdCopyImageToBuffer) -VULKAN_DEVICE_FUNCTION(vkCmdDraw) -VULKAN_DEVICE_FUNCTION(vkCmdDrawIndexed) -VULKAN_DEVICE_FUNCTION(vkCmdEndRenderPass) -VULKAN_DEVICE_FUNCTION(vkCmdPipelineBarrier) -VULKAN_DEVICE_FUNCTION(vkCmdResolveImage) -VULKAN_DEVICE_FUNCTION(vkCmdSetBlendConstants) -VULKAN_DEVICE_FUNCTION(vkCmdSetDepthBias) -VULKAN_DEVICE_FUNCTION(vkCmdSetScissor) -VULKAN_DEVICE_FUNCTION(vkCmdSetStencilReference) -VULKAN_DEVICE_FUNCTION(vkCmdSetViewport) -VULKAN_DEVICE_FUNCTION(vkCreateBuffer) -VULKAN_DEVICE_FUNCTION(vkCreateCommandPool) -VULKAN_DEVICE_FUNCTION(vkCreateDescriptorPool) -VULKAN_DEVICE_FUNCTION(vkCreateDescriptorSetLayout) -VULKAN_DEVICE_FUNCTION(vkCreateFence) -VULKAN_DEVICE_FUNCTION(vkCreateFramebuffer) -VULKAN_DEVICE_FUNCTION(vkCreateGraphicsPipelines) -VULKAN_DEVICE_FUNCTION(vkCreateImage) -VULKAN_DEVICE_FUNCTION(vkCreateImageView) -VULKAN_DEVICE_FUNCTION(vkCreatePipelineCache) -VULKAN_DEVICE_FUNCTION(vkCreatePipelineLayout) -VULKAN_DEVICE_FUNCTION(vkCreateRenderPass) -VULKAN_DEVICE_FUNCTION(vkCreateSampler) -VULKAN_DEVICE_FUNCTION(vkCreateSemaphore) -VULKAN_DEVICE_FUNCTION(vkCreateShaderModule) -VULKAN_DEVICE_FUNCTION(vkCreateQueryPool) -VULKAN_DEVICE_FUNCTION(vkDestroyBuffer) -VULKAN_DEVICE_FUNCTION(vkDestroyCommandPool) -VULKAN_DEVICE_FUNCTION(vkDestroyDescriptorPool) -VULKAN_DEVICE_FUNCTION(vkDestroyDescriptorSetLayout) -VULKAN_DEVICE_FUNCTION(vkDestroyDevice) -VULKAN_DEVICE_FUNCTION(vkDestroyFence) -VULKAN_DEVICE_FUNCTION(vkDestroyFramebuffer) -VULKAN_DEVICE_FUNCTION(vkDestroyImage) -VULKAN_DEVICE_FUNCTION(vkDestroyImageView) -VULKAN_DEVICE_FUNCTION(vkDestroyPipeline) -VULKAN_DEVICE_FUNCTION(vkDestroyPipelineCache) -VULKAN_DEVICE_FUNCTION(vkDestroyPipelineLayout) -VULKAN_DEVICE_FUNCTION(vkDestroyRenderPass) -VULKAN_DEVICE_FUNCTION(vkDestroySampler) -VULKAN_DEVICE_FUNCTION(vkDestroySemaphore) -VULKAN_DEVICE_FUNCTION(vkDestroyQueryPool) -VULKAN_DEVICE_FUNCTION(vkDeviceWaitIdle) -VULKAN_DEVICE_FUNCTION(vkEndCommandBuffer) -VULKAN_DEVICE_FUNCTION(vkFreeCommandBuffers) -VULKAN_DEVICE_FUNCTION(vkFreeMemory) -VULKAN_DEVICE_FUNCTION(vkGetDeviceQueue) -VULKAN_DEVICE_FUNCTION(vkGetPipelineCacheData) -VULKAN_DEVICE_FUNCTION(vkGetFenceStatus) -VULKAN_DEVICE_FUNCTION(vkGetBufferMemoryRequirements) -VULKAN_DEVICE_FUNCTION(vkGetImageMemoryRequirements) -VULKAN_DEVICE_FUNCTION(vkMapMemory) -VULKAN_DEVICE_FUNCTION(vkQueueSubmit) -VULKAN_DEVICE_FUNCTION(vkQueueWaitIdle) -VULKAN_DEVICE_FUNCTION(vkResetCommandBuffer) -VULKAN_DEVICE_FUNCTION(vkResetCommandPool) -VULKAN_DEVICE_FUNCTION(vkResetDescriptorPool) -VULKAN_DEVICE_FUNCTION(vkResetFences) -VULKAN_DEVICE_FUNCTION(vkUnmapMemory) -VULKAN_DEVICE_FUNCTION(vkUpdateDescriptorSets) -VULKAN_DEVICE_FUNCTION(vkWaitForFences) -VULKAN_DEVICE_FUNCTION(vkCmdResetQueryPool) -VULKAN_DEVICE_FUNCTION(vkCmdBeginQuery) -VULKAN_DEVICE_FUNCTION(vkCmdEndQuery) -VULKAN_DEVICE_FUNCTION(vkGetQueryPoolResults) - -/* VK_KHR_swapchain */ -VULKAN_DEVICE_FUNCTION(vkAcquireNextImageKHR) -VULKAN_DEVICE_FUNCTION(vkCreateSwapchainKHR) -VULKAN_DEVICE_FUNCTION(vkDestroySwapchainKHR) -VULKAN_DEVICE_FUNCTION(vkQueuePresentKHR) -VULKAN_DEVICE_FUNCTION(vkGetSwapchainImagesKHR) - -/* - * Redefine these every time you include this header! - */ -#undef VULKAN_GLOBAL_FUNCTION -#undef VULKAN_INSTANCE_FUNCTION -#undef VULKAN_DEVICE_FUNCTION diff --git a/src/FNA3D_Memory.c b/src/FNA3D_Memory.c deleted file mode 100644 index 8488f2c5..00000000 --- a/src/FNA3D_Memory.c +++ /dev/null @@ -1,1111 +0,0 @@ -/* FNA3D - 3D Graphics Library for FNA - * - * Copyright (c) 2020-2024 Ethan Lee - * - * This software is provided 'as-is', without any express or implied warranty. - * In no event will the authors be held liable for any damages arising from - * the use of this software. - * - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you must not - * claim that you wrote the original software. If you use this software in a - * product, an acknowledgment in the product documentation would be - * appreciated but is not required. - * - * 2. Altered source versions must be plainly marked as such, and must not be - * misrepresented as being the original software. - * - * 3. This notice may not be removed or altered from any source distribution. - * - * Ethan "flibitijibibo" Lee - * - */ - -#include "FNA3D_Memory.h" - -#ifdef USE_SDL3 -#include -#else -#include -#define SDL_Mutex SDL_mutex -#endif - -/* - * Memory Allocator - */ - -#define STARTING_ALLOCATION_SIZE 64000000 /* 64MB */ -#define ALLOCATION_INCREMENT 16000000 /* 16MB */ - -typedef struct FNA3D_MemoryAllocation FNA3D_MemoryAllocation; - -typedef struct FNA3D_MemoryFreeRegion -{ - FNA3D_MemoryAllocation *parent; - - size_t offset; - size_t size; - - size_t allocationIndex; - size_t sortedIndex; -} FNA3D_MemoryFreeRegion; - -struct FNA3D_MemoryUsedRegion -{ - FNA3D_MemoryAllocation *parent; - - size_t offset; - size_t size; - size_t resourceOffset; /* Differs from offset based on alignment */ - size_t resourceSize; /* Differs from size based on alignment */ - size_t alignment; - - uint8_t isBuffer; - void* defragResource; -}; - -typedef struct FNA3D_SubAllocator FNA3D_SubAllocator; - -struct FNA3D_MemoryAllocation -{ - FNA3D_SubAllocator *parent; - - FNA3D_MemoryPlatformHandle handle; - size_t size; - - FNA3D_MemoryUsedRegion **usedRegions; - size_t usedRegionCount; - size_t usedRegionCapacity; - size_t usedSpace; - - FNA3D_MemoryFreeRegion **freeRegions; - size_t freeRegionCount; - size_t freeRegionCapacity; - size_t freeSpace; - - uint8_t dedicated; /* For renderers with device-local memory */ - uint8_t available; - - uint8_t *mapPointer; - SDL_Mutex *mapLock; -}; - -struct FNA3D_SubAllocator -{ - size_t index; /* Index within FNA3D_MemoryAllocator */ - size_t nextAllocationSize; - - FNA3D_MemoryAllocation **allocations; - size_t allocationCount; - - FNA3D_MemoryFreeRegion **sortedFreeRegions; - size_t sortedFreeRegionCount; - size_t sortedFreeRegionCapacity; -}; - -struct FNA3D_MemoryAllocator -{ - FNA3D_MemoryDriver driver; - - FNA3D_SubAllocator *subAllocators; - size_t subAllocatorCount; - - FNA3D_MemoryUsedRegion **usedRegionsToDestroy; - size_t usedRegionsToDestroyCount; - size_t usedRegionsToDestroyCapacity; - - SDL_Mutex *lock; -}; - -static void FNA3D_INTERNAL_RemoveMemoryFreeRegion( - FNA3D_MemoryAllocator *allocator, - FNA3D_MemoryFreeRegion *freeRegion -) { - size_t i; - FNA3D_MemoryAllocation *allocation; - FNA3D_SubAllocator *subAllocator; - - SDL_LockMutex(allocator->lock); - - allocation = freeRegion->parent; - subAllocator = allocation->parent; - - if (allocation->available) - { - /* Close the gap in the sorted list */ - if (subAllocator->sortedFreeRegionCount > 1) - { - for (i = freeRegion->sortedIndex; i < subAllocator->sortedFreeRegionCount - 1; i += 1) - { - subAllocator->sortedFreeRegions[i] = - subAllocator->sortedFreeRegions[i + 1]; - - subAllocator->sortedFreeRegions[i]->sortedIndex = i; - } - } - - subAllocator->sortedFreeRegionCount -= 1; - } - - /* Close the gap in the buffer list */ - if (allocation->freeRegionCount > 1 && freeRegion->allocationIndex != allocation->freeRegionCount - 1) - { - allocation->freeRegions[freeRegion->allocationIndex] = - allocation->freeRegions[allocation->freeRegionCount - 1]; - - allocation->freeRegions[freeRegion->allocationIndex]->allocationIndex = - freeRegion->allocationIndex; - } - - allocation->freeRegionCount -= 1; - - allocation->freeSpace -= freeRegion->size; - - SDL_free(freeRegion); - - SDL_UnlockMutex(allocator->lock); -} - -static void FNA3D_INTERNAL_NewMemoryFreeRegion( - FNA3D_MemoryAllocator *allocator, - FNA3D_MemoryAllocation *allocation, - size_t offset, - size_t size -) { - FNA3D_SubAllocator *subAllocator; - FNA3D_MemoryFreeRegion *newFreeRegion; - size_t newOffset, newSize; - size_t insertionIndex; - int32_t i; - - SDL_LockMutex(allocator->lock); - - /* Look for an adjacent region to merge */ - for (i = allocation->freeRegionCount - 1; i >= 0; i -= 1) - { - /* Check left side */ - if (allocation->freeRegions[i]->offset + allocation->freeRegions[i]->size == offset) - { - newOffset = allocation->freeRegions[i]->offset; - newSize = allocation->freeRegions[i]->size + size; - - FNA3D_INTERNAL_RemoveMemoryFreeRegion( - allocator, - allocation->freeRegions[i] - ); - FNA3D_INTERNAL_NewMemoryFreeRegion( - allocator, - allocation, - newOffset, - newSize - ); - - SDL_UnlockMutex(allocator->lock); - return; - } - - /* Check right side */ - if (allocation->freeRegions[i]->offset == offset + size) - { - newOffset = offset; - newSize = allocation->freeRegions[i]->size + size; - - FNA3D_INTERNAL_RemoveMemoryFreeRegion( - allocator, - allocation->freeRegions[i] - ); - FNA3D_INTERNAL_NewMemoryFreeRegion( - allocator, - allocation, - newOffset, - newSize - ); - - SDL_UnlockMutex(allocator->lock); - return; - } - } - - /* Region is not contiguous with another free region, make a new one */ - allocation->freeRegionCount += 1; - if (allocation->freeRegionCount > allocation->freeRegionCapacity) - { - allocation->freeRegionCapacity *= 2; - allocation->freeRegions = (FNA3D_MemoryFreeRegion**) SDL_realloc( - allocation->freeRegions, - sizeof(FNA3D_MemoryFreeRegion*) * allocation->freeRegionCapacity - ); - } - - newFreeRegion = (FNA3D_MemoryFreeRegion*) SDL_malloc(sizeof(FNA3D_MemoryFreeRegion)); - newFreeRegion->offset = offset; - newFreeRegion->size = size; - newFreeRegion->parent = allocation; - - allocation->freeSpace += size; - - allocation->freeRegions[allocation->freeRegionCount - 1] = newFreeRegion; - newFreeRegion->allocationIndex = allocation->freeRegionCount - 1; - - if (allocation->available) - { - subAllocator = allocation->parent; - insertionIndex = 0; - - for (i = 0; i < subAllocator->sortedFreeRegionCount; i += 1) - { - if (subAllocator->sortedFreeRegions[i]->size < size) - { - /* This is where the new region should go */ - break; - } - - insertionIndex += 1; - } - - if (subAllocator->sortedFreeRegionCount + 1 > subAllocator->sortedFreeRegionCapacity) - { - subAllocator->sortedFreeRegionCapacity *= 2; - subAllocator->sortedFreeRegions = SDL_realloc( - subAllocator->sortedFreeRegions, - sizeof(FNA3D_MemoryFreeRegion*) * subAllocator->sortedFreeRegionCapacity - ); - } - - /* Perform insertion sort */ - if ( subAllocator->sortedFreeRegionCount > 0 && - insertionIndex != subAllocator->sortedFreeRegionCount ) - { - for (i = subAllocator->sortedFreeRegionCount; i > insertionIndex && i > 0; i -= 1) - { - subAllocator->sortedFreeRegions[i] = subAllocator->sortedFreeRegions[i - 1]; - subAllocator->sortedFreeRegions[i]->sortedIndex = i; - } - } - - subAllocator->sortedFreeRegionCount += 1; - subAllocator->sortedFreeRegions[insertionIndex] = newFreeRegion; - newFreeRegion->sortedIndex = insertionIndex; - } - - SDL_UnlockMutex(allocator->lock); -} - -uint8_t FNA3D_INTERNAL_RemoveMemoryUsedRegion( - FNA3D_MemoryAllocator *allocator, - FNA3D_MemoryUsedRegion *usedRegion -) { - uint32_t i; - uint8_t needsDefrag; - FNA3D_MemoryAllocation *allocation; - - SDL_LockMutex(allocator->lock); - - allocation = usedRegion->parent; - - for (i = 0; i < allocation->usedRegionCount; i += 1) - { - if (allocation->usedRegions[i] == usedRegion) - { - /* Plug the hole */ - if (i != allocation->usedRegionCount - 1) - { - allocation->usedRegions[i] = - allocation->usedRegions[allocation->usedRegionCount - 1]; - } - - break; - } - } - - allocation->usedSpace -= usedRegion->size; - allocation->usedRegionCount -= 1; - - FNA3D_INTERNAL_NewMemoryFreeRegion( - allocator, - usedRegion->parent, - usedRegion->offset, - usedRegion->size - ); - - needsDefrag = !allocation->dedicated; - - SDL_free(usedRegion); - - SDL_UnlockMutex(allocator->lock); - - return needsDefrag; -} - -static FNA3D_MemoryUsedRegion* FNA3D_INTERNAL_NewMemoryUsedRegion( - FNA3D_MemoryAllocator *allocator, - FNA3D_MemoryAllocation *allocation, - size_t offset, - size_t size, - size_t resourceOffset, - size_t resourceSize, - size_t alignment -) { - FNA3D_MemoryUsedRegion *memoryUsedRegion; - - SDL_LockMutex(allocator->lock); - - if (allocation->usedRegionCount == allocation->usedRegionCapacity) - { - allocation->usedRegionCapacity *= 2; - allocation->usedRegions = (FNA3D_MemoryUsedRegion**) SDL_realloc( - allocation->usedRegions, - allocation->usedRegionCapacity * sizeof(FNA3D_MemoryUsedRegion*) - ); - } - - memoryUsedRegion = (FNA3D_MemoryUsedRegion*) SDL_malloc(sizeof(FNA3D_MemoryUsedRegion)); - memoryUsedRegion->parent = allocation; - memoryUsedRegion->offset = offset; - memoryUsedRegion->size = size; - memoryUsedRegion->resourceOffset = resourceOffset; - memoryUsedRegion->resourceSize = resourceSize; - memoryUsedRegion->alignment = alignment; - - allocation->usedSpace += size; - - allocation->usedRegions[allocation->usedRegionCount] = memoryUsedRegion; - allocation->usedRegionCount += 1; - - SDL_UnlockMutex(allocator->lock); - - return memoryUsedRegion; -} - -static FNA3D_MemoryAllocation* FNA3D_INTERNAL_Allocate( - FNA3D_MemoryAllocator *allocator, - size_t subAllocatorIndex, - size_t memorySize, - uint8_t dedicated, - uint8_t deviceLocal, - uint8_t hostVisible -) { - FNA3D_SubAllocator *subAllocator = &allocator->subAllocators[subAllocatorIndex]; - FNA3D_MemoryAllocation *allocation; - uint8_t result; - - allocation = (FNA3D_MemoryAllocation*) SDL_malloc(sizeof(FNA3D_MemoryAllocation)); - allocation->size = memorySize; - allocation->freeSpace = 0; /* added by FreeRegions */ - allocation->usedSpace = 0; /* added by UsedRegions */ - allocation->mapLock = SDL_CreateMutex(); - - subAllocator->allocationCount += 1; - subAllocator->allocations = (FNA3D_MemoryAllocation**) SDL_realloc( - subAllocator->allocations, - sizeof(FNA3D_MemoryAllocation*) * subAllocator->allocationCount - ); - - subAllocator->allocations[subAllocator->allocationCount - 1] = allocation; - - if (dedicated) - { - allocation->dedicated = 1; - allocation->available = 0; - } - else - { - allocation->dedicated = 0; - allocation->available = 1; - } - - allocation->usedRegions = (FNA3D_MemoryUsedRegion**) SDL_malloc(sizeof(FNA3D_MemoryUsedRegion*)); - allocation->usedRegionCount = 0; - allocation->usedRegionCapacity = 1; - - allocation->freeRegions = (FNA3D_MemoryFreeRegion**) SDL_malloc(sizeof(FNA3D_MemoryFreeRegion*)); - allocation->freeRegionCount = 0; - allocation->freeRegionCapacity = 1; - - allocation->parent = subAllocator; - - result = allocator->driver.AllocDeviceMemory( - allocator->driver.driverData, - subAllocatorIndex, - memorySize, - deviceLocal, - hostVisible, - (FNA3D_MemoryPlatformHandle*) &allocation->handle, - &allocation->mapPointer - ); - - if (!result) - { - /* Uh oh, we couldn't allocate, time to clean up */ - SDL_free(allocation->freeRegions); - - subAllocator->allocationCount -= 1; - subAllocator->allocations = (FNA3D_MemoryAllocation**) SDL_realloc( - subAllocator->allocations, - sizeof(FNA3D_MemoryAllocation*) * subAllocator->allocationCount - ); - - SDL_free(allocation); - return NULL; - } - - FNA3D_INTERNAL_NewMemoryFreeRegion( - allocator, - allocation, - 0, - allocation->size - ); - - return allocation; -} - -static void FNA3D_INTERNAL_Deallocate( - FNA3D_MemoryAllocator *allocator, - FNA3D_SubAllocator *subAllocator, - size_t allocationIndex -) { - size_t i; - FNA3D_MemoryAllocation *allocation; - - SDL_LockMutex(allocator->lock); - - allocation = subAllocator->allocations[allocationIndex]; - - for (i = 0; i < allocation->freeRegionCount; i += 1) - { - FNA3D_INTERNAL_RemoveMemoryFreeRegion( - allocator, - allocation->freeRegions[i] - ); - } - SDL_free(allocation->freeRegions); - - /* No need to iterate used regions because deallocate - * only happens when there are 0 used regions - */ - SDL_free(allocation->usedRegions); - - allocator->driver.FreeDeviceMemory( - allocator->driver.driverData, - allocation->handle, - allocation->size, - subAllocator->index - ); - - SDL_DestroyMutex(allocation->mapLock); - SDL_free(allocation); - - if (allocationIndex != subAllocator->allocationCount - 1) - { - subAllocator->allocations[allocationIndex] = subAllocator->allocations[ - subAllocator->allocationCount - 1 - ]; - } - - subAllocator->allocationCount -= 1; - - SDL_UnlockMutex(allocator->lock); -} - -FNA3D_MemoryAllocator* FNA3D_CreateMemoryAllocator( - FNA3D_MemoryDriver *driver, - size_t numSubAllocators -) { - size_t i; - FNA3D_MemoryAllocator *result; - FNA3D_SubAllocator *subAllocator; - - result = (FNA3D_MemoryAllocator*) SDL_malloc( - sizeof(FNA3D_MemoryAllocator) - ); - SDL_memcpy(&result->driver, driver, sizeof(FNA3D_MemoryDriver)); - result->subAllocators = (FNA3D_SubAllocator*) SDL_malloc( - sizeof(FNA3D_SubAllocator) * numSubAllocators - ); - result->subAllocatorCount = numSubAllocators; - - for (i = 0; i < result->subAllocatorCount; i += 1) - { - subAllocator = &result->subAllocators[i]; - - subAllocator->index = i; - subAllocator->nextAllocationSize = STARTING_ALLOCATION_SIZE; - subAllocator->allocations = NULL; - subAllocator->allocationCount = 0; - - subAllocator->sortedFreeRegions = (FNA3D_MemoryFreeRegion**) SDL_malloc( - sizeof(FNA3D_MemoryFreeRegion*) * 4 - ); - subAllocator->sortedFreeRegionCount = 0; - subAllocator->sortedFreeRegionCapacity = 4; - } - - result->usedRegionsToDestroyCapacity = 16; - result->usedRegionsToDestroyCount = 0; - result->usedRegionsToDestroy = (FNA3D_MemoryUsedRegion**) SDL_malloc( - sizeof(FNA3D_MemoryUsedRegion*) * - result->usedRegionsToDestroyCapacity - ); - - result->lock = SDL_CreateMutex(); - - return result; -} - -void FNA3D_DestroyMemoryAllocator(FNA3D_MemoryAllocator *allocator) -{ - size_t i; - int32_t j, k; - FNA3D_SubAllocator *subAllocator; - - for (i = 0; i < allocator->subAllocatorCount; i += 1) - { - subAllocator = &allocator->subAllocators[i]; - - for (j = subAllocator->allocationCount - 1; j >= 0; j -= 1) - { - for (k = subAllocator->allocations[j]->usedRegionCount - 1; k >= 0; k -= 1) - { - FNA3D_INTERNAL_RemoveMemoryUsedRegion( - allocator, - subAllocator->allocations[j]->usedRegions[k] - ); - } - - FNA3D_INTERNAL_Deallocate( - allocator, - subAllocator, - j - ); - } - - if (subAllocator->allocations != NULL) - { - SDL_free(subAllocator->allocations); - } - SDL_free(subAllocator->sortedFreeRegions); - } - - SDL_free(allocator->usedRegionsToDestroy); - - SDL_DestroyMutex(allocator->lock); - SDL_free(allocator->subAllocators); - SDL_free(allocator); -} - -void FNA3D_Memory_LockAllocator(FNA3D_MemoryAllocator *allocator) -{ - SDL_LockMutex(allocator->lock); -} - -void FNA3D_Memory_UnlockAllocator(FNA3D_MemoryAllocator *allocator) -{ - SDL_UnlockMutex(allocator->lock); -} - -static inline size_t FNA3D_INTERNAL_NextHighestAlignment( - size_t n, - size_t align -) { - return align * ((n + align - 1) / align); -} - -uint8_t FNA3D_Memory_BindResource( - FNA3D_MemoryAllocator *allocator, - size_t subAllocatorIndex, - size_t requiredSize, - size_t requiredAlignment, - uint8_t isHostVisible, - uint8_t isDeviceLocal, - uint8_t shouldAllocDedicated, - size_t resourceSize, /* may be different from requirements size! */ - uint8_t resourceIsImage, - FNA3D_MemoryPlatformHandle resource, - void *defragResourceHandle, - FNA3D_MemoryUsedRegion** pMemoryUsedRegion -) { - FNA3D_MemoryAllocation *allocation; - FNA3D_SubAllocator *subAllocator; - FNA3D_MemoryFreeRegion *region; - FNA3D_MemoryUsedRegion *usedRegion; - - size_t allocationSize; - size_t alignedOffset; - uint32_t newRegionSize, newRegionOffset; - uint8_t bindResult; - - subAllocator = &allocator->subAllocators[subAllocatorIndex]; - - SDL_assert(resource != 0); - - SDL_LockMutex(allocator->lock); - - /* find the largest free region and use it */ - if (!shouldAllocDedicated && subAllocator->sortedFreeRegionCount > 0) - { - region = subAllocator->sortedFreeRegions[0]; - allocation = region->parent; - - alignedOffset = FNA3D_INTERNAL_NextHighestAlignment( - region->offset, - requiredAlignment - ); - - if (alignedOffset + requiredSize <= region->offset + region->size) - { - usedRegion = FNA3D_INTERNAL_NewMemoryUsedRegion( - allocator, - allocation, - region->offset, - requiredSize + (alignedOffset - region->offset), - alignedOffset, - resourceSize, - requiredAlignment - ); - - usedRegion->isBuffer = !resourceIsImage; - usedRegion->defragResource = defragResourceHandle; - - newRegionSize = region->size - ((alignedOffset - region->offset) + requiredSize); - newRegionOffset = alignedOffset + requiredSize; - - /* remove and add modified region to re-sort */ - FNA3D_INTERNAL_RemoveMemoryFreeRegion( - allocator, - region - ); - - /* if size is 0, no need to re-insert */ - if (newRegionSize != 0) - { - FNA3D_INTERNAL_NewMemoryFreeRegion( - allocator, - allocation, - newRegionOffset, - newRegionSize - ); - } - - SDL_UnlockMutex(allocator->lock); - - SDL_LockMutex(usedRegion->parent->mapLock); - if (!resourceIsImage) - { - bindResult = allocator->driver.BindBufferMemory( - allocator->driver.driverData, - usedRegion->parent->handle, - alignedOffset, - resource - ); - } - else - { - bindResult = allocator->driver.BindImageMemory( - allocator->driver.driverData, - usedRegion->parent->handle, - alignedOffset, - resource - ); - } - SDL_UnlockMutex(usedRegion->parent->mapLock); - if (!bindResult) - { - FNA3D_INTERNAL_RemoveMemoryUsedRegion( - allocator, - usedRegion - ); - - return 0; - } - - *pMemoryUsedRegion = usedRegion; - return 1; - } - } - - /* No suitable free regions exist, allocate a new memory region */ - - if (shouldAllocDedicated) - { - allocationSize = requiredSize; - } - else if (requiredSize > subAllocator->nextAllocationSize) - { - /* allocate a page of required size aligned to ALLOCATION_INCREMENT increments */ - allocationSize = - FNA3D_INTERNAL_NextHighestAlignment(requiredSize, ALLOCATION_INCREMENT); - } - else - { - allocationSize = subAllocator->nextAllocationSize; - } - - allocation = FNA3D_INTERNAL_Allocate( - allocator, - subAllocatorIndex, - allocationSize, - shouldAllocDedicated, - isDeviceLocal, - isHostVisible - ); - - /* Uh oh, we're out of memory */ - if (allocation == NULL) - { - SDL_UnlockMutex(allocator->lock); - - /* Responsibility of the caller to handle being out of memory */ - FNA3D_LogWarn("Failed to allocate memory!"); - return 2; - } - - usedRegion = FNA3D_INTERNAL_NewMemoryUsedRegion( - allocator, - allocation, - 0, - requiredSize, - 0, - resourceSize, - requiredAlignment - ); - - usedRegion->isBuffer = !resourceIsImage; - usedRegion->defragResource = defragResourceHandle; - - region = allocation->freeRegions[0]; - - newRegionOffset = region->offset + requiredSize; - newRegionSize = region->size - requiredSize; - - FNA3D_INTERNAL_RemoveMemoryFreeRegion( - allocator, - region - ); - - if (newRegionSize != 0) - { - FNA3D_INTERNAL_NewMemoryFreeRegion( - allocator, - allocation, - newRegionOffset, - newRegionSize - ); - } - - SDL_UnlockMutex(allocator->lock); - - SDL_LockMutex(usedRegion->parent->mapLock); - if (!resourceIsImage) - { - bindResult = allocator->driver.BindBufferMemory( - allocator->driver.driverData, - usedRegion->parent->handle, - 0, - resource - ); - } - else - { - bindResult = allocator->driver.BindImageMemory( - allocator->driver.driverData, - usedRegion->parent->handle, - 0, - resource - ); - } - SDL_UnlockMutex(usedRegion->parent->mapLock); - if (!bindResult) - { - FNA3D_INTERNAL_RemoveMemoryUsedRegion( - allocator, - usedRegion - ); - - return 0; - } - - *pMemoryUsedRegion = usedRegion; - return 1; -} - -uint8_t* FNA3D_Memory_GetHostPointer( - FNA3D_MemoryUsedRegion *usedRegion, - size_t offset -) { - return ( - usedRegion->parent->mapPointer + - usedRegion->resourceOffset + - offset - ); -} - -void FNA3D_Memory_FreeEmptyAllocations(FNA3D_MemoryAllocator *allocator) -{ - FNA3D_SubAllocator *subAllocator; - size_t i; - int32_t j; - - SDL_LockMutex(allocator->lock); - - for (i = 0; i < allocator->subAllocatorCount; i += 1) - { - subAllocator = &allocator->subAllocators[i]; - - for (j = subAllocator->allocationCount - 1; j >= 0; j -= 1) - { - if (subAllocator->allocations[j]->usedRegionCount == 0) - { - FNA3D_INTERNAL_Deallocate( - allocator, - subAllocator, - j - ); - } - } - } - - SDL_UnlockMutex(allocator->lock); -} - -static uint8_t FNA3D_INTERNAL_FindAllocationToDefragment( - FNA3D_MemoryAllocator *allocator, - FNA3D_SubAllocator **subAllocator, - size_t *allocationIndexToDefrag -) { - size_t i, j; - FNA3D_SubAllocator *curAllocator; - - for (i = 0; i < allocator->subAllocatorCount; i += 1) - { - curAllocator = &allocator->subAllocators[i]; - - for (j = 0; j < curAllocator->allocationCount; j += 1) - { - if (curAllocator->allocations[j]->freeRegionCount > 1) - { - *subAllocator = curAllocator; - *allocationIndexToDefrag = j; - return 1; - } - } - } - - return 0; -} - -uint8_t FNA3D_Memory_Defragment(FNA3D_MemoryAllocator *allocator) -{ - FNA3D_SubAllocator *subAllocator; - FNA3D_MemoryAllocation *allocation; - size_t allocationIndexToDefrag; - FNA3D_MemoryFreeRegion *freeRegion; - FNA3D_MemoryUsedRegion *currentRegion; - uint8_t defragResult; - size_t i, j; - - SDL_LockMutex(allocator->lock); - - allocator->driver.BeginDefragCommands(allocator->driver.driverData); - - if (FNA3D_INTERNAL_FindAllocationToDefragment( - allocator, - &subAllocator, - &allocationIndexToDefrag - )) { - - allocation = subAllocator->allocations[allocationIndexToDefrag]; - - /* Make the allocation temporarily unavailable */ - allocation->available = 0; - for (i = 0; i < allocation->freeRegionCount; i += 1) - { - freeRegion = allocation->freeRegions[i]; - - /* close the gap in the sorted list */ - if (subAllocator->sortedFreeRegionCount > 1) - { - for (j = freeRegion->sortedIndex; j < subAllocator->sortedFreeRegionCount - 1; j += 1) - { - subAllocator->sortedFreeRegions[j] = - subAllocator->sortedFreeRegions[j + 1]; - - subAllocator->sortedFreeRegions[j]->sortedIndex = j; - } - } - - subAllocator->sortedFreeRegionCount -= 1; - } - - for (i = 0; i < allocation->usedRegionCount; i += 1) - { - currentRegion = allocation->usedRegions[i]; - - if (currentRegion->isBuffer) - { - defragResult = allocator->driver.DefragBuffer( - allocator->driver.driverData, - currentRegion->defragResource, - currentRegion->resourceSize - ); - } - else - { - defragResult = allocator->driver.DefragImage( - allocator->driver.driverData, - currentRegion->defragResource, - currentRegion->resourceSize - ); - } - - if (!defragResult) - { - return 0; - } - - if (allocator->usedRegionsToDestroyCount >= allocator->usedRegionsToDestroyCapacity) - { - allocator->usedRegionsToDestroyCapacity *= 2; - allocator->usedRegionsToDestroy = (FNA3D_MemoryUsedRegion**) SDL_realloc( - allocator->usedRegionsToDestroy, - sizeof(FNA3D_MemoryUsedRegion*) * allocator->usedRegionsToDestroyCapacity - ); - } - - allocator->usedRegionsToDestroy[ - allocator->usedRegionsToDestroyCount - ] = currentRegion; - - allocator->usedRegionsToDestroyCount += 1; - } - } - - allocator->driver.EndDefragCommands(allocator->driver.driverData); - - SDL_UnlockMutex(allocator->lock); - - return 1; -} - -uint8_t FNA3D_Memory_DestroyDefragmentedRegions(FNA3D_MemoryAllocator *allocator) -{ - uint8_t needsDefrag = 0; - size_t i; - for (i = 0; i < allocator->usedRegionsToDestroyCount; i += 1) - { - needsDefrag |= FNA3D_INTERNAL_RemoveMemoryUsedRegion( - allocator, - allocator->usedRegionsToDestroy[i] - ); - } - - allocator->usedRegionsToDestroyCount = 0; - return needsDefrag; -} - -/* - * Buffer Containers - */ - -struct FNA3D_BufferContainer -{ - size_t sizeInBytes; - FNA3D_BufferHandle *activeBuffer; - - /* These are all the buffers that have been used by this container. - * If a buffer is bound and then updated with Discard, a new buffer - * will be added to this list. - * These can be reused after they are submitted and command processing is complete. - */ - size_t bufferCapacity; - size_t bufferCount; - FNA3D_BufferHandle **referencedBuffers; -}; - -FNA3D_BufferContainer* FNA3D_Memory_CreateBufferContainer( - FNA3D_MemoryAllocator *allocator, - uint8_t isVertexData, - size_t sizeInBytes -) { - FNA3D_BufferContainer *result = (FNA3D_BufferContainer*) SDL_malloc( - sizeof(FNA3D_BufferContainer) - ); - - result->sizeInBytes = sizeInBytes; - result->bufferCapacity = 1; - result->bufferCount = 1; - result->activeBuffer = allocator->driver.CreateBufferHandle( - allocator->driver.driverData, - isVertexData, - sizeInBytes - ); - result->referencedBuffers = SDL_malloc(sizeof(FNA3D_BufferHandle*)); - result->referencedBuffers[0] = result->activeBuffer; - - return result; -} - -void FNA3D_Memory_DestroyBufferContainer( - FNA3D_MemoryAllocator *allocator, - FNA3D_BufferContainer *container -) { - allocator->driver.MarkBufferHandlesForDestroy( - allocator->driver.driverData, - container->referencedBuffers, - container->bufferCount - ); - - SDL_free(container->referencedBuffers); - SDL_free(container); -} - -FNA3D_BufferHandle* FNA3D_Memory_GetActiveBuffer( - FNA3D_BufferContainer *container -) { - return container->activeBuffer; -} - -FNA3D_BufferHandle* FNA3D_Memory_DiscardActiveBuffer( - FNA3D_MemoryAllocator *allocator, - FNA3D_BufferContainer *container -) { - size_t i; - - /* If a previously-discarded buffer is available, we can use that. */ - for (i = 0; i < container->bufferCount; i += 1) - { - if (!allocator->driver.BufferHandleInUse( - allocator->driver.driverData, - container->referencedBuffers[i] - )) { - container->activeBuffer = container->referencedBuffers[i]; - break; - } - } - - /* If no buffer is available, generate a new one. */ - if (i == container->bufferCount) - { - container->activeBuffer = allocator->driver.CloneBufferHandle( - allocator->driver.driverData, - container->activeBuffer - ); - - if (container->bufferCount >= container->bufferCapacity) - { - container->bufferCapacity += 1; - container->referencedBuffers = SDL_realloc( - container->referencedBuffers, - container->bufferCapacity * sizeof(FNA3D_BufferHandle*) - ); - } - - container->referencedBuffers[container->bufferCount] = - container->activeBuffer; - container->bufferCount += 1; - } - - return container->activeBuffer; -} diff --git a/src/FNA3D_Memory.h b/src/FNA3D_Memory.h deleted file mode 100644 index 9151de24..00000000 --- a/src/FNA3D_Memory.h +++ /dev/null @@ -1,215 +0,0 @@ -/* FNA3D - 3D Graphics Library for FNA - * - * Copyright (c) 2020-2024 Ethan Lee - * - * This software is provided 'as-is', without any express or implied warranty. - * In no event will the authors be held liable for any damages arising from - * the use of this software. - * - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you must not - * claim that you wrote the original software. If you use this software in a - * product, an acknowledgment in the product documentation would be - * appreciated but is not required. - * - * 2. Altered source versions must be plainly marked as such, and must not be - * misrepresented as being the original software. - * - * 3. This notice may not be removed or altered from any source distribution. - * - * Ethan "flibitijibibo" Lee - * - */ - -#ifndef FNA3D_MEMORY_H -#define FNA3D_MEMORY_H - -#include "FNA3D_Driver.h" - -#include /* for size_t */ - -/* Driver-defined memory structures */ - -typedef uint64_t FNA3D_MemoryPlatformHandle; -typedef struct FNA3D_BufferHandle FNA3D_BufferHandle; - -/* Renderers will contain a memory driver, so we can call back into the renderer - * to do platform-specific things that don't have to do with the high-level - * memory management - */ - -typedef struct FNA3D_MemoryDriver -{ - uint8_t (*AllocDeviceMemory)( - FNA3D_Renderer *driverData, - size_t subAllocatorIndex, - size_t memorySize, - uint8_t deviceLocal, - uint8_t hostVisible, - FNA3D_MemoryPlatformHandle* driverMemory, - uint8_t **mapPointer - ); - void (*FreeDeviceMemory)( - FNA3D_Renderer *driverData, - FNA3D_MemoryPlatformHandle driverMemory, - size_t memorySize, - size_t subAllocatorIndex - ); - uint8_t (*BindBufferMemory)( - FNA3D_Renderer *driverData, - FNA3D_MemoryPlatformHandle deviceMemory, - size_t alignedOffset, - FNA3D_MemoryPlatformHandle buffer - ); - uint8_t (*BindImageMemory)( - FNA3D_Renderer *driverData, - FNA3D_MemoryPlatformHandle deviceMemory, - size_t alignedOffset, - FNA3D_MemoryPlatformHandle image - ); - void (*BeginDefragCommands)( - FNA3D_Renderer *driverData - ); - void (*EndDefragCommands)( - FNA3D_Renderer *driverData - ); - uint8_t (*DefragBuffer)( - FNA3D_Renderer *driverData, - void* resource, - size_t resourceSize - ); - uint8_t (*DefragImage)( - FNA3D_Renderer *driverData, - void* resource, - size_t resourceSize - ); - - FNA3D_BufferHandle *(*CreateBufferHandle)( - FNA3D_Renderer *driverData, - uint8_t isVertexData, - size_t sizeInBytes - ); - FNA3D_BufferHandle *(*CloneBufferHandle)( - FNA3D_Renderer *driverData, - FNA3D_BufferHandle *buffer - ); - void (*MarkBufferHandlesForDestroy)( - FNA3D_Renderer *driverData, - FNA3D_BufferHandle **buffers, - size_t bufferCount - ); - uint8_t (*BufferHandleInUse)( - FNA3D_Renderer *driverData, - FNA3D_BufferHandle *buffer - ); - - FNA3D_Renderer *driverData; -} FNA3D_MemoryDriver; - -#define ASSIGN_MEMORY_DRIVER_FUNC(func, name) \ - memoryDriver.func = name##_Memory_##func; -#define ASSIGN_MEMORY_DRIVER(name) \ - memoryDriver.driverData = (FNA3D_Renderer*) renderer; \ - ASSIGN_MEMORY_DRIVER_FUNC(AllocDeviceMemory, name) \ - ASSIGN_MEMORY_DRIVER_FUNC(FreeDeviceMemory, name) \ - ASSIGN_MEMORY_DRIVER_FUNC(BindBufferMemory, name) \ - ASSIGN_MEMORY_DRIVER_FUNC(BindImageMemory, name) \ - ASSIGN_MEMORY_DRIVER_FUNC(BeginDefragCommands, name) \ - ASSIGN_MEMORY_DRIVER_FUNC(EndDefragCommands, name) \ - ASSIGN_MEMORY_DRIVER_FUNC(DefragBuffer, name) \ - ASSIGN_MEMORY_DRIVER_FUNC(DefragImage, name) \ - ASSIGN_MEMORY_DRIVER_FUNC(CreateBufferHandle, name) \ - ASSIGN_MEMORY_DRIVER_FUNC(CloneBufferHandle, name) \ - ASSIGN_MEMORY_DRIVER_FUNC(MarkBufferHandlesForDestroy, name) \ - ASSIGN_MEMORY_DRIVER_FUNC(BufferHandleInUse, name) - -/* - * Memory Allocator Interface - */ - -typedef struct FNA3D_MemoryAllocator FNA3D_MemoryAllocator; - -typedef struct FNA3D_MemoryUsedRegion FNA3D_MemoryUsedRegion; - -FNA3D_SHAREDINTERNAL FNA3D_MemoryAllocator* FNA3D_CreateMemoryAllocator( - FNA3D_MemoryDriver *driver, - size_t numSubAllocators -); - -FNA3D_SHAREDINTERNAL void FNA3D_DestroyMemoryAllocator(FNA3D_MemoryAllocator *allocator); - -FNA3D_SHAREDINTERNAL void FNA3D_Memory_LockAllocator(FNA3D_MemoryAllocator *allocator); -FNA3D_SHAREDINTERNAL void FNA3D_Memory_UnlockAllocator(FNA3D_MemoryAllocator *allocator); - -FNA3D_SHAREDINTERNAL uint8_t FNA3D_Memory_BindResource( - FNA3D_MemoryAllocator *allocator, - size_t subAllocatorIndex, - size_t requiredSize, - size_t requiredAlignment, - uint8_t isHostVisible, - uint8_t isDeviceLocal, - uint8_t shouldAllocDedicated, - size_t resourceSize, /* may be different from requirements size! */ - uint8_t resourceIsImage, - FNA3D_MemoryPlatformHandle resource, - void* defragResourceHandle, - FNA3D_MemoryUsedRegion** pMemoryUsedRegion -); - -FNA3D_SHAREDINTERNAL uint8_t* FNA3D_Memory_GetHostPointer( - FNA3D_MemoryUsedRegion *usedRegion, - size_t offset -); - -FNA3D_SHAREDINTERNAL void FNA3D_Memory_FreeEmptyAllocations(FNA3D_MemoryAllocator *allocator); - -FNA3D_SHAREDINTERNAL uint8_t FNA3D_Memory_Defragment(FNA3D_MemoryAllocator *allocator); - -FNA3D_SHAREDINTERNAL uint8_t FNA3D_Memory_DestroyDefragmentedRegions(FNA3D_MemoryAllocator *allocator); - -FNA3D_SHAREDINTERNAL uint8_t FNA3D_INTERNAL_RemoveMemoryUsedRegion( - FNA3D_MemoryAllocator *allocator, - FNA3D_MemoryUsedRegion *usedRegion -); - -/* - * Buffer Container Interface - */ - -/* Buffer containers refer to locations in memory previously allocated - * - * To properly support SETDATAOPTIONS_DISCARD the renderer's "buffer handle" is - * actually a container pointing to a buffer. - * - * This lets us change out the internal buffer without affecting - * the client or requiring a stall. - * - * The "discarded" buffers are kept around to avoid memory fragmentation - * being created by buffers that frequently discard. - */ -typedef struct FNA3D_BufferContainer FNA3D_BufferContainer; - -FNA3D_SHAREDINTERNAL FNA3D_BufferContainer* FNA3D_Memory_CreateBufferContainer( - FNA3D_MemoryAllocator *allocator, - uint8_t isVertexData, - size_t sizeInBytes -); - -FNA3D_SHAREDINTERNAL void FNA3D_Memory_DestroyBufferContainer( - FNA3D_MemoryAllocator *allocator, - FNA3D_BufferContainer *container -); - -FNA3D_SHAREDINTERNAL FNA3D_BufferHandle* FNA3D_Memory_GetActiveBuffer( - FNA3D_BufferContainer *container -); - -FNA3D_SHAREDINTERNAL FNA3D_BufferHandle* FNA3D_Memory_DiscardActiveBuffer( - FNA3D_MemoryAllocator *allocator, - FNA3D_BufferContainer *container -); - -#endif /* FNA3D_MEMORY_H */ diff --git a/visualc-gdk/FNA3D.vcxproj b/visualc-gdk/FNA3D.vcxproj index a68a862c..af04ad53 100644 --- a/visualc-gdk/FNA3D.vcxproj +++ b/visualc-gdk/FNA3D.vcxproj @@ -56,11 +56,6 @@ - - - {81ce8daf-ebb2-4761-8e45-b71abcca8c68} - - FAudio {8cf8e23c-b89a-4c77-9869-0d6247c7e58b} diff --git a/visualc/FNA3D.vcxproj b/visualc/FNA3D.vcxproj index 919d2ea0..c732e7a9 100644 --- a/visualc/FNA3D.vcxproj +++ b/visualc/FNA3D.vcxproj @@ -34,6 +34,18 @@ true MultiByte + + v143 + + + v143 + + + v143 + + + v143 + @@ -42,14 +54,14 @@ - ..\..\SDL2\include;..\MojoShader;..\include;$(DXSDK_DIR)\Include;..\Vulkan-Headers\include;$(IncludePath) + ..\..\SDL2\include;..\MojoShader;..\include;$(DXSDK_DIR)\Include;$(IncludePath) ..\..\SDL2\lib\$(PlatformShortName);$(LibraryPath) Level3 Disabled - FNA3D_DRIVER_OPENGL;FNA3D_DRIVER_D3D11;FNA3D_DRIVER_VULKAN;MOJOSHADER_NO_VERSION_INCLUDE;MOJOSHADER_USE_SDL_STDLIB;MOJOSHADER_EFFECT_SUPPORT;MOJOSHADER_DEPTH_CLIPPING;MOJOSHADER_FLIP_RENDERTARGET;MOJOSHADER_XNA4_VERTEX_TEXTURES;SUPPORT_PROFILE_ARB1=0;SUPPORT_PROFILE_ARB1_NV=0;SUPPORT_PROFILE_BYTECODE=0;SUPPORT_PROFILE_D3D=0;SUPPORT_PROFILE_METAL=0;%(PreprocessorDefinitions) + FNA3D_DRIVER_OPENGL;FNA3D_DRIVER_D3D11;MOJOSHADER_NO_VERSION_INCLUDE;MOJOSHADER_USE_SDL_STDLIB;MOJOSHADER_EFFECT_SUPPORT;MOJOSHADER_DEPTH_CLIPPING;MOJOSHADER_FLIP_RENDERTARGET;MOJOSHADER_XNA4_VERTEX_TEXTURES;SUPPORT_PROFILE_ARB1=0;SUPPORT_PROFILE_ARB1_NV=0;SUPPORT_PROFILE_BYTECODE=0;SUPPORT_PROFILE_D3D=0;SUPPORT_PROFILE_METAL=0;%(PreprocessorDefinitions) true @@ -60,7 +72,7 @@ Level3 MaxSpeed - FNA3D_DRIVER_OPENGL;FNA3D_DRIVER_D3D11;FNA3D_DRIVER_VULKAN;MOJOSHADER_NO_VERSION_INCLUDE;MOJOSHADER_USE_SDL_STDLIB;MOJOSHADER_EFFECT_SUPPORT;MOJOSHADER_DEPTH_CLIPPING;MOJOSHADER_FLIP_RENDERTARGET;MOJOSHADER_XNA4_VERTEX_TEXTURES;SUPPORT_PROFILE_ARB1=0;SUPPORT_PROFILE_ARB1_NV=0;SUPPORT_PROFILE_BYTECODE=0;SUPPORT_PROFILE_D3D=0;SUPPORT_PROFILE_METAL=0;%(PreprocessorDefinitions) + FNA3D_DRIVER_OPENGL;FNA3D_DRIVER_D3D11;MOJOSHADER_NO_VERSION_INCLUDE;MOJOSHADER_USE_SDL_STDLIB;MOJOSHADER_EFFECT_SUPPORT;MOJOSHADER_DEPTH_CLIPPING;MOJOSHADER_FLIP_RENDERTARGET;MOJOSHADER_XNA4_VERTEX_TEXTURES;SUPPORT_PROFILE_ARB1=0;SUPPORT_PROFILE_ARB1_NV=0;SUPPORT_PROFILE_BYTECODE=0;SUPPORT_PROFILE_D3D=0;SUPPORT_PROFILE_METAL=0;%(PreprocessorDefinitions) true true @@ -89,9 +101,6 @@ CompileAsCpp - - CompileAsCpp - CompileAsCpp @@ -111,26 +120,20 @@ CompileAsCpp - - - - - - diff --git a/visualc/FNA3D.vcxproj.filters b/visualc/FNA3D.vcxproj.filters index 1a862363..e6978433 100644 --- a/visualc/FNA3D.vcxproj.filters +++ b/visualc/FNA3D.vcxproj.filters @@ -39,13 +39,9 @@ mojoshader - - mojoshader - mojoshader - @@ -57,7 +53,6 @@ -