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;
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);
resolution.width = static_cast<u32>(ANativeWindow_getWidth(window));
resolution.height = static_cast<u32>(ANativeWindow_getHeight(window));

View File

@ -1,10 +1,11 @@
// SPDX-License-Identifier: MPL-2.0
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
#include <kernel/types/KProcess.h>
#include "memory_manager.h"
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 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) {
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;
});
@ -41,10 +42,10 @@ namespace skyline::gpu::vmm {
}
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;
} else if (chunk->address + chunk->size >= newChunk.address) {
} else if (chunk->address + chunk->size > newChunk.address) {
chunk->size = (newChunk.address - chunk->address);
// 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);
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
* @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));
}
};
@ -45,6 +45,7 @@ namespace skyline {
*/
class MemoryManager {
private:
const DeviceState &state;
std::vector<ChunkDescriptor> chunkList; //!< This vector holds all the chunk descriptors
/**
@ -63,7 +64,7 @@ namespace skyline {
u64 InsertChunk(const ChunkDescriptor &newChunk);
public:
MemoryManager();
MemoryManager(const DeviceState &state);
/**
* @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
*/
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;
};
}
}