9d50952c52730c82976a70ccbea594e22f226a75
[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 v0.4 for Mesa 4.0
27 *
28 * Copyright (C) 2002 - Borca Daniel
29 * Email : dborca@yahoo.com
30 * Web : http://www.geocities.com/dborca
31 */
32
33
34 #include <dpmi.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <stubinfo.h>
38 #include <sys/exceptn.h>
39 #include <sys/segments.h>
40 #include <sys/farptr.h>
41
42 #include "video.h"
43 #include "dpmiint.h"
44
45
46
47 typedef unsigned char word8;
48 typedef unsigned short word16;
49 typedef unsigned long word32;
50
51 typedef struct vl_mode {
52 int mode;
53 int xres, yres;
54 int scanlen;
55 int bpp;
56 } vl_mode;
57
58 #define _16_ *(word16 *)&
59 #define _32_ *(word32 *)&
60
61 static int init;
62
63 static vl_mode modes[64];
64
65 /* card specific: valid forever */
66 static word16 vesa_ver;
67 static word32 hw_granularity, hw_linearfb;
68 static unsigned int gran_shift, gran_mask;
69 /* based upon mode specific data: valid entire session */
70 static int video_selector, banked_selector, linear_selector;
71 static int video_scanlen, video_bypp;
72 /* valid until next buffer */
73 static int current_offset, current_delta, current_width;
74
75
76
77 /* lookup table for scaling 5 bit colors up to 8 bits */
78 static int _rgb_scale_5[32] =
79 {
80 0, 8, 16, 24, 32, 41, 49, 57,
81 65, 74, 82, 90, 98, 106, 115, 123,
82 131, 139, 148, 156, 164, 172, 180, 189,
83 197, 205, 213, 222, 230, 238, 246, 255
84 };
85
86 /* lookup table for scaling 6 bit colors up to 8 bits */
87 static int _rgb_scale_6[64] =
88 {
89 0, 4, 8, 12, 16, 20, 24, 28,
90 32, 36, 40, 44, 48, 52, 56, 60,
91 64, 68, 72, 76, 80, 85, 89, 93,
92 97, 101, 105, 109, 113, 117, 121, 125,
93 129, 133, 137, 141, 145, 149, 153, 157,
94 161, 165, 170, 174, 178, 182, 186, 190,
95 194, 198, 202, 206, 210, 214, 218, 222,
96 226, 230, 234, 238, 242, 246, 250, 255
97 };
98
99
100
101 /*
102 * virtual clearing
103 */
104 void (*vl_clear) (void *buffer, int len, int color);
105
106 #define v_clear15 v_clear16
107 extern void v_clear16 (void *buffer, int len, int color);
108 extern void v_clear32 (void *buffer, int len, int color);
109 __asm__("\n\
110 .text \n\
111 .balign 4 \n\
112 .global _v_clear16 \n\
113 _v_clear16: \n\
114 movl 12(%esp), %eax \n\
115 pushw %ax \n\
116 pushw %ax \n\
117 popl %eax \n\
118 jmp _v_clear_common \n\
119 .balign 4 \n\
120 .global _v_clear32 \n\
121 _v_clear32: \n\
122 movl 12(%esp), %eax \n\
123 .balign 4 \n\
124 _v_clear_common: \n\
125 movl 8(%esp), %ecx \n\
126 movl 4(%esp), %edx \n\
127 shrl $2, %ecx \n\
128 0: \n\
129 .balign 4 \n\
130 movl %eax, (%edx) \n\
131 addl $4, %edx \n\
132 decl %ecx \n\
133 jnz 0b \n\
134 ret");
135 extern void v_clear24 (void *buffer, int len, int color);
136 __asm__("\n\
137 .text \n\
138 .balign 4 \n\
139 .global _v_clear24 \n\
140 _v_clear24: \n\
141 movl 8(%esp), %edx \n\
142 movl $0xaaaaaaab, %eax \n\
143 mull %edx \n\
144 movl 12(%esp), %eax \n\
145 movl %edx, %ecx \n\
146 movl 4(%esp), %edx \n\
147 pushl %ebx \n\
148 shrl %ecx \n\
149 movb 18(%esp), %bl \n\
150 .balign 4 \n\
151 0: \n\
152 movw %ax, (%edx) \n\
153 movb %bl, 2(%edx) \n\
154 addl $3, %edx \n\
155 decl %ecx \n\
156 jnz 0b \n\
157 popl %ebx \n\
158 ret");
159
160
161
162 /*
163 * virtual rectangle clearing
164 */
165 void vl_rect (void *buffer, int x, int y, int width, int height, int color)
166 {
167 int offset = y*current_width + x;
168 int delta = current_width - width;
169
170 for (y=0; y<height; y++) {
171 for (x=0; x<width; x++, offset++) {
172 vl_putpixel(buffer, offset, color);
173 }
174 offset += delta;
175 }
176 }
177
178
179
180 /*
181 * virtual dumping:
182 */
183 void (*vl_flip) (void *buffer, int width, int height);
184
185 extern void b_dump_virtual (void *buffer, int width, int height);
186 __asm__("\n\
187 .text \n\
188 .balign 4 \n\
189 .global _b_dump_virtual \n\
190 _b_dump_virtual: \n\
191 pushl %ebx \n\
192 pushl %esi \n\
193 pushl %edi \n\
194 pushl %ebp \n\
195 movl _video_selector, %fs \n\
196 movl 4*4+4+0(%esp), %esi \n\
197 movl _hw_granularity, %ebp \n\
198 xorl %edx, %edx \n\
199 movl _current_offset, %eax \n\
200 divl %ebp \n\
201 movl %edx, %edi \n\
202 pushl %eax \n\
203 movl %eax, %edx \n\
204 xorl %ebx, %ebx \n\
205 movw $0x4f05, %ax \n\
206 int $0x10 \n\
207 movl _current_delta, %ebx \n\
208 movl 5*4+4+4(%esp), %ecx \n\
209 movl 5*4+4+8(%esp), %edx \n\
210 shrl $2, %ecx \n\
211 .balign 4 \n\
212 0: \n\
213 pushl %ecx \n\
214 .balign 4 \n\
215 1: \n\
216 cmpl %ebp, %edi \n\
217 jb 2f \n\
218 pushl %ebx \n\
219 pushl %edx \n\
220 incl 12(%esp) \n\
221 movw $0x4f05, %ax \n\
222 movl 12(%esp), %edx \n\
223 xorl %ebx, %ebx \n\
224 int $0x10 \n\
225 popl %edx \n\
226 popl %ebx \n\
227 subl %ebp, %edi \n\
228 2: \n\
229 movl (%esi), %eax \n\
230 addl $4, %esi \n\
231 movl %eax, %fs:(%edi) \n\
232 addl $4, %edi \n\
233 decl %ecx \n\
234 jnz 1b \n\
235 popl %ecx \n\
236 addl %ebx, %edi \n\
237 decl %edx \n\
238 jnz 0b \n\
239 popl %eax \n\
240 popl %ebp \n\
241 popl %edi \n\
242 popl %esi \n\
243 popl %ebx \n\
244 ret");
245 extern void l_dump_virtual (void *buffer, int width, int height);
246 __asm__("\n\
247 .text \n\
248 .balign 4 \n\
249 .global _l_dump_virtual \n\
250 _l_dump_virtual: \n\
251 pushl %ebx \n\
252 pushl %esi \n\
253 pushl %edi \n\
254 movl _video_selector, %fs \n\
255 movl 3*4+4+0(%esp), %esi \n\
256 movl _current_offset, %edi \n\
257 movl 3*4+4+4(%esp), %ecx \n\
258 movl 3*4+4+8(%esp), %edx \n\
259 movl _current_delta, %ebx \n\
260 shrl $2, %ecx \n\
261 .balign 4 \n\
262 0: \n\
263 pushl %ecx \n\
264 .balign 4 \n\
265 1: \n\
266 movl (%esi), %eax \n\
267 addl $4, %esi \n\
268 movl %eax, %fs:(%edi) \n\
269 addl $4, %edi \n\
270 decl %ecx \n\
271 jnz 1b \n\
272 popl %ecx \n\
273 addl %ebx, %edi \n\
274 decl %edx \n\
275 jnz 0b \n\
276 popl %edi \n\
277 popl %esi \n\
278 popl %ebx \n\
279 ret");
280
281
282
283 /*
284 * mix RGBA components
285 */
286 int (*vl_mixrgba) (const unsigned char rgba[]);
287
288 #define vl_mixrgba15 vl_mixrgb15
289 #define vl_mixrgba16 vl_mixrgb16
290 #define vl_mixrgba24 vl_mixrgb24
291 static int vl_mixrgba32 (const unsigned char rgba[])
292 {
293 return (rgba[3]<<24)|(rgba[0]<<16)|(rgba[1]<<8)|(rgba[2]);
294 }
295
296
297
298 /*
299 * mix RGB components
300 */
301 int (*vl_mixrgb) (const unsigned char rgb[]);
302
303 static int vl_mixrgb15 (const unsigned char rgb[])
304 {
305 return ((rgb[0]>>3)<<10)|((rgb[1]>>3)<<5)|(rgb[2]>>3);
306 }
307 static int vl_mixrgb16 (const unsigned char rgb[])
308 {
309 return ((rgb[0]>>3)<<11)|((rgb[1]>>2)<<5)|(rgb[2]>>3);
310 }
311 #define vl_mixrgb24 vl_mixrgb32
312 static int vl_mixrgb32 (const unsigned char rgb[])
313 {
314 return (rgb[0]<<16)|(rgb[1]<<8)|(rgb[2]);
315 }
316
317
318
319 /*
320 * vl_putpixel*
321 */
322 void (*vl_putpixel) (void *buffer, int offset, int color);
323
324 #define v_putpixel15 v_putpixel16
325 extern void v_putpixel16 (void *buffer, int offset, int color);
326 __asm__("\n\
327 .text \n\
328 .balign 4 \n\
329 .global _v_putpixel16 \n\
330 _v_putpixel16: \n\
331 movl 8(%esp), %edx \n\
332 shll %edx \n\
333 movl 12(%esp), %eax \n\
334 addl 4(%esp), %edx \n\
335 movw %ax, (%edx) \n\
336 ret");
337 extern void v_putpixel24 (void *buffer, int offset, int color);
338 __asm__("\n\
339 .text \n\
340 .balign 4 \n\
341 .global _v_putpixel24 \n\
342 _v_putpixel24: \n\
343 movl 8(%esp), %edx \n\
344 leal (%edx, %edx, 2), %edx \n\
345 movl 12(%esp), %eax \n\
346 addl 4(%esp), %edx \n\
347 movw %ax, (%edx) \n\
348 shrl $16, %eax \n\
349 movb %al, 2(%edx) \n\
350 ret");
351 extern void v_putpixel32 (void *buffer, int offset, int color);
352 __asm__("\n\
353 .text \n\
354 .balign 4 \n\
355 .global _v_putpixel32 \n\
356 _v_putpixel32: \n\
357 movl 8(%esp), %edx \n\
358 shll $2, %edx \n\
359 movl 12(%esp), %eax \n\
360 addl 4(%esp), %edx \n\
361 movl %eax, (%edx) \n\
362 ret");
363
364
365
366 /*
367 * get pixel and decompose R, G, B, A
368 */
369 void (*vl_getrgba) (void *buffer, int offset, unsigned char rgba[4]);
370
371 /*
372 * v_getrgba*
373 */
374 static void v_getrgba15 (void *buffer, int offset, unsigned char rgba[4])
375 {
376 int c = ((word16 *)buffer)[offset];
377 rgba[0] = _rgb_scale_5[(c >> 10) & 0x1F];
378 rgba[1] = _rgb_scale_5[(c >> 5) & 0x1F];
379 rgba[2] = _rgb_scale_5[c & 0x1F];
380 rgba[3] = 255;
381 }
382 static void v_getrgba16 (void *buffer, int offset, unsigned char rgba[4])
383 {
384 int c = ((word16 *)buffer)[offset];
385 rgba[0] = _rgb_scale_5[(c >> 11) & 0x1F];
386 rgba[1] = _rgb_scale_6[(c >> 5) & 0x3F];
387 rgba[2] = _rgb_scale_5[c & 0x1F];
388 rgba[3] = 255;
389 }
390 static void v_getrgba24 (void *buffer, int offset, unsigned char rgba[4])
391 {
392 int c = *(word32 *)((long)buffer+offset*3);
393 rgba[0] = c >> 16;
394 rgba[1] = c >> 8;
395 rgba[2] = c;
396 rgba[3] = 255;
397 }
398 static void v_getrgba32 (void *buffer, int offset, unsigned char rgba[4])
399 {
400 int c = ((word32 *)buffer)[offset];
401 rgba[0] = c >> 16;
402 rgba[1] = c >> 8;
403 rgba[2] = c;
404 rgba[3] = c >> 24;
405 }
406
407
408
409 /*
410 * sync buffer with video hardware
411 */
412 void *vl_sync_buffer (void *buffer, int x, int y, int width, int height)
413 {
414 void *newbuf;
415
416 if (width&3) {
417 return NULL;
418 } else {
419 current_offset = video_scanlen * y + video_bypp * x;
420 if ((newbuf=realloc(buffer, width*height*video_bypp))!=NULL) {
421 current_width = width;
422 current_delta = video_scanlen - video_bypp * width;
423 return newbuf;
424 } else {
425 return NULL;
426 }
427 }
428 }
429
430
431
432 /*
433 * attempts to detect VESA and video modes
434 */
435 static word16 vl_vesa_init (void)
436 {
437 __dpmi_regs r;
438 unsigned short *p;
439 vl_mode *q;
440 char vesa_info[512], tmp[512];
441 int maxsize = 0;
442
443 _farpokel(_stubinfo->ds_selector, 0, 0x32454256);
444 r.x.ax = 0x4f00;
445 r.x.di = 0;
446 r.x.es = _stubinfo->ds_segment;
447 __dpmi_int(0x10, &r);
448 if (r.x.ax==0x004f) {
449 movedata(_stubinfo->ds_selector, 0, _my_ds(), (unsigned)vesa_info, 512);
450 if ((_32_ vesa_info[0])==0x41534556) {
451 p = (unsigned short *)(((_16_ vesa_info[0x10])<<4) + (_16_ vesa_info[0x0e]));
452 q = modes;
453 do {
454 if ((q->mode=_farpeekw(__djgpp_dos_sel, (unsigned long)(p++)))==0xffff) {
455 break;
456 }
457
458 r.x.ax = 0x4f01;
459 r.x.cx = q->mode;
460 r.x.di = 512;
461 r.x.es = _stubinfo->ds_segment;
462 __dpmi_int(0x10, &r);
463 movedata(_stubinfo->ds_selector, 512, _my_ds(), (unsigned)tmp, 256);
464 switch (tmp[0x19]) {
465 case 16:
466 q->bpp = tmp[0x1f] + tmp[0x21] + tmp[0x23];
467 break;
468 case 15:
469 case 24:
470 case 32:
471 q->bpp = tmp[0x19];
472 break;
473 default:
474 q->bpp = 0;
475 }
476 if ((r.x.ax==0x004f)&&((tmp[0]&0x11)==0x11)&&q->bpp) {
477 q->xres = _16_ tmp[0x12];
478 q->yres = _16_ tmp[0x14];
479 q->scanlen = _16_ tmp[0x10];
480 hw_granularity = (_16_ tmp[4])<<10;
481 if (tmp[0]&0x80) {
482 *(q+1) = *q++;
483 hw_linearfb = _32_ tmp[0x28];
484 q->mode |= 0x4000;
485 }
486 if (maxsize<(q->scanlen*q->yres)) {
487 maxsize = q->scanlen*q->yres;
488 }
489 q++;
490 }
491 } while (!0);
492
493 if (hw_linearfb) {
494 maxsize = ((maxsize+0xfffUL)&~0xfffUL);
495 if (_create_selector(&linear_selector, hw_linearfb, maxsize)) {
496 return 0;
497 }
498 }
499 if (_create_selector(&banked_selector, 0xa0000, hw_granularity)) {
500 _remove_selector(&linear_selector);
501 return 0;
502 }
503
504 return _16_ vesa_info[4];
505 }
506 }
507
508 return 0;
509 }
510
511
512
513 /*
514 * setup mode
515 */
516 static int vl_setup_mode (vl_mode *p)
517 {
518 if (p->mode&0x4000) {
519 video_selector = linear_selector;
520 vl_flip = l_dump_virtual;
521 } else {
522 { int n; for (gran_shift=0, n=hw_granularity; n; gran_shift++, n>>=1) ; }
523 gran_mask = (1<<(--gran_shift)) - 1;
524 if (hw_granularity!=(gran_mask+1)) {
525 return -1;
526 }
527 video_selector = banked_selector;
528 vl_flip = b_dump_virtual;
529 }
530
531 #define INITPTR(bpp) \
532 vl_putpixel = v_putpixel##bpp; \
533 vl_getrgba = v_getrgba##bpp; \
534 vl_clear = v_clear##bpp; \
535 vl_mixrgb = vl_mixrgb##bpp; \
536 vl_mixrgba = vl_mixrgba##bpp;
537
538 switch (p->bpp) {
539 case 15:
540 INITPTR(15);
541 break;
542 case 16:
543 INITPTR(16);
544 break;
545 case 24:
546 INITPTR(24);
547 break;
548 case 32:
549 INITPTR(32);
550 break;
551 default:
552 return -1;
553 }
554
555 #undef INITPTR
556
557 video_bypp = (p->bpp+7)/8;
558 video_scanlen = p->scanlen;
559
560 return 0;
561 }
562
563
564
565 /*
566 * shutdown the video engine
567 */
568 void vl_video_exit (int textmode)
569 {
570 if (init) {
571 if (textmode) {
572 __asm__("movw $0x3, %%ax; int $0x10":::"%eax");
573 }
574
575 _remove_selector(&linear_selector);
576 _remove_selector(&banked_selector);
577
578 init = !init;
579 }
580 }
581
582
583
584 /*
585 * initialize video engine
586 *
587 * success: 0
588 * failure: -1
589 */
590 int vl_video_init (int width, int height, int bpp)
591 {
592 vl_mode *p, *q;
593 unsigned int min;
594
595 /* check for prior initialization */
596 if (init) {
597 return 0;
598 }
599
600 /* initialize hardware */
601 if (!(vesa_ver=vl_vesa_init())) {
602 return -1;
603 }
604 init = !init;
605
606 /* search for a mode that fits our request */
607 for (min=-1, p=NULL, q=modes; q->mode!=0xffff; q++) {
608 if ((q->xres>=width)&&(q->yres>=height)&&(q->bpp==bpp)) {
609 if (min>=(unsigned)(q->xres*q->yres)) {
610 min = q->xres*q->yres;
611 p = q;
612 }
613 }
614 }
615
616 if (p) {
617 vl_setup_mode(p);
618 __asm__("movw $0x4f02, %%ax; int $0x10"::"b"(p->mode):"%eax");
619 return 0;
620 } else {
621 /* no suitable mode found, abort */
622 vl_video_exit(0);
623 return -1;
624 }
625 }