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