Flash Player 10.1內部機制(第二部分) - 執行模型之可變跑道

原文地址:http://blogs.adobe.com/xwlin/2010/04/flash_player_101_-_adobe_max_2009_1.html

演講人: Lee Thomason ([email protected])
翻譯: 林曉偉 ([email protected])

上一篇我們介紹了Flash Player的代碼庫是如何歸併一體以及對Flash平臺的後期開發產生的影響,在第二節裏,我們將重點討論Flash Player的體系結構及其對開發人員的影響。

理解執行模型
執行模型是指Flash Player在每一個幀週期中如何執行相應的指令操作。Flash Player後臺事實上運行着n多線程,只是AS並沒有給開發人員提供多線程編程模型。這意味着從概念上來講我們要把Flash Player看做是單線程運行實體,有關這一單線程編程模型的優勢/劣勢的爭論從未休止過,我不想對這一具有爭議性的問題做過多評論,但請大家記住這一事實。

可變跑道(Elastic Racetrack)
可變跑道是Flash Player的幀執行模型,這個模型描述了在一幀的處理週期中,代碼執行和幀渲染的工作是怎樣彼此平衡的。Flash Player 9和AVM2對這一模型進行了一些改進,這一信息是基於對事件機制和渲染模型的研究總結出來的,完整的模型尚未被官方公佈。

基本的跑道理論沒有發生改變,在Flash Player執行一幀的週期裏,前一部分時間用於執行代碼,剩餘時間用於渲染顯示列表中的對象。每個執行階段都可以根據實際需求增加執行時間來執行更多代碼或做更多的渲染工作,而跑道的總長度也將相應增長。

elasticracetrackexport.png

在前一模型基礎上發生改變的是每一階段在一個微觀週期裏的樣子以及他們怎樣形成一幀。

AVM2是由Flash Player中一個叫做Marshal的元帥級組件所操控,Marshal負責將時間切割成Flash Player工作所依的基本時間片,在這裏我希望澄清一下Flash Player的時間片跟swf文件運行時的幀速率沒有任何關係,我們將最終看到Flash Player是如何將這些時間片合成爲一幀。在Mac OS版Firefox中執行一個由Flex編譯得來的swf文件,Marshal通常會將時間切割成19-20毫秒的時間片,時間片大小根據平臺和瀏覽器的不同而存在差異.爲方便我們接下來的討論,我們假定時間片大小爲20毫秒,也就是說Marshal每秒鐘會產生不超過50個時間片,每個時間片中,五步可能的操作按如下順序執行:

  1. Player事件調度 - 比如Timer事件,鼠標事件,ENTER_FRAME事件,URLLoader事件等等。
  2. 用戶代碼執行 - 所有偵聽上一步相應事件的代碼被執行。
  3. RENDER事件調度 - 在用戶代碼執行期間調用stage.invalidate()會觸發這一特殊事件。
  4. 最後的用戶代碼執行 - 偵聽上述第三步特殊事件的用戶代碼此時被執行。
  5. Player更改顯示列表。

    marshalledsliceexport.png


Marshal如此反覆的執行20毫秒時間片並在運行中決定下一步操作。一個時間片中執行的所有這些操作最終歸納爲上述兩段式跑道(代碼執行,圖像渲染)也就是我們所說的一幀。用戶代碼和失效操作填充在代碼執行區,渲染操作填充在跑道的渲染區段。需要指出的是相關操作只能在Marshal預定的時間內發生,如果你的用戶代碼很短,那麼Marshal仍然會在執行完用戶代碼後等待一段時間然後進入渲染階段。

爲了更好闡述哪些action被如何執行以及可變跑道如何被創建,請參考如下示例,分別描述了以5fps, 25fps和50fps幀速率工作的swf中時間片是如何被處理的。

