Compare commits
2 Commits
6a33bd02ab
...
1429b2e660
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1429b2e660 | ||
|
|
02b221f481 |
@@ -310,9 +310,9 @@ set(RENDER_CADENCE_APP_SOURCES
|
|||||||
"${RENDER_CADENCE_APP_DIR}/app/RuntimeLayerController.cpp"
|
"${RENDER_CADENCE_APP_DIR}/app/RuntimeLayerController.cpp"
|
||||||
"${RENDER_CADENCE_APP_DIR}/app/RuntimeLayerController.h"
|
"${RENDER_CADENCE_APP_DIR}/app/RuntimeLayerController.h"
|
||||||
"${RENDER_CADENCE_APP_DIR}/control/ControlActionResult.h"
|
"${RENDER_CADENCE_APP_DIR}/control/ControlActionResult.h"
|
||||||
"${RENDER_CADENCE_APP_DIR}/control/HttpControlServer.cpp"
|
"${RENDER_CADENCE_APP_DIR}/control/http/HttpControlServer.cpp"
|
||||||
"${RENDER_CADENCE_APP_DIR}/control/HttpControlServer.h"
|
"${RENDER_CADENCE_APP_DIR}/control/http/HttpControlServer.h"
|
||||||
"${RENDER_CADENCE_APP_DIR}/control/HttpControlServerWebSocket.cpp"
|
"${RENDER_CADENCE_APP_DIR}/control/http/HttpControlServerWebSocket.cpp"
|
||||||
"${RENDER_CADENCE_APP_DIR}/control/RuntimeStateJson.h"
|
"${RENDER_CADENCE_APP_DIR}/control/RuntimeStateJson.h"
|
||||||
"${RENDER_CADENCE_APP_DIR}/frames/SystemFrameExchange.cpp"
|
"${RENDER_CADENCE_APP_DIR}/frames/SystemFrameExchange.cpp"
|
||||||
"${RENDER_CADENCE_APP_DIR}/frames/SystemFrameExchange.h"
|
"${RENDER_CADENCE_APP_DIR}/frames/SystemFrameExchange.h"
|
||||||
@@ -323,23 +323,23 @@ set(RENDER_CADENCE_APP_SOURCES
|
|||||||
"${RENDER_CADENCE_APP_DIR}/logging/Logger.h"
|
"${RENDER_CADENCE_APP_DIR}/logging/Logger.h"
|
||||||
"${RENDER_CADENCE_APP_DIR}/platform/HiddenGlWindow.cpp"
|
"${RENDER_CADENCE_APP_DIR}/platform/HiddenGlWindow.cpp"
|
||||||
"${RENDER_CADENCE_APP_DIR}/platform/HiddenGlWindow.h"
|
"${RENDER_CADENCE_APP_DIR}/platform/HiddenGlWindow.h"
|
||||||
"${RENDER_CADENCE_APP_DIR}/render/Bgra8ReadbackPipeline.cpp"
|
"${RENDER_CADENCE_APP_DIR}/render/readback/Bgra8ReadbackPipeline.cpp"
|
||||||
"${RENDER_CADENCE_APP_DIR}/render/Bgra8ReadbackPipeline.h"
|
"${RENDER_CADENCE_APP_DIR}/render/readback/Bgra8ReadbackPipeline.h"
|
||||||
"${RENDER_CADENCE_APP_DIR}/render/PboReadbackRing.cpp"
|
"${RENDER_CADENCE_APP_DIR}/render/readback/PboReadbackRing.cpp"
|
||||||
"${RENDER_CADENCE_APP_DIR}/render/PboReadbackRing.h"
|
"${RENDER_CADENCE_APP_DIR}/render/readback/PboReadbackRing.h"
|
||||||
"${RENDER_CADENCE_APP_DIR}/render/RenderCadenceClock.cpp"
|
"${RENDER_CADENCE_APP_DIR}/render/RenderCadenceClock.cpp"
|
||||||
"${RENDER_CADENCE_APP_DIR}/render/RenderCadenceClock.h"
|
"${RENDER_CADENCE_APP_DIR}/render/RenderCadenceClock.h"
|
||||||
"${RENDER_CADENCE_APP_DIR}/render/RenderThread.cpp"
|
"${RENDER_CADENCE_APP_DIR}/render/RenderThread.cpp"
|
||||||
"${RENDER_CADENCE_APP_DIR}/render/RenderThread.h"
|
"${RENDER_CADENCE_APP_DIR}/render/RenderThread.h"
|
||||||
"${RENDER_CADENCE_APP_DIR}/render/RuntimeShaderRenderer.cpp"
|
"${RENDER_CADENCE_APP_DIR}/render/runtime/RuntimeShaderRenderer.cpp"
|
||||||
"${RENDER_CADENCE_APP_DIR}/render/RuntimeShaderRenderer.h"
|
"${RENDER_CADENCE_APP_DIR}/render/runtime/RuntimeShaderRenderer.h"
|
||||||
"${RENDER_CADENCE_APP_DIR}/render/RuntimeShaderParams.cpp"
|
"${RENDER_CADENCE_APP_DIR}/render/runtime/RuntimeShaderParams.cpp"
|
||||||
"${RENDER_CADENCE_APP_DIR}/render/RuntimeShaderParams.h"
|
"${RENDER_CADENCE_APP_DIR}/render/runtime/RuntimeShaderParams.h"
|
||||||
"${RENDER_CADENCE_APP_DIR}/render/RuntimeRenderScene.cpp"
|
"${RENDER_CADENCE_APP_DIR}/render/runtime/RuntimeRenderScene.cpp"
|
||||||
"${RENDER_CADENCE_APP_DIR}/render/RuntimeRenderScene.h"
|
"${RENDER_CADENCE_APP_DIR}/render/runtime/RuntimeRenderScene.h"
|
||||||
"${RENDER_CADENCE_APP_DIR}/render/RuntimeShaderPrepareWorker.cpp"
|
"${RENDER_CADENCE_APP_DIR}/render/runtime/RuntimeShaderPrepareWorker.cpp"
|
||||||
"${RENDER_CADENCE_APP_DIR}/render/RuntimeShaderPrepareWorker.h"
|
"${RENDER_CADENCE_APP_DIR}/render/runtime/RuntimeShaderPrepareWorker.h"
|
||||||
"${RENDER_CADENCE_APP_DIR}/render/RuntimeShaderProgram.h"
|
"${RENDER_CADENCE_APP_DIR}/render/runtime/RuntimeShaderProgram.h"
|
||||||
"${RENDER_CADENCE_APP_DIR}/render/SimpleMotionRenderer.cpp"
|
"${RENDER_CADENCE_APP_DIR}/render/SimpleMotionRenderer.cpp"
|
||||||
"${RENDER_CADENCE_APP_DIR}/render/SimpleMotionRenderer.h"
|
"${RENDER_CADENCE_APP_DIR}/render/SimpleMotionRenderer.h"
|
||||||
"${RENDER_CADENCE_APP_DIR}/runtime/RuntimeLayerModel.cpp"
|
"${RENDER_CADENCE_APP_DIR}/runtime/RuntimeLayerModel.cpp"
|
||||||
@@ -372,11 +372,14 @@ target_include_directories(RenderCadenceCompositor PRIVATE
|
|||||||
"${RENDER_CADENCE_APP_DIR}"
|
"${RENDER_CADENCE_APP_DIR}"
|
||||||
"${RENDER_CADENCE_APP_DIR}/app"
|
"${RENDER_CADENCE_APP_DIR}/app"
|
||||||
"${RENDER_CADENCE_APP_DIR}/control"
|
"${RENDER_CADENCE_APP_DIR}/control"
|
||||||
|
"${RENDER_CADENCE_APP_DIR}/control/http"
|
||||||
"${RENDER_CADENCE_APP_DIR}/frames"
|
"${RENDER_CADENCE_APP_DIR}/frames"
|
||||||
"${RENDER_CADENCE_APP_DIR}/json"
|
"${RENDER_CADENCE_APP_DIR}/json"
|
||||||
"${RENDER_CADENCE_APP_DIR}/logging"
|
"${RENDER_CADENCE_APP_DIR}/logging"
|
||||||
"${RENDER_CADENCE_APP_DIR}/platform"
|
"${RENDER_CADENCE_APP_DIR}/platform"
|
||||||
"${RENDER_CADENCE_APP_DIR}/render"
|
"${RENDER_CADENCE_APP_DIR}/render"
|
||||||
|
"${RENDER_CADENCE_APP_DIR}/render/readback"
|
||||||
|
"${RENDER_CADENCE_APP_DIR}/render/runtime"
|
||||||
"${RENDER_CADENCE_APP_DIR}/runtime"
|
"${RENDER_CADENCE_APP_DIR}/runtime"
|
||||||
"${RENDER_CADENCE_APP_DIR}/telemetry"
|
"${RENDER_CADENCE_APP_DIR}/telemetry"
|
||||||
"${RENDER_CADENCE_APP_DIR}/video"
|
"${RENDER_CADENCE_APP_DIR}/video"
|
||||||
@@ -815,7 +818,7 @@ endif()
|
|||||||
add_test(NAME RenderCadenceCompositorTelemetryTests COMMAND RenderCadenceCompositorTelemetryTests)
|
add_test(NAME RenderCadenceCompositorTelemetryTests COMMAND RenderCadenceCompositorTelemetryTests)
|
||||||
|
|
||||||
add_executable(RenderCadenceCompositorRuntimeShaderParamsTests
|
add_executable(RenderCadenceCompositorRuntimeShaderParamsTests
|
||||||
"${RENDER_CADENCE_APP_DIR}/render/RuntimeShaderParams.cpp"
|
"${RENDER_CADENCE_APP_DIR}/render/runtime/RuntimeShaderParams.cpp"
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/tests/RenderCadenceCompositorRuntimeShaderParamsTests.cpp"
|
"${CMAKE_CURRENT_SOURCE_DIR}/tests/RenderCadenceCompositorRuntimeShaderParamsTests.cpp"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -823,6 +826,7 @@ target_include_directories(RenderCadenceCompositorRuntimeShaderParamsTests PRIVA
|
|||||||
"${APP_DIR}/gl/shader"
|
"${APP_DIR}/gl/shader"
|
||||||
"${APP_DIR}/shader"
|
"${APP_DIR}/shader"
|
||||||
"${RENDER_CADENCE_APP_DIR}/render"
|
"${RENDER_CADENCE_APP_DIR}/render"
|
||||||
|
"${RENDER_CADENCE_APP_DIR}/render/runtime"
|
||||||
"${RENDER_CADENCE_APP_DIR}/runtime"
|
"${RENDER_CADENCE_APP_DIR}/runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -936,8 +940,8 @@ endif()
|
|||||||
add_test(NAME RenderCadenceCompositorRuntimeStateJsonTests COMMAND RenderCadenceCompositorRuntimeStateJsonTests)
|
add_test(NAME RenderCadenceCompositorRuntimeStateJsonTests COMMAND RenderCadenceCompositorRuntimeStateJsonTests)
|
||||||
|
|
||||||
add_executable(RenderCadenceCompositorHttpControlServerTests
|
add_executable(RenderCadenceCompositorHttpControlServerTests
|
||||||
"${RENDER_CADENCE_APP_DIR}/control/HttpControlServer.cpp"
|
"${RENDER_CADENCE_APP_DIR}/control/http/HttpControlServer.cpp"
|
||||||
"${RENDER_CADENCE_APP_DIR}/control/HttpControlServerWebSocket.cpp"
|
"${RENDER_CADENCE_APP_DIR}/control/http/HttpControlServerWebSocket.cpp"
|
||||||
"${RENDER_CADENCE_APP_DIR}/json/JsonWriter.cpp"
|
"${RENDER_CADENCE_APP_DIR}/json/JsonWriter.cpp"
|
||||||
"${RENDER_CADENCE_APP_DIR}/logging/Logger.cpp"
|
"${RENDER_CADENCE_APP_DIR}/logging/Logger.cpp"
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/tests/RenderCadenceCompositorHttpControlServerTests.cpp"
|
"${CMAKE_CURRENT_SOURCE_DIR}/tests/RenderCadenceCompositorHttpControlServerTests.cpp"
|
||||||
@@ -945,6 +949,7 @@ add_executable(RenderCadenceCompositorHttpControlServerTests
|
|||||||
|
|
||||||
target_include_directories(RenderCadenceCompositorHttpControlServerTests PRIVATE
|
target_include_directories(RenderCadenceCompositorHttpControlServerTests PRIVATE
|
||||||
"${RENDER_CADENCE_APP_DIR}/control"
|
"${RENDER_CADENCE_APP_DIR}/control"
|
||||||
|
"${RENDER_CADENCE_APP_DIR}/control/http"
|
||||||
"${RENDER_CADENCE_APP_DIR}/json"
|
"${RENDER_CADENCE_APP_DIR}/json"
|
||||||
"${RENDER_CADENCE_APP_DIR}/logging"
|
"${RENDER_CADENCE_APP_DIR}/logging"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -72,6 +72,49 @@ Intentionally not included yet:
|
|||||||
|
|
||||||
Those features should be ported only after the cadence spine is stable.
|
Those features should be ported only after the cadence spine is stable.
|
||||||
|
|
||||||
|
## V1 Feature Parity Checklist
|
||||||
|
|
||||||
|
This tracks parity with `apps/LoopThroughWithOpenGLCompositing`.
|
||||||
|
|
||||||
|
- [x] Stable DeckLink output cadence
|
||||||
|
- [x] BGRA8 system-memory output path
|
||||||
|
- [x] Render thread owns its primary GL context
|
||||||
|
- [x] Output startup warmup before scheduled playback
|
||||||
|
- [x] Non-blocking startup when DeckLink output is unavailable
|
||||||
|
- [x] Runtime shader package discovery
|
||||||
|
- [x] Background Slang shader compile
|
||||||
|
- [x] Shared-context GL shader/program preparation
|
||||||
|
- [x] Render-thread program swap at a frame boundary
|
||||||
|
- [x] Stateless single-pass shader rendering
|
||||||
|
- [x] Shader add/remove control path
|
||||||
|
- [x] Previous-layer texture handoff for stacked shaders
|
||||||
|
- [x] Supported shader list in HTTP/UI state
|
||||||
|
- [x] Local HTTP server
|
||||||
|
- [x] WebSocket state updates for the UI
|
||||||
|
- [x] OpenAPI document serving
|
||||||
|
- [x] Static control UI serving
|
||||||
|
- [x] Startup config loading from `config/runtime-host.json`
|
||||||
|
- [x] Cadence telemetry JSON
|
||||||
|
- [x] Health logging for schedule/drop/starvation events
|
||||||
|
- [ ] DeckLink input capture
|
||||||
|
- [ ] Input frame upload into the render scene
|
||||||
|
- [ ] Live video input bound to `gVideoInput`
|
||||||
|
- [ ] Multipass shader rendering
|
||||||
|
- [ ] Temporal history buffers
|
||||||
|
- [ ] Feedback buffers
|
||||||
|
- [ ] Texture asset loading and upload
|
||||||
|
- [ ] LUT asset loading and upload
|
||||||
|
- [ ] Text parameter rasterization
|
||||||
|
- [ ] Runtime parameter updates from controls
|
||||||
|
- [ ] Layer reorder/bypass/set-shader/update-parameter/reset-parameter controls
|
||||||
|
- [ ] Full runtime state store/read model
|
||||||
|
- [ ] Persistent layer stack/config writes
|
||||||
|
- [ ] OSC ingress
|
||||||
|
- [ ] Preview output
|
||||||
|
- [ ] Screenshot capture
|
||||||
|
- [ ] External keying support
|
||||||
|
- [ ] Full V1 health/runtime presentation model
|
||||||
|
|
||||||
## Build
|
## Build
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
@@ -209,13 +252,14 @@ Current runtime shader support is deliberately limited to stateless single-pass
|
|||||||
- no texture/LUT assets yet
|
- no texture/LUT assets yet
|
||||||
- no text parameters yet
|
- no text parameters yet
|
||||||
- manifest defaults are used for parameters
|
- manifest defaults are used for parameters
|
||||||
- `gVideoInput` and `gLayerInput` are bound to a small fallback source texture until DeckLink input is added
|
- the first layer receives a small fallback source texture until DeckLink input is added
|
||||||
|
- stacked layers receive the previous ready layer output through both `gVideoInput` and `gLayerInput`
|
||||||
|
|
||||||
The `/api/state` shader list uses the same support rules as runtime shader compilation and reports only packages this app can run today. Unsupported manifest feature sets such as multipass, temporal, feedback, texture-backed, font-backed, or text-parameter shaders are hidden from the control UI for now.
|
The `/api/state` shader list uses the same support rules as runtime shader compilation and reports only packages this app can run today. Unsupported manifest feature sets such as multipass, temporal, feedback, texture-backed, font-backed, or text-parameter shaders are hidden from the control UI for now.
|
||||||
|
|
||||||
Runtime shaders are exposed through `RuntimeLayerModel` as display layers with manifest parameter defaults. The model also records whether each layer has a render-ready artifact. Add/remove POST controls mutate this app-owned model and may start background shader builds.
|
Runtime shaders are exposed through `RuntimeLayerModel` as display layers with manifest parameter defaults. The model also records whether each layer has a render-ready artifact. Add/remove POST controls mutate this app-owned model and may start background shader builds.
|
||||||
|
|
||||||
When a layer becomes render-ready, the app publishes the ready render-layer snapshot to the render thread. The render thread owns the GL-side `RuntimeRenderScene`, diffs that snapshot at a frame boundary, queues new or changed programs to the shared-context prepare worker, swaps in prepared programs when available, removes obsolete GL programs, and renders ready layers in order. Current layer rendering is still deliberately simple: each stateless full-frame shader draws to the output target using fallback source textures until proper layer-input texture handoff is designed.
|
When a layer becomes render-ready, the app publishes the ready render-layer snapshot to the render thread. The render thread owns the GL-side `RuntimeRenderScene`, diffs that snapshot at a frame boundary, queues new or changed programs to the shared-context prepare worker, swaps in prepared programs when available, removes obsolete GL programs, and renders ready layers in order. Stacked stateless full-frame shaders render through internal ping-pong targets so each layer can sample the previous layer through `gLayerInput`; the final ready layer renders to the output target.
|
||||||
|
|
||||||
Successful handoff signs:
|
Successful handoff signs:
|
||||||
|
|
||||||
@@ -264,11 +308,13 @@ This app keeps the same core behavior but splits it into modules that can grow:
|
|||||||
|
|
||||||
- `frames/`: system-memory handoff
|
- `frames/`: system-memory handoff
|
||||||
- `platform/`: COM/Win32/hidden GL context support
|
- `platform/`: COM/Win32/hidden GL context support
|
||||||
- `render/`: cadence, simple rendering, PBO readback
|
- `render/`: cadence thread, clock, and simple renderer
|
||||||
- `render/RuntimeRenderScene`: render-thread-owned GL scene for ready runtime shader layers
|
- `render/readback/`: PBO-backed BGRA8 readback and completed-frame publication
|
||||||
- `render/RuntimeShaderPrepareWorker`: shared-context runtime shader program compile/link worker
|
- `render/runtime/RuntimeRenderScene`: render-thread-owned GL scene for ready runtime shader layers
|
||||||
|
- `render/runtime/RuntimeShaderPrepareWorker`: shared-context runtime shader program compile/link worker
|
||||||
- `runtime/`: app-owned shader layer readiness model, runtime Slang build bridge, and completed artifact handoff
|
- `runtime/`: app-owned shader layer readiness model, runtime Slang build bridge, and completed artifact handoff
|
||||||
- `control/`: local HTTP API edge and runtime-state JSON presentation
|
- `control/`: control action results and runtime-state JSON presentation
|
||||||
|
- `control/http/`: local HTTP API, static UI serving, OpenAPI serving, and WebSocket updates
|
||||||
- `json/`: compact JSON serialization helpers
|
- `json/`: compact JSON serialization helpers
|
||||||
- `video/`: DeckLink output wrapper and scheduling thread
|
- `video/`: DeckLink output wrapper and scheduling thread
|
||||||
- `telemetry/`: cadence telemetry
|
- `telemetry/`: cadence telemetry
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "../control/HttpControlServer.h"
|
#include "../control/http/HttpControlServer.h"
|
||||||
#include "../logging/Logger.h"
|
#include "../logging/Logger.h"
|
||||||
#include "../telemetry/TelemetryHealthMonitor.h"
|
#include "../telemetry/TelemetryHealthMonitor.h"
|
||||||
#include "../video/DeckLinkOutput.h"
|
#include "../video/DeckLinkOutput.h"
|
||||||
|
|||||||
@@ -4,10 +4,10 @@
|
|||||||
#include "../frames/SystemFrameTypes.h"
|
#include "../frames/SystemFrameTypes.h"
|
||||||
#include "../logging/Logger.h"
|
#include "../logging/Logger.h"
|
||||||
#include "../platform/HiddenGlWindow.h"
|
#include "../platform/HiddenGlWindow.h"
|
||||||
#include "Bgra8ReadbackPipeline.h"
|
#include "readback/Bgra8ReadbackPipeline.h"
|
||||||
#include "GLExtensions.h"
|
#include "GLExtensions.h"
|
||||||
#include "RuntimeRenderScene.h"
|
#include "runtime/RuntimeRenderScene.h"
|
||||||
#include "RuntimeShaderRenderer.h"
|
#include "runtime/RuntimeShaderRenderer.h"
|
||||||
#include "SimpleMotionRenderer.h"
|
#include "SimpleMotionRenderer.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
#include "RenderCadenceClock.h"
|
#include "RenderCadenceClock.h"
|
||||||
#include "../runtime/RuntimeLayerModel.h"
|
#include "../runtime/RuntimeLayerModel.h"
|
||||||
#include "../runtime/RuntimeShaderArtifact.h"
|
#include "../runtime/RuntimeShaderArtifact.h"
|
||||||
#include "RuntimeRenderScene.h"
|
#include "runtime/RuntimeRenderScene.h"
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <condition_variable>
|
#include <condition_variable>
|
||||||
|
|||||||
@@ -1,11 +1,15 @@
|
|||||||
#include "RuntimeRenderScene.h"
|
#include "RuntimeRenderScene.h"
|
||||||
|
|
||||||
#include "../platform/HiddenGlWindow.h"
|
#include "../../platform/HiddenGlWindow.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
|
#ifndef GL_FRAMEBUFFER_BINDING
|
||||||
|
#define GL_FRAMEBUFFER_BINDING 0x8CA6
|
||||||
|
#endif
|
||||||
|
|
||||||
RuntimeRenderScene::~RuntimeRenderScene()
|
RuntimeRenderScene::~RuntimeRenderScene()
|
||||||
{
|
{
|
||||||
ShutdownGl();
|
ShutdownGl();
|
||||||
@@ -90,12 +94,50 @@ void RuntimeRenderScene::RenderFrame(uint64_t frameIndex, unsigned width, unsign
|
|||||||
{
|
{
|
||||||
ConsumePreparedPrograms();
|
ConsumePreparedPrograms();
|
||||||
|
|
||||||
|
std::vector<LayerProgram*> readyLayers;
|
||||||
for (const std::string& layerId : mLayerOrder)
|
for (const std::string& layerId : mLayerOrder)
|
||||||
{
|
{
|
||||||
LayerProgram* layer = FindLayer(layerId);
|
LayerProgram* layer = FindLayer(layerId);
|
||||||
if (!layer || !layer->renderer || !layer->renderer->HasProgram())
|
if (!layer || !layer->renderer || !layer->renderer->HasProgram())
|
||||||
continue;
|
continue;
|
||||||
layer->renderer->RenderFrame(frameIndex, width, height);
|
readyLayers.push_back(layer);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (readyLayers.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
GLint outputFramebuffer = 0;
|
||||||
|
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &outputFramebuffer);
|
||||||
|
|
||||||
|
if (readyLayers.size() == 1)
|
||||||
|
{
|
||||||
|
readyLayers.front()->renderer->RenderFrame(frameIndex, width, height);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!EnsureLayerTargets(width, height))
|
||||||
|
{
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, static_cast<GLuint>(outputFramebuffer));
|
||||||
|
readyLayers.back()->renderer->RenderFrame(frameIndex, width, height);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLuint layerInputTexture = 0;
|
||||||
|
std::size_t nextTargetIndex = 0;
|
||||||
|
for (std::size_t layerIndex = 0; layerIndex < readyLayers.size(); ++layerIndex)
|
||||||
|
{
|
||||||
|
const bool isFinalLayer = layerIndex == readyLayers.size() - 1;
|
||||||
|
if (isFinalLayer)
|
||||||
|
{
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, static_cast<GLuint>(outputFramebuffer));
|
||||||
|
readyLayers[layerIndex]->renderer->RenderFrame(frameIndex, width, height, layerInputTexture, layerInputTexture);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, mLayerFramebuffers[nextTargetIndex]);
|
||||||
|
readyLayers[layerIndex]->renderer->RenderFrame(frameIndex, width, height, layerInputTexture, layerInputTexture);
|
||||||
|
layerInputTexture = mLayerTextures[nextTargetIndex];
|
||||||
|
nextTargetIndex = 1 - nextTargetIndex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,6 +151,7 @@ void RuntimeRenderScene::ShutdownGl()
|
|||||||
}
|
}
|
||||||
mLayers.clear();
|
mLayers.clear();
|
||||||
mLayerOrder.clear();
|
mLayerOrder.clear();
|
||||||
|
DestroyLayerTargets();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RuntimeRenderScene::ConsumePreparedPrograms()
|
void RuntimeRenderScene::ConsumePreparedPrograms()
|
||||||
@@ -146,6 +189,68 @@ void RuntimeRenderScene::ConsumePreparedPrograms()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool RuntimeRenderScene::EnsureLayerTargets(unsigned width, unsigned height)
|
||||||
|
{
|
||||||
|
if (width == 0 || height == 0)
|
||||||
|
return false;
|
||||||
|
if (mLayerFramebuffers[0] != 0 && mLayerFramebuffers[1] != 0 && mLayerTextures[0] != 0 && mLayerTextures[1] != 0
|
||||||
|
&& mLayerTargetWidth == width && mLayerTargetHeight == height)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
DestroyLayerTargets();
|
||||||
|
mLayerTargetWidth = width;
|
||||||
|
mLayerTargetHeight = height;
|
||||||
|
|
||||||
|
glGenFramebuffers(2, mLayerFramebuffers);
|
||||||
|
glGenTextures(2, mLayerTextures);
|
||||||
|
for (int index = 0; index < 2; ++index)
|
||||||
|
{
|
||||||
|
glBindTexture(GL_TEXTURE_2D, mLayerTextures[index]);
|
||||||
|
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>(width),
|
||||||
|
static_cast<GLsizei>(height),
|
||||||
|
0,
|
||||||
|
GL_BGRA,
|
||||||
|
GL_UNSIGNED_INT_8_8_8_8_REV,
|
||||||
|
nullptr);
|
||||||
|
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, mLayerFramebuffers[index]);
|
||||||
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mLayerTextures[index], 0);
|
||||||
|
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
|
||||||
|
{
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
DestroyLayerTargets();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RuntimeRenderScene::DestroyLayerTargets()
|
||||||
|
{
|
||||||
|
if (mLayerFramebuffers[0] != 0 || mLayerFramebuffers[1] != 0)
|
||||||
|
glDeleteFramebuffers(2, mLayerFramebuffers);
|
||||||
|
if (mLayerTextures[0] != 0 || mLayerTextures[1] != 0)
|
||||||
|
glDeleteTextures(2, mLayerTextures);
|
||||||
|
mLayerFramebuffers[0] = 0;
|
||||||
|
mLayerFramebuffers[1] = 0;
|
||||||
|
mLayerTextures[0] = 0;
|
||||||
|
mLayerTextures[1] = 0;
|
||||||
|
mLayerTargetWidth = 0;
|
||||||
|
mLayerTargetHeight = 0;
|
||||||
|
}
|
||||||
|
|
||||||
RuntimeRenderScene::LayerProgram* RuntimeRenderScene::FindLayer(const std::string& layerId)
|
RuntimeRenderScene::LayerProgram* RuntimeRenderScene::FindLayer(const std::string& layerId)
|
||||||
{
|
{
|
||||||
for (LayerProgram& layer : mLayers)
|
for (LayerProgram& layer : mLayers)
|
||||||
@@ -36,6 +36,8 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
void ConsumePreparedPrograms();
|
void ConsumePreparedPrograms();
|
||||||
|
bool EnsureLayerTargets(unsigned width, unsigned height);
|
||||||
|
void DestroyLayerTargets();
|
||||||
LayerProgram* FindLayer(const std::string& layerId);
|
LayerProgram* FindLayer(const std::string& layerId);
|
||||||
const LayerProgram* FindLayer(const std::string& layerId) const;
|
const LayerProgram* FindLayer(const std::string& layerId) const;
|
||||||
static std::string Fingerprint(const RuntimeShaderArtifact& artifact);
|
static std::string Fingerprint(const RuntimeShaderArtifact& artifact);
|
||||||
@@ -43,4 +45,8 @@ private:
|
|||||||
RuntimeShaderPrepareWorker mPrepareWorker;
|
RuntimeShaderPrepareWorker mPrepareWorker;
|
||||||
std::vector<LayerProgram> mLayers;
|
std::vector<LayerProgram> mLayers;
|
||||||
std::vector<std::string> mLayerOrder;
|
std::vector<std::string> mLayerOrder;
|
||||||
|
GLuint mLayerFramebuffers[2] = {};
|
||||||
|
GLuint mLayerTextures[2] = {};
|
||||||
|
unsigned mLayerTargetWidth = 0;
|
||||||
|
unsigned mLayerTargetHeight = 0;
|
||||||
};
|
};
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
#include "RuntimeShaderPrepareWorker.h"
|
#include "RuntimeShaderPrepareWorker.h"
|
||||||
|
|
||||||
#include "../platform/HiddenGlWindow.h"
|
#include "../../platform/HiddenGlWindow.h"
|
||||||
#include "RuntimeShaderRenderer.h"
|
#include "RuntimeShaderRenderer.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "RuntimeShaderProgram.h"
|
#include "RuntimeShaderProgram.h"
|
||||||
#include "../runtime/RuntimeLayerModel.h"
|
#include "../../runtime/RuntimeLayerModel.h"
|
||||||
|
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "GLExtensions.h"
|
#include "GLExtensions.h"
|
||||||
#include "../runtime/RuntimeShaderArtifact.h"
|
#include "../../runtime/RuntimeShaderArtifact.h"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
@@ -9,7 +9,8 @@
|
|||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
constexpr GLuint kGlobalParamsBindingPoint = 0;
|
constexpr GLuint kGlobalParamsBindingPoint = 0;
|
||||||
constexpr GLuint kSourceTextureUnit = 0;
|
constexpr GLuint kVideoInputTextureUnit = 0;
|
||||||
|
constexpr GLuint kLayerInputTextureUnit = 1;
|
||||||
|
|
||||||
const char* kVertexShaderSource = R"GLSL(
|
const char* kVertexShaderSource = R"GLSL(
|
||||||
#version 430 core
|
#version 430 core
|
||||||
@@ -127,7 +128,7 @@ bool RuntimeShaderRenderer::BuildPreparedProgram(
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RuntimeShaderRenderer::RenderFrame(uint64_t frameIndex, unsigned width, unsigned height)
|
void RuntimeShaderRenderer::RenderFrame(uint64_t frameIndex, unsigned width, unsigned height, GLuint sourceTexture, GLuint layerInputTexture)
|
||||||
{
|
{
|
||||||
if (mProgram == 0)
|
if (mProgram == 0)
|
||||||
return;
|
return;
|
||||||
@@ -137,7 +138,7 @@ void RuntimeShaderRenderer::RenderFrame(uint64_t frameIndex, unsigned width, uns
|
|||||||
glDisable(GL_DEPTH_TEST);
|
glDisable(GL_DEPTH_TEST);
|
||||||
glDisable(GL_BLEND);
|
glDisable(GL_BLEND);
|
||||||
UpdateGlobalParams(frameIndex, width, height);
|
UpdateGlobalParams(frameIndex, width, height);
|
||||||
BindRuntimeTextures();
|
BindRuntimeTextures(sourceTexture, layerInputTexture);
|
||||||
glBindVertexArray(mVertexArray);
|
glBindVertexArray(mVertexArray);
|
||||||
glUseProgram(mProgram);
|
glUseProgram(mProgram);
|
||||||
glDrawArrays(GL_TRIANGLES, 0, 3);
|
glDrawArrays(GL_TRIANGLES, 0, 3);
|
||||||
@@ -236,16 +237,16 @@ void RuntimeShaderRenderer::AssignSamplerUniforms(GLuint program)
|
|||||||
glUseProgram(program);
|
glUseProgram(program);
|
||||||
const GLint videoInputLocation = glGetUniformLocation(program, "gVideoInput");
|
const GLint videoInputLocation = glGetUniformLocation(program, "gVideoInput");
|
||||||
if (videoInputLocation >= 0)
|
if (videoInputLocation >= 0)
|
||||||
glUniform1i(videoInputLocation, static_cast<GLint>(kSourceTextureUnit));
|
glUniform1i(videoInputLocation, static_cast<GLint>(kVideoInputTextureUnit));
|
||||||
const GLint videoInputArrayLocation = glGetUniformLocation(program, "gVideoInput_0");
|
const GLint videoInputArrayLocation = glGetUniformLocation(program, "gVideoInput_0");
|
||||||
if (videoInputArrayLocation >= 0)
|
if (videoInputArrayLocation >= 0)
|
||||||
glUniform1i(videoInputArrayLocation, static_cast<GLint>(kSourceTextureUnit));
|
glUniform1i(videoInputArrayLocation, static_cast<GLint>(kVideoInputTextureUnit));
|
||||||
const GLint layerInputLocation = glGetUniformLocation(program, "gLayerInput");
|
const GLint layerInputLocation = glGetUniformLocation(program, "gLayerInput");
|
||||||
if (layerInputLocation >= 0)
|
if (layerInputLocation >= 0)
|
||||||
glUniform1i(layerInputLocation, static_cast<GLint>(kSourceTextureUnit));
|
glUniform1i(layerInputLocation, static_cast<GLint>(kLayerInputTextureUnit));
|
||||||
const GLint layerInputArrayLocation = glGetUniformLocation(program, "gLayerInput_0");
|
const GLint layerInputArrayLocation = glGetUniformLocation(program, "gLayerInput_0");
|
||||||
if (layerInputArrayLocation >= 0)
|
if (layerInputArrayLocation >= 0)
|
||||||
glUniform1i(layerInputArrayLocation, static_cast<GLint>(kSourceTextureUnit));
|
glUniform1i(layerInputArrayLocation, static_cast<GLint>(kLayerInputTextureUnit));
|
||||||
glUseProgram(0);
|
glUseProgram(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -268,10 +269,14 @@ void RuntimeShaderRenderer::UpdateGlobalParams(uint64_t frameIndex, unsigned wid
|
|||||||
glBindBuffer(GL_UNIFORM_BUFFER, 0);
|
glBindBuffer(GL_UNIFORM_BUFFER, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RuntimeShaderRenderer::BindRuntimeTextures()
|
void RuntimeShaderRenderer::BindRuntimeTextures(GLuint sourceTexture, GLuint layerInputTexture)
|
||||||
{
|
{
|
||||||
glActiveTexture(GL_TEXTURE0 + kSourceTextureUnit);
|
const GLuint resolvedSourceTexture = sourceTexture != 0 ? sourceTexture : mFallbackSourceTexture;
|
||||||
glBindTexture(GL_TEXTURE_2D, mFallbackSourceTexture);
|
const GLuint resolvedLayerInputTexture = layerInputTexture != 0 ? layerInputTexture : resolvedSourceTexture;
|
||||||
|
glActiveTexture(GL_TEXTURE0 + kVideoInputTextureUnit);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, resolvedSourceTexture);
|
||||||
|
glActiveTexture(GL_TEXTURE0 + kLayerInputTextureUnit);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, resolvedLayerInputTexture);
|
||||||
glActiveTexture(GL_TEXTURE0);
|
glActiveTexture(GL_TEXTURE0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
#include "GLExtensions.h"
|
#include "GLExtensions.h"
|
||||||
#include "RuntimeShaderProgram.h"
|
#include "RuntimeShaderProgram.h"
|
||||||
#include "../runtime/RuntimeShaderArtifact.h"
|
#include "../../runtime/RuntimeShaderArtifact.h"
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <string>
|
#include <string>
|
||||||
@@ -20,7 +20,7 @@ public:
|
|||||||
bool CommitShaderArtifact(const RuntimeShaderArtifact& artifact, std::string& error);
|
bool CommitShaderArtifact(const RuntimeShaderArtifact& artifact, std::string& error);
|
||||||
bool CommitPreparedProgram(RuntimePreparedShaderProgram& preparedProgram, std::string& error);
|
bool CommitPreparedProgram(RuntimePreparedShaderProgram& preparedProgram, std::string& error);
|
||||||
bool HasProgram() const { return mProgram != 0; }
|
bool HasProgram() const { return mProgram != 0; }
|
||||||
void RenderFrame(uint64_t frameIndex, unsigned width, unsigned height);
|
void RenderFrame(uint64_t frameIndex, unsigned width, unsigned height, GLuint sourceTexture = 0, GLuint layerInputTexture = 0);
|
||||||
void ShutdownGl();
|
void ShutdownGl();
|
||||||
|
|
||||||
static bool BuildPreparedProgram(
|
static bool BuildPreparedProgram(
|
||||||
@@ -35,7 +35,7 @@ private:
|
|||||||
static bool BuildProgram(const std::string& fragmentShaderSource, GLuint& program, GLuint& vertexShader, GLuint& fragmentShader, std::string& error);
|
static bool BuildProgram(const std::string& fragmentShaderSource, GLuint& program, GLuint& vertexShader, GLuint& fragmentShader, std::string& error);
|
||||||
static void AssignSamplerUniforms(GLuint program);
|
static void AssignSamplerUniforms(GLuint program);
|
||||||
void UpdateGlobalParams(uint64_t frameIndex, unsigned width, unsigned height);
|
void UpdateGlobalParams(uint64_t frameIndex, unsigned width, unsigned height);
|
||||||
void BindRuntimeTextures();
|
void BindRuntimeTextures(GLuint sourceTexture, GLuint layerInputTexture);
|
||||||
void DestroyProgram();
|
void DestroyProgram();
|
||||||
void DestroyStaticGlResources();
|
void DestroyStaticGlResources();
|
||||||
|
|
||||||
@@ -40,12 +40,12 @@ float4 sampleWarped(float2 uv, float2 resolution, out bool insideSource)
|
|||||||
insideSource = uv.x >= 0.0 && uv.x <= 1.0 && uv.y >= 0.0 && uv.y <= 1.0;
|
insideSource = uv.x >= 0.0 && uv.x <= 1.0 && uv.y >= 0.0 && uv.y <= 1.0;
|
||||||
|
|
||||||
if (edgeMode == 1)
|
if (edgeMode == 1)
|
||||||
return sampleVideo(clamp(uv, 0.0, 1.0));
|
return sampleLayerInput(clamp(uv, 0.0, 1.0));
|
||||||
if (edgeMode == 2)
|
if (edgeMode == 2)
|
||||||
return sampleVideo(float2(mirroredCoordinate(uv.x), mirroredCoordinate(uv.y)));
|
return sampleLayerInput(float2(mirroredCoordinate(uv.x), mirroredCoordinate(uv.y)));
|
||||||
|
|
||||||
float edgeMask = sourceBoundsMask(uv, resolution);
|
float edgeMask = sourceBoundsMask(uv, resolution);
|
||||||
float4 color = sampleVideo(clamp(uv, 0.0, 1.0));
|
float4 color = sampleLayerInput(clamp(uv, 0.0, 1.0));
|
||||||
return lerp(outsideColor, color, edgeMask);
|
return lerp(outsideColor, color, edgeMask);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user