Migrate Maxwell3D::Registers to OffsetMember

Maxwell3D registers were primarily written with absolute offsets and ended up being fairly messy due to attempting to emulate this using struct relative positioning resulting in a lot of pointless padding members. This has now been improved by utilizing `OffsetMember` to directly use offsets resulting in much neater code.
This commit is contained in:
PixelyIon 2021-11-10 21:31:45 +05:30
parent 69761389ff
commit fbfad21f03
3 changed files with 227 additions and 239 deletions

View File

@ -29,6 +29,16 @@ namespace skyline::soc::gm20b::engine::maxwell3d::type {
MethodReplay = 3, //!< Replays older tracked writes for any new writes to registers, discarding the contents of the new write MethodReplay = 3, //!< Replays older tracked writes for any new writes to registers, discarding the contents of the new write
}; };
struct SyncpointAction {
u16 id : 12;
u8 _pad0_ : 4;
bool flushCache : 1;
u8 _pad1_ : 3;
bool increment : 1;
u16 _pad2_ : 11;
};
static_assert(sizeof(SyncpointAction) == sizeof(u32));
constexpr static size_t RenderTargetCount{8}; //!< Maximum amount of render targets that can be bound at once on Maxwell 3D constexpr static size_t RenderTargetCount{8}; //!< Maximum amount of render targets that can be bound at once on Maxwell 3D
/** /**
@ -360,6 +370,14 @@ namespace skyline::soc::gm20b::engine::maxwell3d::type {
}; };
static_assert(sizeof(Blend) == (sizeof(u32) * 8)); static_assert(sizeof(Blend) == (sizeof(u32) * 8));
struct MultisampleControl {
bool alphaToCoverage : 1;
u8 _pad0_ : 3;
bool alphaToOne : 1;
u32 _pad1_ : 27;
};
static_assert(sizeof(MultisampleControl) == sizeof(u32));
enum class StencilOp : u32 { enum class StencilOp : u32 {
Keep = 1, Keep = 1,
Zero = 2, Zero = 2,
@ -371,6 +389,18 @@ namespace skyline::soc::gm20b::engine::maxwell3d::type {
DecrementAndWrap = 8, DecrementAndWrap = 8,
}; };
struct PointCoordReplace {
u8 _unk_ : 2;
enum class CoordOrigin : u8 {
LowerLeft = 0,
UpperLeft = 1,
};
CoordOrigin origin : 1;
u16 enable : 10;
u32 _pad_ : 19;
};
static_assert(sizeof(PointCoordReplace) == sizeof(u32));
enum class FrontFace : u32 { enum class FrontFace : u32 {
Clockwise = 0x900, Clockwise = 0x900,
CounterClockwise = 0x901, CounterClockwise = 0x901,
@ -495,10 +525,5 @@ namespace skyline::soc::gm20b::engine::maxwell3d::type {
}; };
static_assert(sizeof(SemaphoreInfo) == sizeof(u32)); static_assert(sizeof(SemaphoreInfo) == sizeof(u32));
enum class CoordOrigin : u8 {
LowerLeft = 0,
UpperLeft = 1,
};
#pragma pack(pop) #pragma pack(pop)
} }

View File

@ -16,57 +16,57 @@ namespace skyline::soc::gm20b::engine::maxwell3d {
registers.rasterizerEnable = true; registers.rasterizerEnable = true;
for (auto &transform : registers.viewportTransforms) { for (auto &transform : *registers.viewportTransforms) {
transform.swizzles.x = type::ViewportTransform::Swizzle::PositiveX; transform.swizzles.x = type::ViewportTransform::Swizzle::PositiveX;
transform.swizzles.y = type::ViewportTransform::Swizzle::PositiveY; transform.swizzles.y = type::ViewportTransform::Swizzle::PositiveY;
transform.swizzles.z = type::ViewportTransform::Swizzle::PositiveZ; transform.swizzles.z = type::ViewportTransform::Swizzle::PositiveZ;
transform.swizzles.w = type::ViewportTransform::Swizzle::PositiveW; transform.swizzles.w = type::ViewportTransform::Swizzle::PositiveW;
} }
for (auto &viewport : registers.viewports) { for (auto &viewport : *registers.viewports) {
viewport.depthRangeFar = 1.0f; viewport.depthRangeFar = 1.0f;
viewport.depthRangeNear = 0.0f; viewport.depthRangeNear = 0.0f;
} }
registers.polygonMode.front = type::PolygonMode::Fill; registers.polygonMode->front = type::PolygonMode::Fill;
registers.polygonMode.back = type::PolygonMode::Fill; registers.polygonMode->back = type::PolygonMode::Fill;
registers.stencilFront.failOp = registers.stencilFront.zFailOp = registers.stencilFront.zPassOp = type::StencilOp::Keep; registers.stencilFront->failOp = registers.stencilFront->zFailOp = registers.stencilFront->zPassOp = type::StencilOp::Keep;
registers.stencilFront.compare.op = type::CompareOp::Always; registers.stencilFront->compare.op = type::CompareOp::Always;
registers.stencilFront.compare.mask = 0xFFFFFFFF; registers.stencilFront->compare.mask = 0xFFFFFFFF;
registers.stencilFront.writeMask = 0xFFFFFFFF; registers.stencilFront->writeMask = 0xFFFFFFFF;
registers.stencilTwoSideEnable = true; registers.stencilTwoSideEnable = true;
registers.stencilBack.failOp = registers.stencilBack.zFailOp = registers.stencilBack.zPassOp = type::StencilOp::Keep; registers.stencilBack->failOp = registers.stencilBack->zFailOp = registers.stencilBack->zPassOp = type::StencilOp::Keep;
registers.stencilBack.compareOp = type::CompareOp::Always; registers.stencilBack->compareOp = type::CompareOp::Always;
registers.stencilBackExtra.compareMask = 0xFFFFFFFF; registers.stencilBackExtra->compareMask = 0xFFFFFFFF;
registers.stencilBackExtra.writeMask = 0xFFFFFFFF; registers.stencilBackExtra->writeMask = 0xFFFFFFFF;
registers.rtSeparateFragData = true; registers.rtSeparateFragData = true;
for (auto &attribute : registers.vertexAttributeState) for (auto &attribute : *registers.vertexAttributeState)
attribute.fixed = true; attribute.fixed = true;
registers.depthTestFunc = type::CompareOp::Always; registers.depthTestFunc = type::CompareOp::Always;
registers.blend.colorOp = registers.blend.alphaOp = type::Blend::Op::Add; registers.blendState->colorOp = registers.blendState->alphaOp = type::Blend::Op::Add;
registers.blend.colorSrcFactor = registers.blend.alphaSrcFactor = type::Blend::Factor::One; registers.blendState->colorSrcFactor = registers.blendState->alphaSrcFactor = type::Blend::Factor::One;
registers.blend.colorDestFactor = registers.blend.alphaDestFactor = type::Blend::Factor::Zero; registers.blendState->colorDestFactor = registers.blendState->alphaDestFactor = type::Blend::Factor::Zero;
registers.lineWidthSmooth = 1.0f; registers.lineWidthSmooth = 1.0f;
registers.lineWidthAliased = 1.0f; registers.lineWidthAliased = 1.0f;
registers.pointSpriteEnable = true; registers.pointSpriteEnable = true;
registers.pointSpriteSize = 1.0f; registers.pointSpriteSize = 1.0f;
registers.pointCoordReplace.enable = true; registers.pointCoordReplace->enable = true;
registers.frontFace = type::FrontFace::CounterClockwise; registers.frontFace = type::FrontFace::CounterClockwise;
registers.cullFace = type::CullFace::Back; registers.cullFace = type::CullFace::Back;
for (auto &mask : registers.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 : registers.independentBlend) { for (auto &blend : *registers.independentBlend) {
blend.colorOp = blend.alphaOp = type::Blend::Op::Add; blend.colorOp = blend.alphaOp = type::Blend::Op::Add;
blend.colorSrcFactor = blend.alphaSrcFactor = type::Blend::Factor::One; blend.colorSrcFactor = blend.alphaSrcFactor = type::Blend::Factor::One;
blend.colorDestFactor = blend.alphaDestFactor = type::Blend::Factor::Zero; blend.colorDestFactor = blend.alphaDestFactor = type::Blend::Factor::Zero;
@ -105,27 +105,31 @@ namespace skyline::soc::gm20b::engine::maxwell3d {
return; return;
} }
#define MAXWELL3D_OFFSET(field) U32_OFFSET(Registers, field) #define MAXWELL3D_OFFSET(field) (sizeof(typeof(Registers::field)) - sizeof(typeof(*Registers::field))) / sizeof(u32)
#define MAXWELL3D_STRUCT_OFFSET(field, member) U32_OFFSET(Registers, field) + U32_OFFSET(typeof(Registers::field), member) #define MAXWELL3D_STRUCT_OFFSET(field, member) MAXWELL3D_OFFSET(field) + U32_OFFSET(typeof(*Registers::field), member)
#define MAXWELL3D_ARRAY_OFFSET(field, index) U32_OFFSET(Registers, field) + ((sizeof(typeof(Registers::field[0])) / sizeof(u32)) * index) #define MAXWELL3D_ARRAY_OFFSET(field, index) MAXWELL3D_OFFSET(field) + ((sizeof(typeof(Registers::field[0])) / sizeof(u32)) * index)
#define MAXWELL3D_ARRAY_STRUCT_OFFSET(field, index, member) MAXWELL3D_ARRAY_OFFSET(field, index) + U32_OFFSET(typeof(Registers::field[0]), member) #define MAXWELL3D_ARRAY_STRUCT_OFFSET(field, index, member) MAXWELL3D_ARRAY_OFFSET(field, index) + U32_OFFSET(typeof(Registers::field[0]), member)
#define MAXWELL3D_ARRAY_STRUCT_STRUCT_OFFSET(field, index, member, submember) MAXWELL3D_ARRAY_STRUCT_OFFSET(field, index, member) + U32_OFFSET(typeof(Registers::field[0].member), submember) #define MAXWELL3D_ARRAY_STRUCT_STRUCT_OFFSET(field, index, member, submember) MAXWELL3D_ARRAY_STRUCT_OFFSET(field, index, member) + U32_OFFSET(typeof(Registers::field[0].member), submember)
#define MAXWELL3D_CASE(field, content) case MAXWELL3D_OFFSET(field): { \
auto field{util::BitCast<typeof(*registers.field)>(argument)}; \
content \
return; \
}
#define MAXWELL3D_CASE_BASE(fieldName, fieldAccessor, offset, content) case offset: { \ #define MAXWELL3D_CASE_BASE(fieldName, fieldAccessor, offset, content) case offset: { \
auto fieldName{util::BitCast<typeof(registers.fieldAccessor)>(argument)}; \ auto fieldName{util::BitCast<typeof(registers.fieldAccessor)>(argument)}; \
content \ content \
return; \ return; \
} }
#define MAXWELL3D_CASE(field, content) MAXWELL3D_CASE_BASE(field, field, MAXWELL3D_OFFSET(field), content) #define MAXWELL3D_STRUCT_CASE(field, member, content) MAXWELL3D_CASE_BASE(member, field->member, MAXWELL3D_STRUCT_OFFSET(field, member), content)
#define MAXWELL3D_STRUCT_CASE(field, member, content) MAXWELL3D_CASE_BASE(member, field.member, MAXWELL3D_STRUCT_OFFSET(field, member), content)
#define MAXWELL3D_ARRAY_CASE(field, index, content) MAXWELL3D_CASE_BASE(field, field[index], MAXWELL3D_ARRAY_OFFSET(field, index), content) #define MAXWELL3D_ARRAY_CASE(field, index, content) MAXWELL3D_CASE_BASE(field, field[index], MAXWELL3D_ARRAY_OFFSET(field, index), content)
#define MAXWELL3D_ARRAY_STRUCT_CASE(field, index, member, content) MAXWELL3D_CASE_BASE(member, field[index].member, MAXWELL3D_ARRAY_STRUCT_OFFSET(field, index, member), content) #define MAXWELL3D_ARRAY_STRUCT_CASE(field, index, member, content) MAXWELL3D_CASE_BASE(member, field[index].member, MAXWELL3D_ARRAY_STRUCT_OFFSET(field, index, member), content)
#define MAXWELL3D_ARRAY_STRUCT_STRUCT_CASE(field, index, member, submember, content) MAXWELL3D_CASE_BASE(submember, field[index].member.submember, MAXWELL3D_ARRAY_STRUCT_STRUCT_OFFSET(field, index, member, submember), content) #define MAXWELL3D_ARRAY_STRUCT_STRUCT_CASE(field, index, member, submember, content) MAXWELL3D_CASE_BASE(submember, field[index].member.submember, MAXWELL3D_ARRAY_STRUCT_STRUCT_OFFSET(field, index, member, submember), content)
if (method != MAXWELL3D_OFFSET(mme.shadowRamControl)) { if (method != MAXWELL3D_STRUCT_OFFSET(mme, shadowRamControl)) {
if (shadowRegisters.mme.shadowRamControl == type::MmeShadowRamControl::MethodTrack || shadowRegisters.mme.shadowRamControl == type::MmeShadowRamControl::MethodTrackWithFilter) if (shadowRegisters.mme->shadowRamControl == type::MmeShadowRamControl::MethodTrack || shadowRegisters.mme->shadowRamControl == type::MmeShadowRamControl::MethodTrackWithFilter)
shadowRegisters.raw[method] = argument; shadowRegisters.raw[method] = argument;
else if (shadowRegisters.mme.shadowRamControl == type::MmeShadowRamControl::MethodReplay) else if (shadowRegisters.mme->shadowRamControl == type::MmeShadowRamControl::MethodReplay)
argument = shadowRegisters.raw[method]; argument = shadowRegisters.raw[method];
} }
@ -135,7 +139,7 @@ namespace skyline::soc::gm20b::engine::maxwell3d {
if (!redundant) { if (!redundant) {
switch (method) { switch (method) {
MAXWELL3D_STRUCT_CASE(mme, shadowRamControl, { MAXWELL3D_STRUCT_CASE(mme, shadowRamControl, {
shadowRegisters.mme.shadowRamControl = shadowRamControl; shadowRegisters.mme->shadowRamControl = shadowRamControl;
}) })
#define RENDER_TARGET_ARRAY(z, index, data) \ #define RENDER_TARGET_ARRAY(z, index, data) \
@ -220,43 +224,43 @@ namespace skyline::soc::gm20b::engine::maxwell3d {
#undef SCISSOR_CALLBACKS #undef SCISSOR_CALLBACKS
MAXWELL3D_CASE(renderTargetControl, { MAXWELL3D_CASE(renderTargetControl, {
context.UpdateRenderTargetControl(registers.renderTargetControl); context.UpdateRenderTargetControl(renderTargetControl);
}) })
} }
} }
switch (method) { switch (method) {
MAXWELL3D_STRUCT_CASE(mme, instructionRamLoad, { MAXWELL3D_STRUCT_CASE(mme, instructionRamLoad, {
if (registers.mme.instructionRamPointer >= macroCode.size()) if (registers.mme->instructionRamPointer >= macroCode.size())
throw exception("Macro memory is full!"); throw exception("Macro memory is full!");
macroCode[registers.mme.instructionRamPointer++] = instructionRamLoad; macroCode[registers.mme->instructionRamPointer++] = instructionRamLoad;
// Wraparound writes // Wraparound writes
registers.mme.instructionRamPointer %= macroCode.size(); registers.mme->instructionRamPointer %= macroCode.size();
}) })
MAXWELL3D_STRUCT_CASE(mme, startAddressRamLoad, { MAXWELL3D_STRUCT_CASE(mme, startAddressRamLoad, {
if (registers.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[registers.mme.startAddressRamPointer++] = startAddressRamLoad; macroPositions[registers.mme->startAddressRamPointer++] = startAddressRamLoad;
}) })
MAXWELL3D_CASE(syncpointAction, { MAXWELL3D_CASE(syncpointAction, {
state.logger->Debug("Increment syncpoint: {}", +syncpointAction.id); state.logger->Debug("Increment syncpoint: {}", static_cast<u16>(syncpointAction.id));
channelCtx.executor.Execute(); channelCtx.executor.Execute();
state.soc->host1x.syncpoints.at(syncpointAction.id).Increment(); state.soc->host1x.syncpoints.at(syncpointAction.id).Increment();
}) })
MAXWELL3D_CASE(clearBuffers, { MAXWELL3D_CASE(clearBuffers, {
context.ClearBuffers(registers.clearBuffers); context.ClearBuffers(clearBuffers);
}) })
MAXWELL3D_STRUCT_CASE(semaphore, info, { MAXWELL3D_STRUCT_CASE(semaphore, info, {
switch (info.op) { switch (info.op) {
case type::SemaphoreInfo::Op::Release: case type::SemaphoreInfo::Op::Release:
WriteSemaphoreResult(registers.semaphore.payload); WriteSemaphoreResult(registers.semaphore->payload);
break; break;
case type::SemaphoreInfo::Op::Counter: { case type::SemaphoreInfo::Op::Counter: {
@ -306,9 +310,9 @@ namespace skyline::soc::gm20b::engine::maxwell3d {
u64 timestamp; u64 timestamp;
}; };
switch (registers.semaphore.info.structureSize) { switch (registers.semaphore->info.structureSize) {
case type::SemaphoreInfo::StructureSize::OneWord: case type::SemaphoreInfo::StructureSize::OneWord:
channelCtx.asCtx->gmmu.Write<u32>(registers.semaphore.address.Pack(), static_cast<u32>(result)); channelCtx.asCtx->gmmu.Write<u32>(registers.semaphore->address.Pack(), static_cast<u32>(result));
break; break;
case type::SemaphoreInfo::StructureSize::FourWords: { case type::SemaphoreInfo::StructureSize::FourWords: {
@ -319,7 +323,7 @@ namespace skyline::soc::gm20b::engine::maxwell3d {
i64 nsTime{util::GetTimeNs()}; i64 nsTime{util::GetTimeNs()};
i64 timestamp{(nsTime / NsToTickDenominator) * NsToTickNumerator + ((nsTime % NsToTickDenominator) * NsToTickNumerator) / NsToTickDenominator}; i64 timestamp{(nsTime / NsToTickDenominator) * NsToTickNumerator + ((nsTime % NsToTickDenominator) * NsToTickNumerator) / NsToTickDenominator};
channelCtx.asCtx->gmmu.Write<FourWordResult>(registers.semaphore.address.Pack(), channelCtx.asCtx->gmmu.Write<FourWordResult>(registers.semaphore->address.Pack(),
FourWordResult{result, static_cast<u64>(timestamp)}); FourWordResult{result, static_cast<u64>(timestamp)});
break; break;
} }

View File

@ -46,103 +46,85 @@ namespace skyline::soc::gm20b::engine::maxwell3d {
union Registers { union Registers {
std::array<u32, RegisterCount> raw; std::array<u32, RegisterCount> raw;
struct { template<size_t Offset, typename Type>
u32 _pad0_[0x40]; // 0x0 using Register = util::OffsetMember<Offset, Type, u32>;
u32 noOperation; // 0x40
u32 _pad1_[0x3]; // 0x41
u32 waitForIdle; // 0x44
struct { Register<0x40, u32> noOperation;
Register<0x44, u32> waitForIdle;
struct MME {
u32 instructionRamPointer; // 0x45 u32 instructionRamPointer; // 0x45
u32 instructionRamLoad; // 0x46 u32 instructionRamLoad; // 0x46
u32 startAddressRamPointer; // 0x47 u32 startAddressRamPointer; // 0x47
u32 startAddressRamLoad; // 0x48 u32 startAddressRamLoad; // 0x48
type::MmeShadowRamControl shadowRamControl; // 0x49 type::MmeShadowRamControl shadowRamControl; // 0x49
} mme; };
Register<0x45, MME> mme;
u32 _pad2_[0x68]; // 0x4A Register<0xB2, type::SyncpointAction> syncpointAction;
struct { Register<0xDF, u32> rasterizerEnable;
u16 id : 12; Register<0x200, std::array<type::RenderTarget, type::RenderTargetCount>> renderTargets;
u8 _pad0_ : 4; Register<0x280, std::array<type::ViewportTransform, type::ViewportCount>> viewportTransforms;
bool flushCache : 1; Register<0x300, std::array<type::Viewport, type::ViewportCount>> viewports;
u8 _pad1_ : 3;
bool increment : 1;
u16 _pad2_ : 11;
} syncpointAction; // 0xB2
u32 _pad3_[0x2C]; // 0xB3 Register<0x360, std::array<u32, 4>> clearColorValue;
u32 rasterizerEnable; // 0xDF Register<0x364, u32> clearDepthValue;
u32 _pad4_[0x120]; // 0xE0
std::array<type::RenderTarget, type::RenderTargetCount> renderTargets; // 0x200
std::array<type::ViewportTransform, type::ViewportCount> viewportTransforms; // 0x280
std::array<type::Viewport, type::ViewportCount> viewports; // 0x300
u32 _pad5_[0x20]; // 0x340
std::array<u32, 4> clearColorValue; // 0x360 struct PolygonMode {
u32 clearDepthValue; // 0x364
u32 _pad5_1_[0x6]; // 0x365
struct {
type::PolygonMode front; // 0x36B type::PolygonMode front; // 0x36B
type::PolygonMode back; // 0x36C type::PolygonMode back; // 0x36C
} polygonMode; };
Register<0x36B, PolygonMode> polygonMode;
u32 _pad6_[0x13]; // 0x36D Register<0x380, std::array<type::Scissor, type::ViewportCount>> scissors;
std::array<type::Scissor, type::ViewportCount> scissors; // 0x380
u32 _pad6_1_[0x15]; // 0x3C0
struct { struct StencilBackExtra {
u32 compareRef; // 0x3D5 u32 compareRef; // 0x3D5
u32 writeMask; // 0x3D6 u32 writeMask; // 0x3D6
u32 compareMask; // 0x3D7 u32 compareMask; // 0x3D7
} stencilBackExtra; };
Register<0x3D5, StencilBackExtra> stencilBackExtra;
u32 tiledCacheEnable; // 0x3D8 Register<0x3D8, u32> tiledCacheEnable;
struct { struct TiledCacheSize {
u16 width; u16 width;
u16 height; u16 height;
} tiledCacheSize; // 0x3D9 };
Register<0x3D9, TiledCacheSize> tiledCacheSize;
u32 _pad7_[0x11]; // 0x3DA Register<0x3EB, u32> rtSeparateFragData;
u32 rtSeparateFragData; // 0x3EB Register<0x458, std::array<type::VertexAttribute, 0x20>> vertexAttributeState;
u32 _pad8_[0x6C]; // 0x3EC Register<0x487, type::RenderTargetControl> renderTargetControl;
std::array<type::VertexAttribute, 0x20> vertexAttributeState; // 0x458 Register<0x4C3, type::CompareOp> depthTestFunc;
u32 _pad9_[0xF]; // 0x478 Register<0x4C4, float> alphaTestRef;
type::RenderTargetControl renderTargetControl; // 0x487 Register<0x4C5, type::CompareOp> alphaTestFunc;
u32 _pad9_1_[0x3B]; // 0x488 Register<0x4C6, u32> drawTFBStride;
type::CompareOp depthTestFunc; // 0x4C3
float alphaTestRef; // 0x4C4
type::CompareOp alphaTestFunc; // 0x4C5
u32 drawTFBStride; // 0x4C6
struct { struct BlendConstant {
float r; // 0x4C7 float r; // 0x4C7
float g; // 0x4C8 float g; // 0x4C8
float b; // 0x4C9 float b; // 0x4C9
float a; // 0x4CA float a; // 0x4CA
} blendConstant; };
Register<0x4C7, BlendConstant> blendConstant;
u32 _pad10_[0x4]; // 0x4CB struct BlendState {
struct {
u32 seperateAlpha; // 0x4CF u32 seperateAlpha; // 0x4CF
type::Blend::Op colorOp; // 0x4D0 type::Blend::Op colorOp; // 0x4D0
type::Blend::Factor colorSrcFactor; // 0x4D1 type::Blend::Factor colorSrcFactor; // 0x4D1
type::Blend::Factor colorDestFactor; // 0x4D2 type::Blend::Factor colorDestFactor; // 0x4D2
type::Blend::Op alphaOp; // 0x4D3 type::Blend::Op alphaOp; // 0x4D3
type::Blend::Factor alphaSrcFactor; // 0x4D4 type::Blend::Factor alphaSrcFactor; // 0x4D4
u32 _pad_; // 0x4D5
type::Blend::Factor alphaDestFactor; // 0x4D6 type::Blend::Factor alphaDestFactor; // 0x4D6
u32 enableCommon; // 0x4D7 u32 enableCommon; // 0x4D7
std::array<u32, 8> enable; // 0x4D8 For each render target std::array<u32, 8> enable; // 0x4D8 For each render target
} blend; };
Register<0x4CF, BlendState> blendState;
u32 stencilEnable; // 0x4E0 Register<0x4E0, u32> stencilEnable;
struct StencilFront {
struct {
type::StencilOp failOp; // 0x4E1 type::StencilOp failOp; // 0x4E1
type::StencilOp zFailOp; // 0x4E2 type::StencilOp zFailOp; // 0x4E2
type::StencilOp zPassOp; // 0x4E3 type::StencilOp zPassOp; // 0x4E3
@ -154,96 +136,73 @@ namespace skyline::soc::gm20b::engine::maxwell3d {
} compare; } compare;
u32 writeMask; // 0x4E7 u32 writeMask; // 0x4E7
} stencilFront; };
Register<0x4E1, StencilFront> stencilFront;
u32 _pad11_[0x4]; // 0x4E8 Register<0x4EC, float> lineWidthSmooth;
float lineWidthSmooth; // 0x4EC Register<0x4D, float> lineWidthAliased;
float lineWidthAliased; // 0x4D
u32 _pad12_[0x1F]; // 0x4EE
u32 drawBaseVertex; // 0x50D
u32 drawBaseInstance; // 0x50E
u32 _pad13_[0x35]; // 0x50F
u32 clipDistanceEnable; // 0x544
u32 sampleCounterEnable; // 0x545
float pointSpriteSize; // 0x546
u32 zCullStatCountersEnable; // 0x547
u32 pointSpriteEnable; // 0x548
u32 _pad14_; // 0x549
u32 shaderExceptions; // 0x54A
u32 _pad15_[0x2]; // 0x54B
u32 multisampleEnable; // 0x54D
u32 depthTargetEnable; // 0x54E
struct { Register<0x50D, u32> drawBaseVertex;
bool alphaToCoverage : 1; Register<0x50E, u32> drawBaseInstance;
u8 _pad0_ : 3;
bool alphaToOne : 1;
u32 _pad1_ : 27;
} multisampleControl; // 0x54F
u32 _pad16_[0x7]; // 0x550 Register<0x544, u32> clipDistanceEnable;
Register<0x545, u32> sampleCounterEnable;
Register<0x546, float> pointSpriteSize;
Register<0x547, u32> zCullStatCountersEnable;
Register<0x548, u32> pointSpriteEnable;
Register<0x54A, u32> shaderExceptions;
Register<0x54D, u32> multisampleEnable;
Register<0x54E, u32> depthTargetEnable;
struct { Register<0x54F, type::MultisampleControl> multisampleControl;
struct SamplerPool {
type::Address address; // 0x557 type::Address address; // 0x557
u32 maximumIndex; // 0x559 u32 maximumIndex; // 0x559
} texSamplerPool; };
Register<0x557, SamplerPool> samplerPool;
u32 _pad17_; // 0x55A Register<0x55B, u32> polygonOffsetFactor;
u32 polygonOffsetFactor; // 0x55B Register<0x55C, u32> lineSmoothEnable;
u32 lineSmoothEnable; // 0x55C
struct { struct TexturePool {
type::Address address; // 0x55D type::Address address; // 0x55D
u32 maximumIndex; // 0x55F u32 maximumIndex; // 0x55F
} texHeaderPool; };
Register<0x55D, TexturePool> texturePool;
u32 _pad18_[0x5]; // 0x560
u32 stencilTwoSideEnable; // 0x565 Register<0x565, u32> stencilTwoSideEnable;
struct { struct StencilBack {
type::StencilOp failOp; // 0x566 type::StencilOp failOp; // 0x566
type::StencilOp zFailOp; // 0x567 type::StencilOp zFailOp; // 0x567
type::StencilOp zPassOp; // 0x568 type::StencilOp zPassOp; // 0x568
type::CompareOp compareOp; // 0x569 type::CompareOp compareOp; // 0x569
} stencilBack; };
Register<0x566, StencilBack> stencilBack;
u32 _pad19_[0x17]; // 0x56A Register<0x581, type::PointCoordReplace> pointCoordReplace;
struct { Register<0x646, u32> cullFaceEnable;
u8 _unk_ : 2; Register<0x647, type::FrontFace> frontFace;
type::CoordOrigin origin : 1; Register<0x648, type::CullFace> cullFace;
u16 enable : 10; Register<0x649, u32> pixelCentreImage;
u32 _pad_ : 19; Register<0x64B, u32> viewportTransformEnable;
} pointCoordReplace; // 0x581 Register<0x674, type::ClearBuffers> clearBuffers;
Register<0x680, std::array<type::ColorWriteMask, type::RenderTargetCount>> colorMask;
u32 _pad20_[0xC4]; // 0x582 struct Semaphore {
u32 cullFaceEnable; // 0x646
type::FrontFace frontFace; // 0x647
type::CullFace cullFace; // 0x648
u32 pixelCentreImage; // 0x649
u32 _pad21_; // 0x64A
u32 viewportTransformEnable; // 0x64B
u32 _pad22_[0x28]; // 0x64C
type::ClearBuffers clearBuffers; // 0x674
u32 _pad22_1_[0xB]; // 0x675
std::array<type::ColorWriteMask, type::RenderTargetCount> colorMask; // 0x680
u32 _pad23_[0x38]; // 0x688
struct {
type::Address address; // 0x6C0 type::Address address; // 0x6C0
u32 payload; // 0x6C2 u32 payload; // 0x6C2
type::SemaphoreInfo info; // 0x6C3 type::SemaphoreInfo info; // 0x6C3
} semaphore;
u32 _pad24_[0xBC]; // 0x6C4
std::array<type::Blend, type::RenderTargetCount> independentBlend; // 0x780
u32 _pad25_[0x100]; // 0x7C0
u32 firmwareCall[0x20]; // 0x8C0
}; };
Register<0x6C0, Semaphore> semaphore;
Register<0x780, std::array<type::Blend, type::RenderTargetCount>> independentBlend;
Register<0x8C0, u32[0x20]> firmwareCall;
}; };
static_assert(sizeof(Registers) == (RegisterCount * sizeof(u32))); static_assert(sizeof(Registers) == (RegisterCount * sizeof(u32)));
static_assert(U32_OFFSET(Registers, firmwareCall) == 0x8C0);
#pragma pack(pop) #pragma pack(pop)
Registers registers{}; Registers registers{};