📄 overlay_xscale.c
字号:
#endif
static void SetOrig(xscaledriver* p)
{
int n;
#ifdef X50V
if (p->X50v)
X50vDisable(p);
else
#endif
{
if (p->NotOrig)
{
if (p->OrigDescEnd && p->OrigDescEndSet)
{
p->OrigDescEnd->Next = p->OrigDescPhy[0];
p->OrigDescEndSet = 0;
}
for (n=0;n<p->Count;++n)
p->DescLast[n]->Next = p->OrigDescPhy[0];
// wait for primary to be restored
for (n=0;n<100;++n)
{
if (GetCurrent(p)<0)
break;
Sleep(1);
}
p->NotOrig = 0;
}
}
}
static void Done(xscale* p)
{
SetOrig(p->Driver);
if (p->Driver->Used == p)
p->Driver->Used = NULL;
}
static int Reset(xscale* p)
{
Done(p);
Init(p);
return ERR_NONE;
}
static xscaledesc* BuildDesc(xscaledesc* Desc,phymemblock* DescPhy,int DescPhyCount,phymemblock* BufferPhy,int BufferPhyCount,
int* Map,int Pitch,int Height,int Id)
{
uint32_t First = DescPhy->Addr;
uint32_t Last = 0;
uint32_t DescAddr = 0;
int n,m;
for (n=0;n<Height;++n)
{
uint32_t Pos = Pitch * Map[n];
int Length = Pitch;
for (m=0;Length>0 && m<BufferPhyCount;++m)
{
if (Pos < BufferPhy[m].Length)
{
uint32_t Addr = BufferPhy[m].Addr + Pos;
int Size = BufferPhy[m].Length - Pos;
if (Size > Length)
Size = Length;
if (Size & 3) return NULL; // this shouldn't happen
// add desc
if (Addr != Last)
{
DescAddr += sizeof(xscaledesc);
if (DescAddr > DescPhy->Length)
{
// next desc block
if (--DescPhyCount==0) return NULL; // not enough desc...
++DescPhy;
DescAddr = 0;
}
Desc->Next = DescPhy->Addr + DescAddr;
Desc->Base = Addr;
Desc->Id = Id;
Desc->Cmd = Size;
++Desc;
}
else
Desc[-1].Cmd += Size;
Last = Addr + Size;
Length -= Size;
Pos += Size;
}
Pos -= BufferPhy[m].Length;
}
}
--Desc;
Desc->Next = First;
Desc->Cmd |= (1<<21);
return Desc;
}
static bool_t Build(xscaledriver* p)
{
int n;
for (n=0;n<p->Count;++n)
{
p->DescLast[n] = BuildDesc(p->Desc[n],p->DescPhy[n],p->DescPhyCount[n],p->BufferPhy+p->MaxBlock*n,
p->BufferPhyCount[n],p->Map,p->Width*2,p->Height,MAGIC | (n<<4));
if (!p->DescLast[n])
break;
}
if (n==p->Count)
{
for (n=p->OrigDescCount?1:0;n<p->Count;++n)
memset(p->Buffer[n],0,p->BufferSize);
return 1;
}
return 0;
}
static int UpdateAlign(xscale* p)
{
rect FullScreen;
int* ScaleY;
blitfx FX = p->Overlay.FX;
bool_t FullView;
if (FX.Direction & DIR_SWAPXY)
ScaleY = &FX.ScaleX;
else
ScaleY = &FX.ScaleY;
PhyToVirt(NULL,&FullScreen,&p->Overlay.Output.Format.Video);
FullView = p->Driver->Count && EqRect(&FullScreen,&p->Overlay.Viewport);
if (FullView && p->Driver->Count>=3)
p->Overlay.FX.Flags &= ~BLITFX_AVOIDTEARING; //flipping used
p->Flip = 0;
p->Next = 0;
SetOrig(p->Driver);
OverlayUpdateAlign(&p->Overlay);
if (FullView && p->Driver->Count)
{
int n;
for (n=0;n<p->Overlay.Output.Format.Video.Height;++n)
p->Driver->Map[n]=n;
if (p->Driver->SetupStretch &&
((p->Overlay.Node.Class == XSCALE_LOW_ID && *ScaleY > SCALE_ONE/2) || *ScaleY > SCALE_ONE) &&
!(p->Overlay.Output.Format.Video.Width & 1) && p->Overlay.Output.Format.Video.Height>0)
{
int Num,Den;
int Adj;
int LowSrc,HighSrc,CenterSrc;
rect DstAlignedRect;
rect SrcAlignedRect;
*ScaleY = p->Overlay.Node.Class == XSCALE_LOW_ID ? SCALE_ONE/2 : SCALE_ONE;
VirtToPhy(&p->Overlay.Viewport,&DstAlignedRect,&p->Overlay.Output.Format.Video);
VirtToPhy(NULL,&SrcAlignedRect,&p->Overlay.Input.Format.Video);
BlitRelease(p->Overlay.Soft);
p->Overlay.Soft = BlitCreate(&p->Overlay.Output.Format.Video,&p->Overlay.Input.Format.Video,&FX,&p->Overlay.Caps);
BlitAlign(p->Overlay.Soft, &DstAlignedRect, &SrcAlignedRect );
LowSrc = -(DstAlignedRect.Height/2);
HighSrc = LowSrc + DstAlignedRect.Height;
CenterSrc = DstAlignedRect.y - LowSrc;
Num = DstAlignedRect.Height;
Den = p->Overlay.DstAlignedRect.Height;
if (FX.Direction & DIR_SWAPXY)
{
Num *= p->Overlay.SrcAlignedRect.Width;
Den *= SrcAlignedRect.Width;
}
else
{
Num *= p->Overlay.SrcAlignedRect.Height;
Den *= SrcAlignedRect.Height;
}
Adj = Scale(p->Overlay.DstAlignedRect.Height,Num,2*Den);
for (n=0;n<p->Overlay.DstAlignedRect.Height;++n)
{
int i = Scale(n,Num,Den) - Adj;
if (i >= HighSrc) i=HighSrc-1;
if (i < LowSrc) i=LowSrc;
p->Driver->Map[p->Overlay.DstAlignedRect.y+n] = CenterSrc + i;
}
}
if (Build(p->Driver))
{
p->Overlay.FX.Flags |= BLITFX_AVOIDTEARING; //restore
p->Flip = 1;
}
}
return ERR_NONE;
}
static void Restore(xscaledriver* p,int Next)
{
int n;
char *s,*d;
char *Src = (char*)p->Buffer[Next];
char *Dst = (char*)p->OrigBuffer;
int Middle = p->Height/2;
int Pitch = p->Width*2;
for (n=0;n<Middle;++n)
{
s = Src + p->Map[n] * Pitch;
d = Dst + n*Pitch;
if (s != d)
memcpy(d,s,Pitch);
}
for (n=p->Height-1;n>=Middle;--n)
{
s = Src + p->Map[n] * Pitch;
d = Dst + n*Pitch;
if (s != d)
memcpy(d,s,Pitch);
}
}
static int UpdateShow(xscale* p)
{
if (!p->Overlay.Show)
{
SetOrig(p->Driver);
if (p->Flip)
{
// restore after SetOrig because it's vsynced and restore starts for upper part anyway
Restore(p->Driver,p->Next);
}
p->Next = 0;
}
return ERR_NONE;
}
static int Lock(xscale* p, planes Planes, bool_t OnlyAligned )
{
if (p->Flip)
{
int Next = p->Next+1;
if (Next == p->Driver->Count)
Next = 0;
// use new buffer only if it's not the current
if (GetCurrent(p->Driver) != Next)
p->Next = Next;
Planes[0] = p->Driver->Buffer[p->Next];
}
else
Planes[0] = p->Driver->OrigBuffer;
return ERR_NONE;
}
static int Unlock(xscale* p )
{
if (p->Flip)
{
int Current = GetCurrent(p->Driver);
uint32_t DescPhy = p->Driver->DescPhy[p->Next]->Addr;
// close chain
p->Driver->DescLast[p->Next]->Next = DescPhy;
#ifdef X50V
if (p->Driver->X50v && X50vEnable(p->Driver,DescPhy))
Current = p->Next;
#endif
DEBUG_MSG4(-1,T("%08x %08x %08x %d"),p->Driver->Regs[LCCR0],p->Driver->Regs[LCCR3],p->Driver->Regs[FDADR0],Current);
if (Current<-1)
return ERR_DEVICE_ERROR;
if (Current<0)
{
if (p->Driver->OrigDescEnd)
{
p->Driver->OrigDescEnd->Next = DescPhy;
p->Driver->OrigDescEndSet = 1;
}
else
if (p->Driver->OrigDescCount>1)
{
// multi desc original
bool_t Old = (p->Driver->Regs[LCCR0] & 1);
Disable(p->Driver);
p->Driver->Regs[FBR0] = 0;
p->Driver->Regs[FDADR0] = DescPhy;
if (Old) Enable(p->Driver);
}
else // simply branch
p->Driver->Regs[FBR0] = DescPhy | 1;
}
else
{
// modify last frames tail to new frame
Current = p->Next-1;
if (Current<0)
Current = p->Driver->Count-1;
p->Driver->DescLast[Current]->Next = DescPhy;
}
p->Driver->NotOrig = 1;
}
return ERR_NONE;
}
static int UpdateStretch(xscaledriver* Driver)
{
if (Driver->Used)
UpdateAlign(Driver->Used);
return ERR_NONE;
}
static int UpdateFlip(xscaledriver* Driver)
{
if (Driver->Used)
{
xscale* p = Driver->Used;
Done(p);
FreeBuffer(Driver);
Init(p);
UpdateAlign(p);
p->Overlay.Dirty = 1;
p->Overlay.LastTime = -1;
}
return ERR_NONE;
}
static const datatable Params[] =
{
{ XSCALEDRIVER_STRETCH, TYPE_BOOL, DF_SETUP|DF_CHECKLIST },
{ XSCALEDRIVER_FLIP, TYPE_BOOL, DF_SETUP|DF_CHECKLIST },
{ XSCALEDRIVER_ALLOC_AT_START, TYPE_BOOL, DF_SETUP|DF_CHECKLIST },
DATATABLE_END(XSCALEDRIVER_ID)
};
static int Enum(xscaledriver* p, int* No, datadef* Param)
{
return NodeEnumTable(No,Param,Params);
}
static int Get(xscaledriver* p,int No,void* Data,int Size)
{
int Result = ERR_INVALID_PARAM;
switch (No)
{
case XSCALEDRIVER_STRETCH: GETVALUE(p->SetupStretch,bool_t); break;
case XSCALEDRIVER_FLIP: GETVALUE(p->SetupFlip,bool_t); break;
case XSCALEDRIVER_ALLOC_AT_START: GETVALUE(p->AllocAtStart,bool_t); break;
}
return Result;
}
static bool_t Selected()
{
int Id;
return NodeRegLoadValue(PLAYER_ID,PLAYER_VOUTPUTID,&Id,sizeof(Id),TYPE_INT) && (Id == XSCALE_ID || Id == XSCALE_LOW_ID);
}
static int Set(xscaledriver* p,int No,const void* Data,int Size)
{
int Result = ERR_INVALID_PARAM;
switch (No)
{
case XSCALEDRIVER_STRETCH: SETVALUECMP(p->SetupStretch,bool_t,UpdateStretch(p),EqBool); break;
case XSCALEDRIVER_FLIP: SETVALUECMP(p->SetupFlip,bool_t,UpdateFlip(p),EqBool); break;
case XSCALEDRIVER_ALLOC_AT_START: SETVALUE(p->AllocAtStart,bool_t,ERR_NONE); break;
case NODE_SETTINGSCHANGED:
if (p->AllocAtStart && p->AtStart && Selected())
{
if (!p->OrigBuffer)
GetOrig(p);
AllocBuffer(p);
}
p->AtStart = 0;
break;
case NODE_HIBERNATE:
if (!p->Used && FreeBuffer(p))
Result = ERR_NONE;
break;
}
return Result;
}
static int Create(xscale* p)
{
p->Driver = (xscaledriver*)NodeEnumObject(NULL,XSCALEDRIVER_ID);
if (!p->Driver)
return ERR_NOT_SUPPORTED;
if (p->Overlay.Node.Class == XSCALE_LOW_ID && (p->Driver->Width*p->Driver->Height <= 320*240 ||
(QueryPlatform(PLATFORM_CAPS) & CAPS_ARM_WMMX)!=0))
return ERR_NOT_SUPPORTED;
GetMode(p);
p->Overlay.Init = Init;
p->Overlay.Done= Done;
p->Overlay.Reset = Reset;
p->Overlay.Update = UpdateAlign;
p->Overlay.UpdateShow = UpdateShow;
p->Overlay.Lock = Lock;
p->Overlay.Unlock = Unlock;
return ERR_NONE;
}
static int CreateDriver(xscaledriver* p)
{
bool_t Detected;
int Caps = QueryPlatform(PLATFORM_CAPS);
if (!(Caps & CAPS_ARM_XSCALE))
return ERR_NOT_SUPPORTED;
p->Node.Enum = Enum;
p->Node.Get = Get;
p->Node.Set = Set;
p->AtStart = 1;
p->OrigBuffer = NULL;
p->OrigDescCount = 0;
p->Regs = (uint32_t*)PhyMemBegin(LCD_BASE,LCD_SIZE,0);
if (!p->Regs)
return ERR_NOT_SUPPORTED;
#ifdef X50V
p->X50v = QueryPlatform(PLATFORM_MODEL)==MODEL_AXIM_X50 && CheckModule(T("pvrvadd.dll"));
if (p->X50v)
{
p->Width = 480;
p->Height = 640;
p->Marathon = (uint32_t*) 0xBC000000;
p->GPIO = (uint32_t*) PhyMemBegin(GPIO_BASE,GPIO_SIZE,0);
if (p->GPIO)
{
RawFrameBufferInfo Info;
HDC DC= GetDC(NULL);
memset(&Info,0,sizeof(Info));
ExtEscape(DC, GETRAWFRAMEBUFFER, 0, NULL, sizeof(RawFrameBufferInfo), (char*)&Info);
ReleaseDC(NULL,DC);
p->OrigBuffer = Info.pFramePointer;
}
}
else
#endif
if (!(p->Regs[LCCR0] & 1) || ((p->Regs[LCCR3] >> 24) & 7)!=4) // LCD enabled, RGB 16bit
return ERR_NOT_SUPPORTED;
if (!NodeRegLoadValue(XSCALEDRIVER_ID, XSCALEDRIVER_DETECTED, &Detected, sizeof(Detected), TYPE_BOOL) || !Detected)
{
GetOrig(p);
if (!p->OrigBuffer)
{
PhyMemEnd(p->Regs);
p->Regs = NULL;
return ERR_NOT_SUPPORTED;
}
Detected = 1;
NodeRegSaveValue(XSCALEDRIVER_ID, XSCALEDRIVER_DETECTED, &Detected, sizeof(Detected), TYPE_BOOL);
}
p->AllocAtStart = 1;
p->SetupFlip = 1;
p->SetupStretch = (QueryPlatform(PLATFORM_CAPS) & CAPS_ARM_WMMX)==0;
return ERR_NONE;
}
static void DeleteDriver(xscaledriver* p)
{
if (p->Regs)
SetOrig(p);
FreeBuffer(p);
FreeOrig(p);
#ifdef X50V
if (p->GPIO)
{
PhyMemEnd(p->GPIO);
p->GPIO = NULL;
}
#endif
if (p->Regs)
{
PhyMemEnd(p->Regs);
p->Regs = NULL;
}
}
static const nodedef XScaleDriver =
{
sizeof(xscaledriver)|CF_GLOBAL|CF_SETTINGS,
XSCALEDRIVER_ID,
NODE_CLASS,
PRI_DEFAULT,
(nodecreate)CreateDriver,
(nodedelete)DeleteDriver,
};
static const nodedef XScale =
{
sizeof(xscale)|CF_GLOBAL,
XSCALE_ID,
OVERLAY_CLASS,
PRI_DEFAULT+97,
(nodecreate)Create,
};
static const nodedef XScaleLow =
{
sizeof(xscale)|CF_GLOBAL,
XSCALE_LOW_ID,
XSCALE_ID,
PRI_DEFAULT+96,
};
void OverlayXScale_Init()
{
NodeRegisterClass(&XScaleDriver);
NodeRegisterClass(&XScale);
NodeRegisterClass(&XScaleLow);
}
void OverlayXScale_Done()
{
NodeUnRegisterClass(XSCALE_LOW_ID);
NodeUnRegisterClass(XSCALE_ID);
NodeUnRegisterClass(XSCALEDRIVER_ID);
}
#else
void OverlayXScale_Init() {}
void OverlayXScale_Done() {}
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -