请选择 进入手机版 | 继续访问电脑版

开源计算机图形学社区(Open Source Computer Graphics Community) |OpenGPU Forum (2007-2013)| OpenGPU Project

 找回密码
 注册
搜索
查看: 5141|回复: 52

关于 D3D12 的一些问题 [复制链接]

Rank: 16Rank: 16Rank: 16Rank: 16

注册时间
2009-3-27
积分
3999
发表于 2015-9-8 23:46:12 |显示全部楼层
终于从头到尾用自己的代码(不用工程向导)在屏幕上画出了一个三角形。有一些问题还不是很明白,希望大神能答疑解惑。

1. CreateSwapChainForHwnd 的第一个参数MSDN上是这么说的
pDevice [in] A pointer to the Direct3D device for the swap chain. This parameter cannot be NULL.
于是我传了D3D12对象进去,可是程序报错,于是我翻看例子的代码,发现这个参数给的都是一个 ID3D12CommandQueue 对象,我也照做就没有问题了。这是MSDN的错误吗?

2. 每个程序只能创建一个 SRV 和 RTV Heap 吗?如果只能创建一个Heap的话在初始化就要给定大小,这很困难啊。

3. 创建CommandList的时候必须给出一个CommandAllocator,这是一对一的关系吗?Allocator到底是干什么用的?

4. 关于创建资源。D3D12_HEAP_TYPE_DEFAULT类型的资源无法通过Map上载资源也无法初始化的时候就给出初始数据。难道只能通过再创建D3D12_HEAP_TYPE_UPLOAD类型的对象然后CopyBufferRegion给DEFAULT类型的资源吗?没有其他方法吗?这样不仅麻烦而且还得注意D3D12_HEAP_TYPE_UPLOAD类型对象的释放时机,必须确保在数据真正拷贝完成之后才能释放。关于时机我看D3D12的例子都是在资源加载完毕然后需要和GPU同步一次之后释放。D3D12的例子实在太简单了,用到的资源就一个,如果是一个场景的话是不是要每个资源都得和GPU同步一次呢?

5. ID3D12RootSignature 到底是个啥东西?

Rank: 28Rank: 28Rank: 28Rank: 28Rank: 28Rank: 28Rank: 28

注册时间
2009-3-31
积分
14254
发表于 2015-9-9 03:08:09 |显示全部楼层
1. msdn还是用的11的,没更新。这里应该是给queue。
2. SRV heap可以很多,rtv/dsv只能一个。估计一个最大量,然后用free list去管理。
3. 不是一对一。
4. 得用个upload的,map/unmap之后copybufferregion/copyresource。同步也得自己做。d3d11里面也是这样,只不过再去动力代劳了。
5. 表示srv/cbv/samples的布局。

使用道具 举报

Rank: 1

注册时间
2012-1-30
积分
17
发表于 2015-9-16 15:01:29 |显示全部楼层
跟楼主有同样的疑惑啊

关于Descriptor和Descriptor Heap。文档和一些教程说CBV SRV 和 UAV得创建在一个Heap中,但是对于动态加载场景资源的情形下,很明显Descriptor Handle肯定是要动态分配了。那么Descriptor Heap肯定是类似一个堆,初始给一个定值(例如512),然后Heap中的Handle不够了再另行分配Heap。这样Heap就有点类似FreeList和STL中Allocator的设计了。

Root Signautre是代替DX11中 Context->VSSetShaderResrouceView之类函数的功能,然后通过CommandList->SetGraphicsRootDescriptorTable 将这些描述表与heap链接。文档上说SetGraphicsRootDescriptorTable可以设置多个Heap,但是两种heap (Sampler, CBV_UAV_SRV)只能有一个。

爆栈网的帖子有详细说明  帖子名 How to use commandlist with multiple descriptor heaps?
我等级太低发不了链接

