mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-07-11 01:25:07 +02:00
Merge pull request #21813 from hrydgard/optimize-shader-depal
Optimize shader-based palette lookups
This commit is contained in:
@@ -9,7 +9,6 @@
|
||||
const char * const vulkan_glsl_preamble_fs =
|
||||
"#extension GL_ARB_separate_shader_objects : enable\n"
|
||||
"#extension GL_ARB_shading_language_420pack : enable\n"
|
||||
"#extension GL_ARB_conservative_depth : enable\n"
|
||||
"#extension GL_ARB_shader_image_load_store : enable\n"
|
||||
"#define splat3(x) vec3(x)\n"
|
||||
"#define DISCARD discard\n"
|
||||
|
||||
@@ -70,6 +70,8 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu
|
||||
|
||||
bool texture3D = id.Bit(FS_BIT_3D_TEXTURE);
|
||||
bool arrayTexture = id.Bit(FS_BIT_SAMPLE_ARRAY_TEXTURE);
|
||||
bool forceDepthWritesOff = id.Bit(FS_BIT_DEPTH_TEST_NEVER);
|
||||
bool useDiscardStencilBugWorkaround = id.Bit(FS_BIT_NO_DEPTH_CANNOT_DISCARD_STENCIL) && !forceDepthWritesOff;
|
||||
|
||||
ReplaceAlphaType stencilToAlpha = static_cast<ReplaceAlphaType>(id.Bits(FS_BIT_STENCIL_TO_ALPHA, 2));
|
||||
|
||||
@@ -87,6 +89,10 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu
|
||||
if (gl_extensions.OES_texture_3D && texture3D) {
|
||||
extensions.push_back("#extension GL_OES_texture_3D: enable");
|
||||
}
|
||||
if (useDiscardStencilBugWorkaround) {
|
||||
// The only use of layout (depth_...)
|
||||
extensions.push_back("#extension GL_ARB_conservative_depth : enable\n");
|
||||
}
|
||||
}
|
||||
|
||||
ShaderWriterFlags flags = ShaderWriterFlags::NONE;
|
||||
@@ -129,6 +135,7 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu
|
||||
}
|
||||
|
||||
ShaderDepalMode shaderDepalMode = (ShaderDepalMode)id.Bits(FS_BIT_SHADER_DEPAL_MODE, 2);
|
||||
GEBufferFormat shaderDepalFmt = (GEBufferFormat)(id.Bits(FS_BIT_SHADER_DEPAL_FORMAT, 3));
|
||||
if (texture3D) {
|
||||
shaderDepalMode = ShaderDepalMode::OFF;
|
||||
}
|
||||
@@ -159,9 +166,6 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu
|
||||
shading = doFlatShading ? "flat" : "";
|
||||
}
|
||||
|
||||
bool forceDepthWritesOff = id.Bit(FS_BIT_DEPTH_TEST_NEVER);
|
||||
|
||||
bool useDiscardStencilBugWorkaround = id.Bit(FS_BIT_NO_DEPTH_CANNOT_DISCARD_STENCIL) && !forceDepthWritesOff;
|
||||
|
||||
GEBlendSrcFactor replaceBlendFuncA = (GEBlendSrcFactor)id.Bits(FS_BIT_BLENDFUNC_A, 4);
|
||||
GEBlendDstFactor replaceBlendFuncB = (GEBlendDstFactor)id.Bits(FS_BIT_BLENDFUNC_B, 4);
|
||||
@@ -689,74 +693,100 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu
|
||||
WRITE(p, " } else {\n");
|
||||
WRITE(p, " uv_round = uv;\n");
|
||||
WRITE(p, " }\n");
|
||||
|
||||
p.C(" highp vec4 t = ").SampleTexture2D("tex", "uv_round").C(";\n");
|
||||
p.C(" highp vec4 t1 = ").SampleTexture2DOffset("tex", "uv_round", 1, 0).C(";\n");
|
||||
p.C(" highp vec4 t2 = ").SampleTexture2DOffset("tex", "uv_round", 0, 1).C(";\n");
|
||||
p.C(" highp vec4 t3 = ").SampleTexture2DOffset("tex", "uv_round", 1, 1).C(";\n");
|
||||
|
||||
WRITE(p, " uint depalMask = (u_depal_mask_shift_off_fmt & 0xFFu);\n");
|
||||
WRITE(p, " uint depalShift = (u_depal_mask_shift_off_fmt >> 0x8u) & 0xFFu;\n");
|
||||
WRITE(p, " uint depalOffset = ((u_depal_mask_shift_off_fmt >> 0x10u) & 0xFFu) << 0x4u;\n");
|
||||
WRITE(p, " uint depalFmt = (u_depal_mask_shift_off_fmt >> 0x18u) & 0x3u;\n");
|
||||
WRITE(p, " uvec4 col; uint index0; uint index1; uint index2; uint index3;\n");
|
||||
WRITE(p, " switch (int(depalFmt)) {\n"); // We might want to include fmt in the shader ID if this is a performance issue.
|
||||
WRITE(p, " case 0:\n"); // 565
|
||||
WRITE(p, " col = uvec4(t.rgb * vec3(31.99, 63.99, 31.99), 0);\n");
|
||||
WRITE(p, " index0 = (col.b << 0xBu) | (col.g << 0x5u) | (col.r);\n");
|
||||
WRITE(p, " if (bilinear) {\n");
|
||||
WRITE(p, " col = uvec4(t1.rgb * vec3(31.99, 63.99, 31.99), 0);\n");
|
||||
WRITE(p, " index1 = (col.b << 0xBu) | (col.g << 0x5u) | (col.r);\n");
|
||||
WRITE(p, " col = uvec4(t2.rgb * vec3(31.99, 63.99, 31.99), 0);\n");
|
||||
WRITE(p, " index2 = (col.b << 0xBu) | (col.g << 0x5u) | (col.r);\n");
|
||||
WRITE(p, " col = uvec4(t3.rgb * vec3(31.99, 63.99, 31.99), 0);\n");
|
||||
WRITE(p, " index3 = (col.b << 0xBu) | (col.g << 0x5u) | (col.r);\n");
|
||||
WRITE(p, " }\n");
|
||||
WRITE(p, " break;\n");
|
||||
WRITE(p, " case 1:\n"); // 5551
|
||||
WRITE(p, " col = uvec4(t.rgba * vec4(31.99, 31.99, 31.99, 1.0));\n");
|
||||
WRITE(p, " index0 = (col.a << 0xFu) | (col.b << 0xAu) | (col.g << 0x5u) | (col.r);\n");
|
||||
WRITE(p, " if (bilinear) {\n");
|
||||
WRITE(p, " col = uvec4(t1.rgba * vec4(31.99, 31.99, 31.99, 1.0));\n");
|
||||
WRITE(p, " index1 = (col.a << 0xFu) | (col.b << 0xAu) | (col.g << 0x5u) | (col.r);\n");
|
||||
WRITE(p, " col = uvec4(t2.rgba * vec4(31.99, 31.99, 31.99, 1.0));\n");
|
||||
WRITE(p, " index2 = (col.a << 0xFu) | (col.b << 0xAu) | (col.g << 0x5u) | (col.r);\n");
|
||||
WRITE(p, " col = uvec4(t3.rgba * vec4(31.99, 31.99, 31.99, 1.0));\n");
|
||||
WRITE(p, " index3 = (col.a << 0xFu) | (col.b << 0xAu) | (col.g << 0x5u) | (col.r);\n");
|
||||
WRITE(p, " }\n");
|
||||
WRITE(p, " break;\n");
|
||||
WRITE(p, " case 2:\n"); // 4444
|
||||
WRITE(p, " col = uvec4(t.rgba * 15.99);\n");
|
||||
WRITE(p, " index0 = (col.a << 0xCu) | (col.b << 0x8u) | (col.g << 0x4u) | (col.r);\n");
|
||||
WRITE(p, " if (bilinear) {\n");
|
||||
WRITE(p, " col = uvec4(t1.rgba * 15.99);\n");
|
||||
WRITE(p, " index1 = (col.a << 0xCu) | (col.b << 0x8u) | (col.g << 0x4u) | (col.r);\n");
|
||||
WRITE(p, " col = uvec4(t2.rgba * 15.99);\n");
|
||||
WRITE(p, " index2 = (col.a << 0xCu) | (col.b << 0x8u) | (col.g << 0x4u) | (col.r);\n");
|
||||
WRITE(p, " col = uvec4(t3.rgba * 15.99);\n");
|
||||
WRITE(p, " index3 = (col.a << 0xCu) | (col.b << 0x8u) | (col.g << 0x4u) | (col.r);\n");
|
||||
WRITE(p, " }\n");
|
||||
WRITE(p, " break;\n");
|
||||
WRITE(p, " case 3:\n"); // 8888
|
||||
WRITE(p, " col = uvec4(t.rgba * 255.99);\n");
|
||||
WRITE(p, " index0 = (col.a << 0x18u) | (col.b << 0x10u) | (col.g << 0x8u) | (col.r);\n");
|
||||
WRITE(p, " if (bilinear) {\n");
|
||||
WRITE(p, " col = uvec4(t1.rgba * 255.99);\n");
|
||||
WRITE(p, " index1 = (col.a << 0x18u) | (col.b << 0x10u) | (col.g << 0x8u) | (col.r);\n");
|
||||
WRITE(p, " col = uvec4(t2.rgba * 255.99);\n");
|
||||
WRITE(p, " index2 = (col.a << 0x18u) | (col.b << 0x10u) | (col.g << 0x8u) | (col.r);\n");
|
||||
WRITE(p, " col = uvec4(t3.rgba * 255.99);\n");
|
||||
WRITE(p, " index3 = (col.a << 0x18u) | (col.b << 0x10u) | (col.g << 0x8u) | (col.r);\n");
|
||||
WRITE(p, " }\n");
|
||||
WRITE(p, " break;\n");
|
||||
WRITE(p, " };\n");
|
||||
|
||||
switch (shaderDepalFmt) {
|
||||
case GE_FORMAT_565:
|
||||
WRITE(p, " col = uvec4(t.rgb * vec3(31.99, 63.99, 31.99), 0);\n");
|
||||
WRITE(p, " index0 = (col.b << 0xBu) | (col.g << 0x5u) | (col.r);\n");
|
||||
WRITE(p, " if (bilinear) {\n");
|
||||
WRITE(p, " col = uvec4(t1.rgb * vec3(31.99, 63.99, 31.99), 0);\n");
|
||||
WRITE(p, " index1 = (col.b << 0xBu) | (col.g << 0x5u) | (col.r);\n");
|
||||
WRITE(p, " col = uvec4(t2.rgb * vec3(31.99, 63.99, 31.99), 0);\n");
|
||||
WRITE(p, " index2 = (col.b << 0xBu) | (col.g << 0x5u) | (col.r);\n");
|
||||
WRITE(p, " col = uvec4(t3.rgb * vec3(31.99, 63.99, 31.99), 0);\n");
|
||||
WRITE(p, " index3 = (col.b << 0xBu) | (col.g << 0x5u) | (col.r);\n");
|
||||
WRITE(p, " }\n");
|
||||
break;
|
||||
case GE_FORMAT_5551:
|
||||
WRITE(p, " col = uvec4(t.rgba * vec4(31.99, 31.99, 31.99, 1.0));\n");
|
||||
WRITE(p, " index0 = (col.a << 0xFu) | (col.b << 0xAu) | (col.g << 0x5u) | (col.r);\n");
|
||||
WRITE(p, " if (bilinear) {\n");
|
||||
WRITE(p, " col = uvec4(t1.rgba * vec4(31.99, 31.99, 31.99, 1.0));\n");
|
||||
WRITE(p, " index1 = (col.a << 0xFu) | (col.b << 0xAu) | (col.g << 0x5u) | (col.r);\n");
|
||||
WRITE(p, " col = uvec4(t2.rgba * vec4(31.99, 31.99, 31.99, 1.0));\n");
|
||||
WRITE(p, " index2 = (col.a << 0xFu) | (col.b << 0xAu) | (col.g << 0x5u) | (col.r);\n");
|
||||
WRITE(p, " col = uvec4(t3.rgba * vec4(31.99, 31.99, 31.99, 1.0));\n");
|
||||
WRITE(p, " index3 = (col.a << 0xFu) | (col.b << 0xAu) | (col.g << 0x5u) | (col.r);\n");
|
||||
WRITE(p, " }\n");
|
||||
break;
|
||||
case GE_FORMAT_4444:
|
||||
WRITE(p, " col = uvec4(t.rgba * 15.99);\n");
|
||||
WRITE(p, " index0 = (col.a << 0xCu) | (col.b << 0x8u) | (col.g << 0x4u) | (col.r);\n");
|
||||
WRITE(p, " if (bilinear) {\n");
|
||||
WRITE(p, " col = uvec4(t1.rgba * 15.99);\n");
|
||||
WRITE(p, " index1 = (col.a << 0xCu) | (col.b << 0x8u) | (col.g << 0x4u) | (col.r);\n");
|
||||
WRITE(p, " col = uvec4(t2.rgba * 15.99);\n");
|
||||
WRITE(p, " index2 = (col.a << 0xCu) | (col.b << 0x8u) | (col.g << 0x4u) | (col.r);\n");
|
||||
WRITE(p, " col = uvec4(t3.rgba * 15.99);\n");
|
||||
WRITE(p, " index3 = (col.a << 0xCu) | (col.b << 0x8u) | (col.g << 0x4u) | (col.r);\n");
|
||||
WRITE(p, " }\n");
|
||||
break;
|
||||
case GE_FORMAT_8888:
|
||||
WRITE(p, " col = uvec4(t.rgba * 255.99);\n");
|
||||
WRITE(p, " index0 = (col.a << 0x18u) | (col.b << 0x10u) | (col.g << 0x8u) | (col.r);\n");
|
||||
WRITE(p, " if (bilinear) {\n");
|
||||
WRITE(p, " col = uvec4(t1.rgba * 255.99);\n");
|
||||
WRITE(p, " index1 = (col.a << 0x18u) | (col.b << 0x10u) | (col.g << 0x8u) | (col.r);\n");
|
||||
WRITE(p, " col = uvec4(t2.rgba * 255.99);\n");
|
||||
WRITE(p, " index2 = (col.a << 0x18u) | (col.b << 0x10u) | (col.g << 0x8u) | (col.r);\n");
|
||||
WRITE(p, " col = uvec4(t3.rgba * 255.99);\n");
|
||||
WRITE(p, " index3 = (col.a << 0x18u) | (col.b << 0x10u) | (col.g << 0x8u) | (col.r);\n");
|
||||
WRITE(p, " }\n");
|
||||
break;
|
||||
case GE_FORMAT_CLUT8:
|
||||
WRITE(p, " index0 = uint(t.r * 255.99);\n");
|
||||
WRITE(p, " if (bilinear) {\n");
|
||||
WRITE(p, " index1 = uint(t1.r * 255.99);\n");
|
||||
WRITE(p, " index2 = uint(t2.r * 255.99);\n");
|
||||
WRITE(p, " index3 = uint(t3.r * 255.99);\n");
|
||||
WRITE(p, " }\n");
|
||||
break;
|
||||
case GE_FORMAT_DEPTH16:
|
||||
WRITE(p, " index0 = uint(t.r * 65535.99);\n");
|
||||
WRITE(p, " if (bilinear) {\n");
|
||||
WRITE(p, " index1 = uint(t1.r * 65535.99);\n");
|
||||
WRITE(p, " index2 = uint(t2.r * 65535.99);\n");
|
||||
WRITE(p, " index3 = uint(t3.r * 65535.99);\n");
|
||||
WRITE(p, " }\n");
|
||||
break;
|
||||
default:
|
||||
// Invalid, but the unit test can produce this inadvertently.
|
||||
WRITE(p, " index0 = 0u;\n");
|
||||
WRITE(p, " index1 = 0u;\n");
|
||||
WRITE(p, " index2 = 0u;\n");
|
||||
WRITE(p, " index3 = 0u;\n");
|
||||
break;
|
||||
}
|
||||
WRITE(p, " index0 = ((index0 >> depalShift) & depalMask) | depalOffset;\n");
|
||||
p.C(" t = ").LoadTexture2D("pal", "ivec2(index0, 0)", 0).C(";\n");
|
||||
WRITE(p, " if (bilinear && !(index0 == index1 && index1 == index2 && index2 == index3)) {\n");
|
||||
WRITE(p, " index1 = ((index1 >> depalShift) & depalMask) | depalOffset;\n");
|
||||
WRITE(p, " index2 = ((index2 >> depalShift) & depalMask) | depalOffset;\n");
|
||||
WRITE(p, " index3 = ((index3 >> depalShift) & depalMask) | depalOffset;\n");
|
||||
p.C(" t1 = ").LoadTexture2D("pal", "ivec2(index1, 0)", 0).C(";\n");
|
||||
p.C(" t2 = ").LoadTexture2D("pal", "ivec2(index2, 0)", 0).C(";\n");
|
||||
p.C(" t3 = ").LoadTexture2D("pal", "ivec2(index3, 0)", 0).C(";\n");
|
||||
p.C(" t1 = ").LoadTexture2D("pal", "ivec2(index1, 0)", 0).C(";\n");
|
||||
p.C(" t2 = ").LoadTexture2D("pal", "ivec2(index2, 0)", 0).C(";\n");
|
||||
p.C(" t3 = ").LoadTexture2D("pal", "ivec2(index3, 0)", 0).C(";\n");
|
||||
WRITE(p, " t = mix(t, t1, fraction.x);\n");
|
||||
WRITE(p, " t2 = mix(t2, t3, fraction.x);\n");
|
||||
WRITE(p, " t = mix(t, t2, fraction.y);\n");
|
||||
|
||||
+19
-6
@@ -202,12 +202,6 @@ std::string FragmentShaderDesc(const FShaderID &id) {
|
||||
if (id.Bit(FS_BIT_FLATSHADE)) desc << "Flat ";
|
||||
if (id.Bit(FS_BIT_BGRA_TEXTURE)) desc << "BGRA ";
|
||||
if (id.Bit(FS_BIT_DEPTH_TEST_NEVER)) desc << "DepthNever ";
|
||||
switch ((ShaderDepalMode)id.Bits(FS_BIT_SHADER_DEPAL_MODE, 2)) {
|
||||
case ShaderDepalMode::OFF: break;
|
||||
case ShaderDepalMode::NORMAL: desc << "Depal "; break;
|
||||
case ShaderDepalMode::SMOOTHED: desc << "SmoothDepal "; break;
|
||||
case ShaderDepalMode::CLUT8_8888: desc << "CLUT8From8888Depal"; break;
|
||||
}
|
||||
if (id.Bit(FS_BIT_COLOR_WRITEMASK)) desc << "WriteMask ";
|
||||
if (id.Bit(FS_BIT_SHADER_TEX_CLAMP)) {
|
||||
desc << "TClamp";
|
||||
@@ -275,6 +269,20 @@ std::string FragmentShaderDesc(const FShaderID &id) {
|
||||
if (id.Bit(FS_BIT_USE_FRAMEBUFFER_FETCH)) desc << "(fetch)";
|
||||
if (id.Bit(FS_BIT_MINMAX_DISCARD)) desc << "FragMinMaxDiscard ";
|
||||
if (id.Bit(FS_BIT_DEPTH_CLAMP)) desc << "FragDepthClamp ";
|
||||
|
||||
const ShaderDepalMode depalMode = (ShaderDepalMode)id.Bits(FS_BIT_SHADER_DEPAL_MODE, 2);
|
||||
switch (depalMode) {
|
||||
case ShaderDepalMode::OFF: break;
|
||||
case ShaderDepalMode::NORMAL: desc << "Depal(";
|
||||
{
|
||||
const GEBufferFormat shaderDepalFormat = (GEBufferFormat)id.Bits(FS_BIT_SHADER_DEPAL_FORMAT, 3);
|
||||
desc << GeBufferFormatToString(shaderDepalFormat) << ") ";
|
||||
break;
|
||||
}
|
||||
case ShaderDepalMode::SMOOTHED: desc << "SmoothDepal "; break;
|
||||
case ShaderDepalMode::CLUT8_8888: desc << "CLUT8From8888Depal"; break;
|
||||
}
|
||||
|
||||
return desc.str();
|
||||
}
|
||||
|
||||
@@ -324,6 +332,10 @@ void ComputeFragmentShaderID(FShaderID *id_out, const ComputedPipelineState &pip
|
||||
bool enableTexAlpha = gstate.isTextureAlphaUsed();
|
||||
|
||||
ShaderDepalMode shaderDepalMode = gstate_c.shaderDepalMode;
|
||||
GEBufferFormat shaderDepalFormat = {};
|
||||
if (shaderDepalMode == ShaderDepalMode::NORMAL) {
|
||||
shaderDepalFormat = gstate_c.depalTextureFormat;
|
||||
}
|
||||
|
||||
bool colorWriteMask = pipelineState.maskState.applyFramebufferRead;
|
||||
ReplaceBlendType replaceBlend = pipelineState.blendState.replaceBlend;
|
||||
@@ -343,6 +355,7 @@ void ComputeFragmentShaderID(FShaderID *id_out, const ComputedPipelineState &pip
|
||||
}
|
||||
id.SetBit(FS_BIT_BGRA_TEXTURE, gstate_c.bgraTexture);
|
||||
id.SetBits(FS_BIT_SHADER_DEPAL_MODE, 2, (int)shaderDepalMode);
|
||||
id.SetBits(FS_BIT_SHADER_DEPAL_FORMAT, 3, (int)shaderDepalFormat);
|
||||
id.SetBit(FS_BIT_3D_TEXTURE, gstate_c.curTextureIs3D);
|
||||
}
|
||||
|
||||
|
||||
@@ -88,7 +88,7 @@ enum FShaderBit : uint8_t {
|
||||
FS_BIT_SHADER_TEX_CLAMP = 5,
|
||||
FS_BIT_CLAMP_S = 6,
|
||||
FS_BIT_CLAMP_T = 7,
|
||||
// Free bits: 8-11
|
||||
FS_BIT_SHADER_DEPAL_FORMAT = 8, // 3 bits (GEBufferFormat), connected to FS_BIT_SHADER_DEPAL_MODE
|
||||
FS_BIT_ALPHA_TEST = 12,
|
||||
FS_BIT_ALPHA_TEST_FUNC = 13, // 3 bits
|
||||
FS_BIT_ALPHA_AGAINST_ZERO = 16,
|
||||
|
||||
@@ -191,7 +191,7 @@ void BaseUpdateUniforms(UB_VS_FS_Base *ub, uint64_t dirtyUniforms, bool useBuffe
|
||||
int indexMask = gstate.getClutIndexMask();
|
||||
int indexShift = gstate.getClutIndexShift();
|
||||
int indexOffset = gstate.getClutIndexStartPos() >> 4;
|
||||
int format = gstate_c.depalFramebufferFormat;
|
||||
int format = gstate_c.depalTextureFormat;
|
||||
uint32_t val = BytesToUint32(indexMask, indexShift, indexOffset, format);
|
||||
// Poke in a bilinear filter flag in the top bit.
|
||||
if (gstate.isMagnifyFilteringEnabled())
|
||||
|
||||
@@ -1012,20 +1012,41 @@ static bool ExpandRectangles(int vertexCount, int &numDecodedVerts, int vertsSiz
|
||||
}
|
||||
|
||||
bool pixelMapped = g_Config.bSmart2DTexFiltering && !gstate_c.textureIsVideo;
|
||||
if (pixelMapped) {
|
||||
// Check for pixel mapping. If we find pixel mapping, abandon spriteBorderFix.
|
||||
for (int i = 0; i < vertexCount; i += 2) {
|
||||
const TransformedVertex &transVtxTL = transformed[indsIn[i + 0]];
|
||||
const TransformedVertex &transVtxBR = transformed[indsIn[i + 1]];
|
||||
|
||||
if (pixelMapped) {
|
||||
float dx = transVtxBR.x - transVtxTL.x;
|
||||
float dy = transVtxBR.y - transVtxTL.y;
|
||||
float du = transVtxBR.u - transVtxTL.u;
|
||||
float dv = transVtxBR.v - transVtxTL.v;
|
||||
|
||||
// NOTE: We will accept it as pixel mapped if only one dimension is stretched. This fixes dialog frames in FFI.
|
||||
// Though, there could be false positives in other games due to this. Let's see if it is a problem...
|
||||
if (dx <= 0 || dy <= 0 || (dx != du && dy != dv)) {
|
||||
pixelMapped = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float spriteBorderFixL = 0.0f;
|
||||
float spriteBorderFixR = 0.0f;
|
||||
float spriteBorderFixT = 0.0f;
|
||||
float spriteBorderFixB = 0.0f;
|
||||
float spriteBorderFix = PSP_CoreParameter().compat.flags().SpriteBorderFix;
|
||||
if (spriteBorderFix && !ShouldApplySpriteBorderFix(gstate)) {
|
||||
spriteBorderFix = 0.0f;
|
||||
const float spriteBorderFix = PSP_CoreParameter().compat.flags().SpriteBorderFix;
|
||||
if (pixelMapped || (spriteBorderFix && !ShouldApplySpriteBorderFix(gstate))) {
|
||||
// Don't apply spriteBorderFix if pixel mapped.
|
||||
} else {
|
||||
if (spriteBorderFix < 0.0f) {
|
||||
spriteBorderFixL = (spriteBorderFix / uScale) / gstate_c.curTextureWidth;
|
||||
spriteBorderFixT = (spriteBorderFix / vScale) / gstate_c.curTextureHeight;
|
||||
spriteBorderFixR = (spriteBorderFix / uScale) / gstate_c.curTextureWidth;
|
||||
spriteBorderFixB = (spriteBorderFix / vScale) / gstate_c.curTextureHeight;
|
||||
spriteBorderFixL = (-spriteBorderFix / uScale) / gstate_c.curTextureWidth;
|
||||
spriteBorderFixT = (-spriteBorderFix / vScale) / gstate_c.curTextureHeight;
|
||||
spriteBorderFixR = (-spriteBorderFix / uScale) / gstate_c.curTextureWidth;
|
||||
spriteBorderFixB = (-spriteBorderFix / vScale) / gstate_c.curTextureHeight;
|
||||
} else if (spriteBorderFix > 0.0f) {
|
||||
spriteBorderFixL = 0.0f;
|
||||
spriteBorderFixR = (spriteBorderFix / uScale) / gstate_c.curTextureWidth;
|
||||
@@ -1034,23 +1055,11 @@ static bool ExpandRectangles(int vertexCount, int &numDecodedVerts, int vertsSiz
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (int i = 0; i < vertexCount; i += 2) {
|
||||
const TransformedVertex &transVtxTL = transformed[indsIn[i + 0]];
|
||||
const TransformedVertex &transVtxBR = transformed[indsIn[i + 1]];
|
||||
|
||||
if (pixelMapped) {
|
||||
float dx = transVtxBR.x - transVtxTL.x;
|
||||
float dy = transVtxBR.y - transVtxTL.y;
|
||||
float du = transVtxBR.u - transVtxTL.u;
|
||||
float dv = transVtxBR.v - transVtxTL.v;
|
||||
|
||||
// NOTE: We will accept it as pixel mapped if only one dimension is stretched. This fixes dialog frames in FFI.
|
||||
// Though, there could be false positives in other games due to this. Let's see if it is a problem...
|
||||
if (dx <= 0 || dy <= 0 || (dx != du && dy != dv)) {
|
||||
pixelMapped = false;
|
||||
}
|
||||
}
|
||||
|
||||
float z = transVtxBR.z;
|
||||
// Apply Z clamping. It appears clipping/culling does not affect rectangles, see #12058.
|
||||
// TODO: We might want to make this 65536.999. Since those will pass, and if a game mixes through and non-through...
|
||||
@@ -1065,30 +1074,30 @@ static bool ExpandRectangles(int vertexCount, int &numDecodedVerts, int vertsSiz
|
||||
|
||||
// bottom right
|
||||
trans[0] = transVtxBR;
|
||||
trans[0].u = (transVtxBR.u + spriteBorderFixR) * uScale;
|
||||
trans[0].v = (transVtxBR.v + spriteBorderFixB) * vScale;
|
||||
trans[0].u = (transVtxBR.u - spriteBorderFixR) * uScale;
|
||||
trans[0].v = (transVtxBR.v - spriteBorderFixB) * vScale;
|
||||
trans[0].z = z;
|
||||
|
||||
// top right
|
||||
trans[1] = transVtxBR;
|
||||
trans[1].y = transVtxTL.y;
|
||||
trans[1].u = (transVtxBR.u + spriteBorderFixR) * uScale;
|
||||
trans[1].v = (transVtxTL.v - spriteBorderFixT) * vScale;
|
||||
trans[1].u = (transVtxBR.u - spriteBorderFixR) * uScale;
|
||||
trans[1].v = (transVtxTL.v + spriteBorderFixT) * vScale;
|
||||
trans[1].z = z;
|
||||
|
||||
// top left
|
||||
trans[2] = transVtxBR;
|
||||
trans[2].x = transVtxTL.x;
|
||||
trans[2].y = transVtxTL.y;
|
||||
trans[2].u = (transVtxTL.u - spriteBorderFixL) * uScale;
|
||||
trans[2].v = (transVtxTL.v - spriteBorderFixT) * vScale;
|
||||
trans[2].u = (transVtxTL.u + spriteBorderFixL) * uScale;
|
||||
trans[2].v = (transVtxTL.v + spriteBorderFixT) * vScale;
|
||||
trans[2].z = z;
|
||||
|
||||
// bottom left
|
||||
trans[3] = transVtxBR;
|
||||
trans[3].x = transVtxTL.x;
|
||||
trans[3].u = (transVtxTL.u - spriteBorderFixL) * uScale;
|
||||
trans[3].v = (transVtxBR.v + spriteBorderFixB) * vScale;
|
||||
trans[3].u = (transVtxTL.u + spriteBorderFixL) * uScale;
|
||||
trans[3].v = (transVtxBR.v - spriteBorderFixB) * vScale;
|
||||
trans[3].z = z;
|
||||
|
||||
// That's the four corners. Now process UV rotation.
|
||||
|
||||
@@ -2188,8 +2188,9 @@ void TextureCacheCommon::ApplyTexture(bool doBind, bool flatZ) {
|
||||
}
|
||||
}
|
||||
|
||||
// Can we depalettize at all? This refers to both in-fragment-shader depal and "traditional" depal through a separate pass.
|
||||
static bool CanDepalettize(GETextureFormat texFormat, GEBufferFormat bufferFormat) {
|
||||
// Can we depalettize the bufferFormat as texFormat at all?
|
||||
// This refers to both in-fragment-shader depal and "traditional" depal through a separate pass.
|
||||
static bool CanDepalettizeBufferAs(GETextureFormat texFormat, GEBufferFormat bufferFormat) {
|
||||
if (IsClutFormat(texFormat)) {
|
||||
switch (bufferFormat) {
|
||||
case GE_FORMAT_4444:
|
||||
@@ -2255,17 +2256,18 @@ static bool CanUseSmoothDepal(const GPUgstate &gstate, GEBufferFormat framebuffe
|
||||
|
||||
void TextureCacheCommon::ApplyTextureFramebuffer(VirtualFramebuffer *framebuffer, GETextureFormat texFormat, RasterChannel channel) {
|
||||
Draw2DPipeline *textureShader = nullptr;
|
||||
uint32_t clutMode = gstate.clutformat & 0xFFFFFF;
|
||||
const uint32_t clutMode = gstate.clutformat & 0xFFFFFF;
|
||||
|
||||
bool depth = channel == RASTER_DEPTH;
|
||||
bool need_depalettize = CanDepalettize(texFormat, depth ? GE_FORMAT_DEPTH16 : framebuffer->fb_format);
|
||||
const bool depth = channel == RASTER_DEPTH;
|
||||
const GEBufferFormat fbFormat = depth ? GE_FORMAT_DEPTH16 : framebuffer->fb_format;
|
||||
const bool need_depalettize = CanDepalettizeBufferAs(texFormat, fbFormat);
|
||||
const bool selfRender = framebufferManager_->GetCurrentRenderVFB() == framebuffer;
|
||||
|
||||
// Shader depal is not supported during 3D texturing or depth texturing, and requires 32-bit integer instructions in the shader.
|
||||
bool useShaderDepal = framebufferManager_->GetCurrentRenderVFB() != framebuffer &&
|
||||
!depth && clutRenderAddress_ == 0xFFFFFFFF &&
|
||||
bool useShaderDepal = !selfRender && !depth && clutRenderAddress_ == 0xFFFFFFFF &&
|
||||
!gstate_c.curTextureIs3D &&
|
||||
draw_->GetShaderLanguageDesc().bitwiseOps &&
|
||||
!(texFormat == GE_TFMT_CLUT8 && framebuffer->fb_format == GE_FORMAT_5551); // socom
|
||||
!(texFormat == GE_TFMT_CLUT8 && fbFormat == GE_FORMAT_5551); // socom
|
||||
|
||||
switch (draw_->GetShaderLanguageDesc().shaderLanguage) {
|
||||
case ShaderLanguage::GLSL_1xx:
|
||||
@@ -2284,7 +2286,7 @@ void TextureCacheCommon::ApplyTextureFramebuffer(VirtualFramebuffer *framebuffer
|
||||
if (need_depalettize) {
|
||||
if (clutRenderAddress_ == 0xFFFFFFFF) {
|
||||
clutTexture = textureShaderCache_->GetClutTexture(clutFormat, clutHash_, clutBufRaw_);
|
||||
smoothedDepal = CanUseSmoothDepal(gstate, framebuffer->fb_format, clutTexture);
|
||||
smoothedDepal = CanUseSmoothDepal(gstate, fbFormat, clutTexture);
|
||||
} else {
|
||||
// The CLUT texture is dynamic, it's the framebuffer pointed to by clutRenderAddress.
|
||||
// Instead of texturing directly from that, we copy to a temporary CLUT texture.
|
||||
@@ -2298,6 +2300,8 @@ void TextureCacheCommon::ApplyTextureFramebuffer(VirtualFramebuffer *framebuffer
|
||||
}
|
||||
|
||||
if (useShaderDepal) {
|
||||
_dbg_assert_(!depth);
|
||||
|
||||
// Very icky conflation here of native and thin3d rendering. This will need careful work per backend in BindAsClutTexture.
|
||||
BindAsClutTexture(clutTexture.texture, smoothedDepal);
|
||||
|
||||
@@ -2312,16 +2316,16 @@ void TextureCacheCommon::ApplyTextureFramebuffer(VirtualFramebuffer *framebuffer
|
||||
ApplySamplingParams(samplerKey);
|
||||
|
||||
ShaderDepalMode mode = ShaderDepalMode::NORMAL;
|
||||
if (texFormat == GE_TFMT_CLUT8 && framebuffer->fb_format == GE_FORMAT_8888) {
|
||||
if (texFormat == GE_TFMT_CLUT8 && fbFormat == GE_FORMAT_8888) {
|
||||
mode = ShaderDepalMode::CLUT8_8888;
|
||||
smoothedDepal = false; // just in case
|
||||
} else if (smoothedDepal) {
|
||||
mode = ShaderDepalMode::SMOOTHED;
|
||||
}
|
||||
|
||||
gstate_c.Dirty(DIRTY_DEPAL);
|
||||
gstate_c.Dirty(DIRTY_DEPAL | DIRTY_FRAGMENTSHADER_STATE);
|
||||
gstate_c.SetUseShaderDepal(mode);
|
||||
gstate_c.depalFramebufferFormat = framebuffer->fb_format;
|
||||
gstate_c.depalTextureFormat = fbFormat;
|
||||
|
||||
const u32 bytesPerColor = clutFormat == GE_CMODE_32BIT_ABGR8888 ? sizeof(u32) : sizeof(u16);
|
||||
const u32 clutTotalColors = clutMaxBytes_ / bytesPerColor;
|
||||
@@ -2334,7 +2338,7 @@ void TextureCacheCommon::ApplyTextureFramebuffer(VirtualFramebuffer *framebuffer
|
||||
|
||||
depthUpperBits = (depth && framebuffer->fb_format == GE_FORMAT_8888) ? ((gstate.getTextureAddress(0) & 0x600000) >> 20) : 0;
|
||||
|
||||
textureShader = textureShaderCache_->GetDepalettizeShader(clutMode, texFormat, depth ? GE_FORMAT_DEPTH16 : framebuffer->fb_format, smoothedDepal, depthUpperBits);
|
||||
textureShader = textureShaderCache_->GetDepalettizeShader(clutMode, texFormat, fbFormat, smoothedDepal, depthUpperBits);
|
||||
gstate_c.SetUseShaderDepal(ShaderDepalMode::OFF);
|
||||
}
|
||||
|
||||
|
||||
@@ -377,7 +377,7 @@ void LinkedShader::UpdateUniforms(const ShaderID &vsid, const ShaderLanguageDesc
|
||||
int indexMask = gstate.getClutIndexMask();
|
||||
int indexShift = gstate.getClutIndexShift();
|
||||
int indexOffset = gstate.getClutIndexStartPos() >> 4;
|
||||
int format = gstate_c.depalFramebufferFormat;
|
||||
int format = gstate_c.depalTextureFormat;
|
||||
uint32_t val = BytesToUint32(indexMask, indexShift, indexOffset, format);
|
||||
// Poke in a bilinear filter flag in the top bit.
|
||||
val |= gstate.isMagnifyFilteringEnabled() << 31;
|
||||
|
||||
+1
-1
@@ -700,7 +700,7 @@ public:
|
||||
int spline_num_points_u;
|
||||
|
||||
ShaderDepalMode shaderDepalMode;
|
||||
GEBufferFormat depalFramebufferFormat;
|
||||
GEBufferFormat depalTextureFormat;
|
||||
|
||||
u32 getRelativeAddress(u32 data) const {
|
||||
u32 baseExtended = ((gstate.base & 0x000F0000) << 8) | data;
|
||||
|
||||
@@ -2136,3 +2136,7 @@ ULJS00097 = -0.25
|
||||
ULES00262 = 0.5
|
||||
ULUS10064 = 0.5
|
||||
ULKS46087 = 0.5
|
||||
|
||||
# Tokiden (issue #19422)
|
||||
# This works in the provided dump, but needs more testing.
|
||||
# NPJH50878 = -0.4
|
||||
|
||||
@@ -890,7 +890,7 @@ if (!skiprest &&
|
||||
float DD = float(eq(A, D));
|
||||
float FF = float(eq(C, F));
|
||||
|
||||
float sideFactor = eq_B_D && DD!=FF ? 1.0 : -0.145898;
|
||||
float sideFactor = eq_D_F && DD!=FF ? 1.0 : -0.145898;
|
||||
|
||||
Bl = fract(Bl) - (B1 +B2 +B1*B2) *0.381966;
|
||||
Dl = fract(Dl) - step(El, Dl) + DD*sideFactor;
|
||||
@@ -920,7 +920,7 @@ if (!skiprest &&
|
||||
float DD = float(eq(D, G));
|
||||
float FF = float(eq(F, I));
|
||||
|
||||
float sideFactor = eq_B_D && DD!=FF ? 1.0 : -0.145898;
|
||||
float sideFactor = eq_D_F && DD!=FF ? 1.0 : -0.145898;
|
||||
|
||||
Hl = fract(Hl) - (H1+H2+H1*H2) *0.381966;
|
||||
Dl = fract(Dl) - step(El, Dl) + DD*sideFactor;
|
||||
|
||||
Reference in New Issue
Block a user