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