Make the texcoord speedhack a bit less aggressive at eliminating uvscaleoffset uniform updates.

Should fix #4688 and the new problem in #2919 while keeping Frontier Gate Boost working.
This commit is contained in:
Henrik Rydgard 2013-11-30 15:54:20 +01:00
parent 04742e00fc
commit eea8413a82
6 changed files with 72 additions and 44 deletions

View file

@ -732,7 +732,7 @@ void DIRECTX9_GPU::ExecuteOp(u32 op, u32 diff) {
break;
case GE_CMD_VERTEXTYPE:
if (diff)
if (diff & (GE_VTYPE_TC_MASK | GE_VTYPE_THROUGH_MASK))
shaderManager_->DirtyUniform(DIRTY_UVSCALEOFFSET);
break;

View file

@ -1080,8 +1080,9 @@ void GLES_GPU::ExecuteOpInternal(u32 op, u32 diff) {
case GE_CMD_TEXSIZE5:
case GE_CMD_TEXSIZE6:
case GE_CMD_TEXSIZE7:
if (diff)
if (diff) {
gstate_c.textureChanged = true;
}
break;
case GE_CMD_ZBUFPTR:

View file

@ -391,56 +391,81 @@ void LinkedShader::UpdateUniforms(u32 vertType) {
}
// Texturing
if (dirty & DIRTY_UVSCALEOFFSET) {
float uvscaleoff[4];
float invW = 1.0f / (float)gstate_c.curTextureWidth;
float invH = 1.0f / (float)gstate_c.curTextureHeight;
// If this dirty check is changed to true, Frontier Gate Boost works in texcoord speedhack mode.
// This means that it's not a flushing issue.
// It uses GE_TEXMAP_TEXTURE_MATRIX with GE_PROJMAP_UV a lot.
// Can't figure out why it doesn't dirty at the right points though...
if (dirty & DIRTY_UVSCALEOFFSET) {
const float invW = 1.0f / (float)gstate_c.curTextureWidth;
const float invH = 1.0f / (float)gstate_c.curTextureHeight;
const int w = gstate.getTextureWidth(0);
const int h = gstate.getTextureHeight(0);
const float widthFactor = (float)w * invW;
const float heightFactor = (float)h * invH;
static const float rescale[4] = {1.0f, 2*127.5f/128.f, 2*32767.5f/32768.f, 1.0f};
const float factor = rescale[(vertType & GE_VTYPE_TC_MASK) >> GE_VTYPE_TC_SHIFT];
float uvscaleoff[4];
switch (gstate.getUVGenMode()) {
case GE_TEXMAP_TEXTURE_COORDS:
// Not sure what GE_TEXMAP_UNKNOWN is, but seen in Riviera. Treating the same as GE_TEXMAP_TEXTURE_COORDS works.
case GE_TEXMAP_UNKNOWN:
if (g_Config.bPrescaleUV) {
// Shouldn't even get here as we won't use the uniform in the shader.
// We are here but are prescaling UV in the decoder? Let's do the same as in the other case
// except consider *Scale and *Off to be 1 and 0.
int w = gstate.getTextureWidth(0);
int h = gstate.getTextureHeight(0);
float widthFactor = (float)w * invW;
float heightFactor = (float)h * invH;
// Not sure what GE_TEXMAP_UNKNOWN is, but seen in Riviera. Treating the same as GE_TEXMAP_TEXTURE_COORDS works.
if (gstate.getUVGenMode() == GE_TEXMAP_TEXTURE_COORDS || gstate.getUVGenMode() == GE_TEXMAP_UNKNOWN) {
static const float rescale[4] = {1.0f, 2*127.5f/128.f, 2*32767.5f/32768.f, 1.0f};
float factor = rescale[(vertType & GE_VTYPE_TC_MASK) >> GE_VTYPE_TC_SHIFT];
uvscaleoff[0] = factor * widthFactor;
uvscaleoff[1] = factor * heightFactor;
uvscaleoff[2] = 0;
uvscaleoff[3] = 0;
} else {
uvscaleoff[0] = widthFactor;
uvscaleoff[1] = heightFactor;
uvscaleoff[2] = 0.0f;
uvscaleoff[3] = 0.0f;
}
glUniform4fv(u_uvscaleoffset, 1, uvscaleoff);
} else {
int w = gstate.getTextureWidth(0);
int h = gstate.getTextureHeight(0);
float widthFactor = (float)w * invW;
float heightFactor = (float)h * invH;
// Not sure what GE_TEXMAP_UNKNOWN is, but seen in Riviera. Treating the same as GE_TEXMAP_TEXTURE_COORDS works.
static const float rescale[4] = {1.0f, 2*127.5f/128.f, 2*32767.5f/32768.f, 1.0f};
float factor = rescale[(vertType & GE_VTYPE_TC_MASK) >> GE_VTYPE_TC_SHIFT];
if (gstate.getUVGenMode() == GE_TEXMAP_TEXTURE_COORDS || gstate.getUVGenMode() == GE_TEXMAP_UNKNOWN) {
uvscaleoff[0] = gstate_c.uv.uScale * factor * widthFactor;
uvscaleoff[1] = gstate_c.uv.vScale * factor * heightFactor;
uvscaleoff[2] = gstate_c.uv.uOff * widthFactor;
uvscaleoff[3] = gstate_c.uv.vOff * heightFactor;
}
break;
// These two work the same whether or not we prescale UV.
case GE_TEXMAP_TEXTURE_MATRIX:
// UV coords (that need "factor") are only used here if the getUVProjMode == 1.
// Otherwise we just use it to scale the coordinates to the texture.
// Factor is used even if prescale is enabled, because prescale doesn't apply if the mode
// is texture_matrix.
if (gstate.getUVProjMode() == GE_PROJMAP_UV) {
uvscaleoff[0] = widthFactor * factor;
uvscaleoff[1] = heightFactor * factor;
} else {
uvscaleoff[0] = factor * widthFactor;
uvscaleoff[1] = factor * heightFactor;
// In these other modes we only use uvscaleoff to scale to the texture size.
uvscaleoff[0] = widthFactor;
uvscaleoff[1] = heightFactor;
}
uvscaleoff[2] = 0.0f;
uvscaleoff[3] = 0.0f;
break;
case GE_TEXMAP_ENVIRONMENT_MAP:
// In this mode we only use uvscaleoff to scale to the texture size.
uvscaleoff[0] = widthFactor;
uvscaleoff[1] = heightFactor;
uvscaleoff[2] = 0.0f;
uvscaleoff[3] = 0.0f;
break;
default:
ERROR_LOG_REPORT(G3D, "Unexpected UV gen mode: %d", gstate.getUVGenMode());
}
glUniform4fv(u_uvscaleoffset, 1, uvscaleoff);
}
}
// Transform
if (dirty & DIRTY_WORLDMATRIX) {
SetMatrix4x3(u_world, gstate.worldMatrix);
}
// Transform
if (dirty & DIRTY_WORLDMATRIX) {
SetMatrix4x3(u_world, gstate.worldMatrix);
@ -581,8 +606,10 @@ void ShaderManager::DirtyLastShader() { // disables vertex arrays
LinkedShader *ShaderManager::ApplyShader(int prim, u32 vertType) {
if (g_Config.bPrescaleUV)
globalDirty_ &= ~DIRTY_UVSCALEOFFSET;
// This doesn't work - we miss some events that really do need to dirty the prescale.
// like changing the texmapmode.
// if (g_Config.bPrescaleUV)
// globalDirty_ &= ~DIRTY_UVSCALEOFFSET;
if (globalDirty_) {
if (lastShader_)

View file

@ -300,7 +300,6 @@ void TransformDrawEngine::SoftwareTransformAndDraw(
scaleUV = !g_Config.bPrescaleUV;
}
bool skinningEnabled = vertTypeIsSkinningEnabled(vertType);
int w = gstate.getTextureWidth(0);

View file

@ -700,8 +700,8 @@ void VertexDecoder::SetVertexType(u32 fmt, VertexDecoderJitCache *jitCache) {
if (tcalign[tc] > biggest)
biggest = tcalign[tc];
// NOTE: That we check getTextureFunction here means that we must include it in the decoder ID!
if (g_Config.bPrescaleUV && !throughmode && (gstate.getTextureFunction() == 0 || gstate.getTextureFunction() == 3)) {
// NOTE: That we check getUVGenMode here means that we must include it in the decoder ID!
if (g_Config.bPrescaleUV && !throughmode && (gstate.getUVGenMode() == 0 || gstate.getUVGenMode() == 3)) {
steps_[numSteps_++] = tcstep_prescale[tc];
decFmt.uvfmt = DEC_FLOAT_2;
} else {

View file

@ -208,7 +208,7 @@ void GenerateVertexShader(int prim, u32 vertType, char *buffer, bool useHWTransf
// Add all the uniforms we'll need to transform properly.
}
bool prescale = g_Config.bPrescaleUV && !throughmode && gstate.getTextureFunction() == 0;
bool prescale = g_Config.bPrescaleUV && !throughmode && (gstate.getUVGenMode() == GE_TEXMAP_TEXTURE_COORDS || gstate.getUVGenMode() == GE_TEXMAP_UNKNOWN);
if (useHWTransform) {
// When transforming by hardware, we need a great deal more uniforms...
@ -553,6 +553,7 @@ void GenerateVertexShader(int prim, u32 vertType, char *buffer, bool useHWTransf
break;
case GE_PROJMAP_UV: // Use unscaled UV as source
{
// prescale is false here.
static const char *rescaleuv[4] = {"", " * 1.9921875", " * 1.999969482421875", ""}; // 2*127.5f/128.f, 2*32767.5f/32768.f, 1.0f};
const char *factor = rescaleuv[(vertType & GE_VTYPE_TC_MASK) >> GE_VTYPE_TC_SHIFT];
temp_tc = StringFromFormat("vec4(texcoord.xy %s, 0.0, 1.0)", factor);