应用程序无法启动因为应用程序的并行配置不正确(应用程序无法启动因为应用程序的并行配置不正确win10)

电脑或者手机的渲染是一个非常复杂的过程。本文介绍了渲染的一些基础知识,并结合iOS和Android的技术框架介绍了移动渲染的原理。最后详细分析了iOS中的一些离

电脑或者手机的渲染是一个非常复杂的过程。本文介绍了渲染的一些基础知识,并结合iOS和Android的技术框架介绍了移动渲染的原理。最后详细分析了iOS中的一些离屏渲染和圆角优化的方法。

应用程序无法启动因为应用程序的并行配置不正确(应用程序无法启动因为应用程序的并行配置不正确win10)插图

渲染基础知识屏幕绘图的原始数据源位图

我们在屏幕上绘制图像所需的原始数据称为位图。位图是一种数据结构。位图由n*m个像素组成,每个像素的颜色信息用RGB组合或灰度值表示。根据位深度,位图可以分为1、4、8、16、24和32位图像。每个像素使用的信息量越多,可用的颜色就越多,色彩表现就越生动丰富,对应的数据也就越大。

物理像素和逻辑像素

位图一般存储物理像素,应用层一般使用逻辑像素。物理像素和逻辑像素之间会有一定的对应关系。例如,iOS中物理像素和逻辑像素的对应关系如下:

iOS1 倍屏 1pt 对应 1 个物理像素iOS2 倍屏 1pt 对应 2 个物理像素iOS3 倍屏 1pt 对应 3 个物理像素在显示器上绘制位图。

如上所述,在屏幕上绘制图像所需的原始数据称为位图。那么问题来了,有了位图数据之后,如何在屏幕上绘制图像呢?如下图所示,电子枪从上到下逐行扫描,扫描完成后显示器显示一帧。然后电子枪返回到屏幕的初始位置进行下一次扫描。为了使监视器的显示过程与视频控制器的扫描过程同步,监视器将产生一系列与硬件时钟同步的定时信号。当电子枪换线扫描时,显示器会发出水平同步信号;一帧画完,电子枪回到原来的位置,在下一帧准备画之前,显示器会发出一个垂直同步信号。显示器通常以固定频率刷新,该频率是产生垂直同步信号的频率。

CPU、GPU和显示器的协同工作流程

第一部分介绍了视频控制器在物理屏幕上显示位图数据的过程,那么如何获取位图数据呢?实际上,位图数据是CPU和GPU合作获得的。下图是CPU、GPU、显示器协同工作的常见流程。CPU计算显示内容并提交给GPU。GPU完成渲染后,渲染结果存储在帧缓冲区中。接下来,需要在物理屏幕上显示像素信息。此时,视频控制器将读取帧缓冲区中的信息,并将其传输到监视器进行显示。完整的流程如下图所示:

CPU和GPU的区别

说到CPU、GPU、显示器的协同工作流程,就不得不提到CPU和GPU的区别。

CPU是中央处理器,适合单一复杂逻辑,GPU是图形处理器,适合高并发简单逻辑。

GPU的计算单元特别多,流水线特别长,但是控制逻辑非常简单,省略了缓存,适合低延迟运算。但是CPU不仅被大量空室占用,而且控制逻辑特别复杂,相比之下计算能力只是CPU的一小部分。图形渲染涉及到很多矩阵运算,矩阵相关的运算可以拆分成并行的简单运算,所以渲染特别适合GPU。

总结一下:GPU计算量大,但技术含量不高,需要简单重复多次。就像有一份工作,需要在100以内做几百次加减乘除。CPU像老教授一样,可以计算积分和微分,所以适合处理单一的复杂逻辑运算。

通用渲染管道

我们通常把图像渲染的完整过程称为渲染流水线,由CPU和GPU协同完成。通常,渲染过程可以分为四个概念阶段:应用阶段、几何阶段、光栅化阶段和像素处理阶段。在《实时渲染第四讲》中,对实时渲染的各种知识点进行了透彻的讲解。对渲染原理感兴趣的可以看看这本书,堪称“实时渲染圣经”。下面将简要介绍这些过程。

申请阶段

简而言之,它是图像在应用程序中的处理阶段。说白了就是运行在CPU上的程序。这个时候,GPU就什么都没有了。在这个阶段,CPU主要负责处理用户的交互和操作,然后做一些与应用层布局相关的处理,最后将图元(点、线、三角形)的信息输出到下一个阶段。

你可能会疑惑,primitive是不是只有简单的点、线、三角形,才能表现丰富的立体图形?下面立体感强的海豚可以给出肯定的答案,简单的不同颜色的三角形可以呈现立体图形。

