[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;
}
static void d3d11_preRelease(void)
{
// Nothing needs to be done.
}
struct DXGICopyBackend copyBackendD3D11 = {
.name = "Direct3D 11",
.create = d3d11_create,
@ -195,4 +200,5 @@ struct DXGICopyBackend copyBackendD3D11 = {
.copyFrame = d3d11_copyFrame,
.mapTexture = d3d11_mapTexture,
.unmapTexture = d3d11_unmapTexture,
.preRelease = d3d11_preRelease,
};

View file

@ -29,7 +29,6 @@
struct D3D12Texture
{
ID3D12Resource * src;
ID3D12Resource * tex;
ID3D12CommandAllocator * commandAllocator;
ID3D12CommandList * commandList;
@ -43,7 +42,11 @@ struct D3D12Backend
{
ID3D12Device * device;
ID3D12CommandQueue * commandQueue;
ID3D12Resource * src;
struct D3D12Texture * texture;
UINT64 fenceValue;
ID3D12Fence * fence;
HANDLE event;
};
static struct DXGIInterface * dxgi = NULL;
@ -122,6 +125,22 @@ static bool d3d12_create(struct DXGIInterface * intf)
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 = {
.Type = D3D12_HEAP_TYPE_READBACK,
};
@ -232,6 +251,15 @@ static void d3d12_free(void)
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)
ID3D12CommandQueue_Release(this->commandQueue);
@ -265,7 +293,7 @@ static bool d3d12_copyFrame(Texture * parent, ID3D11Texture2D * src)
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))
{
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);
D3D12_TEXTURE_COPY_LOCATION srcLoc = {
.pResource = tex->src,
.pResource = this->src,
.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX,
.SubresourceIndex = 0
};
@ -324,10 +352,27 @@ static bool d3d12_copyFrame(Texture * parent, ID3D11Texture2D * src)
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);
if (FAILED(status))
{
DEBUG_WINERROR("Failed to signal fence", status);
DEBUG_WINERROR("Failed to signal texture fence", status);
fail = true;
goto cleanup;
}
@ -335,7 +380,7 @@ static bool d3d12_copyFrame(Texture * parent, ID3D11Texture2D * src)
status = ID3D12Fence_SetEventOnCompletion(tex->fence, tex->fenceValue, tex->event);
if (FAILED(status))
{
DEBUG_WINERROR("Failed to signal fence event", status);
DEBUG_WINERROR("Failed to signal texture fence event", status);
fail = true;
goto cleanup;
}
@ -367,8 +412,6 @@ static CaptureResult d3d12_mapTexture(Texture * parent)
return CAPTURE_RESULT_ERROR;
}
ID3D12Resource_Release(tex->src);
D3D12_RANGE range = { .Begin = 0, .End = dxgi->pitch * dxgi->height };
status = ID3D12Resource_Map(tex->tex, 0, &range, &parent->map);
@ -390,6 +433,17 @@ static void d3d12_unmapTexture(Texture * parent)
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 = {
.name = "Direct3D 12",
.create = d3d12_create,
@ -397,4 +451,5 @@ struct DXGICopyBackend copyBackendD3D12 = {
.copyFrame = d3d12_copyFrame,
.mapTexture = d3d12_mapTexture,
.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)
{
this->backend->free();
@ -553,7 +556,6 @@ static bool dxgi_deinit(void)
if (this->dup)
{
dxgi_releaseFrame();
IDXGIOutputDuplication_Release(this->dup);
this->dup = NULL;
}
@ -1036,6 +1038,8 @@ static CaptureResult dxgi_releaseFrame(void)
if (!this->needsRelease)
return CAPTURE_RESULT_OK;
this->backend->preRelease();
HRESULT status;
LOCKED({status = IDXGIOutputDuplication_ReleaseFrame(this->dup);});
switch(status)

View file

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