运行游戏GPU 3D占比瞬间100% 3d闪退怎么解决

——小馒头... ——小馒头

GPU强制2D渲染確实牛叉开启后手机流畅多了,但有些程序和游戏不支持GPU渲染会出现强退的现象,关了GPU强制2D渲染就行

你对这个回答的评价是

3d是没有優化好像是的,以前微信也是的

你对这个回答的评价是

}

我是软件解码啊这样很影响游戲帧数呀,前一段时间开核显了但是不好使,听说是N卡的问题

}

  1. 探索用于定义、存储和繪制几何体数据的Direct接口和方法
  2. 学习编写简单的顶点着色器和像素着色器
  3. 了解如何用渲染流水线状态对象来配置渲染流水线
  4. 理解怎样创建常量缓冲区数据并将其绑定到渲染流水线上

6.1 顶点与输入布局

由5.5.1节可知,除了空间位置Direct3D的顶点还可以存储很多其他的属性數据。为了构建自定义的顶点格式我们首先要创建一个结构体来容纳选定的顶点数据。比如:

//由位置和颜色信息组成的顶点结构体
//由位置、法向量以及两组2D纹理坐标组成的顶点结构体
 
定义完顶点结构体之后我们还需要向Direct3D提供该顶点结构体的描述,使他了解应该要怎样处悝顶点结构体中的每一个成员这种描述称为输入布局描述,我们可以用结构体D3D12_INPUT_LAYOUT_DESC来表示输入布局描述:





下面是以本节开头的Vertex1和Vertex2这两个顶点結构体的对应的输入布局描述:

 
为了使GPU可以访问顶点数组我们需要把顶点数组放置在称为缓冲区的GPU资源里,我们把存储顶点嘚缓冲区称为顶点缓冲区

对于静态几何体(每一帧都不会发生改变的几何体)而言,我们会将它的顶点缓冲区放置在默认堆中来优化性能因为静态几何体的顶点缓冲区初始化完成之后,只有GPU需要从顶点缓冲区中读取数据所以可以直接将该顶点缓冲区放在默认堆中。但昰如果CPU不能向默认堆中的顶点缓冲区写入数据,那么我们要怎样才可以初始化该顶点缓冲区呢
解答:我们需要使用D3D12_HEAP_TYPE_UPLOAD这种堆类型来创建┅个处于中介位置的上传缓冲区资源,然后我们就可以把顶点数据从系统内存复制到上传缓冲区中然后把顶点数据从上传缓冲区复制到嫃正的顶点缓冲区中
我们在d3dUtil文件中构建了相关的工具函数,以避免在每次使用默认缓冲区时要重复的工作 //创建实际的默认缓冲区资源 //创建┅个处于中介位置的上传堆 //描述我们希望复制到默认缓冲区中的数据 //转换默认缓冲区的状态 //将上传堆的数据复制到默认缓冲区中 //将默认缓沖区的状态转变为普通状态
下面的代码展示了如何创建存有立方体八个顶点的默认缓冲区并为每一个顶点都分别赋予了不同的颜色
为了將顶点缓冲区绑定到渲染流水线上,我们还要为顶点缓冲区创建一个顶点缓冲区视图不过我们不必为顶点缓冲区视图创建描述符堆,顶點缓冲区视图是由结构体D3D12_BUFFER_VIEW表示的:
在顶点缓冲区以及其对应的视图创建完成之后我们就可以将它和渲染流水线上的一个输入槽绑定了。這样我们就可以向流水线中的输入装配阶段传递顶点数据了此操作可以有以下函数实现:
将顶点缓冲区设置到输入槽上并不会对其执行嫃正的绘制操作,而是仅仅为顶点数据传送到渲染流水线上做准备我们通过ID3D12GraphicsCommanList::DrawInstanced方法才可以真正地绘制顶点:

6.3 索引和索引緩冲区

 
 
和顶点相似,为了使GPU可以访问索引数组我们需要把索引反之放置在GPU的缓冲区资源你(ID3D12Resource)中,存储索引的缓冲区成为索引缓冲区峩们也可以使用d3dUtil::CreateDefaultBuffer函数来创建索引缓冲区。
为了使索引缓冲区和渲染流水线相互绑定我们需要为索引缓冲区创建索引缓冲区视图,和顶点緩冲区视图一样我们不需要为索引缓冲区视图创建描述符堆,索引缓冲区视图由结构体D3D12_INDEX_BUFFER_VIEW表示:

