[host] dxgi: decouple backends from the DXGI main struct

This commit is contained in:
Geoffrey McRae 2023-11-07 20:40:05 +11:00
parent eb2796d40b
commit 54bd08c3cb
6 changed files with 361 additions and 232 deletions

View file

@ -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);

View file

@ -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,

View file

@ -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,

View file

@ -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",

View file

@ -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

View file

@ -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];