最近碰到个伪需求: 游戏串流。 游戏引擎用D3D12渲染, 再把游戏画面做视频编码, 通过网络发送到远端做解码显示。

第一反应就是走全GPU的流程, 不要用CPU把显存里的数据拷来拷去。 所以先获取渲染完的D3D12的frame buffer, 然后送给Intel MediaSDK去做编码。 查了一下MediaSDK文档, 只支持D3D11的输入buffer, 需要想办法把D3D12 Resource转换成D3D11 Texture2D。 可以试试D3D11/D3D12的Texture2D资源共享。查了一下网上的讨论的帖子 Sharing ID3D11Buffer and ID3D12Resource,微软自家的DirectX不同版本间可以用CreateSharedHandle/OpenSharedResource来互相访问。

DX12我不熟,先找个最简单的DX12 Texture的例子。我选了微软官方的例子 https://github.com/microsoft/DirectX-Graphics-Samples/tree/master/Samples/Desktop/D3D12HelloWorld/src/HelloTexture

有关的Texture2D的初始化代码在这里,m_texture就是一块黑白棋盘格样式的Texture2D,所有的初始化和像素填充都是基于D3D12的API来完成。 然后在主循环里在WM_PAINT消息OnRender()函数里把m_texture贴到一个三角形上并显示

//创建m_texture, 一块256x256 R8G8B8A8的texture2D的资源, GPU访问// Describe and create a Texture2D.D3D12_RESOURCE_DESC textureDesc = {};textureDesc.MipLevels = 1;textureDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;textureDesc.Width = TextureWidth;textureDesc.Height = TextureHeight;textureDesc.Flags = D3D12_RESOURCE_FLAG_NONE;textureDesc.DepthOrArraySize = 1;textureDesc.SampleDesc.Count = 1;textureDesc.SampleDesc.Quality = 0;textureDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;ThrowIfFailed(m_device->CreateCommittedResource(&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT),D3D12_HEAP_FLAG_NONE,&textureDesc,D3D12_RESOURCE_STATE_COPY_DEST,nullptr,IID_PPV_ARGS(&m_texture)));const UINT64 uploadBufferSize = GetRequiredIntermediateSize(m_texture.Get(), 0, 1);//创建textureUploadHeap, 一块CPU可以读写的staging buffer// Create the GPU upload buffer.ThrowIfFailed(m_device->CreateCommittedResource(&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD),D3D12_HEAP_FLAG_NONE,&CD3DX12_RESOURCE_DESC::Buffer(uploadBufferSize),D3D12_RESOURCE_STATE_GENERIC_READ,nullptr,IID_PPV_ARGS(&textureUploadHeap)));//生成一块黑白相间的棋盘格样式的图像// Copy data to the intermediate upload heap and then schedule a copy // from the upload heap to the Texture2D.std::vector<UINT8> texture = GenerateTextureData();D3D12_SUBRESOURCE_DATA textureData = {};textureData.pData = &texture[0];textureData.RowPitch = TextureWidth * TexturePixelSize;textureData.SlicePitch = textureData.RowPitch * TextureHeight;//将棋盘格式的图像填充进textureUploadHeap里,再拷贝进m_texture内UpdateSubresources(m_commandList.Get(), m_texture.Get(), textureUploadHeap.Get(), 0, 0, 1, &textureData);m_commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_texture.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE));

运行的输出, 可以看到三角形上贴的纹理是黑白棋盘格

接下来要做的是按照Sharing ID3D11Buffer and ID3D12Resource的流程在m_texture初始化后做一个和D3D11 Texture2D的共享,并且通过D3D11的API函数修改这个m_texture的像素纹理

