CARLA
PixelReader.cpp
Go to the documentation of this file.
1 // Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
2 // de Barcelona (UAB).
3 //
4 // This work is licensed under the terms of the MIT license.
5 // For a copy, see <https://opensource.org/licenses/MIT>.
6 
7 #include "Carla.h"
9 
10 #include "Engine/TextureRenderTarget2D.h"
11 #include "Async/Async.h"
12 #include "HighResScreenshot.h"
13 #include "Runtime/ImageWriteQueue/Public/ImageWriteQueue.h"
14 
15 // =============================================================================
16 // -- FPixelReader -------------------------------------------------------------
17 // =============================================================================
18 
20  const UTextureRenderTarget2D &RenderTarget,
21  uint32 Offset,
22  FRHICommandListImmediate &RHICmdList,
23  FPixelReader::Payload FuncForSending)
24 {
25  TRACE_CPUPROFILER_EVENT_SCOPE_STR("WritePixelsToBuffer");
26  check(IsInRenderingThread());
27 
28  auto RenderResource =
29  static_cast<const FTextureRenderTarget2DResource *>(RenderTarget.Resource);
30  FTexture2DRHIRef Texture = RenderResource->GetRenderTargetTexture();
31  if (!Texture)
32  {
33  return;
34  }
35 
36  auto BackBufferReadback = std::make_unique<FRHIGPUTextureReadback>(TEXT("CameraBufferReadback"));
37  FIntPoint BackBufferSize = Texture->GetSizeXY();
38  EPixelFormat BackBufferPixelFormat = Texture->GetFormat();
39  {
40  TRACE_CPUPROFILER_EVENT_SCOPE_STR("EnqueueCopy");
41  BackBufferReadback->EnqueueCopy(RHICmdList,
42  Texture,
43  FResolveRect(0, 0, BackBufferSize.X, BackBufferSize.Y));
44  }
45 
46  // workaround to force RHI with Vulkan to refresh the fences state in the middle of frame
47  {
48  FRenderQueryRHIRef Query = RHICreateRenderQuery(RQT_AbsoluteTime);
49  TRACE_CPUPROFILER_EVENT_SCOPE_STR("create query");
50  RHICmdList.EndRenderQuery(Query);
51  TRACE_CPUPROFILER_EVENT_SCOPE_STR("Flush");
52  RHICmdList.ImmediateFlush(EImmediateFlushType::FlushRHIThread);
53  TRACE_CPUPROFILER_EVENT_SCOPE_STR("query result");
54  uint64 OldAbsTime = 0;
55  RHICmdList.GetRenderQueryResult(Query, OldAbsTime, true);
56  }
57 
58  AsyncTask(ENamedThreads::HighTaskPriority, [=, Readback=std::move(BackBufferReadback)]() mutable {
59  {
60  TRACE_CPUPROFILER_EVENT_SCOPE_STR("Wait GPU transfer");
61  while (!Readback->IsReady())
62  {
63  std::this_thread::yield();
64  }
65  }
66 
67  {
68  TRACE_CPUPROFILER_EVENT_SCOPE_STR("Readback data");
69  FPixelFormatInfo PixelFormat = GPixelFormats[BackBufferPixelFormat];
70  uint32 ExpectedRowBytes = BackBufferSize.X * PixelFormat.BlockBytes;
71  int32 Size = (BackBufferSize.Y * (PixelFormat.BlockBytes * BackBufferSize.X));
72  void* LockedData = Readback->Lock(Size);
73  if (LockedData)
74  {
75  FuncForSending(LockedData, Size, Offset, ExpectedRowBytes);
76  }
77  Readback->Unlock();
78  Readback.reset();
79  }
80  });
81 }
82 
84  UTextureRenderTarget2D &RenderTarget,
85  TArray<FColor> &BitMap)
86 {
87  check(IsInGameThread());
88  FTextureRenderTargetResource *RTResource =
89  RenderTarget.GameThread_GetRenderTargetResource();
90  if (RTResource == nullptr)
91  {
92  UE_LOG(LogCarla, Error, TEXT("FPixelReader: UTextureRenderTarget2D missing render target"));
93  return false;
94  }
95  FReadSurfaceDataFlags ReadPixelFlags(RCM_UNorm);
96  ReadPixelFlags.SetLinearToGamma(true);
97  return RTResource->ReadPixels(BitMap, ReadPixelFlags);
98 }
99 
100 TUniquePtr<TImagePixelData<FColor>> FPixelReader::DumpPixels(
101  UTextureRenderTarget2D &RenderTarget)
102 {
103  const FIntPoint DestSize(RenderTarget.GetSurfaceWidth(), RenderTarget.GetSurfaceHeight());
104  TUniquePtr<TImagePixelData<FColor>> PixelData = MakeUnique<TImagePixelData<FColor>>(DestSize);
105  TArray<FColor> Pixels(PixelData->Pixels.GetData(), PixelData->Pixels.Num());
106  if (!WritePixelsToArray(RenderTarget, Pixels))
107  {
108  return nullptr;
109  }
110  PixelData->Pixels = Pixels;
111  return PixelData;
112 }
113 
115  UTextureRenderTarget2D &RenderTarget,
116  const FString &FilePath)
117 {
118  return SavePixelsToDisk(DumpPixels(RenderTarget), FilePath);
119 }
120 
122  TUniquePtr<TImagePixelData<FColor>> PixelData,
123  const FString &FilePath)
124 {
125  TUniquePtr<FImageWriteTask> ImageTask = MakeUnique<FImageWriteTask>();
126  ImageTask->PixelData = MoveTemp(PixelData);
127  ImageTask->Filename = FilePath;
128  ImageTask->Format = EImageFormat::PNG;
129  ImageTask->CompressionQuality = (int32) EImageCompressionQuality::Default;
130  ImageTask->bOverwriteFile = true;
131  ImageTask->PixelPreProcessors.Add(TAsyncAlphaWrite<FColor>(255));
132 
133  FHighResScreenshotConfig &HighResScreenshotConfig = GetHighResScreenshotConfig();
134  return HighResScreenshotConfig.ImageWriteQueue->Enqueue(MoveTemp(ImageTask));
135 }
static TUniquePtr< TImagePixelData< FColor > > DumpPixels(UTextureRenderTarget2D &RenderTarget)
Dump the pixels in RenderTarget.
static bool WritePixelsToArray(UTextureRenderTarget2D &RenderTarget, TArray< FColor > &BitMap)
Copy the pixels in RenderTarget into BitMap.
Definition: PixelReader.cpp:83
static void WritePixelsToBuffer(const UTextureRenderTarget2D &RenderTarget, uint32 Offset, FRHICommandListImmediate &InRHICmdList, FPixelReader::Payload FuncForSending)
Copy the pixels in RenderTarget into Buffer.
Definition: PixelReader.cpp:19
std::function< void(void *, uint32, uint32, uint32)> Payload
Definition: PixelReader.h:38
static TFuture< bool > SavePixelsToDisk(UTextureRenderTarget2D &RenderTarget, const FString &FilePath)
Asynchronously save the pixels in RenderTarget to disk.