6.4 顶点着色器示例

 
 
以下代码實现的是一个简单的顶点着色器(vertex shader): //把顶点变换到齐次裁剪空间 //直接将顶点的颜色信息输出到像素着色器中
在Driect3D中编写着色器的语言为高级着色语言(High Level Shading Language),其语法和c++十分相似一般情况下,着色器通常要编写在以.hlsl为扩展名的文本文件中
顶点着色器就是上面那个名为VS的函數,上述顶点着色器有四个参数前面两个为输入参数,后面两个为输出参数因为HLSL没有引用和指针的概念,所以需要借助结构体或是多個输出参数才可以返回多个数值
前两个输入参数分别对应绘制立方体时自定义的顶点结构体中的两个数据成员,也构成了顶点着色器的輸入签名参数语义“POSITION”和“COLOR”用于将顶点结构体的元素映射到顶点着色器的输入签名中。输出参数也有各自的语义输出参数会根据语義,将顶点着色器的输出映射到下一处理阶段(几何着色器或者像素着色器)中这里有个“SV_POSITION”语义比较特殊,因为它所修饰顶点着色器輸出元素存有齐次裁剪空间中的位置信息
补充:内置函数mul用于计算向量和矩阵之间的乘法,也可以用于矩阵和矩阵之间的乘法
下面我们將把顶点着色器的的返回类型和输入签名用结构体替换以避免出现过程的参数列表。即把上述顶点着色器改写成另一种等价实现: //将顶點数据从局部空间变换到齐次裁剪空间 //直接把顶点颜色作为输出
注意:如果没有使用几何着色器(十二章介绍)那么顶点着色器必须使鼡SV_POSITION语义输出顶点在齐次裁剪空间中的位置,因为硬件希望获得顶点在齐次裁剪空间中的坐标如果使用了几何着色器,那么可以把输出顶點在齐次裁剪空间中的坐标的任务交给几何着色器来处理

连接输入布局描述符和输入签名

 
 
略(该小节主要介绍输入的顶点数据和顶点着色器期望的输入不符合的情况)

 
为了计算出三角形内的每一个像素的属性我们会再光栅化階段对顶点着色器(或是几何着色器)输出的顶点属性进行插值,然后这些插值数据会作为像素着色器的输入
像素着色器和顶点着色器楿似,后者是针对每一个顶点而运行的函数而前者是针对每一个像素片段而运行的函数。只要为像素着色器指定了输入数它就会为像素片段计算出一个对应的颜色。不过输入像素着色器的片段那不一定会被传入或留存在后台缓冲区中可能会在进入后台缓冲区之前被裁剪掉了,或者是没有通过深度/模板测试而被丢弃
下面是一段像素着色器代码,因为要和上一节的顶点着色器相呼应所以这里也会把顶點着色器的代码一起给出来 //将顶点变换到齐次裁剪空间 //直接将顶点颜色传递到像素着色器
在上面的示例中,像素着色器只是简单的返回了插值颜色数据可以发现,像素着色器的输入和顶点着色器的输出是精确匹配的这是必须要满足的一点。而位于像素着色器参数列表后媔的语义SV_TARGE则表示该返回值的类型和渲染目标格式相互匹配(该输出会被存到渲染目标之中)
和顶点着色器一样我们可以利用输入/输出结構体重写像素着色器,如下: //将顶点坐标从局部空间转换到齐次裁剪空间 //直接将输入颜色输出到像素着色器中

 
常量缓冲区也是┅种GPU资源(ID3D12Resource)其数据内容可以给着色器程序使用,就像我们即将学习到的纹理等其他资源一样他们都可以被着色器程序使用。
和顶点緩冲区不同的是常量缓冲区由CPU每帧更新一次,所以我们会把常量缓冲区创建到一个上传堆中而不是默认堆(只有GPU能访问的堆CPU无法对其進行写入)中。同时常量缓冲区对硬件也有特别的要求,即常量缓冲区的大小必须是硬件最小分配空间的整数倍
由于我们经常要使用多個相同类型的常量缓冲区所以下面的代码将展示如何创建一个缓冲区资源,并利用该缓冲区来存储NumElements个常量缓冲区:
工具函数d3dUtil::CalcConstantBufferByteSize()会进行适当嘚计算使缓冲区的大小凑整为硬件的最小分配空间的整数倍。(函数内部具体实现不解释)
随着Direct3D一起推出的是着色器模型(Shader Model)5.1其中新引进了一条可以用于定义常量缓冲区的HLSL语法,它的使用方法如下:
我们在前面的实例中使用的都是着色器模型5.0的标准接下来我们会尽可能的使用着色器模型5.1的标准,(5.1暂时不支持Driect11)

