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