فهرست منبع

GPU: call SDL_SetError where appropriate

cosmonaut 6 ماه پیش
والد
کامیت
557c6dfb18
4فایلهای تغییر یافته به همراه281 افزوده شده و 173 حذف شده
  1. 114 50
      src/gpu/d3d11/SDL_gpu_d3d11.c
  2. 106 49
      src/gpu/d3d12/SDL_gpu_d3d12.c
  3. 9 11
      src/gpu/metal/SDL_gpu_metal.m
  4. 52 63
      src/gpu/vulkan/SDL_gpu_vulkan.c

+ 114 - 50
src/gpu/d3d11/SDL_gpu_d3d11.c

@@ -108,17 +108,23 @@ static const GUID D3D_IID_DXGI_DEBUG_ALL = { 0xe48ae283, 0xda80, 0x490b, { 0x87,
 
 // Macros
 
-#define ERROR_CHECK(msg)                                     \
+#define ERROR_LOG(msg)                                       \
     if (FAILED(res)) {                                       \
         D3D11_INTERNAL_LogError(renderer->device, msg, res); \
     }
 
-#define ERROR_CHECK_RETURN(msg, ret)                         \
+#define ERROR_LOG_RETURN(msg, ret)                           \
     if (FAILED(res)) {                                       \
         D3D11_INTERNAL_LogError(renderer->device, msg, res); \
         return ret;                                          \
     }
 
+#define ERROR_SET_RETURN(msg, ret)                           \
+    if (FAILED(res)) {                                       \
+        D3D11_INTERNAL_SetError(renderer->device, msg, res); \
+        return ret;                                          \
+    }
+
 #define TRACK_RESOURCE(resource, type, array, count, capacity) \
     Uint32 i;                                                  \
                                                                \
@@ -793,7 +799,7 @@ struct D3D11Renderer
 
 // Logging
 
-static void D3D11_INTERNAL_LogError(
+static void D3D11_INTERNAL_SetError(
     ID3D11Device1 *device,
     const char *msg,
     HRESULT res)
@@ -847,6 +853,60 @@ static void D3D11_INTERNAL_LogError(
     SDL_LogError(SDL_LOG_CATEGORY_GPU, "%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_SetError("%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_SetError("%s! Error Code: %s " HRESULT_FMT, msg, wszMsgBuff, res);
+}
+
 // Helper Functions
 
 static inline Uint32 D3D11_INTERNAL_CalcSubresource(
@@ -1288,7 +1348,7 @@ static ID3D11BlendState *D3D11_INTERNAL_FetchBlendState(
         renderer->device,
         &blendDesc,
         &result);
-    ERROR_CHECK_RETURN("Could not create blend state", NULL);
+    ERROR_LOG_RETURN("Could not create blend state", NULL);
 
     return result;
 }
@@ -1326,7 +1386,7 @@ static ID3D11DepthStencilState *D3D11_INTERNAL_FetchDepthStencilState(
         renderer->device,
         &dsDesc,
         &result);
-    ERROR_CHECK_RETURN("Could not create depth-stencil state", NULL);
+    ERROR_LOG_RETURN("Could not create depth-stencil state", NULL);
 
     return result;
 }
@@ -1357,7 +1417,7 @@ static ID3D11RasterizerState *D3D11_INTERNAL_FetchRasterizerState(
         renderer->device,
         &rasterizerDesc,
         &result);
-    ERROR_CHECK_RETURN("Could not create rasterizer state", NULL);
+    ERROR_LOG_RETURN("Could not create rasterizer state", NULL);
 
     return result;
 }
@@ -1426,7 +1486,7 @@ static ID3D11InputLayout *D3D11_INTERNAL_FetchInputLayout(
         shaderByteLength,
         &result);
     if (FAILED(res)) {
-        SDL_LogError(SDL_LOG_CATEGORY_GPU, "Could not create input layout! Error: " HRESULT_FMT, res);
+        SDL_SetError("Could not create input layout! Error: " HRESULT_FMT, res);
         SDL_stack_free(elementDescs);
         return NULL;
     }
@@ -1516,7 +1576,7 @@ static SDL_GPUComputePipeline *D3D11_CreateComputePipeline(
         NULL,
         NULL);
     if (shader == NULL) {
-        SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to create compute pipeline!");
+        SDL_SetError("Failed to create compute pipeline!");
         return NULL;
     }
 
@@ -1815,7 +1875,7 @@ static SDL_GPUSampler *D3D11_CreateSampler(
         renderer->device,
         &samplerDesc,
         &samplerStateHandle);
-    ERROR_CHECK_RETURN("Could not create sampler state", NULL);
+    ERROR_SET_RETURN("Could not create sampler state", NULL);
 
     d3d11Sampler = (D3D11Sampler *)SDL_malloc(sizeof(D3D11Sampler));
     d3d11Sampler->handle = samplerStateHandle;
@@ -1934,7 +1994,7 @@ static D3D11Texture *D3D11_INTERNAL_CreateTexture(
             &desc2D,
             initialData,
             (ID3D11Texture2D **)&textureHandle);
-        ERROR_CHECK_RETURN("Could not create Texture2D", NULL);
+        ERROR_LOG_RETURN("Could not create Texture2D", NULL);
 
         // Create the SRV, if applicable
         if (needsSRV) {
@@ -2002,7 +2062,7 @@ static D3D11Texture *D3D11_INTERNAL_CreateTexture(
             &desc3D,
             initialData,
             (ID3D11Texture3D **)&textureHandle);
-        ERROR_CHECK_RETURN("Could not create Texture3D", NULL);
+        ERROR_LOG_RETURN("Could not create Texture3D", NULL);
 
         // Create the SRV, if applicable
         if (needsSRV) {
@@ -2071,7 +2131,7 @@ static D3D11Texture *D3D11_INTERNAL_CreateTexture(
                     d3d11Texture->handle,
                     &dsvDesc,
                     &d3d11Texture->subresources[subresourceIndex].depthStencilTargetView);
-                ERROR_CHECK_RETURN("Could not create DSV!", NULL);
+                ERROR_LOG_RETURN("Could not create DSV!", NULL);
 
             } else if (isColorTarget) {
 
@@ -2103,7 +2163,7 @@ static D3D11Texture *D3D11_INTERNAL_CreateTexture(
                         d3d11Texture->handle,
                         &rtvDesc,
                         &d3d11Texture->subresources[subresourceIndex].colorTargetViews[depthIndex]);
-                    ERROR_CHECK_RETURN("Could not create RTV!", NULL);
+                    ERROR_LOG_RETURN("Could not create RTV!", NULL);
                 }
             }
 
@@ -2131,7 +2191,7 @@ static D3D11Texture *D3D11_INTERNAL_CreateTexture(
                     d3d11Texture->handle,
                     &uavDesc,
                     &d3d11Texture->subresources[subresourceIndex].uav);
-                ERROR_CHECK_RETURN("Could not create UAV!", NULL);
+                ERROR_LOG_RETURN("Could not create UAV!", NULL);
             }
         }
     }
@@ -2170,7 +2230,7 @@ static SDL_GPUTexture *D3D11_CreateTexture(
         NULL);
 
     if (texture == NULL) {
-        SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to create texture!");
+        SDL_SetError("Failed to create texture!");
         return NULL;
     }
 
@@ -2295,7 +2355,7 @@ static D3D11Buffer *D3D11_INTERNAL_CreateBuffer(
         bufferDesc,
         NULL,
         &bufferHandle);
-    ERROR_CHECK_RETURN("Could not create buffer", NULL);
+    ERROR_LOG_RETURN("Could not create buffer", NULL);
 
     // Storage buffer
     if (bufferDesc->MiscFlags & D3D11_RESOURCE_MISC_BUFFER_ALLOW_RAW_VIEWS) {
@@ -2315,7 +2375,7 @@ static D3D11Buffer *D3D11_INTERNAL_CreateBuffer(
             &uav);
         if (FAILED(res)) {
             ID3D11Buffer_Release(bufferHandle);
-            ERROR_CHECK_RETURN("Could not create UAV for buffer!", NULL);
+            ERROR_LOG_RETURN("Could not create UAV for buffer!", NULL);
         }
 
         // Create a SRV for the buffer
@@ -2334,7 +2394,7 @@ static D3D11Buffer *D3D11_INTERNAL_CreateBuffer(
             &srv);
         if (FAILED(res)) {
             ID3D11Buffer_Release(bufferHandle);
-            ERROR_CHECK_RETURN("Could not create SRV for buffer!", NULL);
+            ERROR_LOG_RETURN("Could not create SRV for buffer!", NULL);
         }
     }
 
