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 #ifndef RENDER_SERVICE_BASE_CORE_COMMON_RS_OCCLUSION_REGION_H 16 #define RENDER_SERVICE_BASE_CORE_COMMON_RS_OCCLUSION_REGION_H 17 18 #include <algorithm> 19 #include <iostream> 20 #include <vector> 21 #include <string> 22 23 #include "rs_rect.h" 24 #include "common/rs_macros.h" 25 #include "platform/common/rs_log.h" 26 27 namespace OHOS { 28 namespace Rosen { 29 namespace Occlusion { 30 31 constexpr int MAX_REGION_VALUE = 1000000; // normal region value should not exceed 1000000 32 constexpr int MIN_REGION_VALUE = -1000000; // normal region value should not less than -1000000 33 class Rect { 34 public: 35 // assumption: left-top is [0,0] 36 int left_ = 0; 37 int top_ = 0; 38 int right_ = 0; 39 int bottom_ = 0; 40 Rect()41 Rect() : left_(0), top_(0), right_(0), bottom_(0) {} 42 Rect(int l, int t, int r, int b, bool checkValue = true) left_(l)43 : left_(l), top_(t), right_(r), bottom_(b) 44 { 45 if (checkValue) { 46 CheckAndCorrectValue(); 47 if (left_ != l || top_ != t || right_ != r || bottom_ != b) { 48 RS_LOGE("Occlusion::Rect initialized with invalid value, ltrb[%{public}d, %{public}d, %{public}d, " 49 "%{public}d], should in range [%{public}d, %{public}d]", 50 l, t, t, b, MIN_REGION_VALUE, MAX_REGION_VALUE); 51 } 52 } 53 } 54 55 Rect(const RectI& r, bool checkValue = true) 56 : left_(r.left_), top_(r.top_), right_(r.GetRight()), bottom_(r.GetBottom()) 57 { 58 if (checkValue) { 59 CheckAndCorrectValue(); 60 if (left_ != r.left_ || top_ != r.top_ || right_ != r.GetRight() || bottom_ != r.GetBottom()) { 61 RS_LOGE("Occlusion::Rect initialized with invalid value, ltrb[%{public}d, %{public}d, %{public}d, " 62 "%{public}d], should in range [%{public}d, %{public}d]", 63 r.left_, r.top_, r.GetRight(), r.GetBottom(), MIN_REGION_VALUE, MAX_REGION_VALUE); 64 } 65 } 66 } 67 SetEmpty()68 void SetEmpty() 69 { 70 left_ = 0; 71 top_ = 0; 72 right_ = 0; 73 bottom_ = 0; 74 } 75 IsEmpty()76 bool IsEmpty() const 77 { 78 return left_ >= right_ || top_ >= bottom_; 79 } 80 81 bool operator==(const Rect& r) const 82 { 83 return left_ == r.left_ && top_ == r.top_ && right_ == r.right_ && bottom_ == r.bottom_; 84 } 85 86 bool operator!=(const Rect& r) const 87 { 88 return !(*this == r); 89 } 90 Intersect(const Rect & rect)91 Rect Intersect(const Rect& rect) const 92 { 93 int left = std::max(left_, rect.left_); 94 int top = std::max(top_, rect.top_); 95 int right = std::min(right_, rect.right_); 96 int bottom = std::min(bottom_, rect.bottom_); 97 if ((right - left <= 0) || (bottom - top <= 0)) { 98 return Rect(0, 0, 0, 0); 99 } else { 100 return Rect(left, top, right, bottom); 101 } 102 } 103 IsIntersect(const Rect & rect)104 bool IsIntersect(const Rect& rect) const 105 { 106 int left = std::max(left_, rect.left_); 107 int top = std::max(top_, rect.top_); 108 int right = std::min(right_, rect.right_); 109 int bottom = std::min(bottom_, rect.bottom_); 110 return (right - left > 0) && (bottom - top > 0); 111 } 112 GetRectInfo()113 std::string GetRectInfo() const 114 { 115 return std::string("[" + 116 std::to_string(left_) + ", " + 117 std::to_string(top_) + ", " + 118 std::to_string(right_ - left_) + ", " + 119 std::to_string(bottom_ - top_) + "]"); 120 } 121 ToRectI()122 RectI ToRectI() const 123 { 124 return RectI{left_, top_, right_ - left_, bottom_ - top_}; 125 } 126 Area()127 int Area() const 128 { 129 if (IsEmpty()) { 130 return 0; 131 } 132 return (right_ - left_) * (bottom_ - top_); 133 } 134 IntersectArea(const Rect & r)135 int IntersectArea(const Rect& r) const 136 { 137 Rect res = this->Intersect(r); 138 return res.Area(); 139 } 140 Expand(int leftExpandSize,int topExpandSize,int rightExpandSize,int bottomExpandSize)141 void Expand(int leftExpandSize, int topExpandSize, int rightExpandSize, int bottomExpandSize) 142 { 143 left_ -= leftExpandSize; 144 top_ -= topExpandSize; 145 right_ += rightExpandSize; 146 bottom_ += bottomExpandSize; 147 } 148 149 private: CheckAndCorrectValue()150 void CheckAndCorrectValue() 151 { 152 left_ = std::max(left_, MIN_REGION_VALUE); 153 top_ = std::max(top_, MIN_REGION_VALUE); 154 right_ = std::min(right_, MAX_REGION_VALUE); 155 bottom_ = std::min(bottom_, MAX_REGION_VALUE); 156 if (IsEmpty()) { 157 SetEmpty(); 158 } 159 } 160 }; 161 162 std::ostream& operator<<(std::ostream& os, const Rect& r); 163 164 /* 165 Event: Used for record a rect edge in/out event 166 y_: rect edge Y value 167 type: OPEN/CLOSE: lhs rect in/out; VOID_OPEN/VOID_CLOSE: rhs rect in/out 168 */ 169 class Event { 170 public: 171 // Use different value to differentiate lhs and rhs ranges 172 enum Type { OPEN = 1, CLOSE = -1, VOID_OPEN = 2, VOID_CLOSE = -2 }; 173 int y_ = 0; 174 Type type_ = Type::OPEN; 175 int left_ = 0; 176 int right_ = 0; 177 Event(int y,Type type,int l,int r)178 Event(int y, Type type, int l, int r) : y_(y), type_(type), left_(l), right_(r) {} 179 }; 180 bool EventSortByY(const Event& e1, const Event& e2); 181 182 class Range { 183 public: 184 int start_ = 0; 185 int end_ = 0; Range(int s,int e)186 Range(int s, int e) : start_(s), end_(e) {} 187 bool operator==(const Range& r) 188 { 189 return start_ == r.start_ && end_ == r.end_; 190 } 191 }; 192 193 class Node { 194 public: 195 int start_ = 0; 196 int end_ = 0; 197 int mid_ = 0; 198 int positive_count_ = 0; // used for counting current lhs ranges 199 int negative_count_ = 0; // used for counting current rhs ranges 200 Node* left_ = nullptr; 201 Node* right_ = nullptr; 202 Node(int s,int e)203 Node(int s, int e) : start_(s), end_(e), mid_((s + e) >> 1) {} ~Node()204 ~Node() 205 { 206 if (left_ != nullptr) { 207 delete left_; 208 left_ = nullptr; 209 } 210 if (right_ != nullptr) { 211 delete right_; 212 right_ = nullptr; 213 } 214 } 215 216 // push current node [start, end] into range result, merge last range if possible PushRange(std::vector<Range> & res)217 inline void PushRange(std::vector<Range>& res) 218 { 219 if (res.size() > 0 && start_ == res[res.size() - 1].end_) { 220 // merge range with previous range if their end and start share same point 221 res[res.size() - 1].end_ = end_; 222 } else { 223 res.emplace_back(Range { start_, end_ }); 224 } 225 } 226 IsLeaf()227 inline bool IsLeaf() 228 { 229 return left_ == nullptr && right_ == nullptr; 230 } 231 232 // update segment tree 233 void Update(int updateStart, int updateEnd, Event::Type type); 234 // get ranges where positive_count_ and negtive_count_ are both positive 235 void GetAndRange(std::vector<Range>& res, bool isParentNodePos, bool isParentNodeNeg); 236 // get ranges where positive_count_ or negtive_count_ is positive 237 void GetOrRange(std::vector<Range>& res, bool isParentNodePos, bool isParentNodeNeg); 238 // get ranges where either positive_count_ and negtive_count_ are both positive 239 void GetXOrRange(std::vector<Range>& res, bool isParentNodePos, bool isParentNodeNeg); 240 // get ranges where positive_count_ is positive and negtive_count_ not 241 void GetSubRange(std::vector<Range>& res, bool isParentNodePos, bool isParentNodeNeg); 242 }; 243 244 class RSB_EXPORT Region { 245 public: 246 enum OP { 247 // bit index 0: lhs 248 // bit index 1: lhs & rhs 249 // bit index 2: rhs 250 AND = 2, // 010 251 OR = 7, // 111 252 XOR = 5, // 101 253 SUB = 1 // 001 254 }; 255 256 Region() = default; Region(Rect r)257 Region(Rect r) 258 { 259 rects_.push_back(r); 260 bound_ = Rect { r }; 261 } 262 Region(const Region & reg)263 Region(const Region& reg) : rects_(reg.rects_), bound_(reg.bound_) {} ~Region()264 ~Region() {} 265 Reset()266 void Reset() 267 { 268 rects_.clear(); 269 bound_ = Rect {}; 270 } 271 GetRegionRectsRef()272 std::vector<Rect>& GetRegionRectsRef() 273 { 274 return rects_; 275 } 276 GetRegionRects()277 const std::vector<Rect>& GetRegionRects() const 278 { 279 return rects_; 280 } 281 GetRegionRectIs()282 std::vector<RectI> GetRegionRectIs() const 283 { 284 std::vector<RectI> rectIs; 285 for (const auto& rect : rects_) { 286 rectIs.emplace_back(rect.ToRectI()); 287 } 288 return rectIs; 289 } 290 GetSize()291 int GetSize() const 292 { 293 return rects_.size(); 294 } GetBound()295 Rect GetBound() const 296 { 297 return bound_; 298 } GetBoundRef()299 Rect& GetBoundRef() 300 { 301 return bound_; 302 } IsEmpty()303 bool IsEmpty() const 304 { 305 return rects_.size() == 0 || bound_.IsEmpty(); 306 } GetRegionInfo()307 std::string GetRegionInfo() const 308 { 309 std::string info; 310 if (IsEmpty()) { 311 info = "Region [Empty]"; 312 } else { 313 info = "Region " + std::to_string(rects_.size()) + ": "; 314 for (auto& r : rects_) { 315 info.append(r.GetRectInfo()); 316 } 317 } 318 return info; 319 } 320 CBegin()321 inline std::vector<Rect>::const_iterator CBegin() const 322 { 323 return rects_.cbegin(); 324 } CEnd()325 inline std::vector<Rect>::const_iterator CEnd() const 326 { 327 return rects_.cend(); 328 } Begin()329 inline std::vector<Rect>::iterator Begin() 330 { 331 return rects_.begin(); 332 } End()333 inline std::vector<Rect>::const_iterator End() 334 { 335 return rects_.end(); 336 } Size()337 inline size_t Size() const 338 { 339 return rects_.size(); 340 } 341 342 // bound of all region rects 343 void MakeBound(); 344 IsIntersectWith(const Rect & r)345 bool IsIntersectWith(const Rect& r) const 346 { 347 for (const Rect& rect : rects_) { 348 if (rect.IsIntersect(r)) { 349 return true; 350 } 351 } 352 return false; 353 } 354 355 /* core Region logic operation function, the return region's rects is guaranteed no-intersection 356 (rect in rects_ do not intersect with each other) 357 */ 358 void RegionOp(Region& r1, Region& r2, Region& res, Region::OP op); 359 void RegionOpLocal(Region& r1, Region& r2, Region& res, Region::OP op); 360 void RegionOpAccelate(Region& r1, Region& r2, Region& res, Region::OP op); 361 362 Region& OperationSelf(Region& r, Region::OP op); 363 // replace region with and result 364 Region& AndSelf(Region& r); 365 // replace region with or result 366 Region& OrSelf(Region& r); 367 // replace region with xor result 368 Region& XOrSelf(Region& r); 369 // replace region with sub result 370 Region& SubSelf(Region& r); 371 372 // return intersection region 373 Region And(Region& r); 374 // return merge region 375 Region Or(Region& r); 376 // return merge region subtract intersection region 377 Region Xor(Region& r); 378 // return region belongs to Region(lhs) but not Region(rhs) 379 Region Sub(Region& r); 380 381 // get current region's area, return the sum of the areas of all rectangles (as they are not intersect each other) 382 int Area() const; 383 // return the area of the region where the current region intersects the rectangle 384 int IntersectArea(const Rect& r) const; 385 386 private: 387 class Rects { 388 public: 389 std::vector<Rect> preRects; 390 std::vector<Rect> curRects; 391 int preY = 0; 392 int curY = 0; 393 }; 394 // get ranges from segmentTree node according to logical operation type 395 void getRange(std::vector<Range>& ranges, Node& node, OP op); 396 // update tmp rects and region according to current ranges 397 void UpdateRects(Rects& r, std::vector<Range>& ranges, std::vector<int>& indexAt, Region& res); 398 399 private: 400 std::vector<Rect> rects_; 401 Rect bound_; 402 static bool _s_so_loaded_; 403 }; 404 std::ostream& operator<<(std::ostream& os, const Region& r); 405 } // namespace Occlusion 406 } // namespace Rosen 407 } // namespace OHOS 408 #endif // RENDER_SERVICE_BASE_CORE_COMMON_RS_OCCLUSION_REGION_H