Skip to content
Draft
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions GNUmakefile
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ OBJS = \
src/async.o \
src/crypto.o \
src/dtls.o \
src/error.o \
src/file.o \
src/hash.o \
src/http.o \
Expand Down
1 change: 1 addition & 0 deletions makefile
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ OBJS = \
src\async.obj \
src\crypto.obj \
src\dtls.obj \
src\error.obj \
src\file.obj \
src\hash.obj \
src\http.obj \
Expand Down
46 changes: 46 additions & 0 deletions src/error.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#include "error.h"

#include "tlocal.h"

static TLOCAL MTY_Queue *Q = NULL;

void error_local_init(void)
{
error_local_clear();

Q = MTY_QueueCreate(10, sizeof(MTY_Error));
}

void error_local_clear(void)
{
MTY_QueueDestroy(&Q);
}


bool error_local_get_next_error(MTY_Error *error)
{
if (!Q)
return false;

MTY_Error *buf = NULL;

bool rc = MTY_QueueGetOutputBuffer(Q, 0, (void **) &buf, NULL);
if (rc) {
*error = *buf;
MTY_QueuePop(Q);
}

return rc;
}

void error_local_push_error(MTY_Error error)
{
if (!Q)
return;

MTY_Error *buf = MTY_QueueGetInputBuffer(Q);
if (buf) {
*buf = error;
MTY_QueuePush(Q, sizeof(MTY_Error));
}
}
9 changes: 9 additions & 0 deletions src/error.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#pragma once

#include "matoya.h"

void error_local_init(void);
void error_local_clear(void);

bool error_local_get_next_error(MTY_Error *error);
void error_local_push_error(MTY_Error error);
16 changes: 16 additions & 0 deletions src/matoya.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,17 @@ typedef bool (*MTY_MenuItemCheckedFunc)(void *opaque);
typedef intptr_t (*MTY_WMsgFunc)(MTY_App *app, MTY_Window window, void *hwnd, uint32_t msg,
intptr_t wparam, uintptr_t lparam, bool *shouldReturn, void *opaque);

/// @brief Error codes indicating the current state of the platform.
/// @details Warnings are positive, errors are negative, 0 (::MTY_ERROR_OK) means no error.
typedef enum {
MTY_ERROR_OK = 0, ///< No errors.
MTY_ERROR_GFX_INVISIBLE_CONTENT = 11, ///< Warning from the gfx driver that rendered content is hidden (for example, when app is in the UAC prompt on Windows)
MTY_ERROR_GFX_REVISIBLE_CONTENT = 12, ///< Notice from the gfx driver that rendered content that was hidden is now visible
MTY_ERROR_GFX_ERROR = -11, ///< Generic gfx error
MTY_ERROR_GFX_DEVICE_REMOVED = -21, ///< Generally indicates that the display was unplugged or disabled abruptly
MTY_ERROR_MAKE_32 = INT32_MAX,
} MTY_Error;

/// @brief 3D graphics APIs.
typedef enum {
MTY_GFX_NONE = 0, ///< No 3D graphics API.
Expand Down Expand Up @@ -2617,6 +2628,11 @@ MTY_ThreadDetach(MTY_ThreadFunc func, void *opaque);
MTY_EXPORT int64_t
MTY_ThreadGetID(MTY_Thread *ctx);

/// @brief Get the next error code for the given thread.
/// @param ctx An MTY_Thread.
MTY_EXPORT MTY_Error
MTY_ThreadGetError(MTY_Thread *ctx);

/// @brief Create an MTY_Mutex for synchronization.
/// @details A mutex can be locked by only one thread at a time. Other threads trying
/// to take the same mutex will block until it becomes unlocked.
Expand Down
11 changes: 11 additions & 0 deletions src/thread.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,18 @@

#include "rwlock.h"
#include "tlocal.h"
#include "error.h"

// Thread

MTY_Error MTY_ThreadGetError(MTY_Thread *ctx)
{
// `ctx` is not used since errors are managed via tlocal state

MTY_Error e = MTY_ERROR_OK;
error_local_get_next_error(&e);
return e;
}

// RWLock

Expand Down
5 changes: 5 additions & 0 deletions src/unix/apple/gfx/metal-ui.m
Original file line number Diff line number Diff line change
Expand Up @@ -236,3 +236,8 @@ void mty_metal_ui_destroy(struct gfx_ui **gfx_ui, MTY_Device *device)
MTY_Free(ctx);
*gfx_ui = NULL;
}

int32_t mty_metal_ui_get_error(struct gfx_ui *gfx_ui)
{
return 0;
}
33 changes: 29 additions & 4 deletions src/windows/gfx/d3d11-ctx.c
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All changes in this file implement a more robust GPU error handling. This portion concerns the main graphics context state.

Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,11 @@ GFX_CTX_PROTOTYPES(_d3d11_)
#include "gfx/sync.h"
#include "dxgi-sync.h"

