~ppsspp/ppsspp/ppsspp_1.3.0

« back to all changes in this revision

Viewing changes to GPU/GLES/DepalettizeShader.cpp

  • Committer: Sérgio Benjamim
  • Date: 2017-01-02 00:12:05 UTC
  • Revision ID: sergio_br2@yahoo.com.br-20170102001205-cxbta9za203nmjwm
1.3.0 source (from ppsspp_1.3.0-r160.p5.l1762.a165.t83~56~ubuntu16.04.1.tar.xz).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Copyright (c) 2014- PPSSPP Project.
 
2
 
 
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.
 
6
 
 
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.
 
11
 
 
12
// A copy of the GPL 2.0 should have been included with the program.
 
13
// If not, see http://www.gnu.org/licenses/
 
14
 
 
15
// Official git repository and contact information can be found at
 
16
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
 
17
 
 
18
#include <map>
 
19
 
 
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"
 
27
 
 
28
static const int DEPAL_TEXTURE_OLD_AGE = 120;
 
29
 
 
30
#ifdef _WIN32
 
31
#define SHADERLOG
 
32
#endif
 
33
 
 
34
static const char *depalVShader100 =
 
35
#ifdef USING_GLES2
 
36
"#version 100\n"
 
37
"precision highp float;\n"
 
38
#endif
 
39
"attribute vec4 a_position;\n"
 
40
"attribute vec2 a_texcoord0;\n"
 
41
"varying vec2 v_texcoord0;\n"
 
42
"void main() {\n"
 
43
"  v_texcoord0 = a_texcoord0;\n"
 
44
"  gl_Position = a_position;\n"
 
45
"}\n";
 
46
 
 
47
static const char *depalVShader300 =
 
48
#ifdef USING_GLES2
 
49
"#version 300 es\n"
 
50
"precision highp float;\n"
 
51
#else
 
52
"#version 330\n"
 
53
#endif
 
54
"in vec4 a_position;\n"
 
55
"in vec2 a_texcoord0;\n"
 
56
"out vec2 v_texcoord0;\n"
 
57
"void main() {\n"
 
58
"  v_texcoord0 = a_texcoord0;\n"
 
59
"  gl_Position = a_position;\n"
 
60
"}\n";
 
61
 
 
62
 
 
63
static bool CheckShaderCompileSuccess(GLuint shader, const char *code) {
 
64
        GLint success;
 
65
        glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
 
66
        if (!success) {
 
67
#define MAX_INFO_LOG_SIZE 2048
 
68
                GLchar infoLog[MAX_INFO_LOG_SIZE];
 
69
                GLsizei len;
 
70
                glGetShaderInfoLog(shader, MAX_INFO_LOG_SIZE, &len, infoLog);
 
71
                infoLog[len] = '\0';
 
72
#ifdef ANDROID
 
73
                ELOG("Error in shader compilation! %s\n", infoLog);
 
74
                ELOG("Shader source:\n%s\n", (const char *)code);
 
75
#endif
 
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);
 
79
#ifdef SHADERLOG
 
80
                OutputDebugStringUTF8(infoLog);
 
81
#endif
 
82
                shader = 0;
 
83
                return false;
 
84
        } else {
 
85
                DEBUG_LOG(G3D, "Compiled shader:\n%s\n", (const char *)code);
 
86
#ifdef SHADERLOG
 
87
                OutputDebugStringUTF8(code);
 
88
#endif
 
89
                return true;
 
90
        }
 
91
}
 
92
 
 
93
DepalShaderCache::DepalShaderCache() {
 
94
        // Pre-build the vertex program
 
95
        useGL3_ = gl_extensions.GLES3 || gl_extensions.VersionGEThan(3, 3);
 
96
 
 
97
        vertexShaderFailed_ = false;
 
98
        vertexShader_ = 0;
 
99
}
 
100
 
 
101
DepalShaderCache::~DepalShaderCache() {
 
102
        Clear();
 
103
}
 
104
 
 
105
bool DepalShaderCache::CreateVertexShader() {
 
106
        if (vertexShaderFailed_) {
 
107
                return false;
 
108
        }
 
109
 
 
110
        vertexShader_ = glCreateShader(GL_VERTEX_SHADER);
 
111
        glShaderSource(vertexShader_, 1, useGL3_ ? &depalVShader300 : &depalVShader100, 0);
 
112
        glCompileShader(vertexShader_);
 
113
 
 
114
        if (!CheckShaderCompileSuccess(vertexShader_, useGL3_ ? depalVShader300 : depalVShader100)) {
 
115
                glDeleteShader(vertexShader_);
 
116
                vertexShader_ = 0;
 
117
                // Don't try to recompile.
 
118
                vertexShaderFailed_ = true;
 
119
        }
 
120
 
 
121
        return !vertexShaderFailed_;
 
122
}
 
123
 
 
124
u32 DepalShaderCache::GenerateShaderID(GEPaletteFormat clutFormat, GEBufferFormat pixelFormat) {
 
125
        return (gstate.clutformat & 0xFFFFFF) | (pixelFormat << 24);
 
126
}
 