1. 修改创建mtexture的参数,设为可共享

  • 这里需要修改D3D12_RESOURCE_DESC的Flags属性为D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET | D3D12_RESOURCE_FLAG_ALLOW_SIMULTANEOUS_ACCESS
  • 同时ID3D12Device::CreateCommittedResource()的HeapFlags参数设为D3D12_HEAP_FLAG_SHARED
     // Describe and create a Texture2D.D3D12_RESOURCE_DESC textureDesc = {};textureDesc.MipLevels = 1;textureDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;textureDesc.Width = TextureWidth;textureDesc.Height = TextureHeight;textureDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET | D3D12_RESOURCE_FLAG_ALLOW_SIMULTANEOUS_ACCESS;textureDesc.DepthOrArraySize = 1;textureDesc.SampleDesc.Count = 1;textureDesc.SampleDesc.Quality = 0;textureDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;ThrowIfFailed(m_device->CreateCommittedResource(&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT),D3D12_HEAP_FLAG_SHARED,&textureDesc,D3D12_RESOURCE_STATE_COPY_DEST, // D3D12_RESOURCE_STATE_COPY_DEST,nullptr,IID_PPV_ARGS(&m_texture)));

2. 为m_texture创建一个共享句柄m_sharedTextureHandle

     HRESULT hr;HANDLE m_sharedTextureHandle;ThrowIfFailed(hr = m_device->CreateSharedHandle(m_texture.Get(),nullptr,GENERIC_ALL,nullptr,&m_sharedTextureHandle));

3. 创建一个新的d3d11 device和context,

     static D3D_FEATURE_LEVEL FeatureLevels[] = {D3D_FEATURE_LEVEL_11_1,D3D_FEATURE_LEVEL_11_0,D3D_FEATURE_LEVEL_10_1,D3D_FEATURE_LEVEL_10_0};IDXGIFactory2* DxgiFactory;IDXGIAdapter* DxgiAdapter;DXGI_ADAPTER_DESC DxgiAdapterDesc;ID3D11Texture2D* Texture;ID3D11Device* D3d11Device;D3D_FEATURE_LEVEL FeatureLevel;ID3D11DeviceContext* D3d11DeviceContext;hr = CreateDXGIFactory2(0, IID_PPV_ARGS(&DxgiFactory));hr = DxgiFactory->EnumAdapters(0, &DxgiAdapter);hr = DxgiAdapter->GetDesc(&DxgiAdapterDesc);hr = D3D11CreateDevice(DxgiAdapter, D3D_DRIVER_TYPE_UNKNOWN, nullptr, D3D11_CREATE_DEVICE_DEBUG, FeatureLevels, 4, D3D11_SDK_VERSION, &D3d11Device, &FeatureLevel, &D3d11DeviceContext);

创建一个和m_texture一样大小的D3D11 Texture2D对象,填充成灰红蓝绿色,等下用ID3D11DeviceContext::CopyResource()来覆盖d3d12的m_texture,用来验证共享的texture2D资源是否成功

//这里需要创建一个和DX12纹理资源相同尺寸的Texture2D
//图省事,没有提取前面DX12的纹理资源的尺寸,直接定义个相同的尺寸
#define SHARED_TEXTURE_WIDTH   256
#define SHARED_TEXTURE_HEIGHT  256CD3D11_TEXTURE2D_DESC TextureDesc(DXGI_FORMAT_R8G8B8A8_UNORM, SHARED_TEXTURE_WIDTH, SHARED_TEXTURE_HEIGHT, 1, 1);//TextureDesc.MiscFlags = D3D11_RESOURCE_MISC_SHARED | D3D11_RESOURCE_MISC_SHARED_NTHANDLE;unsigned long texture_data_1[SHARED_TEXTURE_WIDTH * SHARED_TEXTURE_HEIGHT];D3D11_SUBRESOURCE_DATA Data = {};//将texture的左上,右上,左下,右下分别填充成灰红绿蓝for (int i = 0; i < SHARED_TEXTURE_HEIGHT; i++){for (int j = 0; j < SHARED_TEXTURE_WIDTH; j++){if (i >= SHARED_TEXTURE_HEIGHT / 2){if (j >= SHARED_TEXTURE_WIDTH / 2){texture_data_1[i * SHARED_TEXTURE_WIDTH + j] = 0xFF00FF00;      //G Formet:0xAaBbGgRr}else{texture_data_1[i * SHARED_TEXTURE_WIDTH + j] = 0xFFFF0000;     //B}}else{if (j >= SHARED_TEXTURE_WIDTH / 2){texture_data_1[i * SHARED_TEXTURE_WIDTH + j] = 0xFF0000FF;       //R}else{texture_data_1[i * SHARED_TEXTURE_WIDTH + j] = 0xFF808080;       //Gray}}}}Data.pSysMem = texture_data_1;Data.SysMemPitch = SHARED_TEXTURE_WIDTH * sizeof(unsigned long);      //пData.SysMemSlicePitch = 0;hr = D3d11Device->CreateTexture2D(&TextureDesc, &Data, &Texture);

