mirror of
				https://git.zaroz.cloud/nintendo-back-up/yuzu/yuzu-mainline.git
				synced 2025-03-21 01:53:15 +00:00 
			
		
		
		
	memory_manager: Do not MapBufferEx over already in use memory.
- This fixes rendering when changing areas in Super Mario Odyssey.
This commit is contained in:
		
							parent
							
								
									cc1fe93297
								
							
						
					
					
						commit
						4aa9779ae1
					
				@ -4,18 +4,21 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include "common/alignment.h"
 | 
					#include "common/alignment.h"
 | 
				
			||||||
#include "common/assert.h"
 | 
					#include "common/assert.h"
 | 
				
			||||||
 | 
					#include "common/logging/log.h"
 | 
				
			||||||
#include "video_core/memory_manager.h"
 | 
					#include "video_core/memory_manager.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace Tegra {
 | 
					namespace Tegra {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
GPUVAddr MemoryManager::AllocateSpace(u64 size, u64 align) {
 | 
					GPUVAddr MemoryManager::AllocateSpace(u64 size, u64 align) {
 | 
				
			||||||
    std::optional<GPUVAddr> gpu_addr = FindFreeBlock(size, align);
 | 
					    const std::optional<GPUVAddr> gpu_addr{FindFreeBlock(0, size, align, PageStatus::Unmapped)};
 | 
				
			||||||
    ASSERT(gpu_addr);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for (u64 offset = 0; offset < size; offset += PAGE_SIZE) {
 | 
					    ASSERT_MSG(gpu_addr, "unable to find available GPU memory");
 | 
				
			||||||
        VAddr& slot = PageSlot(*gpu_addr + offset);
 | 
					
 | 
				
			||||||
 | 
					    for (u64 offset{}; offset < size; offset += PAGE_SIZE) {
 | 
				
			||||||
 | 
					        VAddr& slot{PageSlot(*gpu_addr + offset)};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        ASSERT(slot == static_cast<u64>(PageStatus::Unmapped));
 | 
					        ASSERT(slot == static_cast<u64>(PageStatus::Unmapped));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        slot = static_cast<u64>(PageStatus::Allocated);
 | 
					        slot = static_cast<u64>(PageStatus::Allocated);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -23,10 +26,11 @@ GPUVAddr MemoryManager::AllocateSpace(u64 size, u64 align) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
GPUVAddr MemoryManager::AllocateSpace(GPUVAddr gpu_addr, u64 size, u64 align) {
 | 
					GPUVAddr MemoryManager::AllocateSpace(GPUVAddr gpu_addr, u64 size, u64 align) {
 | 
				
			||||||
    for (u64 offset = 0; offset < size; offset += PAGE_SIZE) {
 | 
					    for (u64 offset{}; offset < size; offset += PAGE_SIZE) {
 | 
				
			||||||
        VAddr& slot = PageSlot(gpu_addr + offset);
 | 
					        VAddr& slot{PageSlot(gpu_addr + offset)};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        ASSERT(slot == static_cast<u64>(PageStatus::Unmapped));
 | 
					        ASSERT(slot == static_cast<u64>(PageStatus::Unmapped));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        slot = static_cast<u64>(PageStatus::Allocated);
 | 
					        slot = static_cast<u64>(PageStatus::Allocated);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -34,17 +38,19 @@ GPUVAddr MemoryManager::AllocateSpace(GPUVAddr gpu_addr, u64 size, u64 align) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
GPUVAddr MemoryManager::MapBufferEx(VAddr cpu_addr, u64 size) {
 | 
					GPUVAddr MemoryManager::MapBufferEx(VAddr cpu_addr, u64 size) {
 | 
				
			||||||
    std::optional<GPUVAddr> gpu_addr = FindFreeBlock(size, PAGE_SIZE);
 | 
					    const std::optional<GPUVAddr> gpu_addr{FindFreeBlock(0, size, PAGE_SIZE, PageStatus::Unmapped)};
 | 
				
			||||||
    ASSERT(gpu_addr);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for (u64 offset = 0; offset < size; offset += PAGE_SIZE) {
 | 
					    ASSERT_MSG(gpu_addr, "unable to find available GPU memory");
 | 
				
			||||||
        VAddr& slot = PageSlot(*gpu_addr + offset);
 | 
					
 | 
				
			||||||
 | 
					    for (u64 offset{}; offset < size; offset += PAGE_SIZE) {
 | 
				
			||||||
 | 
					        VAddr& slot{PageSlot(*gpu_addr + offset)};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        ASSERT(slot == static_cast<u64>(PageStatus::Unmapped));
 | 
					        ASSERT(slot == static_cast<u64>(PageStatus::Unmapped));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        slot = cpu_addr + offset;
 | 
					        slot = cpu_addr + offset;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    MappedRegion region{cpu_addr, *gpu_addr, size};
 | 
					    const MappedRegion region{cpu_addr, *gpu_addr, size};
 | 
				
			||||||
    mapped_regions.push_back(region);
 | 
					    mapped_regions.push_back(region);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return *gpu_addr;
 | 
					    return *gpu_addr;
 | 
				
			||||||
@ -53,14 +59,31 @@ GPUVAddr MemoryManager::MapBufferEx(VAddr cpu_addr, u64 size) {
 | 
				
			|||||||
GPUVAddr MemoryManager::MapBufferEx(VAddr cpu_addr, GPUVAddr gpu_addr, u64 size) {
 | 
					GPUVAddr MemoryManager::MapBufferEx(VAddr cpu_addr, GPUVAddr gpu_addr, u64 size) {
 | 
				
			||||||
    ASSERT((gpu_addr & PAGE_MASK) == 0);
 | 
					    ASSERT((gpu_addr & PAGE_MASK) == 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for (u64 offset = 0; offset < size; offset += PAGE_SIZE) {
 | 
					    if (PageSlot(gpu_addr) != static_cast<u64>(PageStatus::Allocated)) {
 | 
				
			||||||
        VAddr& slot = PageSlot(gpu_addr + offset);
 | 
					        // Page has been already mapped. In this case, we must find a new area of memory to use that
 | 
				
			||||||
 | 
					        // is different than the specified one. Super Mario Odyssey hits this scenario when changing
 | 
				
			||||||
 | 
					        // areas, but we do not want to overwrite the old pages.
 | 
				
			||||||
 | 
					        // TODO(bunnei): We need to write a hardware test to confirm this behavior.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        LOG_ERROR(HW_GPU, "attempting to map addr 0x{:016X}, which is not available!", gpu_addr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const std::optional<GPUVAddr> new_gpu_addr{
 | 
				
			||||||
 | 
					            FindFreeBlock(gpu_addr, size, PAGE_SIZE, PageStatus::Allocated)};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ASSERT_MSG(new_gpu_addr, "unable to find available GPU memory");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        gpu_addr = *new_gpu_addr;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (u64 offset{}; offset < size; offset += PAGE_SIZE) {
 | 
				
			||||||
 | 
					        VAddr& slot{PageSlot(gpu_addr + offset)};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        ASSERT(slot == static_cast<u64>(PageStatus::Allocated));
 | 
					        ASSERT(slot == static_cast<u64>(PageStatus::Allocated));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        slot = cpu_addr + offset;
 | 
					        slot = cpu_addr + offset;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    MappedRegion region{cpu_addr, gpu_addr, size};
 | 
					    const MappedRegion region{cpu_addr, gpu_addr, size};
 | 
				
			||||||
    mapped_regions.push_back(region);
 | 
					    mapped_regions.push_back(region);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return gpu_addr;
 | 
					    return gpu_addr;
 | 
				
			||||||
@ -69,11 +92,12 @@ GPUVAddr MemoryManager::MapBufferEx(VAddr cpu_addr, GPUVAddr gpu_addr, u64 size)
 | 
				
			|||||||
GPUVAddr MemoryManager::UnmapBuffer(GPUVAddr gpu_addr, u64 size) {
 | 
					GPUVAddr MemoryManager::UnmapBuffer(GPUVAddr gpu_addr, u64 size) {
 | 
				
			||||||
    ASSERT((gpu_addr & PAGE_MASK) == 0);
 | 
					    ASSERT((gpu_addr & PAGE_MASK) == 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for (u64 offset = 0; offset < size; offset += PAGE_SIZE) {
 | 
					    for (u64 offset{}; offset < size; offset += PAGE_SIZE) {
 | 
				
			||||||
        VAddr& slot = PageSlot(gpu_addr + offset);
 | 
					        VAddr& slot{PageSlot(gpu_addr + offset)};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        ASSERT(slot != static_cast<u64>(PageStatus::Allocated) &&
 | 
					        ASSERT(slot != static_cast<u64>(PageStatus::Allocated) &&
 | 
				
			||||||
               slot != static_cast<u64>(PageStatus::Unmapped));
 | 
					               slot != static_cast<u64>(PageStatus::Unmapped));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        slot = static_cast<u64>(PageStatus::Unmapped);
 | 
					        slot = static_cast<u64>(PageStatus::Unmapped);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -97,13 +121,14 @@ GPUVAddr MemoryManager::GetRegionEnd(GPUVAddr region_start) const {
 | 
				
			|||||||
    return {};
 | 
					    return {};
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
std::optional<GPUVAddr> MemoryManager::FindFreeBlock(u64 size, u64 align) {
 | 
					std::optional<GPUVAddr> MemoryManager::FindFreeBlock(GPUVAddr region_start, u64 size, u64 align,
 | 
				
			||||||
    GPUVAddr gpu_addr = 0;
 | 
					                                                     PageStatus status) {
 | 
				
			||||||
    u64 free_space = 0;
 | 
					    GPUVAddr gpu_addr{region_start};
 | 
				
			||||||
 | 
					    u64 free_space{};
 | 
				
			||||||
    align = (align + PAGE_MASK) & ~PAGE_MASK;
 | 
					    align = (align + PAGE_MASK) & ~PAGE_MASK;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    while (gpu_addr + free_space < MAX_ADDRESS) {
 | 
					    while (gpu_addr + free_space < MAX_ADDRESS) {
 | 
				
			||||||
        if (!IsPageMapped(gpu_addr + free_space)) {
 | 
					        if (PageSlot(gpu_addr + free_space) == static_cast<u64>(status)) {
 | 
				
			||||||
            free_space += PAGE_SIZE;
 | 
					            free_space += PAGE_SIZE;
 | 
				
			||||||
            if (free_space >= size) {
 | 
					            if (free_space >= size) {
 | 
				
			||||||
                return gpu_addr;
 | 
					                return gpu_addr;
 | 
				
			||||||
@ -119,7 +144,7 @@ std::optional<GPUVAddr> MemoryManager::FindFreeBlock(u64 size, u64 align) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
std::optional<VAddr> MemoryManager::GpuToCpuAddress(GPUVAddr gpu_addr) {
 | 
					std::optional<VAddr> MemoryManager::GpuToCpuAddress(GPUVAddr gpu_addr) {
 | 
				
			||||||
    VAddr base_addr = PageSlot(gpu_addr);
 | 
					    const VAddr base_addr{PageSlot(gpu_addr)};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (base_addr == static_cast<u64>(PageStatus::Allocated) ||
 | 
					    if (base_addr == static_cast<u64>(PageStatus::Allocated) ||
 | 
				
			||||||
        base_addr == static_cast<u64>(PageStatus::Unmapped)) {
 | 
					        base_addr == static_cast<u64>(PageStatus::Unmapped)) {
 | 
				
			||||||
@ -133,19 +158,15 @@ std::vector<GPUVAddr> MemoryManager::CpuToGpuAddress(VAddr cpu_addr) const {
 | 
				
			|||||||
    std::vector<GPUVAddr> results;
 | 
					    std::vector<GPUVAddr> results;
 | 
				
			||||||
    for (const auto& region : mapped_regions) {
 | 
					    for (const auto& region : mapped_regions) {
 | 
				
			||||||
        if (cpu_addr >= region.cpu_addr && cpu_addr < (region.cpu_addr + region.size)) {
 | 
					        if (cpu_addr >= region.cpu_addr && cpu_addr < (region.cpu_addr + region.size)) {
 | 
				
			||||||
            u64 offset = cpu_addr - region.cpu_addr;
 | 
					            const u64 offset{cpu_addr - region.cpu_addr};
 | 
				
			||||||
            results.push_back(region.gpu_addr + offset);
 | 
					            results.push_back(region.gpu_addr + offset);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return results;
 | 
					    return results;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool MemoryManager::IsPageMapped(GPUVAddr gpu_addr) {
 | 
					 | 
				
			||||||
    return PageSlot(gpu_addr) != static_cast<u64>(PageStatus::Unmapped);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
VAddr& MemoryManager::PageSlot(GPUVAddr gpu_addr) {
 | 
					VAddr& MemoryManager::PageSlot(GPUVAddr gpu_addr) {
 | 
				
			||||||
    auto& block = page_table[(gpu_addr >> (PAGE_BITS + PAGE_TABLE_BITS)) & PAGE_TABLE_MASK];
 | 
					    auto& block{page_table[(gpu_addr >> (PAGE_BITS + PAGE_TABLE_BITS)) & PAGE_TABLE_MASK]};
 | 
				
			||||||
    if (!block) {
 | 
					    if (!block) {
 | 
				
			||||||
        block = std::make_unique<PageBlock>();
 | 
					        block = std::make_unique<PageBlock>();
 | 
				
			||||||
        block->fill(static_cast<VAddr>(PageStatus::Unmapped));
 | 
					        block->fill(static_cast<VAddr>(PageStatus::Unmapped));
 | 
				
			||||||
 | 
				
			|||||||
@ -34,15 +34,15 @@ public:
 | 
				
			|||||||
    static constexpr u64 PAGE_MASK = PAGE_SIZE - 1;
 | 
					    static constexpr u64 PAGE_MASK = PAGE_SIZE - 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
    std::optional<GPUVAddr> FindFreeBlock(u64 size, u64 align = 1);
 | 
					 | 
				
			||||||
    bool IsPageMapped(GPUVAddr gpu_addr);
 | 
					 | 
				
			||||||
    VAddr& PageSlot(GPUVAddr gpu_addr);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    enum class PageStatus : u64 {
 | 
					    enum class PageStatus : u64 {
 | 
				
			||||||
        Unmapped = 0xFFFFFFFFFFFFFFFFULL,
 | 
					        Unmapped = 0xFFFFFFFFFFFFFFFFULL,
 | 
				
			||||||
        Allocated = 0xFFFFFFFFFFFFFFFEULL,
 | 
					        Allocated = 0xFFFFFFFFFFFFFFFEULL,
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    std::optional<GPUVAddr> FindFreeBlock(GPUVAddr region_start, u64 size, u64 align,
 | 
				
			||||||
 | 
					                                          PageStatus status);
 | 
				
			||||||
 | 
					    VAddr& PageSlot(GPUVAddr gpu_addr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    static constexpr u64 MAX_ADDRESS{0x10000000000ULL};
 | 
					    static constexpr u64 MAX_ADDRESS{0x10000000000ULL};
 | 
				
			||||||
    static constexpr u64 PAGE_TABLE_BITS{10};
 | 
					    static constexpr u64 PAGE_TABLE_BITS{10};
 | 
				
			||||||
    static constexpr u64 PAGE_TABLE_SIZE{1 << PAGE_TABLE_BITS};
 | 
					    static constexpr u64 PAGE_TABLE_SIZE{1 << PAGE_TABLE_BITS};
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user