New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Show panic alerts if the CP configuration doesn't match the XF configuration #10672
Conversation
| @@ -265,6 +267,82 @@ int RunVertices(int vtx_attr_group, OpcodeDecoder::Primitive primitive, int coun | |||
| if (is_preprocess) | |||
| return size; | |||
|
|
|||
| // Validate that the XF input configuration matches the CP configuration | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe wrap this whole block in a function?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
| break; | ||
| default: | ||
| PanicAlertFmt("xfmem.invtxspec.numnormals is invalid: {}", xfmem.invtxspec.numnormals); | ||
| num_xf_normals = 888; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why 888?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's an arbitrary number that num_cp_normals cannot be (so that the second test always fails); leaving it uninitialized would result in undefined behavior, and using 0 could result in no game quirk being reported.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know the c++ community has different views on it. But rather than magic numbers for values being undefined, I personally prefer std::optional.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you do want to use a magic number like this, please add a constant or a comment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought that std::optional would make the num_cp_normals != num_xf_normals check more complicated (instead requiring !num_xf_normals || num_cp_normals != num_xf_normals but it seems like num_cp_normals will be automatically converted to a present optional and if num_xf_normals is not present then the two are considered not equal. There isn't a fmt::formatter for std::optional though so that logic is more complicated though...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't know if it'd be useful to do so but we could add a formatter for optional, someone did so here: fmtlib/fmt#1367
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Eh, I think manually handling it here is OK since it means we can use a specific message for the not-present case (rather than always using "NO VALUE" or the like). If it ends up being a more common problem then we can add one though.
4394ba6
to
c724691
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Untested. LGTM
…x config This probably isn't triggered by real games, but it's possible to accidentally do it with libogc (which results in freezes on real hardware).
… indices This almost certainly never happens, but if it does we want to know.
|
I made an adjustment to the message; it now includes the relevant registers (in hex), as well as the VAT index: (I was going to do it using the formatter, but it's way too large.) |

This is somewhat similar to #8717. At least in some cases, on real hardware this mismatched configuration can result in a hang, but Dolphin was previously allowing it without any warnings (I ran into this when experimenting with embossing).
I've also added a check that the CP and XF matrix index registers match, since it's weird that they are duplicated (we currently always use the CP one with the hardware backends, and the XF one for the software renderer), and the XF input vertex spec register doesn't include a count for matrix indices (so if per-vertex matrix indices are enabled, it's not clear how XF knows which ones are in use).
Ways this could be triggered
As far as I can tell, this kind of bug can only easily be caused with normals, since the normal count is based on both the vertex descriptor and the vertex attribute table while colors and texture coordinates are based on the vertex descriptor only. I ran into this by using
GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_NBT, ...)but alsoGX_SetVtxDesc(GX_VA_NRM, ...); you need to use eitherGX_VA_NBTorGX_VA_NRMin both places. As far as I can tell, that applies to both libogc and the official SDK.Libogc also seems to have a bug where using
GX_SetVtxDesc(GX_VA_NRM, GX_NONE)will result in 1 normal being used for the XF configuration, andGX_SetVtxDesc(GX_VA_NBT, GX_NONE)will result in 3 normals being used (the only way to set it to 0 is to useGX_ClearVtxDesc()). The official SDK does not have this issue.Libogc
GX_SetVtxAttrFmtSDK (from Super Mario Sunshine)
GXSetVtxAttrFmtLibogc
GX_SetVtxDescSDK (from Super Mario Sunshine)
GXSetVtxDescLibogc
__GX_XfVtxSpecsSDK (from Super Mario Sunshine)
__GXXfVtxSpecs__GX_SetMatrixIndexand its SDK version always set both the CP and XF version to the same values, so that shouldn't have any issues.I currently do this check in
VertexLoaderManager::RunVertices, which is called for every primitive command. This might be more frequent than it should be, but I can't put it inVertexManagerBase::Flushas we need to know thevtx_attr_group(andFlushmight be called after multiple differentvtx_attr_groupvalues have been used).