vkd3d: Implement reopening existing caches.

This commit is contained in:
Stefan Dösinger 2024-03-27 13:43:49 +03:00 committed by Alexandre Julliard
parent f24005507c
commit a7860ae752
Notes: Alexandre Julliard 2024-04-11 17:04:06 -05:00
Approved-by: Henri Verbeet (@hverbeet)
Approved-by: Alexandre Julliard (@julliard)
Merge-Request: https://gitlab.winehq.org/wine/vkd3d/-/merge_requests/766
3 changed files with 70 additions and 11 deletions

View File

@ -438,6 +438,12 @@ struct vkd3d_mutex
#endif
};
#ifdef _WIN32
#define VKD3D_MUTEX_INITIALIZER {{NULL, -1, 0, 0, 0, 0}}
#else
#define VKD3D_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
#endif
static inline void vkd3d_mutex_init(struct vkd3d_mutex *lock)
{
#ifdef _WIN32

View File

@ -2529,12 +2529,17 @@ struct d3d12_cache_session
ID3D12ShaderCacheSession ID3D12ShaderCacheSession_iface;
unsigned int refcount;
struct list cache_list_entry;
struct d3d12_device *device;
struct vkd3d_private_store private_store;
D3D12_SHADER_CACHE_SESSION_DESC desc;
struct vkd3d_shader_cache *cache;
};
static struct vkd3d_mutex cache_list_mutex = VKD3D_MUTEX_INITIALIZER;
static struct list cache_list = LIST_INIT(cache_list);
static inline struct d3d12_cache_session *impl_from_ID3D12ShaderCacheSession(ID3D12ShaderCacheSession *iface)
{
return CONTAINING_RECORD(iface, struct d3d12_cache_session, ID3D12ShaderCacheSession_iface);
@ -2583,6 +2588,10 @@ static void d3d12_cache_session_destroy(struct d3d12_cache_session *session)
TRACE("Destroying cache session %p.\n", session);
vkd3d_mutex_lock(&cache_list_mutex);
list_remove(&session->cache_list_entry);
vkd3d_mutex_unlock(&cache_list_mutex);
vkd3d_shader_cache_decref(session->cache);
vkd3d_private_store_destroy(&session->private_store);
vkd3d_free(session);
@ -2709,12 +2718,14 @@ static const struct ID3D12ShaderCacheSessionVtbl d3d12_cache_session_vtbl =
static HRESULT d3d12_cache_session_init(struct d3d12_cache_session *session,
struct d3d12_device *device, const D3D12_SHADER_CACHE_SESSION_DESC *desc)
{
struct d3d12_cache_session *i;
enum vkd3d_result ret;
HRESULT hr;
session->ID3D12ShaderCacheSession_iface.lpVtbl = &d3d12_cache_session_vtbl;
session->refcount = 1;
session->desc = *desc;
session->cache = NULL;
if (!session->desc.MaximumValueFileSizeBytes)
session->desc.MaximumValueFileSizeBytes = 128 * 1024 * 1024;
@ -2726,20 +2737,56 @@ static HRESULT d3d12_cache_session_init(struct d3d12_cache_session *session,
if (FAILED(hr = vkd3d_private_store_init(&session->private_store)))
return hr;
if (session->desc.Mode == D3D12_SHADER_CACHE_MODE_DISK)
FIXME("Disk caches are not yet implemented.\n");
vkd3d_mutex_lock(&cache_list_mutex);
ret = vkd3d_shader_open_cache(&session->cache);
if (ret)
/* We expect the number of open caches to be small. */
LIST_FOR_EACH_ENTRY(i, &cache_list, struct d3d12_cache_session, cache_list_entry)
{
WARN("Failed to open shader cache.\n");
vkd3d_private_store_destroy(&session->private_store);
return hresult_from_vkd3d_result(ret);
if (!memcmp(&i->desc.Identifier, &desc->Identifier, sizeof(desc->Identifier)))
{
TRACE("Found an existing cache %p from session %p.\n", i->cache, i);
if (desc->Version == i->desc.Version)
{
session->desc = i->desc;
vkd3d_shader_cache_incref(session->cache = i->cache);
break;
}
else
{
WARN("version mismatch: Existing %"PRIu64" new %"PRIu64".\n",
i->desc.Version, desc->Version);
hr = DXGI_ERROR_ALREADY_EXISTS;
goto error;
}
}
}
if (!session->cache)
{
if (session->desc.Mode == D3D12_SHADER_CACHE_MODE_DISK)
FIXME("Disk caches are not yet implemented.\n");
ret = vkd3d_shader_open_cache(&session->cache);
if (ret)
{
WARN("Failed to open shader cache.\n");
hr = hresult_from_vkd3d_result(ret);
goto error;
}
}
/* Add it to the list even if we reused an existing cache. The other session might be destroyed,
* but the cache stays alive and can be opened a third time. */
list_add_tail(&cache_list, &session->cache_list_entry);
d3d12_device_add_ref(session->device = device);
vkd3d_mutex_unlock(&cache_list_mutex);
return S_OK;
error:
vkd3d_private_store_destroy(&session->private_store);
vkd3d_mutex_unlock(&cache_list_mutex);
return hr;
}
/* ID3D12Device */
@ -4888,6 +4935,7 @@ static HRESULT STDMETHODCALLTYPE d3d12_device_CreateShaderCacheSession(ID3D12Dev
WARN("No output pointer, returning S_FALSE.\n");
return S_FALSE;
}
*session = NULL;
if (!(object = vkd3d_malloc(sizeof(*object))))
return E_OUTOFMEMORY;

View File

@ -38477,10 +38477,8 @@ static void test_shader_cache(void)
session2 = (void *)0xdeadbeef;
hr = ID3D12Device9_CreateShaderCacheSession(device, &desc,
&IID_ID3D12ShaderCacheSession, (void **)&session2);
todo ok(hr == DXGI_ERROR_ALREADY_EXISTS, "Got unexpected hr %#x.\n", hr);
todo ok(!session2, "Got unexpected pointer %p.\n", session2);
if (session2)
ID3D12ShaderCacheSession_Release(session2);
ok(hr == DXGI_ERROR_ALREADY_EXISTS, "Got unexpected hr %#x.\n", hr);
ok(!session2, "Got unexpected pointer %p.\n", session2);
hr = ID3D12Device9_CreateShaderCacheSession(device, &desc, &IID_IUnknown, NULL);
ok(hr == S_FALSE, "NULL outptr: Got hr %#x.\n", hr);
@ -38489,9 +38487,16 @@ static void test_shader_cache(void)
refcount = get_refcount(device);
ok(refcount == base_refcount, "Got unexpected refcount %u.\n", refcount);
/* Create two sessions with the same cache GUID. */
hr = ID3D12Device9_CreateShaderCacheSession(device, &desc,
&IID_ID3D12ShaderCacheSession, (void **)&session);
ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
hr = ID3D12Device9_CreateShaderCacheSession(device, &desc,
&IID_ID3D12ShaderCacheSession, (void **)&session2);
ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
ok(session2 != session, "Expected different interface pointers, got %p for both.\n",
session);
ID3D12ShaderCacheSession_Release(session2);
ID3D12ShaderCacheSession_Release(session);
ID3D12Device9_Release(device);