#include "OpenGLRenderPipeline.h" #include "OpenGLRenderer.h" #include "RuntimeHost.h" #include "VideoIOFormat.h" #include #include 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 || state.outputPixelFormat == VideoIOPixelFormat::Yuva10) PackOutputFor10Bit(state); glFlush(); const auto renderEndTime = std::chrono::steady_clock::now(); const double renderMilliseconds = std::chrono::duration_cast>(renderEndTime - renderStartTime).count(); mRuntimeHost.TrySetPerformanceStats(state.frameBudgetMilliseconds, renderMilliseconds); mRuntimeHost.TryAdvanceFrame(); ReadOutputFrame(state, outputFrame); if (mPaint) mPaint(); return true; } void OpenGLRenderPipeline::PackOutputFor10Bit(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"); const GLint packFormatLocation = glGetUniformLocation(mRenderer.OutputPackProgram(), "uOutputPackFormat"); if (outputResolutionLocation >= 0) glUniform2f(outputResolutionLocation, static_cast(state.outputFrameSize.width), static_cast(state.outputFrameSize.height)); if (activeWordsLocation >= 0) glUniform1f(activeWordsLocation, static_cast(ActiveV210WordsForWidth(state.outputFrameSize.width))); if (packFormatLocation >= 0) glUniform1i(packFormatLocation, state.outputPixelFormat == VideoIOPixelFormat::Yuva10 ? 2 : 1); 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 || state.outputPixelFormat == VideoIOPixelFormat::Yuva10) { 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); } }