[idd] implemented frame feed from the guest (very hacky)

This is NOT READY for general consumption, if you decide to make
use of this driver, DO NOT ASK FOR SUPPORT.
This commit is contained in:
Geoffrey McRae
2023-04-11 16:55:58 +10:00
parent 3c85957b99
commit 0c3dce3ca6
8 changed files with 315 additions and 33 deletions

View File

@@ -1,36 +1,48 @@
#include "CSwapChainProcessor.h"
#include <avrt.h>
#include "Debug.h"
#define LOCK_CONTEXT() \
while (InterlockedCompareExchange((volatile LONG*)&m_contextLock, 1, 0) != 0) {};
CSwapChainProcessor::CSwapChainProcessor(IDDCX_SWAPCHAIN hSwapChain, std::shared_ptr<Direct3DDevice> device, HANDLE newFrameEvent) :
#define UNLOCK_CONTEXT() \
InterlockedExchange((volatile LONG*)&m_contextLock, 0);
CSwapChainProcessor::CSwapChainProcessor(CIndirectDeviceContext* devContext, IDDCX_SWAPCHAIN hSwapChain,
std::shared_ptr<Direct3DDevice> device, HANDLE newFrameEvent) :
m_devContext(devContext),
m_hSwapChain(hSwapChain),
m_device(device),
m_newFrameEvent(newFrameEvent)
{
{
m_terminateEvent.Attach(CreateEvent(nullptr, FALSE, FALSE, nullptr));
m_thread.Attach(CreateThread(nullptr, 0, RunThread, this, 0, nullptr));
m_thread[0].Attach(CreateThread(nullptr, 0, _SwapChainThread, this, 0, nullptr));
m_thread[1].Attach(CreateThread(nullptr, 0, _FrameThread , this, 0, nullptr));
}
CSwapChainProcessor::~CSwapChainProcessor()
{
SetEvent(m_terminateEvent.Get());
if (m_thread.Get())
WaitForSingleObject(m_thread.Get(), INFINITE);
if (m_thread[0].Get())
WaitForSingleObject(m_thread[0].Get(), INFINITE);
if (m_thread[1].Get())
WaitForSingleObject(m_thread[1].Get(), INFINITE);
}
DWORD CALLBACK CSwapChainProcessor::RunThread(LPVOID argument)
DWORD CALLBACK CSwapChainProcessor::_SwapChainThread(LPVOID arg)
{
reinterpret_cast<CSwapChainProcessor*>(argument)->Run();
reinterpret_cast<CSwapChainProcessor*>(arg)->SwapChainThread();
return 0;
}
void CSwapChainProcessor::Run()
void CSwapChainProcessor::SwapChainThread()
{
DWORD avTask = 0;
HANDLE avTaskHandle = AvSetMmThreadCharacteristicsW(L"Distribution", &avTask);
RunCore();
DBGPRINT("Start");
SwapChainThreadCore();
WdfObjectDelete((WDFOBJECT)m_hSwapChain);
m_hSwapChain = nullptr;
@@ -38,28 +50,41 @@ void CSwapChainProcessor::Run()
AvRevertMmThreadCharacteristics(avTaskHandle);
}
void CSwapChainProcessor::RunCore()
void CSwapChainProcessor::SwapChainThreadCore()
{
Microsoft::WRL::ComPtr<IDXGIDevice> dxgiDevice;
HRESULT hr = m_device->m_device.As(&dxgiDevice);
if (FAILED(hr))
{
DBGPRINT("Failed to get the dxgiDevice");
return;
}
IDARG_IN_SWAPCHAINSETDEVICE setDevice = {};
setDevice.pDevice = dxgiDevice.Get();
LOCK_CONTEXT();
hr = IddCxSwapChainSetDevice(m_hSwapChain, &setDevice);
if (FAILED(hr))
return;
UNLOCK_CONTEXT();
if (FAILED(hr))
{
DBGPRINT("IddCxSwapChainSetDevice Failed");
return;
}
UINT lastFrameNumber = 0;
for (;;)
{
Microsoft::WRL::ComPtr<IDXGIResource> acquiredBuffer;
ComPtr<IDXGIResource> acquiredBuffer;
IDARG_OUT_RELEASEANDACQUIREBUFFER buffer = {};
hr = IddCxSwapChainReleaseAndAcquireBuffer(m_hSwapChain, &buffer);
LOCK_CONTEXT();
hr = IddCxSwapChainReleaseAndAcquireBuffer(m_hSwapChain, &buffer);
if (hr == E_PENDING)
{
UNLOCK_CONTEXT();
HANDLE waitHandles[] =
{
m_newFrameEvent,
@@ -78,16 +103,132 @@ void CSwapChainProcessor::RunCore()
}
else if (SUCCEEDED(hr))
{
//acquiredBuffer.Attach(buffer.MetaData.pSurface);
if (buffer.MetaData.PresentationFrameNumber != lastFrameNumber)
{
lastFrameNumber = buffer.MetaData.PresentationFrameNumber;
if (m_copyCount < STAGING_TEXTURES)
{
acquiredBuffer.Attach(buffer.MetaData.pSurface);
SwapChainNewFrame(acquiredBuffer);
acquiredBuffer.Reset();
}
}
//TODO: process the frame
//acquiredBuffer.Reset();
hr = IddCxSwapChainFinishedProcessingFrame(m_hSwapChain);
UNLOCK_CONTEXT();
if (FAILED(hr))
break;
}
else
{
UNLOCK_CONTEXT();
break;
}
}
}
void CSwapChainProcessor::SwapChainNewFrame(ComPtr<IDXGIResource> acquiredBuffer)
{
Microsoft::WRL::ComPtr<ID3D11Texture2D> texture;
if (FAILED(acquiredBuffer->QueryInterface(__uuidof(ID3D11Texture2D), (void**)&texture)))
{
DBGPRINT("Failed to obtain the ID3D11Texture2D from the acquiredBuffer");
return;
}
D3D11_TEXTURE2D_DESC desc;
texture->GetDesc(&desc);
if (!SetupStagingTexture(m_cpuTex[m_texWIndex], desc.Width, desc.Height, desc.Format))
return;
m_device->m_context->CopyResource(m_cpuTex[m_texWIndex].tex.Get(), texture.Get());
InterlockedAdd(&m_copyCount, 1);
if (++m_texWIndex == STAGING_TEXTURES)
m_texWIndex = 0;
}
DWORD CALLBACK CSwapChainProcessor::_FrameThread(LPVOID arg)
{
reinterpret_cast<CSwapChainProcessor*>(arg)->FrameThread();
return 0;
}
void CSwapChainProcessor::FrameThread()
{
for(;;)
{
if (WaitForSingleObject(m_terminateEvent.Get(), 0) == WAIT_OBJECT_0)
break;
if (!m_copyCount)
{
Sleep(0);
continue;
}
D3D11_MAPPED_SUBRESOURCE map;
StagingTexture & t = m_cpuTex[m_texRIndex];
LOCK_CONTEXT();
HRESULT status = m_device->m_context->Map(t.tex.Get(), 0, D3D11_MAP_READ, D3D11_MAP_FLAG_DO_NOT_WAIT, &map);
UNLOCK_CONTEXT();
if (FAILED(status))
{
if (status == DXGI_ERROR_WAS_STILL_DRAWING)
continue;
DBGPRINT("Failed to map staging texture");
InterlockedAdd(&m_copyCount, -1);
if (++m_texRIndex == STAGING_TEXTURES)
m_texRIndex = 0;
continue;
}
m_devContext->SendFrame(t.width, t.height, map.RowPitch, t.format, map.pData);
LOCK_CONTEXT();
m_device->m_context->Unmap(t.tex.Get(), 0);
UNLOCK_CONTEXT();
InterlockedAdd(&m_copyCount, -1);
if (++m_texRIndex == STAGING_TEXTURES)
m_texRIndex = 0;
}
}
bool CSwapChainProcessor::SetupStagingTexture(StagingTexture & t, int width, int height, DXGI_FORMAT format)
{
if (t.width == width && t.height == height && t.format == format)
return true;
t.tex.Reset();
t.width = width;
t.height = height;
t.format = format;
D3D11_TEXTURE2D_DESC desc = {};
desc.Width = width;
desc.Height = height;
desc.MipLevels = 1;
desc.ArraySize = 1;
desc.SampleDesc.Count = 1;
desc.SampleDesc.Quality = 0;
desc.Usage = D3D11_USAGE_STAGING;
desc.Format = format;
desc.BindFlags = 0;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
desc.MiscFlags = 0;
if (FAILED(m_device->m_device->CreateTexture2D(&desc, nullptr, &t.tex)))
{
DBGPRINT("Failed to create staging texture");
return false;
}
return true;
}