Skip to content

Commit

Permalink
OGL: support palette texture decoding
Browse files Browse the repository at this point in the history
  • Loading branch information
degasus committed Feb 22, 2015
1 parent 860c889 commit 8d0b223
Show file tree
Hide file tree
Showing 3 changed files with 172 additions and 4 deletions.
2 changes: 2 additions & 0 deletions Source/Core/VideoBackends/OGL/Render.cpp
Expand Up @@ -465,6 +465,7 @@ Renderer::Renderer()
g_Config.backend_info.bSupportsBBox = GLExtensions::Supports("GL_ARB_shader_storage_buffer_object");
g_Config.backend_info.bSupportsGSInstancing = GLExtensions::Supports("GL_ARB_gpu_shader5");
g_Config.backend_info.bSupportsGeometryShaders = GLExtensions::Version() >= 320;
g_Config.backend_info.bSupportsPaletteConversion = GLExtensions::Supports("GL_ARB_texture_buffer_object");

// Desktop OpenGL supports the binding layout if it supports 420pack
// OpenGL ES 3.1 supports it implicitly without an extension
Expand Down Expand Up @@ -499,6 +500,7 @@ Renderer::Renderer()
g_Config.backend_info.bSupportsBindingLayout = true;
g_Config.backend_info.bSupportsEarlyZ = true;
g_Config.backend_info.bSupportsGeometryShaders = g_ogl_config.bSupportsAEP;
//g_Config.backend_info.bSupportsPaletteConversion = GLExtensions::Supports("GL_EXT_texture_buffer");
}
}
else
Expand Down
172 changes: 169 additions & 3 deletions Source/Core/VideoBackends/OGL/TextureCache.cpp
Expand Up @@ -22,6 +22,7 @@
#include "VideoBackends/OGL/GLInterfaceBase.h"
#include "VideoBackends/OGL/ProgramShaderCache.h"
#include "VideoBackends/OGL/Render.h"
#include "VideoBackends/OGL/StreamBuffer.h"
#include "VideoBackends/OGL/TextureCache.h"
#include "VideoBackends/OGL/TextureConverter.h"

Expand All @@ -47,6 +48,13 @@ static u32 s_DepthCbufid;
static u32 s_Textures[8];
static u32 s_ActiveTexture;

static SHADER s_palette_pixel_shader[3];
static StreamBuffer* s_palette_stream_buffer = nullptr;
static GLuint s_palette_resolv_texture;
static GLuint s_palette_buffer_offset_uniform[3];
static GLuint s_palette_multiplier_uniform[3];
static GLuint s_palette_copy_position_uniform[3];

bool SaveTexture(const std::string& filename, u32 textarget, u32 tex, int virtual_width, int virtual_height, unsigned int level)
{
if (GLInterface->GetMode() != GLInterfaceMode::MODE_OPENGL)
Expand Down Expand Up @@ -241,12 +249,27 @@ TextureCache::TextureCache()
s_ActiveTexture = -1;
for (auto& gtex : s_Textures)
gtex = -1;

if (g_ActiveConfig.backend_info.bSupportsPaletteConversion)
{
s_palette_stream_buffer = StreamBuffer::Create(GL_TEXTURE_BUFFER, 1024*1024);
glGenTextures(1, &s_palette_resolv_texture);
glBindTexture(GL_TEXTURE_BUFFER, s_palette_resolv_texture);
glTexBuffer(GL_TEXTURE_BUFFER, GL_R16UI, s_palette_stream_buffer->m_buffer);
}
}


TextureCache::~TextureCache()
{
DeleteShaders();

if (g_ActiveConfig.backend_info.bSupportsPaletteConversion)
{
delete s_palette_stream_buffer;
s_palette_stream_buffer = nullptr;
glDeleteTextures(1, &s_palette_resolv_texture);
}
}

void TextureCache::DisableStage(unsigned int stage)
Expand Down Expand Up @@ -351,18 +374,161 @@ void TextureCache::CompileShaders()

