FenceManager: Implement async buffer cache flushes on High settings
This commit is contained in:
parent
4adfc9bb08
commit
b10db7e4a5
|
@ -21,6 +21,7 @@
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
#include "core/memory.h"
|
#include "core/memory.h"
|
||||||
|
#include "core/settings.h"
|
||||||
#include "video_core/buffer_cache/buffer_block.h"
|
#include "video_core/buffer_cache/buffer_block.h"
|
||||||
#include "video_core/buffer_cache/map_interval.h"
|
#include "video_core/buffer_cache/map_interval.h"
|
||||||
#include "video_core/memory_manager.h"
|
#include "video_core/memory_manager.h"
|
||||||
|
@ -80,6 +81,9 @@ public:
|
||||||
auto map = MapAddress(block, gpu_addr, cpu_addr, size);
|
auto map = MapAddress(block, gpu_addr, cpu_addr, size);
|
||||||
if (is_written) {
|
if (is_written) {
|
||||||
map->MarkAsModified(true, GetModifiedTicks());
|
map->MarkAsModified(true, GetModifiedTicks());
|
||||||
|
if (Settings::IsGPULevelHigh() && Settings::values.use_asynchronous_gpu_emulation) {
|
||||||
|
AsyncFlushMap(map);
|
||||||
|
}
|
||||||
if (!map->IsWritten()) {
|
if (!map->IsWritten()) {
|
||||||
map->MarkAsWritten(true);
|
map->MarkAsWritten(true);
|
||||||
MarkRegionAsWritten(map->GetStart(), map->GetEnd() - 1);
|
MarkRegionAsWritten(map->GetStart(), map->GetEnd() - 1);
|
||||||
|
@ -193,6 +197,39 @@ public:
|
||||||
marked_for_unregister.clear();
|
marked_for_unregister.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CommitAsyncFlushes() {
|
||||||
|
commited_flushes.push_back(uncommited_flushes);
|
||||||
|
uncommited_flushes.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ShouldWaitAsyncFlushes() {
|
||||||
|
if (commited_flushes.empty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
auto& flush_list = commited_flushes.front();
|
||||||
|
if (!flush_list) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PopAsyncFlushes() {
|
||||||
|
if (commited_flushes.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto& flush_list = commited_flushes.front();
|
||||||
|
if (!flush_list) {
|
||||||
|
commited_flushes.pop_front();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (MapInterval& map : *flush_list) {
|
||||||
|
if (map->IsRegistered()) {
|
||||||
|
FlushMap(map);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
commited_flushes.pop_front();
|
||||||
|
}
|
||||||
|
|
||||||
virtual BufferType GetEmptyBuffer(std::size_t size) = 0;
|
virtual BufferType GetEmptyBuffer(std::size_t size) = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -316,6 +353,9 @@ private:
|
||||||
MapInterval new_map = CreateMap(new_start, new_end, new_gpu_addr);
|
MapInterval new_map = CreateMap(new_start, new_end, new_gpu_addr);
|
||||||
if (modified_inheritance) {
|
if (modified_inheritance) {
|
||||||
new_map->MarkAsModified(true, GetModifiedTicks());
|
new_map->MarkAsModified(true, GetModifiedTicks());
|
||||||
|
if (Settings::IsGPULevelHigh() && Settings::values.use_asynchronous_gpu_emulation) {
|
||||||
|
AsyncFlushMap(new_map);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Register(new_map, write_inheritance);
|
Register(new_map, write_inheritance);
|
||||||
return new_map;
|
return new_map;
|
||||||
|
@ -502,6 +542,13 @@ private:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AsyncFlushMap(MapInterval& map) {
|
||||||
|
if (!uncommited_flushes) {
|
||||||
|
uncommited_flushes = std::make_shared<std::list<MapInterval>>();
|
||||||
|
}
|
||||||
|
uncommited_flushes->push_back(map);
|
||||||
|
}
|
||||||
|
|
||||||
VideoCore::RasterizerInterface& rasterizer;
|
VideoCore::RasterizerInterface& rasterizer;
|
||||||
Core::System& system;
|
Core::System& system;
|
||||||
|
|
||||||
|
@ -533,6 +580,9 @@ private:
|
||||||
std::vector<u8> staging_buffer;
|
std::vector<u8> staging_buffer;
|
||||||
std::list<MapInterval> marked_for_unregister;
|
std::list<MapInterval> marked_for_unregister;
|
||||||
|
|
||||||
|
std::shared_ptr<std::list<MapInterval>> uncommited_flushes{};
|
||||||
|
std::list<std::shared_ptr<std::list<MapInterval>>> commited_flushes;
|
||||||
|
|
||||||
std::recursive_mutex mutex;
|
std::recursive_mutex mutex;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -6,8 +6,8 @@
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <queue>
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <queue>
|
||||||
|
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
@ -37,7 +37,7 @@ private:
|
||||||
u32 payload;
|
u32 payload;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename TFence, typename TTextureCache>
|
template <typename TFence, typename TTextureCache, typename TTBufferCache>
|
||||||
class FenceManager {
|
class FenceManager {
|
||||||
public:
|
public:
|
||||||
void SignalFence(GPUVAddr addr, u32 value) {
|
void SignalFence(GPUVAddr addr, u32 value) {
|
||||||
|
@ -46,6 +46,7 @@ public:
|
||||||
QueueFence(new_fence);
|
QueueFence(new_fence);
|
||||||
fences.push(new_fence);
|
fences.push(new_fence);
|
||||||
texture_cache.CommitAsyncFlushes();
|
texture_cache.CommitAsyncFlushes();
|
||||||
|
buffer_cache.CommitAsyncFlushes();
|
||||||
rasterizer.FlushCommands();
|
rasterizer.FlushCommands();
|
||||||
rasterizer.SyncGuestHost();
|
rasterizer.SyncGuestHost();
|
||||||
}
|
}
|
||||||
|
@ -54,10 +55,12 @@ public:
|
||||||
while (!fences.empty()) {
|
while (!fences.empty()) {
|
||||||
TFence& current_fence = fences.front();
|
TFence& current_fence = fences.front();
|
||||||
bool should_wait = texture_cache.ShouldWaitAsyncFlushes();
|
bool should_wait = texture_cache.ShouldWaitAsyncFlushes();
|
||||||
|
should_wait |= buffer_cache.ShouldWaitAsyncFlushes();
|
||||||
if (should_wait) {
|
if (should_wait) {
|
||||||
WaitFence(current_fence);
|
WaitFence(current_fence);
|
||||||
}
|
}
|
||||||
texture_cache.PopAsyncFlushes();
|
texture_cache.PopAsyncFlushes();
|
||||||
|
buffer_cache.PopAsyncFlushes();
|
||||||
auto& gpu{system.GPU()};
|
auto& gpu{system.GPU()};
|
||||||
auto& memory_manager{gpu.MemoryManager()};
|
auto& memory_manager{gpu.MemoryManager()};
|
||||||
memory_manager.Write<u32>(current_fence->GetAddress(), current_fence->GetPayload());
|
memory_manager.Write<u32>(current_fence->GetAddress(), current_fence->GetPayload());
|
||||||
|
@ -67,8 +70,9 @@ public:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
FenceManager(Core::System& system, VideoCore::RasterizerInterface& rasterizer,
|
FenceManager(Core::System& system, VideoCore::RasterizerInterface& rasterizer,
|
||||||
TTextureCache& texture_cache)
|
TTextureCache& texture_cache, TTBufferCache& buffer_cache)
|
||||||
: system{system}, rasterizer{rasterizer}, texture_cache{texture_cache} {}
|
: system{system}, rasterizer{rasterizer}, texture_cache{texture_cache}, buffer_cache{
|
||||||
|
buffer_cache} {}
|
||||||
|
|
||||||
virtual TFence CreateFence(GPUVAddr addr, u32 value) = 0;
|
virtual TFence CreateFence(GPUVAddr addr, u32 value) = 0;
|
||||||
virtual void QueueFence(TFence& fence) = 0;
|
virtual void QueueFence(TFence& fence) = 0;
|
||||||
|
@ -78,16 +82,19 @@ protected:
|
||||||
Core::System& system;
|
Core::System& system;
|
||||||
VideoCore::RasterizerInterface& rasterizer;
|
VideoCore::RasterizerInterface& rasterizer;
|
||||||
TTextureCache& texture_cache;
|
TTextureCache& texture_cache;
|
||||||
|
TTBufferCache& buffer_cache;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void TryReleasePendingFences() {
|
void TryReleasePendingFences() {
|
||||||
while (!fences.empty()) {
|
while (!fences.empty()) {
|
||||||
TFence& current_fence = fences.front();
|
TFence& current_fence = fences.front();
|
||||||
bool should_wait = texture_cache.ShouldWaitAsyncFlushes();
|
bool should_wait = texture_cache.ShouldWaitAsyncFlushes();
|
||||||
|
should_wait |= buffer_cache.ShouldWaitAsyncFlushes();
|
||||||
if (should_wait && !IsFenceSignaled(current_fence)) {
|
if (should_wait && !IsFenceSignaled(current_fence)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
texture_cache.PopAsyncFlushes();
|
texture_cache.PopAsyncFlushes();
|
||||||
|
buffer_cache.PopAsyncFlushes();
|
||||||
auto& gpu{system.GPU()};
|
auto& gpu{system.GPU()};
|
||||||
auto& memory_manager{gpu.MemoryManager()};
|
auto& memory_manager{gpu.MemoryManager()};
|
||||||
memory_manager.Write<u32>(current_fence->GetAddress(), current_fence->GetPayload());
|
memory_manager.Write<u32>(current_fence->GetAddress(), current_fence->GetPayload());
|
||||||
|
|
|
@ -81,7 +81,7 @@ void ThreadManager::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ThreadManager::FlushRegion(VAddr addr, u64 size) {
|
void ThreadManager::FlushRegion(VAddr addr, u64 size) {
|
||||||
if (!Settings::IsGPULevelExtreme()) {
|
if (!Settings::IsGPULevelHigh()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (system.Renderer().Rasterizer().MustFlushRegion(addr, size)) {
|
if (system.Renderer().Rasterizer().MustFlushRegion(addr, size)) {
|
||||||
|
|
|
@ -33,8 +33,8 @@ void GLInnerFence::Wait() {
|
||||||
}
|
}
|
||||||
|
|
||||||
FenceManagerOpenGL::FenceManagerOpenGL(Core::System& system, VideoCore::RasterizerInterface& rasterizer,
|
FenceManagerOpenGL::FenceManagerOpenGL(Core::System& system, VideoCore::RasterizerInterface& rasterizer,
|
||||||
TextureCacheOpenGL& texture_cache)
|
TextureCacheOpenGL& texture_cache, OGLBufferCache& buffer_cache)
|
||||||
: GenericFenceManager(system, rasterizer, texture_cache) {}
|
: GenericFenceManager(system, rasterizer, texture_cache, buffer_cache) {}
|
||||||
|
|
||||||
Fence FenceManagerOpenGL::CreateFence(GPUVAddr addr, u32 value) {
|
Fence FenceManagerOpenGL::CreateFence(GPUVAddr addr, u32 value) {
|
||||||
return std::make_shared<GLInnerFence>(addr, value);
|
return std::make_shared<GLInnerFence>(addr, value);
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
|
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "video_core/fence_manager.h"
|
#include "video_core/fence_manager.h"
|
||||||
|
#include "video_core/renderer_opengl/gl_buffer_cache.h"
|
||||||
#include "video_core/renderer_opengl/gl_resource_manager.h"
|
#include "video_core/renderer_opengl/gl_resource_manager.h"
|
||||||
#include "video_core/renderer_opengl/gl_texture_cache.h"
|
#include "video_core/renderer_opengl/gl_texture_cache.h"
|
||||||
|
|
||||||
|
@ -30,12 +31,12 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
using Fence = std::shared_ptr<GLInnerFence>;
|
using Fence = std::shared_ptr<GLInnerFence>;
|
||||||
using GenericFenceManager = VideoCommon::FenceManager<Fence, TextureCacheOpenGL>;
|
using GenericFenceManager = VideoCommon::FenceManager<Fence, TextureCacheOpenGL, OGLBufferCache>;
|
||||||
|
|
||||||
class FenceManagerOpenGL final : public GenericFenceManager {
|
class FenceManagerOpenGL final : public GenericFenceManager {
|
||||||
public:
|
public:
|
||||||
FenceManagerOpenGL(Core::System& system, VideoCore::RasterizerInterface& rasterizer,
|
FenceManagerOpenGL(Core::System& system, VideoCore::RasterizerInterface& rasterizer,
|
||||||
TextureCacheOpenGL& texture_cache);
|
TextureCacheOpenGL& texture_cache, OGLBufferCache& buffer_cache);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Fence CreateFence(GPUVAddr addr, u32 value) override;
|
Fence CreateFence(GPUVAddr addr, u32 value) override;
|
||||||
|
|
|
@ -102,7 +102,8 @@ RasterizerOpenGL::RasterizerOpenGL(Core::System& system, Core::Frontend::EmuWind
|
||||||
shader_cache{*this, system, emu_window, device}, query_cache{system, *this}, system{system},
|
shader_cache{*this, system, emu_window, device}, query_cache{system, *this}, system{system},
|
||||||
screen_info{info}, program_manager{program_manager}, state_tracker{state_tracker},
|
screen_info{info}, program_manager{program_manager}, state_tracker{state_tracker},
|
||||||
buffer_cache{*this, system, device, STREAM_BUFFER_SIZE}, fence_manager{system, *this,
|
buffer_cache{*this, system, device, STREAM_BUFFER_SIZE}, fence_manager{system, *this,
|
||||||
texture_cache} {
|
texture_cache,
|
||||||
|
buffer_cache} {
|
||||||
CheckExtensions();
|
CheckExtensions();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Reference in New Issue