mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2026-09-26 19:11:00 +00:00
Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e7e8bd7b1a | |||
| 07c6eeaabd | |||
| 29293295d4 | |||
| 2a37ed8e15 | |||
| 9ba0d4a541 | |||
| 150c2a53a8 | |||
| 85eb750d2e |
@@ -5,11 +5,6 @@
|
|||||||
"repo": "lioncash/biscuit",
|
"repo": "lioncash/biscuit",
|
||||||
"version": "v0.19.0"
|
"version": "v0.19.0"
|
||||||
},
|
},
|
||||||
"atmosphere_zstd_bic": {
|
|
||||||
"hash": "204f7573ea40de2878759c7ff5b2c016111fc29ae8574df50a3a0db9018c3b012f9040ea7466559130424d4335f2dfd6d7abfdc4d4d67e8a34531b8284f0cc6a",
|
|
||||||
"repo": "Atmosphere-NX/Atmosphere",
|
|
||||||
"version": "3ace80cc7b87e1837fccca1522801bbf6fddc6aa"
|
|
||||||
},
|
|
||||||
"boost": {
|
"boost": {
|
||||||
"artifact": "boost-%VERSION%.tar.zst",
|
"artifact": "boost-%VERSION%.tar.zst",
|
||||||
"find_args": "CONFIG OPTIONAL_COMPONENTS headers context system fiber filesystem",
|
"find_args": "CONFIG OPTIONAL_COMPONENTS headers context system fiber filesystem",
|
||||||
@@ -338,11 +333,6 @@
|
|||||||
"repo": "herumi/xbyak",
|
"repo": "herumi/xbyak",
|
||||||
"version": "v7.40.1"
|
"version": "v7.40.1"
|
||||||
},
|
},
|
||||||
"zbic": {
|
|
||||||
"hash": "fbe2f37986377d7f0d96ae3224c80b5971df6e8b6961f68061f1975ebb2e8cb78f07b90f014b007be4023dbf5513581504e7f7d61a5237cb2a8a7a61ae11e482",
|
|
||||||
"repo": "kinnay/zbic",
|
|
||||||
"version": "11b08f2712264bbed731545085cbd9702096ceb7"
|
|
||||||
},
|
|
||||||
"zlib": {
|
"zlib": {
|
||||||
"hash": "16fea4df307a68cf0035858abe2fd550250618a97590e202037acd18a666f57afc10f8836cbbd472d54a0e76539d0e558cb26f059d53de52ff90634bbf4f47d4",
|
"hash": "16fea4df307a68cf0035858abe2fd550250618a97590e202037acd18a666f57afc10f8836cbbd472d54a0e76539d0e558cb26f059d53de52ff90634bbf4f47d4",
|
||||||
"min_version": "1.2",
|
"min_version": "1.2",
|
||||||
|
|||||||
Vendored
-5
@@ -48,11 +48,6 @@ if (NOT TARGET stb::headers)
|
|||||||
add_library(stb::headers ALIAS stb)
|
add_library(stb::headers ALIAS stb)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
AddJsonPackage(NAME zbic DOWNLOAD_ONLY)
|
|
||||||
set(ZBIC_INCLUDE_DIR
|
|
||||||
"${zbic_SOURCE_DIR}/src"
|
|
||||||
PARENT_SCOPE)
|
|
||||||
|
|
||||||
# ItaniumDemangle (Windows only)
|
# ItaniumDemangle (Windows only)
|
||||||
if (WIN32 AND NOT TARGET LLVM::Demangle)
|
if (WIN32 AND NOT TARGET LLVM::Demangle)
|
||||||
add_library(demangle demangle/ItaniumDemangle.cpp)
|
add_library(demangle demangle/ItaniumDemangle.cpp)
|
||||||
|
|||||||
@@ -137,8 +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_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
|
||||||
@@ -149,10 +147,6 @@ add_library(
|
|||||||
net/net.h net/net.cpp
|
net/net.h net/net.cpp
|
||||||
container/unordered_map.h container/unordered_set.h)
|
container/unordered_map.h container/unordered_set.h)
|
||||||
|
|
||||||
set_source_files_properties(zbic_compression.cpp PROPERTIES
|
|
||||||
INCLUDE_DIRECTORIES "${ZBIC_INCLUDE_DIR}"
|
|
||||||
COMPILE_OPTIONS "$<$<CXX_COMPILER_ID:Clang,GNU>:-Wno-unused-function>")
|
|
||||||
|
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
target_sources(common PRIVATE windows/timer_resolution.cpp
|
target_sources(common PRIVATE windows/timer_resolution.cpp
|
||||||
windows/timer_resolution.h)
|
windows/timer_resolution.h)
|
||||||
|
|||||||
@@ -1,40 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
#include <cstring>
|
|
||||||
|
|
||||||
#include "common/zbic_compression.h"
|
|
||||||
|
|
||||||
#define ZSTD_ZBIC_SUPPORT 1
|
|
||||||
#define ZSTDLIB_VISIBLE static
|
|
||||||
#define ZSTDLIB_HIDDEN static
|
|
||||||
#define ZSTDERRORLIB_VISIBLE static
|
|
||||||
#define ZSTDERRORLIB_HIDDEN static
|
|
||||||
#undef ZSTD_MULTITHREAD
|
|
||||||
|
|
||||||
#include "zstd.h"
|
|
||||||
#include "zstd.c"
|
|
||||||
|
|
||||||
namespace Common::Compression {
|
|
||||||
|
|
||||||
bool IsZBIC(std::span<const u8> src) {
|
|
||||||
if (src.size() < sizeof(u32)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
u32 magic = 0;
|
|
||||||
std::memcpy(&magic, src.data(), sizeof(u32));
|
|
||||||
return magic == ZSTD_MAGICNUMBER; // 0x4349425A ("ZBIC")
|
|
||||||
}
|
|
||||||
|
|
||||||
int DecompressDataZBIC(std::span<u8> dst, std::span<const u8> src) {
|
|
||||||
if (dst.empty() || src.empty()) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
const size_t res = ZSTD_decompress(dst.data(), dst.size(), src.data(), src.size());
|
|
||||||
if (ZSTD_isError(res)) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return static_cast<int>(res);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Common::Compression
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <span>
|
|
||||||
#include "common/common_types.h"
|
|
||||||
|
|
||||||
namespace Common::Compression {
|
|
||||||
|
|
||||||
[[nodiscard]] bool IsZBIC(std::span<const u8> src);
|
|
||||||
|
|
||||||
[[nodiscard]] int DecompressDataZBIC(std::span<u8> dst, std::span<const u8> src);
|
|
||||||
|
|
||||||
} // namespace Common::Compression
|
|
||||||
+4
-31
@@ -7,14 +7,12 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cinttypes>
|
#include <cinttypes>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <span>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "common/common_funcs.h"
|
#include "common/common_funcs.h"
|
||||||
#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"
|
||||||
@@ -106,36 +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
|
ASSERT(r == int(nso_header.segments[i].size));
|
||||||
const int r = Common::Compression::DecompressDataZBIC(
|
std::memcpy(codeset.memory.data() + module_start + nso_header.segments[i].location, decompressed_size.data(), nso_header.segments[i].size);
|
||||||
std::span<u8>{decompressed_size}.first(nso_header.segments[i].size),
|
|
||||||
std::span<const u8>{compressed_data}.first(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));
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
stream_buffer = memory_allocator.CreateBuffer(stream_ci, MemoryUsage::Stream);
|
// Some drivers are more sensitive to increased buffer sizes
|
||||||
|
try {
|
||||||
|
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) {
|
||||||
|
|||||||
Reference in New Issue
Block a user