xref: /haiku/src/add-ons/accelerants/neomagic/engine/nm_acc.c (revision 67bce78b48ed6d01b5a8eef89f5694c372b7e0a1)
1 /* nm Acceleration functions */
2 
3 /* Author:
4    Rudolf Cornelissen 3/2004.
5 */
6 
7 #define MODULE_BIT 0x00080000
8 
9 #include "nm_std.h"
10 
11 //static status_t nm_acc_wait_fifo(uint32 n);
12 
13 /*acceleration notes*/
14 
15 /*functions Be's app_server uses:
16 fill span (horizontal only)
17 fill rectangle (these 2 are very similar)
18 invert rectangle
19 blit
20 */
21 
22 //fixme: acc setup for NM2097 and NM2160 only for now...
23 status_t nm_acc_wait_idle()
24 {
25 	/* wait until engine completely idle */
26 	/* Note:
27 	 * because we have no FIFO functionality we have to make sure we return ASAP(!).
28 	 * snoozing() for just 1 microSecond already more than halfs the engine
29 	 * performance... */
30 	while (ACCR(STATUS) & 0x00000001);
31 
32 	return B_OK;
33 }
34 
35 /* wait for enough room in fifo */
36 //static status_t nm_acc_wait_fifo(uint32 n)
37 //{
38 //	while (((ACCR(STATUS) & 0x0000ff00) >> 8) < n)
39 //	{
40 		/* snooze a bit so I do not hammer the bus */
41 //		snooze (10);
42 //	}
43 //}
44 
45 /* AFAIK this must be done for every new screenmode.
46  * Engine required init. */
47 status_t nm_acc_init()
48 {
49 	/* Set pixel width */
50 	switch(si->dm.space)
51 	{
52 	case B_CMAP8:
53 		/* b8-9 determine engine colordepth */
54 		si->engine.control = (1 << 8);
55 		si->engine.depth = 1;
56 		break;
57 	case B_RGB15_LITTLE:case B_RGB16_LITTLE:
58 		/* b8-9 determine engine colordepth */
59 		si->engine.control = (2 << 8);
60 		si->engine.depth = 2;
61 		break;
62 	case B_RGB24_LITTLE:
63 		/* no acceleration supported on NM2097 and NM2160 */
64 	default:
65 		LOG(8,("ACC: init, invalid bit depth\n"));
66 		return B_ERROR;
67 	}
68 
69 	/* setup memory pitch (b10-12):
70 	 * this works with a table, there are very few fixed settings.. */
71 	switch(si->fbc.bytes_per_row / si->engine.depth)
72 	{
73 	case 640:
74 		si->engine.control |= (2 << 10);
75 		break;
76 	case 800:
77 		si->engine.control |= (3 << 10);
78 		break;
79 	case 1024:
80 		si->engine.control |= (4 << 10);
81 		break;
82 	case 1152:
83 		si->engine.control |= (5 << 10);
84 		break;
85 	case 1280:
86 		si->engine.control |= (6 << 10);
87 		break;
88 	case 1600:
89 		si->engine.control |= (7 << 10);
90 		break;
91 	default:
92 		LOG(8,("ACC: init, invalid mode width\n"));
93 		return B_ERROR;
94 	}
95 
96 	/* enable engine FIFO */
97 	/* fixme when/if possible:
98 	 * does not work on most cards.. (tried NM2160)
99 	 * workaround: always wait until engine completely idle before programming. */
100 //	si->engine.control |= (1 << 27);
101 
102 	/* setup buffer startadress */
103 	/* fixme when/if possible:
104 	 * not possible on all cards or not enough specs known. (tried NM2160)
105 	 * workaround: place cursor bitmap at _end_ of cardRAM instead of in _beginning_. */
106 
107 	/* setup clipping */
108 	/* note:
109 	 * on NM2160 the max acc engine width of 1600 pixels can be programmed, but
110 	 * the max. height is only 1023 pixels (height register holds just 10 bits)!
111 	 * note also:
112 	 * while the vertical clipping feature can do upto and including 1023 pixels,
113 	 * the engine itself can do upto and including 1024 pixels vertically.
114 	 * So:
115 	 * Don't use the engine's clipping feature as we want to get the max out of the
116 	 * engine. We won't export the acc hooks for modes beyond the acc engine's
117 	 * capabilities. */
118 //	si->engine.control |= (1 << 26);
119 //	ACCW(CLIPLT, 0);
120 //	ACCW(CLIPRB, ((si->dm.virtual_height << 16) | (si->dm.virtual_width & 0x0000ffff)));
121 
122 	return B_OK;
123 }
124 
125 /* screen to screen blit - i.e. move windows around and scroll within them. */
126 status_t nm_acc_blit(uint16 xs,uint16 ys,uint16 xd,uint16 yd,uint16 w,uint16 h)
127 {
128 	/* make sure the previous command (if any) is completed */
129 //	does not work yet:
130 //	nm_acc_wait_fifo(4);
131 //	so:
132 	nm_acc_wait_idle();
133 
134     if ((yd < ys) || ((yd == ys) && (xd < xs)))
135     {
136 		/* start with upper left corner */
137 		/* use ROP GXcopy (b16-19), and use XY coord. system (b24-25) */
138 		ACCW(CONTROL, si->engine.control | 0x830c0000);
139 		/* send command and exexute */
140 		ACCW(SRCSTARTOFF, ((ys << 16) | (xs & 0x0000ffff)));
141 		ACCW(DSTSTARTOFF, ((yd << 16) | (xd & 0x0000ffff)));
142 		ACCW(XYEXT, (((h + 1) << 16) | ((w + 1) & 0x0000ffff)));
143 	}
144     else
145     {
146 		/* start with lower right corner */
147 		/* use ROP GXcopy (b16-19), and use XY coord. system (b24-25) */
148 		ACCW(CONTROL, (si->engine.control | 0x830c0013));
149 		/* send command and exexute */
150 		ACCW(SRCSTARTOFF, (((ys + h) << 16) | ((xs + w) & 0x0000ffff)));
151 		ACCW(DSTSTARTOFF, (((yd + h) << 16) | ((xd + w) & 0x0000ffff)));
152 		ACCW(XYEXT, (((h + 1) << 16) | ((w + 1) & 0x0000ffff)));
153 	}
154 
155 	return B_OK;
156 }
157 
158 /* rectangle fill - i.e. workspace and window background color */
159 /* span fill - i.e. (selected) menuitem background color (Dano) */
160 status_t nm_acc_setup_rectangle(uint32 color)
161 {
162 //	does not work yet:
163 //	nm_acc_wait_fifo(2);
164 //	so:
165 	nm_acc_wait_idle();
166 
167 	/* use ROP GXcopy (b16-19), use XY coord. system (b24-25), do foreground color (b3) */
168 	ACCW(CONTROL, (si->engine.control | 0x830c0008));
169 	/* setup color */
170 	ACCW(FGCOLOR, color);
171 
172 	return B_OK;
173 }
174 
175 status_t nm_acc_rectangle(uint32 xs,uint32 xe,uint32 ys,uint32 yl)
176 {
177 	/* The engine does not take kindly if we try to let it fill a rect with
178 	 * zero width. Dano's app_server occasionally tries to let us do that though!
179 	 * Testable with BeRoMeter 1.2.6, all Ellipses tests. Effect of zero width fill:
180 	 * horizontal lines across the entire screen at top and bottom of ellipses. */
181 	if (xe == xs) return B_OK;
182 
183 	/* make sure the previous command (if any) is completed */
184 //	does not work yet:
185 //	nm_acc_wait_fifo(2);
186 //	so:
187 	nm_acc_wait_idle();
188 
189 	/* send command and exexute */
190 	ACCW(DSTSTARTOFF, ((ys << 16) | (xs & 0x0000ffff)));
191 	ACCW(XYEXT, ((yl << 16) | ((xe - xs) & 0x0000ffff)));
192 
193 	return B_OK;
194 }
195 
196 /* rectangle invert - i.e. text cursor and text selection */
197 status_t nm_acc_setup_rect_invert()
198 {
199 	/* make sure the previous command (if any) is completed */
200 //	does not work yet:
201 //	nm_acc_wait_fifo(4);
202 //	so:
203 	nm_acc_wait_idle();
204 
205 	/* use ROP GXinvert (b16-19), use XY coord. system (b24-25), do foreground color (b3) */
206 	ACCW(CONTROL, (si->engine.control | 0x83050008));
207 	/* reset color */
208 	ACCW(FGCOLOR, 0);
209 
210 	return B_OK;
211 }
212 
213 status_t nm_acc_rectangle_invert(uint32 xs,uint32 xe,uint32 ys,uint32 yl)
214 {
215 	/* The engine probably also does not take kindly if we try to let it invert a
216 	 * rect with zero width... (see nm_acc_rectangle() routine for explanation.) */
217 	if (xe == xs) return B_OK;
218 
219 	/* make sure the previous command (if any) is completed */
220 //	does not work yet:
221 //	nm_acc_wait_fifo(4);
222 //	so:
223 	nm_acc_wait_idle();
224 
225 	/* send command and exexute */
226 	ACCW(DSTSTARTOFF, ((ys << 16) | (xs & 0x0000ffff)));
227 	ACCW(XYEXT, ((yl << 16) | ((xe - xs) & 0x0000ffff)));
228 
229 	return B_OK;
230 }
231 
232 /* screen to screen tranparent blit */
233 status_t nm_acc_transparent_blit(uint16 xs,uint16 ys,uint16 xd,uint16 yd,uint16 w,uint16 h,uint32 colour)
234 {
235 	//fixme: implement.
236 
237 	return B_ERROR;
238 }
239 
240 /* screen to screen scaled filtered blit - i.e. scale video in memory */
241 status_t nm_acc_video_blit(uint16 xs,uint16 ys,uint16 ws, uint16 hs,
242 	uint16 xd,uint16 yd,uint16 wd,uint16 hd)
243 {
244 	//fixme: implement.
245 
246 	return B_OK;
247 }
248