xref: /haiku/src/add-ons/accelerants/neomagic/engine/nm_acc.c (revision aa94570a34695672df9b47adda2257f75d8da880)
1 /* nm Acceleration functions */
2 /* Authors:
3    Mark Watson 2/2000,
4    Rudolf Cornelissen 10/2002-8/2003.
5 */
6 
7 #define MODULE_BIT 0x00080000
8 
9 #include "nm_std.h"
10 
11 /*acceleration notes*/
12 
13 /*functions Be's app_server uses:
14 fill span (horizontal only)
15 fill rectangle (these 2 are very similar)
16 invert rectangle
17 blit
18 */
19 
20 /* G100 pre SRCORG/DSTORG registers */
21 static uint32 src_dst;
22 /* MIL1/2 adress linearisation does not always work */
23 static uint8 y_lin;
24 static uint8 depth;
25 
26 /* needed by MIL 1/2 because of adress linearisation constraints */
27 #define ACCW_YDSTLEN(dst, len) do { \
28 	if (y_lin) { \
29 		ACCW(YDST,((dst)* (si->fbc.bytes_per_row / (depth >> 3))) >> 5); \
30 		ACCW(LEN,len); \
31 	} else ACCW(YDSTLEN,((dst)<<16)|(len)); \
32 } while (0)
33 
34 status_t nm_acc_wait_idle()
35 {
36 //	volatile int i;
37 //	while (ACCR(STATUS)&(1<<16))
38 //	{
39 //		for (i=0;i<10000;i++); /*spin in place so I do not hammer the bus*/
40 //	};
41 	return B_OK;
42 }
43 
44 /* AFAIK this must be done for every new screenmode.
45  * Engine required init. */
46 status_t nm_acc_init()
47 {
48 	/* used for convenience: MACCESS is a write only register! */
49 	uint32 maccess = 0x00000000;
50 
51 	/* preset using hardware adress linearisation */
52 	y_lin = 0x00;
53 	/* reset depth */
54 	depth = 0;
55 
56 	/* cleanup bitblt */
57 	ACCW(OPMODE,0);
58 
59 	/* Set the Z origin to the start of FB (otherwise lockup on blits) */
60 	ACCW(ZORG,0);
61 
62 	/* Set pixel width */
63 	switch(si->dm.space)
64 	{
65 	case B_CMAP8:
66 		ACCW(MACCESS, ((maccess & 0xfffffffc) | 0x00));
67 		depth = 8;
68 		break;
69 	case B_RGB15_LITTLE:case B_RGB16_LITTLE:
70 		ACCW(MACCESS, ((maccess & 0xfffffffc) | 0x01));
71 		depth = 16;
72 		break;
73 	case B_RGB32_LITTLE:case B_RGBA32_LITTLE:
74 		ACCW(MACCESS, ((maccess & 0xfffffffc) | 0x02));
75 		depth = 32;
76 		break;
77 	default:
78 		LOG(8,("ACC: init, invalid bit depth\n"));
79 		return B_ERROR;
80 	}
81 
82 	/* setup PITCH: very cardtype specific! */
83 	switch (si->ps.card_type)
84 	{
85 	case G100:
86 		/* always using hardware adress linearisation, because 2D/3D
87 		 * engine works on every pitch multiple of 32 */
88 		ACCW(PITCH, ((si->fbc.bytes_per_row / (depth >> 3)) & 0x0FFF));
89 		break;
90 	default:
91 		/* G200 and up are equal.. */
92 		/* always using hardware adress linearisation, because 2D/3D
93 		 * engine works on every pitch multiple of 32 */
94 		ACCW(PITCH, ((si->fbc.bytes_per_row / (depth >> 3)) & 0x1FFF));
95 		break;
96 	}
97 
98 	/* disable plane write mask (needed for SDRAM): actual change needed to get it sent to RAM */
99 	ACCW(PLNWT,0x00000000);
100 	ACCW(PLNWT,0xffffffff);
101 
102 	if (si->ps.card_type >= G200) {
103 		/*DSTORG - location of active screen in framebuffer*/
104 		ACCW(DSTORG,((uint8*)si->fbc.frame_buffer) - ((uint8*)si->framebuffer));
105 
106 		/*SRCORG - init source address - same as dest*/
107 		ACCW(SRCORG,((uint8*)si->fbc.frame_buffer) - ((uint8*)si->framebuffer));
108 	}
109 
110 	/* init YDSTORG - apsed, if not inited, BitBlts may fails on <= G200 */
111 	src_dst = 0;
112 	ACCW(YDSTORG, src_dst);
113 
114 	/* <= G100 uses this register as SRCORG/DSTORG replacement, but
115 	 * MIL 1/2 does not need framebuffer space for the hardcursor! */
116 	if ((si->ps.card_type == G100) && (si->settings.hardcursor))
117 	{
118 		switch (si->dm.space)
119 		{
120 			case B_CMAP8:
121 				src_dst = 1024 / 1;
122 				break;
123 			case B_RGB15_LITTLE:
124 			case B_RGB16_LITTLE:
125 				src_dst = 1024 / 2;
126 				break;
127 			case B_RGB32_LITTLE:
128 				src_dst =  1024 / 4;
129 				break;
130 			default:
131 				LOG(8,("ACC: G100 hardcursor not supported for current colorspace\n"));
132 				return B_ERROR;
133 		}
134 	}
135 	ACCW(YDSTORG,src_dst);
136 
137 	/* clipping */
138 	/* i.e. highest and lowest X pixel adresses */
139 	ACCW(CXBNDRY,(((si->fbc.bytes_per_row / (depth >> 3)) - 1) << 16) | (0));
140 
141 	/* Y pixel addresses must be linear */
142 	/* lowest adress */
143 	ACCW(YTOP, 0 + src_dst);
144 	/* highest adress */
145 	ACCW(YBOT,((si->dm.virtual_height - 1) *
146 		(si->fbc.bytes_per_row / (depth >> 3))) + src_dst);
147 
148 	return B_OK;
149 }
150 
151 /* screen to screen blit - i.e. move windows around.
152  * Engine function bitblit, paragraph 4.5.7.2 */
153 status_t nm_acc_blit(uint16 xs,uint16 ys,uint16 xd,uint16 yd,uint16 w,uint16 h)
154 {
155 	uint32 t_start,t_end,offset;
156 	uint32 b_start,b_end;
157 
158 	/*find where the top,bottom and offset are*/
159 	offset = (si->fbc.bytes_per_row / (depth >> 3));
160 
161 	t_end = t_start = xs + (offset*ys) + src_dst;
162 	t_end += w;
163 
164 	b_end = b_start = xs + (offset*(ys+h)) + src_dst;
165 	b_end +=w;
166 
167 	/* sgnzero bit _must_ be '0' before accessing SGN! */
168 	ACCW(DWGCTL,0x00000000);
169 
170 	/*find which quadrant */
171 	switch((yd>ys)|((xd>xs)<<1))
172 	{
173 	case 0: /*L->R,down*/
174 		ACCW(SGN,0);
175 
176 		ACCW(AR3,t_start);
177 		ACCW(AR0,t_end);
178 		ACCW(AR5,offset);
179 
180 		ACCW_YDSTLEN(yd,h+1);
181 		break;
182 	case 1: /*L->R,up*/
183 		ACCW(SGN,4);
184 
185 		ACCW(AR3,b_start);
186 		ACCW(AR0,b_end);
187 		ACCW(AR5,-offset);
188 
189 		ACCW_YDSTLEN(yd+h,h+1);
190 		break;
191 	case 2: /*R->L,down*/
192 		ACCW(SGN,1);
193 
194 		ACCW(AR3,t_end);
195 		ACCW(AR0,t_start);
196 		ACCW(AR5,offset);
197 
198 		ACCW_YDSTLEN(yd,h+1);
199 		break;
200 	case 3: /*R->L,up*/
201 		ACCW(SGN,5);
202 
203 		ACCW(AR3,b_end);
204 		ACCW(AR0,b_start);
205 		ACCW(AR5,-offset);
206 
207 		ACCW_YDSTLEN(yd+h,h+1);
208 		break;
209 	}
210 	ACCW(FXBNDRY,((xd+w)<<16)|xd);
211 
212 	/*do the blit*/
213 	ACCGO(DWGCTL,0x040C4018); // atype RSTR
214 
215 	return B_OK;
216 }
217 
218 /* screen to screen tranparent blit - not sure what uses this.
219  * Engine function bitblit, paragraph 4.5.7.2 */
220 status_t nm_acc_transparent_blit(uint16 xs,uint16 ys,uint16 xd,uint16 yd,uint16 w,uint16 h,uint32 colour)
221 {
222 	uint32 t_start,t_end,offset;
223 	uint32 b_start,b_end;
224 
225 	return B_ERROR;
226 
227 	/*find where the top,bottom and offset are*/
228 	offset = (si->fbc.bytes_per_row / (depth >> 3));
229 
230 	t_end = t_start = xs + (offset*ys) + src_dst;
231 	t_end += w;
232 
233 	b_end = b_start = xs + (offset*(ys+h)) + src_dst;
234 	b_end +=w;
235 
236 	/* sgnzero bit _must_ be '0' before accessing SGN! */
237 	ACCW(DWGCTL,0x00000000);
238 
239 	/*find which quadrant */
240 	switch((yd>ys)|((xd>xs)<<1))
241 	{
242 	case 0: /*L->R,down*/
243 		ACCW(SGN,0);
244 
245 		ACCW(AR3,t_start);
246 		ACCW(AR0,t_end);
247 		ACCW(AR5,offset);
248 
249 		ACCW_YDSTLEN(yd,h+1);
250 		break;
251 	case 1: /*L->R,up*/
252 		ACCW(SGN,4);
253 
254 		ACCW(AR3,b_start);
255 		ACCW(AR0,b_end);
256 		ACCW(AR5,-offset);
257 
258 		ACCW_YDSTLEN(yd+h,h+1);
259 		break;
260 	case 2: /*R->L,down*/
261 		ACCW(SGN,1);
262 
263 		ACCW(AR3,t_end);
264 		ACCW(AR0,t_start);
265 		ACCW(AR5,offset);
266 
267 		ACCW_YDSTLEN(yd,h+1);
268 		break;
269 	case 3: /*R->L,up*/
270 		ACCW(SGN,5);
271 
272 		ACCW(AR3,b_end);
273 		ACCW(AR0,b_start);
274 		ACCW(AR5,-offset);
275 
276 		ACCW_YDSTLEN(yd+h,h+1);
277 		break;
278 	}
279 	ACCW(FXBNDRY,((xd+w)<<16)|xd);
280 
281 	/*do the blit*/
282 	ACCW(FCOL,colour);
283 	ACCW(BCOL,0xffffffff);
284 	ACCGO(DWGCTL,0x440C4018); // atype RSTR
285 	return B_OK;
286 }
287 
288 /* rectangle fill.
289  * Engine function rectangle_fill: paragraph 4.5.5.2 */
290 /*colorIndex,fill_rect_params,count*/
291 status_t nm_acc_rectangle(uint32 xs,uint32 xe,uint32 ys,uint32 yl,uint32 col)
292 {
293 /*
294 	FXBNDRY - left and right coordinates    a
295 	YDSTLEN - y start and no of lines       a
296 	(or YDST and LEN)
297 	DWGCTL - atype must be RSTR or BLK      a
298 	FCOL - foreground colour                a
299 */
300 
301 	ACCW(FXBNDRY,(xe<<16)|xs); /*set x start and end*/
302 	ACCW_YDSTLEN(ys,yl); /*set y start and length*/
303 	ACCW(FCOL,col);            /*set colour*/
304 
305 //acc fixme: checkout blockmode constraints for G100+ (mil: nc?): also add blockmode
306 //	         for other functions, and use fastblt on MIL1/2 if possible...
307 //or is CMAP8 contraint a non-blockmode contraint? (linearisation problem maybe?)
308 	if (si->dm.space==B_CMAP8)
309 	{
310 		ACCGO(DWGCTL,0x400C7814); // atype RSTR
311 	}
312 	else
313 	{
314 		ACCGO(DWGCTL,0x400C7844); // atype BLK
315 	}
316 	return B_OK;
317 }
318 
319 /* rectangle invert.
320  * Engine function rectangle_fill: paragraph 4.5.5.2 */
321 /*colorIndex,fill_rect_params,count*/
322 status_t nm_acc_rectangle_invert(uint32 xs,uint32 xe,uint32 ys,uint32 yl,uint32 col)
323 {
324 /*
325 	FXBNDRY - left and right coordinates    a
326 	YDSTLEN - y start and no of lines       a
327 	(or YDST and LEN)
328 	DWGCTL - atype must be RSTR or BLK      a
329 	FCOL - foreground colour                a
330 */
331 
332 	ACCW(FXBNDRY,(xe<<16)|xs); /*set x start and end*/
333 	ACCW_YDSTLEN(ys,yl); /*set y start and length*/
334 	ACCW(FCOL,col);            /*set colour*/
335 
336 	/*draw it! top nibble is c is clipping enabled*/
337 	ACCGO(DWGCTL,0x40057814); // atype RSTR
338 
339 	return B_OK;
340 }
341 
342 /* screen to screen scaled filtered blit - i.e. scale video in memory.
343  * Engine function texture mapping for video, paragraphs 4.5.5.5 - 4.5.5.9 */
344 status_t nm_acc_video_blit(uint16 xs,uint16 ys,uint16 ws, uint16 hs,
345 	uint16 xd,uint16 yd,uint16 wd,uint16 hd)
346 {
347 	//fixme: implement.
348 
349 	return B_OK;
350 }
351