2013-01-21 47 views
1

我需要一些關於OpenCL代碼的建議。我在OpenCL中編寫了一個粒子系統,直接從OpenCL繪製到GPU上,因此不需要複製到CPU。這一切都很好,但我有創建新的粒子的問題。OpenCL粒子系統內存佈局

我分配一個大的存儲區域,並在GPU中的所有粒子的數據。粒子的其中一個參數叫做isAlive,並決定它的活躍天氣。當我想創建一個新的粒子時,我會發現一個沒有活動的粒子,將它的位置修改爲其起始位置,然後將其設置爲isAlive true。這個過程是非常昂貴的,因爲我必須迭代所有粒子來找到那些不活躍的粒子,同時我必須確保幾個線程不會同時創建相同的粒子(所以我不結束了更多的粒子,然後我問)。 有沒有什麼好的考慮,算法或策略來更加優雅和快速地解決這個問題?

+0

因此,您不是將數據複製回主機,而是在每個時間步從主機調用不同的內核?另外,一旦粒子死了,除了被新的粒子取代之外,它能再次活躍嗎? – mfa

+0

是的,我從不將數據複製回CPU。我重複一系列內核調用來每次更新粒子。是的,我一次又一次地重複使用了死亡的粒子,但隨後它成爲了物理世界中的新粒子,只是取代了舊的粒子的存儲區域,所以它與舊的粒子沒有任何關係。 –

+0

你知道在給定的時間內有多少個死粒子嗎?你有足夠的內存來分配一個數組來跟蹤活動狀態嗎?你總共瞄準了多少粒子?你是在同一時間更換所有的死顆粒,還是可以等到更晚的時間步? – mfa

回答

2

這是一個方法,我會嘗試:從數據結構的其餘部分分開的IsAlive的標誌。這看起來像是一段經常閱讀的數據,但很難寫出來。使用單個uint來跟蹤32個粒子的狀態。使用0表示活着,1表示死亡 - 實際上創建一個isDead列表。我假設你將擁有比死亡更多的活着粒子。

的值可以讀取(32一次),到時您需要本地內存。這允許你創建一個快速遍歷數據的內核,尋找一個非零值。這裏的性能提升帶來了密集的數據,從而減少了存儲和加載標誌的內存開銷。這使得檢查這些值中的一個成爲一個更便宜的操作,允許您更快速地遍歷它們。在更改32位值時您需要小心,以免損壞共享相同uint的其他數據(隔行掃描可能有助於此)。當你需要縮小1位的確切位置時,指令clz和popcount將會很有幫助。 opencl 1.2 refcard

可能的優化#1: 如果您願意,您可以嘗試隔行掃描值,以便第一個uint跟蹤索引0,32,64,96,...,992,第二個uint表示1,33 ,65,97,...,993等等。這可能允許通常在特定粒子上工作的工作項目讀取32個連續的isDead狀態。這可能會比努力付出更多努力,但這取決於您的應用程序。

可能的優化#2: 如果死粒子真的稀疏,可能值得它追蹤更高級別的isDead列表。使用相同的技術,很容易再次將isDead位/ uint列表減少32倍。第二級上的每個位代表相應的uint狀態。即:如果uint中的任何位被置位,則該列表的位N也將被置位。只有在數據中預計有很多零時纔有用,但是這一額外步驟可以節省大量搜索數據中罕見「開」位的週期。這包括原始isDead數據的總內存開銷將等於:memBits = ceil(particleCount/32)+ ceil(particleCount/32^2),或者對於每2^20個粒子約128kb + 4kb。

使用上面,就可以編寫內核,將返回死粒子的數量在給定的範圍內,並迅速找到下一個可用的死粒子之一。

+0

非常感謝所有這些信息!我會嘗試這種方法。 –