CARLA
Loading...
Searching...
No Matches
test_multigpu_world_state.cpp
Go to the documentation of this file.
1// Copyright (c) 2026 Computer Vision Center (CVC) at the Universitat Autonoma de Barcelona (UAB).
2// This work is licensed under the terms of the MIT license.
3// For a copy, see <https://opensource.org/licenses/MIT>.
4
5#include "test.h"
6
9
10#include <cstring>
11#include <sstream>
12#include <string>
13#include <vector>
14
21
22namespace {
23
24 template <typename Packet>
25 bool RoundTrip(const Packet &sent, Packet &got) {
26 std::ostringstream out;
27 sent.Write(out);
28 const std::string bytes = out.str();
29 if (static_cast<uint8_t>(bytes[0]) != Packet::kPacketId) {
30 return false;
31 }
32 uint32_t size = 0u;
33 std::memcpy(&size, bytes.data() + 1, sizeof(size));
34 std::istringstream in(bytes.substr(carla::multigpu::kFrameDataHeaderSize));
35 return got.Read(in, size);
36 }
37
38} // namespace
39
40TEST(MultiGpuWorldState, globals_round_trip) {
41 WorldGlobals sent;
42 sent.map_layers = 0x0005u;
43 sent.imu_gravity = 3.71f;
44 sent.day_night_cycle = false;
45 sent.has_day_time_state = true;
46 sent.last_is_day = false;
47 sent.publish_tf = false;
48 WorldGlobals got;
49 ASSERT_TRUE(RoundTrip(sent, got));
50 EXPECT_EQ(got.map_layers, 0x0005u);
51 EXPECT_EQ(got.imu_gravity, 3.71f);
52 EXPECT_FALSE(got.day_night_cycle);
53 EXPECT_TRUE(got.has_day_time_state);
54 EXPECT_FALSE(got.last_is_day);
55 EXPECT_FALSE(got.publish_tf);
56}
57
58TEST(MultiGpuWorldState, objects_round_trip) {
59 WorldObjects sent;
60 sent.disabled_environment_objects = std::vector<uint64_t>{3u, 99u, 0xFFFFFFFFFFull};
61 WorldObjects got;
62 ASSERT_TRUE(RoundTrip(sent, got));
63 ASSERT_TRUE(got.disabled_environment_objects.has_value());
65}
66
67TEST(MultiGpuWorldState, an_empty_set_is_not_an_absent_one) {
68 // Everything enabled again must reach the secondaries as an empty set.
69 WorldObjects sent;
70 sent.disabled_environment_objects = std::vector<uint64_t>{};
71 WorldObjects got;
72 ASSERT_TRUE(RoundTrip(sent, got));
73 ASSERT_TRUE(got.disabled_environment_objects.has_value());
74 EXPECT_TRUE(got.disabled_environment_objects->empty());
75
76 WorldObjects none;
77 ASSERT_TRUE(RoundTrip(WorldObjects{}, none));
78 EXPECT_FALSE(none.disabled_environment_objects.has_value());
79}
80
81TEST(MultiGpuWorldState, objects_with_an_unknown_field_keep_the_set) {
82 std::ostringstream payload;
83 carla::multigpu::WriteField(payload, 7u, std::string("future"));
84 std::ostringstream ids;
85 const uint32_t count = 1u;
86 const uint64_t id = 42u;
87 ids.write(reinterpret_cast<const char *>(&count), sizeof(count));
88 ids.write(reinterpret_cast<const char *>(&id), sizeof(id));
90 const std::string body = payload.str();
91 std::istringstream in(body);
92 WorldObjects got;
93 ASSERT_TRUE(got.Read(in, static_cast<uint32_t>(body.size())));
94 ASSERT_TRUE(got.disabled_environment_objects.has_value());
95 EXPECT_EQ(*got.disabled_environment_objects, std::vector<uint64_t>{42u});
96}
97
98TEST(MultiGpuWorldState, an_impossible_object_count_fails) {
99 std::ostringstream payload;
100 std::ostringstream ids;
101 const uint32_t count = 1000000u;
102 ids.write(reinterpret_cast<const char *>(&count), sizeof(count));
104 const std::string body = payload.str();
105 std::istringstream in(body);
106 WorldObjects got;
107 EXPECT_FALSE(got.Read(in, static_cast<uint32_t>(body.size())));
108}
109
110TEST(MultiGpuWorldState, appearance_round_trip) {
111 ActorAppearances sent;
112 ActorAppearance prop;
113 prop.actor_id = 12u;
114 prop.scale = std::array<double, 3>{2.0, 2.0, 0.5};
115 prop.collisions = false;
116 ActorAppearance hidden;
117 hidden.actor_id = 13u;
118 hidden.hidden = true;
119 sent.actors = {prop, hidden};
121 ASSERT_TRUE(RoundTrip(sent, got));
122 ASSERT_EQ(got.actors.size(), 2u);
123 EXPECT_EQ(got.actors[0].scale, prop.scale);
124 EXPECT_EQ(got.actors[0].collisions, std::optional<bool>(false));
125 EXPECT_FALSE(got.actors[0].hidden.has_value());
126 EXPECT_EQ(got.actors[1].hidden, std::optional<bool>(true));
127}
128
129TEST(MultiGpuWorldState, layer_diff) {
130 const auto diff = ComputeMapLayerDiff(0x00FFu, 0x0F0Fu);
131 EXPECT_EQ(diff.first, 0x0F00u);
132 EXPECT_EQ(diff.second, 0x00F0u);
133 EXPECT_EQ(ComputeMapLayerDiff(0x1234u, 0x1234u), (std::pair<uint16_t, uint16_t>{0u, 0u}));
134}
135
136TEST(MultiGpuWorldState, diff_sorted_ids) {
137 const auto diff = DiffSortedIds({1u, 3u, 5u}, {3u, 4u, 5u, 6u});
138 EXPECT_EQ(diff.first, (std::vector<uint64_t>{4u, 6u}));
139 EXPECT_EQ(diff.second, (std::vector<uint64_t>{1u}));
140}
constexpr std::size_t kFrameDataHeaderSize
Frame data (the SEND_FRAME payload) is a sequence of packets [uint8 id][uint32 payload size][payload]...
void WriteField(std::ostream &out, uint8_t kind, const std::string &value)
std::pair< std::vector< uint64_t >, std::vector< uint64_t > > DiffSortedIds(const std::vector< uint64_t > &current, const std::vector< uint64_t > &desired)
Ids in desired and not in current (first), and the other way round (second).
Definition worldState.h:236
std::pair< uint16_t, uint16_t > ComputeMapLayerDiff(uint16_t current, uint16_t desired)
The map layers to load and to unload to go from current to desired.
Definition worldState.h:230
An actor's appearance on the primary that a mirror does not get from its spawn attributes or pose.
Definition worldState.h:140
std::optional< bool > hidden
Definition worldState.h:144
std::optional< std::array< double, 3 > > scale
Definition worldState.h:142
std::optional< bool > collisions
Definition worldState.h:143
Frame data packet 30, on change and on every full resync.
Definition worldState.h:148
std::vector< ActorAppearance > actors
Definition worldState.h:158
Frame data packet 28, on every frame: world-wide state a client can change on the primary that change...
Definition worldState.h:26
float imu_gravity
The IMU's gravity, m/s^2.
Definition worldState.h:36
bool publish_tf
ROS 2: whether TF frames are published.
Definition worldState.h:45
uint16_t map_layers
rpc::MapLayer bits of the layers loaded.
Definition worldState.h:33
bool day_night_cycle
UCarlaLightSubsystem: whether street lights follow the sun, and the last day/night state it broadcast...
Definition worldState.h:40
Frame data packet 29, on change and on every full resync: map objects whose state is not part of any ...
Definition worldState.h:84
bool Read(std::istream &in, uint32_t size)
Definition worldState.h:112
void Write(std::ostream &out) const
Definition worldState.h:99
@ kDisabledEnvironmentObjects
The complete, sorted set of environment objects disabled.
Definition worldState.h:90
std::optional< std::vector< uint64_t > > disabled_environment_objects
Definition worldState.h:93
TEST(MultiGpuWorldState, globals_round_trip)