1 /* nm Acceleration functions */ 2 3 /* Author: 4 Rudolf Cornelissen 3/2004-8/2004. 5 */ 6 7 /* 8 General note about NeoMagic cards: 9 The Neomagic acceleration engines apparantly contain several faults which is the 10 main reason for the differences in setup for different engines. 11 */ 12 13 #define MODULE_BIT 0x00080000 14 15 #include "nm_std.h" 16 17 static status_t nm_acc_wait_fifo(uint32 n); 18 19 /* 20 acceleration notes: 21 22 -> functions Be's app_server uses: 23 fill span (horizontal only) 24 fill rectangle (these 2 are very similar) 25 invert rectangle 26 blit 27 28 -> Splitting up the acc routines for all cards does not have noticable effects 29 on the acceleration speed, although all those switch statements would vanish. 30 */ 31 32 status_t nm_acc_wait_idle() 33 { 34 /* wait until engine completely idle */ 35 /* Note: 36 * because we have no FIFO functionality we have to make sure we return ASAP(!). 37 * snoozing() for just 1 microSecond already more than halfs the engine 38 * performance... */ 39 while (ACCR(STATUS) & 0x00000001); 40 41 return B_OK; 42 } 43 44 /* wait for enough room in fifo (apparantly works on NM2090 and NM2093 only!) */ 45 static status_t nm_acc_wait_fifo(uint32 n) 46 { 47 while (((ACCR(STATUS) & 0x0000ff00) >> 8) < n) 48 { 49 /* snooze a bit so I do not hammer the bus */ 50 snooze (10); 51 } 52 53 return B_OK; 54 } 55 56 /* AFAIK this must be done for every new screenmode. 57 * Engine required init. */ 58 status_t nm_acc_init() 59 { 60 /* Set pixel width */ 61 switch(si->dm.space) 62 { 63 case B_CMAP8: 64 /* b8-9 determine engine colordepth */ 65 si->engine.control = (1 << 8); 66 si->engine.depth = 1; 67 break; 68 case B_RGB15_LITTLE:case B_RGB16_LITTLE: 69 /* b8-9 determine engine colordepth */ 70 si->engine.control = (2 << 8); 71 si->engine.depth = 2; 72 break; 73 case B_RGB24_LITTLE: 74 /* b8-9 determine engine colordepth */ 75 si->engine.control = (3 << 8); 76 si->engine.depth = 3; 77 /* no acceleration supported on NM2070 - NM2160: let them fallthrough... */ 78 if (si->ps.card_type >= NM2200) break; 79 default: 80 LOG(8,("ACC: init, invalid bit depth\n")); 81 return B_ERROR; 82 } 83 84 /* setup memory pitch (b10-12) on newer cards: 85 * this works with a table, there are very few fixed settings.. */ 86 if(si->ps.card_type > NM2070) 87 { 88 switch(si->fbc.bytes_per_row / si->engine.depth) 89 { 90 case 640: 91 si->engine.control |= (2 << 10); 92 break; 93 case 800: 94 si->engine.control |= (3 << 10); 95 break; 96 case 1024: 97 si->engine.control |= (4 << 10); 98 break; 99 case 1152: 100 si->engine.control |= (5 << 10); 101 break; 102 case 1280: 103 si->engine.control |= (6 << 10); 104 break; 105 case 1600: 106 si->engine.control |= (7 << 10); 107 break; 108 default: 109 LOG(8,("ACC: init, invalid mode width\n")); 110 return B_ERROR; 111 } 112 } 113 114 /* enable engine FIFO (fixme: works this way on pre NM2200 only (engine.control)) */ 115 /* fixme when/if possible: 116 * does not work on most cards.. (tried NM2070 and NM2160) 117 * workaround: always wait until engine completely idle before programming. */ 118 switch (si->ps.card_type) 119 { 120 case NM2090: 121 case NM2093: 122 si->engine.control |= (1 << 27); 123 break; 124 default: 125 break; 126 } 127 128 /* setup buffer startadress */ 129 /* fixme when/if possible: 130 * not possible on all cards or not enough specs known. (tried NM2160) 131 * workaround: place cursor bitmap at _end_ of cardRAM instead of in _beginning_. */ 132 133 /* setup clipping (fixme: works this way on pre NM2200 only (engine.control)) */ 134 /* note: 135 * on NM2160 the max acc engine width of 1600 pixels can be programmed, but 136 * the max. height is only 1023 pixels (height register holds just 10 bits)! 137 * note also: 138 * while the vertical clipping feature can do upto and including 1023 pixels, 139 * the engine itself can do upto and including 1024 pixels vertically. 140 * So: 141 * Don't use the engine's clipping feature as we want to get the max out of the 142 * engine. We won't export the acc hooks for modes beyond the acc engine's 143 * capabilities. */ 144 // si->engine.control |= (1 << 26); 145 // ACCW(CLIPLT, 0); 146 // ACCW(CLIPRB, ((si->dm.virtual_height << 16) | (si->dm.virtual_width & 0x0000ffff))); 147 148 /* init some extra registers on some cards */ 149 switch(si->ps.card_type) 150 { 151 case NM2070: 152 /* make sure the previous command (if any) is completed */ 153 // does not work yet: 154 // nm_acc_wait_fifo(5); 155 // so: 156 nm_acc_wait_idle(); 157 158 /* setup memory pitch */ 159 ACCW(2070_PLANEMASK, 0x0000ffff); 160 ACCW(2070_SRCPITCH, si->fbc.bytes_per_row); 161 ACCW(2070_SRCBITOFF, 0); 162 ACCW(2070_DSTPITCH, si->fbc.bytes_per_row); 163 ACCW(2070_DSTBITOFF, 0); 164 break; 165 case NM2200: 166 case NM2230: 167 case NM2360: 168 case NM2380: 169 /* make sure the previous command (if any) is completed */ 170 // does not work yet: 171 // nm_acc_wait_fifo(2); 172 // so: 173 nm_acc_wait_idle(); 174 175 /* setup engine depth and engine destination-pitch */ 176 ACCW(STATUS, ((si->engine.control & 0x0000ffff) << 16)); 177 /* setup engine source-pitch */ 178 ACCW(2200_SRC_PITCH, 179 ((si->fbc.bytes_per_row << 16) | (si->fbc.bytes_per_row & 0x0000ffff))); 180 break; 181 default: 182 /* nothing to do */ 183 break; 184 } 185 186 return B_OK; 187 } 188 189 /* screen to screen blit - i.e. move windows around and scroll within them. */ 190 status_t nm_acc_blit(uint16 xs,uint16 ys,uint16 xd,uint16 yd,uint16 w,uint16 h) 191 { 192 /* make sure the previous command (if any) is completed */ 193 switch (si->ps.card_type) 194 { 195 case NM2090: 196 case NM2093: 197 nm_acc_wait_fifo(4); 198 break; 199 default: 200 nm_acc_wait_idle(); 201 break; 202 } 203 204 if ((yd < ys) || ((yd == ys) && (xd < xs))) 205 { 206 /* start with upper left corner */ 207 switch (si->ps.card_type) 208 { 209 case NM2070: 210 /* use ROP GXcopy (b16-19), and use linear adressing system */ 211 ACCW(CONTROL, si->engine.control | 0x000c0000); 212 /* send command and exexute (warning: order of programming regs is important!) */ 213 ACCW(2070_XYEXT, ((h << 16) | (w & 0x0000ffff))); 214 ACCW(SRCSTARTOFF, ((ys * si->fbc.bytes_per_row) + (xs * si->engine.depth))); 215 ACCW(2070_DSTSTARTOFF, ((yd * si->fbc.bytes_per_row) + (xd * si->engine.depth))); 216 break; 217 case NM2090: 218 case NM2093: 219 case NM2097: 220 case NM2160: 221 /* use ROP GXcopy (b16-19), and use XY coord. system (b24-25) */ 222 ACCW(CONTROL, si->engine.control | 0x830c0000); 223 /* send command and exexute (warning: order of programming regs is important!) */ 224 ACCW(SRCSTARTOFF, ((ys << 16) | (xs & 0x0000ffff))); 225 ACCW(2090_DSTSTARTOFF, ((yd << 16) | (xd & 0x0000ffff))); 226 ACCW(2090_XYEXT, (((h + 1) << 16) | ((w + 1) & 0x0000ffff))); 227 break; 228 default: /* NM2200 and later */ 229 /* use ROP GXcopy (b16-19), and use linear adressing system */ 230 //fixme? it seems CONTROL nolonger needs direction, and can be pgm'd just once... 231 ACCW(CONTROL, (/*si->engine.control |*/ 0x800c0000)); 232 /* send command and exexute (warning: order of programming regs is important!) */ 233 ACCW(SRCSTARTOFF, ((ys * si->fbc.bytes_per_row) + (xs * si->engine.depth))); 234 ACCW(2090_DSTSTARTOFF, ((yd * si->fbc.bytes_per_row) + (xd * si->engine.depth))); 235 ACCW(2090_XYEXT, (((h + 1) << 16) | ((w + 1) & 0x0000ffff))); 236 break; 237 } 238 } 239 else 240 { 241 /* start with lower right corner */ 242 switch (si->ps.card_type) 243 { 244 case NM2070: 245 /* use ROP GXcopy (b16-19), and use linear adressing system */ 246 ACCW(CONTROL, (si->engine.control | 0x000c0013)); 247 /* send command and exexute (warning: order of programming regs is important!) */ 248 ACCW(2070_XYEXT, ((h << 16) | (w & 0x0000ffff))); 249 ACCW(SRCSTARTOFF, (((ys + h) * si->fbc.bytes_per_row) + ((xs + w) * si->engine.depth))); 250 ACCW(2070_DSTSTARTOFF, (((yd + h) * si->fbc.bytes_per_row) + ((xd + w) * si->engine.depth))); 251 break; 252 case NM2090: 253 case NM2093: 254 case NM2097: 255 case NM2160: 256 /* use ROP GXcopy (b16-19), and use XY coord. system (b24-25) */ 257 ACCW(CONTROL, (si->engine.control | 0x830c0013)); 258 /* send command and exexute (warning: order of programming regs is important!) */ 259 ACCW(SRCSTARTOFF, (((ys + h) << 16) | ((xs + w) & 0x0000ffff))); 260 ACCW(2090_DSTSTARTOFF, (((yd + h) << 16) | ((xd + w) & 0x0000ffff))); 261 ACCW(2090_XYEXT, (((h + 1) << 16) | ((w + 1) & 0x0000ffff))); 262 break; 263 default: /* NM2200 and later */ 264 /* use ROP GXcopy (b16-19), and use linear adressing system */ 265 //fixme? it seems CONTROL nolonger needs direction, and can be pgm'd just once... 266 ACCW(CONTROL, (/*si->engine.control |*/ 0x800c0013)); 267 /* send command and exexute (warning: order of programming regs is important!) */ 268 ACCW(SRCSTARTOFF, (((ys + h) * si->fbc.bytes_per_row) + ((xs + w) * si->engine.depth))); 269 ACCW(2090_DSTSTARTOFF, (((yd + h) * si->fbc.bytes_per_row) + ((xd + w) * si->engine.depth))); 270 ACCW(2090_XYEXT, (((h + 1) << 16) | ((w + 1) & 0x0000ffff))); 271 break; 272 } 273 } 274 275 return B_OK; 276 } 277 278 /* rectangle fill - i.e. workspace and window background color */ 279 /* span fill - i.e. (selected) menuitem background color (Dano) */ 280 status_t nm_acc_setup_rectangle(uint32 color) 281 { 282 /* make sure the previous command (if any) is completed */ 283 switch (si->ps.card_type) 284 { 285 case NM2090: 286 case NM2093: 287 nm_acc_wait_fifo(2); 288 break; 289 default: 290 nm_acc_wait_idle(); 291 break; 292 } 293 294 switch (si->ps.card_type) 295 { 296 case NM2070: 297 /* use ROP GXcopy (b16-19), use linear adressing system, do foreground color (b3) */ 298 ACCW(CONTROL, (si->engine.control | 0x000c0008)); 299 /* setup color */ 300 if (si->engine.depth == 1) 301 ACCW(FGCOLOR, color); 302 else 303 /* swap colorbytes */ 304 ACCW(FGCOLOR, (((color & 0xff00) >> 8) | ((color & 0x00ff) << 8))); 305 break; 306 case NM2090: 307 case NM2093: 308 case NM2097: 309 case NM2160: 310 /* use ROP GXcopy (b16-19), use XY coord. system (b24-25), do foreground color (b3) */ 311 ACCW(CONTROL, (si->engine.control | 0x830c0008)); 312 /* setup color */ 313 ACCW(FGCOLOR, color); 314 break; 315 default: /* NM2200 and later */ 316 /* use ROP GXcopy (b16-19), use XY coord. system (b24-25), do foreground color (b3) */ 317 ACCW(CONTROL, (/*si->engine.control |*/ 0x830c0008)); 318 /* setup color */ 319 ACCW(FGCOLOR, color); 320 break; 321 } 322 323 return B_OK; 324 } 325 326 status_t nm_acc_rectangle(uint32 xs,uint32 xe,uint32 ys,uint32 yl) 327 { 328 /* The engine does not take kindly if we try to let it fill a rect with 329 * zero width. Dano's app_server occasionally tries to let us do that though! 330 * Testable with BeRoMeter 1.2.6, all Ellipses tests. Effect of zero width fill: 331 * horizontal lines across the entire screen at top and bottom of ellipses. */ 332 if (xe == xs) return B_OK; 333 334 /* make sure the previous command (if any) is completed */ 335 switch (si->ps.card_type) 336 { 337 case NM2090: 338 case NM2093: 339 nm_acc_wait_fifo(2); 340 break; 341 default: 342 nm_acc_wait_idle(); 343 break; 344 } 345 346 /* send command and exexute (warning: order of programming regs is important!) */ 347 switch (si->ps.card_type) 348 { 349 case NM2070: 350 ACCW(2070_XYEXT, (((yl - 1) << 16) | ((xe - xs - 1) & 0x0000ffff))); 351 ACCW(2070_DSTSTARTOFF, ((ys * si->fbc.bytes_per_row) + (xs * si->engine.depth))); 352 break; 353 default: /* NM2090 and later */ 354 ACCW(2090_DSTSTARTOFF, ((ys << 16) | (xs & 0x0000ffff))); 355 ACCW(2090_XYEXT, ((yl << 16) | ((xe - xs) & 0x0000ffff))); 356 break; 357 } 358 359 return B_OK; 360 } 361 362 /* rectangle invert - i.e. text cursor and text selection */ 363 status_t nm_acc_setup_rect_invert() 364 { 365 /* make sure the previous command (if any) is completed */ 366 switch (si->ps.card_type) 367 { 368 case NM2090: 369 case NM2093: 370 nm_acc_wait_fifo(2); 371 break; 372 default: 373 nm_acc_wait_idle(); 374 break; 375 } 376 377 switch (si->ps.card_type) 378 { 379 case NM2070: 380 /* use ROP GXinvert (b16-19), use linear adressing system. */ 381 /* note: 382 * although selecting foreground color (b3) should have no influence, NM2070 383 * thinks otherwise if depth is not 8-bit. In 8-bit depth ROP takes precedence 384 * over source-select, but in other spaces it's vice-versa (forcing GXcopy!). */ 385 ACCW(CONTROL, (si->engine.control | 0x00050000)); 386 break; 387 case NM2090: 388 case NM2093: 389 case NM2097: 390 case NM2160: 391 /* use ROP GXinvert (b16-19), use XY coord. system (b24-25), do foreground color (b3) */ 392 ACCW(CONTROL, (si->engine.control | 0x83050008)); 393 break; 394 default: /* NM2200 and later */ 395 /* use ROP GXinvert (b16-19), use XY coord. system (b24-25), do foreground color (b3) */ 396 ACCW(CONTROL, (/*si->engine.control |*/ 0x83050008)); 397 break; 398 } 399 /* reset color (just to be 'safe') */ 400 ACCW(FGCOLOR, 0); 401 402 return B_OK; 403 } 404 405 status_t nm_acc_rectangle_invert(uint32 xs,uint32 xe,uint32 ys,uint32 yl) 406 { 407 /* The engine probably also does not take kindly if we try to let it invert a 408 * rect with zero width... (see nm_acc_rectangle() routine for explanation.) */ 409 if (xe == xs) return B_OK; 410 411 /* make sure the previous command (if any) is completed */ 412 switch (si->ps.card_type) 413 { 414 case NM2090: 415 case NM2093: 416 nm_acc_wait_fifo(2); 417 break; 418 default: 419 nm_acc_wait_idle(); 420 break; 421 } 422 423 /* send command and exexute (warning: order of programming regs is important!) */ 424 switch (si->ps.card_type) 425 { 426 case NM2070: 427 ACCW(2070_XYEXT, (((yl - 1) << 16) | ((xe - xs - 1) & 0x0000ffff))); 428 ACCW(2070_DSTSTARTOFF, ((ys * si->fbc.bytes_per_row) + (xs * si->engine.depth))); 429 break; 430 default: /* NM2090 and later */ 431 ACCW(2090_DSTSTARTOFF, ((ys << 16) | (xs & 0x0000ffff))); 432 ACCW(2090_XYEXT, ((yl << 16) | ((xe - xs) & 0x0000ffff))); 433 break; 434 } 435 436 return B_OK; 437 } 438 439 /* screen to screen tranparent blit */ 440 status_t nm_acc_transparent_blit(uint16 xs,uint16 ys,uint16 xd,uint16 yd,uint16 w,uint16 h,uint32 colour) 441 { 442 //fixme: implement. 443 444 return B_ERROR; 445 } 446 447 /* screen to screen scaled filtered blit - i.e. scale video in memory */ 448 status_t nm_acc_video_blit(uint16 xs,uint16 ys,uint16 ws, uint16 hs, 449 uint16 xd,uint16 yd,uint16 wd,uint16 hd) 450 { 451 //fixme: implement. 452 453 return B_OK; 454 } 455