INput
All checks were successful
CI / React UI Build (push) Successful in 10s
CI / Native Windows Build And Tests (push) Successful in 2m59s
CI / Windows Release Package (push) Has been skipped

This commit is contained in:
Aiden
2026-05-12 18:39:08 +10:00
parent 6e32941675
commit 0a8b335048
14 changed files with 822 additions and 24 deletions

View File

@@ -0,0 +1,83 @@
#include "InputFrameTexture.h"
InputFrameTexture::~InputFrameTexture()
{
ShutdownGl();
}
GLuint InputFrameTexture::PollAndUpload(InputFrameMailbox* mailbox)
{
if (mailbox == nullptr)
return mTexture;
InputFrame frame;
if (!mailbox->TryAcquireLatest(frame))
{
++mUploadMisses;
return mTexture;
}
if (frame.bytes != nullptr && frame.pixelFormat == VideoIOPixelFormat::Bgra8 && EnsureTexture(frame))
{
glBindTexture(GL_TEXTURE_2D, mTexture);
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
glPixelStorei(GL_UNPACK_ROW_LENGTH, frame.rowBytes > 0 ? static_cast<GLint>(frame.rowBytes / 4) : 0);
glTexSubImage2D(
GL_TEXTURE_2D,
0,
0,
0,
static_cast<GLsizei>(frame.width),
static_cast<GLsizei>(frame.height),
GL_BGRA,
GL_UNSIGNED_INT_8_8_8_8_REV,
frame.bytes);
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
glBindTexture(GL_TEXTURE_2D, 0);
++mUploadedFrames;
}
mailbox->Release(frame);
return mTexture;
}
void InputFrameTexture::ShutdownGl()
{
if (mTexture != 0)
glDeleteTextures(1, &mTexture);
mTexture = 0;
mWidth = 0;
mHeight = 0;
}
bool InputFrameTexture::EnsureTexture(const InputFrame& frame)
{
if (frame.width == 0 || frame.height == 0)
return false;
if (mTexture != 0 && mWidth == frame.width && mHeight == frame.height)
return true;
ShutdownGl();
glGenTextures(1, &mTexture);
glBindTexture(GL_TEXTURE_2D, mTexture);
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,
static_cast<GLsizei>(frame.width),
static_cast<GLsizei>(frame.height),
0,
GL_BGRA,
GL_UNSIGNED_INT_8_8_8_8_REV,
nullptr);
glBindTexture(GL_TEXTURE_2D, 0);
mWidth = frame.width;
mHeight = frame.height;
return mTexture != 0;
}

View File

@@ -0,0 +1,30 @@
#pragma once
#include "../frames/InputFrameMailbox.h"
#include "GLExtensions.h"
#include <cstdint>
class InputFrameTexture
{
public:
InputFrameTexture() = default;
InputFrameTexture(const InputFrameTexture&) = delete;
InputFrameTexture& operator=(const InputFrameTexture&) = delete;
~InputFrameTexture();
GLuint PollAndUpload(InputFrameMailbox* mailbox);
GLuint Texture() const { return mTexture; }
uint64_t UploadedFrames() const { return mUploadedFrames; }
uint64_t UploadMisses() const { return mUploadMisses; }
void ShutdownGl();
private:
bool EnsureTexture(const InputFrame& frame);
GLuint mTexture = 0;
unsigned mWidth = 0;
unsigned mHeight = 0;
uint64_t mUploadedFrames = 0;
uint64_t mUploadMisses = 0;
};

View File

