📄 blit_soft.c
字号:
/*****************************************************************************
*
* This program is free software ; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* $Id: blit_soft.c 607 2006-01-22 20:58:29Z picard $
*
* The Core Pocket Media Player
* Copyright (c) 2004-2005 Gabor Kovacs
*
****************************************************************************/
#include "../common.h"
#include "../dyncode/dyncode.h"
#include "../cpu/cpu.h"
#include "blit_soft.h"
//#define BLITTEST
/*
TV range:
+16 (219)
+128 (224)
+128 (224)
PC range:
+0 (255)
+128 (255)
+128 (255)
ranges:
R,G,B,Y [0..1]
Cb,Cr [-0.5..0.5]
Y' = Kr * R' + (1 - Kr - Kb) * G' + Kb * B'
Cb = 0.5 * (B' - Y') / (1 - Kb)
Cr = 0.5 * (R' - Y') / (1 - Kr)
Kb = 0.114
Kr = 0.299
ITU-R BT 601
Y'= 0.299 *R' + 0.587 *G' + 0.114 *B'
Cb=-0.168736*R' - 0.331264*G' + 0.5 *B'
Cr= 0.5 *R' - 0.418688*G' - 0.081312*B'
R'= Y' + 1.403*Cr
G'= Y' - 0.344*Cb - 0.714*Cr
B'= Y' + 1.773*Cb
Kb = 0.0722
Kr = 0.2126
ITU-R BT 709
Y'= 0.2215*R' + 0.7154*G' + 0.0721*B'
Cb=-0.1145*R' - 0.3855*G' + 0.5000*B'
Cr= 0.5016*R' - 0.4556*G' - 0.0459*B'
R'= Y' + 1.5701*Cr
G'= Y' - 0.1870*Cb - 0.4664*Cr
B'= Y' - 1.8556*Cb
*/
#define CM(i) ((int16_t)((i)*8192))
#if defined(_M_IX86) && !defined(TARGET_SYMBIAN)
static const int16_t YUVToRGB[4][8] =
{
// TV range BT-601
{ CM(1.164),-16,CM(1.596),CM(-0.813),-128,CM(2.017),CM(-0.392),-128 },
// TV range BT-709
{ CM(1.164),-16,CM(1.786),CM(-0.530),-128,CM(2.111),CM(-0.213),-128 },
// PC range BT-601
{ CM(1),0,CM(1.402),CM(-0.71414),-128,CM(1.772),CM(-0.34414),-128 },
// PC range BT-709
{ CM(1),0,CM(1.5701),CM(-0.4664),-128,CM(1.8556),CM(-0.1870),-128 },
};
static const int16_t* GetYUVToRGB(const pixel* Src)
{
int i = 0;
if (Src->Flags & PF_YUV_BT709)
i += 1;
if (Src->Flags & PF_YUV_PC)
i += 2;
return YUVToRGB[i];
}
#endif
#define SAT(Value) (Value < 0 ? 0: (Value > 255 ? 255: Value))
static const rgbval_t Gray1[2] = {
CRGB(0,0,0),CRGB(255,255,255)
};
static const rgbval_t Gray2[4] = {
CRGB(0,0,0),CRGB(85,85,85),CRGB(170,170,170),CRGB(255,255,255)
};
static const rgbval_t Gray4[16] = {
CRGB(0,0,0),CRGB(17,17,17),CRGB(34,34,34),CRGB(51,51,51),
CRGB(68,68,68),CRGB(85,85,85),CRGB(102,102,102),CRGB(119,119,119),
CRGB(136,136,136),CRGB(153,153,153),CRGB(170,170,170),CRGB(187,187,187),
CRGB(204,204,204),CRGB(221,221,221),CRGB(238,238,238),CRGB(255,255,255)
};
#if defined(_M_IX86) && !defined(TARGET_SYMBIAN)
#define DECLARE_BLITMMX(name) \
extern void STDCALL name##_mmx(blit_soft* This, uint8_t** DstPtr,uint8_t** SrcPtr,int DstPitch,int SrcPitch,int Width,int Height,uintptr_t Src2SrcLast); \
extern void STDCALL name##_mmx2(blit_soft* This, uint8_t** DstPtr,uint8_t** SrcPtr,int DstPitch,int SrcPitch,int Width,int Height,uintptr_t Src2SrcLast); \
extern void STDCALL name##_3dnow(blit_soft* This, uint8_t** DstPtr,uint8_t** SrcPtr,int DstPitch,int SrcPitch,int Width,int Height,uintptr_t Src2SrcLast);
DECLARE_BLITMMX(blit_i420_i420)
DECLARE_BLITMMX(blit_i420_yuy2)
DECLARE_BLITMMX(blit_i420_rgb32)
DECLARE_BLITMMX(blit_i420_rgb24)
DECLARE_BLITMMX(blit_i420_bgr32)
DECLARE_BLITMMX(blit_i420_bgr24)
DECLARE_BLITMMX(blit_rgb32_rgb32)
DECLARE_BLITMMX(blit_rgb24_rgb24)
DECLARE_BLITMMX(blit_rgb16_rgb16)
typedef struct blitmmx
{
uint32_t In;
uint32_t Out;
blitsoftentry Func[3];
} blitmmx;
static const blitmmx BlitMMX[] =
{
{ FOURCC_I420, FOURCC_I420, { blit_i420_i420_mmx, blit_i420_i420_mmx2, blit_i420_i420_3dnow }},
{ FOURCC_I420, FOURCC_YUY2, { blit_i420_yuy2_mmx, blit_i420_yuy2_mmx2, blit_i420_yuy2_3dnow }},
{ FOURCC_I420, FOURCC_RGB32,{ blit_i420_rgb32_mmx,blit_i420_rgb32_mmx2,blit_i420_rgb32_3dnow }},
{ FOURCC_I420, FOURCC_RGB24,{ blit_i420_rgb24_mmx,blit_i420_rgb24_mmx2,blit_i420_rgb24_3dnow }},
{ FOURCC_I420, FOURCC_BGR32,{ blit_i420_bgr32_mmx,blit_i420_bgr32_mmx2,blit_i420_bgr32_3dnow }},
{ FOURCC_I420, FOURCC_BGR24,{ blit_i420_bgr24_mmx,blit_i420_bgr24_mmx2,blit_i420_bgr24_3dnow }},
{ FOURCC_RGB32,FOURCC_RGB32,{ blit_rgb32_rgb32_mmx,blit_rgb32_rgb32_mmx2,blit_rgb32_rgb32_3dnow }},
{ FOURCC_RGB24,FOURCC_RGB24,{ blit_rgb24_rgb24_mmx,blit_rgb24_rgb24_mmx2,blit_rgb24_rgb24_3dnow }},
{ FOURCC_RGB16,FOURCC_RGB16,{ blit_rgb16_rgb16_mmx,blit_rgb16_rgb16_mmx2,blit_rgb16_rgb16_3dnow }},
{ FOURCC_RGB15,FOURCC_RGB15,{ blit_rgb16_rgb16_mmx,blit_rgb16_rgb16_mmx2,blit_rgb16_rgb16_3dnow }},
{ FOURCC_BGR32,FOURCC_BGR32,{ blit_rgb32_rgb32_mmx,blit_rgb32_rgb32_mmx2,blit_rgb32_rgb32_3dnow }},
{ FOURCC_BGR24,FOURCC_BGR24,{ blit_rgb24_rgb24_mmx,blit_rgb24_rgb24_mmx2,blit_rgb24_rgb24_3dnow }},
{ FOURCC_BGR16,FOURCC_BGR16,{ blit_rgb16_rgb16_mmx,blit_rgb16_rgb16_mmx2,blit_rgb16_rgb16_3dnow }},
{ FOURCC_BGR15,FOURCC_BGR15,{ blit_rgb16_rgb16_mmx,blit_rgb16_rgb16_mmx2,blit_rgb16_rgb16_3dnow }},
{0},
};
#endif
typedef struct blitpack
{
blitfx FX;
video Dst;
video Src;
rect DstRect;
rect SrcRect;
blit_soft Code[2];
bool_t SafeBorder;
int RScaleX;
int RScaleY;
struct blitpack* Next;
} blitpack;
static NOINLINE void FreeBlit(blit_soft* p)
{
CodeDone(&p->Code);
free(p->LookUp_Data);
p->LookUp_Data = NULL;
}
static INLINE struct blitpack* _BlitAlloc()
{
blitpack* p = (blitpack*) malloc(sizeof(blitpack));
if (!p) return NULL;
memset(p,0,sizeof(blitpack));
CodeInit(&p->Code[0].Code);
CodeInit(&p->Code[1].Code);
return p;
}
static INLINE void _BlitFree(struct blitpack* p)
{
FreeBlit(&p->Code[0]);
FreeBlit(&p->Code[1]);
free(p);
}
#ifdef CONFIG_CONTEXT
void Blit_Init()
{
}
void Blit_Done()
{
blitpack* p;
while ((p = Context()->Blit)!=NULL)
{
Context()->Blit = p->Next;
_BlitFree(p);
}
}
static INLINE void BlitFree(struct blitpack* p)
{
p->Next = Context()->Blit;
Context()->Blit = p;
}
static INLINE struct blitpack* BlitAlloc()
{
blitpack* p = Context()->Blit;
if (p)
Context()->Blit = p->Next;
else
p = _BlitAlloc();
return p;
}
#else
#define BlitAlloc _BlitAlloc
#define BlitFree _BlitFree
#endif
static const rgb* DefaultPal(const pixel* Format)
{
if (Format->Flags & PF_PALETTE)
{
if (!Format->Palette)
switch (Format->BitCount)
{
case 1: return (const rgb*)Gray1;
case 2: return (const rgb*)Gray2;
case 4: return (const rgb*)Gray4;
}
return Format->Palette;
}
return NULL;
}
static int CalcScale(int v, int Min, int Max)
{
if (v > Max) v = Max;
if (v < Min) v = Min;
return v;
}
static int CalcRScale(int v, int Gray)
{
if (v<=0) return 16;
v = (16*1024 << 16) / v;
if (Gray) // only 100% and 200% scale
return v > 12288 ? 16:8;
//align to 100%
if (v > 16834-1024 && v < 16384+1024)
v = 16384;
//align to 200%
if (v > 8192-1024 && v < 8192+1024)
v = 8192;
//align to 50%
if (v > 32768-2048 && v < 32768+2048)
v = 32768;
#if defined(SH3)
if (v < 12288)
return 8;
return 16;
// if (v<1024) v=1024;
// return ((v+1024) >> 11) << 1;
#else
if (v<512) v=512;
return (v+512) >> 10;
#endif
}
static NOINLINE bool_t EnlargeIfNeeded(int* v,int Align,int Side,int Limit)
{
int Needed = Align - (*v & (Align-1));
if (Needed < Align && Needed <= (Limit-Side))
{
*v += Needed;
return 1;
}
return 0;
}
void BlitAlign(blitpack* p, rect* DstRect, rect* SrcRect)
{
int i;
int ShrinkX,ShrinkY;
int SrcRight;
int SrcBottom;
int SrcAdjWidth,SrcAdjHeight;
int RScaleX,RScaleY;
blit_soft* Code;
if (!p) return;
RScaleX = p->RScaleX;
RScaleY = p->RScaleY;
Code = &p->Code[0];
p->SafeBorder = 0;
if (Code->ArithStretch && (RScaleX != 16) && (RScaleX != 32))
{
//avoid bilinear scale overrun (shrink source)
if ((p->Src.Pixel.Flags & PF_SAFEBORDER) && Code->DstAlignSize > 2)
p->SafeBorder = 1; // build a one pixel border before blitting on right and bottom side
else
{
//only horizontal bilinear filtering is supported (arm_stretch)
if (SrcRect->Width>2)
SrcRect->Width -= 2;
}
}
// convert source to destination space
if (p->FX.Direction & DIR_SWAPXY)
{
SwapInt(&RScaleX,&RScaleY);
SwapRect(SrcRect);
}
SrcRight = SrcRect->x + SrcRect->Width;
SrcBottom = SrcRect->y + SrcRect->Height;
SrcAdjWidth = SrcRect->Width * 16 / RScaleX;
SrcAdjHeight = SrcRect->Height * 16 / RScaleY;
if (p->FX.Flags & BLITFX_ENLARGEIFNEEDED)
{
SrcRight = p->Src.Width;
SrcBottom = p->Src.Height;
if (p->FX.Direction & DIR_SWAPXY)
SwapInt(&SrcRight,&SrcBottom);
if (p->Src.Pixel.Flags & PF_SAFEBORDER)
{
SrcRight += 16;
SrcBottom += 16;
}
if (EnlargeIfNeeded(&SrcAdjWidth,Code->DstAlignSize,SrcRect->x+SrcRect->Width,SrcRight))
SrcRect->Width = -1; // need calc
if (EnlargeIfNeeded(&SrcAdjHeight,Code->DstAlignSize,SrcRect->y+SrcRect->Height,SrcBottom))
SrcRect->Height = -1; // need calc
}
ShrinkX = DstRect->Width - SrcAdjWidth;
if (ShrinkX>=0) //shrink destination?
{
ShrinkX >>= 1;
DstRect->x += ShrinkX;
DstRect->Width = SrcAdjWidth;
}
else //adjust source position
{
ShrinkX = 0;
SrcRect->x += (SrcAdjWidth - DstRect->Width) * RScaleX >> 5;
SrcRect->Width = -1; // need calc
}
ShrinkY = DstRect->Height - SrcAdjHeight;
if (ShrinkY>=0) //shrink Dst?
{
ShrinkY >>= 1;
DstRect->y += ShrinkY;
DstRect->Height = SrcAdjHeight;
}
else //adjust source position
{
ShrinkY = 0;
SrcRect->y += (SrcAdjHeight - DstRect->Height) * RScaleY >> 5;
SrcRect->Height = -1; // need calc
}
i = DstRect->Width & (Code->DstAlignSize-1);
DstRect->Width -= i;
i >>= 1;
ShrinkX += i;
DstRect->x += i;
i = DstRect->Height & (Code->DstAlignSize-1);
DstRect->Height -= i;
i >>= 1;
ShrinkY += i;
DstRect->y += i;
i = DstRect->x & (Code->DstAlignPos-1);
if (i && ShrinkX < i)
{
DstRect->Width -= Code->DstAlignPos - i;
DstRect->Width &= ~(Code->DstAlignSize-1);
DstRect->x += Code->DstAlignPos - i;
}
else
DstRect->x -= i;
i = DstRect->y & (Code->DstAlignPos-1);
if (i && ShrinkY < i)
{
DstRect->Height -= Code->DstAlignPos - i;
DstRect->Height &= ~(Code->DstAlignSize-1);
DstRect->y += Code->DstAlignPos - i;
}
else
DstRect->y -= i;
SrcRect->x &= ~(Code->SrcAlignPos-1);
SrcRect->y &= ~(Code->SrcAlignPos-1);
// convert source back to it's space (if needed)
if (SrcRect->Width < 0)
SrcRect->Width = (DstRect->Width * RScaleX / 16 + 1) & ~1;
if (SrcRect->Height < 0)
SrcRect->Height = (DstRect->Height * RScaleY / 16 + 1) & ~1;
if (SrcRect->x + SrcRect->Width > SrcRight)
SrcRect->Width = SrcRight - SrcRect->x;
if (SrcRect->y + SrcRect->Height > SrcBottom)
SrcRect->Height = SrcBottom - SrcRect->y;
if (p->FX.Direction & DIR_SWAPXY)
SwapRect(SrcRect);
p->DstRect = *DstRect;
p->SrcRect = *SrcRect;
}
static NOINLINE void CodeRelease(blit_soft* p)
{
//todo... better palette handling
if (p->Dst.Palette)
memset(&p->Dst,0,sizeof(p->Dst));
if (p->Src.Palette)
memset(&p->Src,0,sizeof(p->Src));
}
void BlitRelease(blitpack* p)
{
if (p)
{
CodeRelease(&p->Code[0]);
CodeRelease(&p->Code[1]);
BlitFree(p);
}
}
int AnyAlign(rect* DstRect, rect* SrcRect, const blitfx* FX,
int DstAlignSize, int DstAlignPos,
int MinScale, int MaxScale)
{
int i,ShrinkX,ShrinkY;
int ScaleX,ScaleY;
int SrcRight;
int SrcBottom;
int SrcAdjWidth,SrcAdjHeight;
if (!DstRect || !SrcRect || !FX)
return ERR_INVALID_PARAM;
ScaleX = CalcScale(FX->ScaleX,MinScale,MaxScale);
ScaleY = CalcScale(FX->ScaleY,MinScale,MaxScale);
SrcRight = SrcRect->x + SrcRect->Width;
SrcBottom = SrcRect->y + SrcRect->Height;
// convert source to destination space
if (FX->Direction & DIR_SWAPXY)
{
SwapInt(&ScaleX,&ScaleY);
SwapRect(SrcRect);
}
SrcAdjWidth = (SrcRect->Width * ScaleX + 32768) >> 16;
SrcAdjHeight = (SrcRect->Height * ScaleY + 32768) >> 16;
ShrinkX = DstRect->Width - SrcAdjWidth;
if (ShrinkX>0) //shrink destination?
{
ShrinkX >>= 1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -