205 lines
6.9 KiB
C++
205 lines
6.9 KiB
C++
#include "OpenGLShaderPrograms.h"
|
|
|
|
#include <cstring>
|
|
#include <string>
|
|
#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);
|
|
}
|
|
|
|
std::size_t RequiredTemporaryRenderTargets(const std::vector<OpenGLRenderer::LayerProgram>& layerPrograms)
|
|
{
|
|
// Only one layer renders at a time, so the pool needs to cover the widest
|
|
// layer, not the sum of every intermediate pass in the stack.
|
|
std::size_t requiredTargets = 0;
|
|
for (const OpenGLRenderer::LayerProgram& layerProgram : layerPrograms)
|
|
{
|
|
const std::size_t internalPasses = layerProgram.passes.size() > 0 ? layerProgram.passes.size() - 1 : 0;
|
|
if (internalPasses > requiredTargets)
|
|
requiredTargets = internalPasses;
|
|
}
|
|
return requiredTargets;
|
|
}
|
|
}
|
|
|
|
OpenGLShaderPrograms::OpenGLShaderPrograms(OpenGLRenderer& renderer, RuntimeHost& runtimeHost) :
|
|
mRenderer(renderer),
|
|
mRuntimeHost(runtimeHost),
|
|
mGlobalParamsBuffer(renderer),
|
|
mCompiler(renderer, runtimeHost, mTextureBindings)
|
|
{
|
|
}
|
|
|
|
bool OpenGLShaderPrograms::CompileLayerPrograms(unsigned inputFrameWidth, unsigned inputFrameHeight, int errorMessageSize, char* errorMessage)
|
|
{
|
|
const std::vector<RuntimeRenderState> layerStates = mRuntimeHost.GetLayerRenderStates(inputFrameWidth, inputFrameHeight);
|
|
std::string temporalError;
|
|
const unsigned historyCap = mRuntimeHost.GetMaxTemporalHistoryFrames();
|
|
if (!mRenderer.TemporalHistory().ValidateTextureUnitBudget(layerStates, historyCap, temporalError))
|
|
{
|
|
CopyErrorMessage(temporalError, errorMessageSize, errorMessage);
|
|
return false;
|
|
}
|
|
if (!mRenderer.TemporalHistory().EnsureResources(layerStates, historyCap, inputFrameWidth, inputFrameHeight, temporalError))
|
|
{
|
|
CopyErrorMessage(temporalError, errorMessageSize, errorMessage);
|
|
return false;
|
|
}
|
|
if (mRenderer.ResourcesInitialized() &&
|
|
!mRenderer.FeedbackBuffers().EnsureResources(layerStates, inputFrameWidth, inputFrameHeight, temporalError))
|
|
{
|
|
CopyErrorMessage(temporalError, errorMessageSize, errorMessage);
|
|
return false;
|
|
}
|
|
|
|
// Initial startup still compiles synchronously; auto-reload uses the build
|
|
// queue so Slang/file work stays off the playback path.
|
|
std::vector<LayerProgram> newPrograms;
|
|
newPrograms.reserve(layerStates.size());
|
|
|
|
for (const RuntimeRenderState& state : layerStates)
|
|
{
|
|
LayerProgram layerProgram;
|
|
if (!mCompiler.CompileLayerProgram(state, layerProgram, errorMessageSize, errorMessage))
|
|
{
|
|
for (LayerProgram& program : newPrograms)
|
|
DestroySingleLayerProgram(program);
|
|
return false;
|
|
}
|
|
newPrograms.push_back(layerProgram);
|
|
}
|
|
|
|
std::string targetError;
|
|
if (!mRenderer.ReserveTemporaryRenderTargets(RequiredTemporaryRenderTargets(newPrograms), inputFrameWidth, inputFrameHeight, targetError))
|
|
{
|
|
for (LayerProgram& program : newPrograms)
|
|
DestroySingleLayerProgram(program);
|
|
CopyErrorMessage(targetError, errorMessageSize, errorMessage);
|
|
return false;
|
|
}
|
|
|
|
DestroyLayerPrograms();
|
|
mRenderer.ReplaceLayerPrograms(newPrograms);
|
|
mCommittedLayerStates = layerStates;
|
|
|
|
mRuntimeHost.SetCompileStatus(true, "Shader layers compiled successfully.");
|
|
mRuntimeHost.ClearReloadRequest();
|
|
|
|
return true;
|
|
}
|
|
|
|
bool OpenGLShaderPrograms::CommitPreparedLayerPrograms(const PreparedShaderBuild& preparedBuild, unsigned inputFrameWidth, unsigned inputFrameHeight, int errorMessageSize, char* errorMessage)
|
|
{
|
|
if (!preparedBuild.succeeded)
|
|
{
|
|
CopyErrorMessage(preparedBuild.message, errorMessageSize, errorMessage);
|
|
return false;
|
|
}
|
|
|
|
std::string temporalError;
|
|
const unsigned historyCap = mRuntimeHost.GetMaxTemporalHistoryFrames();
|
|
if (!mRenderer.TemporalHistory().ValidateTextureUnitBudget(preparedBuild.layerStates, historyCap, temporalError))
|
|
{
|
|
CopyErrorMessage(temporalError, errorMessageSize, errorMessage);
|
|
return false;
|
|
}
|
|
if (!mRenderer.TemporalHistory().EnsureResources(preparedBuild.layerStates, historyCap, inputFrameWidth, inputFrameHeight, temporalError))
|
|
{
|
|
CopyErrorMessage(temporalError, errorMessageSize, errorMessage);
|
|
return false;
|
|
}
|
|
if (mRenderer.ResourcesInitialized() &&
|
|
!mRenderer.FeedbackBuffers().EnsureResources(preparedBuild.layerStates, inputFrameWidth, inputFrameHeight, temporalError))
|
|
{
|
|
CopyErrorMessage(temporalError, errorMessageSize, errorMessage);
|
|
return false;
|
|
}
|
|
|
|
// The prepared build already contains GLSL text for each pass. This commit
|
|
// step performs the short GL work on the render thread.
|
|
std::vector<LayerProgram> newPrograms;
|
|
newPrograms.reserve(preparedBuild.layers.size());
|
|
|
|
for (const PreparedLayerShader& preparedLayer : preparedBuild.layers)
|
|
{
|
|
LayerProgram layerProgram;
|
|
if (!mCompiler.CompilePreparedLayerProgram(preparedLayer.state, preparedLayer.passes, layerProgram, errorMessageSize, errorMessage))
|
|
{
|
|
for (LayerProgram& program : newPrograms)
|
|
DestroySingleLayerProgram(program);
|
|
return false;
|
|
}
|
|
newPrograms.push_back(layerProgram);
|
|
}
|
|
|
|
std::string targetError;
|
|
if (!mRenderer.ReserveTemporaryRenderTargets(RequiredTemporaryRenderTargets(newPrograms), inputFrameWidth, inputFrameHeight, targetError))
|
|
{
|
|
for (LayerProgram& program : newPrograms)
|
|
DestroySingleLayerProgram(program);
|
|
CopyErrorMessage(targetError, errorMessageSize, errorMessage);
|
|
return false;
|
|
}
|
|
|
|
DestroyLayerPrograms();
|
|
mRenderer.ReplaceLayerPrograms(newPrograms);
|
|
mCommittedLayerStates = preparedBuild.layerStates;
|
|
|
|
mRuntimeHost.SetCompileStatus(true, "Shader layers compiled successfully.");
|
|
mRuntimeHost.ClearReloadRequest();
|
|
|
|
return true;
|
|
}
|
|
|
|
bool OpenGLShaderPrograms::CompileDecodeShader(int errorMessageSize, char* errorMessage)
|
|
{
|
|
return mCompiler.CompileDecodeShader(errorMessageSize, errorMessage);
|
|
}
|
|
|
|
bool OpenGLShaderPrograms::CompileOutputPackShader(int errorMessageSize, char* errorMessage)
|
|
{
|
|
return mCompiler.CompileOutputPackShader(errorMessageSize, errorMessage);
|
|
}
|
|
|
|
void OpenGLShaderPrograms::DestroySingleLayerProgram(LayerProgram& layerProgram)
|
|
{
|
|
mRenderer.DestroySingleLayerProgram(layerProgram);
|
|
}
|
|
|
|
void OpenGLShaderPrograms::DestroyLayerPrograms()
|
|
{
|
|
mRenderer.DestroyLayerPrograms();
|
|
}
|
|
|
|
void OpenGLShaderPrograms::DestroyDecodeShaderProgram()
|
|
{
|
|
mRenderer.DestroyDecodeShaderProgram();
|
|
}
|
|
|
|
void OpenGLShaderPrograms::ResetTemporalHistoryState()
|
|
{
|
|
mRenderer.TemporalHistory().ResetState();
|
|
}
|
|
|
|
void OpenGLShaderPrograms::ResetShaderFeedbackState()
|
|
{
|
|
mRenderer.FeedbackBuffers().ResetState();
|
|
}
|
|
|
|
bool OpenGLShaderPrograms::UpdateTextBindingTexture(const RuntimeRenderState& state, LayerProgram::TextBinding& textBinding, std::string& error)
|
|
{
|
|
return mTextureBindings.UpdateTextBindingTexture(state, textBinding, error);
|
|
}
|
|
|
|
bool OpenGLShaderPrograms::UpdateGlobalParamsBuffer(const RuntimeRenderState& state, unsigned availableSourceHistoryLength, unsigned availableTemporalHistoryLength, bool feedbackAvailable)
|
|
{
|
|
return mGlobalParamsBuffer.Update(state, availableSourceHistoryLength, availableTemporalHistoryLength, feedbackAvailable);
|
|
}
|