Multi pass
All checks were successful
CI / React UI Build (push) Successful in 10s
CI / Native Windows Build And Tests (push) Successful in 2m16s
CI / Windows Release Package (push) Successful in 2m28s

This commit is contained in:
2026-05-08 17:28:48 +10:00
parent 596d370f43
commit f85abef237
15 changed files with 197 additions and 66 deletions

View File

@@ -152,10 +152,23 @@ Pass fields:
- `id`: required pass identifier. It must be a valid shader identifier and unique inside the package. - `id`: required pass identifier. It must be a valid shader identifier and unique inside the package.
- `source`: required Slang source path relative to the package directory. - `source`: required Slang source path relative to the package directory.
- `entryPoint`: optional Slang function for this pass. Defaults to the package-level `entryPoint`. - `entryPoint`: optional Slang function for this pass. Defaults to the package-level `entryPoint`.
- `inputs`: optional list of named inputs. Current reserved names include `layerInput` and future pass output names. - `inputs`: optional list of named inputs. The first input is used as the pass input texture.
- `output`: optional output name. Use `layerOutput` for the final visible layer result. - `output`: optional output name. Use `layerOutput` for the final visible layer result.
Current runtime note: pass manifests are parsed and every declared pass is Slang-validated/compiled, but execution still uses the first pass until multipass render-target routing is enabled. Existing single-pass shaders are unaffected. Pass input names:
- `layerInput`: the input to this layer, before any of its passes run.
- `previousPass`: the previous pass output in this layer. If there is no previous pass, this falls back to `layerInput`.
- Any earlier pass `id` or `output` name from the same layer.
If `inputs` is omitted, the first pass samples `layerInput` and later passes sample `previousPass`.
Pass output names:
- `layerOutput`: the final visible output of this layer.
- Any other name creates an intermediate 16-bit float render target that later passes may sample.
If the final declared pass does not explicitly output `layerOutput`, the runtime still treats that final pass as the visible layer output. Existing single-pass shaders are unaffected.
## Slang Entry Point ## Slang Entry Point

View File

