Compare commits

..

7 Commits

Author SHA1 Message Date
lizzie e7e8bd7b1a 2026-09-25 09:06:19
Signed-off-by: lizzie <lizzie@eden-emu.dev>
2026-09-25 09:06:19 +00:00
lizzie 07c6eeaabd 2026-09-07 10:21:23
Signed-off-by: lizzie <lizzie@eden-emu.dev>
2026-09-25 11:03:53 +02:00
lizzie 29293295d4 2026-09-06 23:31:33
Signed-off-by: lizzie <lizzie@eden-emu.dev>
2026-09-25 11:03:53 +02:00
lizzie 2a37ed8e15 2026-09-06 22:10:34
Signed-off-by: lizzie <lizzie@eden-emu.dev>
2026-09-25 11:03:53 +02:00
lizzie 9ba0d4a541 Trigger build 2026-09-25 11:03:53 +02:00
lizzie 150c2a53a8 2026-09-05 17:42:18
Signed-off-by: lizzie <lizzie@eden-emu.dev>
2026-09-25 11:03:53 +02:00
lizzie 85eb750d2e 2026-09-05 17:17:08
Signed-off-by: lizzie <lizzie@eden-emu.dev>
2026-09-25 11:03:53 +02:00
15 changed files with 61 additions and 56148 deletions
-6
View File
@@ -137,11 +137,6 @@ add_library(
uuid.cpp uuid.cpp
uuid.h uuid.h
vector_math.h vector_math.h
zbic_compression.cpp
zbic_compression.h
zstd.c
zstd.h
zstd_errors.h
zstd_compression.cpp zstd_compression.cpp
zstd_compression.h zstd_compression.h
fs/ryujinx_compat.h fs/ryujinx_compat.cpp fs/ryujinx_compat.h fs/ryujinx_compat.cpp
@@ -246,7 +241,6 @@ endif()
target_link_libraries(common PUBLIC fmt::fmt stb::headers Threads::Threads) target_link_libraries(common PUBLIC fmt::fmt stb::headers Threads::Threads)
target_link_libraries(common PRIVATE lz4::lz4 zstd::zstd) target_link_libraries(common PRIVATE lz4::lz4 zstd::zstd)
target_compile_definitions(common PRIVATE ZSTD_ZBIC_SUPPORT=1)
# Please refer to src/common/demangle.cpp # Please refer to src/common/demangle.cpp
if (WIN32) if (WIN32)
-43
View File
@@ -1,43 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#include <cstring>
#include "common/zbic_compression.h"
#include "common/zstd.h"
namespace Common::Compression {
bool IsZBIC(const void* src, size_t src_size) {
if (!src || src_size < 4) {
return false;
}
u32 magic = 0;
std::memcpy(&magic, src, sizeof(u32));
return magic == ZSTD_MAGICNUMBER; // 0x4349425A ("ZBIC")
}
int DecompressDataZBIC(void* dst, size_t dst_size, const void* src, size_t src_size) {
if (!dst || !src || dst_size == 0 || src_size == 0) {
return -1;
}
const size_t res = ZSTD_decompress(dst, dst_size, src, src_size);
if (ZSTD_isError(res)) {
return -1;
}
return static_cast<int>(res);
}
std::vector<u8> DecompressDataZBIC(std::span<const u8> compressed, std::size_t uncompressed_size) {
std::vector<u8> uncompressed(uncompressed_size);
const int r = DecompressDataZBIC(uncompressed.data(), uncompressed_size, compressed.data(), compressed.size());
if (r <= 0) {
return {};
}
if (static_cast<size_t>(r) < uncompressed_size) {
uncompressed.resize(static_cast<size_t>(r));
}
return uncompressed;
}
} // namespace Common::Compression
-18
View File
@@ -1,18 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
#include <span>
#include <vector>
#include "common/common_types.h"
namespace Common::Compression {
[[nodiscard]] bool IsZBIC(const void* src, size_t src_size);
[[nodiscard]] std::vector<u8> DecompressDataZBIC(std::span<const u8> compressed, std::size_t uncompressed_size);
[[nodiscard]] int DecompressDataZBIC(void* dst, size_t dst_size, const void* src, size_t src_size);
} // namespace Common::Compression
-52650
View File
File diff suppressed because it is too large Load Diff
-3209
View File
File diff suppressed because it is too large Load Diff
-107
View File
@@ -1,107 +0,0 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
* All rights reserved.
*
* This source code is licensed under both the BSD-style license (found in the
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
* in the COPYING file in the root directory of this source tree).
* You may select, at your option, one of the above-listed licenses.
*/
#ifndef ZSTD_ERRORS_H_398273423
#define ZSTD_ERRORS_H_398273423
#if defined (__cplusplus)
extern "C" {
#endif
/* ===== ZSTDERRORLIB_API : control library symbols visibility ===== */
#ifndef ZSTDERRORLIB_VISIBLE
/* Backwards compatibility with old macro name */
# ifdef ZSTDERRORLIB_VISIBILITY
# define ZSTDERRORLIB_VISIBLE ZSTDERRORLIB_VISIBILITY
# elif defined(__GNUC__) && (__GNUC__ >= 4) && !defined(__MINGW32__)
# define ZSTDERRORLIB_VISIBLE __attribute__ ((visibility ("default")))
# else
# define ZSTDERRORLIB_VISIBLE
# endif
#endif
#ifndef ZSTDERRORLIB_HIDDEN
# if defined(__GNUC__) && (__GNUC__ >= 4) && !defined(__MINGW32__)
# define ZSTDERRORLIB_HIDDEN __attribute__ ((visibility ("hidden")))
# else
# define ZSTDERRORLIB_HIDDEN
# endif
#endif
#if defined(ZSTD_DLL_EXPORT) && (ZSTD_DLL_EXPORT==1)
# define ZSTDERRORLIB_API __declspec(dllexport) ZSTDERRORLIB_VISIBLE
#elif defined(ZSTD_DLL_IMPORT) && (ZSTD_DLL_IMPORT==1)
# define ZSTDERRORLIB_API __declspec(dllimport) ZSTDERRORLIB_VISIBLE /* It isn't required but allows to generate better code, saving a function pointer load from the IAT and an indirect jump.*/
#else
# define ZSTDERRORLIB_API ZSTDERRORLIB_VISIBLE
#endif
/*-*********************************************
* Error codes list
*-*********************************************
* Error codes _values_ are pinned down since v1.3.1 only.
* Therefore, don't rely on values if you may link to any version < v1.3.1.
*
* Only values < 100 are considered stable.
*
* note 1 : this API shall be used with static linking only.
* dynamic linking is not yet officially supported.
* note 2 : Prefer relying on the enum than on its value whenever possible
* This is the only supported way to use the error list < v1.3.1
* note 3 : ZSTD_isError() is always correct, whatever the library version.
**********************************************/
typedef enum {
ZSTD_error_no_error = 0,
ZSTD_error_GENERIC = 1,
ZSTD_error_prefix_unknown = 10,
ZSTD_error_version_unsupported = 12,
ZSTD_error_frameParameter_unsupported = 14,
ZSTD_error_frameParameter_windowTooLarge = 16,
ZSTD_error_corruption_detected = 20,
ZSTD_error_checksum_wrong = 22,
ZSTD_error_literals_headerWrong = 24,
ZSTD_error_dictionary_corrupted = 30,
ZSTD_error_dictionary_wrong = 32,
ZSTD_error_dictionaryCreation_failed = 34,
ZSTD_error_parameter_unsupported = 40,
ZSTD_error_parameter_combination_unsupported = 41,
ZSTD_error_parameter_outOfBound = 42,
ZSTD_error_tableLog_tooLarge = 44,
ZSTD_error_maxSymbolValue_tooLarge = 46,
ZSTD_error_maxSymbolValue_tooSmall = 48,
ZSTD_error_cannotProduce_uncompressedBlock = 49,
ZSTD_error_stabilityCondition_notRespected = 50,
ZSTD_error_stage_wrong = 60,
ZSTD_error_init_missing = 62,
ZSTD_error_memory_allocation = 64,
ZSTD_error_workSpace_tooSmall= 66,
ZSTD_error_dstSize_tooSmall = 70,
ZSTD_error_srcSize_wrong = 72,
ZSTD_error_dstBuffer_null = 74,
ZSTD_error_noForwardProgress_destFull = 80,
ZSTD_error_noForwardProgress_inputEmpty = 82,
/* following error codes are __NOT STABLE__, they can be removed or changed in future versions */
ZSTD_error_frameIndex_tooLarge = 100,
ZSTD_error_seekableIO = 102,
ZSTD_error_dstBuffer_wrong = 104,
ZSTD_error_srcBuffer_wrong = 105,
ZSTD_error_sequenceProducer_failed = 106,
ZSTD_error_externalSequences_invalid = 107,
ZSTD_error_maxCode = 120 /* never EVER use this value directly, it can change in future versions! Use ZSTD_isError() instead */
} ZSTD_ErrorCode;
ZSTDERRORLIB_API const char* ZSTD_getErrorString(ZSTD_ErrorCode code); /**< Same as ZSTD_getErrorName, but using a `ZSTD_ErrorCode` enum argument */
#if defined (__cplusplus)
}
#endif
#endif /* ZSTD_ERRORS_H_398273423 */
+3 -31
View File
@@ -13,7 +13,6 @@
#include "common/hex_util.h" #include "common/hex_util.h"
#include "common/logging.h" #include "common/logging.h"
#include "common/lz4_compression.h" #include "common/lz4_compression.h"
#include "common/zbic_compression.h"
#include "common/settings.h" #include "common/settings.h"
#include "common/swap.h" #include "common/swap.h"
#include "core/core.h" #include "core/core.h"
@@ -105,38 +104,11 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::KProcess& process, Core::
for (std::size_t i = 0; i < nso_header.segments.size(); ++i) { for (std::size_t i = 0; i < nso_header.segments.size(); ++i) {
nso_file.Read(compressed_data.data(), nso_header.segments_compressed_size[i], nso_header.segments[i].offset); nso_file.Read(compressed_data.data(), nso_header.segments_compressed_size[i], nso_header.segments[i].offset);
if (nso_header.IsSegmentCompressed(i)) { if (nso_header.IsSegmentCompressed(i)) {
if (nso_header.IsZBICCompressed()) { int r = Common::Compression::DecompressDataLZ4(decompressed_size.data(), nso_header.segments[i].size, compressed_data.data(), nso_header.segments_compressed_size[i]);
// ZBIC compression
const int r = Common::Compression::DecompressDataZBIC(
decompressed_size.data(),
nso_header.segments[i].size,
compressed_data.data(),
nso_header.segments_compressed_size[i]
);
ASSERT(r > 0);
} else {
// LZ4 compression
int r = Common::Compression::DecompressDataLZ4(
decompressed_size.data(),
nso_header.segments[i].size,
compressed_data.data(),
nso_header.segments_compressed_size[i]
);
ASSERT(r == int(nso_header.segments[i].size)); ASSERT(r == int(nso_header.segments[i].size));
} std::memcpy(codeset.memory.data() + module_start + nso_header.segments[i].location, decompressed_size.data(), nso_header.segments[i].size);
std::memcpy(
codeset.memory.data() + module_start + nso_header.segments[i].location,
decompressed_size.data(),
nso_header.segments[i].size
);
} else { } else {
// Not compressed std::memcpy(codeset.memory.data() + module_start + nso_header.segments[i].location, compressed_data.data(), nso_header.segments[i].size);
std::memcpy(
codeset.memory.data() + module_start + nso_header.segments[i].location,
compressed_data.data(),
nso_header.segments[i].size
);
} }
codeset.segments[i].addr = module_start + nso_header.segments[i].location; codeset.segments[i].addr = module_start + nso_header.segments[i].location;
codeset.segments[i].offset = module_start + nso_header.segments[i].location; codeset.segments[i].offset = module_start + nso_header.segments[i].location;
-6
View File
@@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@@ -61,9 +58,6 @@ struct NSOHeader {
std::array<SHA256Hash, 3> segment_hashes; std::array<SHA256Hash, 3> segment_hashes;
bool IsSegmentCompressed(size_t segment_num) const; bool IsSegmentCompressed(size_t segment_num) const;
bool IsZBICCompressed() const {
return ((flags >> 7) & 1) != 0;
}
}; };
static_assert(sizeof(NSOHeader) == 0x100, "NSOHeader has incorrect size."); static_assert(sizeof(NSOHeader) == 0x100, "NSOHeader has incorrect size.");
static_assert(std::is_trivially_copyable_v<NSOHeader>, "NSOHeader must be trivially copyable."); static_assert(std::is_trivially_copyable_v<NSOHeader>, "NSOHeader must be trivially copyable.");
@@ -200,7 +200,7 @@ public:
if (host_visible) { if (host_visible) {
return StagingBufferRef{}; return StagingBufferRef{};
} }
return staging_pool.Request(size_bytes, MemoryUsage::Upload); return staging_pool.Request(device, size_bytes, MemoryUsage::Upload);
}(); }();
u8* staging_data = host_visible ? buffer.Mapped().data() : staging.mapped_span.data(); u8* staging_data = host_visible ? buffer.Mapped().data() : staging.mapped_span.data();
@@ -375,11 +375,11 @@ BufferCacheRuntime::BufferCacheRuntime(const Device& device_, MemoryAllocator& m
} }
StagingBufferRef BufferCacheRuntime::UploadStagingBuffer(size_t size) { StagingBufferRef BufferCacheRuntime::UploadStagingBuffer(size_t size) {
return staging_pool.Request(size, MemoryUsage::Upload); return staging_pool.Request(device, size, MemoryUsage::Upload);
} }
StagingBufferRef BufferCacheRuntime::DownloadStagingBuffer(size_t size, bool deferred) { StagingBufferRef BufferCacheRuntime::DownloadStagingBuffer(size_t size, bool deferred) {
return staging_pool.Request(size, MemoryUsage::Download, deferred); return staging_pool.Request(device, size, MemoryUsage::Download, deferred);
} }
VkFormat BufferCacheRuntime::TexelBufferFormat(VideoCore::Surface::PixelFormat format) const { VkFormat BufferCacheRuntime::TexelBufferFormat(VideoCore::Surface::PixelFormat format) const {
@@ -162,7 +162,7 @@ public:
std::span<u8> BindMappedUniformBuffer([[maybe_unused]] size_t stage, std::span<u8> BindMappedUniformBuffer([[maybe_unused]] size_t stage,
[[maybe_unused]] u32 binding_index, [[maybe_unused]] u32 binding_index,
u32 size) { u32 size) {
const StagingBufferRef ref = staging_pool.Request(size, MemoryUsage::Upload); const StagingBufferRef ref = staging_pool.Request(device, size, MemoryUsage::Upload);
guest_descriptor_queue.AddBuffer(ref.buffer, ref.device_address, guest_descriptor_queue.AddBuffer(ref.buffer, ref.device_address,
static_cast<u32>(ref.offset), size); static_cast<u32>(ref.offset), size);
return ref.mapped_span; return ref.mapped_span;
@@ -287,7 +287,7 @@ Uint8Pass::~Uint8Pass() = default;
std::pair<VkBuffer, VkDeviceSize> Uint8Pass::Assemble(u32 num_vertices, VkBuffer src_buffer, std::pair<VkBuffer, VkDeviceSize> Uint8Pass::Assemble(u32 num_vertices, VkBuffer src_buffer,
u32 src_offset) { u32 src_offset) {
const u32 staging_size = static_cast<u32>(num_vertices * sizeof(u16)); const u32 staging_size = static_cast<u32>(num_vertices * sizeof(u16));
const auto staging = staging_buffer_pool.Request(staging_size, MemoryUsage::DeviceLocal); const auto staging = staging_buffer_pool.Request(device, staging_size, MemoryUsage::DeviceLocal);
compute_pass_descriptor_queue.Acquire(scheduler, 2); compute_pass_descriptor_queue.Acquire(scheduler, 2);
compute_pass_descriptor_queue.AddBuffer(src_buffer, src_offset, num_vertices); compute_pass_descriptor_queue.AddBuffer(src_buffer, src_offset, num_vertices);
@@ -345,7 +345,7 @@ std::pair<VkBuffer, VkDeviceSize> QuadIndexedPass::Assemble(
const u32 num_tri_vertices = (is_strip ? (num_vertices - 2) / 2 : num_vertices / 4) * 6; const u32 num_tri_vertices = (is_strip ? (num_vertices - 2) / 2 : num_vertices / 4) * 6;
const std::size_t staging_size = num_tri_vertices * sizeof(u32); const std::size_t staging_size = num_tri_vertices * sizeof(u32);
const auto staging = staging_buffer_pool.Request(staging_size, MemoryUsage::DeviceLocal); const auto staging = staging_buffer_pool.Request(device, staging_size, MemoryUsage::DeviceLocal);
compute_pass_descriptor_queue.Acquire(scheduler, 2); compute_pass_descriptor_queue.Acquire(scheduler, 2);
compute_pass_descriptor_queue.AddBuffer(src_buffer, src_offset, input_size); compute_pass_descriptor_queue.AddBuffer(src_buffer, src_offset, input_size);
@@ -852,7 +852,7 @@ public:
void PushUnsyncedQueries() override { void PushUnsyncedQueries() override {
CloseCounter(); CloseCounter();
auto staging_ref = staging_pool.Request( auto staging_ref = staging_pool.Request(device,
pending_flush_queries.size() * TFBQueryBank::QUERY_SIZE, MemoryUsage::Download, true); pending_flush_queries.size() * TFBQueryBank::QUERY_SIZE, MemoryUsage::Download, true);
size_t offset_base = staging_ref.offset; size_t offset_base = staging_ref.offset;
for (auto q : pending_flush_queries) { for (auto q : pending_flush_queries) {
@@ -1657,7 +1657,7 @@ void QueryCacheRuntime::SyncValues(std::span<SyncValuesType> values, VkBuffer ba
impl->copies_setup.clear(); impl->copies_setup.clear();
impl->copies_setup.resize(impl->little_cache.size()); impl->copies_setup.resize(impl->little_cache.size());
if constexpr (SyncValuesType::GeneratesBaseBuffer) { if constexpr (SyncValuesType::GeneratesBaseBuffer) {
ref = impl->staging_pool.Request(total_size, MemoryUsage::Upload); ref = impl->staging_pool.Request(impl->device, total_size, MemoryUsage::Upload);
size_t current_offset = ref.offset; size_t current_offset = ref.offset;
size_t accumulated_size = 0; size_t accumulated_size = 0;
for (size_t i = 0; i < values.size(); i++) { for (size_t i = 0; i < values.size(); i++) {
@@ -28,55 +28,42 @@ using namespace Common::Literals;
// Maximum potential alignment of a Vulkan buffer // Maximum potential alignment of a Vulkan buffer
constexpr VkDeviceSize MAX_ALIGNMENT = 256; constexpr VkDeviceSize MAX_ALIGNMENT = 256;
// Stream buffer size in bytes size_t GetStreamBufferSize(const Device& device, size_t max_stream_buffer_size, size_t max_alignment) {
// *NIX drivers are more sensitive to increased buffers for streaming.
// Windows ones however, can intake bigger buffers and generally do not OOM.
// - GTX 960 on Windows will not OOM with 256mib
// - GT 1030 on ^NIX will OOM with 256mib
#if defined(__FreeBSD__)
constexpr VkDeviceSize MAX_STREAM_BUFFER_SIZE = 128_MiB;
#else
constexpr VkDeviceSize MAX_STREAM_BUFFER_SIZE = 256_MiB;
#endif
size_t GetStreamBufferSize(const Device& device) {
if (!device.HasDebuggingToolAttached()) { if (!device.HasDebuggingToolAttached()) {
return MAX_STREAM_BUFFER_SIZE; return max_stream_buffer_size;
} }
VkDeviceSize size{0}; VkDeviceSize size{0};
bool has_device_local_host_visible_heap{}; bool has_device_local_host_visible_heap{};
ForEachDeviceLocalHostVisibleHeap(device, [&size, &has_device_local_host_visible_heap]( ForEachDeviceLocalHostVisibleHeap(device, [&size, &has_device_local_host_visible_heap](size_t index, VkMemoryHeap& heap) {
size_t index, VkMemoryHeap& heap) {
has_device_local_host_visible_heap = true; has_device_local_host_visible_heap = true;
size = (std::max)(size, heap.size); size = std::max<size_t>(size, heap.size);
}); });
if (has_device_local_host_visible_heap) { if (has_device_local_host_visible_heap) {
// If rebar is not supported, cut the max heap size to 40%. This will allow 2 captures to be // If rebar is not supported, cut the max heap size to 40%. This will allow 2 captures to be
// loaded at the same time in RenderDoc. If rebar is supported, this shouldn't be an issue // loaded at the same time in RenderDoc. If rebar is supported, this shouldn't be an issue
// as the heap will be much larger. // as the heap will be much larger.
if (size <= MAX_STREAM_BUFFER_SIZE) { if (size <= max_stream_buffer_size) {
size = size * 40 / 100; size = size * 40 / 100;
} }
} else { } else {
size = MAX_STREAM_BUFFER_SIZE; size = max_stream_buffer_size;
} }
return (std::min)(Common::AlignUp(size, MAX_ALIGNMENT), MAX_STREAM_BUFFER_SIZE); return std::min<size_t>(Common::AlignUp(size, max_alignment), max_stream_buffer_size);
} }
} // Anonymous namespace } // Anonymous namespace
StagingBufferPool::StagingBufferPool(const Device& device_, MemoryAllocator& memory_allocator_, StagingBufferPool::StagingBufferPool(const Device& device, MemoryAllocator& memory_allocator_, Scheduler& scheduler_)
Scheduler& scheduler_) : memory_allocator{memory_allocator_}, scheduler{scheduler_}
: device{device_}, memory_allocator{memory_allocator_}, scheduler{scheduler_}, , stream_buffer_size{GetStreamBufferSize(device, 256_MiB, MAX_ALIGNMENT)}
stream_buffer_size{GetStreamBufferSize(device)}, region_size{stream_buffer_size / {
StagingBufferPool::NUM_SYNCS} {
VkBufferCreateInfo stream_ci = { VkBufferCreateInfo stream_ci = {
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
.pNext = nullptr, .pNext = nullptr,
.flags = 0, .flags = 0,
.size = stream_buffer_size, .size = stream_buffer_size,
.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | .usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT
VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, | VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
.sharingMode = VK_SHARING_MODE_EXCLUSIVE, .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
.queueFamilyIndexCount = 0, .queueFamilyIndexCount = 0,
.pQueueFamilyIndices = nullptr, .pQueueFamilyIndices = nullptr,
@@ -87,7 +74,16 @@ StagingBufferPool::StagingBufferPool(const Device& device_, MemoryAllocator& mem
if (device.IsBufferDeviceAddressSupported()) { if (device.IsBufferDeviceAddressSupported()) {
stream_ci.usage |= VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT; stream_ci.usage |= VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT;
} }
// Some drivers are more sensitive to increased buffer sizes
try {
stream_buffer = memory_allocator.CreateBuffer(stream_ci, MemoryUsage::Stream); stream_buffer = memory_allocator.CreateBuffer(stream_ci, MemoryUsage::Stream);
} catch (vk::Exception& e) {
LOG_ERROR(Render_Vulkan, "Can't fit {} bytes buffer, halving", stream_ci.size);
stream_buffer_size = GetStreamBufferSize(device, 128_MiB, MAX_ALIGNMENT);
stream_ci.size = stream_buffer_size;
stream_buffer = memory_allocator.CreateBuffer(stream_ci, MemoryUsage::Stream);
}
region_size = stream_buffer_size / StagingBufferPool::NUM_SYNCS;
if (device.HasDebuggingToolAttached()) { if (device.HasDebuggingToolAttached()) {
stream_buffer.SetObjectNameEXT("Stream Buffer"); stream_buffer.SetObjectNameEXT("Stream Buffer");
} }
@@ -100,11 +96,10 @@ StagingBufferPool::StagingBufferPool(const Device& device_, MemoryAllocator& mem
StagingBufferPool::~StagingBufferPool() = default; StagingBufferPool::~StagingBufferPool() = default;
StagingBufferRef StagingBufferPool::Request(size_t size, MemoryUsage usage, bool deferred) { StagingBufferRef StagingBufferPool::Request(const Device& device, size_t size, MemoryUsage usage, bool deferred) {
if (!deferred && usage == MemoryUsage::Upload && size <= region_size) { return (!deferred && usage == MemoryUsage::Upload && size <= region_size)
return GetStreamBuffer(size); ? GetStreamBuffer(device, size)
} : GetStagingBuffer(device, size, usage, deferred);
return GetStagingBuffer(size, usage, deferred);
} }
void StagingBufferPool::FreeDeferred(StagingBufferRef& ref) { void StagingBufferPool::FreeDeferred(StagingBufferRef& ref) {
@@ -127,11 +122,10 @@ void StagingBufferPool::TickFrame() {
ReleaseCache(MemoryUsage::Download); ReleaseCache(MemoryUsage::Download);
} }
StagingBufferRef StagingBufferPool::GetStreamBuffer(size_t size) { StagingBufferRef StagingBufferPool::GetStreamBuffer(const Device& device, size_t size) {
if (AreRegionsActive(Region(free_iterator) + 1, if (AreRegionsActive(Region(free_iterator) + 1, (std::min)(Region(iterator + size) + 1, NUM_SYNCS))) {
(std::min)(Region(iterator + size) + 1, NUM_SYNCS))) {
// Avoid waiting for the previous usages to be free // Avoid waiting for the previous usages to be free
return GetStagingBuffer(size, MemoryUsage::Upload); return GetStagingBuffer(device, size, MemoryUsage::Upload);
} }
const u64 current_tick = scheduler.CurrentTick(); const u64 current_tick = scheduler.CurrentTick();
std::fill(sync_ticks.begin() + Region(used_iterator), sync_ticks.begin() + Region(iterator), std::fill(sync_ticks.begin() + Region(used_iterator), sync_ticks.begin() + Region(iterator),
@@ -140,15 +134,14 @@ StagingBufferRef StagingBufferPool::GetStreamBuffer(size_t size) {
free_iterator = (std::max)(free_iterator, iterator + size); free_iterator = (std::max)(free_iterator, iterator + size);
if (iterator + size >= stream_buffer_size) { if (iterator + size >= stream_buffer_size) {
std::fill(sync_ticks.begin() + Region(used_iterator), sync_ticks.begin() + NUM_SYNCS, std::fill(sync_ticks.begin() + Region(used_iterator), sync_ticks.begin() + NUM_SYNCS, current_tick);
current_tick);
used_iterator = 0; used_iterator = 0;
iterator = 0; iterator = 0;
free_iterator = size; free_iterator = size;
if (AreRegionsActive(0, Region(size) + 1)) { if (AreRegionsActive(0, Region(size) + 1)) {
// Avoid waiting for the previous usages to be free // Avoid waiting for the previous usages to be free
return GetStagingBuffer(size, MemoryUsage::Upload); return GetStagingBuffer(device, size, MemoryUsage::Upload);
} }
} }
const size_t offset = iterator; const size_t offset = iterator;
@@ -156,7 +149,7 @@ StagingBufferRef StagingBufferPool::GetStreamBuffer(size_t size) {
return StagingBufferRef{ return StagingBufferRef{
.buffer = *stream_buffer, .buffer = *stream_buffer,
.device_address = stream_buffer_address, .device_address = stream_buffer_address,
.offset = static_cast<VkDeviceSize>(offset), .offset = VkDeviceSize(offset),
.mapped_span = stream_pointer.subspan(offset, size), .mapped_span = stream_pointer.subspan(offset, size),
.usage{}, .usage{},
.log2_level{}, .log2_level{},
@@ -166,21 +159,18 @@ StagingBufferRef StagingBufferPool::GetStreamBuffer(size_t size) {
bool StagingBufferPool::AreRegionsActive(size_t region_begin, size_t region_end) const { bool StagingBufferPool::AreRegionsActive(size_t region_begin, size_t region_end) const {
const u64 gpu_tick = scheduler.GetMasterSemaphore().KnownGpuTick(); const u64 gpu_tick = scheduler.GetMasterSemaphore().KnownGpuTick();
return std::any_of(sync_ticks.begin() + region_begin, sync_ticks.begin() + region_end, return std::any_of(sync_ticks.begin() + region_begin, sync_ticks.begin() + region_end, [gpu_tick](u64 sync_tick) {
[gpu_tick](u64 sync_tick) { return gpu_tick < sync_tick; }); return gpu_tick < sync_tick;
});
}; };
StagingBufferRef StagingBufferPool::GetStagingBuffer(size_t size, MemoryUsage usage, StagingBufferRef StagingBufferPool::GetStagingBuffer(const Device& device, size_t size, MemoryUsage usage, bool deferred) {
bool deferred) { if (const std::optional<StagingBufferRef> ref = TryGetReservedBuffer(size, usage, deferred))
if (const std::optional<StagingBufferRef> ref = TryGetReservedBuffer(size, usage, deferred)) {
return *ref; return *ref;
} return CreateStagingBuffer(device, size, usage, deferred);
return CreateStagingBuffer(size, usage, deferred);
} }
std::optional<StagingBufferRef> StagingBufferPool::TryGetReservedBuffer(size_t size, std::optional<StagingBufferRef> StagingBufferPool::TryGetReservedBuffer(size_t size, MemoryUsage usage, bool deferred) {
MemoryUsage usage,
bool deferred) {
StagingBuffers& cache_level = GetCache(usage)[Common::Log2Ceil(size)]; StagingBuffers& cache_level = GetCache(usage)[Common::Log2Ceil(size)];
const auto is_free = [this](const StagingBuffer& entry) { const auto is_free = [this](const StagingBuffer& entry) {
@@ -202,7 +192,7 @@ std::optional<StagingBufferRef> StagingBufferPool::TryGetReservedBuffer(size_t s
return it->Ref(); return it->Ref();
} }
StagingBufferRef StagingBufferPool::CreateStagingBuffer(size_t size, MemoryUsage usage, bool deferred) { StagingBufferRef StagingBufferPool::CreateStagingBuffer(const Device& device, size_t size, MemoryUsage usage, bool deferred) {
auto const log2_size = Common::Log2Ceil<u32>(u32(size)); auto const log2_size = Common::Log2Ceil<u32>(u32(size));
VkBufferCreateInfo buffer_ci = { VkBufferCreateInfo buffer_ci = {
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
@@ -33,11 +33,10 @@ class StagingBufferPool {
public: public:
static constexpr size_t NUM_SYNCS = 16; static constexpr size_t NUM_SYNCS = 16;
explicit StagingBufferPool(const Device& device, MemoryAllocator& memory_allocator, explicit StagingBufferPool(const Device& device, MemoryAllocator& memory_allocator, Scheduler& scheduler);
Scheduler& scheduler);
~StagingBufferPool(); ~StagingBufferPool();
StagingBufferRef Request(size_t size, MemoryUsage usage, bool deferred = false); StagingBufferRef Request(const Device& device, size_t size, MemoryUsage usage, bool deferred = false);
void FreeDeferred(StagingBufferRef& ref); void FreeDeferred(StagingBufferRef& ref);
[[nodiscard]] VkBuffer StreamBuf() const noexcept { [[nodiscard]] VkBuffer StreamBuf() const noexcept {
@@ -84,27 +83,18 @@ private:
static constexpr size_t NUM_LEVELS = sizeof(size_t) * CHAR_BIT; static constexpr size_t NUM_LEVELS = sizeof(size_t) * CHAR_BIT;
using StagingBuffersCache = std::array<StagingBuffers, NUM_LEVELS>; using StagingBuffersCache = std::array<StagingBuffers, NUM_LEVELS>;
StagingBufferRef GetStreamBuffer(size_t size); StagingBufferRef GetStreamBuffer(const Device& device, size_t size);
bool AreRegionsActive(size_t region_begin, size_t region_end) const; bool AreRegionsActive(size_t region_begin, size_t region_end) const;
StagingBufferRef GetStagingBuffer(const Device& device, size_t size, MemoryUsage usage, bool deferred = false);
StagingBufferRef GetStagingBuffer(size_t size, MemoryUsage usage, bool deferred = false); std::optional<StagingBufferRef> TryGetReservedBuffer(size_t size, MemoryUsage usage, bool deferred);
StagingBufferRef CreateStagingBuffer(const Device& device, size_t size, MemoryUsage usage, bool deferred);
std::optional<StagingBufferRef> TryGetReservedBuffer(size_t size, MemoryUsage usage,
bool deferred);
StagingBufferRef CreateStagingBuffer(size_t size, MemoryUsage usage, bool deferred);
StagingBuffersCache& GetCache(MemoryUsage usage); StagingBuffersCache& GetCache(MemoryUsage usage);
void ReleaseCache(MemoryUsage usage); void ReleaseCache(MemoryUsage usage);
void ReleaseLevel(StagingBuffersCache& cache, size_t log2); void ReleaseLevel(StagingBuffersCache& cache, size_t log2);
size_t Region(size_t iter) const noexcept { size_t Region(size_t iter) const noexcept {
return iter / region_size; return iter / region_size;
} }
const Device& device;
MemoryAllocator& memory_allocator; MemoryAllocator& memory_allocator;
Scheduler& scheduler; Scheduler& scheduler;
@@ -975,11 +975,11 @@ void TextureCacheRuntime::Finish() {
} }
StagingBufferRef TextureCacheRuntime::UploadStagingBuffer(size_t size, bool deferred) { StagingBufferRef TextureCacheRuntime::UploadStagingBuffer(size_t size, bool deferred) {
return staging_buffer_pool.Request(size, MemoryUsage::Upload, deferred); return staging_buffer_pool.Request(device, size, MemoryUsage::Upload, deferred);
} }
StagingBufferRef TextureCacheRuntime::DownloadStagingBuffer(size_t size, bool deferred) { StagingBufferRef TextureCacheRuntime::DownloadStagingBuffer(size_t size, bool deferred) {
return staging_buffer_pool.Request(size, MemoryUsage::Download, deferred); return staging_buffer_pool.Request(device, size, MemoryUsage::Download, deferred);
} }
void TextureCacheRuntime::FreeDeferredStagingBuffer(StagingBufferRef& ref) { void TextureCacheRuntime::FreeDeferredStagingBuffer(StagingBufferRef& ref) {