mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-17 00:28:31 +09:00
[Test] (MG_Test, Wire): assert a payload crosses byte for byte including the bytes spelled Pad - a codec that normalised one would silently delete the fields P5 and b1 have just put there
This commit is contained in:
@@ -570,6 +570,96 @@ TEST_F(PipeWireCodecTest, KHostSpanClassIsValidatedEvenThoughP5ProducesNone) {
|
|||||||
EXPECT_FALSE(applied);
|
EXPECT_FALSE(applied);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// =====================================================================================
|
||||||
|
// Declared padding is payload, not slack
|
||||||
|
// =====================================================================================
|
||||||
|
|
||||||
|
TEST_F(PipeWireCodecTest, EveryPayloadByteCrossesIncludingTheOnesSpelledPad) {
|
||||||
|
// A PAD IS A FIELD SOMEBODY HAS NOT CLAIMED YET, and this phase is the proof: P5 put the
|
||||||
|
// respecify scope into MGPResourceDesc's two pads (contract table 1 row 19b) and b1 put
|
||||||
|
// MGPSubData::Pad0's low byte to work as HasLiveHostWrites. A codec that zeroed a pad "for
|
||||||
|
// determinism", or built a payload field by field, would DELETE those bits - and a dropped
|
||||||
|
// HasLiveHostWrites is not a visible failure, it is IsBufferDrawClean answering "clean"
|
||||||
|
// for a buffer with a live host writer, i.e. the frame drawing the last uploaded bytes
|
||||||
|
// with no diagnostic at all.
|
||||||
|
//
|
||||||
|
// So this case asserts the whole payload byte for byte rather than the named fields: a
|
||||||
|
// test that compared only the members would go green through exactly that bug.
|
||||||
|
// IT NAMES NO PAD MEMBER, deliberately. The whole struct is stamped with a recognisable
|
||||||
|
// byte first and only the fields the decoder validates are then written, so whatever is
|
||||||
|
// left - Pad0, Pad1, or the names a later phase gives them - still carries the stamp and a
|
||||||
|
// memcmp over the whole payload is the assertion. A case that named `Pad0` would stop
|
||||||
|
// COMPILING the day someone claims it, which is precisely the day it is most needed.
|
||||||
|
Wire2 wire;
|
||||||
|
std::vector<std::uint8_t> texels(64, 0x31);
|
||||||
|
|
||||||
|
MGPSubData upload{};
|
||||||
|
std::memset(&upload, 0xA5, sizeof(upload));
|
||||||
|
upload.Res = MakeHandle(101);
|
||||||
|
upload.Target = MGPipePackSubDataTarget(static_cast<Uint32>(MGPipeResourceTarget::Tex2D), 0u);
|
||||||
|
upload.Level = 2;
|
||||||
|
upload.SourceIsVerbatimLevelShadow = 1;
|
||||||
|
upload.UnionBox = MGPBox{1, 2, 0, 4, 4, 1};
|
||||||
|
upload.RegionCount = 0;
|
||||||
|
upload.Blob = wire.Encoder().StageBytes(texels.data(), texels.size());
|
||||||
|
|
||||||
|
ASSERT_NE(wire.Encoder().EncodeRecord(MGPWireOp::ResourceSubData, &upload, sizeof(upload)),
|
||||||
|
kInvalidSeq);
|
||||||
|
wire.Encoder().Publish();
|
||||||
|
|
||||||
|
Transport::RingRecordView view{};
|
||||||
|
bool corrupt = false;
|
||||||
|
ASSERT_TRUE(wire.Consumer().Pop(view, &corrupt));
|
||||||
|
ASSERT_FALSE(corrupt);
|
||||||
|
ASSERT_GE(view.payloadSize, sizeof(upload));
|
||||||
|
EXPECT_EQ(std::memcmp(view.payload, &upload, sizeof(upload)), 0)
|
||||||
|
<< "the payload did not cross byte for byte";
|
||||||
|
|
||||||
|
// And the stamp really did survive somewhere the named fields do not cover, so the case
|
||||||
|
// cannot pass by comparing a struct that has no unclaimed bytes left.
|
||||||
|
const auto* crossed = static_cast<const std::uint8_t*>(view.payload);
|
||||||
|
std::size_t stamped = 0;
|
||||||
|
for (std::size_t i = 0; i < sizeof(upload); ++i) {
|
||||||
|
if (crossed[i] == 0xA5) {
|
||||||
|
++stamped;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EXPECT_GT(stamped, 0u) << "no byte of the payload was left unclaimed; the case still checks "
|
||||||
|
"the memcmp above, but it no longer proves anything about pads";
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(PipeWireCodecTest, ResourceDescPadsCrossToo) {
|
||||||
|
// The same property over the struct P5 itself put two fields into. The helpers are the
|
||||||
|
// only legal reader (three fields are one value), but the BYTES are what the codec owes.
|
||||||
|
Wire2 wire;
|
||||||
|
MGPResourceDesc desc{};
|
||||||
|
desc.Resource = MakeHandle(111);
|
||||||
|
desc.Target = static_cast<Uint8>(MGPipeResourceTarget::TexCube);
|
||||||
|
desc.InternalFormat = 7;
|
||||||
|
desc.Width = 16;
|
||||||
|
desc.Height = 16;
|
||||||
|
desc.Depth = 1;
|
||||||
|
desc.ArrayLayers = 6;
|
||||||
|
desc.Levels = 3;
|
||||||
|
desc.Samples = 1;
|
||||||
|
MGPipeSetRespecifiedLevel(desc, 0x0304u, 2u);
|
||||||
|
|
||||||
|
ASSERT_NE(wire.Encoder().EncodeRecord(MGPWireOp::ResourceRespecify, &desc, sizeof(desc)),
|
||||||
|
kInvalidSeq);
|
||||||
|
wire.Encoder().Publish();
|
||||||
|
|
||||||
|
Transport::RingRecordView view{};
|
||||||
|
bool corrupt = false;
|
||||||
|
ASSERT_TRUE(wire.Consumer().Pop(view, &corrupt));
|
||||||
|
ASSERT_FALSE(corrupt);
|
||||||
|
EXPECT_EQ(std::memcmp(view.payload, &desc, sizeof(desc)), 0);
|
||||||
|
const auto* crossed = static_cast<const MGPResourceDesc*>(view.payload);
|
||||||
|
EXPECT_FALSE(MGPipeRespecifyIsWholeResource(*crossed));
|
||||||
|
EXPECT_EQ(MGPipeRespecifiedUploadTargetOf(*crossed), 0x0304u);
|
||||||
|
EXPECT_EQ(MGPipeRespecifiedLevelOf(*crossed), 2u);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// =====================================================================================
|
// =====================================================================================
|
||||||
// The two double-tailed rows, and DrawVbo's conditional one
|
// The two double-tailed rows, and DrawVbo's conditional one
|
||||||
// =====================================================================================
|
// =====================================================================================
|
||||||
|
|||||||
Reference in New Issue
Block a user