CARLA
 
载入中...
搜索中...
未找到
PixelReader.cpp
浏览该文件的文档.
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
19/**
20 * 将像素数据从渲染目标异步写入缓冲区。
21 *
22 * @param RenderTarget 要读取像素数据的纹理渲染目标。
23 * @param Offset 缓冲区的字节偏移量。
24 * @param RHICmdList 渲染操作的命令列表。
25 * @param FuncForSending 处理像素数据的回调函数。
26 */
28 const UTextureRenderTarget2D &RenderTarget,
29 uint32 Offset,
30 FRHICommandListImmediate &RHICmdList,
31 FPixelReader::Payload FuncForSending)
32{
33 TRACE_CPUPROFILER_EVENT_SCOPE_STR("WritePixelsToBuffer");
34 check(IsInRenderingThread());
35
36 // 获取与渲染目标关联的渲染资源。
37 auto RenderResource =
38 static_cast<const FTextureRenderTarget2DResource *>(RenderTarget.Resource);
39 FTexture2DRHIRef Texture = RenderResource->GetRenderTargetTexture();
40 if (!Texture)
41 {
42 return; // 如果纹理不可用,则退出。
43 }
44
45 // 创建一个 GPU 纹理读取对象。
46 auto BackBufferReadback = std::make_unique<FRHIGPUTextureReadback>(TEXT("CameraBufferReadback"));
47 FIntPoint BackBufferSize = Texture->GetSizeXY();
48 EPixelFormat BackBufferPixelFormat = Texture->GetFormat();
49
50 // 将纹理数据复制到读取对象。
51 {
52 TRACE_CPUPROFILER_EVENT_SCOPE_STR("EnqueueCopy");
53 BackBufferReadback->EnqueueCopy(RHICmdList,
54 Texture,
55 FResolveRect(0, 0, BackBufferSize.X, BackBufferSize.Y));
56 }
57
58 // 强制 Vulkan 刷新 RHI 状态。
59 {
60 FRenderQueryRHIRef Query = RHICreateRenderQuery(RQT_AbsoluteTime);
61 TRACE_CPUPROFILER_EVENT_SCOPE_STR("create query");
62 RHICmdList.EndRenderQuery(Query);
63 TRACE_CPUPROFILER_EVENT_SCOPE_STR("Flush");
64 RHICmdList.ImmediateFlush(EImmediateFlushType::FlushRHIThread);
65 TRACE_CPUPROFILER_EVENT_SCOPE_STR("query result");
66 uint64 OldAbsTime = 0;
67 RHICmdList.GetRenderQueryResult(Query, OldAbsTime, true);
68 }
69
70 // 异步处理读取的数据。
71 AsyncTask(ENamedThreads::HighTaskPriority, [=, Readback=std::move(BackBufferReadback)]() mutable {
72 {
73 TRACE_CPUPROFILER_EVENT_SCOPE_STR("Wait GPU transfer");
74 while (!Readback->IsReady())
75 {
76 std::this_thread::yield(); // 在读取完成之前让线程让出资源。
77 }
78 }
79
80 {
81 TRACE_CPUPROFILER_EVENT_SCOPE_STR("Readback data");
82 FPixelFormatInfo PixelFormat = GPixelFormats[BackBufferPixelFormat];
83 uint32 ExpectedRowBytes = BackBufferSize.X * PixelFormat.BlockBytes;
84 int32 Size = (BackBufferSize.Y * (PixelFormat.BlockBytes * BackBufferSize.X));
85 void* LockedData = Readback->Lock(Size);
86 if (LockedData)
87 {
88 // 将数据传递给回调函数。
89 FuncForSending(LockedData, Size, Offset, ExpectedRowBytes);
90 }
91 Readback->Unlock();
92 Readback.reset();
93 }
94 });
95}
96
97/**
98 * 将像素数据从渲染目标写入数组。
99 *
100 * @param RenderTarget 要读取的纹理渲染目标。
101 * @param BitMap 用于存储像素数据的数组。
102 * @return 如果成功,返回 true;否则返回 false。
103 */
105 UTextureRenderTarget2D &RenderTarget,
106 TArray<FColor> &BitMap)
107{
108 check(IsInGameThread());
109 FTextureRenderTargetResource *RTResource =
110 RenderTarget.GameThread_GetRenderTargetResource();
111 if (RTResource == nullptr)
112 {
113 UE_LOG(LogCarla, Error, TEXT("FPixelReader: UTextureRenderTarget2D missing render target"));
114 return false;
115 }
116 FReadSurfaceDataFlags ReadPixelFlags(RCM_UNorm);
117 ReadPixelFlags.SetLinearToGamma(true);
118 return RTResource->ReadPixels(BitMap, ReadPixelFlags);
119}
120
121/**
122 * 从渲染目标提取像素数据,并将其封装为唯一指针。
123 *
124 * @param RenderTarget 要读取的纹理渲染目标。
125 * @return 包含像素数据的唯一指针。
126 */
127TUniquePtr<TImagePixelData<FColor>> FPixelReader::DumpPixels(
128 UTextureRenderTarget2D &RenderTarget)
129{
130 const FIntPoint DestSize(RenderTarget.GetSurfaceWidth(), RenderTarget.GetSurfaceHeight());
131 TUniquePtr<TImagePixelData<FColor>> PixelData = MakeUnique<TImagePixelData<FColor>>(DestSize);
132 TArray<FColor> Pixels(PixelData->Pixels.GetData(), PixelData->Pixels.Num());
133 if (!WritePixelsToArray(RenderTarget, Pixels))
134 {
135 return nullptr; // 如果写入像素失败,则返回 null。
136 }
137 PixelData->Pixels = Pixels;
138 return PixelData;
139}
140
141/**
142 * 将渲染目标中的像素数据异步保存到磁盘。
143 *
144 * @param RenderTarget 要读取的纹理渲染目标。
145 * @param FilePath 保存图像的文件路径。
146 * @return 一个指示操作成功的未来值。
147 */
149 UTextureRenderTarget2D &RenderTarget,
150 const FString &FilePath)
151{
152 return SavePixelsToDisk(DumpPixels(RenderTarget), FilePath);
153}
154
155/**
156 * 异步保存像素数据到磁盘。
157 *
158 * @param PixelData 要保存的像素数据。
159 * @param FilePath 保存图像的文件路径。
160 * @return 一个指示操作成功的未来值。
161 */
163 TUniquePtr<TImagePixelData<FColor>> PixelData,
164 const FString &FilePath)
165{
166 TUniquePtr<FImageWriteTask> ImageTask = MakeUnique<FImageWriteTask>();
167 ImageTask->PixelData = MoveTemp(PixelData);
168 ImageTask->Filename = FilePath;
169 ImageTask->Format = EImageFormat::PNG;
170 ImageTask->CompressionQuality = (int32) EImageCompressionQuality::Default;
171 ImageTask->bOverwriteFile = true;
172 ImageTask->PixelPreProcessors.Add(TAsyncAlphaWrite<FColor>(255));
173
174 FHighResScreenshotConfig &HighResScreenshotConfig = GetHighResScreenshotConfig();
175 return HighResScreenshotConfig.ImageWriteQueue->Enqueue(MoveTemp(ImageTask));
176}
UE_LOG(LogCarla, Log, TEXT("UActorDispatcher::Destroying actor: '%s' %x"), *Id, Actor)
static bool WritePixelsToArray(UTextureRenderTarget2D &RenderTarget, TArray< FColor > &BitMap)
将 RenderTarget 中的像素复制到 BitMap 中。
std::function< void(void *, uint32, uint32, uint32)> Payload
Definition PixelReader.h:38
static TUniquePtr< TImagePixelData< FColor > > DumpPixels(UTextureRenderTarget2D &RenderTarget)
转储 RenderTarget 中的像素。
static void WritePixelsToBuffer(const UTextureRenderTarget2D &RenderTarget, uint32 Offset, FRHICommandListImmediate &InRHICmdList, FPixelReader::Payload FuncForSending)
将 RenderTarget 中的像素复制到 Buffer。
static TFuture< bool > SavePixelsToDisk(UTextureRenderTarget2D &RenderTarget, const FString &FilePath)
异步保存 RenderTarget 中的像素到磁盘。