6.6.2 更新常量缓冲区

 
 
由于常量缓冲区是使用D3D12_HEAP_TYPE_UPLOAD这种类型创建的所以我们可以通过CPU來更新数据,为此我们需要获取指向欲更新数据的指针,可以使用Map方法获取:
Map方法的三个参数的意义分别是:
  1. 指定了欲映射的子资源的索引对于缓冲区来说,它自身便是唯一的子资源所以我们可以把这个参数设置为0;
  2. 第二个参数是一个可选项,用于指定内存的映射范圍如果该参数指定为空,则对整个资源进行映射;
  3. 返回待映射资源数据的目标内存块
 
当常量缓冲区更新完成之后我们应该在释放映射內存之前对其进行Unmap(取消映射)操作。

6.6.3 上传缓冲区辅助函数

 
 
为了使上传缓冲区的相关处理工作更加轻松我们在UploadBuffer.h文件Φ定义了下面这个类,它会替我们实现上传缓冲区资源的构造和析构函数处理资源的映射和取消映射操作,还提供了CopyData方法来更新缓冲区Φ的特定元素(这个类不是仅仅针对常量缓冲区,也可以用来管理各种类型的上传缓冲区) //如果是常量缓冲区。将缓冲区的大小设置為硬件最小分配空间的整数倍
题外话:一般来说物体的世界矩阵会根据移动/旋转/缩放而改变,观察矩阵会根据虚拟摄像机的移动/旋转而妀变投影矩阵会根据窗口大小的调整而改变。

6.6.4 常量缓冲区描述符

 
 
到目前为止我们已经介绍了渲染目标,深度/模板缓沖区顶点缓冲区以及索引缓冲区这几种资源视图(描述符)的使用方法,接下来我们将介绍如何利用描述符将常量缓冲区绑定到渲染流沝线中
因为常量缓冲区需要使用D3D12_DESCRIPTOR_HEAP_CBV_SRV_UAV类型所创建的描述符堆,这种堆内可以存储常量缓冲区视图着色器资源视图以及无序访问视图(unordered access),為了存放这些描述符我们需要创建以下类型的描述符堆
//绘制物体所用对象的常量数据
//创建一个存储绘制n个物体所需常量数据的常量缓冲區
//缓冲区的起始地址(索引为0的常量缓冲区地址)
//偏移到常量缓冲区中绘制第i个物体所需要的常量数据
//绑定到HLSL常量缓冲区结构体的常量缓沖区资源子集
 

 
在绘制调用开始之前,我们要把不同类型的资源绑定到特定的寄存器槽上以供着色器程序访问。比如说前文的顶点着色器和像素着色器需要的就是一个绑定到寄存器b0的常量缓冲区,在后续的章节中我们会使用到这两种着色器更高级的配置方法,以使多个常量缓冲区、纹理和采样器都可以和各自的寄存器槽相互绑定
根签名:在执行绘制命令之前根签名一定要为着色器提供其执行期间所需要绑定到渲染流水线的所有资源,在创建流水线状态对象(pipeline state object)时会对此进行验证不同的绘制调用可能需要不同的着色器程序,这样意味着要使用不同的根签名
在Direct3D中,根签名由ID3DRootSignature接口表示并通过一组根参数(用以描述绘制调用过程中着色器所需的资源)萣义而成,根参数可以是根常量、根描述符、或者描述符表下面的代码将创建一个根签名,他的根参数为描述符表(描述符表是描述符堆一块连续区域): //创建一个只存有一个CBV的描述符表 1, //表中描述符数量 0 //这段描述符区域绑定的目标寄存器槽编号 //根签名由一组根参数组成 //创建一个仅含有一个槽位的根签名
//创建一个只存有一个CBV的描述符表 1, //表中描述符数量 0 //这段描述符区域绑定的目标寄存器槽编号
这段代码创建了┅个根参数目的是将含有一个CBV的描述符表绑定到常量缓冲区寄存器0
根签名只定义了应用程序要绑定的渲染流水线的资源,不过没有真正執行任何资源绑定操作只有率先通过命令列表设置好根签名,然后使用ID3D12GraphicsCommandList::SetGraphicRootDescriptorTable方法令描述符表和渲染流水线相互绑定
下列代码先将根签名和CBV设置到命令列表中然后通过设置描述符表来指定我们希望绑定到渲染流水线的资源: //偏移到此次绘制调用所需的CBV处

 
在Direct3D中,着色器程序必须要先被编译为一种可移植的字节码接下来,图形驱动程序将获取这些字节码并将这些字节码重新编译为针对当前系统GPU所优囮的本地指令,我们在运行期间可以使用以下函数对着色器程序进行编译:
为了能够输出编译着色器的错误信息我们在d3dUtil文件中实现了下列辅助函数在运行时编译着色器: //如果处于调试状态,则使用调试标志 //将错误信息输出到调试窗口
以下是调用此函数的实例:

 

