summaryrefslogtreecommitdiffstats
path: root/src/video_core/pica.h
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/video_core/pica.h1393
1 files changed, 1 insertions, 1392 deletions
diff --git a/src/video_core/pica.h b/src/video_core/pica.h
index 731540b99..dc8aa6670 100644
--- a/src/video_core/pica.h
+++ b/src/video_core/pica.h
@@ -4,1400 +4,9 @@
#pragma once
-#include <array>
-#include <cstddef>
-#include <string>
-
-#ifndef _MSC_VER
-#include <type_traits> // for std::enable_if
-#endif
-
-#include "common/assert.h"
-#include "common/bit_field.h"
-#include "common/common_funcs.h"
-#include "common/common_types.h"
-#include "common/logging/log.h"
-#include "common/vector_math.h"
-
+#include "video_core/regs_texturing.h"
namespace Pica {
-// Returns index corresponding to the Regs member labeled by field_name
-// TODO: Due to Visual studio bug 209229, offsetof does not return constant expressions
-// when used with array elements (e.g. PICA_REG_INDEX(vs_uniform_setup.set_value[1])).
-// For details cf.
-// https://connect.microsoft.com/VisualStudio/feedback/details/209229/offsetof-does-not-produce-a-constant-expression-for-array-members
-// Hopefully, this will be fixed sometime in the future.
-// For lack of better alternatives, we currently hardcode the offsets when constant
-// expressions are needed via PICA_REG_INDEX_WORKAROUND (on sane compilers, static_asserts
-// will then make sure the offsets indeed match the automatically calculated ones).
-#define PICA_REG_INDEX(field_name) (offsetof(Pica::Regs, field_name) / sizeof(u32))
-#if defined(_MSC_VER)
-#define PICA_REG_INDEX_WORKAROUND(field_name, backup_workaround_index) (backup_workaround_index)
-#else
-// NOTE: Yeah, hacking in a static_assert here just to workaround the lacking MSVC compiler
-// really is this annoying. This macro just forwards its first argument to PICA_REG_INDEX
-// and then performs a (no-op) cast to size_t iff the second argument matches the expected
-// field offset. Otherwise, the compiler will fail to compile this code.
-#define PICA_REG_INDEX_WORKAROUND(field_name, backup_workaround_index) \
- ((typename std::enable_if<backup_workaround_index == PICA_REG_INDEX(field_name), \
- size_t>::type)PICA_REG_INDEX(field_name))
-#endif // _MSC_VER
-
-struct Regs {
-
- INSERT_PADDING_WORDS(0x10);
-
- u32 trigger_irq;
-
- INSERT_PADDING_WORDS(0x2f);
-
- enum class CullMode : u32 {
- // Select which polygons are considered to be "frontfacing".
- KeepAll = 0,
- KeepClockWise = 1,
- KeepCounterClockWise = 2,
- // TODO: What does the third value imply?
- };
-
- union {
- BitField<0, 2, CullMode> cull_mode;
- };
-
- BitField<0, 24, u32> viewport_size_x;
-
- INSERT_PADDING_WORDS(0x1);
-
- BitField<0, 24, u32> viewport_size_y;
-
- INSERT_PADDING_WORDS(0x9);
-
- BitField<0, 24, u32> viewport_depth_range; // float24
- BitField<0, 24, u32> viewport_depth_near_plane; // float24
-
- BitField<0, 3, u32> vs_output_total;
-
- union VSOutputAttributes {
- // Maps components of output vertex attributes to semantics
- enum Semantic : u32 {
- POSITION_X = 0,
- POSITION_Y = 1,
- POSITION_Z = 2,
- POSITION_W = 3,
-
- QUATERNION_X = 4,
- QUATERNION_Y = 5,
- QUATERNION_Z = 6,
- QUATERNION_W = 7,
-
- COLOR_R = 8,
- COLOR_G = 9,
- COLOR_B = 10,
- COLOR_A = 11,
-
- TEXCOORD0_U = 12,
- TEXCOORD0_V = 13,
- TEXCOORD1_U = 14,
- TEXCOORD1_V = 15,
-
- TEXCOORD0_W = 16,
-
- VIEW_X = 18,
- VIEW_Y = 19,
- VIEW_Z = 20,
-
- TEXCOORD2_U = 22,
- TEXCOORD2_V = 23,
-
- INVALID = 31,
- };
-
- BitField<0, 5, Semantic> map_x;
- BitField<8, 5, Semantic> map_y;
- BitField<16, 5, Semantic> map_z;
- BitField<24, 5, Semantic> map_w;
- } vs_output_attributes[7];
-
- INSERT_PADDING_WORDS(0xe);
-
- enum class ScissorMode : u32 {
- Disabled = 0,
- Exclude = 1, // Exclude pixels inside the scissor box
-
- Include = 3 // Exclude pixels outside the scissor box
- };
-
- struct {
- BitField<0, 2, ScissorMode> mode;
-
- union {
- BitField<0, 16, u32> x1;
- BitField<16, 16, u32> y1;
- };
-
- union {
- BitField<0, 16, u32> x2;
- BitField<16, 16, u32> y2;
- };
- } scissor_test;
-
- union {
- BitField<0, 10, s32> x;
- BitField<16, 10, s32> y;
- } viewport_corner;
-
- INSERT_PADDING_WORDS(0x1);
-
- // TODO: early depth
- INSERT_PADDING_WORDS(0x1);
-
- INSERT_PADDING_WORDS(0x2);
-
- enum DepthBuffering : u32 {
- WBuffering = 0,
- ZBuffering = 1,
- };
- BitField<0, 1, DepthBuffering> depthmap_enable;
-
- INSERT_PADDING_WORDS(0x12);
-
- 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;
-
- u32 GetPhysicalAddress() const {
- return DecodeAddressRegister(address);
- }
-
- // 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
- };
-
- enum class LogicOp : u32 {
- Clear = 0,
- And = 1,
- AndReverse = 2,
- Copy = 3,
- Set = 4,
- CopyInverted = 5,
- NoOp = 6,
- Invert = 7,
- Nand = 8,
- Or = 9,
- Nor = 10,
- Xor = 11,
- Equiv = 12,
- AndInverted = 13,
- OrReverse = 14,
- OrInverted = 15,
- };
-
- 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:
- return 2;
-
- 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<FullTextureConfig, 3> 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<Regs::TevStageConfig, 6> GetTevStages() const {
- return {{tev_stage0, tev_stage1, tev_stage2, tev_stage3, tev_stage4, tev_stage5}};
- };
-
- enum class BlendEquation : u32 {
- Add = 0,
- Subtract = 1,
- ReverseSubtract = 2,
- Min = 3,
- Max = 4,
- };
-
- enum class BlendFactor : u32 {
- Zero = 0,
- One = 1,
- SourceColor = 2,
- OneMinusSourceColor = 3,
- DestColor = 4,
- OneMinusDestColor = 5,
- SourceAlpha = 6,
- OneMinusSourceAlpha = 7,
- DestAlpha = 8,
- OneMinusDestAlpha = 9,
- ConstantColor = 10,
- OneMinusConstantColor = 11,
- ConstantAlpha = 12,
- OneMinusConstantAlpha = 13,
- SourceAlphaSaturate = 14,
- };
-
- enum class CompareFunc : u32 {
- Never = 0,
- Always = 1,
- Equal = 2,
- NotEqual = 3,
- LessThan = 4,
- LessThanOrEqual = 5,
- GreaterThan = 6,
- GreaterThanOrEqual = 7,
- };
-
- enum class StencilAction : u32 {
- Keep = 0,
- Zero = 1,
- Replace = 2,
- Increment = 3,
- Decrement = 4,
- Invert = 5,
- IncrementWrap = 6,
- DecrementWrap = 7,
- };
-
- struct {
- union {
- // If false, logic blending is used
- BitField<8, 1, u32> alphablend_enable;
- };
-
- union {
- BitField<0, 8, BlendEquation> blend_equation_rgb;
- BitField<8, 8, BlendEquation> blend_equation_a;
-
- BitField<16, 4, BlendFactor> factor_source_rgb;
- BitField<20, 4, BlendFactor> factor_dest_rgb;
-
- BitField<24, 4, BlendFactor> factor_source_a;
- BitField<28, 4, BlendFactor> factor_dest_a;
- } alpha_blending;
-
- union {
- BitField<0, 4, LogicOp> logic_op;
- };
-
- union {
- u32 raw;
- BitField<0, 8, u32> r;
- BitField<8, 8, u32> g;
- BitField<16, 8, u32> b;
- BitField<24, 8, u32> a;
- } blend_const;
-
- union {
- BitField<0, 1, u32> enable;
- BitField<4, 3, CompareFunc> func;
- BitField<8, 8, u32> ref;
- } alpha_test;
-
- struct {
- union {
- // Raw value of this register
- u32 raw_func;
-
- // If true, enable stencil testing
- BitField<0, 1, u32> enable;
-
- // Comparison operation for stencil testing
- BitField<4, 3, CompareFunc> func;
-
- // Mask used to control writing to the stencil buffer
- BitField<8, 8, u32> write_mask;
-
- // Value to compare against for stencil testing
- BitField<16, 8, u32> reference_value;
-
- // Mask to apply on stencil test inputs
- BitField<24, 8, u32> input_mask;
- };
-
- union {
- // Raw value of this register
- u32 raw_op;
-
- // Action to perform when the stencil test fails
- BitField<0, 3, StencilAction> action_stencil_fail;
-
- // Action to perform when stencil testing passed but depth testing fails
- BitField<4, 3, StencilAction> action_depth_fail;
-
- // Action to perform when both stencil and depth testing pass
- BitField<8, 3, StencilAction> action_depth_pass;
- };
- } stencil_test;
-
- union {
- BitField<0, 1, u32> depth_test_enable;
- BitField<4, 3, CompareFunc> depth_test_func;
- BitField<8, 1, u32> red_enable;
- BitField<9, 1, u32> green_enable;
- BitField<10, 1, u32> blue_enable;
- BitField<11, 1, u32> alpha_enable;
- BitField<12, 1, u32> depth_write_enable;
- };
-
- INSERT_PADDING_WORDS(0x8);
- } output_merger;
-
- // Components are laid out in reverse byte order, most significant bits first.
- enum class ColorFormat : u32 {
- RGBA8 = 0,
- RGB8 = 1,
- RGB5A1 = 2,
- RGB565 = 3,
- RGBA4 = 4,
- };
-
- enum class DepthFormat : u32 {
- D16 = 0,
- D24 = 2,
- D24S8 = 3,
- };
-
- // Returns the number of bytes in the specified color format
- static unsigned BytesPerColorPixel(ColorFormat format) {
- switch (format) {
- case ColorFormat::RGBA8:
- return 4;
- case ColorFormat::RGB8:
- return 3;
- case ColorFormat::RGB5A1:
- case ColorFormat::RGB565:
- case ColorFormat::RGBA4:
- return 2;
- default:
- LOG_CRITICAL(HW_GPU, "Unknown color format %u", format);
- UNIMPLEMENTED();
- }
- }
-
- struct FramebufferConfig {
- INSERT_PADDING_WORDS(0x3);
-
- union {
- BitField<0, 4, u32> allow_color_write; // 0 = disable, else enable
- };
-
- INSERT_PADDING_WORDS(0x1);
-
- union {
- BitField<0, 2, u32> allow_depth_stencil_write; // 0 = disable, else enable
- };
-
- DepthFormat depth_format; // TODO: Should be a BitField!
- BitField<16, 3, ColorFormat> color_format;
-
- INSERT_PADDING_WORDS(0x4);
-
- u32 depth_buffer_address;
- u32 color_buffer_address;
-
- union {
- // Apparently, the framebuffer width is stored as expected,
- // while the height is stored as the actual height minus one.
- // Hence, don't access these fields directly but use the accessors
- // GetWidth() and GetHeight() instead.
- BitField<0, 11, u32> width;
- BitField<12, 10, u32> height;
- };
-
- INSERT_PADDING_WORDS(0x1);
-
- inline u32 GetColorBufferPhysicalAddress() const {
- return DecodeAddressRegister(color_buffer_address);
- }
- inline u32 GetDepthBufferPhysicalAddress() const {
- return DecodeAddressRegister(depth_buffer_address);
- }
-
- inline u32 GetWidth() const {
- return width;
- }
-
- inline u32 GetHeight() const {
- return height + 1;
- }
- } framebuffer;
-
- // Returns the number of bytes in the specified depth format
- static u32 BytesPerDepthPixel(DepthFormat format) {
- switch (format) {
- case DepthFormat::D16:
- return 2;
- case DepthFormat::D24:
- return 3;
- case DepthFormat::D24S8:
- return 4;
- default:
- LOG_CRITICAL(HW_GPU, "Unknown depth format %u", format);
- UNIMPLEMENTED();
- }
- }
-
- // Returns the number of bits per depth component of the specified depth format
- static u32 DepthBitsPerPixel(DepthFormat format) {
- switch (format) {
- case DepthFormat::D16:
- return 16;
- case DepthFormat::D24:
- case DepthFormat::D24S8:
- return 24;
- default:
- LOG_CRITICAL(HW_GPU, "Unknown depth format %u", format);
- UNIMPLEMENTED();
- }
- }
-
- INSERT_PADDING_WORDS(0x20);
-
- enum class LightingSampler {
- Distribution0 = 0,
- Distribution1 = 1,
- Fresnel = 3,
- ReflectBlue = 4,
- ReflectGreen = 5,
- ReflectRed = 6,
- SpotlightAttenuation = 8,
- DistanceAttenuation = 16,
- };
-
- /**
- * Pica fragment lighting supports using different LUTs for each lighting component:
- * Reflectance R, G, and B channels, distribution function for specular components 0 and 1,
- * fresnel factor, and spotlight attenuation. Furthermore, which LUTs are used for each channel
- * (or whether a channel is enabled at all) is specified by various pre-defined lighting
- * configurations. With configurations that require more LUTs, more cycles are required on HW to
- * perform lighting computations.
- */
- enum class LightingConfig {
- Config0 = 0, ///< Reflect Red, Distribution 0, Spotlight
- Config1 = 1, ///< Reflect Red, Fresnel, Spotlight
- Config2 = 2, ///< Reflect Red, Distribution 0/1
- Config3 = 3, ///< Distribution 0/1, Fresnel
- Config4 = 4, ///< Reflect Red/Green/Blue, Distribution 0/1, Spotlight
- Config5 = 5, ///< Reflect Red/Green/Blue, Distribution 0, Fresnel, Spotlight
- Config6 = 6, ///< Reflect Red, Distribution 0/1, Fresnel, Spotlight
- Config7 = 8, ///< Reflect Red/Green/Blue, Distribution 0/1, Fresnel, Spotlight
- ///< NOTE: '8' is intentional, '7' does not appear to be a valid configuration
- };
-
- /// Selects which lighting components are affected by fresnel
- enum class LightingFresnelSelector {
- None = 0, ///< Fresnel is disabled
- PrimaryAlpha = 1, ///< Primary (diffuse) lighting alpha is affected by fresnel
- SecondaryAlpha = 2, ///< Secondary (specular) lighting alpha is affected by fresnel
- Both =
- PrimaryAlpha |
- SecondaryAlpha, ///< Both primary and secondary lighting alphas are affected by fresnel
- };
-
- /// Factor used to scale the output of a lighting LUT
- enum class LightingScale {
- Scale1 = 0, ///< Scale is 1x
- Scale2 = 1, ///< Scale is 2x
- Scale4 = 2, ///< Scale is 4x
- Scale8 = 3, ///< Scale is 8x
- Scale1_4 = 6, ///< Scale is 0.25x
- Scale1_2 = 7, ///< Scale is 0.5x
- };
-
- enum class LightingLutInput {
- NH = 0, // Cosine of the angle between the normal and half-angle vectors
- VH = 1, // Cosine of the angle between the view and half-angle vectors
- NV = 2, // Cosine of the angle between the normal and the view vector
- LN = 3, // Cosine of the angle between the light and the normal vectors
- };
-
- enum class LightingBumpMode : u32 {
- None = 0,
- NormalMap = 1,
- TangentMap = 2,
- };
-
- union LightColor {
- BitField<0, 10, u32> b;
- BitField<10, 10, u32> g;
- BitField<20, 10, u32> r;
-
- Math::Vec3f ToVec3f() const {
- // These fields are 10 bits wide, however 255 corresponds to 1.0f for each color
- // component
- return Math::MakeVec((f32)r / 255.f, (f32)g / 255.f, (f32)b / 255.f);
- }
- };
-
- /// Returns true if the specified lighting sampler is supported by the current Pica lighting
- /// configuration
- static bool IsLightingSamplerSupported(LightingConfig config, LightingSampler sampler) {
- switch (sampler) {
- case LightingSampler::Distribution0:
- return (config != LightingConfig::Config1);
-
- case LightingSampler::Distribution1:
- return (config != LightingConfig::Config0) && (config != LightingConfig::Config1) &&
- (config != LightingConfig::Config5);
-
- case LightingSampler::Fresnel:
- return (config != LightingConfig::Config0) && (config != LightingConfig::Config2) &&
- (config != LightingConfig::Config4);
-
- case LightingSampler::ReflectRed:
- return (config != LightingConfig::Config3);
-
- case LightingSampler::ReflectGreen:
- case LightingSampler::ReflectBlue:
- return (config == LightingConfig::Config4) || (config == LightingConfig::Config5) ||
- (config == LightingConfig::Config7);
- default:
- UNREACHABLE_MSG("Regs::IsLightingSamplerSupported: Reached "
- "unreachable section, sampler should be one "
- "of Distribution0, Distribution1, Fresnel, "
- "ReflectRed, ReflectGreen or ReflectBlue, instead "
- "got %i",
- static_cast<int>(config));
- }
- }
-
- struct {
- struct LightSrc {
- LightColor specular_0; // material.specular_0 * light.specular_0
- LightColor specular_1; // material.specular_1 * light.specular_1
- LightColor diffuse; // material.diffuse * light.diffuse
- LightColor ambient; // material.ambient * light.ambient
-
- // Encoded as 16-bit floating point
- union {
- BitField<0, 16, u32> x;
- BitField<16, 16, u32> y;
- };
- union {
- BitField<0, 16, u32> z;
- };
-
- INSERT_PADDING_WORDS(0x3);
-
- union {
- BitField<0, 1, u32> directional;
- BitField<1, 1, u32> two_sided_diffuse; // When disabled, clamp dot-product to 0
- } config;
-
- BitField<0, 20, u32> dist_atten_bias;
- BitField<0, 20, u32> dist_atten_scale;
-
- INSERT_PADDING_WORDS(0x4);
- };
- static_assert(sizeof(LightSrc) == 0x10 * sizeof(u32),
- "LightSrc structure must be 0x10 words");
-
- LightSrc light[8];
- LightColor global_ambient; // Emission + (material.ambient * lighting.ambient)
- INSERT_PADDING_WORDS(0x1);
- BitField<0, 3, u32> max_light_index; // Number of enabled lights - 1
-
- union {
- BitField<2, 2, LightingFresnelSelector> fresnel_selector;
- BitField<4, 4, LightingConfig> config;
- BitField<22, 2, u32> bump_selector; // 0: Texture 0, 1: Texture 1, 2: Texture 2
- BitField<27, 1, u32> clamp_highlights;
- BitField<28, 2, LightingBumpMode> bump_mode;
- BitField<30, 1, u32> disable_bump_renorm;
- } config0;
-
- union {
- BitField<16, 1, u32> disable_lut_d0;
- BitField<17, 1, u32> disable_lut_d1;
- BitField<19, 1, u32> disable_lut_fr;
- BitField<20, 1, u32> disable_lut_rr;
- BitField<21, 1, u32> disable_lut_rg;
- BitField<22, 1, u32> disable_lut_rb;
-
- // Each bit specifies whether distance attenuation should be applied for the
- // corresponding light
-
- BitField<24, 1, u32> disable_dist_atten_light_0;
- BitField<25, 1, u32> disable_dist_atten_light_1;
- BitField<26, 1, u32> disable_dist_atten_light_2;
- BitField<27, 1, u32> disable_dist_atten_light_3;
- BitField<28, 1, u32> disable_dist_atten_light_4;
- BitField<29, 1, u32> disable_dist_atten_light_5;
- BitField<30, 1, u32> disable_dist_atten_light_6;
- BitField<31, 1, u32> disable_dist_atten_light_7;
- } config1;
-
- bool IsDistAttenDisabled(unsigned index) const {
- const unsigned disable[] = {
- config1.disable_dist_atten_light_0, config1.disable_dist_atten_light_1,
- config1.disable_dist_atten_light_2, config1.disable_dist_atten_light_3,
- config1.disable_dist_atten_light_4, config1.disable_dist_atten_light_5,
- config1.disable_dist_atten_light_6, config1.disable_dist_atten_light_7};
- return disable[index] != 0;
- }
-
- union {
- BitField<0, 8, u32> index; ///< Index at which to set data in the LUT
- BitField<8, 5, u32> type; ///< Type of LUT for which to set data
- } lut_config;
-
- BitField<0, 1, u32> disable;
- INSERT_PADDING_WORDS(0x1);
-
- // When data is written to any of these registers, it gets written to the lookup table of
- // the selected type at the selected index, specified above in the `lut_config` register.
- // With each write, `lut_config.index` is incremented. It does not matter which of these
- // registers is written to, the behavior will be the same.
- u32 lut_data[8];
-
- // These are used to specify if absolute (abs) value should be used for each LUT index. When
- // abs mode is disabled, LUT indexes are in the range of (-1.0, 1.0). Otherwise, they are in
- // the range of (0.0, 1.0).
- union {
- BitField<1, 1, u32> disable_d0;
- BitField<5, 1, u32> disable_d1;
- BitField<9, 1, u32> disable_sp;
- BitField<13, 1, u32> disable_fr;
- BitField<17, 1, u32> disable_rb;
- BitField<21, 1, u32> disable_rg;
- BitField<25, 1, u32> disable_rr;
- } abs_lut_input;
-
- union {
- BitField<0, 3, LightingLutInput> d0;
- BitField<4, 3, LightingLutInput> d1;
- BitField<8, 3, LightingLutInput> sp;
- BitField<12, 3, LightingLutInput> fr;
- BitField<16, 3, LightingLutInput> rb;
- BitField<20, 3, LightingLutInput> rg;
- BitField<24, 3, LightingLutInput> rr;
- } lut_input;
-
- union {
- BitField<0, 3, LightingScale> d0;
- BitField<4, 3, LightingScale> d1;
- BitField<8, 3, LightingScale> sp;
- BitField<12, 3, LightingScale> fr;
- BitField<16, 3, LightingScale> rb;
- BitField<20, 3, LightingScale> rg;
- BitField<24, 3, LightingScale> rr;
-
- static float GetScale(LightingScale scale) {
- switch (scale) {
- case LightingScale::Scale1:
- return 1.0f;
- case LightingScale::Scale2:
- return 2.0f;
- case LightingScale::Scale4:
- return 4.0f;
- case LightingScale::Scale8:
- return 8.0f;
- case LightingScale::Scale1_4:
- return 0.25f;
- case LightingScale::Scale1_2:
- return 0.5f;
- }
- return 0.0f;
- }
- } lut_scale;
-
- INSERT_PADDING_WORDS(0x6);
-
- union {
- // There are 8 light enable "slots", corresponding to the total number of lights
- // supported by Pica. For N enabled lights (specified by register 0x1c2, or 'src_num'
- // above), the first N slots below will be set to integers within the range of 0-7,
- // corresponding to the actual light that is enabled for each slot.
-
- BitField<0, 3, u32> slot_0;
- BitField<4, 3, u32> slot_1;
- BitField<8, 3, u32> slot_2;
- BitField<12, 3, u32> slot_3;
- BitField<16, 3, u32> slot_4;
- BitField<20, 3, u32> slot_5;
- BitField<24, 3, u32> slot_6;
- BitField<28, 3, u32> slot_7;
-
- unsigned GetNum(unsigned index) const {
- const unsigned enable_slots[] = {slot_0, slot_1, slot_2, slot_3,
- slot_4, slot_5, slot_6, slot_7};
- return enable_slots[index];
- }
- } light_enable;
- } lighting;
-
- INSERT_PADDING_WORDS(0x26);
-
- enum class VertexAttributeFormat : u64 {
- BYTE = 0,
- UBYTE = 1,
- SHORT = 2,
- FLOAT = 3,
- };
-
- struct {
- BitField<0, 29, u32> base_address;
-
- u32 GetPhysicalBaseAddress() const {
- return DecodeAddressRegister(base_address);
- }
-
- // Descriptor for internal vertex attributes
- union {
- BitField<0, 2, VertexAttributeFormat> format0; // size of one element
- BitField<2, 2, u64> size0; // number of elements minus 1
- BitField<4, 2, VertexAttributeFormat> format1;
- BitField<6, 2, u64> size1;
- BitField<8, 2, VertexAttributeFormat> format2;
- BitField<10, 2, u64> size2;
- BitField<12, 2, VertexAttributeFormat> format3;
- BitField<14, 2, u64> size3;
- BitField<16, 2, VertexAttributeFormat> format4;
- BitField<18, 2, u64> size4;
- BitField<20, 2, VertexAttributeFormat> format5;
- BitField<22, 2, u64> size5;
- BitField<24, 2, VertexAttributeFormat> format6;
- BitField<26, 2, u64> size6;
- BitField<28, 2, VertexAttributeFormat> format7;
- BitField<30, 2, u64> size7;
- BitField<32, 2, VertexAttributeFormat> format8;
- BitField<34, 2, u64> size8;
- BitField<36, 2, VertexAttributeFormat> format9;
- BitField<38, 2, u64> size9;
- BitField<40, 2, VertexAttributeFormat> format10;
- BitField<42, 2, u64> size10;
- BitField<44, 2, VertexAttributeFormat> format11;
- BitField<46, 2, u64> size11;
-
- BitField<48, 12, u64> attribute_mask;
-
- // number of total attributes minus 1
- BitField<60, 4, u64> max_attribute_index;
- };
-
- inline VertexAttributeFormat GetFormat(int n) const {
- VertexAttributeFormat formats[] = {format0, format1, format2, format3,
- format4, format5, format6, format7,
- format8, format9, format10, format11};
- return formats[n];
- }
-
- inline int GetNumElements(int n) const {
- u64 sizes[] = {size0, size1, size2, size3, size4, size5,
- size6, size7, size8, size9, size10, size11};
- return (int)sizes[n] + 1;
- }
-
- inline int GetElementSizeInBytes(int n) const {
- return (GetFormat(n) == VertexAttributeFormat::FLOAT)
- ? 4
- : (GetFormat(n) == VertexAttributeFormat::SHORT) ? 2 : 1;
- }
-
- inline int GetStride(int n) const {
- return GetNumElements(n) * GetElementSizeInBytes(n);
- }
-
- inline bool IsDefaultAttribute(int id) const {
- return (id >= 12) || (attribute_mask & (1ULL << id)) != 0;
- }
-
- inline int GetNumTotalAttributes() const {
- return (int)max_attribute_index + 1;
- }
-
- // Attribute loaders map the source vertex data to input attributes
- // This e.g. allows to load different attributes from different memory locations
- struct {
- // Source attribute data offset from the base address
- u32 data_offset;
-
- union {
- BitField<0, 4, u64> comp0;
- BitField<4, 4, u64> comp1;
- BitField<8, 4, u64> comp2;
- BitField<12, 4, u64> comp3;
- BitField<16, 4, u64> comp4;
- BitField<20, 4, u64> comp5;
- BitField<24, 4, u64> comp6;
- BitField<28, 4, u64> comp7;
- BitField<32, 4, u64> comp8;
- BitField<36, 4, u64> comp9;
- BitField<40, 4, u64> comp10;
- BitField<44, 4, u64> comp11;
-
- // bytes for a single vertex in this loader
- BitField<48, 8, u64> byte_count;
-
- BitField<60, 4, u64> component_count;
- };
-
- inline int GetComponent(int n) const {
- u64 components[] = {comp0, comp1, comp2, comp3, comp4, comp5,
- comp6, comp7, comp8, comp9, comp10, comp11};
- return (int)components[n];
- }
- } attribute_loaders[12];
- } vertex_attributes;
-
- struct {
- enum IndexFormat : u32 {
- BYTE = 0,
- SHORT = 1,
- };
-
- union {
- BitField<0, 31, u32> offset; // relative to base attribute address
- BitField<31, 1, IndexFormat> format;
- };
- } index_array;
-
- // Number of vertices to render
- u32 num_vertices;
-
- INSERT_PADDING_WORDS(0x1);
-
- // The index of the first vertex to render
- u32 vertex_offset;
-
- INSERT_PADDING_WORDS(0x3);
-
- // These two trigger rendering of triangles
- u32 trigger_draw;
- u32 trigger_draw_indexed;
-
- INSERT_PADDING_WORDS(0x2);
-
- // These registers are used to setup the default "fall-back" vertex shader attributes
- struct {
- // Index of the current default attribute
- u32 index;
-
- // Writing to these registers sets the "current" default attribute.
- u32 set_value[3];
- } vs_default_attributes_setup;
-
- INSERT_PADDING_WORDS(0x2);
-
- struct {
- // There are two channels that can be used to configure the next command buffer, which
- // can be then executed by writing to the "trigger" registers. There are two reasons why a
- // game might use this feature:
- // 1) With this, an arbitrary number of additional command buffers may be executed in
- // sequence without requiring any intervention of the CPU after the initial one is
- // kicked off.
- // 2) Games can configure these registers to provide a command list subroutine mechanism.
-
- BitField<0, 20, u32> size[2]; ///< Size (in bytes / 8) of each channel's command buffer
- BitField<0, 28, u32> addr[2]; ///< Physical address / 8 of each channel's command buffer
- u32 trigger[2]; ///< Triggers execution of the channel's command buffer when written to
-
- unsigned GetSize(unsigned index) const {
- ASSERT(index < 2);
- return 8 * size[index];
- }
-
- PAddr GetPhysicalAddress(unsigned index) const {
- ASSERT(index < 2);
- return (PAddr)(8 * addr[index]);
- }
- } command_buffer;
-
- INSERT_PADDING_WORDS(4);
-
- /// Number of input attributes to the vertex shader minus 1
- BitField<0, 4, u32> max_input_attrib_index;
-
- INSERT_PADDING_WORDS(2);
-
- enum class GPUMode : u32 {
- Drawing = 0,
- Configuring = 1,
- };
-
- GPUMode gpu_mode;
-
- INSERT_PADDING_WORDS(0x18);
-
- enum class TriangleTopology : u32 {
- List = 0,
- Strip = 1,
- Fan = 2,
- Shader = 3, // Programmable setup unit implemented in a geometry shader
- };
-
- BitField<8, 2, TriangleTopology> triangle_topology;
-
- u32 restart_primitive;
-
- INSERT_PADDING_WORDS(0x20);
-
- struct ShaderConfig {
- BitField<0, 16, u32> bool_uniforms;
-
- union {
- BitField<0, 8, u32> x;
- BitField<8, 8, u32> y;
- BitField<16, 8, u32> z;
- BitField<24, 8, u32> w;
- } int_uniforms[4];
-
- INSERT_PADDING_WORDS(0x4);
-
- union {
- // Number of input attributes to shader unit - 1
- BitField<0, 4, u32> max_input_attribute_index;
- };
-
- // Offset to shader program entry point (in words)
- BitField<0, 16, u32> main_offset;
-
- /// Maps input attributes to registers. 4-bits per attribute, specifying a register index
- u32 input_attribute_to_register_map_low;
- u32 input_attribute_to_register_map_high;
-
- unsigned int GetRegisterForAttribute(unsigned int attribute_index) const {
- u64 map = ((u64)input_attribute_to_register_map_high << 32) |
- (u64)input_attribute_to_register_map_low;
- return (map >> (attribute_index * 4)) & 0b1111;
- }
-
- BitField<0, 16, u32> output_mask;
-
- // 0x28E, CODETRANSFER_END
- INSERT_PADDING_WORDS(0x2);
-
- struct {
- enum Format : u32 {
- FLOAT24 = 0,
- FLOAT32 = 1,
- };
-
- bool IsFloat32() const {
- return format == FLOAT32;
- }
-
- union {
- // Index of the next uniform to write to
- // TODO: ctrulib uses 8 bits for this, however that seems to yield lots of invalid
- // indices
- // TODO: Maybe the uppermost index is for the geometry shader? Investigate!
- BitField<0, 7, u32> index;
-
- BitField<31, 1, Format> format;
- };
-
- // Writing to these registers sets the current uniform.
- u32 set_value[8];
-
- } uniform_setup;
-
- INSERT_PADDING_WORDS(0x2);
-
- struct {
- // Offset of the next instruction to write code to.
- // Incremented with each instruction write.
- u32 offset;
-
- // Writing to these registers sets the "current" word in the shader program.
- u32 set_word[8];
- } program;
-
- INSERT_PADDING_WORDS(0x1);
-
- // This register group is used to load an internal table of swizzling patterns,
- // which are indexed by each shader instruction to specify vector component swizzling.
- struct {
- // Offset of the next swizzle pattern to write code to.
- // Incremented with each instruction write.
- u32 offset;
-
- // Writing to these registers sets the current swizzle pattern in the table.
- u32 set_word[8];
- } swizzle_patterns;
-
- INSERT_PADDING_WORDS(0x2);
- };
-
- ShaderConfig gs;
- ShaderConfig vs;
-
- INSERT_PADDING_WORDS(0x20);
-
- // Map register indices to names readable by humans
- // Used for debugging purposes, so performance is not an issue here
- static std::string GetCommandName(int index);
-
- static constexpr size_t NumIds() {
- return sizeof(Regs) / sizeof(u32);
- }
-
- const u32& operator[](int index) const {
- const u32* content = reinterpret_cast<const u32*>(this);
- return content[index];
- }
-
- u32& operator[](int index) {
- u32* content = reinterpret_cast<u32*>(this);
- return content[index];
- }
-
-private:
- /*
- * Most physical addresses which Pica registers refer to are 8-byte aligned.
- * This function should be used to get the address from a raw register value.
- */
- static inline u32 DecodeAddressRegister(u32 register_value) {
- return register_value * 8;
- }
-};
-
-// TODO: MSVC does not support using offsetof() on non-static data members even though this
-// is technically allowed since C++11. This macro should be enabled once MSVC adds
-// support for that.
-#ifndef _MSC_VER
-#define ASSERT_REG_POSITION(field_name, position) \
- static_assert(offsetof(Regs, field_name) == position * 4, \
- "Field " #field_name " has invalid position")
-
-ASSERT_REG_POSITION(trigger_irq, 0x10);
-ASSERT_REG_POSITION(cull_mode, 0x40);
-ASSERT_REG_POSITION(viewport_size_x, 0x41);
-ASSERT_REG_POSITION(viewport_size_y, 0x43);
-ASSERT_REG_POSITION(viewport_depth_range, 0x4d);
-ASSERT_REG_POSITION(viewport_depth_near_plane, 0x4e);
-ASSERT_REG_POSITION(vs_output_attributes[0], 0x50);
-ASSERT_REG_POSITION(vs_output_attributes[1], 0x51);
-ASSERT_REG_POSITION(scissor_test, 0x65);
-ASSERT_REG_POSITION(viewport_corner, 0x68);
-ASSERT_REG_POSITION(depthmap_enable, 0x6D);
-ASSERT_REG_POSITION(texture0_enable, 0x80);
-ASSERT_REG_POSITION(texture0, 0x81);
-ASSERT_REG_POSITION(texture0_format, 0x8e);
-ASSERT_REG_POSITION(fragment_lighting_enable, 0x8f);
-ASSERT_REG_POSITION(texture1, 0x91);
-ASSERT_REG_POSITION(texture1_format, 0x96);
-ASSERT_REG_POSITION(texture2, 0x99);
-ASSERT_REG_POSITION(texture2_format, 0x9e);
-ASSERT_REG_POSITION(tev_stage0, 0xc0);
-ASSERT_REG_POSITION(tev_stage1, 0xc8);
-ASSERT_REG_POSITION(tev_stage2, 0xd0);
-ASSERT_REG_POSITION(tev_stage3, 0xd8);
-ASSERT_REG_POSITION(tev_combiner_buffer_input, 0xe0);
-ASSERT_REG_POSITION(fog_mode, 0xe0);
-ASSERT_REG_POSITION(fog_color, 0xe1);
-ASSERT_REG_POSITION(fog_lut_offset, 0xe6);
-ASSERT_REG_POSITION(fog_lut_data, 0xe8);
-ASSERT_REG_POSITION(tev_stage4, 0xf0);
-ASSERT_REG_POSITION(tev_stage5, 0xf8);
-ASSERT_REG_POSITION(tev_combiner_buffer_color, 0xfd);
-ASSERT_REG_POSITION(output_merger, 0x100);
-ASSERT_REG_POSITION(framebuffer, 0x110);
-ASSERT_REG_POSITION(lighting, 0x140);
-ASSERT_REG_POSITION(vertex_attributes, 0x200);
-ASSERT_REG_POSITION(index_array, 0x227);
-ASSERT_REG_POSITION(num_vertices, 0x228);
-ASSERT_REG_POSITION(vertex_offset, 0x22a);
-ASSERT_REG_POSITION(trigger_draw, 0x22e);
-ASSERT_REG_POSITION(trigger_draw_indexed, 0x22f);
-ASSERT_REG_POSITION(vs_default_attributes_setup, 0x232);
-ASSERT_REG_POSITION(command_buffer, 0x238);
-ASSERT_REG_POSITION(gpu_mode, 0x245);
-ASSERT_REG_POSITION(triangle_topology, 0x25e);
-ASSERT_REG_POSITION(restart_primitive, 0x25f);
-ASSERT_REG_POSITION(gs, 0x280);
-ASSERT_REG_POSITION(vs, 0x2b0);
-
-#undef ASSERT_REG_POSITION
-#endif // !defined(_MSC_VER)
-
-static_assert(sizeof(Regs::ShaderConfig) == 0x30 * sizeof(u32),
- "ShaderConfig structure has incorrect size");
-
-// The total number of registers is chosen arbitrarily, but let's make sure it's not some odd value
-// anyway.
-static_assert(sizeof(Regs) <= 0x300 * sizeof(u32),
- "Register set structure larger than it should be");
-static_assert(sizeof(Regs) >= 0x300 * sizeof(u32),
- "Register set structure smaller than it should be");
-
/// Initialize Pica state
void Init();