framemarshalingexport.png
以上示例可以看出,不同的幀速率下,一個幀週期中的可變跑道會執行不同操作,例如對於5fps的swf,每幀處理10個用戶action,1個失效action,1個渲染action;幀速率25fps的swf,每幀處理2個用戶action,1個失效action,1個渲染action;對於50fps的swf,每幀只能處理1個用戶action,1個失效action,1個渲染action。需要指出的很重要的一點是,某些事件只可能能發生在某些特定的時間片裏,比如,Event.ENTER_FRAME事件只能在某一幀的初始時間片中被調度。


  1. 一個時間片中代碼部分和渲染部分都有可能過長而導致相應時間片大於20毫秒,這就是"可變"的含義,爲了保證幀的播放速率仍然接近swf編譯時設定的幀率,Marshal會選擇丟掉一些時間片。
  2. swf文件的播放速率不可能超過當前Flash Player切割時間片的速率,你可以爲swf文件設定120fps的播放速率,但Flash最多可以按照50幀的速度播放(具體數值取決於當前系統的設置)。
  3. 代碼的執行頻率可能比swf的幀率更高,播放一個1fps的swf文件,播放一幀時間爲1秒,也就是50個時間片,但在每個時間片裏,都會有觸發鼠標或計時器事件,儘管只有最後一個時間片纔會渲染,另外你可以選擇通過調用函數updateAfterEvent() 提前渲染,但只能在鼠標,計時器和鍵盤事件處理函數中調用。在這種情況下,Marshal會認爲當前幀已結束並從下一個時間片起進入下一幀。 最後,如果一個Sprite的外觀屬性比如width,height等發生變化而將鼠標從該Sprite上方掠過,Flash會進行強制渲染。
  4. 如果幀率不是每秒時間片數量的整數因子,那麼該平臺的渲染時間間隔將變得不固定,比如幀率20fps的swf運行在50個時間片每秒的系統上,Flash Player的行爲將是每5個時間片播放兩幀,那swf的渲染頻率將是2-3-2-3-2-3(時間片)。

 

【博主】
在9RIA上,有關於該文章的進一步討論,主要是updateAfterEvent()到底能不能結束當前幀而進入下一幀,下面是討論內容:

 

【jinni】
我一直對這篇文章的結論有質疑,
根據我測試的結果,當調用updateAfterEvent()時,FP並不認爲是一幀的結束,而只是單純的重繪屏幕
例如你可以在一幀中點擊20次鼠標+updateAfterEvent(),並造成20次重繪事件(RENDER),但對於Flash Player的幀事件(ENTER_FRAME),只會觸發一次。
換句話說,幀的運行次數和重繪屏幕的次數是沒有任何關係的

【jinni】
其實有一個很簡單的論證
很多Flash的邏輯依賴於ENTER_FRAME執行
如果調用updateAfterEvent()就會立即結束當前幀從並觸發下一幀的話
那麼這些Flash的運行邏輯就會加快了,這顯然不合理
而事實上(根據我的測試),調用updateAfterEvent()只會觸發RENDER事件和系統重繪
另外,Flex中的Mouse事件,默認會調用updateAfterEvent()來保證運行效果

【Aone】
我測試下來不會打斷。不過確實有種可以打斷幀的方法,就是給 stage.frameRate賦值,即便是stage.frameRate = stage.frameRate也會打斷幀強制該幀結束。
測試代碼如下:

【jinni】
我所做的測試都是Mac和Win同時做的
事實證明updateAfterEvent()是不會造成幀的結束
而且,在實際情況中,updateAfterEvent()並不只是用戶手動調用纔會觸發
Flash Player會根據需要來對自身進行強制重繪,一幀中可能觸發數十次RENDER事件和重繪
而原文所描述的模型基於一個假設:“一幀之中用戶事件代碼會執行多次,但渲染事件代碼和渲染過程只會執行一次。”就是不成立的。

【Aone】
updateAfterEvent()必須Timer觸發或者鼠標事件還有鍵盤事件觸發後才能正確重繪。
不過呢... 鼠標和鍵盤就算不註冊偵聽在某些情況下也會自動updateAfterEvent()來強制渲染。

【jinni】
我和Ted討論了一下,這是他的回覆:

Yes you can call updateAfterEvent over and over between standard renders. You basically inject a partial render in the code execution side of the racetrack and elongate it.

I would love to see AS have full render control as a playermode in FP11. If set there are no automatic renders and the developer must call render for all visual changes to occur.

是的,你可以在每次標準RENDER(即原文中的Last slice's render)之間調用多次updateAfterEvent(並進行重繪),相當於你在跑道一圈中代碼執行的階段"注入"了部分渲染過程並延長了整個跑道。


其實我很希望看到Flash Player 11可以在某種模式下給開發者完整的渲染控制。在這種情況下開發者必須主動調用API來實現屏幕重繪。

我想問題其實已經比較清楚了,文中跑道模型描述的只是其中一種形態,很多時候,渲染和用戶代碼的調用在一幀的過程中,是穿插進行的,而不是簡單的先執行用戶代碼,最後渲染

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章