Skip to content

Commit

Permalink
Vsync support (#172)
Browse files Browse the repository at this point in the history
* [WIP] Implemented base VRR Support

* Fixed tidy

* Removed timer

* Enabled disable vsync but maintains the timer

* Added vrr support again

* Disabled vrr when force_disable_vsync is enabled

* Implemented vsync toggle on window

* Added HasVRRSupport method

* Update src/core/Window.h

* Update src/core/Window.h

* Update src/core/Window.cpp

* Update src/core/Window.cpp

* Update src/core/Window.cpp

* Update src/core/Window.h

* Update src/core/Window.cpp

* Update src/core/Window.cpp

* Update src/core/Window.cpp

* Update src/core/Window.h

* Update src/graphic/Fast3D/gfx_dxgi.cpp

* Update src/graphic/Fast3D/gfx_dxgi.cpp

* Update src/graphic/Fast3D/gfx_sdl2.cpp

* Update src/graphic/Fast3D/gfx_sdl2.cpp

* Update src/graphic/Fast3D/gfx_window_manager_api.h

* Update src/graphic/Fast3D/gfx_dxgi.cpp

Co-authored-by: briaguya <70942617+briaguya-ai@users.noreply.github.com>

* Update src/graphic/Fast3D/gfx_dxgi.cpp

Co-authored-by: briaguya <70942617+briaguya-ai@users.noreply.github.com>

* Update src/graphic/Fast3D/gfx_dxgi.cpp

Co-authored-by: briaguya <70942617+briaguya-ai@users.noreply.github.com>

* Update src/graphic/Fast3D/gfx_dxgi.cpp

Co-authored-by: briaguya <70942617+briaguya-ai@users.noreply.github.com>

* Update src/graphic/Fast3D/gfx_dxgi.cpp

Co-authored-by: briaguya <70942617+briaguya-ai@users.noreply.github.com>

* Update src/graphic/Fast3D/gfx_dxgi.cpp

Co-authored-by: briaguya <70942617+briaguya-ai@users.noreply.github.com>

* Update src/graphic/Fast3D/gfx_dxgi.cpp

Co-authored-by: briaguya <70942617+briaguya-ai@users.noreply.github.com>

* Update src/graphic/Fast3D/gfx_dxgi.cpp

Co-authored-by: briaguya <70942617+briaguya-ai@users.noreply.github.com>

* Update src/graphic/Fast3D/gfx_dxgi.cpp

Co-authored-by: briaguya <70942617+briaguya-ai@users.noreply.github.com>

* cvar for vsync

* cvar for vsync

* Runs clang-format

* remove from header

* Enables vsync to work on dxgi

* Runs clang-format

---------

Co-authored-by: KiritoDv <kiritodev01@gmail.com>
Co-authored-by: briaguya <70942617+briaguya-ai@users.noreply.github.com>
Co-authored-by: briaguya <briaguya@alice>
  • Loading branch information
4 people committed Apr 20, 2023
1 parent 7095465 commit 10bd53b
Show file tree
Hide file tree
Showing 6 changed files with 53 additions and 19 deletions.
6 changes: 6 additions & 0 deletions src/core/Window.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ void Window::Initialize(const std::vector<std::string>& otrFiles, const std::uno
InitializeConsoleVariables();
InitializeLogging();
InitializeConfiguration();
CVarLoad();
InitializeResourceManager(otrFiles, validHashes);
CreateDefaults();
InitializeControlDeck();
Expand Down Expand Up @@ -130,6 +131,7 @@ void Window::Initialize(const std::vector<std::string>& otrFiles, const std::uno
}

InitializeWindowManager(GetConfig()->getString("Window.GfxBackend"), GetConfig()->getString("Window.GfxApi"));

InitializeAudioPlayer(GetConfig()->getString("Window.AudioBackend"));

InitializeSpeechSynthesis();
Expand Down Expand Up @@ -297,6 +299,10 @@ uint32_t Window::GetCurrentRefreshRate() {
return mRefreshRate;
}

bool Window::CanDisableVerticalSync() {
return mWindowManagerApi->can_disable_vsync();
}

float Window::GetCurrentAspectRatio() {
return (float)GetCurrentWidth() / (float)GetCurrentHeight();
}
Expand Down
1 change: 1 addition & 0 deletions src/core/Window.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ class Window {
uint32_t GetCurrentWidth();
uint32_t GetCurrentHeight();
uint32_t GetCurrentRefreshRate();
bool CanDisableVerticalSync();
float GetCurrentAspectRatio();
bool IsFullscreen();
uint32_t GetMenuBar();
Expand Down
46 changes: 32 additions & 14 deletions src/graphic/Fast3D/gfx_dxgi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include <wrl/client.h>
#include <dxgi1_3.h>
#include <dxgi1_4.h>
#include <dxgi1_5.h>
#include <versionhelpers.h>

#include <shellscalingapi.h>
Expand Down Expand Up @@ -76,6 +77,8 @@ static struct {
uint32_t applied_maximum_frame_latency;
HANDLE timer;
bool use_timer;
bool tearing_support;
bool is_vsync_enabled;
LARGE_INTEGER previous_present_time;

void (*on_fullscreen_changed)(bool is_now_fullscreen);
Expand Down Expand Up @@ -497,7 +500,8 @@ static bool gfx_dxgi_start_frame(void) {

double vsyncs_to_wait = (double)(int64_t)(dxgi.frame_timestamp / FRAME_INTERVAL_NS_DENOMINATOR - last_end_ns) /
estimated_vsync_interval_ns;
// printf("ts: %llu, last_end_ns: %llu, Init v: %f\n", dxgi.frame_timestamp / 3, last_end_ns, vsyncs_to_wait);
// printf("ts: %llu, last_end_ns: %llu, Init v: %f\n", dxgi.frame_timestamp / 3, last_end_ns,
// vsyncs_to_wait);

if (vsyncs_to_wait <= 0) {
// Too late
Expand Down Expand Up @@ -563,9 +567,8 @@ static bool gfx_dxgi_start_frame(void) {
}

static void gfx_dxgi_swap_buffers_begin(void) {
// dxgi.length_in_vsync_frames = 1;
LARGE_INTEGER t;
if (dxgi.use_timer) {
if (dxgi.use_timer || (dxgi.tearing_support && !dxgi.is_vsync_enabled)) {
QueryPerformanceCounter(&t);
int64_t next = qpc_to_100ns(dxgi.previous_present_time.QuadPart) +
FRAME_INTERVAL_NS_NUMERATOR / (FRAME_INTERVAL_NS_DENOMINATOR * 100);
Expand All @@ -579,8 +582,8 @@ static void gfx_dxgi_swap_buffers_begin(void) {
}
QueryPerformanceCounter(&t);
dxgi.previous_present_time = t;

ThrowIfFailed(dxgi.swap_chain->Present(dxgi.length_in_vsync_frames, 0));

UINT this_present_id;
if (dxgi.swap_chain->GetLastPresentCount(&this_present_id) == S_OK) {
dxgi.pending_frame_stats.insert(std::make_pair(this_present_id, dxgi.length_in_vsync_frames));
Expand All @@ -593,9 +596,10 @@ static void gfx_dxgi_swap_buffers_end(void) {
QueryPerformanceCounter(&t0);
QueryPerformanceCounter(&t1);

if (dxgi.applied_maximum_frame_latency > dxgi.maximum_frame_latency) {
// There seems to be a bug that if latency is decreased, there is no effect of that operation, so recreate swap
// chain
if (dxgi.applied_maximum_frame_latency > dxgi.maximum_frame_latency ||
dxgi.is_vsync_enabled != CVarGetInteger("gVsyncEnabled", 1)) {
// There seems to be a bug that if latency is decreased, there is no effect of that operation, so recreate
// swap chain
if (dxgi.waitable_object != nullptr) {
if (!dxgi.dropped_frame) {
// Wait the last time on this swap chain
Expand All @@ -606,9 +610,8 @@ static void gfx_dxgi_swap_buffers_end(void) {
}

dxgi.before_destroy_swap_chain_fn();

dxgi.swap_chain.Reset();

dxgi.is_vsync_enabled = CVarGetInteger("gVsyncEnabled", 1);
gfx_dxgi_create_swap_chain(dxgi.swap_chain_device.Get(), move(dxgi.before_destroy_swap_chain_fn));

dxgi.frame_timestamp = 0;
Expand Down Expand Up @@ -667,11 +670,18 @@ void gfx_dxgi_create_factory_and_device(bool debug, int d3d_version,
ThrowIfFailed(dxgi.CreateDXGIFactory1(__uuidof(IDXGIFactory2), &dxgi.factory));
}

{
ComPtr<IDXGIFactory4> factory4;
if (dxgi.factory->QueryInterface(__uuidof(IDXGIFactory4), &factory4) == S_OK) {
dxgi.dxgi1_4 = true;
ComPtr<IDXGIFactory4> factory4;
if (dxgi.factory->QueryInterface(__uuidof(IDXGIFactory4), &factory4) == S_OK) {
dxgi.dxgi1_4 = true;

ComPtr<IDXGIFactory5> factory;
HRESULT hr = dxgi.factory.As(&factory);
BOOL allowTearing = FALSE;
if (SUCCEEDED(hr)) {
hr = factory->CheckFeatureSupport(DXGI_FEATURE_PRESENT_ALLOW_TEARING, &allowTearing, sizeof(allowTearing));
}

dxgi.tearing_support = SUCCEEDED(hr) && allowTearing;
}

ComPtr<IDXGIAdapter1> adapter;
Expand Down Expand Up @@ -709,6 +719,9 @@ void gfx_dxgi_create_swap_chain(IUnknown* device, std::function<void()>&& before
dxgi.dxgi1_4 ? DXGI_SWAP_EFFECT_FLIP_DISCARD : // Introduced in DXGI 1.4 and Windows 10
DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; // Apparently flip sequential was also backported to Win 7 Platform Update
swap_chain_desc.Flags = dxgi_13 ? DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT : 0;
if (dxgi.tearing_support && !dxgi.is_vsync_enabled) {
swap_chain_desc.Flags |= DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING;
}
swap_chain_desc.SampleDesc.Count = 1;

run_as_dpi_aware([&]() {
Expand Down Expand Up @@ -761,6 +774,10 @@ const char* gfx_dxgi_get_key_name(int scancode) {
return text;
}

bool gfx_dxgi_can_disable_vsync() {
return dxgi.tearing_support;
}

extern "C" struct GfxWindowManagerAPI gfx_dxgi_api = { gfx_dxgi_init,
gfx_dxgi_close,
gfx_dxgi_set_keyboard_callbacks,
Expand All @@ -777,6 +794,7 @@ extern "C" struct GfxWindowManagerAPI gfx_dxgi_api = { gfx_dxgi_init,
gfx_dxgi_get_time,
gfx_dxgi_set_target_fps,
gfx_dxgi_set_maximum_frame_latency,
gfx_dxgi_get_key_name };
gfx_dxgi_get_key_name,
gfx_dxgi_can_disable_vsync };

#endif
17 changes: 13 additions & 4 deletions src/graphic/Fast3D/gfx_sdl2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ static SDL_Window* wnd;
static SDL_GLContext ctx;
static SDL_Renderer* renderer;
static int sdl_to_lus_table[512];
static int vsync_enabled = 0;
static bool vsync_enabled = false;
static int window_width = DESIRED_SCREEN_WIDTH;
static int window_height = DESIRED_SCREEN_HEIGHT;
static bool fullscreen_state;
Expand Down Expand Up @@ -329,12 +329,16 @@ static void gfx_sdl_init(const char* game_name, const char* gfx_api_name, bool s
#endif

SDL_GL_MakeCurrent(wnd, ctx);
SDL_GL_SetSwapInterval(1);
SDL_GL_SetSwapInterval(vsync_enabled ? 1 : 0);

window_impl.Opengl = { wnd, ctx };
window_impl.backend = SohImGui::Backend::SDL_OPENGL;
} else {
renderer = SDL_CreateRenderer(wnd, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
uint32_t flags = SDL_RENDERER_ACCELERATED;
if (vsync_enabled) {
flags |= SDL_RENDERER_PRESENTVSYNC;
}
renderer = SDL_CreateRenderer(wnd, -1, flags);
if (renderer == NULL) {
SPDLOG_ERROR("Error creating renderer: {}", SDL_GetError());
return;
Expand Down Expand Up @@ -545,6 +549,10 @@ static const char* gfx_sdl_get_key_name(int scancode) {
return SDL_GetScancodeName((SDL_Scancode)untranslate_scancode(scancode));
}

bool gfx_sdl_can_disable_vsync() {
return false;
}

struct GfxWindowManagerAPI gfx_sdl = { gfx_sdl_init,
gfx_sdl_close,
gfx_sdl_set_keyboard_callbacks,
Expand All @@ -561,6 +569,7 @@ struct GfxWindowManagerAPI gfx_sdl = { gfx_sdl_init,
gfx_sdl_get_time,
gfx_sdl_set_target_fps,
gfx_sdl_set_maximum_frame_latency,
gfx_sdl_get_key_name };
gfx_sdl_get_key_name,
gfx_sdl_can_disable_vsync };

#endif
1 change: 1 addition & 0 deletions src/graphic/Fast3D/gfx_window_manager_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ struct GfxWindowManagerAPI {
void (*set_target_fps)(int fps);
void (*set_maximum_frame_latency)(int latency);
const char* (*get_key_name)(int scancode);
bool (*can_disable_vsync)();
};

#endif
1 change: 0 additions & 1 deletion src/menu/ImGuiImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -425,7 +425,6 @@ void LoadTexture(const std::string& name, const std::string& path) {
// MARK: - Public API

void Init(WindowImpl windowImpl) {
CVarLoad();
impl = windowImpl;
ImGuiContext* ctx = ImGui::CreateContext();
ImGui::SetCurrentContext(ctx);
Expand Down

0 comments on commit 10bd53b

Please sign in to comment.