mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-11-12 17:19:28 +01:00
Merge pull request #22898 from hrydgard/depal-pixel-mapped
Depal: Skip the bilinear filter on exactly pixel-mapped draws
This commit is contained in:
8 files changed
+50
-20
No files matched your search
@@ -180,7 +180,14 @@ void BaseUpdateUniforms(UB_VS_FS_Base *ub, uint64_t dirtyUniforms, bool useBuffe
|
||||
}
|
||||
}
|
||||
|
||||
void DirtyDepalIfPixelMappedChanged(bool pixelMapped) {
|
||||
if (gstate_c.shaderDepalMode != ShaderDepalMode::OFF && pixelMapped != gstate_c.depalPixelMapped) {
|
||||
gstate_c.Dirty(DIRTY_DEPAL);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t PackDepalBits(bool pixelMapped) {
|
||||
gstate_c.depalPixelMapped = pixelMapped;
|
||||
const int indexMask = gstate.getClutIndexMask();
|
||||
const int indexShift = gstate.getClutIndexShift();
|
||||
const int indexOffset = gstate.getClutIndexStartPos() >> 4;
|
||||
|
||||
@@ -110,6 +110,8 @@ void LightUpdateUniforms(UB_VS_Lights *ub, uint64_t dirtyUniforms);
|
||||
|
||||
uint32_t PackLightControlBits();
|
||||
uint32_t PackDepalBits(bool pixelMapped);
|
||||
// Call before reading the dirty uniforms: the depal uniform depends on pixelMapped, which changes per draw.
|
||||
void DirtyDepalIfPixelMappedChanged(bool pixelMapped);
|
||||
|
||||
void UpdateFogCoef(const GEState &state, float fogCoef[2]);
|
||||
|
||||
|
||||
@@ -1051,26 +1051,37 @@ static bool ExpandRectangles(int vertexCount, int &numDecodedVerts, int vertsSiz
|
||||
vScale /= gstate_c.curTextureHeight;
|
||||
}
|
||||
|
||||
// Look for pixel mapping, two ways at once:
|
||||
// - pixelMapped (with smart 2D filtering): each rect is 1:1 in at least one direction. Turns the texture filter
|
||||
// off and the sprite border fix with it. This one can change what's on screen.
|
||||
// - exactlyPixelMapped: each rect is 1:1 in both directions at a whole-texel offset, so every pixel center lands
|
||||
// on a texel center and bilinear gives the nearest texel anyway. Shader depal filters by hand, with four
|
||||
// texel and four palette lookups per pixel, a lot for a slow GPU on a full-screen pass (DBZ Tenkaichi Tag
|
||||
// Team has two per frame), so for it this turns the filter off without changing anything. Positions are only
|
||||
// in pixels in through mode.
|
||||
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;
|
||||
}
|
||||
}
|
||||
bool exactlyPixelMapped = throughmode && gstate_c.shaderDepalMode != ShaderDepalMode::OFF;
|
||||
for (int i = 0; i < vertexCount && (pixelMapped || exactlyPixelMapped); i += 2) {
|
||||
const TransformedVertex &transVtxTL = transformed[indsIn[i + 0]];
|
||||
const TransformedVertex &transVtxBR = transformed[indsIn[i + 1]];
|
||||
const float dx = transVtxBR.x - transVtxTL.x;
|
||||
const float dy = transVtxBR.y - transVtxTL.y;
|
||||
const float du = transVtxBR.u - transVtxTL.u;
|
||||
const float dv = transVtxBR.v - transVtxTL.v;
|
||||
if (dx <= 0 || dy <= 0) {
|
||||
pixelMapped = false;
|
||||
exactlyPixelMapped = false;
|
||||
break;
|
||||
}
|
||||
// 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 != du && dy != dv) {
|
||||
pixelMapped = false;
|
||||
}
|
||||
const float offsetU = transVtxTL.u - transVtxTL.x;
|
||||
const float offsetV = transVtxTL.v - transVtxTL.y;
|
||||
if (dx != du || dy != dv || offsetU != floorf(offsetU) || offsetV != floorf(offsetV)) {
|
||||
exactlyPixelMapped = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1095,6 +1106,10 @@ static bool ExpandRectangles(int vertexCount, int &numDecodedVerts, int vertsSiz
|
||||
}
|
||||
}
|
||||
|
||||
// The sprite border fix moves the UVs off the texel centers.
|
||||
if (spriteBorderFixL != 0.0f || spriteBorderFixR != 0.0f || spriteBorderFixT != 0.0f || spriteBorderFixB != 0.0f) {
|
||||
exactlyPixelMapped = false;
|
||||
}
|
||||
|
||||
// Like the software renderer's ProcessRect: rectangles aren't clipped, one with a vertex behind the camera
|
||||
// or outside the screen range is dropped whole. With depth clamp, a vertex past the near plane is exempt
|
||||
@@ -1213,7 +1228,7 @@ static bool ExpandRectangles(int vertexCount, int &numDecodedVerts, int vertsSiz
|
||||
}
|
||||
numDecodedVerts = outVerts;
|
||||
inds = newInds;
|
||||
*pixelMappedExactly = pixelMapped;
|
||||
*pixelMappedExactly = pixelMapped || exactlyPixelMapped;
|
||||
*drawIndexCount = indsOut - newInds;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -149,6 +149,7 @@ void ShaderManagerD3D11::ClearShaders() {
|
||||
}
|
||||
|
||||
uint64_t ShaderManagerD3D11::UpdateUniforms(bool useBufferedRendering, bool pixelMapped) {
|
||||
DirtyDepalIfPixelMappedChanged(pixelMapped);
|
||||
uint64_t dirty = gstate_c.GetDirtyUniforms();
|
||||
if (dirty != 0) {
|
||||
D3D11_MAPPED_SUBRESOURCE map;
|
||||
|
||||
@@ -717,6 +717,7 @@ Shader *ShaderManagerGLES::ApplyVertexShader(bool useHWTransform, u32 vertexType
|
||||
}
|
||||
|
||||
LinkedShader *ShaderManagerGLES::ApplyFragmentShader(VShaderID VSID, Shader *vs, const ComputedPipelineState &pipelineState, ClipInfoFlags clipInfoFlags, bool pixelMapped) {
|
||||
DirtyDepalIfPixelMappedChanged(pixelMapped);
|
||||
uint64_t dirty = gstate_c.GetDirtyUniforms();
|
||||
if (dirty) {
|
||||
if (lastShader_)
|
||||
|
||||
@@ -682,6 +682,8 @@ public:
|
||||
|
||||
ShaderDepalMode shaderDepalMode;
|
||||
GEBufferFormat depalTextureFormat;
|
||||
// The pixelMapped that the depal uniform was last packed with (it turns bilinear depal off).
|
||||
bool depalPixelMapped;
|
||||
|
||||
void SetShaderDepal(ShaderDepalMode mode, GEBufferFormat texFormat = {}) {
|
||||
if (mode != shaderDepalMode || (mode != ShaderDepalMode::OFF && texFormat != depalTextureFormat)) {
|
||||
|
||||
@@ -86,6 +86,7 @@ void ShaderManagerMetal::ClearShaders() {
|
||||
}
|
||||
|
||||
uint64_t ShaderManagerMetal::UpdateUniforms(bool useBufferedRendering, bool pixelMapped) {
|
||||
DirtyDepalIfPixelMappedChanged(pixelMapped);
|
||||
uint64_t dirty = gstate_c.GetDirtyUniforms();
|
||||
if (dirty != 0) {
|
||||
if (dirty & DIRTY_BASE_UNIFORMS)
|
||||
|
||||
@@ -218,6 +218,7 @@ void ShaderManagerVulkan::ClearShaders() {
|
||||
}
|
||||
|
||||
uint64_t ShaderManagerVulkan::UpdateUniforms(bool useBufferedRendering, bool pixelMapped) {
|
||||
DirtyDepalIfPixelMappedChanged(pixelMapped);
|
||||
uint64_t dirty = gstate_c.GetDirtyUniforms();
|
||||
if (dirty != 0) {
|
||||
if (dirty & DIRTY_BASE_UNIFORMS)
|
||||
|
||||
Reference in new issue
Block a user