Rewrite how contexts are lost and restored

This means a) context isn't constantly destroyed and recreated when resizing window b) WebGL context is now partially restored, although all textures stay completely black
This commit is contained in:
UnknownShadow200 2019-07-18 21:34:39 +10:00
parent 6de770c6a4
commit ff7bbdb1ad
8 changed files with 136 additions and 98 deletions

View file

@ -40,14 +40,14 @@ void Drawer2D_MakeFont(FontDesc* desc, int size, int style) {
}
}
static Bitmap Drawer2D_FontBitmap;
static Bitmap fontBitmap;
static int Drawer2D_TileSize = 8; /* avoid divide by 0 if default.png missing */
/* So really 16 characters per row */
#define DRAWER2D_LOG2_CHARS_PER_ROW 4
static int Drawer2D_Widths[256];
static void Drawer2D_CalculateTextWidths(void) {
int width = Drawer2D_FontBitmap.Width, height = Drawer2D_FontBitmap.Height;
int width = fontBitmap.Width, height = fontBitmap.Height;
BitmapCol* row;
int i, x, y, xx, tileX, tileY;
@ -57,7 +57,7 @@ static void Drawer2D_CalculateTextWidths(void) {
for (y = 0; y < height; y++) {
tileY = y / Drawer2D_TileSize;
row = Bitmap_GetRow(&Drawer2D_FontBitmap, y);
row = Bitmap_GetRow(&fontBitmap, y);
for (x = 0; x < width; x += Drawer2D_TileSize) {
tileX = x / Drawer2D_TileSize;
@ -77,13 +77,13 @@ static void Drawer2D_CalculateTextWidths(void) {
}
static void Drawer2D_FreeFontBitmap(void) {
Mem_Free(Drawer2D_FontBitmap.Scan0);
Drawer2D_FontBitmap.Scan0 = NULL;
Mem_Free(fontBitmap.Scan0);
fontBitmap.Scan0 = NULL;
}
void Drawer2D_SetFontBitmap(Bitmap* bmp) {
Drawer2D_FreeFontBitmap();
Drawer2D_FontBitmap = *bmp;
fontBitmap = *bmp;
Drawer2D_TileSize = bmp->Width >> DRAWER2D_LOG2_CHARS_PER_ROW;
Drawer2D_CalculateTextWidths();
}
@ -463,7 +463,7 @@ static void Drawer2D_DrawCore(Bitmap* bmp, struct DrawTextArgs* args, int x, int
for (i = 0; i < count; i++) {
srcX = (coords[i] & 0x0F) * Drawer2D_TileSize;
srcY = (coords[i] >> 4) * Drawer2D_TileSize;
srcRow = Bitmap_GetRow(&Drawer2D_FontBitmap, fontY + srcY);
srcRow = Bitmap_GetRow(&fontBitmap, fontY + srcY);
srcWidth = Drawer2D_Widths[coords[i]];
dstWidth = dstWidths[i];

View file

@ -343,7 +343,6 @@ static void Game_ExtractInitialTexturePack(void) {
}
static void Game_LoadOptions(void) {
int method;
Game_ClassicMode = Options_GetBool(OPT_CLASSIC_MODE, false);
Game_ClassicHacks = Options_GetBool(OPT_CLASSIC_HACKS, false);
Game_AllowCustomBlocks = Options_GetBool(OPT_CUSTOM_BLOCKS, true);
@ -351,8 +350,6 @@ static void Game_LoadOptions(void) {
Game_SimpleArmsAnim = Options_GetBool(OPT_SIMPLE_ARMS_ANIM, false);
Game_ViewBobbing = Options_GetBool(OPT_VIEW_BOBBING, true);
method = Options_GetEnum(OPT_FPS_LIMIT, 0, FpsLimit_Names, FPS_LIMIT_COUNT);
Game_SetFpsLimit(method);
Game_ViewDistance = Options_GetInt(OPT_VIEW_DISTANCE, 16, 4096, 512);
Game_UserViewDistance = Game_ViewDistance;
@ -433,7 +430,6 @@ static void Game_Load(void) {
Game_Fov = 70;
Gfx_Init();
Gfx_SetFpsLimit(true, 0);
Gfx_MakeApiInfo();
Gfx.Mipmaps = Options_GetBool(OPT_MIPMAPS, false);
@ -495,6 +491,10 @@ static void Game_Load(void) {
Game_ExtractInitialTexturePack();
entTaskI = ScheduledTask_Add(GAME_DEF_TICKS, Entities_Tick);
/* set vsync after because it causes a context loss depending on backend */
Gfx_SetFpsLimit(true, 0);
Game_SetFpsLimit(Options_GetEnum(OPT_FPS_LIMIT, 0, FpsLimit_Names, FPS_LIMIT_COUNT));
if (Gfx_WarnIfNecessary()) EnvRenderer_SetMode(EnvRenderer_Minimal | ENV_LEGACY);
Server.BeginConnect();
}
@ -625,6 +625,15 @@ static void Game_RenderFrame(double delta) {
bool allowZoom, visible;
float t;
/* TODO: Should other tasks get called back too? */
/* Might not be such a good idea for the http_clearcache, */
/* don't really want all skins getting lost */
if (Gfx.LostContext && !Gfx_TryRestoreContext()) {
Server.Tick(NULL);
Thread_Sleep(16);
return;
}
Gfx_BeginFrame();
Gfx_BindIb(Gfx_defaultIb);
Game.Time += delta;

View file

@ -36,10 +36,15 @@ static float gfx_minFrameMs;
static uint64_t frameStart;
bool Gfx_GetFog(void) { return gfx_fogEnabled; }
/* Initialises/Restores render state. */
CC_NOINLINE static void Gfx_RestoreState(void);
/* Destroys render state, but can be restored later. */
CC_NOINLINE static void Gfx_FreeState(void);
/*########################################################################################################################*
*------------------------------------------------------Generic/Common-----------------------------------------------------*
*#########################################################################################################################*/
CC_NOINLINE static void Gfx_InitDefaultResources(void) {
static void Gfx_InitDefaultResources(void) {
uint16_t indices[GFX_MAX_INDICES];
Gfx_MakeIndices(indices, GFX_MAX_INDICES);
Gfx_defaultIb = Gfx_CreateIb(indices, GFX_MAX_INDICES);
@ -48,7 +53,7 @@ CC_NOINLINE static void Gfx_InitDefaultResources(void) {
Gfx_texVb = Gfx_CreateDynamicVb(VERTEX_FORMAT_P3FT2FC4B, 4);
}
CC_NOINLINE static void Gfx_FreeDefaultResources(void) {
static void Gfx_FreeDefaultResources(void) {
Gfx_DeleteVb(&Gfx_quadVb);
Gfx_DeleteVb(&Gfx_texVb);
Gfx_DeleteIb(&Gfx_defaultIb);
@ -69,16 +74,16 @@ void Gfx_LoseContext(const char* reason) {
Gfx.LostContext = true;
Platform_Log1("Lost graphics context: %c", reason);
Gfx_FreeState();
Event_RaiseVoid(&GfxEvents.ContextLost);
Gfx_FreeDefaultResources();
}
void Gfx_RecreateContext(void) {
static void Gfx_RecreateContext(void) {
Gfx.LostContext = false;
Platform_LogConst("Recreating graphics context");
Gfx_RestoreState();
Event_RaiseVoid(&GfxEvents.ContextRecreated);
Gfx_InitDefaultResources();
}
@ -296,14 +301,13 @@ ReturnCode res = IDirect3DDevice9_SetRenderState(device, state, value); if (res)
#define D3D9_SetRenderState2(state, value, name) \
res = IDirect3DDevice9_SetRenderState(device, state, value); if (res) Logger_Abort2(res, name);
static void D3D9_SetDefaultRenderStates(void);
static void D3D9_RestoreRenderStates(void);
static void D3D9_FreeResource(GfxResourceID* resource) {
IUnknown* unk;
ULONG refCount;
if (!resource || *resource == GFX_NULL) return;
if (*resource == GFX_NULL) return;
unk = (IUnknown*)(*resource);
*resource = GFX_NULL;
@ -318,20 +322,6 @@ static void D3D9_FreeResource(GfxResourceID* resource) {
Platform_Log2("D3D9 resource has %i outstanding references! ID 0x%x", &refCount, &addr);
}
static void D3D9_LoopUntilRetrieved(void) {
struct ScheduledTask task;
task.Interval = 1.0f / 60.0f;
task.Callback = Gfx.LostContextFunction;
while (true) {
Thread_Sleep(16);
ReturnCode code = IDirect3DDevice9_TestCooperativeLevel(device);
if (code == D3DERR_DEVICENOTRESET) return;
task.Callback(&task);
}
}
static void D3D9_FindCompatibleFormat(void) {
static D3DFORMAT depthFormats[6] = { D3DFMT_D32, D3DFMT_D24X8, D3DFMT_D24S8, D3DFMT_D24X4S4, D3DFMT_D16, D3DFMT_D15S1 };
static D3DFORMAT viewFormats[4] = { D3DFMT_X8R8G8B8, D3DFMT_R8G8B8, D3DFMT_R5G6B5, D3DFMT_X1R5G5B5 };
@ -366,19 +356,6 @@ static void D3D9_FillPresentArgs(int width, int height, D3DPRESENT_PARAMETERS* a
args->Windowed = true;
}
static void D3D9_RecreateDevice(void) {
D3DPRESENT_PARAMETERS args = { 0 };
D3D9_FillPresentArgs(Game.Width, Game.Height, &args);
while (IDirect3DDevice9_Reset(device, &args) == D3DERR_DEVICELOST) {
D3D9_LoopUntilRetrieved();
}
D3D9_SetDefaultRenderStates();
D3D9_RestoreRenderStates();
Gfx_RecreateContext();
}
void Gfx_Init(void) {
Gfx.MinZNear = 0.05f;
HWND winHandle = (HWND)Window_Handle;
@ -407,18 +384,52 @@ void Gfx_Init(void) {
Gfx.MaxTexWidth = caps.MaxTextureWidth;
Gfx.MaxTexHeight = caps.MaxTextureHeight;
Gfx.CustomMipmapsLevels = true;
D3D9_SetDefaultRenderStates();
Gfx_InitDefaultResources();
Gfx_RestoreState();
}
bool Gfx_TryRestoreContext(void) {
D3DPRESENT_PARAMETERS args = { 0 };
ReturnCode res;
res = IDirect3DDevice9_TestCooperativeLevel(device);
if (res && res != D3DERR_DEVICENOTRESET) return false;
D3D9_FillPresentArgs(Game.Width, Game.Height, &args);
res = IDirect3DDevice9_Reset(device, &args);
if (res == D3DERR_DEVICELOST) return false;
Gfx_RecreateContext();
return true;
}
void Gfx_Free(void) {
Gfx_FreeDefaultResources();
Gfx_FreeState();
D3D9_FreeResource(&device);
D3D9_FreeResource(&d3d);
}
static void Gfx_FreeState(void) {
Gfx_FreeDefaultResources();
}
static void Gfx_RestoreState(void) {
Gfx_InitDefaultResources();
Gfx_SetFaceCulling(false);
gfx_batchFormat = -1;
D3D9_SetRenderState(D3DRS_COLORVERTEX, false, "D3D9_ColorVertex");
D3D9_SetRenderState2(D3DRS_LIGHTING, false, "D3D9_Lighting");
D3D9_SetRenderState2(D3DRS_SPECULARENABLE, false, "D3D9_SpecularEnable");
D3D9_SetRenderState2(D3DRS_LOCALVIEWER, false, "D3D9_LocalViewer");
D3D9_SetRenderState2(D3DRS_DEBUGMONITORTOKEN, false, "D3D9_DebugMonitor");
/* States relevant to the game */
D3D9_SetRenderState2(D3DRS_ALPHAFUNC, D3DCMP_GREATER, "D3D9_AlphaTestFunc");
D3D9_SetRenderState2(D3DRS_ALPHAREF, 127, "D3D9_AlphaRefFunc");
D3D9_RestoreRenderStates();
}
/*########################################################################################################################*
*---------------------------------------------------------Textures--------------------------------------------------------*
@ -673,20 +684,6 @@ void Gfx_SetDepthWrite(bool enabled) {
D3D9_SetRenderState(D3DRS_ZWRITEENABLE, enabled, "D3D9_SetDepthWrite");
}
static void D3D9_SetDefaultRenderStates(void) {
Gfx_SetFaceCulling(false);
gfx_batchFormat = -1;
D3D9_SetRenderState(D3DRS_COLORVERTEX, false, "D3D9_ColorVertex");
D3D9_SetRenderState2(D3DRS_LIGHTING, false, "D3D9_Lighting");
D3D9_SetRenderState2(D3DRS_SPECULARENABLE, false, "D3D9_SpecularEnable");
D3D9_SetRenderState2(D3DRS_LOCALVIEWER, false, "D3D9_LocalViewer");
D3D9_SetRenderState2(D3DRS_DEBUGMONITORTOKEN, false, "D3D9_DebugMonitor");
/* States relevant to the game */
D3D9_SetRenderState2(D3DRS_ALPHAFUNC, D3DCMP_GREATER, "D3D9_AlphaTestFunc");
D3D9_SetRenderState2(D3DRS_ALPHAREF, 127, "D3D9_AlphaRefFunc");
}
static void D3D9_RestoreRenderStates(void) {
union IntAndFloat raw;
D3D9_SetRenderState(D3DRS_ALPHATESTENABLE, gfx_alphaTesting, "D3D9_AlphaTest");
@ -903,10 +900,9 @@ finished:
void Gfx_SetFpsLimit(bool vsync, float minFrameMs) {
gfx_minFrameMs = minFrameMs;
if (gfx_vsync == vsync) return;
gfx_vsync = vsync;
gfx_vsync = vsync;
Gfx_LoseContext(" (toggling VSync)");
D3D9_RecreateDevice();
}
void Gfx_BeginFrame(void) {
@ -926,11 +922,8 @@ void Gfx_EndFrame(void) {
if (res) {
if (res != D3DERR_DEVICELOST) Logger_Abort2(res, "D3D9_EndFrame");
/* TODO: Make sure this actually works on all graphics cards.*/
/* TODO: Make sure this actually works on all graphics cards. */
Gfx_LoseContext(" (Direct3D9 device lost)");
D3D9_LoopUntilRetrieved();
D3D9_RecreateDevice();
}
if (gfx_minFrameMs) Gfx_LimitFPS();
}
@ -979,8 +972,11 @@ void Gfx_UpdateApiInfo(void) {
}
void Gfx_OnWindowResize(void) {
if (Gfx.LostContext) return;
Gfx_LoseContext(" (resizing window)");
D3D9_RecreateDevice();
/* NOTE: Windows enters a size/move modal loop. (WM_ENTERSIZELOOP) */
/* This blocks the normal game loop from running, which means */
/* Gfx_OnWindowResize can end up getting called multiple times. */
}
#endif
@ -1053,7 +1049,6 @@ static GL_SetupVBFunc gfx_setupVBFunc;
static GL_SetupVBRangeFunc gfx_setupVBRangeFunc;
static void GL_CheckSupport(void);
static void GL_InitState(void);
void Gfx_Init(void) {
struct GraphicsMode mode;
GraphicsMode_MakeDefault(&mode);
@ -1064,8 +1059,13 @@ void Gfx_Init(void) {
Gfx.MaxTexHeight = Gfx.MaxTexWidth;
GL_CheckSupport();
GL_InitState();
Gfx_InitDefaultResources();
Gfx_RestoreState();
}
bool Gfx_TryRestoreContext(void) {
if (!GLContext_TryRestore()) return false;
Gfx_RecreateContext();
return true;
}
void Gfx_Free(void) {
@ -1143,7 +1143,7 @@ void Gfx_BindTexture(GfxResourceID texId) {
}
void Gfx_DeleteTexture(GfxResourceID* texId) {
if (!texId || *texId == GFX_NULL) return;
if (*texId == GFX_NULL) return;
GLuint id = (GLuint)(*texId);
glDeleteTextures(1, &id);
*texId = GFX_NULL;
@ -1232,7 +1232,7 @@ void Gfx_BindVb(GfxResourceID vb) { _glBindBuffer(GL_ARRAY_BUFFER, (GLuint)vb);
void Gfx_BindIb(GfxResourceID ib) { _glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, (GLuint)ib); }
void Gfx_DeleteVb(GfxResourceID* vb) {
if (!vb || *vb == GFX_NULL) return;
if (*vb == GFX_NULL) return;
GLuint id = (GLuint)(*vb);
_glDeleteBuffers(1, &id);
*vb = GFX_NULL;
@ -1653,7 +1653,18 @@ static void GL_CheckSupport(void) {
#endif
}
static void GL_InitState(void) {
static void Gfx_FreeState(void) {
int i;
Gfx_FreeDefaultResources();
for (i = 0; i < Array_Elems(shaders); i++) {
glDeleteProgram(shaders[i].Program);
shaders[i].Program = 0;
}
}
static void Gfx_RestoreState(void) {
Gfx_InitDefaultResources();
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
Gfx_SwitchProgram();
@ -1781,7 +1792,9 @@ void Gfx_LoadIdentityMatrix(MatrixType type) {
glLoadIdentity();
}
static void GL_InitState(void) {
static void Gfx_FreeState(void) { Gfx_FreeDefaultResources(); }
static void Gfx_RestoreState(void) {
Gfx_InitDefaultResources();
glHint(GL_FOG_HINT, GL_NICEST);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
@ -1928,7 +1941,7 @@ void Gfx_BindIb(GfxResourceID ib) { }
void Gfx_DeleteIb(GfxResourceID* ib) { }
void Gfx_DeleteVb(GfxResourceID* vb) {
if (!vb || *vb == GFX_NULL) return;
if (*vb == GFX_NULL) return;
if (*vb != gl_DYNAMICLISTID) glDeleteLists((GLuint)(*vb), 1);
*vb = GFX_NULL;
}

View file

@ -45,8 +45,6 @@ CC_VAR extern struct _GfxData {
/* Whether mipmaps must be created for all dimensions down to 1x1 or not. */
bool CustomMipmapsLevels;
struct Matrix View, Projection;
/* Callback invoked when the context is lost. Repeatedly invoked until a context can be retrieved. */
ScheduledTaskCallback LostContextFunction;
} Gfx;
extern String Gfx_ApiInfo[7];
@ -169,13 +167,13 @@ void Gfx_OnWindowResize(void);
/* Fills Gfx_ApiInfo with information about the backend state and the user's GPU. */
void Gfx_MakeApiInfo(void);
/* Updates Gfx_ApiInfo with current backend state information. */
/* NOTE: This is information such as current free memory, etc. */
/* NOTE: This updates information such as current free memory, etc. */
void Gfx_UpdateApiInfo(void);
/* Raises ContextLost event and updates state for lost contexts. */
void Gfx_LoseContext(const char* reason);
/* Raises ContextRecreated event and restores state from lost contexts. */
void Gfx_RecreateContext(void);
/* Attempts to restore a lost context. Raises ContextRecreated event is successful. */
bool Gfx_TryRestoreContext(void);
/* Binds and draws the specified subset of the vertices in the current dynamic vertex buffer. */
/* NOTE: This replaces the dynamic vertex buffer's data first with the given vertices before drawing. */

View file

@ -476,14 +476,16 @@ static void LoadingScreen_MapLoading(void* screen, float progress) {
static void LoadingScreen_OnResize(void* screen) {
struct LoadingScreen* s = (struct LoadingScreen*)screen;
if (!s->title.VTABLE) return;
Widget_Reposition(&s->title);
Widget_Reposition(&s->message);
}
static void LoadingScreen_ContextLost(void* screen) {
struct LoadingScreen* s = (struct LoadingScreen*)screen;
Elem_TryFree(&s->title);
Elem_TryFree(&s->message);
if (!s->title.VTABLE) return;
Elem_Free(&s->title);
Elem_Free(&s->message);
}
static void LoadingScreen_ContextRecreated(void* screen) {
@ -1427,9 +1429,10 @@ static void DisconnectScreen_UpdateDelayLeft(struct DisconnectScreen* s, double
static void DisconnectScreen_ContextLost(void* screen) {
struct DisconnectScreen* s = (struct DisconnectScreen*)screen;
Elem_TryFree(&s->title);
Elem_TryFree(&s->message);
Elem_TryFree(&s->reconnect);
if (!s->title.VTABLE) return;
Elem_Free(&s->title);
Elem_Free(&s->message);
Elem_Free(&s->reconnect);
}
static void DisconnectScreen_ContextRecreated(void* screen) {
@ -1489,6 +1492,7 @@ static void DisconnectScreen_Free(void* screen) {
static void DisconnectScreen_OnResize(void* screen) {
struct DisconnectScreen* s = (struct DisconnectScreen*)screen;
if (!s->title.VTABLE) return;
Widget_Reposition(&s->title);
Widget_Reposition(&s->message);
Widget_Reposition(&s->reconnect);

View file

@ -240,7 +240,6 @@ static uint8_t* net_readCurrent;
static bool net_writeFailed;
static TimeMS net_lastPacket;
static uint8_t net_lastOpcode;
static double net_discAccumulator;
static bool net_connecting;
static TimeMS net_connectTimeout;
@ -352,15 +351,10 @@ static void MPConnection_SendPosition(Vec3 pos, float rotY, float headX) {
static void MPConnection_CheckDisconnection(double delta) {
static const String title = String_FromConst("Disconnected!");
static const String reason = String_FromConst("You've lost connection to the server");
ReturnCode availRes, selectRes;
uint32_t pending = 0;
bool poll_read;
net_discAccumulator += delta;
if (net_discAccumulator < 1.0) return;
net_discAccumulator = 0.0;
availRes = Socket_Available(net_socket, &pending);
/* poll read returns true when socket is closed */
selectRes = Socket_Poll(net_socket, SOCKET_POLL_READ, &poll_read);
@ -537,7 +531,6 @@ static void Server_Init(void) {
MPConnection_Init();
}
Gfx.LostContextFunction = Server.Tick;
ScheduledTask_Add(GAME_NET_TICKS, Server.Tick);
String_AppendConst(&Server.AppName, GAME_APP_NAME);
}

View file

@ -7,8 +7,10 @@
#include "ExtMath.h"
int Display_BitsPerPixel;
int Display_DpiX = 96, Display_DpiY = 96;
int Display_DpiX = DISPLAY_DEFAULT_DPI;
int Display_DpiY = DISPLAY_DEFAULT_DPI;
Rect2D Display_Bounds;
int Window_X, Window_Y, Window_Width, Window_Height;
bool Window_Exists, Window_Focused;
const void* Window_Handle;
@ -354,7 +356,6 @@ void Window_Init(void) {
Display_DpiX = GetDeviceCaps(hdc, LOGPIXELSX);
Display_DpiY = GetDeviceCaps(hdc, LOGPIXELSY);
ReleaseDC(NULL, hdc);
Platform_Log2("DPI: %i, %i", &Display_DpiX, &Display_DpiY);
}
void Window_Create(int x, int y, int width, int height, struct GraphicsMode* mode) {
@ -3047,6 +3048,7 @@ void GLContext_Init(struct GraphicsMode* mode) {
}
void GLContext_Update(void) { }
bool GLContext_TryRestore(void) { return true; }
void GLContext_Free(void) {
if (!wglDeleteContext(ctx_Handle)) {
Logger_Abort2(GetLastError(), "Failed to destroy OpenGL context");
@ -3117,6 +3119,7 @@ void GLContext_Init(struct GraphicsMode* mode) {
}
void GLContext_Update(void) { }
bool GLContext_TryRestore(void) { return true; }
void GLContext_Free(void) {
if (!ctx_Handle) return;
@ -3335,6 +3338,7 @@ void GLContext_Update(void) {
GLContext_SetDrawable();
aglUpdateContext(ctx_handle);
}
bool GLContext_TryRestore(void) { return true; }
void GLContext_Free(void) {
int code;
@ -3346,7 +3350,7 @@ void GLContext_Free(void) {
code = aglDestroyContext(ctx_handle);
GLContext_Check(code, "Destroying GL context");
ctx_handle = NULL;
}
}10.
void* GLContext_GetAddress(const char* function) {
void* address = DynamicLib_GetFrom("/System/Library/Frameworks/OpenGL.framework/Versions/Current/OpenGL", function);
@ -3387,6 +3391,7 @@ void GLContext_Init(struct GraphicsMode* mode) {
}
void GLContext_Update(void) { }
bool GLContext_TryRestore(void) { return true; }
void GLContext_Free(void) {
SDL_GL_DeleteContext(win_ctx);
win_ctx = NULL;
@ -3456,6 +3461,7 @@ void GLContext_Update(void) {
ctx_surface = eglCreateWindowSurface(ctx_display, ctx_config, win_handle, NULL);
eglMakeCurrent(ctx_display, ctx_surface, ctx_surface, ctx_context);
}
bool GLContext_TryRestore(void) { return true; }
void GLContext_Free(void) {
eglMakeCurrent(ctx_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
@ -3482,10 +3488,16 @@ void GLContext_SetFpsLimit(bool vsync, float minFrameMs) {
*------------------------------------------------Emscripten WebGL context-------------------------------------------------*
*#########################################################################################################################*/
#ifdef CC_BUILD_WEBGL
#include "Graphics.h"
#include <emscripten/emscripten.h>
#include <emscripten/html5.h>
static EMSCRIPTEN_WEBGL_CONTEXT_HANDLE ctx_handle;
static EM_BOOL GLContext_OnLost(int eventType, const void *reserved, void *userData) {
Gfx_LoseContext("WebGL context lost");
return 1;
}
void GLContext_Init(struct GraphicsMode* mode) {
EmscriptenWebGLContextAttributes attribs;
emscripten_webgl_init_context_attributes(&attribs);
@ -3496,14 +3508,19 @@ void GLContext_Init(struct GraphicsMode* mode) {
ctx_handle = emscripten_webgl_create_context(NULL, &attribs);
emscripten_webgl_make_context_current(ctx_handle);
emscripten_set_webglcontextlost_callback("#canvas", NULL, 0, GLContext_OnLost);
}
void GLContext_Update(void) {
/* TODO: do we need to do something here.... ? */
}
bool GLContext_TryRestore(void) {
return !emscripten_is_webgl_context_lost(ctx_handle);
}
void GLContext_Free(void) {
emscripten_webgl_destroy_context(ctx_handle);
emscripten_set_webglcontextlost_callback("#canvas", NULL, 0, NULL);
}
void* GLContext_GetAddress(const char* function) { return NULL; }

View file

@ -33,6 +33,8 @@
/* The states the window can be in. */
enum WindowState { WINDOW_STATE_NORMAL, WINDOW_STATE_MINIMISED, WINDOW_STATE_MAXIMISED, WINDOW_STATE_FULLSCREEN };
#define DISPLAY_DEFAULT_DPI 96
/* Number of bits per pixel. (red bits + green bits + blue bits + alpha bits) */
/* NOTE: Only 24 or 32 bits per pixel are officially supported. */
/* Support for other values of bits per pixel is platform dependent. */
@ -136,6 +138,8 @@ void Window_DisableRawMouse(void);
void GLContext_Init(struct GraphicsMode* mode);
/* Updates the OpenGL context after the window is resized. */
void GLContext_Update(void);
/* Attempts to restore a lost OpenGL context. */
bool GLContext_TryRestore(void);
/* Destroys the OpenGL context. */
/* NOTE: This also unattaches the OpenGL context from the window. */
void GLContext_Free(void);