🌋

Vulkan.hppで関数ポインタを設定したはずなのに何故か関数呼び出しでエラーが起きる

に公開

エラー

こんな感じのエラーが出てきた(本質的にはvkCmdPipelineBarrier以外でも起きえる)

Assertion failed: d.vkCmdPipelineBarrier && "Function <vkCmdPipelineBarrier> requires <VK_VERSION_1_0>", file C:\VulkanSDK\1.4.304.1\Include\vulkan\vulkan_funcs.hpp, line 5662

結論

引数が一つ多い(Dispatchを上書きしてしまっている)

        // NG
        m_commandBuffer->pipelineBarrier(
			srcStage,
			dstStage,
			vk::DependencyFlagBits(0),
			{},
			{},
			{ imageMemoryBarrier },
			{}
		);

        // OK
        m_commandBuffer->pipelineBarrier(
			srcStage,
			dstStage,
			vk::DependencyFlagBits(0),
			{},
			{},
			{ imageMemoryBarrier }
		);

なぜ起きるのか

Vulkan.hppではDispatchという関数ポインタを保持しているものを通して、APIの関数を呼び出している。

実際、Pipeline Barrierの関数を見ると最後の引数はDispatchを指定するとこになっており、内部処理はそのDispatchを呼び出すようになっている。

  template <typename Dispatch>
  VULKAN_HPP_INLINE void
    CommandBuffer::pipelineBarrier( VULKAN_HPP_NAMESPACE::PipelineStageFlags                                                  srcStageMask,
                                    VULKAN_HPP_NAMESPACE::PipelineStageFlags                                                  dstStageMask,
                                    VULKAN_HPP_NAMESPACE::DependencyFlags                                                     dependencyFlags,
                                    VULKAN_HPP_NAMESPACE::ArrayProxy<const VULKAN_HPP_NAMESPACE::MemoryBarrier> const &       memoryBarriers,
                                    VULKAN_HPP_NAMESPACE::ArrayProxy<const VULKAN_HPP_NAMESPACE::BufferMemoryBarrier> const & bufferMemoryBarriers,
                                    VULKAN_HPP_NAMESPACE::ArrayProxy<const VULKAN_HPP_NAMESPACE::ImageMemoryBarrier> const &  imageMemoryBarriers,
                                    Dispatch const &                                                                          d ) const VULKAN_HPP_NOEXCEPT
  {
    VULKAN_HPP_ASSERT( d.getVkHeaderVersion() == VK_HEADER_VERSION );
#  if ( VULKAN_HPP_DISPATCH_LOADER_DYNAMIC == 1 )
    VULKAN_HPP_ASSERT( d.vkCmdPipelineBarrier && "Function <vkCmdPipelineBarrier> requires <VK_VERSION_1_0>" );
#  endif

    d.vkCmdPipelineBarrier( m_commandBuffer,
                            static_cast<VkPipelineStageFlags>( srcStageMask ),
                            static_cast<VkPipelineStageFlags>( dstStageMask ),
                            static_cast<VkDependencyFlags>( dependencyFlags ),
                            memoryBarriers.size(),
                            reinterpret_cast<const VkMemoryBarrier *>( memoryBarriers.data() ),
                            bufferMemoryBarriers.size(),
                            reinterpret_cast<const VkBufferMemoryBarrier *>( bufferMemoryBarriers.data() ),
                            imageMemoryBarriers.size(),
                            reinterpret_cast<const VkImageMemoryBarrier *>( imageMemoryBarriers.data() ) );
  }

Dispatchはデフォルト引数で設定しなくても動くようにはなっているが、定義的に{}で上書きすることも可能で、これはコンパイルに引っかからない。

今回のエラーは{}を指定してしまい、nullptrの関数を呼び出したことによるエラーであったわけでした。しょうもないエラーではあるが、Pipeline Barreirなど{}を指定する関数だとうっかりしかねないので気を付ける必要がある。

Discussion