From fdec0ab332736b5d61f493649b83b1cbd239efd6 Mon Sep 17 00:00:00 2001 From: Triang3l Date: Mon, 1 Nov 2021 22:56:24 +0300 Subject: [PATCH] [Code] Make union usage more consistent --- src/xenia/cpu/backend/x64/x64_op.h | 4 +- src/xenia/gpu/command_processor.h | 6 +- .../gpu/d3d12/d3d12_render_target_cache.h | 36 ++++++--- src/xenia/gpu/d3d12/texture_cache.h | 11 +-- src/xenia/gpu/draw_util.h | 17 +++-- src/xenia/gpu/dxbc_shader_translator.h | 7 +- src/xenia/gpu/primitive_processor.h | 23 +++--- src/xenia/gpu/registers.h | 76 +++++++++---------- src/xenia/gpu/render_target_cache.h | 5 +- src/xenia/gpu/ucode.h | 8 +- src/xenia/gpu/vulkan/texture_cache.h | 3 +- src/xenia/gpu/xenos.h | 48 ++++++------ src/xenia/kernel/util/xex2_info.h | 2 +- src/xenia/kernel/xam/user_profile.h | 2 +- src/xenia/kernel/xnotifylistener.cc | 2 +- src/xenia/kernel/xnotifylistener.h | 15 ++-- src/xenia/memory.h | 2 +- src/xenia/vfs/devices/stfs_xbox.h | 6 +- 18 files changed, 148 insertions(+), 125 deletions(-) diff --git a/src/xenia/cpu/backend/x64/x64_op.h b/src/xenia/cpu/backend/x64/x64_op.h index 0846f9255..1f3e38cc6 100644 --- a/src/xenia/cpu/backend/x64/x64_op.h +++ b/src/xenia/cpu/backend/x64/x64_op.h @@ -46,6 +46,7 @@ enum KeyType { #pragma pack(push, 1) union InstrKey { + uint32_t value; struct { uint32_t opcode : 8; uint32_t dest : 5; @@ -54,11 +55,10 @@ union InstrKey { uint32_t src3 : 5; uint32_t reserved : 4; }; - uint32_t value; operator uint32_t() const { return value; } - InstrKey() : value(0) {} + InstrKey() : value(0) { static_assert_size(*this, sizeof(value)); } InstrKey(uint32_t v) : value(v) {} InstrKey(const Instr* i) : value(0) { opcode = i->opcode->num; diff --git a/src/xenia/gpu/command_processor.h b/src/xenia/gpu/command_processor.h index 8199febcf..d2ee29d8f 100644 --- a/src/xenia/gpu/command_processor.h +++ b/src/xenia/gpu/command_processor.h @@ -67,34 +67,34 @@ enum class GammaRampType { struct GammaRamp { struct NormalEntry { union { + uint32_t value; struct { uint32_t b : 10; uint32_t g : 10; uint32_t r : 10; uint32_t : 2; }; - uint32_t value; }; }; struct PWLValue { union { + uint32_t value; struct { uint16_t base; uint16_t delta; }; - uint32_t value; }; }; struct PWLEntry { union { + PWLValue values[3]; struct { PWLValue r; PWLValue g; PWLValue b; }; - PWLValue values[3]; }; }; diff --git a/src/xenia/gpu/d3d12/d3d12_render_target_cache.h b/src/xenia/gpu/d3d12/d3d12_render_target_cache.h index 19a367bd8..e8b0431c9 100644 --- a/src/xenia/gpu/d3d12/d3d12_render_target_cache.h +++ b/src/xenia/gpu/d3d12/d3d12_render_target_cache.h @@ -410,6 +410,7 @@ class D3D12RenderTargetCache final : public RenderTargetCache { static const TransferModeInfo kTransferModes[size_t(TransferMode::kCount)]; union TransferShaderKey { + uint32_t key; struct { xenos::MsaaSamples dest_msaa_samples : xenos::kMsaaSamplesBits; uint32_t dest_resource_format : xenos::kRenderTargetFormatBits; @@ -433,7 +434,9 @@ class D3D12RenderTargetCache final : public RenderTargetCache { static_assert(size_t(TransferMode::kCount) <= (size_t(1) << 3)); TransferMode mode : 3; }; - uint32_t key = 0; + + TransferShaderKey() : key(0) { static_assert_size(*this, sizeof(key)); } + struct Hasher { size_t operator()(const TransferShaderKey& key) const { return std::hash{}(key.key); @@ -451,6 +454,7 @@ class D3D12RenderTargetCache final : public RenderTargetCache { }; union TransferAddressConstant { + uint32_t constant; struct { // All in tiles. uint32_t dest_pitch : xenos::kEdramPitchTilesBits; @@ -466,7 +470,9 @@ class D3D12RenderTargetCache final : public RenderTargetCache { // destination == source anyway). int32_t source_to_dest : xenos::kEdramBaseTilesBits; }; - uint32_t constant = 0; + TransferAddressConstant() : constant(0) { + static_assert_size(*this, sizeof(constant)); + } bool operator==(const TransferAddressConstant& other_constant) const { return constant == other_constant.constant; } @@ -474,7 +480,6 @@ class D3D12RenderTargetCache final : public RenderTargetCache { return !(*this == other_constant); } }; - static_assert(sizeof(TransferAddressConstant) == sizeof(uint32_t)); struct TransferInvocation { Transfer transfer; @@ -515,6 +520,7 @@ class D3D12RenderTargetCache final : public RenderTargetCache { }; union HostDepthStoreRectangleConstant { + uint32_t constant; struct { // - 1 because the maximum is 0x1FFF / 8, not 0x2000 / 8. uint32_t x_pixels_div_8 : xenos::kResolveSizeBits - 1 - @@ -524,11 +530,13 @@ class D3D12RenderTargetCache final : public RenderTargetCache { uint32_t width_pixels_div_8_minus_1 : xenos::kResolveSizeBits - 1 - xenos::kResolveAlignmentPixelsLog2; }; - uint32_t constant = 0; + HostDepthStoreRectangleConstant() : constant(0) { + static_assert_size(*this, sizeof(constant)); + } }; - static_assert(sizeof(HostDepthStoreRectangleConstant) == sizeof(uint32_t)); union HostDepthStoreRenderTargetConstant { + uint32_t constant; struct { uint32_t pitch_tiles : xenos::kEdramPitchTilesBits; // 1 to 3. @@ -536,9 +544,10 @@ class D3D12RenderTargetCache final : public RenderTargetCache { // Whether 2x MSAA is supported natively rather than through 4x. uint32_t msaa_2x_supported : 1; }; - uint32_t constant = 0; + HostDepthStoreRenderTargetConstant() : constant(0) { + static_assert_size(*this, sizeof(constant)); + } }; - static_assert(sizeof(HostDepthStoreRenderTargetConstant) == sizeof(uint32_t)); enum { kHostDepthStoreRootParameterRectangleConstant, @@ -549,6 +558,7 @@ class D3D12RenderTargetCache final : public RenderTargetCache { }; union DumpPipelineKey { + uint32_t key; struct { xenos::MsaaSamples msaa_samples : 2; uint32_t resource_format : 4; @@ -556,7 +566,9 @@ class D3D12RenderTargetCache final : public RenderTargetCache { // change it at most once. Depth buffers have an additional stencil SRV. uint32_t is_depth : 1; }; - uint32_t key = 0; + + DumpPipelineKey() : key(0) { static_assert_size(*this, sizeof(key)); } + struct Hasher { size_t operator()(const DumpPipelineKey& key) const { return std::hash{}(key.key); @@ -583,13 +595,14 @@ class D3D12RenderTargetCache final : public RenderTargetCache { }; union DumpOffsets { + uint32_t offsets; struct { // Absolute index of the first thread group's tile within the source // texture. uint32_t first_group_tile_source_relative : xenos::kEdramBaseTilesBits; uint32_t source_base_tiles : xenos::kEdramBaseTilesBits; }; - uint32_t offsets = 0; + DumpOffsets() : offsets(0) { static_assert_size(*this, sizeof(offsets)); } bool operator==(const DumpOffsets& other_offsets) const { return offsets == other_offsets.offsets; } @@ -597,15 +610,15 @@ class D3D12RenderTargetCache final : public RenderTargetCache { return !(*this == other_offsets); } }; - static_assert(sizeof(DumpOffsets) == sizeof(uint32_t)); union DumpPitches { + uint32_t pitches; struct { // Both in tiles. uint32_t source_pitch : xenos::kEdramPitchTilesBits; uint32_t dest_pitch : xenos::kEdramPitchTilesBits; }; - uint32_t pitches = 0; + DumpPitches() : pitches(0) { static_assert_size(*this, sizeof(pitches)); } bool operator==(const DumpPitches& other_pitches) const { return pitches == other_pitches.pitches; } @@ -613,7 +626,6 @@ class D3D12RenderTargetCache final : public RenderTargetCache { return !(*this == other_pitches); } }; - static_assert(sizeof(DumpPitches) == sizeof(uint32_t)); enum DumpCbuffer : uint32_t { kDumpCbufferOffsets, diff --git a/src/xenia/gpu/d3d12/texture_cache.h b/src/xenia/gpu/d3d12/texture_cache.h index 21a100ea2..f32031075 100644 --- a/src/xenia/gpu/d3d12/texture_cache.h +++ b/src/xenia/gpu/d3d12/texture_cache.h @@ -124,6 +124,7 @@ class TextureCache { // Sampler parameters that can be directly converted to a host sampler or used // for binding checking validity whether samplers are up to date. union SamplerParameters { + uint32_t value; struct { xenos::ClampMode clamp_x : 3; // 3 xenos::ClampMode clamp_y : 3; // 6 @@ -137,16 +138,8 @@ class TextureCache { uint32_t mip_min_level : 4; // 21 // Maximum mip level is in the texture resource itself. }; - uint32_t value; - // Clearing the unused bits. - SamplerParameters() : value(0) {} - SamplerParameters(const SamplerParameters& parameters) - : value(parameters.value) {} - SamplerParameters& operator=(const SamplerParameters& parameters) { - value = parameters.value; - return *this; - } + SamplerParameters() : value(0) { static_assert_size(*this, sizeof(value)); } bool operator==(const SamplerParameters& parameters) const { return value == parameters.value; } diff --git a/src/xenia/gpu/draw_util.h b/src/xenia/gpu/draw_util.h index 8aa7287f6..a87f82153 100644 --- a/src/xenia/gpu/draw_util.h +++ b/src/xenia/gpu/draw_util.h @@ -215,6 +215,7 @@ xenos::CopySampleSelect SanitizeCopySampleSelect( // constants. union ResolveEdramPackedInfo { + uint32_t packed; struct { // With 32bpp/64bpp taken into account. uint32_t pitch_tiles : xenos::kEdramPitchTilesBits; @@ -228,12 +229,15 @@ union ResolveEdramPackedInfo { // the impact of the half-pixel offset with resolution scaling. uint32_t duplicate_second_pixel : 1; }; - uint32_t packed; + ResolveEdramPackedInfo() : packed(0) { + static_assert_size(*this, sizeof(packed)); + } }; static_assert(sizeof(ResolveEdramPackedInfo) <= sizeof(uint32_t), "ResolveEdramPackedInfo must be packable in uint32_t"); union ResolveAddressPackedInfo { + uint32_t packed; struct { // 160x32 is divisible by both the EDRAM tile size (80x16 samples, but for // simplicity, this is in pixels) and the texture tile size (32x32), so @@ -258,7 +262,9 @@ union ResolveAddressPackedInfo { xenos::CopySampleSelect copy_sample_select : 3; }; - uint32_t packed; + ResolveAddressPackedInfo() : packed(0) { + static_assert_size(*this, sizeof(packed)); + } }; static_assert(sizeof(ResolveAddressPackedInfo) <= sizeof(uint32_t), "ResolveAddressPackedInfo must be packable in uint32_t"); @@ -271,6 +277,7 @@ void GetResolveEdramTileSpan(ResolveEdramPackedInfo edram_info, uint32_t& rows_out); union ResolveCopyDestPitchPackedInfo { + uint32_t packed; struct { // 0...16384/32. uint32_t pitch_aligned_div_32 : xenos::kTexture2DCubeMaxWidthHeightLog2 + @@ -278,10 +285,10 @@ union ResolveCopyDestPitchPackedInfo { uint32_t height_aligned_div_32 : xenos::kTexture2DCubeMaxWidthHeightLog2 + 2 - xenos::kTextureTileWidthHeightLog2; }; - uint32_t packed; + ResolveCopyDestPitchPackedInfo() : packed(0) { + static_assert_size(*this, sizeof(packed)); + } }; -static_assert(sizeof(ResolveCopyDestPitchPackedInfo) <= sizeof(uint32_t), - "ResolveAddressPackedInfo must be packable in uint32_t"); // For backends with Shader Model 5-like compute, host shaders to use to perform // copying in resolve operations. diff --git a/src/xenia/gpu/dxbc_shader_translator.h b/src/xenia/gpu/dxbc_shader_translator.h index f66b7616c..59e5d207f 100644 --- a/src/xenia/gpu/dxbc_shader_translator.h +++ b/src/xenia/gpu/dxbc_shader_translator.h @@ -15,6 +15,7 @@ #include #include +#include "xenia/base/assert.h" #include "xenia/base/math.h" #include "xenia/base/string_buffer.h" #include "xenia/gpu/dxbc.h" @@ -85,6 +86,7 @@ class DxbcShaderTranslator : public ShaderTranslator { kFloat24Rounding, }; + uint64_t value; struct VertexShaderModification { // Dynamically indexable register count from SQ_PROGRAM_CNTL. uint32_t dynamic_addressable_register_count : 8; @@ -98,9 +100,10 @@ class DxbcShaderTranslator : public ShaderTranslator { // Non-ROV - depth / stencil output mode. DepthStencilMode depth_stencil_mode : 2; } pixel; - uint64_t value = 0; - Modification(uint64_t modification_value = 0) : value(modification_value) {} + Modification(uint64_t modification_value = 0) : value(modification_value) { + static_assert_size(*this, sizeof(value)); + } }; // Constant buffer bindings in space 0. diff --git a/src/xenia/gpu/primitive_processor.h b/src/xenia/gpu/primitive_processor.h index 046928738..bfd17caf1 100644 --- a/src/xenia/gpu/primitive_processor.h +++ b/src/xenia/gpu/primitive_processor.h @@ -685,6 +685,7 @@ class PrimitiveProcessor { kCacheBucketSizeBytes; union CacheKey { + uint64_t key; struct { uint32_t base; // 32 total uint32_t count : 16; // 48 @@ -694,19 +695,23 @@ class PrimitiveProcessor { // kNone if not changing the type (like only processing the reset index). xenos::PrimitiveType conversion_guest_primitive_type : 6; // 59 }; - uint64_t key = 0; - CacheKey() = default; + CacheKey() : key(0) { static_assert_size(*this, sizeof(key)); } CacheKey(uint32_t base, uint32_t count, xenos::IndexFormat format, xenos::Endian endian, bool is_reset_enabled, xenos::PrimitiveType conversion_guest_primitive_type = - xenos::PrimitiveType::kNone) - : base(base), - count(count), - format(format), - endian(endian), - is_reset_enabled(is_reset_enabled), - conversion_guest_primitive_type(conversion_guest_primitive_type) {} + xenos::PrimitiveType::kNone) { + // Clear unused bits, then set each field explicitly, not via the + // initializer list (which causes `uint64_t key = 0;` to be ignored, and + // also can't contain initializers for aliasing union members). + key = 0; + this->base = base; + this->count = count; + this->format = format; + this->endian = endian; + this->is_reset_enabled = is_reset_enabled; + this->conversion_guest_primitive_type = conversion_guest_primitive_type; + } struct Hasher { size_t operator()(const CacheKey& key) const { diff --git a/src/xenia/gpu/registers.h b/src/xenia/gpu/registers.h index 029a2d6d8..7e313f09b 100644 --- a/src/xenia/gpu/registers.h +++ b/src/xenia/gpu/registers.h @@ -46,6 +46,7 @@ namespace reg { *******************************************************************************/ union alignas(uint32_t) COHER_STATUS_HOST { + uint32_t value; struct { uint32_t matching_contexts : 8; // +0 uint32_t rb_copy_dest_base_ena : 1; // +8 @@ -64,12 +65,12 @@ union alignas(uint32_t) COHER_STATUS_HOST { uint32_t : 4; // +27 uint32_t status : 1; // +31 }; - uint32_t value; static constexpr Register register_index = XE_GPU_REG_COHER_STATUS_HOST; }; static_assert_size(COHER_STATUS_HOST, sizeof(uint32_t)); union alignas(uint32_t) WAIT_UNTIL { + uint32_t value; struct { uint32_t : 1; // +0 uint32_t wait_re_vsync : 1; // +1 @@ -88,7 +89,6 @@ union alignas(uint32_t) WAIT_UNTIL { uint32_t : 2; // +18 uint32_t cmdfifo_entries : 4; // +20 }; - uint32_t value; static constexpr Register register_index = XE_GPU_REG_WAIT_UNTIL; }; static_assert_size(WAIT_UNTIL, sizeof(uint32_t)); @@ -102,6 +102,7 @@ static_assert_size(WAIT_UNTIL, sizeof(uint32_t)); *******************************************************************************/ union alignas(uint32_t) SQ_PROGRAM_CNTL { + uint32_t value; struct { // Note from a2xx.xml: // Only 0x3F worth of valid register values for VS_NUM_REG and PS_NUM_REG, @@ -118,12 +119,12 @@ union alignas(uint32_t) SQ_PROGRAM_CNTL { uint32_t ps_export_mode : 4; // +27 uint32_t gen_index_vtx : 1; // +31 }; - uint32_t value; static constexpr Register register_index = XE_GPU_REG_SQ_PROGRAM_CNTL; }; static_assert_size(SQ_PROGRAM_CNTL, sizeof(uint32_t)); union alignas(uint32_t) SQ_CONTEXT_MISC { + uint32_t value; struct { uint32_t inst_pred_optimize : 1; // +0 uint32_t sc_output_screen_xy : 1; // +1 @@ -150,19 +151,18 @@ union alignas(uint32_t) SQ_CONTEXT_MISC { uint32_t yeild_optimize : 1; // +17 sic uint32_t tx_cache_sel : 1; // +18 }; - uint32_t value; static constexpr Register register_index = XE_GPU_REG_SQ_CONTEXT_MISC; }; static_assert_size(SQ_CONTEXT_MISC, sizeof(uint32_t)); union alignas(uint32_t) SQ_INTERPOLATOR_CNTL { + uint32_t value; struct { uint32_t param_shade : 16; // +0 // SampleLocation bits - 0 for centroid, 1 for center, if // SQ_CONTEXT_MISC::sc_sample_cntl is kCentroidsAndCenters. uint32_t sampling_pattern : 16; // +16 }; - uint32_t value; static constexpr Register register_index = XE_GPU_REG_SQ_INTERPOLATOR_CNTL; }; static_assert_size(SQ_INTERPOLATOR_CNTL, sizeof(uint32_t)); @@ -186,16 +186,17 @@ static_assert_size(SQ_INTERPOLATOR_CNTL, sizeof(uint32_t)); *******************************************************************************/ union alignas(uint32_t) VGT_DMA_SIZE { + uint32_t value; struct { uint32_t num_words : 24; // +0 uint32_t : 6; // +24 xenos::Endian swap_mode : 2; // +30 }; - uint32_t value; static constexpr Register register_index = XE_GPU_REG_VGT_DMA_SIZE; }; union alignas(uint32_t) VGT_DRAW_INITIATOR { + uint32_t value; // Different than on A2xx and R6xx/R7xx. struct { xenos::PrimitiveType prim_type : 6; // +0 @@ -207,7 +208,6 @@ union alignas(uint32_t) VGT_DRAW_INITIATOR { uint32_t : 3; // +13 uint32_t num_indices : 16; // +16 }; - uint32_t value; static constexpr Register register_index = XE_GPU_REG_VGT_DRAW_INITIATOR; }; static_assert_size(VGT_DRAW_INITIATOR, sizeof(uint32_t)); @@ -223,6 +223,7 @@ static_assert_size(VGT_DRAW_INITIATOR, sizeof(uint32_t)); // clamping. union alignas(uint32_t) VGT_MULTI_PRIM_IB_RESET_INDX { + uint32_t value; struct { // The upper 8 bits of the value from the index buffer are confirmed to be // ignored. So, though this specifically is untested (because @@ -234,13 +235,13 @@ union alignas(uint32_t) VGT_MULTI_PRIM_IB_RESET_INDX { // 0x1FFFFFF, 0xFFFFFFFF all cause primitive reset. uint32_t reset_indx : 24; }; - uint32_t value; static constexpr Register register_index = XE_GPU_REG_VGT_MULTI_PRIM_IB_RESET_INDX; }; static_assert_size(VGT_MULTI_PRIM_IB_RESET_INDX, sizeof(uint32_t)); union alignas(uint32_t) VGT_INDX_OFFSET { + uint32_t value; struct { // Unlike R5xx's VAP_INDEX_OFFSET, which is signed 25-bit, this is 24-bit - // and signedness doesn't matter as index calculations are done in 24-bit @@ -251,44 +252,43 @@ union alignas(uint32_t) VGT_INDX_OFFSET { // anyway, and that has no effect on offsets that fit in 24 bits. uint32_t indx_offset : 24; }; - uint32_t value; static constexpr Register register_index = XE_GPU_REG_VGT_INDX_OFFSET; }; static_assert_size(VGT_INDX_OFFSET, sizeof(uint32_t)); union alignas(uint32_t) VGT_MIN_VTX_INDX { + uint32_t value; struct { uint32_t min_indx : 24; }; - uint32_t value; static constexpr Register register_index = XE_GPU_REG_VGT_MIN_VTX_INDX; }; static_assert_size(VGT_MIN_VTX_INDX, sizeof(uint32_t)); union alignas(uint32_t) VGT_MAX_VTX_INDX { + uint32_t value; struct { // Usually 0xFFFF or 0xFFFFFF. uint32_t max_indx : 24; }; - uint32_t value; static constexpr Register register_index = XE_GPU_REG_VGT_MAX_VTX_INDX; }; static_assert_size(VGT_MAX_VTX_INDX, sizeof(uint32_t)); union alignas(uint32_t) VGT_OUTPUT_PATH_CNTL { + uint32_t value; struct { xenos::VGTOutputPath path_select : 2; // +0 }; - uint32_t value; static constexpr Register register_index = XE_GPU_REG_VGT_OUTPUT_PATH_CNTL; }; static_assert_size(VGT_OUTPUT_PATH_CNTL, sizeof(uint32_t)); union alignas(uint32_t) VGT_HOS_CNTL { + uint32_t value; struct { xenos::TessellationMode tess_mode : 2; // +0 }; - uint32_t value; static constexpr Register register_index = XE_GPU_REG_VGT_HOS_CNTL; }; static_assert_size(VGT_HOS_CNTL, sizeof(uint32_t)); @@ -307,29 +307,30 @@ static_assert_size(VGT_HOS_CNTL, sizeof(uint32_t)); *******************************************************************************/ union alignas(uint32_t) PA_SU_POINT_MINMAX { + uint32_t value; struct { // Radius, 12.4 fixed point. uint32_t min_size : 16; // +0 uint32_t max_size : 16; // +16 }; - uint32_t value; static constexpr Register register_index = XE_GPU_REG_PA_SU_POINT_MINMAX; }; static_assert_size(PA_SU_POINT_MINMAX, sizeof(uint32_t)); union alignas(uint32_t) PA_SU_POINT_SIZE { + uint32_t value; struct { // 1/2 width or height, 12.4 fixed point. uint32_t height : 16; // +0 uint32_t width : 16; // +16 }; - uint32_t value; static constexpr Register register_index = XE_GPU_REG_PA_SU_POINT_SIZE; }; static_assert_size(PA_SU_POINT_SIZE, sizeof(uint32_t)); // Setup Unit / Scanline Converter mode cntl union alignas(uint32_t) PA_SU_SC_MODE_CNTL { + uint32_t value; struct { uint32_t cull_front : 1; // +0 uint32_t cull_back : 1; // +1 @@ -359,36 +360,36 @@ union alignas(uint32_t) PA_SU_SC_MODE_CNTL { // WAIT_RB_IDLE_ALL_TRI and WAIT_RB_IDLE_FIRST_TRI_NEW_STATE were added on // Adreno. }; - uint32_t value; static constexpr Register register_index = XE_GPU_REG_PA_SU_SC_MODE_CNTL; }; static_assert_size(PA_SU_SC_MODE_CNTL, sizeof(uint32_t)); // Setup Unit Vertex Control union alignas(uint32_t) PA_SU_VTX_CNTL { + uint32_t value; struct { uint32_t pix_center : 1; // +0 1 = half pixel offset (OpenGL). uint32_t round_mode : 2; // +1 uint32_t quant_mode : 3; // +3 }; - uint32_t value; static constexpr Register register_index = XE_GPU_REG_PA_SU_VTX_CNTL; }; static_assert_size(PA_SU_VTX_CNTL, sizeof(uint32_t)); union alignas(uint32_t) PA_SC_MPASS_PS_CNTL { + uint32_t value; struct { uint32_t mpass_pix_vec_per_pass : 20; // +0 uint32_t : 11; // +20 uint32_t mpass_ps_ena : 1; // +31 }; - uint32_t value; static constexpr Register register_index = XE_GPU_REG_PA_SC_MPASS_PS_CNTL; }; static_assert_size(PA_SC_MPASS_PS_CNTL, sizeof(uint32_t)); // Scanline converter viz query, used by D3D for gpu side conditional rendering union alignas(uint32_t) PA_SC_VIZ_QUERY { + uint32_t value; struct { // the visibility of draws should be evaluated uint32_t viz_query_ena : 1; // +0 @@ -398,13 +399,13 @@ union alignas(uint32_t) PA_SC_VIZ_QUERY { // not used with d3d uint32_t kill_pix_post_detail_mask : 1; // +8 }; - uint32_t value; static constexpr Register register_index = XE_GPU_REG_PA_SC_VIZ_QUERY; }; static_assert_size(PA_SC_VIZ_QUERY, sizeof(uint32_t)); // Clipper clip control union alignas(uint32_t) PA_CL_CLIP_CNTL { + uint32_t value; struct { uint32_t ucp_ena_0 : 1; // +0 uint32_t ucp_ena_1 : 1; // +1 @@ -424,13 +425,13 @@ union alignas(uint32_t) PA_CL_CLIP_CNTL { uint32_t z_nan_retain : 1; // +23 uint32_t w_nan_retain : 1; // +24 }; - uint32_t value; static constexpr Register register_index = XE_GPU_REG_PA_CL_CLIP_CNTL; }; static_assert_size(PA_CL_CLIP_CNTL, sizeof(uint32_t)); // Viewport transform engine control union alignas(uint32_t) PA_CL_VTE_CNTL { + uint32_t value; struct { uint32_t vport_x_scale_ena : 1; // +0 uint32_t vport_x_offset_ena : 1; // +1 @@ -444,45 +445,45 @@ union alignas(uint32_t) PA_CL_VTE_CNTL { uint32_t vtx_w0_fmt : 1; // +10 uint32_t perfcounter_ref : 1; // +11 }; - uint32_t value; static constexpr Register register_index = XE_GPU_REG_PA_CL_VTE_CNTL; }; static_assert_size(PA_CL_VTE_CNTL, sizeof(uint32_t)); union alignas(uint32_t) PA_SC_SCREEN_SCISSOR_TL { + uint32_t value; struct { int32_t tl_x : 15; // +0 uint32_t : 1; // +15 int32_t tl_y : 15; // +16 }; - uint32_t value; static constexpr Register register_index = XE_GPU_REG_PA_SC_SCREEN_SCISSOR_TL; }; static_assert_size(PA_SC_SCREEN_SCISSOR_TL, sizeof(uint32_t)); union alignas(uint32_t) PA_SC_SCREEN_SCISSOR_BR { + uint32_t value; struct { int32_t br_x : 15; // +0 uint32_t : 1; // +15 int32_t br_y : 15; // +16 }; - uint32_t value; static constexpr Register register_index = XE_GPU_REG_PA_SC_SCREEN_SCISSOR_BR; }; static_assert_size(PA_SC_SCREEN_SCISSOR_BR, sizeof(uint32_t)); union alignas(uint32_t) PA_SC_WINDOW_OFFSET { + uint32_t value; struct { int32_t window_x_offset : 15; // +0 uint32_t : 1; // +15 int32_t window_y_offset : 15; // +16 }; - uint32_t value; static constexpr Register register_index = XE_GPU_REG_PA_SC_WINDOW_OFFSET; }; static_assert_size(PA_SC_WINDOW_OFFSET, sizeof(uint32_t)); union alignas(uint32_t) PA_SC_WINDOW_SCISSOR_TL { + uint32_t value; struct { uint32_t tl_x : 14; // +0 uint32_t : 2; // +14 @@ -490,18 +491,17 @@ union alignas(uint32_t) PA_SC_WINDOW_SCISSOR_TL { uint32_t : 1; // +30 uint32_t window_offset_disable : 1; // +31 }; - uint32_t value; static constexpr Register register_index = XE_GPU_REG_PA_SC_WINDOW_SCISSOR_TL; }; static_assert_size(PA_SC_WINDOW_SCISSOR_TL, sizeof(uint32_t)); union alignas(uint32_t) PA_SC_WINDOW_SCISSOR_BR { + uint32_t value; struct { uint32_t br_x : 14; // +0 uint32_t : 2; // +14 uint32_t br_y : 14; // +16 }; - uint32_t value; static constexpr Register register_index = XE_GPU_REG_PA_SC_WINDOW_SCISSOR_BR; }; static_assert_size(PA_SC_WINDOW_SCISSOR_BR, sizeof(uint32_t)); @@ -520,27 +520,28 @@ static_assert_size(PA_SC_WINDOW_SCISSOR_BR, sizeof(uint32_t)); *******************************************************************************/ union alignas(uint32_t) RB_MODECONTROL { + uint32_t value; struct { xenos::ModeControl edram_mode : 3; // +0 }; - uint32_t value; static constexpr Register register_index = XE_GPU_REG_RB_MODECONTROL; }; static_assert_size(RB_MODECONTROL, sizeof(uint32_t)); union alignas(uint32_t) RB_SURFACE_INFO { + uint32_t value; struct { uint32_t surface_pitch : 14; // +0 in pixels. uint32_t : 2; // +14 xenos::MsaaSamples msaa_samples : 2; // +16 uint32_t hiz_pitch : 14; // +18 }; - uint32_t value; static constexpr Register register_index = XE_GPU_REG_RB_SURFACE_INFO; }; static_assert_size(RB_SURFACE_INFO, sizeof(uint32_t)); union alignas(uint32_t) RB_COLORCONTROL { + uint32_t value; struct { xenos::CompareFunction alpha_func : 3; // +0 uint32_t alpha_test_enable : 1; // +3 @@ -585,19 +586,18 @@ union alignas(uint32_t) RB_COLORCONTROL { uint32_t alpha_to_mask_offset2 : 2; // +28 uint32_t alpha_to_mask_offset3 : 2; // +30 }; - uint32_t value; static constexpr Register register_index = XE_GPU_REG_RB_COLORCONTROL; }; static_assert_size(RB_COLORCONTROL, sizeof(uint32_t)); union alignas(uint32_t) RB_COLOR_INFO { + uint32_t value; struct { uint32_t color_base : 12; // +0 in tiles. uint32_t : 4; // +12 xenos::ColorRenderTargetFormat color_format : 4; // +16 int32_t color_exp_bias : 6; // +20 }; - uint32_t value; static constexpr Register register_index = XE_GPU_REG_RB_COLOR_INFO; // RB_COLOR[1-3]_INFO also use this format. static const Register rt_register_indices[4]; @@ -605,6 +605,7 @@ union alignas(uint32_t) RB_COLOR_INFO { static_assert_size(RB_COLOR_INFO, sizeof(uint32_t)); union alignas(uint32_t) RB_COLOR_MASK { + uint32_t value; struct { uint32_t write_red0 : 1; // +0 uint32_t write_green0 : 1; // +1 @@ -623,12 +624,12 @@ union alignas(uint32_t) RB_COLOR_MASK { uint32_t write_blue3 : 1; // +14 uint32_t write_alpha3 : 1; // +15 }; - uint32_t value; static constexpr Register register_index = XE_GPU_REG_RB_COLOR_MASK; }; static_assert_size(RB_COLOR_MASK, sizeof(uint32_t)); union alignas(uint32_t) RB_BLENDCONTROL { + uint32_t value; struct { xenos::BlendFactor color_srcblend : 5; // +0 xenos::BlendOp color_comb_fcn : 3; // +5 @@ -639,7 +640,6 @@ union alignas(uint32_t) RB_BLENDCONTROL { xenos::BlendFactor alpha_destblend : 5; // +24 // BLEND_FORCE_ENABLE and BLEND_FORCE were added on Adreno. }; - uint32_t value; // RB_BLENDCONTROL[0-3] use this format. static constexpr Register register_index = XE_GPU_REG_RB_BLENDCONTROL0; static const Register rt_register_indices[4]; @@ -647,6 +647,7 @@ union alignas(uint32_t) RB_BLENDCONTROL { static_assert_size(RB_BLENDCONTROL, sizeof(uint32_t)); union alignas(uint32_t) RB_DEPTHCONTROL { + uint32_t value; struct { uint32_t stencil_enable : 1; // +0 uint32_t z_enable : 1; // +1 @@ -664,30 +665,29 @@ union alignas(uint32_t) RB_DEPTHCONTROL { xenos::StencilOp stencilzpass_bf : 3; // +26 xenos::StencilOp stencilzfail_bf : 3; // +29 }; - uint32_t value; static constexpr Register register_index = XE_GPU_REG_RB_DEPTHCONTROL; }; static_assert_size(RB_DEPTHCONTROL, sizeof(uint32_t)); union alignas(uint32_t) RB_STENCILREFMASK { + uint32_t value; struct { uint32_t stencilref : 8; // +0 uint32_t stencilmask : 8; // +8 uint32_t stencilwritemask : 8; // +16 }; - uint32_t value; static constexpr Register register_index = XE_GPU_REG_RB_STENCILREFMASK; // RB_STENCILREFMASK_BF also uses this format. }; static_assert_size(RB_STENCILREFMASK, sizeof(uint32_t)); union alignas(uint32_t) RB_DEPTH_INFO { + uint32_t value; struct { uint32_t depth_base : 12; // +0 in tiles. uint32_t : 4; // +12 xenos::DepthRenderTargetFormat depth_format : 1; // +16 }; - uint32_t value; static constexpr Register register_index = XE_GPU_REG_RB_DEPTH_INFO; }; static_assert_size(RB_DEPTH_INFO, sizeof(uint32_t)); @@ -695,6 +695,7 @@ static_assert_size(RB_DEPTH_INFO, sizeof(uint32_t)); // Copy registers are very different than on Adreno. union alignas(uint32_t) RB_COPY_CONTROL { + uint32_t value; struct { uint32_t copy_src_select : 3; // +0 Depth is 4. uint32_t : 1; // +3 @@ -705,12 +706,12 @@ union alignas(uint32_t) RB_COPY_CONTROL { uint32_t : 10; // +10 xenos::CopyCommand copy_command : 2; // +20 }; - uint32_t value; static constexpr Register register_index = XE_GPU_REG_RB_COPY_CONTROL; }; static_assert_size(RB_COPY_CONTROL, sizeof(uint32_t)); union alignas(uint32_t) RB_COPY_DEST_INFO { + uint32_t value; struct { xenos::Endian128 copy_dest_endian : 3; // +0 uint32_t copy_dest_array : 1; // +3 @@ -721,18 +722,17 @@ union alignas(uint32_t) RB_COPY_DEST_INFO { uint32_t : 2; // +22 uint32_t copy_dest_swap : 1; // +24 }; - uint32_t value; static constexpr Register register_index = XE_GPU_REG_RB_COPY_DEST_INFO; }; static_assert_size(RB_COPY_DEST_INFO, sizeof(uint32_t)); union alignas(uint32_t) RB_COPY_DEST_PITCH { + uint32_t value; struct { uint32_t copy_dest_pitch : 14; // +0 uint32_t : 2; // +14 uint32_t copy_dest_height : 14; // +16 }; - uint32_t value; static constexpr Register register_index = XE_GPU_REG_RB_COPY_DEST_PITCH; }; static_assert_size(RB_COPY_DEST_PITCH, sizeof(uint32_t)); diff --git a/src/xenia/gpu/render_target_cache.h b/src/xenia/gpu/render_target_cache.h index 9fe068f40..5c23a7536 100644 --- a/src/xenia/gpu/render_target_cache.h +++ b/src/xenia/gpu/render_target_cache.h @@ -217,6 +217,7 @@ class RenderTargetCache { // rest of the EDRAM is transferred. union RenderTargetKey { + uint32_t key; struct { // [0, 2047]. uint32_t base_tiles : xenos::kEdramBaseTilesBits - 1; // 11 @@ -228,7 +229,9 @@ class RenderTargetCache { // Ignoring the blending precision and sRGB. uint32_t resource_format : xenos::kRenderTargetFormatBits; // 26 }; - uint32_t key = 0; + + RenderTargetKey() : key(0) { static_assert_size(*this, sizeof(key)); } + struct Hasher { size_t operator()(const RenderTargetKey& render_target_key) const { return std::hash{}(render_target_key.key); diff --git a/src/xenia/gpu/ucode.h b/src/xenia/gpu/ucode.h index 9d5ed7dca..798fd5367 100644 --- a/src/xenia/gpu/ucode.h +++ b/src/xenia/gpu/ucode.h @@ -422,15 +422,15 @@ union ControlFlowInstruction { ControlFlowCondJmpInstruction cond_jmp; // kCondJmp ControlFlowAllocInstruction alloc; // kAlloc + struct { + uint32_t dword_0; + uint32_t dword_1; + }; struct { uint32_t unused_0 : 32; uint32_t unused_1 : 12; ControlFlowOpcode opcode_value : 4; }; - struct { - uint32_t dword_0; - uint32_t dword_1; - }; }; static_assert_size(ControlFlowInstruction, sizeof(uint32_t) * 2); diff --git a/src/xenia/gpu/vulkan/texture_cache.h b/src/xenia/gpu/vulkan/texture_cache.h index 70db17472..dd1adbb91 100644 --- a/src/xenia/gpu/vulkan/texture_cache.h +++ b/src/xenia/gpu/vulkan/texture_cache.h @@ -65,6 +65,7 @@ class TextureCache { VkImageView view; union { + uint16_t swizzle; struct { // FIXME: This only applies on little-endian platforms! uint16_t swiz_x : 3; @@ -73,8 +74,6 @@ class TextureCache { uint16_t swiz_w : 3; uint16_t : 4; }; - - uint16_t swizzle; }; }; diff --git a/src/xenia/gpu/xenos.h b/src/xenia/gpu/xenos.h index 2f0ee64e2..d2279a7b8 100644 --- a/src/xenia/gpu/xenos.h +++ b/src/xenia/gpu/xenos.h @@ -985,6 +985,10 @@ enum class FetchConstantType : uint32_t { // XE_GPU_REG_SHADER_CONSTANT_FETCH_* union alignas(uint32_t) xe_gpu_vertex_fetch_t { + struct { + uint32_t dword_0; + uint32_t dword_1; + }; struct { FetchConstantType type : 2; // +0 uint32_t address : 30; // +2 address in dwords @@ -993,10 +997,6 @@ union alignas(uint32_t) xe_gpu_vertex_fetch_t { uint32_t size : 24; // +2 size in words uint32_t unk1 : 6; // +26 }; - struct { - uint32_t dword_0; - uint32_t dword_1; - }; }; static_assert_size(xe_gpu_vertex_fetch_t, sizeof(uint32_t) * 2); @@ -1044,6 +1044,14 @@ constexpr uint32_t kTextureLinearRowAlignmentBytes = // XE_GPU_REG_SHADER_CONSTANT_FETCH_* union alignas(uint32_t) xe_gpu_texture_fetch_t { + struct { + uint32_t dword_0; + uint32_t dword_1; + uint32_t dword_2; + uint32_t dword_3; + uint32_t dword_4; + uint32_t dword_5; + }; struct { FetchConstantType type : 2; // +0 dword_0 // Likely before the swizzle, seems logical from R5xx (SIGNED_COMP0/1/2/3 @@ -1135,25 +1143,11 @@ union alignas(uint32_t) xe_gpu_texture_fetch_t { uint32_t packed_mips : 1; // +11 uint32_t mip_address : 20; // +12 mip address >> 12 }; - struct { - uint32_t dword_0; - uint32_t dword_1; - uint32_t dword_2; - uint32_t dword_3; - uint32_t dword_4; - uint32_t dword_5; - }; }; static_assert_size(xe_gpu_texture_fetch_t, sizeof(uint32_t) * 6); // XE_GPU_REG_SHADER_CONSTANT_FETCH_* union alignas(uint32_t) xe_gpu_fetch_group_t { - xe_gpu_texture_fetch_t texture_fetch; - struct { - xe_gpu_vertex_fetch_t vertex_fetch_0; - xe_gpu_vertex_fetch_t vertex_fetch_1; - xe_gpu_vertex_fetch_t vertex_fetch_2; - }; struct { uint32_t dword_0; uint32_t dword_1; @@ -1162,6 +1156,12 @@ union alignas(uint32_t) xe_gpu_fetch_group_t { uint32_t dword_4; uint32_t dword_5; }; + xe_gpu_texture_fetch_t texture_fetch; + struct { + xe_gpu_vertex_fetch_t vertex_fetch_0; + xe_gpu_vertex_fetch_t vertex_fetch_1; + xe_gpu_vertex_fetch_t vertex_fetch_2; + }; struct { uint32_t type_0 : 2; uint32_t data_0_a : 30; @@ -1291,6 +1291,12 @@ static_assert_size(xe_gpu_fetch_group_t, sizeof(uint32_t) * 6); // 8in16, 16_16_16_16, uint, RGBA - from 16_16_16_16 uint vfetch // (16_16_16_16 is the largest color format without special values) union alignas(uint32_t) xe_gpu_memexport_stream_t { + struct { + uint32_t dword_0; + uint32_t dword_1; + uint32_t dword_2; + uint32_t dword_3; + }; struct { uint32_t base_address : 30; // +0 dword_0 physical address >> 2 uint32_t const_0x1 : 2; // +30 @@ -1308,12 +1314,6 @@ union alignas(uint32_t) xe_gpu_memexport_stream_t { uint32_t index_count : 23; // +0 dword_3 uint32_t const_0x96 : 9; // +23 }; - struct { - uint32_t dword_0; - uint32_t dword_1; - uint32_t dword_2; - uint32_t dword_3; - }; }; static_assert_size(xe_gpu_memexport_stream_t, sizeof(uint32_t) * 4); diff --git a/src/xenia/kernel/util/xex2_info.h b/src/xenia/kernel/util/xex2_info.h index 6b77476d8..cad98dd83 100644 --- a/src/xenia/kernel/util/xex2_info.h +++ b/src/xenia/kernel/util/xex2_info.h @@ -558,11 +558,11 @@ struct xex2_header { struct xex2_page_descriptor { union { + xe::be value; // 0x0 struct { xex2_section_type info : 4; uint32_t page_count : 28; }; - xe::be value; // 0x0 }; char data_digest[0x14]; // 0x4 }; diff --git a/src/xenia/kernel/xam/user_profile.h b/src/xenia/kernel/xam/user_profile.h index 92bf80bec..82bb7b7a4 100644 --- a/src/xenia/kernel/xam/user_profile.h +++ b/src/xenia/kernel/xam/user_profile.h @@ -36,13 +36,13 @@ class UserProfile { INVALID = 0xFF, }; union Key { + uint32_t value; struct { uint32_t id : 14; uint32_t unk : 2; uint32_t size : 12; uint32_t type : 4; }; - uint32_t value; }; uint32_t setting_id; Type type; diff --git a/src/xenia/kernel/xnotifylistener.cc b/src/xenia/kernel/xnotifylistener.cc index 1ea9af976..7c054db70 100644 --- a/src/xenia/kernel/xnotifylistener.cc +++ b/src/xenia/kernel/xnotifylistener.cc @@ -32,7 +32,7 @@ void XNotifyListener::Initialize(uint64_t mask, uint32_t max_version) { } void XNotifyListener::EnqueueNotification(XNotificationID id, uint32_t data) { - auto key = XNotificationKey{id}; + auto key = XNotificationKey(id); // Ignore if the notification doesn't match our mask. if ((mask_ & uint64_t(1ULL << key.mask_index)) == 0) { return; diff --git a/src/xenia/kernel/xnotifylistener.h b/src/xenia/kernel/xnotifylistener.h index 0e694bd2e..7ec5be2c9 100644 --- a/src/xenia/kernel/xnotifylistener.h +++ b/src/xenia/kernel/xnotifylistener.h @@ -13,6 +13,7 @@ #include #include +#include "xenia/base/assert.h" #include "xenia/base/mutex.h" #include "xenia/base/threading.h" #include "xenia/kernel/xobject.h" @@ -22,21 +23,21 @@ namespace xe { namespace kernel { union XNotificationKey { + XNotificationID id; struct { uint32_t local_id : 16; uint32_t version : 9; uint32_t mask_index : 6; uint32_t : 1; }; - XNotificationID id; - static constexpr XNotificationID get_id(uint8_t mask_index, - uint16_t local_id) { - XNotificationKey key = {}; - key.mask_index = mask_index; - key.local_id = local_id; - return key.id; + constexpr XNotificationKey( + XNotificationID notification_id = XNotificationID(0)) + : id(notification_id) { + static_assert_size(*this, sizeof(id)); } + + constexpr operator XNotificationID() { return id; } }; class XNotifyListener : public XObject { diff --git a/src/xenia/memory.h b/src/xenia/memory.h index 5a0f6084d..bee9defc2 100644 --- a/src/xenia/memory.h +++ b/src/xenia/memory.h @@ -80,6 +80,7 @@ struct HeapAllocationInfo { // Describes a single page in the page table. union PageEntry { + uint64_t qword; struct { // Base address of the allocated region in 4k pages. uint32_t base_address : 20; @@ -95,7 +96,6 @@ union PageEntry { uint32_t state : 2; uint32_t reserved : 14; }; - uint64_t qword; }; // Heap abstraction for page-based allocation. diff --git a/src/xenia/vfs/devices/stfs_xbox.h b/src/xenia/vfs/devices/stfs_xbox.h index ce755ea9c..0cba21393 100644 --- a/src/xenia/vfs/devices/stfs_xbox.h +++ b/src/xenia/vfs/devices/stfs_xbox.h @@ -47,6 +47,7 @@ struct StfsVolumeDescriptor { uint8_t descriptor_length; uint8_t version; union { + uint8_t as_byte; struct { uint8_t read_only_format : 1; // if set, only uses a single backing-block // per hash table (no resiliency), @@ -57,7 +58,6 @@ struct StfsVolumeDescriptor { uint8_t directory_overallocated : 1; uint8_t directory_index_bounds_valid : 1; } bits; - uint8_t as_byte; } flags; uint16_t file_table_block_count; uint8_t file_table_block_number_raw[3]; @@ -195,12 +195,12 @@ struct SvodDeviceDescriptor { uint8_t worker_thread_priority; uint8_t first_fragment_hash_entry[0x14]; union { + uint8_t as_byte; struct { uint8_t must_be_zero_for_future_usage : 6; uint8_t enhanced_gdf_layout : 1; uint8_t zero_for_downlevel_clients : 1; } bits; - uint8_t as_byte; } features; uint8_t num_data_blocks_raw[3]; uint8_t start_data_block_raw[3]; @@ -295,8 +295,8 @@ struct XContentMetadata { char16_t chars[64]; } title_name_raw; union { - XContentAttributes bits; uint8_t as_byte; + XContentAttributes bits; } flags; be thumbnail_size; be title_thumbnail_size;