diff --git a/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell/types.h b/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell/types.h index f7f93299..c2e3cfbf 100644 --- a/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell/types.h +++ b/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell/types.h @@ -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 }; + 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 /** @@ -360,6 +370,14 @@ namespace skyline::soc::gm20b::engine::maxwell3d::type { }; 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 { Keep = 1, Zero = 2, @@ -371,6 +389,18 @@ namespace skyline::soc::gm20b::engine::maxwell3d::type { 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 { Clockwise = 0x900, CounterClockwise = 0x901, @@ -495,10 +525,5 @@ namespace skyline::soc::gm20b::engine::maxwell3d::type { }; static_assert(sizeof(SemaphoreInfo) == sizeof(u32)); - enum class CoordOrigin : u8 { - LowerLeft = 0, - UpperLeft = 1, - }; - #pragma pack(pop) } diff --git a/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.cpp b/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.cpp index 45023d24..ae48af74 100644 --- a/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.cpp +++ b/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.cpp @@ -16,57 +16,57 @@ namespace skyline::soc::gm20b::engine::maxwell3d { registers.rasterizerEnable = true; - for (auto &transform : registers.viewportTransforms) { + for (auto &transform : *registers.viewportTransforms) { transform.swizzles.x = type::ViewportTransform::Swizzle::PositiveX; transform.swizzles.y = type::ViewportTransform::Swizzle::PositiveY; transform.swizzles.z = type::ViewportTransform::Swizzle::PositiveZ; transform.swizzles.w = type::ViewportTransform::Swizzle::PositiveW; } - for (auto &viewport : registers.viewports) { + for (auto &viewport : *registers.viewports) { viewport.depthRangeFar = 1.0f; viewport.depthRangeNear = 0.0f; } - registers.polygonMode.front = type::PolygonMode::Fill; - registers.polygonMode.back = type::PolygonMode::Fill; + registers.polygonMode->front = type::PolygonMode::Fill; + registers.polygonMode->back = type::PolygonMode::Fill; - registers.stencilFront.failOp = registers.stencilFront.zFailOp = registers.stencilFront.zPassOp = type::StencilOp::Keep; - registers.stencilFront.compare.op = type::CompareOp::Always; - registers.stencilFront.compare.mask = 0xFFFFFFFF; - registers.stencilFront.writeMask = 0xFFFFFFFF; + registers.stencilFront->failOp = registers.stencilFront->zFailOp = registers.stencilFront->zPassOp = type::StencilOp::Keep; + registers.stencilFront->compare.op = type::CompareOp::Always; + registers.stencilFront->compare.mask = 0xFFFFFFFF; + registers.stencilFront->writeMask = 0xFFFFFFFF; registers.stencilTwoSideEnable = true; - registers.stencilBack.failOp = registers.stencilBack.zFailOp = registers.stencilBack.zPassOp = type::StencilOp::Keep; - registers.stencilBack.compareOp = type::CompareOp::Always; - registers.stencilBackExtra.compareMask = 0xFFFFFFFF; - registers.stencilBackExtra.writeMask = 0xFFFFFFFF; + registers.stencilBack->failOp = registers.stencilBack->zFailOp = registers.stencilBack->zPassOp = type::StencilOp::Keep; + registers.stencilBack->compareOp = type::CompareOp::Always; + registers.stencilBackExtra->compareMask = 0xFFFFFFFF; + registers.stencilBackExtra->writeMask = 0xFFFFFFFF; registers.rtSeparateFragData = true; - for (auto &attribute : registers.vertexAttributeState) + for (auto &attribute : *registers.vertexAttributeState) attribute.fixed = true; registers.depthTestFunc = type::CompareOp::Always; - registers.blend.colorOp = registers.blend.alphaOp = type::Blend::Op::Add; - registers.blend.colorSrcFactor = registers.blend.alphaSrcFactor = type::Blend::Factor::One; - registers.blend.colorDestFactor = registers.blend.alphaDestFactor = type::Blend::Factor::Zero; + registers.blendState->colorOp = registers.blendState->alphaOp = type::Blend::Op::Add; + registers.blendState->colorSrcFactor = registers.blendState->alphaSrcFactor = type::Blend::Factor::One; + registers.blendState->colorDestFactor = registers.blendState->alphaDestFactor = type::Blend::Factor::Zero; registers.lineWidthSmooth = 1.0f; registers.lineWidthAliased = 1.0f; registers.pointSpriteEnable = true; registers.pointSpriteSize = 1.0f; - registers.pointCoordReplace.enable = true; + registers.pointCoordReplace->enable = true; registers.frontFace = type::FrontFace::CounterClockwise; registers.cullFace = type::CullFace::Back; - for (auto &mask : registers.colorMask) + for (auto &mask : *registers.colorMask) 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.colorSrcFactor = blend.alphaSrcFactor = type::Blend::Factor::One; blend.colorDestFactor = blend.alphaDestFactor = type::Blend::Factor::Zero; @@ -105,27 +105,31 @@ namespace skyline::soc::gm20b::engine::maxwell3d { return; } - #define MAXWELL3D_OFFSET(field) U32_OFFSET(Registers, field) - #define MAXWELL3D_STRUCT_OFFSET(field, member) U32_OFFSET(Registers, 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_OFFSET(field) (sizeof(typeof(Registers::field)) - sizeof(typeof(*Registers::field))) / sizeof(u32) + #define MAXWELL3D_STRUCT_OFFSET(field, member) MAXWELL3D_OFFSET(field) + U32_OFFSET(typeof(*Registers::field), member) + #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_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(argument)}; \ + content \ + return; \ + } #define MAXWELL3D_CASE_BASE(fieldName, fieldAccessor, offset, content) case offset: { \ - auto fieldName{util::BitCast(argument)}; \ + auto fieldName{util::BitCast(argument)}; \ content \ 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_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) - if (method != MAXWELL3D_OFFSET(mme.shadowRamControl)) { - if (shadowRegisters.mme.shadowRamControl == type::MmeShadowRamControl::MethodTrack || shadowRegisters.mme.shadowRamControl == type::MmeShadowRamControl::MethodTrackWithFilter) + if (method != MAXWELL3D_STRUCT_OFFSET(mme, shadowRamControl)) { + if (shadowRegisters.mme->shadowRamControl == type::MmeShadowRamControl::MethodTrack || shadowRegisters.mme->shadowRamControl == type::MmeShadowRamControl::MethodTrackWithFilter) shadowRegisters.raw[method] = argument; - else if (shadowRegisters.mme.shadowRamControl == type::MmeShadowRamControl::MethodReplay) + else if (shadowRegisters.mme->shadowRamControl == type::MmeShadowRamControl::MethodReplay) argument = shadowRegisters.raw[method]; } @@ -135,7 +139,7 @@ namespace skyline::soc::gm20b::engine::maxwell3d { if (!redundant) { switch (method) { MAXWELL3D_STRUCT_CASE(mme, shadowRamControl, { - shadowRegisters.mme.shadowRamControl = shadowRamControl; + shadowRegisters.mme->shadowRamControl = shadowRamControl; }) #define RENDER_TARGET_ARRAY(z, index, data) \ @@ -220,43 +224,43 @@ namespace skyline::soc::gm20b::engine::maxwell3d { #undef SCISSOR_CALLBACKS MAXWELL3D_CASE(renderTargetControl, { - context.UpdateRenderTargetControl(registers.renderTargetControl); + context.UpdateRenderTargetControl(renderTargetControl); }) } } switch (method) { MAXWELL3D_STRUCT_CASE(mme, instructionRamLoad, { - if (registers.mme.instructionRamPointer >= macroCode.size()) + if (registers.mme->instructionRamPointer >= macroCode.size()) throw exception("Macro memory is full!"); - macroCode[registers.mme.instructionRamPointer++] = instructionRamLoad; + macroCode[registers.mme->instructionRamPointer++] = instructionRamLoad; // Wraparound writes - registers.mme.instructionRamPointer %= macroCode.size(); + registers.mme->instructionRamPointer %= macroCode.size(); }) MAXWELL3D_STRUCT_CASE(mme, startAddressRamLoad, { - if (registers.mme.startAddressRamPointer >= macroPositions.size()) + if (registers.mme->startAddressRamPointer >= macroPositions.size()) throw exception("Maximum amount of macros reached!"); - macroPositions[registers.mme.startAddressRamPointer++] = startAddressRamLoad; + macroPositions[registers.mme->startAddressRamPointer++] = startAddressRamLoad; }) MAXWELL3D_CASE(syncpointAction, { - state.logger->Debug("Increment syncpoint: {}", +syncpointAction.id); + state.logger->Debug("Increment syncpoint: {}", static_cast(syncpointAction.id)); channelCtx.executor.Execute(); state.soc->host1x.syncpoints.at(syncpointAction.id).Increment(); }) MAXWELL3D_CASE(clearBuffers, { - context.ClearBuffers(registers.clearBuffers); + context.ClearBuffers(clearBuffers); }) MAXWELL3D_STRUCT_CASE(semaphore, info, { switch (info.op) { case type::SemaphoreInfo::Op::Release: - WriteSemaphoreResult(registers.semaphore.payload); + WriteSemaphoreResult(registers.semaphore->payload); break; case type::SemaphoreInfo::Op::Counter: { @@ -306,9 +310,9 @@ namespace skyline::soc::gm20b::engine::maxwell3d { u64 timestamp; }; - switch (registers.semaphore.info.structureSize) { + switch (registers.semaphore->info.structureSize) { case type::SemaphoreInfo::StructureSize::OneWord: - channelCtx.asCtx->gmmu.Write(registers.semaphore.address.Pack(), static_cast(result)); + channelCtx.asCtx->gmmu.Write(registers.semaphore->address.Pack(), static_cast(result)); break; case type::SemaphoreInfo::StructureSize::FourWords: { @@ -319,7 +323,7 @@ namespace skyline::soc::gm20b::engine::maxwell3d { i64 nsTime{util::GetTimeNs()}; i64 timestamp{(nsTime / NsToTickDenominator) * NsToTickNumerator + ((nsTime % NsToTickDenominator) * NsToTickNumerator) / NsToTickDenominator}; - channelCtx.asCtx->gmmu.Write(registers.semaphore.address.Pack(), + channelCtx.asCtx->gmmu.Write(registers.semaphore->address.Pack(), FourWordResult{result, static_cast(timestamp)}); break; } diff --git a/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.h b/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.h index 01862c26..7498c4ab 100644 --- a/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.h +++ b/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.h @@ -46,204 +46,163 @@ namespace skyline::soc::gm20b::engine::maxwell3d { union Registers { std::array raw; - struct { - u32 _pad0_[0x40]; // 0x0 - u32 noOperation; // 0x40 - u32 _pad1_[0x3]; // 0x41 - u32 waitForIdle; // 0x44 + template + using Register = util::OffsetMember; - struct { - u32 instructionRamPointer; // 0x45 - u32 instructionRamLoad; // 0x46 - u32 startAddressRamPointer; // 0x47 - u32 startAddressRamLoad; // 0x48 - type::MmeShadowRamControl shadowRamControl; // 0x49 - } mme; + Register<0x40, u32> noOperation; + Register<0x44, u32> waitForIdle; - u32 _pad2_[0x68]; // 0x4A - - struct { - u16 id : 12; - u8 _pad0_ : 4; - bool flushCache : 1; - u8 _pad1_ : 3; - bool increment : 1; - u16 _pad2_ : 11; - } syncpointAction; // 0xB2 - - u32 _pad3_[0x2C]; // 0xB3 - u32 rasterizerEnable; // 0xDF - u32 _pad4_[0x120]; // 0xE0 - std::array renderTargets; // 0x200 - std::array viewportTransforms; // 0x280 - std::array viewports; // 0x300 - u32 _pad5_[0x20]; // 0x340 - - std::array clearColorValue; // 0x360 - u32 clearDepthValue; // 0x364 - - u32 _pad5_1_[0x6]; // 0x365 - - struct { - type::PolygonMode front; // 0x36B - type::PolygonMode back; // 0x36C - } polygonMode; - - u32 _pad6_[0x13]; // 0x36D - std::array scissors; // 0x380 - u32 _pad6_1_[0x15]; // 0x3C0 - - struct { - u32 compareRef; // 0x3D5 - u32 writeMask; // 0x3D6 - u32 compareMask; // 0x3D7 - } stencilBackExtra; - - u32 tiledCacheEnable; // 0x3D8 - struct { - u16 width; - u16 height; - } tiledCacheSize; // 0x3D9 - - u32 _pad7_[0x11]; // 0x3DA - u32 rtSeparateFragData; // 0x3EB - u32 _pad8_[0x6C]; // 0x3EC - std::array vertexAttributeState; // 0x458 - u32 _pad9_[0xF]; // 0x478 - type::RenderTargetControl renderTargetControl; // 0x487 - u32 _pad9_1_[0x3B]; // 0x488 - type::CompareOp depthTestFunc; // 0x4C3 - float alphaTestRef; // 0x4C4 - type::CompareOp alphaTestFunc; // 0x4C5 - u32 drawTFBStride; // 0x4C6 - - struct { - float r; // 0x4C7 - float g; // 0x4C8 - float b; // 0x4C9 - float a; // 0x4CA - } blendConstant; - - u32 _pad10_[0x4]; // 0x4CB - - struct { - u32 seperateAlpha; // 0x4CF - type::Blend::Op colorOp; // 0x4D0 - type::Blend::Factor colorSrcFactor; // 0x4D1 - type::Blend::Factor colorDestFactor; // 0x4D2 - type::Blend::Op alphaOp; // 0x4D3 - type::Blend::Factor alphaSrcFactor; // 0x4D4 - u32 _pad_; // 0x4D5 - type::Blend::Factor alphaDestFactor; // 0x4D6 - - u32 enableCommon; // 0x4D7 - std::array enable; // 0x4D8 For each render target - } blend; - - u32 stencilEnable; // 0x4E0 - - struct { - type::StencilOp failOp; // 0x4E1 - type::StencilOp zFailOp; // 0x4E2 - type::StencilOp zPassOp; // 0x4E3 - - struct { - type::CompareOp op; // 0x4E4 - i32 ref; // 0x4E5 - u32 mask; // 0x4E6 - } compare; - - u32 writeMask; // 0x4E7 - } stencilFront; - - u32 _pad11_[0x4]; // 0x4E8 - float lineWidthSmooth; // 0x4EC - 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 { - bool alphaToCoverage : 1; - u8 _pad0_ : 3; - bool alphaToOne : 1; - u32 _pad1_ : 27; - } multisampleControl; // 0x54F - - u32 _pad16_[0x7]; // 0x550 - - struct { - type::Address address; // 0x557 - u32 maximumIndex; // 0x559 - } texSamplerPool; - - u32 _pad17_; // 0x55A - u32 polygonOffsetFactor; // 0x55B - u32 lineSmoothEnable; // 0x55C - - struct { - type::Address address; // 0x55D - u32 maximumIndex; // 0x55F - } texHeaderPool; - - u32 _pad18_[0x5]; // 0x560 - - u32 stencilTwoSideEnable; // 0x565 - - struct { - type::StencilOp failOp; // 0x566 - type::StencilOp zFailOp; // 0x567 - type::StencilOp zPassOp; // 0x568 - type::CompareOp compareOp; // 0x569 - } stencilBack; - - u32 _pad19_[0x17]; // 0x56A - - struct { - u8 _unk_ : 2; - type::CoordOrigin origin : 1; - u16 enable : 10; - u32 _pad_ : 19; - } pointCoordReplace; // 0x581 - - u32 _pad20_[0xC4]; // 0x582 - 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 colorMask; // 0x680 - u32 _pad23_[0x38]; // 0x688 - - struct { - type::Address address; // 0x6C0 - u32 payload; // 0x6C2 - type::SemaphoreInfo info; // 0x6C3 - } semaphore; - - u32 _pad24_[0xBC]; // 0x6C4 - std::array independentBlend; // 0x780 - u32 _pad25_[0x100]; // 0x7C0 - u32 firmwareCall[0x20]; // 0x8C0 + struct MME { + u32 instructionRamPointer; // 0x45 + u32 instructionRamLoad; // 0x46 + u32 startAddressRamPointer; // 0x47 + u32 startAddressRamLoad; // 0x48 + type::MmeShadowRamControl shadowRamControl; // 0x49 }; + Register<0x45, MME> mme; + + Register<0xB2, type::SyncpointAction> syncpointAction; + + Register<0xDF, u32> rasterizerEnable; + Register<0x200, std::array> renderTargets; + Register<0x280, std::array> viewportTransforms; + Register<0x300, std::array> viewports; + + Register<0x360, std::array> clearColorValue; + Register<0x364, u32> clearDepthValue; + + struct PolygonMode { + type::PolygonMode front; // 0x36B + type::PolygonMode back; // 0x36C + }; + Register<0x36B, PolygonMode> polygonMode; + + Register<0x380, std::array> scissors; + + struct StencilBackExtra { + u32 compareRef; // 0x3D5 + u32 writeMask; // 0x3D6 + u32 compareMask; // 0x3D7 + }; + Register<0x3D5, StencilBackExtra> stencilBackExtra; + + Register<0x3D8, u32> tiledCacheEnable; + struct TiledCacheSize { + u16 width; + u16 height; + }; + Register<0x3D9, TiledCacheSize> tiledCacheSize; + + Register<0x3EB, u32> rtSeparateFragData; + Register<0x458, std::array> vertexAttributeState; + Register<0x487, type::RenderTargetControl> renderTargetControl; + Register<0x4C3, type::CompareOp> depthTestFunc; + Register<0x4C4, float> alphaTestRef; + Register<0x4C5, type::CompareOp> alphaTestFunc; + Register<0x4C6, u32> drawTFBStride; + + struct BlendConstant { + float r; // 0x4C7 + float g; // 0x4C8 + float b; // 0x4C9 + float a; // 0x4CA + }; + Register<0x4C7, BlendConstant> blendConstant; + + struct BlendState { + u32 seperateAlpha; // 0x4CF + type::Blend::Op colorOp; // 0x4D0 + type::Blend::Factor colorSrcFactor; // 0x4D1 + type::Blend::Factor colorDestFactor; // 0x4D2 + type::Blend::Op alphaOp; // 0x4D3 + type::Blend::Factor alphaSrcFactor; // 0x4D4 + type::Blend::Factor alphaDestFactor; // 0x4D6 + + u32 enableCommon; // 0x4D7 + std::array enable; // 0x4D8 For each render target + }; + Register<0x4CF, BlendState> blendState; + + Register<0x4E0, u32> stencilEnable; + struct StencilFront { + type::StencilOp failOp; // 0x4E1 + type::StencilOp zFailOp; // 0x4E2 + type::StencilOp zPassOp; // 0x4E3 + + struct { + type::CompareOp op; // 0x4E4 + i32 ref; // 0x4E5 + u32 mask; // 0x4E6 + } compare; + + u32 writeMask; // 0x4E7 + }; + Register<0x4E1, StencilFront> stencilFront; + + Register<0x4EC, float> lineWidthSmooth; + Register<0x4D, float> lineWidthAliased; + + Register<0x50D, u32> drawBaseVertex; + Register<0x50E, u32> drawBaseInstance; + + 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; + + Register<0x54F, type::MultisampleControl> multisampleControl; + + struct SamplerPool { + type::Address address; // 0x557 + u32 maximumIndex; // 0x559 + }; + Register<0x557, SamplerPool> samplerPool; + + Register<0x55B, u32> polygonOffsetFactor; + Register<0x55C, u32> lineSmoothEnable; + + struct TexturePool { + type::Address address; // 0x55D + u32 maximumIndex; // 0x55F + }; + Register<0x55D, TexturePool> texturePool; + + + Register<0x565, u32> stencilTwoSideEnable; + + struct StencilBack { + type::StencilOp failOp; // 0x566 + type::StencilOp zFailOp; // 0x567 + type::StencilOp zPassOp; // 0x568 + type::CompareOp compareOp; // 0x569 + }; + Register<0x566, StencilBack> stencilBack; + + Register<0x581, type::PointCoordReplace> pointCoordReplace; + + Register<0x646, u32> cullFaceEnable; + Register<0x647, type::FrontFace> frontFace; + Register<0x648, type::CullFace> cullFace; + Register<0x649, u32> pixelCentreImage; + Register<0x64B, u32> viewportTransformEnable; + Register<0x674, type::ClearBuffers> clearBuffers; + Register<0x680, std::array> colorMask; + + struct Semaphore { + type::Address address; // 0x6C0 + u32 payload; // 0x6C2 + type::SemaphoreInfo info; // 0x6C3 + }; + Register<0x6C0, Semaphore> semaphore; + + Register<0x780, std::array> independentBlend; + Register<0x8C0, u32[0x20]> firmwareCall; }; static_assert(sizeof(Registers) == (RegisterCount * sizeof(u32))); - static_assert(U32_OFFSET(Registers, firmwareCall) == 0x8C0); #pragma pack(pop) Registers registers{};