那么问题来了,如果我动态分配了Heap,正好一个Draw call使用了一个CBV在一个heap中,还有SRV在另一个Heap中,那岂不是就不行了。但是如果不这么设计,整个系统感觉好死板,很多资源创建的位置都得写死。

有没有大神前来分析DX12 resource Bind在架构设计上的经验

使用道具 举报

Rank: 16Rank: 16Rank: 16Rank: 16

注册时间
2009-3-27
积分
3999
发表于 2015-9-17 14:55:02 |显示全部楼层
IndegnetAngel 发表于 2015-9-16 15:01
跟楼主有同样的疑惑啊

关于Descriptor和Descriptor Heap。文档和一些教程说CBV SRV 和 UAV得创建在一个Hea ...

确实啊,一次DrawCall只能使用一个 Srv/Cbv Heap 这样就造成 Heap 需要和 DrawCall 绑定,然而 Heap 中的 Descriptor 又不能动态增加,难道要给每个 DrawCall 创建一个 Heap ? 还是得把场景中所有 View 都创建到同一个 Heap 中?哪个都不现实啊

使用道具 举报

Rank: 16Rank: 16Rank: 16Rank: 16

注册时间
2009-3-27
积分
3999
发表于 2015-9-24 04:43:44 |显示全部楼层
本帖最后由 Phantom 于 2015-9-24 04:55 编辑
gongminmin 发表于 2015-9-9 03:08
1. msdn还是用的11的,没更新。这里应该是给queue。
2. SRV heap可以很多,rtv/dsv只能一个。估计一个最大 ...

大神,再问俩问题:

1. 我想画两个三角形对象,除了 WMP 矩阵其他都一样,一个画屏幕左边一个在右边。
我通过constant buffer把 WMP矩阵传给 VS , CB 是 Upload 类型的。
我的想法是每画一个三角形对象之前把它的 WMP 数据 Map 到 Constant Buffer 中去然后 Unmap。
可是无论怎么弄屏幕上只有第二次画的三角形,我感觉好像是画了两次,两次都是用第二个三角形的数据画的。
是不是 Map 的时候还有什么特殊方法?或者说需要做同步?
我看了MSDN的例子,它的做法是如果需要画10个物体,就把 ConstantBuffer 建成10倍的 WMP 数据量,这种方法也就做个demo,在实际使用的时候总不能要画多少全都建出来吧。

2. 我在初始化贴图数据的时候用的 WriteToSubresource 方法,使用它之前必须对资源进行 Map,而且 Map 最后一个参数必须是 nullptr
类似 pUpload->Map(0,nullptr,nullptr);
在不进行 D3D 图形调试的时候没问题,运行一切正常,可是只要启动图形调试(Alt+F5),执行到这个 Map 的时候必然崩溃,给出的信息是:
0x00007FFA302888FD (DXCaptureReplay.dll)处(位于 D3D12Learn.exe 中)引发的异常: 0xC0000005: 读取位置 0x0000000000000000 时发生访问冲突。
Map的最后一个参数如果不是 nullptr 则没有问题。
这问题怎么破?
这个问题直接造成我的程序无法进行图形调试,刚才的第一个问题也只能猜测。
顺便说一下,我不想使用 UpdateSubresources.

使用道具 举报

Rank: 28Rank: 28Rank: 28Rank: 28Rank: 28Rank: 28Rank: 28

注册时间
2009-3-31
积分
14254
发表于 2015-9-25 05:54:38 |显示全部楼层
Phantom 发表于 2015-9-24 04:43
大神,再问俩问题:

1. 我想画两个三角形对象,除了 WMP 矩阵其他都一样,一个画屏幕左边一个在右边。

需要同步。否则第二次map就把第一次的覆盖了。

不用WriteToSubresource。这个时候是upload的heap,直接map写就是了。WriteToSubresource是给default用的。

使用道具 举报

Rank: 16Rank: 16Rank: 16Rank: 16

