Extract functions on Command Processor

This commit is contained in:
Huw Pascoe 2017-09-21 21:13:47 +01:00
parent 6fc123d67c
commit f74f4e73b9
3 changed files with 1165 additions and 439 deletions

View File

@ -28,6 +28,7 @@ set(SRCS
) )
set(HEADERS set(HEADERS
command_map.h
command_processor.h command_processor.h
debug_utils/debug_utils.h debug_utils/debug_utils.h
geometry_pipeline.h geometry_pipeline.h

View File

@ -0,0 +1,810 @@
// Copyright 2014 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include "common/common_types.h"
namespace Pica {
namespace CommandProcessor {
struct Command;
static void nop(const Command&) {}
static void TriggerIRQ(const Command&);
static void TriangleTopology(const Command&);
static void RestartPrimitive(const Command&);
static void DefaultAttributes(const Command&);
static void GpuMode(const Command&);
static void TriggerCommandBuffer(const Command&);
static void TriggerDraw(const Command&);
static void DefaultAttribSetup(const Command&);
static void UniformBoolGs(const Command&);
static void UniformBoolVs(const Command&);
static void UniformIntGs(const Command&);
static void UniformIntVs(const Command&);
static void UniformFloatGs(const Command&);
static void UniformFloatVs(const Command&);
static void SetWordGs(const Command&);
static void SetWordVs(const Command&);
static void SetWordSwizzleGs(const Command&);
static void SetWordSwizzleVs(const Command&);
static void LightingLut(const Command&);
static void FogLut(const Command&);
static void ProcTexLut(const Command&);
using CommandAction = void (*)(const Command&);
static const CommandAction CommandMap[] = {
nop, // 0x000
nop, // 0x001
nop, // 0x002
nop, // 0x003
nop, // 0x004
nop, // 0x005
nop, // 0x006
nop, // 0x007
nop, // 0x008
nop, // 0x009
nop, // 0x00a
nop, // 0x00b
nop, // 0x00c
nop, // 0x00d
nop, // 0x00e
nop, // 0x00f
TriggerIRQ, // 0x010 FINALIZE PICA__INTERRUPT
nop, // 0x011
nop, // 0x012
nop, // 0x013
nop, // 0x014
nop, // 0x015
nop, // 0x016
nop, // 0x017
nop, // 0x018
nop, // 0x019
nop, // 0x01a
nop, // 0x01b
nop, // 0x01c
nop, // 0x01d
nop, // 0x01e
nop, // 0x01f
nop, // 0x020
nop, // 0x021
nop, // 0x022
nop, // 0x023
nop, // 0x024
nop, // 0x025
nop, // 0x026
nop, // 0x027
nop, // 0x028
nop, // 0x029
nop, // 0x02a
nop, // 0x02b
nop, // 0x02c
nop, // 0x02d
nop, // 0x02e
nop, // 0x02f
nop, // 0x030
nop, // 0x031
nop, // 0x032
nop, // 0x033
nop, // 0x034
nop, // 0x035
nop, // 0x036
nop, // 0x037
nop, // 0x038
nop, // 0x039
nop, // 0x03a
nop, // 0x03b
nop, // 0x03c
nop, // 0x03d
nop, // 0x03e
nop, // 0x03f
nop, // 0x040 CULLING_CONFIG PICA__CULL_FACE
nop, // 0x041 VIEWPORT_WIDTH PICA__VIEWPORT_WIDTH1
nop, // 0x042 VIEWPORT_INVW PICA__VIEWPORT_WIDTH2
nop, // 0x043 VIEWPORT_HEIGHT PICA__VIEWPORT_HEIGHT1
nop, // 0x044 VIEWPORT_INVH PICA__VIEWPORT_HEIGHT2
nop, // 0x045
nop, // 0x046
nop, // 0x047 FRAGOP_CLIP PICA__FRAGOP_CLIP
nop, // 0x048 FRAGOP_CLIP_DATA0 PICA__FRAGOP_CLIP_DATA1
nop, // 0x049 FRAGOP_CLIP_DATA1 PICA__FRAGOP_CLIP_DATA2
nop, // 0x04a FRAGOP_CLIP_DATA2 PICA__FRAGOP_CLIP_DATA3
nop, // 0x04b FRAGOP_CLIP_DATA3 PICA__FRAGOP_CLIP_DATA4
nop, // 0x04c
nop, // 0x04d DEPTHMAP_SCALE PICA__FRAGOP_WSCALE_DATA1
nop, // 0x04e DEPTHMAP_OFFSET PICA__FRAGOP_WSCALE_DATA2
nop, // 0x04f SH_OUTMAP_TOTAL PICA__GS_OUT__NUM0 / PICA__VS_OUT__NUM0
nop, // 0x050 SH_OUTMAP_O0 PICA__GS_OUT_ATTR0 / PICA__VS_OUT_ATTR0
nop, // 0x051 SH_OUTMAP_O1 PICA__GS_OUT_ATTR1 / PICA__VS_OUT_ATTR1
nop, // 0x052 SH_OUTMAP_O2 PICA__GS_OUT_ATTR2 / PICA__VS_OUT_ATTR2
nop, // 0x053 SH_OUTMAP_O3 PICA__GS_OUT_ATTR3 / PICA__VS_OUT_ATTR3
nop, // 0x054 SH_OUTMAP_O4 PICA__GS_OUT_ATTR4 / PICA__VS_OUT_ATTR4
nop, // 0x055 SH_OUTMAP_O5 PICA__GS_OUT_ATTR5 / PICA__VS_OUT_ATTR5
nop, // 0x056 SH_OUTMAP_O6 PICA__GS_OUT_ATTR6 / PICA__VS_OUT_ATTR6
nop, // 0x057
nop, // 0x058
nop, // 0x059
nop, // 0x05a
nop, // 0x05b
nop, // 0x05c
nop, // 0x05d
nop, // 0x05e
nop, // 0x05f
nop, // 0x060
nop, // 0x061 EARLYDEPTH_FUNC PICA__EARLY_DEPTH_FUNC
nop, // 0x062 EARLYDEPTH_TEST1 PICA__EARLY_DEPTH_TEST1
nop, // 0x063 EARLYDEPTH_CLEAR PICA__EARLY_DEPTH_CLEAR
nop, // 0x064 SH_OUTATTR_MODE PICA__GS_OUT_ATTR_MODE / PICA__VS_OUT_ATTR_MODE
nop, // 0x065 SCISSORTEST_MODE PICA__SCISSOR
nop, // 0x066 SCISSORTEST_POS PICA__SCISSOR_XY
nop, // 0x067 SCISSORTEST_DIM PICA__SCISSOR_SIZE
nop, // 0x068 VIEWPORT_XY PICA__VIEWPORT_XY
nop, // 0x069
nop, // 0x06a EARLYDEPTH_DATA PICA__EARLY_DEPTH_DATA
nop, // 0x06b
nop, // 0x06c
nop, // 0x06d DEPTHMAP_ENABLE PICA__FRAGOP_WSCALE
nop, // 0x06e RENDERBUF_DIM PICA__RENDER_BUF_RESOLUTION1
nop, // 0x06f SH_OUTATTR_CLOCK PICA__GS_OUT_ATTR_CLK / PICA__VS_OUT_ATTR_CLK
nop, // 0x070
nop, // 0x071
nop, // 0x072
nop, // 0x073
nop, // 0x074
nop, // 0x075
nop, // 0x076
nop, // 0x077
nop, // 0x078
nop, // 0x079
nop, // 0x07a
nop, // 0x07b
nop, // 0x07c
nop, // 0x07d
nop, // 0x07e
nop, // 0x07f
nop, // 0x080 TEXUNIT_CONFIG PICA__TEXTURE_FUNC
nop, // 0x081 TEXUNIT0_BORDER_COLOR PICA__TEXTURE0_BORDER_COLOR
nop, // 0x082 TEXUNIT0_DIM PICA__TEXTURE0_SIZE
nop, // 0x083 TEXUNIT0_PARAM PICA__TEXTURE0_WRAP_FILTER
nop, // 0x084 TEXUNIT0_LOD PICA__TEXTURE0_LOD
nop, // 0x085 TEXUNIT0_ADDR1 PICA__TEXTURE0_ADDR1
nop, // 0x086 TEXUNIT0_ADDR2 PICA__TEXTURE0_ADDR2
nop, // 0x087 TEXUNIT0_ADDR3 PICA__TEXTURE0_ADDR3
nop, // 0x088 TEXUNIT0_ADDR4 PICA__TEXTURE0_ADDR4
nop, // 0x089 TEXUNIT0_ADDR5 PICA__TEXTURE0_ADDR5
nop, // 0x08a TEXUNIT0_ADDR6 PICA__TEXTURE0_ADDR6
nop, // 0x08b TEXUNIT0_SHADOW PICA__TEXTURE0_SHADOW
nop, // 0x08c
nop, // 0x08d
nop, // 0x08e TEXUNIT0_TYPE PICA__TEXTURE0_FORMAT
nop, // 0x08f LIGHTING_ENABLE0 PICA__FRAG_LIGHT_EN0
nop, // 0x090
nop, // 0x091 TEXUNIT1_BORDER_COLOR PICA__TEXTURE1_BORDER_COLOR
nop, // 0x092 TEXUNIT1_DIM PICA__TEXTURE1_SIZE
nop, // 0x093 TEXUNIT1_PARAM PICA__TEXTURE1_WRAP_FILTER
nop, // 0x094 TEXUNIT1_LOD PICA__TEXTURE1_LOD
nop, // 0x095 TEXUNIT1_ADDR PICA__TEXTURE1_ADDR
nop, // 0x096 TEXUNIT1_TYPE PICA__TEXTURE1_FORMAT
nop, // 0x097
nop, // 0x098
nop, // 0x099 TEXUNIT2_BORDER_COLOR PICA__TEXTURE2_BORDER_COLOR
nop, // 0x09a TEXUNIT2_DIM PICA__TEXTURE2_SIZE
nop, // 0x09b TEXUNIT2_PARAM PICA__TEXTURE2_WRAP_FILTER
nop, // 0x09c TEXUNIT2_LOD PICA__TEXTURE2_LOD
nop, // 0x09d TEXUNIT2_ADDR PICA__TEXTURE2_ADDR
nop, // 0x09e TEXUNIT2_TYPE PICA__TEXTURE2_FORMAT
nop, // 0x09f
nop, // 0x0a0
nop, // 0x0a1
nop, // 0x0a2
nop, // 0x0a3
nop, // 0x0a4
nop, // 0x0a5
nop, // 0x0a6
nop, // 0x0a7
nop, // 0x0a8 TEXUNIT3_PROCTEX0 PICA__TEXTURE3_PROCTEX0
nop, // 0x0a9 TEXUNIT3_PROCTEX1 PICA__TEXTURE3_PROCTEX1
nop, // 0x0aa TEXUNIT3_PROCTEX2 PICA__TEXTURE3_PROCTEX2
nop, // 0x0ab TEXUNIT3_PROCTEX3 PICA__TEXTURE3_PROCTEX3
nop, // 0x0ac TEXUNIT3_PROCTEX4 PICA__TEXTURE3_PROCTEX4
nop, // 0x0ad TEXUNIT3_PROCTEX5 PICA__TEXTURE3_PROCTEX5
nop, // 0x0ae
nop, // 0x0af PROCTEX_LUT PICA__PROCTEX_LUT
ProcTexLut, // 0x0b0 PROCTEX_LUT_DATA0 PICA__PROCTEX_LUT_DATA0
ProcTexLut, // 0x0b1 PROCTEX_LUT_DATA1 PICA__PROCTEX_LUT_DATA1
ProcTexLut, // 0x0b2 PROCTEX_LUT_DATA2 PICA__PROCTEX_LUT_DATA2
ProcTexLut, // 0x0b3 PROCTEX_LUT_DATA3 PICA__PROCTEX_LUT_DATA3
ProcTexLut, // 0x0b4 PROCTEX_LUT_DATA4 PICA__PROCTEX_LUT_DATA4
ProcTexLut, // 0x0b5 PROCTEX_LUT_DATA5 PICA__PROCTEX_LUT_DATA5
ProcTexLut, // 0x0b6 PROCTEX_LUT_DATA6 PICA__PROCTEX_LUT_DATA6
ProcTexLut, // 0x0b7 PROCTEX_LUT_DATA7 PICA__PROCTEX_LUT_DATA7
nop, // 0x0b8
nop, // 0x0b9
nop, // 0x0ba
nop, // 0x0bb
nop, // 0x0bc
nop, // 0x0bd
nop, // 0x0be
nop, // 0x0bf
nop, // 0x0c0 TEXENV0_SOURCE PICA__TEX_ENV_0
nop, // 0x0c1 TEXENV0_OPERAND PICA__TEX_ENV_0_OPERAND
nop, // 0x0c2 TEXENV0_COMBINER PICA__TEX_ENV_0_COMBINE
nop, // 0x0c3 TEXENV0_COLOR PICA__TEX_ENV_0_COLOR
nop, // 0x0c4 TEXENV0_SCALE PICA__TEX_ENV_0_SCALE
nop, // 0x0c5
nop, // 0x0c6
nop, // 0x0c7
nop, // 0x0c8 TEXENV1_SOURCE PICA__TEX_ENV_1
nop, // 0x0c9 TEXENV1_OPERAND PICA__TEX_ENV_1_OPERAND
nop, // 0x0ca TEXENV1_COMBINER PICA__TEX_ENV_1_COMBINE
nop, // 0x0cb TEXENV1_COLOR PICA__TEX_ENV_1_COLOR
nop, // 0x0cc TEXENV1_SCALE PICA__TEX_ENV_1_SCALE
nop, // 0x0cd
nop, // 0x0ce
nop, // 0x0cf
nop, // 0x0d0 TEXENV2_SOURCE PICA__TEX_ENV_2
nop, // 0x0d1 TEXENV2_OPERAND PICA__TEX_ENV_2_OPERAND
nop, // 0x0d2 TEXENV2_COMBINER PICA__TEX_ENV_2_COMBINE
nop, // 0x0d3 TEXENV2_COLOR PICA__TEX_ENV_2_COLOR
nop, // 0x0d4 TEXENV2_SCALE PICA__TEX_ENV_2_SCALE
nop, // 0x0d5
nop, // 0x0d6
nop, // 0x0d7
nop, // 0x0d8 TEXENV3_SOURCE PICA__TEX_ENV_3
nop, // 0x0d9 TEXENV3_OPERAND PICA__TEX_ENV_3_OPERAND
nop, // 0x0da TEXENV3_COMBINER PICA__TEX_ENV_3_COMBINE
nop, // 0x0db TEXENV3_COLOR PICA__TEX_ENV_3_COLOR
nop, // 0x0dc TEXENV3_SCALE PICA__TEX_ENV_3_SCALE
nop, // 0x0dd
nop, // 0x0de
nop, // 0x0df
nop, // 0x0e0 TEXENV_UPDATE_BUFFER PICA__GAS_FOG_MODE / PICA__TEX_ENV_BUF_INPUT
nop, // 0x0e1 FOG_COLOR PICA__FOG_COLOR
nop, // 0x0e2
nop, // 0x0e3
nop, // 0x0e4 GAS_ATTENUATION PICA__GAS_ATTENUATION
nop, // 0x0e5 GAS_ACCMAX PICA__GAS_ACCMAX
nop, // 0x0e6 FOG_LUT_INDEX PICA__FOG_LUT_INDEX
nop, // 0x0e7
FogLut, // 0x0e8 FOG_LUT_DATA0 PICA__FOG_LUT_DATA0
FogLut, // 0x0e9 FOG_LUT_DATA1 PICA__FOG_LUT_DATA1
FogLut, // 0x0ea FOG_LUT_DATA2 PICA__FOG_LUT_DATA2
FogLut, // 0x0eb FOG_LUT_DATA3 PICA__FOG_LUT_DATA3
FogLut, // 0x0ec FOG_LUT_DATA4 PICA__FOG_LUT_DATA4
FogLut, // 0x0ed FOG_LUT_DATA5 PICA__FOG_LUT_DATA5
FogLut, // 0x0ee FOG_LUT_DATA6 PICA__FOG_LUT_DATA6
FogLut, // 0x0ef FOG_LUT_DATA7 PICA__FOG_LUT_DATA7
nop, // 0x0f0 TEXENV4_SOURCE PICA__TEX_ENV_4
nop, // 0x0f1 TEXENV4_OPERAND PICA__TEX_ENV_4_OPERAND
nop, // 0x0f2 TEXENV4_COMBINER PICA__TEX_ENV_4_COMBINE
nop, // 0x0f3 TEXENV4_COLOR PICA__TEX_ENV_4_COLOR
nop, // 0x0f4 TEXENV4_SCALE PICA__TEX_ENV_4_SCALE
nop, // 0x0f5
nop, // 0x0f6
nop, // 0x0f7
nop, // 0x0f8 TEXENV5_SOURCE PICA__TEX_ENV_5
nop, // 0x0f9 TEXENV5_OPERAND PICA__TEX_ENV_5_OPERAND
nop, // 0x0fa TEXENV5_COMBINER PICA__TEX_ENV_5_COMBINE
nop, // 0x0fb TEXENV5_COLOR PICA__TEX_ENV_5_COLOR
nop, // 0x0fc TEXENV5_SCALE PICA__TEX_ENV_5_SCALE
nop, // 0x0fd TEXENV_BUFFER_COLOR PICA__TEX_ENV_BUF_COLOR
nop, // 0x0fe
nop, // 0x0ff
nop, // 0x100 COLOR_OPERATION PICA__COLOR_OPERATION
nop, // 0x101 BLEND_FUNC PICA__BLEND_FUNC
nop, // 0x102 LOGIC_OP PICA__LOGIC_OP
nop, // 0x103 BLEND_COLOR PICA__BLEND_COLOR
nop, // 0x104 FRAGOP_ALPHA_TEST PICA__FRAGOP_ALPHA_TEST
nop, // 0x105 STENCIL_TEST PICA__STENCIL_TEST
nop, // 0x106 STENCIL_OP PICA__STENCIL_OP
nop, // 0x107 DEPTH_COLOR_MASK PICA__DEPTH_COLOR_MASK
nop, // 0x108
nop, // 0x109
nop, // 0x10a
nop, // 0x10b
nop, // 0x10c
nop, // 0x10d
nop, // 0x10e
nop, // 0x10f
nop, // 0x110 FRAMEBUFFER_INVALIDATE PICA__COLOR_BUFFER_CLEAR0
nop, // 0x111 FRAMEBUFFER_FLUSH PICA__COLOR_BUFFER_CLEAR1
nop, // 0x112 COLORBUFFER_READ PICA__COLOR_BUFFER_READ
nop, // 0x113 COLORBUFFER_WRITE PICA__COLOR_BUFFER_WRITE
nop, // 0x114 DEPTHBUFFER_READ PICA__DEPTH_STENCIL_READ
nop, // 0x115 DEPTHBUFFER_WRITE PICA__DEPTH_STENCIL_WRITE
nop, // 0x116 DEPTHBUFFER_FORMAT PICA__RENDER_BUF_DEPTH_MODE
nop, // 0x117 COLORBUFFER_FORMAT PICA__RENDER_BUF_COLOR_MODE
nop, // 0x118 EARLYDEPTH_TEST2 PICA__EARLY_DEPTH_TEST2
nop, // 0x119
nop, // 0x11a
nop, // 0x11b FRAMEBUFFER_BLOCK32 PICA__RENDER_BLOCK_FORMAT
nop, // 0x11c DEPTHBUFFER_LOC PICA__RENDER_BUF_DEPTH_ADDR
nop, // 0x11d COLORBUFFER_LOC PICA__RENDER_BUF_COLOR_ADDR
nop, // 0x11e FRAMEBUFFER_DIM PICA__RENDER_BUF_RESOLUTION0
nop, // 0x11f
nop, // 0x120 GAS_LIGHT_XY PICA__GAS_LIGHT_XY
nop, // 0x121 GAS_LIGHT_Z PICA__GAS_LIGHT_Z
nop, // 0x122 GAS_LIGHT_Z_COLOR PICA__GAS_LIGHT_Z_COLOR
nop, // 0x123 GAS_LUT_INDEX PICA__GAS_LUT_INDEX
nop, // 0x124 GAS_LUT_DATA PICA__GAS_LUT_DATA
nop, // 0x125
nop, // 0x126 GAS_DELTAZ_DEPTH PICA__GAS_DELTAZ_DEPTH
nop, // 0x127
nop, // 0x128
nop, // 0x129
nop, // 0x12a
nop, // 0x12b
nop, // 0x12c
nop, // 0x12d
nop, // 0x12e
nop, // 0x12f
nop, // 0x130 FRAGOP_SHADOW PICA__FRAGOP_SHADOW
nop, // 0x131
nop, // 0x132
nop, // 0x133
nop, // 0x134
nop, // 0x135
nop, // 0x136
nop, // 0x137
nop, // 0x138
nop, // 0x139
nop, // 0x13a
nop, // 0x13b
nop, // 0x13c
nop, // 0x13d
nop, // 0x13e
nop, // 0x13f
nop, // 0x140 LIGHT0_SPECULAR0 PICA__FRAG_LIGHT0_SPECULAR0 / PICA__FRAG_LIGHT_START
nop, // 0x141 LIGHT0_SPECULAR1 PICA__FRAG_LIGHT0_SPECULAR1
nop, // 0x142 LIGHT0_DIFFUSE PICA__FRAG_LIGHT0_DIFFUSE
nop, // 0x143 LIGHT0_AMBIENT PICA__FRAG_LIGHT0_AMBIENT
nop, // 0x144 LIGHT0_XY PICA__FRAG_LIGHT0_POSITION_XY
nop, // 0x145 LIGHT0_Z PICA__FRAG_LIGHT0_POSITION_Z
nop, // 0x146 LIGHT0_SPOTDIR_XY PICA__FRAG_LIGHT0_SPOT_XY
nop, // 0x147 LIGHT0_SPOTDIR_Z PICA__FRAG_LIGHT0_SPOT_Z
nop, // 0x148
nop, // 0x149 LIGHT0_CONFIG PICA__FRAG_LIGHT0_TYPE
nop, // 0x14a LIGHT0_ATTENUATION_BIAS PICA__FRAG_LIGHT0_DIST_ATTN_BIAS
nop, // 0x14b LIGHT0_ATTENUATION_SCALE PICA__FRAG_LIGHT0_DIST_ATTN_SCALE
nop, // 0x14c
nop, // 0x14d
nop, // 0x14e
nop, // 0x14f
nop, // 0x150 LIGHT1_SPECULAR0 PICA__FRAG_LIGHT1_SPECULAR0
nop, // 0x151 LIGHT1_SPECULAR1 PICA__FRAG_LIGHT1_SPECULAR1
nop, // 0x152 LIGHT1_DIFFUSE PICA__FRAG_LIGHT1_DIFFUSE
nop, // 0x153 LIGHT1_AMBIENT PICA__FRAG_LIGHT1_AMBIENT
nop, // 0x154 LIGHT1_XY PICA__FRAG_LIGHT1_POSITION_XY
nop, // 0x155 LIGHT1_Z PICA__FRAG_LIGHT1_POSITION_Z
nop, // 0x156 LIGHT1_SPOTDIR_XY PICA__FRAG_LIGHT1_SPOT_XY
nop, // 0x157 LIGHT1_SPOTDIR_Z PICA__FRAG_LIGHT1_SPOT_Z
nop, // 0x158
nop, // 0x159 LIGHT1_CONFIG PICA__FRAG_LIGHT1_TYPE
nop, // 0x15a LIGHT1_ATTENUATION_BIAS PICA__FRAG_LIGHT1_DIST_ATTN_BIAS
nop, // 0x15b LIGHT1_ATTENUATION_SCALE PICA__FRAG_LIGHT1_DIST_ATTN_SCALE
nop, // 0x15c
nop, // 0x15d
nop, // 0x15e
nop, // 0x15f
nop, // 0x160 LIGHT2_SPECULAR0 PICA__FRAG_LIGHT2_SPECULAR0
nop, // 0x161 LIGHT2_SPECULAR1 PICA__FRAG_LIGHT2_SPECULAR1
nop, // 0x162 LIGHT2_DIFFUSE PICA__FRAG_LIGHT2_DIFFUSE
nop, // 0x163 LIGHT2_AMBIENT PICA__FRAG_LIGHT2_AMBIENT
nop, // 0x164 LIGHT2_XY PICA__FRAG_LIGHT2_POSITION_XY
nop, // 0x165 LIGHT2_Z PICA__FRAG_LIGHT2_POSITION_Z
nop, // 0x166 LIGHT2_SPOTDIR_XY PICA__FRAG_LIGHT2_SPOT_XY
nop, // 0x167 LIGHT2_SPOTDIR_Z PICA__FRAG_LIGHT2_SPOT_Z
nop, // 0x168
nop, // 0x169 LIGHT2_CONFIG PICA__FRAG_LIGHT2_TYPE
nop, // 0x16a LIGHT2_ATTENUATION_BIAS PICA__FRAG_LIGHT2_DIST_ATTN_BIAS
nop, // 0x16b LIGHT2_ATTENUATION_SCALE PICA__FRAG_LIGHT2_DIST_ATTN_SCALE
nop, // 0x16c
nop, // 0x16d
nop, // 0x16e
nop, // 0x16f
nop, // 0x170 LIGHT3_SPECULAR0 PICA__FRAG_LIGHT3_SPECULAR0
nop, // 0x171 LIGHT3_SPECULAR1 PICA__FRAG_LIGHT3_SPECULAR1
nop, // 0x172 LIGHT3_DIFFUSE PICA__FRAG_LIGHT3_DIFFUSE
nop, // 0x173 LIGHT3_AMBIENT PICA__FRAG_LIGHT3_AMBIENT
nop, // 0x174 LIGHT3_XY PICA__FRAG_LIGHT3_POSITION_XY
nop, // 0x175 LIGHT3_Z PICA__FRAG_LIGHT3_POSITION_Z
nop, // 0x176 LIGHT3_SPOTDIR_XY PICA__FRAG_LIGHT3_SPOT_XY
nop, // 0x177 LIGHT3_SPOTDIR_Z PICA__FRAG_LIGHT3_SPOT_Z
nop, // 0x178
nop, // 0x179 LIGHT3_CONFIG PICA__FRAG_LIGHT3_TYPE
nop, // 0x17a LIGHT3_ATTENUATION_BIAS PICA__FRAG_LIGHT3_DIST_ATTN_BIAS
nop, // 0x17b LIGHT3_ATTENUATION_SCALE PICA__FRAG_LIGHT3_DIST_ATTN_SCALE
nop, // 0x17c
nop, // 0x17d
nop, // 0x17e
nop, // 0x17f
nop, // 0x180 LIGHT4_SPECULAR0 PICA__FRAG_LIGHT4_SPECULAR0
nop, // 0x181 LIGHT4_SPECULAR1 PICA__FRAG_LIGHT4_SPECULAR1
nop, // 0x182 LIGHT4_DIFFUSE PICA__FRAG_LIGHT4_DIFFUSE
nop, // 0x183 LIGHT4_AMBIENT PICA__FRAG_LIGHT4_AMBIENT
nop, // 0x184 LIGHT4_XY PICA__FRAG_LIGHT4_POSITION_XY
nop, // 0x185 LIGHT4_Z PICA__FRAG_LIGHT4_POSITION_Z
nop, // 0x186 LIGHT4_SPOTDIR_XY PICA__FRAG_LIGHT4_SPOT_XY
nop, // 0x187 LIGHT4_SPOTDIR_Z PICA__FRAG_LIGHT4_SPOT_Z
nop, // 0x188
nop, // 0x189 LIGHT4_CONFIG PICA__FRAG_LIGHT4_TYPE
nop, // 0x18a LIGHT4_ATTENUATION_BIAS PICA__FRAG_LIGHT4_DIST_ATTN_BIAS
nop, // 0x18b LIGHT4_ATTENUATION_SCALE PICA__FRAG_LIGHT4_DIST_ATTN_SCALE
nop, // 0x18c
nop, // 0x18d
nop, // 0x18e
nop, // 0x18f
nop, // 0x190 LIGHT5_SPECULAR0 PICA__FRAG_LIGHT5_SPECULAR0
nop, // 0x191 LIGHT5_SPECULAR1 PICA__FRAG_LIGHT5_SPECULAR1
nop, // 0x192 LIGHT5_DIFFUSE PICA__FRAG_LIGHT5_DIFFUSE
nop, // 0x193 LIGHT5_AMBIENT PICA__FRAG_LIGHT5_AMBIENT
nop, // 0x194 LIGHT5_XY PICA__FRAG_LIGHT5_POSITION_XY
nop, // 0x195 LIGHT5_Z PICA__FRAG_LIGHT5_POSITION_Z
nop, // 0x196 LIGHT5_SPOTDIR_XY PICA__FRAG_LIGHT5_SPOT_XY
nop, // 0x197 LIGHT5_SPOTDIR_Z PICA__FRAG_LIGHT5_SPOT_Z
nop, // 0x198
nop, // 0x199 LIGHT5_CONFIG PICA__FRAG_LIGHT5_TYPE
nop, // 0x19a LIGHT5_ATTENUATION_BIAS PICA__FRAG_LIGHT5_DIST_ATTN_BIAS
nop, // 0x19b LIGHT5_ATTENUATION_SCALE PICA__FRAG_LIGHT5_DIST_ATTN_SCALE
nop, // 0x19c
nop, // 0x19d
nop, // 0x19e
nop, // 0x19f
nop, // 0x1a0 LIGHT6_SPECULAR0 PICA__FRAG_LIGHT6_SPECULAR0
nop, // 0x1a1 LIGHT6_SPECULAR1 PICA__FRAG_LIGHT6_SPECULAR1
nop, // 0x1a2 LIGHT6_DIFFUSE PICA__FRAG_LIGHT6_DIFFUSE
nop, // 0x1a3 LIGHT6_AMBIENT PICA__FRAG_LIGHT6_AMBIENT
nop, // 0x1a4 LIGHT6_XY PICA__FRAG_LIGHT6_POSITION_XY
nop, // 0x1a5 LIGHT6_Z PICA__FRAG_LIGHT6_POSITION_Z
nop, // 0x1a6 LIGHT6_SPOTDIR_XY PICA__FRAG_LIGHT6_SPOT_XY
nop, // 0x1a7 LIGHT6_SPOTDIR_Z PICA__FRAG_LIGHT6_SPOT_Z
nop, // 0x1a8
nop, // 0x1a9 LIGHT6_CONFIG PICA__FRAG_LIGHT6_TYPE
nop, // 0x1aa LIGHT6_ATTENUATION_BIAS PICA__FRAG_LIGHT6_DIST_ATTN_BIAS
nop, // 0x1ab LIGHT6_ATTENUATION_SCALE PICA__FRAG_LIGHT6_DIST_ATTN_SCALE
nop, // 0x1ac
nop, // 0x1ad
nop, // 0x1ae
nop, // 0x1af
nop, // 0x1b0 LIGHT7_SPECULAR0 PICA__FRAG_LIGHT7_SPECULAR0
nop, // 0x1b1 LIGHT7_SPECULAR1 PICA__FRAG_LIGHT7_SPECULAR1
nop, // 0x1b2 LIGHT7_DIFFUSE PICA__FRAG_LIGHT7_DIFFUSE
nop, // 0x1b3 LIGHT7_AMBIENT PICA__FRAG_LIGHT7_AMBIENT
nop, // 0x1b4 LIGHT7_XY PICA__FRAG_LIGHT7_POSITION_XY
nop, // 0x1b5 LIGHT7_Z PICA__FRAG_LIGHT7_POSITION_Z
nop, // 0x1b6 LIGHT7_SPOTDIR_XY PICA__FRAG_LIGHT7_SPOT_XY
nop, // 0x1b7 LIGHT7_SPOTDIR_Z PICA__FRAG_LIGHT7_SPOT_Z
nop, // 0x1b8
nop, // 0x1b9 LIGHT7_CONFIG PICA__FRAG_LIGHT7_TYPE
nop, // 0x1ba LIGHT7_ATTENUATION_BIAS PICA__FRAG_LIGHT7_DIST_ATTN_BIAS
nop, // 0x1bb LIGHT7_ATTENUATION_SCALE PICA__FRAG_LIGHT7_DIST_ATTN_SCALE
nop, // 0x1bc
nop, // 0x1bd
nop, // 0x1be
nop, // 0x1bf
nop, // 0x1c0 LIGHTING_AMBIENT PICA__FRAG_LIGHT_AMBIENT
nop, // 0x1c1
nop, // 0x1c2 LIGHTING_NUM_LIGHTS PICA__FRAG_LIGHT_SRC_NUM
nop, // 0x1c3 LIGHTING_CONFIG0 PICA__FRAG_LIGHT_FUNC_MODE0
nop, // 0x1c4 LIGHTING_CONFIG1 PICA__FRAG_LIGHT_FUNC_MODE1
nop, // 0x1c5 LIGHTING_LUT_INDEX PICA__FRAG_LIGHT_LUT
nop, // 0x1c6 LIGHTING_ENABLE1 PICA__FRAG_LIGHT_EN1
nop, // 0x1c7
LightingLut, // 0x1c8 LIGHTING_LUT_DATA0 PICA__FRAG_LIGHT_LUT_DATA0
LightingLut, // 0x1c9 LIGHTING_LUT_DATA1 PICA__FRAG_LIGHT_LUT_DATA1
LightingLut, // 0x1ca LIGHTING_LUT_DATA2 PICA__FRAG_LIGHT_LUT_DATA2
LightingLut, // 0x1cb LIGHTING_LUT_DATA3 PICA__FRAG_LIGHT_LUT_DATA3
LightingLut, // 0x1cc LIGHTING_LUT_DATA4 PICA__FRAG_LIGHT_LUT_DATA4
LightingLut, // 0x1cd LIGHTING_LUT_DATA5 PICA__FRAG_LIGHT_LUT_DATA5
LightingLut, // 0x1ce LIGHTING_LUT_DATA6 PICA__FRAG_LIGHT_LUT_DATA6
LightingLut, // 0x1cf LIGHTING_LUT_DATA7 PICA__FRAG_LIGHT_LUT_DATA7
nop, // 0x1d0 LIGHTING_LUTINPUT_ABS PICA__FRAG_LIGHT_ABSLUTINPUT
nop, // 0x1d1 LIGHTING_LUTINPUT_SELECT PICA__FRAG_LIGHT_LUTINPUT
nop, // 0x1d2 LIGHTING_LUTINPUT_SCALE PICA__FRAG_LIGHT_LUTSCALE
nop, // 0x1d3
nop, // 0x1d4
nop, // 0x1d5
nop, // 0x1d6
nop, // 0x1d7
nop, // 0x1d8
nop, // 0x1d9 LIGHTING_LIGHT_PERMUTATION PICA__FRAG_LIGHT_SRC_EN_ID
nop, // 0x1da
nop, // 0x1db
nop, // 0x1dc
nop, // 0x1dd
nop, // 0x1de
nop, // 0x1df
nop, // 0x1e0
nop, // 0x1e1
nop, // 0x1e2
nop, // 0x1e3
nop, // 0x1e4
nop, // 0x1e5
nop, // 0x1e6
nop, // 0x1e7
nop, // 0x1e8
nop, // 0x1e9
nop, // 0x1ea
nop, // 0x1eb
nop, // 0x1ec
nop, // 0x1ed
nop, // 0x1ee
nop, // 0x1ef
nop, // 0x1f0
nop, // 0x1f1
nop, // 0x1f2
nop, // 0x1f3
nop, // 0x1f4
nop, // 0x1f5
nop, // 0x1f6
nop, // 0x1f7
nop, // 0x1f8
nop, // 0x1f9
nop, // 0x1fa
nop, // 0x1fb
nop, // 0x1fc
nop, // 0x1fd
nop, // 0x1fe
nop, // 0x1ff
nop, // 0x200 ATTRIBBUFFERS_LOC PICA__VTX_ATTR_ARRAYS_BASE_ADDR
nop, // 0x201 ATTRIBBUFFERS_FORMAT_LOW PICA__VTX_ATTR_ARRAYS0
nop, // 0x202 ATTRIBBUFFERS_FORMAT_HIGH PICA__VTX_ATTR_ARRAYS1
nop, // 0x203 ATTRIBBUFFER0_OFFSET PICA__LOAD_ARRAY0_ATTR_OFFSET
nop, // 0x204 ATTRIBBUFFER0_CONFIG1 PICA__LOAD_ARRAY0_ELEMENT0
nop, // 0x205 ATTRIBBUFFER0_CONFIG2 PICA__LOAD_ARRAY0_ELEMENT1
nop, // 0x206 ATTRIBBUFFER1_OFFSET
nop, // 0x207 ATTRIBBUFFER1_CONFIG1
nop, // 0x208 ATTRIBBUFFER1_CONFIG2
nop, // 0x209 ATTRIBBUFFER2_OFFSET
nop, // 0x20a ATTRIBBUFFER2_CONFIG1
nop, // 0x20b ATTRIBBUFFER2_CONFIG2
nop, // 0x20c ATTRIBBUFFER3_OFFSET
nop, // 0x20d ATTRIBBUFFER3_CONFIG1
nop, // 0x20e ATTRIBBUFFER3_CONFIG2
nop, // 0x20f ATTRIBBUFFER4_OFFSET
nop, // 0x210 ATTRIBBUFFER4_CONFIG1
nop, // 0x211 ATTRIBBUFFER4_CONFIG2
nop, // 0x212 ATTRIBBUFFER5_OFFSET
nop, // 0x213 ATTRIBBUFFER5_CONFIG1
nop, // 0x214 ATTRIBBUFFER5_CONFIG2
nop, // 0x215 ATTRIBBUFFER6_OFFSET
nop, // 0x216 ATTRIBBUFFER6_CONFIG1
nop, // 0x217 ATTRIBBUFFER6_CONFIG2
nop, // 0x218 ATTRIBBUFFER7_OFFSET
nop, // 0x219 ATTRIBBUFFER7_CONFIG1
nop, // 0x21a ATTRIBBUFFER7_CONFIG2
nop, // 0x21b ATTRIBBUFFER8_OFFSET
nop, // 0x21c ATTRIBBUFFER8_CONFIG1
nop, // 0x21d ATTRIBBUFFER8_CONFIG2
nop, // 0x21e ATTRIBBUFFER9_OFFSET
nop, // 0x21f ATTRIBBUFFER9_CONFIG1
nop, // 0x220 ATTRIBBUFFER9_CONFIG2
nop, // 0x221 ATTRIBBUFFER10_OFFSET
nop, // 0x222 ATTRIBBUFFER10_CONFIG1
nop, // 0x223 ATTRIBBUFFER10_CONFIG2
nop, // 0x224 ATTRIBBUFFER11_OFFSET
nop, // 0x225 ATTRIBBUFFER11_CONFIG1
nop, // 0x226 ATTRIBBUFFER11_CONFIG2
nop, // 0x227 INDEXBUFFER_CONFIG PICA__INDEX_ARRAY_ADDR_OFFSET
nop, // 0x228 NUMVERTICES PICA__DRAW_VERTEX_NUM
nop, // 0x229 GEOSTAGE_CONFIG PICA__DRAW_MODE0
nop, // 0x22a VERTEX_OFFSET PICA__DRAW_VERTEX_OFFSET
nop, // 0x22b
nop, // 0x22c
nop, // 0x22d POST_VERTEX_CACHE_NUM PICA__POST_VERTEX_CACHE_NUM
TriggerDraw, // 0x22e DRAWARRAYS PICA__START_DRAW_ARRAY
TriggerDraw, // 0x22f DRAWELEMENTS PICA__START_DRAW_ELEMENT
nop, // 0x230
nop, // 0x231 VTX_FUNC PICA__VTX_FUNC
DefaultAttributes, // 0x232 FIXEDATTRIB_INDEX PICA__VS_FIXED_ATTR
DefaultAttribSetup, // 0x233 FIXEDATTRIB_DATA0 PICA__VS_FIXED_ATTR_DATA0
DefaultAttribSetup, // 0x234 FIXEDATTRIB_DATA1 PICA__VS_FIXED_ATTR_DATA1
DefaultAttribSetup, // 0x235 FIXEDATTRIB_DATA2 PICA__VS_FIXED_ATTR_DATA2
nop, // 0x236
nop, // 0x237
nop, // 0x238 CMDBUF_SIZE0 PICA__COMMAND_BUF_SIZE_CH0
nop, // 0x239 CMDBUF_SIZE1 PICA__COMMAND_BUF_SIZE_CH1
nop, // 0x23a CMDBUF_ADDR0 PICA__COMMAND_BUF_ADDR_CH0
nop, // 0x23b CMDBUF_ADDR1 PICA__COMMAND_BUF_ADDR_CH1
TriggerCommandBuffer, // 0x23c CMDBUF_JUMP0 PICA__COMMAND_BUF_KICK_CH0
TriggerCommandBuffer, // 0x23d CMDBUF_JUMP1 PICA__COMMAND_BUF_KICK_CH1
nop, // 0x23e
nop, // 0x23f
nop, // 0x240
nop, // 0x241
nop, // 0x242 VSH_NUM_ATTR PICA__VS_ATTR_NUM1
nop, // 0x243
nop, // 0x244 VSH_COM_MODE PICA__VS_COM_MODE
GpuMode, // 0x245 START_DRAW_FUNC0 PICA__START_DRAW_FUNC0
nop, // 0x246
nop, // 0x247
nop, // 0x248
nop, // 0x249
nop, // 0x24a VSH_OUTMAP_TOTAL1 PICA__VS_OUT__NUM1
nop, // 0x24b
nop, // 0x24c
nop, // 0x24d
nop, // 0x24e
nop, // 0x24f
nop, // 0x250
nop, // 0x251 VSH_OUTMAP_TOTAL2 PICA__VS_OUT__NUM2
nop, // 0x252 GSH_MISC0 PICA__GS_MISC_0
nop, // 0x253 GEOSTAGE_CONFIG2 PICA__DRAW_MODE1
nop, // 0x254 GSH_MISC1 PICA__GS_MISC_1
nop, // 0x255
nop, // 0x256
nop, // 0x257
nop, // 0x258
nop, // 0x259
nop, // 0x25a
nop, // 0x25b
nop, // 0x25c
nop, // 0x25d
TriangleTopology, // 0x25e PRIMITIVE_CONFIG
RestartPrimitive, // 0x25f RESTART_PRIMITIVE PICA__START_DRAW_FUNC1
nop, // 0x260
nop, // 0x261
nop, // 0x262
nop, // 0x263
nop, // 0x264
nop, // 0x265
nop, // 0x266
nop, // 0x267
nop, // 0x268
nop, // 0x269
nop, // 0x26a
nop, // 0x26b
nop, // 0x26c
nop, // 0x26d
nop, // 0x26e
nop, // 0x26f
nop, // 0x270
nop, // 0x271
nop, // 0x272
nop, // 0x273
nop, // 0x274
nop, // 0x275
nop, // 0x276
nop, // 0x277
nop, // 0x278
nop, // 0x279
nop, // 0x27a
nop, // 0x27b
nop, // 0x27c
nop, // 0x27d
nop, // 0x27e
nop, // 0x27f
UniformBoolGs, // 0x280 GSH_BOOLUNIFORM PICA__GS_BOOL
UniformIntGs, // 0x281 GSH_INTUNIFORM_I0 PICA__GS_INT0
UniformIntGs, // 0x282 GSH_INTUNIFORM_I1 PICA__GS_INT1
UniformIntGs, // 0x283 GSH_INTUNIFORM_I2 PICA__GS_INT2
UniformIntGs, // 0x284 GSH_INTUNIFORM_I3 PICA__GS_INT3
nop, // 0x285
nop, // 0x286
nop, // 0x287
nop, // 0x288
nop, // 0x289 GSH_INPUTBUFFER_CONFIG PICA__GS_ATTR_NUM
nop, // 0x28a GSH_ENTRYPOINT PICA__GS_START_ADDR
nop, // 0x28b GSH_ATTRIBUTES_PERMUTATION_LOW PICA__GS_ATTR_IN__MAP0
nop, // 0x28c GSH_ATTRIBUTES_PERMUTATION_HIGH PICA__GS_ATTR_IN__MAP1
nop, // 0x28d GSH_OUTMAP_MASK PICA__GS_OUT__MASK
nop, // 0x28e
nop, // 0x28f GSH_CODETRANSFER_END PICA__GS_PROG_RENEWAL_END
nop, // 0x290 GSH_FLOATUNIFORM_INDEX PICA__GS_FLOAT_ADDR
UniformFloatGs, // 0x291 GSH_FLOATUNIFORM_DATA0 PICA__GS_FLOAT_DATA0
UniformFloatGs, // 0x292 GSH_FLOATUNIFORM_DATA1 PICA__GS_FLOAT_DATA1
UniformFloatGs, // 0x293 GSH_FLOATUNIFORM_DATA2 PICA__GS_FLOAT_DATA2
UniformFloatGs, // 0x294 GSH_FLOATUNIFORM_DATA3 PICA__GS_FLOAT_DATA3
UniformFloatGs, // 0x295 GSH_FLOATUNIFORM_DATA4 PICA__GS_FLOAT_DATA4
UniformFloatGs, // 0x296 GSH_FLOATUNIFORM_DATA5 PICA__GS_FLOAT_DATA5
UniformFloatGs, // 0x297 GSH_FLOATUNIFORM_DATA6 PICA__GS_FLOAT_DATA6
UniformFloatGs, // 0x298 GSH_FLOATUNIFORM_DATA7 PICA__GS_FLOAT_DATA7
nop, // 0x299
nop, // 0x29a
nop, // 0x29b GSH_CODETRANSFER_INDEX PICA__GS_PROG_ADDR
SetWordGs, // 0x29c GSH_CODETRANSFER_DATA0 PICA__GS_PROG_DATA0
SetWordGs, // 0x29d GSH_CODETRANSFER_DATA1 PICA__GS_PROG_DATA1
SetWordGs, // 0x29e GSH_CODETRANSFER_DATA2 PICA__GS_PROG_DATA2
SetWordGs, // 0x29f GSH_CODETRANSFER_DATA3 PICA__GS_PROG_DATA3
SetWordGs, // 0x2a0 GSH_CODETRANSFER_DATA4 PICA__GS_PROG_DATA4
SetWordGs, // 0x2a1 GSH_CODETRANSFER_DATA5 PICA__GS_PROG_DATA5
SetWordGs, // 0x2a2 GSH_CODETRANSFER_DATA6 PICA__GS_PROG_DATA6
SetWordGs, // 0x2a3 GSH_CODETRANSFER_DATA7 PICA__GS_PROG_DATA7
nop, // 0x2a4
nop, // 0x2a5 GSH_OPDESCS_INDEX PICA__GS_PROG_SWIZZLE_ADDR
SetWordSwizzleGs, // 0x2a6 GSH_OPDESCS_DATA0 PICA__GS_PROG_SWIZZLE_DATA0
SetWordSwizzleGs, // 0x2a7 GSH_OPDESCS_DATA1 PICA__GS_PROG_SWIZZLE_DATA1
SetWordSwizzleGs, // 0x2a8 GSH_OPDESCS_DATA2 PICA__GS_PROG_SWIZZLE_DATA2
SetWordSwizzleGs, // 0x2a9 GSH_OPDESCS_DATA3 PICA__GS_PROG_SWIZZLE_DATA3
SetWordSwizzleGs, // 0x2aa GSH_OPDESCS_DATA4 PICA__GS_PROG_SWIZZLE_DATA4
SetWordSwizzleGs, // 0x2ab GSH_OPDESCS_DATA5 PICA__GS_PROG_SWIZZLE_DATA5
SetWordSwizzleGs, // 0x2ac GSH_OPDESCS_DATA6 PICA__GS_PROG_SWIZZLE_DATA6
SetWordSwizzleGs, // 0x2ad GSH_OPDESCS_DATA7 PICA__GS_PROG_SWIZZLE_DATA7
nop, // 0x2ae
nop, // 0x2af
UniformBoolVs, // 0x2b0 VSH_BOOLUNIFORM PICA__VS_BOOL
UniformIntVs, // 0x2b1 VSH_INTUNIFORM_I0 PICA__VS_INT0
UniformIntVs, // 0x2b2 VSH_INTUNIFORM_I1 PICA__VS_INT1
UniformIntVs, // 0x2b3 VSH_INTUNIFORM_I2 PICA__VS_INT2
UniformIntVs, // 0x2b4 VSH_INTUNIFORM_I3 PICA__VS_INT3
nop, // 0x2b5
nop, // 0x2b6
nop, // 0x2b7
nop, // 0x2b8
nop, // 0x2b9 VSH_INPUTBUFFER_CONFIG PICA__VS_ATTR_NUM0
nop, // 0x2ba VSH_ENTRYPOINT PICA__VS_START_ADDR
nop, // 0x2bb VSH_ATTRIBUTES_PERMUTATION_LOW PICA__VS_ATTR_IN__MAP0
nop, // 0x2bc VSH_ATTRIBUTES_PERMUTATION_HIGH PICA__VS_ATTR_IN__MAP1
nop, // 0x2bd VSH_OUTMAP_MASK PICA__VS_OUT__MASK
nop, // 0x2be
nop, // 0x2bf VSH_CODETRANSFER_END PICA__VS_PROG_RENEWAL_END
nop, // 0x2c0 VSH_FLOATUNIFORM_INDEX PICA__VS_FLOAT_ADDR
UniformFloatVs, // 0x2c1 VSH_FLOATUNIFORM_DATA0 PICA__VS_FLOAT_DATA0
UniformFloatVs, // 0x2c2 VSH_FLOATUNIFORM_DATA1 PICA__VS_FLOAT_DATA1
UniformFloatVs, // 0x2c3 VSH_FLOATUNIFORM_DATA2 PICA__VS_FLOAT_DATA2
UniformFloatVs, // 0x2c4 VSH_FLOATUNIFORM_DATA3 PICA__VS_FLOAT_DATA3
UniformFloatVs, // 0x2c5 VSH_FLOATUNIFORM_DATA4 PICA__VS_FLOAT_DATA4
UniformFloatVs, // 0x2c6 VSH_FLOATUNIFORM_DATA5 PICA__VS_FLOAT_DATA5
UniformFloatVs, // 0x2c7 VSH_FLOATUNIFORM_DATA6 PICA__VS_FLOAT_DATA6
UniformFloatVs, // 0x2c8 VSH_FLOATUNIFORM_DATA7 PICA__VS_FLOAT_DATA7
nop, // 0x2c9
nop, // 0x2ca
nop, // 0x2cb VSH_CODETRANSFER_INDEX PICA__VS_PROG_ADDR
SetWordVs, // 0x2cc VSH_CODETRANSFER_DATA0 PICA__VS_PROG_DATA0
SetWordVs, // 0x2cd VSH_CODETRANSFER_DATA1 PICA__VS_PROG_DATA1
SetWordVs, // 0x2ce VSH_CODETRANSFER_DATA2 PICA__VS_PROG_DATA2
SetWordVs, // 0x2cf VSH_CODETRANSFER_DATA3 PICA__VS_PROG_DATA3
SetWordVs, // 0x2d0 VSH_CODETRANSFER_DATA4 PICA__VS_PROG_DATA4
SetWordVs, // 0x2d1 VSH_CODETRANSFER_DATA5 PICA__VS_PROG_DATA5
SetWordVs, // 0x2d2 VSH_CODETRANSFER_DATA6 PICA__VS_PROG_DATA6
SetWordVs, // 0x2d3 VSH_CODETRANSFER_DATA7 PICA__VS_PROG_DATA7
nop, // 0x2d4
nop, // 0x2d5 VSH_OPDESCS_INDEX PICA__VS_PROG_SWIZZLE_ADDR
SetWordSwizzleVs, // 0x2d6 VSH_OPDESCS_DATA0 PICA__VS_PROG_SWIZZLE_DATA0
SetWordSwizzleVs, // 0x2d7 VSH_OPDESCS_DATA1 PICA__VS_PROG_SWIZZLE_DATA1
SetWordSwizzleVs, // 0x2d8 VSH_OPDESCS_DATA2 PICA__VS_PROG_SWIZZLE_DATA2
SetWordSwizzleVs, // 0x2d9 VSH_OPDESCS_DATA3 PICA__VS_PROG_SWIZZLE_DATA3
SetWordSwizzleVs, // 0x2da VSH_OPDESCS_DATA4 PICA__VS_PROG_SWIZZLE_DATA4
SetWordSwizzleVs, // 0x2db VSH_OPDESCS_DATA5 PICA__VS_PROG_SWIZZLE_DATA5
SetWordSwizzleVs, // 0x2dc VSH_OPDESCS_DATA6 PICA__VS_PROG_SWIZZLE_DATA6
SetWordSwizzleVs, // 0x2dd VSH_OPDESCS_DATA7 PICA__VS_PROG_SWIZZLE_DATA7
nop, // 0x2de
nop, // 0x2df
nop, // 0x2e0
nop, // 0x2e1
nop, // 0x2e2
nop, // 0x2e3
nop, // 0x2e4
nop, // 0x2e5
nop, // 0x2e6
nop, // 0x2e7
nop, // 0x2e8
nop, // 0x2e9
nop, // 0x2ea
nop, // 0x2eb
nop, // 0x2ec
nop, // 0x2ed
nop, // 0x2ee
nop, // 0x2ef
nop, // 0x2f0
nop, // 0x2f1
nop, // 0x2f2
nop, // 0x2f3
nop, // 0x2f4
nop, // 0x2f5
nop, // 0x2f6
nop, // 0x2f7
nop, // 0x2f8
nop, // 0x2f9
nop, // 0x2fa
nop, // 0x2fb
nop, // 0x2fc
nop, // 0x2fd
nop, // 0x2fe
nop // 0x2ff
};
} // namespace CommandProcessor
} // namespace Pica

View File

@ -14,6 +14,7 @@
#include "core/hw/gpu.h" #include "core/hw/gpu.h"
#include "core/memory.h" #include "core/memory.h"
#include "core/tracer/recorder.h" #include "core/tracer/recorder.h"
#include "video_core/command_map.h"
#include "video_core/command_processor.h" #include "video_core/command_processor.h"
#include "video_core/debug_utils/debug_utils.h" #include "video_core/debug_utils/debug_utils.h"
#include "video_core/pica_state.h" #include "video_core/pica_state.h"
@ -47,6 +48,12 @@ static const u32 expand_bits_to_bytes[] = {
0xff000000, 0xff0000ff, 0xff00ff00, 0xff00ffff, 0xffff0000, 0xffff00ff, 0xffffff00, 0xffffffff, 0xff000000, 0xff0000ff, 0xff00ff00, 0xff00ffff, 0xffff0000, 0xffff00ff, 0xffffff00, 0xffffffff,
}; };
struct Command {
const u32 ID;
const u32 Value;
const u32 Mask;
};
MICROPROFILE_DEFINE(GPU_Drawing, "GPU", "Drawing", MP_RGB(50, 50, 240)); MICROPROFILE_DEFINE(GPU_Drawing, "GPU", "Drawing", MP_RGB(50, 50, 240));
static const char* GetShaderSetupTypeName(Shader::ShaderSetup& setup) { static const char* GetShaderSetupTypeName(Shader::ShaderSetup& setup) {
@ -119,59 +126,173 @@ static void WriteUniformFloatReg(ShaderRegs& config, Shader::ShaderSetup& setup,
} }
} }
static void WritePicaReg(u32 id, u32 value, u32 mask) { static void TriggerIRQ(const Command&) {
auto& regs = g_state.regs;
if (id >= Regs::NUM_REGS) {
LOG_ERROR(HW_GPU,
"Commandlist tried to write to invalid register 0x%03X (value: %08X, mask: %X)",
id, value, mask);
return;
}
// TODO: Figure out how register masking acts on e.g. vs.uniform_setup.set_value
u32 old_value = regs.reg_array[id];
const u32 write_mask = expand_bits_to_bytes[mask];
regs.reg_array[id] = (old_value & ~write_mask) | (value & write_mask);
// Double check for is_pica_tracing to avoid call overhead
if (DebugUtils::IsPicaTracing()) {
DebugUtils::OnPicaRegWrite({(u16)id, (u16)mask, regs.reg_array[id]});
}
if (g_debug_context)
g_debug_context->OnEvent(DebugContext::Event::PicaCommandLoaded,
reinterpret_cast<void*>(&id));
switch (id) {
// Trigger IRQ
case PICA_REG_INDEX(trigger_irq):
Service::GSP::SignalInterrupt(Service::GSP::InterruptId::P3D); Service::GSP::SignalInterrupt(Service::GSP::InterruptId::P3D);
break; }
case PICA_REG_INDEX(pipeline.triangle_topology): static void TriangleTopology(const Command&) {
g_state.primitive_assembler.Reconfigure(regs.pipeline.triangle_topology); g_state.primitive_assembler.Reconfigure(g_state.regs.pipeline.triangle_topology);
break; }
case PICA_REG_INDEX(pipeline.restart_primitive): static void RestartPrimitive(const Command&) {
g_state.primitive_assembler.Reset(); g_state.primitive_assembler.Reset();
break; }
case PICA_REG_INDEX(pipeline.vs_default_attributes_setup.index): static void DefaultAttributes(const Command&) {
g_state.immediate.current_attribute = 0; g_state.immediate.current_attribute = 0;
g_state.immediate.reset_geometry_pipeline = true; g_state.immediate.reset_geometry_pipeline = true;
default_attr_counter = 0; default_attr_counter = 0;
break; }
// Load default vertex input attributes static void GpuMode(const Command&) {
case PICA_REG_INDEX_WORKAROUND(pipeline.vs_default_attributes_setup.set_value[0], 0x233): if (g_state.regs.pipeline.gpu_mode == PipelineRegs::GPUMode::Configuring) {
case PICA_REG_INDEX_WORKAROUND(pipeline.vs_default_attributes_setup.set_value[1], 0x234): MICROPROFILE_SCOPE(GPU_Drawing);
case PICA_REG_INDEX_WORKAROUND(pipeline.vs_default_attributes_setup.set_value[2], 0x235): {
// Draw immediate mode triangles when GPU Mode is set to GPUMode::Configuring
VideoCore::g_renderer->Rasterizer()->DrawTriangles();
if (g_debug_context) {
g_debug_context->OnEvent(DebugContext::Event::FinishedPrimitiveBatch, nullptr);
}
}
}
static void TriggerCommandBuffer(const Command& cmd) {
unsigned index =
static_cast<unsigned>(cmd.ID - PICA_REG_INDEX(pipeline.command_buffer.trigger[0]));
u32* head_ptr = (u32*)Memory::GetPhysicalPointer(
g_state.regs.pipeline.command_buffer.GetPhysicalAddress(index));
g_state.cmd_list.head_ptr = g_state.cmd_list.current_ptr = head_ptr;
g_state.cmd_list.length = g_state.regs.pipeline.command_buffer.GetSize(index) / sizeof(u32);
}
static void TriggerDraw(const Command& cmd) {
MICROPROFILE_SCOPE(GPU_Drawing);
#if PICA_LOG_TEV
DebugUtils::DumpTevStageConfig(regs.GetTevStages());
#endif
if (g_debug_context)
g_debug_context->OnEvent(DebugContext::Event::IncomingPrimitiveBatch, nullptr);
// Processes information about internal vertex attributes to figure out how a vertex is
// loaded.
// Later, these can be compiled and cached.
const u32 base_address = g_state.regs.pipeline.vertex_attributes.GetPhysicalBaseAddress();
VertexLoader loader(g_state.regs.pipeline);
// Load vertices
bool is_indexed = (cmd.ID == PICA_REG_INDEX(pipeline.trigger_draw_indexed));
const auto& index_info = g_state.regs.pipeline.index_array;
const u8* index_address_8 = Memory::GetPhysicalPointer(base_address + index_info.offset);
const u16* index_address_16 = reinterpret_cast<const u16*>(index_address_8);
bool index_u16 = index_info.format != 0;
PrimitiveAssembler<Shader::OutputVertex>& primitive_assembler = g_state.primitive_assembler;
if (g_debug_context && g_debug_context->recorder) {
for (int i = 0; i < 3; ++i) {
const auto texture = g_state.regs.texturing.GetTextures()[i];
if (!texture.enabled)
continue;
u8* texture_data = Memory::GetPhysicalPointer(texture.config.GetPhysicalAddress());
g_debug_context->recorder->MemoryAccessed(
texture_data, Pica::TexturingRegs::NibblesPerPixel(texture.format) *
texture.config.width / 2 * texture.config.height,
texture.config.GetPhysicalAddress());
}
}
DebugUtils::MemoryAccessTracker memory_accesses;
// Simple circular-replacement vertex cache
// The size has been tuned for optimal balance between hit-rate and the cost of lookup
const size_t VERTEX_CACHE_SIZE = 32;
std::array<u16, VERTEX_CACHE_SIZE> vertex_cache_ids;
std::array<Shader::AttributeBuffer, VERTEX_CACHE_SIZE> vertex_cache;
Shader::AttributeBuffer vs_output;
unsigned int vertex_cache_pos = 0;
vertex_cache_ids.fill(-1);
auto* shader_engine = Shader::GetEngine();
Shader::UnitState shader_unit;
shader_engine->SetupBatch(g_state.vs, g_state.regs.vs.main_offset);
g_state.geometry_pipeline.Reconfigure();
g_state.geometry_pipeline.Setup(shader_engine);
if (g_state.geometry_pipeline.NeedIndexInput())
ASSERT(is_indexed);
for (unsigned int index = 0; index < g_state.regs.pipeline.num_vertices; ++index) {
// Indexed rendering doesn't use the start offset
unsigned int vertex = is_indexed
? (index_u16 ? index_address_16[index] : index_address_8[index])
: (index + g_state.regs.pipeline.vertex_offset);
// -1 is a common special value used for primitive restart. Since it's unknown if
// the PICA supports it, and it would mess up the caching, guard against it here.
ASSERT(vertex != -1);
bool vertex_cache_hit = false;
if (is_indexed) {
if (g_state.geometry_pipeline.NeedIndexInput()) {
g_state.geometry_pipeline.SubmitIndex(vertex);
continue;
}
if (g_debug_context && Pica::g_debug_context->recorder) {
int size = index_u16 ? 2 : 1;
memory_accesses.AddAccess(base_address + index_info.offset + size * index, size);
}
for (unsigned int i = 0; i < VERTEX_CACHE_SIZE; ++i) {
if (vertex == vertex_cache_ids[i]) {
vs_output = vertex_cache[i];
vertex_cache_hit = true;
break;
}
}
}
if (!vertex_cache_hit) {
// Initialize data for the current vertex
Shader::AttributeBuffer input;
loader.LoadVertex(base_address, index, vertex, input, memory_accesses);
// Send to vertex shader
if (g_debug_context)
g_debug_context->OnEvent(DebugContext::Event::VertexShaderInvocation,
(void*)&input);
shader_unit.LoadInput(g_state.regs.vs, input);
shader_engine->Run(g_state.vs, shader_unit);
shader_unit.WriteOutput(g_state.regs.vs, vs_output);
if (is_indexed) {
vertex_cache[vertex_cache_pos] = vs_output;
vertex_cache_ids[vertex_cache_pos] = vertex;
vertex_cache_pos = (vertex_cache_pos + 1) % VERTEX_CACHE_SIZE;
}
}
// Send to geometry pipeline
g_state.geometry_pipeline.SubmitVertex(vs_output);
}
for (auto& range : memory_accesses.ranges) {
g_debug_context->recorder->MemoryAccessed(Memory::GetPhysicalPointer(range.first),
range.second, range.first);
}
}
static void DefaultAttribSetup(const Command& cmd) {
// TODO: Does actual hardware indeed keep an intermediate buffer or does // TODO: Does actual hardware indeed keep an intermediate buffer or does
// it directly write the values? // it directly write the values?
default_attr_write_buffer[default_attr_counter++] = value; default_attr_write_buffer[default_attr_counter++] = cmd.Value;
// Default attributes are written in a packed format such that four float24 values are // Default attributes are written in a packed format such that four float24 values are
// encoded in // encoded in
@ -180,11 +301,11 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
if (default_attr_counter >= 3) { if (default_attr_counter >= 3) {
default_attr_counter = 0; default_attr_counter = 0;
auto& setup = regs.pipeline.vs_default_attributes_setup; auto& setup = g_state.regs.pipeline.vs_default_attributes_setup;
if (setup.index >= 16) { if (setup.index >= 16) {
LOG_ERROR(HW_GPU, "Invalid VS default attribute index %d", (int)setup.index); LOG_ERROR(HW_GPU, "Invalid VS default attribute index %d", (int)setup.index);
break; return;
} }
Math::Vec4<float24> attribute; Math::Vec4<float24> attribute;
@ -215,14 +336,14 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
immediate_input.attr[immediate_attribute_id] = attribute; immediate_input.attr[immediate_attribute_id] = attribute;
if (immediate_attribute_id < regs.pipeline.max_input_attrib_index) { if (immediate_attribute_id < g_state.regs.pipeline.max_input_attrib_index) {
immediate_attribute_id += 1; immediate_attribute_id += 1;
} else { } else {
MICROPROFILE_SCOPE(GPU_Drawing); MICROPROFILE_SCOPE(GPU_Drawing);
immediate_attribute_id = 0; immediate_attribute_id = 0;
auto* shader_engine = Shader::GetEngine(); auto* shader_engine = Shader::GetEngine();
shader_engine->SetupBatch(g_state.vs, regs.vs.main_offset); shader_engine->SetupBatch(g_state.vs, g_state.regs.vs.main_offset);
// Send to vertex shader // Send to vertex shader
if (g_debug_context) if (g_debug_context)
@ -231,9 +352,9 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
Shader::UnitState shader_unit; Shader::UnitState shader_unit;
Shader::AttributeBuffer output{}; Shader::AttributeBuffer output{};
shader_unit.LoadInput(regs.vs, immediate_input); shader_unit.LoadInput(g_state.regs.vs, immediate_input);
shader_engine->Run(g_state.vs, shader_unit); shader_engine->Run(g_state.vs, shader_unit);
shader_unit.WriteOutput(regs.vs, output); shader_unit.WriteOutput(g_state.regs.vs, output);
// Send to geometry pipeline // Send to geometry pipeline
if (g_state.immediate.reset_geometry_pipeline) { if (g_state.immediate.reset_geometry_pipeline) {
@ -246,369 +367,163 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
} }
} }
} }
break;
} }
case PICA_REG_INDEX(pipeline.gpu_mode): static void UniformBoolGs(const Command&) {
if (regs.pipeline.gpu_mode == PipelineRegs::GPUMode::Configuring) {
MICROPROFILE_SCOPE(GPU_Drawing);
// Draw immediate mode triangles when GPU Mode is set to GPUMode::Configuring
VideoCore::g_renderer->Rasterizer()->DrawTriangles();
if (g_debug_context) {
g_debug_context->OnEvent(DebugContext::Event::FinishedPrimitiveBatch, nullptr);
}
}
break;
case PICA_REG_INDEX_WORKAROUND(pipeline.command_buffer.trigger[0], 0x23c):
case PICA_REG_INDEX_WORKAROUND(pipeline.command_buffer.trigger[1], 0x23d): {
unsigned index =
static_cast<unsigned>(id - PICA_REG_INDEX(pipeline.command_buffer.trigger[0]));
u32* head_ptr = (u32*)Memory::GetPhysicalPointer(
regs.pipeline.command_buffer.GetPhysicalAddress(index));
g_state.cmd_list.head_ptr = g_state.cmd_list.current_ptr = head_ptr;
g_state.cmd_list.length = regs.pipeline.command_buffer.GetSize(index) / sizeof(u32);
break;
}
// It seems like these trigger vertex rendering
case PICA_REG_INDEX(pipeline.trigger_draw):
case PICA_REG_INDEX(pipeline.trigger_draw_indexed): {
MICROPROFILE_SCOPE(GPU_Drawing);
#if PICA_LOG_TEV
DebugUtils::DumpTevStageConfig(regs.GetTevStages());
#endif
if (g_debug_context)
g_debug_context->OnEvent(DebugContext::Event::IncomingPrimitiveBatch, nullptr);
// Processes information about internal vertex attributes to figure out how a vertex is
// loaded.
// Later, these can be compiled and cached.
const u32 base_address = regs.pipeline.vertex_attributes.GetPhysicalBaseAddress();
VertexLoader loader(regs.pipeline);
// Load vertices
bool is_indexed = (id == PICA_REG_INDEX(pipeline.trigger_draw_indexed));
const auto& index_info = regs.pipeline.index_array;
const u8* index_address_8 = Memory::GetPhysicalPointer(base_address + index_info.offset);
const u16* index_address_16 = reinterpret_cast<const u16*>(index_address_8);
bool index_u16 = index_info.format != 0;
PrimitiveAssembler<Shader::OutputVertex>& primitive_assembler = g_state.primitive_assembler;
if (g_debug_context && g_debug_context->recorder) {
for (int i = 0; i < 3; ++i) {
const auto texture = regs.texturing.GetTextures()[i];
if (!texture.enabled)
continue;
u8* texture_data = Memory::GetPhysicalPointer(texture.config.GetPhysicalAddress());
g_debug_context->recorder->MemoryAccessed(
texture_data, Pica::TexturingRegs::NibblesPerPixel(texture.format) *
texture.config.width / 2 * texture.config.height,
texture.config.GetPhysicalAddress());
}
}
DebugUtils::MemoryAccessTracker memory_accesses;
// Simple circular-replacement vertex cache
// The size has been tuned for optimal balance between hit-rate and the cost of lookup
const size_t VERTEX_CACHE_SIZE = 32;
std::array<u16, VERTEX_CACHE_SIZE> vertex_cache_ids;
std::array<Shader::AttributeBuffer, VERTEX_CACHE_SIZE> vertex_cache;
Shader::AttributeBuffer vs_output;
unsigned int vertex_cache_pos = 0;
vertex_cache_ids.fill(-1);
auto* shader_engine = Shader::GetEngine();
Shader::UnitState shader_unit;
shader_engine->SetupBatch(g_state.vs, regs.vs.main_offset);
g_state.geometry_pipeline.Reconfigure();
g_state.geometry_pipeline.Setup(shader_engine);
if (g_state.geometry_pipeline.NeedIndexInput())
ASSERT(is_indexed);
for (unsigned int index = 0; index < regs.pipeline.num_vertices; ++index) {
// Indexed rendering doesn't use the start offset
unsigned int vertex =
is_indexed ? (index_u16 ? index_address_16[index] : index_address_8[index])
: (index + regs.pipeline.vertex_offset);
// -1 is a common special value used for primitive restart. Since it's unknown if
// the PICA supports it, and it would mess up the caching, guard against it here.
ASSERT(vertex != -1);
bool vertex_cache_hit = false;
if (is_indexed) {
if (g_state.geometry_pipeline.NeedIndexInput()) {
g_state.geometry_pipeline.SubmitIndex(vertex);
continue;
}
if (g_debug_context && Pica::g_debug_context->recorder) {
int size = index_u16 ? 2 : 1;
memory_accesses.AddAccess(base_address + index_info.offset + size * index,
size);
}
for (unsigned int i = 0; i < VERTEX_CACHE_SIZE; ++i) {
if (vertex == vertex_cache_ids[i]) {
vs_output = vertex_cache[i];
vertex_cache_hit = true;
break;
}
}
}
if (!vertex_cache_hit) {
// Initialize data for the current vertex
Shader::AttributeBuffer input;
loader.LoadVertex(base_address, index, vertex, input, memory_accesses);
// Send to vertex shader
if (g_debug_context)
g_debug_context->OnEvent(DebugContext::Event::VertexShaderInvocation,
(void*)&input);
shader_unit.LoadInput(regs.vs, input);
shader_engine->Run(g_state.vs, shader_unit);
shader_unit.WriteOutput(regs.vs, vs_output);
if (is_indexed) {
vertex_cache[vertex_cache_pos] = vs_output;
vertex_cache_ids[vertex_cache_pos] = vertex;
vertex_cache_pos = (vertex_cache_pos + 1) % VERTEX_CACHE_SIZE;
}
}
// Send to geometry pipeline
g_state.geometry_pipeline.SubmitVertex(vs_output);
}
for (auto& range : memory_accesses.ranges) {
g_debug_context->recorder->MemoryAccessed(Memory::GetPhysicalPointer(range.first),
range.second, range.first);
}
break;
}
case PICA_REG_INDEX(gs.bool_uniforms):
WriteUniformBoolReg(g_state.gs, g_state.regs.gs.bool_uniforms.Value()); WriteUniformBoolReg(g_state.gs, g_state.regs.gs.bool_uniforms.Value());
break;
case PICA_REG_INDEX_WORKAROUND(gs.int_uniforms[0], 0x281):
case PICA_REG_INDEX_WORKAROUND(gs.int_uniforms[1], 0x282):
case PICA_REG_INDEX_WORKAROUND(gs.int_uniforms[2], 0x283):
case PICA_REG_INDEX_WORKAROUND(gs.int_uniforms[3], 0x284): {
unsigned index = (id - PICA_REG_INDEX_WORKAROUND(gs.int_uniforms[0], 0x281));
auto values = regs.gs.int_uniforms[index];
WriteUniformIntReg(g_state.gs, index,
Math::Vec4<u8>(values.x, values.y, values.z, values.w));
break;
} }
case PICA_REG_INDEX_WORKAROUND(gs.uniform_setup.set_value[0], 0x291): static void UniformBoolVs(const Command&) {
case PICA_REG_INDEX_WORKAROUND(gs.uniform_setup.set_value[1], 0x292): // TODO (wwylele): does regs.pipeline.gs_unit_exclusive_configuration affect this?
case PICA_REG_INDEX_WORKAROUND(gs.uniform_setup.set_value[2], 0x293): WriteUniformBoolReg(g_state.vs, g_state.regs.vs.bool_uniforms.Value());
case PICA_REG_INDEX_WORKAROUND(gs.uniform_setup.set_value[3], 0x294): }
case PICA_REG_INDEX_WORKAROUND(gs.uniform_setup.set_value[4], 0x295):
case PICA_REG_INDEX_WORKAROUND(gs.uniform_setup.set_value[5], 0x296): static void UniformIntGs(const Command& cmd) {
case PICA_REG_INDEX_WORKAROUND(gs.uniform_setup.set_value[6], 0x297): unsigned index = (cmd.ID - PICA_REG_INDEX_WORKAROUND(gs.int_uniforms[0], 0x281));
case PICA_REG_INDEX_WORKAROUND(gs.uniform_setup.set_value[7], 0x298): { auto values = g_state.regs.gs.int_uniforms[index];
WriteUniformIntReg(g_state.gs, index, Math::Vec4<u8>(values.x, values.y, values.z, values.w));
}
static void UniformIntVs(const Command& cmd) {
// TODO (wwylele): does regs.pipeline.gs_unit_exclusive_configuration affect this?
unsigned index = (cmd.ID - PICA_REG_INDEX_WORKAROUND(vs.int_uniforms[0], 0x2b1));
auto values = g_state.regs.vs.int_uniforms[index];
WriteUniformIntReg(g_state.vs, index, Math::Vec4<u8>(values.x, values.y, values.z, values.w));
}
static void UniformFloatGs(const Command& cmd) {
WriteUniformFloatReg(g_state.regs.gs, g_state.gs, gs_float_regs_counter, WriteUniformFloatReg(g_state.regs.gs, g_state.gs, gs_float_regs_counter,
gs_uniform_write_buffer, value); gs_uniform_write_buffer, cmd.Value);
break;
} }
case PICA_REG_INDEX_WORKAROUND(gs.program.set_word[0], 0x29c): static void UniformFloatVs(const Command& cmd) {
case PICA_REG_INDEX_WORKAROUND(gs.program.set_word[1], 0x29d): // TODO (wwylele): does regs.pipeline.gs_unit_exclusive_configuration affect this?
case PICA_REG_INDEX_WORKAROUND(gs.program.set_word[2], 0x29e): WriteUniformFloatReg(g_state.regs.vs, g_state.vs, vs_float_regs_counter,
case PICA_REG_INDEX_WORKAROUND(gs.program.set_word[3], 0x29f): vs_uniform_write_buffer, cmd.Value);
case PICA_REG_INDEX_WORKAROUND(gs.program.set_word[4], 0x2a0): }
case PICA_REG_INDEX_WORKAROUND(gs.program.set_word[5], 0x2a1):
case PICA_REG_INDEX_WORKAROUND(gs.program.set_word[6], 0x2a2): static void SetWordGs(const Command& cmd) {
case PICA_REG_INDEX_WORKAROUND(gs.program.set_word[7], 0x2a3): {
u32& offset = g_state.regs.gs.program.offset; u32& offset = g_state.regs.gs.program.offset;
if (offset >= 4096) { if (offset >= 4096) {
LOG_ERROR(HW_GPU, "Invalid GS program offset %u", offset); LOG_ERROR(HW_GPU, "Invalid GS program offset %u", offset);
} else { } else {
g_state.gs.program_code[offset] = value; g_state.gs.program_code[offset] = cmd.Value;
offset++; offset++;
} }
break;
} }
case PICA_REG_INDEX_WORKAROUND(gs.swizzle_patterns.set_word[0], 0x2a6): static void SetWordVs(const Command& cmd) {
case PICA_REG_INDEX_WORKAROUND(gs.swizzle_patterns.set_word[1], 0x2a7):
case PICA_REG_INDEX_WORKAROUND(gs.swizzle_patterns.set_word[2], 0x2a8):
case PICA_REG_INDEX_WORKAROUND(gs.swizzle_patterns.set_word[3], 0x2a9):
case PICA_REG_INDEX_WORKAROUND(gs.swizzle_patterns.set_word[4], 0x2aa):
case PICA_REG_INDEX_WORKAROUND(gs.swizzle_patterns.set_word[5], 0x2ab):
case PICA_REG_INDEX_WORKAROUND(gs.swizzle_patterns.set_word[6], 0x2ac):
case PICA_REG_INDEX_WORKAROUND(gs.swizzle_patterns.set_word[7], 0x2ad): {
u32& offset = g_state.regs.gs.swizzle_patterns.offset;
if (offset >= g_state.gs.swizzle_data.size()) {
LOG_ERROR(HW_GPU, "Invalid GS swizzle pattern offset %u", offset);
} else {
g_state.gs.swizzle_data[offset] = value;
offset++;
}
break;
}
case PICA_REG_INDEX(vs.bool_uniforms):
// TODO (wwylele): does regs.pipeline.gs_unit_exclusive_configuration affect this?
WriteUniformBoolReg(g_state.vs, g_state.regs.vs.bool_uniforms.Value());
break;
case PICA_REG_INDEX_WORKAROUND(vs.int_uniforms[0], 0x2b1):
case PICA_REG_INDEX_WORKAROUND(vs.int_uniforms[1], 0x2b2):
case PICA_REG_INDEX_WORKAROUND(vs.int_uniforms[2], 0x2b3):
case PICA_REG_INDEX_WORKAROUND(vs.int_uniforms[3], 0x2b4): {
// TODO (wwylele): does regs.pipeline.gs_unit_exclusive_configuration affect this?
unsigned index = (id - PICA_REG_INDEX_WORKAROUND(vs.int_uniforms[0], 0x2b1));
auto values = regs.vs.int_uniforms[index];
WriteUniformIntReg(g_state.vs, index,
Math::Vec4<u8>(values.x, values.y, values.z, values.w));
break;
}
case PICA_REG_INDEX_WORKAROUND(vs.uniform_setup.set_value[0], 0x2c1):
case PICA_REG_INDEX_WORKAROUND(vs.uniform_setup.set_value[1], 0x2c2):
case PICA_REG_INDEX_WORKAROUND(vs.uniform_setup.set_value[2], 0x2c3):
case PICA_REG_INDEX_WORKAROUND(vs.uniform_setup.set_value[3], 0x2c4):
case PICA_REG_INDEX_WORKAROUND(vs.uniform_setup.set_value[4], 0x2c5):
case PICA_REG_INDEX_WORKAROUND(vs.uniform_setup.set_value[5], 0x2c6):
case PICA_REG_INDEX_WORKAROUND(vs.uniform_setup.set_value[6], 0x2c7):
case PICA_REG_INDEX_WORKAROUND(vs.uniform_setup.set_value[7], 0x2c8): {
// TODO (wwylele): does regs.pipeline.gs_unit_exclusive_configuration affect this?
WriteUniformFloatReg(g_state.regs.vs, g_state.vs, vs_float_regs_counter,
vs_uniform_write_buffer, value);
break;
}
case PICA_REG_INDEX_WORKAROUND(vs.program.set_word[0], 0x2cc):
case PICA_REG_INDEX_WORKAROUND(vs.program.set_word[1], 0x2cd):
case PICA_REG_INDEX_WORKAROUND(vs.program.set_word[2], 0x2ce):
case PICA_REG_INDEX_WORKAROUND(vs.program.set_word[3], 0x2cf):
case PICA_REG_INDEX_WORKAROUND(vs.program.set_word[4], 0x2d0):
case PICA_REG_INDEX_WORKAROUND(vs.program.set_word[5], 0x2d1):
case PICA_REG_INDEX_WORKAROUND(vs.program.set_word[6], 0x2d2):
case PICA_REG_INDEX_WORKAROUND(vs.program.set_word[7], 0x2d3): {
u32& offset = g_state.regs.vs.program.offset; u32& offset = g_state.regs.vs.program.offset;
if (offset >= 512) { if (offset >= 512) {
LOG_ERROR(HW_GPU, "Invalid VS program offset %u", offset); LOG_ERROR(HW_GPU, "Invalid VS program offset %u", offset);
} else { } else {
g_state.vs.program_code[offset] = value; g_state.vs.program_code[offset] = cmd.Value;
if (!g_state.regs.pipeline.gs_unit_exclusive_configuration) { if (!g_state.regs.pipeline.gs_unit_exclusive_configuration) {
g_state.gs.program_code[offset] = value; g_state.gs.program_code[offset] = cmd.Value;
} }
offset++; offset++;
} }
break;
} }
case PICA_REG_INDEX_WORKAROUND(vs.swizzle_patterns.set_word[0], 0x2d6): static void SetWordSwizzleGs(const Command& cmd) {
case PICA_REG_INDEX_WORKAROUND(vs.swizzle_patterns.set_word[1], 0x2d7): u32& offset = g_state.regs.gs.swizzle_patterns.offset;
case PICA_REG_INDEX_WORKAROUND(vs.swizzle_patterns.set_word[2], 0x2d8): if (offset >= g_state.gs.swizzle_data.size()) {
case PICA_REG_INDEX_WORKAROUND(vs.swizzle_patterns.set_word[3], 0x2d9): LOG_ERROR(HW_GPU, "Invalid GS swizzle pattern offset %u", offset);
case PICA_REG_INDEX_WORKAROUND(vs.swizzle_patterns.set_word[4], 0x2da): } else {
case PICA_REG_INDEX_WORKAROUND(vs.swizzle_patterns.set_word[5], 0x2db): g_state.gs.swizzle_data[offset] = cmd.Value;
case PICA_REG_INDEX_WORKAROUND(vs.swizzle_patterns.set_word[6], 0x2dc): offset++;
case PICA_REG_INDEX_WORKAROUND(vs.swizzle_patterns.set_word[7], 0x2dd): { }
}
static void SetWordSwizzleVs(const Command& cmd) {
u32& offset = g_state.regs.vs.swizzle_patterns.offset; u32& offset = g_state.regs.vs.swizzle_patterns.offset;
if (offset >= g_state.vs.swizzle_data.size()) { if (offset >= g_state.vs.swizzle_data.size()) {
LOG_ERROR(HW_GPU, "Invalid VS swizzle pattern offset %u", offset); LOG_ERROR(HW_GPU, "Invalid VS swizzle pattern offset %u", offset);
} else { } else {
g_state.vs.swizzle_data[offset] = value; g_state.vs.swizzle_data[offset] = cmd.Value;
if (!g_state.regs.pipeline.gs_unit_exclusive_configuration) { if (!g_state.regs.pipeline.gs_unit_exclusive_configuration) {
g_state.gs.swizzle_data[offset] = value; g_state.gs.swizzle_data[offset] = cmd.Value;
} }
offset++; offset++;
} }
break;
} }
case PICA_REG_INDEX_WORKAROUND(lighting.lut_data[0], 0x1c8): static void LightingLut(const Command& cmd) {
case PICA_REG_INDEX_WORKAROUND(lighting.lut_data[1], 0x1c9): auto& lut_config = g_state.regs.lighting.lut_config;
case PICA_REG_INDEX_WORKAROUND(lighting.lut_data[2], 0x1ca):
case PICA_REG_INDEX_WORKAROUND(lighting.lut_data[3], 0x1cb):
case PICA_REG_INDEX_WORKAROUND(lighting.lut_data[4], 0x1cc):
case PICA_REG_INDEX_WORKAROUND(lighting.lut_data[5], 0x1cd):
case PICA_REG_INDEX_WORKAROUND(lighting.lut_data[6], 0x1ce):
case PICA_REG_INDEX_WORKAROUND(lighting.lut_data[7], 0x1cf): {
auto& lut_config = regs.lighting.lut_config;
ASSERT_MSG(lut_config.index < 256, "lut_config.index exceeded maximum value of 255!"); ASSERT_MSG(lut_config.index < 256, "lut_config.index exceeded maximum value of 255!");
g_state.lighting.luts[lut_config.type][lut_config.index].raw = value; g_state.lighting.luts[lut_config.type][lut_config.index].raw = cmd.Value;
lut_config.index.Assign(lut_config.index + 1); lut_config.index.Assign(lut_config.index + 1);
break;
} }
case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[0], 0xe8): static void FogLut(const Command& cmd) {
case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[1], 0xe9): g_state.fog.lut[g_state.regs.texturing.fog_lut_offset % 128].raw = cmd.Value;
case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[2], 0xea): g_state.regs.texturing.fog_lut_offset.Assign(g_state.regs.texturing.fog_lut_offset + 1);
case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[3], 0xeb):
case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[4], 0xec):
case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[5], 0xed):
case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[6], 0xee):
case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[7], 0xef): {
g_state.fog.lut[regs.texturing.fog_lut_offset % 128].raw = value;
regs.texturing.fog_lut_offset.Assign(regs.texturing.fog_lut_offset + 1);
break;
} }
case PICA_REG_INDEX_WORKAROUND(texturing.proctex_lut_data[0], 0xb0): static void ProcTexLut(const Command& cmd) {
case PICA_REG_INDEX_WORKAROUND(texturing.proctex_lut_data[1], 0xb1): auto& index = g_state.regs.texturing.proctex_lut_config.index;
case PICA_REG_INDEX_WORKAROUND(texturing.proctex_lut_data[2], 0xb2):
case PICA_REG_INDEX_WORKAROUND(texturing.proctex_lut_data[3], 0xb3):
case PICA_REG_INDEX_WORKAROUND(texturing.proctex_lut_data[4], 0xb4):
case PICA_REG_INDEX_WORKAROUND(texturing.proctex_lut_data[5], 0xb5):
case PICA_REG_INDEX_WORKAROUND(texturing.proctex_lut_data[6], 0xb6):
case PICA_REG_INDEX_WORKAROUND(texturing.proctex_lut_data[7], 0xb7): {
auto& index = regs.texturing.proctex_lut_config.index;
auto& pt = g_state.proctex; auto& pt = g_state.proctex;
switch (regs.texturing.proctex_lut_config.ref_table.Value()) { switch (g_state.regs.texturing.proctex_lut_config.ref_table.Value()) {
case TexturingRegs::ProcTexLutTable::Noise: case TexturingRegs::ProcTexLutTable::Noise:
pt.noise_table[index % pt.noise_table.size()].raw = value; pt.noise_table[index % pt.noise_table.size()].raw = cmd.Value;
break; break;
case TexturingRegs::ProcTexLutTable::ColorMap: case TexturingRegs::ProcTexLutTable::ColorMap:
pt.color_map_table[index % pt.color_map_table.size()].raw = value; pt.color_map_table[index % pt.color_map_table.size()].raw = cmd.Value;
break; break;
case TexturingRegs::ProcTexLutTable::AlphaMap: case TexturingRegs::ProcTexLutTable::AlphaMap:
pt.alpha_map_table[index % pt.alpha_map_table.size()].raw = value; pt.alpha_map_table[index % pt.alpha_map_table.size()].raw = cmd.Value;
break; break;
case TexturingRegs::ProcTexLutTable::Color: case TexturingRegs::ProcTexLutTable::Color:
pt.color_table[index % pt.color_table.size()].raw = value; pt.color_table[index % pt.color_table.size()].raw = cmd.Value;
break; break;
case TexturingRegs::ProcTexLutTable::ColorDiff: case TexturingRegs::ProcTexLutTable::ColorDiff:
pt.color_diff_table[index % pt.color_diff_table.size()].raw = value; pt.color_diff_table[index % pt.color_diff_table.size()].raw = cmd.Value;
break; break;
} }
index.Assign(index + 1); index.Assign(index + 1);
break;
}
default:
break;
} }
VideoCore::g_renderer->Rasterizer()->NotifyPicaRegisterChanged(id); static void WritePicaReg(const Command& cmd) {
auto& regs = g_state.regs;
if (g_debug_context) if (cmd.ID >= Regs::NUM_REGS) {
LOG_ERROR(HW_GPU,
"Commandlist tried to write to invalid register 0x%03X (value: %08X, mask: %X)",
cmd.ID, cmd.Value, cmd.Mask);
return;
}
// TODO: Figure out how register masking acts on e.g. vs.uniform_setup.set_value
u32 old_value = regs.reg_array[cmd.ID];
const u32 write_mask = expand_bits_to_bytes[cmd.Mask];
regs.reg_array[cmd.ID] = (old_value & ~write_mask) | (cmd.Value & write_mask);
// Double check for is_pica_tracing to avoid call overhead
if (DebugUtils::IsPicaTracing()) {
DebugUtils::OnPicaRegWrite({(u16)cmd.ID, (u16)cmd.Mask, regs.reg_array[cmd.ID]});
}
if (g_debug_context) {
auto id = cmd.ID;
g_debug_context->OnEvent(DebugContext::Event::PicaCommandLoaded,
reinterpret_cast<void*>(&id));
}
CommandMap[cmd.ID](cmd);
VideoCore::g_renderer->Rasterizer()->NotifyPicaRegisterChanged(cmd.ID);
if (g_debug_context) {
auto id = cmd.ID;
g_debug_context->OnEvent(DebugContext::Event::PicaCommandProcessed, g_debug_context->OnEvent(DebugContext::Event::PicaCommandProcessed,
reinterpret_cast<void*>(&id)); reinterpret_cast<void*>(&id));
} }
}
void ProcessCommandList(const u32* list, u32 size) { void ProcessCommandList(const u32* list, u32 size) {
g_state.cmd_list.head_ptr = g_state.cmd_list.current_ptr = list; g_state.cmd_list.head_ptr = g_state.cmd_list.current_ptr = list;
@ -623,11 +538,11 @@ void ProcessCommandList(const u32* list, u32 size) {
u32 value = *g_state.cmd_list.current_ptr++; u32 value = *g_state.cmd_list.current_ptr++;
const CommandHeader header = {*g_state.cmd_list.current_ptr++}; const CommandHeader header = {*g_state.cmd_list.current_ptr++};
WritePicaReg(header.cmd_id, value, header.parameter_mask); WritePicaReg(Command{header.cmd_id, value, header.parameter_mask});
for (unsigned i = 0; i < header.extra_data_length; ++i) { for (unsigned i = 0; i < header.extra_data_length; ++i) {
u32 cmd = header.cmd_id + (header.group_commands ? i + 1 : 0); u32 cmd = header.cmd_id + (header.group_commands ? i + 1 : 0);
WritePicaReg(cmd, *g_state.cmd_list.current_ptr++, header.parameter_mask); WritePicaReg(Command{cmd, *g_state.cmd_list.current_ptr++, header.parameter_mask});
} }
} }
} }