Repository navigation
Expand file tree
/
Copy pathFrameSampleGateProbe.cpp
More file actions
37 lines (37 loc) · 3.26 KB
/
Copy pathFrameSampleGateProbe.cpp
File metadata and controls
37 lines (37 loc) · 3.26 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include "FrameSampleGate.h"
#include <thread>
#include <atomic>
#include <cstdio>
#include <cstdlib>
using namespace FrameSampleGate;
void Check(bool value,const char* text){if(!value){printf("FAIL: %s\n",text);exit(1);}}
std::atomic_bool focus=true;
bool Focused(){return focus;}
struct Fixture {
Transport::Header header{};Transport::TrackingReader reader{};
Fixture(){header.magic=Transport::Magic;header.version=Transport::Version;Put(50);}
void Put(uint64_t id,bool valid=true){Transport::Tracking t{};t.id=id;t.tick=GetTickCount64();t.valid=valid;t.head.orientation.w=1;Transport::WriteTracking(&header,t);}
bool Get(Transport::Tracking& out,Report& r,bool enabled=true,uint64_t completed=50,DWORD timeout=100){return Read(reader,&header,out,completed,enabled,&Focused,r,timeout);}
};
int main(){
Transport::Tracking out{};Report r{};
{Fixture f;Check(f.Get(out,r,false)&&out.id==50&&!r.polls,"OFF reproduces early consumer accepting previous frame");}
{Fixture f;std::atomic_bool advanced{};std::thread host([&]{Sleep(12);advanced=true;f.Put(51);});
bool usable=f.Get(out,r);bool early=!advanced;host.join();Check(usable&&!early&&out.id==51&&r.result==Result::Advanced&&r.polls,"first consumer waits for actual next sample before any Present wait");}
{Fixture f;f.Put(52);r={};Check(f.Get(out,r)&&out.id==52&&!r.polls,"already-new sample has no delay");}
{Fixture f;r={};Check(f.Get(out,r,true,0)&&out.id==50&&!r.polls,"first frame after menu or channel reset is immediate");}
{Fixture f;r={};focus=false;Check(f.Get(out,r)&&r.result==Result::Cancelled&&!r.polls,"background cannot stall");focus=true;}
{Fixture f;std::thread host([&]{Sleep(10);f.Put(51,false);});r={};bool ok=f.Get(out,r);host.join();Check(!ok&&r.result==Result::Unavailable,"invalid tracking terminates wait");}
{Fixture f;f.header.tracking.tick=GetTickCount64()-251;r={};Check(!f.Get(out,r)&&r.result==Result::Unavailable,"stale tracking rejected");}
{Fixture f;r={};auto begin=GetTickCount64();Check(f.Get(out,r,true,50,12)&&out.id==50&&r.result==Result::TimedOut&&GetTickCount64()-begin<100,"timeout preserves original valid pose and bounds shutdown recovery");}
{Fixture f;Check(f.Get(out,r,false),"prime contention reader");InterlockedExchange(&f.header.trackingLock,1);
std::thread host([&]{Sleep(10);InterlockedExchange(&f.header.trackingLock,0);f.Put(51);});r={};bool ok=f.Get(out,r);host.join();Check(ok&&out.id==51&&f.header.trackingLock==0,"reader releases mailbox lock during wait");}
// Once per frame, never once per eye. A synthetic independent XR host
// publishes while a simulation consumer owns its frame sampling scope.
{Fixture f;uint64_t completed=50;for(unsigned frame=0;frame<180;++frame){
std::thread host([&]{Sleep(1);f.Put(completed+1);});r={};bool ok=f.Get(out,r,true,completed);host.join();
Check(ok&&out.id==completed+1,"one new sample for every successive frame");auto left=out,right=out;f.Put(out.id+1);
Check(left.id==right.id&&left.tick==right.tick,"frozen same-frame eye identity survives a newer mailbox sample");completed=out.id;
}}
puts("PASS: first-consumer fresh-pose gate, old interleaving reproduction, no-delay fresh/reset/OFF cases, focus/invalid/stale/timeout/contention exits and 180 same-frame advances.");
}