2014-08-21 09:27:53 +02:00
|
|
|
// Copyright 2014 Citra Emulator Project
|
2014-12-17 06:38:14 +01:00
|
|
|
// Licensed under GPLv2 or any later version
|
2014-08-21 09:27:53 +02:00
|
|
|
// Refer to the license.txt file included.
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
2018-05-19 18:19:34 +02:00
|
|
|
#include <string>
|
2018-03-20 03:57:22 +01:00
|
|
|
#include <vector>
|
2015-08-30 08:37:42 +02:00
|
|
|
#include <glad/glad.h>
|
2018-04-07 07:09:33 +02:00
|
|
|
#include "common/assert.h"
|
|
|
|
#include "common/logging/log.h"
|
2014-08-21 09:27:53 +02:00
|
|
|
|
2015-10-06 04:33:47 +02:00
|
|
|
namespace GLShader {
|
2014-08-21 09:27:53 +02:00
|
|
|
|
2018-05-19 18:19:34 +02:00
|
|
|
/**
|
|
|
|
* Utility function to log the source code of a list of shaders.
|
|
|
|
* @param shaders The OpenGL shaders whose source we will print.
|
|
|
|
*/
|
|
|
|
template <typename... T>
|
|
|
|
void LogShaderSource(T... shaders) {
|
|
|
|
auto shader_list = {shaders...};
|
|
|
|
|
|
|
|
for (const auto& shader : shader_list) {
|
|
|
|
if (shader == 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
GLint source_length;
|
|
|
|
glGetShaderiv(shader, GL_SHADER_SOURCE_LENGTH, &source_length);
|
|
|
|
|
|
|
|
std::string source(source_length, ' ');
|
|
|
|
glGetShaderSource(shader, source_length, nullptr, &source[0]);
|
2018-07-02 18:13:26 +02:00
|
|
|
LOG_INFO(Render_OpenGL, "Shader source {}", source);
|
2018-05-19 18:19:34 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-07 05:54:44 +02:00
|
|
|
/**
|
|
|
|
* Utility function to create and compile an OpenGL GLSL shader
|
|
|
|
* @param source String of the GLSL shader program
|
|
|
|
* @param type Type of the shader (GL_VERTEX_SHADER, GL_GEOMETRY_SHADER or GL_FRAGMENT_SHADER)
|
|
|
|
*/
|
|
|
|
GLuint LoadShader(const char* source, GLenum type);
|
|
|
|
|
2015-10-07 00:10:32 +02:00
|
|
|
/**
|
|
|
|
* Utility function to create and compile an OpenGL GLSL shader program (vertex + fragment shader)
|
2018-04-07 05:54:44 +02:00
|
|
|
* @param separable_program whether to create a separable program
|
|
|
|
* @param shaders ID of shaders to attach to the program
|
|
|
|
* @returns Handle of the newly created OpenGL program object
|
2015-10-07 00:10:32 +02:00
|
|
|
*/
|
2018-04-07 05:54:44 +02:00
|
|
|
template <typename... T>
|
|
|
|
GLuint LoadProgram(bool separable_program, T... shaders) {
|
|
|
|
// Link the program
|
2018-07-02 18:13:26 +02:00
|
|
|
LOG_DEBUG(Render_OpenGL, "Linking program...");
|
2018-04-07 05:54:44 +02:00
|
|
|
|
|
|
|
GLuint program_id = glCreateProgram();
|
|
|
|
|
|
|
|
((shaders == 0 ? (void)0 : glAttachShader(program_id, shaders)), ...);
|
|
|
|
|
|
|
|
if (separable_program) {
|
|
|
|
glProgramParameteri(program_id, GL_PROGRAM_SEPARABLE, GL_TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
glLinkProgram(program_id);
|
|
|
|
|
|
|
|
// Check the program
|
|
|
|
GLint result = GL_FALSE;
|
|
|
|
GLint info_log_length;
|
|
|
|
glGetProgramiv(program_id, GL_LINK_STATUS, &result);
|
|
|
|
glGetProgramiv(program_id, GL_INFO_LOG_LENGTH, &info_log_length);
|
|
|
|
|
|
|
|
if (info_log_length > 1) {
|
|
|
|
std::string program_error(info_log_length, ' ');
|
|
|
|
glGetProgramInfoLog(program_id, info_log_length, nullptr, &program_error[0]);
|
|
|
|
if (result == GL_TRUE) {
|
2018-07-02 18:13:26 +02:00
|
|
|
LOG_DEBUG(Render_OpenGL, "{}", program_error);
|
2018-04-07 05:54:44 +02:00
|
|
|
} else {
|
2018-07-02 18:13:26 +02:00
|
|
|
LOG_ERROR(Render_OpenGL, "Error linking shader:\n{}", program_error);
|
2018-04-07 05:54:44 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-19 18:19:34 +02:00
|
|
|
if (result == GL_FALSE) {
|
|
|
|
// There was a problem linking the shader, print the source for debugging purposes.
|
|
|
|
LogShaderSource(shaders...);
|
|
|
|
}
|
|
|
|
|
2018-04-07 05:54:44 +02:00
|
|
|
ASSERT_MSG(result == GL_TRUE, "Shader not linked");
|
|
|
|
|
|
|
|
((shaders == 0 ? (void)0 : glDetachShader(program_id, shaders)), ...);
|
|
|
|
|
|
|
|
return program_id;
|
|
|
|
}
|
2014-08-21 09:27:53 +02:00
|
|
|
|
2018-01-20 08:48:02 +01:00
|
|
|
} // namespace GLShader
|