#define MODULE_BIT 0x00000200
#include "nm_std.h"
static void nm_bes_calc_move_overlay(move_overlay_info *moi);
static void nm_bes_program_move_overlay(move_overlay_info moi);
* 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;
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)
{
uint16 temp1, temp2;
uint16 crtc_hstart, crtc_vstart, crtc_hend, crtc_vend;
uint32 hsrcstv;
* constraints only */
crtc_hstart = si->dm.h_display_start;
crtc_hend = crtc_hstart + si->dm.timing.h_display;
crtc_vstart = si->dm.v_display_start;
crtc_vend = crtc_vstart + si->dm.timing.v_display;
*** setup all edges of output window ***
****************************************/
moi->hcoordv = 0;
if (si->overlay.ow.h_start < crtc_hstart)
{
temp1 = 0;
}
else
{
if (si->overlay.ow.h_start >= (crtc_hend - 1))
{
temp1 = (crtc_hend - crtc_hstart - 2);
}
else
{
temp1 = (si->overlay.ow.h_start - crtc_hstart);
}
}
moi->hcoordv |= temp1 << 16;
if (si->overlay.ow.width < 2)
{
temp2 = (temp1 + 1);
}
else
{
if ((si->overlay.ow.h_start + si->overlay.ow.width - 1) > (crtc_hend - 1))
{
temp2 = (crtc_hend - crtc_hstart - 1);
}
else
{
if ((si->overlay.ow.h_start + si->overlay.ow.width - 1) < (crtc_hstart + 1))
{
temp2 = 1;
}
else
{
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));
moi->vcoordv = 0;
if (si->overlay.ow.v_start < crtc_vstart)
{
temp1 = 0;
}
else
{
if (si->overlay.ow.v_start >= (crtc_vend - 1))
{
temp1 = (crtc_vend - crtc_vstart - 2);
}
else
{
temp1 = (si->overlay.ow.v_start - crtc_vstart);
}
}
moi->vcoordv |= temp1 << 16;
if (si->overlay.ow.height < 2)
{
temp2 = (temp1 + 1);
}
else
{
if ((si->overlay.ow.v_start + si->overlay.ow.height - 1) > (crtc_vend - 1))
{
temp2 = (crtc_vend - crtc_vstart - 1);
}
else
{
if ((si->overlay.ow.v_start + si->overlay.ow.height - 1) < (crtc_vstart + 1))
{
temp2 = 1;
}
else
{
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 ***
*********************************/
* 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! */
* Even if the scaling factor is clamping we instruct the BES to use the correct source start pos.! */
hsrcstv = 0;
if (si->overlay.ow.h_start < crtc_hstart)
{
* (2 pixels will be clamped onscreen at least) */
if ((si->overlay.ow.h_start + si->overlay.ow.width - 1) < (crtc_hstart + 1))
{
hsrcstv += (si->overlay.ow.width - 2);
}
else
{
hsrcstv += (crtc_hstart - si->overlay.ow.h_start);
}
LOG(4,("Overlay: clipping left...\n"));
* Note that this also already takes care of aligning the value to the BES register! */
hsrcstv *= (si->overlay.h_ifactor << 4);
}
hsrcstv += ((uint32)si->overlay.my_ov.h_start) << 16;
LOG(4,("Overlay: first hor. (sub)pixel of input bitmap contributing %f\n", hsrcstv / (float)65536));
* 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. */
* Even if the scaling factor is clamping we instruct the BES to use the correct source end pos.! */
moi->hsrcendv = 0;
if ((si->overlay.ow.h_start + si->overlay.ow.width - 1) > (crtc_hend - 1))
{
* (2 pixels will be clamped onscreen at least) */
if (si->overlay.ow.h_start > (crtc_hend - 2))
{
moi->hsrcendv += (si->overlay.ow.width - 2);
}
else
{
moi->hsrcendv += ((si->overlay.ow.h_start + si->overlay.ow.width - 1) - (crtc_hend - 1));
}
LOG(4,("Overlay: clipping right...\n"));
* Note that this also already takes care of aligning the value to the BES register! */
moi->hsrcendv *= (si->overlay.h_ifactor << 4);
moi->hsrcendv = (((uint32)((si->overlay.my_ov.h_start + si->overlay.my_ov.width) - 1)) << 16) - moi->hsrcendv;
}
else
{
moi->hsrcendv = (((uint32)((si->overlay.my_ov.h_start + si->overlay.my_ov.width) - 1)) << 16);
}
moi->hsrcendv &= 0x03ffffff;
LOG(4,("Overlay: last horizontal (sub)pixel of input bitmap contributing %f\n", moi->hsrcendv / (float)65536));
*** setup vertical clipping ***
*******************************/
moi->a1orgv = (uintptr_t)((vuint32 *)si->overlay.ob.buffer);
moi->a1orgv -= (uintptr_t)((vuint32 *)si->framebuffer);
LOG(4,("Overlay: topleft corner of input bitmap (cardRAM offset) $%08x\n", moi->a1orgv));
* 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. */
* Even if the scaling factor is clamping we instruct the BES to use the correct source start pos.! */
if (si->overlay.ow.v_start < crtc_vstart)
{
* (2 pixels will be clamped onscreen at least) */
if ((si->overlay.ow.v_start + si->overlay.ow.height - 1) < (crtc_vstart + 1))
{
* (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
{
* (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"));
}
moi->a1orgv += (si->overlay.my_ov.v_start * si->overlay.ob.bytes_per_row);
* (subpixel precision is not supported by NeoMagic cards) */
moi->a1orgv += ((hsrcstv >> 16) * 2);
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) ***
*************************************/
* to prevent register-update glitches (double buffer feature). */
*** actually program the registers ***
**************************************/
if (si->ps.card_type >= NM2097)
{
LOG(4,("Overlay: accelerant is programming BES\n"));
PCIGRPHW(GENLOCK, (PCIGRPHR(GENLOCK) | 0x20));
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)));
if (si->ps.card_type < NM2200)
{
moi.a1orgv >>= 1;
* - 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
{
* - 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);
PCIGRPHW(0xbf, 0x02);
PCISEQW(0x1c, 0xfb);
PCISEQW(0x1d, 0x00);
PCISEQW(0x1e, 0xe2);
PCISEQW(0x1f, 0x02);
PCISEQW(0x09, 0x11);
* downscaling selectable in 12.5% steps on increasing setting by 1) */
PCISEQW(ZVCAP_DSCAL, 0x00);
}
else
{
nm_bes_data bi;
* program entire sequence in kerneldriver in one context switch! */
LOG(4,("Overlay: kerneldriver programs BES\n"));
bi.moi = moi;
bi.card_type = si->ps.card_type;
bi.move_only = true;
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)
{
* in BeOS R5.0.3 and DANO:
* 'ow->offset_xxx' is always 0, so not used;
* 'ow->width' and 'ow->height' are the output window size: does not change
* if window is clipping;
* 'ow->h_start' and 'ow->v_start' are the left-top position of the output
* window. These values can be negative: this means the window is clipping
* at the left or the top of the display, respectively. */
* displayed on screen. This is used for the 'hardware zoom' function. */
nm_bes_data bi;
uint32 ifactor;
overlay_view my_ov;
*** copy, check and limit if needed the user-specified view into the intput bitmap ***
**************************************************************************************/
my_ov = *ov;
if (my_ov.width == 0) my_ov.width++;
if (my_ov.height == 0) my_ov.height++;
if (my_ov.h_start > ((ob->width - si->overlay.myBufInfo[offset].slopspace) - 1))
my_ov.h_start = ((ob->width - si->overlay.myBufInfo[offset].slopspace) - 1);
if (((my_ov.h_start + my_ov.width) - 1) > ((ob->width - si->overlay.myBufInfo[offset].slopspace) - 1))
my_ov.width = ((((ob->width - si->overlay.myBufInfo[offset].slopspace) - 1) - my_ov.h_start) + 1);
if (my_ov.v_start > (ob->height - 1))
my_ov.v_start = (ob->height - 1);
if (((my_ov.v_start + my_ov.height) - 1) > (ob->height - 1))
my_ov.height = (((ob->height - 1) - my_ov.v_start) + 1);
LOG(6,("Overlay: inputbuffer view (zoom) left %d, top %d, width %d, height %d\n",
my_ov.h_start, my_ov.v_start, my_ov.width, my_ov.height));
si->overlay.ow = *ow;
si->overlay.ob = *ob;
si->overlay.my_ov = my_ov;
*** setup horizontal scaling ***
********************************/
LOG(6,("Overlay: total input picture width = %d, height = %d\n",
(ob->width - si->overlay.myBufInfo[offset].slopspace), ob->height));
LOG(6,("Overlay: output picture width = %d, height = %d\n", ow->width, ow->height));
ifactor = ((((uint32)my_ov.width) << 12) / ow->width);
ifactor -= 1;
bi.hiscalv = ifactor;
si->overlay.h_ifactor = ifactor;
LOG(4,("Overlay: horizontal scaling factor is %f\n", (float)4096 / ifactor));
if (bi.hiscalv < 0x00000200)
{
bi.hiscalv = 0x00000200;
LOG(4,("Overlay: horizontal scaling factor too large, clamping at %f\n", (float)4096 / bi.hiscalv));
}
if (bi.hiscalv > (1 << 12))
{
bi.hiscalv = 0x1000;
LOG(4,("Overlay: horizontal scaling factor too small, clamping at %f\n", (float)4096 / bi.hiscalv));
}
*** setup vertical scaling ***
******************************/
ifactor = ((((uint32)my_ov.height) << 12) / ow->height);
ifactor -= 1;
LOG(4,("Overlay: vertical scaling factor is %f\n", (float)4096 / ifactor));
bi.viscalv = ifactor;
si->overlay.v_ifactor = ifactor;
if (bi.viscalv < 0x00000200)
{
bi.viscalv = 0x00000200;
LOG(4,("Overlay: vertical scaling factor too large, clamping at %f\n", (float)4096 / bi.viscalv));
}
if (bi.viscalv > (1 << 12))
{
bi.viscalv = 0x1000;
LOG(4,("Overlay: vertical scaling factor too small, clamping at %f\n", (float)4096 / bi.viscalv));
}
*** setup all edges of output window, setup horizontal and vertical clipping ***
********************************************************************************/
nm_bes_calc_move_overlay(&(bi.moi));
*** log color keying info ***
*****************************/
LOG(6,("Overlay: key_red %d, key_green %d, key_blue %d, key_alpha %d\n",
ow->red.value, ow->green.value, ow->blue.value, ow->alpha.value));
LOG(6,("Overlay: mask_red %d, mask_green %d, mask_blue %d, mask_alpha %d\n",
ow->red.mask, ow->green.mask, ow->blue.mask, ow->alpha.mask));
*** setup BES control ***
*************************/
bi.globctlv = 0;
bi.globctlv |= 1 << 0;
if (ow->flags & B_OVERLAY_COLOR_KEY) bi.globctlv |= 1 << 1;
bi.globctlv |= 0 << 5;
bi.globctlv |= 1 << 8;
bi.globctlv |= 1 << 13;
bi.globctlv |= 0 << 14;
bi.globctlv |= 0 << 15;
*** sync to BES (Back End Scaler) ***
*************************************/
* to prevent register-update glitches (double buffer feature). */
*** actually program the registers ***
**************************************/
if (si->ps.card_type >= NM2097)
{
uint16 buf_pitch = ob->width;
LOG(4,("Overlay: accelerant is programming BES\n"));
PCIGRPHW(GENLOCK, (PCIGRPHR(GENLOCK) | 0x20));
PCIGRPHW(HD1COORD1L, ((bi.moi.hcoordv >> 16) & 0xff));
PCIGRPHW(HD1COORD2L, (bi.moi.hcoordv & 0xff));
PCIGRPHW(HD1COORD21H, (((bi.moi.hcoordv >> 4) & 0xf0) | ((bi.moi.hcoordv >> 24) & 0x0f)));
PCIGRPHW(VD1COORD1L, ((bi.moi.vcoordv >> 16) & 0xff));
PCIGRPHW(VD1COORD2L, (bi.moi.vcoordv & 0xff));
PCIGRPHW(VD1COORD21H, (((bi.moi.vcoordv >> 4) & 0xf0) | ((bi.moi.vcoordv >> 24) & 0x0f)));
PCIGRPHW(XSCALEL, (bi.hiscalv & 0xff));
PCIGRPHW(XSCALEH, ((bi.hiscalv >> 8) & 0xff));
PCIGRPHW(YSCALEL, (bi.viscalv & 0xff));
PCIGRPHW(YSCALEH, ((bi.viscalv >> 8) & 0xff));
if (si->ps.card_type < NM2200)
{
bi.moi.a1orgv >>= 1;
* - 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, ((((bi.moi.hsrcendv >> 16) + 9) >> 3) - 1));
}
else
{
buf_pitch <<= 1;
* - 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, ((((bi.moi.hsrcendv >> 16) + 17) >> 4) - 1));
}
PCIGRPHW(BUF1ORGL, (bi.moi.a1orgv & 0xff));
PCIGRPHW(BUF1ORGM, ((bi.moi.a1orgv >> 8) & 0xff));
PCIGRPHW(BUF1ORGH, ((bi.moi.a1orgv >> 16) & 0xff));
PCIGRPHW(0xbd, 0x02);
PCIGRPHW(0xbe, 0x00);
PCIGRPHW(0xbf, 0x02);
PCISEQW(0x1c, 0xfb);
PCISEQW(0x1d, 0x00);
PCISEQW(0x1e, 0xe2);
PCISEQW(0x1f, 0x02);
PCISEQW(0x09, 0x11);
* downscaling selectable in 12.5% steps on increasing setting by 1) */
PCISEQW(ZVCAP_DSCAL, 0x00);
PCIGRPHW(BESCTRL1, (bi.globctlv & 0xff));
PCISEQW(BESCTRL2, ((bi.globctlv >> 8) & 0xff));
*** setup color keying ***
**************************/
PCIGRPHW(COLKEY_R, (ow->red.value & ow->red.mask));
PCIGRPHW(COLKEY_G, (ow->green.value & ow->green.mask));
PCIGRPHW(COLKEY_B, (ow->blue.value & ow->blue.mask));
*** setup misc. stuff ***
*************************/
PCIGRPHW(BRIGHTNESS, 0x00);
PCIGRPHW(BUF1PITCHL, (buf_pitch & 0xff));
PCIGRPHW(BUF1PITCHH, ((buf_pitch >> 8) & 0xff));
}
else
{
* program entire sequence in kerneldriver in one context switch! */
LOG(4,("Overlay: kerneldriver programs BES\n"));
bi.card_type = si->ps.card_type;
bi.colkey_r = (ow->red.value & ow->red.mask);
bi.colkey_g = (ow->green.value & ow->green.mask);
bi.colkey_b = (ow->blue.value & ow->blue.mask);
bi.ob_width = ob->width;
bi.move_only = false;
bi.magic = NM_PRIVATE_DATA_MAGIC;
ioctl(fd, NM_PGM_BES, &bi, sizeof(bi));
}
si->overlay.active = true;
return B_OK;
}
status_t nm_release_bes()
{
if (si->ps.card_type >= NM2097)
{
PCIGRPHW(BESCTRL1, 0x02);
PCISEQW(BESCTRL2, 0xa0);
}
else
{
ISAGRPHW(BESCTRL1, 0x02);
ISASEQW(BESCTRL2, 0xa0);
}
si->overlay.active = false;
return B_OK;
}