Initial work on depalettization.

This commit is contained in:
Henrik Rydgard committed 2014-05-27 22:07:24 +02:00
1 parent 585050de27
commit 8fba7fa98e
9 files changed
+405 -17

No files matched your search

+67 -16
View File
@@ -27,6 +27,7 @@
#include "GPU/GLES/TextureCache.h"
#include "GPU/GLES/Framebuffer.h"
#include "GPU/GLES/FragmentShaderGenerator.h"
#include "GPU/GLES/DepalettizeShader.h"
#include "GPU/Common/TextureDecoder.h"
#include "Core/Config.h"
#include "Core/Host.h"
@@ -117,6 +118,9 @@ void TextureCache::Decimate() {
for (TexCache::iterator iter = cache.begin(); iter != cache.end(); ) {
if (iter->second.lastFrame + killAge < gpuStats.numFlips) {
glDeleteTextures(1, &iter->second.texture);
if (iter->second.depalFBO) {
fbo_destroy(iter->second.depalFBO);
}
cache.erase(iter++);
} else {
++iter;
@@ -128,6 +132,9 @@ void TextureCache::Decimate() {
// In low memory mode, we kill them all.
if (lowMemoryMode_ || iter->second.lastFrame + TEXTURE_SECOND_KILL_AGE < gpuStats.numFlips) {
glDeleteTextures(1, &iter->second.texture);
if (iter->second.depalFBO) {
fbo_destroy(iter->second.depalFBO);
}
secondCache.erase(iter++);
} else {
++iter;
@@ -214,7 +221,18 @@ inline void AttachFramebufferInvalid(T &entry, VirtualFramebuffer *framebuffer)
}
}
inline void TextureCache::AttachFramebuffer(TexCacheEntry *entry, u32 address, VirtualFramebuffer *framebuffer, bool exactMatch) {
bool TextureCache::AttachFramebufferCLUT(TextureCache::TexCacheEntry *entry, VirtualFramebuffer *framebuffer, u32 address) {
GLuint program = depalShaderCache_->GetDepalettizeShader(framebuffer->format);
if (program) {
entry->framebuffer = framebuffer;
entry->invalidHint = -1;
entry->status |= TexCacheEntry::STATUS_DEPALETTIZE;
return true;
}
return false;
}
void TextureCache::AttachFramebuffer(TexCacheEntry *entry, u32 address, VirtualFramebuffer *framebuffer, bool exactMatch) {
// If they match exactly, it's non-CLUT and from the top left.
if (exactMatch) {
// Apply to non-buffered and buffered mode only.
@@ -237,22 +255,31 @@ inline void TextureCache::AttachFramebuffer(TexCacheEntry *entry, u32 address, V
if (!(g_Config.iRenderingMode == FB_BUFFERED_MODE))
return;
// 3rd Birthday (and possibly other games) render to a 16 bit clut texture.
const bool compatFormat = framebuffer->format == entry->format
|| (framebuffer->format == GE_FORMAT_8888 && entry->format == GE_TFMT_CLUT32)
|| (framebuffer->format != GE_FORMAT_8888 && entry->format == GE_TFMT_CLUT16);
// Check for CLUT. The framebuffer is always RGB, but it can be interpreted as a CLUT texture.
// 3rd Birthday (and a bunch of other games) render to a 16 bit clut texture.
bool clutSuccess = false;
if (((framebuffer->format == GE_FORMAT_8888 && entry->format == GE_TFMT_CLUT32) || (framebuffer->format != GE_FORMAT_8888 && entry->format == GE_TFMT_CLUT16))) {
clutSuccess = AttachFramebufferCLUT(entry, framebuffer, address);
}
// Is it at least the right stride?
if (framebuffer->fb_stride == entry->bufw && compatFormat) {
if (framebuffer->format != entry->format) {
WARN_LOG_REPORT_ONCE(diffFormat2, G3D, "Render to texture with different formats %d != %d at %08x", entry->format, framebuffer->format, address);
// TODO: Use an FBO to translate the palette?
AttachFramebufferValid(entry, framebuffer);
} else if ((entry->addr - address) / entry->bufw < framebuffer->height) {
WARN_LOG_REPORT_ONCE(subarea, G3D, "Render to area containing texture at %08x", address);
// TODO: Keep track of the y offset.
// If "AttachFramebufferValid" , God of War Ghost of Sparta/Chains of Olympus will be missing special effect.
AttachFramebufferInvalid(entry, framebuffer);
if (!clutSuccess) {
// This is either normal or we failed to generate a shader to depalettize
const bool compatFormat = framebuffer->format == entry->format ||
(framebuffer->format == GE_FORMAT_8888 && entry->format == GE_TFMT_CLUT32) ||
(framebuffer->format != GE_FORMAT_8888 && entry->format == GE_TFMT_CLUT16);
// Is it at least the right stride?
if (framebuffer->fb_stride == entry->bufw && compatFormat) {
if (framebuffer->format != entry->format) {
WARN_LOG_REPORT_ONCE(diffFormat2, G3D, "Render to texture with different formats %d != %d at %08x", entry->format, framebuffer->format, address);
// TODO: Use an FBO to translate the palette?
AttachFramebufferValid(entry, framebuffer);
} else if ((entry->addr - address) / entry->bufw < framebuffer->height) {
WARN_LOG_REPORT_ONCE(subarea, G3D, "Render to area containing texture at %08x", address);
// TODO: Keep track of the y offset.
// If "AttachFramebufferValid" , God of War Ghost of Sparta/Chains of Olympus will be missing special effect.
AttachFramebufferInvalid(entry, framebuffer);
}
}
}
}
@@ -723,6 +750,7 @@ static inline u32 MiniHash(const u32 *ptr) {
return ptr[0];
}
// TODO: Unused, remove?
static inline u32 QuickClutHash(const u8 *clut, u32 bytes) {
// CLUTs always come in multiples of 32 bytes, can't load them any other way.
_dbg_assert_msg_(G3D, (bytes & 31) == 0, "CLUT should always have a multiple of 32 bytes.");
@@ -889,6 +917,28 @@ void TextureCache::SetTextureFramebuffer(TexCacheEntry *entry) {
if (useBufferedRendering) {
framebufferManager_->BindFramebufferColor(entry->framebuffer);
if (entry->status & TexCacheEntry::STATUS_DEPALETTIZE) {
GLuint program = depalShaderCache_->GetDepalettizeShader(entry->framebuffer->format);
glUseProgram(program);
// Check if we can handle the current setup
GLuint clutTexture = depalShaderCache_->GetClutTexture(clutHash_, clutBufConverted_);
glActiveTexture(1);
glBindTexture(GL_TEXTURE_2D, clutTexture);
glActiveTexture(0);
if (!entry->depalFBO) {
entry->depalFBO = fbo_create(entry->framebuffer->bufferWidth, entry->framebuffer->bufferHeight, 1, false, FBO_8888);
}
fbo_bind_as_render_target(entry->depalFBO);
// ...
fbo_bind_color_as_texture(entry->depalFBO, 0);
}
// Keep the framebuffer alive.
entry->framebuffer->last_frame_used = gpuStats.numFlips;
@@ -1149,6 +1199,7 @@ void TextureCache::SetTexture(bool force) {
entry->framebuffer = 0;
entry->maxLevel = maxLevel;
entry->lodBias = 0.0f;
entry->depalFBO = 0;
entry->dim = gstate.getTextureDimension(0);
entry->bufw = bufw;