2017-04-12 10 views
3

픽셀 데이터에 액세스하고 게임중인 카메라의 이미지를 디스크에 저장하려고합니다. 처음에는 렌더링 대상과 이후에 RenderTarget -> ReadPixels()를 사용하는 것이었지만 ReadPixels()의 기본 구현에는 FlushRenderingCommands()에 대한 호출이 포함되어 있으므로 이미지가 저장 될 때까지 게임 스레드를 차단합니다. 계산 집약적 인 작업이어서 FPS 방식을 너무 낮추었습니다.언리얼 엔진 4 : 멀티 스레드 프레임 워크에 ReadPixels() 적용하기

이 문제를 해결하려면 CaptureComponent로 카메라에 액세스 할 수있는 전용 스레드를 만든 다음 비슷한 방법을 따르십시오. 그러나 FlushRenderingCommands() 블록은 게임 스레드에서만 호출 할 수 있으므로이 호출없이 ReadPixels()를 다시 작성해야했습니다 (블록하지 않은 방식으로 https://wiki.unrealengine.com/Render_Target_Lookup의 튜토리얼에서 영감을 얻음) : 그렇지만 이미지가 저장 될 때마다 게임 내 FPS가 번쩍 거릴 수있는 문제에 직면합니다 (이 작업은 실제 디스크 저장 작업 때문이 아니라 픽셀 데이터 액세스로 인한 것임을 확인했습니다). 필자가 다시 작성한 ReadPixels() 함수는 다음과 같습니다. 여기서 잘못 될 수있는 것에 대한 제안을 얻고 싶습니다. ENQUEUE_UNIQUE_RENDER_COMMAND_ONEPARAMETER가 비 게임 스레드에서 호출 될 수 있는지, 그리고 이것이 내 문제의 일부인지 확실하지 않습니다.

APIPCamera* cam = GameThread->CameraDirector->getCamera(0); 
USceneCaptureComponent2D* capture = cam->getCaptureComponent(EPIPCameraType::PIP_CAMERA_TYPE_SCENE, true); 
if (capture != nullptr) { 
    if (capture->TextureTarget != nullptr) { 
     FTextureRenderTargetResource* RenderResource = capture->TextureTarget->GetRenderTargetResource(); 
     if (RenderResource != nullptr) { 
      width = capture->TextureTarget->GetSurfaceWidth(); 
      height = capture->TextureTarget->GetSurfaceHeight(); 
      // Read the render target surface data back.  
      struct FReadSurfaceContext 
      { 
       FRenderTarget* SrcRenderTarget; 
       TArray<FColor>* OutData; 
       FIntRect Rect; 
       FReadSurfaceDataFlags Flags; 
      }; 

      bmp.Reset(); 
      FReadSurfaceContext ReadSurfaceContext = 
      { 
       RenderResource, 
       &bmp, 
       FIntRect(0, 0, RenderResource->GetSizeXY().X, RenderResource->GetSizeXY().Y), 
       FReadSurfaceDataFlags(RCM_UNorm, CubeFace_MAX) 
      }; 
      ENQUEUE_UNIQUE_RENDER_COMMAND_ONEPARAMETER(
       ReadSurfaceCommand, 
       FReadSurfaceContext, Context, ReadSurfaceContext, 
       { 
        RHICmdList.ReadSurfaceData(
        Context.SrcRenderTarget->GetRenderTargetTexture(), 
        Context.Rect, 
        *Context.OutData, 
        Context.Flags 
       ); 
      }); 
     } 
    } 
} 

편집 : 내가 발견 한 한 가지 더 내가 내 렌더 타겟 설정에서 HDR을 비활성화합니다 (그러나 이것은 낮은 품질의 이미지 결과) 경우 말더듬은 사라질 것입니다 : 그래서 그럴듯하게 보인다 이미지의 크기 , 아마, 내가 그것을 구현하는 방식 때문에 핵심 스레드 중 하나를 여전히 차단하고있다.

답변

0

작업 그래프의 기본 호출이 있으므로 아무 스레드에서나 ENQUEUE_UNIQUE_RENDER_COMMAND_ONEPARAMETER을 호출 할 수 있어야합니다. 당신은이 매크로가 생성하는 어떤 코드 analize 때, 그것을 볼 수 있습니다 :

if(ShouldExecuteOnRenderThread()) 
{ 
    CheckNotBlockedOnRenderThread(); 
    TGraphTask<EURCMacro_##TypeName>::CreateTask().ConstructAndDispatchWhenReady(ParamValue1); 
} 

당신은 UObjects에 액세스하는 방법에 대한주의해야합니다 (같은 USceneCaptureComponent2D) 다른 스레드가 이러한 가비지 콜렉터에 의해 관리 및 게임 스레드에 의해 자신하는 원인에서.

(...)하지만 그렇다하더라도 나는 이미지가 당신이 stat unit 또는 함께 FPS 저하의 원인이 무엇 스레드 확인 했

저장 될 때마다 내 게임 FPS 인 육포 문제에 직면하고있다 stat unitgraph 명령? profiling tools을 사용하여 더 자세한 통찰력을 수행하고 지연의 다른 원인이 없는지 확인할 수도 있습니다.

편집 : 또 다른 method of accessing pixel data을 찾았습니다. for 루프에서 실제로 데이터를 복사하지 않고 이것을 시험해보고 FPS에 개선이 있는지 확인하십시오. 그 사이에 픽셀 조작/변환이 없기 때문에 조금 더 빨라질 수 있습니다.

+0

프로파일 링 도구를 통해 단일 카메라 HDR 케이스를 보았습니다. 촬영 한 시간 중 가장 큰 히트를 기록한 대부분의 이벤트에는 "CPU 스톨 : 이벤트 대기 중", "CPU 스톨 : 잠자기" 그 (것)들에 쓰여졌는데, GPU가 따라 잡기를 기다리고 있었다고 나는 추측한다. – HighVoltage

+0

주석 주셔서 감사합니다 : 통계 단위 그래프를 실행할 때, 이것은 내가 찾은 것입니다 : 아니오 HDR : 괜찮은 속도로 모든 스레드. HDR : 렌더링 스레드가 많이 부풀어 올라 프레임 타이밍이 급격히 올라갑니다. 가끔 GPU 스레드가 지연됩니다. i.imgur.com/S1YVGaz.png – HighVoltage

+0

'ReadSurfaceData' 메소드가 렌더링 스레드에서 너무 많은 시간을 들여 보내는 것처럼 보입니다. read 함수를 여러 번 호출하는 것과 같은 다른 실수를하지 않았다면,이 특별한 방법으로 픽셀 데이터를 읽는 것이 멀티 스레딩 최적화를 불가능하게 만듭니다. 원시 DirectX 사용에 대해 생각해 보셨습니까?RHI 객체에서 직접 액세스 할 수 있지만 프로젝트가 플랫폼에 따라 크게 달라집니다. – JKovalsky