@@ -2,6 +2,8 @@
#include "GlRenderConstants.h" #include "GlRenderConstants.h"
#include <map>
OpenGLRenderPass::OpenGLRenderPass(OpenGLRenderer& renderer) : OpenGLRenderPass::OpenGLRenderPass(OpenGLRenderer& renderer) :
mRenderer(renderer) mRenderer(renderer)
{ {
@@ -93,7 +95,10 @@ std::vector<RenderPassDescriptor> OpenGLRenderPass::BuildLayerPassDescriptors(
{ {
std::vector<RenderPassDescriptor> passes; std::vector<RenderPassDescriptor> passes;
const std::size_t passCount = layerStates.size() < layerPrograms.size() ? layerStates.size() : layerPrograms.size(); 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 sourceTexture = mRenderer.DecodedTexture();
GLuint sourceFramebuffer = mRenderer.DecodeFramebuffer(); GLuint sourceFramebuffer = mRenderer.DecodeFramebuffer();
@@ -105,25 +110,90 @@ std::vector<RenderPassDescriptor> OpenGLRenderPass::BuildLayerPassDescriptors(
continue; continue;
const std::size_t remaining = layerStates.size() - index; const std::size_t remaining = layerStates.size() - index;
const bool writeToMain = (remaining % 2) == 1; 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; const GLuint layerInputTexture = sourceTexture;
pass.kind = RenderPassKind::LayerEffect; const GLuint layerInputFramebuffer = sourceFramebuffer;
pass.outputTarget = writeToMain ? RenderPassOutputTarget::Composite : RenderPassOutputTarget::LayerTemp; GLuint previousPassTexture = layerInputTexture;
pass.passIndex = index; GLuint previousPassFramebuffer = layerInputFramebuffer;
pass.passId = state.layerId; std::map<std::string, std::pair<GLuint, GLuint>> namedOutputs;
pass.layerId = state.layerId; std::size_t temporaryTargetIndex = 0;
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);
sourceTexture = writeToMain ? mRenderer.CompositeTexture() : mRenderer.LayerTempTexture(); for (std::size_t passIndex = 0; passIndex < layerProgram.passes.size(); ++passIndex)
sourceFramebuffer = writeToMain ? mRenderer.CompositeFramebuffer() : mRenderer.LayerTempFramebuffer(); {
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; return passes;

View File

@@ -15,6 +15,7 @@ enum class RenderPassKind
enum class RenderPassOutputTarget enum class RenderPassOutputTarget
{ {
Temporary,
LayerTemp, LayerTemp,
Composite Composite
}; };
@@ -29,6 +30,7 @@ struct RenderPassDescriptor
std::string shaderId; std::string shaderId;
GLuint sourceTexture = 0; GLuint sourceTexture = 0;
GLuint sourceFramebuffer = 0; GLuint sourceFramebuffer = 0;
GLuint destinationTexture = 0;
GLuint destinationFramebuffer = 0; GLuint destinationFramebuffer = 0;
OpenGLRenderer::LayerProgram* layerProgram = nullptr; OpenGLRenderer::LayerProgram* layerProgram = nullptr;
OpenGLRenderer::LayerProgram::PassProgram* passProgram = nullptr; OpenGLRenderer::LayerProgram::PassProgram* passProgram = nullptr;

View File

@@ -80,6 +80,11 @@ void OpenGLRenderer::SetOutputPackShaderProgram(GLuint program, GLuint vertexSha
mOutputPackFragmentShader = fragmentShader; 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) void OpenGLRenderer::ResizeView(int width, int height)
{ {
mViewWidth = width; mViewWidth = width;

View File

@@ -41,6 +41,8 @@ public:
struct PassProgram struct PassProgram
{ {
std::string passId; std::string passId;
std::vector<std::string> inputNames;
std::string outputName;
GLuint shaderTextureBase = 0; GLuint shaderTextureBase = 0;
GLuint program = 0; GLuint program = 0;
GLuint vertexShader = 0; GLuint vertexShader = 0;
@@ -73,6 +75,9 @@ public:
void ReplaceLayerPrograms(std::vector<LayerProgram>& newPrograms) { mLayerPrograms.swap(newPrograms); } void ReplaceLayerPrograms(std::vector<LayerProgram>& newPrograms) { mLayerPrograms.swap(newPrograms); }
std::vector<LayerProgram>& LayerPrograms() { return mLayerPrograms; } std::vector<LayerProgram>& LayerPrograms() { return mLayerPrograms; }
const std::vector<LayerProgram>& LayerPrograms() const { 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; } TemporalHistoryBuffers& TemporalHistory() { return mTemporalHistory; }
const TemporalHistoryBuffers& TemporalHistory() const { return mTemporalHistory; } const TemporalHistoryBuffers& TemporalHistory() const { return mTemporalHistory; }
void SetDecodeShaderProgram(GLuint program, GLuint vertexShader, GLuint fragmentShader); void SetDecodeShaderProgram(GLuint program, GLuint vertexShader, GLuint fragmentShader);

View File

@@ -69,11 +69,10 @@ bool RenderTargetPool::ReserveTemporaryTargets(
GLenum pixelType, GLenum pixelType,
std::string& error) std::string& error)
{ {
if (!mTemporaryTargets.empty()) if (mTemporaryTargets.size() == count)
{ return true;
error = "Temporary render targets were already initialized.";
return false; DestroyTemporaryTargets();
}
mTemporaryTargets.resize(count); mTemporaryTargets.resize(count);
for (std::size_t index = 0; index < mTemporaryTargets.size(); ++index) for (std::size_t index = 0; index < mTemporaryTargets.size(); ++index)
@@ -105,6 +104,18 @@ bool RenderTargetPool::ReserveTemporaryTargets(
return true; 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() void RenderTargetPool::Destroy()
{ {
for (RenderTarget& target : mTargets) for (RenderTarget& target : mTargets)
@@ -116,14 +127,7 @@ void RenderTargetPool::Destroy()
target = RenderTarget(); target = RenderTarget();
} }
for (RenderTarget& target : mTemporaryTargets) DestroyTemporaryTargets();
{
if (target.framebuffer != 0)
glDeleteFramebuffers(1, &target.framebuffer);
if (target.texture != 0)
glDeleteTextures(1, &target.texture);
}
mTemporaryTargets.clear();
} }
const RenderTarget& RenderTargetPool::Target(RenderTargetId id) const const RenderTarget& RenderTargetPool::Target(RenderTargetId id) const

View File

@@ -47,6 +47,7 @@ public:
GLenum pixelFormat, GLenum pixelFormat,
GLenum pixelType, GLenum pixelType,
std::string& error); std::string& error);
void DestroyTemporaryTargets();
void Destroy(); void Destroy();
GLuint Texture(RenderTargetId id) const { return Target(id).texture; } GLuint Texture(RenderTargetId id) const { return Target(id).texture; }

View File

@@ -2,7 +2,6 @@
#include <cstring> #include <cstring>
#include <string> #include <string>
#include <utility>
#include <vector> #include <vector>
namespace namespace
@@ -14,6 +13,18 @@ void CopyErrorMessage(const std::string& message, int errorMessageSize, char* er
strncpy_s(errorMessage, errorMessageSize, message.c_str(), _TRUNCATE); 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) : OpenGLShaderPrograms::OpenGLShaderPrograms(OpenGLRenderer& renderer, RuntimeHost& runtimeHost) :
@@ -55,6 +66,15 @@ bool OpenGLShaderPrograms::CompileLayerPrograms(unsigned inputFrameWidth, unsign
newPrograms.push_back(layerProgram); 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(); DestroyLayerPrograms();
mRenderer.ReplaceLayerPrograms(newPrograms); mRenderer.ReplaceLayerPrograms(newPrograms);
mCommittedLayerStates = layerStates; mCommittedLayerStates = layerStates;
@@ -92,11 +112,7 @@ bool OpenGLShaderPrograms::CommitPreparedLayerPrograms(const PreparedShaderBuild
for (const PreparedLayerShader& preparedLayer : preparedBuild.layers) for (const PreparedLayerShader& preparedLayer : preparedBuild.layers)
{ {
LayerProgram layerProgram; LayerProgram layerProgram;
std::vector<std::pair<std::string, std::string>> passSources; if (!mCompiler.CompilePreparedLayerProgram(preparedLayer.state, preparedLayer.passes, layerProgram, errorMessageSize, errorMessage))
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))
{ {
for (LayerProgram& program : newPrograms) for (LayerProgram& program : newPrograms)
DestroySingleLayerProgram(program); DestroySingleLayerProgram(program);
@@ -105,6 +121,15 @@ bool OpenGLShaderPrograms::CommitPreparedLayerPrograms(const PreparedShaderBuild
newPrograms.push_back(layerProgram); 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(); DestroyLayerPrograms();
mRenderer.ReplaceLayerPrograms(newPrograms); mRenderer.ReplaceLayerPrograms(newPrograms);
mCommittedLayerStates = preparedBuild.layerStates; mCommittedLayerStates = preparedBuild.layerStates;

View File

@@ -120,15 +120,11 @@ PreparedShaderBuild ShaderBuildQueue::Build(uint64_t generation, unsigned output
{ {
PreparedLayerShader layer; PreparedLayerShader layer;
layer.state = state; layer.state = state;
std::vector<std::pair<std::string, std::string>> passSources; if (!mRuntimeHost.BuildLayerPassFragmentShaderSources(state.layerId, layer.passes, build.message))
if (!mRuntimeHost.BuildLayerPassFragmentShaderSources(state.layerId, passSources, build.message))
{ {
build.succeeded = false; build.succeeded = false;
return build; 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)); build.layers.push_back(std::move(layer));
} }

View File

@@ -13,14 +13,8 @@ class RuntimeHost;
struct PreparedLayerShader struct PreparedLayerShader
{ {
struct Pass
{
std::string passId;
std::string fragmentShaderSource;
};
RuntimeRenderState state; RuntimeRenderState state;
std::vector<Pass> passes; std::vector<ShaderPassBuildSource> passes;
}; };
struct PreparedShaderBuild struct PreparedShaderBuild

View File

@@ -28,7 +28,7 @@ ShaderProgramCompiler::ShaderProgramCompiler(OpenGLRenderer& renderer, RuntimeHo
bool ShaderProgramCompiler::CompileLayerProgram(const RuntimeRenderState& state, LayerProgram& layerProgram, int errorMessageSize, char* errorMessage) 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; std::string loadError;
if (!mRuntimeHost.BuildLayerPassFragmentShaderSources(state.layerId, passSources, 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) 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; std::vector<ShaderPassBuildSource> passSources;
passSources.push_back(std::make_pair(std::string("main"), fragmentShaderSource)); ShaderPassBuildSource passSource;
passSource.passId = "main";
passSource.fragmentShaderSource = fragmentShaderSource;
passSource.outputName = "layerOutput";
passSources.push_back(std::move(passSource));
return CompilePreparedLayerProgram(state, passSources, layerProgram, errorMessageSize, errorMessage); 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; GLsizei errorBufferSize = 0;
std::string loadError; std::string loadError;
@@ -61,7 +65,7 @@ bool ShaderProgramCompiler::CompilePreparedLayerProgram(const RuntimeRenderState
{ {
GLint compileResult = GL_FALSE; GLint compileResult = GL_FALSE;
GLint linkResult = 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)); ScopedGlShader newVertexShader(glCreateShader(GL_VERTEX_SHADER));
glShaderSource(newVertexShader.get(), 1, (const GLchar**)&vertexSource, NULL); glShaderSource(newVertexShader.get(), 1, (const GLchar**)&vertexSource, NULL);
@@ -121,7 +125,9 @@ bool ShaderProgramCompiler::CompilePreparedLayerProgram(const RuntimeRenderState
mTextureBindings.CreateTextBindings(state, textBindings); mTextureBindings.CreateTextBindings(state, textBindings);
PassProgram passProgram; 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.shaderTextureBase = mTextureBindings.ResolveShaderTextureBase(state, mRuntimeHost.GetMaxTemporalHistoryFrames());
passProgram.textureBindings.swap(textureBindings); passProgram.textureBindings.swap(textureBindings);
passProgram.textBindings.swap(textBindings); passProgram.textBindings.swap(textBindings);

View File

@@ -5,7 +5,6 @@
#include "ShaderTextureBindings.h" #include "ShaderTextureBindings.h"
#include <string> #include <string>
#include <utility>
#include <vector> #include <vector>
class ShaderProgramCompiler class ShaderProgramCompiler
@@ -18,7 +17,7 @@ public:
bool CompileLayerProgram(const RuntimeRenderState& state, LayerProgram& layerProgram, int errorMessageSize, char* errorMessage); 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::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 CompileDecodeShader(int errorMessageSize, char* errorMessage);
bool CompileOutputPackShader(int errorMessageSize, char* errorMessage); bool CompileOutputPackShader(int errorMessageSize, char* errorMessage);

View File

@@ -1302,7 +1302,7 @@ bool RuntimeHost::TryAdvanceFrame()
bool RuntimeHost::BuildLayerFragmentShaderSource(const std::string& layerId, std::string& fragmentShaderSource, std::string& error) bool RuntimeHost::BuildLayerFragmentShaderSource(const std::string& layerId, std::string& fragmentShaderSource, std::string& error)
{ {
std::vector<std::pair<std::string, std::string>> passSources; std::vector<ShaderPassBuildSource> passSources;
if (!BuildLayerPassFragmentShaderSources(layerId, passSources, error)) if (!BuildLayerPassFragmentShaderSources(layerId, passSources, error))
return false; return false;
if (passSources.empty()) if (passSources.empty())
@@ -1310,11 +1310,11 @@ bool RuntimeHost::BuildLayerFragmentShaderSource(const std::string& layerId, std
error = "Shader layer produced no compiled passes: " + layerId; error = "Shader layer produced no compiled passes: " + layerId;
return false; return false;
} }
fragmentShaderSource = passSources.front().second; fragmentShaderSource = passSources.front().fragmentShaderSource;
return true; return true;
} }
bool RuntimeHost::BuildLayerPassFragmentShaderSources(const std::string& layerId, std::vector<std::pair<std::string, std::string>>& passSources, std::string& error) bool RuntimeHost::BuildLayerPassFragmentShaderSources(const std::string& layerId, std::vector<ShaderPassBuildSource>& passSources, std::string& error)
{ {
try try
{ {
@@ -1342,10 +1342,13 @@ bool RuntimeHost::BuildLayerPassFragmentShaderSources(const std::string& layerId
passSources.reserve(shaderPackage.passes.size()); passSources.reserve(shaderPackage.passes.size());
for (const ShaderPassDefinition& pass : shaderPackage.passes) for (const ShaderPassDefinition& pass : shaderPackage.passes)
{ {
std::string fragmentShaderSource; ShaderPassBuildSource passSource;
if (!compiler.BuildPassFragmentShaderSource(shaderPackage, pass, fragmentShaderSource, error)) passSource.passId = pass.id;
passSource.inputNames = pass.inputNames;
passSource.outputName = pass.outputName;
if (!compiler.BuildPassFragmentShaderSource(shaderPackage, pass, passSource.fragmentShaderSource, error))
return false; return false;
passSources.push_back(std::make_pair(pass.id, std::move(fragmentShaderSource))); passSources.push_back(std::move(passSource));
} }
return true; return true;
} }

View File

@@ -52,7 +52,7 @@ public:
bool TryAdvanceFrame(); bool TryAdvanceFrame();
bool BuildLayerFragmentShaderSource(const std::string& layerId, std::string& fragmentShaderSource, std::string& error); bool BuildLayerFragmentShaderSource(const std::string& layerId, std::string& fragmentShaderSource, std::string& error);
bool BuildLayerPassFragmentShaderSources(const std::string& layerId, std::vector<std::pair<std::string, std::string>>& passSources, std::string& error); bool BuildLayerPassFragmentShaderSources(const std::string& layerId, std::vector<ShaderPassBuildSource>& passSources, std::string& error);
std::vector<RuntimeRenderState> GetLayerRenderStates(unsigned outputWidth, unsigned outputHeight) const; std::vector<RuntimeRenderState> GetLayerRenderStates(unsigned outputWidth, unsigned outputHeight) const;
bool TryGetLayerRenderStates(unsigned outputWidth, unsigned outputHeight, std::vector<RuntimeRenderState>& states) const; bool TryGetLayerRenderStates(unsigned outputWidth, unsigned outputHeight, std::vector<RuntimeRenderState>& states) const;
void RefreshDynamicRenderStateFields(std::vector<RuntimeRenderState>& states) const; void RefreshDynamicRenderStateFields(std::vector<RuntimeRenderState>& states) const;

View File

@@ -86,6 +86,14 @@ struct ShaderPassDefinition
std::string outputName; std::string outputName;
}; };
struct ShaderPassBuildSource
{
std::string passId;
std::string fragmentShaderSource;
std::vector<std::string> inputNames;
std::string outputName;
};
struct ShaderPackage struct ShaderPackage
{ {
std::string id; std::string id;