From 58b05505129595b38fb512b5b1f2488390e13900 Mon Sep 17 00:00:00 2001 From: Swung0x48 Date: Mon, 19 Oct 2026 02:10:58 -0400 Subject: [PATCH] [Refactor] (MG_Backend/DirectVulkan, MG_Util/ShaderTranspiler): share the integer vertex input masks - IntegerVertexInputMasks, the four narrow data masks and ResolveNarrowIntegerVertexInputs move to MG_Util so another backend can plan the same correction - Magma keeps its VkFormat Note on a derived mask type; behaviour is unchanged --- .../Renderer/NarrowIntegerVertexFormats.h | 56 ++---------------- .../NarrowIntegerVertexInputs.h | 59 +++++++++++++++++-- 2 files changed, 60 insertions(+), 55 deletions(-) diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/NarrowIntegerVertexFormats.h b/MobileGL/MG_Backend/DirectVulkan/Renderer/NarrowIntegerVertexFormats.h index 8f02a1a6..4ab8f9c3 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/NarrowIntegerVertexFormats.h +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/NarrowIntegerVertexFormats.h @@ -14,7 +14,9 @@ #include namespace MobileGL::MG_Backend::DirectVulkan { + using MG_Util::ShaderTranspiler::IntegerVertexInputMasks; using MG_Util::ShaderTranspiler::NarrowIntegerVertexInputs; + using MG_Util::ShaderTranspiler::ResolveNarrowIntegerVertexInputs; // Which vertex inputs need the ExtendNarrowIntegerVertexInputs program variant, decided from // two halves that are each computed once and cached with the object they describe. @@ -58,15 +60,9 @@ namespace MobileGL::MG_Backend::DirectVulkan { } } - // The vertex-input half: the locations whose attribute DATA is narrow integer, by width and - // signedness. Filled from the source formats when a vertex input layout is built, so a draw - // reads four words instead of walking its attributes. - struct NarrowIntegerAttributeMasks { - Uint32 unsigned8 = 0; - Uint32 unsigned16 = 0; - Uint32 signed8 = 0; - Uint32 signed16 = 0; - + // The vertex-input half, filled from the source formats when a vertex input layout is built, + // so a draw reads four words instead of walking its attributes. + struct NarrowIntegerAttributeMasks : MG_Util::ShaderTranspiler::NarrowIntegerAttributeMasks { constexpr void Note(Uint32 location, VkFormat format) { if (location >= 32) return; const Uint32 bit = 1u << location; @@ -88,46 +84,4 @@ namespace MobileGL::MG_Backend::DirectVulkan { } } }; - - // The program half: the locations whose shader input is a 32-bit int or uint scalar/vector. - // Both masks are zero for a program without integer vertex inputs, which is what keeps the - // common draw at four AND instructions. - struct IntegerVertexInputMasks { - Uint32 signedInputs = 0; - Uint32 unsignedInputs = 0; - - constexpr void Note(Uint32 location, GLenum shaderInputType) { - if (location >= 32) return; - const Uint32 bit = 1u << location; - switch (shaderInputType) { - case GL_INT: - case GL_INT_VEC2: - case GL_INT_VEC3: - case GL_INT_VEC4: - signedInputs |= bit; - break; - case GL_UNSIGNED_INT: - case GL_UNSIGNED_INT_VEC2: - case GL_UNSIGNED_INT_VEC3: - case GL_UNSIGNED_INT_VEC4: - unsignedInputs |= bit; - break; - default: - break; - } - } - }; - - // Unsigned narrow data into an int input is fetched sign-extended and must be zero-extended; - // signed narrow data into a uint input is fetched zero-extended and must be sign-extended. - // Matching signedness, 32-bit data and float inputs need nothing. - constexpr NarrowIntegerVertexInputs ResolveNarrowIntegerVertexInputs(const IntegerVertexInputMasks& inputs, - const NarrowIntegerAttributeMasks& data) { - NarrowIntegerVertexInputs result; - result.zeroExtend8 = inputs.signedInputs & data.unsigned8; - result.zeroExtend16 = inputs.signedInputs & data.unsigned16; - result.signExtend8 = inputs.unsignedInputs & data.signed8; - result.signExtend16 = inputs.unsignedInputs & data.signed16; - return result; - } } // namespace MobileGL::MG_Backend::DirectVulkan diff --git a/MobileGL/MG_Util/ShaderTranspiler/NarrowIntegerVertexInputs.h b/MobileGL/MG_Util/ShaderTranspiler/NarrowIntegerVertexInputs.h index 2ddc8db9..aa736fb7 100644 --- a/MobileGL/MG_Util/ShaderTranspiler/NarrowIntegerVertexInputs.h +++ b/MobileGL/MG_Util/ShaderTranspiler/NarrowIntegerVertexInputs.h @@ -13,10 +13,10 @@ namespace MobileGL { namespace MG_Util { namespace ShaderTranspiler { // The vertex input locations whose integer value a vertex module has to widen itself, - // one bit per location in each mask, and how. Every desktop GL driver hands an integer - // input the source integer converted to 32 bits by the SOURCE type's signedness and - // then reinterpreted as the declared int/uint type. A Vulkan fetch whose format has to - // carry the input's signedness instead extends by the wrong rule for 8/16-bit data: + // one bit per location in each mask, and how. GL hands an integer input the source + // integer converted to 32 bits by the SOURCE type's signedness and then reinterpreted + // as the declared int/uint type. A backend whose fetch has to carry the input's + // signedness instead extends 8/16-bit data by the wrong rule: // - zeroExtend*: an int input fed unsigned bytes/shorts, fetched sign-extended, is // masked back to its low 8/16 bits; // - signExtend*: a uint input fed signed bytes/shorts, fetched zero-extended, has its @@ -33,6 +33,57 @@ namespace MobileGL { }; // Hashed as raw bytes by the program cache, so it must stay free of padding. static_assert(sizeof(NarrowIntegerVertexInputs) == 4 * sizeof(Uint32)); + + // The vertex-input half: the locations whose attribute DATA is narrow integer, by width + // and signedness. Each backend fills it from its own description of the data. + struct NarrowIntegerAttributeMasks { + Uint32 unsigned8 = 0; + Uint32 unsigned16 = 0; + Uint32 signed8 = 0; + Uint32 signed16 = 0; + }; + + // The program half: the locations whose shader input is a 32-bit int or uint scalar/vector. + // Both masks are zero for a program without integer vertex inputs, which is what keeps the + // common draw at four AND instructions. + struct IntegerVertexInputMasks { + Uint32 signedInputs = 0; + Uint32 unsignedInputs = 0; + + constexpr void Note(Uint32 location, GLenum shaderInputType) { + if (location >= 32) return; + const Uint32 bit = 1u << location; + switch (shaderInputType) { + case GL_INT: + case GL_INT_VEC2: + case GL_INT_VEC3: + case GL_INT_VEC4: + signedInputs |= bit; + break; + case GL_UNSIGNED_INT: + case GL_UNSIGNED_INT_VEC2: + case GL_UNSIGNED_INT_VEC3: + case GL_UNSIGNED_INT_VEC4: + unsignedInputs |= bit; + break; + default: + break; + } + } + }; + + // Unsigned narrow data into an int input is fetched sign-extended and must be zero-extended; + // signed narrow data into a uint input is fetched zero-extended and must be sign-extended. + // Matching signedness, 32-bit data and float inputs need nothing. + constexpr NarrowIntegerVertexInputs ResolveNarrowIntegerVertexInputs( + const IntegerVertexInputMasks& inputs, const NarrowIntegerAttributeMasks& data) { + NarrowIntegerVertexInputs result; + result.zeroExtend8 = inputs.signedInputs & data.unsigned8; + result.zeroExtend16 = inputs.signedInputs & data.unsigned16; + result.signExtend8 = inputs.unsignedInputs & data.signed8; + result.signExtend16 = inputs.unsignedInputs & data.signed16; + return result; + } } // namespace ShaderTranspiler } // namespace MG_Util } // namespace MobileGL