#include "d3d11-error.h"

#define DXGI_FATAL(e) ( \
(e) == DXGI_ERROR_DEVICE_REMOVED || \
(e) == DXGI_ERROR_DRIVER_INTERNAL_ERROR || \
(e) == DXGI_ERROR_DEVICE_HUNG || \
(e) == DXGI_ERROR_DEVICE_RESET \
)
Expand Down Expand Up @@ -187,12 +190,21 @@ static bool d3d11_ctx_init(struct d3d11_ctx *ctx)
if (device2)
IDXGIDevice2_Release(device2);

if (e != S_OK)
if (e != S_OK) {
d3d11_push_local_error(e);
d3d11_ctx_free(ctx);
}

return e == S_OK;
}

int32_t mty_d3d11_error_handler_default(int32_t e1, int32_t e2, void *opaque)
{
e1; e2; opaque;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We usually put each of these on a different line


return 0;
}

struct gfx_ctx *mty_d3d11_ctx_create(void *native_window, bool vsync)
{
struct d3d11_ctx *ctx = MTY_Alloc(1, sizeof(struct d3d11_ctx));
Expand Down Expand Up @@ -263,6 +275,8 @@ static void d3d11_ctx_refresh(struct d3d11_ctx *ctx)

if (DXGI_FATAL(e)) {
MTY_Log("'IDXGISwapChain2_ResizeBuffers' failed with HRESULT 0x%X", e);
d3d11_push_local_error(e);

d3d11_ctx_free(ctx);
d3d11_ctx_init(ctx);
}
Expand All @@ -273,6 +287,7 @@ MTY_Surface *mty_d3d11_ctx_get_surface(struct gfx_ctx *gfx_ctx)
{
struct d3d11_ctx *ctx = (struct d3d11_ctx *) gfx_ctx;

HRESULT e = S_OK;
ID3D11Resource *resource = NULL;

if (!ctx->swap_chain2)
Expand All @@ -281,22 +296,28 @@ MTY_Surface *mty_d3d11_ctx_get_surface(struct gfx_ctx *gfx_ctx)
if (!ctx->back_buffer) {
d3d11_ctx_refresh(ctx);

HRESULT e = IDXGISwapChain2_GetBuffer(ctx->swap_chain2, 0, &IID_ID3D11Resource, &resource);
e = IDXGISwapChain2_GetBuffer(ctx->swap_chain2, 0, &IID_ID3D11Resource, &resource);
if (e != S_OK) {
MTY_Log("'IDXGISwapChain2_GetBuffer' failed with HRESULT 0x%X", e);
goto except;
}

e = ID3D11Device_CreateRenderTargetView(ctx->device, resource, NULL, &ctx->back_buffer);
if (e != S_OK)
if (e != S_OK) {
MTY_Log("'ID3D11Device_CreateRenderTargetView' failed with HRESULT 0x%X", e);
goto except;
}
}

except:

if (resource)
ID3D11Resource_Release(resource);

if (e != S_OK)
d3d11_push_local_error(e);


return (MTY_Surface *) ctx->back_buffer;
}

Expand Down Expand Up @@ -335,13 +356,17 @@ void mty_d3d11_ctx_present(struct gfx_ctx *gfx_ctx)

if (DXGI_FATAL(e)) {
MTY_Log("'IDXGISwapChain2_Present' failed with HRESULT 0x%X", e);
d3d11_push_local_error(e);

d3d11_ctx_free(ctx);
d3d11_ctx_init(ctx);

} else {
DWORD we = WaitForSingleObjectEx(ctx->waitable, D3D11_CTX_WAIT, TRUE);
if (we != WAIT_OBJECT_0)
if (we != WAIT_OBJECT_0) {
MTY_Log("'WaitForSingleObjectEx' failed with error 0x%X", we);
d3d11_push_local_error(e);
}
}
}
}
Expand Down
29 changes: 29 additions & 0 deletions src/windows/gfx/d3d11-error.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#pragma once

#include "matoya.h"

#include "error.h"

static MTY_Error d3d11_map_error(int32_t e)
{
switch (e) {
case DXGI_ERROR_DEVICE_REMOVED:
case DXGI_ERROR_DRIVER_INTERNAL_ERROR:
return MTY_ERROR_GFX_DEVICE_REMOVED;

case DXGI_ERROR_DEVICE_HUNG:
case DXGI_ERROR_DEVICE_RESET:
return MTY_ERROR_GFX_ERROR;

case DXGI_STATUS_OCCLUDED:
return MTY_ERROR_GFX_INVISIBLE_CONTENT;

case DXGI_STATUS_UNOCCLUDED:
return MTY_ERROR_GFX_REVISIBLE_CONTENT;

default:
return MTY_ERROR_OK;
}
}

