mirror of
https://github.com/skyline-emu/skyline.git
synced 2024-11-26 20:34:18 +01:00
Address review comments
This commit is contained in:
parent
ae131502c6
commit
e5264f7762
@ -26,6 +26,7 @@ namespace skyline::gpu {
|
|||||||
|
|
||||||
void GPU::Loop() {
|
void GPU::Loop() {
|
||||||
gpfifo.Run();
|
gpfifo.Run();
|
||||||
|
vsyncEvent->Signal();
|
||||||
|
|
||||||
if (surfaceUpdate) {
|
if (surfaceUpdate) {
|
||||||
if (Surface == nullptr)
|
if (Surface == nullptr)
|
||||||
|
@ -26,7 +26,7 @@ namespace skyline::gpu {
|
|||||||
u16 method;
|
u16 method;
|
||||||
u32 argument;
|
u32 argument;
|
||||||
u32 subChannel;
|
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 {
|
namespace engine {
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
namespace skyline {
|
namespace skyline {
|
||||||
namespace constant {
|
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 {
|
namespace gpu::engine {
|
||||||
@ -23,8 +23,11 @@ namespace skyline {
|
|||||||
* @brief This holds the GPFIFO engine's registers
|
* @brief This holds the GPFIFO engine's registers
|
||||||
* @url https://github.com/NVIDIA/open-gpu-doc/blob/ab27fc22db5de0d02a4cabe08e555663b62db4d4/classes/host/clb06f.h#L65
|
* @url https://github.com/NVIDIA/open-gpu-doc/blob/ab27fc22db5de0d02a4cabe08e555663b62db4d4/classes/host/clb06f.h#L65
|
||||||
*/
|
*/
|
||||||
union Regs {
|
#pragma pack(push, 1)
|
||||||
enum class SemaphoreOperation {
|
union Registers {
|
||||||
|
std::array<u32, constant::GpfifoRegisterCount> raw;
|
||||||
|
|
||||||
|
enum class SemaphoreOperation : u8 {
|
||||||
Acquire = 1,
|
Acquire = 1,
|
||||||
Release = 2,
|
Release = 2,
|
||||||
AcqGeq = 4,
|
AcqGeq = 4,
|
||||||
@ -32,22 +35,22 @@ namespace skyline {
|
|||||||
Reduction = 16
|
Reduction = 16
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class SemaphoreAcquireSwitch {
|
enum class SemaphoreAcquireSwitch : u8 {
|
||||||
Disabled = 0,
|
Disabled = 0,
|
||||||
Enabled = 1
|
Enabled = 1
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class SemaphoreReleaseWfi {
|
enum class SemaphoreReleaseWfi : u8 {
|
||||||
En = 0,
|
En = 0,
|
||||||
Dis = 1
|
Dis = 1
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class SemaphoreReleaseSize {
|
enum class SemaphoreReleaseSize : u8 {
|
||||||
SixteenBytes = 0,
|
SixteenBytes = 0,
|
||||||
FourBytes = 1
|
FourBytes = 1
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class SemaphoreReduction {
|
enum class SemaphoreReduction : u8 {
|
||||||
Min = 0,
|
Min = 0,
|
||||||
Max = 1,
|
Max = 1,
|
||||||
Xor = 2,
|
Xor = 2,
|
||||||
@ -58,32 +61,32 @@ namespace skyline {
|
|||||||
Dec = 7
|
Dec = 7
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class SemaphoreFormat {
|
enum class SemaphoreFormat : u8 {
|
||||||
Signed = 0,
|
Signed = 0,
|
||||||
Unsigned = 1
|
Unsigned = 1
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class MemOpTlbInvalidatePdb {
|
enum class MemOpTlbInvalidatePdb : u8 {
|
||||||
One = 0,
|
One = 0,
|
||||||
All = 1
|
All = 1
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class SyncpointOperation {
|
enum class SyncpointOperation : u8 {
|
||||||
Wait = 0,
|
Wait = 0,
|
||||||
Incr = 1
|
Incr = 1
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class SyncpointWaitSwitch {
|
enum class SyncpointWaitSwitch : u8 {
|
||||||
Dis = 0,
|
Dis = 0,
|
||||||
En = 1
|
En = 1
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class WfiScope {
|
enum class WfiScope : u8 {
|
||||||
CurrentScgType = 0,
|
CurrentScgType = 0,
|
||||||
All = 1
|
All = 1
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class YieldOp {
|
enum class YieldOp : u8 {
|
||||||
Nop = 0,
|
Nop = 0,
|
||||||
PbdmaTimeslice = 1,
|
PbdmaTimeslice = 1,
|
||||||
RunlistTimeslice = 2,
|
RunlistTimeslice = 2,
|
||||||
@ -93,8 +96,8 @@ namespace skyline {
|
|||||||
struct {
|
struct {
|
||||||
struct {
|
struct {
|
||||||
u16 nvClass : 16;
|
u16 nvClass : 16;
|
||||||
u16 engine : 5;
|
u8 engine : 5;
|
||||||
u32 _pad_ : 11;
|
u16 _pad_ : 11;
|
||||||
} setObject;
|
} setObject;
|
||||||
|
|
||||||
u32 illegal;
|
u32 illegal;
|
||||||
@ -114,7 +117,7 @@ namespace skyline {
|
|||||||
|
|
||||||
u32 payload;
|
u32 payload;
|
||||||
|
|
||||||
struct __attribute__((__packed__)) {
|
struct {
|
||||||
SemaphoreOperation operation : 5;
|
SemaphoreOperation operation : 5;
|
||||||
u8 _pad2_ : 7;
|
u8 _pad2_ : 7;
|
||||||
SemaphoreAcquireSwitch acquireSwitch : 1;
|
SemaphoreAcquireSwitch acquireSwitch : 1;
|
||||||
@ -140,7 +143,7 @@ namespace skyline {
|
|||||||
struct {
|
struct {
|
||||||
u32 payload;
|
u32 payload;
|
||||||
|
|
||||||
struct __attribute__((__packed__)) {
|
struct {
|
||||||
SyncpointOperation operation : 1;
|
SyncpointOperation operation : 1;
|
||||||
u8 _pad0_ : 3;
|
u8 _pad0_ : 3;
|
||||||
SyncpointWaitSwitch waitSwitch : 1;
|
SyncpointWaitSwitch waitSwitch : 1;
|
||||||
@ -162,9 +165,9 @@ namespace skyline {
|
|||||||
u32 _pad_ : 30;
|
u32 _pad_ : 30;
|
||||||
} yield;
|
} yield;
|
||||||
};
|
};
|
||||||
std::array<u32, constant::GpfifoRegisterSize> raw;
|
} registers{};
|
||||||
} regs{};
|
static_assert(sizeof(Registers) == (constant::GpfifoRegisterCount * sizeof(u32)));
|
||||||
static_assert(sizeof(Regs) == (constant::GpfifoRegisterSize << 2));
|
#pragma pack(pop)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
GPFIFO(const DeviceState &state) : Engine(state) {}
|
GPFIFO(const DeviceState &state) : Engine(state) {}
|
||||||
@ -172,7 +175,7 @@ namespace skyline {
|
|||||||
void CallMethod(MethodParams params) {
|
void CallMethod(MethodParams params) {
|
||||||
state.logger->Debug("Called method in GPFIFO: 0x{:X} args: 0x{:X}", params.method, params.argument);
|
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;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -11,72 +11,76 @@ namespace skyline::gpu::engine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Maxwell3D::ResetRegs() {
|
void Maxwell3D::ResetRegs() {
|
||||||
memset(®s, 0, sizeof(regs));
|
registers = {};
|
||||||
|
|
||||||
regs.rasterizerEnable = true;
|
registers.rasterizerEnable = true;
|
||||||
|
|
||||||
for (auto &transform : regs.viewportTransform) {
|
for (auto &transform : registers.viewportTransform) {
|
||||||
transform.swizzles.x = Regs::ViewportTransform::Swizzle::PositiveX;
|
transform.swizzles.x = Registers::ViewportTransform::Swizzle::PositiveX;
|
||||||
transform.swizzles.y = Regs::ViewportTransform::Swizzle::PositiveY;
|
transform.swizzles.y = Registers::ViewportTransform::Swizzle::PositiveY;
|
||||||
transform.swizzles.z = Regs::ViewportTransform::Swizzle::PositiveZ;
|
transform.swizzles.z = Registers::ViewportTransform::Swizzle::PositiveZ;
|
||||||
transform.swizzles.w = Regs::ViewportTransform::Swizzle::PositiveW;
|
transform.swizzles.w = Registers::ViewportTransform::Swizzle::PositiveW;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto &viewport : regs.viewport) {
|
for (auto &viewport : registers.viewport) {
|
||||||
viewport.depthRangeFar = 1.0f;
|
viewport.depthRangeFar = 1.0f;
|
||||||
viewport.depthRangeNear = 0.0f;
|
viewport.depthRangeNear = 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
regs.polygonMode.front = Regs::PolygonMode::Fill;
|
registers.polygonMode.front = Registers::PolygonMode::Fill;
|
||||||
regs.polygonMode.back = Regs::PolygonMode::Fill;
|
registers.polygonMode.back = Registers::PolygonMode::Fill;
|
||||||
|
|
||||||
regs.stencilFront.failOp = regs.stencilFront.zFailOp = regs.stencilFront.zPassOp = Regs::StencilOp::Keep;
|
registers.stencilFront.failOp = registers.stencilFront.zFailOp = registers.stencilFront.zPassOp = Registers::StencilOp::Keep;
|
||||||
regs.stencilFront.func.op = Regs::CompareOp::Always;
|
registers.stencilFront.compare.op = Registers::CompareOp::Always;
|
||||||
regs.stencilFront.func.mask = 0xFFFFFFFF;
|
registers.stencilFront.compare.mask = 0xFFFFFFFF;
|
||||||
regs.stencilFront.mask = 0xFFFFFFFF;
|
registers.stencilFront.writeMask = 0xFFFFFFFF;
|
||||||
|
|
||||||
regs.stencilBack.stencilTwoSideEnable = true;
|
registers.stencilTwoSideEnable = true;
|
||||||
regs.stencilBack.failOp = regs.stencilBack.zFailOp = regs.stencilBack.zPassOp = Regs::StencilOp::Keep;
|
registers.stencilBack.failOp = registers.stencilBack.zFailOp = registers.stencilBack.zPassOp = Registers::StencilOp::Keep;
|
||||||
regs.stencilBack.funcOp = Regs::CompareOp::Always;
|
registers.stencilBack.compareOp = Registers::CompareOp::Always;
|
||||||
regs.stencilBackExtra.funcMask = 0xFFFFFFFF;
|
registers.stencilBackExtra.compareMask = 0xFFFFFFFF;
|
||||||
regs.stencilBackExtra.mask = 0xFFFFFFFF;
|
registers.stencilBackExtra.writeMask = 0xFFFFFFFF;
|
||||||
|
|
||||||
regs.rtSeparateFragData = true;
|
registers.rtSeparateFragData = true;
|
||||||
|
|
||||||
for (auto &attribute : regs.vertexAttributeState)
|
for (auto &attribute : registers.vertexAttributeState)
|
||||||
attribute.fixed = true;
|
attribute.fixed = true;
|
||||||
|
|
||||||
regs.depthTestFunc = Regs::CompareOp::Always;
|
registers.depthTestFunc = Registers::CompareOp::Always;
|
||||||
|
|
||||||
regs.blend.colorOp = regs.blend.alphaOp = Regs::Blend::Op::Add;
|
registers.blend.colorOp = registers.blend.alphaOp = Registers::Blend::Op::Add;
|
||||||
regs.blend.colorSrcFactor = regs.blend.alphaSrcFactor = Regs::Blend::Factor::One;
|
registers.blend.colorSrcFactor = registers.blend.alphaSrcFactor = Registers::Blend::Factor::One;
|
||||||
regs.blend.colorDestFactor = regs.blend.alphaDestFactor = Regs::Blend::Factor::Zero;
|
registers.blend.colorDestFactor = registers.blend.alphaDestFactor = Registers::Blend::Factor::Zero;
|
||||||
|
|
||||||
regs.lineWidthSmooth = 1.0f;
|
registers.lineWidthSmooth = 1.0f;
|
||||||
regs.lineWidthAliased = 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;
|
registers.frontFace = Registers::FrontFace::CounterClockwise;
|
||||||
regs.cullFace = Regs::CullFace::Back;
|
registers.cullFace = Registers::CullFace::Back;
|
||||||
|
|
||||||
for (auto &mask : regs.colorMask)
|
for (auto &mask : registers.colorMask)
|
||||||
mask.r = mask.g = mask.b = mask.a = 1;
|
mask.r = mask.g = mask.b = mask.a = 1;
|
||||||
|
|
||||||
for (auto &blend : regs.independentBlend) {
|
for (auto &blend : registers.independentBlend) {
|
||||||
blend.colorOp = blend.alphaOp = Regs::Blend::Op::Add;
|
blend.colorOp = blend.alphaOp = Registers::Blend::Op::Add;
|
||||||
blend.colorSrcFactor = blend.alphaSrcFactor = Regs::Blend::Factor::One;
|
blend.colorSrcFactor = blend.alphaSrcFactor = Registers::Blend::Factor::One;
|
||||||
blend.colorDestFactor = blend.alphaDestFactor = Regs::Blend::Factor::Zero;
|
blend.colorDestFactor = blend.alphaDestFactor = Registers::Blend::Factor::Zero;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
registers.viewportTransformEnable = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Maxwell3D::CallMethod(MethodParams params) {
|
void Maxwell3D::CallMethod(MethodParams params) {
|
||||||
state.logger->Debug("Called method in Maxwell 3D: 0x{:X} args: 0x{:X}", params.method, params.argument);
|
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
|
// 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))
|
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);
|
macroInvocation.arguments.push_back(params.argument);
|
||||||
|
|
||||||
@ -90,58 +94,58 @@ namespace skyline::gpu::engine {
|
|||||||
return;
|
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)
|
if (shadowRegisters.mme.shadowRamControl == Registers::MmeShadowRamControl::MethodTrack || shadowRegisters.mme.shadowRamControl == Registers::MmeShadowRamControl::MethodTrackWithFilter)
|
||||||
shadowRegs.raw[params.method] = params.argument;
|
shadowRegisters.raw[params.method] = params.argument;
|
||||||
else if (shadowRegs.mme.shadowRamControl == Regs::MmeShadowRamControl::MethodReplay)
|
else if (shadowRegisters.mme.shadowRamControl == Registers::MmeShadowRamControl::MethodReplay)
|
||||||
params.argument = shadowRegs.raw[params.method];
|
params.argument = shadowRegisters.raw[params.method];
|
||||||
|
|
||||||
switch (params.method) {
|
switch (params.method) {
|
||||||
case MAXWELL3D_OFFSET(mme.instructionRamLoad):
|
case MAXWELL3D_OFFSET(mme.instructionRamLoad):
|
||||||
if (regs.mme.instructionRamPointer >= macroCode.size())
|
if (registers.mme.instructionRamPointer >= macroCode.size())
|
||||||
throw exception("Macro memory is full!");
|
throw exception("Macro memory is full!");
|
||||||
|
|
||||||
macroCode[regs.mme.instructionRamPointer++] = params.argument;
|
macroCode[registers.mme.instructionRamPointer++] = params.argument;
|
||||||
break;
|
break;
|
||||||
case MAXWELL3D_OFFSET(mme.startAddressRamLoad):
|
case MAXWELL3D_OFFSET(mme.startAddressRamLoad):
|
||||||
if (regs.mme.startAddressRamPointer >= macroPositions.size())
|
if (registers.mme.startAddressRamPointer >= macroPositions.size())
|
||||||
throw exception("Maximum amount of macros reached!");
|
throw exception("Maximum amount of macros reached!");
|
||||||
|
|
||||||
macroPositions[regs.mme.startAddressRamPointer++] = params.argument;
|
macroPositions[registers.mme.startAddressRamPointer++] = params.argument;
|
||||||
break;
|
break;
|
||||||
case MAXWELL3D_OFFSET(mme.shadowRamControl):
|
case MAXWELL3D_OFFSET(mme.shadowRamControl):
|
||||||
shadowRegs.mme.shadowRamControl = static_cast<Regs::MmeShadowRamControl>(params.argument);
|
shadowRegisters.mme.shadowRamControl = static_cast<Registers::MmeShadowRamControl>(params.argument);
|
||||||
break;
|
break;
|
||||||
case MAXWELL3D_OFFSET(syncpointAction):
|
case MAXWELL3D_OFFSET(syncpointAction):
|
||||||
state.gpu->syncpoints.at(regs.syncpointAction.id).Increment();
|
state.gpu->syncpoints.at(registers.syncpointAction.id).Increment();
|
||||||
break;
|
break;
|
||||||
case MAXWELL3D_OFFSET(semaphore.info):
|
case MAXWELL3D_OFFSET(semaphore.info):
|
||||||
switch (regs.semaphore.info.op) {
|
switch (registers.semaphore.info.op) {
|
||||||
case Regs::SemaphoreInfo::Op::Release:
|
case Registers::SemaphoreInfo::Op::Release:
|
||||||
WriteSemaphoreResult(regs.semaphore.payload);
|
WriteSemaphoreResult(registers.semaphore.payload);
|
||||||
break;
|
break;
|
||||||
case Regs::SemaphoreInfo::Op::Counter:
|
case Registers::SemaphoreInfo::Op::Counter:
|
||||||
HandleSemaphoreCounterOperation();
|
HandleSemaphoreCounterOperation();
|
||||||
break;
|
break;
|
||||||
default:
|
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;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case MAXWELL3D_OFFSET(firmwareCall[4]):
|
case MAXWELL3D_OFFSET(firmwareCall[4]):
|
||||||
regs.raw[0xd00] = 1;
|
registers.raw[0xd00] = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Maxwell3D::HandleSemaphoreCounterOperation() {
|
void Maxwell3D::HandleSemaphoreCounterOperation() {
|
||||||
switch (regs.semaphore.info.counterType) {
|
switch (registers.semaphore.info.counterType) {
|
||||||
case Regs::SemaphoreInfo::CounterType::Zero:
|
case Registers::SemaphoreInfo::CounterType::Zero:
|
||||||
WriteSemaphoreResult(0);
|
WriteSemaphoreResult(0);
|
||||||
break;
|
break;
|
||||||
default:
|
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;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -152,11 +156,11 @@ namespace skyline::gpu::engine {
|
|||||||
u64 timestamp;
|
u64 timestamp;
|
||||||
};
|
};
|
||||||
|
|
||||||
switch (regs.semaphore.info.structureSize) {
|
switch (registers.semaphore.info.structureSize) {
|
||||||
case Regs::SemaphoreInfo::StructureSize::OneWord:
|
case Registers::SemaphoreInfo::StructureSize::OneWord:
|
||||||
state.gpu->memoryManager.Write<u32>(static_cast<u32>(result), regs.semaphore.address.Pack());
|
state.gpu->memoryManager.Write<u32>(static_cast<u32>(result), registers.semaphore.address.Pack());
|
||||||
break;
|
break;
|
||||||
case Regs::SemaphoreInfo::StructureSize::FourWords: {
|
case Registers::SemaphoreInfo::StructureSize::FourWords: {
|
||||||
// Convert the current nanosecond time to GPU ticks
|
// Convert the current nanosecond time to GPU ticks
|
||||||
constexpr u64 NsToTickNumerator = 384;
|
constexpr u64 NsToTickNumerator = 384;
|
||||||
constexpr u64 NsToTickDenominator = 625;
|
constexpr u64 NsToTickDenominator = 625;
|
||||||
@ -164,7 +168,7 @@ namespace skyline::gpu::engine {
|
|||||||
u64 nsTime = util::GetTimeNs();
|
u64 nsTime = util::GetTimeNs();
|
||||||
u64 timestamp = (nsTime / NsToTickDenominator) * NsToTickNumerator + ((nsTime % NsToTickDenominator) * NsToTickNumerator) / NsToTickDenominator;
|
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;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,11 +9,11 @@
|
|||||||
#include <gpu/macro_interpreter.h>
|
#include <gpu/macro_interpreter.h>
|
||||||
#include "engine.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 skyline {
|
||||||
namespace constant {
|
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 {
|
namespace gpu::engine {
|
||||||
@ -40,7 +40,10 @@ namespace skyline {
|
|||||||
* @brief This holds the Maxwell3D engine's register space
|
* @brief This holds the Maxwell3D engine's register space
|
||||||
* @url https://github.com/devkitPro/deko3d/blob/master/source/maxwell/engine_3d.def#L478
|
* @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 {
|
struct Address {
|
||||||
u32 high;
|
u32 high;
|
||||||
u32 low;
|
u32 low;
|
||||||
@ -77,7 +80,7 @@ namespace skyline {
|
|||||||
float translateY;
|
float translateY;
|
||||||
float translateZ;
|
float translateZ;
|
||||||
|
|
||||||
struct __attribute__((__packed__)) {
|
struct {
|
||||||
Swizzle x : 3;
|
Swizzle x : 3;
|
||||||
u8 _pad0_ : 1;
|
u8 _pad0_ : 1;
|
||||||
Swizzle y : 3;
|
Swizzle y : 3;
|
||||||
@ -88,7 +91,7 @@ namespace skyline {
|
|||||||
u32 _pad3_ : 17;
|
u32 _pad3_ : 17;
|
||||||
} swizzles;
|
} swizzles;
|
||||||
|
|
||||||
struct __attribute__((__packed__)) {
|
struct {
|
||||||
u8 x : 5;
|
u8 x : 5;
|
||||||
u8 _pad0_ : 3;
|
u8 _pad0_ : 3;
|
||||||
u8 y : 5;
|
u8 y : 5;
|
||||||
@ -120,6 +123,8 @@ namespace skyline {
|
|||||||
};
|
};
|
||||||
|
|
||||||
union VertexAttribute {
|
union VertexAttribute {
|
||||||
|
u32 raw;
|
||||||
|
|
||||||
enum class Size : u8 {
|
enum class Size : u8 {
|
||||||
Size_1x32 = 0x12,
|
Size_1x32 = 0x12,
|
||||||
Size_2x32 = 0x04,
|
Size_2x32 = 0x04,
|
||||||
@ -148,7 +153,7 @@ namespace skyline {
|
|||||||
Float = 7,
|
Float = 7,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct __attribute__((__packed__)) {
|
struct {
|
||||||
u8 bufferId : 5;
|
u8 bufferId : 5;
|
||||||
u8 _pad0_ : 1;
|
u8 _pad0_ : 1;
|
||||||
bool fixed : 1;
|
bool fixed : 1;
|
||||||
@ -158,8 +163,6 @@ namespace skyline {
|
|||||||
u8 _pad1_ : 1;
|
u8 _pad1_ : 1;
|
||||||
bool bgra : 1;
|
bool bgra : 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
u32 raw;
|
|
||||||
};
|
};
|
||||||
static_assert(sizeof(VertexAttribute) == sizeof(u32));
|
static_assert(sizeof(VertexAttribute) == sizeof(u32));
|
||||||
|
|
||||||
@ -275,19 +278,19 @@ namespace skyline {
|
|||||||
FrontAndBack = 0x408,
|
FrontAndBack = 0x408,
|
||||||
};
|
};
|
||||||
|
|
||||||
union ColorMask {
|
union ColorWriteMask {
|
||||||
struct __attribute__((__packed__)) {
|
u32 raw;
|
||||||
|
|
||||||
|
struct {
|
||||||
u8 r : 4;
|
u8 r : 4;
|
||||||
u8 g : 4;
|
u8 g : 4;
|
||||||
u8 b : 4;
|
u8 b : 4;
|
||||||
u8 a : 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 {
|
enum class Op : u8 {
|
||||||
Release = 0,
|
Release = 0,
|
||||||
Acquire = 1,
|
Acquire = 1,
|
||||||
@ -372,6 +375,11 @@ namespace skyline {
|
|||||||
};
|
};
|
||||||
static_assert(sizeof(SemaphoreInfo) == sizeof(u32));
|
static_assert(sizeof(SemaphoreInfo) == sizeof(u32));
|
||||||
|
|
||||||
|
enum class CoordOrigin : u8 {
|
||||||
|
LowerLeft = 0,
|
||||||
|
UpperLeft = 1
|
||||||
|
};
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
u32 _pad0_[0x40]; // 0x0
|
u32 _pad0_[0x40]; // 0x0
|
||||||
u32 noOperation; // 0x40
|
u32 noOperation; // 0x40
|
||||||
@ -412,9 +420,9 @@ namespace skyline {
|
|||||||
u32 _pad6_[0x68]; // 0x36d
|
u32 _pad6_[0x68]; // 0x36d
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
u32 funcRef; // 0x3d5
|
u32 compareRef; // 0x3d5
|
||||||
u32 mask; // 0x3d6
|
u32 writeMask; // 0x3d6
|
||||||
u32 funcMask; // 0x3d7
|
u32 compareMask; // 0x3d7
|
||||||
} stencilBackExtra;
|
} stencilBackExtra;
|
||||||
|
|
||||||
u32 _pad7_[0x13]; // 0x3d8
|
u32 _pad7_[0x13]; // 0x3d8
|
||||||
@ -461,9 +469,9 @@ namespace skyline {
|
|||||||
CompareOp op; // 0x4e4
|
CompareOp op; // 0x4e4
|
||||||
i32 ref; // 0x4e5
|
i32 ref; // 0x4e5
|
||||||
u32 mask; // 0x4e6
|
u32 mask; // 0x4e6
|
||||||
} func;
|
} compare;
|
||||||
|
|
||||||
u32 mask; // 0x4e7
|
u32 writeMask; // 0x4e7
|
||||||
} stencilFront;
|
} stencilFront;
|
||||||
|
|
||||||
u32 _pad11_[0x4]; // 0x4e8
|
u32 _pad11_[0x4]; // 0x4e8
|
||||||
@ -484,7 +492,7 @@ namespace skyline {
|
|||||||
u32 multisampleEnable; // 0x54d
|
u32 multisampleEnable; // 0x54d
|
||||||
u32 depthTargetEnable; // 0x54e
|
u32 depthTargetEnable; // 0x54e
|
||||||
|
|
||||||
struct __attribute__((__packed__)) {
|
struct {
|
||||||
bool alphaToCoverage : 1;
|
bool alphaToCoverage : 1;
|
||||||
u8 _pad0_ : 3;
|
u8 _pad0_ : 3;
|
||||||
bool alphaToOne : 1;
|
bool alphaToOne : 1;
|
||||||
@ -509,22 +517,34 @@ namespace skyline {
|
|||||||
|
|
||||||
u32 _pad18_[0x5]; // 0x560
|
u32 _pad18_[0x5]; // 0x560
|
||||||
|
|
||||||
struct {
|
|
||||||
u32 stencilTwoSideEnable; // 0x565
|
u32 stencilTwoSideEnable; // 0x565
|
||||||
|
|
||||||
|
struct {
|
||||||
StencilOp failOp; // 0x566
|
StencilOp failOp; // 0x566
|
||||||
StencilOp zFailOp; // 0x567
|
StencilOp zFailOp; // 0x567
|
||||||
StencilOp zPassOp; // 0x568
|
StencilOp zPassOp; // 0x568
|
||||||
CompareOp funcOp; // 0x569
|
CompareOp compareOp; // 0x569
|
||||||
} stencilBack;
|
} 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
|
u32 cullFaceEnable; // 0x646
|
||||||
FrontFace frontFace; // 0x647
|
FrontFace frontFace; // 0x647
|
||||||
CullFace cullFace; // 0x648
|
CullFace cullFace; // 0x648
|
||||||
u32 pixelCentreImage; // 0x649
|
u32 pixelCentreImage; // 0x649
|
||||||
u32 _pad20_[0x36]; // 0x64a
|
u32 _pad21_; // 0x64a
|
||||||
std::array<ColorMask, 8> colorMask; // 0x680 For each render target
|
u32 viewportTransformEnable; // 0x64b
|
||||||
u32 _pad21_[0x38]; // 0x688
|
u32 _pad22_[0x34]; // 0x64a
|
||||||
|
std::array<ColorWriteMask, 8> colorMask; // 0x680 For each render target
|
||||||
|
u32 _pad23_[0x38]; // 0x688
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
Address address; // 0x6c0
|
Address address; // 0x6c0
|
||||||
@ -532,18 +552,17 @@ namespace skyline {
|
|||||||
SemaphoreInfo info; // 0x6c3
|
SemaphoreInfo info; // 0x6c3
|
||||||
} semaphore;
|
} semaphore;
|
||||||
|
|
||||||
u32 _pad22_[0xbc]; // 0x6c4
|
u32 _pad24_[0xbc]; // 0x6c4
|
||||||
std::array<Blend, 8> independentBlend; // 0x780 For each render target
|
std::array<Blend, 8> independentBlend; // 0x780 For each render target
|
||||||
u32 _pad23_[0x100]; // 0x7c0
|
u32 _pad25_[0x100]; // 0x7c0
|
||||||
u32 firmwareCall[0x20]; // 0x8c0
|
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
|
Registers registers{}; //!< The maxwell 3D register space
|
||||||
Regs shadowRegs{}; //!< The shadow registers, their function is controlled by the 'shadowRamControl' register
|
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
|
std::array<u32, 0x10000> macroCode{}; //!< This is used to store GPU macros, the 256kb size is from Ryujinx
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@ namespace skyline::gpu::gpfifo {
|
|||||||
|
|
||||||
state.logger->Info("Bound GPU engine 0x{:X} to subchannel {}", params.argument, params.subChannel);
|
state.logger->Info("Bound GPU engine 0x{:X} to subchannel {}", params.argument, params.subChannel);
|
||||||
return;
|
return;
|
||||||
} else if (params.method < constant::GpfifoRegisterSize) {
|
} else if (params.method < constant::GpfifoRegisterCount) {
|
||||||
gpfifoEngine.CallMethod(params);
|
gpfifoEngine.CallMethod(params);
|
||||||
} else {
|
} else {
|
||||||
if (subchannels.at(params.subChannel) == nullptr)
|
if (subchannels.at(params.subChannel) == nullptr)
|
||||||
|
@ -18,18 +18,19 @@ namespace skyline::gpu {
|
|||||||
* @url https://github.com/NVIDIA/open-gpu-doc/blob/ab27fc22db5de0d02a4cabe08e555663b62db4d4/classes/host/clb06f.h#L155
|
* @url https://github.com/NVIDIA/open-gpu-doc/blob/ab27fc22db5de0d02a4cabe08e555663b62db4d4/classes/host/clb06f.h#L155
|
||||||
*/
|
*/
|
||||||
struct GpEntry {
|
struct GpEntry {
|
||||||
enum class Fetch {
|
enum class Fetch : u8 {
|
||||||
Unconditional = 0,
|
Unconditional = 0,
|
||||||
Conditional = 1,
|
Conditional = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
union {
|
union {
|
||||||
|
u32 entry0;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
Fetch fetch : 1;
|
Fetch fetch : 1;
|
||||||
u8 _pad_ : 1;
|
u8 _pad_ : 1;
|
||||||
u32 get : 30;
|
u32 get : 30;
|
||||||
};
|
};
|
||||||
u32 entry0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class Opcode : u8 {
|
enum class Opcode : u8 {
|
||||||
@ -39,36 +40,38 @@ namespace skyline::gpu {
|
|||||||
PbCrc = 3,
|
PbCrc = 3,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class Priv {
|
enum class Priv : u8 {
|
||||||
User = 0,
|
User = 0,
|
||||||
Kernel = 1,
|
Kernel = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class Level {
|
enum class Level : u8 {
|
||||||
Main = 0,
|
Main = 0,
|
||||||
Subroutine = 1,
|
Subroutine = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class Sync {
|
enum class Sync : u8 {
|
||||||
Proceed = 0,
|
Proceed = 0,
|
||||||
Wait = 1,
|
Wait = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
union {
|
union {
|
||||||
|
u32 entry1;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
union {
|
union {
|
||||||
u8 getHi;
|
u8 getHi;
|
||||||
Opcode opcode;
|
Opcode opcode;
|
||||||
};
|
};
|
||||||
|
|
||||||
Priv priv : 1;
|
Priv priv : 1;
|
||||||
Level level : 1;
|
Level level : 1;
|
||||||
u32 size : 21;
|
u32 size : 21;
|
||||||
Sync sync : 1;
|
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
|
* @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
|
* @url https://github.com/NVIDIA/open-gpu-doc/blob/ab27fc22db5de0d02a4cabe08e555663b62db4d4/classes/host/clb06f.h#L179
|
||||||
*/
|
*/
|
||||||
union PushBufferMethodHeader {
|
union PushBufferMethodHeader {
|
||||||
|
u32 raw;
|
||||||
|
|
||||||
enum class TertOp : u8 {
|
enum class TertOp : u8 {
|
||||||
Grp0IncMethod = 0,
|
Grp0IncMethod = 0,
|
||||||
Grp0SetSubDevMask = 1,
|
Grp0SetSubDevMask = 1,
|
||||||
@ -95,8 +100,6 @@ namespace skyline::gpu {
|
|||||||
EndPbSegment = 7
|
EndPbSegment = 7
|
||||||
};
|
};
|
||||||
|
|
||||||
struct {
|
|
||||||
union {
|
|
||||||
u16 methodAddress : 12;
|
u16 methodAddress : 12;
|
||||||
struct {
|
struct {
|
||||||
u8 _pad0_ : 4;
|
u8 _pad0_ : 4;
|
||||||
@ -118,10 +121,7 @@ namespace skyline::gpu {
|
|||||||
SecOp secOp : 3;
|
SecOp secOp : 3;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
static_assert(sizeof(PushBufferMethodHeader) == sizeof(u32));
|
||||||
u32 entry;
|
|
||||||
};
|
|
||||||
static_assert(sizeof(PushBufferMethodHeader) == 0x4);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The GPFIFO class handles creating pushbuffers from GP entries and then processing them
|
* @brief The GPFIFO class handles creating pushbuffers from GP entries and then processing them
|
||||||
|
@ -67,7 +67,7 @@ namespace skyline::gpu {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Opcode::Operation::ReadImmediate: {
|
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);
|
HandleAssignment(opcode->assignmentOperation, opcode->dest, result);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -10,12 +10,18 @@ namespace skyline::gpu {
|
|||||||
class Maxwell3D;
|
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 {
|
class MacroInterpreter {
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
* @brief This holds a single macro opcode
|
* @brief This holds a single macro opcode
|
||||||
*/
|
*/
|
||||||
|
#pragma pack(push, 1)
|
||||||
union Opcode {
|
union Opcode {
|
||||||
|
u32 raw;
|
||||||
|
|
||||||
enum class Operation : u8 {
|
enum class Operation : u8 {
|
||||||
AluRegister = 0,
|
AluRegister = 0,
|
||||||
AddImmediate = 1,
|
AddImmediate = 1,
|
||||||
@ -54,16 +60,16 @@ namespace skyline::gpu {
|
|||||||
NonZero = 1,
|
NonZero = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct __attribute__((__packed__)) {
|
struct {
|
||||||
Operation operation : 3;
|
Operation operation : 3;
|
||||||
u8 _pad0_ : 1;
|
u8 _pad0_ : 1;
|
||||||
AssignmentOperation assignmentOperation : 3;
|
AssignmentOperation assignmentOperation : 3;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct __attribute__((__packed__)) {
|
struct {
|
||||||
u8 _pad1_ : 4;
|
u8 _pad1_ : 4;
|
||||||
BranchCondition branchCondition : 1;
|
BranchCondition branchCondition : 1;
|
||||||
u8 noDelay : 1;
|
bool noDelay : 1;
|
||||||
u8 _pad2_ : 1;
|
u8 _pad2_ : 1;
|
||||||
u8 exit : 1;
|
u8 exit : 1;
|
||||||
u8 dest : 3;
|
u8 dest : 3;
|
||||||
@ -72,12 +78,12 @@ namespace skyline::gpu {
|
|||||||
AluOperation aluOperation : 5;
|
AluOperation aluOperation : 5;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct __attribute__((__packed__)) {
|
struct {
|
||||||
u16 _pad3_ : 14;
|
u16 _pad3_ : 14;
|
||||||
i32 immediate : 18;
|
i32 immediate : 18;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct __attribute__((__packed__)) {
|
struct {
|
||||||
u32 _pad_ : 17;
|
u32 _pad_ : 17;
|
||||||
u8 srcBit : 5;
|
u8 srcBit : 5;
|
||||||
u8 size : 5;
|
u8 size : 5;
|
||||||
@ -87,21 +93,20 @@ namespace skyline::gpu {
|
|||||||
return (1 << size) - 1;
|
return (1 << size) - 1;
|
||||||
}
|
}
|
||||||
} bitfield;
|
} bitfield;
|
||||||
|
|
||||||
u32 raw;
|
|
||||||
};
|
};
|
||||||
|
#pragma pack(pop)
|
||||||
static_assert(sizeof(Opcode) == sizeof(u32));
|
static_assert(sizeof(Opcode) == sizeof(u32));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief This holds information about the Maxwell 3D method to be called in 'Send'
|
* @brief This holds information about the Maxwell 3D method to be called in 'Send'
|
||||||
*/
|
*/
|
||||||
union MethodAddress {
|
union MethodAddress {
|
||||||
|
u32 raw;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
u16 address : 12;
|
u16 address : 12;
|
||||||
u8 increment : 6;
|
u8 increment : 6;
|
||||||
};
|
};
|
||||||
|
|
||||||
u32 raw;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
engine::Maxwell3D &maxwell3D;
|
engine::Maxwell3D &maxwell3D;
|
||||||
|
@ -97,8 +97,8 @@ namespace skyline::gpu::vmm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
u64 MemoryManager::ReserveFixed(u64 address, u64 size) {
|
u64 MemoryManager::ReserveFixed(u64 address, u64 size) {
|
||||||
if ((address & (constant::GpuPageSize - 1)) != 0)
|
if (!util::IsAligned(address, constant::GpuPageSize))
|
||||||
return 0;
|
return false;
|
||||||
|
|
||||||
size = util::AlignUp(size, constant::GpuPageSize);
|
size = util::AlignUp(size, constant::GpuPageSize);
|
||||||
|
|
||||||
@ -120,8 +120,8 @@ namespace skyline::gpu::vmm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
u64 MemoryManager::MapFixed(u64 address, u64 cpuAddress, u64 size) {
|
u64 MemoryManager::MapFixed(u64 address, u64 cpuAddress, u64 size) {
|
||||||
if ((address & (constant::GpuPageSize - 1)) != 0)
|
if (!util::IsAligned(address, constant::GpuPageSize))
|
||||||
return 0;
|
return false;
|
||||||
|
|
||||||
size = util::AlignUp(size, constant::GpuPageSize);
|
size = util::AlignUp(size, constant::GpuPageSize);
|
||||||
|
|
||||||
@ -129,7 +129,7 @@ namespace skyline::gpu::vmm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool MemoryManager::Unmap(u64 address) {
|
bool MemoryManager::Unmap(u64 address) {
|
||||||
if ((address & (constant::GpuPageSize - 1)) != 0)
|
if (!util::IsAligned(address, constant::GpuPageSize))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
auto chunk = std::find_if(chunkList.begin(), chunkList.end(), [address](const ChunkDescriptor &chunk) -> bool {
|
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 {
|
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;
|
return address < chunk.address;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (chunk == chunkList.end() || chunk->state != ChunkState::Mapped)
|
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;
|
chunk--;
|
||||||
u64 destinationOffset{};
|
|
||||||
|
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
|
// 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) {
|
while (size) {
|
||||||
if (chunk == chunkList.end() || chunk->state != ChunkState::Mapped)
|
state.process->ReadMemory(destination + (initialSize - size), readAddress, readSize);
|
||||||
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;
|
size -= readSize;
|
||||||
destinationOffset += readSize;
|
if (size) {
|
||||||
chunk++;
|
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 {
|
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;
|
return address < chunk.address;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (chunk == chunkList.end() || chunk->state != ChunkState::Mapped)
|
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;
|
chunk--;
|
||||||
u64 sourceOffset{};
|
|
||||||
|
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
|
// 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) {
|
while (size) {
|
||||||
if (chunk == chunkList.end() || chunk->state != ChunkState::Mapped)
|
state.process->WriteMemory(source + (initialSize - size), writeAddress, writeSize);
|
||||||
throw exception("Failed to write to region in GPU address space - address: {#:X} size: {#:X}", address, size);
|
|
||||||
|
|
||||||
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;
|
size -= writeSize;
|
||||||
sourceOffset += writeSize;
|
if (size) {
|
||||||
chunk++;
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -47,7 +47,6 @@ namespace skyline {
|
|||||||
class MemoryManager {
|
class MemoryManager {
|
||||||
private:
|
private:
|
||||||
const DeviceState &state;
|
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
|
* @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:
|
public:
|
||||||
MemoryManager(const DeviceState &state);
|
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
|
* @brief This reserves a region of the GPU address space so it will not be chosen automatically when mapping
|
||||||
|
@ -7,10 +7,13 @@
|
|||||||
|
|
||||||
namespace skyline {
|
namespace skyline {
|
||||||
namespace constant {
|
namespace constant {
|
||||||
constexpr size_t MaxHwSyncpointCount = 192;
|
constexpr size_t MaxHwSyncpointCount = 192; //!< The maximum number of HOST1X syncpoints on t210
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace gpu {
|
namespace gpu {
|
||||||
|
/**
|
||||||
|
* @brief The Syncpoint class represents a single syncpoint in the GPU which is used for GPU -> CPU synchronisation
|
||||||
|
*/
|
||||||
class Syncpoint {
|
class Syncpoint {
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <common.h>
|
#include <common.h>
|
||||||
#include "devices/nvhost_syncpoint.h"
|
#include <services/nvdrv/devices/nvhost_syncpoint.h>
|
||||||
|
|
||||||
namespace skyline::service::nvdrv {
|
namespace skyline::service::nvdrv {
|
||||||
/**
|
/**
|
@ -29,7 +29,7 @@ namespace skyline::service::fssrv {
|
|||||||
void Write(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
|
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);
|
void Flush(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
#include <os.h>
|
#include <os.h>
|
||||||
#include <kernel/types/KProcess.h>
|
#include <kernel/types/KProcess.h>
|
||||||
#include <services/nvdrv/INvDrvServices.h>
|
#include <services/nvdrv/INvDrvServices.h>
|
||||||
#include <services/nvdrv/fence.h>
|
#include <services/common/fence.h>
|
||||||
#include <gpu/format.h>
|
#include <gpu/format.h>
|
||||||
#include "IHOSBinderDriver.h"
|
#include "IHOSBinderDriver.h"
|
||||||
#include "display.h"
|
#include "display.h"
|
||||||
|
@ -126,6 +126,8 @@ namespace skyline::service::nvdrv::device {
|
|||||||
u32 pages;
|
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)};
|
size_t entryCount{buffer.input.at(0).size / sizeof(Entry)};
|
||||||
std::span entries(state.process->GetPointer<Entry>(buffer.input.at(0).address), entryCount);
|
std::span entries(state.process->GetPointer<Entry>(buffer.input.at(0).address), entryCount);
|
||||||
|
|
||||||
@ -133,9 +135,9 @@ namespace skyline::service::nvdrv::device {
|
|||||||
try {
|
try {
|
||||||
auto nvmap = state.os->serviceManager.GetService<nvdrv::INvDrvServices>(Service::nvdrv_INvDrvServices)->GetDevice<nvdrv::device::NvMap>(nvdrv::device::NvDeviceType::nvmap)->handleTable.at(entry.nvmapHandle);
|
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 mapAddress = static_cast<u64>(entry.gpuOffset) << MinAlignmentShift;
|
||||||
u64 mapPhysicalAddress = nvmap->address + (static_cast<u64>(entry.mapOffset) << 0x10);
|
u64 mapPhysicalAddress = nvmap->address + (static_cast<u64>(entry.mapOffset) << MinAlignmentShift);
|
||||||
u64 mapSize = static_cast<u64>(entry.pages) << 0x10;
|
u64 mapSize = static_cast<u64>(entry.pages) << MinAlignmentShift;
|
||||||
|
|
||||||
state.gpu->memoryManager.MapFixed(mapAddress, mapPhysicalAddress, mapSize);
|
state.gpu->memoryManager.MapFixed(mapAddress, mapPhysicalAddress, mapSize);
|
||||||
} catch (const std::exception &e) {
|
} catch (const std::exception &e) {
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <services/nvdrv/fence.h>
|
#include <services/common/fence.h>
|
||||||
#include "nvdevice.h"
|
#include "nvdevice.h"
|
||||||
|
|
||||||
namespace skyline::service::nvdrv::device {
|
namespace skyline::service::nvdrv::device {
|
||||||
|
@ -45,65 +45,6 @@ namespace skyline::service::nvdrv::device {
|
|||||||
{0x001F, NFUNC(NvHostCtrl::EventRegister)},
|
{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 NvHostCtrl::FindFreeEvent(u32 syncpointId) {
|
||||||
u32 eventIndex{constant::NvHostEventCount}; //!< Holds the index of the last populated event in the event array
|
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
|
u32 freeIndex{constant::NvHostEventCount}; //!< Holds the index of the first unused event id
|
||||||
@ -208,4 +149,65 @@ namespace skyline::service::nvdrv::device {
|
|||||||
return;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <services/nvdrv/fence.h>
|
#include <services/common/fence.h>
|
||||||
#include "nvdevice.h"
|
#include "nvdevice.h"
|
||||||
|
|
||||||
namespace skyline {
|
namespace skyline {
|
||||||
@ -12,6 +12,9 @@ namespace skyline {
|
|||||||
}
|
}
|
||||||
|
|
||||||
namespace service::nvdrv::device {
|
namespace service::nvdrv::device {
|
||||||
|
/**
|
||||||
|
* @brief This represents a single registered event with an attached fence
|
||||||
|
*/
|
||||||
class NvHostEvent {
|
class NvHostEvent {
|
||||||
private:
|
private:
|
||||||
u64 waiterId{};
|
u64 waiterId{};
|
||||||
@ -57,6 +60,8 @@ namespace skyline {
|
|||||||
* @brief This holds metadata about an event, it is used by QueryEvent and EventWait
|
* @brief This holds metadata about an event, it is used by QueryEvent and EventWait
|
||||||
*/
|
*/
|
||||||
union EventValue {
|
union EventValue {
|
||||||
|
u32 val;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
u8 _pad0_ : 4;
|
u8 _pad0_ : 4;
|
||||||
u32 syncpointIdAsync : 28;
|
u32 syncpointIdAsync : 28;
|
||||||
@ -71,8 +76,6 @@ namespace skyline {
|
|||||||
bool nonAsync : 1;
|
bool nonAsync : 1;
|
||||||
u8 _pad12_ : 3;
|
u8 _pad12_ : 3;
|
||||||
};
|
};
|
||||||
|
|
||||||
u32 val;
|
|
||||||
};
|
};
|
||||||
static_assert(sizeof(EventValue) == sizeof(u32));
|
static_assert(sizeof(EventValue) == sizeof(u32));
|
||||||
|
|
||||||
|
@ -9,7 +9,6 @@
|
|||||||
|
|
||||||
namespace skyline::service::nvdrv {
|
namespace skyline::service::nvdrv {
|
||||||
/**
|
/**
|
||||||
* @todo Implement the GPU side of this
|
|
||||||
* @brief NvHostSyncpoint handles allocating and accessing host1x syncpoints
|
* @brief NvHostSyncpoint handles allocating and accessing host1x syncpoints
|
||||||
* @url https://http.download.nvidia.com/tegra-public-appnotes/host1x.html
|
* @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
|
* @url https://github.com/Jetson-TX1-AndroidTV/android_kernel_jetson_tx1_hdmi_primary/blob/jetson-tx1/drivers/video/tegra/host/nvhost_syncpt.c
|
||||||
|
@ -28,7 +28,7 @@ namespace skyline::vfs {
|
|||||||
* @param size The size of the file to create
|
* @param size The size of the file to create
|
||||||
* @return Whether creating the file succeeded
|
* @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");
|
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
|
* @param parents Whether all parent directories in the given path should be created
|
||||||
* @return Whether creating the directory succeeded
|
* @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");
|
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
|
* @param mode The mode to open the file with
|
||||||
* @return A shared pointer to a Backing object of the file
|
* @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
|
* @brief Queries the type of the entry given by path
|
||||||
* @param path The path to the entry
|
* @param path The path to the entry
|
||||||
* @return The type of the entry, if present
|
* @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
|
* @brief Checks if a given file exists in a filesystem
|
||||||
* @param path The path to the file
|
* @param path The path to the file
|
||||||
* @return Whether the file exists
|
* @return Whether the file exists
|
||||||
*/
|
*/
|
||||||
inline bool FileExists(std::string path) {
|
inline bool FileExists(const std::string &path) {
|
||||||
auto entry = GetEntryType(path);
|
auto entry = GetEntryType(path);
|
||||||
return entry && *entry == Directory::EntryType::File;
|
return entry && *entry == Directory::EntryType::File;
|
||||||
}
|
}
|
||||||
@ -72,7 +72,7 @@ namespace skyline::vfs {
|
|||||||
* @param path The path to the directory
|
* @param path The path to the directory
|
||||||
* @return Whether the directory exists
|
* @return Whether the directory exists
|
||||||
*/
|
*/
|
||||||
inline bool DirectoryExists(std::string path) {
|
inline bool DirectoryExists(const std::string &path) {
|
||||||
auto entry = GetEntryType(path);
|
auto entry = GetEntryType(path);
|
||||||
return entry && *entry == Directory::EntryType::Directory;
|
return entry && *entry == Directory::EntryType::Directory;
|
||||||
}
|
}
|
||||||
@ -83,7 +83,7 @@ namespace skyline::vfs {
|
|||||||
* @param listMode The list mode for the directory
|
* @param listMode The list mode for the directory
|
||||||
* @return A shared pointer to a Directory object of 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");
|
throw exception("This filesystem does not support opening directories");
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -10,13 +10,13 @@
|
|||||||
#include "os_filesystem.h"
|
#include "os_filesystem.h"
|
||||||
|
|
||||||
namespace skyline::vfs {
|
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 (!DirectoryExists(basePath))
|
||||||
if (!CreateDirectory(basePath, true))
|
if (!CreateDirectory(basePath, true))
|
||||||
throw exception("Error creating the OS filesystem backing directory");
|
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;
|
auto fullPath = basePath + path;
|
||||||
|
|
||||||
// Create a directory that will hold the file
|
// Create a directory that will hold the file
|
||||||
@ -39,7 +39,7 @@ namespace skyline::vfs {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OsFileSystem::CreateDirectory(std::string path, bool parents) {
|
bool OsFileSystem::CreateDirectory(const std::string &path, bool parents) {
|
||||||
if (!parents) {
|
if (!parents) {
|
||||||
int ret = mkdir(path.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
|
int ret = mkdir(path.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
|
||||||
return ret == 0 || errno == EEXIST;
|
return ret == 0 || errno == EEXIST;
|
||||||
@ -59,7 +59,7 @@ namespace skyline::vfs {
|
|||||||
return true;
|
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))
|
if (!(mode.read || mode.write))
|
||||||
throw exception("Cannot open a file that is neither readable or writable");
|
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);
|
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 fullPath = basePath + path;
|
||||||
|
|
||||||
auto directory = opendir(fullPath.c_str());
|
auto directory = opendir(fullPath.c_str());
|
||||||
|
@ -14,14 +14,14 @@ namespace skyline::vfs {
|
|||||||
std::string basePath; //!< The base path for filesystem operations
|
std::string basePath; //!< The base path for filesystem operations
|
||||||
|
|
||||||
public:
|
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);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -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 {
|
try {
|
||||||
auto &entry = fileMap.at(path);
|
auto &entry = fileMap.at(path);
|
||||||
return std::make_shared<RegionBacking>(backing, fileDataOffset + entry.offset, entry.size, mode);
|
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))
|
if (fileMap.count(path))
|
||||||
return Directory::EntryType::File;
|
return Directory::EntryType::File;
|
||||||
|
|
||||||
return std::nullopt;
|
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
|
// PFS doesn't have directories
|
||||||
if (path != "")
|
if (path != "")
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -52,11 +52,11 @@ namespace skyline::vfs {
|
|||||||
public:
|
public:
|
||||||
PartitionFileSystem(std::shared_ptr<Backing> backing);
|
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);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -11,7 +11,7 @@ namespace skyline::vfs {
|
|||||||
TraverseDirectory(0, "");
|
TraverseDirectory(0, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
void RomFileSystem::TraverseFiles(u32 offset, std::string path) {
|
void RomFileSystem::TraverseFiles(u32 offset, const std::string &path) {
|
||||||
RomFsFileEntry entry{};
|
RomFsFileEntry entry{};
|
||||||
|
|
||||||
do {
|
do {
|
||||||
@ -29,7 +29,7 @@ namespace skyline::vfs {
|
|||||||
} while (offset != constant::RomFsEmptyEntry);
|
} while (offset != constant::RomFsEmptyEntry);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RomFileSystem::TraverseDirectory(u32 offset, std::string path) {
|
void RomFileSystem::TraverseDirectory(u32 offset, const std::string &path) {
|
||||||
RomFsDirectoryEntry entry{};
|
RomFsDirectoryEntry entry{};
|
||||||
backing->Read(&entry, header.dirMetaTableOffset + offset);
|
backing->Read(&entry, header.dirMetaTableOffset + offset);
|
||||||
|
|
||||||
@ -52,7 +52,7 @@ namespace skyline::vfs {
|
|||||||
TraverseDirectory(entry.siblingOffset, path);
|
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 {
|
try {
|
||||||
const auto &entry = fileMap.at(path);
|
const auto &entry = fileMap.at(path);
|
||||||
return std::make_shared<RegionBacking>(backing, header.dataOffset + entry.offset, entry.size, mode);
|
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))
|
if (fileMap.count(path))
|
||||||
return Directory::EntryType::File;
|
return Directory::EntryType::File;
|
||||||
else if (directoryMap.count(path))
|
else if (directoryMap.count(path))
|
||||||
@ -70,7 +70,7 @@ namespace skyline::vfs {
|
|||||||
return std::nullopt;
|
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 {
|
try {
|
||||||
auto &entry = directoryMap.at(path);
|
auto &entry = directoryMap.at(path);
|
||||||
return std::make_shared<RomFileSystemDirectory>(backing, header, entry, listMode);
|
return std::make_shared<RomFileSystemDirectory>(backing, header, entry, listMode);
|
||||||
|
@ -23,14 +23,14 @@ namespace skyline {
|
|||||||
* @param offset The offset of the file entry to traverses the siblings of
|
* @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
|
* @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
|
* @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 offset The offset of the directory entry to traverses the directories in
|
||||||
* @param path The path to the supplied directory entry
|
* @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:
|
public:
|
||||||
/**
|
/**
|
||||||
@ -79,11 +79,11 @@ namespace skyline {
|
|||||||
|
|
||||||
RomFileSystem(std::shared_ptr<Backing> backing);
|
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);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
Reference in New Issue
Block a user