• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "common/rs_occlusion_region.h"
17 #include "common/rs_occlusion_region_helper.h"
18 
19 #include <map>
20 #include <set>
21 #include "platform/common/rs_innovation.h"
22 #include "platform/common/rs_log.h"
23 
24 namespace OHOS {
25 namespace Rosen {
26 namespace Occlusion {
27 namespace {
Align(int num,int alignmentSize,bool upward)28 inline int Align(int num, int alignmentSize, bool upward)
29 {
30     if (alignmentSize <= 1) {
31         return num;
32     }
33     int remainder = num % alignmentSize;
34     if (remainder == 0) {
35         return num;
36     }
37     return (num > 0 && upward) ? (num + (alignmentSize - remainder)) : (num - remainder);
38 }
39 
AlignUp(int num,int alignmentSize)40 inline int AlignUp(int num, int alignmentSize)
41 {
42     return Align(num, alignmentSize, true);
43 }
44 
AlignDown(int num,int alignmentSize)45 inline int AlignDown(int num, int alignmentSize)
46 {
47     return Align(num, alignmentSize, false);
48 }
49 }
50 
operator <<(std::ostream & os,const Rect & r)51 std::ostream& operator<<(std::ostream& os, const Rect& r)
52 {
53     os << "{" << r.left_ << "," << r.top_ << "," << r.right_ << "," << r.bottom_ << "}";
54     return os;
55 }
56 
EventSortByY(const Event & e1,const Event & e2)57 bool EventSortByY(const Event& e1, const Event& e2)
58 {
59     if (e1.y_ == e2.y_) {
60         return e1.type_ < e2.type_;
61     }
62     return e1.y_ < e2.y_;
63 }
64 
Rect(int l,int t,int r,int b,bool checkValue)65 Rect::Rect(int l, int t, int r, int b, bool checkValue)
66     : left_(l), top_(t), right_(r), bottom_(b)
67 {
68     if (!checkValue) {
69         return;
70     }
71     CheckAndCorrectValue();
72     if (left_ != l || top_ != t || right_ != r || bottom_ != b) {
73         RS_LOGD("Occlusion::Rect initialized with invalid value, ltrb[%{public}d, %{public}d, %{public}d, "
74             "%{public}d], should in range [%{public}d, %{public}d]",
75             l, t, r, b, MIN_REGION_VALUE, MAX_REGION_VALUE);
76     }
77 }
78 
Rect(const RectI & r,bool checkValue)79 Rect::Rect(const RectI& r, bool checkValue)
80     : left_(r.left_), top_(r.top_), right_(r.GetRight()), bottom_(r.GetBottom())
81 {
82     if (!checkValue) {
83         return;
84     }
85     CheckAndCorrectValue();
86     if (left_ != r.left_ || top_ != r.top_ || right_ != r.GetRight() || bottom_ != r.GetBottom()) {
87         RS_LOGD("Occlusion::Rect initialized with invalid value, ltrb[%{public}d, %{public}d, %{public}d, "
88             "%{public}d], should in range [%{public}d, %{public}d]",
89             r.left_, r.top_, r.GetRight(), r.GetBottom(), MIN_REGION_VALUE, MAX_REGION_VALUE);
90     }
91 }
92 
Update(int updateStart,int updateEnd,Event::Type type)93 void Node::Update(int updateStart, int updateEnd, Event::Type type)
94 {
95     if (updateStart >= updateEnd) {
96         return;
97     }
98     if (updateStart == start_ && updateEnd == end_) {
99         if (type == Event::Type::OPEN || type == Event::Type::CLOSE) {
100             positive_count_ += type;
101         } else {
102             negative_count_ += type;
103         }
104     } else {
105         if (left_ == nullptr) {
106             left_ = new Node { start_, mid_ };
107         }
108         if (right_ == nullptr) {
109             right_ = new Node { mid_, end_ };
110         }
111         // In case the heap memory allocation fails
112         if (left_ != nullptr) {
113             left_->Update(updateStart, mid_ < updateEnd ? mid_ : updateEnd, type);
114         }
115         if (right_ != nullptr) {
116             right_->Update(mid_ > updateStart ? mid_ : updateStart, updateEnd, type);
117         }
118     }
119 }
120 
GetAndRange(std::vector<Range> & res,bool isParentNodePos=false,bool isParentNodeNeg=false)121 void Node::GetAndRange(std::vector<Range>& res, bool isParentNodePos = false, bool isParentNodeNeg = false)
122 {
123     bool isPos = isParentNodePos || (positive_count_ > 0);
124     bool isNeg = isParentNodeNeg || (negative_count_ > 0);
125     if (isPos && isNeg) {
126         PushRange(res);
127     } else {
128         if (left_ != nullptr) {
129             left_->GetAndRange(res, isPos, isNeg);
130         }
131         if (right_ != nullptr) {
132             right_->GetAndRange(res, isPos, isNeg);
133         }
134     }
135 }
136 
GetOrRange(std::vector<Range> & res,bool isParentNodePos=false,bool isParentNodeNeg=false)137 void Node::GetOrRange(std::vector<Range>& res, bool isParentNodePos = false, bool isParentNodeNeg = false)
138 {
139     bool isPos = isParentNodePos || (positive_count_ > 0);
140     bool isNeg = isParentNodeNeg || (negative_count_ > 0);
141     if (isPos || isNeg) {
142         PushRange(res);
143     } else {
144         if (left_ != nullptr) {
145             left_->GetOrRange(res, isPos, isNeg);
146         }
147         if (right_ != nullptr) {
148             right_->GetOrRange(res, isPos, isNeg);
149         }
150     }
151 }
152 
GetXOrRange(std::vector<Range> & res,bool isParentNodePos=false,bool isParentNodeNeg=false)153 void Node::GetXOrRange(std::vector<Range>& res, bool isParentNodePos = false, bool isParentNodeNeg = false)
154 {
155     bool isPos = isParentNodePos || (positive_count_ > 0);
156     bool isNeg = isParentNodeNeg || (negative_count_ > 0);
157     if (((isPos && !isNeg) || (!isPos && isNeg)) && IsLeaf()) {
158         PushRange(res);
159     } else if (isPos && isNeg) {
160         return;
161     } else {
162         if (left_ != nullptr) {
163             left_->GetXOrRange(res, isPos, isNeg);
164         }
165         if (right_ != nullptr) {
166             right_->GetXOrRange(res, isPos, isNeg);
167         }
168     }
169 }
170 
GetSubRange(std::vector<Range> & res,bool isParentNodePos=false,bool isParentNodeNeg=false)171 void Node::GetSubRange(std::vector<Range>& res, bool isParentNodePos = false, bool isParentNodeNeg = false)
172 {
173     bool isPos = isParentNodePos || (positive_count_ > 0);
174     bool isNeg = isParentNodeNeg || (negative_count_ > 0);
175     if (IsLeaf() && isPos && !isNeg) {
176         PushRange(res);
177     } else if (isNeg) {
178         return;
179     } else {
180         if (left_ != nullptr) {
181             left_->GetSubRange(res, isPos, isNeg);
182         }
183         if (right_ != nullptr) {
184             right_->GetSubRange(res, isPos, isNeg);
185         }
186     }
187 }
188 
MakeEnumerate(std::set<int> & ys,std::map<int,int> & indexOf,std::vector<int> & indexAt)189 void MakeEnumerate(std::set<int>& ys, std::map<int, int>& indexOf, std::vector<int>& indexAt)
190 {
191     auto it = ys.begin();
192     int index = 0;
193     while (it != ys.end()) {
194         indexOf[*it] = index++;
195         indexAt.push_back(*it);
196         ++it;
197     }
198     return;
199 }
200 
getRange(std::vector<Range> & ranges,Node & node,Region::OP op)201 void Region::getRange(std::vector<Range>& ranges, Node& node, Region::OP op)
202 {
203     switch (op) {
204         case Region::OP::AND:
205             node.GetAndRange(ranges);
206             break;
207         case Region::OP::OR:
208             node.GetOrRange(ranges);
209             break;
210         case Region::OP::XOR:
211             node.GetXOrRange(ranges);
212             break;
213         case Region::OP::SUB:
214             node.GetSubRange(ranges);
215             break;
216         default:
217             break;
218     }
219     return;
220 }
221 
UpdateRects(Rects & r,std::vector<Range> & ranges,std::vector<int> & indexAt,Region & res)222 void Region::UpdateRects(Rects& r, std::vector<Range>& ranges, std::vector<int>& indexAt, Region& res)
223 {
224     uint32_t i = 0;
225     uint32_t j = 0;
226     while (i < r.preRects.size() && j < ranges.size()) {
227         if (r.preRects[i].left_ == indexAt[ranges[j].start_] && r.preRects[i].right_ == indexAt[ranges[j].end_]) {
228             r.curRects.emplace_back(Rect { r.preRects[i].left_, r.preRects[i].top_, r.preRects[i].right_, r.curY });
229             i++;
230             j++;
231         } else if (r.preRects[i].right_ < indexAt[ranges[j].end_]) {
232             res.GetRegionRectsRef().push_back(r.preRects[i]);
233             i++;
234         } else {
235             r.curRects.emplace_back(Rect { indexAt[ranges[j].start_], r.preY, indexAt[ranges[j].end_], r.curY });
236             j++;
237         }
238     }
239     for (; j < ranges.size(); j++) {
240         r.curRects.emplace_back(Rect { indexAt[ranges[j].start_], r.preY, indexAt[ranges[j].end_], r.curY });
241     }
242     for (; i < r.preRects.size(); i++) {
243         res.GetRegionRectsRef().push_back(r.preRects[i]);
244     }
245     r.preRects.clear();
246     r.preRects.swap(r.curRects);
247     return;
248 }
249 
MakeBound()250 void Region::MakeBound()
251 {
252     if (rects_.size()) {
253         // Tell compiler there is no alias.
254         int left = rects_[0].left_;
255         int top = rects_[0].top_;
256         int right = rects_[0].right_;
257         int bottom = rects_[0].bottom_;
258         for (const auto& r : rects_) {
259             left = std::min(r.left_, left);
260             top = std::min(r.top_, top);
261             right = std::max(r.right_, right);
262             bottom = std::max(r.bottom_, bottom);
263         }
264         bound_.left_ = left;
265         bound_.top_ = top;
266         bound_.right_ = right;
267         bound_.bottom_ = bottom;
268     }
269 }
270 
GetAlignedRegion(int alignmentSize) const271 Region Region::GetAlignedRegion(int alignmentSize) const
272 {
273     Region alignedRegion;
274     for (const auto& rect : rects_) {
275         Rect alignedRect(AlignDown(rect.left_, alignmentSize), AlignDown(rect.top_, alignmentSize),
276             AlignUp(rect.right_, alignmentSize), AlignUp(rect.bottom_, alignmentSize));
277         Region alignedSubRegion{alignedRect};
278         alignedRegion.OrSelf(alignedSubRegion);
279     }
280     return alignedRegion;
281 }
282 
RegionOp(Region & r1,const Region & r2,Region & res,Region::OP op)283 void Region::RegionOp(Region& r1, const Region& r2, Region& res, Region::OP op)
284 {
285     if (r1.IsEmpty()) {
286         if (op == Region::OP::AND || op == Region::OP::SUB) {
287             res = Region();
288         } else {
289             res = r2;
290         }
291         return;
292     }
293     if (r2.IsEmpty()) {
294         if (op == Region::OP::AND) {
295             res = Region();
296         } else {
297             res = r1;
298         }
299         return;
300     }
301     RegionOpAccelate(r1, r2, res, op);
302 }
303 
RegionOpLocal(Region & r1,Region & r2,Region & res,Region::OP op)304 void Region::RegionOpLocal(Region& r1, Region& r2, Region& res, Region::OP op)
305 {
306     r1.MakeBound();
307     r2.MakeBound();
308     res.GetRegionRectsRef().clear();
309     std::vector<Event> events;
310     std::set<int> xs;
311 
312     for (auto& r : r1.GetRegionRects()) {
313         events.emplace_back(Event { r.top_, Event::Type::OPEN, r.left_, r.right_ });
314         events.emplace_back(Event { r.bottom_, Event::Type::CLOSE, r.left_, r.right_ });
315         xs.insert(r.left_);
316         xs.insert(r.right_);
317     }
318     for (auto& r : r2.GetRegionRects()) {
319         events.emplace_back(Event { r.top_, Event::Type::VOID_OPEN, r.left_, r.right_ });
320         events.emplace_back(Event { r.bottom_, Event::Type::VOID_CLOSE, r.left_, r.right_ });
321         xs.insert(r.left_);
322         xs.insert(r.right_);
323     }
324 
325     if (events.size() == 0) {
326         return;
327     }
328 
329     std::map<int, int> indexOf;
330     std::vector<int> indexAt;
331     MakeEnumerate(xs, indexOf, indexAt);
332     sort(events.begin(), events.end(), EventSortByY);
333 
334     Node rootNode { 0, static_cast<int>(indexOf.size() - 1) };
335 
336     std::vector<Range> ranges;
337     Rects r;
338     r.preY = events[0].y_;
339     r.curY = events[0].y_;
340     for (auto& e : events) {
341         r.curY = e.y_;
342         ranges.clear();
343         getRange(ranges, rootNode, op);
344         if (r.curY > r.preY) {
345             UpdateRects(r, ranges, indexAt, res);
346         }
347         rootNode.Update(indexOf[e.left_], indexOf[e.right_], e.type_);
348         r.preY = r.curY;
349     }
350     copy(r.preRects.begin(), r.preRects.end(), back_inserter(res.GetRegionRectsRef()));
351     res.MakeBound();
352 }
353 
RegionOpAccelate(Region & r1,const Region & r2,Region & res,Region::OP op)354 void Region::RegionOpAccelate(Region& r1, const Region& r2, Region& res, Region::OP op)
355 {
356     RectsPtr lhs(r1.CBegin(), r1.Size());
357     RectsPtr rhs(r2.CBegin(), r2.Size());
358     Assembler assembler(res);
359     OuterLooper outer(lhs, rhs);
360     Rect current(0, 0, 0, 0); // init value is irrelevant
361     do {
362         InnerLooper inner(outer);
363         RectType relationship = outer.NextScanline(current.top_, current.bottom_);
364         if (op == Region::OP::AND && relationship != RectType::LHS_RHS_BOTH) {
365             continue;
366         }
367         if (op == Region::OP::SUB && relationship == RectType::RHS_ONLY) {
368             continue;
369         }
370         inner.Init(relationship);
371         do {
372             RectType rectType = inner.NextRect(current.left_, current.right_);
373             if (((static_cast<uint32_t>(op) & static_cast<uint32_t>(rectType)) != 0) && !current.IsEmpty()) {
374                 assembler.Insert(current);
375             }
376         } while (!inner.IsDone());
377     } while (!outer.isDone());
378     assembler.FlushVerticalSpan();
379     return;
380 }
381 
OperationSelf(const Region & r,Region::OP op)382 Region& Region::OperationSelf(const Region& r, Region::OP op)
383 {
384     Region r1(*this);
385     RegionOp(r1, r, *this, op);
386     return *this;
387 }
388 
AndSelf(const Region & r)389 Region& Region::AndSelf(const Region& r)
390 {
391     return OperationSelf(r, Region::OP::AND);
392 }
393 
OrSelf(const Region & r)394 Region& Region::OrSelf(const Region& r)
395 {
396     return OperationSelf(r, Region::OP::OR);
397 }
398 
XOrSelf(const Region & r)399 Region& Region::XOrSelf(const Region& r)
400 {
401     return OperationSelf(r, Region::OP::XOR);
402 }
403 
SubSelf(const Region & r)404 Region& Region::SubSelf(const Region& r)
405 {
406     return OperationSelf(r, Region::OP::SUB);
407 }
408 
And(const Region & r)409 Region Region::And(const Region& r)
410 {
411     Region res;
412     RegionOp(*this, r, res, Region::OP::AND);
413     return res;
414 }
415 
Or(const Region & r)416 Region Region::Or(const Region& r)
417 {
418     Region res;
419     RegionOp(*this, r, res, Region::OP::OR);
420     return res;
421 }
422 
Xor(const Region & r)423 Region Region::Xor(const Region& r)
424 {
425     Region res;
426     RegionOp(*this, r, res, Region::OP::XOR);
427     return res;
428 }
429 
Sub(const Region & r)430 Region Region::Sub(const Region& r)
431 {
432     Region res;
433     RegionOp(*this, r, res, Region::OP::SUB);
434     return res;
435 }
436 
operator <<(std::ostream & os,const Region & r)437 std::ostream& operator<<(std::ostream& os, const Region& r)
438 {
439     os << "{";
440     os << r.GetSize() << ": ";
441     for (const Rect& rect : r.GetRegionRects()) {
442         os << rect;
443     }
444     os << "}" << std::endl;
445     return os;
446 }
447 
Area() const448 int Region::Area() const
449 {
450     int areaSum = 0;
451     for (const auto& rect : GetRegionRects()) {
452         areaSum += rect.Area();
453     }
454     return areaSum;
455 }
456 
IntersectArea(const Rect & r) const457 int Region::IntersectArea(const Rect& r) const
458 {
459     if (r.IsEmpty()) {
460         return 0;
461     }
462     int areaSum = 0;
463     for (const auto& rect : GetRegionRects()) {
464         areaSum += rect.IntersectArea(r);
465     }
466     return areaSum;
467 }
468 
469 } // namespace Occlusion
470 } // namespace Rosen
471 } // namespace OHOS
472