diff options
author | Rob Herring <robh@kernel.org> | 2018-05-09 15:18:36 -0500 |
---|---|---|
committer | Sean Paul <seanpaul@chromium.org> | 2018-05-30 13:31:41 -0400 |
commit | cff7b1e829c3ee3608146144148b6602e218fbae (patch) | |
tree | eac02dd14f57f71d54fb38fb41c4f0d0d8c1f40d | |
parent | af0d975665ca68a3396854cd20b18e59002c2ec5 (diff) |
drm_hwcomposer: remove separate_rects
As part of removing GL compositing, separate_rects.cpp is no long
needed. Use hwc_rect_t and hwc_frect_t in places instead of our own
class.
Signed-off-by: Rob Herring <robh@kernel.org>
-rw-r--r-- | Android.mk | 1 | ||||
-rw-r--r-- | drmdisplaycomposition.cpp | 19 | ||||
-rw-r--r-- | drmdisplaycomposition.h | 7 | ||||
-rw-r--r-- | drmdisplaycompositor.cpp | 4 | ||||
-rw-r--r-- | drmdisplaycompositor.h | 1 | ||||
-rw-r--r-- | drmhwcomposer.h | 10 | ||||
-rw-r--r-- | hwcutils.cpp | 5 | ||||
-rw-r--r-- | separate_rects.cpp | 317 | ||||
-rw-r--r-- | separate_rects.h | 169 | ||||
-rw-r--r-- | tests/Android.mk | 1 | ||||
-rw-r--r-- | tests/separate_rects_test.cpp | 100 |
11 files changed, 9 insertions, 625 deletions
@@ -75,7 +75,6 @@ LOCAL_SRC_FILES := \ hwcutils.cpp \ platform.cpp \ platformdrmgeneric.cpp \ - separate_rects.cpp \ vsyncworker.cpp LOCAL_CFLAGS := $(common_drm_hwcomposer_cflags) diff --git a/drmdisplaycomposition.cpp b/drmdisplaycomposition.cpp index ccf2676..129bec2 100644 --- a/drmdisplaycomposition.cpp +++ b/drmdisplaycomposition.cpp @@ -96,18 +96,6 @@ int DrmDisplayComposition::AddPlaneComposition(DrmCompositionPlane plane) { return 0; } -void DrmDisplayComposition::SeparateLayers(DrmHwcRect<int> *, size_t) { - std::vector<size_t> dedicated_layers; - - // Go through the composition and find the layers that have a dedicated plane. - for (auto &i : composition_planes_) { - if (i.type() == DrmCompositionPlane::Type::kLayer) { - dedicated_layers.insert(dedicated_layers.end(), i.source_layers().begin(), - i.source_layers().end()); - } - } -} - int DrmDisplayComposition::Plan(std::vector<DrmPlane *> *primary_planes, std::vector<DrmPlane *> *overlay_planes) { if (type_ != DRM_COMPOSITION_TYPE_FRAME) @@ -279,12 +267,7 @@ void DrmDisplayComposition::Dump(std::ostringstream *out) const { *out << " transform="; DumpTransform(layer.transform, out); *out << " blending[a=" << (int)layer.alpha - << "]=" << BlendingToString(layer.blending) << " source_crop"; - layer.source_crop.Dump(out); - *out << " display_frame"; - layer.display_frame.Dump(out); - - *out << "\n"; + << "]=" << BlendingToString(layer.blending) << "\n"; } *out << " Planes: count=" << composition_planes_.size() << "\n"; diff --git a/drmdisplaycomposition.h b/drmdisplaycomposition.h index 6110bec..b4c5892 100644 --- a/drmdisplaycomposition.h +++ b/drmdisplaycomposition.h @@ -51,7 +51,6 @@ struct DrmCompositionDisplayLayersMap { }; struct DrmCompositionRegion { - DrmHwcRect<int> frame; std::vector<size_t> source_layers; }; @@ -124,8 +123,6 @@ class DrmDisplayComposition { int Plan(std::vector<DrmPlane *> *primary_planes, std::vector<DrmPlane *> *overlay_planes); - int FinalizeComposition(); - std::vector<DrmHwcLayer> &layers() { return layers_; } @@ -179,10 +176,6 @@ class DrmDisplayComposition { private: bool validate_composition_type(DrmCompositionType desired); - int FinalizeComposition(DrmHwcRect<int> *exclude_rects, - size_t num_exclude_rects); - void SeparateLayers(DrmHwcRect<int> *exclude_rects, size_t num_exclude_rects); - DrmResources *drm_ = NULL; DrmCrtc *crtc_ = NULL; Importer *importer_ = NULL; diff --git a/drmdisplaycompositor.cpp b/drmdisplaycompositor.cpp index 379d80e..2f9f6c6 100644 --- a/drmdisplaycompositor.cpp +++ b/drmdisplaycompositor.cpp @@ -205,8 +205,8 @@ int DrmDisplayCompositor::CommitFrame(DrmDisplayComposition *display_comp, int fb_id = -1; int fence_fd = -1; - DrmHwcRect<int> display_frame; - DrmHwcRect<float> source_crop; + hwc_rect_t display_frame; + hwc_frect_t source_crop; uint64_t rotation = 0; uint64_t alpha = 0xFFFF; diff --git a/drmdisplaycompositor.h b/drmdisplaycompositor.h index eaf82fc..ed46873 100644 --- a/drmdisplaycompositor.h +++ b/drmdisplaycompositor.h @@ -20,7 +20,6 @@ #include "drmhwcomposer.h" #include "drmdisplaycomposition.h" #include "drmframebuffer.h" -#include "separate_rects.h" #include <pthread.h> #include <memory> diff --git a/drmhwcomposer.h b/drmhwcomposer.h index 1723fcb..f3b000b 100644 --- a/drmhwcomposer.h +++ b/drmhwcomposer.h @@ -20,10 +20,11 @@ #include <stdbool.h> #include <stdint.h> +#include <vector> + #include <hardware/hardware.h> #include <hardware/hwcomposer.h> #include "autofd.h" -#include "separate_rects.h" #include "drmhwcgralloc.h" struct hwc_import_context; @@ -110,9 +111,6 @@ class DrmHwcNativeHandle { native_handle_t *handle_ = NULL; }; -template <typename T> -using DrmHwcRect = separate_rects::Rect<T>; - enum DrmHwcTransform { kIdentity = 0, kFlipH = 1 << 0, @@ -136,8 +134,8 @@ struct DrmHwcLayer { uint32_t transform; DrmHwcBlending blending = DrmHwcBlending::kNone; uint16_t alpha = 0xffff; - DrmHwcRect<float> source_crop; - DrmHwcRect<int> display_frame; + hwc_frect_t source_crop; + hwc_rect_t display_frame; UniqueFd acquire_fence; OutputFd release_fence; diff --git a/hwcutils.cpp b/hwcutils.cpp index 7ba382a..e452bc8 100644 --- a/hwcutils.cpp +++ b/hwcutils.cpp @@ -106,12 +106,11 @@ int DrmHwcLayer::ImportBuffer(Importer *importer) { } void DrmHwcLayer::SetSourceCrop(hwc_frect_t const &crop) { - source_crop = DrmHwcRect<float>(crop.left, crop.top, crop.right, crop.bottom); + source_crop = crop; } void DrmHwcLayer::SetDisplayFrame(hwc_rect_t const &frame) { - display_frame = - DrmHwcRect<int>(frame.left, frame.top, frame.right, frame.bottom); + display_frame = frame; } void DrmHwcLayer::SetTransform(int32_t sf_transform) { diff --git a/separate_rects.cpp b/separate_rects.cpp deleted file mode 100644 index 0e74cfc..0000000 --- a/separate_rects.cpp +++ /dev/null @@ -1,317 +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 <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.push_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->push_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 diff --git a/separate_rects.h b/separate_rects.h deleted file mode 100644 index de8b660..0000000 --- a/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 <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 diff --git a/tests/Android.mk b/tests/Android.mk index c6a0afa..b498d62 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -3,7 +3,6 @@ LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES := \ - separate_rects_test.cpp \ worker_test.cpp LOCAL_MODULE := hwc-drm-tests diff --git a/tests/separate_rects_test.cpp b/tests/separate_rects_test.cpp deleted file mode 100644 index d9595dd..0000000 --- a/tests/separate_rects_test.cpp +++ /dev/null @@ -1,100 +0,0 @@ -#include <gtest/gtest.h> -#include <hardware/hardware.h> - -#include "separate_rects.h" - -using namespace separate_rects; - -#define RectSet RectSet<TId, TNum> -#define Rect Rect<TNum> -#define IdSet IdSet<TId> -typedef uint64_t TId; -typedef float TNum; - -struct SeparateRectTest : public testing::Test { - bool IsEquality(std::vector<RectSet> &out, - std::vector<RectSet> &expected_out) { - // Test for rects missing from out - for (size_t i = 0; i < expected_out.size(); i++) { - RectSet &ex_out = expected_out[i]; - if (std::find(out.begin(), out.end(), ex_out) == out.end()) { - return false; - } - } - - // Test for presence of unexpected rects in out - for (size_t 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()) { - return false; - } - } - - return true; - } -}; - -TEST_F(SeparateRectTest, test_separate_rect) { - std::vector<Rect> in; - std::vector<RectSet> out; - std::vector<RectSet> expected_out; - - in.push_back({0, 0, 4, 5}); - in.push_back({2, 0, 6, 6}); - in.push_back({4, 0, 8, 5}); - in.push_back({0, 7, 8, 9}); - - in.push_back({10, 0, 18, 5}); - in.push_back({12, 0, 16, 5}); - - in.push_back({20, 11, 24, 17}); - in.push_back({22, 13, 26, 21}); - in.push_back({32, 33, 36, 37}); - in.push_back({30, 31, 38, 39}); - - in.push_back({40, 43, 48, 45}); - in.push_back({44, 41, 46, 47}); - - in.push_back({50, 51, 52, 53}); - in.push_back({50, 51, 52, 53}); - in.push_back({50, 51, 52, 53}); - - in.push_back({0, 0, 0, 10}); - in.push_back({0, 0, 10, 0}); - in.push_back({10, 0, 0, 10}); - in.push_back({0, 10, 10, 0}); - - for (int i = 0; i < 100000; i++) { - out.clear(); - separate_frects_64(in, &out); - } - - expected_out.push_back(RectSet(IdSet(0), Rect(0, 0, 2, 5))); - expected_out.push_back(RectSet(IdSet(1), Rect(2, 5, 6, 6))); - expected_out.push_back(RectSet(IdSet(1) | 0, Rect(2, 0, 4, 5))); - expected_out.push_back(RectSet(IdSet(1) | 2, Rect(4, 0, 6, 5))); - expected_out.push_back(RectSet(IdSet(2), Rect(6, 0, 8, 5))); - expected_out.push_back(RectSet(IdSet(3), Rect(0, 7, 8, 9))); - expected_out.push_back(RectSet(IdSet(4), Rect(10, 0, 12, 5))); - expected_out.push_back(RectSet(IdSet(5) | 4, Rect(12, 0, 16, 5))); - expected_out.push_back(RectSet(IdSet(4), Rect(16, 0, 18, 5))); - expected_out.push_back(RectSet(IdSet(6), Rect(20, 11, 22, 17))); - expected_out.push_back(RectSet(IdSet(6) | 7, Rect(22, 13, 24, 17))); - expected_out.push_back(RectSet(IdSet(6), Rect(22, 11, 24, 13))); - expected_out.push_back(RectSet(IdSet(7), Rect(22, 17, 24, 21))); - expected_out.push_back(RectSet(IdSet(7), Rect(24, 13, 26, 21))); - expected_out.push_back(RectSet(IdSet(9), Rect(30, 31, 32, 39))); - expected_out.push_back(RectSet(IdSet(8) | 9, Rect(32, 33, 36, 37))); - expected_out.push_back(RectSet(IdSet(9), Rect(32, 37, 36, 39))); - expected_out.push_back(RectSet(IdSet(9), Rect(32, 31, 36, 33))); - expected_out.push_back(RectSet(IdSet(9), Rect(36, 31, 38, 39))); - expected_out.push_back(RectSet(IdSet(10), Rect(40, 43, 44, 45))); - expected_out.push_back(RectSet(IdSet(10) | 11, Rect(44, 43, 46, 45))); - expected_out.push_back(RectSet(IdSet(11), Rect(44, 41, 46, 43))); - expected_out.push_back(RectSet(IdSet(11), Rect(44, 45, 46, 47))); - expected_out.push_back(RectSet(IdSet(10), Rect(46, 43, 48, 45))); - expected_out.push_back(RectSet(IdSet(12) | 13 | 14, Rect(50, 51, 52, 53))); - - ASSERT_TRUE(IsEquality(out, expected_out)); -} |