screen.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719
  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. * Some 3dfx cards (e.g., Voodoo3) have mmio
  382. * buffers the same size as the frame buffer,
  383. * but only the frame buffer is marked as
  384. * prefetchable (bar&8). If a card doesn't fit
  385. * into these heuristics, its driver will have to
  386. * call vgalinearaddr directly.
  387. */
  388. best = -1;
  389. for(i=0; i<nelem(p->mem); i++){
  390. if(p->mem[i].bar&1) /* not memory */
  391. continue;
  392. if(p->mem[i].size < 640*480) /* not big enough */
  393. continue;
  394. if(best==-1
  395. || p->mem[i].size > p->mem[best].size
  396. || (p->mem[i].size == p->mem[best].size && (p->mem[i].bar&8)))
  397. best = i;
  398. }
  399. if(best >= 0){
  400. paddr = p->mem[best].bar & ~0x0F;
  401. size = p->mem[best].size;
  402. vgalinearaddr(scr, paddr, size);
  403. return;
  404. }
  405. error("no video memory found on pci card");
  406. }
  407. void
  408. vgalinearaddr(VGAscr *scr, ulong paddr, int size)
  409. {
  410. int x, nsize;
  411. ulong npaddr;
  412. /*
  413. * new approach. instead of trying to resize this
  414. * later, let's assume that we can just allocate the
  415. * entire window to start with.
  416. */
  417. if(scr->paddr == paddr && size <= scr->apsize)
  418. return;
  419. if(scr->paddr){
  420. /*
  421. * could call vunmap and vmap,
  422. * but worried about dangling pointers in devdraw
  423. */
  424. error("cannot grow vga frame buffer");
  425. }
  426. /* round to page boundary, just in case */
  427. x = paddr&(BY2PG-1);
  428. npaddr = paddr-x;
  429. nsize = PGROUND(size+x);
  430. scr->vaddr = vmap(npaddr, nsize);
  431. if(scr->vaddr == 0)
  432. error("cannot allocate vga frame buffer");
  433. scr->vaddr = (char*)scr->vaddr+x;
  434. scr->paddr = paddr;
  435. scr->apsize = nsize;
  436. }
  437. /*
  438. * Software cursor.
  439. */
  440. int swvisible; /* is the cursor visible? */
  441. int swenabled; /* is the cursor supposed to be on the screen? */
  442. Memimage* swback; /* screen under cursor */
  443. Memimage* swimg; /* cursor image */
  444. Memimage* swmask; /* cursor mask */
  445. Memimage* swimg1;
  446. Memimage* swmask1;
  447. Point swoffset;
  448. Rectangle swrect; /* screen rectangle in swback */
  449. Point swpt; /* desired cursor location */
  450. Point swvispt; /* actual cursor location */
  451. int swvers; /* incremented each time cursor image changes */
  452. int swvisvers; /* the version on the screen */
  453. /*
  454. * called with drawlock locked for us, most of the time.
  455. * kernel prints at inopportune times might mean we don't
  456. * hold the lock, but memimagedraw is now reentrant so
  457. * that should be okay: worst case we get cursor droppings.
  458. */
  459. void
  460. swcursorhide(void)
  461. {
  462. if(swvisible == 0)
  463. return;
  464. if(swback == nil)
  465. return;
  466. swvisible = 0;
  467. memimagedraw(gscreen, swrect, swback, ZP, memopaque, ZP, S);
  468. }
  469. void
  470. swcursoravoid(Rectangle r)
  471. {
  472. if(swvisible && rectXrect(r, swrect))
  473. swcursorhide();
  474. }
  475. void
  476. swcursordraw(void)
  477. {
  478. if(swvisible)
  479. return;
  480. if(swenabled == 0)
  481. return;
  482. if(swback == nil || swimg1 == nil || swmask1 == nil)
  483. return;
  484. assert(!canqlock(&drawlock));
  485. swvispt = swpt;
  486. swvisvers = swvers;
  487. swrect = rectaddpt(Rect(0,0,16,16), swvispt);
  488. memimagedraw(swback, swback->r, gscreen, swpt, memopaque, ZP, S);
  489. memimagedraw(gscreen, swrect, swimg1, ZP, swmask1, ZP, SoverD);
  490. swvisible = 1;
  491. }
  492. /*
  493. * Need to lock drawlock for ourselves.
  494. */
  495. void
  496. swenable(VGAscr*)
  497. {
  498. swenabled = 1;
  499. if(canqlock(&drawlock)){
  500. swcursordraw();
  501. qunlock(&drawlock);
  502. }
  503. }
  504. void
  505. swdisable(VGAscr*)
  506. {
  507. swenabled = 0;
  508. if(canqlock(&drawlock)){
  509. swcursorhide();
  510. qunlock(&drawlock);
  511. }
  512. }
  513. void
  514. swload(VGAscr*, Cursor *curs)
  515. {
  516. uchar *ip, *mp;
  517. int i, j, set, clr;
  518. if(!swimg || !swmask || !swimg1 || !swmask1)
  519. return;
  520. /*
  521. * Build cursor image and mask.
  522. * Image is just the usual cursor image
  523. * but mask is a transparent alpha mask.
  524. *
  525. * The 16x16x8 memimages do not have
  526. * padding at the end of their scan lines.
  527. */
  528. ip = byteaddr(swimg, ZP);
  529. mp = byteaddr(swmask, ZP);
  530. for(i=0; i<32; i++){
  531. set = curs->set[i];
  532. clr = curs->clr[i];
  533. for(j=0x80; j; j>>=1){
  534. *ip++ = set&j ? 0x00 : 0xFF;
  535. *mp++ = (clr|set)&j ? 0xFF : 0x00;
  536. }
  537. }
  538. swoffset = curs->offset;
  539. swvers++;
  540. memimagedraw(swimg1, swimg1->r, swimg, ZP, memopaque, ZP, S);
  541. memimagedraw(swmask1, swmask1->r, swmask, ZP, memopaque, ZP, S);
  542. }
  543. int
  544. swmove(VGAscr*, Point p)
  545. {
  546. swpt = addpt(p, swoffset);
  547. return 0;
  548. }
  549. void
  550. swcursorclock(void)
  551. {
  552. int x;
  553. if(!swenabled)
  554. return;
  555. if(swvisible && eqpt(swpt, swvispt) && swvers==swvisvers)
  556. return;
  557. x = splhi();
  558. if(swenabled)
  559. if(!swvisible || !eqpt(swpt, swvispt) || swvers!=swvisvers)
  560. if(canqlock(&drawlock)){
  561. swcursorhide();
  562. swcursordraw();
  563. qunlock(&drawlock);
  564. }
  565. splx(x);
  566. }
  567. void
  568. swcursorinit(void)
  569. {
  570. static int init, warned;
  571. VGAscr *scr;
  572. didswcursorinit = 1;
  573. if(!init){
  574. init = 1;
  575. addclock0link(swcursorclock, 10);
  576. }
  577. scr = &vgascreen[0];
  578. if(scr==nil || scr->gscreen==nil)
  579. return;
  580. if(scr->dev == nil || scr->dev->linear == nil){
  581. if(!warned){
  582. print("cannot use software cursor on non-linear vga screen\n");
  583. warned = 1;
  584. }
  585. return;
  586. }
  587. if(swback){
  588. freememimage(swback);
  589. freememimage(swmask);
  590. freememimage(swmask1);
  591. freememimage(swimg);
  592. freememimage(swimg1);
  593. }
  594. swback = allocmemimage(Rect(0,0,32,32), gscreen->chan);
  595. swmask = allocmemimage(Rect(0,0,16,16), GREY8);
  596. swmask1 = allocmemimage(Rect(0,0,16,16), GREY1);
  597. swimg = allocmemimage(Rect(0,0,16,16), GREY8);
  598. swimg1 = allocmemimage(Rect(0,0,16,16), GREY1);
  599. if(swback==nil || swmask==nil || swmask1==nil || swimg==nil || swimg1 == nil){
  600. print("software cursor: allocmemimage: %r");
  601. return;
  602. }
  603. memfillcolor(swmask, DOpaque);
  604. memfillcolor(swmask1, DOpaque);
  605. memfillcolor(swimg, DBlack);
  606. memfillcolor(swimg1, DBlack);
  607. }
  608. VGAcur swcursor =
  609. {
  610. "soft",
  611. swenable,
  612. swdisable,
  613. swload,
  614. swmove,
  615. };