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