From 7b06ee5ae610d94bbe51b32b9e5427394f65e22d Mon Sep 17 00:00:00 2001 From: Anders Jenbo Date: Wed, 2 Jul 2025 00:45:25 +0200 Subject: [PATCH] Add support for POT-only GPUs, fix VBO (#468) --- miniwin/src/d3drm/backends/opengl1/actual.cpp | 39 +++++---- miniwin/src/d3drm/backends/opengl1/actual.h | 6 +- .../src/d3drm/backends/opengl1/renderer.cpp | 86 +++++++++++++++---- .../src/d3drm/backends/opengles2/renderer.cpp | 1 + miniwin/src/internal/d3drmrenderer_opengl1.h | 1 + 5 files changed, 96 insertions(+), 37 deletions(-) diff --git a/miniwin/src/d3drm/backends/opengl1/actual.cpp b/miniwin/src/d3drm/backends/opengl1/actual.cpp index e1c56636..e809f7e5 100644 --- a/miniwin/src/d3drm/backends/opengl1/actual.cpp +++ b/miniwin/src/d3drm/backends/opengl1/actual.cpp @@ -42,12 +42,26 @@ void GL11_DestroyTexture(GLuint texId) glDeleteTextures(1, &texId); } -GLuint GL11_UploadTextureData(void* pixels, int width, int height) +GLuint GL11_UploadTextureData(void* pixels, int width, int height, bool isUi) { GLuint texId; glGenTextures(1, &texId); glBindTexture(GL_TEXTURE_2D, texId); + if (isUi) { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + } + else { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + } + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); + return texId; } @@ -111,7 +125,6 @@ void GL11_BeginFrame(const Matrix4x4* projection) glDepthMask(GL_TRUE); glEnable(GL_LIGHTING); glEnable(GL_COLOR_MATERIAL); - glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE); // Disable all lights and reset global ambient for (int i = 0; i < 8; ++i) { @@ -198,6 +211,7 @@ void GL11_SubmitDraw( glLoadMatrixf(&modelViewMatrix[0][0]); glEnable(GL_NORMALIZE); + glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE); glColor4ub(appearance.color.r, appearance.color.g, appearance.color.b, appearance.color.a); if (appearance.shininess != 0.0f) { @@ -220,8 +234,6 @@ void GL11_SubmitDraw( // Bind texture if present if (appearance.textureId != NO_TEXTURE_ID) { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, texId); glEnableClientState(GL_TEXTURE_COORD_ARRAY); @@ -279,7 +291,7 @@ void GL11_Clear(float r, float g, float b) } void GL11_Draw2DImage( - GLuint texId, + GLTextureCacheEntry& cache, const SDL_Rect& srcRect, const SDL_Rect& dstRect, float left, @@ -305,24 +317,17 @@ void GL11_Draw2DImage( glColor4f(1.0f, 1.0f, 1.0f, 1.0f); glEnable(GL_TEXTURE_2D); - glBindTexture(GL_TEXTURE_2D, texId); + glBindTexture(GL_TEXTURE_2D, cache.glTextureId); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - GLint boundTexture = 0; glGetIntegerv(GL_TEXTURE_BINDING_2D, &boundTexture); - GLfloat texW, texH; - glGetTexLevelParameterfv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &texW); - glGetTexLevelParameterfv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &texH); - - float u1 = srcRect.x / texW; - float v1 = srcRect.y / texH; - float u2 = (srcRect.x + srcRect.w) / texW; - float v2 = (srcRect.y + srcRect.h) / texH; + float u1 = srcRect.x / cache.width; + float v1 = srcRect.y / cache.height; + float u2 = (srcRect.x + srcRect.w) / cache.width; + float v2 = (srcRect.y + srcRect.h) / cache.height; float x1 = (float) dstRect.x; float y1 = (float) dstRect.y; diff --git a/miniwin/src/d3drm/backends/opengl1/actual.h b/miniwin/src/d3drm/backends/opengl1/actual.h index 8a4fb8e8..1d5e407d 100644 --- a/miniwin/src/d3drm/backends/opengl1/actual.h +++ b/miniwin/src/d3drm/backends/opengl1/actual.h @@ -39,6 +39,8 @@ struct GLTextureCacheEntry { IDirect3DRMTexture* texture; Uint32 version; GLuint glTextureId; + float width; + float height; }; struct GLMeshCacheEntry { @@ -62,7 +64,7 @@ struct GLMeshCacheEntry { void GL11_InitState(); void GL11_LoadExtensions(); void GL11_DestroyTexture(GLuint texId); -GLuint GL11_UploadTextureData(void* pixels, int width, int height); +GLuint GL11_UploadTextureData(void* pixels, int width, int height, bool isUI); void GL11_UploadMesh(GLMeshCacheEntry& cache, bool hasTexture); void GL11_DestroyMesh(GLMeshCacheEntry& cache); void GL11_BeginFrame(const Matrix4x4* projection); @@ -77,7 +79,7 @@ void GL11_SubmitDraw( void GL11_Resize(int width, int height); void GL11_Clear(float r, float g, float b); void GL11_Draw2DImage( - GLuint texId, + GLTextureCacheEntry& cache, const SDL_Rect& srcRect, const SDL_Rect& dstRect, float left, diff --git a/miniwin/src/d3drm/backends/opengl1/renderer.cpp b/miniwin/src/d3drm/backends/opengl1/renderer.cpp index fb7fccd4..2e18b38a 100644 --- a/miniwin/src/d3drm/backends/opengl1/renderer.cpp +++ b/miniwin/src/d3drm/backends/opengl1/renderer.cpp @@ -58,6 +58,8 @@ OpenGL1Renderer::OpenGL1Renderer(DWORD width, DWORD height, SDL_GLContext contex m_virtualHeight = height; m_renderedImage = SDL_CreateSurface(m_width, m_height, SDL_PIXELFORMAT_RGBA32); GL11_LoadExtensions(); + m_useVBOs = SDL_GL_ExtensionSupported("GL_ARB_vertex_buffer_object"); + m_useNPOT = SDL_GL_ExtensionSupported("GL_OES_texture_npot"); } OpenGL1Renderer::~OpenGL1Renderer() @@ -108,6 +110,58 @@ void OpenGL1Renderer::AddTextureDestroyCallback(Uint32 id, IDirect3DRMTexture* t ); } +static int NextPowerOfTwo(int v) +{ + int power = 1; + while (power < v) { + power <<= 1; + } + return power; +} + +static Uint32 UploadTextureData(SDL_Surface* src, bool useNPOT, bool isUi) +{ + SDL_Surface* working = src; + if (src->format != SDL_PIXELFORMAT_RGBA32) { + working = SDL_ConvertSurface(src, SDL_PIXELFORMAT_RGBA32); + if (!working) { + SDL_Log("SDL_ConvertSurface failed: %s", SDL_GetError()); + return NO_TEXTURE_ID; + } + } + + SDL_Surface* finalSurface = working; + + int newW = NextPowerOfTwo(working->w); + int newH = NextPowerOfTwo(working->h); + + if (!useNPOT && (newW != working->w || newH != working->h)) { + SDL_Surface* resized = SDL_CreateSurface(newW, newH, working->format); + if (!resized) { + SDL_Log("SDL_CreateSurface (resize) failed: %s", SDL_GetError()); + if (working != src) { + SDL_DestroySurface(working); + } + return NO_TEXTURE_ID; + } + + SDL_Rect srcRect = {0, 0, working->w, working->h}; + SDL_Rect dstRect = {0, 0, newW, newH}; + SDL_BlitSurfaceScaled(working, &srcRect, resized, &dstRect, SDL_SCALEMODE_NEAREST); + + if (working != src) { + SDL_DestroySurface(working); + } + finalSurface = resized; + } + + Uint32 texId = GL11_UploadTextureData(finalSurface->pixels, finalSurface->w, finalSurface->h, isUi); + if (finalSurface != src) { + SDL_DestroySurface(finalSurface); + } + return texId; +} + Uint32 OpenGL1Renderer::GetTextureId(IDirect3DRMTexture* iTexture, bool isUi) { auto texture = static_cast(iTexture); @@ -118,28 +172,16 @@ Uint32 OpenGL1Renderer::GetTextureId(IDirect3DRMTexture* iTexture, bool isUi) if (tex.texture == texture) { if (tex.version != texture->m_version) { GL11_DestroyTexture(tex.glTextureId); - - SDL_Surface* surf = SDL_ConvertSurface(surface->m_surface, SDL_PIXELFORMAT_RGBA32); - if (!surf) { - return NO_TEXTURE_ID; - } - tex.glTextureId = GL11_UploadTextureData(surf->pixels, surf->w, surf->h); - SDL_DestroySurface(surf); - + tex.glTextureId = UploadTextureData(surface->m_surface, m_useNPOT, isUi); tex.version = texture->m_version; + tex.width = surface->m_surface->w; + tex.height = surface->m_surface->h; } return i; } } - GLuint texId; - - SDL_Surface* surf = SDL_ConvertSurface(surface->m_surface, SDL_PIXELFORMAT_RGBA32); - if (!surf) { - return NO_TEXTURE_ID; - } - texId = GL11_UploadTextureData(surf->pixels, surf->w, surf->h); - SDL_DestroySurface(surf); + GLuint texId = UploadTextureData(surface->m_surface, m_useNPOT, isUi); for (Uint32 i = 0; i < m_textures.size(); ++i) { auto& tex = m_textures[i]; @@ -147,12 +189,20 @@ Uint32 OpenGL1Renderer::GetTextureId(IDirect3DRMTexture* iTexture, bool isUi) tex.texture = texture; tex.version = texture->m_version; tex.glTextureId = texId; + tex.width = surface->m_surface->w; + tex.height = surface->m_surface->h; AddTextureDestroyCallback(i, texture); return i; } } - m_textures.push_back({texture, texture->m_version, texId}); + m_textures.push_back( + {texture, + texture->m_version, + texId, + static_cast(surface->m_surface->w), + static_cast(surface->m_surface->h)} + ); AddTextureDestroyCallback((Uint32) (m_textures.size() - 1), texture); return (Uint32) (m_textures.size() - 1); } @@ -331,7 +381,7 @@ void OpenGL1Renderer::Draw2DImage(Uint32 textureId, const SDL_Rect& srcRect, con float top = -m_viewportTransform.offsetY / m_viewportTransform.scale; float bottom = (m_height - m_viewportTransform.offsetY) / m_viewportTransform.scale; - GL11_Draw2DImage(m_textures[textureId].glTextureId, srcRect, dstRect, left, right, bottom, top); + GL11_Draw2DImage(m_textures[textureId], srcRect, dstRect, left, right, bottom, top); } void OpenGL1Renderer::Download(SDL_Surface* target) diff --git a/miniwin/src/d3drm/backends/opengles2/renderer.cpp b/miniwin/src/d3drm/backends/opengles2/renderer.cpp index 6695da81..9cb8455c 100644 --- a/miniwin/src/d3drm/backends/opengles2/renderer.cpp +++ b/miniwin/src/d3drm/backends/opengles2/renderer.cpp @@ -47,6 +47,7 @@ Direct3DRMRenderer* OpenGLES2Renderer::Create(DWORD width, DWORD height) SDL_GLContext context = SDL_GL_CreateContext(DDWindow); if (!context) { + SDL_Log("SDL_GL_CreateContext: %s", SDL_GetError()); return nullptr; } diff --git a/miniwin/src/internal/d3drmrenderer_opengl1.h b/miniwin/src/internal/d3drmrenderer_opengl1.h index 58406709..dce25e6b 100644 --- a/miniwin/src/internal/d3drmrenderer_opengl1.h +++ b/miniwin/src/internal/d3drmrenderer_opengl1.h @@ -46,6 +46,7 @@ class OpenGL1Renderer : public Direct3DRMRenderer { D3DRMMATRIX4D m_projection; SDL_Surface* m_renderedImage; bool m_useVBOs; + bool m_useNPOT; bool m_dirty = false; std::vector m_lights; SDL_GLContext m_context;