diff --git a/src/common/common.vcxproj b/src/common/common.vcxproj
index c519cc6bd..78d323a51 100644
--- a/src/common/common.vcxproj
+++ b/src/common/common.vcxproj
@@ -43,6 +43,8 @@
+
+
@@ -59,6 +61,8 @@
+
+
diff --git a/src/common/common.vcxproj.filters b/src/common/common.vcxproj.filters
index 51f685c13..385089087 100644
--- a/src/common/common.vcxproj.filters
+++ b/src/common/common.vcxproj.filters
@@ -17,6 +17,8 @@
+
+
@@ -31,6 +33,8 @@
+
+
diff --git a/src/common/gl_program.cpp b/src/common/gl_program.cpp
new file mode 100644
index 000000000..913b4d514
--- /dev/null
+++ b/src/common/gl_program.cpp
@@ -0,0 +1,171 @@
+#include "gl_program.h"
+#include "YBaseLib/Log.h"
+#include
+Log_SetChannel(GL);
+
+namespace GL {
+
+Program::Program() = default;
+
+Program::~Program()
+{
+ Destroy();
+}
+
+GLuint Program::CompileShader(GLenum type, const char* source)
+{
+ GLuint id = glCreateShader(type);
+
+ std::array sources = {{source}};
+ std::array source_lengths = {{static_cast(std::strlen(source))}};
+ glShaderSource(id, static_cast(sources.size()), sources.data(), source_lengths.data());
+ glCompileShader(id);
+
+ GLint status = GL_FALSE;
+ glGetShaderiv(id, GL_COMPILE_STATUS, &status);
+
+ GLint info_log_length = 0;
+ glGetShaderiv(id, GL_INFO_LOG_LENGTH, &info_log_length);
+
+ if (status == GL_FALSE || info_log_length > 0)
+ {
+ std::string info_log;
+ info_log.resize(info_log_length + 1);
+ glGetShaderInfoLog(id, info_log_length, &info_log_length, &info_log[0]);
+
+ if (status == GL_TRUE)
+ {
+ Log_ErrorPrintf("Shader compiled with warnings:\n%s", info_log.c_str());
+ }
+ else
+ {
+ Log_ErrorPrintf("Shader failed to compile:\n%s", info_log.c_str());
+ glDeleteShader(id);
+ return 0;
+ }
+ }
+
+ return id;
+}
+
+bool Program::Compile(const char* vertex_shader, const char* fragment_shader)
+{
+ GLuint vertex_shader_id = CompileShader(GL_VERTEX_SHADER, vertex_shader);
+ if (vertex_shader_id == 0)
+ return false;
+
+ GLuint fragment_shader_id = CompileShader(GL_FRAGMENT_SHADER, fragment_shader);
+ if (fragment_shader_id == 0)
+ {
+ glDeleteShader(vertex_shader_id);
+ return false;
+ }
+
+ m_program_id = glCreateProgram();
+ glAttachShader(m_program_id, vertex_shader_id);
+ glAttachShader(m_program_id, fragment_shader_id);
+ return true;
+}
+
+void Program::BindAttribute(GLuint index, const char* name)
+{
+ glBindAttribLocation(m_program_id, index, name);
+}
+
+void Program::BindDefaultAttributes()
+{
+ BindAttribute(0, "a_position");
+ BindAttribute(1, "a_texcoord");
+ BindAttribute(2, "a_color");
+}
+
+void Program::BindFragData(GLuint index /*= 0*/, const char* name /*= "ocol0"*/)
+{
+ glBindFragDataLocation(m_program_id, index, name);
+}
+
+bool Program::Link()
+{
+ glLinkProgram(m_program_id);
+
+ glDeleteShader(m_vertex_shader_id);
+ m_vertex_shader_id = 0;
+ glDeleteShader(m_fragment_shader_id);
+ m_fragment_shader_id = 0;
+
+ GLint status = GL_FALSE;
+ glGetProgramiv(m_program_id, GL_LINK_STATUS, &status);
+
+ GLint info_log_length = 0;
+ glGetProgramiv(m_program_id, GL_INFO_LOG_LENGTH, &info_log_length);
+
+ if (status == GL_FALSE || info_log_length > 0)
+ {
+ std::string info_log;
+ info_log.resize(info_log_length + 1);
+ glGetProgramInfoLog(m_program_id, info_log_length, &info_log_length, &info_log[0]);
+
+ if (status == GL_TRUE)
+ {
+ Log_ErrorPrintf("Program linked with warnings:\n%s", info_log.c_str());
+ }
+ else
+ {
+ Log_ErrorPrintf("Program failed to link:\n%s", info_log.c_str());
+ glDeleteProgram(m_program_id);
+ m_program_id = 0;
+ return false;
+ }
+ }
+
+ return true;
+}
+
+void Program::Bind()
+{
+ glUseProgram(m_program_id);
+}
+
+void Program::Destroy()
+{
+ if (m_vertex_shader_id != 0)
+ {
+ glDeleteShader(m_vertex_shader_id);
+ m_vertex_shader_id = 0;
+ }
+ if (m_fragment_shader_id != 0)
+ {
+ glDeleteShader(m_fragment_shader_id);
+ m_fragment_shader_id = 0;
+ }
+ if (m_program_id != 0)
+ {
+ glDeleteProgram(m_program_id);
+ m_program_id = 0;
+ }
+}
+
+u32 Program::RegisterUniform(const char* name)
+{
+ u32 id = static_cast(m_uniform_locations.size());
+ m_uniform_locations.push_back(glGetUniformLocation(m_program_id, name));
+ return id;
+}
+
+void Program::Uniform1ui(u32 index, u32 value)
+{
+ Assert(index < m_uniform_locations.size());
+ const int location = m_uniform_locations[index];
+ if (location >= 0)
+ glUniform1ui(location, value);
+}
+
+void Program::Uniform4f(u32 index, float x, float y, float z, float w)
+{
+ Assert(index < m_uniform_locations.size());
+ const int location = m_uniform_locations[index];
+ if (location >= 0)
+ glUniform4f(location, x, y, z, w);
+}
+
+} // namespace GL
\ No newline at end of file
diff --git a/src/common/gl_program.h b/src/common/gl_program.h
new file mode 100644
index 000000000..bd97de244
--- /dev/null
+++ b/src/common/gl_program.h
@@ -0,0 +1,42 @@
+#pragma once
+#include "glad.h"
+#include "types.h"
+#include
+
+namespace GL {
+class Program
+{
+public:
+ Program();
+ ~Program();
+
+ static GLuint CompileShader(GLenum type, const char* source);
+
+ bool IsVaild() const { return m_program_id != 0; }
+
+ bool Compile(const char* vertex_shader, const char* fragment_shader);
+
+ void BindAttribute(GLuint index, const char* name);
+ void BindDefaultAttributes();
+
+ void BindFragData(GLuint index = 0, const char* name = "ocol0");
+
+ bool Link();
+
+ void Bind();
+
+ void Destroy();
+
+ u32 RegisterUniform(const char* name);
+ void Uniform1ui(u32 index, u32 value);
+ void Uniform4f(u32 index, float x, float y, float z, float w);
+
+private:
+ GLuint m_program_id = 0;
+ GLuint m_vertex_shader_id = 0;
+ GLuint m_fragment_shader_id = 0;
+
+ std::vector m_uniform_locations;
+};
+
+} // namespace GL
\ No newline at end of file
diff --git a/src/common/gl_texture.cpp b/src/common/gl_texture.cpp
new file mode 100644
index 000000000..7640b26c7
--- /dev/null
+++ b/src/common/gl_texture.cpp
@@ -0,0 +1,29 @@
+#include "gl_texture.h"
+#include "YBaseLib/Log.h"
+Log_SetChannel(GL);
+
+namespace GL {
+
+Texture::Texture(u32 width, u32 height, GLenum format, GLenum type, const void* data /* = nullptr */,
+ bool linear_filter /* = false */)
+ : m_width(width), m_height(height)
+{
+ glGenTextures(1, &m_id);
+ glBindTexture(GL_TEXTURE_2D, m_id);
+ glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, type, data);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, linear_filter ? GL_LINEAR : GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, linear_filter ? GL_LINEAR : GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1);
+}
+
+Texture::~Texture()
+{
+ glDeleteTextures(1, &m_id);
+}
+
+void Texture::Bind()
+{
+ glBindTexture(GL_TEXTURE_2D, m_id);
+}
+
+} // namespace GL
\ No newline at end of file
diff --git a/src/common/gl_texture.h b/src/common/gl_texture.h
new file mode 100644
index 000000000..4e4e56d17
--- /dev/null
+++ b/src/common/gl_texture.h
@@ -0,0 +1,24 @@
+#pragma once
+#include "glad.h"
+#include "types.h"
+
+namespace GL {
+class Texture
+{
+public:
+ Texture(u32 width, u32 height, GLenum format, GLenum type, const void* data = nullptr, bool linear_filter = false);
+ ~Texture();
+
+ GLuint GetGLId() const { return m_id; }
+ u32 GetWidth() const { return m_width; }
+ u32 GetHeight() const { return m_height; }
+
+ void Bind();
+
+private:
+ GLuint m_id;
+ u32 m_width;
+ u32 m_height;
+};
+
+} // namespace GL
\ No newline at end of file
diff --git a/src/pse-sdl/main.cpp b/src/pse-sdl/main.cpp
index b985ba0f2..5783dc7df 100644
--- a/src/pse-sdl/main.cpp
+++ b/src/pse-sdl/main.cpp
@@ -7,6 +7,7 @@
#include
#include
+#if 0
static int NoGUITest()
{
std::unique_ptr system = std::make_unique();
@@ -19,14 +20,17 @@ static int NoGUITest()
system->RunFrame();
return 0;
}
+#endif
static int Run(int argc, char* argv[])
{
+#if 0
if (argc < 2)
{
std::fprintf(stderr, "Usage: %s [save state index]\n", argv[0]);
return -1;
}
+#endif
// init sdl
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0)
@@ -48,7 +52,7 @@ static int Run(int argc, char* argv[])
s32 state_index = -1;
if (argc > 2)
state_index = StringConverter::StringToInt32(argv[2]);
- if (!host_interface->InitializeSystem(argv[1], state_index))
+ if (!host_interface->InitializeSystem("", state_index))
{
host_interface.reset();
SDL_Quit();
@@ -79,6 +83,6 @@ int main(int argc, char* argv[])
g_pLog->SetFilterLevel(LOGLEVEL_DEBUG);
#endif
- return NoGUITest();
- //return Run(argc, argv);
+ //return NoGUITest();
+ return Run(argc, argv);
}
diff --git a/src/pse-sdl/sdl_interface.cpp b/src/pse-sdl/sdl_interface.cpp
index 39cb95eda..d8554034b 100644
--- a/src/pse-sdl/sdl_interface.cpp
+++ b/src/pse-sdl/sdl_interface.cpp
@@ -1,181 +1,162 @@
#include "sdl_interface.h"
#include "YBaseLib/ByteStream.h"
#include "YBaseLib/Error.h"
-#include "common/display_renderer_d3d.h"
+#include "YBaseLib/Log.h"
#include "imgui.h"
#include "imgui_impl_opengl3.h"
#include "imgui_impl_sdl.h"
#include "pse/system.h"
-#include
#include
#include
-#ifdef Y_COMPILER_MSVC
-#include "imgui_impl_dx11.h"
-#include
-#endif
+Log_SetChannel(SDLInterface);
-SDLInterface::SDLInterface(SDL_Window* window, std::unique_ptr display_renderer,
- std::unique_ptr mixer)
- : m_window(window), m_display_renderer(std::move(display_renderer)), m_mixer(std::move(mixer))
-{
-}
+SDLInterface::SDLInterface() = default;
SDLInterface::~SDLInterface()
{
- m_mixer.reset();
-
- switch (m_display_renderer->GetBackendType())
+ if (m_gl_context)
{
-#ifdef Y_COMPILER_MSVC
- case DisplayRenderer::BackendType::Direct3D:
- {
- ImGui_ImplDX11_Shutdown();
- ImGui::DestroyContext();
- m_display_renderer.reset();
- }
- break;
-#endif
+ if (m_display_vao != 0)
+ glDeleteVertexArrays(1, &m_display_vao);
- case DisplayRenderer::BackendType::OpenGL:
- {
- SDL_GLContext context = SDL_GL_GetCurrentContext();
- ImGui_ImplOpenGL3_Shutdown();
- ImGui_ImplSDL2_Shutdown();
- ImGui::DestroyContext();
- m_display_renderer.reset();
- SDL_GL_MakeCurrent(nullptr, nullptr);
- SDL_GL_DeleteContext(context);
- }
- break;
-
- default:
- {
-
- ImGui::DestroyContext();
- m_display_renderer.reset();
- }
- break;
+ m_display_program.Destroy();
+ ImGui_ImplOpenGL3_Shutdown();
+ ImGui_ImplSDL2_Shutdown();
+ ImGui::DestroyContext();
+ SDL_GL_MakeCurrent(nullptr, nullptr);
+ SDL_GL_DeleteContext(m_gl_context);
}
+
+ if (m_window)
+ SDL_DestroyWindow(m_window);
}
-std::unique_ptr SDLInterface::Create(
- DisplayRenderer::BackendType display_renderer_backend /* = DisplayRenderer::GetDefaultBackendType() */)
+bool SDLInterface::CreateSDLWindow()
{
constexpr u32 DEFAULT_WINDOW_WIDTH = 900;
constexpr u32 DEFAULT_WINDOW_HEIGHT = 700;
- constexpr u32 MAIN_MENU_BAR_HEIGHT = 20;
// Create window.
- u32 window_flags = SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI;
- if (display_renderer_backend == DisplayRenderer::BackendType::OpenGL)
- window_flags |= SDL_WINDOW_OPENGL;
+ constexpr u32 window_flags = SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_OPENGL;
- auto window = std::unique_ptr(
- SDL_CreateWindow("PCE - Initializing...", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, DEFAULT_WINDOW_WIDTH,
- DEFAULT_WINDOW_HEIGHT, window_flags),
- [](SDL_Window* win) { SDL_DestroyWindow(win); });
- if (!window)
+ m_window = SDL_CreateWindow("Some idea to emulate a system starting with a P", SDL_WINDOWPOS_UNDEFINED,
+ SDL_WINDOWPOS_UNDEFINED, DEFAULT_WINDOW_WIDTH, DEFAULT_WINDOW_HEIGHT, window_flags);
+ if (!m_window)
{
Panic("Failed to create window");
- return nullptr;
+ return false;
}
- DisplayRenderer::WindowHandleType window_handle = nullptr;
- if (display_renderer_backend == DisplayRenderer::BackendType::OpenGL)
+ SDL_GetWindowSize(m_window, &m_window_width, &m_window_height);
+ return true;
+}
+
+static void APIENTRY GLDebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length,
+ const GLchar* message, const void* userParam)
+{
+ Log_InfoPrintf("%s", message);
+}
+
+bool SDLInterface::CreateGLContext()
+{
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG);
+ m_gl_context = SDL_GL_CreateContext(m_window);
+ if (!m_gl_context || SDL_GL_MakeCurrent(m_window, m_gl_context) != 0 || !gladLoadGL())
{
- // We need a GL context. TODO: Move this to common.
- SDL_GLContext gl_context = SDL_GL_CreateContext(window.get());
- if (!gl_context || SDL_GL_MakeCurrent(window.get(), gl_context) != 0 || !gladLoadGL())
- {
- Panic("Failed to create GL context");
- return nullptr;
- }
+ Panic("Failed to create GL context");
+ return false;
}
-#ifdef Y_COMPILER_MSVC
- if (display_renderer_backend == DisplayRenderer::BackendType::Direct3D)
+
+ if (GLAD_GL_KHR_debug)
{
- // Get window handle from SDL window
- SDL_SysWMinfo info = {};
- SDL_VERSION(&info.version);
- if (!SDL_GetWindowWMInfo(window.get(), &info))
- {
- Panic("SDL_GetWindowWMInfo failed");
- return nullptr;
- }
-
- window_handle = info.info.win.window;
- }
-#endif
-
- // Create renderer.
- auto display_renderer =
- DisplayRenderer::Create(display_renderer_backend, window_handle, DEFAULT_WINDOW_WIDTH, DEFAULT_WINDOW_HEIGHT);
- if (!display_renderer)
- {
- Panic("Failed to create display");
- return nullptr;
- }
- display_renderer->SetTopPadding(MAIN_MENU_BAR_HEIGHT);
-
- // Create audio renderer.
- auto mixer = MixerType::Create();
- if (!mixer)
- {
- Panic("Failed to create audio mixer");
- return nullptr;
+ glad_glDebugMessageCallbackKHR(GLDebugCallback, nullptr);
+ glEnable(GL_DEBUG_OUTPUT);
+ glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
}
- // Initialize imgui.
+ return true;
+}
+
+bool SDLInterface::CreateImGuiContext()
+{
ImGui::CreateContext();
ImGui::GetIO().IniFilename = nullptr;
- switch (display_renderer->GetBackendType())
- {
-#ifdef Y_COMPILER_MSVC
- case DisplayRenderer::BackendType::Direct3D:
- {
- if (!ImGui_ImplSDL2_InitForD3D(window.get()) ||
- !ImGui_ImplDX11_Init(static_cast(display_renderer.get())->GetD3DDevice(),
- static_cast(display_renderer.get())->GetD3DContext()))
- {
- return nullptr;
- }
+ if (!ImGui_ImplSDL2_InitForOpenGL(m_window, m_gl_context) || !ImGui_ImplOpenGL3_Init())
+ return false;
- ImGui_ImplDX11_NewFrame();
- ImGui_ImplSDL2_NewFrame(window.get());
- ImGui::NewFrame();
- }
- break;
-#endif
-
- case DisplayRenderer::BackendType::OpenGL:
- {
- if (!ImGui_ImplSDL2_InitForOpenGL(window.get(), SDL_GL_GetCurrentContext()) || !ImGui_ImplOpenGL3_Init())
- return nullptr;
-
- ImGui_ImplOpenGL3_NewFrame();
- ImGui_ImplSDL2_NewFrame(window.get());
- ImGui::NewFrame();
- }
- break;
-
- default:
- break;
- }
-
- return std::make_unique(window.release(), std::move(display_renderer), std::move(mixer));
+ ImGui_ImplOpenGL3_NewFrame();
+ ImGui_ImplSDL2_NewFrame(m_window);
+ ImGui::NewFrame();
+ return true;
}
-TinyString SDLInterface::GetSaveStateFilename(u32 index)
+bool SDLInterface::CreateGLResources()
{
- return TinyString::FromFormat("savestate_%u.bin", index);
+ static constexpr char fullscreen_quad_vertex_shader[] = R"(
+#version 330 core
+
+out vec2 v_tex0;
+
+void main()
+{
+ v_tex0 = vec2(float((gl_VertexID << 1) & 2), float(gl_VertexID & 2));
+ gl_Position = vec4(v_tex0 * vec2(2.0f, -2.0f) + vec2(-1.0f, 1.0f), 0.0f, 1.0f);
+ gl_Position.y = -gl_Position.y;
}
+)";
+
+ static constexpr char display_fragment_shader[] = R"(
+#version 330 core
+
+uniform sampler2D samp0;
+
+in vec2 v_tex0;
+out vec4 ocol0;
+
+void main()
+{
+ ocol0 = texture(samp0, v_tex0);
+}
+)";
+
+ if (!m_display_program.Compile(fullscreen_quad_vertex_shader, display_fragment_shader))
+ return false;
+
+ m_display_program.BindFragData();
+ if (!m_display_program.Link())
+ return false;
+
+ m_display_program.RegisterUniform("samp0");
+ m_display_program.Bind();
+ m_display_program.Uniform1ui(0, 0);
+
+ glGenVertexArrays(1, &m_display_vao);
+ return true;
+}
+
+std::unique_ptr SDLInterface::Create()
+{
+ std::unique_ptr intf = std::make_unique();
+ if (!intf->CreateSDLWindow() || !intf->CreateGLContext() || !intf->CreateImGuiContext() || !intf->CreateGLResources())
+ return nullptr;
+
+ return intf;
+}
+
+// TinyString SDLInterface::GetSaveStateFilename(u32 index)
+// {
+// return TinyString::FromFormat("savestate_%u.bin", index);
+// }
bool SDLInterface::InitializeSystem(const char* filename, s32 save_state_index /* = -1 */)
{
Error error;
- m_system = std::make_unique();
+ m_system = std::make_unique(this);
if (!m_system->Initialize())
{
m_system.reset();
@@ -194,6 +175,8 @@ bool SDLInterface::InitializeSystem(const char* filename, s32 save_state_index /
}
#endif
+ m_system->Reset();
+
// Resume execution.
m_running = true;
return true;
@@ -232,88 +215,13 @@ bool SDLInterface::HandleSDLEvent(const SDL_Event* event)
switch (event->type)
{
-#if 0
- case SDL_MOUSEBUTTONDOWN:
- {
- u32 button = SDLButtonToHostButton(event->button.button);
- if (IsMouseGrabbed())
- {
- ExecuteMouseButtonChangeCallbacks(button, true);
- return true;
- }
- }
- break;
-
- case SDL_MOUSEBUTTONUP:
- {
- u32 button = SDLButtonToHostButton(event->button.button);
- if (IsMouseGrabbed())
- {
- ExecuteMouseButtonChangeCallbacks(button, false);
- return true;
- }
- else
- {
- // Are we capturing the mouse?
- if (button == 0)
- GrabMouse();
- }
- }
- break;
-
- case SDL_MOUSEMOTION:
- {
- if (!IsMouseGrabbed())
- return false;
-
- s32 dx = event->motion.xrel;
- s32 dy = event->motion.yrel;
- ExecuteMousePositionChangeCallbacks(dx, dy);
- return true;
- }
- break;
-
- case SDL_KEYDOWN:
- {
- // Release mouse key combination
- if (((event->key.keysym.sym == SDLK_LCTRL || event->key.keysym.sym == SDLK_RCTRL) &&
- (SDL_GetModState() & KMOD_ALT) != 0) ||
- ((event->key.keysym.sym == SDLK_LALT || event->key.keysym.sym == SDLK_RALT) &&
- (SDL_GetModState() & KMOD_CTRL) != 0))
- {
- // But don't consume the key event.
- ReleaseMouse();
- }
-
- // Create keyboard event.
- // TODO: Since we have crap in the input polling, we can't return true here.
- GenScanCode scancode;
- if (MapSDLScanCode(&scancode, event->key.keysym.scancode))
- {
- ExecuteKeyboardCallbacks(scancode, true);
- return false;
- }
- }
- break;
-
- case SDL_KEYUP:
- {
- // Create keyboard event.
- // TODO: Since we have crap in the input polling, we can't return true here.
- GenScanCode scancode;
- if (MapSDLScanCode(&scancode, event->key.keysym.scancode))
- {
- ExecuteKeyboardCallbacks(scancode, false);
- return false;
- }
- }
- break;
-#endif
-
case SDL_WINDOWEVENT:
{
if (event->window.event == SDL_WINDOWEVENT_RESIZED)
- m_display_renderer->WindowResized(u32(event->window.data1), u32(event->window.data2));
+ {
+ m_window_width = event->window.data1;
+ m_window_height = event->window.data2;
+ }
}
break;
@@ -387,44 +295,39 @@ bool SDLInterface::PassEventToImGui(const SDL_Event* event)
void SDLInterface::Render()
{
- if (!m_display_renderer->BeginFrame())
- return;
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+ glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+ glClear(GL_COLOR_BUFFER_BIT);
- m_display_renderer->RenderDisplays();
+ RenderDisplay();
RenderImGui();
- const DisplayRenderer::BackendType backend_type = m_display_renderer->GetBackendType();
- switch (backend_type)
- {
-#ifdef Y_COMPILER_MSVC
- case DisplayRenderer::BackendType::Direct3D:
- {
- ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData());
- m_display_renderer->EndFrame();
- ImGui_ImplSDL2_NewFrame(m_window);
- ImGui_ImplDX11_NewFrame();
- }
- break;
-#endif
+ ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
- case DisplayRenderer::BackendType::OpenGL:
- {
- ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
- m_display_renderer->EndFrame();
- SDL_GL_SwapWindow(m_window);
- ImGui_ImplSDL2_NewFrame(m_window);
- ImGui_ImplOpenGL3_NewFrame();
- }
- break;
+ SDL_GL_SwapWindow(m_window);
- default:
- break;
- }
+ ImGui_ImplSDL2_NewFrame(m_window);
+ ImGui_ImplOpenGL3_NewFrame();
ImGui::NewFrame();
}
+void SDLInterface::RenderDisplay()
+{
+ if (!m_display_texture)
+ return;
+
+ glViewport(0, 0, m_window_width, m_window_height);
+ glDisable(GL_CULL_FACE);
+ glDisable(GL_DEPTH_TEST);
+ glDepthMask(GL_FALSE);
+ m_display_program.Bind();
+ m_display_texture->Bind();
+ glBindVertexArray(m_display_vao);
+ glDrawArrays(GL_TRIANGLES, 0, 3);
+}
+
void SDLInterface::RenderImGui()
{
RenderMainMenuBar();
@@ -499,6 +402,18 @@ void SDLInterface::AddOSDMessage(const char* message, float duration /*= 2.0f*/)
m_osd_messages.push_back(std::move(msg));
}
+void SDLInterface::SetDisplayTexture(GL::Texture* texture, u32 offset_x, u32 offset_y, u32 width, u32 height)
+{
+ m_display_texture = texture;
+ m_display_texture_offset_x = 0;
+ m_display_texture_offset_y = 0;
+ m_display_texture_width = width;
+ m_display_texture_height = height;
+ m_display_texture_changed = true;
+
+ Render();
+}
+
void SDLInterface::RenderOSDMessages()
{
constexpr ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoInputs |
@@ -561,6 +476,8 @@ void SDLInterface::DoSaveState(u32 index)
void SDLInterface::Run()
{
+ Timer last_render_time;
+
while (m_running)
{
for (;;)
@@ -572,8 +489,12 @@ void SDLInterface::Run()
break;
}
- m_system->RunFrame();
- Render();
+ while (!m_display_texture_changed || last_render_time.GetTimeSeconds() < (1.0f / 60.0f))
+ {
+ m_system->RunFrame();
+ }
+
+ // Render();
+ last_render_time.Reset();
}
}
-
diff --git a/src/pse-sdl/sdl_interface.h b/src/pse-sdl/sdl_interface.h
index 9c49c15af..17fed0e41 100644
--- a/src/pse-sdl/sdl_interface.h
+++ b/src/pse-sdl/sdl_interface.h
@@ -1,43 +1,36 @@
#pragma once
-#include "common/display_renderer.h"
-#include "pse-sdl/sdl_audio_mixer.h"
+#include "YBaseLib/String.h"
+#include "YBaseLib/Timer.h"
+#include "common/gl_program.h"
+#include "common/gl_texture.h"
+#include "pse/host_interface.h"
+#include
#include
#include
#include
-struct SDL_Window;
-union SDL_Event;
-
class System;
-class SDLInterface
+class SDLInterface : public HostInterface
{
public:
- using MixerType = SDLAudioMixer;
- // using MixerType = Audio::NullMixer;
-
- SDLInterface(SDL_Window* window, std::unique_ptr display_renderer,
- std::unique_ptr mixer);
+ SDLInterface();
~SDLInterface();
- static std::unique_ptr
- Create(DisplayRenderer::BackendType display_renderer_backend = DisplayRenderer::GetDefaultBackendType());
+ static std::unique_ptr Create();
- static TinyString GetSaveStateFilename(u32 index);
+ void SetDisplayTexture(GL::Texture* texture, u32 offset_x, u32 offset_y, u32 width, u32 height) override;
- bool InitializeSystem(const char* filename, s32 save_state_index = -1);
+ void ReportMessage(const char* message) override;
- DisplayRenderer* GetDisplayRenderer() const { return m_display_renderer.get(); }
- Audio::Mixer* GetAudioMixer() const { return m_mixer.get(); }
+ // Adds OSD messages, duration is in seconds.
+ void AddOSDMessage(const char* message, float duration = 2.0f) override;
- void ReportMessage(const char* message);
+ bool InitializeSystem(const char* filename, s32 save_state_index /* = -1 */);
void Run();
- // Adds OSD messages, duration is in seconds.
- void AddOSDMessage(const char* message, float duration = 2.0f);
-
-protected:
+private:
struct OSDMessage
{
String text;
@@ -45,6 +38,11 @@ protected:
float duration;
};
+ bool CreateSDLWindow();
+ bool CreateGLContext();
+ bool CreateImGuiContext();
+ bool CreateGLResources();
+
// We only pass mouse input through if it's grabbed
bool IsWindowFullscreen() const;
void RenderImGui();
@@ -54,14 +52,24 @@ protected:
bool HandleSDLEvent(const SDL_Event* event);
bool PassEventToImGui(const SDL_Event* event);
void Render();
+ void RenderDisplay();
void RenderMainMenuBar();
void RenderOSDMessages();
- SDL_Window* m_window;
+ SDL_Window* m_window = nullptr;
+ SDL_GLContext m_gl_context = nullptr;
+ int m_window_width = 0;
+ int m_window_height = 0;
- std::unique_ptr m_display_renderer;
- std::unique_ptr m_mixer;
std::unique_ptr m_system;
+ GL::Program m_display_program;
+ GLuint m_display_vao = 0;
+ GL::Texture* m_display_texture = nullptr;
+ u32 m_display_texture_offset_x = 0;
+ u32 m_display_texture_offset_y = 0;
+ u32 m_display_texture_width = 0;
+ u32 m_display_texture_height = 0;
+ bool m_display_texture_changed = false;
std::deque m_osd_messages;
std::mutex m_osd_messages_lock;
diff --git a/src/pse/gpu.cpp b/src/pse/gpu.cpp
index 7cb0aa03b..61613d73f 100644
--- a/src/pse/gpu.cpp
+++ b/src/pse/gpu.cpp
@@ -8,8 +8,9 @@ GPU::GPU() = default;
GPU::~GPU() = default;
-bool GPU::Initialize(Bus* bus, DMA* dma)
+bool GPU::Initialize(System* system, Bus* bus, DMA* dma)
{
+ m_system = system;
m_bus = bus;
m_dma = dma;
return true;
diff --git a/src/pse/gpu.h b/src/pse/gpu.h
index 7079a3994..252d91278 100644
--- a/src/pse/gpu.h
+++ b/src/pse/gpu.h
@@ -3,6 +3,7 @@
#include "types.h"
#include
+class System;
class Bus;
class DMA;
@@ -12,7 +13,7 @@ public:
GPU();
virtual ~GPU();
- virtual bool Initialize(Bus* bus, DMA* dma);
+ virtual bool Initialize(System* system, Bus* bus, DMA* dma);
virtual void Reset();
u32 ReadRegister(u32 offset);
@@ -101,6 +102,7 @@ protected:
virtual void DispatchRenderCommand(RenderCommand rc, u32 num_vertices);
virtual void FlushRender();
+ System* m_system = nullptr;
Bus* m_bus = nullptr;
DMA* m_dma = nullptr;
diff --git a/src/pse/gpu_hw.cpp b/src/pse/gpu_hw.cpp
index 0acaa93c1..efb2c7b2c 100644
--- a/src/pse/gpu_hw.cpp
+++ b/src/pse/gpu_hw.cpp
@@ -32,6 +32,8 @@ void GPU_HW::LoadVertices(RenderCommand rc, u32 num_vertices)
if (textured)
hw_vert.texcoord = (m_GP0_command[buffer_pos++] & UINT32_C(0x0000FFFF));
+ else
+ hw_vert.texcoord = 0;
m_vertex_staging.push_back(hw_vert);
}
@@ -44,6 +46,22 @@ void GPU_HW::LoadVertices(RenderCommand rc, u32 num_vertices)
}
}
+void GPU_HW::CalcViewport(int* x, int* y, int* width, int* height)
+{
+ *x = m_drawing_offset.x;
+ *y = m_drawing_offset.y;
+ *width = std::max(static_cast(VRAM_WIDTH - m_drawing_offset.x), 1);
+ *height = std::max(static_cast(VRAM_HEIGHT - m_drawing_offset.y), 1);
+}
+
+void GPU_HW::CalcScissorRect(int* left, int* top, int* right, int* bottom)
+{
+ *left = m_drawing_area.top_left_x;
+ *right = m_drawing_area.bottom_right_x;
+ *top = m_drawing_area.top_left_y;
+ *bottom = m_drawing_area.bottom_right_y;
+}
+
std::string GPU_HW::GenerateVertexShader(bool textured)
{
std::stringstream ss;
@@ -54,9 +72,9 @@ std::string GPU_HW::GenerateVertexShader(bool textured)
ss << "/* #define TEXTURED 0 */\n";
ss << R"(
-in uivec2 a_position;
-in uint a_texcoord;
+in ivec2 a_position;
in vec4 a_color;
+in uint a_texcoord;
out vec4 v_color;
#if TEXTURED
@@ -65,14 +83,14 @@ out vec4 v_color;
void main()
{
- // -1024..+1023 -> -1..1
- float gl_x = (a_position.x < 0) ? (float(a_position.x) / 1024.0) : (float(a_position.x) / 1023.0);
- float gl_y = (a_position.y < 0) ? -(float(a_position.y) / 1024.0) : -(float(a_position.y) / 1023.0);
- gl_Position = vec4(gl_x, gl_y, 0.0, 1.0);
+ // 0..+1023 -> -1..1
+ float pos_x = (float(a_position.x) / 511.5) - 1.0;
+ float pos_y = (float(a_position.y) / 255.5) + 1.0;
+ gl_Position = vec4(pos_x, pos_y, 0.0, 1.0);
v_color = a_color;
#if TEXTURED
- v_texcoord = a_texcoord;
+ v_texcoord = vec2(float(a_texcoord & 0xFFu) / 256.0, float((a_texcoord >> 8) & 0xFFu) / 256.0);
#endif
}
)";
@@ -99,8 +117,8 @@ out vec4 ocol0;
void main()
{
- //ocol0 = v_color;
- ocol0 = vec4(1.0, 0.5, 0.5, 1.0);
+ ocol0 = v_color;
+ //ocol0 = vec4(1.0, 0.5, 0.5, 1.0);
}
)";
diff --git a/src/pse/gpu_hw.h b/src/pse/gpu_hw.h
index 227fe5cc3..28b05c405 100644
--- a/src/pse/gpu_hw.h
+++ b/src/pse/gpu_hw.h
@@ -20,6 +20,9 @@ protected:
void LoadVertices(RenderCommand rc, u32 num_vertices);
+ void CalcViewport(int* x, int* y, int* width, int* height);
+ void CalcScissorRect(int* left, int* top, int* right, int* bottom);
+
std::string GenerateVertexShader(bool textured);
std::string GenerateFragmentShader(bool textured);
diff --git a/src/pse/gpu_hw_opengl.cpp b/src/pse/gpu_hw_opengl.cpp
index bd7374dd7..d6f5b20f3 100644
--- a/src/pse/gpu_hw_opengl.cpp
+++ b/src/pse/gpu_hw_opengl.cpp
@@ -1,6 +1,8 @@
#include "gpu_hw_opengl.h"
#include "YBaseLib/Assert.h"
#include "YBaseLib/Log.h"
+#include "host_interface.h"
+#include "system.h"
Log_SetChannel(GPU_HW_OpenGL);
GPU_HW_OpenGL::GPU_HW_OpenGL() : GPU_HW() {}
@@ -10,12 +12,16 @@ GPU_HW_OpenGL::~GPU_HW_OpenGL()
DestroyFramebuffer();
}
-bool GPU_HW_OpenGL::Initialize(Bus* bus, DMA* dma)
+bool GPU_HW_OpenGL::Initialize(System* system, Bus* bus, DMA* dma)
{
- if (!GPU_HW::Initialize(bus, dma))
+ if (!GPU_HW::Initialize(system, bus, dma))
return false;
CreateFramebuffer();
+ CreateVertexBuffer();
+ if (!CompilePrograms())
+ return false;
+
return true;
}
@@ -28,16 +34,12 @@ void GPU_HW_OpenGL::Reset()
void GPU_HW_OpenGL::CreateFramebuffer()
{
- glGenTextures(1, &m_framebuffer_texture_id);
- glBindTexture(GL_TEXTURE_2D, m_framebuffer_texture_id);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, VRAM_WIDTH, VRAM_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1);
+ m_framebuffer_texture =
+ std::make_unique(VRAM_WIDTH, VRAM_HEIGHT, GL_RGBA, GL_UNSIGNED_BYTE, nullptr, false);
glGenFramebuffers(1, &m_framebuffer_fbo_id);
glBindFramebuffer(GL_FRAMEBUFFER, m_framebuffer_fbo_id);
- glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_framebuffer_texture_id, 0);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_framebuffer_texture->GetGLId(), 0);
Assert(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
}
@@ -48,6 +50,8 @@ void GPU_HW_OpenGL::ClearFramebuffer()
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
+
+ m_system->GetHostInterface()->SetDisplayTexture(m_framebuffer_texture.get(), 0, 0, VRAM_WIDTH, VRAM_HEIGHT);
}
void GPU_HW_OpenGL::DestroyFramebuffer()
@@ -55,27 +59,108 @@ void GPU_HW_OpenGL::DestroyFramebuffer()
glDeleteFramebuffers(1, &m_framebuffer_fbo_id);
m_framebuffer_fbo_id = 0;
- glDeleteTextures(1, &m_framebuffer_texture_id);
- m_framebuffer_texture_id = 0;
+ m_framebuffer_texture.reset();
}
+void GPU_HW_OpenGL::CreateVertexBuffer()
+{
+ glGenBuffers(1, &m_vertex_buffer);
+ glBindBuffer(GL_ARRAY_BUFFER, m_vertex_buffer);
+ glBufferData(GL_ARRAY_BUFFER, 128, nullptr, GL_STREAM_DRAW);
+
+ glGenVertexArrays(1, &m_vao_id);
+ glBindVertexArray(m_vao_id);
+ glVertexAttribIPointer(0, 2, GL_INT, sizeof(HWVertex), reinterpret_cast(offsetof(HWVertex, x)));
+ glVertexAttribPointer(1, 4, GL_UNSIGNED_BYTE, true, sizeof(HWVertex),
+ reinterpret_cast(offsetof(HWVertex, color)));
+ glVertexAttribIPointer(2, 1, GL_UNSIGNED_INT, sizeof(HWVertex), reinterpret_cast(offsetof(HWVertex, color)));
+ glEnableVertexAttribArray(0);
+ glEnableVertexAttribArray(1);
+ glEnableVertexAttribArray(2);
+ glBindVertexArray(0);
+}
+
+bool GPU_HW_OpenGL::CompilePrograms()
+{
+ for (u32 texture_enable_i = 0; texture_enable_i < 2; texture_enable_i++)
+ {
+ const bool texture_enable = ConvertToBool(texture_enable_i);
+ const std::string vs = GenerateVertexShader(texture_enable);
+ const std::string fs = GenerateFragmentShader(texture_enable);
+
+ GL::Program& prog = texture_enable ? m_texture_program : m_color_program;
+ if (!prog.Compile(vs.c_str(), fs.c_str()))
+ return false;
+
+ prog.BindAttribute(0, "a_position");
+ prog.BindAttribute(1, "a_color");
+ if (texture_enable)
+ prog.BindAttribute(2, "a_texcoord");
+
+ prog.BindFragData(0, "ocol0");
+
+ if (!prog.Link())
+ return false;
+ }
+
+ return true;
+}
+
+bool GPU_HW_OpenGL::SetProgram(bool texture_enable)
+{
+ GL::Program& prog = texture_enable ? m_texture_program : m_color_program;
+ if (!prog.IsVaild())
+ return false;
+
+ prog.Bind();
+ return true;
+}
+
+void GPU_HW_OpenGL::SetViewport()
+{
+ int x, y, width, height;
+ CalcViewport(&x, &y, &width, &height);
+
+ y = VRAM_HEIGHT - y - height;
+ Log_DebugPrintf("SetViewport: Offset (%d,%d) Size (%d, %d)", x, y, width, height);
+ glViewport(x, y, width, height);
+}
+
+void GPU_HW_OpenGL::SetScissor() {}
+
void GPU_HW_OpenGL::DispatchRenderCommand(RenderCommand rc, u32 num_vertices)
{
LoadVertices(rc, num_vertices);
if (m_vertex_staging.empty())
return;
- glBindFramebuffer(GL_FRAMEBUFFER, m_framebuffer_fbo_id);
+ if (!SetProgram(rc.texture_enable))
+ {
+ Log_ErrorPrintf("Failed to set GL program");
+ m_vertex_staging.clear();
+ return;
+ }
- if (rc.texture_enable)
- m_texture_program.Bind();
- else
- m_color_program.Bind();
+ SetViewport();
+
+ glBindFramebuffer(GL_FRAMEBUFFER, m_framebuffer_fbo_id);
+ glBindVertexArray(m_vao_id);
glBindBuffer(GL_ARRAY_BUFFER, m_vertex_buffer);
glBufferData(GL_ARRAY_BUFFER, static_cast(sizeof(HWVertex) * m_vertex_staging.size()),
m_vertex_staging.data(), GL_STREAM_DRAW);
+ glEnableVertexAttribArray(0);
+ glVertexAttribIPointer(0, 2, GL_INT, sizeof(HWVertex), reinterpret_cast(offsetof(HWVertex, x)));
+ glEnableVertexAttribArray(1);
+ glVertexAttribPointer(1, 4, GL_UNSIGNED_BYTE, true, sizeof(HWVertex),
+ reinterpret_cast(offsetof(HWVertex, color)));
+ glEnableVertexAttribArray(2);
+ glVertexAttribIPointer(2, 1, GL_UNSIGNED_INT, sizeof(HWVertex), reinterpret_cast(offsetof(HWVertex, color)));
+
glDrawArrays(rc.quad_polygon ? GL_TRIANGLE_STRIP : GL_TRIANGLES, 0, static_cast(m_vertex_staging.size()));
+
+ m_system->GetHostInterface()->SetDisplayTexture(m_framebuffer_texture.get(), 0, 0, VRAM_WIDTH, VRAM_HEIGHT);
+ m_vertex_staging.clear();
}
void GPU_HW_OpenGL::FlushRender()
@@ -90,98 +175,3 @@ std::unique_ptr GPU::CreateHardwareOpenGLRenderer()
{
return std::make_unique();
}
-
-void GPU_HW_OpenGL::Program::Bind()
-{
- glUseProgram(program_id);
-}
-
-static GLuint CompileShader(GLenum type, const std::string& source)
-{
- GLuint id = glCreateShader(type);
-
- std::array sources = {{source.c_str()}};
- std::array source_lengths = {{static_cast(source.size())}};
- glShaderSource(id, static_cast(source.size()), sources.data(), source_lengths.data());
-
- GLint status = GL_FALSE;
- glGetShaderiv(id, GL_COMPILE_STATUS, &status);
-
- GLint info_log_length = 0;
- glGetShaderiv(id, GL_INFO_LOG_LENGTH, &info_log_length);
-
- if (status == GL_FALSE || info_log_length > 0)
- {
- std::string info_log;
- info_log.resize(info_log_length + 1);
- glGetShaderInfoLog(id, info_log_length, &info_log_length, info_log.data());
-
- if (status == GL_TRUE)
- {
- Log_ErrorPrintf("Shader compiled with warnings:\n%s", info_log.c_str());
- }
- else
- {
- Log_ErrorPrintf("Shader failed to compile:\n%s", info_log.c_str());
- glDeleteShader(id);
- return 0;
- }
- }
-
- return id;
-}
-
-bool GPU_HW_OpenGL::Program::Compile(const std::string& vertex_shader, const std::string& fragment_shader)
-{
- GLuint vertex_shader_id = CompileShader(GL_VERTEX_SHADER, vertex_shader);
- if (vertex_shader_id == 0)
- return false;
-
- GLuint fragment_shader_id = CompileShader(GL_FRAGMENT_SHADER, fragment_shader);
- if (fragment_shader_id == 0)
- {
- glDeleteShader(vertex_shader_id);
- return false;
- }
-
- program_id = glCreateProgram();
- glAttachShader(program_id, vertex_shader_id);
- glAttachShader(program_id, fragment_shader_id);
-
- glBindAttribLocation(program_id, 0, "a_position");
- glBindAttribLocation(program_id, 1, "a_texcoord");
- glBindAttribLocation(program_id, 2, "a_color");
- glBindFragDataLocation(program_id, 0, "ocol0");
-
- glLinkProgram(program_id);
-
- glDeleteShader(vertex_shader_id);
- glDeleteShader(fragment_shader_id);
-
- GLint status = GL_FALSE;
- glGetProgramiv(program_id, GL_LINK_STATUS, &status);
-
- GLint info_log_length = 0;
- glGetProgramiv(program_id, GL_INFO_LOG_LENGTH, &info_log_length);
-
- if (status == GL_FALSE || info_log_length > 0)
- {
- std::string info_log;
- info_log.resize(info_log_length + 1);
- glGetProgramInfoLog(program_id, info_log_length, &info_log_length, info_log.data());
-
- if (status == GL_TRUE)
- {
- Log_ErrorPrintf("Program linked with warnings:\n%s", info_log.c_str());
- }
- else
- {
- Log_ErrorPrintf("Program failed to link:\n%s", info_log.c_str());
- glDeleteProgram(program_id);
- program_id = 0;
- return false;
- }
- }
-
- return true;
-}
diff --git a/src/pse/gpu_hw_opengl.h b/src/pse/gpu_hw_opengl.h
index 8275c7e87..cdb89403b 100644
--- a/src/pse/gpu_hw_opengl.h
+++ b/src/pse/gpu_hw_opengl.h
@@ -1,7 +1,10 @@
#pragma once
-#include "gpu_hw.h"
+#include "common/gl_program.h"
+#include "common/gl_texture.h"
#include "glad.h"
+#include "gpu_hw.h"
#include
+#include
class GPU_HW_OpenGL : public GPU_HW
{
@@ -9,7 +12,7 @@ public:
GPU_HW_OpenGL();
~GPU_HW_OpenGL() override;
- bool Initialize(Bus* bus, DMA* dma) override;
+ bool Initialize(System* system, Bus* bus, DMA* dma) override;
void Reset() override;
protected:
@@ -23,22 +26,18 @@ private:
void CreateVertexBuffer();
- GLuint m_framebuffer_texture_id = 0;
+ bool CompilePrograms();
+
+ bool SetProgram(bool texture_enable);
+ void SetViewport();
+ void SetScissor();
+
+ std::unique_ptr m_framebuffer_texture;
GLuint m_framebuffer_fbo_id = 0;
GLuint m_vertex_buffer = 0;
GLuint m_vao_id = 0;
- struct Program
- {
- GLuint program_id = 0;
-
- bool IsValid() const { return program_id != 0; }
- void Bind();
- bool Compile(const std::string& vertex_shader, const std::string& fragment_shader);
- };
-
- Program m_texture_program;
- Program m_color_program;
+ GL::Program m_texture_program;
+ GL::Program m_color_program;
};
-
diff --git a/src/pse/host_interface.h b/src/pse/host_interface.h
new file mode 100644
index 000000000..cd571a034
--- /dev/null
+++ b/src/pse/host_interface.h
@@ -0,0 +1,16 @@
+#pragma once
+#include "types.h"
+
+namespace GL {
+class Texture;
+}
+
+class HostInterface
+{
+public:
+ virtual void SetDisplayTexture(GL::Texture* texture, u32 offset_x, u32 offset_y, u32 width, u32 height) = 0;
+ virtual void ReportMessage(const char* message) = 0;
+
+ // Adds OSD messages, duration is in seconds.
+ virtual void AddOSDMessage(const char* message, float duration = 2.0f) = 0;
+};
diff --git a/src/pse/pse.vcxproj b/src/pse/pse.vcxproj
index 3cfb8382b..266d913ab 100644
--- a/src/pse/pse.vcxproj
+++ b/src/pse/pse.vcxproj
@@ -53,6 +53,7 @@
+
diff --git a/src/pse/pse.vcxproj.filters b/src/pse/pse.vcxproj.filters
index 3aff24430..41b27a8b9 100644
--- a/src/pse/pse.vcxproj.filters
+++ b/src/pse/pse.vcxproj.filters
@@ -22,6 +22,7 @@
+
diff --git a/src/pse/system.cpp b/src/pse/system.cpp
index 81daff37e..c255e09e5 100644
--- a/src/pse/system.cpp
+++ b/src/pse/system.cpp
@@ -4,13 +4,13 @@
#include "dma.h"
#include "gpu.h"
-System::System()
+System::System(HostInterface* host_interface) : m_host_interface(host_interface)
{
m_cpu = std::make_unique();
m_bus = std::make_unique();
m_dma = std::make_unique();
- m_gpu = std::make_unique();
- // m_gpu = GPU::CreateHardwareOpenGLRenderer();
+ // m_gpu = std::make_unique();
+ m_gpu = GPU::CreateHardwareOpenGLRenderer();
}
System::~System() = default;
@@ -26,7 +26,7 @@ bool System::Initialize()
if (!m_dma->Initialize(m_bus.get(), m_gpu.get()))
return false;
- if (!m_gpu->Initialize(m_bus.get(), m_dma.get()))
+ if (!m_gpu->Initialize(this, m_bus.get(), m_dma.get()))
return false;
return true;
diff --git a/src/pse/system.h b/src/pse/system.h
index bbebfc1c3..b48baeffa 100644
--- a/src/pse/system.h
+++ b/src/pse/system.h
@@ -1,6 +1,8 @@
#pragma once
#include "types.h"
+class HostInterface;
+
namespace CPU
{
class Core;
@@ -13,15 +15,18 @@ class GPU;
class System
{
public:
- System();
+ System(HostInterface* host_interface);
~System();
+ HostInterface* GetHostInterface() const { return m_host_interface; }
+
bool Initialize();
void Reset();
void RunFrame();
private:
+ HostInterface* m_host_interface;
std::unique_ptr m_cpu;
std::unique_ptr m_bus;
std::unique_ptr m_dma;