Fix SMO synchronization (#300)
This commit is contained in:
parent
7a2a68f7ee
commit
8855290cfa
|
|
@ -36,7 +36,7 @@
|
|||
#StatusBar #volume,
|
||||
#StatusBar #renderer,
|
||||
#StatusBar #dockedMode,
|
||||
#StatusBar #syncMemoryOperations,
|
||||
#StatusBar #gpuCommandSynchronization,
|
||||
#StatusBar #volumePopupBtn
|
||||
{
|
||||
border: 1px solid transparent;
|
||||
|
|
@ -48,7 +48,7 @@
|
|||
#StatusBar #volume:hover,
|
||||
#StatusBar #renderer:hover,
|
||||
#StatusBar #dockedMode:hover,
|
||||
#StatusBar #syncMemoryOperations:hover,
|
||||
#StatusBar #gpuCommandSynchronization:hover,
|
||||
#StatusBar #volumePopupBtn:hover
|
||||
{
|
||||
border: 1px solid color(color-statusbar-hover-border);
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@
|
|||
<div id="StatusBar" >
|
||||
<span id="dockedMode" />
|
||||
<span id="renderer" />
|
||||
<span id="syncMemoryOperations" tooltip="Allow Sync Memory Operations to be toggled at runtime for performance testing." />
|
||||
<span id="gpuCommandSynchronization" tooltip="Toggle guest-requested GPU command synchronization at runtime." />
|
||||
<span id="volumeAnchor">
|
||||
<span id="volume" />
|
||||
<span id="volumePopupBtn"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024"><path d="M104.704 685.248a64 64 0 0 0 90.496 0l316.8-316.8 316.8 316.8a64 64 0 0 0 90.496-90.496L557.248 232.704a64 64 0 0 0-90.496 0L104.704 594.752a64 64 0 0 0 0 90.496"/></svg></span>
|
||||
|
|
|
|||
|
|
@ -71,8 +71,8 @@
|
|||
<div class="right"><ComboBox id="DMAAccuracy" tooltip="Controls the DMA read mode.\nUnsafe is faster, while Safe is more stable and can fix issues in some games.\nDefault follows the GPU Accuracy setting."/></div>
|
||||
</div>
|
||||
<div class="form-row checkbox-row">
|
||||
<div class="left"><label for="SyncMemoryOperations">Sync Memory Operations</label></div>
|
||||
<div class="right"><input type="checkbox" id="SyncMemoryOperations" tooltip="Ensures data consistency between compute and memory operations.\nThis option fixes issues in games, but may degrade performance.\nUnreal Engine 4 games often see the most significant changes thereof."></div>
|
||||
<div class="left"><label for="GpuCommandSynchronization">GPU Command Synchronization</label></div>
|
||||
<div class="right"><input type="checkbox" id="GpuCommandSynchronization" tooltip="Preserves guest-requested GPFIFO command ordering.\nClean command buffers avoid unnecessary GPU stalls, while command buffers that may depend on GPU-written memory are synchronized conservatively.\nDisabling this option ignores these guest synchronization requests and may cause graphical issues, hangs, or crashes."></div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div class="left"><label for="AnisotropicFiltering">Anisotropic Filtering:</label></div>
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ namespace
|
|||
{
|
||||
// Configuration storage stays on the settings thread; the GPU reads these snapshots.
|
||||
std::atomic<int32_t> runtime_dma_accuracy{0};
|
||||
std::atomic<bool> runtime_sync_memory_operations{true};
|
||||
std::atomic<bool> runtime_gpu_command_synchronization{true};
|
||||
}
|
||||
|
||||
namespace Settings
|
||||
|
|
@ -54,9 +54,9 @@ bool UseSafeDMAReads()
|
|||
return accuracy == 0 ? IsGPULevelHigh() : accuracy == 2;
|
||||
}
|
||||
|
||||
bool IsSyncMemoryOperationsEnabled()
|
||||
bool IsGpuCommandSynchronizationEnabled()
|
||||
{
|
||||
return runtime_sync_memory_operations.load(std::memory_order_relaxed);
|
||||
return runtime_gpu_command_synchronization.load(std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
void TranslateResolutionInfo(ResolutionSetup setup, ResolutionScalingInfo & info)
|
||||
|
|
@ -243,7 +243,7 @@ static VideoSetting settings[] = {
|
|||
{NXVideoSetting::AnisotropicFiltering, "video", "anisotropic_filtering", &videoSettings.max_anisotropy, AnisotropyMode::Automatic},
|
||||
#endif
|
||||
{NXVideoSetting::DMAAccuracy, "video", "dma_accuracy", &videoSettings.dma_accuracy, 0, 0, 2},
|
||||
{NXVideoSetting::SyncMemoryOperations, "video", "sync_memory_operations", &videoSettings.sync_memory_operations, true},
|
||||
{NXVideoSetting::GpuCommandSynchronization, "video", "gpu_command_synchronization", &videoSettings.gpu_command_synchronization, true},
|
||||
{NXVideoSetting::VSyncMode, "video", "vsync_mode", &videoSettings.vsync_mode, VSyncMode::Fifo},
|
||||
{NXVideoSetting::NvdecEmulation, "video", "nvdec_emulation", &videoSettings.nvdec_emulation, NvdecEmulation::Gpu},
|
||||
#ifdef _WIN32
|
||||
|
|
@ -345,9 +345,9 @@ void VideoSettingChanged(const char * setting, void * /*userData*/)
|
|||
runtime_dma_accuracy.store(videoSettings.dma_accuracy, std::memory_order_relaxed);
|
||||
return;
|
||||
}
|
||||
if (strcmp(setting, NXVideoSetting::SyncMemoryOperations) == 0)
|
||||
if (strcmp(setting, NXVideoSetting::GpuCommandSynchronization) == 0)
|
||||
{
|
||||
runtime_sync_memory_operations.store(videoSettings.sync_memory_operations, std::memory_order_relaxed);
|
||||
runtime_gpu_command_synchronization.store(videoSettings.gpu_command_synchronization, std::memory_order_relaxed);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -618,7 +618,7 @@ void SetupVideoSetting(void)
|
|||
g_settings->RegisterCallback(videoSetting.identifier, VideoSettingChanged, nullptr);
|
||||
}
|
||||
runtime_dma_accuracy.store(videoSettings.dma_accuracy, std::memory_order_relaxed);
|
||||
runtime_sync_memory_operations.store(videoSettings.sync_memory_operations, std::memory_order_relaxed);
|
||||
runtime_gpu_command_synchronization.store(videoSettings.gpu_command_synchronization, std::memory_order_relaxed);
|
||||
Settings::UpdateRescalingInfo();
|
||||
Settings::UpdateGPUAccuracy();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ bool IsGPULevelHigh();
|
|||
bool IsDMALevelDefault();
|
||||
bool IsDMALevelSafe();
|
||||
bool UseSafeDMAReads();
|
||||
bool IsSyncMemoryOperationsEnabled();
|
||||
bool IsGpuCommandSynchronizationEnabled();
|
||||
void TranslateResolutionInfo(ResolutionSetup setup, ResolutionScalingInfo & info);
|
||||
void UpdateRescalingInfo();
|
||||
|
||||
|
|
@ -80,7 +80,7 @@ struct VideoSettings
|
|||
AnisotropyMode max_anisotropy;
|
||||
bool async_presentation;
|
||||
bool use_reactive_flushing;
|
||||
bool sync_memory_operations;
|
||||
bool gpu_command_synchronization;
|
||||
|
||||
bool use_asynchronous_shaders;
|
||||
bool use_fast_gpu_time;
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ namespace NXVideoSetting
|
|||
constexpr const char * EnableAsynchronousPresentation = "nxvideo:EnableAsynchronousPresentation";
|
||||
constexpr const char * ForceMaximumClocks = "nxvideo:ForceMaximumClocks";
|
||||
constexpr const char * EnableReactiveFlushing = "nxvideo:EnableReactiveFlushing";
|
||||
constexpr const char * SyncMemoryOperations = "nxvideo:SyncMemoryOperations";
|
||||
constexpr const char * GpuCommandSynchronization = "nxvideo:GpuCommandSynchronization";
|
||||
constexpr const char * UseAsynchronousShaderBuilding = "nxvideo:UseAsynchronousShaderBuilding";
|
||||
constexpr const char * FastGPUTime = "nxvideo:FastGPUTime";
|
||||
constexpr const char * UseVulkanPipelineCache = "nxvideo:UseVulkanPipelineCache";
|
||||
|
|
|
|||
|
|
@ -287,7 +287,7 @@ SciterMainWindow::SciterMainWindow(ISciterUI & sciterUI, const char * windowTitl
|
|||
settings.RegisterCallback(NXOsSetting::DockedMode, SciterMainWindow::SettingChanged, this);
|
||||
settings.RegisterCallback(NXUISetting::Hotkeys, SciterMainWindow::HotKeysChanged, this);
|
||||
settings.RegisterCallback(NXVideoSetting::ResolutionUpFactor, SciterMainWindow::SettingChanged, this);
|
||||
settings.RegisterCallback(NXVideoSetting::SyncMemoryOperations, SciterMainWindow::SettingChanged, this);
|
||||
settings.RegisterCallback(NXVideoSetting::GpuCommandSynchronization, SciterMainWindow::SettingChanged, this);
|
||||
settings.RegisterCallback(NXUISetting::HideMouseOnInactivity, SciterMainWindow::SettingChanged, this);
|
||||
settings.RegisterCallback(NXUISetting::EnableDiscordPresence, SciterMainWindow::SettingChanged, this);
|
||||
|
||||
|
|
@ -384,7 +384,7 @@ SciterMainWindow::~SciterMainWindow()
|
|||
settings.UnregisterCallback(NXOsSetting::DockedMode, SciterMainWindow::SettingChanged, this);
|
||||
settings.UnregisterCallback(NXUISetting::Hotkeys, SciterMainWindow::HotKeysChanged, this);
|
||||
settings.UnregisterCallback(NXVideoSetting::ResolutionUpFactor, SciterMainWindow::SettingChanged, this);
|
||||
settings.UnregisterCallback(NXVideoSetting::SyncMemoryOperations, SciterMainWindow::SettingChanged, this);
|
||||
settings.UnregisterCallback(NXVideoSetting::GpuCommandSynchronization, SciterMainWindow::SettingChanged, this);
|
||||
settings.UnregisterCallback(NXUISetting::HideMouseOnInactivity, SciterMainWindow::SettingChanged, this);
|
||||
settings.UnregisterCallback(NXUISetting::EnableDiscordPresence, SciterMainWindow::SettingChanged, this);
|
||||
|
||||
|
|
@ -656,7 +656,7 @@ bool SciterMainWindow::Show()
|
|||
|
||||
m_sciterUI.AttachHandler(m_rootElement.GetElementByID("dockedMode"), IID_ICLICKSINK, (IClickSink *)this);
|
||||
m_sciterUI.AttachHandler(m_rootElement.GetElementByID("renderer"), IID_ICLICKSINK, (IClickSink *)this);
|
||||
m_sciterUI.AttachHandler(m_rootElement.GetElementByID("syncMemoryOperations"), IID_ICLICKSINK, (IClickSink *)this);
|
||||
m_sciterUI.AttachHandler(m_rootElement.GetElementByID("gpuCommandSynchronization"), IID_ICLICKSINK, (IClickSink *)this);
|
||||
m_sciterUI.AttachHandler(m_rootElement.GetElementByID("volume"), IID_ICLICKSINK, (IClickSink *)this);
|
||||
m_sciterUI.AttachHandler(m_rootElement.GetElementByID("volumePopupBtn"), IID_ICLICKSINK, (IClickSink *)this);
|
||||
m_sciterUI.AttachHandler(m_rootElement.GetElementByID("audioVolume"), IID_ISTATECHANGESINK, (IStateChangeSink *)this);
|
||||
|
|
@ -847,12 +847,12 @@ void SciterMainWindow::UpdateStatusWidgets()
|
|||
renderer.SetHTML((const uint8_t *)text.c_str(), text.size());
|
||||
}
|
||||
|
||||
SciterElement syncMemoryOperations(m_rootElement.GetElementByID("syncMemoryOperations"));
|
||||
if (syncMemoryOperations.IsValid())
|
||||
SciterElement gpuCommandSynchronization(m_rootElement.GetElementByID("gpuCommandSynchronization"));
|
||||
if (gpuCommandSynchronization.IsValid())
|
||||
{
|
||||
const bool enabled = settings.GetBool(NXVideoSetting::SyncMemoryOperations);
|
||||
stdstr_f text("SMO: %s", enabled ? "ON" : "OFF");
|
||||
syncMemoryOperations.SetHTML((const uint8_t *)text.c_str(), text.size());
|
||||
const bool enabled = settings.GetBool(NXVideoSetting::GpuCommandSynchronization);
|
||||
stdstr_f text("GPU Sync: %s", enabled ? "ON" : "OFF");
|
||||
gpuCommandSynchronization.SetHTML((const uint8_t *)text.c_str(), text.size());
|
||||
}
|
||||
|
||||
SciterElement volume(m_rootElement.GetElementByID("volume"));
|
||||
|
|
@ -2400,11 +2400,11 @@ bool SciterMainWindow::OnClick(SCITER_ELEMENT element, SCITER_ELEMENT source, ui
|
|||
m_modules.FlushSettings();
|
||||
}
|
||||
}
|
||||
else if (source == rootElement.GetElementByID("syncMemoryOperations"))
|
||||
else if (source == rootElement.GetElementByID("gpuCommandSynchronization"))
|
||||
{
|
||||
SettingsStore & settings = SettingsStore::GetInstance();
|
||||
const bool enabled = settings.GetBool(NXVideoSetting::SyncMemoryOperations);
|
||||
settings.SetBool(NXVideoSetting::SyncMemoryOperations, !enabled);
|
||||
const bool enabled = settings.GetBool(NXVideoSetting::GpuCommandSynchronization);
|
||||
settings.SetBool(NXVideoSetting::GpuCommandSynchronization, !enabled);
|
||||
UpdateStatusWidgets();
|
||||
}
|
||||
else if (source == rootElement.GetElementByID("volume"))
|
||||
|
|
@ -2464,7 +2464,7 @@ void SciterMainWindow::SettingChanged(const char * setting, void * userData)
|
|||
{
|
||||
impl->m_resolutionUpFactor = SettingsStore::GetInstance().GetFloat(NXVideoSetting::ResolutionUpFactor);
|
||||
}
|
||||
else if (strcmp(setting, NXVideoSetting::SyncMemoryOperations) == 0)
|
||||
else if (strcmp(setting, NXVideoSetting::GpuCommandSynchronization) == 0)
|
||||
{
|
||||
impl->UpdateStatusWidgets();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ namespace
|
|||
static ConfigSetting advancedSettings[] = {
|
||||
ConfigSetting(ConfigSetting::ComboBox, "AccuracyLevel", true, SystemConfig::TranslationType::GpuAccuracy, NXVideoSetting::AccuracyLevel),
|
||||
ConfigSetting(ConfigSetting::ComboBox, "DMAAccuracy", true, SystemConfig::TranslationType::DmaAccuracy, NXVideoSetting::DMAAccuracy),
|
||||
ConfigSetting(ConfigSetting::CheckBox, "SyncMemoryOperations", true, NXVideoSetting::SyncMemoryOperations),
|
||||
ConfigSetting(ConfigSetting::CheckBox, "GpuCommandSynchronization", true, NXVideoSetting::GpuCommandSynchronization),
|
||||
ConfigSetting(ConfigSetting::ComboBox, "AnisotropicFiltering", false, SystemConfig::TranslationType::AnisotropyMode, NXVideoSetting::AnisotropicFiltering),
|
||||
ConfigSetting(ConfigSetting::ComboBox, "ASTCRecompressionMethod", false, SystemConfig::TranslationType::AstcRecompression, NXVideoSetting::ASTCRecompressionMethod),
|
||||
ConfigSetting(ConfigSetting::ComboBox, "VRAMUsageMode", false, SystemConfig::TranslationType::VramUsageMode, NXVideoSetting::VRAMUsageMode),
|
||||
|
|
|
|||
|
|
@ -41,6 +41,16 @@ void DmaPusher::DispatchCalls()
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (memory_operation_sync_state == MemoryOperationSyncState::Armed)
|
||||
{
|
||||
WaitForArmedMemoryOperationSync();
|
||||
}
|
||||
else
|
||||
{
|
||||
memory_operation_sync_state = MemoryOperationSyncState::None;
|
||||
}
|
||||
|
||||
gpu.FlushCommands();
|
||||
gpu.OnCommandListEnd();
|
||||
}
|
||||
|
|
@ -75,9 +85,27 @@ bool DmaPusher::Step()
|
|||
dma_state.dma_get = header.Address();
|
||||
|
||||
// SYNC_WAIT applies to the current GP entry, including zero-length entries.
|
||||
if (header.sync && Settings::IsSyncMemoryOperationsEnabled())
|
||||
if (header.sync)
|
||||
{
|
||||
SynchronizeMemoryOperations();
|
||||
switch (memory_operation_sync_state)
|
||||
{
|
||||
case MemoryOperationSyncState::Skip:
|
||||
memory_operation_sync_state = MemoryOperationSyncState::None;
|
||||
break;
|
||||
case MemoryOperationSyncState::Armed:
|
||||
WaitForArmedMemoryOperationSync();
|
||||
break;
|
||||
case MemoryOperationSyncState::None:
|
||||
if (Settings::IsGpuCommandSynchronizationEnabled())
|
||||
{
|
||||
SynchronizeMemoryOperations();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT(memory_operation_sync_state == MemoryOperationSyncState::None);
|
||||
}
|
||||
|
||||
if (header.size > 0 && Settings::IsGPULevelHigh() &&
|
||||
|
|
@ -104,6 +132,26 @@ bool DmaPusher::Step()
|
|||
}
|
||||
}
|
||||
|
||||
// Prepare a following SYNC_WAIT at the current GP-entry boundary. Clean pushbuffers can be
|
||||
// fetched directly because DmaPusher already processes GP entries in order.
|
||||
const std::size_t next_entry_index = dma_pushbuffer_subindex + 1;
|
||||
if (next_entry_index < command_list_size && Settings::IsGpuCommandSynchronizationEnabled())
|
||||
{
|
||||
const CommandListHeader & next_header = command_list.command_lists[next_entry_index];
|
||||
if (next_header.sync)
|
||||
{
|
||||
ASSERT(memory_operation_sync_state == MemoryOperationSyncState::None);
|
||||
if (CanSkipCleanMemoryOperationSync(next_header))
|
||||
{
|
||||
memory_operation_sync_state = MemoryOperationSyncState::Skip;
|
||||
}
|
||||
else
|
||||
{
|
||||
ArmMemoryOperationSync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (++dma_pushbuffer_subindex >= command_list_size)
|
||||
{
|
||||
dma_pushbuffer.pop();
|
||||
|
|
@ -119,6 +167,38 @@ void DmaPusher::SynchronizeMemoryOperations()
|
|||
rasterizer->WaitForFence();
|
||||
}
|
||||
|
||||
void DmaPusher::ArmMemoryOperationSync()
|
||||
{
|
||||
ASSERT(rasterizer != nullptr);
|
||||
ASSERT(memory_operation_sync_state == MemoryOperationSyncState::None);
|
||||
|
||||
memory_operation_sync_ready.store(false, std::memory_order_relaxed);
|
||||
memory_operation_sync_state = MemoryOperationSyncState::Armed;
|
||||
rasterizer->SignalMemoryOperationFence([this]() {
|
||||
memory_operation_sync_ready.store(true, std::memory_order_release);
|
||||
memory_operation_sync_ready.notify_one();
|
||||
});
|
||||
}
|
||||
|
||||
void DmaPusher::WaitForArmedMemoryOperationSync()
|
||||
{
|
||||
ASSERT(memory_operation_sync_state == MemoryOperationSyncState::Armed);
|
||||
|
||||
memory_operation_sync_ready.wait(false, std::memory_order_acquire);
|
||||
memory_operation_sync_state = MemoryOperationSyncState::None;
|
||||
}
|
||||
|
||||
bool DmaPusher::CanSkipCleanMemoryOperationSync(const CommandListHeader & header) const
|
||||
{
|
||||
// The actual fetch must still resolve writes that can appear after this look-ahead probe.
|
||||
if (!Settings::UseSafeDMAReads() || header.size == 0 || header.conditional_fetch)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return !memory_manager.IsMemoryDirty(header.Address(), header.size * sizeof(u32));
|
||||
}
|
||||
|
||||
void DmaPusher::ProcessCommands(std::span<const CommandHeader> commands)
|
||||
{
|
||||
for (std::size_t index = 0; index < commands.size();)
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <span>
|
||||
#include <vector>
|
||||
#include <boost/container/small_vector.hpp>
|
||||
|
|
@ -147,8 +148,17 @@ public:
|
|||
private:
|
||||
static constexpr u32 non_puller_methods = 0x40;
|
||||
static constexpr u32 max_subchannels = 8;
|
||||
enum class MemoryOperationSyncState : u8 {
|
||||
None,
|
||||
Skip,
|
||||
Armed,
|
||||
};
|
||||
|
||||
bool Step();
|
||||
void SynchronizeMemoryOperations();
|
||||
void ArmMemoryOperationSync();
|
||||
void WaitForArmedMemoryOperationSync();
|
||||
bool CanSkipCleanMemoryOperationSync(const CommandListHeader& header) const;
|
||||
void ProcessCommands(std::span<const CommandHeader> commands);
|
||||
|
||||
void SetState(const CommandHeader& command_header);
|
||||
|
|
@ -175,6 +185,8 @@ private:
|
|||
|
||||
DmaState dma_state{};
|
||||
bool dma_increment_once{};
|
||||
MemoryOperationSyncState memory_operation_sync_state{MemoryOperationSyncState::None};
|
||||
std::atomic<bool> memory_operation_sync_ready{};
|
||||
|
||||
const bool ib_enable{true}; ///< IB mode enabled
|
||||
|
||||
|
|
|
|||
|
|
@ -76,6 +76,15 @@ public:
|
|||
(void)SubmitFence(std::move(func), force_delay, false, nullptr);
|
||||
}
|
||||
|
||||
void SignalMemoryOperationFence(std::function<void()>&& func) {
|
||||
const bool completed_inline = SubmitFence(std::move(func), true, true, nullptr);
|
||||
if constexpr (!can_async_check) {
|
||||
if (!completed_inline) {
|
||||
TryReleasePendingFences<true>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SignalSyncPoint(u32 value) {
|
||||
syncpoint_manager.IncrementGuest(value);
|
||||
std::function<void()> func([this, value] { syncpoint_manager.IncrementHost(value); });
|
||||
|
|
|
|||
|
|
@ -68,6 +68,9 @@ public:
|
|||
/// Signal a GPU based semaphore as a fence
|
||||
virtual void SignalFence(std::function<void()>&& func) = 0;
|
||||
|
||||
/// Arm an explicit memory-operation synchronization fence without blocking the DMA pusher.
|
||||
virtual void SignalMemoryOperationFence(std::function<void()>&& func) = 0;
|
||||
|
||||
/// Signal a fence and wait for its deferred synchronization operations to complete.
|
||||
virtual void WaitForFence() = 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -66,6 +66,9 @@ void RasterizerNull::ModifyGPUMemory(size_t as_id, GPUVAddr addr, u64 size) {}
|
|||
void RasterizerNull::SignalFence(std::function<void()>&& func) {
|
||||
func();
|
||||
}
|
||||
void RasterizerNull::SignalMemoryOperationFence(std::function<void()>&& func) {
|
||||
func();
|
||||
}
|
||||
void RasterizerNull::WaitForFence() {}
|
||||
void RasterizerNull::SyncOperation(std::function<void()>&& func) {
|
||||
func();
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ public:
|
|||
void UnmapMemory(DAddr addr, u64 size) override;
|
||||
void ModifyGPUMemory(size_t as_id, GPUVAddr addr, u64 size) override;
|
||||
void SignalFence(std::function<void()>&& func) override;
|
||||
void SignalMemoryOperationFence(std::function<void()>&& func) override;
|
||||
void WaitForFence() override;
|
||||
void SyncOperation(std::function<void()>&& func) override;
|
||||
void SignalSyncPoint(u32 value) override;
|
||||
|
|
|
|||
|
|
@ -615,6 +615,10 @@ void RasterizerOpenGL::SignalFence(std::function<void()>&& func) {
|
|||
fence_manager.SignalFence(std::move(func));
|
||||
}
|
||||
|
||||
void RasterizerOpenGL::SignalMemoryOperationFence(std::function<void()>&& func) {
|
||||
fence_manager.SignalMemoryOperationFence(std::move(func));
|
||||
}
|
||||
|
||||
void RasterizerOpenGL::WaitForFence() {
|
||||
fence_manager.WaitForFence();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -105,6 +105,7 @@ public:
|
|||
void UnmapMemory(DAddr addr, u64 size) override;
|
||||
void ModifyGPUMemory(size_t as_id, GPUVAddr addr, u64 size) override;
|
||||
void SignalFence(std::function<void()>&& func) override;
|
||||
void SignalMemoryOperationFence(std::function<void()>&& func) override;
|
||||
void WaitForFence() override;
|
||||
void SyncOperation(std::function<void()>&& func) override;
|
||||
void SignalSyncPoint(u32 value) override;
|
||||
|
|
|
|||
|
|
@ -685,6 +685,10 @@ void RasterizerVulkan::SignalFence(std::function<void()>&& func) {
|
|||
fence_manager.SignalFence(std::move(func));
|
||||
}
|
||||
|
||||
void RasterizerVulkan::SignalMemoryOperationFence(std::function<void()>&& func) {
|
||||
fence_manager.SignalMemoryOperationFence(std::move(func));
|
||||
}
|
||||
|
||||
void RasterizerVulkan::WaitForFence() {
|
||||
fence_manager.WaitForFence();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -107,6 +107,7 @@ public:
|
|||
void UnmapMemory(DAddr addr, u64 size) override;
|
||||
void ModifyGPUMemory(size_t as_id, GPUVAddr addr, u64 size) override;
|
||||
void SignalFence(std::function<void()>&& func) override;
|
||||
void SignalMemoryOperationFence(std::function<void()>&& func) override;
|
||||
void WaitForFence() override;
|
||||
void SyncOperation(std::function<void()>&& func) override;
|
||||
void SignalSyncPoint(u32 value) override;
|
||||
|
|
|
|||
Loading…
Reference in New Issue