A flip event is emitted during fullscreen present submission. We expect the following event sequence emitted on the same thread: PresentStart FlipMultiPlaneOverlay_Info QueuePacket_Start SubmitSequence MMIOFLIP bPresent=1 QueuePacket_Stop SubmitSequence PresentStop
| 421 | // QueuePacket_Stop SubmitSequence |
| 422 | // PresentStop |
| 423 | std::shared_ptr<PresentEvent> PMTraceConsumer::HandleDxgkFlip(EVENT_HEADER const& hdr) |
| 424 | { |
| 425 | // First, lookup the in-progress present on the same thread. |
| 426 | // |
| 427 | // The present should not have a known QueueSubmitSequence nor seen a DxgkPresent yet, so if it |
| 428 | // does then we've looked up the wrong present. Typically, this means we've lost tracking for |
| 429 | // the looked-up present, and it should be discarded. |
| 430 | // |
| 431 | // However, DWM on recent windows may omit the PresentStart/PresentStop events. In this case, |
| 432 | // we'll end up creating the present here and, because there is no PresentStop, it will be left |
| 433 | // in mPresentByThreadId and looked up again in the next HandleDxgkFlip(). |
| 434 | std::shared_ptr<PresentEvent> presentEvent; |
| 435 | for (;;) { |
| 436 | // Lookup the in-progress present on this thread. |
| 437 | auto ii = mPresentByThreadId.find(hdr.ThreadId); |
| 438 | if (ii != mPresentByThreadId.end()) { |
| 439 | presentEvent = ii->second; |
| 440 | |
| 441 | // If the in-progress present has seen DxgkPresent, it has lost tracking. |
| 442 | if (presentEvent->SeenDxgkPresent) { |
| 443 | RemoveLostPresent(presentEvent); |
| 444 | continue; |
| 445 | } |
| 446 | |
| 447 | // If the in-progress present has seen PresentStop, it has lost tracking. |
| 448 | if (presentEvent->QueueSubmitSequence != 0 && |
| 449 | presentEvent->TimeInPresent != 0 && |
| 450 | presentEvent->Runtime != Runtime::Other) { |
| 451 | RemoveLostPresent(presentEvent); |
| 452 | continue; |
| 453 | } |
| 454 | |
| 455 | // If we did see a PresentStart, then use this present |
| 456 | if (presentEvent->Runtime != Runtime::Other) { |
| 457 | // There may be duplicate flip events for MPO situations, so only handle the first. |
| 458 | if (presentEvent->PresentMode != PresentMode::Unknown) { |
| 459 | return nullptr; |
| 460 | } |
| 461 | break; |
| 462 | } |
| 463 | |
| 464 | // The looked-up present was created by the last Flip, and didn't see a PresentStop; remove |
| 465 | // it from the thread tracking and create a new present for this flip. |
| 466 | mPresentByThreadId.erase(ii); |
| 467 | } |
| 468 | |
| 469 | // Create a new present for this flip |
| 470 | if (!IsProcessTrackedForFiltering(hdr.ProcessId)) { |
| 471 | return nullptr; |
| 472 | } |
| 473 | |
| 474 | presentEvent = std::make_shared<PresentEvent>(); |
| 475 | |
| 476 | VerboseTraceBeforeModifyingPresent(presentEvent.get()); |
| 477 | presentEvent->PresentStartTime = *(uint64_t*) &hdr.TimeStamp; |
| 478 | presentEvent->ProcessId = hdr.ProcessId; |
| 479 | presentEvent->ThreadId = hdr.ThreadId; |
| 480 |