Skip to content

Commit

Permalink
Added SDL_EVENT_RENDER_DEVICE_LOST
Browse files Browse the repository at this point in the history
This is sent when the device is lost and can't be recovered.
  • Loading branch information
slouken committed Oct 21, 2024
1 parent c761ec1 commit 80f3e53
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 102 deletions.
1 change: 1 addition & 0 deletions include/SDL3/SDL_events.h
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,7 @@ typedef enum SDL_EventType
/* Render events */
SDL_EVENT_RENDER_TARGETS_RESET = 0x2000, /**< The render targets have been reset and their contents need to be updated */
SDL_EVENT_RENDER_DEVICE_RESET, /**< The device has been reset and all textures need to be recreated */
SDL_EVENT_RENDER_DEVICE_LOST, /**< The device has been lost and can't be recovered. */

/* Reserved events for private platforms */
SDL_EVENT_PRIVATE0 = 0x4000,
Expand Down
67 changes: 24 additions & 43 deletions src/render/direct3d11/SDL_render_d3d11.c
Original file line number Diff line number Diff line change
Expand Up @@ -982,39 +982,6 @@ static void D3D11_ReleaseMainRenderTargetView(SDL_Renderer *renderer)
SAFE_RELEASE(data->mainRenderTargetView);
}

static HRESULT D3D11_UpdateForWindowSizeChange(SDL_Renderer *renderer);

static HRESULT D3D11_HandleDeviceLost(SDL_Renderer *renderer)
{
HRESULT result = S_OK;

D3D11_ReleaseAll(renderer);

result = D3D11_CreateDeviceResources(renderer);
if (FAILED(result)) {
// D3D11_CreateDeviceResources will set the SDL error
D3D11_ReleaseAll(renderer);
return result;
}

result = D3D11_UpdateForWindowSizeChange(renderer);
if (FAILED(result)) {
// D3D11_UpdateForWindowSizeChange will set the SDL error
D3D11_ReleaseAll(renderer);
return result;
}

// Let the application know that the device has been reset
{
SDL_Event event;
event.type = SDL_EVENT_RENDER_DEVICE_RESET;
event.common.timestamp = 0;
SDL_PushEvent(&event);
}

return S_OK;
}

// Initialize all resources that change when the window's size changes.
static HRESULT D3D11_CreateWindowSizeDependentResources(SDL_Renderer *renderer)
{
Expand Down Expand Up @@ -1045,15 +1012,7 @@ static HRESULT D3D11_CreateWindowSizeDependentResources(SDL_Renderer *renderer)
w, h,
DXGI_FORMAT_UNKNOWN,
0);
if (result == DXGI_ERROR_DEVICE_REMOVED) {
// If the device was removed for any reason, a new device and swap chain will need to be created.
D3D11_HandleDeviceLost(renderer);

/* Everything is set up now. Do not continue execution of this method. HandleDeviceLost will reenter this method
* and correctly set up the new device.
*/
goto done;
} else if (FAILED(result)) {
if (FAILED(result)) {
WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("IDXGISwapChain::ResizeBuffers"), result);
goto done;
}
Expand Down Expand Up @@ -1110,6 +1069,28 @@ static HRESULT D3D11_CreateWindowSizeDependentResources(SDL_Renderer *renderer)
return result;
}

static bool D3D11_HandleDeviceLost(SDL_Renderer *renderer)
{
bool recovered = false;

D3D11_ReleaseAll(renderer);

if (SUCCEEDED(D3D11_CreateDeviceResources(renderer)) &&
SUCCEEDED(D3D11_CreateWindowSizeDependentResources(renderer))) {
recovered = true;
} else {
SDL_LogError(SDL_LOG_CATEGORY_RENDER, "Renderer couldn't recover from device lost: %s\n", SDL_GetError());
}

// Let the application know that the device has been reset or lost
SDL_Event event;
event.type = recovered ? SDL_EVENT_RENDER_DEVICE_RESET : SDL_EVENT_RENDER_DEVICE_LOST;
event.common.timestamp = 0;
SDL_PushEvent(&event);

return recovered;
}

