xref: /haiku/src/add-ons/accelerants/neomagic/engine/nm_bes.c (revision e7742a11bd3a8f635856364de849a5e4caf1058b)
1 /* NeoMagic Back End Scaler functions */
2 /* Written by Rudolf Cornelissen 05/2002-1/2006 */
3 
4 #define MODULE_BIT 0x00000200
5 
6 #include "nm_std.h"
7 
8 static void nm_bes_calc_move_overlay(move_overlay_info *moi);
9 static void nm_bes_program_move_overlay(move_overlay_info moi);
10 
11 /* move the overlay output window in virtualscreens */
12 /* Note:
13  * si->dm.h_display_start and si->dm.v_display_start determine where the new
14  * output window is located! */
nm_bes_move_overlay()15 void nm_bes_move_overlay()
16 {
17 	move_overlay_info moi;
18 
19 	/* abort if overlay is not active */
20 	if (!si->overlay.active) return;
21 
22 	nm_bes_calc_move_overlay(&moi);
23 	nm_bes_program_move_overlay(moi);
24 }
25 
nm_bes_calc_move_overlay(move_overlay_info * moi)26 static void nm_bes_calc_move_overlay(move_overlay_info *moi)
27 {
28 	/* misc used variables */
29 	uint16 temp1, temp2;
30 	/* visible screen window in virtual workspaces */
31 	uint16 crtc_hstart, crtc_vstart, crtc_hend, crtc_vend;
32 	/* horizontal source start in source buffer (clipping) */
33 	uint32 hsrcstv;
34 
35 	/* the BES does not respect virtual_workspaces, but adheres to CRTC
36 	 * constraints only */
37 	crtc_hstart = si->dm.h_display_start;
38 	/* horizontal end is the first position beyond the displayed range on the CRTC */
39 	crtc_hend = crtc_hstart + si->dm.timing.h_display;
40 	crtc_vstart = si->dm.v_display_start;
41 	/* vertical end is the first position beyond the displayed range on the CRTC */
42 	crtc_vend = crtc_vstart + si->dm.timing.v_display;
43 
44 
45 	/****************************************
46 	 *** setup all edges of output window ***
47 	 ****************************************/
48 
49 	/* setup left and right edges of output window */
50 	moi->hcoordv = 0;
51 	/* left edge coordinate of output window, must be inside desktop */
52 	/* clipping on the left side */
53 	if (si->overlay.ow.h_start < crtc_hstart)
54 	{
55 		temp1 = 0;
56 	}
57 	else
58 	{
59 		/* clipping on the right side */
60 		if (si->overlay.ow.h_start >= (crtc_hend - 1))
61 		{
62 			/* width < 2 is not allowed */
63 			temp1 = (crtc_hend - crtc_hstart - 2);
64 		}
65 		else
66 		/* no clipping here */
67 		{
68 			temp1 = (si->overlay.ow.h_start - crtc_hstart);
69 		}
70 	}
71 	moi->hcoordv |= temp1 << 16;
72 
73 	/* right edge coordinate of output window, must be inside desktop */
74 	/* width < 2 is not allowed */
75 	if (si->overlay.ow.width < 2)
76 	{
77 		temp2 = (temp1 + 1);
78 	}
79 	else
80 	{
81 		/* clipping on the right side */
82 		if ((si->overlay.ow.h_start + si->overlay.ow.width - 1) > (crtc_hend - 1))
83 		{
84 			temp2 = (crtc_hend - crtc_hstart - 1);
85 		}
86 		else
87 		{
88 			/* clipping on the left side */
89 			if ((si->overlay.ow.h_start + si->overlay.ow.width - 1) < (crtc_hstart + 1))
90 			{
91 				/* width < 2 is not allowed */
92 				temp2 = 1;
93 			}
94 			else
95 			/* no clipping here */
96 			{
97 				temp2 = ((uint16)(si->overlay.ow.h_start + si->overlay.ow.width - crtc_hstart - 1));
98 			}
99 		}
100 	}
101 	moi->hcoordv |= temp2 << 0;
102 	LOG(4,("Overlay: CRTC left-edge output %d, right-edge output %d\n",temp1, temp2));
103 
104 	/* setup top and bottom edges of output window */
105 	moi->vcoordv = 0;
106 	/* top edge coordinate of output window, must be inside desktop */
107 	/* clipping on the top side */
108 	if (si->overlay.ow.v_start < crtc_vstart)
109 	{
110 		temp1 = 0;
111 	}
112 	else
113 	{
114 		/* clipping on the bottom side */
115 		if (si->overlay.ow.v_start >= (crtc_vend - 1))
116 		{
117 			/* height < 2 is not allowed */
118 			temp1 = (crtc_vend - crtc_vstart - 2);
119 		}
120 		else
121 		/* no clipping here */
122 		{
123 			temp1 = (si->overlay.ow.v_start - crtc_vstart);
124 		}
125 	}
126 	moi->vcoordv |= temp1 << 16;
127 
128 	/* bottom edge coordinate of output window, must be inside desktop */
129 	/* height < 2 is not allowed */
130 	if (si->overlay.ow.height < 2)
131 	{
132 		temp2 = (temp1 + 1);
133 	}
134 	else
135 	{
136 		/* clipping on the bottom side */
137 		if ((si->overlay.ow.v_start + si->overlay.ow.height - 1) > (crtc_vend - 1))
138 		{
139 			temp2 = (crtc_vend - crtc_vstart - 1);
140 		}
141 		else
142 		{
143 			/* clipping on the top side */
144 			if ((si->overlay.ow.v_start + si->overlay.ow.height - 1) < (crtc_vstart + 1))
145 			{
146 				/* height < 2 is not allowed */
147 				temp2 = 1;
148 			}
149 			else
150 			/* no clipping here */
151 			{
152 				temp2 = ((uint16)(si->overlay.ow.v_start + si->overlay.ow.height - crtc_vstart - 1));
153 			}
154 		}
155 	}
156 	moi->vcoordv |= temp2 << 0;
157 	LOG(4,("Overlay: CRTC top-edge output %d, bottom-edge output %d\n",temp1, temp2));
158 
159 
160 	/*********************************
161 	 *** setup horizontal clipping ***
162 	 *********************************/
163 
164 	/* Setup horizontal source start: first (sub)pixel contributing to output picture */
165 	/* Note:
166 	 * The method is to calculate, based on 1:1 scaling, based on the output window.
167 	 * After this is done, include the scaling factor so you get a value based on the input bitmap.
168 	 * Then add the left starting position of the bitmap's view (zoom function) to get the final value needed.
169 	 * Note: The input bitmaps slopspace is automatically excluded from the calculations this way! */
170 	/* Note also:
171 	 * Even if the scaling factor is clamping we instruct the BES to use the correct source start pos.! */
172 	hsrcstv = 0;
173 	/* check for destination horizontal clipping at left side */
174 	if (si->overlay.ow.h_start < crtc_hstart)
175 	{
176 		/* check if entire destination picture is clipping left:
177 		 * (2 pixels will be clamped onscreen at least) */
178 		if ((si->overlay.ow.h_start + si->overlay.ow.width - 1) < (crtc_hstart + 1))
179 		{
180 			/* increase 'first contributing pixel' with 'fixed value': (total dest. width - 2) */
181 			hsrcstv += (si->overlay.ow.width - 2);
182 		}
183 		else
184 		{
185 			/* increase 'first contributing pixel' with actual number of dest. clipping pixels */
186 			hsrcstv += (crtc_hstart - si->overlay.ow.h_start);
187 		}
188 		LOG(4,("Overlay: clipping left...\n"));
189 
190 		/* The calculated value is based on scaling = 1x. So we now compensate for scaling.
191 		 * Note that this also already takes care of aligning the value to the BES register! */
192 		hsrcstv *= (si->overlay.h_ifactor << 4);
193 	}
194 	/* take zoom into account */
195 	hsrcstv += ((uint32)si->overlay.my_ov.h_start) << 16;
196 	LOG(4,("Overlay: first hor. (sub)pixel of input bitmap contributing %f\n", hsrcstv / (float)65536));
197 
198 	/* Setup horizontal source end: last (sub)pixel contributing to output picture */
199 	/* Note:
200 	 * The method is to calculate, based on 1:1 scaling, based on the output window.
201 	 * After this is done, include the scaling factor so you get a value based on the input bitmap.
202 	 * Then add the right ending position of the bitmap's view (zoom function) to get the final value needed. */
203 	/* Note also:
204 	 * Even if the scaling factor is clamping we instruct the BES to use the correct source end pos.! */
205 
206 	moi->hsrcendv = 0;
207 	/* check for destination horizontal clipping at right side */
208 	if ((si->overlay.ow.h_start + si->overlay.ow.width - 1) > (crtc_hend - 1))
209 	{
210 		/* check if entire destination picture is clipping right:
211 		 * (2 pixels will be clamped onscreen at least) */
212 		if (si->overlay.ow.h_start > (crtc_hend - 2))
213 		{
214 			/* increase 'number of clipping pixels' with 'fixed value': (total dest. width - 2) */
215 			moi->hsrcendv += (si->overlay.ow.width - 2);
216 		}
217 		else
218 		{
219 			/* increase 'number of clipping pixels' with actual number of dest. clipping pixels */
220 			moi->hsrcendv += ((si->overlay.ow.h_start + si->overlay.ow.width - 1) - (crtc_hend - 1));
221 		}
222 		LOG(4,("Overlay: clipping right...\n"));
223 
224 		/* The calculated value is based on scaling = 1x. So we now compensate for scaling.
225 		 * Note that this also already takes care of aligning the value to the BES register! */
226 		moi->hsrcendv *= (si->overlay.h_ifactor << 4);
227 		/* now subtract this value from the last used pixel in (zoomed) inputbuffer, aligned to BES */
228 		moi->hsrcendv = (((uint32)((si->overlay.my_ov.h_start + si->overlay.my_ov.width) - 1)) << 16) - moi->hsrcendv;
229 	}
230 	else
231 	{
232 		/* set last contributing pixel to last used pixel in (zoomed) inputbuffer, aligned to BES */
233 		moi->hsrcendv = (((uint32)((si->overlay.my_ov.h_start + si->overlay.my_ov.width) - 1)) << 16);
234 	}
235 	/* AND below required by hardware */
236 	moi->hsrcendv &= 0x03ffffff;
237 	LOG(4,("Overlay: last horizontal (sub)pixel of input bitmap contributing %f\n", moi->hsrcendv / (float)65536));
238 
239 
240 	/*******************************
241 	 *** setup vertical clipping ***
242 	 *******************************/
243 
244 	/* calculate inputbitmap origin adress */
245 	moi->a1orgv = (uintptr_t)((vuint32 *)si->overlay.ob.buffer);
246 	moi->a1orgv -= (uintptr_t)((vuint32 *)si->framebuffer);
247 	LOG(4,("Overlay: topleft corner of input bitmap (cardRAM offset) $%08x\n", moi->a1orgv));
248 
249 	/* Setup vertical source start: first (sub)pixel contributing to output picture. */
250 	/* Note:
251 	 * The method is to calculate, based on 1:1 scaling, based on the output window.
252 	 * 'After' this is done, include the scaling factor so you get a value based on the input bitmap.
253 	 * Then add the top starting position of the bitmap's view (zoom function) to get the final value needed. */
254 	/* Note also:
255 	 * Even if the scaling factor is clamping we instruct the BES to use the correct source start pos.! */
256 
257 	/* check for destination vertical clipping at top side */
258 	if (si->overlay.ow.v_start < crtc_vstart)
259 	{
260 		/* check if entire destination picture is clipping at top:
261 		 * (2 pixels will be clamped onscreen at least) */
262 		if ((si->overlay.ow.v_start + si->overlay.ow.height - 1) < (crtc_vstart + 1))
263 		{
264 			/* increase source buffer origin with 'fixed value':
265 			 * (integer part of ('total height - 2' of dest. picture in pixels * inverse scaling factor)) *
266 			 * bytes per row source picture */
267 			//fixme: rounding down would be better than just chopping off the fractional part...
268 			moi->a1orgv +=
269 				((((si->overlay.ow.height - 2) * (si->overlay.v_ifactor << 4)) >> 16) *
270 				si->overlay.ob.bytes_per_row);
271 		}
272 		else
273 		{
274 			/* increase source buffer origin with:
275 			 * (integer part of (number of destination picture clipping pixels * inverse scaling factor)) *
276 			 * bytes per row source picture */
277 			//fixme: rounding down would be better than just chopping off the fractional part...
278 			moi->a1orgv +=
279 				((((crtc_vstart - si->overlay.ow.v_start) * (si->overlay.v_ifactor << 4)) >> 16) *
280 				si->overlay.ob.bytes_per_row);
281 		}
282 		LOG(4,("Overlay: clipping at top...\n"));
283 	}
284 	/* take zoom into account */
285 	moi->a1orgv += (si->overlay.my_ov.v_start * si->overlay.ob.bytes_per_row);
286 	/* now include 'pixel precise' left clipping...
287 	 * (subpixel precision is not supported by NeoMagic cards) */
288 	moi->a1orgv += ((hsrcstv >> 16) * 2);
289 	/* we need to step in 4-byte (2 pixel) granularity due to the nature of yuy2 */
290 	moi->a1orgv &= ~0x03;
291 	LOG(4,("Overlay: 'contributing part of buffer' origin is (cardRAM offset) $%08x\n", moi->a1orgv));
292 }
293 
nm_bes_program_move_overlay(move_overlay_info moi)294 static void nm_bes_program_move_overlay(move_overlay_info moi)
295 {
296 	/*************************************
297 	 *** sync to BES (Back End Scaler) ***
298 	 *************************************/
299 
300 	/* Make sure reprogramming the BES completes before the next retrace occurs,
301 	 * to prevent register-update glitches (double buffer feature). */
302 
303 	//fixme if needed...
304 
305 
306 	/**************************************
307 	 *** actually program the registers ***
308 	 **************************************/
309 	if (si->ps.card_type >= NM2097)
310 	{
311 		/* PCI card */
312 		LOG(4,("Overlay: accelerant is programming BES\n"));
313 		/* unlock card overlay sequencer registers (b5 = 1) */
314 		PCIGRPHW(GENLOCK, (PCIGRPHR(GENLOCK) | 0x20));
315 		/* destination rectangle #1 (output window position and size) */
316 		PCIGRPHW(HD1COORD1L, ((moi.hcoordv >> 16) & 0xff));
317 		PCIGRPHW(HD1COORD2L, (moi.hcoordv & 0xff));
318 		PCIGRPHW(HD1COORD21H, (((moi.hcoordv >> 4) & 0xf0) | ((moi.hcoordv >> 24) & 0x0f)));
319 		PCIGRPHW(VD1COORD1L, ((moi.vcoordv >> 16) & 0xff));
320 		PCIGRPHW(VD1COORD2L, (moi.vcoordv & 0xff));
321 		PCIGRPHW(VD1COORD21H, (((moi.vcoordv >> 4) & 0xf0) | ((moi.vcoordv >> 24) & 0x0f)));
322 		/* inputbuffer #1 origin */
323 		/* (we don't program buffer #2 as it's unused.) */
324 		if (si->ps.card_type < NM2200)
325 		{
326 			moi.a1orgv >>= 1;
327 			/* horizontal source end does not use subpixelprecision: granularity is 8 pixels */
328 			/* notes:
329 			 * - correctly programming horizontal source end minimizes used bandwidth;
330 			 * - adding 9 below is in fact:
331 			 *   - adding 1 to round-up to the nearest whole source-end value
332 			       (making SURE we NEVER are a (tiny) bit too low);
333 			     - adding 1 to convert 'last used position' to 'number of used pixels';
334 			     - adding 7 to round-up to the nearest higher (or equal) valid register
335 			       value (needed because of it's 8-pixel granularity). */
336 			PCIGRPHW(0xbc, ((((moi.hsrcendv >> 16) + 9) >> 3) - 1));
337 		}
338 		else
339 		{
340 			/* horizontal source end does not use subpixelprecision: granularity is 16 pixels */
341 			/* notes:
342 			 * - programming this register just a tiny bit too low messes up vertical
343 			 *   scaling badly (also distortion stripes and flickering are reported)!
344 			 * - not programming this register correctly will mess-up the picture when
345 			 *   it's partly clipping on the right side of the screen...
346 			 * - make absolutely sure the engine can fetch the last pixel needed from
347 			 *   the sourcebitmap even if only to generate a tiny subpixel from it!
348 			 *   (see remarks for < NM2200 cards regarding programming this register) */
349 			PCIGRPHW(0xbc, ((((moi.hsrcendv >> 16) + 17) >> 4) - 1));
350 		}
351 		PCIGRPHW(BUF1ORGL, (moi.a1orgv & 0xff));
352 		PCIGRPHW(BUF1ORGM, ((moi.a1orgv >> 8) & 0xff));
353 		PCIGRPHW(BUF1ORGH, ((moi.a1orgv >> 16) & 0xff));
354 		/* ??? */
355 		PCIGRPHW(0xbd, 0x02);
356 		PCIGRPHW(0xbe, 0x00);
357 		/* b2 = 0: don't use horizontal mirroring (NM2160) */
358 		/* other bits do ??? */
359 		PCIGRPHW(0xbf, 0x02);
360 		/* ??? */
361 	    PCISEQW(0x1c, 0xfb);
362     	PCISEQW(0x1d, 0x00);
363 		PCISEQW(0x1e, 0xe2);
364     	PCISEQW(0x1f, 0x02);
365  		/* b1 = 0: disable alternating hardware buffers (NM2160) */
366 		/* other bits do ??? */
367  		PCISEQW(0x09, 0x11);
368 		/* we don't use PCMCIA Zoomed Video port capturing, set 1:1 scale just in case */
369 		/* (b6-4 = Y downscale = 100%, b2-0 = X downscale = 100%;
370 		 *  downscaling selectable in 12.5% steps on increasing setting by 1) */
371 		PCISEQW(ZVCAP_DSCAL, 0x00);
372 	}
373 	else
374 	{
375 		/* bes setup data */
376 		nm_bes_data bi;
377 
378 		/* ISA card. Speed required, so:
379 		 * program entire sequence in kerneldriver in one context switch! */
380 		LOG(4,("Overlay: kerneldriver programs BES\n"));
381 
382 		/* setup BES info struct... */
383 		bi.moi = moi;
384 		bi.card_type = si->ps.card_type;
385 		bi.move_only = true;
386 		/* ... and call kerneldriver to program the BES */
387 		bi.magic = NM_PRIVATE_DATA_MAGIC;
388 		ioctl(fd, NM_PGM_BES, &bi, sizeof(bi));
389 	}
390 }
391 
nm_configure_bes(const overlay_buffer * ob,const overlay_window * ow,const overlay_view * ov,int offset)392 status_t nm_configure_bes
393 	(const overlay_buffer *ob, const overlay_window *ow, const overlay_view *ov, int offset)
394 {
395 	/* yuy2 (4:2:2) colorspace calculations */
396 	/* Note: Some calculations will have to be modified for other colorspaces if they are incorporated. */
397 
398 	/* Note:
399 	 * in BeOS R5.0.3 and DANO:
400 	 * 'ow->offset_xxx' is always 0, so not used;
401 	 * 'ow->width' and 'ow->height' are the output window size: does not change
402 	 * if window is clipping;
403 	 * 'ow->h_start' and 'ow->v_start' are the left-top position of the output
404 	 * window. These values can be negative: this means the window is clipping
405 	 * at the left or the top of the display, respectively. */
406 
407 	/* 'ov' is the view in the source bitmap, so which part of the bitmap is actually
408 	 * displayed on screen. This is used for the 'hardware zoom' function. */
409 
410 	/* bes setup data */
411 	nm_bes_data bi;
412 	/* inverse scaling factor, used for source positioning */
413 	uint32 ifactor;
414 	/* copy of overlay view which has checked valid values */
415 	overlay_view my_ov;
416 
417 
418 	/**************************************************************************************
419 	 *** copy, check and limit if needed the user-specified view into the intput bitmap ***
420 	 **************************************************************************************/
421 	my_ov = *ov;
422 	/* check for valid 'coordinates' */
423 	if (my_ov.width == 0) my_ov.width++;
424 	if (my_ov.height == 0) my_ov.height++;
425 	if (my_ov.h_start > ((ob->width - si->overlay.myBufInfo[offset].slopspace) - 1))
426 		my_ov.h_start = ((ob->width - si->overlay.myBufInfo[offset].slopspace) - 1);
427 	if (((my_ov.h_start + my_ov.width) - 1) > ((ob->width - si->overlay.myBufInfo[offset].slopspace) - 1))
428 		my_ov.width = ((((ob->width - si->overlay.myBufInfo[offset].slopspace) - 1) - my_ov.h_start) + 1);
429 	if (my_ov.v_start > (ob->height - 1))
430 		my_ov.v_start = (ob->height - 1);
431 	if (((my_ov.v_start + my_ov.height) - 1) > (ob->height - 1))
432 		my_ov.height = (((ob->height - 1) - my_ov.v_start) + 1);
433 
434 	LOG(6,("Overlay: inputbuffer view (zoom) left %d, top %d, width %d, height %d\n",
435 		my_ov.h_start, my_ov.v_start, my_ov.width, my_ov.height));
436 
437 	/* save for nm_bes_calc_move_overlay() */
438 	si->overlay.ow = *ow;
439 	si->overlay.ob = *ob;
440 	si->overlay.my_ov = my_ov;
441 
442 
443 	/********************************
444 	 *** setup horizontal scaling ***
445 	 ********************************/
446 
447 	LOG(6,("Overlay: total input picture width = %d, height = %d\n",
448 			(ob->width - si->overlay.myBufInfo[offset].slopspace), ob->height));
449 	LOG(6,("Overlay: output picture width = %d, height = %d\n", ow->width, ow->height));
450 
451 	/* calculate inverse horizontal scaling factor, taking zoom into account */
452 	ifactor = ((((uint32)my_ov.width) << 12) / ow->width);
453 
454 	/* correct factor to prevent most-right visible 'line' from distorting */
455 	ifactor -= 1;
456 	bi.hiscalv = ifactor;
457 	/* save for nv_bes_calc_move_overlay() */
458 	si->overlay.h_ifactor = ifactor;
459 	LOG(4,("Overlay: horizontal scaling factor is %f\n", (float)4096 / ifactor));
460 
461 	/* check scaling factor (and modify if needed) to be within scaling limits */
462 	/* the upscaling limit is 8.0 (see official Neomagic specsheets) */
463 	if (bi.hiscalv < 0x00000200)
464 	{
465 		/* (non-inverse) factor too large, set factor to max. valid value */
466 		bi.hiscalv = 0x00000200;
467 		LOG(4,("Overlay: horizontal scaling factor too large, clamping at %f\n", (float)4096 / bi.hiscalv));
468 	}
469 	/* horizontal downscaling cannot be done by NM BES hardware */
470 	if (bi.hiscalv > (1 << 12))
471 	{
472 		/* (non-inverse) factor too small, set factor to min. valid value */
473 		bi.hiscalv = 0x1000;
474 		LOG(4,("Overlay: horizontal scaling factor too small, clamping at %f\n", (float)4096 / bi.hiscalv));
475 	}
476 
477 
478 	/******************************
479 	 *** setup vertical scaling ***
480 	 ******************************/
481 
482 	/* calculate inverse vertical scaling factor, taking zoom into account */
483 	ifactor = ((((uint32)my_ov.height) << 12) / ow->height);
484 
485 	/* correct factor to prevent lowest visible line from distorting */
486 	ifactor -= 1;
487 	LOG(4,("Overlay: vertical scaling factor is %f\n", (float)4096 / ifactor));
488 
489 	/* preserve ifactor for source positioning calculations later on */
490 	bi.viscalv = ifactor;
491 	/* save for nv_bes_calc_move_overlay() */
492 	si->overlay.v_ifactor = ifactor;
493 
494 	/* check scaling factor (and modify if needed) to be within scaling limits */
495 	/* the upscaling limit is 8.0 (see official Neomagic specsheets) */
496 	if (bi.viscalv < 0x00000200)
497 	{
498 		/* (non-inverse) factor too large, set factor to max. valid value */
499 		bi.viscalv = 0x00000200;
500 		LOG(4,("Overlay: vertical scaling factor too large, clamping at %f\n", (float)4096 / bi.viscalv));
501 	}
502 	/* vertical downscaling cannot be done by NM BES hardware */
503 	if (bi.viscalv > (1 << 12))
504 	{
505 		/* (non-inverse) factor too small, set factor to min. valid value */
506 		bi.viscalv = 0x1000;
507 		LOG(4,("Overlay: vertical scaling factor too small, clamping at %f\n", (float)4096 / bi.viscalv));
508 	}
509 
510 
511 	/********************************************************************************
512 	 *** setup all edges of output window, setup horizontal and vertical clipping ***
513 	 ********************************************************************************/
514 	nm_bes_calc_move_overlay(&(bi.moi));
515 
516 
517 	/*****************************
518 	 *** log color keying info ***
519 	 *****************************/
520 
521 	LOG(6,("Overlay: key_red %d, key_green %d, key_blue %d, key_alpha %d\n",
522 		ow->red.value, ow->green.value, ow->blue.value, ow->alpha.value));
523 	LOG(6,("Overlay: mask_red %d, mask_green %d, mask_blue %d, mask_alpha %d\n",
524 		ow->red.mask, ow->green.mask, ow->blue.mask, ow->alpha.mask));
525 
526 
527 	/*************************
528 	 *** setup BES control ***
529 	 *************************/
530 
531 	/* BES global control: setup functions */
532 	bi.globctlv = 0;
533 
534 	/* enable BES */
535 	bi.globctlv |= 1 << 0;
536 	/* enable colorkeying if requested */
537 	if (ow->flags & B_OVERLAY_COLOR_KEY) bi.globctlv |= 1 << 1;
538 	/* b3 = 1: distorts right-half of overlay output. Keeping it zero. */
539 	/* colorspace is YV12, I420 or YUY2 (no RV15 or RV16) */
540 	bi.globctlv |= 0 << 5;
541 
542 	/* enable auto-alternating hardware buffers if alternating buffers is enabled (NM2160) */
543 	bi.globctlv |= 1 << 8;
544 	/* disable capture */
545 	bi.globctlv |= 1 << 13;
546 	/* capture: display one buffer (no alternating buffers) */
547 	bi.globctlv |= 0 << 14;
548 	/* capture: display frame (no field) */
549 	bi.globctlv |= 0 << 15;
550 
551 	/* BTW: horizontal and vertical filtering are always turned on in NM hardware. */
552 
553 
554 	/*************************************
555 	 *** sync to BES (Back End Scaler) ***
556 	 *************************************/
557 
558 	/* Make sure reprogramming the BES completes before the next retrace occurs,
559 	 * to prevent register-update glitches (double buffer feature). */
560 
561 	//fixme if needed...
562 
563 
564 	/**************************************
565 	 *** actually program the registers ***
566 	 **************************************/
567 
568 	if (si->ps.card_type >= NM2097)
569 	{
570 		/* helper: some cards use pixels to define buffer pitch, others use bytes */
571 		uint16 buf_pitch = ob->width;
572 
573 		/* PCI card */
574 		LOG(4,("Overlay: accelerant is programming BES\n"));
575 		/* unlock card overlay sequencer registers (b5 = 1) */
576 		PCIGRPHW(GENLOCK, (PCIGRPHR(GENLOCK) | 0x20));
577 		/* destination rectangle #1 (output window position and size) */
578 		PCIGRPHW(HD1COORD1L, ((bi.moi.hcoordv >> 16) & 0xff));
579 		PCIGRPHW(HD1COORD2L, (bi.moi.hcoordv & 0xff));
580 		PCIGRPHW(HD1COORD21H, (((bi.moi.hcoordv >> 4) & 0xf0) | ((bi.moi.hcoordv >> 24) & 0x0f)));
581 		PCIGRPHW(VD1COORD1L, ((bi.moi.vcoordv >> 16) & 0xff));
582 		PCIGRPHW(VD1COORD2L, (bi.moi.vcoordv & 0xff));
583 		PCIGRPHW(VD1COORD21H, (((bi.moi.vcoordv >> 4) & 0xf0) | ((bi.moi.vcoordv >> 24) & 0x0f)));
584 		/* scaling */
585 		PCIGRPHW(XSCALEL, (bi.hiscalv & 0xff));
586 		PCIGRPHW(XSCALEH, ((bi.hiscalv >> 8) & 0xff));
587 		PCIGRPHW(YSCALEL, (bi.viscalv & 0xff));
588 		PCIGRPHW(YSCALEH, ((bi.viscalv >> 8) & 0xff));
589 		/* inputbuffer #1 origin */
590 		/* (we don't program buffer #2 as it's unused.) */
591 		if (si->ps.card_type < NM2200)
592 		{
593 			bi.moi.a1orgv >>= 1;
594 			/* horizontal source end does not use subpixelprecision: granularity is 8 pixels */
595 			/* notes:
596 			 * - correctly programming horizontal source end minimizes used bandwidth;
597 			 * - adding 9 below is in fact:
598 			 *   - adding 1 to round-up to the nearest whole source-end value
599 			       (making SURE we NEVER are a (tiny) bit too low);
600 			     - adding 1 to convert 'last used position' to 'number of used pixels';
601 			     - adding 7 to round-up to the nearest higher (or equal) valid register
602 			       value (needed because of it's 8-pixel granularity). */
603 			PCIGRPHW(0xbc, ((((bi.moi.hsrcendv >> 16) + 9) >> 3) - 1));
604 		}
605 		else
606 		{
607 			/* NM2200 and later cards use bytes to define buffer pitch */
608 			buf_pitch <<= 1;
609 			/* horizontal source end does not use subpixelprecision: granularity is 16 pixels */
610 			/* notes:
611 			 * - programming this register just a tiny bit too low messes up vertical
612 			 *   scaling badly (also distortion stripes and flickering are reported)!
613 			 * - not programming this register correctly will mess-up the picture when
614 			 *   it's partly clipping on the right side of the screen...
615 			 * - make absolutely sure the engine can fetch the last pixel needed from
616 			 *   the sourcebitmap even if only to generate a tiny subpixel from it!
617 			 *   (see remarks for < NM2200 cards regarding programming this register) */
618 			PCIGRPHW(0xbc, ((((bi.moi.hsrcendv >> 16) + 17) >> 4) - 1));
619 		}
620 		PCIGRPHW(BUF1ORGL, (bi.moi.a1orgv & 0xff));
621 		PCIGRPHW(BUF1ORGM, ((bi.moi.a1orgv >> 8) & 0xff));
622 		PCIGRPHW(BUF1ORGH, ((bi.moi.a1orgv >> 16) & 0xff));
623 		/* ??? */
624 		PCIGRPHW(0xbd, 0x02);
625 		PCIGRPHW(0xbe, 0x00);
626 		/* b2 = 0: don't use horizontal mirroring (NM2160) */
627 		/* other bits do ??? */
628 		PCIGRPHW(0xbf, 0x02);
629 		/* ??? */
630 	    PCISEQW(0x1c, 0xfb);
631     	PCISEQW(0x1d, 0x00);
632 		PCISEQW(0x1e, 0xe2);
633     	PCISEQW(0x1f, 0x02);
634  		/* b1 = 0: disable alternating hardware buffers (NM2160) */
635 		/* other bits do ??? */
636  		PCISEQW(0x09, 0x11);
637 		/* we don't use PCMCIA Zoomed Video port capturing, set 1:1 scale just in case */
638 		/* (b6-4 = Y downscale = 100%, b2-0 = X downscale = 100%;
639 		 *  downscaling selectable in 12.5% steps on increasing setting by 1) */
640 		PCISEQW(ZVCAP_DSCAL, 0x00);
641 		/* global BES control */
642 		PCIGRPHW(BESCTRL1, (bi.globctlv & 0xff));
643 		PCISEQW(BESCTRL2, ((bi.globctlv >> 8) & 0xff));
644 
645 
646 		/**************************
647 		 *** setup color keying ***
648 		 **************************/
649 
650 		PCIGRPHW(COLKEY_R, (ow->red.value & ow->red.mask));
651 		PCIGRPHW(COLKEY_G, (ow->green.value & ow->green.mask));
652 		PCIGRPHW(COLKEY_B, (ow->blue.value & ow->blue.mask));
653 
654 
655 		/*************************
656 		 *** setup misc. stuff ***
657 		 *************************/
658 
659 		/* setup brightness to be 'neutral' (two's complement number) */
660 		PCIGRPHW(BRIGHTNESS, 0x00);
661 
662 		/* setup inputbuffer #1 pitch including slopspace */
663 		/* (we don't program the pitch for inputbuffer #2 as it's unused.) */
664 		PCIGRPHW(BUF1PITCHL, (buf_pitch & 0xff));
665 		PCIGRPHW(BUF1PITCHH, ((buf_pitch >> 8) & 0xff));
666 	}
667 	else
668 	{
669 		/* ISA card. Speed required, so:
670 		 * program entire sequence in kerneldriver in one context switch! */
671 		LOG(4,("Overlay: kerneldriver programs BES\n"));
672 
673 		/* complete BES info struct... */
674 		bi.card_type = si->ps.card_type;
675 		bi.colkey_r = (ow->red.value & ow->red.mask);
676 		bi.colkey_g = (ow->green.value & ow->green.mask);
677 		bi.colkey_b = (ow->blue.value & ow->blue.mask);
678 		bi.ob_width = ob->width;
679 		bi.move_only = false;
680 		/* ... and call kerneldriver to program the BES */
681 		bi.magic = NM_PRIVATE_DATA_MAGIC;
682 		ioctl(fd, NM_PGM_BES, &bi, sizeof(bi));
683 	}
684 
685 	/* note that overlay is in use (for nm_bes_move_overlay()) */
686 	si->overlay.active = true;
687 
688 	return B_OK;
689 }
690 
nm_release_bes()691 status_t nm_release_bes()
692 {
693 	/* setup BES control: disable scaler */
694 	if (si->ps.card_type >= NM2097)
695 	{
696 		/* PCI card */
697 		PCIGRPHW(BESCTRL1, 0x02);
698 		PCISEQW(BESCTRL2, 0xa0);
699 	}
700 	else
701 	{
702 		/* ISA card */
703 		ISAGRPHW(BESCTRL1, 0x02);
704 		ISASEQW(BESCTRL2, 0xa0);
705 	}
706 
707 	/* note that overlay is not in use (for nm_bes_move_overlay()) */
708 	si->overlay.active = false;
709 
710 	return B_OK;
711 }
712