xref: /plan9/sys/src/9/bcm/screen.c (revision b4d1cf41cd5301e4c76aef9c04ddee28ac168a8e)
1 /*
2  * bcm2385 framebuffer
3  */
4 
5 #include "u.h"
6 #include "../port/lib.h"
7 #include "mem.h"
8 #include "dat.h"
9 #include "fns.h"
10 
11 #define	Image	IMAGE
12 #include <draw.h>
13 #include <memdraw.h>
14 #include <cursor.h>
15 #include "screen.h"
16 
17 enum {
18 	Tabstop		= 4,
19 	Scroll		= 8,
20 	Wid		= 1024,
21 	Ht		= 768,
22 	Depth		= 16,
23 };
24 
25 Cursor	arrow = {
26 	{ -1, -1 },
27 	{ 0xFF, 0xFF, 0x80, 0x01, 0x80, 0x02, 0x80, 0x0C,
28 	  0x80, 0x10, 0x80, 0x10, 0x80, 0x08, 0x80, 0x04,
29 	  0x80, 0x02, 0x80, 0x01, 0x80, 0x02, 0x8C, 0x04,
30 	  0x92, 0x08, 0x91, 0x10, 0xA0, 0xA0, 0xC0, 0x40,
31 	},
32 	{ 0x00, 0x00, 0x7F, 0xFE, 0x7F, 0xFC, 0x7F, 0xF0,
33 	  0x7F, 0xE0, 0x7F, 0xE0, 0x7F, 0xF0, 0x7F, 0xF8,
34 	  0x7F, 0xFC, 0x7F, 0xFE, 0x7F, 0xFC, 0x73, 0xF8,
35 	  0x61, 0xF0, 0x60, 0xE0, 0x40, 0x40, 0x00, 0x00,
36 	},
37 };
38 
39 Memimage *gscreen;
40 
41 static Memdata xgdata;
42 
43 static Memimage xgscreen =
44 {
45 	{ 0, 0, Wid, Ht },	/* r */
46 	{ 0, 0, Wid, Ht },	/* clipr */
47 	Depth,			/* depth */
48 	3,			/* nchan */
49 	RGB16,			/* chan */
50 	nil,			/* cmap */
51 	&xgdata,		/* data */
52 	0,			/* zero */
53 	0, 			/* width in words of a single scan line */
54 	0,			/* layer */
55 	0,			/* flags */
56 };
57 
58 static Memimage *conscol;
59 static Memimage *back;
60 static Memsubfont *memdefont;
61 
62 static Lock screenlock;
63 
64 static Point	curpos;
65 static int	h, w;
66 static Rectangle window;
67 
68 static void myscreenputs(char *s, int n);
69 static void screenputc(char *buf);
70 static void screenwin(void);
71 
72 /*
73  * Software cursor.
74  */
75 static int	swvisible;	/* is the cursor visible? */
76 static int	swenabled;	/* is the cursor supposed to be on the screen? */
77 static Memimage *swback;	/* screen under cursor */
78 static Memimage *swimg;		/* cursor image */
79 static Memimage *swmask;	/* cursor mask */
80 static Memimage *swimg1;
81 static Memimage *swmask1;
82 
83 static Point	swoffset;
84 static Rectangle swrect;	/* screen rectangle in swback */
85 static Point	swpt;		/* desired cursor location */
86 static Point	swvispt;	/* actual cursor location */
87 static int	swvers;		/* incremented each time cursor image changes */
88 static int	swvisvers;	/* the version on the screen */
89 
90 /*
91  * called with drawlock locked for us, most of the time.
92  * kernel prints at inopportune times might mean we don't
93  * hold the lock, but memimagedraw is now reentrant so
94  * that should be okay: worst case we get cursor droppings.
95  */
96 static void
swcursorhide(void)97 swcursorhide(void)
98 {
99 	if(swvisible == 0)
100 		return;
101 	if(swback == nil)
102 		return;
103 	swvisible = 0;
104 	memimagedraw(gscreen, swrect, swback, ZP, memopaque, ZP, S);
105 	flushmemscreen(swrect);
106 }
107 
108 static void
swcursoravoid(Rectangle r)109 swcursoravoid(Rectangle r)
110 {
111 	if(swvisible && rectXrect(r, swrect))
112 		swcursorhide();
113 }
114 
115 static void
swcursordraw(void)116 swcursordraw(void)
117 {
118 	int dounlock;
119 
120 	if(swvisible)
121 		return;
122 	if(swenabled == 0)
123 		return;
124 	if(swback == nil || swimg1 == nil || swmask1 == nil)
125 		return;
126 	dounlock = canqlock(&drawlock);
127 	swvispt = swpt;
128 	swvisvers = swvers;
129 	swrect = rectaddpt(Rect(0,0,16,16), swvispt);
130 	memimagedraw(swback, swback->r, gscreen, swpt, memopaque, ZP, S);
131 	memimagedraw(gscreen, swrect, swimg1, ZP, swmask1, ZP, SoverD);
132 	flushmemscreen(swrect);
133 	swvisible = 1;
134 	if(dounlock)
135 		qunlock(&drawlock);
136 }
137 
138 int
cursoron(int dolock)139 cursoron(int dolock)
140 {
141 	int retry;
142 
143 	if (dolock)
144 		lock(&cursor);
145 	if (canqlock(&drawlock)) {
146 		retry = 0;
147 		swcursorhide();
148 		swcursordraw();
149 		qunlock(&drawlock);
150 	} else
151 		retry = 1;
152 	if (dolock)
153 		unlock(&cursor);
154 	return retry;
155 }
156 
157 void
cursoroff(int dolock)158 cursoroff(int dolock)
159 {
160 	if (dolock)
161 		lock(&cursor);
162 	swcursorhide();
163 	if (dolock)
164 		unlock(&cursor);
165 }
166 
167 static void
swload(Cursor * curs)168 swload(Cursor *curs)
169 {
170 	uchar *ip, *mp;
171 	int i, j, set, clr;
172 
173 	if(!swimg || !swmask || !swimg1 || !swmask1)
174 		return;
175 	/*
176 	 * Build cursor image and mask.
177 	 * Image is just the usual cursor image
178 	 * but mask is a transparent alpha mask.
179 	 *
180 	 * The 16x16x8 memimages do not have
181 	 * padding at the end of their scan lines.
182 	 */
183 	ip = byteaddr(swimg, ZP);
184 	mp = byteaddr(swmask, ZP);
185 	for(i=0; i<32; i++){
186 		set = curs->set[i];
187 		clr = curs->clr[i];
188 		for(j=0x80; j; j>>=1){
189 			*ip++ = set&j ? 0x00 : 0xFF;
190 			*mp++ = (clr|set)&j ? 0xFF : 0x00;
191 		}
192 	}
193 	swoffset = curs->offset;
194 	swvers++;
195 	memimagedraw(swimg1,  swimg1->r,  swimg,  ZP, memopaque, ZP, S);
196 	memimagedraw(swmask1, swmask1->r, swmask, ZP, memopaque, ZP, S);
197 }
198 
199 /* called from devmouse */
200 void
setcursor(Cursor * curs)201 setcursor(Cursor* curs)
202 {
203 	cursoroff(0);
204 	swload(curs);
205 	cursoron(0);
206 }
207 
208 static int
swmove(Point p)209 swmove(Point p)
210 {
211 	swpt = addpt(p, swoffset);
212 	return 0;
213 }
214 
215 static void
swcursorclock(void)216 swcursorclock(void)
217 {
218 	int x;
219 
220 	if(!swenabled)
221 		return;
222 	swmove(mousexy());
223 	if(swvisible && eqpt(swpt, swvispt) && swvers==swvisvers)
224 		return;
225 
226 	x = splhi();
227 	if(swenabled)
228 	if(!swvisible || !eqpt(swpt, swvispt) || swvers!=swvisvers)
229 	if(canqlock(&drawlock)){
230 		swcursorhide();
231 		swcursordraw();
232 		qunlock(&drawlock);
233 	}
234 	splx(x);
235 }
236 
237 void
swcursorinit(void)238 swcursorinit(void)
239 {
240 	static int init;
241 
242 	if(!init){
243 		init = 1;
244 		addclock0link(swcursorclock, 10);
245 		swenabled = 1;
246 	}
247 	if(swback){
248 		freememimage(swback);
249 		freememimage(swmask);
250 		freememimage(swmask1);
251 		freememimage(swimg);
252 		freememimage(swimg1);
253 	}
254 
255 	swback  = allocmemimage(Rect(0,0,32,32), gscreen->chan);
256 	swmask  = allocmemimage(Rect(0,0,16,16), GREY8);
257 	swmask1 = allocmemimage(Rect(0,0,16,16), GREY1);
258 	swimg   = allocmemimage(Rect(0,0,16,16), GREY8);
259 	swimg1  = allocmemimage(Rect(0,0,16,16), GREY1);
260 	if(swback==nil || swmask==nil || swmask1==nil || swimg==nil || swimg1 == nil){
261 		print("software cursor: allocmemimage fails\n");
262 		return;
263 	}
264 
265 	memfillcolor(swmask, DOpaque);
266 	memfillcolor(swmask1, DOpaque);
267 	memfillcolor(swimg, DBlack);
268 	memfillcolor(swimg1, DBlack);
269 }
270 
271 int
hwdraw(Memdrawparam * par)272 hwdraw(Memdrawparam *par)
273 {
274 	Memimage *dst, *src, *mask;
275 
276 	if((dst=par->dst) == nil || dst->data == nil)
277 		return 0;
278 	if((src=par->src) == nil || src->data == nil)
279 		return 0;
280 	if((mask=par->mask) == nil || mask->data == nil)
281 		return 0;
282 
283 	if(dst->data->bdata == xgdata.bdata)
284 		swcursoravoid(par->r);
285 	if(src->data->bdata == xgdata.bdata)
286 		swcursoravoid(par->sr);
287 	if(mask->data->bdata == xgdata.bdata)
288 		swcursoravoid(par->mr);
289 
290 	return 0;
291 }
292 
293 static int
screensize(void)294 screensize(void)
295 {
296 	char *p;
297 	char *f[3];
298 	int width, height, depth;
299 
300 	p = getconf("vgasize");
301 	if(p == nil || getfields(p, f, nelem(f), 0, "x") != nelem(f) ||
302 	    (width = atoi(f[0])) < 16 ||
303 	    (height = atoi(f[1])) <= 0 ||
304 	    (depth = atoi(f[2])) <= 0)
305 		return -1;
306 	xgscreen.r.max = Pt(width, height);
307 	xgscreen.depth = depth;
308 	return 0;
309 }
310 
311 void
screeninit(void)312 screeninit(void)
313 {
314 	uchar *fb;
315 	int set;
316 	ulong chan;
317 
318 	set = screensize() == 0;
319 	fb = fbinit(set, &xgscreen.r.max.x, &xgscreen.r.max.y, &xgscreen.depth);
320 	if(fb == nil){
321 		print("can't initialise %dx%dx%d framebuffer \n",
322 			xgscreen.r.max.x, xgscreen.r.max.y, xgscreen.depth);
323 		return;
324 	}
325 	xgscreen.clipr = xgscreen.r;
326 	switch(xgscreen.depth){
327 	default:
328 		print("unsupported screen depth %d\n", xgscreen.depth);
329 		xgscreen.depth = 16;
330 		/* fall through */
331 	case 16:
332 		chan = RGB16;
333 		break;
334 	case 24:
335 		chan = BGR24;
336 		break;
337 	case 32:
338 		chan = ARGB32;
339 		break;
340 	}
341 	memsetchan(&xgscreen, chan);
342 	conf.monitor = 1;
343 	xgdata.bdata = fb;
344 	xgdata.ref = 1;
345 	gscreen = &xgscreen;
346 	gscreen->width = wordsperline(gscreen->r, gscreen->depth);
347 
348 	memimageinit();
349 	memdefont = getmemdefont();
350 	screenwin();
351 	screenputs = myscreenputs;
352 }
353 
354 void
flushmemscreen(Rectangle)355 flushmemscreen(Rectangle)
356 {
357 }
358 
359 uchar*
attachscreen(Rectangle * r,ulong * chan,int * d,int * width,int * softscreen)360 attachscreen(Rectangle *r, ulong *chan, int* d, int *width, int *softscreen)
361 {
362 	*r = gscreen->r;
363 	*d = gscreen->depth;
364 	*chan = gscreen->chan;
365 	*width = gscreen->width;
366 	*softscreen = 0;
367 
368 	return gscreen->data->bdata;
369 }
370 
371 void
getcolor(ulong p,ulong * pr,ulong * pg,ulong * pb)372 getcolor(ulong p, ulong *pr, ulong *pg, ulong *pb)
373 {
374 	USED(p, pr, pg, pb);
375 }
376 
377 int
setcolor(ulong p,ulong r,ulong g,ulong b)378 setcolor(ulong p, ulong r, ulong g, ulong b)
379 {
380 	USED(p, r, g, b);
381 	return 0;
382 }
383 
384 void
blankscreen(int blank)385 blankscreen(int blank)
386 {
387 	fbblank(blank);
388 }
389 
390 static void
myscreenputs(char * s,int n)391 myscreenputs(char *s, int n)
392 {
393 	int i;
394 	Rune r;
395 	char buf[4];
396 
397 	if(!islo()) {
398 		/* don't deadlock trying to print in interrupt */
399 		if(!canlock(&screenlock))
400 			return;
401 	}
402 	else
403 		lock(&screenlock);
404 
405 	while(n > 0){
406 		i = chartorune(&r, s);
407 		if(i == 0){
408 			s++;
409 			--n;
410 			continue;
411 		}
412 		memmove(buf, s, i);
413 		buf[i] = 0;
414 		n -= i;
415 		s += i;
416 		screenputc(buf);
417 	}
418 	unlock(&screenlock);
419 }
420 
421 static void
screenwin(void)422 screenwin(void)
423 {
424 	char *greet;
425 	Memimage *orange;
426 	Point p, q;
427 	Rectangle r;
428 
429 	back = memwhite;
430 	conscol = memblack;
431 
432 	orange = allocmemimage(Rect(0, 0, 1, 1), RGB16);
433 	orange->flags |= Frepl;
434 	orange->clipr = gscreen->r;
435 	orange->data->bdata[0] = 0x40;		/* magic: colour? */
436 	orange->data->bdata[1] = 0xfd;		/* magic: colour? */
437 
438 	w = memdefont->info[' '].width;
439 	h = memdefont->height;
440 
441 	r = insetrect(gscreen->r, 4);
442 
443 	memimagedraw(gscreen, r, memblack, ZP, memopaque, ZP, S);
444 	window = insetrect(r, 4);
445 	memimagedraw(gscreen, window, memwhite, ZP, memopaque, ZP, S);
446 
447 	memimagedraw(gscreen, Rect(window.min.x, window.min.y,
448 		window.max.x, window.min.y + h + 5 + 6), orange, ZP, nil, ZP, S);
449 	freememimage(orange);
450 	window = insetrect(window, 5);
451 
452 	greet = " Plan 9 Console ";
453 	p = addpt(window.min, Pt(10, 0));
454 	q = memsubfontwidth(memdefont, greet);
455 	memimagestring(gscreen, p, conscol, ZP, memdefont, greet);
456 	flushmemscreen(r);
457 	window.min.y += h + 6;
458 	curpos = window.min;
459 	window.max.y = window.min.y + ((window.max.y - window.min.y) / h) * h;
460 }
461 
462 static void
scroll(void)463 scroll(void)
464 {
465 	int o;
466 	Point p;
467 	Rectangle r;
468 
469 	o = Scroll*h;
470 	r = Rpt(window.min, Pt(window.max.x, window.max.y-o));
471 	p = Pt(window.min.x, window.min.y+o);
472 	memimagedraw(gscreen, r, gscreen, p, nil, p, S);
473 	flushmemscreen(r);
474 	r = Rpt(Pt(window.min.x, window.max.y-o), window.max);
475 	memimagedraw(gscreen, r, back, ZP, nil, ZP, S);
476 	flushmemscreen(r);
477 
478 	curpos.y -= o;
479 }
480 
481 static void
screenputc(char * buf)482 screenputc(char *buf)
483 {
484 	int w;
485 	uint pos;
486 	Point p;
487 	Rectangle r;
488 	static int *xp;
489 	static int xbuf[256];
490 
491 	if (xp < xbuf || xp >= &xbuf[sizeof(xbuf)])
492 		xp = xbuf;
493 
494 	switch (buf[0]) {
495 	case '\n':
496 		if (curpos.y + h >= window.max.y)
497 			scroll();
498 		curpos.y += h;
499 		screenputc("\r");
500 		break;
501 	case '\r':
502 		xp = xbuf;
503 		curpos.x = window.min.x;
504 		break;
505 	case '\t':
506 		p = memsubfontwidth(memdefont, " ");
507 		w = p.x;
508 		if (curpos.x >= window.max.x - Tabstop * w)
509 			screenputc("\n");
510 
511 		pos = (curpos.x - window.min.x) / w;
512 		pos = Tabstop - pos % Tabstop;
513 		*xp++ = curpos.x;
514 		r = Rect(curpos.x, curpos.y, curpos.x + pos * w, curpos.y + h);
515 		memimagedraw(gscreen, r, back, back->r.min, nil, back->r.min, S);
516 		flushmemscreen(r);
517 		curpos.x += pos * w;
518 		break;
519 	case '\b':
520 		if (xp <= xbuf)
521 			break;
522 		xp--;
523 		r = Rect(*xp, curpos.y, curpos.x, curpos.y + h);
524 		memimagedraw(gscreen, r, back, back->r.min, nil, back->r.min, S);
525 		flushmemscreen(r);
526 		curpos.x = *xp;
527 		break;
528 	case '\0':
529 		break;
530 	default:
531 		p = memsubfontwidth(memdefont, buf);
532 		w = p.x;
533 
534 		if (curpos.x >= window.max.x - w)
535 			screenputc("\n");
536 
537 		*xp++ = curpos.x;
538 		r = Rect(curpos.x, curpos.y, curpos.x + w, curpos.y + h);
539 		memimagedraw(gscreen, r, back, back->r.min, nil, back->r.min, S);
540 		memimagestring(gscreen, curpos, conscol, ZP, memdefont, buf);
541 		flushmemscreen(r);
542 		curpos.x += w;
543 		break;
544 	}
545 }
546