X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?p=dosdemo;a=blobdiff_plain;f=src%2Fdos%2Fgfx.c;h=48b5c2033c4dea1bc15d2091fdf510c76960e5e3;hp=46cec310e5eb9c64c6fb915e10fdcfdca5046f7a;hb=d956a9d9273eebfacfda58cb3bafff017269d5dc;hpb=0165ec15f868a16a70b56ada2d42db0cb69ea193 diff --git a/src/dos/gfx.c b/src/dos/gfx.c index 46cec31..48b5c20 100644 --- a/src/dos/gfx.c +++ b/src/dos/gfx.c @@ -1,205 +1,311 @@ -#ifndef GFX_H_ -#define GFX_H_ - #include #include #include -#include -#include "vbe.h" +#include "demo.h" #include "cdpmi.h" - -#ifdef __DJGPP__ -#include - -#define REALPTR(s, o) (void*)(((uint32_t)(s) << 4) - __djgpp_base_address + (uint32_t)(o)) -#else -#define REALPTR(s, o) (void*)(((uint32_t)(s) << 4) + (uint32_t)(o)) -#endif - -#define VBEPTR(x) REALPTR(((x) & 0xffff0000) >> 16, (x) & 0xffff) -#define VBEPTR_SEG(x) (((x) & 0xffff0000) >> 16) -#define VBEPTR_OFF(x) ((x) & 0xffff) +#include "gfx.h" +#include "vbe.h" +#include "vga.h" +#include "util.h" #define SAME_BPP(a, b) \ ((a) == (b) || ((a) == 16 && (b) == 15) || ((a) == 15 && (b) == 16) || \ ((a) == 32 && (b) == 24) || ((a) == 24 && (b) == 32)) -static unsigned int make_mask(int sz, int pos); +void (*blit_frame)(void*, int); -static struct vbe_info *vbe_info; -static struct vbe_mode_info *mode_info; -static int pal_bits = 6; +static void blit_frame_lfb(void *pixels, int vsync); +static void blit_frame_banked(void *pixels, int vsync); +static uint32_t calc_mask(int sz, int pos); -void *set_video_mode(int xsz, int ysz, int bpp) -{ - int i; - static uint16_t *modes; - uint16_t best = 0; - unsigned int fbsize; - -#ifdef __DJGPP__ - __djgpp_nearptr_enable(); -#endif - - /* check for VBE2 support and output some info */ - if(!vbe_info) { - if(!(vbe_info = vbe_get_info())) { - fprintf(stderr, "VESA BIOS Extensions not available\n"); - return 0; - } +static struct video_mode *vmodes; +static int num_vmodes; - printf("VBE Version: %x.%x\n", vbe_info->version >> 8, vbe_info->version & 0xff); - if(vbe_info->version < 0x200) { - fprintf(stderr, "This program requires VBE 2.0 or greater. Try running UniVBE\n"); - return 0; - } +static int vbe_init_ver; +static struct vbe_info vbe; + +/* current mode */ +static struct video_mode *curmode; +static void *vpgaddr[2]; +static int frontidx, backidx; +static int pgcount, pgsize, fbsize; + + +int init_video(void) +{ + int i, num, max_modes; + struct video_mode *vmptr; - printf("Graphics adapter: %s, %s (%s)\n", (char*)VBEPTR(vbe_info->oem_vendor_name_ptr), - (char*)VBEPTR(vbe_info->oem_product_name_ptr), (char*)VBEPTR(vbe_info->oem_product_rev_ptr)); - printf("Video memory: %dkb\n", vbe_info->total_mem << 6); + if(vbe_info(&vbe) == -1) { + fprintf(stderr, "failed to retrieve VBE information\n"); + return -1; + } + vbe_print_info(stdout, &vbe); - modes = VBEPTR(vbe_info->vid_mode_ptr); + num_vmodes = 0; + max_modes = 64; + if(!(vmodes = malloc(max_modes * sizeof *vmodes))) { + fprintf(stderr, "failed to allocate video modes list\n"); + return -1; } - for(i=0; i<1024; i++) { /* impose an upper limit to avoid inf-loops */ - if(modes[i] == 0xffff) { - break; /* reached the end */ - } + num = vbe_num_modes(&vbe); + for(i=0; ixres != xsz || mode_info->yres != ysz) { + if(vbe_mode_info(vbe.modes[i], &minf) == -1) { continue; } - if(SAME_BPP(mode_info->bpp, bpp)) { - best = modes[i]; + + if(num_vmodes >= max_modes) { + int newmax = max_modes ? (max_modes << 1) : 16; + if(!(vmptr = realloc(vmodes, newmax * sizeof *vmodes))) { + fprintf(stderr, "failed to grow video mode list (%d)\n", newmax); + free(vmodes); + return -1; + } + vmodes = vmptr; + max_modes = newmax; + } + + vmptr = vmodes + num_vmodes++; + memset(vmptr, 0, sizeof *vmptr); + vmptr->mode = vbe.modes[i]; + vmptr->xsz = minf.xres; + vmptr->ysz = minf.yres; + vmptr->bpp = minf.bpp; + vmptr->pitch = minf.scanline_bytes; + if(minf.mem_model == VBE_TYPE_DIRECT) { + vmptr->rbits = minf.rsize; + vmptr->gbits = minf.gsize; + vmptr->bbits = minf.bsize; + vmptr->rshift = minf.rpos; + vmptr->gshift = minf.gpos; + vmptr->bshift = minf.bpos; + vmptr->rmask = calc_mask(minf.rsize, minf.rpos); + vmptr->gmask = calc_mask(minf.gsize, minf.gpos); + vmptr->bmask = calc_mask(minf.bsize, minf.bpos); + vmptr->bpp = vmptr->rbits + vmptr->gbits + vmptr->bbits; } - } + if(minf.attr & VBE_ATTR_LFB) { + vmptr->fb_addr = minf.fb_addr; + } else { + vmptr->bank_size = (uint32_t)minf.bank_size * 1024; + if(!vmptr->bank_size) { + vmptr->bank_size = 65536; + } + } + vmptr->max_pages = minf.num_img_pages; - if(best) { - mode_info = vbe_get_mode_info(best); - } else { - fprintf(stderr, "Requested video mode (%dx%d %dbpp) is unavailable\n", xsz, ysz, bpp); - return 0; + printf("%04x: ", vbe.modes[i]); + vbe_print_mode_info(stdout, &minf); } + fflush(stdout); - if(vbe_set_mode(best | VBE_MODE_LFB) == -1) { - fprintf(stderr, "Failed to set video mode %dx%d %dbpp\n", mode_info->xres, mode_info->yres, mode_info->bpp); - return 0; - } + vbe_init_ver = VBE_VER_MAJOR(vbe.ver); + return 0; +} - /* attempt to set 8 bits of color per component in palettized modes */ - /*if(bpp <= 8) { - pal_bits = vbe_set_palette_bits(8); - printf("palette bits per color primary: %d\n", pal_bits); - } - */ +void cleanup_video(void) +{ + free(vmodes); +} - fbsize = xsz * ysz * mode_info->num_img_pages * (bpp / CHAR_BIT); - return (void*)dpmi_mmap(mode_info->fb_addr, fbsize); +struct video_mode *video_modes(void) +{ + return vmodes; } -int set_text_mode(void) +int num_video_modes(void) { - vbe_set_mode(0x3); - return 0; + return num_vmodes; } -int get_color_depth(void) +struct video_mode *get_video_mode(int idx) { - if(!mode_info) { - return -1; + if(idx == VMODE_CURRENT) { + return curmode; } - return mode_info->bpp; + return vmodes + idx; } -int get_color_bits(int *rbits, int *gbits, int *bbits) +int match_video_mode(int xsz, int ysz, int bpp) { - if(!mode_info) { + int i, best = -1; + struct video_mode *vm; + + for(i=0; ixsz != xsz || vm->ysz != ysz) continue; + if(SAME_BPP(vm->bpp, bpp)) { + best = i; + } + if(vm->bpp == bpp) break; + } + + if(best == -1) { + fprintf(stderr, "failed to find video mode %dx%d %d bpp)\n", xsz, ysz, bpp); return -1; } - *rbits = mode_info->rmask_size; - *gbits = mode_info->gmask_size; - *bbits = mode_info->bmask_size; - return 0; + return best; } -int get_color_mask(unsigned int *rmask, unsigned int *gmask, unsigned int *bmask) +int find_video_mode(int mode) { - if(!mode_info) { - return -1; + int i; + struct video_mode *vm; + + vm = vmodes; + for(i=0; imode == mode) return i; } - *rmask = make_mask(mode_info->rmask_size, mode_info->rpos); - *gmask = make_mask(mode_info->gmask_size, mode_info->gpos); - *bmask = make_mask(mode_info->bmask_size, mode_info->bpos); - return 0; + return -1; } -int get_color_shift(int *rshift, int *gshift, int *bshift) +void *set_video_mode(int idx, int nbuf) { - if(!mode_info) { - return -1; + unsigned int mode; + struct video_mode *vm = vmodes + idx; + + if(curmode == vm) return vpgaddr[0]; + + printf("setting video mode %x (%dx%d %d bpp)\n", (unsigned int)vm->mode, + vm->xsz, vm->ysz, vm->bpp); + fflush(stdout); + + mode = vm->mode | VBE_MODE_LFB; + if(vbe_setmode(mode) == -1) { + mode = vm->mode; + if(vbe_setmode(mode) == -1) { + fprintf(stderr, "failed to set video mode %x\n", (unsigned int)vm->mode); + return 0; + } + printf("Warning: failed to get a linear framebuffer. falling back to banked mode\n"); } - *rshift = mode_info->rpos; - *gshift = mode_info->gpos; - *bshift = mode_info->bpos; - return 0; + + /* unmap previous video memory mapping, if there was one (switching modes) */ + if(vpgaddr[0] && vpgaddr[0] != (void*)0xa0000) { + dpmi_munmap(vpgaddr[0]); + vpgaddr[0] = vpgaddr[1] = 0; + } + + curmode = vm; + if(nbuf < 1) nbuf = 1; + if(nbuf > 2) nbuf = 2; + pgcount = nbuf > vm->max_pages ? vm->max_pages : nbuf; + pgsize = vm->ysz * vm->pitch; + fbsize = pgcount * pgsize; + + printf("pgcount: %d, pgsize: %d, fbsize: %d\n", pgcount, pgsize, fbsize); + printf("phys addr: %p\n", (void*)vm->fb_addr); + fflush(stdout); + + if(vm->fb_addr) { + vpgaddr[0] = (void*)dpmi_mmap(vm->fb_addr, fbsize); + if(!vpgaddr[0]) { + fprintf(stderr, "failed to map framebuffer (phys: %lx, size: %d)\n", + (unsigned long)vm->fb_addr, fbsize); + set_text_mode(); + return 0; + } + memset(vpgaddr[0], 0xaa, pgsize); + + if(pgcount > 1) { + vpgaddr[1] = (char*)vpgaddr[0] + pgsize; + backidx = 1; + page_flip(FLIP_NOW); /* start with the second page visible */ + } else { + frontidx = backidx = 0; + vpgaddr[1] = 0; + } + + blit_frame = blit_frame_lfb; + + } else { + vpgaddr[0] = (void*)0xa0000; + vpgaddr[1] = 0; + + blit_frame = blit_frame_banked; + } + + /* allocate main memory framebuffer */ + if(demo_resizefb(vm->xsz, vm->ysz, vm->bpp) == -1) { + fprintf(stderr, "failed to allocate %dx%d (%d bpp) framebuffer\n", vm->xsz, + vm->ysz, vm->bpp); + set_text_mode(); + return 0; + } + + return vpgaddr[0]; } -void set_palette(int idx, int r, int g, int b) +int set_text_mode(void) { - int col[3]; - col[0] = r; - col[1] = g; - col[2] = b; - vbe_set_palette(idx, col, 1, pal_bits); + /* unmap previous video memory mapping, if there was one (switching modes) */ + if(vpgaddr[0] && vpgaddr[0] != (void*)0xa0000) { + dpmi_munmap(vpgaddr[0]); + vpgaddr[0] = vpgaddr[1] = 0; + } + + vga_setmode(3); + curmode = 0; + return 0; } -#ifdef __WATCOMC__ -void wait_vsync_asm(void); -#pragma aux wait_vsync_asm = \ - "mov dx, 0x3da" \ - "l1:" \ - "in al, dx" \ - "and al, 0x8" \ - "jnz l1" \ - "l2:" \ - "in al, dx" \ - "and al, 0x8" \ - "jz l2" \ - modify[al dx]; - -void wait_vsync(void) +void *page_flip(int vsync) { - wait_vsync_asm(); + if(!vpgaddr[1]) { + /* page flipping not supported */ + return vpgaddr[0]; + } + + vbe_swap(backidx ? pgsize : 0, vsync ? VBE_SWAP_VBLANK : VBE_SWAP_NOW); + frontidx = backidx; + backidx = (backidx + 1) & 1; + + return vpgaddr[backidx]; } -#endif -#ifdef __DJGPP__ -void wait_vsync(void) + +static void blit_frame_lfb(void *pixels, int vsync) { - asm volatile ( - "mov $0x3da, %%dx\n\t" - "0:\n\t" - "in %%dx, %%al\n\t" - "and $8, %%al\n\t" - "jnz 0b\n\t" - "0:\n\t" - "in %%dx, %%al\n\t" - "and $8, %%al\n\t" - "jz 0b\n\t" - :::"%eax","%edx"); + demo_post_draw(pixels); + + if(vsync) wait_vsync(); + memcpy64(vpgaddr[frontidx], pixels, pgsize >> 3); } -#endif -static unsigned int make_mask(int sz, int pos) +static void blit_frame_banked(void *pixels, int vsync) { - unsigned int i, mask = 0; + int i, sz, offs; + unsigned int pending; + unsigned char *pptr = pixels; + + demo_post_draw(pixels); + + if(vsync) wait_vsync(); + + /* assume initial window offset at 0 */ + offs = 0; + pending = pgsize; + while(pending > 0) { + sz = pending > curmode->bank_size ? curmode->bank_size : pending; + //memcpy64((void*)0xa0000, pptr, sz >> 3); + memcpy((void*)0xa0000, pptr, sz); + pptr += sz; + pending -= sz; + vbe_setwin(0, ++offs); + } + + vbe_setwin(0, 0); +} - for(i=0; i 0) { + mask = (mask << 1) | 1; } return mask << pos; } - - -#endif /* GFX_H_ */