Merge pull request #2085 from degasus/ogl_paletted

OGL: support palette texture decoding
This commit is contained in:
Markus Wick 2015-02-24 22:59:58 +01:00
commit 5fc62ac563
4 changed files with 173 additions and 6 deletions

View File

@ -528,6 +528,7 @@ void ProgramShaderCache::CreateHeader()
"%s\n" // storage buffer
"%s\n" // shader5
"%s\n" // AEP
"%s\n" // texture buffer
// Precision defines for GLSL ES
"%s\n"
@ -563,6 +564,7 @@ void ProgramShaderCache::CreateHeader()
, g_ActiveConfig.backend_info.bSupportsBBox ? "#extension GL_ARB_shader_storage_buffer_object : enable" : ""
, g_ActiveConfig.backend_info.bSupportsGSInstancing ? "#extension GL_ARB_gpu_shader5 : enable" : ""
, g_ogl_config.bSupportsAEP ? "#extension GL_ANDROID_extension_pack_es31a : enable" : ""
, v<GLSL_140 && g_ActiveConfig.backend_info.bSupportsPaletteConversion ? "#extension GL_ARB_texture_buffer_object : enable" : ""
, v>=GLSLES_300 ? "precision highp float;" : ""
, v>=GLSLES_300 ? "precision highp int;" : ""

View File

@ -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
@ -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

View File

@ -18,6 +18,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"
@ -43,6 +44,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)
@ -237,12 +245,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)
@ -347,18 +370,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.0;
}
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.0;
}
float4 DecodePixel_IA8(int val)
{
int i = val & 0xFF;
int a = val >> 8;
return float4(i, i, i, a) / 255.0;
}
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();
}
}

View File

@ -134,13 +134,10 @@ static void InitBackendInfo()
{
g_Config.backend_info.APIType = API_OPENGL;
g_Config.backend_info.bSupportsExclusiveFullscreen = false;
//g_Config.backend_info.bSupportsDualSourceBlend = true; // is GPU dependent and must be set in renderer
//g_Config.backend_info.bSupportsEarlyZ = true; // is GPU dependent and must be set in renderer
g_Config.backend_info.bSupportsOversizedViewports = true;
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.Adapters.clear();