[Spice-devel,RFC,qxl-wddm-dod,2/3] Implement rendering state machine

Submitted by Yuri Benditovich on April 16, 2017, 7:43 p.m.

Details

Message ID 1492371783-19724-3-git-send-email-yuri.benditovich@daynix.com
State New
Headers show
Series "Synchronization of display mode change and pushing drawables" ( rev: 1 ) in Spice

Not browsing as part of any series.

Commit Message

Yuri Benditovich April 16, 2017, 7:43 p.m.
Preparation for synchronization of changing display mode and
sending drawable objects to the host.

Signed-off-by: Yuri Benditovich <yuri.benditovich@daynix.com>
---
 qxldod/QxlDod.h | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 100 insertions(+)

Patch hide | download patch | download mbox

diff --git a/qxldod/QxlDod.h b/qxldod/QxlDod.h
index b524577..63cb3d7 100755
--- a/qxldod/QxlDod.h
+++ b/qxldod/QxlDod.h
@@ -506,6 +506,106 @@  typedef struct DpcCbContext {
 #define MAX(x, y) (((x) >= (y)) ? (x) : (y))
 #define ALIGN(a, b) (((a) + ((b) - 1)) & ~((b) - 1))
 
+class RenderingStateMachine
+{
+public:
+    void Start()
+    {
+        PAGED_CODE();
+        QXL_ASSERT(m_State == FlowState::Stopped);
+        InterlockedIncrement(&m_Counter);
+        m_State = FlowState::Running;
+        InterlockedAnd(&m_Counter, ~StoppedMask);
+    }
+
+    void Stop()
+    {
+        PAGED_CODE();
+        QXL_ASSERT(m_State == FlowState::Running);
+        m_State = FlowState::Stopping;
+        KeClearEvent(&m_NoOutstandingItems);
+        InterlockedOr(&m_Counter, StoppedMask);
+        UnregisterOutstandingItem(__FUNCTION__);
+        WaitForObject(&m_NoOutstandingItems, NULL);
+    }
+
+    bool RegisterOutstandingItem()
+    {
+        PAGED_CODE();
+        auto value = InterlockedIncrement(&m_Counter);
+        if (value & StoppedMask)
+        {
+            value = InterlockedDecrement(&m_Counter);
+            if (value == StoppedMask)
+            {
+                CompleteStopping(__FUNCTION__);
+            }
+            return false;
+        }
+        return true;
+    }
+
+    void UnregisterOutstandingItem(LPCSTR from)
+    {
+        PAGED_CODE();
+        QXL_ASSERT(m_State != FlowState::Stopped);
+        LONG value = InterlockedDecrement(&m_Counter);
+        if (value == StoppedMask)
+        {
+            CompleteStopping(from);
+        }
+        else if (value)
+        {
+            // common case, one or more drawables pushed, StoppedMask not set
+            // also pushing not last drawable during mode set (StoppedMask set)
+        }
+        else
+        {
+            // illegal case
+            QXL_ASSERT(value != 0);
+        }
+    }
+
+    RenderingStateMachine()
+    {
+        PAGED_CODE();
+        m_Counter = 1;
+        KeInitializeMutex(&m_CompleteStoppingMutex, 0);
+        KeInitializeEvent(&m_NoOutstandingItems, SynchronizationEvent, FALSE);
+    }
+    ~RenderingStateMachine() = default;
+    RenderingStateMachine(const RenderingStateMachine&) = delete;
+    RenderingStateMachine& operator= (const RenderingStateMachine&) = delete;
+
+private:
+    void CompleteStopping(LPCSTR from)
+    {
+        PAGED_CODE();
+        WaitForObject(&m_CompleteStoppingMutex, NULL);
+        if (m_State == FlowState::Stopping)
+        {
+            DbgPrint(TRACE_LEVEL_WARNING, ("%s: from %s\n", __FUNCTION__, from));
+            m_State = FlowState::Stopped;
+            KeSetEvent(&m_NoOutstandingItems, IO_NO_INCREMENT, FALSE);
+        }
+        ReleaseMutex(&m_CompleteStoppingMutex, TRUE);
+    }
+
+    enum { StoppedMask = 0x40000000 };
+
+    using FlowState = enum
+    {
+        Running,
+        Stopping,
+        Stopped
+    };
+
+    LONG m_Counter;
+    FlowState m_State = FlowState::Running;
+    KEVENT m_NoOutstandingItems;
+    KMUTEX m_CompleteStoppingMutex;
+};
+
 #include "start-packed.h"
 SPICE_RING_DECLARE(QXLPresentOnlyRing, QXLDrawable**, 1024);
 #include "end-packed.h"