HostDisplay: Move most backend logic to FrontendCommon

This commit is contained in:
Connor McLaughlin
2020-06-30 02:46:57 +10:00
parent 84a52a3911
commit 2a38090e7a
43 changed files with 870 additions and 1909 deletions

View File

@ -2,15 +2,11 @@ add_executable(duckstation-sdl
imgui_impl_sdl.cpp
imgui_impl_sdl.h
main.cpp
opengl_host_display.cpp
opengl_host_display.h
sdl_host_interface.cpp
sdl_host_interface.h
sdl_key_names.h
sdl_util.cpp
sdl_util.h
sdl_vulkan_host_display.cpp
sdl_vulkan_host_display.h
)
target_include_directories(duckstation-sdl PRIVATE ${SDL2_INCLUDE_DIRS})
@ -18,8 +14,6 @@ target_link_libraries(duckstation-sdl PRIVATE core common imgui nativefiledialog
if(WIN32)
target_sources(duckstation-sdl PRIVATE
sdl_d3d11_host_display.cpp
sdl_d3d11_host_display.h
duckstation-sdl.manifest
)

View File

@ -55,23 +55,17 @@
</ProjectReference>
</ItemGroup>
<ItemGroup>
<ClCompile Include="sdl_d3d11_host_display.cpp" />
<ClCompile Include="imgui_impl_sdl.cpp" />
<ClCompile Include="opengl_host_display.cpp" />
<ClCompile Include="sdl_host_interface.cpp" />
<ClCompile Include="main.cpp" />
<ClCompile Include="sdl_util.cpp" />
<ClCompile Include="sdl_vulkan_host_display.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="sdl_d3d11_host_display.h" />
<ClInclude Include="imgui_impl_sdl.h" />
<ClInclude Include="opengl_host_display.h" />
<ClInclude Include="resource.h" />
<ClInclude Include="sdl_host_interface.h" />
<ClInclude Include="sdl_key_names.h" />
<ClInclude Include="sdl_util.h" />
<ClInclude Include="sdl_vulkan_host_display.h" />
</ItemGroup>
<ItemGroup>
<Manifest Include="duckstation-sdl.manifest" />

View File

@ -2,22 +2,16 @@
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ClCompile Include="main.cpp" />
<ClCompile Include="opengl_host_display.cpp" />
<ClCompile Include="sdl_host_interface.cpp" />
<ClCompile Include="imgui_impl_sdl.cpp" />
<ClCompile Include="sdl_util.cpp" />
<ClCompile Include="sdl_vulkan_host_display.cpp" />
<ClCompile Include="sdl_d3d11_host_display.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="opengl_host_display.h" />
<ClInclude Include="sdl_host_interface.h" />
<ClInclude Include="imgui_impl_sdl.h" />
<ClInclude Include="sdl_key_names.h" />
<ClInclude Include="resource.h" />
<ClInclude Include="sdl_util.h" />
<ClInclude Include="sdl_vulkan_host_display.h" />
<ClInclude Include="sdl_d3d11_host_display.h" />
</ItemGroup>
<ItemGroup>
<Manifest Include="duckstation-sdl.manifest" />

View File

@ -1,369 +0,0 @@
#include "opengl_host_display.h"
#include "common/assert.h"
#include "common/log.h"
#include "imgui_impl_sdl.h"
#include "sdl_util.h"
#include <SDL_syswm.h>
#include <array>
#include <imgui.h>
#include <imgui_impl_opengl3.h>
#include <tuple>
Log_SetChannel(OpenGLHostDisplay);
class OpenGLDisplayWidgetTexture : public HostDisplayTexture
{
public:
OpenGLDisplayWidgetTexture(GLuint id, u32 width, u32 height) : m_id(id), m_width(width), m_height(height) {}
~OpenGLDisplayWidgetTexture() override { glDeleteTextures(1, &m_id); }
void* GetHandle() const override { return reinterpret_cast<void*>(static_cast<uintptr_t>(m_id)); }
u32 GetWidth() const override { return m_width; }
u32 GetHeight() const override { return m_height; }
GLuint GetGLID() const { return m_id; }
static std::unique_ptr<OpenGLDisplayWidgetTexture> Create(u32 width, u32 height, const void* initial_data,
u32 initial_data_stride)
{
GLuint id;
glGenTextures(1, &id);
GLint old_texture_binding = 0;
glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_texture_binding);
// TODO: Set pack width
Assert(!initial_data || initial_data_stride == (width * sizeof(u32)));
glBindTexture(GL_TEXTURE_2D, id);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, initial_data);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, id);
return std::make_unique<OpenGLDisplayWidgetTexture>(id, width, height);
}
private:
GLuint m_id;
u32 m_width;
u32 m_height;
};
OpenGLHostDisplay::OpenGLHostDisplay(SDL_Window* window) : m_window(window)
{
SDL_GetWindowSize(window, &m_window_width, &m_window_height);
}
OpenGLHostDisplay::~OpenGLHostDisplay()
{
if (m_gl_context)
{
if (m_display_vao != 0)
glDeleteVertexArrays(1, &m_display_vao);
if (m_display_linear_sampler != 0)
glDeleteSamplers(1, &m_display_linear_sampler);
if (m_display_nearest_sampler != 0)
glDeleteSamplers(1, &m_display_nearest_sampler);
m_display_program.Destroy();
ImGui_ImplOpenGL3_Shutdown();
ImGui_ImplSDL2_Shutdown();
m_gl_context.reset();
}
if (m_window)
SDL_DestroyWindow(m_window);
}
HostDisplay::RenderAPI OpenGLHostDisplay::GetRenderAPI() const
{
return m_gl_context->IsGLES() ? HostDisplay::RenderAPI::OpenGLES : HostDisplay::RenderAPI::OpenGL;
}
void* OpenGLHostDisplay::GetRenderDevice() const
{
return nullptr;
}
void* OpenGLHostDisplay::GetRenderContext() const
{
return m_gl_context.get();
}
void OpenGLHostDisplay::WindowResized(s32 new_window_width, s32 new_window_height)
{
HostDisplay::WindowResized(new_window_width, new_window_height);
m_gl_context->ResizeSurface(static_cast<u32>(new_window_width), static_cast<u32>(new_window_height));
m_window_width = static_cast<s32>(m_gl_context->GetSurfaceWidth());
m_window_height = static_cast<s32>(m_gl_context->GetSurfaceHeight());
ImGui::GetIO().DisplaySize.x = static_cast<float>(m_window_width);
ImGui::GetIO().DisplaySize.y = static_cast<float>(m_window_height);
}
std::unique_ptr<HostDisplayTexture> OpenGLHostDisplay::CreateTexture(u32 width, u32 height, const void* data,
u32 data_stride, bool dynamic)
{
return OpenGLDisplayWidgetTexture::Create(width, height, data, data_stride);
}
void OpenGLHostDisplay::UpdateTexture(HostDisplayTexture* texture, u32 x, u32 y, u32 width, u32 height,
const void* data, u32 data_stride)
{
OpenGLDisplayWidgetTexture* tex = static_cast<OpenGLDisplayWidgetTexture*>(texture);
Assert((data_stride % sizeof(u32)) == 0);
GLint old_texture_binding = 0, old_alignment = 0, old_row_length = 0;
glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_texture_binding);
glGetIntegerv(GL_UNPACK_ALIGNMENT, &old_alignment);
glGetIntegerv(GL_UNPACK_ROW_LENGTH, &old_row_length);
glBindTexture(GL_TEXTURE_2D, tex->GetGLID());
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
glPixelStorei(GL_UNPACK_ROW_LENGTH, data_stride / sizeof(u32));
glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, data);
glPixelStorei(GL_UNPACK_ALIGNMENT, old_alignment);
glPixelStorei(GL_UNPACK_ROW_LENGTH, old_row_length);
glBindTexture(GL_TEXTURE_2D, old_texture_binding);
}
bool OpenGLHostDisplay::DownloadTexture(const void* texture_handle, u32 x, u32 y, u32 width, u32 height, void* out_data,
u32 out_data_stride)
{
GLint old_alignment = 0, old_row_length = 0;
glGetIntegerv(GL_PACK_ALIGNMENT, &old_alignment);
glGetIntegerv(GL_PACK_ROW_LENGTH, &old_row_length);
glPixelStorei(GL_PACK_ALIGNMENT, sizeof(u32));
glPixelStorei(GL_PACK_ROW_LENGTH, out_data_stride / sizeof(u32));
const GLuint texture = static_cast<GLuint>(reinterpret_cast<uintptr_t>(texture_handle));
GL::Texture::GetTextureSubImage(texture, 0, x, y, 0, width, height, 1, GL_RGBA, GL_UNSIGNED_BYTE,
height * out_data_stride, out_data);
glPixelStorei(GL_PACK_ALIGNMENT, old_alignment);
glPixelStorei(GL_PACK_ROW_LENGTH, old_row_length);
return true;
}
void OpenGLHostDisplay::SetVSync(bool enabled)
{
// Window framebuffer has to be bound to call SetSwapInterval.
GLint current_fbo = 0;
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &current_fbo);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
m_gl_context->SetSwapInterval(enabled ? 1 : 0);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, current_fbo);
}
const char* OpenGLHostDisplay::GetGLSLVersionString() const
{
if (m_gl_context->IsGLES())
{
if (GLAD_GL_ES_VERSION_3_0)
return "#version 300 es";
else
return "#version 100";
}
else
{
if (GLAD_GL_VERSION_3_3)
return "#version 330";
else
return "#version 130";
}
}
std::string OpenGLHostDisplay::GetGLSLVersionHeader() const
{
std::string header = GetGLSLVersionString();
header += "\n\n";
if (m_gl_context->IsGLES())
{
header += "precision highp float;\n";
header += "precision highp int;\n\n";
}
return header;
}
static void APIENTRY GLDebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length,
const GLchar* message, const void* userParam)
{
switch (severity)
{
case GL_DEBUG_SEVERITY_HIGH_KHR:
Log_ErrorPrintf(message);
break;
case GL_DEBUG_SEVERITY_MEDIUM_KHR:
Log_WarningPrint(message);
break;
case GL_DEBUG_SEVERITY_LOW_KHR:
Log_InfoPrintf(message);
break;
case GL_DEBUG_SEVERITY_NOTIFICATION:
// Log_DebugPrint(message);
break;
}
}
bool OpenGLHostDisplay::CreateGLContext(bool debug_device)
{
std::optional<WindowInfo> wi = SDLUtil::GetWindowInfoForSDLWindow(m_window);
if (!wi)
return false;
m_gl_context = GL::Context::Create(wi.value());
if (!m_gl_context)
{
Log_ErrorPrintf("Failed to create a GL context of any kind.");
return false;
}
if (debug_device && GLAD_GL_KHR_debug)
{
glad_glDebugMessageCallbackKHR(GLDebugCallback, nullptr);
glEnable(GL_DEBUG_OUTPUT);
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
}
// this can change due to retina scaling on macos?
m_window_width = static_cast<s32>(m_gl_context->GetSurfaceWidth());
m_window_height = static_cast<s32>(m_gl_context->GetSurfaceHeight());
// start with vsync on
m_gl_context->SetSwapInterval(1);
return true;
}
bool OpenGLHostDisplay::CreateImGuiContext()
{
ImGui::GetIO().DisplaySize.x = static_cast<float>(m_window_width);
ImGui::GetIO().DisplaySize.y = static_cast<float>(m_window_height);
if (!ImGui_ImplSDL2_InitForOpenGL(m_window, nullptr) || !ImGui_ImplOpenGL3_Init(GetGLSLVersionString()))
return false;
ImGui_ImplOpenGL3_NewFrame();
ImGui_ImplSDL2_NewFrame(m_window);
ImGui::NewFrame();
return true;
}
bool OpenGLHostDisplay::CreateGLResources()
{
static constexpr char fullscreen_quad_vertex_shader[] = R"(
uniform vec4 u_src_rect;
out vec2 v_tex0;
void main()
{
vec2 pos = vec2(float((gl_VertexID << 1) & 2), float(gl_VertexID & 2));
v_tex0 = u_src_rect.xy + pos * u_src_rect.zw;
gl_Position = vec4(pos * vec2(2.0f, -2.0f) + vec2(-1.0f, 1.0f), 0.0f, 1.0f);
}
)";
static constexpr char display_fragment_shader[] = R"(
uniform sampler2D samp0;
in vec2 v_tex0;
out vec4 o_col0;
void main()
{
o_col0 = texture(samp0, v_tex0);
}
)";
if (!m_display_program.Compile(GetGLSLVersionHeader() + fullscreen_quad_vertex_shader, {},
GetGLSLVersionHeader() + display_fragment_shader))
{
Log_ErrorPrintf("Failed to compile display shaders");
return false;
}
if (!m_gl_context->IsGLES())
m_display_program.BindFragData(0, "o_col0");
if (!m_display_program.Link())
{
Log_ErrorPrintf("Failed to link display program");
return false;
}
m_display_program.Bind();
m_display_program.RegisterUniform("u_src_rect");
m_display_program.RegisterUniform("samp0");
m_display_program.Uniform1i(1, 0);
glGenVertexArrays(1, &m_display_vao);
// samplers
glGenSamplers(1, &m_display_nearest_sampler);
glSamplerParameteri(m_display_nearest_sampler, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glSamplerParameteri(m_display_nearest_sampler, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glGenSamplers(1, &m_display_linear_sampler);
glSamplerParameteri(m_display_linear_sampler, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glSamplerParameteri(m_display_linear_sampler, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
return true;
}
std::unique_ptr<HostDisplay> OpenGLHostDisplay::Create(SDL_Window* window, bool debug_device)
{
std::unique_ptr<OpenGLHostDisplay> display = std::make_unique<OpenGLHostDisplay>(window);
if (!display->CreateGLContext(debug_device) || !display->CreateImGuiContext() || !display->CreateGLResources())
return nullptr;
return display;
}
void OpenGLHostDisplay::Render()
{
glDisable(GL_SCISSOR_TEST);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT);
RenderDisplay();
ImGui::Render();
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
m_gl_context->SwapBuffers();
ImGui::NewFrame();
ImGui_ImplSDL2_NewFrame(m_window);
ImGui_ImplOpenGL3_NewFrame();
GL::Program::ResetLastProgram();
}
void OpenGLHostDisplay::RenderDisplay()
{
if (!m_display_texture_handle)
return;
const auto [vp_left, vp_top, vp_width, vp_height] =
CalculateDrawRect(m_window_width, m_window_height, m_display_top_margin);
glViewport(vp_left, m_window_height - vp_top - vp_height, vp_width, vp_height);
glDisable(GL_BLEND);
glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST);
glDisable(GL_SCISSOR_TEST);
glDepthMask(GL_FALSE);
m_display_program.Bind();
m_display_program.Uniform4f(
0, static_cast<float>(m_display_texture_view_x) / static_cast<float>(m_display_texture_width),
static_cast<float>(m_display_texture_view_y) / static_cast<float>(m_display_texture_height),
(static_cast<float>(m_display_texture_view_width) - 0.5f) / static_cast<float>(m_display_texture_width),
(static_cast<float>(m_display_texture_view_height) + 0.5f) / static_cast<float>(m_display_texture_height));
glBindTexture(GL_TEXTURE_2D, static_cast<GLuint>(reinterpret_cast<uintptr_t>(m_display_texture_handle)));
glBindSampler(0, m_display_linear_filtering ? m_display_linear_sampler : m_display_nearest_sampler);
glBindVertexArray(m_display_vao);
glDrawArrays(GL_TRIANGLES, 0, 3);
glBindSampler(0, 0);
}

View File

@ -1,51 +0,0 @@
#pragma once
#include "common/gl/context.h"
#include "common/gl/program.h"
#include "common/gl/texture.h"
#include "core/host_display.h"
#include <SDL.h>
#include <memory>
#include <string>
class OpenGLHostDisplay final : public HostDisplay
{
public:
OpenGLHostDisplay(SDL_Window* window);
~OpenGLHostDisplay();
static std::unique_ptr<HostDisplay> Create(SDL_Window* window, bool debug_device);
RenderAPI GetRenderAPI() const override;
void* GetRenderDevice() const override;
void* GetRenderContext() const override;
void WindowResized(s32 new_window_width, s32 new_window_height) override;
std::unique_ptr<HostDisplayTexture> CreateTexture(u32 width, u32 height, const void* data, u32 data_stride,
bool dynamic) override;
void UpdateTexture(HostDisplayTexture* texture, u32 x, u32 y, u32 width, u32 height, const void* data,
u32 data_stride) override;
bool DownloadTexture(const void* texture_handle, u32 x, u32 y, u32 width, u32 height, void* out_data,
u32 out_data_stride) override;
void SetVSync(bool enabled) override;
void Render() override;
private:
const char* GetGLSLVersionString() const;
std::string GetGLSLVersionHeader() const;
bool CreateGLContext(bool debug_device);
bool CreateImGuiContext();
bool CreateGLResources();
void RenderDisplay();
SDL_Window* m_window = nullptr;
std::unique_ptr<GL::Context> m_gl_context;
GL::Program m_display_program;
GLuint m_display_vao = 0;
GLuint m_display_nearest_sampler = 0;
GLuint m_display_linear_sampler = 0;
};

View File

@ -1,121 +0,0 @@
#include "sdl_d3d11_host_display.h"
#include "imgui_impl_sdl.h"
#include "sdl_util.h"
#include <SDL_syswm.h>
#include <array>
#include <dxgi1_5.h>
#include <imgui.h>
#include <imgui_impl_dx11.h>
SDLD3D11HostDisplay::SDLD3D11HostDisplay(SDL_Window* window) : m_window(window)
{
SDL_GetWindowSize(window, &m_window_width, &m_window_height);
}
SDLD3D11HostDisplay::~SDLD3D11HostDisplay()
{
if (m_window)
SDL_DestroyWindow(m_window);
}
std::unique_ptr<HostDisplay> SDLD3D11HostDisplay::Create(SDL_Window* window, std::string_view adapter_name, bool debug_device)
{
std::unique_ptr<SDLD3D11HostDisplay> display = std::make_unique<SDLD3D11HostDisplay>(window);
if (!display->Initialize(adapter_name, debug_device))
return {};
return display;
}
HostDisplay::RenderAPI SDLD3D11HostDisplay::GetRenderAPI() const
{
return m_interface.GetRenderAPI();
}
void* SDLD3D11HostDisplay::GetRenderDevice() const
{
return m_interface.GetRenderDevice();
}
void* SDLD3D11HostDisplay::GetRenderContext() const
{
return m_interface.GetRenderContext();
}
void SDLD3D11HostDisplay::WindowResized(s32 new_window_width, s32 new_window_height)
{
m_interface.ResizeSwapChain(static_cast<u32>(new_window_width), static_cast<u32>(new_window_height));
HostDisplay::WindowResized(static_cast<s32>(m_interface.GetSwapChainWidth()),
static_cast<s32>(m_interface.GetSwapChainHeight()));
ImGui::GetIO().DisplaySize.x = static_cast<float>(m_interface.GetSwapChainWidth());
ImGui::GetIO().DisplaySize.y = static_cast<float>(m_interface.GetSwapChainHeight());
}
std::unique_ptr<HostDisplayTexture> SDLD3D11HostDisplay::CreateTexture(u32 width, u32 height, const void* data,
u32 data_stride, bool dynamic)
{
return m_interface.CreateTexture(width, height, data, data_stride, dynamic);
}
void SDLD3D11HostDisplay::UpdateTexture(HostDisplayTexture* texture, u32 x, u32 y, u32 width, u32 height,
const void* data, u32 data_stride)
{
m_interface.UpdateTexture(texture, x, y, width, height, data, data_stride);
}
bool SDLD3D11HostDisplay::DownloadTexture(const void* texture_handle, u32 x, u32 y, u32 width, u32 height,
void* out_data, u32 out_data_stride)
{
return m_interface.DownloadTexture(texture_handle, x, y, width, height, out_data, out_data_stride);
}
void SDLD3D11HostDisplay::SetVSync(bool enabled)
{
m_interface.SetVSync(enabled);
}
bool SDLD3D11HostDisplay::Initialize(std::string_view adapter_name, bool debug_device)
{
std::optional<WindowInfo> wi = SDLUtil::GetWindowInfoForSDLWindow(m_window);
if (!wi.has_value())
return false;
if (!m_interface.CreateContextAndSwapChain(wi.value(), adapter_name, true, debug_device))
return false;
if (!m_interface.CreateResources())
return false;
if (!m_interface.CreateImGuiContext() || !ImGui_ImplSDL2_InitForVulkan(m_window))
return false;
ImGui_ImplSDL2_NewFrame(m_window);
ImGui::NewFrame();
return true;
}
void SDLD3D11HostDisplay::Render()
{
if (!m_interface.BeginRender())
return;
if (HasDisplayTexture())
{
const auto [left, top, width, height] = CalculateDrawRect(m_window_width, m_window_height, m_display_top_margin);
m_interface.RenderDisplay(left, top, width, height, m_display_texture_handle, m_display_texture_width,
m_display_texture_height, m_display_texture_view_x, m_display_texture_view_y,
m_display_texture_view_width, m_display_texture_view_height, m_display_linear_filtering);
}
m_interface.RenderImGui();
if (HasSoftwareCursor())
{
const auto [left, top, width, height] = CalculateSoftwareCursorDrawRect();
m_interface.RenderSoftwareCursor(left, top, width, height, m_cursor_texture.get());
}
m_interface.EndRenderAndPresent();
ImGui_ImplSDL2_NewFrame(m_window);
}

View File

@ -1,39 +0,0 @@
#pragma once
#include "core/host_display.h"
#include "frontend-common/d3d11_host_display.h"
#include <SDL.h>
class SDLD3D11HostDisplay final : public HostDisplay
{
public:
template<typename T>
using ComPtr = Microsoft::WRL::ComPtr<T>;
SDLD3D11HostDisplay(SDL_Window* window);
~SDLD3D11HostDisplay();
static std::unique_ptr<HostDisplay> Create(SDL_Window* window, std::string_view adapter_name, bool debug_device);
RenderAPI GetRenderAPI() const override;
void* GetRenderDevice() const override;
void* GetRenderContext() const override;
void WindowResized(s32 new_window_width, s32 new_window_height) override;
std::unique_ptr<HostDisplayTexture> CreateTexture(u32 width, u32 height, const void* data, u32 data_stride,
bool dynamic) override;
void UpdateTexture(HostDisplayTexture* texture, u32 x, u32 y, u32 width, u32 height, const void* data,
u32 data_stride) override;
bool DownloadTexture(const void* texture_handle, u32 x, u32 y, u32 width, u32 height, void* out_data,
u32 out_data_stride) override;
void SetVSync(bool enabled) override;
void Render() override;
private:
SDL_Window* m_window = nullptr;
FrontendCommon::D3D11HostDisplay m_interface;
bool Initialize(std::string_view adapter_name, bool debug_device);
};

View File

@ -11,13 +11,14 @@
#include "frontend-common/icon.h"
#include "frontend-common/imgui_styles.h"
#include "frontend-common/ini_settings_interface.h"
#include "frontend-common/opengl_host_display.h"
#include "frontend-common/sdl_audio_stream.h"
#include "frontend-common/sdl_controller_interface.h"
#include "frontend-common/vulkan_host_display.h"
#include "imgui_impl_sdl.h"
#include "opengl_host_display.h"
#include "scmversion/scmversion.h"
#include "sdl_key_names.h"
#include "sdl_vulkan_host_display.h"
#include "sdl_util.h"
#include <cinttypes>
#include <cmath>
#include <imgui.h>
@ -26,7 +27,7 @@
Log_SetChannel(SDLHostInterface);
#ifdef WIN32
#include "sdl_d3d11_host_display.h"
#include "frontend-common/d3d11_host_display.h"
#endif
SDLHostInterface::SDLHostInterface()
@ -129,49 +130,86 @@ void SDLHostInterface::DestroySDLWindow()
bool SDLHostInterface::CreateDisplay()
{
const std::string shader_cache_directory(GetShaderCacheDirectory());
std::unique_ptr<HostDisplay> display;
std::optional<WindowInfo> wi = SDLUtil::GetWindowInfoForSDLWindow(m_window);
if (!wi.has_value())
{
ReportError("Failed to get window info from SDL window");
return false;
}
std::unique_ptr<HostDisplay> display;
switch (m_settings.gpu_renderer)
{
case GPURenderer::HardwareVulkan:
display = SDLVulkanHostDisplay::Create(m_window, m_settings.gpu_adapter, shader_cache_directory,
m_settings.gpu_use_debug_device);
display = std::make_unique<FrontendCommon::VulkanHostDisplay>();
break;
case GPURenderer::HardwareOpenGL:
#ifndef WIN32
default:
#endif
display = OpenGLHostDisplay::Create(m_window, m_settings.gpu_use_debug_device);
display = std::make_unique<FrontendCommon::OpenGLHostDisplay>();
break;
#ifdef WIN32
case GPURenderer::HardwareD3D11:
default:
display = SDLD3D11HostDisplay::Create(m_window, m_settings.gpu_adapter, m_settings.gpu_use_debug_device);
display = std::make_unique<FrontendCommon::D3D11HostDisplay>();
break;
#endif
}
if (!display)
Assert(display);
if (!display->CreateRenderDevice(wi.value(), m_settings.gpu_adapter, m_settings.gpu_use_debug_device) ||
!display->InitializeRenderDevice(GetShaderCacheDirectory(), m_settings.gpu_use_debug_device))
{
ReportError("Failed to create/initialize display render device");
return false;
}
bool imgui_result;
switch (display->GetRenderAPI())
{
#ifdef WIN32
case HostDisplay::RenderAPI::D3D11:
imgui_result = ImGui_ImplSDL2_InitForD3D(m_window);
break;
#endif
case HostDisplay::RenderAPI::Vulkan:
imgui_result = ImGui_ImplSDL2_InitForVulkan(m_window);
break;
case HostDisplay::RenderAPI::OpenGL:
case HostDisplay::RenderAPI::OpenGLES:
imgui_result = ImGui_ImplSDL2_InitForOpenGL(m_window, nullptr);
break;
default:
imgui_result = true;
break;
}
if (!imgui_result)
{
ReportError("Failed to initialize ImGui SDL2 wrapper");
return false;
}
m_app_icon_texture =
display->CreateTexture(APP_ICON_WIDTH, APP_ICON_HEIGHT, APP_ICON_DATA, APP_ICON_WIDTH * sizeof(u32));
if (!display)
if (!m_app_icon_texture)
return false;
display->SetDisplayTopMargin(m_fullscreen ? 0 : static_cast<int>(20.0f * ImGui::GetIO().DisplayFramebufferScale.x));
m_display = display.release();
m_display = std::move(display);
return true;
}
void SDLHostInterface::DestroyDisplay()
{
m_app_icon_texture.reset();
delete m_display;
m_display = nullptr;
m_display->DestroyRenderDevice();
m_display.reset();
}
void SDLHostInterface::CreateImGuiContext()
@ -227,13 +265,16 @@ bool SDLHostInterface::AcquireHostDisplay()
{
ImGui::EndFrame();
DestroyDisplay();
DestroySDLWindow();
// We need to recreate the window, otherwise bad things happen...
DestroySDLWindow();
if (!CreateSDLWindow())
Panic("Failed to recreate SDL window on GPU renderer switch");
if (!CreateDisplay())
Panic("Failed to recreate display on GPU renderer switch");
ImGui::NewFrame();
}
return true;
@ -357,7 +398,7 @@ bool SDLHostInterface::SetFullscreen(bool enabled)
int window_width, window_height;
SDL_GetWindowSize(m_window, &window_width, &window_height);
m_display->WindowResized(window_width, window_height);
m_display->ResizeRenderWindow(window_width, window_height);
m_fullscreen = enabled;
return true;
}
@ -389,6 +430,8 @@ bool SDLHostInterface::Initialize()
return false;
}
ImGui::NewFrame();
RegisterHotkeys();
// process events to pick up controllers before updating input map
@ -488,7 +531,7 @@ void SDLHostInterface::HandleSDLEvent(const SDL_Event* event)
{
if (event->window.event == SDL_WINDOWEVENT_RESIZED)
{
m_display->WindowResized(event->window.data1, event->window.data2);
m_display->ResizeRenderWindow(event->window.data1, event->window.data2);
UpdateFramebufferScale();
}
else if (event->window.event == SDL_WINDOWEVENT_MOVED)
@ -1492,6 +1535,8 @@ void SDLHostInterface::Run()
m_system->GetGPU()->ResetGraphicsAPIState();
m_display->Render();
ImGui_ImplSDL2_NewFrame(m_window);
ImGui::NewFrame();
if (m_system)
{

View File

@ -1,137 +0,0 @@
#include "sdl_vulkan_host_display.h"
#include "common/assert.h"
#include "common/log.h"
#include "imgui.h"
#include "imgui_impl_sdl.h"
#include "imgui_impl_vulkan.h"
#include "sdl_util.h"
#include <SDL_syswm.h>
#include <array>
Log_SetChannel(VulkanHostDisplay);
SDLVulkanHostDisplay::SDLVulkanHostDisplay(SDL_Window* window) : m_window(window)
{
SDL_GetWindowSize(window, &m_window_width, &m_window_height);
}
SDLVulkanHostDisplay::~SDLVulkanHostDisplay()
{
ImGui_ImplSDL2_Shutdown();
m_display.DestroyImGuiContext();
m_display.DestroyResources();
m_display.DestroyShaderCache();
m_display.DestroySwapChain();
m_display.DestroyContext();
if (m_window)
SDL_DestroyWindow(m_window);
}
std::unique_ptr<HostDisplay> SDLVulkanHostDisplay::Create(SDL_Window* window, std::string_view adapter_name,
std::string_view shader_cache_directory, bool debug_device)
{
std::unique_ptr<SDLVulkanHostDisplay> display = std::make_unique<SDLVulkanHostDisplay>(window);
if (!display->Initialize(adapter_name, shader_cache_directory, debug_device))
return nullptr;
return display;
}
HostDisplay::RenderAPI SDLVulkanHostDisplay::GetRenderAPI() const
{
return m_display.GetRenderAPI();
}
void* SDLVulkanHostDisplay::GetRenderDevice() const
{
return m_display.GetRenderDevice();
}
void* SDLVulkanHostDisplay::GetRenderContext() const
{
return m_display.GetRenderContext();
}
void SDLVulkanHostDisplay::WindowResized(s32 new_window_width, s32 new_window_height)
{
m_display.ResizeSwapChain(static_cast<u32>(new_window_width), static_cast<u32>(new_window_height));
HostDisplay::WindowResized(static_cast<s32>(m_display.GetSwapChainWidth()),
static_cast<s32>(m_display.GetSwapChainHeight()));
ImGui::GetIO().DisplaySize.x = static_cast<float>(m_display.GetSwapChainWidth());
ImGui::GetIO().DisplaySize.y = static_cast<float>(m_display.GetSwapChainHeight());
}
std::unique_ptr<HostDisplayTexture> SDLVulkanHostDisplay::CreateTexture(u32 width, u32 height, const void* data,
u32 data_stride, bool dynamic /*= false*/)
{
return m_display.CreateTexture(width, height, data, data_stride, dynamic);
}
void SDLVulkanHostDisplay::UpdateTexture(HostDisplayTexture* texture, u32 x, u32 y, u32 width, u32 height,
const void* data, u32 data_stride)
{
m_display.UpdateTexture(texture, x, y, width, height, data, data_stride);
}
bool SDLVulkanHostDisplay::DownloadTexture(const void* texture_handle, u32 x, u32 y, u32 width, u32 height,
void* out_data, u32 out_data_stride)
{
return m_display.DownloadTexture(texture_handle, x, y, width, height, out_data, out_data_stride);
}
void SDLVulkanHostDisplay::SetVSync(bool enabled)
{
m_display.SetVSync(enabled);
}
bool SDLVulkanHostDisplay::Initialize(std::string_view adapter_name, std::string_view shader_cache_directory,
bool debug_device)
{
std::optional<WindowInfo> wi = SDLUtil::GetWindowInfoForSDLWindow(m_window);
if (!wi.has_value())
{
Log_ErrorPrintf("Failed to get window info for SDL window");
return false;
}
if (!m_display.CreateContextAndSwapChain(wi.value(), adapter_name, debug_device))
return false;
m_display.CreateShaderCache(shader_cache_directory, debug_device);
if (!m_display.CreateResources())
return false;
if (!m_display.CreateImGuiContext() || !ImGui_ImplSDL2_InitForVulkan(m_window))
return false;
ImGui_ImplSDL2_NewFrame(m_window);
ImGui::NewFrame();
return true;
}
void SDLVulkanHostDisplay::Render()
{
if (!m_display.BeginRender())
return;
if (HasDisplayTexture())
{
const auto [left, top, width, height] = CalculateDrawRect(m_window_width, m_window_height, m_display_top_margin);
m_display.RenderDisplay(left, top, width, height, m_display_texture_handle, m_display_texture_width,
m_display_texture_height, m_display_texture_view_x, m_display_texture_view_y,
m_display_texture_view_width, m_display_texture_view_height, m_display_linear_filtering);
}
m_display.RenderImGui();
if (HasSoftwareCursor())
{
const auto [left, top, width, height] = CalculateSoftwareCursorDrawRect();
m_display.RenderSoftwareCursor(left, top, width, height, m_cursor_texture.get());
}
m_display.EndRenderAndPresent();
ImGui_ImplSDL2_NewFrame(m_window);
}

View File

@ -1,40 +0,0 @@
#pragma once
#include "core/host_display.h"
#include "frontend-common/vulkan_host_display.h"
#include <SDL.h>
#include <string_view>
class SDLVulkanHostDisplay final : public HostDisplay
{
public:
SDLVulkanHostDisplay(SDL_Window* window);
~SDLVulkanHostDisplay();
static std::unique_ptr<HostDisplay> Create(SDL_Window* window, std::string_view adapter_name,
std::string_view shader_cache_directory, bool debug_device);
RenderAPI GetRenderAPI() const override;
void* GetRenderDevice() const override;
void* GetRenderContext() const override;
void WindowResized(s32 new_window_width, s32 new_window_height) override;
std::unique_ptr<HostDisplayTexture> CreateTexture(u32 width, u32 height, const void* data, u32 data_stride,
bool dynamic = false) override;
void UpdateTexture(HostDisplayTexture* texture, u32 x, u32 y, u32 width, u32 height, const void* data,
u32 data_stride) override;
bool DownloadTexture(const void* texture_handle, u32 x, u32 y, u32 width, u32 height, void* out_data,
u32 out_data_stride) override;
void SetVSync(bool enabled) override;
void Render() override;
private:
bool Initialize(std::string_view adapter_name, std::string_view shader_cache_directory, bool debug_device);
SDL_Window* m_window = nullptr;
FrontendCommon::VulkanHostDisplay m_display;
};