工程GIT地址:https://gitee.com/yaksue/yaksue-graphics
疑问
在之前的博客《图形API学习工程(21):使用CubeMap纹理》中,D3D12的版本我主要参考了《DirectX12(D3D12)基础教程(五)——理解和使用捆绑包,加载并使用DDS Cube Map_Gamebaby Rock Sun的博客-CSDN博客》的代码,而他使用了CreateHeap
和CreatePlacedResource
这两个我之前没使用过的函数:
他用这种方法最终得到了一个“中间资源”(pITextureUploadSkybox),将作为UpdateSubresources
函数的pIntermediate
参数。
对比之前我创建普通纹理的时候,我是使用CreateCommittedResource
创建出那个中间资源 的。
那么问题来了:
- 这两种创建方式的区别是什么?
- 他们能够互相替换吗?
官方文档上的解释
微软D3D12文档上有一些相关的说明,我搬运一些并尝试翻译。但是由于牵扯到一些我并不熟悉的概念,因此翻译的意思很可能是不准确的,待日后修正。
在《Uploading Different Types of Resources》中,官方对“资源”有如下记录:
Resources are the D3D concept which abstracts the usage of GPU physical memory. Resources require GPU virtual address space to access physical memory. Resource creation is free-threaded.
“资源”是D3D中对GPU物理内存的抽象。资源需要一个“GPU虚拟地址空间”(GPU virtual address space)来访问物理内存。资源的创建是“线程自由的”(free-threaded)
There are three types of resources with respect to virtual address creation and flexibility in D3D12:
根据“虚拟地址的创建”和“灵活度”的不同,D3D12有三种类型的资源:
Committed resources
Committed resources are the most common idea of D3D resources over the generations. Creating such a resource allocates virtual address range, an implicit heap large enough to fit the whole resource, and commits the virtual address range to the physical memory encapsulated by the heap. The implicit heap properties must be passed to match functional parity with previous D3D versions. Refer to ID3D12Device::CreateCommittedResource.
“Committed resources”是最常见的资源概念。当创建这种资源的时候:
- “虚拟地址范围”(virtual address range)被分配
- 一个隐式的 堆 被分配,它足够大可以容纳整个资源
- 向GPU物理内存提交 “虚拟地址范围”是被 堆 所封装的。
The implicit heap properties must be passed to match functional parity with previous D3D versions(?)
详见ID3D12Device::CreateCommittedResource
Reserved resources
Reserved resources are equivalent to D3D11 tiled resources. On their creation, only a virtual address range is allocated and not mapped to any heap. The application will map such resources to heaps later. The capabilities of such resources are currently unchanged over D3D11, as they can be mapped to a heap at a 64KB tile granularity with UpdateTileMappings. Refer to ID3D12Device::CreateReservedResource
“Reserved resources”等价于D3D11的“tiled resources”。在创建的时候:
- 只有“虚拟地址范围”被分配
- 而并没有映射到任何堆 中
应用来负责随后将这个资源映射到堆 中。这种资源的能力与D3D11相比没有变化,他们能以 64KB tile的粒度来映射到 堆 中,使用UpdateTileMappings函数。
详见ID3D12Device::CreateReservedResource
Placed resources
New for D3D12, applications may create heaps separate from resources. Afterward, the application may locate multiple resources within a single heap. This can be done without creating tiled or reserved resources, enabling the capabilities for all resource types able to be created directly by applications. Multiple resources may overlap, and the application must use the TiledResourceBarrier to re-use physical memory correctly. Refer to ID3D12Device::CreatePlacedResource
对于D3D12,应用可以创建独立于资源的堆 。之后,应用可以将多个资源定位于同一个堆 中。这不必通过创建 tiled 或者 reserved 资源就能完成。使得应用获得了直接创建所有类型资源的能力。多个资源可能会重叠,因此应用必须使用 TiledResourceBarrier 来正确地复用GPU物理内存。
详见ID3D12Device::CreatePlacedResource
而对于CreateCommittedResource
和CreatePlacedResource
二者的文档上的介绍如下:
ID3D12Device::CreateCommittedResource:
Creates both a resource and an implicit heap, such that the heap is big enough to contain the entire resource, and the resource is mapped to the heap.
创建资源的同时也创建一个隐式的堆 。这个堆 足够大可以容纳整个资源,并且资源会映射到这个堆 上。
ID3D12Device::CreatePlacedResource
Creates a resource that is placed in a specific heap. Placed resources are the lightest weight resource objects available, and are the fastest to create and destroy.
在指定的堆 中创建资源。Placed resources 是可用的最轻量级的资源对象,最快创建与销毁。
从上面的文档来看,我的理解是:“Committed Resources”的创建更方便,而“Placed resources”的性能更好,但对使用者要求更高。
实践:将“Placed resources”替换成“Committed Resources”
然而,当前比起性能,我更关注保持代码简单,因为这样更利于学习。(在龙书中似乎也没搜到CreatePlacedResource的使用)
因此,我想尝试将当前工程里D3D12的“普通纹理”与“CubeMap纹理”中创建的方式统一,即都变成“Committed Resources”的形式。
试验后发现没问题
未来问题
- 官方文档中的“GPU虚拟地址空间”(GPU virtual address space)是什么意思?更深入的知识值得探究。
- 如果未来要使用“Placed resources”,那么该如何去维护各种堆 ?
后记关于DDS的探究
在稍微进行一些重构后,现在我的D3D12Interface::CreateCubeMapTextureFromDDS
已经和D3D12Interface::CreateTexture
在流程结构上相似了:
看来接下来如果想脱离DDS,问题的重点在于探究在LoadDDSTextureFromFile
函数中:
std::vector<D3D12_SUBRESOURCE_DATA>& subresources
中的数据如何得到ID3D12Resource** texture
怎么创建(因为后续需要通过它知道资源的大小以及像素格式)