xref: /inferno-os/os/sa1110/gscreen.c (revision 74a4d8c26dd3c1e9febcb717cfd6cb6512991a7a)
1 #include "u.h"
2 #include "../port/lib.h"
3 #include "mem.h"
4 #include "dat.h"
5 #include "fns.h"
6 #include "../port/error.h"
7 #include "io.h"
8 
9 #include <draw.h>
10 #include <memdraw.h>
11 #include <cursor.h>
12 
13 #include "screen.h"
14 
15 enum {
16 	Backgnd = 0xFF,	/* white */
17 	Foregnd =	0x00,	/* black */
18 };
19 
20 #define	DPRINT	if(1)iprint
21 
22 static Memdata xgdata;
23 static Memimage xgscreen =
24 {
25 	{0, 0, 0, 0},	/* r */
26 	{0, 0, 0, 0},	/* clipr */
27 	8,			/* depth */
28 	1,			/* nchan */
29 	CMAP8,		/* chan */
30 	nil,			/* cmap */
31 	&xgdata,		/* data */
32 	0,			/* zero */
33 	0,			/* width */
34 	nil,			/* layer */
35 	0,			/* flags */
36 };
37 
38 Memimage *gscreen;
39 Memimage *conscol;
40 Memimage *back;
41 
42 Memsubfont *memdefont;
43 
44 static Point curpos;
45 static Rectangle window;
46 
47 typedef struct SWcursor SWcursor;
48 
49 static Vdisplay *vd;
50 
51 static char printbuf[1024];
52 static int printbufpos = 0;
53 static void	lcdscreenputs(char*, int);
54 static void screenpbuf(char*, int);
55 void (*screenputs)(char*, int) = screenpbuf;
56 
57 static Cursor arrow = {
58 	{ -1, -1 },
59 	{ 0xFF, 0xFF, 0x80, 0x01, 0x80, 0x02, 0x80, 0x0C,
60 	  0x80, 0x10, 0x80, 0x10, 0x80, 0x08, 0x80, 0x04,
61 	  0x80, 0x02, 0x80, 0x01, 0x80, 0x02, 0x8C, 0x04,
62 	  0x92, 0x08, 0x91, 0x10, 0xA0, 0xA0, 0xC0, 0x40,
63 	},
64 	{ 0x00, 0x00, 0x7F, 0xFE, 0x7F, 0xFC, 0x7F, 0xF0,
65 	  0x7F, 0xE0, 0x7F, 0xE0, 0x7F, 0xF0, 0x7F, 0xF8,
66 	  0x7F, 0xFC, 0x7F, 0xFE, 0x7F, 0xFC, 0x73, 0xF8,
67 	  0x61, 0xF0, 0x60, 0xE0, 0x40, 0x40, 0x00, 0x00,
68 	},
69 };
70 
71 static	ushort	palette16[256];
72 static	void	(*flushpixels)(Rectangle, ulong*, int, ulong*, int);
73 static	void	flush8to4(Rectangle, ulong*, int, ulong*, int);
74 static	void	flush8to4r(Rectangle, ulong*, int, ulong*, int);
75 static	void	flush8to16(Rectangle, ulong*, int, ulong*, int);
76 static	void	flush8to16r(Rectangle, ulong*, int, ulong*, int);
77 
78 /*
79 lccr0=000000b9 lccr1=0b100930 lccr2=0a0108ef lccr3=00300010
80 	---
81 vd->wid=320 bwid=640 gscreen->width=60 fb=d0b7cb80 data=d0ba25c0
82  */
83 
84 int
setcolor(ulong p,ulong r,ulong g,ulong b)85 setcolor(ulong p, ulong r, ulong g, ulong b)
86 {
87 	if(vd->depth >= 8)
88 		p &= 0xff;
89 	else
90 		p &= 0xf;
91 	vd->colormap[p][0] = r;
92 	vd->colormap[p][1] = g;
93 	vd->colormap[p][2] = b;
94 	palette16[p] = ((r>>(32-4))<<12)|((g>>(32-4))<<7)|((b>>(32-4))<<1);
95 	lcd_setcolor(p, r, g, b);
96 	return ~0;
97 }
98 
99 void
getcolor(ulong p,ulong * pr,ulong * pg,ulong * pb)100 getcolor(ulong p, ulong *pr, ulong *pg, ulong *pb)
101 {
102 	if(vd->depth >= 8)
103 		p = (p&0xff)^0xff;
104 	else
105 		p = (p&0xf)^0xf;
106 	*pr = vd->colormap[p][0];
107 	*pg = vd->colormap[p][1];
108 	*pb = vd->colormap[p][2];
109 }
110 
111 void
graphicscmap(int invert)112 graphicscmap(int invert)
113 {
114 	int num, den, i, j;
115 	int r, g, b, cr, cg, cb, v, p;
116 
117 	for(r=0,i=0;r!=4;r++) for(v=0;v!=4;v++,i+=16){
118 		for(g=0,j=v-r;g!=4;g++) for(b=0;b!=4;b++,j++){
119 			den=r;
120 			if(g>den) den=g;
121 			if(b>den) den=b;
122 			if(den==0)	/* divide check -- pick grey shades */
123 				cr=cg=cb=v*17;
124 			else{
125 				num=17*(4*den+v);
126 				cr=r*num/den;
127 				cg=g*num/den;
128 				cb=b*num/den;
129 			}
130 			p = (i+(j&15));
131 			if(invert)
132 				p ^= 0xFF;
133 			if(vd->depth == 4) {
134 				if((p&0xf) != (p>>4))
135 					continue;
136 				p &= 0xf;
137 			}
138 			setcolor(p,
139 				cr*0x01010101,
140 				cg*0x01010101,
141 				cb*0x01010101);
142 		}
143 	}
144 	lcd_flush();
145 }
146 
147 static uchar lum[256]={
148   0,   7,  15,  23,  39,  47,  55,  63,  79,  87,  95, 103, 119, 127, 135, 143,
149 154,  17,   9,  17,  25,  49,  59,  62,  68,  89,  98, 107, 111, 129, 138, 146,
150 157, 166,  34,  11,  19,  27,  59,  71,  69,  73,  99, 109, 119, 119, 139, 148,
151 159, 169, 178,  51,  13,  21,  29,  69,  83,  75,  78, 109, 120, 131, 128, 149,
152  28,  35,  43,  60,  68,  75,  83, 100, 107, 115, 123, 140, 147, 155, 163,  20,
153  25,  35,  40,  47,  75,  85,  84,  89, 112, 121, 129, 133, 151, 159, 168, 176,
154 190,  30,  42,  44,  50,  90, 102,  94,  97, 125, 134, 144, 143, 163, 172, 181,
155 194, 204,  35,  49,  49,  54, 105, 119, 103, 104, 137, 148, 158, 154, 175, 184,
156  56,  63,  80,  88,  96, 103, 120, 128, 136, 143, 160, 168, 175, 183,  40,  48,
157  54,  63,  69,  90,  99, 107, 111, 135, 144, 153, 155, 173, 182, 190, 198,  45,
158  50,  60,  70,  74, 100, 110, 120, 120, 150, 160, 170, 167, 186, 195, 204, 214,
159 229,  55,  66,  77,  79, 110, 121, 131, 129, 165, 176, 187, 179, 200, 210, 219,
160  84, 100, 108, 116, 124, 140, 148, 156, 164, 180, 188, 196, 204,  60,  68,  76,
161  82,  91, 108, 117, 125, 134, 152, 160, 169, 177, 195, 204, 212, 221,  66,  74,
162  80,  89,  98, 117, 126, 135, 144, 163, 172, 181, 191, 210, 219, 228, 238,  71,
163  76,  85,  95, 105, 126, 135, 145, 155, 176, 185, 195, 205, 225, 235, 245, 255,
164 };
165 
166 void flushmemscreen(Rectangle r);
167 
168 void
screenclear(void)169 screenclear(void)
170 {
171 	memimagedraw(gscreen, gscreen->r, memwhite, ZP, memopaque, ZP, SoverD);
172 	curpos = window.min;
173 	flushmemscreen(gscreen->r);
174 }
175 
176 static void
setscreen(LCDmode * mode)177 setscreen(LCDmode *mode)
178 {
179 	int h;
180 
181 //	if(swc != nil)
182 //		swcurs_destroy(swc);
183 
184 	vd = lcd_init(mode);
185 	if(vd == nil)
186 		panic("can't initialise LCD");
187 
188 	if(lum[255] == 255) {
189 		int i;
190 		for(i=0; i<256; i++)
191 			lum[i] >>= 4;	/* could support depths other than 4 */
192 	}
193 
194 	gscreen = &xgscreen;
195 	xgdata.ref = 1;
196 
197 	if(conf.portrait == 0)
198 		gscreen->r = Rect(0, 0, vd->x, vd->y);
199 	else
200 		gscreen->r = Rect(0, 0, vd->y, vd->x);
201 	gscreen->clipr = gscreen->r;
202 	gscreen->depth = 8;
203 	gscreen->width = wordsperline(gscreen->r, gscreen->depth);
204 	if(vd->depth == 4 || vd->depth == 16 || conf.portrait) {	/* use 8 to 4 bit fakeout for speed */
205 		if((xgdata.bdata = xspanalloc(gscreen->width*gscreen->r.max.y*BY2WD+CACHELINESZ, CACHELINESZ, 0)) == nil)
206 			panic("can't alloc vidmem");
207 		xgdata.bdata = minicached(xgdata.bdata);
208 		if(conf.portrait == 0)
209 			flushpixels = vd->depth==4? flush8to4: flush8to16;
210 		else
211 			flushpixels = vd->depth==4? flush8to4r: flush8to16r;
212 	} else{
213 		xgdata.bdata = (uchar*)vd->fb;
214 		flushpixels = nil;
215 	}
216 	memimageinit();
217 	memdefont = getmemdefont();
218 
219 	memsetchan(gscreen, CMAP8);	/* TO DO: could now use RGB16 */
220 	back = memwhite;
221 	conscol = memblack;
222 	memimagedraw(gscreen, gscreen->r, memwhite, ZP, memopaque, ZP, SoverD);
223 
224 	DPRINT("vd->wid=%d bwid=%d gscreen->width=%ld fb=%p data=%p\n",
225 		vd->x, vd->bwid, gscreen->width, vd->fb, xgdata.bdata);
226 	graphicscmap(0);
227 	h = memdefont->height;
228 	window = insetrect(gscreen->r, 4);
229 	window.max.y = window.min.y+(Dy(window)/h)*h;
230 	screenclear();
231 
232 //	swc = swcurs_create(gscreendata.data, gscreen.width, gscreen.ldepth, gscreen.r, 1);
233 
234 	drawcursor(nil);
235 }
236 
237 void
screeninit(void)238 screeninit(void)
239 {
240 	LCDmode lcd;
241 
242 	memset(&lcd, 0, sizeof(lcd));
243 	if(archlcdmode(&lcd) < 0)
244 		return;
245 	setscreen(&lcd);
246 	screenputs = lcdscreenputs;
247 	if(printbufpos)
248 		screenputs("", 0);
249 	blanktime = 3;	/* minutes */
250 }
251 
252 uchar*
attachscreen(Rectangle * r,ulong * chan,int * d,int * width,int * softscreen)253 attachscreen(Rectangle *r, ulong *chan, int* d, int *width, int *softscreen)
254 {
255 	*r = gscreen->r;
256 	*d = gscreen->depth;
257 	*chan = gscreen->chan;
258 	*width = gscreen->width;
259 	*softscreen = (gscreen->data->bdata != (uchar*)vd->fb);
260 
261 	return (uchar*)gscreen->data->bdata;
262 }
263 
264 void
detachscreen(void)265 detachscreen(void)
266 {
267 }
268 
269 static void
flush8to4(Rectangle r,ulong * s,int sw,ulong * d,int dw)270 flush8to4(Rectangle r, ulong *s, int sw, ulong *d, int dw)
271 {
272 	int i, h, w;
273 
274 /*
275 	print("1) s=%ux sw=%d d=%ux dw=%d r=(%d,%d)(%d,%d)\n",
276 		s, sw, d, dw, r.min.x, r.min.y, r.max.x, r.max.y);
277 */
278 
279 	r.min.x &= ~7;
280 	r.max.x = (r.max.x + 7) & ~7;
281 	s += (r.min.y*sw)+(r.min.x>>2);
282 	d += (r.min.y*dw)+(r.min.x>>3);
283 	h = Dy(r);
284 	w = Dx(r) >> 3;
285 	sw -= w*2;
286 	dw -= w;
287 
288 	while(h--) {
289 		for(i=w; i; i--) {
290 			ulong v1 = *s++;
291 			ulong v2 = *s++;
292 			*d++ = 	 (lum[v2>>24]<<28)
293 				|(lum[(v2>>16)&0xff]<<24)
294 				|(lum[(v2>>8)&0xff]<<20)
295 				|(lum[v2&0xff]<<16)
296 				|(lum[v1>>24]<<12)
297 				|(lum[(v1>>16)&0xff]<<8)
298 				|(lum[(v1>>8)&0xff]<<4)
299 				|(lum[v1&0xff])
300 				;
301 		}
302 		s += sw;
303 		d += dw;
304 	}
305 }
306 
307 static void
flush8to16(Rectangle r,ulong * s,int sw,ulong * d,int dw)308 flush8to16(Rectangle r, ulong *s, int sw, ulong *d, int dw)
309 {
310 	int i, h, w;
311 	ushort *p;
312 
313 	if(0)
314 		iprint("1) s=%p sw=%d d=%p dw=%d r=[%d,%d, %d,%d]\n",
315 		s, sw, d, dw, r.min.x, r.min.y, r.max.x, r.max.y);
316 
317 	r.min.x &= ~3;
318 	r.max.x = (r.max.x + 3) & ~3;	/* nearest ulong */
319 	s += (r.min.y*sw)+(r.min.x>>2);
320 	d += (r.min.y*dw)+(r.min.x>>1);
321 	h = Dy(r);
322 	w = Dx(r) >> 2;	/* also ulong */
323 	sw -= w;
324 	dw -= w*2;
325 	if(0)
326 		iprint("h=%d w=%d sw=%d dw=%d\n", h, w, sw, dw);
327 
328 	p = palette16;
329 	while(--h >= 0){
330 		for(i=w; --i>=0;){
331 			ulong v = *s++;
332 			*d++ = (p[(v>>8)&0xFF]<<16) | p[v & 0xFF];
333 			*d++ = (p[v>>24]<<16) | p[(v>>16)&0xFF];
334 		}
335 		s += sw;
336 		d += dw;
337 	}
338 }
339 
340 static void
flush8to4r(Rectangle r,ulong * s,int sw,ulong * d,int dw)341 flush8to4r(Rectangle r, ulong *s, int sw, ulong *d, int dw)
342 {
343 	flush8to4(r, s, sw, d, dw);	/* rotation not implemented */
344 }
345 
346 static void
flush8to16r(Rectangle r,ulong * s,int sw,ulong * d,int dw)347 flush8to16r(Rectangle r, ulong *s, int sw, ulong *d, int dw)
348 {
349 	int x, y, w, dws;
350 	ushort *p;
351 	ushort *ds;
352 
353 	if(0)
354 		iprint("1) s=%p sw=%d d=%p dw=%d r=[%d,%d, %d,%d]\n",
355 		s, sw, d, dw, r.min.x, r.min.y, r.max.x, r.max.y);
356 
357 	r.min.y &= ~3;
358 	r.max.y = (r.max.y+3) & ~3;
359 	r.min.x &= ~7;
360 	r.max.x = (r.max.x + 7) & ~7;
361 	s += (r.min.y*sw)+(r.min.x>>2);
362 //	d += (r.min.y*dw)+(r.min.x>>1);
363 	w = Dx(r) >> 2;	/* also ulong */
364 	sw -= w;
365 	dws = dw*2;
366 	if(0)
367 		iprint("h=%d w=%d sw=%d dw=%d x,y=%d,%d %d\n", Dy(r), w, sw, dw, r.min.x,r.min.y, dws);
368 
369 	p = palette16;
370 	for(y=r.min.y; y<r.max.y; y++){
371 		for(x=r.min.x; x<r.max.x; x+=4){
372 			ulong v = *s++;
373 			ds = (ushort*)(d + x*dw) + (gscreen->r.max.y-(y+1));
374 			ds[0] = p[v & 0xFF];
375 			ds[dws] = p[(v>>8)&0xFF];
376 			ds[dws*2] = p[(v>>16)&0xFF];
377 			ds[dws*3] = p[(v>>24)&0xFF];
378 		}
379 		s += sw;
380 	}
381 }
382 
383 void
flushmemscreen(Rectangle r)384 flushmemscreen(Rectangle r)
385 {
386 	if(rectclip(&r, gscreen->r) == 0)
387 		return;
388 	if(r.min.x >= r.max.x || r.min.y >= r.max.y)
389 		return;
390 	if(flushpixels != nil)
391 		flushpixels(r, (ulong*)gscreen->data->bdata, gscreen->width, (ulong*)vd->fb, vd->bwid >> 2);
392 	lcd_flush();
393 }
394 
395 static void
scroll(void)396 scroll(void)
397 {
398 	int o;
399 	Point p;
400 	Rectangle r;
401 
402 	o = 4*memdefont->height;
403 	r = Rpt(window.min, Pt(window.max.x, window.max.y-o));
404 	p = Pt(window.min.x, window.min.y+o);
405 	memimagedraw(gscreen, r, gscreen, p, nil, p, SoverD);
406 	flushmemscreen(r);
407 	r = Rpt(Pt(window.min.x, window.max.y-o), window.max);
408 	memimagedraw(gscreen, r, back, ZP, nil, ZP, SoverD);
409 	flushmemscreen(r);
410 
411 	curpos.y -= o;
412 }
413 
414 static void
clearline(void)415 clearline(void)
416 {
417 	Rectangle r;
418 	int yloc = curpos.y;
419 
420 	r = Rpt(Pt(window.min.x, window.min.y + yloc),
421 		Pt(window.max.x, window.min.y+yloc+memdefont->height));
422 	memimagedraw(gscreen, r, back, ZP, nil, ZP, SoverD);
423 }
424 
425 static void
screenputc(char * buf)426 screenputc(char *buf)
427 {
428 	Point p;
429 	int h, w, pos;
430 	Rectangle r;
431 	static int *xp;
432 	static int xbuf[256];
433 
434 	h = memdefont->height;
435 	if(xp < xbuf || xp >= &xbuf[sizeof(xbuf)])
436 		xp = xbuf;
437 
438 	switch(buf[0]) {
439 	case '\n':
440 		if(curpos.y+h >= window.max.y)
441 			scroll();
442 		curpos.y += h;
443 		/* fall through */
444 	case '\r':
445 		xp = xbuf;
446 		curpos.x = window.min.x;
447 		break;
448 	case '\t':
449 		if(curpos.x == window.min.x)
450 			clearline();
451 		p = memsubfontwidth(memdefont, " ");
452 		w = p.x;
453 		*xp++ = curpos.x;
454 		pos = (curpos.x-window.min.x)/w;
455 		pos = 8-(pos%8);
456 		r = Rect(curpos.x, curpos.y, curpos.x+pos*w, curpos.y+h);
457 		memimagedraw(gscreen, r, back, ZP, nil, ZP, SoverD);
458 		flushmemscreen(r);
459 		curpos.x += pos*w;
460 		break;
461 	case '\b':
462 		if(xp <= xbuf)
463 			break;
464 		xp--;
465 		r = Rpt(Pt(*xp, curpos.y), Pt(curpos.x, curpos.y + h));
466 		memimagedraw(gscreen, r, back, ZP, nil, ZP, SoverD);
467 		flushmemscreen(r);
468 		curpos.x = *xp;
469 		break;
470 	case '\0':
471 		break;
472 	default:
473 		p = memsubfontwidth(memdefont, buf);
474 		w = p.x;
475 
476 		if(curpos.x >= window.max.x-w)
477 			screenputc("\n");
478 
479 		if(curpos.x == window.min.x)
480 			clearline();
481 		if(xp < xbuf+nelem(xbuf))
482 			*xp++ = curpos.x;
483 		r = Rect(curpos.x, curpos.y, curpos.x+w, curpos.y+h);
484 		memimagedraw(gscreen, r, back, ZP, nil, ZP, SoverD);
485 		memimagestring(gscreen, curpos, conscol, ZP, memdefont, buf);
486 		flushmemscreen(r);
487 		curpos.x += w;
488 	}
489 }
490 
491 static void
screenpbuf(char * s,int n)492 screenpbuf(char *s, int n)
493 {
494 	if(printbufpos+n > sizeof(printbuf))
495 		n = sizeof(printbuf)-printbufpos;
496 	if(n > 0) {
497 		memmove(&printbuf[printbufpos], s, n);
498 		printbufpos += n;
499 	}
500 }
501 
502 static void
screendoputs(char * s,int n)503 screendoputs(char *s, int n)
504 {
505 	int i;
506 	Rune r;
507 	char buf[4];
508 
509 	while(n > 0) {
510 		i = chartorune(&r, s);
511 		if(i == 0){
512 			s++;
513 			--n;
514 			continue;
515 		}
516 		memmove(buf, s, i);
517 		buf[i] = 0;
518 		n -= i;
519 		s += i;
520 		screenputc(buf);
521 	}
522 }
523 
524 void
screenflush(void)525 screenflush(void)
526 {
527 	int j = 0;
528 	int k;
529 
530 	for (k = printbufpos; j < k; k = printbufpos) {
531 		screendoputs(printbuf + j, k - j);
532 		j = k;
533 	}
534 	printbufpos = 0;
535 }
536 
537 static void
lcdscreenputs(char * s,int n)538 lcdscreenputs(char *s, int n)
539 {
540 	static Proc *me;
541 
542 	if(!canlock(vd)) {
543 		/* don't deadlock trying to print in interrupt */
544 		/* don't deadlock trying to print while in print */
545 		if(islo() == 0 || up != nil && up == me){
546 			/* save it for later... */
547 			/* In some cases this allows seeing a panic message
548 			  that would be locked out forever */
549 			screenpbuf(s, n);
550 			return;
551 		}
552 		lock(vd);
553 	}
554 
555 	me = up;
556 	if(printbufpos)
557 		screenflush();
558 	screendoputs(s, n);
559 	if(printbufpos)
560 		screenflush();
561 	me = nil;
562 
563 	unlock(vd);
564 }
565 
566 /*
567  * interface between draw, mouse and cursor
568  */
569 void
cursorupdate(Rectangle r)570 cursorupdate(Rectangle r)
571 {
572 }
573 
574 void
cursorenable(void)575 cursorenable(void)
576 {
577 }
578 
579 void
cursordisable(void)580 cursordisable(void)
581 {
582 }
583 
584 void
drawcursor(Drawcursor * c)585 drawcursor(Drawcursor* c)
586 {
587 }
588