Subject: [PATCH 01/21] wip: checkpoint source-private tiled DRM foundations

From: Justin Youens <[email-masked]>
Date: Sat, 15 Aug 2026 05:51:32 -0500

---
 CMakeLists.txt                         |   68 +-
 src/backend/drm/ConnectorScan.hpp      |   46 +
 src/backend/drm/PlaneFormats.cpp       |   45 +
 src/backend/drm/PlaneFormats.hpp       |   21 +
 src/backend/drm/PlaneViewport.cpp      |   61 +
 src/backend/drm/PlaneViewport.hpp      |   80 ++
 src/backend/drm/Tile.cpp               |  248 ++++
 src/backend/drm/Tile.hpp               |  137 ++
 src/backend/drm/TileModes.cpp          |  353 ++++++
 src/backend/drm/TileModes.hpp          |   82 ++
 src/backend/drm/TiledCrtcAllocator.cpp | 1187 +++++++++++++++++
 src/backend/drm/TiledCrtcAllocator.hpp |  398 ++++++
 tests/ConnectorScan.cpp                |  192 +++
 tests/PlaneFormats.cpp                 |  119 ++
 tests/PlaneViewport.cpp                |  129 ++
 tests/TileModes.cpp                    |  255 ++++
 tests/TileTopology.cpp                 |  205 +++
 tests/TiledCrtcAllocator.cpp           | 1613 ++++++++++++++++++++++++
 tests/TiledVisibility.cmake            |   79 ++
 tests/TiledVisibilityProbe.cpp         |    3 +
 20 files changed, 5319 insertions(+), 2 deletions(-)
 create mode 100644 src/backend/drm/ConnectorScan.hpp
 create mode 100644 src/backend/drm/PlaneFormats.cpp
 create mode 100644 src/backend/drm/PlaneFormats.hpp
 create mode 100644 src/backend/drm/PlaneViewport.cpp
 create mode 100644 src/backend/drm/PlaneViewport.hpp
 create mode 100644 src/backend/drm/Tile.cpp
 create mode 100644 src/backend/drm/Tile.hpp
 create mode 100644 src/backend/drm/TileModes.cpp
 create mode 100644 src/backend/drm/TileModes.hpp
 create mode 100644 src/backend/drm/TiledCrtcAllocator.cpp
 create mode 100644 src/backend/drm/TiledCrtcAllocator.hpp
 create mode 100644 tests/ConnectorScan.cpp
 create mode 100644 tests/PlaneFormats.cpp
 create mode 100644 tests/PlaneViewport.cpp
 create mode 100644 tests/TileModes.cpp
 create mode 100644 tests/TileTopology.cpp
 create mode 100644 tests/TiledCrtcAllocator.cpp
 create mode 100644 tests/TiledVisibility.cmake
 create mode 100644 tests/TiledVisibilityProbe.cpp

diff --git a/CMakeLists.txt b/CMakeLists.txt
index b1a7843c26ebc422e2ccaad9debb4812a423f6fa..51aa9f871d3d260de8e32fde5032d2c8bfe8ad20 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -60,8 +60,31 @@ endif()
 file(GLOB_RECURSE SRCFILES CONFIGURE_DEPENDS "src/*.cpp" "include/*.hpp")
 file(GLOB_RECURSE PUBLIC_HEADERS CONFIGURE_DEPENDS "include/*.hpp")
 
+set(AQUAMARINE_TILED_PRIVATE_SOURCES
+    "${CMAKE_CURRENT_SOURCE_DIR}/src/backend/drm/PlaneFormats.cpp"
+    "${CMAKE_CURRENT_SOURCE_DIR}/src/backend/drm/PlaneViewport.cpp"
+    "${CMAKE_CURRENT_SOURCE_DIR}/src/backend/drm/Tile.cpp"
+    "${CMAKE_CURRENT_SOURCE_DIR}/src/backend/drm/TileModes.cpp"
+    "${CMAKE_CURRENT_SOURCE_DIR}/src/backend/drm/TiledCrtcAllocator.cpp")
+list(REMOVE_ITEM SRCFILES ${AQUAMARINE_TILED_PRIVATE_SOURCES})
+
+add_library(aquamarine_tiled_private STATIC ${AQUAMARINE_TILED_PRIVATE_SOURCES})
+set_target_properties(aquamarine_tiled_private PROPERTIES POSITION_INDEPENDENT_CODE ON)
+target_compile_options(aquamarine_tiled_private
+                       PRIVATE -fvisibility=hidden -fvisibility-inlines-hidden)
+target_include_directories(
+  aquamarine_tiled_private
+  PRIVATE "./include" "./src" "./src/include" "./protocols"
+          "${CMAKE_BINARY_DIR}")
+target_link_libraries(aquamarine_tiled_private PRIVATE PkgConfig::deps)
+target_link_options(
+  aquamarine_tiled_private INTERFACE
+  "-Wl,--exclude-libs,$<TARGET_FILE_NAME:aquamarine_tiled_private>")
+
 add_library(aquamarine SHARED ${SRCFILES})
 if(deps_libinput_VERSION VERSION_GREATER_EQUAL "1.30")
