diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index 82f47d8a9..085a53800 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt @@ -28,6 +28,7 @@ set(SRCS ) set(HEADERS + command_map.h command_processor.h debug_utils/debug_utils.h geometry_pipeline.h diff --git a/src/video_core/command_map.h b/src/video_core/command_map.h new file mode 100644 index 000000000..566f1a12f --- /dev/null +++ b/src/video_core/command_map.h @@ -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 diff --git a/src/video_core/command_processor.cpp b/src/video_core/command_processor.cpp index fb65a3a0a..a77a021de 100644 --- a/src/video_core/command_processor.cpp +++ b/src/video_core/command_processor.cpp @@ -14,6 +14,7 @@ #include "core/hw/gpu.h" #include "core/memory.h" #include "core/tracer/recorder.h" +#include "video_core/command_map.h" #include "video_core/command_processor.h" #include "video_core/debug_utils/debug_utils.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, }; +struct Command { + const u32 ID; + const u32 Value; + const u32 Mask; +}; + MICROPROFILE_DEFINE(GPU_Drawing, "GPU", "Drawing", MP_RGB(50, 50, 240)); static const char* GetShaderSetupTypeName(Shader::ShaderSetup& setup) { @@ -119,495 +126,403 @@ static void WriteUniformFloatReg(ShaderRegs& config, Shader::ShaderSetup& setup, } } -static void WritePicaReg(u32 id, u32 value, u32 mask) { - auto& regs = g_state.regs; +static void TriggerIRQ(const Command&) { + Service::GSP::SignalInterrupt(Service::GSP::InterruptId::P3D); +} - 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; - } +static void TriangleTopology(const Command&) { + g_state.primitive_assembler.Reconfigure(g_state.regs.pipeline.triangle_topology); +} - // TODO: Figure out how register masking acts on e.g. vs.uniform_setup.set_value - u32 old_value = regs.reg_array[id]; +static void RestartPrimitive(const Command&) { + g_state.primitive_assembler.Reset(); +} - const u32 write_mask = expand_bits_to_bytes[mask]; +static void DefaultAttributes(const Command&) { + g_state.immediate.current_attribute = 0; + g_state.immediate.reset_geometry_pipeline = true; + default_attr_counter = 0; +} - 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(&id)); - - switch (id) { - // Trigger IRQ - case PICA_REG_INDEX(trigger_irq): - Service::GSP::SignalInterrupt(Service::GSP::InterruptId::P3D); - break; - - case PICA_REG_INDEX(pipeline.triangle_topology): - g_state.primitive_assembler.Reconfigure(regs.pipeline.triangle_topology); - break; - - case PICA_REG_INDEX(pipeline.restart_primitive): - g_state.primitive_assembler.Reset(); - break; - - case PICA_REG_INDEX(pipeline.vs_default_attributes_setup.index): - g_state.immediate.current_attribute = 0; - g_state.immediate.reset_geometry_pipeline = true; - default_attr_counter = 0; - break; - - // Load default vertex input attributes - case PICA_REG_INDEX_WORKAROUND(pipeline.vs_default_attributes_setup.set_value[0], 0x233): - case PICA_REG_INDEX_WORKAROUND(pipeline.vs_default_attributes_setup.set_value[1], 0x234): - case PICA_REG_INDEX_WORKAROUND(pipeline.vs_default_attributes_setup.set_value[2], 0x235): { - // TODO: Does actual hardware indeed keep an intermediate buffer or does - // it directly write the values? - default_attr_write_buffer[default_attr_counter++] = value; - - // Default attributes are written in a packed format such that four float24 values are - // encoded in - // three 32-bit numbers. We write to internal memory once a full such vector is - // written. - if (default_attr_counter >= 3) { - default_attr_counter = 0; - - auto& setup = regs.pipeline.vs_default_attributes_setup; - - if (setup.index >= 16) { - LOG_ERROR(HW_GPU, "Invalid VS default attribute index %d", (int)setup.index); - break; - } - - Math::Vec4 attribute; - - // NOTE: The destination component order indeed is "backwards" - attribute.w = float24::FromRaw(default_attr_write_buffer[0] >> 8); - attribute.z = float24::FromRaw(((default_attr_write_buffer[0] & 0xFF) << 16) | - ((default_attr_write_buffer[1] >> 16) & 0xFFFF)); - attribute.y = float24::FromRaw(((default_attr_write_buffer[1] & 0xFFFF) << 8) | - ((default_attr_write_buffer[2] >> 24) & 0xFF)); - attribute.x = float24::FromRaw(default_attr_write_buffer[2] & 0xFFFFFF); - - LOG_TRACE(HW_GPU, "Set default VS attribute %x to (%f %f %f %f)", (int)setup.index, - attribute.x.ToFloat32(), attribute.y.ToFloat32(), attribute.z.ToFloat32(), - attribute.w.ToFloat32()); - - // TODO: Verify that this actually modifies the register! - if (setup.index < 15) { - g_state.input_default_attributes.attr[setup.index] = attribute; - setup.index++; - } else { - // Put each attribute into an immediate input buffer. When all specified immediate - // attributes are present, the Vertex Shader is invoked and everything is sent to - // the primitive assembler. - - auto& immediate_input = g_state.immediate.input_vertex; - auto& immediate_attribute_id = g_state.immediate.current_attribute; - - immediate_input.attr[immediate_attribute_id] = attribute; - - if (immediate_attribute_id < regs.pipeline.max_input_attrib_index) { - immediate_attribute_id += 1; - } else { - MICROPROFILE_SCOPE(GPU_Drawing); - immediate_attribute_id = 0; - - auto* shader_engine = Shader::GetEngine(); - shader_engine->SetupBatch(g_state.vs, regs.vs.main_offset); - - // Send to vertex shader - if (g_debug_context) - g_debug_context->OnEvent(DebugContext::Event::VertexShaderInvocation, - static_cast(&immediate_input)); - Shader::UnitState shader_unit; - Shader::AttributeBuffer output{}; - - shader_unit.LoadInput(regs.vs, immediate_input); - shader_engine->Run(g_state.vs, shader_unit); - shader_unit.WriteOutput(regs.vs, output); - - // Send to geometry pipeline - if (g_state.immediate.reset_geometry_pipeline) { - g_state.geometry_pipeline.Reconfigure(); - g_state.immediate.reset_geometry_pipeline = false; - } - ASSERT(!g_state.geometry_pipeline.NeedIndexInput()); - g_state.geometry_pipeline.Setup(shader_engine); - g_state.geometry_pipeline.SubmitVertex(output); - } - } - } - break; - } - - case PICA_REG_INDEX(pipeline.gpu_mode): - 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(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): { +static void GpuMode(const Command&) { + if (g_state.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); + } + } +} + +static void TriggerCommandBuffer(const Command& cmd) { + unsigned index = + static_cast(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()); + DebugUtils::DumpTevStageConfig(regs.GetTevStages()); #endif - if (g_debug_context) - g_debug_context->OnEvent(DebugContext::Event::IncomingPrimitiveBatch, nullptr); + 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); + // 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 = (id == PICA_REG_INDEX(pipeline.trigger_draw_indexed)); + // Load vertices + bool is_indexed = (cmd.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(index_address_8); - bool index_u16 = index_info.format != 0; + 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(index_address_8); + bool index_u16 = index_info.format != 0; - PrimitiveAssembler& primitive_assembler = g_state.primitive_assembler; + PrimitiveAssembler& 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; + 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()); + 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 vertex_cache_ids; + std::array 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; + } } } - DebugUtils::MemoryAccessTracker memory_accesses; + if (!vertex_cache_hit) { + // Initialize data for the current vertex + Shader::AttributeBuffer input; + loader.LoadVertex(base_address, index, vertex, input, 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 vertex_cache_ids; - std::array 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; + // 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) { - 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; - } - } + vertex_cache[vertex_cache_pos] = vs_output; + vertex_cache_ids[vertex_cache_pos] = vertex; + vertex_cache_pos = (vertex_cache_pos + 1) % VERTEX_CACHE_SIZE; } + } - if (!vertex_cache_hit) { - // Initialize data for the current vertex - Shader::AttributeBuffer input; - loader.LoadVertex(base_address, index, vertex, input, memory_accesses); + // 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 + // it directly write the values? + default_attr_write_buffer[default_attr_counter++] = cmd.Value; + + // Default attributes are written in a packed format such that four float24 values are + // encoded in + // three 32-bit numbers. We write to internal memory once a full such vector is + // written. + if (default_attr_counter >= 3) { + default_attr_counter = 0; + + auto& setup = g_state.regs.pipeline.vs_default_attributes_setup; + + if (setup.index >= 16) { + LOG_ERROR(HW_GPU, "Invalid VS default attribute index %d", (int)setup.index); + return; + } + + Math::Vec4 attribute; + + // NOTE: The destination component order indeed is "backwards" + attribute.w = float24::FromRaw(default_attr_write_buffer[0] >> 8); + attribute.z = float24::FromRaw(((default_attr_write_buffer[0] & 0xFF) << 16) | + ((default_attr_write_buffer[1] >> 16) & 0xFFFF)); + attribute.y = float24::FromRaw(((default_attr_write_buffer[1] & 0xFFFF) << 8) | + ((default_attr_write_buffer[2] >> 24) & 0xFF)); + attribute.x = float24::FromRaw(default_attr_write_buffer[2] & 0xFFFFFF); + + LOG_TRACE(HW_GPU, "Set default VS attribute %x to (%f %f %f %f)", (int)setup.index, + attribute.x.ToFloat32(), attribute.y.ToFloat32(), attribute.z.ToFloat32(), + attribute.w.ToFloat32()); + + // TODO: Verify that this actually modifies the register! + if (setup.index < 15) { + g_state.input_default_attributes.attr[setup.index] = attribute; + setup.index++; + } else { + // Put each attribute into an immediate input buffer. When all specified immediate + // attributes are present, the Vertex Shader is invoked and everything is sent to + // the primitive assembler. + + auto& immediate_input = g_state.immediate.input_vertex; + auto& immediate_attribute_id = g_state.immediate.current_attribute; + + immediate_input.attr[immediate_attribute_id] = attribute; + + if (immediate_attribute_id < g_state.regs.pipeline.max_input_attrib_index) { + immediate_attribute_id += 1; + } else { + MICROPROFILE_SCOPE(GPU_Drawing); + immediate_attribute_id = 0; + + auto* shader_engine = Shader::GetEngine(); + shader_engine->SetupBatch(g_state.vs, g_state.regs.vs.main_offset); // Send to vertex shader if (g_debug_context) g_debug_context->OnEvent(DebugContext::Event::VertexShaderInvocation, - (void*)&input); - shader_unit.LoadInput(regs.vs, input); + static_cast(&immediate_input)); + Shader::UnitState shader_unit; + Shader::AttributeBuffer output{}; + + shader_unit.LoadInput(g_state.regs.vs, immediate_input); shader_engine->Run(g_state.vs, shader_unit); - shader_unit.WriteOutput(regs.vs, vs_output); + shader_unit.WriteOutput(g_state.regs.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 + if (g_state.immediate.reset_geometry_pipeline) { + g_state.geometry_pipeline.Reconfigure(); + g_state.immediate.reset_geometry_pipeline = false; } + ASSERT(!g_state.geometry_pipeline.NeedIndexInput()); + g_state.geometry_pipeline.Setup(shader_engine); + g_state.geometry_pipeline.SubmitVertex(output); } - - // 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 UniformBoolGs(const Command&) { + WriteUniformBoolReg(g_state.gs, g_state.regs.gs.bool_uniforms.Value()); +} + +static void UniformBoolVs(const Command&) { + // TODO (wwylele): does regs.pipeline.gs_unit_exclusive_configuration affect this? + WriteUniformBoolReg(g_state.vs, g_state.regs.vs.bool_uniforms.Value()); +} + +static void UniformIntGs(const Command& cmd) { + unsigned index = (cmd.ID - PICA_REG_INDEX_WORKAROUND(gs.int_uniforms[0], 0x281)); + auto values = g_state.regs.gs.int_uniforms[index]; + WriteUniformIntReg(g_state.gs, index, Math::Vec4(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(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, + gs_uniform_write_buffer, cmd.Value); +} + +static void UniformFloatVs(const Command& cmd) { + // 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, cmd.Value); +} + +static void SetWordGs(const Command& cmd) { + u32& offset = g_state.regs.gs.program.offset; + if (offset >= 4096) { + LOG_ERROR(HW_GPU, "Invalid GS program offset %u", offset); + } else { + g_state.gs.program_code[offset] = cmd.Value; + offset++; + } +} + +static void SetWordVs(const Command& cmd) { + u32& offset = g_state.regs.vs.program.offset; + if (offset >= 512) { + LOG_ERROR(HW_GPU, "Invalid VS program offset %u", offset); + } else { + g_state.vs.program_code[offset] = cmd.Value; + if (!g_state.regs.pipeline.gs_unit_exclusive_configuration) { + g_state.gs.program_code[offset] = cmd.Value; } - - break; + offset++; } +} - case PICA_REG_INDEX(gs.bool_uniforms): - 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(values.x, values.y, values.z, values.w)); - break; +static void SetWordSwizzleGs(const Command& cmd) { + 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] = cmd.Value; + offset++; } +} - case PICA_REG_INDEX_WORKAROUND(gs.uniform_setup.set_value[0], 0x291): - case PICA_REG_INDEX_WORKAROUND(gs.uniform_setup.set_value[1], 0x292): - case PICA_REG_INDEX_WORKAROUND(gs.uniform_setup.set_value[2], 0x293): - 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): - case PICA_REG_INDEX_WORKAROUND(gs.uniform_setup.set_value[6], 0x297): - case PICA_REG_INDEX_WORKAROUND(gs.uniform_setup.set_value[7], 0x298): { - WriteUniformFloatReg(g_state.regs.gs, g_state.gs, gs_float_regs_counter, - gs_uniform_write_buffer, value); - break; - } - - case PICA_REG_INDEX_WORKAROUND(gs.program.set_word[0], 0x29c): - case PICA_REG_INDEX_WORKAROUND(gs.program.set_word[1], 0x29d): - case PICA_REG_INDEX_WORKAROUND(gs.program.set_word[2], 0x29e): - case PICA_REG_INDEX_WORKAROUND(gs.program.set_word[3], 0x29f): - 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): - case PICA_REG_INDEX_WORKAROUND(gs.program.set_word[7], 0x2a3): { - u32& offset = g_state.regs.gs.program.offset; - if (offset >= 4096) { - LOG_ERROR(HW_GPU, "Invalid GS program offset %u", offset); - } else { - g_state.gs.program_code[offset] = value; - offset++; +static void SetWordSwizzleVs(const Command& cmd) { + u32& offset = g_state.regs.vs.swizzle_patterns.offset; + if (offset >= g_state.vs.swizzle_data.size()) { + LOG_ERROR(HW_GPU, "Invalid VS swizzle pattern offset %u", offset); + } else { + g_state.vs.swizzle_data[offset] = cmd.Value; + if (!g_state.regs.pipeline.gs_unit_exclusive_configuration) { + g_state.gs.swizzle_data[offset] = cmd.Value; } + offset++; + } +} + +static void LightingLut(const Command& cmd) { + auto& lut_config = g_state.regs.lighting.lut_config; + + 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 = cmd.Value; + lut_config.index.Assign(lut_config.index + 1); +} + +static void FogLut(const Command& cmd) { + g_state.fog.lut[g_state.regs.texturing.fog_lut_offset % 128].raw = cmd.Value; + g_state.regs.texturing.fog_lut_offset.Assign(g_state.regs.texturing.fog_lut_offset + 1); +} + +static void ProcTexLut(const Command& cmd) { + auto& index = g_state.regs.texturing.proctex_lut_config.index; + auto& pt = g_state.proctex; + + switch (g_state.regs.texturing.proctex_lut_config.ref_table.Value()) { + case TexturingRegs::ProcTexLutTable::Noise: + pt.noise_table[index % pt.noise_table.size()].raw = cmd.Value; + break; + case TexturingRegs::ProcTexLutTable::ColorMap: + pt.color_map_table[index % pt.color_map_table.size()].raw = cmd.Value; + break; + case TexturingRegs::ProcTexLutTable::AlphaMap: + pt.alpha_map_table[index % pt.alpha_map_table.size()].raw = cmd.Value; + break; + case TexturingRegs::ProcTexLutTable::Color: + pt.color_table[index % pt.color_table.size()].raw = cmd.Value; + break; + case TexturingRegs::ProcTexLutTable::ColorDiff: + pt.color_diff_table[index % pt.color_diff_table.size()].raw = cmd.Value; break; } + index.Assign(index + 1); +} - case PICA_REG_INDEX_WORKAROUND(gs.swizzle_patterns.set_word[0], 0x2a6): - 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; +static void WritePicaReg(const Command& cmd) { + auto& regs = g_state.regs; + + 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; } - 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; + // TODO: Figure out how register masking acts on e.g. vs.uniform_setup.set_value + u32 old_value = regs.reg_array[cmd.ID]; - 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(values.x, values.y, values.z, values.w)); - break; + 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]}); } - 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; + if (g_debug_context) { + auto id = cmd.ID; + g_debug_context->OnEvent(DebugContext::Event::PicaCommandLoaded, + reinterpret_cast(&id)); } - 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; - if (offset >= 512) { - LOG_ERROR(HW_GPU, "Invalid VS program offset %u", offset); - } else { - g_state.vs.program_code[offset] = value; - if (!g_state.regs.pipeline.gs_unit_exclusive_configuration) { - g_state.gs.program_code[offset] = value; - } - offset++; - } - break; - } + CommandMap[cmd.ID](cmd); - case PICA_REG_INDEX_WORKAROUND(vs.swizzle_patterns.set_word[0], 0x2d6): - case PICA_REG_INDEX_WORKAROUND(vs.swizzle_patterns.set_word[1], 0x2d7): - case PICA_REG_INDEX_WORKAROUND(vs.swizzle_patterns.set_word[2], 0x2d8): - case PICA_REG_INDEX_WORKAROUND(vs.swizzle_patterns.set_word[3], 0x2d9): - case PICA_REG_INDEX_WORKAROUND(vs.swizzle_patterns.set_word[4], 0x2da): - case PICA_REG_INDEX_WORKAROUND(vs.swizzle_patterns.set_word[5], 0x2db): - case PICA_REG_INDEX_WORKAROUND(vs.swizzle_patterns.set_word[6], 0x2dc): - case PICA_REG_INDEX_WORKAROUND(vs.swizzle_patterns.set_word[7], 0x2dd): { - u32& offset = g_state.regs.vs.swizzle_patterns.offset; - if (offset >= g_state.vs.swizzle_data.size()) { - LOG_ERROR(HW_GPU, "Invalid VS swizzle pattern offset %u", offset); - } else { - g_state.vs.swizzle_data[offset] = value; - if (!g_state.regs.pipeline.gs_unit_exclusive_configuration) { - g_state.gs.swizzle_data[offset] = value; - } - offset++; - } - break; - } + VideoCore::g_renderer->Rasterizer()->NotifyPicaRegisterChanged(cmd.ID); - case PICA_REG_INDEX_WORKAROUND(lighting.lut_data[0], 0x1c8): - case PICA_REG_INDEX_WORKAROUND(lighting.lut_data[1], 0x1c9): - 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!"); - - g_state.lighting.luts[lut_config.type][lut_config.index].raw = value; - lut_config.index.Assign(lut_config.index + 1); - break; - } - - case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[0], 0xe8): - case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[1], 0xe9): - case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[2], 0xea): - 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): - case PICA_REG_INDEX_WORKAROUND(texturing.proctex_lut_data[1], 0xb1): - 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; - - switch (regs.texturing.proctex_lut_config.ref_table.Value()) { - case TexturingRegs::ProcTexLutTable::Noise: - pt.noise_table[index % pt.noise_table.size()].raw = value; - break; - case TexturingRegs::ProcTexLutTable::ColorMap: - pt.color_map_table[index % pt.color_map_table.size()].raw = value; - break; - case TexturingRegs::ProcTexLutTable::AlphaMap: - pt.alpha_map_table[index % pt.alpha_map_table.size()].raw = value; - break; - case TexturingRegs::ProcTexLutTable::Color: - pt.color_table[index % pt.color_table.size()].raw = value; - break; - case TexturingRegs::ProcTexLutTable::ColorDiff: - pt.color_diff_table[index % pt.color_diff_table.size()].raw = value; - break; - } - index.Assign(index + 1); - break; - } - default: - break; - } - - VideoCore::g_renderer->Rasterizer()->NotifyPicaRegisterChanged(id); - - if (g_debug_context) + if (g_debug_context) { + auto id = cmd.ID; g_debug_context->OnEvent(DebugContext::Event::PicaCommandProcessed, reinterpret_cast(&id)); + } } void ProcessCommandList(const u32* list, u32 size) { @@ -623,11 +538,11 @@ void ProcessCommandList(const u32* list, u32 size) { u32 value = *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) { 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}); } } }