• DirectX 11 编程指南


    微软在2009年8月的DirectXSDK中发布了DirectX的正式版本。基于对DirectX的一贯兴趣,我把DirectX Graphics的文档边看边译为中文。也算是一份学习笔记吧。

    众所周知,Direct3D是在Windows平台上开发实时3D应用的软件开发接口。随着Windows操作系统的升级,Direct3D的版本也随着升级。WindowsXP对应Direct3D9的各个版本,Vista对应D3D10,10.1,Windows7则对应D3D11。所以在XP平台上是没法做D3D10及以上的开发了。不过看起来因为Win7实际上是Vista的一个升级,所以微软也准备在Vista上支持D3D11。

    D3D11是D3D10的一个超集,即它包含了D3D10的所有功能,并在其渲染管线上添加了一些新的特性。根据官方的文档,D3D11的新特性包括:

    ComputerShader(计算着色器)

    计算着色器能把GPU当成一种通用功能的并行处理器来使用。其实在D3D9时代就已经可以应用GPU来进行GP(General-Purpose)计算了,只不过那时候需要使用一些特殊的手段来处理(比如将数据包装成“纹理”)。在D3D11中专门实现了这样一个着色器阶段来支持GP计算,应该使得开发这类应用更为方便一些了。(参考NVIDIA的CUDA 技术以及OpenCL标准)

    虽然计算着色器也是通过D3DDevice进行访问的,并能和其他的图形着色器共享内存资源,但它并不直接连接到其他的着色器阶段上面。这大概是因为ComputerShader并不直接与图形渲染功能相关吧。

    Dynamic Shader Linkage(动态着色器链接)

    D3D11包含的SM5(Shader Model规范)支持面向对象语言的构建方式,并支持运行时的着色器链接。

    多线程(Multithreading)

    随着CPU的多核化趋势渐渐普及,D3DAPI对多线程的支持势在必行。D3D11对多线程提供了这样的功能支持:

    • 并发的对象创建 - 可以在多个线程中并发地进行对象(资源、着色器等)的创建。
    • 在多线程中创建命令列表 - 命令列表是一个记录了图形处理命令的序列。在D3D11中,可以在多个线程中创建命令列表,然后又主渲染线程来发送这个命令列表到渲染硬件。

    Tessellation(细分)

    细分技术使得能够用不同的精度等级(LOD,Level of detail)来渲染一个模型。GPU可以根据所需的LOD来处理输入的模型,以得到相应负责度的实际模型。这项技术可以大大减少内存带宽对三角形数量的限制。这项技术通过两个新的着色器阶段来实现:Hull Shader(壳着色器)和Domain Shader(域着色器)。

    除了上面的4项主要的特性外,D3D11还支持:

    • 通过在创建Device的时候指定特性等级(feature level),D3D11可以在低于等级的硬件(即不完全支持D3D11规格的硬件)上运行。
    • ShaderModel 5
    • 大内存支持 支持超过4GB的资源。
    • …(有待深入了解)

     

    DirectX11 不但包含了新的Direct3D 11。 还引入了两个新的图形组件: Direct2D和DirectWrite。

    Direct2D是一套硬件加速的、立即模式的2D图形绘制接口。(是用来取代GDI,GDI+,DirectDraw吗?) 它能高性能、高质量地绘制2D图形、位图以及文本。D2D能与D3D及GDI良好地互操作。

    DirectWrite支持高质量的文本渲染,与分辨率无关的字体轮廓线绘制,全unicode文本支持及布局处理等等。

     

    在D3D API 中, Device(设备)是一个核心的概念,Device是对一个图形硬件的抽象,它负责创建和销毁其他的对象,渲染图元等功能。D3D11中,Device对象主要用来管理资源,而DeviceContext对象执行渲染操作。一个对象只能被创建它的Device使用。多个Device可以通过共享资源来共享数据,但这个共享的资源也只能在创建它的Device内使用。(意思就是说多个Device都可以访问共享对象里面的数据,但处了创建Device之外,其他Device不能直接把这个资源连接到渲染管线上使用)

    每个Device都由一个ID3D11Device接口来代表,可以通过D3D11CreateDevice或者D3D11CreateDeviceAndSwapChain函数来创建这个接口。每个Device都可以使用一个或多个DeviceContext,这主要是用来支持多线程操作。

    D3D11CreateDevice函数的原型如下:

    HRESULT D3D11CreateDevice(IDXGIAdapter*pAdapter,D3D_DRIVER_TYPEDriverType,HMODULESoftware,UINTFlags,CONST D3D_FEATURE_LEVEL*pFeatureLevels,UINTFeatureLevels,UINTSDKVersion,ID3D11Device **ppDevice,D3D_FEATURE_LEVEL*pFeatureLevel,ID3D11DeviceContext **ppImmediateContext);

    参数解析:

    IDXGIAdapter *pAdapter: 显示适配器接口。表示要创建的Device与这个适配器硬件对应。一台电脑上可能安装多个显示适配器(即显卡),可以使用IDXGIFactory::EnumAdapters函数来遍历所有的适配器。传入NULL的话就表示使用默认的适配器(你的电脑上至少应该有一个显卡吧)。

    D3D_DRIVER_TYPEDriverType:创建的Device的类型。可能的值有:

    • D3D_DRIVER_TYPE_UNKNOWN: 未知类型,创建设备时不能使用
    • D3D_DRIVER_TYPE_HARDWARE: 硬件设备,指使用硬件来实现D3D的功能。它使用硬件来加速D3D功能,并用软件实现硬件不支持的部分,因此能提供最好的性能。这一种设备类型通常都用一个HAL(Hardware Abstraction Layer,硬件抽象层)来代表。
    • D3D_DRIVER_TYPE_REFERENCE: 参考设备,即使用软件(CPU上运行)来实现D3D的所有功能。参考设备注重功能的准确性而不保证速度。因此主要用来做功能的测试、演示与调试等。参考设备由DirectXSDK提供(D3D11Ref.dll ?)。这个设备通常叫做REF Device或Reference rasterizer(光栅器)
    • D3D_DRIVER_TYPE_NULL: 空设备,即不提供D3D渲染功能的设备,它主要用来测试一些非测试的API的功能。它也是由DirectXSDK提供。
    • D3D_DRIVER_TYPE_SOFTWARE:  软件渲染器,也是由软件实现D3D的所有功能。这个渲染器必须由用户自己实现,并通过一个DLL提供。
    • D3D_DRIVER_TYPE_WARP: Windows Advanced Resterization Platform。 一个高性能的软件光栅器。提供特性集9.1到10.1的支持。

    HMODULESoftware:软件渲染器DLL,如果不用软件渲染器的话,传入NULL

    UINTFlags:创建标记,这写标记主要用来控制创建的Device中的层次,这些标记可以按位与操作。如果不特别指定的话,传入0。  D3D11_CREATE_DEVICE_FLAG 的取值有:

    • D3D11_CREATE_DEVICE_SINGLETHREADED = 0x1,  设置Device为单线程使用。D3D11默认是支持多线程使用的,即在每个API的调用中都会进行锁保护。如果确定不会在多线程环境中使用,则设置该标记,则不会进行锁保护,这样可以提高性能。
    • D3D11_CREATE_DEVICE_DEBUG = 0x2,  让Device支持调试层
    • D3D11_CREATE_DEVICE_SWITCH_TO_REF = 0x4,  同时创建REF和HAL设备,这样就可以在运行时进行切换,以支持调试功能。
    • D3D11_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS = 0x8,  阻止创建多线程(这个需要深入了解)
    • D3D11_CREATE_DEVICE_BGRA_SUPPORT = 0x20, 在允许D2D与D3D互操作时设置

    CONST D3D_FEATURE_LEVEL *pFeatureLevels, UINTFeatureLevels:指向一组特征集。创建函数会按顺序尝试这些特征集,并选择第一个能支持的特征集。传入NULL的话,则会依次尝试从高到低(SM5->SM2)的所有特征集。  特征集的可选项有:

    • D3D_FEATURE_LEVEL_9_1 = 0x9100,   SM2
    • D3D_FEATURE_LEVEL_9_2 = 0x9200,   SM2
    • D3D_FEATURE_LEVEL_9_3 = 0x9300,    SM3
    • D3D_FEATURE_LEVEL_10_0 = 0xa000,    SM4
    • D3D_FEATURE_LEVEL_10_1 = 0xa100,    SM4
    • D3D_FEATURE_LEVEL_11_0 = 0xb000,    SM5

    UINTSDKVersion: SDK版本,传入D3D11_SDK_VERSION,这是由SDK设置的一个常数

    ID3D11Device **ppDevice,D3D_FEATURE_LEVEL *pFeatureLevel,ID3D11DeviceContext**ppImmediateContext  三个返回值,返回创建的Device,立即DeviceContext及当前的特征集。

    Device Context 包含了Device的环境或设置。更精确地说,DeviceContext用来设置渲染状态,产生渲染命令,并使用资源。D3D11实现了两种Context,一种是立即渲染(immediate rendering),一种是延迟渲染(deferred rendering)。它们都由ID3D11DeviceContext接口代表。每个线程只能有一个Context,一般主线程拥有立即Context,用于渲染,其他工作线程拥有延迟Context。

    一个Device有且只有一个立即Context,它用来直接绘制到硬件,它能够从GPU获取数据,也可以用来立即执行(或回放)一个命令列表。立即Context可以在创建Device时获取,也可以通过ID3D11Device::GetImmediateContext()接口获取。

    延迟Context将GPU命令记录到命令列表之中。它主要用来在主线程之外记录渲染命令。创建延迟Context时将不会继承任何的立即Context的状态。延迟Context通过ID3D11Device::CreateDeferredContext()接口创建。

    ID3D11Device接口函数都是线程安全的,但ID3D11DeviceContext接口不是线程安全的,即必须只能在一个线程内进行调用。这区别于ID3D10Device接口。

     

     

    D3D11 运行时是按照层次构建的,核心层提供了最基本的功能,外围层则提供了一些可选功能及辅助程序员进行开发的功能。通常来讲,外围层添加新的功能,但不改变里层的已有行为。在创建设备时核心层是必须的,外围层可以使用D3D11_CREATE_DEVICE_FLAG标记进行配置。

    Core Layer: 核心层默认就被创建。它提供了图形设备驱动和API之间的简单映射。它只提供最关键性的校验,以尽量减少开销,提供最佳的性能。

    Debug Layer: 调试层提供了更多的一致性检查,并提供更多新返回信息。这会导致一定的性能损失,并且需要额外的DLL来支持(D3D11SDKLayers.dll)

    所以,在发布版本中只保留Core Layer,而在开发过程中可以使用Debug Layer。

     

     

     

    资源为渲染管线提供数据。它可以是从外部载入的,也可以在运行时动态生成。典型的资源包括纹理数据、顶点数据(几何数据)和着色器数据。资源可以是强类型的或无类型的。也可以指定资源的读写属性。资源可以被CPU或/和GPU访问。每个渲染管线状态至多可以有128个活动的资源。

    有两种方式指定资源的内存布局(即格式),一种是在创建资源时,另一种是在将资源绑定到管线上时。前一种称为有类型的资源,后一种称为无类型资源。无类型资源可以通过资源视图来指导类型并绑定到渲染管线上,一个资源可以同时拥有多个视图,并同时绑定到多个渲染管线阶段上。

    资源主要分为纹理和缓存两大类。

    D3D11资源系统的类图如下:

    D3D11Resouces

    渲染管线状态根据一个视图来解析资源数据。一个视图就像一种转换,将数据解析成适合某种用途的格式。

    四种视图:

    子资源(Subresource) 是一个资源的一部分。一个Buffer资源只有一个子资源,而纹理资源根据维、Mipmap及array的不同,会有多种情况。纹理的每一个Mipmap等级,array中的每个元素都单独构成一个子资源。

    Buffer是用来存放描述几何体的数据,几何体索引数据以及着色器数据。buffer资源必须是有类型的,一个buffer是由一个个元素组成的,每个元素由一到4个组件组成。

    Buffer可以用来存放顶点数据,法线数据,纹理坐标,索引,以及设备状态等。 Buffer分为3种:

    VertexBuffer(顶点缓存) 存放每个顶点的数据

    IndexBuffer(索引缓存) 存放顶点索引数据

    ConstantBuffer(常数缓存) 存放着色器常量数据,也可以存放Stream-output的输出。从概念上讲,它就像一个单组件元素的数组。常数缓存只能使用D3D11_BIND_CONSTANT_BUFFER绑定。常数缓存的大小必须是16bytes的整数倍,而且必须小于或等于D3D11_REQ_CONSTANT_BUFFER_ELEMENT_COUNT

    Buffer使用ID3D11Device::CreateBuffer接口进行创建

    HRESULT CreateBuffer(const D3D11_BUFFER_DESC *pDesc,const D3D11_SUBRESOURCE_DATA*pInitialData,ID3D11Buffer **ppBuffer);

    参数解析如下:

    const D3D11_BUFFER_DESC *pDesc: buffer描述结构

    • UINT ByteWidth; Buffer的总大小,以byte记。
    • D3D11_USAGE Usage;  Buffer的用途,即读写属性。这主要根据对buffer的访问/更新频率来确定。
    • UINT BindFlags;  指定Buffer如何绑定到渲染管线上。这个值是可以是D3D11_BIND_FLAG 的值的“或”,但通常只选择一种绑定方式。
    • UINT CPUAccessFlags;  Buffer的CPU访问权限,0表示CPU无法读写
    • UINT MiscFlags; 其他辅助功能选项。
    • UINT StructureByteStride;  当作为有结构的Buffer时,结构的大小

    DXGI(DirectX Graphics Infrastructure,DirectX 图形基础架构) 提供了对图形硬件进行底层管理的功能。这些功能不涉及显卡的高级特性(比如不需要区别D3D9级别显卡和D3D11级别显卡),因此是与D3D的图形功能是分开的。 DXGI是提供了一个底层的通用框架来支持未来的硬件。DXGI最初是在D3D10中引入的。现在它支持D3D11。即DXGI和D3D可以分开进行进化,而且DXGI的进化应该比D3D慢。

    DXGI的主要功能有:枚举显示硬件设备,将渲染好的帧呈现到输出设备,调整Gamma,以及全屏模式的切换等。DXGI的目的是沟通核心模式驱动和系统硬件。一个应用程序可以直接调用DXGI接口,也可以通过D3D接口间接使用DXGI的功能。

    DXGI类结构图如下:

     

    枚举显示适配器(Adapter)

    适配器是对显示硬件或软件的抽象,它可以是一个显卡,也可以是一个软件渲染器。一台计算机可以有多个适配器。一个适配器可以有一个或多个输出终端(Monitor)。每个输出终端用一个IDXGIOutput接口来代表,适配器用IDXGIAdapter来代表。IDXGIFactory用来枚举Adapter

    呈现(Presentation)

    D3D的功能是渲染到帧缓存,然后DXGI将帧呈现到输出终端上。为了得到最好的性能和效果,至少需要两个缓存,一个用于D3D的绘制,一个用于DXGI的呈现。也可能有不止两个的帧。这样一组帧缓存就组成一个交换链(Swap Chain)SwapChain用IDXGISwapChain接口来表示。SwapChain有一个前缓存,一到多个后缓存。为了得到最好的效率SwapChain总是创建在显示子系统(这个显示子系统就是一个适配器)中,这个系统包括GPU,DAC(Digital to Analog Converter,数模转换器)以及内存。这个子系统通常是一个显卡,但也可能在主板上实现。SwapChain分配在显示子系统的内存中以提高呈现的速度。显示子系统负责把SwapChain 前缓存的数据呈现到输出终端上。SwapChain可以被设置使用全屏或窗口模式绘制,这样就不需要知道显示终端是全屏幕还是一个窗口。全屏模式的SwapChain能切换显示器的分辨率以优化性能。

    创建SwapChain

    SwapChain包含一组Buffer,它们都有相同的尺寸和格式。SwapChain由IDXGIFactory::CreateSwapChain 函数创建。

    HRESULT CreateSwapChain(IUnknown *pDevice,DXGI_SWAP_CHAIN_DESC*pDesc,IDXGISwapChain **ppSwapChain);

    参数解析如下:

    IUnknown *pDevice: D3D Device,SwapChain在创建时就必须绑定到Device。这个Device将绘制到SwapChain的Buffer中。

    DXGI_SWAP_CHAIN_DESC *pDesc: SwapChain描述结构。字段有:

    • DXGI_MODE_DESC BufferDesc;  设置显示模式,比如分辨率,刷新率,缓存格式,扫描线模式,缩放模式。默认选项都是0,所以只需要改变你想改变的值。
    • DXGI_SAMPLE_DESC SampleDesc;  设置多重采样(multi-sampling)参数包括每像素的采样数量及图形质量等级。默认不进行多重采样,则两个数值分别为1和0
    • DXGI_USAGE BufferUsage; 设置表面的用法及CPU的访问选项。后缓存可以作为着色器的输入或者渲染目标。
    • UINT BufferCount; 缓存的数量,包括前缓存,
    • HWND OutputWindow; 显示窗口,不能为空
    • BOOL Windowed; 是否窗口模式
    • DXGI_SWAP_EFFECT SwapEffect;  设置当表面呈现之后对缓存的处理方式。可选方式为:DXGI_SWAP_EFFECT_DISCARD = 0, 丢弃缓存,即缓存内容将不再被使用。应用程序只能操作索引为0的缓存。 DXGI_SWAP_EFFECT_SEQUENTIAL = 1, 缓存将不会被丢弃,按顺序使用缓存链中的缓存,不能在多重采样时使用。
    • UINT Flags; 其他可选项。DXGI_SWAP_CHAIN_FLAG_NONPREROTATED = 1, 关闭图像自动旋转DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH = 2, 允许切换显示模式。DXGI_SWAP_CHAIN_FLAG_GDI_COMPATIBLE = 4, 允许使用GDI来访问缓存。

    D3D11 的图形渲染管线是在D3D10 的基础上进行扩展而得到的。D3D10的功能都得到了保留,并添加了一些新的特性。

    d3d11Pipeline

    两个主要的新特性就是ComputerShader和Tessellation技术。注意ComputerShader并不是对图形渲染的功能的扩展,所以没有在渲染管线上体现出来。

    DirectX Effect(特效?)是一组管线状态的集合。如何组织管线状态,也就决定了会得到什么样的渲染结果,所以Effect这个名字是名副其实的。Effect中的表达式是用HLSL语言写成的,再加上一些Effect特定的语法。经过编译以后,EffectAPI就可以加载Effect并控制渲染硬件进行渲染。Effect不止可以控制可编程阶段的着色器,也可以控制不可编程阶段的设置。

    Effect可以管理的状态包括:着色器状态(shader state),在着色器中使用的纹理及采样状态(Texture and Sampler state),非可编程管线阶段状态。effect代码是纯文本形式的,通常以fx为扩展名。

    一个Effect文件中可以包含多个渲染效果,每个渲染效果是一组完整的状态集合,这组集合称为一个Technique。通常的做法是把适合不同硬件平台的效果放到不同的Technique中。一组Technique可以组织到一个group中(使用fxgroup)。通常可以这样组织:一个Effect文件包含多个Group,每个Group表示一种材质(即渲染效果),每个Group包含多个Technique,用来对应不同的硬件等级(配置),每个Technique都可以由一到多个pass组成。

    Effect系统API是作为D3DX库的一部分提供的,即它不是D3D核心API。它只是作为一个辅助工具提供,在实际开发中完全可以不用Effect来组织你的Material。

    Effect系统API的意义都很直接,与Effect文件的内容也几乎是一一对应的,只是为应用程序提供了一个接口使用Effect文件以及与Effect交换数据。

    奇怪的是,D3D11的经典Sample Basic HLSL 也没有使用ID3DX11Effect接口。Effect看起来很强大,但实际上还是不够灵活啊。

    D3D11支持在多线程中进行对象的创建和渲染。多线程的主要目的是调高性能。

    D3D11的多线程支持分为两个部分:

    1 多线程式的对象创建

    2 立即渲染与延迟渲染

     

     

     

    再分享一下我老师大神的人工智能教程吧。零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!https://blog.csdn.net/jiangjunshow

  • 相关阅读:
    从零开始webpack4.x(十)区分不同环境
    从零开始webpack4.x(九)watch、resolve、小插件、跨域问题、环境变量
    从零开始webpack4.x(八)配置source-map
    从零开始webpack4.x(七)图片处理及打包文件分类
    浏览器:输入url,到页面加载的过程
    从零开始webpack4.x(六)全局变量引入
    JS 闭包
    PHP 回调函数call_user_func和 call_user_func_array()的理解
    面试总结之谈谈你对面向对象的理解
    maven私有库配置
  • 原文地址:https://www.cnblogs.com/skiwnchiwns/p/10344034.html
Copyright © 2020-2023  润新知