Phase 4 step 1
This commit is contained in:
@@ -195,9 +195,15 @@ bool RenderEngine::TryPresentPreview(bool force, unsigned previewFps, unsigned o
|
|||||||
if (!TryEnterCriticalSection(&mMutex))
|
if (!TryEnterCriticalSection(&mMutex))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
const bool presented = PresentPreviewOnRenderThread(outputFrameWidth, outputFrameHeight);
|
||||||
|
LeaveCriticalSection(&mMutex);
|
||||||
|
return presented;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RenderEngine::PresentPreviewOnRenderThread(unsigned outputFrameWidth, unsigned outputFrameHeight)
|
||||||
|
{
|
||||||
mRenderer.PresentToWindow(mHdc, outputFrameWidth, outputFrameHeight);
|
mRenderer.PresentToWindow(mHdc, outputFrameWidth, outputFrameHeight);
|
||||||
mLastPreviewPresentTime = std::chrono::steady_clock::now();
|
mLastPreviewPresentTime = std::chrono::steady_clock::now();
|
||||||
LeaveCriticalSection(&mMutex);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -206,12 +212,19 @@ bool RenderEngine::TryUploadInputFrame(const VideoIOFrame& inputFrame, const Vid
|
|||||||
if (inputFrame.hasNoInputSource || inputFrame.bytes == nullptr)
|
if (inputFrame.hasNoInputSource || inputFrame.bytes == nullptr)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
const long textureSize = inputFrame.rowBytes * static_cast<long>(inputFrame.height);
|
|
||||||
if (!TryEnterCriticalSection(&mMutex))
|
if (!TryEnterCriticalSection(&mMutex))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
wglMakeCurrent(mHdc, mHglrc);
|
wglMakeCurrent(mHdc, mHglrc);
|
||||||
|
const bool uploaded = UploadInputFrameOnRenderThread(inputFrame, videoState);
|
||||||
|
wglMakeCurrent(NULL, NULL);
|
||||||
|
LeaveCriticalSection(&mMutex);
|
||||||
|
return uploaded;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RenderEngine::UploadInputFrameOnRenderThread(const VideoIOFrame& inputFrame, const VideoIOState& videoState)
|
||||||
|
{
|
||||||
|
const long textureSize = inputFrame.rowBytes * static_cast<long>(inputFrame.height);
|
||||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
|
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
|
||||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
||||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, mRenderer.TextureUploadBuffer());
|
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, mRenderer.TextureUploadBuffer());
|
||||||
@@ -224,8 +237,6 @@ bool RenderEngine::TryUploadInputFrame(const VideoIOFrame& inputFrame, const Vid
|
|||||||
glBindTexture(GL_TEXTURE_2D, 0);
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
|
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
|
||||||
|
|
||||||
wglMakeCurrent(NULL, NULL);
|
|
||||||
LeaveCriticalSection(&mMutex);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -233,12 +244,17 @@ bool RenderEngine::RenderOutputFrame(const RenderPipelineFrameContext& context,
|
|||||||
{
|
{
|
||||||
EnterCriticalSection(&mMutex);
|
EnterCriticalSection(&mMutex);
|
||||||
wglMakeCurrent(mHdc, mHglrc);
|
wglMakeCurrent(mHdc, mHglrc);
|
||||||
const bool rendered = mRenderPipeline.RenderFrame(context, outputFrame);
|
const bool rendered = RenderOutputFrameOnRenderThread(context, outputFrame);
|
||||||
wglMakeCurrent(NULL, NULL);
|
wglMakeCurrent(NULL, NULL);
|
||||||
LeaveCriticalSection(&mMutex);
|
LeaveCriticalSection(&mMutex);
|
||||||
return rendered;
|
return rendered;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool RenderEngine::RenderOutputFrameOnRenderThread(const RenderPipelineFrameContext& context, VideoIOOutputFrame& outputFrame)
|
||||||
|
{
|
||||||
|
return mRenderPipeline.RenderFrame(context, outputFrame);
|
||||||
|
}
|
||||||
|
|
||||||
bool RenderEngine::ResolveRenderFrameState(
|
bool RenderEngine::ResolveRenderFrameState(
|
||||||
const RenderFrameInput& input,
|
const RenderFrameInput& input,
|
||||||
std::vector<OscOverlayCommitRequest>* commitRequests,
|
std::vector<OscOverlayCommitRequest>* commitRequests,
|
||||||
@@ -297,14 +313,11 @@ void RenderEngine::RenderLayerStack(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RenderEngine::ReadOutputFrameRgba(unsigned width, unsigned height, std::vector<unsigned char>& bottomUpPixels)
|
bool RenderEngine::ReadOutputFrameRgbaOnRenderThread(unsigned width, unsigned height, std::vector<unsigned char>& bottomUpPixels)
|
||||||
{
|
{
|
||||||
if (width == 0 || height == 0)
|
if (width == 0 || height == 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
EnterCriticalSection(&mMutex);
|
|
||||||
wglMakeCurrent(mHdc, mHglrc);
|
|
||||||
|
|
||||||
bottomUpPixels.resize(static_cast<std::size_t>(width) * height * 4);
|
bottomUpPixels.resize(static_cast<std::size_t>(width) * height * 4);
|
||||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, mRenderer.OutputFramebuffer());
|
glBindFramebuffer(GL_READ_FRAMEBUFFER, mRenderer.OutputFramebuffer());
|
||||||
glReadBuffer(GL_COLOR_ATTACHMENT0);
|
glReadBuffer(GL_COLOR_ATTACHMENT0);
|
||||||
@@ -313,15 +326,23 @@ bool RenderEngine::ReadOutputFrameRgba(unsigned width, unsigned height, std::vec
|
|||||||
glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, bottomUpPixels.data());
|
glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, bottomUpPixels.data());
|
||||||
glPixelStorei(GL_PACK_ALIGNMENT, 4);
|
glPixelStorei(GL_PACK_ALIGNMENT, 4);
|
||||||
|
|
||||||
wglMakeCurrent(NULL, NULL);
|
|
||||||
LeaveCriticalSection(&mMutex);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RenderEngine::CaptureOutputFrameRgbaTopDown(unsigned width, unsigned height, std::vector<unsigned char>& topDownPixels)
|
bool RenderEngine::CaptureOutputFrameRgbaTopDown(unsigned width, unsigned height, std::vector<unsigned char>& topDownPixels)
|
||||||
|
{
|
||||||
|
EnterCriticalSection(&mMutex);
|
||||||
|
wglMakeCurrent(mHdc, mHglrc);
|
||||||
|
const bool captured = CaptureOutputFrameRgbaTopDownOnRenderThread(width, height, topDownPixels);
|
||||||
|
wglMakeCurrent(NULL, NULL);
|
||||||
|
LeaveCriticalSection(&mMutex);
|
||||||
|
return captured;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RenderEngine::CaptureOutputFrameRgbaTopDownOnRenderThread(unsigned width, unsigned height, std::vector<unsigned char>& topDownPixels)
|
||||||
{
|
{
|
||||||
std::vector<unsigned char> bottomUpPixels;
|
std::vector<unsigned char> bottomUpPixels;
|
||||||
if (!ReadOutputFrameRgba(width, height, bottomUpPixels))
|
if (!ReadOutputFrameRgbaOnRenderThread(width, height, bottomUpPixels))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
topDownPixels.resize(bottomUpPixels.size());
|
topDownPixels.resize(bottomUpPixels.size());
|
||||||
|
|||||||
@@ -118,10 +118,15 @@ public:
|
|||||||
unsigned captureTextureWidth,
|
unsigned captureTextureWidth,
|
||||||
VideoIOPixelFormat inputPixelFormat,
|
VideoIOPixelFormat inputPixelFormat,
|
||||||
unsigned historyCap);
|
unsigned historyCap);
|
||||||
bool ReadOutputFrameRgba(unsigned width, unsigned height, std::vector<unsigned char>& bottomUpPixels);
|
|
||||||
bool CaptureOutputFrameRgbaTopDown(unsigned width, unsigned height, std::vector<unsigned char>& topDownPixels);
|
bool CaptureOutputFrameRgbaTopDown(unsigned width, unsigned height, std::vector<unsigned char>& topDownPixels);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
bool PresentPreviewOnRenderThread(unsigned outputFrameWidth, unsigned outputFrameHeight);
|
||||||
|
bool UploadInputFrameOnRenderThread(const VideoIOFrame& inputFrame, const VideoIOState& videoState);
|
||||||
|
bool RenderOutputFrameOnRenderThread(const RenderPipelineFrameContext& context, VideoIOOutputFrame& outputFrame);
|
||||||
|
bool ReadOutputFrameRgbaOnRenderThread(unsigned width, unsigned height, std::vector<unsigned char>& bottomUpPixels);
|
||||||
|
bool CaptureOutputFrameRgbaTopDownOnRenderThread(unsigned width, unsigned height, std::vector<unsigned char>& topDownPixels);
|
||||||
|
|
||||||
OpenGLRenderer mRenderer;
|
OpenGLRenderer mRenderer;
|
||||||
OpenGLRenderPass mRenderPass;
|
OpenGLRenderPass mRenderPass;
|
||||||
OpenGLRenderPipeline mRenderPipeline;
|
OpenGLRenderPipeline mRenderPipeline;
|
||||||
|
|||||||
@@ -7,12 +7,12 @@ Phase 1 named the subsystems. Phase 2 added the typed event substrate. Phase 3 m
|
|||||||
## Status
|
## Status
|
||||||
|
|
||||||
- Phase 4 design package: proposed.
|
- Phase 4 design package: proposed.
|
||||||
- Phase 4 implementation: not started.
|
- Phase 4 implementation: Step 1 started. The existing synchronous `RenderEngine` entrypoints now delegate their GL bodies to named `...OnRenderThread(...)` helpers, but no command queue or dedicated render thread exists yet.
|
||||||
- Current alignment: the repo has a named frame-state contract and cleaner render-state preparation, but GL work is still entered through multiple paths protected by one shared `CRITICAL_SECTION`.
|
- Current alignment: the repo has a named frame-state contract and cleaner render-state preparation, but GL work is still entered through multiple paths protected by one shared `CRITICAL_SECTION`.
|
||||||
|
|
||||||
Current GL ownership footholds:
|
Current GL ownership footholds:
|
||||||
|
|
||||||
- `RenderEngine` owns GL resources and the current context-binding helpers.
|
- `RenderEngine` owns GL resources, the current context-binding compatibility shims, and named render-thread helper methods.
|
||||||
- `RenderFrameInput` / `RenderFrameState` provide the frame-state contract that a render thread can consume.
|
- `RenderFrameInput` / `RenderFrameState` provide the frame-state contract that a render thread can consume.
|
||||||
- `RenderFrameStateResolver` prepares the render-facing layer state before drawing.
|
- `RenderFrameStateResolver` prepares the render-facing layer state before drawing.
|
||||||
- `OpenGLVideoIOBridge` still calls `RenderEngine::TryUploadInputFrame(...)` from the input path and `RenderEngine::RenderOutputFrame(...)` from the output path.
|
- `OpenGLVideoIOBridge` still calls `RenderEngine::TryUploadInputFrame(...)` from the input path and `RenderEngine::RenderOutputFrame(...)` from the output path.
|
||||||
@@ -64,10 +64,10 @@ The current code paths that matter most are:
|
|||||||
|
|
||||||
| Entry point | Current behavior | Phase 4 direction |
|
| Entry point | Current behavior | Phase 4 direction |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| `RenderEngine::TryUploadInputFrame(...)` | attempts to take the GL lock, binds the context, uploads input texture | enqueue latest input frame; render thread uploads |
|
| `RenderEngine::TryUploadInputFrame(...)` | attempts to take the GL lock, binds the context, delegates upload to `UploadInputFrameOnRenderThread(...)` | enqueue latest input frame; render thread uploads |
|
||||||
| `RenderEngine::RenderOutputFrame(...)` | takes the GL lock, binds the context, renders, packs/readbacks output | render thread executes output frame production |
|
| `RenderEngine::RenderOutputFrame(...)` | takes the GL lock, binds the context, delegates render/readback to `RenderOutputFrameOnRenderThread(...)` | render thread executes output frame production |
|
||||||
| `RenderEngine::TryPresentPreview(...)` | attempts to take the GL lock and presents preview | render thread or preview presenter consumes latest completed frame |
|
| `RenderEngine::TryPresentPreview(...)` | attempts to take the GL lock and delegates presentation to `PresentPreviewOnRenderThread(...)` | render thread or preview presenter consumes latest completed frame |
|
||||||
| `RenderEngine::CaptureOutputFrameRgbaTopDown(...)` | takes the GL lock and reads output pixels | screenshot request becomes render-thread command |
|
| `RenderEngine::CaptureOutputFrameRgbaTopDown(...)` | takes the GL lock, binds the context, delegates readback to `CaptureOutputFrameRgbaTopDownOnRenderThread(...)` | screenshot request becomes render-thread command |
|
||||||
| `OpenGLVideoIOBridge::UploadInputFrame(...)` | calls render upload directly | push input frame into render queue/mailbox |
|
| `OpenGLVideoIOBridge::UploadInputFrame(...)` | calls render upload directly | push input frame into render queue/mailbox |
|
||||||
| `OpenGLVideoIOBridge::RenderScheduledFrame(...)` | calls render output directly from backend path | request/consume render-produced output without callback-owned GL |
|
| `OpenGLVideoIOBridge::RenderScheduledFrame(...)` | calls render output directly from backend path | request/consume render-produced output without callback-owned GL |
|
||||||
|
|
||||||
@@ -184,7 +184,7 @@ Render-thread-only methods should be private or clearly named:
|
|||||||
|
|
||||||
- `RenderEngine::UploadInputFrameOnRenderThread(...)`
|
- `RenderEngine::UploadInputFrameOnRenderThread(...)`
|
||||||
- `RenderEngine::RenderOutputFrameOnRenderThread(...)`
|
- `RenderEngine::RenderOutputFrameOnRenderThread(...)`
|
||||||
- `RenderEngine::CaptureOutputFrameOnRenderThread(...)`
|
- `RenderEngine::CaptureOutputFrameRgbaTopDownOnRenderThread(...)`
|
||||||
|
|
||||||
The current `TryUploadInputFrame`, `RenderOutputFrame`, `TryPresentPreview`, and `CaptureOutputFrameRgbaTopDown` methods can remain as compatibility shims during migration, but their implementations should move toward enqueue-and-wait or enqueue-and-return behavior instead of binding GL directly from the caller's thread.
|
The current `TryUploadInputFrame`, `RenderOutputFrame`, `TryPresentPreview`, and `CaptureOutputFrameRgbaTopDown` methods can remain as compatibility shims during migration, but their implementations should move toward enqueue-and-wait or enqueue-and-return behavior instead of binding GL directly from the caller's thread.
|
||||||
|
|
||||||
@@ -214,9 +214,9 @@ Split existing direct GL methods into public request methods and private render-
|
|||||||
|
|
||||||
Initial target:
|
Initial target:
|
||||||
|
|
||||||
- keep current synchronous behavior where callers need a result
|
- [x] keep current synchronous behavior where callers need a result
|
||||||
- move GL bodies into clearly render-thread-owned helpers
|
- [x] move GL bodies into clearly render-thread-owned helpers for upload, output render, preview presentation, and screenshot readback
|
||||||
- make future queue migration mechanical
|
- [x] make future queue migration mechanical
|
||||||
|
|
||||||
### Step 2. Add Render Command Queue
|
### Step 2. Add Render Command Queue
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user