From: arpallet Date: Sun, 29 Jan 2017 06:55:11 +0000 (-0800) Subject: Algorithm to detect disjoint regions for gpu composition. X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=6b3836b869c8e3d43ebbd66e1b97f17a3d0bc0a2;p=android-x86%2Fexternal-IA-Hardware-Composer.git Algorithm to detect disjoint regions for gpu composition. This algorithm traverse through x co-ordinates and at each intersection of x co-ordinates, it will traverse through y axis for intersections. At each y co-ordinate intersection it will give out new layer with input layer ids active at that point. Jira: None. Test: No graphics regressions on Linux and Android. Signed-off-by: arpallet --- diff --git a/Android.mk b/Android.mk index c9e301d..87da9ec 100644 --- a/Android.mk +++ b/Android.mk @@ -64,7 +64,7 @@ LOCAL_SRC_FILES := \ common/display/pageflipeventhandler.cpp \ common/utils/drmscopedtypes.cpp \ common/utils/hwcthread.cpp \ - common/utils/separate_rects.cpp \ + common/utils/disjoint_layers.cpp \ os/android/grallocbufferhandler.cpp \ os/android/drmhwctwo.cpp diff --git a/Makefile.sources b/Makefile.sources index e00eb8e..c880ee5 100644 --- a/Makefile.sources +++ b/Makefile.sources @@ -17,7 +17,7 @@ common_SOURCES = \ common/display/pageflipeventhandler.cpp \ common/utils/drmscopedtypes.cpp \ common/utils/hwcthread.cpp \ - common/utils/separate_rects.cpp \ + common/utils/disjoint_layers.cpp \ os/linux/gbmbufferhandler.cpp \ $(NULL) diff --git a/common/compositor/compositor.cpp b/common/compositor/compositor.cpp index 0e84ecc..cdbcce7 100644 --- a/common/compositor/compositor.cpp +++ b/common/compositor/compositor.cpp @@ -18,15 +18,15 @@ #include +#include "disjoint_layers.h" #include "displayplanestate.h" #include "hwctrace.h" #include "nativegpuresource.h" #include "nativesurface.h" #include "nativesync.h" -#include "renderstate.h" -#include "renderer.h" #include "overlaylayer.h" -#include "separate_rects.h" +#include "renderer.h" +#include "renderstate.h" #include "scopedrendererstate.h" namespace hwcomposer { @@ -285,13 +285,13 @@ void Compositor::SeparateLayers(const std::vector &dedicated_layers, return display_frame[layer_index]; }); - std::vector> separate_regions; - separate_rects::separate_rects_64(layer_rects, &separate_regions); + std::vector> separate_regions; + get_draw_regions(layer_rects, &separate_regions); uint64_t exclude_mask = ((uint64_t)1 << num_exclude_rects) - 1; uint64_t dedicated_mask = (((uint64_t)1 << dedicated_layers.size()) - 1) << num_exclude_rects; - for (separate_rects::RectSet ®ion : separate_regions) { + for (RectSet ®ion : separate_regions) { if (region.id_set.getBits() & exclude_mask) continue; diff --git a/common/utils/disjoint_layers.cpp b/common/utils/disjoint_layers.cpp new file mode 100644 index 0000000..20745d8 --- /dev/null +++ b/common/utils/disjoint_layers.cpp @@ -0,0 +1,333 @@ +/* +// 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 +#include +#include +#include +#include +#include +#include +#include +#include +#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 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> *out) { + Rect out_rect; + out_rect.left = reg->sx; + out_rect.right = x; + RectIDs rect_ids; + + for (std::set::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(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::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> &in, + std::vector> *out) { + if (in.size() > RectIDs::max_elements) { + return; + } + + // Set of all point of interests from input rectangles. + std::set pois; + std::list imp_reg; + std::list active_regions; + + // This loop will add all point of interests into pois. + for (uint64_t i = 0; i < in.size(); i++) { + const Rect &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::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::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::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::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::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::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 diff --git a/common/utils/separate_rects.cpp b/common/utils/separate_rects.cpp deleted file mode 100644 index fc7ec26..0000000 --- a/common/utils/separate_rects.cpp +++ /dev/null @@ -1,416 +0,0 @@ -/* - * 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 -#include -#include -#include -#include -#include -#include - -namespace separate_rects { - -enum EventType { START, END }; - -template -struct StartedRect { - IdSet 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 &rhs) const { - return (top < rhs.top || (top == rhs.top && bottom < rhs.bottom)) || - (top == rhs.top && bottom == rhs.bottom && id_set < rhs.id_set); - } -}; - -template -struct SweepEvent { - EventType type; - union { - TNum x; - TNum y; - }; - - TId rect_id; - - bool operator<(const SweepEvent &rhs) const { - return (y < rhs.y || (y == rhs.y && rect_id < rhs.rect_id)); - } -}; - -template -std::ostream &operator<<(std::ostream &os, const Rect &rect) { - return os << rect.bounds[0] << ", " << rect.bounds[1] << ", " - << rect.bounds[2] << ", " << rect.bounds[3]; -} - -template -std::ostream &operator<<(std::ostream &os, const IdSet &obj) { - int bits = IdSet::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 -void separate_rects(const std::vector> &in, - std::vector> *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::max_elements) { - return; - } - - // Events are when the sweep line encounters the starting or ending edge of - // any input rectangle. - std::set> sweep_h_events; // Left or right bounds - std::set> 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, 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>> 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 &rect = in[i]; - - // Filter out empty or invalid rects. - if (rect.left >= rect.right || rect.top >= rect.bottom) - continue; - - SweepEvent 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>::iterator it = - sweep_h_events.begin(); - it != sweep_h_events.end(); ++it) { - const SweepEvent &h_evt = *it; - const Rect &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 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>::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>::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>::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 active_set; - for (typename std::set>::iterator it = - sweep_v_events.begin(); - it != sweep_v_events.end(); ++it) { - const SweepEvent &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>::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, 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>>::iterator it = - active_regions.begin(); - it != active_regions.end(); ++it) { - IdSet 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>>::iterator next_it = it; - ++next_it; - assert(next_it != active_regions.end()); - - TNum region_top = it->first; - TNum region_bottom = next_it->first; - - StartedRect 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, 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, bool>::iterator it = - started_rects.begin(); - it != started_rects.end(); - /* inc in body */) { - if (!it->second) { - const StartedRect &proto_rect = it->first; - Rect 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(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> &in, - std::vector> *out) { - separate_rects(in, out); -} - -void separate_rects_64(const std::vector> &in, - std::vector> *out) { - separate_rects(in, out); -} - -} // namespace separate_rects - -#ifdef RECTS_TEST - -using namespace separate_rects; - -int main(int argc, char **argv) { -#define RectSet RectSet -#define Rect Rect -#define IdSet IdSet - typedef uint64_t TId; - typedef float TNum; - - std::vector in; - std::vector out; - std::vector 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 diff --git a/public/disjoint_layers.h b/public/disjoint_layers.h new file mode 100644 index 0000000..edb8105 --- /dev/null +++ b/public/disjoint_layers.h @@ -0,0 +1,148 @@ +/* +// 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. +*/ + +#ifndef DISJOINT_LAYERS_H_ +#define DISJOINT_LAYERS_H_ + +#include + +#include +#include + +namespace hwcomposer { + +//Some of the structs are adopted from drm_hwcomposer +template +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 + Rect(const Rect &rhs) { + for (int i = 0; i < 4; i++) + bounds[i] = rhs.bounds[i]; + } + template + Rect &operator=(const Rect &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(); + } +}; +struct RectIDs { + public: + typedef uint64_t TId; + + RectIDs() : bitset(0) { + } + + RectIDs(TId id) : bitset(0) { + add(id); + } + + void add(TId id) { + bitset |= ((uint64_t)1) << id; + } + + void subtract(TId id) { + bitset &= ~(((uint64_t)1) << id); + } + + bool isEmpty() const { + return bitset == 0; + } + + uint64_t getBits() const { + return bitset; + } + + bool operator==(const RectIDs &rhs) const { + return bitset == rhs.bitset; + } + + bool operator<(const RectIDs &rhs) const { + return bitset < rhs.bitset; + } + + RectIDs operator|(const RectIDs &rhs) const { + RectIDs ret; + ret.bitset = bitset | rhs.bitset; + return ret; + } + + RectIDs operator|(TId id) const { + RectIDs ret; + ret.bitset = bitset; + ret.add(id); + return ret; + } + + static const int max_elements = sizeof(TId) * 8; + + private: + uint64_t bitset; +}; + +template +struct RectSet { + RectIDs id_set; + Rect rect; + + RectSet(const RectIDs &i, const Rect &r) : id_set(i), rect(r) { + } + + bool operator==(const RectSet &rhs) const { + return (id_set == rhs.id_set) && (rect == rhs.rect); + } +}; + +void get_draw_regions(const std::vector> &in, + std::vector> *out); +} + +#endif diff --git a/public/hwcdefs.h b/public/hwcdefs.h index 5ba4a2a..774deb4 100644 --- a/public/hwcdefs.h +++ b/public/hwcdefs.h @@ -19,12 +19,12 @@ #include -#include "separate_rects.h" +#include "disjoint_layers.h" namespace hwcomposer { template -using HwcRect = separate_rects::Rect; +using HwcRect = Rect; enum class HWCBlending : int32_t { kBlendingNone = 0x0100, diff --git a/public/separate_rects.h b/public/separate_rects.h deleted file mode 100644 index de8b660..0000000 --- a/public/separate_rects.h +++ /dev/null @@ -1,169 +0,0 @@ -/* - * 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 - -#include -#include - -namespace separate_rects { - -template -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 - Rect(const Rect &rhs) { - for (int i = 0; i < 4; i++) - bounds[i] = rhs.bounds[i]; - } - - template - Rect &operator=(const Rect &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 -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 &rhs) const { - return bitset == rhs.bitset; - } - - bool operator<(const IdSet &rhs) const { - return bitset < rhs.bitset; - } - - IdSet operator|(const IdSet &rhs) const { - IdSet ret; - ret.bitset = bitset | rhs.bitset; - return ret; - } - - IdSet operator|(TId id) const { - IdSet ret; - ret.bitset = bitset; - ret.add(id); - return ret; - } - - static const int max_elements = sizeof(TId) * 8; - - private: - TUInt bitset; -}; - -template -struct RectSet { - IdSet id_set; - Rect rect; - - RectSet(const IdSet &i, const Rect &r) : id_set(i), rect(r) { - } - - bool operator==(const RectSet &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> &in, - std::vector> *out); -void separate_rects_64(const std::vector> &in, - std::vector> *out); - -} // namespace separate_rects - -#endif