GPU: More work on OpenGL renderer
This commit is contained in:
parent
4706a906d5
commit
aea7a18ac2
|
@ -43,6 +43,8 @@
|
||||||
<ClInclude Include="display_renderer_gl.h" />
|
<ClInclude Include="display_renderer_gl.h" />
|
||||||
<ClInclude Include="display_timing.h" />
|
<ClInclude Include="display_timing.h" />
|
||||||
<ClInclude Include="fastjmp.h" />
|
<ClInclude Include="fastjmp.h" />
|
||||||
|
<ClInclude Include="gl_program.h" />
|
||||||
|
<ClInclude Include="gl_texture.h" />
|
||||||
<ClInclude Include="hdd_image.h" />
|
<ClInclude Include="hdd_image.h" />
|
||||||
<ClInclude Include="jit_code_buffer.h" />
|
<ClInclude Include="jit_code_buffer.h" />
|
||||||
<ClInclude Include="object.h" />
|
<ClInclude Include="object.h" />
|
||||||
|
@ -59,6 +61,8 @@
|
||||||
<ClCompile Include="display_renderer.cpp" />
|
<ClCompile Include="display_renderer.cpp" />
|
||||||
<ClCompile Include="display_renderer_gl.cpp" />
|
<ClCompile Include="display_renderer_gl.cpp" />
|
||||||
<ClCompile Include="display_timing.cpp" />
|
<ClCompile Include="display_timing.cpp" />
|
||||||
|
<ClCompile Include="gl_program.cpp" />
|
||||||
|
<ClCompile Include="gl_texture.cpp" />
|
||||||
<ClCompile Include="hdd_image.cpp" />
|
<ClCompile Include="hdd_image.cpp" />
|
||||||
<ClCompile Include="jit_code_buffer.cpp" />
|
<ClCompile Include="jit_code_buffer.cpp" />
|
||||||
<ClCompile Include="object.cpp" />
|
<ClCompile Include="object.cpp" />
|
||||||
|
|
|
@ -17,6 +17,8 @@
|
||||||
<ClInclude Include="display_timing.h" />
|
<ClInclude Include="display_timing.h" />
|
||||||
<ClInclude Include="jit_code_buffer.h" />
|
<ClInclude Include="jit_code_buffer.h" />
|
||||||
<ClInclude Include="state_wrapper.h" />
|
<ClInclude Include="state_wrapper.h" />
|
||||||
|
<ClInclude Include="gl_program.h" />
|
||||||
|
<ClInclude Include="gl_texture.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="hdd_image.cpp" />
|
<ClCompile Include="hdd_image.cpp" />
|
||||||
|
@ -31,6 +33,8 @@
|
||||||
<ClCompile Include="display_timing.cpp" />
|
<ClCompile Include="display_timing.cpp" />
|
||||||
<ClCompile Include="jit_code_buffer.cpp" />
|
<ClCompile Include="jit_code_buffer.cpp" />
|
||||||
<ClCompile Include="state_wrapper.cpp" />
|
<ClCompile Include="state_wrapper.cpp" />
|
||||||
|
<ClCompile Include="gl_program.cpp" />
|
||||||
|
<ClCompile Include="gl_texture.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Natvis Include="bitfield.natvis" />
|
<Natvis Include="bitfield.natvis" />
|
||||||
|
|
|
@ -0,0 +1,171 @@
|
||||||
|
#include "gl_program.h"
|
||||||
|
#include "YBaseLib/Log.h"
|
||||||
|
#include <array>
|
||||||
|
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<const GLchar*, 1> sources = {{source}};
|
||||||
|
std::array<GLint, 1> source_lengths = {{static_cast<GLint>(std::strlen(source))}};
|
||||||
|
glShaderSource(id, static_cast<GLsizei>(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<u32>(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
|
|
@ -0,0 +1,42 @@
|
||||||
|
#pragma once
|
||||||
|
#include "glad.h"
|
||||||
|
#include "types.h"
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
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<GLint> m_uniform_locations;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace GL
|
|
@ -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
|
|
@ -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
|
|
@ -7,6 +7,7 @@
|
||||||
#include <SDL.h>
|
#include <SDL.h>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
|
||||||
|
#if 0
|
||||||
static int NoGUITest()
|
static int NoGUITest()
|
||||||
{
|
{
|
||||||
std::unique_ptr<System> system = std::make_unique<System>();
|
std::unique_ptr<System> system = std::make_unique<System>();
|
||||||
|
@ -19,14 +20,17 @@ static int NoGUITest()
|
||||||
system->RunFrame();
|
system->RunFrame();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static int Run(int argc, char* argv[])
|
static int Run(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
|
#if 0
|
||||||
if (argc < 2)
|
if (argc < 2)
|
||||||
{
|
{
|
||||||
std::fprintf(stderr, "Usage: %s <path to system ini> [save state index]\n", argv[0]);
|
std::fprintf(stderr, "Usage: %s <path to system ini> [save state index]\n", argv[0]);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// init sdl
|
// init sdl
|
||||||
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0)
|
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;
|
s32 state_index = -1;
|
||||||
if (argc > 2)
|
if (argc > 2)
|
||||||
state_index = StringConverter::StringToInt32(argv[2]);
|
state_index = StringConverter::StringToInt32(argv[2]);
|
||||||
if (!host_interface->InitializeSystem(argv[1], state_index))
|
if (!host_interface->InitializeSystem("", state_index))
|
||||||
{
|
{
|
||||||
host_interface.reset();
|
host_interface.reset();
|
||||||
SDL_Quit();
|
SDL_Quit();
|
||||||
|
@ -79,6 +83,6 @@ int main(int argc, char* argv[])
|
||||||
g_pLog->SetFilterLevel(LOGLEVEL_DEBUG);
|
g_pLog->SetFilterLevel(LOGLEVEL_DEBUG);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return NoGUITest();
|
//return NoGUITest();
|
||||||
//return Run(argc, argv);
|
return Run(argc, argv);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,181 +1,162 @@
|
||||||
#include "sdl_interface.h"
|
#include "sdl_interface.h"
|
||||||
#include "YBaseLib/ByteStream.h"
|
#include "YBaseLib/ByteStream.h"
|
||||||
#include "YBaseLib/Error.h"
|
#include "YBaseLib/Error.h"
|
||||||
#include "common/display_renderer_d3d.h"
|
#include "YBaseLib/Log.h"
|
||||||
#include "imgui.h"
|
#include "imgui.h"
|
||||||
#include "imgui_impl_opengl3.h"
|
#include "imgui_impl_opengl3.h"
|
||||||
#include "imgui_impl_sdl.h"
|
#include "imgui_impl_sdl.h"
|
||||||
#include "pse/system.h"
|
#include "pse/system.h"
|
||||||
#include <SDL.h>
|
|
||||||
#include <cinttypes>
|
#include <cinttypes>
|
||||||
#include <glad.h>
|
#include <glad.h>
|
||||||
#ifdef Y_COMPILER_MSVC
|
Log_SetChannel(SDLInterface);
|
||||||
#include "imgui_impl_dx11.h"
|
|
||||||
#include <SDL_syswm.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
SDLInterface::SDLInterface(SDL_Window* window, std::unique_ptr<DisplayRenderer> display_renderer,
|
SDLInterface::SDLInterface() = default;
|
||||||
std::unique_ptr<MixerType> mixer)
|
|
||||||
: m_window(window), m_display_renderer(std::move(display_renderer)), m_mixer(std::move(mixer))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
SDLInterface::~SDLInterface()
|
SDLInterface::~SDLInterface()
|
||||||
{
|
{
|
||||||
m_mixer.reset();
|
if (m_gl_context)
|
||||||
|
{
|
||||||
|
if (m_display_vao != 0)
|
||||||
|
glDeleteVertexArrays(1, &m_display_vao);
|
||||||
|
|
||||||
switch (m_display_renderer->GetBackendType())
|
m_display_program.Destroy();
|
||||||
{
|
|
||||||
#ifdef Y_COMPILER_MSVC
|
|
||||||
case DisplayRenderer::BackendType::Direct3D:
|
|
||||||
{
|
|
||||||
ImGui_ImplDX11_Shutdown();
|
|
||||||
ImGui::DestroyContext();
|
|
||||||
m_display_renderer.reset();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
case DisplayRenderer::BackendType::OpenGL:
|
|
||||||
{
|
|
||||||
SDL_GLContext context = SDL_GL_GetCurrentContext();
|
|
||||||
ImGui_ImplOpenGL3_Shutdown();
|
ImGui_ImplOpenGL3_Shutdown();
|
||||||
ImGui_ImplSDL2_Shutdown();
|
ImGui_ImplSDL2_Shutdown();
|
||||||
ImGui::DestroyContext();
|
ImGui::DestroyContext();
|
||||||
m_display_renderer.reset();
|
|
||||||
SDL_GL_MakeCurrent(nullptr, nullptr);
|
SDL_GL_MakeCurrent(nullptr, nullptr);
|
||||||
SDL_GL_DeleteContext(context);
|
SDL_GL_DeleteContext(m_gl_context);
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
|
|
||||||
ImGui::DestroyContext();
|
|
||||||
m_display_renderer.reset();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<SDLInterface> SDLInterface::Create(
|
if (m_window)
|
||||||
DisplayRenderer::BackendType display_renderer_backend /* = DisplayRenderer::GetDefaultBackendType() */)
|
SDL_DestroyWindow(m_window);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SDLInterface::CreateSDLWindow()
|
||||||
{
|
{
|
||||||
constexpr u32 DEFAULT_WINDOW_WIDTH = 900;
|
constexpr u32 DEFAULT_WINDOW_WIDTH = 900;
|
||||||
constexpr u32 DEFAULT_WINDOW_HEIGHT = 700;
|
constexpr u32 DEFAULT_WINDOW_HEIGHT = 700;
|
||||||
constexpr u32 MAIN_MENU_BAR_HEIGHT = 20;
|
|
||||||
|
|
||||||
// Create window.
|
// Create window.
|
||||||
u32 window_flags = SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI;
|
constexpr u32 window_flags = SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_OPENGL;
|
||||||
if (display_renderer_backend == DisplayRenderer::BackendType::OpenGL)
|
|
||||||
window_flags |= SDL_WINDOW_OPENGL;
|
|
||||||
|
|
||||||
auto window = std::unique_ptr<SDL_Window, void (*)(SDL_Window*)>(
|
m_window = SDL_CreateWindow("Some idea to emulate a system starting with a P", SDL_WINDOWPOS_UNDEFINED,
|
||||||
SDL_CreateWindow("PCE - Initializing...", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, DEFAULT_WINDOW_WIDTH,
|
SDL_WINDOWPOS_UNDEFINED, DEFAULT_WINDOW_WIDTH, DEFAULT_WINDOW_HEIGHT, window_flags);
|
||||||
DEFAULT_WINDOW_HEIGHT, window_flags),
|
if (!m_window)
|
||||||
[](SDL_Window* win) { SDL_DestroyWindow(win); });
|
|
||||||
if (!window)
|
|
||||||
{
|
{
|
||||||
Panic("Failed to create window");
|
Panic("Failed to create window");
|
||||||
return nullptr;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
DisplayRenderer::WindowHandleType window_handle = nullptr;
|
SDL_GetWindowSize(m_window, &m_window_width, &m_window_height);
|
||||||
if (display_renderer_backend == DisplayRenderer::BackendType::OpenGL)
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void APIENTRY GLDebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length,
|
||||||
|
const GLchar* message, const void* userParam)
|
||||||
{
|
{
|
||||||
// We need a GL context. TODO: Move this to common.
|
Log_InfoPrintf("%s", message);
|
||||||
SDL_GLContext gl_context = SDL_GL_CreateContext(window.get());
|
}
|
||||||
if (!gl_context || SDL_GL_MakeCurrent(window.get(), gl_context) != 0 || !gladLoadGL())
|
|
||||||
|
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())
|
||||||
{
|
{
|
||||||
Panic("Failed to create GL context");
|
Panic("Failed to create GL context");
|
||||||
return nullptr;
|
return false;
|
||||||
}
|
|
||||||
}
|
|
||||||
#ifdef Y_COMPILER_MSVC
|
|
||||||
if (display_renderer_backend == DisplayRenderer::BackendType::Direct3D)
|
|
||||||
{
|
|
||||||
// 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;
|
if (GLAD_GL_KHR_debug)
|
||||||
}
|
|
||||||
#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");
|
glad_glDebugMessageCallbackKHR(GLDebugCallback, nullptr);
|
||||||
return nullptr;
|
glEnable(GL_DEBUG_OUTPUT);
|
||||||
|
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
|
||||||
}
|
}
|
||||||
display_renderer->SetTopPadding(MAIN_MENU_BAR_HEIGHT);
|
|
||||||
|
|
||||||
// Create audio renderer.
|
return true;
|
||||||
auto mixer = MixerType::Create();
|
}
|
||||||
if (!mixer)
|
|
||||||
|
bool SDLInterface::CreateImGuiContext()
|
||||||
{
|
{
|
||||||
Panic("Failed to create audio mixer");
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize imgui.
|
|
||||||
ImGui::CreateContext();
|
ImGui::CreateContext();
|
||||||
ImGui::GetIO().IniFilename = nullptr;
|
ImGui::GetIO().IniFilename = nullptr;
|
||||||
|
|
||||||
switch (display_renderer->GetBackendType())
|
if (!ImGui_ImplSDL2_InitForOpenGL(m_window, m_gl_context) || !ImGui_ImplOpenGL3_Init())
|
||||||
{
|
return false;
|
||||||
#ifdef Y_COMPILER_MSVC
|
|
||||||
case DisplayRenderer::BackendType::Direct3D:
|
|
||||||
{
|
|
||||||
if (!ImGui_ImplSDL2_InitForD3D(window.get()) ||
|
|
||||||
!ImGui_ImplDX11_Init(static_cast<DisplayRendererD3D*>(display_renderer.get())->GetD3DDevice(),
|
|
||||||
static_cast<DisplayRendererD3D*>(display_renderer.get())->GetD3DContext()))
|
|
||||||
{
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
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_ImplOpenGL3_NewFrame();
|
||||||
ImGui_ImplSDL2_NewFrame(window.get());
|
ImGui_ImplSDL2_NewFrame(m_window);
|
||||||
ImGui::NewFrame();
|
ImGui::NewFrame();
|
||||||
}
|
return true;
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::make_unique<SDLInterface>(window.release(), std::move(display_renderer), std::move(mixer));
|
bool SDLInterface::CreateGLResources()
|
||||||
}
|
|
||||||
|
|
||||||
TinyString SDLInterface::GetSaveStateFilename(u32 index)
|
|
||||||
{
|
{
|
||||||
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> SDLInterface::Create()
|
||||||
|
{
|
||||||
|
std::unique_ptr<SDLInterface> intf = std::make_unique<SDLInterface>();
|
||||||
|
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 */)
|
bool SDLInterface::InitializeSystem(const char* filename, s32 save_state_index /* = -1 */)
|
||||||
{
|
{
|
||||||
Error error;
|
Error error;
|
||||||
|
|
||||||
m_system = std::make_unique<System>();
|
m_system = std::make_unique<System>(this);
|
||||||
if (!m_system->Initialize())
|
if (!m_system->Initialize())
|
||||||
{
|
{
|
||||||
m_system.reset();
|
m_system.reset();
|
||||||
|
@ -194,6 +175,8 @@ bool SDLInterface::InitializeSystem(const char* filename, s32 save_state_index /
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
m_system->Reset();
|
||||||
|
|
||||||
// Resume execution.
|
// Resume execution.
|
||||||
m_running = true;
|
m_running = true;
|
||||||
return true;
|
return true;
|
||||||
|
@ -232,88 +215,13 @@ bool SDLInterface::HandleSDLEvent(const SDL_Event* event)
|
||||||
|
|
||||||
switch (event->type)
|
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:
|
case SDL_WINDOWEVENT:
|
||||||
{
|
{
|
||||||
if (event->window.event == SDL_WINDOWEVENT_RESIZED)
|
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;
|
break;
|
||||||
|
|
||||||
|
@ -387,44 +295,39 @@ bool SDLInterface::PassEventToImGui(const SDL_Event* event)
|
||||||
|
|
||||||
void SDLInterface::Render()
|
void SDLInterface::Render()
|
||||||
{
|
{
|
||||||
if (!m_display_renderer->BeginFrame())
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||||
return;
|
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
|
|
||||||
m_display_renderer->RenderDisplays();
|
RenderDisplay();
|
||||||
|
|
||||||
RenderImGui();
|
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
|
|
||||||
|
|
||||||
case DisplayRenderer::BackendType::OpenGL:
|
|
||||||
{
|
|
||||||
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
|
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
|
||||||
m_display_renderer->EndFrame();
|
|
||||||
SDL_GL_SwapWindow(m_window);
|
SDL_GL_SwapWindow(m_window);
|
||||||
|
|
||||||
ImGui_ImplSDL2_NewFrame(m_window);
|
ImGui_ImplSDL2_NewFrame(m_window);
|
||||||
ImGui_ImplOpenGL3_NewFrame();
|
ImGui_ImplOpenGL3_NewFrame();
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::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()
|
void SDLInterface::RenderImGui()
|
||||||
{
|
{
|
||||||
RenderMainMenuBar();
|
RenderMainMenuBar();
|
||||||
|
@ -499,6 +402,18 @@ void SDLInterface::AddOSDMessage(const char* message, float duration /*= 2.0f*/)
|
||||||
m_osd_messages.push_back(std::move(msg));
|
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()
|
void SDLInterface::RenderOSDMessages()
|
||||||
{
|
{
|
||||||
constexpr ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoInputs |
|
constexpr ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoInputs |
|
||||||
|
@ -561,6 +476,8 @@ void SDLInterface::DoSaveState(u32 index)
|
||||||
|
|
||||||
void SDLInterface::Run()
|
void SDLInterface::Run()
|
||||||
{
|
{
|
||||||
|
Timer last_render_time;
|
||||||
|
|
||||||
while (m_running)
|
while (m_running)
|
||||||
{
|
{
|
||||||
for (;;)
|
for (;;)
|
||||||
|
@ -572,8 +489,12 @@ void SDLInterface::Run()
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
while (!m_display_texture_changed || last_render_time.GetTimeSeconds() < (1.0f / 60.0f))
|
||||||
|
{
|
||||||
m_system->RunFrame();
|
m_system->RunFrame();
|
||||||
Render();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Render();
|
||||||
|
last_render_time.Reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,43 +1,36 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "common/display_renderer.h"
|
#include "YBaseLib/String.h"
|
||||||
#include "pse-sdl/sdl_audio_mixer.h"
|
#include "YBaseLib/Timer.h"
|
||||||
|
#include "common/gl_program.h"
|
||||||
|
#include "common/gl_texture.h"
|
||||||
|
#include "pse/host_interface.h"
|
||||||
|
#include <SDL.h>
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <deque>
|
#include <deque>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
|
||||||
struct SDL_Window;
|
|
||||||
union SDL_Event;
|
|
||||||
|
|
||||||
class System;
|
class System;
|
||||||
|
|
||||||
class SDLInterface
|
class SDLInterface : public HostInterface
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using MixerType = SDLAudioMixer;
|
SDLInterface();
|
||||||
// using MixerType = Audio::NullMixer;
|
|
||||||
|
|
||||||
SDLInterface(SDL_Window* window, std::unique_ptr<DisplayRenderer> display_renderer,
|
|
||||||
std::unique_ptr<MixerType> mixer);
|
|
||||||
~SDLInterface();
|
~SDLInterface();
|
||||||
|
|
||||||
static std::unique_ptr<SDLInterface>
|
static std::unique_ptr<SDLInterface> Create();
|
||||||
Create(DisplayRenderer::BackendType display_renderer_backend = DisplayRenderer::GetDefaultBackendType());
|
|
||||||
|
|
||||||
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(); }
|
// Adds OSD messages, duration is in seconds.
|
||||||
Audio::Mixer* GetAudioMixer() const { return m_mixer.get(); }
|
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();
|
void Run();
|
||||||
|
|
||||||
// Adds OSD messages, duration is in seconds.
|
private:
|
||||||
void AddOSDMessage(const char* message, float duration = 2.0f);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
struct OSDMessage
|
struct OSDMessage
|
||||||
{
|
{
|
||||||
String text;
|
String text;
|
||||||
|
@ -45,6 +38,11 @@ protected:
|
||||||
float duration;
|
float duration;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
bool CreateSDLWindow();
|
||||||
|
bool CreateGLContext();
|
||||||
|
bool CreateImGuiContext();
|
||||||
|
bool CreateGLResources();
|
||||||
|
|
||||||
// We only pass mouse input through if it's grabbed
|
// We only pass mouse input through if it's grabbed
|
||||||
bool IsWindowFullscreen() const;
|
bool IsWindowFullscreen() const;
|
||||||
void RenderImGui();
|
void RenderImGui();
|
||||||
|
@ -54,14 +52,24 @@ protected:
|
||||||
bool HandleSDLEvent(const SDL_Event* event);
|
bool HandleSDLEvent(const SDL_Event* event);
|
||||||
bool PassEventToImGui(const SDL_Event* event);
|
bool PassEventToImGui(const SDL_Event* event);
|
||||||
void Render();
|
void Render();
|
||||||
|
void RenderDisplay();
|
||||||
void RenderMainMenuBar();
|
void RenderMainMenuBar();
|
||||||
void RenderOSDMessages();
|
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<DisplayRenderer> m_display_renderer;
|
|
||||||
std::unique_ptr<MixerType> m_mixer;
|
|
||||||
std::unique_ptr<System> m_system;
|
std::unique_ptr<System> 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<OSDMessage> m_osd_messages;
|
std::deque<OSDMessage> m_osd_messages;
|
||||||
std::mutex m_osd_messages_lock;
|
std::mutex m_osd_messages_lock;
|
||||||
|
|
|
@ -8,8 +8,9 @@ GPU::GPU() = default;
|
||||||
|
|
||||||
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_bus = bus;
|
||||||
m_dma = dma;
|
m_dma = dma;
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include <array>
|
#include <array>
|
||||||
|
|
||||||
|
class System;
|
||||||
class Bus;
|
class Bus;
|
||||||
class DMA;
|
class DMA;
|
||||||
|
|
||||||
|
@ -12,7 +13,7 @@ public:
|
||||||
GPU();
|
GPU();
|
||||||
virtual ~GPU();
|
virtual ~GPU();
|
||||||
|
|
||||||
virtual bool Initialize(Bus* bus, DMA* dma);
|
virtual bool Initialize(System* system, Bus* bus, DMA* dma);
|
||||||
virtual void Reset();
|
virtual void Reset();
|
||||||
|
|
||||||
u32 ReadRegister(u32 offset);
|
u32 ReadRegister(u32 offset);
|
||||||
|
@ -101,6 +102,7 @@ protected:
|
||||||
virtual void DispatchRenderCommand(RenderCommand rc, u32 num_vertices);
|
virtual void DispatchRenderCommand(RenderCommand rc, u32 num_vertices);
|
||||||
virtual void FlushRender();
|
virtual void FlushRender();
|
||||||
|
|
||||||
|
System* m_system = nullptr;
|
||||||
Bus* m_bus = nullptr;
|
Bus* m_bus = nullptr;
|
||||||
DMA* m_dma = nullptr;
|
DMA* m_dma = nullptr;
|
||||||
|
|
||||||
|
|
|
@ -32,6 +32,8 @@ void GPU_HW::LoadVertices(RenderCommand rc, u32 num_vertices)
|
||||||
|
|
||||||
if (textured)
|
if (textured)
|
||||||
hw_vert.texcoord = (m_GP0_command[buffer_pos++] & UINT32_C(0x0000FFFF));
|
hw_vert.texcoord = (m_GP0_command[buffer_pos++] & UINT32_C(0x0000FFFF));
|
||||||
|
else
|
||||||
|
hw_vert.texcoord = 0;
|
||||||
|
|
||||||
m_vertex_staging.push_back(hw_vert);
|
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<int>(VRAM_WIDTH - m_drawing_offset.x), 1);
|
||||||
|
*height = std::max(static_cast<int>(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::string GPU_HW::GenerateVertexShader(bool textured)
|
||||||
{
|
{
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
|
@ -54,9 +72,9 @@ std::string GPU_HW::GenerateVertexShader(bool textured)
|
||||||
ss << "/* #define TEXTURED 0 */\n";
|
ss << "/* #define TEXTURED 0 */\n";
|
||||||
|
|
||||||
ss << R"(
|
ss << R"(
|
||||||
in uivec2 a_position;
|
in ivec2 a_position;
|
||||||
in uint a_texcoord;
|
|
||||||
in vec4 a_color;
|
in vec4 a_color;
|
||||||
|
in uint a_texcoord;
|
||||||
|
|
||||||
out vec4 v_color;
|
out vec4 v_color;
|
||||||
#if TEXTURED
|
#if TEXTURED
|
||||||
|
@ -65,14 +83,14 @@ out vec4 v_color;
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
// -1024..+1023 -> -1..1
|
// 0..+1023 -> -1..1
|
||||||
float gl_x = (a_position.x < 0) ? (float(a_position.x) / 1024.0) : (float(a_position.x) / 1023.0);
|
float pos_x = (float(a_position.x) / 511.5) - 1.0;
|
||||||
float gl_y = (a_position.y < 0) ? -(float(a_position.y) / 1024.0) : -(float(a_position.y) / 1023.0);
|
float pos_y = (float(a_position.y) / 255.5) + 1.0;
|
||||||
gl_Position = vec4(gl_x, gl_y, 0.0, 1.0);
|
gl_Position = vec4(pos_x, pos_y, 0.0, 1.0);
|
||||||
|
|
||||||
v_color = a_color;
|
v_color = a_color;
|
||||||
#if TEXTURED
|
#if TEXTURED
|
||||||
v_texcoord = a_texcoord;
|
v_texcoord = vec2(float(a_texcoord & 0xFFu) / 256.0, float((a_texcoord >> 8) & 0xFFu) / 256.0);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
|
@ -99,8 +117,8 @@ out vec4 ocol0;
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
//ocol0 = v_color;
|
ocol0 = v_color;
|
||||||
ocol0 = vec4(1.0, 0.5, 0.5, 1.0);
|
//ocol0 = vec4(1.0, 0.5, 0.5, 1.0);
|
||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,9 @@ protected:
|
||||||
|
|
||||||
void LoadVertices(RenderCommand rc, u32 num_vertices);
|
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 GenerateVertexShader(bool textured);
|
||||||
std::string GenerateFragmentShader(bool textured);
|
std::string GenerateFragmentShader(bool textured);
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
#include "gpu_hw_opengl.h"
|
#include "gpu_hw_opengl.h"
|
||||||
#include "YBaseLib/Assert.h"
|
#include "YBaseLib/Assert.h"
|
||||||
#include "YBaseLib/Log.h"
|
#include "YBaseLib/Log.h"
|
||||||
|
#include "host_interface.h"
|
||||||
|
#include "system.h"
|
||||||
Log_SetChannel(GPU_HW_OpenGL);
|
Log_SetChannel(GPU_HW_OpenGL);
|
||||||
|
|
||||||
GPU_HW_OpenGL::GPU_HW_OpenGL() : GPU_HW() {}
|
GPU_HW_OpenGL::GPU_HW_OpenGL() : GPU_HW() {}
|
||||||
|
@ -10,12 +12,16 @@ GPU_HW_OpenGL::~GPU_HW_OpenGL()
|
||||||
DestroyFramebuffer();
|
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;
|
return false;
|
||||||
|
|
||||||
CreateFramebuffer();
|
CreateFramebuffer();
|
||||||
|
CreateVertexBuffer();
|
||||||
|
if (!CompilePrograms())
|
||||||
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,16 +34,12 @@ void GPU_HW_OpenGL::Reset()
|
||||||
|
|
||||||
void GPU_HW_OpenGL::CreateFramebuffer()
|
void GPU_HW_OpenGL::CreateFramebuffer()
|
||||||
{
|
{
|
||||||
glGenTextures(1, &m_framebuffer_texture_id);
|
m_framebuffer_texture =
|
||||||
glBindTexture(GL_TEXTURE_2D, m_framebuffer_texture_id);
|
std::make_unique<GL::Texture>(VRAM_WIDTH, VRAM_HEIGHT, GL_RGBA, GL_UNSIGNED_BYTE, nullptr, false);
|
||||||
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);
|
|
||||||
|
|
||||||
glGenFramebuffers(1, &m_framebuffer_fbo_id);
|
glGenFramebuffers(1, &m_framebuffer_fbo_id);
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, 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);
|
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);
|
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
|
||||||
glClear(GL_COLOR_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||||
|
|
||||||
|
m_system->GetHostInterface()->SetDisplayTexture(m_framebuffer_texture.get(), 0, 0, VRAM_WIDTH, VRAM_HEIGHT);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GPU_HW_OpenGL::DestroyFramebuffer()
|
void GPU_HW_OpenGL::DestroyFramebuffer()
|
||||||
|
@ -55,27 +59,108 @@ void GPU_HW_OpenGL::DestroyFramebuffer()
|
||||||
glDeleteFramebuffers(1, &m_framebuffer_fbo_id);
|
glDeleteFramebuffers(1, &m_framebuffer_fbo_id);
|
||||||
m_framebuffer_fbo_id = 0;
|
m_framebuffer_fbo_id = 0;
|
||||||
|
|
||||||
glDeleteTextures(1, &m_framebuffer_texture_id);
|
m_framebuffer_texture.reset();
|
||||||
m_framebuffer_texture_id = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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<void*>(offsetof(HWVertex, x)));
|
||||||
|
glVertexAttribPointer(1, 4, GL_UNSIGNED_BYTE, true, sizeof(HWVertex),
|
||||||
|
reinterpret_cast<void*>(offsetof(HWVertex, color)));
|
||||||
|
glVertexAttribIPointer(2, 1, GL_UNSIGNED_INT, sizeof(HWVertex), reinterpret_cast<void*>(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)
|
void GPU_HW_OpenGL::DispatchRenderCommand(RenderCommand rc, u32 num_vertices)
|
||||||
{
|
{
|
||||||
LoadVertices(rc, num_vertices);
|
LoadVertices(rc, num_vertices);
|
||||||
if (m_vertex_staging.empty())
|
if (m_vertex_staging.empty())
|
||||||
return;
|
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)
|
SetViewport();
|
||||||
m_texture_program.Bind();
|
|
||||||
else
|
glBindFramebuffer(GL_FRAMEBUFFER, m_framebuffer_fbo_id);
|
||||||
m_color_program.Bind();
|
glBindVertexArray(m_vao_id);
|
||||||
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, m_vertex_buffer);
|
glBindBuffer(GL_ARRAY_BUFFER, m_vertex_buffer);
|
||||||
glBufferData(GL_ARRAY_BUFFER, static_cast<GLsizei>(sizeof(HWVertex) * m_vertex_staging.size()),
|
glBufferData(GL_ARRAY_BUFFER, static_cast<GLsizei>(sizeof(HWVertex) * m_vertex_staging.size()),
|
||||||
m_vertex_staging.data(), GL_STREAM_DRAW);
|
m_vertex_staging.data(), GL_STREAM_DRAW);
|
||||||
|
glEnableVertexAttribArray(0);
|
||||||
|
glVertexAttribIPointer(0, 2, GL_INT, sizeof(HWVertex), reinterpret_cast<void*>(offsetof(HWVertex, x)));
|
||||||
|
glEnableVertexAttribArray(1);
|
||||||
|
glVertexAttribPointer(1, 4, GL_UNSIGNED_BYTE, true, sizeof(HWVertex),
|
||||||
|
reinterpret_cast<void*>(offsetof(HWVertex, color)));
|
||||||
|
glEnableVertexAttribArray(2);
|
||||||
|
glVertexAttribIPointer(2, 1, GL_UNSIGNED_INT, sizeof(HWVertex), reinterpret_cast<void*>(offsetof(HWVertex, color)));
|
||||||
|
|
||||||
glDrawArrays(rc.quad_polygon ? GL_TRIANGLE_STRIP : GL_TRIANGLES, 0, static_cast<GLsizei>(m_vertex_staging.size()));
|
glDrawArrays(rc.quad_polygon ? GL_TRIANGLE_STRIP : GL_TRIANGLES, 0, static_cast<GLsizei>(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()
|
void GPU_HW_OpenGL::FlushRender()
|
||||||
|
@ -90,98 +175,3 @@ std::unique_ptr<GPU> GPU::CreateHardwareOpenGLRenderer()
|
||||||
{
|
{
|
||||||
return std::make_unique<GPU_HW_OpenGL>();
|
return std::make_unique<GPU_HW_OpenGL>();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GPU_HW_OpenGL::Program::Bind()
|
|
||||||
{
|
|
||||||
glUseProgram(program_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
static GLuint CompileShader(GLenum type, const std::string& source)
|
|
||||||
{
|
|
||||||
GLuint id = glCreateShader(type);
|
|
||||||
|
|
||||||
std::array<const GLchar*, 1> sources = {{source.c_str()}};
|
|
||||||
std::array<GLint, 1> source_lengths = {{static_cast<GLint>(source.size())}};
|
|
||||||
glShaderSource(id, static_cast<GLsizei>(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;
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "gpu_hw.h"
|
#include "common/gl_program.h"
|
||||||
|
#include "common/gl_texture.h"
|
||||||
#include "glad.h"
|
#include "glad.h"
|
||||||
|
#include "gpu_hw.h"
|
||||||
#include <array>
|
#include <array>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
class GPU_HW_OpenGL : public GPU_HW
|
class GPU_HW_OpenGL : public GPU_HW
|
||||||
{
|
{
|
||||||
|
@ -9,7 +12,7 @@ public:
|
||||||
GPU_HW_OpenGL();
|
GPU_HW_OpenGL();
|
||||||
~GPU_HW_OpenGL() override;
|
~GPU_HW_OpenGL() override;
|
||||||
|
|
||||||
bool Initialize(Bus* bus, DMA* dma) override;
|
bool Initialize(System* system, Bus* bus, DMA* dma) override;
|
||||||
void Reset() override;
|
void Reset() override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -23,22 +26,18 @@ private:
|
||||||
|
|
||||||
void CreateVertexBuffer();
|
void CreateVertexBuffer();
|
||||||
|
|
||||||
GLuint m_framebuffer_texture_id = 0;
|
bool CompilePrograms();
|
||||||
|
|
||||||
|
bool SetProgram(bool texture_enable);
|
||||||
|
void SetViewport();
|
||||||
|
void SetScissor();
|
||||||
|
|
||||||
|
std::unique_ptr<GL::Texture> m_framebuffer_texture;
|
||||||
GLuint m_framebuffer_fbo_id = 0;
|
GLuint m_framebuffer_fbo_id = 0;
|
||||||
|
|
||||||
GLuint m_vertex_buffer = 0;
|
GLuint m_vertex_buffer = 0;
|
||||||
GLuint m_vao_id = 0;
|
GLuint m_vao_id = 0;
|
||||||
|
|
||||||
struct Program
|
GL::Program m_texture_program;
|
||||||
{
|
GL::Program m_color_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;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
};
|
|
@ -53,6 +53,7 @@
|
||||||
<ClInclude Include="gpu.h" />
|
<ClInclude Include="gpu.h" />
|
||||||
<ClInclude Include="gpu_hw.h" />
|
<ClInclude Include="gpu_hw.h" />
|
||||||
<ClInclude Include="gpu_hw_opengl.h" />
|
<ClInclude Include="gpu_hw_opengl.h" />
|
||||||
|
<ClInclude Include="host_interface.h" />
|
||||||
<ClInclude Include="save_state_version.h" />
|
<ClInclude Include="save_state_version.h" />
|
||||||
<ClInclude Include="system.h" />
|
<ClInclude Include="system.h" />
|
||||||
<ClInclude Include="types.h" />
|
<ClInclude Include="types.h" />
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
<ClInclude Include="gpu.h" />
|
<ClInclude Include="gpu.h" />
|
||||||
<ClInclude Include="gpu_hw_opengl.h" />
|
<ClInclude Include="gpu_hw_opengl.h" />
|
||||||
<ClInclude Include="gpu_hw.h" />
|
<ClInclude Include="gpu_hw.h" />
|
||||||
|
<ClInclude Include="host_interface.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="cpu_core.inl" />
|
<None Include="cpu_core.inl" />
|
||||||
|
|
|
@ -4,13 +4,13 @@
|
||||||
#include "dma.h"
|
#include "dma.h"
|
||||||
#include "gpu.h"
|
#include "gpu.h"
|
||||||
|
|
||||||
System::System()
|
System::System(HostInterface* host_interface) : m_host_interface(host_interface)
|
||||||
{
|
{
|
||||||
m_cpu = std::make_unique<CPU::Core>();
|
m_cpu = std::make_unique<CPU::Core>();
|
||||||
m_bus = std::make_unique<Bus>();
|
m_bus = std::make_unique<Bus>();
|
||||||
m_dma = std::make_unique<DMA>();
|
m_dma = std::make_unique<DMA>();
|
||||||
m_gpu = std::make_unique<GPU>();
|
// m_gpu = std::make_unique<GPU>();
|
||||||
// m_gpu = GPU::CreateHardwareOpenGLRenderer();
|
m_gpu = GPU::CreateHardwareOpenGLRenderer();
|
||||||
}
|
}
|
||||||
|
|
||||||
System::~System() = default;
|
System::~System() = default;
|
||||||
|
@ -26,7 +26,7 @@ bool System::Initialize()
|
||||||
if (!m_dma->Initialize(m_bus.get(), m_gpu.get()))
|
if (!m_dma->Initialize(m_bus.get(), m_gpu.get()))
|
||||||
return false;
|
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 false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
|
class HostInterface;
|
||||||
|
|
||||||
namespace CPU
|
namespace CPU
|
||||||
{
|
{
|
||||||
class Core;
|
class Core;
|
||||||
|
@ -13,15 +15,18 @@ class GPU;
|
||||||
class System
|
class System
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
System();
|
System(HostInterface* host_interface);
|
||||||
~System();
|
~System();
|
||||||
|
|
||||||
|
HostInterface* GetHostInterface() const { return m_host_interface; }
|
||||||
|
|
||||||
bool Initialize();
|
bool Initialize();
|
||||||
void Reset();
|
void Reset();
|
||||||
|
|
||||||
void RunFrame();
|
void RunFrame();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
HostInterface* m_host_interface;
|
||||||
std::unique_ptr<CPU::Core> m_cpu;
|
std::unique_ptr<CPU::Core> m_cpu;
|
||||||
std::unique_ptr<Bus> m_bus;
|
std::unique_ptr<Bus> m_bus;
|
||||||
std::unique_ptr<DMA> m_dma;
|
std::unique_ptr<DMA> m_dma;
|
||||||
|
|
Loading…
Reference in New Issue