From e23cae6d277697027ff72491553f3643b0200ab2 Mon Sep 17 00:00:00 2001 From: Christian Semmler Date: Sat, 28 Jun 2025 10:58:01 -0700 Subject: [PATCH] Add WebGL support to Emscripten --- CMakeLists.txt | 2 +- miniwin/CMakeLists.txt | 16 +++++++--- .../src/d3drm/backends/opengles2/renderer.cpp | 31 +++++++++++++------ miniwin/src/ddraw/ddraw.cpp | 6 ++-- miniwin/src/internal/d3drmrenderer.h | 11 +++++-- .../src/internal/d3drmrenderer_opengles2.h | 21 ++++++++++--- miniwin/src/internal/ddraw_impl.h | 2 +- 7 files changed, 61 insertions(+), 28 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1f7e0595..3100f3a1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,7 +4,7 @@ project(isle LANGUAGES CXX C VERSION 0.1) if (EMSCRIPTEN) add_compile_options(-pthread) - add_link_options(-sALLOW_MEMORY_GROWTH=1 -sMAXIMUM_MEMORY=2gb -sUSE_PTHREADS=1 -sPROXY_TO_PTHREAD=1 -sPTHREAD_POOL_SIZE_STRICT=0 -sFORCE_FILESYSTEM=1 -sWASMFS=1 -sEXIT_RUNTIME=1) + add_link_options(-sALLOW_MEMORY_GROWTH=1 -sMAXIMUM_MEMORY=2gb -sUSE_PTHREADS=1 -sPROXY_TO_PTHREAD=1 -sOFFSCREENCANVAS_SUPPORT=1 -sPTHREAD_POOL_SIZE_STRICT=0 -sFORCE_FILESYSTEM=1 -sWASMFS=1 -sEXIT_RUNTIME=1) set(SDL_PTHREADS ON CACHE BOOL "Enable SDL pthreads" FORCE) endif() diff --git a/miniwin/CMakeLists.txt b/miniwin/CMakeLists.txt index a1939441..5c718985 100644 --- a/miniwin/CMakeLists.txt +++ b/miniwin/CMakeLists.txt @@ -42,14 +42,20 @@ else() message(STATUS "🧩 OpenGL 1.x support not enabled — needs OpenGL and GLEW") endif() -find_library(OPENGL_ES2_LIBRARY NAMES GLESv2) -if(OPENGL_ES2_LIBRARY) - message(STATUS "Found OpenGL: enabling OpenGL ES 2.x renderer") +if(EMSCRIPTEN) + message(STATUS "Found OpenGL: enabling OpenGL ES 2.x renderer for Emscripten") target_sources(miniwin PRIVATE src/d3drm/backends/opengles2/renderer.cpp) target_compile_definitions(miniwin PRIVATE USE_OPENGLES2) - target_link_libraries(miniwin PRIVATE OpenGL::GL) else() - message(STATUS "🧩 OpenGL ES 2.x support not enabled") + find_library(OPENGL_ES2_LIBRARY NAMES GLESv2) + if(OPENGL_ES2_LIBRARY) + message(STATUS "Found OpenGL: enabling OpenGL ES 2.x renderer") + target_sources(miniwin PRIVATE src/d3drm/backends/opengles2/renderer.cpp) + target_compile_definitions(miniwin PRIVATE USE_OPENGLES2) + target_link_libraries(miniwin PRIVATE OpenGL::GL) + else() + message(STATUS "🧩 OpenGL ES 2.x support not enabled") + endif() endif() if(WIN32) diff --git a/miniwin/src/d3drm/backends/opengles2/renderer.cpp b/miniwin/src/d3drm/backends/opengles2/renderer.cpp index 3dbabda2..7eec8207 100644 --- a/miniwin/src/d3drm/backends/opengles2/renderer.cpp +++ b/miniwin/src/d3drm/backends/opengles2/renderer.cpp @@ -177,6 +177,24 @@ Direct3DRMRenderer* OpenGLES2Renderer::Create(DWORD width, DWORD height) return new OpenGLES2Renderer(width, height, context, shaderProgram); } +void OpenGLES2Desc::GetDesc(D3DDEVICEDESC* halDesc, D3DDEVICEDESC* helDesc) +{ + halDesc->dcmColorModel = D3DCOLORMODEL::RGB; + halDesc->dwFlags = D3DDD_DEVICEZBUFFERBITDEPTH; + halDesc->dwDeviceZBufferBitDepth = DDBD_16; + helDesc->dwDeviceRenderBitDepth = DDBD_32; + halDesc->dpcTriCaps.dwTextureCaps = D3DPTEXTURECAPS_PERSPECTIVE; + halDesc->dpcTriCaps.dwShadeCaps = D3DPSHADECAPS_ALPHAFLATBLEND; + halDesc->dpcTriCaps.dwTextureFilterCaps = D3DPTFILTERCAPS_LINEAR; + + memset(helDesc, 0, sizeof(D3DDEVICEDESC)); +} + +const char* OpenGLES2Desc::GetName() +{ + return "OpenGL ES 2.0 HAL"; +} + OpenGLES2Renderer::OpenGLES2Renderer(DWORD width, DWORD height, SDL_GLContext context, GLuint shaderProgram) : m_context(context), m_shaderProgram(shaderProgram) { @@ -409,9 +427,8 @@ Uint32 OpenGLES2Renderer::GetMeshId(IDirect3DRMMesh* mesh, const MeshGroup* mesh void OpenGLES2Renderer::GetDesc(D3DDEVICEDESC* halDesc, D3DDEVICEDESC* helDesc) { - halDesc->dcmColorModel = D3DCOLORMODEL::RGB; - halDesc->dwFlags = D3DDD_DEVICEZBUFFERBITDEPTH; - halDesc->dwDeviceZBufferBitDepth = DDBD_16; + OpenGLES2Desc::GetDesc(halDesc, helDesc); + const char* extensions = (const char*) glGetString(GL_EXTENSIONS); if (extensions) { if (strstr(extensions, "GL_OES_depth24")) { @@ -421,17 +438,11 @@ void OpenGLES2Renderer::GetDesc(D3DDEVICEDESC* halDesc, D3DDEVICEDESC* helDesc) halDesc->dwDeviceZBufferBitDepth |= DDBD_32; } } - helDesc->dwDeviceRenderBitDepth = DDBD_32; - halDesc->dpcTriCaps.dwTextureCaps = D3DPTEXTURECAPS_PERSPECTIVE; - halDesc->dpcTriCaps.dwShadeCaps = D3DPSHADECAPS_ALPHAFLATBLEND; - halDesc->dpcTriCaps.dwTextureFilterCaps = D3DPTFILTERCAPS_LINEAR; - - memset(helDesc, 0, sizeof(D3DDEVICEDESC)); } const char* OpenGLES2Renderer::GetName() { - return "OpenGL ES 2.0 HAL"; + return OpenGLES2Desc::GetName(); } HRESULT OpenGLES2Renderer::BeginFrame() diff --git a/miniwin/src/ddraw/ddraw.cpp b/miniwin/src/ddraw/ddraw.cpp index acf695eb..a79bd4c2 100644 --- a/miniwin/src/ddraw/ddraw.cpp +++ b/miniwin/src/ddraw/ddraw.cpp @@ -207,12 +207,12 @@ HRESULT DirectDrawImpl::GetCaps(LPDDCAPS lpDDDriverCaps, LPDDCAPS lpDDHELCaps) return S_OK; } -void EnumDevice(LPD3DENUMDEVICESCALLBACK cb, void* ctx, Direct3DRMRenderer* device, GUID deviceGuid) +void EnumDevice(LPD3DENUMDEVICESCALLBACK cb, void* ctx, Direct3DRMDesc* desc, GUID deviceGuid) { D3DDEVICEDESC halDesc = {}; D3DDEVICEDESC helDesc = {}; - device->GetDesc(&halDesc, &helDesc); - char* deviceNameDup = SDL_strdup(device->GetName()); + desc->GetDesc(&halDesc, &helDesc); + char* deviceNameDup = SDL_strdup(desc->GetName()); char* deviceDescDup = SDL_strdup("Miniwin driver"); cb(&deviceGuid, deviceNameDup, deviceDescDup, &halDesc, &helDesc, ctx); SDL_free(deviceDescDup); diff --git a/miniwin/src/internal/d3drmrenderer.h b/miniwin/src/internal/d3drmrenderer.h index e76f0759..ceaa3795 100644 --- a/miniwin/src/internal/d3drmrenderer.h +++ b/miniwin/src/internal/d3drmrenderer.h @@ -26,7 +26,14 @@ struct Plane { float d; }; -class Direct3DRMRenderer : public IDirect3DDevice2 { +class Direct3DRMDesc { +public: + virtual ~Direct3DRMDesc() {} + virtual void GetDesc(D3DDEVICEDESC* halDesc, D3DDEVICEDESC* helDesc) = 0; + virtual const char* GetName() = 0; +}; + +class Direct3DRMRenderer : public IDirect3DDevice2, public Direct3DRMDesc { public: virtual void PushLights(const SceneLight* vertices, size_t count) = 0; virtual void SetProjection(const D3DRMMATRIX4D& projection, D3DVALUE front, D3DVALUE back) = 0; @@ -37,8 +44,6 @@ class Direct3DRMRenderer : public IDirect3DDevice2 { int GetHeight() { return m_height; } int GetVirtualWidth() { return m_virtualWidth; } int GetVirtualHeight() { return m_virtualHeight; } - virtual void GetDesc(D3DDEVICEDESC* halDesc, D3DDEVICEDESC* helDesc) = 0; - virtual const char* GetName() = 0; virtual HRESULT BeginFrame() = 0; virtual void EnableTransparency() = 0; virtual void SubmitDraw( diff --git a/miniwin/src/internal/d3drmrenderer_opengles2.h b/miniwin/src/internal/d3drmrenderer_opengles2.h index 7ea1ed9a..6520f520 100644 --- a/miniwin/src/internal/d3drmrenderer_opengles2.h +++ b/miniwin/src/internal/d3drmrenderer_opengles2.h @@ -30,7 +30,13 @@ struct GLES2MeshCacheEntry { GLuint ibo; }; -class OpenGLES2Renderer : public Direct3DRMRenderer { +class OpenGLES2Desc : public Direct3DRMDesc { +public: + void GetDesc(D3DDEVICEDESC* halDesc, D3DDEVICEDESC* helDesc) override; + const char* GetName() override; +}; + +class OpenGLES2Renderer : public Direct3DRMRenderer, public OpenGLES2Desc { public: static Direct3DRMRenderer* Create(DWORD width, DWORD height); OpenGLES2Renderer(DWORD width, DWORD height, SDL_GLContext context, GLuint shaderProgram); @@ -77,9 +83,14 @@ class OpenGLES2Renderer : public Direct3DRMRenderer { inline static void OpenGLES2Renderer_EnumDevice(LPD3DENUMDEVICESCALLBACK cb, void* ctx) { - Direct3DRMRenderer* device = OpenGLES2Renderer::Create(640, 480); - if (device) { - EnumDevice(cb, ctx, device, OpenGLES2_GUID); - delete device; +#ifdef __EMSCRIPTEN__ + // We need a static description since creating test windows, context changes etc. are not allowed + Direct3DRMDesc* desc = new OpenGLES2Desc(); +#else + Direct3DRMDesc* desc = OpenGLES2Renderer::Create(640, 480); +#endif + if (desc) { + EnumDevice(cb, ctx, desc, OpenGLES2_GUID); + delete desc; } } diff --git a/miniwin/src/internal/ddraw_impl.h b/miniwin/src/internal/ddraw_impl.h index f2604946..3faa9f89 100644 --- a/miniwin/src/internal/ddraw_impl.h +++ b/miniwin/src/internal/ddraw_impl.h @@ -56,4 +56,4 @@ HRESULT DirectDrawEnumerate(LPDDENUMCALLBACKA cb, void* context); HRESULT DirectDrawCreate(LPGUID lpGuid, LPDIRECTDRAW* lplpDD, IUnknown* pUnkOuter); -void EnumDevice(LPD3DENUMDEVICESCALLBACK cb, void* ctx, Direct3DRMRenderer* device, GUID deviceGuid); +void EnumDevice(LPD3DENUMDEVICESCALLBACK cb, void* ctx, Direct3DRMDesc* desc, GUID deviceGuid);