]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/zynq/screen.c
ip: add some primitive rate limiting knobs to counteract bufferbloat
[plan9front.git] / sys / src / 9 / zynq / screen.c
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 "../port/error.h"
8
9 #define Image   IMAGE
10 #include <draw.h>
11 #include <memdraw.h>
12 #include <cursor.h>
13 #include "screen.h"
14
15 Memimage *gscreen;
16
17 static struct {
18         Rendez;
19
20         Rectangle       rect;
21         Proc            *proc;
22
23         uintptr         addr;
24 } fbscreen;
25
26 static struct {
27         Rendez;
28
29         Cursor;
30
31         Proc            *proc;
32         uintptr         addr;
33 } hwcursor;
34
35 void
36 cursoron(void)
37 {
38         wakeup(&hwcursor);
39 }
40
41 void
42 cursoroff(void)
43 {
44 }
45
46 void
47 setcursor(Cursor *curs)
48 {
49         hwcursor.Cursor = *curs;
50 }
51
52 void
53 flushmemscreen(Rectangle r)
54 {
55         if(badrect(fbscreen.rect))
56                 fbscreen.rect = r;
57         else
58                 combinerect(&fbscreen.rect, r);
59         wakeup(&fbscreen);
60 }
61
62 void
63 screeninit(void)
64 {
65         conf.monitor = 1;
66 }
67
68 uchar*
69 attachscreen(Rectangle *r, ulong *chan, int* d, int *width, int *softscreen)
70 {
71         if(gscreen == nil)
72                 return nil;
73
74         *r = gscreen->r;
75         *d = gscreen->depth;
76         *chan = gscreen->chan;
77         *width = gscreen->width;
78
79         /* make devdraw use gscreen->data */
80         *softscreen = 0xa110c;
81         gscreen->data->ref++;
82
83         return gscreen->data->bdata;
84 }
85
86 void
87 getcolor(ulong, ulong *, ulong *, ulong *)
88 {
89 }
90
91 int
92 setcolor(ulong, ulong, ulong, ulong)
93 {
94         return 0;
95 }
96
97 void
98 blankscreen(int)
99 {
100 }
101
102
103 static void
104 cursorproc(void *arg)
105 {
106         uchar *set, *clr;
107         u32int *reg;
108         Point xy;
109         int i;
110
111         for(i = 0; i < NSEG; i++)
112                 if(up->seg[i] == nil && i != ESEG)
113                         break;
114         if(i == NSEG)
115                 panic(up->text);
116
117         up->seg[i] = arg;
118
119         hwcursor.proc = up;
120         if(waserror()){
121                 hwcursor.addr = 0;
122                 hwcursor.proc = nil;
123                 pexit("detached", 1);
124         }
125
126         reg = (u32int*)hwcursor.addr;
127         for(;;){
128                 eqlock(&drawlock);
129                 xy = addpt(mousexy(), hwcursor.offset);
130                 qunlock(&drawlock);
131
132                 set = hwcursor.set;
133                 clr = hwcursor.clr;
134                 for(i=0; i<8; i++){
135                         reg[0x70/4 + i] = clr[i*4]<<24 | clr[i*4+1]<<16 | clr[i*4+2]<<8 | clr[i*4+3];
136                         reg[0x90/4 + i] = set[i*4]<<24 | set[i*4+1]<<16 | set[i*4+2]<<8 | set[i*4+3];
137                 }
138                 reg[0] = (xy.x<<16) | (xy.y&0xFFFF);
139
140                 sleep(&hwcursor, return0, nil);
141         }
142 }
143
144 void
145 mousectl(Cmdbuf *cb)
146 {
147         Segment *s;
148         uintptr addr;
149
150         if(strcmp(cb->f[0], "addr") == 0 && cb->nf == 2){
151                 s = nil;
152                 addr = strtoul(cb->f[1], 0, 0);
153                 if(addr != 0){
154                         if((s = seg(up, addr, 0)) == nil || (s->type&SG_RONLY) != 0
155                         || (addr&3) != 0 || addr+0xB0 > s->top)
156                                 error(Ebadarg);
157                         incref(s);
158                 }
159                 if(hwcursor.proc != nil){
160                         postnote(hwcursor.proc, 0, "die", NUser);
161                         while(hwcursor.proc != nil)
162                                 sched();
163                 }
164                 if(addr != 0){
165                         hwcursor.addr = addr;
166                         kproc("cursor", cursorproc, s);
167                 }
168                 return;
169         }
170
171         if(strcmp(cb->f[0], "linear") == 0){
172                 mouseaccelerate(0);
173                 return;
174         }
175
176         if(strcmp(cb->f[0], "accelerated") == 0){
177                 mouseaccelerate(cb->nf == 1 ? 1 : atoi(cb->f[1]));
178                 return;
179         }
180 }
181
182 static int
183 isflush(void *)
184 {
185         return !badrect(fbscreen.rect);
186 }
187
188 static void
189 screenproc(void *arg)
190 {
191         int sno, n, w;
192         uchar *sp, *dp, *top;
193         Rectangle r;
194
195         for(sno = 0; sno < NSEG; sno++)
196                 if(up->seg[sno] == nil && sno != ESEG)
197                         break;
198         if(sno == NSEG)
199                 panic(up->text);
200
201         up->seg[sno] = arg;
202
203         fbscreen.proc = up;
204         if(waserror()){
205                 fbscreen.addr = 0;
206                 fbscreen.proc = nil;
207                 pexit("detached", 1);
208         }
209
210         for(;;){
211                 sleep(&fbscreen, isflush, nil);
212
213                 eqlock(&drawlock);
214                 r = fbscreen.rect;
215                 fbscreen.rect = ZR;
216                 if(badrect(r) || gscreen == nil || rectclip(&r, gscreen->r) == 0){
217                         qunlock(&drawlock);
218                         continue;
219                 }
220                 w = sizeof(ulong)*gscreen->width;
221                 n = bytesperline(r, gscreen->depth);
222                 sp = byteaddr(gscreen, r.min);
223                 dp = (uchar*)fbscreen.addr + (sp - &gscreen->data->bdata[gscreen->zero]);
224                 top = (uchar*)up->seg[sno]->top;
225                 if(dp+(Dy(r)-1)*w+n > top)
226                         r.max.y = (top-(uchar*)fbscreen.addr)/w;
227                 qunlock(&drawlock);
228
229                 while(r.min.y < r.max.y) {
230                         memmove(dp, sp, n);
231                         sp += w;
232                         dp += w;
233                         r.min.y++;
234                 }
235         }
236 }
237
238 enum {
239         CMaddr,
240         CMsize,
241         CMinit,
242 };
243
244 static Cmdtab fbctlmsg[] = {
245         CMaddr,         "addr",         2,
246         CMsize,         "size",         3,
247         CMinit,         "init",         1,
248 };
249
250 long
251 fbctlwrite(Chan*, void *a, long n, vlong)
252 {
253         Cmdbuf *cb;
254         Cmdtab *ct;
255         ulong x, y, z, chan;
256         Segment *s;
257         uintptr addr;
258         char *p;
259
260         cb = parsecmd(a, n);
261         if(waserror()){
262                 free(cb);
263                 nexterror();
264         }
265         ct = lookupcmd(cb, fbctlmsg, nelem(fbctlmsg));
266         switch(ct->index){
267         case CMaddr:
268                 s = nil;
269                 addr = strtoul(cb->f[1], 0, 0);
270                 if(addr != 0){
271                         if((s = seg(up, addr, 0)) == nil || (s->type&SG_RONLY) != 0)
272                                 error(Ebadarg);
273                         incref(s);
274                 }
275                 if(fbscreen.proc != nil){
276                         postnote(fbscreen.proc, 0, "die", NUser);
277                         while(fbscreen.proc != nil)
278                                 sched();
279                 }
280                 if(addr != 0){
281                         fbscreen.addr = addr;
282                         kproc("screen", screenproc, s);
283                 }
284                 break;
285
286         case CMsize:
287                 x = strtoul(cb->f[1], &p, 0);
288                 if(x == 0 || x > 10240)
289                         error(Ebadarg);
290                 if(*p)
291                         p++;
292                 y = strtoul(p, &p, 0);
293                 if(y == 0 || y > 10240)
294                         error(Ebadarg);
295                 if(*p)
296                         p++;
297                 z = strtoul(p, &p, 0);
298
299                 if((chan = strtochan(cb->f[2])) == 0)
300                         error("bad channel");
301                 if(chantodepth(chan) != z)
302                         error("depth, channel do not match");
303
304                 deletescreenimage();
305                 eqlock(&drawlock);
306                 if(memimageinit() < 0){
307                         qunlock(&drawlock);
308                         error("memimageinit failed");
309                 }
310                 if(gscreen != nil){
311                         freememimage(gscreen);
312                         gscreen = nil;
313                 }
314                 gscreen = allocmemimage(Rect(0,0,x,y), chan);
315                 qunlock(&drawlock);
316                 /* wet floor */
317
318         case CMinit:
319                 if(gscreen == nil)
320                         error("no framebuffer");
321                 resetscreenimage();
322                 break;
323         }
324         free(cb);
325         poperror();
326         return n;
327 }
328
329 long
330 fbctlread(Chan*, void *a, long n, vlong offset)
331 {
332         char buf[256], chan[32], *p, *e;
333
334         p = buf;
335         e = p + sizeof(buf);
336         qlock(&drawlock);
337         if(gscreen != nil){
338                 p = seprint(p, e, "size %dx%dx%d %s\n",
339                         Dx(gscreen->r), Dy(gscreen->r), gscreen->depth,
340                         chantostr(chan, gscreen->chan));
341         }
342         qunlock(&drawlock);
343         seprint(p, e, "addr %#p\n", fbscreen.addr);
344         return readstr(offset, a, n, buf);
345 }