Address review comments

This commit is contained in:
Billy Laws 2020-08-12 20:02:24 +01:00 committed by ◱ PixelyIon
parent ae131502c6
commit e5264f7762
27 changed files with 342 additions and 295 deletions

View File

@ -26,6 +26,7 @@ namespace skyline::gpu {
void GPU::Loop() {
gpfifo.Run();
vsyncEvent->Signal();
if (surfaceUpdate) {
if (Surface == nullptr)

View File

@ -26,7 +26,7 @@ namespace skyline::gpu {
u16 method;
u32 argument;
u32 subChannel;
bool lastCall; //!< Whether this is the last call in the pushbuffer entry to this specifc macro
bool lastCall; //!< If this is the last call in the pushbuffer entry to this specific macro
};
namespace engine {

View File

@ -9,7 +9,7 @@
namespace skyline {
namespace constant {
constexpr u32 GpfifoRegisterSize = 0x40; //!< The size of the GPFIFO's register space in units of u32
constexpr u32 GpfifoRegisterCount = 0x40; //!< The number of GPFIFO registers
}
namespace gpu::engine {
@ -23,8 +23,11 @@ namespace skyline {
* @brief This holds the GPFIFO engine's registers
* @url https://github.com/NVIDIA/open-gpu-doc/blob/ab27fc22db5de0d02a4cabe08e555663b62db4d4/classes/host/clb06f.h#L65
*/
union Regs {
enum class SemaphoreOperation {
#pragma pack(push, 1)
union Registers {
std::array<u32, constant::GpfifoRegisterCount> raw;
enum class SemaphoreOperation : u8 {
Acquire = 1,
Release = 2,
AcqGeq = 4,
@ -32,22 +35,22 @@ namespace skyline {
Reduction = 16
};
enum class SemaphoreAcquireSwitch {
enum class SemaphoreAcquireSwitch : u8 {
Disabled = 0,
Enabled = 1
};
enum class SemaphoreReleaseWfi {
enum class SemaphoreReleaseWfi : u8 {
En = 0,
Dis = 1
};
enum class SemaphoreReleaseSize {
enum class SemaphoreReleaseSize : u8 {
SixteenBytes = 0,
FourBytes = 1
};
enum class SemaphoreReduction {
enum class SemaphoreReduction : u8 {
Min = 0,
Max = 1,
Xor = 2,
@ -58,32 +61,32 @@ namespace skyline {
Dec = 7
};
enum class SemaphoreFormat {
enum class SemaphoreFormat : u8 {
Signed = 0,
Unsigned = 1
};
enum class MemOpTlbInvalidatePdb {
enum class MemOpTlbInvalidatePdb : u8 {
One = 0,
All = 1
};
enum class SyncpointOperation {
enum class SyncpointOperation : u8 {
Wait = 0,
Incr = 1
};
enum class SyncpointWaitSwitch {
enum class SyncpointWaitSwitch : u8 {
Dis = 0,
En = 1
};
enum class WfiScope {
enum class WfiScope : u8 {
CurrentScgType = 0,
All = 1
};
enum class YieldOp {
enum class YieldOp : u8 {
Nop = 0,
PbdmaTimeslice = 1,
RunlistTimeslice = 2,
@ -93,8 +96,8 @@ namespace skyline {
struct {
struct {
u16 nvClass : 16;
u16 engine : 5;
u32 _pad_ : 11;
u8 engine : 5;
u16 _pad_ : 11;
} setObject;
u32 illegal;
@ -114,7 +117,7 @@ namespace skyline {
u32 payload;
struct __attribute__((__packed__)) {
struct {
SemaphoreOperation operation : 5;
u8 _pad2_ : 7;
SemaphoreAcquireSwitch acquireSwitch : 1;
@ -140,7 +143,7 @@ namespace skyline {
struct {
u32 payload;
struct __attribute__((__packed__)) {
struct {
SyncpointOperation operation : 1;
u8 _pad0_ : 3;
SyncpointWaitSwitch waitSwitch : 1;
@ -162,9 +165,9 @@ namespace skyline {
u32 _pad_ : 30;
} yield;
};
std::array<u32, constant::GpfifoRegisterSize> raw;
} regs{};
static_assert(sizeof(Regs) == (constant::GpfifoRegisterSize << 2));
} registers{};
static_assert(sizeof(Registers) == (constant::GpfifoRegisterCount * sizeof(u32)));
#pragma pack(pop)
public:
GPFIFO(const DeviceState &state) : Engine(state) {}
@ -172,7 +175,7 @@ namespace skyline {
void CallMethod(MethodParams params) {
state.logger->Debug("Called method in GPFIFO: 0x{:X} args: 0x{:X}", params.method, params.argument);
regs.raw[params.method] = params.argument;
registers.raw[params.method] = params.argument;
};
};
}

View File

@ -11,72 +11,76 @@ namespace skyline::gpu::engine {
}
void Maxwell3D::ResetRegs() {
memset(&regs, 0, sizeof(regs));
registers = {};
regs.rasterizerEnable = true;
registers.rasterizerEnable = true;
for (auto &transform : regs.viewportTransform) {
transform.swizzles.x = Regs::ViewportTransform::Swizzle::PositiveX;
transform.swizzles.y = Regs::ViewportTransform::Swizzle::PositiveY;
transform.swizzles.z = Regs::ViewportTransform::Swizzle::PositiveZ;
transform.swizzles.w = Regs::ViewportTransform::Swizzle::PositiveW;
for (auto &transform : registers.viewportTransform) {
transform.swizzles.x = Registers::ViewportTransform::Swizzle::PositiveX;
transform.swizzles.y = Registers::ViewportTransform::Swizzle::PositiveY;
transform.swizzles.z = Registers::ViewportTransform::Swizzle::PositiveZ;
transform.swizzles.w = Registers::ViewportTransform::Swizzle::PositiveW;
}
for (auto &viewport : regs.viewport) {
for (auto &viewport : registers.viewport) {
viewport.depthRangeFar = 1.0f;
viewport.depthRangeNear = 0.0f;
}
regs.polygonMode.front = Regs::PolygonMode::Fill;
regs.polygonMode.back = Regs::PolygonMode::Fill;
registers.polygonMode.front = Registers::PolygonMode::Fill;
registers.polygonMode.back = Registers::PolygonMode::Fill;
regs.stencilFront.failOp = regs.stencilFront.zFailOp = regs.stencilFront.zPassOp = Regs::StencilOp::Keep;
regs.stencilFront.func.op = Regs::CompareOp::Always;
regs.stencilFront.func.mask = 0xFFFFFFFF;
regs.stencilFront.mask = 0xFFFFFFFF;
registers.stencilFront.failOp = registers.stencilFront.zFailOp = registers.stencilFront.zPassOp = Registers::StencilOp::Keep;
registers.stencilFront.compare.op = Registers::CompareOp::Always;
registers.stencilFront.compare.mask = 0xFFFFFFFF;
registers.stencilFront.writeMask = 0xFFFFFFFF;
regs.stencilBack.stencilTwoSideEnable = true;
regs.stencilBack.failOp = regs.stencilBack.zFailOp = regs.stencilBack.zPassOp = Regs::StencilOp::Keep;
regs.stencilBack.funcOp = Regs::CompareOp::Always;
regs.stencilBackExtra.funcMask = 0xFFFFFFFF;
regs.stencilBackExtra.mask = 0xFFFFFFFF;
registers.stencilTwoSideEnable = true;
registers.stencilBack.failOp = registers.stencilBack.zFailOp = registers.stencilBack.zPassOp = Registers::StencilOp::Keep;
registers.stencilBack.compareOp = Registers::CompareOp::Always;
registers.stencilBackExtra.compareMask = 0xFFFFFFFF;
registers.stencilBackExtra.writeMask = 0xFFFFFFFF;
regs.rtSeparateFragData = true;
registers.rtSeparateFragData = true;
for (auto &attribute : regs.vertexAttributeState)
for (auto &attribute : registers.vertexAttributeState)
attribute.fixed = true;
regs.depthTestFunc = Regs::CompareOp::Always;
registers.depthTestFunc = Registers::CompareOp::Always;
regs.blend.colorOp = regs.blend.alphaOp = Regs::Blend::Op::Add;
regs.blend.colorSrcFactor = regs.blend.alphaSrcFactor = Regs::Blend::Factor::One;
regs.blend.colorDestFactor = regs.blend.alphaDestFactor = Regs::Blend::Factor::Zero;
registers.blend.colorOp = registers.blend.alphaOp = Registers::Blend::Op::Add;
registers.blend.colorSrcFactor = registers.blend.alphaSrcFactor = Registers::Blend::Factor::One;
registers.blend.colorDestFactor = registers.blend.alphaDestFactor = Registers::Blend::Factor::Zero;
regs.lineWidthSmooth = 1.0f;
regs.lineWidthAliased = 1.0f;
registers.lineWidthSmooth = 1.0f;
registers.lineWidthAliased = 1.0f;
regs.pointSpriteSize = 1.0f;
registers.pointSpriteEnable = true;
registers.pointSpriteSize = 1.0f;
registers.pointCoordReplace.enable = true;
regs.frontFace = Regs::FrontFace::CounterClockwise;
regs.cullFace = Regs::CullFace::Back;
registers.frontFace = Registers::FrontFace::CounterClockwise;
registers.cullFace = Registers::CullFace::Back;
for (auto &mask : regs.colorMask)
for (auto &mask : registers.colorMask)
mask.r = mask.g = mask.b = mask.a = 1;
for (auto &blend : regs.independentBlend) {
blend.colorOp = blend.alphaOp = Regs::Blend::Op::Add;
blend.colorSrcFactor = blend.alphaSrcFactor = Regs::Blend::Factor::One;
blend.colorDestFactor = blend.alphaDestFactor = Regs::Blend::Factor::Zero;
for (auto &blend : registers.independentBlend) {
blend.colorOp = blend.alphaOp = Registers::Blend::Op::Add;
blend.colorSrcFactor = blend.alphaSrcFactor = Registers::Blend::Factor::One;
blend.colorDestFactor = blend.alphaDestFactor = Registers::Blend::Factor::Zero;
}
registers.viewportTransformEnable = true;
}
void Maxwell3D::CallMethod(MethodParams params) {
state.logger->Debug("Called method in Maxwell 3D: 0x{:X} args: 0x{:X}", params.method, params.argument);
// Methods that are greater than the register size are for macro control
if (params.method > constant::Maxwell3DRegisterSize) {
if (params.method > constant::Maxwell3DRegisterCounter) {
if (!(params.method & 1))
macroInvocation.index = ((params.method - constant::Maxwell3DRegisterSize) >> 1) % macroPositions.size();
macroInvocation.index = ((params.method - constant::Maxwell3DRegisterCounter) >> 1) % macroPositions.size();
macroInvocation.arguments.push_back(params.argument);
@ -90,58 +94,58 @@ namespace skyline::gpu::engine {
return;
}
regs.raw[params.method] = params.argument;
registers.raw[params.method] = params.argument;
if (shadowRegs.mme.shadowRamControl == Regs::MmeShadowRamControl::MethodTrack || shadowRegs.mme.shadowRamControl == Regs::MmeShadowRamControl::MethodTrackWithFilter)
shadowRegs.raw[params.method] = params.argument;
else if (shadowRegs.mme.shadowRamControl == Regs::MmeShadowRamControl::MethodReplay)
params.argument = shadowRegs.raw[params.method];
if (shadowRegisters.mme.shadowRamControl == Registers::MmeShadowRamControl::MethodTrack || shadowRegisters.mme.shadowRamControl == Registers::MmeShadowRamControl::MethodTrackWithFilter)
shadowRegisters.raw[params.method] = params.argument;
else if (shadowRegisters.mme.shadowRamControl == Registers::MmeShadowRamControl::MethodReplay)
params.argument = shadowRegisters.raw[params.method];
switch (params.method) {
case MAXWELL3D_OFFSET(mme.instructionRamLoad):
if (regs.mme.instructionRamPointer >= macroCode.size())
if (registers.mme.instructionRamPointer >= macroCode.size())
throw exception("Macro memory is full!");
macroCode[regs.mme.instructionRamPointer++] = params.argument;
macroCode[registers.mme.instructionRamPointer++] = params.argument;
break;
case MAXWELL3D_OFFSET(mme.startAddressRamLoad):
if (regs.mme.startAddressRamPointer >= macroPositions.size())
if (registers.mme.startAddressRamPointer >= macroPositions.size())
throw exception("Maximum amount of macros reached!");
macroPositions[regs.mme.startAddressRamPointer++] = params.argument;
macroPositions[registers.mme.startAddressRamPointer++] = params.argument;
break;
case MAXWELL3D_OFFSET(mme.shadowRamControl):
shadowRegs.mme.shadowRamControl = static_cast<Regs::MmeShadowRamControl>(params.argument);
shadowRegisters.mme.shadowRamControl = static_cast<Registers::MmeShadowRamControl>(params.argument);
break;
case MAXWELL3D_OFFSET(syncpointAction):
state.gpu->syncpoints.at(regs.syncpointAction.id).Increment();
state.gpu->syncpoints.at(registers.syncpointAction.id).Increment();
break;
case MAXWELL3D_OFFSET(semaphore.info):
switch (regs.semaphore.info.op) {
case Regs::SemaphoreInfo::Op::Release:
WriteSemaphoreResult(regs.semaphore.payload);
switch (registers.semaphore.info.op) {
case Registers::SemaphoreInfo::Op::Release:
WriteSemaphoreResult(registers.semaphore.payload);
break;
case Regs::SemaphoreInfo::Op::Counter:
case Registers::SemaphoreInfo::Op::Counter:
HandleSemaphoreCounterOperation();
break;
default:
state.logger->Warn("Unsupported semaphore operation: 0x{:X}", static_cast<u8>(regs.semaphore.info.op));
state.logger->Warn("Unsupported semaphore operation: 0x{:X}", static_cast<u8>(registers.semaphore.info.op));
break;
}
break;
case MAXWELL3D_OFFSET(firmwareCall[4]):
regs.raw[0xd00] = 1;
registers.raw[0xd00] = 1;
break;
}
}
void Maxwell3D::HandleSemaphoreCounterOperation() {
switch (regs.semaphore.info.counterType) {
case Regs::SemaphoreInfo::CounterType::Zero:
switch (registers.semaphore.info.counterType) {
case Registers::SemaphoreInfo::CounterType::Zero:
WriteSemaphoreResult(0);
break;
default:
state.logger->Warn("Unsupported semaphore counter type: 0x{:X}", static_cast<u8>(regs.semaphore.info.counterType));
state.logger->Warn("Unsupported semaphore counter type: 0x{:X}", static_cast<u8>(registers.semaphore.info.counterType));
break;
}
}
@ -152,11 +156,11 @@ namespace skyline::gpu::engine {
u64 timestamp;
};
switch (regs.semaphore.info.structureSize) {
case Regs::SemaphoreInfo::StructureSize::OneWord:
state.gpu->memoryManager.Write<u32>(static_cast<u32>(result), regs.semaphore.address.Pack());
switch (registers.semaphore.info.structureSize) {
case Registers::SemaphoreInfo::StructureSize::OneWord:
state.gpu->memoryManager.Write<u32>(static_cast<u32>(result), registers.semaphore.address.Pack());
break;
case Regs::SemaphoreInfo::StructureSize::FourWords: {
case Registers::SemaphoreInfo::StructureSize::FourWords: {
// Convert the current nanosecond time to GPU ticks
constexpr u64 NsToTickNumerator = 384;
constexpr u64 NsToTickDenominator = 625;
@ -164,7 +168,7 @@ namespace skyline::gpu::engine {
u64 nsTime = util::GetTimeNs();
u64 timestamp = (nsTime / NsToTickDenominator) * NsToTickNumerator + ((nsTime % NsToTickDenominator) * NsToTickNumerator) / NsToTickDenominator;
state.gpu->memoryManager.Write<FourWordResult>(FourWordResult{result, timestamp}, regs.semaphore.address.Pack());
state.gpu->memoryManager.Write<FourWordResult>(FourWordResult{result, timestamp}, registers.semaphore.address.Pack());
break;
}
}

View File

@ -9,11 +9,11 @@
#include <gpu/macro_interpreter.h>
#include "engine.h"
#define MAXWELL3D_OFFSET(field) U32_OFFSET(skyline::gpu::engine::Maxwell3D::Regs, field)
#define MAXWELL3D_OFFSET(field) U32_OFFSET(skyline::gpu::engine::Maxwell3D::Registers, field)
namespace skyline {
namespace constant {
constexpr u32 Maxwell3DRegisterSize = 0xe00; //!< The size of the GPFIFO's register space in units of u32
constexpr u32 Maxwell3DRegisterCounter = 0xe00; //!< The number of Maxwell 3D registers
}
namespace gpu::engine {
@ -40,7 +40,10 @@ namespace skyline {
* @brief This holds the Maxwell3D engine's register space
* @url https://github.com/devkitPro/deko3d/blob/master/source/maxwell/engine_3d.def#L478
*/
union Regs {
#pragma pack(push, 1)
union Registers {
std::array<u32, constant::Maxwell3DRegisterCounter> raw;
struct Address {
u32 high;
u32 low;
@ -77,7 +80,7 @@ namespace skyline {
float translateY;
float translateZ;
struct __attribute__((__packed__)) {
struct {
Swizzle x : 3;
u8 _pad0_ : 1;
Swizzle y : 3;
@ -88,7 +91,7 @@ namespace skyline {
u32 _pad3_ : 17;
} swizzles;
struct __attribute__((__packed__)) {
struct {
u8 x : 5;
u8 _pad0_ : 3;
u8 y : 5;
@ -120,6 +123,8 @@ namespace skyline {
};
union VertexAttribute {
u32 raw;
enum class Size : u8 {
Size_1x32 = 0x12,
Size_2x32 = 0x04,
@ -148,7 +153,7 @@ namespace skyline {
Float = 7,
};
struct __attribute__((__packed__)) {
struct {
u8 bufferId : 5;
u8 _pad0_ : 1;
bool fixed : 1;
@ -158,8 +163,6 @@ namespace skyline {
u8 _pad1_ : 1;
bool bgra : 1;
};
u32 raw;
};
static_assert(sizeof(VertexAttribute) == sizeof(u32));
@ -275,19 +278,19 @@ namespace skyline {
FrontAndBack = 0x408,
};
union ColorMask {
struct __attribute__((__packed__)) {
union ColorWriteMask {
u32 raw;
struct {
u8 r : 4;
u8 g : 4;
u8 b : 4;
u8 a : 4;
};
u32 raw;
};
static_assert(sizeof(ColorMask) == sizeof(u32));
static_assert(sizeof(ColorWriteMask) == sizeof(u32));
struct __attribute__((__packed__)) SemaphoreInfo {
struct SemaphoreInfo {
enum class Op : u8 {
Release = 0,
Acquire = 1,
@ -372,6 +375,11 @@ namespace skyline {
};
static_assert(sizeof(SemaphoreInfo) == sizeof(u32));
enum class CoordOrigin : u8 {
LowerLeft = 0,
UpperLeft = 1
};
struct {
u32 _pad0_[0x40]; // 0x0
u32 noOperation; // 0x40
@ -412,9 +420,9 @@ namespace skyline {
u32 _pad6_[0x68]; // 0x36d
struct {
u32 funcRef; // 0x3d5
u32 mask; // 0x3d6
u32 funcMask; // 0x3d7
u32 compareRef; // 0x3d5
u32 writeMask; // 0x3d6
u32 compareMask; // 0x3d7
} stencilBackExtra;
u32 _pad7_[0x13]; // 0x3d8
@ -461,9 +469,9 @@ namespace skyline {
CompareOp op; // 0x4e4
i32 ref; // 0x4e5
u32 mask; // 0x4e6
} func;
} compare;
u32 mask; // 0x4e7
u32 writeMask; // 0x4e7
} stencilFront;
u32 _pad11_[0x4]; // 0x4e8
@ -484,7 +492,7 @@ namespace skyline {
u32 multisampleEnable; // 0x54d
u32 depthTargetEnable; // 0x54e
struct __attribute__((__packed__)) {
struct {
bool alphaToCoverage : 1;
u8 _pad0_ : 3;
bool alphaToOne : 1;
@ -509,22 +517,34 @@ namespace skyline {
u32 _pad18_[0x5]; // 0x560
u32 stencilTwoSideEnable; // 0x565
struct {
u32 stencilTwoSideEnable; // 0x565
StencilOp failOp; // 0x566
StencilOp zFailOp; // 0x567
StencilOp zPassOp; // 0x568
CompareOp funcOp; // 0x569
CompareOp compareOp; // 0x569
} stencilBack;
u32 _pad19_[0xdc]; // 0x56a
u32 _pad19_[0x17]; // 0x56a
struct {
u8 _unk_ : 2;
CoordOrigin origin : 1;
u16 enable : 10;
u32 _pad_ : 19;
} pointCoordReplace; // 0x581
u32 _pad20_[0xc4]; // 0x582
u32 cullFaceEnable; // 0x646
FrontFace frontFace; // 0x647
CullFace cullFace; // 0x648
u32 pixelCentreImage; // 0x649
u32 _pad20_[0x36]; // 0x64a
std::array<ColorMask, 8> colorMask; // 0x680 For each render target
u32 _pad21_[0x38]; // 0x688
u32 _pad21_; // 0x64a
u32 viewportTransformEnable; // 0x64b
u32 _pad22_[0x34]; // 0x64a
std::array<ColorWriteMask, 8> colorMask; // 0x680 For each render target
u32 _pad23_[0x38]; // 0x688
struct {
Address address; // 0x6c0
@ -532,18 +552,17 @@ namespace skyline {
SemaphoreInfo info; // 0x6c3
} semaphore;
u32 _pad22_[0xbc]; // 0x6c4
u32 _pad24_[0xbc]; // 0x6c4
std::array<Blend, 8> independentBlend; // 0x780 For each render target
u32 _pad23_[0x100]; // 0x7c0
u32 _pad25_[0x100]; // 0x7c0
u32 firmwareCall[0x20]; // 0x8c0
};
std::array<u32, constant::Maxwell3DRegisterSize> raw;
};
static_assert(sizeof(Regs) == (constant::Maxwell3DRegisterSize * sizeof(u32)));
static_assert(sizeof(Registers) == (constant::Maxwell3DRegisterCounter * sizeof(u32)));
#pragma pack(pop)
Regs regs{}; //!< The maxwell 3D register space
Regs shadowRegs{}; //!< The shadow registers, their function is controlled by the 'shadowRamControl' register
Registers registers{}; //!< The maxwell 3D register space
Registers shadowRegisters{}; //!< The shadow registers, their function is controlled by the 'shadowRamControl' register
std::array<u32, 0x10000> macroCode{}; //!< This is used to store GPU macros, the 256kb size is from Ryujinx

View File

@ -32,7 +32,7 @@ namespace skyline::gpu::gpfifo {
state.logger->Info("Bound GPU engine 0x{:X} to subchannel {}", params.argument, params.subChannel);
return;
} else if (params.method < constant::GpfifoRegisterSize) {
} else if (params.method < constant::GpfifoRegisterCount) {
gpfifoEngine.CallMethod(params);
} else {
if (subchannels.at(params.subChannel) == nullptr)

View File

@ -18,18 +18,19 @@ namespace skyline::gpu {
* @url https://github.com/NVIDIA/open-gpu-doc/blob/ab27fc22db5de0d02a4cabe08e555663b62db4d4/classes/host/clb06f.h#L155
*/
struct GpEntry {
enum class Fetch {
enum class Fetch : u8 {
Unconditional = 0,
Conditional = 1,
};
union {
u32 entry0;
struct {
Fetch fetch : 1;
u8 _pad_ : 1;
u32 get : 30;
};
u32 entry0;
};
enum class Opcode : u8 {
@ -39,36 +40,38 @@ namespace skyline::gpu {
PbCrc = 3,
};
enum class Priv {
enum class Priv : u8 {
User = 0,
Kernel = 1,
};
enum class Level {
enum class Level : u8 {
Main = 0,
Subroutine = 1,
};
enum class Sync {
enum class Sync : u8 {
Proceed = 0,
Wait = 1,
};
union {
u32 entry1;
struct {
union {
u8 getHi;
Opcode opcode;
};
Priv priv : 1;
Level level : 1;
u32 size : 21;
Sync sync : 1;
};
u32 entry1;
};
};
static_assert(sizeof(GpEntry) == 0x8);
static_assert(sizeof(GpEntry) == sizeof(u64));
/**
* @brief This holds a single pushbuffer method header that describes a compressed method sequence
@ -76,6 +79,8 @@ namespace skyline::gpu {
* @url https://github.com/NVIDIA/open-gpu-doc/blob/ab27fc22db5de0d02a4cabe08e555663b62db4d4/classes/host/clb06f.h#L179
*/
union PushBufferMethodHeader {
u32 raw;
enum class TertOp : u8 {
Grp0IncMethod = 0,
Grp0SetSubDevMask = 1,
@ -95,33 +100,28 @@ namespace skyline::gpu {
EndPbSegment = 7
};
u16 methodAddress : 12;
struct {
u8 _pad0_ : 4;
u16 subDeviceMask : 12;
};
struct {
u16 _pad1_ : 13;
u8 methodSubChannel : 3;
union {
u16 methodAddress : 12;
struct {
u8 _pad0_ : 4;
u16 subDeviceMask : 12;
};
struct {
u16 _pad1_ : 13;
u8 methodSubChannel : 3;
union {
TertOp tertOp : 3;
u16 methodCount : 13;
u16 immdData : 13;
};
};
struct {
u32 _pad2_ : 29;
SecOp secOp : 3;
};
TertOp tertOp : 3;
u16 methodCount : 13;
u16 immdData : 13;
};
};
u32 entry;
struct {
u32 _pad2_ : 29;
SecOp secOp : 3;
};
};
static_assert(sizeof(PushBufferMethodHeader) == 0x4);
static_assert(sizeof(PushBufferMethodHeader) == sizeof(u32));
/**
* @brief The GPFIFO class handles creating pushbuffers from GP entries and then processing them

View File

@ -67,7 +67,7 @@ namespace skyline::gpu {
break;
}
case Opcode::Operation::ReadImmediate: {
u32 result = maxwell3D.regs.raw[registers[opcode->srcA] + opcode->immediate];
u32 result = maxwell3D.registers.raw[registers[opcode->srcA] + opcode->immediate];
HandleAssignment(opcode->assignmentOperation, opcode->dest, result);
break;
}

View File

@ -10,12 +10,18 @@ namespace skyline::gpu {
class Maxwell3D;
}
/**
* @brief The MacroInterpreter class handles interpreting macros. Macros are small programs that run on the GPU and are used for things like instanced rendering.
*/
class MacroInterpreter {
private:
/**
* @brief This holds a single macro opcode
*/
#pragma pack(push, 1)
union Opcode {
u32 raw;
enum class Operation : u8 {
AluRegister = 0,
AddImmediate = 1,
@ -54,16 +60,16 @@ namespace skyline::gpu {
NonZero = 1,
};
struct __attribute__((__packed__)) {
struct {
Operation operation : 3;
u8 _pad0_ : 1;
AssignmentOperation assignmentOperation : 3;
};
struct __attribute__((__packed__)) {
struct {
u8 _pad1_ : 4;
BranchCondition branchCondition : 1;
u8 noDelay : 1;
bool noDelay : 1;
u8 _pad2_ : 1;
u8 exit : 1;
u8 dest : 3;
@ -72,12 +78,12 @@ namespace skyline::gpu {
AluOperation aluOperation : 5;
};
struct __attribute__((__packed__)) {
struct {
u16 _pad3_ : 14;
i32 immediate : 18;
};
struct __attribute__((__packed__)) {
struct {
u32 _pad_ : 17;
u8 srcBit : 5;
u8 size : 5;
@ -87,21 +93,20 @@ namespace skyline::gpu {
return (1 << size) - 1;
}
} bitfield;
u32 raw;
};
#pragma pack(pop)
static_assert(sizeof(Opcode) == sizeof(u32));
/**
* @brief This holds information about the Maxwell 3D method to be called in 'Send'
*/
union MethodAddress {
u32 raw;
struct {
u16 address : 12;
u8 increment : 6;
};
u32 raw;
};
engine::Maxwell3D &maxwell3D;

View File

@ -97,8 +97,8 @@ namespace skyline::gpu::vmm {
}
u64 MemoryManager::ReserveFixed(u64 address, u64 size) {
if ((address & (constant::GpuPageSize - 1)) != 0)
return 0;
if (!util::IsAligned(address, constant::GpuPageSize))
return false;
size = util::AlignUp(size, constant::GpuPageSize);
@ -120,8 +120,8 @@ namespace skyline::gpu::vmm {
}
u64 MemoryManager::MapFixed(u64 address, u64 cpuAddress, u64 size) {
if ((address & (constant::GpuPageSize - 1)) != 0)
return 0;
if (!util::IsAligned(address, constant::GpuPageSize))
return false;
size = util::AlignUp(size, constant::GpuPageSize);
@ -129,7 +129,7 @@ namespace skyline::gpu::vmm {
}
bool MemoryManager::Unmap(u64 address) {
if ((address & (constant::GpuPageSize - 1)) != 0)
if (!util::IsAligned(address, constant::GpuPageSize))
return false;
auto chunk = std::find_if(chunkList.begin(), chunkList.end(), [address](const ChunkDescriptor &chunk) -> bool {
@ -146,56 +146,62 @@ namespace skyline::gpu::vmm {
}
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 {
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: 0x{:X} size: 0x{:X}", address, size);
throw exception("Failed to read region in GPU address space: Address: 0x{:X}, Size: 0x{:X}", address, size);
u64 chunkOffset = address - chunk->address;
u64 destinationOffset{};
chunk--;
u64 initialSize{size};
u64 chunkOffset{address - chunk->address};
u64 readAddress{chunk->cpuAddress + chunkOffset};
u64 readSize{std::min(chunk->size - chunkOffset, size)};
// 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);
while (size) {
state.process->ReadMemory(destination + (initialSize - size), readAddress, readSize);
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++;
if (size) {
if (++chunk == chunkList.end() || chunk->state != ChunkState::Mapped)
throw exception("Failed to read region in GPU address space: Address: 0x{:X}, Size: 0x{:X}", address, size);
readAddress = chunk->cpuAddress;
readSize = std::min(chunk->size, size);
}
}
}
void MemoryManager::Write(u8 *source, u64 address, u64 size) const {
auto chunk = --std::upper_bound(chunkList.begin(), chunkList.end(), address, [](const u64 address, const ChunkDescriptor &chunk) -> bool {
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 write to region in GPU address space - address: {#:X} size: {#:X}", address, size);
throw exception("Failed to write region in GPU address space: Address: 0x{:X}, Size: 0x{:X}", address, size);
u64 chunkOffset = address - chunk->address;
u64 sourceOffset{};
chunk--;
u64 initialSize{size};
u64 chunkOffset{address - chunk->address};
u64 writeAddress{chunk->cpuAddress + chunkOffset};
u64 writeSize{std::min(chunk->size - chunkOffset, size)};
// 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 write to region in GPU address space - address: {#:X} size: {#:X}", address, size);
while (size) {
state.process->WriteMemory(source + (initialSize - size), writeAddress, writeSize);
u64 writeSize = std::min(chunk->size - chunkOffset, size);
state.process->WriteMemory(source + sourceOffset, chunk->cpuAddress + chunkOffset, writeSize);
// After the first read all further reads will start from the base of the chunk
chunkOffset = 0;
size -= writeSize;
sourceOffset += writeSize;
chunk++;
if (size) {
if (++chunk == chunkList.end() || chunk->state != ChunkState::Mapped)
throw exception("Failed to write region in GPU address space: Address: 0x{:X}, Size: 0x{:X}", address, size);
writeAddress = chunk->cpuAddress;
writeSize = std::min(chunk->size, size);
}
}
}
}

View File

@ -47,7 +47,6 @@ namespace skyline {
class MemoryManager {
private:
const DeviceState &state;
std::vector<ChunkDescriptor> chunkList; //!< This vector holds all the chunk descriptors
/**
* @brief This finds a chunk of the specified type in the GPU address space that is larger than the given size
@ -66,6 +65,7 @@ namespace skyline {
public:
MemoryManager(const DeviceState &state);
std::vector<ChunkDescriptor> chunkList; //!< This vector holds all the chunk descriptors
/**
* @brief This reserves a region of the GPU address space so it will not be chosen automatically when mapping

View File

@ -7,10 +7,13 @@
namespace skyline {
namespace constant {
constexpr size_t MaxHwSyncpointCount = 192;
constexpr size_t MaxHwSyncpointCount = 192; //!< The maximum number of HOST1X syncpoints on t210
}
namespace gpu {
/**
* @brief The Syncpoint class represents a single syncpoint in the GPU which is used for GPU -> CPU synchronisation
*/
class Syncpoint {
private:
/**

View File

@ -4,7 +4,7 @@
#pragma once
#include <common.h>
#include "devices/nvhost_syncpoint.h"
#include <services/nvdrv/devices/nvhost_syncpoint.h>
namespace skyline::service::nvdrv {
/**

View File

@ -29,7 +29,7 @@ namespace skyline::service::fssrv {
void Write(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
/**
* @brief This flushes any written data to the IFile
* @brief This flushes any written data to the IFile on the Switch, however the emulator processes any FS event immediately so this does nothing
*/
void Flush(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);

View File

@ -5,7 +5,7 @@
#include <os.h>
#include <kernel/types/KProcess.h>
#include <services/nvdrv/INvDrvServices.h>
#include <services/nvdrv/fence.h>
#include <services/common/fence.h>
#include <gpu/format.h>
#include "IHOSBinderDriver.h"
#include "display.h"

View File

@ -126,6 +126,8 @@ namespace skyline::service::nvdrv::device {
u32 pages;
};
constexpr u32 MinAlignmentShift{0x10}; // This shift is applied to all addresses passed to Remap
size_t entryCount{buffer.input.at(0).size / sizeof(Entry)};
std::span entries(state.process->GetPointer<Entry>(buffer.input.at(0).address), entryCount);
@ -133,9 +135,9 @@ namespace skyline::service::nvdrv::device {
try {
auto nvmap = state.os->serviceManager.GetService<nvdrv::INvDrvServices>(Service::nvdrv_INvDrvServices)->GetDevice<nvdrv::device::NvMap>(nvdrv::device::NvDeviceType::nvmap)->handleTable.at(entry.nvmapHandle);
u64 mapAddress = static_cast<u64>(entry.gpuOffset) << 0x10;
u64 mapPhysicalAddress = nvmap->address + (static_cast<u64>(entry.mapOffset) << 0x10);
u64 mapSize = static_cast<u64>(entry.pages) << 0x10;
u64 mapAddress = static_cast<u64>(entry.gpuOffset) << MinAlignmentShift;
u64 mapPhysicalAddress = nvmap->address + (static_cast<u64>(entry.mapOffset) << MinAlignmentShift);
u64 mapSize = static_cast<u64>(entry.pages) << MinAlignmentShift;
state.gpu->memoryManager.MapFixed(mapAddress, mapPhysicalAddress, mapSize);
} catch (const std::exception &e) {

View File

@ -3,7 +3,7 @@
#pragma once
#include <services/nvdrv/fence.h>
#include <services/common/fence.h>
#include "nvdevice.h"
namespace skyline::service::nvdrv::device {

View File

@ -45,65 +45,6 @@ namespace skyline::service::nvdrv::device {
{0x001F, NFUNC(NvHostCtrl::EventRegister)},
}) {}
void NvHostCtrl::GetConfig(IoctlData &buffer) {
buffer.status = NvStatus::BadValue;
}
void NvHostCtrl::EventSignal(IoctlData &buffer) {
struct Data {
u16 _pad_;
u16 userEventId;
};
auto userEventId = state.process->GetObject<Data>(buffer.input.at(0).address).userEventId;
state.logger->Debug("Signalling nvhost event: {}", userEventId);
if (userEventId >= constant::NvHostEventCount || !events.at(userEventId)) {
buffer.status = NvStatus::BadValue;
return;
}
auto &event = *events.at(userEventId);
if (event.state == NvHostEvent::State::Waiting) {
event.state = NvHostEvent::State::Cancelling;
state.logger->Debug("Cancelling waiting nvhost event: {}", userEventId);
event.Cancel(state.gpu);
}
event.state = NvHostEvent::State::Cancelled;
auto &hostSyncpoint = state.os->serviceManager.GetService<nvdrv::INvDrvServices>(Service::nvdrv_INvDrvServices)->hostSyncpoint;
hostSyncpoint.UpdateMin(event.fence.id);
}
void NvHostCtrl::EventWait(IoctlData &buffer) {
EventWaitImpl(buffer, false);
}
void NvHostCtrl::EventWaitAsync(IoctlData &buffer) {
EventWaitImpl(buffer, true);
}
void NvHostCtrl::EventRegister(IoctlData &buffer) {
auto userEventId = state.process->GetObject<u32>(buffer.input.at(0).address);
state.logger->Debug("Registering nvhost event: {}", userEventId);
if (events.at(userEventId))
throw exception("Recreating events is unimplemented");
events.at(userEventId) = NvHostEvent(state);
}
std::shared_ptr<type::KEvent> NvHostCtrl::QueryEvent(u32 eventId) {
auto eventValue = reinterpret_cast<EventValue *>(&eventId);
const auto &event = events.at(eventValue->nonAsync ? eventValue->eventSlotNonAsync : eventValue->eventSlotAsync);
if (event && event->fence.id == (eventValue->nonAsync ? eventValue->syncpointIdNonAsync : eventValue->syncpointIdAsync))
return event->event;
return nullptr;
}
u32 NvHostCtrl::FindFreeEvent(u32 syncpointId) {
u32 eventIndex{constant::NvHostEventCount}; //!< Holds the index of the last populated event in the event array
u32 freeIndex{constant::NvHostEventCount}; //!< Holds the index of the first unused event id
@ -208,4 +149,65 @@ namespace skyline::service::nvdrv::device {
return;
}
}
void NvHostCtrl::GetConfig(IoctlData &buffer) {
buffer.status = NvStatus::BadValue;
}
void NvHostCtrl::EventSignal(IoctlData &buffer) {
struct Data {
u16 _pad_;
u16 userEventId;
};
auto userEventId = state.process->GetObject<Data>(buffer.input.at(0).address).userEventId;
state.logger->Debug("Signalling nvhost event: {}", userEventId);
if (userEventId >= constant::NvHostEventCount || !events.at(userEventId)) {
buffer.status = NvStatus::BadValue;
return;
}
auto &event = *events.at(userEventId);
if (event.state == NvHostEvent::State::Waiting) {
event.state = NvHostEvent::State::Cancelling;
state.logger->Debug("Cancelling waiting nvhost event: {}", userEventId);
event.Cancel(state.gpu);
}
event.state = NvHostEvent::State::Cancelled;
auto &hostSyncpoint = state.os->serviceManager.GetService<nvdrv::INvDrvServices>(Service::nvdrv_INvDrvServices)->hostSyncpoint;
hostSyncpoint.UpdateMin(event.fence.id);
}
void NvHostCtrl::EventWait(IoctlData &buffer) {
EventWaitImpl(buffer, false);
}
void NvHostCtrl::EventWaitAsync(IoctlData &buffer) {
EventWaitImpl(buffer, true);
}
void NvHostCtrl::EventRegister(IoctlData &buffer) {
auto userEventId = state.process->GetObject<u32>(buffer.input.at(0).address);
state.logger->Debug("Registering nvhost event: {}", userEventId);
auto &event = events.at(userEventId);
if (event)
throw exception("Recreating events is unimplemented");
event = NvHostEvent(state);
}
std::shared_ptr<type::KEvent> NvHostCtrl::QueryEvent(u32 eventId) {
auto eventValue = EventValue{.val = eventId};
const auto &event = events.at(eventValue.nonAsync ? eventValue.eventSlotNonAsync : eventValue.eventSlotAsync);
if (event && event->fence.id == (eventValue.nonAsync ? eventValue.syncpointIdNonAsync : eventValue.syncpointIdAsync))
return event->event;
return nullptr;
}
}

View File

@ -3,7 +3,7 @@
#pragma once
#include <services/nvdrv/fence.h>
#include <services/common/fence.h>
#include "nvdevice.h"
namespace skyline {
@ -12,6 +12,9 @@ namespace skyline {
}
namespace service::nvdrv::device {
/**
* @brief This represents a single registered event with an attached fence
*/
class NvHostEvent {
private:
u64 waiterId{};
@ -57,6 +60,8 @@ namespace skyline {
* @brief This holds metadata about an event, it is used by QueryEvent and EventWait
*/
union EventValue {
u32 val;
struct {
u8 _pad0_ : 4;
u32 syncpointIdAsync : 28;
@ -71,8 +76,6 @@ namespace skyline {
bool nonAsync : 1;
u8 _pad12_ : 3;
};
u32 val;
};
static_assert(sizeof(EventValue) == sizeof(u32));

View File

@ -9,7 +9,6 @@
namespace skyline::service::nvdrv {
/**
* @todo Implement the GPU side of this
* @brief NvHostSyncpoint handles allocating and accessing host1x syncpoints
* @url https://http.download.nvidia.com/tegra-public-appnotes/host1x.html
* @url https://github.com/Jetson-TX1-AndroidTV/android_kernel_jetson_tx1_hdmi_primary/blob/jetson-tx1/drivers/video/tegra/host/nvhost_syncpt.c

View File

@ -28,7 +28,7 @@ namespace skyline::vfs {
* @param size The size of the file to create
* @return Whether creating the file succeeded
*/
virtual bool CreateFile(std::string path, size_t size) {
virtual bool CreateFile(const std::string &path, size_t size) {
throw exception("This filesystem does not support creating files");
};
@ -38,7 +38,7 @@ namespace skyline::vfs {
* @param parents Whether all parent directories in the given path should be created
* @return Whether creating the directory succeeded
*/
virtual bool CreateDirectory(std::string path, bool parents) {
virtual bool CreateDirectory(const std::string &path, bool parents) {
throw exception("This filesystem does not support creating directories");
};
@ -48,21 +48,21 @@ namespace skyline::vfs {
* @param mode The mode to open the file with
* @return A shared pointer to a Backing object of the file
*/
virtual std::shared_ptr<Backing> OpenFile(std::string path, Backing::Mode mode = {true, false, false}) = 0;
virtual std::shared_ptr<Backing> OpenFile(const std::string &path, Backing::Mode mode = {true, false, false}) = 0;
/**
* @brief Queries the type of the entry given by path
* @param path The path to the entry
* @return The type of the entry, if present
*/
virtual std::optional<Directory::EntryType> GetEntryType(std::string path) = 0;
virtual std::optional<Directory::EntryType> GetEntryType(const std::string &path) = 0;
/**
* @brief Checks if a given file exists in a filesystem
* @param path The path to the file
* @return Whether the file exists
*/
inline bool FileExists(std::string path) {
inline bool FileExists(const std::string &path) {
auto entry = GetEntryType(path);
return entry && *entry == Directory::EntryType::File;
}
@ -72,7 +72,7 @@ namespace skyline::vfs {
* @param path The path to the directory
* @return Whether the directory exists
*/
inline bool DirectoryExists(std::string path) {
inline bool DirectoryExists(const std::string &path) {
auto entry = GetEntryType(path);
return entry && *entry == Directory::EntryType::Directory;
}
@ -83,7 +83,7 @@ namespace skyline::vfs {
* @param listMode The list mode for the directory
* @return A shared pointer to a Directory object of the directory
*/
virtual std::shared_ptr<Directory> OpenDirectory(std::string path, Directory::ListMode listMode) {
virtual std::shared_ptr<Directory> OpenDirectory(const std::string &path, Directory::ListMode listMode) {
throw exception("This filesystem does not support opening directories");
};
};

View File

@ -10,13 +10,13 @@
#include "os_filesystem.h"
namespace skyline::vfs {
OsFileSystem::OsFileSystem(std::string basePath) : FileSystem(), basePath(basePath) {
OsFileSystem::OsFileSystem(const std::string &basePath) : FileSystem(), basePath(std::move(basePath)) {
if (!DirectoryExists(basePath))
if (!CreateDirectory(basePath, true))
throw exception("Error creating the OS filesystem backing directory");
}
bool OsFileSystem::CreateFile(std::string path, size_t size) {
bool OsFileSystem::CreateFile(const std::string &path, size_t size) {
auto fullPath = basePath + path;
// Create a directory that will hold the file
@ -39,7 +39,7 @@ namespace skyline::vfs {
return true;
}
bool OsFileSystem::CreateDirectory(std::string path, bool parents) {
bool OsFileSystem::CreateDirectory(const std::string &path, bool parents) {
if (!parents) {
int ret = mkdir(path.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
return ret == 0 || errno == EEXIST;
@ -59,7 +59,7 @@ namespace skyline::vfs {
return true;
}
std::shared_ptr<Backing> OsFileSystem::OpenFile(std::string path, Backing::Mode mode) {
std::shared_ptr<Backing> OsFileSystem::OpenFile(const std::string &path, Backing::Mode mode) {
if (!(mode.read || mode.write))
throw exception("Cannot open a file that is neither readable or writable");
@ -70,7 +70,7 @@ namespace skyline::vfs {
return std::make_shared<OsBacking>(fd, true, mode);
}
std::optional<Directory::EntryType> OsFileSystem::GetEntryType(std::string path) {
std::optional<Directory::EntryType> OsFileSystem::GetEntryType(const std::string &path) {
auto fullPath = basePath + path;
auto directory = opendir(fullPath.c_str());

View File

@ -14,14 +14,14 @@ namespace skyline::vfs {
std::string basePath; //!< The base path for filesystem operations
public:
OsFileSystem(std::string basePath);
OsFileSystem(const std::string &basePath);
bool CreateFile(std::string path, size_t size);
bool CreateFile(const std::string &path, size_t size);
bool CreateDirectory(std::string path, bool parents);
bool CreateDirectory(const std::string &path, bool parents);
std::shared_ptr<Backing> OpenFile(std::string path, Backing::Mode mode = {true, false, false});
std::shared_ptr<Backing> OpenFile(const std::string &path, Backing::Mode mode = {true, false, false});
std::optional<Directory::EntryType> GetEntryType(std::string path);
std::optional<Directory::EntryType> GetEntryType(const std::string &path);
};
}

View File

@ -31,7 +31,7 @@ namespace skyline::vfs {
}
}
std::shared_ptr<Backing> PartitionFileSystem::OpenFile(std::string path, Backing::Mode mode) {
std::shared_ptr<Backing> PartitionFileSystem::OpenFile(const std::string &path, Backing::Mode mode) {
try {
auto &entry = fileMap.at(path);
return std::make_shared<RegionBacking>(backing, fileDataOffset + entry.offset, entry.size, mode);
@ -40,14 +40,14 @@ namespace skyline::vfs {
}
}
std::optional<Directory::EntryType> PartitionFileSystem::GetEntryType(std::string path) {
std::optional<Directory::EntryType> PartitionFileSystem::GetEntryType(const std::string &path) {
if (fileMap.count(path))
return Directory::EntryType::File;
return std::nullopt;
}
std::shared_ptr<Directory> PartitionFileSystem::OpenDirectory(std::string path, Directory::ListMode listMode) {
std::shared_ptr<Directory> PartitionFileSystem::OpenDirectory(const std::string &path, Directory::ListMode listMode) {
// PFS doesn't have directories
if (path != "")
return nullptr;

View File

@ -52,11 +52,11 @@ namespace skyline::vfs {
public:
PartitionFileSystem(std::shared_ptr<Backing> backing);
std::shared_ptr<Backing> OpenFile(std::string path, Backing::Mode mode = {true, false, false});
std::shared_ptr<Backing> OpenFile(const std::string &path, Backing::Mode mode = {true, false, false});
std::optional<Directory::EntryType> GetEntryType(std::string path);
std::optional<Directory::EntryType> GetEntryType(const std::string &path);
std::shared_ptr<Directory> OpenDirectory(std::string path, Directory::ListMode listMode);
std::shared_ptr<Directory> OpenDirectory(const std::string &path, Directory::ListMode listMode);
};
/**

View File

@ -11,7 +11,7 @@ namespace skyline::vfs {
TraverseDirectory(0, "");
}
void RomFileSystem::TraverseFiles(u32 offset, std::string path) {
void RomFileSystem::TraverseFiles(u32 offset, const std::string &path) {
RomFsFileEntry entry{};
do {
@ -29,7 +29,7 @@ namespace skyline::vfs {
} while (offset != constant::RomFsEmptyEntry);
}
void RomFileSystem::TraverseDirectory(u32 offset, std::string path) {
void RomFileSystem::TraverseDirectory(u32 offset, const std::string &path) {
RomFsDirectoryEntry entry{};
backing->Read(&entry, header.dirMetaTableOffset + offset);
@ -52,7 +52,7 @@ namespace skyline::vfs {
TraverseDirectory(entry.siblingOffset, path);
}
std::shared_ptr<Backing> RomFileSystem::OpenFile(std::string path, Backing::Mode mode) {
std::shared_ptr<Backing> RomFileSystem::OpenFile(const std::string &path, Backing::Mode mode) {
try {
const auto &entry = fileMap.at(path);
return std::make_shared<RegionBacking>(backing, header.dataOffset + entry.offset, entry.size, mode);
@ -61,7 +61,7 @@ namespace skyline::vfs {
}
}
std::optional<Directory::EntryType> RomFileSystem::GetEntryType(std::string path) {
std::optional<Directory::EntryType> RomFileSystem::GetEntryType(const std::string &path) {
if (fileMap.count(path))
return Directory::EntryType::File;
else if (directoryMap.count(path))
@ -70,7 +70,7 @@ namespace skyline::vfs {
return std::nullopt;
}
std::shared_ptr<Directory> RomFileSystem::OpenDirectory(std::string path, Directory::ListMode listMode) {
std::shared_ptr<Directory> RomFileSystem::OpenDirectory(const std::string &path, Directory::ListMode listMode) {
try {
auto &entry = directoryMap.at(path);
return std::make_shared<RomFileSystemDirectory>(backing, header, entry, listMode);

View File

@ -23,14 +23,14 @@ namespace skyline {
* @param offset The offset of the file entry to traverses the siblings of
* @param path The path to the parent directory of the supplied file entry
*/
void TraverseFiles(u32 offset, std::string path);
void TraverseFiles(u32 offset, const std::string &path);
/**
* @brief Traverses the directories within the given directory, adds them to the directory map and calls TraverseFiles on them
* @param offset The offset of the directory entry to traverses the directories in
* @param path The path to the supplied directory entry
*/
void TraverseDirectory(u32 offset, std::string path);
void TraverseDirectory(u32 offset, const std::string &path);
public:
/**
@ -79,11 +79,11 @@ namespace skyline {
RomFileSystem(std::shared_ptr<Backing> backing);
std::shared_ptr<Backing> OpenFile(std::string path, Backing::Mode mode = {true, false, false});
std::shared_ptr<Backing> OpenFile(const std::string &path, Backing::Mode mode = {true, false, false});
std::optional<Directory::EntryType> GetEntryType(std::string path);
std::optional<Directory::EntryType> GetEntryType(const std::string &path);
std::shared_ptr<Directory> OpenDirectory(std::string path, Directory::ListMode listMode);
std::shared_ptr<Directory> OpenDirectory(const std::string &path, Directory::ListMode listMode);
};
/**