很久以前研究过 用NV_DX_interop扩展让D3D和OpenGL共享资源 , OpenGL在当初设计的时候电脑和操作系统还是个相对比较简单的东西,因此OpenGL API设计没有考虑到现在计算机架构的一些特性,比如多核编程和多显卡并发。最近几年出来个Vulkan来接OpenGL的班,所以继续走起研究下D3D11和Vulkan的共享。
Vulkan主程序用了vulkan tutorial下面的一个教程Combined image sampler , 这段代码演示了把一个纹理vkImage贴到一个3D的四边形面上.

接下来是尝试打通一个D3D11 Texture2D和这个vkImage存放图像数据的buffer, 这样我可以通过修改Texture2D的内容来让显示的vkImage的内容也发生变化。D3D11 Texture2D和vkImage共享的代码流程主要参考自这个github VulkanSdkDemos/BindImageMemory2.cpp at d3d11-image-interop · roman380/VulkanSdkDemos · GitHub
要让vulkan和D3d11共享资源,大致需要这么五步:
#define GLFW_INCLUDE_VULKAN
#define VK_USE_PLATFORM_WIN32_KHR
#include <GLFW/glfw3.h>
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!");
}
/* 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!");
}
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)));
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的情况
主要区别是
总的来说,粗粗的学习了一下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);
}
运行一下, 一切正常,搞定收工

最后还是老规矩,源码奉上,仅供参考
https://gitee.com/tisandman/d3d11_vulkan_sharing
我正在编写一个gem,我必须在其中fork两个启动两个webrick服务器的进程。我想通过基类的类方法启动这个服务器,因为应该只有这两个服务器在运行,而不是多个。在运行时,我想调用这两个服务器上的一些方法来更改变量。我的问题是,我无法通过基类的类方法访问fork的实例变量。此外,我不能在我的基类中使用线程,因为在幕后我正在使用另一个不是线程安全的库。所以我必须将每个服务器派生到它自己的进程。我用类变量试过了,比如@@server。但是当我试图通过基类访问这个变量时,它是nil。我读到在Ruby中不可能在分支之间共享类变量,对吗?那么,还有其他解决办法吗?我考虑过使用单例,但我不确定这是
当我尝试安装Ruby时遇到此错误。我试过查看this和this但无济于事➜~brewinstallrubyWarning:YouareusingOSX10.12.Wedonotprovidesupportforthispre-releaseversion.Youmayencounterbuildfailuresorotherbreakages.Pleasecreatepull-requestsinsteadoffilingissues.==>Installingdependenciesforruby:readline,libyaml,makedepend==>Installingrub
我真的为这个而疯狂。我一直在搜索答案并尝试我找到的所有内容,包括相关问题和stackoverflow上的答案,但仍然无法正常工作。我正在使用嵌套资源,但无法使表单正常工作。我总是遇到错误,例如没有路线匹配[PUT]"/galleries/1/photos"表格在这里:/galleries/1/photos/1/edit路线.rbresources:galleriesdoresources:photosendresources:galleriesresources:photos照片Controller.rbdefnew@gallery=Gallery.find(params[:galle
无论您是想搭建桌面端、WEB端或者移动端APP应用,HOOPSPlatform组件都可以为您提供弹性的3D集成架构,同时,由工业领域3D技术专家组成的HOOPS技术团队也能为您提供技术支持服务。如果您的客户期望有一种在多个平台(桌面/WEB/APP,而且某些客户端是“瘦”客户端)快速、方便地将数据接入到3D应用系统的解决方案,并且当访问数据时,在各个平台上的性能和用户体验保持一致,HOOPSPlatform将帮助您完成。利用HOOPSPlatform,您可以开发在任何环境下的3D基础应用架构。HOOPSPlatform可以帮您打造3D创新型产品,HOOPSSDK包含的技术有:快速且准确的CAD
本教程将在Unity3D中混合Optitrack与数据手套的数据流,在人体运动的基础上,添加双手手指部分的运动。双手手背的角度仍由Optitrack提供,数据手套提供双手手指的角度。 01 客户端软件分别安装MotiveBody与MotionVenus并校准人体与数据手套。MotiveBodyMotionVenus数据手套使用、校准流程参照:https://gitee.com/foheart_1/foheart-h1-data-summary.git02 数据转发打开MotiveBody软件的Streaming,开始向Unity3D广播数据;MotionVenus中设置->选项选择Unit
Unity自动旋转动画1.开门需要门把手先动,门再动2.关门需要门先动,门把手再动3.中途播放过程中不可以再次进行操作觉得太复杂?查看我的文章开关门简易进阶版效果:如果这个门可以直接打开的话,就不需要放置"门把手"如果门把手还有钥匙需要旋转,那就可以把钥匙放在门把手的"门把手",理论上是可以无限套娃的可调整参数有:角度,反向,轴向,速度运行时点击Test进行测试自己写的代码比较垃圾,命名与结构比较拉,高手轻点喷,新手有类似的需求可以拿去做参考上代码usingSystem.Collections;usingSystem.Collections.Generic;usingUnityEngine;u
之前说过10之后的版本没有3dScan了,所以还是9.8的版本或者之前更早的版本。 3d物体扫描需要先下载扫描的APK进行扫面。首先要在手机上装一个扫描程序,扫描现实中的三维物体,然后上传高通官网,在下载成UnityPackage类型让Unity能够使用这个扫描程序可以从高通官网上进行下载,是一个安卓程序。点到Tools往下滑,找到VuforiaObjectScanner下载后解压数据线连接手机,将apk文件拷入手机安装然后刚才解压文件中的Media文件夹打开,两个PDF图打印第一张A4-ObjectScanningTarget.pdf,主要是用来辅助扫描的。好了,接下来就是扫描三维物体。将瓶
运行bundleinstall后出现此错误:Gem::Package::FormatError:nometadatafoundin/Users/jeanosorio/.rvm/gems/ruby-1.9.3-p286/cache/libv8-3.11.8.13-x86_64-darwin-12.gemAnerroroccurredwhileinstallinglibv8(3.11.8.13),andBundlercannotcontinue.Makesurethat`geminstalllibv8-v'3.11.8.13'`succeedsbeforebundling.我试试gemin
我正在尝试将一个资源属性的默认值设置为另一个属性的值。我正在为我正在构建的tomcat说明书定义一个资源,其中包含以下定义。我想要可以独立设置的“名称”和“服务名称”属性。当未设置服务名称时,我希望它默认为为“名称”提供的任何内容。以下不符合我的预期:attribute:name,:kind_of=>String,:required=>true,:name_attribute=>trueattribute:service_name,:kind_of=>String,:default=>:name注意第二行末尾的“:default=>:name”。当我在Recipe的新block中引用我
在许多ruby类之间共享记录器实例的最佳(正确)方法是什么?现在我只是将记录器创建为全局$logger=Logger.new变量,但我觉得有更好的方法可以在不使用全局变量的情况下执行此操作。如果我有以下内容:moduleFooclassAclassBclassC...classZend在所有类之间共享记录器实例的最佳方式是什么?我是以某种方式在Foo模块中声明/创建记录器还是只是使用全局$logger没问题? 最佳答案 在模块中添加常量:moduleFooLogger=Logger.newclassAclassBclassC..