]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/pc/screen.c
merge
[plan9front.git] / sys / src / 9 / 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 Memimage *gscreen;
23
24 VGAscr vgascreen[1];
25
26 Cursor arrow = {
27         { -1, -1 },
28         { 0xFF, 0xFF, 0x80, 0x01, 0x80, 0x02, 0x80, 0x0C, 
29           0x80, 0x10, 0x80, 0x10, 0x80, 0x08, 0x80, 0x04, 
30           0x80, 0x02, 0x80, 0x01, 0x80, 0x02, 0x8C, 0x04, 
31           0x92, 0x08, 0x91, 0x10, 0xA0, 0xA0, 0xC0, 0x40, 
32         },
33         { 0x00, 0x00, 0x7F, 0xFE, 0x7F, 0xFC, 0x7F, 0xF0, 
34           0x7F, 0xE0, 0x7F, 0xE0, 0x7F, 0xF0, 0x7F, 0xF8, 
35           0x7F, 0xFC, 0x7F, 0xFE, 0x7F, 0xFC, 0x73, 0xF8, 
36           0x61, 0xF0, 0x60, 0xE0, 0x40, 0x40, 0x00, 0x00, 
37         },
38 };
39
40 int
41 screensize(int x, int y, int, ulong chan)
42 {
43         VGAscr *scr;
44
45         qlock(&drawlock);
46         if(waserror()){
47                 qunlock(&drawlock);
48                 nexterror();
49         }
50
51         memimageinit();
52
53         lock(&vgascreenlock);
54         if(waserror()){
55                 unlock(&vgascreenlock);
56                 nexterror();
57         }
58
59         scr = &vgascreen[0];
60         scr->gscreendata = nil;
61         scr->gscreen = nil;
62         if(gscreen){
63                 freememimage(gscreen);
64                 gscreen = nil;
65         }
66
67         if(scr->paddr == 0){
68                 if(scr->dev && scr->dev->page){
69                         scr->vaddr = KADDR(VGAMEM());
70                         scr->apsize = 1<<16;
71                 }
72                 scr->softscreen = 1;
73         }
74         if(scr->softscreen){
75                 gscreen = allocmemimage(Rect(0,0,x,y), chan);
76                 scr->useflush = 1;
77         }else{
78                 static Memdata md;
79
80                 md.ref = 1;
81                 if((md.bdata = scr->vaddr) == 0)
82                         error("framebuffer not maped");
83                 gscreen = allocmemimaged(Rect(0,0,x,y), chan, &md);
84                 scr->useflush = scr->dev && scr->dev->flush;
85         }
86         if(gscreen == nil)
87                 error("no memory for vga memimage");
88
89         scr->palettedepth = 6;  /* default */
90         scr->memdefont = getmemdefont();
91         scr->gscreen = gscreen;
92         scr->gscreendata = gscreen->data;
93
94         physgscreenr = gscreen->r;
95
96         vgaimageinit(chan);
97
98         unlock(&vgascreenlock);
99         poperror();
100
101         drawcmap();
102         swcursorinit();
103
104         qunlock(&drawlock);
105         poperror();
106
107         return 0;
108 }
109
110 int
111 screenaperture(int size, int align)
112 {
113         VGAscr *scr;
114
115         scr = &vgascreen[0];
116
117         if(scr->paddr)  /* set up during enable */
118                 return 0;
119
120         if(size == 0)
121                 return 0;
122
123         if(scr->dev && scr->dev->linear){
124                 scr->dev->linear(scr, size, align);
125                 return 0;
126         }
127
128         /*
129          * Need to allocate some physical address space.
130          * The driver will tell the card to use it.
131          */
132         size = PGROUND(size);
133         scr->paddr = upaalloc(size, align);
134         if(scr->paddr == 0)
135                 return -1;
136         scr->vaddr = vmap(scr->paddr, size);
137         if(scr->vaddr == nil)
138                 return -1;
139         scr->apsize = size;
140
141         return 0;
142 }
143
144 uchar*
145 attachscreen(Rectangle* r, ulong* chan, int* d, int* width, int *softscreen)
146 {
147         VGAscr *scr;
148
149         scr = &vgascreen[0];
150         if(scr->gscreen == nil || scr->gscreendata == nil)
151                 return nil;
152
153         *r = scr->gscreen->clipr;
154         *chan = scr->gscreen->chan;
155         *d = scr->gscreen->depth;
156         *width = scr->gscreen->width;
157         if(scr->gscreendata->allocd){
158                 /*
159                  * we use a memimage as softscreen. devdraw will create its own
160                  * screen image on the backing store of that image. when our gscreen
161                  * and devdraws screenimage gets freed, the imagedata will
162                  * be released.
163                  */
164                 *softscreen = 0xa110c;
165                 scr->gscreendata->ref++;
166         } else
167                 *softscreen = scr->useflush ? 1 : 0;
168         return scr->gscreendata->bdata;
169 }
170
171 void
172 flushmemscreen(Rectangle r)
173 {
174         VGAscr *scr;
175         uchar *sp, *disp, *sdisp, *edisp;
176         int y, len, incs, off, page;
177
178         scr = &vgascreen[0];
179         if(scr->gscreen == nil || scr->useflush == 0)
180                 return;
181         if(scr->dev && scr->dev->flush){
182                 scr->dev->flush(scr, r);
183                 return;
184         }
185         if(rectclip(&r, scr->gscreen->r) == 0)
186                 return;
187         disp = scr->vaddr;
188         incs = scr->gscreen->width*BY2WD;
189         off = (r.min.x*scr->gscreen->depth) / 8;
190         len = (r.max.x*scr->gscreen->depth + 7) / 8;
191         len -= off;
192         off += r.min.y*incs;
193         sp = scr->gscreendata->bdata + scr->gscreen->zero + off;
194
195         /*
196          * Linear framebuffer with softscreen.
197          */
198         if(scr->paddr){
199                 sdisp = disp+off;
200                 for(y = r.min.y; y < r.max.y; y++) {
201                         memmove(sdisp, sp, len);
202                         sp += incs;
203                         sdisp += incs;
204                 }
205                 return;
206         }
207
208         /*
209          * Paged framebuffer window.
210          */
211         if(scr->dev == nil || scr->dev->page == nil)
212                 return;
213
214         page = off/scr->apsize;
215         off %= scr->apsize;
216         sdisp = disp+off;
217         edisp = disp+scr->apsize;
218
219         scr->dev->page(scr, page);
220         for(y = r.min.y; y < r.max.y; y++) {
221                 if(sdisp + incs < edisp) {
222                         memmove(sdisp, sp, len);
223                         sp += incs;
224                         sdisp += incs;
225                 }
226                 else {
227                         off = edisp - sdisp;
228                         page++;
229                         if(off <= len){
230                                 if(off > 0)
231                                         memmove(sdisp, sp, off);
232                                 scr->dev->page(scr, page);
233                                 if(len - off > 0)
234                                         memmove(disp, sp+off, len - off);
235                         }
236                         else {
237                                 memmove(sdisp, sp, len);
238                                 scr->dev->page(scr, page);
239                         }
240                         sp += incs;
241                         sdisp += incs - scr->apsize;
242                 }
243         }
244 }
245
246 void
247 getcolor(ulong p, ulong* pr, ulong* pg, ulong* pb)
248 {
249         VGAscr *scr;
250         ulong x;
251
252         scr = &vgascreen[0];
253         if(scr->gscreen == nil)
254                 return;
255
256         switch(scr->gscreen->depth){
257         default:
258                 x = 0x0F;
259                 break;
260         case 8:
261                 x = 0xFF;
262                 break;
263         }
264         p &= x;
265
266         lock(&cursor);
267         *pr = scr->colormap[p][0];
268         *pg = scr->colormap[p][1];
269         *pb = scr->colormap[p][2];
270         unlock(&cursor);
271 }
272
273 int
274 setpalette(ulong p, ulong r, ulong g, ulong b)
275 {
276         VGAscr *scr;
277         int d;
278
279         scr = &vgascreen[0];
280         d = scr->palettedepth;
281
282         lock(&cursor);
283         scr->colormap[p][0] = r;
284         scr->colormap[p][1] = g;
285         scr->colormap[p][2] = b;
286         vgao(PaddrW, p);
287         vgao(Pdata, r>>(32-d));
288         vgao(Pdata, g>>(32-d));
289         vgao(Pdata, b>>(32-d));
290         unlock(&cursor);
291
292         return ~0;
293 }
294
295 /*
296  * On some video cards (e.g. Mach64), the palette is used as the 
297  * DAC registers for >8-bit modes.  We don't want to set them when the user
298  * is trying to set a colormap and the card is in one of these modes.
299  */
300 int
301 setcolor(ulong p, ulong r, ulong g, ulong b)
302 {
303         VGAscr *scr;
304         int x;
305
306         scr = &vgascreen[0];
307         if(scr->gscreen == nil)
308                 return 0;
309
310         switch(scr->gscreen->depth){
311         case 1:
312         case 2:
313         case 4:
314                 x = 0x0F;
315                 break;
316         case 8:
317                 x = 0xFF;
318                 break;
319         default:
320                 return 0;
321         }
322         p &= x;
323
324         return setpalette(p, r, g, b);
325 }
326
327 void
328 swenable(VGAscr*)
329 {
330         swcursorload(&arrow);
331 }
332
333 void
334 swdisable(VGAscr*)
335 {
336 }
337
338 void
339 swload(VGAscr*, Cursor *curs)
340 {
341         swcursorload(curs);
342 }
343
344 int
345 swmove(VGAscr*, Point p)
346 {
347         swcursorhide();
348         swcursordraw(p);
349         return 0;
350 }
351
352 VGAcur swcursor =
353 {
354         "soft",
355         swenable,
356         swdisable,
357         swload,
358         swmove,
359 };
360
361
362 void
363 cursoron(void)
364 {
365         VGAscr *scr;
366         VGAcur *cur;
367
368         scr = &vgascreen[0];
369         cur = scr->cur;
370         if(cur == nil || cur->move == nil)
371                 return;
372
373         if(cur == &swcursor)
374                 qlock(&drawlock);
375         lock(&cursor);
376         cur->move(scr, mousexy());
377         unlock(&cursor);
378         if(cur == &swcursor)
379                 qunlock(&drawlock);
380 }
381
382 void
383 cursoroff(void)
384 {
385 }
386
387 void
388 setcursor(Cursor* curs)
389 {
390         VGAscr *scr;
391
392         scr = &vgascreen[0];
393         if(scr->cur == nil || scr->cur->load == nil)
394                 return;
395
396         scr->cur->load(scr, curs);
397 }
398
399 int hwaccel = 1;
400 int hwblank = 0;        /* turned on by drivers that are known good */
401 int panning = 0;
402
403 int
404 hwdraw(Memdrawparam *par)
405 {
406         VGAscr *scr;
407         Memimage *dst, *src, *mask;
408         Memdata *scrd;
409         int m;
410
411         scr = &vgascreen[0];
412         scrd = scr->gscreendata;
413         if(scr->gscreen == nil || scrd == nil)
414                 return 0;
415         if((dst = par->dst) == nil || dst->data == nil)
416                 return 0;
417         if((src = par->src) && src->data == nil)
418                 src = nil;
419         if((mask = par->mask) && mask->data == nil)
420                 mask = nil;
421         if(scr->cur == &swcursor){
422                 if(dst->data->bdata == scrd->bdata)
423                         swcursoravoid(par->r);
424                 if(src && src->data->bdata == scrd->bdata)
425                         swcursoravoid(par->sr);
426                 if(mask && mask->data->bdata == scrd->bdata)
427                         swcursoravoid(par->mr);
428         }
429         if(hwaccel == 0)
430                 return 0;
431         if(dst->data->bdata != scrd->bdata || src == nil || mask == nil)
432                 return 0;
433         if(scr->fill==nil && scr->scroll==nil)
434                 return 0;
435
436         /*
437          * If we have an opaque mask and source is one opaque
438          * pixel we can convert to the destination format and just
439          * replicate with memset.
440          */
441         m = Simplesrc|Simplemask|Fullmask;
442         if(scr->fill
443         && (par->state&m)==m
444         && ((par->srgba&0xFF) == 0xFF)
445         && (par->op&S) == S)
446                 return scr->fill(scr, par->r, par->sdval);
447
448         /*
449          * If no source alpha, an opaque mask, we can just copy the
450          * source onto the destination.  If the channels are the same and
451          * the source is not replicated, memmove suffices.
452          */
453         m = Simplemask|Fullmask;
454         if(scr->scroll
455         && src->data->bdata==dst->data->bdata
456         && !(src->flags&Falpha)
457         && (par->state&m)==m
458         && (par->op&S) == S)
459                 return scr->scroll(scr, par->r, par->sr);
460
461         return 0;       
462 }
463
464 void
465 blankscreen(int blank)
466 {
467         VGAscr *scr;
468
469         scr = &vgascreen[0];
470         if(hwblank){
471                 if(scr->blank)
472                         scr->blank(scr, blank);
473                 else
474                         vgablank(scr, blank);
475         }
476 }
477
478 void
479 vgalinearpci(VGAscr *scr)
480 {
481         ulong paddr;
482         int i, size, best;
483         Pcidev *p;
484         
485         p = scr->pci;
486         if(p == nil)
487                 return;
488
489         /*
490          * Scan for largest memory region on card.
491          * Some S3 cards (e.g. Savage) have enormous
492          * mmio regions (but even larger frame buffers).
493          * Some 3dfx cards (e.g., Voodoo3) have mmio
494          * buffers the same size as the frame buffer,
495          * but only the frame buffer is marked as
496          * prefetchable (bar&8).  If a card doesn't fit
497          * into these heuristics, its driver will have to
498          * call vgalinearaddr directly.
499          */
500         best = -1;
501         for(i=0; i<nelem(p->mem); i++){
502                 if(p->mem[i].bar&1)     /* not memory */
503                         continue;
504                 if(p->mem[i].size < 640*480)    /* not big enough */
505                         continue;
506                 if(best==-1 
507                 || p->mem[i].size > p->mem[best].size 
508                 || (p->mem[i].size == p->mem[best].size 
509                   && (p->mem[i].bar&8)
510                   && !(p->mem[best].bar&8)))
511                         best = i;
512         }
513         if(best >= 0){
514                 paddr = p->mem[best].bar & ~0x0F;
515                 size = p->mem[best].size;
516                 vgalinearaddr(scr, paddr, size);
517                 return;
518         }
519         error("no video memory found on pci card");
520 }
521
522 void
523 vgalinearaddr(VGAscr *scr, ulong paddr, int size)
524 {
525         int x, nsize;
526         ulong npaddr;
527
528         /*
529          * new approach.  instead of trying to resize this
530          * later, let's assume that we can just allocate the
531          * entire window to start with.
532          */
533
534         if(scr->paddr == paddr && size <= scr->apsize)
535                 return;
536
537         if(scr->paddr){
538                 /*
539                  * could call vunmap and vmap,
540                  * but worried about dangling pointers in devdraw
541                  */
542                 error("cannot grow vga frame buffer");
543         }
544         
545         /* round to page boundary, just in case */
546         x = paddr&(BY2PG-1);
547         npaddr = paddr-x;
548         nsize = PGROUND(size+x);
549
550         /*
551          * Don't bother trying to map more than 4000x4000x32 = 64MB.
552          * We only have a 256MB window.
553          */
554         if(nsize > 64*MB)
555                 nsize = 64*MB;
556         scr->vaddr = vmap(npaddr, nsize);
557         if(scr->vaddr == 0)
558                 error("cannot allocate vga frame buffer");
559         scr->vaddr = (char*)scr->vaddr+x;
560         scr->paddr = paddr;
561         scr->apsize = nsize;
562         /* let mtrr harmlessly fail on old CPUs, e.g., P54C */
563         if(!waserror()){
564                 mtrr(npaddr, nsize, "wc");
565                 poperror();
566         }
567 }