diff --git a/src/video_core/buffer_cache/buffer_cache.h b/src/video_core/buffer_cache/buffer_cache.h
index 087d7ac1f8..734ec5e0f3 100644
--- a/src/video_core/buffer_cache/buffer_cache.h
+++ b/src/video_core/buffer_cache/buffer_cache.h
@@ -1876,6 +1876,20 @@ void BufferCache
::MappedUploadMemory([[maybe_unused]] Buffer& buffer,
[[maybe_unused]] u64 total_size_bytes,
[[maybe_unused]] std::span copies) {
if constexpr (USE_MEMORY_MAPS) {
+ if constexpr (requires { runtime.DirectUploadSpan(buffer, copies); }) {
+ const std::span direct = runtime.DirectUploadSpan(buffer, copies);
+ if (!direct.empty()) {
+ for (const BufferCopy& copy : copies) {
+ const DAddr device_addr = buffer.CpuAddr() + copy.dst_offset;
+ if (Settings::values.enable_gpu_buffer_readback.GetValue()) {
+ DownloadBufferMemory(buffer, device_addr, copy.size);
+ }
+ device_memory.ReadBlockUnsafe(device_addr, direct.data() + copy.dst_offset,
+ copy.size);
+ }
+ return;
+ }
+ }
auto upload_staging = runtime.UploadStagingBuffer(total_size_bytes);
const std::span staging_pointer = upload_staging.mapped_span;
for (BufferCopy& copy : copies) {
diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
index 77e33d1354..f35ee502ce 100644
--- a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
@@ -97,10 +97,14 @@ vk::Buffer CreateBuffer(const Device& device, const MemoryAllocator& memory_allo
.queueFamilyIndexCount = 0,
.pQueueFamilyIndices = nullptr,
};
- if (sparse_alignment > 1) {
- return memory_allocator.CreateBuffer(buffer_ci, MemoryUsage::DeviceLocal, sparse_alignment);
+ MemoryUsage usage = MemoryUsage::DeviceLocal;
+ if (device.IsUMA()) {
+ usage = MemoryUsage::Stream;
}
- return memory_allocator.CreateBuffer(buffer_ci, MemoryUsage::DeviceLocal);
+ if (sparse_alignment > 1) {
+ return memory_allocator.CreateBuffer(buffer_ci, usage, sparse_alignment);
+ }
+ return memory_allocator.CreateBuffer(buffer_ci, usage);
}
} // Anonymous namespace
@@ -138,6 +142,17 @@ void Buffer::MarkUsage(u64 offset, u64 size) noexcept {
last_usage_tick = scheduler->CurrentTick();
}
+void Buffer::MarkUpload() noexcept {
+ last_upload_tick = scheduler->CurrentTick();
+}
+
+std::span Buffer::CoherentMapping() noexcept {
+ if (!buffer.IsHostCoherent()) {
+ return {};
+ }
+ return buffer.Mapped();
+}
+
VkBufferView Buffer::View(u32 offset, u32 size, VideoCore::Surface::PixelFormat format) {
if (!device) {
// Null buffer supported, return a null descriptor
@@ -496,6 +511,16 @@ bool BufferCacheRuntime::CanReorderUpload(const Buffer& buffer,
return can_use_upload_cmdbuf;
}
+std::span BufferCacheRuntime::DirectUploadSpan(
+ Buffer& buffer, std::span copies) {
+ const std::span mapping = buffer.CoherentMapping();
+ if (mapping.empty() || !scheduler.IsFree(buffer.LastUploadTick()) ||
+ !CanReorderUpload(buffer, copies)) {
+ return {};
+ }
+ return mapping;
+}
+
void BufferCacheRuntime::CopyBuffer(VkBuffer dst_buffer, VkBuffer src_buffer,
std::span copies, bool barrier,
bool can_reorder_upload) {
diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.h b/src/video_core/renderer_vulkan/vk_buffer_cache.h
index 2f40cc2ac1..d96bd3783a 100644
--- a/src/video_core/renderer_vulkan/vk_buffer_cache.h
+++ b/src/video_core/renderer_vulkan/vk_buffer_cache.h
@@ -69,6 +69,14 @@ public:
return last_usage_tick;
}
+ void MarkUpload() noexcept;
+
+ [[nodiscard]] u64 LastUploadTick() const noexcept {
+ return last_upload_tick;
+ }
+
+ [[nodiscard]] std::span CoherentMapping() noexcept;
+
operator VkBuffer() const noexcept {
return *buffer;
}
@@ -88,6 +96,7 @@ private:
VideoCommon::UsageTracker tracker;
VkDeviceAddress device_address{};
u64 last_usage_tick{};
+ u64 last_upload_tick{};
bool is_null{};
bool sparse_compatible{};
};
@@ -140,6 +149,9 @@ public:
bool CanReorderUpload(const Buffer& buffer, std::span copies);
+ [[nodiscard]] std::span DirectUploadSpan(Buffer& buffer,
+ std::span copies);
+
void FreeDeferredStagingBuffer(StagingBufferRef& ref);
void PreCopyBarrier();
@@ -148,6 +160,13 @@ public:
std::span copies, bool barrier,
bool can_reorder_upload = false);
+ void CopyBuffer(Buffer& dst_buffer, VkBuffer src_buffer,
+ std::span copies, bool barrier,
+ bool can_reorder_upload = false) {
+ dst_buffer.MarkUpload();
+ CopyBuffer(dst_buffer.Handle(), src_buffer, copies, barrier, can_reorder_upload);
+ }
+
void PostCopyBarrier();
void ClearBuffer(VkBuffer dest_buffer, u32 offset, size_t size, u32 value);
diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp
index b3969fd77d..e9075a62b5 100644
--- a/src/video_core/vulkan_common/vulkan_device.cpp
+++ b/src/video_core/vulkan_common/vulkan_device.cpp
@@ -487,6 +487,15 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
properties.subgroup_size_control.maxSubgroupSize > GuestWarpSize;
is_integrated = properties.properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU;
+ const VkPhysicalDeviceMemoryProperties memory_properties =
+ physical.GetMemoryProperties().memoryProperties;
+ is_uma = std::all_of(memory_properties.memoryTypes,
+ memory_properties.memoryTypes + memory_properties.memoryTypeCount,
+ [](const VkMemoryType& type) {
+ return (type.propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) ==
+ 0 ||
+ (type.propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0;
+ });
supports_d24_depth =
IsFormatSupported(VK_FORMAT_D24_UNORM_S8_UINT,
diff --git a/src/video_core/vulkan_common/vulkan_device.h b/src/video_core/vulkan_common/vulkan_device.h
index fa230fa0f4..b562c210e5 100644
--- a/src/video_core/vulkan_common/vulkan_device.h
+++ b/src/video_core/vulkan_common/vulkan_device.h
@@ -984,6 +984,10 @@ FN_MAX_LIMIT_LIST
return must_emulate_scaled_formats;
}
+ bool IsUMA() const {
+ return is_uma;
+ }
+
bool HasNullDescriptor() const {
return features.robustness2.nullDescriptor;
}
@@ -1198,6 +1202,7 @@ private:
bool is_blit_depth32_stencil8_supported{}; ///< Support for blitting from and to D32S8.
bool is_warp_potentially_bigger{}; ///< Host warp size can be bigger than guest.
bool is_integrated{}; ///< Is GPU an iGPU.
+ bool is_uma{};
bool has_broken_compute{}; ///< Compute shaders can cause crashes
bool has_broken_cube_compatibility{}; ///< Has broken cube compatibility bit
bool has_broken_float16_math{};