s_ColorCopyPositionUniform = glGetUniformLocation(s_ColorMatrixProgram.glprogid, "copy_position");
s_DepthCopyPositionUniform = glGetUniformLocation(s_DepthMatrixProgram.glprogid, "copy_position");

std::string palette_shader =
R"GLSL(
uniform int texture_buffer_offset;
uniform float multiplier;
SAMPLER_BINDING(9) uniform sampler2DArray samp9;
SAMPLER_BINDING(10) uniform usamplerBuffer samp10;
in vec3 f_uv0;
out vec4 ocol0;
int Convert3To8(int v)
{
// Swizzle bits: 00000123 -> 12312312
return (v << 5) | (v << 2) | (v >> 1);
}
int Convert4To8(int v)
{
// Swizzle bits: 00001234 -> 12341234
return (v << 4) | v;
}
int Convert5To8(int v)
{
// Swizzle bits: 00012345 -> 12345123
return (v << 3) | (v >> 2);
}
int Convert6To8(int v)
{
// Swizzle bits: 00123456 -> 12345612
return (v << 2) | (v >> 4);
}
float4 DecodePixel_RGB5A3(int val)
{
int r,g,b,a;
if ((val&0x8000) > 0)
{
r=Convert5To8((val>>10) & 0x1f);
g=Convert5To8((val>>5 ) & 0x1f);
b=Convert5To8((val ) & 0x1f);
a=0xFF;
}
else
{
a=Convert3To8((val>>12) & 0x7);
r=Convert4To8((val>>8 ) & 0xf);
g=Convert4To8((val>>4 ) & 0xf);
b=Convert4To8((val ) & 0xf);
}
return float4(r, g, b, a) / 255;
}
float4 DecodePixel_RGB565(int val)
{
int r, g, b, a;
r = Convert5To8((val >> 11) & 0x1f);
g = Convert6To8((val >> 5) & 0x3f);
b = Convert5To8((val) & 0x1f);
a = 0xFF;
return float4(r, g, b, a) / 255;
}
float4 DecodePixel_IA8(int val)
{
int i = val & 0xFF;
int a = val >> 8;
return float4(i, i, i, a) / 255;
}
void main()
{
int src = int(round(texture(samp9, f_uv0).r * multiplier));
src = int(texelFetch(samp10, src + texture_buffer_offset).r);
src = ((src << 8) & 0xFF00) | (src >> 8);
ocol0 = DECODE(src);
}
)GLSL";

if (g_ActiveConfig.backend_info.bSupportsPaletteConversion)
{
ProgramShaderCache::CompileShader(
s_palette_pixel_shader[GX_TL_IA8],
StringFromFormat(VProgram, prefix, prefix).c_str(),
("#define DECODE DecodePixel_IA8" + palette_shader).c_str(),
GProgram);
s_palette_buffer_offset_uniform[GX_TL_IA8] = glGetUniformLocation(s_palette_pixel_shader[GX_TL_IA8].glprogid, "texture_buffer_offset");
s_palette_multiplier_uniform[GX_TL_IA8] = glGetUniformLocation(s_palette_pixel_shader[GX_TL_IA8].glprogid, "multiplier");
s_palette_copy_position_uniform[GX_TL_IA8] = glGetUniformLocation(s_palette_pixel_shader[GX_TL_IA8].glprogid, "copy_position");

ProgramShaderCache::CompileShader(
s_palette_pixel_shader[GX_TL_RGB565],
StringFromFormat(VProgram, prefix, prefix).c_str(),
("#define DECODE DecodePixel_RGB565" + palette_shader).c_str(),
GProgram);
s_palette_buffer_offset_uniform[GX_TL_RGB565] = glGetUniformLocation(s_palette_pixel_shader[GX_TL_RGB565].glprogid, "texture_buffer_offset");
s_palette_multiplier_uniform[GX_TL_RGB565] = glGetUniformLocation(s_palette_pixel_shader[GX_TL_RGB565].glprogid, "multiplier");
s_palette_copy_position_uniform[GX_TL_RGB565] = glGetUniformLocation(s_palette_pixel_shader[GX_TL_RGB565].glprogid, "copy_position");

ProgramShaderCache::CompileShader(
s_palette_pixel_shader[GX_TL_RGB5A3],
StringFromFormat(VProgram, prefix, prefix).c_str(),
("#define DECODE DecodePixel_RGB5A3" + palette_shader).c_str(),
GProgram);
s_palette_buffer_offset_uniform[GX_TL_RGB5A3] = glGetUniformLocation(s_palette_pixel_shader[GX_TL_RGB5A3].glprogid, "texture_buffer_offset");
s_palette_multiplier_uniform[GX_TL_RGB5A3] = glGetUniformLocation(s_palette_pixel_shader[GX_TL_RGB5A3].glprogid, "multiplier");
s_palette_copy_position_uniform[GX_TL_RGB5A3] = glGetUniformLocation(s_palette_pixel_shader[GX_TL_RGB5A3].glprogid, "copy_position");
}
}

