1 #pragma once
2 
3 #include <mbgl/algorithm/generate_clip_ids.hpp>
4 #include <mbgl/math/log2.hpp>
5 #include <mbgl/util/logging.hpp>
6 
7 namespace mbgl {
8 namespace algorithm {
9 
10 template <typename Renderable>
update(std::vector<std::reference_wrapper<Renderable>> renderables)11 void ClipIDGenerator::update(std::vector<std::reference_wrapper<Renderable>> renderables) {
12     std::size_t size = 0;
13 
14     std::sort(renderables.begin(), renderables.end(),
15               [](const auto& a, const auto& b) { return a.get().id < b.get().id; });
16 
17     const auto end = renderables.end();
18     for (auto it = renderables.begin(); it != end; it++) {
19         auto& renderable = it->get();
20         if (!renderable.used || !renderable.needsClipping) {
21             continue;
22         }
23 
24         renderable.clip = {};
25         Leaf leaf{ renderable.clip };
26 
27         // Try to add all remaining ids as children. We sorted the tile list
28         // by z earlier, so all preceding items cannot be children of the current
29         // tile. We also compute the lower bound of the next wrap, because items of the next wrap
30         // can never be children of the current wrap.
31         auto child_it = std::next(it);
32         const auto children_end = std::lower_bound(
33             child_it, end, UnwrappedTileID{ static_cast<int16_t>(renderable.id.wrap + 1), { 0, 0, 0 } },
34             [](auto& a, auto& b) { return a.get().id < b; });
35         for (; child_it != children_end; ++child_it) {
36             auto& childTileID = child_it->get().id;
37             if (childTileID.isChildOf(it->get().id)) {
38                 leaf.add(childTileID.canonical);
39             }
40         }
41 
42         // Find a leaf with matching children.
43         for (auto its = pool.equal_range(renderable.id); its.first != its.second; ++its.first) {
44             auto& existing = its.first->second;
45             if (existing == leaf) {
46                 leaf.clip = existing.clip;
47                 break;
48             }
49         }
50         if (leaf.clip.reference.none()) {
51             // We haven't found an existing clip ID
52             size++;
53         }
54 
55         pool.emplace(renderable.id, std::move(leaf));
56     }
57 
58     if (size > 0) {
59         const uint32_t bit_count = util::ceil_log2(size + 1);
60         const std::bitset<8> mask = uint64_t(((1ul << bit_count) - 1) << bit_offset);
61 
62         // We are starting our count with 1 since we need at least 1 bit set to distinguish between
63         // areas without any tiles whatsoever and the current area.
64         uint8_t count = 1;
65         for (auto& it : renderables) {
66             auto& renderable = it.get();
67             if (!renderable.used) {
68                 continue;
69             }
70             renderable.clip.mask |= mask;
71 
72             // Assign only to clip IDs that have no value yet.
73             if (renderable.clip.reference.none()) {
74                 renderable.clip.reference = uint32_t(count++) << bit_offset;
75             }
76         }
77 
78         bit_offset += bit_count;
79     }
80 
81     // Prevent this warning from firing on every frame,
82     // which can be expensive in some platforms.
83     static bool warned = false;
84 
85     if (!warned && bit_offset > 8) {
86         Log::Error(Event::OpenGL, "stencil mask overflow");
87         warned = true;
88     }
89 }
90 
91 } // namespace algorithm
92 } // namespace mbgl
93