+  target_compile_definitions(aquamarine_tiled_private
+                             PRIVATE AQUAMARINE_HAS_LIBINPUT_PLUGINS)
   target_compile_definitions(aquamarine PRIVATE AQUAMARINE_HAS_LIBINPUT_PLUGINS)
 endif()
 target_include_directories(
@@ -70,12 +93,24 @@ target_include_directories(
   PRIVATE "./src" "./src/include" "./protocols" "${CMAKE_BINARY_DIR}")
 set_target_properties(aquamarine PROPERTIES VERSION ${AQUAMARINE_VERSION}
                                             SOVERSION 13)
-target_link_libraries(aquamarine OpenGL::EGL OpenGL::OpenGL PkgConfig::deps)
+target_link_libraries(aquamarine PUBLIC OpenGL::EGL OpenGL::OpenGL
+                                  PkgConfig::deps)
+target_link_libraries(aquamarine PRIVATE aquamarine_tiled_private)
+
+add_library(aquamarine_tiled_visibility_probe SHARED
+            "tests/TiledVisibilityProbe.cpp")
+target_link_libraries(
+  aquamarine_tiled_visibility_probe
+  PRIVATE PkgConfig::deps
+          "-Wl,--whole-archive"
+          aquamarine_tiled_private
+          "-Wl,--no-whole-archive"
+          aquamarine)
 
 check_include_file("sys/timerfd.h" HAS_TIMERFD)
 pkg_check_modules(epoll IMPORTED_TARGET epoll-shim)
 if(NOT HAS_TIMERFD AND epoll_FOUND)
-  target_link_libraries(aquamarine PkgConfig::epoll)
+  target_link_libraries(aquamarine PUBLIC PkgConfig::epoll)
 endif()
 
 # Protocols
@@ -149,6 +184,35 @@ add_test(
   COMMAND attachments "attachments")
 add_dependencies(tests attachments)
 
+function(addTiledPrivateTest testName source)
+  add_executable(${testName} ${source})
+  target_include_directories(${testName} PRIVATE "./src")
+  target_link_libraries(${testName} PRIVATE PkgConfig::deps
+                                                aquamarine_tiled_private aquamarine)
+  add_test(
+    NAME ${testName}
+    WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/tests
+    COMMAND ${testName} ${testName})
+  add_dependencies(tests ${testName})
+endfunction()
+
+addTiledPrivateTest(connectorScan "tests/ConnectorScan.cpp")
+addTiledPrivateTest(tileTopology "tests/TileTopology.cpp")
+addTiledPrivateTest(tileModes "tests/TileModes.cpp")
+addTiledPrivateTest(planeFormats "tests/PlaneFormats.cpp")
+addTiledPrivateTest(planeViewport "tests/PlaneViewport.cpp")
+addTiledPrivateTest(tiledCrtcAllocator "tests/TiledCrtcAllocator.cpp")
+
+add_test(
+  NAME tiledVisibility
+  COMMAND
+    ${CMAKE_COMMAND} -DNM=${CMAKE_NM}
+    -DLIBRARY=$<TARGET_FILE:aquamarine>
+    -DPRIVATE_ARCHIVE=$<TARGET_FILE:aquamarine_tiled_private>
+    -DPROBE_LIBRARY=$<TARGET_FILE:aquamarine_tiled_visibility_probe> -P
+    "${CMAKE_SOURCE_DIR}/tests/TiledVisibility.cmake")
+add_dependencies(tests aquamarine_tiled_visibility_probe)
+
 # Installation
 install(TARGETS aquamarine)
 install(DIRECTORY "include/aquamarine" DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
diff --git a/src/backend/drm/ConnectorScan.hpp b/src/backend/drm/ConnectorScan.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..fe14983b0ccbee51de72f27600b97ffac1e940b5
--- /dev/null
+++ b/src/backend/drm/ConnectorScan.hpp
@@ -0,0 +1,46 @@
+#pragma once
+
+#include <algorithm>
+#include <cstdint>
+#include <functional>
+#include <optional>
+#include <span>
+#include <utility>
+#include <vector>
+
+namespace Aquamarine::NDRM { // NOLINT(readability-identifier-naming): established project namespace
+
+    enum class eConnectorScanResult : uint8_t {
+        COMMITTED = 0,
+        STAGING_FAILED,
+        DUPLICATE_CONNECTOR,
+    };
+
+    // Recoverable DRM acquisition and new-connector initialization failures are
+    // confined to staging. The commit callback is invoked exactly once and only
+    // after the full, duplicate-free snapshot has been staged successfully.
+    template <typename TStagedConnector, typename FStage, typename FCommit>
+    [[nodiscard]] eConnectorScanResult connectorScanTransaction(std::span<const uint32_t> connectorIds, FStage stage, FCommit commit) {
+        std::vector<uint32_t>         stagedIds;
+        std::vector<TStagedConnector> staged;
+        stagedIds.reserve(connectorIds.size());
+        staged.reserve(connectorIds.size());
+
+        for (const auto id : connectorIds) {
+            if (std::ranges::contains(stagedIds, id))
+                return eConnectorScanResult::DUPLICATE_CONNECTOR;
+
+            stagedIds.emplace_back(id);
+
+            auto connector = std::invoke(stage, id);
+            if (!connector)
+                return eConnectorScanResult::STAGING_FAILED;
+
+            staged.emplace_back(std::move(*connector));
+        }
+
+        std::invoke(commit, std::span<TStagedConnector>{staged});
+        return eConnectorScanResult::COMMITTED;
+    }
+
+}
diff --git a/src/backend/drm/PlaneFormats.cpp b/src/backend/drm/PlaneFormats.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..0903bc46eeb0205158344331f67521d13742adf9
--- /dev/null
+++ b/src/backend/drm/PlaneFormats.cpp
@@ -0,0 +1,45 @@
+#include "PlaneFormats.hpp"
+
+#include <algorithm>
+#include <iterator>
+
+using namespace Aquamarine;
+using namespace Aquamarine::NDRM;
+
+namespace {
+    bool containsExactPair(const SPlaneFormatSet& member, uint32_t drmFormat, uint64_t modifier) {
+        return std::ranges::any_of(member.formats, [drmFormat, modifier](const SDRMFormat& format) {
+            return format.drmFormat == drmFormat && std::ranges::find(format.modifiers, modifier) != format.modifiers.end();
+        });
+    }
+}
+
+std::vector<SDRMFormat> Aquamarine::NDRM::intersectPlaneFormats(std::span<const SPlaneFormatSet> members, size_t primaryMember) {
+    if (members.empty() || primaryMember >= members.size())
+        return {};
+
+    const auto&             PRIMARY = members.subspan(primaryMember, 1).front();
+    std::vector<SDRMFormat> result;
+    result.reserve(PRIMARY.formats.size());
+
+    for (const auto& PRIMARY_FORMAT : PRIMARY.formats) {
+        auto output = std::ranges::find(result, PRIMARY_FORMAT.drmFormat, &SDRMFormat::drmFormat);
+        if (output == result.end()) {
+            result.emplace_back(SDRMFormat{.drmFormat = PRIMARY_FORMAT.drmFormat});
+            output = std::prev(result.end());
+        }
+
+        for (const auto MODIFIER : PRIMARY_FORMAT.modifiers) {
+            if (std::ranges::find(output->modifiers, MODIFIER) != output->modifiers.end())
+                continue;
+
+            const bool SHARED_BY_ALL = std::ranges::all_of(
+                members, [drmFormat = PRIMARY_FORMAT.drmFormat, modifier = MODIFIER](const SPlaneFormatSet& member) { return containsExactPair(member, drmFormat, modifier); });
+            if (SHARED_BY_ALL)
+                output->modifiers.emplace_back(MODIFIER);
+        }
+    }
+
+    std::erase_if(result, [](const SDRMFormat& format) { return format.modifiers.empty(); });
+    return result;
+}
diff --git a/src/backend/drm/PlaneFormats.hpp b/src/backend/drm/PlaneFormats.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..0aa68776c21ce1686e69459efcf79858c6dff39a
--- /dev/null
+++ b/src/backend/drm/PlaneFormats.hpp
@@ -0,0 +1,21 @@
+#pragma once
+
+#include <aquamarine/backend/Misc.hpp>
+
+#include <cstddef>
+#include <span>
+#include <vector>
+
+namespace Aquamarine::NDRM { // NOLINT(readability-identifier-naming): established project namespace
+
+    struct SPlaneFormatSet {
+        std::span<const SDRMFormat> formats;
+    };
+
+    // Returns the exact (fourcc, modifier) capabilities shared by every member.
+    // Format and modifier ordering follow the explicitly selected primary member,
+    // with duplicate pairs retaining their first occurrence. INVALID is an
+    // ordinary implicit-modifier value and never aliases LINEAR.
+    [[nodiscard]] std::vector<SDRMFormat> intersectPlaneFormats(std::span<const SPlaneFormatSet> members, size_t primaryMember);
+
+}
diff --git a/src/backend/drm/PlaneViewport.cpp b/src/backend/drm/PlaneViewport.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e0434b3a38dd98fba95b0a5792ddeb08d057e89d
--- /dev/null
+++ b/src/backend/drm/PlaneViewport.cpp
@@ -0,0 +1,61 @@
+#include "PlaneViewport.hpp"
+
+#include <limits>
+
+using namespace Aquamarine::NDRM;
+
+namespace {
+    constexpr uint32_t   SOURCE_FRACTIONAL_BITS = 16;
+    constexpr uint32_t   MAX_SOURCE_INTEGER     = std::numeric_limits<uint32_t>::max() >> SOURCE_FRACTIONAL_BITS;
+
+    SPlaneViewportResult failure(ePlaneViewportError error) {
+        return {.error = error};
+    }
+
+    bool additionOverflows(uint32_t lhs, uint32_t rhs) {
+        return rhs > std::numeric_limits<uint32_t>::max() - lhs;
+    }
+
+    bool fixedPointEncodable(uint32_t value) {
+        return value <= MAX_SOURCE_INTEGER;
+    }
+
+    uint32_t toFixedPoint(uint32_t value) {
+        return value << SOURCE_FRACTIONAL_BITS;
+    }
+}
+
+SPlaneViewportResult Aquamarine::NDRM::encodePlaneViewport(const SPlaneFramebufferSize& framebuffer, const SPlaneViewport& viewport) {
+    if (framebuffer.width == 0 || framebuffer.height == 0)
+        return failure(ePlaneViewportError::ZERO_FRAMEBUFFER_DIMENSION);
+
+    if (viewport.source.width == 0 || viewport.source.height == 0)
+        return failure(ePlaneViewportError::ZERO_SOURCE_DIMENSION);
+
+    if (viewport.destination.width == 0 || viewport.destination.height == 0)
+        return failure(ePlaneViewportError::ZERO_DESTINATION_DIMENSION);
+
+    if (additionOverflows(viewport.source.x, viewport.source.width) || additionOverflows(viewport.source.y, viewport.source.height))
+        return failure(ePlaneViewportError::SOURCE_BOUNDS_OVERFLOW);
+
+    if (viewport.source.x + viewport.source.width > framebuffer.width || viewport.source.y + viewport.source.height > framebuffer.height)
+        return failure(ePlaneViewportError::SOURCE_OUT_OF_BOUNDS);
+
+    if (!fixedPointEncodable(viewport.source.x) || !fixedPointEncodable(viewport.source.y) || !fixedPointEncodable(viewport.source.width) ||
+        !fixedPointEncodable(viewport.source.height))
+        return failure(ePlaneViewportError::SOURCE_FIXED_POINT_OVERFLOW);
+
+    return {
+        .values =
+            {
+                .srcX  = toFixedPoint(viewport.source.x),
+                .srcY  = toFixedPoint(viewport.source.y),
+                .srcW  = toFixedPoint(viewport.source.width),
+                .srcH  = toFixedPoint(viewport.source.height),
+                .crtcX = viewport.destination.x,
+                .crtcY = viewport.destination.y,
+                .crtcW = viewport.destination.width,
+                .crtcH = viewport.destination.height,
+            },
+    };
+}
diff --git a/src/backend/drm/PlaneViewport.hpp b/src/backend/drm/PlaneViewport.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..c5e48cb438795d0a14d195eacee35bef2f70cc40
--- /dev/null
+++ b/src/backend/drm/PlaneViewport.hpp
@@ -0,0 +1,80 @@
+#pragma once
+
+#include <cstdint>
+
+namespace Aquamarine::NDRM { // NOLINT(readability-identifier-naming): established project namespace
+
+    struct SPlaneFramebufferSize {
+        uint32_t width  = 0;
+        uint32_t height = 0;
+
+        bool     operator==(const SPlaneFramebufferSize&) const = default;
+    };
+
+    struct SPlaneSourceRect {
+        uint32_t x      = 0;
+        uint32_t y      = 0;
+        uint32_t width  = 0;
+        uint32_t height = 0;
+
+        bool     operator==(const SPlaneSourceRect&) const = default;
+    };
+
+    struct SPlaneDestinationRect {
+        int32_t  x      = 0;
+        int32_t  y      = 0;
+        uint32_t width  = 0;
+        uint32_t height = 0;
+
+        bool     operator==(const SPlaneDestinationRect&) const = default;
+    };
+
+    struct SPlaneViewport {
+        SPlaneSourceRect      source;
+        SPlaneDestinationRect destination;
+
+        bool                  operator==(const SPlaneViewport&) const = default;
+    };
+
+    // Values for the standard KMS plane rectangle properties. Source values
+    // use the UAPI's unsigned 16.16 representation; destination positions stay
+    // signed until the atomic request serializes them.
+    struct SPlanePropertyValues {
+        uint32_t srcX  = 0;
+        uint32_t srcY  = 0;
+        uint32_t srcW  = 0;
+        uint32_t srcH  = 0;
+        int32_t  crtcX = 0;
+        int32_t  crtcY = 0;
+        uint32_t crtcW = 0;
+        uint32_t crtcH = 0;
+
+        bool     operator==(const SPlanePropertyValues&) const = default;
+    };
+
+    enum class ePlaneViewportError : uint8_t {
+        NONE = 0,
+        ZERO_FRAMEBUFFER_DIMENSION,
+        ZERO_SOURCE_DIMENSION,
+        ZERO_DESTINATION_DIMENSION,
+        SOURCE_BOUNDS_OVERFLOW,
+        SOURCE_OUT_OF_BOUNDS,
+        SOURCE_FIXED_POINT_OVERFLOW,
+    };
+
+    struct SPlaneViewportResult {
+        SPlanePropertyValues values;
+        ePlaneViewportError  error = ePlaneViewportError::NONE;
+
+        explicit             operator bool() const {
+            return error == ePlaneViewportError::NONE;
+        }
+
+        bool operator==(const SPlaneViewportResult&) const = default;
+    };
+
+    // Validates an integer-pixel viewport and encodes it without rounding.
+    // Failure returns zero property values and a stable, specific error.
+    [[nodiscard]] SPlaneViewportResult encodePlaneViewport(const SPlaneFramebufferSize& framebuffer, const SPlaneViewport& viewport);
+
+}
diff --git a/src/backend/drm/Tile.cpp b/src/backend/drm/Tile.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..80ac24d775739e3feb5aab0547768f064c4750e6
--- /dev/null
+++ b/src/backend/drm/Tile.cpp
@@ -0,0 +1,248 @@
+#include "Tile.hpp"
+
+#include <algorithm>
+#include <array>
+#include <charconv>
+#include <limits>
+#include <map>
+#include <set>
+
+using namespace Aquamarine::NTiling;
+
+Aquamarine::NTiling::STileParseResult Aquamarine::NTiling::parseTileInfo(std::string_view blob) {
+    if (const auto NULL_POS = blob.find('\0'); NULL_POS != std::string_view::npos)
+        blob = blob.substr(0, NULL_POS);
+
+    if (blob.empty())
+        return {.error = eTileParseError::EMPTY};
+
+    std::array<uint32_t, 8> values = {};
+    size_t                  begin  = 0;
+
+    for (size_t i = 0; i < values.size(); ++i) {
+        const auto END = blob.find(':', begin);
+        if ((i + 1 < values.size() && END == std::string_view::npos) || (i + 1 == values.size() && END != std::string_view::npos))
+            return {.error = eTileParseError::FIELD_COUNT};
+
+        const auto TOKEN_END = END == std::string_view::npos ? blob.size() : END;
+        if (TOKEN_END == begin)
+            return {.error = eTileParseError::INVALID_NUMBER};
+
+        const auto TOKEN  = blob.substr(begin, TOKEN_END - begin);
+        const auto RESULT = std::from_chars(TOKEN.data(), TOKEN.data() + TOKEN.size(), values.at(i));
+        if (RESULT.ec == std::errc::result_out_of_range)
+            return {.error = eTileParseError::NUMBER_OUT_OF_RANGE};
+        if (RESULT.ec != std::errc{} || RESULT.ptr != TOKEN.data() + TOKEN.size())
+            return {.error = eTileParseError::INVALID_NUMBER};
+
+        begin = TOKEN_END + 1;
+    }
+
+    STileInfo tile = {
+        .groupId         = values.at(0),
+        .isSingleMonitor = values.at(1) == 1,
+        .numHTile        = values.at(2),
+        .numVTile        = values.at(3),
+        .tileHLoc        = values.at(4),
+        .tileVLoc        = values.at(5),
+        .tileHSize       = values.at(6),
+        .tileVSize       = values.at(7),
+    };
+
+    if (tile.groupId == 0)
+        return {.error = eTileParseError::INVALID_GROUP};
+    if (values.at(1) > 1)
+        return {.error = eTileParseError::INVALID_SINGLE_MONITOR};
+    for (size_t i = 2; i < values.size(); ++i) {
+        if (values.at(i) > static_cast<uint32_t>(std::numeric_limits<int>::max()))
+            return {.error = eTileParseError::NUMBER_OUT_OF_RANGE};
+    }
+    if (tile.numHTile == 0 || tile.numVTile == 0)
+        return {.error = eTileParseError::INVALID_GRID};
+    if (tile.tileHLoc >= tile.numHTile || tile.tileVLoc >= tile.numVTile)
+        return {.error = eTileParseError::INVALID_LOCATION};
+    if (tile.tileHSize == 0 || tile.tileVSize == 0)
+        return {.error = eTileParseError::INVALID_SIZE};
+
+    return {.tile = tile};
+}
+
+std::string_view Aquamarine::NTiling::tileParseErrorName(eTileParseError error) {
+    switch (error) {
+        case eTileParseError::NONE: return "none";
+        case eTileParseError::EMPTY: return "empty property";
+        case eTileParseError::FIELD_COUNT: return "wrong field count";
+        case eTileParseError::INVALID_NUMBER: return "invalid number";
+        case eTileParseError::NUMBER_OUT_OF_RANGE: return "number out of range";
+        case eTileParseError::INVALID_GROUP: return "invalid group id";
+        case eTileParseError::INVALID_SINGLE_MONITOR: return "invalid single-monitor flag";
+        case eTileParseError::INVALID_GRID: return "invalid grid dimensions";
+        case eTileParseError::INVALID_LOCATION: return "tile outside grid";
+        case eTileParseError::INVALID_SIZE: return "invalid tile size";
+    }
+
+    return "unknown";
+}
+
+namespace {
+    using SConnectorGroup = std::vector<STileConnector>;
+
+    struct SGroupValidationResult {
+        std::optional<STileGroup> group;
+        eTileGroupError           error = eTileGroupError::INVALID_MEMBER;
+    };
+
+    bool validMember(const STileConnector& connector) {
+        const auto& TILE = connector.tile;
+        return connector.connectorId != 0 && TILE.groupId != 0 && TILE.numHTile != 0 && TILE.numVTile != 0 && TILE.tileHLoc < TILE.numHTile && TILE.tileVLoc < TILE.numVTile &&
+            TILE.tileHSize != 0 && TILE.tileVSize != 0;
+    }
+
+    SGroupValidationResult validateGroup(const STileGroupKey& key, SConnectorGroup connectors) {
+        std::ranges::sort(connectors, {}, &STileConnector::connectorId);
+
+        for (size_t i = 0; i < connectors.size(); ++i) {
+            const auto& CONNECTOR = connectors.at(i);
+            if (!validMember(CONNECTOR) || CONNECTOR.deviceId != key.deviceId || CONNECTOR.tile.groupId != key.groupId)
+                return {.error = eTileGroupError::INVALID_MEMBER};
+            if (i > 0 && connectors.at(i - 1).connectorId == CONNECTOR.connectorId)
+                return {.error = eTileGroupError::DUPLICATE_CONNECTOR};
+        }
+
+        const auto FIRST = connectors.front().tile;
+        for (const auto& CONNECTOR : connectors) {
+            if (CONNECTOR.tile.numHTile != FIRST.numHTile || CONNECTOR.tile.numVTile != FIRST.numVTile)
+                return {.error = eTileGroupError::INCONSISTENT_GRID};
+            if (CONNECTOR.tile.isSingleMonitor != FIRST.isSingleMonitor)
+                return {.error = eTileGroupError::INCONSISTENT_MONITOR};
+        }
+
+        std::set<std::pair<uint32_t, uint32_t>> locations;
+        for (const auto& CONNECTOR : connectors) {
+            if (!locations.emplace(CONNECTOR.tile.tileVLoc, CONNECTOR.tile.tileHLoc).second)
+                return {.error = eTileGroupError::DUPLICATE_TILE};
+        }
+
+        const uint64_t EXPECTED_MEMBERS = static_cast<uint64_t>(FIRST.numHTile) * FIRST.numVTile;
+        if (EXPECTED_MEMBERS != connectors.size())
+            return {.error = eTileGroupError::INCOMPLETE_GRID};
+
+        std::vector<uint32_t> columnWidths(FIRST.numHTile);
+        std::vector<uint32_t> rowHeights(FIRST.numVTile);
+        for (const auto& CONNECTOR : connectors) {
+            auto&       columnWidth = columnWidths.at(CONNECTOR.tile.tileHLoc);
+            auto&       rowHeight   = rowHeights.at(CONNECTOR.tile.tileVLoc);
+            const auto& TILE        = CONNECTOR.tile;
+
+            if ((columnWidth != 0 && columnWidth != TILE.tileHSize) || (rowHeight != 0 && rowHeight != TILE.tileVSize))
+                return {.error = eTileGroupError::INCONSISTENT_GEOMETRY};
+
+            columnWidth = TILE.tileHSize;
+            rowHeight   = TILE.tileVSize;
+        }
+
+        std::vector<uint32_t> xOffsets(FIRST.numHTile);
+        std::vector<uint32_t> yOffsets(FIRST.numVTile);
+        uint64_t              width  = 0;
+        uint64_t              height = 0;
+
+        for (size_t i = 0; i < columnWidths.size(); ++i) {
+            xOffsets.at(i) = width;
+            width += columnWidths.at(i);
+            if (width > std::numeric_limits<uint32_t>::max())
+                return {.error = eTileGroupError::GEOMETRY_OVERFLOW};
+        }
+
+        for (size_t i = 0; i < rowHeights.size(); ++i) {
+            yOffsets.at(i) = height;
+            height += rowHeights.at(i);
+            if (height > std::numeric_limits<uint32_t>::max())
+                return {.error = eTileGroupError::GEOMETRY_OVERFLOW};
+        }
+
+        std::ranges::sort(connectors, [](const STileConnector& lhs, const STileConnector& rhs) {
+            if (lhs.tile.tileVLoc != rhs.tile.tileVLoc)
+                return lhs.tile.tileVLoc < rhs.tile.tileVLoc;
+            if (lhs.tile.tileHLoc != rhs.tile.tileHLoc)
+                return lhs.tile.tileHLoc < rhs.tile.tileHLoc;
+            return lhs.connectorId < rhs.connectorId;
+        });
+
+        STileGroup group = {
+            .key              = key,
+            .isSingleMonitor  = FIRST.isSingleMonitor,
+            .numHTile         = FIRST.numHTile,
+            .numVTile         = FIRST.numVTile,
+            .width            = static_cast<uint32_t>(width),
+            .height           = static_cast<uint32_t>(height),
+            .kind             = eTileGroupKind::MULTI_STREAM,
+            .primaryConnector = connectors.front().connectorId,
+        };
+
+        for (const auto& CONNECTOR : connectors) {
+            const auto& TILE = CONNECTOR.tile;
+            group.members.emplace_back(STileGroupMember{
+                .connectorId = CONNECTOR.connectorId,
+                .tileHLoc    = TILE.tileHLoc,
+                .tileVLoc    = TILE.tileVLoc,
+                .x           = xOffsets.at(TILE.tileHLoc),
+                .y           = yOffsets.at(TILE.tileVLoc),
+                .width       = TILE.tileHSize,
+                .height      = TILE.tileVSize,
+            });
+
+            const bool HAS_COMBINED_MODE =
+                std::ranges::any_of(CONNECTOR.modes, [&group](const STileMode& mode) { return mode.width >= group.width && mode.height >= group.height; });
+            if (group.kind == eTileGroupKind::MULTI_STREAM && HAS_COMBINED_MODE) {
+                group.kind             = eTileGroupKind::DRIVER_UNIFIED;
+                group.primaryConnector = CONNECTOR.connectorId;
+            }
+        }
+
+        return {.group = std::move(group)};
+    }
+}
+
+Aquamarine::NTiling::STileTopology Aquamarine::NTiling::buildTileTopology(std::span<const STileConnector> connectors) {
+    std::map<STileGroupKey, SConnectorGroup> candidates;
+    for (const auto& CONNECTOR : connectors) {
+        if (CONNECTOR.tile.groupId == 0)
+            continue;
+        candidates[{.deviceId = CONNECTOR.deviceId, .groupId = CONNECTOR.tile.groupId}].emplace_back(CONNECTOR);
+    }
+
+    STileTopology topology;
+    for (auto& [key, members] : candidates) {
+        auto RESULT = validateGroup(key, members);
+        if (RESULT.group) {
+            topology.groups.emplace_back(std::move(*RESULT.group));
+            continue;
+        }
+
+        std::vector<uint32_t> connectorIds;
+        connectorIds.reserve(members.size());
+        for (const auto& MEMBER : members) {
+            connectorIds.emplace_back(MEMBER.connectorId);
+        }
+        std::ranges::sort(connectorIds);
+
+        topology.rejected.emplace_back(SRejectedTileGroup{.key = key, .error = RESULT.error, .connectorIds = std::move(connectorIds)});
+    }
+
+    return topology;
+}
+
+std::string_view Aquamarine::NTiling::tileGroupErrorName(eTileGroupError error) {
+    switch (error) {
+        case eTileGroupError::INVALID_MEMBER: return "invalid member";
+        case eTileGroupError::DUPLICATE_CONNECTOR: return "duplicate connector";
+        case eTileGroupError::INCONSISTENT_GRID: return "inconsistent grid";
+        case eTileGroupError::INCONSISTENT_MONITOR: return "inconsistent single-monitor flag";
+        case eTileGroupError::DUPLICATE_TILE: return "duplicate tile position";
+        case eTileGroupError::INCOMPLETE_GRID: return "incomplete grid";
+        case eTileGroupError::INCONSISTENT_GEOMETRY: return "inconsistent tile geometry";
+        case eTileGroupError::GEOMETRY_OVERFLOW: return "geometry overflow";
+    }
+
+    return "unknown";
+}
diff --git a/src/backend/drm/Tile.hpp b/src/backend/drm/Tile.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..8562dea73715e6fc0da1bc3bda4e3b390d0f1e0f
--- /dev/null
+++ b/src/backend/drm/Tile.hpp
@@ -0,0 +1,137 @@
+#pragma once
+
+#include <compare>
+#include <cstdint>
+#include <optional>
+#include <span>
+#include <string_view>
+#include <vector>
+
+namespace Aquamarine::NTiling { // NOLINT(readability-identifier-naming): established project namespace
+
+    struct STileInfo {
+        uint32_t groupId         = 0;
+        bool     isSingleMonitor = false;
+        uint32_t numHTile        = 0;
+        uint32_t numVTile        = 0;
+        uint32_t tileHLoc        = 0;
+        uint32_t tileVLoc        = 0;
+        uint32_t tileHSize       = 0;
+        uint32_t tileVSize       = 0;
+
+        bool     operator==(const STileInfo&) const = default;
+    };
+
+    enum class eTileParseError : uint8_t {
+        NONE = 0,
+        EMPTY,
+        FIELD_COUNT,
+        INVALID_NUMBER,
+        NUMBER_OUT_OF_RANGE,
+        INVALID_GROUP,
+        INVALID_SINGLE_MONITOR,
+        INVALID_GRID,
+        INVALID_LOCATION,
+        INVALID_SIZE,
+    };
+
+    struct STileParseResult {
+        std::optional<STileInfo> tile;
+        eTileParseError          error = eTileParseError::NONE;
+
+        explicit                 operator bool() const {
+            return tile.has_value();
+        }
+    };
+
+    // Parses the DRM TILE property format:
+    // group_id:single_monitor:num_h:num_v:h_loc:v_loc:h_size:v_size
+    STileParseResult parseTileInfo(std::string_view blob);
+    std::string_view tileParseErrorName(eTileParseError error);
+
+    struct STileMode {
+        uint32_t width  = 0;
+        uint32_t height = 0;
+
+        bool     operator==(const STileMode&) const = default;
+    };
+
+    struct STileConnector {
+        uint64_t  deviceId    = 0;
+        uint32_t  connectorId = 0;
+        STileInfo tile;
+        // Keep exact dimension pairs: independent width/height maxima can come
+        // from different modes and must not imply a driver-unified output.
+        std::vector<STileMode> modes;
+
+        bool                   operator==(const STileConnector&) const = default;
+    };
+
+    struct STileGroupKey {
+        uint64_t deviceId = 0;
+        uint32_t groupId  = 0;
+
+        auto     operator<=>(const STileGroupKey&) const = default;
+    };
+
+    enum class eTileGroupKind : uint8_t {
+        MULTI_STREAM = 0,
+        DRIVER_UNIFIED,
+    };
+
+    struct STileGroupMember {
+        uint32_t connectorId = 0;
+        uint32_t tileHLoc    = 0;
+        uint32_t tileVLoc    = 0;
+        uint32_t x           = 0;
+        uint32_t y           = 0;
+        uint32_t width       = 0;
+        uint32_t height      = 0;
+
+        bool     operator==(const STileGroupMember&) const = default;
+    };
+
+    struct STileGroup {
+        STileGroupKey                 key;
+        bool                          isSingleMonitor  = false;
+        uint32_t                      numHTile         = 0;
+        uint32_t                      numVTile         = 0;
+        uint32_t                      width            = 0;
+        uint32_t                      height           = 0;
+        eTileGroupKind                kind             = eTileGroupKind::MULTI_STREAM;
+        uint32_t                      primaryConnector = 0;
+        std::vector<STileGroupMember> members;
+
+        bool                          operator==(const STileGroup&) const = default;
+    };
+
+    enum class eTileGroupError : uint8_t {
+        INVALID_MEMBER = 0,
+        DUPLICATE_CONNECTOR,
+        INCONSISTENT_GRID,
+        INCONSISTENT_MONITOR,
+        DUPLICATE_TILE,
+        INCOMPLETE_GRID,
+        INCONSISTENT_GEOMETRY,
+        GEOMETRY_OVERFLOW,
+    };
+
+    struct SRejectedTileGroup {
+        STileGroupKey         key;
+        eTileGroupError       error = eTileGroupError::INVALID_MEMBER;
+        std::vector<uint32_t> connectorIds;
+
+        bool                  operator==(const SRejectedTileGroup&) const = default;
+    };
+
+    struct STileTopology {
+        std::vector<STileGroup>         groups;
+        std::vector<SRejectedTileGroup> rejected;
+    };
+
+    // Builds validated groups from connectors on any number of DRM devices. A TILE
+    // group ID is scoped to its device, and output ordering is deterministic.
+    STileTopology    buildTileTopology(std::span<const STileConnector> connectors);
+    std::string_view tileGroupErrorName(eTileGroupError error);
+
+}
diff --git a/src/backend/drm/TileModes.cpp b/src/backend/drm/TileModes.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..f0f3ad8a855c36daf842db234e2238d741c5287d
--- /dev/null
+++ b/src/backend/drm/TileModes.cpp
@@ -0,0 +1,353 @@
+#include "TileModes.hpp"
+
+#include <algorithm>
+#include <compare>
+#include <functional>
+#include <limits>
+#include <map>
+#include <numeric>
+#include <optional>
+#include <set>
+#include <string_view>
+#include <tuple>
+#include <utility>
+
+using namespace Aquamarine::NTiling;
+
+namespace {
+    struct STimingKey {
+        uint64_t refreshNumerator   = 0;
+        uint64_t refreshDenominator = 0;
+        uint32_t clock              = 0;
+        uint32_t flags              = 0;
+        uint16_t hdisplay           = 0;
+        uint16_t hsyncStart         = 0;
+        uint16_t hsyncEnd           = 0;
+        uint16_t htotal             = 0;
+        uint16_t hskew              = 0;
+        uint16_t vdisplay           = 0;
+        uint16_t vsyncStart         = 0;
+        uint16_t vsyncEnd           = 0;
+        uint16_t vtotal             = 0;
+        uint16_t vscan              = 0;
+
+        auto     operator<=>(const STimingKey&) const = default;
+    };
+
+    struct SModeTiming {
+        STimingKey timing;
+        uint32_t   refreshRate = 0;
+    };
+
+    struct SCandidate {
+        STimingKey                     timing;
+        uint32_t                       refreshRate         = 0;
+        bool                           allMembersPreferred = false;
+        std::vector<STilePhysicalMode> members;
+    };
+
+    using SModeSet = std::map<STimingKey, drmModeModeInfo>;
+
+    std::optional<uint64_t> checkedMultiply(uint64_t lhs, uint64_t rhs) {
+        if (rhs != 0 && lhs > std::numeric_limits<uint64_t>::max() / rhs)
+            return std::nullopt;
+
+        return lhs * rhs;
+    }
+
+    bool validTiming(const drmModeModeInfo& mode) {
+        return mode.clock != 0 && mode.hdisplay != 0 && mode.hdisplay <= mode.hsync_start && mode.hsync_start <= mode.hsync_end && mode.hsync_end <= mode.htotal &&
+            mode.vdisplay != 0 && mode.vdisplay <= mode.vsync_start && mode.vsync_start <= mode.vsync_end && mode.vsync_end <= mode.vtotal;
+    }
+
+    std::optional<SModeTiming> modeTiming(const drmModeModeInfo& mode) {
+        if (!validTiming(mode))
+            return std::nullopt;
+
+        auto numerator = checkedMultiply(mode.clock, 1000);
+        if (!numerator)
+            return std::nullopt;
+        if ((mode.flags & DRM_MODE_FLAG_INTERLACE) != 0)
+            numerator = checkedMultiply(*numerator, 2);
+        if (!numerator)
+            return std::nullopt;
+
+        auto denominator = checkedMultiply(mode.htotal, mode.vtotal);
+        if (!denominator)
+            return std::nullopt;
+        if ((mode.flags & DRM_MODE_FLAG_DBLSCAN) != 0)
+            denominator = checkedMultiply(*denominator, 2);
+        if (!denominator)
+            return std::nullopt;
+
+        const uint16_t VSCAN = std::max<uint16_t>(mode.vscan, 1);
+        denominator          = checkedMultiply(*denominator, VSCAN);
+        if (!denominator || *denominator == 0)
+            return std::nullopt;
+
+        const uint64_t DIVISOR             = std::gcd(*numerator, *denominator);
+        const uint64_t REFRESH_NUMERATOR   = *numerator / DIVISOR;
+        const uint64_t REFRESH_DENOMINATOR = *denominator / DIVISOR;
+
+        const auto     MILLIHERTZ_NUMERATOR = checkedMultiply(REFRESH_NUMERATOR, 1000);
+        if (!MILLIHERTZ_NUMERATOR)
+            return std::nullopt;
+
+        uint64_t   refreshRate = *MILLIHERTZ_NUMERATOR / REFRESH_DENOMINATOR;
+        const auto REMAINDER   = *MILLIHERTZ_NUMERATOR % REFRESH_DENOMINATOR;
+        if (REMAINDER >= (REFRESH_DENOMINATOR / 2) + (REFRESH_DENOMINATOR % 2))
+            ++refreshRate;
+        if (refreshRate > std::numeric_limits<uint32_t>::max())
+            return std::nullopt;
+
+        return SModeTiming{
+            .timing =
+                {
+                    .refreshNumerator   = REFRESH_NUMERATOR,
+                    .refreshDenominator = REFRESH_DENOMINATOR,
+                    .clock              = mode.clock,
+                    .flags              = mode.flags,
+                    .hdisplay           = mode.hdisplay,
+                    .hsyncStart         = mode.hsync_start,
+                    .hsyncEnd           = mode.hsync_end,
+                    .htotal             = mode.htotal,
+                    .hskew              = mode.hskew,
+                    .vdisplay           = mode.vdisplay,
+                    .vsyncStart         = mode.vsync_start,
+                    .vsyncEnd           = mode.vsync_end,
+                    .vtotal             = mode.vtotal,
+                    .vscan              = VSCAN,
+                },
+            .refreshRate = static_cast<uint32_t>(refreshRate),
+        };
+    }
+
+    bool preferred(const drmModeModeInfo& mode) {
+        return (mode.type & DRM_MODE_TYPE_PREFERRED) != 0;
+    }
+
+    std::string_view modeName(const drmModeModeInfo& mode) {
+        return {mode.name, sizeof(mode.name)};
+    }
+
+    auto modeFields(const drmModeModeInfo& mode) {
+        return std::tie(mode.clock, mode.hdisplay, mode.hsync_start, mode.hsync_end, mode.htotal, mode.hskew, mode.vdisplay, mode.vsync_start, mode.vsync_end, mode.vtotal,
+                        mode.vscan, mode.vrefresh, mode.flags, mode.type);
+    }
+
+    bool modePreferredOver(const drmModeModeInfo& candidate, const drmModeModeInfo& current) {
+        if (preferred(candidate) != preferred(current))
+            return preferred(candidate);
+        if (modeFields(candidate) != modeFields(current))
+            return modeFields(candidate) < modeFields(current);
+        return modeName(candidate) < modeName(current);
+    }
+
+    SModeSet collectModes(const STileGroupMember& member, const STileConnectorModes& connector) {
+        SModeSet modes;
+
+        for (const auto& MODE : connector.modes) {
+            if (MODE.hdisplay != member.width || MODE.vdisplay != member.height)
+                continue;
+
+            const auto TIMING = modeTiming(MODE);
+            if (!TIMING)
+                continue;
+
+            const auto [ITERATOR, INSERTED] = modes.emplace(TIMING->timing, MODE);
+            if (!INSERTED && modePreferredOver(MODE, ITERATOR->second))
+                ITERATOR->second = MODE;
+        }
+
+        return modes;
+    }
+
+    eTileModeSynthesisError validateGroup(const STileGroup& group) {
+        if (group.key.groupId == 0 || group.numHTile == 0 || group.numVTile == 0 || group.width == 0 || group.height == 0 || group.members.empty())
+            return eTileModeSynthesisError::INVALID_GROUP;
+
+        const uint64_t EXPECTED_MEMBERS = static_cast<uint64_t>(group.numHTile) * group.numVTile;
+        if (EXPECTED_MEMBERS != group.members.size())
+            return eTileModeSynthesisError::INVALID_GROUP;
+
+        const uint32_t TILE_WIDTH  = group.members.front().width;
+        const uint32_t TILE_HEIGHT = group.members.front().height;
+        if (TILE_WIDTH == 0 || TILE_HEIGHT == 0)
+            return eTileModeSynthesisError::INVALID_GROUP;
+
+        std::set<uint32_t> connectorIds;
+        for (size_t i = 0; i < group.members.size(); ++i) {
+            const auto& MEMBER = group.members.at(i);
+            if (MEMBER.connectorId == 0 || !connectorIds.emplace(MEMBER.connectorId).second)
+                return eTileModeSynthesisError::INVALID_GROUP;
+            if (MEMBER.tileHLoc != i % group.numHTile || MEMBER.tileVLoc != i / group.numHTile)
+                return eTileModeSynthesisError::INVALID_GROUP;
+            if (MEMBER.width != TILE_WIDTH || MEMBER.height != TILE_HEIGHT)
+                return eTileModeSynthesisError::NONUNIFORM_GEOMETRY;
+        }
+
+        const uint64_t EXPECTED_WIDTH  = static_cast<uint64_t>(TILE_WIDTH) * group.numHTile;
+        const uint64_t EXPECTED_HEIGHT = static_cast<uint64_t>(TILE_HEIGHT) * group.numVTile;
+        if (EXPECTED_WIDTH != group.width || EXPECTED_HEIGHT != group.height)
+            return eTileModeSynthesisError::INVALID_GROUP;
+
+        for (const auto& MEMBER : group.members) {
+            if (MEMBER.x != static_cast<uint64_t>(MEMBER.tileHLoc) * TILE_WIDTH || MEMBER.y != static_cast<uint64_t>(MEMBER.tileVLoc) * TILE_HEIGHT)
+                return eTileModeSynthesisError::INVALID_GROUP;
+        }
+
+        return eTileModeSynthesisError::NONE;
+    }
+
+    std::optional<std::reference_wrapper<const STileConnectorModes>> findConnector(const STileGroup& group, const STileGroupMember& member,
+                                                                                   std::span<const STileConnectorModes> connectors) {
+        std::optional<std::reference_wrapper<const STileConnectorModes>> result;
+
+        for (const auto& CONNECTOR : connectors) {
+            if (CONNECTOR.deviceId != group.key.deviceId || CONNECTOR.connectorId != member.connectorId)
+                continue;
+            if (result)
+                return std::nullopt;
+            result = std::cref(CONNECTOR);
+        }
+
+        return result;
+    }
+
+    std::strong_ordering compareFractions(STileModeRefresh lhs, STileModeRefresh rhs) {
+        bool       invert = false;
+
+        const auto maybeInvert = [&invert](std::strong_ordering ordering) {
+            if (!invert || ordering == std::strong_ordering::equal)
+                return ordering;
+            return ordering == std::strong_ordering::less ? std::strong_ordering::greater : std::strong_ordering::less;
+        };
+
+        while (true) {
+            const uint64_t LHS_QUOTIENT = lhs.numerator / lhs.denominator;
+            const uint64_t RHS_QUOTIENT = rhs.numerator / rhs.denominator;
+            if (LHS_QUOTIENT != RHS_QUOTIENT) {
+                const auto ORDERING = LHS_QUOTIENT <=> RHS_QUOTIENT;
+                return maybeInvert(ORDERING);
+            }
+
+            const uint64_t LHS_REMAINDER = lhs.numerator % lhs.denominator;
+            const uint64_t RHS_REMAINDER = rhs.numerator % rhs.denominator;
+            if (LHS_REMAINDER == 0 || RHS_REMAINDER == 0) {
+                const auto ORDERING = LHS_REMAINDER <=> RHS_REMAINDER;
+                return maybeInvert(ORDERING);
+            }
+
+            lhs    = {.numerator = lhs.denominator, .denominator = LHS_REMAINDER};
+            rhs    = {.numerator = rhs.denominator, .denominator = RHS_REMAINDER};
+            invert = !invert;
+        }
+    }
+
+    bool candidateLess(const SCandidate& lhs, const SCandidate& rhs) {
+        if (lhs.allMembersPreferred != rhs.allMembersPreferred)
+            return lhs.allMembersPreferred;
+
+        const auto REFRESH_ORDERING = compareFractions({.numerator = lhs.timing.refreshNumerator, .denominator = lhs.timing.refreshDenominator},
+                                                       {.numerator = rhs.timing.refreshNumerator, .denominator = rhs.timing.refreshDenominator});
+        if (REFRESH_ORDERING != std::strong_ordering::equal)
+            return REFRESH_ORDERING == std::strong_ordering::greater;
+
+        return lhs.timing < rhs.timing;
+    }
+}
+
+bool Aquamarine::NTiling::STilePhysicalMode::operator==(const STilePhysicalMode& other) const {
+    return connectorId == other.connectorId && modeFields(modeInfo) == modeFields(other.modeInfo) && modeName(modeInfo) == modeName(other.modeInfo);
+}
+
+Aquamarine::NTiling::STileModeSynthesisResult Aquamarine::NTiling::synthesizeTileModes(const STileGroup& group, std::span<const STileConnectorModes> connectors) {
+    if (group.kind != eTileGroupKind::MULTI_STREAM)
+        return {.error = eTileModeSynthesisError::NOT_MULTI_STREAM};
+
+    if (const auto ERROR = validateGroup(group); ERROR != eTileModeSynthesisError::NONE)
+        return {.error = ERROR};
+
+    std::vector<SModeSet> memberModes;
+    memberModes.reserve(group.members.size());
+
+    for (const auto& MEMBER : group.members) {
+        const auto CONNECTOR = findConnector(group, MEMBER, connectors);
+        if (!CONNECTOR)
+            return {.error = eTileModeSynthesisError::MEMBER_MISMATCH};
+        memberModes.emplace_back(collectModes(MEMBER, CONNECTOR->get()));
+    }
+
+    std::vector<SCandidate> candidates;
+    for (const auto& [timing, firstMode] : memberModes.front()) {
+        const auto FIRST_TIMING = modeTiming(firstMode);
+        if (!FIRST_TIMING)
+            continue;
+
+        SCandidate candidate = {
+            .timing              = timing,
+            .refreshRate         = FIRST_TIMING->refreshRate,
+            .allMembersPreferred = true,
+        };
+        candidate.members.reserve(group.members.size());
+
+        for (size_t i = 0; i < memberModes.size(); ++i) {
+            const auto MATCH = memberModes.at(i).find(timing);
+            if (MATCH == memberModes.at(i).end()) {
+                candidate.members.clear();
+                break;
+            }
+
+            candidate.allMembersPreferred = candidate.allMembersPreferred && preferred(MATCH->second);
+            candidate.members.emplace_back(STilePhysicalMode{.connectorId = group.members.at(i).connectorId, .modeInfo = MATCH->second});
+        }
+
+        if (!candidate.members.empty())
+            candidates.emplace_back(std::move(candidate));
+    }
+
+    if (candidates.empty())
+        return {.error = eTileModeSynthesisError::NO_COMMON_MODE};
+    if (candidates.size() > std::numeric_limits<uint32_t>::max())
+        return {.error = eTileModeSynthesisError::INVALID_GROUP};
+
+    std::ranges::sort(candidates, candidateLess);
+
+    STileModeSynthesisResult result;
+    result.modes.reserve(candidates.size());
+    result.mappings.reserve(candidates.size());
+
+    for (size_t i = 0; i < candidates.size(); ++i) {
+        auto&          candidate = candidates.at(i);
+        const uint32_t MODE_ID   = static_cast<uint32_t>(i + 1);
+        result.modes.emplace_back(STileLogicalMode{
+            .id          = MODE_ID,
+            .width       = group.width,
+            .height      = group.height,
+            .refreshRate = candidate.refreshRate,
+            .flags       = candidate.timing.flags,
+            .preferred   = i == 0,
+            .refresh =
+                {
+                    .numerator   = candidate.timing.refreshNumerator,
+                    .denominator = candidate.timing.refreshDenominator,
+                },
+        });
+        result.mappings.emplace_back(STileModeMap{.logicalModeId = MODE_ID, .members = std::move(candidate.members)});
+    }
+
+    return result;
+}
+
+std::string_view Aquamarine::NTiling::tileModeSynthesisErrorName(eTileModeSynthesisError error) {
+    switch (error) {
+        case eTileModeSynthesisError::NONE: return "none";
+        case eTileModeSynthesisError::NOT_MULTI_STREAM: return "not a multi-stream group";
+        case eTileModeSynthesisError::INVALID_GROUP: return "invalid tile group";
+        case eTileModeSynthesisError::MEMBER_MISMATCH: return "connector modes do not match group members";
+        case eTileModeSynthesisError::NONUNIFORM_GEOMETRY: return "nonuniform tile geometry";
+        case eTileModeSynthesisError::NO_COMMON_MODE: return "no common physical mode";
+    }
+
+    return "unknown";
+}
diff --git a/src/backend/drm/TileModes.hpp b/src/backend/drm/TileModes.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..0365b3385740347395fdd8d767d4ed91d5bc6648
--- /dev/null
+++ b/src/backend/drm/TileModes.hpp
@@ -0,0 +1,82 @@
+#pragma once
+
+#include "Tile.hpp"
+
+#include <cstdint>
+#include <span>
+#include <string_view>
+#include <vector>
+
+#include <xf86drmMode.h>
+
+namespace Aquamarine::NTiling { // NOLINT(readability-identifier-naming): established project namespace
+
+    struct STileConnectorModes {
+        uint64_t                     deviceId    = 0;
+        uint32_t                     connectorId = 0;
+        std::vector<drmModeModeInfo> modes;
+    };
+
+    // Exact normalized frame cadence. Both fields are reduced by their GCD.
+    struct STileModeRefresh {
+        uint64_t numerator   = 0;
+        uint64_t denominator = 0;
+
+        bool     operator==(const STileModeRefresh&) const = default;
+    };
+
+    struct STileLogicalMode {
+        // Local to one synthesis result and assigned after deterministic sorting.
+        uint32_t         id          = 0;
+        uint32_t         width       = 0;
+        uint32_t         height      = 0;
+        uint32_t         refreshRate = 0; // rounded mHz for output protocol use
+        uint32_t         flags       = 0;
+        bool             preferred   = false;
+        STileModeRefresh refresh;
+
+        bool             operator==(const STileLogicalMode&) const = default;
+    };
+
+    struct STilePhysicalMode {
+        uint32_t        connectorId = 0;
+        drmModeModeInfo modeInfo    = {};
+
+        bool            operator==(const STilePhysicalMode& other) const;
+    };
+
+    // The logical identity remains separate from the exact physical KMS blobs.
+    struct STileModeMap {
+        uint32_t                       logicalModeId = 0;
+        std::vector<STilePhysicalMode> members;
+
+        bool                           operator==(const STileModeMap&) const = default;
+    };
+
+    enum class eTileModeSynthesisError : uint8_t {
+        NONE = 0,
+        NOT_MULTI_STREAM,
+        INVALID_GROUP,
+        MEMBER_MISMATCH,
+        NONUNIFORM_GEOMETRY,
+        NO_COMMON_MODE,
+    };
+
+    struct STileModeSynthesisResult {
+        std::vector<STileLogicalMode> modes;
+        std::vector<STileModeMap>     mappings;
+        eTileModeSynthesisError       error = eTileModeSynthesisError::NONE;
+
+        explicit                      operator bool() const {
+            return error == eTileModeSynthesisError::NONE;
+        }
+
+        bool operator==(const STileModeSynthesisResult&) const = default;
+    };
+
+    // Intersects exact physical tile modes for a complete validated multi-stream
+    // group. It never creates a full-width drmModeModeInfo.
+    STileModeSynthesisResult synthesizeTileModes(const STileGroup& group, std::span<const STileConnectorModes> connectors);
+    std::string_view         tileModeSynthesisErrorName(eTileModeSynthesisError error);
+
+}
diff --git a/src/backend/drm/TiledCrtcAllocator.cpp b/src/backend/drm/TiledCrtcAllocator.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..359dd942f5caa7f0b910a84a305fe837724ad7d7
--- /dev/null
+++ b/src/backend/drm/TiledCrtcAllocator.cpp
@@ -0,0 +1,1187 @@
+#include "TiledCrtcAllocator.hpp"
+
+#include <algorithm>
+#include <array>
+#include <limits>
+#include <map>
+#include <set>
+#include <tuple>
+#include <utility>
+
+namespace Aquamarine::NDRM::NTiledCrtcAllocator { // NOLINT(readability-identifier-naming): established Aquamarine DRM namespace
+    class CPlanAssembler {
+      public:
+        static CBinding binding(bool tiled, CSharedPointer<const CGroupDefinition> definition, uint32_t tileX, uint32_t tileY, CSharedPointer<SDRMConnector> connector,
+                                CSharedPointer<const SResourceIncarnation> connectorIncarnation, CSharedPointer<SDRMCRTC> crtc,
+                                CSharedPointer<const SResourceIncarnation> crtcIncarnation, CSharedPointer<SDRMPlane> primaryPlane,
+                                CSharedPointer<const SResourceIncarnation> primaryPlaneIncarnation) {
+            return CBinding(tiled, std::move(definition), tileX, tileY, std::move(connector), std::move(connectorIncarnation), std::move(crtc), std::move(crtcIncarnation),
+                            std::move(primaryPlane), std::move(primaryPlaneIncarnation));
+        }
+
+        static CGroupAllocation group(CSharedPointer<const CGroupDefinition> definition, eGroupStatus status, std::vector<CBinding> bindings) {
+            return CGroupAllocation(std::move(definition), status, std::move(bindings));
+        }
+
+        static CSharedPointer<const CPlan> plan(CSharedPointer<const CSnapshot> snapshot, CSharedPointer<const CAllocationObservation> observation, ePlanStatus status,
+                                                std::vector<CGroupAllocation> groups = {}, std::vector<CBinding> ordinaryBindings = {},
+                                                std::vector<uint32_t> unallocatedOrdinaryConnectorIDs = {}) {
+            CSharedPointer<CPlan> result(
+                new CPlan(std::move(snapshot), std::move(observation), status, std::move(groups), std::move(ordinaryBindings), std::move(unallocatedOrdinaryConnectorIDs)));
+            return result;
+        }
+    };
+
+    namespace {
+        template <typename T>
+        bool sameOwner(const CSharedPointer<const T>& lhs, const CSharedPointer<const T>& rhs) {
+            return lhs.impl_ != nullptr && lhs.impl_ == rhs.impl_;
+        }
+
+        template <typename T>
+        bool sameWeakOwner(const CWeakPointer<T>& lhs, const CWeakPointer<T>& rhs) {
+            return lhs.impl_ == rhs.impl_;
+        }
+
+        bool validGeneration(const SGeneration& generation) {
+            return generation.device != 0 && generation.session != 0 && generation.observation != 0;
+        }
+
+        bool validBackendBinding(const SDeviceIncarnation& device) {
+            if (!device.backendLifetime.valid())
+                return false;
+            const auto lifetime = device.backendLifetime.lock();
+            if (!lifetime || lifetime->serial == 0)
+                return false;
+            switch (device.binding) {
+                case eBackendBinding::LIFETIME_TOKEN: return device.backend.impl_ == nullptr;
+                case eBackendBinding::PRODUCTION_BACKEND: return device.backend.valid();
+            }
+            return false;
+        }
+
+        bool matchesBackendLifetime(const SDeviceIncarnation& device, const CSharedPointer<const SBackendIncarnation>& lifetime) {
+            if (!lifetime || lifetime->serial == 0 || !validBackendBinding(device))
+                return false;
+            const auto captured = device.backendLifetime.lock();
+            return sameOwner(captured, lifetime);
+        }
+
+        template <typename T>
+        void sortUnique(std::vector<T>& values) {
+            std::ranges::sort(values);
+            const auto duplicates = std::ranges::unique(values);
+            values.erase(duplicates.begin(), duplicates.end());
+        }
+
+        bool contains(const std::vector<uint32_t>& values, uint32_t value) {
+            return std::ranges::binary_search(values, value);
+        }
+
+        bool validIncarnation(const CSharedPointer<const SResourceIncarnation>& incarnation, eResourceKind kind, uint32_t id, const SGeneration& generation,
+                              const CSharedPointer<const SDeviceIncarnation>& device, const CSharedPointer<const SObservationIncarnation>& observation) {
+            return incarnation && incarnation->kind == kind && incarnation->resourceID == id && incarnation->serial != 0 && incarnation->generation == generation &&
+                sameOwner(incarnation->device, device) && sameOwner(incarnation->observation, observation);
+        }
+
+        bool tileMemberLess(const NTiling::STileGroupMember& lhs, const NTiling::STileGroupMember& rhs) {
+            return std::tie(lhs.tileVLoc, lhs.tileHLoc, lhs.connectorId, lhs.width, lhs.height) < std::tie(rhs.tileVLoc, rhs.tileHLoc, rhs.connectorId, rhs.width, rhs.height);
+        }
+
+        bool definitionLess(const CSharedPointer<const CGroupDefinition>& lhs, const CSharedPointer<const CGroupDefinition>& rhs) {
+            const auto& left  = lhs->group();
+            const auto& right = rhs->group();
+            if (left.key != right.key)
+                return left.key < right.key;
+            if (left.primaryConnector != right.primaryConnector)
+                return left.primaryConnector < right.primaryConnector;
+            return std::ranges::lexicographical_compare(left.members, right.members, tileMemberLess);
+        }
+
+        bool sameDefinitionKey(const CGroupDefinition& lhs, const CGroupDefinition& rhs) {
+            return lhs.group().key == rhs.group().key;
+        }
+
+        bool validDefinitionRegistry(std::vector<CSharedPointer<const CGroupDefinition>>& definitions) {
+            if (std::ranges::any_of(definitions, [](const auto& definition) { return !definition; }))
+                return false;
+            std::ranges::sort(definitions, definitionLess);
+            const auto duplicate = std::ranges::adjacent_find(definitions, [](const auto& lhs, const auto& rhs) { return sameDefinitionKey(*lhs, *rhs); });
+            if (duplicate != definitions.end())
+                return false;
+
+            std::set<uint32_t> connectorIDs;
+            for (const auto& definition : definitions) {
+                for (const auto& member : definition->group().members) {
+                    if (!connectorIDs.insert(member.connectorId).second)
+                        return false;
+                }
+            }
+            return true;
+        }
+
+        enum class eCandidateClass : uint8_t {
+            GROUP_MEMBER,
+            ENABLED_ORDINARY,
+            DISABLED_BACKUP,
+        };
+
+        struct SCanonicalMember {
+            eCandidateClass candidateClass = eCandidateClass::ENABLED_ORDINARY;
+            size_t          groupOrder     = 0;
+            uint32_t        connectorID    = 0;
+            uint32_t        tileX          = 0;
+            uint32_t        tileY          = 0;
+            bool            required       = false;
+        };
+
+        bool memberLess(const SCanonicalMember& lhs, const SCanonicalMember& rhs) {
+            return std::tie(lhs.candidateClass, lhs.groupOrder, lhs.tileY, lhs.tileX, lhs.connectorID) <
+                std::tie(rhs.candidateClass, rhs.groupOrder, rhs.tileY, rhs.tileX, rhs.connectorID);
+        }
+
+        struct STierCost {
+            int  drops            = 0;
+            int  droppedPreferred = 0;
+            int  connectorChanges = 0;
+            int  planeChanges     = 0;
+
+            bool operator==(const STierCost&) const = default;
+        };
+
+        STierCost operator+(const STierCost& lhs, const STierCost& rhs) {
+            return {
+                .drops            = lhs.drops + rhs.drops,
+                .droppedPreferred = lhs.droppedPreferred + rhs.droppedPreferred,
+                .connectorChanges = lhs.connectorChanges + rhs.connectorChanges,
+                .planeChanges     = lhs.planeChanges + rhs.planeChanges,
+            };
+        }
+
+        STierCost operator-(const STierCost& cost) {
+            return {
+                .drops            = -cost.drops,
+                .droppedPreferred = -cost.droppedPreferred,
+                .connectorChanges = -cost.connectorChanges,
+                .planeChanges     = -cost.planeChanges,
+            };
+        }
+
+        bool costLess(const STierCost& lhs, const STierCost& rhs) {
+            return std::tie(lhs.drops, lhs.droppedPreferred, lhs.connectorChanges, lhs.planeChanges) <
+                std::tie(rhs.drops, rhs.droppedPreferred, rhs.connectorChanges, rhs.planeChanges);
+        }
+
+        struct SFlowEdge {
+            size_t    to       = 0;
+            size_t    reverse  = 0;
+            int       capacity = 0;
+            STierCost cost;
+        };
+
+        using CFlowGraph = std::vector<std::vector<SFlowEdge>>;
+
+        void addFlowEdge(CFlowGraph& graph, size_t from, size_t to, int capacity, STierCost cost) {
+            const auto reverseFrom = graph.at(to).size();
+            const auto reverseTo   = graph.at(from).size();
+            graph.at(from).push_back({.to = to, .reverse = reverseFrom, .capacity = capacity, .cost = cost});
+            graph.at(to).push_back({.to = from, .reverse = reverseTo, .capacity = 0, .cost = -cost});
+        }
+
+        struct SSolverContext {
+            std::map<uint32_t, const SConnectorResource*>    connectors;
+            std::map<uint32_t, const SCRTCResource*>         crtcs;
+            std::map<uint32_t, const SPrimaryPlaneResource*> planes;
+            std::map<uint32_t, uint32_t>                     preferredConnectorCRTC;
+            std::map<uint32_t, uint32_t>                     preferredCRTCPlane;
+        };
+
+        STierCost bindingCost(const SSolverContext& context, uint32_t connectorID, uint32_t crtcID, uint32_t planeID) {
+            const auto connectorPreference = context.preferredConnectorCRTC.find(connectorID);
+            const auto planePreference     = context.preferredCRTCPlane.find(crtcID);
+            return {
+                .connectorChanges = connectorPreference != context.preferredConnectorCRTC.end() && connectorPreference->second != crtcID ? 1 : 0,
+                .planeChanges     = planePreference != context.preferredCRTCPlane.end() && planePreference->second != planeID ? 1 : 0,
+            };
+        }
+
+        STierCost dropCost(const SSolverContext& context, uint32_t connectorID) {
+            return {
+                .drops            = 1,
+                .droppedPreferred = context.preferredConnectorCRTC.contains(connectorID) ? 1 : 0,
+            };
+        }
+
+        std::optional<STierCost> minimumCost(const SSolverContext& context, std::span<const SCanonicalMember> members, const std::set<uint32_t>& usedCRTCs,
+                                             const std::set<uint32_t>& usedPlanes) {
+            if (members.empty())
+                return STierCost{};
+
+            std::vector<uint32_t> crtcIDs;
+            std::vector<uint32_t> planeIDs;
+            for (const auto& entry : context.crtcs) {
+                if (!usedCRTCs.contains(entry.first))
+                    crtcIDs.push_back(entry.first);
+            }
+            for (const auto& entry : context.planes) {
+                if (!usedPlanes.contains(entry.first) && entry.second->usable)
+                    planeIDs.push_back(entry.first);
+            }
+
+            const size_t source      = 0;
+            const size_t memberBase  = 1;
+            const size_t crtcInBase  = memberBase + members.size();
+            const size_t crtcOutBase = crtcInBase + crtcIDs.size();
+            const size_t planeBase   = crtcOutBase + crtcIDs.size();
+            const size_t sink        = planeBase + planeIDs.size();
+            const size_t nodeCount   = sink + 1;
+            CFlowGraph   graph(nodeCount);
+
+            for (size_t memberIndex = 0; memberIndex < members.size(); ++memberIndex) {
+                addFlowEdge(graph, source, memberBase + memberIndex, 1, {});
+                const auto& member    = members.subspan(memberIndex, 1).front();
+                const auto  connector = context.connectors.at(member.connectorID);
+                if (!member.required)
+                    addFlowEdge(graph, memberBase + memberIndex, sink, 1, dropCost(context, member.connectorID));
+                for (size_t crtcIndex = 0; crtcIndex < crtcIDs.size(); ++crtcIndex) {
+                    const auto crtcID = crtcIDs.at(crtcIndex);
+                    if (!contains(connector->possibleCRTCIDs, crtcID))
+                        continue;
+                    const auto preference = context.preferredConnectorCRTC.find(member.connectorID);
+                    addFlowEdge(graph, memberBase + memberIndex, crtcInBase + crtcIndex, 1,
+                                {.connectorChanges = preference != context.preferredConnectorCRTC.end() && preference->second != crtcID ? 1 : 0});
+                }
+            }
+
+            for (size_t crtcIndex = 0; crtcIndex < crtcIDs.size(); ++crtcIndex) {
+                const auto crtcID     = crtcIDs.at(crtcIndex);
+                const auto preference = context.preferredCRTCPlane.find(crtcID);
+                addFlowEdge(graph, crtcInBase + crtcIndex, crtcOutBase + crtcIndex, 1, {});
+                for (size_t planeIndex = 0; planeIndex < planeIDs.size(); ++planeIndex) {
+                    const auto planeID = planeIDs.at(planeIndex);
+                    if (!contains(context.planes.at(planeID)->possibleCRTCIDs, crtcID))
+                        continue;
+                    addFlowEdge(graph, crtcOutBase + crtcIndex, planeBase + planeIndex, 1,
+                                {.planeChanges = preference != context.preferredCRTCPlane.end() && preference->second != planeID ? 1 : 0});
+                }
+            }
+
+            for (size_t planeIndex = 0; planeIndex < planeIDs.size(); ++planeIndex)
+                addFlowEdge(graph, planeBase + planeIndex, sink, 1, {});
+
+            STierCost total;
+            size_t    flow = 0;
+            while (flow < members.size()) {
+                std::vector<std::optional<STierCost>> distances(nodeCount);
+                std::vector<size_t>                   previousNode(nodeCount, nodeCount);
+                std::vector<size_t>                   previousEdge(nodeCount, 0);
+                distances.at(source) = STierCost{};
+
+                for (size_t iteration = 1; iteration < nodeCount; ++iteration) {
+                    bool changed = false;
+                    for (size_t node = 0; node < nodeCount; ++node) {
+                        const auto& nodeDistance = distances.at(node);
+                        if (!nodeDistance)
+                            continue;
+                        for (size_t edgeIndex = 0; edgeIndex < graph.at(node).size(); ++edgeIndex) {
+                            const auto& edge = graph.at(node).at(edgeIndex);
+                            if (edge.capacity == 0)
+                                continue;
+                            const auto candidate    = nodeDistance.value() + edge.cost;
+                            auto&      edgeDistance = distances.at(edge.to);
+                            if (!edgeDistance || costLess(candidate, edgeDistance.value())) {
+                                edgeDistance             = candidate;
+                                previousNode.at(edge.to) = node;
+                                previousEdge.at(edge.to) = edgeIndex;
+                                changed                  = true;
+                            }
+                        }
+                    }
+                    if (!changed)
+                        break;
+                }
+
+                const auto& sinkDistance = distances.at(sink);
+                if (!sinkDistance)
+                    return std::nullopt;
+
+                for (size_t node = sink; node != source; node = previousNode.at(node)) {
+                    if (previousNode.at(node) == nodeCount)
+                        return std::nullopt;
+                    auto& edge = graph.at(previousNode.at(node)).at(previousEdge.at(node));
+                    --edge.capacity;
+                    ++graph.at(node).at(edge.reverse).capacity;
+                }
+
+                total = total + sinkDistance.value();
+                ++flow;
+            }
+
+            return total;
+        }
+
+        struct SInternalBinding {
+            SCanonicalMember member;
+            uint32_t         crtcID  = 0;
+            uint32_t         planeID = 0;
+        };
+
+        bool bindingLess(const SInternalBinding& lhs, const SInternalBinding& rhs) {
+            if (memberLess(lhs.member, rhs.member))
+                return true;
+            if (memberLess(rhs.member, lhs.member))
+                return false;
+            return std::tie(lhs.crtcID, lhs.planeID) < std::tie(rhs.crtcID, rhs.planeID);
+        }
+
+        struct STierSolution {
+            STierCost                     cost;
+            std::vector<SInternalBinding> bindings;
+            std::vector<uint32_t>         droppedConnectorIDs;
+        };
+
+        std::optional<STierSolution> solveCanonicalTier(const SSolverContext& context, std::vector<SCanonicalMember> members, const std::set<uint32_t>& initiallyUsedCRTCs,
+                                                        const std::set<uint32_t>& initiallyUsedPlanes, const std::optional<STierCost>& requiredCost = std::nullopt) {
+            std::ranges::sort(members, memberLess);
+            const auto target = minimumCost(context, members, initiallyUsedCRTCs, initiallyUsedPlanes);
+            if (!target || (requiredCost && !(*target == *requiredCost)))
+                return std::nullopt;
+
+            std::set<uint32_t>            usedCRTCs  = initiallyUsedCRTCs;
+            std::set<uint32_t>            usedPlanes = initiallyUsedPlanes;
+            STierCost                     fixedCost;
+            std::vector<SInternalBinding> bindings;
+            std::vector<uint32_t>         dropped;
+            bindings.reserve(members.size());
+
+            for (size_t memberIndex = 0; memberIndex < members.size(); ++memberIndex) {
+                const auto& member    = members.at(memberIndex);
+                const auto  connector = context.connectors.at(member.connectorID);
+                bool        selected  = false;
+
+                for (const auto crtcID : connector->possibleCRTCIDs) {
+                    if (usedCRTCs.contains(crtcID))
+                        continue;
+                    for (const auto& planeEntry : context.planes) {
+                        const auto planeID = planeEntry.first;
+                        const auto plane   = planeEntry.second;
+                        if (!plane->usable || usedPlanes.contains(planeID) || !contains(plane->possibleCRTCIDs, crtcID))
+                            continue;
+
+                        auto candidateCRTCs  = usedCRTCs;
+                        auto candidatePlanes = usedPlanes;
+                        candidateCRTCs.insert(crtcID);
+                        candidatePlanes.insert(planeID);
+                        const auto remaining = std::span<const SCanonicalMember>{members}.subspan(memberIndex + 1);
+                        const auto remainder = minimumCost(context, remaining, candidateCRTCs, candidatePlanes);
+                        if (!remainder || !(fixedCost + bindingCost(context, member.connectorID, crtcID, planeID) + *remainder == *target))
+                            continue;
+
+                        bindings.push_back({.member = member, .crtcID = crtcID, .planeID = planeID});
+                        fixedCost  = fixedCost + bindingCost(context, member.connectorID, crtcID, planeID);
+                        usedCRTCs  = std::move(candidateCRTCs);
+                        usedPlanes = std::move(candidatePlanes);
+                        selected   = true;
+                        break;
+                    }
+                    if (selected)
+                        break;
+                }
+
+                if (selected)
+                    continue;
+                if (member.required)
+                    return std::nullopt;
+                const auto remaining = std::span<const SCanonicalMember>{members}.subspan(memberIndex + 1);
+                const auto remainder = minimumCost(context, remaining, usedCRTCs, usedPlanes);
+                const auto omitted   = dropCost(context, member.connectorID);
+                if (!remainder || !(fixedCost + omitted + *remainder == *target))
+                    return std::nullopt;
+                fixedCost = fixedCost + omitted;
+                dropped.push_back(member.connectorID);
+            }
+
+            return STierSolution{.cost = *target, .bindings = std::move(bindings), .droppedConnectorIDs = std::move(dropped)};
+        }
+
+        struct SCombinedSolution {
+            bool                          valid = false;
+            STierCost                     backupCost;
+            std::vector<SInternalBinding> bindings;
+            std::vector<uint32_t>         droppedConnectorIDs;
+        };
+
+        enum class eCombinedStatus : uint8_t {
+            SOLVED,
+            NO_SOLUTION,
+            COMPLEXITY_LIMIT,
+        };
+
+        struct SCombinedResult {
+            eCombinedStatus                  status = eCombinedStatus::NO_SOLUTION;
+            std::optional<SCombinedSolution> solution;
+        };
+
+        struct SCombinedSearch {
+            // Counts visited backup-search states, not elapsed time. With two
+            // dense symmetric backups, seven CRTC/plane choices complete under
+            // this budget while eight deliberately use legacy fallback.
+            static constexpr size_t MAX_WORK = 2048;
+
+            size_t                  work      = 0;
+            bool                    exhausted = false;
+            SCombinedSolution       best;
+
+            bool                    spend() {
+                if (work >= MAX_WORK) {
+                    exhausted = true;
+                    return false;
+                }
+                ++work;
+                return true;
+            }
+        };
+
+        bool bindingVectorLess(const std::vector<SInternalBinding>& lhs, const std::vector<SInternalBinding>& rhs) {
+            return std::ranges::lexicographical_compare(lhs, rhs, bindingLess);
+        }
+
+        void enumerateBackupSolutions(const SSolverContext& context, const std::vector<SCanonicalMember>& activeMembers, const std::vector<SCanonicalMember>& backupMembers,
+                                      size_t memberIndex, const STierCost& activeTarget, const STierCost& fixedBackupCost, const std::set<uint32_t>& usedCRTCs,
+                                      const std::set<uint32_t>& usedPlanes, std::vector<SInternalBinding>& backupBindings, std::vector<uint32_t>& backupDropped,
+                                      SCombinedSearch& search) {
+            if (!search.spend())
+                return;
+            if (memberIndex == backupMembers.size()) {
+                const auto active = solveCanonicalTier(context, activeMembers, usedCRTCs, usedPlanes, activeTarget);
+                if (!active)
+                    return;
+                auto bindings = active->bindings;
+                bindings.insert(bindings.end(), backupBindings.begin(), backupBindings.end());
+                auto dropped = active->droppedConnectorIDs;
+                dropped.insert(dropped.end(), backupDropped.begin(), backupDropped.end());
+                if (!search.best.valid || costLess(fixedBackupCost, search.best.backupCost) ||
+                    (fixedBackupCost == search.best.backupCost && bindingVectorLess(bindings, search.best.bindings))) {
+                    search.best.valid               = true;
+                    search.best.backupCost          = fixedBackupCost;
+                    search.best.bindings            = std::move(bindings);
+                    search.best.droppedConnectorIDs = std::move(dropped);
+                }
+                return;
+            }
+
+            const auto remaining  = std::span<const SCanonicalMember>{backupMembers}.subspan(memberIndex);
+            const auto lowerBound = minimumCost(context, remaining, usedCRTCs, usedPlanes);
+            if (!lowerBound || (search.best.valid && costLess(search.best.backupCost, fixedBackupCost + *lowerBound)))
+                return;
+
+            const auto& member    = backupMembers.at(memberIndex);
+            const auto  connector = context.connectors.at(member.connectorID);
+            for (const auto crtcID : connector->possibleCRTCIDs) {
+                if (usedCRTCs.contains(crtcID))
+                    continue;
+                for (const auto& planeEntry : context.planes) {
+                    const auto planeID = planeEntry.first;
+                    const auto plane   = planeEntry.second;
+                    if (!plane->usable || usedPlanes.contains(planeID) || !contains(plane->possibleCRTCIDs, crtcID))
+                        continue;
+                    auto candidateCRTCs  = usedCRTCs;
+                    auto candidatePlanes = usedPlanes;
+                    candidateCRTCs.insert(crtcID);
+                    candidatePlanes.insert(planeID);
+                    const auto candidateCost = bindingCost(context, member.connectorID, crtcID, planeID);
+                    backupBindings.push_back({.member = member, .crtcID = crtcID, .planeID = planeID});
+                    enumerateBackupSolutions(context, activeMembers, backupMembers, memberIndex + 1, activeTarget, fixedBackupCost + candidateCost, candidateCRTCs, candidatePlanes,
+                                             backupBindings, backupDropped, search);
+                    backupBindings.pop_back();
+                    if (search.exhausted)
+                        return;
+                }
+            }
+
+            backupDropped.push_back(member.connectorID);
+            enumerateBackupSolutions(context, activeMembers, backupMembers, memberIndex + 1, activeTarget, fixedBackupCost + dropCost(context, member.connectorID), usedCRTCs,
+                                     usedPlanes, backupBindings, backupDropped, search);
+            backupDropped.pop_back();
+        }
+
+        SCombinedResult solveCombined(const SSolverContext& context, std::vector<SCanonicalMember> activeMembers, std::vector<SCanonicalMember> backupMembers,
+                                      const std::set<uint32_t>& initiallyUsedCRTCs, const std::set<uint32_t>& initiallyUsedPlanes, const STierCost& activeTarget) {
+            std::ranges::sort(activeMembers, memberLess);
+            std::ranges::sort(backupMembers, memberLess);
+            std::vector<SInternalBinding> backupBindings;
+            std::vector<uint32_t>         backupDropped;
+            SCombinedSearch               search;
+            enumerateBackupSolutions(context, activeMembers, backupMembers, 0, activeTarget, {}, initiallyUsedCRTCs, initiallyUsedPlanes, backupBindings, backupDropped, search);
+            if (search.exhausted)
+                return {.status = eCombinedStatus::COMPLEXITY_LIMIT, .solution = std::nullopt};
+            if (!search.best.valid)
+                return {.status = eCombinedStatus::NO_SOLUTION, .solution = std::nullopt};
+            return {.status = eCombinedStatus::SOLVED, .solution = std::move(search.best)};
+        }
+
+        CBinding makeBinding(const SSolverContext& context, const SInternalBinding& binding, const CSharedPointer<const CGroupDefinition>& definition) {
+            const auto connector = context.connectors.at(binding.member.connectorID);
+            const auto crtc      = context.crtcs.at(binding.crtcID);
+            const auto plane     = context.planes.at(binding.planeID);
+            return CPlanAssembler::binding(static_cast<bool>(definition), definition, binding.member.tileX, binding.member.tileY, connector->connector, connector->incarnation,
+                                           crtc->crtc, crtc->incarnation, plane->plane, plane->incarnation);
+        }
+
+        bool validHoldReason(eHardHoldReason reason) {
+            switch (reason) {
+                case eHardHoldReason::ACTIVE_OR_PENDING:
+                case eHardHoldReason::RETIRING:
+                case eHardHoldReason::LEASED:
+                case eHardHoldReason::FOREIGN_KERNEL_ATTACHMENT: return true;
+            }
+            return false;
+        }
+    }
+
+    std::optional<std::vector<uint32_t>> normalizeCRTCIDs(uint32_t possibleMask, std::span<const uint32_t> resourceOrder) {
+        if (resourceOrder.size() > std::numeric_limits<uint32_t>::digits)
+            return std::nullopt;
+
+        const auto representableCount = resourceOrder.size();
+        const auto representableMask = representableCount == std::numeric_limits<uint32_t>::digits ? std::numeric_limits<uint32_t>::max() : (uint32_t{1} << representableCount) - 1;
+        if ((possibleMask & ~representableMask) != 0)
+            return std::nullopt;
+
+        std::vector<uint32_t> uniqueOrder(resourceOrder.begin(), resourceOrder.end());
+        std::ranges::sort(uniqueOrder);
+        if (std::ranges::adjacent_find(uniqueOrder) != uniqueOrder.end())
+            return std::nullopt;
+
+        std::vector<uint32_t> ids;
+        ids.reserve(representableCount);
+        for (size_t index = 0; index < representableCount; ++index) {
+            if ((possibleMask & (uint32_t{1} << index)) != 0)
+                ids.push_back(resourceOrder.subspan(index, 1).front());
+        }
+        std::ranges::sort(ids);
+        return ids;
+    }
+
+    CSnapshot::CSnapshot(SGeneration generation, CSharedPointer<const SDeviceIncarnation> device, CSharedPointer<const SObservationIncarnation> observation,
+                         std::vector<SConnectorResource> connectors, std::vector<SCRTCResource> crtcs, std::vector<SPrimaryPlaneResource> primaryPlanes) :
+        m_generation(generation), m_device(std::move(device)), m_observation(std::move(observation)), m_connectors(std::move(connectors)), m_crtcs(std::move(crtcs)),
+        m_primaryPlanes(std::move(primaryPlanes)) {}
+
+    CSharedPointer<const CSnapshot> CSnapshot::create(SGeneration generation, CSharedPointer<const SObservationIncarnation> observation, std::vector<SConnectorResource> connectors,
+                                                      std::vector<SCRTCResource> crtcs, std::vector<SPrimaryPlaneResource> primaryPlanes) {
+        if (crtcs.size() > std::numeric_limits<uint32_t>::digits || !validGeneration(generation) || !observation || observation->serial == 0 ||
+            !(observation->generation == generation) || !observation->device || observation->device->deviceId == 0 || observation->device->deviceEpoch == 0 ||
+            observation->device->fdEpoch == 0 || observation->device->serial == 0 || observation->device->deviceEpoch != generation.device ||
+            !validBackendBinding(*observation->device) || !sameWeakOwner(observation->backendLifetime, observation->device->backendLifetime))
+            return {};
+        const auto device = observation->device;
+
+        const auto connectorLess = [](const SConnectorResource& lhs, const SConnectorResource& rhs) { return lhs.connector->id < rhs.connector->id; };
+        const auto crtcLess      = [](const SCRTCResource& lhs, const SCRTCResource& rhs) { return lhs.crtc->id < rhs.crtc->id; };
+        const auto planeLess     = [](const SPrimaryPlaneResource& lhs, const SPrimaryPlaneResource& rhs) { return lhs.plane->id < rhs.plane->id; };
+
+        for (auto& connector : connectors) {
+            if (!connector.connector || connector.connector->id == 0 || !sameWeakOwner(connector.connector->backend, device->backend) ||
+                !validIncarnation(connector.incarnation, eResourceKind::CONNECTOR, connector.connector->id, generation, device, observation))
+                return {};
+            sortUnique(connector.possibleCRTCIDs);
+        }
+        for (const auto& crtc : crtcs) {
+            if (!crtc.crtc || crtc.crtc->id == 0 || !sameWeakOwner(crtc.crtc->backend, device->backend) ||
+                !validIncarnation(crtc.incarnation, eResourceKind::CRTC, crtc.crtc->id, generation, device, observation))
+                return {};
+        }
+        for (auto& plane : primaryPlanes) {
+            if (!plane.plane || plane.plane->id == 0 || plane.plane->type != DRM_PLANE_TYPE_PRIMARY || !sameWeakOwner(plane.plane->backend, device->backend) ||
+                !validIncarnation(plane.incarnation, eResourceKind::PRIMARY_PLANE, plane.plane->id, generation, device, observation))
+                return {};
+            sortUnique(plane.possibleCRTCIDs);
+        }
+
+        std::ranges::sort(connectors, connectorLess);
+        std::ranges::sort(crtcs, crtcLess);
+        std::ranges::sort(primaryPlanes, planeLess);
+
+        if (std::ranges::adjacent_find(connectors, [](const auto& lhs, const auto& rhs) { return lhs.connector->id == rhs.connector->id; }) != connectors.end() ||
+            std::ranges::adjacent_find(crtcs, [](const auto& lhs, const auto& rhs) { return lhs.crtc->id == rhs.crtc->id; }) != crtcs.end() ||
+            std::ranges::adjacent_find(primaryPlanes, [](const auto& lhs, const auto& rhs) { return lhs.plane->id == rhs.plane->id; }) != primaryPlanes.end())
+            return {};
+
+        std::vector<uint32_t> crtcIDs;
+        crtcIDs.reserve(crtcs.size());
+        for (const auto& crtc : crtcs)
+            crtcIDs.push_back(crtc.crtc->id);
+
+        const auto referencesUnknownCRTC = [&crtcIDs](const std::vector<uint32_t>& possible) {
+            return std::ranges::any_of(possible, [&crtcIDs](uint32_t id) { return !std::ranges::binary_search(crtcIDs, id); });
+        };
+        if (std::ranges::any_of(connectors, [&](const auto& connector) { return referencesUnknownCRTC(connector.possibleCRTCIDs); }) ||
+            std::ranges::any_of(primaryPlanes, [&](const auto& plane) { return referencesUnknownCRTC(plane.possibleCRTCIDs); }))
+            return {};
+
+        CSharedPointer<CSnapshot> snapshot(new CSnapshot(generation, device, std::move(observation), std::move(connectors), std::move(crtcs), std::move(primaryPlanes)));
+        return snapshot;
+    }
+
+    const SGeneration& CSnapshot::generation() const {
+        return m_generation;
+    }
+
+    const CSharedPointer<const SDeviceIncarnation>& CSnapshot::device() const {
+        return m_device;
+    }
+
+    const CSharedPointer<const SObservationIncarnation>& CSnapshot::observation() const {
+        return m_observation;
+    }
+
+    const std::vector<SConnectorResource>& CSnapshot::connectors() const {
+        return m_connectors;
+    }
+
+    const std::vector<SCRTCResource>& CSnapshot::crtcs() const {
+        return m_crtcs;
+    }
+
+    const std::vector<SPrimaryPlaneResource>& CSnapshot::primaryPlanes() const {
+        return m_primaryPlanes;
+    }
+
+    CGroupDefinition::CGroupDefinition(NTiling::STileGroup group, CSharedPointer<const SDeviceIncarnation> device, uint64_t definitionSerial) :
+        m_group(std::move(group)), m_device(std::move(device)), m_serial(definitionSerial) {}
+
+    CSharedPointer<const CGroupDefinition> CGroupDefinition::create(NTiling::STileGroup group, CSharedPointer<const SDeviceIncarnation> device, uint64_t definitionSerial) {
+        if (!device || device->deviceId == 0 || device->deviceEpoch == 0 || device->fdEpoch == 0 || device->serial == 0 || !validBackendBinding(*device) || definitionSerial == 0 ||
+            group.key.deviceId == 0 || group.key.groupId == 0 || group.key.deviceId != device->deviceId || group.kind != NTiling::eTileGroupKind::MULTI_STREAM ||
+            !group.isSingleMonitor || group.members.size() <= 1 || group.numHTile == 0 || group.numVTile == 0 || group.width == 0 || group.height == 0 ||
+            group.primaryConnector == 0)
+            return {};
+
+        const uint64_t expectedMembers = static_cast<uint64_t>(group.numHTile) * group.numVTile;
+        if (expectedMembers != group.members.size())
+            return {};
+
+        std::ranges::sort(group.members, tileMemberLess);
+        std::set<uint32_t>                      connectorIDs;
+        std::set<std::pair<uint32_t, uint32_t>> coordinates;
+        std::vector<uint32_t>                   columnWidths(group.numHTile);
+        std::vector<uint32_t>                   rowHeights(group.numVTile);
+        for (const auto& member : group.members) {
+            if (member.connectorId == 0 || member.tileHLoc >= group.numHTile || member.tileVLoc >= group.numVTile || member.width == 0 || member.height == 0 ||
+                !connectorIDs.insert(member.connectorId).second || !coordinates.emplace(member.tileVLoc, member.tileHLoc).second)
+                return {};
+
+            auto& columnWidth = columnWidths.at(member.tileHLoc);
+            auto& rowHeight   = rowHeights.at(member.tileVLoc);
+            if ((columnWidth != 0 && columnWidth != member.width) || (rowHeight != 0 && rowHeight != member.height))
+                return {};
+            columnWidth = member.width;
+            rowHeight   = member.height;
+        }
+
+        if (group.primaryConnector != group.members.front().connectorId)
+            return {};
+
+        std::vector<uint32_t> xOffsets(group.numHTile);
+        std::vector<uint32_t> yOffsets(group.numVTile);
+        uint64_t              width  = 0;
+        uint64_t              height = 0;
+        for (size_t index = 0; index < columnWidths.size(); ++index) {
+            xOffsets.at(index) = static_cast<uint32_t>(width);
+            width += columnWidths.at(index);
+            if (width > std::numeric_limits<uint32_t>::max())
+                return {};
+        }
+        for (size_t index = 0; index < rowHeights.size(); ++index) {
+            yOffsets.at(index) = static_cast<uint32_t>(height);
+            height += rowHeights.at(index);
+            if (height > std::numeric_limits<uint32_t>::max())
+                return {};
+        }
+        if (width != group.width || height != group.height)
+            return {};
+        if (std::ranges::any_of(group.members, [&](const auto& member) { return member.x != xOffsets.at(member.tileHLoc) || member.y != yOffsets.at(member.tileVLoc); }))
+            return {};
+
+        CSharedPointer<CGroupDefinition> definition(new CGroupDefinition(std::move(group), std::move(device), definitionSerial));
+        return definition;
+    }
+
+    const NTiling::STileGroup& CGroupDefinition::group() const {
+        return m_group;
+    }
+
+    const CSharedPointer<const SDeviceIncarnation>& CGroupDefinition::device() const {
+        return m_device;
+    }
+
+    uint64_t CGroupDefinition::serial() const {
+        return m_serial;
+    }
+
+    CAllocationObservation::CAllocationObservation(SSnapshotExpectation expected, CWeakPointer<const SBackendIncarnation> backendLifetime,
+                                                   std::vector<CSharedPointer<const CGroupDefinition>> currentGroupDefinitions, std::vector<SHardHold> hardHolds,
+                                                   std::vector<SGroupRequest> groups, std::vector<SOrdinaryRequest> ordinary,
+                                                   std::vector<SConnectorCRTCPreference> connectorPreferences, std::vector<SCRTCPlanePreference> planePreferences,
+                                                   SAllocationEpoch epoch, std::thread::id eventThread) :
+        m_expected(std::move(expected)), m_backendLifetime(std::move(backendLifetime)), m_currentGroupDefinitions(std::move(currentGroupDefinitions)),
+        m_hardHolds(std::move(hardHolds)), m_groups(std::move(groups)), m_ordinary(std::move(ordinary)), m_connectorPreferences(std::move(connectorPreferences)),
+        m_planePreferences(std::move(planePreferences)), m_epoch(epoch), m_eventThread(eventThread) {}
+
+    CSharedPointer<const CAllocationObservation> CAllocationObservation::create(CSharedPointer<const CSnapshot>                     snapshot,
+                                                                                CSharedPointer<const SBackendIncarnation>           currentBackendLifetime,
+                                                                                std::vector<CSharedPointer<const CGroupDefinition>> currentGroupDefinitions,
+                                                                                std::vector<SHardHold> hardHolds, std::vector<SGroupRequest> groups,
+                                                                                std::vector<SOrdinaryRequest> ordinary, std::vector<SConnectorCRTCPreference> connectorPreferences,
+                                                                                std::vector<SCRTCPlanePreference> planePreferences, SAllocationEpoch epoch) {
+        if (!snapshot || !currentBackendLifetime || !matchesBackendLifetime(*snapshot->device(), currentBackendLifetime) || epoch.session == 0 || epoch.allocation == 0 ||
+            epoch.eventThread == 0 || epoch.session != snapshot->generation().session)
+            return {};
+        CSharedPointer<CAllocationObservation> observation(new CAllocationObservation(
+            expectationFor(snapshot), CWeakPointer<const SBackendIncarnation>{currentBackendLifetime}, std::move(currentGroupDefinitions), std::move(hardHolds), std::move(groups),
+            std::move(ordinary), std::move(connectorPreferences), std::move(planePreferences), epoch, std::this_thread::get_id()));
+        return observation;
+    }
+
+    const SSnapshotExpectation& CAllocationObservation::expected() const {
+        return m_expected;
+    }
+
+    const CWeakPointer<const SBackendIncarnation>& CAllocationObservation::backendLifetime() const {
+        return m_backendLifetime;
+    }
+
+    const std::vector<CSharedPointer<const CGroupDefinition>>& CAllocationObservation::currentGroupDefinitions() const {
+        return m_currentGroupDefinitions;
+    }
+
+    const std::vector<SHardHold>& CAllocationObservation::hardHolds() const {
+        return m_hardHolds;
+    }
+
+    const std::vector<SGroupRequest>& CAllocationObservation::groups() const {
+        return m_groups;
+    }
+
+    const std::vector<SOrdinaryRequest>& CAllocationObservation::ordinary() const {
+        return m_ordinary;
+    }
+
+    const std::vector<SConnectorCRTCPreference>& CAllocationObservation::connectorPreferences() const {
+        return m_connectorPreferences;
+    }
+
+    const std::vector<SCRTCPlanePreference>& CAllocationObservation::planePreferences() const {
+        return m_planePreferences;
+    }
+
+    const SAllocationEpoch& CAllocationObservation::epoch() const {
+        return m_epoch;
+    }
+
+    std::thread::id CAllocationObservation::eventThread() const {
+        return m_eventThread;
+    }
+
+    CBinding::CBinding(bool tiled, CSharedPointer<const CGroupDefinition> definition, uint32_t tileX, uint32_t tileY, CSharedPointer<SDRMConnector> connector,
+                       CSharedPointer<const SResourceIncarnation> connectorIncarnation, CSharedPointer<SDRMCRTC> crtc, CSharedPointer<const SResourceIncarnation> crtcIncarnation,
+                       CSharedPointer<SDRMPlane> primaryPlane, CSharedPointer<const SResourceIncarnation> primaryPlaneIncarnation) :
+        m_tiled(tiled), m_definition(std::move(definition)), m_tileX(tileX), m_tileY(tileY), m_connector(std::move(connector)),
+        m_connectorIncarnation(std::move(connectorIncarnation)), m_crtc(std::move(crtc)), m_crtcIncarnation(std::move(crtcIncarnation)), m_primaryPlane(std::move(primaryPlane)),
+        m_primaryPlaneIncarnation(std::move(primaryPlaneIncarnation)) {}
+
+    bool CBinding::tiled() const {
+        return m_tiled;
+    }
+
+    const CSharedPointer<const CGroupDefinition>& CBinding::definition() const {
+        return m_definition;
+    }
+
+    uint32_t CBinding::tileX() const {
+        return m_tileX;
+    }
+
+    uint32_t CBinding::tileY() const {
+        return m_tileY;
+    }
+
+    const CSharedPointer<SDRMConnector>& CBinding::connector() const {
+        return m_connector;
+    }
+
+    const CSharedPointer<const SResourceIncarnation>& CBinding::connectorIncarnation() const {
+        return m_connectorIncarnation;
+    }
+
+    const CSharedPointer<SDRMCRTC>& CBinding::crtc() const {
+        return m_crtc;
+    }
+
+    const CSharedPointer<const SResourceIncarnation>& CBinding::crtcIncarnation() const {
+        return m_crtcIncarnation;
+    }
+
+    const CSharedPointer<SDRMPlane>& CBinding::primaryPlane() const {
+        return m_primaryPlane;
+    }
+
+    const CSharedPointer<const SResourceIncarnation>& CBinding::primaryPlaneIncarnation() const {
+        return m_primaryPlaneIncarnation;
+    }
+
+    CGroupAllocation::CGroupAllocation(CSharedPointer<const CGroupDefinition> definition, eGroupStatus status, std::vector<CBinding> bindings) :
+        m_definition(std::move(definition)), m_status(status), m_bindings(std::move(bindings)) {}
+
+    const CSharedPointer<const CGroupDefinition>& CGroupAllocation::definition() const {
+        return m_definition;
+    }
+
+    eGroupStatus CGroupAllocation::status() const {
+        return m_status;
+    }
+
+    const std::vector<CBinding>& CGroupAllocation::bindings() const {
+        return m_bindings;
+    }
+
+    CPlan::CPlan(CSharedPointer<const CSnapshot> snapshot, CSharedPointer<const CAllocationObservation> observation, ePlanStatus status, std::vector<CGroupAllocation> groups,
+                 std::vector<CBinding> ordinaryBindings, std::vector<uint32_t> unallocatedOrdinaryConnectorIDs) :
+        m_snapshot(std::move(snapshot)), m_observation(std::move(observation)), m_status(status), m_groups(std::move(groups)), m_ordinaryBindings(std::move(ordinaryBindings)),
+        m_unallocatedOrdinaryConnectorIDs(std::move(unallocatedOrdinaryConnectorIDs)) {}
+
+    const CSharedPointer<const CSnapshot>& CPlan::snapshot() const {
+        return m_snapshot;
+    }
+
+    const CSharedPointer<const CAllocationObservation>& CPlan::observation() const {
+        return m_observation;
+    }
+
+    ePlanStatus CPlan::status() const {
+        return m_status;
+    }
+
+    const std::vector<CGroupAllocation>& CPlan::groups() const {
+        return m_groups;
+    }
+
+    const std::vector<CBinding>& CPlan::ordinaryBindings() const {
+        return m_ordinaryBindings;
+    }
+
+    const std::vector<uint32_t>& CPlan::unallocatedOrdinaryConnectorIDs() const {
+        return m_unallocatedOrdinaryConnectorIDs;
+    }
+
+    SSnapshotExpectation expectationFor(const CSharedPointer<const CSnapshot>& snapshot) {
+        if (!snapshot)
+            return {};
+        return {.snapshot = snapshot, .generation = snapshot->generation(), .device = snapshot->device(), .observation = snapshot->observation()};
+    }
+
+    CSharedPointer<const CPlan> solve(const CSharedPointer<const CAllocationObservation>& observation) {
+        if (!observation)
+            return CPlanAssembler::plan({}, {}, ePlanStatus::INVALID);
+        // This is the first observation-dependent check. A worker must not
+        // dereference the captured snapshot or any retained DRM resource.
+        if (observation->eventThread() != std::this_thread::get_id())
+            return CPlanAssembler::plan({}, observation, ePlanStatus::STALE);
+
+        const auto snapshot = observation->expected().snapshot;
+        const auto fail     = [&](ePlanStatus status) { return CPlanAssembler::plan(snapshot, observation, status); };
+        if (!snapshot)
+            return fail(ePlanStatus::INVALID);
+
+        const auto& expected = observation->expected();
+        if (!(expected.generation == snapshot->generation()) || !sameOwner(expected.device, snapshot->device()) || !sameOwner(expected.observation, snapshot->observation()))
+            return fail(ePlanStatus::STALE);
+        const auto backendLifetime = observation->backendLifetime().lock();
+        if (!matchesBackendLifetime(*snapshot->device(), backendLifetime) || observation->epoch().session != snapshot->generation().session)
+            return fail(ePlanStatus::STALE);
+
+        auto currentDefinitions = observation->currentGroupDefinitions();
+        if (!validDefinitionRegistry(currentDefinitions))
+            return fail(ePlanStatus::INVALID);
+        if (std::ranges::any_of(currentDefinitions, [&](const auto& definition) { return !sameOwner(definition->device(), snapshot->device()); }))
+            return fail(ePlanStatus::STALE);
+
+        SSolverContext context;
+        for (const auto& connector : snapshot->connectors())
+            context.connectors.emplace(connector.connector->id, &connector);
+        for (const auto& crtc : snapshot->crtcs())
+            context.crtcs.emplace(crtc.crtc->id, &crtc);
+        for (const auto& plane : snapshot->primaryPlanes())
+            context.planes.emplace(plane.plane->id, &plane);
+
+        const auto validConnector = [&context](const SConnectorHandle& handle) {
+            const auto resource = context.connectors.find(handle.id);
+            return resource != context.connectors.end() && sameOwner(handle.incarnation, resource->second->incarnation);
+        };
+        const auto validCRTC = [&context](const SCRTCHandle& handle) {
+            const auto resource = context.crtcs.find(handle.id);
+            return resource != context.crtcs.end() && sameOwner(handle.incarnation, resource->second->incarnation);
+        };
+        const auto validPlane = [&context](const SPrimaryPlaneHandle& handle) {
+            const auto resource = context.planes.find(handle.id);
+            return resource != context.planes.end() && sameOwner(handle.incarnation, resource->second->incarnation);
+        };
+
+        for (const auto& hold : observation->hardHolds()) {
+            if ((hold.connector && !validConnector(*hold.connector)) || (hold.crtc && !validCRTC(*hold.crtc)) || (hold.plane && !validPlane(*hold.plane)))
+                return fail(ePlanStatus::STALE);
+        }
+        for (const auto& group : observation->groups()) {
+            if (!group.definition)
+                return fail(ePlanStatus::INVALID);
+            if (!sameOwner(group.definition->device(), snapshot->device()))
+                return fail(ePlanStatus::STALE);
+            if (std::ranges::any_of(group.connectors, [&](const auto& connector) { return !validConnector(connector); }))
+                return fail(ePlanStatus::STALE);
+            if (group.retained) {
+                for (const auto& binding : *group.retained) {
+                    if (!validConnector(binding.connector) || !validCRTC(binding.crtc) || !validPlane(binding.primaryPlane))
+                        return fail(ePlanStatus::STALE);
+                }
+            }
+        }
+        for (const auto& ordinary : observation->ordinary()) {
+            if (!validConnector(ordinary.connector))
+                return fail(ePlanStatus::STALE);
+        }
+        for (const auto& preference : observation->connectorPreferences()) {
+            if (!validConnector(preference.connector) || !validCRTC(preference.crtc))
+                return fail(ePlanStatus::STALE);
+        }
+        for (const auto& preference : observation->planePreferences()) {
+            if (!validCRTC(preference.crtc) || !validPlane(preference.plane))
+                return fail(ePlanStatus::STALE);
+        }
+
+        std::set<uint32_t> heldConnectors;
+        std::set<uint32_t> usedCRTCs;
+        std::set<uint32_t> usedPlanes;
+        for (const auto& hold : observation->hardHolds()) {
+            if (!validHoldReason(hold.reason) || (!hold.connector && !hold.crtc && !hold.plane) || (hold.connector && !heldConnectors.insert(hold.connector->id).second) ||
+                (hold.crtc && !usedCRTCs.insert(hold.crtc->id).second) || (hold.plane && !usedPlanes.insert(hold.plane->id).second))
+                return fail(ePlanStatus::INVALID);
+            if (hold.connector && hold.crtc && !contains(context.connectors.at(hold.connector->id)->possibleCRTCIDs, hold.crtc->id))
+                return fail(ePlanStatus::INVALID);
+            if (hold.crtc && hold.plane && !contains(context.planes.at(hold.plane->id)->possibleCRTCIDs, hold.crtc->id))
+                return fail(ePlanStatus::INVALID);
+        }
+
+        struct SCanonicalGroup {
+            CSharedPointer<const CGroupDefinition>            definition;
+            std::vector<SCanonicalMember>                     members;
+            std::optional<std::vector<SRetainedGroupBinding>> retained;
+            std::vector<SInternalBinding>                     retainedBindings;
+            bool                                              selected = false;
+        };
+
+        std::vector<SCanonicalGroup> groups;
+        groups.reserve(observation->groups().size());
+        std::set<uint32_t> requestedConnectors;
+        std::set<uint32_t> requestedGroupIDs;
+        for (const auto& group : observation->groups()) {
+            const auto registered = std::ranges::find_if(currentDefinitions, [&](const auto& definition) { return definition->group().key == group.definition->group().key; });
+            if (registered == currentDefinitions.end() || !sameOwner(*registered, group.definition))
+                return fail(ePlanStatus::STALE);
+            if (!requestedGroupIDs.insert(group.definition->group().key.groupId).second)
+                return fail(ePlanStatus::INVALID);
+
+            std::set<uint32_t> projectedIDs;
+            for (const auto& connector : group.connectors) {
+                if (!projectedIDs.insert(connector.id).second || !requestedConnectors.insert(connector.id).second)
+                    return fail(ePlanStatus::INVALID);
+            }
+            const auto& definitionMembers = group.definition->group().members;
+            if (projectedIDs.size() != definitionMembers.size() ||
+                std::ranges::any_of(definitionMembers, [&](const auto& member) { return !projectedIDs.contains(member.connectorId); }))
+                return fail(ePlanStatus::INVALID);
+            groups.push_back({
+                .definition       = group.definition,
+                .members          = {},
+                .retained         = group.retained,
+                .retainedBindings = {},
+                .selected         = false,
+            });
+        }
+        if (groups.size() != currentDefinitions.size())
+            return fail(ePlanStatus::INVALID);
+
+        std::array<std::vector<uint32_t>, 2> ordinaryConnectorIDs;
+        for (const auto& ordinary : observation->ordinary()) {
+            if (!requestedConnectors.insert(ordinary.connector.id).second)
+                return fail(ePlanStatus::INVALID);
+            switch (ordinary.priority) {
+                case eOrdinaryPriority::ENABLED_UNMATCHED: ordinaryConnectorIDs.at(0).push_back(ordinary.connector.id); break;
+                case eOrdinaryPriority::DETACHED_DISABLED_BACKUP: ordinaryConnectorIDs.at(1).push_back(ordinary.connector.id); break;
+                default: return fail(ePlanStatus::INVALID);
+            }
+        }
+        if (std::ranges::any_of(requestedConnectors, [&heldConnectors](uint32_t id) { return heldConnectors.contains(id); }))
+            return fail(ePlanStatus::INVALID);
+
+        for (const auto& preference : observation->connectorPreferences()) {
+            if (!context.preferredConnectorCRTC.emplace(preference.connector.id, preference.crtc.id).second)
+                return fail(ePlanStatus::INVALID);
+        }
+        for (const auto& preference : observation->planePreferences()) {
+            if (!context.preferredCRTCPlane.emplace(preference.crtc.id, preference.plane.id).second)
+                return fail(ePlanStatus::INVALID);
+        }
+
+        std::ranges::sort(groups, [](const auto& lhs, const auto& rhs) { return definitionLess(lhs.definition, rhs.definition); });
+        for (size_t groupIndex = 0; groupIndex < groups.size(); ++groupIndex) {
+            auto& group = groups.at(groupIndex);
+            for (const auto& member : group.definition->group().members) {
+                group.members.push_back({
+                    .candidateClass = eCandidateClass::GROUP_MEMBER,
+                    .groupOrder     = groupIndex,
+                    .connectorID    = member.connectorId,
+                    .tileX          = member.tileHLoc,
+                    .tileY          = member.tileVLoc,
+                });
+            }
+        }
+
+        // Retention is mandatory and is validated/reserved before unresolved
+        // groups and optional active/backup demand enter the optimizer.
+        for (auto& group : groups) {
+            if (!group.retained)
+                continue;
+            if (group.retained->size() != group.members.size())
+                return fail(ePlanStatus::INVALID);
+            std::map<uint32_t, SRetainedGroupBinding> byConnector;
+            for (const auto& binding : *group.retained) {
+                if (!byConnector.emplace(binding.connector.id, binding).second)
+                    return fail(ePlanStatus::INVALID);
+            }
+            for (const auto& member : group.members) {
+                const auto retained = byConnector.find(member.connectorID);
+                if (retained == byConnector.end())
+                    return fail(ePlanStatus::INVALID);
+                const auto& binding = retained->second;
+                const auto  plane   = context.planes.at(binding.primaryPlane.id);
+                if (!plane->usable || !contains(context.connectors.at(member.connectorID)->possibleCRTCIDs, binding.crtc.id) ||
+                    !contains(plane->possibleCRTCIDs, binding.crtc.id) || !usedCRTCs.insert(binding.crtc.id).second || !usedPlanes.insert(binding.primaryPlane.id).second)
+                    return fail(ePlanStatus::INVALID);
+                group.retainedBindings.push_back({.member = member, .crtcID = binding.crtc.id, .planeID = binding.primaryPlane.id});
+            }
+            group.selected = true;
+        }
+
+        std::vector<SCanonicalMember> activeMembers;
+        std::vector<SCanonicalMember> backupMembers;
+        for (const auto& group : groups) {
+            if (!group.retained)
+                activeMembers.insert(activeMembers.end(), group.members.begin(), group.members.end());
+        }
+        for (const auto connectorID : ordinaryConnectorIDs.at(0))
+            activeMembers.push_back({.candidateClass = eCandidateClass::ENABLED_ORDINARY, .connectorID = connectorID});
+        for (const auto connectorID : ordinaryConnectorIDs.at(1))
+            backupMembers.push_back({.candidateClass = eCandidateClass::DISABLED_BACKUP, .connectorID = connectorID});
+        std::ranges::sort(activeMembers, memberLess);
+        std::ranges::sort(backupMembers, memberLess);
+
+        const auto activeTarget = minimumCost(context, activeMembers, usedCRTCs, usedPlanes);
+        if (!activeTarget)
+            return fail(ePlanStatus::INVALID);
+
+        // Group status is considered only after the exact active coverage and
+        // preference tuple. Force canonical complete groups when that tuple is
+        // unchanged; no CRTC or plane route is fixed here.
+        for (size_t groupIndex = 0; groupIndex < groups.size(); ++groupIndex) {
+            auto& group = groups.at(groupIndex);
+            if (group.retained)
+                continue;
+            for (auto& member : activeMembers) {
+                if (member.candidateClass == eCandidateClass::GROUP_MEMBER && member.groupOrder == groupIndex)
+                    member.required = true;
+            }
+            const auto candidateCost = minimumCost(context, activeMembers, usedCRTCs, usedPlanes);
+            if (candidateCost && *candidateCost == *activeTarget) {
+                group.selected = true;
+                continue;
+            }
+            for (auto& member : activeMembers) {
+                if (member.candidateClass == eCandidateClass::GROUP_MEMBER && member.groupOrder == groupIndex)
+                    member.required = false;
+            }
+        }
+
+        // Once aggregate status is fixed, every NO_MATCH member is an enabled
+        // ordinary fallback. Its final canonical key is connector ID, merged
+        // with explicit enabled ordinary demand; retained/ALLOCATED members
+        // preserve definition, tile, and member order.
+        for (size_t groupIndex = 0; groupIndex < groups.size(); ++groupIndex) {
+            if (groups.at(groupIndex).selected)
+                continue;
+            for (auto& member : activeMembers) {
+                if (member.candidateClass != eCandidateClass::GROUP_MEMBER || member.groupOrder != groupIndex)
+                    continue;
+                member.candidateClass = eCandidateClass::ENABLED_ORDINARY;
+                member.groupOrder     = 0;
+                member.tileX          = 0;
+                member.tileY          = 0;
+            }
+        }
+        std::ranges::sort(activeMembers, memberLess);
+
+        const auto combined = solveCombined(context, activeMembers, backupMembers, usedCRTCs, usedPlanes, *activeTarget);
+        if (combined.status == eCombinedStatus::COMPLEXITY_LIMIT)
+            return fail(ePlanStatus::UNSUPPORTED_COMPLEXITY);
+        if (combined.status != eCombinedStatus::SOLVED || !combined.solution)
+            return fail(ePlanStatus::INVALID);
+        const auto&                                     solution = *combined.solution;
+
+        std::map<size_t, std::vector<SInternalBinding>> groupBindings;
+        std::vector<SInternalBinding>                   ordinaryInternal;
+        for (const auto& binding : solution.bindings) {
+            if (binding.member.candidateClass == eCandidateClass::GROUP_MEMBER && groups.at(binding.member.groupOrder).selected) {
+                groupBindings.try_emplace(binding.member.groupOrder).first->second.push_back(binding);
+                continue;
+            }
+            ordinaryInternal.push_back(binding);
+        }
+
+        std::vector<CGroupAllocation> groupAllocations;
+        groupAllocations.reserve(groups.size());
+        for (size_t groupIndex = 0; groupIndex < groups.size(); ++groupIndex) {
+            const auto& group = groups.at(groupIndex);
+            if (!group.selected) {
+                if (groupBindings.contains(groupIndex))
+                    return fail(ePlanStatus::INVALID);
+                groupAllocations.push_back(CPlanAssembler::group(group.definition, eGroupStatus::NO_MATCH, {}));
+                continue;
+            }
+            const auto& bindings = group.retained ? group.retainedBindings : groupBindings.at(groupIndex);
+            if (bindings.size() != group.members.size())
+                return fail(ePlanStatus::INVALID);
+            std::vector<CBinding> publicBindings;
+            publicBindings.reserve(bindings.size());
+            for (const auto& binding : bindings)
+                publicBindings.push_back(makeBinding(context, binding, group.definition));
+            groupAllocations.push_back(CPlanAssembler::group(group.definition, eGroupStatus::ALLOCATED, std::move(publicBindings)));
+        }
+
+        std::vector<CBinding> ordinaryBindings;
+        ordinaryBindings.reserve(ordinaryInternal.size());
+        for (const auto& binding : ordinaryInternal)
+            ordinaryBindings.push_back(makeBinding(context, binding, {}));
+
+        return CPlanAssembler::plan(snapshot, observation, ePlanStatus::READY, std::move(groupAllocations), std::move(ordinaryBindings), solution.droppedConnectorIDs);
+    }
+
+    bool withCurrentPlan(const CSharedPointer<const CPlan>& plan, const SCurrentState& current, const std::function<void(const CPlan&)>& callback) {
+        if (!plan || plan->status() != ePlanStatus::READY || !callback || !current.snapshot || !current.observation || !sameOwner(plan->snapshot(), current.snapshot) ||
+            !sameOwner(plan->observation(), current.observation) || !(current.epoch == current.observation->epoch()) ||
+            current.observation->eventThread() != std::this_thread::get_id() || !sameOwner(current.observation->expected().snapshot, current.snapshot) ||
+            !matchesBackendLifetime(*current.snapshot->device(), current.backendLifetime))
+            return false;
+        callback(*plan);
+        return true;
+    }
+}
diff --git a/src/backend/drm/TiledCrtcAllocator.hpp b/src/backend/drm/TiledCrtcAllocator.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..6f81d8681e951c70da7125d58de16087395bafd0
--- /dev/null
+++ b/src/backend/drm/TiledCrtcAllocator.hpp
@@ -0,0 +1,398 @@
+#pragma once
+
+#include "Tile.hpp"
+
+#include <aquamarine/backend/DRM.hpp>
+
+#include <cstdint>
+#include <functional>
+#include <optional>
+#include <span>
+#include <thread>
+#include <vector>
+
+#ifdef __GNUC__
+#define AQ_TILED_ALLOCATOR_PRIVATE __attribute__((visibility("hidden")))
+#else
+#define AQ_TILED_ALLOCATOR_PRIVATE
+#endif
+
+namespace Aquamarine::NDRM::NTiledCrtcAllocator { // NOLINT(readability-identifier-naming): established Aquamarine DRM namespace
+    using Hyprutils::Memory::CSharedPointer;
+    using Hyprutils::Memory::CWeakPointer;
+
+    // These counters identify one immutable resource observation. Reusing any
+    // counter across its corresponding lifetime boundary is a caller bug.
+    struct AQ_TILED_ALLOCATOR_PRIVATE SGeneration {
+        uint64_t device      = 0;
+        uint64_t session     = 0;
+        uint64_t observation = 0;
+
+        bool     operator==(const SGeneration&) const = default;
+    };
+
+    struct AQ_TILED_ALLOCATOR_PRIVATE SBackendIncarnation {
+        uint64_t serial = 0;
+    };
+
+    enum class eBackendBinding : uint8_t {
+        // Pure tests use a live generic token and must leave actual SDRM backend
+        // owners empty. There is deliberately no unbound mode.
+        LIFETIME_TOKEN,
+        // Production additionally requires a live actual CDRMBackend owner and
+        // exact equality with every captured SDRM resource backend.
+        PRODUCTION_BACKEND,
+    };
+
+    // Exact owner for one backend/device/fd lifetime. A production capture must
+    // provide the actual backend weak owner, a stable device ID, and fresh
+    // nonzero device/fd epochs. The generic token makes lifetime expiry and
+    // owner mismatch testable without constructing a DRM backend.
+    struct AQ_TILED_ALLOCATOR_PRIVATE SDeviceIncarnation {
+        uint64_t                                deviceId    = 0;
+        uint64_t                                deviceEpoch = 0;
+        uint64_t                                fdEpoch     = 0;
+        uint64_t                                serial      = 0;
+        eBackendBinding                         binding     = eBackendBinding::LIFETIME_TOKEN;
+        CWeakPointer<const SBackendIncarnation> backendLifetime;
+        CWeakPointer<CDRMBackend>               backend;
+    };
+
+    struct AQ_TILED_ALLOCATOR_PRIVATE SObservationIncarnation {
+        SGeneration                              generation;
+        uint64_t                                 serial = 0;
+        CSharedPointer<const SDeviceIncarnation> device;
+        CWeakPointer<const SBackendIncarnation>  backendLifetime;
+    };
+
+    enum class eResourceKind : uint8_t {
+        CONNECTOR,
+        CRTC,
+        PRIMARY_PLANE,
+    };
+
+    // Identity is the owner identity of this object, not merely these fields.
+    // The fields make accidental cross-observation construction rejectable.
+    struct AQ_TILED_ALLOCATOR_PRIVATE SResourceIncarnation {
+        eResourceKind                                 kind       = eResourceKind::CONNECTOR;
+        uint32_t                                      resourceID = 0;
+        uint64_t                                      serial     = 0;
+        SGeneration                                   generation;
+        CSharedPointer<const SDeviceIncarnation>      device;
+        CSharedPointer<const SObservationIncarnation> observation;
+    };
+
+    struct AQ_TILED_ALLOCATOR_PRIVATE SConnectorResource {
+        CSharedPointer<SDRMConnector>              connector;
+        CSharedPointer<const SResourceIncarnation> incarnation;
+        std::vector<uint32_t>                      possibleCRTCIDs;
+    };
+
+    struct AQ_TILED_ALLOCATOR_PRIVATE SCRTCResource {
+        CSharedPointer<SDRMCRTC>                   crtc;
+        CSharedPointer<const SResourceIncarnation> incarnation;
+    };
+
+    struct AQ_TILED_ALLOCATOR_PRIVATE SPrimaryPlaneResource {
+        CSharedPointer<SDRMPlane>                  plane;
+        CSharedPointer<const SResourceIncarnation> incarnation;
+        std::vector<uint32_t>                      possibleCRTCIDs;
+        // Capture must establish scanout usability independently of plane type.
+        bool usable = false;
+    };
+
+    // Converts a KMS resource-index mask at the observation boundary. The
+    // solver itself accepts only normalized object IDs and never raw masks.
+    [[nodiscard]] AQ_TILED_ALLOCATOR_PRIVATE std::optional<std::vector<uint32_t>> normalizeCRTCIDs(uint32_t possibleMask, std::span<const uint32_t> resourceOrder);
+
+    class AQ_TILED_ALLOCATOR_PRIVATE CSnapshot {
+      public:
+        [[nodiscard]] static CSharedPointer<const CSnapshot>               create(SGeneration generation, CSharedPointer<const SObservationIncarnation> observation,
+                                                                                  std::vector<SConnectorResource> connectors, std::vector<SCRTCResource> crtcs,
+                                                                                  std::vector<SPrimaryPlaneResource> primaryPlanes);
+
+        [[nodiscard]] const SGeneration&                                   generation() const;
+        [[nodiscard]] const CSharedPointer<const SDeviceIncarnation>&      device() const;
+        [[nodiscard]] const CSharedPointer<const SObservationIncarnation>& observation() const;
+        [[nodiscard]] const std::vector<SConnectorResource>&               connectors() const;
+        [[nodiscard]] const std::vector<SCRTCResource>&                    crtcs() const;
+        [[nodiscard]] const std::vector<SPrimaryPlaneResource>&            primaryPlanes() const;
+
+      private:
+        CSnapshot(SGeneration generation, CSharedPointer<const SDeviceIncarnation> device, CSharedPointer<const SObservationIncarnation> observation,
+                  std::vector<SConnectorResource> connectors, std::vector<SCRTCResource> crtcs, std::vector<SPrimaryPlaneResource> primaryPlanes);
+
+        SGeneration                                   m_generation;
+        CSharedPointer<const SDeviceIncarnation>      m_device;
+        CSharedPointer<const SObservationIncarnation> m_observation;
+        std::vector<SConnectorResource>               m_connectors;
+        std::vector<SCRTCResource>                    m_crtcs;
+        std::vector<SPrimaryPlaneResource>            m_primaryPlanes;
+    };
+
+    class AQ_TILED_ALLOCATOR_PRIVATE CGroupDefinition {
+      public:
+        CGroupDefinition(const CGroupDefinition&)                                                        = delete;
+        CGroupDefinition(CGroupDefinition&&)                                                             = delete;
+        CGroupDefinition&                                             operator=(const CGroupDefinition&) = delete;
+        CGroupDefinition&                                             operator=(CGroupDefinition&&)      = delete;
+
+        [[nodiscard]] static CSharedPointer<const CGroupDefinition>   create(NTiling::STileGroup group, CSharedPointer<const SDeviceIncarnation> device, uint64_t definitionSerial);
+
+        [[nodiscard]] const NTiling::STileGroup&                      group() const;
+        [[nodiscard]] const CSharedPointer<const SDeviceIncarnation>& device() const;
+        [[nodiscard]] uint64_t                                        serial() const;
+
+      private:
+        CGroupDefinition(NTiling::STileGroup group, CSharedPointer<const SDeviceIncarnation> device, uint64_t definitionSerial);
+
+        NTiling::STileGroup                      m_group;
+        CSharedPointer<const SDeviceIncarnation> m_device;
+        uint64_t                                 m_serial = 0;
+    };
+
+    struct AQ_TILED_ALLOCATOR_PRIVATE SSnapshotExpectation {
+        // Pointer/control-block identity is the primary freshness boundary.
+        CSharedPointer<const CSnapshot>               snapshot;
+        SGeneration                                   generation;
+        CSharedPointer<const SDeviceIncarnation>      device;
+        CSharedPointer<const SObservationIncarnation> observation;
+    };
+
+    struct AQ_TILED_ALLOCATOR_PRIVATE SConnectorHandle {
+        uint32_t                                   id = 0;
+        CSharedPointer<const SResourceIncarnation> incarnation;
+    };
+
+    struct AQ_TILED_ALLOCATOR_PRIVATE SCRTCHandle {
+        uint32_t                                   id = 0;
+        CSharedPointer<const SResourceIncarnation> incarnation;
+    };
+
+    struct AQ_TILED_ALLOCATOR_PRIVATE SPrimaryPlaneHandle {
+        uint32_t                                   id = 0;
+        CSharedPointer<const SResourceIncarnation> incarnation;
+    };
+
+    struct AQ_TILED_ALLOCATOR_PRIVATE SRetainedGroupBinding {
+        SConnectorHandle    connector;
+        SCRTCHandle         crtc;
+        SPrimaryPlaneHandle primaryPlane;
+    };
+
+    struct AQ_TILED_ALLOCATOR_PRIVATE SGroupRequest {
+        CSharedPointer<const CGroupDefinition> definition;
+        // Must project exactly the definition's connector membership. Tile
+        // coordinates and group identity are always derived from definition.
+        std::vector<SConnectorHandle> connectors;
+        // Presence is an explicit claim that every member is still retained.
+        std::optional<std::vector<SRetainedGroupBinding>> retained;
+    };
+
+    enum class eOrdinaryPriority : uint8_t {
+        ENABLED_UNMATCHED,
+        DETACHED_DISABLED_BACKUP,
+    };
+
+    struct AQ_TILED_ALLOCATOR_PRIVATE SOrdinaryRequest {
+        SConnectorHandle connector;
+        // The lifecycle supplies this proof explicitly. The solver never
+        // infers it from mutable connector or output enabled fields.
+        eOrdinaryPriority priority = eOrdinaryPriority::ENABLED_UNMATCHED;
+    };
+
+    struct AQ_TILED_ALLOCATOR_PRIVATE SConnectorCRTCPreference {
+        SConnectorHandle connector;
+        SCRTCHandle      crtc;
+    };
+
+    struct AQ_TILED_ALLOCATOR_PRIVATE SCRTCPlanePreference {
+        SCRTCHandle         crtc;
+        SPrimaryPlaneHandle plane;
+    };
+
+    enum class eHardHoldReason : uint8_t {
+        ACTIVE_OR_PENDING,
+        RETIRING,
+        LEASED,
+        FOREIGN_KERNEL_ATTACHMENT,
+    };
+
+    // Every present resource is unavailable to new allocations. Capture must
+    // report active/pending/retiring bindings, leases, and foreign/unaccounted
+    // kernel attachments. Supplying a full triple also validates compatibility.
+    struct AQ_TILED_ALLOCATOR_PRIVATE SHardHold {
+        eHardHoldReason                    reason = eHardHoldReason::ACTIVE_OR_PENDING;
+        std::optional<SConnectorHandle>    connector;
+        std::optional<SCRTCHandle>         crtc;
+        std::optional<SPrimaryPlaneHandle> plane;
+    };
+
+    struct AQ_TILED_ALLOCATOR_PRIVATE SAllocationEpoch {
+        uint64_t session     = 0;
+        uint64_t allocation  = 0;
+        uint64_t eventThread = 0;
+
+        bool     operator==(const SAllocationEpoch&) const = default;
+    };
+
+    // One immutable allocation observation. The event-thread sidecar must
+    // replace this owner whenever holds, retention, priorities, preferences,
+    // session/VT state, definitions, or resource compatibility change.
+    class AQ_TILED_ALLOCATOR_PRIVATE CAllocationObservation {
+      public:
+        CAllocationObservation(const CAllocationObservation&)                                                      = delete;
+        CAllocationObservation(CAllocationObservation&&)                                                           = delete;
+        CAllocationObservation&                                           operator=(const CAllocationObservation&) = delete;
+        CAllocationObservation&                                           operator=(CAllocationObservation&&)      = delete;
+
+        [[nodiscard]] static CSharedPointer<const CAllocationObservation> create(CSharedPointer<const CSnapshot>                     snapshot,
+                                                                                 CSharedPointer<const SBackendIncarnation>           currentBackendLifetime,
+                                                                                 std::vector<CSharedPointer<const CGroupDefinition>> currentGroupDefinitions,
+                                                                                 std::vector<SHardHold> hardHolds, std::vector<SGroupRequest> groups,
+                                                                                 std::vector<SOrdinaryRequest> ordinary, std::vector<SConnectorCRTCPreference> connectorPreferences,
+                                                                                 std::vector<SCRTCPlanePreference> planePreferences, SAllocationEpoch epoch);
+
+        [[nodiscard]] const SSnapshotExpectation&                         expected() const;
+        [[nodiscard]] const CWeakPointer<const SBackendIncarnation>&      backendLifetime() const;
+        [[nodiscard]] const std::vector<CSharedPointer<const CGroupDefinition>>& currentGroupDefinitions() const;
+        [[nodiscard]] const std::vector<SHardHold>&                              hardHolds() const;
+        [[nodiscard]] const std::vector<SGroupRequest>&                          groups() const;
+        [[nodiscard]] const std::vector<SOrdinaryRequest>&                       ordinary() const;
+        [[nodiscard]] const std::vector<SConnectorCRTCPreference>&               connectorPreferences() const;
+        [[nodiscard]] const std::vector<SCRTCPlanePreference>&                   planePreferences() const;
+        [[nodiscard]] const SAllocationEpoch&                                    epoch() const;
+        [[nodiscard]] std::thread::id                                            eventThread() const;
+
+      private:
+        CAllocationObservation(SSnapshotExpectation expected, CWeakPointer<const SBackendIncarnation> backendLifetime,
+                               std::vector<CSharedPointer<const CGroupDefinition>> currentGroupDefinitions, std::vector<SHardHold> hardHolds, std::vector<SGroupRequest> groups,
+                               std::vector<SOrdinaryRequest> ordinary, std::vector<SConnectorCRTCPreference> connectorPreferences,
+                               std::vector<SCRTCPlanePreference> planePreferences, SAllocationEpoch epoch, std::thread::id eventThread);
+
+        SSnapshotExpectation                                m_expected;
+        CWeakPointer<const SBackendIncarnation>             m_backendLifetime;
+        std::vector<CSharedPointer<const CGroupDefinition>> m_currentGroupDefinitions;
+        std::vector<SHardHold>                              m_hardHolds;
+        std::vector<SGroupRequest>                          m_groups;
+        std::vector<SOrdinaryRequest>                       m_ordinary;
+        std::vector<SConnectorCRTCPreference>               m_connectorPreferences;
+        std::vector<SCRTCPlanePreference>                   m_planePreferences;
+        SAllocationEpoch                                    m_epoch;
+        std::thread::id                                     m_eventThread;
+    };
+
+    enum class ePlanStatus : uint8_t {
+        READY,
+        STALE,
+        INVALID,
+        // Exact lower-tier lookahead exceeded its deterministic work budget.
+        // Highly symmetric backup topologies may take this deterministic
+        // legacy-fallback path even when a solution exists. No allocation is
+        // published; a future adapter must retain ordinary allocation.
+        UNSUPPORTED_COMPLEXITY,
+    };
+
+    enum class eGroupStatus : uint8_t {
+        ALLOCATED,
+        NO_MATCH,
+    };
+
+    class CPlanAssembler;
+
+    class AQ_TILED_ALLOCATOR_PRIVATE CBinding {
+      public:
+        [[nodiscard]] bool                                              tiled() const;
+        [[nodiscard]] const CSharedPointer<const CGroupDefinition>&     definition() const;
+        [[nodiscard]] uint32_t                                          tileX() const;
+        [[nodiscard]] uint32_t                                          tileY() const;
+        [[nodiscard]] const CSharedPointer<SDRMConnector>&              connector() const;
+        [[nodiscard]] const CSharedPointer<const SResourceIncarnation>& connectorIncarnation() const;
+        [[nodiscard]] const CSharedPointer<SDRMCRTC>&                   crtc() const;
+        [[nodiscard]] const CSharedPointer<const SResourceIncarnation>& crtcIncarnation() const;
+        [[nodiscard]] const CSharedPointer<SDRMPlane>&                  primaryPlane() const;
+        [[nodiscard]] const CSharedPointer<const SResourceIncarnation>& primaryPlaneIncarnation() const;
+
+      private:
+        CBinding(bool tiled, CSharedPointer<const CGroupDefinition> definition, uint32_t tileX, uint32_t tileY, CSharedPointer<SDRMConnector> connector,
+                 CSharedPointer<const SResourceIncarnation> connectorIncarnation, CSharedPointer<SDRMCRTC> crtc, CSharedPointer<const SResourceIncarnation> crtcIncarnation,
+                 CSharedPointer<SDRMPlane> primaryPlane, CSharedPointer<const SResourceIncarnation> primaryPlaneIncarnation);
+
+        bool                                       m_tiled = false;
+        CSharedPointer<const CGroupDefinition>     m_definition;
+        uint32_t                                   m_tileX = 0;
+        uint32_t                                   m_tileY = 0;
+        CSharedPointer<SDRMConnector>              m_connector;
+        CSharedPointer<const SResourceIncarnation> m_connectorIncarnation;
+        CSharedPointer<SDRMCRTC>                   m_crtc;
+        CSharedPointer<const SResourceIncarnation> m_crtcIncarnation;
+        CSharedPointer<SDRMPlane>                  m_primaryPlane;
+        CSharedPointer<const SResourceIncarnation> m_primaryPlaneIncarnation;
+
+        friend class CPlanAssembler;
+    };
+
+    class AQ_TILED_ALLOCATOR_PRIVATE CGroupAllocation {
+      public:
+        [[nodiscard]] const CSharedPointer<const CGroupDefinition>& definition() const;
+        [[nodiscard]] eGroupStatus                                  status() const;
+        [[nodiscard]] const std::vector<CBinding>&                  bindings() const;
+
+      private:
+        CGroupAllocation(CSharedPointer<const CGroupDefinition> definition, eGroupStatus status, std::vector<CBinding> bindings);
+
+        CSharedPointer<const CGroupDefinition> m_definition;
+        eGroupStatus                           m_status = eGroupStatus::NO_MATCH;
+        std::vector<CBinding>                  m_bindings;
+
+        friend class CPlanAssembler;
+    };
+
+    class AQ_TILED_ALLOCATOR_PRIVATE CPlan {
+      public:
+        CPlan(const CPlan&)                                                                       = delete;
+        CPlan(CPlan&&)                                                                            = delete;
+        CPlan&                                                            operator=(const CPlan&) = delete;
+        CPlan&                                                            operator=(CPlan&&)      = delete;
+
+        [[nodiscard]] const CSharedPointer<const CSnapshot>&              snapshot() const;
+        [[nodiscard]] const CSharedPointer<const CAllocationObservation>& observation() const;
+        [[nodiscard]] ePlanStatus                                         status() const;
+        [[nodiscard]] const std::vector<CGroupAllocation>&                groups() const;
+        [[nodiscard]] const std::vector<CBinding>&                        ordinaryBindings() const;
+        [[nodiscard]] const std::vector<uint32_t>&                        unallocatedOrdinaryConnectorIDs() const;
+
+      private:
+        CPlan(CSharedPointer<const CSnapshot> snapshot, CSharedPointer<const CAllocationObservation> observation, ePlanStatus status, std::vector<CGroupAllocation> groups,
+              std::vector<CBinding> ordinaryBindings, std::vector<uint32_t> unallocatedOrdinaryConnectorIDs);
+
+        // Retaining the snapshot keeps every resource incarnation alive. The
+        // immutable allocation observation retains every exact non-resource
+        // input but only weakly references the backend-lifetime token.
+        CSharedPointer<const CSnapshot>              m_snapshot;
+        CSharedPointer<const CAllocationObservation> m_observation;
+        ePlanStatus                                  m_status = ePlanStatus::INVALID;
+        std::vector<CGroupAllocation>                m_groups;
+        std::vector<CBinding>                        m_ordinaryBindings;
+        std::vector<uint32_t>                        m_unallocatedOrdinaryConnectorIDs;
+
+        friend class CPlanAssembler;
+    };
+
+    struct AQ_TILED_ALLOCATOR_PRIVATE SCurrentState {
+        CSharedPointer<const CSnapshot>              snapshot;
+        CSharedPointer<const SBackendIncarnation>    backendLifetime;
+        CSharedPointer<const CAllocationObservation> observation;
+        SAllocationEpoch                             epoch;
+    };
+
+    [[nodiscard]] AQ_TILED_ALLOCATOR_PRIVATE SSnapshotExpectation expectationFor(const CSharedPointer<const CSnapshot>& snapshot);
+    [[nodiscard]] AQ_TILED_ALLOCATOR_PRIVATE CSharedPointer<const CPlan> solve(const CSharedPointer<const CAllocationObservation>& observation);
+    // This synchronous gate validates and invokes the callback before returning.
+    // Capture, solve, this preflight, and mutation must remain serialized on the
+    // same DRM event thread; stale/invalid input never invokes the callback.
+    [[nodiscard]] AQ_TILED_ALLOCATOR_PRIVATE bool withCurrentPlan(const CSharedPointer<const CPlan>& plan, const SCurrentState& current,
+                                                                  const std::function<void(const CPlan&)>& callback);
+}
+
+#undef AQ_TILED_ALLOCATOR_PRIVATE
diff --git a/tests/ConnectorScan.cpp b/tests/ConnectorScan.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b09ffc7c896f30f729bf76ae6e2f92d218983bfc
--- /dev/null
+++ b/tests/ConnectorScan.cpp
@@ -0,0 +1,192 @@
+#include "backend/drm/ConnectorScan.hpp"
+#include "shared.hpp"
+
+#include <algorithm>
+#include <array>
+#include <cstdint>
+#include <optional>
+#include <span>
+#include <vector>
+
+using namespace Aquamarine::NDRM;
+
+namespace {
+    struct SLiveConnector {
+        uint32_t         id     = 0;
+        int              status = 0;
+        std::vector<int> modes;
+        int              updateCount = 0;
+
+        bool             operator==(const SLiveConnector&) const = default;
+    };
+
+    struct SStagedConnector {
+        uint32_t         id     = 0;
+        int              status = 0;
+        std::vector<int> modes;
+    };
+
+    struct SScanHarness {
+        std::vector<SLiveConnector> live = {
+            {.id = 1, .status = 101, .modes = {1'001}},
+            {.id = 2, .status = 202, .modes = {2'002}},
+        };
+        std::optional<uint32_t>         acquisitionFailure;
+        std::optional<uint32_t>         initializationFailure;
+        int                             acquisitionCount    = 0;
+        int                             initializationCount = 0;
+        int                             commitCount         = 0;
+        int                             additionCount       = 0;
+        int                             removalCount        = 0;
+        int                             disconnectCount     = 0;
+
+        std::optional<SStagedConnector> stage(uint32_t id) {
+            ++acquisitionCount;
+            if (acquisitionFailure == id)
+                return std::nullopt;
+
+            const bool exists = std::ranges::contains(live, id, &SLiveConnector::id);
+            if (!exists) {
+                ++initializationCount;
+                if (initializationFailure == id)
+                    return std::nullopt;
+            }
+
+            return SStagedConnector{.id = id, .status = static_cast<int>(id * 10), .modes = {static_cast<int>(id * 100), static_cast<int>((id * 100) + 1)}};
+        }
+
+        void commit(std::span<SStagedConnector> staged) {
+            ++commitCount;
+
+            for (const auto& connector : staged) {
+                const auto it = std::ranges::find(live, connector.id, &SLiveConnector::id);
+                if (it == live.end()) {
+                    live.emplace_back(SLiveConnector{.id = connector.id, .status = connector.status, .modes = connector.modes, .updateCount = 1});
+                    ++additionCount;
+                    continue;
+                }
+
+                it->status = connector.status;
+                it->modes  = connector.modes;
+                ++it->updateCount;
+            }
+
+            std::erase_if(live, [&](const auto& connector) {
+                if (std::ranges::contains(staged, connector.id, &SStagedConnector::id))
+                    return false;
+                ++removalCount;
+                ++disconnectCount;
+                return true;
+            });
+        }
+    };
+
+    int resultOf(eConnectorScanResult result) {
+        return static_cast<int>(result);
+    }
+}
+
+int main() {
+    int                               ret = 0;
+
+    constexpr std::array<uint32_t, 2> CHANGED_SNAPSHOT{1, 3};
+
+    {
+        SScanHarness harness;
+        const auto   before        = harness.live;
+        harness.acquisitionFailure = 3;
+
+        const auto result = connectorScanTransaction<SStagedConnector>(
+            CHANGED_SNAPSHOT, [&](uint32_t id) { return harness.stage(id); }, [&](std::span<SStagedConnector> staged) { harness.commit(staged); });
+
+        EXPECT(resultOf(result), resultOf(eConnectorScanResult::STAGING_FAILED));
+        EXPECT(harness.live == before, true);
+        EXPECT(harness.commitCount, 0);
+        EXPECT(harness.additionCount, 0);
+        EXPECT(harness.removalCount, 0);
+        EXPECT(harness.disconnectCount, 0);
+        EXPECT(harness.acquisitionCount, 2);
+        EXPECT(harness.initializationCount, 0);
+    }
+
+    {
+        SScanHarness harness;
+        const auto   before           = harness.live;
+        harness.initializationFailure = 3;
+
+        const auto result = connectorScanTransaction<SStagedConnector>(
+            CHANGED_SNAPSHOT, [&](uint32_t id) { return harness.stage(id); }, [&](std::span<SStagedConnector> staged) { harness.commit(staged); });
+
+        EXPECT(resultOf(result), resultOf(eConnectorScanResult::STAGING_FAILED));
+        EXPECT(harness.live == before, true);
+        EXPECT(harness.commitCount, 0);
+        EXPECT(harness.additionCount, 0);
+        EXPECT(harness.removalCount, 0);
+        EXPECT(harness.disconnectCount, 0);
+        EXPECT(harness.acquisitionCount, 2);
+        EXPECT(harness.initializationCount, 1);
+    }
+
+    {
+        SScanHarness                      harness;
+        const auto                        before = harness.live;
+        constexpr std::array<uint32_t, 3> DUPLICATE_SNAPSHOT{1, 3, 3};
+
+        const auto                        result = connectorScanTransaction<SStagedConnector>(
+            DUPLICATE_SNAPSHOT, [&](uint32_t id) { return harness.stage(id); }, [&](std::span<SStagedConnector> staged) { harness.commit(staged); });
+
+        EXPECT(resultOf(result), resultOf(eConnectorScanResult::DUPLICATE_CONNECTOR));
+        EXPECT(harness.live == before, true);
+        EXPECT(harness.commitCount, 0);
+        EXPECT(harness.additionCount, 0);
+        EXPECT(harness.removalCount, 0);
+        EXPECT(harness.disconnectCount, 0);
+        EXPECT(harness.acquisitionCount, 2);
+        EXPECT(harness.initializationCount, 1);
+    }
+
+    {
+        SScanHarness harness;
+
+        const auto   result = connectorScanTransaction<SStagedConnector>(
+            CHANGED_SNAPSHOT, [&](uint32_t id) { return harness.stage(id); }, [&](std::span<SStagedConnector> staged) { harness.commit(staged); });
+
+        EXPECT(resultOf(result), resultOf(eConnectorScanResult::COMMITTED));
+        EXPECT(harness.commitCount, 1);
+        EXPECT(harness.additionCount, 1);
+        EXPECT(harness.removalCount, 1);
+        EXPECT(harness.disconnectCount, 1);
+        EXPECT(harness.live.size(), 2U);
+
+        const auto existing = std::ranges::find(harness.live, 1U, &SLiveConnector::id);
+        EXPECT(existing != harness.live.end(), true);
+        EXPECT(existing->status, 10);
+        EXPECT(existing->modes == std::vector<int>({100, 101}), true);
+        EXPECT(existing->updateCount, 1);
+
+        const auto added = std::ranges::find(harness.live, 3U, &SLiveConnector::id);
+        EXPECT(added != harness.live.end(), true);
+        EXPECT(added->status, 30);
+        EXPECT(added->modes == std::vector<int>({300, 301}), true);
+        EXPECT(added->updateCount, 1);
+    }
+
+    {
+        SScanHarness                      harness;
+        constexpr std::array<uint32_t, 0> EMPTY_SNAPSHOT{};
+
+        const auto                        result = connectorScanTransaction<SStagedConnector>(
+            EMPTY_SNAPSHOT, [&](uint32_t id) { return harness.stage(id); }, [&](std::span<SStagedConnector> staged) { harness.commit(staged); });
+
+        EXPECT(resultOf(result), resultOf(eConnectorScanResult::COMMITTED));
+        EXPECT(harness.commitCount, 1);
+        EXPECT(harness.additionCount, 0);
+        EXPECT(harness.removalCount, 2);
+        EXPECT(harness.disconnectCount, 2);
+        EXPECT(harness.live.empty(), true);
+        EXPECT(harness.acquisitionCount, 0);
+        EXPECT(harness.initializationCount, 0);
+    }
+
+    return ret;
+}
diff --git a/tests/PlaneFormats.cpp b/tests/PlaneFormats.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..beeef5fdd8ffbd6ec4a4b83860b6da3ca9142b82
--- /dev/null
+++ b/tests/PlaneFormats.cpp
@@ -0,0 +1,119 @@
+#include "backend/drm/PlaneFormats.hpp"
+#include "shared.hpp"
+
+#include <algorithm>
+#include <array>
+#include <cstdint>
+#include <vector>
+
+#include <drm_fourcc.h>
+
+using namespace Aquamarine;
+using namespace Aquamarine::NDRM;
+
+namespace {
+    constexpr uint64_t MODIFIER_A = 0x100000000000001;
+    constexpr uint64_t MODIFIER_B = 0x100000000000002;
+    constexpr uint64_t MODIFIER_C = 0x100000000000003;
+
+    bool               sameFormats(const std::vector<SDRMFormat>& lhs, const std::vector<SDRMFormat>& rhs) {
+        if (lhs.size() != rhs.size())
+            return false;
+
+        for (size_t i = 0; i < lhs.size(); ++i) {
+            if (lhs.at(i).drmFormat != rhs.at(i).drmFormat || lhs.at(i).modifiers != rhs.at(i).modifiers)
+                return false;
+        }
+
+        return true;
+    }
+
+    SPlaneFormatSet view(const std::vector<SDRMFormat>& formats) {
+        return {.formats = formats};
+    }
+}
+
+int main() {
+    int                           ret = 0;
+
+    const std::vector<SDRMFormat> PRIMARY = {
+        {.drmFormat = DRM_FORMAT_XRGB8888, .modifiers = {MODIFIER_B, MODIFIER_B, MODIFIER_A, DRM_FORMAT_MOD_LINEAR, DRM_FORMAT_MOD_INVALID}},
+        {.drmFormat = DRM_FORMAT_ARGB8888, .modifiers = {MODIFIER_C, DRM_FORMAT_MOD_LINEAR, MODIFIER_A}},
+        {.drmFormat = DRM_FORMAT_XRGB8888, .modifiers = {MODIFIER_C, MODIFIER_A}},
+    };
+    const std::vector<SDRMFormat> OTHER = {
+        {.drmFormat = DRM_FORMAT_ARGB8888, .modifiers = {MODIFIER_A, DRM_FORMAT_MOD_LINEAR, MODIFIER_C}},
+        {.drmFormat = DRM_FORMAT_XRGB8888, .modifiers = {DRM_FORMAT_MOD_INVALID, DRM_FORMAT_MOD_LINEAR, MODIFIER_C, MODIFIER_A, MODIFIER_B}},
+    };
+    const std::array<SPlaneFormatSet, 2> MEMBERS = {view(PRIMARY), view(OTHER)};
+
+    const auto                           PRIMARY_RESULT   = intersectPlaneFormats(MEMBERS, 0);
+    const std::vector<SDRMFormat>        EXPECTED_PRIMARY = {
+        {.drmFormat = DRM_FORMAT_XRGB8888, .modifiers = {MODIFIER_B, MODIFIER_A, DRM_FORMAT_MOD_LINEAR, DRM_FORMAT_MOD_INVALID, MODIFIER_C}},
+        {.drmFormat = DRM_FORMAT_ARGB8888, .modifiers = {MODIFIER_C, DRM_FORMAT_MOD_LINEAR, MODIFIER_A}},
+    };
+    EXPECT(sameFormats(PRIMARY_RESULT, EXPECTED_PRIMARY), true);
+    EXPECT(PRIMARY_RESULT.front().drmFormat, DRM_FORMAT_XRGB8888);
+    EXPECT(PRIMARY_RESULT.front().modifiers.front(), MODIFIER_B);
+    EXPECT(PRIMARY_RESULT.front().modifiers.at(2), DRM_FORMAT_MOD_LINEAR);
+
+    auto reorderedOther = OTHER;
+    std::ranges::reverse(reorderedOther);
+    for (auto& FORMAT : reorderedOther) {
+        std::ranges::reverse(FORMAT.modifiers);
+    }
+    const std::array<SPlaneFormatSet, 2> REORDERED_OTHER = {view(PRIMARY), view(reorderedOther)};
+    EXPECT(sameFormats(intersectPlaneFormats(REORDERED_OTHER, 0), PRIMARY_RESULT), true);
+
+    const auto                    OTHER_PRIMARY_RESULT   = intersectPlaneFormats(MEMBERS, 1);
+    const std::vector<SDRMFormat> EXPECTED_OTHER_PRIMARY = {
+        {.drmFormat = DRM_FORMAT_ARGB8888, .modifiers = {MODIFIER_A, DRM_FORMAT_MOD_LINEAR, MODIFIER_C}},
+        {.drmFormat = DRM_FORMAT_XRGB8888, .modifiers = {DRM_FORMAT_MOD_INVALID, DRM_FORMAT_MOD_LINEAR, MODIFIER_C, MODIFIER_A, MODIFIER_B}},
+    };
+    EXPECT(sameFormats(OTHER_PRIMARY_RESULT, EXPECTED_OTHER_PRIMARY), true);
+    EXPECT(sameFormats(OTHER_PRIMARY_RESULT, PRIMARY_RESULT), false);
+
+    const std::vector<SDRMFormat> IMPLICIT_ONLY = {
+        {.drmFormat = DRM_FORMAT_XRGB8888, .modifiers = {DRM_FORMAT_MOD_INVALID}},
+    };
+    const std::vector<SDRMFormat> LINEAR_ONLY = {
+        {.drmFormat = DRM_FORMAT_XRGB8888, .modifiers = {DRM_FORMAT_MOD_LINEAR}},
+    };
+    const std::array<SPlaneFormatSet, 2> INVALID_VS_LINEAR = {view(IMPLICIT_ONLY), view(LINEAR_ONLY)};
+    EXPECT(intersectPlaneFormats(INVALID_VS_LINEAR, 0).empty(), true);
+    EXPECT(intersectPlaneFormats(INVALID_VS_LINEAR, 1).empty(), true);
+
+    const std::array<SPlaneFormatSet, 2> COMMON_IMPLICIT   = {view(IMPLICIT_ONLY), view(IMPLICIT_ONLY)};
+    const std::vector<SDRMFormat>        EXPECTED_IMPLICIT = {
+        {.drmFormat = DRM_FORMAT_XRGB8888, .modifiers = {DRM_FORMAT_MOD_INVALID}},
+    };
+    EXPECT(sameFormats(intersectPlaneFormats(COMMON_IMPLICIT, 0), EXPECTED_IMPLICIT), true);
+
+    const std::vector<SDRMFormat> ONLY_XRGB = {
+        {.drmFormat = DRM_FORMAT_XRGB8888, .modifiers = {MODIFIER_A}},
+    };
+    const std::vector<SDRMFormat> ONLY_ARGB = {
+        {.drmFormat = DRM_FORMAT_ARGB8888, .modifiers = {MODIFIER_A}},
+    };
+    const std::array<SPlaneFormatSet, 2> MISSING_FORMAT = {view(ONLY_XRGB), view(ONLY_ARGB)};
+    EXPECT(intersectPlaneFormats(MISSING_FORMAT, 0).empty(), true);
+
+    const std::array<SPlaneFormatSet, 0> NO_MEMBERS = {};
+    EXPECT(intersectPlaneFormats(NO_MEMBERS, 0).empty(), true);
+    EXPECT(intersectPlaneFormats(MEMBERS, MEMBERS.size()).empty(), true);
+
+    const std::vector<SDRMFormat>        EMPTY_MEMBER      = {};
+    const std::array<SPlaneFormatSet, 2> WITH_EMPTY_MEMBER = {view(PRIMARY), view(EMPTY_MEMBER)};
+    EXPECT(intersectPlaneFormats(WITH_EMPTY_MEMBER, 0).empty(), true);
+
+    const std::vector<SDRMFormat> NO_MODIFIERS = {
+        {.drmFormat = DRM_FORMAT_XRGB8888},
+    };
+    const std::array<SPlaneFormatSet, 2> WITH_NO_MODIFIERS = {view(PRIMARY), view(NO_MODIFIERS)};
+    EXPECT(intersectPlaneFormats(WITH_NO_MODIFIERS, 0).empty(), true);
+
+    const std::array<SPlaneFormatSet, 1> ONE_MEMBER = {view(PRIMARY)};
+    EXPECT(sameFormats(intersectPlaneFormats(ONE_MEMBER, 0), EXPECTED_PRIMARY), true);
+
+    return ret;
+}
diff --git a/tests/PlaneViewport.cpp b/tests/PlaneViewport.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..ba1ee619f4ecc7b376289f312df1670d83091d9c
--- /dev/null
+++ b/tests/PlaneViewport.cpp
@@ -0,0 +1,129 @@
+#include "backend/drm/PlaneViewport.hpp"
+#include "shared.hpp"
+
+#include <array>
+#include <cstdint>
+#include <limits>
+
+using namespace Aquamarine::NDRM;
+
+namespace {
+    constexpr uint32_t fixed(uint32_t value) {
+        return value << 16U;
+    }
+
+    constexpr SPlaneFramebufferSize framebuffer(uint32_t width, uint32_t height) {
+        return {.width = width, .height = height};
+    }
+
+    constexpr SPlaneSourceRect source(uint32_t x, uint32_t y, uint32_t width, uint32_t height) {
+        return {.x = x, .y = y, .width = width, .height = height};
+    }
+
+    constexpr SPlaneDestinationRect destination(int32_t x, int32_t y, uint32_t width, uint32_t height) {
+        return {.x = x, .y = y, .width = width, .height = height};
+    }
+
+    int resultOf(ePlaneViewportError error) {
+        return static_cast<int>(error);
+    }
+
+    int expected(ePlaneViewportError error) {
+        return static_cast<int>(error);
+    }
+}
+
+int main() {
+    int        ret = 0;
+
+    const auto encode = [](SPlaneFramebufferSize framebuffer, SPlaneSourceRect source, SPlaneDestinationRect destination) {
+        return encodePlaneViewport(framebuffer, {.source = source, .destination = destination});
+    };
+
+    const auto expectFailure = [&](SPlaneFramebufferSize framebuffer, SPlaneSourceRect source, SPlaneDestinationRect destination, ePlaneViewportError error) {
+        const auto ENCODED = encode(framebuffer, source, destination);
+        EXPECT(static_cast<bool>(ENCODED), false);
+        EXPECT(resultOf(ENCODED.error), expected(error));
+        EXPECT((ENCODED.values == SPlanePropertyValues{}), true);
+    };
+
+    const auto FULL_FRAME = encode(framebuffer(5120, 2880), source(0, 0, 5120, 2880), destination(0, 0, 5120, 2880));
+    EXPECT(static_cast<bool>(FULL_FRAME), true);
+    EXPECT(resultOf(FULL_FRAME.error), expected(ePlaneViewportError::NONE));
+    EXPECT((FULL_FRAME.values == SPlanePropertyValues{.srcX = 0, .srcY = 0, .srcW = fixed(5120), .srcH = fixed(2880), .crtcX = 0, .crtcY = 0, .crtcW = 5120, .crtcH = 2880}), true);
+    EXPECT(encode(framebuffer(5120, 2880), source(0, 0, 5120, 2880), destination(0, 0, 5120, 2880)) == FULL_FRAME, true);
+
+    const auto LG_LEFT  = encode(framebuffer(5120, 2880), source(0, 0, 2560, 2880), destination(0, 0, 2560, 2880));
+    const auto LG_RIGHT = encode(framebuffer(5120, 2880), source(2560, 0, 2560, 2880), destination(0, 0, 2560, 2880));
+    EXPECT(static_cast<bool>(LG_LEFT), true);
+    EXPECT(static_cast<bool>(LG_RIGHT), true);
+    EXPECT(LG_LEFT.values.srcX, 0U);
+    EXPECT(LG_LEFT.values.srcW, 167772160U);
+    EXPECT(LG_RIGHT.values.srcX, 167772160U);
+    EXPECT(LG_RIGHT.values.srcW, 167772160U);
+    EXPECT(LG_RIGHT.values.srcH, 188743680U);
+
+    const auto VERTICAL_TOP    = encode(framebuffer(2560, 2880), source(0, 0, 2560, 1440), destination(0, 0, 2560, 1440));
+    const auto VERTICAL_BOTTOM = encode(framebuffer(2560, 2880), source(0, 1440, 2560, 1440), destination(0, 0, 2560, 1440));
+    EXPECT(static_cast<bool>(VERTICAL_TOP), true);
+    EXPECT(static_cast<bool>(VERTICAL_BOTTOM), true);
+    EXPECT(VERTICAL_TOP.values.srcY, 0U);
+    EXPECT(VERTICAL_BOTTOM.values.srcY, 94371840U);
+    EXPECT(VERTICAL_BOTTOM.values.srcH, 94371840U);
+
+    constexpr std::array<SPlaneSourceRect, 4> NONUNIFORM_2X2 = {
+        source(0, 0, 2300, 1200),
+        source(2300, 0, 2700, 1200),
+        source(0, 1200, 2300, 1800),
+        source(2300, 1200, 2700, 1800),
+    };
+    constexpr std::array<SPlanePropertyValues, 4> EXPECTED_2X2 = {
+        SPlanePropertyValues{.srcX = fixed(0), .srcY = fixed(0), .srcW = fixed(2300), .srcH = fixed(1200), .crtcW = 2300, .crtcH = 1200},
+        SPlanePropertyValues{.srcX = fixed(2300), .srcY = fixed(0), .srcW = fixed(2700), .srcH = fixed(1200), .crtcW = 2700, .crtcH = 1200},
+        SPlanePropertyValues{.srcX = fixed(0), .srcY = fixed(1200), .srcW = fixed(2300), .srcH = fixed(1800), .crtcW = 2300, .crtcH = 1800},
+        SPlanePropertyValues{.srcX = fixed(2300), .srcY = fixed(1200), .srcW = fixed(2700), .srcH = fixed(1800), .crtcW = 2700, .crtcH = 1800},
+    };
+    for (size_t i = 0; i < NONUNIFORM_2X2.size(); ++i) {
+        const auto ENCODED = encode(framebuffer(5000, 3000), NONUNIFORM_2X2.at(i), destination(0, 0, NONUNIFORM_2X2.at(i).width, NONUNIFORM_2X2.at(i).height));
+        EXPECT(static_cast<bool>(ENCODED), true);
+        EXPECT(ENCODED.values == EXPECTED_2X2.at(i), true);
+    }
+
+    const auto NEGATIVE_DESTINATION = encode(framebuffer(640, 480), source(0, 0, 640, 480), destination(std::numeric_limits<int32_t>::min(), -1, 320, 240));
+    EXPECT(static_cast<bool>(NEGATIVE_DESTINATION), true);
+    EXPECT(NEGATIVE_DESTINATION.values.crtcX, std::numeric_limits<int32_t>::min());
+    EXPECT(NEGATIVE_DESTINATION.values.crtcY, -1);
+    EXPECT(NEGATIVE_DESTINATION.values.crtcW, 320U);
+    EXPECT(NEGATIVE_DESTINATION.values.crtcH, 240U);
+
+    const auto EXACT_EDGE = encode(framebuffer(10, 10), source(9, 9, 1, 1), destination(0, 0, 1, 1));
+    EXPECT(static_cast<bool>(EXACT_EDGE), true);
+    EXPECT(EXACT_EDGE.values.srcX, fixed(9));
+    EXPECT(EXACT_EDGE.values.srcY, fixed(9));
+
+    expectFailure(framebuffer(10, 10), source(10, 0, 1, 1), destination(0, 0, 1, 1), ePlaneViewportError::SOURCE_OUT_OF_BOUNDS);
+    expectFailure(framebuffer(10, 10), source(0, 10, 1, 1), destination(0, 0, 1, 1), ePlaneViewportError::SOURCE_OUT_OF_BOUNDS);
+    expectFailure(framebuffer(10, 10), source(1, 0, 10, 1), destination(0, 0, 10, 1), ePlaneViewportError::SOURCE_OUT_OF_BOUNDS);
+    expectFailure(framebuffer(10, 10), source(0, 1, 1, 10), destination(0, 0, 1, 10), ePlaneViewportError::SOURCE_OUT_OF_BOUNDS);
+
+    constexpr auto UINT32_MAXIMUM = std::numeric_limits<uint32_t>::max();
+    expectFailure(framebuffer(UINT32_MAXIMUM, 1), source(UINT32_MAXIMUM, 0, 1, 1), destination(0, 0, 1, 1), ePlaneViewportError::SOURCE_BOUNDS_OVERFLOW);
+    expectFailure(framebuffer(1, UINT32_MAXIMUM), source(0, UINT32_MAXIMUM, 1, 1), destination(0, 0, 1, 1), ePlaneViewportError::SOURCE_BOUNDS_OVERFLOW);
+    expectFailure(framebuffer(UINT32_MAXIMUM, 1), source(UINT32_MAXIMUM - 1, 0, 1, 1), destination(0, 0, 1, 1), ePlaneViewportError::SOURCE_FIXED_POINT_OVERFLOW);
+    expectFailure(framebuffer(UINT32_MAXIMUM, 1), source(0, 0, UINT32_MAXIMUM, 1), destination(0, 0, 1, 1), ePlaneViewportError::SOURCE_FIXED_POINT_OVERFLOW);
+
+    constexpr uint32_t FIRST_UNENCODABLE = (std::numeric_limits<uint32_t>::max() >> 16U) + 1U;
+    expectFailure(framebuffer(FIRST_UNENCODABLE + 1U, 1), source(FIRST_UNENCODABLE, 0, 1, 1), destination(0, 0, 1, 1), ePlaneViewportError::SOURCE_FIXED_POINT_OVERFLOW);
+    expectFailure(framebuffer(1, FIRST_UNENCODABLE + 1U), source(0, FIRST_UNENCODABLE, 1, 1), destination(0, 0, 1, 1), ePlaneViewportError::SOURCE_FIXED_POINT_OVERFLOW);
+    expectFailure(framebuffer(FIRST_UNENCODABLE, 1), source(0, 0, FIRST_UNENCODABLE, 1), destination(0, 0, 1, 1), ePlaneViewportError::SOURCE_FIXED_POINT_OVERFLOW);
+    expectFailure(framebuffer(1, FIRST_UNENCODABLE), source(0, 0, 1, FIRST_UNENCODABLE), destination(0, 0, 1, 1), ePlaneViewportError::SOURCE_FIXED_POINT_OVERFLOW);
+
+    expectFailure(framebuffer(0, 1), source(0, 0, 1, 1), destination(0, 0, 1, 1), ePlaneViewportError::ZERO_FRAMEBUFFER_DIMENSION);
+    expectFailure(framebuffer(1, 0), source(0, 0, 1, 1), destination(0, 0, 1, 1), ePlaneViewportError::ZERO_FRAMEBUFFER_DIMENSION);
+    expectFailure(framebuffer(1, 1), source(0, 0, 0, 1), destination(0, 0, 1, 1), ePlaneViewportError::ZERO_SOURCE_DIMENSION);
+    expectFailure(framebuffer(1, 1), source(0, 0, 1, 0), destination(0, 0, 1, 1), ePlaneViewportError::ZERO_SOURCE_DIMENSION);
+    expectFailure(framebuffer(1, 1), source(0, 0, 1, 1), destination(0, 0, 0, 1), ePlaneViewportError::ZERO_DESTINATION_DIMENSION);
+    expectFailure(framebuffer(1, 1), source(0, 0, 1, 1), destination(0, 0, 1, 0), ePlaneViewportError::ZERO_DESTINATION_DIMENSION);
+
+    return ret;
+}
diff --git a/tests/TileModes.cpp b/tests/TileModes.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..d701c7fcd6784cb674381f66d37534cb321f98e3
--- /dev/null
+++ b/tests/TileModes.cpp
@@ -0,0 +1,255 @@
+#include "backend/drm/TileModes.hpp"
+#include "shared.hpp"
+
+#include <algorithm>
+#include <cstddef>
+#include <cstdint>
+#include <string_view>
+#include <utility>
+#include <vector>
+
+using namespace Aquamarine::NTiling;
+
+namespace {
+    constexpr uint32_t DEFAULT_FLAGS = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC;
+
+    STileGroup         uniformGroup(uint32_t groupId, uint32_t columns, uint32_t rows, uint32_t tileWidth, uint32_t tileHeight, std::vector<uint32_t> connectorIds) {
+        STileGroup group = {
+            .key              = {.deviceId = 1, .groupId = groupId},
+            .isSingleMonitor  = true,
+            .numHTile         = columns,
+            .numVTile         = rows,
+            .width            = tileWidth * columns,
+            .height           = tileHeight * rows,
+            .kind             = eTileGroupKind::MULTI_STREAM,
+            .primaryConnector = connectorIds.empty() ? 0 : connectorIds.front(),
+        };
+
+        for (uint32_t row = 0; row < rows; ++row) {
+            for (uint32_t column = 0; column < columns; ++column) {
+                const size_t INDEX = (static_cast<size_t>(row) * columns) + column;
+                group.members.emplace_back(STileGroupMember{
+                    .connectorId = connectorIds.at(INDEX),
+                    .tileHLoc    = column,
+                    .tileVLoc    = row,
+                    .x           = column * tileWidth,
+                    .y           = row * tileHeight,
+                    .width       = tileWidth,
+                    .height      = tileHeight,
+                });
+            }
+        }
+
+        return group;
+    }
+
+    drmModeModeInfo mode(uint16_t width, uint16_t height, uint32_t clock, uint32_t type = DRM_MODE_TYPE_DRIVER, uint32_t flags = DEFAULT_FLAGS, std::string_view name = "tile",
+                         uint32_t reportedRefresh = 60) {
+        drmModeModeInfo result = {
+            .clock       = clock,
+            .hdisplay    = width,
+            .hsync_start = static_cast<uint16_t>(width + 8),
+            .hsync_end   = static_cast<uint16_t>(width + 40),
+            .htotal      = static_cast<uint16_t>(width + 80),
+            .hskew       = 0,
+            .vdisplay    = height,
+            .vsync_start = static_cast<uint16_t>(height + 1),
+            .vsync_end   = static_cast<uint16_t>(height + 9),
+            .vtotal      = static_cast<uint16_t>(height + 82),
+            .vscan       = 0,
+            .vrefresh    = reportedRefresh,
+            .flags       = flags,
+            .type        = type,
+        };
+        const size_t COPY_SIZE = std::min(name.size(), sizeof(result.name));
+        std::ranges::copy_n(name.begin(), COPY_SIZE, result.name);
+        return result;
+    }
+
+    STileConnectorModes connectorModes(uint32_t connectorId, std::vector<drmModeModeInfo> modes, uint64_t deviceId = 1) {
+        return {.deviceId = deviceId, .connectorId = connectorId, .modes = std::move(modes)};
+    }
+
+    std::string_view modeName(const drmModeModeInfo& modeInfo) {
+        const std::string_view FULL_NAME{modeInfo.name, sizeof(modeInfo.name)};
+        return FULL_NAME.substr(0, FULL_NAME.find('\0'));
+    }
+
+    int errorOf(const STileModeSynthesisResult& result) {
+        return static_cast<int>(result.error);
+    }
+}
+
+int main() {
+    int                              ret = 0;
+
+    const auto                       LG_GROUP      = uniformGroup(1, 2, 1, 2560, 2880, {101, 202});
+    const auto                       LG_60_LEFT    = mode(2560, 2880, 469180, DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED, DEFAULT_FLAGS, "left-60", 60);
+    const auto                       LG_60_RIGHT   = mode(2560, 2880, 469180, DRM_MODE_TYPE_USERDEF | DRM_MODE_TYPE_PREFERRED, DEFAULT_FLAGS, "right-60", 61);
+    const auto                       LG_5994_LEFT  = mode(2560, 2880, 468711, DRM_MODE_TYPE_DRIVER, DEFAULT_FLAGS, "left-5994", 59);
+    const auto                       LG_5994_RIGHT = mode(2560, 2880, 468711, DRM_MODE_TYPE_USERDEF, DEFAULT_FLAGS, "right-5994", 60);
+
+    std::vector<STileConnectorModes> lgModes = {
+        connectorModes(202, {LG_5994_RIGHT, LG_60_RIGHT}),
+        connectorModes(101, {LG_60_LEFT, LG_5994_LEFT}),
+    };
+    const auto LG_RESULT = synthesizeTileModes(LG_GROUP, lgModes);
+    EXPECT(!!LG_RESULT, true);
+    EXPECT(LG_RESULT.modes.size(), 2U);
+    EXPECT(LG_RESULT.mappings.size(), 2U);
+    EXPECT(LG_RESULT.modes.at(0).width, 5120U);
+    EXPECT(LG_RESULT.modes.at(0).height, 2880U);
+    EXPECT(LG_RESULT.modes.at(0).refreshRate, 60000U);
+    EXPECT(LG_RESULT.modes.at(0).refresh.numerator, 2932375U);
+    EXPECT(LG_RESULT.modes.at(0).refresh.denominator, 48873U);
+    EXPECT(LG_RESULT.modes.at(0).preferred, true);
+    EXPECT(LG_RESULT.modes.at(1).refreshRate, 59940U);
+    EXPECT(LG_RESULT.modes.at(1).refresh.numerator, 3905925U);
+    EXPECT(LG_RESULT.modes.at(1).refresh.denominator, 65164U);
+    EXPECT(LG_RESULT.modes.at(1).preferred, false);
+    EXPECT(LG_RESULT.mappings.at(0).logicalModeId, LG_RESULT.modes.at(0).id);
+    EXPECT(LG_RESULT.mappings.at(0).members.size(), 2U);
+    EXPECT(LG_RESULT.mappings.at(0).members.at(0).connectorId, 101U);
+    EXPECT(LG_RESULT.mappings.at(0).members.at(1).connectorId, 202U);
+    EXPECT(LG_RESULT.mappings.at(0).members.at(0).modeInfo.hdisplay, 2560U);
+    EXPECT(LG_RESULT.mappings.at(0).members.at(0).modeInfo.vdisplay, 2880U);
+    EXPECT(LG_RESULT.mappings.at(0).members.at(0).modeInfo.type, LG_60_LEFT.type);
+    EXPECT(LG_RESULT.mappings.at(0).members.at(1).modeInfo.type, LG_60_RIGHT.type);
+    EXPECT(LG_RESULT.mappings.at(0).members.at(1).modeInfo.vrefresh, LG_60_RIGHT.vrefresh);
+    EXPECT(modeName(LG_RESULT.mappings.at(0).members.at(0).modeInfo), "left-60");
+    EXPECT(modeName(LG_RESULT.mappings.at(0).members.at(1).modeInfo), "right-60");
+    const STilePhysicalMode EXPECTED_LEFT_60  = {.connectorId = 101, .modeInfo = LG_60_LEFT};
+    const STilePhysicalMode EXPECTED_RIGHT_60 = {.connectorId = 202, .modeInfo = LG_60_RIGHT};
+    EXPECT(LG_RESULT.mappings.at(0).members.at(0) == EXPECTED_LEFT_60, true);
+    EXPECT(LG_RESULT.mappings.at(0).members.at(1) == EXPECTED_RIGHT_60, true);
+
+    auto reversedLgModes = lgModes;
+    std::ranges::reverse(reversedLgModes);
+    for (auto& CONNECTOR : reversedLgModes) {
+        std::ranges::reverse(CONNECTOR.modes);
+    }
+    EXPECT(synthesizeTileModes(LG_GROUP, reversedLgModes) == LG_RESULT, true);
+
+    const std::vector<STileConnectorModes> NO_INTERSECTION = {
+        connectorModes(101, {LG_60_LEFT}),
+        connectorModes(202, {LG_5994_RIGHT}),
+    };
+    EXPECT(errorOf(synthesizeTileModes(LG_GROUP, NO_INTERSECTION)), static_cast<int>(eTileModeSynthesisError::NO_COMMON_MODE));
+
+    const std::vector<STileConnectorModes> NONPREFERRED = {
+        connectorModes(101, {LG_5994_LEFT, mode(2560, 2880, 469180)}),
+        connectorModes(202, {mode(2560, 2880, 469180), LG_5994_RIGHT}),
+    };
+    const auto NONPREFERRED_RESULT = synthesizeTileModes(LG_GROUP, NONPREFERRED);
+    EXPECT(!!NONPREFERRED_RESULT, true);
+    EXPECT(NONPREFERRED_RESULT.modes.at(0).refreshRate, 60000U);
+    EXPECT(NONPREFERRED_RESULT.modes.at(0).preferred, true);
+    EXPECT(NONPREFERRED_RESULT.modes.at(1).preferred, false);
+
+    const auto                             PREFERRED_5994_LEFT  = mode(2560, 2880, 468711, DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED);
+    const auto                             PREFERRED_5994_RIGHT = mode(2560, 2880, 468711, DRM_MODE_TYPE_USERDEF | DRM_MODE_TYPE_PREFERRED);
+    const std::vector<STileConnectorModes> LOWER_PREFERRED      = {
+        connectorModes(101, {mode(2560, 2880, 469180), PREFERRED_5994_LEFT}),
+        connectorModes(202, {PREFERRED_5994_RIGHT, mode(2560, 2880, 469180)}),
+    };
+    const auto LOWER_PREFERRED_RESULT = synthesizeTileModes(LG_GROUP, LOWER_PREFERRED);
+    EXPECT(LOWER_PREFERRED_RESULT.modes.at(0).refreshRate, 59940U);
+    EXPECT(LOWER_PREFERRED_RESULT.modes.at(0).preferred, true);
+
+    auto differentSync = LG_60_RIGHT;
+    ++differentSync.hsync_start;
+    const std::vector<STileConnectorModes> INCOMPATIBLE_TIMING = {
+        connectorModes(101, {LG_60_LEFT}),
+        connectorModes(202, {differentSync}),
+    };
+    EXPECT(errorOf(synthesizeTileModes(LG_GROUP, INCOMPATIBLE_TIMING)), static_cast<int>(eTileModeSynthesisError::NO_COMMON_MODE));
+
+    auto sameRoundedRefresh = LG_60_RIGHT;
+    ++sameRoundedRefresh.clock;
+    const std::vector<STileConnectorModes> DIFFERENT_EXACT_CADENCE = {
+        connectorModes(101, {LG_60_LEFT}),
+        connectorModes(202, {sameRoundedRefresh}),
+    };
+    EXPECT(errorOf(synthesizeTileModes(LG_GROUP, DIFFERENT_EXACT_CADENCE)), static_cast<int>(eTileModeSynthesisError::NO_COMMON_MODE));
+
+    auto incompatibleFlags = LG_60_RIGHT;
+    incompatibleFlags.flags ^= DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_PVSYNC;
+    const std::vector<STileConnectorModes> INCOMPATIBLE_FLAGS = {
+        connectorModes(101, {LG_60_LEFT}),
+        connectorModes(202, {incompatibleFlags}),
+    };
+    EXPECT(errorOf(synthesizeTileModes(LG_GROUP, INCOMPATIBLE_FLAGS)), static_cast<int>(eTileModeSynthesisError::NO_COMMON_MODE));
+
+    auto explicitSingleVscan                                = LG_60_RIGHT;
+    explicitSingleVscan.vscan                               = 1;
+    const std::vector<STileConnectorModes> NORMALIZED_VSCAN = {
+        connectorModes(101, {LG_60_LEFT}),
+        connectorModes(202, {explicitSingleVscan}),
+    };
+    const auto NORMALIZED_VSCAN_RESULT = synthesizeTileModes(LG_GROUP, NORMALIZED_VSCAN);
+    EXPECT(!!NORMALIZED_VSCAN_RESULT, true);
+    EXPECT(NORMALIZED_VSCAN_RESULT.mappings.front().members.at(0).modeInfo.vscan, 0U);
+    EXPECT(NORMALIZED_VSCAN_RESULT.mappings.front().members.at(1).modeInfo.vscan, 1U);
+
+    auto scanAdjustedMode                                = LG_60_LEFT;
+    scanAdjustedMode.flags                               = DEFAULT_FLAGS | DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLSCAN;
+    scanAdjustedMode.vscan                               = 2;
+    const std::vector<STileConnectorModes> SCAN_ADJUSTED = {
+        connectorModes(101, {scanAdjustedMode}),
+        connectorModes(202, {scanAdjustedMode}),
+    };
+    const auto SCAN_ADJUSTED_RESULT = synthesizeTileModes(LG_GROUP, SCAN_ADJUSTED);
+    EXPECT(SCAN_ADJUSTED_RESULT.modes.front().refreshRate, 30000U);
+    EXPECT(SCAN_ADJUSTED_RESULT.modes.front().refresh.numerator, 2932375U);
+    EXPECT(SCAN_ADJUSTED_RESULT.modes.front().refresh.denominator, 97746U);
+
+    const auto                             VERTICAL_GROUP = uniformGroup(2, 1, 2, 1920, 1080, {301, 302});
+    const auto                             HD_MODE        = mode(1920, 1080, 139440);
+    const std::vector<STileConnectorModes> VERTICAL_MODES = {
+        connectorModes(302, {HD_MODE}),
+        connectorModes(301, {HD_MODE}),
+    };
+    const auto VERTICAL_RESULT = synthesizeTileModes(VERTICAL_GROUP, VERTICAL_MODES);
+    EXPECT(!!VERTICAL_RESULT, true);
+    EXPECT(VERTICAL_RESULT.modes.front().width, 1920U);
+    EXPECT(VERTICAL_RESULT.modes.front().height, 2160U);
+    EXPECT(VERTICAL_RESULT.mappings.front().members.at(0).connectorId, 301U);
+    EXPECT(VERTICAL_RESULT.mappings.front().members.at(1).connectorId, 302U);
+
+    const auto                             GRID_GROUP   = uniformGroup(3, 2, 2, 1280, 720, {11, 22, 33, 44});
+    const auto                             HD_TILE_MODE = mode(1280, 720, 65443);
+    const std::vector<STileConnectorModes> GRID_MODES   = {
+        connectorModes(44, {HD_TILE_MODE}),
+        connectorModes(11, {HD_TILE_MODE}),
+        connectorModes(33, {HD_TILE_MODE}),
+        connectorModes(22, {HD_TILE_MODE}),
+    };
+    const auto GRID_RESULT = synthesizeTileModes(GRID_GROUP, GRID_MODES);
+    EXPECT(!!GRID_RESULT, true);
+    EXPECT(GRID_RESULT.modes.front().width, 2560U);
+    EXPECT(GRID_RESULT.modes.front().height, 1440U);
+    EXPECT(GRID_RESULT.mappings.front().members.size(), 4U);
+    EXPECT(GRID_RESULT.mappings.front().members.at(0).connectorId, 11U);
+    EXPECT(GRID_RESULT.mappings.front().members.at(3).connectorId, 44U);
+
+    auto nonuniformGroup                = GRID_GROUP;
+    nonuniformGroup.members.at(1).width = 1920;
+    nonuniformGroup.members.at(3).width = 1920;
+    nonuniformGroup.width               = 3200;
+    EXPECT(errorOf(synthesizeTileModes(nonuniformGroup, GRID_MODES)), static_cast<int>(eTileModeSynthesisError::NONUNIFORM_GEOMETRY));
+
+    auto unifiedGroup = LG_GROUP;
+    unifiedGroup.kind = eTileGroupKind::DRIVER_UNIFIED;
+    EXPECT(errorOf(synthesizeTileModes(unifiedGroup, lgModes)), static_cast<int>(eTileModeSynthesisError::NOT_MULTI_STREAM));
+
+    const std::vector<STileConnectorModes> MISSING_MEMBER = {connectorModes(101, {LG_60_LEFT})};
+    EXPECT(errorOf(synthesizeTileModes(LG_GROUP, MISSING_MEMBER)), static_cast<int>(eTileModeSynthesisError::MEMBER_MISMATCH));
+
+    const std::vector<STileConnectorModes> WRONG_DEVICE = {
+        connectorModes(101, {LG_60_LEFT}, 1),
+        connectorModes(202, {LG_60_RIGHT}, 2),
+    };
+    EXPECT(errorOf(synthesizeTileModes(LG_GROUP, WRONG_DEVICE)), static_cast<int>(eTileModeSynthesisError::MEMBER_MISMATCH));
+
+    return ret;
+}
diff --git a/tests/TileTopology.cpp b/tests/TileTopology.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..46273da91d5437c393ec27bbb056de9dd5c46564
--- /dev/null
+++ b/tests/TileTopology.cpp
@@ -0,0 +1,205 @@
+#include "backend/drm/Tile.hpp"
+#include "shared.hpp"
+
+#include <algorithm>
+#include <cstdint>
+#include <limits>
+#include <string>
+#include <vector>
+
+using namespace Aquamarine::NTiling;
+
+namespace {
+    STileInfo tile(uint32_t groupId, uint32_t columns, uint32_t rows, uint32_t column, uint32_t row, uint32_t width, uint32_t height, bool singleMonitor = true) {
+        return {
+            .groupId         = groupId,
+            .isSingleMonitor = singleMonitor,
+            .numHTile        = columns,
+            .numVTile        = rows,
+            .tileHLoc        = column,
+            .tileVLoc        = row,
+            .tileHSize       = width,
+            .tileVSize       = height,
+        };
+    }
+
+    STileConnector connector(uint32_t connectorId, const STileInfo& tileInfo, uint32_t maxWidth, uint32_t maxHeight, uint64_t deviceId = 1) {
+        return {
+            .deviceId    = deviceId,
+            .connectorId = connectorId,
+            .tile        = tileInfo,
+            .modes       = {{.width = maxWidth, .height = maxHeight}},
+        };
+    }
+}
+
+int main() {
+    int                               ret = 0;
+
+    const std::vector<STileConnector> NON_TILE          = {{.deviceId = 1, .connectorId = 1}};
+    const auto                        NON_TILE_TOPOLOGY = buildTileTopology(NON_TILE);
+    EXPECT(NON_TILE_TOPOLOGY.groups.empty(), true);
+    EXPECT(NON_TILE_TOPOLOGY.rejected.empty(), true);
+
+    const auto PARSED = parseTileInfo("1:1:2:1:0:0:2560:2880");
+    EXPECT(!!PARSED, true);
+    const auto PARSED_TILE = PARSED.tile.value_or(STileInfo{});
+    EXPECT(PARSED_TILE.groupId, 1U);
+    EXPECT(PARSED_TILE.isSingleMonitor, true);
+    EXPECT(PARSED_TILE.numHTile, 2U);
+    EXPECT(PARSED_TILE.numVTile, 1U);
+    EXPECT(PARSED_TILE.tileHSize, 2560U);
+    EXPECT(PARSED_TILE.tileVSize, 2880U);
+
+    constexpr char    NUL_TERMINATED_DATA[] = "2:0:1:1:0:0:1920:1080\0ignored";
+    const std::string NUL_TERMINATED{NUL_TERMINATED_DATA, sizeof(NUL_TERMINATED_DATA) - 1};
+    const auto        PARSED_NUL = parseTileInfo(NUL_TERMINATED);
+    EXPECT(!!PARSED_NUL, true);
+    const auto PARSED_NUL_TILE = PARSED_NUL.tile.value_or(STileInfo{});
+    EXPECT(PARSED_NUL_TILE.groupId, 2U);
+    EXPECT(PARSED_NUL_TILE.isSingleMonitor, false);
+
+    const auto expectParseError = [&](std::string_view blob, eTileParseError error) {
+        const auto PARSE_RESULT = parseTileInfo(blob);
+        EXPECT(!!PARSE_RESULT, false);
+        EXPECT(static_cast<int>(PARSE_RESULT.error), static_cast<int>(error));
+    };
+
+    expectParseError("", eTileParseError::EMPTY);
+    expectParseError("1:1:2:1:0:0:2560", eTileParseError::FIELD_COUNT);
+    expectParseError("1:1:2:1:0:0:2560:2880:0", eTileParseError::FIELD_COUNT);
+    expectParseError("1:1:two:1:0:0:2560:2880", eTileParseError::INVALID_NUMBER);
+    expectParseError("1:1:-2:1:0:0:2560:2880", eTileParseError::INVALID_NUMBER);
+    expectParseError("4294967296:1:2:1:0:0:2560:2880", eTileParseError::NUMBER_OUT_OF_RANGE);
+    expectParseError("0:1:2:1:0:0:2560:2880", eTileParseError::INVALID_GROUP);
+    expectParseError("1:2:2:1:0:0:2560:2880", eTileParseError::INVALID_SINGLE_MONITOR);
+    expectParseError("1:1:0:1:0:0:2560:2880", eTileParseError::INVALID_GRID);
+    expectParseError("1:1:2:1:2:0:2560:2880", eTileParseError::INVALID_LOCATION);
+    expectParseError("1:1:2:1:0:0:0:2880", eTileParseError::INVALID_SIZE);
+    expectParseError("1:1:2:1:0:0:2147483648:2880", eTileParseError::NUMBER_OUT_OF_RANGE);
+
+    std::vector<STileConnector> lg = {
+        connector(202, tile(1, 2, 1, 1, 0, 2560, 2880), 2560, 2880),
+        connector(101, tile(1, 2, 1, 0, 0, 2560, 2880), 2560, 2880),
+    };
+
+    const auto LG_TOPOLOGY = buildTileTopology(lg);
+    EXPECT(LG_TOPOLOGY.rejected.size(), 0U);
+    EXPECT(LG_TOPOLOGY.groups.size(), 1U);
+    const auto& LG_GROUP = LG_TOPOLOGY.groups.front();
+    EXPECT(LG_GROUP.width, 5120U);
+    EXPECT(LG_GROUP.height, 2880U);
+    EXPECT(LG_GROUP.numHTile, 2U);
+    EXPECT(LG_GROUP.numVTile, 1U);
+    EXPECT(static_cast<int>(LG_GROUP.kind), static_cast<int>(eTileGroupKind::MULTI_STREAM));
+    EXPECT(LG_GROUP.primaryConnector, 101U);
+    EXPECT(LG_GROUP.members.at(0).connectorId, 101U);
+    EXPECT(LG_GROUP.members.at(0).x, 0U);
+    EXPECT(LG_GROUP.members.at(1).connectorId, 202U);
+    EXPECT(LG_GROUP.members.at(1).x, 2560U);
+
+    std::ranges::reverse(lg);
+    const auto LG_REVERSED = buildTileTopology(lg);
+    EXPECT(LG_REVERSED.groups.front() == LG_GROUP, true);
+
+    auto unified                = lg;
+    unified.at(0).modes         = {{.width = 5120, .height = 2880}};
+    const auto UNIFIED_TOPOLOGY = buildTileTopology(unified);
+    EXPECT(UNIFIED_TOPOLOGY.groups.size(), 1U);
+    EXPECT(static_cast<int>(UNIFIED_TOPOLOGY.groups.front().kind), static_cast<int>(eTileGroupKind::DRIVER_UNIFIED));
+    EXPECT(UNIFIED_TOPOLOGY.groups.front().primaryConnector, unified.at(0).connectorId);
+
+    auto oneDimensionShort            = unified;
+    oneDimensionShort.at(0).modes     = {{.width = 5120, .height = 2160}};
+    const auto ONE_DIMENSION_TOPOLOGY = buildTileTopology(oneDimensionShort);
+    EXPECT(static_cast<int>(ONE_DIMENSION_TOPOLOGY.groups.front().kind), static_cast<int>(eTileGroupKind::MULTI_STREAM));
+
+    auto splitDimensionMaxima        = lg;
+    splitDimensionMaxima.at(0).modes = {{.width = 5120, .height = 1440}, {.width = 2560, .height = 2880}};
+    const auto SPLIT_MAXIMA_TOPOLOGY = buildTileTopology(splitDimensionMaxima);
+    EXPECT(static_cast<int>(SPLIT_MAXIMA_TOPOLOGY.groups.front().kind), static_cast<int>(eTileGroupKind::MULTI_STREAM));
+
+    const auto INCOMPLETE = buildTileTopology(std::span<const STileConnector>{lg}.first(1));
+    EXPECT(INCOMPLETE.groups.size(), 0U);
+    EXPECT(INCOMPLETE.rejected.size(), 1U);
+    EXPECT(static_cast<int>(INCOMPLETE.rejected.front().error), static_cast<int>(eTileGroupError::INCOMPLETE_GRID));
+
+    const std::vector<STileConnector> DUPLICATE_TILE = {
+        connector(101, tile(1, 2, 1, 0, 0, 2560, 2880), 2560, 2880),
+        connector(202, tile(1, 2, 1, 0, 0, 2560, 2880), 2560, 2880),
+    };
+    const auto DUPLICATE_TILE_TOPOLOGY = buildTileTopology(DUPLICATE_TILE);
+    EXPECT(static_cast<int>(DUPLICATE_TILE_TOPOLOGY.rejected.front().error), static_cast<int>(eTileGroupError::DUPLICATE_TILE));
+
+    const std::vector<STileConnector> DUPLICATE_CONNECTOR = {
+        connector(101, tile(1, 2, 1, 0, 0, 2560, 2880), 2560, 2880),
+        connector(101, tile(1, 2, 1, 1, 0, 2560, 2880), 2560, 2880),
+    };
+    const auto DUPLICATE_CONNECTOR_TOPOLOGY = buildTileTopology(DUPLICATE_CONNECTOR);
+    EXPECT(static_cast<int>(DUPLICATE_CONNECTOR_TOPOLOGY.rejected.front().error), static_cast<int>(eTileGroupError::DUPLICATE_CONNECTOR));
+
+    const std::vector<STileConnector> INCONSISTENT_GRID = {
+        connector(101, tile(1, 2, 1, 0, 0, 2560, 2880), 2560, 2880),
+        connector(202, tile(1, 3, 1, 1, 0, 2560, 2880), 2560, 2880),
+    };
+    const auto INCONSISTENT_GRID_TOPOLOGY = buildTileTopology(INCONSISTENT_GRID);
+    EXPECT(static_cast<int>(INCONSISTENT_GRID_TOPOLOGY.rejected.front().error), static_cast<int>(eTileGroupError::INCONSISTENT_GRID));
+
+    const std::vector<STileConnector> INCONSISTENT_MONITOR = {
+        connector(101, tile(1, 2, 1, 0, 0, 2560, 2880, true), 2560, 2880),
+        connector(202, tile(1, 2, 1, 1, 0, 2560, 2880, false), 2560, 2880),
+    };
+    const auto INCONSISTENT_MONITOR_TOPOLOGY = buildTileTopology(INCONSISTENT_MONITOR);
+    EXPECT(static_cast<int>(INCONSISTENT_MONITOR_TOPOLOGY.rejected.front().error), static_cast<int>(eTileGroupError::INCONSISTENT_MONITOR));
+
+    const std::vector<STileConnector> VERTICAL = {
+        connector(302, tile(3, 1, 2, 0, 1, 3840, 2160), 3840, 2160),
+        connector(301, tile(3, 1, 2, 0, 0, 3840, 2160), 3840, 2160),
+    };
+    const auto  VERTICAL_TOPOLOGY = buildTileTopology(VERTICAL);
+    const auto& VERTICAL_GROUP    = VERTICAL_TOPOLOGY.groups.front();
+    EXPECT(VERTICAL_GROUP.width, 3840U);
+    EXPECT(VERTICAL_GROUP.height, 4320U);
+    EXPECT(VERTICAL_GROUP.members.at(1).y, 2160U);
+
+    const std::vector<STileConnector> GRID_2X2 = {
+        connector(44, tile(4, 2, 2, 1, 1, 2560, 1200), 2560, 1200),
+        connector(11, tile(4, 2, 2, 0, 0, 1920, 1080), 1920, 1080),
+        connector(33, tile(4, 2, 2, 0, 1, 1920, 1200), 1920, 1200),
+        connector(22, tile(4, 2, 2, 1, 0, 2560, 1080), 2560, 1080),
+    };
+    const auto  GRID_2X2_TOPOLOGY = buildTileTopology(GRID_2X2);
+    const auto& GRID_2X2_GROUP    = GRID_2X2_TOPOLOGY.groups.front();
+    EXPECT(GRID_2X2_GROUP.width, 4480U);
+    EXPECT(GRID_2X2_GROUP.height, 2280U);
+    EXPECT(GRID_2X2_GROUP.members.at(3).x, 1920U);
+    EXPECT(GRID_2X2_GROUP.members.at(3).y, 1080U);
+
+    auto inconsistentGeometry                 = GRID_2X2;
+    inconsistentGeometry.at(2).tile.tileHSize = 1919;
+    const auto INCONSISTENT_GEOMETRY          = buildTileTopology(inconsistentGeometry);
+    EXPECT(static_cast<int>(INCONSISTENT_GEOMETRY.rejected.front().error), static_cast<int>(eTileGroupError::INCONSISTENT_GEOMETRY));
+
+    const std::vector<STileConnector> OVERFLOW = {
+        connector(1, tile(5, 2, 1, 0, 0, std::numeric_limits<uint32_t>::max(), 1), 1, 1),
+        connector(2, tile(5, 2, 1, 1, 0, 1, 1), 1, 1),
+    };
+    const auto OVERFLOW_TOPOLOGY = buildTileTopology(OVERFLOW);
+    EXPECT(static_cast<int>(OVERFLOW_TOPOLOGY.rejected.front().error), static_cast<int>(eTileGroupError::GEOMETRY_OVERFLOW));
+
+    std::vector<STileConnector> TWO_DEVICES = {
+        connector(11, tile(7, 2, 1, 0, 0, 100, 100), 100, 100, 10),
+        connector(12, tile(7, 2, 1, 1, 0, 100, 100), 100, 100, 10),
+        connector(21, tile(7, 2, 1, 0, 0, 200, 200), 200, 200, 20),
+        connector(22, tile(7, 2, 1, 1, 0, 200, 200), 200, 200, 20),
+    };
+    std::ranges::reverse(TWO_DEVICES);
+    const auto DEVICE_TOPOLOGY = buildTileTopology(TWO_DEVICES);
+    EXPECT(DEVICE_TOPOLOGY.groups.size(), 2U);
+    EXPECT(DEVICE_TOPOLOGY.groups.at(0).key.deviceId, 10U);
+    EXPECT(DEVICE_TOPOLOGY.groups.at(0).width, 200U);
+    EXPECT(DEVICE_TOPOLOGY.groups.at(1).key.deviceId, 20U);
+    EXPECT(DEVICE_TOPOLOGY.groups.at(1).width, 400U);
+
+    return ret;
+}
diff --git a/tests/TiledCrtcAllocator.cpp b/tests/TiledCrtcAllocator.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..25248fa8bcbc8ffd95572f4ed6f7edcce96b664a
--- /dev/null
+++ b/tests/TiledCrtcAllocator.cpp
@@ -0,0 +1,1613 @@
+#include "../src/backend/drm/TiledCrtcAllocator.hpp"
+
+#include <algorithm>
+#include <array>
+#include <atomic>
+#include <cstdint>
+#include <functional>
+#include <iostream>
+#include <limits>
+#include <numeric>
+#include <optional>
+#include <string_view>
+#include <thread>
+#include <tuple>
+#include <type_traits>
+#include <utility>
+#include <vector>
+
+using namespace Aquamarine;
+using namespace Aquamarine::NDRM::NTiledCrtcAllocator;
+using Hyprutils::Memory::CSharedPointer;
+using Hyprutils::Memory::CWeakPointer;
+using Hyprutils::Memory::makeShared;
+
+namespace {
+    static_assert(!std::is_aggregate_v<CPlan>);
+    static_assert(!std::is_default_constructible_v<CPlan>);
+    static_assert(!std::is_copy_constructible_v<CPlan>);
+    static_assert(!std::is_move_constructible_v<CPlan>);
+    static_assert(!std::is_default_constructible_v<CBinding>);
+    static_assert(!std::is_default_constructible_v<CGroupAllocation>);
+    static_assert(std::is_same_v<decltype(std::declval<const CPlan&>().groups()), const std::vector<CGroupAllocation>&>);
+    static_assert(std::is_same_v<decltype(std::declval<const CGroupAllocation&>().bindings()), const std::vector<CBinding>&>);
+
+    int  FAILURES = 0;
+
+    void check(bool condition, std::string_view expression, int line) {
+        if (condition)
+            return;
+        std::cerr << __FILE__ << ':' << line << ": check failed: " << expression << '\n';
+        ++FAILURES;
+    }
+
+#define CHECK(condition) check((condition), #condition, __LINE__)
+
+    struct SObjectPool {
+        std::vector<CSharedPointer<SDRMConnector>> connectors;
+        std::vector<CSharedPointer<SDRMCRTC>>      crtcs;
+        std::vector<CSharedPointer<SDRMPlane>>     planes;
+
+        SObjectPool(std::vector<uint32_t> connectorIDs, std::vector<uint32_t> crtcIDs, std::vector<uint32_t> planeIDs) {
+            for (const auto id : connectorIDs) {
+                auto connector = makeShared<SDRMConnector>();
+                connector->id  = id;
+                connectors.push_back(std::move(connector));
+            }
+            for (const auto id : crtcIDs) {
+                auto crtc = makeShared<SDRMCRTC>();
+                crtc->id  = id;
+                crtcs.push_back(std::move(crtc));
+            }
+            for (const auto id : planeIDs) {
+                auto plane  = makeShared<SDRMPlane>();
+                plane->id   = id;
+                plane->type = DRM_PLANE_TYPE_PRIMARY;
+                planes.push_back(std::move(plane));
+            }
+        }
+    };
+
+    struct SCompatibility {
+        std::vector<std::vector<uint32_t>> connectors;
+        std::vector<std::vector<uint32_t>> planes;
+    };
+
+    uint64_t                                               NEXT_OBSERVATION = 1;
+    uint64_t                                               NEXT_RESOURCE    = 1;
+    uint64_t                                               NEXT_DEFINITION  = 1;
+    uint64_t                                               NEXT_ALLOCATION  = 1;
+    std::vector<CSharedPointer<const SBackendIncarnation>> BACKEND_LIFETIMES;
+
+    struct SRequest {
+        CSharedPointer<const CSnapshot>                     snapshot;
+        CSharedPointer<const SBackendIncarnation>           currentBackendLifetime;
+        std::vector<CSharedPointer<const CGroupDefinition>> currentGroupDefinitions;
+        std::vector<SHardHold>                              hardHolds;
+        std::vector<SGroupRequest>                          groups;
+        std::vector<SOrdinaryRequest>                       ordinary;
+        std::vector<SConnectorCRTCPreference>               connectorPreferences;
+        std::vector<SCRTCPlanePreference>                   planePreferences;
+        SAllocationEpoch                                    epoch;
+    };
+
+    template <typename T>
+    CSharedPointer<const T> asConst(CSharedPointer<T> pointer) {
+        return pointer;
+    }
+
+    CSharedPointer<const SBackendIncarnation> makeBackendLifetime(uint64_t serial) {
+        auto lifetime    = makeShared<SBackendIncarnation>();
+        lifetime->serial = serial;
+        return asConst(std::move(lifetime));
+    }
+
+    CSharedPointer<const SDeviceIncarnation> makeDevice(uint64_t deviceId = 900, uint64_t deviceEpoch = 9, uint64_t fdEpoch = 27, uint64_t serial = 81,
+                                                        CSharedPointer<const SBackendIncarnation> lifetime = {}, eBackendBinding binding = eBackendBinding::LIFETIME_TOKEN) {
+        if (!lifetime) {
+            lifetime = makeBackendLifetime(serial + 1000);
+            BACKEND_LIFETIMES.push_back(lifetime);
+        }
+        auto device             = makeShared<SDeviceIncarnation>();
+        device->deviceId        = deviceId;
+        device->deviceEpoch     = deviceEpoch;
+        device->fdEpoch         = fdEpoch;
+        device->serial          = serial;
+        device->binding         = binding;
+        device->backendLifetime = lifetime;
+        return asConst(std::move(device));
+    }
+
+    CSharedPointer<const SResourceIncarnation> makeIncarnation(eResourceKind kind, uint32_t id, const SGeneration& generation,
+                                                               const CSharedPointer<const SDeviceIncarnation>&      device,
+                                                               const CSharedPointer<const SObservationIncarnation>& observation) {
+        auto incarnation         = makeShared<SResourceIncarnation>();
+        incarnation->kind        = kind;
+        incarnation->resourceID  = id;
+        incarnation->serial      = NEXT_RESOURCE++;
+        incarnation->generation  = generation;
+        incarnation->device      = device;
+        incarnation->observation = observation;
+        return asConst(std::move(incarnation));
+    }
+
+    std::vector<size_t> naturalOrder(size_t size) {
+        std::vector<size_t> result(size);
+        std::ranges::iota(result, 0);
+        return result;
+    }
+
+    CSharedPointer<const CSnapshot> makeSnapshot(const SObjectPool& pool, const SCompatibility& compatibility, std::vector<size_t> connectorOrder = {},
+                                                 std::vector<size_t> crtcOrder = {}, std::vector<size_t> planeOrder = {}, CSharedPointer<const SDeviceIncarnation> device = {}) {
+        CHECK(compatibility.connectors.size() == pool.connectors.size());
+        CHECK(compatibility.planes.size() == pool.planes.size());
+        if (!device)
+            device = makeDevice();
+        if (connectorOrder.empty())
+            connectorOrder = naturalOrder(pool.connectors.size());
+        if (crtcOrder.empty())
+            crtcOrder = naturalOrder(pool.crtcs.size());
+        if (planeOrder.empty())
+            planeOrder = naturalOrder(pool.planes.size());
+
+        const SGeneration generation                   = {.device = device->deviceEpoch, .session = 17, .observation = NEXT_OBSERVATION++};
+        auto              mutableObservation           = makeShared<SObservationIncarnation>();
+        mutableObservation->generation                 = generation;
+        mutableObservation->serial                     = generation.observation;
+        mutableObservation->device                     = device;
+        mutableObservation->backendLifetime            = device->backendLifetime;
+        const auto                         observation = asConst(std::move(mutableObservation));
+
+        std::vector<SConnectorResource>    connectors;
+        std::vector<SCRTCResource>         crtcs;
+        std::vector<SPrimaryPlaneResource> planes;
+        connectors.reserve(connectorOrder.size());
+        crtcs.reserve(crtcOrder.size());
+        planes.reserve(planeOrder.size());
+        for (const auto index : connectorOrder) {
+            connectors.push_back({
+                .connector       = pool.connectors.at(index),
+                .incarnation     = makeIncarnation(eResourceKind::CONNECTOR, pool.connectors.at(index)->id, generation, device, observation),
+                .possibleCRTCIDs = compatibility.connectors.at(index),
+            });
+        }
+        for (const auto index : crtcOrder) {
+            crtcs.push_back({
+                .crtc        = pool.crtcs.at(index),
+                .incarnation = makeIncarnation(eResourceKind::CRTC, pool.crtcs.at(index)->id, generation, device, observation),
+            });
+        }
+        for (const auto index : planeOrder) {
+            planes.push_back({
+                .plane           = pool.planes.at(index),
+                .incarnation     = makeIncarnation(eResourceKind::PRIMARY_PLANE, pool.planes.at(index)->id, generation, device, observation),
+                .possibleCRTCIDs = compatibility.planes.at(index),
+                .usable          = true,
+            });
+        }
+
+        const auto snapshot = CSnapshot::create(generation, observation, std::move(connectors), std::move(crtcs), std::move(planes));
+        CHECK(static_cast<bool>(snapshot));
+        return snapshot;
+    }
+
+    SConnectorHandle connectorHandle(const CSharedPointer<const CSnapshot>& snapshot, uint32_t id) {
+        const auto resource = std::ranges::find_if(snapshot->connectors(), [id](const auto& candidate) { return candidate.connector->id == id; });
+        CHECK(resource != snapshot->connectors().end());
+        return {.id = id, .incarnation = resource->incarnation};
+    }
+
+    SCRTCHandle crtcHandle(const CSharedPointer<const CSnapshot>& snapshot, uint32_t id) {
+        const auto resource = std::ranges::find_if(snapshot->crtcs(), [id](const auto& candidate) { return candidate.crtc->id == id; });
+        CHECK(resource != snapshot->crtcs().end());
+        return {.id = id, .incarnation = resource->incarnation};
+    }
+
+    SPrimaryPlaneHandle planeHandle(const CSharedPointer<const CSnapshot>& snapshot, uint32_t id) {
+        const auto resource = std::ranges::find_if(snapshot->primaryPlanes(), [id](const auto& candidate) { return candidate.plane->id == id; });
+        CHECK(resource != snapshot->primaryPlanes().end());
+        return {.id = id, .incarnation = resource->incarnation};
+    }
+
+    NTiling::STileGroup tileGroup(uint64_t deviceId, uint32_t groupId, const std::vector<uint32_t>& connectorIDs, bool reverseMembers = false) {
+        NTiling::STileGroup group{
+            .key              = {.deviceId = deviceId, .groupId = groupId},
+            .isSingleMonitor  = true,
+            .numHTile         = static_cast<uint32_t>(connectorIDs.size()),
+            .numVTile         = 1,
+            .width            = static_cast<uint32_t>(connectorIDs.size() * 100),
+            .height           = 50,
+            .kind             = NTiling::eTileGroupKind::MULTI_STREAM,
+            .primaryConnector = connectorIDs.front(),
+            .members          = {},
+        };
+        for (size_t index = 0; index < connectorIDs.size(); ++index) {
+            group.members.push_back({
+                .connectorId = connectorIDs.at(index),
+                .tileHLoc    = static_cast<uint32_t>(index),
+                .tileVLoc    = 0,
+                .x           = static_cast<uint32_t>(index * 100),
+                .y           = 0,
+                .width       = 100,
+                .height      = 50,
+            });
+        }
+        if (reverseMembers)
+            std::ranges::reverse(group.members);
+        return group;
+    }
+
+    CSharedPointer<const CGroupDefinition> makeDefinition(const CSharedPointer<const CSnapshot>& snapshot, uint32_t groupId, const std::vector<uint32_t>& connectorIDs,
+                                                          bool reverseMembers = false) {
+        auto definition = CGroupDefinition::create(tileGroup(snapshot->device()->deviceId, groupId, connectorIDs, reverseMembers), snapshot->device(), NEXT_DEFINITION++);
+        CHECK(static_cast<bool>(definition));
+        return definition;
+    }
+
+    SGroupRequest groupRequest(const CSharedPointer<const CSnapshot>& snapshot, const CSharedPointer<const CGroupDefinition>& definition, bool reverseConnectors = false) {
+        SGroupRequest request{
+            .definition = definition,
+            .connectors = {},
+            .retained   = std::nullopt,
+        };
+        for (const auto& member : definition->group().members)
+            request.connectors.push_back(connectorHandle(snapshot, member.connectorId));
+        if (reverseConnectors)
+            std::ranges::reverse(request.connectors);
+        return request;
+    }
+
+    SRequest requestFor(const CSharedPointer<const CSnapshot>& snapshot, std::vector<CSharedPointer<const CGroupDefinition>> definitions = {}) {
+        SRequest request;
+        request.snapshot                = snapshot;
+        request.currentBackendLifetime  = snapshot->device()->backendLifetime.lock();
+        request.currentGroupDefinitions = std::move(definitions);
+        request.epoch                   = {
+            .session     = snapshot->generation().session,
+            .allocation  = NEXT_ALLOCATION++,
+            .eventThread = 1,
+        };
+        return request;
+    }
+
+    CSharedPointer<const CAllocationObservation> observe(const SRequest& request) {
+        return CAllocationObservation::create(request.snapshot, request.currentBackendLifetime, request.currentGroupDefinitions, request.hardHolds, request.groups,
+                                              request.ordinary, request.connectorPreferences, request.planePreferences, request.epoch);
+    }
+
+    CSharedPointer<const CPlan> solve(const CSharedPointer<const CSnapshot>& snapshot, const SRequest& request) {
+        CHECK(snapshot.impl_ == request.snapshot.impl_);
+        return Aquamarine::NDRM::NTiledCrtcAllocator::solve(observe(request));
+    }
+
+    SCurrentState currentState(const CSharedPointer<const CPlan>& plan) {
+        CHECK(static_cast<bool>(plan));
+        return {
+            .snapshot        = plan->snapshot(),
+            .backendLifetime = plan->snapshot()->device()->backendLifetime.lock(),
+            .observation     = plan->observation(),
+            .epoch           = plan->observation()->epoch(),
+        };
+    }
+
+    SRequest oneGroupRequest(const CSharedPointer<const CSnapshot>& snapshot, uint32_t groupId, const std::vector<uint32_t>& connectorIDs, bool reverseDefinition = false,
+                             bool reverseRequest = false) {
+        const auto definition = makeDefinition(snapshot, groupId, connectorIDs, reverseDefinition);
+        auto       request    = requestFor(snapshot, {definition});
+        request.groups.push_back(groupRequest(snapshot, definition, reverseRequest));
+        return request;
+    }
+
+    const CBinding* bindingFor(const std::vector<CBinding>& bindings, uint32_t connectorID) {
+        const auto binding = std::ranges::find_if(bindings, [connectorID](const auto& candidate) { return candidate.connector()->id == connectorID; });
+        return binding == bindings.end() ? nullptr : &*binding;
+    }
+
+    const CGroupAllocation* allocationFor(const CSharedPointer<const CPlan>& plan, uint32_t groupId) {
+        const auto allocation = std::ranges::find_if(plan->groups(), [groupId](const auto& candidate) { return candidate.definition()->group().key.groupId == groupId; });
+        return allocation == plan->groups().end() ? nullptr : &*allocation;
+    }
+
+    size_t bindingCount(const CSharedPointer<const CPlan>& plan) {
+        size_t result = plan->ordinaryBindings().size();
+        for (const auto& group : plan->groups())
+            result += group.bindings().size();
+        return result;
+    }
+
+    std::vector<uint32_t> idsFromMask(uint32_t mask, const std::vector<uint32_t>& ids) {
+        const auto normalized = normalizeCRTCIDs(mask, ids);
+        CHECK(normalized.has_value());
+        return normalized.value_or(std::vector<uint32_t>{});
+    }
+
+    SRetainedGroupBinding retainedBinding(const CSharedPointer<const CSnapshot>& snapshot, uint32_t connectorID, uint32_t crtcID, uint32_t planeID) {
+        return {
+            .connector    = connectorHandle(snapshot, connectorID),
+            .crtc         = crtcHandle(snapshot, crtcID),
+            .primaryPlane = planeHandle(snapshot, planeID),
+        };
+    }
+
+    using CBindingPairs = std::vector<std::pair<uint32_t, uint32_t>>;
+
+    std::optional<CBindingPairs> bruteForce(const std::vector<uint32_t>& connectorMasks, const std::vector<uint32_t>& planeMasks, const std::vector<uint32_t>& crtcIDs,
+                                            const std::vector<uint32_t>& planeIDs) {
+        const auto                   size            = connectorMasks.size();
+        std::vector<size_t>          crtcPermutation = naturalOrder(size);
+        std::optional<CBindingPairs> best;
+        do {
+            bool connectorsCompatible = true;
+            for (size_t member = 0; member < size; ++member)
+                connectorsCompatible = connectorsCompatible && (connectorMasks.at(member) & (uint32_t{1} << crtcPermutation.at(member))) != 0;
+            if (!connectorsCompatible)
+                continue;
+
+            std::vector<size_t> planePermutation = naturalOrder(size);
+            do {
+                bool planesCompatible = true;
+                for (size_t member = 0; member < size; ++member)
+                    planesCompatible = planesCompatible && (planeMasks.at(planePermutation.at(member)) & (uint32_t{1} << crtcPermutation.at(member))) != 0;
+                if (!planesCompatible)
+                    continue;
+
+                CBindingPairs candidate;
+                for (size_t member = 0; member < size; ++member)
+                    candidate.emplace_back(crtcIDs.at(crtcPermutation.at(member)), planeIDs.at(planePermutation.at(member)));
+                if (!best || candidate < *best)
+                    best = std::move(candidate);
+            } while (std::ranges::next_permutation(planePermutation).found);
+        } while (std::ranges::next_permutation(crtcPermutation).found);
+        return best;
+    }
+
+    using COrdinaryBindings = std::vector<std::tuple<uint32_t, uint32_t, uint32_t>>;
+
+    COrdinaryBindings bruteForceOrdinary(const std::vector<uint32_t>& connectorMasks, const std::vector<uint32_t>& planeMasks, const std::vector<uint32_t>& connectorIDs,
+                                         const std::vector<uint32_t>& crtcIDs, const std::vector<uint32_t>& planeIDs) {
+        const auto        size = connectorMasks.size();
+        COrdinaryBindings best;
+        for (uint32_t subset = 0; subset < (uint32_t{1} << size); ++subset) {
+            std::vector<size_t> selectedConnectors;
+            for (size_t connector = 0; connector < size; ++connector) {
+                if ((subset & (uint32_t{1} << connector)) != 0)
+                    selectedConnectors.push_back(connector);
+            }
+            if (selectedConnectors.size() < best.size())
+                continue;
+
+            auto crtcPermutation = naturalOrder(size);
+            do {
+                bool connectorsCompatible = true;
+                for (size_t selected = 0; selected < selectedConnectors.size(); ++selected) {
+                    connectorsCompatible = connectorsCompatible && (connectorMasks.at(selectedConnectors.at(selected)) & (uint32_t{1} << crtcPermutation.at(selected))) != 0;
+                }
+                if (!connectorsCompatible)
+                    continue;
+
+                auto planePermutation = naturalOrder(size);
+                do {
+                    bool planesCompatible = true;
+                    for (size_t selected = 0; selected < selectedConnectors.size(); ++selected) {
+                        planesCompatible = planesCompatible && (planeMasks.at(planePermutation.at(selected)) & (uint32_t{1} << crtcPermutation.at(selected))) != 0;
+                    }
+                    if (!planesCompatible)
+                        continue;
+
+                    COrdinaryBindings candidate;
+                    for (size_t selected = 0; selected < selectedConnectors.size(); ++selected) {
+                        candidate.emplace_back(connectorIDs.at(selectedConnectors.at(selected)), crtcIDs.at(crtcPermutation.at(selected)),
+                                               planeIDs.at(planePermutation.at(selected)));
+                    }
+                    if (candidate.size() > best.size() || (candidate.size() == best.size() && candidate < best))
+                        best = std::move(candidate);
+                } while (std::ranges::next_permutation(planePermutation).found);
+            } while (std::ranges::next_permutation(crtcPermutation).found);
+        }
+        return best;
+    }
+
+    struct SOracleCandidate {
+        uint32_t                connectorID   = 0;
+        uint32_t                connectorMask = 0;
+        bool                    active        = true;
+        std::optional<size_t>   groupOrder;
+        std::optional<uint32_t> preferredCRTC;
+    };
+
+    struct SCombinedOracleInput {
+        std::vector<SOracleCandidate>        candidates;
+        std::vector<uint32_t>                planeMasks;
+        std::vector<uint32_t>                crtcIDs;
+        std::vector<uint32_t>                planeIDs;
+        std::vector<std::optional<uint32_t>> preferredPlanes;
+        size_t                               groupCount = 0;
+    };
+
+    struct SCombinedOracleScore {
+        int                  activeDropped          = 0;
+        int                  activePreferredDropped = 0;
+        int                  activeConnectorChanges = 0;
+        int                  activePlaneChanges     = 0;
+        std::vector<uint8_t> groupStatus;
+        int                  backupDropped          = 0;
+        int                  backupPreferredDropped = 0;
+        int                  backupConnectorChanges = 0;
+        int                  backupPlaneChanges     = 0;
+        COrdinaryBindings    bindings;
+    };
+
+    bool oracleScoreLess(const SCombinedOracleScore& lhs, const SCombinedOracleScore& rhs) {
+        const auto lhsActive = std::tie(lhs.activeDropped, lhs.activePreferredDropped, lhs.activeConnectorChanges, lhs.activePlaneChanges);
+        const auto rhsActive = std::tie(rhs.activeDropped, rhs.activePreferredDropped, rhs.activeConnectorChanges, rhs.activePlaneChanges);
+        if (lhsActive != rhsActive)
+            return lhsActive < rhsActive;
+        if (lhs.groupStatus != rhs.groupStatus)
+            return lhs.groupStatus < rhs.groupStatus;
+        const auto lhsBackup = std::tie(lhs.backupDropped, lhs.backupPreferredDropped, lhs.backupConnectorChanges, lhs.backupPlaneChanges);
+        const auto rhsBackup = std::tie(rhs.backupDropped, rhs.backupPreferredDropped, rhs.backupConnectorChanges, rhs.backupPlaneChanges);
+        if (lhsBackup != rhsBackup)
+            return lhsBackup < rhsBackup;
+        return lhs.bindings < rhs.bindings;
+    }
+
+    using COracleAssignment = std::vector<std::optional<std::pair<size_t, size_t>>>;
+
+    SCombinedOracleScore scoreOracleAssignment(const SCombinedOracleInput& input, const COracleAssignment& assignment) {
+        SCombinedOracleScore score;
+        score.groupStatus.assign(input.groupCount, 0);
+        for (size_t candidateIndex = 0; candidateIndex < input.candidates.size(); ++candidateIndex) {
+            const auto& groupOrder = input.candidates.at(candidateIndex).groupOrder;
+            if (groupOrder && !assignment.at(candidateIndex))
+                score.groupStatus.at(*groupOrder) = 1;
+        }
+
+        using CCanonicalKey = std::tuple<uint8_t, size_t, size_t, uint32_t, uint32_t, uint32_t>;
+        std::vector<std::pair<CCanonicalKey, std::tuple<uint32_t, uint32_t, uint32_t>>> canonicalBindings;
+        for (size_t candidateIndex = 0; candidateIndex < input.candidates.size(); ++candidateIndex) {
+            const auto& candidate = input.candidates.at(candidateIndex);
+            const auto& binding   = assignment.at(candidateIndex);
+            if (!binding) {
+                if (candidate.active) {
+                    ++score.activeDropped;
+                    if (candidate.preferredCRTC)
+                        ++score.activePreferredDropped;
+                } else {
+                    ++score.backupDropped;
+                    if (candidate.preferredCRTC)
+                        ++score.backupPreferredDropped;
+                }
+                continue;
+            }
+
+            const auto  crtcID           = input.crtcIDs.at(binding->first);
+            const auto  planeID          = input.planeIDs.at(binding->second);
+            const bool  connectorChanged = candidate.preferredCRTC && *candidate.preferredCRTC != crtcID;
+            const auto& preferredPlane   = input.preferredPlanes.at(binding->first);
+            const bool  planeChanged     = preferredPlane && *preferredPlane != planeID;
+            if (candidate.active) {
+                score.activeConnectorChanges += connectorChanged ? 1 : 0;
+                score.activePlaneChanges += planeChanged ? 1 : 0;
+            } else {
+                score.backupConnectorChanges += connectorChanged ? 1 : 0;
+                score.backupPlaneChanges += planeChanged ? 1 : 0;
+            }
+            const bool selectedGroup  = candidate.groupOrder && score.groupStatus.at(*candidate.groupOrder) == 0;
+            const auto candidateClass = static_cast<uint8_t>(selectedGroup ? 0 : (candidate.active ? 1 : 2));
+            canonicalBindings.push_back({
+                {
+                    candidateClass,
+                    selectedGroup ? *candidate.groupOrder : 0,
+                    selectedGroup ? candidateIndex : 0,
+                    candidate.connectorID,
+                    crtcID,
+                    planeID,
+                },
+                {candidate.connectorID, crtcID, planeID},
+            });
+        }
+        std::ranges::sort(canonicalBindings, [](const auto& lhs, const auto& rhs) { return lhs.first < rhs.first; });
+        for (const auto& entry : canonicalBindings)
+            score.bindings.push_back(entry.second);
+        return score;
+    }
+
+    void enumerateCombinedOracle(const SCombinedOracleInput& input, size_t candidateIndex, uint32_t usedCRTCMask, uint32_t usedPlaneMask, COracleAssignment& assignment,
+                                 std::optional<SCombinedOracleScore>& best) {
+        if (candidateIndex == input.candidates.size()) {
+            auto candidate = scoreOracleAssignment(input, assignment);
+            if (!best || oracleScoreLess(candidate, *best))
+                best = std::move(candidate);
+            return;
+        }
+
+        assignment.at(candidateIndex) = std::nullopt;
+        enumerateCombinedOracle(input, candidateIndex + 1, usedCRTCMask, usedPlaneMask, assignment, best);
+
+        const auto connectorMask = input.candidates.at(candidateIndex).connectorMask;
+        for (size_t crtcIndex = 0; crtcIndex < input.crtcIDs.size(); ++crtcIndex) {
+            const auto crtcBit = uint32_t{1} << crtcIndex;
+            if ((connectorMask & crtcBit) == 0 || (usedCRTCMask & crtcBit) != 0)
+                continue;
+            for (size_t planeIndex = 0; planeIndex < input.planeIDs.size(); ++planeIndex) {
+                const auto planeBit = uint32_t{1} << planeIndex;
+                if ((usedPlaneMask & planeBit) != 0 || (input.planeMasks.at(planeIndex) & crtcBit) == 0)
+                    continue;
+                assignment.at(candidateIndex) = std::pair{crtcIndex, planeIndex};
+                enumerateCombinedOracle(input, candidateIndex + 1, usedCRTCMask | crtcBit, usedPlaneMask | planeBit, assignment, best);
+            }
+        }
+        assignment.at(candidateIndex) = std::nullopt;
+    }
+
+    SCombinedOracleScore bruteForceCombined(const SCombinedOracleInput& input) {
+        CHECK(input.candidates.size() <= 3);
+        CHECK(input.crtcIDs.size() <= 3);
+        CHECK(input.planeIDs.size() <= 3);
+        CHECK(input.planeMasks.size() == input.planeIDs.size());
+        CHECK(input.preferredPlanes.size() == input.crtcIDs.size());
+        COracleAssignment                   assignment(input.candidates.size());
+        std::optional<SCombinedOracleScore> best;
+        enumerateCombinedOracle(input, 0, 0, 0, assignment, best);
+        CHECK(best.has_value());
+        return best.value_or(SCombinedOracleScore{});
+    }
+
+    COrdinaryBindings planBindings(const CSharedPointer<const CPlan>& plan) {
+        COrdinaryBindings bindings;
+        for (const auto& group : plan->groups()) {
+            for (const auto& binding : group.bindings())
+                bindings.emplace_back(binding.connector()->id, binding.crtc()->id, binding.primaryPlane()->id);
+        }
+        for (const auto& binding : plan->ordinaryBindings())
+            bindings.emplace_back(binding.connector()->id, binding.crtc()->id, binding.primaryPlane()->id);
+        return bindings;
+    }
+
+    size_t fakeGroupMutations(const CSharedPointer<const CPlan>& plan, const SCurrentState& current) {
+        size_t     mutations = 0;
+        const auto applied   = withCurrentPlan(plan, current, [&](const CPlan& currentPlan) {
+            for (const auto& group : currentPlan.groups())
+                mutations += group.bindings().size();
+        });
+        static_cast<void>(applied);
+        return mutations;
+    }
+
+    void testNormalizationAndSnapshotBoundary() {
+        std::vector<uint32_t> resourceOrder(32);
+        std::ranges::iota(resourceOrder, 1000);
+        resourceOrder.at(0)  = 42;
+        resourceOrder.at(2)  = 42;
+        resourceOrder.at(31) = 7;
+
+        CHECK(!normalizeCRTCIDs((uint32_t{1} << 0) | (uint32_t{1} << 2) | (uint32_t{1} << 31), resourceOrder));
+        resourceOrder.at(2) = 1002;
+        const auto bit31    = normalizeCRTCIDs((uint32_t{1} << 0) | (uint32_t{1} << 31), resourceOrder);
+        CHECK(bit31 && *bit31 == std::vector<uint32_t>({7, 42}));
+        CHECK(!normalizeCRTCIDs(std::numeric_limits<uint32_t>::max(), std::span<const uint32_t>{resourceOrder}.first(2)));
+        const auto allRepresentable = normalizeCRTCIDs(std::numeric_limits<uint32_t>::max(), resourceOrder);
+        CHECK(allRepresentable && allRepresentable->size() == 32);
+        auto oversizedOrder = resourceOrder;
+        oversizedOrder.push_back(2000);
+        CHECK(!normalizeCRTCIDs(0, oversizedOrder));
+
+        SObjectPool pool({1}, {10, 11}, {100});
+        const auto  snapshot = makeSnapshot(pool, {.connectors = {{11, 10, 11}}, .planes = {{11, 10, 10}}});
+        CHECK(snapshot->connectors().front().possibleCRTCIDs == std::vector<uint32_t>({10, 11}));
+        CHECK(snapshot->primaryPlanes().front().possibleCRTCIDs == std::vector<uint32_t>({10, 11}));
+
+        auto connectors = snapshot->connectors();
+        connectors.front().possibleCRTCIDs.push_back(999);
+        CHECK(!CSnapshot::create(snapshot->generation(), snapshot->observation(), std::move(connectors), snapshot->crtcs(), snapshot->primaryPlanes()));
+
+        auto duplicateCRTCs = snapshot->crtcs();
+        duplicateCRTCs.push_back(snapshot->crtcs().front());
+        CHECK(!CSnapshot::create(snapshot->generation(), snapshot->observation(), snapshot->connectors(), std::move(duplicateCRTCs), snapshot->primaryPlanes()));
+
+        auto tooManyCRTCs = snapshot->crtcs();
+        for (uint32_t id = 12; id < 43; ++id) {
+            auto crtc = makeShared<SDRMCRTC>();
+            crtc->id  = id;
+            tooManyCRTCs.push_back({
+                .crtc        = std::move(crtc),
+                .incarnation = makeIncarnation(eResourceKind::CRTC, id, snapshot->generation(), snapshot->device(), snapshot->observation()),
+            });
+        }
+        CHECK(tooManyCRTCs.size() == 33);
+        CHECK(!CSnapshot::create(snapshot->generation(), snapshot->observation(), snapshot->connectors(), std::move(tooManyCRTCs), snapshot->primaryPlanes()));
+
+        auto unusablePlanes           = snapshot->primaryPlanes();
+        unusablePlanes.front().usable = false;
+        const auto unusableSnapshot   = CSnapshot::create(snapshot->generation(), snapshot->observation(), snapshot->connectors(), snapshot->crtcs(), std::move(unusablePlanes));
+        CHECK(static_cast<bool>(unusableSnapshot));
+        auto ordinary = requestFor(unusableSnapshot);
+        ordinary.ordinary.push_back({.connector = connectorHandle(unusableSnapshot, 1)});
+        CHECK(solve(unusableSnapshot, ordinary)->ordinaryBindings().empty());
+    }
+
+    void testDefinitionFactory() {
+        const auto device     = makeDevice(901, 10, 30, 90);
+        auto       valid      = tileGroup(device->deviceId, 7, {1, 2});
+        const auto definition = CGroupDefinition::create(valid, device, 1);
+        CHECK(static_cast<bool>(definition));
+        CHECK(definition->group().members.front().connectorId == 1);
+        CHECK(definition->serial() == 1);
+
+        auto singleton = tileGroup(device->deviceId, 7, {1});
+        CHECK(!CGroupDefinition::create(singleton, device, 2));
+        auto unified = valid;
+        unified.kind = NTiling::eTileGroupKind::DRIVER_UNIFIED;
+        CHECK(!CGroupDefinition::create(unified, device, 3));
+        auto notMonitor            = valid;
+        notMonitor.isSingleMonitor = false;
+        CHECK(!CGroupDefinition::create(notMonitor, device, 4));
+        auto incomplete     = valid;
+        incomplete.numHTile = 3;
+        CHECK(!CGroupDefinition::create(incomplete, device, 5));
+        auto duplicateConnector                      = valid;
+        duplicateConnector.members.at(1).connectorId = 1;
+        CHECK(!CGroupDefinition::create(duplicateConnector, device, 6));
+        auto duplicateCoordinate                   = valid;
+        duplicateCoordinate.members.at(1).tileHLoc = 0;
+        CHECK(!CGroupDefinition::create(duplicateCoordinate, device, 7));
+        auto badGeometry            = valid;
+        badGeometry.members.at(1).x = 99;
+        CHECK(!CGroupDefinition::create(badGeometry, device, 8));
+        auto badPrimary             = valid;
+        badPrimary.primaryConnector = 2;
+        CHECK(!CGroupDefinition::create(badPrimary, device, 9));
+        auto wrongDevice         = valid;
+        wrongDevice.key.deviceId = device->deviceId + 1;
+        CHECK(!CGroupDefinition::create(wrongDevice, device, 10));
+        CHECK(!CGroupDefinition::create(valid, device, 0));
+    }
+
+    void testGroupGreedyTrapAndPreferences() {
+        SObjectPool          pool({1, 2}, {10, 11}, {100, 101});
+        const SCompatibility compatibility = {
+            .connectors = {{10, 11}, {10}},
+            .planes     = {{10, 11}, {10}},
+        };
+
+        for (uint32_t permutationBits = 0; permutationBits < 32; ++permutationBits) {
+            auto connectorOrder = naturalOrder(2);
+            auto crtcOrder      = naturalOrder(2);
+            auto planeOrder     = naturalOrder(2);
+            if ((permutationBits & 1U) != 0)
+                std::ranges::reverse(connectorOrder);
+            if ((permutationBits & 2U) != 0)
+                std::ranges::reverse(crtcOrder);
+            if ((permutationBits & 4U) != 0)
+                std::ranges::reverse(planeOrder);
+
+            const auto snapshot = makeSnapshot(pool, compatibility, connectorOrder, crtcOrder, planeOrder);
+            auto       request  = oneGroupRequest(snapshot, 50, {1, 2}, (permutationBits & 8U) != 0, (permutationBits & 16U) != 0);
+            const auto plan     = solve(snapshot, request);
+            CHECK(plan->status() == ePlanStatus::READY);
+            CHECK(plan->groups().size() == 1);
+            CHECK(plan->groups().front().status() == eGroupStatus::ALLOCATED);
+            CHECK(plan->groups().front().bindings().size() == 2);
+            const auto a = bindingFor(plan->groups().front().bindings(), 1);
+            const auto b = bindingFor(plan->groups().front().bindings(), 2);
+            CHECK(a && a->crtc()->id == 11 && a->primaryPlane()->id == 100);
+            CHECK(b && b->crtc()->id == 10 && b->primaryPlane()->id == 101);
+            CHECK(a && a->definition().impl_ == plan->groups().front().definition().impl_);
+        }
+
+        SObjectPool preferencePool({1, 2}, {10, 11, 12}, {100, 101, 102});
+        const auto  snapshot = makeSnapshot(preferencePool, {.connectors = {{10, 11}, {12}}, .planes = {{10, 11}, {10}, {12}}});
+        auto        request  = oneGroupRequest(snapshot, 51, {1, 2});
+        request.connectorPreferences.push_back({.connector = connectorHandle(snapshot, 1), .crtc = crtcHandle(snapshot, 11)});
+        request.planePreferences.push_back({.crtc = crtcHandle(snapshot, 11), .plane = planeHandle(snapshot, 101)});
+        const auto plan    = solve(snapshot, request);
+        const auto binding = bindingFor(plan->groups().front().bindings(), 1);
+        CHECK(binding && binding->crtc()->id == 11 && binding->primaryPlane()->id == 100);
+    }
+
+    void testGlobalGroupLookahead() {
+        SObjectPool          pool({1, 2, 3, 4}, {10, 11, 12, 13}, {100, 101, 102, 103});
+        const SCompatibility compatibility = {
+            .connectors = {{10, 12}, {11, 13}, {10}, {11}},
+            .planes     = {{10}, {11}, {12}, {13}},
+        };
+
+        for (uint32_t permutationBits = 0; permutationBits < 32; ++permutationBits) {
+            auto connectorOrder = naturalOrder(4);
+            auto crtcOrder      = naturalOrder(4);
+            auto planeOrder     = naturalOrder(4);
+            if ((permutationBits & 1U) != 0)
+                std::ranges::reverse(connectorOrder);
+            if ((permutationBits & 2U) != 0)
+                std::ranges::reverse(crtcOrder);
+            if ((permutationBits & 4U) != 0)
+                std::ranges::reverse(planeOrder);
+            const auto snapshot = makeSnapshot(pool, compatibility, connectorOrder, crtcOrder, planeOrder);
+            const auto group10  = makeDefinition(snapshot, 10, {1, 2}, (permutationBits & 8U) != 0);
+            const auto group20  = makeDefinition(snapshot, 20, {3, 4}, (permutationBits & 16U) != 0);
+            auto       request  = requestFor(snapshot, {group20, group10});
+            request.groups      = {groupRequest(snapshot, group20, true), groupRequest(snapshot, group10, true)};
+            if ((permutationBits & 16U) != 0)
+                std::ranges::reverse(request.groups);
+
+            const auto plan = solve(snapshot, request);
+            const auto low  = allocationFor(plan, 10);
+            const auto high = allocationFor(plan, 20);
+            CHECK(plan->status() == ePlanStatus::READY);
+            CHECK(low && low->status() == eGroupStatus::ALLOCATED);
+            CHECK(high && high->status() == eGroupStatus::ALLOCATED);
+            const auto lowA = low ? bindingFor(low->bindings(), 1) : nullptr;
+            const auto lowB = low ? bindingFor(low->bindings(), 2) : nullptr;
+            CHECK(lowA && lowA->crtc()->id == 12 && lowA->primaryPlane()->id == 102);
+            CHECK(lowB && lowB->crtc()->id == 13 && lowB->primaryPlane()->id == 103);
+            const auto highA = high ? bindingFor(high->bindings(), 3) : nullptr;
+            const auto highB = high ? bindingFor(high->bindings(), 4) : nullptr;
+            CHECK(highA && highA->crtc()->id == 10 && highA->primaryPlane()->id == 100);
+            CHECK(highB && highB->crtc()->id == 11 && highB->primaryPlane()->id == 101);
+        }
+
+        // Status priority is lexicographic, not maximum group count.
+        SObjectPool priorityPool({1, 2, 3, 4}, {10, 11}, {100, 101});
+        const auto  snapshot = makeSnapshot(priorityPool, {.connectors = {{10, 11}, {10, 11}, {10, 11}, {10, 11}}, .planes = {{10, 11}, {10, 11}}});
+        const auto  group10  = makeDefinition(snapshot, 10, {1, 2});
+        const auto  group20  = makeDefinition(snapshot, 20, {3, 4});
+        auto        request  = requestFor(snapshot, {group20, group10});
+        request.groups       = {groupRequest(snapshot, group20), groupRequest(snapshot, group10)};
+        const auto plan      = solve(snapshot, request);
+        CHECK(allocationFor(plan, 10)->status() == eGroupStatus::ALLOCATED);
+        CHECK(allocationFor(plan, 20)->status() == eGroupStatus::NO_MATCH);
+        CHECK(allocationFor(plan, 20)->bindings().empty());
+    }
+
+    void testCrossTierGlobalLookahead() {
+        // Group routes remain unfrozen until explicit enabled demand has
+        // reached its exact optimum.
+        SObjectPool          groupPool({1, 2, 3}, {10, 11, 12}, {100, 101, 102});
+        const SCompatibility groupCompatibility = {
+            .connectors = {{10, 12}, {11}, {10}},
+            .planes     = {{10}, {11}, {12}},
+        };
+        for (uint32_t permutationBits = 0; permutationBits < 32; ++permutationBits) {
+            auto connectorOrder = naturalOrder(3);
+            auto crtcOrder      = naturalOrder(3);
+            auto planeOrder     = naturalOrder(3);
+            if ((permutationBits & 1U) != 0)
+                std::ranges::reverse(connectorOrder);
+            if ((permutationBits & 2U) != 0)
+                std::ranges::reverse(crtcOrder);
+            if ((permutationBits & 4U) != 0)
+                std::ranges::reverse(planeOrder);
+            const auto snapshot   = makeSnapshot(groupPool, groupCompatibility, connectorOrder, crtcOrder, planeOrder);
+            const auto definition = makeDefinition(snapshot, 80, {1, 2}, (permutationBits & 8U) != 0);
+            auto       request    = requestFor(snapshot, {definition});
+            request.groups.push_back(groupRequest(snapshot, definition, (permutationBits & 16U) != 0));
+            request.ordinary.push_back({.connector = connectorHandle(snapshot, 3), .priority = eOrdinaryPriority::ENABLED_UNMATCHED});
+            const auto plan = solve(snapshot, request);
+            CHECK(plan->status() == ePlanStatus::READY);
+            CHECK(plan->groups().front().status() == eGroupStatus::ALLOCATED);
+            CHECK(bindingFor(plan->groups().front().bindings(), 1)->crtc()->id == 12);
+            CHECK(bindingFor(plan->groups().front().bindings(), 2)->crtc()->id == 11);
+            CHECK(bindingFor(plan->ordinaryBindings(), 3)->crtc()->id == 10);
+        }
+
+        // Enabled routes remain unfrozen until the disabled-backup cardinality
+        // and preference tier has been optimized.
+        SObjectPool          tierPool({1, 2}, {10, 11}, {100, 101});
+        const SCompatibility tierCompatibility = {
+            .connectors = {{10, 11}, {10}},
+            .planes     = {{10, 11}, {10}},
+        };
+        for (uint32_t permutationBits = 0; permutationBits < 16; ++permutationBits) {
+            auto connectorOrder = naturalOrder(2);
+            auto crtcOrder      = naturalOrder(2);
+            auto planeOrder     = naturalOrder(2);
+            if ((permutationBits & 1U) != 0)
+                std::ranges::reverse(connectorOrder);
+            if ((permutationBits & 2U) != 0)
+                std::ranges::reverse(crtcOrder);
+            if ((permutationBits & 4U) != 0)
+                std::ranges::reverse(planeOrder);
+            const auto snapshot = makeSnapshot(tierPool, tierCompatibility, connectorOrder, crtcOrder, planeOrder);
+            auto       request  = requestFor(snapshot);
+            request.ordinary    = {
+                {.connector = connectorHandle(snapshot, 1), .priority = eOrdinaryPriority::ENABLED_UNMATCHED},
+                {.connector = connectorHandle(snapshot, 2), .priority = eOrdinaryPriority::DETACHED_DISABLED_BACKUP},
+            };
+            if ((permutationBits & 8U) != 0)
+                std::ranges::reverse(request.ordinary);
+            const auto plan = solve(snapshot, request);
+            CHECK(plan->status() == ePlanStatus::READY);
+            CHECK(bindingFor(plan->ordinaryBindings(), 1)->crtc()->id == 11);
+            CHECK(bindingFor(plan->ordinaryBindings(), 2)->crtc()->id == 10);
+        }
+
+        // Plane-change costs keep the source tier even after both classes
+        // contend for the same CRTC-to-plane graph.
+        SObjectPool planePool({1, 2}, {10, 11}, {100, 101});
+        const auto  planeSnapshot = makeSnapshot(planePool, {.connectors = {{11}, {10}}, .planes = {{10, 11}, {10, 11}}});
+        auto        planeRequest  = requestFor(planeSnapshot);
+        planeRequest.ordinary     = {
+            {.connector = connectorHandle(planeSnapshot, 1), .priority = eOrdinaryPriority::ENABLED_UNMATCHED},
+            {.connector = connectorHandle(planeSnapshot, 2), .priority = eOrdinaryPriority::DETACHED_DISABLED_BACKUP},
+        };
+        planeRequest.planePreferences = {
+            {.crtc = crtcHandle(planeSnapshot, 10), .plane = planeHandle(planeSnapshot, 100)},
+            {.crtc = crtcHandle(planeSnapshot, 11), .plane = planeHandle(planeSnapshot, 100)},
+        };
+        const auto planePlan = solve(planeSnapshot, planeRequest);
+        CHECK(bindingFor(planePlan->ordinaryBindings(), 1)->primaryPlane()->id == 100);
+        CHECK(bindingFor(planePlan->ordinaryBindings(), 2)->primaryPlane()->id == 101);
+
+        // A complete group cannot worsen the already-optimal enabled
+        // preference tuple merely to gain aggregate status.
+        SObjectPool preferencePool({1, 2, 3}, {10, 11}, {100, 101});
+        const auto  preferenceSnapshot = makeSnapshot(preferencePool, {.connectors = {{10}, {11}, {10}}, .planes = {{10}, {11}}});
+        const auto  preferenceGroup    = makeDefinition(preferenceSnapshot, 81, {1, 2});
+        auto        preferenceRequest  = requestFor(preferenceSnapshot, {preferenceGroup});
+        preferenceRequest.groups.push_back(groupRequest(preferenceSnapshot, preferenceGroup));
+        preferenceRequest.ordinary.push_back({.connector = connectorHandle(preferenceSnapshot, 3)});
+        preferenceRequest.connectorPreferences.push_back({.connector = connectorHandle(preferenceSnapshot, 3), .crtc = crtcHandle(preferenceSnapshot, 10)});
+        const auto preferencePlan = solve(preferenceSnapshot, preferenceRequest);
+        CHECK(preferencePlan->groups().front().status() == eGroupStatus::NO_MATCH);
+        CHECK(bindingFor(preferencePlan->ordinaryBindings(), 1) == nullptr);
+        CHECK(bindingFor(preferencePlan->ordinaryBindings(), 2) != nullptr);
+        CHECK(bindingFor(preferencePlan->ordinaryBindings(), 3) != nullptr);
+
+        // Once the enabled tuple ties, complete-group status precedes raw ID
+        // canonicalization.
+        SObjectPool statusPool({1, 2, 3}, {10, 11}, {100, 101});
+        const auto  statusSnapshot = makeSnapshot(statusPool, {.connectors = {{10, 11}, {10}, {11}}, .planes = {{10}, {11}}});
+        const auto  statusGroup    = makeDefinition(statusSnapshot, 82, {1, 2});
+        auto        statusRequest  = requestFor(statusSnapshot, {statusGroup});
+        statusRequest.groups.push_back(groupRequest(statusSnapshot, statusGroup));
+        statusRequest.ordinary.push_back({.connector = connectorHandle(statusSnapshot, 3)});
+        const auto statusPlan = solve(statusSnapshot, statusRequest);
+        CHECK(statusPlan->groups().front().status() == eGroupStatus::ALLOCATED);
+        CHECK(bindingFor(statusPlan->groups().front().bindings(), 1)->crtc()->id == 11);
+        CHECK(bindingFor(statusPlan->groups().front().bindings(), 2)->crtc()->id == 10);
+        CHECK(statusPlan->ordinaryBindings().empty());
+
+        // Once this group is fixed NO_MATCH, its members join the enabled
+        // fallback connector-ID order. They must not retain group/member
+        // priority over the lower-ID explicit ordinary connector.
+        SObjectPool          fallbackPool({100, 101, 1}, {10}, {1000});
+        const SCompatibility fallbackCompatibility = {
+            .connectors = {{10}, {10}, {10}},
+            .planes     = {{10}},
+        };
+        const SCombinedOracleInput fallbackOracleInput = {
+            .candidates =
+                {
+                    {
+                        .connectorID   = 100,
+                        .connectorMask = 1,
+                        .active        = true,
+                        .groupOrder    = 0,
+                        .preferredCRTC = std::nullopt,
+                    },
+                    {
+                        .connectorID   = 101,
+                        .connectorMask = 1,
+                        .active        = true,
+                        .groupOrder    = 0,
+                        .preferredCRTC = std::nullopt,
+                    },
+                    {
+                        .connectorID   = 1,
+                        .connectorMask = 1,
+                        .active        = true,
+                        .groupOrder    = std::nullopt,
+                        .preferredCRTC = std::nullopt,
+                    },
+                },
+            .planeMasks      = {1},
+            .crtcIDs         = {10},
+            .planeIDs        = {1000},
+            .preferredPlanes = {std::nullopt},
+            .groupCount      = 1,
+        };
+        const auto fallbackReference = bruteForceCombined(fallbackOracleInput);
+        CHECK(fallbackReference.groupStatus == std::vector<uint8_t>({1}));
+        CHECK(fallbackReference.bindings == COrdinaryBindings({{1, 10, 1000}}));
+        for (uint32_t permutationBits = 0; permutationBits < 8; ++permutationBits) {
+            auto connectorOrder = naturalOrder(3);
+            if ((permutationBits & 1U) != 0)
+                std::ranges::reverse(connectorOrder);
+            const auto fallbackSnapshot = makeSnapshot(fallbackPool, fallbackCompatibility, connectorOrder);
+            const auto fallbackGroup    = makeDefinition(fallbackSnapshot, 83, {100, 101}, (permutationBits & 2U) != 0);
+            auto       fallbackRequest  = requestFor(fallbackSnapshot, {fallbackGroup});
+            fallbackRequest.groups.push_back(groupRequest(fallbackSnapshot, fallbackGroup, (permutationBits & 4U) != 0));
+            fallbackRequest.ordinary.push_back({.connector = connectorHandle(fallbackSnapshot, 1), .priority = eOrdinaryPriority::ENABLED_UNMATCHED});
+            const auto fallbackPlan = solve(fallbackSnapshot, fallbackRequest);
+            CHECK(fallbackPlan->status() == ePlanStatus::READY);
+            CHECK(fallbackPlan->groups().front().status() == eGroupStatus::NO_MATCH);
+            CHECK(fallbackPlan->groups().front().bindings().empty());
+            CHECK(planBindings(fallbackPlan) == fallbackReference.bindings);
+            CHECK(fallbackPlan->unallocatedOrdinaryConnectorIDs() == std::vector<uint32_t>({100, 101}));
+        }
+    }
+
+    void testRetainedGroupsAndContention() {
+        SObjectPool pool({1, 2, 3, 4, 5, 6}, {10, 11, 12, 13, 14}, {100, 101, 102, 103, 104});
+        const auto  snapshot = makeSnapshot(pool,
+                                            {
+                                                .connectors = {{10, 12}, {11, 13}, {10}, {11}, {14}, {14}},
+                                                .planes     = {{10}, {11}, {12}, {13}, {14}},
+                                            });
+        const auto  group10  = makeDefinition(snapshot, 10, {1, 2});
+        const auto  group20  = makeDefinition(snapshot, 20, {3, 4});
+        auto        request  = requestFor(snapshot, {group10, group20});
+        auto        retained = groupRequest(snapshot, group20);
+        retained.retained    = std::vector<SRetainedGroupBinding>{retainedBinding(snapshot, 3, 10, 100), retainedBinding(snapshot, 4, 11, 101)};
+        request.groups       = {groupRequest(snapshot, group10), retained};
+        request.ordinary     = {
+            {.connector = connectorHandle(snapshot, 5), .priority = eOrdinaryPriority::ENABLED_UNMATCHED},
+            {.connector = connectorHandle(snapshot, 6), .priority = eOrdinaryPriority::DETACHED_DISABLED_BACKUP},
+        };
+        const auto plan = solve(snapshot, request);
+        CHECK(plan->status() == ePlanStatus::READY);
+        CHECK(allocationFor(plan, 20)->status() == eGroupStatus::ALLOCATED);
+        CHECK(bindingFor(allocationFor(plan, 20)->bindings(), 3)->crtc()->id == 10);
+        CHECK(bindingFor(allocationFor(plan, 10)->bindings(), 1)->crtc()->id == 12);
+        CHECK(bindingFor(allocationFor(plan, 10)->bindings(), 2)->crtc()->id == 13);
+        CHECK(plan->ordinaryBindings().size() == 1);
+        CHECK(plan->ordinaryBindings().front().connector()->id == 5);
+        CHECK(plan->unallocatedOrdinaryConnectorIDs() == std::vector<uint32_t>({6}));
+
+        // Conflicting retained claims fail the whole request without partials.
+        auto conflict                  = request;
+        conflict.groups.at(0).retained = std::vector<SRetainedGroupBinding>{retainedBinding(snapshot, 1, 10, 100), retainedBinding(snapshot, 2, 12, 102)};
+        const auto conflictPlan        = solve(snapshot, conflict);
+        CHECK(conflictPlan->status() == ePlanStatus::INVALID);
+        CHECK(bindingCount(conflictPlan) == 0);
+        CHECK(conflictPlan->groups().empty());
+
+        // A disabled/quiesced retained group is still retained; ordinary state
+        // is explicit and cannot displace it.
+        SObjectPool disabledPool({1, 2, 3}, {10, 11}, {100, 101});
+        const auto  disabledSnapshot = makeSnapshot(disabledPool, {.connectors = {{10}, {11}, {10}}, .planes = {{10}, {11}}});
+        const auto  disabledGroup    = makeDefinition(disabledSnapshot, 30, {1, 2});
+        auto        disabledRequest  = requestFor(disabledSnapshot, {disabledGroup});
+        auto        disabledRetained = groupRequest(disabledSnapshot, disabledGroup);
+        disabledRetained.retained    = std::vector<SRetainedGroupBinding>{retainedBinding(disabledSnapshot, 1, 10, 100), retainedBinding(disabledSnapshot, 2, 11, 101)};
+        disabledRequest.groups.push_back(std::move(disabledRetained));
+        disabledRequest.ordinary.push_back({.connector = connectorHandle(disabledSnapshot, 3), .priority = eOrdinaryPriority::DETACHED_DISABLED_BACKUP});
+        const auto disabledPlan = solve(disabledSnapshot, disabledRequest);
+        CHECK(disabledPlan->groups().front().status() == eGroupStatus::ALLOCATED);
+        CHECK(disabledPlan->groups().front().bindings().size() == 2);
+        CHECK(disabledPlan->ordinaryBindings().empty());
+    }
+
+    void testOrdinaryJointBatchesAndPreferences() {
+        SObjectPool          pool({1, 2}, {10, 11}, {100, 101});
+        const SCompatibility compatibility = {
+            .connectors = {{10, 11}, {10}},
+            .planes     = {{10, 11}, {10}},
+        };
+        for (uint32_t permutationBits = 0; permutationBits < 16; ++permutationBits) {
+            auto connectorOrder = naturalOrder(2);
+            auto crtcOrder      = naturalOrder(2);
+            auto planeOrder     = naturalOrder(2);
+            if ((permutationBits & 1U) != 0)
+                std::ranges::reverse(connectorOrder);
+            if ((permutationBits & 2U) != 0)
+                std::ranges::reverse(crtcOrder);
+            if ((permutationBits & 4U) != 0)
+                std::ranges::reverse(planeOrder);
+            const auto snapshot = makeSnapshot(pool, compatibility, connectorOrder, crtcOrder, planeOrder);
+            auto       request  = requestFor(snapshot);
+            request.ordinary    = {{.connector = connectorHandle(snapshot, 1)}, {.connector = connectorHandle(snapshot, 2)}};
+            if ((permutationBits & 8U) != 0)
+                std::ranges::reverse(request.ordinary);
+            const auto plan = solve(snapshot, request);
+            const auto a    = bindingFor(plan->ordinaryBindings(), 1);
+            const auto b    = bindingFor(plan->ordinaryBindings(), 2);
+            CHECK(plan->ordinaryBindings().size() == 2);
+            CHECK(a && a->crtc()->id == 11 && a->primaryPlane()->id == 100);
+            CHECK(b && b->crtc()->id == 10 && b->primaryPlane()->id == 101);
+        }
+
+        SObjectPool priorityPool({1, 2}, {10}, {100});
+        const auto  prioritySnapshot = makeSnapshot(priorityPool, {.connectors = {{10}, {10}}, .planes = {{10}}});
+        auto        priorityRequest  = requestFor(prioritySnapshot);
+        priorityRequest.ordinary     = {
+            {.connector = connectorHandle(prioritySnapshot, 1), .priority = eOrdinaryPriority::DETACHED_DISABLED_BACKUP},
+            {.connector = connectorHandle(prioritySnapshot, 2), .priority = eOrdinaryPriority::ENABLED_UNMATCHED},
+        };
+        const auto priorityPlan = solve(prioritySnapshot, priorityRequest);
+        CHECK(priorityPlan->ordinaryBindings().size() == 1);
+        CHECK(priorityPlan->ordinaryBindings().front().connector()->id == 2);
+
+        // At equal cardinality, moving a preferred connector is better than
+        // dropping it in favor of a no-preference newcomer.
+        SObjectPool dropPool({1, 2}, {10, 11}, {100, 101});
+        const auto  dropSnapshot = makeSnapshot(dropPool, {.connectors = {{10, 11}, {10}}, .planes = {{10}, {11}}});
+        auto        dropRequest  = requestFor(dropSnapshot);
+        SHardHold   dropHold;
+        dropHold.crtc  = crtcHandle(dropSnapshot, 11);
+        dropHold.plane = planeHandle(dropSnapshot, 101);
+        dropRequest.hardHolds.push_back(std::move(dropHold));
+        dropRequest.ordinary = {{.connector = connectorHandle(dropSnapshot, 2)}, {.connector = connectorHandle(dropSnapshot, 1)}};
+        dropRequest.connectorPreferences.push_back({.connector = connectorHandle(dropSnapshot, 1), .crtc = crtcHandle(dropSnapshot, 11)});
+        const auto dropPlan = solve(dropSnapshot, dropRequest);
+        CHECK(dropPlan->ordinaryBindings().size() == 1);
+        CHECK(dropPlan->ordinaryBindings().front().connector()->id == 1);
+        CHECK(dropPlan->ordinaryBindings().front().crtc()->id == 10);
+
+        // The same joint matching and canonical objective applies inside the
+        // detached-disabled tier, not only to enabled outputs.
+        for (uint32_t permutationBits = 0; permutationBits < 16; ++permutationBits) {
+            auto connectorOrder = naturalOrder(2);
+            auto crtcOrder      = naturalOrder(2);
+            auto planeOrder     = naturalOrder(2);
+            if ((permutationBits & 1U) != 0)
+                std::ranges::reverse(connectorOrder);
+            if ((permutationBits & 2U) != 0)
+                std::ranges::reverse(crtcOrder);
+            if ((permutationBits & 4U) != 0)
+                std::ranges::reverse(planeOrder);
+            const auto backupSnapshot = makeSnapshot(pool, compatibility, connectorOrder, crtcOrder, planeOrder);
+            auto       backupRequest  = requestFor(backupSnapshot);
+            backupRequest.ordinary    = {
+                {.connector = connectorHandle(backupSnapshot, 1), .priority = eOrdinaryPriority::DETACHED_DISABLED_BACKUP},
+                {.connector = connectorHandle(backupSnapshot, 2), .priority = eOrdinaryPriority::DETACHED_DISABLED_BACKUP},
+            };
+            if ((permutationBits & 8U) != 0)
+                std::ranges::reverse(backupRequest.ordinary);
+            const auto backupPlan = solve(backupSnapshot, backupRequest);
+            CHECK(bindingFor(backupPlan->ordinaryBindings(), 1)->crtc()->id == 11);
+            CHECK(bindingFor(backupPlan->ordinaryBindings(), 2)->crtc()->id == 10);
+        }
+    }
+
+    void testHoldsHallAndZeroMutation() {
+        SObjectPool pool({1, 2, 3}, {10, 11}, {100, 101});
+        const auto  snapshot = makeSnapshot(pool, {.connectors = {{10}, {10}, {11}}, .planes = {{10}, {11}}});
+        auto        request  = oneGroupRequest(snapshot, 40, {1, 2});
+        request.hardHolds.push_back({
+            .reason    = eHardHoldReason::LEASED,
+            .connector = connectorHandle(snapshot, 3),
+            .crtc      = crtcHandle(snapshot, 11),
+            .plane     = planeHandle(snapshot, 101),
+        });
+        const auto plan = solve(snapshot, request);
+        CHECK(plan->status() == ePlanStatus::READY);
+        CHECK(plan->groups().front().status() == eGroupStatus::NO_MATCH);
+        CHECK(plan->groups().front().bindings().empty());
+        CHECK(plan->ordinaryBindings().size() == 1);
+        CHECK(fakeGroupMutations(plan, currentState(plan)) == 0);
+
+        auto invalidHold                     = request;
+        invalidHold.hardHolds.front().reason = static_cast<eHardHoldReason>(255);
+        CHECK(solve(snapshot, invalidHold)->status() == ePlanStatus::INVALID);
+        auto emptyHold = requestFor(snapshot);
+        emptyHold.hardHolds.emplace_back();
+        CHECK(solve(snapshot, emptyHold)->status() == ePlanStatus::INVALID);
+    }
+
+    void testComplexityBudget() {
+        const auto solveDenseTwoBackup = [](size_t resourceCount) {
+            std::vector<uint32_t> crtcIDs(resourceCount);
+            std::vector<uint32_t> planeIDs(resourceCount);
+            std::ranges::iota(crtcIDs, 10);
+            std::ranges::iota(planeIDs, 100);
+            SObjectPool pool({1, 2}, crtcIDs, planeIDs);
+            const auto  snapshot = makeSnapshot(pool,
+                                                {
+                                                    .connectors = {crtcIDs, crtcIDs},
+                                                    .planes     = std::vector<std::vector<uint32_t>>(resourceCount, crtcIDs),
+                                                });
+            auto        request  = requestFor(snapshot);
+            request.ordinary     = {
+                {.connector = connectorHandle(snapshot, 1), .priority = eOrdinaryPriority::DETACHED_DISABLED_BACKUP},
+                {.connector = connectorHandle(snapshot, 2), .priority = eOrdinaryPriority::DETACHED_DISABLED_BACKUP},
+            };
+            return solve(snapshot, request);
+        };
+
+        const auto justUnder = solveDenseTwoBackup(7);
+        CHECK(justUnder->status() == ePlanStatus::READY);
+        CHECK(justUnder->ordinaryBindings().size() == 2);
+        const auto justOver = solveDenseTwoBackup(8);
+        CHECK(justOver->status() == ePlanStatus::UNSUPPORTED_COMPLEXITY);
+        CHECK(bindingCount(justOver) == 0);
+
+        // The maximum admitted dense active+backup topology is also bounded
+        // and returns no partially reconstructed plan.
+        std::vector<uint32_t> connectorIDs(64);
+        std::vector<uint32_t> crtcIDs(32);
+        std::vector<uint32_t> planeIDs(32);
+        std::ranges::iota(connectorIDs, 1);
+        std::ranges::iota(crtcIDs, 10);
+        std::ranges::iota(planeIDs, 100);
+        SObjectPool    pool(connectorIDs, crtcIDs, planeIDs);
+        SCompatibility compatibility;
+        compatibility.connectors.assign(connectorIDs.size(), crtcIDs);
+        compatibility.planes.assign(planeIDs.size(), crtcIDs);
+        const auto snapshot = makeSnapshot(pool, compatibility);
+        auto       request  = requestFor(snapshot);
+        for (size_t index = 0; index < connectorIDs.size(); ++index) {
+            request.ordinary.push_back({
+                .connector = connectorHandle(snapshot, connectorIDs.at(index)),
+                .priority  = index < crtcIDs.size() ? eOrdinaryPriority::ENABLED_UNMATCHED : eOrdinaryPriority::DETACHED_DISABLED_BACKUP,
+            });
+        }
+        const auto plan = solve(snapshot, request);
+        CHECK(plan->status() == ePlanStatus::UNSUPPORTED_COMPLEXITY);
+        CHECK(bindingCount(plan) == 0);
+        CHECK(plan->groups().empty());
+        CHECK(plan->ordinaryBindings().empty());
+        size_t callbacks = 0;
+        CHECK(!withCurrentPlan(plan, currentState(plan), [&](const CPlan&) { ++callbacks; }));
+        CHECK(callbacks == 0);
+    }
+
+    void testBackendLifetimeBoundary() {
+        const auto  lifetime = makeBackendLifetime(7001);
+        const auto  device   = makeDevice(902, 11, 31, 91, lifetime);
+        SObjectPool pool({1, 2}, {10, 11}, {100, 101});
+        const auto  snapshot = makeSnapshot(pool, {.connectors = {{10}, {11}}, .planes = {{10}, {11}}}, {}, {}, {}, device);
+        auto        request  = oneGroupRequest(snapshot, 70, {1, 2});
+        const auto  ready    = solve(snapshot, request);
+        CHECK(ready->status() == ePlanStatus::READY);
+
+        const auto wrongLifetime       = makeBackendLifetime(7002);
+        request.currentBackendLifetime = wrongLifetime;
+        const auto wrongPlan           = solve(snapshot, request);
+        CHECK(wrongPlan->status() == ePlanStatus::INVALID);
+        CHECK(bindingCount(wrongPlan) == 0);
+
+        auto wrongObservation             = makeShared<SObservationIncarnation>(*snapshot->observation());
+        wrongObservation->backendLifetime = wrongLifetime;
+        CHECK(!CSnapshot::create(snapshot->generation(), asConst(std::move(wrongObservation)), {}, {}, {}));
+
+        auto productionDevice                  = makeShared<SDeviceIncarnation>(*device);
+        productionDevice->binding              = eBackendBinding::PRODUCTION_BACKEND;
+        const auto productionOwner             = asConst(std::move(productionDevice));
+        auto       productionObservation       = makeShared<SObservationIncarnation>();
+        productionObservation->generation      = snapshot->generation();
+        productionObservation->serial          = snapshot->observation()->serial;
+        productionObservation->device          = productionOwner;
+        productionObservation->backendLifetime = productionOwner->backendLifetime;
+        // A production-bound capture can never use an empty/expired actual DRM
+        // backend, even though the generic lifetime token is live.
+        CHECK(!CSnapshot::create(snapshot->generation(), asConst(std::move(productionObservation)), {}, {}, {}));
+
+        request.currentBackendLifetime.reset();
+        auto expiringLifetime = lifetime;
+        expiringLifetime.reset();
+        // The original const owner is still live until this scope ends, so make
+        // a separate snapshot whose token can actually expire.
+        auto       shortLifetime = makeBackendLifetime(7003);
+        const auto shortDevice   = makeDevice(903, 12, 32, 92, shortLifetime);
+        const auto shortSnapshot = makeSnapshot(pool, {.connectors = {{10}, {11}}, .planes = {{10}, {11}}}, {}, {}, {}, shortDevice);
+        auto       shortRequest  = oneGroupRequest(shortSnapshot, 71, {1, 2});
+        const auto shortReady    = solve(shortSnapshot, shortRequest);
+        CHECK(shortReady->status() == ePlanStatus::READY);
+        shortRequest.currentBackendLifetime.reset();
+        shortLifetime.reset();
+        CHECK(!shortDevice->backendLifetime.valid());
+        CHECK(Aquamarine::NDRM::NTiledCrtcAllocator::solve(shortReady->observation())->status() == ePlanStatus::STALE);
+        auto staleCurrent            = currentState(shortReady);
+        staleCurrent.backendLifetime = {};
+        CHECK(!withCurrentPlan(shortReady, staleCurrent, [](const CPlan&) {}));
+    }
+
+    void testStaleIdentityAndCurrentness() {
+        SObjectPool pool({1, 2}, {10, 11}, {100, 101});
+        const auto  snapshot = makeSnapshot(pool, {.connectors = {{10}, {11}}, .planes = {{10}, {11}}});
+        auto        request  = oneGroupRequest(snapshot, 50, {1, 2});
+
+        auto        twinConnectors             = snapshot->connectors();
+        twinConnectors.front().possibleCRTCIDs = {10, 11};
+        const auto twin = CSnapshot::create(snapshot->generation(), snapshot->observation(), std::move(twinConnectors), snapshot->crtcs(), snapshot->primaryPlanes());
+        CHECK(static_cast<bool>(twin));
+
+        const auto originalDefinition = request.groups.front().definition;
+        const auto clonedDefinition   = CGroupDefinition::create(originalDefinition->group(), snapshot->device(), originalDefinition->serial());
+        CHECK(static_cast<bool>(clonedDefinition));
+        auto cloneRequest                      = request;
+        cloneRequest.groups.front().definition = clonedDefinition;
+        const auto clonePlan                   = solve(snapshot, cloneRequest);
+        CHECK(clonePlan->status() == ePlanStatus::STALE);
+        CHECK(bindingCount(clonePlan) == 0);
+
+        auto badProjection = request;
+        badProjection.groups.front().connectors.pop_back();
+        CHECK(solve(snapshot, badProjection)->status() == ePlanStatus::INVALID);
+
+        auto missingDefinition = request;
+        missingDefinition.groups.clear();
+        CHECK(solve(snapshot, missingDefinition)->status() == ePlanStatus::INVALID);
+
+        auto clonedIncarnation                                    = makeShared<SResourceIncarnation>(*request.groups.front().connectors.front().incarnation);
+        auto staleHandle                                          = request;
+        staleHandle.groups.front().connectors.front().incarnation = asConst(std::move(clonedIncarnation));
+        CHECK(solve(snapshot, staleHandle)->status() == ePlanStatus::STALE);
+
+        const auto readyPlan    = solve(snapshot, request);
+        auto       freshCurrent = currentState(readyPlan);
+        size_t     callbacks    = 0;
+        CHECK(withCurrentPlan(readyPlan, freshCurrent, [&](const CPlan&) { ++callbacks; }));
+        CHECK(callbacks == 1);
+        auto twinCurrent     = freshCurrent;
+        twinCurrent.snapshot = twin;
+        CHECK(!withCurrentPlan(readyPlan, twinCurrent, [&](const CPlan&) { ++callbacks; }));
+        CHECK(fakeGroupMutations(readyPlan, twinCurrent) == 0);
+
+        auto replacementRequest                      = request;
+        replacementRequest.currentGroupDefinitions   = {clonedDefinition};
+        replacementRequest.groups.front().definition = clonedDefinition;
+        replacementRequest.epoch                     = request.epoch;
+        const auto replacementObservation            = observe(replacementRequest);
+        CHECK(static_cast<bool>(replacementObservation));
+        auto replacedCurrent        = freshCurrent;
+        replacedCurrent.observation = replacementObservation;
+        replacedCurrent.epoch       = replacementObservation->epoch();
+        CHECK(!withCurrentPlan(readyPlan, replacedCurrent, [&](const CPlan&) { ++callbacks; }));
+        CHECK(fakeGroupMutations(readyPlan, replacedCurrent) == 0);
+        CHECK(callbacks == 1);
+
+        // Same numeric IDs on another device owner cannot rehabilitate a group.
+        const auto otherDevice   = makeDevice(901, 10, 30, 90);
+        const auto otherSnapshot = makeSnapshot(pool, {.connectors = {{10}, {11}}, .planes = {{10}, {11}}}, {}, {}, {}, otherDevice);
+        auto       crossDevice   = requestFor(otherSnapshot, {originalDefinition});
+        crossDevice.groups.push_back(groupRequest(otherSnapshot, originalDefinition));
+        CHECK(solve(otherSnapshot, crossDevice)->status() == ePlanStatus::STALE);
+        CHECK(!CGroupDefinition::create(tileGroup(snapshot->device()->deviceId, 50, {1, 2}), otherDevice, 99));
+
+        // Observation-generation ABA with the same resource IDs stays stale.
+        const auto newerSnapshot   = makeSnapshot(pool, {.connectors = {{10}, {11}}, .planes = {{10}, {11}}}, {}, {}, {}, snapshot->device());
+        const auto newerDefinition = makeDefinition(newerSnapshot, 50, {1, 2});
+        auto       generationABA   = groupRequest(newerSnapshot, newerDefinition);
+        generationABA.connectors   = request.groups.front().connectors;
+        auto abaRequest            = requestFor(newerSnapshot, {newerDefinition});
+        abaRequest.groups          = {generationABA};
+        CHECK(solve(newerSnapshot, abaRequest)->status() == ePlanStatus::STALE);
+    }
+
+    void testAllocationObservationCurrentness() {
+        SObjectPool pool({1, 2, 3, 4, 5}, {10, 11, 12, 13, 14}, {100, 101, 102, 103, 104});
+        const auto  snapshot   = makeSnapshot(pool,
+                                              {
+                                                  .connectors = {{10}, {11}, {12}, {13}, {14}},
+                                                  .planes     = {{10}, {11}, {12}, {13}, {14}},
+                                              });
+        const auto  definition = makeDefinition(snapshot, 90, {1, 2});
+        auto        request    = requestFor(snapshot, {definition});
+        auto        retained   = groupRequest(snapshot, definition);
+        retained.retained      = std::vector<SRetainedGroupBinding>{retainedBinding(snapshot, 1, 10, 100), retainedBinding(snapshot, 2, 11, 101)};
+        request.groups.push_back(std::move(retained));
+        request.ordinary = {
+            {.connector = connectorHandle(snapshot, 3), .priority = eOrdinaryPriority::ENABLED_UNMATCHED},
+            {.connector = connectorHandle(snapshot, 4), .priority = eOrdinaryPriority::DETACHED_DISABLED_BACKUP},
+        };
+        const auto plan = solve(snapshot, request);
+        CHECK(plan->status() == ePlanStatus::READY);
+        const auto freshCurrent = currentState(plan);
+        size_t     callbacks    = 0;
+        CHECK(withCurrentPlan(plan, freshCurrent, [&](const CPlan&) { ++callbacks; }));
+        CHECK(callbacks == 1);
+        CHECK(!withCurrentPlan(plan, freshCurrent, std::function<void(const CPlan&)>{}));
+
+        const auto rejectsReplacement = [&](const SRequest& replacement) {
+            const auto replacementObservation = observe(replacement);
+            CHECK(static_cast<bool>(replacementObservation));
+            auto replacementCurrent        = freshCurrent;
+            replacementCurrent.observation = replacementObservation;
+            replacementCurrent.epoch       = replacementObservation->epoch();
+            CHECK(!withCurrentPlan(plan, replacementCurrent, [&](const CPlan&) { ++callbacks; }));
+        };
+
+        // Value equality is never enough: even an identical observation with
+        // the same epochs is stale when its owner differs.
+        rejectsReplacement(request);
+
+        const std::array holdReasons = {
+            eHardHoldReason::ACTIVE_OR_PENDING,
+            eHardHoldReason::RETIRING,
+            eHardHoldReason::LEASED,
+            eHardHoldReason::FOREIGN_KERNEL_ATTACHMENT,
+        };
+        for (const auto reason : holdReasons) {
+            auto replacement = request;
+            replacement.hardHolds.push_back({
+                .reason    = reason,
+                .connector = connectorHandle(snapshot, 5),
+                .crtc      = crtcHandle(snapshot, 14),
+                .plane     = planeHandle(snapshot, 104),
+            });
+            rejectsReplacement(replacement);
+        }
+
+        auto occupancyChanged = request;
+        occupancyChanged.hardHolds.push_back({
+            .reason    = eHardHoldReason::LEASED,
+            .connector = std::nullopt,
+            .crtc      = crtcHandle(snapshot, 13),
+            .plane     = planeHandle(snapshot, 103),
+        });
+        rejectsReplacement(occupancyChanged);
+
+        auto retentionLost = request;
+        retentionLost.groups.front().retained.reset();
+        rejectsReplacement(retentionLost);
+
+        auto priorityChanged                      = request;
+        priorityChanged.ordinary.front().priority = eOrdinaryPriority::DETACHED_DISABLED_BACKUP;
+        rejectsReplacement(priorityChanged);
+
+        auto connectorPreferenceChanged = request;
+        connectorPreferenceChanged.connectorPreferences.push_back({.connector = connectorHandle(snapshot, 3), .crtc = crtcHandle(snapshot, 12)});
+        rejectsReplacement(connectorPreferenceChanged);
+
+        auto planePreferenceChanged = request;
+        planePreferenceChanged.planePreferences.push_back({.crtc = crtcHandle(snapshot, 12), .plane = planeHandle(snapshot, 102)});
+        rejectsReplacement(planePreferenceChanged);
+
+        auto allocationEpochChanged = request;
+        ++allocationEpochChanged.epoch.allocation;
+        rejectsReplacement(allocationEpochChanged);
+
+        auto sessionChanged = freshCurrent;
+        ++sessionChanged.epoch.session;
+        CHECK(!withCurrentPlan(plan, sessionChanged, [&](const CPlan&) { ++callbacks; }));
+        auto eventEpochChanged = freshCurrent;
+        ++eventEpochChanged.epoch.eventThread;
+        CHECK(!withCurrentPlan(plan, eventEpochChanged, [&](const CPlan&) { ++callbacks; }));
+
+        std::atomic_size_t          wrongThreadCallbacks   = 0;
+        std::atomic_bool            readyGateAccepted      = true;
+        std::atomic_bool            workerPlanGateAccepted = true;
+        CSharedPointer<const CPlan> workerPlan;
+        std::thread                 wrongThread([&] {
+            readyGateAccepted      = withCurrentPlan(plan, freshCurrent, [&](const CPlan&) { ++wrongThreadCallbacks; });
+            workerPlan             = Aquamarine::NDRM::NTiledCrtcAllocator::solve(plan->observation());
+            workerPlanGateAccepted = withCurrentPlan(workerPlan, freshCurrent, [&](const CPlan&) { ++wrongThreadCallbacks; });
+        });
+        wrongThread.join();
+        CHECK(!readyGateAccepted.load());
+        CHECK(static_cast<bool>(workerPlan));
+        CHECK(workerPlan->status() == ePlanStatus::STALE);
+        CHECK(!workerPlan->snapshot());
+        CHECK(bindingCount(workerPlan) == 0);
+        CHECK(!workerPlanGateAccepted.load());
+        CHECK(wrongThreadCallbacks.load() == 0);
+        CHECK(callbacks == 1);
+    }
+
+    void testOwnerRetentionForBothStatuses() {
+        CWeakPointer<const CGroupDefinition> allocatedOwner;
+        CWeakPointer<const CGroupDefinition> unmatchedOwner;
+        CSharedPointer<const CPlan>          allocatedPlan;
+        CSharedPointer<const CPlan>          unmatchedPlan;
+        {
+            SObjectPool allocatedPool({1, 2}, {10, 11}, {100, 101});
+            const auto  snapshot = makeSnapshot(allocatedPool, {.connectors = {{10}, {11}}, .planes = {{10}, {11}}});
+            auto        request  = oneGroupRequest(snapshot, 60, {1, 2});
+            allocatedOwner       = request.groups.front().definition;
+            allocatedPlan        = solve(snapshot, request);
+        }
+        {
+            SObjectPool unmatchedPool({1, 2}, {10}, {100});
+            const auto  snapshot = makeSnapshot(unmatchedPool, {.connectors = {{10}, {10}}, .planes = {{10}}});
+            auto        request  = oneGroupRequest(snapshot, 61, {1, 2});
+            unmatchedOwner       = request.groups.front().definition;
+            unmatchedPlan        = solve(snapshot, request);
+        }
+        CHECK(allocatedPlan->groups().front().status() == eGroupStatus::ALLOCATED);
+        CHECK(unmatchedPlan->groups().front().status() == eGroupStatus::NO_MATCH);
+        CHECK(allocatedOwner.valid());
+        CHECK(unmatchedOwner.valid());
+        CHECK(allocatedPlan->groups().front().definition().impl_ == allocatedPlan->groups().front().bindings().front().definition().impl_);
+        allocatedPlan = {};
+        unmatchedPlan = {};
+        CHECK(!allocatedOwner.valid());
+        CHECK(!unmatchedOwner.valid());
+    }
+
+    void testExhaustiveCompatibility() {
+        uint64_t groupCases    = 0;
+        uint64_t ordinaryCases = 0;
+        uint64_t combinedCases = 0;
+        uint64_t tierCases     = 0;
+        for (size_t size = 1; size <= 3; ++size) {
+            std::vector<uint32_t> variableConnectorIDs(size);
+            std::vector<uint32_t> variableCRTCIDs(size);
+            std::vector<uint32_t> variablePlaneIDs(size);
+            for (size_t index = 0; index < size; ++index) {
+                variableConnectorIDs.at(index) = static_cast<uint32_t>(index + 1);
+                variableCRTCIDs.at(index)      = static_cast<uint32_t>(index + 10);
+                variablePlaneIDs.at(index)     = static_cast<uint32_t>(index + 100);
+            }
+
+            // The one-variable group gets a fixed independent companion, so
+            // every group oracle case is a genuine multi-member definition.
+            auto allConnectorIDs = variableConnectorIDs;
+            auto allCRTCIDs      = variableCRTCIDs;
+            auto allPlaneIDs     = variablePlaneIDs;
+            if (size == 1) {
+                allConnectorIDs.push_back(2);
+                allCRTCIDs.push_back(11);
+                allPlaneIDs.push_back(101);
+            }
+            SObjectPool    pool(allConnectorIDs, allCRTCIDs, allPlaneIDs);
+
+            const uint32_t choices             = (uint32_t{1} << size) - 1;
+            uint64_t       combinationsPerSide = 1;
+            for (size_t index = 0; index < size; ++index)
+                combinationsPerSide *= choices;
+
+            for (uint64_t connectorCode = 0; connectorCode < combinationsPerSide; ++connectorCode) {
+                std::vector<uint32_t> connectorMasks(size);
+                auto                  value = connectorCode;
+                for (size_t index = 0; index < size; ++index) {
+                    connectorMasks.at(index) = static_cast<uint32_t>(value % choices) + 1;
+                    value /= choices;
+                }
+                for (uint64_t planeCode = 0; planeCode < combinationsPerSide; ++planeCode) {
+                    std::vector<uint32_t> planeMasks(size);
+                    value = planeCode;
+                    for (size_t index = 0; index < size; ++index) {
+                        planeMasks.at(index) = static_cast<uint32_t>(value % choices) + 1;
+                        value /= choices;
+                    }
+
+                    SCompatibility compatibility;
+                    for (const auto mask : connectorMasks)
+                        compatibility.connectors.push_back(idsFromMask(mask, variableCRTCIDs));
+                    for (const auto mask : planeMasks)
+                        compatibility.planes.push_back(idsFromMask(mask, variableCRTCIDs));
+                    if (size == 1) {
+                        compatibility.connectors.push_back({11});
+                        compatibility.planes.push_back({11});
+                    }
+
+                    const auto snapshot  = makeSnapshot(pool, compatibility);
+                    const auto plan      = solve(snapshot, oneGroupRequest(snapshot, 1, allConnectorIDs));
+                    const auto reference = bruteForce(connectorMasks, planeMasks, variableCRTCIDs, variablePlaneIDs);
+                    ++groupCases;
+                    CHECK(plan->status() == ePlanStatus::READY);
+                    CHECK(plan->groups().size() == 1);
+                    CHECK((plan->groups().front().status() == eGroupStatus::ALLOCATED) == reference.has_value());
+                    if (!reference) {
+                        CHECK(plan->groups().front().bindings().empty());
+                    } else {
+                        CHECK(plan->groups().front().bindings().size() == allConnectorIDs.size());
+                        for (size_t member = 0; member < size; ++member) {
+                            const auto binding = bindingFor(plan->groups().front().bindings(), variableConnectorIDs.at(member));
+                            CHECK(binding != nullptr);
+                            if (binding)
+                                CHECK(std::pair(binding->crtc()->id, binding->primaryPlane()->id) == reference->at(member));
+                        }
+                    }
+
+                    auto ordinaryRequest = requestFor(snapshot);
+                    for (const auto connectorID : variableConnectorIDs)
+                        ordinaryRequest.ordinary.push_back({.connector = connectorHandle(snapshot, connectorID)});
+                    const auto        ordinaryPlan      = solve(snapshot, ordinaryRequest);
+                    const auto        ordinaryReference = bruteForceOrdinary(connectorMasks, planeMasks, variableConnectorIDs, variableCRTCIDs, variablePlaneIDs);
+                    COrdinaryBindings ordinaryActual;
+                    for (const auto& binding : ordinaryPlan->ordinaryBindings())
+                        ordinaryActual.emplace_back(binding.connector()->id, binding.crtc()->id, binding.primaryPlane()->id);
+                    ++ordinaryCases;
+                    CHECK(ordinaryPlan->status() == ePlanStatus::READY);
+                    CHECK(ordinaryActual == ordinaryReference);
+
+                    if (size == 3) {
+                        const auto combinedDefinition = makeDefinition(snapshot, 2, {variableConnectorIDs.at(0), variableConnectorIDs.at(1)});
+                        auto       combinedRequest    = requestFor(snapshot, {combinedDefinition});
+                        combinedRequest.groups.push_back(groupRequest(snapshot, combinedDefinition));
+                        combinedRequest.ordinary.push_back({
+                            .connector = connectorHandle(snapshot, variableConnectorIDs.at(2)),
+                            .priority  = eOrdinaryPriority::ENABLED_UNMATCHED,
+                        });
+                        const auto                 combinedPlan  = solve(snapshot, combinedRequest);
+                        const SCombinedOracleInput combinedInput = {
+                            .candidates =
+                                {
+                                    {
+                                        .connectorID   = variableConnectorIDs.at(0),
+                                        .connectorMask = connectorMasks.at(0),
+                                        .active        = true,
+                                        .groupOrder    = 0,
+                                        .preferredCRTC = std::nullopt,
+                                    },
+                                    {
+                                        .connectorID   = variableConnectorIDs.at(1),
+                                        .connectorMask = connectorMasks.at(1),
+                                        .active        = true,
+                                        .groupOrder    = 0,
+                                        .preferredCRTC = std::nullopt,
+                                    },
+                                    {
+                                        .connectorID   = variableConnectorIDs.at(2),
+                                        .connectorMask = connectorMasks.at(2),
+                                        .active        = true,
+                                        .groupOrder    = std::nullopt,
+                                        .preferredCRTC = std::nullopt,
+                                    },
+                                },
+                            .planeMasks      = planeMasks,
+                            .crtcIDs         = variableCRTCIDs,
+                            .planeIDs        = variablePlaneIDs,
+                            .preferredPlanes = std::vector<std::optional<uint32_t>>(size),
+                            .groupCount      = 1,
+                        };
+                        const auto combinedReference = bruteForceCombined(combinedInput);
+                        ++combinedCases;
+                        CHECK(combinedPlan->status() == ePlanStatus::READY);
+                        CHECK((combinedPlan->groups().front().status() == eGroupStatus::ALLOCATED) == (combinedReference.groupStatus.front() == 0));
+                        CHECK(planBindings(combinedPlan) == combinedReference.bindings);
+                    }
+
+                    if (size == 2) {
+                        auto tierRequest     = requestFor(snapshot);
+                        tierRequest.ordinary = {
+                            {.connector = connectorHandle(snapshot, variableConnectorIDs.at(0)), .priority = eOrdinaryPriority::ENABLED_UNMATCHED},
+                            {.connector = connectorHandle(snapshot, variableConnectorIDs.at(1)), .priority = eOrdinaryPriority::DETACHED_DISABLED_BACKUP},
+                        };
+                        const auto                 tierPlan  = solve(snapshot, tierRequest);
+                        const SCombinedOracleInput tierInput = {
+                            .candidates =
+                                {
+                                    {
+                                        .connectorID   = variableConnectorIDs.at(0),
+                                        .connectorMask = connectorMasks.at(0),
+                                        .active        = true,
+                                        .groupOrder    = std::nullopt,
+                                        .preferredCRTC = std::nullopt,
+                                    },
+                                    {
+                                        .connectorID   = variableConnectorIDs.at(1),
+                                        .connectorMask = connectorMasks.at(1),
+                                        .active        = false,
+                                        .groupOrder    = std::nullopt,
+                                        .preferredCRTC = std::nullopt,
+                                    },
+                                },
+                            .planeMasks      = planeMasks,
+                            .crtcIDs         = variableCRTCIDs,
+                            .planeIDs        = variablePlaneIDs,
+                            .preferredPlanes = std::vector<std::optional<uint32_t>>(size),
+                            .groupCount      = 0,
+                        };
+                        const auto tierReference = bruteForceCombined(tierInput);
+                        ++tierCases;
+                        CHECK(tierPlan->status() == ePlanStatus::READY);
+                        CHECK(planBindings(tierPlan) == tierReference.bindings);
+                    }
+                }
+            }
+        }
+        CHECK(groupCases == 117731);
+        CHECK(ordinaryCases == 117731);
+        CHECK(combinedCases == 117649);
+        CHECK(tierCases == 81);
+    }
+}
+
+int main(int argc, char** argv) {
+    const auto arguments = std::span<char*>{argv, static_cast<size_t>(argc)};
+    const bool focused   = arguments.size() > 1 && std::string_view{arguments.subspan(1, 1).front()} == "--focused";
+
+    testNormalizationAndSnapshotBoundary();
+    testDefinitionFactory();
+    testGroupGreedyTrapAndPreferences();
+    testGlobalGroupLookahead();
+    testCrossTierGlobalLookahead();
+    testRetainedGroupsAndContention();
+    testOrdinaryJointBatchesAndPreferences();
+    testHoldsHallAndZeroMutation();
+    testComplexityBudget();
+    testBackendLifetimeBoundary();
+    testStaleIdentityAndCurrentness();
+    testAllocationObservationCurrentness();
+    testOwnerRetentionForBothStatuses();
+    if (!focused)
+        testExhaustiveCompatibility();
+
+    if (FAILURES != 0)
+        std::cerr << FAILURES << " TiledCrtcAllocator checks failed\n";
+    return FAILURES == 0 ? 0 : 1;
+}
diff --git a/tests/TiledVisibility.cmake b/tests/TiledVisibility.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..ab089ff6c27cdd8e9f5e5dc3094a77514c67f705
--- /dev/null
+++ b/tests/TiledVisibility.cmake
@@ -0,0 +1,79 @@
+if(NOT DEFINED NM OR NOT EXISTS "${NM}")
+  message(FATAL_ERROR "nm executable is unavailable: ${NM}")
+endif()
+if(NOT DEFINED LIBRARY OR NOT EXISTS "${LIBRARY}")
+  message(FATAL_ERROR "Aquamarine library is unavailable: ${LIBRARY}")
+endif()
+if(NOT DEFINED PRIVATE_ARCHIVE OR NOT EXISTS "${PRIVATE_ARCHIVE}")
+  message(FATAL_ERROR "TILE private archive is unavailable: ${PRIVATE_ARCHIVE}")
+endif()
+if(NOT DEFINED PROBE_LIBRARY OR NOT EXISTS "${PROBE_LIBRARY}")
+  message(FATAL_ERROR "TILE visibility probe is unavailable: ${PROBE_LIBRARY}")
+endif()
+
+execute_process(
+  COMMAND "${NM}" -g --defined-only --format=posix "${PRIVATE_ARCHIVE}"
+  RESULT_VARIABLE private_result
+  OUTPUT_VARIABLE private_output
+  ERROR_VARIABLE private_error)
+if(NOT private_result EQUAL 0)
+  message(FATAL_ERROR "failed to inspect TILE private archive: ${private_error}")
+endif()
+
+execute_process(
+  COMMAND "${NM}" -D --defined-only --format=posix "${PROBE_LIBRARY}"
+  RESULT_VARIABLE probe_result
+  OUTPUT_VARIABLE probe_output
+  ERROR_VARIABLE probe_error)
+if(NOT probe_result EQUAL 0)
+  message(FATAL_ERROR "failed to inspect TILE visibility probe: ${probe_error}")
+endif()
+
+function(collect_symbols output result_name)
+  string(REPLACE "\r\n" "\n" normalized "${output}")
+  string(REPLACE "\n" ";" lines "${normalized}")
+  set(symbols)
+  foreach(line IN LISTS lines)
+    string(STRIP "${line}" line)
+    if(line STREQUAL "" OR line MATCHES ":$")
+      continue()
+    endif()
+    string(REGEX MATCH "^[^ ]+" symbol "${line}")
+    if(symbol STREQUAL "" OR symbol MATCHES "^DW\\.ref\\.")
+      continue()
+    endif()
+    list(APPEND symbols "${symbol}")
+  endforeach()
+  list(REMOVE_DUPLICATES symbols)
+  set(${result_name} "${symbols}" PARENT_SCOPE)
+endfunction()
+
+collect_symbols("${private_output}" private_symbols)
+collect_symbols("${probe_output}" probe_symbols)
+
+set(leaked_symbols)
+foreach(symbol IN LISTS private_symbols)
+  if(symbol IN_LIST probe_symbols)
+    list(APPEND leaked_symbols "${symbol}")
+  endif()
+endforeach()
+
+if(leaked_symbols)
+  list(JOIN leaked_symbols "\n  " leaked_report)
+  message(FATAL_ERROR
+          "TILE private archive symbols escaped archive localization:\n  ${leaked_report}")
+endif()
+
+execute_process(
+  COMMAND "${NM}" -D --defined-only --demangle "${LIBRARY}"
+  RESULT_VARIABLE demangle_result
+  OUTPUT_VARIABLE demangled_output
+  ERROR_VARIABLE demangle_error)
+if(NOT demangle_result EQUAL 0)
+  message(FATAL_ERROR "failed to demangle Aquamarine dynamic symbols: ${demangle_error}")
+endif()
+
+if(demangled_output MATCHES
+   "Aquamarine::(NTiling|TiledCrtcAllocator)::|Aquamarine::NDRM::.*(Tile|tile|PlaneViewport|PlaneFormats|intersectPlaneFormats|encodePlaneViewport)")
+  message(FATAL_ERROR "source-private TILE symbol family is dynamically exported")
+endif()
diff --git a/tests/TiledVisibilityProbe.cpp b/tests/TiledVisibilityProbe.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..0fbfd3fc36eb39373fcec1fd9626931f88936572
--- /dev/null
+++ b/tests/TiledVisibilityProbe.cpp
@@ -0,0 +1,3 @@
+extern "C" int aquamarineTiledVisibilityProbe() {
+    return 0;
+}