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