注册时间
2009-3-27
积分
3999
发表于 2015-9-25 14:18:44 |显示全部楼层
本帖最后由 Phantom 于 2015-9-25 14:22 编辑
gongminmin 发表于 2015-9-25 05:54
需要同步。否则第二次map就把第一次的覆盖了。

不用WriteToSubresource。这个时候是upload的heap,直接m ...

对于这个同步大牛你看我理解的对不对。
现在渲染主流程是这样的:
// step1
OMSetRenderTargets / ClearRenderTargetView / ClearDepthStencilView

// step2
for_each(ObjectList)
{
  SetGraphicsRootSignature / SetDescriptorHeaps / SetGraphicsRootDescriptorTable
  Map / Unmap // Update WMP Matrix to CB
  DrawInstanced
}

// step3
Close
ExecuteCommandLists
Signal / SetEventOnCompletion / WaitForSingleObject

// step4
Present

Draw* 函数并不是调用完立刻执行和同步,真正开始执行渲染操作的是ExecuteCommandLists,而且并不同步。
如果按照上面的流程进行渲染在 step2 的时候渲染并未执行,所以在为每个 Object 设置 WMP 矩阵的时候后面的就把前面的给覆盖了,所以造成只能看到最后一个。
如果要想达到一开始的目的,则渲染流程需要改变,得让每个 Object 在真正画完之后才能进行下一个 Object 的数据设置
这样的话 Step2 则应该改成
for_each(ObjectList)
{
  SetGraphicsRootSignature / SetDescriptorHeaps / SetGraphicsRootDescriptorTable
  Map / Unmap // Update WMP Matrix to CB
  DrawInstanced

  Close
  ExecuteCommandLists
  Signal / SetEventOnCompletion / WaitForSingleObject
}

大牛,我这么理解对不对?

使用道具 举报

Rank: 16Rank: 16Rank: 16Rank: 16

注册时间
2010-7-23
积分
2614
发表于 2015-9-25 16:52:42 |显示全部楼层
帮顶, 学习下, 我也想搞dx12.

使用道具 举报

Rank: 28Rank: 28Rank: 28Rank: 28Rank: 28Rank: 28Rank: 28

注册时间
2009-3-31
积分
14254
发表于 2015-9-26 02:45:56 |显示全部楼层
Phantom 发表于 2015-9-25 14:18
对于这个同步大牛你看我理解的对不对。
现在渲染主流程是这样的:
// step1

是的,就是这个意思

使用道具 举报

Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20

注册时间
2013-9-21
积分
6382
发表于 2015-9-26 13:00:15 |显示全部楼层
不過個人覺得那樣每幀都無數次同步也太誇張。
我覺得以用個大CB裝這些資料來渲染還蠻合理的,如果真的超過CB裡面允許的數量,
那麼分開渲染也不遲。

使用道具 举报

Rank: 28Rank: 28Rank: 28Rank: 28Rank: 28Rank: 28Rank: 28

注册时间
2009-3-31
积分
14254
发表于 2015-9-27 02:28:25 |显示全部楼层
等號卡比 发表于 2015-9-26 13:00
不過個人覺得那樣每幀都無數次同步也太誇張。
我覺得以用個大CB裝這些資料來渲染還蠻合理的,如果真的超過C ...

不用无数次同步,只要加fence就行

使用道具 举报

Rank: 16Rank: 16Rank: 16Rank: 16

注册时间
2009-3-27
积分
3999
发表于 2015-10-1 05:22:27 |显示全部楼层
gongminmin 发表于 2015-9-27 02:28
不用无数次同步,只要加fence就行

大牛,我弄了好几天还是不对,我再确认一下,如果要保证一个物体画完就必须执行m_pCommandList->Close和m_pCommandQueue->ExecuteCommandLists是吧?
再画下一个物体的时候还得进行m_pCommandList->Reset是吧?
说白了就是每个DrawCall都得ExecuteCommandLists一次然后同步是吧?

使用道具 举报

Rank: 28Rank: 28Rank: 28Rank: 28Rank: 28Rank: 28Rank: 28

