diff --git a/include/Refresh.h b/include/Refresh.h index 74f76e0..1248072 100644 --- a/include/Refresh.h +++ b/include/Refresh.h @@ -383,12 +383,6 @@ typedef struct Refresh_TextureSlice uint32_t level; } Refresh_TextureSlice; -typedef struct Refresh_PresentationParameters -{ - void* deviceWindowHandle; - Refresh_PresentMode presentMode; -} Refresh_PresentationParameters; - /* State structures */ typedef struct Refresh_SamplerStateCreateInfo @@ -609,7 +603,8 @@ REFRESHAPI void Refresh_HookLogFunctions( * Note that Refresh is not required to select your preferred backend * if it detects an incompatibility. * - * Returns the backend that will actually be used. + * Returns the backend that will actually be used, and fills in a window flag bitmask. + * This bitmask should be used to create all windows that the device claims. * * preferredBackend: The preferred backend that Refresh should select. * flags: A pointer to a bitflag value that will be filled in with required SDL_WindowFlags masks. @@ -621,11 +616,9 @@ REFRESHAPI Refresh_Backend Refresh_SelectBackend(Refresh_Backend preferredBacken /* Create a rendering context for use on the calling thread. * You MUST have called Refresh_SelectDriver prior to calling this function. * - * presentationParameters: A window handle and presentation mode. * debugMode: Enable debug mode properties. */ REFRESHAPI Refresh_Device* Refresh_CreateDevice( - Refresh_PresentationParameters *presentationParameters, uint8_t debugMode ); @@ -1138,6 +1131,41 @@ REFRESHAPI void Refresh_BindComputeTextures( /* Submission/Presentation */ +/* Claims a window, creating a swapchain structure for it. + * This function MUST be called before any swapchain functions + * are called using the window. + * + * Returns 0 on swapchain creation failure. + */ +REFRESHAPI uint8_t Refresh_ClaimWindow( + Refresh_Device *device, + void *windowHandle, + Refresh_PresentMode presentMode +); + +/* Unclaims a window, destroying the swapchain structure for it. + * It is good practice to call this when a window is closed to + * prevent memory bloat, but windows are automatically unclaimed + * by DestroyDevice. + */ +REFRESHAPI void Refresh_UnclaimWindow( + Refresh_Device *device, + void *windowHandle +); + +/* Changes the present mode of the swapchain for the given window. */ +REFRESHAPI void Refresh_SetSwapchainPresentMode( + Refresh_Device *device, + void *windowHandle, + Refresh_PresentMode presentMode +); + +/* Returns the format of the swapchain for the given window. */ +REFRESHAPI Refresh_TextureFormat Refresh_GetSwapchainFormat( + Refresh_Device *device, + void *windowHandle +); + /* Returns an allocated Refresh_CommandBuffer* object. * This command buffer is managed by the implementation and * should NOT be freed by the user. @@ -1177,12 +1205,6 @@ REFRESHAPI Refresh_Texture* Refresh_AcquireSwapchainTexture( uint32_t *pHeight ); -/* Returns the format of the swapchain for the given window. */ -REFRESHAPI Refresh_TextureFormat Refresh_GetSwapchainFormat( - Refresh_Device *device, - void *windowHandle -); - /* Submits all of the enqueued commands. */ REFRESHAPI void Refresh_Submit( Refresh_Device* device, diff --git a/src/Refresh.c b/src/Refresh.c index 7842892..40eb7f3 100644 --- a/src/Refresh.c +++ b/src/Refresh.c @@ -169,7 +169,6 @@ Refresh_Backend Refresh_SelectBackend(Refresh_Backend preferredBackend, uint32_t } Refresh_Device* Refresh_CreateDevice( - Refresh_PresentationParameters *presentationParameters, uint8_t debugMode ) { if (selectedBackend == REFRESH_BACKEND_INVALID) @@ -179,7 +178,6 @@ Refresh_Device* Refresh_CreateDevice( } return backends[selectedBackend]->CreateDevice( - presentationParameters, debugMode ); } @@ -760,6 +758,30 @@ void Refresh_BindComputeTextures( ); } +uint8_t Refresh_ClaimWindow( + Refresh_Device *device, + void *windowHandle, + Refresh_PresentMode presentMode +) { + if (device == NULL) { return 0; } + return device->ClaimWindow( + device->driverData, + windowHandle, + presentMode + ); +} + +void Refresh_UnclaimWindow( + Refresh_Device *device, + void *windowHandle +) { + NULL_RETURN(device); + device->UnclaimWindow( + device->driverData, + windowHandle + ); +} + Refresh_CommandBuffer* Refresh_AcquireCommandBuffer( Refresh_Device *device, uint8_t fixed @@ -799,6 +821,19 @@ Refresh_TextureFormat Refresh_GetSwapchainFormat( ); } +void Refresh_SetSwapchainPresentMode( + Refresh_Device *device, + void *windowHandle, + Refresh_PresentMode presentMode +) { + NULL_RETURN(device); + device->SetSwapchainPresentMode( + device->driverData, + windowHandle, + presentMode + ); +} + void Refresh_Submit( Refresh_Device *device, uint32_t commandBufferCount, diff --git a/src/Refresh_Driver.h b/src/Refresh_Driver.h index 9308372..e3c83c3 100644 --- a/src/Refresh_Driver.h +++ b/src/Refresh_Driver.h @@ -459,6 +459,17 @@ struct Refresh_Device Refresh_Texture **pTextures ); + uint8_t (*ClaimWindow)( + Refresh_Renderer *driverData, + void *windowHandle, + Refresh_PresentMode presentMode + ); + + void(*UnclaimWindow)( + Refresh_Renderer *driverData, + void *windowHandle + ); + Refresh_CommandBuffer* (*AcquireCommandBuffer)( Refresh_Renderer *driverData, uint8_t fixed @@ -477,6 +488,12 @@ struct Refresh_Device void *windowHandle ); + void (*SetSwapchainPresentMode)( + Refresh_Renderer *driverData, + void *windowHandle, + Refresh_PresentMode presentMode + ); + void(*Submit)( Refresh_Renderer *driverData, uint32_t commandBufferCount, @@ -533,9 +550,12 @@ struct Refresh_Device ASSIGN_DRIVER_FUNC(BindComputePipeline, name) \ ASSIGN_DRIVER_FUNC(BindComputeBuffers, name) \ ASSIGN_DRIVER_FUNC(BindComputeTextures, name) \ + ASSIGN_DRIVER_FUNC(ClaimWindow, name) \ + ASSIGN_DRIVER_FUNC(UnclaimWindow, name) \ ASSIGN_DRIVER_FUNC(AcquireCommandBuffer, name) \ ASSIGN_DRIVER_FUNC(AcquireSwapchainTexture, name) \ ASSIGN_DRIVER_FUNC(GetSwapchainFormat, name) \ + ASSIGN_DRIVER_FUNC(SetSwapchainPresentMode, name) \ ASSIGN_DRIVER_FUNC(Submit, name) \ ASSIGN_DRIVER_FUNC(Wait, name) @@ -544,7 +564,6 @@ typedef struct Refresh_Driver const char *Name; uint8_t (*PrepareDriver)(uint32_t *flags); Refresh_Device* (*CreateDevice)( - Refresh_PresentationParameters *presentationParameters, uint8_t debugMode ); } Refresh_Driver; diff --git a/src/Refresh_Driver_Vulkan.c b/src/Refresh_Driver_Vulkan.c index ecd407e..d53e1be 100644 --- a/src/Refresh_Driver_Vulkan.c +++ b/src/Refresh_Driver_Vulkan.c @@ -1691,8 +1691,6 @@ typedef struct VulkanRenderer VkQueue computeQueue; VkQueue transferQueue; - Refresh_PresentMode presentMode; - VulkanCommandBuffer **submittedCommandBuffers; uint32_t submittedCommandBufferCount; uint32_t submittedCommandBufferCapacity; @@ -4252,7 +4250,8 @@ static uint8_t VULKAN_INTERNAL_ChooseSwapPresentMode( static uint8_t VULKAN_INTERNAL_CreateSwapchain( VulkanRenderer *renderer, - void *windowHandle + void *windowHandle, + Refresh_PresentMode presentMode ) { VkResult vulkanResult; VulkanSwapchainData *swapchainData; @@ -4351,7 +4350,7 @@ static uint8_t VULKAN_INTERNAL_CreateSwapchain( } if (!VULKAN_INTERNAL_ChooseSwapPresentMode( - renderer->presentMode, + presentMode, swapchainSupportDetails.presentModes, swapchainSupportDetails.presentModesLength, &swapchainData->presentMode @@ -4642,11 +4641,12 @@ static uint8_t VULKAN_INTERNAL_CreateSwapchain( static void VULKAN_INTERNAL_RecreateSwapchain( VulkanRenderer* renderer, - void *windowHandle + void *windowHandle, + Refresh_PresentMode presentMode ) { VULKAN_Wait((Refresh_Renderer*) renderer); VULKAN_INTERNAL_DestroySwapchain(renderer, windowHandle); - VULKAN_INTERNAL_CreateSwapchain(renderer, windowHandle); + VULKAN_INTERNAL_CreateSwapchain(renderer, windowHandle, presentMode); } /* Command Buffers */ @@ -9265,22 +9265,39 @@ static Refresh_CommandBuffer* VULKAN_AcquireCommandBuffer( } static VulkanSwapchainData* VULKAN_INTERNAL_FetchSwapchainData( - VulkanRenderer *renderer, void *windowHandle ) { - VulkanSwapchainData *swapchainData = NULL; + return (VulkanSwapchainData*) SDL_GetWindowData(windowHandle, WINDOW_SWAPCHAIN_DATA); +} - swapchainData = (VulkanSwapchainData*) SDL_GetWindowData(windowHandle, WINDOW_SWAPCHAIN_DATA); +static uint8_t VULKAN_ClaimWindow( + Refresh_Renderer *driverData, + void *windowHandle, + Refresh_PresentMode presentMode +) { + VulkanRenderer *renderer = (VulkanRenderer*) driverData; + VulkanSwapchainData *swapchainData = VULKAN_INTERNAL_FetchSwapchainData(windowHandle); if (swapchainData == NULL) { - if (VULKAN_INTERNAL_CreateSwapchain(renderer, windowHandle)) - { - swapchainData = (VulkanSwapchainData*) SDL_GetWindowData(windowHandle, WINDOW_SWAPCHAIN_DATA); - } + return VULKAN_INTERNAL_CreateSwapchain(renderer, windowHandle, presentMode); } + else + { + Refresh_LogWarn("Window already claimed!"); + return 0; + } +} - return swapchainData; +static void VULKAN_UnclaimWindow( + Refresh_Renderer *driverData, + void *windowHandle +) { + VULKAN_Wait(driverData); + VULKAN_INTERNAL_DestroySwapchain( + (VulkanRenderer*) driverData, + windowHandle + ); } static Refresh_Texture* VULKAN_AcquireSwapchainTexture( @@ -9298,10 +9315,11 @@ static Refresh_Texture* VULKAN_AcquireSwapchainTexture( VulkanTexture *swapchainTexture = NULL; VulkanPresentData *presentData; - swapchainData = VULKAN_INTERNAL_FetchSwapchainData(renderer, windowHandle); + swapchainData = VULKAN_INTERNAL_FetchSwapchainData(windowHandle); if (swapchainData == NULL) { + Refresh_LogError("Cannot acquire swapchain texture, window has not been claimed!"); return NULL; } @@ -9317,12 +9335,15 @@ static Refresh_Texture* VULKAN_AcquireSwapchainTexture( /* Swapchain is invalid, let's try to recreate */ if (acquireResult != VK_SUCCESS && acquireResult != VK_SUBOPTIMAL_KHR) { - VULKAN_INTERNAL_RecreateSwapchain(renderer, windowHandle); + swapchainData = VULKAN_INTERNAL_FetchSwapchainData(windowHandle); - swapchainData = VULKAN_INTERNAL_FetchSwapchainData(renderer, windowHandle); + VULKAN_INTERNAL_RecreateSwapchain(renderer, windowHandle, swapchainData->presentMode); + + swapchainData = VULKAN_INTERNAL_FetchSwapchainData(windowHandle); if (swapchainData == NULL) { + Refresh_LogWarn("Failed to recreate swapchain!"); return NULL; } @@ -9433,6 +9454,26 @@ static Refresh_TextureFormat VULKAN_GetSwapchainFormat( } } +static void VULKAN_SetSwapchainPresentMode( + Refresh_Renderer *driverData, + void *windowHandle, + Refresh_PresentMode presentMode +) { + VulkanSwapchainData *swapchainData = (VulkanSwapchainData*) SDL_GetWindowData(windowHandle, WINDOW_SWAPCHAIN_DATA); + + if (swapchainData == NULL) + { + Refresh_LogWarn("Cannot set present mode, window has not been claimed!"); + return; + } + + VULKAN_INTERNAL_RecreateSwapchain( + (VulkanRenderer *)driverData, + windowHandle, + presentMode + ); +} + /* Submission structure */ static void VULKAN_INTERNAL_PerformPendingDestroys( @@ -9842,7 +9883,11 @@ static void VULKAN_Submit( if (presentResult != VK_SUCCESS) { - VULKAN_INTERNAL_RecreateSwapchain(renderer, presentData->swapchainData->windowHandle); + VULKAN_INTERNAL_RecreateSwapchain( + renderer, + presentData->swapchainData->windowHandle, + presentData->swapchainData->presentMode + ); } } } @@ -10543,17 +10588,14 @@ static void VULKAN_INTERNAL_LoadEntryPoints() #include "Refresh_Driver_Vulkan_vkfuncs.h" } -static uint8_t VULKAN_PrepareDriver(uint32_t *flags) -{ +static uint8_t VULKAN_INTERNAL_PrepareVulkan( + VulkanRenderer *renderer +) { SDL_Window *dummyWindowHandle; - VulkanRenderer *renderer; VkSurfaceKHR surface; - uint8_t result; VULKAN_INTERNAL_LoadEntryPoints(); - /* Test if we can create a Vulkan device */ - dummyWindowHandle = SDL_CreateWindow( "Refresh Vulkan", 0, 0, @@ -10567,10 +10609,6 @@ static uint8_t VULKAN_PrepareDriver(uint32_t *flags) return 0; } - /* 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, dummyWindowHandle)) { SDL_DestroyWindow(dummyWindowHandle); @@ -10597,16 +10635,30 @@ static uint8_t VULKAN_PrepareDriver(uint32_t *flags) renderer->func = (vkfntype_##func) vkGetInstanceProcAddr(renderer->instance, #func); #include "Refresh_Driver_Vulkan_vkfuncs.h" - result = VULKAN_INTERNAL_DeterminePhysicalDevice(renderer, surface); + if (!VULKAN_INTERNAL_DeterminePhysicalDevice(renderer, surface)) + { + return 0; + } renderer->vkDestroySurfaceKHR( renderer->instance, surface, NULL ); - renderer->vkDestroyInstance(renderer->instance, NULL); SDL_DestroyWindow(dummyWindowHandle); - SDL_free(renderer); + + return 1; +} + +static uint8_t VULKAN_PrepareDriver(uint32_t *flags) +{ + /* Set up dummy VulkanRenderer */ + VulkanRenderer *renderer = (VulkanRenderer*) SDL_malloc(sizeof(VulkanRenderer)); + uint8_t result; + + SDL_memset(renderer, '\0', sizeof(VulkanRenderer)); + + result = VULKAN_INTERNAL_PrepareVulkan(renderer); if (!result) { @@ -10617,15 +10669,15 @@ static uint8_t VULKAN_PrepareDriver(uint32_t *flags) *flags = SDL_WINDOW_VULKAN; } + renderer->vkDestroyInstance(renderer->instance, NULL); + SDL_free(renderer); return result; } static Refresh_Device* VULKAN_CreateDevice( - Refresh_PresentationParameters *presentationParameters, uint8_t debugMode ) { VulkanRenderer *renderer = (VulkanRenderer*) SDL_malloc(sizeof(VulkanRenderer)); - VkSurfaceKHR surface; Refresh_Device *result; VkResult vulkanResult; @@ -10650,64 +10702,14 @@ static Refresh_Device* VULKAN_CreateDevice( /* Variables: Image Format Detection */ VkImageFormatProperties imageFormatProperties; - VULKAN_INTERNAL_LoadEntryPoints(renderer); - - renderer->presentMode = presentationParameters->presentMode; renderer->debugMode = debugMode; - /* Create the VkInstance */ - if (!VULKAN_INTERNAL_CreateInstance(renderer, presentationParameters->deviceWindowHandle)) + if (!VULKAN_INTERNAL_PrepareVulkan(renderer)) { - Refresh_LogError("Error creating vulkan instance"); + Refresh_LogError("Failed to initialize Vulkan!"); return NULL; } - /* - * Create the WSI vkSurface - */ - - if (!SDL_Vulkan_CreateSurface( - (SDL_Window*)presentationParameters->deviceWindowHandle, - renderer->instance, - &surface - )) { - Refresh_LogError( - "SDL_Vulkan_CreateSurface failed: %s", - SDL_GetError() - ); - return NULL; - } - - /* - * Get vkInstance entry points - */ - - #define VULKAN_INSTANCE_FUNCTION(ext, ret, func, params) \ - renderer->func = (vkfntype_##func) vkGetInstanceProcAddr(renderer->instance, #func); - #include "Refresh_Driver_Vulkan_vkfuncs.h" - - /* - * Choose/Create vkDevice - */ - - if (SDL_strcmp(SDL_GetPlatform(), "Stadia") != 0) - { - deviceExtensionCount -= 1; - } - if (!VULKAN_INTERNAL_DeterminePhysicalDevice( - renderer, - surface - )) { - Refresh_LogError("Failed to determine a suitable physical device"); - return NULL; - } - - renderer->vkDestroySurfaceKHR( - renderer->instance, - surface, - NULL - ); - Refresh_LogInfo("Refresh Driver: Vulkan"); Refresh_LogInfo( "Vulkan Device: %s", @@ -10749,7 +10751,7 @@ static Refresh_Device* VULKAN_CreateDevice( result->driverData = (Refresh_Renderer*) renderer; /* - * Create initial swapchain + * Create initial swapchain array */ renderer->swapchainDataCapacity = 1; @@ -10758,12 +10760,6 @@ static Refresh_Device* VULKAN_CreateDevice( renderer->swapchainDataCapacity * sizeof(VulkanSwapchainData*) ); - if (!VULKAN_INTERNAL_CreateSwapchain(renderer, presentationParameters->deviceWindowHandle)) - { - Refresh_LogError("Failed to create swapchain"); - return NULL; - } - /* Threading */ renderer->allocatorLock = SDL_CreateMutex();