cbscreen.c 13 KB

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