VDB windows: render the actual gauge framebuffer (similar output)

Replace the palette-swatch windows with ones that render DOSBox's live gauge
framebuffer -- the M_LIN16 16bpp video memory (vga.mem.linear, 640x480, 5:6:5,
start=vga.config.real_start) via glDrawPixels. Each window now shows the real
gauge image, matching the DOSBox screen ("similar output"), confirmed live.
Diagnostic: the VDB splitter-on log now prints the framebuffer mode
(0x111 / M_LIN16 / 640x480) -- confirming direct color, so the palettes are
not index LUTs.

All three windows currently show the shared framebuffer identically; the
per-display palette decode (how the VDB carves the encoded 16bpp stream into
the six monitor outputs) is the next step.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Cyd
2026-07-03 19:55:53 -05:00
co-authored by Claude Opus 4.8
parent 7fead4f493
commit 1b973917fa
+42 -20
View File
@@ -33,6 +33,9 @@
#include "dosbox.h"
#include "inout.h"
#include "logging.h"
#include "mem.h"
#include "vga.h"
#include "../ints/int10.h"
#include <stdio.h>
#include <stdlib.h>
@@ -652,27 +655,40 @@ static void rt_draw(HDC dc, const VFrame &f, int cw, int ch) {
SwapBuffers(dc);
}
/* ---- VDB palette windows: one 640x480 window per display palette ---------
* Each shows a 16x16 grid of the 256 colors, updated live. */
/* ---- VDB display windows: one 640x480 window per display -----------------
* Renders the actual gauge framebuffer (DOSBox's 16bpp M_LIN16 video memory,
* the encoded video stream the VDB splits) so each window shows "similar
* output" to the DOSBox screen. (Palette-based per-display decode is TBD; for
* now all three show the shared framebuffer.) */
static void pal_draw(HDC dc, int g, int cw, int ch) {
glViewport(0, 0, cw, ch);
glClearColor(0.09f, 0.09f, 0.11f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glDisable(GL_DEPTH_TEST);
glDisable(GL_TEXTURE_2D);
glDisable(GL_LIGHTING);
glMatrixMode(GL_PROJECTION); glLoadIdentity();
glOrtho(0, 16, 16, 0, -1, 1); /* 16x16 grid, y-down */
glMatrixMode(GL_MODELVIEW); glLoadIdentity();
glBegin(GL_QUADS);
for (int i = 0; i < 256; i++) {
float x = (float)(i % 16), y = (float)(i / 16);
const unsigned char *e = &vdb_pal[g].ram[i * 3];
glColor3ub(e[0], e[1], e[2]);
glVertex2f(x, y); glVertex2f(x + 1, y);
glVertex2f(x + 1, y + 1); glVertex2f(x, y + 1);
const int W = 640, H = 480;
static unsigned char img[640 * 480 * 3];
const uint8_t *fb = vga.mem.linear;
Bitu mask = vga.draw.linear_mask ? vga.draw.linear_mask
: (vga.mem.memsize ? vga.mem.memsize - 1 : 0);
Bitu start = vga.config.real_start; /* visible page start (bytes) */
Bitu stride = (Bitu)W * 2; /* 16bpp */
if (fb) {
for (int y = 0; y < H; y++) {
Bitu ofs = start + (Bitu)y * stride;
unsigned char *d = &img[(size_t)y * W * 3];
for (int x = 0; x < W; x++, ofs += 2, d += 3) {
uint16_t px = *(const uint16_t *)(fb + (ofs & mask));
d[0] = (unsigned char)(((px >> 11) & 0x1F) * 255 / 31);
d[1] = (unsigned char)(((px >> 5) & 0x3F) * 255 / 63);
d[2] = (unsigned char)(( px & 0x1F) * 255 / 31);
}
}
} else {
memset(img, 0, sizeof img);
}
glEnd();
(void)g;
glViewport(0, 0, cw, ch);
glClearColor(0, 0, 0, 1); glClear(GL_COLOR_BUFFER_BIT);
glDisable(GL_DEPTH_TEST); glDisable(GL_TEXTURE_2D); glDisable(GL_LIGHTING);
glPixelZoom((float)cw / W, -(float)ch / H); /* scale + flip y */
glRasterPos2f(-1.0f, 1.0f);
glDrawPixels(W, H, GL_RGB, GL_UNSIGNED_BYTE, img);
SwapBuffers(dc);
}
@@ -1201,7 +1217,13 @@ static void vdb_write(Bitu port, Bitu val, Bitu /*iolen*/) {
io_port_t off = (io_port_t)port - VDB_BASE;
unsigned char v = (unsigned char)val;
if (port == 0x319) { vdb_splitter_on = false; vdb_note("splitter clock OFF (0x319)"); return; }
if (port == 0x31A) { vdb_splitter_on = true; vdb_note("splitter clock ON (0x31A)"); return; }
if (port == 0x31A) { vdb_splitter_on = true; vdb_note("splitter clock ON (0x31A)");
if (vpx_fp && CurMode) { flush_run();
fprintf(vpx_fp, "# VDB framebuffer mode: 0x%X type=%d %ux%u pitch=%u\n",
(unsigned)CurMode->mode, (int)CurMode->type,
(unsigned)CurMode->swidth, (unsigned)CurMode->sheight,
(unsigned)CurMode->pitch); fflush(vpx_fp); }
return; }
int g = vdb_group_of(off);
if (g < 0) return;
VDBPalette &p = vdb_pal[g];