Skip to content

Commit

Permalink
Add SDL_WaitAndAcquireGPUSwapchainTexture
Browse files Browse the repository at this point in the history
  • Loading branch information
thatcosmonaut committed Dec 11, 2024
1 parent 0c762f6 commit 08c7f61
Show file tree
Hide file tree
Showing 9 changed files with 258 additions and 80 deletions.
116 changes: 72 additions & 44 deletions include/SDL3/SDL_gpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -1068,26 +1068,20 @@ 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
* the window if you wish to change the present mode to IMMEDIATE or MAILBOX.
*
* - 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
*
Expand Down Expand Up @@ -3501,8 +3495,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
* return false, 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.
Expand All @@ -3514,9 +3508,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.
*
Expand Down Expand Up @@ -3547,20 +3539,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
Expand All @@ -3572,15 +3561,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,
Expand All @@ -3589,6 +3580,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.
*
Expand Down Expand Up @@ -3675,25 +3722,6 @@ extern SDL_DECLSPEC bool SDLCALL SDL_CancelGPUCommandBuffer(
extern SDL_DECLSPEC bool SDLCALL SDL_WaitForGPUIdle(
SDL_GPUDevice *device);

/**
* Blocks the thread until a swapchain texture is available to be acquired.
* Calling this function before SDL_AcquireGPUSwapchainTexture() will ensure
* that the acquire will immediately return a swapchain texture under most, but
* not all, conditions.
*
* \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.
*
* \since This function is available since SDL 3.2.0.
*
* \sa SDL_AcquireGPUSwapchainTexture
*/
extern SDL_DECLSPEC bool SDLCALL SDL_WaitForGPUSwapchain(
SDL_GPUDevice *device,
SDL_Window *window);

/**
* Blocks the thread until the given fences are signaled.
*
Expand Down
1 change: 1 addition & 0 deletions src/dynapi/SDL_dynapi.sym
Original file line number Diff line number Diff line change
Expand Up @@ -1206,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: *;
};
1 change: 1 addition & 0 deletions src/dynapi/SDL_dynapi_overrides.h
Original file line number Diff line number Diff line change
Expand Up @@ -1231,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
1 change: 1 addition & 0 deletions src/dynapi/SDL_dynapi_procs.h
Original file line number Diff line number Diff line change
Expand Up @@ -1237,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)
68 changes: 57 additions & 11 deletions src/gpu/SDL_gpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -2725,6 +2725,63 @@ bool SDL_AcquireGPUSwapchainTexture(
return result;
}

bool SDL_WaitForGPUSwapchain(
SDL_GPUDevice *device,
SDL_Window *window)
{
CHECK_DEVICE_MAGIC(device, false);

if (window == NULL) {
SDL_InvalidParamError("window");
return false;
}

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) {
SDL_InvalidParamError("command_buffer");
return false;
}
if (window == NULL) {
SDL_InvalidParamError("window");
return false;
}
if (swapchain_texture == NULL) {
SDL_InvalidParamError("swapchain_texture");
return false;
}

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)
{
Expand Down Expand Up @@ -2809,17 +2866,6 @@ bool SDL_WaitForGPUIdle(
device->driverData);
}

bool SDL_WaitForGPUSwapchain(
SDL_GPUDevice *device,
SDL_Window *window)
{
CHECK_DEVICE_MAGIC(device, false);

return device->WaitForSwapchain(
device->driverData,
window);
}

bool SDL_WaitForGPUFences(
SDL_GPUDevice *device,
bool wait_all,
Expand Down
18 changes: 13 additions & 5 deletions src/gpu/SDL_sysgpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand All @@ -823,10 +834,6 @@ struct SDL_GPUDevice
bool (*Wait)(
SDL_GPURenderer *driverData);

bool (*WaitForSwapchain)(
SDL_GPURenderer *driverData,
SDL_Window *window);

bool (*WaitForFences)(
SDL_GPURenderer *driverData,
bool waitAll,
Expand Down Expand Up @@ -941,11 +948,12 @@ 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) \
ASSIGN_DRIVER_FUNC(Wait, name) \
ASSIGN_DRIVER_FUNC(WaitForSwapchain, name) \
ASSIGN_DRIVER_FUNC(WaitForFences, name) \
ASSIGN_DRIVER_FUNC(QueryFence, name) \
ASSIGN_DRIVER_FUNC(ReleaseFence, name) \
Expand Down
Loading

0 comments on commit 08c7f61

Please sign in to comment.