diff --git a/common/D3D12/Context.cpp b/common/D3D12/Context.cpp index aa3bbf9cab3608..79f5f1c62258d1 100644 --- a/common/D3D12/Context.cpp +++ b/common/D3D12/Context.cpp @@ -28,6 +28,12 @@ #include #include +#ifdef __LIBRETRO__ +#include +extern retro_environment_t environ_cb; +retro_hw_render_interface_d3d12 *d3d12; +#endif + std::unique_ptr g_d3d12_context; using namespace D3D12; @@ -136,6 +142,18 @@ bool Context::Create(IDXGIFactory5* dxgi_factory, IDXGIAdapter1* adapter, bool e } g_d3d12_context.reset(new Context()); +#ifdef __LIBRETRO__ + d3d12 = nullptr; + if (!environ_cb(RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE, (void **)&d3d12) || !d3d12) { + printf("Failed to get HW rendering interface!\n"); + return false; + } + + if (d3d12->interface_version != RETRO_HW_RENDER_INTERFACE_D3D12_VERSION) { + printf("HW render interface mismatch, expected %u, got %u!\n", RETRO_HW_RENDER_INTERFACE_D3D12_VERSION, d3d12->interface_version); + return false; + } +#endif if (!g_d3d12_context->CreateDevice(dxgi_factory, adapter, enable_debug_layer) || !g_d3d12_context->CreateCommandQueue() || !g_d3d12_context->CreateAllocator() || !g_d3d12_context->CreateFence() || !g_d3d12_context->CreateDescriptorHeaps() || @@ -171,6 +189,9 @@ u32 Context::GetAdapterVendorID() const bool Context::CreateDevice(IDXGIFactory5* dxgi_factory, IDXGIAdapter1* adapter, bool enable_debug_layer) { +#ifdef __LIBRETRO__ + m_device = d3d12->device; +#else HRESULT hr; // Enabling the debug layer will fail if the Graphics Tools feature is not installed. @@ -195,12 +216,12 @@ bool Context::CreateDevice(IDXGIFactory5* dxgi_factory, IDXGIAdapter1* adapter, Console.Error("Failed to create D3D12 device: %08X", hr); return false; } - +#endif // get adapter const LUID luid(m_device->GetAdapterLuid()); if (FAILED(dxgi_factory->EnumAdapterByLuid(luid, IID_PPV_ARGS(m_adapter.put())))) Console.Error("Failed to get lookup adapter by device LUID"); - +#ifndef __LIBRETRO__ if (enable_debug_layer) { ComPtr info_queue = m_device.try_query(); @@ -225,17 +246,22 @@ bool Context::CreateDevice(IDXGIFactory5* dxgi_factory, IDXGIAdapter1* adapter, info_queue->PushStorageFilter(&filter); } } - +#endif return true; } bool Context::CreateCommandQueue() { +#ifdef __LIBRETRO__ + m_command_queue = d3d12->queue; + return true; +#else const D3D12_COMMAND_QUEUE_DESC queue_desc = {D3D12_COMMAND_LIST_TYPE_DIRECT, D3D12_COMMAND_QUEUE_PRIORITY_NORMAL, D3D12_COMMAND_QUEUE_FLAG_NONE}; HRESULT hr = m_device->CreateCommandQueue(&queue_desc, IID_PPV_ARGS(&m_command_queue)); pxAssertRel(SUCCEEDED(hr), "Create command queue"); return SUCCEEDED(hr); +#endif } bool Context::CreateAllocator() diff --git a/libretro/CMakeLists.txt b/libretro/CMakeLists.txt index b80c4b83d4d108..0181a2186bbb44 100644 --- a/libretro/CMakeLists.txt +++ b/libretro/CMakeLists.txt @@ -42,6 +42,10 @@ target_include_directories(PCSX2_FLAGS INTERFACE "${CMAKE_SOURCE_DIR}/libretro" ) +target_include_directories(common PUBLIC + "${CMAKE_SOURCE_DIR}/libretro" +) + target_include_directories(pcsx2_libretro PRIVATE "${CMAKE_SOURCE_DIR}" "${CMAKE_SOURCE_DIR}/libretro" @@ -72,4 +76,4 @@ else(PACKAGE_MODE) install(TARGETS pcsx2_libretro DESTINATION ${CMAKE_SOURCE_DIR}/bin) endif(PACKAGE_MODE) -#setup_main_executable(pcsx2-libretro) \ No newline at end of file +#setup_main_executable(pcsx2-libretro) diff --git a/libretro/libretro_d3d.h b/libretro/libretro_d3d.h index 05c7c99df2325e..c813fbac832c3a 100644 --- a/libretro/libretro_d3d.h +++ b/libretro/libretro_d3d.h @@ -1,7 +1,7 @@ -/* Copyright (C) 2010-2016 The RetroArch team +/* Copyright (C) 2010-2023 The RetroArch team * * --------------------------------------------------------------------------------------------- - * The following license statement only applies to this libretro API header (libretro_vulkan.h) + * The following license statement only applies to this libretro API header (libretro_d3d.h) * --------------------------------------------------------------------------------------------- * * Permission is hereby granted, free of charge, @@ -30,7 +30,7 @@ #include "libretro.h" #include -#include +#include #define RETRO_HW_RENDER_INTERFACE_D3D11_VERSION 1 @@ -52,5 +52,29 @@ struct retro_hw_render_interface_d3d11 pD3DCompile D3DCompile; }; +#include +#include + +#define RETRO_HW_RENDER_INTERFACE_D3D12_VERSION 1 + +struct retro_hw_render_interface_d3d12 +{ + /* Must be set to RETRO_HW_RENDER_INTERFACE_D3D12. */ + enum retro_hw_render_interface_type interface_type; + /* Must be set to RETRO_HW_RENDER_INTERFACE_D3D12_VERSION. */ + unsigned interface_version; + + /* Opaque handle to the d3d12 backend in the frontend + * which must be passed along to all function pointers + * in this interface. + */ + void* handle; + ID3D12Device *device; + ID3D12CommandQueue *queue; + pD3DCompile D3DCompile; + D3D12_RESOURCE_STATES required_state; + void (*set_texture)(void* handle, ID3D12Resource* texture, DXGI_FORMAT format); +}; + #endif /* LIBRETRO_DIRECT3D_H__ */ diff --git a/libretro/main.cpp b/libretro/main.cpp index 997d26e378362f..4bd87ae9383341 100644 --- a/libretro/main.cpp +++ b/libretro/main.cpp @@ -79,10 +79,10 @@ static Option fast_boot("pcsx2_fastboot", "Fast Boot", true); GfxOption renderer("pcsx2_renderer", "Renderer", {"Auto", "OpenGL", #ifdef _WIN32 - "D3D11", + "D3D11", "D3D12", #endif #ifdef ENABLE_VULKAN - "Vulkan", + "Vulkan", #endif "Software", "Null"}); @@ -451,13 +451,14 @@ static bool set_hw_render(retro_hw_context_type type) hw_render.context_destroy = context_destroy; hw_render.bottom_left_origin = true; hw_render.depth = true; - hw_render.cache_context = true; + hw_render.cache_context = false; switch (type) { #ifdef _WIN32 case RETRO_HW_CONTEXT_DIRECT3D: - hw_render.version_major = 11; + if(!hw_render.version_major) + hw_render.version_major = 11; hw_render.version_minor = 0; break; #endif @@ -465,13 +466,11 @@ static bool set_hw_render(retro_hw_context_type type) case RETRO_HW_CONTEXT_VULKAN: hw_render.version_major = VK_API_VERSION_1_1; hw_render.version_minor = 0; - hw_render.cache_context = false; break; #endif case RETRO_HW_CONTEXT_OPENGL_CORE: hw_render.version_major = 3; hw_render.version_minor = 3; - hw_render.cache_context = false; break; case RETRO_HW_CONTEXT_OPENGL: @@ -505,7 +504,15 @@ bool select_hw_render() } #ifdef _WIN32 if (Options::renderer == "D3D11") + { + hw_render.version_major = 11; + return set_hw_render(RETRO_HW_CONTEXT_DIRECT3D); + } + if (Options::renderer == "D3D12") + { + hw_render.version_major = 12; return set_hw_render(RETRO_HW_CONTEXT_DIRECT3D); + } #endif #ifdef ENABLE_VULKAN if (Options::renderer == "Vulkan") @@ -661,7 +668,10 @@ bool retro_load_game(const struct retro_game_info* game) switch (hw_render.context_type) { case RETRO_HW_CONTEXT_DIRECT3D: - s_settings_interface.SetIntValue("EmuCore/GS", "Renderer", (int)GSRendererType::DX11); + if(hw_render.version_major == 12) + s_settings_interface.SetIntValue("EmuCore/GS", "Renderer", (int)GSRendererType::DX12); + else + s_settings_interface.SetIntValue("EmuCore/GS", "Renderer", (int)GSRendererType::DX11); break; #ifdef ENABLE_VULKAN case RETRO_HW_CONTEXT_VULKAN: diff --git a/pcsx2/GS/Renderers/DX12/GSDevice12.cpp b/pcsx2/GS/Renderers/DX12/GSDevice12.cpp index a43a11f80ff390..674f77d0146089 100644 --- a/pcsx2/GS/Renderers/DX12/GSDevice12.cpp +++ b/pcsx2/GS/Renderers/DX12/GSDevice12.cpp @@ -38,6 +38,12 @@ #include #include +#ifdef __LIBRETRO__ +#include "libretro_d3d.h" +extern retro_hw_render_interface_d3d12 *d3d12; +extern retro_video_refresh_t video_cb; +#endif + static bool IsDATMConvertShader(ShaderConvert i) { return (i == ShaderConvert::DATM_0 || i == ShaderConvert::DATM_1); } static bool IsDATEModePrimIDInit(u32 flag) { return flag == 1 || flag == 2; } @@ -113,7 +119,11 @@ RenderAPI GSDevice12::GetRenderAPI() const bool GSDevice12::HasSurface() const { +#ifdef __LIBRETRO__ + return true; +#else return static_cast(m_swap_chain); +#endif } bool GSDevice12::Create(const WindowInfo& wi, VsyncMode vsync) @@ -224,6 +234,7 @@ void GSDevice12::Destroy() bool GSDevice12::GetHostRefreshRate(float* refresh_rate) { +#ifndef __LIBRETRO__ if (m_swap_chain && IsExclusiveFullscreen()) { DXGI_SWAP_CHAIN_DESC desc; @@ -237,7 +248,7 @@ bool GSDevice12::GetHostRefreshRate(float* refresh_rate) return true; } } - +#endif return GSDevice::GetHostRefreshRate(refresh_rate); } @@ -249,6 +260,7 @@ void GSDevice12::SetVSync(VsyncMode mode) bool GSDevice12::CreateSwapChain(const DXGI_MODE_DESC* fullscreen_mode) { +#ifndef __LIBRETRO__ if (m_window_info.type != WindowInfo::Type::Win32) return false; @@ -297,12 +309,13 @@ bool GSDevice12::CreateSwapChain(const DXGI_MODE_DESC* fullscreen_mode) hr = m_dxgi_factory->MakeWindowAssociation(window_hwnd, DXGI_MWA_NO_WINDOW_CHANGES); if (FAILED(hr)) Console.Warning("MakeWindowAssociation() to disable ALT+ENTER failed"); - +#endif return CreateSwapChainRTV(); } bool GSDevice12::CreateSwapChainRTV() { +#ifndef __LIBRETRO__ DXGI_SWAP_CHAIN_DESC swap_chain_desc; HRESULT hr = m_swap_chain->GetDesc(&swap_chain_desc); if (FAILED(hr)) @@ -349,15 +362,18 @@ bool GSDevice12::CreateSwapChainRTV() } m_current_swap_chain_buffer = 0; +#endif return true; } void GSDevice12::DestroySwapChainRTVs() { +#ifndef __LIBRETRO__ for (D3D12::Texture& buffer : m_swap_chain_buffers) buffer.Destroy(false); m_swap_chain_buffers.clear(); m_current_swap_chain_buffer = 0; +#endif } bool GSDevice12::ChangeWindow(const WindowInfo& new_wi) @@ -373,6 +389,7 @@ bool GSDevice12::ChangeWindow(const WindowInfo& new_wi) void GSDevice12::DestroySurface() { +#ifndef __LIBRETRO__ ExecuteCommandList(true); if (IsExclusiveFullscreen()) @@ -380,6 +397,7 @@ void GSDevice12::DestroySurface() DestroySwapChainRTVs(); m_swap_chain.reset(); +#endif } std::string GSDevice12::GetDriverInfo() const @@ -426,6 +444,7 @@ std::string GSDevice12::GetDriverInfo() const void GSDevice12::ResizeWindow(s32 new_window_width, s32 new_window_height, float new_window_scale) { +#ifndef __LIBRETRO__ if (!m_swap_chain) return; @@ -445,6 +464,7 @@ void GSDevice12::ResizeWindow(s32 new_window_width, s32 new_window_height, float if (!CreateSwapChainRTV()) pxFailRel("Failed to recreate swap chain RTV after resize"); +#endif } bool GSDevice12::SupportsExclusiveFullscreen() const @@ -454,12 +474,17 @@ bool GSDevice12::SupportsExclusiveFullscreen() const bool GSDevice12::IsExclusiveFullscreen() { +#ifdef __LIBRETRO__ + return false; +#else BOOL is_fullscreen = FALSE; return (m_swap_chain && SUCCEEDED(m_swap_chain->GetFullscreenState(&is_fullscreen, nullptr)) && is_fullscreen); +#endif } bool GSDevice12::SetExclusiveFullscreen(bool fullscreen, u32 width, u32 height, float refresh_rate) { +#ifndef __LIBRETRO__ if (!m_swap_chain) return false; @@ -517,7 +542,7 @@ bool GSDevice12::SetExclusiveFullscreen(bool fullscreen, u32 width, u32 height, return false; } - +#endif return true; } @@ -527,7 +552,7 @@ GSDevice::PresentResult GSDevice12::BeginPresent(bool frame_skip) if (m_device_lost) return PresentResult::DeviceLost; - +#ifndef __LIBRETRO__ if (frame_skip || !m_swap_chain) return PresentResult::FrameSkipped; @@ -545,11 +570,13 @@ GSDevice::PresentResult GSDevice12::BeginPresent(bool frame_skip) 0, 0, static_cast(m_window_info.surface_width), static_cast(m_window_info.surface_height)}; cmdlist->RSSetViewports(1, &vp); cmdlist->RSSetScissorRects(1, &scissor); +#endif return PresentResult::OK; } void GSDevice12::EndPresent() { +#ifndef __LIBRETRO__ RenderImGui(); D3D12::Texture& swap_chain_buf = m_swap_chain_buffers[m_current_swap_chain_buffer]; @@ -568,7 +595,7 @@ void GSDevice12::EndPresent() m_swap_chain->Present(0, DXGI_PRESENT_ALLOW_TEARING); else m_swap_chain->Present(static_cast(vsync), 0); - +#endif InvalidateCachedState(); } @@ -861,6 +888,15 @@ void GSDevice12::StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* void GSDevice12::PresentRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, PresentShader shader, float shaderTime, bool linear) { +#ifdef __LIBRETRO__ + GSTexture12* texture = (GSTexture12*)sTex; + texture->TransitionToState(d3d12->required_state); +// texture->SetUsedThisCommandBuffer(); + g_d3d12_context->ExecuteCommandList(D3D12::Context::WaitType::None); + + d3d12->set_texture(d3d12->handle, texture->GetTexture().GetResource(), texture->GetTexture().GetResource()->GetDesc().Format); + video_cb(RETRO_HW_FRAME_BUFFER_VALID, texture->GetWidth(), texture->GetHeight(), 0); +#else DisplayConstantBuffer cb; cb.SetSource(sRect, sTex->GetSize()); cb.SetTarget(dRect, dTex ? dTex->GetSize() : GSVector2i(GetWindowWidth(), GetWindowHeight())); @@ -870,6 +906,7 @@ void GSDevice12::PresentRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* DoStretchRect(static_cast(sTex), sRect, static_cast(dTex), dRect, m_present[static_cast(shader)].get(), linear, true); +#endif } void GSDevice12::UpdateCLUTTexture(GSTexture* sTex, float sScale, u32 offsetX, u32 offsetY, GSTexture* dTex, u32 dOffset, u32 dSize) diff --git a/pcsx2/GS/Renderers/DX12/GSDevice12.h b/pcsx2/GS/Renderers/DX12/GSDevice12.h index ed4f74eaf10b7a..b7743d1c742bb5 100644 --- a/pcsx2/GS/Renderers/DX12/GSDevice12.h +++ b/pcsx2/GS/Renderers/DX12/GSDevice12.h @@ -139,9 +139,11 @@ class GSDevice12 final : public GSDevice private: ComPtr m_dxgi_factory; +#ifndef __LIBRETRO__ ComPtr m_swap_chain; std::vector m_swap_chain_buffers; u32 m_current_swap_chain_buffer = 0; +#endif bool m_allow_tearing_supported = false; bool m_using_allow_tearing = false;