2016-09-14 18:01:13 +00:00
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
// Copyright(C) 2016 Magnus Norddahl
|
|
|
|
// All rights reserved.
|
|
|
|
//
|
|
|
|
// This program is free software: you can redistribute it and/or modify
|
|
|
|
// it under the terms of the GNU Lesser General Public License as published by
|
|
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
|
|
// (at your option) any later version.
|
|
|
|
//
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
// GNU Lesser General Public License for more details.
|
|
|
|
//
|
|
|
|
// You should have received a copy of the GNU Lesser General Public License
|
|
|
|
// along with this program. If not, see http://www.gnu.org/licenses/
|
|
|
|
//
|
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
//
|
2016-07-26 19:27:02 +00:00
|
|
|
/*
|
|
|
|
** gl_shaderprogram.cpp
|
|
|
|
** GLSL shader program compile and link
|
|
|
|
**
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "gl/system/gl_system.h"
|
|
|
|
#include "files.h"
|
|
|
|
#include "m_swap.h"
|
|
|
|
#include "v_video.h"
|
|
|
|
#include "gl/gl_functions.h"
|
|
|
|
#include "vectors.h"
|
|
|
|
#include "gl/system/gl_interface.h"
|
|
|
|
#include "gl/system/gl_cvars.h"
|
2016-08-17 21:18:47 +00:00
|
|
|
#include "gl/system/gl_debug.h"
|
2016-07-26 19:27:02 +00:00
|
|
|
#include "gl/shaders/gl_shaderprogram.h"
|
|
|
|
#include "w_wad.h"
|
|
|
|
#include "i_system.h"
|
|
|
|
#include "doomerrors.h"
|
|
|
|
|
2016-08-25 23:40:28 +00:00
|
|
|
FShaderProgram::FShaderProgram()
|
|
|
|
{
|
|
|
|
for (int i = 0; i < NumShaderTypes; i++)
|
|
|
|
mShaders[i] = 0;
|
|
|
|
}
|
|
|
|
|
2016-07-26 19:27:02 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// Free shader program resources
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
FShaderProgram::~FShaderProgram()
|
|
|
|
{
|
|
|
|
if (mProgram != 0)
|
|
|
|
glDeleteProgram(mProgram);
|
|
|
|
|
|
|
|
for (int i = 0; i < NumShaderTypes; i++)
|
|
|
|
{
|
|
|
|
if (mShaders[i] != 0)
|
|
|
|
glDeleteShader(mShaders[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// Creates an OpenGL shader object for the specified type of shader
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
void FShaderProgram::CreateShader(ShaderType type)
|
|
|
|
{
|
|
|
|
GLenum gltype = 0;
|
|
|
|
switch (type)
|
|
|
|
{
|
|
|
|
default:
|
|
|
|
case Vertex: gltype = GL_VERTEX_SHADER; break;
|
|
|
|
case Fragment: gltype = GL_FRAGMENT_SHADER; break;
|
|
|
|
}
|
|
|
|
mShaders[type] = glCreateShader(gltype);
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// Compiles a shader and attaches it the program object
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
2016-07-29 19:31:20 +00:00
|
|
|
void FShaderProgram::Compile(ShaderType type, const char *lumpName, const char *defines, int maxGlslVersion)
|
2016-07-26 19:27:02 +00:00
|
|
|
{
|
|
|
|
int lump = Wads.CheckNumForFullName(lumpName);
|
2016-07-29 19:31:20 +00:00
|
|
|
if (lump == -1) I_FatalError("Unable to load '%s'", lumpName);
|
2016-07-26 19:27:02 +00:00
|
|
|
FString code = Wads.ReadLump(lump).GetString().GetChars();
|
2016-07-29 19:31:20 +00:00
|
|
|
Compile(type, lumpName, code, defines, maxGlslVersion);
|
2016-07-27 19:50:30 +00:00
|
|
|
}
|
|
|
|
|
2016-07-29 19:31:20 +00:00
|
|
|
void FShaderProgram::Compile(ShaderType type, const char *name, const FString &code, const char *defines, int maxGlslVersion)
|
2016-07-27 19:50:30 +00:00
|
|
|
{
|
|
|
|
CreateShader(type);
|
|
|
|
|
|
|
|
const auto &handle = mShaders[type];
|
2016-07-26 19:27:02 +00:00
|
|
|
|
2016-08-17 21:18:47 +00:00
|
|
|
FGLDebug::LabelObject(GL_SHADER, handle, name);
|
|
|
|
|
2016-07-29 19:31:20 +00:00
|
|
|
FString patchedCode = PatchShader(type, code, defines, maxGlslVersion);
|
|
|
|
int lengths[1] = { (int)patchedCode.Len() };
|
|
|
|
const char *sources[1] = { patchedCode.GetChars() };
|
2016-07-26 19:27:02 +00:00
|
|
|
glShaderSource(handle, 1, sources, lengths);
|
|
|
|
|
|
|
|
glCompileShader(handle);
|
|
|
|
|
|
|
|
GLint status = 0;
|
|
|
|
glGetShaderiv(handle, GL_COMPILE_STATUS, &status);
|
|
|
|
if (status == GL_FALSE)
|
|
|
|
{
|
2016-07-29 19:31:20 +00:00
|
|
|
I_FatalError("Compile Shader '%s':\n%s\n", name, GetShaderInfoLog(handle).GetChars());
|
2016-07-26 19:27:02 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (mProgram == 0)
|
|
|
|
mProgram = glCreateProgram();
|
|
|
|
glAttachShader(mProgram, handle);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// Binds a fragment output variable to a frame buffer render target
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
void FShaderProgram::SetFragDataLocation(int index, const char *name)
|
|
|
|
{
|
|
|
|
glBindFragDataLocation(mProgram, index, name);
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// Links a program with the compiled shaders
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
void FShaderProgram::Link(const char *name)
|
|
|
|
{
|
2016-08-17 21:18:47 +00:00
|
|
|
FGLDebug::LabelObject(GL_PROGRAM, mProgram, name);
|
2016-07-26 19:27:02 +00:00
|
|
|
glLinkProgram(mProgram);
|
|
|
|
|
|
|
|
GLint status = 0;
|
|
|
|
glGetProgramiv(mProgram, GL_LINK_STATUS, &status);
|
|
|
|
if (status == GL_FALSE)
|
|
|
|
{
|
2016-07-29 19:31:20 +00:00
|
|
|
I_FatalError("Link Shader '%s':\n%s\n", name, GetProgramInfoLog(mProgram).GetChars());
|
2016-07-26 19:27:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// Set vertex attribute location
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
void FShaderProgram::SetAttribLocation(int index, const char *name)
|
|
|
|
{
|
|
|
|
glBindAttribLocation(mProgram, index, name);
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// Makes the shader the active program
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
void FShaderProgram::Bind()
|
|
|
|
{
|
|
|
|
glUseProgram(mProgram);
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// Returns the shader info log (warnings and compile errors)
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
FString FShaderProgram::GetShaderInfoLog(GLuint handle)
|
|
|
|
{
|
|
|
|
static char buffer[10000];
|
|
|
|
GLsizei length = 0;
|
|
|
|
buffer[0] = 0;
|
|
|
|
glGetShaderInfoLog(handle, 10000, &length, buffer);
|
|
|
|
return FString(buffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// Returns the program info log (warnings and compile errors)
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
FString FShaderProgram::GetProgramInfoLog(GLuint handle)
|
|
|
|
{
|
|
|
|
static char buffer[10000];
|
|
|
|
GLsizei length = 0;
|
|
|
|
buffer[0] = 0;
|
|
|
|
glGetProgramInfoLog(handle, 10000, &length, buffer);
|
|
|
|
return FString(buffer);
|
|
|
|
}
|
2016-07-29 19:31:20 +00:00
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// Patches a shader to be compatible with the version of OpenGL in use
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
FString FShaderProgram::PatchShader(ShaderType type, const FString &code, const char *defines, int maxGlslVersion)
|
|
|
|
{
|
|
|
|
FString patchedCode;
|
|
|
|
|
|
|
|
int shaderVersion = MIN((int)round(gl.glslversion * 10) * 10, maxGlslVersion);
|
|
|
|
patchedCode.AppendFormat("#version %d\n", shaderVersion);
|
|
|
|
|
|
|
|
// TODO: Find some way to add extension requirements to the patching
|
|
|
|
//
|
|
|
|
// #extension GL_ARB_uniform_buffer_object : require
|
|
|
|
// #extension GL_ARB_shader_storage_buffer_object : require
|
|
|
|
|
|
|
|
if (defines)
|
|
|
|
patchedCode << defines;
|
|
|
|
|
2016-09-01 09:52:52 +00:00
|
|
|
// these settings are actually pointless but there seem to be some old ATI drivers that fail to compile the shader without setting the precision here.
|
|
|
|
patchedCode << "precision highp int;\n";
|
|
|
|
patchedCode << "precision highp float;\n";
|
2016-07-29 19:31:20 +00:00
|
|
|
|
|
|
|
patchedCode << "#line 1\n";
|
|
|
|
patchedCode << code;
|
|
|
|
|
|
|
|
return patchedCode;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// patch the shader source to work with
|
|
|
|
// GLSL 1.2 keywords and identifiers
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|