Direct 2D与Direct 3D 11协同工作时遇到的一些问题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
Direct 2D与Direct 3D 11协同工作时遇到的一些问题
Direct 2D与Direct 3D 11协同工作时遇到的一些问题
1、前言
最近在把游戏引擎的API从DirectX 9升级到DirectX 11,因为两套API之间存在巨大的差异,因此在升级迁移的过程中撞了不少坑,现在主要把Direct 2D和Direct3D 11协同工作时遇到的问题总结一下。
原来的游戏引擎对纹理做处理的时候(如写字、绘制简单图形等)用的都是GDI+这套API,使用的方法也比较傻,就是在内存中存两套完全相同的图片,一套交给Direct 3D作为纹理,一套作为Bitmap保留在GDI+中,当需要对纹理做一些处理的时候,首先在Bitmap中用GDI+来处理,然后把Direct 3D中的纹理Lock住,然后往里面逐个拷贝像素。
在打算升级到DirectX 11的时候,就已经打算不再使用GDI+了,改为使用Direct 2D,毕竟Direct 2D有硬件加速并且更加底层,而且能够直接和Direct 3D交互。
2、思路
对于Direct 2D和Direct 3D的交互,我的主要思路是在Direct 2D中绘制图片,然后作为纹理让Direct 3D使用,中途参考了MSDN上的文档:
Direct2D and Direct3D Interoperability Overview
我一开始是按照这篇文章中Using Direct2D Content as a Texture这一小节的说明为指导来进行编写的,但是在前面的工作都顺利完成的时候,最后卡在了这里:
hr = m_pD2DFactory->CreateDxgiSurfaceRenderTarget(
pDxgiSurface,
&props,
&m_pRenderTarget
);
也就是我无论如何都无法创建一个DxgiSurfaceRenderTarget,hr返回值永远都是INVALIDARGS。
而整体的思路很简单,将Direct2D的操作作为纹理让Direct3D能够使用的步骤如下:
1.Direct 3D创建一个离屏纹理OffscreenTexcture作为
Direct 2D的渲染对象;
2.对OffscreenTexcture创建相应的DxgiSurface作为离屏表
面;
3.对DxgiSurface创建Direct 2D的RenderTarget。
当我们拿到RenderTarget之后就能够和Direct 2D中的其他普通渲染对象一样,进行各种操作了;但问题就在于,我现在无法创建这个渲染对象。
于是我Google了很久,开始怀疑是我的Direct 3D初始化的问题,接着又怀疑是我的显卡驱动问题;找了半天,我注意到上面那篇文章讲的是Direct X 10和Direct 2D的交互——开始怀疑是Direct X版本的问题,于是按着这个思路搜索,终于在Stack Overflow上找到了这样一个回答:
Can Direct2D actually work with a direct3D 11 device?
综合另外一些搜索结果我大致得到了以下结论:
Direct 2D是基于DirectX 10.1的,不能保证它可以和DirectX
10.1以外的API按照上面那篇MSDN的文章的说明来直接交互。
当然,有的地方又说在Windows 8以后Direct 3D 11是可以和Direct 2D交互的,然而我是Windows 10,就我自己的结果来看,是不可以的。
但是我想因为Direct 2D的这个问题把API降级到DirectX 10.1,但另一方面对Direct 2D又不死心——实在是不怎么想继续用GDI+,因此就以Using DirectX 11 With Direct 2D为中心来搜索,终于,搜了大半天让我搜到了下面这篇答案:Can't create Direct2D DXGI Surface
下面的回答:
Direct2D only works when you create a Direct3D 10.1 device,
but it can share surfaces with Direct3D 11. All you need to
do is create both devices and render all of your Direct2D
content to a texture that you share between them. I use this
technique in my own applications to use Direct2D with
Direct3D 11. It incurs a slight cost, but it is small and
constant per frame.
A basic outline of the process you will need to use is: Create your Direct3D 11 device like you do normally.
1.
Create a texture with the
D3D10_RESOURCE_MISC_SHARED_KEYEDMUTEX option in
order to allow access to the ID3D11KeyedMutex
interface.
2.
3.
Use the GetSharedHandle to get a handle to the texture
that can be shared among devices.
4.
5.
Create a Direct3D 10.1 device, ensuring that it is
created on the same adapter.
6.
7.
Use OpenSharedResource function on the Direct3D 10.1
device to get a version of the texture for Direct3D
10.1.
8.
9.
Get access to the D3D10 KeyedMutex interface for the
texture.
10.
11.
Use the Direct3D 10.1 version of the texture to create
the RenderTarget using Direct2D.
12.
13.