Files
video-shader-toys/tests/RenderOutputQueueTests.cpp
Aiden f1f4e3421b
All checks were successful
CI / React UI Build (push) Successful in 10s
CI / Native Windows Build And Tests (push) Successful in 2m53s
CI / Windows Release Package (push) Successful in 3m6s
Frame timing
2026-05-12 01:08:32 +10:00

210 lines
5.6 KiB
C++

#include "RenderOutputQueue.h"
#include <iostream>
namespace
{
int gFailures = 0;
int gReleasedFrames = 0;
void Expect(bool condition, const char* message)
{
if (condition)
return;
std::cerr << "FAIL: " << message << "\n";
++gFailures;
}
RenderOutputFrame MakeFrame(uint64_t index)
{
RenderOutputFrame frame;
frame.frameIndex = index;
frame.frame.nativeFrame = reinterpret_cast<void*>(static_cast<uintptr_t>(index + 1));
return frame;
}
void CountReleasedFrame(VideoIOOutputFrame& frame)
{
if (frame.nativeFrame != nullptr)
{
++gReleasedFrames;
frame.nativeFrame = nullptr;
}
}
RenderOutputFrame MakeOwnedFrame(uint64_t index)
{
RenderOutputFrame frame = MakeFrame(index);
frame.releaseFrame = CountReleasedFrame;
return frame;
}
void TestQueuePreservesOrdering()
{
VideoPlayoutPolicy policy;
policy.maxReadyFrames = 3;
RenderOutputQueue queue(policy);
Expect(queue.Push(MakeFrame(1)), "first ready frame pushes");
Expect(queue.Push(MakeFrame(2)), "second ready frame pushes");
RenderOutputFrame frame;
Expect(queue.TryPop(frame), "first ready frame pops");
Expect(frame.frameIndex == 1, "queue pops first frame first");
Expect(queue.TryPop(frame), "second ready frame pops");
Expect(frame.frameIndex == 2, "queue pops second frame second");
}
void TestBoundedQueueDropsOldestFrame()
{
VideoPlayoutPolicy policy;
policy.maxReadyFrames = 2;
RenderOutputQueue queue(policy);
queue.Push(MakeFrame(1));
queue.Push(MakeFrame(2));
queue.Push(MakeFrame(3));
RenderOutputQueueMetrics metrics = queue.GetMetrics();
Expect(metrics.depth == 2, "bounded queue depth stays at capacity");
Expect(metrics.droppedCount == 1, "bounded queue counts dropped oldest frame");
RenderOutputFrame frame;
Expect(queue.TryPop(frame), "bounded queue pops after drop");
Expect(frame.frameIndex == 2, "oldest frame was dropped when queue overflowed");
}
void TestOverflowReleasesDroppedFrame()
{
gReleasedFrames = 0;
VideoPlayoutPolicy policy;
policy.targetReadyFrames = 1;
policy.maxReadyFrames = 1;
RenderOutputQueue queue(policy);
queue.Push(MakeOwnedFrame(1));
queue.Push(MakeOwnedFrame(2));
Expect(gReleasedFrames == 1, "overflow releases dropped ready frame");
RenderOutputFrame frame;
Expect(queue.TryPop(frame), "newest owned frame remains queued");
Expect(frame.frameIndex == 2, "overflow keeps newest owned frame");
Expect(gReleasedFrames == 1, "pop transfers ownership without releasing");
}
void TestDropOldestFrameReleasesFrame()
{
gReleasedFrames = 0;
VideoPlayoutPolicy policy;
policy.maxReadyFrames = 2;
RenderOutputQueue queue(policy);
queue.Push(MakeOwnedFrame(1));
queue.Push(MakeOwnedFrame(2));
Expect(queue.DropOldestFrame(), "oldest ready frame can be explicitly dropped");
Expect(gReleasedFrames == 1, "explicit drop releases oldest frame");
RenderOutputQueueMetrics metrics = queue.GetMetrics();
Expect(metrics.depth == 1, "explicit drop reduces queue depth");
Expect(metrics.droppedCount == 1, "explicit drop increments dropped count");
RenderOutputFrame frame;
Expect(queue.TryPop(frame), "newest frame remains after explicit drop");
Expect(frame.frameIndex == 2, "explicit drop keeps newest frame");
Expect(!queue.DropOldestFrame(), "empty queue cannot drop a frame");
}
void TestUnderrunIsCounted()
{
RenderOutputQueue queue;
RenderOutputFrame frame;
Expect(!queue.TryPop(frame), "empty queue reports underrun");
RenderOutputQueueMetrics metrics = queue.GetMetrics();
Expect(metrics.underrunCount == 1, "empty pop increments underrun count");
}
void TestConfigureShrinksDepthToNewCapacity()
{
VideoPlayoutPolicy policy;
policy.maxReadyFrames = 4;
RenderOutputQueue queue(policy);
queue.Push(MakeFrame(1));
queue.Push(MakeFrame(2));
queue.Push(MakeFrame(3));
VideoPlayoutPolicy smallerPolicy;
smallerPolicy.targetReadyFrames = 1;
smallerPolicy.maxReadyFrames = 1;
queue.Configure(smallerPolicy);
RenderOutputQueueMetrics metrics = queue.GetMetrics();
Expect(metrics.depth == 1, "configure trims queue to new capacity");
Expect(metrics.droppedCount == 2, "configure counts trimmed frames as drops");
RenderOutputFrame frame;
Expect(queue.TryPop(frame), "trimmed queue still has newest frame");
Expect(frame.frameIndex == 3, "configure keeps newest ready frame");
}
void TestConfigureReleasesTrimmedFrames()
{
gReleasedFrames = 0;
VideoPlayoutPolicy policy;
policy.maxReadyFrames = 3;
RenderOutputQueue queue(policy);
queue.Push(MakeOwnedFrame(1));
queue.Push(MakeOwnedFrame(2));
queue.Push(MakeOwnedFrame(3));
VideoPlayoutPolicy smallerPolicy;
smallerPolicy.targetReadyFrames = 1;
smallerPolicy.maxReadyFrames = 1;
queue.Configure(smallerPolicy);
Expect(gReleasedFrames == 2, "configure releases trimmed ready frames");
RenderOutputFrame frame;
Expect(queue.TryPop(frame), "trimmed owned queue still has newest frame");
Expect(frame.frameIndex == 3, "configure keeps newest owned frame after release");
}
void TestClearReleasesQueuedFrames()
{
gReleasedFrames = 0;
RenderOutputQueue queue;
queue.Push(MakeOwnedFrame(1));
queue.Push(MakeOwnedFrame(2));
queue.Clear();
RenderOutputQueueMetrics metrics = queue.GetMetrics();
Expect(metrics.depth == 0, "clear empties ready queue");
Expect(gReleasedFrames == 2, "clear releases queued ready frames");
}
}
int main()
{
TestQueuePreservesOrdering();
TestBoundedQueueDropsOldestFrame();
TestOverflowReleasesDroppedFrame();
TestDropOldestFrameReleasesFrame();
TestUnderrunIsCounted();
TestConfigureShrinksDepthToNewCapacity();
TestConfigureReleasesTrimmedFrames();
TestClearReleasesQueuedFrames();
if (gFailures != 0)
{
std::cerr << gFailures << " render output queue test failure(s).\n";
return 1;
}
std::cout << "RenderOutputQueue tests passed.\n";
return 0;
}