218 lines
8.1 KiB
C++
218 lines
8.1 KiB
C++
#include "ShaderProgramCompiler.h"
|
|
|
|
#include "GlRenderConstants.h"
|
|
#include "GlScopedObjects.h"
|
|
#include "GlShaderSources.h"
|
|
|
|
#include <cstring>
|
|
#include <vector>
|
|
|
|
namespace
|
|
{
|
|
void CopyErrorMessage(const std::string& message, int errorMessageSize, char* errorMessage)
|
|
{
|
|
if (!errorMessage || errorMessageSize <= 0)
|
|
return;
|
|
|
|
strncpy_s(errorMessage, errorMessageSize, message.c_str(), _TRUNCATE);
|
|
}
|
|
}
|
|
|
|
ShaderProgramCompiler::ShaderProgramCompiler(OpenGLRenderer& renderer, RuntimeHost& runtimeHost, ShaderTextureBindings& textureBindings) :
|
|
mRenderer(renderer),
|
|
mRuntimeHost(runtimeHost),
|
|
mTextureBindings(textureBindings)
|
|
{
|
|
}
|
|
|
|
bool ShaderProgramCompiler::CompileLayerProgram(const RuntimeRenderState& state, LayerProgram& layerProgram, int errorMessageSize, char* errorMessage)
|
|
{
|
|
std::string fragmentShaderSource;
|
|
std::string loadError;
|
|
|
|
if (!mRuntimeHost.BuildLayerFragmentShaderSource(state.layerId, fragmentShaderSource, loadError))
|
|
{
|
|
CopyErrorMessage(loadError, errorMessageSize, errorMessage);
|
|
return false;
|
|
}
|
|
|
|
return CompilePreparedLayerProgram(state, fragmentShaderSource, layerProgram, errorMessageSize, errorMessage);
|
|
}
|
|
|
|
bool ShaderProgramCompiler::CompilePreparedLayerProgram(const RuntimeRenderState& state, const std::string& fragmentShaderSource, LayerProgram& layerProgram, int errorMessageSize, char* errorMessage)
|
|
{
|
|
GLsizei errorBufferSize = 0;
|
|
GLint compileResult = GL_FALSE;
|
|
GLint linkResult = GL_FALSE;
|
|
std::string loadError;
|
|
std::vector<LayerProgram::TextureBinding> textureBindings;
|
|
const char* vertexSource = kFullscreenTriangleVertexShaderSource;
|
|
const char* fragmentSource = fragmentShaderSource.c_str();
|
|
|
|
ScopedGlShader newVertexShader(glCreateShader(GL_VERTEX_SHADER));
|
|
glShaderSource(newVertexShader.get(), 1, (const GLchar**)&vertexSource, NULL);
|
|
glCompileShader(newVertexShader.get());
|
|
glGetShaderiv(newVertexShader.get(), GL_COMPILE_STATUS, &compileResult);
|
|
if (compileResult == GL_FALSE)
|
|
{
|
|
glGetShaderInfoLog(newVertexShader.get(), errorMessageSize, &errorBufferSize, errorMessage);
|
|
return false;
|
|
}
|
|
|
|
ScopedGlShader newFragmentShader(glCreateShader(GL_FRAGMENT_SHADER));
|
|
glShaderSource(newFragmentShader.get(), 1, (const GLchar**)&fragmentSource, NULL);
|
|
glCompileShader(newFragmentShader.get());
|
|
glGetShaderiv(newFragmentShader.get(), GL_COMPILE_STATUS, &compileResult);
|
|
if (compileResult == GL_FALSE)
|
|
{
|
|
glGetShaderInfoLog(newFragmentShader.get(), errorMessageSize, &errorBufferSize, errorMessage);
|
|
return false;
|
|
}
|
|
|
|
ScopedGlProgram newProgram(glCreateProgram());
|
|
glAttachShader(newProgram.get(), newVertexShader.get());
|
|
glAttachShader(newProgram.get(), newFragmentShader.get());
|
|
glLinkProgram(newProgram.get());
|
|
glGetProgramiv(newProgram.get(), GL_LINK_STATUS, &linkResult);
|
|
if (linkResult == GL_FALSE)
|
|
{
|
|
glGetProgramInfoLog(newProgram.get(), errorMessageSize, &errorBufferSize, errorMessage);
|
|
return false;
|
|
}
|
|
|
|
for (const ShaderTextureAsset& textureAsset : state.textureAssets)
|
|
{
|
|
LayerProgram::TextureBinding textureBinding;
|
|
textureBinding.samplerName = textureAsset.id;
|
|
textureBinding.sourcePath = textureAsset.path;
|
|
if (!mTextureBindings.LoadTextureAsset(textureAsset, textureBinding.texture, loadError))
|
|
{
|
|
for (LayerProgram::TextureBinding& loadedTexture : textureBindings)
|
|
{
|
|
if (loadedTexture.texture != 0)
|
|
glDeleteTextures(1, &loadedTexture.texture);
|
|
}
|
|
CopyErrorMessage(loadError, errorMessageSize, errorMessage);
|
|
return false;
|
|
}
|
|
textureBindings.push_back(textureBinding);
|
|
}
|
|
|
|
std::vector<LayerProgram::TextBinding> textBindings;
|
|
mTextureBindings.CreateTextBindings(state, textBindings);
|
|
|
|
layerProgram.layerId = state.layerId;
|
|
layerProgram.shaderId = state.shaderId;
|
|
layerProgram.shaderTextureBase = mTextureBindings.ResolveShaderTextureBase(state, mRuntimeHost.GetMaxTemporalHistoryFrames());
|
|
layerProgram.textureBindings.swap(textureBindings);
|
|
layerProgram.textBindings.swap(textBindings);
|
|
|
|
const GLuint globalParamsIndex = glGetUniformBlockIndex(newProgram.get(), "GlobalParams");
|
|
if (globalParamsIndex != GL_INVALID_INDEX)
|
|
glUniformBlockBinding(newProgram.get(), globalParamsIndex, kGlobalParamsBindingPoint);
|
|
|
|
const unsigned historyCap = mRuntimeHost.GetMaxTemporalHistoryFrames();
|
|
glUseProgram(newProgram.get());
|
|
mTextureBindings.AssignLayerSamplerUniforms(newProgram.get(), state, layerProgram, historyCap);
|
|
glUseProgram(0);
|
|
|
|
layerProgram.program = newProgram.release();
|
|
layerProgram.vertexShader = newVertexShader.release();
|
|
layerProgram.fragmentShader = newFragmentShader.release();
|
|
return true;
|
|
}
|
|
|
|
bool ShaderProgramCompiler::CompileDecodeShader(int errorMessageSize, char* errorMessage)
|
|
{
|
|
GLsizei errorBufferSize = 0;
|
|
GLint compileResult = GL_FALSE;
|
|
GLint linkResult = GL_FALSE;
|
|
const char* vertexSource = kFullscreenTriangleVertexShaderSource;
|
|
const char* fragmentSource = kDecodeFragmentShaderSource;
|
|
|
|
ScopedGlShader newVertexShader(glCreateShader(GL_VERTEX_SHADER));
|
|
glShaderSource(newVertexShader.get(), 1, (const GLchar**)&vertexSource, NULL);
|
|
glCompileShader(newVertexShader.get());
|
|
glGetShaderiv(newVertexShader.get(), GL_COMPILE_STATUS, &compileResult);
|
|
if (compileResult == GL_FALSE)
|
|
{
|
|
glGetShaderInfoLog(newVertexShader.get(), errorMessageSize, &errorBufferSize, errorMessage);
|
|
return false;
|
|
}
|
|
|
|
ScopedGlShader newFragmentShader(glCreateShader(GL_FRAGMENT_SHADER));
|
|
glShaderSource(newFragmentShader.get(), 1, (const GLchar**)&fragmentSource, NULL);
|
|
glCompileShader(newFragmentShader.get());
|
|
glGetShaderiv(newFragmentShader.get(), GL_COMPILE_STATUS, &compileResult);
|
|
if (compileResult == GL_FALSE)
|
|
{
|
|
glGetShaderInfoLog(newFragmentShader.get(), errorMessageSize, &errorBufferSize, errorMessage);
|
|
return false;
|
|
}
|
|
|
|
ScopedGlProgram newProgram(glCreateProgram());
|
|
glAttachShader(newProgram.get(), newVertexShader.get());
|
|
glAttachShader(newProgram.get(), newFragmentShader.get());
|
|
glLinkProgram(newProgram.get());
|
|
glGetProgramiv(newProgram.get(), GL_LINK_STATUS, &linkResult);
|
|
if (linkResult == GL_FALSE)
|
|
{
|
|
glGetProgramInfoLog(newProgram.get(), errorMessageSize, &errorBufferSize, errorMessage);
|
|
return false;
|
|
}
|
|
|
|
mRenderer.DestroyDecodeShaderProgram();
|
|
mRenderer.SetDecodeShaderProgram(newProgram.release(), newVertexShader.release(), newFragmentShader.release());
|
|
return true;
|
|
}
|
|
|
|
bool ShaderProgramCompiler::CompileOutputPackShader(int errorMessageSize, char* errorMessage)
|
|
{
|
|
GLsizei errorBufferSize = 0;
|
|
GLint compileResult = GL_FALSE;
|
|
GLint linkResult = GL_FALSE;
|
|
const char* vertexSource = kFullscreenTriangleVertexShaderSource;
|
|
const char* fragmentSource = kOutputPackFragmentShaderSource;
|
|
|
|
ScopedGlShader newVertexShader(glCreateShader(GL_VERTEX_SHADER));
|
|
glShaderSource(newVertexShader.get(), 1, (const GLchar**)&vertexSource, NULL);
|
|
glCompileShader(newVertexShader.get());
|
|
glGetShaderiv(newVertexShader.get(), GL_COMPILE_STATUS, &compileResult);
|
|
if (compileResult == GL_FALSE)
|
|
{
|
|
glGetShaderInfoLog(newVertexShader.get(), errorMessageSize, &errorBufferSize, errorMessage);
|
|
return false;
|
|
}
|
|
|
|
ScopedGlShader newFragmentShader(glCreateShader(GL_FRAGMENT_SHADER));
|
|
glShaderSource(newFragmentShader.get(), 1, (const GLchar**)&fragmentSource, NULL);
|
|
glCompileShader(newFragmentShader.get());
|
|
glGetShaderiv(newFragmentShader.get(), GL_COMPILE_STATUS, &compileResult);
|
|
if (compileResult == GL_FALSE)
|
|
{
|
|
glGetShaderInfoLog(newFragmentShader.get(), errorMessageSize, &errorBufferSize, errorMessage);
|
|
return false;
|
|
}
|
|
|
|
ScopedGlProgram newProgram(glCreateProgram());
|
|
glAttachShader(newProgram.get(), newVertexShader.get());
|
|
glAttachShader(newProgram.get(), newFragmentShader.get());
|
|
glLinkProgram(newProgram.get());
|
|
glGetProgramiv(newProgram.get(), GL_LINK_STATUS, &linkResult);
|
|
if (linkResult == GL_FALSE)
|
|
{
|
|
glGetProgramInfoLog(newProgram.get(), errorMessageSize, &errorBufferSize, errorMessage);
|
|
return false;
|
|
}
|
|
|
|
glUseProgram(newProgram.get());
|
|
const GLint outputSamplerLocation = glGetUniformLocation(newProgram.get(), "uOutputRgb");
|
|
if (outputSamplerLocation >= 0)
|
|
glUniform1i(outputSamplerLocation, 0);
|
|
glUseProgram(0);
|
|
|
|
mRenderer.DestroyOutputPackShaderProgram();
|
|
mRenderer.SetOutputPackShaderProgram(newProgram.release(), newVertexShader.release(), newFragmentShader.release());
|
|
return true;
|
|
}
|