mirror of
https://github.com/gnif/LookingGlass.git
synced 2024-12-22 13:52:57 +00:00
[host] dxgi: decouple backends from the DXGI main struct
This commit is contained in:
parent
eb2796d40b
commit
54bd08c3cb
6 changed files with 361 additions and 232 deletions
|
@ -35,23 +35,37 @@ struct DXGICopyBackend
|
|||
const char * code;
|
||||
|
||||
// create the copy backend
|
||||
bool (*create)(struct DXGIInterface * intf);
|
||||
bool (*create)(unsigned textures);
|
||||
|
||||
// configure the copy backend with the specified format
|
||||
bool (*configure)(unsigned width, unsigned height,
|
||||
DXGI_FORMAT format, unsigned * pitch);
|
||||
bool (*configure)(
|
||||
unsigned width,
|
||||
unsigned height,
|
||||
DXGI_FORMAT format,
|
||||
unsigned bpp,
|
||||
unsigned * pitch);
|
||||
|
||||
// free the copy backend
|
||||
void (*free)(void);
|
||||
|
||||
// called each captured frame after post processing to copy the frame
|
||||
bool (*copyFrame)(struct Texture * tex, ID3D11Texture2D * src);
|
||||
// called just before the copy starts
|
||||
bool (*preCopy)(ID3D11Texture2D * src, unsigned textureIndex);
|
||||
|
||||
// called to copy the full frame
|
||||
bool (*copyFull)(ID3D11Texture2D * src, unsigned textureIndex);
|
||||
|
||||
// called for each damage rect that needs to be copied
|
||||
bool (*copyRect)(ID3D11Texture2D * src, unsigned textureIndex,
|
||||
FrameDamageRect * rect);
|
||||
|
||||
// called just after the copy has finished
|
||||
bool (*postCopy)(ID3D11Texture2D * src, unsigned textureIndex);
|
||||
|
||||
// maps the copied frame into memory
|
||||
CaptureResult (*mapTexture)(struct Texture * tex);
|
||||
CaptureResult (*mapTexture)(unsigned textureIndex, void ** map);
|
||||
|
||||
// unmaps the copied frame from memory
|
||||
void (*unmapTexture)(struct Texture * tex);
|
||||
void (*unmapTexture)(unsigned textureIndex);
|
||||
|
||||
// called just before the frame is released by the frontend
|
||||
void (*preRelease)(void);
|
||||
|
|
|
@ -31,26 +31,29 @@ struct D3D11Backend
|
|||
{
|
||||
RunningAvg avgMapTime;
|
||||
uint64_t usleepMapTime;
|
||||
};
|
||||
|
||||
struct D3D11TexImpl
|
||||
{
|
||||
ID3D11Texture2D ** cpu;
|
||||
unsigned textures;
|
||||
struct
|
||||
{
|
||||
uint64_t copyTime;
|
||||
ID3D11Texture2D ** cpu;
|
||||
}
|
||||
texture[0];
|
||||
};
|
||||
|
||||
#define TEXIMPL(x) ((struct D3D11TexImpl *)(x).impl)
|
||||
|
||||
static struct DXGIInterface * dxgi = NULL;
|
||||
static struct D3D11Backend * this = NULL;
|
||||
|
||||
static void d3d11_free(void);
|
||||
|
||||
static bool d3d11_create(struct DXGIInterface * intf)
|
||||
static bool d3d11_create(unsigned textures)
|
||||
{
|
||||
dxgi = intf;
|
||||
|
||||
DEBUG_ASSERT(!this);
|
||||
this = calloc(1, sizeof(struct D3D11Backend));
|
||||
this = calloc(1,
|
||||
sizeof(struct D3D11Backend) +
|
||||
sizeof(*this->texture) + textures);
|
||||
|
||||
if (!this)
|
||||
{
|
||||
DEBUG_ERROR("failed to allocate D3D11Backend struct");
|
||||
|
@ -58,11 +61,16 @@ static bool d3d11_create(struct DXGIInterface * intf)
|
|||
}
|
||||
|
||||
this->avgMapTime = runningavg_new(10);
|
||||
this->textures = textures;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool d3d11_configure(unsigned width, unsigned height, DXGI_FORMAT format,
|
||||
unsigned * pitch)
|
||||
static bool d3d11_configure(
|
||||
unsigned width,
|
||||
unsigned height,
|
||||
DXGI_FORMAT format,
|
||||
unsigned bpp,
|
||||
unsigned * pitch)
|
||||
{
|
||||
HRESULT status;
|
||||
|
||||
|
@ -81,32 +89,22 @@ static bool d3d11_configure(unsigned width, unsigned height, DXGI_FORMAT format,
|
|||
.MiscFlags = 0
|
||||
};
|
||||
|
||||
for (int i = 0; i < dxgi->maxTextures; ++i)
|
||||
comRef_defineLocal(ID3D11Texture2D, cpu);
|
||||
for(int i = 0; i < this->textures; ++i)
|
||||
{
|
||||
if (!(dxgi->texture[i].impl =
|
||||
(struct D3D11TexImpl *)calloc(sizeof(struct D3D11TexImpl), 1)))
|
||||
{
|
||||
DEBUG_ERROR("Failed to allocate D3D11TexImpl struct");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
struct D3D11TexImpl * teximpl = TEXIMPL(dxgi->texture[i]);
|
||||
|
||||
status = ID3D11Device_CreateTexture2D(*dxgi->device, &cpuTexDesc, NULL,
|
||||
(ID3D11Texture2D **)comRef_newGlobal(&teximpl->cpu));
|
||||
|
||||
status = ID3D11Device_CreateTexture2D(dxgi_getDevice(), &cpuTexDesc, NULL, cpu);
|
||||
if (FAILED(status))
|
||||
{
|
||||
DEBUG_WINERROR("Failed to create CPU texture", status);
|
||||
goto fail;
|
||||
}
|
||||
comRef_toGlobal(this->texture[i].cpu, cpu);
|
||||
}
|
||||
|
||||
// map the texture simply to get the pitch and stride
|
||||
D3D11_MAPPED_SUBRESOURCE mapping;
|
||||
status = ID3D11DeviceContext_Map(*dxgi->deviceContext,
|
||||
*(ID3D11Resource **)TEXIMPL(dxgi->texture[0])->cpu, 0,
|
||||
D3D11_MAP_READ, 0, &mapping);
|
||||
status = ID3D11DeviceContext_Map(dxgi_getContext(),
|
||||
*(ID3D11Resource **)this->texture[0].cpu, 0, D3D11_MAP_READ, 0, &mapping);
|
||||
|
||||
if (FAILED(status))
|
||||
{
|
||||
|
@ -114,8 +112,8 @@ static bool d3d11_configure(unsigned width, unsigned height, DXGI_FORMAT format,
|
|||
goto fail;
|
||||
}
|
||||
|
||||
ID3D11DeviceContext_Unmap(*dxgi->deviceContext,
|
||||
*(ID3D11Resource **)TEXIMPL(dxgi->texture[0])->cpu, 0);
|
||||
ID3D11DeviceContext_Unmap(dxgi_getContext(),
|
||||
*(ID3D11Resource **)this->texture[0].cpu, 0);
|
||||
|
||||
*pitch = mapping.RowPitch;
|
||||
return true;
|
||||
|
@ -129,81 +127,79 @@ static void d3d11_free(void)
|
|||
if (!this)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < dxgi->maxTextures; ++i)
|
||||
{
|
||||
struct D3D11TexImpl * teximpl = TEXIMPL(dxgi->texture[i]);
|
||||
free(teximpl);
|
||||
teximpl = NULL;
|
||||
}
|
||||
|
||||
runningavg_free(&this->avgMapTime);
|
||||
free(this);
|
||||
this = NULL;
|
||||
}
|
||||
|
||||
static bool d3d11_copyFrame(Texture * tex, ID3D11Texture2D * src)
|
||||
static bool d3d11_preCopy(ID3D11Texture2D * src, unsigned textureIndex)
|
||||
{
|
||||
struct D3D11TexImpl * teximpl = TEXIMPL(*tex);
|
||||
ID3D11Texture2D * dst = *teximpl->cpu;
|
||||
|
||||
INTERLOCKED_SECTION(dxgi->deviceContextLock,
|
||||
{
|
||||
tex->copyTime = microtime();
|
||||
|
||||
if (tex->texDamageCount < 0)
|
||||
ID3D11DeviceContext_CopyResource(*dxgi->deviceContext,
|
||||
(ID3D11Resource *)dst, (ID3D11Resource *)src);
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < tex->texDamageCount; ++i)
|
||||
{
|
||||
FrameDamageRect * rect = tex->texDamageRects + i;
|
||||
D3D11_BOX box =
|
||||
{
|
||||
.left = rect->x,
|
||||
.top = rect->y,
|
||||
.front = 0,
|
||||
.back = 1,
|
||||
.right = rect->x + rect->width,
|
||||
.bottom = rect->y + rect->height,
|
||||
};
|
||||
|
||||
if (dxgi->outputFormat == CAPTURE_FMT_BGR)
|
||||
{
|
||||
box.left = box.left * 3 / 4;
|
||||
box.right = box.right * 3 / 4;
|
||||
}
|
||||
|
||||
ID3D11DeviceContext_CopySubresourceRegion(*dxgi->deviceContext,
|
||||
(ID3D11Resource *)dst, 0, box.left, box.top, 0,
|
||||
(ID3D11Resource *)src, 0, &box);
|
||||
}
|
||||
}
|
||||
|
||||
ID3D11DeviceContext_Flush(*dxgi->deviceContext);
|
||||
});
|
||||
dxgi_contextLock();
|
||||
this->texture[textureIndex].copyTime = microtime();
|
||||
return true;
|
||||
}
|
||||
|
||||
static CaptureResult d3d11_mapTexture(Texture * tex)
|
||||
static bool d3d11_copyFull(ID3D11Texture2D * src, unsigned textureIndex)
|
||||
{
|
||||
struct D3D11TexImpl * teximpl = TEXIMPL(*tex);
|
||||
D3D11_MAPPED_SUBRESOURCE map;
|
||||
ID3D11Texture2D * dst = *this->texture[textureIndex].cpu;
|
||||
|
||||
ID3D11DeviceContext_CopyResource(dxgi_getContext(),
|
||||
(ID3D11Resource *)dst, (ID3D11Resource *)src);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static bool d3d11_copyRect(ID3D11Texture2D * src, unsigned textureIndex,
|
||||
FrameDamageRect * rect)
|
||||
{
|
||||
ID3D11Texture2D * dst = *this->texture[textureIndex].cpu;
|
||||
|
||||
D3D11_BOX box =
|
||||
{
|
||||
.left = rect->x,
|
||||
.top = rect->y,
|
||||
.front = 0,
|
||||
.back = 1,
|
||||
.right = rect->x + rect->width,
|
||||
.bottom = rect->y + rect->height,
|
||||
};
|
||||
|
||||
ID3D11DeviceContext_CopySubresourceRegion(
|
||||
dxgi_getContext(),
|
||||
(ID3D11Resource *)dst, 0, box.left, box.top, 0,
|
||||
(ID3D11Resource *)src, 0, &box);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool d3d11_postCopy(ID3D11Texture2D * src, unsigned textureIndex)
|
||||
{
|
||||
ID3D11DeviceContext_Flush(dxgi_getContext());
|
||||
dxgi_contextUnlock();
|
||||
return true;
|
||||
}
|
||||
|
||||
static CaptureResult d3d11_mapTexture(unsigned textureIndex, void ** map)
|
||||
{
|
||||
ID3D11Resource * cpu = *(ID3D11Resource **)this->texture[textureIndex].cpu;
|
||||
|
||||
// sleep until it's close to time to map
|
||||
const uint64_t delta = microtime() - tex->copyTime;
|
||||
const uint64_t delta = microtime() - this->texture[textureIndex].copyTime;
|
||||
if (delta < this->usleepMapTime)
|
||||
usleep(this->usleepMapTime - delta);
|
||||
|
||||
D3D11_MAPPED_SUBRESOURCE mappedRes;
|
||||
|
||||
// try to map the resource, but don't wait for it
|
||||
for (int i = 0; ; ++i)
|
||||
{
|
||||
HRESULT status;
|
||||
|
||||
INTERLOCKED_SECTION(dxgi->deviceContextLock, {
|
||||
status = ID3D11DeviceContext_Map(*dxgi->deviceContext,
|
||||
(ID3D11Resource *)*teximpl->cpu, 0, D3D11_MAP_READ, 0x100000L, &map);
|
||||
});
|
||||
dxgi_contextLock();
|
||||
status = ID3D11DeviceContext_Map(dxgi_getContext(), cpu, 0, D3D11_MAP_READ,
|
||||
0x100000L, &mappedRes);
|
||||
dxgi_contextUnlock();
|
||||
if (status == DXGI_ERROR_WAS_STILL_DRAWING)
|
||||
{
|
||||
if (i == 100)
|
||||
|
@ -222,23 +218,23 @@ static CaptureResult d3d11_mapTexture(Texture * tex)
|
|||
break;
|
||||
}
|
||||
|
||||
tex->map = map.pData;
|
||||
*map = mappedRes.pData;
|
||||
|
||||
// update the sleep average and sleep for 80% of the average on the next call
|
||||
runningavg_push(this->avgMapTime, microtime() - tex->copyTime);
|
||||
runningavg_push(this->avgMapTime,
|
||||
microtime() - this->texture[textureIndex].copyTime);
|
||||
|
||||
this->usleepMapTime = (uint64_t)(runningavg_calc(this->avgMapTime) * 0.8);
|
||||
return CAPTURE_RESULT_OK;
|
||||
}
|
||||
|
||||
static void d3d11_unmapTexture(Texture * tex)
|
||||
static void d3d11_unmapTexture(unsigned textureIndex)
|
||||
{
|
||||
struct D3D11TexImpl * teximpl = TEXIMPL(*tex);
|
||||
ID3D11Resource * cpu = *(ID3D11Resource **)this->texture[textureIndex].cpu;
|
||||
|
||||
INTERLOCKED_SECTION(dxgi->deviceContextLock, {
|
||||
ID3D11DeviceContext_Unmap(*dxgi->deviceContext,
|
||||
(ID3D11Resource *)*teximpl->cpu, 0);
|
||||
});
|
||||
tex->map = NULL;
|
||||
dxgi_contextLock();
|
||||
ID3D11DeviceContext_Unmap(dxgi_getContext(), cpu, 0);
|
||||
dxgi_contextUnlock();
|
||||
}
|
||||
|
||||
static void d3d11_preRelease(void)
|
||||
|
@ -252,7 +248,10 @@ struct DXGICopyBackend copyBackendD3D11 = {
|
|||
.create = d3d11_create,
|
||||
.configure = d3d11_configure,
|
||||
.free = d3d11_free,
|
||||
.copyFrame = d3d11_copyFrame,
|
||||
.preCopy = d3d11_preCopy,
|
||||
.copyFull = d3d11_copyFull,
|
||||
.copyRect = d3d11_copyRect,
|
||||
.postCopy = d3d11_postCopy,
|
||||
.mapTexture = d3d11_mapTexture,
|
||||
.unmapTexture = d3d11_unmapTexture,
|
||||
.preRelease = d3d11_preRelease,
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2023 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
|
@ -58,7 +57,6 @@ struct D3D12Backend
|
|||
float copySleep;
|
||||
ID3D12Device ** device;
|
||||
ID3D12CommandQueue ** commandQueue;
|
||||
struct D3D12Texture * texture;
|
||||
UINT64 fenceValue;
|
||||
ID3D12Fence ** fence;
|
||||
HANDLE event;
|
||||
|
@ -66,10 +64,13 @@ struct D3D12Backend
|
|||
// shared handle cache
|
||||
struct SharedCache sharedCache[10];
|
||||
int sharedCacheCount;
|
||||
ID3D12Resource * d12src;
|
||||
|
||||
unsigned textures;
|
||||
struct D3D12Texture texture[0];
|
||||
};
|
||||
|
||||
static struct DXGIInterface * dxgi = NULL;
|
||||
static struct D3D12Backend * this = NULL;
|
||||
static struct D3D12Backend * this = NULL;
|
||||
|
||||
typedef HRESULT (*D3D12CreateDevice_t)(
|
||||
IUnknown *pAdapter,
|
||||
|
@ -85,18 +86,17 @@ typedef HRESULT (*D3D12GetDebugInterface_t)(
|
|||
|
||||
static void d3d12_free(void);
|
||||
|
||||
static bool d3d12_create(struct DXGIInterface * intf)
|
||||
static bool d3d12_create(unsigned textures)
|
||||
{
|
||||
DEBUG_ASSERT(!this);
|
||||
|
||||
HRESULT status;
|
||||
dxgi = intf;
|
||||
|
||||
HMODULE d3d12 = LoadLibrary("d3d12.dll");
|
||||
if (!d3d12)
|
||||
return false;
|
||||
|
||||
if (dxgi->debug)
|
||||
if (dxgi_debug())
|
||||
{
|
||||
D3D12GetDebugInterface_t D3D12GetDebugInterface = (D3D12GetDebugInterface_t)
|
||||
GetProcAddress(d3d12, "D3D12GetDebugInterface");
|
||||
|
@ -118,20 +118,17 @@ static bool d3d12_create(struct DXGIInterface * intf)
|
|||
if (!D3D12CreateDevice)
|
||||
return false;
|
||||
|
||||
this = calloc(1, sizeof(struct D3D12Backend));
|
||||
this = calloc(1,
|
||||
sizeof(struct D3D12Backend) +
|
||||
sizeof(*this->texture) * textures);
|
||||
|
||||
if (!this)
|
||||
{
|
||||
DEBUG_ERROR("failed to allocate D3D12Backend struct");
|
||||
return false;
|
||||
}
|
||||
|
||||
this->texture = calloc(dxgi->maxTextures, sizeof(struct D3D12Texture));
|
||||
if (!this->texture)
|
||||
{
|
||||
DEBUG_ERROR("Failed to allocate memory");
|
||||
return false;
|
||||
}
|
||||
|
||||
this->textures = textures;
|
||||
this->copySleep = option_get_float("dxgi", "d3d12CopySleep");
|
||||
DEBUG_INFO("Sleep before copy : %f ms", this->copySleep);
|
||||
|
||||
|
@ -139,8 +136,8 @@ static bool d3d12_create(struct DXGIInterface * intf)
|
|||
comRef_scopePush();
|
||||
|
||||
comRef_defineLocal(ID3D12Device, device);
|
||||
status = D3D12CreateDevice(*(IUnknown **)dxgi->adapter, D3D_FEATURE_LEVEL_11_0,
|
||||
&IID_ID3D12Device, (void **)device);
|
||||
status = D3D12CreateDevice((IUnknown *)dxgi_getAdapter(),
|
||||
D3D_FEATURE_LEVEL_11_0, &IID_ID3D12Device, (void **)device);
|
||||
|
||||
if (FAILED(status))
|
||||
{
|
||||
|
@ -200,8 +197,12 @@ exit:
|
|||
return result;
|
||||
}
|
||||
|
||||
static bool d3d12_configure(unsigned width, unsigned height, DXGI_FORMAT format,
|
||||
unsigned * pitch)
|
||||
static bool d3d12_configure(
|
||||
unsigned width,
|
||||
unsigned height,
|
||||
DXGI_FORMAT format,
|
||||
unsigned bpp,
|
||||
unsigned * pitch)
|
||||
{
|
||||
bool result = false;
|
||||
HRESULT status;
|
||||
|
@ -210,7 +211,7 @@ static bool d3d12_configure(unsigned width, unsigned height, DXGI_FORMAT format,
|
|||
this->width = width;
|
||||
this->height = height;
|
||||
this->format = format;
|
||||
this->pitch = ALIGN_TO(width * dxgi->bpp, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
|
||||
this->pitch = ALIGN_TO(width * bpp, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
|
||||
|
||||
D3D12_HEAP_PROPERTIES readbackHeapProperties =
|
||||
{
|
||||
|
@ -237,7 +238,7 @@ static bool d3d12_configure(unsigned width, unsigned height, DXGI_FORMAT format,
|
|||
comRef_defineLocal(ID3D12CommandAllocator , commandAllocator );
|
||||
comRef_defineLocal(ID3D12GraphicsCommandList, graphicsCommandList);
|
||||
comRef_defineLocal(ID3D12CommandList , commandList );
|
||||
for (int i = 0; i < dxgi->maxTextures; ++i)
|
||||
for (int i = 0; i < this->textures; ++i)
|
||||
{
|
||||
status = ID3D12Device_CreateCommittedResource(*this->device,
|
||||
&readbackHeapProperties,
|
||||
|
@ -306,8 +307,6 @@ static bool d3d12_configure(unsigned width, unsigned height, DXGI_FORMAT format,
|
|||
goto exit;
|
||||
}
|
||||
|
||||
dxgi->texture[i].impl = this->texture + i;
|
||||
|
||||
comRef_toGlobal(this->texture[i].tex , texture );
|
||||
comRef_toGlobal(this->texture[i].fence , fence );
|
||||
comRef_toGlobal(this->texture[i].commandAllocator , commandAllocator );
|
||||
|
@ -329,13 +328,9 @@ static void d3d12_free(void)
|
|||
if (!this)
|
||||
return;
|
||||
|
||||
if (this->texture)
|
||||
{
|
||||
for (int i = 0; i < dxgi->maxTextures; ++i)
|
||||
if (this->texture[i].event)
|
||||
CloseHandle(this->texture[i].event);
|
||||
free(this->texture);
|
||||
}
|
||||
for (int i = 0; i < this->textures; ++i)
|
||||
if (this->texture[i].event)
|
||||
CloseHandle(this->texture[i].event);
|
||||
|
||||
if (this->event)
|
||||
CloseHandle(this->event);
|
||||
|
@ -344,86 +339,97 @@ static void d3d12_free(void)
|
|||
this = NULL;
|
||||
}
|
||||
|
||||
static bool d3d12_copyFrame(Texture * parent, ID3D11Texture2D * src)
|
||||
static bool d3d12_preCopy(ID3D11Texture2D * src, unsigned textureIndex)
|
||||
{
|
||||
// we need to flush the DX11 context explicity or we get tons of lag
|
||||
ID3D11DeviceContext_Flush(*dxgi->deviceContext);
|
||||
|
||||
comRef_scopePush();
|
||||
bool result = false;
|
||||
|
||||
struct D3D12Texture * tex = parent->impl;
|
||||
bool fail = true;
|
||||
comRef_defineLocal(IDXGIResource1, res1);
|
||||
ID3D12Resource * d12src = NULL;
|
||||
HRESULT status;
|
||||
// we need to flush the DX11 context explicity or we get tons of lag
|
||||
dxgi_contextLock();
|
||||
ID3D11DeviceContext_Flush(dxgi_getContext());
|
||||
dxgi_contextUnlock();
|
||||
|
||||
if (this->copySleep > 0)
|
||||
nsleep((uint64_t)(this->copySleep * 1000000));
|
||||
|
||||
this->d12src = NULL;
|
||||
if (this->sharedCacheCount > -1)
|
||||
{
|
||||
// see if there is a cached handle already available for this texture
|
||||
for(int i = 0; i < this->sharedCacheCount; ++i)
|
||||
if (this->sharedCache[i].tex == src)
|
||||
{
|
||||
d12src = *this->sharedCache[i].d12src;
|
||||
break;
|
||||
this->d12src = *this->sharedCache[i].d12src;
|
||||
result = true;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
if (!d12src)
|
||||
comRef_defineLocal(IDXGIResource1, res1);
|
||||
HRESULT status = ID3D11Texture2D_QueryInterface(src,
|
||||
&IID_IDXGIResource1, (void **)res1);
|
||||
|
||||
if (FAILED(status))
|
||||
{
|
||||
status = ID3D11Texture2D_QueryInterface(src,
|
||||
&IID_IDXGIResource1, (void **)res1);
|
||||
DEBUG_WINERROR("Failed to get IDXGIResource1 from texture", status);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (FAILED(status))
|
||||
{
|
||||
DEBUG_WINERROR("Failed to get IDXGIResource1 from texture", status);
|
||||
goto cleanup;
|
||||
}
|
||||
HANDLE handle;
|
||||
status = IDXGIResource1_CreateSharedHandle(*res1,
|
||||
NULL, DXGI_SHARED_RESOURCE_READ, NULL, &handle);
|
||||
|
||||
HANDLE handle;
|
||||
status = IDXGIResource1_CreateSharedHandle(*res1,
|
||||
NULL, DXGI_SHARED_RESOURCE_READ, NULL, &handle);
|
||||
if (FAILED(status))
|
||||
{
|
||||
DEBUG_WINERROR("Failed to get create shared handle for texture", status);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (FAILED(status))
|
||||
{
|
||||
DEBUG_WINERROR("Failed to get create shared handle for texture", status);
|
||||
goto cleanup;
|
||||
}
|
||||
status = ID3D12Device_OpenSharedHandle(*this->device,
|
||||
handle, &IID_ID3D12Resource, (void **)&this->d12src);
|
||||
|
||||
status = ID3D12Device_OpenSharedHandle(*this->device,
|
||||
handle, &IID_ID3D12Resource, (void **)&d12src);
|
||||
CloseHandle(handle);
|
||||
CloseHandle(handle);
|
||||
|
||||
if (FAILED(status))
|
||||
{
|
||||
DEBUG_WINERROR("Failed to open the shared handle for texture", status);
|
||||
goto cleanup;
|
||||
}
|
||||
if (FAILED(status))
|
||||
{
|
||||
DEBUG_WINERROR("Failed to open the shared handle for texture", status);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
// store the texture for later use
|
||||
if (this->sharedCacheCount < ARRAY_LENGTH(this->sharedCache))
|
||||
// store the texture for later use
|
||||
if (this->sharedCacheCount < ARRAY_LENGTH(this->sharedCache))
|
||||
{
|
||||
struct SharedCache *cache = &this->sharedCache[this->sharedCacheCount++];
|
||||
cache->tex = src;
|
||||
*comRef_newGlobal(&cache->d12src) = (IUnknown *)this->d12src;
|
||||
}
|
||||
else
|
||||
{
|
||||
// too many handles to cache, disable the cache entirely
|
||||
for(int i = 0; i < this->sharedCacheCount; ++i)
|
||||
{
|
||||
struct SharedCache *cache = &this->sharedCache[this->sharedCacheCount++];
|
||||
cache->tex = src;
|
||||
*comRef_newGlobal(&cache->d12src) = (IUnknown *)d12src;
|
||||
}
|
||||
else
|
||||
{
|
||||
// too many handles to cache, disable the cache entirely
|
||||
for(int i = 0; i < this->sharedCacheCount; ++i)
|
||||
{
|
||||
struct SharedCache *cache = &this->sharedCache[this->sharedCacheCount++];
|
||||
comRef_release(cache->d12src);
|
||||
}
|
||||
this->sharedCacheCount = -1;
|
||||
comRef_release(cache->d12src);
|
||||
}
|
||||
this->sharedCacheCount = -1;
|
||||
}
|
||||
|
||||
result = true;
|
||||
|
||||
exit:
|
||||
if (!result)
|
||||
comRef_scopePop();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool d3d12_copyFull(ID3D11Texture2D * src, unsigned textureIndex)
|
||||
{
|
||||
struct D3D12Texture * tex = &this->texture[textureIndex];
|
||||
|
||||
D3D12_TEXTURE_COPY_LOCATION srcLoc =
|
||||
{
|
||||
.pResource = d12src,
|
||||
.pResource = this->d12src,
|
||||
.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX,
|
||||
.SubresourceIndex = 0
|
||||
};
|
||||
|
@ -446,42 +452,69 @@ static bool d3d12_copyFrame(Texture * parent, ID3D11Texture2D * src)
|
|||
}
|
||||
};
|
||||
|
||||
if (parent->texDamageCount < 0)
|
||||
ID3D12GraphicsCommandList_CopyTextureRegion(*tex->graphicsCommandList,
|
||||
&destLoc, 0, 0, 0, &srcLoc, NULL);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static bool d3d12_copyRect(ID3D11Texture2D * src, unsigned textureIndex,
|
||||
FrameDamageRect * rect)
|
||||
{
|
||||
struct D3D12Texture * tex = &this->texture[textureIndex];
|
||||
|
||||
D3D12_TEXTURE_COPY_LOCATION srcLoc =
|
||||
{
|
||||
ID3D12GraphicsCommandList_CopyTextureRegion(*tex->graphicsCommandList,
|
||||
&destLoc, 0, 0, 0, &srcLoc, NULL);
|
||||
}
|
||||
else
|
||||
.pResource = this->d12src,
|
||||
.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX,
|
||||
.SubresourceIndex = 0
|
||||
};
|
||||
|
||||
D3D12_TEXTURE_COPY_LOCATION destLoc =
|
||||
{
|
||||
for (int i = 0; i < parent->texDamageCount; ++i)
|
||||
.pResource = *tex->tex,
|
||||
.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT,
|
||||
.PlacedFootprint =
|
||||
{
|
||||
FrameDamageRect * rect = parent->texDamageRects + i;
|
||||
D3D12_BOX box =
|
||||
.Offset = 0,
|
||||
.Footprint =
|
||||
{
|
||||
.left = rect->x,
|
||||
.top = rect->y,
|
||||
.front = 0,
|
||||
.back = 1,
|
||||
.right = rect->x + rect->width,
|
||||
.bottom = rect->y + rect->height,
|
||||
};
|
||||
|
||||
if (dxgi->outputFormat == CAPTURE_FMT_BGR)
|
||||
{
|
||||
box.left = box.left * 3 / 4;
|
||||
box.right = box.right * 3 / 4;
|
||||
.Format = this->format,
|
||||
.Width = this->width,
|
||||
.Height = this->height,
|
||||
.Depth = 1,
|
||||
.RowPitch = this->pitch,
|
||||
}
|
||||
|
||||
ID3D12GraphicsCommandList_CopyTextureRegion(*tex->graphicsCommandList,
|
||||
&destLoc, box.left, box.top, 0, &srcLoc, &box);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
status = ID3D12GraphicsCommandList_Close(*tex->graphicsCommandList);
|
||||
D3D12_BOX box =
|
||||
{
|
||||
.left = rect->x,
|
||||
.top = rect->y,
|
||||
.front = 0,
|
||||
.back = 1,
|
||||
.right = rect->x + rect->width,
|
||||
.bottom = rect->y + rect->height,
|
||||
};
|
||||
|
||||
ID3D12GraphicsCommandList_CopyTextureRegion(*tex->graphicsCommandList,
|
||||
&destLoc, box.left, box.top, 0, &srcLoc, &box);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool d3d12_postCopy(ID3D11Texture2D * src, unsigned textureIndex)
|
||||
{
|
||||
bool result = false;
|
||||
struct D3D12Texture * tex = &this->texture[textureIndex];
|
||||
|
||||
HRESULT status = ID3D12GraphicsCommandList_Close(*tex->graphicsCommandList);
|
||||
if (FAILED(status))
|
||||
{
|
||||
DEBUG_WINERROR("Failed to close command list", status);
|
||||
goto cleanup;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ID3D12CommandQueue_ExecuteCommandLists(*this->commandQueue,
|
||||
|
@ -492,7 +525,7 @@ static bool d3d12_copyFrame(Texture * parent, ID3D11Texture2D * src)
|
|||
if (FAILED(status))
|
||||
{
|
||||
DEBUG_WINERROR("Failed to signal capture fence", status);
|
||||
goto cleanup;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ResetEvent(this->event);
|
||||
|
@ -501,7 +534,7 @@ static bool d3d12_copyFrame(Texture * parent, ID3D11Texture2D * src)
|
|||
if (FAILED(status))
|
||||
{
|
||||
DEBUG_WINERROR("Failed to signal capture fence event", status);
|
||||
goto cleanup;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
status = ID3D12CommandQueue_Signal(*this->commandQueue,
|
||||
|
@ -509,7 +542,7 @@ static bool d3d12_copyFrame(Texture * parent, ID3D11Texture2D * src)
|
|||
if (FAILED(status))
|
||||
{
|
||||
DEBUG_WINERROR("Failed to signal texture fence", status);
|
||||
goto cleanup;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
status = ID3D12Fence_SetEventOnCompletion(*tex->fence,
|
||||
|
@ -517,18 +550,19 @@ static bool d3d12_copyFrame(Texture * parent, ID3D11Texture2D * src)
|
|||
if (FAILED(status))
|
||||
{
|
||||
DEBUG_WINERROR("Failed to signal texture fence event", status);
|
||||
goto cleanup;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
fail = false;
|
||||
cleanup:
|
||||
comRef_scopePop();
|
||||
return !fail;
|
||||
result = true;
|
||||
|
||||
exit:
|
||||
comRef_scopePop(); //push is in pre-copy
|
||||
return result;
|
||||
}
|
||||
|
||||
static CaptureResult d3d12_mapTexture(Texture * parent)
|
||||
static CaptureResult d3d12_mapTexture(unsigned textureIndex, void ** map)
|
||||
{
|
||||
struct D3D12Texture * tex = parent->impl;
|
||||
struct D3D12Texture * tex = &this->texture[textureIndex];
|
||||
HRESULT status;
|
||||
|
||||
WaitForSingleObject(tex->event, INFINITE);
|
||||
|
@ -553,7 +587,7 @@ static CaptureResult d3d12_mapTexture(Texture * parent)
|
|||
.Begin = 0,
|
||||
.End = this->pitch * this->height
|
||||
};
|
||||
status = ID3D12Resource_Map(*tex->tex, 0, &range, &parent->map);
|
||||
status = ID3D12Resource_Map(*tex->tex, 0, &range, map);
|
||||
|
||||
if (FAILED(status))
|
||||
{
|
||||
|
@ -564,9 +598,9 @@ static CaptureResult d3d12_mapTexture(Texture * parent)
|
|||
return CAPTURE_RESULT_OK;
|
||||
}
|
||||
|
||||
static void d3d12_unmapTexture(Texture * parent)
|
||||
static void d3d12_unmapTexture(unsigned textureIndex)
|
||||
{
|
||||
struct D3D12Texture * tex = parent->impl;
|
||||
struct D3D12Texture * tex = &this->texture[textureIndex];
|
||||
|
||||
D3D12_RANGE range =
|
||||
{
|
||||
|
@ -574,7 +608,6 @@ static void d3d12_unmapTexture(Texture * parent)
|
|||
.End = 0
|
||||
};
|
||||
ID3D12Resource_Unmap(*tex->tex, 0, &range);
|
||||
parent->map = NULL;
|
||||
}
|
||||
|
||||
static void d3d12_preRelease(void)
|
||||
|
@ -589,7 +622,10 @@ struct DXGICopyBackend copyBackendD3D12 =
|
|||
.create = d3d12_create,
|
||||
.configure = d3d12_configure,
|
||||
.free = d3d12_free,
|
||||
.copyFrame = d3d12_copyFrame,
|
||||
.preCopy = d3d12_preCopy,
|
||||
.copyFull = d3d12_copyFull,
|
||||
.copyRect = d3d12_copyRect,
|
||||
.postCopy = d3d12_postCopy,
|
||||
.mapTexture = d3d12_mapTexture,
|
||||
.unmapTexture = d3d12_unmapTexture,
|
||||
.preRelease = d3d12_preRelease,
|
||||
|
|
|
@ -708,7 +708,7 @@ static bool dxgi_init(void)
|
|||
{
|
||||
if (!strcasecmp(copyBackend, backends[i]->code))
|
||||
{
|
||||
if (!backends[i]->create(this))
|
||||
if (!backends[i]->create(this->maxTextures))
|
||||
{
|
||||
DEBUG_ERROR("Failed to initialize selected capture backend: %s", backends[i]->name);
|
||||
backends[i]->free();
|
||||
|
@ -795,7 +795,7 @@ static bool dxgi_deinit(void)
|
|||
Texture * tex = &this->texture[i];
|
||||
if (!tex->map)
|
||||
continue;
|
||||
this->backend->unmapTexture(tex);
|
||||
this->backend->unmapTexture(i);
|
||||
tex->map = NULL;
|
||||
}
|
||||
|
||||
|
@ -1099,7 +1099,12 @@ static CaptureResult dxgi_capture(void)
|
|||
|
||||
unsigned pitch = 0;
|
||||
LG_LOCK(this->deviceContextLock);
|
||||
if (!this->backend->configure(cols, rows, this->dxgiFormat, &pitch))
|
||||
if (!this->backend->configure(
|
||||
cols,
|
||||
rows,
|
||||
this->dxgiFormat,
|
||||
this->bpp,
|
||||
&pitch))
|
||||
{
|
||||
LG_UNLOCK(this->deviceContextLock);
|
||||
DEBUG_ERROR("Failed to configure the copy backend");
|
||||
|
@ -1132,7 +1137,44 @@ static CaptureResult dxgi_capture(void)
|
|||
computeFrameDamage(tex);
|
||||
computeTexDamage(tex);
|
||||
|
||||
if (!this->backend->copyFrame(tex, dst))
|
||||
if (!this->backend->preCopy(dst, this->texWIndex))
|
||||
{
|
||||
result = CAPTURE_RESULT_ERROR;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (tex->texDamageCount <= 0)
|
||||
{
|
||||
if (!this->backend->copyFull(dst, this->texWIndex))
|
||||
{
|
||||
// call this so the backend can cleanup
|
||||
this->backend->postCopy(dst, this->texWIndex);
|
||||
result = CAPTURE_RESULT_ERROR;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < tex->texDamageCount; ++i)
|
||||
{
|
||||
FrameDamageRect * rect = &tex->texDamageRects[i];
|
||||
|
||||
// correct the damage rect for BGR packed data
|
||||
if (this->outputFormat == CAPTURE_FMT_BGR)
|
||||
{
|
||||
rect->x = (rect->x * 3 ) / 4; // round down
|
||||
rect->width = (rect->width * 3 + 3) / 4; // round up
|
||||
}
|
||||
|
||||
if (!this->backend->copyRect(dst, this->texWIndex, rect))
|
||||
{
|
||||
result = CAPTURE_RESULT_ERROR;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!this->backend->postCopy(dst, this->texWIndex))
|
||||
{
|
||||
result = CAPTURE_RESULT_ERROR;
|
||||
goto exit;
|
||||
|
@ -1266,7 +1308,7 @@ static CaptureResult dxgi_waitFrame(CaptureFrame * frame, const size_t maxFrameS
|
|||
|
||||
Texture * tex = &this->texture[this->texRIndex];
|
||||
|
||||
CaptureResult result = this->backend->mapTexture(tex);
|
||||
CaptureResult result = this->backend->mapTexture(this->texRIndex, &tex->map);
|
||||
if (result != CAPTURE_RESULT_OK)
|
||||
return result;
|
||||
|
||||
|
@ -1355,7 +1397,8 @@ static CaptureResult dxgi_getFrame(FrameBuffer * frame, int frameIndex)
|
|||
damage->count = -1;
|
||||
}
|
||||
|
||||
this->backend->unmapTexture(tex);
|
||||
this->backend->unmapTexture(this->texRIndex);
|
||||
tex->map = NULL;
|
||||
tex->state = TEXTURE_STATE_UNUSED;
|
||||
|
||||
if (++this->texRIndex == this->maxTextures)
|
||||
|
@ -1549,6 +1592,36 @@ static void ppFreeAll(void)
|
|||
}
|
||||
}
|
||||
|
||||
IDXGIAdapter1 * dxgi_getAdapter(void)
|
||||
{
|
||||
return *this->adapter;
|
||||
}
|
||||
|
||||
ID3D11Device * dxgi_getDevice(void)
|
||||
{
|
||||
return *this->device;
|
||||
}
|
||||
|
||||
ID3D11DeviceContext * dxgi_getContext(void)
|
||||
{
|
||||
return *this->deviceContext;
|
||||
}
|
||||
|
||||
void dxgi_contextLock(void)
|
||||
{
|
||||
LG_LOCK(this->deviceContextLock);
|
||||
};
|
||||
|
||||
void dxgi_contextUnlock(void)
|
||||
{
|
||||
LG_UNLOCK(this->deviceContextLock);
|
||||
};
|
||||
|
||||
bool dxgi_debug(void)
|
||||
{
|
||||
return this->debug;
|
||||
}
|
||||
|
||||
struct CaptureInterface Capture_DXGI =
|
||||
{
|
||||
.shortName = "DXGI",
|
||||
|
|
|
@ -50,7 +50,6 @@ typedef struct Texture
|
|||
unsigned int formatVer;
|
||||
volatile enum TextureState state;
|
||||
void * map;
|
||||
uint64_t copyTime;
|
||||
uint32_t damageRectsCount;
|
||||
FrameDamageRect damageRects[KVMFR_MAX_DAMAGE_RECTS];
|
||||
int texDamageCount;
|
||||
|
@ -63,11 +62,12 @@ typedef struct Texture
|
|||
}
|
||||
Texture;
|
||||
|
||||
struct FrameDamage
|
||||
typedef struct FrameDamage
|
||||
{
|
||||
int count;
|
||||
FrameDamageRect rects[KVMFR_MAX_DAMAGE_RECTS];
|
||||
};
|
||||
}
|
||||
FrameDamage;
|
||||
|
||||
struct DXGIInterface
|
||||
{
|
||||
|
@ -122,4 +122,11 @@ struct DXGIInterface
|
|||
struct FrameDamage frameDamage[LGMP_Q_FRAME_LEN];
|
||||
};
|
||||
|
||||
IDXGIAdapter1 * dxgi_getAdapter(void);
|
||||
ID3D11Device * dxgi_getDevice(void);
|
||||
ID3D11DeviceContext * dxgi_getContext(void);
|
||||
void dxgi_contextLock(void);
|
||||
void dxgi_contextUnlock(void);
|
||||
bool dxgi_debug(void);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -78,7 +78,7 @@ static bool rgb24_configure(void * opaque,
|
|||
|
||||
if (!this.pshader)
|
||||
{
|
||||
this.width = *cols * 3 / 4;
|
||||
this.width = (*cols * 3 + 3) / 4;
|
||||
this.height = *rows;
|
||||
|
||||
char sOutputWidth[6], sOutputHeight[6];
|
||||
|
|
Loading…
Reference in a new issue