mirror of
https://github.com/spice2x/spice2x.github.io.git
synced 2026-08-06 16:40:41 -07:00
popn: fix subscreen redraw option causing graphical glitches (#854)
## Link to GitHub Issue or related Pull Request, if one exists #0 ## Description of change Old behavior: Forced redraw presented the subscreen every main frame, even when the game already presented it, causing duplicate presents and tearing in popn (was fine in sdvx) New behavior: Forced redraw acts as a fallback, presenting only when the game skips or fails a subscreen update. ## Testing Popn - no more glitching Nabla - no regression
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
#include "d3d9_backend.h"
|
||||
|
||||
#include <atomic>
|
||||
#include <cassert>
|
||||
#include <memory>
|
||||
#include <thread>
|
||||
@@ -113,6 +114,12 @@ static Direct3DCreate9On12Ex_t Direct3DCreate9On12Ex_orig = nullptr;
|
||||
static bool ATTEMPTED_SUB_SWAP_CHAIN_ACQUIRE = false;
|
||||
static IDirect3DSwapChain9 *SUB_SWAP_CHAIN = nullptr;
|
||||
|
||||
// main and subscreen presents may occur on different threads.
|
||||
static std::atomic_bool SUBSCREEN_PRESENTED_SINCE_LAST_MAIN = false;
|
||||
|
||||
// do not mistake the fallback Present below for a game-originated Present.
|
||||
static thread_local bool SUBSCREEN_FORCE_REDRAW_IN_PROGRESS = false;
|
||||
|
||||
static void graphics_d3d9_ldj_init_sub_screen(
|
||||
IDirect3DDevice9Ex *device,
|
||||
D3DPRESENT_PARAMETERS *present_params,
|
||||
@@ -1445,6 +1452,12 @@ IDirect3DSurface9 *graphics_d3d9_ldj_get_sub_screen() {
|
||||
return surface;
|
||||
}
|
||||
|
||||
void graphics_d3d9_notify_subscreen_present() {
|
||||
if (SUBSCREEN_FORCE_REDRAW && !SUBSCREEN_FORCE_REDRAW_IN_PROGRESS) {
|
||||
SUBSCREEN_PRESENTED_SINCE_LAST_MAIN.store(true, std::memory_order_relaxed);
|
||||
}
|
||||
}
|
||||
|
||||
static void graphics_d3d9_ldj_on_present(IDirect3DDevice9 *wrapped_device) {
|
||||
// iidx/sdvx
|
||||
int swapchain = 1;
|
||||
@@ -1472,8 +1485,16 @@ static void graphics_d3d9_ldj_on_present(IDirect3DDevice9 *wrapped_device) {
|
||||
//
|
||||
// early versions of popn HC needs this as well, but not on by default as it can cause
|
||||
// graphical glitches on some GPUs
|
||||
if (GRAPHICS_WINDOWED || SUBSCREEN_FORCE_REDRAW) {
|
||||
//
|
||||
// treat forced redraw as a fallback so it does not duplicate a successful game present.
|
||||
|
||||
const bool force_redraw = SUBSCREEN_FORCE_REDRAW &&
|
||||
!SUBSCREEN_PRESENTED_SINCE_LAST_MAIN.exchange(false, std::memory_order_relaxed);
|
||||
|
||||
if (GRAPHICS_WINDOWED || force_redraw) {
|
||||
SUBSCREEN_FORCE_REDRAW_IN_PROGRESS = true;
|
||||
SUB_SWAP_CHAIN->Present(nullptr, nullptr, nullptr, nullptr, 0);
|
||||
SUBSCREEN_FORCE_REDRAW_IN_PROGRESS = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,8 @@ void graphics_d3d9_on_present(
|
||||
IDirect3DDevice9 *device,
|
||||
IDirect3DDevice9 *wrapped_device);
|
||||
|
||||
void graphics_d3d9_notify_subscreen_present();
|
||||
|
||||
IDirect3DSurface9 *graphics_d3d9_ldj_get_sub_screen();
|
||||
|
||||
struct WrappedIDirect3D9 : IDirect3D9Ex {
|
||||
|
||||
@@ -134,6 +134,10 @@ ULONG STDMETHODCALLTYPE WrappedIDirect3DDevice9::Release() {
|
||||
this->main_swapchain->Release();
|
||||
this->main_swapchain = nullptr;
|
||||
}
|
||||
if (this->implicit_sub_swapchain) {
|
||||
this->implicit_sub_swapchain->Release();
|
||||
this->implicit_sub_swapchain = nullptr;
|
||||
}
|
||||
for (auto &sc : this->sub_swapchain) {
|
||||
if (sc) {
|
||||
sc->Release();
|
||||
@@ -487,6 +491,24 @@ HRESULT STDMETHODCALLTYPE WrappedIDirect3DDevice9::GetSwapChain(
|
||||
fake_sub_swapchain[0]->AddRef();
|
||||
*ppSwapChain = static_cast<IDirect3DSwapChain9 *>(fake_sub_swapchain[0]);
|
||||
|
||||
graphics_screens_register(iSwapChain);
|
||||
return D3D_OK;
|
||||
} else if (SUBSCREEN_FORCE_REDRAW) {
|
||||
// store implicit sub swap chain
|
||||
if (!implicit_sub_swapchain) {
|
||||
IDirect3DSwapChain9 *real_swapchain = nullptr;
|
||||
HRESULT ret = pReal->GetSwapChain(iSwapChain, &real_swapchain);
|
||||
if (FAILED(ret)) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
implicit_sub_swapchain = new WrappedIDirect3DSwapChain9(this, real_swapchain);
|
||||
implicit_sub_swapchain->should_run_hooks = false;
|
||||
}
|
||||
|
||||
implicit_sub_swapchain->AddRef();
|
||||
*ppSwapChain = static_cast<IDirect3DSwapChain9 *>(implicit_sub_swapchain);
|
||||
|
||||
graphics_screens_register(iSwapChain);
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
@@ -262,6 +262,7 @@ struct WrappedIDirect3DDevice9 : IDirect3DDevice9Ex {
|
||||
std::atomic_ulong refs = 1;
|
||||
|
||||
WrappedIDirect3DSwapChain9 *main_swapchain = nullptr;
|
||||
WrappedIDirect3DSwapChain9 *implicit_sub_swapchain = nullptr;
|
||||
WrappedIDirect3DSwapChain9 *sub_swapchain[3] = { nullptr, nullptr, nullptr };
|
||||
FakeIDirect3DSwapChain9 *fake_sub_swapchain[3] = { nullptr, nullptr, nullptr };
|
||||
|
||||
|
||||
@@ -96,6 +96,12 @@ HRESULT STDMETHODCALLTYPE WrappedIDirect3DSwapChain9::Present(const RECT *pSourc
|
||||
pDirtyRegion,
|
||||
dwFlags);
|
||||
|
||||
// a successful game subscreen present suppresses the next forced fallback present.
|
||||
if (SUCCEEDED(result) &&
|
||||
(this == pDev->implicit_sub_swapchain || this == pDev->sub_swapchain[0])) {
|
||||
graphics_d3d9_notify_subscreen_present();
|
||||
}
|
||||
|
||||
// Some drivers report S_PRESENT_MODE_CHANGED after Windows moves the portrait SMALL
|
||||
// head into the requested exclusive mode, leaving both group heads black. Toggle SMALL
|
||||
// through another supported mode and restore it once, then retry the interrupted MAIN
|
||||
|
||||
@@ -981,7 +981,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
||||
.display_name = "sdvxsubredraw",
|
||||
.aliases= "sdvxsubredraw",
|
||||
.desc = "Check if submonitor in fullscreen mode doesn't update every frame; "
|
||||
"this option forces subscreen to redraw every frame.",
|
||||
"this option presents the subscreen when the game does not.",
|
||||
.type = OptionType::Bool,
|
||||
.game_name = "Sound Voltex",
|
||||
.category = "Advanced Game Options",
|
||||
@@ -1175,7 +1175,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
||||
.title = "Pop'n Music PikaPika Subscreen Force Redraw",
|
||||
.name = "popnsubredraw",
|
||||
.desc = "Check if submonitor in fullscreen mode appears stuck; "
|
||||
"this option forces subscreen to redraw every frame.",
|
||||
"this option presents the subscreen when the game does not.",
|
||||
.type = OptionType::Bool,
|
||||
.game_name = "Pop'n Music",
|
||||
.category = "Advanced Game Options",
|
||||
|
||||
Reference in New Issue
Block a user