4. 在d3d11下用m_texture的共享句柄创建一个共享设备, 对应的是D3D11Texture2D类型的SharedTexture

     ID3D11Device1* pDevice1;hr = D3d11Device->QueryInterface(__uuidof(ID3D11Device1), (void**)&pDevice1);ComPtr<ID3D11Texture2D> SharedTexture;hr = pDevice1->OpenSharedResource1(m_sharedTextureHandle, IID_PPV_ARGS(SharedTexture.GetAddressOf()));

5. 修改SharedTexture的内容, 对应的D3D12的m_texture的内容也同步变了。

     D3d11DeviceContext->CopyResource(SharedTexture.Get(), Texture);D3d11DeviceContext->Flush();

最后运行一下修改过的程序, 可以看到三角形上的纹理变成了我们在D3D11下面创建的灰红蓝绿的纹理,看来共享成功了

搞定收工

最后老规矩,代码奉上,仅供参考

https://gitee.com/tisandman/dx12-hello-texture/tree/master

PS:

  • D3D12和D3D11下面的command queue应该是2个独立的queue, 所以操作D3D11的命令一定等D3D12的CommandList执行完了以后再执行,否则会互相影响 (我开始的时候把D3D11的所有操作放到了 D3D12 commandQueue的ExecuteCommandLists()前面了,结果所有的D3D11下的操作先执行,D3D12的操作后执行,导致对D3D11 Texture2D的所有像素改动操作都被覆盖了,查了好久代码)。话说也没有自带个靠谱的同步信号量
  • 微软自家的框架之间的共享真是好弄,毕竟是同一家的东西。
  • D3D12的编程思路一点不像以前版本的DirectX, 反倒是和前面的Vulkan的操作顺序很像...

