D3D11和D3D12共享资源

news2024/11/24 19:26:37

最近碰到个伪需求: 游戏串流。 游戏引擎用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  256

		CD3D11_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的操作顺序很像...

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/426171.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

进程管理 - 银行家算法

文章目录1 概述2 银行家算法2.1 原理2.2 例题1 概述 #mermaid-svg-7QKAqjQpckpStO9Q {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-7QKAqjQpckpStO9Q .error-icon{fill:#552222;}#mermaid-svg-7QKAqjQpckpStO9Q .e…

android framework-PackageManagerService(PKMS)包管理服务

一、概述 Android系统启动过程中&#xff0c;会启动一个包管理服务PackageManagerService(PKMS)&#xff0c;这个服务主要负责扫描系统中指定目录&#xff0c;找出里面以apk结尾的文件&#xff0c;通过对这些文件进行解析&#xff0c;得到应用程序的所有信息并完成应用程序的安…

算法学习day59

算法学习day591.力扣503.下一个更大元素II1.1 题目描述1.2 分析1.3代码2.力扣42. 接雨水2.1 题目描述2.2 分析2.3 代码3.参考资料1.力扣503.下一个更大元素II 1.1 题目描述 题目描述&#xff1a; 给定一个循环数组&#xff08;最后一个元素的下一个元素是数组的第一个元素&a…

【大数据Hadoop】HDFS3.3.1-Namenode-租约管理

租约管理前言LeaseManager.LeaseLeaseManager添加租约 - addLease租约检查 - FsNamesystem.checkLease租约更新 - renewLease删除租约 - removeLease租约检查 - Monitor 线程租约恢复 - Monitor 线程发起租约恢复 - 其他方式发起前言 我们知道 HDFS 文件是 write-once-read-man…

CloudCompare插件开发之点云如何创建、保存并显示?

文章目录0.引言1.创建插件工程2.代码编写3.显示点云4.保存点云0.引言 CloudCompaer是一款优秀的开源软件&#xff0c;在点云处理时可以根据实际要求开发合适的插件&#xff0c;在实际使用中&#xff0c;创建点云、保存点云、显示点云的操作较为基础&#xff0c;为了使这些操作得…

施工组织设计合集

