224 lines
6.6 KiB
C
224 lines
6.6 KiB
C
// dvx_comp.c — Layer 3: Dirty rectangle compositor for DV/X GUI (optimized)
|
|
|
|
#include "dvxComp.h"
|
|
|
|
#include <string.h>
|
|
|
|
// ============================================================
|
|
// 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], 4)) {
|
|
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 BlitOpsT *ops, const RectT *r) {
|
|
(void)ops;
|
|
|
|
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;
|
|
}
|