1
// Copyright (c) 2014- PPSSPP Project.
3
// This program is free software: you can redistribute it and/or modify
4
// it under the terms of the GNU General Public License as published by
5
// the Free Software Foundation, version 2.0 or later versions.
7
// This program is distributed in the hope that it will be useful,
8
// but WITHOUT ANY WARRANTY; without even the implied warranty of
9
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
// GNU General Public License 2.0 for more details.
12
// A copy of the GPL 2.0 should have been included with the program.
13
// If not, see http://www.gnu.org/licenses/
15
// Official git repository and contact information can be found at
16
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
20
#include "base/logging.h"
21
#include "Common/Log.h"
22
#include "Core/Reporting.h"
23
#include "DepalettizeShader.h"
24
#include "GPU/GLES/TextureCache.h"
25
#include "GPU/GLES/GLStateCache.h"
26
#include "GPU/Common/DepalettizeShaderCommon.h"
28
static const int DEPAL_TEXTURE_OLD_AGE = 120;
34
static const char *depalVShader100 =
37
"precision highp float;\n"
39
"attribute vec4 a_position;\n"
40
"attribute vec2 a_texcoord0;\n"
41
"varying vec2 v_texcoord0;\n"
43
" v_texcoord0 = a_texcoord0;\n"
44
" gl_Position = a_position;\n"
47
static const char *depalVShader300 =
50
"precision highp float;\n"
54
"in vec4 a_position;\n"
55
"in vec2 a_texcoord0;\n"
56
"out vec2 v_texcoord0;\n"
58
" v_texcoord0 = a_texcoord0;\n"
59
" gl_Position = a_position;\n"
63
static bool CheckShaderCompileSuccess(GLuint shader, const char *code) {
65
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
67
#define MAX_INFO_LOG_SIZE 2048
68
GLchar infoLog[MAX_INFO_LOG_SIZE];
70
glGetShaderInfoLog(shader, MAX_INFO_LOG_SIZE, &len, infoLog);
73
ELOG("Error in shader compilation! %s\n", infoLog);
74
ELOG("Shader source:\n%s\n", (const char *)code);
76
ERROR_LOG(G3D, "Error in shader compilation!\n");
77
ERROR_LOG(G3D, "Info log: %s\n", infoLog);
78
ERROR_LOG(G3D, "Shader source:\n%s\n", (const char *)code);
80
OutputDebugStringUTF8(infoLog);
85
DEBUG_LOG(G3D, "Compiled shader:\n%s\n", (const char *)code);
87
OutputDebugStringUTF8(code);
93
DepalShaderCache::DepalShaderCache() {
94
// Pre-build the vertex program
95
useGL3_ = gl_extensions.GLES3 || gl_extensions.VersionGEThan(3, 3);
97
vertexShaderFailed_ = false;
101
DepalShaderCache::~DepalShaderCache() {
105
bool DepalShaderCache::CreateVertexShader() {
106
if (vertexShaderFailed_) {
110
vertexShader_ = glCreateShader(GL_VERTEX_SHADER);
111
glShaderSource(vertexShader_, 1, useGL3_ ? &depalVShader300 : &depalVShader100, 0);
112
glCompileShader(vertexShader_);
114
if (!CheckShaderCompileSuccess(vertexShader_, useGL3_ ? depalVShader300 : depalVShader100)) {
115
glDeleteShader(vertexShader_);
117
// Don't try to recompile.
118
vertexShaderFailed_ = true;
121
return !vertexShaderFailed_;
124
u32 DepalShaderCache::GenerateShaderID(GEPaletteFormat clutFormat, GEBufferFormat pixelFormat) {
125
return (gstate.clutformat & 0xFFFFFF) | (pixelFormat << 24);
128
GLuint DepalShaderCache::GetClutTexture(GEPaletteFormat clutFormat, const u32 clutID, u32 *rawClut) {
129
const u32 realClutID = clutID ^ clutFormat;
131
auto oldtex = texCache_.find(realClutID);
132
if (oldtex != texCache_.end()) {
133
oldtex->second->lastFrame = gpuStats.numFlips;
134
return oldtex->second->texture;
137
GLuint dstFmt = getClutDestFormat(clutFormat);
138
int texturePixels = clutFormat == GE_CMODE_32BIT_ABGR8888 ? 256 : 512;
140
bool useBGRA = UseBGRA8888() && dstFmt == GL_UNSIGNED_BYTE;
142
DepalTexture *tex = new DepalTexture();
143
glGenTextures(1, &tex->texture);
144
glBindTexture(GL_TEXTURE_2D, tex->texture);
145
GLuint components = dstFmt == GL_UNSIGNED_SHORT_5_6_5 ? GL_RGB : GL_RGBA;
147
GLuint components2 = components;
149
components2 = GL_BGRA_EXT;
152
glTexImage2D(GL_TEXTURE_2D, 0, components, texturePixels, 1, 0, components2, dstFmt, (void *)rawClut);
154
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
155
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
156
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
157
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
159
tex->lastFrame = gpuStats.numFlips;
160
texCache_[realClutID] = tex;
164
void DepalShaderCache::Clear() {
165
for (auto shader = cache_.begin(); shader != cache_.end(); ++shader) {
166
glDeleteShader(shader->second->fragShader);
167
if (shader->second->program) {
168
glDeleteProgram(shader->second->program);
170
delete shader->second;
173
for (auto tex = texCache_.begin(); tex != texCache_.end(); ++tex) {
174
glDeleteTextures(1, &tex->second->texture);
179
glDeleteShader(vertexShader_);
184
void DepalShaderCache::Decimate() {
185
for (auto tex = texCache_.begin(); tex != texCache_.end(); ) {
186
if (tex->second->lastFrame + DEPAL_TEXTURE_OLD_AGE < gpuStats.numFlips) {
187
glDeleteTextures(1, &tex->second->texture);
189
texCache_.erase(tex++);
196
DepalShader *DepalShaderCache::GetDepalettizeShader(GEPaletteFormat clutFormat, GEBufferFormat pixelFormat) {
197
u32 id = GenerateShaderID(clutFormat, pixelFormat);
199
auto shader = cache_.find(id);
200
if (shader != cache_.end()) {
201
return shader->second;
204
if (vertexShader_ == 0) {
205
if (!CreateVertexShader()) {
206
// The vertex shader failed, no need to bother trying the fragment.
211
char *buffer = new char[2048];
213
GenerateDepalShader(buffer, pixelFormat, useGL3_ ? GLSL_300 : GLSL_140);
215
GLuint fragShader = glCreateShader(GL_FRAGMENT_SHADER);
217
const char *buf = buffer;
218
glShaderSource(fragShader, 1, &buf, 0);
219
glCompileShader(fragShader);
221
CheckShaderCompileSuccess(fragShader, buffer);
223
GLuint program = glCreateProgram();
224
glAttachShader(program, vertexShader_);
225
glAttachShader(program, fragShader);
227
glBindAttribLocation(program, 0, "a_position");
228
glBindAttribLocation(program, 1, "a_texcoord0");
230
glLinkProgram(program);
231
glUseProgram(program);
233
GLint u_tex = glGetUniformLocation(program, "tex");
234
GLint u_pal = glGetUniformLocation(program, "pal");
236
glUniform1i(u_tex, 0);
237
glUniform1i(u_pal, 3);
239
DepalShader *depal = new DepalShader();
240
depal->program = program;
241
depal->fragShader = fragShader;
244
GLint linkStatus = GL_FALSE;
245
glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
246
if (linkStatus != GL_TRUE) {
248
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength);
250
char* errorbuf = new char[bufLength];
251
glGetProgramInfoLog(program, bufLength, NULL, errorbuf);
253
OutputDebugStringUTF8(buffer);
254
OutputDebugStringUTF8(errorbuf);
256
ERROR_LOG(G3D, "Could not link program:\n %s \n\n %s", errorbuf, buf);
257
delete[] errorbuf; // we're dead!
260
// Since it failed, let's mark it in the cache so we don't keep retrying.
261
// That will only make it slower.
264
// We will delete the shader later in Clear().
265
glDeleteProgram(program);
267
depal->a_position = glGetAttribLocation(program, "a_position");
268
depal->a_texcoord0 = glGetAttribLocation(program, "a_texcoord0");
272
return depal->program ? depal : nullptr;