mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-07-11 01:25:07 +02:00
Add the necessary logic to use in-shader CLUT lookups for regular textures
This commit is contained in:
@@ -685,7 +685,7 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu
|
||||
}
|
||||
WRITE(p, " vec2 tsize = vec2(textureSize(tex, 0).xy);\n");
|
||||
WRITE(p, " vec2 fraction;\n");
|
||||
WRITE(p, " bool bilinear = (u_depal_mask_shift_off_fmt >> 0x2Fu) != 0x0u;\n");
|
||||
WRITE(p, " bool bilinear = (u_depal_mask_shift_off_fmt >> 0x1Fu) != 0x0u;\n");
|
||||
WRITE(p, " if (bilinear) {\n");
|
||||
WRITE(p, " uv_round = uv * tsize - vec2(0.5, 0.5);\n");
|
||||
WRITE(p, " fraction = fract(uv_round);\n");
|
||||
@@ -694,6 +694,7 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu
|
||||
WRITE(p, " uv_round = uv;\n");
|
||||
WRITE(p, " }\n");
|
||||
|
||||
// TODO: Use fetch here when possible.
|
||||
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");
|
||||
|
||||
@@ -944,7 +944,7 @@ Draw2DPipeline *FramebufferManagerCommon::GetReinterpretPipeline(GEBufferFormat
|
||||
|
||||
Draw2DPipeline *pipeline = reinterpretFromTo_[(int)from][(int)to];
|
||||
if (!pipeline) {
|
||||
pipeline = draw2D_.Create2DPipeline([=](ShaderWriter &shaderWriter) -> Draw2DPipelineInfo {
|
||||
pipeline = draw2D_.Create2DPipeline([from, to](ShaderWriter &shaderWriter) -> Draw2DPipelineInfo {
|
||||
return GenerateReinterpretFragmentShader(shaderWriter, from, to);
|
||||
});
|
||||
reinterpretFromTo_[(int)from][(int)to] = pipeline;
|
||||
|
||||
@@ -193,9 +193,24 @@ void BaseUpdateUniforms(UB_VS_FS_Base *ub, uint64_t dirtyUniforms, bool useBuffe
|
||||
int indexOffset = gstate.getClutIndexStartPos() >> 4;
|
||||
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())
|
||||
// NOTE: This must follow similar logic to TextureCacheCommon::GetSamplingParams -
|
||||
// maybe we can share it somehow.
|
||||
// TOOD: Handle replaced textures.
|
||||
bool bilinear = gstate.isMagnifyFilteringEnabled() && !gstate_c.pixelMapped;
|
||||
switch (g_Config.iTexFiltering) {
|
||||
case TEX_FILTER_FORCE_NEAREST:
|
||||
bilinear = false;
|
||||
break;
|
||||
case TEX_FILTER_FORCE_LINEAR:
|
||||
bilinear = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (bilinear) {
|
||||
// Poke in a bilinear filter flag in the top bit.
|
||||
val |= 0x80000000;
|
||||
}
|
||||
ub->depal_mask_shift_off_fmt = val;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -669,7 +669,7 @@ TexCacheEntry *TextureCacheCommon::SetTexture() {
|
||||
|
||||
if (hasClutGPU) {
|
||||
WARN_LOG_N_TIMES(clutUseRender, 5, Log::G3D, "Using texture with dynamic CLUT: texfmt=%d, clutfmt=%d", gstate.getTextureFormat(), gstate.getClutPaletteFormat());
|
||||
entry->status |= TexStatus::CLUT_GPU;
|
||||
entry->status |= TexStatus::CLUT_GPU | TexStatus::CLUT8_INDEXED;
|
||||
}
|
||||
|
||||
if (hasClut && clutRenderAddress_ == 0xFFFFFFFF) {
|
||||
@@ -691,6 +691,8 @@ TexCacheEntry *TextureCacheCommon::SetTexture() {
|
||||
}
|
||||
|
||||
nextNeedsChange_ = false;
|
||||
} else {
|
||||
// We had an entry already, modify it.
|
||||
}
|
||||
|
||||
// We have to decode it, let's setup the cache entry first.
|
||||
@@ -704,6 +706,14 @@ TexCacheEntry *TextureCacheCommon::SetTexture() {
|
||||
|
||||
entry->cluthash = cluthash;
|
||||
|
||||
/*
|
||||
if (entry->maxLevel == 0 && (entry->format == GE_TFMT_CLUT8 || entry->format == GE_TFMT_CLUT4) &&
|
||||
!(entry->status & TexStatus::TO_REPLACE) && !(entry->status & TexStatus::TO_SCALE) && !(entry->status & TexStatus::RELIABLE)) {
|
||||
// Experiment with CLUT8 decoding for regular textures.
|
||||
entry->status |= TexStatus::CLUT8_INDEXED;
|
||||
}
|
||||
*/
|
||||
|
||||
gstate_c.curTextureWidth = w;
|
||||
gstate_c.curTextureHeight = h;
|
||||
gstate_c.SetTextureIsVideo((entry->status & TexStatus::VIDEO) != 0);
|
||||
@@ -720,7 +730,6 @@ TexCacheEntry *TextureCacheCommon::SetTexture() {
|
||||
nextTexture_ = entry;
|
||||
nextFramebufferTexture_ = nullptr;
|
||||
nextNeedsRehash_ = true;
|
||||
// We still need to rebuild, to allocate a texture. But we'll bail early.
|
||||
nextNeedsRebuild_ = true;
|
||||
return entry;
|
||||
}
|
||||
@@ -2216,16 +2225,16 @@ void TextureCacheCommon::ApplyTexture(bool doBind, bool flatZ) {
|
||||
}
|
||||
|
||||
gstate_c.SetTextureIsVideo((entry->status & TexStatus::VIDEO) != 0);
|
||||
entry->lastFrame = gpuStats.totals.numFlips;
|
||||
if (entry->status & TexStatus::CLUT_GPU) {
|
||||
_dbg_assert_(entry->status & TexStatus::CLUT8_INDEXED);
|
||||
// Special process.
|
||||
ApplyTextureDepal(entry);
|
||||
entry->lastFrame = gpuStats.totals.numFlips;
|
||||
ApplyTextureDepalFramebufferCLUT(entry);
|
||||
gstate_c.SetTextureSolidAlpha(false);
|
||||
gstate_c.SetTextureIs3D(false);
|
||||
gstate_c.SetTextureIsArray(false);
|
||||
gstate_c.SetTextureIsBGRA(false);
|
||||
} else {
|
||||
entry->lastFrame = gpuStats.totals.numFlips;
|
||||
if (doBind) {
|
||||
BindTexture(entry, flatZ);
|
||||
}
|
||||
@@ -2233,7 +2242,15 @@ void TextureCacheCommon::ApplyTexture(bool doBind, bool flatZ) {
|
||||
gstate_c.SetTextureIs3D((entry->status & TexStatus::IS_3D) != 0);
|
||||
gstate_c.SetTextureIsArray(false);
|
||||
gstate_c.SetTextureIsBGRA((entry->status & TexStatus::BGRA) != 0);
|
||||
gstate_c.SetShaderDepal(ShaderDepalMode::OFF);
|
||||
if (entry->status & TexStatus::CLUT8_INDEXED) {
|
||||
bool smoothedDepal = false;
|
||||
u32 depthUpperBits = 0;
|
||||
ClutTexture clutTexture = clutTextureCache_.GetClutTexture(gstate.getClutPaletteFormat(), clutHash_, clutBuf_);
|
||||
BindAsClutTexture(clutTexture.texture, false);
|
||||
gstate_c.SetShaderDepal(ShaderDepalMode::NORMAL, GE_FORMAT_CLUT8);
|
||||
} else {
|
||||
gstate_c.SetShaderDepal(ShaderDepalMode::OFF);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2474,7 +2491,7 @@ void TextureCacheCommon::ApplyTextureFramebuffer(VirtualFramebuffer *framebuffer
|
||||
}
|
||||
|
||||
// Applies depal to a normal (non-framebuffer) texture, pre-decoded to CLUT8 format.
|
||||
void TextureCacheCommon::ApplyTextureDepal(TexCacheEntry *entry) {
|
||||
void TextureCacheCommon::ApplyTextureDepalFramebufferCLUT(TexCacheEntry *entry) {
|
||||
uint32_t clutMode = gstate.clutformat & 0xFFFFFF;
|
||||
|
||||
switch (entry->format) {
|
||||
@@ -2881,7 +2898,7 @@ bool TextureCacheCommon::PrepareBuildTexture(BuildTexturePlan &plan, TexCacheEnt
|
||||
}
|
||||
|
||||
bool canReplace = !isPPGETexture;
|
||||
if (entry->status & TexStatus::CLUT_GPU) {
|
||||
if (entry->status & TexStatus::CLUT8_INDEXED) {
|
||||
_dbg_assert_(entry->format == GE_TFMT_CLUT4 || entry->format == GE_TFMT_CLUT8);
|
||||
plan.decodeToClut8 = true;
|
||||
// We only support 1 mip level when doing CLUT on GPU for now.
|
||||
@@ -3001,7 +3018,7 @@ void TextureCacheCommon::LoadTextureLevel(TexCacheEntry &entry, uint8_t *data, s
|
||||
if (!gstate_c.Use(GPU_USE_16BIT_FORMATS) || dstFmt == Draw::DataFormat::R8G8B8A8_UNORM) {
|
||||
texDecFlags |= TexDecodeFlags::EXPAND32;
|
||||
}
|
||||
if (entry.status & (TexStatus::CLUT_GPU | TexStatus::CLUT8_INDEXED)) {
|
||||
if (entry.status & TexStatus::CLUT8_INDEXED) {
|
||||
_dbg_assert_(entry.format == GE_TFMT_CLUT4 || entry.format == GE_TFMT_CLUT8);
|
||||
texDecFlags |= TexDecodeFlags::TO_CLUT8;
|
||||
}
|
||||
@@ -3080,6 +3097,9 @@ std::string TexStatusToString(TexStatus status) {
|
||||
if (status & TexStatus::CLUT_GPU) {
|
||||
result += "CLUT_GPU ";
|
||||
}
|
||||
if (status & TexStatus::CLUT8_INDEXED) {
|
||||
result += "CLUT8_INDEXED ";
|
||||
}
|
||||
if (status & TexStatus::FORCE_REBUILD) {
|
||||
result += "FORCE_REBUILD ";
|
||||
}
|
||||
|
||||
@@ -404,7 +404,7 @@ protected:
|
||||
void Decimate(TexCacheEntry *exceptThisOne, bool forcePressure); // forcePressure defaults to false.
|
||||
|
||||
void ApplyTextureFramebuffer(VirtualFramebuffer *framebuffer, GETextureFormat texFormat, RasterChannel channel);
|
||||
void ApplyTextureDepal(TexCacheEntry *entry);
|
||||
void ApplyTextureDepalFramebufferCLUT(TexCacheEntry *entry);
|
||||
|
||||
void HandleTextureChange(TexCacheEntry *const entry, const char *reason, bool initialMatch, bool doDelete);
|
||||
virtual void BuildTexture(TexCacheEntry *const entry) = 0;
|
||||
|
||||
@@ -287,6 +287,7 @@ const char *GeBufferFormatToString(GEBufferFormat fmt) {
|
||||
case GE_FORMAT_565: return "565";
|
||||
case GE_FORMAT_8888: return "8888";
|
||||
case GE_FORMAT_DEPTH16: return "DEPTH16";
|
||||
case GE_FORMAT_CLUT8: return "CLUT8";
|
||||
default: return "N/A";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -958,7 +958,7 @@ void TextureCacheVulkan::LoadVulkanTextureLevel(TexCacheEntry &entry, uint8_t *w
|
||||
if (!gstate_c.Use(GPU_USE_16BIT_FORMATS) || scaleFactor > 1 || dstFmt == VULKAN_8888_FORMAT) {
|
||||
texDecFlags |= TexDecodeFlags::EXPAND32;
|
||||
}
|
||||
if (entry.status & TexStatus::CLUT_GPU) {
|
||||
if (entry.status & TexStatus::CLUT8_INDEXED) {
|
||||
texDecFlags |= TexDecodeFlags::TO_CLUT8;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user