几何阶段(几何阶段)

1.顶点着色器(顶点着色器)

顶点着色器可以对顶点的属性进行一些基本的处理。顶点信息转化为视角,添加光照信息,添加纹理等等。CPU抛给GPU的信息,就像是把从这个视角看到的所有信息,以上帝的视角给了GPU。而GPU则是站在人类的角度,在显示器上输出人类可以观察到的图像。所以在这里,坐标变换是从人类的角度进行的。

2.形状装配。在这个阶段,顶点着色器输出的所有顶点都被作为输入,所有的点都被组装成指定图元的形状。点、线和三角形等基本元素。这个阶段也被称为原始装配。

3.几何着色器向图元添加额外的顶点,并将原始图元转换为新的图元,以构建更复杂的模型。

光栅阶段(光栅化阶段)

光栅化阶段将把前三个几何阶段获得的图元转换成一系列像素。

如上图所示,我们可以看到每个像素的中心都有一个点,栅格化就是用这个中心点来划分的。如果中心点在图元内部,则对应于该中心点的像素属于图元。简而言之,这个阶段就是将连续的几何图形转化为离散的像素。

像素处理阶段(像素处理)

1.片段着色器(片段着色器)

经过上面的光栅化阶段,我们得到了每个图元对应的像素。最后阶段我们需要做的就是用正确的颜色填充每个像素,然后通过一系列的处理计算,得到相应的图像信息,最后输出到显示器上。这里将进行插值,就像补间动画一样。例如,如果要将一系列分散的点连接成一条平滑的曲线,相邻的已知点之间可能会有许多缺失点。这时候就需要通过插值的方式来填补缺失的数据。最后,平滑曲线上除已知点以外的所有点都被插值。同样,三角形的三个角色值给定后,其他段按插值计算,呈现渐变效果。

2.测试和混合

在这个阶段,将检测相应的深度值(Z坐标),以确定该像素是位于其他层像素的前面还是后面,以及是否应该将其丢弃。此外,这个阶段还会检查alpha值(它定义了像素的透明度)来混合图层。(简单来说,就是检查图层的深度和透明度,并进行混合。)

R = S + D * (1 - Sa)含义:R:Result,最终像素颜色。S:Source,来源像素(上面的图层像素)。D:Destination,目标像素(下面的图层像素)。a:alpha,透明度。结果 = S(上)的颜色 + D(下)的颜色 * (1 - S(上)的透明度)

经过上面长长的流水线,我们就可以得到原始的数据源——屏幕绘制所需的位图数据,然后视频控制器将位图数据显示在物理屏幕上。

IOS渲染原理渲染技术堆栈

在铺垫了一些渲染相关的基础知识之后,下面主要介绍一些iOS渲染相关的原理和知识。下图是iOS的图形渲染技术栈。有三个相关的核心系统框架:核心图形、核心动画和核心图像,主要用于绘制可视化内容。他们使用OpenGL调用GPU进行实际渲染,然后生成最终的位图数据并存储在帧缓冲区中,再由视频控制器将帧缓冲区中的数据显示在物理屏幕上。

对象

UIKit是iOS开发者最常用的框架。可以通过设置UIKit组件的布局和相关属性来绘制界面。但是,UIKit不具备在屏幕上成像的能力。这个框架主要负责响应用户操作事件(UIView继承自UIResponder),事件通过响应链传递。

核心动画

核心动画主要负责在屏幕上组合不同的视觉内容。这些可视化的内容可以分解成独立的层,也就是我们日常开发过程中经常接触到的CALayer。这些层存储在层树中。CALayer主要负责页面渲染,这是用户在屏幕上所能看到的一切的基础。

核心图形

核心图形主要用于运行时绘制图像。开发者可以使用这个框架来处理基于路径的绘制、变换、色彩管理、离屏渲染、图案、渐变和阴影等。

核心图像

核心映像与核心图形相反,核心映像在运行时创建映像,而核心映像在运行前创建映像。

Es和金属

Opengl和Metal是第三方标准,基于这些标准的具体内部实现由相应的GPU厂商开发。Metal是苹果的第三方标准,由苹果实现。很多开发者从来没有直接使用过metal,但是通过核心动画、核心形象等核心系统框架在间接使用Metal。

CoreAnimation和UIKit框架的关系

上面渲染框架中提到的核心动画是iOS和OS X上图形渲染和动画的基础框架,主要用于应用程序的视图和其他视觉元素的动画制作。核心动画的实现逻辑是将大部分实际绘制工作交给GPU加速渲染,不会给CPU造成负担,还能实现流畅的动画。CoreAnimation的核心类是CALayer,UIKit框架的核心类是UIView。下面是这两个类之间关系的详细描述。

