From 55efa7dc9616ba25c4c7148d067f0d848f314894 Mon Sep 17 00:00:00 2001 From: Ishan09811 <156402647+Ishan09811@users.noreply.github.com> Date: Thu, 26 Dec 2024 20:30:27 +0530 Subject: [PATCH] Implement Android 15 16kib page size support (#40) --- .github/workflows/ci.yml | 2 +- app/build.gradle | 12 +- app/libraries/audio-core | 2 +- app/src/main/cpp/skyline/common/base.h | 105 +++++++------ .../main/cpp/skyline/common/interval_map.h | 8 +- .../main/cpp/skyline/common/trap_manager.cpp | 2 +- .../gpu/interconnect/common/pipeline.inc | 7 +- .../interconnect/maxwell_3d/maxwell_3d.cpp | 3 +- app/src/main/cpp/skyline/gpu/megabuffer.cpp | 139 +++++++++--------- .../cpp/skyline/gpu/presentation_engine.cpp | 5 +- .../main/cpp/skyline/kernel/types/KProcess.h | 3 +- app/src/main/cpp/skyline/loader/loader.cpp | 3 +- 12 files changed, 158 insertions(+), 133 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4e5a7f5e..04d0ed3a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,7 +19,7 @@ jobs: IS_BUILD_SIGNED: ${{ secrets.KEYSTORE != '' }} UPLOAD_ARTIFACTS: ${{ github.event_name != 'pull_request' || contains(github.event.pull_request.labels.*.name, 'ci') }} CMAKE_VERSION: "3.22.1" - NDK_VERSION: "26.1.10909125" + NDK_VERSION: "27.2.12479018" BUILD_TYPE: release steps: diff --git a/app/build.gradle b/app/build.gradle index c39fac3e..32b7fb78 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -15,7 +15,7 @@ idea.module { android { namespace 'emu.skyline' - compileSdk 34 + compileSdk 35 var isBuildSigned = (System.getenv("CI") == "true") && (System.getenv("IS_BUILD_SIGNED") == "true") @@ -23,7 +23,7 @@ android { applicationId "io.github.pine.emu" minSdk 29 - targetSdk 34 + targetSdk 35 versionCode 1 versionName "1.0.0" @@ -76,7 +76,8 @@ android { debuggable true externalNativeBuild { cmake { - arguments "-DCMAKE_BUILD_TYPE=RELEASE" + arguments "-DCMAKE_BUILD_TYPE=RELEASE", + "-DANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES=ON" } } minifyEnabled true @@ -90,7 +91,8 @@ android { debuggable true externalNativeBuild { cmake { - arguments "-DCMAKE_BUILD_TYPE=RELWITHDEBINFO" + arguments "-DCMAKE_BUILD_TYPE=RELWITHDEBINFO", + "-DANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES=ON" } } minifyEnabled false @@ -132,7 +134,7 @@ android { } /* NDK and CMake */ - ndkVersion '26.1.10909125' + ndkVersion '27.2.12479018' externalNativeBuild { cmake { version '3.22.1+' diff --git a/app/libraries/audio-core b/app/libraries/audio-core index f99f0b33..e1ccbd4d 160000 --- a/app/libraries/audio-core +++ b/app/libraries/audio-core @@ -1 +1 @@ -Subproject commit f99f0b337c97a84abdf152710a9b81e10f3d4ae8 +Subproject commit e1ccbd4d4f9757856e4998b1c6087c265c62605d diff --git a/app/src/main/cpp/skyline/common/base.h b/app/src/main/cpp/skyline/common/base.h index c5a58b06..b7e94ec7 100644 --- a/app/src/main/cpp/skyline/common/base.h +++ b/app/src/main/cpp/skyline/common/base.h @@ -1,43 +1,62 @@ -// SPDX-License-Identifier: MPL-2.0 -// Copyright © 2021 Skyline Team and Contributors (https://github.com/skyline-emu/) - -#pragma once - -#include -#include - -namespace skyline { - using u128 = __uint128_t; //!< Unsigned 128-bit integer - using u64 = __uint64_t; //!< Unsigned 64-bit integer - using u32 = __uint32_t; //!< Unsigned 32-bit integer - using u16 = __uint16_t; //!< Unsigned 16-bit integer - using u8 = __uint8_t; //!< Unsigned 8-bit integer - using i128 = __int128_t; //!< Signed 128-bit integer - using i64 = __int64_t; //!< Signed 64-bit integer - using i32 = __int32_t; //!< Signed 32-bit integer - using i16 = __int16_t; //!< Signed 16-bit integer - using i8 = __int8_t; //!< Signed 8-bit integer - - using KHandle = u32; //!< The type of a kernel handle - - namespace constant { - // Time - constexpr i64 NsInMicrosecond{1000}; //!< The amount of nanoseconds in a microsecond - constexpr i64 NsInSecond{1000000000}; //!< The amount of nanoseconds in a second - constexpr i64 NsInMillisecond{1000000}; //!< The amount of nanoseconds in a millisecond - constexpr i64 NsInDay{86400000000000UL}; //!< The amount of nanoseconds in a day - - constexpr size_t AddressSpaceSize{1ULL << 39}; //!< The size of the host CPU AS in bytes - constexpr size_t PageSize{0x1000}; //!< The size of a host page - constexpr size_t PageSizeBits{12}; //!< log2(PageSize) - - static_assert(PageSize == PAGE_SIZE); - } - - /** - * @brief A deduction guide for overloads required for std::visit with std::variant - */ - template - struct VariantVisitor : Ts ... { using Ts::operator()...; }; - template VariantVisitor(Ts...) -> VariantVisitor; -} +// SPDX-License-Identifier: MPL-2.0 +// Copyright © 2021 Skyline Team and Contributors (https://github.com/skyline-emu/) + +#pragma once + +#include +#include +#include +#include + +namespace skyline { + using u128 = __uint128_t; //!< Unsigned 128-bit integer + using u64 = __uint64_t; //!< Unsigned 64-bit integer + using u32 = __uint32_t; //!< Unsigned 32-bit integer + using u16 = __uint16_t; //!< Unsigned 16-bit integer + using u8 = __uint8_t; //!< Unsigned 8-bit integer + using i128 = __int128_t; //!< Signed 128-bit integer + using i64 = __int64_t; //!< Signed 64-bit integer + using i32 = __int32_t; //!< Signed 32-bit integer + using i16 = __int16_t; //!< Signed 16-bit integer + using i8 = __int8_t; //!< Signed 8-bit integer + + using KHandle = u32; //!< The type of a kernel handle + + namespace constant { + // Time + constexpr i64 NsInMicrosecond{1000}; //!< The amount of nanoseconds in a microsecond + constexpr i64 NsInSecond{1000000000}; //!< The amount of nanoseconds in a second + constexpr i64 NsInMillisecond{1000000}; //!< The amount of nanoseconds in a millisecond + constexpr i64 NsInDay{86400000000000UL}; //!< The amount of nanoseconds in a day + + constexpr size_t AddressSpaceSize{1ULL << 39}; //!< The size of the host CPU AS in bytes + + constexpr u16 TlsSlotSize{0x200}; + + inline size_t getDynamicPageSize() { + size_t pageSize = getpagesize(); + if (pageSize == 0) { + throw std::runtime_error("Failed to retrieve page size"); + } + return pageSize; + } + + inline u8 getTlsSlots() { + size_t slots = getDynamicPageSize() / TlsSlotSize; + if (slots > 255) { + throw std::runtime_error("TlsSlots exceeds u8 capacity!"); + } + return static_cast(slots); + } + + const size_t PageSize{getDynamicPageSize()}; //!< The size of a host page + constexpr size_t PageSizeBits{12}; //!< log2(PageSize) + } + + /** + * @brief A deduction guide for overloads required for std::visit with std::variant + */ + template + struct VariantVisitor : Ts ... { using Ts::operator()...; }; + template VariantVisitor(Ts...) -> VariantVisitor; +} diff --git a/app/src/main/cpp/skyline/common/interval_map.h b/app/src/main/cpp/skyline/common/interval_map.h index cb37b55b..e8559a2f 100644 --- a/app/src/main/cpp/skyline/common/interval_map.h +++ b/app/src/main/cpp/skyline/common/interval_map.h @@ -158,8 +158,7 @@ namespace skyline { * @return All entries overlapping with the given interval and a list of intervals they recursively cover with alignment for page-based lookup semantics * @note This function is specifically designed for memory faulting lookups and has design-decisions that correspond to that which might not work for other uses */ - template - std::pair>, std::vector> GetAlignedRecursiveRange(Interval interval) { + std::pair>, std::vector> GetAlignedRecursiveRange(std::size_t Alignment, Interval interval) { std::vector> queryEntries; std::vector intervals; @@ -242,9 +241,8 @@ namespace skyline { return std::pair{queryEntries, intervals}; } - template - std::pair>, std::vector> GetAlignedRecursiveRange(AddressType address) { - return GetAlignedRecursiveRange(Interval{address, address + 1}); + std::pair>, std::vector> GetAlignedRecursiveRange(std::size_t Alignment, AddressType address) { + return GetAlignedRecursiveRange(Alignment, Interval{address, address + 1}); } }; } diff --git a/app/src/main/cpp/skyline/common/trap_manager.cpp b/app/src/main/cpp/skyline/common/trap_manager.cpp index 5cbb279c..7d438c28 100644 --- a/app/src/main/cpp/skyline/common/trap_manager.cpp +++ b/app/src/main/cpp/skyline/common/trap_manager.cpp @@ -121,7 +121,7 @@ namespace skyline { std::scoped_lock lock(trapMutex); // Retrieve any callbacks for the page that was faulted - auto [entries, intervals]{trapMap.GetAlignedRecursiveRange(address)}; + auto [entries, intervals]{trapMap.GetAlignedRecursiveRange(constant::PageSize, address)}; if (entries.empty()) return false; // There's no callbacks associated with this page diff --git a/app/src/main/cpp/skyline/gpu/interconnect/common/pipeline.inc b/app/src/main/cpp/skyline/gpu/interconnect/common/pipeline.inc index 3b10dc05..a83482fd 100644 --- a/app/src/main/cpp/skyline/gpu/interconnect/common/pipeline.inc +++ b/app/src/main/cpp/skyline/gpu/interconnect/common/pipeline.inc @@ -5,6 +5,7 @@ #include #include "samplers.h" +#include #include "textures.h" namespace skyline::gpu::interconnect { @@ -23,7 +24,7 @@ namespace skyline::gpu::interconnect { vk::PipelineStageFlagBits dstStage, vk::PipelineStageFlags &srcStageMask, vk::PipelineStageFlags &dstStageMask) { if (!view) // Return a dummy buffer if the constant buffer isn't bound - return BufferBinding{ctx.gpu.megaBufferAllocator.Allocate(ctx.executor.cycle, PAGE_SIZE).buffer, 0, PAGE_SIZE}; + return BufferBinding{ctx.gpu.megaBufferAllocator.Allocate(ctx.executor.cycle, getpagesize()).buffer, 0, static_cast(getpagesize())}; ctx.executor.AttachBuffer(view); view.GetBuffer()->PopulateReadBarrier(dstStage, srcStageMask, dstStageMask); @@ -47,12 +48,12 @@ namespace skyline::gpu::interconnect { }; auto ssbo{cbuf.Read(ctx.executor, desc.cbuf_offset)}; if (ssbo.size == 0) - return BufferBinding{ctx.gpu.megaBufferAllocator.Allocate(ctx.executor.cycle, PAGE_SIZE).buffer, 0, PAGE_SIZE}; + return BufferBinding{ctx.gpu.megaBufferAllocator.Allocate(ctx.executor.cycle, getpagesize()).buffer, 0, static_cast(getpagesize())}; size_t padding{ssbo.address & (ctx.gpu.traits.minimumStorageBufferAlignment - 1)}; cachedView.Update(ctx, ssbo.address - padding, util::AlignUp(ssbo.size + padding, ctx.gpu.traits.minimumStorageBufferAlignment)); if (!cachedView.view) // Return a dummy buffer if the SSBO isn't bound - return BufferBinding{ctx.gpu.megaBufferAllocator.Allocate(ctx.executor.cycle, PAGE_SIZE).buffer, 0, PAGE_SIZE}; + return BufferBinding{ctx.gpu.megaBufferAllocator.Allocate(ctx.executor.cycle, getpagesize()).buffer, 0, static_cast(getpagesize())}; auto view{cachedView.view}; ctx.executor.AttachBuffer(view); diff --git a/app/src/main/cpp/skyline/gpu/interconnect/maxwell_3d/maxwell_3d.cpp b/app/src/main/cpp/skyline/gpu/interconnect/maxwell_3d/maxwell_3d.cpp index cf86fdfc..3dc6d038 100644 --- a/app/src/main/cpp/skyline/gpu/interconnect/maxwell_3d/maxwell_3d.cpp +++ b/app/src/main/cpp/skyline/gpu/interconnect/maxwell_3d/maxwell_3d.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include "common/utils.h" #include "maxwell_3d.h" #include "common.h" @@ -53,7 +54,7 @@ namespace skyline::gpu::interconnect::maxwell3d { vk::DeviceSize size{conversion::quads::GetRequiredBufferSize(count, sizeof(u32)) + offset}; if (!quadConversionBuffer || quadConversionBuffer->size_bytes() < size) { - quadConversionBuffer = std::make_shared(ctx.gpu.memory.AllocateBuffer(util::AlignUp(size, PAGE_SIZE))); + quadConversionBuffer = std::make_shared(ctx.gpu.memory.AllocateBuffer(util::AlignUp(size, getpagesize()))); conversion::quads::GenerateQuadListConversionBuffer(quadConversionBuffer->cast().data(), firstVertex + count); quadConversionBufferAttached = false; } diff --git a/app/src/main/cpp/skyline/gpu/megabuffer.cpp b/app/src/main/cpp/skyline/gpu/megabuffer.cpp index 8e04792a..fc3b93e0 100644 --- a/app/src/main/cpp/skyline/gpu/megabuffer.cpp +++ b/app/src/main/cpp/skyline/gpu/megabuffer.cpp @@ -1,69 +1,70 @@ -// SPDX-License-Identifier: MPL-2.0 -// Copyright © 2021 Skyline Team and Contributors (https://github.com/skyline-emu/) - -#include -#include "megabuffer.h" - -namespace skyline::gpu { - MegaBufferChunk::MegaBufferChunk(GPU &gpu) : backing{gpu.memory.AllocateBuffer(MegaBufferChunkSize)}, freeRegion{backing.subspan(PAGE_SIZE)} {} - - bool MegaBufferChunk::TryReset() { - if (cycle && cycle->Poll(true)) { - freeRegion = backing.subspan(PAGE_SIZE); - cycle = nullptr; - return true; - } - - return cycle == nullptr; - } - - vk::Buffer MegaBufferChunk::GetBacking() const { - return backing.vkBuffer; - } - - std::pair> MegaBufferChunk::Allocate(const std::shared_ptr &newCycle, vk::DeviceSize size, bool pageAlign) { - if (pageAlign) { - // If page aligned data was requested then align the free - auto alignedFreeBase{util::AlignUp(static_cast(freeRegion.data() - backing.data()), PAGE_SIZE)}; - freeRegion = backing.subspan(alignedFreeBase); - } - - if (size > freeRegion.size()) - return {0, {}}; - - if (cycle != newCycle) { - newCycle->ChainCycle(cycle); - cycle = newCycle; - } - - // Allocate space for data from the free region - auto resultSpan{freeRegion.subspan(0, size)}; - - // Move the free region along - freeRegion = freeRegion.subspan(size); - - return {static_cast(resultSpan.data() - backing.data()), resultSpan}; - } - - MegaBufferAllocator::MegaBufferAllocator(GPU &gpu) : gpu{gpu}, activeChunk{chunks.emplace(chunks.end(), gpu)} {} - - MegaBufferAllocator::Allocation MegaBufferAllocator::Allocate(const std::shared_ptr &cycle, vk::DeviceSize size, bool pageAlign) { - if (auto allocation{activeChunk->Allocate(cycle, size, pageAlign)}; allocation.first) - return {activeChunk->GetBacking(), allocation.first, allocation.second}; - - activeChunk = ranges::find_if(chunks, [&](auto &chunk) { return chunk.TryReset(); }); - if (activeChunk == chunks.end()) // If there are no chunks available, allocate a new one - activeChunk = chunks.emplace(chunks.end(), gpu); - - if (auto allocation{activeChunk->Allocate(cycle, size, pageAlign)}; allocation.first) - return {activeChunk->GetBacking(), allocation.first, allocation.second}; - else - throw exception("Failed to to allocate megabuffer space for size: 0x{:X}", size); - } - - MegaBufferAllocator::Allocation MegaBufferAllocator::Push(const std::shared_ptr &cycle, span data, bool pageAlign) { - auto allocation{Allocate(cycle, data.size(), pageAlign)}; - allocation.region.copy_from(data); - return allocation; - } -} +// SPDX-License-Identifier: MPL-2.0 +// Copyright © 2021 Skyline Team and Contributors (https://github.com/skyline-emu/) + +#include +#include +#include "megabuffer.h" + +namespace skyline::gpu { + MegaBufferChunk::MegaBufferChunk(GPU &gpu) : backing{gpu.memory.AllocateBuffer(MegaBufferChunkSize)}, freeRegion{backing.subspan(getpagesize())} {} + + bool MegaBufferChunk::TryReset() { + if (cycle && cycle->Poll(true)) { + freeRegion = backing.subspan(getpagesize()); + cycle = nullptr; + return true; + } + + return cycle == nullptr; + } + + vk::Buffer MegaBufferChunk::GetBacking() const { + return backing.vkBuffer; + } + + std::pair> MegaBufferChunk::Allocate(const std::shared_ptr &newCycle, vk::DeviceSize size, bool pageAlign) { + if (pageAlign) { + // If page aligned data was requested then align the free + auto alignedFreeBase{util::AlignUp(static_cast(freeRegion.data() - backing.data()), getpagesize())}; + freeRegion = backing.subspan(alignedFreeBase); + } + + if (size > freeRegion.size()) + return {0, {}}; + + if (cycle != newCycle) { + newCycle->ChainCycle(cycle); + cycle = newCycle; + } + + // Allocate space for data from the free region + auto resultSpan{freeRegion.subspan(0, size)}; + + // Move the free region along + freeRegion = freeRegion.subspan(size); + + return {static_cast(resultSpan.data() - backing.data()), resultSpan}; + } + + MegaBufferAllocator::MegaBufferAllocator(GPU &gpu) : gpu{gpu}, activeChunk{chunks.emplace(chunks.end(), gpu)} {} + + MegaBufferAllocator::Allocation MegaBufferAllocator::Allocate(const std::shared_ptr &cycle, vk::DeviceSize size, bool pageAlign) { + if (auto allocation{activeChunk->Allocate(cycle, size, pageAlign)}; allocation.first) + return {activeChunk->GetBacking(), allocation.first, allocation.second}; + + activeChunk = ranges::find_if(chunks, [&](auto &chunk) { return chunk.TryReset(); }); + if (activeChunk == chunks.end()) // If there are no chunks available, allocate a new one + activeChunk = chunks.emplace(chunks.end(), gpu); + + if (auto allocation{activeChunk->Allocate(cycle, size, pageAlign)}; allocation.first) + return {activeChunk->GetBacking(), allocation.first, allocation.second}; + else + throw exception("Failed to to allocate megabuffer space for size: 0x{:X}", size); + } + + MegaBufferAllocator::Allocation MegaBufferAllocator::Push(const std::shared_ptr &cycle, span data, bool pageAlign) { + auto allocation{Allocate(cycle, data.size(), pageAlign)}; + allocation.region.copy_from(data); + return allocation; + } +} diff --git a/app/src/main/cpp/skyline/gpu/presentation_engine.cpp b/app/src/main/cpp/skyline/gpu/presentation_engine.cpp index 80910fbc..e8a01d11 100644 --- a/app/src/main/cpp/skyline/gpu/presentation_engine.cpp +++ b/app/src/main/cpp/skyline/gpu/presentation_engine.cpp @@ -78,11 +78,14 @@ namespace skyline::gpu { try { choreographerLooper = ALooper_prepare(0); AChoreographer_postFrameCallback64(AChoreographer_getInstance(), reinterpret_cast(&ChoreographerCallback), this); - while (ALooper_pollAll(-1, nullptr, nullptr, nullptr) == ALOOPER_POLL_WAKE && !choreographerStop) { + + + while (ALooper_pollOnce(-1, nullptr, nullptr, nullptr) == ALOOPER_POLL_WAKE && !choreographerStop) { while (paused.load(std::memory_order_acquire)) { std::this_thread::sleep_for(std::chrono::milliseconds(10)); } } + } catch (const signal::SignalException &e) { LOGE("{}\nStack Trace:{}", e.what(), state.loader->GetStackTrace(e.frames)); if (state.process) diff --git a/app/src/main/cpp/skyline/kernel/types/KProcess.h b/app/src/main/cpp/skyline/kernel/types/KProcess.h index 4d6b11af..0d2d9c5e 100644 --- a/app/src/main/cpp/skyline/kernel/types/KProcess.h +++ b/app/src/main/cpp/skyline/kernel/types/KProcess.h @@ -12,8 +12,7 @@ namespace skyline { namespace constant { - constexpr u16 TlsSlotSize{0x200}; //!< The size of a single TLS slot - constexpr u8 TlsSlots{constant::PageSize / TlsSlotSize}; //!< The amount of TLS slots in a single page + const u8 TlsSlots{constant::getTlsSlots()}; //!< The amount of TLS slots in a single page constexpr KHandle BaseHandleIndex{0xD000}; //!< The index of the base handle } diff --git a/app/src/main/cpp/skyline/loader/loader.cpp b/app/src/main/cpp/skyline/loader/loader.cpp index 4c21fcb3..2c320e28 100644 --- a/app/src/main/cpp/skyline/loader/loader.cpp +++ b/app/src/main/cpp/skyline/loader/loader.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include "loader.h" namespace skyline::loader { @@ -45,7 +46,7 @@ namespace skyline::loader { size_t hookSize{0}; if (enableSymbolHooking && dynamicallyLinked) { executableSymbols = hle::GetExecutableSymbols(dynsym.cast(), dynstr); - hookSize = util::AlignUp(state.nce->GetHookSectionSize(executableSymbols), PAGE_SIZE); + hookSize = util::AlignUp(state.nce->GetHookSectionSize(executableSymbols), getpagesize()); } // Reserve patch + hook size only if we need to patch