D3D11和Vulkan共享资源 (一)

这篇具有很好参考价值的文章主要介绍了D3D11和Vulkan共享资源 (一)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

很久以前研究过 用NV_DX_interop扩展让D3D和OpenGL共享资源 , OpenGL在当初设计的时候电脑和操作系统还是个相对比较简单的东西,因此OpenGL API设计没有考虑到现在计算机架构的一些特性,比如多核编程和多显卡并发。最近几年出来个Vulkan来接OpenGL的班,所以继续走起研究下D3D11和Vulkan的共享。

Vulkan主程序用了vulkan tutorial下面的一个教程Combined image sampler , 这段代码演示了把一个纹理vkImage贴到一个3D的四边形面上.

D3D11和Vulkan共享资源 (一)

接下来是尝试打通一个D3D11 Texture2D和这个vkImage存放图像数据的buffer, 这样我可以通过修改Texture2D的内容来让显示的vkImage的内容也发生变化。D3D11 Texture2D和vkImage共享的代码流程主要参考自这个github VulkanSdkDemos/BindImageMemory2.cpp at d3d11-image-interop · roman380/VulkanSdkDemos · GitHub

要让vulkan和D3d11共享资源,大致需要这么五步:

  • 在include glfw头文件前,加上#define VK_USE_PLATFORM_WIN32_KHR
#define GLFW_INCLUDE_VULKAN
#define VK_USE_PLATFORM_WIN32_KHR
#include <GLFW/glfw3.h>
  • 初始化vk device的时候,多打开4个extension扩展

        VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME,

        VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME,

        VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME,

        VK_KHR_BIND_MEMORY_2_EXTENSION_NAME


const std::vector<const char*> deviceExtensions = {
    VK_KHR_SWAPCHAIN_EXTENSION_NAME,
    VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME,
    VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME,
    VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME,
    VK_KHR_BIND_MEMORY_2_EXTENSION_NAME
};

...

createInfo.enabledExtensionCount = static_cast<uint32_t>(deviceExtensions.size());
createInfo.ppEnabledExtensionNames = deviceExtensions.data();

if (vkCreateDevice(physicalDevice, &createInfo, nullptr, &device) != VK_SUCCESS) {
        throw std::runtime_error("failed to create logical device!");
}
  •  创建vkImage对象的时候, VkExternalMemoryImageCreateInfo要声明使用外部的内存对象VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT

        /* add for DX11/vulkan interop*/
        VkPhysicalDeviceExternalImageFormatInfo PhysicalDeviceExternalImageFormatInfo = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO };
        PhysicalDeviceExternalImageFormatInfo.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT;
        VkPhysicalDeviceImageFormatInfo2 PhysicalDeviceImageFormatInfo2 = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2 };
        PhysicalDeviceImageFormatInfo2.pNext = &PhysicalDeviceExternalImageFormatInfo;
        PhysicalDeviceImageFormatInfo2.format = VK_FORMAT_R8G8B8A8_UNORM;
        PhysicalDeviceImageFormatInfo2.type = VK_IMAGE_TYPE_2D;
        PhysicalDeviceImageFormatInfo2.tiling = VK_IMAGE_TILING_OPTIMAL;
        PhysicalDeviceImageFormatInfo2.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT;
        VkExternalImageFormatProperties ExternalImageFormatProperties = { VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES };
        VkImageFormatProperties2 ImageFormatProperties2 = { VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2 };
        ImageFormatProperties2.pNext = &ExternalImageFormatProperties;

        if (vkGetPhysicalDeviceImageFormatProperties2(physicalDevice, &PhysicalDeviceImageFormatInfo2, &ImageFormatProperties2) != VK_SUCCESS) {
            throw std::runtime_error("failed to vkGetPhysicalDeviceImageFormatProperties2!");
        }
        assert(ExternalImageFormatProperties.externalMemoryProperties.externalMemoryFeatures & VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT);
        assert(ExternalImageFormatProperties.externalMemoryProperties.externalMemoryFeatures & VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT);
        assert(ExternalImageFormatProperties.externalMemoryProperties.compatibleHandleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT);
        /*******************************/

        VkExternalMemoryImageCreateInfo ExternalMemoryImageCreateInfo = { VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO };
        ExternalMemoryImageCreateInfo.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT;

        VkImageCreateInfo imageInfo{};

        imageInfo.pNext = &ExternalMemoryImageCreateInfo;

        imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
        imageInfo.imageType = VK_IMAGE_TYPE_2D;
        imageInfo.extent.width = width;
        imageInfo.extent.height = height;
        imageInfo.extent.depth = 1;
        imageInfo.mipLevels = 1;
        imageInfo.arrayLayers = 1;
        imageInfo.format = format;
        imageInfo.tiling = tiling;
        imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
        imageInfo.usage = usage;
        imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
        imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;

        if (vkCreateImage(device, &imageInfo, nullptr, &image) != VK_SUCCESS) {
            throw std::runtime_error("failed to create image!");
        }
  • 创建D3D11Texture2D时, MiscFlags要包含 D3D11_RESOURCE_MISC_SHARED_NTHANDLE以及D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX 或D3D11_RESOURCE_MISC_SHARED
