diff --git a/apps/RenderCadenceCompositor/render/RenderThread.cpp b/apps/RenderCadenceCompositor/render/RenderThread.cpp index 91fb3b3..6dcd173 100644 --- a/apps/RenderCadenceCompositor/render/RenderThread.cpp +++ b/apps/RenderCadenceCompositor/render/RenderThread.cpp @@ -159,6 +159,8 @@ void RenderThread::ThreadMain() if (!readback.RenderAndQueue(frameIndex, [this, &renderer, &runtimeRenderScene, videoInputTexture](uint64_t index) { if (runtimeRenderScene.HasLayers()) runtimeRenderScene.RenderFrame(index, mConfig.width, mConfig.height, videoInputTexture); + else if (videoInputTexture != 0) + renderer.RenderTexture(videoInputTexture); else renderer.RenderFrame(index); })) diff --git a/apps/RenderCadenceCompositor/render/SimpleMotionRenderer.cpp b/apps/RenderCadenceCompositor/render/SimpleMotionRenderer.cpp index b1333e2..4d06dcc 100644 --- a/apps/RenderCadenceCompositor/render/SimpleMotionRenderer.cpp +++ b/apps/RenderCadenceCompositor/render/SimpleMotionRenderer.cpp @@ -3,8 +3,43 @@ #include "GLExtensions.h" #include +#include #include +namespace +{ +constexpr GLuint kInputTextureUnit = 0; + +const char* kTextureVertexShader = R"GLSL( +#version 430 core +out vec2 vTexCoord; +void main() +{ + vec2 positions[3] = vec2[3]( + vec2(-1.0, -1.0), + vec2( 3.0, -1.0), + vec2(-1.0, 3.0)); + vec2 texCoords[3] = vec2[3]( + vec2(0.0, 0.0), + vec2(2.0, 0.0), + vec2(0.0, 2.0)); + gl_Position = vec4(positions[gl_VertexID], 0.0, 1.0); + vTexCoord = texCoords[gl_VertexID]; +} +)GLSL"; + +const char* kTextureFragmentShader = R"GLSL( +#version 430 core +layout(binding = 0) uniform sampler2D uInputTexture; +in vec2 vTexCoord; +out vec4 fragColor; +void main() +{ + fragColor = texture(uInputTexture, clamp(vTexCoord, vec2(0.0), vec2(1.0))); +} +)GLSL"; +} + bool SimpleMotionRenderer::InitializeGl(unsigned width, unsigned height) { mWidth = width; @@ -43,8 +78,100 @@ void SimpleMotionRenderer::RenderFrame(uint64_t frameIndex) glDisable(GL_SCISSOR_TEST); } +void SimpleMotionRenderer::RenderTexture(GLuint texture) +{ + if (texture == 0 || !EnsureTextureProgram()) + { + RenderFrame(0); + return; + } + + glViewport(0, 0, static_cast(mWidth), static_cast(mHeight)); + glDisable(GL_SCISSOR_TEST); + glDisable(GL_DEPTH_TEST); + glDisable(GL_BLEND); + glActiveTexture(GL_TEXTURE0 + kInputTextureUnit); + glBindTexture(GL_TEXTURE_2D, texture); + glUseProgram(mTextureProgram); + glBindVertexArray(mTextureVertexArray); + glDrawArrays(GL_TRIANGLES, 0, 3); + glBindVertexArray(0); + glUseProgram(0); + glBindTexture(GL_TEXTURE_2D, 0); + glActiveTexture(GL_TEXTURE0); +} + void SimpleMotionRenderer::ShutdownGl() { + DestroyTextureProgram(); mWidth = 0; mHeight = 0; } + +bool SimpleMotionRenderer::EnsureTextureProgram() +{ + if (mTextureProgram != 0) + return true; + + if (!CompileShader(GL_VERTEX_SHADER, kTextureVertexShader, mTextureVertexShader)) + return false; + if (!CompileShader(GL_FRAGMENT_SHADER, kTextureFragmentShader, mTextureFragmentShader)) + { + DestroyTextureProgram(); + return false; + } + + mTextureProgram = glCreateProgram(); + glAttachShader(mTextureProgram, mTextureVertexShader); + glAttachShader(mTextureProgram, mTextureFragmentShader); + glLinkProgram(mTextureProgram); + + GLint linkResult = GL_FALSE; + glGetProgramiv(mTextureProgram, GL_LINK_STATUS, &linkResult); + if (linkResult == GL_FALSE) + { + DestroyTextureProgram(); + return false; + } + + glUseProgram(mTextureProgram); + const GLint inputLocation = glGetUniformLocation(mTextureProgram, "uInputTexture"); + if (inputLocation >= 0) + glUniform1i(inputLocation, static_cast(kInputTextureUnit)); + glUseProgram(0); + + glGenVertexArrays(1, &mTextureVertexArray); + return mTextureVertexArray != 0; +} + +void SimpleMotionRenderer::DestroyTextureProgram() +{ + if (mTextureProgram != 0) + glDeleteProgram(mTextureProgram); + if (mTextureVertexShader != 0) + glDeleteShader(mTextureVertexShader); + if (mTextureFragmentShader != 0) + glDeleteShader(mTextureFragmentShader); + if (mTextureVertexArray != 0) + glDeleteVertexArrays(1, &mTextureVertexArray); + mTextureProgram = 0; + mTextureVertexShader = 0; + mTextureFragmentShader = 0; + mTextureVertexArray = 0; +} + +bool SimpleMotionRenderer::CompileShader(GLenum shaderType, const char* source, GLuint& shader) +{ + shader = glCreateShader(shaderType); + glShaderSource(shader, 1, &source, nullptr); + glCompileShader(shader); + + GLint compileResult = GL_FALSE; + glGetShaderiv(shader, GL_COMPILE_STATUS, &compileResult); + if (compileResult != GL_FALSE) + return true; + + glDeleteShader(shader); + shader = 0; + return false; +} diff --git a/apps/RenderCadenceCompositor/render/SimpleMotionRenderer.h b/apps/RenderCadenceCompositor/render/SimpleMotionRenderer.h index 72df37e..db00879 100644 --- a/apps/RenderCadenceCompositor/render/SimpleMotionRenderer.h +++ b/apps/RenderCadenceCompositor/render/SimpleMotionRenderer.h @@ -1,5 +1,7 @@ #pragma once +#include "GLExtensions.h" + #include class SimpleMotionRenderer @@ -9,12 +11,21 @@ public: bool InitializeGl(unsigned width, unsigned height); void RenderFrame(uint64_t frameIndex); + void RenderTexture(GLuint texture); void ShutdownGl(); unsigned Width() const { return mWidth; } unsigned Height() const { return mHeight; } private: + bool EnsureTextureProgram(); + void DestroyTextureProgram(); + static bool CompileShader(GLenum shaderType, const char* source, GLuint& shader); + unsigned mWidth = 0; unsigned mHeight = 0; + GLuint mTextureProgram = 0; + GLuint mTextureVertexShader = 0; + GLuint mTextureFragmentShader = 0; + GLuint mTextureVertexArray = 0; };