plan9fox/sys/src/9/omap/screen.c
cinap_lenrek 1fe3143e4c kernel: cleanup the software mouse cursor mess
The swcursor used a 32x32 image for saving/restoring
screen contents for no reason.

Add a doflush argument to swcursorhide(), so that
disabling software cursor with a double buffered
softscreen is properly hidden. The doflush parameter
should be set to 0 in all other cases as swcursordraw()
will flushes both (current and previours) locations.

Make sure swcursorinit() and swcursorhide() clear the
visibility flag, even when gscreen is nil.

Remove the cursor locking and just do everything within
the drawlock. All cursor functions such as curson(),
cursoff() and setcursor() will be called drawlock
locked. This also means &cursor can be read.

Fix devmouse cursor reads and writes. We now have the
global cursor variable that is only modified under
the drawlock. So copy under drawlock.

Move the pc software cursor implementation into vgasoft
driver, so screen.c does not need to handle it as
a special case.

Remove unused functions such as drawhasclients().
2020-04-10 17:12:51 +02:00

610 lines
12 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* ti omap35 display subsystem (dss)
*
* can handle 2ⁿ bits per pixel for 0 < n ≤ 4, and 12 and 24 bits.
* can handle 1024×768 at 60 Hz with pixel clock of 63.5 MHz
* 1280×800 at 59.91 Hz with pixel clock of 71 MHz
* 1400×1050 lcd at 50 MHz with pixel clock of 75 MHz
* has 256 24-bit entries in RGB palette
*/
#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "io.h"
#include "ureg.h"
#include "../port/error.h"
#define Image IMAGE
#include <draw.h>
#include <memdraw.h>
#include <cursor.h>
#include "screen.h"
// #include "gamma.h"
enum {
Tabstop = 4, /* should be 8 */
Scroll = 8, /* lines to scroll at one time */
/*
* screen settings for Wid and Ht, should a bit more dynamic?
* http://www.epanorama.net/faq/vga2rgb/calc.html
* used to calculate settings.
*/
// Hbp = (248-1) << 20,
// Hfp = (48-1) << 8,
// Hsw = 112-1,
// Vbp = 38 << 20,
// Vfp = 1 << 8,
// Vsw = 3,
Tft = 0x60,
Loadmode = 2 << 1,
Fifosize = 0x400,
/* dispc sysconfig */
Midlemode = 2 << 12,
Sidlemode = 2 << 3,
EnableWakeup = 1 << 2,
Autoidle = 1 << 0,
/* dispc pool_freq */
Ipc = 1 << 14,
Ihs = 1 << 13,
Ivs = 1 << 12,
Acb = 0x28,
/* gfx attribs */
Burstsize = 2 << 6,
Format = 6 << 1,
Gfxenable = 1 << 0,
/* dispc control */
Gpout1 = 1 << 16,
Gpout0 = 1 << 15,
Tftdata = 3 << 8,
Digital = 1 << 6,
Lcd = 1 << 5,
Stntft = 1 << 3,
Digitalen = 1 << 1,
// Lcden = 1 << 0, /* unused */
};
typedef struct Dispcregs Dispc;
typedef struct Dssregs Dss;
typedef struct Ioregs Ioregs;
struct Ioregs { /* common registers, 68 (0x44) bytes */
ulong rev;
uchar _pad0[0x10-0x4];
ulong sysconf;
ulong sysstat;
ulong irqstat1;
/* Dispc only regs */
ulong irqen1;
ulong wkupen;
ulong _pad1;
ulong irqsts2;
ulong irqen2;
ulong _pad2[4];
ulong ctrl;
};
struct Dssregs { /* display subsys at 0x48050000 */
Ioregs;
ulong sdicrtl;
ulong pllcrtl;
uchar _pad3[0x5c-0x4c];
ulong sdistat;
};
struct Dispcregs { /* display ctlr at 0x48050400 */
Ioregs;
ulong config;
ulong _pad3;
ulong defaultcolor[2];
ulong transcolor[2];
ulong linestat;
ulong linenum;
ulong timing_h;
ulong timing_v;
ulong pol_req;
ulong divisor;
ulong alpha;
ulong digsize;
ulong lcdsize;
ulong base[2]; /* should allocate both to avoid dithering */
ulong pos;
ulong size;
ulong _pad4[4];
ulong attrib;
ulong fifothr;
ulong fifosize;
ulong rowinc;
ulong pixelinc;
ulong winskip;
ulong palette; /* gfx_table_ba */
uchar _pad5[0x5d4 - 0x4bc];
ulong datacycle[3];
uchar _pad5[0x620 - 0x5e0];
ulong cprcoefr;
ulong cprcoefg;
ulong cprcoefb;
ulong preload;
};
OScreen oscreen;
Settings settings[] = {
[Res800x600] { 800, 600, 60, RGB16, 40000, 88, 40, 128, 23, 1, 5, },
[Res1024x768] { 1024, 768, 60, RGB16, 65000, 160, 24, 136, 29, 3, 7, },
[Res1280x1024] { 1280, 1024, 60, RGB16, 108000, 248, 48, 112, 38, 1, 4, },
[Res1400x1050] { 1400, 1050, 50, RGB16, 108000, 248, 48, 112, 38, 1, 4, }, // TODO
};
Omap3fb *framebuf;
Memimage *gscreen;
static Memdata xgdata;
static Memimage xgscreen =
{
{ 0, 0, Wid, Ht }, /* r */
{ 0, 0, Wid, Ht }, /* clipr */
Depth, /* depth */
3, /* nchan */
RGB16, /* chan */
nil, /* cmap */
&xgdata, /* data */
0, /* zero */
Wid*(Depth/BI2BY)/BY2WD, /* width in words of a single scan line */
0, /* layer */
0, /* flags */
};
static Memimage *conscol;
static Memimage *back;
static Memsubfont *memdefont;
static Lock screenlock;
static Point curpos;
static int h, w;
static int landscape = 0; /* screen orientation, default is 0: portrait */
static ushort *vscreen; /* virtual screen */
static Rectangle window;
static Dispc *dispc = (Dispc *)PHYSDISPC;
static Dss *dss = (Dss *)PHYSDSS;
static void omapscreenputs(char *s, int n);
static ulong rep(ulong, int);
static void screenputc(char *buf);
static void screenwin(void);
static void
lcdoff(void)
{
dispc->ctrl &= ~1; /* disable the lcd */
coherence();
dispc->irqstat1 |= 1; /* set framedone */
coherence();
/* the lcd never comes ready, so don't bother with this */
#ifdef notdef
/* spin until the frame is complete, but not forever */
for(cnt = 50; !(dispc->irqstat1 & 1) && cnt-- > 0; )
delay(10);
#endif
delay(20); /* worst case for 1 frame, 50Hz */
}
static void
dssstart(void)
{
/* should reset the dss system */
dss->sysconf |= 1;
coherence();
}
/* see spruf98i §15.6.7.4.2 */
static void
configdispc(void)
{
Settings *sp;
sp = oscreen.settings;
dss->ctrl &= 0x78; /* choose dss clock */
dispc->sysconf = Midlemode | Sidlemode | EnableWakeup | Autoidle;
dispc->config = Loadmode;
coherence();
/* pll */
dispc->defaultcolor[0] = 0; /* set background color to black? */
dispc->defaultcolor[1] = 0;
dispc->transcolor[0] = 0; /* set transparency to full */
dispc->transcolor[1] = 0;
dispc->timing_h = (sp->hbp-1) << 20 | (sp->hfp-1) << 8 |
(sp->hsw-1);
dispc->timing_v = sp->vbp << 20 | sp->vfp << 8 |
(sp->vsw-1);
dispc->pol_req = Ipc | Ihs | Ivs | Acb;
dispc->divisor = 1 << 16 | ((432000+sp->pixelclock-1)/sp->pixelclock);
dispc->lcdsize = (sp->ht - 1) << 16 | (sp->wid - 1);
coherence();
dispc->base[0] = PADDR(framebuf->pixel);
dispc->base[1] = PADDR(framebuf->pixel);
dispc->pos = 0; /* place screen in the left corner */
/* use the whole screen */
dispc->size = (sp->ht - 1) << 16 | (sp->wid - 1);
/* what mode does plan 9 use for fb? */
dispc->attrib = Burstsize | Format | Gfxenable;
dispc->preload = Tft;
dispc->fifosize = Fifosize;
/* 1008 is max for our Burstsize */
dispc->fifothr = (Fifosize - 1) << 16 | (1008 - 1);
/* 1 byte is one pixel (not true, we use 2 bytes per pixel) */
dispc->rowinc = 1;
dispc->pixelinc = 1;
dispc->winskip = 0; /* don't skip anything */
coherence();
// dispc->palette = PADDR(framebuf->palette);
}
static void
lcdon(int enable)
{
dispc->ctrl = Gpout1 | Gpout0 | Tftdata | Digital | Lcd | Stntft |
Digitalen | enable;
coherence();
delay(10);
}
static void
lcdstop(void)
{
configscreengpio();
screenclockson();
lcdoff();
}
static void
lcdinit(void)
{
lcdstop();
dssstart();
configdispc();
}
/* Paint the image data with blue pixels */
void
screentest(void)
{
int i;
for (i = nelem(framebuf->pixel) - 1; i >= 0; i--)
framebuf->pixel[i] = 0x1f; /* blue */
// memset(framebuf->pixel, ~0, sizeof framebuf->pixel); /* white */
}
void
screenpower(int on)
{
blankscreen(on == 0);
}
/* called from devmouse */
void
cursoron(void)
{
swcursorhide(0);
swcursordraw(mousexy());
}
void
cursoroff(void)
{
swcursorhide(0);
}
void
setcursor(Cursor* curs)
{
oscreen.Cursor = *curs;
swcursorload(curs);
}
/* called from main and possibly later from devdss to change resolution */
void
screeninit(void)
{
static int first = 1;
if (first) {
iprint("screeninit...");
oscreen.settings = &settings[Res1280x1024];
lcdstop();
if (framebuf)
free(framebuf);
/* mode is 16*32 = 512 */
framebuf = xspanalloc(sizeof *framebuf, 16*32, 0);
}
lcdinit();
lcdon(1);
if (first) {
memimageinit();
memdefont = getmemdefont();
screentest();
}
xgdata.ref = 1;
xgdata.bdata = (uchar *)framebuf->pixel;
gscreen = &xgscreen;
gscreen->r = Rect(0, 0, Wid, Ht);
gscreen->clipr = gscreen->r;
/* width, in words, of a single scan line */
gscreen->width = Wid * (Depth / BI2BY) / BY2WD;
flushmemscreen(gscreen->r);
if (first) {
iprint("on: blue for 3 seconds...");
delay(3*1000);
iprint("\n");
screenwin(); /* draw border & top orange bar */
screenputs = omapscreenputs;
iprint("screen: frame buffer at %#p for %dx%d\n",
framebuf, oscreen.settings->wid, oscreen.settings->ht);
swcursorinit(); /* needs gscreen set */
first = 0;
}
}
/* flushmemscreen should change buffer? */
void
flushmemscreen(Rectangle r)
{
ulong start, end;
if (r.min.x < 0)
r.min.x = 0;
if (r.max.x > Wid)
r.max.x = Wid;
if (r.min.y < 0)
r.min.y = 0;
if (r.max.y > Ht)
r.max.y = Ht;
if (rectclip(&r, gscreen->r) == 0)
return;
start = (ulong)&framebuf->pixel[r.min.y*Wid + r.min.x];
end = (ulong)&framebuf->pixel[(r.max.y - 1)*Wid + r.max.x -1];
cachedwbse((ulong *)start, end - start);
}
/*
* export screen to devdraw
*/
Memdata*
attachscreen(Rectangle *r, ulong *chan, int* d, int *width, int *softscreen)
{
if(gscreen == nil)
return nil;
*r = gscreen->r;
*d = gscreen->depth;
*chan = gscreen->chan;
*width = gscreen->width;
*softscreen = (landscape == 0);
gscreen->data->ref++;
return gscreen->data;
}
void
getcolor(ulong p, ulong *pr, ulong *pg, ulong *pb)
{
USED(p, pr, pg, pb);
}
int
setcolor(ulong p, ulong r, ulong g, ulong b)
{
USED(p, r, g, b);
return 0;
}
void
blankscreen(int blank)
{
if (blank)
lcdon(0);
else {
lcdinit();
lcdon(1);
}
}
static void
omapscreenputs(char *s, int n)
{
int i;
Rune r;
char buf[4];
if (!islo()) {
/* don't deadlock trying to print in interrupt */
if (!canlock(&screenlock))
return; /* discard s */
} else
lock(&screenlock);
while (n > 0) {
i = chartorune(&r, s);
if (i == 0) {
s++;
--n;
continue;
}
memmove(buf, s, i);
buf[i] = 0;
n -= i;
s += i;
screenputc(buf);
}
unlock(&screenlock);
}
static void
screenwin(void)
{
char *greet;
Memimage *orange;
Point p, q;
Rectangle r;
memsetchan(gscreen, RGB16);
back = memwhite;
conscol = memblack;
orange = allocmemimage(Rect(0, 0, 1, 1), RGB16);
orange->flags |= Frepl;
orange->clipr = gscreen->r;
orange->data->bdata[0] = 0x40; /* magic: colour? */
orange->data->bdata[1] = 0xfd; /* magic: colour? */
w = memdefont->info[' '].width;
h = memdefont->height;
r = insetrect(gscreen->r, 4);
memimagedraw(gscreen, r, memblack, ZP, memopaque, ZP, S);
window = insetrect(r, 4);
memimagedraw(gscreen, window, memwhite, ZP, memopaque, ZP, S);
memimagedraw(gscreen, Rect(window.min.x, window.min.y,
window.max.x, window.min.y + h + 5 + 6), orange, ZP, nil, ZP, S);
freememimage(orange);
window = insetrect(window, 5);
greet = " Plan 9 Console ";
p = addpt(window.min, Pt(10, 0));
q = memsubfontwidth(memdefont, greet);
memimagestring(gscreen, p, conscol, ZP, memdefont, greet);
flushmemscreen(r);
window.min.y += h + 6;
curpos = window.min;
window.max.y = window.min.y + ((window.max.y - window.min.y) / h) * h;
}
static void
scroll(void)
{
int o;
Point p;
Rectangle r;
/* move window contents up Scroll text lines */
o = Scroll * h;
r = Rpt(window.min, Pt(window.max.x, window.max.y - o));
p = Pt(window.min.x, window.min.y + o);
memimagedraw(gscreen, r, gscreen, p, nil, p, S);
flushmemscreen(r);
/* clear the bottom Scroll text lines */
r = Rpt(Pt(window.min.x, window.max.y - o), window.max);
memimagedraw(gscreen, r, back, ZP, nil, ZP, S);
flushmemscreen(r);
curpos.y -= o;
}
static void
screenputc(char *buf)
{
int w;
uint pos;
Point p;
Rectangle r;
static int *xp;
static int xbuf[256];
if (xp < xbuf || xp >= &xbuf[nelem(xbuf)])
xp = xbuf;
switch (buf[0]) {
case '\n':
if (curpos.y + h >= window.max.y)
scroll();
curpos.y += h;
screenputc("\r");
break;
case '\r':
xp = xbuf;
curpos.x = window.min.x;
break;
case '\t':
p = memsubfontwidth(memdefont, " ");
w = p.x;
if (curpos.x >= window.max.x - Tabstop * w)
screenputc("\n");
pos = (curpos.x - window.min.x) / w;
pos = Tabstop - pos % Tabstop;
*xp++ = curpos.x;
r = Rect(curpos.x, curpos.y, curpos.x + pos * w, curpos.y + h);
memimagedraw(gscreen, r, back, back->r.min, nil, back->r.min, S);
flushmemscreen(r);
curpos.x += pos * w;
break;
case '\b':
if (xp <= xbuf)
break;
xp--;
r = Rect(*xp, curpos.y, curpos.x, curpos.y + h);
memimagedraw(gscreen, r, back, back->r.min, nil, back->r.min, S);
flushmemscreen(r);
curpos.x = *xp;
break;
case '\0':
break;
default:
p = memsubfontwidth(memdefont, buf);
w = p.x;
if (curpos.x >= window.max.x - w)
screenputc("\n");
*xp++ = curpos.x;
r = Rect(curpos.x, curpos.y, curpos.x + w, curpos.y + h);
memimagedraw(gscreen, r, back, back->r.min, nil, back->r.min, S);
memimagestring(gscreen, curpos, conscol, ZP, memdefont, buf);
flushmemscreen(r);
curpos.x += w;
}
}