mirror of
https://github.com/spice2x/spice2x.github.io.git
synced 2026-08-01 22:30:42 -07:00
overlay: implement dx11 backend (#707)
## Link to GitHub Issue or related Pull Request, if one exists Fixes #134 ## Description of change Add ImGui DX11 backend implementation, and integrate into the spice overlay. The tricky part is that some of the Unity games: 1. Launch multiple windows, and 2. Can be resized (even full screen games launch at a certain resolution and then expand to fit desktop resolution) 3. lazy load DX11 DLLs This PR also adds screenshot functionality, but screen resize is not implemented. ## Testing Seems to be working for most games. Need to do final tests for: - [x] CCJ (attract movie plays as well) - [x] Busou Shinki (title movie plays) - [x] MFG - [x] QuizKnock - [x] Polaris Chord - [x] check dx9 for regression
This commit is contained in:
@@ -41,6 +41,8 @@ static INT64 g_TicksPerSecond = 0;
|
||||
static ImGuiMouseCursor g_LastMouseCursor = ImGuiMouseCursor_COUNT;
|
||||
static double g_LastMouseMovement = 0.f;
|
||||
static bool g_MouseCursorAutoHide = false;
|
||||
static float g_DisplaySizeOverrideW = 0.0f;
|
||||
static float g_DisplaySizeOverrideH = 0.0f;
|
||||
|
||||
constexpr size_t VKEY_MAX = 255;
|
||||
static std::array<bool, VKEY_MAX> g_KeysDown;
|
||||
@@ -179,12 +181,25 @@ void ImGui_ImplSpice_Shutdown() {
|
||||
|
||||
void ImGui_ImplSpice_UpdateDisplaySize() {
|
||||
|
||||
// backends that render to a surface different from the window's client
|
||||
// area (e.g. dx11 swapchain backbuffer) can override the size here so
|
||||
// ImGui's viewport matches the actual render target.
|
||||
if (g_DisplaySizeOverrideW > 0.0f && g_DisplaySizeOverrideH > 0.0f) {
|
||||
ImGui::GetIO().DisplaySize = ImVec2(g_DisplaySizeOverrideW, g_DisplaySizeOverrideH);
|
||||
return;
|
||||
}
|
||||
|
||||
// get display size
|
||||
RECT rect;
|
||||
::GetClientRect(g_hWnd, &rect);
|
||||
ImGui::GetIO().DisplaySize = ImVec2((float)(rect.right - rect.left), (float)(rect.bottom - rect.top));
|
||||
}
|
||||
|
||||
void ImGui_ImplSpice_SetDisplaySizeOverride(float w, float h) {
|
||||
g_DisplaySizeOverrideW = w;
|
||||
g_DisplaySizeOverrideH = h;
|
||||
}
|
||||
|
||||
bool ImGui_ImplSpice_UpdateMouseCursor() {
|
||||
|
||||
// check if cursor should be changed
|
||||
|
||||
@@ -6,5 +6,6 @@
|
||||
IMGUI_IMPL_API bool ImGui_ImplSpice_Init(HWND hWnd);
|
||||
IMGUI_IMPL_API void ImGui_ImplSpice_Shutdown();
|
||||
IMGUI_IMPL_API void ImGui_ImplSpice_UpdateDisplaySize();
|
||||
IMGUI_IMPL_API void ImGui_ImplSpice_SetDisplaySizeOverride(float w, float h);
|
||||
IMGUI_IMPL_API bool ImGui_ImplSpice_UpdateMouseCursor();
|
||||
IMGUI_IMPL_API void ImGui_ImplSpice_NewFrame();
|
||||
|
||||
@@ -15,10 +15,19 @@
|
||||
#include "build/resource.h"
|
||||
|
||||
#include "external/imgui/backends/imgui_impl_dx9.h"
|
||||
#ifdef SPICE_D3D11
|
||||
#include "external/imgui/backends/imgui_impl_dx11.h"
|
||||
#include "hooks/graphics/backends/d3d11/d3d11_backend.h"
|
||||
#endif
|
||||
#include "overlay/imgui/impl_spice.h"
|
||||
#include "overlay/imgui/impl_sw.h"
|
||||
#include "overlay/notifications.h"
|
||||
|
||||
#ifdef SPICE_D3D11
|
||||
#include <d3d11.h>
|
||||
#include <dxgi.h>
|
||||
#endif
|
||||
|
||||
#include "window.h"
|
||||
#ifdef SPICE64
|
||||
#include "windows/camera_control.h"
|
||||
@@ -105,6 +114,21 @@ void overlay::create_d3d9(HWND hWnd, IDirect3D9 *d3d, IDirect3DDevice9 *device)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SPICE_D3D11
|
||||
void overlay::create_d3d11(HWND hWnd, ID3D11Device *device, ID3D11DeviceContext *context,
|
||||
IDXGISwapChain *swapchain) {
|
||||
if (!overlay::ENABLED) {
|
||||
return;
|
||||
}
|
||||
|
||||
const std::lock_guard<std::mutex> lock(OVERLAY_MUTEX);
|
||||
|
||||
if (!overlay::OVERLAY) {
|
||||
overlay::OVERLAY = std::make_unique<overlay::SpiceOverlay>(hWnd, device, context, swapchain);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void overlay::create_software(HWND hWnd) {
|
||||
if (!overlay::ENABLED) {
|
||||
return;
|
||||
@@ -165,6 +189,27 @@ overlay::SpiceOverlay::SpiceOverlay(HWND hWnd)
|
||||
this->init();
|
||||
}
|
||||
|
||||
#ifdef SPICE_D3D11
|
||||
overlay::SpiceOverlay::SpiceOverlay(HWND hWnd, ID3D11Device *d3d11_device,
|
||||
ID3D11DeviceContext *d3d11_context,
|
||||
IDXGISwapChain *d3d11_swapchain)
|
||||
: renderer(OverlayRenderer::D3D11),
|
||||
hWnd(hWnd),
|
||||
d3d11_device(d3d11_device),
|
||||
d3d11_context(d3d11_context),
|
||||
d3d11_swapchain(d3d11_swapchain) {
|
||||
log_info("overlay", "initializing (D3D11)");
|
||||
|
||||
// increment reference counts
|
||||
this->d3d11_device->AddRef();
|
||||
this->d3d11_context->AddRef();
|
||||
this->d3d11_swapchain->AddRef();
|
||||
|
||||
// init
|
||||
this->init();
|
||||
}
|
||||
#endif
|
||||
|
||||
void overlay::SpiceOverlay::init() {
|
||||
|
||||
// init imgui
|
||||
@@ -317,6 +362,11 @@ void overlay::SpiceOverlay::init() {
|
||||
case OverlayRenderer::D3D9:
|
||||
ImGui_ImplDX9_Init(this->device);
|
||||
break;
|
||||
#ifdef SPICE_D3D11
|
||||
case OverlayRenderer::D3D11:
|
||||
ImGui_ImplDX11_Init(this->d3d11_device, this->d3d11_context);
|
||||
break;
|
||||
#endif
|
||||
case OverlayRenderer::SOFTWARE:
|
||||
imgui_sw::bind_imgui_painting();
|
||||
break;
|
||||
@@ -327,6 +377,11 @@ void overlay::SpiceOverlay::init() {
|
||||
case OverlayRenderer::D3D9:
|
||||
ImGui_ImplDX9_NewFrame();
|
||||
break;
|
||||
#ifdef SPICE_D3D11
|
||||
case OverlayRenderer::D3D11:
|
||||
ImGui_ImplDX11_NewFrame();
|
||||
break;
|
||||
#endif
|
||||
case OverlayRenderer::SOFTWARE:
|
||||
break;
|
||||
}
|
||||
@@ -449,6 +504,21 @@ overlay::SpiceOverlay::~SpiceOverlay() {
|
||||
this->d3d->Release();
|
||||
|
||||
break;
|
||||
#ifdef SPICE_D3D11
|
||||
case OverlayRenderer::D3D11:
|
||||
if (this->d3d11_rtv) {
|
||||
this->d3d11_rtv->Release();
|
||||
this->d3d11_rtv = nullptr;
|
||||
}
|
||||
ImGui_ImplDX11_Shutdown();
|
||||
|
||||
// drop references
|
||||
this->d3d11_swapchain->Release();
|
||||
this->d3d11_context->Release();
|
||||
this->d3d11_device->Release();
|
||||
|
||||
break;
|
||||
#endif
|
||||
case OverlayRenderer::SOFTWARE:
|
||||
imgui_sw::unbind_imgui_painting();
|
||||
break;
|
||||
@@ -484,6 +554,15 @@ void overlay::SpiceOverlay::new_frame() {
|
||||
case OverlayRenderer::D3D9:
|
||||
ImGui_ImplDX9_NewFrame();
|
||||
break;
|
||||
#ifdef SPICE_D3D11
|
||||
case OverlayRenderer::D3D11:
|
||||
// refresh DisplaySize each frame; the dx11 swapchain hook pushes
|
||||
// the current backbuffer dimensions into impl_spice via the
|
||||
// size override so ImGui's viewport tracks ResizeBuffers calls.
|
||||
ImGui_ImplSpice_UpdateDisplaySize();
|
||||
ImGui_ImplDX11_NewFrame();
|
||||
break;
|
||||
#endif
|
||||
case OverlayRenderer::SOFTWARE:
|
||||
ImGui_ImplSpice_UpdateDisplaySize();
|
||||
break;
|
||||
@@ -526,6 +605,12 @@ void overlay::SpiceOverlay::render() {
|
||||
case OverlayRenderer::D3D9:
|
||||
ImGui_ImplDX9_RenderDrawData(ImGui::GetDrawData());
|
||||
break;
|
||||
#ifdef SPICE_D3D11
|
||||
case OverlayRenderer::D3D11:
|
||||
overlay::d3d11::render(this->d3d11_device, this->d3d11_context,
|
||||
this->d3d11_swapchain, &this->d3d11_rtv);
|
||||
break;
|
||||
#endif
|
||||
case OverlayRenderer::SOFTWARE: {
|
||||
|
||||
// get display metrics
|
||||
@@ -705,11 +790,44 @@ bool overlay::SpiceOverlay::hotkeys_triggered() {
|
||||
}
|
||||
|
||||
void overlay::SpiceOverlay::reset_invalidate() {
|
||||
ImGui_ImplDX9_InvalidateDeviceObjects();
|
||||
if (!overlay::OVERLAY) {
|
||||
return;
|
||||
}
|
||||
switch (overlay::OVERLAY->renderer) {
|
||||
case OverlayRenderer::D3D9:
|
||||
ImGui_ImplDX9_InvalidateDeviceObjects();
|
||||
break;
|
||||
#ifdef SPICE_D3D11
|
||||
case OverlayRenderer::D3D11:
|
||||
// for DX11 a ResizeBuffers only invalidates the backbuffer RTV; the imgui
|
||||
// device objects (shaders, buffers, textures) remain valid.
|
||||
if (overlay::OVERLAY->d3d11_rtv) {
|
||||
overlay::OVERLAY->d3d11_rtv->Release();
|
||||
overlay::OVERLAY->d3d11_rtv = nullptr;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case OverlayRenderer::SOFTWARE:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void overlay::SpiceOverlay::reset_recreate() {
|
||||
ImGui_ImplDX9_CreateDeviceObjects();
|
||||
if (!overlay::OVERLAY) {
|
||||
return;
|
||||
}
|
||||
switch (overlay::OVERLAY->renderer) {
|
||||
case OverlayRenderer::D3D9:
|
||||
ImGui_ImplDX9_CreateDeviceObjects();
|
||||
break;
|
||||
#ifdef SPICE_D3D11
|
||||
case OverlayRenderer::D3D11:
|
||||
// RTV is lazily recreated on the next render()
|
||||
break;
|
||||
#endif
|
||||
case OverlayRenderer::SOFTWARE:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void overlay::SpiceOverlay::input_char(unsigned int c) {
|
||||
|
||||
@@ -10,11 +10,22 @@
|
||||
|
||||
#include "external/imgui/imgui.h"
|
||||
|
||||
#ifdef SPICE_D3D11
|
||||
// forward decls for D3D11 (avoid pulling d3d11.h into every TU)
|
||||
struct ID3D11Device;
|
||||
struct ID3D11DeviceContext;
|
||||
struct ID3D11RenderTargetView;
|
||||
struct IDXGISwapChain;
|
||||
#endif
|
||||
|
||||
namespace overlay {
|
||||
class Window;
|
||||
|
||||
enum class OverlayRenderer {
|
||||
D3D9,
|
||||
#ifdef SPICE_D3D11
|
||||
D3D11,
|
||||
#endif
|
||||
SOFTWARE,
|
||||
};
|
||||
|
||||
@@ -62,6 +73,10 @@ namespace overlay {
|
||||
Window *window_log = nullptr;
|
||||
|
||||
explicit SpiceOverlay(HWND hWnd, IDirect3D9 *d3d, IDirect3DDevice9 *device);
|
||||
#ifdef SPICE_D3D11
|
||||
explicit SpiceOverlay(HWND hWnd, ID3D11Device *d3d11_device,
|
||||
ID3D11DeviceContext *d3d11_context, IDXGISwapChain *d3d11_swapchain);
|
||||
#endif
|
||||
explicit SpiceOverlay(HWND hWnd);
|
||||
~SpiceOverlay();
|
||||
|
||||
@@ -92,6 +107,14 @@ namespace overlay {
|
||||
inline bool uses_device(IDirect3DDevice9 *other) {
|
||||
return this->device == other;
|
||||
}
|
||||
#ifdef SPICE_D3D11
|
||||
inline bool uses_device(ID3D11Device *other) {
|
||||
return this->d3d11_device == other;
|
||||
}
|
||||
inline bool uses_swapchain(IDXGISwapChain *other) {
|
||||
return this->d3d11_swapchain == other;
|
||||
}
|
||||
#endif
|
||||
inline IDirect3DDevice9 *get_device() {
|
||||
return this->device;
|
||||
}
|
||||
@@ -124,6 +147,14 @@ namespace overlay {
|
||||
IDirect3D9 *d3d = nullptr;
|
||||
IDirect3DDevice9 *device = nullptr;
|
||||
|
||||
#ifdef SPICE_D3D11
|
||||
// D3D11
|
||||
ID3D11Device *d3d11_device = nullptr;
|
||||
ID3D11DeviceContext *d3d11_context = nullptr;
|
||||
IDXGISwapChain *d3d11_swapchain = nullptr;
|
||||
ID3D11RenderTargetView *d3d11_rtv = nullptr;
|
||||
#endif
|
||||
|
||||
// software
|
||||
std::vector<uint32_t> pixel_data;
|
||||
size_t pixel_data_width = 0;
|
||||
@@ -156,6 +187,10 @@ namespace overlay {
|
||||
|
||||
// synchronized helpers
|
||||
void create_d3d9(HWND hWnd, IDirect3D9 *d3d, IDirect3DDevice9 *device);
|
||||
#ifdef SPICE_D3D11
|
||||
void create_d3d11(HWND hWnd, ID3D11Device *device, ID3D11DeviceContext *context,
|
||||
IDXGISwapChain *swapchain);
|
||||
#endif
|
||||
void create_software(HWND hWnd);
|
||||
void destroy(HWND hWnd = nullptr);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user