@@ -124,7 +124,8 @@ PresentEvent::PresentEvent()
124124 , PresentFailed(false )
125125 , PresentInDwmWaitingStruct(false )
126126
127- , DeferredReason(DeferredReason_None)
127+ , WaitingForPresentStop(false )
128+ , WaitingForFlipFrameType(false )
128129
129130 #ifdef TRACK_PRESENT_PATHS
130131 , AnalysisPath(0ull )
@@ -400,7 +401,7 @@ void PMTraceConsumer::HandleDxgkQueueSubmit(
400401 if (packetType == (uint32_t ) Microsoft_Windows_DxgKrnl::QueuePacketType::DXGKETW_MMIOFLIP_COMMAND_BUFFER ||
401402 packetType == (uint32_t ) Microsoft_Windows_DxgKrnl::QueuePacketType::DXGKETW_SOFTWARE_COMMAND_BUFFER ||
402403 isPresentPacket) {
403- auto present = FindThreadPresent (hdr.ThreadId );
404+ auto present = FindPresentByThreadId (hdr.ThreadId );
404405 if (present != nullptr && present->QueueSubmitSequence == 0 ) {
405406
406407 TRACK_PRESENT_PATH (present);
@@ -1020,7 +1021,7 @@ void PMTraceConsumer::HandleDXGKEvent(EVENT_RECORD* pEventRecord)
10201021 // no further work was needed.
10211022 case Microsoft_Windows_DxgKrnl::BlitCancel_Info::Id:
10221023 {
1023- auto present = FindThreadPresent (hdr.ThreadId );
1024+ auto present = FindPresentByThreadId (hdr.ThreadId );
10241025 if (present != nullptr ) {
10251026 TRACK_PRESENT_PATH (present);
10261027
@@ -1219,18 +1220,21 @@ void PMTraceConsumer::HandleDXGKEvent(EVENT_RECORD* pEventRecord)
12191220 DebugAssert (present == nullptr || present->PresentIds .empty ());
12201221
12211222 for (uint32_t i = 0 ; i < PlaneCount; ++i) {
1222- // Any previous present on this VidPnLayer will not get any more
1223- // FlipFrameType events.
1223+
1224+ // Mark any present already assigned to this VidPnLayer as they will not be
1225+ // getting any more FlipFrameType events.
12241226 auto vidPnLayerId = GenerateVidPnLayerId (VidPnSourceId, LayerIndex[i]);
12251227 {
12261228 auto ii = mPresentByVidPnLayerId .find (vidPnLayerId);
12271229 if (ii != mPresentByVidPnLayerId .end ()) {
12281230 auto p2 = ii->second ;
1229- mPresentByVidPnLayerId .erase (ii); // Remove first because ClearDeferredReason () may
1230- // complete the present can trigger removal.
1231+ mPresentByVidPnLayerId .erase (ii); // Remove first because UpdateReadyCount () may
1232+ // call StopTrackingPresent()
12311233
1232- if (p2->DeferredReason & DeferredReason_WaitingForFlipFrameType) {
1233- ClearDeferredReason (p2, DeferredReason_WaitingForFlipFrameType);
1234+ VerboseTraceBeforeModifyingPresent (p2.get ());
1235+ if (p2->WaitingForFlipFrameType ) {
1236+ p2->WaitingForFlipFrameType = false ;
1237+ UpdateReadyCount (p2);
12341238 } else {
12351239 p2->PresentIds .clear ();
12361240 }
@@ -1242,7 +1246,6 @@ void PMTraceConsumer::HandleDXGKEvent(EVENT_RECORD* pEventRecord)
12421246 if (present != nullptr ) {
12431247 VerboseTraceBeforeModifyingPresent (present.get ());
12441248 present->PresentIds .emplace (vidPnLayerId, PresentId[i]);
1245-
12461249 mPresentByVidPnLayerId .emplace (vidPnLayerId, present);
12471250 }
12481251
@@ -1706,8 +1709,9 @@ void PMTraceConsumer::RemovePresentFromSubmitSequenceIdTracking(std::shared_ptr<
17061709 // presentsBySubmitSequence is expected to be small (typically one element)
17071710 // this should be faster.
17081711 if (presentsBySubmitSequence->size () == 1 ) {
1709- DebugAssert (presentsBySubmitSequence->begin ()->second == present);
1710- mPresentBySubmitSequence .erase (ii);
1712+ if (presentsBySubmitSequence->begin ()->second == present) {
1713+ mPresentBySubmitSequence .erase (ii);
1714+ }
17111715 } else {
17121716 for (auto jj = presentsBySubmitSequence->begin (), je = presentsBySubmitSequence->end (); jj != je; ++jj) {
17131717 if (jj->second == present) {
@@ -1743,7 +1747,7 @@ void PMTraceConsumer::StopTrackingPresent(std::shared_ptr<PresentEvent> const& p
17431747 //
17441748 // We don't reset ThreadId nor DriverThreadId as both are useful outside of
17451749 // tracking.
1746- if (( p->DeferredReason & DeferredReason_WaitingForPresentStop) == 0 ) {
1750+ if (! p->WaitingForPresentStop ) {
17471751 auto ii = mPresentByThreadId .find (p->ThreadId );
17481752 if (ii != mPresentByThreadId .end () && ii->second == p) {
17491753 mPresentByThreadId .erase (ii);
@@ -1808,7 +1812,7 @@ void PMTraceConsumer::StopTrackingPresent(std::shared_ptr<PresentEvent> const& p
18081812 }
18091813
18101814 // mPresentByVidPnLayerId (unless it will be needed by deferred FlipFrameType handling)
1811- if (( p->DeferredReason & DeferredReason_WaitingForFlipFrameType) == 0 ) {
1815+ if (! p->WaitingForFlipFrameType ) {
18121816 for (auto const & pr : p->PresentIds ) {
18131817 auto ii = mPresentByVidPnLayerId .find (pr.first );
18141818 if (ii != mPresentByVidPnLayerId .end () && ii->second == p) {
@@ -1936,8 +1940,10 @@ void PMTraceConsumer::CompletePresent(std::shared_ptr<PresentEvent> const& p)
19361940 p2->IsLost = true ;
19371941 }
19381942
1939- if (p2->DeferredReason & DeferredReason_WaitingForFlipFrameType) {
1940- ClearDeferredReason (p2, DeferredReason_WaitingForFlipFrameType);
1943+ if (p2->WaitingForFlipFrameType ) {
1944+ VerboseTraceBeforeModifyingPresent (p2.get ());
1945+ p2->WaitingForFlipFrameType = false ;
1946+ UpdateReadyCount (p2);
19411947 } else {
19421948 CompletePresent (p2);
19431949 }
@@ -1951,7 +1957,7 @@ void PMTraceConsumer::CompletePresent(std::shared_ptr<PresentEvent> const& p)
19511957 // Present_Stop will check if the present is completed and add it to the dequeue list if so.
19521958 if (!p->IsLost && p->Runtime != Runtime::Other && p->TimeInPresent == 0 ) {
19531959 VerboseTraceBeforeModifyingPresent (p.get ());
1954- p->DeferredReason |= DeferredReason_WaitingForPresentStop ;
1960+ p->WaitingForPresentStop = true ;
19551961 }
19561962
19571963 // If flip frame type tracking is enabled, we defer the completion because we may see subsequent
@@ -1960,7 +1966,7 @@ void PMTraceConsumer::CompletePresent(std::shared_ptr<PresentEvent> const& p)
19601966 // (VidPnSourceId, LayerIndex) pair.
19611967 if (mTrackFrameType && !p->PresentIds .empty ()) {
19621968 VerboseTraceBeforeModifyingPresent (p.get ());
1963- p->DeferredReason |= DeferredReason_WaitingForFlipFrameType ;
1969+ p->WaitingForFlipFrameType = true ;
19641970 }
19651971
19661972 // Remove the present from tracking structures.
@@ -2006,12 +2012,10 @@ void PMTraceConsumer::AddPresentToCompletedList(std::shared_ptr<PresentEvent> co
20062012 }
20072013
20082014 mCompletedPresents [index] = present;
2009-
2010- if (present->DeferredReason == DeferredReason_None && index == GetRingIndex (mCompletedIndex + mReadyCount )) {
2011- mReadyCount ++;
2012- }
20132015 }
20142016
2017+ UpdateReadyCount (present);
2018+
20152019 // It's possible for a deferred condition to never be cleared. e.g., a process' last present
20162020 // doesn't get a Present_Stop event. When this happens the deferred present will prevent all
20172021 // subsequent presents from other processes from being dequeued until the ring buffer wraps and
@@ -2023,27 +2027,31 @@ void PMTraceConsumer::AddPresentToCompletedList(std::shared_ptr<PresentEvent> co
20232027 present->PresentStartTime - deferredPresent->PresentStartTime > mDeferralTimeLimit ) {
20242028 VerboseTraceBeforeModifyingPresent (deferredPresent.get ());
20252029 deferredPresent->IsLost = true ;
2026- ClearDeferredReason (deferredPresent, deferredPresent->DeferredReason );
2030+ deferredPresent->WaitingForPresentStop = false ;
2031+ deferredPresent->WaitingForFlipFrameType = false ;
2032+ UpdateReadyCount (deferredPresent);
20272033 }
20282034 }
20292035}
20302036
2031- void PMTraceConsumer::ClearDeferredReason (std::shared_ptr<PresentEvent> const & present, uint32_t deferredReason )
2037+ void PMTraceConsumer::UpdateReadyCount (std::shared_ptr<PresentEvent> const & present)
20322038{
2033- // Remove the deferred reason
2034- if (present->DeferredReason != DeferredReason_None) {
2035- VerboseTraceBeforeModifyingPresent (present.get ());
2036- present->DeferredReason &= ~deferredReason;
2039+ if (!present->WaitingForPresentStop &&
2040+ !present->WaitingForFlipFrameType ) {
20372041
20382042 StopTrackingPresent (present);
20392043
2040- if (present-> DeferredReason == DeferredReason_None) {
2044+ {
20412045 std::lock_guard<std::mutex> lock (mPresentEventMutex );
20422046
2043- uint32_t nextIndex = GetRingIndex (mCompletedIndex + mReadyCount );
2044- while (mReadyCount < mCompletedCount && mCompletedPresents [nextIndex]->DeferredReason == DeferredReason_None) {
2045- mReadyCount ++;
2046- nextIndex = GetRingIndex (mCompletedIndex + mReadyCount );
2047+ uint32_t i = GetRingIndex (mCompletedIndex + mReadyCount );
2048+ if (present == mCompletedPresents [i]) {
2049+ DebugAssert (mReadyCount < mCompletedCount );
2050+ do {
2051+ mReadyCount += 1 ;
2052+ i = GetRingIndex (i + 1 );
2053+ } while (mReadyCount < mCompletedCount && !mCompletedPresents [i]->WaitingForPresentStop
2054+ && !mCompletedPresents [i]->WaitingForFlipFrameType );
20472055 }
20482056 }
20492057 }
@@ -2061,7 +2069,7 @@ void PMTraceConsumer::SetThreadPresent(uint32_t threadId, std::shared_ptr<Presen
20612069 mPresentByThreadId .emplace (threadId, present);
20622070}
20632071
2064- std::shared_ptr<PresentEvent> PMTraceConsumer::FindThreadPresent (uint32_t threadId)
2072+ std::shared_ptr<PresentEvent> PMTraceConsumer::FindPresentByThreadId (uint32_t threadId)
20652073{
20662074 auto ii = mPresentByThreadId .find (threadId);
20672075 return ii == mPresentByThreadId .end () ? std::shared_ptr<PresentEvent>() : ii->second ;
@@ -2071,7 +2079,7 @@ std::shared_ptr<PresentEvent> PMTraceConsumer::FindOrCreatePresent(EVENT_HEADER
20712079{
20722080 // First, we check if there is an in-progress present that was last
20732081 // operated on from this same thread.
2074- auto present = FindThreadPresent (hdr.ThreadId );
2082+ auto present = FindPresentByThreadId (hdr.ThreadId );
20752083 if (present != nullptr ) {
20762084 return present;
20772085 }
@@ -2204,19 +2212,19 @@ void PMTraceConsumer::RuntimePresentStop(Runtime runtime, EVENT_HEADER const& hd
22042212
22052213 // If this present completed early and was deferred until the Present_Stop, then no more
22062214 // analysis is needed; we just clear the deferral.
2207- if (present->DeferredReason & DeferredReason_WaitingForPresentStop) {
2215+ if (present->WaitingForPresentStop ) {
2216+ present->WaitingForPresentStop = false ;
22082217 mPresentByThreadId .erase (eventIter);
2209- ClearDeferredReason (present, DeferredReason_WaitingForPresentStop );
2218+ UpdateReadyCount (present);
22102219 return ;
22112220 }
22122221
22132222 // If the Present() call failed, no more analysis is needed.
22142223 if (FAILED (result)) {
22152224 // Check expected state (a new Present() that has only been started).
2216- DebugAssert (present->TimeInPresent == 0 );
2217- DebugAssert (present->IsCompleted == false );
2218- DebugAssert (present->IsLost == false );
2219- DebugAssert (present->DeferredReason == 0 );
2225+ DebugAssert (present->TimeInPresent == 0 );
2226+ DebugAssert (present->IsCompleted == false );
2227+ DebugAssert (present->IsLost == false );
22202228 DebugAssert (present->DependentPresents .empty ());
22212229
22222230 present->PresentFailed = true ;
@@ -2403,7 +2411,7 @@ void PMTraceConsumer::ApplyFlipFrameType(
24032411 auto copy = std::make_shared<PresentEvent>();
24042412 *copy = *present;
24052413 copy->IsLost = false ;
2406- copy->DeferredReason &= ~DeferredReason_WaitingForFlipFrameType ;
2414+ copy->WaitingForFlipFrameType = false ;
24072415
24082416 VerboseTraceBeforeModifyingPresent (present.get ());
24092417 present->IsLost = true ;
0 commit comments