Skip to content

Commit

Permalink
GPU: Add SDL_CancelGPUCommandBuffer
Browse files Browse the repository at this point in the history
  • Loading branch information
thatcosmonaut committed Oct 24, 2024
1 parent 7108291 commit 8fe02ce
Show file tree
Hide file tree
Showing 9 changed files with 247 additions and 102 deletions.
27 changes: 27 additions & 0 deletions include/SDL3/SDL_gpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -3529,6 +3529,11 @@ extern SDL_DECLSPEC SDL_GPUTextureFormat SDLCALL SDL_GetGPUSwapchainTextureForma
* 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 @@ -3542,9 +3547,11 @@ extern SDL_DECLSPEC SDL_GPUTextureFormat SDLCALL SDL_GetGPUSwapchainTextureForma
*
* \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
*/
extern SDL_DECLSPEC bool SDLCALL SDL_AcquireGPUSwapchainTexture(
Expand Down Expand Up @@ -3603,6 +3610,26 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SubmitGPUCommandBuffer(
extern SDL_DECLSPEC SDL_GPUFence *SDLCALL SDL_SubmitGPUCommandBufferAndAcquireFence(
SDL_GPUCommandBuffer *command_buffer);

/**
* Cancels a command buffer. None of the enqueued commands are executed.
*
* This must be called from the thread the command buffer was acquired on.
*
* You must not reference the command buffer after calling this function.
* It is an error to call this function after a swapchain texture has been acquired.
*
* \param command_buffer a command buffer.
* \returns true on success, false on error; call SDL_GetError() for more
* information.
*
* \since This function is available since SDL 3.2.0.
*
* \sa SDL_AcquireGPUCommandBuffer
* \sa SDL_AcquireGPUSwapchainTexture
*/
extern SDL_DECLSPEC bool SDLCALL SDL_CancelGPUCommandBuffer(
SDL_GPUCommandBuffer *command_buffer);

/**
* Blocks the thread until the GPU is completely idle.
*
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 @@ -1183,6 +1183,7 @@ SDL3_0.0.0 {
SDL_GetDefaultLogOutputFunction;
SDL_RenderDebugText;
SDL_GetSandbox;
SDL_CancelGPUCommandBuffer;
# 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 @@ -1208,3 +1208,4 @@
#define SDL_GetDefaultLogOutputFunction SDL_GetDefaultLogOutputFunction_REAL
#define SDL_RenderDebugText SDL_RenderDebugText_REAL
#define SDL_GetSandbox SDL_GetSandbox_REAL
#define SDL_CancelGPUCommandBuffer SDL_CancelGPUCommandBuffer_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 @@ -1214,3 +1214,4 @@ SDL_DYNAPI_PROC(bool,SDL_SetErrorV,(SDL_PRINTF_FORMAT_STRING const char *a,va_li
SDL_DYNAPI_PROC(SDL_LogOutputFunction,SDL_GetDefaultLogOutputFunction,(void),(),return)
SDL_DYNAPI_PROC(bool,SDL_RenderDebugText,(SDL_Renderer *a,float b,float c,const char *d),(a,b,c,d),return)
SDL_DYNAPI_PROC(SDL_Sandbox,SDL_GetSandbox,(void),(),return)
SDL_DYNAPI_PROC(bool,SDL_CancelGPUCommandBuffer,(SDL_GPUCommandBuffer *a),(a),return)
32 changes: 31 additions & 1 deletion src/gpu/SDL_gpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -1301,6 +1301,7 @@ SDL_GPUCommandBuffer *SDL_AcquireGPUCommandBuffer(
commandBufferHeader->compute_pipeline_bound = false;
commandBufferHeader->copy_pass.command_buffer = command_buffer;
commandBufferHeader->copy_pass.in_progress = false;
commandBufferHeader->swapchain_texture_acquired = false;
commandBufferHeader->submitted = false;

return command_buffer;
Expand Down Expand Up @@ -2666,6 +2667,8 @@ bool SDL_AcquireGPUSwapchainTexture(
Uint32 *swapchain_texture_width,
Uint32 *swapchain_texture_height)
{
CommandBufferCommonHeader *commandBufferHeader = (CommandBufferCommonHeader *)command_buffer;

if (command_buffer == NULL) {
SDL_InvalidParamError("command_buffer");
return false;
Expand All @@ -2684,12 +2687,18 @@ bool SDL_AcquireGPUSwapchainTexture(
CHECK_ANY_PASS_IN_PROGRESS("Cannot acquire a swapchain texture during a pass!", false)
}

return COMMAND_BUFFER_DEVICE->AcquireSwapchainTexture(
bool result = COMMAND_BUFFER_DEVICE->AcquireSwapchainTexture(
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(
Expand Down Expand Up @@ -2746,6 +2755,27 @@ SDL_GPUFence *SDL_SubmitGPUCommandBufferAndAcquireFence(
command_buffer);
}

bool SDL_CancelGPUCommandBuffer(
SDL_GPUCommandBuffer *command_buffer)
{
CommandBufferCommonHeader *commandBufferHeader = (CommandBufferCommonHeader *)command_buffer;

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

if (COMMAND_BUFFER_DEVICE->debug_mode) {
if (commandBufferHeader->swapchain_texture_acquired) {
SDL_assert_release(!"Cannot cancel command buffer after a swapchain texture has been acquired!");
return false;
}
}

return COMMAND_BUFFER_DEVICE->Cancel(
command_buffer);
}

bool SDL_WaitForGPUIdle(
SDL_GPUDevice *device)
{
Expand Down
5 changes: 5 additions & 0 deletions src/gpu/SDL_sysgpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ typedef struct CommandBufferCommonHeader
Pass compute_pass;
bool compute_pipeline_bound;
Pass copy_pass;
bool swapchain_texture_acquired;
bool submitted;
} CommandBufferCommonHeader;

Expand Down Expand Up @@ -810,6 +811,9 @@ struct SDL_GPUDevice
SDL_GPUFence *(*SubmitAndAcquireFence)(
SDL_GPUCommandBuffer *commandBuffer);

bool (*Cancel)(
SDL_GPUCommandBuffer *commandBuffer);

bool (*Wait)(
SDL_GPURenderer *driverData);

Expand Down Expand Up @@ -928,6 +932,7 @@ struct SDL_GPUDevice
ASSIGN_DRIVER_FUNC(AcquireSwapchainTexture, name) \
ASSIGN_DRIVER_FUNC(Submit, name) \
ASSIGN_DRIVER_FUNC(SubmitAndAcquireFence, name) \
ASSIGN_DRIVER_FUNC(Cancel, name) \
ASSIGN_DRIVER_FUNC(Wait, name) \
ASSIGN_DRIVER_FUNC(WaitForFences, name) \
ASSIGN_DRIVER_FUNC(QueryFence, name) \
Expand Down
68 changes: 45 additions & 23 deletions src/gpu/d3d11/SDL_gpu_d3d11.c
Original file line number Diff line number Diff line change
Expand Up @@ -3280,15 +3280,8 @@ static SDL_GPUCommandBuffer *D3D11_AcquireCommandBuffer(
SDL_zeroa(commandBuffer->computeReadWriteStorageTextureSubresources);
SDL_zeroa(commandBuffer->computeReadWriteStorageBuffers);

bool acquireFenceResult = D3D11_INTERNAL_AcquireFence(commandBuffer);
commandBuffer->autoReleaseFence = 1;

SDL_UnlockMutex(renderer->acquireCommandBufferLock);

if (!acquireFenceResult) {
return NULL;
}

return (SDL_GPUCommandBuffer *)commandBuffer;
}

Expand Down Expand Up @@ -4806,7 +4799,8 @@ static bool D3D11_INTERNAL_MapAndCopyTextureDownload(

static bool D3D11_INTERNAL_CleanCommandBuffer(
D3D11Renderer *renderer,
D3D11CommandBuffer *commandBuffer)
D3D11CommandBuffer *commandBuffer,
bool cancel)
{
Uint32 i, j;
bool result = true;
Expand All @@ -4817,17 +4811,21 @@ static bool D3D11_INTERNAL_CleanCommandBuffer(
D3D11TransferBuffer *transferBuffer = commandBuffer->usedTransferBuffers[i];

for (j = 0; j < transferBuffer->bufferDownloadCount; j += 1) {
result &= D3D11_INTERNAL_MapAndCopyBufferDownload(
renderer,
transferBuffer,
&transferBuffer->bufferDownloads[j]);
if (!cancel) {
result &= D3D11_INTERNAL_MapAndCopyBufferDownload(
renderer,
transferBuffer,
&transferBuffer->bufferDownloads[j]);
}
}

for (j = 0; j < transferBuffer->textureDownloadCount; j += 1) {
result &= D3D11_INTERNAL_MapAndCopyTextureDownload(
renderer,
transferBuffer,
&transferBuffer->textureDownloads[j]);
if (!cancel) {
result &= D3D11_INTERNAL_MapAndCopyTextureDownload(
renderer,
transferBuffer,
&transferBuffer->textureDownloads[j]);
}
}

transferBuffer->bufferDownloadCount = 0;
Expand Down Expand Up @@ -4887,10 +4885,12 @@ static bool D3D11_INTERNAL_CleanCommandBuffer(
SDL_UnlockMutex(renderer->acquireCommandBufferLock);

// Remove this command buffer from the submitted list
for (i = 0; i < renderer->submittedCommandBufferCount; i += 1) {
if (renderer->submittedCommandBuffers[i] == commandBuffer) {
renderer->submittedCommandBuffers[i] = renderer->submittedCommandBuffers[renderer->submittedCommandBufferCount - 1];
renderer->submittedCommandBufferCount -= 1;
if (!cancel) {
for (i = 0; i < renderer->submittedCommandBufferCount; i += 1) {
if (renderer->submittedCommandBuffers[i] == commandBuffer) {
renderer->submittedCommandBuffers[i] = renderer->submittedCommandBuffers[renderer->submittedCommandBufferCount - 1];
renderer->submittedCommandBufferCount -= 1;
}
}
}

Expand Down Expand Up @@ -5024,7 +5024,8 @@ static bool D3D11_WaitForFences(
if (res == S_OK) {
result &= D3D11_INTERNAL_CleanCommandBuffer(
renderer,
renderer->submittedCommandBuffers[i]);
renderer->submittedCommandBuffers[i],
false);
}
}

Expand Down Expand Up @@ -5696,6 +5697,11 @@ static bool D3D11_Submit(

SDL_LockMutex(renderer->contextLock);

if (!D3D11_INTERNAL_AcquireFence(d3d11CommandBuffer)) {
return false;
}
d3d11CommandBuffer->autoReleaseFence = 1;

// Notify the command buffer completion query that we have completed recording
ID3D11DeviceContext_End(
renderer->immediateContext,
Expand Down Expand Up @@ -5778,7 +5784,8 @@ static bool D3D11_Submit(
if (res == S_OK) {
result &= D3D11_INTERNAL_CleanCommandBuffer(
renderer,
renderer->submittedCommandBuffers[i]);
renderer->submittedCommandBuffers[i],
false);
}
}

Expand All @@ -5801,6 +5808,21 @@ static SDL_GPUFence *D3D11_SubmitAndAcquireFence(
return (SDL_GPUFence *)fence;
}

static bool D3D11_Cancel(
SDL_GPUCommandBuffer *commandBuffer)
{
D3D11CommandBuffer *d3d11CommandBuffer = (D3D11CommandBuffer *)commandBuffer;
D3D11Renderer *renderer = d3d11CommandBuffer->renderer;
bool result;

d3d11CommandBuffer->autoReleaseFence = 0;
SDL_LockMutex(renderer->contextLock);
result = D3D11_INTERNAL_CleanCommandBuffer(renderer, d3d11CommandBuffer, true);
SDL_UnlockMutex(renderer->contextLock);

return result;
}

static bool D3D11_Wait(
SDL_GPURenderer *driverData)
{
Expand All @@ -5822,7 +5844,7 @@ static bool D3D11_Wait(

for (Sint32 i = renderer->submittedCommandBufferCount - 1; i >= 0; i -= 1) {
commandBuffer = renderer->submittedCommandBuffers[i];
result &= D3D11_INTERNAL_CleanCommandBuffer(renderer, commandBuffer);
result &= D3D11_INTERNAL_CleanCommandBuffer(renderer, commandBuffer, false);
}

D3D11_INTERNAL_PerformPendingDestroys(renderer);
Expand Down
50 changes: 38 additions & 12 deletions src/gpu/d3d12/SDL_gpu_d3d12.c
Original file line number Diff line number Diff line change
Expand Up @@ -7176,18 +7176,20 @@ static bool D3D12_INTERNAL_CopyTextureDownload(

static bool D3D12_INTERNAL_CleanCommandBuffer(
D3D12Renderer *renderer,
D3D12CommandBuffer *commandBuffer)
D3D12CommandBuffer *commandBuffer,
bool cancel)
{
Uint32 i;
HRESULT res;
bool result = true;

// Perform deferred texture data copies

for (i = 0; i < commandBuffer->textureDownloadCount; i += 1) {
result &= D3D12_INTERNAL_CopyTextureDownload(
commandBuffer,
commandBuffer->textureDownloads[i]);
if (!cancel) {
result &= D3D12_INTERNAL_CopyTextureDownload(
commandBuffer,
commandBuffer->textureDownloads[i]);
}
SDL_free(commandBuffer->textureDownloads[i]);
}
commandBuffer->textureDownloadCount = 0;
Expand Down Expand Up @@ -7280,10 +7282,12 @@ static bool D3D12_INTERNAL_CleanCommandBuffer(
SDL_UnlockMutex(renderer->acquireCommandBufferLock);

// Remove this command buffer from the submitted list
for (i = 0; i < renderer->submittedCommandBufferCount; i += 1) {
if (renderer->submittedCommandBuffers[i] == commandBuffer) {
renderer->submittedCommandBuffers[i] = renderer->submittedCommandBuffers[renderer->submittedCommandBufferCount - 1];
renderer->submittedCommandBufferCount -= 1;
if (!cancel) {
for (i = 0; i < renderer->submittedCommandBufferCount; i += 1) {
if (renderer->submittedCommandBuffers[i] == commandBuffer) {
renderer->submittedCommandBuffers[i] = renderer->submittedCommandBuffers[renderer->submittedCommandBufferCount - 1];
renderer->submittedCommandBufferCount -= 1;
}
}
}

Expand Down Expand Up @@ -7452,7 +7456,8 @@ static bool D3D12_Submit(
if (fenceValue == D3D12_FENCE_SIGNAL_VALUE) {
result &= D3D12_INTERNAL_CleanCommandBuffer(
renderer,
renderer->submittedCommandBuffers[i]);
renderer->submittedCommandBuffers[i],
false);
}
}

Expand All @@ -7472,6 +7477,26 @@ static SDL_GPUFence *D3D12_SubmitAndAcquireFence(
return (SDL_GPUFence *)d3d12CommandBuffer->inFlightFence;
}

static bool D3D12_Cancel(
SDL_GPUCommandBuffer *commandBuffer)
{
D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer;
D3D12Renderer *renderer = d3d12CommandBuffer->renderer;
bool result;
HRESULT res;

// Notify the command buffer that we have completed recording
res = ID3D12GraphicsCommandList_Close(d3d12CommandBuffer->graphicsCommandList);
CHECK_D3D12_ERROR_AND_RETURN("Failed to close command list!", false);

d3d12CommandBuffer->autoReleaseFence = 0;
SDL_LockMutex(renderer->submitLock);
result = D3D12_INTERNAL_CleanCommandBuffer(renderer, d3d12CommandBuffer, true);
SDL_UnlockMutex(renderer->submitLock);

return result;
}

static bool D3D12_Wait(
SDL_GPURenderer *driverData)
{
Expand Down Expand Up @@ -7515,7 +7540,7 @@ static bool D3D12_Wait(

// Clean up
for (Sint32 i = renderer->submittedCommandBufferCount - 1; i >= 0; i -= 1) {
result &= D3D12_INTERNAL_CleanCommandBuffer(renderer, renderer->submittedCommandBuffers[i]);
result &= D3D12_INTERNAL_CleanCommandBuffer(renderer, renderer->submittedCommandBuffers[i], false);
}

D3D12_INTERNAL_PerformPendingDestroys(renderer);
Expand Down Expand Up @@ -7571,7 +7596,8 @@ static bool D3D12_WaitForFences(
if (fenceValue == D3D12_FENCE_SIGNAL_VALUE) {
result &= D3D12_INTERNAL_CleanCommandBuffer(
renderer,
renderer->submittedCommandBuffers[i]);
renderer->submittedCommandBuffers[i],
false);
}
}

Expand Down
Loading

0 comments on commit 8fe02ce

Please sign in to comment.