Browse Source

Some memory corrections

temporary-branch
CamilleLaVey 2 days ago
parent
commit
6346371725
  1. 86
      src/common/host_memory.cpp
  2. 2
      src/common/host_memory.h
  3. 6
      src/core/core.cpp
  4. 2
      src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
  5. 34
      src/video_core/vulkan_common/vulkan_device.cpp
  6. 3
      src/video_core/vulkan_common/vulkan_device.h
  7. 9
      src/video_core/vulkan_common/vulkan_memory_allocator.cpp

86
src/common/host_memory.cpp

@ -51,6 +51,7 @@
#endif // ^^^ POSIX ^^^
#include <atomic>
#include <mutex>
#include <random>
#include <vector>
@ -60,6 +61,7 @@
#include "common/free_region_manager.h"
#include "common/host_memory.h"
#include "common/logging.h"
#include "common/memory_detect.h"
#include "common/settings.h"
#ifdef __ANDROID__
@ -104,6 +106,12 @@ namespace Common {
[[maybe_unused]] constexpr size_t PageAlignment = 0x1000;
[[maybe_unused]] constexpr size_t HugePageSize = 0x200000;
static std::atomic<u64> committed_backing_size{};
u64 GetCommittedBackingSize() noexcept {
return committed_backing_size.load(std::memory_order_relaxed);
}
#ifdef _WIN32
// Manually imported for MinGW compatibility
@ -605,6 +613,54 @@ public:
}
#ifdef __ANDROID__
static bool ProbeAhbBacking(PFN_AHardwareBuffer_getNativeHandle get_native_handle) {
const AHardwareBuffer_Desc desc{
.width = static_cast<u32>(PageAlignment * 2),
.height = 1,
.layers = 1,
.format = AHARDWAREBUFFER_FORMAT_BLOB,
.usage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN |
AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN |
AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER,
.stride = 0,
.rfu0 = 0,
.rfu1 = 0,
};
AHardwareBuffer* buffer{};
if (AHardwareBuffer_allocate(&desc, &buffer) != 0 || buffer == nullptr) {
LOG_WARNING(HW_Memory, "Hardware buffer probe allocation failed");
return false;
}
const NativeHandle* const handle = get_native_handle(buffer);
if (handle == nullptr || handle->numFds < 1) {
LOG_WARNING(HW_Memory, "Hardware buffer has no mappable file descriptor");
AHardwareBuffer_release(buffer);
return false;
}
const int probe_fd = handle->data[0];
bool ok = true;
const auto try_map = [&](int prot, off_t offset, const char* what) {
if (!ok) {
return;
}
void* const ptr = mmap(nullptr, PageAlignment, prot, MAP_SHARED, probe_fd, offset);
if (ptr == MAP_FAILED) {
LOG_WARNING(HW_Memory, "Hardware buffer backing rejects {}: {}", what,
strerror(errno));
ok = false;
return;
}
munmap(ptr, PageAlignment);
};
try_map(PROT_READ | PROT_WRITE, 0, "shared mappings");
try_map(PROT_READ | PROT_WRITE, static_cast<off_t>(PageAlignment), "mappings at an offset");
#ifdef ARCHITECTURE_arm64
try_map(PROT_READ | PROT_EXEC, 0, "executable mappings");
#endif
AHardwareBuffer_release(buffer);
return ok;
}
bool InitAhbBacking() {
if (!Settings::values.use_unified_memory.GetValue()) {
return false;
@ -615,6 +671,17 @@ public:
LOG_WARNING(HW_Memory, "AHardwareBuffer_getNativeHandle is not available");
return false;
}
const u64 total_physical = Common::GetMemInfo().TotalPhysicalMemory;
if (total_physical != 0 && backing_size > total_physical / 2) {
LOG_WARNING(HW_Memory,
"Hardware buffer backing would commit {} MiB on a {} MiB system, keeping "
"lazily committed memory",
backing_size >> 20, total_physical >> 20);
return false;
}
if (!ProbeAhbBacking(get_native_handle)) {
return false;
}
constexpr size_t window_size = 1ULL << 30;
const size_t num_windows = (backing_size + window_size - 1) / window_size;
std::vector<AHardwareBuffer*> buffers;
@ -678,23 +745,14 @@ public:
return false;
}
}
void* const exec_probe =
mmap(nullptr, PageAlignment, PROT_READ | PROT_EXEC, MAP_SHARED, buffer_fds[0], 0);
if (exec_probe == MAP_FAILED) {
LOG_WARNING(HW_Memory, "Hardware buffer backing rejects executable mappings: {}",
strerror(errno));
munmap(base, backing_size);
cleanup();
return false;
}
munmap(exec_probe, PageAlignment);
backing_base = base;
ahb_windows = std::move(buffers);
ahb_fds = std::move(buffer_fds);
ahb_window_size = window_size;
ahb_backing = true;
LOG_INFO(HW_Memory, "Guest memory backed by {} hardware buffer windows",
ahb_windows.size());
committed_backing_size.store(backing_size, std::memory_order_relaxed);
LOG_INFO(HW_Memory, "Guest memory backed by {} hardware buffer windows, {} MiB committed",
ahb_windows.size(), backing_size >> 20);
return true;
}
@ -823,6 +881,10 @@ private:
}
ahb_windows.clear();
ahb_fds.clear();
if (ahb_backing) {
committed_backing_size.store(0, std::memory_order_relaxed);
ahb_backing = false;
}
#endif
}

