more vbe
authorJohn Tsiombikas <nuclear@member.fsf.org>
Sun, 25 Jun 2023 03:41:31 +0000 (06:41 +0300)
committerJohn Tsiombikas <nuclear@member.fsf.org>
Sun, 25 Jun 2023 03:41:31 +0000 (06:41 +0300)
drv.h
drv_vbe.c
main.c
vidsys.c
vidsys.h

diff --git a/drv.h b/drv.h
index ef8ef30..172f146 100644 (file)
--- a/drv.h
+++ b/drv.h
@@ -15,6 +15,9 @@ struct vid_drvops {
 extern struct vid_driver *vid_drvlist[MAX_DRV];
 extern int vid_numdrv;
 
+extern void *vid_vmem;
+extern int vid_vmem_size;
+
 void vid_register_vga(void);           /* drv_vga.c */
 void vid_register_vbe(void);           /* drv_vbe.c */
 void vid_register_s3(void);            /* drv_s3.c */
index 59ec306..69c89eb 100644 (file)
--- a/drv_vbe.c
+++ b/drv_vbe.c
@@ -4,6 +4,7 @@
 #include "vidsys.h"
 #include "drv.h"
 #include "vbe.h"
+#include "vga.h"
 #include "cdpmi.h"
 
 #define farptr_to_linear(rmaddr) \
 
 static int init(void);
 static void cleanup(void);
+static struct vid_modeinfo *find_mode(int mode);
 static int setmode(int mode);
 static int getmode(void);
 static const char *memsize_str(long sz);
 static int get_mode_info(int mode, struct vbe_mode_info *mi);
+static int setwin(int wid, int pos);
 static int conv_vbeinfo(int mode, struct vid_modeinfo *mi, struct vbe_mode_info *vbemi);
 static unsigned int calc_mask(int nbits, int pos);
 
+static void pack(uint32_t *pix, int r, int g, int b);
+static void unpack(uint32_t pix, int *r, int *g, int *b);
+static void clear(uint32_t color);
+static void blitfb_lfb(void *fb, int pitch);
+static void blitfb_banked(void *fb, int pitch);
+static void flip(int vsync);
+
 static struct vid_driver drv;
 static struct vid_drvops drvops = {init, cleanup, setmode, getmode};
 static unsigned int vbe_ver;
 
 static int cur_mode;
+static struct vid_modeinfo *cur_mi;
+static int cur_pgsize;
 
 
 void vid_register_vbe(void)
@@ -46,6 +58,7 @@ static int init(void)
        struct vid_modeinfo modeinf;
 
        cur_mode = -1;
+       cur_mi = 0;
 
        vbe = dpmi_lowbuf();
        bufseg = (intptr_t)vbe >> 4;
@@ -55,7 +68,7 @@ static int init(void)
        regs.eax = 0x4f00;
        regs.es = bufseg;
        dpmi_rmint(0x10, &regs);
-       if(regs.eax != 0x4f || memcmp(vbe->sig, "VESA", 4) != 0) {
+       if((regs.eax & 0xffff) != 0x4f || memcmp(vbe->sig, "VESA", 4) != 0) {
                fprintf(stderr, "failed to get VBE controller information\n");
                return -1;
        }
@@ -114,24 +127,48 @@ static void cleanup(void)
        drv.num_modes = 0;
 }
 
+static struct vid_modeinfo *find_mode(int mode)
+{
+       int i;
+       for(i=0; i<drv.num_modes; i++) {
+               if(drv.modes[i].modeno == mode) {
+                       return drv.modes + i;
+               }
+       }
+       return 0;
+}
+
 static int setmode(int mode)
 {
+       struct vid_modeinfo *minf;
        struct dpmi_regs regs = {0};
 
+       if((minf = find_mode(mode)) && minf->lfb) {
+               mode |= VBE_MODE_LFB;
+       }
+
+retry:
        regs.eax = 0x4f02;
-       regs.ebx = mode | VBE_MODE_LFB;
+       regs.ebx = mode;
        dpmi_rmint(0x10, &regs);
 
-       if(regs.eax != 0x4f) {
-               regs.eax = 0x4f02;
-               regs.ebx = mode;
-               dpmi_rmint(0x10, &regs);
-               if(regs.eax != 0x4f) {
-                       return -1;
+       if((regs.eax & 0xffff) != 0x4f) {
+               if(mode & VBE_MODE_LFB) {
+                       mode &= ~VBE_MODE_LFB;
+                       goto retry;
                }
-               cur_mode = mode;
+               return -1;
+       }
+       cur_mode = mode;
+
+       if(!(cur_mi = minf)) return 0;
+
+       cur_pgsize = minf->height * minf->pitch;
+
+       if(mode & VBE_MODE_LFB) {
+               minf->ops.blitfb = blitfb_lfb;
        } else {
-               cur_mode = mode | VBE_MODE_LFB;
+               minf->ops.blitfb = blitfb_banked;
        }
        return 0;
 }
@@ -169,7 +206,7 @@ static int get_mode_info(int mode, struct vbe_mode_info *mi)
        regs.ecx = mode;
        regs.es = bufseg;
        dpmi_rmint(0x10, &regs);
-       if(regs.eax != 0x4f) {
+       if((regs.eax & 0xffff) != 0x4f) {
                return -1;
        }
 
@@ -177,8 +214,23 @@ static int get_mode_info(int mode, struct vbe_mode_info *mi)
        return 0;
 }
 
+static int setwin(int wid, int pos)
+{
+       struct dpmi_regs regs = {0};
+
+       regs.eax = 0x4f05;
+       regs.ebx = wid;
+       regs.edx = pos;
+       dpmi_rmint(0x10, &regs);
+       if((regs.eax & 0xffff) != 0x4f) {
+               return -1;
+       }
+       return 0;
+}
+
 static int conv_vbeinfo(int mode, struct vid_modeinfo *mi, struct vbe_mode_info *vbemi)
 {
+       static int gran_shift;
        static const struct { int width, height, bpp; } stdmode[] = {
                {640, 400, 8},          /* 100h */
                {640, 480, 8},          /* 101h */
@@ -235,6 +287,26 @@ static int conv_vbeinfo(int mode, struct vid_modeinfo *mi, struct vbe_mode_info
        mi->pitch = vbemi->scanline_bytes;
        mi->win_size = vbemi->win_size;
        mi->win_gran = vbemi->win_gran;
+
+       gran_shift = 0;
+       mi->win_step = 1;
+       if(mi->win_gran > 0 && mi->win_gran < 64) {
+               int gran = mi->win_gran;
+               while(gran < 64) {
+                       gran_shift++;
+                       gran <<= 1;
+               }
+               mi->win_step = 1 << gran_shift;
+       }
+
+       mi->ops.pack = pack;
+       mi->ops.unpack = unpack;
+       mi->ops.setpal = vga_setpal;
+       mi->ops.getpal = vga_getpal;
+       mi->ops.vsync = vga_vsync;
+       mi->ops.clear = clear;
+       mi->ops.blitfb = 0;
+       mi->ops.flip = flip;
        return 0;
 }
 
@@ -248,3 +320,61 @@ static unsigned int calc_mask(int nbits, int pos)
        }
        return mask << pos;
 }
+
+
+static void pack(uint32_t *pix, int r, int g, int b)
+{
+       *pix = (((uint32_t)r << cur_mi->rshift) & cur_mi->rmask) |
+               (((uint32_t)g << cur_mi->gshift) & cur_mi->gmask) |
+               (((uint32_t)b << cur_mi->bshift) & cur_mi->bmask);
+}
+
+static void unpack(uint32_t pix, int *r, int *g, int *b)
+{
+       *r = (pix & cur_mi->rmask) >> cur_mi->rshift;
+       *g = (pix & cur_mi->gmask) >> cur_mi->gshift;
+       *b = (pix & cur_mi->bmask) >> cur_mi->bshift;
+}
+
+static void clear(uint32_t color)
+{
+}
+
+static void blitfb_lfb(void *fb, int pitch)
+{
+       int i;
+       unsigned char *dest, *src;
+
+       dest = vid_vmem;
+       src = fb;
+
+       for(i=0; i<cur_mi->height; i++) {
+               memcpy(dest, src, cur_mi->pitch);
+               dest += cur_mi->pitch;
+               src += pitch;
+       }
+}
+
+static void blitfb_banked(void *fb, int pitch)
+{
+       int sz, offs, pending;
+       unsigned char *pptr = fb;
+
+       /* assume initial window offset at 0 */
+       offs = 0;
+       pending = cur_pgsize;
+       while(pending > 0) {
+               sz = pending > 65536 ? 65536 : pending;
+               memcpy((void*)0xa0000, pptr, sz);
+               pptr += sz;
+               pending -= sz;
+               offs += cur_mi->win_step;
+               setwin(0, offs);
+       }
+       setwin(0, 0);
+}
+
+static void flip(int vsync)
+{
+       /* TODO */
+}
diff --git a/main.c b/main.c
index 4b7ad18..ed2377e 100644 (file)
--- a/main.c
+++ b/main.c
@@ -8,13 +8,53 @@ void test8bpp(void);
 struct vid_modeinfo *vm;
 void *vmem;
 
+static const char *usage_fmt = "Usage %s: [options]\n"
+       "Options:      \n"
+       " -s <XxY>: video resolution\n"
+       " -b <bpp>: color depth\n";
+
 int main(int argc, char **argv)
 {
+       int i;
        int mode;
        int xres = 320;
        int yres = 200;
        int bpp = 8;
 
+       for(i=1; i<argc; i++) {
+               if(argv[i][0] == '-') {
+                       if(argv[i][2]) {
+invalopt:              fprintf(stderr, "invalid option: %s\n", argv[i]);
+                               return 1;
+                       }
+                       switch(argv[i][1]) {
+                       case 's':
+                               if(!argv[++i] || sscanf(argv[i], "%dx%d", &xres, &yres) != 2) {
+                                       fprintf(stderr, "invalid resolution: %s\n", argv[i]);
+                                       return 1;
+                               }
+                               break;
+
+                       case 'b':
+                               if(!argv[++i] || (bpp = atoi(argv[i])) <= 0) {
+                                       fprintf(stderr, "invalid color depth: %s\n", argv[i]);
+                                       return 1;
+                               }
+
+                       case 'h':
+                               printf(usage_fmt, argv[0]);
+                               return 0;
+
+                       default:
+                               goto invalopt;
+                       }
+               } else {
+                       fprintf(stderr, "unexpected argument: %s\n", argv[i]);
+                       return 1;
+               }
+       }
+
+
        if(vid_init() == -1) {
                fprintf(stderr, "failed to initialize video\n");
                return 1;
index 66f6811..01c8c81 100644 (file)
--- a/vidsys.c
+++ b/vidsys.c
@@ -2,21 +2,24 @@
 #include <stdlib.h>
 #include <assert.h>
 #include "vidsys.h"
+#include "vga.h"
 #include "drv.h"
 #include "cdpmi.h"
 
 struct vid_driver *vid_drvlist[MAX_DRV];
 int vid_numdrv;
 
+void *vid_vmem;
+int vid_vmem_size;
+
 static struct vid_modeinfo **modes, *cur_mode;
 static int num_modes, max_modes;
 
-static void *vmem;
-static int vmem_size;
 
 int vid_init(void)
 {
-       int i, j;
+       int i, j, len;
+       struct vid_modeinfo *vm;
 
        vid_numdrv = 0;
        free(modes);
@@ -24,8 +27,8 @@ int vid_init(void)
        cur_mode = 0;
        num_modes = max_modes = 0;
 
-       vmem = 0;
-       vmem_size = 0;
+       vid_vmem = 0;
+       vid_vmem_size = 0;
 
        if(dpmi_init() == -1) {
                return -1;
@@ -57,9 +60,18 @@ int vid_init(void)
        }
 
        printf("found %d modes:\n", num_modes);
-       for(i=0; i<num_modes; i++) {
-               printf("[%6s] %04x: %dx%d %dbpp\n", modes[i]->drv->name, modes[i]->modeno,
-                               modes[i]->width, modes[i]->height, modes[i]->bpp);
+       for(i=0; i<num_modes; i+=2) {
+               vm = modes[i];
+               len = printf("[%4s] %04x: %dx%d %dbpp", vm->drv->name, vm->modeno,
+                               vm->width, vm->height, vm->bpp);
+               if(i + 1 >= num_modes) {
+                       putchar('\n');
+                       break;
+               }
+               for(j=len; j<40; j++) putchar(' ');
+               vm = modes[i + 1];
+               printf("[%4s] %04x: %dx%d %dbpp\n", vm->drv->name, vm->modeno,
+                               vm->width, vm->height, vm->bpp);
        }
 
        return 0;
@@ -73,8 +85,8 @@ void vid_cleanup(void)
                vid_setmode(3);
        }
 
-       if(vmem >= (void*)0x100000) {
-               dpmi_munmap(vmem);
+       if(vid_vmem >= (void*)0x100000) {
+               dpmi_munmap(vid_vmem);
        }
 
        for(i=0; i<vid_numdrv; i++) {
@@ -106,19 +118,19 @@ void *vid_setmode(int mode)
                        if(drv->ops->setmode(mode) == 0) {
                                cur_mode = modes[i];
 
-                               if(vmem >= (void*)0x100000) {
-                                       assert(vmem_size);
-                                       dpmi_munmap(vmem);
+                               if(vid_vmem >= (void*)0x100000) {
+                                       assert(vid_vmem_size);
+                                       dpmi_munmap(vid_vmem);
                                }
 
                                if(modes[i]->vmem_addr < 0x100000) {
-                                       vmem = (void*)modes[i]->vmem_addr;
-                                       vmem_size = 0;
+                                       vid_vmem = (void*)modes[i]->vmem_addr;
+                                       vid_vmem_size = 0;
                                } else {
-                                       vmem = dpmi_mmap(modes[i]->vmem_addr, modes[i]->vmem_size);
-                                       vmem_size = modes[i]->vmem_size;
+                                       vid_vmem = dpmi_mmap(modes[i]->vmem_addr, modes[i]->vmem_size);
+                                       vid_vmem_size = modes[i]->vmem_size;
                                }
-                               return vmem;
+                               return vid_vmem;
                        }
                }
        }
index 34e35ed..bcf7837 100644 (file)
--- a/vidsys.h
+++ b/vidsys.h
@@ -45,7 +45,7 @@ struct vid_modeinfo {
        uint32_t rmask, gmask, bmask;
        int rshift, gshift, bshift;
        int pages;
-       int win_size, win_gran;
+       int win_size, win_gran, win_step;
        uint32_t vmem_addr;
        size_t vmem_size;
        int lfb;