93 lines
3.5 KiB
C++
93 lines
3.5 KiB
C++
#include "OpenGLRenderPipeline.h"
|
|
|
|
#include "OpenGLRenderer.h"
|
|
#include "RuntimeHost.h"
|
|
#include "VideoIOFormat.h"
|
|
|
|
#include <chrono>
|
|
#include <gl/gl.h>
|
|
|
|
OpenGLRenderPipeline::OpenGLRenderPipeline(
|
|
OpenGLRenderer& renderer,
|
|
RuntimeHost& runtimeHost,
|
|
RenderEffectCallback renderEffect,
|
|
OutputReadyCallback outputReady,
|
|
PaintCallback paint) :
|
|
mRenderer(renderer),
|
|
mRuntimeHost(runtimeHost),
|
|
mRenderEffect(renderEffect),
|
|
mOutputReady(outputReady),
|
|
mPaint(paint)
|
|
{
|
|
}
|
|
|
|
bool OpenGLRenderPipeline::RenderFrame(const RenderPipelineFrameContext& context, VideoIOOutputFrame& outputFrame)
|
|
{
|
|
const VideoIOState& state = context.videoState;
|
|
|
|
const auto renderStartTime = std::chrono::steady_clock::now();
|
|
glBindFramebuffer(GL_FRAMEBUFFER, mRenderer.CompositeFramebuffer());
|
|
mRenderEffect();
|
|
glBindFramebuffer(GL_READ_FRAMEBUFFER, mRenderer.CompositeFramebuffer());
|
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mRenderer.OutputFramebuffer());
|
|
glBlitFramebuffer(0, 0, state.inputFrameSize.width, state.inputFrameSize.height, 0, 0, state.outputFrameSize.width, state.outputFrameSize.height, GL_COLOR_BUFFER_BIT, GL_LINEAR);
|
|
glBindFramebuffer(GL_FRAMEBUFFER, mRenderer.OutputFramebuffer());
|
|
if (mOutputReady)
|
|
mOutputReady();
|
|
if (state.outputPixelFormat == VideoIOPixelFormat::V210)
|
|
PackOutputForV210(state);
|
|
glFlush();
|
|
|
|
const auto renderEndTime = std::chrono::steady_clock::now();
|
|
const double renderMilliseconds = std::chrono::duration_cast<std::chrono::duration<double, std::milli>>(renderEndTime - renderStartTime).count();
|
|
mRuntimeHost.TrySetPerformanceStats(state.frameBudgetMilliseconds, renderMilliseconds);
|
|
mRuntimeHost.TryAdvanceFrame();
|
|
|
|
ReadOutputFrame(state, outputFrame);
|
|
if (mPaint)
|
|
mPaint();
|
|
|
|
return true;
|
|
}
|
|
|
|
void OpenGLRenderPipeline::PackOutputForV210(const VideoIOState& state)
|
|
{
|
|
glBindFramebuffer(GL_FRAMEBUFFER, mRenderer.OutputPackFramebuffer());
|
|
glViewport(0, 0, state.outputPackTextureWidth, state.outputFrameSize.height);
|
|
glDisable(GL_SCISSOR_TEST);
|
|
glDisable(GL_BLEND);
|
|
glDisable(GL_DEPTH_TEST);
|
|
glActiveTexture(GL_TEXTURE0);
|
|
glBindTexture(GL_TEXTURE_2D, mRenderer.OutputTexture());
|
|
glBindVertexArray(mRenderer.FullscreenVertexArray());
|
|
glUseProgram(mRenderer.OutputPackProgram());
|
|
|
|
const GLint outputResolutionLocation = glGetUniformLocation(mRenderer.OutputPackProgram(), "uOutputVideoResolution");
|
|
const GLint activeWordsLocation = glGetUniformLocation(mRenderer.OutputPackProgram(), "uActiveV210Words");
|
|
if (outputResolutionLocation >= 0)
|
|
glUniform2f(outputResolutionLocation, static_cast<float>(state.outputFrameSize.width), static_cast<float>(state.outputFrameSize.height));
|
|
if (activeWordsLocation >= 0)
|
|
glUniform1f(activeWordsLocation, static_cast<float>(ActiveV210WordsForWidth(state.outputFrameSize.width)));
|
|
|
|
glDrawArrays(GL_TRIANGLES, 0, 3);
|
|
glUseProgram(0);
|
|
glBindVertexArray(0);
|
|
glBindTexture(GL_TEXTURE_2D, 0);
|
|
}
|
|
|
|
void OpenGLRenderPipeline::ReadOutputFrame(const VideoIOState& state, VideoIOOutputFrame& outputFrame)
|
|
{
|
|
glPixelStorei(GL_PACK_ALIGNMENT, 4);
|
|
glPixelStorei(GL_PACK_ROW_LENGTH, 0);
|
|
if (state.outputPixelFormat == VideoIOPixelFormat::V210)
|
|
{
|
|
glBindFramebuffer(GL_READ_FRAMEBUFFER, mRenderer.OutputPackFramebuffer());
|
|
glReadPixels(0, 0, state.outputPackTextureWidth, state.outputFrameSize.height, GL_RGBA, GL_UNSIGNED_BYTE, outputFrame.bytes);
|
|
}
|
|
else
|
|
{
|
|
glBindFramebuffer(GL_READ_FRAMEBUFFER, mRenderer.OutputFramebuffer());
|
|
glReadPixels(0, 0, state.outputFrameSize.width, state.outputFrameSize.height, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, outputFrame.bytes);
|
|
}
|
|
}
|