[idd] implement cursor shape & position transmission

This commit is contained in:
Geoffrey McRae 2023-04-14 20:40:00 +10:00
parent c11748a76f
commit bbd0c7a99b
4 changed files with 194 additions and 14 deletions

View file

@ -374,6 +374,9 @@ void CIndirectDeviceContext::LGMPTimer()
if (wrapper)
wrapper->context->ResendLastFrame();
}
if (lgmpHostQueueNewSubs(m_pointerQueue))
ResendCursor();
}
void CIndirectDeviceContext::SendFrame(int width, int height, int pitch, DXGI_FORMAT format, void* data)
@ -444,4 +447,100 @@ void CIndirectDeviceContext::SendFrame(int width, int height, int pitch, DXGI_FO
lgmpHostQueuePost(m_frameQueue, 0, m_frameMemory[m_frameIndex]);
memcpy(fb->data, data, (size_t)height * (size_t)pitch);
fb->wp = height * pitch;
}
void CIndirectDeviceContext::SendCursor(const IDARG_OUT_QUERY_HWCURSOR& info, const BYTE * data)
{
PLGMPMemory mem;
if (info.CursorShapeInfo.CursorType == IDDCX_CURSOR_SHAPE_TYPE_UNINITIALIZED)
{
mem = m_pointerMemory[m_pointerMemoryIndex];
if (++m_pointerMemoryIndex == LGMP_Q_POINTER_LEN)
m_pointerMemoryIndex = 0;
}
else
{
mem = m_pointerShapeMemory[m_pointerShapeIndex];
if (++m_pointerShapeIndex == POINTER_SHAPE_BUFFERS)
m_pointerShapeIndex = 0;
}
KVMFRCursor * cursor = (KVMFRCursor *)lgmpHostMemPtr(mem);
m_cursorVisible = info.IsCursorVisible;
m_cursorX = info.X;
m_cursorY = info.Y;
cursor->x = (int16_t)info.X;
cursor->y = (int16_t)info.Y;
uint32_t flags = CURSOR_FLAG_POSITION |
(info.IsCursorVisible ? CURSOR_FLAG_VISIBLE : 0);
if (info.CursorShapeInfo.CursorType != IDDCX_CURSOR_SHAPE_TYPE_UNINITIALIZED)
{
memcpy(cursor + 1, data,
(size_t)(info.CursorShapeInfo.Height * info.CursorShapeInfo.Pitch));
cursor->hx = (int8_t )info.CursorShapeInfo.XHot;
cursor->hy = (int8_t )info.CursorShapeInfo.YHot;
cursor->width = (uint32_t)info.CursorShapeInfo.Width;
cursor->height = (uint32_t)info.CursorShapeInfo.Height;
cursor->pitch = (uint32_t)info.CursorShapeInfo.Pitch;
switch (info.CursorShapeInfo.CursorType)
{
case IDDCX_CURSOR_SHAPE_TYPE_ALPHA:
cursor->type = CURSOR_TYPE_COLOR;
break;
case IDDCX_CURSOR_SHAPE_TYPE_MASKED_COLOR:
cursor->type = CURSOR_TYPE_MASKED_COLOR;
break;
}
flags |= CURSOR_FLAG_SHAPE;
m_pointerShape = mem;
}
LGMP_STATUS status;
while ((status = lgmpHostQueuePost(m_pointerQueue, flags, mem)) != LGMP_OK)
{
if (status == LGMP_ERR_QUEUE_FULL)
{
Sleep(1);
continue;
}
DBGPRINT("lgmpHostQueuePost Failed (Pointer): %s", lgmpStatusString(status));
break;
}
}
void CIndirectDeviceContext::ResendCursor()
{
PLGMPMemory mem = m_pointerShape;
if (!mem)
return;
KVMFRCursor* cursor = (KVMFRCursor*)lgmpHostMemPtr(mem);
cursor->x = (int16_t)m_cursorX;
cursor->y = (int16_t)m_cursorY;
const uint32_t flags =
CURSOR_FLAG_POSITION | CURSOR_FLAG_SHAPE |
(m_cursorVisible ? CURSOR_FLAG_VISIBLE : 0);
LGMP_STATUS status;
while ((status = lgmpHostQueuePost(m_pointerQueue, flags, mem)) != LGMP_OK)
{
if (status == LGMP_ERR_QUEUE_FULL)
{
Sleep(1);
continue;
}
DBGPRINT("lgmpHostQueuePost Failed (Pointer): %s", lgmpStatusString(status));
break;
}
}

View file

@ -21,14 +21,20 @@ private:
IDDCX_ADAPTER m_adapter = nullptr;
IDDCX_MONITOR m_monitor = nullptr;
CIVSHMEM m_ivshmem;
CIVSHMEM m_ivshmem;
PLGMPHost m_lgmp = nullptr;
PLGMPHostQueue m_frameQueue = nullptr;
PLGMPHost m_lgmp = nullptr;
WDFTIMER m_lgmpTimer = nullptr;
PLGMPHostQueue m_frameQueue = nullptr;
PLGMPHostQueue m_pointerQueue = nullptr;
PLGMPMemory m_pointerMemory [LGMP_Q_POINTER_LEN ] = {};
PLGMPMemory m_pointerShapeMemory[POINTER_SHAPE_BUFFERS] = {};
PLGMPMemory m_pointerShape = nullptr;
int m_pointerMemoryIndex = 0;
int m_pointerShapeIndex = 0;
bool m_cursorVisible = false;
int m_cursorX = 0, m_cursorY = 0;
size_t m_maxFrameSize = 0;
int m_frameIndex = 0;
@ -42,10 +48,8 @@ private:
DXGI_FORMAT m_format = DXGI_FORMAT_UNKNOWN;
bool SetupLGMP();
void LGMPTimer();
WDFTIMER m_lgmpTimer = nullptr;
void ResendCursor();
public:
CIndirectDeviceContext(_In_ WDFDEVICE wdfDevice) :
@ -58,6 +62,7 @@ public:
void FinishInit(UINT connectorIndex);
void SendFrame(int width, int height, int pitch, DXGI_FORMAT format, void* data);
void SendCursor(const IDARG_OUT_QUERY_HWCURSOR & info, const BYTE * data);
};
struct CIndirectDeviceContextWrapper