#define d3d11_push_local_error(e) error_local_push_error(d3d11_map_error(e))
29 changes: 22 additions & 7 deletions src/windows/gfx/d3d11-ui.c
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All changes in this file implement a more robust GPU error handling. This portion concerns state pertaining to rendering UI.

Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ static
static
#include "shaders/vsui.h"

#include "d3d11-error.h"

struct d3d11_ui_buffer {
ID3D11Buffer *b;
ID3D11Resource *res;
Expand Down Expand Up @@ -149,8 +151,11 @@ struct gfx_ui *mty_d3d11_ui_create(MTY_Device *device)

except:

if (e != S_OK)
if (e != S_OK) {
d3d11_push_local_error(e);
mty_d3d11_ui_destroy((struct gfx_ui **) &ctx, device);
}


return (struct gfx_ui *) ctx;
}
Expand Down Expand Up @@ -204,30 +209,32 @@ bool mty_d3d11_ui_render(struct gfx_ui *gfx_ui, MTY_Device *device, MTY_Context
if (dd->displaySize.x <= 0 || dd->displaySize.y <= 0 || dd->cmdListLength == 0)
return false;

bool result = false;

// Resize vertex and index buffers if necessary
HRESULT e = d3d11_ui_resize_buffer(_device, &ctx->vb, dd->vtxTotalLength, GFX_UI_VTX_INCR, sizeof(MTY_Vtx),
D3D11_BIND_VERTEX_BUFFER);
if (e != S_OK)
return false;
goto except;

e = d3d11_ui_resize_buffer(_device, &ctx->ib, dd->idxTotalLength, GFX_UI_IDX_INCR, sizeof(uint16_t),
D3D11_BIND_INDEX_BUFFER);
if (e != S_OK)
return false;
goto except;

// Map both vertex and index buffers and bulk copy the data
D3D11_MAPPED_SUBRESOURCE vtx_map = {0};
e = ID3D11DeviceContext_Map(_context, ctx->vb.res, 0, D3D11_MAP_WRITE_DISCARD, 0, &vtx_map);
if (e != S_OK) {
MTY_Log("'ID3D11DeviceContext_Map' failed with HRESULT 0x%X", e);
return false;
goto except;
}

D3D11_MAPPED_SUBRESOURCE idx_map = {0};
e = ID3D11DeviceContext_Map(_context, ctx->ib.res, 0, D3D11_MAP_WRITE_DISCARD, 0, &idx_map);
if (e != S_OK) {
MTY_Log("'ID3D11DeviceContext_Map' failed with HRESULT 0x%X", e);
return false;
goto except;
}

MTY_Vtx *vtx_dst = (MTY_Vtx *) vtx_map.pData;
Expand Down Expand Up @@ -261,7 +268,7 @@ bool mty_d3d11_ui_render(struct gfx_ui *gfx_ui, MTY_Device *device, MTY_Context
D3D11_MAPPED_SUBRESOURCE cb_map = {0};
e = ID3D11DeviceContext_Map(_context, ctx->cb_res, 0, D3D11_MAP_WRITE_DISCARD, 0, &cb_map);
if (e != S_OK)
return false;
goto except;

struct d3d11_ui_cb *cb = (struct d3d11_ui_cb *) cb_map.pData;
memcpy(&cb->proj, proj, sizeof(proj));
Expand Down Expand Up @@ -338,7 +345,14 @@ bool mty_d3d11_ui_render(struct gfx_ui *gfx_ui, MTY_Device *device, MTY_Context
vtxOffset += cmdList->vtxLength;
}

return true;
result = true;

except:

if (e != S_OK)
d3d11_push_local_error(e);

return result;
}

void *mty_d3d11_ui_create_texture(struct gfx_ui *gfx_ui, MTY_Device *device, const void *rgba,
Expand Down Expand Up @@ -394,6 +408,7 @@ void *mty_d3d11_ui_create_texture(struct gfx_ui *gfx_ui, MTY_Device *device, con
ID3D11Texture2D_Release(tex);

if (e != S_OK && srv) {
d3d11_push_local_error(e);
ID3D11ShaderResourceView_Release(srv);
srv = NULL;
}
Expand Down
4 changes: 4 additions & 0 deletions src/windows/threadw.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#include <windows.h>

#include "error.h"

// Thread

Expand Down Expand Up @@ -51,6 +52,7 @@ static MTY_Thread *thread_create(MTY_ThreadFunc func, void *opaque, bool detach)

} else {
ctx->thread = thread;
error_local_init();
}

return ctx;
Expand All @@ -69,6 +71,8 @@ void *MTY_ThreadDestroy(MTY_Thread **thread)
MTY_Thread *ctx = *thread;

if (ctx->thread) {
error_local_clear();

if (WaitForSingleObject(ctx->thread, INFINITE) == WAIT_FAILED)
MTY_LogFatal("'WaitForSingleObject' failed with error 0x%X", GetLastError());

Expand Down