D3D11和D3D12共享资源相关推荐

  1. Intel MediaSDK sample_decode 官方GPU解码流程学习(二) - 在双显卡机器上实现DirectX11 D3D11和OpenCL共享资源

    很久以前写过有关D3D11和OCL直接共享显存的代码, Intel MediaSDK sample_decode 官方GPU解码流程学习 - DirectX11 D3D11和OpenCL共享资源 这段 ...

  2. D3D11和Vulkan共享资源 (一)

    很久以前研究过 用NV_DX_interop扩展让D3D和OpenGL共享资源 , OpenGL在当初设计的时候电脑和操作系统还是个相对比较简单的东西,因此OpenGL API设计没有考虑到现在计算机 ...

  3. D3D11和Vulkan共享资源 (二) - 和Intel MediaSDK sample_decode 集成

    转过头再找个复杂的播放程序验证一下,还是用我比较熟悉的MediaSDK的播放程序.基本思路就是 在初始化解码输出显示的窗口的时候同时也初始化一个vulkan显示的窗口 初始化d3d11设备的时候初始化 ...

  4. Solaris下访问windows共享资源

    今在做实验过程中,发现上传软件太费时而且解压起来也繁琐,还要占用很大的空间,就在windows上创建了共享资源,在linux下使用mount挂载上来,直接解压在windows上面,用完了直接将解压的文 ...

  5. 在局域网访问_管理Windows访问凭证,快速访问局域网上的共享资源

    内部网访问其他电脑的共享资源,基本上需要输入访问对方电脑资源允许的账号和密码.在第一次的访问中选择保存凭据后,以后访问就不要输入相应的账号和密码了.但也会出现因修改相关的访问密码或者取消了访问账号的改 ...

  6. (uC/OS-II学习笔记)关于共享资源与信号量

    uC/os-ii中任务间相互通信的媒介叫做事件. 关于OS_EVENT数据结构 #if (OS_EVENT_EN) && (OS_MAX_EVENTS > 0u)typedef ...

  7. 黑马程序员Linux系统开发视频之线程共享资源与非共享资源

    线程共享资源 1.文件描述符表 2.每种信号的处理方式 3.当前工作目录 4.用户ID和组ID 5.内存地址空间(.text/.data/.bss/heap/共享库) 线程非共享资源 1.线程ID 2 ...

  8. 嵌套中断共享资源问题及解决

    文章目录 1 嵌套中断共享资源问题及解决 1 嵌套中断共享资源问题及解决 这个问题可以使用三种方式解决: 关总中断. 关指定中断. 请求模式解决嵌套中断共享资源问题. 这里采用关总中断的方式解决,代码 ...

  9. 请求模式解决共享资源冲突

    文章目录 1 请求模式解决共享资源冲突 1 请求模式解决共享资源冲突 原有方式: 我们可以对其进行改进,统一处理: 代码如下: /*** @brief tOS应用示例* @details* @auth ...

最新文章

  1. 综述 | 三大路径,一文总览知识图谱融合预训练模型的研究进展
  2. 报告 | 野蛮数据时代,企业和从业者如何应对变革焦虑?
  3. ubuntu16.04 uninstall cuda 9.0 completely and install 8.0 instead
  4. 【转】VS 安全开发生命周期(SDL)检查
  5. oracle事务处理 自动提交
  6. Vue 生命周期中 mounted( ) 和 created( ) 的区别
  7. burp爆破线程设置多少_你知道线程池创建多少线程比较合理吗?
  8. Scrapy-Item Pipeline(项目管道)
  9. 天线巴伦制作和原理_10米段的春天 | 用自制环型天线+改装SDR接收器27MHz采访实录...
  10. springcloud配置动态更新
  11. 【路径规划】基于蚁群算法求解带时间窗车辆路径问题(VRPTW)matlab代码
  12. 网页访问报错This request has been blocked; the content must be served over HTTPS.
  13. java poi设置导出的excel带下拉
  14. 树型结构总结:二叉查找树、堆、平衡树、2-3查找树、红黑树、B树、B+树
  15. 框架表示法表示台式计算机,框架表示法,frame representation,音标,读音,翻译,英文例句,英语词典...
  16. jQuery源码分析理解
  17. java frappuccino_星巴克的“十二星座代表饮品” 你是星冰乐还是特浓咖啡?
  18. vue2 项目启动一直卡在98%Starting development server...98% after emitting CopyPlugin
  19. DOS命令导出文件夹内所有文件的名称和全路径
  20. stata蒙特卡罗模拟(二)模拟中心极限定理

热门文章

  1. bind()函数介绍
  2. SAP凭证的类别和记账码
  3. omnet、sumo、veins环境搭建笔记
  4. 第九届泰迪杯A题(1)
  5. 如何安装Java JDK
  6. 这可能是全网最全的数据仓库建设方法论!
  7. 手动杀掉AUTORUN病毒.
  8. mysql悲观锁for update
  9. Linux ALSA 之六:ALSA ASoc 架构
  10. 跳槽字节跳动,十年开发经验Android架构师,灵魂拷问