2
src/common/host_memory.h

@ -17,6 +17,8 @@ struct AHardwareBuffer;
namespace Common {
[[nodiscard]] u64 GetCommittedBackingSize() noexcept;
enum class MemoryPermission : u32 {
Read = 1 << 0,
Write = 1 << 1,

6
src/core/core.cpp

@ -118,6 +118,7 @@ struct System::Impl {
is_multicore = Settings::values.use_multi_core.GetValue();
extended_memory_layout = Settings::values.memory_layout_mode.GetValue() != Settings::MemoryLayout::Memory_4Gb;
unified_memory = Settings::values.use_unified_memory.GetValue();
core_timing.SetMulticore(is_multicore);
core_timing.Initialize([&system]() { system.RegisterHostThread(); });
@ -145,7 +146,8 @@ struct System::Impl {
!device_memory.has_value() ||
is_multicore != Settings::values.use_multi_core.GetValue() ||
extended_memory_layout != (Settings::values.memory_layout_mode.GetValue() !=
Settings::MemoryLayout::Memory_4Gb);
Settings::MemoryLayout::Memory_4Gb) ||
unified_memory != Settings::values.use_unified_memory.GetValue();
if (!must_reinitialize) {
return;
@ -156,6 +158,7 @@ struct System::Impl {
is_multicore = Settings::values.use_multi_core.GetValue();
extended_memory_layout =
Settings::values.memory_layout_mode.GetValue() != Settings::MemoryLayout::Memory_4Gb;
unified_memory = Settings::values.use_unified_memory.GetValue();
Initialize(system);
}
@ -503,6 +506,7 @@ struct System::Impl {
std::atomic_bool is_powered_on{};
bool is_multicore : 1 = false;
bool extended_memory_layout : 1 = false;
bool unified_memory : 1 = false;
bool exit_locked : 1 = false;
bool exit_requested : 1 = false;
bool nvdec_active : 1 = false;

2
src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp

@ -293,7 +293,7 @@ GraphicsPipeline::GraphicsPipeline(
key.Hash(), descriptor_buffer_layout.size);
uses_descriptor_buffer = false;
descriptor_buffer_layout = {};
descriptor_set_layout = builder.CreateDescriptorSetLayout(false);
descriptor_set_layout = builder.CreateDescriptorSetLayout(uses_push_descriptor);
}
}

34
src/video_core/vulkan_common/vulkan_device.cpp

@ -21,6 +21,7 @@
#include "common/assert.h"
#include "common/fs/fs.h"
#include "common/fs/path_util.h"
#include "common/host_memory.h"
#include "common/literals.h"
#include <ranges>
#include "common/settings.h"
@ -1088,6 +1089,17 @@ bool Device::GetSuitability(bool requires_swapchain) {
extensions.robustness_2 = false;
}
#ifdef __ANDROID__
if (extensions.external_memory_ahb && !extensions.queue_family_foreign) {
LOG_INFO(Render_Vulkan,
"Not loading {} because its dependency {} is unavailable",
VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME,
VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME);
loaded_extensions.erase(VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME);
extensions.external_memory_ahb = false;
}
#endif
#undef FEATURE_EXTENSION
#undef EXTENSION
@ -1669,12 +1681,27 @@ void Device::CollectPhysicalMemoryInfo() {
device_access_memory = 0;
u64 device_initial_usage = 0;
u64 local_memory = 0;
const auto heap_has_usable_type = [&mem_properties](size_t heap) {
for (u32 index = 0; index < mem_properties.memoryTypeCount; ++index) {
if (mem_properties.memoryTypes[index].heapIndex != heap) {
continue;
}
if ((mem_properties.memoryTypes[index].propertyFlags &
VK_MEMORY_PROPERTY_PROTECTED_BIT) == 0) {
return true;
}
}
return false;
};
for (size_t element = 0; element < num_properties; ++element) {
const bool is_heap_local =
(mem_properties.memoryHeaps[element].flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) != 0;
if (!is_integrated && !is_heap_local) {
continue;
}
if (!heap_has_usable_type(element)) {
continue;
}
valid_heap_memory.push_back(element);
if (is_heap_local) {
local_memory += mem_properties.memoryHeaps[element].size;
@ -1686,6 +1713,13 @@ void Device::CollectPhysicalMemoryInfo() {
}
device_access_memory += mem_properties.memoryHeaps[element].size;
}
const u64 committed_backing = Common::GetCommittedBackingSize();
if (committed_backing != 0) {
LOG_INFO(Render_Vulkan, "Discounting {} MiB of guest memory committed by the host",
committed_backing >> 20);
local_memory -= std::min(local_memory, committed_backing);
device_access_memory -= std::min(device_access_memory, committed_backing);
}
if (is_integrated) {
const bool aggressive =
Settings::values.vram_usage_mode.GetValue() == Settings::VramUsageMode::Aggressive;

3
src/video_core/vulkan_common/vulkan_device.h

@ -120,6 +120,7 @@ VK_DEFINE_HANDLE(VmaAllocator)
#ifdef __ANDROID__
#define FOR_EACH_VK_PLATFORM_EXTENSION(EXTENSION) \
EXTENSION(EXT, QUEUE_FAMILY_FOREIGN, queue_family_foreign) \
EXTENSION(ANDROID, EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER, external_memory_ahb)
#else
#define FOR_EACH_VK_PLATFORM_EXTENSION(EXTENSION)
@ -914,7 +915,7 @@ FN_MAX_LIMIT_LIST
bool IsExtExternalMemoryAhbSupported() const {
#ifdef __ANDROID__
return extensions.external_memory_ahb;
return extensions.external_memory_ahb && extensions.queue_family_foreign;
#else
return false;
#endif

9
src/video_core/vulkan_common/vulkan_memory_allocator.cpp

@ -180,6 +180,15 @@ namespace Vulkan {
logical.DestroyBufferRaw(new_buffer);
break;
}
const u32 heap_index = memory_props.memoryTypes[*type_index].heapIndex;
const VkDeviceSize heap_size = memory_props.memoryHeaps[heap_index].size;
if (imported_size + window_len > heap_size / 2) {
LOG_INFO(Render_Vulkan,
"Stopping guest memory import at {} MiB to leave room on heap {} of {} MiB",
imported_size >> 20, heap_index, heap_size >> 20);
logical.DestroyBufferRaw(new_buffer);
break;
}
const VkImportMemoryHostPointerInfoEXT import_info{
.sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_HOST_POINTER_INFO_EXT,
.pNext = nullptr,

Loading…
Cancel
Save