Files
ppsspp/Common/GPU/OpenGL/GLSLProgram.cpp
Henrik RydgårdandClaude Opus 5 86cd7c43e1 GLSLProgram: Cut it down to what's actually used, fix a shader leak
This is a leftover from the old "native" library. Its only users are the Win32 GE
debugger's preview windows, which call glsl_create_source/destroy/bind/unbind and
read four locations off the struct.

Everything else was dead: glsl_create was declared but never defined anywhere,
which made the entire file-loading and auto-reload half of glsl_recompile
unreachable (glsl_create_source always passes empty filenames), along with the
mtime fields, AutoCharArrayBuf and the VFS/stat includes. glsl_attrib_loc,
glsl_uniform_loc and glsl_get_program had no callers, and the active_programs set
was written and never read. The unused convenience locations cost a
glGetUniformLocation round trip each at link time.

The bug: the vertex shader was leaked when its own compile failed - the fragment
path right below it already deleted it correctly. Failed links leaked the program
object too.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vd8ntC2brCUtCrDJMqLbs8
2026-08-28 23:27:28 +02:00

119 lines
3.3 KiB
C++

#include <cstdio>
#include <cstring>
#include "Common/GPU/OpenGL/GLSLProgram.h"
#include "Common/Log.h"
static bool CompileShader(const char *source, GLuint shader, const char *stageName, std::string *error_message) {
glShaderSource(shader, 1, &source, nullptr);
glCompileShader(shader);
GLint success;
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
if (!success) {
#define MAX_INFO_LOG_SIZE 2048
GLchar infoLog[MAX_INFO_LOG_SIZE];
GLsizei len;
glGetShaderInfoLog(shader, MAX_INFO_LOG_SIZE, &len, infoLog);
infoLog[len] = '\0';
ERROR_LOG(Log::G3D, "Error compiling %s shader!\n", stageName);
ERROR_LOG(Log::G3D, "Info log: %s\n", infoLog);
ERROR_LOG(Log::G3D, "Shader source:\n%s\n", source);
if (error_message)
*error_message = infoLog;
return false;
}
return true;
}
static bool glsl_compile(GLSLProgram *program, const char *vshader_src, const char *fshader_src, std::string *error_message) {
GLuint vsh = glCreateShader(GL_VERTEX_SHADER);
if (!CompileShader(vshader_src, vsh, "vertex", error_message)) {
glDeleteShader(vsh);
return false;
}
GLuint fsh = glCreateShader(GL_FRAGMENT_SHADER);
if (!CompileShader(fshader_src, fsh, "fragment", error_message)) {
glDeleteShader(vsh);
glDeleteShader(fsh);
return false;
}
GLuint prog = glCreateProgram();
glAttachShader(prog, vsh);
glAttachShader(prog, fsh);
glLinkProgram(prog);
GLint linkStatus;
glGetProgramiv(prog, GL_LINK_STATUS, &linkStatus);
if (linkStatus == GL_FALSE) {
GLint bufLength = 0;
glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &bufLength);
if (bufLength) {
char *buf = new char[bufLength + 1]; // safety
glGetProgramInfoLog(prog, bufLength, nullptr, buf);
ERROR_LOG(Log::G3D, "Could not link shader program (linkstatus=%i):\n %s \n", linkStatus, buf);
if (error_message) {
*error_message = buf;
}
delete[] buf;
} else {
ERROR_LOG(Log::G3D, "Could not link shader program (linkstatus=%i). No OpenGL error log was available.", linkStatus);
if (error_message) {
*error_message = "(no error message available)";
}
}
glDeleteProgram(prog);
glDeleteShader(vsh);
glDeleteShader(fsh);
return false;
}
program->program_ = prog;
program->vsh_ = vsh;
program->fsh_ = fsh;
program->sampler0 = glGetUniformLocation(program->program_, "sampler0");
program->u_viewproj = glGetUniformLocation(program->program_, "u_viewproj");
program->a_position = glGetAttribLocation(program->program_, "a_position");
program->a_texcoord0 = glGetAttribLocation(program->program_, "a_texcoord0");
return true;
}
GLSLProgram *glsl_create_source(const char *vshader_src, const char *fshader_src, std::string *error_message) {
GLSLProgram *program = new GLSLProgram();
program->program_ = 0;
program->vsh_ = 0;
program->fsh_ = 0;
if (!glsl_compile(program, vshader_src, fshader_src, error_message)) {
ERROR_LOG(Log::G3D, "Failed compiling GLSL program from source strings");
delete program;
return nullptr;
}
return program;
}
void glsl_destroy(GLSLProgram *program) {
if (program) {
glDeleteShader(program->vsh_);
glDeleteShader(program->fsh_);
glDeleteProgram(program->program_);
} else {
ERROR_LOG(Log::G3D, "Deleting null GLSL program!");
}
delete program;
}
void glsl_bind(const GLSLProgram *program) {
if (program)
glUseProgram(program->program_);
else
glUseProgram(0);
}
void glsl_unbind() {
glUseProgram(0);
}