--- /dev/null
+/*
+// Copyright (c) 2016 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#include "disjoint_layers.h"
+#include <assert.h>
+#include <stdint.h>
+#include <algorithm>
+#include <iostream>
+#include <list>
+#include <map>
+#include <set>
+#include <utility>
+#include <vector>
+#include "hwctrace.h"
+
+namespace hwcomposer {
+
+enum EventType { START, END };
+
+struct YPOI {
+ EventType type;
+ uint64_t y;
+ uint64_t rect_id;
+
+ bool operator<(const YPOI &rhs) const {
+ if (y == rhs.y)
+ return rect_id < rhs.rect_id;
+ else
+ return (y < rhs.y);
+ }
+};
+
+// Any region will have start X and set of Y coordinates.
+struct Region {
+ uint64_t sx;
+ std::set<YPOI> y_points;
+ RectIDs rect_ids;
+};
+
+// POI is the point of interest while traversing through x coordinates
+struct POI {
+ EventType type;
+ uint64_t rect_id;
+ uint64_t x;
+ uint64_t top_y;
+ uint64_t bot_y;
+
+ bool operator<(const POI &rhs) const {
+ return (x <= rhs.x);
+ }
+};
+
+// This function will take active region and right x
+// For an active region there will be set of YPOI
+// It will traverse through each y_poi and given out
+// rectangle with rect_ids active at that time.
+void GenerateOutLayers(Region *reg, uint64_t x,
+ std::vector<RectSet<int>> *out) {
+ Rect<int> out_rect;
+ out_rect.left = reg->sx;
+ out_rect.right = x;
+ RectIDs rect_ids;
+
+ for (std::set<YPOI>::iterator y_poi_it = reg->y_points.begin();
+ y_poi_it != reg->y_points.end(); y_poi_it++) {
+ const YPOI &y_poi = *y_poi_it;
+ // No need to check for start or end event
+ // as rect_ids is empty
+ if (rect_ids.isEmpty()) {
+ out_rect.top = y_poi.y;
+ rect_ids.add(y_poi.rect_id);
+ } else {
+ if(out_rect.top == (int)y_poi.y) {
+ if (y_poi.type == START) {
+ rect_ids.add(y_poi.rect_id);
+ } else {
+ rect_ids.subtract(y_poi.rect_id);
+ }
+ continue;
+ }
+ out_rect.bottom = y_poi.y;
+ out->emplace_back(RectSet<int>(rect_ids, out_rect));
+ out_rect.top = y_poi.y;
+ if (y_poi.type == START) {
+ rect_ids.add(y_poi.rect_id);
+ } else {
+ rect_ids.subtract(y_poi.rect_id);
+ }
+ }
+ }
+}
+
+// This function will remove y coordinates corresponding to given rect_id
+void RemoveYpois(Region *reg, uint64_t rect_id) {
+ std::set<YPOI>::iterator top_it = reg->y_points.begin();
+ while (top_it != reg->y_points.end()) {
+ if ((*top_it).rect_id == rect_id) {
+ reg->y_points.erase(top_it++);
+ } else {
+ top_it++;
+ }
+ }
+}
+
+bool compare_region(const Region *first, const Region *second) {
+ uint64_t first_min_y = (*(first->y_points.begin())).y;
+ uint64_t second_min_y = (*(second->y_points.begin())).y;
+ return (first_min_y < second_min_y);
+}
+
+void get_draw_regions(const std::vector<Rect<int>> &in,
+ std::vector<RectSet<int>> *out) {
+ if (in.size() > RectIDs::max_elements) {
+ return;
+ }
+
+ // Set of all point of interests from input rectangles.
+ std::set<POI> pois;
+ std::list<Region *> imp_reg;
+ std::list<Region> active_regions;
+
+ // This loop will add all point of interests into pois.
+ for (uint64_t i = 0; i < in.size(); i++) {
+ const Rect<int> &rect = in[i];
+
+ // Filter out empty or invalid rects.
+ if (rect.left >= rect.right || rect.top >= rect.bottom)
+ continue;
+
+ POI poi;
+ poi.rect_id = i;
+ poi.x = rect.left;
+ poi.top_y = rect.top;
+ poi.bot_y = rect.bottom;
+ poi.type = START;
+ pois.insert(poi);
+
+ poi.type = END;
+ poi.x = rect.right;
+ pois.insert(poi);
+ }
+
+ for (std::set<POI>::iterator it = pois.begin(); it != pois.end(); ++it) {
+ const POI &poi = *it;
+ // First rectangle has to be inserted into active region
+ // This condition will be true if existing all active
+ // regions are already copied to out.
+ // If current poi is of type END there are no active regions,
+ // then this poi might already covered in previous pass
+ if (active_regions.size() == 0 && poi.type == START) {
+ Region reg;
+ reg.sx = poi.x;
+ YPOI y_poi;
+
+ y_poi.rect_id = poi.rect_id;
+ y_poi.type = START;
+ y_poi.y = poi.top_y;
+ reg.y_points.insert(y_poi);
+
+ y_poi.type = END;
+ y_poi.y = poi.bot_y;
+ reg.y_points.insert(y_poi);
+
+ RectIDs rectIds;
+ rectIds.add(poi.rect_id);
+ reg.rect_ids = rectIds;
+ active_regions.push_back(reg);
+ continue;
+ }
+
+ // If active_regions in not empty, Check if current
+ // poi y points fall in range of any existing
+ // active_regions.
+ // If yes, get that active region and do further processing
+ // If No, create a new region and insert into active regions
+ // If it is start event then there is possibility that multiple
+ // active_regions get impacted.
+ // If it is end event then one or none active_regions will get
+ // impacted.
+ bool found = false;
+ imp_reg.clear();
+ std::list<Region>::iterator it_reg = active_regions.begin();
+ while (it_reg != active_regions.end()) {
+ Region &cur_reg = *it_reg;
+ uint64_t min_y = (*(cur_reg.y_points.begin())).y;
+ uint64_t max_y = (*(cur_reg.y_points.rbegin())).y;
+ // If bottom y is less than minimum y in region or top y is greater than
+ // max y in region, then this region is not impacted by this rect
+ if (poi.bot_y <= min_y || poi.top_y >= max_y) {
+ it_reg++;
+ continue;
+ } else {
+ found = true;
+ // Found atleast one affected active region. If it is start event,
+ // add rect_id to cur_reg.rect_ids, also top_y and bot_y to
+ // cur_reg.y_points. if it is end event, remove rect_id from
+ // cur_reg.rect_ids and also top_y and bot_y from cur_reg.y_points.
+ // Also, if it is end event, check cur_reg.rect_ids is non empty,
+ // if it is empty remove region from active_regions.
+ // If it is end event, check next poi.x and see if it is same and
+ // those y coordinates fall in this region, if yes 1) remove
+ // that rect_id and y coordinates as well
+ // 2)contine to check next poi.x until you find mismatch x.
+ if (poi.x == cur_reg.sx) {
+ if (poi.type == START) {
+ cur_reg.rect_ids.add(poi.rect_id);
+ imp_reg.push_back(&cur_reg);
+ }
+
+ it_reg++;
+ continue;
+ }
+ if (poi.type == START) {
+ GenerateOutLayers(&cur_reg, poi.x, out);
+ cur_reg.sx = poi.x;
+ cur_reg.rect_ids.add(poi.rect_id);
+ imp_reg.push_back(&cur_reg);
+ it_reg++;
+ } else {
+ GenerateOutLayers(&cur_reg, poi.x, out);
+ RemoveYpois(&cur_reg, poi.rect_id);
+ cur_reg.sx = poi.x;
+ cur_reg.rect_ids.subtract(poi.rect_id);
+
+ std::set<POI>::iterator next_poi_it = it;
+ next_poi_it++;
+ for (; next_poi_it != pois.end(); next_poi_it++) {
+ const POI &next_poi = *next_poi_it;
+ if (next_poi.x != poi.x) {
+ break;
+ } else {
+ if (next_poi.bot_y <= min_y || next_poi.top_y >= max_y ||
+ next_poi.type == START) {
+ continue;
+ }
+ cur_reg.rect_ids.subtract(next_poi.rect_id);
+ RemoveYpois(&cur_reg, next_poi.rect_id);
+ }
+ }
+ if (cur_reg.rect_ids.isEmpty()) {
+ active_regions.erase(it_reg++);
+ } else {
+ it_reg++;
+ }
+ }
+ }
+ }
+ // If no affected active region found, add new active region
+ if (!found && poi.type == START) {
+ Region reg;
+ reg.sx = poi.x;
+ YPOI y_poi;
+
+ y_poi.rect_id = poi.rect_id;
+ y_poi.type = START;
+ y_poi.y = poi.top_y;
+ reg.y_points.insert(y_poi);
+
+ y_poi.type = END;
+ y_poi.y = poi.bot_y;
+ reg.y_points.insert(y_poi);
+
+ RectIDs rectIds;
+ rectIds.add(poi.rect_id);
+ reg.rect_ids = rectIds;
+ active_regions.push_back(reg);
+ } else {
+ if (imp_reg.size() > 1 && poi.type == START) {
+ imp_reg.sort(compare_region);
+ uint64_t cur_y = 0;
+ for (std::list<Region *>::iterator cur_imp_reg_it = imp_reg.begin();
+ cur_imp_reg_it != imp_reg.end(); cur_imp_reg_it++) {
+ Region &cur_imp_reg = *(*cur_imp_reg_it);
+ YPOI y_poi;
+ y_poi.rect_id = poi.rect_id;
+ y_poi.type = START;
+
+ if (cur_y == 0) {
+ y_poi.y = poi.top_y;
+ } else {
+ y_poi.y = cur_y;
+ }
+ // This is to split vertical
+ // line into all impacted
+ // regions.
+ cur_imp_reg.y_points.insert(y_poi);
+ // Take bottom of current region as start of next impacted region
+ cur_y = (*(cur_imp_reg.y_points.rbegin())).y;
+ std::list<Region *>::iterator next_imp_reg_it = cur_imp_reg_it;
+ next_imp_reg_it++;
+ if (next_imp_reg_it == imp_reg.end()) {
+ // If there is an another
+ // region which is impacted, no
+ // need to add anything.
+ // if there is no other active region left,
+ // take bottom y and push into this active region
+ y_poi.y = poi.bot_y;
+ } else {
+ y_poi.y = cur_y;
+ }
+ y_poi.type = END;
+ cur_imp_reg.y_points.insert(y_poi);
+ }
+ } else if (imp_reg.size() == 1 && poi.type == START) {
+ // Only one region got impacted add y coordinated to that region
+ std::list<Region *>::iterator cur_imp_reg_it = imp_reg.begin();
+ YPOI y_poi;
+ y_poi.rect_id = poi.rect_id;
+ y_poi.type = START;
+ y_poi.y = poi.top_y;
+ (*cur_imp_reg_it)->y_points.insert(y_poi);
+ y_poi.type = END;
+ y_poi.y = poi.bot_y;
+ (*cur_imp_reg_it)->y_points.insert(y_poi);
+ }
+ }
+ }
+}
+
+} // namespace hwcomposer
+++ /dev/null
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "separate_rects.h"
-#include <algorithm>
-#include <assert.h>
-#include <iostream>
-#include <map>
-#include <set>
-#include <utility>
-#include <vector>
-
-namespace separate_rects {
-
-enum EventType { START, END };
-
-template <typename TId, typename TNum>
-struct StartedRect {
- IdSet<TId> id_set;
- TNum left, top, bottom;
-
- // Note that this->left is not part of the key. That field is only to mark the
- // left edge of the rectangle.
- bool operator<(const StartedRect<TId, TNum> &rhs) const {
- return (top < rhs.top || (top == rhs.top && bottom < rhs.bottom)) ||
- (top == rhs.top && bottom == rhs.bottom && id_set < rhs.id_set);
- }
-};
-
-template <typename TId, typename TNum>
-struct SweepEvent {
- EventType type;
- union {
- TNum x;
- TNum y;
- };
-
- TId rect_id;
-
- bool operator<(const SweepEvent<TId, TNum> &rhs) const {
- return (y < rhs.y || (y == rhs.y && rect_id < rhs.rect_id));
- }
-};
-
-template <typename TNum>
-std::ostream &operator<<(std::ostream &os, const Rect<TNum> &rect) {
- return os << rect.bounds[0] << ", " << rect.bounds[1] << ", "
- << rect.bounds[2] << ", " << rect.bounds[3];
-}
-
-template <typename TUInt>
-std::ostream &operator<<(std::ostream &os, const IdSet<TUInt> &obj) {
- int bits = IdSet<TUInt>::max_elements;
- TUInt mask = ((TUInt)0x1) << (bits - 1);
- for (int i = 0; i < bits; i++)
- os << ((obj.getBits() & (mask >> i)) ? "1" : "0");
- return os;
-}
-
-template <typename TNum, typename TId>
-void separate_rects(const std::vector<Rect<TNum>> &in,
- std::vector<RectSet<TId, TNum>> *out) {
- // Overview:
- // This algorithm is a line sweep algorithm that travels from left to right.
- // The sweep stops at each vertical edge of each input rectangle in sorted
- // order of x-coordinate. At each stop, the sweep line is examined in order of
- // y-coordinate from top to bottom. Along the way, a running set of rectangle
- // IDs is either added to or subtracted from as the top and bottom edges are
- // encountered, respectively. At each change of that running set, a copy of
- // that set is recorded in along with the the y-coordinate it happened at in a
- // list. This list is then interpreted as a sort of vertical cross section of
- // our output set of non-overlapping rectangles. Based of the algorithm found
- // at: http://stackoverflow.com/a/2755498
-
- if (in.size() > IdSet<TId>::max_elements) {
- return;
- }
-
- // Events are when the sweep line encounters the starting or ending edge of
- // any input rectangle.
- std::set<SweepEvent<TId, TNum>> sweep_h_events; // Left or right bounds
- std::set<SweepEvent<TId, TNum>> sweep_v_events; // Top or bottom bounds
-
- // A started rect is a rectangle whose left, top, bottom edge, and set of
- // rectangle IDs is known. The key of this map includes all that information
- // (except the left edge is never used to determine key equivalence or
- // ordering),
- std::map<StartedRect<TId, TNum>, bool> started_rects;
-
- // This is cleared after every event. Its declaration is here to avoid
- // reallocating a vector and its buffers every event.
- std::vector<std::pair<TNum, IdSet<TId>>> active_regions;
-
- // This pass will add rectangle start and end events to be triggered as the
- // algorithm sweeps from left to right.
- for (TId i = 0; i < in.size(); i++) {
- const Rect<TNum> &rect = in[i];
-
- // Filter out empty or invalid rects.
- if (rect.left >= rect.right || rect.top >= rect.bottom)
- continue;
-
- SweepEvent<TId, TNum> evt;
- evt.rect_id = i;
-
- evt.type = START;
- evt.x = rect.left;
- sweep_h_events.insert(evt);
-
- evt.type = END;
- evt.x = rect.right;
- sweep_h_events.insert(evt);
- }
-
- for (typename std::set<SweepEvent<TId, TNum>>::iterator it =
- sweep_h_events.begin();
- it != sweep_h_events.end(); ++it) {
- const SweepEvent<TId, TNum> &h_evt = *it;
- const Rect<TNum> &rect = in[h_evt.rect_id];
-
- // During this event, we have encountered a vertical starting or ending edge
- // of a rectangle so want to append or remove (respectively) that rectangles
- // top and bottom from the vertical sweep line.
- SweepEvent<TId, TNum> v_evt;
- v_evt.rect_id = h_evt.rect_id;
- if (h_evt.type == START) {
- v_evt.type = START;
- v_evt.y = rect.top;
- sweep_v_events.insert(v_evt);
-
- v_evt.type = END;
- v_evt.y = rect.bottom;
- sweep_v_events.insert(v_evt);
- } else {
- v_evt.type = START;
- v_evt.y = rect.top;
- typename std::set<SweepEvent<TId, TNum>>::iterator start_it =
- sweep_v_events.find(v_evt);
- assert(start_it != sweep_v_events.end());
- sweep_v_events.erase(start_it);
-
- v_evt.type = END;
- v_evt.y = rect.bottom;
- typename std::set<SweepEvent<TId, TNum>>::iterator end_it =
- sweep_v_events.find(v_evt);
- assert(end_it != sweep_v_events.end());
- sweep_v_events.erase(end_it);
- }
-
- // Peeks ahead to see if there are other rectangles sharing a vertical edge
- // with the current sweep line. If so, we want to continue marking up the
- // sweep line before actually processing the rectangles the sweep line is
- // intersecting.
- typename std::set<SweepEvent<TId, TNum>>::iterator next_it = it;
- ++next_it;
- if (next_it != sweep_h_events.end()) {
- if (next_it->x == h_evt.x) {
- continue;
- }
- }
-
-#ifdef RECTS_DEBUG
- std::cout << h_evt.x << std::endl;
-#endif
-
- // After the following for loop, active_regions will be a list of
- // y-coordinates paired with the set of rectangle IDs that are intersect at
- // that y-coordinate (and the current sweep line's x-coordinate). For
- // example if the current sweep line were the left edge of a scene with only
- // one rectangle of ID 0 and bounds (left, top, right, bottom) == (2, 3, 4,
- // 5), active_regions will be [({ 0 }, 3), {}, 5].
- active_regions.clear();
- IdSet<TId> active_set;
- for (typename std::set<SweepEvent<TId, TNum>>::iterator it =
- sweep_v_events.begin();
- it != sweep_v_events.end(); ++it) {
- const SweepEvent<TId, TNum> &v_evt = *it;
-
- if (v_evt.type == START) {
- active_set.add(v_evt.rect_id);
- } else {
- active_set.subtract(v_evt.rect_id);
- }
-
- if (active_regions.size() > 0 && active_regions.back().first == v_evt.y) {
- active_regions.back().second = active_set;
- } else {
- active_regions.emplace_back(std::make_pair(v_evt.y, active_set));
- }
- }
-
-#ifdef RECTS_DEBUG
- std::cout << "x:" << h_evt.x;
- for (std::vector<std::pair<TNum, IdSet>>::iterator it =
- active_regions.begin();
- it != active_regions.end(); ++it) {
- std::cout << " " << it->first << "(" << it->second << ")"
- << ",";
- }
- std::cout << std::endl;
-#endif
-
- // To determine which started rectangles are ending this event, we make them
- // all as false, or unseen during this sweep line.
- for (typename std::map<StartedRect<TId, TNum>, bool>::iterator it =
- started_rects.begin();
- it != started_rects.end(); ++it) {
- it->second = false;
- }
-
- // This for loop will iterate all potential new rectangles and either
- // discover it was already started (and then mark it true), or that it is a
- // new rectangle and add it to the started rectangles. A started rectangle
- // is unique if it has a distinct top, bottom, and set of rectangle IDs.
- // This is tricky because a potential rectangle could be encountered here
- // that has a non-unique top and bottom, so it shares geometry with an
- // already started rectangle, but the set of rectangle IDs differs. In that
- // case, we have a new rectangle, and the already existing started rectangle
- // will not be marked as seen ("true" in the std::pair) and will get ended
- // by the for loop after this one. This is as intended.
- for (typename std::vector<std::pair<TNum, IdSet<TId>>>::iterator it =
- active_regions.begin();
- it != active_regions.end(); ++it) {
- IdSet<TId> region_set = it->second;
-
- if (region_set.isEmpty())
- continue;
-
- // An important property of active_regions is that each region where a set
- // of rectangles applies is bounded at the bottom by the next (in the
- // vector) region's starting y-coordinate.
- typename std::vector<std::pair<TNum, IdSet<TId>>>::iterator next_it = it;
- ++next_it;
- assert(next_it != active_regions.end());
-
- TNum region_top = it->first;
- TNum region_bottom = next_it->first;
-
- StartedRect<TId, TNum> rect_key;
- rect_key.id_set = region_set;
- rect_key.left = h_evt.x;
- rect_key.top = region_top;
- rect_key.bottom = region_bottom;
-
- // Remember that rect_key.left is ignored for the purposes of searching
- // the started rects. This follows from the fact that a previously started
- // rectangle would by definition have a left bound less than the current
- // event's x-coordinate. We are interested in continuing the started
- // rectangles by marking them seen (true) but we don't know, care, or wish
- // to change the left bound at this point. If there are no matching
- // rectangles for this region, start a new one and mark it as seen (true).
- typename std::map<StartedRect<TId, TNum>, bool>::iterator
- started_rect_it = started_rects.find(rect_key);
- if (started_rect_it == started_rects.end()) {
- started_rects[rect_key] = true;
- } else {
- started_rect_it->second = true;
- }
- }
-
- // This for loop ends all rectangles that were unseen during this event.
- // Because this is the first event where we didn't see this rectangle, it's
- // right edge is exactly the current event's x-coordinate. With this, we
- // have the final piece of information to output this rectangle's geometry
- // and set of input rectangle IDs. To end a started rectangle, we erase it
- // from the started_rects map and append the completed rectangle to the
- // output vector.
- for (typename std::map<StartedRect<TId, TNum>, bool>::iterator it =
- started_rects.begin();
- it != started_rects.end();
- /* inc in body */) {
- if (!it->second) {
- const StartedRect<TId, TNum> &proto_rect = it->first;
- Rect<TNum> out_rect;
- out_rect.left = proto_rect.left;
- out_rect.top = proto_rect.top;
- out_rect.right = h_evt.x;
- out_rect.bottom = proto_rect.bottom;
- out->emplace_back(RectSet<TId, TNum>(proto_rect.id_set, out_rect));
- started_rects.erase(it++); // Also increments out iterator.
-
-#ifdef RECTS_DEBUG
- std::cout << " <" << proto_rect.id_set << "(" << rect << ")"
- << std::endl;
-#endif
- } else {
- // Remember this for loop has no built in increment step. We do it here.
- ++it;
- }
- }
- }
-}
-
-void separate_frects_64(const std::vector<Rect<float>> &in,
- std::vector<RectSet<uint64_t, float>> *out) {
- separate_rects(in, out);
-}
-
-void separate_rects_64(const std::vector<Rect<int>> &in,
- std::vector<RectSet<uint64_t, int>> *out) {
- separate_rects(in, out);
-}
-
-} // namespace separate_rects
-
-#ifdef RECTS_TEST
-
-using namespace separate_rects;
-
-int main(int argc, char **argv) {
-#define RectSet RectSet<TId, TNum>
-#define Rect Rect<TNum>
-#define IdSet IdSet<TId>
- typedef uint64_t TId;
- typedef float TNum;
-
- std::vector<Rect> in;
- std::vector<RectSet> out;
- std::vector<RectSet> expected_out;
-
- in.emplace_back({0, 0, 4, 5});
- in.emplace_back({2, 0, 6, 6});
- in.emplace_back({4, 0, 8, 5});
- in.emplace_back({0, 7, 8, 9});
-
- in.emplace_back({10, 0, 18, 5});
- in.emplace_back({12, 0, 16, 5});
-
- in.emplace_back({20, 11, 24, 17});
- in.emplace_back({22, 13, 26, 21});
- in.emplace_back({32, 33, 36, 37});
- in.emplace_back({30, 31, 38, 39});
-
- in.emplace_back({40, 43, 48, 45});
- in.emplace_back({44, 41, 46, 47});
-
- in.emplace_back({50, 51, 52, 53});
- in.emplace_back({50, 51, 52, 53});
- in.emplace_back({50, 51, 52, 53});
-
- in.emplace_back({0, 0, 0, 10});
- in.emplace_back({0, 0, 10, 0});
- in.emplace_back({10, 0, 0, 10});
- in.emplace_back({0, 10, 10, 0});
-
- for (int i = 0; i < 100000; i++) {
- out.clear();
- separate_rects(in, &out);
- }
-
- for (int i = 0; i < out.size(); i++) {
- std::cout << out[i].id_set << "(" << out[i].rect << ")" << std::endl;
- }
-
- std::cout << "# of rects: " << out.size() << std::endl;
-
- expected_out.emplace_back(RectSet(IdSet(0), Rect(0, 0, 2, 5)));
- expected_out.emplace_back(RectSet(IdSet(1), Rect(2, 5, 6, 6)));
- expected_out.emplace_back(RectSet(IdSet(1) | 0, Rect(2, 0, 4, 5)));
- expected_out.emplace_back(RectSet(IdSet(1) | 2, Rect(4, 0, 6, 5)));
- expected_out.emplace_back(RectSet(IdSet(2), Rect(6, 0, 8, 5)));
- expected_out.emplace_back(RectSet(IdSet(3), Rect(0, 7, 8, 9)));
- expected_out.emplace_back(RectSet(IdSet(4), Rect(10, 0, 12, 5)));
- expected_out.emplace_back(RectSet(IdSet(5) | 4, Rect(12, 0, 16, 5)));
- expected_out.emplace_back(RectSet(IdSet(4), Rect(16, 0, 18, 5)));
- expected_out.emplace_back(RectSet(IdSet(6), Rect(20, 11, 22, 17)));
- expected_out.emplace_back(RectSet(IdSet(6) | 7, Rect(22, 13, 24, 17)));
- expected_out.emplace_back(RectSet(IdSet(6), Rect(22, 11, 24, 13)));
- expected_out.emplace_back(RectSet(IdSet(7), Rect(22, 17, 24, 21)));
- expected_out.emplace_back(RectSet(IdSet(7), Rect(24, 13, 26, 21)));
- expected_out.emplace_back(RectSet(IdSet(9), Rect(30, 31, 32, 39)));
- expected_out.emplace_back(RectSet(IdSet(8) | 9, Rect(32, 33, 36, 37)));
- expected_out.emplace_back(RectSet(IdSet(9), Rect(32, 37, 36, 39)));
- expected_out.emplace_back(RectSet(IdSet(9), Rect(32, 31, 36, 33)));
- expected_out.emplace_back(RectSet(IdSet(9), Rect(36, 31, 38, 39)));
- expected_out.emplace_back(RectSet(IdSet(10), Rect(40, 43, 44, 45)));
- expected_out.emplace_back(RectSet(IdSet(10) | 11, Rect(44, 43, 46, 45)));
- expected_out.emplace_back(RectSet(IdSet(11), Rect(44, 41, 46, 43)));
- expected_out.emplace_back(RectSet(IdSet(11), Rect(44, 45, 46, 47)));
- expected_out.emplace_back(RectSet(IdSet(10), Rect(46, 43, 48, 45)));
- expected_out.emplace_back(RectSet(IdSet(12) | 13 | 14, Rect(50, 51, 52, 53)));
-
- for (int i = 0; i < expected_out.size(); i++) {
- RectSet &ex_out = expected_out[i];
- if (std::find(out.begin(), out.end(), ex_out) == out.end()) {
- std::cout << "Missing Rect: " << ex_out.id_set << "(" << ex_out.rect
- << ")" << std::endl;
- }
- }
-
- for (int i = 0; i < out.size(); i++) {
- RectSet &actual_out = out[i];
- if (std::find(expected_out.begin(), expected_out.end(), actual_out) ==
- expected_out.end()) {
- std::cout << "Extra Rect: " << actual_out.id_set << "(" << actual_out.rect
- << ")" << std::endl;
- }
- }
-
- return 0;
-}
-
-#endif
+++ /dev/null
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef DRM_HWCOMPOSER_SEPARATE_RECTS_H_
-#define DRM_HWCOMPOSER_SEPARATE_RECTS_H_
-
-#include <stdint.h>
-
-#include <sstream>
-#include <vector>
-
-namespace separate_rects {
-
-template <typename TFloat>
-struct Rect {
- union {
- struct {
- TFloat left, top, right, bottom;
- };
- struct {
- TFloat x1, y1, x2, y2;
- };
- TFloat bounds[4];
- };
-
- typedef TFloat TNum;
-
- Rect() {
- }
-
- Rect(TFloat xx1, TFloat yy1, TFloat xx2, TFloat yy2)
- : x1(xx1), y1(yy1), x2(xx2), y2(yy2) {
- }
-
- template <typename T>
- Rect(const Rect<T> &rhs) {
- for (int i = 0; i < 4; i++)
- bounds[i] = rhs.bounds[i];
- }
-
- template <typename T>
- Rect<TFloat> &operator=(const Rect<T> &rhs) {
- for (int i = 0; i < 4; i++)
- bounds[i] = rhs.bounds[i];
- return *this;
- }
-
- bool operator==(const Rect &rhs) const {
- for (int i = 0; i < 4; i++) {
- if (bounds[i] != rhs.bounds[i])
- return false;
- }
-
- return true;
- }
-
- TFloat width() const {
- return bounds[2] - bounds[0];
- }
-
- TFloat height() const {
- return bounds[3] - bounds[1];
- }
-
- TFloat area() const {
- return width() * height();
- }
-
- void Dump(std::ostringstream *out) const {
- *out << "[x/y/w/h]=" << left << "/" << top << "/" << width() << "/"
- << height();
- }
-};
-
-template <typename TUInt>
-struct IdSet {
- public:
- typedef TUInt TId;
-
- IdSet() : bitset(0) {
- }
-
- IdSet(TId id) : bitset(0) {
- add(id);
- }
-
- void add(TId id) {
- bitset |= ((TUInt)1) << id;
- }
-
- void subtract(TId id) {
- bitset &= ~(((TUInt)1) << id);
- }
-
- bool isEmpty() const {
- return bitset == 0;
- }
-
- TUInt getBits() const {
- return bitset;
- }
-
- bool operator==(const IdSet<TId> &rhs) const {
- return bitset == rhs.bitset;
- }
-
- bool operator<(const IdSet<TId> &rhs) const {
- return bitset < rhs.bitset;
- }
-
- IdSet<TId> operator|(const IdSet<TId> &rhs) const {
- IdSet ret;
- ret.bitset = bitset | rhs.bitset;
- return ret;
- }
-
- IdSet<TId> operator|(TId id) const {
- IdSet<TId> ret;
- ret.bitset = bitset;
- ret.add(id);
- return ret;
- }
-
- static const int max_elements = sizeof(TId) * 8;
-
- private:
- TUInt bitset;
-};
-
-template <typename TId, typename TNum>
-struct RectSet {
- IdSet<TId> id_set;
- Rect<TNum> rect;
-
- RectSet(const IdSet<TId> &i, const Rect<TNum> &r) : id_set(i), rect(r) {
- }
-
- bool operator==(const RectSet<TId, TNum> &rhs) const {
- return id_set == rhs.id_set && rect == rhs.rect;
- }
-};
-
-// Separates up to a maximum of 64 input rectangles into mutually non-
-// overlapping rectangles that cover the exact same area and outputs those non-
-// overlapping rectangles. Each output rectangle also includes the set of input
-// rectangle indices that overlap the output rectangle encoded in a bitset. For
-// example, an output rectangle that overlaps input rectangles in[0], in[1], and
-// in[4], the bitset would be (ommitting leading zeroes) 10011.
-void separate_frects_64(const std::vector<Rect<float>> &in,
- std::vector<RectSet<uint64_t, float>> *out);
-void separate_rects_64(const std::vector<Rect<int>> &in,
- std::vector<RectSet<uint64_t, int>> *out);
-
-} // namespace separate_rects
-
-#endif