View file

@ -1,20 +1,27 @@
#include "CIndirectMonitorContext.h"
#include "Direct3DDevice.h"
#include "Debug.h"
CIndirectMonitorContext::CIndirectMonitorContext(_In_ IDDCX_MONITOR monitor, CIndirectDeviceContext * device) :
m_monitor(monitor),
m_devContext(device)
{
m_terminateEvent .Attach(CreateEvent(nullptr, FALSE, FALSE, nullptr));
m_cursorDataEvent.Attach(CreateEvent(nullptr, FALSE, FALSE, nullptr));
m_thread.Attach(CreateThread(nullptr, 0, _CursorThread, this, 0, nullptr));
m_shapeBuffer = new BYTE[512 * 512 * 4];
}
CIndirectMonitorContext::~CIndirectMonitorContext()
{
m_thread.reset();
m_swapChain.reset();
SetEvent(m_terminateEvent.Get());
delete[] m_shapeBuffer;
}
void CIndirectMonitorContext::AssignSwapChain(IDDCX_SWAPCHAIN swapChain, LUID renderAdapter, HANDLE newFrameEvent)
{
m_thread.reset();
m_swapChain.reset();
auto device = std::make_shared<Direct3DDevice>(renderAdapter);
if (FAILED(device->Init()))
{
@ -22,10 +29,67 @@ void CIndirectMonitorContext::AssignSwapChain(IDDCX_SWAPCHAIN swapChain, LUID re
return;
}
m_thread.reset(new CSwapChainProcessor(m_devContext, swapChain, device, newFrameEvent));
m_swapChain.reset(new CSwapChainProcessor(m_devContext, swapChain, device, newFrameEvent));
IDARG_IN_SETUP_HWCURSOR c = {};
c.CursorInfo.Size = sizeof(c.CursorInfo);
c.CursorInfo.AlphaCursorSupport = TRUE;
c.CursorInfo.ColorXorCursorSupport = IDDCX_XOR_CURSOR_SUPPORT_FULL;
c.CursorInfo.MaxX = 512;
c.CursorInfo.MaxY = 512;
c.hNewCursorDataAvailable = m_cursorDataEvent.Get();
NTSTATUS status = IddCxMonitorSetupHardwareCursor(m_monitor, &c);
if (!NT_SUCCESS(status))
DBGPRINT("IddCxMonitorSetupHardwareCursor Failed: %08x", status);
}
void CIndirectMonitorContext::UnassignSwapChain()
{
m_thread.reset();
m_swapChain.reset();
}
DWORD CALLBACK CIndirectMonitorContext::_CursorThread(LPVOID arg)
{
reinterpret_cast<CIndirectMonitorContext*>(arg)->CursorThread();
return 0;
}
void CIndirectMonitorContext::CursorThread()
{
HRESULT hr = 0;
for (;;)
{
HANDLE waitHandles[] =
{
m_cursorDataEvent.Get(),
m_terminateEvent.Get()
};
DWORD waitResult = WaitForMultipleObjects(ARRAYSIZE(waitHandles), waitHandles, FALSE, 100);
if (waitResult == WAIT_TIMEOUT)
continue;
else if (waitResult == WAIT_OBJECT_0 + 1)
break;
else if (waitResult != WAIT_OBJECT_0)
{
hr = HRESULT_FROM_WIN32(waitResult);
DBGPRINT("WaitForMultipleObjects: %08", hr);
return;
}
IDARG_IN_QUERY_HWCURSOR in = {};
in.LastShapeId = m_lastShapeId;
in.pShapeBuffer = m_shapeBuffer;
in.ShapeBufferSizeInBytes = 512 * 512 * 4;
IDARG_OUT_QUERY_HWCURSOR out = {};
NTSTATUS status = IddCxMonitorQueryHardwareCursor(m_monitor, &in, &out);
if (FAILED(status))
{
DBGPRINT("IddCxMonitorQueryHardwareCursor failed: %08x", status);
return;
}
m_devContext->SendCursor(out, m_shapeBuffer);
}
}

View file

@ -8,12 +8,24 @@
#include "CIndirectDeviceContext.h"
#include "CSwapChainProcessor.h"
using namespace Microsoft::WRL;
class CIndirectMonitorContext
{
protected:
private:
IDDCX_MONITOR m_monitor;
CIndirectDeviceContext * m_devContext;
std::unique_ptr<CSwapChainProcessor> m_thread;
std::unique_ptr<CSwapChainProcessor> m_swapChain;
Wrappers::Event m_terminateEvent;
Wrappers::Event m_cursorDataEvent;
Wrappers::HandleT<Wrappers::HandleTraits::HANDLENullTraits> m_thread;
BYTE * m_shapeBuffer;
DWORD m_lastShapeId = 0;
static DWORD CALLBACK _CursorThread(LPVOID arg);
void CursorThread();
public:
CIndirectMonitorContext(_In_ IDDCX_MONITOR monitor, CIndirectDeviceContext * device);
@ -25,8 +37,8 @@ public:
inline void ResendLastFrame()
{
if (m_thread)
m_thread->ResendLastFrame();
if (m_swapChain)
m_swapChain->ResendLastFrame();
}
};