// dvx_comp.c — Layer 3: Dirty rectangle compositor for DV/X GUI (optimized) #include "dvxComp.h" #include "platform/dvxPlatform.h" #include #define DIRTY_MERGE_GAP 4 // ============================================================ // Prototypes // ============================================================ static inline bool rectsOverlapOrAdjacent(const RectT *a, const RectT *b, int32_t gap); static inline void rectUnion(const RectT *a, const RectT *b, RectT *result); // ============================================================ // dirtyListAdd // ============================================================ void dirtyListAdd(DirtyListT *dl, int32_t x, int32_t y, int32_t w, int32_t h) { if (__builtin_expect(w <= 0 || h <= 0, 0)) { return; } if (__builtin_expect(dl->count >= MAX_DIRTY_RECTS, 0)) { dirtyListMerge(dl); if (dl->count >= MAX_DIRTY_RECTS) { RectT merged = dl->rects[0]; for (int32_t i = 1; i < dl->count; i++) { rectUnion(&merged, &dl->rects[i], &merged); } RectT newRect = {x, y, w, h}; rectUnion(&merged, &newRect, &merged); dl->rects[0] = merged; dl->count = 1; return; } } dl->rects[dl->count].x = x; dl->rects[dl->count].y = y; dl->rects[dl->count].w = w; dl->rects[dl->count].h = h; dl->count++; } // ============================================================ // dirtyListClear // ============================================================ void dirtyListClear(DirtyListT *dl) { dl->count = 0; } // ============================================================ // dirtyListInit // ============================================================ void dirtyListInit(DirtyListT *dl) { dl->count = 0; } // ============================================================ // dirtyListMerge // ============================================================ void dirtyListMerge(DirtyListT *dl) { if (dl->count <= 1) { return; } // O(N²) with bounded restarts: for each rect, try to merge it // into an earlier rect. When a merge succeeds the merged rect // may now overlap others, so restart the inner scan — but cap // restarts per slot to avoid O(N³) pathological cascades. for (int32_t i = 0; i < dl->count; i++) { int32_t restarts = 0; bool merged = true; while (merged && restarts < 3) { merged = false; for (int32_t j = i + 1; j < dl->count; j++) { if (rectsOverlapOrAdjacent(&dl->rects[i], &dl->rects[j], DIRTY_MERGE_GAP)) { rectUnion(&dl->rects[i], &dl->rects[j], &dl->rects[i]); dl->rects[j] = dl->rects[dl->count - 1]; dl->count--; j--; merged = true; } } restarts++; } } } // ============================================================ // flushRect // ============================================================ void flushRect(DisplayT *d, const RectT *r) { platformFlushRect(d, r); } // ============================================================ // rectIntersect // ============================================================ bool rectIntersect(const RectT *a, const RectT *b, RectT *result) { int32_t ix1 = a->x > b->x ? a->x : b->x; int32_t iy1 = a->y > b->y ? a->y : b->y; int32_t ix2 = (a->x + a->w) < (b->x + b->w) ? (a->x + a->w) : (b->x + b->w); int32_t iy2 = (a->y + a->h) < (b->y + b->h) ? (a->y + a->h) : (b->y + b->h); if (__builtin_expect(ix1 >= ix2 || iy1 >= iy2, 0)) { return false; } result->x = ix1; result->y = iy1; result->w = ix2 - ix1; result->h = iy2 - iy1; return true; } // ============================================================ // rectIsEmpty // ============================================================ bool rectIsEmpty(const RectT *r) { return (r->w <= 0 || r->h <= 0); } // ============================================================ // rectsOverlapOrAdjacent // ============================================================ static inline bool rectsOverlapOrAdjacent(const RectT *a, const RectT *b, int32_t gap) { if (a->x + a->w + gap < b->x) { return false; } if (b->x + b->w + gap < a->x) { return false; } if (a->y + a->h + gap < b->y) { return false; } if (b->y + b->h + gap < a->y) { return false; } return true; } // ============================================================ // rectUnion // ============================================================ static inline void rectUnion(const RectT *a, const RectT *b, RectT *result) { int32_t x1 = a->x < b->x ? a->x : b->x; int32_t y1 = a->y < b->y ? a->y : b->y; int32_t x2 = (a->x + a->w) > (b->x + b->w) ? (a->x + a->w) : (b->x + b->w); int32_t y2 = (a->y + a->h) > (b->y + b->h) ? (a->y + a->h) : (b->y + b->h); result->x = x1; result->y = y1; result->w = x2 - x1; result->h = y2 - y1; }