Minor bug fixes in GPU VMM and add support for reading

This commit is contained in:
Billy Laws 2020-07-23 19:44:53 +01:00 committed by ◱ PixelyIon
parent 78712712c7
commit 3c5cc33a34
3 changed files with 41 additions and 8 deletions

View File

@ -12,7 +12,7 @@ extern skyline::u16 fps;
extern skyline::u32 frametime; extern skyline::u32 frametime;
namespace skyline::gpu { namespace skyline::gpu {
GPU::GPU(const DeviceState &state) : state(state), window(ANativeWindow_fromSurface(state.jvm->GetEnv(), Surface)), vsyncEvent(std::make_shared<kernel::type::KEvent>(state)), bufferEvent(std::make_shared<kernel::type::KEvent>(state)) { GPU::GPU(const DeviceState &state) : state(state), memoryManager(state), window(ANativeWindow_fromSurface(state.jvm->GetEnv(), Surface)), vsyncEvent(std::make_shared<kernel::type::KEvent>(state)), bufferEvent(std::make_shared<kernel::type::KEvent>(state)) {
ANativeWindow_acquire(window); ANativeWindow_acquire(window);
resolution.width = static_cast<u32>(ANativeWindow_getWidth(window)); resolution.width = static_cast<u32>(ANativeWindow_getWidth(window));
resolution.height = static_cast<u32>(ANativeWindow_getHeight(window)); resolution.height = static_cast<u32>(ANativeWindow_getHeight(window));

View File

@ -1,10 +1,11 @@
// SPDX-License-Identifier: MPL-2.0 // SPDX-License-Identifier: MPL-2.0
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/) // Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
#include <kernel/types/KProcess.h>
#include "memory_manager.h" #include "memory_manager.h"
namespace skyline::gpu::vmm { namespace skyline::gpu::vmm {
MemoryManager::MemoryManager() { MemoryManager::MemoryManager(const DeviceState &state) : state(state) {
constexpr u64 GpuAddressSpaceSize = 1ul << 40; //!< The size of the GPU address space constexpr u64 GpuAddressSpaceSize = 1ul << 40; //!< The size of the GPU address space
constexpr u64 GpuAddressSpaceBase = 0x100000; //!< The base of the GPU address space - must be non-zero constexpr u64 GpuAddressSpaceBase = 0x100000; //!< The base of the GPU address space - must be non-zero
@ -14,7 +15,7 @@ namespace skyline::gpu::vmm {
} }
std::optional<ChunkDescriptor> MemoryManager::FindChunk(u64 size, ChunkState state) { std::optional<ChunkDescriptor> MemoryManager::FindChunk(u64 size, ChunkState state) {
auto chunk = std::find_if(chunkList.begin(), chunkList.end(), [size, state] (const ChunkDescriptor& chunk) -> bool { auto chunk = std::find_if(chunkList.begin(), chunkList.end(), [size, state](const ChunkDescriptor &chunk) -> bool {
return chunk.size > size && chunk.state == state; return chunk.size > size && chunk.state == state;
}); });
@ -41,10 +42,10 @@ namespace skyline::gpu::vmm {
} }
if (extension) if (extension)
chunkList.insert(std::next(chunk), ChunkDescriptor(newChunk.address + newChunk.size, extension, oldChunk.cpuAddress + oldChunk.size + newChunk.size, oldChunk.state)); chunkList.insert(std::next(chunk), ChunkDescriptor(newChunk.address + newChunk.size, extension, (oldChunk.state == ChunkState::Mapped) ? (oldChunk.cpuAddress + oldChunk.size + newChunk.size) : 0, oldChunk.state));
return newChunk.address; return newChunk.address;
} else if (chunk->address + chunk->size >= newChunk.address) { } else if (chunk->address + chunk->size > newChunk.address) {
chunk->size = (newChunk.address - chunk->address); chunk->size = (newChunk.address - chunk->address);
// Deletes all chunks that are within the chunk being inserted and split the final one // Deletes all chunks that are within the chunk being inserted and split the final one
@ -116,7 +117,33 @@ namespace skyline::gpu::vmm {
size = util::AlignUp(size, constant::GpuPageSize); size = util::AlignUp(size, constant::GpuPageSize);
return InsertChunk(ChunkDescriptor(address, size, cpuAddress, ChunkState::Mapped)); return InsertChunk(ChunkDescriptor(address, size, cpuAddress, ChunkState::Mapped));
} }
void MemoryManager::Read(u8 *destination, u64 address, u64 size) const {
auto chunk = --std::upper_bound(chunkList.begin(), chunkList.end(), address, [](const u64 address, const ChunkDescriptor &chunk) -> bool {
return address < chunk.address;
});
if (chunk == chunkList.end() || chunk->state != ChunkState::Mapped)
throw exception("Failed to read region in GPU address space - address: {#:X} size: {#:X}", address, size);
u64 chunkOffset = address - chunk->address;
u64 destinationOffset{};
// A continuous region in the GPU address space may be made up of several discontinuous regions in physical memory so we have to iterate over all chunks
while (size != 0) {
if (chunk == chunkList.end() || chunk->state != ChunkState::Mapped)
throw exception("Failed to read region in GPU address space - address: {#:X} size: {#:X}", address, size);
u64 readSize = std::min(chunk->size - chunkOffset, size);
state.process->ReadMemory(destination + destinationOffset, chunk->cpuAddress + chunkOffset, readSize);
// After the first read all further reads will start from the base of the chunk
chunkOffset = 0;
size -= readSize;
destinationOffset += readSize;
chunk++;
}
}
} }

View File

@ -35,7 +35,7 @@ namespace skyline {
* @param chunk The chunk to check * @param chunk The chunk to check
* @return If the given chunk can be contained wholly within this chunk * @return If the given chunk can be contained wholly within this chunk
*/ */
inline bool CanContain(const ChunkDescriptor& chunk) { inline bool CanContain(const ChunkDescriptor &chunk) {
return (chunk.address >= this->address) && ((this->size + this->address) >= (chunk.size + chunk.address)); return (chunk.address >= this->address) && ((this->size + this->address) >= (chunk.size + chunk.address));
} }
}; };
@ -45,6 +45,7 @@ namespace skyline {
*/ */
class MemoryManager { class MemoryManager {
private: private:
const DeviceState &state;
std::vector<ChunkDescriptor> chunkList; //!< This vector holds all the chunk descriptors std::vector<ChunkDescriptor> chunkList; //!< This vector holds all the chunk descriptors
/** /**
@ -63,7 +64,7 @@ namespace skyline {
u64 InsertChunk(const ChunkDescriptor &newChunk); u64 InsertChunk(const ChunkDescriptor &newChunk);
public: public:
MemoryManager(); MemoryManager(const DeviceState &state);
/** /**
* @brief This reserves a region of the GPU address space so it can be automatically used when mapping * @brief This reserves a region of the GPU address space so it can be automatically used when mapping
@ -96,6 +97,11 @@ namespace skyline {
* @return The virtual address of the region base * @return The virtual address of the region base
*/ */
u64 MapFixed(u64 address, u64 cpuAddress, u64 size); u64 MapFixed(u64 address, u64 cpuAddress, u64 size);
/**
* @brief Reads in a buffer from a region of the GPU virtual address space
*/
void Read(u8 *destination, u64 address, u64 size) const;
}; };
} }
} }