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
nm_acc_wait_idle()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!) */
nm_acc_wait_fifo(uint32 n)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. */
nm_acc_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. */
nm_acc_blit(uint16 xs,uint16 ys,uint16 xd,uint16 yd,uint16 w,uint16 h)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) */
nm_acc_setup_rectangle(uint32 color)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
nm_acc_rectangle(uint32 xs,uint32 xe,uint32 ys,uint32 yl)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 */
nm_acc_setup_rect_invert()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
nm_acc_rectangle_invert(uint32 xs,uint32 xe,uint32 ys,uint32 yl)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 */
nm_acc_transparent_blit(uint16 xs,uint16 ys,uint16 xd,uint16 yd,uint16 w,uint16 h,uint32 colour)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 */
nm_acc_video_blit(uint16 xs,uint16 ys,uint16 ws,uint16 hs,uint16 xd,uint16 yd,uint16 wd,uint16 hd)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