#include "OpenGLRenderer.h" #include "GlRenderConstants.h" namespace { void ConfigureByteFrameTexture(unsigned width, unsigned height) { 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); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); } } bool OpenGLRenderer::InitializeResources(unsigned inputFrameWidth, unsigned inputFrameHeight, unsigned captureTextureWidth, unsigned outputFrameWidth, unsigned outputFrameHeight, unsigned outputPackTextureWidth, std::string& error) { glClearColor(0.0f, 0.0f, 0.0f, 0.5f); glDisable(GL_DEPTH_TEST); glGenBuffers(1, &mTextureUploadBuffer); glGenTextures(1, &mCaptureTexture); glBindTexture(GL_TEXTURE_2D, mCaptureTexture); ConfigureByteFrameTexture(captureTextureWidth, inputFrameHeight); glBindTexture(GL_TEXTURE_2D, 0); glGenRenderbuffers(1, &mIdColorBuf); glGenRenderbuffers(1, &mIdDepthBuf); glGenVertexArrays(1, &mFullscreenVAO); glGenBuffers(1, &mGlobalParamsUBO); if (!mRenderTargets.Create(RenderTargetId::Decoded, inputFrameWidth, inputFrameHeight, GL_RGBA16F, GL_RGBA, GL_FLOAT, "decode", error)) return false; if (!mRenderTargets.Create(RenderTargetId::LayerTemp, inputFrameWidth, inputFrameHeight, GL_RGBA16F, GL_RGBA, GL_FLOAT, "layer", error)) return false; if (!mRenderTargets.Create(RenderTargetId::Composite, inputFrameWidth, inputFrameHeight, GL_RGBA16F, GL_RGBA, GL_FLOAT, "composite", error)) return false; glBindFramebuffer(GL_FRAMEBUFFER, CompositeFramebuffer()); glBindRenderbuffer(GL_RENDERBUFFER, mIdDepthBuf); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, inputFrameWidth, inputFrameHeight); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER, mIdDepthBuf); if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { error = "Cannot initialize framebuffer."; return false; } if (!mRenderTargets.Create(RenderTargetId::Output, outputFrameWidth, outputFrameHeight, GL_RGBA16F, GL_RGBA, GL_FLOAT, "output", error)) return false; if (!mRenderTargets.Create(RenderTargetId::OutputPack, outputPackTextureWidth, outputFrameHeight, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, "output pack", error)) return false; glBindTexture(GL_TEXTURE_2D, 0); glBindRenderbuffer(GL_RENDERBUFFER, 0); glBindFramebuffer(GL_FRAMEBUFFER, 0); glBindVertexArray(mFullscreenVAO); glBindVertexArray(0); glBindBuffer(GL_UNIFORM_BUFFER, mGlobalParamsUBO); glBufferData(GL_UNIFORM_BUFFER, 1024, NULL, GL_DYNAMIC_DRAW); glBindBufferBase(GL_UNIFORM_BUFFER, kGlobalParamsBindingPoint, mGlobalParamsUBO); glBindBuffer(GL_UNIFORM_BUFFER, 0); return true; } void OpenGLRenderer::SetDecodeShaderProgram(GLuint program, GLuint vertexShader, GLuint fragmentShader) { mDecodeProgram = program; mDecodeVertexShader = vertexShader; mDecodeFragmentShader = fragmentShader; mDecodePackedResolutionLocation = program != 0 ? glGetUniformLocation(program, "uPackedVideoResolution") : -1; mDecodeDecodedResolutionLocation = program != 0 ? glGetUniformLocation(program, "uDecodedVideoResolution") : -1; mDecodeInputPixelFormatLocation = program != 0 ? glGetUniformLocation(program, "uInputPixelFormat") : -1; } void OpenGLRenderer::SetOutputPackShaderProgram(GLuint program, GLuint vertexShader, GLuint fragmentShader) { mOutputPackProgram = program; mOutputPackVertexShader = vertexShader; mOutputPackFragmentShader = fragmentShader; mOutputPackResolutionLocation = program != 0 ? glGetUniformLocation(program, "uOutputVideoResolution") : -1; mOutputPackActiveWordsLocation = program != 0 ? glGetUniformLocation(program, "uActiveV210Words") : -1; mOutputPackFormatLocation = program != 0 ? glGetUniformLocation(program, "uOutputPackFormat") : -1; } 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) { mViewWidth = width; mViewHeight = height; } void OpenGLRenderer::PresentToWindow(HDC hdc, unsigned outputFrameWidth, unsigned outputFrameHeight) { int destWidth = mViewWidth; int destHeight = mViewHeight; int destX = 0; int destY = 0; if (outputFrameWidth > 0 && outputFrameHeight > 0 && mViewWidth > 0 && mViewHeight > 0) { const double frameAspect = static_cast(outputFrameWidth) / static_cast(outputFrameHeight); const double viewAspect = static_cast(mViewWidth) / static_cast(mViewHeight); if (viewAspect > frameAspect) { destHeight = mViewHeight; destWidth = static_cast(destHeight * frameAspect + 0.5); destX = (mViewWidth - destWidth) / 2; } else { destWidth = mViewWidth; destHeight = static_cast(destWidth / frameAspect + 0.5); destY = (mViewHeight - destHeight) / 2; } } glBindFramebuffer(GL_READ_FRAMEBUFFER, OutputFramebuffer()); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); glDisable(GL_SCISSOR_TEST); glViewport(0, 0, mViewWidth, mViewHeight); glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); glBlitFramebuffer(0, 0, outputFrameWidth, outputFrameHeight, destX, destY, destX + destWidth, destY + destHeight, GL_COLOR_BUFFER_BIT, GL_LINEAR); SwapBuffers(hdc); } void OpenGLRenderer::DestroyResources() { if (mFullscreenVAO != 0) glDeleteVertexArrays(1, &mFullscreenVAO); if (mGlobalParamsUBO != 0) glDeleteBuffers(1, &mGlobalParamsUBO); if (mIdColorBuf != 0) glDeleteRenderbuffers(1, &mIdColorBuf); if (mIdDepthBuf != 0) glDeleteRenderbuffers(1, &mIdDepthBuf); if (mCaptureTexture != 0) glDeleteTextures(1, &mCaptureTexture); if (mTextureUploadBuffer != 0) glDeleteBuffers(1, &mTextureUploadBuffer); mRenderTargets.Destroy(); mFullscreenVAO = 0; mGlobalParamsUBO = 0; mIdColorBuf = 0; mIdDepthBuf = 0; mCaptureTexture = 0; mTextureUploadBuffer = 0; mGlobalParamsUBOSize = 0; mTemporalHistory.DestroyResources(); DestroyLayerPrograms(); DestroyDecodeShaderProgram(); DestroyOutputPackShaderProgram(); } void OpenGLRenderer::DestroySingleLayerProgram(LayerProgram& layerProgram) { for (LayerProgram::PassProgram& passProgram : layerProgram.passes) { for (LayerProgram::TextureBinding& binding : passProgram.textureBindings) { if (binding.texture != 0) { glDeleteTextures(1, &binding.texture); binding.texture = 0; } } passProgram.textureBindings.clear(); for (LayerProgram::TextBinding& binding : passProgram.textBindings) { if (binding.texture != 0) { glDeleteTextures(1, &binding.texture); binding.texture = 0; } } passProgram.textBindings.clear(); if (passProgram.program != 0) { glDeleteProgram(passProgram.program); passProgram.program = 0; } if (passProgram.fragmentShader != 0) { glDeleteShader(passProgram.fragmentShader); passProgram.fragmentShader = 0; } if (passProgram.vertexShader != 0) { glDeleteShader(passProgram.vertexShader); passProgram.vertexShader = 0; } } layerProgram.passes.clear(); } void OpenGLRenderer::DestroyLayerPrograms() { for (LayerProgram& layerProgram : mLayerPrograms) DestroySingleLayerProgram(layerProgram); mLayerPrograms.clear(); } void OpenGLRenderer::DestroyDecodeShaderProgram() { if (mDecodeProgram != 0) { glDeleteProgram(mDecodeProgram); mDecodeProgram = 0; } mDecodePackedResolutionLocation = -1; mDecodeDecodedResolutionLocation = -1; mDecodeInputPixelFormatLocation = -1; if (mDecodeFragmentShader != 0) { glDeleteShader(mDecodeFragmentShader); mDecodeFragmentShader = 0; } if (mDecodeVertexShader != 0) { glDeleteShader(mDecodeVertexShader); mDecodeVertexShader = 0; } } void OpenGLRenderer::DestroyOutputPackShaderProgram() { if (mOutputPackProgram != 0) { glDeleteProgram(mOutputPackProgram); mOutputPackProgram = 0; } mOutputPackResolutionLocation = -1; mOutputPackActiveWordsLocation = -1; mOutputPackFormatLocation = -1; if (mOutputPackFragmentShader != 0) { glDeleteShader(mOutputPackFragmentShader); mOutputPackFragmentShader = 0; } if (mOutputPackVertexShader != 0) { glDeleteShader(mOutputPackVertexShader); mOutputPackVertexShader = 0; } }