#define MODULE_BIT 0x00000200
#include "std.h"
typedef struct move_overlay_info move_overlay_info;
struct move_overlay_info
{
uint32 hcoordv;
uint32 vcoordv;
uint32 hsrcstv;
uint32 v1srcstv;
uint32 a1orgv;
};
static void eng_bes_calc_move_overlay(move_overlay_info *moi);
static void eng_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 eng_bes_move_overlay()
{
move_overlay_info moi;
if (!si->overlay.active) return;
eng_bes_calc_move_overlay(&moi);
eng_bes_program_move_overlay(moi);
}
static void eng_bes_calc_move_overlay(move_overlay_info *moi)
{
uint16 temp1, temp2;
uint16 crtc_hstart, crtc_vstart, crtc_hend, crtc_vend;
if (si->ps.secondary_head)
{
switch (si->dm.flags & DUALHEAD_BITS)
{
case DUALHEAD_ON:
case DUALHEAD_SWITCH:
if ((si->overlay.ow.h_start + (si->overlay.ow.width / 2)) <
(si->dm.h_display_start + si->dm.timing.h_display))
eng_bes_to_crtc(si->crtc_switch_mode);
else
eng_bes_to_crtc(!si->crtc_switch_mode);
break;
default:
eng_bes_to_crtc(si->crtc_switch_mode);
break;
}
}
* constraints only */
crtc_hstart = si->dm.h_display_start;
if (si->overlay.crtc)
{
crtc_hstart += si->dm.timing.h_display;
}
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) & 0x7ff;
}
else
{
temp1 = (si->overlay.ow.h_start - crtc_hstart) & 0x7ff;
}
}
moi->hcoordv |= temp1 << 16;
if (si->overlay.ow.width < 2)
{
temp2 = (temp1 + 1) & 0x7ff;
}
else
{
if ((si->overlay.ow.h_start + si->overlay.ow.width - 1) > (crtc_hend - 1))
{
temp2 = (crtc_hend - crtc_hstart - 1) & 0x7ff;
}
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)) & 0x7ff;
}
}
}
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) & 0x7ff;
}
else
{
temp1 = (si->overlay.ow.v_start - crtc_vstart) & 0x7ff;
}
}
moi->vcoordv |= temp1 << 16;
if (si->overlay.ow.height < 2)
{
temp2 = (temp1 + 1) & 0x7ff;
}
else
{
if ((si->overlay.ow.v_start + si->overlay.ow.height - 1) > (crtc_vend - 1))
{
temp2 = (crtc_vend - crtc_vstart - 1) & 0x7ff;
}
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)) & 0x7ff;
}
}
}
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.! */
moi->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))
{
moi->hsrcstv += (si->overlay.ow.width - 2);
}
else
{
moi->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! */
moi->hsrcstv *= si->overlay.h_ifactor;
}
moi->hsrcstv += ((uint32)si->overlay.my_ov.h_start) << 16;
moi->hsrcstv &= 0x03fffffc;
LOG(4,("Overlay: first hor. (sub)pixel of input bitmap contributing %f\n", moi->hsrcstv / (float)65536));
*** setup vertical clipping ***
*******************************/
moi->a1orgv = (uint32)((vuint32 *)si->overlay.ob.buffer);
moi->a1orgv -= (uint32)((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.! */
moi->v1srcstv = 0;
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))
{
* 'total height - 2' of dest. picture in pixels * inverse scaling factor */
moi->v1srcstv = (si->overlay.ow.height - 2) * si->overlay.v_ifactor;
* bitmap because no seperate clipping registers exist... */
if (si->ps.card_arch < NV10A)
moi->a1orgv += ((moi->v1srcstv >> 16) * si->overlay.ob.bytes_per_row);
}
else
{
* number of destination picture clipping pixels * inverse scaling factor */
moi->v1srcstv = (crtc_vstart - si->overlay.ow.v_start) * si->overlay.v_ifactor;
* bitmap because no seperate clipping registers exist... */
if (si->ps.card_arch < NV10A)
moi->a1orgv += ((moi->v1srcstv >> 16) * si->overlay.ob.bytes_per_row);
}
LOG(4,("Overlay: clipping at top...\n"));
}
moi->v1srcstv += (((uint32)si->overlay.my_ov.v_start) << 16);
if (si->ps.card_arch < NV10A)
{
moi->a1orgv += (si->overlay.my_ov.v_start * si->overlay.ob.bytes_per_row);
LOG(4,("Overlay: 'contributing part of buffer' origin is (cardRAM offset) $%08x\n", moi->a1orgv));
}
LOG(4,("Overlay: first vert. (sub)pixel of input bitmap contributing %f\n", moi->v1srcstv / (float)65536));
moi->a1orgv &= 0xfffffff0;
}
static void eng_bes_program_move_overlay(move_overlay_info moi)
{
*** sync to BES (Back End Scaler) ***
*************************************/
* double buffered registers + trigger if programming complete feature. */
*** actually program the registers ***
**************************************/
if (si->ps.card_arch < NV10A)
{
BESW(NV04_OE_STATE, 0x00000000);
BESW(NV04_SU_STATE, 0x00000000);
BESW(NV04_RM_STATE, 0x00000000);
* either. We do pixelprecise vertical and 'two pixel' precise horizontal clipping here. */
moi.a1orgv += ((moi.hsrcstv >> 16) * 2);
BESW(NV04_0BUFADR, (moi.a1orgv & ~0x03));
BESW(NV04_1BUFADR, (moi.a1orgv & ~0x03));
BESW(NV04_DSTREF, ((moi.vcoordv & 0xffff0000) | ((moi.hcoordv & 0xffff0000) >> 16)));
BESW(NV04_DSTSIZE, (
(((moi.vcoordv & 0x0000ffff) - ((moi.vcoordv & 0xffff0000) >> 16) + 1) << 16) |
((moi.hcoordv & 0x0000ffff) - ((moi.hcoordv & 0xffff0000) >> 16) + 1)
));
BESW(NV04_SU_STATE, 0x00010000);
}
else
{
BESW(NV10_0SRCREF, ((moi.v1srcstv << 4) & 0xffff0000) | ((moi.hsrcstv >> 12) & 0x0000ffff));
BESW(NV10_0DSTREF, ((moi.vcoordv & 0xffff0000) | ((moi.hcoordv & 0xffff0000) >> 16)));
BESW(NV10_0DSTSIZE, (
(((moi.vcoordv & 0x0000ffff) - ((moi.vcoordv & 0xffff0000) >> 16) + 1) << 16) |
((moi.hcoordv & 0x0000ffff) - ((moi.hcoordv & 0xffff0000) >> 16) + 1)
));
BESW(NV10_BUFSEL, 0x00000001);
}
}
status_t eng_bes_to_crtc(bool crtc)
{
if (si->ps.secondary_head)
{
if (crtc)
{
LOG(4,("Overlay: switching overlay to CRTC2\n"));
ENG_RG32(RG32_FUNCSEL) &= ~0x00001000;
ENG_RG32(RG32_2FUNCSEL) |= 0x00001000;
si->overlay.crtc = !si->crtc_switch_mode;
}
else
{
LOG(4,("Overlay: switching overlay to CRTC1\n"));
ENG_RG32(RG32_2FUNCSEL) &= ~0x00001000;
ENG_RG32(RG32_FUNCSEL) |= 0x00001000;
si->overlay.crtc = si->crtc_switch_mode;
}
return B_OK;
}
else
{
return B_ERROR;
}
}
status_t eng_bes_init()
{
if (si->ps.card_arch < NV10A)
{
BESW(NV04_INTE, 0x00000000);
BESW(NV04_SAT, 0x00000000);
BESW(NV04_RED_AMP, 0x00000069);
BESW(NV04_GRN_AMP, 0x0000003e);
BESW(NV04_BLU_AMP, 0x00000089);
BESW(NV04_FIFOBURL, 0x00000003);
BESW(NV04_FIFOTHRS, 0x00000038);
BESW(NV04_0OFFSET, 0x00000000);
BESW(NV04_1OFFSET, 0x00000000);
}
else
{
BESW(NV10_INTE, 0x00000000);
BESW(DEC_GENCTRL, 0x00000000);
BESW(NV10_0MEMMASK, (si->ps.memory_size - 1));
BESW(NV10_0OFFSET, 0x00000000);
BESW(NV10_0BRICON, ((0x1000 << 16) | 0x1000));
BESW(NV10_0SAT, ((0x0000 << 16) | 0x1000));
}
return B_OK;
}
status_t eng_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. */
move_overlay_info moi;
uint32 hiscalv, viscalv;
uint16 intrep;
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(4,("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(4,("Overlay: total input picture width = %d, height = %d\n",
(ob->width - si->overlay.myBufInfo[offset].slopspace), ob->height));
LOG(4,("Overlay: output picture width = %d, height = %d\n", ow->width, ow->height));
if (ow->flags & B_OVERLAY_HORIZONTAL_FILTERING)
{
if ((my_ov.width == ow->width) | (ow->width < 2))
{
intrep = 0;
}
else
{
intrep = 1;
}
}
else
{
if ((ow->width < my_ov.width) & (ow->width >= 2))
{
intrep = 1;
}
else
{
intrep = 0;
}
}
LOG(4,("Overlay: horizontal interval representation value is %d\n",intrep));
ifactor = (((uint32)(my_ov.width - intrep)) << 16) / (ow->width - intrep);
ifactor -= (1 << 2);
hiscalv = ifactor;
si->overlay.h_ifactor = ifactor;
LOG(4,("Overlay: horizontal scaling factor is %f\n", (float)65536 / ifactor));
if (hiscalv < 0x00002000)
{
hiscalv = 0x00002000;
LOG(4,("Overlay: horizontal scaling factor too large, clamping at %f\n", (float)65536 / hiscalv));
}
switch (si->ps.card_arch)
{
case NV04A:
* (16bit register with 0.11 format value) */
if (hiscalv > 0x0000ffff)
{
hiscalv = 0x0000ffff;
LOG(4,("Overlay: horizontal scaling factor too small, clamping at %f\n", (float)2048 / (hiscalv >> 5)));
}
break;
case NV30A:
case NV40A:
if ((hiscalv > (2 << 16)) && (si->ps.card_type != NV31))
{
hiscalv = (2 << 16);
LOG(4,("Overlay: horizontal scaling factor too small, clamping at %f\n", (float)65536 / hiscalv));
}
* So let it fall through... */
if (si->ps.card_type != NV31) break;
default:
if (hiscalv > (8 << 16))
{
hiscalv = (8 << 16);
LOG(4,("Overlay: horizontal scaling factor too small, clamping at %f\n", (float)65536 / hiscalv));
}
break;
}
hiscalv &= 0x001ffffc;
*** setup vertical scaling ***
******************************/
if (ow->flags & B_OVERLAY_VERTICAL_FILTERING)
{
if ((my_ov.height == ow->height) | (ow->height < 2))
{
intrep = 0;
}
else
{
intrep = 1;
}
}
else
{
if ((ow->height < my_ov.height) & (ow->height >= 2))
{
intrep = 1;
}
else
{
intrep = 0;
}
}
LOG(4,("Overlay: vertical interval representation value is %d\n",intrep));
ifactor = (((uint32)(my_ov.height - intrep)) << 16) / (ow->height - intrep);
ifactor -= (1 << 2);
LOG(4,("Overlay: vertical scaling factor is %f\n", (float)65536 / ifactor));
viscalv = ifactor;
si->overlay.v_ifactor = ifactor;
if (viscalv < 0x00002000)
{
viscalv = 0x00002000;
LOG(4,("Overlay: vertical scaling factor too large, clamping at %f\n", (float)65536 / viscalv));
}
switch (si->ps.card_arch)
{
case NV04A:
* (16bit register with 0.11 format value) */
if (viscalv > 0x0000ffff)
{
viscalv = 0x0000ffff;
LOG(4,("Overlay: vertical scaling factor too small, clamping at %f\n", (float)2048 / (viscalv >> 5)));
}
break;
case NV30A:
case NV40A:
if ((viscalv > (2 << 16)) && (si->ps.card_type != NV31))
{
viscalv = (2 << 16);
LOG(4,("Overlay: vertical scaling factor too small, clamping at %f\n", (float)65536 / viscalv));
}
* So let it fall through... */
if (si->ps.card_type != NV31) break;
default:
if (viscalv > (8 << 16))
{
viscalv = (8 << 16);
LOG(4,("Overlay: vertical scaling factor too small, clamping at %f\n", (float)65536 / viscalv));
}
break;
}
viscalv &= 0x001ffffc;
*** setup all edges of output window, setup horizontal and vertical clipping ***
********************************************************************************/
eng_bes_calc_move_overlay(&moi);
*** log color keying info ***
*****************************/
LOG(4,("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(4,("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));
*** log flags ***
*****************/
LOG(4,("Overlay: ow->flags is $%08x\n",ow->flags));
*** sync to BES (Back End Scaler) ***
*************************************/
* double buffered registers + trigger if programming complete feature. */
*** actually program the registers ***
**************************************/
if (si->ps.card_arch < NV10A)
{
BESW(NV04_OE_STATE, 0x00000000);
BESW(NV04_SU_STATE, 0x00000000);
BESW(NV04_RM_STATE, 0x00000000);
* either. We do pixelprecise vertical and 'two pixel' precise horizontal clipping here. */
moi.a1orgv += ((moi.hsrcstv >> 16) * 2);
BESW(NV04_0BUFADR, (moi.a1orgv & ~0x03));
BESW(NV04_1BUFADR, (moi.a1orgv & ~0x03));
* Note:
* source pitch granularity = 16 pixels on the RIVA128 - TNT (so pre-NV10) bes */
BESW(NV04_0SRCPTCH, (ob->width * 2));
BESW(NV04_1SRCPTCH, (ob->width * 2));
BESW(NV04_DSTREF, ((moi.vcoordv & 0xffff0000) | ((moi.hcoordv & 0xffff0000) >> 16)));
BESW(NV04_DSTSIZE, (
(((moi.vcoordv & 0x0000ffff) - ((moi.vcoordv & 0xffff0000) >> 16) + 1) << 16) |
((moi.hcoordv & 0x0000ffff) - ((moi.hcoordv & 0xffff0000) >> 16) + 1)
));
BESW(NV04_ISCALVH, (((viscalv << 16) >> 5) | (hiscalv >> 5)));
BESW(NV04_CTRL_V, 0x00000001);
BESW(NV04_CTRL_H, 0x00000111);
BESW(NV04_GENCTRL, 0x00000111);
BESW(NV04_SU_STATE, 0x00010000);
*** setup color keying ***
**************************/
switch(si->dm.space)
{
case B_RGB15_LITTLE:
BESW(NV04_COLKEY, (
((ow->blue.value & ow->blue.mask) << 0) |
((ow->green.value & ow->green.mask) << 5) |
((ow->red.value & ow->red.mask) << 10) |
((ow->alpha.value & ow->alpha.mask) << 15)
));
break;
case B_RGB16_LITTLE:
BESW(NV04_COLKEY, (
((ow->blue.value & ow->blue.mask) << 0) |
((ow->green.value & ow->green.mask) << 5) |
((ow->red.value & ow->red.mask) << 11)
));
break;
case B_CMAP8:
case B_RGB32_LITTLE:
default:
BESW(NV04_COLKEY, (
((ow->blue.value & ow->blue.mask) << 0) |
((ow->green.value & ow->green.mask) << 8) |
((ow->red.value & ow->red.mask) << 16) |
((ow->alpha.value & ow->alpha.mask) << 24)
));
break;
}
}
else
{
BESW(NV10_0SRCREF, ((moi.v1srcstv << 4) & 0xffff0000) | ((moi.hsrcstv >> 12) & 0x0000ffff));
BESW(NV10_0SRCSIZE, ((ob->height << 16) | ob->width));
* b16: select YUY2 (0 = YV12), b20: use colorkey, b24: no iturbt_709 (do iturbt_601) */
* source pitch granularity = 32 pixels on GeForce cards!! */
BESW(NV10_0SRCPTCH, (((ob->width * 2) & 0x0000ffff) | (1 << 16) | (1 << 20) | (0 << 24)));
BESW(NV10_0DSTREF, ((moi.vcoordv & 0xffff0000) | ((moi.hcoordv & 0xffff0000) >> 16)));
BESW(NV10_0DSTSIZE, (
(((moi.vcoordv & 0x0000ffff) - ((moi.vcoordv & 0xffff0000) >> 16) + 1) << 16) |
((moi.hcoordv & 0x0000ffff) - ((moi.hcoordv & 0xffff0000) >> 16) + 1)
));
BESW(NV10_0ISCALH, (hiscalv << 4));
BESW(NV10_0ISCALV, (viscalv << 4));
BESW(NV10_0BUFADR, moi.a1orgv);
BESW(NV10_GENCTRL, 0x00000000);
BESW(NV10_BUFSEL, 0x00000001);
*** setup color keying ***
**************************/
switch(si->dm.space)
{
case B_RGB15_LITTLE:
BESW(NV10_COLKEY, (
((ow->blue.value & ow->blue.mask) << 0) |
((ow->green.value & ow->green.mask) << 5) |
((ow->red.value & ow->red.mask) << 10) |
((ow->alpha.value & ow->alpha.mask) << 15)
));
break;
case B_RGB16_LITTLE:
BESW(NV10_COLKEY, (
((ow->blue.value & ow->blue.mask) << 0) |
((ow->green.value & ow->green.mask) << 5) |
((ow->red.value & ow->red.mask) << 11)
));
break;
case B_CMAP8:
case B_RGB32_LITTLE:
default:
BESW(NV10_COLKEY, (
((ow->blue.value & ow->blue.mask) << 0) |
((ow->green.value & ow->green.mask) << 8) |
((ow->red.value & ow->red.mask) << 16) |
((ow->alpha.value & ow->alpha.mask) << 24)
));
break;
}
}
si->overlay.active = true;
return B_OK;
}
status_t eng_release_bes()
{
if (si->ps.card_arch < NV10A)
{
BESW(NV04_GENCTRL, 0x00000000);
}
else
{
BESW(NV10_GENCTRL, 0x00000001);
}
si->overlay.active = false;
return B_OK;
}