CD3D11_TEXTURE2D_DESC TextureDesc(DXGI_FORMAT_R8G8B8A8_UNORM, imageInfo.extent.width, imageInfo.extent.height, 1, 1);
#ifdef USE_KEYEDMUTEX
        TextureDesc.MiscFlags = D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX | D3D11_RESOURCE_MISC_SHARED_NTHANDLE;
#else
        TextureDesc.MiscFlags = D3D11_RESOURCE_MISC_SHARED | D3D11_RESOURCE_MISC_SHARED_NTHANDLE;
#endif
        

        VERIFY(SUCCEEDED(D3d11Device->CreateTexture2D(&TextureDesc, &Data, &Texture)));
  • 最后把D3D11Texture2D的NTHandle传给vkAllocateMemory,这样AllocateMemory就会复用这个Texture2D的memory, 然后vkBindImageMemory给vkImage
        VERIFY(SUCCEEDED(Texture->QueryInterface(&DxgiResource1)));
        VERIFY(SUCCEEDED(DxgiResource1->CreateSharedHandle(nullptr, GENERIC_ALL, nullptr, &Handle)));

        VkMemoryDedicatedAllocateInfo MemoryDedicatedAllocateInfo = { VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO };
        MemoryDedicatedAllocateInfo.image = image;
        VkImportMemoryWin32HandleInfoKHR ImportMemoryWin32HandleInfo = { VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR };
        ImportMemoryWin32HandleInfo.pNext = &MemoryDedicatedAllocateInfo;
        ImportMemoryWin32HandleInfo.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT;
        ImportMemoryWin32HandleInfo.handle = Handle;
        VkMemoryAllocateInfo MemoryAllocateInfo = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO };
        MemoryAllocateInfo.pNext = &ImportMemoryWin32HandleInfo;
        MemoryAllocateInfo.allocationSize = MemoryRequirements.size;
        // WARN: MemoryAllocateInfo.memoryTypeIndex remains zero
        VkDeviceMemory ImageMemory;
        VERIFY(vkAllocateMemory(device, &MemoryAllocateInfo, nullptr, &ImageMemory) == VK_SUCCESS);
        VkBindImageMemoryInfo BindImageMemoryInfo = { VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO };
        BindImageMemoryInfo.image = image;
        BindImageMemoryInfo.memory = ImageMemory;
        VERIFY(vkBindImageMemory2(device, 1, &BindImageMemoryInfo) == VK_SUCCESS);

这样这个vkImage里面存放像素的那块内存其实就是D3D11Texture2D里存放像素的那个内存区了。接下来只要用D3D11的API对这个Texture2D的像素做改动,vkImage的像素也会相应变化。

代码里有个编译参数

#define USE_KEYEDMUTEX
分别对应创建D3D11 texture2D时候的MiscFlags包含D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX或者D3D11_RESOURCE_MISC_SHARED的情况

主要区别是

  • 用D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX创建的Texture2D是自带一个mutex锁的,可能是用来同步d3d11多线程之间不要同时访问这块Texture2D/vkImage内存用的。
  • D3D11_RESOURCE_MISC_SHARED创建的Texture2D资源没有互斥锁的限制,所有线程可以随时随地的访问。

总的来说,粗粗的学习了一下vkImage部分,没有发现什么官方建议的API用来防止D3D11和Vulkan之间同时访问共享资源导致数据完整性错误的机制。所以真正设计程序的时候,可能需要借用windows自己的mutex机制来保证这块。

