diff --git a/GPU/Common/VertexDecoderX86.cpp b/GPU/Common/VertexDecoderX86.cpp index 91ae79e276..8ab795fa88 100644 --- a/GPU/Common/VertexDecoderX86.cpp +++ b/GPU/Common/VertexDecoderX86.cpp @@ -890,71 +890,23 @@ static const u32 MEMORY_ALIGNED16(nibbles[4]) = { 0x0f0f0f0f, 0x0f0f0f0f, 0x0f0f static const u32 MEMORY_ALIGNED16(color4444mask[4]) = { 0xf00ff00f, 0xf00ff00f, 0xf00ff00f, 0xf00ff00f, }; void VertexDecoderJitCache::Jit_Color4444() { - // Needs benchmarking. A bit wasteful by only using 1 SSE lane. -#if 0 + // This over-reads slightly, but we assume pos or another component follows anyway. MOVD_xmm(fpScratchReg, MDisp(srcReg, dec_->coloff)); + // Spread to RGBA -> R00GB00A. PUNPCKLBW(fpScratchReg, R(fpScratchReg)); PAND(fpScratchReg, M(color4444mask)); MOVSS(fpScratchReg2, R(fpScratchReg)); MOVSS(fpScratchReg3, R(fpScratchReg)); + // Create 0R000B00 and 00G000A0. PSRLW(fpScratchReg2, 4); PSLLW(fpScratchReg3, 4); + // Combine for the complete set: RRGGBBAA. POR(fpScratchReg, R(fpScratchReg2)); POR(fpScratchReg, R(fpScratchReg3)); - MOVD_xmm(MDisp(dstReg, dec_->decFmt.c0off), fpScratchReg); - return; -#elif 0 - // Alternate approach - MOVD_xmm(XMM3, MDisp(srcReg, dec_->coloff)); - MOVAPS(XMM2, R(XMM3)); - MOVAPS(XMM1, M(nibbles)); - PSLLD(XMM2, 4); - PAND(XMM3, R(XMM1)); - PAND(XMM2, R(XMM1)); - PSRLD(XMM2, 4); - PXOR(XMM1, R(XMM1)); - PUNPCKLBW(XMM2, R(XMM1)); - PUNPCKLBW(XMM3, R(XMM1)); - PSLLD(XMM2, 4); - POR(XMM3, R(XMM2)); - MOVAPS(XMM2, R(XMM3)); - PSLLD(XMM2, 4); - POR(XMM3, R(XMM2)); - MOVD_xmm(MDisp(dstReg, dec_->decFmt.c0off), XMM3); - return; -#endif + MOVD_xmm(R(tempReg1), fpScratchReg); + MOV(32, MDisp(dstReg, dec_->decFmt.c0off), R(tempReg1)); - MOVZX(32, 16, tempReg1, MDisp(srcReg, dec_->coloff)); - - // Pick out A and B, and space them out by a nibble. - MOV(32, R(tempReg2), R(tempReg1)); - MOV(32, R(tempReg3), R(tempReg1)); - AND(32, R(tempReg2), Imm32(0x0000F000)); - AND(32, R(tempReg3), Imm32(0x00000F00)); - SHL(32, R(tempReg2), Imm8(4)); - OR(32, R(tempReg2), R(tempReg3)); - - // Now grab R and G. - MOV(32, R(tempReg3), R(tempReg1)); - AND(32, R(tempReg1), Imm32(0x0000000F)); - AND(32, R(tempReg3), Imm32(0x000000F0)); - - // Currently: 000A0B00, so let's shift once so G is spaced out. - SHL(32, R(tempReg2), Imm8(4)); - OR(32, R(tempReg2), R(tempReg3)); - - // Now: 00A0B0G0, so shift it once more to add R at the bottom. - SHL(32, R(tempReg2), Imm8(4)); - OR(32, R(tempReg2), R(tempReg1)); - - // Now we just need to duplicate the nibbles. - MOV(32, R(tempReg3), R(tempReg2)); - SHL(32, R(tempReg3), Imm8(4)); - OR(32, R(tempReg2), R(tempReg3)); - - MOV(32, MDisp(dstReg, dec_->decFmt.c0off), R(tempReg2)); - - CMP(32, R(tempReg2), Imm32(0xFF000000)); + CMP(32, R(tempReg1), Imm32(0xFF000000)); FixupBranch skip = J_CC(CC_AE, false); MOV(8, M(&gstate_c.vertexFullAlpha), Imm8(0)); SetJumpTarget(skip); @@ -1269,12 +1221,19 @@ void VertexDecoderJitCache::Jit_NormalS16() { } void VertexDecoderJitCache::Jit_NormalFloat() { - MOV(32, R(tempReg1), MDisp(srcReg, dec_->nrmoff)); - MOV(32, R(tempReg2), MDisp(srcReg, dec_->nrmoff + 4)); - MOV(32, R(tempReg3), MDisp(srcReg, dec_->nrmoff + 8)); - MOV(32, MDisp(dstReg, dec_->decFmt.nrmoff), R(tempReg1)); - MOV(32, MDisp(dstReg, dec_->decFmt.nrmoff + 4), R(tempReg2)); - MOV(32, MDisp(dstReg, dec_->decFmt.nrmoff + 8), R(tempReg3)); + if (cpu_info.Mode64bit) { + MOV(64, R(tempReg1), MDisp(srcReg, dec_->nrmoff)); + MOV(32, R(tempReg3), MDisp(srcReg, dec_->nrmoff + 8)); + MOV(64, MDisp(dstReg, dec_->decFmt.posoff), R(tempReg1)); + MOV(32, MDisp(dstReg, dec_->decFmt.posoff + 8), R(tempReg3)); + } else { + MOV(32, R(tempReg1), MDisp(srcReg, dec_->nrmoff)); + MOV(32, R(tempReg2), MDisp(srcReg, dec_->nrmoff + 4)); + MOV(32, R(tempReg3), MDisp(srcReg, dec_->nrmoff + 8)); + MOV(32, MDisp(dstReg, dec_->decFmt.nrmoff), R(tempReg1)); + MOV(32, MDisp(dstReg, dec_->decFmt.nrmoff + 4), R(tempReg2)); + MOV(32, MDisp(dstReg, dec_->decFmt.nrmoff + 8), R(tempReg3)); + } } // This could be a bit shorter with AVX 3-operand instructions and FMA. @@ -1313,7 +1272,7 @@ void VertexDecoderJitCache::Jit_NormalFloatSkin() { // Through expands into floats, always. Might want to look at changing this. void VertexDecoderJitCache::Jit_PosS8Through() { DEBUG_LOG_REPORT_ONCE(vertexS8Through, G3D, "Using S8 positions in throughmode"); - // TODO: SIMD + // SIMD doesn't really matter since this isn't useful on hardware. for (int i = 0; i < 3; i++) { MOVSX(32, 8, tempReg1, MDisp(srcReg, dec_->posoff + i)); CVTSI2SS(fpScratchReg, R(tempReg1)); @@ -1323,15 +1282,25 @@ void VertexDecoderJitCache::Jit_PosS8Through() { // Through expands into floats, always. Might want to look at changing this. void VertexDecoderJitCache::Jit_PosS16Through() { - 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 - CVTSI2SS(fpScratchReg, R(tempReg1)); - MOVSS(MDisp(dstReg, dec_->decFmt.posoff), fpScratchReg); - CVTSI2SS(fpScratchReg, R(tempReg2)); - MOVSS(MDisp(dstReg, dec_->decFmt.posoff + 4), fpScratchReg); - CVTSI2SS(fpScratchReg, R(tempReg3)); - MOVSS(MDisp(dstReg, dec_->decFmt.posoff + 8), fpScratchReg); + if (cpu_info.bSSE4_1) { + MOVD_xmm(fpScratchReg, MDisp(srcReg, dec_->posoff)); + MOVZX(32, 16, tempReg3, MDisp(srcReg, dec_->posoff + 4)); + MOVD_xmm(fpScratchReg2, R(tempReg3)); + PMOVSXWD(fpScratchReg, R(fpScratchReg)); + PUNPCKLQDQ(fpScratchReg, R(fpScratchReg2)); + CVTDQ2PS(fpScratchReg, R(fpScratchReg)); + MOVUPS(MDisp(dstReg, dec_->decFmt.posoff), fpScratchReg); + } else { + 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 + CVTSI2SS(fpScratchReg, R(tempReg1)); + MOVSS(MDisp(dstReg, dec_->decFmt.posoff), fpScratchReg); + CVTSI2SS(fpScratchReg, R(tempReg2)); + MOVSS(MDisp(dstReg, dec_->decFmt.posoff + 4), fpScratchReg); + CVTSI2SS(fpScratchReg, R(tempReg3)); + MOVSS(MDisp(dstReg, dec_->decFmt.posoff + 8), fpScratchReg); + } } void VertexDecoderJitCache::Jit_PosS8() { @@ -1346,12 +1315,19 @@ void VertexDecoderJitCache::Jit_PosS16() { // Just copy 12 bytes. void VertexDecoderJitCache::Jit_PosFloat() { - MOV(32, R(tempReg1), MDisp(srcReg, dec_->posoff)); - MOV(32, R(tempReg2), MDisp(srcReg, dec_->posoff + 4)); - MOV(32, R(tempReg3), MDisp(srcReg, dec_->posoff + 8)); - MOV(32, MDisp(dstReg, dec_->decFmt.posoff), R(tempReg1)); - MOV(32, MDisp(dstReg, dec_->decFmt.posoff + 4), R(tempReg2)); - MOV(32, MDisp(dstReg, dec_->decFmt.posoff + 8), R(tempReg3)); + if (cpu_info.Mode64bit) { + MOV(64, R(tempReg1), MDisp(srcReg, dec_->posoff)); + MOV(32, R(tempReg3), MDisp(srcReg, dec_->posoff + 8)); + MOV(64, MDisp(dstReg, dec_->decFmt.posoff), R(tempReg1)); + MOV(32, MDisp(dstReg, dec_->decFmt.posoff + 8), R(tempReg3)); + } else { + MOV(32, R(tempReg1), MDisp(srcReg, dec_->posoff)); + MOV(32, R(tempReg2), MDisp(srcReg, dec_->posoff + 4)); + MOV(32, R(tempReg3), MDisp(srcReg, dec_->posoff + 8)); + MOV(32, MDisp(dstReg, dec_->decFmt.posoff), R(tempReg1)); + MOV(32, MDisp(dstReg, dec_->decFmt.posoff + 4), R(tempReg2)); + MOV(32, MDisp(dstReg, dec_->decFmt.posoff + 8), R(tempReg3)); + } } void VertexDecoderJitCache::Jit_PosS8Skin() { @@ -1364,7 +1340,6 @@ void VertexDecoderJitCache::Jit_PosS16Skin() { Jit_WriteMatrixMul(dec_->decFmt.posoff, true); } -// Just copy 12 bytes. void VertexDecoderJitCache::Jit_PosFloatSkin() { MOVUPS(XMM3, MDisp(srcReg, dec_->posoff)); Jit_WriteMatrixMul(dec_->decFmt.posoff, true); @@ -1493,7 +1468,6 @@ void VertexDecoderJitCache::Jit_AnyS8Morph(int srcoff, int dstoff) { } } - // TODO: Is it okay that we're over-writing by 4 bytes? Probably... MOVUPS(MDisp(dstReg, dstoff), fpScratchReg); } @@ -1532,7 +1506,6 @@ void VertexDecoderJitCache::Jit_AnyS16Morph(int srcoff, int dstoff) { } } - // TODO: Is it okay that we're over-writing by 4 bytes? Probably... MOVUPS(MDisp(dstReg, dstoff), fpScratchReg); } @@ -1554,7 +1527,6 @@ void VertexDecoderJitCache::Jit_AnyFloatMorph(int srcoff, int dstoff) { } } - // TODO: Is it okay that we're over-writing by 4 bytes? Probably... MOVUPS(MDisp(dstReg, dstoff), fpScratchReg); }