aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp1
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp8
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h1
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_vic.cpp5
-rw-r--r--src/video_core/memory_manager.cpp19
-rw-r--r--src/video_core/memory_manager.h8
-rw-r--r--src/video_core/rasterizer_interface.h6
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp20
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h2
-rw-r--r--src/video_core/renderer_vulkan/vk_rasterizer.cpp20
-rw-r--r--src/video_core/renderer_vulkan/vk_rasterizer.h2
11 files changed, 89 insertions, 3 deletions
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp
index e2f671d8e3..aa51d44c5c 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp
@@ -68,6 +68,7 @@ void nvhost_nvdec::OnOpen(DeviceFD fd) {}
void nvhost_nvdec::OnClose(DeviceFD fd) {
LOG_INFO(Service_NVDRV, "NVDEC video stream ended");
system.GPU().ClearCdmaInstance();
+ system.GPU().MemoryManager().InvalidateQueuedCaches();
}
} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp
index c2f152190f..6654aa66d9 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp
@@ -198,7 +198,13 @@ NvResult nvhost_nvdec_common::UnmapBuffer(const std::vector<u8>& input, std::vec
return NvResult::InvalidState;
}
if (const auto size{RemoveBufferMap(object->dma_map_addr)}; size) {
- gpu.MemoryManager().Unmap(object->dma_map_addr, *size);
+ if (vic_device) {
+ // UnmapVicFrame defers texture_cache invalidation of the frame address until
+ // the stream is over
+ gpu.MemoryManager().UnmapVicFrame(object->dma_map_addr, *size);
+ } else {
+ gpu.MemoryManager().Unmap(object->dma_map_addr, *size);
+ }
} else {
// This occurs quite frequently, however does not seem to impact functionality
LOG_DEBUG(Service_NVDRV, "invalid offset=0x{:X} dma=0x{:X}", object->addr,
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h
index 4c9d4ba416..2e0aece2f0 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h
@@ -160,6 +160,7 @@ protected:
s32_le nvmap_fd{};
u32_le submit_timeout{};
+ bool vic_device{};
std::shared_ptr<nvmap> nvmap_dev;
SyncpointManager& syncpoint_manager;
std::array<u32, MaxSyncPoints> device_syncpoints{};
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp
index 301efe8a1c..8e712c4516 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp
@@ -12,8 +12,9 @@
namespace Service::Nvidia::Devices {
nvhost_vic::nvhost_vic(Core::System& system, std::shared_ptr<nvmap> nvmap_dev,
SyncpointManager& syncpoint_manager)
- : nvhost_nvdec_common(system, std::move(nvmap_dev), syncpoint_manager) {}
-
+ : nvhost_nvdec_common(system, std::move(nvmap_dev), syncpoint_manager) {
+ vic_device = true;
+}
nvhost_vic::~nvhost_vic() = default;
NvResult nvhost_vic::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
diff --git a/src/video_core/memory_manager.cpp b/src/video_core/memory_manager.cpp
index 4eb71efbdc..9529a1256c 100644
--- a/src/video_core/memory_manager.cpp
+++ b/src/video_core/memory_manager.cpp
@@ -114,6 +114,25 @@ void MemoryManager::TryUnlockPage(PageEntry page_entry, std::size_t size) {
.IsSuccess());
}
+void MemoryManager::UnmapVicFrame(GPUVAddr gpu_addr, std::size_t size) {
+ if (!size) {
+ return;
+ }
+
+ const std::optional<VAddr> cpu_addr = GpuToCpuAddress(gpu_addr);
+ ASSERT(cpu_addr);
+ rasterizer->InvalidateExceptTextureCache(*cpu_addr, size);
+ cache_invalidate_queue.push_back({*cpu_addr, size});
+
+ UpdateRange(gpu_addr, PageEntry::State::Unmapped, size);
+}
+
+void MemoryManager::InvalidateQueuedCaches() {
+ for (const auto& entry : cache_invalidate_queue) {
+ rasterizer->InvalidateTextureCache(entry.first, entry.second);
+ }
+ cache_invalidate_queue.clear();
+}
PageEntry MemoryManager::GetPageEntry(GPUVAddr gpu_addr) const {
return page_table[PageEntryIndex(gpu_addr)];
}
diff --git a/src/video_core/memory_manager.h b/src/video_core/memory_manager.h
index b3538d503d..5d6c196fa3 100644
--- a/src/video_core/memory_manager.h
+++ b/src/video_core/memory_manager.h
@@ -123,6 +123,14 @@ public:
[[nodiscard]] GPUVAddr Allocate(std::size_t size, std::size_t align);
void Unmap(GPUVAddr gpu_addr, std::size_t size);
+ /**
+ * Some Decoded NVDEC frames require that texture cache does not get invalidated.
+ * UnmapVicFrame defers the texture cache invalidation until the stream ends
+ * by invoking InvalidateQueuedCaches to invalidate all frame texture caches.
+ */
+ void UnmapVicFrame(GPUVAddr gpu_addr, std::size_t size);
+ void InvalidateQueuedCaches();
+
private:
[[nodiscard]] PageEntry GetPageEntry(GPUVAddr gpu_addr) const;
void SetPageEntry(GPUVAddr gpu_addr, PageEntry page_entry, std::size_t size = page_size);
diff --git a/src/video_core/rasterizer_interface.h b/src/video_core/rasterizer_interface.h
index 50491b7586..afc7ff4ae1 100644
--- a/src/video_core/rasterizer_interface.h
+++ b/src/video_core/rasterizer_interface.h
@@ -69,6 +69,12 @@ public:
/// Notify rasterizer that any caches of the specified region should be flushed to Switch memory
virtual void FlushRegion(VAddr addr, u64 size) = 0;
+ /// Notify rasterizer to flush the texture cache to Switch memory
+ virtual void InvalidateExceptTextureCache(VAddr addr, u64 size) = 0;
+
+ /// Notify rasterizer to invalidate the texture cache
+ virtual void InvalidateTextureCache(VAddr addr, u64 size) = 0;
+
/// Check if the the specified memory area requires flushing to CPU Memory.
virtual bool MustFlushRegion(VAddr addr, u64 size) = 0;
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 0863904e9c..2f27849519 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -544,6 +544,26 @@ void RasterizerOpenGL::FlushRegion(VAddr addr, u64 size) {
query_cache.FlushRegion(addr, size);
}
+void RasterizerOpenGL::InvalidateExceptTextureCache(VAddr addr, u64 size) {
+ if (addr == 0 || size == 0) {
+ return;
+ }
+ shader_cache.InvalidateRegion(addr, size);
+ {
+ std::scoped_lock lock{buffer_cache.mutex};
+ buffer_cache.WriteMemory(addr, size);
+ }
+ query_cache.InvalidateRegion(addr, size);
+}
+
+void RasterizerOpenGL::InvalidateTextureCache(VAddr addr, u64 size) {
+ if (addr == 0 || size == 0) {
+ return;
+ }
+ std::scoped_lock lock{texture_cache.mutex};
+ texture_cache.UnmapMemory(addr, size);
+}
+
bool RasterizerOpenGL::MustFlushRegion(VAddr addr, u64 size) {
std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex};
if (!Settings::IsGPULevelHigh()) {
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index 3745cf6379..9730544d9c 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -74,6 +74,8 @@ public:
void BindGraphicsUniformBuffer(size_t stage, u32 index, GPUVAddr gpu_addr, u32 size) override;
void FlushAll() override;
void FlushRegion(VAddr addr, u64 size) override;
+ void InvalidateExceptTextureCache(VAddr addr, u64 size) override;
+ void InvalidateTextureCache(VAddr addr, u64 size) override;
bool MustFlushRegion(VAddr addr, u64 size) override;
void InvalidateRegion(VAddr addr, u64 size) override;
void OnCPUWrite(VAddr addr, u64 size) override;
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
index e9a0e78118..ea47ac5fc6 100644
--- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp
+++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
@@ -493,6 +493,26 @@ void RasterizerVulkan::FlushRegion(VAddr addr, u64 size) {
query_cache.FlushRegion(addr, size);
}
+void Vulkan::RasterizerVulkan::InvalidateExceptTextureCache(VAddr addr, u64 size) {
+ if (addr == 0 || size == 0) {
+ return;
+ }
+ pipeline_cache.InvalidateRegion(addr, size);
+ {
+ std::scoped_lock lock{buffer_cache.mutex};
+ buffer_cache.WriteMemory(addr, size);
+ }
+ query_cache.InvalidateRegion(addr, size);
+}
+
+void Vulkan::RasterizerVulkan::InvalidateTextureCache(VAddr addr, u64 size) {
+ if (addr == 0 || size == 0) {
+ return;
+ }
+ std::scoped_lock lock{texture_cache.mutex};
+ texture_cache.UnmapMemory(addr, size);
+}
+
bool RasterizerVulkan::MustFlushRegion(VAddr addr, u64 size) {
std::scoped_lock lock{texture_cache.mutex, buffer_cache.mutex};
if (!Settings::IsGPULevelHigh()) {
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.h b/src/video_core/renderer_vulkan/vk_rasterizer.h
index 235afc6f3b..d8b5bf0fcb 100644
--- a/src/video_core/renderer_vulkan/vk_rasterizer.h
+++ b/src/video_core/renderer_vulkan/vk_rasterizer.h
@@ -66,6 +66,8 @@ public:
void BindGraphicsUniformBuffer(size_t stage, u32 index, GPUVAddr gpu_addr, u32 size) override;
void FlushAll() override;
void FlushRegion(VAddr addr, u64 size) override;
+ void InvalidateExceptTextureCache(VAddr addr, u64 size) override;
+ void InvalidateTextureCache(VAddr addr, u64 size) override;
bool MustFlushRegion(VAddr addr, u64 size) override;
void InvalidateRegion(VAddr addr, u64 size) override;
void OnCPUWrite(VAddr addr, u64 size) override;