34-6 施工组织设计02017-年亲曼旗大镇市政道路及广场公园园林绿化工程(第一.A1-1五中教学楼施工组织设计A2施工组织设计(方案) 报审表hasuploaded-中建施|组织设计 (22P)安徽大包庄125万吨疏铁矿斜坡道施工组织设计 (修改)宝山万科四季花城施T组织设计 (126P)对税信息培训中心装…

软件测试,月薪还没过万的进来看

目录 前言 一、技能提升 二、多语言掌握 三、团队协作 四、持续学习 五、提高测试效率 六、质量保障 七、职业发展 八、总结 前言 在当今IT行业中&#xff0c;软件测试是一个不可或缺的环节。随着互联网和移动应用的发展&#xff0c;对软件质量的要求也越来越高。因此…

前后端分离架构

前后端分离架构介绍 前后端分离已成为互联网项目开发的业界标准使用方式&#xff0c;将前端和后端的开发进行解耦。并且前后端分离会为以后的大型分布式架构、微服务架构、多端化服务&#xff08;各种客户端&#xff0c;比如浏览器、车载终端、安卓、IOS等&#xff09;打下坚实…

[Netty] FastThreadLocal (十四)

文章目录1.FastThreadLocal介绍2.FastThreadLocal分析3.FastThreadLocal结构分析4.FastThreadLocal方法分析4.1 FastThreadLocal.get()4.2 FastThreadLocal.set()1.FastThreadLocal介绍 FastThreadLocal是Netty中常用的一个工具类, FastThreadLocal所使用的InternalThreadLoca…

[架构之路-159]-《软考-系统分析师》-10-系统分析-6-现有业务流程分析, 系统分析最核心的任务

目录 第 10章 现有系统 分 析 1 0 . 6 现有业务流程分析 10.6.1 业务流程分析槪述 1 . 业务流程分析的步骤 2 . 业务流程分析的方法 10.6.2 业务-流程图TFD 1. T F D 的基本符号 2. TFD的绘制 10.6.3 业务 - 活动图 10.6.4 业务流程建模BPM 1. B P M 概述 2 . 标杆…

Pytest自动化测试框架一些常见的插件

Pytest拥有丰富的插件架构&#xff0c;超过800个以上的外部插件和活跃的社区&#xff0c;在PyPI项目中以“ pytest- *”为标识。 本篇将列举github标星超过两百的一些插件进行实战演示。 插件库地址&#xff1a;http://plugincompat.herokuapp.com/ 1、pytest-html&#xff1…

python机器学习决策树和SVM向量机算法实现红酒分类

1、红酒数据介绍 经典的红酒分类数据集是指UCI机器学习库中的Wine数据集。该数据集包含178个样本&#xff0c;每个样本有13个特征&#xff0c;可以用于分类任务。 具体每个字段的含义如下&#xff1a; alcohol&#xff1a;酒精含量百分比 malic_acid&#xff1a;苹果酸含量&a…

中科大ChatGPT学术镜像小白部署教程,全民都可以拥抱AI

docker…不会用…python不会用…服务器默认python版本3.6不会升级…代理也不会配置…各种命令不会用… 那么下面就是最简单办法&#xff0c;点点点即可【希望有帮助&#xff1f;】 文章目录一、体验镜像地址二、 基本配置2.1 config.py文件2.2 main.py文件三、下载项目四、项目…

FRP内网穿透配置

FRP内网穿透&#xff08;WIN&#xff09; 官方文档&#xff1a;点击进入 1.下载地址&#xff1a;点击进入 2.linux 压缩命令&#xff1a;tar -zxvf 包名&#xff0c;即可&#xff01; 3.linux配置服务端&#xff08;frps&#xff09; [common] bind_addr0.0.0.0 # frp监听的…

【NLP实战】基于Bert和双向LSTM的情感分类【下篇】

文章目录前言简介第一部分关于pytorch lightning保存模型的机制关于如何读取保存好的模型完善测试代码第二部分第一次训练出的模型的过拟合问题如何解决过拟合后记前言 本文涉及的代码全由博主自己完成&#xff0c;可以随意拿去做参考。如对代码有不懂的地方请联系博主。 博主…

TCP协议与UDP协议

1.TCP协议特点 1.1连接的建立与断开 TCP协议提供的是&#xff1a;面向连接、可靠的、字节流服务。使用TCP协议通信的双发必须先建立连接&#xff0c;然后才能开始数据的读写。双方都必须为该连接分配必要的内核资源&#xff0c;以管理连接的状态和连接上数据的传输。TCP连接是全…

从C语言到C++(第一章_C++入门_下篇)内联函数+auto关键字(C++11)+范围for +nullptr

目录 1. 内联函数 1.1 内联函数的概念 1.2 内联函数的特性 1.3 宏的优缺点和替代方法 2. auto关键字&#xff08;C11&#xff09; 2.1 改版前的auto 2.2 改版后的auto 2.3 auto 的使用场景 2.3.1处理很长的数据类型 2.3.2 auto 与指针结合起来使用&#xff1a; 2.4…

第2章 数据的类型

第2章 数据的类型 文章目录第2章 数据的类型2.2 为什么要进行区分2.3 结构化数据和非结构化数据案例&#xff1a;数据预处理字数/短语数特殊符号文本相对长度文本主题2.4 定量数据和定性数据2.4.1 案例&#xff1a;咖啡店数据2.4.2 案例&#xff1a;世界酒精消费量2.4.3 更深入…

4.18、TCP滑动窗口

4.18、TCP滑动窗口1.滑动窗口的介绍2.滑动窗口通信的例子1.滑动窗口的介绍 滑动窗口&#xff08;Sliding window&#xff09;是一种流量控制技术。早期的网络通信中&#xff0c;通信双方不会考虑网络的拥挤情况直接发送数据。由于大家不知道网络拥塞状况&#xff0c;同时发送数…

客户案例 | 迎接智能化浪潮,传统水厂数字化势在必行

关键发现 客户痛点&#xff1a;传统水厂业务离散&#xff0c;无法实现数据实时同步&#xff0c;为收集和分析处理数据并辅助决策带来障碍。需要智能化管理系统帮助水厂提升管理效率&#xff0c;优化管理流程&#xff0c;实现数字化、智能化的目标。 解决方案&#xff1a;天津腾…