45 using Payload = std::function<void(
void *, uint32, uint32, uint32)>;
51 UTextureRenderTarget2D &RenderTarget,
52 TArray<FColor> &BitMap);
57 static TUniquePtr<TImagePixelData<FColor>>
DumpPixels(
58 UTextureRenderTarget2D &RenderTarget);
64 UTextureRenderTarget2D &RenderTarget,
65 const FString &FilePath);
71 TUniquePtr<TImagePixelData<FColor>> PixelData,
72 const FString &FilePath);
82 template <
typename TSensor,
typename TPixel>
83 static void SendPixelsInRenderThread(TSensor &Sensor,
bool use16BitFormat =
false, std::function<TArray<TPixel>(
void *, uint32)> Conversor = {});
91 UTextureRenderTarget2D &RenderTarget,
93 FRHICommandListImmediate &InRHICmdList,
107 check(Sensor.CaptureRenderTarget !=
nullptr);
109 if (!Sensor.HasActorBegunPlay() || !IsValidChecked(&Sensor))
115 Sensor.EnqueueRenderSceneImmediate();
121 ENQUEUE_RENDER_COMMAND(FWritePixels_SendPixelsInRenderThread)
124 Timestamp = Sensor.GetEpisode().GetElapsedGameTime(), Transform = Sensor.GetActorTransform()](
auto &InRHICmdList)
mutable
126 TRACE_CPUPROFILER_EVENT_SCOPE_STR(
"FWritePixels_SendPixelsInRenderThread");
129 if (IsValidChecked(&Sensor))
132 [&Sensor, Frame, Timestamp, Transform, Conversor = std::move(Conversor)]
133 (
void *LockedData, uint32 Size, uint32 Offset, uint32 ExpectedRowBytes)
135 if (!IsValidChecked(&Sensor))
138 TArray<TPixel> Converted;
143 TRACE_CPUPROFILER_EVENT_SCOPE_STR(
"Data conversion");
144 Converted = Conversor(LockedData, Size);
145 LockedData =
reinterpret_cast<void *
>(Converted.GetData());
146 Size = Converted.Num() * Converted.GetTypeSize();
149 auto Stream = Sensor.GetDataStream(Sensor);
150 Stream.SetFrameNumber(Frame);
151 Stream.SetTimestamp(Timestamp);
152 Stream.SetTransform(Transform);
153 auto Buffer = Stream.PopBufferFromPool();
155 uint32 CurrentRowBytes = ExpectedRowBytes;
160 if (IsD3DPlatform(GMaxRHIShaderPlatform) && Sensor.AreClientsListening())
162 CurrentRowBytes = Align(ExpectedRowBytes, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
163 if (ExpectedRowBytes != CurrentRowBytes)
165 TRACE_CPUPROFILER_EVENT_SCOPE_STR(
"Buffer Copy (windows, row by row)");
166 Buffer.reset(Offset + Size);
167 auto DstRow = Buffer.begin() + Offset;
168 const uint8 *SrcRow =
reinterpret_cast<uint8 *
>(LockedData);
172 FMemory::Memcpy(DstRow, SrcRow, ExpectedRowBytes);
173 DstRow += ExpectedRowBytes;
174 SrcRow += CurrentRowBytes;
175 i += ExpectedRowBytes;
181 if (ExpectedRowBytes == CurrentRowBytes)
183 check(ExpectedRowBytes == CurrentRowBytes);
184 TRACE_CPUPROFILER_EVENT_SCOPE_STR(
"Buffer Copy");
185 Buffer.copy_from(Offset, boost::asio::buffer(LockedData, Size));
190 TRACE_CPUPROFILER_EVENT_SCOPE_STR(
"Sending buffer");
198 #if defined(WITH_ROS2)
200 if (ROS2->IsEnabled())
202 TRACE_CPUPROFILER_EVENT_SCOPE_STR(
"ROS2 Send PixelReader");
204 auto Res = std::async(std::launch::async, [&Sensor, ROS2, &Stream, StreamId, BufView]()
209 auto WidthOpt = Sensor.GetAttribute(
"image_size_x");
210 if (WidthOpt.has_value())
211 W = FCString::Atoi(*WidthOpt->Value);
212 auto HeightOpt = Sensor.GetAttribute(
"image_size_y");
213 if (HeightOpt.has_value())
214 H = FCString::Atoi(*HeightOpt->Value);
215 auto FovOpt = Sensor.GetAttribute(
"fov");
216 if (FovOpt.has_value())
217 Fov = FCString::Atof(*FovOpt->Value);
219 AActor* ParentActor = Sensor.GetAttachParentActor();
222 FTransform LocalTransformRelativeToParent = Sensor.GetActorTransform().GetRelativeTransform(ParentActor->GetActorTransform());
223 ROS2->ProcessDataFromCamera(Stream.GetSensorType(), StreamId, LocalTransformRelativeToParent, W, H, Fov, BufView, &Sensor);
227 ROS2->ProcessDataFromCamera(Stream.GetSensorType(), StreamId, Stream.GetSensorTransform(), W, H, Fov, BufView, &Sensor);
233 if (Sensor.AreClientsListening())
236 SCOPE_CYCLE_COUNTER(STAT_CarlaSensorStreamSend);
237 TRACE_CPUPROFILER_EVENT_SCOPE_STR(
"Stream Send");
238 Stream.Send(Sensor, BufView);
245 *Sensor.CaptureRenderTarget,
248 std::move(FuncForSending),
249 Sensor.GetReadbackPool());
256 Sensor.WaitForRenderThreadToFinish();