[host] dxgi: add preRelease callback

This is meant to avoid freeing the texture before the copy has finished.
This commit is contained in:
Quantum 2021-08-12 05:03:27 -04:00 committed by Geoffrey McRae
parent 5a93f1e00c
commit 68e5b812a9
4 changed files with 74 additions and 8 deletions

View file

@ -188,6 +188,11 @@ static void d3d11_unmapTexture(Texture * tex)
tex->map = NULL; tex->map = NULL;
} }
static void d3d11_preRelease(void)
{
// Nothing needs to be done.
}
struct DXGICopyBackend copyBackendD3D11 = { struct DXGICopyBackend copyBackendD3D11 = {
.name = "Direct3D 11", .name = "Direct3D 11",
.create = d3d11_create, .create = d3d11_create,
@ -195,4 +200,5 @@ struct DXGICopyBackend copyBackendD3D11 = {
.copyFrame = d3d11_copyFrame, .copyFrame = d3d11_copyFrame,
.mapTexture = d3d11_mapTexture, .mapTexture = d3d11_mapTexture,
.unmapTexture = d3d11_unmapTexture, .unmapTexture = d3d11_unmapTexture,
.preRelease = d3d11_preRelease,
}; };

View file

@ -29,7 +29,6 @@
struct D3D12Texture struct D3D12Texture
{ {
ID3D12Resource * src;
ID3D12Resource * tex; ID3D12Resource * tex;
ID3D12CommandAllocator * commandAllocator; ID3D12CommandAllocator * commandAllocator;
ID3D12CommandList * commandList; ID3D12CommandList * commandList;
@ -43,7 +42,11 @@ struct D3D12Backend
{ {
ID3D12Device * device; ID3D12Device * device;
ID3D12CommandQueue * commandQueue; ID3D12CommandQueue * commandQueue;
ID3D12Resource * src;
struct D3D12Texture * texture; struct D3D12Texture * texture;
UINT64 fenceValue;
ID3D12Fence * fence;
HANDLE event;
}; };
static struct DXGIInterface * dxgi = NULL; static struct DXGIInterface * dxgi = NULL;
@ -122,6 +125,22 @@ static bool d3d12_create(struct DXGIInterface * intf)
goto fail; goto fail;
} }
this->event = CreateEvent(NULL, TRUE, TRUE, NULL);
if (!this->event)
{
DEBUG_WINERROR("Failed to create capture event", status);
goto fail;
}
this->fenceValue = 0;
status = ID3D12Device_CreateFence(this->device, 0, D3D12_FENCE_FLAG_NONE,
&IID_ID3D12Fence, (void **)&this->fence);
if (FAILED(status))
{
DEBUG_WINERROR("Failed to create capture fence", status);
goto fail;
}
D3D12_HEAP_PROPERTIES readbackHeapProperties = { D3D12_HEAP_PROPERTIES readbackHeapProperties = {
.Type = D3D12_HEAP_TYPE_READBACK, .Type = D3D12_HEAP_TYPE_READBACK,
}; };
@ -232,6 +251,15 @@ static void d3d12_free(void)
free(this->texture); free(this->texture);
} }
if (this->fence)
ID3D12Fence_Release(this->fence);
if (this->event)
CloseHandle(this->event);
if (this->src)
ID3D12Resource_Release(this->src);
if (this->commandQueue) if (this->commandQueue)
ID3D12CommandQueue_Release(this->commandQueue); ID3D12CommandQueue_Release(this->commandQueue);
@ -265,7 +293,7 @@ static bool d3d12_copyFrame(Texture * parent, ID3D11Texture2D * src)
goto cleanup; goto cleanup;
} }
status = ID3D12Device_OpenSharedHandle(this->device, handle, &IID_ID3D12Resource, (void **)&tex->src); status = ID3D12Device_OpenSharedHandle(this->device, handle, &IID_ID3D12Resource, (void **)&this->src);
if (FAILED(status)) if (FAILED(status))
{ {
DEBUG_WINERROR("Failed to get create shared handle for texture", status); DEBUG_WINERROR("Failed to get create shared handle for texture", status);
@ -277,7 +305,7 @@ static bool d3d12_copyFrame(Texture * parent, ID3D11Texture2D * src)
CloseHandle(handle); CloseHandle(handle);
D3D12_TEXTURE_COPY_LOCATION srcLoc = { D3D12_TEXTURE_COPY_LOCATION srcLoc = {
.pResource = tex->src, .pResource = this->src,
.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX, .Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX,
.SubresourceIndex = 0 .SubresourceIndex = 0
}; };
@ -324,10 +352,27 @@ static bool d3d12_copyFrame(Texture * parent, ID3D11Texture2D * src)
ID3D12CommandQueue_ExecuteCommandLists(this->commandQueue, 1, &tex->commandList); ID3D12CommandQueue_ExecuteCommandLists(this->commandQueue, 1, &tex->commandList);
status = ID3D12CommandQueue_Signal(this->commandQueue, this->fence, ++this->fenceValue);
if (FAILED(status))
{
DEBUG_WINERROR("Failed to signal capture fence", status);
fail = true;
goto cleanup;
}
ResetEvent(this->event);
status = ID3D12Fence_SetEventOnCompletion(this->fence, this->fenceValue, this->event);
if (FAILED(status))
{
DEBUG_WINERROR("Failed to signal capture fence event", status);
fail = true;
goto cleanup;
}
status = ID3D12CommandQueue_Signal(this->commandQueue, tex->fence, ++tex->fenceValue); status = ID3D12CommandQueue_Signal(this->commandQueue, tex->fence, ++tex->fenceValue);
if (FAILED(status)) if (FAILED(status))
{ {
DEBUG_WINERROR("Failed to signal fence", status); DEBUG_WINERROR("Failed to signal texture fence", status);
fail = true; fail = true;
goto cleanup; goto cleanup;
} }
@ -335,7 +380,7 @@ static bool d3d12_copyFrame(Texture * parent, ID3D11Texture2D * src)
status = ID3D12Fence_SetEventOnCompletion(tex->fence, tex->fenceValue, tex->event); status = ID3D12Fence_SetEventOnCompletion(tex->fence, tex->fenceValue, tex->event);
if (FAILED(status)) if (FAILED(status))
{ {
DEBUG_WINERROR("Failed to signal fence event", status); DEBUG_WINERROR("Failed to signal texture fence event", status);
fail = true; fail = true;
goto cleanup; goto cleanup;
} }
@ -367,8 +412,6 @@ static CaptureResult d3d12_mapTexture(Texture * parent)
return CAPTURE_RESULT_ERROR; return CAPTURE_RESULT_ERROR;
} }
ID3D12Resource_Release(tex->src);
D3D12_RANGE range = { .Begin = 0, .End = dxgi->pitch * dxgi->height }; D3D12_RANGE range = { .Begin = 0, .End = dxgi->pitch * dxgi->height };
status = ID3D12Resource_Map(tex->tex, 0, &range, &parent->map); status = ID3D12Resource_Map(tex->tex, 0, &range, &parent->map);
@ -390,6 +433,17 @@ static void d3d12_unmapTexture(Texture * parent)
parent->map = NULL; parent->map = NULL;
} }
static void d3d12_preRelease(void)
{
WaitForSingleObject(this->event, INFINITE);
if (this->src)
{
ID3D12Resource_Release(this->src);
this->src = NULL;
}
}
struct DXGICopyBackend copyBackendD3D12 = { struct DXGICopyBackend copyBackendD3D12 = {
.name = "Direct3D 12", .name = "Direct3D 12",
.create = d3d12_create, .create = d3d12_create,
@ -397,4 +451,5 @@ struct DXGICopyBackend copyBackendD3D12 = {
.copyFrame = d3d12_copyFrame, .copyFrame = d3d12_copyFrame,
.mapTexture = d3d12_mapTexture, .mapTexture = d3d12_mapTexture,
.unmapTexture = d3d12_unmapTexture, .unmapTexture = d3d12_unmapTexture,
.preRelease = d3d12_preRelease,
}; };

View file

@ -539,6 +539,9 @@ static bool dxgi_deinit(void)
} }
} }
if (this->dup)
dxgi_releaseFrame();
if (this->backend) if (this->backend)
{ {
this->backend->free(); this->backend->free();
@ -553,7 +556,6 @@ static bool dxgi_deinit(void)
if (this->dup) if (this->dup)
{ {
dxgi_releaseFrame();
IDXGIOutputDuplication_Release(this->dup); IDXGIOutputDuplication_Release(this->dup);
this->dup = NULL; this->dup = NULL;
} }
@ -1036,6 +1038,8 @@ static CaptureResult dxgi_releaseFrame(void)
if (!this->needsRelease) if (!this->needsRelease)
return CAPTURE_RESULT_OK; return CAPTURE_RESULT_OK;
this->backend->preRelease();
HRESULT status; HRESULT status;
LOCKED({status = IDXGIOutputDuplication_ReleaseFrame(this->dup);}); LOCKED({status = IDXGIOutputDuplication_ReleaseFrame(this->dup);});
switch(status) switch(status)

View file

@ -113,6 +113,7 @@ struct DXGICopyBackend
bool (*copyFrame)(Texture * tex, ID3D11Texture2D * src); bool (*copyFrame)(Texture * tex, ID3D11Texture2D * src);
CaptureResult (*mapTexture)(Texture * tex); CaptureResult (*mapTexture)(Texture * tex);
void (*unmapTexture)(Texture * tex); void (*unmapTexture)(Texture * tex);
void (*preRelease)(void);
}; };
const char * GetDXGIFormatStr(DXGI_FORMAT format); const char * GetDXGIFormatStr(DXGI_FORMAT format);