diff --git a/src/add-ons/accelerants/neomagic/engine/nm_bes.c b/src/add-ons/accelerants/neomagic/engine/nm_bes.c index b74799dcaa..cf4d9302a8 100644 --- a/src/add-ons/accelerants/neomagic/engine/nm_bes.c +++ b/src/add-ons/accelerants/neomagic/engine/nm_bes.c @@ -1,12 +1,401 @@ /* NeoMagic Back End Scaler functions */ -/* Written by Rudolf Cornelissen 05/2002-08/2004 */ +/* Written by Rudolf Cornelissen 05/2002-11/2004 */ #define MODULE_BIT 0x00000200 #include "nm_std.h" -//fixme: implement: (used for virtual screens!) -//void move_overlay(uint16 hdisp_start, uint16 vdisp_start); +//fixme: implementation of move_overlay() function in progress... +//fixme: probably best to add routine:status_t nm_bes_init(void); +typedef struct move_overlay_info move_overlay_info; + +struct move_overlay_info +{ + uint32 hcoordv; /* left and right edges of video output window */ + uint32 vcoordv; /* top and bottom edges of video output window */ + uint32 hsrcstv; /* horizontal source start in source buffer (clipping) */ + uint32 hsrcendv; /* horizontal source end in source buffer (clipping) */ + uint32 a1orgv; /* vertical source clipping via startadress of source buffer */ +}; + +static void nm_bes_calc_move_overlay(move_overlay_info *moi); +static void nm_bes_program_move_overlay(move_overlay_info moi); + +/* move the overlay output window in virtualscreens */ +/* Note: + * si->dm.h_display_start and si->dm.v_display_start determine where the new + * output window is located! */ +void nm_bes_move_overlay() +{ + move_overlay_info moi; + + /* abort if overlay is not active */ + if (!si->overlay.active) return; + + nm_bes_calc_move_overlay(&moi); + nm_bes_program_move_overlay(moi); +} + +static void nm_bes_calc_move_overlay(move_overlay_info *moi) +{ + /* misc used variables */ + uint16 temp1, temp2; + /* visible screen window in virtual workspaces */ + uint16 crtc_hstart, crtc_vstart, crtc_hend, crtc_vend; + + /* the BES does not respect virtual_workspaces, but adheres to CRTC + * constraints only */ + crtc_hstart = si->dm.h_display_start; + /* horizontal end is the first position beyond the displayed range on the CRTC */ + crtc_hend = crtc_hstart + si->dm.timing.h_display; + crtc_vstart = si->dm.v_display_start; + /* vertical end is the first position beyond the displayed range on the CRTC */ + crtc_vend = crtc_vstart + si->dm.timing.v_display; + + + /**************************************** + *** setup all edges of output window *** + ****************************************/ + + /* setup left and right edges of output window */ + moi->hcoordv = 0; + /* left edge coordinate of output window, must be inside desktop */ + /* clipping on the left side */ + if (si->overlay.ow.h_start < crtc_hstart) + { + temp1 = 0; + } + else + { + /* clipping on the right side */ + if (si->overlay.ow.h_start >= (crtc_hend - 1)) + { + /* width < 2 is not allowed */ + temp1 = (crtc_hend - crtc_hstart - 2); + } + else + /* no clipping here */ + { + temp1 = (si->overlay.ow.h_start - crtc_hstart); + } + } + moi->hcoordv |= temp1 << 16; + + /* right edge coordinate of output window, must be inside desktop */ + /* width < 2 is not allowed */ + if (si->overlay.ow.width < 2) + { + temp2 = (temp1 + 1); + } + else + { + /* clipping on the right side */ + if ((si->overlay.ow.h_start + si->overlay.ow.width - 1) > (crtc_hend - 1)) + { + temp2 = (crtc_hend - crtc_hstart - 1); + } + else + { + /* clipping on the left side */ + if ((si->overlay.ow.h_start + si->overlay.ow.width - 1) < (crtc_hstart + 1)) + { + /* width < 2 is not allowed */ + temp2 = 1; + } + else + /* no clipping here */ + { + temp2 = ((uint16)(si->overlay.ow.h_start + si->overlay.ow.width - crtc_hstart - 1)); + } + } + } + moi->hcoordv |= temp2 << 0; + LOG(4,("Overlay: CRTC left-edge output %d, right-edge output %d\n",temp1, temp2)); + + /* setup top and bottom edges of output window */ + moi->vcoordv = 0; + /* top edge coordinate of output window, must be inside desktop */ + /* clipping on the top side */ + if (si->overlay.ow.v_start < crtc_vstart) + { + temp1 = 0; + } + else + { + /* clipping on the bottom side */ + if (si->overlay.ow.v_start >= (crtc_vend - 1)) + { + /* height < 2 is not allowed */ + temp1 = (crtc_vend - crtc_vstart - 2); + } + else + /* no clipping here */ + { + temp1 = (si->overlay.ow.v_start - crtc_vstart); + } + } + moi->vcoordv |= temp1 << 16; + + /* bottom edge coordinate of output window, must be inside desktop */ + /* height < 2 is not allowed */ + if (si->overlay.ow.height < 2) + { + temp2 = (temp1 + 1); + } + else + { + /* clipping on the bottom side */ + if ((si->overlay.ow.v_start + si->overlay.ow.height - 1) > (crtc_vend - 1)) + { + temp2 = (crtc_vend - crtc_vstart - 1); + } + else + { + /* clipping on the top side */ + if ((si->overlay.ow.v_start + si->overlay.ow.height - 1) < (crtc_vstart + 1)) + { + /* height < 2 is not allowed */ + temp2 = 1; + } + else + /* no clipping here */ + { + temp2 = ((uint16)(si->overlay.ow.v_start + si->overlay.ow.height - crtc_vstart - 1)); + } + } + } + moi->vcoordv |= temp2 << 0; + LOG(4,("Overlay: CRTC top-edge output %d, bottom-edge output %d\n",temp1, temp2)); + + + /********************************* + *** setup horizontal clipping *** + *********************************/ + + /* Setup horizontal source start: first (sub)pixel contributing to output picture */ + /* Note: + * The method is to calculate, based on 1:1 scaling, based on the output window. + * After this is done, include the scaling factor so you get a value based on the input bitmap. + * Then add the left starting position of the bitmap's view (zoom function) to get the final value needed. + * Note: The input bitmaps slopspace is automatically excluded from the calculations this way! */ + /* Note also: + * Even if the scaling factor is clamping we instruct the BES to use the correct source start pos.! */ + moi->hsrcstv = 0; + /* check for destination horizontal clipping at left side */ + if (si->overlay.ow.h_start < crtc_hstart) + { + /* check if entire destination picture is clipping left: + * (2 pixels will be clamped onscreen at least) */ + if ((si->overlay.ow.h_start + si->overlay.ow.width - 1) < (crtc_hstart + 1)) + { + /* increase 'first contributing pixel' with 'fixed value': (total dest. width - 2) */ + moi->hsrcstv += (si->overlay.ow.width - 2); + } + else + { + /* increase 'first contributing pixel' with actual number of dest. clipping pixels */ + moi->hsrcstv += (crtc_hstart - si->overlay.ow.h_start); + } + LOG(4,("Overlay: clipping left...\n")); + + /* The calculated value is based on scaling = 1x. So we now compensate for scaling. + * Note that this also already takes care of aligning the value to the BES register! */ + moi->hsrcstv *= (si->overlay.h_ifactor << 4); + } + /* take zoom into account */ + moi->hsrcstv += ((uint32)si->overlay.my_ov.h_start) << 16; + LOG(4,("Overlay: first hor. (sub)pixel of input bitmap contributing %f\n", moi->hsrcstv / (float)65536)); + + /* Setup horizontal source end: last (sub)pixel contributing to output picture */ + /* Note: + * The method is to calculate, based on 1:1 scaling, based on the output window. + * After this is done, include the scaling factor so you get a value based on the input bitmap. + * Then add the right ending position of the bitmap's view (zoom function) to get the final value needed. */ + /* Note also: + * Even if the scaling factor is clamping we instruct the BES to use the correct source end pos.! */ + + moi->hsrcendv = 0; + /* check for destination horizontal clipping at right side */ + if ((si->overlay.ow.h_start + si->overlay.ow.width - 1) > (crtc_hend - 1)) + { + /* check if entire destination picture is clipping right: + * (2 pixels will be clamped onscreen at least) */ + if (si->overlay.ow.h_start > (crtc_hend - 2)) + { + /* increase 'number of clipping pixels' with 'fixed value': (total dest. width - 2) */ + moi->hsrcendv += (si->overlay.ow.width - 2); + } + else + { + /* increase 'number of clipping pixels' with actual number of dest. clipping pixels */ + moi->hsrcendv += ((si->overlay.ow.h_start + si->overlay.ow.width - 1) - (crtc_hend - 1)); + } + LOG(4,("Overlay: clipping right...\n")); + + /* The calculated value is based on scaling = 1x. So we now compensate for scaling. + * Note that this also already takes care of aligning the value to the BES register! */ + moi->hsrcendv *= (si->overlay.h_ifactor << 4); + /* now subtract this value from the last used pixel in (zoomed) inputbuffer, aligned to BES */ + moi->hsrcendv = (((uint32)((si->overlay.my_ov.h_start + si->overlay.my_ov.width) - 1)) << 16) - moi->hsrcendv; + } + else + { + /* set last contributing pixel to last used pixel in (zoomed) inputbuffer, aligned to BES */ + moi->hsrcendv = (((uint32)((si->overlay.my_ov.h_start + si->overlay.my_ov.width) - 1)) << 16); + } + /* AND below required by hardware */ + moi->hsrcendv &= 0x03ffffff; + LOG(4,("Overlay: last horizontal (sub)pixel of input bitmap contributing %f\n", moi->hsrcendv / (float)65536)); + + + /******************************* + *** setup vertical clipping *** + *******************************/ + + /* calculate inputbitmap origin adress */ + moi->a1orgv = (uint32)((vuint32 *)si->overlay.ob.buffer); + moi->a1orgv -= (uint32)((vuint32 *)si->framebuffer); + + /* Setup vertical source start: first (sub)pixel contributing to output picture. */ + /* Note: + * The method is to calculate, based on 1:1 scaling, based on the output window. + * 'After' this is done, include the scaling factor so you get a value based on the input bitmap. + * Then add the top starting position of the bitmap's view (zoom function) to get the final value needed. */ + /* Note also: + * Even if the scaling factor is clamping we instruct the BES to use the correct source start pos.! */ + + /* check for destination vertical clipping at top side */ + if (si->overlay.ow.v_start < crtc_vstart) + { + /* check if entire destination picture is clipping at top: + * (2 pixels will be clamped onscreen at least) */ + if ((si->overlay.ow.v_start + si->overlay.ow.height - 1) < (crtc_vstart + 1)) + { + /* increase source buffer origin with 'fixed value': + * (integer part of ('total height - 2' of dest. picture in pixels * inverse scaling factor)) * + * bytes per row source picture */ + moi->a1orgv += + ((((si->overlay.ow.height - 2) * (si->overlay.v_ifactor << 4)) >> 16) * + si->overlay.ob.bytes_per_row); + } + else + { + /* increase source buffer origin with: + * (integer part of (number of destination picture clipping pixels * inverse scaling factor)) * + * bytes per row source picture */ + moi->a1orgv += + ((((crtc_vstart - si->overlay.ow.v_start) * (si->overlay.v_ifactor << 4)) >> 16) * + si->overlay.ob.bytes_per_row); + } + LOG(4,("Overlay: clipping at top...\n")); + } + /* take zoom into account */ + moi->a1orgv += (si->overlay.my_ov.v_start * si->overlay.ob.bytes_per_row); + /* now include 'pixel precise' left clipping... + * (subpixel precision is not supported by NeoMagic cards) */ + moi->a1orgv += ((moi->hsrcstv >> 16) * 2); + /* we need to step in 4-byte (2 pixel) granularity due to the nature of yuy2 */ + moi->a1orgv &= ~0x03; + LOG(4,("Overlay: 'contributing part of buffer' origin is (cardRAM offset) $%08x\n", moi->a1orgv)); +} + +static void nm_bes_program_move_overlay(move_overlay_info moi) +{ + /************************************* + *** sync to BES (Back End Scaler) *** + *************************************/ + + /* Make sure reprogramming the BES completes before the next retrace occurs, + * to prevent register-update glitches (double buffer feature). */ + + //fixme if needed... + + + /************************************** + *** actually program the registers *** + **************************************/ + if (si->ps.card_type >= NM2097) + { + /* PCI card */ + LOG(4,("Overlay: accelerant is programming BES\n")); + /* unlock card overlay sequencer registers (b5 = 1) */ + PCIGRPHW(GENLOCK, (PCIGRPHR(GENLOCK) | 0x20)); + /* destination rectangle #1 (output window position and size) */ + PCIGRPHW(HD1COORD1L, ((moi.hcoordv >> 16) & 0xff)); + PCIGRPHW(HD1COORD2L, (moi.hcoordv & 0xff)); + PCIGRPHW(HD1COORD21H, (((moi.hcoordv >> 4) & 0xf0) | ((moi.hcoordv >> 24) & 0x0f))); + PCIGRPHW(VD1COORD1L, ((moi.vcoordv >> 16) & 0xff)); + PCIGRPHW(VD1COORD2L, (moi.vcoordv & 0xff)); + PCIGRPHW(VD1COORD21H, (((moi.vcoordv >> 4) & 0xf0) | ((moi.vcoordv >> 24) & 0x0f))); + /* inputbuffer #1 origin */ + /* (we don't program buffer #2 as it's unused.) */ + if (si->ps.card_type < NM2200) + { + moi.a1orgv >>= 1; + /* horizontal source end does not use subpixelprecision: granularity is 8 pixels */ + /* notes: + * - correctly programming horizontal source end minimizes used bandwidth; + * - adding 9 below is in fact: + * - adding 1 to round-up to the nearest whole source-end value + (making SURE we NEVER are a (tiny) bit too low); + - adding 1 to convert 'last used position' to 'number of used pixels'; + - adding 7 to round-up to the nearest higher (or equal) valid register + value (needed because of it's 8-pixel granularity). */ + PCIGRPHW(0xbc, ((((moi.hsrcendv >> 16) + 9) >> 3) - 1)); + } + else + { + /* horizontal source end does not use subpixelprecision: granularity is 16 pixels */ + /* notes: + * - programming this register just a tiny bit too low messes up vertical + * scaling badly (also distortion stripes and flickering are reported)! + * - not programming this register correctly will mess-up the picture when + * it's partly clipping on the right side of the screen... + * - make absolutely sure the engine can fetch the last pixel needed from + * the sourcebitmap even if only to generate a tiny subpixel from it! + * (see remarks for < NM2200 cards regarding programming this register) */ + PCIGRPHW(0xbc, ((((moi.hsrcendv >> 16) + 17) >> 4) - 1)); + } + PCIGRPHW(BUF1ORGL, (moi.a1orgv & 0xff)); + PCIGRPHW(BUF1ORGM, ((moi.a1orgv >> 8) & 0xff)); + PCIGRPHW(BUF1ORGH, ((moi.a1orgv >> 16) & 0xff)); + /* ??? */ + PCIGRPHW(0xbd, 0x02); + PCIGRPHW(0xbe, 0x00); + /* b2 = 0: don't use horizontal mirroring (NM2160) */ + /* other bits do ??? */ + PCIGRPHW(0xbf, 0x02); + /* ??? */ + PCISEQW(0x1c, 0xfb); + PCISEQW(0x1d, 0x00); + PCISEQW(0x1e, 0xe2); + PCISEQW(0x1f, 0x02); + /* b1 = 0: disable alternating hardware buffers (NM2160) */ + /* other bits do ??? */ + PCISEQW(0x09, 0x11); + /* we don't use PCMCIA Zoomed Video port capturing, set 1:1 scale just in case */ + /* (b6-4 = Y downscale = 100%, b2-0 = X downscale = 100%; + * downscaling selectable in 12.5% steps on increasing setting by 1) */ + PCISEQW(ZVCAP_DSCAL, 0x00); + } + else + { + /* bes setup data */ + nm_bes_data bi; + + /* ISA card. Speed required, so: + * program entire sequence in kerneldriver in one context switch! */ + LOG(4,("Overlay: kerneldriver programs BES\n")); + + /* setup BES info struct... */ +// bi.moi = moi; + bi.card_type = si->ps.card_type; +// bi.pgm_all = false; //maybe better to setup a seperate kerneldriver function.. + /* ... and call kerneldriver to program the BES */ + bi.magic = NM_PRIVATE_DATA_MAGIC; + ioctl(fd, NM_PGM_BES, &bi, sizeof(bi)); + } +} status_t nm_configure_bes (const overlay_buffer *ob, const overlay_window *ow, const overlay_view *ov, int offset) diff --git a/src/add-ons/accelerants/neomagic/engine/nm_proto.h b/src/add-ons/accelerants/neomagic/engine/nm_proto.h index 4526a1387c..618d2c084b 100644 --- a/src/add-ons/accelerants/neomagic/engine/nm_proto.h +++ b/src/add-ons/accelerants/neomagic/engine/nm_proto.h @@ -69,6 +69,7 @@ status_t nm_acc_wait_idle(void); /*backend scaler functions*/ status_t check_overlay_capability(uint32 feature); +void nm_bes_move_overlay(void); status_t nm_configure_bes (const overlay_buffer *ob, const overlay_window *ow,const overlay_view *ov, int offset); status_t nm_release_bes(void);