// Setup Unit #include "pch.h" // Processing of BP address space registers Load Commands using namespace Debug; #define NO_VIEWPORT namespace GX { void GXCore::GL_SetScissor(int x, int y, int w, int h) { //h += 32; #ifndef NO_VIEWPORT glScissor(x, scr_h - (h + y), w, h); #endif } void GXCore::GL_SetCullMode(int mode) { switch(mode) { case GEN_REJECT_NONE: glDisable(GL_CULL_FACE); break; case GEN_REJECT_FRONT: // TODO: It's mixed up so far, not sure why, but it has to be that way glEnable(GL_CULL_FACE); glCullFace(GL_BACK); break; case GEN_REJECT_BACK: // TODO: It's mixed up so far, not sure why, but it has to be that way glEnable(GL_CULL_FACE); glCullFace(GL_FRONT); break; case GEN_REJECT_ALL: glEnable(GL_CULL_FACE); glCullFace(GL_FRONT_AND_BACK); break; } } // index range = 00..FF // reg size = 24 bit (value is already masked) void GXCore::loadBPReg(size_t index, uint32_t value) { bpLoads++; if (GpRegsLog) { Report(Channel::GP, "Load BP: index: 0x%02X, data: 0x%08X\n", index, value); } switch (index) { // // gen mode // case GEN_MODE_ID: { genmode.bits = value; GL_SetCullMode(genmode.reject_en); } return; // I don't see any use for MSLOC yet, I added it to avoid spamming with warnings case GEN_MSLOC0_ID: msloc[0].bits = value; break; case GEN_MSLOC1_ID: msloc[1].bits = value; break; case GEN_MSLOC2_ID: msloc[2].bits = value; break; case GEN_MSLOC3_ID: msloc[3].bits = value; break; // // set scissor box // case SU_SCIS0_ID: { int x, y, w, h; scis0.bits = value; x = scis0.sux - 342; y = scis0.suy - 342; w = scis1.suw - scis0.sux + 1; h = scis1.suh - scis0.suy + 1; //GFXError("scissor (%i, %i)-(%i, %i)", x, y, w, h); GL_SetScissor(x, y, w, h); } return; case SU_SCIS1_ID: { int x, y, w, h; scis1.bits = value; x = scis0.sux - 342; y = scis0.suy - 342; w = scis1.suw - scis0.sux + 1; h = scis1.suh - scis0.suy + 1; //GFXError("scissor (%i, %i)-(%i, %i)", x, y, w, h); GL_SetScissor(x, y, w, h); } return; // Pixel Engine block case PE_ZMODE_ID: { static const char* zf[] = { "NEVER", "LESS", "EQUAL", "LEQUAL", "GREATER", "NEQUAL", "GEQUAL", "ALWAYS" }; static uint32_t glzf[] = { GL_NEVER, GL_LESS, GL_EQUAL, GL_LEQUAL, GL_GREATER, GL_NOTEQUAL, GL_GEQUAL, GL_ALWAYS }; pe.zmode.bits = value; /*/ GFXError( "z mode:\n" "compare: %s\n" "func: %s\n" "update: %s", (bpRegs.zmode.enable) ? ("yes") : ("no"), zf[bpRegs.zmode.func], (bpRegs.zmode.mask) ? ("yes") : ("no") ); /*/ if (pe.zmode.enable) { glEnable(GL_DEPTH_TEST); glDepthFunc(glzf[pe.zmode.func]); glDepthMask(pe.zmode.mask); } else glDisable(GL_DEPTH_TEST); } return; // set blending rules case PE_CMODE0_ID: { pe.cmode0.bits = value; static const char* logicop[] = { "clear", "and", "revand", "copy", "invand", "nop", "xor", "or", "nor", "eqv", "inv", "revor", "invcopy", "invor", "nand", "set" }; static const char* sfactor[] = { "zero", "one", "srcclr", "invsrcclr", "srcalpha", "invsrcalpha", "dstalpha", "invdstalpha" }; static const char* dfactor[] = { "zero", "one", "dstclr", "invdstclr", "srcalpha", "invsrcalpha", "dstalpha", "invdstalpha" }; /*/ GFXError( "blend rules\n\n" "blend:%s, logic:%s\n" "logic op : %s\n" "sfactor : %s\n" "dfactor : %s\n", (bpRegs.cmode0.blend_en) ? ("on") : ("off"), (bpRegs.cmode0.logop_en) ? ("on") : ("off"), logicop[bpRegs.cmode0.logop], sfactor[bpRegs.cmode0.sfactor], dfactor[bpRegs.cmode0.dfactor] ); /*/ static uint32_t glsf[] = { GL_ZERO, GL_ONE, GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_DST_ALPHA, GL_ONE_MINUS_DST_ALPHA }; static uint32_t gldf[] = { GL_ZERO, GL_ONE, GL_DST_COLOR, GL_ONE_MINUS_DST_COLOR, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_DST_ALPHA, GL_ONE_MINUS_DST_ALPHA }; // blend hack if (pe.cmode0.blend_en) { glEnable(GL_BLEND); glBlendFunc(glsf[pe.cmode0.sfactor], gldf[pe.cmode0.dfactor]); } else glDisable(GL_BLEND); static uint32_t logop[] = { GL_CLEAR, GL_AND, GL_AND_REVERSE, GL_COPY, GL_AND_INVERTED, GL_NOOP, GL_XOR, GL_OR, GL_NOR, GL_EQUIV, GL_INVERT, GL_OR_REVERSE, GL_COPY_INVERTED, GL_OR_INVERTED, GL_NAND, GL_SET }; // logic operations if (pe.cmode0.logop_en) { glEnable(GL_COLOR_LOGIC_OP); glLogicOp(logop[pe.cmode0.logop]); } else glDisable(GL_COLOR_LOGIC_OP); } return; case PE_CMODE1_ID: pe.cmode1.bits = value; break; // TODO: Make a GP update when copying the frame buffer by Pixel Engine. // draw done case PE_FINISH_ID: { GPFrameDone(); pe_done_num++; if (pe_done_num == 1) { vi.xfb = false; // disable VI output } DONE_INT(); } break; case PE_TOKEN_ID: { pe.token.bits = value; if (pe.token.token == pe.token_int.token) { GPFrameDone(); vi.xfb = false; // disable VI output TOKEN_INT(); } } break; // token case PE_TOKEN_INT_ID: pe.token_int.bits = value; break; case PE_COPY_CLEAR_AR_ID: pe.copy_clear_ar.bits = value; break; case PE_COPY_CLEAR_GB_ID: pe.copy_clear_gb.bits = value; break; case PE_COPY_CLEAR_Z_ID: pe.copy_clear_z.bits = value; break; // // SetImage0. texture image width, height, format // case TX_SETIMAGE0_I0_ID: { teximg0[0].bits = value; texvalid[0][0] = true; tryLoadTex(0); } return; case TX_SETIMAGE0_I1_ID: { teximg0[1].bits = value; texvalid[0][1] = true; //tryLoadTex(1); } return; case TX_SETIMAGE0_I2_ID: { teximg0[2].bits = value; texvalid[0][2] = true; //tryLoadTex(2); } return; case TX_SETIMAGE0_I3_ID: { teximg0[3].bits = value; texvalid[0][3] = true; //tryLoadTex(3); } return; case TX_SETIMAGE0_I4_ID: { teximg0[4].bits = value; texvalid[0][4] = true; //tryLoadTex(4); } return; case TX_SETIMAGE0_I5_ID: { teximg0[5].bits = value; texvalid[0][5] = true; //tryLoadTex(5); } return; case TX_SETIMAGE0_I6_ID: { teximg0[6].bits = value; texvalid[0][6] = true; //tryLoadTex(6); } return; case TX_SETIMAGE0_I7_ID: { teximg0[7].bits = value; texvalid[0][7] = true; //tryLoadTex(7); } return; // SetImage1 // SetImage2 // // SetImage3. texture image base // case TX_SETIMAGE3_I0_ID: { teximg3[0].bits = value; texvalid[3][0] = true; tryLoadTex(0); } return; case TX_SETIMAGE3_I1_ID: { teximg3[1].bits = value; texvalid[3][1] = true; //tryLoadTex(1); } return; case TX_SETIMAGE3_I2_ID: { teximg3[2].bits = value; texvalid[3][2] = true; //tryLoadTex(2); } return; case TX_SETIMAGE3_I3_ID: { teximg3[3].bits = value; texvalid[3][3] = true; //tryLoadTex(3); } return; case TX_SETIMAGE3_I4_ID: { teximg3[4].bits = value; texvalid[3][4] = true; //tryLoadTex(4); } return; case TX_SETIMAGE3_I5_ID: { teximg3[5].bits = value; texvalid[3][5] = true; //tryLoadTex(5); } return; case TX_SETIMAGE3_I6_ID: { teximg3[6].bits = value; texvalid[3][6] = true; //tryLoadTex(6); } return; case TX_SETIMAGE3_I7_ID: { teximg3[7].bits = value; texvalid[3][7] = true; //tryLoadTex(7); } return; // // load tlut // case TX_LOADTLUT0_ID: { loadtlut0.bits = value; LoadTlut( (loadtlut0.base << 5), // ram address (loadtlut1.tmem << 9), // tlut offset loadtlut1.count // tlut size ); } return; case TX_LOADTLUT1_ID: { loadtlut1.bits = value; LoadTlut( (loadtlut0.base << 5), // ram address (loadtlut1.tmem << 9), // tlut offset loadtlut1.count // tlut size ); } return; // // set tlut // case TX_SETTLUT_I0_ID: { settlut[0].bits = value; } return; // // set texture modes // case TX_SETMODE0_I0_ID: { texmode0[0].bits = value; } return; // // texture coord scale // case SU_SSIZE0_ID: case SU_SSIZE1_ID: case SU_SSIZE2_ID: case SU_SSIZE3_ID: case SU_SSIZE4_ID: case SU_SSIZE5_ID: case SU_SSIZE6_ID: case SU_SSIZE7_ID: { int num = (index >> 1) & 1; ssize[num].bits = value; } return; case SU_TSIZE0_ID: case SU_TSIZE1_ID: case SU_TSIZE2_ID: case SU_TSIZE3_ID: case SU_TSIZE4_ID: case SU_TSIZE5_ID: case SU_TSIZE6_ID: case SU_TSIZE7_ID: { int num = (index >> 1) & 1; tsize[num].bits = value; } return; #pragma region "TEV bypass" case TEV_COLOR_ENV_0_ID: tev.color_env[0].bits = value; break; case TEV_ALPHA_ENV_0_ID: tev.alpha_env[0].bits = value; break; case TEV_COLOR_ENV_1_ID: tev.color_env[1].bits = value; break; case TEV_ALPHA_ENV_1_ID: tev.alpha_env[1].bits = value; break; case TEV_COLOR_ENV_2_ID: tev.color_env[2].bits = value; break; case TEV_ALPHA_ENV_2_ID: tev.alpha_env[2].bits = value; break; case TEV_COLOR_ENV_3_ID: tev.color_env[3].bits = value; break; case TEV_ALPHA_ENV_3_ID: tev.alpha_env[3].bits = value; break; case TEV_COLOR_ENV_4_ID: tev.color_env[4].bits = value; break; case TEV_ALPHA_ENV_4_ID: tev.alpha_env[4].bits = value; break; case TEV_COLOR_ENV_5_ID: tev.color_env[5].bits = value; break; case TEV_ALPHA_ENV_5_ID: tev.alpha_env[5].bits = value; break; case TEV_COLOR_ENV_6_ID: tev.color_env[6].bits = value; break; case TEV_ALPHA_ENV_6_ID: tev.alpha_env[6].bits = value; break; case TEV_COLOR_ENV_7_ID: tev.color_env[7].bits = value; break; case TEV_ALPHA_ENV_7_ID: tev.alpha_env[7].bits = value; break; case TEV_COLOR_ENV_8_ID: tev.color_env[8].bits = value; break; case TEV_ALPHA_ENV_8_ID: tev.alpha_env[8].bits = value; break; case TEV_COLOR_ENV_9_ID: tev.color_env[9].bits = value; break; case TEV_ALPHA_ENV_9_ID: tev.alpha_env[9].bits = value; break; case TEV_COLOR_ENV_A_ID: tev.color_env[0xa].bits = value; break; case TEV_ALPHA_ENV_A_ID: tev.alpha_env[0xa].bits = value; break; case TEV_COLOR_ENV_B_ID: tev.color_env[0xb].bits = value; break; case TEV_ALPHA_ENV_B_ID: tev.alpha_env[0xb].bits = value; break; case TEV_COLOR_ENV_C_ID: tev.color_env[0xc].bits = value; break; case TEV_ALPHA_ENV_C_ID: tev.alpha_env[0xc].bits = value; break; case TEV_COLOR_ENV_D_ID: tev.color_env[0xd].bits = value; break; case TEV_ALPHA_ENV_D_ID: tev.alpha_env[0xd].bits = value; break; case TEV_COLOR_ENV_E_ID: tev.color_env[0xe].bits = value; break; case TEV_ALPHA_ENV_E_ID: tev.alpha_env[0xe].bits = value; break; case TEV_COLOR_ENV_F_ID: tev.color_env[0xf].bits = value; break; case TEV_ALPHA_ENV_F_ID: tev.alpha_env[0xf].bits = value; break; case TEV_REGISTERL_0_ID: tev.regl[0].bits = value; break; case TEV_REGISTERH_0_ID: tev.regh[0].bits = value; break; case TEV_REGISTERL_1_ID: tev.regl[1].bits = value; break; case TEV_REGISTERH_1_ID: tev.regh[1].bits = value; break; case TEV_REGISTERL_2_ID: tev.regl[2].bits = value; break; case TEV_REGISTERH_2_ID: tev.regh[2].bits = value; break; case TEV_REGISTERL_3_ID: tev.regl[3].bits = value; break; case TEV_REGISTERH_3_ID: tev.regh[3].bits = value; break; case TEV_RANGE_ADJ_C_ID: tev.rangeadj_control.bits = value; break; case TEV_RANGE_ADJ_0_ID: tev.range_adj[0].bits = value; break; case TEV_RANGE_ADJ_1_ID: tev.range_adj[1].bits = value; break; case TEV_RANGE_ADJ_2_ID: tev.range_adj[2].bits = value; break; case TEV_RANGE_ADJ_3_ID: tev.range_adj[3].bits = value; break; case TEV_RANGE_ADJ_4_ID: tev.range_adj[4].bits = value; break; case TEV_FOG_PARAM_0_ID: tev.fog_param0.bits = value; break; case TEV_FOG_PARAM_1_ID: tev.fog_param1.bits = value; break; case TEV_FOG_PARAM_2_ID: tev.fog_param2.bits = value; break; case TEV_FOG_PARAM_3_ID: tev.fog_param3.bits = value; break; case TEV_FOG_COLOR_ID: tev.fog_color.bits = value; break; case TEV_ALPHAFUNC_ID: tev.alpha_func.bits = value; break; case TEV_Z_ENV_0_ID: tev.zenv0.bits = value; break; case TEV_Z_ENV_1_ID: tev.zenv1.bits = value; break; case TEV_KSEL_0_ID: tev.ksel[0].bits = value; break; case TEV_KSEL_1_ID: tev.ksel[1].bits = value; break; case TEV_KSEL_2_ID: tev.ksel[2].bits = value; break; case TEV_KSEL_3_ID: tev.ksel[3].bits = value; break; case TEV_KSEL_4_ID: tev.ksel[4].bits = value; break; case TEV_KSEL_5_ID: tev.ksel[5].bits = value; break; case TEV_KSEL_6_ID: tev.ksel[6].bits = value; break; case TEV_KSEL_7_ID: tev.ksel[7].bits = value; break; #pragma endregion "TEV bypass" default: { Report(Channel::GP, "Unknown BP load, index: 0x%02X\n", index); break; } } } }