GPU: Revise swapchain acquisition (#11633)

---------

Co-authored-by: Lucas Murray <22484+lmurray@users.noreply.github.com>
This commit is contained in:
Evan Hemsley 2024-12-11 11:16:35 -08:00 committed by GitHub
parent bbd4eeb287
commit 3ee39f6c3f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 337 additions and 51 deletions

View file

@ -1068,8 +1068,7 @@ typedef enum SDL_GPUSamplerAddressMode
* Specifies the timing that will be used to present swapchain textures to the
* OS.
*
* Note that this value affects the behavior of
* SDL_AcquireGPUSwapchainTexture. VSYNC mode will always be supported.
* VSYNC mode will always be supported.
* IMMEDIATE and MAILBOX modes may not be supported on certain systems.
*
* It is recommended to query SDL_WindowSupportsGPUPresentMode after claiming
@ -1077,17 +1076,12 @@ typedef enum SDL_GPUSamplerAddressMode
*
* - VSYNC: Waits for vblank before presenting. No tearing is possible. If
* there is a pending image to present, the new image is enqueued for
* presentation. Disallows tearing at the cost of visual latency. When using
* this present mode, AcquireGPUSwapchainTexture will block if too many
* frames are in flight.
* presentation. Disallows tearing at the cost of visual latency.
* - IMMEDIATE: Immediately presents. Lowest latency option, but tearing may
* occur. When using this mode, AcquireGPUSwapchainTexture will fill the
* swapchain texture pointer with NULL if too many frames are in flight.
* occur.
* - MAILBOX: Waits for vblank before presenting. No tearing is possible. If
* there is a pending image to present, the pending image is replaced by the
* new image. Similar to VSYNC, but with reduced visual latency. When using
* this mode, AcquireGPUSwapchainTexture will fill the swapchain texture
* pointer with NULL if too many frames are in flight.
* new image. Similar to VSYNC, but with reduced visual latency.
*
* \since This enum is available since SDL 3.1.3
*
@ -3442,6 +3436,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_WindowSupportsGPUPresentMode(
* \returns true on success, or false on failure; call SDL_GetError() for more
* information.
*
* \threadsafety This function should only be called from the thread that created the window.
*
* \since This function is available since SDL 3.1.3.
*
* \sa SDL_AcquireGPUSwapchainTexture
@ -3501,8 +3497,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetGPUSwapchainParameters(
*
* The default value when the device is created is 2. This means that after
* you have submitted 2 frames for presentation, if the GPU has not finished
* working on the first frame, SDL_AcquireGPUSwapchainTexture() will block or
* return false depending on the present mode.
* working on the first frame, SDL_AcquireGPUSwapchainTexture() will fill the swapchain texture pointer with NULL,
* and SDL_WaitAndAcquireGPUSwapchainTexture() will block.
*
* Higher values increase throughput at the expense of visual latency. Lower
* values decrease visual latency at the expense of throughput.
@ -3514,9 +3510,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetGPUSwapchainParameters(
*
* \param device a GPU context.
* \param allowed_frames_in_flight the maximum number of frames that can be
* pending on the GPU before
* AcquireSwapchainTexture blocks or returns
* false.
* pending on the GPU.
* \returns true if successful, false on error; call SDL_GetError() for more
* information.
*
@ -3547,20 +3541,17 @@ extern SDL_DECLSPEC SDL_GPUTextureFormat SDLCALL SDL_GetGPUSwapchainTextureForma
* When a swapchain texture is acquired on a command buffer, it will
* automatically be submitted for presentation when the command buffer is
* submitted. The swapchain texture should only be referenced by the command
* buffer used to acquire it. The swapchain texture handle can be filled in
* with NULL under certain conditions. This is not necessarily an error. If
* this function returns false then there is an error.
* buffer used to acquire it.
*
* This function will fill the swapchain texture handle with NULL if too many frames are in flight.
* This is not an error.
* The best practice is to call SDL_CancelGPUCommandBuffer if the swapchain texture
* handle is NULL to avoid enqueuing needless work on the GPU.
*
* The swapchain texture is managed by the implementation and must not be
* freed by the user. You MUST NOT call this function from any thread other
* than the one that created the window.
*
* When using SDL_GPU_PRESENTMODE_VSYNC, this function will block if too many
* frames are in flight. Otherwise, this function will fill the swapchain
* texture handle with NULL if too many frames are in flight. The best
* practice is to call SDL_CancelGPUCommandBuffer if the swapchain texture
* handle is NULL to avoid enqueuing needless work on the GPU.
*
* \param command_buffer a command buffer.
* \param window a window that has been claimed.
* \param swapchain_texture a pointer filled in with a swapchain texture
@ -3572,14 +3563,17 @@ extern SDL_DECLSPEC SDL_GPUTextureFormat SDLCALL SDL_GetGPUSwapchainTextureForma
* \returns true on success, false on error; call SDL_GetError() for more
* information.
*
* \threadsafety This function should only be called from the thread that created the window.
*
* \since This function is available since SDL 3.1.3.
*
* \sa SDL_GPUPresentMode
* \sa SDL_ClaimWindowForGPUDevice
* \sa SDL_SubmitGPUCommandBuffer
* \sa SDL_SubmitGPUCommandBufferAndAcquireFence
* \sa SDL_CancelGPUCommandBuffer
* \sa SDL_GetWindowSizeInPixels
* \sa SDL_WaitForGPUSwapchain
* \sa SDL_SetGPUAllowedFramesInFlight
*/
extern SDL_DECLSPEC bool SDLCALL SDL_AcquireGPUSwapchainTexture(
SDL_GPUCommandBuffer *command_buffer,
@ -3588,6 +3582,62 @@ extern SDL_DECLSPEC bool SDLCALL SDL_AcquireGPUSwapchainTexture(
Uint32 *swapchain_texture_width,
Uint32 *swapchain_texture_height);
/**
* Blocks the thread until a swapchain texture is available to be acquired.
*
* \param device a GPU context.
* \param window a window that has been claimed.
* \returns true on success, false on failure; call SDL_GetError() for more
* information.
*
* \threadsafety This function should only be called from the thread that created the window.
*
* \since This function is available since SDL 3.2.0.
*
* \sa SDL_AcquireGPUSwapchainTexture
* \sa SDL_SetGPUAllowedFramesInFlight
*/
extern SDL_DECLSPEC bool SDLCALL SDL_WaitForGPUSwapchain(
SDL_GPUDevice *device,
SDL_Window *window);
/**
* Blocks the thread until a swapchain texture is available to be acquired, and then acquires it.
*
* When a swapchain texture is acquired on a command buffer, it will
* automatically be submitted for presentation when the command buffer is
* submitted. The swapchain texture should only be referenced by the command
* buffer used to acquire it. It is an error to call SDL_CancelGPUCommandBuffer() after a swapchain texture is acquired.
*
* The swapchain texture is managed by the implementation and must not be
* freed by the user. You MUST NOT call this function from any thread other
* than the one that created the window.
*
* \param command_buffer a command buffer.
* \param window a window that has been claimed.
* \param swapchain_texture a pointer filled in with a swapchain texture
* handle.
* \param swapchain_texture_width a pointer filled in with the swapchain
* texture width, may be NULL.
* \param swapchain_texture_height a pointer filled in with the swapchain
* texture height, may be NULL.
* \returns true on success, false on error; call SDL_GetError() for more
* information.
*
* \threadsafety This function should only be called from the thread that created the window.
*
* \since This function is available since SDL 3.2.0.
*
* \sa SDL_SubmitGPUCommandBuffer
* \sa SDL_SubmitGPUCommandBufferAndAcquireFence
*/
extern SDL_DECLSPEC bool SDLCALL SDL_WaitAndAcquireGPUSwapchainTexture(
SDL_GPUCommandBuffer *command_buffer,
SDL_Window *window,
SDL_GPUTexture **swapchain_texture,
Uint32 *swapchain_texture_width,
Uint32 *swapchain_texture_height);
/**
* Submits a command buffer so its commands can be processed on the GPU.
*

View file

@ -974,6 +974,7 @@ SDL3_0.0.0 {
SDL_WaitEventTimeout;
SDL_WaitForGPUFences;
SDL_WaitForGPUIdle;
SDL_WaitForGPUSwapchain;
SDL_WaitProcess;
SDL_WaitSemaphore;
SDL_WaitSemaphoreTimeout;
@ -1205,6 +1206,7 @@ SDL3_0.0.0 {
SDL_RunOnMainThread;
SDL_SetGPUAllowedFramesInFlight;
SDL_RenderTextureAffine;
SDL_WaitAndAcquireGPUSwapchainTexture;
# extra symbols go here (don't modify this line)
local: *;
};

View file

@ -999,6 +999,7 @@
#define SDL_WaitEventTimeout SDL_WaitEventTimeout_REAL
#define SDL_WaitForGPUFences SDL_WaitForGPUFences_REAL
#define SDL_WaitForGPUIdle SDL_WaitForGPUIdle_REAL
#define SDL_WaitForGPUSwapchain SDL_WaitForGPUSwapchain_REAL
#define SDL_WaitProcess SDL_WaitProcess_REAL
#define SDL_WaitSemaphore SDL_WaitSemaphore_REAL
#define SDL_WaitSemaphoreTimeout SDL_WaitSemaphoreTimeout_REAL
@ -1230,3 +1231,4 @@
#define SDL_RunOnMainThread SDL_RunOnMainThread_REAL
#define SDL_SetGPUAllowedFramesInFlight SDL_SetGPUAllowedFramesInFlight_REAL
#define SDL_RenderTextureAffine SDL_RenderTextureAffine_REAL
#define SDL_WaitAndAcquireGPUSwapchainTexture SDL_WaitAndAcquireGPUSwapchainTexture_REAL

View file

@ -1009,6 +1009,7 @@ SDL_DYNAPI_PROC(bool,SDL_WaitEvent,(SDL_Event *a),(a),return)
SDL_DYNAPI_PROC(bool,SDL_WaitEventTimeout,(SDL_Event *a, Sint32 b),(a,b),return)
SDL_DYNAPI_PROC(bool,SDL_WaitForGPUFences,(SDL_GPUDevice *a, bool b, SDL_GPUFence *const *c, Uint32 d),(a,b,c,d),return)
SDL_DYNAPI_PROC(bool,SDL_WaitForGPUIdle,(SDL_GPUDevice *a),(a),return)
SDL_DYNAPI_PROC(bool,SDL_WaitForGPUSwapchain,(SDL_GPUDevice *a, SDL_Window *b),(a,b),return)
SDL_DYNAPI_PROC(bool,SDL_WaitProcess,(SDL_Process *a, bool b, int *c),(a,b,c),return)
SDL_DYNAPI_PROC(void,SDL_WaitSemaphore,(SDL_Semaphore *a),(a),)
SDL_DYNAPI_PROC(bool,SDL_WaitSemaphoreTimeout,(SDL_Semaphore *a, Sint32 b),(a,b),return)
@ -1236,3 +1237,4 @@ SDL_DYNAPI_PROC(bool,SDL_IsMainThread,(void),(),return)
SDL_DYNAPI_PROC(bool,SDL_RunOnMainThread,(SDL_MainThreadCallback a,void *b,bool c),(a,b,c),return)
SDL_DYNAPI_PROC(bool,SDL_SetGPUAllowedFramesInFlight,(SDL_GPUDevice *a,Uint32 b),(a,b),return)
SDL_DYNAPI_PROC(bool,SDL_RenderTextureAffine,(SDL_Renderer *a,SDL_Texture *b,const SDL_FRect *c,const SDL_FPoint *d,const SDL_FPoint *e,const SDL_FPoint *f),(a,b,c,d,e,f),return)
SDL_DYNAPI_PROC(bool,SDL_WaitAndAcquireGPUSwapchainTexture,(SDL_GPUCommandBuffer *a,SDL_Window *b,SDL_GPUTexture **c,Uint32 *d,Uint32 *e),(a,b,c,d,e),return)

View file

@ -2694,16 +2694,13 @@ bool SDL_AcquireGPUSwapchainTexture(
CommandBufferCommonHeader *commandBufferHeader = (CommandBufferCommonHeader *)command_buffer;
if (command_buffer == NULL) {
SDL_InvalidParamError("command_buffer");
return false;
return SDL_InvalidParamError("command_buffer");
}
if (window == NULL) {
SDL_InvalidParamError("window");
return false;
return SDL_InvalidParamError("window");
}
if (swapchain_texture == NULL) {
SDL_InvalidParamError("swapchain_texture");
return false;
return SDL_InvalidParamError("swapchain_texture");
}
if (COMMAND_BUFFER_DEVICE->debug_mode) {
@ -2725,6 +2722,59 @@ bool SDL_AcquireGPUSwapchainTexture(
return result;
}
bool SDL_WaitForGPUSwapchain(
SDL_GPUDevice *device,
SDL_Window *window)
{
CHECK_DEVICE_MAGIC(device, false);
if (window == NULL) {
return SDL_InvalidParamError("window");
}
return device->WaitForSwapchain(
device->driverData,
window);
}
bool SDL_WaitAndAcquireGPUSwapchainTexture(
SDL_GPUCommandBuffer *command_buffer,
SDL_Window *window,
SDL_GPUTexture **swapchain_texture,
Uint32 *swapchain_texture_width,
Uint32 *swapchain_texture_height)
{
CommandBufferCommonHeader *commandBufferHeader = (CommandBufferCommonHeader *)command_buffer;
if (command_buffer == NULL) {
return SDL_InvalidParamError("command_buffer");
}
if (window == NULL) {
return SDL_InvalidParamError("window");
}
if (swapchain_texture == NULL) {
return SDL_InvalidParamError("swapchain_texture");
}
if (COMMAND_BUFFER_DEVICE->debug_mode) {
CHECK_COMMAND_BUFFER_RETURN_FALSE
CHECK_ANY_PASS_IN_PROGRESS("Cannot acquire a swapchain texture during a pass!", false)
}
bool result = COMMAND_BUFFER_DEVICE->WaitAndAcquireSwapchainTexture(
command_buffer,
window,
swapchain_texture,
swapchain_texture_width,
swapchain_texture_height);
if (*swapchain_texture != NULL){
commandBufferHeader->swapchain_texture_acquired = true;
}
return result;
}
bool SDL_SubmitGPUCommandBuffer(
SDL_GPUCommandBuffer *command_buffer)
{

View file

@ -811,6 +811,17 @@ struct SDL_GPUDevice
Uint32 *swapchainTextureWidth,
Uint32 *swapchainTextureHeight);
bool (*WaitForSwapchain)(
SDL_GPURenderer *driverData,
SDL_Window *window);
bool (*WaitAndAcquireSwapchainTexture)(
SDL_GPUCommandBuffer *commandBuffer,
SDL_Window *window,
SDL_GPUTexture **swapchainTexture,
Uint32 *swapchainTextureWidth,
Uint32 *swapchainTextureHeight);
bool (*Submit)(
SDL_GPUCommandBuffer *commandBuffer);
@ -937,6 +948,8 @@ struct SDL_GPUDevice
ASSIGN_DRIVER_FUNC(GetSwapchainTextureFormat, name) \
ASSIGN_DRIVER_FUNC(AcquireCommandBuffer, name) \
ASSIGN_DRIVER_FUNC(AcquireSwapchainTexture, name) \
ASSIGN_DRIVER_FUNC(WaitForSwapchain, name) \
ASSIGN_DRIVER_FUNC(WaitAndAcquireSwapchainTexture, name)\
ASSIGN_DRIVER_FUNC(Submit, name) \
ASSIGN_DRIVER_FUNC(SubmitAndAcquireFence, name) \
ASSIGN_DRIVER_FUNC(Cancel, name) \

View file

@ -7124,7 +7124,32 @@ static SDL_GPUCommandBuffer *D3D12_AcquireCommandBuffer(
return (SDL_GPUCommandBuffer *)commandBuffer;
}
static bool D3D12_AcquireSwapchainTexture(
static bool D3D12_WaitForSwapchain(
SDL_GPURenderer *driverData,
SDL_Window *window)
{
D3D12Renderer *renderer = (D3D12Renderer *)driverData;
D3D12WindowData *windowData = D3D12_INTERNAL_FetchWindowData(window);
if (windowData == NULL) {
SET_STRING_ERROR_AND_RETURN("Cannot wait for a swapchain from an unclaimed window!", false);
}
if (windowData->inFlightFences[windowData->frameCounter] != NULL) {
if (!D3D12_WaitForFences(
driverData,
true,
&windowData->inFlightFences[windowData->frameCounter],
1)) {
return false;
}
}
return true;
}
static bool D3D12_INTERNAL_AcquireSwapchainTexture(
bool block,
SDL_GPUCommandBuffer *commandBuffer,
SDL_Window *window,
SDL_GPUTexture **swapchainTexture,
@ -7164,7 +7189,7 @@ static bool D3D12_AcquireSwapchainTexture(
}
if (windowData->inFlightFences[windowData->frameCounter] != NULL) {
if (windowData->present_mode == SDL_GPU_PRESENTMODE_VSYNC) {
if (block) {
// In VSYNC mode, block until the least recent presented frame is done
if (!D3D12_WaitForFences(
(SDL_GPURenderer *)renderer,
@ -7174,13 +7199,11 @@ static bool D3D12_AcquireSwapchainTexture(
return false;
}
} else {
// If we are not blocking and the least recent fence is not signaled,
// return true to indicate that there is no error but rendering should be skipped.
if (!D3D12_QueryFence(
(SDL_GPURenderer *)renderer,
windowData->inFlightFences[windowData->frameCounter])) {
/*
* In MAILBOX or IMMEDIATE mode, if the least recent fence is not signaled,
* return true to indicate that there is no error but rendering should be skipped
*/
return true;
}
}
@ -7238,6 +7261,38 @@ static bool D3D12_AcquireSwapchainTexture(
return true;
}
static bool D3D12_AcquireSwapchainTexture(
SDL_GPUCommandBuffer *command_buffer,
SDL_Window *window,
SDL_GPUTexture **swapchain_texture,
Uint32 *swapchain_texture_width,
Uint32 *swapchain_texture_height
) {
return D3D12_INTERNAL_AcquireSwapchainTexture(
false,
command_buffer,
window,
swapchain_texture,
swapchain_texture_width,
swapchain_texture_height);
}
static bool D3D12_WaitAndAcquireSwapchainTexture(
SDL_GPUCommandBuffer *command_buffer,
SDL_Window *window,
SDL_GPUTexture **swapchain_texture,
Uint32 *swapchain_texture_width,
Uint32 *swapchain_texture_height
) {
return D3D12_INTERNAL_AcquireSwapchainTexture(
true,
command_buffer,
window,
swapchain_texture,
swapchain_texture_width,
swapchain_texture_height);
}
static void D3D12_INTERNAL_PerformPendingDestroys(D3D12Renderer *renderer)
{
SDL_LockMutex(renderer->disposeLock);

View file

@ -3671,7 +3671,34 @@ static void METAL_ReleaseWindow(
}
}
static bool METAL_AcquireSwapchainTexture(
static bool METAL_WaitForSwapchain(
SDL_GPURenderer *driverData,
SDL_Window *window)
{
@autoreleasepool {
MetalRenderer *renderer = (MetalRenderer *)driverData;
MetalWindowData *windowData = METAL_INTERNAL_FetchWindowData(window);
if (windowData == NULL) {
SET_STRING_ERROR_AND_RETURN("Cannot wait for a swapchain from an unclaimed window!", false);
}
if (windowData->inFlightFences[windowData->frameCounter] != NULL) {
if (!METAL_WaitForFences(
driverData,
true,
&windowData->inFlightFences[windowData->frameCounter],
1)) {
return false;
}
}
return true;
}
}
static bool METAL_INTERNAL_AcquireSwapchainTexture(
bool block,
SDL_GPUCommandBuffer *commandBuffer,
SDL_Window *window,
SDL_GPUTexture **texture,
@ -3709,8 +3736,8 @@ static bool METAL_AcquireSwapchainTexture(
}
if (windowData->inFlightFences[windowData->frameCounter] != NULL) {
if (windowData->presentMode == SDL_GPU_PRESENTMODE_VSYNC) {
// In VSYNC mode, block until the least recent presented frame is done
if (block) {
// If we are blocking, just wait for the fence!
if (!METAL_WaitForFences(
(SDL_GPURenderer *)renderer,
true,
@ -3719,13 +3746,11 @@ static bool METAL_AcquireSwapchainTexture(
return false;
}
} else {
// If we are not blocking and the least recent fence is not signaled,
// return true to indicate that there is no error but rendering should be skipped.
if (!METAL_QueryFence(
(SDL_GPURenderer *)metalCommandBuffer->renderer,
windowData->inFlightFences[windowData->frameCounter])) {
/*
* In IMMEDIATE mode, if the least recent fence is not signaled,
* return true to indicate that there is no error but rendering should be skipped
*/
return true;
}
}
@ -3757,6 +3782,38 @@ static bool METAL_AcquireSwapchainTexture(
}
}
static bool METAL_AcquireSwapchainTexture(
SDL_GPUCommandBuffer *command_buffer,
SDL_Window *window,
SDL_GPUTexture **swapchain_texture,
Uint32 *swapchain_texture_width,
Uint32 *swapchain_texture_height
) {
return METAL_INTERNAL_AcquireSwapchainTexture(
false,
command_buffer,
window,
swapchain_texture,
swapchain_texture_width,
swapchain_texture_height);
}
static bool METAL_WaitAndAcquireSwapchainTexture(
SDL_GPUCommandBuffer *command_buffer,
SDL_Window *window,
SDL_GPUTexture **swapchain_texture,
Uint32 *swapchain_texture_width,
Uint32 *swapchain_texture_height
) {
return METAL_INTERNAL_AcquireSwapchainTexture(
true,
command_buffer,
window,
swapchain_texture,
swapchain_texture_width,
swapchain_texture_height);
}
static SDL_GPUTextureFormat METAL_GetSwapchainTextureFormat(
SDL_GPURenderer *driverData,
SDL_Window *window)

View file

@ -9655,7 +9655,32 @@ static Uint32 VULKAN_INTERNAL_RecreateSwapchain(
return VULKAN_INTERNAL_CreateSwapchain(renderer, windowData);
}
static bool VULKAN_AcquireSwapchainTexture(
static bool VULKAN_WaitForSwapchain(
SDL_GPURenderer *driverData,
SDL_Window *window)
{
VulkanRenderer *renderer = (VulkanRenderer *)driverData;
WindowData *windowData = VULKAN_INTERNAL_FetchWindowData(window);
if (windowData == NULL) {
SET_STRING_ERROR_AND_RETURN("Cannot wait for a swapchain from an unclaimed window!", false);
}
if (windowData->inFlightFences[windowData->frameCounter] != NULL) {
if (!VULKAN_WaitForFences(
driverData,
true,
&windowData->inFlightFences[windowData->frameCounter],
1)) {
return false;
}
}
return true;
}
static bool VULKAN_INTERNAL_AcquireSwapchainTexture(
bool block,
SDL_GPUCommandBuffer *commandBuffer,
SDL_Window *window,
SDL_GPUTexture **swapchainTexture,
@ -9708,8 +9733,8 @@ static bool VULKAN_AcquireSwapchainTexture(
}
if (windowData->inFlightFences[windowData->frameCounter] != NULL) {
if (windowData->presentMode == SDL_GPU_PRESENTMODE_VSYNC) {
// In VSYNC mode, block until the least recent presented frame is done
if (block) {
// If we are blocking, just wait for the fence!
if (!VULKAN_WaitForFences(
(SDL_GPURenderer *)renderer,
true,
@ -9718,13 +9743,11 @@ static bool VULKAN_AcquireSwapchainTexture(
return false;
}
} else {
// If we are not blocking and the least recent fence is not signaled,
// return true to indicate that there is no error but rendering should be skipped.
if (!VULKAN_QueryFence(
(SDL_GPURenderer *)renderer,
windowData->inFlightFences[windowData->frameCounter])) {
/*
* In MAILBOX or IMMEDIATE mode, if the least recent fence is not signaled,
* return true to indicate that there is no error but rendering should be skipped
*/
return true;
}
}
@ -9843,6 +9866,38 @@ static bool VULKAN_AcquireSwapchainTexture(
return true;
}
static bool VULKAN_AcquireSwapchainTexture(
SDL_GPUCommandBuffer *command_buffer,
SDL_Window *window,
SDL_GPUTexture **swapchain_texture,
Uint32 *swapchain_texture_width,
Uint32 *swapchain_texture_height
) {
return VULKAN_INTERNAL_AcquireSwapchainTexture(
false,
command_buffer,
window,
swapchain_texture,
swapchain_texture_width,
swapchain_texture_height);
}
static bool VULKAN_WaitAndAcquireSwapchainTexture(
SDL_GPUCommandBuffer *command_buffer,
SDL_Window *window,
SDL_GPUTexture **swapchain_texture,
Uint32 *swapchain_texture_width,
Uint32 *swapchain_texture_height
) {
return VULKAN_INTERNAL_AcquireSwapchainTexture(
true,
command_buffer,
window,
swapchain_texture,
swapchain_texture_width,
swapchain_texture_height);
}
static SDL_GPUTextureFormat VULKAN_GetSwapchainTextureFormat(
SDL_GPURenderer *driverData,
SDL_Window *window)