[Test] fix the two new stage-chunk cases' own expectations

Both cases were written against the wrong property and went red on the first WGB
build, which is the one thing a case may not do.

TextureEmit.ALevelTooLargeForTheStageChunkIsCutIntoSlabs asserted D == 8 slices for
every slab of the 512x128x33 level, whose last slab is the 33rd slice alone. The
per-slab check now names the scheme (Z = 8 * index, D = 8 for every slab but the
remainder) instead of restating one number for all of them.

StagedTextureStoreTest.ALevelWithAPieceMissingIsRefusedAsAWholeLevelReadByName
wanted "not covered" out of a single LEADING run, and the store cannot answer that:
it knows no format, so it cannot know how many bytes the level should have - the
check is "the range the reader asks is covered". The case now uses the shape the
check really is about, two runs with a hole between them (ServerLoopTest's
R-11 coverage case, one store over), and the looseness is written down: in the
header's coverage ruling, and as an assertion on the leading-run case beside it.
This commit is contained in:
2026-09-20 19:22:38 -04:00
parent 9469d48edb
commit 7059869848
3 changed files with 27 additions and 6 deletions
@@ -61,7 +61,11 @@
// that lets the sync read - the set is complete exactly when every piece has landed, and a level
// with a hole in it is Fatal{StageSnapshotTooNarrow}: the same words as the buffer half, for the
// same reason, because those bytes have never existed on this side and inventing them is silent
// data loss rather than a missing optimisation.
// data loss rather than a missing optimisation. THE QUESTION IS "IS THE RANGE THE READER ASKS
// FOR COVERED", not "is the level the size the client meant": no format crosses the wire, so a
// leading run that already reaches the image's high-water mark reads as complete when later
// pieces are still missing - unreachable, because nothing reads between the pieces of one verb,
// and written down here because it is the one place this check is looser than it looks.
//
// DEFINED-NESS IS TRACKED, NOT DERIVED ALONE. §1's per-level extent derivation (max(1,
// base >> level), layer axes fixed) computes the extent of a level that EXISTS; it cannot
+4 -2
View File
@@ -666,12 +666,14 @@ TEST(TextureEmit, ALevelTooLargeForTheStageChunkIsCutIntoSlabs) {
const Uint64 volumeBytes = 512ull * 128ull * 33ull * 16ull;
const std::vector<MGPipeTextureSlab> volumeSlabs = cut(volume, volumeBytes, cap);
ASSERT_EQ(volumeSlabs.size(), 5u);
for (const MGPipeTextureSlab& slab : volumeSlabs) {
for (SizeT i = 0; i < volumeSlabs.size(); ++i) {
const MGPipeTextureSlab& slab = volumeSlabs[i];
EXPECT_EQ(slab.Box.X, 0);
EXPECT_EQ(slab.Box.Y, 0);
EXPECT_EQ(slab.Box.W, 512u) << "a slab is not the level's full width";
EXPECT_EQ(slab.Box.H, 128u);
EXPECT_EQ(slab.Box.D, 8u);
EXPECT_EQ(slab.Box.Z, static_cast<Int32>(8 * i)) << "the slabs are not in slice order";
EXPECT_EQ(slab.Box.D, i + 1 == volumeSlabs.size() ? 1u : 8u);
}
EXPECT_EQ(volumeSlabs.back().Box.D, 1u) << "the remainder slice is its own piece";
@@ -281,6 +281,17 @@ TEST(StagedTextureStoreTest, StageChunkRunsAssembleTheLevelImageAndAGapIsNotCove
EXPECT_EQ(store.LevelCoveredRunCount(holed, kTex2DTarget, 0), 2u)
<< "two runs with a 16-byte gap merged into one";
EXPECT_FALSE(store.IsCovered(holed, kTex2DTarget, 0)) << "a span across the gap reads covered";
// AND WHAT THE CHECK CANNOT SEE, written down rather than left to be discovered: the store
// knows no format, so it cannot know how many bytes a level SHOULD have. A leading run that
// already reaches the image's high-water mark therefore reads as covered - the check is "the
// range the reader asks for is covered", not "the level is the size the client meant", and no
// reader runs between the pieces of one level anyway (they are records of ONE verb, and the
// texture sync runs at the barrier that closes it).
const Uint64 leading = Server::StagedTextureStore::KeyForHandle(TestHandle(14, 1));
store.AdoptRun(leading, kTex2DTarget, 0, IntVec3{4, 4, 1}, 0, part.data(), part.size());
EXPECT_TRUE(store.IsCovered(leading, kTex2DTarget, 0))
<< "a leading run is the whole image as far as this store can tell";
EXPECT_EQ(store.LevelByteSize(leading, kTex2DTarget, 0), 16u);
// Filling the gap merges all three into one run: adjacency, not proximity, is the rule.
store.AdoptRun(holed, kTex2DTarget, 0, extent, 16, part.data(), part.size());
EXPECT_EQ(store.LevelCoveredRunCount(holed, kTex2DTarget, 0), 1u);
@@ -398,11 +409,15 @@ TEST(StagedTextureStoreTest, AGpuGeneratedLevelHasNoBytesAndItsTexelReadIsFatalB
TEST(StagedTextureStoreTest, ALevelWithAPieceMissingIsRefusedAsAWholeLevelReadByName) {
Server::StagedTextureStore store(/*copies=*/true);
const Uint64 key = Server::StagedTextureStore::KeyForHandle(TestHandle(13, 1));
Vector<Uint8> half(32, 0x55);
Vector<Uint8> part(16, 0x55);
Vector<Uint8> whole(64, 0x22);
store.AdoptRun(key, kTex2DTarget, 0, IntVec3{4, 4, 1}, 0, half.data(), half.size());
// TWO RUNS WITH A HOLE BETWEEN THEM, which is what a missing piece looks like from here: the
// image's high-water mark is the level's size and the covered set does not reach across it.
store.AdoptRun(key, kTex2DTarget, 0, IntVec3{4, 4, 1}, 0, part.data(), part.size());
store.AdoptRun(key, kTex2DTarget, 0, IntVec3{4, 4, 1}, 32, part.data(), part.size());
ASSERT_FALSE(store.IsCovered(key, kTex2DTarget, 0));
ASSERT_EQ(store.LevelCoveredRunCount(key, kTex2DTarget, 0), 1u);
ASSERT_EQ(store.LevelCoveredRunCount(key, kTex2DTarget, 0), 2u);
ASSERT_EQ(store.LevelByteSize(key, kTex2DTarget, 0), 48u);
// A DIFFERENT level of the same store, adopted whole, reads fine - asserted first so that the
// death below cannot be a function that aborts on everything.