Dawn native/vulkan: PipelineLayoutVk holds multiple VkPipelineLayouts
PipelineLayoutVk holds a map with internal immediate data as key to
store multiple VkPipelineLayouts. Delay VkPipelineLayout creation time
to native pipeline initialization to know the internal immediate data
from shader module.
PipelineLayoutVk also holds creationInfo to avoid temp allocation for
VkPipelineLayoutCreateInfo.
Bug:chromium:42240537, chromium:366291600
Change-Id: Ib9726e7a17808628ab09f63e1b2327c9f418239c
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/208734
Reviewed-by: Geoff Lang <geofflang@chromium.org>
Commit-Queue: Shaobo Yan <shaobo.yan@intel.com>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
diff --git a/src/dawn/native/BUILD.gn b/src/dawn/native/BUILD.gn
index 004b8c3..766688d 100644
--- a/src/dawn/native/BUILD.gn
+++ b/src/dawn/native/BUILD.gn
@@ -802,6 +802,8 @@
"vulkan/PipelineCacheVk.h",
"vulkan/PipelineLayoutVk.cpp",
"vulkan/PipelineLayoutVk.h",
+ "vulkan/PipelineVk.cpp",
+ "vulkan/PipelineVk.h",
"vulkan/QuerySetVk.cpp",
"vulkan/QuerySetVk.h",
"vulkan/QueueVk.cpp",
diff --git a/src/dawn/native/BindGroupTracker.h b/src/dawn/native/BindGroupTracker.h
index 318c979..f448ff8 100644
--- a/src/dawn/native/BindGroupTracker.h
+++ b/src/dawn/native/BindGroupTracker.h
@@ -77,9 +77,11 @@
void OnSetPipeline(PipelineBase* pipeline) { mPipelineLayout = pipeline->GetLayout(); }
protected:
+ virtual bool AreLayoutsCompatible() { return mLastAppliedPipelineLayout == mPipelineLayout; }
+
// The Derived class should call this before it applies bind groups.
void BeforeApply() {
- if (mLastAppliedPipelineLayout == mPipelineLayout) {
+ if (AreLayoutsCompatible()) {
return;
}
diff --git a/src/dawn/native/CMakeLists.txt b/src/dawn/native/CMakeLists.txt
index 051ca77..4f9a0bb 100644
--- a/src/dawn/native/CMakeLists.txt
+++ b/src/dawn/native/CMakeLists.txt
@@ -668,6 +668,7 @@
"vulkan/FencedDeleter.h"
"vulkan/Forward.h"
"vulkan/PhysicalDeviceVk.h"
+ "vulkan/PipelineVk.h"
"vulkan/PipelineCacheVk.h"
"vulkan/PipelineLayoutVk.h"
"vulkan/QuerySetVk.h"
@@ -707,6 +708,7 @@
"vulkan/DeviceVk.cpp"
"vulkan/FencedDeleter.cpp"
"vulkan/PhysicalDeviceVk.cpp"
+ "vulkan/PipelineVk.cpp"
"vulkan/PipelineCacheVk.cpp"
"vulkan/PipelineLayoutVk.cpp"
"vulkan/QuerySetVk.cpp"
diff --git a/src/dawn/native/vulkan/CommandBufferVk.cpp b/src/dawn/native/vulkan/CommandBufferVk.cpp
index 1481329..40bf707 100644
--- a/src/dawn/native/vulkan/CommandBufferVk.cpp
+++ b/src/dawn/native/vulkan/CommandBufferVk.cpp
@@ -154,6 +154,19 @@
public:
DescriptorSetTracker() = default;
+ bool AreLayoutsCompatible() override {
+ return mPipelineLayout == mLastAppliedPipelineLayout &&
+ mLastAppliedInternalImmediateDataSize == mInternalImmediateDataSize;
+ }
+
+ template <typename VkPipelineType>
+ void OnSetPipeline(VkPipelineType* pipeline) {
+ BindGroupTrackerBase::OnSetPipeline(pipeline);
+
+ mVkLayout = pipeline->GetVkLayout();
+ mInternalImmediateDataSize = pipeline->GetInternalImmediateDataSize();
+ }
+
void Apply(Device* device,
CommandRecordingContext* recordingContext,
VkPipelineBindPoint bindPoint) {
@@ -163,12 +176,20 @@
uint32_t count = static_cast<uint32_t>(mDynamicOffsets[dirtyIndex].size());
const uint32_t* dynamicOffset =
count > 0 ? mDynamicOffsets[dirtyIndex].data() : nullptr;
- device->fn.CmdBindDescriptorSets(
- recordingContext->commandBuffer, bindPoint, ToBackend(mPipelineLayout)->GetHandle(),
- static_cast<uint32_t>(dirtyIndex), 1, &*set, count, dynamicOffset);
+ device->fn.CmdBindDescriptorSets(recordingContext->commandBuffer, bindPoint, mVkLayout,
+ static_cast<uint32_t>(dirtyIndex), 1, &*set, count,
+ dynamicOffset);
}
+
+ // Update PipelineLayout
AfterApply();
+
+ mLastAppliedInternalImmediateDataSize = mInternalImmediateDataSize;
}
+
+ RAW_PTR_EXCLUSION VkPipelineLayout mVkLayout;
+ uint32_t mLastAppliedInternalImmediateDataSize = 0;
+ uint32_t mInternalImmediateDataSize = 0;
};
// Records the necessary barriers for a synchronization scope using the resource usage
@@ -1076,7 +1097,7 @@
device->fn.CmdBindPipeline(commands, VK_PIPELINE_BIND_POINT_COMPUTE,
pipeline->GetHandle());
- descriptorSets.OnSetPipeline(pipeline);
+ descriptorSets.OnSetPipeline<ComputePipeline>(pipeline);
break;
}
@@ -1211,9 +1232,10 @@
if (!clampFragDepthArgsDirty || lastPipeline == nullptr) {
return;
}
- device->fn.CmdPushConstants(commands, ToBackend(lastPipeline->GetLayout())->GetHandle(),
- VK_SHADER_STAGE_FRAGMENT_BIT, kClampFragDepthArgsOffset,
- kClampFragDepthArgsSize, &clampFragDepthArgs);
+ device->fn.CmdPushConstants(
+ commands, lastPipeline->GetVkLayout(),
+ ToBackend(lastPipeline->GetLayout())->GetImmediateDataRangeStage(),
+ kClampFragDepthArgsOffset, kClampFragDepthArgsSize, &clampFragDepthArgs);
clampFragDepthArgsDirty = false;
};
@@ -1390,7 +1412,7 @@
pipeline->GetHandle());
lastPipeline = pipeline;
- descriptorSets.OnSetPipeline(pipeline);
+ descriptorSets.OnSetPipeline<RenderPipeline>(pipeline);
// Apply the deferred min/maxDepth push constants update if needed.
ApplyClampFragDepthArgs();
diff --git a/src/dawn/native/vulkan/ComputePipelineVk.cpp b/src/dawn/native/vulkan/ComputePipelineVk.cpp
index c8d2821..4085b22 100644
--- a/src/dawn/native/vulkan/ComputePipelineVk.cpp
+++ b/src/dawn/native/vulkan/ComputePipelineVk.cpp
@@ -52,16 +52,20 @@
MaybeError ComputePipeline::InitializeImpl() {
Device* device = ToBackend(GetDevice());
- const PipelineLayout* layout = ToBackend(GetLayout());
+ PipelineLayout* layout = ToBackend(GetLayout());
// Vulkan devices need cache UUID field to be serialized into pipeline cache keys.
StreamIn(&mCacheKey, device->GetDeviceInfo().properties.pipelineCacheUUID);
+ // Compute pipeline doesn't have clamp depth feature.
+ // TODO(crbug.com/366291600): Setting immediate data size if needed.
+ DAWN_TRY(InitializeBase(layout, 0));
+
VkComputePipelineCreateInfo createInfo;
createInfo.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO;
createInfo.pNext = nullptr;
createInfo.flags = 0;
- createInfo.layout = layout->GetHandle();
+ createInfo.layout = GetVkLayout();
createInfo.basePipelineHandle = VkPipeline{};
createInfo.basePipelineIndex = -1;
@@ -150,7 +154,7 @@
void ComputePipeline::DestroyImpl() {
ComputePipelineBase::DestroyImpl();
-
+ PipelineVk::DestroyImpl();
if (mHandle != VK_NULL_HANDLE) {
ToBackend(GetDevice())->GetFencedDeleter()->DeleteWhenUnused(mHandle);
mHandle = VK_NULL_HANDLE;
diff --git a/src/dawn/native/vulkan/ComputePipelineVk.h b/src/dawn/native/vulkan/ComputePipelineVk.h
index 4d557a0..823f895 100644
--- a/src/dawn/native/vulkan/ComputePipelineVk.h
+++ b/src/dawn/native/vulkan/ComputePipelineVk.h
@@ -33,12 +33,14 @@
#include "dawn/common/vulkan_platform.h"
#include "dawn/native/CreatePipelineAsyncEvent.h"
#include "dawn/native/Error.h"
+#include "dawn/native/vulkan/PipelineVk.h"
namespace dawn::native::vulkan {
class Device;
+struct VkPipelineLayoutObject;
-class ComputePipeline final : public ComputePipelineBase {
+class ComputePipeline final : public ComputePipelineBase, public PipelineVk {
public:
static Ref<ComputePipeline> CreateUninitialized(
Device* device,
diff --git a/src/dawn/native/vulkan/PipelineLayoutVk.cpp b/src/dawn/native/vulkan/PipelineLayoutVk.cpp
index cced6c4..db549c4 100644
--- a/src/dawn/native/vulkan/PipelineLayoutVk.cpp
+++ b/src/dawn/native/vulkan/PipelineLayoutVk.cpp
@@ -27,6 +27,9 @@
#include "dawn/native/vulkan/PipelineLayoutVk.h"
+#include <string>
+#include <utility>
+
#include "dawn/common/BitSetIterator.h"
#include "dawn/native/vulkan/BindGroupLayoutVk.h"
#include "dawn/native/vulkan/DeviceVk.h"
@@ -45,64 +48,114 @@
return layout;
}
-MaybeError PipelineLayout::Initialize() {
+ResultOrError<Ref<RefCountedVkHandle<VkPipelineLayout>>> PipelineLayout::CreateVkPipelineLayout(
+ uint32_t internalImmediateDataSize) {
// Compute the array of VkDescriptorSetLayouts that will be chained in the create info.
// TODO(crbug.com/dawn/277) Vulkan doesn't allow holes in this array, should we expose
// this constraints at the Dawn level?
uint32_t numSetLayouts = 0;
std::array<VkDescriptorSetLayout, kMaxBindGroups> setLayouts;
- std::array<const CachedObject*, kMaxBindGroups> cachedObjects;
for (BindGroupIndex setIndex : IterateBitSet(GetBindGroupLayoutsMask())) {
const BindGroupLayoutInternalBase* bindGroupLayout = GetBindGroupLayout(setIndex);
setLayouts[numSetLayouts] = ToBackend(bindGroupLayout)->GetHandle();
- cachedObjects[numSetLayouts] = bindGroupLayout;
numSetLayouts++;
}
- // Always reserve push constant space for the ClampFragDepthArgs.
- VkPushConstantRange depthClampArgsRange;
- depthClampArgsRange.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
- depthClampArgsRange.offset = kClampFragDepthArgsOffset;
- depthClampArgsRange.size = kClampFragDepthArgsSize;
-
VkPipelineLayoutCreateInfo createInfo;
createInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
createInfo.pNext = nullptr;
createInfo.flags = 0;
createInfo.setLayoutCount = numSetLayouts;
createInfo.pSetLayouts = AsVkArray(setLayouts.data());
- createInfo.pushConstantRangeCount = 1;
- createInfo.pPushConstantRanges = &depthClampArgsRange;
+ createInfo.pushConstantRangeCount = 0;
+ createInfo.pPushConstantRanges = nullptr;
- // Record cache key information now since the createInfo is not stored.
- StreamIn(&mCacheKey, stream::Iterable(cachedObjects.data(), numSetLayouts), createInfo);
+ // Create pipeline layout without internal immediate data size.
+ uint32_t immediateDataSize = GetImmediateDataRangeByteSize() + internalImmediateDataSize;
+ VkPushConstantRange immediateDataRange;
+ // createInfo has been initialized based on PipelineLayout attributes.
+ // Create immediateDataRange info based on
+ // Record cache key information now to represent pipelineLayout to exclude future changes
+ // caused by internal immediate data size from pipeline.
+ if (immediateDataSize > 0) {
+ immediateDataRange.stageFlags = kImmediateDataRangeShaderStage;
+ immediateDataRange.offset = 0;
+ immediateDataRange.size = immediateDataSize;
+ createInfo.pushConstantRangeCount = 1;
+ createInfo.pPushConstantRanges = &immediateDataRange;
+ }
+
+ VkPipelineLayout vkPipelineLayout;
Device* device = ToBackend(GetDevice());
- DAWN_TRY(CheckVkSuccess(
- device->fn.CreatePipelineLayout(device->GetVkDevice(), &createInfo, nullptr, &*mHandle),
- "CreatePipelineLayout"));
+ DAWN_TRY(CheckVkSuccess(device->fn.CreatePipelineLayout(device->GetVkDevice(), &createInfo,
+ nullptr, &*vkPipelineLayout),
+ "CreatePipelineLayout"));
- SetLabelImpl();
+ return AcquireRef(new RefCountedVkHandle<VkPipelineLayout>(device, vkPipelineLayout));
+}
+
+MaybeError PipelineLayout::Initialize() {
+ uint32_t numSetLayouts = 0;
+ std::array<const CachedObject*, kMaxBindGroups> cachedObjects;
+ for (BindGroupIndex setIndex : IterateBitSet(GetBindGroupLayoutsMask())) {
+ const BindGroupLayoutInternalBase* bindGroupLayout = GetBindGroupLayout(setIndex);
+ cachedObjects[numSetLayouts] = bindGroupLayout;
+ numSetLayouts++;
+ }
+
+ // Record bind group layout objects and user immediate data size into pipeline layout cache key.
+ // It represents pipeline layout base attributes and ignored future changes caused by internal
+ // immediate data size from pipeline.
+ StreamIn(&mCacheKey, stream::Iterable(cachedObjects.data(), numSetLayouts),
+ GetImmediateDataRangeByteSize());
return {};
}
+ResultOrError<Ref<RefCountedVkHandle<VkPipelineLayout>>> PipelineLayout::GetOrCreateVkLayoutObject(
+ uint32_t internalImmediateDataSize) {
+ // Check cache
+ Ref<RefCountedVkHandle<VkPipelineLayout>> pipelineLayoutVk;
+ mVkPipelineLayouts.Use([&](auto vkPipelineLayouts) {
+ auto it = vkPipelineLayouts->find(internalImmediateDataSize);
+ if (it != vkPipelineLayouts->end()) {
+ pipelineLayoutVk = it->second;
+ }
+ });
+
+ if (pipelineLayoutVk != nullptr) {
+ return pipelineLayoutVk;
+ }
+
+ DAWN_TRY_ASSIGN(pipelineLayoutVk, CreateVkPipelineLayout(internalImmediateDataSize));
+
+ return mVkPipelineLayouts.Use([&](auto vkPipelineLayouts) {
+ return vkPipelineLayouts->insert({internalImmediateDataSize, std::move(pipelineLayoutVk)})
+ .first->second;
+ });
+}
+
+VkShaderStageFlags PipelineLayout::GetImmediateDataRangeStage() const {
+ return kImmediateDataRangeShaderStage;
+}
+
PipelineLayout::~PipelineLayout() = default;
void PipelineLayout::DestroyImpl() {
PipelineLayoutBase::DestroyImpl();
- if (mHandle != VK_NULL_HANDLE) {
- ToBackend(GetDevice())->GetFencedDeleter()->DeleteWhenUnused(mHandle);
- mHandle = VK_NULL_HANDLE;
- }
-}
-
-VkPipelineLayout PipelineLayout::GetHandle() const {
- return mHandle;
+ mVkPipelineLayouts->clear();
}
void PipelineLayout::SetLabelImpl() {
- SetDebugName(ToBackend(GetDevice()), mHandle, "Dawn_PipelineLayout", GetLabel());
+ Device* device = ToBackend(GetDevice());
+ const std::string& label = GetLabel();
+
+ mVkPipelineLayouts.Use([&](auto vkPipelineLayouts) {
+ for (const auto& [_, vkLayout] : *vkPipelineLayouts) {
+ SetDebugName(device, vkLayout->Get(), "Dawn_PipelineLayout", label);
+ }
+ });
}
} // namespace dawn::native::vulkan
diff --git a/src/dawn/native/vulkan/PipelineLayoutVk.h b/src/dawn/native/vulkan/PipelineLayoutVk.h
index 06bd9f0..5dbbbc1 100644
--- a/src/dawn/native/vulkan/PipelineLayoutVk.h
+++ b/src/dawn/native/vulkan/PipelineLayoutVk.h
@@ -28,10 +28,12 @@
#ifndef SRC_DAWN_NATIVE_VULKAN_PIPELINELAYOUTVK_H_
#define SRC_DAWN_NATIVE_VULKAN_PIPELINELAYOUTVK_H_
-#include "dawn/native/PipelineLayout.h"
+#include <memory>
#include "dawn/common/vulkan_platform.h"
#include "dawn/native/Error.h"
+#include "dawn/native/PipelineLayout.h"
+#include "dawn/native/vulkan/RefCountedVkHandle.h"
namespace dawn::native::vulkan {
@@ -54,7 +56,13 @@
Device* device,
const UnpackedPtr<PipelineLayoutDescriptor>& descriptor);
- VkPipelineLayout GetHandle() const;
+ // Pipeline might use different amounts of immediate data internally which cause difference in
+ // VkPipelineLayout push constant range part. Pass internalImmediateDataSize to
+ // get correct VkPipelineLayout.
+ ResultOrError<Ref<RefCountedVkHandle<VkPipelineLayout>>> GetOrCreateVkLayoutObject(
+ uint32_t internalImmediateDataSize);
+
+ VkShaderStageFlags GetImmediateDataRangeStage() const;
// Friend definition of StreamIn which can be found by ADL to override stream::StreamIn<T>.
friend void StreamIn(stream::Sink* sink, const PipelineLayout& obj) {
@@ -68,10 +76,21 @@
using PipelineLayoutBase::PipelineLayoutBase;
MaybeError Initialize();
+ ResultOrError<Ref<RefCountedVkHandle<VkPipelineLayout>>> CreateVkPipelineLayout(
+ uint32_t internalImmediateDataSize);
+
// Dawn API
void SetLabelImpl() override;
- VkPipelineLayout mHandle = VK_NULL_HANDLE;
+ // Multiple VkPipelineLayouts is possible because variant internal immediate data size.
+ // Using map to manage 1 PipelineLayout to N VkPipelineLayouts relationship with
+ // total immediate data size as key.
+ MutexProtected<absl::flat_hash_map<uint32_t, Ref<RefCountedVkHandle<VkPipelineLayout>>>>
+ mVkPipelineLayouts;
+
+ // Immediate data requires unique range among shader stages.
+ VkShaderStageFlags kImmediateDataRangeShaderStage =
+ VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_COMPUTE_BIT | VK_SHADER_STAGE_VERTEX_BIT;
};
} // namespace dawn::native::vulkan
diff --git a/src/dawn/native/vulkan/PipelineVk.cpp b/src/dawn/native/vulkan/PipelineVk.cpp
new file mode 100644
index 0000000..78ce372
--- /dev/null
+++ b/src/dawn/native/vulkan/PipelineVk.cpp
@@ -0,0 +1,54 @@
+// Copyright 2024 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "dawn/native/vulkan/PipelineVk.h"
+#include "dawn/native/vulkan/PipelineLayoutVk.h"
+
+namespace dawn::native::vulkan {
+
+VkPipelineLayout PipelineVk::GetVkLayout() const {
+ return mVkPipelineLayout->Get();
+}
+
+uint32_t PipelineVk::GetInternalImmediateDataSize() const {
+ return mInternalImmediateDataSize;
+}
+
+MaybeError PipelineVk::InitializeBase(PipelineLayout* layout, uint32_t internalImmediateDataSize) {
+ mInternalImmediateDataSize = internalImmediateDataSize;
+
+ DAWN_TRY_ASSIGN(mVkPipelineLayout,
+ layout->GetOrCreateVkLayoutObject(internalImmediateDataSize));
+
+ return {};
+}
+
+void PipelineVk::DestroyImpl() {
+ mVkPipelineLayout = nullptr;
+}
+
+} // namespace dawn::native::vulkan
diff --git a/src/dawn/native/vulkan/PipelineVk.h b/src/dawn/native/vulkan/PipelineVk.h
new file mode 100644
index 0000000..833a538
--- /dev/null
+++ b/src/dawn/native/vulkan/PipelineVk.h
@@ -0,0 +1,65 @@
+// Copyright 2024 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef SRC_DAWN_NATIVE_VULKAN_PIPELINEVK_H_
+#define SRC_DAWN_NATIVE_VULKAN_PIPELINEVK_H_
+
+#include <memory>
+
+#include "dawn/common/vulkan_platform.h"
+#include "dawn/native/Error.h"
+#include "dawn/native/PipelineLayout.h"
+#include "dawn/native/vulkan/RefCountedVkHandle.h"
+
+namespace dawn::native::vulkan {
+
+class Device;
+class PipelineLayout;
+
+class PipelineVk {
+ public:
+ PipelineVk() = default;
+ ~PipelineVk() = default;
+
+ VkPipelineLayout GetVkLayout() const;
+ uint32_t GetInternalImmediateDataSize() const;
+
+ protected:
+ MaybeError InitializeBase(PipelineLayout* layout, uint32_t internalImmediateDataSize);
+ void DestroyImpl();
+
+ private:
+ // Internal immediate data is decided by shader modules and might be different from
+ // pipelines created with same pipeline layout object.
+ int32_t mInternalImmediateDataSize = 0;
+
+ Ref<RefCountedVkHandle<VkPipelineLayout>> mVkPipelineLayout;
+};
+
+} // namespace dawn::native::vulkan
+
+#endif // SRC_DAWN_NATIVE_VULKAN_PIPELINEVK_H_
diff --git a/src/dawn/native/vulkan/RenderPipelineVk.cpp b/src/dawn/native/vulkan/RenderPipelineVk.cpp
index 55860c5..4037536 100644
--- a/src/dawn/native/vulkan/RenderPipelineVk.cpp
+++ b/src/dawn/native/vulkan/RenderPipelineVk.cpp
@@ -331,7 +331,7 @@
MaybeError RenderPipeline::InitializeImpl() {
Device* device = ToBackend(GetDevice());
- const PipelineLayout* layout = ToBackend(GetLayout());
+ PipelineLayout* layout = ToBackend(GetLayout());
// Vulkan devices need cache UUID field to be serialized into pipeline cache keys.
StreamIn(&mCacheKey, device->GetDeviceInfo().properties.pipelineCacheUUID);
@@ -539,6 +539,9 @@
DAWN_TRY_ASSIGN(renderPassInfo, device->GetRenderPassCache()->GetRenderPass(query));
}
+ // TODO(crbug.com/366291600): Add internal immediate data size when needed.
+ DAWN_TRY(InitializeBase(layout, kClampFragDepthArgsSize));
+
// The create info chains in a bunch of things created on the stack here or inside state
// objects.
VkGraphicsPipelineCreateInfo createInfo;
@@ -557,7 +560,7 @@
createInfo.pColorBlendState =
(GetStageMask() & wgpu::ShaderStage::Fragment) ? &colorBlend : nullptr;
createInfo.pDynamicState = &dynamic;
- createInfo.layout = ToBackend(GetLayout())->GetHandle();
+ createInfo.layout = GetVkLayout();
createInfo.renderPass = renderPassInfo.renderPass;
createInfo.basePipelineHandle = VkPipeline{};
createInfo.basePipelineIndex = -1;
@@ -695,6 +698,7 @@
void RenderPipeline::DestroyImpl() {
RenderPipelineBase::DestroyImpl();
+ PipelineVk::DestroyImpl();
if (mHandle != VK_NULL_HANDLE) {
ToBackend(GetDevice())->GetFencedDeleter()->DeleteWhenUnused(mHandle);
mHandle = VK_NULL_HANDLE;
diff --git a/src/dawn/native/vulkan/RenderPipelineVk.h b/src/dawn/native/vulkan/RenderPipelineVk.h
index 71fb8ff..942f917 100644
--- a/src/dawn/native/vulkan/RenderPipelineVk.h
+++ b/src/dawn/native/vulkan/RenderPipelineVk.h
@@ -32,12 +32,14 @@
#include "dawn/common/vulkan_platform.h"
#include "dawn/native/Error.h"
+#include "dawn/native/vulkan/PipelineVk.h"
namespace dawn::native::vulkan {
class Device;
+struct VkPipelineLayoutObject;
-class RenderPipeline final : public RenderPipelineBase {
+class RenderPipeline final : public RenderPipelineBase, public PipelineVk {
public:
static Ref<RenderPipeline> CreateUninitialized(
Device* device,
diff --git a/src/dawn/native/vulkan/ResolveTextureLoadingUtilsVk.cpp b/src/dawn/native/vulkan/ResolveTextureLoadingUtilsVk.cpp
index 1bc34c7..65bf71d 100644
--- a/src/dawn/native/vulkan/ResolveTextureLoadingUtilsVk.cpp
+++ b/src/dawn/native/vulkan/ResolveTextureLoadingUtilsVk.cpp
@@ -229,8 +229,6 @@
device, pipelineKey, static_cast<uint8_t>(colorAttachmentCount)));
RenderPipeline* pipelineVk = ToBackend(pipeline.Get());
- PipelineLayout* layoutVk = ToBackend(pipeline->GetLayout());
- DAWN_ASSERT(layoutVk != nullptr);
// Construct bind group.
Ref<BindGroupLayoutBase> bgl;
@@ -284,8 +282,8 @@
device->fn.CmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS,
*pipelineVk->GetHandle());
device->fn.CmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS,
- *layoutVk->GetHandle(), 0, 1, &*bindGroupVk->GetHandle(), 0,
- nullptr);
+ *pipelineVk->GetVkLayout(), 0, 1, &*bindGroupVk->GetHandle(),
+ 0, nullptr);
device->fn.CmdDraw(commandBuffer, 3, 1, 0, 0);
device->fn.CmdNextSubpass(commandBuffer, VK_SUBPASS_CONTENTS_INLINE);