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