dawn-cmake/src/dawn/native/vulkan/ComputePipelineVk.cpp
Corentin Wallez 363a995068 ShaderModuleVk: Add a renamer to make other transforms safe.
Without this other Tint transforms may end up calling user code instead
of builtins (for example for the min() used in robustness).

This commit does the following changes:
 - Changes ShaderModuleVk to return a CompiledSpirv object instead of
   just a Spirv Blob so that a remappedEntryPoint can be stored in the
   cache alongside the SPIR-V.
 - Inlines the logic and simplifies TransformedConcurrentShaderModuleCache
   slightly (by introducing a struct instead of std::pair, and adding a
   conversion method to ModuleAndSpirv).
 - Adds the Renamer transform to ShaderModuleVk and adapt the code to
   use the remappedEntryPoint where needed (pipeline creation and
   post-compilation reflection).
 - Adds a test where the min() used by the robustness transform is
   overriden to return a constant 0.
 - Moves the Renamer transform to be just after the SingleEntryPoint
   transform in D3D12 and Metal as well so as to make the test pass.

Fixed: dawn:1583
Bug: dawn:1585 dawn:1587

Change-Id: Ia9de38d391a7901ed04b097f4a8d439759f7556e
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/107020
Reviewed-by: Ben Clayton <bclayton@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
2022-10-31 11:17:50 +00:00

130 lines
5.0 KiB
C++

// Copyright 2018 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "dawn/native/vulkan/ComputePipelineVk.h"
#include <memory>
#include <utility>
#include <vector>
#include "dawn/native/CreatePipelineAsyncTask.h"
#include "dawn/native/vulkan/DeviceVk.h"
#include "dawn/native/vulkan/FencedDeleter.h"
#include "dawn/native/vulkan/PipelineCacheVk.h"
#include "dawn/native/vulkan/PipelineLayoutVk.h"
#include "dawn/native/vulkan/ShaderModuleVk.h"
#include "dawn/native/vulkan/UtilsVulkan.h"
#include "dawn/native/vulkan/VulkanError.h"
namespace dawn::native::vulkan {
// static
Ref<ComputePipeline> ComputePipeline::CreateUninitialized(
Device* device,
const ComputePipelineDescriptor* descriptor) {
return AcquireRef(new ComputePipeline(device, descriptor));
}
MaybeError ComputePipeline::Initialize() {
Device* device = ToBackend(GetDevice());
const PipelineLayout* layout = ToBackend(GetLayout());
// Vulkan devices need cache UUID field to be serialized into pipeline cache keys.
StreamIn(&mCacheKey, device->GetDeviceInfo().properties.pipelineCacheUUID);
VkComputePipelineCreateInfo createInfo;
createInfo.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO;
createInfo.pNext = nullptr;
createInfo.flags = 0;
createInfo.layout = layout->GetHandle();
createInfo.basePipelineHandle = VkPipeline{};
createInfo.basePipelineIndex = -1;
createInfo.stage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
createInfo.stage.pNext = nullptr;
createInfo.stage.flags = 0;
createInfo.stage.stage = VK_SHADER_STAGE_COMPUTE_BIT;
// Generate a new VkShaderModule with BindingRemapper tint transform for each pipeline
const ProgrammableStage& computeStage = GetStage(SingleShaderStage::Compute);
ShaderModule* module = ToBackend(computeStage.module.Get());
ShaderModule::ModuleAndSpirv moduleAndSpirv;
DAWN_TRY_ASSIGN(moduleAndSpirv,
module->GetHandleAndSpirv(SingleShaderStage::Compute, computeStage, layout));
createInfo.stage.module = moduleAndSpirv.module;
createInfo.stage.pName = moduleAndSpirv.remappedEntryPoint;
createInfo.stage.pSpecializationInfo = nullptr;
PNextChainBuilder stageExtChain(&createInfo.stage);
VkPipelineShaderStageRequiredSubgroupSizeCreateInfoEXT subgroupSizeInfo = {};
uint32_t computeSubgroupSize = device->GetComputeSubgroupSize();
if (computeSubgroupSize != 0u) {
ASSERT(device->GetDeviceInfo().HasExt(DeviceExt::SubgroupSizeControl));
subgroupSizeInfo.requiredSubgroupSize = computeSubgroupSize;
stageExtChain.Add(
&subgroupSizeInfo,
VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_REQUIRED_SUBGROUP_SIZE_CREATE_INFO_EXT);
}
// Record cache key information now since the createInfo is not stored.
StreamIn(&mCacheKey, createInfo, layout,
stream::Iterable(moduleAndSpirv.spirv, moduleAndSpirv.wordCount));
// Try to see if we have anything in the blob cache.
Ref<PipelineCache> cache = ToBackend(GetDevice()->GetOrCreatePipelineCache(GetCacheKey()));
DAWN_TRY(
CheckVkSuccess(device->fn.CreateComputePipelines(device->GetVkDevice(), cache->GetHandle(),
1, &createInfo, nullptr, &*mHandle),
"CreateComputePipeline"));
// TODO(dawn:549): Flush is currently in the same thread, but perhaps deferrable.
DAWN_TRY(cache->FlushIfNeeded());
SetLabelImpl();
return {};
}
void ComputePipeline::SetLabelImpl() {
SetDebugName(ToBackend(GetDevice()), mHandle, "Dawn_ComputePipeline", GetLabel());
}
ComputePipeline::~ComputePipeline() = default;
void ComputePipeline::DestroyImpl() {
ComputePipelineBase::DestroyImpl();
if (mHandle != VK_NULL_HANDLE) {
ToBackend(GetDevice())->GetFencedDeleter()->DeleteWhenUnused(mHandle);
mHandle = VK_NULL_HANDLE;
}
}
VkPipeline ComputePipeline::GetHandle() const {
return mHandle;
}
void ComputePipeline::InitializeAsync(Ref<ComputePipelineBase> computePipeline,
WGPUCreateComputePipelineAsyncCallback callback,
void* userdata) {
std::unique_ptr<CreateComputePipelineAsyncTask> asyncTask =
std::make_unique<CreateComputePipelineAsyncTask>(std::move(computePipeline), callback,
userdata);
CreateComputePipelineAsyncTask::RunAsync(std::move(asyncTask));
}
} // namespace dawn::native::vulkan