35c643b4c9a23dba20b54c75568d282ffc7785f2
[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.3 for Mesa
27 *
28 * Copyright (C) 2002 - Borca Daniel
29 * Email : dborca@yahoo.com
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 return (rgba[3]<<24)|(rgba[0]<<16)|(rgba[1]<<8)|(rgba[2]);
167 }
168
169
170
171 /* Desc: color composition (w/o ALPHA)
172 *
173 * In : array of integers (R, G, B)
174 * Out : color
175 *
176 * Note: -
177 */
178 static int vl_mixrgb8fake (const unsigned char rgba[])
179 {
180 return array_b[rgba[2]]*G_CNT*R_CNT
181 + array_g[rgba[1]]*R_CNT
182 + array_r[rgba[0]];
183 }
184 #define vl_mixrgb8 vl_mixrgb8fake
185 static int vl_mixrgb15 (const unsigned char rgb[])
186 {
187 return ((rgb[0]>>3)<<10)|((rgb[1]>>3)<<5)|(rgb[2]>>3);
188 }
189 static int vl_mixrgb16 (const unsigned char rgb[])
190 {
191 return ((rgb[0]>>3)<<11)|((rgb[1]>>2)<<5)|(rgb[2]>>3);
192 }
193 #define vl_mixrgb24 vl_mixrgb32
194 static int vl_mixrgb32 (const unsigned char rgb[])
195 {
196 return (rgb[0]<<16)|(rgb[1]<<8)|(rgb[2]);
197 }
198
199
200
201 /* Desc: color decomposition
202 *
203 * In : pixel offset, array of integers to hold color components (R, G, B, A)
204 * Out : -
205 *
206 * Note: uses current read buffer
207 */
208 static void v_getrgba8fake6 (unsigned int offset, unsigned char rgba[])
209 {
210 word32 c = VGAPalette[((word8 *)vl_current_read_buffer)[offset]];
211 rgba[0] = _rgb_scale_6[(c >> 16) & 0x3F];
212 rgba[1] = _rgb_scale_6[(c >> 8) & 0x3F];
213 rgba[2] = _rgb_scale_6[c & 0x3F];
214 rgba[3] = c >> 24;
215 }
216 static void v_getrgba8fake8 (unsigned int offset, unsigned char rgba[])
217 {
218 word32 c = VGAPalette[((word8 *)vl_current_read_buffer)[offset]];
219 rgba[0] = c >> 16;
220 rgba[1] = c >> 8;
221 rgba[2] = c;
222 rgba[3] = c >> 24;
223 }
224 #define v_getrgba8 v_getrgba8fake6
225 static void v_getrgba15 (unsigned int offset, unsigned char rgba[4])
226 {
227 word32 c = ((word16 *)vl_current_read_buffer)[offset];
228 #if HUGE_LOOKUP
229 c &= 0x7fff;
230 rgba[0] = pix15r[c];
231 rgba[1] = pix15g[c];
232 rgba[2] = pix15b[c];
233 #else
234 rgba[0] = _rgb_scale_5[(c >> 10) & 0x1F];
235 rgba[1] = _rgb_scale_5[(c >> 5) & 0x1F];
236 rgba[2] = _rgb_scale_5[c & 0x1F];
237 #endif
238 rgba[3] = 255;
239 }
240 static void v_getrgba16 (unsigned int offset, unsigned char rgba[4])
241 {
242 word32 c = ((word16 *)vl_current_read_buffer)[offset];
243 #if HUGE_LOOKUP
244 rgba[0] = pix16r[c];
245 rgba[1] = pix16g[c];
246 rgba[2] = pix16b[c];
247 #else
248 rgba[0] = _rgb_scale_5[(c >> 11) & 0x1F];
249 rgba[1] = _rgb_scale_6[(c >> 5) & 0x3F];
250 rgba[2] = _rgb_scale_5[c & 0x1F];
251 #endif
252 rgba[3] = 255;
253 }
254 static void v_getrgba24 (unsigned int offset, unsigned char rgba[4])
255 {
256 word32 c = *(word32 *)((long)vl_current_read_buffer+offset*3);
257 rgba[0] = c >> 16;
258 rgba[1] = c >> 8;
259 rgba[2] = c;
260 rgba[3] = 255;
261 }
262 static void v_getrgba32 (unsigned int offset, unsigned char rgba[4])
263 {
264 word32 c = ((word32 *)vl_current_read_buffer)[offset];
265 rgba[0] = c >> 16;
266 rgba[1] = c >> 8;
267 rgba[2] = c;
268 rgba[3] = c >> 24;
269 }
270
271
272
273 /* Desc: pixel retrieval
274 *
275 * In : pixel offset
276 * Out : pixel value
277 *
278 * Note: uses current read buffer
279 */
280 static int v_getpixel8 (unsigned int offset)
281 {
282 return ((word8 *)vl_current_read_buffer)[offset];
283 }
284 #define v_getpixel15 v_getpixel16
285 static int v_getpixel16 (unsigned int offset)
286 {
287 return ((word16 *)vl_current_read_buffer)[offset];
288 }
289 static int v_getpixel24 (unsigned int offset)
290 {
291 return *(word32 *)((long)vl_current_read_buffer+offset*3);
292 }
293 static int v_getpixel32 (unsigned int offset)
294 {
295 return ((word32 *)vl_current_read_buffer)[offset];
296 }
297
298
299
300 /* Desc: set one palette entry
301 *
302 * In : index, R, G, B
303 * Out : -
304 *
305 * Note: color components are in range [0.0 .. 1.0]
306 */
307 void vl_setCI (int index, float red, float green, float blue)
308 {
309 drv->setCI_f(index, red, green, blue);
310 }
311
312
313
314 /* Desc: set one palette entry
315 *
316 * In : color, R, G, B
317 * Out : -
318 *
319 * Note: -
320 */
321 static void fake_setcolor (int c, int r, int g, int b)
322 {
323 VGAPalette[c] = 0xff000000 | (r<<16) | (g<<8) | b;
324
325 drv->setCI_i(c, r, g, b);
326 }
327
328
329
330 /* Desc: build FakeColor palette
331 *
332 * In : CI precision in bits
333 * Out : -
334 *
335 * Note: -
336 */
337 static void fake_buildpalette (int bits)
338 {
339 double c_r, c_g, c_b;
340 int r, g, b, color = 0;
341
342 double max = (1 << bits) - 1;
343
344 for (b=0; b<B_CNT; ++b) {
345 for (g=0; g<G_CNT; ++g) {
346 for (r=0; r<R_CNT; ++r) {
347 c_r = 0.5 + (double)r*(max-R_BIAS)/(R_CNT-1.) + R_BIAS;
348 c_g = 0.5 + (double)g*(max-G_BIAS)/(G_CNT-1.) + G_BIAS;
349 c_b = 0.5 + (double)b*(max-B_BIAS)/(B_CNT-1.) + B_BIAS;
350 fake_setcolor(color++, (int)c_r, (int)c_g, (int)c_b);
351 }
352 }
353 }
354
355 for (color=0; color<256; color++) {
356 c_r = (double)color*R_CNT/256.;
357 c_g = (double)color*G_CNT/256.;
358 c_b = (double)color*B_CNT/256.;
359 array_r[color] = (int)c_r;
360 array_g[color] = (int)c_g;
361 array_b[color] = (int)c_b;
362 }
363 }
364
365
366
367 #if HUGE_LOOKUP
368 /* Desc: initialize lookup arrays
369 *
370 * In : -
371 * Out : -
372 *
373 * Note: -
374 */
375 void v_init_pixeltables (void)
376 {
377 unsigned int pixel;
378
379 for (pixel = 0; pixel <= 0xffff; pixel++) {
380 unsigned int r, g, b;
381
382 if (pixel <= 0x7fff) {
383 /* 15bit */
384 r = (pixel & 0x7c00) >> 8;
385 g = (pixel & 0x03E0) >> 3;
386 b = (pixel & 0x001F) << 2;
387
388 r = (unsigned int)(((double)r * 255. / 0x7c) + 0.5);
389 g = (unsigned int)(((double)g * 255. / 0x7c) + 0.5);
390 b = (unsigned int)(((double)b * 255. / 0x7c) + 0.5);
391
392 pix15r[pixel] = r;
393 pix15g[pixel] = g;
394 pix15b[pixel] = b;
395 }
396
397 /* 16bit */
398 r = (pixel & 0xF800) >> 8;
399 g = (pixel & 0x07E0) >> 3;
400 b = (pixel & 0x001F) << 3;
401
402 r = (unsigned int)(((double)r * 255. / 0xF8) + 0.5);
403 g = (unsigned int)(((double)g * 255. / 0xFC) + 0.5);
404 b = (unsigned int)(((double)b * 255. / 0xF8) + 0.5);
405
406 pix16r[pixel] = r;
407 pix16g[pixel] = g;
408 pix16b[pixel] = b;
409 }
410 }
411 #endif
412
413
414
415 /* Desc: sync buffer with video hardware
416 *
417 * In : ptr to old buffer, position, size
418 * Out : 0 if success
419 *
420 * Note: -
421 */
422 int vl_sync_buffer (void **buffer, int x, int y, int width, int height)
423 {
424 if ((width & 7) || (x < 0) || (y < 0) || (x+width > video_mode->xres) || (y+height > video_mode->yres)) {
425 return -1;
426 } else {
427 void *newbuf = *buffer;
428
429 if ((newbuf == NULL) || (vl_current_width != width) || (vl_current_height != height)) {
430 newbuf = realloc(newbuf, width * height * video_bypp);
431 }
432
433 if (newbuf == NULL) {
434 return -2;
435 }
436
437 vl_current_width = width;
438 vl_current_height = height;
439 vl_current_stride = vl_current_width * video_bypp;
440 vl_current_bytes = vl_current_stride * height;
441
442 vl_current_offset = video_scanlen * y + video_bypp * x;
443 vl_current_delta = video_scanlen - vl_current_stride;
444
445 vl_current_draw_buffer = vl_current_read_buffer = *buffer = newbuf;
446 return 0;
447 }
448 }
449
450
451
452 /* Desc: state retrieval
453 *
454 * In : name, storage
455 * Out : -
456 *
457 * Note: -
458 */
459 int vl_get (int pname, int *params)
460 {
461 switch (pname) {
462 case VL_GET_SCREEN_SIZE:
463 params[0] = video_mode->xres;
464 params[1] = video_mode->yres;
465 break;
466 default:
467 return drv->get(pname, params);
468 }
469 return 0;
470 }
471
472
473
474 /* Desc: setup mode
475 *
476 * In : ptr to mode definition
477 * Out : 0 if success
478 *
479 * Note: -
480 */
481 static int vl_setup_mode (vl_mode *p)
482 {
483 if (p == NULL) {
484 return -1;
485 }
486
487 #define INITPTR(bpp) \
488 vl_putpixel = v_putpixel##bpp; \
489 vl_getrgba = v_getrgba##bpp; \
490 vl_getpixel = v_getpixel##bpp; \
491 vl_rect = v_rect##bpp; \
492 vl_mixfix = vl_mixfix##bpp; \
493 vl_mixrgb = vl_mixrgb##bpp; \
494 vl_mixrgba = vl_mixrgba##bpp; \
495 vl_clear = _can_mmx() ? v_clear##bpp##_mmx : v_clear##bpp
496
497 switch (p->bpp) {
498 case 8:
499 INITPTR(8);
500 break;
501 case 15:
502 INITPTR(15);
503 break;
504 case 16:
505 INITPTR(16);
506 break;
507 case 24:
508 INITPTR(24);
509 break;
510 case 32:
511 INITPTR(32);
512 break;
513 default:
514 return -1;
515 }
516
517 #undef INITPTR
518
519 video_mode = p;
520 video_bypp = (p->bpp+7)/8;
521 video_scanlen = p->scanlen;
522 vl_video_selector = p->sel;
523
524 return 0;
525 }
526
527
528
529 /* Desc: restore to the mode prior to first call to `vl_video_init'.
530 *
531 * In : -
532 * Out : -
533 *
534 * Note: -
535 */
536 void vl_video_exit (void)
537 {
538 drv->restore();
539 drv->fini();
540 }
541
542
543
544 /* Desc: enter mode
545 *
546 * In : xres, yres, bits/pixel, RGB, refresh rate
547 * Out : pixel width in bits if success
548 *
549 * Note: -
550 */
551 int vl_video_init (int width, int height, int bpp, int rgb, int refresh)
552 {
553 int fake;
554 vl_mode *p, *q;
555 unsigned int min;
556
557 fake = 0;
558 if (!rgb) {
559 bpp = 8;
560 } else if (bpp == 8) {
561 fake = 1;
562 }
563 #if HUGE_LOOKUP
564 else if (bpp < 24) {
565 v_init_pixeltables();
566 }
567 #endif
568
569 /* initialize hardware */
570 drv = &VESA;
571 if ((q=drv->init()) == NULL) {
572 drv = &VGA;
573 if ((q=drv->init()) == NULL) {
574 return 0;
575 }
576 }
577
578 /* search for a mode that fits our request */
579 for (min=-1, p=NULL; q->mode!=0xffff; q++) {
580 if ((q->xres>=width) && (q->yres>=height) && (q->bpp==bpp)) {
581 if (min>=(unsigned)(q->xres*q->yres)) {
582 min = q->xres*q->yres;
583 p = q;
584 }
585 }
586 }
587
588 /* setup and enter mode */
589 if ((vl_setup_mode(p) == 0) && (drv->entermode(p, refresh) == 0)) {
590 vl_flip = drv->blit;
591 if (fake) {
592 drv->get(VL_GET_CI_PREC, (int *)(&min));
593 fake_buildpalette(min);
594 if (min == 8) {
595 vl_getrgba = v_getrgba8fake8;
596 }
597 }
598 return bpp;
599 }
600
601 /* abort */
602 return 0;
603 }