Shader clean up
This commit is contained in:
@@ -56,8 +56,12 @@ set(APP_SOURCES
|
|||||||
"${APP_DIR}/gl/OpenGLComposite.cpp"
|
"${APP_DIR}/gl/OpenGLComposite.cpp"
|
||||||
"${APP_DIR}/gl/OpenGLComposite.h"
|
"${APP_DIR}/gl/OpenGLComposite.h"
|
||||||
"${APP_DIR}/gl/OpenGLCompositeRuntimeControls.cpp"
|
"${APP_DIR}/gl/OpenGLCompositeRuntimeControls.cpp"
|
||||||
|
"${APP_DIR}/gl/OpenGLRenderPass.cpp"
|
||||||
|
"${APP_DIR}/gl/OpenGLRenderPass.h"
|
||||||
"${APP_DIR}/gl/OpenGLRenderer.cpp"
|
"${APP_DIR}/gl/OpenGLRenderer.cpp"
|
||||||
"${APP_DIR}/gl/OpenGLRenderer.h"
|
"${APP_DIR}/gl/OpenGLRenderer.h"
|
||||||
|
"${APP_DIR}/gl/OpenGLShaderPrograms.cpp"
|
||||||
|
"${APP_DIR}/gl/OpenGLShaderPrograms.h"
|
||||||
"${APP_DIR}/gl/Std140Buffer.h"
|
"${APP_DIR}/gl/Std140Buffer.h"
|
||||||
"${APP_DIR}/gl/TextRasterizer.cpp"
|
"${APP_DIR}/gl/TextRasterizer.cpp"
|
||||||
"${APP_DIR}/gl/TextRasterizer.h"
|
"${APP_DIR}/gl/TextRasterizer.h"
|
||||||
|
|||||||
@@ -195,7 +195,9 @@
|
|||||||
<ClCompile Include="gl\GLExtensions.cpp" />
|
<ClCompile Include="gl\GLExtensions.cpp" />
|
||||||
<ClCompile Include="LoopThroughWithOpenGLCompositing.cpp" />
|
<ClCompile Include="LoopThroughWithOpenGLCompositing.cpp" />
|
||||||
<ClCompile Include="gl\OpenGLComposite.cpp" />
|
<ClCompile Include="gl\OpenGLComposite.cpp" />
|
||||||
|
<ClCompile Include="gl\OpenGLRenderPass.cpp" />
|
||||||
<ClCompile Include="gl\OpenGLRenderer.cpp" />
|
<ClCompile Include="gl\OpenGLRenderer.cpp" />
|
||||||
|
<ClCompile Include="gl\OpenGLShaderPrograms.cpp" />
|
||||||
<ClCompile Include="gl\TemporalHistoryBuffers.cpp" />
|
<ClCompile Include="gl\TemporalHistoryBuffers.cpp" />
|
||||||
<ClCompile Include="stdafx.cpp">
|
<ClCompile Include="stdafx.cpp">
|
||||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
|
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
|
||||||
@@ -210,7 +212,9 @@
|
|||||||
<ClInclude Include="gl\GLExtensions.h" />
|
<ClInclude Include="gl\GLExtensions.h" />
|
||||||
<ClInclude Include="LoopThroughWithOpenGLCompositing.h" />
|
<ClInclude Include="LoopThroughWithOpenGLCompositing.h" />
|
||||||
<ClInclude Include="gl\OpenGLComposite.h" />
|
<ClInclude Include="gl\OpenGLComposite.h" />
|
||||||
|
<ClInclude Include="gl\OpenGLRenderPass.h" />
|
||||||
<ClInclude Include="gl\OpenGLRenderer.h" />
|
<ClInclude Include="gl\OpenGLRenderer.h" />
|
||||||
|
<ClInclude Include="gl\OpenGLShaderPrograms.h" />
|
||||||
<ClInclude Include="gl\TemporalHistoryBuffers.h" />
|
<ClInclude Include="gl\TemporalHistoryBuffers.h" />
|
||||||
<ClInclude Include="resource.h" />
|
<ClInclude Include="resource.h" />
|
||||||
<ClInclude Include="stdafx.h" />
|
<ClInclude Include="stdafx.h" />
|
||||||
|
|||||||
@@ -27,9 +27,15 @@
|
|||||||
<ClCompile Include="gl\OpenGLComposite.cpp">
|
<ClCompile Include="gl\OpenGLComposite.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="gl\OpenGLRenderPass.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="gl\OpenGLRenderer.cpp">
|
<ClCompile Include="gl\OpenGLRenderer.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="gl\OpenGLShaderPrograms.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="gl\TemporalHistoryBuffers.cpp">
|
<ClCompile Include="gl\TemporalHistoryBuffers.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
@@ -53,9 +59,15 @@
|
|||||||
<ClInclude Include="gl\OpenGLComposite.h">
|
<ClInclude Include="gl\OpenGLComposite.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="gl\OpenGLRenderPass.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
<ClInclude Include="gl\OpenGLRenderer.h">
|
<ClInclude Include="gl\OpenGLRenderer.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="gl\OpenGLShaderPrograms.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
<ClInclude Include="gl\TemporalHistoryBuffers.h">
|
<ClInclude Include="gl\TemporalHistoryBuffers.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
|||||||
@@ -63,10 +63,12 @@
|
|||||||
#define GL_ARRAY_BUFFER 0x8892
|
#define GL_ARRAY_BUFFER 0x8892
|
||||||
#define GL_PIXEL_PACK_BUFFER 0x88EB
|
#define GL_PIXEL_PACK_BUFFER 0x88EB
|
||||||
#define GL_PIXEL_UNPACK_BUFFER 0x88EC
|
#define GL_PIXEL_UNPACK_BUFFER 0x88EC
|
||||||
|
#define GL_PIXEL_UNPACK_BUFFER_BINDING 0x88EF
|
||||||
#define GL_FRAGMENT_SHADER 0x8B30
|
#define GL_FRAGMENT_SHADER 0x8B30
|
||||||
#define GL_VERTEX_SHADER 0x8B31
|
#define GL_VERTEX_SHADER 0x8B31
|
||||||
#define GL_COMPILE_STATUS 0x8B81
|
#define GL_COMPILE_STATUS 0x8B81
|
||||||
#define GL_LINK_STATUS 0x8B82
|
#define GL_LINK_STATUS 0x8B82
|
||||||
|
#define GL_INVALID_INDEX 0xFFFFFFFFu
|
||||||
#define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872
|
#define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872
|
||||||
#define GL_RENDERBUFFER_EXT 0x8D41
|
#define GL_RENDERBUFFER_EXT 0x8D41
|
||||||
#define GL_FRAMEBUFFER_EXT 0x8D40
|
#define GL_FRAMEBUFFER_EXT 0x8D40
|
||||||
|
|||||||
@@ -44,62 +44,15 @@
|
|||||||
#include "OpenGLComposite.h"
|
#include "OpenGLComposite.h"
|
||||||
#include "GLExtensions.h"
|
#include "GLExtensions.h"
|
||||||
#include "GlRenderConstants.h"
|
#include "GlRenderConstants.h"
|
||||||
#include "GlScopedObjects.h"
|
#include "OpenGLRenderPass.h"
|
||||||
#include "GlShaderSources.h"
|
#include "OpenGLShaderPrograms.h"
|
||||||
#include "OscServer.h"
|
#include "OscServer.h"
|
||||||
#include "RuntimeControlBridge.h"
|
#include "RuntimeControlBridge.h"
|
||||||
#include "Std140Buffer.h"
|
|
||||||
#include "TextRasterizer.h"
|
|
||||||
#include "TextureAssetLoader.h"
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <cstdint>
|
|
||||||
#include <cstring>
|
|
||||||
#include <cctype>
|
|
||||||
#include <limits>
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#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::string TextValueForBinding(const RuntimeRenderState& state, const std::string& parameterId)
|
|
||||||
{
|
|
||||||
auto valueIt = state.parameterValues.find(parameterId);
|
|
||||||
return valueIt == state.parameterValues.end() ? std::string() : valueIt->second.textValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const ShaderFontAsset* FindFontAssetForParameter(const RuntimeRenderState& state, const ShaderParameterDefinition& definition)
|
|
||||||
{
|
|
||||||
if (!definition.fontId.empty())
|
|
||||||
{
|
|
||||||
for (const ShaderFontAsset& fontAsset : state.fontAssets)
|
|
||||||
{
|
|
||||||
if (fontAsset.id == definition.fontId)
|
|
||||||
return &fontAsset;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return state.fontAssets.empty() ? nullptr : &state.fontAssets.front();
|
|
||||||
}
|
|
||||||
|
|
||||||
GLint FindSamplerUniformLocation(GLuint program, const std::string& samplerName)
|
|
||||||
{
|
|
||||||
GLint location = glGetUniformLocation(program, samplerName.c_str());
|
|
||||||
if (location >= 0)
|
|
||||||
return location;
|
|
||||||
return glGetUniformLocation(program, (samplerName + "_0").c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
OpenGLComposite::OpenGLComposite(HWND hWnd, HDC hDC, HGLRC hRC) :
|
OpenGLComposite::OpenGLComposite(HWND hWnd, HDC hDC, HGLRC hRC) :
|
||||||
hGLWnd(hWnd), hGLDC(hDC), hGLRC(hRC),
|
hGLWnd(hWnd), hGLDC(hDC), hGLRC(hRC),
|
||||||
mCaptureDelegate(NULL), mPlayoutDelegate(NULL),
|
mCaptureDelegate(NULL), mPlayoutDelegate(NULL),
|
||||||
@@ -118,6 +71,8 @@ OpenGLComposite::OpenGLComposite(HWND hWnd, HDC hDC, HGLRC hRC) :
|
|||||||
{
|
{
|
||||||
InitializeCriticalSection(&pMutex);
|
InitializeCriticalSection(&pMutex);
|
||||||
mRuntimeHost = std::make_unique<RuntimeHost>();
|
mRuntimeHost = std::make_unique<RuntimeHost>();
|
||||||
|
mRenderPass = std::make_unique<OpenGLRenderPass>(*mRenderer);
|
||||||
|
mShaderPrograms = std::make_unique<OpenGLShaderPrograms>(*mRenderer, *mRuntimeHost);
|
||||||
mControlServer = std::make_unique<ControlServer>();
|
mControlServer = std::make_unique<ControlServer>();
|
||||||
mOscServer = std::make_unique<OscServer>();
|
mOscServer = std::make_unique<OscServer>();
|
||||||
}
|
}
|
||||||
@@ -648,18 +603,18 @@ bool OpenGLComposite::InitOpenGLState()
|
|||||||
|
|
||||||
// Prepare the runtime shader program generated from the active shader package.
|
// Prepare the runtime shader program generated from the active shader package.
|
||||||
char compilerErrorMessage[1024];
|
char compilerErrorMessage[1024];
|
||||||
if (! compileDecodeShader(sizeof(compilerErrorMessage), compilerErrorMessage))
|
if (!mShaderPrograms->CompileDecodeShader(sizeof(compilerErrorMessage), compilerErrorMessage))
|
||||||
{
|
{
|
||||||
MessageBoxA(NULL, compilerErrorMessage, "OpenGL decode shader failed to load or compile", MB_OK);
|
MessageBoxA(NULL, compilerErrorMessage, "OpenGL decode shader failed to load or compile", MB_OK);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! compileLayerPrograms(sizeof(compilerErrorMessage), compilerErrorMessage))
|
if (!mShaderPrograms->CompileLayerPrograms(mInputFrameWidth, mInputFrameHeight, sizeof(compilerErrorMessage), compilerErrorMessage))
|
||||||
{
|
{
|
||||||
MessageBoxA(NULL, compilerErrorMessage, "OpenGL shader failed to load or compile", MB_OK);
|
MessageBoxA(NULL, compilerErrorMessage, "OpenGL shader failed to load or compile", MB_OK);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
resetTemporalHistoryState();
|
mShaderPrograms->ResetTemporalHistoryState();
|
||||||
|
|
||||||
std::string rendererError;
|
std::string rendererError;
|
||||||
if (!mRenderer->InitializeResources(mInputFrameWidth, mInputFrameHeight, mOutputFrameWidth, mOutputFrameHeight, rendererError))
|
if (!mRenderer->InitializeResources(mInputFrameWidth, mInputFrameHeight, mOutputFrameWidth, mOutputFrameHeight, rendererError))
|
||||||
@@ -943,7 +898,7 @@ bool OpenGLComposite::ReloadShader()
|
|||||||
EnterCriticalSection(&pMutex);
|
EnterCriticalSection(&pMutex);
|
||||||
wglMakeCurrent(hGLDC, hGLRC);
|
wglMakeCurrent(hGLDC, hGLRC);
|
||||||
|
|
||||||
bool success = compileLayerPrograms(sizeof(compilerErrorMessage), compilerErrorMessage);
|
bool success = mShaderPrograms->CompileLayerPrograms(mInputFrameWidth, mInputFrameHeight, sizeof(compilerErrorMessage), compilerErrorMessage);
|
||||||
if (mRuntimeHost)
|
if (mRuntimeHost)
|
||||||
mRuntimeHost->ClearReloadRequest();
|
mRuntimeHost->ClearReloadRequest();
|
||||||
|
|
||||||
@@ -966,455 +921,25 @@ bool OpenGLComposite::ReloadShader()
|
|||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OpenGLComposite::compileSingleLayerProgram(const RuntimeRenderState& state, LayerProgram& layerProgram, int errorMessageSize, char* errorMessage)
|
|
||||||
{
|
|
||||||
GLsizei errorBufferSize = 0;
|
|
||||||
GLint compileResult = GL_FALSE;
|
|
||||||
GLint linkResult = GL_FALSE;
|
|
||||||
std::string fragmentShaderSource;
|
|
||||||
std::string loadError;
|
|
||||||
std::vector<LayerProgram::TextureBinding> textureBindings;
|
|
||||||
const char* vertexSource = kFullscreenTriangleVertexShaderSource;
|
|
||||||
|
|
||||||
if (!mRuntimeHost->BuildLayerFragmentShaderSource(state.layerId, fragmentShaderSource, loadError))
|
|
||||||
{
|
|
||||||
CopyErrorMessage(loadError, errorMessageSize, errorMessage);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* fragmentSource = 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);
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const ShaderTextureAsset& textureAsset : state.textureAssets)
|
|
||||||
{
|
|
||||||
LayerProgram::TextureBinding textureBinding;
|
|
||||||
textureBinding.samplerName = textureAsset.id;
|
|
||||||
textureBinding.sourcePath = textureAsset.path;
|
|
||||||
if (!loadTextureAsset(textureAsset, textureBinding.texture, loadError))
|
|
||||||
{
|
|
||||||
for (LayerProgram::TextureBinding& loadedTexture : textureBindings)
|
|
||||||
{
|
|
||||||
if (loadedTexture.texture != 0)
|
|
||||||
glDeleteTextures(1, &loadedTexture.texture);
|
|
||||||
}
|
|
||||||
CopyErrorMessage(loadError, errorMessageSize, errorMessage);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
textureBindings.push_back(textureBinding);
|
|
||||||
}
|
|
||||||
std::vector<LayerProgram::TextBinding> textBindings;
|
|
||||||
for (const ShaderParameterDefinition& definition : state.parameterDefinitions)
|
|
||||||
{
|
|
||||||
if (definition.type != ShaderParameterType::Text)
|
|
||||||
continue;
|
|
||||||
LayerProgram::TextBinding textBinding;
|
|
||||||
textBinding.parameterId = definition.id;
|
|
||||||
textBinding.samplerName = definition.id + "Texture";
|
|
||||||
textBinding.fontId = definition.fontId;
|
|
||||||
glGenTextures(1, &textBinding.texture);
|
|
||||||
glBindTexture(GL_TEXTURE_2D, textBinding.texture);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
||||||
std::vector<unsigned char> empty(static_cast<std::size_t>(kTextTextureWidth) * kTextTextureHeight * 4, 0);
|
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, kTextTextureWidth, kTextTextureHeight, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, empty.data());
|
|
||||||
glBindTexture(GL_TEXTURE_2D, 0);
|
|
||||||
textBindings.push_back(textBinding);
|
|
||||||
}
|
|
||||||
|
|
||||||
const GLuint globalParamsIndex = glGetUniformBlockIndex(newProgram.get(), "GlobalParams");
|
|
||||||
if (globalParamsIndex != GL_INVALID_INDEX)
|
|
||||||
glUniformBlockBinding(newProgram.get(), globalParamsIndex, kGlobalParamsBindingPoint);
|
|
||||||
|
|
||||||
const unsigned historyCap = mRuntimeHost ? mRuntimeHost->GetMaxTemporalHistoryFrames() : 0;
|
|
||||||
const GLuint shaderTextureBase = state.isTemporal ? kSourceHistoryTextureUnitBase + historyCap + historyCap : kSourceHistoryTextureUnitBase;
|
|
||||||
glUseProgram(newProgram.get());
|
|
||||||
const GLint videoInputLocation = glGetUniformLocation(newProgram.get(), "gVideoInput");
|
|
||||||
if (videoInputLocation >= 0)
|
|
||||||
glUniform1i(videoInputLocation, static_cast<GLint>(kDecodedVideoTextureUnit));
|
|
||||||
for (unsigned index = 0; index < historyCap; ++index)
|
|
||||||
{
|
|
||||||
const std::string sourceSamplerName = "gSourceHistory" + std::to_string(index);
|
|
||||||
const GLint sourceSamplerLocation = glGetUniformLocation(newProgram.get(), sourceSamplerName.c_str());
|
|
||||||
if (sourceSamplerLocation >= 0)
|
|
||||||
glUniform1i(sourceSamplerLocation, static_cast<GLint>(kSourceHistoryTextureUnitBase + index));
|
|
||||||
|
|
||||||
const std::string temporalSamplerName = "gTemporalHistory" + std::to_string(index);
|
|
||||||
const GLint temporalSamplerLocation = glGetUniformLocation(newProgram.get(), temporalSamplerName.c_str());
|
|
||||||
if (temporalSamplerLocation >= 0)
|
|
||||||
glUniform1i(temporalSamplerLocation, static_cast<GLint>(kSourceHistoryTextureUnitBase + historyCap + index));
|
|
||||||
}
|
|
||||||
for (std::size_t index = 0; index < textureBindings.size(); ++index)
|
|
||||||
{
|
|
||||||
const GLint textureSamplerLocation = FindSamplerUniformLocation(newProgram.get(), textureBindings[index].samplerName);
|
|
||||||
if (textureSamplerLocation >= 0)
|
|
||||||
glUniform1i(textureSamplerLocation, static_cast<GLint>(shaderTextureBase + static_cast<GLuint>(index)));
|
|
||||||
}
|
|
||||||
const GLuint textTextureBase = shaderTextureBase + static_cast<GLuint>(textureBindings.size());
|
|
||||||
for (std::size_t index = 0; index < textBindings.size(); ++index)
|
|
||||||
{
|
|
||||||
const GLint textSamplerLocation = FindSamplerUniformLocation(newProgram.get(), textBindings[index].samplerName);
|
|
||||||
if (textSamplerLocation >= 0)
|
|
||||||
glUniform1i(textSamplerLocation, static_cast<GLint>(textTextureBase + static_cast<GLuint>(index)));
|
|
||||||
}
|
|
||||||
glUseProgram(0);
|
|
||||||
|
|
||||||
layerProgram.layerId = state.layerId;
|
|
||||||
layerProgram.shaderId = state.shaderId;
|
|
||||||
layerProgram.shaderTextureBase = shaderTextureBase;
|
|
||||||
layerProgram.program = newProgram.release();
|
|
||||||
layerProgram.vertexShader = newVertexShader.release();
|
|
||||||
layerProgram.fragmentShader = newFragmentShader.release();
|
|
||||||
layerProgram.textureBindings.swap(textureBindings);
|
|
||||||
layerProgram.textBindings.swap(textBindings);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool OpenGLComposite::compileLayerPrograms(int errorMessageSize, char* errorMessage)
|
|
||||||
{
|
|
||||||
const std::vector<RuntimeRenderState> layerStates = mRuntimeHost ? mRuntimeHost->GetLayerRenderStates(mInputFrameWidth, mInputFrameHeight) : std::vector<RuntimeRenderState>();
|
|
||||||
std::string temporalError;
|
|
||||||
if (!validateTemporalTextureUnitBudget(layerStates, temporalError))
|
|
||||||
{
|
|
||||||
CopyErrorMessage(temporalError, errorMessageSize, errorMessage);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!ensureTemporalHistoryResources(layerStates, temporalError))
|
|
||||||
{
|
|
||||||
CopyErrorMessage(temporalError, errorMessageSize, errorMessage);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
std::vector<LayerProgram> newPrograms;
|
|
||||||
newPrograms.reserve(layerStates.size());
|
|
||||||
|
|
||||||
for (const RuntimeRenderState& state : layerStates)
|
|
||||||
{
|
|
||||||
LayerProgram layerProgram;
|
|
||||||
if (!compileSingleLayerProgram(state, layerProgram, errorMessageSize, errorMessage))
|
|
||||||
{
|
|
||||||
for (LayerProgram& program : newPrograms)
|
|
||||||
destroySingleLayerProgram(program);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
newPrograms.push_back(layerProgram);
|
|
||||||
}
|
|
||||||
|
|
||||||
destroyLayerPrograms();
|
|
||||||
mRenderer->mLayerPrograms.swap(newPrograms);
|
|
||||||
|
|
||||||
if (mRuntimeHost)
|
|
||||||
{
|
|
||||||
mRuntimeHost->SetCompileStatus(true, "Shader layers compiled successfully.");
|
|
||||||
mRuntimeHost->ClearReloadRequest();
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool OpenGLComposite::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;
|
|
||||||
}
|
|
||||||
|
|
||||||
destroyDecodeShaderProgram();
|
|
||||||
mRenderer->mDecodeProgram = newProgram.release();
|
|
||||||
mRenderer->mDecodeVertexShader = newVertexShader.release();
|
|
||||||
mRenderer->mDecodeFragmentShader = newFragmentShader.release();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void OpenGLComposite::destroySingleLayerProgram(LayerProgram& layerProgram)
|
|
||||||
{
|
|
||||||
mRenderer->DestroySingleLayerProgram(layerProgram);
|
|
||||||
}
|
|
||||||
|
|
||||||
void OpenGLComposite::destroyLayerPrograms()
|
|
||||||
{
|
|
||||||
mRenderer->DestroyLayerPrograms();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool OpenGLComposite::loadTextureAsset(const ShaderTextureAsset& textureAsset, GLuint& textureId, std::string& error)
|
|
||||||
{
|
|
||||||
return LoadTextureAsset(textureAsset, textureId, error);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool OpenGLComposite::renderTextBindingTexture(const RuntimeRenderState& state, LayerProgram::TextBinding& textBinding, std::string& error)
|
|
||||||
{
|
|
||||||
const std::string text = TextValueForBinding(state, textBinding.parameterId);
|
|
||||||
if (text == textBinding.renderedText && textBinding.renderedWidth == kTextTextureWidth && textBinding.renderedHeight == kTextTextureHeight)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
auto definitionIt = std::find_if(state.parameterDefinitions.begin(), state.parameterDefinitions.end(),
|
|
||||||
[&textBinding](const ShaderParameterDefinition& definition) { return definition.id == textBinding.parameterId; });
|
|
||||||
if (definitionIt == state.parameterDefinitions.end())
|
|
||||||
return true;
|
|
||||||
|
|
||||||
const ShaderFontAsset* fontAsset = FindFontAssetForParameter(state, *definitionIt);
|
|
||||||
std::filesystem::path fontPath;
|
|
||||||
if (fontAsset)
|
|
||||||
fontPath = fontAsset->path;
|
|
||||||
|
|
||||||
std::vector<unsigned char> sdf;
|
|
||||||
if (!RasterizeTextSdf(text, fontPath, sdf, error))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
GLint previousActiveTexture = 0;
|
|
||||||
GLint previousUnpackBuffer = 0;
|
|
||||||
glGetIntegerv(GL_ACTIVE_TEXTURE, &previousActiveTexture);
|
|
||||||
glGetIntegerv(GL_PIXEL_UNPACK_BUFFER_BINDING, &previousUnpackBuffer);
|
|
||||||
glActiveTexture(GL_TEXTURE0);
|
|
||||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
|
|
||||||
glBindTexture(GL_TEXTURE_2D, textBinding.texture);
|
|
||||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kTextTextureWidth, kTextTextureHeight, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, sdf.data());
|
|
||||||
glBindTexture(GL_TEXTURE_2D, 0);
|
|
||||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, static_cast<GLuint>(previousUnpackBuffer));
|
|
||||||
glActiveTexture(static_cast<GLenum>(previousActiveTexture));
|
|
||||||
|
|
||||||
textBinding.renderedText = text;
|
|
||||||
textBinding.renderedWidth = kTextTextureWidth;
|
|
||||||
textBinding.renderedHeight = kTextTextureHeight;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void OpenGLComposite::bindLayerTextureAssets(const LayerProgram& layerProgram)
|
|
||||||
{
|
|
||||||
const GLuint shaderTextureBase = layerProgram.shaderTextureBase != 0 ? layerProgram.shaderTextureBase : kSourceHistoryTextureUnitBase;
|
|
||||||
for (std::size_t index = 0; index < layerProgram.textureBindings.size(); ++index)
|
|
||||||
{
|
|
||||||
glActiveTexture(GL_TEXTURE0 + shaderTextureBase + static_cast<GLuint>(index));
|
|
||||||
glBindTexture(GL_TEXTURE_2D, layerProgram.textureBindings[index].texture);
|
|
||||||
}
|
|
||||||
const GLuint textTextureBase = shaderTextureBase + static_cast<GLuint>(layerProgram.textureBindings.size());
|
|
||||||
for (std::size_t index = 0; index < layerProgram.textBindings.size(); ++index)
|
|
||||||
{
|
|
||||||
glActiveTexture(GL_TEXTURE0 + textTextureBase + static_cast<GLuint>(index));
|
|
||||||
glBindTexture(GL_TEXTURE_2D, layerProgram.textBindings[index].texture);
|
|
||||||
}
|
|
||||||
glActiveTexture(GL_TEXTURE0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void OpenGLComposite::destroyDecodeShaderProgram()
|
|
||||||
{
|
|
||||||
mRenderer->DestroyDecodeShaderProgram();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool OpenGLComposite::validateTemporalTextureUnitBudget(const std::vector<RuntimeRenderState>& layerStates, std::string& error) const
|
|
||||||
{
|
|
||||||
const unsigned historyCap = mRuntimeHost ? mRuntimeHost->GetMaxTemporalHistoryFrames() : 0;
|
|
||||||
return mRenderer->mTemporalHistory.ValidateTextureUnitBudget(layerStates, historyCap, error);
|
|
||||||
}
|
|
||||||
|
|
||||||
void OpenGLComposite::resetTemporalHistoryState()
|
|
||||||
{
|
|
||||||
mRenderer->mTemporalHistory.ResetState();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool OpenGLComposite::ensureTemporalHistoryResources(const std::vector<RuntimeRenderState>& layerStates, std::string& error)
|
|
||||||
{
|
|
||||||
const unsigned historyCap = mRuntimeHost ? mRuntimeHost->GetMaxTemporalHistoryFrames() : 0;
|
|
||||||
return mRenderer->mTemporalHistory.EnsureResources(layerStates, historyCap, mInputFrameWidth, mInputFrameHeight, error);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned OpenGLComposite::sourceHistoryAvailableCount() const
|
|
||||||
{
|
|
||||||
return mRenderer->mTemporalHistory.SourceAvailableCount();
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned OpenGLComposite::temporalHistoryAvailableCountForLayer(const std::string& layerId) const
|
|
||||||
{
|
|
||||||
return mRenderer->mTemporalHistory.AvailableCountForLayer(layerId);
|
|
||||||
}
|
|
||||||
|
|
||||||
void OpenGLComposite::bindHistorySamplers(const RuntimeRenderState& state, GLuint currentSourceTexture)
|
|
||||||
{
|
|
||||||
const unsigned historyCap = mRuntimeHost ? mRuntimeHost->GetMaxTemporalHistoryFrames() : 0;
|
|
||||||
mRenderer->mTemporalHistory.BindSamplers(state, currentSourceTexture, historyCap);
|
|
||||||
}
|
|
||||||
|
|
||||||
void OpenGLComposite::renderEffect()
|
void OpenGLComposite::renderEffect()
|
||||||
{
|
{
|
||||||
PollRuntimeChanges();
|
PollRuntimeChanges();
|
||||||
|
|
||||||
const bool hasInputSource = !mHasNoInputSource;
|
const bool hasInputSource = !mHasNoInputSource;
|
||||||
if (hasInputSource && mRenderer->mFastTransferExtensionAvailable)
|
|
||||||
{
|
|
||||||
// Signal that we're about to draw using mRenderer->mCaptureTexture onto mRenderer->mFBOTexture.
|
|
||||||
VideoFrameTransfer::beginTextureInUse(VideoFrameTransfer::CPUtoGPU);
|
|
||||||
}
|
|
||||||
|
|
||||||
glDisable(GL_BLEND);
|
|
||||||
glDisable(GL_DEPTH_TEST);
|
|
||||||
if (hasInputSource)
|
|
||||||
{
|
|
||||||
renderDecodePass();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, mRenderer->mDecodeFrameBuf);
|
|
||||||
glViewport(0, 0, mInputFrameWidth, mInputFrameHeight);
|
|
||||||
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
|
||||||
glClear(GL_COLOR_BUFFER_BIT);
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::vector<RuntimeRenderState> layerStates = mRuntimeHost ? mRuntimeHost->GetLayerRenderStates(mInputFrameWidth, mInputFrameHeight) : std::vector<RuntimeRenderState>();
|
const std::vector<RuntimeRenderState> layerStates = mRuntimeHost ? mRuntimeHost->GetLayerRenderStates(mInputFrameWidth, mInputFrameHeight) : std::vector<RuntimeRenderState>();
|
||||||
if (layerStates.empty() || mRenderer->mLayerPrograms.empty())
|
|
||||||
{
|
|
||||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, mRenderer->mDecodeFrameBuf);
|
|
||||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mRenderer->mIdFrameBuf);
|
|
||||||
glBlitFramebuffer(0, 0, mInputFrameWidth, mInputFrameHeight, 0, 0, mInputFrameWidth, mInputFrameHeight, GL_COLOR_BUFFER_BIT, GL_LINEAR);
|
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, mRenderer->mIdFrameBuf);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
GLuint sourceTexture = mRenderer->mDecodedTexture;
|
|
||||||
GLuint sourceFrameBuffer = mRenderer->mDecodeFrameBuf;
|
|
||||||
for (std::size_t index = 0; index < layerStates.size() && index < mRenderer->mLayerPrograms.size(); ++index)
|
|
||||||
{
|
|
||||||
const std::size_t remaining = layerStates.size() - index;
|
|
||||||
const bool writeToMain = (remaining % 2) == 1;
|
|
||||||
renderShaderProgram(sourceTexture, writeToMain ? mRenderer->mIdFrameBuf : mRenderer->mLayerTempFrameBuf, mRenderer->mLayerPrograms[index], layerStates[index]);
|
|
||||||
if (layerStates[index].temporalHistorySource == TemporalHistorySource::PreLayerInput)
|
|
||||||
mRenderer->mTemporalHistory.PushPreLayerFramebuffer(layerStates[index].layerId, sourceFrameBuffer, mInputFrameWidth, mInputFrameHeight);
|
|
||||||
sourceTexture = writeToMain ? mRenderer->mFBOTexture : mRenderer->mLayerTempTexture;
|
|
||||||
sourceFrameBuffer = writeToMain ? mRenderer->mIdFrameBuf : mRenderer->mLayerTempFrameBuf;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mRenderer->mTemporalHistory.PushSourceFramebuffer(mRenderer->mDecodeFrameBuf, mInputFrameWidth, mInputFrameHeight);
|
|
||||||
|
|
||||||
if (hasInputSource && mRenderer->mFastTransferExtensionAvailable)
|
|
||||||
VideoFrameTransfer::endTextureInUse(VideoFrameTransfer::CPUtoGPU);
|
|
||||||
}
|
|
||||||
|
|
||||||
void OpenGLComposite::renderShaderProgram(GLuint sourceTexture, GLuint destinationFrameBuffer, LayerProgram& layerProgram, const RuntimeRenderState& state)
|
|
||||||
{
|
|
||||||
for (LayerProgram::TextBinding& textBinding : layerProgram.textBindings)
|
|
||||||
{
|
|
||||||
std::string textError;
|
|
||||||
if (!renderTextBindingTexture(state, textBinding, textError))
|
|
||||||
OutputDebugStringA((textError + "\n").c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, destinationFrameBuffer);
|
|
||||||
glViewport(0, 0, mInputFrameWidth, mInputFrameHeight);
|
|
||||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
||||||
glActiveTexture(GL_TEXTURE0 + kDecodedVideoTextureUnit);
|
|
||||||
glBindTexture(GL_TEXTURE_2D, sourceTexture);
|
|
||||||
bindHistorySamplers(state, sourceTexture);
|
|
||||||
bindLayerTextureAssets(layerProgram);
|
|
||||||
glBindVertexArray(mRenderer->mFullscreenVAO);
|
|
||||||
glUseProgram(layerProgram.program);
|
|
||||||
updateGlobalParamsBuffer(state, sourceHistoryAvailableCount(), temporalHistoryAvailableCountForLayer(state.layerId));
|
|
||||||
glDrawArrays(GL_TRIANGLES, 0, 3);
|
|
||||||
glUseProgram(0);
|
|
||||||
glBindVertexArray(0);
|
|
||||||
const unsigned historyCap = mRuntimeHost ? mRuntimeHost->GetMaxTemporalHistoryFrames() : 0;
|
const unsigned historyCap = mRuntimeHost ? mRuntimeHost->GetMaxTemporalHistoryFrames() : 0;
|
||||||
for (unsigned index = 0; index < historyCap; ++index)
|
mRenderPass->Render(
|
||||||
{
|
hasInputSource,
|
||||||
glActiveTexture(GL_TEXTURE0 + kSourceHistoryTextureUnitBase + index);
|
layerStates,
|
||||||
glBindTexture(GL_TEXTURE_2D, 0);
|
mInputFrameWidth,
|
||||||
glActiveTexture(GL_TEXTURE0 + kSourceHistoryTextureUnitBase + historyCap + index);
|
mInputFrameHeight,
|
||||||
glBindTexture(GL_TEXTURE_2D, 0);
|
historyCap,
|
||||||
}
|
[this](const RuntimeRenderState& state, LayerProgram::TextBinding& textBinding, std::string& error) {
|
||||||
const GLuint shaderTextureBase = layerProgram.shaderTextureBase != 0 ? layerProgram.shaderTextureBase : kSourceHistoryTextureUnitBase;
|
return mShaderPrograms->UpdateTextBindingTexture(state, textBinding, error);
|
||||||
for (std::size_t index = 0; index < layerProgram.textureBindings.size() + layerProgram.textBindings.size(); ++index)
|
},
|
||||||
{
|
[this](const RuntimeRenderState& state, unsigned availableSourceHistoryLength, unsigned availableTemporalHistoryLength) {
|
||||||
glActiveTexture(GL_TEXTURE0 + shaderTextureBase + static_cast<GLuint>(index));
|
return mShaderPrograms->UpdateGlobalParamsBuffer(state, availableSourceHistoryLength, availableTemporalHistoryLength);
|
||||||
glBindTexture(GL_TEXTURE_2D, 0);
|
});
|
||||||
}
|
|
||||||
glActiveTexture(GL_TEXTURE0 + kDecodedVideoTextureUnit);
|
|
||||||
glBindTexture(GL_TEXTURE_2D, 0);
|
|
||||||
glActiveTexture(GL_TEXTURE0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void OpenGLComposite::renderDecodePass()
|
|
||||||
{
|
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, mRenderer->mDecodeFrameBuf);
|
|
||||||
glViewport(0, 0, mInputFrameWidth, mInputFrameHeight);
|
|
||||||
glClear(GL_COLOR_BUFFER_BIT);
|
|
||||||
glActiveTexture(GL_TEXTURE0 + kPackedVideoTextureUnit);
|
|
||||||
glBindTexture(GL_TEXTURE_2D, mRenderer->mCaptureTexture);
|
|
||||||
glBindVertexArray(mRenderer->mFullscreenVAO);
|
|
||||||
glUseProgram(mRenderer->mDecodeProgram);
|
|
||||||
|
|
||||||
const GLint packedResolutionLocation = glGetUniformLocation(mRenderer->mDecodeProgram, "uPackedVideoResolution");
|
|
||||||
const GLint decodedResolutionLocation = glGetUniformLocation(mRenderer->mDecodeProgram, "uDecodedVideoResolution");
|
|
||||||
if (packedResolutionLocation >= 0)
|
|
||||||
glUniform2f(packedResolutionLocation, static_cast<float>(mInputFrameWidth / 2), static_cast<float>(mInputFrameHeight));
|
|
||||||
if (decodedResolutionLocation >= 0)
|
|
||||||
glUniform2f(decodedResolutionLocation, static_cast<float>(mInputFrameWidth), static_cast<float>(mInputFrameHeight));
|
|
||||||
|
|
||||||
glDrawArrays(GL_TRIANGLES, 0, 3);
|
|
||||||
|
|
||||||
glUseProgram(0);
|
|
||||||
glBindVertexArray(0);
|
|
||||||
glBindTexture(GL_TEXTURE_2D, 0);
|
|
||||||
glActiveTexture(GL_TEXTURE0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OpenGLComposite::PollRuntimeChanges()
|
bool OpenGLComposite::PollRuntimeChanges()
|
||||||
@@ -1439,7 +964,7 @@ bool OpenGLComposite::PollRuntimeChanges()
|
|||||||
return true;
|
return true;
|
||||||
|
|
||||||
char compilerErrorMessage[1024] = {};
|
char compilerErrorMessage[1024] = {};
|
||||||
if (!compileLayerPrograms(sizeof(compilerErrorMessage), compilerErrorMessage))
|
if (!mShaderPrograms->CompileLayerPrograms(mInputFrameWidth, mInputFrameHeight, sizeof(compilerErrorMessage), compilerErrorMessage))
|
||||||
{
|
{
|
||||||
mRuntimeHost->SetCompileStatus(false, compilerErrorMessage);
|
mRuntimeHost->SetCompileStatus(false, compilerErrorMessage);
|
||||||
mRuntimeHost->ClearReloadRequest();
|
mRuntimeHost->ClearReloadRequest();
|
||||||
@@ -1447,7 +972,7 @@ bool OpenGLComposite::PollRuntimeChanges()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
resetTemporalHistoryState();
|
mShaderPrograms->ResetTemporalHistoryState();
|
||||||
broadcastRuntimeState();
|
broadcastRuntimeState();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -1458,88 +983,9 @@ void OpenGLComposite::broadcastRuntimeState()
|
|||||||
mControlServer->BroadcastState();
|
mControlServer->BroadcastState();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OpenGLComposite::updateGlobalParamsBuffer(const RuntimeRenderState& state, unsigned availableSourceHistoryLength, unsigned availableTemporalHistoryLength)
|
void OpenGLComposite::resetTemporalHistoryState()
|
||||||
{
|
{
|
||||||
std::vector<unsigned char> buffer;
|
mShaderPrograms->ResetTemporalHistoryState();
|
||||||
buffer.reserve(512);
|
|
||||||
|
|
||||||
AppendStd140Float(buffer, static_cast<float>(state.timeSeconds));
|
|
||||||
AppendStd140Vec2(buffer, static_cast<float>(state.inputWidth), static_cast<float>(state.inputHeight));
|
|
||||||
AppendStd140Vec2(buffer, static_cast<float>(state.outputWidth), static_cast<float>(state.outputHeight));
|
|
||||||
AppendStd140Float(buffer, static_cast<float>(state.frameCount));
|
|
||||||
AppendStd140Float(buffer, static_cast<float>(state.mixAmount));
|
|
||||||
AppendStd140Float(buffer, static_cast<float>(state.bypass));
|
|
||||||
const unsigned effectiveSourceHistoryLength = availableSourceHistoryLength < state.effectiveTemporalHistoryLength
|
|
||||||
? availableSourceHistoryLength
|
|
||||||
: state.effectiveTemporalHistoryLength;
|
|
||||||
const unsigned effectiveTemporalHistoryLength = (state.temporalHistorySource == TemporalHistorySource::PreLayerInput)
|
|
||||||
? (availableTemporalHistoryLength < state.effectiveTemporalHistoryLength ? availableTemporalHistoryLength : state.effectiveTemporalHistoryLength)
|
|
||||||
: 0u;
|
|
||||||
AppendStd140Int(buffer, static_cast<int>(effectiveSourceHistoryLength));
|
|
||||||
AppendStd140Int(buffer, static_cast<int>(effectiveTemporalHistoryLength));
|
|
||||||
|
|
||||||
for (const ShaderParameterDefinition& definition : state.parameterDefinitions)
|
|
||||||
{
|
|
||||||
auto valueIt = state.parameterValues.find(definition.id);
|
|
||||||
const ShaderParameterValue value = valueIt != state.parameterValues.end()
|
|
||||||
? valueIt->second
|
|
||||||
: ShaderParameterValue();
|
|
||||||
|
|
||||||
switch (definition.type)
|
|
||||||
{
|
|
||||||
case ShaderParameterType::Float:
|
|
||||||
AppendStd140Float(buffer, value.numberValues.empty() ? 0.0f : static_cast<float>(value.numberValues[0]));
|
|
||||||
break;
|
|
||||||
case ShaderParameterType::Vec2:
|
|
||||||
AppendStd140Vec2(buffer,
|
|
||||||
value.numberValues.size() > 0 ? static_cast<float>(value.numberValues[0]) : 0.0f,
|
|
||||||
value.numberValues.size() > 1 ? static_cast<float>(value.numberValues[1]) : 0.0f);
|
|
||||||
break;
|
|
||||||
case ShaderParameterType::Color:
|
|
||||||
AppendStd140Vec4(buffer,
|
|
||||||
value.numberValues.size() > 0 ? static_cast<float>(value.numberValues[0]) : 1.0f,
|
|
||||||
value.numberValues.size() > 1 ? static_cast<float>(value.numberValues[1]) : 1.0f,
|
|
||||||
value.numberValues.size() > 2 ? static_cast<float>(value.numberValues[2]) : 1.0f,
|
|
||||||
value.numberValues.size() > 3 ? static_cast<float>(value.numberValues[3]) : 1.0f);
|
|
||||||
break;
|
|
||||||
case ShaderParameterType::Boolean:
|
|
||||||
AppendStd140Int(buffer, value.booleanValue ? 1 : 0);
|
|
||||||
break;
|
|
||||||
case ShaderParameterType::Enum:
|
|
||||||
{
|
|
||||||
int selectedIndex = 0;
|
|
||||||
for (std::size_t optionIndex = 0; optionIndex < definition.enumOptions.size(); ++optionIndex)
|
|
||||||
{
|
|
||||||
if (definition.enumOptions[optionIndex].value == value.enumValue)
|
|
||||||
{
|
|
||||||
selectedIndex = static_cast<int>(optionIndex);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
AppendStd140Int(buffer, selectedIndex);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case ShaderParameterType::Text:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
buffer.resize(AlignStd140(buffer.size(), 16), 0);
|
|
||||||
|
|
||||||
glBindBuffer(GL_UNIFORM_BUFFER, mRenderer->mGlobalParamsUBO);
|
|
||||||
if (mRenderer->mGlobalParamsUBOSize != static_cast<GLsizeiptr>(buffer.size()))
|
|
||||||
{
|
|
||||||
glBufferData(GL_UNIFORM_BUFFER, static_cast<GLsizeiptr>(buffer.size()), buffer.data(), GL_DYNAMIC_DRAW);
|
|
||||||
mRenderer->mGlobalParamsUBOSize = static_cast<GLsizeiptr>(buffer.size());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
glBufferSubData(GL_UNIFORM_BUFFER, 0, static_cast<GLsizeiptr>(buffer.size()), buffer.data());
|
|
||||||
}
|
|
||||||
glBindBufferBase(GL_UNIFORM_BUFFER, kGlobalParamsBindingPoint, mRenderer->mGlobalParamsUBO);
|
|
||||||
glBindBuffer(GL_UNIFORM_BUFFER, 0);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OpenGLComposite::CheckOpenGLExtensions()
|
bool OpenGLComposite::CheckOpenGLExtensions()
|
||||||
|
|||||||
@@ -68,6 +68,8 @@ class CaptureDelegate;
|
|||||||
class PinnedMemoryAllocator;
|
class PinnedMemoryAllocator;
|
||||||
class ControlServer;
|
class ControlServer;
|
||||||
class OscServer;
|
class OscServer;
|
||||||
|
class OpenGLRenderPass;
|
||||||
|
class OpenGLShaderPrograms;
|
||||||
|
|
||||||
|
|
||||||
class OpenGLComposite
|
class OpenGLComposite
|
||||||
@@ -136,31 +138,16 @@ private:
|
|||||||
|
|
||||||
std::unique_ptr<OpenGLRenderer> mRenderer;
|
std::unique_ptr<OpenGLRenderer> mRenderer;
|
||||||
std::unique_ptr<RuntimeHost> mRuntimeHost;
|
std::unique_ptr<RuntimeHost> mRuntimeHost;
|
||||||
|
std::unique_ptr<OpenGLRenderPass> mRenderPass;
|
||||||
|
std::unique_ptr<OpenGLShaderPrograms> mShaderPrograms;
|
||||||
std::unique_ptr<ControlServer> mControlServer;
|
std::unique_ptr<ControlServer> mControlServer;
|
||||||
std::unique_ptr<OscServer> mOscServer;
|
std::unique_ptr<OscServer> mOscServer;
|
||||||
|
|
||||||
bool InitOpenGLState();
|
bool InitOpenGLState();
|
||||||
bool compileLayerPrograms(int errorMessageSize, char* errorMessage);
|
|
||||||
bool compileSingleLayerProgram(const RuntimeRenderState& state, LayerProgram& layerProgram, int errorMessageSize, char* errorMessage);
|
|
||||||
bool compileDecodeShader(int errorMessageSize, char* errorMessage);
|
|
||||||
void destroyLayerPrograms();
|
|
||||||
void destroySingleLayerProgram(LayerProgram& layerProgram);
|
|
||||||
void destroyDecodeShaderProgram();
|
|
||||||
void renderDecodePass();
|
|
||||||
void renderShaderProgram(GLuint sourceTexture, GLuint destinationFrameBuffer, LayerProgram& layerProgram, const RuntimeRenderState& state);
|
|
||||||
bool loadTextureAsset(const ShaderTextureAsset& textureAsset, GLuint& textureId, std::string& error);
|
|
||||||
bool renderTextBindingTexture(const RuntimeRenderState& state, LayerProgram::TextBinding& textBinding, std::string& error);
|
|
||||||
void bindLayerTextureAssets(const LayerProgram& layerProgram);
|
|
||||||
void renderEffect();
|
void renderEffect();
|
||||||
bool PollRuntimeChanges();
|
bool PollRuntimeChanges();
|
||||||
void broadcastRuntimeState();
|
void broadcastRuntimeState();
|
||||||
bool updateGlobalParamsBuffer(const RuntimeRenderState& state, unsigned availableSourceHistoryLength, unsigned availableTemporalHistoryLength);
|
|
||||||
bool validateTemporalTextureUnitBudget(const std::vector<RuntimeRenderState>& layerStates, std::string& error) const;
|
|
||||||
bool ensureTemporalHistoryResources(const std::vector<RuntimeRenderState>& layerStates, std::string& error);
|
|
||||||
void resetTemporalHistoryState();
|
void resetTemporalHistoryState();
|
||||||
void bindHistorySamplers(const RuntimeRenderState& state, GLuint currentSourceTexture);
|
|
||||||
unsigned sourceHistoryAvailableCount() const;
|
|
||||||
unsigned temporalHistoryAvailableCountForLayer(const std::string& layerId) const;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // __OPENGL_COMPOSITE_H__
|
#endif // __OPENGL_COMPOSITE_H__
|
||||||
|
|||||||
172
apps/LoopThroughWithOpenGLCompositing/gl/OpenGLRenderPass.cpp
Normal file
172
apps/LoopThroughWithOpenGLCompositing/gl/OpenGLRenderPass.cpp
Normal file
@@ -0,0 +1,172 @@
|
|||||||
|
#include "OpenGLRenderPass.h"
|
||||||
|
|
||||||
|
#include "GlRenderConstants.h"
|
||||||
|
#include "VideoFrameTransfer.h"
|
||||||
|
|
||||||
|
OpenGLRenderPass::OpenGLRenderPass(OpenGLRenderer& renderer) :
|
||||||
|
mRenderer(renderer)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLRenderPass::Render(
|
||||||
|
bool hasInputSource,
|
||||||
|
const std::vector<RuntimeRenderState>& layerStates,
|
||||||
|
unsigned inputFrameWidth,
|
||||||
|
unsigned inputFrameHeight,
|
||||||
|
unsigned historyCap,
|
||||||
|
const TextBindingUpdater& updateTextBinding,
|
||||||
|
const GlobalParamsUpdater& updateGlobalParams)
|
||||||
|
{
|
||||||
|
if (hasInputSource && mRenderer.mFastTransferExtensionAvailable)
|
||||||
|
{
|
||||||
|
// Signal that we're about to draw using mCaptureTexture onto mFBOTexture.
|
||||||
|
VideoFrameTransfer::beginTextureInUse(VideoFrameTransfer::CPUtoGPU);
|
||||||
|
}
|
||||||
|
|
||||||
|
glDisable(GL_BLEND);
|
||||||
|
glDisable(GL_DEPTH_TEST);
|
||||||
|
if (hasInputSource)
|
||||||
|
{
|
||||||
|
RenderDecodePass(inputFrameWidth, inputFrameHeight);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, mRenderer.mDecodeFrameBuf);
|
||||||
|
glViewport(0, 0, inputFrameWidth, inputFrameHeight);
|
||||||
|
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (layerStates.empty() || mRenderer.mLayerPrograms.empty())
|
||||||
|
{
|
||||||
|
glBindFramebuffer(GL_READ_FRAMEBUFFER, mRenderer.mDecodeFrameBuf);
|
||||||
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mRenderer.mIdFrameBuf);
|
||||||
|
glBlitFramebuffer(0, 0, inputFrameWidth, inputFrameHeight, 0, 0, inputFrameWidth, inputFrameHeight, GL_COLOR_BUFFER_BIT, GL_LINEAR);
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, mRenderer.mIdFrameBuf);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GLuint sourceTexture = mRenderer.mDecodedTexture;
|
||||||
|
GLuint sourceFrameBuffer = mRenderer.mDecodeFrameBuf;
|
||||||
|
for (std::size_t index = 0; index < layerStates.size() && index < mRenderer.mLayerPrograms.size(); ++index)
|
||||||
|
{
|
||||||
|
const std::size_t remaining = layerStates.size() - index;
|
||||||
|
const bool writeToMain = (remaining % 2) == 1;
|
||||||
|
RenderShaderProgram(
|
||||||
|
sourceTexture,
|
||||||
|
writeToMain ? mRenderer.mIdFrameBuf : mRenderer.mLayerTempFrameBuf,
|
||||||
|
mRenderer.mLayerPrograms[index],
|
||||||
|
layerStates[index],
|
||||||
|
inputFrameWidth,
|
||||||
|
inputFrameHeight,
|
||||||
|
historyCap,
|
||||||
|
updateTextBinding,
|
||||||
|
updateGlobalParams);
|
||||||
|
if (layerStates[index].temporalHistorySource == TemporalHistorySource::PreLayerInput)
|
||||||
|
mRenderer.mTemporalHistory.PushPreLayerFramebuffer(layerStates[index].layerId, sourceFrameBuffer, inputFrameWidth, inputFrameHeight);
|
||||||
|
sourceTexture = writeToMain ? mRenderer.mFBOTexture : mRenderer.mLayerTempTexture;
|
||||||
|
sourceFrameBuffer = writeToMain ? mRenderer.mIdFrameBuf : mRenderer.mLayerTempFrameBuf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mRenderer.mTemporalHistory.PushSourceFramebuffer(mRenderer.mDecodeFrameBuf, inputFrameWidth, inputFrameHeight);
|
||||||
|
|
||||||
|
if (hasInputSource && mRenderer.mFastTransferExtensionAvailable)
|
||||||
|
VideoFrameTransfer::endTextureInUse(VideoFrameTransfer::CPUtoGPU);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLRenderPass::RenderDecodePass(unsigned inputFrameWidth, unsigned inputFrameHeight)
|
||||||
|
{
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, mRenderer.mDecodeFrameBuf);
|
||||||
|
glViewport(0, 0, inputFrameWidth, inputFrameHeight);
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
|
glActiveTexture(GL_TEXTURE0 + kPackedVideoTextureUnit);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, mRenderer.mCaptureTexture);
|
||||||
|
glBindVertexArray(mRenderer.mFullscreenVAO);
|
||||||
|
glUseProgram(mRenderer.mDecodeProgram);
|
||||||
|
|
||||||
|
const GLint packedResolutionLocation = glGetUniformLocation(mRenderer.mDecodeProgram, "uPackedVideoResolution");
|
||||||
|
const GLint decodedResolutionLocation = glGetUniformLocation(mRenderer.mDecodeProgram, "uDecodedVideoResolution");
|
||||||
|
if (packedResolutionLocation >= 0)
|
||||||
|
glUniform2f(packedResolutionLocation, static_cast<float>(inputFrameWidth / 2), static_cast<float>(inputFrameHeight));
|
||||||
|
if (decodedResolutionLocation >= 0)
|
||||||
|
glUniform2f(decodedResolutionLocation, static_cast<float>(inputFrameWidth), static_cast<float>(inputFrameHeight));
|
||||||
|
|
||||||
|
glDrawArrays(GL_TRIANGLES, 0, 3);
|
||||||
|
|
||||||
|
glUseProgram(0);
|
||||||
|
glBindVertexArray(0);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLRenderPass::RenderShaderProgram(
|
||||||
|
GLuint sourceTexture,
|
||||||
|
GLuint destinationFrameBuffer,
|
||||||
|
LayerProgram& layerProgram,
|
||||||
|
const RuntimeRenderState& state,
|
||||||
|
unsigned inputFrameWidth,
|
||||||
|
unsigned inputFrameHeight,
|
||||||
|
unsigned historyCap,
|
||||||
|
const TextBindingUpdater& updateTextBinding,
|
||||||
|
const GlobalParamsUpdater& updateGlobalParams)
|
||||||
|
{
|
||||||
|
for (LayerProgram::TextBinding& textBinding : layerProgram.textBindings)
|
||||||
|
{
|
||||||
|
std::string textError;
|
||||||
|
if (!updateTextBinding(state, textBinding, textError))
|
||||||
|
OutputDebugStringA((textError + "\n").c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, destinationFrameBuffer);
|
||||||
|
glViewport(0, 0, inputFrameWidth, inputFrameHeight);
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||||
|
glActiveTexture(GL_TEXTURE0 + kDecodedVideoTextureUnit);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, sourceTexture);
|
||||||
|
mRenderer.mTemporalHistory.BindSamplers(state, sourceTexture, historyCap);
|
||||||
|
BindLayerTextureAssets(layerProgram);
|
||||||
|
glBindVertexArray(mRenderer.mFullscreenVAO);
|
||||||
|
glUseProgram(layerProgram.program);
|
||||||
|
updateGlobalParams(state, mRenderer.mTemporalHistory.SourceAvailableCount(), mRenderer.mTemporalHistory.AvailableCountForLayer(state.layerId));
|
||||||
|
glDrawArrays(GL_TRIANGLES, 0, 3);
|
||||||
|
glUseProgram(0);
|
||||||
|
glBindVertexArray(0);
|
||||||
|
UnbindLayerTextureAssets(layerProgram, historyCap);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLRenderPass::BindLayerTextureAssets(const LayerProgram& layerProgram)
|
||||||
|
{
|
||||||
|
const GLuint shaderTextureBase = layerProgram.shaderTextureBase != 0 ? layerProgram.shaderTextureBase : kSourceHistoryTextureUnitBase;
|
||||||
|
for (std::size_t index = 0; index < layerProgram.textureBindings.size(); ++index)
|
||||||
|
{
|
||||||
|
glActiveTexture(GL_TEXTURE0 + shaderTextureBase + static_cast<GLuint>(index));
|
||||||
|
glBindTexture(GL_TEXTURE_2D, layerProgram.textureBindings[index].texture);
|
||||||
|
}
|
||||||
|
const GLuint textTextureBase = shaderTextureBase + static_cast<GLuint>(layerProgram.textureBindings.size());
|
||||||
|
for (std::size_t index = 0; index < layerProgram.textBindings.size(); ++index)
|
||||||
|
{
|
||||||
|
glActiveTexture(GL_TEXTURE0 + textTextureBase + static_cast<GLuint>(index));
|
||||||
|
glBindTexture(GL_TEXTURE_2D, layerProgram.textBindings[index].texture);
|
||||||
|
}
|
||||||
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLRenderPass::UnbindLayerTextureAssets(const LayerProgram& layerProgram, unsigned historyCap)
|
||||||
|
{
|
||||||
|
for (unsigned index = 0; index < historyCap; ++index)
|
||||||
|
{
|
||||||
|
glActiveTexture(GL_TEXTURE0 + kSourceHistoryTextureUnitBase + index);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
glActiveTexture(GL_TEXTURE0 + kSourceHistoryTextureUnitBase + historyCap + index);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
}
|
||||||
|
const GLuint shaderTextureBase = layerProgram.shaderTextureBase != 0 ? layerProgram.shaderTextureBase : kSourceHistoryTextureUnitBase;
|
||||||
|
for (std::size_t index = 0; index < layerProgram.textureBindings.size() + layerProgram.textBindings.size(); ++index)
|
||||||
|
{
|
||||||
|
glActiveTexture(GL_TEXTURE0 + shaderTextureBase + static_cast<GLuint>(index));
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
}
|
||||||
|
glActiveTexture(GL_TEXTURE0 + kDecodedVideoTextureUnit);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
}
|
||||||
44
apps/LoopThroughWithOpenGLCompositing/gl/OpenGLRenderPass.h
Normal file
44
apps/LoopThroughWithOpenGLCompositing/gl/OpenGLRenderPass.h
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "OpenGLRenderer.h"
|
||||||
|
#include "ShaderTypes.h"
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
class OpenGLRenderPass
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using LayerProgram = OpenGLRenderer::LayerProgram;
|
||||||
|
using TextBindingUpdater = std::function<bool(const RuntimeRenderState&, LayerProgram::TextBinding&, std::string&)>;
|
||||||
|
using GlobalParamsUpdater = std::function<bool(const RuntimeRenderState&, unsigned, unsigned)>;
|
||||||
|
|
||||||
|
explicit OpenGLRenderPass(OpenGLRenderer& renderer);
|
||||||
|
|
||||||
|
void Render(
|
||||||
|
bool hasInputSource,
|
||||||
|
const std::vector<RuntimeRenderState>& layerStates,
|
||||||
|
unsigned inputFrameWidth,
|
||||||
|
unsigned inputFrameHeight,
|
||||||
|
unsigned historyCap,
|
||||||
|
const TextBindingUpdater& updateTextBinding,
|
||||||
|
const GlobalParamsUpdater& updateGlobalParams);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void RenderDecodePass(unsigned inputFrameWidth, unsigned inputFrameHeight);
|
||||||
|
void RenderShaderProgram(
|
||||||
|
GLuint sourceTexture,
|
||||||
|
GLuint destinationFrameBuffer,
|
||||||
|
LayerProgram& layerProgram,
|
||||||
|
const RuntimeRenderState& state,
|
||||||
|
unsigned inputFrameWidth,
|
||||||
|
unsigned inputFrameHeight,
|
||||||
|
unsigned historyCap,
|
||||||
|
const TextBindingUpdater& updateTextBinding,
|
||||||
|
const GlobalParamsUpdater& updateGlobalParams);
|
||||||
|
void BindLayerTextureAssets(const LayerProgram& layerProgram);
|
||||||
|
void UnbindLayerTextureAssets(const LayerProgram& layerProgram, unsigned historyCap);
|
||||||
|
|
||||||
|
OpenGLRenderer& mRenderer;
|
||||||
|
};
|
||||||
@@ -0,0 +1,427 @@
|
|||||||
|
#include "OpenGLShaderPrograms.h"
|
||||||
|
|
||||||
|
#include "GlRenderConstants.h"
|
||||||
|
#include "GlScopedObjects.h"
|
||||||
|
#include "GlShaderSources.h"
|
||||||
|
#include "Std140Buffer.h"
|
||||||
|
#include "TextRasterizer.h"
|
||||||
|
#include "TextureAssetLoader.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <cstring>
|
||||||
|
#include <filesystem>
|
||||||
|
#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::string TextValueForBinding(const RuntimeRenderState& state, const std::string& parameterId)
|
||||||
|
{
|
||||||
|
auto valueIt = state.parameterValues.find(parameterId);
|
||||||
|
return valueIt == state.parameterValues.end() ? std::string() : valueIt->second.textValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ShaderFontAsset* FindFontAssetForParameter(const RuntimeRenderState& state, const ShaderParameterDefinition& definition)
|
||||||
|
{
|
||||||
|
if (!definition.fontId.empty())
|
||||||
|
{
|
||||||
|
for (const ShaderFontAsset& fontAsset : state.fontAssets)
|
||||||
|
{
|
||||||
|
if (fontAsset.id == definition.fontId)
|
||||||
|
return &fontAsset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return state.fontAssets.empty() ? nullptr : &state.fontAssets.front();
|
||||||
|
}
|
||||||
|
|
||||||
|
GLint FindSamplerUniformLocation(GLuint program, const std::string& samplerName)
|
||||||
|
{
|
||||||
|
GLint location = glGetUniformLocation(program, samplerName.c_str());
|
||||||
|
if (location >= 0)
|
||||||
|
return location;
|
||||||
|
return glGetUniformLocation(program, (samplerName + "_0").c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
OpenGLShaderPrograms::OpenGLShaderPrograms(OpenGLRenderer& renderer, RuntimeHost& runtimeHost) :
|
||||||
|
mRenderer(renderer),
|
||||||
|
mRuntimeHost(runtimeHost)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
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.mTemporalHistory.ValidateTextureUnitBudget(layerStates, historyCap, temporalError))
|
||||||
|
{
|
||||||
|
CopyErrorMessage(temporalError, errorMessageSize, errorMessage);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!mRenderer.mTemporalHistory.EnsureResources(layerStates, historyCap, inputFrameWidth, inputFrameHeight, temporalError))
|
||||||
|
{
|
||||||
|
CopyErrorMessage(temporalError, errorMessageSize, errorMessage);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<LayerProgram> newPrograms;
|
||||||
|
newPrograms.reserve(layerStates.size());
|
||||||
|
|
||||||
|
for (const RuntimeRenderState& state : layerStates)
|
||||||
|
{
|
||||||
|
LayerProgram layerProgram;
|
||||||
|
if (!CompileSingleLayerProgram(state, layerProgram, errorMessageSize, errorMessage))
|
||||||
|
{
|
||||||
|
for (LayerProgram& program : newPrograms)
|
||||||
|
DestroySingleLayerProgram(program);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
newPrograms.push_back(layerProgram);
|
||||||
|
}
|
||||||
|
|
||||||
|
DestroyLayerPrograms();
|
||||||
|
mRenderer.mLayerPrograms.swap(newPrograms);
|
||||||
|
|
||||||
|
mRuntimeHost.SetCompileStatus(true, "Shader layers compiled successfully.");
|
||||||
|
mRuntimeHost.ClearReloadRequest();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OpenGLShaderPrograms::CompileSingleLayerProgram(const RuntimeRenderState& state, LayerProgram& layerProgram, int errorMessageSize, char* errorMessage)
|
||||||
|
{
|
||||||
|
GLsizei errorBufferSize = 0;
|
||||||
|
GLint compileResult = GL_FALSE;
|
||||||
|
GLint linkResult = GL_FALSE;
|
||||||
|
std::string fragmentShaderSource;
|
||||||
|
std::string loadError;
|
||||||
|
std::vector<LayerProgram::TextureBinding> textureBindings;
|
||||||
|
const char* vertexSource = kFullscreenTriangleVertexShaderSource;
|
||||||
|
|
||||||
|
if (!mRuntimeHost.BuildLayerFragmentShaderSource(state.layerId, fragmentShaderSource, loadError))
|
||||||
|
{
|
||||||
|
CopyErrorMessage(loadError, errorMessageSize, errorMessage);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* fragmentSource = 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);
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const ShaderTextureAsset& textureAsset : state.textureAssets)
|
||||||
|
{
|
||||||
|
LayerProgram::TextureBinding textureBinding;
|
||||||
|
textureBinding.samplerName = textureAsset.id;
|
||||||
|
textureBinding.sourcePath = textureAsset.path;
|
||||||
|
if (!LoadTextureAsset(textureAsset, textureBinding.texture, loadError))
|
||||||
|
{
|
||||||
|
for (LayerProgram::TextureBinding& loadedTexture : textureBindings)
|
||||||
|
{
|
||||||
|
if (loadedTexture.texture != 0)
|
||||||
|
glDeleteTextures(1, &loadedTexture.texture);
|
||||||
|
}
|
||||||
|
CopyErrorMessage(loadError, errorMessageSize, errorMessage);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
textureBindings.push_back(textureBinding);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<LayerProgram::TextBinding> textBindings;
|
||||||
|
for (const ShaderParameterDefinition& definition : state.parameterDefinitions)
|
||||||
|
{
|
||||||
|
if (definition.type != ShaderParameterType::Text)
|
||||||
|
continue;
|
||||||
|
LayerProgram::TextBinding textBinding;
|
||||||
|
textBinding.parameterId = definition.id;
|
||||||
|
textBinding.samplerName = definition.id + "Texture";
|
||||||
|
textBinding.fontId = definition.fontId;
|
||||||
|
glGenTextures(1, &textBinding.texture);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, textBinding.texture);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||||
|
std::vector<unsigned char> empty(static_cast<std::size_t>(kTextTextureWidth) * kTextTextureHeight * 4, 0);
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, kTextTextureWidth, kTextTextureHeight, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, empty.data());
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
textBindings.push_back(textBinding);
|
||||||
|
}
|
||||||
|
|
||||||
|
const GLuint globalParamsIndex = glGetUniformBlockIndex(newProgram.get(), "GlobalParams");
|
||||||
|
if (globalParamsIndex != GL_INVALID_INDEX)
|
||||||
|
glUniformBlockBinding(newProgram.get(), globalParamsIndex, kGlobalParamsBindingPoint);
|
||||||
|
|
||||||
|
const unsigned historyCap = mRuntimeHost.GetMaxTemporalHistoryFrames();
|
||||||
|
const GLuint shaderTextureBase = state.isTemporal ? kSourceHistoryTextureUnitBase + historyCap + historyCap : kSourceHistoryTextureUnitBase;
|
||||||
|
glUseProgram(newProgram.get());
|
||||||
|
const GLint videoInputLocation = glGetUniformLocation(newProgram.get(), "gVideoInput");
|
||||||
|
if (videoInputLocation >= 0)
|
||||||
|
glUniform1i(videoInputLocation, static_cast<GLint>(kDecodedVideoTextureUnit));
|
||||||
|
for (unsigned index = 0; index < historyCap; ++index)
|
||||||
|
{
|
||||||
|
const std::string sourceSamplerName = "gSourceHistory" + std::to_string(index);
|
||||||
|
const GLint sourceSamplerLocation = glGetUniformLocation(newProgram.get(), sourceSamplerName.c_str());
|
||||||
|
if (sourceSamplerLocation >= 0)
|
||||||
|
glUniform1i(sourceSamplerLocation, static_cast<GLint>(kSourceHistoryTextureUnitBase + index));
|
||||||
|
|
||||||
|
const std::string temporalSamplerName = "gTemporalHistory" + std::to_string(index);
|
||||||
|
const GLint temporalSamplerLocation = glGetUniformLocation(newProgram.get(), temporalSamplerName.c_str());
|
||||||
|
if (temporalSamplerLocation >= 0)
|
||||||
|
glUniform1i(temporalSamplerLocation, static_cast<GLint>(kSourceHistoryTextureUnitBase + historyCap + index));
|
||||||
|
}
|
||||||
|
for (std::size_t index = 0; index < textureBindings.size(); ++index)
|
||||||
|
{
|
||||||
|
const GLint textureSamplerLocation = FindSamplerUniformLocation(newProgram.get(), textureBindings[index].samplerName);
|
||||||
|
if (textureSamplerLocation >= 0)
|
||||||
|
glUniform1i(textureSamplerLocation, static_cast<GLint>(shaderTextureBase + static_cast<GLuint>(index)));
|
||||||
|
}
|
||||||
|
const GLuint textTextureBase = shaderTextureBase + static_cast<GLuint>(textureBindings.size());
|
||||||
|
for (std::size_t index = 0; index < textBindings.size(); ++index)
|
||||||
|
{
|
||||||
|
const GLint textSamplerLocation = FindSamplerUniformLocation(newProgram.get(), textBindings[index].samplerName);
|
||||||
|
if (textSamplerLocation >= 0)
|
||||||
|
glUniform1i(textSamplerLocation, static_cast<GLint>(textTextureBase + static_cast<GLuint>(index)));
|
||||||
|
}
|
||||||
|
glUseProgram(0);
|
||||||
|
|
||||||
|
layerProgram.layerId = state.layerId;
|
||||||
|
layerProgram.shaderId = state.shaderId;
|
||||||
|
layerProgram.shaderTextureBase = shaderTextureBase;
|
||||||
|
layerProgram.program = newProgram.release();
|
||||||
|
layerProgram.vertexShader = newVertexShader.release();
|
||||||
|
layerProgram.fragmentShader = newFragmentShader.release();
|
||||||
|
layerProgram.textureBindings.swap(textureBindings);
|
||||||
|
layerProgram.textBindings.swap(textBindings);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OpenGLShaderPrograms::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;
|
||||||
|
}
|
||||||
|
|
||||||
|
DestroyDecodeShaderProgram();
|
||||||
|
mRenderer.mDecodeProgram = newProgram.release();
|
||||||
|
mRenderer.mDecodeVertexShader = newVertexShader.release();
|
||||||
|
mRenderer.mDecodeFragmentShader = newFragmentShader.release();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLShaderPrograms::DestroySingleLayerProgram(LayerProgram& layerProgram)
|
||||||
|
{
|
||||||
|
mRenderer.DestroySingleLayerProgram(layerProgram);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLShaderPrograms::DestroyLayerPrograms()
|
||||||
|
{
|
||||||
|
mRenderer.DestroyLayerPrograms();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLShaderPrograms::DestroyDecodeShaderProgram()
|
||||||
|
{
|
||||||
|
mRenderer.DestroyDecodeShaderProgram();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLShaderPrograms::ResetTemporalHistoryState()
|
||||||
|
{
|
||||||
|
mRenderer.mTemporalHistory.ResetState();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OpenGLShaderPrograms::LoadTextureAsset(const ShaderTextureAsset& textureAsset, GLuint& textureId, std::string& error)
|
||||||
|
{
|
||||||
|
return ::LoadTextureAsset(textureAsset, textureId, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OpenGLShaderPrograms::UpdateTextBindingTexture(const RuntimeRenderState& state, LayerProgram::TextBinding& textBinding, std::string& error)
|
||||||
|
{
|
||||||
|
const std::string text = TextValueForBinding(state, textBinding.parameterId);
|
||||||
|
if (text == textBinding.renderedText && textBinding.renderedWidth == kTextTextureWidth && textBinding.renderedHeight == kTextTextureHeight)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
auto definitionIt = std::find_if(state.parameterDefinitions.begin(), state.parameterDefinitions.end(),
|
||||||
|
[&textBinding](const ShaderParameterDefinition& definition) { return definition.id == textBinding.parameterId; });
|
||||||
|
if (definitionIt == state.parameterDefinitions.end())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
const ShaderFontAsset* fontAsset = FindFontAssetForParameter(state, *definitionIt);
|
||||||
|
std::filesystem::path fontPath;
|
||||||
|
if (fontAsset)
|
||||||
|
fontPath = fontAsset->path;
|
||||||
|
|
||||||
|
std::vector<unsigned char> sdf;
|
||||||
|
if (!RasterizeTextSdf(text, fontPath, sdf, error))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
GLint previousActiveTexture = 0;
|
||||||
|
GLint previousUnpackBuffer = 0;
|
||||||
|
glGetIntegerv(GL_ACTIVE_TEXTURE, &previousActiveTexture);
|
||||||
|
glGetIntegerv(GL_PIXEL_UNPACK_BUFFER_BINDING, &previousUnpackBuffer);
|
||||||
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, textBinding.texture);
|
||||||
|
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kTextTextureWidth, kTextTextureHeight, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, sdf.data());
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, static_cast<GLuint>(previousUnpackBuffer));
|
||||||
|
glActiveTexture(static_cast<GLenum>(previousActiveTexture));
|
||||||
|
|
||||||
|
textBinding.renderedText = text;
|
||||||
|
textBinding.renderedWidth = kTextTextureWidth;
|
||||||
|
textBinding.renderedHeight = kTextTextureHeight;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OpenGLShaderPrograms::UpdateGlobalParamsBuffer(const RuntimeRenderState& state, unsigned availableSourceHistoryLength, unsigned availableTemporalHistoryLength)
|
||||||
|
{
|
||||||
|
std::vector<unsigned char> buffer;
|
||||||
|
buffer.reserve(512);
|
||||||
|
|
||||||
|
AppendStd140Float(buffer, static_cast<float>(state.timeSeconds));
|
||||||
|
AppendStd140Vec2(buffer, static_cast<float>(state.inputWidth), static_cast<float>(state.inputHeight));
|
||||||
|
AppendStd140Vec2(buffer, static_cast<float>(state.outputWidth), static_cast<float>(state.outputHeight));
|
||||||
|
AppendStd140Float(buffer, static_cast<float>(state.frameCount));
|
||||||
|
AppendStd140Float(buffer, static_cast<float>(state.mixAmount));
|
||||||
|
AppendStd140Float(buffer, static_cast<float>(state.bypass));
|
||||||
|
const unsigned effectiveSourceHistoryLength = availableSourceHistoryLength < state.effectiveTemporalHistoryLength
|
||||||
|
? availableSourceHistoryLength
|
||||||
|
: state.effectiveTemporalHistoryLength;
|
||||||
|
const unsigned effectiveTemporalHistoryLength = (state.temporalHistorySource == TemporalHistorySource::PreLayerInput)
|
||||||
|
? (availableTemporalHistoryLength < state.effectiveTemporalHistoryLength ? availableTemporalHistoryLength : state.effectiveTemporalHistoryLength)
|
||||||
|
: 0u;
|
||||||
|
AppendStd140Int(buffer, static_cast<int>(effectiveSourceHistoryLength));
|
||||||
|
AppendStd140Int(buffer, static_cast<int>(effectiveTemporalHistoryLength));
|
||||||
|
|
||||||
|
for (const ShaderParameterDefinition& definition : state.parameterDefinitions)
|
||||||
|
{
|
||||||
|
auto valueIt = state.parameterValues.find(definition.id);
|
||||||
|
const ShaderParameterValue value = valueIt != state.parameterValues.end()
|
||||||
|
? valueIt->second
|
||||||
|
: ShaderParameterValue();
|
||||||
|
|
||||||
|
switch (definition.type)
|
||||||
|
{
|
||||||
|
case ShaderParameterType::Float:
|
||||||
|
AppendStd140Float(buffer, value.numberValues.empty() ? 0.0f : static_cast<float>(value.numberValues[0]));
|
||||||
|
break;
|
||||||
|
case ShaderParameterType::Vec2:
|
||||||
|
AppendStd140Vec2(buffer,
|
||||||
|
value.numberValues.size() > 0 ? static_cast<float>(value.numberValues[0]) : 0.0f,
|
||||||
|
value.numberValues.size() > 1 ? static_cast<float>(value.numberValues[1]) : 0.0f);
|
||||||
|
break;
|
||||||
|
case ShaderParameterType::Color:
|
||||||
|
AppendStd140Vec4(buffer,
|
||||||
|
value.numberValues.size() > 0 ? static_cast<float>(value.numberValues[0]) : 1.0f,
|
||||||
|
value.numberValues.size() > 1 ? static_cast<float>(value.numberValues[1]) : 1.0f,
|
||||||
|
value.numberValues.size() > 2 ? static_cast<float>(value.numberValues[2]) : 1.0f,
|
||||||
|
value.numberValues.size() > 3 ? static_cast<float>(value.numberValues[3]) : 1.0f);
|
||||||
|
break;
|
||||||
|
case ShaderParameterType::Boolean:
|
||||||
|
AppendStd140Int(buffer, value.booleanValue ? 1 : 0);
|
||||||
|
break;
|
||||||
|
case ShaderParameterType::Enum:
|
||||||
|
{
|
||||||
|
int selectedIndex = 0;
|
||||||
|
for (std::size_t optionIndex = 0; optionIndex < definition.enumOptions.size(); ++optionIndex)
|
||||||
|
{
|
||||||
|
if (definition.enumOptions[optionIndex].value == value.enumValue)
|
||||||
|
{
|
||||||
|
selectedIndex = static_cast<int>(optionIndex);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AppendStd140Int(buffer, selectedIndex);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ShaderParameterType::Text:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer.resize(AlignStd140(buffer.size(), 16), 0);
|
||||||
|
|
||||||
|
glBindBuffer(GL_UNIFORM_BUFFER, mRenderer.mGlobalParamsUBO);
|
||||||
|
if (mRenderer.mGlobalParamsUBOSize != static_cast<GLsizeiptr>(buffer.size()))
|
||||||
|
{
|
||||||
|
glBufferData(GL_UNIFORM_BUFFER, static_cast<GLsizeiptr>(buffer.size()), buffer.data(), GL_DYNAMIC_DRAW);
|
||||||
|
mRenderer.mGlobalParamsUBOSize = static_cast<GLsizeiptr>(buffer.size());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
glBufferSubData(GL_UNIFORM_BUFFER, 0, static_cast<GLsizeiptr>(buffer.size()), buffer.data());
|
||||||
|
}
|
||||||
|
glBindBufferBase(GL_UNIFORM_BUFFER, kGlobalParamsBindingPoint, mRenderer.mGlobalParamsUBO);
|
||||||
|
glBindBuffer(GL_UNIFORM_BUFFER, 0);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "OpenGLRenderer.h"
|
||||||
|
#include "RuntimeHost.h"
|
||||||
|
#include "ShaderTypes.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class OpenGLShaderPrograms
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using LayerProgram = OpenGLRenderer::LayerProgram;
|
||||||
|
|
||||||
|
OpenGLShaderPrograms(OpenGLRenderer& renderer, RuntimeHost& runtimeHost);
|
||||||
|
|
||||||
|
bool CompileLayerPrograms(unsigned inputFrameWidth, unsigned inputFrameHeight, int errorMessageSize, char* errorMessage);
|
||||||
|
bool CompileDecodeShader(int errorMessageSize, char* errorMessage);
|
||||||
|
void DestroyLayerPrograms();
|
||||||
|
void DestroySingleLayerProgram(LayerProgram& layerProgram);
|
||||||
|
void DestroyDecodeShaderProgram();
|
||||||
|
void ResetTemporalHistoryState();
|
||||||
|
bool UpdateTextBindingTexture(const RuntimeRenderState& state, LayerProgram::TextBinding& textBinding, std::string& error);
|
||||||
|
bool UpdateGlobalParamsBuffer(const RuntimeRenderState& state, unsigned availableSourceHistoryLength, unsigned availableTemporalHistoryLength);
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool CompileSingleLayerProgram(const RuntimeRenderState& state, LayerProgram& layerProgram, int errorMessageSize, char* errorMessage);
|
||||||
|
bool LoadTextureAsset(const ShaderTextureAsset& textureAsset, GLuint& textureId, std::string& error);
|
||||||
|
|
||||||
|
OpenGLRenderer& mRenderer;
|
||||||
|
RuntimeHost& mRuntimeHost;
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user