FreeBASIC  0.91.0
gfx_driver_bios.c
Go to the documentation of this file.
1 /* BIOS gfx driver */
2 
3 #include "../fb_gfx.h"
4 #include "fb_gfx_dos.h"
5 #include <go32.h>
6 #include <pc.h>
7 
8 typedef void (*fnUpdate)(void);
9 
10 static int driver_init(char *title, int w, int h, int depth, int refresh_rate, int flags);
11 static void driver_update_bpp1(void);
12 static void driver_update_bpp2(void);
13 static void driver_update_bpp4(void);
14 static void end_of_driver_update(void);
15 static int *driver_fetch_modes(int depth, int *size);
16 
18 {
19  "BIOS", /* char *name; */
20  driver_init, /* int (*init)(char *title, int w, int h, int depth, int refresh_rate, int flags); */
21  fb_dos_exit, /* void (*exit)(void); */
22  fb_dos_lock, /* void (*lock)(void); */
23  fb_dos_unlock, /* void (*unlock)(void); */
24  fb_dos_set_palette, /* void (*set_palette)(int index, int r, int g, int b); */
25  fb_dos_vga_wait_vsync, /* void (*wait_vsync)(void); */
26  fb_dos_get_mouse, /* int (*get_mouse)(int *x, int *y, int *z, int *buttons, int *clip); */
27  fb_dos_set_mouse, /* void (*set_mouse)(int x, int y, int cursor, int clip); */
28  fb_dos_set_window_title, /* void (*set_window_title)(char *title); */
29  NULL, /* int (*set_window_pos)(int x, int y); */
30  driver_fetch_modes, /* int *(*fetch_modes)(int depth, int *size); */
31  NULL, /* void (*flip)(void); */
32  NULL /* void (*poll_events)(void); */
33 };
34 
35 static const int res_bpp1[] = {
36  SCREENLIST(640, 200), /* 0x06 */
37  SCREENLIST(640, 350), /* 0x0F */
38  SCREENLIST(640, 480), /* 0x11 */
39  0
40 };
41 static const unsigned char mode_bpp1[] = {
42  0x06, 0x0F, 0x11, 0
43 };
44 static const int res_bpp2[] = {
45  SCREENLIST(320, 200), /* 0x04 */
46  0
47 };
48 static const unsigned char mode_bpp2[] = {
49  0x04, 0
50 };
51 static const int res_bpp4[] = {
52 #if 0
53  SCREENLIST(320, 200), /* 0x0D */
54  SCREENLIST(640, 200), /* 0x0E */
55 #endif
56  SCREENLIST(640, 350), /* 0x10 */
57  SCREENLIST(640, 480), /* 0x12 */
58  0
59 };
60 static const unsigned char mode_bpp4[] = {
61 #if 0
62  0x0D, 0x0E,
63 #endif
64  0x10, 0x12,
65  0
66 };
67 
68 typedef struct _driver_depth_modes {
69  int bit_depth;
70  const int * resolutions;
71  const unsigned char * modes;
74 
75 static const driver_depth_modes scr_modes[] = {
79 };
80 
81 #define DRV_DEPTH_COUNT (sizeof(scr_modes)/sizeof(scr_modes[0]))
82 
83 static unsigned char uchScanLineBuffer[ 640 ];
84 
85 static int driver_init(char *title, int w, int h, int depth, int refresh_rate, int flags)
86 {
87  int i;
88  unsigned char uchNewMode;
89  const driver_depth_modes *depth_modes = NULL;
90  int iResCount, iFoundRes;
91 
92  fb_dos_detect();
93 
94  /* Remove this dumb "fake" scan line size */
95  h /= __fb_gfx->scanline_size;
96 
97  if (flags & DRIVER_OPENGL)
98  return -1;
99 
100  for( i=0; i!=DRV_DEPTH_COUNT; ++i ) {
101  if( scr_modes[i].bit_depth == depth ) {
102  depth_modes = scr_modes + i;
103  break;
104  }
105  }
106 
107  if (depth_modes == NULL)
108  return -1;
109 
110  iResCount = 0;
111  while( depth_modes->resolutions[ iResCount ]!=0 )
112  ++iResCount;
113 
114  iFoundRes = iResCount;
115  for( i=0; i!=iResCount; ++i ) {
116  if( depth_modes->resolutions[ i ]==SCREENLIST( w, h ) ) {
117  iFoundRes = i;
118  break;
119  }
120  }
121 
122  if( iFoundRes==iResCount )
123  return -1;
124 
125  fb_dos.regs.h.ah = 0x00;
126  fb_dos.regs.h.al = depth_modes->modes[ iFoundRes ];
127  __dpmi_int(0x10, &fb_dos.regs);
128 
129  _movedatab( _dos_ds, 0x449, _my_ds(), (int) &uchNewMode, 1 );
130  if( uchNewMode!=depth_modes->modes[ iFoundRes ] )
131  return -1;
132 
133  /* We only need a scanline_size of 1 because the doubling will be done
134  * by the graphics card itself. */
135  __fb_gfx->scanline_size = 1;
136  refresh_rate = 70;
137 
138  fb_dos.bios_mode = depth_modes->modes[ iFoundRes ];
139  fb_dos.update = depth_modes->pfnUpdate;
140  fb_dos.update_len = (unsigned char*)end_of_driver_update - (unsigned char*)fb_dos.update;
141  if( fb_dos.bios_mode >= 0x11 ) {
142  /* 16 or 256 colors out of 64*64*64 (262144) */
144  } else if( fb_dos.bios_mode >= 0x0D ) {
145  /* FIXME: Implement setting the palette for EGA cards.
146  * (2 or 16 out of 64) */
148  } else {
149  /* FIXME: Implement setting the palette for CGA cards.
150  * Two sets of four colors. */
152  }
153 
154  return fb_dos_init(title, w, h, depth, refresh_rate, flags);
155 
156 }
157 
158 static void init_planar_access( void )
159 {
160  /* Write mask: Allow all bits */
161  outportb(0x3CE, 0x08);
162  outportb(0x3CF, 0xFF);
163 
164  /* Write mode: 0 */
165  outportb(0x3CE, 0x05);
166  outportb(0x3CF, 0x00);
167 
168  /* Overwrite mode, no rotation */
169  outportb(0x3CE, 0x03);
170  outportb(0x3CF, 0x00);
171 
172  /* Enable write access for plane "plane" */
173  outportb(0x3C4, 0x02);
174 }
175 
176 static void driver_update_planar_ega_vga( int planes )
177 {
178  /* EGA/VGA planar mode */
179  int y;
180  unsigned w = fb_dos.w, w8 = w >> 3, w32 = w >> 5;
181  unsigned char *buffer = (unsigned char *)__fb_gfx->framebuffer;
182  unsigned screen_offset = 0xA0000;
183  static const unsigned char vga_bitmap[8] = {
184  128, 64, 32, 16, 8, 4, 2, 1
185  };
186  static const unsigned char bitmask[4] = {
187  1, 2, 4, 8
188  };
189  unsigned uiDestOffset[4] = { 0, w8, w8*2, w8*3 };
190 
192 
193  for (y = 0;
194  y != fb_dos.h;
195  ++y)
196  {
197  if (__fb_gfx->dirty[y]) {
198  unsigned x, uiDestIndex = 0;
199  unsigned char *pFrameBuffer = buffer;
200  unsigned plane;
201 
202  /* Split "per pixel" color values into a plane oriented
203  * representation */
204  for( x=0; x!=w; x+=8 ) {
205  unsigned i;
206  for( plane=0; plane!=planes; ++plane ) {
207  unsigned char color_mask = bitmask[plane];
208  unsigned char pattern = 0;
209  for( i=0; i!=8; ++i ) {
210  if (pFrameBuffer[i] & color_mask)
211  pattern |= vga_bitmap[i];
212  }
213  uchScanLineBuffer[ uiDestOffset[plane] + uiDestIndex ] = pattern;
214  }
215  pFrameBuffer += 8;
216  ++uiDestIndex;
217  }
218  for( plane=0; plane!=planes; ++plane ) {
219  outportb(0x3C5, bitmask[plane] ); /* Select plane */
220  _movedatal(_my_ds(),
221  (int) uchScanLineBuffer + uiDestOffset[ plane ],
222  _dos_ds,
223  screen_offset,
224  w32);
225  }
226  }
227  buffer += w;
228  screen_offset += w8;
229  }
230 }
231 
232 static void driver_update_bpp1(void)
233 {
234  if( fb_dos.bios_mode==0x06 ) {
235  /* CGA interlaced mode */
236  int y, w = fb_dos.w, w4 = w >> 2, w8 = w >> 3, w32 = w >> 5;
237  unsigned int *buffer = (unsigned int *)__fb_gfx->framebuffer;
238  unsigned int screen_even = 0xB8000;
239  unsigned int screen_odd = 0xBA000;
240 
241  for (y = 0;
242  y != fb_dos.h;
243  ++y)
244  {
245  unsigned int *pScreenOffset = ( ((y & 1)==0) ? &screen_even : &screen_odd );
246  if (__fb_gfx->dirty[y]) {
247  unsigned dx = w8;
248  unsigned x = w4;
249  unsigned char uchDst = 0;
250  while( x-- ) {
251  unsigned value = buffer[x];
252  if( x & 1 ) {
253  uchDst = (unsigned char)
254  (
255  ((value & 0x01000000) >> 24) +
256  ((value & 0x00010000) >> 15) +
257  ((value & 0x00000100) >> 6) +
258  ((value & 0x00000001) << 3)
259  );
260  } else {
261  uchScanLineBuffer[dx--] = (unsigned char)
262  (
263  uchDst +
264  (
265  ((value & 0x01000000) >> 20) +
266  ((value & 0x00010000) >> 11) +
267  ((value & 0x00000100) >> 2) +
268  ((value & 0x00000001) << 7)
269  )
270  );
271  }
272  }
273  _movedatal(_my_ds(), (int) uchScanLineBuffer,
274  _dos_ds, *pScreenOffset,
275  w32);
276  }
277  buffer += w4;
278  *pScreenOffset += w8;
279  }
280  } else {
281  /* EGA/VGA linear mode */
282  int y, w = fb_dos.w, w4 = w >> 2, w8 = w >> 3, w32 = w >> 5;
283  unsigned int *buffer = (unsigned int *)__fb_gfx->framebuffer;
284  unsigned int screen_offset = 0xA0000;
285 
287  outportb(0x3C5, 0x0F); /* All planes */
288 
289  for (y = 0;
290  y != fb_dos.h;
291  ++y)
292  {
293  if (__fb_gfx->dirty[y]) {
294  unsigned dx = w8;
295  unsigned x = w4;
296  unsigned char uchDst = 0;
297  while( x-- ) {
298  unsigned value = buffer[x];
299  if( x & 1 ) {
300  uchDst = (unsigned char)
301  (
302  ((value & 0x01000000) >> 24) +
303  ((value & 0x00010000) >> 15) +
304  ((value & 0x00000100) >> 6) +
305  ((value & 0x00000001) << 3)
306  );
307  } else {
308  uchScanLineBuffer[dx--] = (unsigned char)
309  (
310  uchDst +
311  (
312  ((value & 0x01000000) >> 20) +
313  ((value & 0x00010000) >> 11) +
314  ((value & 0x00000100) >> 2) +
315  ((value & 0x00000001) << 7)
316  )
317  );
318  }
319  }
320  _movedatal(_my_ds(), (int) uchScanLineBuffer,
321  _dos_ds, screen_offset,
322  w32);
323  }
324  buffer += w4;
325  screen_offset += w8;
326  }
327  }
328 }
329 
330 static void driver_update_bpp2(void)
331 {
332  int y, w = fb_dos.w, w4 = w >> 2, w16 = w >> 4;
333  unsigned int *buffer = (unsigned int *)__fb_gfx->framebuffer;
334  unsigned int screen_even = 0xB8000;
335  unsigned int screen_odd = 0xBA000;
336 
337  for (y = 0;
338  y != fb_dos.h;
339  ++y)
340  {
341  unsigned int *pScreenOffset = ( ((y & 1)==0) ? &screen_even : &screen_odd );
342  if (__fb_gfx->dirty[y]) {
343  unsigned x = w4;
344  while( x-- ) {
345  unsigned value = buffer[x];
346  uchScanLineBuffer[x] = (unsigned char)
347  (
348  ((value & 0x03000000) >> 24) +
349  ((value & 0x00030000) >> 14) +
350  ((value & 0x00000300) >> 4) +
351  ((value & 0x00000003) << 6)
352  );
353  }
354  _movedatal(_my_ds(), (int) uchScanLineBuffer,
355  _dos_ds, *pScreenOffset,
356  w16);
357  }
358  buffer += w4;
359  *pScreenOffset += w4;
360  }
361 }
362 
363 static void driver_update_bpp4(void)
364 {
365  /* FIXME: This has to be implemented soon (to support SCREEN 12
366  * and others) */
367  if( fb_dos.bios_mode >= 0x10 ) {
369  }
370 }
371 static void end_of_driver_update(void) { /* do not remove */ }
372 
373 static int *driver_fetch_modes(int depth, int *size)
374 {
375  int i;
376  const driver_depth_modes *depth_modes = NULL;
377  int iResCount;
378 #ifdef DEBUG
379  int iModeCount;
380 #endif
381  for( i=0; i!=DRV_DEPTH_COUNT; ++i ) {
382  if( scr_modes[i].bit_depth == depth ) {
383  depth_modes = scr_modes + i;
384  break;
385  }
386  }
387 
388  if (depth_modes == NULL)
389  return NULL;
390 
391  iResCount = 0;
392  while( depth_modes->resolutions[ iResCount ]!=0 )
393  ++iResCount;
394 
395 #ifdef DEBUG
396  iModeCount = 0;
397  while( depth_modes->modes[ iModeCount ]!=0 )
398  ++iModeCount;
399  DBG_ASSERT( iModeCount==iResCount );
400 #endif
401 
402  *size = iResCount;
403  return memcpy((void*)malloc(iResCount * sizeof( int )),
404  depth_modes->resolutions, iResCount * sizeof( int ));
405 }