210 lines
5.6 KiB
C++
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;
|
|
}
|