CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
hrydgard

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

GitHub Repository: hrydgard/ppsspp
Path: blob/master/Common/GPU/OpenGL/GLSLProgram.cpp
Views: 1401
1
#include <set>
2
3
#include <cstdio>
4
#include <cstring>
5
#include <sys/stat.h>
6
7
#include "Common/File/VFS/VFS.h"
8
#include "Common/File/FileUtil.h"
9
#include "Common/GPU/OpenGL/GLSLProgram.h"
10
11
#include "Common/Log.h"
12
13
static std::set<GLSLProgram *> active_programs;
14
15
bool CompileShader(const char *source, GLuint shader, const char *filename, std::string *error_message) {
16
glShaderSource(shader, 1, &source, NULL);
17
glCompileShader(shader);
18
GLint success;
19
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
20
if (!success) {
21
#define MAX_INFO_LOG_SIZE 2048
22
GLchar infoLog[MAX_INFO_LOG_SIZE];
23
GLsizei len;
24
glGetShaderInfoLog(shader, MAX_INFO_LOG_SIZE, &len, infoLog);
25
infoLog[len] = '\0';
26
ERROR_LOG(Log::G3D, "Error in shader compilation of %s!\n", filename);
27
ERROR_LOG(Log::G3D, "Info log: %s\n", infoLog);
28
ERROR_LOG(Log::G3D, "Shader source:\n%s\n", (const char *)source);
29
if (error_message)
30
*error_message = infoLog;
31
return false;
32
}
33
return true;
34
}
35
36
GLSLProgram *glsl_create_source(const char *vshader_src, const char *fshader_src, std::string *error_message) {
37
GLSLProgram *program = new GLSLProgram();
38
program->program_ = 0;
39
program->vsh_ = 0;
40
program->fsh_ = 0;
41
program->vshader_source = vshader_src;
42
program->fshader_source = fshader_src;
43
strcpy(program->name, "[srcshader]");
44
strcpy(program->vshader_filename, "");
45
strcpy(program->fshader_filename, "");
46
if (glsl_recompile(program, error_message)) {
47
active_programs.insert(program);
48
} else {
49
ERROR_LOG(Log::G3D, "Failed compiling GLSL program from source strings");
50
delete program;
51
return 0;
52
}
53
return program;
54
}
55
56
// Not wanting to change ReadLocalFile semantics.
57
// TODO: Use C++11 unique_ptr, remove delete[]
58
struct AutoCharArrayBuf {
59
AutoCharArrayBuf(char *buf = nullptr) : buf_(buf) {
60
}
61
~AutoCharArrayBuf() {
62
delete [] buf_;
63
buf_ = nullptr;
64
}
65
void reset(char *buf) {
66
delete[] buf_;
67
buf_ = buf;
68
}
69
operator char *() {
70
return buf_;
71
}
72
73
private:
74
char *buf_;
75
};
76
77
bool glsl_recompile(GLSLProgram *program, std::string *error_message) {
78
struct stat vs, fs;
79
AutoCharArrayBuf vsh_src, fsh_src;
80
81
if (strlen(program->vshader_filename) > 0 && 0 == stat(program->vshader_filename, &vs)) {
82
program->vshader_mtime = vs.st_mtime;
83
if (!program->vshader_source) {
84
size_t sz;
85
vsh_src.reset((char *)File::ReadLocalFile(Path(program->vshader_filename), &sz));
86
}
87
} else {
88
program->vshader_mtime = 0;
89
}
90
91
if (strlen(program->fshader_filename) > 0 && 0 == stat(program->fshader_filename, &fs)) {
92
program->fshader_mtime = fs.st_mtime;
93
if (!program->fshader_source) {
94
size_t sz;
95
fsh_src.reset((char *)File::ReadLocalFile(Path(program->fshader_filename), &sz));
96
}
97
} else {
98
program->fshader_mtime = 0;
99
}
100
101
if (!program->vshader_source && !vsh_src) {
102
size_t sz;
103
vsh_src.reset((char *)g_VFS.ReadFile(program->vshader_filename, &sz));
104
}
105
if (!program->vshader_source && !vsh_src) {
106
ERROR_LOG(Log::G3D, "File missing: %s", program->vshader_filename);
107
if (error_message) {
108
*error_message = std::string("File missing: ") + program->vshader_filename;
109
}
110
return false;
111
}
112
if (!program->fshader_source && !fsh_src) {
113
size_t sz;
114
fsh_src.reset((char *)g_VFS.ReadFile(program->fshader_filename, &sz));
115
}
116
if (!program->fshader_source && !fsh_src) {
117
ERROR_LOG(Log::G3D, "File missing: %s", program->fshader_filename);
118
if (error_message) {
119
*error_message = std::string("File missing: ") + program->fshader_filename;
120
}
121
return false;
122
}
123
124
GLuint vsh = glCreateShader(GL_VERTEX_SHADER);
125
const GLchar *vsh_str = program->vshader_source ? program->vshader_source : (const GLchar *)(vsh_src);
126
if (!CompileShader(vsh_str, vsh, program->vshader_filename, error_message)) {
127
return false;
128
}
129
130
const GLchar *fsh_str = program->fshader_source ? program->fshader_source : (const GLchar *)(fsh_src);
131
GLuint fsh = glCreateShader(GL_FRAGMENT_SHADER);
132
if (!CompileShader(fsh_str, fsh, program->fshader_filename, error_message)) {
133
glDeleteShader(vsh);
134
return false;
135
}
136
137
GLuint prog = glCreateProgram();
138
glAttachShader(prog, vsh);
139
glAttachShader(prog, fsh);
140
141
glLinkProgram(prog);
142
143
GLint linkStatus;
144
glGetProgramiv(prog, GL_LINK_STATUS, &linkStatus);
145
if (linkStatus == GL_FALSE) {
146
GLint bufLength = 0;
147
glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &bufLength);
148
if (bufLength) {
149
char* buf = new char[bufLength + 1]; // safety
150
glGetProgramInfoLog(prog, bufLength, NULL, buf);
151
INFO_LOG(Log::G3D, "vsh: %i fsh: %i", vsh, fsh);
152
ERROR_LOG(Log::G3D, "Could not link shader program (linkstatus=%i):\n %s \n", linkStatus, buf);
153
if (error_message) {
154
*error_message = buf;
155
}
156
delete [] buf;
157
} else {
158
INFO_LOG(Log::G3D, "vsh: %i fsh: %i", vsh, fsh);
159
ERROR_LOG(Log::G3D, "Could not link shader program (linkstatus=%i). No OpenGL error log was available.", linkStatus);
160
if (error_message) {
161
*error_message = "(no error message available)";
162
}
163
}
164
glDeleteShader(vsh);
165
glDeleteShader(fsh);
166
return false;
167
}
168
169
// Destroy the old program, if any.
170
if (program->program_) {
171
glDeleteProgram(program->program_);
172
}
173
174
program->program_ = prog;
175
program->vsh_ = vsh;
176
program->fsh_ = fsh;
177
178
program->sampler0 = glGetUniformLocation(program->program_, "sampler0");
179
program->sampler1 = glGetUniformLocation(program->program_, "sampler1");
180
181
program->a_position = glGetAttribLocation(program->program_, "a_position");
182
program->a_color = glGetAttribLocation(program->program_, "a_color");
183
program->a_normal = glGetAttribLocation(program->program_, "a_normal");
184
program->a_texcoord0 = glGetAttribLocation(program->program_, "a_texcoord0");
185
program->a_texcoord1 = glGetAttribLocation(program->program_, "a_texcoord1");
186
187
program->u_worldviewproj = glGetUniformLocation(program->program_, "u_worldviewproj");
188
program->u_world = glGetUniformLocation(program->program_, "u_world");
189
program->u_viewproj = glGetUniformLocation(program->program_, "u_viewproj");
190
program->u_fog = glGetUniformLocation(program->program_, "u_fog");
191
program->u_sundir = glGetUniformLocation(program->program_, "u_sundir");
192
program->u_camerapos = glGetUniformLocation(program->program_, "u_camerapos");
193
194
//INFO_LOG(Log::G3D, "Shader compilation success: %s %s",
195
// program->vshader_filename,
196
// program->fshader_filename);
197
return true;
198
}
199
200
int glsl_attrib_loc(const GLSLProgram *program, const char *name) {
201
return glGetAttribLocation(program->program_, name);
202
}
203
204
int glsl_uniform_loc(const GLSLProgram *program, const char *name) {
205
return glGetUniformLocation(program->program_, name);
206
}
207
208
void glsl_destroy(GLSLProgram *program) {
209
if (program) {
210
glDeleteShader(program->vsh_);
211
glDeleteShader(program->fsh_);
212
glDeleteProgram(program->program_);
213
active_programs.erase(program);
214
} else {
215
ERROR_LOG(Log::G3D, "Deleting null GLSL program!");
216
}
217
delete program;
218
}
219
220
static const GLSLProgram *curProgram;
221
222
void glsl_bind(const GLSLProgram *program) {
223
if (program)
224
glUseProgram(program->program_);
225
else
226
glUseProgram(0);
227
curProgram = program;
228
}
229
230
void glsl_unbind() {
231
glUseProgram(0);
232
curProgram = nullptr;
233
}
234
235
const GLSLProgram *glsl_get_program() {
236
return curProgram;
237
}
238
239