mirror of
https://github.com/libretro/Libretro-Supermodel.git
synced 2026-11-10 03:01:26 -10:00
Add native Libretro supersampling
This commit is contained in:
1 parent
4be6d8222c
commit
800e6dfe11
9 files changed
+122
-69
No files matched your search
@@ -244,6 +244,7 @@ endif
|
||||
|
||||
ifneq ($(filter $(platform),android rpi64 aarch64),$(platform))
|
||||
RENDERER_DEFINES += -DHAVE_CRT_COLOURS
|
||||
RENDERER_DEFINES += -DHAVE_SUPERSAMPLING
|
||||
endif
|
||||
|
||||
# GIT version
|
||||
|
||||
+22
-16
@@ -4,9 +4,10 @@
|
||||
|
||||
SuperAA::SuperAA(int aaValue, CRTcolor CRTcolors) :
|
||||
m_aa(aaValue),
|
||||
m_crtcolors(CRTcolors),
|
||||
m_vao(0),
|
||||
m_width(0),
|
||||
m_crtcolors(CRTcolors),
|
||||
m_vao(0),
|
||||
m_outputTarget(0),
|
||||
m_width(0),
|
||||
m_height(0)
|
||||
{
|
||||
if ((m_aa > 1) || (m_crtcolors != CRTcolor::None)) {
|
||||
@@ -203,25 +204,30 @@ void SuperAA::Init(int width, int height)
|
||||
}
|
||||
}
|
||||
|
||||
void SuperAA::Draw()
|
||||
{
|
||||
if ((m_aa > 1) || (m_crtcolors != CRTcolor::None)) {
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glDisable(GL_STENCIL_TEST);
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
glDisable(GL_BLEND);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, m_fbo.GetTextureID());
|
||||
void SuperAA::Draw()
|
||||
{
|
||||
if ((m_aa > 1) || (m_crtcolors != CRTcolor::None)) {
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, m_outputTarget);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glDisable(GL_STENCIL_TEST);
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
glDisable(GL_BLEND);
|
||||
glBindTexture(GL_TEXTURE_2D, m_fbo.GetTextureID());
|
||||
glBindVertexArray(m_vao);
|
||||
glViewport(0, 0, m_width, m_height);
|
||||
m_shader.EnableShader();
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
m_shader.DisableShader();
|
||||
glBindVertexArray(0);
|
||||
}
|
||||
}
|
||||
|
||||
GLuint SuperAA::GetTargetID()
|
||||
}
|
||||
}
|
||||
|
||||
void SuperAA::SetOutputTarget(GLuint fbo)
|
||||
{
|
||||
m_outputTarget = fbo;
|
||||
}
|
||||
|
||||
GLuint SuperAA::GetTargetID()
|
||||
{
|
||||
return m_fbo.GetFBOID(); // will return 0 if no render target which will be our default frame buffer (back buffer)
|
||||
}
|
||||
@@ -16,17 +16,19 @@ public:
|
||||
SuperAA(int aaValue, CRTcolor CRTcolors);
|
||||
~SuperAA();
|
||||
|
||||
void Init(int width, int height); // width & height are real window dimensions
|
||||
void Draw(); // this is a no-op if AA is 1 and CRTcolors 0, since we'll be drawing straight on the back buffer anyway
|
||||
|
||||
GLuint GetTargetID();
|
||||
void Init(int width, int height); // width & height are real window dimensions
|
||||
void Draw(); // this is a no-op if AA is 1 and CRTcolors 0, since we'll be drawing straight on the back buffer anyway
|
||||
void SetOutputTarget(GLuint fbo); // optional resolved output FBO (0 = window backbuffer)
|
||||
|
||||
GLuint GetTargetID();
|
||||
|
||||
private:
|
||||
FBO m_fbo;
|
||||
GLSLShader m_shader;
|
||||
const int m_aa;
|
||||
const CRTcolor m_crtcolors;
|
||||
GLuint m_vao;
|
||||
int m_width;
|
||||
GLuint m_vao;
|
||||
GLuint m_outputTarget;
|
||||
int m_width;
|
||||
int m_height;
|
||||
};
|
||||
@@ -50,6 +50,7 @@ struct CoreOptions {
|
||||
Renderer3D renderer_3d;
|
||||
bool quad_rendering;
|
||||
int crt_colors;
|
||||
int supersampling;
|
||||
int upscale_mode;
|
||||
WidescreenMode widescreen_mode;
|
||||
unsigned crosshairs; // native Supermodel mask: 0=off, 1=P1, 2=P2, 3=both
|
||||
|
||||
@@ -338,6 +338,7 @@ namespace LibretroConfigProvider {
|
||||
!use_legacy_3d && g_options.quad_rendering);
|
||||
config.Set("CRTcolors",
|
||||
!use_legacy_3d ? g_options.crt_colors : 0);
|
||||
config.Set("Supersampling", g_options.supersampling);
|
||||
config.Set("UpscaleMode", g_options.upscale_mode);
|
||||
config.Set("WideScreen",
|
||||
g_options.widescreen_mode != WidescreenMode::Disabled);
|
||||
|
||||
@@ -380,43 +380,45 @@ bool LibretroWrapper::InitRenderers()
|
||||
superAA = new SuperAA(aaValue, CRTcolors);
|
||||
superAA->Init(totalXRes, totalYRes);
|
||||
|
||||
GLuint renderTarget = superAA->GetTargetID();
|
||||
|
||||
// SuperAA skips FBO creation when aa==1 and no CRT filter.
|
||||
// In that case we must provide our own FBO; otherwise glBlitFramebuffer
|
||||
// reads from FBO-0 (the raw window backbuffer), which is invalid in libretro.
|
||||
if (renderTarget == 0)
|
||||
{
|
||||
glGenFramebuffers(1, &m_libretrFBO);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, m_libretrFBO);
|
||||
|
||||
glGenTextures(1, &m_libretrTex);
|
||||
glBindTexture(GL_TEXTURE_2D, m_libretrTex);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8,
|
||||
totalXRes, totalYRes,
|
||||
0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
|
||||
GL_TEXTURE_2D, m_libretrTex, 0);
|
||||
|
||||
glGenRenderbuffers(1, &m_libretrDepth);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, m_libretrDepth);
|
||||
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8,
|
||||
totalXRes, totalYRes);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
|
||||
GL_RENDERBUFFER, m_libretrDepth);
|
||||
|
||||
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
||||
if (status != GL_FRAMEBUFFER_COMPLETE)
|
||||
ErrorLog("[Supermodel] Libretro FBO incomplete: 0x%X", status);
|
||||
else
|
||||
InfoLog("[Supermodel] Libretro FBO created: %ux%u (id=%u)",
|
||||
totalXRes, totalYRes, m_libretrFBO);
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
renderTarget = m_libretrFBO;
|
||||
}
|
||||
GLuint renderTarget = superAA->GetTargetID();
|
||||
|
||||
// Libretro always needs a base-resolution resolved target. With native
|
||||
// supersampling/CRT colour active, SuperAA renders its high-resolution
|
||||
// input down into this FBO. Without that pass, the Model 3 renderers draw
|
||||
// here directly. Never submit SuperAA's high-resolution source FBO to the
|
||||
// frontend: doing so crops the image to its lower-left base-size region.
|
||||
glGenFramebuffers(1, &m_libretrFBO);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, m_libretrFBO);
|
||||
|
||||
glGenTextures(1, &m_libretrTex);
|
||||
glBindTexture(GL_TEXTURE_2D, m_libretrTex);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8,
|
||||
totalXRes, totalYRes,
|
||||
0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
|
||||
GL_TEXTURE_2D, m_libretrTex, 0);
|
||||
|
||||
glGenRenderbuffers(1, &m_libretrDepth);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, m_libretrDepth);
|
||||
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8,
|
||||
totalXRes, totalYRes);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
|
||||
GL_RENDERBUFFER, m_libretrDepth);
|
||||
|
||||
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
||||
if (status != GL_FRAMEBUFFER_COMPLETE)
|
||||
ErrorLog("[Supermodel] Libretro FBO incomplete: 0x%X", status);
|
||||
else
|
||||
InfoLog("[Supermodel] Libretro resolved FBO created: %ux%u (id=%u)",
|
||||
totalXRes, totalYRes, m_libretrFBO);
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
if (renderTarget != 0)
|
||||
superAA->SetOutputTarget(m_libretrFBO);
|
||||
else
|
||||
renderTarget = m_libretrFBO;
|
||||
|
||||
Render2D = new CRender2D(s_runtime_config);
|
||||
// Normal desktop builds can include both renderers and select at runtime.
|
||||
@@ -907,11 +909,10 @@ bool LibretroWrapper::InitGL()
|
||||
return InitRenderers();
|
||||
}
|
||||
|
||||
GLuint LibretroWrapper::getSuperModelFBO() const
|
||||
{
|
||||
GLuint saaFBO = superAA ? superAA->GetTargetID() : 0;
|
||||
return (saaFBO != 0) ? saaFBO : m_libretrFBO;
|
||||
}
|
||||
GLuint LibretroWrapper::getSuperModelFBO() const
|
||||
{
|
||||
return m_libretrFBO;
|
||||
}
|
||||
|
||||
void LibretroWrapper::SetWidescreen(bool enabled, bool wideBackground)
|
||||
{
|
||||
|
||||
@@ -81,8 +81,8 @@ public:
|
||||
void ShutDownSupermodel();
|
||||
bool InitRenderers();
|
||||
bool InitGL();
|
||||
// Returns the actual FBO Supermodel renders into (SuperAA's or our own)
|
||||
GLuint getSuperModelFBO() const;
|
||||
// Returns the base-resolution frame resolved for Libretro submission.
|
||||
GLuint getSuperModelFBO() const;
|
||||
|
||||
private:
|
||||
float lastEngineMs = 0.0f;
|
||||
|
||||
@@ -285,6 +285,7 @@ CoreOptions g_options = {
|
||||
/* renderer_3d */ Renderer3D::New3D,
|
||||
/* quad_rendering */ false,
|
||||
/* crt_colors */ 0,
|
||||
/* supersampling */ 1,
|
||||
/* upscale_mode */ 2,
|
||||
/* widescreen_mode */ WidescreenMode::Disabled,
|
||||
/* crosshairs */ 0,
|
||||
@@ -1099,6 +1100,7 @@ void retro_run(void)
|
||||
Renderer3D old_renderer_3d = g_options.renderer_3d;
|
||||
bool old_quad_rendering = g_options.quad_rendering;
|
||||
int old_crt_colors = g_options.crt_colors;
|
||||
int old_supersampling = g_options.supersampling;
|
||||
WidescreenMode old_widescreen_mode = g_options.widescreen_mode;
|
||||
int old_upscale_mode = g_options.upscale_mode;
|
||||
bool old_legacy_sound_dsp = g_options.legacy_sound_dsp;
|
||||
@@ -1123,10 +1125,11 @@ void retro_run(void)
|
||||
|
||||
if (g_options.renderer_3d != old_renderer_3d ||
|
||||
g_options.quad_rendering != old_quad_rendering ||
|
||||
g_options.crt_colors != old_crt_colors)
|
||||
g_options.crt_colors != old_crt_colors ||
|
||||
g_options.supersampling != old_supersampling)
|
||||
{
|
||||
static const struct retro_message message = {
|
||||
"3D Renderer, Quad Rendering and CRT Colour changes require restarting the content.", 240
|
||||
"Renderer and supersampling changes require restarting the content.", 240
|
||||
};
|
||||
environ_cb(RETRO_ENVIRONMENT_SET_MESSAGE, (void *)&message);
|
||||
}
|
||||
@@ -1338,7 +1341,14 @@ void retro_run(void)
|
||||
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
||||
|
||||
glViewport(0, 0, target_w, target_h);
|
||||
glScissor(0, 0, target_w, target_h);
|
||||
// Render2D re-enables the scissor test after clearing its target. The
|
||||
// box is global GL state and must describe the supersampled render FBO,
|
||||
// exactly as standalone scales its scissor by aaValue. Leaving this at
|
||||
// base resolution clips a 2x source to its lower-left quarter before
|
||||
// SuperAA resolves it.
|
||||
const unsigned render_scale = static_cast<unsigned>(
|
||||
std::max(1, wrapper.getAaValue()));
|
||||
glScissor(0, 0, target_w * render_scale, target_h * render_scale);
|
||||
|
||||
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
glClearDepth(1.0);
|
||||
|
||||
@@ -132,6 +132,28 @@ static struct retro_core_option_v2_definition option_defs[] = {
|
||||
},
|
||||
"0"
|
||||
},
|
||||
#endif
|
||||
#ifdef HAVE_SUPERSAMPLING
|
||||
{
|
||||
"supermodel_supersampling",
|
||||
"Supersampling",
|
||||
NULL,
|
||||
"Render each output pixel from multiple internal samples using Supermodel's native supersampling pass. The scale applies on top of Internal Resolution: 2x uses 4 samples per pixel, 3x uses 9, and 8x uses 64. Higher values can require substantial GPU time and memory. Takes effect after restarting content.",
|
||||
NULL,
|
||||
"video",
|
||||
{
|
||||
{ "1", "1x (Disabled, Default)" },
|
||||
{ "2", "2x (4 Samples)" },
|
||||
{ "3", "3x (9 Samples)" },
|
||||
{ "4", "4x (16 Samples)" },
|
||||
{ "5", "5x (25 Samples)" },
|
||||
{ "6", "6x (36 Samples)" },
|
||||
{ "7", "7x (49 Samples)" },
|
||||
{ "8", "8x (64 Samples)" },
|
||||
{ NULL, NULL },
|
||||
},
|
||||
"1"
|
||||
},
|
||||
#endif
|
||||
{
|
||||
"supermodel_timing_overlay",
|
||||
@@ -571,6 +593,15 @@ void update_core_options(void)
|
||||
g_options.crt_colors = 0;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SUPERSAMPLING
|
||||
g_options.supersampling =
|
||||
atoi(option_get("supermodel_supersampling", "1"));
|
||||
if (g_options.supersampling < 1 || g_options.supersampling > 8)
|
||||
g_options.supersampling = 1;
|
||||
#else
|
||||
g_options.supersampling = 1;
|
||||
#endif
|
||||
|
||||
g_options.upscale_mode = atoi(option_get("supermodel_upscale_mode", "2"));
|
||||
if (g_options.upscale_mode < 0 || g_options.upscale_mode > 3)
|
||||
g_options.upscale_mode = 2;
|
||||
|
||||
Reference in new issue
Block a user