xoyojank 的 UE4中的DynamicTexture數據更新

源地址 http://blog.csdn.net/xoyojank/article/details/49232841

問題:gamethread 和render thread


static ENGINE_API class UTexture2D * CreateTransient
(
    int32 InSizeX,
    int32 InSizeY,
    EPixelFormat InFormat
)




最近在UE4中實現了程序實時生成的Mesh頂點動畫, 使用的頂點數目很多(幾十萬量級)

一開始是創建Dynamic Vertex Buffer, 然後每幀去更新頂點數據,發現效率比較低

效率的瓶頸在頂點座標的計算上, 畢竟數量有點多

於是改成了基於Vertex Texture(Material中的World Position Offset)的實現,那VB就不用更新了, 只需要每幀更新Texture

這麼做雖然傳輸的數據量是一致的, 但是可以把頂點座標的一部分計算轉入GPU端, 大大減輕了CPU壓力

實際測下來發現GameThread的時間消耗仍然很高, 那進一步的優化就是把這部分操作扔進後臺線程

[cpp] view plain copy
  1. void ADynamicTextureTestCharacter::UpdateInGameThread()  
  2. {  
  3.     FTexture2DMipMap& Mip = DynamicTexture->PlatformData->Mips[0];  
  4.     FVector4* Dest = (FVector4*)Mip.BulkData.Lock(LOCK_READ_WRITE);  
  5.     WriteTextureData(Dest);  
  6.     Mip.BulkData.Unlock();  
  7.     DynamicTexture->UpdateResource();  
  8. }  

改完一測, Crash了, 仔細一看, 原來是FTexture2D::UpdateResource()中會重新創建D3D Texture對象,相關函數必須是GameThread中調用纔可以

本身這種數據更新的方式就有問題, 能不能直接更新到對應的D3D Texture中呢?搜索UE4的代碼, 發現FTwitchLiveStreaming::UpdateWebCamTexture()中有比較高效的實現, 大致思路就是把數據發到RenderThread去直接更新, 調用的是RHIUpdateTexture2D

[cpp] view plain copy
  1. void ADynamicTextureTestCharacter::UpdateInRenderThread()  
  2. {  
  3.     FVector4* Dest = DataBuffer.GetData();  
  4.     WriteTextureData(Dest);  
  5.   
  6.     struct FUpdateTextureContext  
  7.     {  
  8.         uint8* SourceBuffer;    // Render thread assumes ownership  
  9.         uint32 BufferPitch;  
  10.         FTexture2DResource* DestTextureResource;  
  11.     } UpdateTextureContext =  
  12.     {  
  13.         (uint8*)Dest,  
  14.         sizeof(FVector4) * DynamicTexture->GetSizeX(),  
  15.         (FTexture2DResource*)DynamicTexture->Resource  
  16.     };  
  17.   
  18.     ENQUEUE_UNIQUE_RENDER_COMMAND_ONEPARAMETER(  
  19.         UpdateDynamicTexture,  
  20.         FUpdateTextureContext, Context, UpdateTextureContext,  
  21.         {  
  22.         const FUpdateTextureRegion2D UpdateRegion(  
  23.         0, 0,       // Dest X, Y  
  24.         0, 0,       // Source X, Y  
  25.         Context.DestTextureResource->GetSizeX(), // Width  
  26.         Context.DestTextureResource->GetSizeY());    // Height  
  27.   
  28.         RHIUpdateTexture2D(  
  29.             Context.DestTextureResource->GetTexture2DRHI(),  // Destination GPU texture  
  30.             0,                                              // Mip map index  
  31.             UpdateRegion,                                   // Update region  
  32.             Context.BufferPitch,                        // Source buffer pitch  
  33.             Context.SourceBuffer);                          // Source buffer pointer  
  34.     });  
  35. }  

這種做法不再權限於GameThread運行, 所以對性能影響比較小。 實際測試下來調用線程的執行時間比上一種做法要快1ms左右, 這對於FPS影響還是挺大的


參考資料

https://wiki.unrealengine.com/Dynamic_Textures

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