41903ebe7998b95bee1546a0fee94c6ec1662e36
[mesa.git] / src / mesa / drivers / dos / video.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 4.0
4 *
5 * Copyright (C) 1999 Brian Paul All Rights Reserved.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25 /*
26 * DOS/DJGPP device driver v1.5 for Mesa
27 *
28 * Copyright (C) 2002 - Borca Daniel
29 * Email : dborca@users.sourceforge.net
30 * Web : http://www.geocities.com/dborca
31 *
32 * Thanks to CrazyPyro (Neil Funk) for FakeColor
33 */
34
35
36 #include <stdlib.h>
37
38 #include "internal.h"
39 #include "vesa.h"
40 #include "vga.h"
41 #include "video.h"
42
43
44
45 static vl_driver *drv;
46 /* based upon mode specific data: valid entire session */
47 int vl_video_selector;
48 static vl_mode *video_mode;
49 static int video_scanlen, video_bypp;
50 /* valid until next buffer */
51 void *vl_current_draw_buffer, *vl_current_read_buffer;
52 int vl_current_stride, vl_current_width, vl_current_height, vl_current_bytes;
53 int vl_current_offset, vl_current_delta;
54
55
56
57 #if HUGE_LOOKUP
58 /* These lookup tables are used to extract RGB values in [0,255]
59 * from 15/16-bit pixel values.
60 */
61 static unsigned char pix15r[0x8000];
62 static unsigned char pix15g[0x8000];
63 static unsigned char pix15b[0x8000];
64 static unsigned char pix16r[0x10000];
65 static unsigned char pix16g[0x10000];
66 static unsigned char pix16b[0x10000];
67 #else
68 /* lookup table for scaling 5 bit colors up to 8 bits */
69 static int _rgb_scale_5[32] = {
70 0, 8, 16, 25, 33, 41, 49, 58,
71 66, 74, 82, 90, 99, 107, 115, 123,
72 132, 140, 148, 156, 165, 173, 181, 189,
73 197, 206, 214, 222, 230, 239, 247, 255
74 };
75 #endif
76
77 /* lookup table for scaling 6 bit colors up to 8 bits */
78 static int _rgb_scale_6[64] = {
79 0, 4, 8, 12, 16, 20, 24, 28,
80 32, 36, 40, 45, 49, 53, 57, 61,
81 65, 69, 73, 77, 81, 85, 89, 93,
82 97, 101, 105, 109, 113, 117, 121, 125,
83 130, 134, 138, 142, 146, 150, 154, 158,
84 162, 166, 170, 174, 178, 182, 186, 190,
85 194, 198, 202, 206, 210, 215, 219, 223,
86 227, 231, 235, 239, 243, 247, 251, 255
87 };
88
89 /* FakeColor data */
90 #define R_CNT 6
91 #define G_CNT 6
92 #define B_CNT 6
93
94 #define R_BIAS 7
95 #define G_BIAS 7
96 #define B_BIAS 7
97
98 static word32 VGAPalette[256];
99 static word8 array_r[256];
100 static word8 array_g[256];
101 static word8 array_b[256];
102
103
104
105 int (*vl_mixfix) (fixed r, fixed g, fixed b);
106 int (*vl_mixrgb) (const unsigned char rgb[]);
107 int (*vl_mixrgba) (const unsigned char rgba[]);
108 void (*vl_getrgba) (unsigned int offset, unsigned char rgba[4]);
109 int (*vl_getpixel) (unsigned int offset);
110 void (*vl_clear) (int color);
111 void (*vl_rect) (int x, int y, int width, int height, int color);
112 void (*vl_flip) (void);
113 void (*vl_putpixel) (unsigned int offset, int color);
114
115
116
117 /* Desc: color composition (w/o ALPHA)
118 *
119 * In : R, G, B
120 * Out : color
121 *
122 * Note: -
123 */
124 static int vl_mixfix8fake (fixed r, fixed g, fixed b)
125 {
126 return array_b[b>>FIXED_SHIFT]*G_CNT*R_CNT
127 + array_g[g>>FIXED_SHIFT]*R_CNT
128 + array_r[r>>FIXED_SHIFT];
129 }
130 #define vl_mixfix8 vl_mixfix8fake
131 static int vl_mixfix15 (fixed r, fixed g, fixed b)
132 {
133 return ((r>>(3+FIXED_SHIFT))<<10)
134 |((g>>(3+FIXED_SHIFT))<<5)
135 |(b>>(3+FIXED_SHIFT));
136 }
137 static int vl_mixfix16 (fixed r, fixed g, fixed b)
138 {
139 return ((r>>(3+FIXED_SHIFT))<<11)
140 |((g>>(2+FIXED_SHIFT))<<5)
141 |(b>>(3+FIXED_SHIFT));
142 }
143 #define vl_mixfix24 vl_mixfix32
144 static int vl_mixfix32 (fixed r, fixed g, fixed b)
145 {
146 return ((r>>FIXED_SHIFT)<<16)
147 |((g>>FIXED_SHIFT)<<8)
148 |(b>>FIXED_SHIFT);
149 }
150
151
152
153 /* Desc: color composition (w/ ALPHA)
154 *
155 * In : array of integers (R, G, B, A)
156 * Out : color
157 *
158 * Note: -
159 */
160 #define vl_mixrgba8 vl_mixrgb8fake
161 #define vl_mixrgba15 vl_mixrgb15
162 #define vl_mixrgba16 vl_mixrgb16
163 #define vl_mixrgba24 vl_mixrgb24
164 static int vl_mixrgba32 (const unsigned char rgba[])
165 {
166 /* Hack alert:
167 * currently, DMesa uses Mesa's alpha buffer;
168 * so we don't really care about alpha value here...
169 */
170 return /*(rgba[3]<<24)|*/(rgba[0]<<16)|(rgba[1]<<8)|(rgba[2]);
171 }
172
173
174
175 /* Desc: color composition (w/o ALPHA)
176 *
177 * In : array of integers (R, G, B)
178 * Out : color
179 *
180 * Note: -
181 */
182 static int vl_mixrgb8fake (const unsigned char rgb[])
183 {
184 return array_b[rgb[2]]*G_CNT*R_CNT
185 + array_g[rgb[1]]*R_CNT
186 + array_r[rgb[0]];
187 }
188 #define vl_mixrgb8 vl_mixrgb8fake
189 static int vl_mixrgb15 (const unsigned char rgb[])
190 {
191 return ((rgb[0]>>3)<<10)|((rgb[1]>>3)<<5)|(rgb[2]>>3);
192 }
193 static int vl_mixrgb16 (const unsigned char rgb[])
194 {
195 return ((rgb[0]>>3)<<11)|((rgb[1]>>2)<<5)|(rgb[2]>>3);
196 }
197 #define vl_mixrgb24 vl_mixrgb32
198 static int vl_mixrgb32 (const unsigned char rgb[])
199 {
200 return (rgb[0]<<16)|(rgb[1]<<8)|(rgb[2]);
201 }
202
203
204
205 /* Desc: color decomposition
206 *
207 * In : pixel offset, array of integers to hold color components (R, G, B, A)
208 * Out : -
209 *
210 * Note: uses current read buffer
211 */
212 static void v_getrgba8fake6 (unsigned int offset, unsigned char rgba[4])
213 {
214 word32 c = VGAPalette[((word8 *)vl_current_read_buffer)[offset]];
215 rgba[0] = _rgb_scale_6[(c >> 16) & 0x3F];
216 rgba[1] = _rgb_scale_6[(c >> 8) & 0x3F];
217 rgba[2] = _rgb_scale_6[c & 0x3F];
218 /*rgba[3] = c >> 24;*/ /* dummy alpha; we have separate SW alpha, so ignore */
219 }
220 static void v_getrgba8fake8 (unsigned int offset, unsigned char rgba[4])
221 {
222 word32 c = VGAPalette[((word8 *)vl_current_read_buffer)[offset]];
223 rgba[0] = c >> 16;
224 rgba[1] = c >> 8;
225 rgba[2] = c;
226 /*rgba[3] = c >> 24;*/ /* dummy alpha; we have separate SW alpha, so ignore */
227 }
228 #define v_getrgba8 v_getrgba8fake6
229 static void v_getrgba15 (unsigned int offset, unsigned char rgba[4])
230 {
231 word32 c = ((word16 *)vl_current_read_buffer)[offset];
232 #if HUGE_LOOKUP
233 c &= 0x7fff;
234 rgba[0] = pix15r[c];
235 rgba[1] = pix15g[c];
236 rgba[2] = pix15b[c];
237 #else
238 rgba[0] = _rgb_scale_5[(c >> 10) & 0x1F];
239 rgba[1] = _rgb_scale_5[(c >> 5) & 0x1F];
240 rgba[2] = _rgb_scale_5[c & 0x1F];
241 #endif
242 /*rgba[3] = 255;*/ /* dummy alpha; we have separate SW alpha, so ignore */
243 }
244 static void v_getrgba16 (unsigned int offset, unsigned char rgba[4])
245 {
246 word32 c = ((word16 *)vl_current_read_buffer)[offset];
247 #if HUGE_LOOKUP
248 rgba[0] = pix16r[c];
249 rgba[1] = pix16g[c];
250 rgba[2] = pix16b[c];
251 #else
252 rgba[0] = _rgb_scale_5[(c >> 11) & 0x1F];
253 rgba[1] = _rgb_scale_6[(c >> 5) & 0x3F];
254 rgba[2] = _rgb_scale_5[c & 0x1F];
255 #endif
256 /*rgba[3] = 255;*/ /* dummy alpha; we have separate SW alpha, so ignore */
257 }
258 static void v_getrgba24 (unsigned int offset, unsigned char rgba[4])
259 {
260 word32 c = *(word32 *)((long)vl_current_read_buffer+offset*3);
261 rgba[0] = c >> 16;
262 rgba[1] = c >> 8;
263 rgba[2] = c;
264 /*rgba[3] = 255;*/ /* dummy alpha; we have separate SW alpha, so ignore */
265 }
266 static void v_getrgba32 (unsigned int offset, unsigned char rgba[4])
267 {
268 word32 c = ((word32 *)vl_current_read_buffer)[offset];
269 rgba[0] = c >> 16;
270 rgba[1] = c >> 8;
271 rgba[2] = c;
272 /*rgba[3] = c >> 24;*/ /* dummy alpha; we have separate SW alpha, so ignore */
273 }
274
275
276
277 /* Desc: pixel retrieval
278 *
279 * In : pixel offset
280 * Out : pixel value
281 *
282 * Note: uses current read buffer
283 */
284 static int v_getpixel8 (unsigned int offset)
285 {
286 return ((word8 *)vl_current_read_buffer)[offset];
287 }
288 #define v_getpixel15 v_getpixel16
289 static int v_getpixel16 (unsigned int offset)
290 {
291 return ((word16 *)vl_current_read_buffer)[offset];
292 }
293 static int v_getpixel24 (unsigned int offset)
294 {
295 return *(word32 *)((long)vl_current_read_buffer+offset*3);
296 }
297 static int v_getpixel32 (unsigned int offset)
298 {
299 return ((word32 *)vl_current_read_buffer)[offset];
300 }
301
302
303
304 /* Desc: set one palette entry
305 *
306 * In : index, R, G, B
307 * Out : -
308 *
309 * Note: color components are in range [0.0 .. 1.0]
310 */
311 void vl_setCI (int index, float red, float green, float blue)
312 {
313 drv->setCI_f(index, red, green, blue);
314 }
315
316
317
318 /* Desc: set one palette entry
319 *
320 * In : color, R, G, B
321 * Out : -
322 *
323 * Note: -
324 */
325 static void fake_setcolor (int c, int r, int g, int b)
326 {
327 VGAPalette[c] = 0xff000000 | (r<<16) | (g<<8) | b;
328
329 drv->setCI_i(c, r, g, b);
330 }
331
332
333
334 /* Desc: build FakeColor palette
335 *
336 * In : CI precision in bits
337 * Out : -
338 *
339 * Note: -
340 */
341 static void fake_buildpalette (int bits)
342 {
343 double c_r, c_g, c_b;
344 int r, g, b, color = 0;
345
346 double max = (1 << bits) - 1;
347
348 for (b=0; b<B_CNT; ++b) {
349 for (g=0; g<G_CNT; ++g) {
350 for (r=0; r<R_CNT; ++r) {
351 c_r = 0.5 + (double)r*(max-R_BIAS)/(R_CNT-1.) + R_BIAS;
352 c_g = 0.5 + (double)g*(max-G_BIAS)/(G_CNT-1.) + G_BIAS;
353 c_b = 0.5 + (double)b*(max-B_BIAS)/(B_CNT-1.) + B_BIAS;
354 fake_setcolor(color++, (int)c_r, (int)c_g, (int)c_b);
355 }
356 }
357 }
358
359 for (color=0; color<256; color++) {
360 c_r = (double)color*R_CNT/256.;
361 c_g = (double)color*G_CNT/256.;
362 c_b = (double)color*B_CNT/256.;
363 array_r[color] = (int)c_r;
364 array_g[color] = (int)c_g;
365 array_b[color] = (int)c_b;
366 }
367 }
368
369
370
371 #if HUGE_LOOKUP
372 /* Desc: initialize lookup arrays
373 *
374 * In : -
375 * Out : -
376 *
377 * Note: -
378 */
379 void v_init_pixeltables (void)
380 {
381 unsigned int pixel;
382
383 for (pixel = 0; pixel <= 0xffff; pixel++) {
384 unsigned int r, g, b;
385
386 if (pixel <= 0x7fff) {
387 /* 15bit */
388 r = (pixel & 0x7c00) >> 8;
389 g = (pixel & 0x03E0) >> 3;
390 b = (pixel & 0x001F) << 2;
391
392 r = (unsigned int)(((double)r * 255. / 0x7c) + 0.5);
393 g = (unsigned int)(((double)g * 255. / 0x7c) + 0.5);
394 b = (unsigned int)(((double)b * 255. / 0x7c) + 0.5);
395
396 pix15r[pixel] = r;
397 pix15g[pixel] = g;
398 pix15b[pixel] = b;
399 }
400
401 /* 16bit */
402 r = (pixel & 0xF800) >> 8;
403 g = (pixel & 0x07E0) >> 3;
404 b = (pixel & 0x001F) << 3;
405
406 r = (unsigned int)(((double)r * 255. / 0xF8) + 0.5);
407 g = (unsigned int)(((double)g * 255. / 0xFC) + 0.5);
408 b = (unsigned int)(((double)b * 255. / 0xF8) + 0.5);
409
410 pix16r[pixel] = r;
411 pix16g[pixel] = g;
412 pix16b[pixel] = b;
413 }
414 }
415 #endif
416
417
418
419 /* Desc: initialize hardware
420 *
421 * In : -
422 * Out : list of available modes
423 *
424 * Note: when returning non-NULL, global variable `drv' is guaranteed to be ok
425 */
426 static vl_mode *v_init_hw (void)
427 {
428 static vl_mode *q = NULL;
429
430 if (q == NULL) {
431 /* initialize hardware */
432 if ((q = VESA.init()) != NULL) {
433 drv = &VESA;
434 } else if ((q = VGA.init()) != NULL) {
435 drv = &VGA;
436 } else {
437 drv = NULL;
438 }
439 }
440
441 return q;
442 }
443
444
445
446 /* Desc: sync buffer with video hardware
447 *
448 * In : ptr to old buffer, position, size
449 * Out : 0 if success
450 *
451 * Note: -
452 */
453 int vl_sync_buffer (void **buffer, int x, int y, int width, int height)
454 {
455 if ((width & 7) || (x < 0) || (y < 0) || (x+width > video_mode->xres) || (y+height > video_mode->yres)) {
456 return -1;
457 } else {
458 void *newbuf = *buffer;
459
460 if ((newbuf == NULL) || (vl_current_width != width) || (vl_current_height != height)) {
461 newbuf = realloc(newbuf, width * height * video_bypp);
462 }
463
464 if (newbuf == NULL) {
465 return -2;
466 }
467
468 vl_current_width = width;
469 vl_current_height = height;
470 vl_current_stride = vl_current_width * video_bypp;
471 vl_current_bytes = vl_current_stride * height;
472
473 vl_current_offset = video_scanlen * y + video_bypp * x;
474 vl_current_delta = video_scanlen - vl_current_stride;
475
476 vl_current_draw_buffer = vl_current_read_buffer = *buffer = newbuf;
477 return 0;
478 }
479 }
480
481
482
483 /* Desc: state retrieval
484 *
485 * In : name, storage
486 * Out : -1 for an error
487 *
488 * Note: -
489 */
490 int vl_get (int pname, int *params)
491 {
492 switch (pname) {
493 case VL_GET_SCREEN_SIZE:
494 params[0] = video_mode->xres;
495 params[1] = video_mode->yres;
496 break;
497 case VL_GET_VIDEO_MODES:
498 {
499 int n;
500 vl_mode *q;
501 if ((q = v_init_hw()) == NULL) {
502 return -1;
503 }
504 /* count available visuals */
505 for (n = 0; q->mode != 0xffff; q++) {
506 if ((q + 1)->mode == (q->mode | 0x4000)) {
507 /* same mode, but linear */
508 q++;
509 }
510 if (params) {
511 params[n] = (int)q;
512 }
513 n++;
514 }
515 return n;
516 }
517 default:
518 return (drv != NULL) ? drv->get(pname, params) : -1;
519 }
520 return 0;
521 }
522
523
524
525 /* Desc: setup mode
526 *
527 * In : ptr to mode definition
528 * Out : 0 if success
529 *
530 * Note: -
531 */
532 static int vl_setup_mode (vl_mode *p)
533 {
534 if (p == NULL) {
535 return -1;
536 }
537
538 #define INITPTR(bpp) \
539 vl_putpixel = v_putpixel##bpp; \
540 vl_getrgba = v_getrgba##bpp; \
541 vl_getpixel = v_getpixel##bpp; \
542 vl_rect = v_rect##bpp; \
543 vl_mixfix = vl_mixfix##bpp; \
544 vl_mixrgb = vl_mixrgb##bpp; \
545 vl_mixrgba = vl_mixrgba##bpp; \
546 vl_clear = _can_mmx() ? v_clear##bpp##_mmx : v_clear##bpp
547
548 switch (p->bpp) {
549 case 8:
550 INITPTR(8);
551 break;
552 case 15:
553 INITPTR(15);
554 break;
555 case 16:
556 INITPTR(16);
557 break;
558 case 24:
559 INITPTR(24);
560 break;
561 case 32:
562 INITPTR(32);
563 break;
564 default:
565 return -1;
566 }
567
568 #undef INITPTR
569
570 video_mode = p;
571 video_bypp = (p->bpp+7)/8;
572 video_scanlen = p->scanlen;
573 vl_video_selector = p->sel;
574
575 return 0;
576 }
577
578
579
580 /* Desc: restore to the mode prior to first call to `vl_video_init'.
581 *
582 * In : -
583 * Out : -
584 *
585 * Note: -
586 */
587 void vl_video_exit (void)
588 {
589 drv->restore();
590 drv->fini();
591 video_mode = NULL;
592 }
593
594
595
596 /* Desc: enter mode
597 *
598 * In : xres, yres, bits/pixel, RGB, refresh rate
599 * Out : pixel width in bits if success
600 *
601 * Note: -
602 */
603 int vl_video_init (int width, int height, int bpp, int rgb, int refresh)
604 {
605 int fake;
606 vl_mode *p, *q;
607 unsigned int min;
608
609 fake = 0;
610 if (!rgb) {
611 bpp = 8;
612 } else if (bpp == 8) {
613 fake = 1;
614 }
615 #if HUGE_LOOKUP
616 else if (bpp < 24) {
617 v_init_pixeltables();
618 }
619 #endif
620
621 /* initialize hardware */
622 if ((q = v_init_hw()) == NULL) {
623 return 0;
624 }
625
626 /* search for a mode that fits our request */
627 for (min=-1, p=NULL; q->mode!=0xffff; q++) {
628 if ((q->xres>=width) && (q->yres>=height) && (q->bpp==bpp)) {
629 if (min>=(unsigned)(q->xres*q->yres)) {
630 min = q->xres*q->yres;
631 p = q;
632 }
633 }
634 }
635
636 /* setup and enter mode */
637 if ((vl_setup_mode(p) == 0) && (drv->entermode(p, refresh) == 0)) {
638 vl_flip = drv->blit;
639 if (fake) {
640 drv->get(VL_GET_CI_PREC, (int *)(&min));
641 fake_buildpalette(min);
642 if (min == 8) {
643 vl_getrgba = v_getrgba8fake8;
644 }
645 }
646 return bpp;
647 }
648
649 /* abort */
650 return 0;
651 }