screen.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711
  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 "ureg.h"
  8. #include "../port/error.h"
  9. #define Image IMAGE
  10. #include <draw.h>
  11. #include <memdraw.h>
  12. #include <cursor.h>
  13. #include "screen.h"
  14. #define RGB2K(r,g,b) ((156763*(r)+307758*(g)+59769*(b))>>19)
  15. Point ZP = {0, 0};
  16. Rectangle physgscreenr;
  17. Memdata gscreendata;
  18. Memimage *gscreen;
  19. VGAscr vgascreen[1];
  20. Cursor arrow = {
  21. { -1, -1 },
  22. { 0xFF, 0xFF, 0x80, 0x01, 0x80, 0x02, 0x80, 0x0C,
  23. 0x80, 0x10, 0x80, 0x10, 0x80, 0x08, 0x80, 0x04,
  24. 0x80, 0x02, 0x80, 0x01, 0x80, 0x02, 0x8C, 0x04,
  25. 0x92, 0x08, 0x91, 0x10, 0xA0, 0xA0, 0xC0, 0x40,
  26. },
  27. { 0x00, 0x00, 0x7F, 0xFE, 0x7F, 0xFC, 0x7F, 0xF0,
  28. 0x7F, 0xE0, 0x7F, 0xE0, 0x7F, 0xF0, 0x7F, 0xF8,
  29. 0x7F, 0xFC, 0x7F, 0xFE, 0x7F, 0xFC, 0x73, 0xF8,
  30. 0x61, 0xF0, 0x60, 0xE0, 0x40, 0x40, 0x00, 0x00,
  31. },
  32. };
  33. int didswcursorinit;
  34. int
  35. screensize(int x, int y, int z, ulong chan)
  36. {
  37. VGAscr *scr;
  38. lock(&vgascreenlock);
  39. memimageinit();
  40. scr = &vgascreen[0];
  41. /*
  42. * BUG: need to check if any xalloc'ed memory needs to
  43. * be given back if aperture is set.
  44. */
  45. if(scr->paddr == 0){
  46. int width = (x*z)/BI2WD;
  47. gscreendata.bdata = xalloc(width*BY2WD*y);
  48. if(gscreendata.bdata == 0)
  49. error("screensize: vga soft memory");
  50. /* memset(gscreendata.bdata, 0x72, width*BY2WD*y); /* not really black */
  51. scr->useflush = 1;
  52. scr->paddr = VGAMEM();
  53. scr->vaddr = KADDR(scr->paddr);
  54. scr->apsize = 1<<16;
  55. }
  56. else
  57. gscreendata.bdata = scr->vaddr;
  58. if(gscreen)
  59. freememimage(gscreen);
  60. scr->gscreen = nil;
  61. gscreen = allocmemimaged(Rect(0,0,x,y), chan, &gscreendata);
  62. vgaimageinit(chan);
  63. if(gscreen == nil){
  64. unlock(&vgascreenlock);
  65. return -1;
  66. }
  67. if(scr->dev && scr->dev->flush)
  68. scr->useflush = 1;
  69. scr->palettedepth = 6; /* default */
  70. scr->gscreendata = &gscreendata;
  71. scr->memdefont = getmemdefont();
  72. scr->gscreen = gscreen;
  73. physgscreenr = gscreen->r;
  74. unlock(&vgascreenlock);
  75. if(didswcursorinit)
  76. swcursorinit();
  77. drawcmap();
  78. return 0;
  79. }
  80. int
  81. screenaperture(int size, int align)
  82. {
  83. VGAscr *scr;
  84. scr = &vgascreen[0];
  85. if(scr->paddr) /* set up during enable */
  86. return 0;
  87. if(size == 0)
  88. return 0;
  89. if(scr->dev && scr->dev->linear){
  90. scr->dev->linear(scr, size, align);
  91. return 0;
  92. }
  93. /*
  94. * Need to allocate some physical address space.
  95. * The driver will tell the card to use it.
  96. */
  97. size = PGROUND(size);
  98. scr->paddr = upaalloc(size, align);
  99. if(scr->paddr == 0)
  100. return -1;
  101. scr->vaddr = vmap(scr->paddr, size);
  102. if(scr->vaddr == nil)
  103. return -1;
  104. scr->apsize = size;
  105. return 0;
  106. }
  107. uchar*
  108. attachscreen(Rectangle* r, ulong* chan, int* d, int* width, int *softscreen)
  109. {
  110. VGAscr *scr;
  111. scr = &vgascreen[0];
  112. if(scr->gscreen == nil || scr->gscreendata == nil)
  113. return nil;
  114. *r = scr->gscreen->clipr;
  115. *chan = scr->gscreen->chan;
  116. *d = scr->gscreen->depth;
  117. *width = scr->gscreen->width;
  118. *softscreen = scr->useflush;
  119. return scr->gscreendata->bdata;
  120. }
  121. /*
  122. * It would be fair to say that this doesn't work for >8-bit screens.
  123. */
  124. void
  125. flushmemscreen(Rectangle r)
  126. {
  127. VGAscr *scr;
  128. uchar *sp, *disp, *sdisp, *edisp;
  129. int y, len, incs, off, page;
  130. scr = &vgascreen[0];
  131. if(scr->dev && scr->dev->flush){
  132. scr->dev->flush(scr, r);
  133. return;
  134. }
  135. if(scr->gscreen == nil || scr->useflush == 0)
  136. return;
  137. if(scr->dev == nil || scr->dev->page == nil)
  138. return;
  139. if(rectclip(&r, scr->gscreen->r) == 0)
  140. return;
  141. incs = scr->gscreen->width * BY2WD;
  142. switch(scr->gscreen->depth){
  143. default:
  144. len = 0;
  145. panic("flushmemscreen: depth\n");
  146. break;
  147. case 8:
  148. len = Dx(r);
  149. break;
  150. }
  151. if(len < 1)
  152. return;
  153. off = r.min.y*scr->gscreen->width*BY2WD+(r.min.x*scr->gscreen->depth)/8;
  154. page = off/scr->apsize;
  155. off %= scr->apsize;
  156. disp = scr->vaddr;
  157. sdisp = disp+off;
  158. edisp = disp+scr->apsize;
  159. off = r.min.y*scr->gscreen->width*BY2WD+(r.min.x*scr->gscreen->depth)/8;
  160. sp = scr->gscreendata->bdata + off;
  161. scr->dev->page(scr, page);
  162. for(y = r.min.y; y < r.max.y; y++) {
  163. if(sdisp + incs < edisp) {
  164. memmove(sdisp, sp, len);
  165. sp += incs;
  166. sdisp += incs;
  167. }
  168. else {
  169. off = edisp - sdisp;
  170. page++;
  171. if(off <= len){
  172. if(off > 0)
  173. memmove(sdisp, sp, off);
  174. scr->dev->page(scr, page);
  175. if(len - off > 0)
  176. memmove(disp, sp+off, len - off);
  177. }
  178. else {
  179. memmove(sdisp, sp, len);
  180. scr->dev->page(scr, page);
  181. }
  182. sp += incs;
  183. sdisp += incs - scr->apsize;
  184. }
  185. }
  186. }
  187. void
  188. getcolor(ulong p, ulong* pr, ulong* pg, ulong* pb)
  189. {
  190. VGAscr *scr;
  191. ulong x;
  192. scr = &vgascreen[0];
  193. if(scr->gscreen == nil)
  194. return;
  195. switch(scr->gscreen->depth){
  196. default:
  197. x = 0x0F;
  198. break;
  199. case 8:
  200. x = 0xFF;
  201. break;
  202. }
  203. p &= x;
  204. lock(&cursor);
  205. *pr = scr->colormap[p][0];
  206. *pg = scr->colormap[p][1];
  207. *pb = scr->colormap[p][2];
  208. unlock(&cursor);
  209. }
  210. int
  211. setpalette(ulong p, ulong r, ulong g, ulong b)
  212. {
  213. VGAscr *scr;
  214. int d;
  215. scr = &vgascreen[0];
  216. d = scr->palettedepth;
  217. lock(&cursor);
  218. scr->colormap[p][0] = r;
  219. scr->colormap[p][1] = g;
  220. scr->colormap[p][2] = b;
  221. vgao(PaddrW, p);
  222. vgao(Pdata, r>>(32-d));
  223. vgao(Pdata, g>>(32-d));
  224. vgao(Pdata, b>>(32-d));
  225. unlock(&cursor);
  226. return ~0;
  227. }
  228. /*
  229. * On some video cards (e.g. Mach64), the palette is used as the
  230. * DAC registers for >8-bit modes. We don't want to set them when the user
  231. * is trying to set a colormap and the card is in one of these modes.
  232. */
  233. int
  234. setcolor(ulong p, ulong r, ulong g, ulong b)
  235. {
  236. VGAscr *scr;
  237. int x;
  238. scr = &vgascreen[0];
  239. if(scr->gscreen == nil)
  240. return 0;
  241. switch(scr->gscreen->depth){
  242. case 1:
  243. case 2:
  244. case 4:
  245. x = 0x0F;
  246. break;
  247. case 8:
  248. x = 0xFF;
  249. break;
  250. default:
  251. return 0;
  252. }
  253. p &= x;
  254. return setpalette(p, r, g, b);
  255. }
  256. int
  257. cursoron(int dolock)
  258. {
  259. VGAscr *scr;
  260. int v;
  261. scr = &vgascreen[0];
  262. if(scr->cur == nil || scr->cur->move == nil)
  263. return 0;
  264. if(dolock)
  265. lock(&cursor);
  266. v = scr->cur->move(scr, mousexy());
  267. if(dolock)
  268. unlock(&cursor);
  269. return v;
  270. }
  271. void
  272. cursoroff(int)
  273. {
  274. }
  275. void
  276. setcursor(Cursor* curs)
  277. {
  278. VGAscr *scr;
  279. scr = &vgascreen[0];
  280. if(scr->cur == nil || scr->cur->load == nil)
  281. return;
  282. scr->cur->load(scr, curs);
  283. }
  284. int hwaccel = 1;
  285. int hwblank = 0; /* turned on by drivers that are known good */
  286. int panning = 0;
  287. int
  288. hwdraw(Memdrawparam *par)
  289. {
  290. VGAscr *scr;
  291. Memimage *dst, *src, *mask;
  292. int m;
  293. if(hwaccel == 0)
  294. return 0;
  295. scr = &vgascreen[0];
  296. if((dst=par->dst) == nil || dst->data == nil)
  297. return 0;
  298. if((src=par->src) == nil || src->data == nil)
  299. return 0;
  300. if((mask=par->mask) == nil || mask->data == nil)
  301. return 0;
  302. if(scr->cur == &swcursor){
  303. if(dst->data->bdata == gscreendata.bdata)
  304. swcursoravoid(par->r);
  305. if(src->data->bdata == gscreendata.bdata)
  306. swcursoravoid(par->sr);
  307. if(mask->data->bdata == gscreendata.bdata)
  308. swcursoravoid(par->mr);
  309. }
  310. if(dst->data->bdata != gscreendata.bdata)
  311. return 0;
  312. if(scr->fill==nil && scr->scroll==nil)
  313. return 0;
  314. /*
  315. * If we have an opaque mask and source is one opaque
  316. * pixel we can convert to the destination format and just
  317. * replicate with memset.
  318. */
  319. m = Simplesrc|Simplemask|Fullmask;
  320. if(scr->fill
  321. && (par->state&m)==m
  322. && ((par->srgba&0xFF) == 0xFF)
  323. && (par->op&S) == S)
  324. return scr->fill(scr, par->r, par->sdval);
  325. /*
  326. * If no source alpha, an opaque mask, we can just copy the
  327. * source onto the destination. If the channels are the same and
  328. * the source is not replicated, memmove suffices.
  329. */
  330. m = Simplemask|Fullmask;
  331. if(scr->scroll
  332. && src->data->bdata==dst->data->bdata
  333. && !(src->flags&Falpha)
  334. && (par->state&m)==m
  335. && (par->op&S) == S)
  336. return scr->scroll(scr, par->r, par->sr);
  337. return 0;
  338. }
  339. void
  340. blankscreen(int blank)
  341. {
  342. VGAscr *scr;
  343. scr = &vgascreen[0];
  344. if(hwblank){
  345. if(scr->blank)
  346. scr->blank(scr, blank);
  347. else
  348. vgablank(scr, blank);
  349. }
  350. }
  351. void
  352. vgalinearpciid(VGAscr *scr, int vid, int did)
  353. {
  354. Pcidev *p;
  355. p = nil;
  356. while((p = pcimatch(p, vid, 0)) != nil){
  357. if(p->ccrb != 3) /* video card */
  358. continue;
  359. if(did != 0 && p->did != did)
  360. continue;
  361. break;
  362. }
  363. if(p == nil)
  364. error("pci video card not found");
  365. scr->pci = p;
  366. vgalinearpci(scr);
  367. }
  368. void
  369. vgalinearpci(VGAscr *scr)
  370. {
  371. ulong paddr;
  372. int i, size, best;
  373. Pcidev *p;
  374. p = scr->pci;
  375. if(p == nil)
  376. return;
  377. /*
  378. * Scan for largest memory region on card.
  379. * Some S3 cards (e.g. Savage) have enormous
  380. * mmio regions (but even larger frame buffers).
  381. */
  382. best = -1;
  383. for(i=0; i<nelem(p->mem); i++){
  384. if(p->mem[i].bar&1) /* not memory */
  385. continue;
  386. if(p->mem[i].size < 640*480) /* not big enough */
  387. continue;
  388. if(best==-1 || p->mem[i].size > p->mem[best].size)
  389. best = i;
  390. }
  391. if(best >= 0){
  392. paddr = p->mem[best].bar & ~0x0F;
  393. size = p->mem[best].size;
  394. vgalinearaddr(scr, paddr, size);
  395. return;
  396. }
  397. error("no video memory found on pci card");
  398. }
  399. void
  400. vgalinearaddr(VGAscr *scr, ulong paddr, int size)
  401. {
  402. int x, nsize;
  403. ulong npaddr;
  404. /*
  405. * new approach. instead of trying to resize this
  406. * later, let's assume that we can just allocate the
  407. * entire window to start with.
  408. */
  409. if(scr->paddr == paddr && size <= scr->apsize)
  410. return;
  411. if(scr->paddr){
  412. /*
  413. * could call vunmap and vmap,
  414. * but worried about dangling pointers in devdraw
  415. */
  416. error("cannot grow vga frame buffer");
  417. }
  418. /* round to page boundary, just in case */
  419. x = paddr&(BY2PG-1);
  420. npaddr = paddr-x;
  421. nsize = PGROUND(size+x);
  422. scr->vaddr = vmap(npaddr, nsize);
  423. if(scr->vaddr == 0)
  424. error("cannot allocate vga frame buffer");
  425. scr->vaddr = (char*)scr->vaddr+x;
  426. scr->paddr = paddr;
  427. scr->apsize = nsize;
  428. }
  429. /*
  430. * Software cursor.
  431. */
  432. int swvisible; /* is the cursor visible? */
  433. int swenabled; /* is the cursor supposed to be on the screen? */
  434. Memimage* swback; /* screen under cursor */
  435. Memimage* swimg; /* cursor image */
  436. Memimage* swmask; /* cursor mask */
  437. Memimage* swimg1;
  438. Memimage* swmask1;
  439. Point swoffset;
  440. Rectangle swrect; /* screen rectangle in swback */
  441. Point swpt; /* desired cursor location */
  442. Point swvispt; /* actual cursor location */
  443. int swvers; /* incremented each time cursor image changes */
  444. int swvisvers; /* the version on the screen */
  445. /*
  446. * called with drawlock locked for us, most of the time.
  447. * kernel prints at inopportune times might mean we don't
  448. * hold the lock, but memimagedraw is now reentrant so
  449. * that should be okay: worst case we get cursor droppings.
  450. */
  451. void
  452. swcursorhide(void)
  453. {
  454. if(swvisible == 0)
  455. return;
  456. if(swback == nil)
  457. return;
  458. swvisible = 0;
  459. memimagedraw(gscreen, swrect, swback, ZP, memopaque, ZP, S);
  460. }
  461. void
  462. swcursoravoid(Rectangle r)
  463. {
  464. if(swvisible && rectXrect(r, swrect))
  465. swcursorhide();
  466. }
  467. void
  468. swcursordraw(void)
  469. {
  470. if(swvisible)
  471. return;
  472. if(swenabled == 0)
  473. return;
  474. if(swback == nil || swimg1 == nil || swmask1 == nil)
  475. return;
  476. assert(!canqlock(&drawlock));
  477. swvispt = swpt;
  478. swvisvers = swvers;
  479. swrect = rectaddpt(Rect(0,0,16,16), swvispt);
  480. memimagedraw(swback, swback->r, gscreen, swpt, memopaque, ZP, S);
  481. memimagedraw(gscreen, swrect, swimg1, ZP, swmask1, ZP, SoverD);
  482. swvisible = 1;
  483. }
  484. /*
  485. * Need to lock drawlock for ourselves.
  486. */
  487. void
  488. swenable(VGAscr*)
  489. {
  490. swenabled = 1;
  491. if(canqlock(&drawlock)){
  492. swcursordraw();
  493. qunlock(&drawlock);
  494. }
  495. }
  496. void
  497. swdisable(VGAscr*)
  498. {
  499. swenabled = 0;
  500. if(canqlock(&drawlock)){
  501. swcursorhide();
  502. qunlock(&drawlock);
  503. }
  504. }
  505. void
  506. swload(VGAscr*, Cursor *curs)
  507. {
  508. uchar *ip, *mp;
  509. int i, j, set, clr;
  510. if(!swimg || !swmask || !swimg1 || !swmask1)
  511. return;
  512. /*
  513. * Build cursor image and mask.
  514. * Image is just the usual cursor image
  515. * but mask is a transparent alpha mask.
  516. *
  517. * The 16x16x8 memimages do not have
  518. * padding at the end of their scan lines.
  519. */
  520. ip = byteaddr(swimg, ZP);
  521. mp = byteaddr(swmask, ZP);
  522. for(i=0; i<32; i++){
  523. set = curs->set[i];
  524. clr = curs->clr[i];
  525. for(j=0x80; j; j>>=1){
  526. *ip++ = set&j ? 0x00 : 0xFF;
  527. *mp++ = (clr|set)&j ? 0xFF : 0x00;
  528. }
  529. }
  530. swoffset = curs->offset;
  531. swvers++;
  532. memimagedraw(swimg1, swimg1->r, swimg, ZP, memopaque, ZP, S);
  533. memimagedraw(swmask1, swmask1->r, swmask, ZP, memopaque, ZP, S);
  534. }
  535. int
  536. swmove(VGAscr*, Point p)
  537. {
  538. swpt = addpt(p, swoffset);
  539. return 0;
  540. }
  541. void
  542. swcursorclock(void)
  543. {
  544. int x;
  545. if(!swenabled)
  546. return;
  547. if(swvisible && eqpt(swpt, swvispt) && swvers==swvisvers)
  548. return;
  549. x = splhi();
  550. if(swenabled)
  551. if(!swvisible || !eqpt(swpt, swvispt) || swvers!=swvisvers)
  552. if(canqlock(&drawlock)){
  553. swcursorhide();
  554. swcursordraw();
  555. qunlock(&drawlock);
  556. }
  557. splx(x);
  558. }
  559. void
  560. swcursorinit(void)
  561. {
  562. static int init, warned;
  563. VGAscr *scr;
  564. didswcursorinit = 1;
  565. if(!init){
  566. init = 1;
  567. addclock0link(swcursorclock, 10);
  568. }
  569. scr = &vgascreen[0];
  570. if(scr==nil || scr->gscreen==nil)
  571. return;
  572. if(scr->dev == nil || scr->dev->linear == nil){
  573. if(!warned){
  574. print("cannot use software cursor on non-linear vga screen\n");
  575. warned = 1;
  576. }
  577. return;
  578. }
  579. if(swback){
  580. freememimage(swback);
  581. freememimage(swmask);
  582. freememimage(swmask1);
  583. freememimage(swimg);
  584. freememimage(swimg1);
  585. }
  586. swback = allocmemimage(Rect(0,0,32,32), gscreen->chan);
  587. swmask = allocmemimage(Rect(0,0,16,16), GREY8);
  588. swmask1 = allocmemimage(Rect(0,0,16,16), GREY1);
  589. swimg = allocmemimage(Rect(0,0,16,16), GREY8);
  590. swimg1 = allocmemimage(Rect(0,0,16,16), GREY1);
  591. if(swback==nil || swmask==nil || swmask1==nil || swimg==nil || swimg1 == nil){
  592. print("software cursor: allocmemimage: %r");
  593. return;
  594. }
  595. memfillcolor(swmask, DOpaque);
  596. memfillcolor(swmask1, DOpaque);
  597. memfillcolor(swimg, DBlack);
  598. memfillcolor(swimg1, DBlack);
  599. }
  600. VGAcur swcursor =
  601. {
  602. "soft",
  603. swenable,
  604. swdisable,
  605. swload,
  606. swmove,
  607. };