更新“橡皮圈跑道”于Flash 9及AVM2


在2005年Ted Patrick发表了一篇优秀的文章,文章讲述了Flash播放器内部帧的执行模型,他为之命名为“ 橡皮圈跑道”。这对于我来说是一份很好的参考,它帮助我在过去几年内了解了在一帧内,代码执行和画面渲染之间的关系。如今已经是Flash播放器9及AVM2的时代,我注意到橡皮圈跑道发生了一些变化,于是在此将之共享。这里所提到的内容仅仅是我对Flash播放器内在的研究,以及对事件和渲染模型的体会,并非全部经过Adobe工程师们的确认。

基础部分还是一样,通过给定的一个帧频,Flash播放器会在每帧的最初部分执行代码,在剩下部分渲染可视对象。这两部分会因为处理内容过多而增大自身跑道长度,并延长帧的持续时间。


相对于之前的模型,这两部分在细节以及如何组成“一帧”上有了细微的变化。

一切控制经由AMV2,我准备称其为控制中心。控制中心的责任是为Flash播放器把时间分割成一段一段的去执行。这里有一点很重要,需要先搞清楚,即分段的时间不是指SWF里的帧频,不过我们下面会看到播放器最终是如何把这些分段时间整合进帧频的。在苹果机的Firefox里运行一个由Flex编译的SWF,控制中心似乎把时间分割为19-20毫秒一段,不过我看下来,这在不同操作系统或者浏览器是不一样的,这点Adobe的员工也有 提及。如何编译SWF对之也有影响,可以看下之后的回复。而这和本篇文章关系不大,我们假设一段为20毫秒,便于计算。这样一来,意味着控制中心在每秒产生并执行的时间段不会超过50段,而由于代码和渲染伸缩性,往往会更少。在每一段内,按着顺序可能有以下五步要处理。

1.发布内置事件——包含的事件有Timer、Mouse、ENTER_FRAME、URLLoader等等...
2.执行用户编写的代码——仅包括监听第一步事件的处理代码。
3.发布RENDER事件的——这个特殊事件会在用户编写的代码中,凡调用stage.invalidate()时发布。
4.执行最后用户编写的代码——用户监听第三步事件的代码。
5.渲染显示列表。


控制中心以每20毫秒为一段,一刻不停的处理这些步骤。每一个步骤花一段时间,最终就形成了橡皮跑道的两块主要部分(代码执行和渲染)构成了“一帧”。用户行为和画面作废(Invalidation)行为充斥了代码部分,渲染部分则比较单纯。需要注重讲一下,因为行为步骤的发生时间是控制中心预先定义了的,所以即使运行的是一个短促的用户行为,控制中心还是会等几毫秒后,再去处理画面作废或者渲染。

描述行为执行和橡皮圈跑道如何被创建最好的方法,就是看一个SWF在帧频5fps、25fps和50fps下时间段是如何处理的。


如图所示,橡皮圈跑道在不同帧频下每帧执行的行为是不同的。当SWF运行在5fps时,每帧处理10个用户行为,1个画面作废行为和1个渲染行为。在25fps时,每帧处理2个用户行为,1个画面作废行为和1个渲染行为。在50fps时,每帧处理1个用户行为,1个画面作废行为,1个渲染行为。上图揭示了一个重要内容,即一些事件只在某一时间段内有效。比如,Event.ENTER_FRAME事件只会在每帧一开始的时间段内发布一次。

所有这些意味着什么?来快速过一下想法。
1.运行超过20毫秒的代码或者渲染会拖长给定的时间段。橡皮圈将根据实际时间段来决定是否延长。控制中心可能会为了保证帧频而放弃一些时间段。
2.一个SWF的真正帧频不会超过控制中心为播放器定义好的频率。即使设置帧频为120fps,但Flash仍只能处理最多50段,也就是渲染50次(多少取决于系统配置)
3.代码执行的次数通常会多于帧频的结果。一个1fps的SWF在每个时间段都能执行一次Timer或者Mouse事件,但渲染只会在最后一个时间段才做。另外,如果需要,可以通过调用updateAfterEvent()来立刻渲染场景,但这只能在Mouse、Timer或者键盘事件的处理函数中使用。然而这样一来,控制中心会认为这就是帧尾,把下一时间段看作是新的一帧。最后,Flash会在鼠标滑过任何可视属性(x、y、width、height等)有变化的Sprite时,强制进行渲染。这些在时间段的最后还是会发生,任何预渲染的逻辑也都会运行。
4.设定的帧频如果不是时间段的整数倍,将会导致不规则的渲染发生。比如设定的帧频是20,每秒执行50个时间段,那么播放器就得2帧渲染5次,也就是3-2-3-2-3-2这样的频率。

以上4点视具体情况而定,因为这篇文章假设一个时间段是20毫秒,每秒处理50个时间段。实际中的时间段有低于5毫秒的,有高于100毫秒的,任何数字上的变化都会影响结果。

如果有兴趣自己测试模型,最有效的办法是创建一个1fps的SWF和一个100fps的SWF,两个都设置一个Timer,间隔为1毫秒。在Timer事件处理函数里改变一个显示对象的x属性,并用getTimer()来跟踪时间,再试试不同的内置事件比如Mouse、EnterFrame、Render然后看看变化。

你可能感兴趣的:(Flash)