diff --git a/MobileGL/MG_Backend/BackendObject.h b/MobileGL/MG_Backend/BackendObject.h index 37e9aaec..e12b1778 100644 --- a/MobileGL/MG_Backend/BackendObject.h +++ b/MobileGL/MG_Backend/BackendObject.h @@ -111,11 +111,18 @@ namespace MobileGL { GLsizei height, GLint border); void (*CopyTexSubImage2D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); + // The by-name form: the destination is `texture`, whatever the units hold. `target` is + // the one the record carries (the texture's own 2D-class target). + void (*CopyTextureSubImage2D)(const SharedPtr& texture, GLenum target, + GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, + GLsizei height); void (*CopyImageSubData)(const CopyImageEndpoint& src, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, const CopyImageEndpoint& dst, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth); void (*GenerateMipmap)(GLenum target); + // The by-name form, also used once the bound-target form has resolved its texture. + void (*GenerateTextureMipmap)(const SharedPtr& texture, GLenum target); void (*ReadPixels)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels); void (*GetTexImage)(GLenum target, GLint level, GLenum format, GLenum type, GLvoid* pixels); diff --git a/MobileGL/MG_Impl/Pipe/Verb/VerbPort.cpp b/MobileGL/MG_Impl/Pipe/Verb/VerbPort.cpp index bffb5cce..a3bba8fc 100644 --- a/MobileGL/MG_Impl/Pipe/Verb/VerbPort.cpp +++ b/MobileGL/MG_Impl/Pipe/Verb/VerbPort.cpp @@ -471,18 +471,21 @@ namespace MobileGL::MG_Record { EmitF1Clear("ClearNamedFramebufferfi", MG_Pipe::MGPipeFramebufferEmitter::HandleFor(*fbo), buffer, drawbuffer, MG_Pipe::kMGPipeClearValueClassFloat, nullptr, depth, stencil); } + // The target-taking slots name the texture through the active unit; the by-name slots pass + // it in. Both build the same record, so the server cannot tell the two apart. const SharedPtr& F1BoundTexture(GLenum target) { auto& ctx = *MG_State::pGLContext; return ctx.GetTextureUnitObject(ctx.GetActiveTextureUnit()) .GetBindingSlot(MG_Util::ConvertGLEnumToTextureTarget(target)) .GetBoundObject(); } - void EmitF1Copy(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, + void EmitF1Copy(const char* slot, const SharedPtr& destination, + GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, GLint xoffset, GLint yoffset, Bool subImage) { - VerbChannel session = ChannelFor(subImage ? "CopyTexSubImage2D" : "CopyTexImage2D"); + VerbChannel session = ChannelFor(slot); BeforeReadOnlyVerb(); MG_Pipe::MGPCopyFromFramebuffer record{}; - record.Dst = MG_Pipe::MGPipeTextureEmitterInstance().FindTexture(*F1BoundTexture(target)); + record.Dst = MG_Pipe::MGPipeTextureEmitterInstance().FindTexture(*destination); record.Target = static_cast(target); record.Level = level; record.InternalFormat = format; @@ -498,16 +501,22 @@ namespace MobileGL::MG_Record { } void EmitCopyTexImage2D(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, GLint) { - EmitF1Copy(target, level, format, x, y, width, height, 0, 0, false); + EmitF1Copy("CopyTexImage2D", F1BoundTexture(target), target, level, format, x, y, width, height, 0, 0, + false); } void EmitCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) { - EmitF1Copy(target, level, 0, x, y, width, height, xoffset, yoffset, true); + EmitF1Copy("CopyTexSubImage2D", F1BoundTexture(target), target, level, 0, x, y, width, height, xoffset, + yoffset, true); } - void EmitGenerateMipmap(GLenum target) { - VerbChannel session = ChannelFor("GenerateMipmap"); + void EmitCopyTextureSubImage2D(const SharedPtr& texture, GLenum target, + GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, + GLsizei height) { + EmitF1Copy("CopyTextureSubImage2D", texture, target, level, 0, x, y, width, height, xoffset, yoffset, true); + } + void EmitMipPlan(const char* slot, const SharedPtr& texture, GLenum target) { + VerbChannel session = ChannelFor(slot); BeforeReadOnlyVerb(); - const auto& texture = F1BoundTexture(target); MG_Pipe::MGPMipPlan record{}; record.Res = MG_Pipe::MGPipeTextureEmitterInstance().FindTexture(*texture); record.Target = static_cast(target); @@ -523,6 +532,12 @@ namespace MobileGL::MG_Record { session.EmitAndWait(MG_Pipe::MGPWireOp::GenerateMipmap, &record, sizeof(record), nullptr, 0, nullptr, 0, nullptr); } + void EmitGenerateMipmap(GLenum target) { + EmitMipPlan("GenerateMipmap", F1BoundTexture(target), target); + } + void EmitGenerateTextureMipmap(const SharedPtr& texture, GLenum target) { + EmitMipPlan("GenerateTextureMipmap", texture, target); + } // All draw entry points share the owned-input preparation and emission below. [[noreturn]] void RefuseDrawByName(const char* slot, const char* qualifier); @@ -1639,7 +1654,9 @@ namespace MobileGL::MG_Record { table.GL.ClearNamedFramebufferuiv = &EmitClearNamedFramebufferuiv; table.GL.CopyTexImage2D = &EmitCopyTexImage2D; table.GL.CopyTexSubImage2D = &EmitCopyTexSubImage2D; + table.GL.CopyTextureSubImage2D = &EmitCopyTextureSubImage2D; table.GL.GenerateMipmap = &EmitGenerateMipmap; + table.GL.GenerateTextureMipmap = &EmitGenerateTextureMipmap; table.GL.GetTexImage = &EmitGetTexImage; table.GL.GetTextureImage = &EmitGetTextureImage; table.GL.BindImageTexture = &EmitBindImageTexture; @@ -1680,8 +1697,10 @@ namespace MobileGL::MG_Record { // P13 W4b: the texture family - its record arm resolves the texture from the verb's own // handle (VerbMipRes, VerbCopyTexDst, the copy's two endpoints). table.GL.GenerateMipmap = &EmitGenerateMipmap; + table.GL.GenerateTextureMipmap = &EmitGenerateTextureMipmap; table.GL.CopyTexImage2D = &EmitCopyTexImage2D; table.GL.CopyTexSubImage2D = &EmitCopyTexSubImage2D; + table.GL.CopyTextureSubImage2D = &EmitCopyTextureSubImage2D; table.GL.CopyImageSubData = &EmitCopyImageSubData; table.GL.ReadPixels = &EmitReadPixels; table.GL.GetTexImage = &EmitGetTexImage; diff --git a/MobileGL/MG_IntegrationTest/Harness/SplitRuntimePeek.h b/MobileGL/MG_IntegrationTest/Harness/SplitRuntimePeek.h index b7768d11..8424abf7 100644 --- a/MobileGL/MG_IntegrationTest/Harness/SplitRuntimePeek.h +++ b/MobileGL/MG_IntegrationTest/Harness/SplitRuntimePeek.h @@ -69,7 +69,7 @@ namespace MGITest { bool dataArmIsRecord = false; // ClientSession::Active() != nullptr. bool sessionActive = false; - // ImplementedVerbCount(), out of kRemoteEmitSlotCount (71). + // ImplementedVerbCount(), out of kRemoteEmitSlotCount (73). unsigned int implementedVerbs = 0; unsigned int totalVerbSlots = 0; // The encoder's highest produced record ordinal, or 0 when there is no session. diff --git a/MobileGL/MG_Pipe/FillPoints.def b/MobileGL/MG_Pipe/FillPoints.def index e2dc420f..496228f3 100644 --- a/MobileGL/MG_Pipe/FillPoints.def +++ b/MobileGL/MG_Pipe/FillPoints.def @@ -51,8 +51,10 @@ X(BlitNamedFramebuffer, kBlitOrCopy) \ X(CopyTexImage2D, kBlitOrCopy) \ X(CopyTexSubImage2D, kBlitOrCopy) \ + X(CopyTextureSubImage2D, kBlitOrCopy) \ X(CopyImageSubData, kBlitOrCopy) \ X(GenerateMipmap, kTextureOp) \ + X(GenerateTextureMipmap, kTextureOp) \ X(ReadPixels, kReadback) \ X(GetTexImage, kReadback) \ X(GetTextureImage, kReadback) \ diff --git a/MobileGL/MG_Pipe/VerbRecordOps.h b/MobileGL/MG_Pipe/VerbRecordOps.h index 4b11b059..7eecd62e 100644 --- a/MobileGL/MG_Pipe/VerbRecordOps.h +++ b/MobileGL/MG_Pipe/VerbRecordOps.h @@ -56,8 +56,10 @@ X(BlitNamedFramebuffer, Blit) \ X(CopyTexImage2D, CopyFramebufferToTexture) \ X(CopyTexSubImage2D, CopyFramebufferToTexture) \ + X(CopyTextureSubImage2D, CopyFramebufferToTexture) \ X(CopyImageSubData, ResourceCopyRegion) \ X(GenerateMipmap, GenerateMipmap) \ + X(GenerateTextureMipmap, GenerateMipmap) \ /* read_pixels (reply) or read_pixels_to_buffer (pack buffer): the reply wins. */ \ X(ReadPixels, ReadPixels) \ /* get_texture_image (reply) or its pack-buffer half: the reply wins. */ \ diff --git a/MobileGL/MG_Pipe/generated/PipeFieldOwnership.inc b/MobileGL/MG_Pipe/generated/PipeFieldOwnership.inc index 58151cc9..75726d1c 100644 --- a/MobileGL/MG_Pipe/generated/PipeFieldOwnership.inc +++ b/MobileGL/MG_Pipe/generated/PipeFieldOwnership.inc @@ -366,8 +366,10 @@ inline constexpr MGPipeFieldMask kMGPipeAdmittedPullMask[kMGPipeVerbCount] = { {{0x0000000000000000ull, 0x0000000000000000ull}}, // BlitNamedFramebuffer {{0x0000000000000000ull, 0x0000000000000000ull}}, // CopyTexImage2D {{0x0000000000000000ull, 0x0000000000000000ull}}, // CopyTexSubImage2D + {{0x0000000000000000ull, 0x0000000000000000ull}}, // CopyTextureSubImage2D {{0x0000000000000000ull, 0x0000000000000000ull}}, // CopyImageSubData {{0x0000000000000000ull, 0x0000000000000000ull}}, // GenerateMipmap + {{0x0000000000000000ull, 0x0000000000000000ull}}, // GenerateTextureMipmap {{0x0000000000000000ull, 0x0000000000000000ull}}, // ReadPixels {{0x0000000000000000ull, 0x0000000000000000ull}}, // GetTexImage {{0x0000000000000000ull, 0x0000000000000000ull}}, // GetTextureImage diff --git a/MobileGL/MG_Pipe/generated/PipeFillPoints.inc b/MobileGL/MG_Pipe/generated/PipeFillPoints.inc index 1512f363..79e30246 100644 --- a/MobileGL/MG_Pipe/generated/PipeFillPoints.inc +++ b/MobileGL/MG_Pipe/generated/PipeFillPoints.inc @@ -52,8 +52,10 @@ enum class MGPipeVerb : Uint8 { BlitNamedFramebuffer, CopyTexImage2D, CopyTexSubImage2D, + CopyTextureSubImage2D, CopyImageSubData, GenerateMipmap, + GenerateTextureMipmap, ReadPixels, GetTexImage, GetTextureImage, @@ -92,7 +94,7 @@ enum class MGPipeVerb : Uint8 { }; inline constexpr SizeT kMGPipeVerbCount = static_cast(MGPipeVerb::kVerbCount); -static_assert(kMGPipeVerbCount == 69, "the GLFunctionsTable verb set moved"); +static_assert(kMGPipeVerbCount == 71, "the GLFunctionsTable verb set moved"); inline constexpr const char* kMGPipeVerbNames[kMGPipeVerbCount] = { "DrawArrays", @@ -128,8 +130,10 @@ inline constexpr const char* kMGPipeVerbNames[kMGPipeVerbCount] = { "BlitNamedFramebuffer", "CopyTexImage2D", "CopyTexSubImage2D", + "CopyTextureSubImage2D", "CopyImageSubData", "GenerateMipmap", + "GenerateTextureMipmap", "ReadPixels", "GetTexImage", "GetTextureImage", @@ -228,8 +232,10 @@ inline constexpr MGPipeVerbClass kMGPipeVerbClass[kMGPipeVerbCount] = { MGPipeVerbClass::kBlitOrCopy, // BlitNamedFramebuffer MGPipeVerbClass::kBlitOrCopy, // CopyTexImage2D MGPipeVerbClass::kBlitOrCopy, // CopyTexSubImage2D + MGPipeVerbClass::kBlitOrCopy, // CopyTextureSubImage2D MGPipeVerbClass::kBlitOrCopy, // CopyImageSubData MGPipeVerbClass::kTextureOp, // GenerateMipmap + MGPipeVerbClass::kTextureOp, // GenerateTextureMipmap MGPipeVerbClass::kReadback, // ReadPixels MGPipeVerbClass::kReadback, // GetTexImage MGPipeVerbClass::kReadback, // GetTextureImage diff --git a/MobileGL/MG_Remote/Client/EmitTables.cpp b/MobileGL/MG_Remote/Client/EmitTables.cpp index f143195a..e4b3ecfa 100644 --- a/MobileGL/MG_Remote/Client/EmitTables.cpp +++ b/MobileGL/MG_Remote/Client/EmitTables.cpp @@ -67,7 +67,7 @@ namespace MobileGL::MG_Remote::Client { using MG_Record::LogE2ControlLine; // The slot arithmetic, asserted rather than commented. GlobalBackendFunctionsTable is - // GLFunctionsTable plus Present plus SetSwapInterval; GLFunctionsTable is 69 function + // GLFunctionsTable plus Present plus SetSwapInterval; GLFunctionsTable is 71 function // pointers plus one Bool (PrefersCpuXfbPrimitiveAccounting). A slot // added to either without a decision here is a build break, which is the point: R-4 forbids // a null slot, so a new slot needs an owner on the day it appears. @@ -76,7 +76,7 @@ namespace MobileGL::MG_Remote::Client { "GlobalBackendFunctionsTable is no longer GLFunctionsTable + Present + SetSwapInterval"); static_assert(sizeof(MG_Backend::GlobalBackendFunctionsTable) == kRemoteEmitSlotCount * sizeof(void (*)()) + sizeof(void (*)()), - "the emit table's 71 slots plus the packed Bool no longer describe the table"); + "the emit table's 73 slots plus the packed Bool no longer describe the table"); namespace { @@ -558,7 +558,7 @@ namespace MobileGL::MG_Remote::Client { constexpr Uint32 kEmittedSlotsD1 = 19; constexpr Uint32 kEmittedSlotsI1 = 7; constexpr Uint32 kEmittedSlotsT2 = 7; - constexpr Uint32 kEmittedSlotsF1 = 11; + constexpr Uint32 kEmittedSlotsF1 = 13; // BlitNamedFramebuffer, both texture readbacks, and SetSwapInterval (P10 B) - the one // class-B slot that crosses as a surface control frame rather than a SEG_CMD record. constexpr Uint32 kEmittedSlotsTail = 4; @@ -575,12 +575,12 @@ namespace MobileGL::MG_Remote::Client { static_assert(kUnmigratedD1 + kEmittedSlotsD1 == 19, "d1 owns the 19 draw slots"); static_assert(kUnmigratedI1 + kEmittedSlotsI1 == 7, "i1 owns the 7 image/compute/barrier/copy/SSBO slots"); static_assert(kUnmigratedT2 + kEmittedSlotsT2 == 7, "t2 owns the 7 XFB/tessellation slots"); - static_assert(kUnmigratedF1 + kEmittedSlotsF1 == 11, "f1 owns the 11 clear/copy/mip slots"); + static_assert(kUnmigratedF1 + kEmittedSlotsF1 == 13, "f1 owns the 13 clear/copy/mip slots"); static_assert(kUnmigratedTail + kEmittedSlotsTail + kEmittedSlotsSync + kEmittedSlotsQueries == 20, "the original wave-3 tail owns 20 slots"); - static_assert(kUnmigratedSlots + kEmittedSlots == 69, "class B and C own 69 slots"); + static_assert(kUnmigratedSlots + kEmittedSlots == 71, "class B and C own 71 slots"); static_assert(kLocallyAnsweredSlots + kEmittedSlots + kUnmigratedSlots == kRemoteEmitSlotCount, - "the three classes no longer partition the 71 slots"); + "the three classes no longer partition the 73 slots"); MG_Backend::GlobalBackendFunctionsTable BuildRemoteEmitTable() { MG_Record::ArmVerbControlKnobs(); diff --git a/MobileGL/MG_Remote/Client/EmitTables.h b/MobileGL/MG_Remote/Client/EmitTables.h index af78cfc1..9439528f 100644 --- a/MobileGL/MG_Remote/Client/EmitTables.h +++ b/MobileGL/MG_Remote/Client/EmitTables.h @@ -69,14 +69,14 @@ namespace MobileGL::MG_Remote::Client { using MG_Record::TightReadbackByteCount; using MG_Record::UnmigratedVerbFatal; - // How many of the 71 slots have a real emitter. Reported at bring-up and asserted by the + // How many of the 73 slots have a real emitter. Reported at bring-up and asserted by the // gate: a table that silently loses an emitter should not be able to look the same as one // that never had it. Uint32 ImplementedVerbCount(); // The total the count above is out of. Asserted against the struct in EmitTables.cpp, so // a slot added to GLFunctionsTable without a decision here is a build break. - inline constexpr Uint32 kRemoteEmitSlotCount = 71; + inline constexpr Uint32 kRemoteEmitSlotCount = 73; // The other two thirds of the census, so a case can assert the WHOLE partition rather than // only the half that emits. CONTRACT-P5.md ยง7's three classes are 2 + 5 + 64, and diff --git a/MobileGL/MG_Test/Pipe/PipeCatalogueTest.cpp b/MobileGL/MG_Test/Pipe/PipeCatalogueTest.cpp index b4e39975..a9f8ab90 100644 --- a/MobileGL/MG_Test/Pipe/PipeCatalogueTest.cpp +++ b/MobileGL/MG_Test/Pipe/PipeCatalogueTest.cpp @@ -938,10 +938,10 @@ TEST(PipeCatalogue, PipeInputFieldsStartUnfilled) { EXPECT_FALSE(MGPipeInputFieldIsFresh(state, MGPipeInputField::GetRenderStateParameters)); } -// G5b: the verb enum is GLFunctionsTable's member list (69 entries), every class has verbs, +// G5b: the verb enum is GLFunctionsTable's member list (71 entries), every class has verbs, // and the seven sticky fields ride in every class mask (P1 brief D7). TEST(PipeCatalogue, VerbTableIsTheFunctionTable) { - EXPECT_EQ(kMGPipeVerbCount, 69u); + EXPECT_EQ(kMGPipeVerbCount, 71u); EXPECT_EQ(kMGPipeVerbClassCount, 9u); SizeT perClass[kMGPipeVerbClassCount] = {}; for (SizeT v = 0; v < kMGPipeVerbCount; ++v) { @@ -964,6 +964,7 @@ TEST(PipeCatalogue, VerbTableIsTheFunctionTable) { EXPECT_FALSE(MGPipeFieldMaskHas(query, MGPipeInputField::GetRenderStateParameters)); EXPECT_TRUE(MGPipeFieldMaskHas(query, MGPipeInputField::GetTransformFeedbackPausedPrimitiveCounter)); EXPECT_EQ(kMGPipeVerbClass[static_cast(MGPipeVerb::GenerateMipmap)], MGPipeVerbClass::kTextureOp); + EXPECT_EQ(kMGPipeVerbClass[static_cast(MGPipeVerb::GenerateTextureMipmap)], MGPipeVerbClass::kTextureOp); EXPECT_STREQ(kMGPipeVerbNames[static_cast(MGPipeVerb::GetGpuTimestampNs)], "GetGpuTimestampNs"); } diff --git a/MobileGL/MG_Test/Pipe/PipeInputsTest.cpp b/MobileGL/MG_Test/Pipe/PipeInputsTest.cpp index 58dc5b07..41ea85d1 100644 --- a/MobileGL/MG_Test/Pipe/PipeInputsTest.cpp +++ b/MobileGL/MG_Test/Pipe/PipeInputsTest.cpp @@ -359,7 +359,7 @@ TEST_F(PipeInputsTest, MutatedFieldIsNamedAtRead) { ::_exit(3); }); ASSERT_TRUE(DiedOfAbort(r)) << DescribeStatus(r) << "\n" << r.Log; - EXPECT_NE(r.Log.find("MGPipe: verify armed - 63 fields, 69 verbs, fatal=1"), std::string::npos) << r.Log; + EXPECT_NE(r.Log.find("MGPipe: verify armed - 63 fields, 71 verbs, fatal=1"), std::string::npos) << r.Log; EXPECT_NE(r.Log.find("MGPipe: verify read of GetLineWidth (index 0, 0) differs from the live context"), std::string::npos) << r.Log; @@ -389,7 +389,7 @@ TEST_F(PipeInputsTest, VerifyCorruptKnobNamesTheFieldAtEntry) { ::_exit(3); }); ASSERT_TRUE(DiedOfAbort(r)) << DescribeStatus(r) << "\n" << r.Log; - EXPECT_NE(r.Log.find("MGPipe: verify armed - 63 fields, 69 verbs, fatal=1"), std::string::npos) << r.Log; + EXPECT_NE(r.Log.find("MGPipe: verify armed - 63 fields, 71 verbs, fatal=1"), std::string::npos) << r.Log; EXPECT_NE(r.Log.find("MGPipe: verify corruption armed - GetRenderStateParameters"), std::string::npos) << r.Log; const std::string expected = "Fatal{PipeVerifyDiffer, \"GetRenderStateParameters@DrawArrays\", verb=" + std::to_string(serial) + @@ -445,7 +445,7 @@ TEST_F(PipeInputsTest, VerifyFatalOffLogsTheDivergenceAndContinues) { std::exit(0); }); ASSERT_TRUE(ExitedWith(r, 0)) << DescribeStatus(r) << "\n" << r.Log; - EXPECT_NE(r.Log.find("MGPipe: verify armed - 63 fields, 69 verbs, fatal=0"), std::string::npos) << r.Log; + EXPECT_NE(r.Log.find("MGPipe: verify armed - 63 fields, 71 verbs, fatal=0"), std::string::npos) << r.Log; EXPECT_NE(r.Log.find("MGPipe: verify summary - 2 divergence(s) survived MOBILEGL_PIPE_VERIFY_FATAL=0"), std::string::npos) << r.Log; diff --git a/MobileGL/MG_Test/Wire/CMakeLists.txt b/MobileGL/MG_Test/Wire/CMakeLists.txt index 9278ab1f..128b38c8 100644 --- a/MobileGL/MG_Test/Wire/CMakeLists.txt +++ b/MobileGL/MG_Test/Wire/CMakeLists.txt @@ -209,7 +209,7 @@ gtest_discover_tests(PipeWireCodecTest DISCOVERY_TIMEOUT 30 PROPERTIES LABELS un # main() of its own. All three also reach MG_Pipe, MG_Backend and MG_State, so all three carry # those include paths. # -# RemoteClientTest the 71-slot emit table, the caps mirror, R-8's liveness gates, R-17's +# RemoteClientTest the 73-slot emit table, the caps mirror, R-8's liveness gates, R-17's # routing and ID-47/ID-49's readback rules (c1) # ServerLoopTest the apply thread, the blocking control mailbox, the verb stamp and # R-11's server-owned staging copy (v1) diff --git a/MobileGL/MG_Test/Wire/RemoteClientTest.cpp b/MobileGL/MG_Test/Wire/RemoteClientTest.cpp index 5a91eaaf..0135c200 100644 --- a/MobileGL/MG_Test/Wire/RemoteClientTest.cpp +++ b/MobileGL/MG_Test/Wire/RemoteClientTest.cpp @@ -6,7 +6,7 @@ // SPDX-License-Identifier: LGPL-3.0-only // End of Source File Header -// P5 package c1's suite: the 71-slot emit table, the caps mirror and R-8's liveness gates. +// P5 package c1's suite: the 73-slot emit table, the caps mirror and R-8's liveness gates. // The helper cases below are supplemented by RemoteClientControls.inc: installed producers // over a live session, with adversarial peer replies and a repeated-make-current control. // @@ -192,11 +192,11 @@ namespace { // The emit table: the partition, and that no slot is null // ===================================================================================== -TEST(RemoteEmitTable, TheThreeClassesPartitionAllSeventyOneSlots) { - // P5 baseline five + f1 eleven + i1 seven + t2 six emitted slots, ... and since P10 B the +TEST(RemoteEmitTable, TheThreeClassesPartitionEverySlot) { + // P5 baseline five + f1 thirteen + i1 seven + t2 six emitted slots, ... and since P10 B the // swap interval: class C is EMPTY, every slot but the two local answers reaches the server. EXPECT_EQ(LocallyAnsweredSlotCount(), 2u); - EXPECT_EQ(ImplementedVerbCount(), 69u); + EXPECT_EQ(ImplementedVerbCount(), 71u); EXPECT_EQ(UnmigratedSlotCount(), 0u); EXPECT_EQ(LocallyAnsweredSlotCount() + ImplementedVerbCount() + UnmigratedSlotCount(), kRemoteEmitSlotCount); } @@ -298,7 +298,7 @@ TEST(RemoteEmitTable, NoSlotIsNull) { const MG_Backend::GlobalBackendFunctionsTable& table = RemoteEmitTable(); const void* const* cells = reinterpret_cast(&table); const SizeT cellCount = sizeof(table) / sizeof(void*); - // The struct is 71 function pointers plus ONE cell holding the packed Bool + // The struct is 73 function pointers plus ONE cell holding the packed Bool // PrefersCpuXfbPrimitiveAccounting and its padding (EmitTables.cpp static_asserts exactly // that shape). That Bool is legitimately zero when the server did not publish // kCapCpuXfbPrimitiveAccounting, so at most one cell may read null - and this is stated as @@ -1981,6 +1981,65 @@ TEST(RemoteF1, GenerateMipmapFieldsCross) { EXPECT_TRUE(WIFEXITED(child.Status) && WEXITSTATUS(child.Status) == 0) << "F1.GenerateMipmap.fields: " << DescribeStatus(child) << child.Log; } + +namespace { + // A second texture for the by-name slots, acquired but NOT bound: F1Texture's stays on the unit. + SharedPtr F1NamedTexture() { + auto tex = MakeShared(92); + tex->SetInternalFormat(TextureInternalFormat::RGBA8); + for (Uint level = 0; level != 2; ++level) { + const Int size = 4 >> level; + tex->AllocateStorage( + TextureUploadTarget::Texture2D, level, + MG_State::GLState::MipmapInput{IntVec3{size, size, 1}, static_cast(size * size * 4)}); + } + MGPipeTextureEmitterInstance().AcquireTexture(tex->GetLifetimeId(), tex.get()); + return tex; + } +} // namespace + +// The by-name slots name their texture themselves: the record carries the named texture's handle +// while another texture stays bound on the active unit. +TEST(RemoteF1, CopyTextureSubImage2DNamesItsTextureNotTheBoundOne) { + const auto child = RunInChild([] { + StartControlSession(); + F1Peer peer; + peer.Install(); + const auto bound = F1Texture(); + const auto named = F1NamedTexture(); + RemoteEmitTable().GL.CopyTextureSubImage2D(named, GL_TEXTURE_2D, 1, 1, 0, -3, 4, 1, 2); + const auto& r = peer.copy; + if (peer.calls != 1 || r.Dst != MGPipeTextureEmitterInstance().FindTexture(*named) || + MGPipeHandleIsNull(r.Dst) || r.Dst == MGPipeTextureEmitterInstance().FindTexture(*bound) || + r.Target != GL_TEXTURE_2D || r.Level != 1 || r.XOffset != 1 || r.YOffset != 0 || r.X != -3 || r.Y != 4 || + r.Width != 1 || r.Height != 2 || r.SubImage != 1) + ::_exit(101); + ClientSessionInstance().Stop(); + }); + EXPECT_TRUE(WIFEXITED(child.Status) && WEXITSTATUS(child.Status) == 0) + << "F1.CopyTextureSubImage2D.fields: " << DescribeStatus(child) << child.Log; +} + +TEST(RemoteF1, GenerateTextureMipmapNamesItsTextureNotTheBoundOne) { + const auto child = RunInChild([] { + StartControlSession(); + F1Peer peer; + peer.Install(); + const auto bound = F1Texture(); + const auto named = F1NamedTexture(); + RemoteEmitTable().GL.GenerateTextureMipmap(named, GL_TEXTURE_2D); + const GLfloat fence[4] = {0, 0, 0, 0}; // see GenerateMipmapFieldsCross + RemoteEmitTable().GL.ClearBufferfv(GL_COLOR, 0, fence); + const auto& r = peer.mip; + if (peer.calls != 2 || r.Res != MGPipeTextureEmitterInstance().FindTexture(*named) || + MGPipeHandleIsNull(r.Res) || r.Res == MGPipeTextureEmitterInstance().FindTexture(*bound) || + r.Target != GL_TEXTURE_2D || r.BaseLevel != 0 || r.LevelCount != 2) + ::_exit(101); + ClientSessionInstance().Stop(); + }); + EXPECT_TRUE(WIFEXITED(child.Status) && WEXITSTATUS(child.Status) == 0) + << "F1.GenerateTextureMipmap.fields: " << DescribeStatus(child) << child.Log; +} #endif #if MGTEST_HAVE_FORK diff --git a/scripts/data/skip_census_baseline.json b/scripts/data/skip_census_baseline.json index 01ecd7f6..54c2c008 100644 --- a/scripts/data/skip_census_baseline.json +++ b/scripts/data/skip_census_baseline.json @@ -9121,7 +9121,7 @@ "RemoteEmitTable.TheNineteenDrawSlotsAreEmittersDistinctFromEveryStub", "RemoteEmitTable.TheSevenI1SlotsAreClassBAndAreNotTheFatalThunk", "RemoteEmitTable.TheSixXfbAndPatchSlotsAreNonNullAndDistinct", - "RemoteEmitTable.TheThreeClassesPartitionAllSeventyOneSlots", + "RemoteEmitTable.TheThreeClassesPartitionEverySlot", "RemoteF1.AnIndirectDrawStashesTheCommandAndParameterBuffers", "RemoteF1.BlitNamedCarriesHandlesAndLeavesTheClientBindingsAlone", "RemoteF1.BoundBlitCarriesNoHandlesAndIsAppliedAsBefore",