FreeBSD/Linux Kernel Cross Reference
sys/pc/screen.c
1 #include "u.h"
2 #include "../port/lib.h"
3 #include "mem.h"
4 #include "dat.h"
5 #include "fns.h"
6 #include "io.h"
7 #include "ureg.h"
8 #include "../port/error.h"
9
10 #define Image IMAGE
11 #include <draw.h>
12 #include <memdraw.h>
13 #include <cursor.h>
14 #include "screen.h"
15
16 #define RGB2K(r,g,b) ((156763*(r)+307758*(g)+59769*(b))>>19)
17
18 Point ZP = {0, 0};
19
20 Rectangle physgscreenr;
21
22 Memdata gscreendata;
23 Memimage *gscreen;
24
25 VGAscr vgascreen[1];
26
27 Cursor arrow = {
28 { -1, -1 },
29 { 0xFF, 0xFF, 0x80, 0x01, 0x80, 0x02, 0x80, 0x0C,
30 0x80, 0x10, 0x80, 0x10, 0x80, 0x08, 0x80, 0x04,
31 0x80, 0x02, 0x80, 0x01, 0x80, 0x02, 0x8C, 0x04,
32 0x92, 0x08, 0x91, 0x10, 0xA0, 0xA0, 0xC0, 0x40,
33 },
34 { 0x00, 0x00, 0x7F, 0xFE, 0x7F, 0xFC, 0x7F, 0xF0,
35 0x7F, 0xE0, 0x7F, 0xE0, 0x7F, 0xF0, 0x7F, 0xF8,
36 0x7F, 0xFC, 0x7F, 0xFE, 0x7F, 0xFC, 0x73, 0xF8,
37 0x61, 0xF0, 0x60, 0xE0, 0x40, 0x40, 0x00, 0x00,
38 },
39 };
40
41 int didswcursorinit;
42
43 int
44 screensize(int x, int y, int z, ulong chan)
45 {
46 VGAscr *scr;
47
48 lock(&vgascreenlock);
49 memimageinit();
50 scr = &vgascreen[0];
51
52 /*
53 * BUG: need to check if any xalloc'ed memory needs to
54 * be given back if aperture is set.
55 */
56 if(scr->paddr == 0){
57 int width = (x*z)/BI2WD;
58
59 gscreendata.bdata = xalloc(width*BY2WD*y);
60 if(gscreendata.bdata == 0)
61 error("screensize: vga soft memory");
62 /* memset(gscreendata.bdata, 0x72, width*BY2WD*y); /* not really black */
63 scr->useflush = 1;
64 scr->paddr = VGAMEM();
65 scr->vaddr = KADDR(scr->paddr);
66 scr->apsize = 1<<16;
67 }
68 else
69 gscreendata.bdata = scr->vaddr;
70
71 if(gscreen)
72 freememimage(gscreen);
73 scr->gscreen = nil;
74
75 gscreen = allocmemimaged(Rect(0,0,x,y), chan, &gscreendata);
76 vgaimageinit(chan);
77 if(gscreen == nil){
78 unlock(&vgascreenlock);
79 return -1;
80 }
81
82 if(scr->dev && scr->dev->flush)
83 scr->useflush = 1;
84
85 scr->palettedepth = 6; /* default */
86 scr->gscreendata = &gscreendata;
87 scr->memdefont = getmemdefont();
88 scr->gscreen = gscreen;
89
90 physgscreenr = gscreen->r;
91 unlock(&vgascreenlock);
92
93 if(didswcursorinit)
94 swcursorinit();
95 drawcmap();
96 return 0;
97 }
98
99 int
100 screenaperture(int size, int align)
101 {
102 VGAscr *scr;
103
104 scr = &vgascreen[0];
105
106 if(scr->paddr) /* set up during enable */
107 return 0;
108
109 if(size == 0)
110 return 0;
111
112 if(scr->dev && scr->dev->linear){
113 scr->dev->linear(scr, size, align);
114 return 0;
115 }
116
117 /*
118 * Need to allocate some physical address space.
119 * The driver will tell the card to use it.
120 */
121 size = PGROUND(size);
122 scr->paddr = upaalloc(size, align);
123 if(scr->paddr == 0)
124 return -1;
125 scr->vaddr = vmap(scr->paddr, size);
126 if(scr->vaddr == nil)
127 return -1;
128 scr->apsize = size;
129
130 return 0;
131 }
132
133 uchar*
134 attachscreen(Rectangle* r, ulong* chan, int* d, int* width, int *softscreen)
135 {
136 VGAscr *scr;
137
138 scr = &vgascreen[0];
139 if(scr->gscreen == nil || scr->gscreendata == nil)
140 return nil;
141
142 *r = scr->gscreen->clipr;
143 *chan = scr->gscreen->chan;
144 *d = scr->gscreen->depth;
145 *width = scr->gscreen->width;
146 *softscreen = scr->useflush;
147
148 return scr->gscreendata->bdata;
149 }
150
151 /*
152 * It would be fair to say that this doesn't work for >8-bit screens.
153 */
154 void
155 flushmemscreen(Rectangle r)
156 {
157 VGAscr *scr;
158 uchar *sp, *disp, *sdisp, *edisp;
159 int y, len, incs, off, page;
160
161 scr = &vgascreen[0];
162 if(scr->dev && scr->dev->flush){
163 scr->dev->flush(scr, r);
164 return;
165 }
166 if(scr->gscreen == nil || scr->useflush == 0)
167 return;
168 if(scr->dev == nil || scr->dev->page == nil)
169 return;
170
171 if(rectclip(&r, scr->gscreen->r) == 0)
172 return;
173
174 incs = scr->gscreen->width * BY2WD;
175
176 switch(scr->gscreen->depth){
177 default:
178 len = 0;
179 panic("flushmemscreen: depth\n");
180 break;
181 case 8:
182 len = Dx(r);
183 break;
184 }
185 if(len < 1)
186 return;
187
188 off = r.min.y*scr->gscreen->width*BY2WD+(r.min.x*scr->gscreen->depth)/8;
189 page = off/scr->apsize;
190 off %= scr->apsize;
191 disp = scr->vaddr;
192 sdisp = disp+off;
193 edisp = disp+scr->apsize;
194
195 off = r.min.y*scr->gscreen->width*BY2WD+(r.min.x*scr->gscreen->depth)/8;
196
197 sp = scr->gscreendata->bdata + off;
198
199 scr->dev->page(scr, page);
200 for(y = r.min.y; y < r.max.y; y++) {
201 if(sdisp + incs < edisp) {
202 memmove(sdisp, sp, len);
203 sp += incs;
204 sdisp += incs;
205 }
206 else {
207 off = edisp - sdisp;
208 page++;
209 if(off <= len){
210 if(off > 0)
211 memmove(sdisp, sp, off);
212 scr->dev->page(scr, page);
213 if(len - off > 0)
214 memmove(disp, sp+off, len - off);
215 }
216 else {
217 memmove(sdisp, sp, len);
218 scr->dev->page(scr, page);
219 }
220 sp += incs;
221 sdisp += incs - scr->apsize;
222 }
223 }
224 }
225
226 void
227 getcolor(ulong p, ulong* pr, ulong* pg, ulong* pb)
228 {
229 VGAscr *scr;
230 ulong x;
231
232 scr = &vgascreen[0];
233 if(scr->gscreen == nil)
234 return;
235
236 switch(scr->gscreen->depth){
237 default:
238 x = 0x0F;
239 break;
240 case 8:
241 x = 0xFF;
242 break;
243 }
244 p &= x;
245
246 lock(&cursor);
247 *pr = scr->colormap[p][0];
248 *pg = scr->colormap[p][1];
249 *pb = scr->colormap[p][2];
250 unlock(&cursor);
251 }
252
253 int
254 setpalette(ulong p, ulong r, ulong g, ulong b)
255 {
256 VGAscr *scr;
257 int d;
258
259 scr = &vgascreen[0];
260 d = scr->palettedepth;
261
262 lock(&cursor);
263 scr->colormap[p][0] = r;
264 scr->colormap[p][1] = g;
265 scr->colormap[p][2] = b;
266 vgao(PaddrW, p);
267 vgao(Pdata, r>>(32-d));
268 vgao(Pdata, g>>(32-d));
269 vgao(Pdata, b>>(32-d));
270 unlock(&cursor);
271
272 return ~0;
273 }
274
275 /*
276 * On some video cards (e.g. Mach64), the palette is used as the
277 * DAC registers for >8-bit modes. We don't want to set them when the user
278 * is trying to set a colormap and the card is in one of these modes.
279 */
280 int
281 setcolor(ulong p, ulong r, ulong g, ulong b)
282 {
283 VGAscr *scr;
284 int x;
285
286 scr = &vgascreen[0];
287 if(scr->gscreen == nil)
288 return 0;
289
290 switch(scr->gscreen->depth){
291 case 1:
292 case 2:
293 case 4:
294 x = 0x0F;
295 break;
296 case 8:
297 x = 0xFF;
298 break;
299 default:
300 return 0;
301 }
302 p &= x;
303
304 return setpalette(p, r, g, b);
305 }
306
307 int
308 cursoron(int dolock)
309 {
310 VGAscr *scr;
311 int v;
312
313 scr = &vgascreen[0];
314 if(scr->cur == nil || scr->cur->move == nil)
315 return 0;
316
317 if(dolock)
318 lock(&cursor);
319 v = scr->cur->move(scr, mousexy());
320 if(dolock)
321 unlock(&cursor);
322
323 return v;
324 }
325
326 void
327 cursoroff(int)
328 {
329 }
330
331 void
332 setcursor(Cursor* curs)
333 {
334 VGAscr *scr;
335
336 scr = &vgascreen[0];
337 if(scr->cur == nil || scr->cur->load == nil)
338 return;
339
340 scr->cur->load(scr, curs);
341 }
342
343 int hwaccel = 1;
344 int hwblank = 0; /* turned on by drivers that are known good */
345 int panning = 0;
346
347 int
348 hwdraw(Memdrawparam *par)
349 {
350 VGAscr *scr;
351 Memimage *dst, *src, *mask;
352 int m;
353
354 if(hwaccel == 0)
355 return 0;
356
357 scr = &vgascreen[0];
358 if((dst=par->dst) == nil || dst->data == nil)
359 return 0;
360 if((src=par->src) == nil || src->data == nil)
361 return 0;
362 if((mask=par->mask) == nil || mask->data == nil)
363 return 0;
364
365 if(scr->cur == &swcursor){
366 if(dst->data->bdata == gscreendata.bdata)
367 swcursoravoid(par->r);
368 if(src->data->bdata == gscreendata.bdata)
369 swcursoravoid(par->sr);
370 if(mask->data->bdata == gscreendata.bdata)
371 swcursoravoid(par->mr);
372 }
373
374 if(dst->data->bdata != gscreendata.bdata)
375 return 0;
376
377 if(scr->fill==nil && scr->scroll==nil)
378 return 0;
379
380 /*
381 * If we have an opaque mask and source is one opaque
382 * pixel we can convert to the destination format and just
383 * replicate with memset.
384 */
385 m = Simplesrc|Simplemask|Fullmask;
386 if(scr->fill
387 && (par->state&m)==m
388 && ((par->srgba&0xFF) == 0xFF)
389 && (par->op&S) == S)
390 return scr->fill(scr, par->r, par->sdval);
391
392 /*
393 * If no source alpha, an opaque mask, we can just copy the
394 * source onto the destination. If the channels are the same and
395 * the source is not replicated, memmove suffices.
396 */
397 m = Simplemask|Fullmask;
398 if(scr->scroll
399 && src->data->bdata==dst->data->bdata
400 && !(src->flags&Falpha)
401 && (par->state&m)==m
402 && (par->op&S) == S)
403 return scr->scroll(scr, par->r, par->sr);
404
405 return 0;
406 }
407
408 void
409 blankscreen(int blank)
410 {
411 VGAscr *scr;
412
413 scr = &vgascreen[0];
414 if(hwblank){
415 if(scr->blank)
416 scr->blank(scr, blank);
417 else
418 vgablank(scr, blank);
419 }
420 }
421
422 void
423 vgalinearpciid(VGAscr *scr, int vid, int did)
424 {
425 Pcidev *p;
426
427 p = nil;
428 while((p = pcimatch(p, vid, 0)) != nil){
429 if(p->ccrb != 3) /* video card */
430 continue;
431 if(did != 0 && p->did != did)
432 continue;
433 break;
434 }
435 if(p == nil)
436 error("pci video card not found");
437
438 scr->pci = p;
439 vgalinearpci(scr);
440 }
441
442 void
443 vgalinearpci(VGAscr *scr)
444 {
445 ulong paddr;
446 int i, size, best;
447 Pcidev *p;
448
449 p = scr->pci;
450 if(p == nil)
451 return;
452
453 /*
454 * Scan for largest memory region on card.
455 * Some S3 cards (e.g. Savage) have enormous
456 * mmio regions (but even larger frame buffers).
457 * Some 3dfx cards (e.g., Voodoo3) have mmio
458 * buffers the same size as the frame buffer,
459 * but only the frame buffer is marked as
460 * prefetchable (bar&8). If a card doesn't fit
461 * into these heuristics, its driver will have to
462 * call vgalinearaddr directly.
463 */
464 best = -1;
465 for(i=0; i<nelem(p->mem); i++){
466 if(p->mem[i].bar&1) /* not memory */
467 continue;
468 if(p->mem[i].size < 640*480) /* not big enough */
469 continue;
470 if(best==-1
471 || p->mem[i].size > p->mem[best].size
472 || (p->mem[i].size == p->mem[best].size
473 && (p->mem[i].bar&8)
474 && !(p->mem[best].bar&8)))
475 best = i;
476 }
477 if(best >= 0){
478 paddr = p->mem[best].bar & ~0x0F;
479 size = p->mem[best].size;
480 vgalinearaddr(scr, paddr, size);
481 return;
482 }
483 error("no video memory found on pci card");
484 }
485
486 void
487 vgalinearaddr(VGAscr *scr, ulong paddr, int size)
488 {
489 int x, nsize;
490 ulong npaddr;
491
492 /*
493 * new approach. instead of trying to resize this
494 * later, let's assume that we can just allocate the
495 * entire window to start with.
496 */
497
498 if(scr->paddr == paddr && size <= scr->apsize)
499 return;
500
501 if(scr->paddr){
502 /*
503 * could call vunmap and vmap,
504 * but worried about dangling pointers in devdraw
505 */
506 error("cannot grow vga frame buffer");
507 }
508
509 /* round to page boundary, just in case */
510 x = paddr&(BY2PG-1);
511 npaddr = paddr-x;
512 nsize = PGROUND(size+x);
513
514 /*
515 * Don't bother trying to map more than 4000x4000x32 = 64MB.
516 * We only have a 256MB window.
517 */
518 if(nsize > 64*MB)
519 nsize = 64*MB;
520 scr->vaddr = vmap(npaddr, nsize);
521 if(scr->vaddr == 0)
522 error("cannot allocate vga frame buffer");
523 scr->vaddr = (char*)scr->vaddr+x;
524 scr->paddr = paddr;
525 scr->apsize = nsize;
526 }
527
528
529 /*
530 * Software cursor.
531 */
532 int swvisible; /* is the cursor visible? */
533 int swenabled; /* is the cursor supposed to be on the screen? */
534 Memimage* swback; /* screen under cursor */
535 Memimage* swimg; /* cursor image */
536 Memimage* swmask; /* cursor mask */
537 Memimage* swimg1;
538 Memimage* swmask1;
539
540 Point swoffset;
541 Rectangle swrect; /* screen rectangle in swback */
542 Point swpt; /* desired cursor location */
543 Point swvispt; /* actual cursor location */
544 int swvers; /* incremented each time cursor image changes */
545 int swvisvers; /* the version on the screen */
546
547 /*
548 * called with drawlock locked for us, most of the time.
549 * kernel prints at inopportune times might mean we don't
550 * hold the lock, but memimagedraw is now reentrant so
551 * that should be okay: worst case we get cursor droppings.
552 */
553 void
554 swcursorhide(void)
555 {
556 if(swvisible == 0)
557 return;
558 if(swback == nil)
559 return;
560 swvisible = 0;
561 memimagedraw(gscreen, swrect, swback, ZP, memopaque, ZP, S);
562 flushmemscreen(swrect);
563 }
564
565 void
566 swcursoravoid(Rectangle r)
567 {
568 if(swvisible && rectXrect(r, swrect))
569 swcursorhide();
570 }
571
572 void
573 swcursordraw(void)
574 {
575 if(swvisible)
576 return;
577 if(swenabled == 0)
578 return;
579 if(swback == nil || swimg1 == nil || swmask1 == nil)
580 return;
581 assert(!canqlock(&drawlock));
582 swvispt = swpt;
583 swvisvers = swvers;
584 swrect = rectaddpt(Rect(0,0,16,16), swvispt);
585 memimagedraw(swback, swback->r, gscreen, swpt, memopaque, ZP, S);
586 memimagedraw(gscreen, swrect, swimg1, ZP, swmask1, ZP, SoverD);
587 flushmemscreen(swrect);
588 swvisible = 1;
589 }
590
591 /*
592 * Need to lock drawlock for ourselves.
593 */
594 void
595 swenable(VGAscr*)
596 {
597 swenabled = 1;
598 if(canqlock(&drawlock)){
599 swcursordraw();
600 qunlock(&drawlock);
601 }
602 }
603
604 void
605 swdisable(VGAscr*)
606 {
607 swenabled = 0;
608 if(canqlock(&drawlock)){
609 swcursorhide();
610 qunlock(&drawlock);
611 }
612 }
613
614 void
615 swload(VGAscr*, Cursor *curs)
616 {
617 uchar *ip, *mp;
618 int i, j, set, clr;
619
620 if(!swimg || !swmask || !swimg1 || !swmask1)
621 return;
622 /*
623 * Build cursor image and mask.
624 * Image is just the usual cursor image
625 * but mask is a transparent alpha mask.
626 *
627 * The 16x16x8 memimages do not have
628 * padding at the end of their scan lines.
629 */
630 ip = byteaddr(swimg, ZP);
631 mp = byteaddr(swmask, ZP);
632 for(i=0; i<32; i++){
633 set = curs->set[i];
634 clr = curs->clr[i];
635 for(j=0x80; j; j>>=1){
636 *ip++ = set&j ? 0x00 : 0xFF;
637 *mp++ = (clr|set)&j ? 0xFF : 0x00;
638 }
639 }
640 swoffset = curs->offset;
641 swvers++;
642 memimagedraw(swimg1, swimg1->r, swimg, ZP, memopaque, ZP, S);
643 memimagedraw(swmask1, swmask1->r, swmask, ZP, memopaque, ZP, S);
644 }
645
646 int
647 swmove(VGAscr*, Point p)
648 {
649 swpt = addpt(p, swoffset);
650 return 0;
651 }
652
653 void
654 swcursorclock(void)
655 {
656 int x;
657
658 if(!swenabled)
659 return;
660 if(swvisible && eqpt(swpt, swvispt) && swvers==swvisvers)
661 return;
662
663 x = splhi();
664 if(swenabled)
665 if(!swvisible || !eqpt(swpt, swvispt) || swvers!=swvisvers)
666 if(canqlock(&drawlock)){
667 swcursorhide();
668 swcursordraw();
669 qunlock(&drawlock);
670 }
671 splx(x);
672 }
673
674 void
675 swcursorinit(void)
676 {
677 static int init, warned;
678 VGAscr *scr;
679
680 didswcursorinit = 1;
681 if(!init){
682 init = 1;
683 addclock0link(swcursorclock, 10);
684 }
685 scr = &vgascreen[0];
686 if(scr==nil || scr->gscreen==nil)
687 return;
688
689 if(scr->dev == nil || scr->dev->linear == nil){
690 if(!warned){
691 print("cannot use software cursor on non-linear vga screen\n");
692 warned = 1;
693 }
694 return;
695 }
696
697 if(swback){
698 freememimage(swback);
699 freememimage(swmask);
700 freememimage(swmask1);
701 freememimage(swimg);
702 freememimage(swimg1);
703 }
704
705 swback = allocmemimage(Rect(0,0,32,32), gscreen->chan);
706 swmask = allocmemimage(Rect(0,0,16,16), GREY8);
707 swmask1 = allocmemimage(Rect(0,0,16,16), GREY1);
708 swimg = allocmemimage(Rect(0,0,16,16), GREY8);
709 swimg1 = allocmemimage(Rect(0,0,16,16), GREY1);
710 if(swback==nil || swmask==nil || swmask1==nil || swimg==nil || swimg1 == nil){
711 print("software cursor: allocmemimage fails");
712 return;
713 }
714
715 memfillcolor(swmask, DOpaque);
716 memfillcolor(swmask1, DOpaque);
717 memfillcolor(swimg, DBlack);
718 memfillcolor(swimg1, DBlack);
719 }
720
721 VGAcur swcursor =
722 {
723 "soft",
724 swenable,
725 swdisable,
726 swload,
727 swmove,
728 };
729
Cache object: 6e517b02b2766811d8ae6cb76057cd9c
|