OSDN Git Service

drm_hwcomposer: remove separate_rects
authorRob Herring <robh@kernel.org>
Wed, 9 May 2018 20:18:36 +0000 (15:18 -0500)
committerSean Paul <seanpaul@chromium.org>
Wed, 30 May 2018 17:31:41 +0000 (13:31 -0400)
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>
Android.mk
drmdisplaycomposition.cpp
drmdisplaycomposition.h
drmdisplaycompositor.cpp
drmdisplaycompositor.h
drmhwcomposer.h
hwcutils.cpp
separate_rects.cpp [deleted file]
separate_rects.h [deleted file]
tests/Android.mk
tests/separate_rects_test.cpp [deleted file]

index e47a7d0..3d48ba5 100644 (file)
@@ -75,7 +75,6 @@ LOCAL_SRC_FILES := \
        hwcutils.cpp \
        platform.cpp \
        platformdrmgeneric.cpp \
-       separate_rects.cpp \
        vsyncworker.cpp
 
 LOCAL_CFLAGS := $(common_drm_hwcomposer_cflags)
index ccf2676..129bec2 100644 (file)
@@ -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";
index 6110bec..b4c5892 100644 (file)
@@ -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;
index 379d80e..2f9f6c6 100644 (file)
@@ -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;
 
index eaf82fc..ed46873 100644 (file)
@@ -20,7 +20,6 @@
 #include "drmhwcomposer.h"
 #include "drmdisplaycomposition.h"
 #include "drmframebuffer.h"
-#include "separate_rects.h"
 
 #include <pthread.h>
 #include <memory>
index 1723fcb..f3b000b 100644 (file)
 #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;
index 7ba382a..e452bc8 100644 (file)
@@ -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 (file)
index 0e74cfc..0000000
+++ /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 (file)
index de8b660..0000000
+++ /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
index c6a0afa..b498d62 100644 (file)
@@ -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 (file)
index d9595dd..0000000
+++ /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));
-}