From e5eabd08f583fbdd3bb2551778e5ecb67dff0843 Mon Sep 17 00:00:00 2001 From: Scott Mansell Date: Fri, 7 Aug 2026 17:12:00 +1200 Subject: [PATCH] Optimize vertex_shader_uid_data down to 28 bytes This started as a fixing a misalignment issue, but I got carried away. Was originally 41 bytes (overflowing it's expected 40 bytes by 1 bit). Now it's 27 bytes plus 8 bits of padding (ready for future expansion). The savings come from: - Removing UV usage from components, it can be reconstructed from texcoord_elem_count (saved 8 bits) - Removed the 8 unused bits from texMtxInfo_n_projection (saved 8 bits) - Removing unused bit from from start of components (saved 1 bit) - Removed extra bit from inputform, texgentype and sourcerow - packed texMtxInfo_n_projection and texcoord_elem_count back into the per texgen info space freed up above. (saved 24 bits) - Overlayed postMtx index and Emboss mode shifts into a union based on texgentype (saved 56 bits) - Move to a single-bit union tag, freeing up an extra bit for regular texgens. - Move PotMtx normalize into the freed up space (saved 8 bits) Total savings: 105 bits of data EDIT: Even worse, MSVC wasn't respecting pack(1) for bitfields at all, so on windows this struct was actually quite a bit larger. Something like 80 bytes, if not more. Fixed this by dropping the size of any enums used in these bit structs to u8. Our Common::BitField allows for the underlying type to be explicitly specified to something larger. msvc's bitfield packing appears to be completely braindead, can't mix sizes at all. --- Source/Core/VideoCommon/GXPipelineTypes.h | 2 +- Source/Core/VideoCommon/NativeVertexFormat.h | 54 +++---- Source/Core/VideoCommon/PipelineUtils.cpp | 3 +- Source/Core/VideoCommon/VertexShaderGen.cpp | 150 ++++++++++--------- Source/Core/VideoCommon/VertexShaderGen.h | 71 +++++---- Source/Core/VideoCommon/XFMemory.h | 16 +- 6 files changed, 164 insertions(+), 132 deletions(-) diff --git a/Source/Core/VideoCommon/GXPipelineTypes.h b/Source/Core/VideoCommon/GXPipelineTypes.h index 388551e767..22014c993f 100644 --- a/Source/Core/VideoCommon/GXPipelineTypes.h +++ b/Source/Core/VideoCommon/GXPipelineTypes.h @@ -19,7 +19,7 @@ namespace VideoCommon // As pipelines encompass both shader UIDs and render states, changes to either of these should // also increment the pipeline UID version. Incrementing the UID version will cause all UID // caches to be invalidated. -constexpr u32 GX_PIPELINE_UID_VERSION = 8; // Last changed in PR 12185 +constexpr u32 GX_PIPELINE_UID_VERSION = 9; // Last changed in PR 14789 struct GXPipelineUid { diff --git a/Source/Core/VideoCommon/NativeVertexFormat.h b/Source/Core/VideoCommon/NativeVertexFormat.h index 0f6be25541..76ca7875c2 100644 --- a/Source/Core/VideoCommon/NativeVertexFormat.h +++ b/Source/Core/VideoCommon/NativeVertexFormat.h @@ -12,36 +12,38 @@ // m_components enum : u32 { - VB_HAS_POSMTXIDX = (1 << 1), - VB_HAS_TEXMTXIDX0 = (1 << 2), - VB_HAS_TEXMTXIDX1 = (1 << 3), - VB_HAS_TEXMTXIDX2 = (1 << 4), - VB_HAS_TEXMTXIDX3 = (1 << 5), - VB_HAS_TEXMTXIDX4 = (1 << 6), - VB_HAS_TEXMTXIDX5 = (1 << 7), - VB_HAS_TEXMTXIDX6 = (1 << 8), - VB_HAS_TEXMTXIDX7 = (1 << 9), - VB_HAS_TEXMTXIDXALL = (0xff << 2), + VB_HAS_TEXMTXIDX0 = (1 << 0), + VB_HAS_TEXMTXIDX1 = (1 << 1), + VB_HAS_TEXMTXIDX2 = (1 << 2), + VB_HAS_TEXMTXIDX3 = (1 << 3), + VB_HAS_TEXMTXIDX4 = (1 << 4), + VB_HAS_TEXMTXIDX5 = (1 << 5), + VB_HAS_TEXMTXIDX6 = (1 << 6), + VB_HAS_TEXMTXIDX7 = (1 << 7), + VB_HAS_TEXMTXIDXALL = (0xff << 0), + + VB_HAS_POSMTXIDX = (1 << 8), // VB_HAS_POS=0, // Implied, it always has pos! don't bother testing - VB_HAS_NORMAL = (1 << 10), - VB_HAS_TANGENT = (1 << 11), - VB_HAS_BINORMAL = (1 << 12), + VB_HAS_NORMAL = (1 << 9), + VB_HAS_TANGENT = (1 << 10), + VB_HAS_BINORMAL = (1 << 11), - VB_COL_SHIFT = 13, - VB_HAS_COL0 = (1 << 13), - VB_HAS_COL1 = (1 << 14), + VB_COL_SHIFT = 12, + VB_HAS_COL0 = (1 << 12), + VB_HAS_COL1 = (1 << 13), + VB_HAS_SHARED = 0x3f << 8, - VB_HAS_UV0 = (1 << 15), - VB_HAS_UV1 = (1 << 16), - VB_HAS_UV2 = (1 << 17), - VB_HAS_UV3 = (1 << 18), - VB_HAS_UV4 = (1 << 19), - VB_HAS_UV5 = (1 << 20), - VB_HAS_UV6 = (1 << 21), - VB_HAS_UV7 = (1 << 22), - VB_HAS_UVALL = (0xff << 15), - VB_HAS_UVTEXMTXSHIFT = 13, + VB_HAS_UV0 = (1 << 16), + VB_HAS_UV1 = (1 << 17), + VB_HAS_UV2 = (1 << 18), + VB_HAS_UV3 = (1 << 19), + VB_HAS_UV4 = (1 << 20), + VB_HAS_UV5 = (1 << 21), + VB_HAS_UV6 = (1 << 22), + VB_HAS_UV7 = (1 << 23), + VB_HAS_UVALL = (0xff << 16), + VB_HAS_UVTEXMTXSHIFT = 16, }; struct AttributeFormat diff --git a/Source/Core/VideoCommon/PipelineUtils.cpp b/Source/Core/VideoCommon/PipelineUtils.cpp index 40d9d08458..7562c99d2e 100644 --- a/Source/Core/VideoCommon/PipelineUtils.cpp +++ b/Source/Core/VideoCommon/PipelineUtils.cpp @@ -125,13 +125,12 @@ GXPipelineUid ApplyDriverBugs(const GXPipelineUid& in) vertex_shader_uid_data* vs = out.vs_uid.GetUidData(); const PortableVertexDeclaration& decl = out.vertex_format->GetVertexDeclaration(); vs->position_has_3_elems = decl.position.components >= 3; - vs->texcoord_elem_count = 0; for (int i = 0; i < 8; i++) { if (decl.texcoords[i].enable) { ASSERT(decl.texcoords[i].components <= 3); - vs->texcoord_elem_count |= decl.texcoords[i].components << (i * 2); + vs->texGenInfo[i].texcoord_elem_count = decl.texcoords[i].components; } } out.vertex_format = nullptr; diff --git a/Source/Core/VideoCommon/VertexShaderGen.cpp b/Source/Core/VideoCommon/VertexShaderGen.cpp index 837c30c556..ac0950628a 100644 --- a/Source/Core/VideoCommon/VertexShaderGen.cpp +++ b/Source/Core/VideoCommon/VertexShaderGen.cpp @@ -22,52 +22,68 @@ VertexShaderUid GetVertexShaderUid() VertexShaderUid out; vertex_shader_uid_data* const uid_data = out.GetUidData(); uid_data->numTexGens = xfmem.numTexGen.numTexGens; - uid_data->components = VertexLoaderManager::g_current_components; uid_data->numColorChans = xfmem.numChan.numColorChans; + uid_data->components = + VertexLoaderManager::g_current_components & (VB_HAS_SHARED | VB_HAS_TEXMTXIDXALL); + + // Move UV components into texcoord_elem_count + for (u32 i = 0; i < 8; i++) + { + if (VertexLoaderManager::g_current_components & (VB_HAS_UV0 << i)) + { + // Hardcode to 2 components (ApplyDriverBugs will replace this with an exact count if needed) + uid_data->texGenInfo[i].texcoord_elem_count = 2; + } + } + GetLightingShaderUid(uid_data->lighting); // transform texcoords for (u32 i = 0; i < uid_data->numTexGens; ++i) { - auto& texinfo = uid_data->texMtxInfo[i]; + auto& texinfo = uid_data->texGenInfo[i]; + // sourcerow, inputform and texgentype each have an extra bit that gets ignored later. + // Validate and eliminate them now to save space in the UID. + ASSERT(xfmem.texMtxInfo[i].sourcerow <= SourceRow::Tex7); texinfo.sourcerow = xfmem.texMtxInfo[i].sourcerow; - texinfo.texgentype = xfmem.texMtxInfo[i].texgentype; - texinfo.inputform = xfmem.texMtxInfo[i].inputform; + texinfo.inputform = xfmem.texMtxInfo[i].inputform == TexInputForm::ABC1 ? TexInputForm::ABC1 : + TexInputForm::AB11; + auto texgentype = xfmem.texMtxInfo[i].texgentype; // first transformation - switch (texinfo.texgentype) + switch (texgentype) { + default: + case TexGenType::Regular: + texinfo.is_regular_texgen = true; + texinfo.regular.projection = xfmem.texMtxInfo[i].projection; + + // only put dualTexTrans_enabled in UID if we have at least one regular texgen. + uid_data->dualTexTrans_enabled = xfmem.dualTexTrans.enabled; + + // CHECKME: does this only work for regular tex gen types? + if (uid_data->dualTexTrans_enabled) + { + texinfo.regular.postmtx_index = xfmem.postMtxInfo[i].index; + texinfo.regular.postmtx_normalize = xfmem.postMtxInfo[i].normalize; + } + break; case TexGenType::EmbossMap: // calculate tex coords into bump map + texinfo.is_regular_texgen = false; + texinfo.other.texgentype = texgentype; + + // transform the light dir into tangent space + texinfo.other.emboss_sourceshift = xfmem.texMtxInfo[i].embosssourceshift; if ((uid_data->components & (VB_HAS_TANGENT | VB_HAS_BINORMAL)) != 0) - { - // transform the light dir into tangent space - texinfo.embosslightshift = xfmem.texMtxInfo[i].embosslightshift; - texinfo.embosssourceshift = xfmem.texMtxInfo[i].embosssourceshift; - } - else - { - texinfo.embosssourceshift = xfmem.texMtxInfo[i].embosssourceshift; - } + texinfo.other.emboss_lightshift = xfmem.texMtxInfo[i].embosslightshift; break; case TexGenType::Color0: case TexGenType::Color1: + texinfo.is_regular_texgen = false; + texinfo.other.texgentype = texgentype; break; - case TexGenType::Regular: - default: - uid_data->texMtxInfo_n_projection |= static_cast(xfmem.texMtxInfo[i].projection.Value()) - << i; - break; - } - - uid_data->dualTexTrans_enabled = xfmem.dualTexTrans.enabled; - // CHECKME: does this only work for regular tex gen types? - if (uid_data->dualTexTrans_enabled && texinfo.texgentype == TexGenType::Regular) - { - auto& postInfo = uid_data->postMtxInfo[i]; - postInfo.index = xfmem.postMtxInfo[i].index; - postInfo.normalize = xfmem.postMtxInfo[i].normalize; } } @@ -163,10 +179,10 @@ static void WriteTexCoordTransforms(APIType api_type, const ShaderHostConfig& ho { for (u32 i = 0; i < uid_data->numTexGens; ++i) { - auto& texinfo = uid_data->texMtxInfo[i]; + auto& texinfo = uid_data->texGenInfo[i]; out.Write("vec3 dolphin_transform_texcoord{}(vec4 coord)\n", i); out.Write("{{\n"); - if (texinfo.texgentype != TexGenType::Regular) + if (!texinfo.is_regular_texgen) { out.Write("\treturn vec3(coord.xyz);\n"); } @@ -176,7 +192,7 @@ static void WriteTexCoordTransforms(APIType api_type, const ShaderHostConfig& ho if ((uid_data->components & (VB_HAS_TEXMTXIDX0 << i)) != 0) { out.Write("\tint tmp = int(rawtex{}.z);\n", i); - if (static_cast((uid_data->texMtxInfo_n_projection >> i) & 1) == TexSize::STQ) + if (texinfo.regular.projection == TexSize::STQ) { out.Write("\tresult = vec3(dot(coord, " I_TRANSFORMMATRICES "[tmp]), dot(coord, " I_TRANSFORMMATRICES @@ -190,7 +206,7 @@ static void WriteTexCoordTransforms(APIType api_type, const ShaderHostConfig& ho } else { - if (static_cast((uid_data->texMtxInfo_n_projection >> i) & 1) == TexSize::STQ) + if (texinfo.regular.projection == TexSize::STQ) { out.Write("\tresult = vec3(dot(coord, " I_TEXMATRICES "[{}]), dot(coord, " I_TEXMATRICES "[{}]), dot(coord, " I_TEXMATRICES "[{}]));\n", @@ -206,14 +222,14 @@ static void WriteTexCoordTransforms(APIType api_type, const ShaderHostConfig& ho // CHECKME: does this only work for regular tex gen types? if (uid_data->dualTexTrans_enabled) { - auto& postInfo = uid_data->postMtxInfo[i]; + auto postmtx_index = texinfo.regular.postmtx_index; out.Write("\tvec4 P0 = " I_POSTTRANSFORMMATRICES "[{}];\n" "\tvec4 P1 = " I_POSTTRANSFORMMATRICES "[{}];\n" "\tvec4 P2 = " I_POSTTRANSFORMMATRICES "[{}];\n", - postInfo.index & 0x3f, (postInfo.index + 1) & 0x3f, (postInfo.index + 2) & 0x3f); + postmtx_index & 0x3f, (postmtx_index + 1) & 0x3f, (postmtx_index + 2) & 0x3f); - if (postInfo.normalize) + if (texinfo.regular.postmtx_normalize) out.Write("\tresult = normalize(result);\n"); // multiply by postmatrix @@ -313,7 +329,7 @@ static void WriteVertexDefines(APIType, const ShaderHostConfig&, for (u32 i = 0; i < uid_data->numTexGens; i++) { - if ((uid_data->components & (VB_HAS_UV0 << i)) != 0) + if (uid_data->texGenInfo[i].texcoord_elem_count != 0) { out.Write("#define HAS_TEXTURE_COORD_{} 1\n", i); } @@ -415,7 +431,7 @@ ShaderCode GenerateVertexShaderCode(APIType api_type, const ShaderHostConfig& ho { const u32 has_texmtx = (uid_data->components & (VB_HAS_TEXMTXIDX0 << i)); - if ((uid_data->components & (VB_HAS_UV0 << i)) != 0 || has_texmtx != 0) + if (uid_data->texGenInfo[i].texcoord_elem_count != 0 || has_texmtx != 0) { out.Write("ATTRIBUTE_LOCATION({:s}) in float{} rawtex{};\n", ShaderAttrib::TexCoord0 + i, has_texmtx != 0 ? 3 : 2, i); @@ -472,30 +488,25 @@ ShaderCode GenerateVertexShaderCode(APIType api_type, const ShaderHostConfig& ho } for (int i = 0; i < 8; i++) { - if (uid_data->components & (VB_HAS_UV0 << i)) + switch (uid_data->texGenInfo[i].texcoord_elem_count) { - u32 ncomponents = (uid_data->texcoord_elem_count >> (2 * i)) & 3; - if (ncomponents < 2) - { - out.Write(" float tex{};\n", i); - input_extract.Write("float3 rawtex{0} = float3(i.tex{0}, 0.0f, 0.0f);\n", i); - } - else if (ncomponents == 2) - { - out.Write(" float tex{0}_0;\n" - " float tex{0}_1;\n", - i); - input_extract.Write("float3 rawtex{0} = float3(i.tex{0}_0, i.tex{0}_1, 0.0f);\n", i); - } - else - { - out.Write(" float tex{0}_0;\n" - " float tex{0}_1;\n" - " float tex{0}_2;\n", - i); - input_extract.Write("float3 rawtex{0} = float3(i.tex{0}_0, i.tex{0}_1, i.tex{0}_2);\n", - i); - } + case 1: + out.Write(" float tex{};\n", i); + input_extract.Write("float3 rawtex{0} = float3(i.tex{0}, 0.0f, 0.0f);\n", i); + break; + case 2: + out.Write(" float tex{0}_0;\n" + " float tex{0}_1;\n", + i); + input_extract.Write("float3 rawtex{0} = float3(i.tex{0}_0, i.tex{0}_1, 0.0f);\n", i); + break; + case 3: + out.Write(" float tex{0}_0;\n" + " float tex{0}_1;\n" + " float tex{0}_2;\n", + i); + input_extract.Write("float3 rawtex{0} = float3(i.tex{0}_0, i.tex{0}_1, i.tex{0}_2);\n", i); + break; } } out.Write("}};\n\n" @@ -633,7 +644,7 @@ ShaderCode GenerateVertexShaderCode(APIType api_type, const ShaderHostConfig& ho for (u32 i = 0; i < uid_data->numTexGens; ++i) { - auto& texinfo = uid_data->texMtxInfo[i]; + auto& texinfo = uid_data->texGenInfo[i]; out.Write("\t{{\n"); out.Write("\t\tvec4 coord = vec4(0.0, 0.0, 1.0, 1.0);\n"); @@ -649,7 +660,9 @@ ShaderCode GenerateVertexShaderCode(APIType api_type, const ShaderHostConfig& ho } break; case SourceRow::Colors: - ASSERT(texinfo.texgentype == TexGenType::Color0 || texinfo.texgentype == TexGenType::Color1); + ASSERT(!texinfo.is_regular_texgen); + ASSERT(texinfo.other.texgentype == TexGenType::Color0 || + texinfo.other.texgentype == TexGenType::Color1); break; case SourceRow::BinormalT: if ((uid_data->components & VB_HAS_TANGENT) != 0) @@ -664,9 +677,8 @@ ShaderCode GenerateVertexShaderCode(APIType api_type, const ShaderHostConfig& ho } break; default: - ASSERT(texinfo.sourcerow >= SourceRow::Tex0 && texinfo.sourcerow <= SourceRow::Tex7); u32 texnum = static_cast(texinfo.sourcerow) - static_cast(SourceRow::Tex0); - if ((uid_data->components & (VB_HAS_UV0 << (texnum))) != 0) + if (uid_data->texGenInfo[texnum].texcoord_elem_count != 0) { out.Write("\t\tcoord = vec4(rawtex{}.x, rawtex{}.y, 1.0, 1.0);\n", texnum, texnum); } @@ -917,23 +929,25 @@ void WriteVertexBody(APIType api_type, const ShaderHostConfig& host_config, for (u32 i = 0; i < uid_data->numTexGens; ++i) { - auto& texinfo = uid_data->texMtxInfo[i]; + auto& texinfo = uid_data->texGenInfo[i]; - switch (texinfo.texgentype) + auto texgentype = texinfo.is_regular_texgen ? TexGenType::Regular : texinfo.other.texgentype; + + switch (texgentype) { case TexGenType::EmbossMap: // calculate tex coords into bump map out.Write("\t{{\n"); // transform the light dir into tangent space out.Write("\t\tvec3 ldir = normalize(" LIGHT_POS ".xyz - vertex_output.position.xyz);\n", - LIGHT_POS_PARAMS(texinfo.embosslightshift)); + LIGHT_POS_PARAMS(texinfo.other.emboss_lightshift)); out.Write("\t\tvec3 tangent = vertex_input.tangent * dolphin_normal_matrix();\n"); out.Write("\t\tvec3 binormal = vertex_input.binormal * dolphin_normal_matrix();\n"); out.Write("\t\tvertex_output.texture_coord_{}.xyz = vertex_output.texture_coord_{}.xyz + " "vec3(dot(ldir, tangent), " "dot(ldir, binormal), 0.0);\n", - i, texinfo.embosssourceshift); + i, texinfo.other.emboss_sourceshift); out.Write("\t}}\n"); break; case TexGenType::Color0: diff --git a/Source/Core/VideoCommon/VertexShaderGen.h b/Source/Core/VideoCommon/VertexShaderGen.h index 3e9b73940b..a0fd342621 100644 --- a/Source/Core/VideoCommon/VertexShaderGen.h +++ b/Source/Core/VideoCommon/VertexShaderGen.h @@ -10,9 +10,10 @@ #include "VideoCommon/ShaderGenCommon.h" enum class APIType; -enum class TexInputForm : u32; -enum class TexGenType : u32; -enum class SourceRow : u32; +enum class TexInputForm : u8; +enum class TexGenType : u8; +enum class SourceRow : u8; +enum class TexSize : u8; enum class VSExpand : u32; // TODO should be reordered @@ -50,41 +51,57 @@ constexpr ShaderAttrib operator+(ShaderAttrib attrib, int offset) return static_cast(static_cast(attrib) + offset); } -#pragma pack(1) - -struct vertex_shader_uid_data +// Currently optimized to 28 bytes (with 8 bits spare) +// The smaller (and less redundant) this is, the better. +// Though, it probably does like to be somewhat aligned. +struct alignas(4) vertex_shader_uid_data { u32 NumValues() const { return sizeof(vertex_shader_uid_data); } - u32 components : 23; - u32 numTexGens : 4; - u32 numColorChans : 2; - u32 dualTexTrans_enabled : 1; - VSExpand vs_expand : 2; + u32 components : 14; u32 position_has_3_elems : 1; + u32 dualTexTrans_enabled : 1; + u32 numTexGens : 4; // if more bits are needed, this could be eliminated by somehow marking the + // first unused texGen as empty. + u32 numColorChans : 2; // Output color channels. + VSExpand vs_expand : 2; - u16 texcoord_elem_count; // 2 bits per texcoord input - u16 texMtxInfo_n_projection; // Stored separately to guarantee that the texMtxInfo struct is - // 8 bits wide + u32 pad : 8; + // texInfo is optimized to fit all per-texgen config into just 16-bits. + // But it did require a union struct { - TexInputForm inputform : 2; - TexGenType texgentype : 3; - SourceRow sourcerow : 5; - u32 embosssourceshift : 3; - u32 embosslightshift : 3; - } texMtxInfo[8]; + u8 texcoord_elem_count : 2; + TexInputForm inputform : 1; + SourceRow sourcerow : 4; + bool is_regular_texgen : 1; // union tag + union + { + struct + { + u8 postmtx_index : 6; + u8 postmtx_normalize : 1; + TexSize projection : 1; + } regular; + struct + { + TexGenType texgentype : 2; + // these are only used by EmbossMap texgen. + u8 emboss_sourceshift : 3; + u8 emboss_lightshift : 3; + } other; + }; + } texGenInfo[8]; - struct - { - u32 index : 6; - u32 normalize : 1; - u32 pad : 1; - } postMtxInfo[8]; + static_assert(sizeof(texGenInfo[0]) == 2, "texGenInfo should be 2 bytes per texgen"); LightingUidData lighting; }; -#pragma pack() + +// We do need to make sure lighting is correctly aligned +static_assert(offsetof(vertex_shader_uid_data, lighting) % alignof(LightingUidData) == 0); +static_assert(offsetof(vertex_shader_uid_data, texGenInfo) % alignof(u32) == 0); +static_assert(sizeof(vertex_shader_uid_data) == 28, "vertex_shader_uid_data should be 28 bytes"); using VertexShaderUid = ShaderUid; diff --git a/Source/Core/VideoCommon/XFMemory.h b/Source/Core/VideoCommon/XFMemory.h index 4077e50859..04d22dc9f3 100644 --- a/Source/Core/VideoCommon/XFMemory.h +++ b/Source/Core/VideoCommon/XFMemory.h @@ -18,7 +18,7 @@ constexpr size_t NUM_XF_COLOR_CHANNELS = 2; // Lighting // Projection -enum class TexSize : u32 +enum class TexSize : u8 { ST = 0, STQ = 1 @@ -30,7 +30,7 @@ struct fmt::formatter : EnumFormatter }; // Input form -enum class TexInputForm : u32 +enum class TexInputForm : u8 { AB11 = 0, ABC1 = 1 @@ -63,7 +63,7 @@ struct fmt::formatter : EnumFormatter }; // Texture generation type -enum class TexGenType : u32 +enum class TexGenType : u8 { Regular = 0, EmbossMap = 1, // Used when bump mapping @@ -83,7 +83,7 @@ struct fmt::formatter : EnumFormatter }; // Source row -enum class SourceRow : u32 +enum class SourceRow : u8 { Geom = 0, // Input is abc Normal = 1, // Input is abc @@ -318,11 +318,11 @@ struct fmt::formatter union TexMtxInfo { BitField<0, 1, u32> unknown; - BitField<1, 1, TexSize> projection; - BitField<2, 1, TexInputForm> inputform; + BitField<1, 1, TexSize, u32> projection; + BitField<2, 1, TexInputForm, u32> inputform; BitField<3, 1, u32> unknown2; - BitField<4, 3, TexGenType> texgentype; - BitField<7, 5, SourceRow> sourcerow; + BitField<4, 3, TexGenType, u32> texgentype; + BitField<7, 5, SourceRow, u32> sourcerow; BitField<12, 3, u32> embosssourceshift; // what generated texcoord to use BitField<15, 3, u32> embosslightshift; // light index that is used u32 hex;