Multi pass
This commit is contained in:
@@ -2,6 +2,8 @@
|
||||
|
||||
#include "GlRenderConstants.h"
|
||||
|
||||
#include <map>
|
||||
|
||||
OpenGLRenderPass::OpenGLRenderPass(OpenGLRenderer& renderer) :
|
||||
mRenderer(renderer)
|
||||
{
|
||||
@@ -93,7 +95,10 @@ std::vector<RenderPassDescriptor> OpenGLRenderPass::BuildLayerPassDescriptors(
|
||||
{
|
||||
std::vector<RenderPassDescriptor> passes;
|
||||
const std::size_t passCount = layerStates.size() < layerPrograms.size() ? layerStates.size() : layerPrograms.size();
|
||||
passes.reserve(passCount);
|
||||
std::size_t descriptorCount = 0;
|
||||
for (std::size_t index = 0; index < passCount; ++index)
|
||||
descriptorCount += layerPrograms[index].passes.size();
|
||||
passes.reserve(descriptorCount);
|
||||
|
||||
GLuint sourceTexture = mRenderer.DecodedTexture();
|
||||
GLuint sourceFramebuffer = mRenderer.DecodeFramebuffer();
|
||||
@@ -105,25 +110,90 @@ std::vector<RenderPassDescriptor> OpenGLRenderPass::BuildLayerPassDescriptors(
|
||||
continue;
|
||||
const std::size_t remaining = layerStates.size() - index;
|
||||
const bool writeToMain = (remaining % 2) == 1;
|
||||
const GLuint layerOutputTexture = writeToMain ? mRenderer.CompositeTexture() : mRenderer.LayerTempTexture();
|
||||
const GLuint layerOutputFramebuffer = writeToMain ? mRenderer.CompositeFramebuffer() : mRenderer.LayerTempFramebuffer();
|
||||
const RenderPassOutputTarget layerOutputTarget = writeToMain ? RenderPassOutputTarget::Composite : RenderPassOutputTarget::LayerTemp;
|
||||
|
||||
RenderPassDescriptor pass;
|
||||
pass.kind = RenderPassKind::LayerEffect;
|
||||
pass.outputTarget = writeToMain ? RenderPassOutputTarget::Composite : RenderPassOutputTarget::LayerTemp;
|
||||
pass.passIndex = index;
|
||||
pass.passId = state.layerId;
|
||||
pass.layerId = state.layerId;
|
||||
pass.shaderId = state.shaderId;
|
||||
pass.sourceTexture = sourceTexture;
|
||||
pass.sourceFramebuffer = sourceFramebuffer;
|
||||
pass.destinationFramebuffer = writeToMain ? mRenderer.CompositeFramebuffer() : mRenderer.LayerTempFramebuffer();
|
||||
pass.layerProgram = &layerProgram;
|
||||
pass.passProgram = &layerProgram.passes.front();
|
||||
pass.layerState = &state;
|
||||
pass.capturePreLayerHistory = state.temporalHistorySource == TemporalHistorySource::PreLayerInput;
|
||||
passes.push_back(pass);
|
||||
const GLuint layerInputTexture = sourceTexture;
|
||||
const GLuint layerInputFramebuffer = sourceFramebuffer;
|
||||
GLuint previousPassTexture = layerInputTexture;
|
||||
GLuint previousPassFramebuffer = layerInputFramebuffer;
|
||||
std::map<std::string, std::pair<GLuint, GLuint>> namedOutputs;
|
||||
std::size_t temporaryTargetIndex = 0;
|
||||
|
||||
sourceTexture = writeToMain ? mRenderer.CompositeTexture() : mRenderer.LayerTempTexture();
|
||||
sourceFramebuffer = writeToMain ? mRenderer.CompositeFramebuffer() : mRenderer.LayerTempFramebuffer();
|
||||
for (std::size_t passIndex = 0; passIndex < layerProgram.passes.size(); ++passIndex)
|
||||
{
|
||||
PassProgram& passProgram = layerProgram.passes[passIndex];
|
||||
const bool lastPassForLayer = passIndex + 1 == layerProgram.passes.size();
|
||||
const std::string outputName = passProgram.outputName.empty() ? passProgram.passId : passProgram.outputName;
|
||||
const bool writesLayerOutput = outputName == "layerOutput" || lastPassForLayer;
|
||||
|
||||
GLuint passSourceTexture = previousPassTexture;
|
||||
GLuint passSourceFramebuffer = previousPassFramebuffer;
|
||||
if (!passProgram.inputNames.empty())
|
||||
{
|
||||
const std::string& inputName = passProgram.inputNames.front();
|
||||
if (inputName == "layerInput")
|
||||
{
|
||||
passSourceTexture = layerInputTexture;
|
||||
passSourceFramebuffer = layerInputFramebuffer;
|
||||
}
|
||||
else if (inputName == "previousPass")
|
||||
{
|
||||
passSourceTexture = previousPassTexture;
|
||||
passSourceFramebuffer = previousPassFramebuffer;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto namedOutputIt = namedOutputs.find(inputName);
|
||||
if (namedOutputIt != namedOutputs.end())
|
||||
{
|
||||
passSourceTexture = namedOutputIt->second.first;
|
||||
passSourceFramebuffer = namedOutputIt->second.second;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GLuint passDestinationTexture = layerOutputTexture;
|
||||
GLuint passDestinationFramebuffer = layerOutputFramebuffer;
|
||||
RenderPassOutputTarget outputTarget = layerOutputTarget;
|
||||
if (!writesLayerOutput)
|
||||
{
|
||||
if (temporaryTargetIndex < mRenderer.TemporaryRenderTargetCount())
|
||||
{
|
||||
const RenderTarget& temporaryTarget = mRenderer.TemporaryRenderTarget(temporaryTargetIndex);
|
||||
++temporaryTargetIndex;
|
||||
passDestinationTexture = temporaryTarget.texture;
|
||||
passDestinationFramebuffer = temporaryTarget.framebuffer;
|
||||
outputTarget = RenderPassOutputTarget::Temporary;
|
||||
}
|
||||
}
|
||||
|
||||
RenderPassDescriptor pass;
|
||||
pass.kind = RenderPassKind::LayerEffect;
|
||||
pass.outputTarget = outputTarget;
|
||||
pass.passIndex = passes.size();
|
||||
pass.passId = passProgram.passId;
|
||||
pass.layerId = state.layerId;
|
||||
pass.shaderId = state.shaderId;
|
||||
pass.sourceTexture = passSourceTexture;
|
||||
pass.sourceFramebuffer = passIndex == 0 ? layerInputFramebuffer : passSourceFramebuffer;
|
||||
pass.destinationTexture = passDestinationTexture;
|
||||
pass.destinationFramebuffer = passDestinationFramebuffer;
|
||||
pass.layerProgram = &layerProgram;
|
||||
pass.passProgram = &passProgram;
|
||||
pass.layerState = &state;
|
||||
pass.capturePreLayerHistory = passIndex == 0 && state.temporalHistorySource == TemporalHistorySource::PreLayerInput;
|
||||
passes.push_back(pass);
|
||||
|
||||
namedOutputs[outputName] = std::make_pair(passDestinationTexture, passDestinationFramebuffer);
|
||||
namedOutputs[passProgram.passId] = std::make_pair(passDestinationTexture, passDestinationFramebuffer);
|
||||
previousPassTexture = passDestinationTexture;
|
||||
previousPassFramebuffer = passDestinationFramebuffer;
|
||||
}
|
||||
|
||||
sourceTexture = layerOutputTexture;
|
||||
sourceFramebuffer = layerOutputFramebuffer;
|
||||
}
|
||||
|
||||
return passes;
|
||||
|
||||
@@ -15,6 +15,7 @@ enum class RenderPassKind
|
||||
|
||||
enum class RenderPassOutputTarget
|
||||
{
|
||||
Temporary,
|
||||
LayerTemp,
|
||||
Composite
|
||||
};
|
||||
@@ -29,6 +30,7 @@ struct RenderPassDescriptor
|
||||
std::string shaderId;
|
||||
GLuint sourceTexture = 0;
|
||||
GLuint sourceFramebuffer = 0;
|
||||
GLuint destinationTexture = 0;
|
||||
GLuint destinationFramebuffer = 0;
|
||||
OpenGLRenderer::LayerProgram* layerProgram = nullptr;
|
||||
OpenGLRenderer::LayerProgram::PassProgram* passProgram = nullptr;
|
||||
|
||||
@@ -80,6 +80,11 @@ void OpenGLRenderer::SetOutputPackShaderProgram(GLuint program, GLuint vertexSha
|
||||
mOutputPackFragmentShader = fragmentShader;
|
||||
}
|
||||
|
||||
bool OpenGLRenderer::ReserveTemporaryRenderTargets(std::size_t count, unsigned width, unsigned height, std::string& error)
|
||||
{
|
||||
return mRenderTargets.ReserveTemporaryTargets(count, width, height, GL_RGBA16F, GL_RGBA, GL_FLOAT, error);
|
||||
}
|
||||
|
||||
void OpenGLRenderer::ResizeView(int width, int height)
|
||||
{
|
||||
mViewWidth = width;
|
||||
|
||||
@@ -41,6 +41,8 @@ public:
|
||||
struct PassProgram
|
||||
{
|
||||
std::string passId;
|
||||
std::vector<std::string> inputNames;
|
||||
std::string outputName;
|
||||
GLuint shaderTextureBase = 0;
|
||||
GLuint program = 0;
|
||||
GLuint vertexShader = 0;
|
||||
@@ -73,6 +75,9 @@ public:
|
||||
void ReplaceLayerPrograms(std::vector<LayerProgram>& newPrograms) { mLayerPrograms.swap(newPrograms); }
|
||||
std::vector<LayerProgram>& LayerPrograms() { return mLayerPrograms; }
|
||||
const std::vector<LayerProgram>& LayerPrograms() const { return mLayerPrograms; }
|
||||
bool ReserveTemporaryRenderTargets(std::size_t count, unsigned width, unsigned height, std::string& error);
|
||||
const RenderTarget& TemporaryRenderTarget(std::size_t index) const { return mRenderTargets.TemporaryTarget(index); }
|
||||
std::size_t TemporaryRenderTargetCount() const { return mRenderTargets.TemporaryTargetCount(); }
|
||||
TemporalHistoryBuffers& TemporalHistory() { return mTemporalHistory; }
|
||||
const TemporalHistoryBuffers& TemporalHistory() const { return mTemporalHistory; }
|
||||
void SetDecodeShaderProgram(GLuint program, GLuint vertexShader, GLuint fragmentShader);
|
||||
|
||||
@@ -69,11 +69,10 @@ bool RenderTargetPool::ReserveTemporaryTargets(
|
||||
GLenum pixelType,
|
||||
std::string& error)
|
||||
{
|
||||
if (!mTemporaryTargets.empty())
|
||||
{
|
||||
error = "Temporary render targets were already initialized.";
|
||||
return false;
|
||||
}
|
||||
if (mTemporaryTargets.size() == count)
|
||||
return true;
|
||||
|
||||
DestroyTemporaryTargets();
|
||||
|
||||
mTemporaryTargets.resize(count);
|
||||
for (std::size_t index = 0; index < mTemporaryTargets.size(); ++index)
|
||||
@@ -105,6 +104,18 @@ bool RenderTargetPool::ReserveTemporaryTargets(
|
||||
return true;
|
||||
}
|
||||
|
||||
void RenderTargetPool::DestroyTemporaryTargets()
|
||||
{
|
||||
for (RenderTarget& target : mTemporaryTargets)
|
||||
{
|
||||
if (target.framebuffer != 0)
|
||||
glDeleteFramebuffers(1, &target.framebuffer);
|
||||
if (target.texture != 0)
|
||||
glDeleteTextures(1, &target.texture);
|
||||
}
|
||||
mTemporaryTargets.clear();
|
||||
}
|
||||
|
||||
void RenderTargetPool::Destroy()
|
||||
{
|
||||
for (RenderTarget& target : mTargets)
|
||||
@@ -116,14 +127,7 @@ void RenderTargetPool::Destroy()
|
||||
target = RenderTarget();
|
||||
}
|
||||
|
||||
for (RenderTarget& target : mTemporaryTargets)
|
||||
{
|
||||
if (target.framebuffer != 0)
|
||||
glDeleteFramebuffers(1, &target.framebuffer);
|
||||
if (target.texture != 0)
|
||||
glDeleteTextures(1, &target.texture);
|
||||
}
|
||||
mTemporaryTargets.clear();
|
||||
DestroyTemporaryTargets();
|
||||
}
|
||||
|
||||
const RenderTarget& RenderTargetPool::Target(RenderTargetId id) const
|
||||
|
||||
@@ -47,6 +47,7 @@ public:
|
||||
GLenum pixelFormat,
|
||||
GLenum pixelType,
|
||||
std::string& error);
|
||||
void DestroyTemporaryTargets();
|
||||
void Destroy();
|
||||
|
||||
GLuint Texture(RenderTargetId id) const { return Target(id).texture; }
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace
|
||||
@@ -14,6 +13,18 @@ void CopyErrorMessage(const std::string& message, int errorMessageSize, char* er
|
||||
|
||||
strncpy_s(errorMessage, errorMessageSize, message.c_str(), _TRUNCATE);
|
||||
}
|
||||
|
||||
std::size_t RequiredTemporaryRenderTargets(const std::vector<OpenGLRenderer::LayerProgram>& layerPrograms)
|
||||
{
|
||||
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) :
|
||||
@@ -55,6 +66,15 @@ bool OpenGLShaderPrograms::CompileLayerPrograms(unsigned inputFrameWidth, unsign
|
||||
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;
|
||||
@@ -92,11 +112,7 @@ bool OpenGLShaderPrograms::CommitPreparedLayerPrograms(const PreparedShaderBuild
|
||||
for (const PreparedLayerShader& preparedLayer : preparedBuild.layers)
|
||||
{
|
||||
LayerProgram layerProgram;
|
||||
std::vector<std::pair<std::string, std::string>> passSources;
|
||||
passSources.reserve(preparedLayer.passes.size());
|
||||
for (const PreparedLayerShader::Pass& pass : preparedLayer.passes)
|
||||
passSources.push_back(std::make_pair(pass.passId, pass.fragmentShaderSource));
|
||||
if (!mCompiler.CompilePreparedLayerProgram(preparedLayer.state, passSources, layerProgram, errorMessageSize, errorMessage))
|
||||
if (!mCompiler.CompilePreparedLayerProgram(preparedLayer.state, preparedLayer.passes, layerProgram, errorMessageSize, errorMessage))
|
||||
{
|
||||
for (LayerProgram& program : newPrograms)
|
||||
DestroySingleLayerProgram(program);
|
||||
@@ -105,6 +121,15 @@ bool OpenGLShaderPrograms::CommitPreparedLayerPrograms(const PreparedShaderBuild
|
||||
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;
|
||||
|
||||
@@ -120,15 +120,11 @@ PreparedShaderBuild ShaderBuildQueue::Build(uint64_t generation, unsigned output
|
||||
{
|
||||
PreparedLayerShader layer;
|
||||
layer.state = state;
|
||||
std::vector<std::pair<std::string, std::string>> passSources;
|
||||
if (!mRuntimeHost.BuildLayerPassFragmentShaderSources(state.layerId, passSources, build.message))
|
||||
if (!mRuntimeHost.BuildLayerPassFragmentShaderSources(state.layerId, layer.passes, build.message))
|
||||
{
|
||||
build.succeeded = false;
|
||||
return build;
|
||||
}
|
||||
layer.passes.reserve(passSources.size());
|
||||
for (auto& passSource : passSources)
|
||||
layer.passes.push_back({ std::move(passSource.first), std::move(passSource.second) });
|
||||
build.layers.push_back(std::move(layer));
|
||||
}
|
||||
|
||||
|
||||
@@ -13,14 +13,8 @@ class RuntimeHost;
|
||||
|
||||
struct PreparedLayerShader
|
||||
{
|
||||
struct Pass
|
||||
{
|
||||
std::string passId;
|
||||
std::string fragmentShaderSource;
|
||||
};
|
||||
|
||||
RuntimeRenderState state;
|
||||
std::vector<Pass> passes;
|
||||
std::vector<ShaderPassBuildSource> passes;
|
||||
};
|
||||
|
||||
struct PreparedShaderBuild
|
||||
|
||||
@@ -28,7 +28,7 @@ ShaderProgramCompiler::ShaderProgramCompiler(OpenGLRenderer& renderer, RuntimeHo
|
||||
|
||||
bool ShaderProgramCompiler::CompileLayerProgram(const RuntimeRenderState& state, LayerProgram& layerProgram, int errorMessageSize, char* errorMessage)
|
||||
{
|
||||
std::vector<std::pair<std::string, std::string>> passSources;
|
||||
std::vector<ShaderPassBuildSource> passSources;
|
||||
std::string loadError;
|
||||
|
||||
if (!mRuntimeHost.BuildLayerPassFragmentShaderSources(state.layerId, passSources, loadError))
|
||||
@@ -42,12 +42,16 @@ bool ShaderProgramCompiler::CompileLayerProgram(const RuntimeRenderState& state,
|
||||
|
||||
bool ShaderProgramCompiler::CompilePreparedLayerProgram(const RuntimeRenderState& state, const std::string& fragmentShaderSource, LayerProgram& layerProgram, int errorMessageSize, char* errorMessage)
|
||||
{
|
||||
std::vector<std::pair<std::string, std::string>> passSources;
|
||||
passSources.push_back(std::make_pair(std::string("main"), fragmentShaderSource));
|
||||
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<std::pair<std::string, std::string>>& passSources, LayerProgram& layerProgram, int errorMessageSize, char* errorMessage)
|
||||
bool ShaderProgramCompiler::CompilePreparedLayerProgram(const RuntimeRenderState& state, const std::vector<ShaderPassBuildSource>& passSources, LayerProgram& layerProgram, int errorMessageSize, char* errorMessage)
|
||||
{
|
||||
GLsizei errorBufferSize = 0;
|
||||
std::string loadError;
|
||||
@@ -61,7 +65,7 @@ bool ShaderProgramCompiler::CompilePreparedLayerProgram(const RuntimeRenderState
|
||||
{
|
||||
GLint compileResult = GL_FALSE;
|
||||
GLint linkResult = GL_FALSE;
|
||||
const char* fragmentSource = passSource.second.c_str();
|
||||
const char* fragmentSource = passSource.fragmentShaderSource.c_str();
|
||||
|
||||
ScopedGlShader newVertexShader(glCreateShader(GL_VERTEX_SHADER));
|
||||
glShaderSource(newVertexShader.get(), 1, (const GLchar**)&vertexSource, NULL);
|
||||
@@ -121,7 +125,9 @@ bool ShaderProgramCompiler::CompilePreparedLayerProgram(const RuntimeRenderState
|
||||
mTextureBindings.CreateTextBindings(state, textBindings);
|
||||
|
||||
PassProgram passProgram;
|
||||
passProgram.passId = passSource.first;
|
||||
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);
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
#include "ShaderTextureBindings.h"
|
||||
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
class ShaderProgramCompiler
|
||||
@@ -18,7 +17,7 @@ public:
|
||||
|
||||
bool CompileLayerProgram(const RuntimeRenderState& state, LayerProgram& layerProgram, int errorMessageSize, char* errorMessage);
|
||||
bool CompilePreparedLayerProgram(const RuntimeRenderState& state, const std::string& fragmentShaderSource, LayerProgram& layerProgram, int errorMessageSize, char* errorMessage);
|
||||
bool CompilePreparedLayerProgram(const RuntimeRenderState& state, const std::vector<std::pair<std::string, std::string>>& passSources, LayerProgram& layerProgram, int errorMessageSize, char* errorMessage);
|
||||
bool CompilePreparedLayerProgram(const RuntimeRenderState& state, const std::vector<ShaderPassBuildSource>& passSources, LayerProgram& layerProgram, int errorMessageSize, char* errorMessage);
|
||||
bool CompileDecodeShader(int errorMessageSize, char* errorMessage);
|
||||
bool CompileOutputPackShader(int errorMessageSize, char* errorMessage);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user