#include "RenderOutputQueue.h" #include 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(static_cast(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 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(); 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; }