注册时间
2009-3-31
积分
14254
发表于 2015-10-1 13:05:49 |显示全部楼层
Phantom 发表于 2015-10-1 05:22
大牛,我弄了好几天还是不对,我再确认一下,如果要保证一个物体画完就必须执行m_pCommandList->Close和m ...

CommandList->Close
CommandQueue->ExecuteCommandLists

CommandQueue->Signal
fence->SetEventOnCompletion(fence_val, event);
WaitForSingleObjectEx(event, INFINITE, FALSE);

Allocator->Reset
CommandList->Reset

使用道具 举报

Rank: 16Rank: 16Rank: 16Rank: 16

注册时间
2009-3-27
积分
3999
发表于 2015-10-6 00:14:24 |显示全部楼层
等號卡比 发表于 2015-9-26 13:00
不過個人覺得那樣每幀都無數次同步也太誇張。
我覺得以用個大CB裝這些資料來渲染還蠻合理的,如果真的超過C ...

再画一些静态的东西还好说,毕竟物体的属性不是这么多占用的CB也还可以,但是如果是角色就麻烦了
当前主流游戏主角的骨骼都得是100根起,一个角色骨骼所需要的空间就得占大半个CB,这根本没法batch

使用道具 举报

Rank: 16Rank: 16Rank: 16Rank: 16

注册时间
2009-3-27
积分
3999
发表于 2015-10-6 02:10:26 |显示全部楼层
gongminmin 发表于 2015-10-1 13:05
CommandList->Close
CommandQueue->ExecuteCommandLists

还是有问题

