// dvx_comp.c — Layer 3: Dirty rectangle compositor for DV/X GUI (optimized) #include "dvxComp.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; } bool merged = true; while (merged) { merged = false; for (int32_t i = 0; i < dl->count; i++) { 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; } } } } } // ============================================================ // flushRect // ============================================================ void flushRect(DisplayT *d, const RectT *r) { int32_t bpp = d->format.bytesPerPixel; int32_t x = r->x; int32_t y = r->y; int32_t w = r->w; int32_t h = r->h; if (__builtin_expect(x < 0, 0)) { w += x; x = 0; } if (__builtin_expect(y < 0, 0)) { h += y; y = 0; } if (__builtin_expect(x + w > d->width, 0)) { w = d->width - x; } if (__builtin_expect(y + h > d->height, 0)) { h = d->height - y; } if (__builtin_expect(w <= 0 || h <= 0, 0)) { return; } int32_t rowBytes = w * bpp; int32_t pitch = d->pitch; uint8_t *src = d->backBuf + y * pitch + x * bpp; uint8_t *dst = d->lfb + y * pitch + x * bpp; // Full-width flush: single large copy (write-combined memory loves sequential writes) if (rowBytes == pitch) { // Entire scanlines — copy as one contiguous block int32_t totalBytes = pitch * h; int32_t dwords = totalBytes >> 2; int32_t remainder = totalBytes & 3; __asm__ __volatile__ ( "rep movsl" : "+D"(dst), "+S"(src), "+c"(dwords) : : "memory" ); // Handle any trailing bytes (unlikely for aligned pitch) while (remainder-- > 0) { *dst++ = *src++; } } else { // Partial scanlines — copy row by row with rep movsd for (int32_t i = 0; i < h; i++) { int32_t dwords = rowBytes >> 2; int32_t remainder = rowBytes & 3; uint8_t *s = src; uint8_t *dd = dst; __asm__ __volatile__ ( "rep movsl" : "+D"(dd), "+S"(s), "+c"(dwords) : : "memory" ); // Trailing bytes (dd and s already advanced by rep movsl) if (__builtin_expect(remainder > 0, 0)) { while (remainder-- > 0) { *dd++ = *s++; } } src += pitch; dst += pitch; } } } // ============================================================ // 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; }