ui和CALayer的关系

如上图所示,UIView和CALayer是一对一的关系。每个UIView都有一个对应的CALayer,一个负责布局、交互响应,另一个负责页面渲染。

它们的两个核心关系如下:

CALayer 是 UIView 的属性之一,负责渲染和动画,提供可视内容的呈现。UIView 提供了对 CALayer 功能的封装,负责了交互事件的处理。

举个例子,UIView是画板,CALayer是画布。创建画板时,会自动绑定一个画布,画板会响应你的操作。比如你可以移动画板,画布负责呈现特定的图形。这两种责任是明确的。一个负责交互,一个负责渲染。

为什么要把CALayer和UIView分开?

iOS和MacOS平台的用户交互有本质区别,但渲染逻辑是通用的。在iOS中,我们使用UIKit和UIView,而在MacOS中,我们使用AppKit和NSView,所以在这种情况下,显示部分的逻辑被分离出来,跨平台重用。

CALayer中的contents属性存储由设备渲染管道(通常称为后备存储)渲染的位图,这是屏幕绘制所需的最原始的数据源。刷新设备屏幕时,将从CALayer中读取生成的位图,然后显示在屏幕上。

@interface CALayer : NSObject <NSSecureCoding, CAMediaTiming>/** Layer content properties and methods. **//* An object providing the contents of the layer, typically a CGImageRef, * but may be something else. (For example, NSImage objects are * supported on Mac OS X 10.6 and later.) Default value is nil. * Animatable. */@property(nullable, strong) id contents;@end核心动画管道

其实早在WWDC的iOS应用高级图形动画(WWDC 14 419,关于UIKit和Core Animation Foundation的会话)中,苹果就给出了Core Animation框架的渲染管道,具体流程如下图所示:

在整个管道中,app本身并不负责渲染,而是有一个单独的进程,即渲染服务器进程,负责渲染。下面将详细介绍整个流水线流程。

应用阶段视图的创建布局计算对图层进行打包,在下一次 RunLoop 时将其发送至 Render Serverapp 处理用户的点击操作,在这个过程中 app 可能需要更新视图树,如果视图树发生更新,图层树也会被更新其次,app 通过 CPU 完成对显示内容的计算Render Server & GPU这一阶段主要执行 metal、Core Graphics 等相关程序,并调用 GPU 在物理层上完成对图像的渲染GPU 将渲染后的位图数据存储到 Frame BufferDisplay视频控制器将帧缓冲区的位图数据一帧一帧的显示在物理屏幕上

如果把以上步骤串起来,会发现它们的执行时间都超过了16.67 ms,所以为了支持屏幕的60 FPS刷新率,这些步骤需要流水线并行执行,如下图所示。每个阶段都不断地向下一个阶段输送产品。此时可以满足16.67毫秒生成一帧数据的要求。

安卓渲染原理安卓上层显示系统

Android中Activity的一个重要职责就是管理界面生命周期,伴随着视图窗口的管理。这涉及到两个主要的Android服务,AMS(ActivityManagerService)和WMS(WindowManagerService)。

在Android中,一个视图会有一个相应的画布。视图树对应一个画布树,Surfaceflinger控制多个画布的构图。最后将位图数据渲染显示在手机屏幕上。

应用层布局

和视图组。

View是Android中所有控件的基类。View类有一个非常重要的子类:ViewGroup,用作其他视图的容器。Android的所有UI组件都是基于View和ViewGroup,整体上用“组合”的思路设计的:ViewGroup是View的子类,所以View Group也可以作为View使用。一个Android app的图形用户界面对应一个视图树,视图树对应一个画布树。这有点类似于iOS中UIView和CALayer的概念,一个负责应用层的布局,一个负责底层的渲染。

系统底部渲染显示

应用层的视图对应canvas,canvas对系统进程就变成了层。SurfaceFlinger主要为layer提供渲染和合成服务。SurfaceFlinger是一个常驻绑定器服务,它将随着init进程的启动而启动。下图详细介绍了从上层视图到下层的转换,以及SurfaceFlinger对多个图层的渲染合成。

IOS屏幕外渲染离屏渲染的原理和定义

首先,我们来介绍一下离屏渲染的原理。我们正常的渲染流程是:CPU和GPU配合,将内容渲染后得到的位图数据连续放入Framebuffer,视频控制器连续从Framebuffer中获取内容,显示实时内容。

而离屏渲染的过程是这样的:

与一般情况下GPU直接将渲染内容放入Framebuffer不同,离屏渲染需要先创建一个额外的离屏渲染缓冲区,将预渲染的内容放入其中,等到合适的时机再进一步叠加渲染离屏缓冲区的内容,完成后再将结果写入Framebuffer。