void TextureCache::DeleteShaders()
{
s_ColorMatrixProgram.Destroy();
s_DepthMatrixProgram.Destroy();

if (g_ActiveConfig.backend_info.bSupportsPaletteConversion)
for (auto& shader : s_palette_pixel_shader)
shader.Destroy();
}

void TextureCache::ConvertTexture(TextureCache::TCacheEntryBase* entry, TCacheEntryBase* unconverted, void* palette, TlutFormat format)
void TextureCache::ConvertTexture(TCacheEntryBase* _entry, TCacheEntryBase* _unconverted, void* palette, TlutFormat format)
{
// TODO: Implement.
return;
if (!g_ActiveConfig.backend_info.bSupportsPaletteConversion)
return;

g_renderer->ResetAPIState();

TCacheEntry* entry = (TCacheEntry*) _entry;
TCacheEntry* unconverted = (TCacheEntry*) _unconverted;

glActiveTexture(GL_TEXTURE0 + 9);
glBindTexture(GL_TEXTURE_2D_ARRAY, unconverted->texture);

FramebufferManager::SetFramebuffer(entry->framebuffer);
glViewport(0, 0, entry->config.width, entry->config.height);
s_palette_pixel_shader[format].Bind();

int size = unconverted->format == 0 ? 32 : 512;
auto buffer = s_palette_stream_buffer->Map(size);
memcpy(buffer.first, palette, size);
s_palette_stream_buffer->Unmap(size);
glUniform1i(s_palette_buffer_offset_uniform[format], buffer.second / 2);
glUniform1f(s_palette_multiplier_uniform[format], unconverted->format == 0 ? 15.0f : 255.0f);
glUniform4f(s_palette_copy_position_uniform[format], 0.0f, 0.0f, (float)unconverted->config.width, (float)unconverted->config.height);

glActiveTexture(GL_TEXTURE0 + 10);
glBindTexture(GL_TEXTURE_BUFFER, s_palette_resolv_texture);

OpenGL_BindAttributelessVAO();
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

FramebufferManager::SetFramebuffer(0);
g_renderer->RestoreAPIState();
}

}
2 changes: 1 addition & 1 deletion Source/Core/VideoBackends/OGL/main.cpp
Expand Up @@ -140,7 +140,7 @@ static void InitBackendInfo()
g_Config.backend_info.bSupportsGeometryShaders = true;
g_Config.backend_info.bSupports3DVision = false;
g_Config.backend_info.bSupportsPostProcessing = true;
g_Config.backend_info.bSupportsPaletteConversion = false;
//g_Config.backend_info.bSupportsPaletteConversion = true; // is GPU dependent and must be set in renderer

g_Config.backend_info.Adapters.clear();

Expand Down

0 comments on commit 8d0b223

Please sign in to comment.