// Copyright 2017 Citra Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. #pragma once #include #include "common/assert.h" #include "common/bit_field.h" #include "common/common_funcs.h" #include "common/common_types.h" namespace Pica { struct TexturingRegs { struct TextureConfig { enum TextureType : u32 { Texture2D = 0, TextureCube = 1, Shadow2D = 2, Projection2D = 3, ShadowCube = 4, Disabled = 5, }; enum WrapMode : u32 { ClampToEdge = 0, ClampToBorder = 1, Repeat = 2, MirroredRepeat = 3, }; enum TextureFilter : u32 { Nearest = 0, Linear = 1, }; union { u32 raw; BitField<0, 8, u32> r; BitField<8, 8, u32> g; BitField<16, 8, u32> b; BitField<24, 8, u32> a; } border_color; union { BitField<0, 16, u32> height; BitField<16, 16, u32> width; }; union { BitField<1, 1, TextureFilter> mag_filter; BitField<2, 1, TextureFilter> min_filter; BitField<8, 2, WrapMode> wrap_t; BitField<12, 2, WrapMode> wrap_s; BitField<28, 2, TextureType> type; ///< @note Only valid for texture 0 according to 3DBrew. }; INSERT_PADDING_WORDS(0x1); u32 address; PAddr GetPhysicalAddress() const { return address * 8; } // texture1 and texture2 store the texture format directly after the address // whereas texture0 inserts some additional flags inbetween. // Hence, we store the format separately so that all other parameters can be described // in a single structure. }; enum class TextureFormat : u32 { RGBA8 = 0, RGB8 = 1, RGB5A1 = 2, RGB565 = 3, RGBA4 = 4, IA8 = 5, RG8 = 6, ///< @note Also called HILO8 in 3DBrew. I8 = 7, A8 = 8, IA4 = 9, I4 = 10, A4 = 11, ETC1 = 12, // compressed ETC1A4 = 13, // compressed }; static unsigned NibblesPerPixel(TextureFormat format) { switch (format) { case TextureFormat::RGBA8: return 8; case TextureFormat::RGB8: return 6; case TextureFormat::RGB5A1: case TextureFormat::RGB565: case TextureFormat::RGBA4: case TextureFormat::IA8: case TextureFormat::RG8: return 4; case TextureFormat::I4: case TextureFormat::A4: return 1; case TextureFormat::I8: case TextureFormat::A8: case TextureFormat::IA4: default: // placeholder for yet unknown formats UNIMPLEMENTED(); return 0; } } union { BitField<0, 1, u32> texture0_enable; BitField<1, 1, u32> texture1_enable; BitField<2, 1, u32> texture2_enable; }; TextureConfig texture0; INSERT_PADDING_WORDS(0x8); BitField<0, 4, TextureFormat> texture0_format; BitField<0, 1, u32> fragment_lighting_enable; INSERT_PADDING_WORDS(0x1); TextureConfig texture1; BitField<0, 4, TextureFormat> texture1_format; INSERT_PADDING_WORDS(0x2); TextureConfig texture2; BitField<0, 4, TextureFormat> texture2_format; INSERT_PADDING_WORDS(0x21); struct FullTextureConfig { const bool enabled; const TextureConfig config; const TextureFormat format; }; const std::array GetTextures() const { return {{ {texture0_enable.ToBool(), texture0, texture0_format}, {texture1_enable.ToBool(), texture1, texture1_format}, {texture2_enable.ToBool(), texture2, texture2_format}, }}; } // 0xc0-0xff: Texture Combiner (akin to glTexEnv) struct TevStageConfig { enum class Source : u32 { PrimaryColor = 0x0, PrimaryFragmentColor = 0x1, SecondaryFragmentColor = 0x2, Texture0 = 0x3, Texture1 = 0x4, Texture2 = 0x5, Texture3 = 0x6, PreviousBuffer = 0xd, Constant = 0xe, Previous = 0xf, }; enum class ColorModifier : u32 { SourceColor = 0x0, OneMinusSourceColor = 0x1, SourceAlpha = 0x2, OneMinusSourceAlpha = 0x3, SourceRed = 0x4, OneMinusSourceRed = 0x5, SourceGreen = 0x8, OneMinusSourceGreen = 0x9, SourceBlue = 0xc, OneMinusSourceBlue = 0xd, }; enum class AlphaModifier : u32 { SourceAlpha = 0x0, OneMinusSourceAlpha = 0x1, SourceRed = 0x2, OneMinusSourceRed = 0x3, SourceGreen = 0x4, OneMinusSourceGreen = 0x5, SourceBlue = 0x6, OneMinusSourceBlue = 0x7, }; enum class Operation : u32 { Replace = 0, Modulate = 1, Add = 2, AddSigned = 3, Lerp = 4, Subtract = 5, Dot3_RGB = 6, MultiplyThenAdd = 8, AddThenMultiply = 9, }; union { u32 sources_raw; BitField<0, 4, Source> color_source1; BitField<4, 4, Source> color_source2; BitField<8, 4, Source> color_source3; BitField<16, 4, Source> alpha_source1; BitField<20, 4, Source> alpha_source2; BitField<24, 4, Source> alpha_source3; }; union { u32 modifiers_raw; BitField<0, 4, ColorModifier> color_modifier1; BitField<4, 4, ColorModifier> color_modifier2; BitField<8, 4, ColorModifier> color_modifier3; BitField<12, 3, AlphaModifier> alpha_modifier1; BitField<16, 3, AlphaModifier> alpha_modifier2; BitField<20, 3, AlphaModifier> alpha_modifier3; }; union { u32 ops_raw; BitField<0, 4, Operation> color_op; BitField<16, 4, Operation> alpha_op; }; union { u32 const_color; BitField<0, 8, u32> const_r; BitField<8, 8, u32> const_g; BitField<16, 8, u32> const_b; BitField<24, 8, u32> const_a; }; union { u32 scales_raw; BitField<0, 2, u32> color_scale; BitField<16, 2, u32> alpha_scale; }; inline unsigned GetColorMultiplier() const { return (color_scale < 3) ? (1 << color_scale) : 1; } inline unsigned GetAlphaMultiplier() const { return (alpha_scale < 3) ? (1 << alpha_scale) : 1; } }; TevStageConfig tev_stage0; INSERT_PADDING_WORDS(0x3); TevStageConfig tev_stage1; INSERT_PADDING_WORDS(0x3); TevStageConfig tev_stage2; INSERT_PADDING_WORDS(0x3); TevStageConfig tev_stage3; INSERT_PADDING_WORDS(0x3); enum class FogMode : u32 { None = 0, Fog = 5, Gas = 7, }; union { BitField<0, 3, FogMode> fog_mode; BitField<16, 1, u32> fog_flip; union { // Tev stages 0-3 write their output to the combiner buffer if the corresponding bit in // these masks are set BitField<8, 4, u32> update_mask_rgb; BitField<12, 4, u32> update_mask_a; bool TevStageUpdatesCombinerBufferColor(unsigned stage_index) const { return (stage_index < 4) && (update_mask_rgb & (1 << stage_index)); } bool TevStageUpdatesCombinerBufferAlpha(unsigned stage_index) const { return (stage_index < 4) && (update_mask_a & (1 << stage_index)); } } tev_combiner_buffer_input; }; union { u32 raw; BitField<0, 8, u32> r; BitField<8, 8, u32> g; BitField<16, 8, u32> b; } fog_color; INSERT_PADDING_WORDS(0x4); BitField<0, 16, u32> fog_lut_offset; INSERT_PADDING_WORDS(0x1); u32 fog_lut_data[8]; TevStageConfig tev_stage4; INSERT_PADDING_WORDS(0x3); TevStageConfig tev_stage5; union { u32 raw; BitField<0, 8, u32> r; BitField<8, 8, u32> g; BitField<16, 8, u32> b; BitField<24, 8, u32> a; } tev_combiner_buffer_color; INSERT_PADDING_WORDS(0x2); const std::array GetTevStages() const { return {{tev_stage0, tev_stage1, tev_stage2, tev_stage3, tev_stage4, tev_stage5}}; }; }; static_assert(sizeof(TexturingRegs) == 0x80 * sizeof(u32), "TexturingRegs struct has incorrect size"); } // namespace Pica