@@ -1,9 +1,11 @@
#include "RenderThread.h"
#include "../frames/InputFrameMailbox.h"
#include "../frames/SystemFrameExchange.h"
#include "../frames/SystemFrameTypes.h"
#include "../logging/Logger.h"
#include "../platform/HiddenGlWindow.h"
#include "InputFrameTexture.h"
#include "readback/Bgra8ReadbackPipeline.h"
#include "GLExtensions.h"
#include "runtime/RuntimeRenderScene.h"
@@ -20,6 +22,13 @@ RenderThread::RenderThread(SystemFrameExchange& frameExchange, Config config) :
{
}
RenderThread::RenderThread(SystemFrameExchange& frameExchange, InputFrameMailbox* inputMailbox, Config config) :
mFrameExchange(frameExchange),
mInputMailbox(inputMailbox),
mConfig(config)
{
}
RenderThread::~RenderThread()
{
Stop();
@@ -109,6 +118,7 @@ void RenderThread::ThreadMain()
SimpleMotionRenderer renderer;
RuntimeRenderScene runtimeRenderScene;
Bgra8ReadbackPipeline readback;
InputFrameTexture inputTexture;
if (!runtimeRenderScene.StartPrepareWorker(std::move(prepareWindow), error))
{
SignalStartupFailure(error.empty() ? "Runtime shader prepare worker initialization failed." : error);
@@ -145,9 +155,10 @@ void RenderThread::ThreadMain()
}
TryCommitReadyRuntimeShader(runtimeRenderScene);
if (!readback.RenderAndQueue(frameIndex, [this, &renderer, &runtimeRenderScene](uint64_t index) {
const GLuint videoInputTexture = inputTexture.PollAndUpload(mInputMailbox);
if (!readback.RenderAndQueue(frameIndex, [this, &renderer, &runtimeRenderScene, videoInputTexture](uint64_t index) {
if (runtimeRenderScene.HasLayers())
runtimeRenderScene.RenderFrame(index, mConfig.width, mConfig.height);
runtimeRenderScene.RenderFrame(index, mConfig.width, mConfig.height, videoInputTexture);
else
renderer.RenderFrame(index);
}))
@@ -175,6 +186,7 @@ void RenderThread::ThreadMain()
}
readback.Shutdown();
inputTexture.ShutdownGl();
runtimeRenderScene.ShutdownGl();
renderer.ShutdownGl();
window.ClearCurrent();

View File

@@ -14,6 +14,7 @@
#include <thread>
class SystemFrameExchange;
class InputFrameMailbox;
class RenderThread
{
@@ -39,6 +40,7 @@ public:
};
RenderThread(SystemFrameExchange& frameExchange, Config config);
RenderThread(SystemFrameExchange& frameExchange, InputFrameMailbox* inputMailbox, Config config);
RenderThread(const RenderThread&) = delete;
RenderThread& operator=(const RenderThread&) = delete;
~RenderThread();
@@ -63,6 +65,7 @@ private:
bool TryTakePendingRenderLayers(std::vector<RenderCadenceCompositor::RuntimeRenderLayerModel>& layers);
SystemFrameExchange& mFrameExchange;
InputFrameMailbox* mInputMailbox = nullptr;
Config mConfig;
std::thread mThread;
std::atomic<bool> mStopping{ false };

View File

@@ -120,7 +120,7 @@ bool RuntimeRenderScene::HasLayers()
return false;
}
void RuntimeRenderScene::RenderFrame(uint64_t frameIndex, unsigned width, unsigned height)
void RuntimeRenderScene::RenderFrame(uint64_t frameIndex, unsigned width, unsigned height, GLuint videoInputTexture)
{
ConsumePreparedPrograms();
@@ -148,18 +148,18 @@ void RuntimeRenderScene::RenderFrame(uint64_t frameIndex, unsigned width, unsign
if (readyLayers.size() == 1)
{
RenderLayer(*readyLayers.front(), frameIndex, width, height, 0, static_cast<GLuint>(outputFramebuffer), true);
RenderLayer(*readyLayers.front(), frameIndex, width, height, videoInputTexture, videoInputTexture, static_cast<GLuint>(outputFramebuffer), true);
return;
}
if (!EnsureLayerTargets(width, height))
{
glBindFramebuffer(GL_FRAMEBUFFER, static_cast<GLuint>(outputFramebuffer));
RenderLayer(*readyLayers.back(), frameIndex, width, height, 0, static_cast<GLuint>(outputFramebuffer), true);
RenderLayer(*readyLayers.back(), frameIndex, width, height, videoInputTexture, videoInputTexture, static_cast<GLuint>(outputFramebuffer), true);
return;
}
GLuint layerInputTexture = 0;
GLuint layerInputTexture = videoInputTexture;
std::size_t nextTargetIndex = 0;
for (std::size_t layerIndex = 0; layerIndex < readyLayers.size(); ++layerIndex)
{
@@ -167,11 +167,11 @@ void RuntimeRenderScene::RenderFrame(uint64_t frameIndex, unsigned width, unsign
if (isFinalLayer)
{
glBindFramebuffer(GL_FRAMEBUFFER, static_cast<GLuint>(outputFramebuffer));
RenderLayer(*readyLayers[layerIndex], frameIndex, width, height, layerInputTexture, static_cast<GLuint>(outputFramebuffer), true);
RenderLayer(*readyLayers[layerIndex], frameIndex, width, height, videoInputTexture, layerInputTexture, static_cast<GLuint>(outputFramebuffer), true);
continue;
}
RenderLayer(*readyLayers[layerIndex], frameIndex, width, height, layerInputTexture, mLayerFramebuffers[nextTargetIndex], true);
RenderLayer(*readyLayers[layerIndex], frameIndex, width, height, videoInputTexture, layerInputTexture, mLayerFramebuffers[nextTargetIndex], true);
layerInputTexture = mLayerTextures[nextTargetIndex];
nextTargetIndex = 1 - nextTargetIndex;
}
@@ -309,6 +309,7 @@ GLuint RuntimeRenderScene::RenderLayer(
uint64_t frameIndex,
unsigned width,
unsigned height,
GLuint videoInputTexture,
GLuint layerInputTexture,
GLuint outputFramebuffer,
bool renderToOutput)
@@ -327,7 +328,11 @@ GLuint RuntimeRenderScene::RenderLayer(
if (!pass.inputNames.empty())
{
const std::string& inputName = pass.inputNames.front();
if (inputName != "layerInput" && inputName != "videoInput")
if (inputName == "videoInput")
{
sourceTexture = videoInputTexture;
}
else if (inputName != "layerInput")
{
for (std::size_t index = 0; index < 2; ++index)
{
@@ -344,7 +349,7 @@ GLuint RuntimeRenderScene::RenderLayer(
if (writesLayerOutput && renderToOutput)
{
glBindFramebuffer(GL_FRAMEBUFFER, outputFramebuffer);
pass.renderer->RenderFrame(frameIndex, width, height, sourceTexture, sourceTexture);
pass.renderer->RenderFrame(frameIndex, width, height, sourceTexture, layerInputTexture);
lastOutputTexture = 0;
continue;
}
@@ -355,7 +360,7 @@ GLuint RuntimeRenderScene::RenderLayer(
const std::size_t targetIndex = nextTargetIndex;
nextTargetIndex = nextTargetIndex == 2 ? 3 : 2;
glBindFramebuffer(GL_FRAMEBUFFER, mLayerFramebuffers[targetIndex]);
pass.renderer->RenderFrame(frameIndex, width, height, sourceTexture, sourceTexture);
pass.renderer->RenderFrame(frameIndex, width, height, sourceTexture, layerInputTexture);
const std::size_t namedIndex = targetIndex - 2;
namedOutputs[namedIndex] = mLayerTextures[targetIndex];
namedOutputNames[namedIndex] = pass.outputName;

View File

@@ -22,7 +22,7 @@ public:
bool StartPrepareWorker(std::unique_ptr<HiddenGlWindow> sharedWindow, std::string& error);
bool CommitRenderLayers(const std::vector<RenderCadenceCompositor::RuntimeRenderLayerModel>& layers, std::string& error);
bool HasLayers();
void RenderFrame(uint64_t frameIndex, unsigned width, unsigned height);
void RenderFrame(uint64_t frameIndex, unsigned width, unsigned height, GLuint videoInputTexture = 0);
void ShutdownGl();
private:
@@ -48,7 +48,7 @@ private:
void TryCommitPendingPrograms(LayerProgram& layer);
bool EnsureLayerTargets(unsigned width, unsigned height);
void DestroyLayerTargets();
GLuint RenderLayer(LayerProgram& layer, uint64_t frameIndex, unsigned width, unsigned height, GLuint layerInputTexture, GLuint outputFramebuffer, bool renderToOutput);
GLuint RenderLayer(LayerProgram& layer, uint64_t frameIndex, unsigned width, unsigned height, GLuint videoInputTexture, GLuint layerInputTexture, GLuint outputFramebuffer, bool renderToOutput);
LayerProgram* FindLayer(const std::string& layerId);
const LayerProgram* FindLayer(const std::string& layerId) const;
LayerProgram::PassProgram* FindPass(LayerProgram& layer, const std::string& passId);