Improvement
This commit is contained in:
170
tests/SystemOutputFramePoolTests.cpp
Normal file
170
tests/SystemOutputFramePoolTests.cpp
Normal file
@@ -0,0 +1,170 @@
|
||||
#include "SystemOutputFramePool.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
|
||||
namespace
|
||||
{
|
||||
int gFailures = 0;
|
||||
|
||||
void Expect(bool condition, const char* message)
|
||||
{
|
||||
if (condition)
|
||||
return;
|
||||
|
||||
std::cerr << "FAIL: " << message << "\n";
|
||||
++gFailures;
|
||||
}
|
||||
|
||||
SystemOutputFramePoolConfig MakeConfig(std::size_t capacity = 2)
|
||||
{
|
||||
SystemOutputFramePoolConfig config;
|
||||
config.width = 4;
|
||||
config.height = 3;
|
||||
config.pixelFormat = VideoIOPixelFormat::Bgra8;
|
||||
config.capacity = capacity;
|
||||
return config;
|
||||
}
|
||||
|
||||
void TestAcquireHonorsCapacityAndFrameShape()
|
||||
{
|
||||
SystemOutputFramePool pool(MakeConfig(2));
|
||||
|
||||
OutputFrameSlot first;
|
||||
OutputFrameSlot second;
|
||||
OutputFrameSlot third;
|
||||
Expect(pool.AcquireFreeSlot(first), "first slot can be acquired");
|
||||
Expect(pool.AcquireFreeSlot(second), "second slot can be acquired");
|
||||
Expect(!pool.AcquireFreeSlot(third), "fixed capacity rejects third acquire");
|
||||
|
||||
Expect(first.frame.bytes != nullptr, "acquired slot has system memory");
|
||||
Expect(first.frame.nativeBuffer == first.frame.bytes, "native buffer points at system memory");
|
||||
Expect(first.frame.nativeFrame == nullptr, "system frame has no native frame");
|
||||
Expect(first.frame.width == 4, "frame width is configured");
|
||||
Expect(first.frame.height == 3, "frame height is configured");
|
||||
Expect(first.frame.rowBytes == 16, "BGRA8 row bytes are inferred");
|
||||
Expect(first.frame.pixelFormat == VideoIOPixelFormat::Bgra8, "BGRA8 is the default output format");
|
||||
Expect(first.frame.bytes != second.frame.bytes, "each slot owns distinct memory");
|
||||
|
||||
SystemOutputFramePoolMetrics metrics = pool.GetMetrics();
|
||||
Expect(metrics.freeCount == 0, "all slots are in use");
|
||||
Expect(metrics.acquiredCount == 2, "acquired slots are counted");
|
||||
Expect(metrics.acquireMissCount == 1, "capacity miss is counted");
|
||||
}
|
||||
|
||||
void TestReadySlotsAreConsumedFifo()
|
||||
{
|
||||
SystemOutputFramePool pool(MakeConfig(2));
|
||||
|
||||
OutputFrameSlot first;
|
||||
OutputFrameSlot second;
|
||||
Expect(pool.AcquireFreeSlot(first), "first FIFO slot can be acquired");
|
||||
Expect(pool.AcquireFreeSlot(second), "second FIFO slot can be acquired");
|
||||
Expect(pool.PublishReadySlot(first), "first FIFO slot can be published");
|
||||
Expect(pool.PublishReadySlot(second), "second FIFO slot can be published");
|
||||
|
||||
OutputFrameSlot consumed;
|
||||
Expect(pool.ConsumeReadySlot(consumed), "first ready slot can be consumed");
|
||||
Expect(consumed.index == first.index, "first published slot is consumed first");
|
||||
Expect(pool.MarkScheduled(consumed), "consumed slot can be marked scheduled");
|
||||
Expect(pool.ReleaseScheduledSlot(consumed), "scheduled slot can be released");
|
||||
|
||||
Expect(pool.ConsumeReadySlot(consumed), "second ready slot can be consumed");
|
||||
Expect(consumed.index == second.index, "second published slot is consumed second");
|
||||
Expect(pool.ReleaseSlot(consumed), "consumed slot can be released without scheduling");
|
||||
|
||||
SystemOutputFramePoolMetrics metrics = pool.GetMetrics();
|
||||
Expect(metrics.freeCount == 2, "released slots return to free pool");
|
||||
Expect(metrics.readyCount == 0, "ready queue is empty after consumption");
|
||||
}
|
||||
|
||||
void TestReadySlotCanBeScheduledByBuffer()
|
||||
{
|
||||
SystemOutputFramePool pool(MakeConfig(1));
|
||||
|
||||
OutputFrameSlot slot;
|
||||
Expect(pool.AcquireFreeSlot(slot), "buffer schedule slot can be acquired");
|
||||
void* bytes = slot.frame.bytes;
|
||||
Expect(pool.PublishReadySlot(slot), "buffer schedule slot can be published");
|
||||
Expect(pool.MarkScheduledByBuffer(bytes), "ready slot can be marked scheduled by buffer");
|
||||
|
||||
SystemOutputFramePoolMetrics metrics = pool.GetMetrics();
|
||||
Expect(metrics.readyCount == 0, "scheduled-by-buffer removes slot from ready queue");
|
||||
Expect(metrics.scheduledCount == 1, "scheduled-by-buffer counts scheduled slot");
|
||||
|
||||
Expect(pool.ReleaseSlotByBuffer(bytes), "scheduled slot can be released by buffer");
|
||||
metrics = pool.GetMetrics();
|
||||
Expect(metrics.freeCount == 1, "released-by-buffer slot returns to free pool");
|
||||
}
|
||||
|
||||
void TestInvalidTransitionsAreRejected()
|
||||
{
|
||||
SystemOutputFramePool pool(MakeConfig(1));
|
||||
|
||||
OutputFrameSlot slot;
|
||||
Expect(pool.AcquireFreeSlot(slot), "transition slot can be acquired");
|
||||
Expect(!pool.MarkScheduled(slot), "acquired slot cannot be marked scheduled");
|
||||
Expect(pool.PublishReadySlot(slot), "acquired slot can be published");
|
||||
Expect(!pool.PublishReadySlot(slot), "ready slot cannot be published twice");
|
||||
Expect(pool.ReleaseSlot(slot), "ready slot can be released to free");
|
||||
Expect(!pool.ReleaseSlot(slot), "free slot cannot be released again");
|
||||
|
||||
OutputFrameSlot next;
|
||||
Expect(pool.AcquireFreeSlot(next), "slot can be reacquired after release");
|
||||
Expect(next.index == slot.index, "same storage slot can be reused");
|
||||
Expect(next.generation != slot.generation, "stale handles are invalidated on reacquire");
|
||||
Expect(!pool.PublishReadySlot(slot), "stale handle cannot publish reacquired slot");
|
||||
}
|
||||
|
||||
void TestPixelFormatAwareSizing()
|
||||
{
|
||||
SystemOutputFramePoolConfig config;
|
||||
config.width = 7;
|
||||
config.height = 2;
|
||||
config.pixelFormat = VideoIOPixelFormat::V210;
|
||||
config.capacity = 1;
|
||||
|
||||
SystemOutputFramePool pool(config);
|
||||
OutputFrameSlot slot;
|
||||
Expect(pool.AcquireFreeSlot(slot), "v210 slot can be acquired");
|
||||
Expect(slot.frame.pixelFormat == VideoIOPixelFormat::V210, "slot keeps configured pixel format");
|
||||
Expect(slot.frame.rowBytes == static_cast<long>(MinimumV210RowBytes(config.width)), "v210 row bytes are inferred");
|
||||
|
||||
SystemOutputFramePoolConfig explicitConfig = config;
|
||||
explicitConfig.pixelFormat = VideoIOPixelFormat::Uyvy8;
|
||||
explicitConfig.rowBytes = 64;
|
||||
pool.Configure(explicitConfig);
|
||||
Expect(pool.AcquireFreeSlot(slot), "explicit row-byte slot can be acquired");
|
||||
Expect(slot.frame.pixelFormat == VideoIOPixelFormat::Uyvy8, "slot keeps reconfigured pixel format");
|
||||
Expect(slot.frame.rowBytes == 64, "explicit row bytes are preserved");
|
||||
}
|
||||
|
||||
void TestEmptyReadyQueueUnderrunIsCounted()
|
||||
{
|
||||
SystemOutputFramePool pool(MakeConfig(1));
|
||||
OutputFrameSlot slot;
|
||||
Expect(!pool.ConsumeReadySlot(slot), "empty ready queue cannot be consumed");
|
||||
|
||||
SystemOutputFramePoolMetrics metrics = pool.GetMetrics();
|
||||
Expect(metrics.readyUnderrunCount == 1, "ready underrun is counted");
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
TestAcquireHonorsCapacityAndFrameShape();
|
||||
TestReadySlotsAreConsumedFifo();
|
||||
TestReadySlotCanBeScheduledByBuffer();
|
||||
TestInvalidTransitionsAreRejected();
|
||||
TestPixelFormatAwareSizing();
|
||||
TestEmptyReadyQueueUnderrunIsCounted();
|
||||
|
||||
if (gFailures != 0)
|
||||
{
|
||||
std::cerr << gFailures << " system output frame pool test failure(s).\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::cout << "SystemOutputFramePool tests passed.\n";
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user