From: Stefan Dösinger stefan@codeweavers.com
--- include/private/vkd3d_common.h | 6 +++ libs/vkd3d/device.c | 69 +++++++++++++++++++++++++++++----- tests/d3d12.c | 6 +-- 3 files changed, 67 insertions(+), 14 deletions(-)
diff --git a/include/private/vkd3d_common.h b/include/private/vkd3d_common.h index 6a8694a79..10e2afd5d 100644 --- a/include/private/vkd3d_common.h +++ b/include/private/vkd3d_common.h @@ -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 diff --git a/libs/vkd3d/device.c b/libs/vkd3d/device.c index ad164201e..9b33be235 100644 --- a/libs/vkd3d/device.c +++ b/libs/vkd3d/device.c @@ -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); @@ -2710,12 +2719,14 @@ static HRESULT d3d12_cache_session_init(struct d3d12_cache_session *session, struct d3d12_device *device, const D3D12_SHADER_CACHE_SESSION_DESC *desc) { struct vkd3d_shader_cache_info cache_info = {0}; + 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; @@ -2727,23 +2738,60 @@ static HRESULT d3d12_cache_session_init(struct d3d12_cache_session *session, if (FAILED(hr = vkd3d_private_store_init(&session->private_store))) return hr;
- cache_info.max_entries = session->desc.MaximumInMemoryCacheEntries; - cache_info.mem_size = session->desc.MaximumInMemoryCacheSizeBytes; - cache_info.version = session->desc.Version; - if (session->desc.Mode == D3D12_SHADER_CACHE_MODE_DISK) - FIXME("Disk caches are not yet implemented.\n"); + vkd3d_mutex_lock(&cache_list_mutex); + + /* We expect the number of open caches to be small. */ + LIST_FOR_EACH_ENTRY(i, &cache_list, struct d3d12_cache_session, cache_list_entry) + { + 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; + } + } + }
- ret = vkd3d_shader_open_cache(&cache_info, &session->cache); - if (ret) + if (!session->cache) { - WARN("Failed to open shader cache.\n"); - vkd3d_private_store_destroy(&session->private_store); - return hresult_from_vkd3d_result(ret); + cache_info.max_entries = session->desc.MaximumInMemoryCacheEntries; + cache_info.mem_size = session->desc.MaximumInMemoryCacheSizeBytes; + cache_info.version = session->desc.Version; + if (session->desc.Mode == D3D12_SHADER_CACHE_MODE_DISK) + FIXME("Disk caches are not yet implemented.\n"); + + ret = vkd3d_shader_open_cache(&cache_info, &session->cache); + if (ret) + { + WARN("Failed to open shader cache.\n"); + hr = hresult_from_vkd3d_result(ret); + goto error; + } }
+ /* Yes, we add this unconditionally, even if we reused an existing cache from a different + * session. 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 */ @@ -4892,6 +4940,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; diff --git a/tests/d3d12.c b/tests/d3d12.c index fb151cad3..ed8c8a09e 100644 --- a/tests/d3d12.c +++ b/tests/d3d12.c @@ -38438,10 +38438,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);