CARLA
 
载入中...
搜索中...
未找到
PixelReader.h
浏览该文件的文档.
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#pragma once
8
9#include "CoreGlobals.h"
10#include "Engine/TextureRenderTarget2D.h"
11#include "Runtime/ImageWriteQueue/Public/ImagePixelData.h"
12
13#ifdef _WIN32
14 #define WIN32_LEAN_AND_MEAN
15 #include <D3d12.h>
16#endif
17
19
21#include <carla/Logging.h>
22#include <carla/Buffer.h>
23#include <carla/BufferView.h>
26
27// =============================================================================
28// -- FPixelReader -------------------------------------------------------------
29// =============================================================================
30
31/// Utils for reading pixels from UTextureRenderTarget2D.
32///
33/// @todo This class only supports PF_R8G8B8A8 format.
35{
36public:
37
38 using Payload = std::function<void(void *, uint32, uint32, uint32)>;
39
40 /// Copy the pixels in @a RenderTarget into @a BitMap.
41 ///
42 /// @pre To be called from game-thread.
43 static bool WritePixelsToArray(
44 UTextureRenderTarget2D &RenderTarget,
45 TArray<FColor> &BitMap);
46
47 /// Dump the pixels in @a RenderTarget.
48 ///
49 /// @pre To be called from game-thread.
50 static TUniquePtr<TImagePixelData<FColor>> DumpPixels(
51 UTextureRenderTarget2D &RenderTarget);
52
53 /// Asynchronously save the pixels in @a RenderTarget to disk.
54 ///
55 /// @pre To be called from game-thread.
56 static TFuture<bool> SavePixelsToDisk(
57 UTextureRenderTarget2D &RenderTarget,
58 const FString &FilePath);
59
60 /// Asynchronously save the pixels in @a PixelData to disk.
61 ///
62 /// @pre To be called from game-thread.
63 static TFuture<bool> SavePixelsToDisk(
64 TUniquePtr<TImagePixelData<FColor>> PixelData,
65 const FString &FilePath);
66
67 /// Convenience function to enqueue a render command that sends the pixels
68 /// down the @a Sensor's data stream. It expects a sensor derived from
69 /// ASceneCaptureSensor or compatible.
70 ///
71 /// Note that the serializer needs to define a "header_offset" that it's
72 /// allocated in front of the buffer.
73 ///
74 /// @pre To be called from game-thread.
75 template <typename TSensor, typename TPixel>
76 static void SendPixelsInRenderThread(TSensor &Sensor, bool use16BitFormat = false, std::function<TArray<TPixel>(void *, uint32)> Conversor = {});
77
78 /// Copy the pixels in @a RenderTarget into @a Buffer.
79 ///
80 /// @pre To be called from render-thread.
81 static void WritePixelsToBuffer(
82 const UTextureRenderTarget2D &RenderTarget,
83 uint32 Offset,
84 FRHICommandListImmediate &InRHICmdList,
85 FPixelReader::Payload FuncForSending);
86
87};
88
89// =============================================================================
90// -- FPixelReader::SendPixelsInRenderThread -----------------------------------
91// =============================================================================
92
93template <typename TSensor, typename TPixel>
94void FPixelReader::SendPixelsInRenderThread(TSensor &Sensor, bool use16BitFormat, std::function<TArray<TPixel>(void *, uint32)> Conversor)
95{
96 TRACE_CPUPROFILER_EVENT_SCOPE(FPixelReader::SendPixelsInRenderThread);
97 check(Sensor.CaptureRenderTarget != nullptr);
98
99 if (!Sensor.HasActorBegunPlay() || Sensor.IsPendingKill())
100 {
101 return;
102 }
103
104 /// Blocks until the render thread has finished all it's tasks.
105 Sensor.EnqueueRenderSceneImmediate();
106
107 // Enqueue a command in the render-thread that will write the image buffer to
108 // the data stream. The stream is created in the capture thus executed in the
109 // game-thread.
110 ENQUEUE_RENDER_COMMAND(FWritePixels_SendPixelsInRenderThread)
111 (
112 [&Sensor, use16BitFormat, Conversor = std::move(Conversor)](auto &InRHICmdList) mutable
113 {
114 TRACE_CPUPROFILER_EVENT_SCOPE_STR("FWritePixels_SendPixelsInRenderThread");
115
116 /// @todo Can we make sure the sensor is not going to be destroyed?
117 if (!Sensor.IsPendingKill())
118 {
119 FPixelReader::Payload FuncForSending =
120 [&Sensor, Frame = FCarlaEngine::GetFrameCounter(), Conversor = std::move(Conversor)](void *LockedData, uint32 Size, uint32 Offset, uint32 ExpectedRowBytes)
121 {
122 if (Sensor.IsPendingKill()) return;
123
124 TArray<TPixel> Converted;
125
126 // optional conversion of data
127 if (Conversor)
128 {
129 TRACE_CPUPROFILER_EVENT_SCOPE_STR("Data conversion");
130 Converted = Conversor(LockedData, Size);
131 LockedData = reinterpret_cast<void *>(Converted.GetData());
132 Size = Converted.Num() * Converted.GetTypeSize();
133 }
134
135 auto Stream = Sensor.GetDataStream(Sensor);
136 Stream.SetFrameNumber(Frame);
137 auto Buffer = Stream.PopBufferFromPool();
138
139 uint32 CurrentRowBytes = ExpectedRowBytes;
140
141#ifdef _WIN32
142 // DirectX uses additional bytes to align each row to 256 boundry,
143 // so we need to remove that extra data
144 if (IsD3DPlatform(GMaxRHIShaderPlatform, false))
145 {
146 CurrentRowBytes = Align(ExpectedRowBytes, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
147 if (ExpectedRowBytes != CurrentRowBytes)
148 {
149 TRACE_CPUPROFILER_EVENT_SCOPE_STR("Buffer Copy (windows, row by row)");
150 Buffer.reset(Offset + Size);
151 auto DstRow = Buffer.begin() + Offset;
152 const uint8 *SrcRow = reinterpret_cast<uint8 *>(LockedData);
153 uint32 i = 0;
154 while (i < Size)
155 {
156 FMemory::Memcpy(DstRow, SrcRow, ExpectedRowBytes);
157 DstRow += ExpectedRowBytes;
158 SrcRow += CurrentRowBytes;
159 i += ExpectedRowBytes;
160 }
161 }
162 }
163#endif // _WIN32
164
165 if (ExpectedRowBytes == CurrentRowBytes)
166 {
167 check(ExpectedRowBytes == CurrentRowBytes);
168 TRACE_CPUPROFILER_EVENT_SCOPE_STR("Buffer Copy");
169 Buffer.copy_from(Offset, boost::asio::buffer(LockedData, Size));
170 }
171
172 {
173 // send
174 TRACE_CPUPROFILER_EVENT_SCOPE_STR("Sending buffer");
175 if(Buffer.data())
176 {
177 // serialize data
178 carla::Buffer BufferReady(std::move(carla::sensor::SensorRegistry::Serialize(Sensor, std::move(Buffer))));
179 carla::SharedBufferView BufView = carla::BufferView::CreateFrom(std::move(BufferReady));
180
181 // ROS2
182 #if defined(WITH_ROS2)
183 auto ROS2 = carla::ros2::ROS2::GetInstance();
184 if (ROS2->IsEnabled())
185 {
186 TRACE_CPUPROFILER_EVENT_SCOPE_STR("ROS2 Send PixelReader");
187 auto StreamId = carla::streaming::detail::token_type(Sensor.GetToken()).get_stream_id();
188 auto Res = std::async(std::launch::async, [&Sensor, ROS2, &Stream, StreamId, BufView]()
189 {
190 // get resolution of camera
191 int W = -1, H = -1;
192 float Fov = -1.0f;
193 auto WidthOpt = Sensor.GetAttribute("image_size_x");
194 if (WidthOpt.has_value())
195 W = FCString::Atoi(*WidthOpt->Value);
196 auto HeightOpt = Sensor.GetAttribute("image_size_y");
197 if (HeightOpt.has_value())
198 H = FCString::Atoi(*HeightOpt->Value);
199 auto FovOpt = Sensor.GetAttribute("fov");
200 if (FovOpt.has_value())
201 Fov = FCString::Atof(*FovOpt->Value);
202 // send data to ROS2
203 AActor* ParentActor = Sensor.GetAttachParentActor();
204 if (ParentActor)
205 {
206 FTransform LocalTransformRelativeToParent = Sensor.GetActorTransform().GetRelativeTransform(ParentActor->GetActorTransform());
207 ROS2->ProcessDataFromCamera(Stream.GetSensorType(), StreamId, LocalTransformRelativeToParent, W, H, Fov, BufView, &Sensor);
208 }
209 else
210 {
211 ROS2->ProcessDataFromCamera(Stream.GetSensorType(), StreamId, Stream.GetSensorTransform(), W, H, Fov, BufView, &Sensor);
212 }
213 });
214 }
215 #endif
216
217 // network
218 SCOPE_CYCLE_COUNTER(STAT_CarlaSensorStreamSend);
219 TRACE_CPUPROFILER_EVENT_SCOPE_STR("Stream Send");
220 Stream.Send(Sensor, BufView);
221 }
222 }
223 };
224
226 *Sensor.CaptureRenderTarget,
228 InRHICmdList,
229 std::move(FuncForSending));
230 }
231 }
232 );
233
234 // Blocks until the render thread has finished all it's tasks
235 Sensor.WaitForRenderThreadToFinish();
236}
static uint64_t GetFrameCounter()
Definition CarlaEngine.h:65
Utils for reading pixels from UTextureRenderTarget2D.
Definition PixelReader.h:35
static bool WritePixelsToArray(UTextureRenderTarget2D &RenderTarget, TArray< FColor > &BitMap)
Copy the pixels in RenderTarget into BitMap.
static void SendPixelsInRenderThread(TSensor &Sensor, bool use16BitFormat=false, std::function< TArray< TPixel >(void *, uint32)> Conversor={})
Convenience function to enqueue a render command that sends the pixels down the Sensor's data stream.
Definition PixelReader.h:94
std::function< void(void *, uint32, uint32, uint32)> Payload
Definition PixelReader.h:38
static TUniquePtr< TImagePixelData< FColor > > DumpPixels(UTextureRenderTarget2D &RenderTarget)
Dump the pixels in RenderTarget.
static void WritePixelsToBuffer(const UTextureRenderTarget2D &RenderTarget, uint32 Offset, FRHICommandListImmediate &InRHICmdList, FPixelReader::Payload FuncForSending)
Copy the pixels in RenderTarget into Buffer.
static TFuture< bool > SavePixelsToDisk(UTextureRenderTarget2D &RenderTarget, const FString &FilePath)
Asynchronously save the pixels in RenderTarget to disk.
static std::shared_ptr< BufferView > CreateFrom(Buffer &&buffer)
Definition BufferView.h:56
A piece of raw data.
static std::shared_ptr< ROS2 > GetInstance()
Definition ROS2.h:51
static Buffer Serialize(Sensor &sensor, Args &&... args)
Serialize the arguments provided into a Buffer by calling to the serializer registered for the given ...
Serializes a stream endpoint.
std::shared_ptr< BufferView > SharedBufferView
Definition BufferView.h:151
typename detail::CompileTimeTypeMapImpl< sizeof...(Items), Items... >::template get< InKey > get