initial commit
[xdos] / src / dos / gfx.c
1 #ifndef GFX_H_
2 #define GFX_H_
3
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include "vbe.h"
8 #include "logger.h"
9
10 #define REALPTR(s, o)   (void*)(((uint32_t)(s) << 4) + (uint32_t)(o))
11 #define VBEPTR(x)               REALPTR(((x) & 0xffff0000) >> 16, (x) & 0xffff)
12 #define VBEPTR_SEG(x)   (((x) & 0xffff0000) >> 16)
13 #define VBEPTR_OFF(x)   ((x) & 0xffff)
14
15 #define SAME_BPP(a, b)  \
16         ((a) == (b) || (a) == 16 && (b) == 15 || (a) == 15 && (b) == 16 || (a) == 32 && (b) == 24 || (a) == 24 && (b) == 32)
17
18 static unsigned int make_mask(int sz, int pos);
19
20 static struct vbe_info *vbe_info;
21 static struct vbe_mode_info *mode_info;
22 static int pal_bits = 6;
23
24 void *set_video_mode(int xsz, int ysz, int bpp)
25 {
26         int i;
27         uint16_t *modes, best = 0;
28         unsigned int fbsize;
29
30         /* check for VBE2 support and output some info */
31         if(!vbe_info) {
32                 if(!(vbe_info = vbe_get_info())) {
33                         fprintf(stderr, "VESA BIOS Extensions not available\n");
34                         return 0;
35                 }
36
37                 printlog("VBE Version: %x.%x\n", vbe_info->version >> 8, vbe_info->version & 0xff);
38                 if(vbe_info->version < 0x200) {
39                         fprintf(stderr, "This program requires VBE 2.0 or greater. Try running UniVBE\n");
40                         return 0;
41                 }
42
43                 printlog("Graphics adapter: %s, %s (%s)\n", VBEPTR(vbe_info->oem_vendor_name_ptr),
44                                 VBEPTR(vbe_info->oem_product_name_ptr), VBEPTR(vbe_info->oem_product_rev_ptr));
45                 printlog("Video memory: %dmb\n", vbe_info->total_mem << 6);
46
47                 modes = VBEPTR(vbe_info->vid_mode_ptr);
48         }
49
50         for(i=0; i<1024; i++) { /* impose an upper limit to avoid inf-loops */
51                 if(modes[i] == 0xffff) {
52                         break;  /* reached the end */
53                 }
54
55                 mode_info = vbe_get_mode_info(modes[i] | VBE_MODE_LFB);
56                 if(!mode_info || mode_info->xres != xsz || mode_info->yres != ysz) {
57                         continue;
58                 }
59                 if(SAME_BPP(mode_info->bpp, bpp)) {
60                         best = modes[i];
61                 }
62         }
63
64         if(best) {
65                 mode_info = vbe_get_mode_info(best);
66         } else {
67                 fprintf(stderr, "Requested video mode (%dx%d %dbpp) is unavailable\n", xsz, ysz, bpp);
68                 return 0;
69         }
70
71         if(vbe_set_mode(best | VBE_MODE_LFB) == -1) {
72                 fprintf(stderr, "Failed to set video mode %dx%d %dbpp\n", mode_info->xres, mode_info->yres, mode_info->bpp);
73                 return 0;
74         }
75
76         /* attempt to set 8 bits of color per component in palettized modes */
77         if(bpp <= 8) {
78                 pal_bits = vbe_set_palette_bits(8);
79                 printlog("palette bits per color primary: %d\n", pal_bits);
80         }
81
82         fbsize = xsz * ysz * mode_info->num_img_pages * (bpp / CHAR_BIT);
83         return (void*)dpmi_mmap(mode_info->fb_addr, fbsize);
84 }
85
86 int set_text_mode(void)
87 {
88         vbe_set_mode(0x3);
89         return 0;
90 }
91
92 int get_color_depth(void)
93 {
94         if(!mode_info) {
95                 return -1;
96         }
97         return mode_info->bpp;
98 }
99
100 int get_color_bits(int *rbits, int *gbits, int *bbits)
101 {
102         if(!mode_info) {
103                 return -1;
104         }
105         *rbits = mode_info->rmask_size;
106         *gbits = mode_info->gmask_size;
107         *bbits = mode_info->bmask_size;
108         return 0;
109 }
110
111 int get_color_mask(unsigned int *rmask, unsigned int *gmask, unsigned int *bmask)
112 {
113         if(!mode_info) {
114                 return -1;
115         }
116         *rmask = make_mask(mode_info->rmask_size, mode_info->rpos);
117         *gmask = make_mask(mode_info->gmask_size, mode_info->gpos);
118         *bmask = make_mask(mode_info->bmask_size, mode_info->bpos);
119         return 0;
120 }
121
122 int get_color_shift(int *rshift, int *gshift, int *bshift)
123 {
124         if(!mode_info) {
125                 return -1;
126         }
127         *rshift = mode_info->rpos;
128         *gshift = mode_info->gpos;
129         *bshift = mode_info->bpos;
130         return 0;
131 }
132
133 void set_palette(int idx, int r, int g, int b)
134 {
135         int col[3];
136         col[0] = r;
137         col[1] = g;
138         col[2] = b;
139         vbe_set_palette(idx, col, 1, pal_bits);
140 }
141
142 void wait_vsync(void)
143 {
144         /* TODO */
145 }
146
147 static unsigned int make_mask(int sz, int pos)
148 {
149         unsigned int i, mask = 0;
150
151         for(i=0; i<sz; i++) {
152                 mask |= 1 << i;
153         }
154         return mask << pos;
155 }
156
157
158 #endif  /* GFX_H_ */