From 73f7e37ba6eba2357de247737f2f7e6269c5b0f2 Mon Sep 17 00:00:00 2001 From: Scott Duensing Date: Tue, 10 Mar 2026 00:37:35 -0500 Subject: [PATCH] Some optimizations. --- dvx/dvxApp.c | 2 +- dvx/dvxComp.c | 8 +- dvx/dvxComp.h | 2 +- dvx/dvxVideo.c | 2 + dvx/dvxWm.c | 246 +++++++++++++++++++++++++++++-------------------- 5 files changed, 152 insertions(+), 108 deletions(-) diff --git a/dvx/dvxApp.c b/dvx/dvxApp.c index 5671d5e..4f6882a 100644 --- a/dvx/dvxApp.c +++ b/dvx/dvxApp.c @@ -155,7 +155,7 @@ static void compositeAndFlush(AppContextT *ctx) { drawCursorAt(ctx, ctx->mouseX, ctx->mouseY); // 5. Flush this dirty rect to LFB - flushRect(d, ops, dr); + flushRect(d, dr); } resetClipRect(d); diff --git a/dvx/dvxComp.c b/dvx/dvxComp.c index 6a04204..a8bbb3e 100644 --- a/dvx/dvxComp.c +++ b/dvx/dvxComp.c @@ -4,6 +4,8 @@ #include +#define DIRTY_MERGE_GAP 4 + // ============================================================ // Prototypes // ============================================================ @@ -82,7 +84,7 @@ void dirtyListMerge(DirtyListT *dl) { 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)) { + 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--; @@ -99,9 +101,7 @@ void dirtyListMerge(DirtyListT *dl) { // flushRect // ============================================================ -void flushRect(DisplayT *d, const BlitOpsT *ops, const RectT *r) { - (void)ops; - +void flushRect(DisplayT *d, const RectT *r) { int32_t bpp = d->format.bytesPerPixel; int32_t x = r->x; diff --git a/dvx/dvxComp.h b/dvx/dvxComp.h index 688d120..d4f0a7e 100644 --- a/dvx/dvxComp.h +++ b/dvx/dvxComp.h @@ -17,7 +17,7 @@ void dirtyListMerge(DirtyListT *dl); void dirtyListClear(DirtyListT *dl); // Flush a single rectangle from backbuffer to LFB -void flushRect(DisplayT *d, const BlitOpsT *ops, const RectT *r); +void flushRect(DisplayT *d, const RectT *r); // Intersect two rectangles, returns true if intersection is non-empty bool rectIntersect(const RectT *a, const RectT *b, RectT *result); diff --git a/dvx/dvxVideo.c b/dvx/dvxVideo.c index 489e95c..263ba9d 100644 --- a/dvx/dvxVideo.c +++ b/dvx/dvxVideo.c @@ -368,6 +368,7 @@ int32_t videoInit(DisplayT *d, int32_t requestedW, int32_t requestedH, int32_t p if (!d->backBuf) { fprintf(stderr, "VBE: Failed to allocate %lu byte backbuffer\n", (unsigned long)fbSize); + __djgpp_nearptr_disable(); return -1; } @@ -381,6 +382,7 @@ int32_t videoInit(DisplayT *d, int32_t requestedW, int32_t requestedH, int32_t p fprintf(stderr, "VBE: Failed to allocate palette\n"); free(d->backBuf); d->backBuf = NULL; + __djgpp_nearptr_disable(); return -1; } diff --git a/dvx/dvxWm.c b/dvx/dvxWm.c index 00d80de..692a9a1 100644 --- a/dvx/dvxWm.c +++ b/dvx/dvxWm.c @@ -10,11 +10,37 @@ #include #include +// ============================================================ +// Constants +// ============================================================ + +#define GADGET_PAD 2 +#define GADGET_INSET 2 // inset from title bar edges + +// ============================================================ +// Title bar gadget geometry +// ============================================================ + +typedef struct { + int32_t titleX; + int32_t titleY; + int32_t titleW; + int32_t titleH; + int32_t gadgetS; // gadget square size + int32_t gadgetY; // gadget Y position + int32_t closeX; // close gadget X + int32_t minX; // minimize gadget X + int32_t maxX; // maximize gadget X (-1 if not resizable) + int32_t textLeftEdge; // left edge of title text area + int32_t textRightEdge; // right edge of title text area +} TitleGeomT; + // ============================================================ // Prototypes // ============================================================ static void computeMenuBarPositions(WindowT *win, const BitmapFontT *font); +static void computeTitleGeom(const WindowT *win, TitleGeomT *g); static void drawBorderFrame(DisplayT *d, const BlitOpsT *ops, const ColorSchemeT *colors, int32_t x, int32_t y, int32_t w, int32_t h); static void drawMenuBar(DisplayT *d, const BlitOpsT *ops, const BitmapFontT *font, const ColorSchemeT *colors, WindowT *win); static void drawResizeBreaks(DisplayT *d, const BlitOpsT *ops, const ColorSchemeT *colors, WindowT *win); @@ -50,6 +76,42 @@ static void computeMenuBarPositions(WindowT *win, const BitmapFontT *font) { } +// ============================================================ +// computeTitleGeom +// ============================================================ +// +// Compute title bar gadget positions. Used by both drawTitleBar() +// and wmHitTest() to keep geometry in sync. + +static void computeTitleGeom(const WindowT *win, TitleGeomT *g) { + g->titleX = win->x + CHROME_BORDER_WIDTH; + g->titleY = win->y + CHROME_BORDER_WIDTH; + g->titleW = win->w - CHROME_BORDER_WIDTH * 2; + g->titleH = CHROME_TITLE_HEIGHT; + g->gadgetS = g->titleH - GADGET_INSET * 2; + g->gadgetY = g->titleY + GADGET_INSET; + + // Close gadget on the left + g->closeX = g->titleX + GADGET_PAD; + + // Rightmost gadget position (decremented as gadgets are placed) + int32_t rightX = g->titleX + g->titleW - GADGET_PAD - g->gadgetS; + + if (win->resizable) { + g->maxX = rightX; + rightX -= g->gadgetS + GADGET_PAD; + } else { + g->maxX = -1; + } + + g->minX = rightX; + + // Text area between close gadget and minimize gadget + g->textLeftEdge = g->closeX + g->gadgetS + GADGET_PAD; + g->textRightEdge = g->minX - GADGET_PAD; +} + + // ============================================================ // drawBorderFrame // ============================================================ @@ -201,34 +263,46 @@ static void drawResizeBreaks(DisplayT *d, const BlitOpsT *ops, const ColorScheme // ============================================================ static void drawScaledRect(DisplayT *d, int32_t dstX, int32_t dstY, int32_t dstW, int32_t dstH, const uint8_t *src, int32_t srcW, int32_t srcH, int32_t srcPitch, int32_t bpp) { - for (int32_t dy = 0; dy < dstH; dy++) { - int32_t sy = (dy * srcH) / dstH; - int32_t screenY = dstY + dy; + // Pre-compute visible row/col range (clip against display clip rect) + int32_t rowStart = 0; + int32_t rowEnd = dstH; + int32_t colStart = 0; + int32_t colEnd = dstW; - if (screenY < d->clipY || screenY >= d->clipY + d->clipH) { - continue; - } + if (dstY < d->clipY) { rowStart = d->clipY - dstY; } + if (dstY + dstH > d->clipY + d->clipH) { rowEnd = d->clipY + d->clipH - dstY; } + if (dstX < d->clipX) { colStart = d->clipX - dstX; } + if (dstX + dstW > d->clipX + d->clipW) { colEnd = d->clipX + d->clipW - dstX; } - uint8_t *dstRow = d->backBuf + screenY * d->pitch; + if (rowStart >= rowEnd || colStart >= colEnd) { + return; + } + + // Pre-compute source X lookup table (one division per column instead of per pixel) + int32_t srcXTab[ICON_SIZE]; + int32_t visibleCols = colEnd - colStart; + + for (int32_t dx = 0; dx < visibleCols; dx++) { + srcXTab[dx] = ((colStart + dx) * srcW) / dstW * bpp; + } + + // Blit with pre-computed lookups — no per-pixel divisions or clip checks + for (int32_t dy = rowStart; dy < rowEnd; dy++) { + int32_t sy = (dy * srcH) / dstH; + uint8_t *dstRow = d->backBuf + (dstY + dy) * d->pitch + (dstX + colStart) * bpp; const uint8_t *srcRow = src + sy * srcPitch; - for (int32_t dx = 0; dx < dstW; dx++) { - int32_t sx = (dx * srcW) / dstW; - int32_t screenX = dstX + dx; - - if (screenX < d->clipX || screenX >= d->clipX + d->clipW) { - continue; + if (bpp == 1) { + for (int32_t dx = 0; dx < visibleCols; dx++) { + dstRow[dx] = srcRow[srcXTab[dx]]; } - - const uint8_t *srcPx = srcRow + sx * bpp; - uint8_t *dstPx = dstRow + screenX * bpp; - - if (bpp == 1) { - *dstPx = *srcPx; - } else if (bpp == 2) { - *(uint16_t *)dstPx = *(const uint16_t *)srcPx; - } else { - *(uint32_t *)dstPx = *(const uint32_t *)srcPx; + } else if (bpp == 2) { + for (int32_t dx = 0; dx < visibleCols; dx++) { + *(uint16_t *)(dstRow + dx * 2) = *(const uint16_t *)(srcRow + srcXTab[dx]); + } + } else { + for (int32_t dx = 0; dx < visibleCols; dx++) { + *(uint32_t *)(dstRow + dx * 4) = *(const uint32_t *)(srcRow + srcXTab[dx]); } } } @@ -345,45 +419,30 @@ static void drawScrollbarArrow(DisplayT *d, const BlitOpsT *ops, const ColorSche // ============================================================ static void drawTitleBar(DisplayT *d, const BlitOpsT *ops, const BitmapFontT *font, const ColorSchemeT *colors, WindowT *win) { - int32_t titleX = win->x + CHROME_BORDER_WIDTH; - int32_t titleY = win->y + CHROME_BORDER_WIDTH; - int32_t titleW = win->w - CHROME_BORDER_WIDTH * 2; - int32_t titleH = CHROME_TITLE_HEIGHT; + TitleGeomT g; + computeTitleGeom(win, &g); uint32_t bg = win->focused ? colors->activeTitleBg : colors->inactiveTitleBg; uint32_t fg = win->focused ? colors->activeTitleFg : colors->inactiveTitleFg; // Fill title bar background - rectFill(d, ops, titleX, titleY, titleW, titleH, bg); - - // GEOS Motif gadget sizing - int32_t gadgetS = titleH - 4; // gadget size, fits within title bar - int32_t gadgetY = titleY + 2; - int32_t gadgetPad = 2; + rectFill(d, ops, g.titleX, g.titleY, g.titleW, g.titleH, bg); // Close gadget on the LEFT (system menu / close) - int32_t closeX = titleX + gadgetPad; - drawTitleGadget(d, ops, colors, closeX, gadgetY, gadgetS); + drawTitleGadget(d, ops, colors, g.closeX, g.gadgetY, g.gadgetS); // Horizontal bar icon inside close gadget - drawHLine(d, ops, closeX + 3, gadgetY + gadgetS / 2, - gadgetS - 6, colors->contentFg); + drawHLine(d, ops, g.closeX + 3, g.gadgetY + g.gadgetS / 2, + g.gadgetS - 6, colors->contentFg); - // Right edge of title text area - int32_t textRightEdge = titleX + titleW - gadgetPad; - - // Rightmost gadget position - int32_t rightGadgetX = titleX + titleW - gadgetPad - gadgetS; - - if (win->resizable) { + if (g.maxX >= 0) { // Maximize/restore gadget on the far RIGHT - int32_t maxX = rightGadgetX; - drawTitleGadget(d, ops, colors, maxX, gadgetY, gadgetS); + drawTitleGadget(d, ops, colors, g.maxX, g.gadgetY, g.gadgetS); if (win->maximized) { // Restore icon: larger box outline filling more of the gadget - int32_t bx = maxX + 2; - int32_t by = gadgetY + 2; - int32_t bs = gadgetS - 4; + int32_t bx = g.maxX + 2; + int32_t by = g.gadgetY + 2; + int32_t bs = g.gadgetS - 4; rectFill(d, ops, bx, by, bs, bs, colors->buttonFace); drawHLine(d, ops, bx, by, bs, colors->contentFg); drawHLine(d, ops, bx, by + 1, bs, colors->contentFg); @@ -392,30 +451,24 @@ static void drawTitleBar(DisplayT *d, const BlitOpsT *ops, const BitmapFontT *fo drawVLine(d, ops, bx + bs - 1, by, bs, colors->contentFg); } else { // Maximize icon: small box outline - rectFill(d, ops, maxX + 3, gadgetY + 3, - gadgetS - 6, gadgetS - 6, colors->buttonFace); - drawHLine(d, ops, maxX + 3, gadgetY + 3, gadgetS - 6, colors->contentFg); - drawHLine(d, ops, maxX + 3, gadgetY + gadgetS - 4, gadgetS - 6, colors->contentFg); - drawVLine(d, ops, maxX + 3, gadgetY + 3, gadgetS - 6, colors->contentFg); - drawVLine(d, ops, maxX + gadgetS - 4, gadgetY + 3, gadgetS - 6, colors->contentFg); + rectFill(d, ops, g.maxX + 3, g.gadgetY + 3, + g.gadgetS - 6, g.gadgetS - 6, colors->buttonFace); + drawHLine(d, ops, g.maxX + 3, g.gadgetY + 3, g.gadgetS - 6, colors->contentFg); + drawHLine(d, ops, g.maxX + 3, g.gadgetY + g.gadgetS - 4, g.gadgetS - 6, colors->contentFg); + drawVLine(d, ops, g.maxX + 3, g.gadgetY + 3, g.gadgetS - 6, colors->contentFg); + drawVLine(d, ops, g.maxX + g.gadgetS - 4, g.gadgetY + 3, g.gadgetS - 6, colors->contentFg); } - - rightGadgetX -= gadgetS + gadgetPad; } - // Minimize gadget (always present, to the left of maximize or on the far right) - int32_t minX = rightGadgetX; - drawTitleGadget(d, ops, colors, minX, gadgetY, gadgetS); + // Minimize gadget (always present) + drawTitleGadget(d, ops, colors, g.minX, g.gadgetY, g.gadgetS); // Small square centered in minimize gadget int32_t miniSize = 4; - rectFill(d, ops, minX + (gadgetS - miniSize) / 2, gadgetY + (gadgetS - miniSize) / 2, + rectFill(d, ops, g.minX + (g.gadgetS - miniSize) / 2, g.gadgetY + (g.gadgetS - miniSize) / 2, miniSize, miniSize, colors->contentFg); - textRightEdge = minX - gadgetPad; - - // Title text — centered between close gadget and right edge, truncated to fit - int32_t textLeftEdge = closeX + gadgetS + gadgetPad; - int32_t availW = textRightEdge - textLeftEdge; + // Title text — centered between close gadget and minimize, truncated to fit + int32_t availW = g.textRightEdge - g.textLeftEdge; if (availW > 0) { int32_t maxChars = availW / font->charWidth; @@ -426,15 +479,16 @@ static void drawTitleBar(DisplayT *d, const BlitOpsT *ops, const BitmapFontT *fo } if (len > 0) { - int32_t textW = len * font->charWidth; - int32_t textX = textLeftEdge + (availW - textW) / 2; - int32_t textY = titleY + (titleH - font->charHeight) / 2; + // Build truncated title for drawText + char truncTitle[MAX_TITLE_LEN]; + memcpy(truncTitle, win->title, len); + truncTitle[len] = '\0'; - // Draw truncated title character by character - for (int32_t i = 0; i < len; i++) { - drawChar(d, ops, font, textX + i * font->charWidth, textY, - win->title[i], fg, bg, true); - } + int32_t textW = len * font->charWidth; + int32_t textX = g.textLeftEdge + (availW - textW) / 2; + int32_t textY = g.titleY + (g.titleH - font->charHeight) / 2; + + drawText(d, ops, font, textX, textY, truncTitle, fg, bg, true); } } } @@ -464,13 +518,13 @@ static int32_t scrollbarThumbInfo(const ScrollbarT *sb, int32_t *thumbPos, int32 return trackLen; } - *thumbSize = (sb->pageSize * trackLen) / (range + sb->pageSize); + *thumbSize = (int32_t)(((int64_t)sb->pageSize * trackLen) / (range + sb->pageSize)); if (*thumbSize < SCROLLBAR_WIDTH) { *thumbSize = SCROLLBAR_WIDTH; } - *thumbPos = ((sb->value - sb->min) * (trackLen - *thumbSize)) / range; + *thumbPos = (int32_t)(((int64_t)(sb->value - sb->min) * (trackLen - *thumbSize)) / range); return trackLen; } @@ -944,46 +998,34 @@ int32_t wmHitTest(const WindowStackT *stack, int32_t mx, int32_t my, int32_t *hi continue; } - // Title bar gadget geometry (must match drawTitleBar) - int32_t titleX = win->x + CHROME_BORDER_WIDTH; - int32_t titleY = win->y + CHROME_BORDER_WIDTH; - int32_t titleW = win->w - CHROME_BORDER_WIDTH * 2; - int32_t gadgetS = CHROME_TITLE_HEIGHT - 4; - int32_t gadgetY = titleY + 2; - int32_t gadgetP = 2; + TitleGeomT g; + computeTitleGeom(win, &g); // Close gadget (top-left) - int32_t closeX = titleX + gadgetP; - if (mx >= closeX && mx < closeX + gadgetS && - my >= gadgetY && my < gadgetY + gadgetS) { + if (mx >= g.closeX && mx < g.closeX + g.gadgetS && + my >= g.gadgetY && my < g.gadgetY + g.gadgetS) { *hitPart = 2; return i; } - // Rightmost gadget position - int32_t rightGadgetX = titleX + titleW - gadgetP - gadgetS; - - // Maximize gadget only on resizable windows - if (win->resizable) { - if (mx >= rightGadgetX && mx < rightGadgetX + gadgetS && - my >= gadgetY && my < gadgetY + gadgetS) { - *hitPart = 8; - return i; - } - - rightGadgetX -= gadgetS + gadgetP; + // Maximize gadget (resizable windows only) + if (g.maxX >= 0 && + mx >= g.maxX && mx < g.maxX + g.gadgetS && + my >= g.gadgetY && my < g.gadgetY + g.gadgetS) { + *hitPart = 8; + return i; } // Minimize gadget (always present) - if (mx >= rightGadgetX && mx < rightGadgetX + gadgetS && - my >= gadgetY && my < gadgetY + gadgetS) { + if (mx >= g.minX && mx < g.minX + g.gadgetS && + my >= g.gadgetY && my < g.gadgetY + g.gadgetS) { *hitPart = 7; return i; } // Title bar (drag area — between gadgets) - if (my >= titleY && my < titleY + CHROME_TITLE_HEIGHT && - mx >= titleX && mx < titleX + titleW) { + if (my >= g.titleY && my < g.titleY + CHROME_TITLE_HEIGHT && + mx >= g.titleX && mx < g.titleX + g.titleW) { *hitPart = 1; return i; }