8818ab995f14be72e5f61587ea935181b2797ea4
[dosdemo] / src / dos / gfx.c
1 #include <stdio.h>
2 #include "gfx.h"
3 #include "vbe.h"
4 #include "vga.h"
5 #include "cdpmi.h"
6
7 #ifdef __DJGPP__
8 #include <sys/nearptr.h>
9 #define REALPTR(s, o)   (void*)(((uint32_t)(s) << 4) - __djgpp_base_address + ((uint32_t)(o)))
10 #else
11 #define REALPTR(s, o)   (void*)(((uint32_t)(s) << 4) + ((uint32_t)(o)))
12 #endif
13
14 #define SAME_BPP(a, b)  \
15     ((a) == (b) || ((a) == 16 && (b) == 15) || ((a) == 15 && (b) == 16) || \
16      ((a) == 32 && (b) == 24) || ((a) == 24 && (b) == 32))
17
18 static int vbe_init_ver;
19 static struct vbe_info vbe;
20 static int mode, pgsize, fbsize;
21 static struct vbe_mode_info mode_info;
22
23 static void *vpgaddr[2];
24 static int fbidx;
25 static int pgcount;
26
27 static int init_vbe(void)
28 {
29         int i, num;
30
31         if(vbe_info(&vbe) == -1) {
32                 fprintf(stderr, "failed to retrieve VBE information\n");
33                 return -1;
34         }
35
36         vbe_print_info(stdout, &vbe);
37
38         num = vbe_num_modes(&vbe);
39         for(i=0; i<num; i++) {
40                 struct vbe_mode_info minf;
41
42                 if(vbe_mode_info(vbe.modes[i], &minf) == -1) {
43                         continue;
44                 }
45                 printf("%04x: ", vbe.modes[i]);
46                 vbe_print_mode_info(stdout, &minf);
47         }
48         fflush(stdout);
49
50         vbe_init_ver = VBE_VER_MAJOR(vbe.ver);
51         return 0;
52 }
53
54 void *set_video_mode(int xsz, int ysz, int bpp, int nbuf)
55 {
56         int i, nmodes;
57         int best_match_mode = -1;
58         struct vbe_mode_info minf;
59
60         if(!vbe_init_ver) {
61                 if(init_vbe() == -1) {
62                         fprintf(stderr, "failed to initialize VBE\n");
63                         return 0;
64                 }
65                 if(vbe_init_ver < 2) {
66                         fprintf(stderr, "VBE >= 2.0 required\n");
67                         return 0;
68                 }
69         }
70
71         mode = -1;
72         nmodes = vbe_num_modes(&vbe);
73         for(i=0; i<nmodes; i++) {
74                 if(vbe_mode_info(vbe.modes[i] | VBE_MODE_LFB, &minf) == -1) {
75                         continue;
76                 }
77                 if(minf.xres != xsz || minf.yres != ysz) continue;
78                 if(minf.bpp == bpp) {
79                         mode = vbe.modes[i];
80                         break;
81                 }
82                 if(SAME_BPP(minf.bpp, bpp)) {
83                         best_match_mode = mode;
84                 }
85         }
86
87         if(mode == -1) {
88                 if(best_match_mode == -1) {
89                         fprintf(stderr, "failed to find requested video mode (%dx%d %d bpp)\n", xsz, ysz, bpp);
90                         return 0;
91                 }
92                 mode = best_match_mode;
93         }
94
95         vbe_mode_info(mode, &mode_info);
96         printf("setting video mode %x: (%dx%d %d)\n", (unsigned int)mode, mode_info.xres,
97                         mode_info.yres, mode_info.bpp);
98
99         if(vbe_setmode(mode | VBE_MODE_LFB) == -1) {
100                 fprintf(stderr, "failed to set video mode\n");
101                 return 0;
102         }
103
104         if(nbuf < 1) nbuf = 1;
105         if(nbuf > 2) nbuf = 2;
106         pgcount = nbuf > mode_info.num_img_pages ? mode_info.num_img_pages : nbuf;
107
108         pgsize = mode_info.xres * mode_info.yres * (bpp / 8);
109         fbsize = pgcount * pgsize;
110
111         vpgaddr[0] = (void*)dpmi_mmap(mode_info.fb_addr, fbsize);
112         memset(vpgaddr[0], 0xaa, fbsize);
113
114         if(pgcount > 1) {
115                 vpgaddr[1] = (char*)vpgaddr[0] + pgsize;
116                 fbidx = 1;
117                 page_flip(FLIP_NOW);    /* start with the second page visible */
118         } else {
119                 fbidx = 0;
120                 vpgaddr[1] = 0;
121         }
122
123         return vpgaddr[0];
124 }
125
126 int set_text_mode(void)
127 {
128         vga_setmode(3);
129         return 0;
130 }
131
132 void *page_flip(int vsync)
133 {
134         if(!vpgaddr[1]) {
135                 /* page flipping not supported */
136                 return vpgaddr[0];
137         }
138
139         vbe_swap(fbidx ? pgsize : 0, vsync ? VBE_SWAP_VBLANK : VBE_SWAP_NOW);
140         fbidx = (fbidx + 1) & 1;
141
142         return vpgaddr[fbidx];
143 }