mirror of
https://github.com/azahar-emu/azahar.git
synced 2026-07-11 01:34:03 +02:00
Add Skip Presenting Duplicate Frames Feature (#1867)
* added basic skip duplicate frames implementation * fix secondary display and attempt to fix lcd color fill
This commit is contained in:
@@ -42,6 +42,7 @@ foreach(KEY IN ITEMS
|
||||
"use_disk_shader_cache"
|
||||
"shaders_accurate_mul"
|
||||
"use_vsync"
|
||||
"use_skip_duplicate_frames"
|
||||
"use_display_refresh_rate_detection"
|
||||
"use_shader_jit"
|
||||
"resolution_factor"
|
||||
|
||||
@@ -39,6 +39,7 @@ object SettingKeys {
|
||||
external fun use_disk_shader_cache(): String
|
||||
external fun shaders_accurate_mul(): String
|
||||
external fun use_vsync(): String
|
||||
external fun use_skip_duplicate_frames(): String
|
||||
external fun use_shader_jit(): String
|
||||
external fun resolution_factor(): String
|
||||
external fun frame_limit(): String
|
||||
|
||||
+5
@@ -97,6 +97,11 @@ enum class BooleanSetting(
|
||||
HW_SHADER(SettingKeys.use_hw_shader(), Settings.SECTION_RENDERER, true),
|
||||
SHADER_JIT(SettingKeys.use_shader_jit(), Settings.SECTION_RENDERER, true),
|
||||
VSYNC(SettingKeys.use_vsync(), Settings.SECTION_RENDERER, false),
|
||||
USE_SKIP_DUPLICATE_FRAMES(
|
||||
SettingKeys.use_skip_duplicate_frames(),
|
||||
Settings.SECTION_RENDERER,
|
||||
false
|
||||
),
|
||||
USE_FRAME_LIMIT(SettingKeys.use_frame_limit(), Settings.SECTION_RENDERER, true),
|
||||
DEBUG_RENDERER(SettingKeys.renderer_debug(), Settings.SECTION_DEBUG, false),
|
||||
DISABLE_RIGHT_EYE_RENDER(
|
||||
|
||||
+9
@@ -1146,6 +1146,15 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView)
|
||||
IntSetting.TEXTURE_SAMPLING.defaultValue
|
||||
)
|
||||
)
|
||||
add(
|
||||
SwitchSetting(
|
||||
BooleanSetting.USE_SKIP_DUPLICATE_FRAMES,
|
||||
R.string.use_skip_duplicate_frames,
|
||||
R.string.use_skip_duplicate_frames_description,
|
||||
BooleanSetting.USE_SKIP_DUPLICATE_FRAMES.key,
|
||||
BooleanSetting.USE_SKIP_DUPLICATE_FRAMES.defaultValue
|
||||
)
|
||||
)
|
||||
|
||||
// Disabled until custom texture implementation gets rewrite, current one overloads RAM
|
||||
// and crashes Citra.
|
||||
|
||||
@@ -152,6 +152,7 @@ void Config::ReadValues() {
|
||||
ReadSetting("Renderer", Settings::values.resolution_factor);
|
||||
ReadSetting("Renderer", Settings::values.use_disk_shader_cache);
|
||||
ReadSetting("Renderer", Settings::values.use_vsync);
|
||||
ReadSetting("Renderer", Settings::values.use_skip_duplicate_frames);
|
||||
ReadSetting("Renderer", Settings::values.texture_filter);
|
||||
ReadSetting("Renderer", Settings::values.texture_sampling);
|
||||
ReadSetting("Renderer", Settings::values.turbo_limit);
|
||||
|
||||
@@ -130,6 +130,10 @@ static const char* android_config_default_file_content = (BOOST_HANA_STRING(R"(
|
||||
# 0 (default): Off, 1: On
|
||||
)") DECLARE_KEY(use_vsync) BOOST_HANA_STRING(R"(
|
||||
|
||||
# Skips display of duplicated frames in 30 fps games
|
||||
# 0: Off, 1 (default): On
|
||||
)") DECLARE_KEY(use_skip_duplicate_frames) BOOST_HANA_STRING(R"(
|
||||
|
||||
# Reduce stuttering by storing and loading generated shaders to disk
|
||||
# 0: Off, 1 (default. On)
|
||||
)") DECLARE_KEY(use_disk_shader_cache) BOOST_HANA_STRING(R"(
|
||||
|
||||
@@ -271,6 +271,8 @@
|
||||
<string name="advanced">Advanced</string>
|
||||
<string name="texture_sampling_name">Texture Sampling</string>
|
||||
<string name="texture_sampling_description">Overrides the sampling filter used by games. This can be useful in certain cases with poorly behaved games when upscaling. If unsure, set this to Game Controlled.</string>
|
||||
<string name="use_skip_duplicate_frames">Skip Presenting Duplicate Frames</string>
|
||||
<string name="use_skip_duplicate_frames_description">Skips the presentation of frames that are not unique. It also allows external frame generation tools to work correctly with 30fps games</string>
|
||||
<string name="shaders_accurate_mul">Accurate Multiplication</string>
|
||||
<string name="shaders_accurate_mul_description">Uses more accurate multiplication in hardware shaders, which may fix some graphical bugs. When enabled, performance will be reduced.</string>
|
||||
<string name="asynchronous_gpu">Enable Asynchronous GPU Emulation</string>
|
||||
|
||||
@@ -715,6 +715,7 @@ void QtConfig::ReadRendererValues() {
|
||||
ReadGlobalSetting(Settings::values.shaders_accurate_mul);
|
||||
ReadGlobalSetting(Settings::values.use_disk_shader_cache);
|
||||
ReadGlobalSetting(Settings::values.use_vsync);
|
||||
ReadGlobalSetting(Settings::values.use_skip_duplicate_frames);
|
||||
ReadGlobalSetting(Settings::values.use_display_refresh_rate_detection);
|
||||
ReadGlobalSetting(Settings::values.resolution_factor);
|
||||
ReadGlobalSetting(Settings::values.use_integer_scaling);
|
||||
@@ -1265,6 +1266,7 @@ void QtConfig::SaveRendererValues() {
|
||||
WriteGlobalSetting(Settings::values.shaders_accurate_mul);
|
||||
WriteGlobalSetting(Settings::values.use_disk_shader_cache);
|
||||
WriteGlobalSetting(Settings::values.use_vsync);
|
||||
WriteGlobalSetting(Settings::values.use_skip_duplicate_frames);
|
||||
WriteGlobalSetting(Settings::values.use_display_refresh_rate_detection);
|
||||
WriteGlobalSetting(Settings::values.resolution_factor);
|
||||
WriteGlobalSetting(Settings::values.use_integer_scaling);
|
||||
|
||||
@@ -144,6 +144,8 @@ void ConfigureGraphics::SetConfiguration() {
|
||||
ui->toggle_accurate_mul->setChecked(Settings::values.shaders_accurate_mul.GetValue());
|
||||
ui->toggle_disk_shader_cache->setChecked(Settings::values.use_disk_shader_cache.GetValue());
|
||||
ui->toggle_vsync->setChecked(Settings::values.use_vsync.GetValue());
|
||||
ui->toggle_skip_duplicate_frames->setChecked(
|
||||
Settings::values.use_skip_duplicate_frames.GetValue());
|
||||
ui->spirv_shader_gen->setChecked(Settings::values.spirv_shader_gen.GetValue());
|
||||
ui->disable_spirv_optimizer->setChecked(Settings::values.disable_spirv_optimizer.GetValue());
|
||||
ui->toggle_async_shaders->setChecked(Settings::values.async_shader_compilation.GetValue());
|
||||
@@ -180,6 +182,9 @@ void ConfigureGraphics::ApplyConfiguration() {
|
||||
ui->toggle_disk_shader_cache, use_disk_shader_cache);
|
||||
ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_vsync, ui->toggle_vsync,
|
||||
use_vsync);
|
||||
ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_skip_duplicate_frames,
|
||||
ui->toggle_skip_duplicate_frames,
|
||||
use_skip_duplicate_frames);
|
||||
ConfigurationShared::ApplyPerGameSetting(
|
||||
&Settings::values.delay_game_render_thread_us, ui->delay_render_combo,
|
||||
[this](s32) { return ui->delay_render_slider->value(); });
|
||||
@@ -208,6 +213,9 @@ void ConfigureGraphics::SetupPerGameUI() {
|
||||
Settings::values.use_disk_shader_cache.UsingGlobal());
|
||||
ui->toggle_vsync->setEnabled(ui->toggle_vsync->isEnabled() &&
|
||||
Settings::values.use_vsync.UsingGlobal());
|
||||
ui->toggle_skip_duplicate_frames->setEnabled(
|
||||
ui->toggle_skip_duplicate_frames->isEnabled() &&
|
||||
Settings::values.use_skip_duplicate_frames.UsingGlobal());
|
||||
ui->toggle_async_shaders->setEnabled(
|
||||
Settings::values.async_shader_compilation.UsingGlobal());
|
||||
ui->widget_texture_sampling->setEnabled(Settings::values.texture_sampling.UsingGlobal());
|
||||
@@ -250,6 +258,9 @@ void ConfigureGraphics::SetupPerGameUI() {
|
||||
use_disk_shader_cache);
|
||||
ConfigurationShared::SetColoredTristate(ui->toggle_vsync, Settings::values.use_vsync,
|
||||
use_vsync);
|
||||
ConfigurationShared::SetColoredTristate(ui->toggle_skip_duplicate_frames,
|
||||
Settings::values.use_skip_duplicate_frames,
|
||||
use_skip_duplicate_frames);
|
||||
ConfigurationShared::SetColoredTristate(ui->toggle_async_shaders,
|
||||
Settings::values.async_shader_compilation,
|
||||
async_shader_compilation);
|
||||
|
||||
@@ -39,6 +39,7 @@ private:
|
||||
ConfigurationShared::CheckState shaders_accurate_mul;
|
||||
ConfigurationShared::CheckState use_disk_shader_cache;
|
||||
ConfigurationShared::CheckState use_vsync;
|
||||
ConfigurationShared::CheckState use_skip_duplicate_frames;
|
||||
ConfigurationShared::CheckState use_display_refresh_rate_detection;
|
||||
ConfigurationShared::CheckState async_shader_compilation;
|
||||
ConfigurationShared::CheckState async_presentation;
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>509</height>
|
||||
<height>559</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
@@ -317,6 +317,16 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="toggle_skip_duplicate_frames">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>This detects and skips the presentation of frames that are not unique. It also allows external frame generation tools to work correctly with 30fps games. Works in OpenGL and Vulkan.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Skip Presenting Duplicate Frames</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="toggle_display_refresh_rate_detection">
|
||||
<property name="toolTip">
|
||||
|
||||
@@ -104,6 +104,7 @@ void LogSettings() {
|
||||
log_setting("Renderer_UseIntegerScaling", values.use_integer_scaling.GetValue());
|
||||
log_setting("Renderer_FrameLimit", values.frame_limit.GetValue());
|
||||
log_setting("Renderer_VSyncNew", values.use_vsync.GetValue());
|
||||
log_setting("Renderer_SkipDuplicateFrames", values.use_skip_duplicate_frames.GetValue());
|
||||
log_setting("Renderer_PostProcessingShader", values.pp_shader_name.GetValue());
|
||||
log_setting("Renderer_FilterMode", values.filter_mode.GetValue());
|
||||
log_setting("Renderer_TextureFilter", GetTextureFilterName(values.texture_filter.GetValue()));
|
||||
@@ -216,6 +217,7 @@ void RestoreGlobalState(bool is_powered_on) {
|
||||
values.use_disk_shader_cache.SetGlobal(true);
|
||||
values.shaders_accurate_mul.SetGlobal(true);
|
||||
values.use_vsync.SetGlobal(true);
|
||||
values.use_skip_duplicate_frames.SetGlobal(true);
|
||||
values.resolution_factor.SetGlobal(true);
|
||||
values.use_integer_scaling.SetGlobal(true);
|
||||
values.frame_limit.SetGlobal(true);
|
||||
|
||||
@@ -535,6 +535,7 @@ struct Values {
|
||||
SwitchableSetting<bool> async_presentation{true, Keys::async_presentation};
|
||||
SwitchableSetting<bool> use_hw_shader{true, Keys::use_hw_shader};
|
||||
SwitchableSetting<bool> use_disk_shader_cache{true, Keys::use_disk_shader_cache};
|
||||
SwitchableSetting<bool> use_skip_duplicate_frames{true, Keys::use_skip_duplicate_frames};
|
||||
SwitchableSetting<bool> shaders_accurate_mul{true, Keys::shaders_accurate_mul};
|
||||
#ifdef ANDROID // TODO: Fuck this -OS
|
||||
SwitchableSetting<bool> use_vsync{false, Keys::use_vsync};
|
||||
|
||||
@@ -29,6 +29,8 @@ constexpr std::size_t IgnoreFrames = 5;
|
||||
|
||||
namespace Core {
|
||||
|
||||
bool PerfStats::game_frames_updated = true;
|
||||
|
||||
PerfStats::PerfStats(u64 title_id) : title_id(title_id) {}
|
||||
|
||||
PerfStats::~PerfStats() {
|
||||
@@ -109,6 +111,7 @@ void PerfStats::EndGameFrame() {
|
||||
std::scoped_lock lock{object_mutex};
|
||||
|
||||
game_frames += 1;
|
||||
PerfStats::game_frames_updated = true;
|
||||
}
|
||||
|
||||
double PerfStats::GetMeanFrametime() const {
|
||||
|
||||
@@ -120,6 +120,8 @@ public:
|
||||
artic_events.Set(event, set);
|
||||
}
|
||||
}
|
||||
/// Boolean representing whether game_frames has been updated since last time it was presented
|
||||
static bool game_frames_updated;
|
||||
|
||||
private:
|
||||
mutable std::mutex object_mutex;
|
||||
|
||||
@@ -93,11 +93,26 @@ void RendererOpenGL::SwapBuffers() {
|
||||
// Maintain the rasterizer's state as a priority
|
||||
OpenGLState prev_state = OpenGLState::GetCurState();
|
||||
state.Apply();
|
||||
#ifdef ANDROID
|
||||
if (secondary_window) {
|
||||
secondaryWindowEnabled = true;
|
||||
} else {
|
||||
secondaryWindowEnabled = false;
|
||||
}
|
||||
#else
|
||||
if (Settings::values.layout_option.GetValue() == Settings::LayoutOption::SeparateWindows) {
|
||||
ASSERT(secondary_window);
|
||||
secondaryWindowEnabled = true;
|
||||
} else {
|
||||
secondaryWindowEnabled = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
render_window.SetupFramebuffer();
|
||||
|
||||
PrepareRendertarget();
|
||||
RenderScreenshot();
|
||||
isSecondaryWindow = false;
|
||||
#ifdef HAVE_LIBRETRO
|
||||
DrawScreens(render_window.GetFramebufferLayout(), false);
|
||||
render_window.SwapBuffers();
|
||||
@@ -110,6 +125,7 @@ void RendererOpenGL::SwapBuffers() {
|
||||
// it means we have a second display
|
||||
if (secondary_window) {
|
||||
const auto& secondary_layout = secondary_window->GetFramebufferLayout();
|
||||
isSecondaryWindow = true;
|
||||
RenderToMailbox(secondary_layout, secondary_window->mailbox, false);
|
||||
secondary_window->PollEvents();
|
||||
}
|
||||
@@ -117,6 +133,7 @@ void RendererOpenGL::SwapBuffers() {
|
||||
if (Settings::values.layout_option.GetValue() == Settings::LayoutOption::SeparateWindows) {
|
||||
ASSERT(secondary_window);
|
||||
const auto& secondary_layout = secondary_window->GetFramebufferLayout();
|
||||
isSecondaryWindow = true;
|
||||
RenderToMailbox(secondary_layout, secondary_window->mailbox, false);
|
||||
secondary_window->PollEvents();
|
||||
}
|
||||
@@ -196,51 +213,57 @@ void RendererOpenGL::PrepareRendertarget() {
|
||||
void RendererOpenGL::RenderToMailbox(const Layout::FramebufferLayout& layout,
|
||||
std::unique_ptr<Frontend::TextureMailbox>& mailbox,
|
||||
bool flipped) {
|
||||
if (!Settings::values.use_skip_duplicate_frames.GetValue() ||
|
||||
Core::PerfStats::game_frames_updated) {
|
||||
Frontend::Frame* frame;
|
||||
{
|
||||
MICROPROFILE_SCOPE(OpenGL_WaitPresent);
|
||||
|
||||
Frontend::Frame* frame;
|
||||
{
|
||||
MICROPROFILE_SCOPE(OpenGL_WaitPresent);
|
||||
frame = mailbox->GetRenderFrame();
|
||||
|
||||
frame = mailbox->GetRenderFrame();
|
||||
// Clean up sync objects before drawing
|
||||
|
||||
// Clean up sync objects before drawing
|
||||
// INTEL driver workaround. We can't delete the previous render sync object until we are
|
||||
// sure that the presentation is done
|
||||
if (frame->present_fence) {
|
||||
glClientWaitSync(frame->present_fence, 0, GL_TIMEOUT_IGNORED);
|
||||
}
|
||||
|
||||
// INTEL driver workaround. We can't delete the previous render sync object until we are
|
||||
// sure that the presentation is done
|
||||
if (frame->present_fence) {
|
||||
glClientWaitSync(frame->present_fence, 0, GL_TIMEOUT_IGNORED);
|
||||
// delete the draw fence if the frame wasn't presented
|
||||
if (frame->render_fence) {
|
||||
glDeleteSync(frame->render_fence);
|
||||
frame->render_fence = nullptr;
|
||||
}
|
||||
|
||||
// wait for the presentation to be done
|
||||
if (frame->present_fence) {
|
||||
glWaitSync(frame->present_fence, 0, GL_TIMEOUT_IGNORED);
|
||||
glDeleteSync(frame->present_fence);
|
||||
frame->present_fence = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// delete the draw fence if the frame wasn't presented
|
||||
if (frame->render_fence) {
|
||||
glDeleteSync(frame->render_fence);
|
||||
frame->render_fence = nullptr;
|
||||
{
|
||||
MICROPROFILE_SCOPE(OpenGL_RenderFrame);
|
||||
// Recreate the frame if the size of the window has changed
|
||||
if (layout.width != frame->width || layout.height != frame->height) {
|
||||
LOG_DEBUG(Render_OpenGL, "Reloading render frame");
|
||||
mailbox->ReloadRenderFrame(frame, layout.width, layout.height);
|
||||
}
|
||||
|
||||
state.draw.draw_framebuffer = frame->render.handle;
|
||||
state.Apply();
|
||||
DrawScreens(layout, flipped);
|
||||
// Create a fence for the frontend to wait on and swap this frame to OffTex
|
||||
frame->render_fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
|
||||
glFlush();
|
||||
mailbox->ReleaseRenderFrame(frame);
|
||||
}
|
||||
|
||||
// wait for the presentation to be done
|
||||
if (frame->present_fence) {
|
||||
glWaitSync(frame->present_fence, 0, GL_TIMEOUT_IGNORED);
|
||||
glDeleteSync(frame->present_fence);
|
||||
frame->present_fence = nullptr;
|
||||
if ((secondaryWindowEnabled && isSecondaryWindow) || (!secondaryWindowEnabled)) {
|
||||
Core::PerfStats::game_frames_updated = false;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
MICROPROFILE_SCOPE(OpenGL_RenderFrame);
|
||||
// Recreate the frame if the size of the window has changed
|
||||
if (layout.width != frame->width || layout.height != frame->height) {
|
||||
LOG_DEBUG(Render_OpenGL, "Reloading render frame");
|
||||
mailbox->ReloadRenderFrame(frame, layout.width, layout.height);
|
||||
}
|
||||
|
||||
state.draw.draw_framebuffer = frame->render.handle;
|
||||
state.Apply();
|
||||
DrawScreens(layout, flipped);
|
||||
// Create a fence for the frontend to wait on and swap this frame to OffTex
|
||||
frame->render_fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
|
||||
glFlush();
|
||||
mailbox->ReleaseRenderFrame(frame);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -112,6 +112,8 @@ private:
|
||||
GLuint attrib_tex_coord;
|
||||
|
||||
FrameDumperOpenGL frame_dumper;
|
||||
bool isSecondaryWindow;
|
||||
bool secondaryWindowEnabled;
|
||||
};
|
||||
|
||||
} // namespace OpenGL
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
#include "video_core/host_shaders/vulkan_cursor_vert.h"
|
||||
|
||||
#include <vk_mem_alloc.h>
|
||||
|
||||
#if defined(__APPLE__) && !defined(HAVE_LIBRETRO)
|
||||
#include "common/apple_utils.h"
|
||||
#endif
|
||||
@@ -237,23 +236,29 @@ void RendererVulkan::PrepareDraw(Frame* frame, const Layout::FramebufferLayout&
|
||||
|
||||
void RendererVulkan::RenderToWindow(PresentWindow& window, const Layout::FramebufferLayout& layout,
|
||||
bool flipped) {
|
||||
Frame* frame = window.GetRenderFrame();
|
||||
if (!Settings::values.use_skip_duplicate_frames.GetValue() ||
|
||||
Core::PerfStats::game_frames_updated) {
|
||||
Frame* frame = window.GetRenderFrame();
|
||||
|
||||
if (layout.width != frame->width || layout.height != frame->height) {
|
||||
window.WaitPresent();
|
||||
scheduler.Finish();
|
||||
window.RecreateFrame(frame, layout.width, layout.height);
|
||||
if (layout.width != frame->width || layout.height != frame->height) {
|
||||
window.WaitPresent();
|
||||
scheduler.Finish();
|
||||
window.RecreateFrame(frame, layout.width, layout.height);
|
||||
}
|
||||
|
||||
clear_color.float32[0] = Settings::values.bg_red.GetValue();
|
||||
clear_color.float32[1] = Settings::values.bg_green.GetValue();
|
||||
clear_color.float32[2] = Settings::values.bg_blue.GetValue();
|
||||
clear_color.float32[3] = 1.0f;
|
||||
|
||||
DrawScreens(frame, layout, flipped);
|
||||
scheduler.Flush(frame->render_ready);
|
||||
window.Present(frame);
|
||||
if ((secondaryWindowEnabled && isSecondaryWindow) || (!secondaryWindowEnabled)) {
|
||||
Core::PerfStats::game_frames_updated = false;
|
||||
screenRendered = true;
|
||||
}
|
||||
}
|
||||
|
||||
clear_color.float32[0] = Settings::values.bg_red.GetValue();
|
||||
clear_color.float32[1] = Settings::values.bg_green.GetValue();
|
||||
clear_color.float32[2] = Settings::values.bg_blue.GetValue();
|
||||
clear_color.float32[3] = 1.0f;
|
||||
|
||||
DrawScreens(frame, layout, flipped);
|
||||
scheduler.Flush(frame->render_ready);
|
||||
|
||||
window.Present(frame);
|
||||
}
|
||||
|
||||
void RendererVulkan::LoadFBToScreenInfo(const Pica::FramebufferConfig& framebuffer,
|
||||
@@ -1116,9 +1121,28 @@ void RendererVulkan::DrawCursor(const Layout::FramebufferLayout& layout) {
|
||||
|
||||
void RendererVulkan::SwapBuffers() {
|
||||
system.perf_stats->StartSwap();
|
||||
screenRendered = false;
|
||||
#ifndef ANDROID
|
||||
if (Settings::values.layout_option.GetValue() == Settings::LayoutOption::SeparateWindows) {
|
||||
ASSERT(secondary_window);
|
||||
secondaryWindowEnabled = true;
|
||||
} else {
|
||||
secondaryWindowEnabled = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ANDROID
|
||||
if (secondary_window) {
|
||||
secondaryWindowEnabled = true;
|
||||
} else {
|
||||
secondaryWindowEnabled = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
const Layout::FramebufferLayout& layout = render_window.GetFramebufferLayout();
|
||||
PrepareRendertarget();
|
||||
RenderScreenshot();
|
||||
isSecondaryWindow = false;
|
||||
RenderToWindow(main_present_window, layout, false);
|
||||
#ifndef ANDROID
|
||||
if (Settings::values.layout_option.GetValue() == Settings::LayoutOption::SeparateWindows) {
|
||||
@@ -1128,6 +1152,7 @@ void RendererVulkan::SwapBuffers() {
|
||||
secondary_present_window_ptr = std::make_unique<PresentWindow>(
|
||||
*secondary_window, instance, scheduler, IsLowRefreshRate());
|
||||
}
|
||||
isSecondaryWindow = true;
|
||||
RenderToWindow(*secondary_present_window_ptr, secondary_layout, false);
|
||||
secondary_window->PollEvents();
|
||||
}
|
||||
@@ -1140,10 +1165,14 @@ void RendererVulkan::SwapBuffers() {
|
||||
secondary_present_window_ptr = std::make_unique<PresentWindow>(
|
||||
*secondary_window, instance, scheduler, IsLowRefreshRate());
|
||||
}
|
||||
isSecondaryWindow = true;
|
||||
RenderToWindow(*secondary_present_window_ptr, secondary_layout, false);
|
||||
secondary_window->PollEvents();
|
||||
}
|
||||
#endif
|
||||
if (!screenRendered) {
|
||||
scheduler.Finish();
|
||||
}
|
||||
|
||||
system.perf_stats->EndSwap();
|
||||
rasterizer.TickFrame();
|
||||
|
||||
@@ -134,7 +134,6 @@ private:
|
||||
DescriptorUpdateQueue update_queue;
|
||||
RasterizerVulkan rasterizer;
|
||||
std::unique_ptr<PresentWindow> secondary_present_window_ptr;
|
||||
|
||||
DescriptorHeap present_heap;
|
||||
vk::UniquePipelineLayout present_pipeline_layout;
|
||||
std::array<vk::Pipeline, PRESENT_PIPELINES> present_pipelines;
|
||||
@@ -151,6 +150,9 @@ private:
|
||||
vk::ShaderModule cursor_fragment_shader{};
|
||||
vk::Pipeline cursor_pipeline{};
|
||||
vk::UniquePipelineLayout cursor_pipeline_layout{};
|
||||
bool isSecondaryWindow;
|
||||
bool secondaryWindowEnabled;
|
||||
bool screenRendered;
|
||||
};
|
||||
|
||||
} // namespace Vulkan
|
||||
|
||||
Reference in New Issue
Block a user