摘要:運行時環境與大多數應用程序所期望的環境不同。不過程序是要手動交換緩沖區的。第一個主題介紹代碼可移植性與限制第二個主題介紹的運行時環境第三個主題第一篇文章介紹連接和第三個主題第二篇文章介紹第四個主題介紹文件和文件系統第六個主題介紹如何調試代碼
翻譯:云荒杯傾
本文是Emscripten-WebAssembly專欄系列文章之一,更多文章請查看專欄。
也可以去作者的博客閱讀文章。
Emscripten運行時環境與大多數C/C++應用程序所期望的環境不同。Emscripten努力抽象和減輕這些差異,因此在一般的代碼中,可以用很少或沒有更改來編譯。
本文描述了一些差異和由此產生的API限制,并概述了您可能需要對C/C++代碼做出的一些更改。
1、輸入/輸出Emscripten為瀏覽器環境實現了簡單的DirectMedia Layer API(SDL),它提供了對音頻、鍵盤、鼠標、操縱桿和圖形硬件的底層訪問。使用了SDL的應用程序通常不需要為了在瀏覽器中運行做輸入/輸出方面的更改。
不過,我們對glut, glfw, glew 和 xlib等庫有一些支持上的限制。
不使用SDL或其他api的應用程序可以使用Emscripten特有的API來輸入和輸出,他們是:
html5.h,它定義了Emscripten底層膠水綁定以使得本地代碼可以與HTML5事件進行交互,包括訪問鍵盤、鼠標、滾輪、設備方向、電池級別、振動等。
多媒體和圖形API,包括OpenGL和EGL。
2、文件系統很多C/C++代碼使用libc和libcxx中的同步文件系統APIs來訪問本地文件系統中的代碼。這是有問題的,因為瀏覽器是不會讓代碼直接訪問主機系統上的文件的,而且JavaScript只支持異步文件訪問(在web worker之外)。
Emscripten 提供了libc和libcxx的一種實現,并且提供了一個虛擬文件系統,這樣正常的C/C++代碼可以在不需要修改的情況下被編譯然后運行。開發者需要做的只是將文件集合在預加載階段打包放到這個虛擬文件系統。
NOTE: 文件數據在 “編譯期間” 打包,并在 “ 代碼運行之前 ” 使用異步JavaScript api下載到虛擬文件系統中。 編譯后的代碼發出“文件”調用操作,實際上只是調用程序內存。
默認文件系統(MEMFS)在內存存儲文件,如果文件做了修改但是頁面reload了,則修改的工作就白做了。如果想永久地存儲文件的更改,那么開發人員可以安裝IDBFS文件系統,該系統允許在瀏覽器中持久化數據。
如果是在node.js中運行代碼,開發人員可以安裝NODEFS,它可以讓代碼直接訪問本地文件系統。
Emscripten也有一個API支持同步文件獲取。
更多信息
3、瀏覽器主循環瀏覽器事件模型使用合作模式的多任務處理——每個事件都有一個運行的“turn”,然后必須將控制權返回給瀏覽器事件循環,這樣其他事件就可以處理了。HTML頁面掛起的一個常見原因是JavaScript未完成并且未將控制權返回給瀏覽器。
圖形化C++應用程序通常在一個無限循環中運行。在循環的每個迭代中,應用程序執行事件獲取、處理和渲染,接著是延遲(“等待”)以保持幀速率為常數。無限循環在瀏覽器環境中是一個問題,因為沒有辦法把控制權返回到瀏覽器以執行其他代碼。通常是在一段時間之后,瀏覽器將通知用戶該頁面被卡住并提供停止或關閉它的操作。
同樣,js中的webGL API也需要當上一個事件完成之后,才開始運行的,然后自動渲染并且交換緩沖區。不過OpenGL C++程序是要手動交換緩沖區的。
C/C++中實現異步主循環這個問題的標準解決方案是定義一個C函數,它執行主循環的一次迭代(不包括“延遲”)。對于本機編譯,可以在無限循環中調用這個函數,從而有效地保持行為不變。
但在Emscripten編譯的代碼中,我們使用emscripten_set_main_loop()來獲得環境,從而以指定頻率調用相同的函數。迭代仍然是“無限的”,但現在可以在迭代之間運行其他代碼,而且瀏覽器不會掛起。
下面給個示例:
int main() { ... #ifdef __EMSCRIPTEN__ // void emscripten_set_main_loop(em_callback_func func, int fps, int simulate_infinite_loop); emscripten_set_main_loop(one_iter, 60, 1); #else while (1) { one_iter(); // Delay to keep frame rate constant (using SDL) SDL_Delay(time_to_next_frame()); } #endif } // The "main loop" function. void one_iter() { // process input // render to screen }
NOTE: 當你使用SDL時,您可能需要設置主循環。你也應該注意: 1. As the page is shut, it will force a final direct call to the main loop, giving it a chance to notice the SDL_QUIT event. If you do not use a main loop, your app will close before you have had an opportunity to notice this event. 2.There are limitations to what you can do as the page shuts (in onunload). Some actions like showing alerts are banned by browsers at this point.4、執行生命周期
當你的Emscripten編譯后程序已經加載完畢后,就開始預加載文件的階段。(可以通過emcc --preload-file設置要預加載的文件,也可以使用 FS.createPreloadedFile()手動加載),在這個階段進行文件安裝。
您可以使用addRunDependency()添加額外的操作,這是一個依賴項計數器,他要在編譯后的代碼運行之前執行。當這些已經完成,您可以調用removeRunDependency()來刪除已完成的依賴項。
一般來說,不需要添加額外的操作,預加載幾乎能滿足你的需求。
當滿足所有依賴項時,Emscripten將調用run()函數,run()函數將調用您的main()函數。main()函數應該用于執行初始化任務,并且通常main()要調用emscripten_set_main_loop()(如上所述)。然后主循環函數將按請求的頻率被調用。
您可以通過多種方式影響主循環的操作:
emscripten_push_main_loop_blocker()添加一個函數,該函數阻塞主循環,直到攔截器完成為止。舉個例子,當你加載一個新的游戲級別的時候,這是有用的。一個游戲級別完成,你放一個一些阻塞塊來做解包文件,生成數據結構
等操作。當所有阻塞塊完成,主循環就可以重新開始一個新等級的游戲。emscripten_push_main_loop_blocker()可以和emscripten_set_main_loop_expected_blockers()函數一起使用,這能讓用戶知道進度。
emscripten_pause_main_loop()會暫停主循環,emscripten_resume_main_loop()重新開始主循環。不推薦使用這兩個函數,因為他們其實是blocker函數(上面那條)的更底層替代品。
*emscripten_async_call()讓你在特定間隔調用一個函數。這個是在模擬requestAnimationFrame(默認)和setTimeout。
這里有很多其他方法來控制執行
5、Emscripten中內存表示Emscripten中內存模型是Typed Arrays Mode 2。他使用單種類型數組表達內存,不過提供了多種類型視圖來讀取內存。(HEAPU8、HEAPU16、HEAPU32等)。
NOTE: Typed Arrays Mode 2是Fastcomp編譯器支持的唯一內存模型,它是舊編譯器的默認內存模型。 與本項目所嘗試的其他內存模型相比,它適用于許多的任意編譯后的代碼,而且速度相對較快。
這個模型以與普通C和C++相同的方式在內存中lays out items,它和C/C++使用相同數量的內存。
這個模型允許您使用違背 load-store consistency假設的代碼。由于不同的視圖顯示了相同的數據,所以您可以(比方說)編寫一個32位的整數,然后從中間讀取一個字節,它就像在大多數平臺上本地構建C或C++那樣工作。
Emscripten代碼移植系列文章Emscripten代碼移植主題系列文章是emscripten中文站點的一部分內容。
第一個主題介紹代碼可移植性與限制
第二個主題介紹Emscripten的運行時環境
第三個主題第一篇文章介紹連接C++和JavaScript
第三個主題第二篇文章介紹embind
第四個主題介紹文件和文件系統
第六個主題介紹Emscripten如何調試代碼
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/91892.html
摘要:教程之代碼可移植性與限制一翻譯云荒杯傾本文是專欄系列文章之一,更多文章請查看專欄。下面是正文代碼可移植性與限制幾乎可以編譯任何可移植的代碼到。如果標準機構將共享狀態添加到中,支持多線程代碼將成為可能。 Emscripten教程之代碼可移植性與限制(一) 翻譯:云荒杯傾本文是Emscripten-WebAssembly專欄系列文章之一,更多文章請查看專欄。也可以去作者的博客閱讀文章。歡迎...
摘要:優化項也會引發一些問題。檢查你的代碼是否工作并修復問題。從起,及以上的優化級別默認啟動了這項設置。目前正在進行改進。代碼移植系列文章代碼移植主題系列文章是中文站點的一部分內容。 作者:云荒杯傾歡迎加入Wasm和emscripten技術交流群,群聊號碼:939206522。 這是關于Emscripten的系列文章,更多文章請看下面鏈接。 Emscripten代碼移植系列文章 Emscr...
摘要:優化項也會引發一些問題。檢查你的代碼是否工作并修復問題。從起,及以上的優化級別默認啟動了這項設置。目前正在進行改進。代碼移植系列文章代碼移植主題系列文章是中文站點的一部分內容。 作者:云荒杯傾歡迎加入Wasm和emscripten技術交流群,群聊號碼:939206522。 這是關于Emscripten的系列文章,更多文章請看下面鏈接。 Emscripten代碼移植系列文章 Emscr...
閱讀 1979·2021-11-23 10:03
閱讀 4162·2021-11-22 09:34
閱讀 2479·2021-10-08 10:05
閱讀 2252·2019-08-30 15:53
閱讀 1689·2019-08-30 13:56
閱讀 1159·2019-08-29 16:52
閱讀 1109·2019-08-26 13:31
閱讀 3351·2019-08-26 11:45