Browse Source
Merge pull request #2482 from yuriks/pica-refactor
Merge pull request #2482 from yuriks/pica-refactor
Split up monolithic Regs structpull/15/merge
committed by
GitHub
37 changed files with 2635 additions and 2427 deletions
-
24src/citra_qt/debugger/graphics/graphics_cmdlists.cpp
-
33src/citra_qt/debugger/graphics/graphics_surface.cpp
-
1src/citra_qt/debugger/graphics/graphics_tracing.cpp
-
3src/citra_qt/debugger/graphics/graphics_vertex_shader.cpp
-
8src/video_core/CMakeLists.txt
-
10src/video_core/clipper.cpp
-
82src/video_core/command_processor.cpp
-
43src/video_core/debug_utils/debug_utils.cpp
-
14src/video_core/debug_utils/debug_utils.h
-
487src/video_core/pica.cpp
-
1393src/video_core/pica.h
-
2src/video_core/pica_state.h
-
18src/video_core/primitive_assembly.cpp
-
9src/video_core/primitive_assembly.h
-
307src/video_core/rasterizer.cpp
-
493src/video_core/regs.cpp
-
164src/video_core/regs.h
-
284src/video_core/regs_framebuffer.h
-
294src/video_core/regs_lighting.h
-
224src/video_core/regs_pipeline.h
-
129src/video_core/regs_rasterizer.h
-
104src/video_core/regs_shader.h
-
328src/video_core/regs_texturing.h
-
294src/video_core/renderer_opengl/gl_rasterizer.cpp
-
51src/video_core/renderer_opengl/gl_rasterizer.h
-
17src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
-
12src/video_core/renderer_opengl/gl_rasterizer_cache.h
-
99src/video_core/renderer_opengl/gl_shader_gen.cpp
-
18src/video_core/renderer_opengl/pica_to_gl.h
-
14src/video_core/shader/shader.cpp
-
24src/video_core/shader/shader.h
-
2src/video_core/shader/shader_interpreter.cpp
-
2src/video_core/shader/shader_interpreter.h
-
38src/video_core/texture/texture_decode.cpp
-
12src/video_core/texture/texture_decode.h
-
17src/video_core/vertex_loader.cpp
-
8src/video_core/vertex_loader.h
1393
src/video_core/pica.h
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -0,0 +1,493 @@ |
|||||
|
// Copyright 2015 Citra Emulator Project
|
||||
|
// Licensed under GPLv2 or any later version
|
||||
|
// Refer to the license.txt file included.
|
||||
|
|
||||
|
#include <iterator>
|
||||
|
#include <unordered_map>
|
||||
|
#include <utility>
|
||||
|
|
||||
|
#include "common/common_types.h"
|
||||
|
#include "video_core/regs.h"
|
||||
|
|
||||
|
namespace Pica { |
||||
|
|
||||
|
static const std::pair<u16, const char*> register_names[] = { |
||||
|
{0x010, "GPUREG_FINALIZE"}, |
||||
|
|
||||
|
{0x040, "GPUREG_FACECULLING_CONFIG"}, |
||||
|
{0x041, "GPUREG_VIEWPORT_WIDTH"}, |
||||
|
{0x042, "GPUREG_VIEWPORT_INVW"}, |
||||
|
{0x043, "GPUREG_VIEWPORT_HEIGHT"}, |
||||
|
{0x044, "GPUREG_VIEWPORT_INVH"}, |
||||
|
|
||||
|
{0x047, "GPUREG_FRAGOP_CLIP"}, |
||||
|
{0x048, "GPUREG_FRAGOP_CLIP_DATA0"}, |
||||
|
{0x049, "GPUREG_FRAGOP_CLIP_DATA1"}, |
||||
|
{0x04A, "GPUREG_FRAGOP_CLIP_DATA2"}, |
||||
|
{0x04B, "GPUREG_FRAGOP_CLIP_DATA3"}, |
||||
|
|
||||
|
{0x04D, "GPUREG_DEPTHMAP_SCALE"}, |
||||
|
{0x04E, "GPUREG_DEPTHMAP_OFFSET"}, |
||||
|
{0x04F, "GPUREG_SH_OUTMAP_TOTAL"}, |
||||
|
{0x050, "GPUREG_SH_OUTMAP_O0"}, |
||||
|
{0x051, "GPUREG_SH_OUTMAP_O1"}, |
||||
|
{0x052, "GPUREG_SH_OUTMAP_O2"}, |
||||
|
{0x053, "GPUREG_SH_OUTMAP_O3"}, |
||||
|
{0x054, "GPUREG_SH_OUTMAP_O4"}, |
||||
|
{0x055, "GPUREG_SH_OUTMAP_O5"}, |
||||
|
{0x056, "GPUREG_SH_OUTMAP_O6"}, |
||||
|
|
||||
|
{0x061, "GPUREG_EARLYDEPTH_FUNC"}, |
||||
|
{0x062, "GPUREG_EARLYDEPTH_TEST1"}, |
||||
|
{0x063, "GPUREG_EARLYDEPTH_CLEAR"}, |
||||
|
{0x064, "GPUREG_SH_OUTATTR_MODE"}, |
||||
|
{0x065, "GPUREG_SCISSORTEST_MODE"}, |
||||
|
{0x066, "GPUREG_SCISSORTEST_POS"}, |
||||
|
{0x067, "GPUREG_SCISSORTEST_DIM"}, |
||||
|
{0x068, "GPUREG_VIEWPORT_XY"}, |
||||
|
|
||||
|
{0x06A, "GPUREG_EARLYDEPTH_DATA"}, |
||||
|
|
||||
|
{0x06D, "GPUREG_DEPTHMAP_ENABLE"}, |
||||
|
{0x06E, "GPUREG_RENDERBUF_DIM"}, |
||||
|
{0x06F, "GPUREG_SH_OUTATTR_CLOCK"}, |
||||
|
|
||||
|
{0x080, "GPUREG_TEXUNIT_CONFIG"}, |
||||
|
{0x081, "GPUREG_TEXUNIT0_BORDER_COLOR"}, |
||||
|
{0x082, "GPUREG_TEXUNIT0_DIM"}, |
||||
|
{0x083, "GPUREG_TEXUNIT0_PARAM"}, |
||||
|
{0x084, "GPUREG_TEXUNIT0_LOD"}, |
||||
|
{0x085, "GPUREG_TEXUNIT0_ADDR1"}, |
||||
|
{0x086, "GPUREG_TEXUNIT0_ADDR2"}, |
||||
|
{0x087, "GPUREG_TEXUNIT0_ADDR3"}, |
||||
|
{0x088, "GPUREG_TEXUNIT0_ADDR4"}, |
||||
|
{0x089, "GPUREG_TEXUNIT0_ADDR5"}, |
||||
|
{0x08A, "GPUREG_TEXUNIT0_ADDR6"}, |
||||
|
{0x08B, "GPUREG_TEXUNIT0_SHADOW"}, |
||||
|
|
||||
|
{0x08E, "GPUREG_TEXUNIT0_TYPE"}, |
||||
|
{0x08F, "GPUREG_LIGHTING_ENABLE0"}, |
||||
|
|
||||
|
{0x091, "GPUREG_TEXUNIT1_BORDER_COLOR"}, |
||||
|
{0x092, "GPUREG_TEXUNIT1_DIM"}, |
||||
|
{0x093, "GPUREG_TEXUNIT1_PARAM"}, |
||||
|
{0x094, "GPUREG_TEXUNIT1_LOD"}, |
||||
|
{0x095, "GPUREG_TEXUNIT1_ADDR"}, |
||||
|
{0x096, "GPUREG_TEXUNIT1_TYPE"}, |
||||
|
|
||||
|
{0x099, "GPUREG_TEXUNIT2_BORDER_COLOR"}, |
||||
|
{0x09A, "GPUREG_TEXUNIT2_DIM"}, |
||||
|
{0x09B, "GPUREG_TEXUNIT2_PARAM"}, |
||||
|
{0x09C, "GPUREG_TEXUNIT2_LOD"}, |
||||
|
{0x09D, "GPUREG_TEXUNIT2_ADDR"}, |
||||
|
{0x09E, "GPUREG_TEXUNIT2_TYPE"}, |
||||
|
|
||||
|
{0x0A8, "GPUREG_TEXUNIT3_PROCTEX0"}, |
||||
|
{0x0A9, "GPUREG_TEXUNIT3_PROCTEX1"}, |
||||
|
{0x0AA, "GPUREG_TEXUNIT3_PROCTEX2"}, |
||||
|
{0x0AB, "GPUREG_TEXUNIT3_PROCTEX3"}, |
||||
|
{0x0AC, "GPUREG_TEXUNIT3_PROCTEX4"}, |
||||
|
{0x0AD, "GPUREG_TEXUNIT3_PROCTEX5"}, |
||||
|
|
||||
|
{0x0AF, "GPUREG_PROCTEX_LUT"}, |
||||
|
{0x0B0, "GPUREG_PROCTEX_LUT_DATA0"}, |
||||
|
{0x0B1, "GPUREG_PROCTEX_LUT_DATA1"}, |
||||
|
{0x0B2, "GPUREG_PROCTEX_LUT_DATA2"}, |
||||
|
{0x0B3, "GPUREG_PROCTEX_LUT_DATA3"}, |
||||
|
{0x0B4, "GPUREG_PROCTEX_LUT_DATA4"}, |
||||
|
{0x0B5, "GPUREG_PROCTEX_LUT_DATA5"}, |
||||
|
{0x0B6, "GPUREG_PROCTEX_LUT_DATA6"}, |
||||
|
{0x0B7, "GPUREG_PROCTEX_LUT_DATA7"}, |
||||
|
|
||||
|
{0x0C0, "GPUREG_TEXENV0_SOURCE"}, |
||||
|
{0x0C1, "GPUREG_TEXENV0_OPERAND"}, |
||||
|
{0x0C2, "GPUREG_TEXENV0_COMBINER"}, |
||||
|
{0x0C3, "GPUREG_TEXENV0_COLOR"}, |
||||
|
{0x0C4, "GPUREG_TEXENV0_SCALE"}, |
||||
|
|
||||
|
{0x0C8, "GPUREG_TEXENV1_SOURCE"}, |
||||
|
{0x0C9, "GPUREG_TEXENV1_OPERAND"}, |
||||
|
{0x0CA, "GPUREG_TEXENV1_COMBINER"}, |
||||
|
{0x0CB, "GPUREG_TEXENV1_COLOR"}, |
||||
|
{0x0CC, "GPUREG_TEXENV1_SCALE"}, |
||||
|
|
||||
|
{0x0D0, "GPUREG_TEXENV2_SOURCE"}, |
||||
|
{0x0D1, "GPUREG_TEXENV2_OPERAND"}, |
||||
|
{0x0D2, "GPUREG_TEXENV2_COMBINER"}, |
||||
|
{0x0D3, "GPUREG_TEXENV2_COLOR"}, |
||||
|
{0x0D4, "GPUREG_TEXENV2_SCALE"}, |
||||
|
|
||||
|
{0x0D8, "GPUREG_TEXENV3_SOURCE"}, |
||||
|
{0x0D9, "GPUREG_TEXENV3_OPERAND"}, |
||||
|
{0x0DA, "GPUREG_TEXENV3_COMBINER"}, |
||||
|
{0x0DB, "GPUREG_TEXENV3_COLOR"}, |
||||
|
{0x0DC, "GPUREG_TEXENV3_SCALE"}, |
||||
|
|
||||
|
{0x0E0, "GPUREG_TEXENV_UPDATE_BUFFER"}, |
||||
|
{0x0E1, "GPUREG_FOG_COLOR"}, |
||||
|
|
||||
|
{0x0E4, "GPUREG_GAS_ATTENUATION"}, |
||||
|
{0x0E5, "GPUREG_GAS_ACCMAX"}, |
||||
|
{0x0E6, "GPUREG_FOG_LUT_INDEX"}, |
||||
|
|
||||
|
{0x0E8, "GPUREG_FOG_LUT_DATA0"}, |
||||
|
{0x0E9, "GPUREG_FOG_LUT_DATA1"}, |
||||
|
{0x0EA, "GPUREG_FOG_LUT_DATA2"}, |
||||
|
{0x0EB, "GPUREG_FOG_LUT_DATA3"}, |
||||
|
{0x0EC, "GPUREG_FOG_LUT_DATA4"}, |
||||
|
{0x0ED, "GPUREG_FOG_LUT_DATA5"}, |
||||
|
{0x0EE, "GPUREG_FOG_LUT_DATA6"}, |
||||
|
{0x0EF, "GPUREG_FOG_LUT_DATA7"}, |
||||
|
{0x0F0, "GPUREG_TEXENV4_SOURCE"}, |
||||
|
{0x0F1, "GPUREG_TEXENV4_OPERAND"}, |
||||
|
{0x0F2, "GPUREG_TEXENV4_COMBINER"}, |
||||
|
{0x0F3, "GPUREG_TEXENV4_COLOR"}, |
||||
|
{0x0F4, "GPUREG_TEXENV4_SCALE"}, |
||||
|
|
||||
|
{0x0F8, "GPUREG_TEXENV5_SOURCE"}, |
||||
|
{0x0F9, "GPUREG_TEXENV5_OPERAND"}, |
||||
|
{0x0FA, "GPUREG_TEXENV5_COMBINER"}, |
||||
|
{0x0FB, "GPUREG_TEXENV5_COLOR"}, |
||||
|
{0x0FC, "GPUREG_TEXENV5_SCALE"}, |
||||
|
{0x0FD, "GPUREG_TEXENV_BUFFER_COLOR"}, |
||||
|
|
||||
|
{0x100, "GPUREG_COLOR_OPERATION"}, |
||||
|
{0x101, "GPUREG_BLEND_FUNC"}, |
||||
|
{0x102, "GPUREG_LOGIC_OP"}, |
||||
|
{0x103, "GPUREG_BLEND_COLOR"}, |
||||
|
{0x104, "GPUREG_FRAGOP_ALPHA_TEST"}, |
||||
|
{0x105, "GPUREG_STENCIL_TEST"}, |
||||
|
{0x106, "GPUREG_STENCIL_OP"}, |
||||
|
{0x107, "GPUREG_DEPTH_COLOR_MASK"}, |
||||
|
|
||||
|
{0x110, "GPUREG_FRAMEBUFFER_INVALIDATE"}, |
||||
|
{0x111, "GPUREG_FRAMEBUFFER_FLUSH"}, |
||||
|
{0x112, "GPUREG_COLORBUFFER_READ"}, |
||||
|
{0x113, "GPUREG_COLORBUFFER_WRITE"}, |
||||
|
{0x114, "GPUREG_DEPTHBUFFER_READ"}, |
||||
|
{0x115, "GPUREG_DEPTHBUFFER_WRITE"}, |
||||
|
{0x116, "GPUREG_DEPTHBUFFER_FORMAT"}, |
||||
|
{0x117, "GPUREG_COLORBUFFER_FORMAT"}, |
||||
|
{0x118, "GPUREG_EARLYDEPTH_TEST2"}, |
||||
|
|
||||
|
{0x11B, "GPUREG_FRAMEBUFFER_BLOCK32"}, |
||||
|
{0x11C, "GPUREG_DEPTHBUFFER_LOC"}, |
||||
|
{0x11D, "GPUREG_COLORBUFFER_LOC"}, |
||||
|
{0x11E, "GPUREG_FRAMEBUFFER_DIM"}, |
||||
|
|
||||
|
{0x120, "GPUREG_GAS_LIGHT_XY"}, |
||||
|
{0x121, "GPUREG_GAS_LIGHT_Z"}, |
||||
|
{0x122, "GPUREG_GAS_LIGHT_Z_COLOR"}, |
||||
|
{0x123, "GPUREG_GAS_LUT_INDEX"}, |
||||
|
{0x124, "GPUREG_GAS_LUT_DATA"}, |
||||
|
|
||||
|
{0x126, "GPUREG_GAS_DELTAZ_DEPTH"}, |
||||
|
|
||||
|
{0x130, "GPUREG_FRAGOP_SHADOW"}, |
||||
|
|
||||
|
{0x140, "GPUREG_LIGHT0_SPECULAR0"}, |
||||
|
{0x141, "GPUREG_LIGHT0_SPECULAR1"}, |
||||
|
{0x142, "GPUREG_LIGHT0_DIFFUSE"}, |
||||
|
{0x143, "GPUREG_LIGHT0_AMBIENT"}, |
||||
|
{0x144, "GPUREG_LIGHT0_XY"}, |
||||
|
{0x145, "GPUREG_LIGHT0_Z"}, |
||||
|
{0x146, "GPUREG_LIGHT0_SPOTDIR_XY"}, |
||||
|
{0x147, "GPUREG_LIGHT0_SPOTDIR_Z"}, |
||||
|
|
||||
|
{0x149, "GPUREG_LIGHT0_CONFIG"}, |
||||
|
{0x14A, "GPUREG_LIGHT0_ATTENUATION_BIAS"}, |
||||
|
{0x14B, "GPUREG_LIGHT0_ATTENUATION_SCALE"}, |
||||
|
|
||||
|
{0x150, "GPUREG_LIGHT1_SPECULAR0"}, |
||||
|
{0x151, "GPUREG_LIGHT1_SPECULAR1"}, |
||||
|
{0x152, "GPUREG_LIGHT1_DIFFUSE"}, |
||||
|
{0x153, "GPUREG_LIGHT1_AMBIENT"}, |
||||
|
{0x154, "GPUREG_LIGHT1_XY"}, |
||||
|
{0x155, "GPUREG_LIGHT1_Z"}, |
||||
|
{0x156, "GPUREG_LIGHT1_SPOTDIR_XY"}, |
||||
|
{0x157, "GPUREG_LIGHT1_SPOTDIR_Z"}, |
||||
|
|
||||
|
{0x159, "GPUREG_LIGHT1_CONFIG"}, |
||||
|
{0x15A, "GPUREG_LIGHT1_ATTENUATION_BIAS"}, |
||||
|
{0x15B, "GPUREG_LIGHT1_ATTENUATION_SCALE"}, |
||||
|
|
||||
|
{0x160, "GPUREG_LIGHT2_SPECULAR0"}, |
||||
|
{0x161, "GPUREG_LIGHT2_SPECULAR1"}, |
||||
|
{0x162, "GPUREG_LIGHT2_DIFFUSE"}, |
||||
|
{0x163, "GPUREG_LIGHT2_AMBIENT"}, |
||||
|
{0x164, "GPUREG_LIGHT2_XY"}, |
||||
|
{0x165, "GPUREG_LIGHT2_Z"}, |
||||
|
{0x166, "GPUREG_LIGHT2_SPOTDIR_XY"}, |
||||
|
{0x167, "GPUREG_LIGHT2_SPOTDIR_Z"}, |
||||
|
|
||||
|
{0x169, "GPUREG_LIGHT2_CONFIG"}, |
||||
|
{0x16A, "GPUREG_LIGHT2_ATTENUATION_BIAS"}, |
||||
|
{0x16B, "GPUREG_LIGHT2_ATTENUATION_SCALE"}, |
||||
|
|
||||
|
{0x170, "GPUREG_LIGHT3_SPECULAR0"}, |
||||
|
{0x171, "GPUREG_LIGHT3_SPECULAR1"}, |
||||
|
{0x172, "GPUREG_LIGHT3_DIFFUSE"}, |
||||
|
{0x173, "GPUREG_LIGHT3_AMBIENT"}, |
||||
|
{0x174, "GPUREG_LIGHT3_XY"}, |
||||
|
{0x175, "GPUREG_LIGHT3_Z"}, |
||||
|
{0x176, "GPUREG_LIGHT3_SPOTDIR_XY"}, |
||||
|
{0x177, "GPUREG_LIGHT3_SPOTDIR_Z"}, |
||||
|
|
||||
|
{0x179, "GPUREG_LIGHT3_CONFIG"}, |
||||
|
{0x17A, "GPUREG_LIGHT3_ATTENUATION_BIAS"}, |
||||
|
{0x17B, "GPUREG_LIGHT3_ATTENUATION_SCALE"}, |
||||
|
|
||||
|
{0x180, "GPUREG_LIGHT4_SPECULAR0"}, |
||||
|
{0x181, "GPUREG_LIGHT4_SPECULAR1"}, |
||||
|
{0x182, "GPUREG_LIGHT4_DIFFUSE"}, |
||||
|
{0x183, "GPUREG_LIGHT4_AMBIENT"}, |
||||
|
{0x184, "GPUREG_LIGHT4_XY"}, |
||||
|
{0x185, "GPUREG_LIGHT4_Z"}, |
||||
|
{0x186, "GPUREG_LIGHT4_SPOTDIR_XY"}, |
||||
|
{0x187, "GPUREG_LIGHT4_SPOTDIR_Z"}, |
||||
|
|
||||
|
{0x189, "GPUREG_LIGHT4_CONFIG"}, |
||||
|
{0x18A, "GPUREG_LIGHT4_ATTENUATION_BIAS"}, |
||||
|
{0x18B, "GPUREG_LIGHT4_ATTENUATION_SCALE"}, |
||||
|
|
||||
|
{0x190, "GPUREG_LIGHT5_SPECULAR0"}, |
||||
|
{0x191, "GPUREG_LIGHT5_SPECULAR1"}, |
||||
|
{0x192, "GPUREG_LIGHT5_DIFFUSE"}, |
||||
|
{0x193, "GPUREG_LIGHT5_AMBIENT"}, |
||||
|
{0x194, "GPUREG_LIGHT5_XY"}, |
||||
|
{0x195, "GPUREG_LIGHT5_Z"}, |
||||
|
{0x196, "GPUREG_LIGHT5_SPOTDIR_XY"}, |
||||
|
{0x197, "GPUREG_LIGHT5_SPOTDIR_Z"}, |
||||
|
|
||||
|
{0x199, "GPUREG_LIGHT5_CONFIG"}, |
||||
|
{0x19A, "GPUREG_LIGHT5_ATTENUATION_BIAS"}, |
||||
|
{0x19B, "GPUREG_LIGHT5_ATTENUATION_SCALE"}, |
||||
|
|
||||
|
{0x1A0, "GPUREG_LIGHT6_SPECULAR0"}, |
||||
|
{0x1A1, "GPUREG_LIGHT6_SPECULAR1"}, |
||||
|
{0x1A2, "GPUREG_LIGHT6_DIFFUSE"}, |
||||
|
{0x1A3, "GPUREG_LIGHT6_AMBIENT"}, |
||||
|
{0x1A4, "GPUREG_LIGHT6_XY"}, |
||||
|
{0x1A5, "GPUREG_LIGHT6_Z"}, |
||||
|
{0x1A6, "GPUREG_LIGHT6_SPOTDIR_XY"}, |
||||
|
{0x1A7, "GPUREG_LIGHT6_SPOTDIR_Z"}, |
||||
|
|
||||
|
{0x1A9, "GPUREG_LIGHT6_CONFIG"}, |
||||
|
{0x1AA, "GPUREG_LIGHT6_ATTENUATION_BIAS"}, |
||||
|
{0x1AB, "GPUREG_LIGHT6_ATTENUATION_SCALE"}, |
||||
|
|
||||
|
{0x1B0, "GPUREG_LIGHT7_SPECULAR0"}, |
||||
|
{0x1B1, "GPUREG_LIGHT7_SPECULAR1"}, |
||||
|
{0x1B2, "GPUREG_LIGHT7_DIFFUSE"}, |
||||
|
{0x1B3, "GPUREG_LIGHT7_AMBIENT"}, |
||||
|
{0x1B4, "GPUREG_LIGHT7_XY"}, |
||||
|
{0x1B5, "GPUREG_LIGHT7_Z"}, |
||||
|
{0x1B6, "GPUREG_LIGHT7_SPOTDIR_XY"}, |
||||
|
{0x1B7, "GPUREG_LIGHT7_SPOTDIR_Z"}, |
||||
|
|
||||
|
{0x1B9, "GPUREG_LIGHT7_CONFIG"}, |
||||
|
{0x1BA, "GPUREG_LIGHT7_ATTENUATION_BIAS"}, |
||||
|
{0x1BB, "GPUREG_LIGHT7_ATTENUATION_SCALE"}, |
||||
|
|
||||
|
{0x1C0, "GPUREG_LIGHTING_AMBIENT"}, |
||||
|
|
||||
|
{0x1C2, "GPUREG_LIGHTING_NUM_LIGHTS"}, |
||||
|
{0x1C3, "GPUREG_LIGHTING_CONFIG0"}, |
||||
|
{0x1C4, "GPUREG_LIGHTING_CONFIG1"}, |
||||
|
{0x1C5, "GPUREG_LIGHTING_LUT_INDEX"}, |
||||
|
{0x1C6, "GPUREG_LIGHTING_ENABLE1"}, |
||||
|
|
||||
|
{0x1C8, "GPUREG_LIGHTING_LUT_DATA0"}, |
||||
|
{0x1C9, "GPUREG_LIGHTING_LUT_DATA1"}, |
||||
|
{0x1CA, "GPUREG_LIGHTING_LUT_DATA2"}, |
||||
|
{0x1CB, "GPUREG_LIGHTING_LUT_DATA3"}, |
||||
|
{0x1CC, "GPUREG_LIGHTING_LUT_DATA4"}, |
||||
|
{0x1CD, "GPUREG_LIGHTING_LUT_DATA5"}, |
||||
|
{0x1CE, "GPUREG_LIGHTING_LUT_DATA6"}, |
||||
|
{0x1CF, "GPUREG_LIGHTING_LUT_DATA7"}, |
||||
|
{0x1D0, "GPUREG_LIGHTING_LUTINPUT_ABS"}, |
||||
|
{0x1D1, "GPUREG_LIGHTING_LUTINPUT_SELECT"}, |
||||
|
{0x1D2, "GPUREG_LIGHTING_LUTINPUT_SCALE"}, |
||||
|
|
||||
|
{0x1D9, "GPUREG_LIGHTING_LIGHT_PERMUTATION"}, |
||||
|
|
||||
|
{0x200, "GPUREG_ATTRIBBUFFERS_LOC"}, |
||||
|
{0x201, "GPUREG_ATTRIBBUFFERS_FORMAT_LOW"}, |
||||
|
{0x202, "GPUREG_ATTRIBBUFFERS_FORMAT_HIGH"}, |
||||
|
{0x203, "GPUREG_ATTRIBBUFFER0_OFFSET"}, |
||||
|
{0x204, "GPUREG_ATTRIBBUFFER0_CONFIG1"}, |
||||
|
{0x205, "GPUREG_ATTRIBBUFFER0_CONFIG2"}, |
||||
|
{0x206, "GPUREG_ATTRIBBUFFER1_OFFSET"}, |
||||
|
{0x207, "GPUREG_ATTRIBBUFFER1_CONFIG1"}, |
||||
|
{0x208, "GPUREG_ATTRIBBUFFER1_CONFIG2"}, |
||||
|
{0x209, "GPUREG_ATTRIBBUFFER2_OFFSET"}, |
||||
|
{0x20A, "GPUREG_ATTRIBBUFFER2_CONFIG1"}, |
||||
|
{0x20B, "GPUREG_ATTRIBBUFFER2_CONFIG2"}, |
||||
|
{0x20C, "GPUREG_ATTRIBBUFFER3_OFFSET"}, |
||||
|
{0x20D, "GPUREG_ATTRIBBUFFER3_CONFIG1"}, |
||||
|
{0x20E, "GPUREG_ATTRIBBUFFER3_CONFIG2"}, |
||||
|
{0x20F, "GPUREG_ATTRIBBUFFER4_OFFSET"}, |
||||
|
{0x210, "GPUREG_ATTRIBBUFFER4_CONFIG1"}, |
||||
|
{0x211, "GPUREG_ATTRIBBUFFER4_CONFIG2"}, |
||||
|
{0x212, "GPUREG_ATTRIBBUFFER5_OFFSET"}, |
||||
|
{0x213, "GPUREG_ATTRIBBUFFER5_CONFIG1"}, |
||||
|
{0x214, "GPUREG_ATTRIBBUFFER5_CONFIG2"}, |
||||
|
{0x215, "GPUREG_ATTRIBBUFFER6_OFFSET"}, |
||||
|
{0x216, "GPUREG_ATTRIBBUFFER6_CONFIG1"}, |
||||
|
{0x217, "GPUREG_ATTRIBBUFFER6_CONFIG2"}, |
||||
|
{0x218, "GPUREG_ATTRIBBUFFER7_OFFSET"}, |
||||
|
{0x219, "GPUREG_ATTRIBBUFFER7_CONFIG1"}, |
||||
|
{0x21A, "GPUREG_ATTRIBBUFFER7_CONFIG2"}, |
||||
|
{0x21B, "GPUREG_ATTRIBBUFFER8_OFFSET"}, |
||||
|
{0x21C, "GPUREG_ATTRIBBUFFER8_CONFIG1"}, |
||||
|
{0x21D, "GPUREG_ATTRIBBUFFER8_CONFIG2"}, |
||||
|
{0x21E, "GPUREG_ATTRIBBUFFER9_OFFSET"}, |
||||
|
{0x21F, "GPUREG_ATTRIBBUFFER9_CONFIG1"}, |
||||
|
{0x220, "GPUREG_ATTRIBBUFFER9_CONFIG2"}, |
||||
|
{0x221, "GPUREG_ATTRIBBUFFER10_OFFSET"}, |
||||
|
{0x222, "GPUREG_ATTRIBBUFFER10_CONFIG1"}, |
||||
|
{0x223, "GPUREG_ATTRIBBUFFER10_CONFIG2"}, |
||||
|
{0x224, "GPUREG_ATTRIBBUFFER11_OFFSET"}, |
||||
|
{0x225, "GPUREG_ATTRIBBUFFER11_CONFIG1"}, |
||||
|
{0x226, "GPUREG_ATTRIBBUFFER11_CONFIG2"}, |
||||
|
{0x227, "GPUREG_INDEXBUFFER_CONFIG"}, |
||||
|
{0x228, "GPUREG_NUMVERTICES"}, |
||||
|
{0x229, "GPUREG_GEOSTAGE_CONFIG"}, |
||||
|
{0x22A, "GPUREG_VERTEX_OFFSET"}, |
||||
|
|
||||
|
{0x22D, "GPUREG_POST_VERTEX_CACHE_NUM"}, |
||||
|
{0x22E, "GPUREG_DRAWARRAYS"}, |
||||
|
{0x22F, "GPUREG_DRAWELEMENTS"}, |
||||
|
|
||||
|
{0x231, "GPUREG_VTX_FUNC"}, |
||||
|
{0x232, "GPUREG_FIXEDATTRIB_INDEX"}, |
||||
|
{0x233, "GPUREG_FIXEDATTRIB_DATA0"}, |
||||
|
{0x234, "GPUREG_FIXEDATTRIB_DATA1"}, |
||||
|
{0x235, "GPUREG_FIXEDATTRIB_DATA2"}, |
||||
|
|
||||
|
{0x238, "GPUREG_CMDBUF_SIZE0"}, |
||||
|
{0x239, "GPUREG_CMDBUF_SIZE1"}, |
||||
|
{0x23A, "GPUREG_CMDBUF_ADDR0"}, |
||||
|
{0x23B, "GPUREG_CMDBUF_ADDR1"}, |
||||
|
{0x23C, "GPUREG_CMDBUF_JUMP0"}, |
||||
|
{0x23D, "GPUREG_CMDBUF_JUMP1"}, |
||||
|
|
||||
|
{0x242, "GPUREG_VSH_NUM_ATTR"}, |
||||
|
|
||||
|
{0x244, "GPUREG_VSH_COM_MODE"}, |
||||
|
{0x245, "GPUREG_START_DRAW_FUNC0"}, |
||||
|
|
||||
|
{0x24A, "GPUREG_VSH_OUTMAP_TOTAL1"}, |
||||
|
|
||||
|
{0x251, "GPUREG_VSH_OUTMAP_TOTAL2"}, |
||||
|
{0x252, "GPUREG_GSH_MISC0"}, |
||||
|
{0x253, "GPUREG_GEOSTAGE_CONFIG2"}, |
||||
|
{0x254, "GPUREG_GSH_MISC1"}, |
||||
|
|
||||
|
{0x25E, "GPUREG_PRIMITIVE_CONFIG"}, |
||||
|
{0x25F, "GPUREG_RESTART_PRIMITIVE"}, |
||||
|
|
||||
|
{0x280, "GPUREG_GSH_BOOLUNIFORM"}, |
||||
|
{0x281, "GPUREG_GSH_INTUNIFORM_I0"}, |
||||
|
{0x282, "GPUREG_GSH_INTUNIFORM_I1"}, |
||||
|
{0x283, "GPUREG_GSH_INTUNIFORM_I2"}, |
||||
|
{0x284, "GPUREG_GSH_INTUNIFORM_I3"}, |
||||
|
|
||||
|
{0x289, "GPUREG_GSH_INPUTBUFFER_CONFIG"}, |
||||
|
{0x28A, "GPUREG_GSH_ENTRYPOINT"}, |
||||
|
{0x28B, "GPUREG_GSH_ATTRIBUTES_PERMUTATION_LOW"}, |
||||
|
{0x28C, "GPUREG_GSH_ATTRIBUTES_PERMUTATION_HIGH"}, |
||||
|
{0x28D, "GPUREG_GSH_OUTMAP_MASK"}, |
||||
|
|
||||
|
{0x28F, "GPUREG_GSH_CODETRANSFER_END"}, |
||||
|
{0x290, "GPUREG_GSH_FLOATUNIFORM_INDEX"}, |
||||
|
{0x291, "GPUREG_GSH_FLOATUNIFORM_DATA0"}, |
||||
|
{0x292, "GPUREG_GSH_FLOATUNIFORM_DATA1"}, |
||||
|
{0x293, "GPUREG_GSH_FLOATUNIFORM_DATA2"}, |
||||
|
{0x294, "GPUREG_GSH_FLOATUNIFORM_DATA3"}, |
||||
|
{0x295, "GPUREG_GSH_FLOATUNIFORM_DATA4"}, |
||||
|
{0x296, "GPUREG_GSH_FLOATUNIFORM_DATA5"}, |
||||
|
{0x297, "GPUREG_GSH_FLOATUNIFORM_DATA6"}, |
||||
|
{0x298, "GPUREG_GSH_FLOATUNIFORM_DATA7"}, |
||||
|
|
||||
|
{0x29B, "GPUREG_GSH_CODETRANSFER_INDEX"}, |
||||
|
{0x29C, "GPUREG_GSH_CODETRANSFER_DATA0"}, |
||||
|
{0x29D, "GPUREG_GSH_CODETRANSFER_DATA1"}, |
||||
|
{0x29E, "GPUREG_GSH_CODETRANSFER_DATA2"}, |
||||
|
{0x29F, "GPUREG_GSH_CODETRANSFER_DATA3"}, |
||||
|
{0x2A0, "GPUREG_GSH_CODETRANSFER_DATA4"}, |
||||
|
{0x2A1, "GPUREG_GSH_CODETRANSFER_DATA5"}, |
||||
|
{0x2A2, "GPUREG_GSH_CODETRANSFER_DATA6"}, |
||||
|
{0x2A3, "GPUREG_GSH_CODETRANSFER_DATA7"}, |
||||
|
|
||||
|
{0x2A5, "GPUREG_GSH_OPDESCS_INDEX"}, |
||||
|
{0x2A6, "GPUREG_GSH_OPDESCS_DATA0"}, |
||||
|
{0x2A7, "GPUREG_GSH_OPDESCS_DATA1"}, |
||||
|
{0x2A8, "GPUREG_GSH_OPDESCS_DATA2"}, |
||||
|
{0x2A9, "GPUREG_GSH_OPDESCS_DATA3"}, |
||||
|
{0x2AA, "GPUREG_GSH_OPDESCS_DATA4"}, |
||||
|
{0x2AB, "GPUREG_GSH_OPDESCS_DATA5"}, |
||||
|
{0x2AC, "GPUREG_GSH_OPDESCS_DATA6"}, |
||||
|
{0x2AD, "GPUREG_GSH_OPDESCS_DATA7"}, |
||||
|
|
||||
|
{0x2B0, "GPUREG_VSH_BOOLUNIFORM"}, |
||||
|
{0x2B1, "GPUREG_VSH_INTUNIFORM_I0"}, |
||||
|
{0x2B2, "GPUREG_VSH_INTUNIFORM_I1"}, |
||||
|
{0x2B3, "GPUREG_VSH_INTUNIFORM_I2"}, |
||||
|
{0x2B4, "GPUREG_VSH_INTUNIFORM_I3"}, |
||||
|
|
||||
|
{0x2B9, "GPUREG_VSH_INPUTBUFFER_CONFIG"}, |
||||
|
{0x2BA, "GPUREG_VSH_ENTRYPOINT"}, |
||||
|
{0x2BB, "GPUREG_VSH_ATTRIBUTES_PERMUTATION_LOW"}, |
||||
|
{0x2BC, "GPUREG_VSH_ATTRIBUTES_PERMUTATION_HIGH"}, |
||||
|
{0x2BD, "GPUREG_VSH_OUTMAP_MASK"}, |
||||
|
|
||||
|
{0x2BF, "GPUREG_VSH_CODETRANSFER_END"}, |
||||
|
{0x2C0, "GPUREG_VSH_FLOATUNIFORM_INDEX"}, |
||||
|
{0x2C1, "GPUREG_VSH_FLOATUNIFORM_DATA0"}, |
||||
|
{0x2C2, "GPUREG_VSH_FLOATUNIFORM_DATA1"}, |
||||
|
{0x2C3, "GPUREG_VSH_FLOATUNIFORM_DATA2"}, |
||||
|
{0x2C4, "GPUREG_VSH_FLOATUNIFORM_DATA3"}, |
||||
|
{0x2C5, "GPUREG_VSH_FLOATUNIFORM_DATA4"}, |
||||
|
{0x2C6, "GPUREG_VSH_FLOATUNIFORM_DATA5"}, |
||||
|
{0x2C7, "GPUREG_VSH_FLOATUNIFORM_DATA6"}, |
||||
|
{0x2C8, "GPUREG_VSH_FLOATUNIFORM_DATA7"}, |
||||
|
|
||||
|
{0x2CB, "GPUREG_VSH_CODETRANSFER_INDEX"}, |
||||
|
{0x2CC, "GPUREG_VSH_CODETRANSFER_DATA0"}, |
||||
|
{0x2CD, "GPUREG_VSH_CODETRANSFER_DATA1"}, |
||||
|
{0x2CE, "GPUREG_VSH_CODETRANSFER_DATA2"}, |
||||
|
{0x2CF, "GPUREG_VSH_CODETRANSFER_DATA3"}, |
||||
|
{0x2D0, "GPUREG_VSH_CODETRANSFER_DATA4"}, |
||||
|
{0x2D1, "GPUREG_VSH_CODETRANSFER_DATA5"}, |
||||
|
{0x2D2, "GPUREG_VSH_CODETRANSFER_DATA6"}, |
||||
|
{0x2D3, "GPUREG_VSH_CODETRANSFER_DATA7"}, |
||||
|
|
||||
|
{0x2D5, "GPUREG_VSH_OPDESCS_INDEX"}, |
||||
|
{0x2D6, "GPUREG_VSH_OPDESCS_DATA0"}, |
||||
|
{0x2D7, "GPUREG_VSH_OPDESCS_DATA1"}, |
||||
|
{0x2D8, "GPUREG_VSH_OPDESCS_DATA2"}, |
||||
|
{0x2D9, "GPUREG_VSH_OPDESCS_DATA3"}, |
||||
|
{0x2DA, "GPUREG_VSH_OPDESCS_DATA4"}, |
||||
|
{0x2DB, "GPUREG_VSH_OPDESCS_DATA5"}, |
||||
|
{0x2DC, "GPUREG_VSH_OPDESCS_DATA6"}, |
||||
|
{0x2DD, "GPUREG_VSH_OPDESCS_DATA7"}, |
||||
|
}; |
||||
|
|
||||
|
std::string Regs::GetCommandName(int index) { |
||||
|
static std::unordered_map<u32, const char*> map; |
||||
|
|
||||
|
if (map.empty()) { |
||||
|
map.insert(std::begin(register_names), std::end(register_names)); |
||||
|
} |
||||
|
|
||||
|
// Return empty string if no match is found
|
||||
|
auto it = map.find(index); |
||||
|
if (it != map.end()) { |
||||
|
return it->second; |
||||
|
} else { |
||||
|
return std::string(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
} // namespace Pica
|
||||
@ -0,0 +1,164 @@ |
|||||
|
// Copyright 2017 Citra Emulator Project |
||||
|
// Licensed under GPLv2 or any later version |
||||
|
// Refer to the license.txt file included. |
||||
|
|
||||
|
#pragma once |
||||
|
|
||||
|
#include <array> |
||||
|
#include <cstddef> |
||||
|
#include <string> |
||||
|
#ifndef _MSC_VER |
||||
|
#include <type_traits> // for std::enable_if |
||||
|
#endif |
||||
|
|
||||
|
#include "common/common_funcs.h" |
||||
|
#include "common/common_types.h" |
||||
|
#include "video_core/regs_framebuffer.h" |
||||
|
#include "video_core/regs_lighting.h" |
||||
|
#include "video_core/regs_pipeline.h" |
||||
|
#include "video_core/regs_rasterizer.h" |
||||
|
#include "video_core/regs_shader.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); |
||||
|
RasterizerRegs rasterizer; |
||||
|
TexturingRegs texturing; |
||||
|
FramebufferRegs framebuffer; |
||||
|
LightingRegs lighting; |
||||
|
PipelineRegs pipeline; |
||||
|
ShaderRegs gs; |
||||
|
ShaderRegs 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(rasterizer, 0x40); |
||||
|
ASSERT_REG_POSITION(rasterizer.cull_mode, 0x40); |
||||
|
ASSERT_REG_POSITION(rasterizer.viewport_size_x, 0x41); |
||||
|
ASSERT_REG_POSITION(rasterizer.viewport_size_y, 0x43); |
||||
|
ASSERT_REG_POSITION(rasterizer.viewport_depth_range, 0x4d); |
||||
|
ASSERT_REG_POSITION(rasterizer.viewport_depth_near_plane, 0x4e); |
||||
|
ASSERT_REG_POSITION(rasterizer.vs_output_attributes[0], 0x50); |
||||
|
ASSERT_REG_POSITION(rasterizer.vs_output_attributes[1], 0x51); |
||||
|
ASSERT_REG_POSITION(rasterizer.scissor_test, 0x65); |
||||
|
ASSERT_REG_POSITION(rasterizer.viewport_corner, 0x68); |
||||
|
ASSERT_REG_POSITION(rasterizer.depthmap_enable, 0x6D); |
||||
|
|
||||
|
ASSERT_REG_POSITION(texturing, 0x80); |
||||
|
ASSERT_REG_POSITION(texturing.texture0_enable, 0x80); |
||||
|
ASSERT_REG_POSITION(texturing.texture0, 0x81); |
||||
|
ASSERT_REG_POSITION(texturing.texture0_format, 0x8e); |
||||
|
ASSERT_REG_POSITION(texturing.fragment_lighting_enable, 0x8f); |
||||
|
ASSERT_REG_POSITION(texturing.texture1, 0x91); |
||||
|
ASSERT_REG_POSITION(texturing.texture1_format, 0x96); |
||||
|
ASSERT_REG_POSITION(texturing.texture2, 0x99); |
||||
|
ASSERT_REG_POSITION(texturing.texture2_format, 0x9e); |
||||
|
ASSERT_REG_POSITION(texturing.tev_stage0, 0xc0); |
||||
|
ASSERT_REG_POSITION(texturing.tev_stage1, 0xc8); |
||||
|
ASSERT_REG_POSITION(texturing.tev_stage2, 0xd0); |
||||
|
ASSERT_REG_POSITION(texturing.tev_stage3, 0xd8); |
||||
|
ASSERT_REG_POSITION(texturing.tev_combiner_buffer_input, 0xe0); |
||||
|
ASSERT_REG_POSITION(texturing.fog_mode, 0xe0); |
||||
|
ASSERT_REG_POSITION(texturing.fog_color, 0xe1); |
||||
|
ASSERT_REG_POSITION(texturing.fog_lut_offset, 0xe6); |
||||
|
ASSERT_REG_POSITION(texturing.fog_lut_data, 0xe8); |
||||
|
ASSERT_REG_POSITION(texturing.tev_stage4, 0xf0); |
||||
|
ASSERT_REG_POSITION(texturing.tev_stage5, 0xf8); |
||||
|
ASSERT_REG_POSITION(texturing.tev_combiner_buffer_color, 0xfd); |
||||
|
|
||||
|
ASSERT_REG_POSITION(framebuffer, 0x100); |
||||
|
ASSERT_REG_POSITION(framebuffer.output_merger, 0x100); |
||||
|
ASSERT_REG_POSITION(framebuffer.framebuffer, 0x110); |
||||
|
|
||||
|
ASSERT_REG_POSITION(lighting, 0x140); |
||||
|
|
||||
|
ASSERT_REG_POSITION(pipeline, 0x200); |
||||
|
ASSERT_REG_POSITION(pipeline.vertex_attributes, 0x200); |
||||
|
ASSERT_REG_POSITION(pipeline.index_array, 0x227); |
||||
|
ASSERT_REG_POSITION(pipeline.num_vertices, 0x228); |
||||
|
ASSERT_REG_POSITION(pipeline.vertex_offset, 0x22a); |
||||
|
ASSERT_REG_POSITION(pipeline.trigger_draw, 0x22e); |
||||
|
ASSERT_REG_POSITION(pipeline.trigger_draw_indexed, 0x22f); |
||||
|
ASSERT_REG_POSITION(pipeline.vs_default_attributes_setup, 0x232); |
||||
|
ASSERT_REG_POSITION(pipeline.command_buffer, 0x238); |
||||
|
ASSERT_REG_POSITION(pipeline.gpu_mode, 0x245); |
||||
|
ASSERT_REG_POSITION(pipeline.triangle_topology, 0x25e); |
||||
|
ASSERT_REG_POSITION(pipeline.restart_primitive, 0x25f); |
||||
|
|
||||
|
ASSERT_REG_POSITION(gs, 0x280); |
||||
|
ASSERT_REG_POSITION(vs, 0x2b0); |
||||
|
|
||||
|
#undef ASSERT_REG_POSITION |
||||
|
#endif // !defined(_MSC_VER) |
||||
|
|
||||
|
// 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"); |
||||
|
|
||||
|
} // namespace Pica |
||||
@ -0,0 +1,284 @@ |
|||||
|
// Copyright 2017 Citra Emulator Project |
||||
|
// Licensed under GPLv2 or any later version |
||||
|
// Refer to the license.txt file included. |
||||
|
|
||||
|
#pragma once |
||||
|
|
||||
|
#include <array> |
||||
|
|
||||
|
#include "common/assert.h" |
||||
|
#include "common/bit_field.h" |
||||
|
#include "common/common_funcs.h" |
||||
|
#include "common/common_types.h" |
||||
|
#include "common/logging/log.h" |
||||
|
|
||||
|
namespace Pica { |
||||
|
|
||||
|
struct FramebufferRegs { |
||||
|
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, |
||||
|
}; |
||||
|
|
||||
|
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 PAddr GetColorBufferPhysicalAddress() const { |
||||
|
return color_buffer_address * 8; |
||||
|
} |
||||
|
inline PAddr GetDepthBufferPhysicalAddress() const { |
||||
|
return depth_buffer_address * 8; |
||||
|
} |
||||
|
|
||||
|
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); |
||||
|
}; |
||||
|
|
||||
|
static_assert(sizeof(FramebufferRegs) == 0x40 * sizeof(u32), |
||||
|
"FramebufferRegs struct has incorrect size"); |
||||
|
|
||||
|
} // namespace Pica |
||||
@ -0,0 +1,294 @@ |
|||||
|
// Copyright 2017 Citra Emulator Project |
||||
|
// Licensed under GPLv2 or any later version |
||||
|
// Refer to the license.txt file included. |
||||
|
|
||||
|
#pragma once |
||||
|
|
||||
|
#include <array> |
||||
|
|
||||
|
#include "common/assert.h" |
||||
|
#include "common/bit_field.h" |
||||
|
#include "common/common_funcs.h" |
||||
|
#include "common/common_types.h" |
||||
|
#include "common/vector_math.h" |
||||
|
|
||||
|
namespace Pica { |
||||
|
|
||||
|
struct LightingRegs { |
||||
|
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 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; |
||||
|
|
||||
|
INSERT_PADDING_WORDS(0x26); |
||||
|
}; |
||||
|
|
||||
|
static_assert(sizeof(LightingRegs) == 0xC0 * sizeof(u32), "LightingRegs struct has incorrect size"); |
||||
|
|
||||
|
} // namespace Pica |
||||
@ -0,0 +1,224 @@ |
|||||
|
// Copyright 2017 Citra Emulator Project |
||||
|
// Licensed under GPLv2 or any later version |
||||
|
// Refer to the license.txt file included. |
||||
|
|
||||
|
#pragma once |
||||
|
|
||||
|
#include <array> |
||||
|
|
||||
|
#include "common/assert.h" |
||||
|
#include "common/bit_field.h" |
||||
|
#include "common/common_funcs.h" |
||||
|
#include "common/common_types.h" |
||||
|
|
||||
|
namespace Pica { |
||||
|
|
||||
|
struct PipelineRegs { |
||||
|
enum class VertexAttributeFormat : u64 { |
||||
|
BYTE = 0, |
||||
|
UBYTE = 1, |
||||
|
SHORT = 2, |
||||
|
FLOAT = 3, |
||||
|
}; |
||||
|
|
||||
|
struct { |
||||
|
BitField<0, 29, u32> base_address; |
||||
|
|
||||
|
PAddr GetPhysicalBaseAddress() const { |
||||
|
return base_address * 8; |
||||
|
} |
||||
|
|
||||
|
// 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); |
||||
|
}; |
||||
|
|
||||
|
static_assert(sizeof(PipelineRegs) == 0x80 * sizeof(u32), "PipelineRegs struct has incorrect size"); |
||||
|
|
||||
|
} // namespace Pica |
||||
@ -0,0 +1,129 @@ |
|||||
|
// Copyright 2017 Citra Emulator Project |
||||
|
// Licensed under GPLv2 or any later version |
||||
|
// Refer to the license.txt file included. |
||||
|
|
||||
|
#pragma once |
||||
|
|
||||
|
#include <array> |
||||
|
|
||||
|
#include "common/bit_field.h" |
||||
|
#include "common/common_funcs.h" |
||||
|
#include "common/common_types.h" |
||||
|
|
||||
|
namespace Pica { |
||||
|
|
||||
|
struct RasterizerRegs { |
||||
|
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); |
||||
|
}; |
||||
|
|
||||
|
static_assert(sizeof(RasterizerRegs) == 0x40 * sizeof(u32), |
||||
|
"RasterizerRegs struct has incorrect size"); |
||||
|
|
||||
|
} // namespace Pica |
||||
@ -0,0 +1,104 @@ |
|||||
|
// Copyright 2017 Citra Emulator Project |
||||
|
// Licensed under GPLv2 or any later version |
||||
|
// Refer to the license.txt file included. |
||||
|
|
||||
|
#pragma once |
||||
|
|
||||
|
#include <array> |
||||
|
|
||||
|
#include "common/bit_field.h" |
||||
|
#include "common/common_funcs.h" |
||||
|
#include "common/common_types.h" |
||||
|
|
||||
|
namespace Pica { |
||||
|
|
||||
|
struct ShaderRegs { |
||||
|
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); |
||||
|
}; |
||||
|
|
||||
|
static_assert(sizeof(ShaderRegs) == 0x30 * sizeof(u32), "ShaderRegs struct has incorrect size"); |
||||
|
|
||||
|
} // namespace Pica |
||||
@ -0,0 +1,328 @@ |
|||||
|
// Copyright 2017 Citra Emulator Project |
||||
|
// Licensed under GPLv2 or any later version |
||||
|
// Refer to the license.txt file included. |
||||
|
|
||||
|
#pragma once |
||||
|
|
||||
|
#include <array> |
||||
|
|
||||
|
#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<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<TevStageConfig, 6> 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 |
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue