如果获取不到,那就使用旧的方法枚举
// 如果枚举不到,那系统返回啥都可以for (int adapterIndex = 0;factory.EnumAdapters1(adapterIndex, out DXGI.IDXGIAdapter1? adapter).Success;adapterIndex++){DXGI.AdapterDescription1 desc = adapter.Description1;if ((desc.Flags & DXGI.AdapterFlags.Software) != DXGI.AdapterFlags.None){// Don't select the Basic Render Driver adapter.adapter.Dispose();continue;}Console.WriteLine($"枚举到 {adapter.Description1.Description} 显卡");yield return adapter;}
为了方便调试 , 这里就加上 ToList 让所有代码都执行
var hardwareAdapter = GetHardwareAdapter(dxgiFactory2)// 这里 ToList 只是想列出所有的 IDXGIAdapter1 在实际代码里 , 大部分都是获取第一个.ToList().FirstOrDefault();if (hardwareAdapter == null){throw new InvalidOperationException("Cannot detect D3D11 adapter");}
以上代码即可获取到显示适配器接口用来进行后续的初始化
初始化 D3D 交换链在开始之前 , 按照 C# 从零开始写 SharpDx 应用 聊聊功能等级 的方法,定义代码
// 功能等级// [C# 从零开始写 SharpDx 应用 聊聊功能等级](https://blog.lindexi.com/post/C-%E4%BB%8E%E9%9B%B6%E5%BC%80%E5%A7%8B%E5%86%99-SharpDx-%E5%BA%94%E7%94%A8-%E8%81%8A%E8%81%8A%E5%8A%9F%E8%83%BD%E7%AD%89%E7%BA%A7.html)D3D.FeatureLevel[] featureLevels = new[]{D3D.FeatureLevel.Level_11_1,D3D.FeatureLevel.Level_11_0,D3D.FeatureLevel.Level_10_1,D3D.FeatureLevel.Level_10_0,D3D.FeatureLevel.Level_9_3,D3D.FeatureLevel.Level_9_2,D3D.FeatureLevel.Level_9_1,};
使用以上获取的显示适配器接口创建设备
DXGI.IDXGIAdapter1 adapter = hardwareAdapter;D3D11.DeviceCreationFlags creationFlags = D3D11.DeviceCreationFlags.BgraSupport;var result = D3D11.D3D11.D3D11CreateDevice(adapter,D3D.DriverType.Unknown,creationFlags,featureLevels,out D3D11.ID3D11Device d3D11Device, out D3D.FeatureLevel featureLevel,out D3D11.ID3D11DeviceContext d3D11DeviceContext);
也许使用这个显示适配器接口创建不出设备,通过判断返回值即可了解是否成功 。创建失败,那就不指定具体的参数,使用 WARP 的方法创建
if (result.Failure){// 如果失败了,那就不指定显卡,走 WARP 的方式// http://go.microsoft.com/fwlink/?LinkId=286690result = D3D11.D3D11.D3D11CreateDevice(IntPtr.Zero,D3D.DriverType.Warp,creationFlags,featureLevels,out d3D11Device, out featureLevel, out d3D11DeviceContext);// 如果失败 , 就不能继续result.CheckError();}
以上代码的 CheckError 方法,将会在失败抛出异常
创建成功,可以获取到 ID3D11Device 和 ID3D11DeviceContext 类型的对象和实际的功能等级 。这里的 ID3D11Device 就是 D3D 设备,提供给交换链绑定的功能,可以绘制到交换链的缓存里,从而被交换链刷新到屏幕上 。这里的 ID3D11DeviceContext 是包含了 D3D 设备的环境和配置,可以用来设置渲染状态等
由于后续期望使用的是 ID3D11Device1 接口,按照惯例 , 从 d3D11Device
获取
// 大部分情况下,用的是 ID3D11Device1 和 ID3D11DeviceContext1 类型// 从 ID3D11Device 转换为 ID3D11Device1 类型var d3D11Device1 = d3D11Device.QueryInterface<D3D11.ID3D11Device1>();
理论上当前能运行 dotnet 6 的 Windows 系统 , 都是支持 ID3D11Device1 的
同理,获取 ID3D11DeviceContext1 接口
var d3D11DeviceContext1 = d3D11DeviceContext.QueryInterface<D3D11.ID3D11DeviceContext1>();
获取到了新的两个接口 , 就可以减少 d3D11Device
和 d3D11DeviceContext
的引用计数 。调用 Dispose 不会释放掉刚才申请的 D3D 资源 , 只是减少引用计数
d3D11Device.Dispose();d3D11DeviceContext.Dispose();
创建设备完成之后 , 接下来就是创建交换链和关联窗口 。创建交换链需要很多参数 , 在 DX 的设计上,将参数放入到 SwapChainDescription 类型里面 。和 DX 的接口设计一样,也有多个 SwapChainDescription 版本
创建 SwapChainDescription1 参数的代码如下
// 颜色格式,如果后续准备接入 WPF 那推荐使用此格式DXGI.Format colorFormat = DXGI.Format.B8G8R8A8_UNorm;// 缓存的数量,包括前缓存 。大部分应用来说,至少需要两个缓存 , 这个玩过游戏的伙伴都知道const int FrameCount = 2;DXGI.SwapChainDescription1 swapChainDescription = new(){Width = clientSize.Width,Height = clientSize.Height,Format = colorFormat,BufferCount = FrameCount,BufferUsage = DXGI.Usage.RenderTargetOutput,SampleDescription = DXGI.SampleDescription.Default,Scaling = DXGI.Scaling.Stretch,SwapEffect = DXGI.SwapEffect.FlipDiscard,AlphaMode = AlphaMode.Ignore};
参数上面的各个参数的排列组合可以实现很多不同的功能 , 但是 DX 有一个坑的地方在于,参数是不正交的,有些参数设置不对,将会在后续创建失败
推荐阅读
- 为什么阿里Java开发手册不推荐使用Timestamp
- VMware安装Win11+WSA子系统和使用教程
- 支付宝取消自动续费怎么取消? 支付宝取消自动续费怎么取消
- 宝马3系320Li的使用日记 宝马3系320li价格
- 晚上避光使用了果酸面霜,为什么脸色还是变黑了
- 手镯变黑怎么恢复 银手镯变黑怎么清洗变亮
- 姜力洗发水跟润发乳要怎么使用
- 甜橙信用卡免费还款额度怎么使用不了 甜橙信用卡免费还款额度怎么使用
- 婷美高保湿面膏如何使用
- 百果园回应使用变质水果做果切