Add render pipeline cache key generation for Vulkan.
Bug: dawn:549 Change-Id: I0c0607984193ddcc2add05594517638e5370484d Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/85863 Reviewed-by: Austin Eng <enga@chromium.org> Commit-Queue: Loko Kung <lokokung@google.com>
This commit is contained in:
parent
c083d65a0c
commit
ca11c03824
|
@ -15,6 +15,9 @@
|
||||||
#ifndef SRC_DAWN_NATIVE_CACHEKEY_H_
|
#ifndef SRC_DAWN_NATIVE_CACHEKEY_H_
|
||||||
#define SRC_DAWN_NATIVE_CACHEKEY_H_
|
#define SRC_DAWN_NATIVE_CACHEKEY_H_
|
||||||
|
|
||||||
|
#include "dawn/common/TypedInteger.h"
|
||||||
|
#include "dawn/common/ityp_array.h"
|
||||||
|
|
||||||
#include <bitset>
|
#include <bitset>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
@ -66,6 +69,14 @@ namespace dawn::native {
|
||||||
}
|
}
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
template <typename Index, typename Value, size_t Size>
|
||||||
|
CacheKey& RecordIterable(const ityp::array<Index, Value, Size>& iterable) {
|
||||||
|
Record(static_cast<Index>(iterable.size()));
|
||||||
|
for (auto it = iterable.begin(); it != iterable.end(); ++it) {
|
||||||
|
Record(*it);
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
template <typename Ptr>
|
template <typename Ptr>
|
||||||
CacheKey& RecordIterable(const Ptr* ptr, size_t n) {
|
CacheKey& RecordIterable(const Ptr* ptr, size_t n) {
|
||||||
Record(n);
|
Record(n);
|
||||||
|
@ -131,6 +142,15 @@ namespace dawn::native {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Specialized overload for TypedInteger.
|
||||||
|
template <typename Tag, typename Integer>
|
||||||
|
class CacheKeySerializer<::detail::TypedIntegerImpl<Tag, Integer>> {
|
||||||
|
public:
|
||||||
|
static void Serialize(CacheKey* key, const ::detail::TypedIntegerImpl<Tag, Integer> t) {
|
||||||
|
CacheKeySerializer<Integer>::Serialize(key, static_cast<Integer>(t));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Specialized overload for pointers. Since we are serializing for a cache key, we always
|
// Specialized overload for pointers. Since we are serializing for a cache key, we always
|
||||||
// serialize via value, not by pointer. To handle nullptr scenarios, we always serialize whether
|
// serialize via value, not by pointer. To handle nullptr scenarios, we always serialize whether
|
||||||
// the pointer was nullptr followed by the contents if applicable.
|
// the pointer was nullptr followed by the contents if applicable.
|
||||||
|
@ -145,14 +165,27 @@ namespace dawn::native {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Specialized overload for string literals.
|
// Specialized overload for fixed arrays of primitives.
|
||||||
template <size_t N>
|
template <typename T, size_t N>
|
||||||
class CacheKeySerializer<char[N]> {
|
class CacheKeySerializer<T[N], std::enable_if_t<std::is_fundamental_v<T>>> {
|
||||||
public:
|
public:
|
||||||
static void Serialize(CacheKey* key, const char (&t)[N]) {
|
static void Serialize(CacheKey* key, const T (&t)[N]) {
|
||||||
static_assert(N > 0);
|
static_assert(N > 0);
|
||||||
key->Record(static_cast<size_t>(N));
|
key->Record(static_cast<size_t>(N));
|
||||||
key->insert(key->end(), t, t + N);
|
key->insert(key->end(), t, t + (N * sizeof(T)));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Specialized overload for fixed arrays of non-primitives.
|
||||||
|
template <typename T, size_t N>
|
||||||
|
class CacheKeySerializer<T[N], std::enable_if_t<!std::is_fundamental_v<T>>> {
|
||||||
|
public:
|
||||||
|
static void Serialize(CacheKey* key, const T (&t)[N]) {
|
||||||
|
static_assert(N > 0);
|
||||||
|
key->Record(static_cast<size_t>(N));
|
||||||
|
for (size_t i = 0; i < N; i++) {
|
||||||
|
key->Record(t[i]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
#include "dawn/native/vulkan/CacheKeyVk.h"
|
#include "dawn/native/vulkan/CacheKeyVk.h"
|
||||||
|
#include "dawn/native/vulkan/RenderPassCache.h"
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
|
@ -30,7 +31,7 @@ namespace dawn::native {
|
||||||
CacheKey* key,
|
CacheKey* key,
|
||||||
const VkDescriptorSetLayoutCreateInfo& t) {
|
const VkDescriptorSetLayoutCreateInfo& t) {
|
||||||
key->Record(t.flags).RecordIterable(t.pBindings, t.bindingCount);
|
key->Record(t.flags).RecordIterable(t.pBindings, t.bindingCount);
|
||||||
vulkan::SerializePnext<>(key, reinterpret_cast<const VkBaseOutStructure*>(&t));
|
vulkan::SerializePnext<>(key, &t);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
|
@ -46,7 +47,7 @@ namespace dawn::native {
|
||||||
// The set layouts are not serialized here because they are pointers to backend objects.
|
// The set layouts are not serialized here because they are pointers to backend objects.
|
||||||
// They need to be cross-referenced with the frontend objects and serialized from there.
|
// They need to be cross-referenced with the frontend objects and serialized from there.
|
||||||
key->Record(t.flags).RecordIterable(t.pPushConstantRanges, t.pushConstantRangeCount);
|
key->Record(t.flags).RecordIterable(t.pPushConstantRanges, t.pushConstantRangeCount);
|
||||||
vulkan::SerializePnext<>(key, reinterpret_cast<const VkBaseOutStructure*>(&t));
|
vulkan::SerializePnext<>(key, &t);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
|
@ -78,8 +79,7 @@ namespace dawn::native {
|
||||||
key->Record(t.flags, t.stage)
|
key->Record(t.flags, t.stage)
|
||||||
.RecordIterable(t.pName, strlen(t.pName))
|
.RecordIterable(t.pName, strlen(t.pName))
|
||||||
.Record(t.pSpecializationInfo);
|
.Record(t.pSpecializationInfo);
|
||||||
vulkan::SerializePnext<VkPipelineShaderStageRequiredSubgroupSizeCreateInfoEXT>(
|
vulkan::SerializePnext<VkPipelineShaderStageRequiredSubgroupSizeCreateInfoEXT>(key, &t);
|
||||||
key, reinterpret_cast<const VkBaseOutStructure*>(&t));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
|
@ -94,4 +94,164 @@ namespace dawn::native {
|
||||||
key->Record(t.flags, t.stage);
|
key->Record(t.flags, t.stage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
void CacheKeySerializer<VkVertexInputBindingDescription>::Serialize(
|
||||||
|
CacheKey* key,
|
||||||
|
const VkVertexInputBindingDescription& t) {
|
||||||
|
key->Record(t.binding, t.stride, t.inputRate);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
void CacheKeySerializer<VkVertexInputAttributeDescription>::Serialize(
|
||||||
|
CacheKey* key,
|
||||||
|
const VkVertexInputAttributeDescription& t) {
|
||||||
|
key->Record(t.location, t.binding, t.format, t.offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
void CacheKeySerializer<VkPipelineVertexInputStateCreateInfo>::Serialize(
|
||||||
|
CacheKey* key,
|
||||||
|
const VkPipelineVertexInputStateCreateInfo& t) {
|
||||||
|
key->Record(t.flags)
|
||||||
|
.RecordIterable(t.pVertexBindingDescriptions, t.vertexBindingDescriptionCount)
|
||||||
|
.RecordIterable(t.pVertexAttributeDescriptions, t.vertexAttributeDescriptionCount);
|
||||||
|
vulkan::SerializePnext<>(key, &t);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
void CacheKeySerializer<VkPipelineInputAssemblyStateCreateInfo>::Serialize(
|
||||||
|
CacheKey* key,
|
||||||
|
const VkPipelineInputAssemblyStateCreateInfo& t) {
|
||||||
|
key->Record(t.flags, t.topology, t.primitiveRestartEnable);
|
||||||
|
vulkan::SerializePnext<>(key, &t);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
void CacheKeySerializer<VkPipelineTessellationStateCreateInfo>::Serialize(
|
||||||
|
CacheKey* key,
|
||||||
|
const VkPipelineTessellationStateCreateInfo& t) {
|
||||||
|
key->Record(t.flags, t.patchControlPoints);
|
||||||
|
vulkan::SerializePnext<>(key, &t);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
void CacheKeySerializer<VkViewport>::Serialize(CacheKey* key, const VkViewport& t) {
|
||||||
|
key->Record(t.x, t.y, t.width, t.height, t.minDepth, t.maxDepth);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
void CacheKeySerializer<VkOffset2D>::Serialize(CacheKey* key, const VkOffset2D& t) {
|
||||||
|
key->Record(t.x, t.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
void CacheKeySerializer<VkExtent2D>::Serialize(CacheKey* key, const VkExtent2D& t) {
|
||||||
|
key->Record(t.width, t.height);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
void CacheKeySerializer<VkRect2D>::Serialize(CacheKey* key, const VkRect2D& t) {
|
||||||
|
key->Record(t.offset, t.extent);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
void CacheKeySerializer<VkPipelineViewportStateCreateInfo>::Serialize(
|
||||||
|
CacheKey* key,
|
||||||
|
const VkPipelineViewportStateCreateInfo& t) {
|
||||||
|
key->Record(t.flags)
|
||||||
|
.RecordIterable(t.pViewports, t.viewportCount)
|
||||||
|
.RecordIterable(t.pScissors, t.scissorCount);
|
||||||
|
vulkan::SerializePnext<>(key, &t);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
void CacheKeySerializer<VkPipelineRasterizationStateCreateInfo>::Serialize(
|
||||||
|
CacheKey* key,
|
||||||
|
const VkPipelineRasterizationStateCreateInfo& t) {
|
||||||
|
key->Record(t.flags, t.depthClampEnable, t.rasterizerDiscardEnable, t.polygonMode,
|
||||||
|
t.cullMode, t.frontFace, t.depthBiasEnable, t.depthBiasConstantFactor,
|
||||||
|
t.depthBiasClamp, t.depthBiasSlopeFactor, t.lineWidth);
|
||||||
|
vulkan::SerializePnext<>(key, &t);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
void CacheKeySerializer<VkPipelineMultisampleStateCreateInfo>::Serialize(
|
||||||
|
CacheKey* key,
|
||||||
|
const VkPipelineMultisampleStateCreateInfo& t) {
|
||||||
|
key->Record(t.flags, t.rasterizationSamples, t.sampleShadingEnable, t.minSampleShading,
|
||||||
|
t.pSampleMask, t.alphaToCoverageEnable, t.alphaToOneEnable);
|
||||||
|
vulkan::SerializePnext<>(key, &t);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
void CacheKeySerializer<VkStencilOpState>::Serialize(CacheKey* key, const VkStencilOpState& t) {
|
||||||
|
key->Record(t.failOp, t.passOp, t.depthFailOp, t.compareOp, t.compareMask, t.writeMask,
|
||||||
|
t.reference);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
void CacheKeySerializer<VkPipelineDepthStencilStateCreateInfo>::Serialize(
|
||||||
|
CacheKey* key,
|
||||||
|
const VkPipelineDepthStencilStateCreateInfo& t) {
|
||||||
|
key->Record(t.flags, t.depthTestEnable, t.depthWriteEnable, t.depthCompareOp,
|
||||||
|
t.depthBoundsTestEnable, t.stencilTestEnable, t.front, t.back, t.minDepthBounds,
|
||||||
|
t.maxDepthBounds);
|
||||||
|
vulkan::SerializePnext<>(key, &t);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
void CacheKeySerializer<VkPipelineColorBlendAttachmentState>::Serialize(
|
||||||
|
CacheKey* key,
|
||||||
|
const VkPipelineColorBlendAttachmentState& t) {
|
||||||
|
key->Record(t.blendEnable, t.srcColorBlendFactor, t.dstColorBlendFactor, t.colorBlendOp,
|
||||||
|
t.srcAlphaBlendFactor, t.dstAlphaBlendFactor, t.alphaBlendOp, t.colorWriteMask);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
void CacheKeySerializer<VkPipelineColorBlendStateCreateInfo>::Serialize(
|
||||||
|
CacheKey* key,
|
||||||
|
const VkPipelineColorBlendStateCreateInfo& t) {
|
||||||
|
key->Record(t.flags, t.logicOpEnable, t.logicOp)
|
||||||
|
.RecordIterable(t.pAttachments, t.attachmentCount)
|
||||||
|
.Record(t.blendConstants);
|
||||||
|
vulkan::SerializePnext<>(key, &t);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
void CacheKeySerializer<VkPipelineDynamicStateCreateInfo>::Serialize(
|
||||||
|
CacheKey* key,
|
||||||
|
const VkPipelineDynamicStateCreateInfo& t) {
|
||||||
|
key->Record(t.flags).RecordIterable(t.pDynamicStates, t.dynamicStateCount);
|
||||||
|
vulkan::SerializePnext<>(key, &t);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
void CacheKeySerializer<vulkan::RenderPassCacheQuery>::Serialize(
|
||||||
|
CacheKey* key,
|
||||||
|
const vulkan::RenderPassCacheQuery& t) {
|
||||||
|
key->Record(t.colorMask.to_ulong(), t.resolveTargetMask.to_ulong())
|
||||||
|
.RecordIterable(t.colorFormats)
|
||||||
|
.RecordIterable(t.colorLoadOp)
|
||||||
|
.RecordIterable(t.colorStoreOp)
|
||||||
|
.Record(t.hasDepthStencil, t.depthStencilFormat, t.depthLoadOp, t.depthStoreOp,
|
||||||
|
t.stencilLoadOp, t.stencilStoreOp, t.readOnlyDepthStencil, t.sampleCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
void CacheKeySerializer<VkGraphicsPipelineCreateInfo>::Serialize(
|
||||||
|
CacheKey* key,
|
||||||
|
const VkGraphicsPipelineCreateInfo& t) {
|
||||||
|
// The pipeline layout and render pass are not serialized here because they are pointers to
|
||||||
|
// backend objects. They need to be cross-referenced with the frontend objects and
|
||||||
|
// serialized from there. The base pipeline information is also currently not recorded since
|
||||||
|
// we do not use them in our backend implementation. If we decide to use them later on, they
|
||||||
|
// also need to be cross-referenced from the frontend.
|
||||||
|
key->Record(t.flags)
|
||||||
|
.RecordIterable(t.pStages, t.stageCount)
|
||||||
|
.Record(t.pVertexInputState, t.pInputAssemblyState, t.pTessellationState,
|
||||||
|
t.pViewportState, t.pRasterizationState, t.pMultisampleState,
|
||||||
|
t.pDepthStencilState, t.pColorBlendState, t.pDynamicState, t.subpass);
|
||||||
|
vulkan::SerializePnext<>(key, &t);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace dawn::native
|
} // namespace dawn::native
|
||||||
|
|
|
@ -70,18 +70,32 @@ namespace dawn::native::vulkan {
|
||||||
SerializePnextImpl<VK_STRUCT_TYPES...>(key, root);
|
SerializePnextImpl<VK_STRUCT_TYPES...>(key, root);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename VK_STRUCT_TYPE>
|
||||||
|
const VkBaseOutStructure* ToVkBaseOutStructure(const VK_STRUCT_TYPE* t) {
|
||||||
|
// Sanity checks to ensure proper type safety.
|
||||||
|
static_assert(
|
||||||
|
offsetof(VK_STRUCT_TYPE, sType) == offsetof(VkBaseOutStructure, sType) &&
|
||||||
|
offsetof(VK_STRUCT_TYPE, pNext) == offsetof(VkBaseOutStructure, pNext),
|
||||||
|
"Argument type is not a proper Vulkan structure type");
|
||||||
|
return reinterpret_cast<const VkBaseOutStructure*>(t);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
template <typename... VK_STRUCT_TYPES>
|
template <typename... VK_STRUCT_TYPES,
|
||||||
void SerializePnext(CacheKey* key, const VkBaseOutStructure* root) {
|
typename VK_STRUCT_TYPE,
|
||||||
|
typename = std::enable_if_t<(sizeof...(VK_STRUCT_TYPES) > 0)>>
|
||||||
|
void SerializePnext(CacheKey* key, const VK_STRUCT_TYPE* t) {
|
||||||
|
const VkBaseOutStructure* root = detail::ToVkBaseOutStructure(t);
|
||||||
detail::ValidatePnextImpl<VK_STRUCT_TYPES...>(root);
|
detail::ValidatePnextImpl<VK_STRUCT_TYPES...>(root);
|
||||||
detail::SerializePnextImpl<VK_STRUCT_TYPES...>(key, root);
|
detail::SerializePnextImpl<VK_STRUCT_TYPES...>(key, root);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Empty template specialization so that we can put this in to ensure failures occur if new
|
// Empty template specialization so that we can put this in to ensure failures occur if new
|
||||||
// extensions are added without updating serialization.
|
// extensions are added without updating serialization.
|
||||||
template <>
|
template <typename VK_STRUCT_TYPE>
|
||||||
void SerializePnext(CacheKey* key, const VkBaseOutStructure* root) {
|
void SerializePnext(CacheKey* key, const VK_STRUCT_TYPE* t) {
|
||||||
|
const VkBaseOutStructure* root = detail::ToVkBaseOutStructure(t);
|
||||||
detail::ValidatePnextImpl<>(root);
|
detail::ValidatePnextImpl<>(root);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -381,6 +381,9 @@ namespace dawn::native::vulkan {
|
||||||
DAWN_ASSERT(stageCount < 2);
|
DAWN_ASSERT(stageCount < 2);
|
||||||
shaderStages[stageCount] = shaderStage;
|
shaderStages[stageCount] = shaderStage;
|
||||||
stageCount++;
|
stageCount++;
|
||||||
|
|
||||||
|
// Record cache key for each shader since it will become inaccessible later on.
|
||||||
|
GetCacheKey()->Record(stage).RecordIterable(*spirv);
|
||||||
}
|
}
|
||||||
|
|
||||||
PipelineVertexInputStateCreateInfoTemporaryAllocations tempAllocations;
|
PipelineVertexInputStateCreateInfoTemporaryAllocations tempAllocations;
|
||||||
|
@ -528,6 +531,7 @@ namespace dawn::native::vulkan {
|
||||||
|
|
||||||
query.SetSampleCount(GetSampleCount());
|
query.SetSampleCount(GetSampleCount());
|
||||||
|
|
||||||
|
GetCacheKey()->Record(query);
|
||||||
DAWN_TRY_ASSIGN(renderPass, device->GetRenderPassCache()->GetRenderPass(query));
|
DAWN_TRY_ASSIGN(renderPass, device->GetRenderPassCache()->GetRenderPass(query));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -555,6 +559,10 @@ namespace dawn::native::vulkan {
|
||||||
createInfo.basePipelineHandle = VkPipeline{};
|
createInfo.basePipelineHandle = VkPipeline{};
|
||||||
createInfo.basePipelineIndex = -1;
|
createInfo.basePipelineIndex = -1;
|
||||||
|
|
||||||
|
// Record cache key information now since createInfo is not stored.
|
||||||
|
GetCacheKey()->Record(createInfo,
|
||||||
|
static_cast<const RenderPipeline*>(this)->GetLayout()->GetCacheKey());
|
||||||
|
|
||||||
DAWN_TRY(CheckVkSuccess(
|
DAWN_TRY(CheckVkSuccess(
|
||||||
device->fn.CreateGraphicsPipelines(device->GetVkDevice(), VkPipelineCache{}, 1,
|
device->fn.CreateGraphicsPipelines(device->GetVkDevice(), VkPipelineCache{}, 1,
|
||||||
&createInfo, nullptr, &*mHandle),
|
&createInfo, nullptr, &*mHandle),
|
||||||
|
|
Loading…
Reference in New Issue