Mipmaps: Use a uniform to specify the texture lod in SLOPE and CONST modes. Fixes the mipmap test for D3D11, Vulkan and modern GL properly, while keeping Tony Hawk games working.

Also implements increasing the lod level with the render resolution
properly.
This commit is contained in:
Henrik Rydgård 2017-12-08 15:18:37 +01:00
parent 836ae73f92
commit 795ddf16e5
23 changed files with 203 additions and 60 deletions

View File

@ -518,7 +518,11 @@ VirtualFramebuffer *FramebufferManagerCommon::DoSetRenderFrameBuffer(const Frame
gstate_c.curRTHeight = vfb->height;
gstate_c.curRTRenderWidth = vfb->renderWidth;
gstate_c.curRTRenderHeight = vfb->renderHeight;
gstate_c.curRTScale = (float)vfb->renderWidth / (float)vfb->width;
float newRTScale = (float)vfb->renderWidth / (float)vfb->width;
if (gstate_c.curRTScale != newRTScale) {
gstate_c.curRTScale = newRTScale;
gstate_c.Dirty(DIRTY_TEXLOD);
}
return vfb;
}

View File

@ -85,15 +85,15 @@ enum : uint64_t {
DIRTY_BONEMATRIX6 = 1ULL << 30,
DIRTY_BONEMATRIX7 = 1ULL << 31,
// These are for hardware tessellation
DIRTY_BEZIERSPLINE = 1ULL << 32,
DIRTY_BEZIERSPLINE = 1ULL << 32, // For hardware tesselation
DIRTY_TEXCLAMP = 1ULL << 33,
DIRTY_TEXLOD = 1ULL << 34,
// space for 7 more uniforms.
DIRTY_BONE_UNIFORMS = 0xFF000000ULL,
DIRTY_ALL_UNIFORMS = 0x3FFFFFFFFULL,
DIRTY_ALL_UNIFORMS = 0x7FFFFFFFFULL,
DIRTY_ALL_LIGHTS = DIRTY_LIGHT0 | DIRTY_LIGHT1 | DIRTY_LIGHT2 | DIRTY_LIGHT3,
// Other dirty elements that aren't uniforms!

View File

@ -1,3 +1,4 @@
#include <Windows.h>
#include <string>
#include <sstream>
@ -166,6 +167,7 @@ std::string FragmentShaderDesc(const ShaderID &id) {
if (id.Bit(FS_BIT_DO_TEXTURE_PROJ)) desc << "TexProj ";
if (id.Bit(FS_BIT_TEXALPHA)) desc << "TexAlpha ";
if (id.Bit(FS_BIT_TEXTURE_AT_OFFSET)) desc << "TexOffs ";
if (id.Bit(FS_BIT_TEXLOD)) desc << "TexLod ";
if (id.Bit(FS_BIT_LMODE)) desc << "LM ";
if (id.Bit(FS_BIT_ENABLE_FOG)) desc << "Fog ";
if (id.Bit(FS_BIT_COLOR_DOUBLE)) desc << "2x ";
@ -258,6 +260,9 @@ void ComputeFragmentShaderID(ShaderID *id_out) {
id.SetBit(FS_BIT_TEXTURE_AT_OFFSET, textureAtOffset);
}
id.SetBit(FS_BIT_BGRA_TEXTURE, gstate_c.bgraTexture);
if (gstate.getTexLevelMode() != GE_TEXLEVEL_MODE_AUTO && gstate_c.Supports(GPU_SUPPORTS_EXPLICIT_LOD)) {
id.SetBit(FS_BIT_TEXLOD);
}
}
id.SetBit(FS_BIT_LMODE, lmode);

View File

@ -86,6 +86,7 @@ enum {
FS_BIT_BLENDFUNC_B = 42, // 4 bits
FS_BIT_FLATSHADE = 46,
FS_BIT_BGRA_TEXTURE = 47,
FS_BIT_TEXLOD = 48,
// 48+ are free.
};

View File

@ -85,7 +85,6 @@ void BaseUpdateUniforms(UB_VS_FS_Base *ub, uint64_t dirtyUniforms, bool flipView
if (g_Config.iRenderingMode == 0 && g_display_rotation != DisplayRotation::ROTATE_0) {
flippedMatrix = flippedMatrix * g_display_rot_matrix;
}
CopyMatrix4x4(ub->proj, flippedMatrix.getReadPtr());
}
@ -141,6 +140,28 @@ void BaseUpdateUniforms(UB_VS_FS_Base *ub, uint64_t dirtyUniforms, bool flipView
ub->stencil = (float)gstate.getStencilTestRef() / 255.0;
}
if (dirtyUniforms & DIRTY_TEXLOD) {
switch (gstate.getTexLevelMode()) {
case GE_TEXLEVEL_MODE_CONST: {
float scaleLog = TexLog2F((float)gstate_c.curRTScale);
float bias = (float)gstate.getTexLevelOffset16() * (1.0f / 16.0f);
ub->texLod = bias + scaleLog;
break;
}
case GE_TEXLEVEL_MODE_SLOPE:
case GE_TEXLEVEL_MODE_UNKNOWN: {
float scaleLog = TexLog2F((float)gstate_c.curRTScale);
float slopeLog = TexLog2F(fabsf(gstate.getTextureLodSlope()));
float bias = (float)gstate.getTexLevelOffset16() * (1.0f / 16.0f);
ub->texLod = bias + slopeLog + scaleLog + 1.0f; // The 1.0f bias is unclear where it's from...
break;
}
default:
ub->texLod = 0;
break;
}
}
// Note - this one is not in lighting but in transformCommon as it has uses beyond lighting
if (dirtyUniforms & DIRTY_MATAMBIENTALPHA) {
Uint8x3ToFloat4_AlphaUint8(ub->matAmbient, gstate.materialambient, gstate.getMaterialAmbientA());

View File

@ -8,13 +8,13 @@
enum : uint64_t {
DIRTY_BASE_UNIFORMS =
DIRTY_WORLDMATRIX | DIRTY_PROJTHROUGHMATRIX | DIRTY_VIEWMATRIX | DIRTY_TEXMATRIX | DIRTY_ALPHACOLORREF |
DIRTY_PROJMATRIX | DIRTY_FOGCOLOR | DIRTY_FOGCOEF | DIRTY_TEXENV | DIRTY_STENCILREPLACEVALUE |
DIRTY_ALPHACOLORMASK | DIRTY_SHADERBLEND | DIRTY_UVSCALEOFFSET | DIRTY_TEXCLAMP | DIRTY_DEPTHRANGE | DIRTY_MATAMBIENTALPHA |
DIRTY_BEZIERSPLINE,
DIRTY_WORLDMATRIX | DIRTY_PROJTHROUGHMATRIX | DIRTY_VIEWMATRIX | DIRTY_TEXMATRIX | DIRTY_ALPHACOLORREF |
DIRTY_PROJMATRIX | DIRTY_FOGCOLOR | DIRTY_FOGCOEF | DIRTY_TEXENV | DIRTY_STENCILREPLACEVALUE |
DIRTY_ALPHACOLORMASK | DIRTY_SHADERBLEND | DIRTY_UVSCALEOFFSET | DIRTY_TEXCLAMP | DIRTY_DEPTHRANGE | DIRTY_MATAMBIENTALPHA |
DIRTY_BEZIERSPLINE | DIRTY_TEXLOD,
DIRTY_LIGHT_UNIFORMS =
DIRTY_LIGHT0 | DIRTY_LIGHT1 | DIRTY_LIGHT2 | DIRTY_LIGHT3 |
DIRTY_MATDIFFUSE | DIRTY_MATSPECULAR | DIRTY_MATEMISSIVE | DIRTY_AMBIENT,
DIRTY_LIGHT0 | DIRTY_LIGHT1 | DIRTY_LIGHT2 | DIRTY_LIGHT3 |
DIRTY_MATDIFFUSE | DIRTY_MATSPECULAR | DIRTY_MATEMISSIVE | DIRTY_AMBIENT,
};
// TODO: Split into two structs, one for software transform and one for hardware transform, to save space.
@ -28,7 +28,7 @@ struct UB_VS_FS_Base {
float tex[12];
float uvScaleOffset[4];
float depthRange[4];
float fogCoef[2]; float stencil; float pad0;
float fogCoef[2]; float stencil; float texLod;
float matAmbient[4];
int spline_count_u; int spline_count_v; int spline_type_u; int spline_type_v;
// Fragment data
@ -52,6 +52,7 @@ R"( mat4 proj_mtx;
vec4 depthRange;
vec2 fogcoef;
float stencilReplace;
float texLod;
vec4 matambientalpha;
int spline_count_u;
int spline_count_v;
@ -78,6 +79,7 @@ R"( float4x4 u_proj;
float4 u_depthRange;
float2 u_fogcoef;
float u_stencilReplaceValue;
float u_texLod;
float4 u_matambientalpha;
int u_spline_count_u;
int u_spline_count_v;

View File

@ -16,6 +16,7 @@
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#include <algorithm>
#include "math/math_util.h"
#include "Common/ColorConv.h"
#include "Common/MemoryUtil.h"
#include "Core/Config.h"
@ -127,21 +128,6 @@ int TextureCacheCommon::AttachedDrawingHeight() {
return 0;
}
// Produces a signed 1.23.8 value.
static int TexLog2(float delta) {
union FloatBits {
float f;
u32 u;
};
FloatBits f;
f.f = delta;
// Use the exponent as the tex level, and the top mantissa bits for a frac.
// We can't support more than 8 bits of frac, so truncate.
int useful = (f.u >> 15) & 0xFFFF;
// Now offset so the exponent aligns with log2f (exp=127 is 0.)
return useful - 127 * 256;
}
void TextureCacheCommon::GetSamplingParams(int &minFilt, int &magFilt, bool &sClamp, bool &tClamp, float &lodBias, int maxLevel, u32 addr, GETexLevelMode &mode) {
minFilt = gstate.texfilter & 0x7;
magFilt = gstate.isMagnifyFilteringEnabled();
@ -151,13 +137,15 @@ void TextureCacheCommon::GetSamplingParams(int &minFilt, int &magFilt, bool &sCl
GETexLevelMode mipMode = gstate.getTexLevelMode();
mode = mipMode;
bool autoMip = mipMode == GE_TEXLEVEL_MODE_AUTO;
lodBias = (float)gstate.getTexLevelOffset16() * (1.0f / 16.0f);
if (mipMode == GE_TEXLEVEL_MODE_SLOPE) {
lodBias += 1.0f + TexLog2(gstate.getTextureLodSlope()) * (1.0f / 256.0f);
if (autoMip) {
float scaleLog = TexLog2F((float)gstate_c.curRTScale);
lodBias = (float)gstate.getTexLevelOffset16() * (1.0f / 16.0f) + scaleLog;
} else {
lodBias = 0; // We use a uniform instead to look up the level explicitly.
}
// If mip level is forced to zero, disable mipmapping.
bool noMip = maxLevel == 0 || (!autoMip && lodBias <= 0.0f);
bool noMip = maxLevel == 0;
if (IsFakeMipmapChange())
noMip = noMip || !autoMip;
@ -229,9 +217,16 @@ void TextureCacheCommon::UpdateSamplingParams(TexCacheEntry &entry, SamplerCache
break;
case GE_TEXLEVEL_MODE_CONST:
case GE_TEXLEVEL_MODE_UNKNOWN:
key.maxLevel = (int)(lodBias * 256.0f);
key.minLevel = (int)(lodBias * 256.0f);
key.lodBias = 0;
if (gstate_c.Supports(GPU_SUPPORTS_EXPLICIT_LOD)) {
// We handle this in the shader, no restrictions.
key.maxLevel = entry.maxLevel * 256;
key.minLevel = 0;
key.lodBias = 0;
} else {
key.maxLevel = (int)(lodBias * 256.0f);
key.minLevel = (int)(lodBias * 256.0f);
key.lodBias = 0;
}
break;
case GE_TEXLEVEL_MODE_SLOPE:
// It's incorrect to use the slope as a bias. Instead it should be passed

View File

@ -224,6 +224,7 @@ void GPU_D3D11::CheckGPUFeatures() {
features |= GPU_SUPPORTS_INSTANCE_RENDERING;
features |= GPU_SUPPORTS_TEXTURE_LOD_CONTROL;
features |= GPU_SUPPORTS_FBO;
features |= GPU_SUPPORTS_EXPLICIT_LOD;
uint32_t fmt4444 = draw_->GetDataFormatSupport(Draw::DataFormat::A4R4G4B4_UNORM_PACK16);
uint32_t fmt1555 = draw_->GetDataFormatSupport(Draw::DataFormat::A1R5G5B5_UNORM_PACK16);

View File

@ -218,7 +218,11 @@ bool GenerateFragmentShaderHLSL(const FShaderID &id, char *buffer, ShaderLanguag
if (doTextureProjection) {
WRITE(p, " float4 t = tex.Sample(samp, In.v_texcoord.xy / In.v_texcoord.z)%s;\n", bgraTexture ? ".bgra" : "");
} else {
WRITE(p, " float4 t = tex.Sample(samp, %s.xy)%s;\n", texcoord, bgraTexture ? ".bgra" : "");
if (id.Bit(FS_BIT_TEXLOD)) {
WRITE(p, " float4 t = tex.SampleLevel(samp, %s.xy, u_texLod)%s;\n", texcoord, bgraTexture ? ".bgra" : "");
} else {
WRITE(p, " float4 t = tex.Sample(samp, %s.xy)%s;\n", texcoord, bgraTexture ? ".bgra" : "");
}
}
} else {
if (doTextureProjection) {

View File

@ -47,7 +47,8 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, uint64_t *uniform
const char *fragColor0 = "gl_FragColor";
const char *fragColor1 = "fragColor1";
const char *texture = "texture2D";
const char *texelFetch = NULL;
const char *textureLod = nullptr;
const char *texelFetch = nullptr;
bool highpFog = false;
bool highpTexcoord = false;
bool bitwiseOps = false;
@ -61,6 +62,7 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, uint64_t *uniform
WRITE(p, "#version 300 es\n"); // GLSL ES 3.0
fragColor0 = "fragColor0";
texture = "texture";
textureLod = "textureLod";
glslES30 = true;
bitwiseOps = true;
texelFetch = "texelFetch";
@ -113,12 +115,14 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, uint64_t *uniform
if (gl_extensions.VersionGEThan(3, 3, 0)) {
fragColor0 = "fragColor0";
texture = "texture";
textureLod = "textureLod";
glslES30 = true;
bitwiseOps = true;
texelFetch = "texelFetch";
WRITE(p, "#version 330\n");
} else if (gl_extensions.VersionGEThan(3, 0, 0)) {
fragColor0 = "fragColor0";
textureLod = "textureLod";
bitwiseOps = true;
texelFetch = "texelFetch";
WRITE(p, "#version 130\n");
@ -164,6 +168,7 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, uint64_t *uniform
GETexFunc texFunc = (GETexFunc)id.Bits(FS_BIT_TEXFUNC, 3);
bool textureAtOffset = id.Bit(FS_BIT_TEXTURE_AT_OFFSET);
bool texLod = id.Bit(FS_BIT_TEXLOD);
ReplaceBlendType replaceBlend = static_cast<ReplaceBlendType>(id.Bits(FS_BIT_REPLACE_BLEND, 3));
@ -235,6 +240,10 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, uint64_t *uniform
WRITE(p, "uniform vec3 u_fogcolor;\n");
WRITE(p, "%s %s float v_fogdepth;\n", varying, highpFog ? "highp" : "mediump");
}
if (texLod) {
WRITE(p, "uniform float u_texlod;\n");
*uniformMask |= DIRTY_TEXLOD;
}
if (doTexture) {
WRITE(p, "%s %s vec3 v_texcoord;\n", varying, highpTexcoord ? "highp" : "mediump");
}
@ -335,9 +344,17 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, uint64_t *uniform
}
if (doTextureProjection) {
WRITE(p, " vec4 t = %sProj(tex, %s);\n", texture, texcoord);
if (texLod) {
WRITE(p, " vec4 t = %sProj(tex, %s, u_texlod);\n", textureLod, texcoord);
} else {
WRITE(p, " vec4 t = %sProj(tex, %s);\n", texture, texcoord);
}
} else {
WRITE(p, " vec4 t = %s(tex, %s.xy);\n", texture, texcoord);
if (texLod) {
WRITE(p, " vec4 t = %s(tex, %s.xy, u_texlod);\n", textureLod, texcoord);
} else {
WRITE(p, " vec4 t = %s(tex, %s.xy);\n", texture, texcoord);
}
}
WRITE(p, " vec4 p = v_color0;\n");

View File

@ -291,8 +291,13 @@ void GPU_GLES::CheckGPUFeatures() {
if (!gl_extensions.IsGLES)
features |= GPU_SUPPORTS_LOGIC_OP;
if (gl_extensions.GLES3 || !gl_extensions.IsGLES)
if (gl_extensions.GLES3 || !gl_extensions.IsGLES) {
features |= GPU_SUPPORTS_TEXTURE_LOD_CONTROL;
}
if (gl_extensions.GLES3) {
features |= GPU_SUPPORTS_EXPLICIT_LOD;
}
if (gl_extensions.EXT_texture_filter_anisotropic)
features |= GPU_SUPPORTS_ANISOTROPY;

View File

@ -220,6 +220,7 @@ LinkedShader::LinkedShader(VShaderID VSID, Shader *vs, FShaderID FSID, Shader *f
u_uvscaleoffset = glGetUniformLocation(program, "u_uvscaleoffset");
u_texclamp = glGetUniformLocation(program, "u_texclamp");
u_texclampoff = glGetUniformLocation(program, "u_texclampoff");
u_texlod = glGetUniformLocation(program, "u_texlod");
for (int i = 0; i < 4; i++) {
char temp[64];
@ -586,6 +587,31 @@ void LinkedShader::UpdateUniforms(u32 vertType, const VShaderID &vsid) {
if (dirty & DIRTY_STENCILREPLACEVALUE) {
glUniform1f(u_stencilReplaceValue, (float)gstate.getStencilTestRef() * (1.0f / 255.0f));
}
if ((dirty & DIRTY_TEXLOD) && gstate_c.Supports(GPU_SUPPORTS_EXPLICIT_LOD) && u_texlod) {
float lod = 0.0;
switch (gstate.getTexLevelMode()) {
case GE_TEXLEVEL_MODE_CONST: {
float scaleLog = TexLog2F((float)gstate_c.curRTScale);
float bias = (float)gstate.getTexLevelOffset16() * (1.0f / 16.0f);
lod = bias + scaleLog;
break;
}
case GE_TEXLEVEL_MODE_SLOPE:
case GE_TEXLEVEL_MODE_UNKNOWN: {
float scaleLog = TexLog2F((float)gstate_c.curRTScale);
float slopeLog = TexLog2F(fabsf(gstate.getTextureLodSlope()));
float bias = (float)gstate.getTexLevelOffset16() * (1.0f / 16.0f);
lod = bias + slopeLog + scaleLog + 1.0f; // The 1.0f bias is unclear where it's from...
break;
}
default:
lod = 0;
break;
}
glUniform1f(u_texlod, lod);
}
// TODO: Could even set all bones in one go if they're all dirty.
#ifdef USE_BONE_ARRAY
if (u_bone != -1) {

View File

@ -95,6 +95,7 @@ public:
int u_uvscaleoffset;
int u_texclamp;
int u_texclampoff;
int u_texlod;
// Lighting
int u_ambient;

View File

@ -144,17 +144,31 @@ void TextureCacheGLES::UpdateSamplingParams(TexCacheEntry &entry, bool force) {
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_LOD, 0);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, (float)maxLevel);
} else if (mode == GE_TEXLEVEL_MODE_CONST) {
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_LOD, std::max(0.0f, std::min((float)maxLevel, lodBias)));
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, std::max(0.0f, std::min((float)maxLevel, lodBias)));
} else { // mode == GE_TEXLEVEL_MODE_SLOPE) {
// It's incorrect to use the slope as a bias. Instead it should be passed
// into the shader directly as an explicit lod level, with the bias on top. For now, we just kill the
// lodBias in this mode, working around #9772.
#ifndef USING_GLES2
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, 0.0f);
if (gstate_c.Supports(GPU_SUPPORTS_EXPLICIT_LOD)) {
// we handle it in the shader.
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_LOD, 0.0f);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, (float)maxLevel);
} else {
// Abuse min/max to fetch a specific lod.
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_LOD, std::max(0.0f, std::min((float)maxLevel, lodBias)));
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, std::max(0.0f, std::min((float)maxLevel, lodBias)));
}
} else { // mode == GE_TEXLEVEL_MODE_SLOPE) {
if (gstate_c.Supports(GPU_SUPPORTS_EXPLICIT_LOD)) {
// we handle it in the shader.
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_LOD, 0.0f);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, (float)maxLevel);
} else {
// It's incorrect to use the slope as a bias. Instead it should be passed
// into the shader directly as an explicit lod level, with the bias on top. For now, we just kill the
// lodBias in this mode, working around #9772.
#ifndef USING_GLES2
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, 0.0f);
#endif
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_LOD, 0);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, (float)maxLevel);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_LOD, 0);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, (float)maxLevel);
}
}
entry.lodBias = lodBias;
}