127
 
 
128
GLuint DepalShaderCache::GetClutTexture(GEPaletteFormat clutFormat, const u32 clutID, u32 *rawClut) {
 
129
        const u32 realClutID = clutID ^ clutFormat;
 
130
 
 
131
        auto oldtex = texCache_.find(realClutID);
 
132
        if (oldtex != texCache_.end()) {
 
133
                oldtex->second->lastFrame = gpuStats.numFlips;
 
134
                return oldtex->second->texture;
 
135
        }
 
136
 
 
137
        GLuint dstFmt = getClutDestFormat(clutFormat);
 
138
        int texturePixels = clutFormat == GE_CMODE_32BIT_ABGR8888 ? 256 : 512;
 
139
 
 
140
        bool useBGRA = UseBGRA8888() && dstFmt == GL_UNSIGNED_BYTE;
 
141
 
 
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;
 
146
 
 
147
        GLuint components2 = components;
 
148
        if (useBGRA) {
 
149
                components2 = GL_BGRA_EXT;
 
150
        }
 
151
 
 
152
        glTexImage2D(GL_TEXTURE_2D, 0, components, texturePixels, 1, 0, components2, dstFmt, (void *)rawClut);
 
153
 
 
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);
 
158
 
 
159
        tex->lastFrame = gpuStats.numFlips;
 
160
        texCache_[realClutID] = tex;
 
161
        return tex->texture;
 
162
}
 
163
 
 
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);
 
169
                }
 
170
                delete shader->second;
 
171
        }
 
172
        cache_.clear();
 
173
        for (auto tex = texCache_.begin(); tex != texCache_.end(); ++tex) {
 
174
                glDeleteTextures(1, &tex->second->texture);
 
175
                delete tex->second;
 
176
        }
 
177
        texCache_.clear();
 
178
        if (vertexShader_) {
 
179
                glDeleteShader(vertexShader_);
 
180
                vertexShader_ = 0;
 
181
        }
 
182
}
 
183
 
 
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);
 
188
                        delete tex->second;
 
189
                        texCache_.erase(tex++);
 
190
                } else {
 
191
                        ++tex;
 
192
                }
 
193
        }
 
194
}
 
195
 
 
196
DepalShader *DepalShaderCache::GetDepalettizeShader(GEPaletteFormat clutFormat, GEBufferFormat pixelFormat) {
 
197
        u32 id = GenerateShaderID(clutFormat, pixelFormat);
 
198
 
 
199
        auto shader = cache_.find(id);
 
200
        if (shader != cache_.end()) {
 
201
                return shader->second;
 
202
        }
 
203
 
 
204
        if (vertexShader_ == 0) {
 
205
                if (!CreateVertexShader()) {
 
206
                        // The vertex shader failed, no need to bother trying the fragment.
 
207
                        return nullptr;
 
208
                }
 
209
        }
 
210
 
 
211
        char *buffer = new char[2048];
 
212
 
 
213
        GenerateDepalShader(buffer, pixelFormat, useGL3_ ? GLSL_300 : GLSL_140);
 
214
 
 
215
        GLuint fragShader = glCreateShader(GL_FRAGMENT_SHADER);
 
216
 
 
217
        const char *buf = buffer;
 
218
        glShaderSource(fragShader, 1, &buf, 0);
 
219
        glCompileShader(fragShader);
 
220
 
 
221
        CheckShaderCompileSuccess(fragShader, buffer);
 
222
 
 
223
        GLuint program = glCreateProgram();
 
224
        glAttachShader(program, vertexShader_);
 
225
        glAttachShader(program, fragShader);
 
226
        
 
227
        glBindAttribLocation(program, 0, "a_position");
 
228
        glBindAttribLocation(program, 1, "a_texcoord0");
 
229
 
 
230
        glLinkProgram(program);
 
231
        glUseProgram(program);
 
232
 
 
233
        GLint u_tex = glGetUniformLocation(program, "tex");
 
234
        GLint u_pal = glGetUniformLocation(program, "pal");
 
235
 
 
236
        glUniform1i(u_tex, 0);
 
237
        glUniform1i(u_pal, 3);
 
238
 
 
239
        DepalShader *depal = new DepalShader();
 
240
        depal->program = program;
 
241
        depal->fragShader = fragShader;
 
242
        cache_[id] = depal;
 
243
 
 
244
        GLint linkStatus = GL_FALSE;
 
245
        glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
 
246
        if (linkStatus != GL_TRUE) {
 
247
                GLint bufLength = 0;
 
248
                glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength);
 
249
                if (bufLength) {
 
250
                        char* errorbuf = new char[bufLength];
 
251
                        glGetProgramInfoLog(program, bufLength, NULL, errorbuf);
 
252
#ifdef SHADERLOG
 
253
                        OutputDebugStringUTF8(buffer);
 
254
                        OutputDebugStringUTF8(errorbuf);
 
255
#endif
 
256
                        ERROR_LOG(G3D, "Could not link program:\n %s  \n\n %s", errorbuf, buf);
 
257
                        delete[] errorbuf;      // we're dead!
 
258
                }
 
259
 
 
260
                // Since it failed, let's mark it in the cache so we don't keep retrying.
 
261
                // That will only make it slower.
 
262
                depal->program = 0;
 
263
 
 
264
                // We will delete the shader later in Clear().
 
265
                glDeleteProgram(program);
 
266
        } else {
 
267
                depal->a_position = glGetAttribLocation(program, "a_position");
 
268
                depal->a_texcoord0 = glGetAttribLocation(program, "a_texcoord0");
 
269
        }
 
270
 
 
271
        delete[] buffer;
 
272
        return depal->program ? depal : nullptr;
 
273
}