From be401dd1e35c08baaf44000f031b81951698fc10 Mon Sep 17 00:00:00 2001 From: Evan Hemsley <2342303+thatcosmonaut@users.noreply.github.com> Date: Fri, 27 Sep 2024 00:30:18 -0700 Subject: [PATCH] GPU: More robust error reporting (#10958) --------- Co-authored-by: Ethan Lee Co-authored-by: Caleb Cornett --- include/SDL3/SDL_gpu.h | 63 +-- src/dynapi/SDL_dynapi_procs.h | 8 +- src/gpu/SDL_gpu.c | 68 ++-- src/gpu/SDL_sysgpu.h | 11 +- src/gpu/d3d11/SDL_gpu_d3d11.c | 309 +++++++-------- src/gpu/d3d12/SDL_gpu_d3d12.c | 376 +++++++++--------- src/gpu/metal/SDL_gpu_metal.m | 86 ++-- src/gpu/vulkan/SDL_gpu_vulkan.c | 682 ++++++++++++++++---------------- src/render/gpu/SDL_render_gpu.c | 18 +- test/testgpu_simple_clear.c | 7 +- test/testgpu_spinning_cube.c | 21 +- 11 files changed, 805 insertions(+), 844 deletions(-) diff --git a/include/SDL3/SDL_gpu.h b/include/SDL3/SDL_gpu.h index 04099f2408..a17dd5661d 100644 --- a/include/SDL3/SDL_gpu.h +++ b/include/SDL3/SDL_gpu.h @@ -877,15 +877,15 @@ 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, AcquireSwapchainTexture will block if too many frames + * this present mode, AcquireGPUSwapchainTexture will block if too many frames * are in flight. * - IMMEDIATE: Immediately presents. Lowest latency option, but tearing may - * occur. When using this mode, AcquireSwapchainTexture will return NULL if + * occur. When using this mode, AcquireGPUSwapchainTexture will return NULL if * too many frames are in flight. * - 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, AcquireSwapchainTexture will return NULL if too many frames + * this mode, AcquireGPUSwapchainTexture will return NULL if too many frames * are in flight. * * \since This enum is available since SDL 3.0.0 @@ -1623,6 +1623,7 @@ typedef struct SDL_GPUBlitInfo { Uint8 padding2; Uint8 padding3; } SDL_GPUBlitInfo; + /* Binding structs */ /** @@ -1731,7 +1732,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GPUSupportsProperties( * \param debug_mode enable debug mode properties and validations. * \param name the preferred GPU driver, or NULL to let SDL pick the optimal * driver. - * \returns a GPU context on success or NULL on failure. + * \returns a GPU context on success or NULL on failure; call SDL_GetError() for more information. * * \since This function is available since SDL 3.0.0. * @@ -1778,7 +1779,7 @@ extern SDL_DECLSPEC SDL_GPUDevice *SDLCALL SDL_CreateGPUDevice( * use for all vertex semantics, default is "TEXCOORD". * * \param props the properties to use. - * \returns a GPU context on success or NULL on failure. + * \returns a GPU context on success or NULL on failure; call SDL_GetError() for more information. * * \since This function is available since SDL 3.0.0. * @@ -1904,7 +1905,7 @@ extern SDL_DECLSPEC SDL_GPUShaderFormat SDLCALL SDL_GetGPUShaderFormats(SDL_GPUD * \param device a GPU Context. * \param createinfo a struct describing the state of the compute pipeline to * create. - * \returns a compute pipeline object on success, or NULL on failure. + * \returns a compute pipeline object on success, or NULL on failure; call SDL_GetError() for more information. * * \since This function is available since SDL 3.0.0. * @@ -1921,7 +1922,7 @@ extern SDL_DECLSPEC SDL_GPUComputePipeline *SDLCALL SDL_CreateGPUComputePipeline * \param device a GPU Context. * \param createinfo a struct describing the state of the graphics pipeline to * create. - * \returns a graphics pipeline object on success, or NULL on failure. + * \returns a graphics pipeline object on success, or NULL on failure; call SDL_GetError() for more information. * * \since This function is available since SDL 3.0.0. * @@ -1939,7 +1940,7 @@ extern SDL_DECLSPEC SDL_GPUGraphicsPipeline *SDLCALL SDL_CreateGPUGraphicsPipeli * * \param device a GPU Context. * \param createinfo a struct describing the state of the sampler to create. - * \returns a sampler object on success, or NULL on failure. + * \returns a sampler object on success, or NULL on failure; call SDL_GetError() for more information. * * \since This function is available since SDL 3.0.0. * @@ -2008,7 +2009,7 @@ extern SDL_DECLSPEC SDL_GPUSampler *SDLCALL SDL_CreateGPUSampler( * * \param device a GPU Context. * \param createinfo a struct describing the state of the shader to create. - * \returns a shader object on success, or NULL on failure. + * \returns a shader object on success, or NULL on failure; call SDL_GetError() for more information. * * \since This function is available since SDL 3.0.0. * @@ -2034,7 +2035,7 @@ extern SDL_DECLSPEC SDL_GPUShader *SDLCALL SDL_CreateGPUShader( * * \param device a GPU Context. * \param createinfo a struct describing the state of the texture to create. - * \returns a texture object on success, or NULL on failure. + * \returns a texture object on success, or NULL on failure; call SDL_GetError() for more information. * * \since This function is available since SDL 3.0.0. * @@ -2064,7 +2065,7 @@ extern SDL_DECLSPEC SDL_GPUTexture *SDLCALL SDL_CreateGPUTexture( * * \param device a GPU Context. * \param createinfo a struct describing the state of the buffer to create. - * \returns a buffer object on success, or NULL on failure. + * \returns a buffer object on success, or NULL on failure; call SDL_GetError() for more information. * * \since This function is available since SDL 3.0.0. * @@ -2093,7 +2094,7 @@ extern SDL_DECLSPEC SDL_GPUBuffer *SDLCALL SDL_CreateGPUBuffer( * \param device a GPU Context. * \param createinfo a struct describing the state of the transfer buffer to * create. - * \returns a transfer buffer on success, or NULL on failure. + * \returns a transfer buffer on success, or NULL on failure; call SDL_GetError() for more information. * * \since This function is available since SDL 3.0.0. * @@ -2301,7 +2302,7 @@ extern SDL_DECLSPEC void SDLCALL SDL_ReleaseGPUGraphicsPipeline( * acquired on. * * \param device a GPU context. - * \returns a command buffer. + * \returns a command buffer, or NULL on failure; call SDL_GetError() for more information. * * \since This function is available since SDL 3.0.0. * @@ -2967,7 +2968,7 @@ extern SDL_DECLSPEC void SDLCALL SDL_EndGPUComputePass( * \param device a GPU context. * \param transfer_buffer a transfer buffer. * \param cycle if true, cycles the transfer buffer if it is already bound. - * \returns the address of the mapped transfer buffer memory. + * \returns the address of the mapped transfer buffer memory, or NULL on failure; call SDL_GetError() for more information. * * \since This function is available since SDL 3.0.0. */ @@ -3183,7 +3184,7 @@ extern SDL_DECLSPEC void SDLCALL SDL_BlitGPUTexture( * \param device a GPU context. * \param window an SDL_Window. * \param swapchain_composition the swapchain composition to check. - * \returns true if supported, false if unsupported (or on error). + * \returns true if supported, false if unsupported. * * \since This function is available since SDL 3.0.0. * @@ -3202,7 +3203,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_WindowSupportsGPUSwapchainComposition( * \param device a GPU context. * \param window an SDL_Window. * \param present_mode the presentation mode to check. - * \returns true if supported, false if unsupported (or on error). + * \returns true if supported, false if unsupported. * * \since This function is available since SDL 3.0.0. * @@ -3226,7 +3227,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_WindowSupportsGPUPresentMode( * * \param device a GPU context. * \param window an SDL_Window. - * \returns true on success, otherwise false. + * \returns true on success, or false on failure; call SDL_GetError() for more information. * * \since This function is available since SDL 3.0.0. * @@ -3283,6 +3284,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetGPUSwapchainParameters( /** * Obtains the texture format of the swapchain for the given window. + * Note that this format can change if the swapchain parameters change. * * \param device a GPU context. * \param window an SDL_Window that has been claimed. @@ -3300,16 +3302,15 @@ 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. May return NULL under certain conditions. This - * is not necessarily an error. This texture is managed by the implementation - * and must not be freed by the user. You MUST NOT call this function from any + * buffer used to acquire it. The swapchain texture handle can be NULL under certain conditions. This + * is not necessarily an error. If this function returns false then there is an error. This texture is managed by the implementation + * and must not be freed by the user. The texture dimensions will be the height and width of the claimed window. 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 w a pointer filled in with the swapchain width. - * \param h a pointer filled in with the swapchain height. - * \returns a swapchain texture. + * \param swapchainTexture a pointer filled in with a swapchain texture handle + * \returns true on success, false on error. * * \since This function is available since SDL 3.0.0. * @@ -3317,11 +3318,10 @@ extern SDL_DECLSPEC SDL_GPUTextureFormat SDLCALL SDL_GetGPUSwapchainTextureForma * \sa SDL_SubmitGPUCommandBuffer * \sa SDL_SubmitGPUCommandBufferAndAcquireFence */ -extern SDL_DECLSPEC SDL_GPUTexture *SDLCALL SDL_AcquireGPUSwapchainTexture( +extern SDL_DECLSPEC bool SDLCALL SDL_AcquireGPUSwapchainTexture( SDL_GPUCommandBuffer *command_buffer, SDL_Window *window, - Uint32 *w, - Uint32 *h); + SDL_GPUTexture **swapchainTexture); /** * Submits a command buffer so its commands can be processed on the GPU. @@ -3334,6 +3334,7 @@ extern SDL_DECLSPEC SDL_GPUTexture *SDLCALL SDL_AcquireGPUSwapchainTexture( * command in a subsequent submission begins executing. * * \param command_buffer a command buffer. + * \returns true on success, false on failure; call SDL_GetError() for more information. * * \since This function is available since SDL 3.0.0. * @@ -3341,7 +3342,7 @@ extern SDL_DECLSPEC SDL_GPUTexture *SDLCALL SDL_AcquireGPUSwapchainTexture( * \sa SDL_AcquireGPUSwapchainTexture * \sa SDL_SubmitGPUCommandBufferAndAcquireFence */ -extern SDL_DECLSPEC void SDLCALL SDL_SubmitGPUCommandBuffer( +extern SDL_DECLSPEC bool SDLCALL SDL_SubmitGPUCommandBuffer( SDL_GPUCommandBuffer *command_buffer); /** @@ -3357,7 +3358,7 @@ extern SDL_DECLSPEC void SDLCALL SDL_SubmitGPUCommandBuffer( * command in a subsequent submission begins executing. * * \param command_buffer a command buffer. - * \returns a fence associated with the command buffer. + * \returns a fence associated with the command buffer, or NULL on failure; call SDL_GetError() for more information. * * \since This function is available since SDL 3.0.0. * @@ -3373,12 +3374,13 @@ extern SDL_DECLSPEC SDL_GPUFence *SDLCALL SDL_SubmitGPUCommandBufferAndAcquireFe * Blocks the thread until the GPU is completely idle. * * \param device a GPU context. + * \returns true on success, false on failure; call SDL_GetError() for more information. * * \since This function is available since SDL 3.0.0. * * \sa SDL_WaitForGPUFences */ -extern SDL_DECLSPEC void SDLCALL SDL_WaitForGPUIdle( +extern SDL_DECLSPEC bool SDLCALL SDL_WaitForGPUIdle( SDL_GPUDevice *device); /** @@ -3389,13 +3391,14 @@ extern SDL_DECLSPEC void SDLCALL SDL_WaitForGPUIdle( * fences to be signaled. * \param fences an array of fences to wait on. * \param num_fences the number of fences in the fences array. + * \returns true on success, false on failure; call SDL_GetError() for more information. * * \since This function is available since SDL 3.0.0. * * \sa SDL_SubmitGPUCommandBufferAndAcquireFence * \sa SDL_WaitForGPUIdle */ -extern SDL_DECLSPEC void SDLCALL SDL_WaitForGPUFences( +extern SDL_DECLSPEC bool SDLCALL SDL_WaitForGPUFences( SDL_GPUDevice *device, bool wait_all, SDL_GPUFence *const *fences, diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h index f0986cd3ac..0aaa592b04 100644 --- a/src/dynapi/SDL_dynapi_procs.h +++ b/src/dynapi/SDL_dynapi_procs.h @@ -50,7 +50,7 @@ SDL_DYNAPI_PROC(int,SDL_swprintf,(SDL_OUT_Z_CAP(b) wchar_t *a, size_t b, SDL_PRI // New API symbols are added at the end SDL_DYNAPI_PROC(SDL_Surface*,SDL_AcquireCameraFrame,(SDL_Camera *a, Uint64 *b),(a,b),return) SDL_DYNAPI_PROC(SDL_GPUCommandBuffer*,SDL_AcquireGPUCommandBuffer,(SDL_GPUDevice *a),(a),return) -SDL_DYNAPI_PROC(SDL_GPUTexture*,SDL_AcquireGPUSwapchainTexture,(SDL_GPUCommandBuffer *a, SDL_Window *b, Uint32 *c, Uint32 *d),(a,b,c,d),return) +SDL_DYNAPI_PROC(bool,SDL_AcquireGPUSwapchainTexture,(SDL_GPUCommandBuffer *a, SDL_Window *b, SDL_GPUTexture **c),(a,b,c),return) SDL_DYNAPI_PROC(int,SDL_AddAtomicInt,(SDL_AtomicInt *a, int b),(a,b),return) SDL_DYNAPI_PROC(bool,SDL_AddEventWatch,(SDL_EventFilter a, void *b),(a,b),return) SDL_DYNAPI_PROC(int,SDL_AddGamepadMapping,(const char *a),(a),return) @@ -953,7 +953,7 @@ SDL_DYNAPI_PROC(bool,SDL_StopHapticRumble,(SDL_Haptic *a),(a),return) SDL_DYNAPI_PROC(bool,SDL_StopTextInput,(SDL_Window *a),(a),return) SDL_DYNAPI_PROC(bool,SDL_StorageReady,(SDL_Storage *a),(a),return) SDL_DYNAPI_PROC(SDL_GUID,SDL_StringToGUID,(const char *a),(a),return) -SDL_DYNAPI_PROC(void,SDL_SubmitGPUCommandBuffer,(SDL_GPUCommandBuffer *a),(a),) +SDL_DYNAPI_PROC(bool,SDL_SubmitGPUCommandBuffer,(SDL_GPUCommandBuffer *a),(a),return) SDL_DYNAPI_PROC(SDL_GPUFence*,SDL_SubmitGPUCommandBufferAndAcquireFence,(SDL_GPUCommandBuffer *a),(a),return) SDL_DYNAPI_PROC(bool,SDL_SurfaceHasAlternateImages,(SDL_Surface *a),(a),return) SDL_DYNAPI_PROC(bool,SDL_SurfaceHasColorKey,(SDL_Surface *a),(a),return) @@ -1006,8 +1006,8 @@ SDL_DYNAPI_PROC(void,SDL_WaitCondition,(SDL_Condition *a, SDL_Mutex *b),(a,b),) SDL_DYNAPI_PROC(bool,SDL_WaitConditionTimeout,(SDL_Condition *a, SDL_Mutex *b, Sint32 c),(a,b,c),return) 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(void,SDL_WaitForGPUFences,(SDL_GPUDevice *a, bool b, SDL_GPUFence *const *c, Uint32 d),(a,b,c,d),) -SDL_DYNAPI_PROC(void,SDL_WaitForGPUIdle,(SDL_GPUDevice *a),(a),) +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_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) diff --git a/src/gpu/SDL_gpu.c b/src/gpu/SDL_gpu.c index 16e04b41ae..fb9c4d107a 100644 --- a/src/gpu/SDL_gpu.c +++ b/src/gpu/SDL_gpu.c @@ -28,16 +28,22 @@ return retval; \ } -#define CHECK_COMMAND_BUFFER \ +#define CHECK_COMMAND_BUFFER \ if (((CommandBufferCommonHeader *)command_buffer)->submitted) { \ - SDL_assert_release(!"Command buffer already submitted!"); \ - return; \ + SDL_assert_release(!"Command buffer already submitted!"); \ + return; \ } -#define CHECK_COMMAND_BUFFER_RETURN_NULL \ +#define CHECK_COMMAND_BUFFER_RETURN_FALSE \ if (((CommandBufferCommonHeader *)command_buffer)->submitted) { \ - SDL_assert_release(!"Command buffer already submitted!"); \ - return NULL; \ + SDL_assert_release(!"Command buffer already submitted!"); \ + return false; \ + } + +#define CHECK_COMMAND_BUFFER_RETURN_NULL \ + if (((CommandBufferCommonHeader *)command_buffer)->submitted) { \ + SDL_assert_release(!"Command buffer already submitted!"); \ + return NULL; \ } #define CHECK_ANY_PASS_IN_PROGRESS(msg, retval) \ @@ -2594,65 +2600,59 @@ SDL_GPUTextureFormat SDL_GetGPUSwapchainTextureFormat( window); } -SDL_GPUTexture *SDL_AcquireGPUSwapchainTexture( +bool SDL_AcquireGPUSwapchainTexture( SDL_GPUCommandBuffer *command_buffer, SDL_Window *window, - Uint32 *w, - Uint32 *h) + SDL_GPUTexture **swapchainTexture) { if (command_buffer == NULL) { SDL_InvalidParamError("command_buffer"); - return NULL; + return false; } if (window == NULL) { SDL_InvalidParamError("window"); - return NULL; + return false; } - if (w == NULL) { - SDL_InvalidParamError("w"); - return NULL; - } - if (h == NULL) { - SDL_InvalidParamError("h"); - return NULL; + if (swapchainTexture == NULL) { + SDL_InvalidParamError("swapchainTexture"); + return false; } if (COMMAND_BUFFER_DEVICE->debug_mode) { - CHECK_COMMAND_BUFFER_RETURN_NULL - CHECK_ANY_PASS_IN_PROGRESS("Cannot acquire a swapchain texture during a pass!", NULL) + CHECK_COMMAND_BUFFER_RETURN_FALSE + CHECK_ANY_PASS_IN_PROGRESS("Cannot acquire a swapchain texture during a pass!", false) } return COMMAND_BUFFER_DEVICE->AcquireSwapchainTexture( command_buffer, window, - w, - h); + swapchainTexture); } -void SDL_SubmitGPUCommandBuffer( +bool SDL_SubmitGPUCommandBuffer( SDL_GPUCommandBuffer *command_buffer) { CommandBufferCommonHeader *commandBufferHeader = (CommandBufferCommonHeader *)command_buffer; if (command_buffer == NULL) { SDL_InvalidParamError("command_buffer"); - return; + return false; } if (COMMAND_BUFFER_DEVICE->debug_mode) { - CHECK_COMMAND_BUFFER + CHECK_COMMAND_BUFFER_RETURN_FALSE if ( commandBufferHeader->render_pass.in_progress || commandBufferHeader->compute_pass.in_progress || commandBufferHeader->copy_pass.in_progress) { SDL_assert_release(!"Cannot submit command buffer while a pass is in progress!"); - return; + return false; } } commandBufferHeader->submitted = true; - COMMAND_BUFFER_DEVICE->Submit( + return COMMAND_BUFFER_DEVICE->Submit( command_buffer); } @@ -2683,28 +2683,28 @@ SDL_GPUFence *SDL_SubmitGPUCommandBufferAndAcquireFence( command_buffer); } -void SDL_WaitForGPUIdle( +bool SDL_WaitForGPUIdle( SDL_GPUDevice *device) { - CHECK_DEVICE_MAGIC(device, ); + CHECK_DEVICE_MAGIC(device, false); - device->Wait( + return device->Wait( device->driverData); } -void SDL_WaitForGPUFences( +bool SDL_WaitForGPUFences( SDL_GPUDevice *device, bool wait_all, SDL_GPUFence *const *fences, Uint32 num_fences) { - CHECK_DEVICE_MAGIC(device, ); + CHECK_DEVICE_MAGIC(device, false); if (fences == NULL && num_fences > 0) { SDL_InvalidParamError("fences"); - return; + return false; } - device->WaitForFences( + return device->WaitForFences( device->driverData, wait_all, fences, diff --git a/src/gpu/SDL_sysgpu.h b/src/gpu/SDL_sysgpu.h index 5ae9b95a84..e2e60cffb3 100644 --- a/src/gpu/SDL_sysgpu.h +++ b/src/gpu/SDL_sysgpu.h @@ -648,22 +648,21 @@ struct SDL_GPUDevice SDL_GPUCommandBuffer *(*AcquireCommandBuffer)( SDL_GPURenderer *driverData); - SDL_GPUTexture *(*AcquireSwapchainTexture)( + bool (*AcquireSwapchainTexture)( SDL_GPUCommandBuffer *commandBuffer, SDL_Window *window, - Uint32 *w, - Uint32 *h); + SDL_GPUTexture **swapchainTexture); - void (*Submit)( + bool (*Submit)( SDL_GPUCommandBuffer *commandBuffer); SDL_GPUFence *(*SubmitAndAcquireFence)( SDL_GPUCommandBuffer *commandBuffer); - void (*Wait)( + bool (*Wait)( SDL_GPURenderer *driverData); - void (*WaitForFences)( + bool (*WaitForFences)( SDL_GPURenderer *driverData, bool waitAll, SDL_GPUFence *const *fences, diff --git a/src/gpu/d3d11/SDL_gpu_d3d11.c b/src/gpu/d3d11/SDL_gpu_d3d11.c index 78b77a401b..5a5210112c 100644 --- a/src/gpu/d3d11/SDL_gpu_d3d11.c +++ b/src/gpu/d3d11/SDL_gpu_d3d11.c @@ -108,20 +108,18 @@ static const GUID D3D_IID_DXGI_DEBUG_ALL = { 0xe48ae283, 0xda80, 0x490b, { 0x87, // Macros -#define ERROR_LOG(msg) \ - if (FAILED(res)) { \ - D3D11_INTERNAL_LogError(renderer->device, msg, res); \ - } +#define SET_ERROR_AND_RETURN(fmt, msg, ret) \ + if (renderer->debugMode) { \ + SDL_LogError(SDL_LOG_CATEGORY_GPU, fmt, msg); \ + } \ + SDL_SetError(fmt, msg); \ + return ret; \ -#define ERROR_LOG_RETURN(msg, ret) \ - if (FAILED(res)) { \ - D3D11_INTERNAL_LogError(renderer->device, msg, res); \ - return ret; \ - } +#define SET_STRING_ERROR_AND_RETURN(msg, ret) SET_ERROR_AND_RETURN("%s", msg, ret) -#define ERROR_SET_RETURN(msg, ret) \ +#define CHECK_D3D11_ERROR_AND_RETURN(msg, ret) \ if (FAILED(res)) { \ - D3D11_INTERNAL_SetError(renderer->device, msg, res); \ + D3D11_INTERNAL_SetError(renderer, msg, res); \ return ret; \ } @@ -146,7 +144,7 @@ static const GUID D3D_IID_DXGI_DEBUG_ALL = { 0xe48ae283, 0xda80, 0x490b, { 0x87, // Forward Declarations -static void D3D11_Wait(SDL_GPURenderer *driverData); +static bool D3D11_Wait(SDL_GPURenderer *driverData); static void D3D11_ReleaseWindow( SDL_GPURenderer *driverData, SDL_Window *window); @@ -800,7 +798,7 @@ struct D3D11Renderer // Logging static void D3D11_INTERNAL_SetError( - ID3D11Device1 *device, + D3D11Renderer *renderer, const char *msg, HRESULT res) { @@ -811,7 +809,7 @@ static void D3D11_INTERNAL_SetError( DWORD dwChars; // Number of chars returned. if (res == DXGI_ERROR_DEVICE_REMOVED) { - res = ID3D11Device_GetDeviceRemovedReason(device); + res = ID3D11Device_GetDeviceRemovedReason(renderer->device); } // Try to get the message from the system errors. @@ -831,6 +829,9 @@ static void D3D11_INTERNAL_SetError( // No message? Screw it, just post the code. if (dwChars == 0) { + if (renderer->debugMode) { + SDL_LogError(SDL_LOG_CATEGORY_GPU, "%s! Error Code: " HRESULT_FMT, msg, res); + } SDL_SetError("%s! Error Code: " HRESULT_FMT, msg, res); return; } @@ -850,63 +851,12 @@ static void D3D11_INTERNAL_SetError( // Ensure null-terminated string wszMsgBuff[dwChars] = '\0'; + if (renderer->debugMode) { + SDL_LogError(SDL_LOG_CATEGORY_GPU, "%s! Error Code: %s " HRESULT_FMT, msg, wszMsgBuff, res); + } SDL_SetError("%s! Error Code: %s " HRESULT_FMT, msg, wszMsgBuff, res); } -static void D3D11_INTERNAL_LogError( - ID3D11Device1 *device, - const char *msg, - HRESULT res) -{ -#define MAX_ERROR_LEN 1024 // FIXME: Arbitrary! - - // Buffer for text, ensure space for \0 terminator after buffer - char wszMsgBuff[MAX_ERROR_LEN + 1]; - DWORD dwChars; // Number of chars returned. - - if (res == DXGI_ERROR_DEVICE_REMOVED) { - res = ID3D11Device_GetDeviceRemovedReason(device); - } - - // Try to get the message from the system errors. -#ifdef _WIN32 - dwChars = FormatMessageA( - FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, - res, - 0, - wszMsgBuff, - MAX_ERROR_LEN, - NULL); -#else - // FIXME: Do we have error strings in dxvk-native? -flibit - dwChars = 0; -#endif - - // No message? Screw it, just post the code. - if (dwChars == 0) { - SDL_LogError(SDL_LOG_CATEGORY_GPU, "%s! Error Code: " HRESULT_FMT, msg, res); - return; - } - - // Ensure valid range - dwChars = SDL_min(dwChars, MAX_ERROR_LEN); - - // Trim whitespace from tail of message - while (dwChars > 0) { - if (wszMsgBuff[dwChars - 1] <= ' ') { - dwChars--; - } else { - break; - } - } - - // Ensure null-terminated string - wszMsgBuff[dwChars] = '\0'; - - SDL_LogError(SDL_LOG_CATEGORY_GPU, "%s! Error Code: %s " HRESULT_FMT, msg, wszMsgBuff, res); -} - // Helper Functions static inline Uint32 D3D11_INTERNAL_CalcSubresource( @@ -1348,7 +1298,7 @@ static ID3D11BlendState *D3D11_INTERNAL_FetchBlendState( renderer->device, &blendDesc, &result); - ERROR_LOG_RETURN("Could not create blend state", NULL); + CHECK_D3D11_ERROR_AND_RETURN("Could not create blend state", NULL); return result; } @@ -1386,7 +1336,7 @@ static ID3D11DepthStencilState *D3D11_INTERNAL_FetchDepthStencilState( renderer->device, &dsDesc, &result); - ERROR_LOG_RETURN("Could not create depth-stencil state", NULL); + CHECK_D3D11_ERROR_AND_RETURN("Could not create depth-stencil state", NULL); return result; } @@ -1417,7 +1367,7 @@ static ID3D11RasterizerState *D3D11_INTERNAL_FetchRasterizerState( renderer->device, &rasterizerDesc, &result); - ERROR_LOG_RETURN("Could not create rasterizer state", NULL); + CHECK_D3D11_ERROR_AND_RETURN("Could not create rasterizer state", NULL); return result; } @@ -1486,8 +1436,8 @@ static ID3D11InputLayout *D3D11_INTERNAL_FetchInputLayout( shaderByteLength, &result); if (FAILED(res)) { - SDL_SetError("Could not create input layout! Error: " HRESULT_FMT, res); SDL_stack_free(elementDescs); + CHECK_D3D11_ERROR_AND_RETURN("Could not create input layout!", NULL) return NULL; } @@ -1522,10 +1472,7 @@ static ID3D11DeviceChild *D3D11_INTERNAL_CreateID3D11Shader( codeSize, NULL, (ID3D11VertexShader **)&handle); - if (FAILED(res)) { - D3D11_INTERNAL_LogError(renderer->device, "Could not create vertex shader", res); - return NULL; - } + CHECK_D3D11_ERROR_AND_RETURN("Could not create vertex shader", NULL) } else if (stage == SDL_GPU_SHADERSTAGE_FRAGMENT) { res = ID3D11Device_CreatePixelShader( renderer->device, @@ -1533,10 +1480,7 @@ static ID3D11DeviceChild *D3D11_INTERNAL_CreateID3D11Shader( codeSize, NULL, (ID3D11PixelShader **)&handle); - if (FAILED(res)) { - D3D11_INTERNAL_LogError(renderer->device, "Could not create pixel shader", res); - return NULL; - } + CHECK_D3D11_ERROR_AND_RETURN("Could not create pixel shader", NULL) } else if (stage == SDL_GPU_SHADERSTAGE_COMPUTE) { res = ID3D11Device_CreateComputeShader( renderer->device, @@ -1544,10 +1488,7 @@ static ID3D11DeviceChild *D3D11_INTERNAL_CreateID3D11Shader( codeSize, NULL, (ID3D11ComputeShader **)&handle); - if (FAILED(res)) { - D3D11_INTERNAL_LogError(renderer->device, "Could not create compute shader", res); - return NULL; - } + CHECK_D3D11_ERROR_AND_RETURN("Could not create compute shader", NULL) } if (pBytecode != NULL) { @@ -1576,7 +1517,6 @@ static SDL_GPUComputePipeline *D3D11_CreateComputePipeline( NULL, NULL); if (shader == NULL) { - SDL_SetError("Failed to create compute pipeline!"); return NULL; } @@ -1609,6 +1549,10 @@ static SDL_GPUGraphicsPipeline *D3D11_CreateGraphicsPipeline( createinfo->target_info.num_color_targets, createinfo->target_info.color_target_descriptions); + if (pipeline->colorTargetBlendState == NULL) { + return NULL; + } + pipeline->numColorTargets = createinfo->target_info.num_color_targets; for (Sint32 i = 0; i < pipeline->numColorTargets; i += 1) { pipeline->colorTargetFormats[i] = SDLToD3D11_TextureFormat[createinfo->target_info.color_target_descriptions[i].format]; @@ -1627,6 +1571,10 @@ static SDL_GPUGraphicsPipeline *D3D11_CreateGraphicsPipeline( renderer, createinfo->depth_stencil_state); + if (pipeline->depthStencilState == NULL) { + return NULL; + } + pipeline->hasDepthStencilTarget = createinfo->target_info.has_depth_stencil_target; pipeline->depthStencilTargetFormat = SDLToD3D11_TextureFormat[createinfo->target_info.depth_stencil_format]; @@ -1637,6 +1585,10 @@ static SDL_GPUGraphicsPipeline *D3D11_CreateGraphicsPipeline( renderer, createinfo->rasterizer_state); + if (pipeline->rasterizerState == NULL) { + return NULL; + } + // Shaders pipeline->vertexShader = (ID3D11VertexShader *)vertShader->handle; @@ -1875,7 +1827,7 @@ static SDL_GPUSampler *D3D11_CreateSampler( renderer->device, &samplerDesc, &samplerStateHandle); - ERROR_SET_RETURN("Could not create sampler state", NULL); + CHECK_D3D11_ERROR_AND_RETURN("Could not create sampler state", NULL); d3d11Sampler = (D3D11Sampler *)SDL_malloc(sizeof(D3D11Sampler)); d3d11Sampler->handle = samplerStateHandle; @@ -1901,7 +1853,7 @@ SDL_GPUShader *D3D11_CreateShader( createinfo->entrypoint, createinfo->stage == SDL_GPU_SHADERSTAGE_VERTEX ? &bytecode : NULL, createinfo->stage == SDL_GPU_SHADERSTAGE_VERTEX ? &bytecodeSize : NULL); - if (!handle) { + if (handle == NULL) { return NULL; } @@ -1994,7 +1946,7 @@ static D3D11Texture *D3D11_INTERNAL_CreateTexture( &desc2D, initialData, (ID3D11Texture2D **)&textureHandle); - ERROR_LOG_RETURN("Could not create Texture2D", NULL); + CHECK_D3D11_ERROR_AND_RETURN("Could not create Texture2D", NULL); // Create the SRV, if applicable if (needsSRV) { @@ -2030,7 +1982,7 @@ static D3D11Texture *D3D11_INTERNAL_CreateTexture( &srv); if (FAILED(res)) { ID3D11Resource_Release(textureHandle); - D3D11_INTERNAL_LogError(renderer->device, "Could not create SRV for 2D texture", res); + D3D11_INTERNAL_SetError(renderer, "Could not create SRV for 2D texture", res); return NULL; } } @@ -2062,7 +2014,7 @@ static D3D11Texture *D3D11_INTERNAL_CreateTexture( &desc3D, initialData, (ID3D11Texture3D **)&textureHandle); - ERROR_LOG_RETURN("Could not create Texture3D", NULL); + CHECK_D3D11_ERROR_AND_RETURN("Could not create Texture3D", NULL); // Create the SRV, if applicable if (needsSRV) { @@ -2079,7 +2031,7 @@ static D3D11Texture *D3D11_INTERNAL_CreateTexture( &srv); if (FAILED(res)) { ID3D11Resource_Release(textureHandle); - D3D11_INTERNAL_LogError(renderer->device, "Could not create SRV for 3D texture", res); + D3D11_INTERNAL_SetError(renderer, "Could not create SRV for 3D texture", res); return NULL; } } @@ -2131,7 +2083,7 @@ static D3D11Texture *D3D11_INTERNAL_CreateTexture( d3d11Texture->handle, &dsvDesc, &d3d11Texture->subresources[subresourceIndex].depthStencilTargetView); - ERROR_LOG_RETURN("Could not create DSV!", NULL); + CHECK_D3D11_ERROR_AND_RETURN("Could not create DSV!", NULL); } else if (isColorTarget) { @@ -2163,7 +2115,7 @@ static D3D11Texture *D3D11_INTERNAL_CreateTexture( d3d11Texture->handle, &rtvDesc, &d3d11Texture->subresources[subresourceIndex].colorTargetViews[depthIndex]); - ERROR_LOG_RETURN("Could not create RTV!", NULL); + CHECK_D3D11_ERROR_AND_RETURN("Could not create RTV!", NULL); } } @@ -2191,7 +2143,7 @@ static D3D11Texture *D3D11_INTERNAL_CreateTexture( d3d11Texture->handle, &uavDesc, &d3d11Texture->subresources[subresourceIndex].uav); - ERROR_LOG_RETURN("Could not create UAV!", NULL); + CHECK_D3D11_ERROR_AND_RETURN("Could not create UAV!", NULL); } } } @@ -2230,7 +2182,6 @@ static SDL_GPUTexture *D3D11_CreateTexture( NULL); if (texture == NULL) { - SDL_SetError("Failed to create texture!"); return NULL; } @@ -2267,7 +2218,6 @@ static void D3D11_INTERNAL_CycleActiveTexture( &container->header.info, NULL); if (texture == NULL) { - SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to cycle active texture!"); return; } @@ -2355,7 +2305,7 @@ static D3D11Buffer *D3D11_INTERNAL_CreateBuffer( bufferDesc, NULL, &bufferHandle); - ERROR_LOG_RETURN("Could not create buffer", NULL); + CHECK_D3D11_ERROR_AND_RETURN("Could not create buffer", NULL); // Storage buffer if (bufferDesc->MiscFlags & D3D11_RESOURCE_MISC_BUFFER_ALLOW_RAW_VIEWS) { @@ -2375,7 +2325,7 @@ static D3D11Buffer *D3D11_INTERNAL_CreateBuffer( &uav); if (FAILED(res)) { ID3D11Buffer_Release(bufferHandle); - ERROR_LOG_RETURN("Could not create UAV for buffer!", NULL); + CHECK_D3D11_ERROR_AND_RETURN("Could not create UAV for buffer!", NULL); } // Create a SRV for the buffer @@ -2394,7 +2344,7 @@ static D3D11Buffer *D3D11_INTERNAL_CreateBuffer( &srv); if (FAILED(res)) { ID3D11Buffer_Release(bufferHandle); - ERROR_LOG_RETURN("Could not create SRV for buffer!", NULL); + CHECK_D3D11_ERROR_AND_RETURN("Could not create SRV for buffer!", NULL); } } @@ -2456,7 +2406,6 @@ static SDL_GPUBuffer *D3D11_CreateBuffer( size); if (buffer == NULL) { - SDL_SetError("Failed to create buffer!"); return NULL; } @@ -2494,7 +2443,7 @@ static D3D11UniformBuffer *D3D11_INTERNAL_CreateUniformBuffer( &bufferDesc, NULL, &buffer); - ERROR_LOG_RETURN("Could not create uniform buffer", NULL) + CHECK_D3D11_ERROR_AND_RETURN("Could not create uniform buffer", NULL) uniformBuffer = SDL_malloc(sizeof(D3D11UniformBuffer)); uniformBuffer->buffer = buffer; @@ -2738,7 +2687,6 @@ static void D3D11_UploadToTexture( &initialData); if (stagingTexture == NULL) { - SDL_LogError(SDL_LOG_CATEGORY_GPU, "Staging texture creation failed"); return; } @@ -2797,7 +2745,7 @@ static void D3D11_UploadToBuffer( &stagingBufferDesc, &stagingBufferData, &stagingBuffer); - ERROR_LOG_RETURN("Could not create staging buffer", ) + CHECK_D3D11_ERROR_AND_RETURN("Could not create staging buffer", ) // Copy from staging buffer to buffer ID3D11DeviceContext1_CopySubresourceRegion( @@ -2880,7 +2828,7 @@ static void D3D11_DownloadFromTexture( &stagingDesc2D, NULL, (ID3D11Texture2D **)&textureDownload->stagingTexture); - ERROR_LOG_RETURN("Staging texture creation failed", ) + CHECK_D3D11_ERROR_AND_RETURN("Staging texture creation failed", ) } else { stagingDesc3D.Width = source->w; stagingDesc3D.Height = source->h; @@ -2959,7 +2907,7 @@ static void D3D11_DownloadFromBuffer( &stagingBufferDesc, NULL, &bufferDownload->stagingBuffer); - ERROR_LOG_RETURN("Could not create staging buffer", ) + CHECK_D3D11_ERROR_AND_RETURN("Could not create staging buffer", ) ID3D11DeviceContext1_CopySubresourceRegion1( d3d11CommandBuffer->context, @@ -3103,7 +3051,7 @@ static void D3D11_INTERNAL_AllocateCommandBuffers( renderer->device, 0, &commandBuffer->context); - ERROR_LOG("Could not create deferred context"); + CHECK_D3D11_ERROR_AND_RETURN("Could not create deferred context", ); // Initialize debug annotation support, if available ID3D11DeviceContext_QueryInterface( @@ -3174,7 +3122,7 @@ static bool D3D11_INTERNAL_CreateFence( renderer->device, &queryDesc, &queryHandle); - ERROR_LOG_RETURN("Could not create query", 0); + CHECK_D3D11_ERROR_AND_RETURN("Could not create query", false); fence = SDL_malloc(sizeof(D3D11Fence)); fence->handle = queryHandle; @@ -3207,7 +3155,6 @@ static bool D3D11_INTERNAL_AcquireFence( if (renderer->availableFenceCount == 0) { if (!D3D11_INTERNAL_CreateFence(renderer)) { SDL_UnlockMutex(renderer->fenceLock); - SDL_SetError("Failed to create fence!"); return false; } } @@ -3408,7 +3355,7 @@ static void D3D11_INTERNAL_PushUniformData( D3D11_MAP_WRITE_DISCARD, 0, &subres); - ERROR_LOG_RETURN("Failed to map uniform buffer", ) + CHECK_D3D11_ERROR_AND_RETURN("Failed to map uniform buffer", ) d3d11UniformBuffer->mappedData = subres.pData; } @@ -4721,7 +4668,7 @@ static void D3D11_ReleaseFence( * wait until the command buffer has finished executing to map the staging resource. */ -static void D3D11_INTERNAL_MapAndCopyBufferDownload( +static bool D3D11_INTERNAL_MapAndCopyBufferDownload( D3D11Renderer *renderer, D3D11TransferBuffer *transferBuffer, D3D11BufferDownload *bufferDownload) @@ -4737,13 +4684,16 @@ static void D3D11_INTERNAL_MapAndCopyBufferDownload( D3D11_MAP_READ, 0, &subres); - ERROR_LOG_RETURN("Failed to map staging buffer", ) + SDL_UnlockMutex(renderer->contextLock); + + CHECK_D3D11_ERROR_AND_RETURN("Failed to map staging buffer", false) SDL_memcpy( ((Uint8 *)transferBuffer->data) + bufferDownload->dstOffset, ((Uint8 *)subres.pData), bufferDownload->size); + SDL_LockMutex(renderer->contextLock); ID3D11DeviceContext_Unmap( renderer->immediateContext, (ID3D11Resource *)bufferDownload->stagingBuffer, @@ -4751,9 +4701,11 @@ static void D3D11_INTERNAL_MapAndCopyBufferDownload( SDL_UnlockMutex(renderer->contextLock); ID3D11Buffer_Release(bufferDownload->stagingBuffer); + + return true; } -static void D3D11_INTERNAL_MapAndCopyTextureDownload( +static bool D3D11_INTERNAL_MapAndCopyTextureDownload( D3D11Renderer *renderer, D3D11TransferBuffer *transferBuffer, D3D11TextureDownload *textureDownload) @@ -4771,7 +4723,9 @@ static void D3D11_INTERNAL_MapAndCopyTextureDownload( D3D11_MAP_READ, 0, &subres); - ERROR_LOG_RETURN("Could not map staging texture", ) + SDL_UnlockMutex(renderer->contextLock); + + CHECK_D3D11_ERROR_AND_RETURN("Could not map staging texture", false) for (depth = 0; depth < textureDownload->depth; depth += 1) { dataPtrOffset = textureDownload->bufferOffset + (depth * textureDownload->bytesPerDepthSlice); @@ -4785,21 +4739,24 @@ static void D3D11_INTERNAL_MapAndCopyTextureDownload( } } + SDL_LockMutex(renderer->contextLock); ID3D11DeviceContext_Unmap( renderer->immediateContext, textureDownload->stagingTexture, 0); - SDL_UnlockMutex(renderer->contextLock); ID3D11Resource_Release(textureDownload->stagingTexture); + + return true; } -static void D3D11_INTERNAL_CleanCommandBuffer( +static bool D3D11_INTERNAL_CleanCommandBuffer( D3D11Renderer *renderer, D3D11CommandBuffer *commandBuffer) { Uint32 i, j; + bool result = true; // Perform deferred download map and copy @@ -4807,14 +4764,14 @@ static void D3D11_INTERNAL_CleanCommandBuffer( D3D11TransferBuffer *transferBuffer = commandBuffer->usedTransferBuffers[i]; for (j = 0; j < transferBuffer->bufferDownloadCount; j += 1) { - D3D11_INTERNAL_MapAndCopyBufferDownload( + result &= D3D11_INTERNAL_MapAndCopyBufferDownload( renderer, transferBuffer, &transferBuffer->bufferDownloads[j]); } for (j = 0; j < transferBuffer->textureDownloadCount; j += 1) { - D3D11_INTERNAL_MapAndCopyTextureDownload( + result &= D3D11_INTERNAL_MapAndCopyTextureDownload( renderer, transferBuffer, &transferBuffer->textureDownloads[j]); @@ -4883,6 +4840,8 @@ static void D3D11_INTERNAL_CleanCommandBuffer( renderer->submittedCommandBufferCount -= 1; } } + + return result; } static void D3D11_INTERNAL_PerformPendingDestroys( @@ -4961,7 +4920,7 @@ static void D3D11_INTERNAL_WaitForFence( SDL_UnlockMutex(renderer->contextLock); } -static void D3D11_WaitForFences( +static bool D3D11_WaitForFences( SDL_GPURenderer *driverData, bool waitAll, SDL_GPUFence *const *fences, @@ -5000,6 +4959,7 @@ static void D3D11_WaitForFences( SDL_LockMutex(renderer->contextLock); + bool result = true; // Check if we can perform any cleanups for (Sint32 i = renderer->submittedCommandBufferCount - 1; i >= 0; i -= 1) { res = ID3D11DeviceContext_GetData( @@ -5009,7 +4969,7 @@ static void D3D11_WaitForFences( sizeof(queryData), 0); if (res == S_OK) { - D3D11_INTERNAL_CleanCommandBuffer( + result &= D3D11_INTERNAL_CleanCommandBuffer( renderer, renderer->submittedCommandBuffers[i]); } @@ -5018,6 +4978,8 @@ static void D3D11_WaitForFences( D3D11_INTERNAL_PerformPendingDestroys(renderer); SDL_UnlockMutex(renderer->contextLock); + + return result; } static bool D3D11_QueryFence( @@ -5073,7 +5035,7 @@ static bool D3D11_INTERNAL_InitializeSwapchainTexture( 0, &D3D_IID_ID3D11Texture2D, (void **)&swapchainTexture); - ERROR_LOG_RETURN("Could not get buffer from swapchain!", 0); + CHECK_D3D11_ERROR_AND_RETURN("Could not get buffer from swapchain!", false); // Create the RTV for the swapchain rtvDesc.Format = rtvFormat; @@ -5087,7 +5049,7 @@ static bool D3D11_INTERNAL_InitializeSwapchainTexture( &rtv); if (FAILED(res)) { ID3D11Texture2D_Release(swapchainTexture); - D3D11_INTERNAL_LogError(renderer->device, "Swapchain RTV creation failed", res); + D3D11_INTERNAL_SetError(renderer, "Swapchain RTV creation failed", res); return false; } @@ -5173,7 +5135,7 @@ static bool D3D11_INTERNAL_CreateSwapchain( (IUnknown *)renderer->device, &swapchainDesc, &swapchain); - ERROR_LOG_RETURN("Could not create swapchain", 0); + CHECK_D3D11_ERROR_AND_RETURN("Could not create swapchain", false); /* * The swapchain's parent is a separate factory from the factory that @@ -5288,7 +5250,7 @@ static bool D3D11_INTERNAL_ResizeSwapchain( height, DXGI_FORMAT_UNKNOWN, // Keep the old format renderer->supportsTearing ? DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING : 0); - ERROR_LOG_RETURN("Could not resize swapchain buffers", 0); + CHECK_D3D11_ERROR_AND_RETURN("Could not resize swapchain buffers", false); // Create the texture object for the swapchain return D3D11_INTERNAL_InitializeSwapchainTexture( @@ -5328,8 +5290,7 @@ static bool D3D11_SupportsSwapchainComposition( D3D11WindowData *windowData = D3D11_INTERNAL_FetchWindowData(window); if (windowData == NULL) { - SDL_SetError("Must claim window before querying swapchain composition support!"); - return false; + SET_STRING_ERROR_AND_RETURN("Must claim window before querying swapchain composition support!", false) } // Check the color space support if necessary @@ -5349,8 +5310,7 @@ static bool D3D11_SupportsSwapchainComposition( return false; } } else { - SDL_SetError("DXGI 1.4 not supported, cannot use composition other than SDL_GPU_SWAPCHAINCOMPOSITION_SDR!"); - return false; + SET_STRING_ERROR_AND_RETURN("DXGI 1.4 not supported, cannot use composition other than SDL_GPU_SWAPCHAINCOMPOSITION_SDR!", false) } } @@ -5404,9 +5364,8 @@ static bool D3D11_ClaimWindow( return true; } else { - SDL_SetError("Could not create swapchain, failed to claim window!"); SDL_free(windowData); - return false; + SET_STRING_ERROR_AND_RETURN("Could not create swapchain, failed to claim window!", false) } } else { SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "Window already claimed!"); @@ -5475,11 +5434,10 @@ static void D3D11_ReleaseWindow( SDL_ClearProperty(SDL_GetWindowProperties(window), WINDOW_PROPERTY_DATA); } -static SDL_GPUTexture *D3D11_AcquireSwapchainTexture( +static bool D3D11_AcquireSwapchainTexture( SDL_GPUCommandBuffer *commandBuffer, SDL_Window *window, - Uint32 *w, - Uint32 *h) + SDL_GPUTexture **swapchainTexture) { D3D11CommandBuffer *d3d11CommandBuffer = (D3D11CommandBuffer *)commandBuffer; D3D11Renderer *renderer = (D3D11Renderer *)d3d11CommandBuffer->renderer; @@ -5488,9 +5446,11 @@ static SDL_GPUTexture *D3D11_AcquireSwapchainTexture( int windowW, windowH; HRESULT res; + *swapchainTexture = NULL; + windowData = D3D11_INTERNAL_FetchWindowData(window); if (windowData == NULL) { - return NULL; + SET_STRING_ERROR_AND_RETURN("Cannot acquire a swapchain texture from an unclaimed window!", false) } // Check for window size changes and resize the swapchain if needed. @@ -5498,31 +5458,34 @@ static SDL_GPUTexture *D3D11_AcquireSwapchainTexture( SDL_GetWindowSize(window, &windowW, &windowH); if ((UINT)windowW != swapchainDesc.BufferDesc.Width || (UINT)windowH != swapchainDesc.BufferDesc.Height) { - res = D3D11_INTERNAL_ResizeSwapchain( + if (!D3D11_INTERNAL_ResizeSwapchain( renderer, windowData, windowW, - windowH); - ERROR_SET_RETURN("Could not resize swapchain", NULL); + windowH)) { + return false; + } } 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 - D3D11_WaitForFences( + if (!D3D11_WaitForFences( (SDL_GPURenderer *)renderer, true, &windowData->inFlightFences[windowData->frameCounter], - 1); + 1)) { + return false; + } } else { if (!D3D11_QueryFence( (SDL_GPURenderer *)d3d11CommandBuffer->renderer, windowData->inFlightFences[windowData->frameCounter])) { /* * In MAILBOX or IMMEDIATE mode, if the least recent fence is not signaled, - * return NULL to indicate that rendering should be skipped + * return true to indicate that there is no error but rendering should be skipped */ - return NULL; + return true; } } @@ -5539,11 +5502,7 @@ static SDL_GPUTexture *D3D11_AcquireSwapchainTexture( 0, &D3D_IID_ID3D11Texture2D, (void **)&windowData->texture.handle); - ERROR_SET_RETURN("Could not acquire swapchain!", NULL); - - // Send the dimensions to the out parameters. - *w = windowW; - *h = windowH; + CHECK_D3D11_ERROR_AND_RETURN("Could not acquire swapchain!", false); // Update the texture container dimensions windowData->textureContainer.header.info.width = windowW; @@ -5560,18 +5519,19 @@ static SDL_GPUTexture *D3D11_AcquireSwapchainTexture( d3d11CommandBuffer->windowDataCount += 1; // Return the swapchain texture - return (SDL_GPUTexture *)&windowData->textureContainer; + *swapchainTexture = (SDL_GPUTexture*) &windowData->textureContainer; + return true; } static SDL_GPUTextureFormat D3D11_GetSwapchainTextureFormat( SDL_GPURenderer *driverData, SDL_Window *window) { + D3D11Renderer *renderer = (D3D11Renderer *)driverData; D3D11WindowData *windowData = D3D11_INTERNAL_FetchWindowData(window); if (windowData == NULL) { - SDL_SetError("Cannot get swapchain format, window has not been claimed!"); - return SDL_GPU_TEXTUREFORMAT_INVALID; + SET_STRING_ERROR_AND_RETURN("Cannot get swapchain format, window has not been claimed!", SDL_GPU_TEXTUREFORMAT_INVALID) } return windowData->textureContainer.header.info.format; @@ -5587,18 +5547,15 @@ static bool D3D11_SetSwapchainParameters( D3D11WindowData *windowData = D3D11_INTERNAL_FetchWindowData(window); if (windowData == NULL) { - SDL_SetError("Cannot set swapchain parameters on unclaimed window!"); - return false; + SET_STRING_ERROR_AND_RETURN("Cannot set swapchain parameters on unclaimed window!", false) } if (!D3D11_SupportsSwapchainComposition(driverData, window, swapchainComposition)) { - SDL_SetError("Swapchain composition not supported!"); - return false; + SET_STRING_ERROR_AND_RETURN("Swapchain composition not supported!", false) } if (!D3D11_SupportsPresentMode(driverData, window, presentMode)) { - SDL_SetError("Present mode not supported!"); - return false; + SET_STRING_ERROR_AND_RETURN("Present mode not supported!", false) } if ( @@ -5623,7 +5580,7 @@ static bool D3D11_SetSwapchainParameters( // Submission -static void D3D11_Submit( +static bool D3D11_Submit( SDL_GPUCommandBuffer *commandBuffer) { D3D11CommandBuffer *d3d11CommandBuffer = (D3D11CommandBuffer *)commandBuffer; @@ -5668,7 +5625,10 @@ static void D3D11_Submit( d3d11CommandBuffer->context, 0, &commandList); - ERROR_LOG("Could not finish command list recording!"); + if (FAILED(res)) { + SDL_UnlockMutex(renderer->contextLock); + CHECK_D3D11_ERROR_AND_RETURN("Could not finish command list recording!", false) + } // Submit the command list to the immediate context ID3D11DeviceContext_ExecuteCommandList( @@ -5689,6 +5649,8 @@ static void D3D11_Submit( renderer->submittedCommandBuffers[renderer->submittedCommandBufferCount] = d3d11CommandBuffer; renderer->submittedCommandBufferCount += 1; + bool result = true; + // Present, if applicable for (Uint32 i = 0; i < d3d11CommandBuffer->windowDataCount; i += 1) { D3D11WindowData *windowData = d3d11CommandBuffer->windowDatas[i]; @@ -5705,11 +5667,15 @@ static void D3D11_Submit( presentFlags = DXGI_PRESENT_ALLOW_TEARING; } - IDXGISwapChain_Present( + res = IDXGISwapChain_Present( windowData->swapchain, syncInterval, presentFlags); + if (FAILED(res)) { + result = false; + } + ID3D11Texture2D_Release(windowData->texture.handle); windowData->inFlightFences[windowData->frameCounter] = (SDL_GPUFence*)d3d11CommandBuffer->fence; @@ -5729,7 +5695,7 @@ static void D3D11_Submit( sizeof(queryData), 0); if (res == S_OK) { - D3D11_INTERNAL_CleanCommandBuffer( + result &= D3D11_INTERNAL_CleanCommandBuffer( renderer, renderer->submittedCommandBuffers[i]); } @@ -5738,6 +5704,8 @@ static void D3D11_Submit( D3D11_INTERNAL_PerformPendingDestroys(renderer); SDL_UnlockMutex(renderer->contextLock); + + return result; } static SDL_GPUFence *D3D11_SubmitAndAcquireFence( @@ -5752,11 +5720,12 @@ static SDL_GPUFence *D3D11_SubmitAndAcquireFence( return (SDL_GPUFence *)fence; } -static void D3D11_Wait( +static bool D3D11_Wait( SDL_GPURenderer *driverData) { D3D11Renderer *renderer = (D3D11Renderer *)driverData; D3D11CommandBuffer *commandBuffer; + bool result = true; /* * Wait for all submitted command buffers to complete. @@ -5772,12 +5741,14 @@ static void D3D11_Wait( for (Sint32 i = renderer->submittedCommandBufferCount - 1; i >= 0; i -= 1) { commandBuffer = renderer->submittedCommandBuffers[i]; - D3D11_INTERNAL_CleanCommandBuffer(renderer, commandBuffer); + result &= D3D11_INTERNAL_CleanCommandBuffer(renderer, commandBuffer); } D3D11_INTERNAL_PerformPendingDestroys(renderer); SDL_UnlockMutex(renderer->contextLock); + + return result; } // Format Info @@ -6209,8 +6180,7 @@ static SDL_GPUDevice *D3D11_CreateDevice(bool debugMode, bool preferLowPower, SD // Load the DXGI library renderer->dxgi_dll = SDL_LoadObject(DXGI_DLL); if (renderer->dxgi_dll == NULL) { - SDL_SetError("Could not find " DXGI_DLL); - return NULL; + SET_STRING_ERROR_AND_RETURN("Could not find " DXGI_DLL, NULL) } // Load the CreateDXGIFactory1 function @@ -6218,15 +6188,14 @@ static SDL_GPUDevice *D3D11_CreateDevice(bool debugMode, bool preferLowPower, SD renderer->dxgi_dll, CREATE_DXGI_FACTORY1_FUNC); if (CreateDxgiFactoryFunc == NULL) { - SDL_SetError("Could not load function: " CREATE_DXGI_FACTORY1_FUNC); - return NULL; + SET_STRING_ERROR_AND_RETURN("Could not load function: " CREATE_DXGI_FACTORY1_FUNC, NULL) } // Create the DXGI factory res = CreateDxgiFactoryFunc( &D3D_IID_IDXGIFactory1, (void **)&renderer->factory); - ERROR_SET_RETURN("Could not create DXGIFactory", NULL); + CHECK_D3D11_ERROR_AND_RETURN("Could not create DXGIFactory", NULL); // Check for flip-model discard support (supported on Windows 10+) res = IDXGIFactory1_QueryInterface( @@ -6286,8 +6255,7 @@ static SDL_GPUDevice *D3D11_CreateDevice(bool debugMode, bool preferLowPower, SD // Load the D3D library renderer->d3d11_dll = SDL_LoadObject(D3D11_DLL); if (renderer->d3d11_dll == NULL) { - SDL_SetError("Could not find " D3D11_DLL); - return NULL; + SET_STRING_ERROR_AND_RETURN("Could not find " D3D11_DLL, NULL) } // Load the CreateDevice function @@ -6295,8 +6263,7 @@ static SDL_GPUDevice *D3D11_CreateDevice(bool debugMode, bool preferLowPower, SD renderer->d3d11_dll, D3D11_CREATE_DEVICE_FUNC); if (D3D11CreateDeviceFunc == NULL) { - SDL_SetError("Could not load function: " D3D11_CREATE_DEVICE_FUNC); - return NULL; + SET_STRING_ERROR_AND_RETURN("Could not load function: " D3D11_CREATE_DEVICE_FUNC, NULL) } // Set up device flags @@ -6327,14 +6294,14 @@ tryCreateDevice: goto tryCreateDevice; } - ERROR_SET_RETURN("Could not create D3D11 device", NULL); + CHECK_D3D11_ERROR_AND_RETURN("Could not create D3D11 device", NULL); // The actual device we want is the ID3D11Device1 interface... res = ID3D11Device_QueryInterface( d3d11Device, &D3D_IID_ID3D11Device1, (void **)&renderer->device); - ERROR_SET_RETURN("Could not get ID3D11Device1 interface", NULL); + CHECK_D3D11_ERROR_AND_RETURN("Could not get ID3D11Device1 interface", NULL); // Release the old device interface, we don't need it anymore ID3D11Device_Release(d3d11Device); diff --git a/src/gpu/d3d12/SDL_gpu_d3d12.c b/src/gpu/d3d12/SDL_gpu_d3d12.c index b9dfaafee5..981b4b1f56 100644 --- a/src/gpu/d3d12/SDL_gpu_d3d12.c +++ b/src/gpu/d3d12/SDL_gpu_d3d12.c @@ -56,20 +56,24 @@ // Macros -#define ERROR_LOG(msg) \ - if (FAILED(res)) { \ - D3D12_INTERNAL_LogError(renderer->device, msg, res); \ - } +#define SET_ERROR(fmt, msg) \ + if (renderer->debug_mode) { \ + SDL_LogError(SDL_LOG_CATEGORY_GPU, fmt, msg); \ + } \ + SDL_SetError(fmt, msg); -#define ERROR_LOG_RETURN(msg, ret) \ - if (FAILED(res)) { \ - D3D12_INTERNAL_LogError(renderer->device, msg, res); \ - return ret; \ - } +#define SET_ERROR_AND_RETURN(fmt, msg, ret) \ + if (renderer->debug_mode) { \ + SDL_LogError(SDL_LOG_CATEGORY_GPU, fmt, msg); \ + } \ + SDL_SetError(fmt, msg); \ + return ret; \ -#define ERROR_SET_RETURN(msg, ret) \ +#define SET_STRING_ERROR_AND_RETURN(msg, ret) SET_ERROR_AND_RETURN("%s", msg, ret) + +#define CHECK_D3D12_ERROR_AND_RETURN(msg, ret) \ if (FAILED(res)) { \ - D3D12_INTERNAL_SetError(renderer->device, msg, res); \ + D3D12_INTERNAL_SetError(renderer, msg, res); \ return ret; \ } @@ -897,8 +901,8 @@ struct D3D12UniformBuffer // Forward function declarations static void D3D12_ReleaseWindow(SDL_GPURenderer *driverData, SDL_Window *window); -static void D3D12_Wait(SDL_GPURenderer *driverData); -static void D3D12_WaitForFences(SDL_GPURenderer *driverData, bool waitAll, SDL_GPUFence *const *fences, Uint32 numFences); +static bool D3D12_Wait(SDL_GPURenderer *driverData); +static bool D3D12_WaitForFences(SDL_GPURenderer *driverData, bool waitAll, SDL_GPUFence *const *fences, Uint32 numFences); static void D3D12_INTERNAL_ReleaseBlitPipelines(SDL_GPURenderer *driverData); // Helpers @@ -924,7 +928,7 @@ typedef HRESULT (D3DAPI* PFN_D3D12_XBOX_CREATE_DEVICE)(_In_opt_ IGraphicsUnknown // Logging static void D3D12_INTERNAL_SetError( - ID3D12Device *device, + D3D12Renderer *renderer, const char *msg, HRESULT res) { @@ -935,8 +939,8 @@ static void D3D12_INTERNAL_SetError( DWORD dwChars; // Number of chars returned. if (res == DXGI_ERROR_DEVICE_REMOVED) { - if (device) { - res = ID3D12Device_GetDeviceRemovedReason(device); + if (renderer->device) { + res = ID3D12Device_GetDeviceRemovedReason(renderer->device); } } @@ -952,6 +956,9 @@ static void D3D12_INTERNAL_SetError( // No message? Screw it, just post the code. if (dwChars == 0) { + if (renderer->debug_mode) { + SDL_LogError(SDL_LOG_CATEGORY_GPU, "%s! Error Code: " HRESULT_FMT, msg, res); + } SDL_SetError("%s! Error Code: " HRESULT_FMT, msg, res); return; } @@ -971,61 +978,12 @@ static void D3D12_INTERNAL_SetError( // Ensure null-terminated string wszMsgBuff[dwChars] = '\0'; + if (renderer->debug_mode) { + SDL_LogError(SDL_LOG_CATEGORY_GPU, "%s! Error Code: %s " HRESULT_FMT, msg, wszMsgBuff, res); + } SDL_SetError("%s! Error Code: %s " HRESULT_FMT, msg, wszMsgBuff, res); } -static void -D3D12_INTERNAL_LogError( - ID3D12Device *device, - const char *msg, - HRESULT res) -{ -#define MAX_ERROR_LEN 1024 // FIXME: Arbitrary! - - // Buffer for text, ensure space for \0 terminator after buffer - char wszMsgBuff[MAX_ERROR_LEN + 1]; - DWORD dwChars; // Number of chars returned. - - if (res == DXGI_ERROR_DEVICE_REMOVED) { - if (device) { - res = ID3D12Device_GetDeviceRemovedReason(device); - } - } - - // Try to get the message from the system errors. - dwChars = FormatMessageA( - FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, - res, - 0, - wszMsgBuff, - MAX_ERROR_LEN, - NULL); - - // No message? Screw it, just post the code. - if (dwChars == 0) { - SDL_LogError(SDL_LOG_CATEGORY_GPU, "%s! Error Code: " HRESULT_FMT, msg, res); - return; - } - - // Ensure valid range - dwChars = SDL_min(dwChars, MAX_ERROR_LEN); - - // Trim whitespace from tail of message - while (dwChars > 0) { - if (wszMsgBuff[dwChars - 1] <= ' ') { - dwChars--; - } else { - break; - } - } - - // Ensure null-terminated string - wszMsgBuff[dwChars] = '\0'; - - SDL_LogError(SDL_LOG_CATEGORY_GPU, "%s! Error Code: %s " HRESULT_FMT, msg, wszMsgBuff, res); -} - // Debug Naming static void D3D12_INTERNAL_SetResourceName( @@ -1831,7 +1789,7 @@ static D3D12DescriptorHeap *D3D12_INTERNAL_CreateDescriptorHeap( (void **)&handle); if (FAILED(res)) { - D3D12_INTERNAL_LogError(renderer->device, "Failed to create descriptor heap!", res); + D3D12_INTERNAL_SetError(renderer, "Failed to create descriptor heap!", res); D3D12_INTERNAL_DestroyDescriptorHeap(heap); return NULL; } @@ -2137,7 +2095,7 @@ static D3D12GraphicsRootSignature *D3D12_INTERNAL_CreateGraphicsRootSignature( if (FAILED(res)) { if (errorBlob) { - SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to serialize RootSignature: %s", (const char *)ID3D10Blob_GetBufferPointer(errorBlob)); + SET_ERROR("Failed to serialize RootSignature: %s", (const char *)ID3D10Blob_GetBufferPointer(errorBlob)); ID3D10Blob_Release(errorBlob); } D3D12_INTERNAL_DestroyGraphicsRootSignature(d3d12GraphicsRootSignature); @@ -2157,7 +2115,7 @@ static D3D12GraphicsRootSignature *D3D12_INTERNAL_CreateGraphicsRootSignature( if (FAILED(res)) { if (errorBlob) { - SDL_SetError("Failed to create RootSignature"); + SET_ERROR("Failed to create RootSignature: %s", (const char *)ID3D10Blob_GetBufferPointer(errorBlob)); ID3D10Blob_Release(errorBlob); } D3D12_INTERNAL_DestroyGraphicsRootSignature(d3d12GraphicsRootSignature); @@ -2355,7 +2313,7 @@ static D3D12ComputeRootSignature *D3D12_INTERNAL_CreateComputeRootSignature( if (FAILED(res)) { if (errorBlob) { - SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to serialize RootSignature: %s", (const char *)ID3D10Blob_GetBufferPointer(errorBlob)); + SET_ERROR("Failed to serialize RootSignature: %s", (const char *)ID3D10Blob_GetBufferPointer(errorBlob)); ID3D10Blob_Release(errorBlob); } D3D12_INTERNAL_DestroyComputeRootSignature(d3d12ComputeRootSignature); @@ -2374,7 +2332,7 @@ static D3D12ComputeRootSignature *D3D12_INTERNAL_CreateComputeRootSignature( if (FAILED(res)) { if (errorBlob) { - SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to create RootSignature"); + SET_ERROR("Failed to create RootSignature: %s", (const char *)ID3D10Blob_GetBufferPointer(errorBlob)); ID3D10Blob_Release(errorBlob); } D3D12_INTERNAL_DestroyComputeRootSignature(d3d12ComputeRootSignature); @@ -2411,9 +2369,8 @@ static SDL_GPUComputePipeline *D3D12_CreateComputePipeline( createinfo); if (rootSignature == NULL) { - SDL_SetError("Could not create root signature!"); SDL_free(bytecode); - return NULL; + SET_STRING_ERROR_AND_RETURN("Could not create root signature!", NULL) } D3D12_COMPUTE_PIPELINE_STATE_DESC pipelineDesc; @@ -2432,7 +2389,7 @@ static SDL_GPUComputePipeline *D3D12_CreateComputePipeline( (void **)&pipelineState); if (FAILED(res)) { - D3D12_INTERNAL_SetError(renderer->device, "Could not create compute pipeline state", res); + D3D12_INTERNAL_SetError(renderer, "Could not create compute pipeline state", res); SDL_free(bytecode); return NULL; } @@ -2697,7 +2654,6 @@ static SDL_GPUGraphicsPipeline *D3D12_CreateGraphicsPipeline( fragShader); if (rootSignature == NULL) { - SDL_SetError("Could not create root signature!"); D3D12_INTERNAL_DestroyGraphicsPipeline(pipeline); return NULL; } @@ -2712,7 +2668,7 @@ static SDL_GPUGraphicsPipeline *D3D12_CreateGraphicsPipeline( D3D_GUID(D3D_IID_ID3D12PipelineState), (void **)&pipelineState); if (FAILED(res)) { - D3D12_INTERNAL_SetError(renderer->device, "Could not create graphics pipeline state", res); + D3D12_INTERNAL_SetError(renderer, "Could not create graphics pipeline state", res); D3D12_INTERNAL_DestroyGraphicsPipeline(pipeline); return NULL; } @@ -2913,7 +2869,7 @@ static D3D12Texture *D3D12_INTERNAL_CreateTexture( D3D_GUID(D3D_IID_ID3D12Resource), (void **)&handle); if (FAILED(res)) { - D3D12_INTERNAL_LogError(renderer->device, "Failed to create texture!", res); + D3D12_INTERNAL_SetError(renderer, "Failed to create texture!", res); D3D12_INTERNAL_DestroyTexture(renderer, texture); return NULL; } @@ -3217,8 +3173,7 @@ static D3D12Buffer *D3D12_INTERNAL_CreateBuffer( } heapFlags = D3D12_HEAP_FLAG_NONE; } else { - SDL_SetError("Unrecognized buffer type!"); - return NULL; + SET_STRING_ERROR_AND_RETURN("Unrecognized buffer type!", NULL) } desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; @@ -3243,7 +3198,7 @@ static D3D12Buffer *D3D12_INTERNAL_CreateBuffer( D3D_GUID(D3D_IID_ID3D12Resource), (void **)&handle); if (FAILED(res)) { - D3D12_INTERNAL_LogError(renderer->device, "Could not create buffer!", res); + D3D12_INTERNAL_SetError(renderer, "Could not create buffer!", res); D3D12_INTERNAL_DestroyBuffer(renderer, buffer); return NULL; } @@ -3333,7 +3288,7 @@ static D3D12Buffer *D3D12_INTERNAL_CreateBuffer( NULL, (void **)&buffer->mapPointer); if (FAILED(res)) { - D3D12_INTERNAL_LogError(renderer->device, "Failed to map upload buffer!", res); + D3D12_INTERNAL_SetError(renderer, "Failed to map upload buffer!", res); D3D12_INTERNAL_DestroyBuffer(renderer, buffer); return NULL; } @@ -3382,7 +3337,6 @@ static D3D12BufferContainer *D3D12_INTERNAL_CreateBufferContainer( type); if (buffer == NULL) { - SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to create buffer!"); SDL_free(container->buffers); SDL_free(container); return NULL; @@ -3796,7 +3750,6 @@ static void D3D12_INTERNAL_CycleActiveTexture( false); if (!texture) { - SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to cycle active texture!"); return; } @@ -3878,7 +3831,6 @@ static void D3D12_INTERNAL_CycleActiveBuffer( container->type); if (!buffer) { - SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to cycle active buffer!"); return; } @@ -4168,7 +4120,7 @@ static D3D12UniformBuffer *D3D12_INTERNAL_AcquireUniformBufferFromPool( 0, NULL, (void **)&uniformBuffer->buffer->mapPointer); - ERROR_LOG_RETURN("Failed to map buffer pool!", NULL); + CHECK_D3D12_ERROR_AND_RETURN("Failed to map buffer pool!", NULL); D3D12_INTERNAL_TrackUniformBuffer(commandBuffer, uniformBuffer); @@ -5487,7 +5439,6 @@ static void D3D12_UploadToTexture( D3D12_BUFFER_TYPE_UPLOAD); if (!temporaryBuffer) { - SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to create temporary upload buffer."); return; } @@ -5534,7 +5485,6 @@ static void D3D12_UploadToTexture( D3D12_BUFFER_TYPE_UPLOAD); if (!temporaryBuffer) { - SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to create temporary upload buffer."); return; } @@ -5818,7 +5768,6 @@ static void D3D12_DownloadFromTexture( D3D12_BUFFER_TYPE_DOWNLOAD); if (!textureDownload->temporaryBuffer) { - SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to create temporary download buffer!"); SDL_free(textureDownload); return; } @@ -6048,8 +5997,7 @@ static bool D3D12_SupportsSwapchainComposition( D3D12WindowData *windowData = D3D12_INTERNAL_FetchWindowData(window); if (windowData == NULL) { - SDL_SetError("Must claim window before querying swapchain composition support!"); - return false; + SET_STRING_ERROR_AND_RETURN("Must claim window before querying swapchain composition support!", false) } // Check the color space support if necessary @@ -6218,7 +6166,7 @@ static bool D3D12_INTERNAL_InitializeSwapchainTexture( index, D3D_GUID(D3D_IID_ID3D12Resource), (void **)&swapchainTexture); - ERROR_LOG_RETURN("Could not get buffer from swapchain!", 0); + CHECK_D3D12_ERROR_AND_RETURN("Could not get buffer from swapchain!", false); pTexture = (D3D12Texture *)SDL_calloc(1, sizeof(D3D12Texture)); if (!pTexture) { @@ -6350,7 +6298,7 @@ static bool D3D12_INTERNAL_ResizeSwapchainIfNeeded( h, DXGI_FORMAT_UNKNOWN, // Keep the old format renderer->supportsTearing ? DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING : 0); - ERROR_LOG_RETURN("Could not resize swapchain buffers", 0) + CHECK_D3D12_ERROR_AND_RETURN("Could not resize swapchain buffers", false) // Create texture object for the swapchain for (Uint32 i = 0; i < MAX_FRAMES_IN_FLIGHT; i += 1) { @@ -6459,14 +6407,14 @@ static bool D3D12_INTERNAL_CreateSwapchain( &fullscreenDesc, NULL, &swapchain); - ERROR_LOG_RETURN("Could not create swapchain", 0); + CHECK_D3D12_ERROR_AND_RETURN("Could not create swapchain", false); res = IDXGISwapChain1_QueryInterface( swapchain, D3D_GUID(D3D_IID_IDXGISwapChain3), (void **)&swapchain3); IDXGISwapChain1_Release(swapchain); - ERROR_LOG_RETURN("Could not create IDXGISwapChain3", 0); + CHECK_D3D12_ERROR_AND_RETURN("Could not create IDXGISwapChain3", false); if (swapchainComposition != SDL_GPU_SWAPCHAINCOMPOSITION_SDR) { // Support already verified if we hit this block @@ -6583,9 +6531,8 @@ static bool D3D12_ClaimWindow( return true; } else { - SDL_SetError("Could not create swapchain, failed to claim window!"); SDL_free(windowData); - return false; + SET_STRING_ERROR_AND_RETURN("Could not create swapchain, failed to claim window!", false) } } else { SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Window already claimed!"); @@ -6642,18 +6589,15 @@ static bool D3D12_SetSwapchainParameters( D3D12WindowData *windowData = D3D12_INTERNAL_FetchWindowData(window); if (windowData == NULL) { - SDL_SetError("Cannot set swapchain parameters on unclaimed window!"); - return false; + SET_STRING_ERROR_AND_RETURN("Cannot set swapchain parameters on unclaimed window!", false) } if (!D3D12_SupportsSwapchainComposition(driverData, window, swapchainComposition)) { - SDL_SetError("Swapchain composition not supported!"); - return false; + SET_STRING_ERROR_AND_RETURN("Swapchain composition not supported!", false) } if (!D3D12_SupportsPresentMode(driverData, window, presentMode)) { - SDL_SetError("Present mode not supported!"); - return false; + SET_STRING_ERROR_AND_RETURN("Present mode not supported!", false) } if ( @@ -6680,11 +6624,11 @@ static SDL_GPUTextureFormat D3D12_GetSwapchainTextureFormat( SDL_GPURenderer *driverData, SDL_Window *window) { + D3D12Renderer *renderer = (D3D12Renderer *)driverData; D3D12WindowData *windowData = D3D12_INTERNAL_FetchWindowData(window); if (windowData == NULL) { - SDL_SetError("Cannot get swapchain format, window has not been claimed!"); - return SDL_GPU_TEXTUREFORMAT_INVALID; + SET_STRING_ERROR_AND_RETURN("Cannot get swapchain format, window has not been claimed!", SDL_GPU_TEXTUREFORMAT_INVALID) } return windowData->textureContainers[windowData->frameCounter].header.info.format; @@ -6707,7 +6651,7 @@ static D3D12Fence *D3D12_INTERNAL_AcquireFence( D3D_GUID(D3D_IID_ID3D12Fence), (void **)&handle); if (FAILED(res)) { - D3D12_INTERNAL_LogError(renderer->device, "Failed to create fence!", res); + D3D12_INTERNAL_SetError(renderer, "Failed to create fence!", res); SDL_UnlockMutex(renderer->fenceLock); return NULL; } @@ -6733,7 +6677,7 @@ static D3D12Fence *D3D12_INTERNAL_AcquireFence( return fence; } -static void D3D12_INTERNAL_AllocateCommandBuffer( +static bool D3D12_INTERNAL_AllocateCommandBuffer( D3D12Renderer *renderer) { D3D12CommandBuffer *commandBuffer; @@ -6743,8 +6687,7 @@ static void D3D12_INTERNAL_AllocateCommandBuffer( commandBuffer = (D3D12CommandBuffer *)SDL_calloc(1, sizeof(D3D12CommandBuffer)); if (!commandBuffer) { - SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to create ID3D12CommandList. Out of Memory"); - return; + SET_STRING_ERROR_AND_RETURN("Failed to create ID3D12CommandList. Out of Memory", false) } res = ID3D12Device_CreateCommandAllocator( @@ -6753,9 +6696,9 @@ static void D3D12_INTERNAL_AllocateCommandBuffer( D3D_GUID(D3D_IID_ID3D12CommandAllocator), (void **)&commandAllocator); if (FAILED(res)) { - SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to create ID3D12CommandAllocator"); + D3D12_INTERNAL_SetError(renderer, "Failed to create ID3D12CommandAllocator", res); D3D12_INTERNAL_DestroyCommandBuffer(commandBuffer); - return; + return false; } commandBuffer->commandAllocator = commandAllocator; @@ -6769,9 +6712,9 @@ static void D3D12_INTERNAL_AllocateCommandBuffer( (void **)&commandList); if (FAILED(res)) { - SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to create ID3D12CommandList"); + D3D12_INTERNAL_SetError(renderer, "Failed to create ID3D12CommandList", res); D3D12_INTERNAL_DestroyCommandBuffer(commandBuffer); - return; + return false; } commandBuffer->graphicsCommandList = commandList; @@ -6829,9 +6772,8 @@ static void D3D12_INTERNAL_AllocateCommandBuffer( (!commandBuffer->usedComputePipelines) || (!commandBuffer->usedUniformBuffers) || (!commandBuffer->textureDownloads)) { - SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to create ID3D12CommandList. Out of Memory"); D3D12_INTERNAL_DestroyCommandBuffer(commandBuffer); - return; + SET_STRING_ERROR_AND_RETURN("Failed to create ID3D12CommandList. Out of Memory", false) } D3D12CommandBuffer **resizedAvailableCommandBuffers = (D3D12CommandBuffer **)SDL_realloc( @@ -6839,9 +6781,8 @@ static void D3D12_INTERNAL_AllocateCommandBuffer( sizeof(D3D12CommandBuffer *) * (renderer->availableCommandBufferCapacity + 1)); if (!resizedAvailableCommandBuffers) { - SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to create ID3D12CommandList. Out of Memory"); D3D12_INTERNAL_DestroyCommandBuffer(commandBuffer); - return; + SET_STRING_ERROR_AND_RETURN("Failed to create ID3D12CommandList. Out of Memory", false) } // Add to inactive command buffer array renderer->availableCommandBufferCapacity += 1; @@ -6849,6 +6790,8 @@ static void D3D12_INTERNAL_AllocateCommandBuffer( renderer->availableCommandBuffers[renderer->availableCommandBufferCount] = commandBuffer; renderer->availableCommandBufferCount += 1; + + return true; } static D3D12CommandBuffer *D3D12_INTERNAL_AcquireCommandBufferFromPool( @@ -6857,7 +6800,9 @@ static D3D12CommandBuffer *D3D12_INTERNAL_AcquireCommandBufferFromPool( D3D12CommandBuffer *commandBuffer; if (renderer->availableCommandBufferCount == 0) { - D3D12_INTERNAL_AllocateCommandBuffer(renderer); + if (!D3D12_INTERNAL_AllocateCommandBuffer(renderer)) { + return NULL; + } } commandBuffer = renderer->availableCommandBuffers[renderer->availableCommandBufferCount - 1]; @@ -6879,7 +6824,6 @@ static SDL_GPUCommandBuffer *D3D12_AcquireCommandBuffer( SDL_UnlockMutex(renderer->acquireCommandBufferLock); if (commandBuffer == NULL) { - SDL_SetError("Failed to acquire command buffer!"); return NULL; } @@ -6888,7 +6832,6 @@ static SDL_GPUCommandBuffer *D3D12_AcquireCommandBuffer( D3D12_INTERNAL_AcquireDescriptorHeapFromPool(commandBuffer, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); if (!commandBuffer->gpuDescriptorHeaps[D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV]) { - SDL_SetError("Failed to acquire descriptor heap!"); D3D12_INTERNAL_DestroyCommandBuffer(commandBuffer); return NULL; } @@ -6897,7 +6840,6 @@ static SDL_GPUCommandBuffer *D3D12_AcquireCommandBuffer( D3D12_INTERNAL_AcquireDescriptorHeapFromPool(commandBuffer, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER); if (!commandBuffer->gpuDescriptorHeaps[D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER]) { - SDL_SetError("Failed to acquire descriptor heap!"); D3D12_INTERNAL_DestroyCommandBuffer(commandBuffer); return NULL; } @@ -6946,11 +6888,10 @@ static SDL_GPUCommandBuffer *D3D12_AcquireCommandBuffer( return (SDL_GPUCommandBuffer *)commandBuffer; } -static SDL_GPUTexture *D3D12_AcquireSwapchainTexture( +static bool D3D12_AcquireSwapchainTexture( SDL_GPUCommandBuffer *commandBuffer, SDL_Window *window, - Uint32 *w, - Uint32 *h) + SDL_GPUTexture **swapchainTexture) { D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer; D3D12Renderer *renderer = d3d12CommandBuffer->renderer; @@ -6958,33 +6899,37 @@ static SDL_GPUTexture *D3D12_AcquireSwapchainTexture( Uint32 swapchainIndex; HRESULT res; + *swapchainTexture = NULL; + windowData = D3D12_INTERNAL_FetchWindowData(window); if (windowData == NULL) { - return NULL; + SET_STRING_ERROR_AND_RETURN("Cannot acquire swapchain texture from an unclaimed window!", false) } res = D3D12_INTERNAL_ResizeSwapchainIfNeeded( renderer, windowData); - ERROR_SET_RETURN("Could not resize swapchain", NULL); + CHECK_D3D12_ERROR_AND_RETURN("Could not resize swapchain", false); if (windowData->inFlightFences[windowData->frameCounter] != NULL) { if (windowData->present_mode == SDL_GPU_PRESENTMODE_VSYNC) { // In VSYNC mode, block until the least recent presented frame is done - D3D12_WaitForFences( + if (!D3D12_WaitForFences( (SDL_GPURenderer *)renderer, true, &windowData->inFlightFences[windowData->frameCounter], - 1); + 1)) { + return false; + } } else { if (!D3D12_QueryFence( (SDL_GPURenderer *)renderer, windowData->inFlightFences[windowData->frameCounter])) { /* * In MAILBOX or IMMEDIATE mode, if the least recent fence is not signaled, - * return NULL to indicate that rendering should be skipped + * return true to indicate that there is no error but rendering should be skipped */ - return NULL; + return true; } } @@ -7009,13 +6954,9 @@ static SDL_GPUTexture *D3D12_AcquireSwapchainTexture( swapchainIndex, D3D_GUID(D3D_IID_ID3D12Resource), (void **)&windowData->textureContainers[swapchainIndex].activeTexture->resource); - ERROR_SET_RETURN("Could not acquire swapchain!", NULL); + CHECK_D3D12_ERROR_AND_RETURN("Could not acquire swapchain!", false); #endif - // Send the dimensions to the out parameters. - *w = windowData->textureContainers[swapchainIndex].header.info.width; - *h = windowData->textureContainers[swapchainIndex].header.info.height; - // Set up presentation if (d3d12CommandBuffer->presentDataCount == d3d12CommandBuffer->presentDataCapacity) { d3d12CommandBuffer->presentDataCapacity += 1; @@ -7041,7 +6982,8 @@ static SDL_GPUTexture *D3D12_AcquireSwapchainTexture( 1, &barrierDesc); - return (SDL_GPUTexture *)&windowData->textureContainers[swapchainIndex]; + *swapchainTexture = (SDL_GPUTexture*)&windowData->textureContainers[swapchainIndex]; + return true; } static void D3D12_INTERNAL_PerformPendingDestroys(D3D12Renderer *renderer) @@ -7104,10 +7046,11 @@ static void D3D12_INTERNAL_PerformPendingDestroys(D3D12Renderer *renderer) SDL_UnlockMutex(renderer->disposeLock); } -static void D3D12_INTERNAL_CopyTextureDownload( +static bool D3D12_INTERNAL_CopyTextureDownload( D3D12CommandBuffer *commandBuffer, D3D12TextureDownload *download) { + D3D12Renderer *renderer = commandBuffer->renderer; Uint8 *sourcePtr; Uint8 *destPtr; HRESULT res; @@ -7118,10 +7061,7 @@ static void D3D12_INTERNAL_CopyTextureDownload( NULL, (void **)&sourcePtr); - if (FAILED(res)) { - SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to map temporary buffer!"); - return; - } + CHECK_D3D12_ERROR_AND_RETURN("Failed to map temporary buffer", false) res = ID3D12Resource_Map( download->destinationBuffer->handle, @@ -7129,10 +7069,7 @@ static void D3D12_INTERNAL_CopyTextureDownload( NULL, (void **)&destPtr); - if (FAILED(res)) { - SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to map destination buffer!"); - return; - } + CHECK_D3D12_ERROR_AND_RETURN("Failed to map destination buffer", false) for (Uint32 sliceIndex = 0; sliceIndex < download->depth; sliceIndex += 1) { for (Uint32 rowIndex = 0; rowIndex < download->height; rowIndex += 1) { @@ -7152,33 +7089,40 @@ static void D3D12_INTERNAL_CopyTextureDownload( download->destinationBuffer->handle, 0, NULL); + + return true; } -static void D3D12_INTERNAL_CleanCommandBuffer( +static bool D3D12_INTERNAL_CleanCommandBuffer( D3D12Renderer *renderer, D3D12CommandBuffer *commandBuffer) { Uint32 i; HRESULT res; + bool result = true; // Perform deferred texture data copies for (i = 0; i < commandBuffer->textureDownloadCount; i += 1) { - D3D12_INTERNAL_CopyTextureDownload( + result &= D3D12_INTERNAL_CopyTextureDownload( commandBuffer, commandBuffer->textureDownloads[i]); SDL_free(commandBuffer->textureDownloads[i]); } commandBuffer->textureDownloadCount = 0; + if (!result) { + return false; + } + res = ID3D12CommandAllocator_Reset(commandBuffer->commandAllocator); - ERROR_LOG("Could not reset command allocator") + CHECK_D3D12_ERROR_AND_RETURN("Could not reset command allocator", false) res = ID3D12GraphicsCommandList_Reset( commandBuffer->graphicsCommandList, commandBuffer->commandAllocator, NULL); - ERROR_LOG("Could not reset graphicsCommandList") + CHECK_D3D12_ERROR_AND_RETURN("Could not reset command list", false) // Return descriptor heaps to pool D3D12_INTERNAL_ReturnDescriptorHeapToPool( @@ -7261,9 +7205,11 @@ static void D3D12_INTERNAL_CleanCommandBuffer( renderer->submittedCommandBufferCount -= 1; } } + + return true; } -static void D3D12_Submit( +static bool D3D12_Submit( SDL_GPUCommandBuffer *commandBuffer) { D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer; @@ -7316,13 +7262,16 @@ static void D3D12_Submit( // Notify the command buffer that we have completed recording res = ID3D12GraphicsCommandList_Close(d3d12CommandBuffer->graphicsCommandList); - ERROR_LOG("Failed to close command list!"); + CHECK_D3D12_ERROR_AND_RETURN("Failed to close command list!", false); res = ID3D12GraphicsCommandList_QueryInterface( d3d12CommandBuffer->graphicsCommandList, D3D_GUID(D3D_IID_ID3D12CommandList), (void **)&commandLists[0]); - ERROR_LOG("Failed to convert command list!") + if (FAILED(res)) { + SDL_UnlockMutex(renderer->submitLock); + CHECK_D3D12_ERROR_AND_RETURN("Failed to convert command list!", false) + } // Submit the command list to the queue ID3D12CommandQueue_ExecuteCommandLists( @@ -7335,7 +7284,8 @@ static void D3D12_Submit( // Acquire a fence and set it to the in-flight fence d3d12CommandBuffer->inFlightFence = D3D12_INTERNAL_AcquireFence(renderer); if (!d3d12CommandBuffer->inFlightFence) { - SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to acquire fence."); + SDL_UnlockMutex(renderer->submitLock); + return false; } // Mark that a fence should be signaled after command list execution @@ -7343,7 +7293,10 @@ static void D3D12_Submit( renderer->commandQueue, d3d12CommandBuffer->inFlightFence->handle, D3D12_FENCE_SIGNAL_VALUE); - ERROR_LOG("Failed to enqueue fence signal!"); + if (FAILED(res)) { + SDL_UnlockMutex(renderer->submitLock); + CHECK_D3D12_ERROR_AND_RETURN("Failed to enqueue fence signal!", false); + } // Mark the command buffer as submitted if (renderer->submittedCommandBufferCount + 1 >= renderer->submittedCommandBufferCapacity) { @@ -7357,6 +7310,8 @@ static void D3D12_Submit( renderer->submittedCommandBuffers[renderer->submittedCommandBufferCount] = d3d12CommandBuffer; renderer->submittedCommandBufferCount += 1; + bool result = true; + // Present, if applicable for (Uint32 i = 0; i < d3d12CommandBuffer->presentDataCount; i += 1) { D3D12PresentData *presentData = &d3d12CommandBuffer->presentDatas[i]; @@ -7375,6 +7330,9 @@ static void D3D12_Submit( presentParams.Flags = (windowData->present_mode == SDL_GPU_PRESENTMODE_IMMEDIATE) ? D3D12XBOX_PRESENT_FLAG_IMMEDIATE : D3D12XBOX_PRESENT_FLAG_NONE; renderer->commandQueue->PresentX(1, &planeParams, &presentParams); + if (FAILED(res)) { + result = false; + } #else // NOTE: flip discard always supported since DXGI 1.4 is required Uint32 syncInterval = 1; @@ -7389,10 +7347,13 @@ static void D3D12_Submit( presentFlags = DXGI_PRESENT_ALLOW_TEARING; } - IDXGISwapChain_Present( + res = IDXGISwapChain_Present( windowData->swapchain, syncInterval, presentFlags); + if (FAILED(res)) { + result = false; + } ID3D12Resource_Release(windowData->textureContainers[presentData->swapchainImageIndex].activeTexture->resource); #endif @@ -7408,7 +7369,7 @@ static void D3D12_Submit( renderer->submittedCommandBuffers[i]->inFlightFence->handle); if (fenceValue == D3D12_FENCE_SIGNAL_VALUE) { - D3D12_INTERNAL_CleanCommandBuffer( + result &= D3D12_INTERNAL_CleanCommandBuffer( renderer, renderer->submittedCommandBuffers[i]); } @@ -7417,6 +7378,8 @@ static void D3D12_Submit( D3D12_INTERNAL_PerformPendingDestroys(renderer); SDL_UnlockMutex(renderer->submitLock); + + return result; } static SDL_GPUFence *D3D12_SubmitAndAcquireFence( @@ -7428,14 +7391,13 @@ static SDL_GPUFence *D3D12_SubmitAndAcquireFence( return (SDL_GPUFence *)d3d12CommandBuffer->inFlightFence; } -static void D3D12_Wait( +static bool D3D12_Wait( SDL_GPURenderer *driverData) { D3D12Renderer *renderer = (D3D12Renderer *)driverData; D3D12Fence *fence = D3D12_INTERNAL_AcquireFence(renderer); if (!fence) { - SDL_SetError("Failed to acquire fence."); - return; + return false; } HRESULT res; @@ -7454,9 +7416,13 @@ static void D3D12_Wait( fence->handle, D3D12_FENCE_SIGNAL_VALUE, fence->event); - ERROR_LOG_RETURN("Setting fence event failed", ) + CHECK_D3D12_ERROR_AND_RETURN("Setting fence event failed", false) - WaitForSingleObject(fence->event, INFINITE); + DWORD waitResult = WaitForSingleObject(fence->event, INFINITE); + if (waitResult == WAIT_FAILED) { + SDL_UnlockMutex(renderer->submitLock); + SET_STRING_ERROR_AND_RETURN("Wait failed", false) // TODO: is there a better way to report this? + } } } @@ -7464,17 +7430,21 @@ static void D3D12_Wait( (SDL_GPURenderer *)renderer, (SDL_GPUFence *)fence); + bool result = true; + // Clean up for (Sint32 i = renderer->submittedCommandBufferCount - 1; i >= 0; i -= 1) { - D3D12_INTERNAL_CleanCommandBuffer(renderer, renderer->submittedCommandBuffers[i]); + result &= D3D12_INTERNAL_CleanCommandBuffer(renderer, renderer->submittedCommandBuffers[i]); } D3D12_INTERNAL_PerformPendingDestroys(renderer); SDL_UnlockMutex(renderer->submitLock); + + return result; } -static void D3D12_WaitForFences( +static bool D3D12_WaitForFences( SDL_GPURenderer *driverData, bool waitAll, SDL_GPUFence *const *fences, @@ -7494,24 +7464,31 @@ static void D3D12_WaitForFences( fence->handle, D3D12_FENCE_SIGNAL_VALUE, fence->event); - ERROR_LOG_RETURN("Setting fence event failed", ) + CHECK_D3D12_ERROR_AND_RETURN("Setting fence event failed", false) events[i] = fence->event; } - WaitForMultipleObjects( + DWORD waitResult = WaitForMultipleObjects( numFences, events, waitAll, INFINITE); + if (waitResult == WAIT_FAILED) { + SDL_UnlockMutex(renderer->submitLock); + SET_STRING_ERROR_AND_RETURN("Wait failed", false) // TODO: is there a better way to report this? + } + + bool result = true; + // Check for cleanups for (Sint32 i = renderer->submittedCommandBufferCount - 1; i >= 0; i -= 1) { Uint64 fenceValue = ID3D12Fence_GetCompletedValue( renderer->submittedCommandBuffers[i]->inFlightFence->handle); if (fenceValue == D3D12_FENCE_SIGNAL_VALUE) { - D3D12_INTERNAL_CleanCommandBuffer( + result &= D3D12_INTERNAL_CleanCommandBuffer( renderer, renderer->submittedCommandBuffers[i]); } @@ -7522,6 +7499,8 @@ static void D3D12_WaitForFences( SDL_stack_free(events); SDL_UnlockMutex(renderer->submitLock); + + return result; } // Feature Queries @@ -7917,7 +7896,7 @@ static void D3D12_INTERNAL_TryInitializeD3D12Debug(D3D12Renderer *renderer) } #if !(defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES)) -static void D3D12_INTERNAL_TryInitializeD3D12DebugInfoQueue(D3D12Renderer *renderer) +static bool D3D12_INTERNAL_TryInitializeD3D12DebugInfoQueue(D3D12Renderer *renderer) { ID3D12InfoQueue *infoQueue = NULL; D3D12_MESSAGE_SEVERITY severities[] = { D3D12_MESSAGE_SEVERITY_INFO }; @@ -7929,7 +7908,7 @@ static void D3D12_INTERNAL_TryInitializeD3D12DebugInfoQueue(D3D12Renderer *rende D3D_GUID(D3D_IID_ID3D12InfoQueue), (void **)&infoQueue); if (FAILED(res)) { - ERROR_LOG_RETURN("Failed to convert ID3D12Device to ID3D12InfoQueue", ); + CHECK_D3D12_ERROR_AND_RETURN("Failed to convert ID3D12Device to ID3D12InfoQueue", false); } SDL_zero(filter); @@ -7950,6 +7929,8 @@ static void D3D12_INTERNAL_TryInitializeD3D12DebugInfoQueue(D3D12Renderer *rende true); ID3D12InfoQueue_Release(infoQueue); + + return true; } #endif @@ -7979,9 +7960,8 @@ static SDL_GPUDevice *D3D12_CreateDevice(bool debugMode, bool preferLowPower, SD // Load the DXGI library renderer->dxgi_dll = SDL_LoadObject(DXGI_DLL); if (renderer->dxgi_dll == NULL) { - SDL_SetError("Could not find " DXGI_DLL); D3D12_INTERNAL_DestroyRenderer(renderer); - return NULL; + SET_STRING_ERROR_AND_RETURN("Could not find " DXGI_DLL, NULL); } #ifdef HAVE_IDXGIINFOQUEUE @@ -7996,9 +7976,8 @@ static SDL_GPUDevice *D3D12_CreateDevice(bool debugMode, bool preferLowPower, SD renderer->dxgi_dll, CREATE_DXGI_FACTORY1_FUNC); if (CreateDXGIFactoryFunc == NULL) { - SDL_SetError("Could not load function: " CREATE_DXGI_FACTORY1_FUNC); D3D12_INTERNAL_DestroyRenderer(renderer); - return NULL; + SET_STRING_ERROR_AND_RETURN("Could not load function: " CREATE_DXGI_FACTORY1_FUNC, NULL) } // Create the DXGI factory @@ -8007,7 +7986,7 @@ static SDL_GPUDevice *D3D12_CreateDevice(bool debugMode, bool preferLowPower, SD (void **)&factory1); if (FAILED(res)) { D3D12_INTERNAL_DestroyRenderer(renderer); - ERROR_SET_RETURN("Could not create DXGIFactory", NULL); + CHECK_D3D12_ERROR_AND_RETURN("Could not create DXGIFactory", NULL); } // Check for DXGI 1.4 support @@ -8017,7 +7996,7 @@ static SDL_GPUDevice *D3D12_CreateDevice(bool debugMode, bool preferLowPower, SD (void **)&renderer->factory); if (FAILED(res)) { D3D12_INTERNAL_DestroyRenderer(renderer); - ERROR_SET_RETURN("DXGI1.4 support not found, required for DX12", NULL); + CHECK_D3D12_ERROR_AND_RETURN("DXGI1.4 support not found, required for DX12", NULL); } IDXGIFactory1_Release(factory1); @@ -8060,14 +8039,14 @@ static SDL_GPUDevice *D3D12_CreateDevice(bool debugMode, bool preferLowPower, SD if (FAILED(res)) { D3D12_INTERNAL_DestroyRenderer(renderer); - ERROR_SET_RETURN("Could not find adapter for D3D12Device", NULL); + CHECK_D3D12_ERROR_AND_RETURN("Could not find adapter for D3D12Device", NULL); } // Get information about the selected adapter. Used for logging info. res = IDXGIAdapter1_GetDesc1(renderer->adapter, &adapterDesc); if (FAILED(res)) { D3D12_INTERNAL_DestroyRenderer(renderer); - ERROR_SET_RETURN("Could not get adapter description", NULL); + CHECK_D3D12_ERROR_AND_RETURN("Could not get adapter description", NULL); } SDL_LogInfo(SDL_LOG_CATEGORY_GPU, "SDL_GPU Driver: D3D12"); @@ -8077,9 +8056,8 @@ static SDL_GPUDevice *D3D12_CreateDevice(bool debugMode, bool preferLowPower, SD // Load the D3D library renderer->d3d12_dll = SDL_LoadObject(D3D12_DLL); if (renderer->d3d12_dll == NULL) { - SDL_SetError("Could not find " D3D12_DLL); D3D12_INTERNAL_DestroyRenderer(renderer); - return NULL; + SET_STRING_ERROR_AND_RETURN("Could not find " D3D12_DLL, NULL); } // Load the CreateDevice function @@ -8088,18 +8066,16 @@ static SDL_GPUDevice *D3D12_CreateDevice(bool debugMode, bool preferLowPower, SD renderer->d3d12_dll, "D3D12XboxCreateDevice"); if (D3D12XboxCreateDeviceFunc == NULL) { - SDL_SetError("Could not load function: D3D12XboxCreateDevice"); D3D12_INTERNAL_DestroyRenderer(renderer); - return NULL; + SET_STRING_ERROR_AND_RETURN("Could not load function: D3D12XboxCreateDevice", NULL) } #else D3D12CreateDeviceFunc = (PFN_D3D12_CREATE_DEVICE)SDL_LoadFunction( renderer->d3d12_dll, D3D12_CREATE_DEVICE_FUNC); if (D3D12CreateDeviceFunc == NULL) { - SDL_SetError("Could not load function: " D3D12_CREATE_DEVICE_FUNC); D3D12_INTERNAL_DestroyRenderer(renderer); - return NULL; + SET_STRING_ERROR_AND_RETURN("Could not load function: " D3D12_CREATE_DEVICE_FUNC, NULL) } #endif @@ -8107,9 +8083,8 @@ static SDL_GPUDevice *D3D12_CreateDevice(bool debugMode, bool preferLowPower, SD renderer->d3d12_dll, D3D12_SERIALIZE_ROOT_SIGNATURE_FUNC); if (renderer->D3D12SerializeRootSignature_func == NULL) { - SDL_SetError("Could not load function: " D3D12_SERIALIZE_ROOT_SIGNATURE_FUNC); D3D12_INTERNAL_DestroyRenderer(renderer); - return NULL; + SET_STRING_ERROR_AND_RETURN("Could not load function: " D3D12_SERIALIZE_ROOT_SIGNATURE_FUNC, NULL) } // Initialize the D3D12 debug layer, if applicable @@ -8176,12 +8151,14 @@ static SDL_GPUDevice *D3D12_CreateDevice(bool debugMode, bool preferLowPower, SD if (FAILED(res)) { D3D12_INTERNAL_DestroyRenderer(renderer); - ERROR_SET_RETURN("Could not create D3D12Device", NULL); + CHECK_D3D12_ERROR_AND_RETURN("Could not create D3D12Device", NULL); } // Initialize the D3D12 debug info queue, if applicable if (debugMode) { - D3D12_INTERNAL_TryInitializeD3D12DebugInfoQueue(renderer); + if (!D3D12_INTERNAL_TryInitializeD3D12DebugInfoQueue(renderer)) { + return NULL; + } } #endif @@ -8194,7 +8171,7 @@ static SDL_GPUDevice *D3D12_CreateDevice(bool debugMode, bool preferLowPower, SD sizeof(D3D12_FEATURE_DATA_ARCHITECTURE)); if (FAILED(res)) { D3D12_INTERNAL_DestroyRenderer(renderer); - ERROR_SET_RETURN("Could not get device architecture", NULL); + CHECK_D3D12_ERROR_AND_RETURN("Could not get device architecture", NULL); } renderer->UMA = (bool)architecture.UMA; @@ -8236,7 +8213,7 @@ static SDL_GPUDevice *D3D12_CreateDevice(bool debugMode, bool preferLowPower, SD if (FAILED(res)) { D3D12_INTERNAL_DestroyRenderer(renderer); - ERROR_SET_RETURN("Could not create D3D12CommandQueue", NULL); + CHECK_D3D12_ERROR_AND_RETURN("Could not create D3D12CommandQueue", NULL); } #if (defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES)) s_CommandQueue = renderer->commandQueue; @@ -8263,7 +8240,7 @@ static SDL_GPUDevice *D3D12_CreateDevice(bool debugMode, bool preferLowPower, SD (void **)&renderer->indirectDrawCommandSignature); if (FAILED(res)) { D3D12_INTERNAL_DestroyRenderer(renderer); - ERROR_SET_RETURN("Could not create indirect draw command signature", NULL) + CHECK_D3D12_ERROR_AND_RETURN("Could not create indirect draw command signature", NULL) } indirectArgumentDesc.Type = D3D12_INDIRECT_ARGUMENT_TYPE_DRAW_INDEXED; @@ -8278,7 +8255,7 @@ static SDL_GPUDevice *D3D12_CreateDevice(bool debugMode, bool preferLowPower, SD (void **)&renderer->indirectIndexedDrawCommandSignature); if (FAILED(res)) { D3D12_INTERNAL_DestroyRenderer(renderer); - ERROR_SET_RETURN("Could not create indirect indexed draw command signature", NULL) + CHECK_D3D12_ERROR_AND_RETURN("Could not create indirect indexed draw command signature", NULL) } indirectArgumentDesc.Type = D3D12_INDIRECT_ARGUMENT_TYPE_DISPATCH; @@ -8293,7 +8270,7 @@ static SDL_GPUDevice *D3D12_CreateDevice(bool debugMode, bool preferLowPower, SD (void **)&renderer->indirectDispatchCommandSignature); if (FAILED(res)) { D3D12_INTERNAL_DestroyRenderer(renderer); - ERROR_SET_RETURN("Could not create indirect dispatch command signature", NULL) + CHECK_D3D12_ERROR_AND_RETURN("Could not create indirect dispatch command signature", NULL) } // Initialize pools @@ -8341,6 +8318,10 @@ static SDL_GPUDevice *D3D12_CreateDevice(bool debugMode, bool preferLowPower, SD (D3D12_DESCRIPTOR_HEAP_TYPE)i, (i <= D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER) ? VIEW_SAMPLER_STAGING_DESCRIPTOR_COUNT : TARGET_STAGING_DESCRIPTOR_COUNT, true); + if (renderer->stagingDescriptorHeaps[i] == NULL) { + D3D12_INTERNAL_DestroyRenderer(renderer); + return NULL; + } } // Initialize GPU descriptor heaps @@ -8357,6 +8338,11 @@ static SDL_GPUDevice *D3D12_CreateDevice(bool debugMode, bool preferLowPower, SD (D3D12_DESCRIPTOR_HEAP_TYPE)i, i == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV ? VIEW_GPU_DESCRIPTOR_COUNT : SAMPLER_GPU_DESCRIPTOR_COUNT, false); + + if (renderer->descriptorHeapPools[i].heaps[j] == NULL) { + D3D12_INTERNAL_DestroyRenderer(renderer); + return NULL; + } } } @@ -8458,8 +8444,7 @@ void SDL_GDKSuspendGPU(SDL_GPUDevice *device) D3D12Renderer *renderer = (D3D12Renderer *)device->driverData; HRESULT res; if (device == NULL) { - SDL_SetError("Invalid GPU device"); - return; + SET_STRING_ERROR_AND_RETURN("Invalid GPU device", ); } SDL_LockMutex(renderer->submitLock); @@ -8477,8 +8462,7 @@ void SDL_GDKResumeGPU(SDL_GPUDevice *device) D3D12Renderer *renderer = (D3D12Renderer *)device->driverData; HRESULT res; if (device == NULL) { - SDL_SetError("Invalid GPU device"); - return; + SET_STRING_ERROR_AND_RETURN("Invalid GPU device", ); } SDL_LockMutex(renderer->submitLock); diff --git a/src/gpu/metal/SDL_gpu_metal.m b/src/gpu/metal/SDL_gpu_metal.m index 1f2abf1a71..55ab5c8ba2 100644 --- a/src/gpu/metal/SDL_gpu_metal.m +++ b/src/gpu/metal/SDL_gpu_metal.m @@ -53,13 +53,22 @@ commandBuffer->count += 1; \ SDL_AtomicIncRef(&resource->referenceCount); +#define SET_ERROR_AND_RETURN(fmt, msg, ret) \ + if (renderer->debugMode) { \ + SDL_LogError(SDL_LOG_CATEGORY_GPU, fmt, msg); \ + } \ + SDL_SetError(fmt, msg); \ + return ret; \ + +#define SET_STRING_ERROR_AND_RETURN(msg, ret) SET_ERROR_AND_RETURN("%s", msg, ret) + // Blit Shaders #include "Metal_Blit.h" // Forward Declarations -static void METAL_Wait(SDL_GPURenderer *driverData); +static bool METAL_Wait(SDL_GPURenderer *driverData); static void METAL_ReleaseWindow( SDL_GPURenderer *driverData, SDL_Window *window); @@ -574,7 +583,7 @@ struct MetalRenderer id device; id queue; - bool debug_mode; + bool debugMode; MetalWindowData **claimedWindows; Uint32 claimedWindowCount; @@ -973,9 +982,7 @@ static SDL_GPUComputePipeline *METAL_CreateComputePipeline( handle = [renderer->device newComputePipelineStateWithFunction:libraryFunction.function error:&error]; if (error != NULL) { - SDL_SetError( - "Creating compute pipeline failed: %s", [[error description] UTF8String]); - return NULL; + SET_ERROR_AND_RETURN("Creating compute pipeline failed: %s", [[error description] UTF8String], NULL); } pipeline = SDL_calloc(1, sizeof(MetalComputePipeline)); @@ -1107,9 +1114,7 @@ static SDL_GPUGraphicsPipeline *METAL_CreateGraphicsPipeline( pipelineState = [renderer->device newRenderPipelineStateWithDescriptor:pipelineDescriptor error:&error]; if (error != NULL) { - SDL_SetError( - "Creating render pipeline failed: %s", [[error description] UTF8String]); - return NULL; + SET_ERROR_AND_RETURN("Creating render pipeline failed: %s", [[error description] UTF8String], NULL); } Uint32 sampleMask = createinfo->multisample_state.enable_mask ? @@ -1146,7 +1151,7 @@ static void METAL_SetBufferName( MetalBufferContainer *container = (MetalBufferContainer *)buffer; size_t textLength = SDL_strlen(text) + 1; - if (renderer->debug_mode) { + if (renderer->debugMode) { container->debugName = SDL_realloc( container->debugName, textLength); @@ -1173,7 +1178,7 @@ static void METAL_SetTextureName( MetalTextureContainer *container = (MetalTextureContainer *)texture; size_t textLength = SDL_strlen(text) + 1; - if (renderer->debug_mode) { + if (renderer->debugMode) { container->debugName = SDL_realloc( container->debugName, textLength); @@ -1282,8 +1287,7 @@ static SDL_GPUSampler *METAL_CreateSampler( sampler = [renderer->device newSamplerStateWithDescriptor:samplerDesc]; if (sampler == NULL) { - SDL_SetError("Failed to create sampler"); - return NULL; + SET_STRING_ERROR_AND_RETURN("Failed to create sampler", NULL); } metalSampler = (MetalSampler *)SDL_calloc(1, sizeof(MetalSampler)); @@ -1341,8 +1345,7 @@ static MetalTexture *METAL_INTERNAL_CreateTexture( MTLTextureSwizzleRed, MTLTextureSwizzleAlpha); } else { - SDL_SetError("SDL_GPU_TEXTUREFORMAT_B4G4R4A4_UNORM is not supported"); - return NULL; + SET_STRING_ERROR_AND_RETURN("SDL_GPU_TEXTUREFORMAT_B4G4R4A4_UNORM is not supported", NULL); } } @@ -1409,8 +1412,7 @@ static SDL_GPUTexture *METAL_CreateTexture( createinfo); if (texture == NULL) { - SDL_SetError("Failed to create texture!"); - return NULL; + SET_STRING_ERROR_AND_RETURN("Failed to create texture", NULL); } container = SDL_calloc(1, sizeof(MetalTextureContainer)); @@ -1459,7 +1461,7 @@ static MetalTexture *METAL_INTERNAL_PrepareTextureForWrite( container->activeTexture = container->textures[container->textureCount - 1]; - if (renderer->debug_mode && container->debugName != NULL) { + if (renderer->debugMode && container->debugName != NULL) { container->activeTexture->handle.label = @(container->debugName); } } @@ -1623,7 +1625,7 @@ static MetalBuffer *METAL_INTERNAL_PrepareBufferForWrite( container->activeBuffer = container->buffers[container->bufferCount - 1]; - if (renderer->debug_mode && container->debugName != NULL) { + if (renderer->debugMode && container->debugName != NULL) { container->activeBuffer->handle.label = @(container->debugName); } } @@ -3345,7 +3347,7 @@ static void METAL_INTERNAL_PerformPendingDestroys( // Fences -static void METAL_WaitForFences( +static bool METAL_WaitForFences( SDL_GPURenderer *driverData, bool waitAll, SDL_GPUFence *const *fences, @@ -3374,6 +3376,8 @@ static void METAL_WaitForFences( } METAL_INTERNAL_PerformPendingDestroys(renderer); + + return true; } } @@ -3524,9 +3528,8 @@ static bool METAL_ClaimWindow( return true; } else { - SDL_SetError("Could not create swapchain, failed to claim window!"); SDL_free(windowData); - return false; + SET_STRING_ERROR_AND_RETURN("Could not create swapchain, failed to claim window", false); } } else { SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "Window already claimed!"); @@ -3544,7 +3547,7 @@ static void METAL_ReleaseWindow( MetalWindowData *windowData = METAL_INTERNAL_FetchWindowData(window); if (windowData == NULL) { - return; + SET_STRING_ERROR_AND_RETURN("Window is not claimed by this SDL_GpuDevice", ); } METAL_Wait(driverData); @@ -3566,20 +3569,20 @@ static void METAL_ReleaseWindow( } } -static SDL_GPUTexture *METAL_AcquireSwapchainTexture( +static bool METAL_AcquireSwapchainTexture( SDL_GPUCommandBuffer *commandBuffer, SDL_Window *window, - Uint32 *w, - Uint32 *h) + SDL_GPUTexture **texture) { @autoreleasepool { MetalCommandBuffer *metalCommandBuffer = (MetalCommandBuffer *)commandBuffer; + MetalRenderer *renderer = metalCommandBuffer->renderer; MetalWindowData *windowData; CGSize drawableSize; windowData = METAL_INTERNAL_FetchWindowData(window); if (windowData == NULL) { - return NULL; + SET_STRING_ERROR_AND_RETURN("Window is not claimed by this SDL_GpuDevice", false); } // Get the drawable and its underlying texture @@ -3591,10 +3594,6 @@ static SDL_GPUTexture *METAL_AcquireSwapchainTexture( windowData->textureContainer.header.info.width = (Uint32)drawableSize.width; windowData->textureContainer.header.info.height = (Uint32)drawableSize.height; - // Send the dimensions to the out parameters. - *w = (Uint32)drawableSize.width; - *h = (Uint32)drawableSize.height; - // Set up presentation if (metalCommandBuffer->windowDataCount == metalCommandBuffer->windowDataCapacity) { metalCommandBuffer->windowDataCapacity += 1; @@ -3606,7 +3605,8 @@ static SDL_GPUTexture *METAL_AcquireSwapchainTexture( metalCommandBuffer->windowDataCount += 1; // Return the swapchain texture - return (SDL_GPUTexture *)&windowData->textureContainer; + *texture = (SDL_GPUTexture *)&windowData->textureContainer; + return true; } } @@ -3614,11 +3614,11 @@ static SDL_GPUTextureFormat METAL_GetSwapchainTextureFormat( SDL_GPURenderer *driverData, SDL_Window *window) { + MetalRenderer *renderer = (MetalRenderer *)driverData; MetalWindowData *windowData = METAL_INTERNAL_FetchWindowData(window); if (windowData == NULL) { - SDL_SetError("Cannot get swapchain format, window has not been claimed!"); - return SDL_GPU_TEXTUREFORMAT_INVALID; + SET_STRING_ERROR_AND_RETURN("Cannot get swapchain format, window has not been claimed", SDL_GPU_TEXTUREFORMAT_INVALID); } return windowData->textureContainer.header.info.format; @@ -3631,22 +3631,20 @@ static bool METAL_SetSwapchainParameters( SDL_GPUPresentMode presentMode) { @autoreleasepool { + MetalRenderer *renderer = (MetalRenderer *)driverData; MetalWindowData *windowData = METAL_INTERNAL_FetchWindowData(window); CGColorSpaceRef colorspace; if (windowData == NULL) { - SDL_SetError("Cannot set swapchain parameters, window has not been claimed!"); - return false; + SET_STRING_ERROR_AND_RETURN("Cannot set swapchain parameters, window has not been claimed!", false); } if (!METAL_SupportsSwapchainComposition(driverData, window, swapchainComposition)) { - SDL_SetError("Swapchain composition not supported!"); - return false; + SET_STRING_ERROR_AND_RETURN("Swapchain composition not supported", false); } if (!METAL_SupportsPresentMode(driverData, window, presentMode)) { - SDL_SetError("Present mode not supported!"); - return false; + SET_STRING_ERROR_AND_RETURN("Present mode not supported", false); } METAL_Wait(driverData); @@ -3673,7 +3671,7 @@ static bool METAL_SetSwapchainParameters( // Submission -static void METAL_Submit( +static bool METAL_Submit( SDL_GPUCommandBuffer *commandBuffer) { @autoreleasepool { @@ -3720,6 +3718,8 @@ static void METAL_Submit( METAL_INTERNAL_PerformPendingDestroys(renderer); SDL_UnlockMutex(renderer->submitLock); + + return true; } } @@ -3735,7 +3735,7 @@ static SDL_GPUFence *METAL_SubmitAndAcquireFence( return (SDL_GPUFence *)fence; } -static void METAL_Wait( +static bool METAL_Wait( SDL_GPURenderer *driverData) { @autoreleasepool { @@ -3762,6 +3762,8 @@ static void METAL_Wait( METAL_INTERNAL_PerformPendingDestroys(renderer); SDL_UnlockMutex(renderer->submitLock); + + return true; } } @@ -4039,7 +4041,7 @@ static SDL_GPUDevice *METAL_CreateDevice(bool debugMode, bool preferLowPower, SD [renderer->device.name UTF8String]); // Remember debug mode - renderer->debug_mode = debugMode; + renderer->debugMode = debugMode; // Set up colorspace array SwapchainCompositionToColorSpace[0] = kCGColorSpaceSRGB; diff --git a/src/gpu/vulkan/SDL_gpu_vulkan.c b/src/gpu/vulkan/SDL_gpu_vulkan.c index 2bea8fd1b1..2811904eac 100644 --- a/src/gpu/vulkan/SDL_gpu_vulkan.c +++ b/src/gpu/vulkan/SDL_gpu_vulkan.c @@ -1165,12 +1165,12 @@ struct VulkanRenderer // Forward declarations -static Uint8 VULKAN_INTERNAL_DefragmentMemory(VulkanRenderer *renderer); -static void VULKAN_INTERNAL_BeginCommandBuffer(VulkanRenderer *renderer, VulkanCommandBuffer *commandBuffer); +static bool VULKAN_INTERNAL_DefragmentMemory(VulkanRenderer *renderer); +static bool VULKAN_INTERNAL_BeginCommandBuffer(VulkanRenderer *renderer, VulkanCommandBuffer *commandBuffer); static void VULKAN_ReleaseWindow(SDL_GPURenderer *driverData, SDL_Window *window); -static void VULKAN_Wait(SDL_GPURenderer *driverData); -static void VULKAN_WaitForFences(SDL_GPURenderer *driverData, bool waitAll, SDL_GPUFence *const *fences, Uint32 numFences); -static void VULKAN_Submit(SDL_GPUCommandBuffer *commandBuffer); +static bool VULKAN_Wait(SDL_GPURenderer *driverData); +static bool VULKAN_WaitForFences(SDL_GPURenderer *driverData, bool waitAll, SDL_GPUFence *const *fences, Uint32 numFences); +static bool VULKAN_Submit(SDL_GPUCommandBuffer *commandBuffer); // Error Handling @@ -1201,29 +1201,21 @@ static inline const char *VkErrorMessages(VkResult code) #undef ERR_TO_STR } -static inline void LogVulkanResultAsError( - const char *vulkanFunctionName, - VkResult result) -{ - if (result != VK_SUCCESS) { - SDL_LogError( - SDL_LOG_CATEGORY_GPU, - "%s: %s", - vulkanFunctionName, - VkErrorMessages(result)); - } -} +#define SET_ERROR_AND_RETURN(fmt, msg, ret) \ + if (renderer->debugMode) { \ + SDL_LogError(SDL_LOG_CATEGORY_GPU, fmt, msg); \ + } \ + SDL_SetError(fmt, msg); \ + return ret; \ -#define ERROR_LOG_RETURN(res, fn, ret) \ - if (res != VK_SUCCESS) { \ - SDL_LogError(SDL_LOG_CATEGORY_GPU, "%s %s", #fn, VkErrorMessages(res)); \ - return ret; \ - } +#define SET_STRING_ERROR_AND_RETURN(msg, ret) SET_ERROR_AND_RETURN("%s", msg, ret) -#define ERROR_SET_RETURN(res, fn, ret) \ - if (res != VK_SUCCESS) { \ - SDL_SetError("%s %s", #fn, VkErrorMessages(res)); \ - return ret; \ +#define CHECK_VULKAN_ERROR_AND_RETURN(res, fn, ret) \ + if (res != VK_SUCCESS) { \ + if (renderer->debugMode) { \ + SDL_LogError(SDL_LOG_CATEGORY_GPU, "%s %s", #fn, VkErrorMessages(res)); \ + } \ + SDL_SetError("%s %s", #fn, VkErrorMessages(res)); \ } // Utility @@ -1804,7 +1796,7 @@ static Uint8 VULKAN_INTERNAL_AllocateMemory( VK_WHOLE_SIZE, 0, (void **)&allocation->mapPointer); - ERROR_LOG_RETURN(result, vkMapMemory, 0) + CHECK_VULKAN_ERROR_AND_RETURN(result, vkMapMemory, 0) } else { allocation->mapPointer = NULL; } @@ -1837,7 +1829,7 @@ static Uint8 VULKAN_INTERNAL_BindBufferMemory( SDL_UnlockMutex(usedRegion->allocation->memoryLock); - ERROR_LOG_RETURN(vulkanResult, vkBindBufferMemory, 0) + CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkBindBufferMemory, 0) return 1; } @@ -1860,7 +1852,7 @@ static Uint8 VULKAN_INTERNAL_BindImageMemory( SDL_UnlockMutex(usedRegion->allocation->memoryLock); - ERROR_LOG_RETURN(vulkanResult, vkBindBufferMemory, 0) + CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkBindBufferMemory, 0) return 1; } @@ -2944,19 +2936,25 @@ static void VULKAN_INTERNAL_DestroyTexture( SDL_free(texture->subresources); - renderer->vkDestroyImageView( - renderer->logicalDevice, - texture->fullView, - NULL); + if (texture->fullView) { + renderer->vkDestroyImageView( + renderer->logicalDevice, + texture->fullView, + NULL); + } - renderer->vkDestroyImage( - renderer->logicalDevice, - texture->image, - NULL); + if (texture->image) { + renderer->vkDestroyImage( + renderer->logicalDevice, + texture->image, + NULL); + } - VULKAN_INTERNAL_RemoveMemoryUsedRegion( - renderer, - texture->usedRegion); + if (texture->usedRegion) { + VULKAN_INTERNAL_RemoveMemoryUsedRegion( + renderer, + texture->usedRegion); + } SDL_free(texture); } @@ -3500,12 +3498,12 @@ static bool VULKAN_INTERNAL_AllocateDescriptorSets( SDL_stack_free(descriptorSetLayouts); - ERROR_LOG_RETURN(vulkanResult, "vkAllocateDescriptorSets", false) + CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkAllocateDescriptorSets, false) return true; } -static void VULKAN_INTERNAL_AllocateDescriptorsFromPool( +static bool VULKAN_INTERNAL_AllocateDescriptorsFromPool( VulkanRenderer *renderer, DescriptorSetLayout *descriptorSetLayout, DescriptorSetPool *descriptorSetPool) @@ -3573,10 +3571,7 @@ static void VULKAN_INTERNAL_AllocateDescriptorsFromPool( NULL, &pool); - if (vulkanResult != VK_SUCCESS) { - LogVulkanResultAsError("vkCreateDescriptorPool", vulkanResult); - return; - } + CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateDescriptorPool, false) descriptorSetPool->poolCount += 1; descriptorSetPool->descriptorPools = SDL_realloc( @@ -3589,14 +3584,18 @@ static void VULKAN_INTERNAL_AllocateDescriptorsFromPool( descriptorSetPool->descriptorSets, sizeof(VkDescriptorSet) * descriptorSetPool->poolCount * DESCRIPTOR_POOL_SIZE); - VULKAN_INTERNAL_AllocateDescriptorSets( + if (!VULKAN_INTERNAL_AllocateDescriptorSets( renderer, pool, descriptorSetLayout->descriptorSetLayout, DESCRIPTOR_POOL_SIZE, - &descriptorSetPool->descriptorSets[descriptorSetPool->descriptorSetCount]); + &descriptorSetPool->descriptorSets[descriptorSetPool->descriptorSetCount])) { + return false; + } descriptorSetPool->descriptorSetCount += DESCRIPTOR_POOL_SIZE; + + return true; } // NOTE: these categories should be mutually exclusive @@ -3711,10 +3710,7 @@ static DescriptorSetLayout *VULKAN_INTERNAL_FetchDescriptorSetLayout( NULL, &descriptorSetLayout); - if (vulkanResult != VK_SUCCESS) { - LogVulkanResultAsError("vkCreateDescriptorSetLayout", vulkanResult); - return NULL; - } + CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateDescriptorSetLayout, NULL) layout = SDL_malloc(sizeof(DescriptorSetLayout)); layout->descriptorSetLayout = descriptorSetLayout; @@ -3841,9 +3837,8 @@ static VulkanGraphicsPipelineResourceLayout *VULKAN_INTERNAL_FetchGraphicsPipeli &pipelineResourceLayout->pipelineLayout); if (vulkanResult != VK_SUCCESS) { - LogVulkanResultAsError("vkCreatePipelineLayout", vulkanResult); VULKAN_INTERNAL_DestroyGraphicsPipelineResourceLayout(renderer, pipelineResourceLayout); - return NULL; + CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreatePipelineLayout, NULL) } GraphicsPipelineResourceLayoutHashTableKey *allocedKey = SDL_malloc(sizeof(GraphicsPipelineResourceLayoutHashTableKey)); @@ -3943,9 +3938,8 @@ static VulkanComputePipelineResourceLayout *VULKAN_INTERNAL_FetchComputePipeline &pipelineResourceLayout->pipelineLayout); if (vulkanResult != VK_SUCCESS) { - LogVulkanResultAsError("vkCreatePipelineLayout", vulkanResult); VULKAN_INTERNAL_DestroyComputePipelineResourceLayout(renderer, pipelineResourceLayout); - return NULL; + CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreatePipelineLayout, NULL) } ComputePipelineResourceLayoutHashTableKey *allocedKey = SDL_malloc(sizeof(ComputePipelineResourceLayoutHashTableKey)); @@ -4023,7 +4017,11 @@ static VulkanBuffer *VULKAN_INTERNAL_CreateBuffer( &createinfo, NULL, &buffer->buffer); - ERROR_LOG_RETURN(vulkanResult, vkCreateBuffer, 0) + + if (vulkanResult != VK_SUCCESS) { + SDL_free(buffer); + CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateBuffer, 0) + } bindResult = VULKAN_INTERNAL_BindMemoryForBuffer( renderer, @@ -4038,6 +4036,7 @@ static VulkanBuffer *VULKAN_INTERNAL_CreateBuffer( buffer->buffer, NULL); + SDL_free(buffer); return NULL; } @@ -4064,7 +4063,6 @@ static VulkanBufferContainer *VULKAN_INTERNAL_CreateBufferContainer( type); if (buffer == NULL) { - SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to create buffer container!"); return NULL; } @@ -4107,7 +4105,7 @@ static VulkanTextureSubresource *VULKAN_INTERNAL_FetchTextureSubresource( return &textureContainer->activeTexture->subresources[index]; } -static void VULKAN_INTERNAL_CreateRenderTargetView( +static bool VULKAN_INTERNAL_CreateRenderTargetView( VulkanRenderer *renderer, VulkanTexture *texture, Uint32 layerOrDepth, @@ -4140,16 +4138,14 @@ static void VULKAN_INTERNAL_CreateRenderTargetView( pView); if (vulkanResult != VK_SUCCESS) { - LogVulkanResultAsError( - "vkCreateImageView", - vulkanResult); - SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to create color attachment image view"); *pView = (VkImageView)VK_NULL_HANDLE; - return; + CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateImageView, false) } + + return true; } -static void VULKAN_INTERNAL_CreateSubresourceView( +static bool VULKAN_INTERNAL_CreateSubresourceView( VulkanRenderer *renderer, const SDL_GPUTextureCreateInfo *createinfo, VulkanTexture *texture, @@ -4182,18 +4178,16 @@ static void VULKAN_INTERNAL_CreateSubresourceView( pView); if (vulkanResult != VK_SUCCESS) { - LogVulkanResultAsError( - "vkCreateImageView", - vulkanResult); - SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to create color attachment image view"); *pView = (VkImageView)VK_NULL_HANDLE; - return; + CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateImageView, false) } + + return true; } // Swapchain -static Uint8 VULKAN_INTERNAL_QuerySwapchainSupport( +static bool VULKAN_INTERNAL_QuerySwapchainSupport( VulkanRenderer *renderer, VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, @@ -4214,7 +4208,7 @@ static Uint8 VULKAN_INTERNAL_QuerySwapchainSupport( if (!supportsPresent) { SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "This surface does not support presenting!"); - return 0; + return false; } // Run the device surface queries @@ -4222,7 +4216,7 @@ static Uint8 VULKAN_INTERNAL_QuerySwapchainSupport( physicalDevice, surface, &outputDetails->capabilities); - ERROR_LOG_RETURN(result, vkGetPhysicalDeviceSurfaceCapabilitiesKHR, 0) + CHECK_VULKAN_ERROR_AND_RETURN(result, vkGetPhysicalDeviceSurfaceCapabilitiesKHR, false) if (!(outputDetails->capabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR)) { SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "Opaque presentation unsupported! Expect weird transparency bugs!"); @@ -4233,13 +4227,13 @@ static Uint8 VULKAN_INTERNAL_QuerySwapchainSupport( surface, &outputDetails->formatsLength, NULL); - ERROR_LOG_RETURN(result, vkGetPhysicalDeviceSurfaceFormatsKHR, 0) + CHECK_VULKAN_ERROR_AND_RETURN(result, vkGetPhysicalDeviceSurfaceFormatsKHR, false) result = renderer->vkGetPhysicalDeviceSurfacePresentModesKHR( physicalDevice, surface, &outputDetails->presentModesLength, NULL); - ERROR_LOG_RETURN(result, vkGetPhysicalDeviceSurfacePresentModesKHR, 0) + CHECK_VULKAN_ERROR_AND_RETURN(result, vkGetPhysicalDeviceSurfacePresentModesKHR, false) // Generate the arrays, if applicable @@ -4258,13 +4252,8 @@ static Uint8 VULKAN_INTERNAL_QuerySwapchainSupport( &outputDetails->formatsLength, outputDetails->formats); if (result != VK_SUCCESS) { - SDL_LogError( - SDL_LOG_CATEGORY_GPU, - "vkGetPhysicalDeviceSurfaceFormatsKHR: %s", - VkErrorMessages(result)); - SDL_free(outputDetails->formats); - return 0; + CHECK_VULKAN_ERROR_AND_RETURN(result, vkGetPhysicalDeviceSurfaceFormatsKHR, false) } } @@ -4275,7 +4264,7 @@ static Uint8 VULKAN_INTERNAL_QuerySwapchainSupport( if (!outputDetails->presentModes) { SDL_free(outputDetails->formats); - return 0; + return false; } result = renderer->vkGetPhysicalDeviceSurfacePresentModesKHR( @@ -4284,21 +4273,16 @@ static Uint8 VULKAN_INTERNAL_QuerySwapchainSupport( &outputDetails->presentModesLength, outputDetails->presentModes); if (result != VK_SUCCESS) { - SDL_LogError( - SDL_LOG_CATEGORY_GPU, - "vkGetPhysicalDeviceSurfacePresentModesKHR: %s", - VkErrorMessages(result)); - SDL_free(outputDetails->formats); SDL_free(outputDetails->presentModes); - return 0; + CHECK_VULKAN_ERROR_AND_RETURN(result, vkGetPhysicalDeviceSurfacePresentModesKHR, false) } } /* If we made it here, all the queries were successful. This does NOT * necessarily mean there are any supported formats or present modes! */ - return 1; + return true; } static bool VULKAN_INTERNAL_VerifySwapSurfaceFormat( @@ -4383,7 +4367,6 @@ static bool VULKAN_INTERNAL_CreateSwapchain( SDL_free(swapchainSupportDetails.presentModes); } SDL_free(swapchainData); - SDL_LogError(SDL_LOG_CATEGORY_GPU, "Device does not support swap chain creation"); return false; } @@ -4451,10 +4434,10 @@ static bool VULKAN_INTERNAL_CreateSwapchain( SDL_free(swapchainData); if (!hasValidSwapchainComposition) { - SDL_LogError(SDL_LOG_CATEGORY_GPU, "Device does not support requested swapchain composition!"); + SET_STRING_ERROR_AND_RETURN("Device does not support requested swapchain composition!", false); } if (!hasValidPresentMode) { - SDL_LogError(SDL_LOG_CATEGORY_GPU, "Device does not support requested present_mode!"); + SET_STRING_ERROR_AND_RETURN("Device does not support requested present_mode!", false); } return false; } @@ -4491,8 +4474,7 @@ static bool VULKAN_INTERNAL_CreateSwapchain( SDL_free(swapchainSupportDetails.presentModes); } SDL_free(swapchainData); - SDL_LogError(SDL_LOG_CATEGORY_GPU, "No fallback swapchain size available!"); - return false; + SET_STRING_ERROR_AND_RETURN("No fallback swapchain size available!", false); } } @@ -4558,8 +4540,7 @@ static bool VULKAN_INTERNAL_CreateSwapchain( swapchainData->surface, NULL); SDL_free(swapchainData); - ERROR_LOG_RETURN(vulkanResult, "vkCreateSwapchainKHR", false) - return false; + CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateSwapchainKHR, false) } renderer->vkGetSwapchainImagesKHR( @@ -4567,6 +4548,7 @@ static bool VULKAN_INTERNAL_CreateSwapchain( swapchainData->swapchain, &swapchainData->imageCount, NULL); + CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkGetSwapchainImagesKHR, false) swapchainData->textureContainers = SDL_malloc( sizeof(VulkanTextureContainer) * swapchainData->imageCount); @@ -4582,11 +4564,12 @@ static bool VULKAN_INTERNAL_CreateSwapchain( swapchainImages = SDL_stack_alloc(VkImage, swapchainData->imageCount); - renderer->vkGetSwapchainImagesKHR( + vulkanResult = renderer->vkGetSwapchainImagesKHR( renderer->logicalDevice, swapchainData->swapchain, &swapchainData->imageCount, swapchainImages); + CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkGetSwapchainImagesKHR, false) for (i = 0; i < swapchainData->imageCount; i += 1) { @@ -4625,14 +4608,18 @@ static bool VULKAN_INTERNAL_CreateSwapchain( swapchainData->textureContainers[i].activeTexture->subresources[0].level = 0; swapchainData->textureContainers[i].activeTexture->subresources[0].transitioned = true; swapchainData->textureContainers[i].activeTexture->subresources[0].renderTargetViews = SDL_malloc(sizeof(VkImageView)); - VULKAN_INTERNAL_CreateRenderTargetView( + // TODO: ERROR CHECK + if (!VULKAN_INTERNAL_CreateRenderTargetView( renderer, swapchainData->textureContainers[i].activeTexture, 0, 0, swapchainData->format, swapchainData->swapchainSwizzle, - &swapchainData->textureContainers[i].activeTexture->subresources[0].renderTargetViews[0]); + &swapchainData->textureContainers[i].activeTexture->subresources[0].renderTargetViews[0])) { + SDL_free(swapchainData); + return false; + } } SDL_stack_free(swapchainImages); @@ -4642,29 +4629,40 @@ static bool VULKAN_INTERNAL_CreateSwapchain( semaphoreCreateInfo.flags = 0; for (i = 0; i < MAX_FRAMES_IN_FLIGHT; i += 1) { - renderer->vkCreateSemaphore( + vulkanResult = renderer->vkCreateSemaphore( renderer->logicalDevice, &semaphoreCreateInfo, NULL, &swapchainData->imageAvailableSemaphore[i]); + if (vulkanResult != VK_SUCCESS) { + SDL_free(swapchainData); + CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateSemaphore, false) + } + renderer->vkCreateSemaphore( renderer->logicalDevice, &semaphoreCreateInfo, NULL, &swapchainData->renderFinishedSemaphore[i]); + if (vulkanResult != VK_SUCCESS) { + SDL_free(swapchainData); + CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateSemaphore, false) + } + swapchainData->inFlightFences[i] = NULL; } windowData->swapchainData = swapchainData; windowData->needsSwapchainRecreate = false; + return true; } // Command Buffers -static void VULKAN_INTERNAL_BeginCommandBuffer( +static bool VULKAN_INTERNAL_BeginCommandBuffer( VulkanRenderer *renderer, VulkanCommandBuffer *commandBuffer) { @@ -4681,23 +4679,21 @@ static void VULKAN_INTERNAL_BeginCommandBuffer( commandBuffer->commandBuffer, &beginInfo); - if (result != VK_SUCCESS) { - LogVulkanResultAsError("vkBeginCommandBuffer", result); - } + CHECK_VULKAN_ERROR_AND_RETURN(result, vkBeginCommandBuffer, false) + + return true; } -static void VULKAN_INTERNAL_EndCommandBuffer( +static bool VULKAN_INTERNAL_EndCommandBuffer( VulkanRenderer *renderer, VulkanCommandBuffer *commandBuffer) { - VkResult result; - - result = renderer->vkEndCommandBuffer( + VkResult result = renderer->vkEndCommandBuffer( commandBuffer->commandBuffer); - if (result != VK_SUCCESS) { - LogVulkanResultAsError("vkEndCommandBuffer", result); - } + CHECK_VULKAN_ERROR_AND_RETURN(result, vkEndCommandBuffer, false) + + return true; } static void VULKAN_DestroyDevice( @@ -4860,10 +4856,12 @@ static VkDescriptorSet VULKAN_INTERNAL_FetchDescriptorSet( &vulkanCommandBuffer->descriptorSetCache->pools[descriptorSetLayout->ID]; if (pool->descriptorSetIndex == pool->descriptorSetCount) { - VULKAN_INTERNAL_AllocateDescriptorsFromPool( + if (!VULKAN_INTERNAL_AllocateDescriptorsFromPool( renderer, descriptorSetLayout, - pool); + pool)) { + return VK_NULL_HANDLE; + } } VkDescriptorSet descriptorSet = pool->descriptorSets[pool->descriptorSetIndex]; @@ -5445,13 +5443,10 @@ static VulkanTexture *VULKAN_INTERNAL_CreateTexture( Uint32 layerCount = (createinfo->type == SDL_GPU_TEXTURETYPE_3D) ? 1 : createinfo->layer_count_or_depth; Uint32 depth = (createinfo->type == SDL_GPU_TEXTURETYPE_3D) ? createinfo->layer_count_or_depth : 1; - // FIXME: We probably shouldn't alloc this until the actual image/memory creation have succeeded! - VulkanTexture *texture = SDL_malloc(sizeof(VulkanTexture)); - texture->markedForDestroy = false; + VulkanTexture *texture = SDL_calloc(1, sizeof(VulkanTexture)); texture->swizzle = SwizzleForSDLFormat(createinfo->format); texture->depth = depth; texture->usage = createinfo->usage; - texture->fullView = VK_NULL_HANDLE; SDL_SetAtomicInt(&texture->referenceCount, 0); if (IsDepthFormat(createinfo->format)) { @@ -5508,7 +5503,11 @@ static VulkanTexture *VULKAN_INTERNAL_CreateTexture( &imageCreateInfo, NULL, &texture->image); - ERROR_LOG_RETURN(vulkanResult, vkCreateImage, 0) + + if (vulkanResult != VK_SUCCESS) { + VULKAN_INTERNAL_DestroyTexture(renderer, texture); + CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateImage, NULL) + } bindResult = VULKAN_INTERNAL_BindMemoryForImage( renderer, @@ -5521,8 +5520,8 @@ static VulkanTexture *VULKAN_INTERNAL_CreateTexture( texture->image, NULL); - SDL_LogError(SDL_LOG_CATEGORY_GPU, "Unable to bind memory for texture!"); - return NULL; + VULKAN_INTERNAL_DestroyTexture(renderer, texture); + SET_STRING_ERROR_AND_RETURN("Unable to bind memory for texture!", NULL) } texture->usedRegion->vulkanTexture = texture; // lol @@ -5559,13 +5558,17 @@ static VulkanTexture *VULKAN_INTERNAL_CreateTexture( NULL, &texture->fullView); - ERROR_LOG_RETURN(vulkanResult, "vkCreateImageView", NULL) + if (vulkanResult != VK_SUCCESS) { + VULKAN_INTERNAL_DestroyTexture(renderer, texture); + CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, "vkCreateImageView", NULL) + } } // Define slices texture->subresourceCount = layerCount * createinfo->num_levels; - texture->subresources = SDL_malloc( - texture->subresourceCount * sizeof(VulkanTextureSubresource)); + texture->subresources = SDL_calloc( + texture->subresourceCount, + sizeof(VulkanTextureSubresource)); for (Uint32 i = 0; i < layerCount; i += 1) { for (Uint32 j = 0; j < createinfo->num_levels; j += 1) { @@ -5574,57 +5577,65 @@ static VulkanTexture *VULKAN_INTERNAL_CreateTexture( i, createinfo->num_levels); - texture->subresources[subresourceIndex].renderTargetViews = NULL; - texture->subresources[subresourceIndex].computeWriteView = VK_NULL_HANDLE; - texture->subresources[subresourceIndex].depthStencilView = VK_NULL_HANDLE; - if (createinfo->usage & SDL_GPU_TEXTUREUSAGE_COLOR_TARGET) { texture->subresources[subresourceIndex].renderTargetViews = SDL_malloc( depth * sizeof(VkImageView)); if (depth > 1) { for (Uint32 k = 0; k < depth; k += 1) { - VULKAN_INTERNAL_CreateRenderTargetView( + if (!VULKAN_INTERNAL_CreateRenderTargetView( renderer, texture, k, j, SDLToVK_TextureFormat[createinfo->format], texture->swizzle, - &texture->subresources[subresourceIndex].renderTargetViews[k]); + &texture->subresources[subresourceIndex].renderTargetViews[k])) { + VULKAN_INTERNAL_DestroyTexture(renderer, texture); + return NULL; + } } } else { - VULKAN_INTERNAL_CreateRenderTargetView( + if (!VULKAN_INTERNAL_CreateRenderTargetView( renderer, texture, i, j, SDLToVK_TextureFormat[createinfo->format], texture->swizzle, - &texture->subresources[subresourceIndex].renderTargetViews[0]); + &texture->subresources[subresourceIndex].renderTargetViews[0])) { + VULKAN_INTERNAL_DestroyTexture(renderer, texture); + return NULL; + } } } if (createinfo->usage & SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_WRITE) { - VULKAN_INTERNAL_CreateSubresourceView( + if (!VULKAN_INTERNAL_CreateSubresourceView( renderer, createinfo, texture, i, j, texture->swizzle, - &texture->subresources[subresourceIndex].computeWriteView); + &texture->subresources[subresourceIndex].computeWriteView)) { + VULKAN_INTERNAL_DestroyTexture(renderer, texture); + return NULL; + } } if (createinfo->usage & SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET) { - VULKAN_INTERNAL_CreateSubresourceView( + if (!VULKAN_INTERNAL_CreateSubresourceView( renderer, createinfo, texture, i, j, texture->swizzle, - &texture->subresources[subresourceIndex].depthStencilView); + &texture->subresources[subresourceIndex].depthStencilView)) { + VULKAN_INTERNAL_DestroyTexture(renderer, texture); + return NULL; + } } texture->subresources[subresourceIndex].parent = texture; @@ -5660,7 +5671,6 @@ static void VULKAN_INTERNAL_CycleActiveBuffer( container->activeBuffer->type); if (!buffer) { - SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to cycle active buffer!"); return; } @@ -5708,7 +5718,6 @@ static void VULKAN_INTERNAL_CycleActiveTexture( &container->header.info); if (!texture) { - SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to cycle active texture!"); return; } @@ -5910,10 +5919,7 @@ static VkRenderPass VULKAN_INTERNAL_CreateRenderPass( NULL, &renderPass); - if (vulkanResult != VK_SUCCESS) { - renderPass = VK_NULL_HANDLE; - LogVulkanResultAsError("vkCreateRenderPass", vulkanResult); - } + CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateRenderPass, VK_NULL_HANDLE); return renderPass; } @@ -6005,10 +6011,7 @@ static VkRenderPass VULKAN_INTERNAL_CreateTransientRenderPass( NULL, &renderPass); - if (result != VK_SUCCESS) { - renderPass = VK_NULL_HANDLE; - LogVulkanResultAsError("vkCreateRenderPass", result); - } + CHECK_VULKAN_ERROR_AND_RETURN(result, vkCreateRenderPass, VK_NULL_HANDLE) return renderPass; } @@ -6293,7 +6296,7 @@ static SDL_GPUGraphicsPipeline *VULKAN_CreateGraphicsPipeline( SDL_stack_free(colorBlendAttachmentStates); SDL_stack_free(divisorDescriptions); SDL_free(graphicsPipeline); - SDL_SetError("Failed to initialize pipeline resource layout!"); + SET_STRING_ERROR_AND_RETURN("Failed to initialize pipeline resource layout!", NULL); return NULL; } @@ -6340,7 +6343,7 @@ static SDL_GPUGraphicsPipeline *VULKAN_CreateGraphicsPipeline( if (vulkanResult != VK_SUCCESS) { SDL_free(graphicsPipeline); - ERROR_SET_RETURN(vulkanResult, "vkCreateGraphicsPipelines", NULL) + CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateGraphicsPipelines, NULL) } SDL_SetAtomicInt(&graphicsPipeline->referenceCount, 0); @@ -6360,8 +6363,7 @@ static SDL_GPUComputePipeline *VULKAN_CreateComputePipeline( VulkanComputePipeline *vulkanComputePipeline; if (createinfo->format != SDL_GPU_SHADERFORMAT_SPIRV) { - SDL_SetError("Incompatible shader format for Vulkan!"); - return NULL; + SET_STRING_ERROR_AND_RETURN("Incompatible shader format for Vulkan!", NULL) } vulkanComputePipeline = SDL_malloc(sizeof(VulkanComputePipeline)); @@ -6379,7 +6381,7 @@ static SDL_GPUComputePipeline *VULKAN_CreateComputePipeline( if (vulkanResult != VK_SUCCESS) { SDL_free(vulkanComputePipeline); - ERROR_SET_RETURN(vulkanResult, "vkCreateShaderModule", NULL) + CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateShaderModule, NULL) } pipelineShaderStageCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; @@ -6421,7 +6423,7 @@ static SDL_GPUComputePipeline *VULKAN_CreateComputePipeline( if (vulkanResult != VK_SUCCESS) { VULKAN_INTERNAL_DestroyComputePipeline(renderer, vulkanComputePipeline); - ERROR_SET_RETURN(vulkanResult, "vkCreateComputePipeline", NULL) + CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateComputePipeline, NULL) return NULL; } @@ -6466,7 +6468,7 @@ static SDL_GPUSampler *VULKAN_CreateSampler( if (vulkanResult != VK_SUCCESS) { SDL_free(vulkanSampler); - ERROR_SET_RETURN(vulkanResult, "vkCreateSampler", NULL) + CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateSampler, NULL) } SDL_SetAtomicInt(&vulkanSampler->referenceCount, 0); @@ -6499,7 +6501,7 @@ static SDL_GPUShader *VULKAN_CreateShader( if (vulkanResult != VK_SUCCESS) { SDL_free(vulkanShader); - ERROR_SET_RETURN(vulkanResult, "vkCreateShaderModule", NULL) + CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateShaderModule, NULL) } entryPointNameLength = SDL_strlen(createinfo->entrypoint) + 1; @@ -6540,7 +6542,6 @@ static SDL_GPUTexture *VULKAN_CreateTexture( createinfo); if (texture == NULL) { - SDL_SetError("Failed to create texture!"); return NULL; } @@ -6874,7 +6875,6 @@ static VkRenderPass VULKAN_INTERNAL_FetchRenderPass( depthStencilTargetInfo); if (renderPassHandle == VK_NULL_HANDLE) { - SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to create VkRenderPass!"); return VK_NULL_HANDLE; } @@ -7030,9 +7030,8 @@ static VulkanFramebuffer *VULKAN_INTERNAL_FetchFramebuffer( SDL_UnlockMutex(renderer->framebufferFetchLock); } else { - LogVulkanResultAsError("vkCreateFramebuffer", result); SDL_free(vulkanFramebuffer); - vulkanFramebuffer = NULL; + CHECK_VULKAN_ERROR_AND_RETURN(result, vkCreateFramebuffer, NULL) } return vulkanFramebuffer; @@ -7536,6 +7535,10 @@ static void VULKAN_BeginRenderPass( numColorTargets, depthStencilTargetInfo); + if (renderPass == VK_NULL_HANDLE) { + return; + } + framebuffer = VULKAN_INTERNAL_FetchFramebuffer( renderer, renderPass, @@ -7545,6 +7548,10 @@ static void VULKAN_BeginRenderPass( framebufferWidth, framebufferHeight); + if (framebuffer == NULL) { + return; + } + VULKAN_INTERNAL_TrackFramebuffer(renderer, vulkanCommandBuffer, framebuffer); // Set clear values @@ -8921,18 +8928,16 @@ static void VULKAN_Blit( VULKAN_INTERNAL_TrackTexture(vulkanCommandBuffer, dstSubresource->parent); } -static void VULKAN_INTERNAL_AllocateCommandBuffers( +static bool VULKAN_INTERNAL_AllocateCommandBuffer( VulkanRenderer *renderer, - VulkanCommandPool *vulkanCommandPool, - Uint32 allocateCount) + VulkanCommandPool *vulkanCommandPool) { VkCommandBufferAllocateInfo allocateInfo; VkResult vulkanResult; - Uint32 i; - VkCommandBuffer *commandBuffers = SDL_stack_alloc(VkCommandBuffer, allocateCount); + VkCommandBuffer commandBufferHandle; VulkanCommandBuffer *commandBuffer; - vulkanCommandPool->inactiveCommandBufferCapacity += allocateCount; + vulkanCommandPool->inactiveCommandBufferCapacity += 1; vulkanCommandPool->inactiveCommandBuffers = SDL_realloc( vulkanCommandPool->inactiveCommandBuffers, @@ -8942,112 +8947,106 @@ static void VULKAN_INTERNAL_AllocateCommandBuffers( allocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; allocateInfo.pNext = NULL; allocateInfo.commandPool = vulkanCommandPool->commandPool; - allocateInfo.commandBufferCount = allocateCount; + allocateInfo.commandBufferCount = 1; allocateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; vulkanResult = renderer->vkAllocateCommandBuffers( renderer->logicalDevice, &allocateInfo, - commandBuffers); + &commandBufferHandle); - if (vulkanResult != VK_SUCCESS) { - LogVulkanResultAsError("vkAllocateCommandBuffers", vulkanResult); - SDL_stack_free(commandBuffers); - return; - } + CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkAllocateCommandBuffers, false) - for (i = 0; i < allocateCount; i += 1) { - commandBuffer = SDL_malloc(sizeof(VulkanCommandBuffer)); - commandBuffer->renderer = renderer; - commandBuffer->commandPool = vulkanCommandPool; - commandBuffer->commandBuffer = commandBuffers[i]; + commandBuffer = SDL_malloc(sizeof(VulkanCommandBuffer)); + commandBuffer->renderer = renderer; + commandBuffer->commandPool = vulkanCommandPool; + commandBuffer->commandBuffer = commandBufferHandle; - commandBuffer->inFlightFence = VK_NULL_HANDLE; + commandBuffer->inFlightFence = VK_NULL_HANDLE; - // Presentation tracking + // Presentation tracking - commandBuffer->presentDataCapacity = 1; - commandBuffer->presentDataCount = 0; - commandBuffer->presentDatas = SDL_malloc( - commandBuffer->presentDataCapacity * sizeof(VulkanPresentData)); + commandBuffer->presentDataCapacity = 1; + commandBuffer->presentDataCount = 0; + commandBuffer->presentDatas = SDL_malloc( + commandBuffer->presentDataCapacity * sizeof(VulkanPresentData)); - commandBuffer->waitSemaphoreCapacity = 1; - commandBuffer->waitSemaphoreCount = 0; - commandBuffer->waitSemaphores = SDL_malloc( - commandBuffer->waitSemaphoreCapacity * sizeof(VkSemaphore)); + commandBuffer->waitSemaphoreCapacity = 1; + commandBuffer->waitSemaphoreCount = 0; + commandBuffer->waitSemaphores = SDL_malloc( + commandBuffer->waitSemaphoreCapacity * sizeof(VkSemaphore)); - commandBuffer->signalSemaphoreCapacity = 1; - commandBuffer->signalSemaphoreCount = 0; - commandBuffer->signalSemaphores = SDL_malloc( - commandBuffer->signalSemaphoreCapacity * sizeof(VkSemaphore)); + commandBuffer->signalSemaphoreCapacity = 1; + commandBuffer->signalSemaphoreCount = 0; + commandBuffer->signalSemaphores = SDL_malloc( + commandBuffer->signalSemaphoreCapacity * sizeof(VkSemaphore)); - // Resource bind tracking + // Resource bind tracking - commandBuffer->needNewVertexResourceDescriptorSet = true; - commandBuffer->needNewVertexUniformDescriptorSet = true; - commandBuffer->needNewVertexUniformOffsets = true; - commandBuffer->needNewFragmentResourceDescriptorSet = true; - commandBuffer->needNewFragmentUniformDescriptorSet = true; - commandBuffer->needNewFragmentUniformOffsets = true; + commandBuffer->needNewVertexResourceDescriptorSet = true; + commandBuffer->needNewVertexUniformDescriptorSet = true; + commandBuffer->needNewVertexUniformOffsets = true; + commandBuffer->needNewFragmentResourceDescriptorSet = true; + commandBuffer->needNewFragmentUniformDescriptorSet = true; + commandBuffer->needNewFragmentUniformOffsets = true; - commandBuffer->needNewComputeWriteOnlyDescriptorSet = true; - commandBuffer->needNewComputeReadOnlyDescriptorSet = true; - commandBuffer->needNewComputeUniformDescriptorSet = true; - commandBuffer->needNewComputeUniformOffsets = true; + commandBuffer->needNewComputeWriteOnlyDescriptorSet = true; + commandBuffer->needNewComputeReadOnlyDescriptorSet = true; + commandBuffer->needNewComputeUniformDescriptorSet = true; + commandBuffer->needNewComputeUniformOffsets = true; - commandBuffer->vertexResourceDescriptorSet = VK_NULL_HANDLE; - commandBuffer->vertexUniformDescriptorSet = VK_NULL_HANDLE; - commandBuffer->fragmentResourceDescriptorSet = VK_NULL_HANDLE; - commandBuffer->fragmentUniformDescriptorSet = VK_NULL_HANDLE; + commandBuffer->vertexResourceDescriptorSet = VK_NULL_HANDLE; + commandBuffer->vertexUniformDescriptorSet = VK_NULL_HANDLE; + commandBuffer->fragmentResourceDescriptorSet = VK_NULL_HANDLE; + commandBuffer->fragmentUniformDescriptorSet = VK_NULL_HANDLE; - commandBuffer->computeReadOnlyDescriptorSet = VK_NULL_HANDLE; - commandBuffer->computeWriteOnlyDescriptorSet = VK_NULL_HANDLE; - commandBuffer->computeUniformDescriptorSet = VK_NULL_HANDLE; + commandBuffer->computeReadOnlyDescriptorSet = VK_NULL_HANDLE; + commandBuffer->computeWriteOnlyDescriptorSet = VK_NULL_HANDLE; + commandBuffer->computeUniformDescriptorSet = VK_NULL_HANDLE; - // Resource tracking + // Resource tracking - commandBuffer->usedBufferCapacity = 4; - commandBuffer->usedBufferCount = 0; - commandBuffer->usedBuffers = SDL_malloc( - commandBuffer->usedBufferCapacity * sizeof(VulkanBuffer *)); + commandBuffer->usedBufferCapacity = 4; + commandBuffer->usedBufferCount = 0; + commandBuffer->usedBuffers = SDL_malloc( + commandBuffer->usedBufferCapacity * sizeof(VulkanBuffer *)); - commandBuffer->usedTextureCapacity = 4; - commandBuffer->usedTextureCount = 0; - commandBuffer->usedTextures = SDL_malloc( - commandBuffer->usedTextureCapacity * sizeof(VulkanTexture *)); + commandBuffer->usedTextureCapacity = 4; + commandBuffer->usedTextureCount = 0; + commandBuffer->usedTextures = SDL_malloc( + commandBuffer->usedTextureCapacity * sizeof(VulkanTexture *)); - commandBuffer->usedSamplerCapacity = 4; - commandBuffer->usedSamplerCount = 0; - commandBuffer->usedSamplers = SDL_malloc( - commandBuffer->usedSamplerCapacity * sizeof(VulkanSampler *)); + commandBuffer->usedSamplerCapacity = 4; + commandBuffer->usedSamplerCount = 0; + commandBuffer->usedSamplers = SDL_malloc( + commandBuffer->usedSamplerCapacity * sizeof(VulkanSampler *)); - commandBuffer->usedGraphicsPipelineCapacity = 4; - commandBuffer->usedGraphicsPipelineCount = 0; - commandBuffer->usedGraphicsPipelines = SDL_malloc( - commandBuffer->usedGraphicsPipelineCapacity * sizeof(VulkanGraphicsPipeline *)); + commandBuffer->usedGraphicsPipelineCapacity = 4; + commandBuffer->usedGraphicsPipelineCount = 0; + commandBuffer->usedGraphicsPipelines = SDL_malloc( + commandBuffer->usedGraphicsPipelineCapacity * sizeof(VulkanGraphicsPipeline *)); - commandBuffer->usedComputePipelineCapacity = 4; - commandBuffer->usedComputePipelineCount = 0; - commandBuffer->usedComputePipelines = SDL_malloc( - commandBuffer->usedComputePipelineCapacity * sizeof(VulkanComputePipeline *)); + commandBuffer->usedComputePipelineCapacity = 4; + commandBuffer->usedComputePipelineCount = 0; + commandBuffer->usedComputePipelines = SDL_malloc( + commandBuffer->usedComputePipelineCapacity * sizeof(VulkanComputePipeline *)); - commandBuffer->usedFramebufferCapacity = 4; - commandBuffer->usedFramebufferCount = 0; - commandBuffer->usedFramebuffers = SDL_malloc( - commandBuffer->usedFramebufferCapacity * sizeof(VulkanFramebuffer *)); + commandBuffer->usedFramebufferCapacity = 4; + commandBuffer->usedFramebufferCount = 0; + commandBuffer->usedFramebuffers = SDL_malloc( + commandBuffer->usedFramebufferCapacity * sizeof(VulkanFramebuffer *)); - commandBuffer->usedUniformBufferCapacity = 4; - commandBuffer->usedUniformBufferCount = 0; - commandBuffer->usedUniformBuffers = SDL_malloc( - commandBuffer->usedUniformBufferCapacity * sizeof(VulkanUniformBuffer *)); + commandBuffer->usedUniformBufferCapacity = 4; + commandBuffer->usedUniformBufferCount = 0; + commandBuffer->usedUniformBuffers = SDL_malloc( + commandBuffer->usedUniformBufferCapacity * sizeof(VulkanUniformBuffer *)); - // Pool it! + // Pool it! - vulkanCommandPool->inactiveCommandBuffers[vulkanCommandPool->inactiveCommandBufferCount] = commandBuffer; - vulkanCommandPool->inactiveCommandBufferCount += 1; - } + vulkanCommandPool->inactiveCommandBuffers[vulkanCommandPool->inactiveCommandBufferCount] = commandBuffer; + vulkanCommandPool->inactiveCommandBufferCount += 1; - SDL_stack_free(commandBuffers); + return true; } static VulkanCommandPool *VULKAN_INTERNAL_FetchCommandPool( @@ -9083,8 +9082,8 @@ static VulkanCommandPool *VULKAN_INTERNAL_FetchCommandPool( &vulkanCommandPool->commandPool); if (vulkanResult != VK_SUCCESS) { - SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to create command pool!"); - LogVulkanResultAsError("vkCreateCommandPool", vulkanResult); + SDL_free(vulkanCommandPool); + CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateCommandPool, NULL) return NULL; } @@ -9094,10 +9093,12 @@ static VulkanCommandPool *VULKAN_INTERNAL_FetchCommandPool( vulkanCommandPool->inactiveCommandBufferCount = 0; vulkanCommandPool->inactiveCommandBuffers = NULL; - VULKAN_INTERNAL_AllocateCommandBuffers( + if (!VULKAN_INTERNAL_AllocateCommandBuffer( renderer, - vulkanCommandPool, - 2); + vulkanCommandPool)) { + VULKAN_INTERNAL_DestroyCommandPool(renderer, vulkanCommandPool); + return NULL; + } CommandPoolHashTableKey *allocedKey = SDL_malloc(sizeof(CommandPoolHashTableKey)); allocedKey->threadID = threadID; @@ -9119,15 +9120,15 @@ static VulkanCommandBuffer *VULKAN_INTERNAL_GetInactiveCommandBufferFromPool( VulkanCommandBuffer *commandBuffer; if (commandPool == NULL) { - SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to fetch command pool!"); return NULL; } if (commandPool->inactiveCommandBufferCount == 0) { - VULKAN_INTERNAL_AllocateCommandBuffers( + if (!VULKAN_INTERNAL_AllocateCommandBuffer( renderer, - commandPool, - commandPool->inactiveCommandBufferCapacity); + commandPool)) { + return NULL; + } } commandBuffer = commandPool->inactiveCommandBuffers[commandPool->inactiveCommandBufferCount - 1]; @@ -9155,7 +9156,6 @@ static SDL_GPUCommandBuffer *VULKAN_AcquireCommandBuffer( SDL_UnlockMutex(renderer->acquireCommandBufferLock); if (commandBuffer == NULL) { - SDL_SetError("Failed to acquire command buffer!"); return NULL; } @@ -9225,9 +9225,11 @@ static SDL_GPUCommandBuffer *VULKAN_AcquireCommandBuffer( commandBuffer->commandBuffer, VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT); - ERROR_SET_RETURN(result, "vkResetCommandBuffer", NULL) + CHECK_VULKAN_ERROR_AND_RETURN(result, vkResetCommandBuffer, NULL) - VULKAN_INTERNAL_BeginCommandBuffer(renderer, commandBuffer); + if (!VULKAN_INTERNAL_BeginCommandBuffer(renderer, commandBuffer)) { + return NULL; + } return (SDL_GPUCommandBuffer *)commandBuffer; } @@ -9248,8 +9250,7 @@ static bool VULKAN_QueryFence( } else if (result == VK_NOT_READY) { return false; } else { - SDL_SetError("%s %s", "vkGetFenceStatus", VkErrorMessages(result)); - return false; + SET_ERROR_AND_RETURN("vkGetFenceStatus: %s", VkErrorMessages(result), false) } } @@ -9314,8 +9315,7 @@ static bool VULKAN_SupportsSwapchainComposition( bool result = false; if (windowData == NULL || windowData->swapchainData == NULL) { - SDL_SetError("Must claim window before querying swapchain composition support!"); - return false; + SET_STRING_ERROR_AND_RETURN("Must claim window before querying swapchain composition support!", false) } surface = windowData->swapchainData->surface; @@ -9360,8 +9360,7 @@ static bool VULKAN_SupportsPresentMode( bool result = false; if (windowData == NULL || windowData->swapchainData == NULL) { - SDL_SetError("Must claim window before querying present mode support!"); - return false; + SET_STRING_ERROR_AND_RETURN("Must claim window before querying present mode support!", false) } surface = windowData->swapchainData->surface; @@ -9414,9 +9413,8 @@ static bool VULKAN_ClaimWindow( return 1; } else { - SDL_SetError("Could not create swapchain, failed to claim window!"); SDL_free(windowData); - return 0; + SET_STRING_ERROR_AND_RETURN("Could not create swapchain, failed to claim window!", 0); } } else { SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "Window already claimed!"); @@ -9473,7 +9471,9 @@ static bool VULKAN_INTERNAL_RecreateSwapchain( Uint32 i; if (windowData->swapchainData != NULL) { - VULKAN_Wait((SDL_GPURenderer *)renderer); + if (!VULKAN_Wait((SDL_GPURenderer *)renderer)) { + return false; + } for (i = 0; i < MAX_FRAMES_IN_FLIGHT; i += 1) { if (windowData->swapchainData->inFlightFences[i] != NULL) { @@ -9488,11 +9488,10 @@ static bool VULKAN_INTERNAL_RecreateSwapchain( return VULKAN_INTERNAL_CreateSwapchain(renderer, windowData); } -static SDL_GPUTexture *VULKAN_AcquireSwapchainTexture( +static bool VULKAN_AcquireSwapchainTexture( SDL_GPUCommandBuffer *commandBuffer, SDL_Window *window, - Uint32 *w, - Uint32 *h) + SDL_GPUTexture **swapchainTexture) { VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; VulkanRenderer *renderer = (VulkanRenderer *)vulkanCommandBuffer->renderer; @@ -9503,9 +9502,11 @@ static SDL_GPUTexture *VULKAN_AcquireSwapchainTexture( VulkanTextureContainer *swapchainTextureContainer = NULL; VulkanPresentData *presentData; + *swapchainTexture = NULL; + windowData = VULKAN_INTERNAL_FetchWindowData(window); if (windowData == NULL) { - return NULL; + SET_STRING_ERROR_AND_RETURN("Cannot acquire a swapchain texture from an unclaimed window!", false) } swapchainData = windowData->swapchainData; @@ -9514,7 +9515,7 @@ static SDL_GPUTexture *VULKAN_AcquireSwapchainTexture( if (swapchainData == NULL) { if (SDL_GetWindowFlags(window) & SDL_WINDOW_MINIMIZED) { // Window is minimized, don't bother - return NULL; + return true; } // Let's try to recreate @@ -9522,28 +9523,29 @@ static SDL_GPUTexture *VULKAN_AcquireSwapchainTexture( swapchainData = windowData->swapchainData; if (swapchainData == NULL) { - SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "Failed to recreate swapchain!"); - return NULL; + return false; } } if (swapchainData->inFlightFences[swapchainData->frameCounter] != NULL) { if (swapchainData->presentMode == VK_PRESENT_MODE_FIFO_KHR) { // In VSYNC mode, block until the least recent presented frame is done - VULKAN_WaitForFences( + if (!VULKAN_WaitForFences( (SDL_GPURenderer *)renderer, true, &swapchainData->inFlightFences[swapchainData->frameCounter], - 1); + 1)) { + return false; + } } else { if (!VULKAN_QueryFence( (SDL_GPURenderer *)renderer, swapchainData->inFlightFences[swapchainData->frameCounter])) { /* * In MAILBOX or IMMEDIATE mode, if the least recent fence is not signaled, - * return NULL to indicate that rendering should be skipped + * return true to indicate that there is no error but rendering should be skipped */ - return NULL; + return true; } } @@ -9560,8 +9562,7 @@ static SDL_GPUTexture *VULKAN_AcquireSwapchainTexture( swapchainData = windowData->swapchainData; if (swapchainData == NULL) { - SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "Failed to recreate swapchain!"); - return NULL; + return false; } } @@ -9580,8 +9581,7 @@ static SDL_GPUTexture *VULKAN_AcquireSwapchainTexture( swapchainData = windowData->swapchainData; if (swapchainData == NULL) { - SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "Failed to recreate swapchain!"); - return NULL; + return false; } acquireResult = renderer->vkAcquireNextImageKHR( @@ -9593,8 +9593,7 @@ static SDL_GPUTexture *VULKAN_AcquireSwapchainTexture( &swapchainImageIndex); if (acquireResult != VK_SUCCESS && acquireResult != VK_SUBOPTIMAL_KHR) { - SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "Failed to acquire swapchain texture!"); - return NULL; + return false; } } @@ -9669,26 +9668,23 @@ static SDL_GPUTexture *VULKAN_AcquireSwapchainTexture( swapchainData->renderFinishedSemaphore[swapchainData->frameCounter]; vulkanCommandBuffer->signalSemaphoreCount += 1; - *w = swapchainData->textureContainers[swapchainData->frameCounter].header.info.width; - *h = swapchainData->textureContainers[swapchainData->frameCounter].header.info.height; - - return (SDL_GPUTexture *)swapchainTextureContainer; + *swapchainTexture = (SDL_GPUTexture *)swapchainTextureContainer; + return true; } static SDL_GPUTextureFormat VULKAN_GetSwapchainTextureFormat( SDL_GPURenderer *driverData, SDL_Window *window) { + VulkanRenderer *renderer = (VulkanRenderer*)driverData; WindowData *windowData = VULKAN_INTERNAL_FetchWindowData(window); if (windowData == NULL) { - SDL_SetError("Cannot get swapchain format, window has not been claimed!"); - return SDL_GPU_TEXTUREFORMAT_INVALID; + SET_STRING_ERROR_AND_RETURN("Cannot get swapchain format, window has not been claimed!", SDL_GPU_TEXTUREFORMAT_INVALID) } if (windowData->swapchainData == NULL) { - SDL_SetError("Cannot get swapchain format, swapchain is currently invalid!"); - return SDL_GPU_TEXTUREFORMAT_INVALID; + SET_STRING_ERROR_AND_RETURN("Cannot get swapchain format, swapchain is currently invalid!", SDL_GPU_TEXTUREFORMAT_INVALID) } return SwapchainCompositionToSDLFormat( @@ -9702,21 +9698,19 @@ static bool VULKAN_SetSwapchainParameters( SDL_GPUSwapchainComposition swapchainComposition, SDL_GPUPresentMode presentMode) { + VulkanRenderer *renderer = (VulkanRenderer *)driverData; WindowData *windowData = VULKAN_INTERNAL_FetchWindowData(window); if (windowData == NULL) { - SDL_SetError("Cannot set swapchain parameters on unclaimed window!"); - return false; + SET_STRING_ERROR_AND_RETURN("Cannot set swapchain parameters on unclaimed window!", false) } if (!VULKAN_SupportsSwapchainComposition(driverData, window, swapchainComposition)) { - SDL_SetError("Swapchain composition not supported!"); - return false; + SET_STRING_ERROR_AND_RETURN("Swapchain composition not supported!", false) } if (!VULKAN_SupportsPresentMode(driverData, window, presentMode)) { - SDL_SetError("Present mode not supported!"); - return false; + SET_STRING_ERROR_AND_RETURN("Present mode not supported!", false) } windowData->presentMode = presentMode; @@ -9749,10 +9743,7 @@ static VulkanFenceHandle *VULKAN_INTERNAL_AcquireFenceFromPool( NULL, &fence); - if (vulkanResult != VK_SUCCESS) { - LogVulkanResultAsError("vkCreateFence", vulkanResult); - return NULL; - } + CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateFence, NULL) handle = SDL_malloc(sizeof(VulkanFenceHandle)); handle->fence = fence; @@ -9770,12 +9761,10 @@ static VulkanFenceHandle *VULKAN_INTERNAL_AcquireFenceFromPool( 1, &handle->fence); - if (vulkanResult != VK_SUCCESS) { - LogVulkanResultAsError("vkResetFences", vulkanResult); - } - SDL_UnlockMutex(renderer->fencePool.lock); + CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkResetFences, NULL) + return handle; } @@ -9966,7 +9955,7 @@ static void VULKAN_INTERNAL_CleanCommandBuffer( } } -static void VULKAN_WaitForFences( +static bool VULKAN_WaitForFences( SDL_GPURenderer *driverData, bool waitAll, SDL_GPUFence *const *fences, @@ -9987,9 +9976,7 @@ static void VULKAN_WaitForFences( waitAll, SDL_MAX_UINT64); - if (result != VK_SUCCESS) { - LogVulkanResultAsError("vkWaitForFences", result); - } + CHECK_VULKAN_ERROR_AND_RETURN(result, vkWaitForFences, false) SDL_stack_free(vkFences); @@ -10010,9 +9997,11 @@ static void VULKAN_WaitForFences( VULKAN_INTERNAL_PerformPendingDestroys(renderer); SDL_UnlockMutex(renderer->submitLock); + + return true; } -static void VULKAN_Wait( +static bool VULKAN_Wait( SDL_GPURenderer *driverData) { VulkanRenderer *renderer = (VulkanRenderer *)driverData; @@ -10022,10 +10011,7 @@ static void VULKAN_Wait( result = renderer->vkDeviceWaitIdle(renderer->logicalDevice); - if (result != VK_SUCCESS) { - LogVulkanResultAsError("vkDeviceWaitIdle", result); - return; - } + CHECK_VULKAN_ERROR_AND_RETURN(result, vkDeviceWaitIdle, false) SDL_LockMutex(renderer->submitLock); @@ -10037,6 +10023,8 @@ static void VULKAN_Wait( VULKAN_INTERNAL_PerformPendingDestroys(renderer); SDL_UnlockMutex(renderer->submitLock); + + return true; } static SDL_GPUFence *VULKAN_SubmitAndAcquireFence( @@ -10047,12 +10035,14 @@ static SDL_GPUFence *VULKAN_SubmitAndAcquireFence( vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; vulkanCommandBuffer->autoReleaseFence = 0; - VULKAN_Submit(commandBuffer); + if (!VULKAN_Submit(commandBuffer)) { + return NULL; + } return (SDL_GPUFence *)vulkanCommandBuffer->inFlightFence; } -static void VULKAN_Submit( +static bool VULKAN_Submit( SDL_GPUCommandBuffer *commandBuffer) { VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; @@ -10089,9 +10079,16 @@ static void VULKAN_Submit( swapchainTextureSubresource); } - VULKAN_INTERNAL_EndCommandBuffer(renderer, vulkanCommandBuffer); + if (!VULKAN_INTERNAL_EndCommandBuffer(renderer, vulkanCommandBuffer)) { + SDL_UnlockMutex(renderer->submitLock); + return false; + } vulkanCommandBuffer->inFlightFence = VULKAN_INTERNAL_AcquireFenceFromPool(renderer); + if (vulkanCommandBuffer->inFlightFence == NULL) { + SDL_UnlockMutex(renderer->submitLock); + return false; + } // Command buffer has a reference to the in-flight fence (void)SDL_AtomicIncRef(&vulkanCommandBuffer->inFlightFence->referenceCount); @@ -10114,7 +10111,8 @@ static void VULKAN_Submit( vulkanCommandBuffer->inFlightFence->fence); if (vulkanResult != VK_SUCCESS) { - LogVulkanResultAsError("vkQueueSubmit", vulkanResult); + SDL_UnlockMutex(renderer->submitLock); + CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkQueueSubmit, false) } // Mark command buffers as submitted @@ -10131,6 +10129,7 @@ static void VULKAN_Submit( renderer->submittedCommandBufferCount += 1; // Present, if applicable + bool result = true; for (Uint32 j = 0; j < vulkanCommandBuffer->presentDataCount; j += 1) { presenting = true; @@ -10155,7 +10154,7 @@ static void VULKAN_Submit( (presentData->windowData->swapchainData->frameCounter + 1) % MAX_FRAMES_IN_FLIGHT; if (presentResult != VK_SUCCESS) { - VULKAN_INTERNAL_RecreateSwapchain( + result = VULKAN_INTERNAL_RecreateSwapchain( renderer, presentData->windowData); } else { @@ -10209,13 +10208,15 @@ static void VULKAN_Submit( presenting && renderer->allocationsToDefragCount > 0 && !renderer->defragInProgress) { - VULKAN_INTERNAL_DefragmentMemory(renderer); + result = VULKAN_INTERNAL_DefragmentMemory(renderer); } SDL_UnlockMutex(renderer->submitLock); + + return result; } -static Uint8 VULKAN_INTERNAL_DefragmentMemory( +static bool VULKAN_INTERNAL_DefragmentMemory( VulkanRenderer *renderer) { VulkanMemoryAllocation *allocation; @@ -10229,17 +10230,16 @@ static Uint8 VULKAN_INTERNAL_DefragmentMemory( VulkanTextureSubresource *dstSubresource; Uint32 i, subresourceIndex; - SDL_LockMutex(renderer->allocatorLock); - renderer->defragInProgress = 1; commandBuffer = (VulkanCommandBuffer *)VULKAN_AcquireCommandBuffer((SDL_GPURenderer *)renderer); if (commandBuffer == NULL) { - SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to create defrag command buffer!"); - return 0; + return false; } commandBuffer->isDefrag = 1; + SDL_LockMutex(renderer->allocatorLock); + allocation = renderer->allocationsToDefrag[renderer->allocationsToDefragCount - 1]; renderer->allocationsToDefragCount -= 1; @@ -10260,8 +10260,8 @@ static Uint8 VULKAN_INTERNAL_DefragmentMemory( currentRegion->vulkanBuffer->type); if (newBuffer == NULL) { - SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to create defrag buffer!"); - return 0; + SDL_UnlockMutex(renderer->allocatorLock); + return false; } if ( @@ -10330,8 +10330,8 @@ static Uint8 VULKAN_INTERNAL_DefragmentMemory( ¤tRegion->vulkanTexture->container->header.info); if (newTexture == NULL) { - SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to create defrag texture!"); - return 0; + SDL_UnlockMutex(renderer->allocatorLock); + return false; } SDL_GPUTextureCreateInfo info = currentRegion->vulkanTexture->container->header.info; @@ -10417,10 +10417,8 @@ static Uint8 VULKAN_INTERNAL_DefragmentMemory( SDL_UnlockMutex(renderer->allocatorLock); - VULKAN_Submit( + return VULKAN_Submit( (SDL_GPUCommandBuffer *)commandBuffer); - - return 1; } // Format Info @@ -10703,12 +10701,8 @@ static Uint8 VULKAN_INTERNAL_CreateInstance(VulkanRenderer *renderer) instanceExtensionCount, &renderer->supportsDebugUtils, &renderer->supportsColorspace)) { - SDL_LogError( - SDL_LOG_CATEGORY_GPU, - "Required Vulkan instance extensions not supported"); - SDL_stack_free((char *)instanceExtensionNames); - return 0; + SET_STRING_ERROR_AND_RETURN("Required Vulkan instance extensions not supported", false) } if (renderer->supportsDebugUtils) { @@ -10750,17 +10744,12 @@ static Uint8 VULKAN_INTERNAL_CreateInstance(VulkanRenderer *renderer) } vulkanResult = vkCreateInstance(&createInfo, NULL, &renderer->instance); - if (vulkanResult != VK_SUCCESS) { - SDL_LogError( - SDL_LOG_CATEGORY_GPU, - "vkCreateInstance failed: %s", - VkErrorMessages(vulkanResult)); + SDL_stack_free((char *)instanceExtensionNames); - SDL_stack_free((char *)instanceExtensionNames); - return 0; + if (vulkanResult != VK_SUCCESS) { + CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateInstance, 0) } - SDL_stack_free((char *)instanceExtensionNames); return 1; } @@ -10900,10 +10889,10 @@ static Uint8 VULKAN_INTERNAL_DeterminePhysicalDevice(VulkanRenderer *renderer) renderer->instance, &physicalDeviceCount, NULL); - ERROR_LOG_RETURN(vulkanResult, vkEnumeratePhysicalDevices, 0) + CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkEnumeratePhysicalDevices, 0) if (physicalDeviceCount == 0) { - SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "Failed to find any GPUs with Vulkan support"); + SDL_LogInfo(SDL_LOG_CATEGORY_GPU, "Failed to find any GPUs with Vulkan support"); return 0; } @@ -11097,7 +11086,7 @@ static Uint8 VULKAN_INTERNAL_CreateLogicalDevice( NULL, &renderer->logicalDevice); SDL_stack_free((void *)deviceExtensions); - ERROR_LOG_RETURN(vulkanResult, vkCreateDevice, 0) + CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateDevice, 0) // Load vkDevice entry points @@ -11219,10 +11208,9 @@ static SDL_GPUDevice *VULKAN_CreateDevice(bool debugMode, bool preferLowPower, S renderer->preferLowPower = preferLowPower; if (!VULKAN_INTERNAL_PrepareVulkan(renderer)) { - SDL_SetError("Failed to initialize Vulkan!"); SDL_free(renderer); SDL_Vulkan_UnloadLibrary(); - return NULL; + SET_STRING_ERROR_AND_RETURN("Failed to initialize Vulkan!", NULL) } SDL_LogInfo(SDL_LOG_CATEGORY_GPU, "SDL_GPU Driver: Vulkan"); @@ -11248,9 +11236,9 @@ static SDL_GPUDevice *VULKAN_CreateDevice(bool debugMode, bool preferLowPower, S if (!VULKAN_INTERNAL_CreateLogicalDevice( renderer)) { - SDL_SetError("Failed to create logical device"); SDL_free(renderer); SDL_Vulkan_UnloadLibrary(); + SET_STRING_ERROR_AND_RETURN("Failed to create logical device!", NULL) return NULL; } diff --git a/src/render/gpu/SDL_render_gpu.c b/src/render/gpu/SDL_render_gpu.c index 69bc2e9a24..41a7e0ccf4 100644 --- a/src/render/gpu/SDL_render_gpu.c +++ b/src/render/gpu/SDL_render_gpu.c @@ -956,9 +956,12 @@ static bool GPU_RenderPresent(SDL_Renderer *renderer) { GPU_RenderData *data = (GPU_RenderData *)renderer->internal; - Uint32 swapchain_w, swapchain_h; + SDL_GPUTexture *swapchain; + bool result = SDL_AcquireGPUSwapchainTexture(data->state.command_buffer, renderer->window, &swapchain); - SDL_GPUTexture *swapchain = SDL_AcquireGPUSwapchainTexture(data->state.command_buffer, renderer->window, &swapchain_w, &swapchain_h); + if (!result) { + SDL_LogError(SDL_LOG_CATEGORY_RENDER, "Failed to acquire swapchain texture: %s", SDL_GetError()); + } if (swapchain == NULL) { goto submit; @@ -966,6 +969,9 @@ static bool GPU_RenderPresent(SDL_Renderer *renderer) SDL_GPUTextureFormat swapchain_fmt = SDL_GetGPUSwapchainTextureFormat(data->device, renderer->window); + int window_w, window_h; + SDL_GetWindowSizeInPixels(renderer->window, &window_w, &window_h); + SDL_GPUBlitInfo blit_info; SDL_zero(blit_info); @@ -973,16 +979,16 @@ static bool GPU_RenderPresent(SDL_Renderer *renderer) blit_info.source.w = data->backbuffer.width; blit_info.source.h = data->backbuffer.height; blit_info.destination.texture = swapchain; - blit_info.destination.w = swapchain_w; - blit_info.destination.h = swapchain_h; + blit_info.destination.w = window_w; + blit_info.destination.h = window_h; blit_info.load_op = SDL_GPU_LOADOP_DONT_CARE; blit_info.filter = SDL_GPU_FILTER_LINEAR; SDL_BlitGPUTexture(data->state.command_buffer, &blit_info); - if (swapchain_w != data->backbuffer.width || swapchain_h != data->backbuffer.height || swapchain_fmt != data->backbuffer.format) { + if (window_w != data->backbuffer.width || window_h != data->backbuffer.height || swapchain_fmt != data->backbuffer.format) { SDL_ReleaseGPUTexture(data->device, data->backbuffer.texture); - CreateBackbuffer(data, swapchain_w, swapchain_h, swapchain_fmt); + CreateBackbuffer(data, window_w, window_h, swapchain_fmt); } // *** FIXME *** diff --git a/test/testgpu_simple_clear.c b/test/testgpu_simple_clear.c index 19017b92f1..099cd0b485 100644 --- a/test/testgpu_simple_clear.c +++ b/test/testgpu_simple_clear.c @@ -74,7 +74,6 @@ SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event) SDL_AppResult SDL_AppIterate(void *appstate) { - Uint32 w, h; SDL_GPUCommandBuffer *cmdbuf = SDL_AcquireGPUCommandBuffer(gpu_device); if (cmdbuf == NULL) { @@ -82,7 +81,11 @@ SDL_AppResult SDL_AppIterate(void *appstate) return SDL_APP_FAILURE; } - SDL_GPUTexture *swapchainTexture = SDL_AcquireGPUSwapchainTexture(cmdbuf, state->windows[0], &w, &h); + SDL_GPUTexture *swapchainTexture; + if (!SDL_AcquireGPUSwapchainTexture(cmdbuf, state->windows[0], &swapchainTexture)) { + SDL_Log("SDL_AcquireGPUSwapchainTexture failed: %s", SDL_GetError()); + return SDL_APP_FAILURE; + } if (swapchainTexture != NULL) { const double currentTime = (double)SDL_GetPerformanceCounter() / SDL_GetPerformanceFrequency(); SDL_GPURenderPass *renderPass; diff --git a/test/testgpu_spinning_cube.c b/test/testgpu_spinning_cube.c index 2df8f70c60..2e646d4940 100644 --- a/test/testgpu_spinning_cube.c +++ b/test/testgpu_spinning_cube.c @@ -325,27 +325,36 @@ static void Render(SDL_Window *window, const int windownum) { WindowState *winstate = &window_states[windownum]; - SDL_GPUTexture *swapchain; + SDL_GPUTexture *swapchainTexture; SDL_GPUColorTargetInfo color_target; SDL_GPUDepthStencilTargetInfo depth_target; float matrix_rotate[16], matrix_modelview[16], matrix_perspective[16], matrix_final[16]; - Uint32 drawablew, drawableh; SDL_GPUCommandBuffer *cmd; SDL_GPURenderPass *pass; SDL_GPUBufferBinding vertex_binding; SDL_GPUBlitInfo blit_info; + int drawablew, drawableh; /* Acquire the swapchain texture */ cmd = SDL_AcquireGPUCommandBuffer(gpu_device); - swapchain = SDL_AcquireGPUSwapchainTexture(cmd, state->windows[windownum], &drawablew, &drawableh); + if (!cmd) { + SDL_Log("Failed to acquire command buffer :%s", SDL_GetError()); + quit(2); + } + if (!SDL_AcquireGPUSwapchainTexture(cmd, state->windows[windownum], &swapchainTexture)) { + SDL_Log("Failed to acquire swapchain texture: %s", SDL_GetError()); + quit(2); + } - if (!swapchain) { + if (swapchainTexture == NULL) { /* No swapchain was acquired, probably too many frames in flight */ SDL_SubmitGPUCommandBuffer(cmd); return; } + SDL_GetWindowSizeInPixels(window, &drawablew, &drawableh); + /* * Do some rotation with Euler angles. It is not a fixed axis as * quaterions would be, but the effect is cool. @@ -403,7 +412,7 @@ Render(SDL_Window *window, const int windownum) } else { color_target.load_op = SDL_GPU_LOADOP_CLEAR; color_target.store_op = SDL_GPU_STOREOP_STORE; - color_target.texture = swapchain; + color_target.texture = swapchainTexture; } SDL_zero(depth_target); @@ -437,7 +446,7 @@ Render(SDL_Window *window, const int windownum) blit_info.source.w = drawablew; blit_info.source.h = drawableh; - blit_info.destination.texture = swapchain; + blit_info.destination.texture = swapchainTexture; blit_info.destination.w = drawablew; blit_info.destination.h = drawableh;