diff options
Diffstat (limited to '')
-rw-r--r-- | src/core/file_sys/fssystem/fssystem_alignment_matching_storage.h | 146 |
1 files changed, 146 insertions, 0 deletions
diff --git a/src/core/file_sys/fssystem/fssystem_alignment_matching_storage.h b/src/core/file_sys/fssystem/fssystem_alignment_matching_storage.h new file mode 100644 index 000000000..f96691d03 --- /dev/null +++ b/src/core/file_sys/fssystem/fssystem_alignment_matching_storage.h @@ -0,0 +1,146 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "common/alignment.h" +#include "core/file_sys/errors.h" +#include "core/file_sys/fssystem/fs_i_storage.h" +#include "core/file_sys/fssystem/fssystem_alignment_matching_storage_impl.h" +#include "core/file_sys/fssystem/fssystem_pooled_buffer.h" + +namespace FileSys { + +template <size_t DataAlign_, size_t BufferAlign_> +class AlignmentMatchingStorage : public IStorage { + YUZU_NON_COPYABLE(AlignmentMatchingStorage); + YUZU_NON_MOVEABLE(AlignmentMatchingStorage); + +public: + static constexpr size_t DataAlign = DataAlign_; + static constexpr size_t BufferAlign = BufferAlign_; + + static constexpr size_t DataAlignMax = 0x200; + static_assert(DataAlign <= DataAlignMax); + static_assert(Common::IsPowerOfTwo(DataAlign)); + static_assert(Common::IsPowerOfTwo(BufferAlign)); + +private: + VirtualFile m_base_storage; + s64 m_base_storage_size; + +public: + explicit AlignmentMatchingStorage(VirtualFile bs) : m_base_storage(std::move(bs)) {} + + virtual size_t Read(u8* buffer, size_t size, size_t offset) const override { + // Allocate a work buffer on stack. + alignas(DataAlignMax) std::array<char, DataAlign> work_buf; + + // Succeed if zero size. + if (size == 0) { + return size; + } + + // Validate arguments. + ASSERT(buffer != nullptr); + + s64 bs_size = this->GetSize(); + ASSERT(R_SUCCEEDED(IStorage::CheckAccessRange(offset, size, bs_size))); + + return AlignmentMatchingStorageImpl::Read(m_base_storage, work_buf.data(), work_buf.size(), + DataAlign, BufferAlign, offset, buffer, size); + } + + virtual size_t Write(const u8* buffer, size_t size, size_t offset) override { + // Allocate a work buffer on stack. + alignas(DataAlignMax) std::array<char, DataAlign> work_buf; + + // Succeed if zero size. + if (size == 0) { + return size; + } + + // Validate arguments. + ASSERT(buffer != nullptr); + + s64 bs_size = this->GetSize(); + ASSERT(R_SUCCEEDED(IStorage::CheckAccessRange(offset, size, bs_size))); + + return AlignmentMatchingStorageImpl::Write(m_base_storage, work_buf.data(), work_buf.size(), + DataAlign, BufferAlign, offset, buffer, size); + } + + virtual size_t GetSize() const override { + return m_base_storage->GetSize(); + } +}; + +template <size_t BufferAlign_> +class AlignmentMatchingStoragePooledBuffer : public IStorage { + YUZU_NON_COPYABLE(AlignmentMatchingStoragePooledBuffer); + YUZU_NON_MOVEABLE(AlignmentMatchingStoragePooledBuffer); + +public: + static constexpr size_t BufferAlign = BufferAlign_; + + static_assert(Common::IsPowerOfTwo(BufferAlign)); + +private: + VirtualFile m_base_storage; + s64 m_base_storage_size; + size_t m_data_align; + +public: + explicit AlignmentMatchingStoragePooledBuffer(VirtualFile bs, size_t da) + : m_base_storage(std::move(bs)), m_data_align(da) { + ASSERT(Common::IsPowerOfTwo(da)); + } + + virtual size_t Read(u8* buffer, size_t size, size_t offset) const override { + // Succeed if zero size. + if (size == 0) { + return size; + } + + // Validate arguments. + ASSERT(buffer != nullptr); + + s64 bs_size = this->GetSize(); + ASSERT(R_SUCCEEDED(IStorage::CheckAccessRange(offset, size, bs_size))); + + // Allocate a pooled buffer. + PooledBuffer pooled_buffer; + pooled_buffer.AllocateParticularlyLarge(m_data_align, m_data_align); + + return AlignmentMatchingStorageImpl::Read(m_base_storage, pooled_buffer.GetBuffer(), + pooled_buffer.GetSize(), m_data_align, + BufferAlign, offset, buffer, size); + } + + virtual size_t Write(const u8* buffer, size_t size, size_t offset) override { + // Succeed if zero size. + if (size == 0) { + return size; + } + + // Validate arguments. + ASSERT(buffer != nullptr); + + s64 bs_size = this->GetSize(); + ASSERT(R_SUCCEEDED(IStorage::CheckAccessRange(offset, size, bs_size))); + + // Allocate a pooled buffer. + PooledBuffer pooled_buffer; + pooled_buffer.AllocateParticularlyLarge(m_data_align, m_data_align); + + return AlignmentMatchingStorageImpl::Write(m_base_storage, pooled_buffer.GetBuffer(), + pooled_buffer.GetSize(), m_data_align, + BufferAlign, offset, buffer, size); + } + + virtual size_t GetSize() const override { + return m_base_storage->GetSize(); + } +}; + +} // namespace FileSys |