PS: 这段原始参考代码是有坑的, 简单的说代码的原作者在注释里提到了一个问题,就是这段代码如果在vulkan初始化的时候打开了validation layer, 在后面获取vkImage所需存放像素的buffer大小 vkGetImageMemoryRequirements2()的时候就会出现memory access violation的错误。这段代码是他为了复现问题专门写的,他当时是在AMD的显卡上发现的,我这边用Intel显卡也有一样的问题。我也没搞懂导致这个问题的原因是什么,可能是vulkan库里面的某段代码或者显卡驱动里有错误吧 (当时没看懂代码里作者的注释,后来费了好大劲调试找问题无果,最后发现代码用release模式就能跑,最后定位在了debug模式编译时打开了validation layer) 这个还希望有明白的大佬能指点一下...

最后验证一下,在主循环里,每循环30帧就给Texture2D对象刷一个纯色(红,黄,蓝),这段代码因为没有D3D11的显示部分,而CopyResource()是一个异步操作,函数返回的时候相关的copy命令序列并不一定会进入GPU的command queue并且运行完毕,所以窗口里的贴图的颜色变化会有很明显的延迟 (有些D3D11相关的函数会自动做Flush GPU Command Queue的操作,比如Map()/UnMap(), Present()之类)。因此需要在每次做完CopyResource()以后调用Flush()一下,把拷贝命令刷进GPU的Command Queue里,这样延迟就不是很明显了。

    void mainLoop() {
        unsigned long frame_counter = 0;
        while (!glfwWindowShouldClose(window)) {
            glfwPollEvents();
            drawFrame();
#if 1
            frame_counter++;
            if ((frame_counter % 90 )==0)
            {
#ifdef USE_KEYEDMUTEX
                Texture_Mutex->AcquireSync(1, INFINITE);
                Texture_R_Mutex->AcquireSync(1, INFINITE);
#endif
                //texture刷红色
                D3d11DeviceContext->CopyResource(Texture, Texture_R);
                std::cout << "D3d11DeviceContext->CopyResource(Texture, Texture_R); : " << frame_counter << std::endl;
                D3d11DeviceContext->Flush();
#ifdef USE_KEYEDMUTEX
                Texture_Mutex->ReleaseSync(1);
                Texture_R_Mutex->ReleaseSync(1);
#endif

            }
            else if ((frame_counter % 60) == 0)
            {
#ifdef USE_KEYEDMUTEX
                Texture_Mutex->AcquireSync(1, INFINITE);
                Texture_G_Mutex->AcquireSync(1, INFINITE);
#endif
                //texture刷绿色
                D3d11DeviceContext->CopyResource(Texture, Texture_G);
                std::cout << "D3d11DeviceContext->CopyResource(Texture, Texture_G); : " << frame_counter << std::endl;
                D3d11DeviceContext->Flush();
#ifdef USE_KEYEDMUTEX
                Texture_Mutex->ReleaseSync(1);
                Texture_G_Mutex->ReleaseSync(1);
#endif
            }
            else if ((frame_counter % 30) == 0)
            {
#ifdef USE_KEYEDMUTEX
                Texture_Mutex->AcquireSync(1, INFINITE);
                Texture_B_Mutex->AcquireSync(1, INFINITE);
#endif
                //texture刷蓝色
                D3d11DeviceContext->CopyResource(Texture, Texture_B);
                std::cout << "D3d11DeviceContext->CopyResource(Texture, Texture_B); : " << frame_counter << std::endl;
                D3d11DeviceContext->Flush();
#ifdef USE_KEYEDMUTEX
                Texture_Mutex->ReleaseSync(1);
                Texture_G_Mutex->ReleaseSync(1);
#endif
            }
#endif
        }

        vkDeviceWaitIdle(device);
    }

运行一下, 一切正常,搞定收工

D3D11和Vulkan共享资源 (一)

最后还是老规矩,源码奉上,仅供参考

https://gitee.com/tisandman/d3d11_vulkan_sharing文章来源地址https://www.toymoban.com/news/detail-412303.html