View File

@ -130,8 +130,8 @@ const CommonCommandTableEntry commonCommandTable[] = {
{ GE_CMD_TEXSIZE6, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS },
{ GE_CMD_TEXSIZE7, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS },
{ GE_CMD_TEXFORMAT, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_IMAGE },
{ GE_CMD_TEXLEVEL, FLAG_EXECUTEONCHANGE, DIRTY_TEXTURE_PARAMS, &GPUCommon::Execute_TexLevel },
{ GE_CMD_TEXLODSLOPE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS },
{ GE_CMD_TEXLEVEL, FLAG_EXECUTEONCHANGE, DIRTY_TEXTURE_PARAMS | DIRTY_TEXLOD, &GPUCommon::Execute_TexLevel },
{ GE_CMD_TEXLODSLOPE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS | DIRTY_TEXLOD },
{ GE_CMD_TEXADDR0, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_IMAGE | DIRTY_UVSCALEOFFSET },
{ GE_CMD_TEXADDR1, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS },
{ GE_CMD_TEXADDR2, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS },
@ -1315,14 +1315,20 @@ void GPUCommon::Execute_End(u32 op, u32 diff) {
}
void GPUCommon::Execute_TexLevel(u32 op, u32 diff) {
if (diff == 0xFFFFFFFF) return;
if (diff == 0)
return;
gstate.texlevel ^= diff;
// Gran Turismo hack.
if (gstate.getTexLevelMode() != GE_TEXLEVEL_MODE_AUTO && (0x00FF0000 & gstate.texlevel) != 0) {
Flush();
}
gstate.texlevel ^= diff;
gstate_c.Dirty(DIRTY_TEXTURE_PARAMS | DIRTY_FRAGMENTSHADER_STATE);
if (diff & 0x00FF0000) {
gstate_c.Dirty(DIRTY_TEXTURE_PARAMS | DIRTY_TEXLOD);
}
if (diff & 0x00000003) {
gstate_c.Dirty(DIRTY_FRAGMENTSHADER_STATE);
}
}
void GPUCommon::Execute_TexSize0(u32 op, u32 diff) {

View File

@ -147,7 +147,7 @@ struct GPUgstate {
clutformat, // 0xC5
texfilter, // 0xC6
texwrap, // 0xC7
texlevel, // 0xC8
texlevel, // 0xC8 GE_CMD_TEXLEVEL
texfunc, // 0xC9
texenvcolor, // 0xCA
texflush, // 0xCB
@ -291,6 +291,7 @@ struct GPUgstate {
u16 getTextureDimension(int level) const { return texsize[level] & 0xf0f;}
GETexLevelMode getTexLevelMode() const { return static_cast<GETexLevelMode>(texlevel & 0x3); }
int getTexLevelOffset16() const { return (int)(s8)((texlevel >> 16) & 0xFF); }
float getTextureLodSlope() const { return getFloat24(texlodslope); }
bool isTextureMapEnabled() const { return textureMapEnable & 1; }
GETexFunc getTextureFunction() const { return static_cast<GETexFunc>(texfunc & 0x7); }
bool isColorDoublingEnabled() const { return (texfunc & 0x10000) != 0; }
@ -320,7 +321,6 @@ struct GPUgstate {
bool isMinifyFilteringEnabled() const { return (texfilter & 1) != 0; }
bool isMagnifyFilteringEnabled() const { return (texfilter >> 8) & 1; }
int getTextureMaxLevel() const { return (texmode >> 16) & 0x7; }
float getTextureLodSlope() const { return getFloat24(texlodslope); }
// Lighting
bool isLightingEnabled() const { return lightingEnable & 1; }
@ -477,6 +477,8 @@ enum {
GPU_SUPPORTS_VERTEX_TEXTURE_FETCH = FLAG_BIT(11),
GPU_SUPPORTS_TEXTURE_FLOAT = FLAG_BIT(12),
GPU_SUPPORTS_16BIT_FORMATS = FLAG_BIT(13),
GPU_SUPPORTS_EXPLICIT_LOD = FLAG_BIT(14),
// 2 free bits!
GPU_SUPPORTS_LARGE_VIEWPORTS = FLAG_BIT(16),
GPU_SUPPORTS_ACCURATE_DEPTH = FLAG_BIT(17),
GPU_SUPPORTS_VAO = FLAG_BIT(18),

View File

@ -171,9 +171,17 @@ bool GenerateVulkanGLSLFragmentShader(const FShaderID &id, char *buffer) {
}
if (doTextureProjection) {
WRITE(p, " vec4 t = textureProj(tex, %s);\n", texcoord);
if (id.Bit(FS_BIT_TEXLOD)) {
WRITE(p, " vec4 t = textureProjLod(tex, %s, base.texLod);\n", texcoord);
} else {
WRITE(p, " vec4 t = textureProj(tex, %s);\n", texcoord);
}
} else {
WRITE(p, " vec4 t = texture(tex, %s.xy);\n", texcoord);
if (id.Bit(FS_BIT_TEXLOD)) {
WRITE(p, " vec4 t = textureLod(tex, %s.xy, base.texLod);\n", texcoord);
} else {
WRITE(p, " vec4 t = texture(tex, %s.xy);\n", texcoord);
}
}
WRITE(p, " vec4 p = v_color0;\n");

View File

@ -192,6 +192,7 @@ void GPU_Vulkan::CheckGPUFeatures() {
features |= GPU_SUPPORTS_INSTANCE_RENDERING;
features |= GPU_SUPPORTS_VERTEX_TEXTURE_FETCH;
features |= GPU_SUPPORTS_TEXTURE_FLOAT;
features |= GPU_SUPPORTS_EXPLICIT_LOD;
if (vulkan_->GetFeaturesEnabled().wideLines) {
features |= GPU_SUPPORTS_WIDE_LINES;

View File

@ -20,6 +20,7 @@
#endif
#include "base/logging.h"
#include "Common/StringUtils.h"
#include "math/lin/matrix4x4.h"
#include "math/math_util.h"
#include "math/dataconv.h"

View File

@ -61,7 +61,7 @@
#include "Windows/GPU/WindowsVulkanContext.h"
#ifdef _DEBUG
static const bool g_validate_ = true;
static const bool g_validate_ = false;
#else
static const bool g_validate_ = false;
#endif

View File

@ -47,6 +47,35 @@ inline uint32_t log2i(uint32_t val) {
return ret;
}
// Produces a signed 1.23.8 value.
inline int TexLog2(float delta) {
union FloatBits {
float f;
uint32_t u;
};
FloatBits f;
f.f = delta;
// Use the exponent as the tex level, and the top mantissa bits for a frac.
// We can't support more than 8 bits of frac, so truncate.
int useful = (f.u >> 15) & 0xFFFF;
// Now offset so the exponent aligns with log2f (exp=127 is 0.)
return useful - 127 * 256;
}
inline float TexLog2F(float delta) {
union FloatBits {
float f;
uint32_t u;
};
FloatBits f;
f.f = delta;
// Use the exponent as the tex level, and the top mantissa bits for a frac.
// We can't support more than 8 bits of frac, so truncate.
int useful = (f.u >> 15) & 0xFFFF;
// Now offset so the exponent aligns with log2f (exp=127 is 0.)
return (float)(useful - 127 * 256) * (1.0f / 256.0f);
}
#define PI 3.141592653589793f
#ifndef M_PI
#define M_PI 3.141592653589793f

View File

@ -95,7 +95,7 @@ int printUsage(const char *progname, const char *reason)
#if defined(HEADLESSHOST_CLASS)
{
fprintf(stderr, " --graphics=BACKEND use the full gpu backend (slower)\n");
fprintf(stderr, " options: gles, software, directx9, etc.\n");
fprintf(stderr, " options: software, directx9, directx11, vulkan, gles, null.\n");
fprintf(stderr, " --screenshot=FILE compare against a screenshot\n");
}
#endif

View File

@ -27,7 +27,7 @@ PPSSPP_EXECUTABLES = [
PPSSPP_EXE = None
TEST_ROOT = "pspautotests/tests/"
teamcity_mode = False
TIMEOUT = 5
TIMEOUT = 500
class Command(object):
def __init__(self, cmd, data = None):