From be401dd1e35c08baaf44000f031b81951698fc10 Mon Sep 17 00:00:00 2001
From: Evan Hemsley <[EMAIL REDACTED]>
Date: Fri, 27 Sep 2024 00:30:18 -0700
Subject: [PATCH] GPU: More robust error reporting (#10958)
---------
Co-authored-by: Ethan Lee <flibitijibibo@gmail.com>
Co-authored-by: Caleb Cornett <caleb.cornett@outlook.com>
---
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 | 380 +++++++++--------
src/gpu/metal/SDL_gpu_metal.m | 86 ++--
src/gpu/vulkan/SDL_gpu_vulkan.c | 700 ++++++++++++++++----------------
src/render/gpu/SDL_render_gpu.c | 18 +-
test/testgpu_simple_clear.c | 7 +-
test/testgpu_spinning_cube.c | 21 +-
11 files changed, 816 insertions(+), 855 deletions(-)
diff --git a/include/SDL3/SDL_gpu.h b/include/SDL3/SDL_gpu.h
index 04099f240859d..a17dd5661d777 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 f0986cd3ac929..0aaa592b049c8 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 16e04b41ae35e..fb9c4d107afb9 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;
- }
- if (w == NULL) {
- SDL_InvalidParamError("w");
- return NULL;
+ return false;
}
- 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 5ae9b95a84767..e2e60cffb3041 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 78b77a401b7b5..5a5210112c3e0 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,61 +851,10 @@ static void D3D11_INTERNAL_SetError(
// Ensure null-terminated string
wszMsgBuff[dwChars] = '\0';
- 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;
- }
+ if (renderer->debugMode) {
+ SDL_LogError(SDL_LOG_CATEGORY_GPU, "%s! Error Code: %s " HRESULT_FMT, msg, wszMsgBuff, res);
}
-
- // Ensure null-terminated string
- wszMsgBuff[dwChars] = '\0';
-
- 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);
}
// Helper Functions
@@ -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_L
(Patch may be truncated, please check the link at the top of this post.)