From: Stefan Dösinger stefan@codeweavers.com
---
I have tests that test what happens when a cache exists, has a matching version but other properties (e.g. disk vs memory) differ. The anwer is that the existing cache's properties win. Because those tests make use of D3D12_SHADER_CACHE_MODE_DISK I plan to send them after implementing disk cache support. --- include/private/vkd3d_common.h | 6 ++++ libs/vkd3d/device.c | 62 ++++++++++++++++++++++++++++++---- tests/d3d12.c | 13 ++++--- 3 files changed, 70 insertions(+), 11 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 266465e00..90de27c53 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); @@ -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; diff --git a/tests/d3d12.c b/tests/d3d12.c index 159f27cb5..a120db6a5 100644 --- a/tests/d3d12.c +++ b/tests/d3d12.c @@ -38440,10 +38440,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);
@@ -38452,9 +38450,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);