diff options
-rw-r--r-- | src/core/hle/kernel/kernel.cpp | 41 | ||||
-rw-r--r-- | src/core/hle/kernel/process.cpp | 24 | ||||
-rw-r--r-- | src/video_core/engines/engine_interface.h | 3 | ||||
-rw-r--r-- | src/video_core/engines/fermi_2d.h | 2 | ||||
-rw-r--r-- | src/video_core/engines/kepler_memory.h | 2 | ||||
-rw-r--r-- | src/video_core/engines/maxwell_dma.h | 2 | ||||
-rw-r--r-- | src/video_core/renderer_vulkan/vk_master_semaphore.h | 4 | ||||
-rw-r--r-- | src/video_core/renderer_vulkan/vk_texture_cache.cpp | 11 | ||||
-rw-r--r-- | src/video_core/texture_cache/util.cpp | 21 | ||||
-rw-r--r-- | src/video_core/texture_cache/util.h | 5 |
10 files changed, 55 insertions, 60 deletions
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 8fd990577..f7d3f218a 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -67,8 +67,13 @@ struct KernelCore::Impl { is_phantom_mode_for_singlecore = false; InitializePhysicalCores(); - InitializeSystemResourceLimit(kernel, system); - InitializeMemoryLayout(); + + // Derive the initial memory layout from the emulated board + KMemoryLayout memory_layout; + DeriveInitialMemoryLayout(memory_layout); + InitializeMemoryLayout(memory_layout); + InitializeSystemResourceLimit(kernel, system, memory_layout); + InitializeSlabHeaps(); InitializeSchedulers(); InitializeSuspendThreads(); InitializePreemption(kernel); @@ -137,27 +142,32 @@ struct KernelCore::Impl { } // Creates the default system resource limit - void InitializeSystemResourceLimit(KernelCore& kernel, Core::System& system) { + void InitializeSystemResourceLimit(KernelCore& kernel, Core::System& system, + const KMemoryLayout& memory_layout) { system_resource_limit = std::make_shared<KResourceLimit>(kernel, system); + const auto [total_size, kernel_size] = memory_layout.GetTotalAndKernelMemorySizes(); // If setting the default system values fails, then something seriously wrong has occurred. - ASSERT(system_resource_limit->SetLimitValue(LimitableResource::PhysicalMemory, 0x100000000) + ASSERT(system_resource_limit->SetLimitValue(LimitableResource::PhysicalMemory, total_size) .IsSuccess()); ASSERT(system_resource_limit->SetLimitValue(LimitableResource::Threads, 800).IsSuccess()); ASSERT(system_resource_limit->SetLimitValue(LimitableResource::Events, 900).IsSuccess()); ASSERT(system_resource_limit->SetLimitValue(LimitableResource::TransferMemory, 200) .IsSuccess()); ASSERT(system_resource_limit->SetLimitValue(LimitableResource::Sessions, 1133).IsSuccess()); + system_resource_limit->Reserve(LimitableResource::PhysicalMemory, kernel_size); - // Derived from recent software updates. The kernel reserves 27MB - constexpr u64 kernel_size{0x1b00000}; - if (!system_resource_limit->Reserve(LimitableResource::PhysicalMemory, kernel_size)) { - UNREACHABLE(); - } // Reserve secure applet memory, introduced in firmware 5.0.0 - constexpr u64 secure_applet_memory_size{0x400000}; + constexpr u64 secure_applet_memory_size{Common::Size_4_MB}; ASSERT(system_resource_limit->Reserve(LimitableResource::PhysicalMemory, secure_applet_memory_size)); + + // This memory seems to be reserved on hardware, but is not reserved/used by yuzu. + // Likely Horizon OS reserved memory + // TODO(ameerj): Derive the memory rather than hardcode it. + constexpr u64 unknown_reserved_memory{0x2f896000}; + ASSERT(system_resource_limit->Reserve(LimitableResource::PhysicalMemory, + unknown_reserved_memory)); } void InitializePreemption(KernelCore& kernel) { @@ -531,11 +541,7 @@ struct KernelCore::Impl { linear_region_start); } - void InitializeMemoryLayout() { - // Derive the initial memory layout from the emulated board - KMemoryLayout memory_layout; - DeriveInitialMemoryLayout(memory_layout); - + void InitializeMemoryLayout(const KMemoryLayout& memory_layout) { const auto system_pool = memory_layout.GetKernelSystemPoolRegionPhysicalExtents(); const auto applet_pool = memory_layout.GetKernelAppletPoolRegionPhysicalExtents(); const auto application_pool = memory_layout.GetKernelApplicationPoolRegionPhysicalExtents(); @@ -578,11 +584,14 @@ struct KernelCore::Impl { system.Kernel(), system.DeviceMemory(), nullptr, {time_phys_addr, time_size / PageSize}, KMemoryPermission::None, KMemoryPermission::Read, time_phys_addr, time_size, "Time:SharedMemory"); + } + void InitializeSlabHeaps() { // Allocate slab heaps user_slab_heap_pages = std::make_unique<KSlabHeap<Page>>(); - constexpr u64 user_slab_heap_size{0x1ef000}; + // TODO(ameerj): This should be derived, not hardcoded within the kernel + constexpr u64 user_slab_heap_size{0x3de000}; // Reserve slab heaps ASSERT( system_resource_limit->Reserve(LimitableResource::PhysicalMemory, user_slab_heap_size)); diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index 9d5956ead..dd01f3924 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp @@ -120,9 +120,7 @@ std::shared_ptr<Process> Process::Create(Core::System& system, std::string name, std::shared_ptr<Process> process = std::make_shared<Process>(system); process->name = std::move(name); - // TODO: This is inaccurate - // The process should hold a reference to the kernel-wide resource limit. - process->resource_limit = std::make_shared<KResourceLimit>(kernel, system); + process->resource_limit = kernel.GetSystemResourceLimit(); process->status = ProcessStatus::Created; process->program_id = 0; process->process_id = type == ProcessType::KernelInternal ? kernel.CreateNewKernelProcessID() @@ -160,17 +158,13 @@ void Process::DecrementThreadCount() { } u64 Process::GetTotalPhysicalMemoryAvailable() const { - // TODO: This is expected to always return the application memory pool size after accurately - // reserving kernel resources. The current workaround uses a process-local resource limit of - // application memory pool size, which is inaccurate. const u64 capacity{resource_limit->GetFreeValue(LimitableResource::PhysicalMemory) + page_table->GetTotalHeapSize() + GetSystemResourceSize() + image_size + main_thread_stack_size}; - + ASSERT(capacity == kernel.MemoryManager().GetSize(KMemoryManager::Pool::Application)); if (capacity < memory_usage_capacity) { return capacity; } - return memory_usage_capacity; } @@ -272,10 +266,6 @@ ResultCode Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, system_resource_size = metadata.GetSystemResourceSize(); image_size = code_size; - // Set initial resource limits - resource_limit->SetLimitValue( - LimitableResource::PhysicalMemory, - kernel.MemoryManager().GetSize(KMemoryManager::Pool::Application)); KScopedResourceReservation memory_reservation(resource_limit, LimitableResource::PhysicalMemory, code_size + system_resource_size); if (!memory_reservation.Succeeded()) { @@ -324,16 +314,6 @@ ResultCode Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, UNREACHABLE(); } - // Set initial resource limits - resource_limit->SetLimitValue( - LimitableResource::PhysicalMemory, - kernel.MemoryManager().GetSize(KMemoryManager::Pool::Application)); - - resource_limit->SetLimitValue(LimitableResource::Threads, 608); - resource_limit->SetLimitValue(LimitableResource::Events, 700); - resource_limit->SetLimitValue(LimitableResource::TransferMemory, 128); - resource_limit->SetLimitValue(LimitableResource::Sessions, 894); - // Create TLS region tls_region_address = CreateTLSRegion(); memory_reservation.Commit(); diff --git a/src/video_core/engines/engine_interface.h b/src/video_core/engines/engine_interface.h index 18a9db7e6..c7ffd68c5 100644 --- a/src/video_core/engines/engine_interface.h +++ b/src/video_core/engines/engine_interface.h @@ -4,13 +4,14 @@ #pragma once -#include <type_traits> #include "common/common_types.h" namespace Tegra::Engines { class EngineInterface { public: + virtual ~EngineInterface() = default; + /// Write the value to the register identified by method. virtual void CallMethod(u32 method, u32 method_argument, bool is_last_call) = 0; diff --git a/src/video_core/engines/fermi_2d.h b/src/video_core/engines/fermi_2d.h index c808a577d..a4170ffff 100644 --- a/src/video_core/engines/fermi_2d.h +++ b/src/video_core/engines/fermi_2d.h @@ -35,7 +35,7 @@ namespace Tegra::Engines { class Fermi2D final : public EngineInterface { public: explicit Fermi2D(); - ~Fermi2D(); + ~Fermi2D() override; /// Binds a rasterizer to this engine. void BindRasterizer(VideoCore::RasterizerInterface* rasterizer); diff --git a/src/video_core/engines/kepler_memory.h b/src/video_core/engines/kepler_memory.h index 19808a5c6..0d8ea09a9 100644 --- a/src/video_core/engines/kepler_memory.h +++ b/src/video_core/engines/kepler_memory.h @@ -36,7 +36,7 @@ namespace Tegra::Engines { class KeplerMemory final : public EngineInterface { public: explicit KeplerMemory(Core::System& system_, MemoryManager& memory_manager); - ~KeplerMemory(); + ~KeplerMemory() override; /// Write the value to the register identified by method. void CallMethod(u32 method, u32 method_argument, bool is_last_call) override; diff --git a/src/video_core/engines/maxwell_dma.h b/src/video_core/engines/maxwell_dma.h index 3c59eeb13..c77f02a22 100644 --- a/src/video_core/engines/maxwell_dma.h +++ b/src/video_core/engines/maxwell_dma.h @@ -188,7 +188,7 @@ public: static_assert(sizeof(RemapConst) == 12); explicit MaxwellDMA(Core::System& system_, MemoryManager& memory_manager_); - ~MaxwellDMA(); + ~MaxwellDMA() override; /// Write the value to the register identified by method. void CallMethod(u32 method, u32 method_argument, bool is_last_call) override; diff --git a/src/video_core/renderer_vulkan/vk_master_semaphore.h b/src/video_core/renderer_vulkan/vk_master_semaphore.h index 2c7ed654d..4b6d64daa 100644 --- a/src/video_core/renderer_vulkan/vk_master_semaphore.h +++ b/src/video_core/renderer_vulkan/vk_master_semaphore.h @@ -35,8 +35,8 @@ public: } /// Returns true when a tick has been hit by the GPU. - [[nodiscard]] bool IsFree(u64 tick) { - return gpu_tick.load(std::memory_order_relaxed) >= tick; + [[nodiscard]] bool IsFree(u64 tick) const noexcept { + return KnownGpuTick() >= tick; } /// Advance to the logical tick. diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp index 18155e449..bc2a53841 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp @@ -7,6 +7,8 @@ #include <span> #include <vector> +#include "common/bit_cast.h" + #include "video_core/engines/fermi_2d.h" #include "video_core/renderer_vulkan/blit_image.h" #include "video_core/renderer_vulkan/maxwell_to_vk.h" @@ -1062,14 +1064,13 @@ vk::ImageView ImageView::MakeDepthStencilView(VkImageAspectFlags aspect_mask) { Sampler::Sampler(TextureCacheRuntime& runtime, const Tegra::Texture::TSCEntry& tsc) { const auto& device = runtime.device; const bool arbitrary_borders = runtime.device.IsExtCustomBorderColorSupported(); - const std::array<float, 4> color = tsc.BorderColor(); - // C++20 bit_cast - VkClearColorValue border_color; - std::memcpy(&border_color, &color, sizeof(color)); + const auto color = tsc.BorderColor(); + const VkSamplerCustomBorderColorCreateInfoEXT border_ci{ .sType = VK_STRUCTURE_TYPE_SAMPLER_CUSTOM_BORDER_COLOR_CREATE_INFO_EXT, .pNext = nullptr, - .customBorderColor = border_color, + // TODO: Make use of std::bit_cast once libc++ supports it. + .customBorderColor = Common::BitCast<VkClearColorValue>(color), .format = VK_FORMAT_UNDEFINED, }; const void* pnext = nullptr; diff --git a/src/video_core/texture_cache/util.cpp b/src/video_core/texture_cache/util.cpp index c22dd0148..0ab297413 100644 --- a/src/video_core/texture_cache/util.cpp +++ b/src/video_core/texture_cache/util.cpp @@ -268,16 +268,19 @@ template <u32 GOB_EXTENT> return num_tiles << shift; } -[[nodiscard]] constexpr std::array<u32, MAX_MIP_LEVELS> CalculateLevelSizes(const LevelInfo& info, - u32 num_levels) { +[[nodiscard]] constexpr LevelArray CalculateLevelSizes(const LevelInfo& info, u32 num_levels) { ASSERT(num_levels <= MAX_MIP_LEVELS); - std::array<u32, MAX_MIP_LEVELS> sizes{}; + LevelArray sizes{}; for (u32 level = 0; level < num_levels; ++level) { sizes[level] = CalculateLevelSize(info, level); } return sizes; } +[[nodiscard]] u32 CalculateLevelBytes(const LevelArray& sizes, u32 num_levels) { + return std::reduce(sizes.begin(), sizes.begin() + num_levels, 0U); +} + [[nodiscard]] constexpr LevelInfo MakeLevelInfo(PixelFormat format, Extent3D size, Extent3D block, u32 num_samples, u32 tile_width_spacing) { const auto [samples_x, samples_y] = Samples(num_samples); @@ -566,10 +569,10 @@ void SwizzleBlockLinearImage(Tegra::MemoryManager& gpu_memory, GPUVAddr gpu_addr const u32 num_levels = info.resources.levels; const std::array sizes = CalculateLevelSizes(level_info, num_levels); - size_t guest_offset = std::reduce(sizes.begin(), sizes.begin() + level, 0); + size_t guest_offset = CalculateLevelBytes(sizes, level); const size_t layer_stride = - AlignLayerSize(std::reduce(sizes.begin(), sizes.begin() + num_levels, 0), size, - level_info.block, tile_size.height, info.tile_width_spacing); + AlignLayerSize(CalculateLevelBytes(sizes, num_levels), size, level_info.block, + tile_size.height, info.tile_width_spacing); const size_t subresource_size = sizes[level]; const auto dst_data = std::make_unique<u8[]>(subresource_size); @@ -643,10 +646,10 @@ u32 CalculateLayerSize(const ImageInfo& info) noexcept { info.tile_width_spacing, info.resources.levels); } -std::array<u32, MAX_MIP_LEVELS> CalculateMipLevelOffsets(const ImageInfo& info) noexcept { +LevelArray CalculateMipLevelOffsets(const ImageInfo& info) noexcept { ASSERT(info.resources.levels <= static_cast<s32>(MAX_MIP_LEVELS)); const LevelInfo level_info = MakeLevelInfo(info); - std::array<u32, MAX_MIP_LEVELS> offsets{}; + LevelArray offsets{}; u32 offset = 0; for (s32 level = 0; level < info.resources.levels; ++level) { offsets[level] = offset; @@ -812,7 +815,7 @@ std::vector<BufferImageCopy> UnswizzleImage(Tegra::MemoryManager& gpu_memory, GP const Extent2D tile_size = DefaultBlockSize(info.format); const std::array level_sizes = CalculateLevelSizes(level_info, num_levels); const Extent2D gob = GobSize(bpp_log2, info.block.height, info.tile_width_spacing); - const u32 layer_size = std::reduce(level_sizes.begin(), level_sizes.begin() + num_levels, 0); + const u32 layer_size = CalculateLevelBytes(level_sizes, num_levels); const u32 layer_stride = AlignLayerSize(layer_size, size, level_info.block, tile_size.height, info.tile_width_spacing); size_t guest_offset = 0; diff --git a/src/video_core/texture_cache/util.h b/src/video_core/texture_cache/util.h index 4d0072867..cdc5cbc75 100644 --- a/src/video_core/texture_cache/util.h +++ b/src/video_core/texture_cache/util.h @@ -20,6 +20,8 @@ namespace VideoCommon { using Tegra::Texture::TICEntry; +using LevelArray = std::array<u32, MAX_MIP_LEVELS>; + struct OverlapResult { GPUVAddr gpu_addr; VAddr cpu_addr; @@ -36,8 +38,7 @@ struct OverlapResult { [[nodiscard]] u32 CalculateLayerSize(const ImageInfo& info) noexcept; -[[nodiscard]] std::array<u32, MAX_MIP_LEVELS> CalculateMipLevelOffsets( - const ImageInfo& info) noexcept; +[[nodiscard]] LevelArray CalculateMipLevelOffsets(const ImageInfo& info) noexcept; [[nodiscard]] std::vector<u32> CalculateSliceOffsets(const ImageInfo& info); |