diff --git a/apps/RenderCadenceCompositor/README.md b/apps/RenderCadenceCompositor/README.md index 404373b..00ebb79 100644 --- a/apps/RenderCadenceCompositor/README.md +++ b/apps/RenderCadenceCompositor/README.md @@ -273,6 +273,10 @@ Input telemetry: - `inputFramesReceived`: frames accepted into `InputFrameMailbox` - `inputFramesDropped`: ready input frames dropped or missed because the mailbox was full +- `inputConsumeMisses`: render ticks where no ready input frame was available to upload +- `inputUploadMisses`: input texture upload attempts that reused the previous GL input texture +- `inputReadyFrames`: ready input frames currently queued in `InputFrameMailbox` +- `inputReadingFrames`: input frames currently protected while render uploads them - `inputLatestAgeMs`: age of the newest submitted input frame - `inputUploadMs`: render-thread GL upload/decode submission time for the latest uploaded input frame - `inputFormatSupported`: whether the latest frame reaching the render upload path was BGRA8 or UYVY8 compatible diff --git a/apps/RenderCadenceCompositor/render/RenderThread.cpp b/apps/RenderCadenceCompositor/render/RenderThread.cpp index 46f6efa..05548ed 100644 --- a/apps/RenderCadenceCompositor/render/RenderThread.cpp +++ b/apps/RenderCadenceCompositor/render/RenderThread.cpp @@ -87,6 +87,10 @@ RenderThread::Metrics RenderThread::GetMetrics() const metrics.shaderBuildFailures = mShaderBuildFailures.load(std::memory_order_relaxed); metrics.inputFramesReceived = mInputFramesReceived.load(std::memory_order_relaxed); metrics.inputFramesDropped = mInputFramesDropped.load(std::memory_order_relaxed); + metrics.inputConsumeMisses = mInputConsumeMisses.load(std::memory_order_relaxed); + metrics.inputUploadMisses = mInputUploadMisses.load(std::memory_order_relaxed); + metrics.inputReadyFrames = mInputReadyFrames.load(std::memory_order_relaxed); + metrics.inputReadingFrames = mInputReadingFrames.load(std::memory_order_relaxed); metrics.inputLatestAgeMilliseconds = mInputLatestAgeMilliseconds.load(std::memory_order_relaxed); metrics.inputUploadMilliseconds = mInputUploadMilliseconds.load(std::memory_order_relaxed); metrics.inputFormatSupported = mInputFormatSupported.load(std::memory_order_relaxed); @@ -240,6 +244,9 @@ void RenderThread::PublishInputMetrics(const InputFrameTexture& inputTexture) const InputFrameMailboxMetrics mailboxMetrics = mInputMailbox->Metrics(); mInputFramesReceived.store(mailboxMetrics.submittedFrames, std::memory_order_relaxed); mInputFramesDropped.store(mailboxMetrics.droppedReadyFrames + mailboxMetrics.submitMisses, std::memory_order_relaxed); + mInputConsumeMisses.store(mailboxMetrics.consumeMisses, std::memory_order_relaxed); + mInputReadyFrames.store(mailboxMetrics.readyCount, std::memory_order_relaxed); + mInputReadingFrames.store(mailboxMetrics.readingCount, std::memory_order_relaxed); mInputLatestAgeMilliseconds.store(mailboxMetrics.latestFrameAgeMilliseconds, std::memory_order_relaxed); mInputSignalPresent.store(mailboxMetrics.hasSubmittedFrame, std::memory_order_relaxed); } @@ -247,10 +254,14 @@ void RenderThread::PublishInputMetrics(const InputFrameTexture& inputTexture) { mInputFramesReceived.store(0, std::memory_order_relaxed); mInputFramesDropped.store(0, std::memory_order_relaxed); + mInputConsumeMisses.store(0, std::memory_order_relaxed); + mInputReadyFrames.store(0, std::memory_order_relaxed); + mInputReadingFrames.store(0, std::memory_order_relaxed); mInputLatestAgeMilliseconds.store(0.0, std::memory_order_relaxed); mInputSignalPresent.store(false, std::memory_order_relaxed); } + mInputUploadMisses.store(inputTexture.UploadMisses(), std::memory_order_relaxed); mInputUploadMilliseconds.store(inputTexture.LastUploadMilliseconds(), std::memory_order_relaxed); mInputFormatSupported.store(inputTexture.LastFrameFormatSupported(), std::memory_order_relaxed); } diff --git a/apps/RenderCadenceCompositor/render/RenderThread.h b/apps/RenderCadenceCompositor/render/RenderThread.h index 0a81c30..3948f47 100644 --- a/apps/RenderCadenceCompositor/render/RenderThread.h +++ b/apps/RenderCadenceCompositor/render/RenderThread.h @@ -40,6 +40,10 @@ public: uint64_t shaderBuildFailures = 0; uint64_t inputFramesReceived = 0; uint64_t inputFramesDropped = 0; + uint64_t inputConsumeMisses = 0; + uint64_t inputUploadMisses = 0; + std::size_t inputReadyFrames = 0; + std::size_t inputReadingFrames = 0; double inputLatestAgeMilliseconds = 0.0; double inputUploadMilliseconds = 0.0; bool inputFormatSupported = true; @@ -94,6 +98,10 @@ private: std::atomic mShaderBuildFailures{ 0 }; std::atomic mInputFramesReceived{ 0 }; std::atomic mInputFramesDropped{ 0 }; + std::atomic mInputConsumeMisses{ 0 }; + std::atomic mInputUploadMisses{ 0 }; + std::atomic mInputReadyFrames{ 0 }; + std::atomic mInputReadingFrames{ 0 }; std::atomic mInputLatestAgeMilliseconds{ 0.0 }; std::atomic mInputUploadMilliseconds{ 0.0 }; std::atomic mInputFormatSupported{ true }; diff --git a/apps/RenderCadenceCompositor/telemetry/CadenceTelemetry.h b/apps/RenderCadenceCompositor/telemetry/CadenceTelemetry.h index aaf69b2..2b44070 100644 --- a/apps/RenderCadenceCompositor/telemetry/CadenceTelemetry.h +++ b/apps/RenderCadenceCompositor/telemetry/CadenceTelemetry.h @@ -26,6 +26,10 @@ struct CadenceTelemetrySnapshot uint64_t shaderBuildFailures = 0; uint64_t inputFramesReceived = 0; uint64_t inputFramesDropped = 0; + uint64_t inputConsumeMisses = 0; + uint64_t inputUploadMisses = 0; + std::size_t inputReadyFrames = 0; + std::size_t inputReadingFrames = 0; double inputLatestAgeMilliseconds = 0.0; double inputUploadMilliseconds = 0.0; bool inputFormatSupported = true; @@ -104,6 +108,10 @@ public: snapshot.shaderBuildFailures = renderMetrics.shaderBuildFailures; snapshot.inputFramesReceived = renderMetrics.inputFramesReceived; snapshot.inputFramesDropped = renderMetrics.inputFramesDropped; + snapshot.inputConsumeMisses = renderMetrics.inputConsumeMisses; + snapshot.inputUploadMisses = renderMetrics.inputUploadMisses; + snapshot.inputReadyFrames = renderMetrics.inputReadyFrames; + snapshot.inputReadingFrames = renderMetrics.inputReadingFrames; snapshot.inputLatestAgeMilliseconds = renderMetrics.inputLatestAgeMilliseconds; snapshot.inputUploadMilliseconds = renderMetrics.inputUploadMilliseconds; snapshot.inputFormatSupported = renderMetrics.inputFormatSupported; diff --git a/apps/RenderCadenceCompositor/telemetry/CadenceTelemetryJson.h b/apps/RenderCadenceCompositor/telemetry/CadenceTelemetryJson.h index 3618717..5f4f153 100644 --- a/apps/RenderCadenceCompositor/telemetry/CadenceTelemetryJson.h +++ b/apps/RenderCadenceCompositor/telemetry/CadenceTelemetryJson.h @@ -28,6 +28,10 @@ inline void WriteCadenceTelemetryJson(JsonWriter& writer, const CadenceTelemetry writer.KeyUInt("shaderFailures", snapshot.shaderBuildFailures); writer.KeyUInt("inputFramesReceived", snapshot.inputFramesReceived); writer.KeyUInt("inputFramesDropped", snapshot.inputFramesDropped); + writer.KeyUInt("inputConsumeMisses", snapshot.inputConsumeMisses); + writer.KeyUInt("inputUploadMisses", snapshot.inputUploadMisses); + writer.KeyUInt("inputReadyFrames", static_cast(snapshot.inputReadyFrames)); + writer.KeyUInt("inputReadingFrames", static_cast(snapshot.inputReadingFrames)); writer.KeyDouble("inputLatestAgeMs", snapshot.inputLatestAgeMilliseconds); writer.KeyDouble("inputUploadMs", snapshot.inputUploadMilliseconds); writer.KeyBool("inputFormatSupported", snapshot.inputFormatSupported); diff --git a/docs/openapi.yaml b/docs/openapi.yaml index 6278885..0ac10c1 100644 --- a/docs/openapi.yaml +++ b/docs/openapi.yaml @@ -649,6 +649,39 @@ components: type: number flushedFrameCount: type: number + cadence: + $ref: "#/components/schemas/CadenceTelemetry" + CadenceTelemetry: + type: object + properties: + inputFramesReceived: + type: number + inputFramesDropped: + type: number + inputConsumeMisses: + type: number + description: Render ticks where no ready input frame was available to upload. + inputUploadMisses: + type: number + description: Input texture upload attempts that reused the previous GL input texture. + inputReadyFrames: + type: number + description: Ready input frames currently queued in the input mailbox. + inputReadingFrames: + type: number + description: Input frames currently protected while render uploads them. + inputLatestAgeMs: + type: number + inputUploadMs: + type: number + inputCaptureFps: + type: number + inputConvertMs: + type: number + inputSubmitMs: + type: number + inputCaptureFormat: + type: string BackendPlayoutStatus: type: object properties: diff --git a/tests/RenderCadenceCompositorTelemetryTests.cpp b/tests/RenderCadenceCompositorTelemetryTests.cpp index fdb71ec..d7b8a0e 100644 --- a/tests/RenderCadenceCompositorTelemetryTests.cpp +++ b/tests/RenderCadenceCompositorTelemetryTests.cpp @@ -69,6 +69,10 @@ struct FakeRenderThreadMetrics uint64_t shaderBuildFailures = 0; uint64_t inputFramesReceived = 0; uint64_t inputFramesDropped = 0; + uint64_t inputConsumeMisses = 0; + uint64_t inputUploadMisses = 0; + std::size_t inputReadyFrames = 0; + std::size_t inputReadingFrames = 0; double inputLatestAgeMilliseconds = 0.0; double inputUploadMilliseconds = 0.0; bool inputFormatSupported = true; @@ -104,6 +108,10 @@ void TestTelemetrySamplesCompletedPollMissesAndShaderCounts() renderThread.metrics.shaderBuildFailures = 0; renderThread.metrics.inputFramesReceived = 9; renderThread.metrics.inputFramesDropped = 2; + renderThread.metrics.inputConsumeMisses = 3; + renderThread.metrics.inputUploadMisses = 4; + renderThread.metrics.inputReadyFrames = 1; + renderThread.metrics.inputReadingFrames = 0; renderThread.metrics.inputLatestAgeMilliseconds = 4.5; renderThread.metrics.inputUploadMilliseconds = 0.25; renderThread.metrics.inputFormatSupported = true; @@ -118,6 +126,10 @@ void TestTelemetrySamplesCompletedPollMissesAndShaderCounts() Expect(snapshot.shaderBuildFailures == 0, "shader failure count is sampled"); Expect(snapshot.inputFramesReceived == 9, "input received count is sampled"); Expect(snapshot.inputFramesDropped == 2, "input dropped count is sampled"); + Expect(snapshot.inputConsumeMisses == 3, "input consume miss count is sampled"); + Expect(snapshot.inputUploadMisses == 4, "input upload miss count is sampled"); + Expect(snapshot.inputReadyFrames == 1, "input ready frame count is sampled"); + Expect(snapshot.inputReadingFrames == 0, "input reading frame count is sampled"); Expect(snapshot.inputLatestAgeMilliseconds == 4.5, "input latest age is sampled"); Expect(snapshot.inputUploadMilliseconds == 0.25, "input upload timing is sampled"); Expect(snapshot.inputFormatSupported, "input format support is sampled"); @@ -168,6 +180,10 @@ void TestTelemetrySerializesToJson() snapshot.shaderBuildFailures = 0; snapshot.inputFramesReceived = 10; snapshot.inputFramesDropped = 1; + snapshot.inputConsumeMisses = 2; + snapshot.inputUploadMisses = 3; + snapshot.inputReadyFrames = 1; + snapshot.inputReadingFrames = 0; snapshot.inputLatestAgeMilliseconds = 3.5; snapshot.inputUploadMilliseconds = 0.75; snapshot.inputFormatSupported = true; @@ -192,6 +208,8 @@ void TestTelemetrySerializesToJson() "\"completions\":117,\"late\":1,\"dropped\":2," "\"shaderCommitted\":1,\"shaderFailures\":0," "\"inputFramesReceived\":10,\"inputFramesDropped\":1," + "\"inputConsumeMisses\":2,\"inputUploadMisses\":3," + "\"inputReadyFrames\":1,\"inputReadingFrames\":0," "\"inputLatestAgeMs\":3.5,\"inputUploadMs\":0.75," "\"inputFormatSupported\":true,\"inputSignalPresent\":true," "\"inputCaptureFps\":59.94,\"inputConvertMs\":4.25,"