// demo.c -- Test/demo application for accelerated video drivers // // Detects the video card, sets a graphics mode, exercises the // hardware acceleration (fill rects, blit, draw lines, color // expand), and provides a simple interactive benchmark comparing // hardware vs software rendering speed. // // Usage: demo [width height bpp] // Defaults to 640x480x16 if no arguments given. // // Press ESC to exit, 'b' to run benchmark, space to cycle tests. #include "accelVid.h" #include "pci.h" #include #include #include #include #include #include #include #include // Scancode for ESC key #define KEY_ESC 0x01 // Default video mode #define DEFAULT_WIDTH 640 #define DEFAULT_HEIGHT 480 #define DEFAULT_BPP 16 // Benchmark iteration counts #define BENCH_FILL_COUNT 1000 #define BENCH_BLIT_COUNT 1000 #define BENCH_LINE_COUNT 5000 #define BENCH_EXPAND_COUNT 500 #define BENCH_HBLIT_COUNT 1000 #define BENCH_PATFILL_COUNT 1000 // Host blit test pattern dimensions #define HBLIT_PAT_W 100 #define HBLIT_PAT_H 100 // ============================================================ // External driver registration functions // ============================================================ extern void atiRegisterDriver(void); extern void bansheeRegisterDriver(void); extern void clRegisterDriver(void); extern void etRegisterDriver(void); extern void lagunaRegisterDriver(void); extern void mgaRegisterDriver(void); extern void nvRegisterDriver(void); extern void s3RegisterDriver(void); extern void sisRegisterDriver(void); extern void tridentRegisterDriver(void); // ============================================================ // Prototypes // ============================================================ static void demoBenchmark(AccelDriverT *drv); static void demoBitBlt(AccelDriverT *drv); static void demoColorExpand(AccelDriverT *drv); static void demoFillRects(AccelDriverT *drv); static void demoHostBlit(AccelDriverT *drv); static void demoLines(AccelDriverT *drv); static void demoPatternFill(AccelDriverT *drv); static bool isKeyPressed(void); static uint32_t packColor16(uint8_t r, uint8_t g, uint8_t b); static uint8_t readKey(void); static void softFillRect(AccelDriverT *drv, int32_t x, int32_t y, int32_t w, int32_t h, uint32_t color); // ============================================================ // demoBenchmark // ============================================================ // // Runs timed comparisons of hardware vs software rendering for // rectangle fills and blits. Prints results to stdout after // restoring text mode. static void demoBenchmark(AccelDriverT *drv) { int32_t screenW = drv->mode.width; int32_t screenH = drv->mode.height; // Benchmark hardware rect fill clock_t hwFillStart = clock(); for (int32_t i = 0; i < BENCH_FILL_COUNT; i++) { int32_t x = (i * 37) % (screenW - 100); int32_t y = (i * 53) % (screenH - 100); drv->rectFill(drv, x, y, 100, 100, packColor16(i & 0xFF, (i >> 3) & 0xFF, (i >> 6) & 0xFF)); } drv->waitIdle(drv); clock_t hwFillEnd = clock(); // Benchmark software rect fill clock_t swFillStart = clock(); for (int32_t i = 0; i < BENCH_FILL_COUNT; i++) { int32_t x = (i * 37) % (screenW - 100); int32_t y = (i * 53) % (screenH - 100); softFillRect(drv, x, y, 100, 100, packColor16(i & 0xFF, (i >> 3) & 0xFF, (i >> 6) & 0xFF)); } clock_t swFillEnd = clock(); // Benchmark hardware bitblt clock_t hwBltStart = clock(); for (int32_t i = 0; i < BENCH_BLIT_COUNT; i++) { int32_t sx = (i * 31) % (screenW - 100); int32_t sy = (i * 47) % (screenH - 100); int32_t dx = (i * 43) % (screenW - 100); int32_t dy = (i * 59) % (screenH - 100); drv->bitBlt(drv, sx, sy, dx, dy, 100, 100); } drv->waitIdle(drv); clock_t hwBltEnd = clock(); // Benchmark hardware line draw clock_t hwLineStart = clock(); for (int32_t i = 0; i < BENCH_LINE_COUNT; i++) { int32_t x1 = (i * 37) % screenW; int32_t y1 = (i * 53) % screenH; int32_t x2 = (i * 71) % screenW; int32_t y2 = (i * 89) % screenH; drv->lineDraw(drv, x1, y1, x2, y2, packColor16(255, 255, 255)); } drv->waitIdle(drv); clock_t hwLineEnd = clock(); // Benchmark host blit (CPU-to-screen) int32_t bytesPerPix = (drv->mode.bpp + 7) / 8; int32_t hblitPitch = HBLIT_PAT_W * bytesPerPix; uint8_t *hblitBuf = (uint8_t *)malloc(hblitPitch * HBLIT_PAT_H); clock_t hwHblitEnd = 0; clock_t hwHblitStart = 0; bool hblitValid = false; if (hblitBuf) { // Fill buffer with a checkerboard pattern for (int32_t row = 0; row < HBLIT_PAT_H; row++) { for (int32_t col = 0; col < HBLIT_PAT_W; col++) { uint32_t color; if ((row / 8 + col / 8) & 1) { color = packColor16(255, 255, 0); } else { color = packColor16(0, 0, 128); } if (bytesPerPix == 2) { ((uint16_t *)(hblitBuf + row * hblitPitch))[col] = (uint16_t)color; } else if (bytesPerPix == 4) { ((uint32_t *)(hblitBuf + row * hblitPitch))[col] = color; } else { hblitBuf[row * hblitPitch + col] = (uint8_t)color; } } } hwHblitStart = clock(); for (int32_t i = 0; i < BENCH_HBLIT_COUNT; i++) { int32_t dx = (i * 37) % (screenW - HBLIT_PAT_W); int32_t dy = (i * 53) % (screenH - HBLIT_PAT_H); drv->hostBlit(drv, hblitBuf, hblitPitch, dx, dy, HBLIT_PAT_W, HBLIT_PAT_H); } drv->waitIdle(drv); hwHblitEnd = clock(); hblitValid = true; free(hblitBuf); } // Benchmark pattern fill static const uint8_t benchPattern[8] = { 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55 }; clock_t hwPatStart = clock(); for (int32_t i = 0; i < BENCH_PATFILL_COUNT; i++) { int32_t px = (i * 37) % (screenW - 100); int32_t py = (i * 53) % (screenH - 100); drv->rectFillPat(drv, px, py, 100, 100, benchPattern, packColor16(255, 255, 255), packColor16(0, 0, 0)); } drv->waitIdle(drv); clock_t hwPatEnd = clock(); // Calculate times in milliseconds double hwFillMs = (double)(hwFillEnd - hwFillStart) * 1000.0 / CLOCKS_PER_SEC; double swFillMs = (double)(swFillEnd - swFillStart) * 1000.0 / CLOCKS_PER_SEC; double hwBltMs = (double)(hwBltEnd - hwBltStart) * 1000.0 / CLOCKS_PER_SEC; double hwLineMs = (double)(hwLineEnd - hwLineStart) * 1000.0 / CLOCKS_PER_SEC; double hwHblitMs = (double)(hwHblitEnd - hwHblitStart) * 1000.0 / CLOCKS_PER_SEC; double hwPatMs = (double)(hwPatEnd - hwPatStart) * 1000.0 / CLOCKS_PER_SEC; // Store results, then restore text mode to print accelShutdown(drv); printf("\n=== Benchmark Results ===\n\n"); printf("Rectangle Fill (%d x 100x100):\n", BENCH_FILL_COUNT); printf(" Hardware: %.1f ms (%.0f rects/sec)\n", hwFillMs, BENCH_FILL_COUNT * 1000.0 / hwFillMs); printf(" Software: %.1f ms (%.0f rects/sec)\n", swFillMs, BENCH_FILL_COUNT * 1000.0 / swFillMs); if (swFillMs > 0) { printf(" Speedup: %.1fx\n", swFillMs / hwFillMs); } printf("\nBitBlt (%d x 100x100 screen-to-screen):\n", BENCH_BLIT_COUNT); printf(" Hardware: %.1f ms (%.0f blits/sec)\n", hwBltMs, BENCH_BLIT_COUNT * 1000.0 / hwBltMs); printf("\nLine Draw (%d lines):\n", BENCH_LINE_COUNT); printf(" Hardware: %.1f ms (%.0f lines/sec)\n", hwLineMs, BENCH_LINE_COUNT * 1000.0 / hwLineMs); if (hblitValid) { printf("\nHost Blit (%d x %dx%d CPU-to-screen):\n", BENCH_HBLIT_COUNT, HBLIT_PAT_W, HBLIT_PAT_H); printf(" Hardware: %.1f ms (%.0f blits/sec)\n", hwHblitMs, BENCH_HBLIT_COUNT * 1000.0 / hwHblitMs); } printf("\nPattern Fill (%d x 100x100):\n", BENCH_PATFILL_COUNT); printf(" Hardware: %.1f ms (%.0f fills/sec)\n", hwPatMs, BENCH_PATFILL_COUNT * 1000.0 / hwPatMs); printf("\nPress any key to exit...\n"); readKey(); } // ============================================================ // demoBitBlt // ============================================================ // // Demonstrates screen-to-screen BitBLT by filling colored // rectangles and then copying them around the screen. static void demoBitBlt(AccelDriverT *drv) { int32_t screenW = drv->mode.width; int32_t screenH = drv->mode.height; // Clear screen drv->rectFill(drv, 0, 0, screenW, screenH, 0); // Draw some source rectangles drv->rectFill(drv, 10, 10, 100, 100, packColor16(255, 0, 0)); drv->rectFill(drv, 120, 10, 100, 100, packColor16(0, 255, 0)); drv->rectFill(drv, 230, 10, 100, 100, packColor16(0, 0, 255)); drv->rectFill(drv, 340, 10, 100, 100, packColor16(255, 255, 0)); drv->waitIdle(drv); // Copy them diagonally across the screen for (int32_t i = 0; i < 5; i++) { int32_t offsetY = 120 + i * 60; if (offsetY + 100 > screenH) { break; } drv->bitBlt(drv, 10, 10, 10 + i * 30, offsetY, 430, 100); } drv->waitIdle(drv); } // ============================================================ // demoColorExpand // ============================================================ // // Demonstrates monochrome color expansion by rendering text-like // patterns. Creates a simple 8x16 glyph and renders it repeatedly. static void demoColorExpand(AccelDriverT *drv) { int32_t screenW = drv->mode.width; int32_t screenH = drv->mode.height; // Clear screen drv->rectFill(drv, 0, 0, screenW, screenH, packColor16(0, 0, 128)); drv->waitIdle(drv); // 8x16 glyph bitmaps for several characters static const uint8_t glyphA[16] = { 0x00, 0x18, 0x3C, 0x66, 0x66, 0xC3, 0xC3, 0xFF, 0xFF, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0x00, 0x00 }; static const uint8_t glyphB[16] = { 0x00, 0xFC, 0xC6, 0xC6, 0xC6, 0xFC, 0xC6, 0xC3, 0xC3, 0xC3, 0xC6, 0xFC, 0x00, 0x00, 0x00, 0x00 }; static const uint8_t glyphC[16] = { 0x00, 0x3E, 0x63, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0x63, 0x3E, 0x00, 0x00, 0x00, 0x00 }; static const uint8_t glyphD[16] = { 0x00, 0xFC, 0xC6, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC6, 0xFC, 0x00, 0x00, 0x00, 0x00 }; static const uint8_t glyphE[16] = { 0x00, 0xFF, 0xC0, 0xC0, 0xC0, 0xFE, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xFF, 0x00, 0x00, 0x00, 0x00 }; static const uint8_t glyphF[16] = { 0x00, 0xFF, 0xC0, 0xC0, 0xC0, 0xFE, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0x00, 0x00, 0x00, 0x00 }; static const uint8_t *glyphs[6] = { glyphA, glyphB, glyphC, glyphD, glyphE, glyphF }; #define NUM_GLYPHS 6 // Color pairs for different rows (foreground/background) static const uint8_t colorPairs[][6] = { // R G B R G B (fg, then bg) {255, 255, 255, 0, 0, 128}, // white on dark blue {255, 255, 0, 0, 0, 0}, // yellow on black { 0, 255, 0, 0, 64, 0}, // green on dark green {255, 128, 0, 64, 0, 0}, // orange on dark red { 0, 255, 255, 0, 0, 64}, // cyan on navy {255, 0, 255, 32, 0, 32}, // magenta on dark purple }; #define NUM_COLOR_PAIRS 6 int32_t cols = screenW / 8; int32_t rows = screenH / 16; for (int32_t row = 0; row < rows; row++) { int32_t pairIdx = row % NUM_COLOR_PAIRS; const uint8_t *pair = colorPairs[pairIdx]; uint32_t fg = packColor16(pair[0], pair[1], pair[2]); uint32_t bg = packColor16(pair[3], pair[4], pair[5]); for (int32_t col = 0; col < cols; col++) { const uint8_t *glyph = glyphs[(row + col) % NUM_GLYPHS]; drv->colorExpand(drv, glyph, 1, col * 8, row * 16, 8, 16, fg, bg); } } drv->waitIdle(drv); #undef NUM_GLYPHS #undef NUM_COLOR_PAIRS } // ============================================================ // demoFillRects // ============================================================ // // Demonstrates hardware rectangle fill with various colors // and sizes. Draws a pattern of overlapping rectangles. static void demoFillRects(AccelDriverT *drv) { int32_t screenW = drv->mode.width; int32_t screenH = drv->mode.height; // Clear screen to dark blue drv->rectFill(drv, 0, 0, screenW, screenH, packColor16(0, 0, 64)); drv->waitIdle(drv); // Draw concentric rectangles int32_t colors[][3] = { {255, 0, 0}, {0, 255, 0}, {0, 0, 255}, {255, 255, 0}, {255, 0, 255}, {0, 255, 255}, {255, 128, 0}, {128, 0, 255} }; int32_t numColors = 8; int32_t cx = screenW / 2; int32_t cy = screenH / 2; for (int32_t i = 0; i < numColors; i++) { int32_t size = 200 - i * 20; if (size < 10) { break; } uint32_t color = packColor16(colors[i][0], colors[i][1], colors[i][2]); drv->rectFill(drv, cx - size / 2, cy - size / 2, size, size, color); } // Draw a grid of small rectangles for (int32_t y = 10; y < screenH - 30; y += 25) { for (int32_t x = 10; x < 150; x += 25) { uint32_t color = packColor16((x * 7) & 0xFF, (y * 3) & 0xFF, ((x + y) * 5) & 0xFF); drv->rectFill(drv, x, y, 20, 20, color); } } // Draw grid on right side too for (int32_t y = 10; y < screenH - 30; y += 25) { for (int32_t x = screenW - 160; x < screenW - 10; x += 25) { uint32_t color = packColor16((x * 3) & 0xFF, (y * 7) & 0xFF, ((x + y) * 2) & 0xFF); drv->rectFill(drv, x, y, 20, 20, color); } } drv->waitIdle(drv); } // ============================================================ // demoHostBlit // ============================================================ // // Demonstrates CPU-to-screen blit by creating a colorful gradient // pattern in system RAM, then tiling copies across the screen. static void demoHostBlit(AccelDriverT *drv) { int32_t screenW = drv->mode.width; int32_t screenH = drv->mode.height; // Clear screen drv->rectFill(drv, 0, 0, screenW, screenH, 0); drv->waitIdle(drv); // Create a gradient tile in system RAM int32_t tileW = 64; int32_t tileH = 64; int32_t bytesPerPix = (drv->mode.bpp + 7) / 8; int32_t tilePitch = tileW * bytesPerPix; uint8_t *tileBuf = (uint8_t *)malloc(tilePitch * tileH); if (!tileBuf) { return; } // Fill tile with a radial gradient pattern int32_t cx = tileW / 2; int32_t cy = tileH / 2; for (int32_t row = 0; row < tileH; row++) { for (int32_t col = 0; col < tileW; col++) { int32_t dx = col - cx; int32_t dy = row - cy; int32_t dist = dx * dx + dy * dy; // Map distance to color -- creates concentric rings uint8_t r = (dist * 7) & 0xFF; uint8_t g = (dist * 3 + col * 4) & 0xFF; uint8_t b = (row * 8 + col * 2) & 0xFF; uint32_t color = packColor16(r, g, b); if (bytesPerPix == 2) { ((uint16_t *)(tileBuf + row * tilePitch))[col] = (uint16_t)color; } else if (bytesPerPix == 4) { ((uint32_t *)(tileBuf + row * tilePitch))[col] = color; } else { tileBuf[row * tilePitch + col] = (uint8_t)color; } } } // Tile the pattern across the screen for (int32_t y = 0; y + tileH <= screenH; y += tileH) { for (int32_t x = 0; x + tileW <= screenW; x += tileW) { drv->hostBlit(drv, tileBuf, tilePitch, x, y, tileW, tileH); } } drv->waitIdle(drv); // Draw a border around each tile using rect fills for contrast uint32_t borderColor = packColor16(255, 255, 255); for (int32_t y = 0; y + tileH <= screenH; y += tileH) { drv->rectFill(drv, 0, y, screenW, 1, borderColor); } for (int32_t x = 0; x + tileW <= screenW; x += tileW) { drv->rectFill(drv, x, 0, 1, screenH, borderColor); } drv->waitIdle(drv); free(tileBuf); } // ============================================================ // demoLines // ============================================================ // // Demonstrates hardware line drawing with a starburst pattern. static void demoLines(AccelDriverT *drv) { int32_t screenW = drv->mode.width; int32_t screenH = drv->mode.height; // Clear screen drv->rectFill(drv, 0, 0, screenW, screenH, 0); drv->waitIdle(drv); int32_t cx = screenW / 2; int32_t cy = screenH / 2; // Draw starburst from center for (int32_t i = 0; i < 360; i += 3) { // Simple integer approximation of sin/cos using a lookup // approach. For a demo, we just use the endpoint calculation. int32_t dx = 0; int32_t dy = 0; // Approximate angle -> direction int32_t radius = (screenH / 2) - 10; int32_t angle = i; // Crude trig via quadrant decomposition int32_t quadrant = (angle / 90) % 4; int32_t subAngle = angle % 90; // Linear interpolation within each quadrant (good enough for demo) int32_t frac = subAngle * radius / 90; int32_t comp = radius - frac; switch (quadrant) { case 0: dx = frac; dy = -comp; break; case 1: dx = comp; dy = frac; break; case 2: dx = -frac; dy = comp; break; case 3: dx = -comp; dy = -frac; break; } uint32_t color = packColor16( (i * 3) & 0xFF, (i * 5 + 100) & 0xFF, (i * 7 + 50) & 0xFF ); drv->lineDraw(drv, cx, cy, cx + dx, cy + dy, color); } // Draw border rectangle with lines uint32_t white = packColor16(255, 255, 255); drv->lineDraw(drv, 0, 0, screenW - 1, 0, white); drv->lineDraw(drv, screenW - 1, 0, screenW - 1, screenH - 1, white); drv->lineDraw(drv, screenW - 1, screenH - 1, 0, screenH - 1, white); drv->lineDraw(drv, 0, screenH - 1, 0, 0, white); drv->waitIdle(drv); } // ============================================================ // demoPatternFill // ============================================================ // // Demonstrates 8x8 pattern fills with several distinct patterns // drawn side by side in colored rectangles. static void demoPatternFill(AccelDriverT *drv) { int32_t screenW = drv->mode.width; int32_t screenH = drv->mode.height; // Clear screen to dark gray drv->rectFill(drv, 0, 0, screenW, screenH, packColor16(32, 32, 32)); drv->waitIdle(drv); // Define several 8x8 patterns static const uint8_t patCheckerboard[8] = { 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55 }; static const uint8_t patCrosshatch[8] = { 0xFF, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 }; static const uint8_t patDiagStripes[8] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 }; static const uint8_t patDots[8] = { 0x00, 0x22, 0x00, 0x88, 0x00, 0x22, 0x00, 0x88 }; static const uint8_t patHorzStripes[8] = { 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00 }; static const uint8_t patVertStripes[8] = { 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA }; struct { const uint8_t *pattern; uint32_t fg; uint32_t bg; } patterns[] = { {patCheckerboard, packColor16(255, 255, 255), packColor16(0, 0, 0)}, {patCrosshatch, packColor16(255, 255, 0), packColor16(0, 0, 128)}, {patDiagStripes, packColor16(0, 255, 0), packColor16(0, 64, 0)}, {patDots, packColor16(255, 0, 0), packColor16(64, 0, 0)}, {patHorzStripes, packColor16(0, 255, 255), packColor16(0, 0, 64)}, {patVertStripes, packColor16(255, 0, 255), packColor16(64, 0, 64)}, }; int32_t numPatterns = 6; // Arrange patterns in a 3x2 grid int32_t margin = 20; int32_t spacing = 10; int32_t cellW = (screenW - 2 * margin - (3 - 1) * spacing) / 3; int32_t cellH = (screenH - 2 * margin - (2 - 1) * spacing) / 2; for (int32_t i = 0; i < numPatterns; i++) { int32_t gridCol = i % 3; int32_t gridRow = i / 3; int32_t x = margin + gridCol * (cellW + spacing); int32_t y = margin + gridRow * (cellH + spacing); drv->rectFillPat(drv, x, y, cellW, cellH, patterns[i].pattern, patterns[i].fg, patterns[i].bg); } drv->waitIdle(drv); } // ============================================================ // isKeyPressed // ============================================================ // // Non-blocking check for a keypress using BIOS INT 16h. static bool isKeyPressed(void) { __dpmi_regs r; memset(&r, 0, sizeof(r)); r.h.ah = 0x11; // check for extended keystroke __dpmi_int(0x16, &r); return !(r.x.flags & 0x40); // ZF clear = key available } // ============================================================ // main // ============================================================ int main(int argc, char *argv[]) { int32_t reqW = DEFAULT_WIDTH; int32_t reqH = DEFAULT_HEIGHT; int32_t reqBpp = DEFAULT_BPP; if (argc >= 4) { reqW = atoi(argv[1]); reqH = atoi(argv[2]); reqBpp = atoi(argv[3]); } printf("DOS Accelerated Video Driver Demo\n"); printf("Requested mode: %ldx%ldx%ld\n\n", (long)reqW, (long)reqH, (long)reqBpp); // Register all available drivers atiRegisterDriver(); bansheeRegisterDriver(); clRegisterDriver(); etRegisterDriver(); lagunaRegisterDriver(); mgaRegisterDriver(); nvRegisterDriver(); s3RegisterDriver(); sisRegisterDriver(); tridentRegisterDriver(); // Detect hardware printf("Scanning PCI bus for supported video hardware...\n"); AccelDriverT *drv = accelDetect(); if (!drv) { printf("No supported video hardware found.\n"); printf("\nPCI video devices present:\n"); // Enumerate and display all VGA-class PCI devices for diagnostics for (int32_t bus = 0; bus < 256; bus++) { for (int32_t dev = 0; dev < 32; dev++) { uint16_t vid = pciRead16(bus, dev, 0, PCI_VENDOR_ID); if (vid == 0xFFFF) { continue; } uint8_t baseClass = pciRead8(bus, dev, 0, PCI_BASE_CLASS); if (baseClass == PCI_CLASS_DISPLAY) { uint16_t did = pciRead16(bus, dev, 0, PCI_DEVICE_ID); printf(" %02lX:%02lX.0 vendor=%04X device=%04X\n", (long)bus, (long)dev, vid, did); } } } return 1; } // Initialize with requested mode AccelModeRequestT modeReq; modeReq.width = reqW; modeReq.height = reqH; modeReq.bpp = reqBpp; if (!accelInit(drv, &modeReq)) { printf("Failed to initialize video driver.\n"); return 1; } printf("\nDriver: %s\n", accelGetName(drv)); printf("Mode: %ldx%ldx%ld (pitch=%ld)\n", (long)drv->mode.width, (long)drv->mode.height, (long)drv->mode.bpp, (long)drv->mode.pitch); printf("VRAM: %lu KB\n", (unsigned long)(drv->mode.vramSize / 1024)); printf("\nPress any key to start demos...\n"); printf(" SPACE = next demo\n"); printf(" B = benchmark\n"); printf(" ESC = exit\n"); readKey(); // Run demos in a loop int32_t currentDemo = 0; int32_t numDemos = 6; bool running = true; while (running) { switch (currentDemo) { case 0: demoFillRects(drv); break; case 1: demoBitBlt(drv); break; case 2: demoLines(drv); break; case 3: demoColorExpand(drv); break; case 4: demoHostBlit(drv); break; case 5: demoPatternFill(drv); break; } // Wait for keypress while (!isKeyPressed()) { // spin } uint8_t key = readKey(); switch (key) { case 0x01: // ESC running = false; break; case 0x30: // 'b' demoBenchmark(drv); return 0; // benchmark already shut down the driver case 0x39: // space currentDemo = (currentDemo + 1) % numDemos; break; default: currentDemo = (currentDemo + 1) % numDemos; break; } } accelShutdown(drv); printf("Demo complete.\n"); return 0; } // ============================================================ // packColor16 // ============================================================ // // Packs an RGB triplet into 16-bit 565 format. // This is a simplification -- a real integration would use the // display's actual pixel format. For the demo, 565 is fine since // that's what most 16-bit VESA modes use. static uint32_t packColor16(uint8_t r, uint8_t g, uint8_t b) { return ((uint32_t)(r >> 3) << 11) | ((uint32_t)(g >> 2) << 5) | ((uint32_t)(b >> 3)); } // ============================================================ // readKey // ============================================================ // // Blocking read of one keypress via BIOS INT 16h. // Returns the scan code. static uint8_t readKey(void) { __dpmi_regs r; memset(&r, 0, sizeof(r)); r.h.ah = 0x10; // read extended keystroke __dpmi_int(0x16, &r); return r.h.ah; // scan code } // ============================================================ // softFillRect // ============================================================ // // Software rectangle fill for benchmark comparison. Writes // directly to the LFB (intentionally slow due to PCI bus writes). static void softFillRect(AccelDriverT *drv, int32_t x, int32_t y, int32_t w, int32_t h, uint32_t color) { uint8_t *fb = drv->mode.framebuffer; int32_t pitch = drv->mode.pitch; int32_t bpp = (drv->mode.bpp + 7) / 8; for (int32_t row = 0; row < h; row++) { uint8_t *dst = fb + (y + row) * pitch + x * bpp; if (bpp == 2) { uint16_t *dst16 = (uint16_t *)dst; for (int32_t col = 0; col < w; col++) { dst16[col] = (uint16_t)color; } } else if (bpp == 4) { uint32_t *dst32 = (uint32_t *)dst; for (int32_t col = 0; col < w; col++) { dst32[col] = color; } } else { for (int32_t col = 0; col < w; col++) { dst[col] = (uint8_t)color; } } } }