diff --git a/GPU/GLES/VertexDecoder.cpp b/GPU/GLES/VertexDecoder.cpp index 7bcab4bc35..f8cae9348b 100644 --- a/GPU/GLES/VertexDecoder.cpp +++ b/GPU/GLES/VertexDecoder.cpp @@ -219,6 +219,7 @@ void VertexDecoder::Step_Color565() const c[1] = Convert6To8((cdata>>5) & 0x3f); c[2] = Convert5To8((cdata>>11) & 0x1f); c[3] = 255; + // Always full alpha. } void VertexDecoder::Step_Color5551() const @@ -229,6 +230,7 @@ void VertexDecoder::Step_Color5551() const c[1] = Convert5To8((cdata>>5) & 0x1f); c[2] = Convert5To8((cdata>>10) & 0x1f); c[3] = (cdata >> 15) ? 255 : 0; + gstate_c.vertexFullAlpha = gstate_c.vertexFullAlpha && c[3] != 0; } void VertexDecoder::Step_Color4444() const @@ -237,6 +239,7 @@ void VertexDecoder::Step_Color4444() const u16 cdata = *(u16*)(ptr_ + coloff); for (int j = 0; j < 4; j++) c[j] = Convert4To8((cdata >> (j * 4)) & 0xF); + gstate_c.vertexFullAlpha = gstate_c.vertexFullAlpha && c[3] == 255; } void VertexDecoder::Step_Color8888() const @@ -244,6 +247,7 @@ void VertexDecoder::Step_Color8888() const u8 *c = decoded_ + decFmt.c0off; const u8 *cdata = (const u8*)(ptr_ + coloff); memcpy(c, cdata, sizeof(u8) * 4); + gstate_c.vertexFullAlpha = gstate_c.vertexFullAlpha && c[3] == 255; } void VertexDecoder::Step_Color565Morph() const @@ -262,6 +266,7 @@ void VertexDecoder::Step_Color565Morph() const c[i] = (u8)col[i]; } c[3] = 255; + // Always full alpha. } void VertexDecoder::Step_Color5551Morph() const @@ -280,6 +285,7 @@ void VertexDecoder::Step_Color5551Morph() const for (int i = 0; i < 4; i++) { c[i] = (u8)col[i]; } + gstate_c.vertexFullAlpha = gstate_c.vertexFullAlpha && c[3] == 255; } void VertexDecoder::Step_Color4444Morph() const @@ -296,6 +302,7 @@ void VertexDecoder::Step_Color4444Morph() const for (int i = 0; i < 4; i++) { c[i] = (u8)col[i]; } + gstate_c.vertexFullAlpha = gstate_c.vertexFullAlpha && c[3] == 255; } void VertexDecoder::Step_Color8888Morph() const @@ -312,6 +319,7 @@ void VertexDecoder::Step_Color8888Morph() const for (int i = 0; i < 4; i++) { c[i] = (u8)(col[i]); } + gstate_c.vertexFullAlpha = gstate_c.vertexFullAlpha && c[3] == 255; } void VertexDecoder::Step_NormalS8() const @@ -841,6 +849,7 @@ void VertexDecoder::DecodeVerts(u8 *decodedptr, const void *verts, int indexLowe jitted_(ptr_, decoded_, count); } else { // Interpret the decode steps + // TODO: Init gstate_c.vertexFullAlpha here? Or in Setup? When is it reset? for (; count; count--) { for (int i = 0; i < numSteps_; i++) { ((*this).*steps_[i])(); diff --git a/GPU/GLES/VertexDecoder.h b/GPU/GLES/VertexDecoder.h index 92643bb5ae..dad0e142c3 100644 --- a/GPU/GLES/VertexDecoder.h +++ b/GPU/GLES/VertexDecoder.h @@ -266,6 +266,6 @@ private: bool CompileStep(const VertexDecoder &dec, int i); void Jit_ApplyWeights(); void Jit_WriteMatrixMul(int outOff, bool pos); - void Jit_WriteMorphColor(int outOff); + void Jit_WriteMorphColor(int outOff, bool checkAlpha = true); const VertexDecoder *dec_; }; diff --git a/GPU/GLES/VertexDecoderArm.cpp b/GPU/GLES/VertexDecoderArm.cpp index 0efba2780a..619d0ebc1d 100644 --- a/GPU/GLES/VertexDecoderArm.cpp +++ b/GPU/GLES/VertexDecoderArm.cpp @@ -61,7 +61,8 @@ static const ARMReg tempReg2 = R4; static const ARMReg tempReg3 = R5; static const ARMReg scratchReg = R6; static const ARMReg scratchReg2 = R7; -static const ARMReg scratchReg3 = R12; +static const ARMReg scratchReg3 = R8; +static const ARMReg fullAlphaReg = R12; static const ARMReg srcReg = R0; static const ARMReg dstReg = R1; static const ARMReg counterReg = R2; @@ -262,6 +263,11 @@ JittedVertexDecoder VertexDecoderJitCache::Compile(const VertexDecoder &dec) { // TODO: Preload scale factors } + if (dec.col) { + // Or LDB and skip the conditional? This is probably cheaper. + MOV(fullAlphaReg, 0xFF); + } + JumpTarget loopStart = GetCodePtr(); // Preload data cache ahead of reading. This offset seems pretty good. PLD(srcReg, 64); @@ -281,6 +287,14 @@ JittedVertexDecoder VertexDecoderJitCache::Compile(const VertexDecoder &dec) { SUBS(counterReg, counterReg, 1); B_CC(CC_NEQ, loopStart); + if (dec.col) { + MOVP2R(tempReg, &gstate_c.textureFullAlpha); + CMP(fullAlphaReg, 0); + SetCC(CC_EQ); + STRB(fullAlphaReg, tempReg, 0); + SetCC(CC_AL); + } + if (NEONSkinning || NEONMorphing) { VPOP(D8, 8); } @@ -664,7 +678,12 @@ void VertexDecoderJitCache::Jit_TcFloatPrescale() { void VertexDecoderJitCache::Jit_Color8888() { LDR(tempReg1, srcReg, dec_->coloff); + // Set flags to determine if alpha != 0xFF. + MVNS(tempReg2, Operand2(tempReg1, ST_ASR, 24)); STR(tempReg1, dstReg, dec_->decFmt.c0off); + SetCC(CC_NEQ); + MOV(fullAlphaReg, 0); + SetCC(CC_AL); } void VertexDecoderJitCache::Jit_Color4444() { @@ -679,10 +698,16 @@ void VertexDecoderJitCache::Jit_Color4444() { ANDI2R(tempReg3, tempReg1, 0xF000, scratchReg); ORR(tempReg2, tempReg2, Operand2(tempReg3, ST_LSL, 12)); - // And saturate. + // And expand to 8 bits. ORR(tempReg1, tempReg2, Operand2(tempReg2, ST_LSL, 4)); STR(tempReg1, dstReg, dec_->decFmt.c0off); + + // Set flags to determine if alpha != 0xFF. + MVNS(tempReg2, Operand2(tempReg1, ST_ASR, 24)); + SetCC(CC_NEQ); + MOV(fullAlphaReg, 0); + SetCC(CC_AL); } void VertexDecoderJitCache::Jit_Color565() { @@ -706,7 +731,7 @@ void VertexDecoderJitCache::Jit_Color565() { ORR(tempReg3, tempReg3, Operand2(tempReg1, ST_LSR, 4)); ORR(tempReg2, tempReg2, Operand2(tempReg3, ST_LSL, 8)); - // Add in full alpha. + // Add in full alpha. No need to update fullAlphaReg. ORI2R(tempReg1, tempReg2, 0xFF000000, scratchReg); STR(tempReg1, dstReg, dec_->decFmt.c0off); @@ -731,8 +756,13 @@ void VertexDecoderJitCache::Jit_Color5551() { // Now we just need alpha. Since we loaded as signed, it'll be extended. ANDI2R(tempReg1, tempReg1, 0xFF000000, scratchReg); ORR(tempReg2, tempReg2, tempReg1); - + + // Set flags to determine if alpha != 0xFF. + MVNS(tempReg3, Operand2(tempReg1, ST_ASR, 24)); STR(tempReg2, dstReg, dec_->decFmt.c0off); + SetCC(CC_NEQ); + MOV(fullAlphaReg, 0); + SetCC(CC_AL); } void VertexDecoderJitCache::Jit_Color8888Morph() { @@ -957,7 +987,7 @@ void VertexDecoderJitCache::Jit_Color565Morph() { } else { VMOV(S11, tempReg3); } - Jit_WriteMorphColor(dec_->decFmt.c0off); + Jit_WriteMorphColor(dec_->decFmt.c0off, false); } // First is the left shift, second is the right shift (against walls, to get the RGBA values.) @@ -1045,13 +1075,16 @@ void VertexDecoderJitCache::Jit_Color5551Morph() { } // Expects RGBA color in S8 - S11, which is Q2. -void VertexDecoderJitCache::Jit_WriteMorphColor(int outOff) { +void VertexDecoderJitCache::Jit_WriteMorphColor(int outOff, bool checkAlpha) { if (NEONMorphing) { ADDI2R(tempReg1, dstReg, outOff, scratchReg); VCVT(I_32 | I_UNSIGNED, neonScratchRegQ, neonScratchRegQ); VQMOVN(I_32 | I_UNSIGNED, neonScratchReg, neonScratchRegQ); VQMOVN(I_16 | I_UNSIGNED, neonScratchReg, neonScratchRegQ); VST1_lane(I_32, neonScratchReg, tempReg1, 0, true); + if (checkAlpha) { + VMOV_neon(I_32, scratchReg, neonScratchReg, 0); + } } else { VCVT(S8, S8, TO_INT); VCVT(S9, S9, TO_INT); @@ -1066,6 +1099,14 @@ void VertexDecoderJitCache::Jit_WriteMorphColor(int outOff) { ORR(scratchReg, scratchReg, Operand2(tempReg3, ST_LSL, 24)); STR(scratchReg, dstReg, outOff); } + + // Set flags to determine if alpha != 0xFF. + if (checkAlpha) { + MVNS(tempReg2, Operand2(scratchReg, ST_ASR, 24)); + SetCC(CC_NEQ); + MOV(fullAlphaReg, 0); + SetCC(CC_AL); + } } void VertexDecoderJitCache::Jit_NormalS8() { diff --git a/GPU/GLES/VertexDecoderX86.cpp b/GPU/GLES/VertexDecoderX86.cpp index 0c770903da..7350fe7924 100644 --- a/GPU/GLES/VertexDecoderX86.cpp +++ b/GPU/GLES/VertexDecoderX86.cpp @@ -187,7 +187,7 @@ JittedVertexDecoder VertexDecoderJitCache::Compile(const VertexDecoder &dec) { if (dec.steps_[i] == &VertexDecoder::Step_TcU8Prescale || dec.steps_[i] == &VertexDecoder::Step_TcU16Prescale || dec.steps_[i] == &VertexDecoder::Step_TcFloatPrescale) { - prescaleStep = true; + prescaleStep = true; } } @@ -671,6 +671,7 @@ void VertexDecoderJitCache::Jit_Color565() { OR(32, R(tempReg2), R(tempReg1)); MOV(32, MDisp(dstReg, dec_->decFmt.c0off), R(tempReg2)); + // Never has alpha, no need to update fullAlphaArg. } void VertexDecoderJitCache::Jit_Color5551() { @@ -840,7 +841,7 @@ void VertexDecoderJitCache::Jit_Color565Morph() { } } - Jit_WriteMorphColor(dec_->decFmt.c0off); + Jit_WriteMorphColor(dec_->decFmt.c0off, false); } // Intentionally in reverse order. @@ -899,7 +900,7 @@ void VertexDecoderJitCache::Jit_Color5551Morph() { Jit_WriteMorphColor(dec_->decFmt.c0off); } -void VertexDecoderJitCache::Jit_WriteMorphColor(int outOff) { +void VertexDecoderJitCache::Jit_WriteMorphColor(int outOff, bool checkAlpha) { // Pack back into a u32. CVTPS2DQ(fpScratchReg, R(fpScratchReg)); PACKSSDW(fpScratchReg, R(fpScratchReg)); @@ -907,11 +908,13 @@ void VertexDecoderJitCache::Jit_WriteMorphColor(int outOff) { MOVD_xmm(MDisp(dstReg, outOff), fpScratchReg); // TODO: May be a faster way to do this without the MOVD. - MOVD_xmm(R(tempReg1), fpScratchReg); - CMP(32, R(tempReg1), Imm32(0xFF000000)); - FixupBranch skip = J_CC(CC_AE, false); - MOV(8, M(&gstate_c.textureFullAlpha), Imm8(0)); - SetJumpTarget(skip); + if (checkAlpha) { + MOVD_xmm(R(tempReg1), fpScratchReg); + CMP(32, R(tempReg1), Imm32(0xFF000000)); + FixupBranch skip = J_CC(CC_AE, false); + MOV(8, M(&gstate_c.textureFullAlpha), Imm8(0)); + SetJumpTarget(skip); + } } // Copy 3 bytes and then a zero. Might as well copy four. @@ -1005,17 +1008,6 @@ void VertexDecoderJitCache::Jit_PosS8Through() { // Through expands into floats, always. Might want to look at changing this. void VertexDecoderJitCache::Jit_PosS16Through() { - // This commented out version is likely slightly faster but treats all three as signed, which - // appears to be wrong. - /* - XORPS(XMM3, R(XMM3)); - MOVQ_xmm(XMM1, MDisp(srcReg, dec_->posoff)); - PUNPCKLWD(XMM1, R(XMM3)); - PSLLD(XMM1, 16); - PSRAD(XMM1, 16); // Ugly sign extension, can be done faster in SSE4 - CVTDQ2PS(XMM3, R(XMM1)); - MOVUPS(MDisp(dstReg, dec_->decFmt.posoff), XMM3); - */ MOVSX(32, 16, tempReg1, MDisp(srcReg, dec_->posoff)); MOVSX(32, 16, tempReg2, MDisp(srcReg, dec_->posoff + 2)); MOVZX(32, 16, tempReg3, MDisp(srcReg, dec_->posoff + 4)); // NOTE: MOVZX