@@ -2396,7 +2456,7 @@ static SDL_GPUBuffer *D3D11_CreateBuffer(
         size);
 
     if (buffer == NULL) {
-        SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to create buffer!");
+        SDL_SetError("Failed to create buffer!");
         return NULL;
     }
 
@@ -2434,7 +2494,7 @@ static D3D11UniformBuffer *D3D11_INTERNAL_CreateUniformBuffer(
         &bufferDesc,
         NULL,
         &buffer);
-    ERROR_CHECK_RETURN("Could not create uniform buffer", NULL)
+    ERROR_LOG_RETURN("Could not create uniform buffer", NULL)
 
     uniformBuffer = SDL_malloc(sizeof(D3D11UniformBuffer));
     uniformBuffer->buffer = buffer;
@@ -2737,7 +2797,7 @@ static void D3D11_UploadToBuffer(
         &stagingBufferDesc,
         &stagingBufferData,
         &stagingBuffer);
-    ERROR_CHECK_RETURN("Could not create staging buffer", )
+    ERROR_LOG_RETURN("Could not create staging buffer", )
 
     // Copy from staging buffer to buffer
     ID3D11DeviceContext1_CopySubresourceRegion(
@@ -2820,7 +2880,7 @@ static void D3D11_DownloadFromTexture(
             &stagingDesc2D,
             NULL,
             (ID3D11Texture2D **)&textureDownload->stagingTexture);
-        ERROR_CHECK_RETURN("Staging texture creation failed", )
+        ERROR_LOG_RETURN("Staging texture creation failed", )
     } else {
         stagingDesc3D.Width = source->w;
         stagingDesc3D.Height = source->h;
@@ -2899,7 +2959,7 @@ static void D3D11_DownloadFromBuffer(
         &stagingBufferDesc,
         NULL,
         &bufferDownload->stagingBuffer);
-    ERROR_CHECK_RETURN("Could not create staging buffer", )
+    ERROR_LOG_RETURN("Could not create staging buffer", )
 
     ID3D11DeviceContext1_CopySubresourceRegion1(
         d3d11CommandBuffer->context,
@@ -3043,7 +3103,7 @@ static void D3D11_INTERNAL_AllocateCommandBuffers(
             renderer->device,
             0,
             &commandBuffer->context);
-        ERROR_CHECK("Could not create deferred context");
+        ERROR_LOG("Could not create deferred context");
 
         // Initialize debug annotation support, if available
         ID3D11DeviceContext_QueryInterface(
@@ -3114,7 +3174,7 @@ static bool D3D11_INTERNAL_CreateFence(
         renderer->device,
         &queryDesc,
         &queryHandle);
-    ERROR_CHECK_RETURN("Could not create query", 0);
+    ERROR_LOG_RETURN("Could not create query", 0);
 
     fence = SDL_malloc(sizeof(D3D11Fence));
     fence->handle = queryHandle;
@@ -3147,7 +3207,7 @@ static bool D3D11_INTERNAL_AcquireFence(
     if (renderer->availableFenceCount == 0) {
         if (!D3D11_INTERNAL_CreateFence(renderer)) {
             SDL_UnlockMutex(renderer->fenceLock);
-            SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to create fence!");
+            SDL_SetError("Failed to create fence!");
             return false;
         }
     }
@@ -3220,11 +3280,15 @@ static SDL_GPUCommandBuffer *D3D11_AcquireCommandBuffer(
     SDL_zeroa(commandBuffer->computeWriteOnlyStorageTextureSubresources);
     SDL_zeroa(commandBuffer->computeWriteOnlyStorageBuffers);
 
-    D3D11_INTERNAL_AcquireFence(commandBuffer);
+    bool acquireFenceResult = D3D11_INTERNAL_AcquireFence(commandBuffer);
     commandBuffer->autoReleaseFence = 1;
 
     SDL_UnlockMutex(renderer->acquireCommandBufferLock);
 
+    if (!acquireFenceResult) {
+        return NULL;
+    }
+
     return (SDL_GPUCommandBuffer *)commandBuffer;
 }
 
@@ -3344,7 +3408,7 @@ static void D3D11_INTERNAL_PushUniformData(
             D3D11_MAP_WRITE_DISCARD,
             0,
             &subres);
-        ERROR_CHECK_RETURN("Failed to map uniform buffer", )
+        ERROR_LOG_RETURN("Failed to map uniform buffer", )
 
         d3d11UniformBuffer->mappedData = subres.pData;
     }
@@ -4673,7 +4737,7 @@ static void D3D11_INTERNAL_MapAndCopyBufferDownload(
         D3D11_MAP_READ,
         0,
         &subres);
-    ERROR_CHECK_RETURN("Failed to map staging buffer", )
+    ERROR_LOG_RETURN("Failed to map staging buffer", )
 
     SDL_memcpy(
         ((Uint8 *)transferBuffer->data) + bufferDownload->dstOffset,
@@ -4707,7 +4771,7 @@ static void D3D11_INTERNAL_MapAndCopyTextureDownload(
         D3D11_MAP_READ,
         0,
         &subres);
-    ERROR_CHECK_RETURN("Could not map staging texture", )
+    ERROR_LOG_RETURN("Could not map staging texture", )
 
     for (depth = 0; depth < textureDownload->depth; depth += 1) {
         dataPtrOffset = textureDownload->bufferOffset + (depth * textureDownload->bytesPerDepthSlice);
@@ -5009,7 +5073,7 @@ static bool D3D11_INTERNAL_InitializeSwapchainTexture(
         0,
         &D3D_IID_ID3D11Texture2D,
         (void **)&swapchainTexture);
-    ERROR_CHECK_RETURN("Could not get buffer from swapchain!", 0);
+    ERROR_LOG_RETURN("Could not get buffer from swapchain!", 0);
 
     // Create the RTV for the swapchain
     rtvDesc.Format = rtvFormat;
@@ -5109,7 +5173,7 @@ static bool D3D11_INTERNAL_CreateSwapchain(
         (IUnknown *)renderer->device,
         &swapchainDesc,
         &swapchain);
-    ERROR_CHECK_RETURN("Could not create swapchain", 0);
+    ERROR_LOG_RETURN("Could not create swapchain", 0);
 
     /*
      * The swapchain's parent is a separate factory from the factory that
@@ -5224,7 +5288,7 @@ static bool D3D11_INTERNAL_ResizeSwapchain(
         height,
         DXGI_FORMAT_UNKNOWN, // Keep the old format
         renderer->supportsTearing ? DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING : 0);
-    ERROR_CHECK_RETURN("Could not resize swapchain buffers", 0);
+    ERROR_LOG_RETURN("Could not resize swapchain buffers", 0);
 
     // Create the texture object for the swapchain
     return D3D11_INTERNAL_InitializeSwapchainTexture(
@@ -5264,7 +5328,7 @@ static bool D3D11_SupportsSwapchainComposition(
 
     D3D11WindowData *windowData = D3D11_INTERNAL_FetchWindowData(window);
     if (windowData == NULL) {
-        SDL_LogError(SDL_LOG_CATEGORY_GPU, "Must claim window before querying swapchain composition support!");
+        SDL_SetError("Must claim window before querying swapchain composition support!");
         return false;
     }
 
@@ -5285,7 +5349,7 @@ static bool D3D11_SupportsSwapchainComposition(
                 return false;
             }
         } else {
-            SDL_LogError(SDL_LOG_CATEGORY_GPU, "DXGI 1.4 not supported, cannot use composition other than SDL_GPU_SWAPCHAINCOMPOSITION_SDR!");
+            SDL_SetError("DXGI 1.4 not supported, cannot use composition other than SDL_GPU_SWAPCHAINCOMPOSITION_SDR!");
             return false;
         }
     }
@@ -5340,7 +5404,7 @@ static bool D3D11_ClaimWindow(
 
             return true;
         } else {
-            SDL_LogError(SDL_LOG_CATEGORY_GPU, "Could not create swapchain, failed to claim window!");
+            SDL_SetError("Could not create swapchain, failed to claim window!");
             SDL_free(windowData);
             return false;
         }
@@ -5439,7 +5503,7 @@ static SDL_GPUTexture *D3D11_AcquireSwapchainTexture(
             windowData,
             windowW,
             windowH);
-        ERROR_CHECK_RETURN("Could not resize swapchain", NULL);
+        ERROR_SET_RETURN("Could not resize swapchain", NULL);
     }
 
     if (windowData->inFlightFences[windowData->frameCounter] != NULL) {
@@ -5475,7 +5539,7 @@ static SDL_GPUTexture *D3D11_AcquireSwapchainTexture(
         0,
         &D3D_IID_ID3D11Texture2D,
         (void **)&windowData->texture.handle);
-    ERROR_CHECK_RETURN("Could not acquire swapchain!", NULL);
+    ERROR_SET_RETURN("Could not acquire swapchain!", NULL);
 
     // Send the dimensions to the out parameters.
     *w = windowW;
@@ -5506,7 +5570,7 @@ static SDL_GPUTextureFormat D3D11_GetSwapchainTextureFormat(
     D3D11WindowData *windowData = D3D11_INTERNAL_FetchWindowData(window);
 
     if (windowData == NULL) {
-        SDL_LogError(SDL_LOG_CATEGORY_GPU, "Cannot get swapchain format, window has not been claimed!");
+        SDL_SetError("Cannot get swapchain format, window has not been claimed!");
         return SDL_GPU_TEXTUREFORMAT_INVALID;
     }
 
@@ -5523,17 +5587,17 @@ static bool D3D11_SetSwapchainParameters(
     D3D11WindowData *windowData = D3D11_INTERNAL_FetchWindowData(window);
 
     if (windowData == NULL) {
-        SDL_LogError(SDL_LOG_CATEGORY_GPU, "Cannot set swapchain parameters on unclaimed window!");
+        SDL_SetError("Cannot set swapchain parameters on unclaimed window!");
         return false;
     }
 
     if (!D3D11_SupportsSwapchainComposition(driverData, window, swapchainComposition)) {
-        SDL_LogError(SDL_LOG_CATEGORY_GPU, "Swapchain composition not supported!");
+        SDL_SetError("Swapchain composition not supported!");
         return false;
     }
 
     if (!D3D11_SupportsPresentMode(driverData, window, presentMode)) {
-        SDL_LogError(SDL_LOG_CATEGORY_GPU, "Present mode not supported!");
+        SDL_SetError("Present mode not supported!");
         return false;
     }
 
@@ -5604,7 +5668,7 @@ static void D3D11_Submit(
         d3d11CommandBuffer->context,
         0,
         &commandList);
-    ERROR_CHECK("Could not finish command list recording!");
+    ERROR_LOG("Could not finish command list recording!");
 
     // Submit the command list to the immediate context
     ID3D11DeviceContext_ExecuteCommandList(
@@ -6145,7 +6209,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_LogError(SDL_LOG_CATEGORY_GPU, "Could not find " DXGI_DLL);
+        SDL_SetError("Could not find " DXGI_DLL);
         return NULL;
     }
 
@@ -6154,7 +6218,7 @@ static SDL_GPUDevice *D3D11_CreateDevice(bool debugMode, bool preferLowPower, SD
         renderer->dxgi_dll,
         CREATE_DXGI_FACTORY1_FUNC);
     if (CreateDxgiFactoryFunc == NULL) {
-        SDL_LogError(SDL_LOG_CATEGORY_GPU, "Could not load function: " CREATE_DXGI_FACTORY1_FUNC);
+        SDL_SetError("Could not load function: " CREATE_DXGI_FACTORY1_FUNC);
         return NULL;
     }
 
@@ -6162,7 +6226,7 @@ static SDL_GPUDevice *D3D11_CreateDevice(bool debugMode, bool preferLowPower, SD
     res = CreateDxgiFactoryFunc(
         &D3D_IID_IDXGIFactory1,
         (void **)&renderer->factory);
-    ERROR_CHECK_RETURN("Could not create DXGIFactory", NULL);
+    ERROR_SET_RETURN("Could not create DXGIFactory", NULL);
 
     // Check for flip-model discard support (supported on Windows 10+)
     res = IDXGIFactory1_QueryInterface(
@@ -6222,7 +6286,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_LogError(SDL_LOG_CATEGORY_GPU, "Could not find " D3D11_DLL);
+        SDL_SetError("Could not find " D3D11_DLL);
         return NULL;
     }
 
@@ -6231,7 +6295,7 @@ static SDL_GPUDevice *D3D11_CreateDevice(bool debugMode, bool preferLowPower, SD
         renderer->d3d11_dll,
         D3D11_CREATE_DEVICE_FUNC);
     if (D3D11CreateDeviceFunc == NULL) {
-        SDL_LogError(SDL_LOG_CATEGORY_GPU, "Could not load function: " D3D11_CREATE_DEVICE_FUNC);
+        SDL_SetError("Could not load function: " D3D11_CREATE_DEVICE_FUNC);
         return NULL;
     }
 
@@ -6263,14 +6327,14 @@ tryCreateDevice:
         goto tryCreateDevice;
     }
 
-    ERROR_CHECK_RETURN("Could not create D3D11 device", NULL);
+    ERROR_SET_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_CHECK_RETURN("Could not get ID3D11Device1 interface", NULL);
+    ERROR_SET_RETURN("Could not get ID3D11Device1 interface", NULL);
 
     // Release the old device interface, we don't need it anymore
     ID3D11Device_Release(d3d11Device);

+ 106 - 49
src/gpu/d3d12/SDL_gpu_d3d12.c

@@ -56,17 +56,23 @@
 
 // Macros
 
-#define ERROR_CHECK(msg)                                     \
+#define ERROR_LOG(msg)                                       \
     if (FAILED(res)) {                                       \
         D3D12_INTERNAL_LogError(renderer->device, msg, res); \
     }
 
-#define ERROR_CHECK_RETURN(msg, ret)                         \
+#define ERROR_LOG_RETURN(msg, ret)                           \
     if (FAILED(res)) {                                       \
         D3D12_INTERNAL_LogError(renderer->device, msg, res); \
         return ret;                                          \
     }
 
+#define ERROR_SET_RETURN(msg, ret)                           \
+    if (FAILED(res)) {                                       \
+        D3D12_INTERNAL_SetError(renderer->device, msg, res); \
+        return ret;                                          \
+    }
+
 // Defines
 #if defined(_WIN32)
 #if defined(SDL_PLATFORM_XBOXSERIES)
@@ -917,6 +923,57 @@ typedef HRESULT (D3DAPI* PFN_D3D12_XBOX_CREATE_DEVICE)(_In_opt_ IGraphicsUnknown
 
 // Logging
 
+static void D3D12_INTERNAL_SetError(
+    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_SetError("%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_SetError("%s! Error Code: %s " HRESULT_FMT, msg, wszMsgBuff, res);
+}
+
 static void
 D3D12_INTERNAL_LogError(
     ID3D12Device *device,
@@ -2100,7 +2157,7 @@ static D3D12GraphicsRootSignature *D3D12_INTERNAL_CreateGraphicsRootSignature(
 
     if (FAILED(res)) {
         if (errorBlob) {
-            SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to create RootSignature");
+            SDL_SetError("Failed to create RootSignature");
             ID3D10Blob_Release(errorBlob);
         }
         D3D12_INTERNAL_DestroyGraphicsRootSignature(d3d12GraphicsRootSignature);
@@ -2354,7 +2411,7 @@ static SDL_GPUComputePipeline *D3D12_CreateComputePipeline(
         createinfo);
 
     if (rootSignature == NULL) {
-        SDL_LogError(SDL_LOG_CATEGORY_GPU, "Could not create root signature!");
+        SDL_SetError("Could not create root signature!");
         SDL_free(bytecode);
         return NULL;
     }
@@ -2375,7 +2432,7 @@ static SDL_GPUComputePipeline *D3D12_CreateComputePipeline(
         (void **)&pipelineState);
 
     if (FAILED(res)) {
-        D3D12_INTERNAL_LogError(renderer->device, "Could not create compute pipeline state", res);
+        D3D12_INTERNAL_SetError(renderer->device, "Could not create compute pipeline state", res);
         SDL_free(bytecode);
         return NULL;
     }
@@ -2640,7 +2697,7 @@ static SDL_GPUGraphicsPipeline *D3D12_CreateGraphicsPipeline(
         fragShader);
 
     if (rootSignature == NULL) {
-        SDL_LogError(SDL_LOG_CATEGORY_GPU, "Could not create root signature!");
+        SDL_SetError("Could not create root signature!");
         D3D12_INTERNAL_DestroyGraphicsPipeline(pipeline);
         return NULL;
     }
@@ -2655,7 +2712,7 @@ static SDL_GPUGraphicsPipeline *D3D12_CreateGraphicsPipeline(
         D3D_GUID(D3D_IID_ID3D12PipelineState),
         (void **)&pipelineState);
     if (FAILED(res)) {
-        D3D12_INTERNAL_LogError(renderer->device, "Could not create graphics pipeline state", res);
+        D3D12_INTERNAL_SetError(renderer->device, "Could not create graphics pipeline state", res);
         D3D12_INTERNAL_DestroyGraphicsPipeline(pipeline);
         return NULL;
     }
@@ -3160,7 +3217,7 @@ static D3D12Buffer *D3D12_INTERNAL_CreateBuffer(
         }
         heapFlags = D3D12_HEAP_FLAG_NONE;
     } else {
-        SDL_LogError(SDL_LOG_CATEGORY_GPU, "Unrecognized buffer type!");
+        SDL_SetError("Unrecognized buffer type!");
         return NULL;
     }
 
@@ -4111,7 +4168,7 @@ static D3D12UniformBuffer *D3D12_INTERNAL_AcquireUniformBufferFromPool(
         0,
         NULL,
         (void **)&uniformBuffer->buffer->mapPointer);
-    ERROR_CHECK_RETURN("Failed to map buffer pool!", NULL);
+    ERROR_LOG_RETURN("Failed to map buffer pool!", NULL);
 
     D3D12_INTERNAL_TrackUniformBuffer(commandBuffer, uniformBuffer);
 
@@ -5991,7 +6048,7 @@ static bool D3D12_SupportsSwapchainComposition(
 
     D3D12WindowData *windowData = D3D12_INTERNAL_FetchWindowData(window);
     if (windowData == NULL) {
-        SDL_LogError(SDL_LOG_CATEGORY_GPU, "Must claim window before querying swapchain composition support!");
+        SDL_SetError("Must claim window before querying swapchain composition support!");
         return false;
     }
 
@@ -6161,7 +6218,7 @@ static bool D3D12_INTERNAL_InitializeSwapchainTexture(
         index,
         D3D_GUID(D3D_IID_ID3D12Resource),
         (void **)&swapchainTexture);
-    ERROR_CHECK_RETURN("Could not get buffer from swapchain!", 0);
+    ERROR_LOG_RETURN("Could not get buffer from swapchain!", 0);
 
     pTexture = (D3D12Texture *)SDL_calloc(1, sizeof(D3D12Texture));
     if (!pTexture) {
@@ -6293,7 +6350,7 @@ static bool D3D12_INTERNAL_ResizeSwapchainIfNeeded(
             h,
             DXGI_FORMAT_UNKNOWN, // Keep the old format
             renderer->supportsTearing ? DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING : 0);
-        ERROR_CHECK_RETURN("Could not resize swapchain buffers", 0)
+        ERROR_LOG_RETURN("Could not resize swapchain buffers", 0)
 
         // Create texture object for the swapchain
         for (Uint32 i = 0; i < MAX_FRAMES_IN_FLIGHT; i += 1) {
@@ -6402,14 +6459,14 @@ static bool D3D12_INTERNAL_CreateSwapchain(
         &fullscreenDesc,
         NULL,
         &swapchain);
-    ERROR_CHECK_RETURN("Could not create swapchain", 0);
+    ERROR_LOG_RETURN("Could not create swapchain", 0);
 
     res = IDXGISwapChain1_QueryInterface(
         swapchain,
         D3D_GUID(D3D_IID_IDXGISwapChain3),
         (void **)&swapchain3);
     IDXGISwapChain1_Release(swapchain);
-    ERROR_CHECK_RETURN("Could not create IDXGISwapChain3", 0);
+    ERROR_LOG_RETURN("Could not create IDXGISwapChain3", 0);
 
     if (swapchainComposition != SDL_GPU_SWAPCHAINCOMPOSITION_SDR) {
         // Support already verified if we hit this block
@@ -6526,7 +6583,7 @@ static bool D3D12_ClaimWindow(
 
             return true;
         } else {
-            SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Could not create swapchain, failed to claim window!");
+            SDL_SetError("Could not create swapchain, failed to claim window!");
             SDL_free(windowData);
             return false;
         }
@@ -6585,17 +6642,17 @@ static bool D3D12_SetSwapchainParameters(
     D3D12WindowData *windowData = D3D12_INTERNAL_FetchWindowData(window);
 
     if (windowData == NULL) {
-        SDL_LogError(SDL_LOG_CATEGORY_GPU, "Cannot set swapchain parameters on unclaimed window!");
+        SDL_SetError("Cannot set swapchain parameters on unclaimed window!");
         return false;
     }
 
     if (!D3D12_SupportsSwapchainComposition(driverData, window, swapchainComposition)) {
-        SDL_LogError(SDL_LOG_CATEGORY_GPU, "Swapchain composition not supported!");
+        SDL_SetError("Swapchain composition not supported!");
         return false;
     }
 
     if (!D3D12_SupportsPresentMode(driverData, window, presentMode)) {
-        SDL_LogError(SDL_LOG_CATEGORY_GPU, "Present mode not supported!");
+        SDL_SetError("Present mode not supported!");
         return false;
     }
 
@@ -6626,7 +6683,7 @@ static SDL_GPUTextureFormat D3D12_GetSwapchainTextureFormat(
     D3D12WindowData *windowData = D3D12_INTERNAL_FetchWindowData(window);
 
     if (windowData == NULL) {
-        SDL_LogError(SDL_LOG_CATEGORY_GPU, "Cannot get swapchain format, window has not been claimed!");
+        SDL_SetError("Cannot get swapchain format, window has not been claimed!");
         return SDL_GPU_TEXTUREFORMAT_INVALID;
     }
 
@@ -6822,7 +6879,7 @@ static SDL_GPUCommandBuffer *D3D12_AcquireCommandBuffer(
     SDL_UnlockMutex(renderer->acquireCommandBufferLock);
 
     if (commandBuffer == NULL) {
-        SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to acquire command buffer!");
+        SDL_SetError("Failed to acquire command buffer!");
         return NULL;
     }
 
@@ -6831,7 +6888,7 @@ 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_LogError(SDL_LOG_CATEGORY_GPU, "Failed to acquire descriptor heap!");
+        SDL_SetError("Failed to acquire descriptor heap!");
         D3D12_INTERNAL_DestroyCommandBuffer(commandBuffer);
         return NULL;
     }
@@ -6840,7 +6897,7 @@ static SDL_GPUCommandBuffer *D3D12_AcquireCommandBuffer(
         D3D12_INTERNAL_AcquireDescriptorHeapFromPool(commandBuffer, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER);
 
     if (!commandBuffer->gpuDescriptorHeaps[D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER]) {
-        SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to acquire descriptor heap!");
+        SDL_SetError("Failed to acquire descriptor heap!");
         D3D12_INTERNAL_DestroyCommandBuffer(commandBuffer);
         return NULL;
     }
@@ -6909,7 +6966,7 @@ static SDL_GPUTexture *D3D12_AcquireSwapchainTexture(
     res = D3D12_INTERNAL_ResizeSwapchainIfNeeded(
         renderer,
         windowData);
-    ERROR_CHECK_RETURN("Could not resize swapchain", NULL);
+    ERROR_SET_RETURN("Could not resize swapchain", NULL);
 
     if (windowData->inFlightFences[windowData->frameCounter] != NULL) {
         if (windowData->present_mode == SDL_GPU_PRESENTMODE_VSYNC) {
@@ -6952,7 +7009,7 @@ static SDL_GPUTexture *D3D12_AcquireSwapchainTexture(
         swapchainIndex,
         D3D_GUID(D3D_IID_ID3D12Resource),
         (void **)&windowData->textureContainers[swapchainIndex].activeTexture->resource);
-    ERROR_CHECK_RETURN("Could not acquire swapchain!", NULL);
+    ERROR_SET_RETURN("Could not acquire swapchain!", NULL);
 #endif
 
     // Send the dimensions to the out parameters.
@@ -7115,13 +7172,13 @@ static void D3D12_INTERNAL_CleanCommandBuffer(
     commandBuffer->textureDownloadCount = 0;
 
     res = ID3D12CommandAllocator_Reset(commandBuffer->commandAllocator);
-    ERROR_CHECK("Could not reset command allocator")
+    ERROR_LOG("Could not reset command allocator")
 
     res = ID3D12GraphicsCommandList_Reset(
         commandBuffer->graphicsCommandList,
         commandBuffer->commandAllocator,
         NULL);
-    ERROR_CHECK("Could not reset graphicsCommandList")
+    ERROR_LOG("Could not reset graphicsCommandList")
 
     // Return descriptor heaps to pool
     D3D12_INTERNAL_ReturnDescriptorHeapToPool(
@@ -7259,13 +7316,13 @@ static void D3D12_Submit(
 
     // Notify the command buffer that we have completed recording
     res = ID3D12GraphicsCommandList_Close(d3d12CommandBuffer->graphicsCommandList);
-    ERROR_CHECK("Failed to close command list!");
+    ERROR_LOG("Failed to close command list!");
 
     res = ID3D12GraphicsCommandList_QueryInterface(
         d3d12CommandBuffer->graphicsCommandList,
         D3D_GUID(D3D_IID_ID3D12CommandList),
         (void **)&commandLists[0]);
-    ERROR_CHECK("Failed to convert command list!")
+    ERROR_LOG("Failed to convert command list!")
 
     // Submit the command list to the queue
     ID3D12CommandQueue_ExecuteCommandLists(
@@ -7286,7 +7343,7 @@ static void D3D12_Submit(
         renderer->commandQueue,
         d3d12CommandBuffer->inFlightFence->handle,
         D3D12_FENCE_SIGNAL_VALUE);
-    ERROR_CHECK("Failed to enqueue fence signal!");
+    ERROR_LOG("Failed to enqueue fence signal!");
 
     // Mark the command buffer as submitted
     if (renderer->submittedCommandBufferCount + 1 >= renderer->submittedCommandBufferCapacity) {
@@ -7377,7 +7434,7 @@ static void D3D12_Wait(
     D3D12Renderer *renderer = (D3D12Renderer *)driverData;
     D3D12Fence *fence = D3D12_INTERNAL_AcquireFence(renderer);
     if (!fence) {
-        SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to acquire fence.");
+        SDL_SetError("Failed to acquire fence.");
         return;
     }
     HRESULT res;
@@ -7397,7 +7454,7 @@ static void D3D12_Wait(
                 fence->handle,
                 D3D12_FENCE_SIGNAL_VALUE,
                 fence->event);
-            ERROR_CHECK_RETURN("Setting fence event failed", )
+            ERROR_LOG_RETURN("Setting fence event failed", )
 
             WaitForSingleObject(fence->event, INFINITE);
         }
@@ -7437,7 +7494,7 @@ static void D3D12_WaitForFences(
             fence->handle,
             D3D12_FENCE_SIGNAL_VALUE,
             fence->event);
-        ERROR_CHECK_RETURN("Setting fence event failed", )
+        ERROR_LOG_RETURN("Setting fence event failed", )
 
         events[i] = fence->event;
     }
@@ -7872,7 +7929,7 @@ static void D3D12_INTERNAL_TryInitializeD3D12DebugInfoQueue(D3D12Renderer *rende
         D3D_GUID(D3D_IID_ID3D12InfoQueue),
         (void **)&infoQueue);
     if (FAILED(res)) {
-        ERROR_CHECK_RETURN("Failed to convert ID3D12Device to ID3D12InfoQueue", );
+        ERROR_LOG_RETURN("Failed to convert ID3D12Device to ID3D12InfoQueue", );
     }
 
     SDL_zero(filter);
@@ -7922,7 +7979,7 @@ 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_LogError(SDL_LOG_CATEGORY_APPLICATION, "Could not find " DXGI_DLL);
+        SDL_SetError("Could not find " DXGI_DLL);
         D3D12_INTERNAL_DestroyRenderer(renderer);
         return NULL;
     }
@@ -7939,7 +7996,7 @@ static SDL_GPUDevice *D3D12_CreateDevice(bool debugMode, bool preferLowPower, SD
         renderer->dxgi_dll,
         CREATE_DXGI_FACTORY1_FUNC);
     if (CreateDXGIFactoryFunc == NULL) {
-        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Could not load function: " CREATE_DXGI_FACTORY1_FUNC);
+        SDL_SetError("Could not load function: " CREATE_DXGI_FACTORY1_FUNC);
         D3D12_INTERNAL_DestroyRenderer(renderer);
         return NULL;
     }
@@ -7950,7 +8007,7 @@ static SDL_GPUDevice *D3D12_CreateDevice(bool debugMode, bool preferLowPower, SD
         (void **)&factory1);
     if (FAILED(res)) {
         D3D12_INTERNAL_DestroyRenderer(renderer);
-        ERROR_CHECK_RETURN("Could not create DXGIFactory", NULL);
+        ERROR_SET_RETURN("Could not create DXGIFactory", NULL);
     }
 
     // Check for DXGI 1.4 support
@@ -7960,7 +8017,7 @@ static SDL_GPUDevice *D3D12_CreateDevice(bool debugMode, bool preferLowPower, SD
         (void **)&renderer->factory);
     if (FAILED(res)) {
         D3D12_INTERNAL_DestroyRenderer(renderer);
-        ERROR_CHECK_RETURN("DXGI1.4 support not found, required for DX12", NULL);
+        ERROR_SET_RETURN("DXGI1.4 support not found, required for DX12", NULL);
     }
     IDXGIFactory1_Release(factory1);
 
@@ -8003,14 +8060,14 @@ static SDL_GPUDevice *D3D12_CreateDevice(bool debugMode, bool preferLowPower, SD
 
     if (FAILED(res)) {
         D3D12_INTERNAL_DestroyRenderer(renderer);
-        ERROR_CHECK_RETURN("Could not find adapter for D3D12Device", NULL);
+        ERROR_SET_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_CHECK_RETURN("Could not get adapter description", NULL);
+        ERROR_SET_RETURN("Could not get adapter description", NULL);
     }
 
     SDL_LogInfo(SDL_LOG_CATEGORY_GPU, "SDL_GPU Driver: D3D12");
@@ -8020,7 +8077,7 @@ 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_LogError(SDL_LOG_CATEGORY_APPLICATION, "Could not find " D3D12_DLL);
+        SDL_SetError("Could not find " D3D12_DLL);
         D3D12_INTERNAL_DestroyRenderer(renderer);
         return NULL;
     }
@@ -8031,7 +8088,7 @@ static SDL_GPUDevice *D3D12_CreateDevice(bool debugMode, bool preferLowPower, SD
         renderer->d3d12_dll,
         "D3D12XboxCreateDevice");
     if (D3D12XboxCreateDeviceFunc == NULL) {
-        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Could not load function: D3D12XboxCreateDevice");
+        SDL_SetError("Could not load function: D3D12XboxCreateDevice");
         D3D12_INTERNAL_DestroyRenderer(renderer);
         return NULL;
     }
@@ -8040,7 +8097,7 @@ static SDL_GPUDevice *D3D12_CreateDevice(bool debugMode, bool preferLowPower, SD
         renderer->d3d12_dll,
         D3D12_CREATE_DEVICE_FUNC);
     if (D3D12CreateDeviceFunc == NULL) {
-        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Could not load function: " D3D12_CREATE_DEVICE_FUNC);
+        SDL_SetError("Could not load function: " D3D12_CREATE_DEVICE_FUNC);
         D3D12_INTERNAL_DestroyRenderer(renderer);
         return NULL;
     }
@@ -8050,7 +8107,7 @@ static SDL_GPUDevice *D3D12_CreateDevice(bool debugMode, bool preferLowPower, SD
         renderer->d3d12_dll,
         D3D12_SERIALIZE_ROOT_SIGNATURE_FUNC);
     if (renderer->D3D12SerializeRootSignature_func == NULL) {
-        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Could not load function: " D3D12_SERIALIZE_ROOT_SIGNATURE_FUNC);
+        SDL_SetError("Could not load function: " D3D12_SERIALIZE_ROOT_SIGNATURE_FUNC);
         D3D12_INTERNAL_DestroyRenderer(renderer);
         return NULL;
     }
@@ -8119,7 +8176,7 @@ static SDL_GPUDevice *D3D12_CreateDevice(bool debugMode, bool preferLowPower, SD
 
     if (FAILED(res)) {
         D3D12_INTERNAL_DestroyRenderer(renderer);
-        ERROR_CHECK_RETURN("Could not create D3D12Device", NULL);
+        ERROR_SET_RETURN("Could not create D3D12Device", NULL);
     }
 
     // Initialize the D3D12 debug info queue, if applicable
@@ -8137,7 +8194,7 @@ static SDL_GPUDevice *D3D12_CreateDevice(bool debugMode, bool preferLowPower, SD
         sizeof(D3D12_FEATURE_DATA_ARCHITECTURE));
     if (FAILED(res)) {
         D3D12_INTERNAL_DestroyRenderer(renderer);
-        ERROR_CHECK_RETURN("Could not get device architecture", NULL);
+        ERROR_SET_RETURN("Could not get device architecture", NULL);
     }
 
     renderer->UMA = (bool)architecture.UMA;
@@ -8179,7 +8236,7 @@ static SDL_GPUDevice *D3D12_CreateDevice(bool debugMode, bool preferLowPower, SD
 
         if (FAILED(res)) {
             D3D12_INTERNAL_DestroyRenderer(renderer);
-            ERROR_CHECK_RETURN("Could not create D3D12CommandQueue", NULL);
+            ERROR_SET_RETURN("Could not create D3D12CommandQueue", NULL);
         }
 #if (defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES))
         s_CommandQueue = renderer->commandQueue;
@@ -8206,7 +8263,7 @@ static SDL_GPUDevice *D3D12_CreateDevice(bool debugMode, bool preferLowPower, SD
         (void **)&renderer->indirectDrawCommandSignature);
     if (FAILED(res)) {
         D3D12_INTERNAL_DestroyRenderer(renderer);
-        ERROR_CHECK_RETURN("Could not create indirect draw command signature", NULL)
+        ERROR_SET_RETURN("Could not create indirect draw command signature", NULL)
     }
 
     indirectArgumentDesc.Type = D3D12_INDIRECT_ARGUMENT_TYPE_DRAW_INDEXED;
@@ -8221,7 +8278,7 @@ static SDL_GPUDevice *D3D12_CreateDevice(bool debugMode, bool preferLowPower, SD
         (void **)&renderer->indirectIndexedDrawCommandSignature);
     if (FAILED(res)) {
         D3D12_INTERNAL_DestroyRenderer(renderer);
-        ERROR_CHECK_RETURN("Could not create indirect indexed draw command signature", NULL)
+        ERROR_SET_RETURN("Could not create indirect indexed draw command signature", NULL)
     }
 
     indirectArgumentDesc.Type = D3D12_INDIRECT_ARGUMENT_TYPE_DISPATCH;
@@ -8236,7 +8293,7 @@ static SDL_GPUDevice *D3D12_CreateDevice(bool debugMode, bool preferLowPower, SD
         (void **)&renderer->indirectDispatchCommandSignature);
     if (FAILED(res)) {
         D3D12_INTERNAL_DestroyRenderer(renderer);
-        ERROR_CHECK_RETURN("Could not create indirect dispatch command signature", NULL)
+        ERROR_SET_RETURN("Could not create indirect dispatch command signature", NULL)
     }
 
     // Initialize pools

+ 9 - 11
src/gpu/metal/SDL_gpu_metal.m

@@ -973,8 +973,7 @@ static SDL_GPUComputePipeline *METAL_CreateComputePipeline(
 
         handle = [renderer->device newComputePipelineStateWithFunction:libraryFunction.function error:&error];
         if (error != NULL) {
-            SDL_LogError(
-                SDL_LOG_CATEGORY_GPU,
+            SDL_SetError(
                 "Creating compute pipeline failed: %s", [[error description] UTF8String]);
             return NULL;
         }
@@ -1108,8 +1107,7 @@ static SDL_GPUGraphicsPipeline *METAL_CreateGraphicsPipeline(
 
         pipelineState = [renderer->device newRenderPipelineStateWithDescriptor:pipelineDescriptor error:&error];
         if (error != NULL) {
-            SDL_LogError(
-                SDL_LOG_CATEGORY_GPU,
+            SDL_SetError(
                 "Creating render pipeline failed: %s", [[error description] UTF8String]);
             return NULL;
         }
@@ -1284,7 +1282,7 @@ static SDL_GPUSampler *METAL_CreateSampler(
 
         sampler = [renderer->device newSamplerStateWithDescriptor:samplerDesc];
         if (sampler == NULL) {
-            SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to create sampler");
+            SDL_SetError("Failed to create sampler");
             return NULL;
         }
 
@@ -1411,7 +1409,7 @@ static SDL_GPUTexture *METAL_CreateTexture(
             createinfo);
 
         if (texture == NULL) {
-            SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to create texture!");
+            SDL_SetError("Failed to create texture!");
             return NULL;
         }
 
@@ -3526,7 +3524,7 @@ static bool METAL_ClaimWindow(
 
                 return true;
             } else {
-                SDL_LogError(SDL_LOG_CATEGORY_GPU, "Could not create swapchain, failed to claim window!");
+                SDL_SetError("Could not create swapchain, failed to claim window!");
                 SDL_free(windowData);
                 return false;
             }
@@ -3619,7 +3617,7 @@ static SDL_GPUTextureFormat METAL_GetSwapchainTextureFormat(
     MetalWindowData *windowData = METAL_INTERNAL_FetchWindowData(window);
 
     if (windowData == NULL) {
-        SDL_LogError(SDL_LOG_CATEGORY_GPU, "Cannot get swapchain format, window has not been claimed!");
+        SDL_SetError("Cannot get swapchain format, window has not been claimed!");
         return SDL_GPU_TEXTUREFORMAT_INVALID;
     }
 
@@ -3637,17 +3635,17 @@ static bool METAL_SetSwapchainParameters(
         CGColorSpaceRef colorspace;
 
         if (windowData == NULL) {
-            SDL_LogError(SDL_LOG_CATEGORY_GPU, "Cannot set swapchain parameters, window has not been claimed!");
+            SDL_SetError("Cannot set swapchain parameters, window has not been claimed!");
             return false;
         }
 
         if (!METAL_SupportsSwapchainComposition(driverData, window, swapchainComposition)) {
-            SDL_LogError(SDL_LOG_CATEGORY_GPU, "Swapchain composition not supported!");
+            SDL_SetError("Swapchain composition not supported!");
             return false;
         }
 
         if (!METAL_SupportsPresentMode(driverData, window, presentMode)) {
-            SDL_LogError(SDL_LOG_CATEGORY_GPU, "Present mode not supported!");
+            SDL_SetError("Present mode not supported!");
             return false;
         }
 

+ 52 - 63
src/gpu/vulkan/SDL_gpu_vulkan.c

@@ -1214,7 +1214,13 @@ static inline void LogVulkanResultAsError(
     }
 }
 
-#define VULKAN_ERROR_CHECK(res, fn, ret)                                        \
+#define ERROR_LOG_RETURN(res, fn, ret)                    \
+    if (res != VK_SUCCESS) {                              \
+        SDL_SetError("%s %s", #fn, VkErrorMessages(res)); \
+        return ret;                                       \
+    }
+
+#define ERROR_SET_RETURN(res, fn, ret)                                          \
     if (res != VK_SUCCESS) {                                                    \
         SDL_LogError(SDL_LOG_CATEGORY_GPU, "%s %s", #fn, VkErrorMessages(res)); \
         return ret;                                                             \
@@ -1798,7 +1804,7 @@ static Uint8 VULKAN_INTERNAL_AllocateMemory(
             VK_WHOLE_SIZE,
             0,
             (void **)&allocation->mapPointer);
-        VULKAN_ERROR_CHECK(result, vkMapMemory, 0)
+        ERROR_LOG_RETURN(result, vkMapMemory, 0)
     } else {
         allocation->mapPointer = NULL;
     }
@@ -1831,7 +1837,7 @@ static Uint8 VULKAN_INTERNAL_BindBufferMemory(
 
     SDL_UnlockMutex(usedRegion->allocation->memoryLock);
 
-    VULKAN_ERROR_CHECK(vulkanResult, vkBindBufferMemory, 0)
+    ERROR_LOG_RETURN(vulkanResult, vkBindBufferMemory, 0)
 
     return 1;
 }
@@ -1854,7 +1860,7 @@ static Uint8 VULKAN_INTERNAL_BindImageMemory(
 
     SDL_UnlockMutex(usedRegion->allocation->memoryLock);
 
-    VULKAN_ERROR_CHECK(vulkanResult, vkBindBufferMemory, 0)
+    ERROR_LOG_RETURN(vulkanResult, vkBindBufferMemory, 0)
 
     return 1;
 }
@@ -3494,10 +3500,7 @@ static bool VULKAN_INTERNAL_AllocateDescriptorSets(
 
     SDL_stack_free(descriptorSetLayouts);
 
-    if (vulkanResult != VK_SUCCESS) {
-        LogVulkanResultAsError("vkAllocateDescriptorSets", vulkanResult);
-        return false;
-    }
+    ERROR_LOG_RETURN(vulkanResult, "vkAllocateDescriptorSets", false)
 
     return true;
 }
@@ -4020,7 +4023,7 @@ static VulkanBuffer *VULKAN_INTERNAL_CreateBuffer(
         &createinfo,
         NULL,
         &buffer->buffer);
-    VULKAN_ERROR_CHECK(vulkanResult, vkCreateBuffer, 0)
+    ERROR_LOG_RETURN(vulkanResult, vkCreateBuffer, 0)
 
     bindResult = VULKAN_INTERNAL_BindMemoryForBuffer(
         renderer,
@@ -4219,7 +4222,7 @@ static Uint8 VULKAN_INTERNAL_QuerySwapchainSupport(
         physicalDevice,
         surface,
         &outputDetails->capabilities);
-    VULKAN_ERROR_CHECK(result, vkGetPhysicalDeviceSurfaceCapabilitiesKHR, 0)
+    ERROR_LOG_RETURN(result, vkGetPhysicalDeviceSurfaceCapabilitiesKHR, 0)
 
     if (!(outputDetails->capabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR)) {
         SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "Opaque presentation unsupported! Expect weird transparency bugs!");
@@ -4230,13 +4233,13 @@ static Uint8 VULKAN_INTERNAL_QuerySwapchainSupport(
         surface,
         &outputDetails->formatsLength,
         NULL);
-    VULKAN_ERROR_CHECK(result, vkGetPhysicalDeviceSurfaceFormatsKHR, 0)
+    ERROR_LOG_RETURN(result, vkGetPhysicalDeviceSurfaceFormatsKHR, 0)
     result = renderer->vkGetPhysicalDeviceSurfacePresentModesKHR(
         physicalDevice,
         surface,
         &outputDetails->presentModesLength,
         NULL);
-    VULKAN_ERROR_CHECK(result, vkGetPhysicalDeviceSurfacePresentModesKHR, 0)
+    ERROR_LOG_RETURN(result, vkGetPhysicalDeviceSurfacePresentModesKHR, 0)
 
     // Generate the arrays, if applicable
 
@@ -4467,7 +4470,7 @@ static bool VULKAN_INTERNAL_CreateSwapchain(
         drawableWidth > (Sint32)swapchainSupportDetails.capabilities.maxImageExtent.width ||
         drawableHeight < (Sint32)swapchainSupportDetails.capabilities.minImageExtent.height ||
         drawableHeight > (Sint32)swapchainSupportDetails.capabilities.maxImageExtent.height) {
-        if (swapchainSupportDetails.capabilities.currentExtent.width != UINT32_MAX) {
+        if (swapchainSupportDetails.capabilities.currentExtent.width != SDL_MAX_UINT32) {
             drawableWidth = VULKAN_INTERNAL_clamp(
                 drawableWidth,
                 (Sint32)swapchainSupportDetails.capabilities.minImageExtent.width,
@@ -4555,7 +4558,7 @@ static bool VULKAN_INTERNAL_CreateSwapchain(
             swapchainData->surface,
             NULL);
         SDL_free(swapchainData);
-        LogVulkanResultAsError("vkCreateSwapchainKHR", vulkanResult);
+        ERROR_LOG_RETURN(vulkanResult, "vkCreateSwapchainKHR", false)
         return false;
     }
 
@@ -5505,7 +5508,7 @@ static VulkanTexture *VULKAN_INTERNAL_CreateTexture(
         &imageCreateInfo,
         NULL,
         &texture->image);
-    VULKAN_ERROR_CHECK(vulkanResult, vkCreateImage, 0)
+    ERROR_LOG_RETURN(vulkanResult, vkCreateImage, 0)
 
     bindResult = VULKAN_INTERNAL_BindMemoryForImage(
         renderer,
@@ -5556,11 +5559,7 @@ static VulkanTexture *VULKAN_INTERNAL_CreateTexture(
             NULL,
             &texture->fullView);
 
-        if (vulkanResult != VK_SUCCESS) {
-            LogVulkanResultAsError("vkCreateImageView", vulkanResult);
-            SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to create texture image view");
-            return NULL;
-        }
+        ERROR_LOG_RETURN(vulkanResult, "vkCreateImageView", NULL)
     }
 
     // Define slices
@@ -6294,7 +6293,7 @@ static SDL_GPUGraphicsPipeline *VULKAN_CreateGraphicsPipeline(
         SDL_stack_free(colorBlendAttachmentStates);
         SDL_stack_free(divisorDescriptions);
         SDL_free(graphicsPipeline);
-        SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to initialize pipeline resource layout!");
+        SDL_SetError("Failed to initialize pipeline resource layout!");
         return NULL;
     }
 
@@ -6341,9 +6340,7 @@ static SDL_GPUGraphicsPipeline *VULKAN_CreateGraphicsPipeline(
 
     if (vulkanResult != VK_SUCCESS) {
         SDL_free(graphicsPipeline);
-        LogVulkanResultAsError("vkCreateGraphicsPipelines", vulkanResult);
-        SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to create graphics pipeline!");
-        return NULL;
+        ERROR_SET_RETURN(vulkanResult, "vkCreateGraphicsPipelines", NULL)
     }
 
     SDL_SetAtomicInt(&graphicsPipeline->referenceCount, 0);
@@ -6363,7 +6360,7 @@ static SDL_GPUComputePipeline *VULKAN_CreateComputePipeline(
     VulkanComputePipeline *vulkanComputePipeline;
 
     if (createinfo->format != SDL_GPU_SHADERFORMAT_SPIRV) {
-        SDL_LogError(SDL_LOG_CATEGORY_GPU, "Incompatible shader format for Vulkan!");
+        SDL_SetError("Incompatible shader format for Vulkan!");
         return NULL;
     }
 
@@ -6382,9 +6379,7 @@ static SDL_GPUComputePipeline *VULKAN_CreateComputePipeline(
 
     if (vulkanResult != VK_SUCCESS) {
         SDL_free(vulkanComputePipeline);
-        LogVulkanResultAsError("vkCreateShaderModule", vulkanResult);
-        SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to create compute pipeline!");
-        return NULL;
+        ERROR_SET_RETURN(vulkanResult, "vkCreateShaderModule", NULL)
     }
 
     pipelineShaderStageCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
@@ -6425,9 +6420,8 @@ static SDL_GPUComputePipeline *VULKAN_CreateComputePipeline(
         &vulkanComputePipeline->pipeline);
 
     if (vulkanResult != VK_SUCCESS) {
-        LogVulkanResultAsError("vkCreateComputePipeline", vulkanResult);
-        SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to create compute pipeline!");
         VULKAN_INTERNAL_DestroyComputePipeline(renderer, vulkanComputePipeline);
+        ERROR_SET_RETURN(vulkanResult, "vkCreateComputePipeline", NULL)
         return NULL;
     }
 
@@ -6472,8 +6466,7 @@ static SDL_GPUSampler *VULKAN_CreateSampler(
 
     if (vulkanResult != VK_SUCCESS) {
         SDL_free(vulkanSampler);
-        LogVulkanResultAsError("vkCreateSampler", vulkanResult);
-        return NULL;
+        ERROR_SET_RETURN(vulkanResult, "vkCreateSampler", NULL)
     }
 
     SDL_SetAtomicInt(&vulkanSampler->referenceCount, 0);
@@ -6506,9 +6499,7 @@ static SDL_GPUShader *VULKAN_CreateShader(
 
     if (vulkanResult != VK_SUCCESS) {
         SDL_free(vulkanShader);
-        LogVulkanResultAsError("vkCreateShaderModule", vulkanResult);
-        SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to create shader module!");
-        return NULL;
+        ERROR_SET_RETURN(vulkanResult, "vkCreateShaderModule", NULL)
     }
 
     entryPointNameLength = SDL_strlen(createinfo->entrypoint) + 1;
@@ -6549,7 +6540,7 @@ static SDL_GPUTexture *VULKAN_CreateTexture(
         createinfo);
 
     if (texture == NULL) {
-        SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to create texture!");
+        SDL_SetError("Failed to create texture!");
         return NULL;
     }
 
@@ -7447,8 +7438,8 @@ static void VULKAN_BeginRenderPass(
     SDL_GPUViewport defaultViewport;
     SDL_Rect defaultScissor;
     SDL_FColor defaultBlendConstants;
-    Uint32 framebufferWidth = UINT32_MAX;
-    Uint32 framebufferHeight = UINT32_MAX;
+    Uint32 framebufferWidth = SDL_MAX_UINT32;
+    Uint32 framebufferHeight = SDL_MAX_UINT32;
 
     for (i = 0; i < numColorTargets; i += 1) {
         VulkanTextureContainer *textureContainer = (VulkanTextureContainer *)colorTargetInfos[i].texture;
@@ -9164,7 +9155,7 @@ static SDL_GPUCommandBuffer *VULKAN_AcquireCommandBuffer(
     SDL_UnlockMutex(renderer->acquireCommandBufferLock);
 
     if (commandBuffer == NULL) {
-        SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to acquire command buffer!");
+        SDL_SetError("Failed to acquire command buffer!");
         return NULL;
     }
 
@@ -9234,9 +9225,7 @@ static SDL_GPUCommandBuffer *VULKAN_AcquireCommandBuffer(
         commandBuffer->commandBuffer,
         VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT);
 
-    if (result != VK_SUCCESS) {
-        LogVulkanResultAsError("vkResetCommandBuffer", result);
-    }
+    ERROR_SET_RETURN(result, "vkResetCommandBuffer", NULL)
 
     VULKAN_INTERNAL_BeginCommandBuffer(renderer, commandBuffer);
 
@@ -9255,12 +9244,12 @@ static bool VULKAN_QueryFence(
         ((VulkanFenceHandle *)fence)->fence);
 
     if (result == VK_SUCCESS) {
-        return 1;
+        return true;
     } else if (result == VK_NOT_READY) {
-        return 0;
+        return false;
     } else {
-        LogVulkanResultAsError("vkGetFenceStatus", result);
-        return 0;
+        SDL_SetError("%s %s", "vkGetFenceStatus", VkErrorMessages(result));
+        return false;
     }
 }
 
@@ -9325,7 +9314,7 @@ static bool VULKAN_SupportsSwapchainComposition(
     bool result = false;
 
     if (windowData == NULL || windowData->swapchainData == NULL) {
-        SDL_LogError(SDL_LOG_CATEGORY_GPU, "Must claim window before querying swapchain composition support!");
+        SDL_SetError("Must claim window before querying swapchain composition support!");
         return false;
     }
 
@@ -9371,7 +9360,7 @@ static bool VULKAN_SupportsPresentMode(
     bool result = false;
 
     if (windowData == NULL || windowData->swapchainData == NULL) {
-        SDL_LogError(SDL_LOG_CATEGORY_GPU, "Must claim window before querying present mode support!");
+        SDL_SetError("Must claim window before querying present mode support!");
         return false;
     }
 
@@ -9425,7 +9414,7 @@ static bool VULKAN_ClaimWindow(
 
             return 1;
         } else {
-            SDL_LogError(SDL_LOG_CATEGORY_GPU, "Could not create swapchain, failed to claim window!");
+            SDL_SetError("Could not create swapchain, failed to claim window!");
             SDL_free(windowData);
             return 0;
         }
@@ -9580,7 +9569,7 @@ static SDL_GPUTexture *VULKAN_AcquireSwapchainTexture(
     acquireResult = renderer->vkAcquireNextImageKHR(
         renderer->logicalDevice,
         swapchainData->swapchain,
-        UINT64_MAX,
+        SDL_MAX_UINT64,
         swapchainData->imageAvailableSemaphore[swapchainData->frameCounter],
         VK_NULL_HANDLE,
         &swapchainImageIndex);
@@ -9598,7 +9587,7 @@ static SDL_GPUTexture *VULKAN_AcquireSwapchainTexture(
         acquireResult = renderer->vkAcquireNextImageKHR(
             renderer->logicalDevice,
             swapchainData->swapchain,
-            UINT64_MAX,
+            SDL_MAX_UINT64,
             swapchainData->imageAvailableSemaphore[swapchainData->frameCounter],
             VK_NULL_HANDLE,
             &swapchainImageIndex);
@@ -9693,12 +9682,12 @@ static SDL_GPUTextureFormat VULKAN_GetSwapchainTextureFormat(
     WindowData *windowData = VULKAN_INTERNAL_FetchWindowData(window);
 
     if (windowData == NULL) {
-        SDL_LogError(SDL_LOG_CATEGORY_GPU, "Cannot get swapchain format, window has not been claimed!");
+        SDL_SetError("Cannot get swapchain format, window has not been claimed!");
         return SDL_GPU_TEXTUREFORMAT_INVALID;
     }
 
     if (windowData->swapchainData == NULL) {
-        SDL_LogError(SDL_LOG_CATEGORY_GPU, "Cannot get swapchain format, swapchain is currently invalid!");
+        SDL_SetError("Cannot get swapchain format, swapchain is currently invalid!");
         return SDL_GPU_TEXTUREFORMAT_INVALID;
     }
 
@@ -9716,17 +9705,17 @@ static bool VULKAN_SetSwapchainParameters(
     WindowData *windowData = VULKAN_INTERNAL_FetchWindowData(window);
 
     if (windowData == NULL) {
-        SDL_LogError(SDL_LOG_CATEGORY_GPU, "Cannot set swapchain parameters on unclaimed window!");
+        SDL_SetError("Cannot set swapchain parameters on unclaimed window!");
         return false;
     }
 
     if (!VULKAN_SupportsSwapchainComposition(driverData, window, swapchainComposition)) {
-        SDL_LogError(SDL_LOG_CATEGORY_GPU, "Swapchain composition not supported!");
+        SDL_SetError("Swapchain composition not supported!");
         return false;
     }
 
     if (!VULKAN_SupportsPresentMode(driverData, window, presentMode)) {
-        SDL_LogError(SDL_LOG_CATEGORY_GPU, "Present mode not supported!");
+        SDL_SetError("Present mode not supported!");
         return false;
     }
 
@@ -9996,7 +9985,7 @@ static void VULKAN_WaitForFences(
         numFences,
         vkFences,
         waitAll,
-        UINT64_MAX);
+        SDL_MAX_UINT64);
 
     if (result != VK_SUCCESS) {
         LogVulkanResultAsError("vkWaitForFences", result);
@@ -10833,7 +10822,7 @@ static Uint8 VULKAN_INTERNAL_IsDeviceSuitable(
         queueProps);
 
     queueFamilyBest = 0;
-    *queueFamilyIndex = UINT32_MAX;
+    *queueFamilyIndex = SDL_MAX_UINT32;
     for (i = 0; i < queueFamilyCount; i += 1) {
         supportsPresent = SDL_Vulkan_GetPresentationSupport(
             renderer->instance,
@@ -10888,7 +10877,7 @@ static Uint8 VULKAN_INTERNAL_IsDeviceSuitable(
 
     SDL_stack_free(queueProps);
 
-    if (*queueFamilyIndex == UINT32_MAX) {
+    if (*queueFamilyIndex == SDL_MAX_UINT32) {
         // Somehow no graphics queues existed. Compute-only device?
         return 0;
     }
@@ -10911,7 +10900,7 @@ static Uint8 VULKAN_INTERNAL_DeterminePhysicalDevice(VulkanRenderer *renderer)
         renderer->instance,
         &physicalDeviceCount,
         NULL);
-    VULKAN_ERROR_CHECK(vulkanResult, vkEnumeratePhysicalDevices, 0)
+    ERROR_LOG_RETURN(vulkanResult, vkEnumeratePhysicalDevices, 0)
 
     if (physicalDeviceCount == 0) {
         SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "Failed to find any GPUs with Vulkan support");
@@ -11108,7 +11097,7 @@ static Uint8 VULKAN_INTERNAL_CreateLogicalDevice(
         NULL,
         &renderer->logicalDevice);
     SDL_stack_free((void *)deviceExtensions);
-    VULKAN_ERROR_CHECK(vulkanResult, vkCreateDevice, 0)
+    ERROR_LOG_RETURN(vulkanResult, vkCreateDevice, 0)
 
     // Load vkDevice entry points
 
@@ -11230,7 +11219,7 @@ static SDL_GPUDevice *VULKAN_CreateDevice(bool debugMode, bool preferLowPower, S
     renderer->preferLowPower = preferLowPower;
 
     if (!VULKAN_INTERNAL_PrepareVulkan(renderer)) {
-        SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to initialize Vulkan!");
+        SDL_SetError("Failed to initialize Vulkan!");
         SDL_free(renderer);
         SDL_Vulkan_UnloadLibrary();
         return NULL;
@@ -11259,7 +11248,7 @@ static SDL_GPUDevice *VULKAN_CreateDevice(bool debugMode, bool preferLowPower, S
 
     if (!VULKAN_INTERNAL_CreateLogicalDevice(
             renderer)) {
-        SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to create logical device");
+        SDL_SetError("Failed to create logical device");
         SDL_free(renderer);
         SDL_Vulkan_UnloadLibrary();
         return NULL;