215 lines
5.7 KiB
C++
215 lines
5.7 KiB
C++
#include "RuntimeShaderRenderer.h"
|
|
|
|
#include <array>
|
|
#include <cstring>
|
|
#include <string>
|
|
|
|
namespace
|
|
{
|
|
constexpr GLuint kGlobalParamsBindingPoint = 0;
|
|
|
|
const char* kVertexShaderSource = R"GLSL(
|
|
#version 430 core
|
|
out vec2 vTexCoord;
|
|
void main()
|
|
{
|
|
vec2 positions[3] = vec2[3](
|
|
vec2(-1.0, -1.0),
|
|
vec2( 3.0, -1.0),
|
|
vec2(-1.0, 3.0));
|
|
vec2 texCoords[3] = vec2[3](
|
|
vec2(0.0, 0.0),
|
|
vec2(2.0, 0.0),
|
|
vec2(0.0, 2.0));
|
|
gl_Position = vec4(positions[gl_VertexID], 0.0, 1.0);
|
|
vTexCoord = texCoords[gl_VertexID];
|
|
}
|
|
)GLSL";
|
|
|
|
struct GlobalParamsStd140
|
|
{
|
|
float time = 0.0f;
|
|
float pad0 = 0.0f;
|
|
float inputResolution[2] = {};
|
|
float outputResolution[2] = {};
|
|
float utcTimeSeconds = 0.0f;
|
|
float utcOffsetSeconds = 0.0f;
|
|
float startupRandom = 0.37f;
|
|
float frameCount = 0.0f;
|
|
float mixAmount = 1.0f;
|
|
float bypass = 0.0f;
|
|
int sourceHistoryLength = 0;
|
|
int temporalHistoryLength = 0;
|
|
int feedbackAvailable = 0;
|
|
float speed = 1.0f;
|
|
float scale = 1.0f;
|
|
float raySteps = 77.0f;
|
|
float intensity = 1.0f;
|
|
float sourceMix = 0.0f;
|
|
float pad1[3] = {};
|
|
};
|
|
}
|
|
|
|
RuntimeShaderRenderer::~RuntimeShaderRenderer()
|
|
{
|
|
ShutdownGl();
|
|
}
|
|
|
|
bool RuntimeShaderRenderer::CommitFragmentShader(const std::string& fragmentShaderSource, std::string& error)
|
|
{
|
|
if (fragmentShaderSource.empty())
|
|
{
|
|
error = "Cannot commit an empty fragment shader.";
|
|
return false;
|
|
}
|
|
|
|
if (!EnsureStaticGlResources(error))
|
|
return false;
|
|
|
|
GLuint vertexShader = 0;
|
|
GLuint fragmentShader = 0;
|
|
GLuint program = 0;
|
|
if (!CompileShader(GL_VERTEX_SHADER, kVertexShaderSource, vertexShader, error))
|
|
return false;
|
|
if (!CompileShader(GL_FRAGMENT_SHADER, fragmentShaderSource.c_str(), fragmentShader, error))
|
|
{
|
|
glDeleteShader(vertexShader);
|
|
return false;
|
|
}
|
|
|
|
program = glCreateProgram();
|
|
glAttachShader(program, vertexShader);
|
|
glAttachShader(program, fragmentShader);
|
|
glLinkProgram(program);
|
|
|
|
GLint linkResult = GL_FALSE;
|
|
glGetProgramiv(program, GL_LINK_STATUS, &linkResult);
|
|
if (linkResult == GL_FALSE)
|
|
{
|
|
std::array<char, 4096> log = {};
|
|
GLsizei length = 0;
|
|
glGetProgramInfoLog(program, static_cast<GLsizei>(log.size()), &length, log.data());
|
|
error = std::string(log.data(), static_cast<std::size_t>(length));
|
|
glDeleteProgram(program);
|
|
glDeleteShader(vertexShader);
|
|
glDeleteShader(fragmentShader);
|
|
return false;
|
|
}
|
|
|
|
const GLuint globalParamsIndex = glGetUniformBlockIndex(program, "GlobalParams");
|
|
if (globalParamsIndex != GL_INVALID_INDEX)
|
|
glUniformBlockBinding(program, globalParamsIndex, kGlobalParamsBindingPoint);
|
|
|
|
glUseProgram(program);
|
|
const GLint videoInputLocation = glGetUniformLocation(program, "gVideoInput");
|
|
if (videoInputLocation >= 0)
|
|
glUniform1i(videoInputLocation, 0);
|
|
const GLint layerInputLocation = glGetUniformLocation(program, "gLayerInput");
|
|
if (layerInputLocation >= 0)
|
|
glUniform1i(layerInputLocation, 0);
|
|
glUseProgram(0);
|
|
|
|
DestroyProgram();
|
|
mProgram = program;
|
|
mVertexShader = vertexShader;
|
|
mFragmentShader = fragmentShader;
|
|
return true;
|
|
}
|
|
|
|
void RuntimeShaderRenderer::RenderFrame(uint64_t frameIndex, unsigned width, unsigned height)
|
|
{
|
|
if (mProgram == 0)
|
|
return;
|
|
|
|
GlobalParamsStd140 params;
|
|
params.time = static_cast<float>(frameIndex) / 60.0f;
|
|
params.inputResolution[0] = static_cast<float>(width);
|
|
params.inputResolution[1] = static_cast<float>(height);
|
|
params.outputResolution[0] = static_cast<float>(width);
|
|
params.outputResolution[1] = static_cast<float>(height);
|
|
params.frameCount = static_cast<float>(frameIndex);
|
|
|
|
glViewport(0, 0, static_cast<GLsizei>(width), static_cast<GLsizei>(height));
|
|
glDisable(GL_SCISSOR_TEST);
|
|
glDisable(GL_DEPTH_TEST);
|
|
glDisable(GL_BLEND);
|
|
glBindBuffer(GL_UNIFORM_BUFFER, mGlobalParamsBuffer);
|
|
glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(params), ¶ms);
|
|
glBindBufferBase(GL_UNIFORM_BUFFER, kGlobalParamsBindingPoint, mGlobalParamsBuffer);
|
|
glBindBuffer(GL_UNIFORM_BUFFER, 0);
|
|
glBindVertexArray(mVertexArray);
|
|
glUseProgram(mProgram);
|
|
glDrawArrays(GL_TRIANGLES, 0, 3);
|
|
glUseProgram(0);
|
|
glBindVertexArray(0);
|
|
}
|
|
|
|
void RuntimeShaderRenderer::ShutdownGl()
|
|
{
|
|
DestroyProgram();
|
|
DestroyStaticGlResources();
|
|
}
|
|
|
|
bool RuntimeShaderRenderer::EnsureStaticGlResources(std::string& error)
|
|
{
|
|
if (mVertexArray == 0)
|
|
glGenVertexArrays(1, &mVertexArray);
|
|
if (mGlobalParamsBuffer == 0)
|
|
{
|
|
glGenBuffers(1, &mGlobalParamsBuffer);
|
|
glBindBuffer(GL_UNIFORM_BUFFER, mGlobalParamsBuffer);
|
|
glBufferData(GL_UNIFORM_BUFFER, static_cast<GLsizeiptr>(sizeof(GlobalParamsStd140)), nullptr, GL_DYNAMIC_DRAW);
|
|
glBindBuffer(GL_UNIFORM_BUFFER, 0);
|
|
}
|
|
|
|
if (mVertexArray == 0 || mGlobalParamsBuffer == 0)
|
|
{
|
|
error = "Failed to create runtime shader GL resources.";
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool RuntimeShaderRenderer::CompileShader(GLenum shaderType, const char* source, GLuint& shader, std::string& error) const
|
|
{
|
|
shader = glCreateShader(shaderType);
|
|
glShaderSource(shader, 1, &source, nullptr);
|
|
glCompileShader(shader);
|
|
|
|
GLint compileResult = GL_FALSE;
|
|
glGetShaderiv(shader, GL_COMPILE_STATUS, &compileResult);
|
|
if (compileResult != GL_FALSE)
|
|
return true;
|
|
|
|
std::array<char, 4096> log = {};
|
|
GLsizei length = 0;
|
|
glGetShaderInfoLog(shader, static_cast<GLsizei>(log.size()), &length, log.data());
|
|
error = std::string(log.data(), static_cast<std::size_t>(length));
|
|
glDeleteShader(shader);
|
|
shader = 0;
|
|
return false;
|
|
}
|
|
|
|
void RuntimeShaderRenderer::DestroyProgram()
|
|
{
|
|
if (mProgram != 0)
|
|
glDeleteProgram(mProgram);
|
|
if (mVertexShader != 0)
|
|
glDeleteShader(mVertexShader);
|
|
if (mFragmentShader != 0)
|
|
glDeleteShader(mFragmentShader);
|
|
mProgram = 0;
|
|
mVertexShader = 0;
|
|
mFragmentShader = 0;
|
|
}
|
|
|
|
void RuntimeShaderRenderer::DestroyStaticGlResources()
|
|
{
|
|
if (mGlobalParamsBuffer != 0)
|
|
glDeleteBuffers(1, &mGlobalParamsBuffer);
|
|
if (mVertexArray != 0)
|
|
glDeleteVertexArrays(1, &mVertexArray);
|
|
mGlobalParamsBuffer = 0;
|
|
mVertexArray = 0;
|
|
}
|