zoukankan      html  css  js  c++  java
  • Tile based Rendering 二 tbr and tbdr 优化建议tiled based deferred rendering

    http://www.seas.upenn.edu/~pcozzi/OpenGLInsights/OpenGLInsights-TileBasedArchitectures.pdf

    tbr 和tbdr是gpu的一种架构 硬件层面的事情和deferred shading是两回事

    有关blend的开销

    immediate模式 要走相对较慢的 memory   read-modify-write framebuffer

    tile based模式 就在on chip tile buffer上用专门的硬件做了 基本没有开销 而如果在shader里面写会占shader吞吐量

    所以这段的建议就是如果做透明的话 推荐用blend 而不在shader里做

    而透明与不透明相比 透明(无论哪种方式alpha blend, alpha test, alpha to coverage)总会导致 对于透明物体后面的fragment来讲hidden surface removal 和earlyz 失效

    ==============

    ===================

    tbr multisampling对带宽的影响情况是这样的

    multisamp的瓶颈是带宽, 4x为例 访问framebuffer的带宽变为之前的4倍 (一个pixel 4个sample)

    如果是tbt这部分 都在tile buffer上做 做完 一次送到framebuffer (resolved 之后 相当于一个pixel1个sample)

    开销包含以下两部分

    1.tile buffer上的大小需要4倍,厂商在开ms的情况下,减小tile size 为了省下buffer大小,这对性能有些许冲击,half size不会导致half performace

    如果程序的瓶颈是shading吞吐量 tile buffer size减小 只会对性能有很很轻微的影响(比几乎无影响高一点 minor impact也就是除非程序瓶颈就是在这里了

    2 第二种类型的开销在immediate mode下也是同样存在的 会增加大概10%的fragments(数量)的计算  具体数量取决于场景

    不只是cover center的 frag参与  只要cover sample的 frags都会算在内

    ==============

    介于profile 不那么准确好用了

    建议 开发初期 确定复杂度预算 trigngles ,textures ,shader complexity等等,这个我有做

    来避免 geometry 超过一个最高的量引发的切分 性能会大幅下降

     它最后说这段很诡异 应该是举了个反例: 你在draw 后面加glclear ,那个draw可能不会被提交 引擎这边给优化掉了之类吧

    要确保命令按预期执行 应该是这意思

    =========================================

    总结 performance的核心是 测试  测试 测试  因为硬件 driver都是不同的

    对于tb GPU

    1. clear color , depth ,stencil在每帧开始的时候

    2.For each framebuffer, bind it once during the frame, and submit all the commands for the frame before unbinding it or using the results.

    这步是在避免framebuffer的bind

    3.latency for gpu query

    4.保证多边形数量在合理范围,避免那次跳崖式下跌

    5.有了隐藏面消除 不需要对opaquel从前向后排序(powerVR),不是tb的gpu需要这样做,考虑用z pre pass

    6.多利用cheap的multisample

    7.移动平台performance和电量消耗取平衡 两者都要兼顾

    =================

    tbr 透明要不要cpu排序?? (要排, opaque不排是因为被剔掉了

    对于这种情况 是不是完全隐藏面消除就失效了   一个不透明场景 前面蒙上一层透明面片

    我估计这是对一个tile来讲的 场景不要大块很多透明 透明后面不要太多东西 省掉的是透明后面frag的计算

    这段括号里的理解是不对的 粒度肯定不是tile是pixel 分两个passtrans就不会使opaque的hsr失效 后面有论证

    ===============

    基本方法:1 减少状态切换

    2 texture 压缩

    3.减少drawcalls

    4.降低shader复杂度

    各种差异性   导致优化需要持续profiling 并试验

    所以我们不应该记一些方法 而是要知道 每种特性如何影响性能

    (这两点深切赞同)

    锁低帧可以延长电量 

    在达到目标帧率之后还可以持续优化 以减少电量消耗

    移动平台  performance and power consumption

    带宽--移动数据 费电

    immediate mode下pixel需要 read depth/stencil write depth/stencil(opt) write color 这里消耗带宽 

    tbr可以省电  把数据放在计算器旁边(on-chip) 最后往framebuffer放一次 

    GPU的tbr就是为了省带宽 进而省电

    depth/stencil test和blend都是在tile上做

    tbdr的gpu 会用专门的硬件单元 收集到所有的vertex 的信息 用相应的数据结构 包含vertex position ,vertex output, triangle indices, fragment state等

    这部分叫做frame data/polygon lists/parameter buffer

    这部分是有开销的 如果曲面细分导致vertex过多 这部分开销就会抵消掉tbdr的优势

     

    tbdr mode 在每一帧构造的是上文提到的frame data(所有vertex)信息 而不是frame buffer 在性能调优的时候需要铭记这一点

    drawcall越多这部分数据就越大

    (看到一个黑科技using half the depth range on alternate frames to avoid clearing the depth buffer 这个应该是immediate 模式下 为了避免清depth的一种方法 分开用

    避免写这两块buffer都到了这种程度 说明开销很高了)

    tbdr要clear 避免tile buffer copy回 framebuffer 和从framebuffer copy数据去tilebuffer 

    相关mask也设置上 

    clear只是clear 推荐用e EXT_discard_framebuffer 这个扩展可以真正告诉driver 那部分frame buffer的内容可以丢弃 driver可以做他想做的比如rtt时候复用framebuffer不用再copy一份了

    ====================================

    扩展里面提供了一种按tile局部更新的方法(好方法啊!)比如 ui界面很多地方不用更新只是某个图标更新 那其它地方只是从framebuffercopy到tilebuffer就可以

    这个不默认提供 因为copy有开销 参见clear那部分

    glStartTilingQCOM(x , y , width , height , GL_NONE );

    glClear ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);

    glViewport(x , y , width , height );

    // Draw the scene

    glEndTilingQCOM( GL_COLOR_BUFFER_BIT0_QCOM); eglSwapBuffers(dpy , surface );

    这两个扩展EGL_SWAP_BEHAVIOR to EGL_BUFFER_PRESERVED.

    ==========================

    Flushing

    glflush--提交command buffer 清空缓存(cb相关的 包含其它资源buffer) 拿framebuffer的时候会引发flush 执行完命令才能拿结果

    这里讲了一下

    1.framebuffer 如果要访问 肯定需要先把里面的东西shader完 即使是再gpu里访问也是一样的

    2.如果glBindFramebuffer会导致前面那个fm2 unbound 这样fm2会shade return

      这就解释了为什么要减少不必要的framebuffer bound 最好的情况是用到的fm一帧只绑一次(这段出现的fm都是destination

      这就解释了为什么smpass cubemap pass reflection pass都是一个在前面

    3. vertex一直增加会引发一个是平时flush开销16倍的flush (面片在几十万级别不会触发 1M也没事 大了没测)

    通过提前的测试找到这个vertex的数量避免这种问题发生

    ===============================

    Latency

     最后一段latency的问题

    数据被同时访问时会存在driver的 copy on write 费memory 解决方法是 把一块资源一次更新好 不要改一下给gpu处理下再改再给gpu

    ============================================

    Hidden Surface Removal

    overdraw 部分的开销分析

    immediate 两部分开销1overdraw的shading计算2判断遮挡时对depth color buffer 的访问写回

    tbr 2没有 只有1 所以上层要有深度从近到远排序 利用earlyz把1去掉

    tbdr(powervr) 2没有 1也完全没有 这样就不需要上层对opaque排序了

    hsr失效 :

    fragment里面替换遮挡像素

    discard,sample mask,alpha test,alphatocoverage, blend

    所以这些应该只在需要的时候开 即使有切换状态的开销

    没有hsr的平台考虑 z pre pass

    可以去掉大量overdraw shader计算 

    开销分析

    immediate 1depth pass 的开销 2带宽开销 两个pass都访问depth

    tbr 1depth pass 的开销 2没有访问memory的带宽开销(直接在tile上做了),有pass1到pass2 copy frame data的开销(vertex那些)

    这样看来这个zprepass的实现 复用了gpu内部的信息--frame data这是怎么做到的--render to vertex buffer 上层做

    https://www.csee.umbc.edu/~olano/s2006c03/scheuermann.pdf  这个是dx9的 很旧了 新的直接用gs输出vb再拿来用之类的就可以

    所以 带宽limited的app tbr架构的用zprepass会比immediate有效些

    =============

    mali fpk forward pixel kill

    ===============

    发现个好东西 opengl insights.pdf

    =============

    总结

    1.一个pass开始的时候clear  (或者用ext discard) framebuffer--color depth stencil

    2.避免反复绑定framebuffer,一开始绑好,之后这块buffer上的cmd尽可能一次提交

    3.考虑tbr,tbdr的latency和传统模式有区别需要处理 ocquery用上一帧数据,不要卡住当前帧,vb cb动态更新有copy EGL KHR image pixmap or GLX EXT texture from pixmap这俩扩展也会卡住,考虑latency的意思就是关注那些会卡住当前帧的事情 cpu等gpu返回

    4.顶点个数需要测出来 这块显卡的上限 在technique stander的时候做 各个显卡 找到那个16倍flush

    5.tbdr不用上层 opaque排序,没有hsr就手写zprepass

    6.考虑使用廉价multisample

    7.关注用电量高于帧率

     =============

    我之前忽视了一点  tbdr意味着处理的粒度是一个pass

    而不是一个frame 不是只有一次flush才会触发 frame buffer 的read/write

    切换rt都会的 read pix也会

    在一个pass之内 rt上每块tile vs会全部处理完 在最后deferred 处理fs 之后blit到frame buffer上

    --------以上这种理解意味着 如果 场景后面有pp 之后画ui中间切过rt ui透明并不会使rsr失效 因为隐藏面那个pass已经提过frame buffer了

    之后额外又有一次 frame buffer 到tile mem的blit 又往上画了透明 ui所以没有多少消耗 (没有让复杂场景的隐藏面消除失效)

     =======================所以这段profiling的看法更新一下

    profiling 的话 gpu query在此类硬件上 以pass为粒度是可用的,但metal对gpu query的支持不是很友善 是cmd starttime endtime

    (运行时 用gpu query拿精确时间 实时显示 是个人认为最有效的方法 )

    硬件的处理顺序是 每个pass 所有vertex  之后按tile处理fragment这样拿到的commend buffer里面的 粒度不在pass之内的marker是可用的

    此平台推荐方法 debug menu做开关检验impact ,用某些工具

    =========

    接着这点 我又有了新的认识 这就是为什么opaque transparent分开分俩pass的原因

    这样transparent就不会让opaque 的隐藏面消除失效了 opaque的东西已经提交了

    opaque-alpla test ---alpha blend 提交顺序

    http://cdn.imgtec.com/sdk-documentation/PowerVR+Series5.Architecture+Guide+for+Developers.pdf

    接着上面的路往下理解 如果transparent不会让hsr失效

    要注意的是什么呢 是opaque里面的alphatest 我这里还真有这个  先opaque后alphaatest 这样会好些 这里还需要继续理解下

    应该是当前tile失效 不仅仅是像素失效 

    ---

    前面那篇paper里面 framedata framebuffer这个词误导我了 我现在90%+确定粒度是 pass 不是一帧

    https://wiki.mozilla.org/Platform/GFX/MobileGPUs

    ================================

    这个事情我今天完全想明白了 

    xcode 的instrument印证了我的想法

    tbdr的粒度就是 逐个pass的对应 instrument里面每个encoder

    我之前很好奇 既然是deferred为什么instrument能query到准确时间 

    这就是因为 tbdr是deferred到一个pass结束的时候 而不是一帧结束

    一个pass结束的时候是个笼统的概念 这个是我2.0的认识

    更精确的3.0版本的描述是这样的

    fbo的unbound 

    bind new fbo(not quite sure 比如不是mrt的情况下 因为就一个)

    geometry  超大导致的强制flush

    swapbuffer

    readpixel

    等等这些 导致framebuffer resolve

    然后接着解释instrument 可以发现encoder的时间是准确的 里面drawcall的时间是总的encoder的时间除以里面drawcall的个数

    是估摸的 所以hsr就在这里面咯

    并且这个结果也和 metal的api是一致的 这一个encoder就对应一块cmdbuffer metal的gpuquery是拿一个cmd的start-endtime

    这样也同时意味着unity的底层 在metal这里是分cmd提交的 这样我就也可以像instrument那样拿到每个pass的时间显示出来了

    所以接下来我要做实时显示gpu时间在metal上

    ==========================================

    本文一共三篇比较重要的refs 建议阅读它们仨

    =================================================

    今天做了测试 印证了我之前的看法

    测试用例

    alphatest 面片

    alphablend 面片

    opque面片 (触发hsr)

    高费ps 

    pc 100000 Max

    iphonex 1000-100 Max

    for(int ind; ind<Max;ind++)

    {testdata+=exp(testdata);}

    测试结果:

    1.手机有hsr功能

    2.unity 因为把 opque和trandparent作为两个pass  alphablend并没有使opaque的hsr失效

      alphablend当然会使transparent pass的hsr失效

    3.alphatest的不透明部分hsr是生效的 discard部分 当然hsr失效 --这里更新了一点我之前的认识 alphatest的粒度是像素 不是一个obj 现在想想显而易见 扔掉的肯定是那个像素的depth 在那个pipeline里面那时还有什么obj 或者primitive

    还有个测试结果顺便贴下 unity 的aplha blend很费alu的bound

    alphatest基本没有开销 这三个都用的surfaceshader(这里数据和实时监测数据不一致  xcodeprofile显示alphatest有4ms开销但实时运行没有。。。<1ms)

    hsr是perpixel的

    这里的测试有个问题 没有排除上述所谓的hsr只是个earlyz 所以需要增加一步测试 渲染次序 把高费ps提前 之后列结果

    =======================================

     https://developer.apple.com/documentation/metal/mtldevice/ios_and_tvos_devices/about_gpu_family_4

    这篇也很推荐

    苹果没有公布A7到A10的 tbdr arch技术细节 但是根据这段能看到和powerVR有不同 apple自己的意思是tbdr有所提升 隐含discard那条 和我测下来 alphatest性能不错也是符合的 问题是unity没用metal2。。。。

    =====================================================================

    https://www.imgtec.com/blog/the-dr-in-tbdr-deferred-rendering-in-rogue/

    遇到透明之后 会flush之前的数据从isp到fs

    把这个trans pixel和之前hsr的最后一个(visible) blend 这个和测试数据一直相符合

    alphatest

    会先刷isp 全部opaque shader算完再把 discard的pixel返回isp

    ----------------------

    powervr有Firmware 把传统驱动(cpu做的)一些graphics process event放到 firmware里减少对cpu的依赖

    --------

    metal 4+4种 load store action

    https://developer.apple.com/documentation/metal/mtlrenderpassdescriptor/setting_load_and_store_actions 

  • 相关阅读:
    几个关于集合的有趣证明
    SICP 作业2.5
    有关集合大小的比较
    2020 ICPC 小米邀请赛 部分题解
    Hello World!
    【图论】BellmanFord算法
    【图论】格子图
    【图论】BFS
    【图论】二分图最大匹配 | 二分图最大独立集 | 二分图最小点覆盖
    【图论】最大权不相交区间
  • 原文地址:https://www.cnblogs.com/minggoddess/p/9284359.html
Copyright © 2011-2022 走看看