OpenGL renderer support in melonDS!

This commit is contained in:
CasualPokePlayer 2023-09-24 04:25:41 -07:00
parent acff619034
commit f71f2fafc6
8 changed files with 4573 additions and 11 deletions

Binary file not shown.

View File

@ -0,0 +1,207 @@
#include "GPU.h"
#include "OpenGLSupport.h"
#include "frontend/FrontendUtil.h"
#include "BizGLPresenter.h"
#include <emulibc.h>
// half of this is taken from melonDS/src/frontend/qt_sdl/main.cpp
namespace GLPresenter
{
static const char* VertexShader = R"(#version 140
uniform vec2 uSize;
uniform mat2x3 uTransform;
in vec2 vPosition;
in vec2 vTexcoord;
smooth out vec2 fTexcoord;
void main()
{
vec4 fpos;
fpos.xy = vec3(vPosition, 1.0) * uTransform;
fpos.xy = ((fpos.xy * 2.0) / uSize) - 1.0;
// fpos.y *= -1;
fpos.z = 0.0;
fpos.w = 1.0;
gl_Position = fpos;
fTexcoord = vTexcoord;
}
)";
static const char* FragmentShader = R"(#version 140
uniform sampler2D Tex;
smooth in vec2 fTexcoord;
out vec4 oColor;
void main()
{
vec4 pixel = texture(Tex, fTexcoord);
oColor = vec4(pixel.bgr, 1.0);
}
)";
ECL_INVISIBLE static GLuint ShaderProgram[3];
ECL_INVISIBLE static GLuint ShaderTransformULoc, ShaderSizeULoc;
ECL_INVISIBLE static GLuint VertexBuffer, VertexArray;
ECL_INVISIBLE static float TransformMatrix[2 * 6];
ECL_INVISIBLE static u32 Width, Height;
ECL_INVISIBLE static GLuint TextureID;
ECL_INVISIBLE static GLuint FboID;
ECL_INVISIBLE static GLuint PboID;
void Init(u32 scale)
{
Width = 256 * scale;
Height = 384 * scale;
OpenGL::BuildShaderProgram(VertexShader, FragmentShader, ShaderProgram, "GLPresenterShader");
GLuint pid = ShaderProgram[2];
glBindAttribLocation(pid, 0, "vPosition");
glBindAttribLocation(pid, 1, "vTexcoord");
glBindFragDataLocation(pid, 0, "oColor");
OpenGL::LinkShaderProgram(ShaderProgram);
glUseProgram(pid);
glUniform1i(glGetUniformLocation(pid, "Tex"), 0);
ShaderSizeULoc = glGetUniformLocation(pid, "uSize");
ShaderTransformULoc = glGetUniformLocation(pid, "uTransform");
constexpr int paddedHeight = 192 * 2 + 2;
constexpr float padPixels = 1.f / paddedHeight;
static const float vertices[] =
{
0.f, 0.f, 0.f, 0.f,
0.f, 192.f, 0.f, 0.5f - padPixels,
256.f, 192.f, 1.f, 0.5f - padPixels,
0.f, 0.f, 0.f, 0.f,
256.f, 192.f, 1.f, 0.5f - padPixels,
256.f, 0.f, 1.f, 0.f,
0.f, 0.f, 0.f, 0.5f + padPixels,
0.f, 192.f, 0.f, 1.f,
256.f, 192.f, 1.f, 1.f,
0.f, 0.f, 0.f, 0.5f + padPixels,
256.f, 192.f, 1.f, 1.f,
256.f, 0.f, 1.f, 0.5f + padPixels
};
glGenBuffers(1, &VertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, VertexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glGenVertexArrays(1, &VertexArray);
glBindVertexArray(VertexArray);
glEnableVertexAttribArray(0); // position
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * 4, (void*)(0));
glEnableVertexAttribArray(1); // texcoord
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * 4, (void*)(2 * 4));
// TODO: Could we use this instead of all the screen transforming code in the frontend?
// see https://github.com/TASEmulators/BizHawk/issues/3772
Frontend::SetupScreenLayout(Width, Height, Frontend::screenLayout_Natural, Frontend::screenRot_0Deg, Frontend::screenSizing_Even, 0, true, false, 1, 1);
int discard[2];
Frontend::GetScreenTransforms(TransformMatrix, discard);
glGenTextures(1, &TextureID);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, TextureID);
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);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, Width, Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glBindTexture(GL_TEXTURE_2D, 0);
glGenFramebuffers(1, &FboID);
glBindFramebuffer(GL_FRAMEBUFFER, FboID);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, TextureID, 0);
glDrawBuffer(GL_COLOR_ATTACHMENT0);
glGenBuffers(1, &PboID);
}
std::pair<u32, u32> Present(bool filter)
{
glBindFramebuffer(GL_FRAMEBUFFER, FboID);
glDisable(GL_DEPTH_TEST);
glDepthMask(false);
glDisable(GL_BLEND);
glDisable(GL_SCISSOR_TEST);
glDisable(GL_STENCIL_TEST);
glClear(GL_COLOR_BUFFER_BIT);
glViewport(0, 0, Width, Height);
glUseProgram(ShaderProgram[2]);
glUniform2f(ShaderSizeULoc, Width, Height);
glActiveTexture(GL_TEXTURE0);
GPU::CurGLCompositor->BindOutputTexture(GPU::FrontBuffer);
GLint texFilter = filter ? GL_LINEAR : GL_NEAREST;
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, texFilter);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, texFilter);
glBindBuffer(GL_ARRAY_BUFFER, VertexBuffer);
glBindVertexArray(VertexArray);
glUniformMatrix2x3fv(ShaderTransformULoc, 1, GL_TRUE, &TransformMatrix[0]);
glDrawArrays(GL_TRIANGLES, 0, 6);
glUniformMatrix2x3fv(ShaderTransformULoc, 1, GL_TRUE, &TransformMatrix[6]);
glDrawArrays(GL_TRIANGLES, 6, 6);
glFlush();
glBindBuffer(GL_PIXEL_PACK_BUFFER, PboID);
glBufferData(GL_PIXEL_PACK_BUFFER, Width * Height * sizeof(u32), nullptr, GL_STREAM_READ);
glReadPixels(0, 0, Width, Height, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, static_cast<void*>(0));
return std::make_pair(Width, Height);
}
ECL_EXPORT u32 GetGLTexture()
{
return TextureID;
}
ECL_EXPORT void ReadFrameBuffer(u32* buffer)
{
glBindBuffer(GL_PIXEL_PACK_BUFFER, PboID);
const auto p = static_cast<const u32*>(glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY));
if (p) {
// FBOs render upside down, so flip vertically to counteract that
buffer += Width * (Height - 1);
const int w = Width;
const int h = Height;
for (int i = 0; i < h; i++) {
std::memcpy(&buffer[-i * w], &p[i * w], Width * sizeof(u32));
}
glUnmapBuffer(GL_PIXEL_PACK_BUFFER);
}
}
}

