diff --git a/melonDS.cbp b/melonDS.cbp
index 46345135..ff01ebfb 100644
--- a/melonDS.cbp
+++ b/melonDS.cbp
@@ -230,6 +230,7 @@
+
diff --git a/src/GPU3D_OpenGL43.cpp b/src/GPU3D_OpenGL43.cpp
index 3a2a3f1c..b3e08566 100644
--- a/src/GPU3D_OpenGL43.cpp
+++ b/src/GPU3D_OpenGL43.cpp
@@ -732,7 +732,8 @@ bool ChunkedRendering = false;
bool InitGLExtensions()
{
- if (!OpenGL_Init()) return false;
+ // TODO move this elsewhere!!
+ //if (!OpenGL_Init()) return false;
return true;
}
@@ -1385,7 +1386,7 @@ void VCount144()
}
void RenderFrame()
-{
+{return;
ShaderConfig.uScreenSize[0] = ScreenW;
ShaderConfig.uScreenSize[1] = ScreenH;
ShaderConfig.uDispCnt = RenderDispCnt;
@@ -1544,7 +1545,7 @@ void RenderFrame()
u32* GetLine(int line)
{
int stride = 256 << (ScaleFactor*2);
-
+return &Framebuffer[stride * line];
if (!ChunkedRendering)
{
if (line == 0)
diff --git a/src/OpenGLSupport.cpp b/src/OpenGLSupport.cpp
index c22fd1c4..81a008b8 100644
--- a/src/OpenGLSupport.cpp
+++ b/src/OpenGLSupport.cpp
@@ -28,3 +28,88 @@ bool OpenGL_Init()
return true;
}
+
+bool OpenGL_BuildShaderProgram(const char* vs, const char* fs, GLuint* ids, const char* name)
+{
+ int len;
+ int res;
+
+ ids[0] = glCreateShader(GL_VERTEX_SHADER);
+ len = strlen(vs);
+ glShaderSource(ids[0], 1, &vs, &len);
+ glCompileShader(ids[0]);
+
+ glGetShaderiv(ids[0], GL_COMPILE_STATUS, &res);
+ if (res != GL_TRUE)
+ {
+ glGetShaderiv(ids[0], GL_INFO_LOG_LENGTH, &res);
+ if (res < 1) res = 1024;
+ char* log = new char[res+1];
+ glGetShaderInfoLog(ids[0], res+1, NULL, log);
+ printf("OpenGL: failed to compile vertex shader %s: %s\n", name, log);
+ printf("shader source:\n--\n%s\n--\n", vs);
+ delete[] log;
+
+ glDeleteShader(ids[0]);
+
+ return false;
+ }
+
+ ids[1] = glCreateShader(GL_FRAGMENT_SHADER);
+ len = strlen(fs);
+ glShaderSource(ids[1], 1, &fs, &len);
+ glCompileShader(ids[1]);
+
+ glGetShaderiv(ids[1], GL_COMPILE_STATUS, &res);
+ if (res != GL_TRUE)
+ {
+ glGetShaderiv(ids[1], GL_INFO_LOG_LENGTH, &res);
+ if (res < 1) res = 1024;
+ char* log = new char[res+1];
+ glGetShaderInfoLog(ids[1], res+1, NULL, log);
+ printf("OpenGL: failed to compile fragment shader %s: %s\n", name, log);
+ //printf("shader source:\n--\n%s\n--\n", fs);
+ delete[] log;
+
+ glDeleteShader(ids[0]);
+ glDeleteShader(ids[1]);
+
+ return false;
+ }
+
+ ids[2] = glCreateProgram();
+ glAttachShader(ids[2], ids[0]);
+ glAttachShader(ids[2], ids[1]);
+ glLinkProgram(ids[2]);
+
+ glGetProgramiv(ids[2], GL_LINK_STATUS, &res);
+ if (res != GL_TRUE)
+ {
+ glGetProgramiv(ids[2], GL_INFO_LOG_LENGTH, &res);
+ if (res < 1) res = 1024;
+ char* log = new char[res+1];
+ glGetProgramInfoLog(ids[2], res+1, NULL, log);
+ printf("OpenGL: failed to link program %s: %s\n", name, log);
+ delete[] log;
+
+ glDeleteShader(ids[0]);
+ glDeleteShader(ids[1]);
+ glDeleteProgram(ids[2]);
+
+ return false;
+ }
+
+ return true;
+}
+
+void OpenGL_DeleteShaderProgram(GLuint* ids)
+{
+ glDeleteShader(ids[0]);
+ glDeleteShader(ids[1]);
+ glDeleteProgram(ids[2]);
+}
+
+void OpenGL_UseShaderProgram(GLuint* ids)
+{
+ glUseProgram(ids[2]);
+}
diff --git a/src/OpenGLSupport.h b/src/OpenGLSupport.h
index 10ba1e5e..2cee7410 100644
--- a/src/OpenGLSupport.h
+++ b/src/OpenGLSupport.h
@@ -109,4 +109,8 @@ DO_PROCLIST(DECLPROC_EXT);
bool OpenGL_Init();
+bool OpenGL_BuildShaderProgram(const char* vs, const char* fs, GLuint* ids, const char* name);
+void OpenGL_DeleteShaderProgram(GLuint* ids);
+void OpenGL_UseShaderProgram(GLuint* ids);
+
#endif // OPENGLSUPPORT_H
diff --git a/src/libui_sdl/libui/windows/gl.cpp b/src/libui_sdl/libui/windows/gl.cpp
index 67eaedae..832a2e59 100644
--- a/src/libui_sdl/libui/windows/gl.cpp
+++ b/src/libui_sdl/libui/windows/gl.cpp
@@ -39,7 +39,7 @@ uiGLContext* uiGLNewContext(uiControl* c, int vermajor, int verminor)
memset(&pfd, 0, sizeof(pfd));
pfd.nSize = sizeof(pfd);
pfd.nVersion = 1;
- pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
+ pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = 24;
pfd.cAlphaBits = 8;
diff --git a/src/libui_sdl/main.cpp b/src/libui_sdl/main.cpp
index b39f493d..23e66173 100644
--- a/src/libui_sdl/main.cpp
+++ b/src/libui_sdl/main.cpp
@@ -24,6 +24,9 @@
#include
#include "libui/ui.h"
+#include "../OpenGLSupport.h"
+#include "main_shaders.h"
+
#include "../types.h"
#include "../version.h"
#include "PlatformConfig.h"
@@ -97,6 +100,19 @@ bool SavestateLoaded;
bool ScreenDrawInited = false;
uiDrawBitmap* ScreenBitmap[2] = {NULL,NULL};
+GLuint GL_ScreenShader[3];
+struct
+{
+ float uScreenSize[2];
+ u32 uFilterMode;
+
+} GL_ShaderConfig;
+GLuint GL_ShaderConfigUBO;
+GLuint GL_ScreenVertexArrayID, GL_ScreenVertexBufferID;
+float GL_ScreenVertices[2 * 3*2 * 4]; // position/texcoord
+GLuint GL_ScreenTexture;
+bool GL_ScreenSizeDirty;
+
int ScreenScale[3];
int ScreenScaleMode;
@@ -141,6 +157,204 @@ void GetSavestateName(int slot, char* filename, int len);
+bool GLDrawing_Init()
+{
+ if (!OpenGL_Init())
+ return false;
+
+ if (!OpenGL_BuildShaderProgram(kScreenVS, kScreenFS, GL_ScreenShader, "ScreenShader"))
+ return false;
+
+ memset(&GL_ShaderConfig, 0, sizeof(GL_ShaderConfig));
+
+ glGenBuffers(1, &GL_ShaderConfigUBO);
+ glBindBuffer(GL_UNIFORM_BUFFER, GL_ShaderConfigUBO);
+ glBufferData(GL_UNIFORM_BUFFER, sizeof(GL_ShaderConfig), &GL_ShaderConfig, GL_STATIC_DRAW);
+ glBindBufferBase(GL_UNIFORM_BUFFER, 16, GL_ShaderConfigUBO);
+ glUniformBlockBinding(GL_ScreenShader[2], 0, 16);
+
+ glGenBuffers(1, &GL_ScreenVertexBufferID);
+ glBindBuffer(GL_ARRAY_BUFFER, GL_ScreenVertexBufferID);
+ glBufferData(GL_ARRAY_BUFFER, sizeof(GL_ScreenVertices), NULL, GL_STATIC_DRAW);
+
+ glGenVertexArrays(1, &GL_ScreenVertexArrayID);
+ glBindVertexArray(GL_ScreenVertexArrayID);
+ 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));
+
+ glGenTextures(1, &GL_ScreenTexture);
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, GL_ScreenTexture);
+ 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_RGBA8UI, 1024, 1536, 0, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE, NULL);
+
+ GL_ScreenSizeDirty = true;
+
+ return true;
+}
+
+void GLDrawing_DeInit()
+{
+ glDeleteTextures(1, &GL_ScreenTexture);
+
+ glDeleteVertexArrays(1, &GL_ScreenVertexArrayID);
+ glDeleteBuffers(1, &GL_ScreenVertexBufferID);
+
+ OpenGL_DeleteShaderProgram(GL_ScreenShader);
+}
+
+void GLDrawing_DrawScreen()
+{
+ if (GL_ScreenSizeDirty)
+ {
+ GL_ScreenSizeDirty = false;
+
+ GL_ShaderConfig.uScreenSize[0] = WindowWidth;
+ GL_ShaderConfig.uScreenSize[1] = WindowHeight;
+
+ glBindBuffer(GL_UNIFORM_BUFFER, GL_ShaderConfigUBO);
+ void* unibuf = glMapBuffer(GL_UNIFORM_BUFFER, GL_WRITE_ONLY);
+ if (unibuf) memcpy(unibuf, &GL_ShaderConfig, sizeof(GL_ShaderConfig));
+ glUnmapBuffer(GL_UNIFORM_BUFFER);
+
+ float scwidth, scheight;
+ scwidth = 512;
+ scheight = 384;
+
+ float x0, y0, x1, y1;
+ float s0, s1, s2, s3;
+ float t0, t1, t2, t3;
+
+#define SETVERTEX(i, x, y, s, t) \
+ GL_ScreenVertices[4*(i) + 0] = x; \
+ GL_ScreenVertices[4*(i) + 1] = y; \
+ GL_ScreenVertices[4*(i) + 2] = s; \
+ GL_ScreenVertices[4*(i) + 3] = t;
+
+ x0 = TopScreenRect.X;
+ y0 = TopScreenRect.Y;
+ x1 = TopScreenRect.X + TopScreenRect.Width;
+ y1 = TopScreenRect.Y + TopScreenRect.Height;
+
+ switch (ScreenRotation)
+ {
+ case 0:
+ s0 = 0; t0 = 0;
+ s1 = scwidth; t1 = 0;
+ s2 = 0; t2 = scheight;
+ s3 = scwidth; t3 = scheight;
+ break;
+
+ case 1:
+ s0 = 0; t0 = scheight;
+ s1 = 0; t1 = 0;
+ s2 = scwidth; t2 = scheight;
+ s3 = scwidth; t3 = 0;
+ break;
+
+ case 2:
+ s0 = scwidth; t0 = scheight;
+ s1 = 0; t1 = scheight;
+ s2 = scwidth; t2 = 0;
+ s3 = 0; t3 = 0;
+ break;
+
+ case 3:
+ s0 = scwidth; t0 = 0;
+ s1 = scwidth; t1 = scheight;
+ s2 = 0; t2 = 0;
+ s3 = 0; t3 = scheight;
+ break;
+ }
+
+ SETVERTEX(0, x0, y0, s0, t0);
+ SETVERTEX(1, x1, y1, s3, t3);
+ SETVERTEX(2, x1, y0, s1, t1);
+ SETVERTEX(3, x0, y0, s0, t0);
+ SETVERTEX(4, x0, y1, s2, t2);
+ SETVERTEX(5, x1, y1, s3, t3);
+
+ // TODO: adjust scwidth/scheight
+
+ x0 = BottomScreenRect.X;
+ y0 = BottomScreenRect.Y;
+ x1 = BottomScreenRect.X + BottomScreenRect.Width;
+ y1 = BottomScreenRect.Y + BottomScreenRect.Height;
+
+ switch (ScreenRotation)
+ {
+ case 0:
+ s0 = 0; t0 = 768;
+ s1 = scwidth; t1 = 768;
+ s2 = 0; t2 = 768+scheight;
+ s3 = scwidth; t3 = 768+scheight;
+ break;
+
+ case 1:
+ s0 = 0; t0 = 768+scheight;
+ s1 = 0; t1 = 768;
+ s2 = scwidth; t2 = 768+scheight;
+ s3 = scwidth; t3 = 768;
+ break;
+
+ case 2:
+ s0 = scwidth; t0 = 768+scheight;
+ s1 = 0; t1 = 768+scheight;
+ s2 = scwidth; t2 = 768;
+ s3 = 0; t3 = 768;
+ break;
+
+ case 3:
+ s0 = scwidth; t0 = 768;
+ s1 = scwidth; t1 = 768+scheight;
+ s2 = 0; t2 = 768;
+ s3 = 0; t3 = 768+scheight;
+ break;
+ }
+
+ SETVERTEX(6, x0, y0, s0, t0);
+ SETVERTEX(7, x1, y1, s3, t3);
+ SETVERTEX(8, x1, y0, s1, t1);
+ SETVERTEX(9, x0, y0, s0, t0);
+ SETVERTEX(10, x0, y1, s2, t2);
+ SETVERTEX(11, x1, y1, s3, t3);
+
+#undef SETVERTEX
+
+ glBindBuffer(GL_ARRAY_BUFFER, GL_ScreenVertexBufferID);
+ glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(GL_ScreenVertices), GL_ScreenVertices);
+ }
+
+ glDisable(GL_DEPTH_TEST);
+ glDisable(GL_BLEND);
+
+ glViewport(0, 0, WindowWidth, WindowHeight);
+
+ OpenGL_UseShaderProgram(GL_ScreenShader);
+
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
+ glClearColor(0, 1, 0, 1);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ int frontbuf = GPU::FrontBuffer;
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, GL_ScreenTexture);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 512, 384, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE, GPU::Framebuffer[frontbuf][0]);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 768, 512, 384, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE, GPU::Framebuffer[frontbuf][1]);
+
+ glBindBuffer(GL_ARRAY_BUFFER, GL_ScreenVertexBufferID);
+ glBindVertexArray(GL_ScreenVertexArrayID);
+ glDrawArrays(GL_TRIANGLES, 0, 4*3);
+
+ uiGLSwapBuffers(GLContext);
+ uiAreaQueueRedrawAll(MainDrawArea);
+}
+
void MicLoadWav(char* name)
{
SDL_AudioSpec format;
@@ -397,6 +611,8 @@ void FeedMicInput()
int EmuThreadFunc(void* burp)
{
uiGLMakeContextCurrent(GLContext);
+ GLDrawing_Init();
+
NDS::Init();
MainScreenPos[0] = 0;
@@ -567,7 +783,9 @@ int EmuThreadFunc(void* burp)
if (EmuRunning == 0) break;
- uiAreaQueueRedrawAll(MainDrawArea);
+ GLDrawing_DrawScreen();
+
+ //uiAreaQueueRedrawAll(MainDrawArea);
//uiGLSwapBuffers(GLContext);
// framerate limiter based off SDL2_gfx
@@ -622,6 +840,7 @@ int EmuThreadFunc(void* burp)
{
//uiAreaQueueRedrawAll(MainDrawArea);
//uiGLSwapBuffers(GLContext);
+ GLDrawing_DrawScreen();
}
EmuStatus = EmuRunning;
@@ -637,6 +856,8 @@ int EmuThreadFunc(void* burp)
NDS::DeInit();
Platform::LAN_DeInit();
+ GLDrawing_DeInit();
+
return 44203;
}
@@ -1058,6 +1279,8 @@ void SetupScreenRects(int width, int height)
}
break;
}
+
+ GL_ScreenSizeDirty = true;
}
void SetMinSize(int w, int h)
@@ -2063,7 +2286,7 @@ int main(int argc, char** argv)
areahandler.Resize = OnAreaResize;
ScreenDrawInited = false;
- MainDrawArea = uiNewArea(&areahandler, 0);
+ MainDrawArea = uiNewArea(&areahandler, 1);
uiWindowSetChild(MainWindow, uiControl(MainDrawArea));
uiControlSetMinSize(uiControl(MainDrawArea), 256, 384);
uiAreaSetBackgroundColor(MainDrawArea, 0, 0, 0); // TODO: make configurable?
diff --git a/src/libui_sdl/main_shaders.h b/src/libui_sdl/main_shaders.h
new file mode 100644
index 00000000..dcf79d9c
--- /dev/null
+++ b/src/libui_sdl/main_shaders.h
@@ -0,0 +1,72 @@
+/*
+ Copyright 2016-2019 Arisotura
+
+ This file is part of melonDS.
+
+ melonDS is free software: you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free
+ Software Foundation, either version 3 of the License, or (at your option)
+ any later version.
+
+ melonDS is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with melonDS. If not, see http://www.gnu.org/licenses/.
+*/
+
+#ifndef MAIN_SHADERS_H
+#define MAIN_SHADERS_H
+
+const char* kScreenVS = R"(#version 420
+
+layout(std140, binding=0) uniform uConfig
+{
+ vec2 uScreenSize;
+ uint uFilterMode;
+};
+
+layout(location=0) in vec2 vPosition;
+layout(location=1) in vec2 vTexcoord;
+
+smooth out vec2 fTexcoord;
+
+void main()
+{
+ vec4 fpos;
+ fpos.xy = ((vPosition.xy * 2.0) / uScreenSize) - 1.0;
+ fpos.y *= -1;
+ fpos.z = 0.0;
+ fpos.w = 1.0;
+
+ gl_Position = fpos;
+ fTexcoord = vTexcoord;
+}
+)";
+
+const char* kScreenFS = R"(#version 420
+
+layout(std140, binding=0) uniform uConfig
+{
+ vec2 uScreenSize;
+ uint uFilterMode;
+};
+
+layout(binding=0) uniform usampler2D ScreenTex;
+
+smooth in vec2 fTexcoord;
+
+layout(location=0) out vec4 oColor;
+
+void main()
+{
+ uvec4 pixel = texelFetch(ScreenTex, ivec2(fTexcoord), 0);
+
+ // TODO: filters
+
+ oColor = vec4(vec3(pixel.bgr) / 255.0, 1.0);
+}
+)";
+
+#endif // MAIN_SHADERS_H