// 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 #include #include #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::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 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 computePipeline, WGPUCreateComputePipelineAsyncCallback callback, void* userdata) { std::unique_ptr asyncTask = std::make_unique(std::move(computePipeline), callback, userdata); CreateComputePipelineAsyncTask::RunAsync(std::move(asyncTask)); } } // namespace dawn::native::vulkan