[host] d12: adjust backend API to allow multiple instances

This commit is contained in:
Geoffrey McRae 2024-01-31 09:43:01 +11:00
parent 462d8187b6
commit c07b72883a
3 changed files with 90 additions and 51 deletions

View File

@ -25,7 +25,9 @@
#include <d3d12.h> #include <d3d12.h>
#include "interface/capture.h" #include "interface/capture.h"
typedef struct D12Backend typedef struct D12Backend D12Backend;
struct D12Backend
{ {
// friendly name // friendly name
const char * name; const char * name;
@ -34,21 +36,37 @@ typedef struct D12Backend
const char * codeName; const char * codeName;
// creation/init/free // creation/init/free
bool (*create)(unsigned frameBuffers); bool (*create)(D12Backend ** instance, unsigned frameBuffers);
bool (*init)( bool (*init)(
D12Backend * instance,
bool debug, bool debug,
ID3D12Device3 * device, ID3D12Device3 * device,
IDXGIAdapter1 * adapter, IDXGIAdapter1 * adapter,
IDXGIOutput * output); IDXGIOutput * output);
bool (*deinit)(void); bool (*deinit)(D12Backend * instance);
void (*free)(void); void (*free)(D12Backend ** instance);
// capture callbacks // capture callbacks
CaptureResult (*capture)(unsigned frameBufferIndex); CaptureResult (*capture)(D12Backend * instance,
CaptureResult (*sync )(ID3D12CommandQueue * commandQueue); unsigned frameBufferIndex);
ID3D12Resource * (*fetch )(unsigned frameBufferIndex);
CaptureResult (*sync)(D12Backend * instance,
ID3D12CommandQueue * commandQueue);
ID3D12Resource * (*fetch)(D12Backend * instance,
unsigned frameBufferIndex);
};
// helpers for the interface
static inline bool d12_createBackend(
D12Backend * backend, D12Backend ** instance, unsigned frameBuffers)
{
if (!backend->create(instance, frameBuffers))
return false;
memcpy(*instance, backend, sizeof(*backend));
return true;
} }
D12Backend;
// apis for the backend // apis for the backend
void d12_updatePointer( void d12_updatePointer(

View File

@ -29,8 +29,10 @@ typedef struct DDCacheInfo
} }
DDCacheInfo; DDCacheInfo;
struct DDInstance typedef struct DDInstance
{ {
D12Backend base;
ComScope * comScope; ComScope * comScope;
HDESK desktop; HDESK desktop;
@ -49,43 +51,47 @@ struct DDInstance
void * shapeBuffer; void * shapeBuffer;
unsigned shapeBufferSize; unsigned shapeBufferSize;
}; }
DDInstance;
struct DDInstance * this = NULL;
#define comRef_toGlobal(dst, src) \ #define comRef_toGlobal(dst, src) \
_comRef_toGlobal(this->comScope, dst, src) _comRef_toGlobal(this->comScope, dst, src)
static void d12_dd_openDesktop(void); static void d12_dd_openDesktop(DDInstance * this);
static bool d12_dd_handleFrameUpdate(IDXGIResource * res); static bool d12_dd_handleFrameUpdate(DDInstance * this, IDXGIResource * res);
static void d12_dd_handlePointerMovement(DXGI_OUTDUPL_POINTER_POSITION * pos, static void d12_dd_handlePointerMovement(DDInstance * this,
CapturePointer * pointer, bool * changed); DXGI_OUTDUPL_POINTER_POSITION * pos, CapturePointer * pointer, bool * changed);
static void d12_dd_handlePointerShape( static void d12_dd_handlePointerShape(DDInstance * this,
CapturePointer * pointer, size_t size, bool * changed); CapturePointer * pointer, size_t size, bool * changed);
static bool d12_dd_getCache(ID3D11Texture2D * srcTex, DDCacheInfo ** result); static bool d12_dd_getCache(DDInstance * this,
static bool d12_dd_convertResource(ID3D11Texture2D * srcTex, ID3D11Texture2D * srcTex, DDCacheInfo ** result);
DDCacheInfo * cache); static bool d12_dd_convertResource(DDInstance * this,
ID3D11Texture2D * srcTex, DDCacheInfo * cache);
static bool d12_dd_create(unsigned frameBuffers) static bool d12_dd_create(D12Backend ** instance, unsigned frameBuffers)
{ {
this = calloc(1, sizeof(*this)); DDInstance * this = calloc(1, sizeof(*this));
if (!this) if (!this)
{ {
DEBUG_ERROR("out of memory"); DEBUG_ERROR("out of memory");
return false; return false;
} }
*instance = &this->base;
return true; return true;
} }
static bool d12_dd_init( static bool d12_dd_init(
D12Backend * instance,
bool debug, bool debug,
ID3D12Device3 * device, ID3D12Device3 * device,
IDXGIAdapter1 * adapter, IDXGIAdapter1 * adapter,
IDXGIOutput * output) IDXGIOutput * output)
{ {
DDInstance * this = UPCAST(DDInstance, instance);
bool result = false; bool result = false;
HRESULT hr; HRESULT hr;
@ -93,7 +99,7 @@ static bool d12_dd_init(
comRef_scopePush(10); comRef_scopePush(10);
// try to open the desktop so we can capture the secure desktop // try to open the desktop so we can capture the secure desktop
d12_dd_openDesktop(); d12_dd_openDesktop(this);
comRef_defineLocal(IDXGIAdapter, _adapter); comRef_defineLocal(IDXGIAdapter, _adapter);
hr = IDXGIAdapter1_QueryInterface( hr = IDXGIAdapter1_QueryInterface(
@ -249,8 +255,10 @@ exit:
return result; return result;
} }
static bool d12_dd_deinit(void) static bool d12_dd_deinit(D12Backend * instance)
{ {
DDInstance * this = UPCAST(DDInstance, instance);
if (this->release) if (this->release)
{ {
IDXGIOutputDuplication_ReleaseFrame(*this->dup); IDXGIOutputDuplication_ReleaseFrame(*this->dup);
@ -264,15 +272,17 @@ static bool d12_dd_deinit(void)
} }
comRef_freeScope(&this->comScope); comRef_freeScope(&this->comScope);
memset(this, 0, sizeof(*this)); memset(this->cache, 0, sizeof(this->cache));
return true; return true;
} }
static void d12_dd_free(void) static void d12_dd_free(D12Backend ** instance)
{ {
DDInstance * this = UPCAST(DDInstance, *instance);
free(this->shapeBuffer); free(this->shapeBuffer);
free(this); free(this);
this = NULL; *instance = NULL;
} }
static CaptureResult d12_dd_hResultToCaptureResult(const HRESULT status) static CaptureResult d12_dd_hResultToCaptureResult(const HRESULT status)
@ -295,8 +305,11 @@ static CaptureResult d12_dd_hResultToCaptureResult(const HRESULT status)
} }
} }
static CaptureResult d12_dd_capture(unsigned frameBufferIndex) static CaptureResult d12_dd_capture(D12Backend * instance,
unsigned frameBufferIndex)
{ {
DDInstance * this = UPCAST(DDInstance, instance);
HRESULT hr; HRESULT hr;
CaptureResult result = CAPTURE_RESULT_ERROR; CaptureResult result = CAPTURE_RESULT_ERROR;
comRef_scopePush(10); comRef_scopePush(10);
@ -337,7 +350,7 @@ retry:
// if we have a new frame // if we have a new frame
if (frameInfo.LastPresentTime.QuadPart != 0) if (frameInfo.LastPresentTime.QuadPart != 0)
if (!d12_dd_handleFrameUpdate(*res)) if (!d12_dd_handleFrameUpdate(this, *res))
{ {
result = CAPTURE_RESULT_ERROR; result = CAPTURE_RESULT_ERROR;
goto exit; goto exit;
@ -348,12 +361,12 @@ retry:
// if the pointer has moved // if the pointer has moved
if (frameInfo.LastMouseUpdateTime.QuadPart != 0) if (frameInfo.LastMouseUpdateTime.QuadPart != 0)
d12_dd_handlePointerMovement( d12_dd_handlePointerMovement(this,
&frameInfo.PointerPosition, &pointer, &postPointer); &frameInfo.PointerPosition, &pointer, &postPointer);
// if the pointer shape has changed // if the pointer shape has changed
if (frameInfo.PointerShapeBufferSize > 0) if (frameInfo.PointerShapeBufferSize > 0)
d12_dd_handlePointerShape( d12_dd_handlePointerShape(this,
&pointer, frameInfo.PointerShapeBufferSize, &postPointer); &pointer, frameInfo.PointerShapeBufferSize, &postPointer);
if (postPointer) if (postPointer)
@ -368,8 +381,11 @@ exit:
return result; return result;
} }
static CaptureResult d12_dd_sync(ID3D12CommandQueue * commandQueue) static CaptureResult d12_dd_sync(D12Backend * instance,
ID3D12CommandQueue * commandQueue)
{ {
DDInstance * this = UPCAST(DDInstance, instance);
if (!this->current) if (!this->current)
return CAPTURE_RESULT_TIMEOUT; return CAPTURE_RESULT_TIMEOUT;
@ -380,8 +396,11 @@ static CaptureResult d12_dd_sync(ID3D12CommandQueue * commandQueue)
return CAPTURE_RESULT_OK; return CAPTURE_RESULT_OK;
} }
static ID3D12Resource * d12_dd_fetch(unsigned frameBufferIndex) static ID3D12Resource * d12_dd_fetch(D12Backend * instance,
unsigned frameBufferIndex)
{ {
DDInstance * this = UPCAST(DDInstance, instance);
if (!this->current) if (!this->current)
return NULL; return NULL;
@ -389,7 +408,7 @@ static ID3D12Resource * d12_dd_fetch(unsigned frameBufferIndex)
return *this->current->d12Res; return *this->current->d12Res;
} }
static void d12_dd_openDesktop(void) static void d12_dd_openDesktop(DDInstance * this)
{ {
this->desktop = OpenInputDesktop(0, FALSE, GENERIC_READ); this->desktop = OpenInputDesktop(0, FALSE, GENERIC_READ);
if (!this->desktop) if (!this->desktop)
@ -415,7 +434,7 @@ static void d12_dd_openDesktop(void)
} }
} }
static bool d12_dd_handleFrameUpdate(IDXGIResource * res) static bool d12_dd_handleFrameUpdate(DDInstance * this, IDXGIResource * res)
{ {
bool result = false; bool result = false;
comRef_scopePush(1); comRef_scopePush(1);
@ -429,7 +448,7 @@ static bool d12_dd_handleFrameUpdate(IDXGIResource * res)
goto exit; goto exit;
} }
if (!d12_dd_getCache(*srcTex, &this->current)) if (!d12_dd_getCache(this, *srcTex, &this->current))
goto exit; goto exit;
/** /**
@ -447,8 +466,8 @@ exit:
return result; return result;
} }
static void d12_dd_handlePointerMovement(DXGI_OUTDUPL_POINTER_POSITION * pos, static void d12_dd_handlePointerMovement(DDInstance * this,
CapturePointer * pointer, bool * changed) DXGI_OUTDUPL_POINTER_POSITION * pos, CapturePointer * pointer, bool * changed)
{ {
bool setPos = false; bool setPos = false;
@ -488,7 +507,7 @@ static void d12_dd_handlePointerMovement(DXGI_OUTDUPL_POINTER_POSITION * pos,
this->lastPosValid = true; this->lastPosValid = true;
} }
static void d12_dd_handlePointerShape( static void d12_dd_handlePointerShape(DDInstance * this,
CapturePointer * pointer, size_t size, bool * changed) CapturePointer * pointer, size_t size, bool * changed)
{ {
HRESULT hr; HRESULT hr;
@ -556,7 +575,8 @@ retry:
*changed = true; *changed = true;
} }
static bool d12_dd_getCache(ID3D11Texture2D * srcTex, DDCacheInfo ** result) static bool d12_dd_getCache(DDInstance * this,
ID3D11Texture2D * srcTex, DDCacheInfo ** result)
{ {
*result = NULL; *result = NULL;
D3D11_TEXTURE2D_DESC srcDesc; D3D11_TEXTURE2D_DESC srcDesc;
@ -597,7 +617,7 @@ static bool d12_dd_getCache(ID3D11Texture2D * srcTex, DDCacheInfo ** result)
return false; return false;
// convert the resource // convert the resource
if (!d12_dd_convertResource(srcTex, &this->cache[freeSlot])) if (!d12_dd_convertResource(this, srcTex, &this->cache[freeSlot]))
return false; return false;
// return the new cache entry // return the new cache entry
@ -605,7 +625,8 @@ static bool d12_dd_getCache(ID3D11Texture2D * srcTex, DDCacheInfo ** result)
return true; return true;
} }
static bool d12_dd_convertResource(ID3D11Texture2D * srcTex, DDCacheInfo * cache) static bool d12_dd_convertResource(DDInstance * this,
ID3D11Texture2D * srcTex, DDCacheInfo * cache)
{ {
bool result = false; bool result = false;
HRESULT hr; HRESULT hr;

View File

@ -166,8 +166,7 @@ static bool d12_create(
this->getPointerBufferFn = getPointerBufferFn; this->getPointerBufferFn = getPointerBufferFn;
this->postPointerBufferFn = postPointerBufferFn; this->postPointerBufferFn = postPointerBufferFn;
this->backend = &D12Backend_DD; if (!d12_createBackend(&D12Backend_DD, &this->backend, frameBuffers))
if (!this->backend->create(frameBuffers))
{ {
DEBUG_ERROR("backend \"%s\" failed to create", this->backend->codeName); DEBUG_ERROR("backend \"%s\" failed to create", this->backend->codeName);
CloseHandle(this->d3d12); CloseHandle(this->d3d12);
@ -279,7 +278,8 @@ retryCreateCommandQueue:
*alignSize = heapDesc.Alignment; *alignSize = heapDesc.Alignment;
// initialize the backend // initialize the backend
if (!this->backend->init(this->debug, *device, *adapter, *output)) if (!this->backend->init(this->backend,
this->debug, *device, *adapter, *output))
goto exit; goto exit;
comRef_toGlobal(this->factory , factory ); comRef_toGlobal(this->factory , factory );
@ -304,7 +304,7 @@ static void d12_stop(void)
static bool d12_deinit(void) static bool d12_deinit(void)
{ {
bool result = true; bool result = true;
if (!this->backend->deinit()) if (!this->backend->deinit(this->backend))
result = false; result = false;
d12_freeCommandGroup(&this->copyCommand); d12_freeCommandGroup(&this->copyCommand);
@ -314,7 +314,7 @@ static bool d12_deinit(void)
static void d12_free(void) static void d12_free(void)
{ {
this->backend->free(); this->backend->free(&this->backend);
FreeLibrary(this->d3d12); FreeLibrary(this->d3d12);
free(this); free(this);
this = NULL; this = NULL;
@ -323,7 +323,7 @@ static void d12_free(void)
static CaptureResult d12_capture( static CaptureResult d12_capture(
unsigned frameBufferIndex, FrameBuffer * frameBuffer) unsigned frameBufferIndex, FrameBuffer * frameBuffer)
{ {
return this->backend->capture(frameBufferIndex); return this->backend->capture(this->backend, frameBufferIndex);
} }
static CaptureResult d12_waitFrame(unsigned frameBufferIndex, static CaptureResult d12_waitFrame(unsigned frameBufferIndex,
@ -333,7 +333,7 @@ static CaptureResult d12_waitFrame(unsigned frameBufferIndex,
comRef_scopePush(1); comRef_scopePush(1);
comRef_defineLocal(ID3D12Resource, src); comRef_defineLocal(ID3D12Resource, src);
*src = this->backend->fetch(frameBufferIndex); *src = this->backend->fetch(this->backend, frameBufferIndex);
if (!*src) if (!*src)
{ {
DEBUG_ERROR("D12 backend failed to produce an expected frame: %u", DEBUG_ERROR("D12 backend failed to produce an expected frame: %u",
@ -383,7 +383,7 @@ static CaptureResult d12_getFrame(unsigned frameBufferIndex,
comRef_scopePush(2); comRef_scopePush(2);
comRef_defineLocal(ID3D12Resource, src); comRef_defineLocal(ID3D12Resource, src);
*src = this->backend->fetch(frameBufferIndex); *src = this->backend->fetch(this->backend, frameBufferIndex);
if (!*src) if (!*src)
{ {
DEBUG_ERROR("D12 backend failed to produce an expected frame: %u", DEBUG_ERROR("D12 backend failed to produce an expected frame: %u",
@ -427,7 +427,7 @@ static CaptureResult d12_getFrame(unsigned frameBufferIndex,
*this->copyCommand.gfxList, &dstLoc, 0, 0, 0, &srcLoc, NULL); *this->copyCommand.gfxList, &dstLoc, 0, 0, 0, &srcLoc, NULL);
// allow the backend to insert a fence into the command queue if it needs it // allow the backend to insert a fence into the command queue if it needs it
result = this->backend->sync(*this->commandQueue); result = this->backend->sync(this->backend, *this->commandQueue);
if (result != CAPTURE_RESULT_OK) if (result != CAPTURE_RESULT_OK)
goto exit; goto exit;