![cinap_lenrek](/assets/img/avatar_default.png)
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().
610 lines
12 KiB
C
610 lines
12 KiB
C
/*
|
||
* 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;
|
||
}
|
||
}
|