dxgi: cache shared handles instead of re-creating them

This will cache up to 10 handles, in practice I have never seen DXGI
return anything but the same resource each time but we allow for more
anyway should MS change something in the future.

Should the cache get over filled it is disabled entirely and we revert
to the original behaviour.
This commit is contained in:
Geoffrey McRae 2022-01-19 08:00:03 +11:00
parent 04ae9217e8
commit cff64ee7d3

View File

@ -26,6 +26,7 @@
#include "common/debug.h" #include "common/debug.h"
#include "common/option.h" #include "common/option.h"
#include "common/windebug.h" #include "common/windebug.h"
#include "common/array.h"
#include "ods_capture.h" #include "ods_capture.h"
#define ALIGN_TO(value, align) (((value) + (align) - 1) & -(align)) #define ALIGN_TO(value, align) (((value) + (align) - 1) & -(align))
@ -52,6 +53,15 @@ struct D3D12Backend
UINT64 fenceValue; UINT64 fenceValue;
ID3D12Fence * fence; ID3D12Fence * fence;
HANDLE event; HANDLE event;
// shared handle cache
struct
{
ID3D11Texture2D * tex;
HANDLE handle;
}
handleCache[10];
int handleCacheCount;
}; };
static struct DXGIInterface * dxgi = NULL; static struct DXGIInterface * dxgi = NULL;
@ -289,6 +299,9 @@ static void d3d12_free(void)
if (this->src) if (this->src)
ID3D12Resource_Release(this->src); ID3D12Resource_Release(this->src);
for(int i = 0; i < this->handleCacheCount; ++i)
CloseHandle(this->handleCache[i].handle);
if (this->commandQueue) if (this->commandQueue)
ID3D12CommandQueue_Release(this->commandQueue); ID3D12CommandQueue_Release(this->commandQueue);
@ -309,6 +322,21 @@ static bool d3d12_copyFrame(Texture * parent, ID3D11Texture2D * src)
if (this->copySleep > 0) if (this->copySleep > 0)
Sleep(this->copySleep); Sleep(this->copySleep);
HANDLE handle = INVALID_HANDLE_VALUE;
if (this->handleCacheCount > -1)
{
// see if there is a cached handle already available for this texture
for(int i = 0; i < this->handleCacheCount; ++i)
if (this->handleCache[i].tex == src)
{
handle = this->handleCache[i].handle;
break;
}
}
if (handle == INVALID_HANDLE_VALUE)
{
status = ID3D11Texture2D_QueryInterface(src, &IID_IDXGIResource1, (void **)&res1); status = ID3D11Texture2D_QueryInterface(src, &IID_IDXGIResource1, (void **)&res1);
if (FAILED(status)) if (FAILED(status))
{ {
@ -316,7 +344,6 @@ static bool d3d12_copyFrame(Texture * parent, ID3D11Texture2D * src)
return CAPTURE_RESULT_ERROR; return CAPTURE_RESULT_ERROR;
} }
HANDLE handle;
status = IDXGIResource1_CreateSharedHandle(res1, NULL, DXGI_SHARED_RESOURCE_READ, NULL, &handle); status = IDXGIResource1_CreateSharedHandle(res1, NULL, DXGI_SHARED_RESOURCE_READ, NULL, &handle);
if (FAILED(status)) if (FAILED(status))
{ {
@ -325,17 +352,33 @@ static bool d3d12_copyFrame(Texture * parent, ID3D11Texture2D * src)
goto cleanup; goto cleanup;
} }
// store the handle for later use
if (this->handleCacheCount < ARRAY_LENGTH(this->handleCache))
{
this->handleCache[this->handleCacheCount].tex = src;
this->handleCache[this->handleCacheCount].handle = handle;
++this->handleCacheCount;
}
else
{
// too many handles to cache, disable the cache entirely
for(int i = 0; i < this->handleCacheCount; ++i)
CloseHandle(this->handleCache[i].handle);
this->handleCacheCount = -1;
}
}
status = ID3D12Device_OpenSharedHandle(this->device, handle, &IID_ID3D12Resource, (void **)&this->src); status = ID3D12Device_OpenSharedHandle(this->device, handle, &IID_ID3D12Resource, (void **)&this->src);
if (this->handleCacheCount == -1)
CloseHandle(handle);
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);
CloseHandle(handle);
fail = true; fail = true;
goto cleanup; goto cleanup;
} }
CloseHandle(handle);
D3D12_TEXTURE_COPY_LOCATION srcLoc = { D3D12_TEXTURE_COPY_LOCATION srcLoc = {
.pResource = this->src, .pResource = this->src,
.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX, .Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX,