This commit is contained in:
Anders Jenbo 2025-06-06 02:32:04 +02:00
parent 5be9b09b40
commit 9ef35c3dc5
2 changed files with 73 additions and 29 deletions

View File

@ -6,12 +6,13 @@
#include <GL/glew.h> #include <GL/glew.h>
#include <cstring> #include <cstring>
#include <vector> #include <vector>
Direct3DRMRenderer* OpenGL15Renderer::Create(DWORD width, DWORD height) Direct3DRMRenderer* OpenGL15Renderer::Create(DWORD width, DWORD height)
{ {
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 1); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 1);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 5); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 5);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY); SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY);
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 8);
SDL_Window* window = DDWindow; SDL_Window* window = DDWindow;
bool testWindow = false; bool testWindow = false;
@ -37,55 +38,82 @@ Direct3DRMRenderer* OpenGL15Renderer::Create(DWORD width, DWORD height)
return nullptr; return nullptr;
} }
if (!GLEW_EXT_framebuffer_object) {
SDL_Log("FBOs are not supported (missing GL_EXT_framebuffer_object)");
return nullptr;
}
if (!GLEW_EXT_framebuffer_multisample || !GLEW_EXT_framebuffer_blit) {
SDL_Log("MSAA not supported (missing GL_EXT_framebuffer_multisample or GL_EXT_framebuffer_blit)");
return nullptr;
}
glEnable(GL_CULL_FACE); glEnable(GL_CULL_FACE);
glCullFace(GL_BACK); glCullFace(GL_BACK);
glFrontFace(GL_CCW); glFrontFace(GL_CCW);
glEnable(GL_DEPTH_TEST); glEnable(GL_DEPTH_TEST);
glEnable(GL_LIGHTING); glEnable(GL_LIGHTING);
glEnable(GL_COLOR_MATERIAL); glEnable(GL_COLOR_MATERIAL);
glEnable(GL_MULTISAMPLE);
// Setup FBO // Create color texture for resolved FBO
GLuint fbo;
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
// Create color texture
GLuint colorTex; GLuint colorTex;
glGenTextures(1, &colorTex); glGenTextures(1, &colorTex);
glBindTexture(GL_TEXTURE_2D, colorTex); glBindTexture(GL_TEXTURE_2D, colorTex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorTex, 0);
// Create depth renderbuffer // Create multisample renderbuffers
GLuint depthRb; GLuint msaaColorRb, msaaDepthRb;
glGenRenderbuffers(1, &depthRb); glGenRenderbuffers(1, &msaaColorRb);
glBindRenderbuffer(GL_RENDERBUFFER, depthRb); glBindRenderbuffer(GL_RENDERBUFFER, msaaColorRb);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, width, height); glRenderbufferStorageMultisample(GL_RENDERBUFFER, 8, GL_RGBA8, width, height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthRb);
glGenRenderbuffers(1, &msaaDepthRb);
glBindRenderbuffer(GL_RENDERBUFFER, msaaDepthRb);
glRenderbufferStorageMultisample(GL_RENDERBUFFER, 8, GL_DEPTH_COMPONENT24, width, height);
// Create FBO for resolved (non-MSAA) rendering target
GLuint fbo;
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorTex, 0);
// No depth buffer needed here for resolve FBO
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
if (testWindow) {
SDL_DestroyWindow(window);
}
return nullptr; return nullptr;
} }
// Create MSAA FBO for actual rendering
GLuint msaaFBO;
glGenFramebuffers(1, &msaaFBO);
glBindFramebuffer(GL_FRAMEBUFFER, msaaFBO);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, msaaColorRb);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, msaaDepthRb);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
if (testWindow) {
SDL_DestroyWindow(window);
}
return nullptr;
}
// Unbind FBO
glBindFramebuffer(GL_FRAMEBUFFER, 0); glBindFramebuffer(GL_FRAMEBUFFER, 0);
if (testWindow) { if (testWindow) {
SDL_DestroyWindow(window); SDL_DestroyWindow(window);
} }
return new OpenGL15Renderer(width, height, context, fbo, colorTex, depthRb); return new OpenGL15Renderer(width, height, context, fbo, msaaFBO);
} }
OpenGL15Renderer::OpenGL15Renderer( OpenGL15Renderer::OpenGL15Renderer(int width, int height, SDL_GLContext context, GLuint fbo, GLuint msaaFBO)
int width, : m_width(width), m_height(height), m_context(context), m_fbo(fbo), m_msaaFBO(msaaFBO)
int height,
SDL_GLContext context,
GLuint fbo,
GLuint colorTex,
GLuint depthRb
)
: m_width(width), m_height(height), m_context(context), m_fbo(fbo), m_colorTex(colorTex), m_depthRb(depthRb)
{ {
m_renderedImage = SDL_CreateSurface(m_width, m_height, SDL_PIXELFORMAT_ABGR8888); m_renderedImage = SDL_CreateSurface(m_width, m_height, SDL_PIXELFORMAT_ABGR8888);
} }
@ -95,6 +123,14 @@ OpenGL15Renderer::~OpenGL15Renderer()
if (m_renderedImage) { if (m_renderedImage) {
SDL_DestroySurface(m_renderedImage); SDL_DestroySurface(m_renderedImage);
} }
if (m_fbo) {
glDeleteFramebuffers(1, &m_fbo);
}
if (m_msaaFBO) {
glDeleteFramebuffers(1, &m_msaaFBO);
}
// You may also want to delete textures and renderbuffers similarly if you keep references to them.
} }
void OpenGL15Renderer::PushLights(const SceneLight* lightsArray, size_t count) void OpenGL15Renderer::PushLights(const SceneLight* lightsArray, size_t count)
@ -227,7 +263,7 @@ HRESULT OpenGL15Renderer::BeginFrame(const D3DRMMATRIX4D& viewMatrix)
memcpy(m_viewMatrix, viewMatrix, sizeof(D3DRMMATRIX4D)); memcpy(m_viewMatrix, viewMatrix, sizeof(D3DRMMATRIX4D));
SDL_GL_MakeCurrent(DDWindow, m_context); SDL_GL_MakeCurrent(DDWindow, m_context);
glBindFramebuffer(GL_FRAMEBUFFER, m_fbo); glBindFramebuffer(GL_FRAMEBUFFER, m_msaaFBO);
glViewport(0, 0, m_width, m_height); glViewport(0, 0, m_width, m_height);
glEnable(GL_BLEND); glEnable(GL_BLEND);
@ -365,10 +401,19 @@ void OpenGL15Renderer::SubmitDraw(
HRESULT OpenGL15Renderer::FinalizeFrame() HRESULT OpenGL15Renderer::FinalizeFrame()
{ {
// Resolve multisampled FBO into resolved FBO (texture)
glBindFramebuffer(GL_READ_FRAMEBUFFER, m_msaaFBO);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_fbo);
glBlitFramebuffer(0, 0, m_width, m_height, 0, 0, m_width, m_height, GL_COLOR_BUFFER_BIT, GL_NEAREST);
// Read pixels from resolved FBO (texture)
glBindFramebuffer(GL_FRAMEBUFFER, m_fbo);
glReadPixels(0, 0, m_width, m_height, GL_RGBA, GL_UNSIGNED_BYTE, m_renderedImage->pixels); glReadPixels(0, 0, m_width, m_height, GL_RGBA, GL_UNSIGNED_BYTE, m_renderedImage->pixels);
// Unbind framebuffer to avoid side effects
glBindFramebuffer(GL_FRAMEBUFFER, 0); glBindFramebuffer(GL_FRAMEBUFFER, 0);
// Composite onto SDL backbuffer // Copy the pixels to SDL backbuffer surface
SDL_BlitSurface(m_renderedImage, nullptr, DDBackBuffer, nullptr); SDL_BlitSurface(m_renderedImage, nullptr, DDBackBuffer, nullptr);
return DD_OK; return DD_OK;

View File

@ -19,7 +19,7 @@ struct GLTextureCacheEntry {
class OpenGL15Renderer : public Direct3DRMRenderer { class OpenGL15Renderer : public Direct3DRMRenderer {
public: public:
static Direct3DRMRenderer* Create(DWORD width, DWORD height); static Direct3DRMRenderer* Create(DWORD width, DWORD height);
OpenGL15Renderer(int width, int height, SDL_GLContext context, GLuint fbo, GLuint colorTex, GLuint depthRb); OpenGL15Renderer(int width, int height, SDL_GLContext context, GLuint fbo, GLuint msaaFBO);
~OpenGL15Renderer() override; ~OpenGL15Renderer() override;
void PushLights(const SceneLight* lightsArray, size_t count) override; void PushLights(const SceneLight* lightsArray, size_t count) override;
void SetProjection(const D3DRMMATRIX4D& projection, D3DVALUE front, D3DVALUE back) override; void SetProjection(const D3DRMMATRIX4D& projection, D3DVALUE front, D3DVALUE back) override;
@ -48,8 +48,7 @@ class OpenGL15Renderer : public Direct3DRMRenderer {
std::vector<SceneLight> m_lights; std::vector<SceneLight> m_lights;
SDL_GLContext m_context; SDL_GLContext m_context;
GLuint m_fbo = 0; GLuint m_fbo = 0;
GLuint m_colorTex = 0; GLuint m_msaaFBO = 0;
GLuint m_depthRb = 0;
}; };
inline static void OpenGL15Renderer_EnumDevice(LPD3DENUMDEVICESCALLBACK cb, void* ctx) inline static void OpenGL15Renderer_EnumDevice(LPD3DENUMDEVICESCALLBACK cb, void* ctx)