xref: /haiku/src/add-ons/accelerants/neomagic/engine/nm_acc.c (revision 489527469f9ecb605992c39ce40a4fdbc5bbebdb)
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