screen.c 14 KB

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