到了这里,关于D3D11和Vulkan共享资源 (一)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 缺失d3d9.dll怎么办,修复d3d9.dll的方法分享

    当您在 Windows 操作系统中启动某些游戏或应用程序时,您可能会遇到“缺失d3d9.dll”的错误提示。这个问题通常是由于系统缺失了DirectX 9的组件库,从而导致该dll文件无法正常加载。但是,您不需要担心,因为这个问题可以很容易地解决。本文将介绍一些最常见的解决方案,

    2024年02月10日
    浏览(50)
  • d3d12龙书阅读----d3d渲染流水线

    在输入装配器阶段,会从显存中读取顶点与索引这种几何数据,然后根据图形基元的类型,根据索引将顶点组装起来。 我们来看看几种常见的图形基元类型: 我们可以看到可以把图形基元设置为未定义、点、线、三角形与控制点 根据索引我们可以将顶点按照一定的顺序组装

    2024年03月16日
    浏览(40)
  • 【UE4闪退解决办法】D3D设备丢失,Unreal Engine is exiting due to D3D device being lost

    百度那些被小编到处传的,一般来说都没啥用的。我后来在贴吧老哥的楼里才翻出一个别样的解决方法。 打开英伟达的这个驱动软件,GeForce Experience  进去后,在“驱动程序”里面,点3个点打开列表,选择“studio驱动程序” 然后就是选择自定义安装(不要快速!),之后弹

    2024年02月13日
    浏览(111)
  • nodejs中的共享资源和锁

    在Node.js中,如果你使用锁来同步代码,通常是为了防止多个线程或进程同时访问共享资源,这可能导致数据不一致或其他问题。然而,Node.js本身并不是一个多线程环境,而是单线程的。因此,你通常不会在Node.js中使用锁来同步线程,而是使用锁来同步异步操作。 如果你正在

    2024年01月22日
    浏览(32)
  • 云计算资源供应模型是指云计算所提供的资源供应方式,主要包括共享型资源和专属型资源。

    作者:禅与计算机程序设计艺术 云计算是一种将大数据、机器学习等技术应用到互联网的数据中心中,向用户提供更高级的计算服务的一种服务模式。其特点之一就是利用计算机硬件、网络和软件资源池作为计算基础设施(Infrastructure as a Service, IaaS)或平台服务(Platform as

    2024年02月06日
    浏览(32)
  • HTTP 第六章 跨资源共享(CORS)

    跨源资源共享(CORS,或通俗地译为跨域资源共享)是一种基于 HTTP 头的机制,该机制通过允许服务器标示除了它自己以外的其他源(域、协议或端口),使得浏览器允许这些源访问加载自己的资源。跨源资源共享还通过一种机制来检查服务器是否会允许要发送的真实请求,该

    2024年02月22日
    浏览(32)
  • 进程和线程的区别 && 线程之间共享的资源

    线程和进程都是操作系统中的执行单位,但它们在以下几个方面存在区别: 1.执行环境:线程和进程都有自己的执行上下文,包括程序计数器、寄存器和栈,可以独立执行指令。 2.并发性:线程和进程都可以实现并发执行,提高系统资源利用率。 3.调度:线程和进程都需要操

    2024年02月07日
    浏览(32)
  • 【开源】基于JAVA的教学资源共享平台

    基于JAVA+Vue+SpringBoot+MySQL的教学资源共享平台,包含了课程管理、课程课件、授课中心、作业发布、课程评价、课程质量分析、交流互动模块,还包含系统自带的用户管理、部门管理、角色管理、菜单管理、日志管理、数据字典管理、文件管理、图表展示等基础模块,教学资源

    2024年01月19日
    浏览(45)
  • 【开源】基于JAVA语言的教学资源共享平台

    基于JAVA+Vue+SpringBoot+MySQL的教学资源共享平台,包含了课程管理、课程课件、授课中心、作业发布、课程评价、课程质量分析、交流互动模块,还包含系统自带的用户管理、部门管理、角色管理、菜单管理、日志管理、数据字典管理、文件管理、图表展示等基础模块,教学资源

    2024年01月20日
    浏览(41)
  • CORS(跨域资源共享)源验证失败解决方法

    在web系统中,安全软件扫描经常会发现CORS(跨域资源共享)作为高危漏洞出现。本文提供用Nginx作为反向代理的解决方案。解决方式是在nginx.conf文件中做如下配置: 注意: 1、“xxxx.com\\\"是示例域名,按你实际用到的更改。如果有多个外部域名,则逐一按if方式处理。不建议用

    2024年02月15日
    浏览(34)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包