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