Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

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