// This method is called when the window's size changes.
static HRESULT D3D11_UpdateForWindowSizeChange(SDL_Renderer *renderer)
{
Expand Down Expand Up @@ -2644,7 +2625,7 @@ static bool D3D11_RenderPresent(SDL_Renderer *renderer)
* must recreate all device resources.
*/
if (result == DXGI_ERROR_DEVICE_REMOVED) {
if (SUCCEEDED(D3D11_HandleDeviceLost(renderer))) {
if (D3D11_HandleDeviceLost(renderer)) {
SDL_SetError("Present failed, device lost");
} else {
// Recovering from device lost failed, error is already set
Expand Down
66 changes: 24 additions & 42 deletions src/render/direct3d12/SDL_render_d3d12.c
Original file line number Diff line number Diff line change
Expand Up @@ -1326,38 +1326,6 @@ static HRESULT D3D12_CreateSwapChain(SDL_Renderer *renderer, int w, int h)
}
#endif

static HRESULT D3D12_UpdateForWindowSizeChange(SDL_Renderer *renderer);

HRESULT
D3D12_HandleDeviceLost(SDL_Renderer *renderer)
{
HRESULT result = S_OK;

D3D12_ReleaseAll(renderer);

result = D3D12_CreateDeviceResources(renderer);
if (FAILED(result)) {
// D3D12_CreateDeviceResources will set the SDL error
return result;
}

result = D3D12_UpdateForWindowSizeChange(renderer);
if (FAILED(result)) {
// D3D12_UpdateForWindowSizeChange will set the SDL error
return result;
}

// Let the application know that the device has been reset
{
SDL_Event event;
event.type = SDL_EVENT_RENDER_DEVICE_RESET;
event.common.timestamp = 0;
SDL_PushEvent(&event);
}

return S_OK;
}

// Initialize all resources that change when the window's size changes.
static HRESULT D3D12_CreateWindowSizeDependentResources(SDL_Renderer *renderer)
{
Expand Down Expand Up @@ -1396,15 +1364,7 @@ static HRESULT D3D12_CreateWindowSizeDependentResources(SDL_Renderer *renderer)
w, h,
DXGI_FORMAT_UNKNOWN,
data->swapFlags);
if (result == DXGI_ERROR_DEVICE_REMOVED) {
// If the device was removed for any reason, a new device and swap chain will need to be created.
D3D12_HandleDeviceLost(renderer);

/* Everything is set up now. Do not continue execution of this method. HandleDeviceLost will reenter this method
* and correctly set up the new device.
*/
goto done;
} else if (FAILED(result)) {
if (FAILED(result)) {
WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("IDXGISwapChain::ResizeBuffers"), result);
goto done;
}
Expand Down Expand Up @@ -1484,6 +1444,28 @@ static HRESULT D3D12_CreateWindowSizeDependentResources(SDL_Renderer *renderer)
return result;
}

static bool D3D12_HandleDeviceLost(SDL_Renderer *renderer)
{
bool recovered = false;

D3D12_ReleaseAll(renderer);

if (SUCCEEDED(D3D12_CreateDeviceResources(renderer)) &&
SUCCEEDED(D3D12_CreateWindowSizeDependentResources(renderer))) {
recovered = true;
} else {
SDL_LogError(SDL_LOG_CATEGORY_RENDER, "Renderer couldn't recover from device lost: %s\n", SDL_GetError());
}

// Let the application know that the device has been reset or lost
SDL_Event event;
event.type = recovered ? SDL_EVENT_RENDER_DEVICE_RESET : SDL_EVENT_RENDER_DEVICE_LOST;
event.common.timestamp = 0;
SDL_PushEvent(&event);

return recovered;
}

// This method is called when the window's size changes.
static HRESULT D3D12_UpdateForWindowSizeChange(SDL_Renderer *renderer)
{
Expand Down Expand Up @@ -3137,7 +3119,7 @@ static bool D3D12_RenderPresent(SDL_Renderer *renderer)
* must recreate all device resources.
*/
if (result == DXGI_ERROR_DEVICE_REMOVED) {
if (SUCCEEDED(D3D12_HandleDeviceLost(renderer))) {
if (D3D12_HandleDeviceLost(renderer)) {
SDL_SetError("Present failed, device lost");
} else {
// Recovering from device lost failed, error is already set
Expand Down
39 changes: 22 additions & 17 deletions src/render/vulkan/SDL_render_vulkan.c
Original file line number Diff line number Diff line change
Expand Up @@ -490,6 +490,7 @@ static void VULKAN_DestroyAll(SDL_Renderer *renderer)
if (rendererData->surfaceFormats != NULL) {
SDL_free(rendererData->surfaceFormats);
rendererData->surfaceFormats = NULL;
rendererData->surfaceFormatsAllocatedCount = 0;
}
if (rendererData->swapchainImages != NULL) {
SDL_free(rendererData->swapchainImages);
Expand Down Expand Up @@ -2481,28 +2482,24 @@ static VkResult VULKAN_CreateWindowSizeDependentResources(SDL_Renderer *renderer
static bool VULKAN_HandleDeviceLost(SDL_Renderer *renderer)
{
VULKAN_RenderData *rendererData = (VULKAN_RenderData *)renderer->internal;

VULKAN_WaitForGPU(rendererData);
bool recovered = false;

VULKAN_DestroyAll(renderer);

if (VULKAN_CreateDeviceResources(renderer, rendererData->create_props) != VK_SUCCESS) {
return false;
}

if (VULKAN_CreateWindowSizeDependentResources(renderer) != VK_SUCCESS) {
return false;
if (VULKAN_CreateDeviceResources(renderer, rendererData->create_props) == VK_SUCCESS &&
VULKAN_CreateWindowSizeDependentResources(renderer) == VK_SUCCESS) {
recovered = true;
} else {
SDL_LogError(SDL_LOG_CATEGORY_RENDER, "Renderer couldn't recover from device lost: %s\n", SDL_GetError());
}

// Let the application know that the device has been reset
{
SDL_Event event;
event.type = SDL_EVENT_RENDER_DEVICE_RESET;
event.common.timestamp = 0;
SDL_PushEvent(&event);
}
// Let the application know that the device has been reset or lost
SDL_Event event;
event.type = recovered ? SDL_EVENT_RENDER_DEVICE_RESET : SDL_EVENT_RENDER_DEVICE_LOST;
event.common.timestamp = 0;
SDL_PushEvent(&event);

return true;
return recovered;
}

// This method is called when the window's size changes.
Expand Down Expand Up @@ -4111,7 +4108,15 @@ static bool VULKAN_RenderPresent(SDL_Renderer *renderer)
// Wait for previous time this command buffer was submitted, will be N frames ago
result = vkWaitForFences(rendererData->device, 1, &rendererData->fences[rendererData->currentCommandBufferIndex], VK_TRUE, UINT64_MAX);
if (result != VK_SUCCESS) {
SDL_LogError(SDL_LOG_CATEGORY_RENDER, "vkWaitForFences(): %s\n", SDL_Vulkan_GetResultString(result));
if (result == VK_ERROR_DEVICE_LOST) {
if (VULKAN_HandleDeviceLost(renderer)) {
SDL_SetError("Present failed, device lost");
} else {
// Recovering from device lost failed, error is already set
}
} else {
SDL_LogError(SDL_LOG_CATEGORY_RENDER, "vkWaitForFences(): %s\n", SDL_Vulkan_GetResultString(result));
}
return false;
}

Expand Down

0 comments on commit 80f3e53

Please sign in to comment.