mirror of
https://github.com/WinampDesktop/winamp.git
synced 2025-06-17 18:55:46 -04:00
HostDisplay: Move most backend logic to FrontendCommon
This commit is contained in:
@ -9,13 +9,15 @@ add_library(frontend-common
|
||||
imgui_styles.h
|
||||
ini_settings_interface.cpp
|
||||
ini_settings_interface.h
|
||||
opengl_host_display.cpp
|
||||
opengl_host_display.h
|
||||
save_state_selector_ui.cpp
|
||||
save_state_selector_ui.h
|
||||
vulkan_host_display.cpp
|
||||
vulkan_host_display.h
|
||||
)
|
||||
|
||||
target_link_libraries(frontend-common PUBLIC core common imgui simpleini scmversion vulkan-loader)
|
||||
target_link_libraries(frontend-common PUBLIC core common imgui simpleini scmversion glad vulkan-loader)
|
||||
|
||||
if(WIN32)
|
||||
target_sources(frontend-common PRIVATE
|
||||
@ -25,7 +27,7 @@ if(WIN32)
|
||||
target_link_libraries(frontend-common PRIVATE d3d11.lib dxgi.lib)
|
||||
endif()
|
||||
|
||||
if(SDL2_FOUND)
|
||||
if(SDL2_FOUND AND NOT BUILD_LIBRETRO_CORE)
|
||||
target_sources(frontend-common PRIVATE
|
||||
sdl_audio_stream.cpp
|
||||
sdl_audio_stream.h
|
||||
@ -45,7 +47,7 @@ if(SDL2_FOUND)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(ENABLE_DISCORD_PRESENCE)
|
||||
if(ENABLE_DISCORD_PRESENCE AND NOT BUILD_LIBRETRO_CORE)
|
||||
target_compile_definitions(frontend-common PUBLIC -DWITH_DISCORD_PRESENCE=1)
|
||||
target_link_libraries(frontend-common PRIVATE discord-rpc)
|
||||
endif()
|
||||
|
@ -1814,8 +1814,8 @@ void CommonHostInterface::DisplayLoadingScreen(const char* message, int progress
|
||||
const bool has_progress = (progress_min < progress_max);
|
||||
|
||||
// eat the last imgui frame, it might've been partially rendered by the caller.
|
||||
ImGui::EndFrame();
|
||||
ImGui::NewFrame();
|
||||
//ImGui::EndFrame();
|
||||
//ImGui::NewFrame();
|
||||
|
||||
ImGui::SetNextWindowSize(ImVec2(width, (has_progress ? 50.0f : 30.0f) * scale), ImGuiCond_Always);
|
||||
ImGui::SetNextWindowPos(ImVec2(io.DisplaySize.x * 0.5f, io.DisplaySize.y * 0.5f), ImGuiCond_Always,
|
||||
@ -1843,6 +1843,7 @@ void CommonHostInterface::DisplayLoadingScreen(const char* message, int progress
|
||||
ImGui::End();
|
||||
|
||||
m_display->Render();
|
||||
ImGui::NewFrame();
|
||||
}
|
||||
|
||||
void CommonHostInterface::GetGameInfo(const char* path, CDImage* image, std::string* code, std::string* title)
|
||||
|
@ -67,7 +67,36 @@ private:
|
||||
|
||||
D3D11HostDisplay::D3D11HostDisplay() = default;
|
||||
|
||||
D3D11HostDisplay::~D3D11HostDisplay() = default;
|
||||
D3D11HostDisplay::~D3D11HostDisplay()
|
||||
{
|
||||
AssertMsg(!m_context, "Context should have been destroyed by now");
|
||||
AssertMsg(!m_swap_chain, "Swap chain should have been destroyed by now");
|
||||
}
|
||||
|
||||
HostDisplay::RenderAPI D3D11HostDisplay::GetRenderAPI() const
|
||||
{
|
||||
return HostDisplay::RenderAPI::D3D11;
|
||||
}
|
||||
|
||||
void* D3D11HostDisplay::GetRenderDevice() const
|
||||
{
|
||||
return m_device.Get();
|
||||
}
|
||||
|
||||
void* D3D11HostDisplay::GetRenderContext() const
|
||||
{
|
||||
return m_context.Get();
|
||||
}
|
||||
|
||||
bool D3D11HostDisplay::HasRenderDevice() const
|
||||
{
|
||||
return static_cast<bool>(m_device);
|
||||
}
|
||||
|
||||
bool D3D11HostDisplay::HasRenderSurface() const
|
||||
{
|
||||
return static_cast<bool>(m_swap_chain);
|
||||
}
|
||||
|
||||
std::unique_ptr<HostDisplayTexture> D3D11HostDisplay::CreateTexture(u32 width, u32 height, const void* initial_data,
|
||||
u32 initial_data_stride, bool dynamic)
|
||||
@ -135,13 +164,7 @@ void D3D11HostDisplay::SetVSync(bool enabled)
|
||||
m_vsync = enabled;
|
||||
}
|
||||
|
||||
bool D3D11HostDisplay::HasContext() const
|
||||
{
|
||||
return static_cast<bool>(m_device);
|
||||
}
|
||||
|
||||
bool D3D11HostDisplay::CreateContextAndSwapChain(const WindowInfo& wi, std::string_view adapter_name,
|
||||
bool use_flip_model, bool debug_device)
|
||||
bool D3D11HostDisplay::CreateRenderDevice(const WindowInfo& wi, std::string_view adapter_name, bool debug_device)
|
||||
{
|
||||
UINT create_flags = 0;
|
||||
if (debug_device)
|
||||
@ -242,24 +265,53 @@ bool D3D11HostDisplay::CreateContextAndSwapChain(const WindowInfo& wi, std::stri
|
||||
m_allow_tearing_supported = (allow_tearing_supported == TRUE);
|
||||
}
|
||||
|
||||
return CreateSwapChain(wi, use_flip_model);
|
||||
m_window_info = wi;
|
||||
return true;
|
||||
}
|
||||
|
||||
void D3D11HostDisplay::DestroyContext()
|
||||
bool D3D11HostDisplay::InitializeRenderDevice(std::string_view shader_cache_directory, bool debug_device)
|
||||
{
|
||||
Assert(!m_swap_chain);
|
||||
if (!CreateSwapChain())
|
||||
return false;
|
||||
|
||||
if (!CreateResources())
|
||||
return false;
|
||||
|
||||
if (ImGui::GetCurrentContext() && !CreateImGuiContext())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void D3D11HostDisplay::DestroyRenderDevice()
|
||||
{
|
||||
if (ImGui::GetCurrentContext())
|
||||
DestroyImGuiContext();
|
||||
|
||||
DestroyResources();
|
||||
DestroyRenderSurface();
|
||||
m_context.Reset();
|
||||
m_device.Reset();
|
||||
}
|
||||
|
||||
bool D3D11HostDisplay::CreateSwapChain(const WindowInfo& new_wi, bool use_flip_model)
|
||||
bool D3D11HostDisplay::MakeRenderContextCurrent()
|
||||
{
|
||||
if (new_wi.type != WindowInfo::Type::Win32)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool D3D11HostDisplay::DoneRenderContextCurrent()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool D3D11HostDisplay::CreateSwapChain()
|
||||
{
|
||||
if (m_window_info.type != WindowInfo::Type::Win32)
|
||||
return false;
|
||||
|
||||
m_using_flip_model_swap_chain = use_flip_model;
|
||||
m_using_flip_model_swap_chain = UseFlipModelSwapChain();
|
||||
|
||||
const HWND window_hwnd = reinterpret_cast<HWND>(new_wi.window_handle);
|
||||
const HWND window_hwnd = reinterpret_cast<HWND>(m_window_info.window_handle);
|
||||
RECT client_rc{};
|
||||
GetClientRect(window_hwnd, &client_rc);
|
||||
const u32 width = static_cast<u32>(client_rc.right - client_rc.left);
|
||||
@ -330,23 +382,33 @@ bool D3D11HostDisplay::CreateSwapChainRTV()
|
||||
return false;
|
||||
}
|
||||
|
||||
m_swap_chain_width = backbuffer_desc.Width;
|
||||
m_swap_chain_height = backbuffer_desc.Height;
|
||||
m_window_info.surface_width = backbuffer_desc.Width;
|
||||
m_window_info.surface_height = backbuffer_desc.Height;
|
||||
|
||||
if (ImGui::GetCurrentContext())
|
||||
{
|
||||
ImGui::GetIO().DisplaySize.x = static_cast<float>(backbuffer_desc.Width);
|
||||
ImGui::GetIO().DisplaySize.y = static_cast<float>(backbuffer_desc.Height);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool D3D11HostDisplay::RecreateSwapChain(const WindowInfo& new_wi, bool use_flip_model)
|
||||
bool D3D11HostDisplay::ChangeRenderWindow(const WindowInfo& new_wi)
|
||||
{
|
||||
return CreateSwapChain(new_wi, use_flip_model);
|
||||
DestroyRenderSurface();
|
||||
|
||||
m_window_info = new_wi;
|
||||
return CreateSwapChain();
|
||||
}
|
||||
|
||||
void D3D11HostDisplay::DestroySwapChain()
|
||||
void D3D11HostDisplay::DestroyRenderSurface()
|
||||
{
|
||||
m_swap_chain_rtv.Reset();
|
||||
m_swap_chain.Reset();
|
||||
}
|
||||
|
||||
void D3D11HostDisplay::ResizeSwapChain(u32 new_width, u32 new_height)
|
||||
void D3D11HostDisplay::ResizeRenderWindow(s32 new_window_width, s32 new_window_height)
|
||||
{
|
||||
if (!m_swap_chain)
|
||||
return;
|
||||
@ -423,8 +485,8 @@ void D3D11HostDisplay::DestroyResources()
|
||||
|
||||
bool D3D11HostDisplay::CreateImGuiContext()
|
||||
{
|
||||
ImGui::GetIO().DisplaySize.x = static_cast<float>(m_swap_chain_width);
|
||||
ImGui::GetIO().DisplaySize.y = static_cast<float>(m_swap_chain_height);
|
||||
ImGui::GetIO().DisplaySize.x = static_cast<float>(m_window_info.surface_width);
|
||||
ImGui::GetIO().DisplaySize.y = static_cast<float>(m_window_info.surface_height);
|
||||
|
||||
if (!ImGui_ImplDX11_Init(m_device.Get(), m_context.Get()))
|
||||
return false;
|
||||
@ -438,12 +500,27 @@ void D3D11HostDisplay::DestroyImGuiContext()
|
||||
ImGui_ImplDX11_Shutdown();
|
||||
}
|
||||
|
||||
bool D3D11HostDisplay::BeginRender()
|
||||
bool D3D11HostDisplay::Render()
|
||||
{
|
||||
static constexpr std::array<float, 4> clear_color = {};
|
||||
m_context->ClearRenderTargetView(m_swap_chain_rtv.Get(), clear_color.data());
|
||||
m_context->OMSetRenderTargets(1, m_swap_chain_rtv.GetAddressOf(), nullptr);
|
||||
|
||||
RenderDisplay();
|
||||
|
||||
if (ImGui::GetCurrentContext())
|
||||
RenderImGui();
|
||||
|
||||
RenderSoftwareCursor();
|
||||
|
||||
if (!m_vsync && m_using_allow_tearing)
|
||||
m_swap_chain->Present(0, DXGI_PRESENT_ALLOW_TEARING);
|
||||
else
|
||||
m_swap_chain->Present(BoolToUInt32(m_vsync), 0);
|
||||
|
||||
if (ImGui::GetCurrentContext())
|
||||
ImGui_ImplDX11_NewFrame();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -453,20 +530,20 @@ void D3D11HostDisplay::RenderImGui()
|
||||
ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData());
|
||||
}
|
||||
|
||||
void D3D11HostDisplay::EndRenderAndPresent()
|
||||
void D3D11HostDisplay::RenderDisplay()
|
||||
{
|
||||
if (!m_vsync && m_using_allow_tearing)
|
||||
m_swap_chain->Present(0, DXGI_PRESENT_ALLOW_TEARING);
|
||||
else
|
||||
m_swap_chain->Present(BoolToUInt32(m_vsync), 0);
|
||||
if (!HasDisplayTexture())
|
||||
return;
|
||||
|
||||
ImGui::NewFrame();
|
||||
ImGui_ImplDX11_NewFrame();
|
||||
const auto [left, top, width, height] = CalculateDrawRect(GetWindowWidth(), GetWindowHeight(), m_display_top_margin);
|
||||
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);
|
||||
}
|
||||
|
||||
void D3D11HostDisplay::RenderDisplay(s32 left, s32 top, s32 width, s32 height, void* texture_handle, u32 texture_width,
|
||||
u32 texture_height, u32 texture_view_x, u32 texture_view_y, u32 texture_view_width,
|
||||
u32 texture_view_height, bool linear_filter)
|
||||
s32 texture_height, s32 texture_view_x, s32 texture_view_y, s32 texture_view_width,
|
||||
s32 texture_view_height, bool linear_filter)
|
||||
{
|
||||
m_context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
||||
m_context->VSSetShader(m_display_vertex_shader.Get(), nullptr, 0);
|
||||
@ -493,6 +570,15 @@ void D3D11HostDisplay::RenderDisplay(s32 left, s32 top, s32 width, s32 height, v
|
||||
m_context->Draw(3, 0);
|
||||
}
|
||||
|
||||
void D3D11HostDisplay::RenderSoftwareCursor()
|
||||
{
|
||||
if (!HasSoftwareCursor())
|
||||
return;
|
||||
|
||||
const auto [left, top, width, height] = CalculateSoftwareCursorDrawRect();
|
||||
RenderSoftwareCursor(left, top, width, height, m_cursor_texture.get());
|
||||
}
|
||||
|
||||
void D3D11HostDisplay::RenderSoftwareCursor(s32 left, s32 top, s32 width, s32 height,
|
||||
HostDisplayTexture* texture_handle)
|
||||
{
|
||||
@ -574,4 +660,9 @@ std::vector<std::string> D3D11HostDisplay::EnumerateAdapterNames(IDXGIFactory* d
|
||||
return adapter_names;
|
||||
}
|
||||
|
||||
bool D3D11HostDisplay::UseFlipModelSwapChain() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace FrontendCommon
|
||||
|
@ -15,7 +15,7 @@
|
||||
|
||||
namespace FrontendCommon {
|
||||
|
||||
class D3D11HostDisplay final
|
||||
class D3D11HostDisplay : public HostDisplay
|
||||
{
|
||||
public:
|
||||
template<typename T>
|
||||
@ -24,56 +24,62 @@ public:
|
||||
D3D11HostDisplay();
|
||||
~D3D11HostDisplay();
|
||||
|
||||
ALWAYS_INLINE HostDisplay::RenderAPI GetRenderAPI() const { return HostDisplay::RenderAPI::D3D11; }
|
||||
ALWAYS_INLINE void* GetRenderDevice() const { return m_device.Get(); }
|
||||
ALWAYS_INLINE void* GetRenderContext() const { return m_context.Get(); }
|
||||
virtual RenderAPI GetRenderAPI() const override;
|
||||
virtual void* GetRenderDevice() const override;
|
||||
virtual void* GetRenderContext() const override;
|
||||
|
||||
bool CreateContextAndSwapChain(const WindowInfo& wi, std::string_view adapter_name, bool use_flip_model,
|
||||
bool debug_device);
|
||||
bool HasContext() const;
|
||||
void DestroyContext();
|
||||
virtual bool HasRenderDevice() const override;
|
||||
virtual bool HasRenderSurface() const override;
|
||||
|
||||
bool CreateResources();
|
||||
void DestroyResources();
|
||||
virtual bool CreateRenderDevice(const WindowInfo& wi, std::string_view adapter_name, bool debug_device) override;
|
||||
virtual bool InitializeRenderDevice(std::string_view shader_cache_directory, bool debug_device) override;
|
||||
virtual void DestroyRenderDevice() override;
|
||||
|
||||
bool CreateImGuiContext();
|
||||
void DestroyImGuiContext();
|
||||
virtual bool MakeRenderContextCurrent() override;
|
||||
virtual bool DoneRenderContextCurrent() override;
|
||||
|
||||
ALWAYS_INLINE u32 GetSwapChainWidth() const { return m_swap_chain_width; }
|
||||
ALWAYS_INLINE u32 GetSwapChainHeight() const { return m_swap_chain_height; }
|
||||
ALWAYS_INLINE bool HasSwapChain() const { return static_cast<bool>(m_swap_chain); }
|
||||
|
||||
bool RecreateSwapChain(const WindowInfo& new_wi, bool use_flip_model);
|
||||
void ResizeSwapChain(u32 new_width, u32 new_height);
|
||||
void DestroySwapChain();
|
||||
virtual bool ChangeRenderWindow(const WindowInfo& new_wi) override;
|
||||
virtual void ResizeRenderWindow(s32 new_window_width, s32 new_window_height) override;
|
||||
virtual void DestroyRenderSurface() override;
|
||||
|
||||
std::unique_ptr<HostDisplayTexture> CreateTexture(u32 width, u32 height, const void* initial_data,
|
||||
u32 initial_data_stride, bool dynamic);
|
||||
u32 initial_data_stride, bool dynamic) override;
|
||||
void UpdateTexture(HostDisplayTexture* texture, u32 x, u32 y, u32 width, u32 height, const void* texture_data,
|
||||
u32 texture_data_stride);
|
||||
u32 texture_data_stride) override;
|
||||
bool DownloadTexture(const void* texture_handle, u32 x, u32 y, u32 width, u32 height, void* out_data,
|
||||
u32 out_data_stride);
|
||||
u32 out_data_stride) override;
|
||||
|
||||
void SetVSync(bool enabled);
|
||||
virtual void SetVSync(bool enabled) override;
|
||||
|
||||
bool BeginRender();
|
||||
void RenderDisplay(s32 left, s32 top, s32 width, s32 height, void* texture_handle, u32 texture_width,
|
||||
u32 texture_height, u32 texture_view_x, u32 texture_view_y, u32 texture_view_width,
|
||||
u32 texture_view_height, bool linear_filter);
|
||||
void RenderImGui();
|
||||
void RenderSoftwareCursor(s32 left, s32 top, s32 width, s32 height, HostDisplayTexture* texture_handle);
|
||||
void EndRenderAndPresent();
|
||||
virtual bool Render() override;
|
||||
|
||||
static std::vector<std::string> EnumerateAdapterNames();
|
||||
|
||||
private:
|
||||
protected:
|
||||
static constexpr u32 DISPLAY_UNIFORM_BUFFER_SIZE = 16;
|
||||
|
||||
virtual bool UseFlipModelSwapChain() const;
|
||||
|
||||
static std::vector<std::string> EnumerateAdapterNames(IDXGIFactory* dxgi_factory);
|
||||
|
||||
bool CreateSwapChain(const WindowInfo& new_wi, bool use_flip_model);
|
||||
virtual bool CreateResources();
|
||||
virtual void DestroyResources();
|
||||
|
||||
virtual bool CreateImGuiContext();
|
||||
virtual void DestroyImGuiContext();
|
||||
|
||||
bool CreateSwapChain();
|
||||
bool CreateSwapChainRTV();
|
||||
|
||||
void RenderDisplay();
|
||||
void RenderImGui();
|
||||
void RenderSoftwareCursor();
|
||||
|
||||
void RenderDisplay(s32 left, s32 top, s32 width, s32 height, void* texture_handle, u32 texture_width,
|
||||
s32 texture_height, s32 texture_view_x, s32 texture_view_y, s32 texture_view_width,
|
||||
s32 texture_view_height, bool linear_filter);
|
||||
void RenderSoftwareCursor(s32 left, s32 top, s32 width, s32 height, HostDisplayTexture* texture_handle);
|
||||
|
||||
ComPtr<IDXGIFactory> m_dxgi_factory;
|
||||
|
||||
ComPtr<ID3D11Device> m_device;
|
||||
@ -94,9 +100,6 @@ private:
|
||||
D3D11::StreamBuffer m_display_uniform_buffer;
|
||||
D3D11::AutoStagingTexture m_readback_staging_texture;
|
||||
|
||||
u32 m_swap_chain_width = 0;
|
||||
u32 m_swap_chain_height = 0;
|
||||
|
||||
bool m_allow_tearing_supported = false;
|
||||
bool m_using_flip_model_swap_chain = true;
|
||||
bool m_using_allow_tearing = false;
|
||||
|
@ -44,6 +44,9 @@
|
||||
<ProjectReference Include="..\..\dep\glad\glad.vcxproj">
|
||||
<Project>{43540154-9e1e-409c-834f-b84be5621388}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\dep\imgui\imgui.vcxproj">
|
||||
<Project>{bb08260f-6fbc-46af-8924-090ee71360c6}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\dep\libcue\libcue.vcxproj">
|
||||
<Project>{6a4208ed-e3dc-41e1-81cd-f61025fc285a}</Project>
|
||||
</ProjectReference>
|
||||
@ -67,6 +70,7 @@
|
||||
<ClCompile Include="icon.cpp" />
|
||||
<ClCompile Include="imgui_styles.cpp" />
|
||||
<ClCompile Include="ini_settings_interface.cpp" />
|
||||
<ClCompile Include="opengl_host_display.cpp" />
|
||||
<ClCompile Include="save_state_selector_ui.cpp" />
|
||||
<ClCompile Include="sdl_audio_stream.cpp" />
|
||||
<ClCompile Include="sdl_controller_interface.cpp" />
|
||||
@ -80,6 +84,7 @@
|
||||
<ClInclude Include="icon.h" />
|
||||
<ClInclude Include="imgui_styles.h" />
|
||||
<ClInclude Include="ini_settings_interface.h" />
|
||||
<ClInclude Include="opengl_host_display.h" />
|
||||
<ClInclude Include="save_state_selector_ui.h" />
|
||||
<ClInclude Include="sdl_audio_stream.h" />
|
||||
<ClInclude Include="sdl_controller_interface.h" />
|
||||
@ -234,7 +239,7 @@
|
||||
<PreprocessorDefinitions>WITH_SDL2=1;WITH_DISCORD_PRESENCE=1;WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\discord-rpc\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\discord-rpc\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
@ -261,7 +266,7 @@
|
||||
<PreprocessorDefinitions>WITH_SDL2=1;WITH_DISCORD_PRESENCE=1;_ITERATOR_DEBUG_LEVEL=1;WIN32;_DEBUGFAST;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\discord-rpc\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\discord-rpc\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
|
||||
<SupportJustMyCode>false</SupportJustMyCode>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
@ -291,7 +296,7 @@
|
||||
<PreprocessorDefinitions>WITH_SDL2=1;WITH_DISCORD_PRESENCE=1;WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\discord-rpc\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\discord-rpc\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
@ -318,7 +323,7 @@
|
||||
<PreprocessorDefinitions>WITH_SDL2=1;WITH_DISCORD_PRESENCE=1;_ITERATOR_DEBUG_LEVEL=1;WIN32;_DEBUGFAST;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\discord-rpc\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\discord-rpc\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
|
||||
<SupportJustMyCode>false</SupportJustMyCode>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
@ -349,7 +354,7 @@
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WITH_SDL2=1;WITH_DISCORD_PRESENCE=1;WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\discord-rpc\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\discord-rpc\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<WholeProgramOptimization>false</WholeProgramOptimization>
|
||||
@ -378,7 +383,7 @@
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WITH_SDL2=1;WITH_DISCORD_PRESENCE=1;WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\discord-rpc\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\discord-rpc\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<OmitFramePointers>true</OmitFramePointers>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
@ -409,7 +414,7 @@
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WITH_SDL2=1;WITH_DISCORD_PRESENCE=1;WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\discord-rpc\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\discord-rpc\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<WholeProgramOptimization>false</WholeProgramOptimization>
|
||||
@ -438,7 +443,7 @@
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WITH_SDL2=1;WITH_DISCORD_PRESENCE=1;WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\discord-rpc\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\discord-rpc\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<OmitFramePointers>true</OmitFramePointers>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
|
@ -12,6 +12,7 @@
|
||||
<ClCompile Include="save_state_selector_ui.cpp" />
|
||||
<ClCompile Include="vulkan_host_display.cpp" />
|
||||
<ClCompile Include="d3d11_host_display.cpp" />
|
||||
<ClCompile Include="opengl_host_display.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="icon.h" />
|
||||
@ -25,6 +26,7 @@
|
||||
<ClInclude Include="save_state_selector_ui.h" />
|
||||
<ClInclude Include="vulkan_host_display.h" />
|
||||
<ClInclude Include="d3d11_host_display.h" />
|
||||
<ClInclude Include="opengl_host_display.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="font_roboto_regular.inl" />
|
||||
|
487
src/frontend-common/opengl_host_display.cpp
Normal file
487
src/frontend-common/opengl_host_display.cpp
Normal file
@ -0,0 +1,487 @@
|
||||
#include "opengl_host_display.h"
|
||||
#include "common/assert.h"
|
||||
#include "common/log.h"
|
||||
#include "imgui.h"
|
||||
#include <array>
|
||||
#include <imgui_impl_opengl3.h>
|
||||
#include <tuple>
|
||||
Log_SetChannel(LibretroOpenGLHostDisplay);
|
||||
|
||||
namespace FrontendCommon {
|
||||
|
||||
class OpenGLHostDisplayTexture : public HostDisplayTexture
|
||||
{
|
||||
public:
|
||||
OpenGLHostDisplayTexture(GLuint id, u32 width, u32 height) : m_id(id), m_width(width), m_height(height) {}
|
||||
~OpenGLHostDisplayTexture() 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<OpenGLHostDisplayTexture> 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<OpenGLHostDisplayTexture>(id, width, height);
|
||||
}
|
||||
|
||||
private:
|
||||
GLuint m_id;
|
||||
u32 m_width;
|
||||
u32 m_height;
|
||||
};
|
||||
|
||||
OpenGLHostDisplay::OpenGLHostDisplay() = default;
|
||||
|
||||
OpenGLHostDisplay::~OpenGLHostDisplay()
|
||||
{
|
||||
AssertMsg(!m_gl_context, "Context should have been destroyed by now");
|
||||
}
|
||||
|
||||
HostDisplay::RenderAPI OpenGLHostDisplay::GetRenderAPI() const
|
||||
{
|
||||
return m_gl_context->IsGLES() ? RenderAPI::OpenGLES : RenderAPI::OpenGL;
|
||||
}
|
||||
|
||||
void* OpenGLHostDisplay::GetRenderDevice() const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void* OpenGLHostDisplay::GetRenderContext() const
|
||||
{
|
||||
return m_gl_context.get();
|
||||
}
|
||||
|
||||
std::unique_ptr<HostDisplayTexture> OpenGLHostDisplay::CreateTexture(u32 width, u32 height, const void* initial_data,
|
||||
u32 initial_data_stride, bool dynamic)
|
||||
{
|
||||
return OpenGLHostDisplayTexture::Create(width, height, initial_data, initial_data_stride);
|
||||
}
|
||||
|
||||
void OpenGLHostDisplay::UpdateTexture(HostDisplayTexture* texture, u32 x, u32 y, u32 width, u32 height,
|
||||
const void* texture_data, u32 texture_data_stride)
|
||||
{
|
||||
OpenGLHostDisplayTexture* tex = static_cast<OpenGLHostDisplayTexture*>(texture);
|
||||
Assert((texture_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, texture_data_stride / sizeof(u32));
|
||||
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, texture_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, ¤t_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 (GetRenderAPI() == RenderAPI::OpenGLES)
|
||||
{
|
||||
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 (GetRenderAPI() == RenderAPI::OpenGLES)
|
||||
{
|
||||
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::HasRenderDevice() const
|
||||
{
|
||||
return static_cast<bool>(m_gl_context);
|
||||
}
|
||||
|
||||
bool OpenGLHostDisplay::HasRenderSurface() const
|
||||
{
|
||||
return m_window_info.type != WindowInfo::Type::Surfaceless;
|
||||
}
|
||||
|
||||
bool OpenGLHostDisplay::CreateRenderDevice(const WindowInfo& wi, std::string_view adapter_name, bool debug_device)
|
||||
{
|
||||
m_gl_context = GL::Context::Create(wi);
|
||||
if (!m_gl_context)
|
||||
{
|
||||
Log_ErrorPrintf("Failed to create any GL context");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_window_info = wi;
|
||||
m_window_info.surface_width = m_gl_context->GetSurfaceWidth();
|
||||
m_window_info.surface_height = m_gl_context->GetSurfaceHeight();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OpenGLHostDisplay::InitializeRenderDevice(std::string_view shader_cache_directory, bool debug_device)
|
||||
{
|
||||
if (debug_device && GLAD_GL_KHR_debug)
|
||||
{
|
||||
if (GetRenderAPI() == RenderAPI::OpenGLES)
|
||||
glDebugMessageCallbackKHR(GLDebugCallback, nullptr);
|
||||
else
|
||||
glDebugMessageCallback(GLDebugCallback, nullptr);
|
||||
|
||||
glEnable(GL_DEBUG_OUTPUT);
|
||||
// glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
|
||||
}
|
||||
|
||||
if (!CreateResources())
|
||||
return false;
|
||||
|
||||
if (ImGui::GetCurrentContext() && !CreateImGuiContext())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OpenGLHostDisplay::MakeRenderContextCurrent()
|
||||
{
|
||||
if (!m_gl_context->MakeCurrent())
|
||||
{
|
||||
Log_ErrorPrintf("Failed to make GL context current");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OpenGLHostDisplay::DoneRenderContextCurrent()
|
||||
{
|
||||
return m_gl_context->DoneCurrent();
|
||||
}
|
||||
|
||||
void OpenGLHostDisplay::DestroyRenderDevice()
|
||||
{
|
||||
if (!m_gl_context)
|
||||
return;
|
||||
|
||||
if (ImGui::GetCurrentContext())
|
||||
DestroyImGuiContext();
|
||||
|
||||
DestroyResources();
|
||||
|
||||
m_gl_context->DoneCurrent();
|
||||
m_gl_context.reset();
|
||||
}
|
||||
|
||||
bool OpenGLHostDisplay::ChangeRenderWindow(const WindowInfo& new_wi)
|
||||
{
|
||||
Assert(m_gl_context);
|
||||
|
||||
if (!m_gl_context->ChangeSurface(new_wi))
|
||||
{
|
||||
Log_ErrorPrintf("Failed to change surface");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_window_info = new_wi;
|
||||
m_window_info.surface_width = m_gl_context->GetSurfaceWidth();
|
||||
m_window_info.surface_height = m_gl_context->GetSurfaceHeight();
|
||||
|
||||
if (ImGui::GetCurrentContext())
|
||||
{
|
||||
ImGui::GetIO().DisplaySize.x = static_cast<float>(m_window_info.surface_width);
|
||||
ImGui::GetIO().DisplaySize.y = static_cast<float>(m_window_info.surface_height);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void OpenGLHostDisplay::ResizeRenderWindow(s32 new_window_width, s32 new_window_height)
|
||||
{
|
||||
if (!m_gl_context)
|
||||
return;
|
||||
|
||||
m_gl_context->ResizeSurface(static_cast<u32>(new_window_width), static_cast<u32>(new_window_height));
|
||||
m_window_info.surface_width = m_gl_context->GetSurfaceWidth();
|
||||
m_window_info.surface_height = m_gl_context->GetSurfaceHeight();
|
||||
|
||||
if (ImGui::GetCurrentContext())
|
||||
{
|
||||
ImGui::GetIO().DisplaySize.x = static_cast<float>(m_window_info.surface_width);
|
||||
ImGui::GetIO().DisplaySize.y = static_cast<float>(m_window_info.surface_height);
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLHostDisplay::DestroyRenderSurface()
|
||||
{
|
||||
if (!m_gl_context)
|
||||
return;
|
||||
|
||||
m_window_info = {};
|
||||
if (!m_gl_context->ChangeSurface(m_window_info))
|
||||
Log_ErrorPrintf("Failed to switch to surfaceless");
|
||||
}
|
||||
|
||||
bool OpenGLHostDisplay::CreateImGuiContext()
|
||||
{
|
||||
ImGui::GetIO().DisplaySize.x = static_cast<float>(m_window_info.surface_width);
|
||||
ImGui::GetIO().DisplaySize.y = static_cast<float>(m_window_info.surface_height);
|
||||
|
||||
if (!ImGui_ImplOpenGL3_Init(GetGLSLVersionString()))
|
||||
return false;
|
||||
|
||||
ImGui_ImplOpenGL3_NewFrame();
|
||||
return true;
|
||||
}
|
||||
|
||||
void OpenGLHostDisplay::DestroyImGuiContext()
|
||||
{
|
||||
ImGui_ImplOpenGL3_Shutdown();
|
||||
}
|
||||
|
||||
bool OpenGLHostDisplay::CreateResources()
|
||||
{
|
||||
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 = vec4(texture(samp0, v_tex0).rgb, 1.0);
|
||||
}
|
||||
)";
|
||||
|
||||
if (!m_display_program.Compile(GetGLSLVersionHeader() + fullscreen_quad_vertex_shader, {},
|
||||
GetGLSLVersionHeader() + display_fragment_shader))
|
||||
{
|
||||
Log_ErrorPrintf("Failed to compile display shaders");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (GetRenderAPI() != RenderAPI::OpenGLES)
|
||||
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;
|
||||
}
|
||||
|
||||
void OpenGLHostDisplay::DestroyResources()
|
||||
{
|
||||
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();
|
||||
}
|
||||
|
||||
bool OpenGLHostDisplay::Render()
|
||||
{
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
||||
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
RenderDisplay();
|
||||
|
||||
if (ImGui::GetCurrentContext())
|
||||
RenderImGui();
|
||||
|
||||
RenderSoftwareCursor();
|
||||
|
||||
m_gl_context->SwapBuffers();
|
||||
|
||||
if (ImGui::GetCurrentContext())
|
||||
ImGui_ImplOpenGL3_NewFrame();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void OpenGLHostDisplay::RenderImGui()
|
||||
{
|
||||
ImGui::Render();
|
||||
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
|
||||
GL::Program::ResetLastProgram();
|
||||
}
|
||||
|
||||
void OpenGLHostDisplay::RenderDisplay()
|
||||
{
|
||||
if (!HasDisplayTexture())
|
||||
return;
|
||||
|
||||
const auto [left, top, width, height] = CalculateDrawRect(GetWindowWidth(), GetWindowHeight(), m_display_top_margin);
|
||||
RenderDisplay(left, GetWindowHeight() - top - height, 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);
|
||||
}
|
||||
|
||||
void OpenGLHostDisplay::RenderDisplay(s32 left, s32 bottom, s32 width, s32 height, void* texture_handle,
|
||||
u32 texture_width, s32 texture_height, s32 texture_view_x, s32 texture_view_y,
|
||||
s32 texture_view_width, s32 texture_view_height, bool linear_filter)
|
||||
{
|
||||
glViewport(left, bottom, width, 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>(texture_view_x) / static_cast<float>(texture_width),
|
||||
static_cast<float>(texture_view_y) / static_cast<float>(texture_height),
|
||||
(static_cast<float>(texture_view_width) - 0.5f) / static_cast<float>(texture_width),
|
||||
(static_cast<float>(texture_view_height) + 0.5f) / static_cast<float>(texture_height));
|
||||
glBindTexture(GL_TEXTURE_2D, static_cast<GLuint>(reinterpret_cast<uintptr_t>(texture_handle)));
|
||||
glBindSampler(0, linear_filter ? m_display_linear_sampler : m_display_nearest_sampler);
|
||||
glBindVertexArray(m_display_vao);
|
||||
glDrawArrays(GL_TRIANGLES, 0, 3);
|
||||
glBindSampler(0, 0);
|
||||
}
|
||||
|
||||
void OpenGLHostDisplay::RenderSoftwareCursor()
|
||||
{
|
||||
if (!HasSoftwareCursor())
|
||||
return;
|
||||
|
||||
const auto [left, top, width, height] = CalculateSoftwareCursorDrawRect();
|
||||
RenderSoftwareCursor(left, top, width, height, m_cursor_texture.get());
|
||||
}
|
||||
|
||||
void OpenGLHostDisplay::RenderSoftwareCursor(s32 left, s32 top, s32 width, s32 height,
|
||||
HostDisplayTexture* texture_handle)
|
||||
{
|
||||
glViewport(left, GetWindowHeight() - top - height, width, height);
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ZERO);
|
||||
glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD);
|
||||
glDisable(GL_CULL_FACE);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
glDepthMask(GL_FALSE);
|
||||
m_display_program.Bind();
|
||||
m_display_program.Uniform4f(0, 0.0f, 0.0f, 1.0f, 1.0f);
|
||||
glBindTexture(GL_TEXTURE_2D, static_cast<OpenGLHostDisplayTexture*>(texture_handle)->GetGLID());
|
||||
glBindSampler(0, m_display_linear_sampler);
|
||||
glBindVertexArray(m_display_vao);
|
||||
glDrawArrays(GL_TRIANGLES, 0, 3);
|
||||
glBindSampler(0, 0);
|
||||
}
|
||||
|
||||
} // namespace FrontendCommon
|
82
src/frontend-common/opengl_host_display.h
Normal file
82
src/frontend-common/opengl_host_display.h
Normal file
@ -0,0 +1,82 @@
|
||||
#pragma once
|
||||
|
||||
// GLAD has to come first so that Qt doesn't pull in the system GL headers, which are incompatible with glad.
|
||||
#include <glad.h>
|
||||
|
||||
// Hack to prevent Apple's glext.h headers from getting included via qopengl.h, since we still want to use glad.
|
||||
#ifdef __APPLE__
|
||||
#define __glext_h_
|
||||
#endif
|
||||
|
||||
#include "common/gl/context.h"
|
||||
#include "common/gl/program.h"
|
||||
#include "common/gl/texture.h"
|
||||
#include "common/window_info.h"
|
||||
#include "core/host_display.h"
|
||||
#include <memory>
|
||||
|
||||
namespace FrontendCommon {
|
||||
|
||||
class OpenGLHostDisplay : public HostDisplay
|
||||
{
|
||||
public:
|
||||
OpenGLHostDisplay();
|
||||
virtual ~OpenGLHostDisplay();
|
||||
|
||||
virtual RenderAPI GetRenderAPI() const override;
|
||||
virtual void* GetRenderDevice() const override;
|
||||
virtual void* GetRenderContext() const override;
|
||||
|
||||
virtual bool HasRenderDevice() const override;
|
||||
virtual bool HasRenderSurface() const override;
|
||||
|
||||
virtual bool CreateRenderDevice(const WindowInfo& wi, std::string_view adapter_name, bool debug_device) override;
|
||||
virtual bool InitializeRenderDevice(std::string_view shader_cache_directory, bool debug_device) override;
|
||||
virtual void DestroyRenderDevice() override;
|
||||
|
||||
virtual bool MakeRenderContextCurrent() override;
|
||||
virtual bool DoneRenderContextCurrent() override;
|
||||
|
||||
virtual bool ChangeRenderWindow(const WindowInfo& new_wi) override;
|
||||
virtual void ResizeRenderWindow(s32 new_window_width, s32 new_window_height) override;
|
||||
virtual void DestroyRenderSurface() override;
|
||||
|
||||
std::unique_ptr<HostDisplayTexture> CreateTexture(u32 width, u32 height, const void* initial_data,
|
||||
u32 initial_data_stride, bool dynamic) override;
|
||||
void UpdateTexture(HostDisplayTexture* texture, u32 x, u32 y, u32 width, u32 height, const void* texture_data,
|
||||
u32 texture_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;
|
||||
|
||||
virtual void SetVSync(bool enabled) override;
|
||||
|
||||
virtual bool Render() override;
|
||||
|
||||
protected:
|
||||
const char* GetGLSLVersionString() const;
|
||||
std::string GetGLSLVersionHeader() const;
|
||||
|
||||
virtual bool CreateResources();
|
||||
virtual void DestroyResources();
|
||||
|
||||
virtual bool CreateImGuiContext();
|
||||
virtual void DestroyImGuiContext();
|
||||
|
||||
void RenderDisplay();
|
||||
void RenderImGui();
|
||||
void RenderSoftwareCursor();
|
||||
|
||||
void RenderDisplay(s32 left, s32 bottom, s32 width, s32 height, void* texture_handle, u32 texture_width,
|
||||
s32 texture_height, s32 texture_view_x, s32 texture_view_y, s32 texture_view_width,
|
||||
s32 texture_view_height, bool linear_filter);
|
||||
void RenderSoftwareCursor(s32 left, s32 top, s32 width, s32 height, HostDisplayTexture* texture_handle);
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
} // namespace FrontendCommon
|
@ -96,7 +96,22 @@ VulkanHostDisplay::~VulkanHostDisplay()
|
||||
AssertMsg(!m_swap_chain, "Swap chain should have been destroyed by now");
|
||||
}
|
||||
|
||||
bool VulkanHostDisplay::RecreateSwapChain(const WindowInfo& new_wi)
|
||||
HostDisplay::RenderAPI VulkanHostDisplay::GetRenderAPI() const
|
||||
{
|
||||
return HostDisplay::RenderAPI::Vulkan;
|
||||
}
|
||||
|
||||
void* VulkanHostDisplay::GetRenderDevice() const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void* VulkanHostDisplay::GetRenderContext() const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool VulkanHostDisplay::ChangeRenderWindow(const WindowInfo& new_wi)
|
||||
{
|
||||
Assert(!m_swap_chain);
|
||||
|
||||
@ -115,22 +130,39 @@ bool VulkanHostDisplay::RecreateSwapChain(const WindowInfo& new_wi)
|
||||
return false;
|
||||
}
|
||||
|
||||
m_window_info = wi_copy;
|
||||
m_window_info.surface_width = m_swap_chain->GetWidth();
|
||||
m_window_info.surface_height = m_swap_chain->GetHeight();
|
||||
|
||||
if (ImGui::GetCurrentContext())
|
||||
{
|
||||
ImGui::GetIO().DisplaySize.x = static_cast<float>(m_window_info.surface_width);
|
||||
ImGui::GetIO().DisplaySize.y = static_cast<float>(m_window_info.surface_height);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void VulkanHostDisplay::ResizeSwapChain(u32 new_width, u32 new_height)
|
||||
void VulkanHostDisplay::ResizeRenderWindow(s32 new_window_width, s32 new_window_height)
|
||||
{
|
||||
g_vulkan_context->WaitForGPUIdle();
|
||||
|
||||
if (!m_swap_chain->ResizeSwapChain(new_width, new_height))
|
||||
if (!m_swap_chain->ResizeSwapChain(new_window_width, new_window_height))
|
||||
Panic("Failed to resize swap chain");
|
||||
|
||||
ImGui::GetIO().DisplaySize.x = static_cast<float>(m_swap_chain->GetWidth());
|
||||
ImGui::GetIO().DisplaySize.y = static_cast<float>(m_swap_chain->GetHeight());
|
||||
m_window_info.surface_width = m_swap_chain->GetWidth();
|
||||
m_window_info.surface_height = m_swap_chain->GetHeight();
|
||||
|
||||
if (ImGui::GetCurrentContext())
|
||||
{
|
||||
ImGui::GetIO().DisplaySize.x = static_cast<float>(m_window_info.surface_width);
|
||||
ImGui::GetIO().DisplaySize.y = static_cast<float>(m_window_info.surface_height);
|
||||
}
|
||||
}
|
||||
|
||||
void VulkanHostDisplay::DestroySwapChain()
|
||||
void VulkanHostDisplay::DestroyRenderSurface()
|
||||
{
|
||||
m_window_info = {};
|
||||
m_swap_chain.reset();
|
||||
}
|
||||
|
||||
@ -193,27 +225,47 @@ void VulkanHostDisplay::SetVSync(bool enabled)
|
||||
m_swap_chain->SetVSync(enabled);
|
||||
}
|
||||
|
||||
bool VulkanHostDisplay::CreateContextAndSwapChain(const WindowInfo& wi, std::string_view gpu_name, bool debug_device)
|
||||
bool VulkanHostDisplay::CreateRenderDevice(const WindowInfo& wi, std::string_view adapter_name, bool debug_device)
|
||||
{
|
||||
if (!Vulkan::Context::Create(gpu_name, &wi, &m_swap_chain, debug_device, false))
|
||||
if (!Vulkan::Context::Create(adapter_name, &wi, &m_swap_chain, debug_device, false))
|
||||
{
|
||||
Log_ErrorPrintf("Failed to create Vulkan context");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_window_info = wi;
|
||||
if (m_swap_chain)
|
||||
{
|
||||
m_window_info.surface_width = m_swap_chain->GetWidth();
|
||||
m_window_info.surface_height = m_swap_chain->GetHeight();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void VulkanHostDisplay::CreateShaderCache(std::string_view shader_cache_directory, bool debug_shaders)
|
||||
bool VulkanHostDisplay::InitializeRenderDevice(std::string_view shader_cache_directory, bool debug_device)
|
||||
{
|
||||
Vulkan::ShaderCache::Create(shader_cache_directory, debug_shaders);
|
||||
Vulkan::ShaderCache::Create(shader_cache_directory, debug_device);
|
||||
|
||||
if (!CreateResources())
|
||||
return false;
|
||||
|
||||
if (ImGui::GetCurrentContext() && !CreateImGuiContext())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VulkanHostDisplay::HasContext() const
|
||||
bool VulkanHostDisplay::HasRenderDevice() const
|
||||
{
|
||||
return static_cast<bool>(g_vulkan_context);
|
||||
}
|
||||
|
||||
bool VulkanHostDisplay::HasRenderSurface() const
|
||||
{
|
||||
return static_cast<bool>(m_swap_chain);
|
||||
}
|
||||
|
||||
bool VulkanHostDisplay::CreateResources()
|
||||
{
|
||||
static constexpr char fullscreen_quad_vertex_shader[] = R"(
|
||||
@ -329,24 +381,37 @@ void VulkanHostDisplay::DestroyImGuiContext()
|
||||
ImGui_ImplVulkan_Shutdown();
|
||||
}
|
||||
|
||||
void VulkanHostDisplay::DestroyContext()
|
||||
void VulkanHostDisplay::DestroyRenderDevice()
|
||||
{
|
||||
if (!g_vulkan_context)
|
||||
return;
|
||||
|
||||
g_vulkan_context->WaitForGPUIdle();
|
||||
|
||||
if (ImGui::GetCurrentContext())
|
||||
DestroyImGuiContext();
|
||||
|
||||
DestroyResources();
|
||||
|
||||
Vulkan::ShaderCache::Destroy();
|
||||
DestroyRenderSurface();
|
||||
Vulkan::Context::Destroy();
|
||||
}
|
||||
|
||||
void VulkanHostDisplay::DestroyShaderCache()
|
||||
bool VulkanHostDisplay::MakeRenderContextCurrent()
|
||||
{
|
||||
Vulkan::ShaderCache::Destroy();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VulkanHostDisplay::DoneRenderContextCurrent()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VulkanHostDisplay::CreateImGuiContext()
|
||||
{
|
||||
ImGui::GetIO().DisplaySize.x = static_cast<float>(m_swap_chain->GetWidth());
|
||||
ImGui::GetIO().DisplaySize.y = static_cast<float>(m_swap_chain->GetHeight());
|
||||
ImGui::GetIO().DisplaySize.x = static_cast<float>(m_window_info.surface_width);
|
||||
ImGui::GetIO().DisplaySize.y = static_cast<float>(m_window_info.surface_height);
|
||||
|
||||
ImGui_ImplVulkan_InitInfo vii = {};
|
||||
vii.Instance = g_vulkan_context->GetVulkanInstance();
|
||||
@ -370,14 +435,14 @@ bool VulkanHostDisplay::CreateImGuiContext()
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VulkanHostDisplay::BeginRender()
|
||||
bool VulkanHostDisplay::Render()
|
||||
{
|
||||
VkResult res = m_swap_chain->AcquireNextImage();
|
||||
if (res != VK_SUCCESS)
|
||||
{
|
||||
if (res == VK_SUBOPTIMAL_KHR || res == VK_ERROR_OUT_OF_DATE_KHR)
|
||||
{
|
||||
ResizeSwapChain(0, 0);
|
||||
ResizeRenderWindow(0, 0);
|
||||
res = m_swap_chain->AcquireNextImage();
|
||||
}
|
||||
|
||||
@ -409,13 +474,13 @@ bool VulkanHostDisplay::BeginRender()
|
||||
1u,
|
||||
&clear_value};
|
||||
vkCmdBeginRenderPass(cmdbuffer, &rp, VK_SUBPASS_CONTENTS_INLINE);
|
||||
return true;
|
||||
}
|
||||
|
||||
void VulkanHostDisplay::EndRenderAndPresent()
|
||||
{
|
||||
VkCommandBuffer cmdbuffer = g_vulkan_context->GetCurrentCommandBuffer();
|
||||
Vulkan::Texture& swap_chain_texture = m_swap_chain->GetCurrentTexture();
|
||||
RenderDisplay();
|
||||
|
||||
if (ImGui::GetCurrentContext())
|
||||
RenderImGui();
|
||||
|
||||
RenderSoftwareCursor();
|
||||
|
||||
vkCmdEndRenderPass(cmdbuffer);
|
||||
|
||||
@ -426,13 +491,26 @@ void VulkanHostDisplay::EndRenderAndPresent()
|
||||
m_swap_chain->GetCurrentImageIndex());
|
||||
g_vulkan_context->MoveToNextCommandBuffer();
|
||||
|
||||
ImGui::NewFrame();
|
||||
ImGui_ImplVulkan_NewFrame();
|
||||
if (ImGui::GetCurrentContext())
|
||||
ImGui_ImplVulkan_NewFrame();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void VulkanHostDisplay::RenderDisplay()
|
||||
{
|
||||
if (!HasDisplayTexture())
|
||||
return;
|
||||
|
||||
const auto [left, top, width, height] = CalculateDrawRect(GetWindowWidth(), GetWindowHeight(), m_display_top_margin);
|
||||
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);
|
||||
}
|
||||
|
||||
void VulkanHostDisplay::RenderDisplay(s32 left, s32 top, s32 width, s32 height, void* texture_handle, u32 texture_width,
|
||||
u32 texture_height, u32 texture_view_x, u32 texture_view_y,
|
||||
u32 texture_view_width, u32 texture_view_height, bool linear_filter)
|
||||
s32 texture_height, s32 texture_view_x, s32 texture_view_y,
|
||||
s32 texture_view_width, s32 texture_view_height, bool linear_filter)
|
||||
{
|
||||
VkCommandBuffer cmdbuffer = g_vulkan_context->GetCurrentCommandBuffer();
|
||||
|
||||
@ -469,6 +547,15 @@ void VulkanHostDisplay::RenderImGui()
|
||||
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), g_vulkan_context->GetCurrentCommandBuffer());
|
||||
}
|
||||
|
||||
void VulkanHostDisplay::RenderSoftwareCursor()
|
||||
{
|
||||
if (!HasSoftwareCursor())
|
||||
return;
|
||||
|
||||
const auto [left, top, width, height] = CalculateSoftwareCursorDrawRect();
|
||||
RenderSoftwareCursor(left, top, width, height, m_cursor_texture.get());
|
||||
}
|
||||
|
||||
void VulkanHostDisplay::RenderSoftwareCursor(s32 left, s32 top, s32 width, s32 height, HostDisplayTexture* texture)
|
||||
{
|
||||
VkCommandBuffer cmdbuffer = g_vulkan_context->GetCurrentCommandBuffer();
|
||||
|
@ -14,57 +14,44 @@ class SwapChain;
|
||||
|
||||
namespace FrontendCommon {
|
||||
|
||||
class VulkanHostDisplay
|
||||
class VulkanHostDisplay : public HostDisplay
|
||||
{
|
||||
public:
|
||||
VulkanHostDisplay();
|
||||
~VulkanHostDisplay();
|
||||
virtual ~VulkanHostDisplay();
|
||||
|
||||
ALWAYS_INLINE HostDisplay::RenderAPI GetRenderAPI() const { return HostDisplay::RenderAPI::Vulkan; }
|
||||
ALWAYS_INLINE void* GetRenderDevice() const { return nullptr; }
|
||||
ALWAYS_INLINE void* GetRenderContext() const { return nullptr; }
|
||||
virtual RenderAPI GetRenderAPI() const override;
|
||||
virtual void* GetRenderDevice() const override;
|
||||
virtual void* GetRenderContext() const override;
|
||||
|
||||
std::unique_ptr<HostDisplayTexture> CreateTexture(u32 width, u32 height, const void* data, u32 data_stride,
|
||||
bool dynamic);
|
||||
void UpdateTexture(HostDisplayTexture* texture, u32 x, u32 y, u32 width, u32 height, const void* data,
|
||||
u32 data_stride);
|
||||
virtual bool HasRenderDevice() const override;
|
||||
virtual bool HasRenderSurface() const override;
|
||||
|
||||
virtual bool CreateRenderDevice(const WindowInfo& wi, std::string_view adapter_name, bool debug_device) override;
|
||||
virtual bool InitializeRenderDevice(std::string_view shader_cache_directory, bool debug_device) override;
|
||||
virtual void DestroyRenderDevice() override;
|
||||
|
||||
virtual bool MakeRenderContextCurrent() override;
|
||||
virtual bool DoneRenderContextCurrent() override;
|
||||
|
||||
virtual bool ChangeRenderWindow(const WindowInfo& new_wi) override;
|
||||
virtual void ResizeRenderWindow(s32 new_window_width, s32 new_window_height) override;
|
||||
virtual void DestroyRenderSurface() override;
|
||||
|
||||
std::unique_ptr<HostDisplayTexture> CreateTexture(u32 width, u32 height, const void* initial_data,
|
||||
u32 initial_data_stride, bool dynamic) override;
|
||||
void UpdateTexture(HostDisplayTexture* texture, u32 x, u32 y, u32 width, u32 height, const void* texture_data,
|
||||
u32 texture_data_stride) override;
|
||||
bool DownloadTexture(const void* texture_handle, u32 x, u32 y, u32 width, u32 height, void* out_data,
|
||||
u32 out_data_stride);
|
||||
u32 out_data_stride) override;
|
||||
|
||||
void SetVSync(bool enabled);
|
||||
virtual void SetVSync(bool enabled) override;
|
||||
|
||||
bool BeginRender();
|
||||
void RenderDisplay(s32 left, s32 top, s32 width, s32 height, void* texture_handle, u32 texture_width,
|
||||
u32 texture_height, u32 texture_view_x, u32 texture_view_y, u32 texture_view_width,
|
||||
u32 texture_view_height, bool linear_filter);
|
||||
void RenderImGui();
|
||||
void RenderSoftwareCursor(s32 left, s32 top, s32 width, s32 height, HostDisplayTexture* texture_handle);
|
||||
void EndRenderAndPresent();
|
||||
|
||||
bool CreateContextAndSwapChain(const WindowInfo& wi, std::string_view gpu_name, bool debug_device);
|
||||
bool HasContext() const;
|
||||
void DestroyContext();
|
||||
|
||||
void CreateShaderCache(std::string_view shader_cache_directory, bool debug_shaders);
|
||||
void DestroyShaderCache();
|
||||
|
||||
bool CreateResources();
|
||||
void DestroyResources();
|
||||
|
||||
bool CreateImGuiContext();
|
||||
void DestroyImGuiContext();
|
||||
|
||||
ALWAYS_INLINE u32 GetSwapChainWidth() const { return m_swap_chain->GetWidth(); }
|
||||
ALWAYS_INLINE u32 GetSwapChainHeight() const { return m_swap_chain->GetHeight(); }
|
||||
ALWAYS_INLINE bool HasSwapChain() const { return static_cast<bool>(m_swap_chain); }
|
||||
|
||||
bool RecreateSwapChain(const WindowInfo& new_wi);
|
||||
void ResizeSwapChain(u32 new_width, u32 new_height);
|
||||
void DestroySwapChain();
|
||||
virtual bool Render() override;
|
||||
|
||||
static std::vector<std::string> EnumerateAdapterNames();
|
||||
|
||||
private:
|
||||
protected:
|
||||
struct PushConstants
|
||||
{
|
||||
float src_rect_left;
|
||||
@ -73,6 +60,21 @@ private:
|
||||
float src_rect_height;
|
||||
};
|
||||
|
||||
virtual bool CreateResources();
|
||||
virtual void DestroyResources();
|
||||
|
||||
virtual bool CreateImGuiContext();
|
||||
virtual void DestroyImGuiContext();
|
||||
|
||||
void RenderDisplay();
|
||||
void RenderImGui();
|
||||
void RenderSoftwareCursor();
|
||||
|
||||
void RenderDisplay(s32 left, s32 top, s32 width, s32 height, void* texture_handle, u32 texture_width,
|
||||
s32 texture_height, s32 texture_view_x, s32 texture_view_y, s32 texture_view_width,
|
||||
s32 texture_view_height, bool linear_filter);
|
||||
void RenderSoftwareCursor(s32 left, s32 top, s32 width, s32 height, HostDisplayTexture* texture_handle);
|
||||
|
||||
std::unique_ptr<Vulkan::SwapChain> m_swap_chain;
|
||||
|
||||
VkDescriptorSetLayout m_descriptor_set_layout = VK_NULL_HANDLE;
|
||||
|
Reference in New Issue
Block a user