-#ifndef GFX_H_
-#define GFX_H_
-
#include <stdio.h>
-#include <stdlib.h>
#include <string.h>
-#include <limits.h>
+#include "gfx.h"
#include "vbe.h"
-#include "dpmi.h"
-#include "logger.h"
-
-#define REALPTR(s, o) (void*)(((uint32_t)(s) << 4) + (uint32_t)(o))
-#define VBEPTR(x) REALPTR(((x) & 0xffff0000) >> 16, (x) & 0xffff)
-#define VBEPTR_SEG(x) (((x) & 0xffff0000) >> 16)
-#define VBEPTR_OFF(x) ((x) & 0xffff)
+#include "vga.h"
+#include "cdpmi.h"
-#define SAME_BPP(a, b) \
- ((a) == (b) || (a) == 16 && (b) == 15 || (a) == 15 && (b) == 16 || (a) == 32 && (b) == 24 || (a) == 24 && (b) == 32)
+#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);
+static int vbe_init_ver;
+static struct vbe_info vbe;
+static int mode, pgsize, fbsize;
+static struct vbe_mode_info mode_info;
-static struct vbe_info *vbe_info;
-static struct vbe_mode_info *mode_info;
-static int pal_bits = 6;
+static void *vpgaddr[2];
+static int fbidx;
+static int pgcount;
-void *set_video_mode(int xsz, int ysz, int bpp)
+static int init_vbe(void)
{
- int i;
- uint16_t *modes, best = 0;
- unsigned int fbsize;
-
- /* 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;
- }
+ int i, num;
- printlog("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;
- }
+ if(vbe_info(&vbe) == -1) {
+ fprintf(stderr, "failed to retrieve VBE information\n");
+ return -1;
+ }
- printlog("Graphics adapter: %s, %s (%s)\n", VBEPTR(vbe_info->oem_vendor_name_ptr),
- VBEPTR(vbe_info->oem_product_name_ptr), VBEPTR(vbe_info->oem_product_rev_ptr));
- printlog("Video memory: %dkb\n", vbe_info->total_mem << 6);
+ vbe_print_info(stdout, &vbe);
- modes = VBEPTR(vbe_info->vid_mode_ptr);
+ num = vbe_num_modes(&vbe);
+ for(i=0; i<num; i++) {
+ struct vbe_mode_info minf;
+
+ if(vbe_mode_info(vbe.modes[i], &minf) == -1) {
+ continue;
+ }
+ printf("%04x: ", vbe.modes[i]);
+ vbe_print_mode_info(stdout, &minf);
}
+ fflush(stdout);
- for(i=0; i<1024; i++) { /* impose an upper limit to avoid inf-loops */
- if(modes[i] == 0xffff) {
- break; /* reached the end */
+ vbe_init_ver = VBE_VER_MAJOR(vbe.ver);
+ return 0;
+}
+
+void *set_video_mode(int xsz, int ysz, int bpp, int nbuf)
+{
+ int i, nmodes;
+ int best_match_mode = -1;
+ struct vbe_mode_info minf;
+
+ if(!vbe_init_ver) {
+ if(init_vbe() == -1) {
+ fprintf(stderr, "failed to initialize VBE\n");
+ return 0;
+ }
+ if(vbe_init_ver < 2) {
+ fprintf(stderr, "VBE >= 2.0 required\n");
+ return 0;
}
+ }
- mode_info = vbe_get_mode_info(modes[i] | VBE_MODE_LFB);
- if(!mode_info || mode_info->xres != xsz || mode_info->yres != ysz) {
+ mode = -1;
+ nmodes = vbe_num_modes(&vbe);
+ for(i=0; i<nmodes; i++) {
+ if(vbe_mode_info(vbe.modes[i], &minf) == -1) {
continue;
}
- if(SAME_BPP(mode_info->bpp, bpp)) {
- best = modes[i];
+ if(minf.xres != xsz || minf.yres != ysz) continue;
+ if(minf.bpp == bpp) {
+ mode = vbe.modes[i];
+ break;
+ }
+ if(SAME_BPP(minf.bpp, bpp)) {
+ best_match_mode = mode;
}
}
- 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;
+ if(mode == -1) {
+ if(best_match_mode == -1) {
+ fprintf(stderr, "failed to find requested video mode (%dx%d %d bpp)\n", xsz, ysz, bpp);
+ return 0;
+ }
+ mode = best_match_mode;
}
- 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);
+ vbe_mode_info(mode, &mode_info);
+ printf("setting video mode %x: (%dx%d %d)\n", (unsigned int)mode, mode_info.xres,
+ mode_info.yres, mode_info.bpp);
+
+ if(vbe_setmode(mode | VBE_MODE_LFB) == -1) {
+ fprintf(stderr, "failed to set video mode\n");
return 0;
}
- /* attempt to set 8 bits of color per component in palettized modes */
- /*if(bpp <= 8) {
- pal_bits = vbe_set_palette_bits(8);
- printlog("palette bits per color primary: %d\n", pal_bits);
- }
- */
+ if(nbuf < 1) nbuf = 1;
+ if(nbuf > 2) nbuf = 2;
+ pgcount = nbuf > mode_info.num_img_pages ? mode_info.num_img_pages : nbuf;
- fbsize = xsz * ysz * mode_info->num_img_pages * (bpp / CHAR_BIT);
- return (void*)dpmi_mmap(mode_info->fb_addr, fbsize);
-}
+ pgsize = mode_info.xres * mode_info.yres * (bpp / 8);
+ fbsize = pgcount * pgsize;
-int set_text_mode(void)
-{
- vbe_set_mode(0x3);
- return 0;
-}
-
-int get_color_depth(void)
-{
- if(!mode_info) {
- return -1;
- }
- return mode_info->bpp;
-}
+ vpgaddr[0] = (void*)dpmi_mmap(mode_info.fb_addr, fbsize);
+ memset(vpgaddr[0], 0xaa, fbsize);
-int get_color_bits(int *rbits, int *gbits, int *bbits)
-{
- if(!mode_info) {
- return -1;
+ if(pgcount > 1) {
+ vpgaddr[1] = (char*)vpgaddr[0] + pgsize;
+ fbidx = 1;
+ page_flip(FLIP_NOW); /* start with the second page visible */
+ } else {
+ fbidx = 0;
+ vpgaddr[1] = 0;
}
- *rbits = mode_info->rmask_size;
- *gbits = mode_info->gmask_size;
- *bbits = mode_info->bmask_size;
- return 0;
-}
-int get_color_mask(unsigned int *rmask, unsigned int *gmask, unsigned int *bmask)
-{
- if(!mode_info) {
- return -1;
- }
- *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 vpgaddr[0];
}
-int get_color_shift(int *rshift, int *gshift, int *bshift)
+int set_text_mode(void)
{
- if(!mode_info) {
- return -1;
- }
- *rshift = mode_info->rpos;
- *gshift = mode_info->gpos;
- *bshift = mode_info->bpos;
+ vga_setmode(3);
return 0;
}
-void set_palette(int idx, int r, int g, int b)
-{
- int col[3];
- col[0] = r;
- col[1] = g;
- col[2] = b;
- vbe_set_palette(idx, col, 1, pal_bits);
-}
-
-void wait_vsync(void)
+void *page_flip(int vsync)
{
- __asm {
- mov dx, 0x3da
- l1:
- in al, dx
- and al, 0x8
- jnz l1
- l2:
- in al, dx
- and al, 0x8
- jz l2
+ if(!vpgaddr[1]) {
+ /* page flipping not supported */
+ return vpgaddr[0];
}
-}
-static unsigned int make_mask(int sz, int pos)
-{
- unsigned int i, mask = 0;
+ vbe_swap(fbidx ? pgsize : 0, vsync ? VBE_SWAP_VBLANK : VBE_SWAP_NOW);
+ fbidx = (fbidx + 1) & 1;
- for(i=0; i<sz; i++) {
- mask |= 1 << i;
- }
- return mask << pos;
+ return vpgaddr[fbidx];
}
-
-
-#endif /* GFX_H_ */