| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634 |
- // Copyright (C) 2009-2023, Panagiotis Christopoulos Charitos and contributors.
- // All rights reserved.
- // Code licensed under the BSD License.
- // http://www.anki3d.org/LICENSE
- #include <AnKi/Gr/Vulkan/VkPipelineFactory.h>
- #include <AnKi/Gr/Vulkan/VkGrManager.h>
- #include <AnKi/Gr/BackendCommon/Functions.h>
- #include <AnKi/Util/Tracer.h>
- #include <AnKi/Util/Filesystem.h>
- namespace anki {
- static NumericCVar<PtrSize> g_diskShaderCacheMaxSizeCVar(CVarSubsystem::kGr, "DiskShaderCacheMaxSize", 128_MB, 1_MB, 1_GB,
- "Max size of the pipeline cache file");
- void PipelineStateTracker::reset()
- {
- m_state.reset();
- m_hashes = {};
- m_dirty = {};
- m_set = {};
- m_shaderVertexAttributeMask.unsetAll();
- m_shaderColorAttachmentWritemask.unsetAll();
- m_fbDepth = false;
- m_fbStencil = false;
- m_rendersToSwapchain = false;
- m_fbColorAttachmentCount = 0;
- }
- Bool PipelineStateTracker::updateHashes()
- {
- Bool stateDirty = false;
- // Prog
- if(m_dirty.m_prog)
- {
- m_dirty.m_prog = false;
- stateDirty = true;
- m_hashes.m_prog = m_state.m_prog->getUuid();
- }
- // Vertex
- if(m_dirty.m_attribs.getAnySet() || m_dirty.m_vertBindings.getAnySet())
- {
- for(VertexAttributeSemantic i : EnumIterable<VertexAttributeSemantic>())
- {
- if(m_shaderVertexAttributeMask.get(i))
- {
- ANKI_ASSERT(m_set.m_attribs.get(i) && "Forgot to set the attribute");
- Bool dirty = false;
- if(m_dirty.m_attribs.get(i))
- {
- m_dirty.m_attribs.unset(i);
- dirty = true;
- }
- const U binding = m_state.m_vertex.m_attributes[i].m_binding;
- ANKI_ASSERT(m_set.m_vertBindings.get(binding) && "Forgot to set a vertex binding");
- if(m_dirty.m_vertBindings.get(binding))
- {
- m_dirty.m_vertBindings.unset(binding);
- dirty = true;
- }
- if(dirty)
- {
- m_hashes.m_vertexAttribs[i] = computeHash(&m_state.m_vertex.m_attributes[i], sizeof(m_state.m_vertex.m_attributes[i]));
- m_hashes.m_vertexAttribs[i] =
- appendHash(&m_state.m_vertex.m_bindings[i], sizeof(m_state.m_vertex.m_bindings[i]), m_hashes.m_vertexAttribs[i]);
- stateDirty = true;
- }
- }
- }
- }
- // IA
- if(m_dirty.m_inputAssembler)
- {
- m_dirty.m_inputAssembler = false;
- stateDirty = true;
- m_hashes.m_ia = computeHash(&m_state.m_inputAssembler, sizeof(m_state.m_inputAssembler));
- }
- // Rasterizer
- if(m_dirty.m_rasterizer)
- {
- m_dirty.m_rasterizer = false;
- stateDirty = true;
- m_hashes.m_raster = computeHash(&m_state.m_rasterizer, sizeof(m_state.m_rasterizer));
- }
- // Depth
- if(m_fbDepth && m_dirty.m_depth)
- {
- m_dirty.m_depth = false;
- stateDirty = true;
- m_hashes.m_depth = computeHash(&m_state.m_depth, sizeof(m_state.m_depth));
- }
- // Stencil
- if(m_fbStencil && m_dirty.m_stencil)
- {
- m_dirty.m_stencil = false;
- stateDirty = true;
- m_hashes.m_stencil = computeHash(&m_state.m_stencil, sizeof(m_state.m_stencil));
- }
- // Color
- if(m_fbColorAttachmentCount)
- {
- ANKI_ASSERT((m_fbColorAttachmentCount == m_shaderColorAttachmentWritemask.getSetBitCount() || !m_shaderColorAttachmentWritemask)
- && "Shader and FB should have same attachment mask or shader mask should be zero");
- if(m_dirty.m_color)
- {
- m_dirty.m_color = false;
- m_hashes.m_color = m_state.m_color.m_alphaToCoverageEnabled ? 1 : 2;
- stateDirty = true;
- }
- for(U32 i = 0; i < m_fbColorAttachmentCount; ++i)
- {
- if(m_dirty.m_colAttachments.get(i))
- {
- m_dirty.m_colAttachments.unset(i);
- m_hashes.m_colAttachments[i] = computeHash(&m_state.m_color.m_attachments[i], sizeof(m_state.m_color.m_attachments[i]));
- stateDirty = true;
- }
- }
- }
- // Rpass
- if(m_dirty.m_rpass)
- {
- m_dirty.m_rpass = false;
- stateDirty = true;
- m_hashes.m_rpass = computeHash(m_state.m_attachmentFormats.getBegin(), m_state.m_attachmentFormats.getSizeInBytes());
- }
- return stateDirty;
- }
- void PipelineStateTracker::updateSuperHash()
- {
- Array<U64, sizeof(Hashes) / sizeof(U64)> buff;
- U count = 0;
- // Prog
- buff[count++] = m_hashes.m_prog;
- // Rpass
- buff[count++] = m_hashes.m_rpass;
- // Vertex
- if(!!m_shaderVertexAttributeMask)
- {
- for(VertexAttributeSemantic i : EnumIterable<VertexAttributeSemantic>())
- {
- if(m_shaderVertexAttributeMask.get(i))
- {
- buff[count++] = m_hashes.m_vertexAttribs[i];
- }
- }
- }
- // IA
- buff[count++] = m_hashes.m_ia;
- // Rasterizer
- buff[count++] = m_hashes.m_raster;
- // Depth
- if(m_fbDepth)
- {
- buff[count++] = m_hashes.m_depth;
- }
- // Stencil
- if(m_fbStencil)
- {
- buff[count++] = m_hashes.m_stencil;
- }
- // Color
- if(m_fbColorAttachmentCount)
- {
- buff[count++] = m_hashes.m_color;
- for(U i = 0; i < m_fbColorAttachmentCount; ++i)
- {
- buff[count++] = m_hashes.m_colAttachments[i];
- }
- }
- // Super hash
- m_hashes.m_superHash = computeHash(&buff[0], count * sizeof(buff[0]));
- }
- const VkGraphicsPipelineCreateInfo& PipelineStateTracker::updatePipelineCreateInfo()
- {
- VkGraphicsPipelineCreateInfo& ci = m_ci.m_ppline;
- ci = {};
- ci.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
- if(m_pipelineStatisticsEnabled)
- {
- ci.flags |= VK_PIPELINE_CREATE_CAPTURE_STATISTICS_BIT_KHR;
- }
- // Prog
- ci.pStages = static_cast<const ShaderProgramImpl&>(*m_state.m_prog).getShaderCreateInfos(ci.stageCount);
- // Vert
- VkPipelineVertexInputStateCreateInfo& vertCi = m_ci.m_vert;
- vertCi = {};
- vertCi.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
- vertCi.pVertexAttributeDescriptions = &m_ci.m_attribs[0];
- vertCi.pVertexBindingDescriptions = &m_ci.m_vertBindings[0];
- BitSet<U32(VertexAttributeSemantic::kCount), U8> bindingSet = {false};
- for(VertexAttributeSemantic semantic : EnumIterable<VertexAttributeSemantic>())
- {
- if(m_shaderVertexAttributeMask.get(semantic))
- {
- VkVertexInputAttributeDescription& attrib = m_ci.m_attribs[vertCi.vertexAttributeDescriptionCount++];
- attrib.binding = m_state.m_vertex.m_attributes[semantic].m_binding;
- attrib.format = convertFormat(m_state.m_vertex.m_attributes[semantic].m_format);
- attrib.location = m_semanticToVertexAttributeLocation[semantic];
- attrib.offset = U32(m_state.m_vertex.m_attributes[semantic].m_offset);
- if(!bindingSet.get(attrib.binding))
- {
- bindingSet.set(attrib.binding);
- VkVertexInputBindingDescription& binding = m_ci.m_vertBindings[vertCi.vertexBindingDescriptionCount++];
- binding.binding = attrib.binding;
- binding.inputRate = convertVertexStepRate(m_state.m_vertex.m_bindings[attrib.binding].m_stepRate);
- binding.stride = m_state.m_vertex.m_bindings[attrib.binding].m_stride;
- }
- }
- }
- ci.pVertexInputState = &vertCi;
- // IA
- VkPipelineInputAssemblyStateCreateInfo& iaCi = m_ci.m_ia;
- iaCi = {};
- iaCi.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
- iaCi.primitiveRestartEnable = m_state.m_inputAssembler.m_primitiveRestartEnabled;
- iaCi.topology = convertTopology(m_state.m_inputAssembler.m_topology);
- ci.pInputAssemblyState = &iaCi;
- // Viewport
- VkPipelineViewportStateCreateInfo& vpCi = m_ci.m_vp;
- vpCi = {};
- vpCi.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
- vpCi.scissorCount = 1;
- vpCi.viewportCount = 1;
- ci.pViewportState = &vpCi;
- // Raster
- VkPipelineRasterizationStateCreateInfo& rastCi = m_ci.m_rast;
- rastCi = {};
- rastCi.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
- rastCi.depthClampEnable = false;
- rastCi.rasterizerDiscardEnable = false;
- rastCi.polygonMode = convertFillMode(m_state.m_rasterizer.m_fillMode);
- rastCi.cullMode = convertCullMode(m_state.m_rasterizer.m_cullMode);
- rastCi.frontFace = (!m_rendersToSwapchain) ? VK_FRONT_FACE_CLOCKWISE : VK_FRONT_FACE_COUNTER_CLOCKWISE; // For viewport flip
- rastCi.depthBiasEnable = m_state.m_rasterizer.m_depthBiasEnabled;
- rastCi.lineWidth = 1.0;
- ci.pRasterizationState = &rastCi;
- if(m_state.m_rasterizer.m_rasterizationOrder != RasterizationOrder::kOrdered)
- {
- VkPipelineRasterizationStateRasterizationOrderAMD& rastOrderCi = m_ci.m_rasterOrder;
- rastOrderCi = {};
- rastOrderCi.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_RASTERIZATION_ORDER_AMD;
- rastOrderCi.rasterizationOrder = convertRasterizationOrder(m_state.m_rasterizer.m_rasterizationOrder);
- appendPNextList(rastCi, &rastOrderCi);
- }
- // MS
- VkPipelineMultisampleStateCreateInfo& msCi = m_ci.m_ms;
- msCi = {};
- msCi.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
- msCi.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
- ci.pMultisampleState = &msCi;
- // DS
- if(m_fbDepth || m_fbStencil)
- {
- VkPipelineDepthStencilStateCreateInfo& dsCi = m_ci.m_ds;
- dsCi = {};
- dsCi.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
- if(m_fbDepth)
- {
- dsCi.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
- dsCi.depthTestEnable = m_state.m_depth.m_depthCompareFunction != CompareOperation::kAlways || m_state.m_depth.m_depthWriteEnabled;
- dsCi.depthWriteEnable = m_state.m_depth.m_depthWriteEnabled;
- dsCi.depthCompareOp = convertCompareOp(m_state.m_depth.m_depthCompareFunction);
- }
- if(m_fbStencil)
- {
- const StencilPipelineState& ss = m_state.m_stencil;
- dsCi.stencilTestEnable = !stencilTestDisabled(ss.m_face[0].m_stencilFailOperation, ss.m_face[0].m_stencilPassDepthFailOperation,
- ss.m_face[0].m_stencilPassDepthPassOperation, ss.m_face[0].m_compareFunction)
- || !stencilTestDisabled(ss.m_face[1].m_stencilFailOperation, ss.m_face[1].m_stencilPassDepthFailOperation,
- ss.m_face[1].m_stencilPassDepthPassOperation, ss.m_face[1].m_compareFunction);
- dsCi.front.failOp = convertStencilOp(ss.m_face[0].m_stencilFailOperation);
- dsCi.front.passOp = convertStencilOp(ss.m_face[0].m_stencilPassDepthPassOperation);
- dsCi.front.depthFailOp = convertStencilOp(ss.m_face[0].m_stencilPassDepthFailOperation);
- dsCi.front.compareOp = convertCompareOp(ss.m_face[0].m_compareFunction);
- dsCi.back.failOp = convertStencilOp(ss.m_face[1].m_stencilFailOperation);
- dsCi.back.passOp = convertStencilOp(ss.m_face[1].m_stencilPassDepthPassOperation);
- dsCi.back.depthFailOp = convertStencilOp(ss.m_face[1].m_stencilPassDepthFailOperation);
- dsCi.back.compareOp = convertCompareOp(ss.m_face[1].m_compareFunction);
- }
- ci.pDepthStencilState = &dsCi;
- }
- // Color/blend
- if(m_fbColorAttachmentCount)
- {
- VkPipelineColorBlendStateCreateInfo& colCi = m_ci.m_color;
- colCi = {};
- colCi.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
- colCi.attachmentCount = m_fbColorAttachmentCount;
- colCi.pAttachments = &m_ci.m_colAttachments[0];
- for(U i = 0; i < colCi.attachmentCount; ++i)
- {
- VkPipelineColorBlendAttachmentState& out = m_ci.m_colAttachments[i];
- const ColorAttachmentState& in = m_state.m_color.m_attachments[i];
- out.blendEnable = !blendingDisabled(in.m_srcBlendFactorRgb, in.m_dstBlendFactorRgb, in.m_srcBlendFactorA, in.m_dstBlendFactorA,
- in.m_blendFunctionRgb, in.m_blendFunctionA);
- out.srcColorBlendFactor = convertBlendFactor(in.m_srcBlendFactorRgb);
- out.dstColorBlendFactor = convertBlendFactor(in.m_dstBlendFactorRgb);
- out.srcAlphaBlendFactor = convertBlendFactor(in.m_srcBlendFactorA);
- out.dstAlphaBlendFactor = convertBlendFactor(in.m_dstBlendFactorA);
- out.colorBlendOp = convertBlendOperation(in.m_blendFunctionRgb);
- out.alphaBlendOp = convertBlendOperation(in.m_blendFunctionA);
- out.colorWriteMask = convertColorWriteMask(in.m_channelWriteMask);
- }
- ci.pColorBlendState = &colCi;
- }
- // Dyn state
- VkPipelineDynamicStateCreateInfo& dynCi = m_ci.m_dyn;
- dynCi = {};
- dynCi.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
- // Renderpass related (Dynamic rendering)
- VkPipelineRenderingCreateInfoKHR& dynRendering = m_ci.m_dynamicRendering;
- dynRendering = {};
- dynRendering.sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR;
- dynRendering.colorAttachmentCount = m_fbColorAttachmentCount;
- dynRendering.pColorAttachmentFormats = m_ci.m_dynamicRenderingAttachmentFormats.getBegin();
- for(U i = 0; i < m_fbColorAttachmentCount; ++i)
- {
- m_ci.m_dynamicRenderingAttachmentFormats[i] = convertFormat(m_state.m_attachmentFormats[i]);
- }
- if(m_fbDepth)
- {
- dynRendering.depthAttachmentFormat = convertFormat(m_state.m_attachmentFormats[kMaxColorRenderTargets]);
- }
- if(m_fbStencil)
- {
- dynRendering.stencilAttachmentFormat = convertFormat(m_state.m_attachmentFormats[kMaxColorRenderTargets]);
- }
- appendPNextList(ci, &m_ci.m_dynamicRendering);
- // Almost all state is dynamic. Depth bias is static
- static constexpr Array<VkDynamicState, 10> kDyn = {
- {VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR, VK_DYNAMIC_STATE_BLEND_CONSTANTS, VK_DYNAMIC_STATE_DEPTH_BOUNDS,
- VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK, VK_DYNAMIC_STATE_STENCIL_WRITE_MASK, VK_DYNAMIC_STATE_STENCIL_REFERENCE, VK_DYNAMIC_STATE_LINE_WIDTH,
- VK_DYNAMIC_STATE_DEPTH_BIAS, VK_DYNAMIC_STATE_FRAGMENT_SHADING_RATE_KHR}};
- dynCi.dynamicStateCount = (m_vrsCapable) ? kDyn.getSize() : (kDyn.getSize() - 1);
- dynCi.pDynamicStates = &kDyn[0];
- ci.pDynamicState = &dynCi;
- // The rest
- ci.layout = static_cast<const ShaderProgramImpl&>(*m_state.m_prog).getPipelineLayout().getHandle();
- ci.subpass = 0;
- return ci;
- }
- class PipelineFactory::PipelineInternal
- {
- public:
- VkPipeline m_handle = VK_NULL_HANDLE;
- };
- class PipelineFactory::Hasher
- {
- public:
- U64 operator()(U64 h)
- {
- return h;
- }
- };
- PipelineFactory::PipelineFactory()
- {
- }
- PipelineFactory::~PipelineFactory()
- {
- }
- void PipelineFactory::destroy()
- {
- for(auto it : m_pplines)
- {
- if(it.m_handle)
- {
- vkDestroyPipeline(getVkDevice(), it.m_handle, nullptr);
- }
- }
- m_pplines.destroy();
- }
- void PipelineFactory::getOrCreatePipeline(PipelineStateTracker& state, Pipeline& ppline, Bool& stateDirty)
- {
- ANKI_TRACE_SCOPED_EVENT(VkPipelineGetOrCreate);
- U64 hash;
- state.flush(hash, stateDirty);
- if(!stateDirty) [[unlikely]]
- {
- ppline.m_handle = VK_NULL_HANDLE;
- return;
- }
- // Check if ppline exists
- {
- RLockGuard<RWMutex> lock(m_pplinesMtx);
- auto it = m_pplines.find(hash);
- if(it != m_pplines.getEnd())
- {
- ppline.m_handle = (*it).m_handle;
- ANKI_TRACE_INC_COUNTER(VkPipelineCacheHit, 1);
- return;
- }
- }
- // Doesnt exist. Need to create it
- WLockGuard<RWMutex> lock(m_pplinesMtx);
- // Check again
- auto it = m_pplines.find(hash);
- if(it != m_pplines.getEnd())
- {
- ppline.m_handle = (*it).m_handle;
- return;
- }
- // Create it for real
- PipelineInternal pp;
- const VkGraphicsPipelineCreateInfo& ci = state.updatePipelineCreateInfo();
- {
- ANKI_TRACE_SCOPED_EVENT(VkPipelineCreate);
- #if ANKI_PLATFORM_MOBILE
- if(PipelineCache::getSingleton().m_globalCreatePipelineMtx)
- {
- PipelineCache::getSingleton().m_globalCreatePipelineMtx->lock();
- }
- #endif
- ANKI_VK_CHECKF(vkCreateGraphicsPipelines(getVkDevice(), PipelineCache::getSingleton().m_cacheHandle, 1, &ci, nullptr, &pp.m_handle));
- #if ANKI_PLATFORM_MOBILE
- if(PipelineCache::getSingleton().m_globalCreatePipelineMtx)
- {
- PipelineCache::getSingleton().m_globalCreatePipelineMtx->unlock();
- }
- #endif
- }
- ANKI_TRACE_INC_COUNTER(VkPipelineCacheMiss, 1);
- m_pplines.emplace(hash, pp);
- ppline.m_handle = pp.m_handle;
- // Print shader info
- getGrManagerImpl().printPipelineShaderInfo(pp.m_handle, state.m_state.m_prog->getName(), hash);
- }
- Error PipelineCache::init(CString cacheDir)
- {
- ANKI_ASSERT(cacheDir);
- m_dumpSize = g_diskShaderCacheMaxSizeCVar.get();
- m_dumpFilename.sprintf("%s/VkPipelineCache", cacheDir.cstr());
- // Try read the pipeline cache file.
- GrDynamicArray<U8, PtrSize> diskDump;
- if(fileExists(m_dumpFilename.toCString()))
- {
- File file;
- ANKI_CHECK(file.open(m_dumpFilename.toCString(), FileOpenFlag::kBinary | FileOpenFlag::kRead));
- const PtrSize diskDumpSize = file.getSize();
- if(diskDumpSize <= sizeof(U8) * VK_UUID_SIZE)
- {
- ANKI_VK_LOGI("Pipeline cache dump appears to be empty: %s", &m_dumpFilename[0]);
- }
- else
- {
- // Get current pipeline UUID and compare it with the cache's
- VkPhysicalDeviceProperties props;
- vkGetPhysicalDeviceProperties(getGrManagerImpl().getPhysicalDevice(), &props);
- Array<U8, VK_UUID_SIZE> cacheUuid;
- ANKI_CHECK(file.read(&cacheUuid[0], VK_UUID_SIZE));
- if(memcmp(&cacheUuid[0], &props.pipelineCacheUUID[0], VK_UUID_SIZE) != 0)
- {
- ANKI_VK_LOGI("Pipeline cache dump is not compatible with the current device: %s", &m_dumpFilename[0]);
- }
- else
- {
- diskDump.resize(diskDumpSize - VK_UUID_SIZE);
- ANKI_CHECK(file.read(&diskDump[0], diskDumpSize - VK_UUID_SIZE));
- }
- }
- }
- else
- {
- ANKI_VK_LOGI("Pipeline cache dump not found: %s", &m_dumpFilename[0]);
- }
- // Create the cache
- VkPipelineCacheCreateInfo ci = {};
- ci.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO;
- if(diskDump.getSize())
- {
- ANKI_VK_LOGI("Will load %zu bytes of pipeline cache", diskDump.getSize());
- ci.initialDataSize = diskDump.getSize();
- ci.pInitialData = &diskDump[0];
- }
- ANKI_VK_CHECK(vkCreatePipelineCache(getVkDevice(), &ci, nullptr, &m_cacheHandle));
- #if ANKI_PLATFORM_MOBILE
- ANKI_ASSERT(GrManager::getSingleton().getDeviceCapabilities() != GpuVendor::kNone);
- if(GrManager::getSingleton().getDeviceCapabilities().m_gpuVendor == GpuVendor::kQualcomm)
- {
- // Calling vkCreateGraphicsPipeline from multiple threads crashes qualcomm's compiler
- ANKI_VK_LOGI("Enabling workaround for vkCreateGraphicsPipeline crashing when called from multiple threads");
- m_globalCreatePipelineMtx = anki::newInstance<Mutex>(GrMemoryPool::getSingleton());
- }
- #endif
- return Error::kNone;
- }
- void PipelineCache::destroy()
- {
- const Error err = destroyInternal();
- if(err)
- {
- ANKI_VK_LOGE("An error occurred while storing the pipeline cache to disk. Will ignore");
- }
- m_dumpFilename.destroy();
- }
- Error PipelineCache::destroyInternal()
- {
- #if ANKI_PLATFORM_MOBILE
- deleteInstance(GrMemoryPool::getSingleton(), m_globalCreatePipelineMtx);
- #endif
- if(m_cacheHandle)
- {
- // Get size of cache
- size_t size = 0;
- ANKI_VK_CHECK(vkGetPipelineCacheData(getVkDevice(), m_cacheHandle, &size, nullptr));
- size = min(size, m_dumpSize);
- if(size > 0)
- {
- // Read cache
- GrDynamicArray<U8, PtrSize> cacheData;
- cacheData.resize(size);
- ANKI_VK_CHECK(vkGetPipelineCacheData(getVkDevice(), m_cacheHandle, &size, &cacheData[0]));
- // Write file
- File file;
- ANKI_CHECK(file.open(&m_dumpFilename[0], FileOpenFlag::kBinary | FileOpenFlag::kWrite));
- VkPhysicalDeviceProperties props;
- vkGetPhysicalDeviceProperties(getGrManagerImpl().getPhysicalDevice(), &props);
- ANKI_CHECK(file.write(&props.pipelineCacheUUID[0], VK_UUID_SIZE));
- ANKI_CHECK(file.write(&cacheData[0], size));
- ANKI_VK_LOGI("Dumped %zu bytes of the pipeline cache", size);
- }
- // Destroy cache
- vkDestroyPipelineCache(getVkDevice(), m_cacheHandle, nullptr);
- m_cacheHandle = VK_NULL_HANDLE;
- }
- return Error::kNone;
- }
- } // end namespace anki
|