-
Notifications
You must be signed in to change notification settings - Fork 2.7k
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_NBT
orGX_VA_NRM
in 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_SetVtxAttrFmt
SDK (from Super Mario Sunshine)
GXSetVtxAttrFmt
Libogc
GX_SetVtxDesc
SDK (from Super Mario Sunshine)
GXSetVtxDesc
Libogc
__GX_XfVtxSpecs
SDK (from Super Mario Sunshine)
__GXXfVtxSpecs
__GX_SetMatrixIndex
and 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::Flush
as we need to know thevtx_attr_group
(andFlush
might be called after multiple differentvtx_attr_group
values have been used).