为什么要先把数据存储在离屏渲染缓冲区?原因有二,一个是被动的,一个是主动的。

一些特殊效果需要使用额外的 Offscreen Buffer 来保存渲染的中间状态(被动)处于效率目的,可以将内容提前渲染保存在 Offscreen Buffer 中,达到复用的目的。(主动)被动离屏渲染触发被动离屏渲染的常见场景

透明和阴影圆润常被称为UI三宝,但这些效果在iOS的日常开发中往往会导致被动的离屏渲染。下面是几个会触发被动离屏渲染的常见场景。

触发屏幕外渲染的原因

离屏渲染的原因就不得不提画师算法了。画师算法的总体思路是绘制图层,先画远处的场景,然后用距离较近的场景覆盖远处的部分。这里的层可以映射到iOS的渲染技术栈中的层。

通常情况下,对于每一层,渲染服务器都会遵循“画家算法”,依次输出到帧缓冲区,最后一层会覆盖上一层,从而得到最终的显示结果。对于该图层树,深度优先算法将用于将图层输出到帧缓冲区。

GPU作为一个“画师”,可以一层一层的输出到画布上,但是在渲染到某一层之后就没有办法再改变其中的某一部分了。因为这一层之前的几层图层像素数据在渲染时已经合成在一起了。其实和photoshop里的图层合并很像。一旦多个图层合并在一起,就不可能修改单个图层。因此,你需要依次绘制离屏缓冲区中的子图层,然后剪切四个角并与前面的图层混合。

GPU离屏渲染的性能影响

一解除屏外渲染,我们直觉上就觉得会影响性能。因为为了满足60fps的刷新频率,GPU操作是高度流水线化的。所有原始的计算工作被有序地输出到帧缓冲区。这时突然有一些特效触发了离屏渲染,需要切换上下文,将数据输出到另一个内存。此时,流水线中的许多中间产品只能被丢弃,这种频繁的上下文切换对GPU的渲染性能产生了很大的影响。

如何防止不必要的离屏渲染?对于一些圆角可以创建四个背景颜色弧形的 layer 盖住四个角,从视觉上制造圆角的效果对于 view 的圆形边框,如果没有 backgroundColor,可以放心使用 cornerRadius 来做对于所有的阴影,使用 shadowPath 来规避离屏渲染对于特殊形状的 view,使用 layer mask 并打开 shouldRasterize 来对渲染结果进行缓存圆角实现的优化策略

使用CALayer的cornerRadius并设置cliptobounds将触发屏幕外渲染。滚动时需要每秒60帧进行裁剪操作,即使内容没有变化。GPU还必须在每帧之间切换上下文,合成整个帧并对其进行裁剪。这些性能消耗会直接影响渲染服务器(一个独立的渲染进程),从而导致丢帧。为了优化渲染性能,我们可以选择一些其他的方案来实现圆角。以下是圆角具体实现需要考虑的条件。

具体实施fillet时需要考虑的条件

圆角下(movement underneath the corner)是否有滑动。是否有穿过圆角滑动(movement through the corner)。四个圆角是否处于同一个 layer 上,有没有与其他 子 layer 相交。

基于的圆角的具体实现方案

如何根据相应的条件选择圆角的实施方案?

以上提到了优化圆角时需要考虑的条件以及不同的圆角实现方案。以下流程图将条件和方案对应起来,给出圆角的最佳实施方案。

摘要

本文主要介绍手机渲染的原理。本文首先介绍了渲染的基础知识,讲述了渲染所需的原始数据源——位图以及CPU和GPU如何协同工作获取位图数据。然后,结合iOS和Android的技术框架,介绍了移动渲染的相关原理。最后,对iOS中的离屏渲染进行了深入分析,并对现有的一些角点优化方案进行了说明。

参考文章

1.iOS图像渲染原理

2.iOS渲染渲染全分辨率

3.iOS渲染流程

4.从自动布局的布局算法谈性能

5.五点怎么样?Auto Layout自动布局,性能如何?

6.iOS界面渲染过程分析

7.iOS谈GPU和“App渲染过程”

8.8有什么区别。CPU和GPU?

9.IOS高级-图层和渲染

10.一篇文章揭示了渲染管道到底是什么。

1.GPU渲染流水线——GPU渲染流水线简介

12.深入研究iOS离屏渲染

13 .纹理

14.Android的各个渲染框架以及Android图层渲染的原理

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。

作者:美站资讯,如若转载,请注明出处:https://www.meizw.com/n/120216.html

发表回复

登录后才能评论