View File

@ -0,0 +1,14 @@
#ifndef BIZGLPRESENTER_H
#define BIZGLPRESENTER_H
#include "types.h"
namespace GLPresenter
{
void Init(u32 scale);
std::pair<u32, u32> Present(bool filter);
}
#endif

View File

@ -8,7 +8,10 @@
#include "BizPlatform/BizConfig.h"
#include "BizPlatform/BizFile.h"
#include "BizPlatform/BizLog.h"
#include "BizPlatform/BizOGL.h"
#include "BizFileManager.h"
#include "BizGLPresenter.h"
#include <emulibc.h>
#include <waterboxcore.h>
@ -23,6 +26,7 @@ struct InitConfig
bool DSi;
bool ClearNAND;
bool LoadDSiWare;
bool IsWinApi;
int ThreeDeeRenderer;
GPU::RenderSettings RenderSettings;
};
@ -30,7 +34,8 @@ struct InitConfig
ECL_EXPORT const char* Init(InitConfig* initConfig,
Platform::ConfigCallbackInterface* configCallbackInterface,
Platform::FileCallbackInterface* fileCallbackInterface,
Platform::LogCallback_t logCallback)
Platform::LogCallback_t logCallback,
BizOGL::LoadGLProc loadGLProc)
{
Platform::SetConfigCallbacks(*configCallbackInterface);
Platform::SetFileCallbacks(*fileCallbackInterface);
@ -55,6 +60,27 @@ ECL_EXPORT const char* Init(InitConfig* initConfig,
return "Failed to init core!";
}
switch (initConfig->ThreeDeeRenderer)
{
case 0:
break;
case 1:
BizOGL::LoadGL(loadGLProc, BizOGL::LoadGLVersion::V3_2, initConfig->IsWinApi);
break;
#if false
case 2:
BizOGL::LoadGL(loadGLProc, BizOGL::LoadGLVersion::V4_3, initConfig->IsWinApi);
break;
#endif
default:
return "Unknown 3DRenderer!";
}
if (initConfig->ThreeDeeRenderer)
{
GLPresenter::Init(initConfig->RenderSettings.GL_ScaleFactor);
}
GPU::InitRenderer(initConfig->ThreeDeeRenderer);
GPU::SetRenderSettings(initConfig->ThreeDeeRenderer, initConfig->RenderSettings);
@ -166,17 +192,22 @@ ECL_EXPORT void FrameAdvance(MyFrameInfo* f)
NDS::RunFrame();
if (auto softRenderer = dynamic_cast<GPU3D::SoftRenderer*>(GPU3D::CurrentRenderer.get()))
if (GPU3D::CurrentRenderer->Accelerated)
{
softRenderer->StopRenderThread();
std::tie(f->Width, f->Height) = GLPresenter::Present(false);
}
else
{
auto softRenderer = reinterpret_cast<GPU3D::SoftRenderer*>(GPU3D::CurrentRenderer.get());
softRenderer->StopRenderThread();
const u32 SingleScreenSize = 256 * 192;
memcpy(f->VideoBuffer, GPU::Framebuffer[GPU::FrontBuffer][0], SingleScreenSize * sizeof (u32));
memcpy(f->VideoBuffer + SingleScreenSize, GPU::Framebuffer[GPU::FrontBuffer][1], SingleScreenSize * sizeof (u32));
constexpr u32 SingleScreenSize = 256 * 192;
memcpy(f->VideoBuffer, GPU::Framebuffer[GPU::FrontBuffer][0], SingleScreenSize * sizeof(u32));
memcpy(f->VideoBuffer + SingleScreenSize, GPU::Framebuffer[GPU::FrontBuffer][1], SingleScreenSize * sizeof(u32));
f->Width = 256;
f->Height = 384;
f->Width = 256;
f->Height = 384;
}
f->Samples = SPU::ReadOutput(f->SoundBuffer);
if (f->Samples == 0) // hack

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
CCFLAGS := -Wno-incompatible-pointer-types-discards-qualifiers -Wno-pointer-sign
CXXFLAGS := -DMELONDS_VERSION="" \
-I./melonDS/src -I./melonDS/src/teakra/include \
CXXFLAGS := -DMELONDS_VERSION="" -DOGLRENDERER_ENABLED \
-I. -I./melonDS/src -I./melonDS/src/teakra/include \
-Wall -Wextra -Werror=int-to-pointer-cast \
-Wfatal-errors -Wno-unused-parameter -Wno-unused-variable \
-Wno-unused-but-set-variable -Wno-unused-function \
@ -49,6 +49,12 @@ CORE_SRCS = \
Wifi.cpp \
WifiAP.cpp
CORE_GL_SRCS = \
GPU_OpenGL.cpp \
GPU3D_OpenGL.cpp \
OpenGLSupport.cpp \
frontend/Util_Video.cpp
TEAKRA_SRCS = \
ahbm.cpp \
apbp.cpp \
@ -76,18 +82,21 @@ BIZPLATFORM_SRCS = \
BizPlatform/BizConfig.cpp \
BizPlatform/BizFile.cpp \
BizPlatform/BizLog.cpp \
BizPlatform/BizOGL.cpp \
BizPlatform/BizPlatformStubs.cpp \
BizPlatform/BizSaveManager.cpp \
BizPlatform/BizThread.cpp \
SRCS = \
$(addprefix melonDS/src/,$(CORE_SRCS)) \
$(addprefix melonDS/src/,$(CORE_GL_SRCS)) \
$(addprefix melonDS/src/teakra/src/,$(TEAKRA_SRCS)) \
$(addprefix melonDS/src/fatfs/,$(FATFS_SRCS)) \
$(addprefix melonDS/src/,$(MISC_SRCS)) \
$(BIZPLATFORM_SRCS) \
BizDebugging.cpp \
BizFileManager.cpp \
BizGLPresenter.cpp \
BizInterface.cpp \
dthumb.c

@ -1 +1 @@
Subproject commit 270f7083caaf477b7ca3456eed9721c3ef239f41
Subproject commit b200c5476bce4a0c127c304105b3cb7d54f0cee4