diff --git a/Core/Config.cpp b/Core/Config.cpp index 520002dd73..4fee46c4b7 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -172,6 +172,9 @@ void Config::Load(const char *iniFileName) debugConfig->Get("FontWidth", &iFontWidth, 8); debugConfig->Get("FontHeight", &iFontHeight, 12); + IniFile::Section *gleshacks = iniFile.GetOrCreateSection("GLESHacks"); + gleshacks->Get("PrescaleUV", &bPrescaleUV, false); + KeyMap::LoadFromIni(iniFile); CleanRecent(); diff --git a/Core/Config.h b/Core/Config.h index 614c42fba0..aca6d83603 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -113,6 +113,19 @@ public: int iTouchButtonOpacity; float fButtonScale; + + // GLES backend-specific hacks. Not saved to the ini file, do not add checkboxes. Will be made into + // proper options when good enough. + // PrescaleUV: + // * Applies UV scale/offset when decoding verts. Get rid of some work in the vertex shader, + // saves a uniform upload and is a prerequisite for future optimized hybrid + // (SW skinning, HW transform) skinning. + // * Still has major problems so off by default - need to store tex scale/offset per DeferredDrawCall, + // which currently isn't done so if texscale/offset isn't static (like in Tekken 6) things go wrong. + bool bPrescaleUV; + + // End GLES hacks. + // SystemParam std::string sNickName; int ilanguage; diff --git a/Core/MIPS/ARM/ArmCompFPU.cpp b/Core/MIPS/ARM/ArmCompFPU.cpp index 231a0f61b7..9af3490644 100644 --- a/Core/MIPS/ARM/ArmCompFPU.cpp +++ b/Core/MIPS/ARM/ArmCompFPU.cpp @@ -55,11 +55,11 @@ void Jit::Comp_FPU3op(u32 op) case 1: VSUB(fpr.R(fd), fpr.R(fs), fpr.R(ft)); break; //F(fd) = F(fs) - F(ft); //sub case 2: { //F(fd) = F(fs) * F(ft); //mul u32 nextOp = Memory::Read_Instruction(js.compilerPC + 4); - // Optimise possible if destination is the same - if (fd == ((nextOp>>6) & 0x1F)) { + // Optimization possible if destination is the same + if (fd == (int)((nextOp>>6) & 0x1F)) { // VMUL + VNEG -> VNMUL if (!strcmp(MIPSGetName(nextOp), "neg.s")) { - if (fd == ((nextOp>>11) & 0x1F)) { + if (fd == (int)((nextOp>>11) & 0x1F)) { VNMUL(fpr.R(fd), fpr.R(fs), fpr.R(ft)); EatInstruction(nextOp); } diff --git a/GPU/GLES/VertexDecoder.cpp b/GPU/GLES/VertexDecoder.cpp index f149d06abf..a06cbb22ac 100644 --- a/GPU/GLES/VertexDecoder.cpp +++ b/GPU/GLES/VertexDecoder.cpp @@ -17,8 +17,9 @@ #include "math/lin/matrix4x4.h" -#include "../../Core/MemMap.h" -#include "../ge_constants.h" +#include "Core/Config.h" +#include "Core/MemMap.h" +#include "GPU/ge_constants.h" #include "VertexDecoder.h" #include "VertexShaderGenerator.h" @@ -207,6 +208,27 @@ void VertexDecoder::Step_TcFloatThrough() const uv[1] = uvdata[1]; } +void VertexDecoder::Step_TcU8Prescale() const { + float *uv = (float *)(decoded_ + decFmt.uvoff); + const u8 *uvdata = (const u8 *)(ptr_ + tcoff); + uv[0] = (float)uvdata[0] * (1.f / 128.f) * gstate_c.uScale + gstate_c.uOff; + uv[1] = (float)uvdata[1] * (1.f / 128.f) * gstate_c.vScale + gstate_c.vOff; +} + +void VertexDecoder::Step_TcU16Prescale() const { + float *uv = (float *)(decoded_ + decFmt.uvoff); + const u16 *uvdata = (const u16 *)(ptr_ + tcoff); + uv[0] = (float)uvdata[0] * (1.f / 32768.f) * gstate_c.uScale + gstate_c.uOff; + uv[1] = (float)uvdata[1] * (1.f / 32768.f) * gstate_c.vScale + gstate_c.vOff; +} + +void VertexDecoder::Step_TcFloatPrescale() const { + float *uv = (float *)(decoded_ + decFmt.uvoff); + const float *uvdata = (const float*)(ptr_ + tcoff); + uv[0] = uvdata[0] * gstate_c.uScale + gstate_c.uOff; + uv[1] = uvdata[1] * gstate_c.vScale + gstate_c.vOff; +} + void VertexDecoder::Step_Color565() const { u8 *c = decoded_ + decFmt.c0off; @@ -496,6 +518,13 @@ static const StepFunction tcstep[4] = { &VertexDecoder::Step_TcFloat, }; +static const StepFunction tcstep_prescale[4] = { + 0, + &VertexDecoder::Step_TcU8Prescale, + &VertexDecoder::Step_TcU16Prescale, + &VertexDecoder::Step_TcFloatPrescale, +}; + static const StepFunction tcstep_through[4] = { 0, &VertexDecoder::Step_TcU8, @@ -638,21 +667,26 @@ void VertexDecoder::SetVertexType(u32 fmt) { if (tcalign[tc] > biggest) biggest = tcalign[tc]; - if(g_DoubleTextureCoordinates) - steps_[numSteps_++] = throughmode ? tcstep_through_Remaster[tc] : tcstep_Remaster[tc]; - else - steps_[numSteps_++] = throughmode ? tcstep_through[tc] : tcstep[tc]; - - switch (tc) { - case GE_VTYPE_TC_8BIT >> GE_VTYPE_TC_SHIFT: - decFmt.uvfmt = throughmode ? DEC_U8A_2 : DEC_U8_2; - break; - case GE_VTYPE_TC_16BIT >> GE_VTYPE_TC_SHIFT: - decFmt.uvfmt = throughmode ? DEC_U16A_2 : DEC_U16_2; - break; - case GE_VTYPE_TC_FLOAT >> GE_VTYPE_TC_SHIFT: + if (g_Config.bPrescaleUV && !throughmode && gstate.getTextureFunction() == 0) { + steps_[numSteps_++] = tcstep_prescale[tc]; decFmt.uvfmt = DEC_FLOAT_2; - break; + } else { + if (g_DoubleTextureCoordinates) + steps_[numSteps_++] = throughmode ? tcstep_through_Remaster[tc] : tcstep_Remaster[tc]; + else + steps_[numSteps_++] = throughmode ? tcstep_through[tc] : tcstep[tc]; + + switch (tc) { + case GE_VTYPE_TC_8BIT >> GE_VTYPE_TC_SHIFT: + decFmt.uvfmt = throughmode ? DEC_U8A_2 : DEC_U8_2; + break; + case GE_VTYPE_TC_16BIT >> GE_VTYPE_TC_SHIFT: + decFmt.uvfmt = throughmode ? DEC_U16A_2 : DEC_U16_2; + break; + case GE_VTYPE_TC_FLOAT >> GE_VTYPE_TC_SHIFT: + decFmt.uvfmt = DEC_FLOAT_2; + break; + } } decFmt.uvoff = decOff; diff --git a/GPU/GLES/VertexDecoder.h b/GPU/GLES/VertexDecoder.h index 53b441e5e1..a2fa9ccce6 100644 --- a/GPU/GLES/VertexDecoder.h +++ b/GPU/GLES/VertexDecoder.h @@ -83,24 +83,19 @@ enum { }; // Right now -// - only contains computed information -// - does decoding in nasty branchfilled loops +// - compiles into list of called functions // Future TODO -// - should be cached, not recreated every time -// - will compile into list of called functions // - will compile into lighting fast specialized x86 and ARM -// - will not bother translating components that can be read directly -// by OpenGL ES. Will still have to translate 565 colors and things -// like that. DecodedVertex will not be a fixed struct. Will have to -// do morphing here. class VertexDecoder { public: VertexDecoder() : coloff(0), nrmoff(0), posoff(0) {} ~VertexDecoder() {} + // prim is needed knowledge for a performance hack (PrescaleUV) void SetVertexType(u32 vtype); u32 VertexType() const { return fmt_; } + const DecVtxFormat &GetDecVtxFmt() { return decFmt; } void DecodeVerts(u8 *decoded, const void *verts, int indexLowerBound, int indexUpperBound) const; @@ -117,8 +112,13 @@ public: void Step_TcU8() const; void Step_TcU16() const; - void Step_TcU16Double() const; void Step_TcFloat() const; + + void Step_TcU8Prescale() const; + void Step_TcU16Prescale() const; + void Step_TcFloatPrescale() const; + + void Step_TcU16Double() const; void Step_TcU16Through() const; void Step_TcU16ThroughDouble() const; void Step_TcFloatThrough() const; diff --git a/GPU/GLES/VertexShaderGenerator.cpp b/GPU/GLES/VertexShaderGenerator.cpp index ee6f556c32..9acfe632dc 100644 --- a/GPU/GLES/VertexShaderGenerator.cpp +++ b/GPU/GLES/VertexShaderGenerator.cpp @@ -514,9 +514,15 @@ void GenerateVertexShader(int prim, char *buffer, bool useHWTransform) { // Step 3: UV generation if (doTexture) { + bool prescale = g_Config.bPrescaleUV && !throughmode && gstate.getTextureFunction() == 0; + switch (gstate.getUVGenMode()) { case 0: // Scale-offset. Easy. - WRITE(p, " v_texcoord = a_texcoord * u_uvscaleoffset.xy + u_uvscaleoffset.zw;\n"); + if (prescale) { + WRITE(p, " v_texcoord = a_texcoord;\n"); + } else { + WRITE(p, " v_texcoord = a_texcoord * u_uvscaleoffset.xy + u_uvscaleoffset.zw;\n"); + } break; case 1: // Projection mapping.