diff --git a/libs/vkd3d/cache.c b/libs/vkd3d/cache.c index d61a1bcd..d03f0b56 100644 --- a/libs/vkd3d/cache.c +++ b/libs/vkd3d/cache.c @@ -299,8 +299,8 @@ static bool vkd3d_serialized_pipeline_stream_entry_validate(const uint8_t *data, return checksum == entry->checksum; } -static const struct vkd3d_pipeline_blob_chunk *find_blob_chunk(const struct vkd3d_pipeline_blob_chunk *chunk, - size_t size, uint32_t type) +static const struct vkd3d_pipeline_blob_chunk *find_blob_chunk_masked(const struct vkd3d_pipeline_blob_chunk *chunk, + size_t size, uint32_t type, uint32_t mask) { uint32_t aligned_chunk_size; @@ -310,7 +310,7 @@ static const struct vkd3d_pipeline_blob_chunk *find_blob_chunk(const struct vkd3 VKD3D_PIPELINE_BLOB_CHUNK_ALIGN); if (aligned_chunk_size > size) return NULL; - if (chunk->type == type) + if ((chunk->type & mask) == type) return chunk; chunk = (const struct vkd3d_pipeline_blob_chunk *)&chunk->data[align(chunk->size, VKD3D_PIPELINE_BLOB_CHUNK_ALIGN)]; @@ -320,6 +320,12 @@ static const struct vkd3d_pipeline_blob_chunk *find_blob_chunk(const struct vkd3 return NULL; } +static const struct vkd3d_pipeline_blob_chunk *find_blob_chunk(const struct vkd3d_pipeline_blob_chunk *chunk, + size_t size, uint32_t type) +{ + return find_blob_chunk_masked(chunk, size, type, ~0u); +} + static uint32_t d3d12_cached_pipeline_state_to_flags(const struct d3d12_cached_pipeline_state *state) { uint32_t pipeline_library_flags; @@ -435,6 +441,41 @@ HRESULT d3d12_cached_pipeline_state_validate(struct d3d12_device *device, return S_OK; } +bool d3d12_cached_pipeline_state_is_dummy(const struct d3d12_cached_pipeline_state *state) +{ + const struct vkd3d_pipeline_blob *blob = state->blob.pCachedBlob; + const struct vkd3d_pipeline_blob_chunk *chunk; + size_t payload_size; + + if (!state->blob.CachedBlobSizeInBytes) + return true; + + if (state->blob.CachedBlobSizeInBytes < sizeof(*blob) || blob->version != VKD3D_CACHE_BLOB_VERSION) + return true; + payload_size = state->blob.CachedBlobSizeInBytes - offsetof(struct vkd3d_pipeline_blob, data); + + chunk = CONST_CAST_CHUNK_BASE(blob); + + /* Try to find any PSO cache or SPIR-V entry. If they exist, this is not a dummy blob. */ + if (find_blob_chunk(chunk, payload_size, VKD3D_PIPELINE_BLOB_CHUNK_TYPE_PIPELINE_CACHE)) + return false; + + if (find_blob_chunk(chunk, payload_size, VKD3D_PIPELINE_BLOB_CHUNK_TYPE_PIPELINE_CACHE_LINK)) + return false; + + if (find_blob_chunk_masked(chunk, payload_size, + VKD3D_PIPELINE_BLOB_CHUNK_TYPE_VARINT_SPIRV, + VKD3D_PIPELINE_BLOB_CHUNK_TYPE_MASK)) + return false; + + if (find_blob_chunk_masked(chunk, payload_size, + VKD3D_PIPELINE_BLOB_CHUNK_TYPE_VARINT_SPIRV_LINK, + VKD3D_PIPELINE_BLOB_CHUNK_TYPE_MASK)) + return false; + + return true; +} + static struct vkd3d_pipeline_blob_chunk *finish_and_iterate_blob_chunk(struct vkd3d_pipeline_blob_chunk *chunk) { uint32_t aligned_size = align(chunk->size, VKD3D_PIPELINE_BLOB_CHUNK_ALIGN); diff --git a/libs/vkd3d/state.c b/libs/vkd3d/state.c index 51db4f9d..a1182449 100644 --- a/libs/vkd3d/state.c +++ b/libs/vkd3d/state.c @@ -3694,7 +3694,17 @@ HRESULT d3d12_pipeline_state_create(struct d3d12_device *device, VkPipelineBindP return hr; } } - else if (device->disk_cache.library) + + /* If we rely on internal shader cache, the PSO blob app provides us might be a pure metadata blob, + * and therefore kinda useless. Try to use disk cache blob instead. + * Also, consider that we might have to serialize this pipeline if we don't find anything in disk cache. */ + if (d3d12_cached_pipeline_state_is_dummy(&desc->cached_pso)) + { + memset(&cached_pso, 0, sizeof(cached_pso)); + desc_cached_pso = &cached_pso; + } + + if (desc_cached_pso->blob.CachedBlobSizeInBytes == 0 && device->disk_cache.library) { if (SUCCEEDED(vkd3d_pipeline_library_find_cached_blob_from_disk_cache(&device->disk_cache, &object->pipeline_cache_compat, &cached_pso))) @@ -3704,7 +3714,14 @@ HRESULT d3d12_pipeline_state_create(struct d3d12_device *device, VkPipelineBindP * However, unlike app-proved blob, it's not fatal if we fail, so just fall back. */ if (SUCCEEDED(hr = d3d12_cached_pipeline_state_validate(device, &cached_pso, &object->pipeline_cache_compat))) + { + if ((vkd3d_config_flags & VKD3D_CONFIG_FLAG_PIPELINE_LIBRARY_LOG) && + desc->cached_pso.blob.CachedBlobSizeInBytes) + { + INFO("Application provided cached PSO blob, but we opted for disk cache blob instead.\n"); + } desc_cached_pso = &cached_pso; + } else FIXME("Failed to validate internal pipeline which was fetched from disk cache. This should not happen.\n"); } diff --git a/libs/vkd3d/vkd3d_private.h b/libs/vkd3d/vkd3d_private.h index 6a46adca..903ff8ec 100644 --- a/libs/vkd3d/vkd3d_private.h +++ b/libs/vkd3d/vkd3d_private.h @@ -1755,6 +1755,7 @@ VkResult vkd3d_serialize_pipeline_state(struct d3d12_pipeline_library *pipeline_ HRESULT d3d12_cached_pipeline_state_validate(struct d3d12_device *device, const struct d3d12_cached_pipeline_state *state, const struct vkd3d_pipeline_cache_compatibility *compat); +bool d3d12_cached_pipeline_state_is_dummy(const struct d3d12_cached_pipeline_state *state); void vkd3d_pipeline_cache_compat_from_state_desc(struct vkd3d_pipeline_cache_compatibility *compat, const struct d3d12_pipeline_state_desc *desc);