一开始我在DrawObject循环里面只放入我觉得需要更新的代码
UpdateCB / Draw / Close / ExecuteCommandLists / Signal-Fence-Wait / Reset
可是我在画第二个物体的时候D3D报错说
D3D12 ERROR: ID3D12CommandList:rawInstanced: No root signature has been set so calling Draw can lead to unexpected behavior. [ EXECUTION ERROR #200: COMMAND_LIST_DRAW_ROOT_SIGNATURE_NOT_SET]

于是我把 SetGraphicsRootSignature / SetPipelineState / SetDescriptorHeaps / SetGraphicsRootDescriptorTable 也加入到循环中,这个时候第一桢可以正常渲染了,可是第二桢执行到 ExecuteCommandLists D3D又出错了
D3D12 ERROR: ID3D12CommandQueue::ExecuteCommandLists: Command lists must be successfully closed before execution. [ EXECUTION ERROR #838: EXECUTECOMMANDLISTS_FAILEDCOMMANDLIST]

第一桢虽然能渲染,可是还是只有一个三角形。
我想问问在 CommandList 和 Allocator Close 之后已经bind到管线上的数据都需要重新设置吗?

使用道具 举报

Rank: 28Rank: 28Rank: 28Rank: 28Rank: 28Rank: 28Rank: 28

注册时间
2009-3-31
积分
14254
发表于 2015-10-6 02:15:56 |显示全部楼层
Phantom 发表于 2015-10-6 02:10
还是有问题

一开始我在DrawObject循环里面只放入我觉得需要更新的代码

是啊,你可以认为close之后所有状态都清空了,得全部重新设置一次。而且execute之前必须close。

使用道具 举报

Rank: 16Rank: 16Rank: 16Rank: 16

注册时间
2009-3-27
积分
3999
发表于 2015-10-6 02:48:30 |显示全部楼层
gongminmin 发表于 2015-10-6 02:15
是啊,你可以认为close之后所有状态都清空了,得全部重新设置一次。而且execute之前必须close。 ...

我在画第二桢的时候D3D给我报错
D3D12 ERROR: ID3D12CommandQueue::ExecuteCommandLists: Command lists must be successfully closed before execution
可是我每次DrawCall之后都Close了啊,这怎么回事呢?

还有大牛说的所有状态都清空包括RenderTarget什么的么?

使用道具 举报

Rank: 28Rank: 28Rank: 28Rank: 28Rank: 28Rank: 28Rank: 28

注册时间
2009-3-31
积分
14254
发表于 2015-10-6 08:34:24 |显示全部楼层
Phantom 发表于 2015-10-6 02:48
我在画第二桢的时候D3D给我报错
D3D12 ERROR: ID3D12CommandQueue::ExecuteCommandLists: Command lists  ...

你看看是不是多线程造成的。如果正确地close了,不会出这个错。

对,所有都清空了。我是每一次draw之前都会设置一下,否则似乎会触发warp的一个bug。

使用道具 举报

Rank: 16Rank: 16Rank: 16Rank: 16

注册时间
2009-3-27
积分
3999
发表于 2015-10-7 21:28:48 |显示全部楼层
gongminmin 发表于 2015-10-6 08:34
你看看是不是多线程造成的。如果正确地close了,不会出这个错。

对,所有都清空了。我是每一次draw之前 ...

我把所有状态再画每个object之前都设置一次,果然在第一桢达到了效果,画出了2个三角形。

现在的问题就在第二桢,不知道为什么 D3D 就是给我报错
D3D12 ERROR: ID3D12CommandQueue::ExecuteCommandLists: Command lists must be successfully closed before execution.
也奇了怪了

使用道具 举报

Rank: 17Rank: 17Rank: 17Rank: 17Rank: 17

注册时间
2010-3-27
积分
5647
发表于 2015-10-8 12:29:15 |显示全部楼层
收藏下,以后来学习。

使用道具 举报

Rank: 16Rank: 16Rank: 16Rank: 16

注册时间
2009-3-27
积分
3999
发表于 2015-10-8 20:00:47 |显示全部楼层
gongminmin 发表于 2015-10-6 08:34
你看看是不是多线程造成的。如果正确地close了,不会出这个错。

对,所有都清空了。我是每一次draw之前 ...

大牛,我发现问题了。
再第一桢 m_pCommandList->Close 的时候是正确的,但是在第二桢 Close 的时候返回失败
错误是
E_INVALIDARG One or more arguments are invalid.

我查了MSDN没说明这种情况会是什么问题。Close 也没有参数啊

使用道具 举报

Rank: 28Rank: 28Rank: 28Rank: 28Rank: 28Rank: 28Rank: 28

注册时间
2009-3-31
积分
14254
发表于 2015-10-9 10:47:27 |显示全部楼层
Phantom 发表于 2015-10-8 20:00
大牛,我发现问题了。
再第一桢 m_pCommandList->Close 的时候是正确的,但是在第二桢 Close 的时候返回 ...

应该是barrier造成的。如果set barrier是1个,那么当时就报错,否则会积累到执行的时候。

使用道具 举报

Rank: 16Rank: 16Rank: 16Rank: 16

注册时间
2009-3-27
积分
3999
发表于 2015-10-9 11:51:16 |显示全部楼层
gongminmin 发表于 2015-10-9 10:47
应该是barrier造成的。如果set barrier是1个,那么当时就报错,否则会积累到执行的时候。 ...

那要如何解决呢?

使用道具 举报

Rank: 16Rank: 16Rank: 16Rank: 16

注册时间
2009-3-27
积分
3999
发表于 2015-10-9 11:53:32 |显示全部楼层
本帖最后由 Phantom 于 2015-10-9 12:25 编辑
gongminmin 发表于 2015-10-9 10:47
应该是barrier造成的。如果set barrier是1个,那么当时就报错,否则会积累到执行的时候。 ...

我用了一个非常奇葩的方法解决了这个问题,我创建了2个CommandList,其中一个什么都不干就管Resource Barrier,另一个用作渲染,这样就可以正常运行了。
可是这是正路吗?

对了,到底CommandList中什么指令是必须Execute才会执行?好像 ResourceBarrier 就不需要CommandList 执行 Execute

使用道具 举报

Rank: 28Rank: 28Rank: 28Rank: 28Rank: 28Rank: 28Rank: 28

注册时间
2009-3-31
积分
14254
发表于 2015-10-9 12:54:05 |显示全部楼层
Phantom 发表于 2015-10-9 11:53
我用了一个非常奇葩的方法解决了这个问题,我创建了2个CommandList,其中一个什么都不干就管Resource Barr ...

不是正路。你这么做跟没有任何barrier一样。一定是有个地方你的barrier搞错了,才会这样。在nv驱动上,指令一调用就会找机会执行,warp上会等到execute。

使用道具 举报

Rank: 16Rank: 16Rank: 16Rank: 16

注册时间
2009-3-27
积分
3999
发表于 2015-10-9 13:15:43 |显示全部楼层
gongminmin 发表于 2015-10-9 12:54
不是正路。你这么做跟没有任何barrier一样。一定是有个地方你的barrier搞错了,才会这样。在nv驱动上,指 ...

我做barrier的地方只有RenderTarget
渲染之前 D3D12_RESOURCE_STATE_PRESENT -> D3D12_RESOURCE_STATE_RENDER_TARGET
渲染之后Present之前 D3D12_RESOURCE_STATE_RENDER_TARGET -> D3D12_RESOURCE_STATE_PRESENT

是不是还有什么别的蹊跷的地方?

使用道具 举报

Rank: 28Rank: 28Rank: 28Rank: 28Rank: 28Rank: 28Rank: 28

注册时间
2009-3-31
积分
14254
发表于 2015-10-9 13:50:15 |显示全部楼层
Phantom 发表于 2015-10-9 13:15
我做barrier的地方只有RenderTarget
渲染之前 D3D12_RESOURCE_STATE_PRESENT -> D3D12_RESOURCE_STATE_RE ...

这我也遇到过。最后是在draw的前后加。

使用道具 举报

Rank: 16Rank: 16Rank: 16Rank: 16

注册时间
2009-3-27
积分
3999
发表于 2015-10-9 13:55:39 |显示全部楼层
gongminmin 发表于 2015-10-9 13:50
这我也遇到过。最后是在draw的前后加。

意思是每个DrawCall都要变换一次RenderTarget的state吗?

使用道具 举报

Rank: 28Rank: 28Rank: 28Rank: 28Rank: 28Rank: 28Rank: 28

注册时间
2009-3-31
积分
14254
发表于 2015-10-10 11:19:52 |显示全部楼层
Phantom 发表于 2015-10-9 13:55
意思是每个DrawCall都要变换一次RenderTarget的state吗?

我遇到的情况是,如果一个command list里没有draw,就会在close的时候挂。所以就把set rt挪到draw之前。

使用道具 举报

Rank: 16Rank: 16Rank: 16Rank: 16

注册时间
2009-3-27
积分
3999
发表于 2015-10-10 15:00:18 |显示全部楼层
本帖最后由 Phantom 于 2015-10-10 15:02 编辑
gongminmin 发表于 2015-10-10 11:19
我遇到的情况是,如果一个command list里没有draw,就会在close的时候挂。所以就把set rt挪到draw之前。 ...

我现在在每个 DrawCall 的前后对 RenderTarget 进行一次 State 的变换,现在已经到达我的目的了。
就是感觉这么做太2了,明明还没有到 Present 的时候却要来回变换

其实在正常的游戏场景中根本不可能一次 DrawCall 都出来,像角色这种肯定要一个一个画,这么搞太2了

使用道具 举报

最近看过此主题的会员

您需要登录后才可以回帖 登录 | 注册

‹‹
我的工具栏

关于我们|手机版|Archiver|开源计算机图形学社区(Open Source Computer Graphics Community) | OpenGPU Project | OpenGPU Forum (2007-2013)

GMT+8, 2017-2-23 12:43 , Processed in 0.105398 second(s), 12 queries .

Powered by Discuz! X2

© 2001-2011 Comsenz Inc.

回顶部