245 lines
9.2 KiB
C++
245 lines
9.2 KiB
C++
#include "ShaderProgramCompiler.h"
|
|
|
|
#include "GlRenderConstants.h"
|
|
#include "GlScopedObjects.h"
|
|
#include "GlShaderSources.h"
|
|
|
|
#include <cstring>
|
|
#include <utility>
|
|
#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::vector<ShaderPassBuildSource> passSources;
|
|
std::string loadError;
|
|
|
|
if (!mRuntimeHost.BuildLayerPassFragmentShaderSources(state.layerId, passSources, loadError))
|
|
{
|
|
CopyErrorMessage(loadError, errorMessageSize, errorMessage);
|
|
return false;
|
|
}
|
|
|
|
return CompilePreparedLayerProgram(state, passSources, layerProgram, errorMessageSize, errorMessage);
|
|
}
|
|
|
|
bool ShaderProgramCompiler::CompilePreparedLayerProgram(const RuntimeRenderState& state, const std::string& fragmentShaderSource, LayerProgram& layerProgram, int errorMessageSize, char* errorMessage)
|
|
{
|
|
std::vector<ShaderPassBuildSource> passSources;
|
|
ShaderPassBuildSource passSource;
|
|
passSource.passId = "main";
|
|
passSource.fragmentShaderSource = fragmentShaderSource;
|
|
passSource.outputName = "layerOutput";
|
|
passSources.push_back(std::move(passSource));
|
|
return CompilePreparedLayerProgram(state, passSources, layerProgram, errorMessageSize, errorMessage);
|
|
}
|
|
|
|
bool ShaderProgramCompiler::CompilePreparedLayerProgram(const RuntimeRenderState& state, const std::vector<ShaderPassBuildSource>& passSources, LayerProgram& layerProgram, int errorMessageSize, char* errorMessage)
|
|
{
|
|
GLsizei errorBufferSize = 0;
|
|
std::string loadError;
|
|
const char* vertexSource = kFullscreenTriangleVertexShaderSource;
|
|
|
|
layerProgram.layerId = state.layerId;
|
|
layerProgram.shaderId = state.shaderId;
|
|
layerProgram.passes.clear();
|
|
|
|
for (const auto& passSource : passSources)
|
|
{
|
|
GLint compileResult = GL_FALSE;
|
|
GLint linkResult = GL_FALSE;
|
|
const char* fragmentSource = passSource.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);
|
|
mRenderer.DestroySingleLayerProgram(layerProgram);
|
|
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);
|
|
mRenderer.DestroySingleLayerProgram(layerProgram);
|
|
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);
|
|
mRenderer.DestroySingleLayerProgram(layerProgram);
|
|
return false;
|
|
}
|
|
|
|
std::vector<LayerProgram::TextureBinding> textureBindings;
|
|
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);
|
|
mRenderer.DestroySingleLayerProgram(layerProgram);
|
|
return false;
|
|
}
|
|
textureBindings.push_back(textureBinding);
|
|
}
|
|
|
|
std::vector<LayerProgram::TextBinding> textBindings;
|
|
mTextureBindings.CreateTextBindings(state, textBindings);
|
|
|
|
PassProgram passProgram;
|
|
passProgram.passId = passSource.passId;
|
|
passProgram.inputNames = passSource.inputNames;
|
|
passProgram.outputName = passSource.outputName;
|
|
passProgram.shaderTextureBase = mTextureBindings.ResolveShaderTextureBase(state, mRuntimeHost.GetMaxTemporalHistoryFrames());
|
|
passProgram.textureBindings.swap(textureBindings);
|
|
passProgram.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, passProgram, historyCap);
|
|
glUseProgram(0);
|
|
|
|
passProgram.program = newProgram.release();
|
|
passProgram.vertexShader = newVertexShader.release();
|
|
passProgram.fragmentShader = newFragmentShader.release();
|
|
layerProgram.passes.push_back(std::move(passProgram));
|
|
}
|
|
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;
|
|
}
|