From a5a3c4ec83092f1bacb92e98715f5f2edc9a857d Mon Sep 17 00:00:00 2001 From: Christian Semmler Date: Wed, 23 Jul 2025 11:00:48 -0700 Subject: [PATCH] Upgrade OpenGL ES renderer to 3.0, add option for MSAA (#636) --- CMakeLists.txt | 4 +- ISLE/isleapp.cpp | 3 + ISLE/isleapp.h | 1 + LEGO1/mxdirectx/mxdirect3d.cpp | 20 + LEGO1/mxdirectx/mxdirectxinfo.cpp | 19 + LEGO1/omni/include/mxvideoparam.h | 6 + LEGO1/omni/src/video/mxvideoparam.cpp | 3 + miniwin/CMakeLists.txt | 16 +- miniwin/include/miniwin/miniwind3d.h | 8 + .../{opengles2 => opengles3}/renderer.cpp | 344 +++++++++--------- miniwin/src/d3drm/d3drm.cpp | 6 +- miniwin/src/d3drm/d3drmrenderer.cpp | 22 +- miniwin/src/ddraw/ddraw.cpp | 20 +- miniwin/src/internal/d3drmrenderer.h | 9 +- ..._opengles2.h => d3drmrenderer_opengles3.h} | 49 ++- miniwin/src/internal/ddraw_impl.h | 7 +- 16 files changed, 324 insertions(+), 213 deletions(-) create mode 100644 miniwin/include/miniwin/miniwind3d.h rename miniwin/src/d3drm/backends/{opengles2 => opengles3}/renderer.cpp (76%) rename miniwin/src/internal/{d3drmrenderer_opengles2.h => d3drmrenderer_opengles3.h} (71%) diff --git a/CMakeLists.txt b/CMakeLists.txt index f43617c0..24860101 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,7 +14,7 @@ endif() if (EMSCRIPTEN) add_compile_options(-pthread) - 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) + add_link_options(-sUSE_WEBGL2=1 -sMIN_WEBGL_VERSION=2 -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() @@ -181,6 +181,8 @@ target_include_directories(lego1 PUBLIC "$:DirectX5::DirectX5>) +# Allow unconditional include of miniwin/miniwind3d.h +target_link_libraries(lego1 PRIVATE miniwin-headers) if(WIN32) set_property(TARGET lego1 PROPERTY PREFIX "") endif() diff --git a/ISLE/isleapp.cpp b/ISLE/isleapp.cpp index b2fab5fb..b2a39dcc 100644 --- a/ISLE/isleapp.cpp +++ b/ISLE/isleapp.cpp @@ -182,6 +182,7 @@ IsleApp::IsleApp() m_exclusiveFrameRate = 60.00f; m_frameRate = 100.0f; m_exclusiveFullScreen = FALSE; + m_msaaSamples = 0; } // FUNCTION: ISLE 0x4011a0 @@ -914,6 +915,7 @@ MxResult IsleApp::SetupWindow() #endif window = SDL_CreateWindowWithProperties(props); + SDL_SetPointerProperty(SDL_GetWindowProperties(window), ISLE_PROP_WINDOW_CREATE_VIDEO_PARAM, &m_videoParam); if (m_exclusiveFullScreen && m_fullScreen) { SDL_DisplayMode closestMode; @@ -1188,6 +1190,7 @@ bool IsleApp::LoadConfig() } m_frameRate = (1000.0f / iniparser_getdouble(dict, "isle:Frame Delta", m_frameDelta)); m_frameDelta = static_cast(std::round(iniparser_getdouble(dict, "isle:Frame Delta", m_frameDelta))); + m_videoParam.SetMSAASamples(iniparser_getint(dict, "isle:MSAA", m_msaaSamples)); const char* deviceId = iniparser_getstring(dict, "isle:3D Device ID", NULL); if (deviceId != NULL) { diff --git a/ISLE/isleapp.h b/ISLE/isleapp.h index 06c1b51f..7346d817 100644 --- a/ISLE/isleapp.h +++ b/ISLE/isleapp.h @@ -114,6 +114,7 @@ private: MxFloat m_exclusiveFrameRate; MxFloat m_frameRate; MxBool m_exclusiveFullScreen; + MxU32 m_msaaSamples; }; extern IsleApp* g_isle; diff --git a/LEGO1/mxdirectx/mxdirect3d.cpp b/LEGO1/mxdirectx/mxdirect3d.cpp index 7f12d147..5eacf824 100644 --- a/LEGO1/mxdirectx/mxdirect3d.cpp +++ b/LEGO1/mxdirectx/mxdirect3d.cpp @@ -1,7 +1,12 @@ +#ifndef MINIWIN +#include +#endif + #include "mxdirect3d.h" #include // for SDL_Log #include +#include DECOMP_SIZE_ASSERT(MxDirect3D, 0x894) @@ -44,6 +49,7 @@ BOOL MxDirect3D::Create( ) { BOOL success = FALSE; + IDirect3DMiniwin* miniwind3d = nullptr; assert(m_currentDeviceInfo); if (!MxDirectDraw::Create( @@ -64,6 +70,20 @@ BOOL MxDirect3D::Create( goto done; } + if (m_pDirect3d->QueryInterface(IID_IDirect3DMiniwin, (void**) &miniwind3d) == DD_OK) { + MxVideoParam* videoParam = (MxVideoParam*) SDL_GetPointerProperty( + SDL_GetWindowProperties(reinterpret_cast(hWnd)), + ISLE_PROP_WINDOW_CREATE_VIDEO_PARAM, + nullptr + ); +#ifndef MXDIRECTX_FOR_CONFIG + assert(videoParam); +#endif + if (videoParam) { + miniwind3d->RequestMSAA(videoParam->GetMSAASamples()); + } + } + if (!D3DSetMode()) { goto done; } diff --git a/LEGO1/mxdirectx/mxdirectxinfo.cpp b/LEGO1/mxdirectx/mxdirectxinfo.cpp index 3451b8fc..bbff9534 100644 --- a/LEGO1/mxdirectx/mxdirectxinfo.cpp +++ b/LEGO1/mxdirectx/mxdirectxinfo.cpp @@ -1,7 +1,10 @@ #include "mxdirectxinfo.h" +#include "omni/include/mxvideoparam.h" + #include #include +#include #include // for vsprintf DECOMP_SIZE_ASSERT(MxAssignedDevice, 0xe4) @@ -216,12 +219,28 @@ BOOL MxDeviceEnumerate::EnumDirectDrawCallback(LPGUID p_guid, LPSTR p_driverDesc LPDIRECTDRAW lpDD = NULL; MxDriver& newDevice = m_ddInfo.back(); HRESULT result = DirectDrawCreate(newDevice.m_guid, &lpDD, NULL); + IDirect3DMiniwin* miniwind3d = nullptr; if (result != DD_OK) { BuildErrorString("DirectDraw Create failed: %s\n", EnumerateErrorToString(result)); goto done; } + result = lpDD->QueryInterface(IID_IDirect3DMiniwin, (void**) &miniwind3d); + if (result == DD_OK) { + MxVideoParam* videoParam = (MxVideoParam*) SDL_GetPointerProperty( + SDL_GetWindowProperties(reinterpret_cast(m_hWnd)), + ISLE_PROP_WINDOW_CREATE_VIDEO_PARAM, + nullptr + ); +#ifndef MXDIRECTX_FOR_CONFIG + assert(videoParam); +#endif + if (videoParam) { + miniwind3d->RequestMSAA(videoParam->GetMSAASamples()); + } + } + result = lpDD->SetCooperativeLevel(m_hWnd, DDSCL_NORMAL); if (result != DD_OK) { BuildErrorString("SetCooperativeLevel failed: %s\n", EnumerateErrorToString(result)); diff --git a/LEGO1/omni/include/mxvideoparam.h b/LEGO1/omni/include/mxvideoparam.h index ccc073ab..af2fcddf 100644 --- a/LEGO1/omni/include/mxvideoparam.h +++ b/LEGO1/omni/include/mxvideoparam.h @@ -15,6 +15,8 @@ class MxPalette; +#define ISLE_PROP_WINDOW_CREATE_VIDEO_PARAM "ISLE.window.create.videoParam" + // SIZE 0x24 class MxVideoParam { public: @@ -51,6 +53,9 @@ public: // FUNCTION: BETA10 0x10141fe0 void SetBackBuffers(MxU32 p_backBuffers) { m_backBuffers = p_backBuffers; } + void SetMSAASamples(MxU32 p_msaaSamples) { m_msaaSamples = p_msaaSamples; } + MxU32 GetMSAASamples() { return m_msaaSamples; } + private: MxRect32 m_rect; // 0x00 MxPalette* m_palette; // 0x10 @@ -58,6 +63,7 @@ private: MxVideoParamFlags m_flags; // 0x18 int m_unk0x1c; // 0x1c char* m_deviceId; // 0x20 + MxU32 m_msaaSamples; }; #endif // MXVIDEOPARAM_H diff --git a/LEGO1/omni/src/video/mxvideoparam.cpp b/LEGO1/omni/src/video/mxvideoparam.cpp index 9a095c4e..7c029e52 100644 --- a/LEGO1/omni/src/video/mxvideoparam.cpp +++ b/LEGO1/omni/src/video/mxvideoparam.cpp @@ -28,6 +28,7 @@ MxVideoParam::MxVideoParam(MxRect32& p_rect, MxPalette* p_palette, MxULong p_bac m_flags = p_flags; m_unk0x1c = 0; m_deviceId = NULL; + m_msaaSamples = 0; } // FUNCTION: LEGO1 0x100becf0 @@ -41,6 +42,7 @@ MxVideoParam::MxVideoParam(MxVideoParam& p_videoParam) m_unk0x1c = p_videoParam.m_unk0x1c; m_deviceId = NULL; SetDeviceName(p_videoParam.m_deviceId); + m_msaaSamples = p_videoParam.m_msaaSamples; } // FUNCTION: LEGO1 0x100bed50 @@ -82,6 +84,7 @@ MxVideoParam& MxVideoParam::operator=(const MxVideoParam& p_videoParam) m_flags = p_videoParam.m_flags; m_unk0x1c = p_videoParam.m_unk0x1c; SetDeviceName(p_videoParam.m_deviceId); + m_msaaSamples = p_videoParam.m_msaaSamples; return *this; } diff --git a/miniwin/CMakeLists.txt b/miniwin/CMakeLists.txt index 3fe96ea3..615832cf 100644 --- a/miniwin/CMakeLists.txt +++ b/miniwin/CMakeLists.txt @@ -44,16 +44,16 @@ if(NOT WINDOWS_STORE) message(STATUS "🧩 OpenGL 1.x support not enabled — needs OpenGL") endif() - find_library(OPENGL_ES2_LIBRARY NAMES GLESv2) - if(EMSCRIPTEN OR OPENGL_ES2_LIBRARY) - message(STATUS "Found OpenGL: enabling OpenGL ES 2.x renderer") - target_sources(miniwin PRIVATE src/d3drm/backends/opengles2/renderer.cpp) - list(APPEND GRAPHICS_BACKENDS USE_OPENGLES2) - if(OPENGL_ES2_LIBRARY) - target_link_libraries(miniwin PRIVATE ${OPENGL_ES2_LIBRARY}) + find_library(OPENGL_ES3_LIBRARY NAMES GLESv2) + if(EMSCRIPTEN OR OPENGL_ES3_LIBRARY) + message(STATUS "Found OpenGL: enabling OpenGL ES 3.x renderer") + target_sources(miniwin PRIVATE src/d3drm/backends/opengles3/renderer.cpp) + list(APPEND GRAPHICS_BACKENDS USE_OPENGLES3) + if(OPENGL_ES3_LIBRARY) + target_link_libraries(miniwin PRIVATE ${OPENGL_ES3_LIBRARY}) endif() else() - message(STATUS "🧩 OpenGL ES 2.x support not enabled") + message(STATUS "🧩 OpenGL ES 3.x support not enabled") endif() endif() diff --git a/miniwin/include/miniwin/miniwind3d.h b/miniwin/include/miniwin/miniwind3d.h new file mode 100644 index 00000000..8204af17 --- /dev/null +++ b/miniwin/include/miniwin/miniwind3d.h @@ -0,0 +1,8 @@ +#pragma once + +DEFINE_GUID(IID_IDirect3DMiniwin, 0xf8a97f2d, 0x9b3a, 0x4f1c, 0x9e, 0x8d, 0x6a, 0x5b, 0x4c, 0x3d, 0x2e, 0x1f); + +struct IDirect3DMiniwin : virtual public IUnknown { + virtual HRESULT RequestMSAA(DWORD msaaSamples) = 0; + virtual DWORD GetMSAASamples() const = 0; +}; diff --git a/miniwin/src/d3drm/backends/opengles2/renderer.cpp b/miniwin/src/d3drm/backends/opengles3/renderer.cpp similarity index 76% rename from miniwin/src/d3drm/backends/opengles2/renderer.cpp rename to miniwin/src/d3drm/backends/opengles3/renderer.cpp index e1c86a62..5c3ac1e5 100644 --- a/miniwin/src/d3drm/backends/opengles2/renderer.cpp +++ b/miniwin/src/d3drm/backends/opengles3/renderer.cpp @@ -1,8 +1,8 @@ -#include "d3drmrenderer_opengles2.h" +#include "d3drmrenderer_opengles3.h" #include "meshutils.h" -#include #include +#include #include #include #include @@ -15,20 +15,29 @@ static GLuint CompileShader(GLenum type, const char* source) GLint success; glGetShaderiv(shader, GL_COMPILE_STATUS, &success); if (!success) { + GLint logLength = 0; + glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &logLength); + if (logLength > 0) { + std::vector log(logLength); + glGetShaderInfoLog(shader, logLength, nullptr, log.data()); + SDL_Log("Shader compile error: %s", log.data()); + } + else { + SDL_Log("CompileShader (%s)", SDL_GetError()); + } glDeleteShader(shader); - SDL_Log("CompileShader (%s)", SDL_GetError()); return 0; } return shader; } -struct SceneLightGLES2 { +struct SceneLightGLES3 { float color[4]; float position[4]; float direction[4]; }; -Direct3DRMRenderer* OpenGLES2Renderer::Create(DWORD width, DWORD height) +Direct3DRMRenderer* OpenGLES3Renderer::Create(DWORD width, DWORD height, DWORD msaaSamples) { // We have to reset the attributes here after having enumerated the // OpenGL ES 2.0 renderer, or else SDL gets very confused by SDL_GL_DEPTH_SIZE @@ -37,7 +46,7 @@ Direct3DRMRenderer* OpenGLES2Renderer::Create(DWORD width, DWORD height) // But ResetAttributes resets it to 16. SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); if (!DDWindow) { @@ -61,18 +70,20 @@ Direct3DRMRenderer* OpenGLES2Renderer::Create(DWORD width, DWORD height) glCullFace(GL_BACK); glFrontFace(GL_CW); - const char* vertexShaderSource = R"( - attribute vec3 a_position; - attribute vec3 a_normal; - attribute vec2 a_texCoord; + const char* vertexShaderSource = R"(#version 300 es + precision mediump float; + + in vec3 a_position; + in vec3 a_normal; + in vec2 a_texCoord; uniform mat4 u_modelViewMatrix; uniform mat3 u_normalMatrix; uniform mat4 u_projectionMatrix; - varying vec3 v_viewPos; - varying vec3 v_normal; - varying vec2 v_texCoord; + out vec3 v_viewPos; + out vec3 v_normal; + out vec2 v_texCoord; void main() { vec4 viewPos = u_modelViewMatrix * vec4(a_position, 1.0); @@ -83,7 +94,7 @@ Direct3DRMRenderer* OpenGLES2Renderer::Create(DWORD width, DWORD height) } )"; - const char* fragmentShaderSource = R"( + const char* fragmentShaderSource = R"(#version 300 es precision mediump float; struct SceneLight { @@ -95,22 +106,22 @@ Direct3DRMRenderer* OpenGLES2Renderer::Create(DWORD width, DWORD height) uniform SceneLight u_lights[3]; uniform int u_lightCount; - varying vec3 v_viewPos; - varying vec3 v_normal; - varying vec2 v_texCoord; + in vec3 v_viewPos; + in vec3 v_normal; + in vec2 v_texCoord; uniform float u_shininess; uniform vec4 u_color; - uniform int u_useTexture; + uniform bool u_useTexture; uniform sampler2D u_texture; + out vec4 fragColor; + void main() { vec3 diffuse = vec3(0.0); vec3 specular = vec3(0.0); - for (int i = 0; i < 3; ++i) { - if (i >= u_lightCount) break; - + for (int i = 0; i < u_lightCount; ++i) { vec3 lightColor = u_lights[i].color.rgb; if (u_lights[i].position.w == 0.0 && u_lights[i].direction.w == 0.0) { @@ -134,7 +145,7 @@ Direct3DRMRenderer* OpenGLES2Renderer::Create(DWORD width, DWORD height) // Specular if (u_shininess > 0.0 && u_lights[i].direction.w == 1.0) { - vec3 viewVec = normalize(-v_viewPos); // Assuming camera at origin + vec3 viewVec = normalize(-v_viewPos); vec3 H = normalize(lightVec + viewVec); float dotNH = max(dot(v_normal, H), 0.0); float spec = pow(dotNH, u_shininess); @@ -145,13 +156,13 @@ Direct3DRMRenderer* OpenGLES2Renderer::Create(DWORD width, DWORD height) vec4 finalColor = u_color; finalColor.rgb = clamp(diffuse * u_color.rgb + specular, 0.0, 1.0); - if (u_useTexture != 0) { - vec4 texel = texture2D(u_texture, v_texCoord); + if (u_useTexture) { + vec4 texel = texture(u_texture, v_texCoord); finalColor.rgb = clamp(texel.rgb * finalColor.rgb, 0.0, 1.0); finalColor.a = texel.a; } - gl_FragColor = finalColor; + fragColor = finalColor; } )"; @@ -168,12 +179,12 @@ Direct3DRMRenderer* OpenGLES2Renderer::Create(DWORD width, DWORD height) glDeleteShader(vs); glDeleteShader(fs); - return new OpenGLES2Renderer(width, height, context, shaderProgram); + return new OpenGLES3Renderer(width, height, msaaSamples, context, shaderProgram); } -GLES2MeshCacheEntry GLES2UploadMesh(const MeshGroup& meshGroup, bool forceUV = false) +GLES3MeshCacheEntry OpenGLES3Renderer::GLES3UploadMesh(const MeshGroup& meshGroup, bool forceUV) { - GLES2MeshCacheEntry cache{&meshGroup, meshGroup.version}; + GLES3MeshCacheEntry cache{&meshGroup, meshGroup.version}; cache.flat = meshGroup.quality == D3DRMRENDER_FLAT || meshGroup.quality == D3DRMRENDER_UNLITFLAT; @@ -211,18 +222,27 @@ GLES2MeshCacheEntry GLES2UploadMesh(const MeshGroup& meshGroup, bool forceUV = f std::vector normals(vertices.size()); std::transform(vertices.begin(), vertices.end(), normals.begin(), [](const D3DRMVERTEX& v) { return v.normal; }); + glGenVertexArrays(1, &cache.vao); + glBindVertexArray(cache.vao); + glGenBuffers(1, &cache.vboPositions); glBindBuffer(GL_ARRAY_BUFFER, cache.vboPositions); glBufferData(GL_ARRAY_BUFFER, positions.size() * sizeof(D3DVECTOR), positions.data(), GL_STATIC_DRAW); + glEnableVertexAttribArray(m_posLoc); + glVertexAttribPointer(m_posLoc, 3, GL_FLOAT, GL_FALSE, 0, nullptr); glGenBuffers(1, &cache.vboNormals); glBindBuffer(GL_ARRAY_BUFFER, cache.vboNormals); glBufferData(GL_ARRAY_BUFFER, normals.size() * sizeof(D3DVECTOR), normals.data(), GL_STATIC_DRAW); + glEnableVertexAttribArray(m_normLoc); + glVertexAttribPointer(m_normLoc, 3, GL_FLOAT, GL_FALSE, 0, nullptr); if (meshGroup.texture || forceUV) { glGenBuffers(1, &cache.vboTexcoords); glBindBuffer(GL_ARRAY_BUFFER, cache.vboTexcoords); glBufferData(GL_ARRAY_BUFFER, texcoords.size() * sizeof(TexCoord), texcoords.data(), GL_STATIC_DRAW); + glEnableVertexAttribArray(m_texLoc); + glVertexAttribPointer(m_texLoc, 2, GL_FLOAT, GL_FALSE, 0, nullptr); } glGenBuffers(1, &cache.ibo); @@ -234,6 +254,8 @@ GLES2MeshCacheEntry GLES2UploadMesh(const MeshGroup& meshGroup, bool forceUV = f GL_STATIC_DRAW ); + glBindVertexArray(0); + return cache; } @@ -262,7 +284,7 @@ bool UploadTexture(SDL_Surface* source, GLuint& outTexId, bool isUI) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - if (strstr((const char*) glGetString(GL_EXTENSIONS), "GL_EXT_texture_filter_anisotropic")) { + if (SDL_GL_ExtensionSupported("GL_EXT_texture_filter_anisotropic")) { GLfloat maxAniso = 0.0f; glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &maxAniso); GLfloat desiredAniso = fminf(8.0f, maxAniso); @@ -278,12 +300,35 @@ bool UploadTexture(SDL_Surface* source, GLuint& outTexId, bool isUI) return true; } -OpenGLES2Renderer::OpenGLES2Renderer(DWORD width, DWORD height, SDL_GLContext context, GLuint shaderProgram) - : m_context(context), m_shaderProgram(shaderProgram) +OpenGLES3Renderer::OpenGLES3Renderer( + DWORD width, + DWORD height, + DWORD msaaSamples, + SDL_GLContext context, + GLuint shaderProgram +) + : m_context(context), m_shaderProgram(shaderProgram), m_msaa(msaaSamples) { glGenFramebuffers(1, &m_fbo); glBindFramebuffer(GL_FRAMEBUFFER, m_fbo); + GLint maxSamples; + glGetIntegerv(GL_MAX_SAMPLES, &maxSamples); + if (m_msaa > maxSamples) { + m_msaa = maxSamples; + } + SDL_Log( + "MSAA is %s. Requested samples: %d, active samples: %d, max samples: %d", + m_msaa > 1 ? "on" : "off", + msaaSamples, + m_msaa, + maxSamples + ); + + if (m_msaa > 1) { + glGenFramebuffers(1, &m_resolveFBO); + } + m_virtualWidth = width; m_virtualHeight = height; ViewportTransform viewportTransform = {1.0f, 0.0f, 0.0f}; @@ -310,14 +355,6 @@ OpenGLES2Renderer::OpenGLES2Renderer(DWORD width, DWORD height, SDL_GLContext co } SDL_DestroySurface(dummySurface); - m_uiMesh.vertices = { - {{0.0f, 0.0f, 0.0f}, {0, 0, -1}, {0.0f, 0.0f}}, - {{1.0f, 0.0f, 0.0f}, {0, 0, -1}, {1.0f, 0.0f}}, - {{1.0f, 1.0f, 0.0f}, {0, 0, -1}, {1.0f, 1.0f}}, - {{0.0f, 1.0f, 0.0f}, {0, 0, -1}, {0.0f, 1.0f}} - }; - m_uiMesh.indices = {0, 1, 2, 0, 2, 3}; - m_uiMeshCache = GLES2UploadMesh(m_uiMesh, true); m_posLoc = glGetAttribLocation(m_shaderProgram, "a_position"); m_normLoc = glGetAttribLocation(m_shaderProgram, "a_normal"); m_texLoc = glGetAttribLocation(m_shaderProgram, "a_texCoord"); @@ -336,17 +373,35 @@ OpenGLES2Renderer::OpenGLES2Renderer(DWORD width, DWORD height, SDL_GLContext co m_normalMatrixLoc = glGetUniformLocation(m_shaderProgram, "u_normalMatrix"); m_projectionMatrixLoc = glGetUniformLocation(m_shaderProgram, "u_projectionMatrix"); + m_uiMesh.vertices = { + {{0.0f, 0.0f, 0.0f}, {0, 0, -1}, {0.0f, 0.0f}}, + {{1.0f, 0.0f, 0.0f}, {0, 0, -1}, {1.0f, 0.0f}}, + {{1.0f, 1.0f, 0.0f}, {0, 0, -1}, {1.0f, 1.0f}}, + {{0.0f, 1.0f, 0.0f}, {0, 0, -1}, {0.0f, 1.0f}} + }; + m_uiMesh.indices = {0, 1, 2, 0, 2, 3}; + m_uiMeshCache = GLES3UploadMesh(m_uiMesh, true); + glUseProgram(m_shaderProgram); } -OpenGLES2Renderer::~OpenGLES2Renderer() +OpenGLES3Renderer::~OpenGLES3Renderer() { SDL_DestroySurface(m_renderedImage); + glDeleteTextures(1, &m_dummyTexture); glDeleteProgram(m_shaderProgram); + glDeleteRenderbuffers(1, &m_colorTarget); + glDeleteRenderbuffers(1, &m_depthTarget); + glDeleteFramebuffers(1, &m_fbo); + if (m_msaa > 1) { + glDeleteRenderbuffers(1, &m_resolveColor); + glDeleteFramebuffers(1, &m_resolveFBO); + } + SDL_GL_DestroyContext(m_context); } -void OpenGLES2Renderer::PushLights(const SceneLight* lightsArray, size_t count) +void OpenGLES3Renderer::PushLights(const SceneLight* lightsArray, size_t count) { if (count > 3) { SDL_Log("Unsupported number of lights (%d)", static_cast(count)); @@ -356,21 +411,21 @@ void OpenGLES2Renderer::PushLights(const SceneLight* lightsArray, size_t count) m_lights.assign(lightsArray, lightsArray + count); } -void OpenGLES2Renderer::SetFrustumPlanes(const Plane* frustumPlanes) +void OpenGLES3Renderer::SetFrustumPlanes(const Plane* frustumPlanes) { } -void OpenGLES2Renderer::SetProjection(const D3DRMMATRIX4D& projection, D3DVALUE front, D3DVALUE back) +void OpenGLES3Renderer::SetProjection(const D3DRMMATRIX4D& projection, D3DVALUE front, D3DVALUE back) { memcpy(&m_projection, projection, sizeof(D3DRMMATRIX4D)); } struct TextureDestroyContextGLS2 { - OpenGLES2Renderer* renderer; + OpenGLES3Renderer* renderer; Uint32 textureId; }; -void OpenGLES2Renderer::AddTextureDestroyCallback(Uint32 id, IDirect3DRMTexture* texture) +void OpenGLES3Renderer::AddTextureDestroyCallback(Uint32 id, IDirect3DRMTexture* texture) { auto* ctx = new TextureDestroyContextGLS2{this, id}; texture->AddDestroyCallback( @@ -388,7 +443,7 @@ void OpenGLES2Renderer::AddTextureDestroyCallback(Uint32 id, IDirect3DRMTexture* ); } -Uint32 OpenGLES2Renderer::GetTextureId(IDirect3DRMTexture* iTexture, bool isUI, float scaleX, float scaleY) +Uint32 OpenGLES3Renderer::GetTextureId(IDirect3DRMTexture* iTexture, bool isUI, float scaleX, float scaleY) { SDL_GL_MakeCurrent(DDWindow, m_context); auto texture = static_cast(iTexture); @@ -432,42 +487,43 @@ Uint32 OpenGLES2Renderer::GetTextureId(IDirect3DRMTexture* iTexture, bool isUI, return (Uint32) (m_textures.size() - 1); } -struct GLES2MeshDestroyContext { - OpenGLES2Renderer* renderer; +struct GLES3MeshDestroyContext { + OpenGLES3Renderer* renderer; Uint32 id; }; -void OpenGLES2Renderer::AddMeshDestroyCallback(Uint32 id, IDirect3DRMMesh* mesh) +void OpenGLES3Renderer::AddMeshDestroyCallback(Uint32 id, IDirect3DRMMesh* mesh) { - auto* ctx = new GLES2MeshDestroyContext{this, id}; + auto* ctx = new GLES3MeshDestroyContext{this, id}; mesh->AddDestroyCallback( [](IDirect3DRMObject*, void* arg) { - auto* ctx = static_cast(arg); + auto* ctx = static_cast(arg); auto& cache = ctx->renderer->m_meshs[ctx->id]; cache.meshGroup = nullptr; glDeleteBuffers(1, &cache.vboPositions); glDeleteBuffers(1, &cache.vboNormals); glDeleteBuffers(1, &cache.vboTexcoords); glDeleteBuffers(1, &cache.ibo); + glDeleteVertexArrays(1, &cache.vao); delete ctx; }, ctx ); } -Uint32 OpenGLES2Renderer::GetMeshId(IDirect3DRMMesh* mesh, const MeshGroup* meshGroup) +Uint32 OpenGLES3Renderer::GetMeshId(IDirect3DRMMesh* mesh, const MeshGroup* meshGroup) { for (Uint32 i = 0; i < m_meshs.size(); ++i) { auto& cache = m_meshs[i]; if (cache.meshGroup == meshGroup) { if (cache.version != meshGroup->version) { - cache = std::move(GLES2UploadMesh(*meshGroup)); + cache = std::move(GLES3UploadMesh(*meshGroup)); } return i; } } - auto newCache = GLES2UploadMesh(*meshGroup); + auto newCache = GLES3UploadMesh(*meshGroup); for (Uint32 i = 0; i < m_meshs.size(); ++i) { auto& cache = m_meshs[i]; @@ -483,7 +539,7 @@ Uint32 OpenGLES2Renderer::GetMeshId(IDirect3DRMMesh* mesh, const MeshGroup* mesh return (Uint32) (m_meshs.size() - 1); } -HRESULT OpenGLES2Renderer::BeginFrame() +HRESULT OpenGLES3Renderer::BeginFrame() { SDL_GL_MakeCurrent(DDWindow, m_context); m_dirty = true; @@ -495,7 +551,7 @@ HRESULT OpenGLES2Renderer::BeginFrame() glEnable(GL_DEPTH_TEST); glDepthMask(GL_TRUE); - SceneLightGLES2 lightData[3]; + SceneLightGLES3 lightData[3]; int lightCount = std::min(static_cast(m_lights.size()), 3); for (int i = 0; i < lightCount; ++i) { @@ -525,14 +581,14 @@ HRESULT OpenGLES2Renderer::BeginFrame() return DD_OK; } -void OpenGLES2Renderer::EnableTransparency() +void OpenGLES3Renderer::EnableTransparency() { glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glDepthMask(GL_FALSE); } -void OpenGLES2Renderer::SubmitDraw( +void OpenGLES3Renderer::SubmitDraw( DWORD meshId, const D3DRMMATRIX4D& modelViewMatrix, const D3DRMMATRIX4D& worldMatrix, @@ -570,28 +626,12 @@ void OpenGLES2Renderer::SubmitDraw( glUniform1i(m_textureLoc, 0); } - glBindBuffer(GL_ARRAY_BUFFER, mesh.vboPositions); - glEnableVertexAttribArray(m_posLoc); - glVertexAttribPointer(m_posLoc, 3, GL_FLOAT, GL_FALSE, 0, nullptr); - - glBindBuffer(GL_ARRAY_BUFFER, mesh.vboNormals); - glEnableVertexAttribArray(m_normLoc); - glVertexAttribPointer(m_normLoc, 3, GL_FLOAT, GL_FALSE, 0, nullptr); - - if (appearance.textureId != NO_TEXTURE_ID) { - glBindBuffer(GL_ARRAY_BUFFER, mesh.vboTexcoords); - glEnableVertexAttribArray(m_texLoc); - glVertexAttribPointer(m_texLoc, 2, GL_FLOAT, GL_FALSE, 0, nullptr); - } - - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh.ibo); + glBindVertexArray(mesh.vao); glDrawElements(GL_TRIANGLES, static_cast(mesh.indices.size()), GL_UNSIGNED_SHORT, nullptr); - - glDisableVertexAttribArray(m_normLoc); - glDisableVertexAttribArray(m_texLoc); + glBindVertexArray(0); } -HRESULT OpenGLES2Renderer::FinalizeFrame() +HRESULT OpenGLES3Renderer::FinalizeFrame() { glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); @@ -599,7 +639,7 @@ HRESULT OpenGLES2Renderer::FinalizeFrame() return DD_OK; } -void OpenGLES2Renderer::Resize(int width, int height, const ViewportTransform& viewportTransform) +void OpenGLES3Renderer::Resize(int width, int height, const ViewportTransform& viewportTransform) { SDL_GL_MakeCurrent(DDWindow, m_context); m_width = width; @@ -610,37 +650,65 @@ void OpenGLES2Renderer::Resize(int width, int height, const ViewportTransform& v } m_renderedImage = SDL_CreateSurface(m_width, m_height, SDL_PIXELFORMAT_RGBA32); + if (m_colorTarget) { + glDeleteRenderbuffers(1, &m_colorTarget); + m_colorTarget = 0; + } + if (m_resolveColor) { + glDeleteRenderbuffers(1, &m_resolveColor); + m_resolveColor = 0; + } + if (m_depthTarget) { + glDeleteRenderbuffers(1, &m_depthTarget); + m_depthTarget = 0; + } + glBindFramebuffer(GL_FRAMEBUFFER, m_fbo); // Create color texture - glGenTextures(1, &m_colorTarget); - glBindTexture(GL_TEXTURE_2D, m_colorTarget); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_colorTarget, 0); + glGenRenderbuffers(1, &m_colorTarget); + glBindRenderbuffer(GL_RENDERBUFFER, m_colorTarget); + if (m_msaa > 1) { + glRenderbufferStorageMultisample(GL_RENDERBUFFER, m_msaa, GL_RGBA8, width, height); + } + else { + glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, width, height); + } + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_colorTarget); // Create depth renderbuffer glGenRenderbuffers(1, &m_depthTarget); glBindRenderbuffer(GL_RENDERBUFFER, m_depthTarget); - - if (SDL_GL_ExtensionSupported("GL_OES_depth24")) { - glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24_OES, width, height); - } - else if (SDL_GL_ExtensionSupported("GL_OES_depth32")) { - glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT32_OES, width, height); + if (m_msaa > 1) { + glRenderbufferStorageMultisample(GL_RENDERBUFFER, m_msaa, GL_DEPTH_COMPONENT24, width, height); } else { - glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, width, height); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, width, height); } glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_depthTarget); + GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + if (status != GL_FRAMEBUFFER_COMPLETE) { + SDL_Log("FBO incomplete: 0x%X", status); + } + + if (m_msaa > 1) { + glBindFramebuffer(GL_FRAMEBUFFER, m_resolveFBO); + glGenRenderbuffers(1, &m_resolveColor); + glBindRenderbuffer(GL_RENDERBUFFER, m_resolveColor); + glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, width, height); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_resolveColor); + GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + if (status != GL_FRAMEBUFFER_COMPLETE) { + SDL_Log("Resolve FBO incomplete: 0x%X", status); + } + } + + glBindFramebuffer(GL_FRAMEBUFFER, m_fbo); glViewport(0, 0, m_width, m_height); } -void OpenGLES2Renderer::Clear(float r, float g, float b) +void OpenGLES3Renderer::Clear(float r, float g, float b) { SDL_GL_MakeCurrent(DDWindow, m_context); m_dirty = true; @@ -653,71 +721,22 @@ void OpenGLES2Renderer::Clear(float r, float g, float b) glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } -void OpenGLES2Renderer::Flip() +void OpenGLES3Renderer::Flip() { SDL_GL_MakeCurrent(DDWindow, m_context); if (!m_dirty) { return; } - glBindFramebuffer(GL_FRAMEBUFFER, 0); - - glDisable(GL_DEPTH_TEST); - glFrontFace(GL_CCW); - glDepthMask(GL_FALSE); - - glUniform4f(m_colorLoc, 1.0f, 1.0f, 1.0f, 1.0f); - glUniform1f(m_shinLoc, 0.0f); - - float ambient[] = {1.0f, 1.0f, 1.0f, 1.0f}; - float blank[] = {0.0f, 0.0f, 0.0f, 0.0f}; - glUniform4fv(u_lightLocs[0][0], 1, ambient); - glUniform4fv(u_lightLocs[0][1], 1, blank); - glUniform4fv(u_lightLocs[0][2], 1, blank); - glUniform1i(m_lightCountLoc, 1); - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, m_colorTarget); - glUniform1i(m_textureLoc, 0); - glUniform1i(m_useTextureLoc, 1); - - D3DRMMATRIX4D projection; - D3DRMMATRIX4D modelViewMatrix = { - {(float) m_width, 0.0f, 0.0f, 0.0f}, - {0.0f, (float) -m_height, 0.0f, 0.0f}, - {0.0f, 0.0f, 1.0f, 0.0f}, - {0.0f, (float) m_height, 0.0f, 1.0f} - }; - glUniformMatrix4fv(m_modelViewMatrixLoc, 1, GL_FALSE, &modelViewMatrix[0][0]); - Matrix3x3 identity = {{1.f, 0.f, 0.f}, {0.f, 1.f, 0.f}, {0.f, 0.f, 1.f}}; - glUniformMatrix3fv(m_normalMatrixLoc, 1, GL_FALSE, &identity[0][0]); - CreateOrthographicProjection((float) m_width, (float) m_height, projection); - glUniformMatrix4fv(m_projectionMatrixLoc, 1, GL_FALSE, &projection[0][0]); - - glDisable(GL_SCISSOR_TEST); - - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - glBindBuffer(GL_ARRAY_BUFFER, m_uiMeshCache.vboPositions); - glEnableVertexAttribArray(m_posLoc); - glVertexAttribPointer(m_posLoc, 3, GL_FLOAT, GL_FALSE, 0, nullptr); - - glBindBuffer(GL_ARRAY_BUFFER, m_uiMeshCache.vboTexcoords); - glEnableVertexAttribArray(m_texLoc); - glVertexAttribPointer(m_texLoc, 2, GL_FLOAT, GL_FALSE, 0, nullptr); - - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_uiMeshCache.ibo); - glDrawElements(GL_TRIANGLES, static_cast(m_uiMeshCache.indices.size()), GL_UNSIGNED_SHORT, nullptr); - - glDisableVertexAttribArray(m_texLoc); + glBindFramebuffer(GL_READ_FRAMEBUFFER, m_fbo); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); + glBlitFramebuffer(0, 0, m_width, m_height, 0, 0, m_width, m_height, GL_COLOR_BUFFER_BIT, GL_NEAREST); SDL_GL_SwapWindow(DDWindow); - glFrontFace(GL_CW); m_dirty = false; } -void OpenGLES2Renderer::Draw2DImage(Uint32 textureId, const SDL_Rect& srcRect, const SDL_Rect& dstRect, FColor color) +void OpenGLES3Renderer::Draw2DImage(Uint32 textureId, const SDL_Rect& srcRect, const SDL_Rect& dstRect, FColor color) { SDL_GL_MakeCurrent(DDWindow, m_context); m_dirty = true; @@ -739,7 +758,7 @@ void OpenGLES2Renderer::Draw2DImage(Uint32 textureId, const SDL_Rect& srcRect, c SDL_Rect expandedDstRect; if (textureId != NO_TEXTURE_ID) { - const GLES2TextureCacheEntry& texture = m_textures[textureId]; + const GLES3TextureCacheEntry& texture = m_textures[textureId]; float scaleX = static_cast(dstRect.w) / srcRect.w; float scaleY = static_cast(dstRect.h) / srcRect.h; expandedDstRect = { @@ -790,26 +809,27 @@ void OpenGLES2Renderer::Draw2DImage(Uint32 textureId, const SDL_Rect& srcRect, c static_cast(std::round(dstRect.h * m_viewportTransform.scale)) ); - glBindBuffer(GL_ARRAY_BUFFER, m_uiMeshCache.vboPositions); - glEnableVertexAttribArray(m_posLoc); - glVertexAttribPointer(m_posLoc, 3, GL_FLOAT, GL_FALSE, 0, nullptr); - - glBindBuffer(GL_ARRAY_BUFFER, m_uiMeshCache.vboTexcoords); - glEnableVertexAttribArray(m_texLoc); - glVertexAttribPointer(m_texLoc, 2, GL_FLOAT, GL_FALSE, 0, nullptr); - - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_uiMeshCache.ibo); + glBindVertexArray(m_uiMeshCache.vao); glDrawElements(GL_TRIANGLES, static_cast(m_uiMeshCache.indices.size()), GL_UNSIGNED_SHORT, nullptr); + glBindVertexArray(0); - glDisableVertexAttribArray(m_texLoc); glDisable(GL_SCISSOR_TEST); } -void OpenGLES2Renderer::Download(SDL_Surface* target) +void OpenGLES3Renderer::Download(SDL_Surface* target) { glFinish(); - glBindFramebuffer(GL_FRAMEBUFFER, m_fbo); + if (m_msaa > 1) { + glBindFramebuffer(GL_READ_FRAMEBUFFER, m_fbo); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_resolveFBO); + glBlitFramebuffer(0, 0, m_width, m_height, 0, 0, m_width, m_height, GL_COLOR_BUFFER_BIT, GL_NEAREST); + glBindFramebuffer(GL_FRAMEBUFFER, m_resolveFBO); + } + else { + glBindFramebuffer(GL_FRAMEBUFFER, m_fbo); + } + glReadPixels(0, 0, m_width, m_height, GL_RGBA, GL_UNSIGNED_BYTE, m_renderedImage->pixels); SDL_Rect srcRect = { @@ -839,7 +859,7 @@ void OpenGLES2Renderer::Download(SDL_Surface* target) SDL_DestroySurface(bufferClone); } -void OpenGLES2Renderer::SetDither(bool dither) +void OpenGLES3Renderer::SetDither(bool dither) { if (dither) { glEnable(GL_DITHER); diff --git a/miniwin/src/d3drm/d3drm.cpp b/miniwin/src/d3drm/d3drm.cpp index 7328d21c..3b4d5c9d 100644 --- a/miniwin/src/d3drm/d3drm.cpp +++ b/miniwin/src/d3drm/d3drm.cpp @@ -132,7 +132,11 @@ HRESULT Direct3DRMImpl::CreateDeviceFromSurface( DDSDesc.dwSize = sizeof(DDSURFACEDESC); surface->GetSurfaceDesc(&DDSDesc); - DDRenderer = CreateDirect3DRMRenderer(DDSDesc, guid); + IDirect3DMiniwin* miniwind3d = nullptr; + dd->QueryInterface(IID_IDirect3DMiniwin, (void**) &miniwind3d); + SDL_assert(miniwind3d); + + DDRenderer = CreateDirect3DRMRenderer(miniwind3d, DDSDesc, guid); if (!DDRenderer) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Device GUID not recognized"); return E_NOINTERFACE; diff --git a/miniwin/src/d3drm/d3drmrenderer.cpp b/miniwin/src/d3drm/d3drmrenderer.cpp index ca9b5541..913e55de 100644 --- a/miniwin/src/d3drm/d3drmrenderer.cpp +++ b/miniwin/src/d3drm/d3drmrenderer.cpp @@ -2,8 +2,8 @@ #ifdef USE_OPENGL1 #include "d3drmrenderer_opengl1.h" #endif -#ifdef USE_OPENGLES2 -#include "d3drmrenderer_opengles2.h" +#ifdef USE_OPENGLES3 +#include "d3drmrenderer_opengles3.h" #endif #ifdef USE_CITRO3D #include "d3drmrenderer_citro3d.h" @@ -18,7 +18,11 @@ #include "d3drmrenderer_software.h" #endif -Direct3DRMRenderer* CreateDirect3DRMRenderer(const DDSURFACEDESC& DDSDesc, const GUID* guid) +Direct3DRMRenderer* CreateDirect3DRMRenderer( + const IDirect3DMiniwin* d3d, + const DDSURFACEDESC& DDSDesc, + const GUID* guid +) { #ifdef USE_SDL_GPU if (SDL_memcmp(guid, &SDL3_GPU_GUID, sizeof(GUID)) == 0) { @@ -30,9 +34,9 @@ Direct3DRMRenderer* CreateDirect3DRMRenderer(const DDSURFACEDESC& DDSDesc, const return new Direct3DRMSoftwareRenderer(DDSDesc.dwWidth, DDSDesc.dwHeight); } #endif -#ifdef USE_OPENGLES2 - if (SDL_memcmp(guid, &OpenGLES2_GUID, sizeof(GUID)) == 0) { - return OpenGLES2Renderer::Create(DDSDesc.dwWidth, DDSDesc.dwHeight); +#ifdef USE_OPENGLES3 + if (SDL_memcmp(guid, &OpenGLES3_GUID, sizeof(GUID)) == 0) { + return OpenGLES3Renderer::Create(DDSDesc.dwWidth, DDSDesc.dwHeight, d3d->GetMSAASamples()); } #endif #ifdef USE_OPENGL1 @@ -53,13 +57,13 @@ Direct3DRMRenderer* CreateDirect3DRMRenderer(const DDSURFACEDESC& DDSDesc, const return nullptr; } -void Direct3DRMRenderer_EnumDevices(LPD3DENUMDEVICESCALLBACK cb, void* ctx) +void Direct3DRMRenderer_EnumDevices(const IDirect3DMiniwin* d3d, LPD3DENUMDEVICESCALLBACK cb, void* ctx) { #ifdef USE_SDL_GPU Direct3DRMSDL3GPU_EnumDevice(cb, ctx); #endif -#ifdef USE_OPENGLES2 - OpenGLES2Renderer_EnumDevice(cb, ctx); +#ifdef USE_OPENGLES3 + OpenGLES3Renderer_EnumDevice(d3d, cb, ctx); #endif #ifdef USE_OPENGL1 OpenGL1Renderer_EnumDevice(cb, ctx); diff --git a/miniwin/src/ddraw/ddraw.cpp b/miniwin/src/ddraw/ddraw.cpp index 264ceeb1..bb0e40ce 100644 --- a/miniwin/src/ddraw/ddraw.cpp +++ b/miniwin/src/ddraw/ddraw.cpp @@ -29,6 +29,11 @@ HRESULT DirectDrawImpl::QueryInterface(const GUID& riid, void** ppvObject) *ppvObject = static_cast(this); return S_OK; } + if (SDL_memcmp(&riid, &IID_IDirect3DMiniwin, sizeof(GUID)) == 0) { + this->IUnknown::AddRef(); + *ppvObject = static_cast(this); + return S_OK; + } MINIWIN_NOT_IMPLEMENTED(); return E_NOINTERFACE; } @@ -220,7 +225,7 @@ void EnumDevice( HRESULT DirectDrawImpl::EnumDevices(LPD3DENUMDEVICESCALLBACK cb, void* ctx) { - Direct3DRMRenderer_EnumDevices(cb, ctx); + Direct3DRMRenderer_EnumDevices(this, cb, ctx); return S_OK; } @@ -317,7 +322,7 @@ HRESULT DirectDrawImpl::CreateDevice( DDSDesc.dwSize = sizeof(DDSURFACEDESC); pBackBuffer->GetSurfaceDesc(&DDSDesc); - DDRenderer = CreateDirect3DRMRenderer(DDSDesc, &guid); + DDRenderer = CreateDirect3DRMRenderer(this, DDSDesc, &guid); if (!DDRenderer) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Device GUID not recognized"); return E_NOINTERFACE; @@ -326,6 +331,17 @@ HRESULT DirectDrawImpl::CreateDevice( return DD_OK; } +HRESULT DirectDrawImpl::RequestMSAA(DWORD msaaSamples) +{ + m_msaaSamples = msaaSamples; + return DD_OK; +} + +DWORD DirectDrawImpl::GetMSAASamples() const +{ + return m_msaaSamples; +} + HRESULT DirectDrawEnumerate(LPDDENUMCALLBACKA cb, void* context) { const char* driverName = SDL_GetCurrentVideoDriver(); diff --git a/miniwin/src/internal/d3drmrenderer.h b/miniwin/src/internal/d3drmrenderer.h index 85b2d1b9..7c19a8b4 100644 --- a/miniwin/src/internal/d3drmrenderer.h +++ b/miniwin/src/internal/d3drmrenderer.h @@ -3,6 +3,7 @@ #include "d3drmmesh_impl.h" #include "mathutils.h" #include "miniwin/d3drm.h" +#include "miniwin/miniwind3d.h" #include "miniwin/miniwindevice.h" #include "structs.h" @@ -61,5 +62,9 @@ protected: ViewportTransform m_viewportTransform; }; -Direct3DRMRenderer* CreateDirect3DRMRenderer(const DDSURFACEDESC& DDSDesc, const GUID* guid); -void Direct3DRMRenderer_EnumDevices(LPD3DENUMDEVICESCALLBACK cb, void* ctx); +Direct3DRMRenderer* CreateDirect3DRMRenderer( + const IDirect3DMiniwin* d3d, + const DDSURFACEDESC& DDSDesc, + const GUID* guid +); +void Direct3DRMRenderer_EnumDevices(const IDirect3DMiniwin* d3d, LPD3DENUMDEVICESCALLBACK cb, void* ctx); diff --git a/miniwin/src/internal/d3drmrenderer_opengles2.h b/miniwin/src/internal/d3drmrenderer_opengles3.h similarity index 71% rename from miniwin/src/internal/d3drmrenderer_opengles2.h rename to miniwin/src/internal/d3drmrenderer_opengles3.h index d4985f32..1e029cd8 100644 --- a/miniwin/src/internal/d3drmrenderer_opengles2.h +++ b/miniwin/src/internal/d3drmrenderer_opengles3.h @@ -4,13 +4,13 @@ #include "d3drmtexture_impl.h" #include "ddraw_impl.h" -#include +#include #include #include -DEFINE_GUID(OpenGLES2_GUID, 0x682656F3, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04); +DEFINE_GUID(OpenGLES3_GUID, 0x682656F3, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04); -struct GLES2TextureCacheEntry { +struct GLES3TextureCacheEntry { IDirect3DRMTexture* texture; Uint32 version; GLuint glTextureId; @@ -18,7 +18,7 @@ struct GLES2TextureCacheEntry { uint16_t height; }; -struct GLES2MeshCacheEntry { +struct GLES3MeshCacheEntry { const MeshGroup* meshGroup; int version; bool flat; @@ -28,13 +28,14 @@ struct GLES2MeshCacheEntry { GLuint vboNormals; GLuint vboTexcoords; GLuint ibo; + GLuint vao; }; -class OpenGLES2Renderer : public Direct3DRMRenderer { +class OpenGLES3Renderer : public Direct3DRMRenderer { public: - static Direct3DRMRenderer* Create(DWORD width, DWORD height); - OpenGLES2Renderer(DWORD width, DWORD height, SDL_GLContext context, GLuint shaderProgram); - ~OpenGLES2Renderer() override; + static Direct3DRMRenderer* Create(DWORD width, DWORD height, DWORD msaaSamples); + OpenGLES3Renderer(DWORD width, DWORD height, DWORD msaaSamples, SDL_GLContext context, GLuint shaderProgram); + ~OpenGLES3Renderer() override; void PushLights(const SceneLight* lightsArray, size_t count) override; void SetProjection(const D3DRMMATRIX4D& projection, D3DVALUE front, D3DVALUE back) override; @@ -62,18 +63,22 @@ public: private: void AddTextureDestroyCallback(Uint32 id, IDirect3DRMTexture* texture); void AddMeshDestroyCallback(Uint32 id, IDirect3DRMMesh* mesh); + GLES3MeshCacheEntry GLES3UploadMesh(const MeshGroup& meshGroup, bool forceUV = false); MeshGroup m_uiMesh; - GLES2MeshCacheEntry m_uiMeshCache; - std::vector m_textures; - std::vector m_meshs; + GLES3MeshCacheEntry m_uiMeshCache; + std::vector m_textures; + std::vector m_meshs; D3DRMMATRIX4D m_projection; SDL_Surface* m_renderedImage = nullptr; bool m_dirty = false; std::vector m_lights; SDL_GLContext m_context; + uint32_t m_msaa; GLuint m_fbo; + GLuint m_resolveFBO; GLuint m_colorTarget; + GLuint m_resolveColor = 0; GLuint m_depthTarget; GLuint m_shaderProgram; GLuint m_dummyTexture; @@ -92,35 +97,25 @@ private: ViewportTransform m_viewportTransform; }; -inline static void OpenGLES2Renderer_EnumDevice(LPD3DENUMDEVICESCALLBACK cb, void* ctx) +inline static void OpenGLES3Renderer_EnumDevice(const IDirect3DMiniwin* d3d, LPD3DENUMDEVICESCALLBACK cb, void* ctx) { - Direct3DRMRenderer* device = OpenGLES2Renderer::Create(640, 480); + Direct3DRMRenderer* device = OpenGLES3Renderer::Create(640, 480, d3d->GetMSAASamples()); if (!device) { return; } + delete device; + D3DDEVICEDESC halDesc = {}; halDesc.dcmColorModel = D3DCOLOR_RGB; halDesc.dwFlags = D3DDD_DEVICEZBUFFERBITDEPTH; - halDesc.dwDeviceZBufferBitDepth = DDBD_16; + halDesc.dwDeviceZBufferBitDepth = DDBD_24; halDesc.dwDeviceRenderBitDepth = DDBD_32; halDesc.dpcTriCaps.dwTextureCaps = D3DPTEXTURECAPS_PERSPECTIVE; halDesc.dpcTriCaps.dwShadeCaps = D3DPSHADECAPS_ALPHAFLATBLEND; halDesc.dpcTriCaps.dwTextureFilterCaps = D3DPTFILTERCAPS_LINEAR; - const char* extensions = (const char*) glGetString(GL_EXTENSIONS); - if (extensions) { - if (strstr(extensions, "GL_OES_depth24")) { - halDesc.dwDeviceZBufferBitDepth |= DDBD_24; - } - if (strstr(extensions, "GL_OES_depth32")) { - halDesc.dwDeviceZBufferBitDepth |= DDBD_32; - } - } - - delete device; - D3DDEVICEDESC helDesc = {}; - EnumDevice(cb, ctx, "OpenGL ES 2.0 HAL", &halDesc, &helDesc, OpenGLES2_GUID); + EnumDevice(cb, ctx, "OpenGL ES 3.0 HAL", &halDesc, &helDesc, OpenGLES3_GUID); } diff --git a/miniwin/src/internal/ddraw_impl.h b/miniwin/src/internal/ddraw_impl.h index 4adfb4a5..ac4e01a9 100644 --- a/miniwin/src/internal/ddraw_impl.h +++ b/miniwin/src/internal/ddraw_impl.h @@ -4,6 +4,7 @@ #include "framebuffer_impl.h" #include "miniwin/d3d.h" #include "miniwin/ddraw.h" +#include "miniwin/miniwind3d.h" #include @@ -15,7 +16,7 @@ inline static SDL_Rect ConvertRect(const RECT* r) return {r->left, r->top, r->right - r->left, r->bottom - r->top}; } -struct DirectDrawImpl : public IDirectDraw2, public IDirect3D2 { +struct DirectDrawImpl : public IDirectDraw2, public IDirect3D2, public IDirect3DMiniwin { // IUnknown interface HRESULT QueryInterface(const GUID& riid, void** ppvObject) override; // IDirectDraw interface @@ -45,11 +46,15 @@ struct DirectDrawImpl : public IDirectDraw2, public IDirect3D2 { HRESULT CreateDevice(const GUID& guid, IDirectDrawSurface* pBackBuffer, IDirect3DDevice2** ppDirect3DDevice) override; HRESULT EnumDevices(LPD3DENUMDEVICESCALLBACK cb, void* ctx) override; + // IDirect3DMiniwin interface + HRESULT RequestMSAA(DWORD msaaSamples) override; + DWORD GetMSAASamples() const override; private: FrameBufferImpl* m_frameBuffer; int m_virtualWidth = 0; int m_virtualHeight = 0; + DWORD m_msaaSamples = 0; }; HRESULT DirectDrawEnumerate(LPDDENUMCALLBACKA cb, void* context);