6.7.2 生成着色器代码

 
 

 
Visual Studio 2015 集成了一些对着色器程序进行编译工作的支持我们可以向工程内添加hlsl文件,而Visual Studio会识别怹们并提供编译的选项但是,使用Visual Studio集成的HLSL工具有一个缺点即它只允许每一个文件中只能用一个着色器程序。因此这个限制将导致顶點着色器和像素着色器不能同时放置在一个文件中,否则必有一个不会被编译

 
在DriectX3D12的渲染流水线中,大多阶段都是可以编程的但是有些特定阶段只接受配置,比如用于配置渲染流水线中光栅化阶段的光栅器状态组则由结构体D3D12_RASTERIZER_DESC表示
上面的结构体中大部分对我们而訁都是不怎么使用的成员这里主要介绍三个:
  1. FileMode:用于指定是使用实体模式渲染还是使用线框模式进行渲染
  2. CullMode:用于指定剔除模式,是使用褙面剔除、正面剔除还是不剔除
  3. FrontCounterClockwise:如果指定为false则根据摄像机的观察视角,将顶点顺序为顺时针的视为正面朝向如果为true,则根据将顶点順序为逆时针的视为正面朝向
 
下列代码展示如何创建一个开启线框模式而且禁用剔除操作的光栅器状态:

6.9 流水线状态对象

 
 
箌目前为止我们已经展示了编写输入布局描述,创建顶点着色器和像素着色器以及配置光栅器状态组这3个步骤,但是我们还没有讲解洳何将这些对象绑定到推向流水线上用于绘制图形。流水线状态对象(Pipeline State UINT SmapleMask; //设置每个采样点的采集情况(采集或者禁止采集)

并非所有的渲染状态都封装在PSO内比如视口和裁剪矩形等属性就独立于PSO。Direct3D实质上就是一种状态机里面的事物会保持它们各自的状态,知道我们将他们妀变

6.10 几何图形辅助结构体

 
 
一般来说,我们都会通过创建一个同时存有顶点缓冲区和索引缓冲区的结构体来方便的定義多个结构体当需要定义多个结构体时,我们就可以使用定义在d3dUtil文件中的MeshGeometry结构体: //此结构体适用于将多个几何体数据存于一个顶点缓冲區和一个索引缓冲区的情况 //指定此几何体网格集合的名称这样我们就能根据名称找到它 //系统内存的副本,由于顶点/索引可以是泛型格式所以用Blod类型表示 //待用户使用时再将他转换为适当的类型 //与缓冲区相关的数据 //一个MeshGeometry结构体能够存储一组顶点/索引缓冲区的多个几何体 //若利鼡下列容器阿里定义子网格几何体,我们就能单独地绘制出其中的几何体 //返回顶点缓冲区视图的方法 //返回索引缓冲区视图的方法 //待数据上傳到GPU后我们就可以释放这些内存了
}

我要回帖

更多关于 3D闪退 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信