425 lines
11 KiB
C
Executable File
425 lines
11 KiB
C
Executable File
/*****************************************************************************
|
|
*
|
|
* 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: ge2d.c 543 2006-01-07 22:06:24Z picard $
|
|
*
|
|
* The Core Pocket Media Player
|
|
* Copyright (c) 2004-2005 Gabor Kovacs
|
|
*
|
|
* Big thanks to Mobile Stream (http://www.mobile-stream.com)
|
|
* for reverse enginerring the GE2D interface
|
|
*
|
|
****************************************************************************/
|
|
|
|
#include "../common/common.h"
|
|
|
|
#if defined(TARGET_PALMOS)
|
|
|
|
#include "../common/palmos/pace.h"
|
|
|
|
#if defined(_M_IX86)
|
|
//#define GE2DEMU
|
|
#endif
|
|
|
|
#define GE2D_ID FOURCC('G','E','2','D')
|
|
|
|
#define sonyGE2DLibType 'aexo'
|
|
#define sonyGE2DLibCreator 'SeGE'
|
|
|
|
enum {
|
|
sonyGE2DFormatYCbCr422 = 1,
|
|
sonyGE2DFormatYCbCr422Planar,
|
|
sonyGE2DFormatYCbCr420Planar
|
|
};
|
|
|
|
#define sonyGE2DBlitPixelCoord 0x2
|
|
|
|
typedef UInt32 GE2DInsnType;
|
|
|
|
typedef struct GE2DBitmapType
|
|
{
|
|
UInt8 format; /* 0x00 */
|
|
UInt8 zero; /* 0x01 */
|
|
UInt16 pitch; /* 0x02 */
|
|
UInt16 chromaPitch;/* 0x04 */
|
|
UInt16 width; /* 0x06 */
|
|
UInt16 height; /* 0x08 */
|
|
UInt16 unused; /* 0x0a */
|
|
void * plane1P; /* 0x0c: Y */
|
|
void * plane2P; /* 0x10: Cb */
|
|
void * plane3P; /* 0x14: Cr */
|
|
|
|
} GE2DBitmapType;
|
|
|
|
typedef struct GE2DLibAPIType
|
|
{
|
|
Err (*GE2DLibOpen)();
|
|
Err (*GE2DLibClose)();
|
|
Err (*GE2DProgramBlit)(GE2DInsnType *,
|
|
void *, UInt16,
|
|
const void *, UInt16,
|
|
UInt16, UInt16, UInt8);
|
|
Err (*GE2DBlitWithAlpha)(void *, UInt16,
|
|
const void *, UInt16,
|
|
UInt16, UInt16, UInt8);
|
|
Err (*GE2DBlit)(void *dstBitsP, UInt16 dstPitch,
|
|
const void *srcBitsP, UInt16 srcPitch,
|
|
UInt16 srcWidth, UInt16 srcHeight, UInt8 ff);
|
|
Err (*GE2DBlitWithMask)(void *dstBitsP, UInt16 dstPitch,
|
|
const void *srcBitsP, UInt16 srcPitch,
|
|
UInt16 srcWidth, UInt16 srcHeight,
|
|
UInt8 ff, const void *maskBitsP);
|
|
Err (*GE2DBlitBitmap)(void *dstP, Coord left, Coord top,
|
|
UInt16 dstWidth, UInt16 dstHeight, GE2DBitmapType *);
|
|
Err (*GE2DConvertBitmap)(GE2DBitmapType *, GE2DBitmapType *);
|
|
Err (*GE2DProgramBlitBitmapWithMask)(GE2DInsnType *programP,
|
|
void *dstP, Coord left, Coord top,
|
|
UInt16 dstWidth, UInt16 dstHeight,
|
|
GE2DBitmapType *bmpP, const void *p7);
|
|
Err (*GE2DProgramBlitBitmap)(GE2DInsnType *programP,
|
|
void *dstP, Coord left, Coord top,
|
|
UInt16 dstWidth, UInt16 dstHeight, GE2DBitmapType *bmpP);
|
|
Err (*GE2DScaleBitmap)(GE2DBitmapType *dstBmpP, GE2DBitmapType *srcBmpP);
|
|
Err (*GE2DShowOverlay)(Coord left, Coord top, GE2DBitmapType *);
|
|
Err (*GE2DHideOverlay)();
|
|
Err (*GE2DRunProgram)(const GE2DInsnType *programP);
|
|
Err (*GE2DRunProgram2)(const GE2DInsnType *programP);
|
|
Err (*GE2D_60)(UInt16 x, UInt16 y);
|
|
Err (*GE2D_64)();
|
|
Err (*GE2D_68)(void *);
|
|
Err (*GE2D_72)(RectangleType *);
|
|
Err (*GE2D_76)(FormType *);
|
|
Err (*GE2D_80)(Boolean);
|
|
Err (*GE2D_84)();
|
|
Err (*GE2DSetLock)(Boolean lock);
|
|
|
|
} GE2DLibAPIType;
|
|
|
|
typedef struct ge2d
|
|
{
|
|
overlay p;
|
|
point Offset;
|
|
GE2DBitmapType Buffer;
|
|
GE2DBitmapType Scale;
|
|
int BufferSize;
|
|
int ScaleSize;
|
|
rect OverlayRect;
|
|
blitfx SoftFX;
|
|
char* Bits;
|
|
|
|
} ge2d;
|
|
|
|
static UInt32 LibRef = 0;
|
|
|
|
#if defined(GE2DEMU)
|
|
#include "ge2demu.c"
|
|
#else
|
|
static GE2DLibAPIType API;
|
|
#endif
|
|
|
|
extern char* QueryScreen(video* Video,int* Offset,int* Mode);
|
|
|
|
static void FreeBuffer(GE2DBitmapType* p,int* Allocated)
|
|
{
|
|
free(p->plane1P);
|
|
free(p->plane2P);
|
|
free(p->plane3P);
|
|
memset(p,0,sizeof(GE2DBitmapType));
|
|
*Allocated = 0;
|
|
}
|
|
|
|
static bool_t AllocBuffer(GE2DBitmapType* p,int w,int h,int* Allocated)
|
|
{
|
|
int size;
|
|
w = (w+1) & ~1;
|
|
h = (h+1) & ~1;
|
|
size = w*h;
|
|
|
|
p->format = sonyGE2DFormatYCbCr420Planar;
|
|
p->zero = 0;
|
|
p->pitch = (UInt16)w;
|
|
p->chromaPitch = (UInt16)(w >> 1);
|
|
p->width = (UInt16)w;
|
|
p->height = (UInt16)h;
|
|
p->unused = 0;
|
|
|
|
if (*Allocated < size)
|
|
{
|
|
free(p->plane1P);
|
|
free(p->plane2P);
|
|
free(p->plane3P);
|
|
p->plane1P = malloc(size);
|
|
p->plane2P = malloc(size/4);
|
|
p->plane3P = malloc(size/4);
|
|
if (!p->plane1P || !p->plane2P || !p->plane3P)
|
|
{
|
|
FreeBuffer(p,Allocated);
|
|
return 0;
|
|
}
|
|
*Allocated = size;
|
|
}
|
|
|
|
memset(p->plane1P,0,size);
|
|
memset(p->plane2P,128,size/4);
|
|
memset(p->plane2P,128,size/4);
|
|
return 1;
|
|
}
|
|
|
|
static int GetMode(ge2d* p)
|
|
{
|
|
int Offset;
|
|
p->Bits = QueryScreen(&p->p.Output.Format.Video,&Offset,NULL);
|
|
|
|
if (!p->p.Output.Format.Video.Pitch || !p->p.Output.Format.Video.Pixel.BitCount)
|
|
return ERR_INVALID_PARAM;
|
|
|
|
p->Offset.x = (Offset % p->p.Output.Format.Video.Pitch) / (p->p.Output.Format.Video.Pixel.BitCount/8);
|
|
p->Offset.y = Offset / p->p.Output.Format.Video.Pitch;
|
|
|
|
return ERR_NONE;
|
|
}
|
|
|
|
static int Init(ge2d* p)
|
|
{
|
|
//p->p.SetFX = BLITFX_AVOIDTEARING;
|
|
p->p.Overlay = 0;
|
|
|
|
if (GetMode(p) != ERR_NONE)
|
|
return ERR_INVALID_PARAM;
|
|
|
|
if (!AllocBuffer(&p->Buffer,p->p.Input.Format.Video.Width,p->p.Input.Format.Video.Height,&p->BufferSize))
|
|
return ERR_OUT_OF_MEMORY;
|
|
|
|
return ERR_NONE;
|
|
}
|
|
|
|
static void Done(ge2d* p)
|
|
{
|
|
FreeBuffer(&p->Buffer,&p->BufferSize);
|
|
FreeBuffer(&p->Scale,&p->ScaleSize);
|
|
}
|
|
|
|
static int UpdateOverlay(ge2d* p)
|
|
{
|
|
if (p->p.Overlay)
|
|
{
|
|
if (p->p.Show)
|
|
{
|
|
int x = p->p.DstAlignedRect.x;
|
|
int y = p->p.DstAlignedRect.y;
|
|
|
|
x += p->Offset.x;
|
|
y += p->Offset.y;
|
|
|
|
PALMCALL3(API.GE2DShowOverlay,(Coord)x,(Coord)y,p->Scale.format? &p->Scale : &p->Buffer);
|
|
}
|
|
else
|
|
PALMCALL0(API.GE2DHideOverlay);
|
|
}
|
|
return ERR_NONE;
|
|
}
|
|
|
|
static int Update(ge2d* p)
|
|
{
|
|
blitfx OvlFX = p->p.FX;
|
|
video Buffer;
|
|
|
|
if (p->p.Overlay)
|
|
PALMCALL0(API.GE2DHideOverlay);
|
|
|
|
p->SoftFX = p->p.FX;
|
|
p->SoftFX.ScaleX = SCALE_ONE; // scale handled by hardware
|
|
p->SoftFX.ScaleY = SCALE_ONE;
|
|
OvlFX.Direction = 0;
|
|
|
|
//align to 100%
|
|
if (OvlFX.ScaleX > SCALE_ONE-(SCALE_ONE/16) && OvlFX.ScaleX < SCALE_ONE+(SCALE_ONE/16) &&
|
|
OvlFX.ScaleY > SCALE_ONE-(SCALE_ONE/16) && OvlFX.ScaleY < SCALE_ONE+(SCALE_ONE/16))
|
|
{
|
|
OvlFX.ScaleX = SCALE_ONE;
|
|
OvlFX.ScaleY = SCALE_ONE;
|
|
}
|
|
|
|
if (p->SoftFX.Direction & DIR_SWAPXY)
|
|
SwapInt(&OvlFX.ScaleX,&OvlFX.ScaleY);
|
|
|
|
memset(&Buffer,0,sizeof(Buffer));
|
|
Buffer.Pixel.Flags = PF_YUV420;
|
|
Buffer.Width = p->p.Input.Format.Video.Width;
|
|
Buffer.Height = p->p.Input.Format.Video.Height;
|
|
Buffer.Direction = CombineDir(p->p.InputDirection,p->p.OrigFX.Direction,p->p.Output.Format.Video.Direction);
|
|
if (Buffer.Direction & DIR_SWAPXY)
|
|
SwapInt(&Buffer.Width,&Buffer.Height);
|
|
Buffer.Pitch = Buffer.Width;
|
|
|
|
for (;;)
|
|
{
|
|
VirtToPhy(&p->p.Viewport,&p->p.DstAlignedRect,&p->p.Output.Format.Video);
|
|
VirtToPhy(NULL,&p->OverlayRect,&Buffer);
|
|
|
|
AnyAlign(&p->p.DstAlignedRect, &p->OverlayRect, &OvlFX, 2, 1, SCALE_ONE/256, SCALE_ONE*256);
|
|
|
|
if ((OvlFX.ScaleX != SCALE_ONE || OvlFX.ScaleY != SCALE_ONE) &&
|
|
(p->p.DstAlignedRect.Width != p->OverlayRect.Width && p->p.DstAlignedRect.Height != p->OverlayRect.Height))
|
|
{
|
|
if (!AllocBuffer(&p->Scale,p->p.DstAlignedRect.Width,p->p.DstAlignedRect.Height,&p->ScaleSize))
|
|
{
|
|
// fallback to 100%
|
|
OvlFX.ScaleX = SCALE_ONE;
|
|
OvlFX.ScaleY = SCALE_ONE;
|
|
continue;
|
|
}
|
|
}
|
|
else
|
|
FreeBuffer(&p->Scale,&p->ScaleSize);
|
|
break;
|
|
}
|
|
|
|
VirtToPhy(NULL,&p->p.SrcAlignedRect,&p->p.Input.Format.Video);
|
|
|
|
BlitRelease(p->p.Soft);
|
|
p->p.Soft = BlitCreate(&Buffer,&p->p.Input.Format.Video,&p->SoftFX,&p->p.Caps);
|
|
BlitAlign(p->p.Soft,&p->OverlayRect,&p->p.SrcAlignedRect);
|
|
|
|
if (!AllocBuffer(&p->Buffer,p->OverlayRect.Width,p->OverlayRect.Height,&p->BufferSize))
|
|
return ERR_OUT_OF_MEMORY;
|
|
|
|
Buffer.Width = p->OverlayRect.Width;
|
|
Buffer.Height = p->OverlayRect.Height;
|
|
Buffer.Pitch = Buffer.Width;
|
|
p->OverlayRect.x = 0;
|
|
p->OverlayRect.y = 0;
|
|
|
|
BlitRelease(p->p.Soft);
|
|
p->p.Soft = BlitCreate(&Buffer,&p->p.Input.Format.Video,&p->SoftFX,&p->p.Caps);
|
|
BlitAlign(p->p.Soft,&p->OverlayRect,&p->p.SrcAlignedRect);
|
|
|
|
if (!p->Scale.format) // no scaling -> adjust dst rectangle with soft yuv blitting alignement
|
|
{
|
|
p->p.DstAlignedRect.x += (p->p.DstAlignedRect.Width - p->OverlayRect.Width) >> 1;
|
|
p->p.DstAlignedRect.y += (p->p.DstAlignedRect.Height - p->OverlayRect.Height) >> 1;
|
|
p->p.DstAlignedRect.Width = p->OverlayRect.Width;
|
|
p->p.DstAlignedRect.Height = p->OverlayRect.Height;
|
|
}
|
|
PhyToVirt(&p->p.DstAlignedRect,&p->p.GUIAlignedRect,&p->p.Output.Format.Video);
|
|
|
|
return UpdateOverlay(p);
|
|
}
|
|
|
|
static INLINE void FlushDCache(void *p, int n)
|
|
{
|
|
SonyCleanDCache(p,n);
|
|
SonyInvalidateDCache(p,n);
|
|
}
|
|
|
|
static int Blit(ge2d* p, const constplanes Data, const constplanes DataLast )
|
|
{
|
|
int n;
|
|
planes Planes;
|
|
|
|
Planes[0] = p->Buffer.plane1P;
|
|
Planes[1] = p->Buffer.plane3P;
|
|
Planes[2] = p->Buffer.plane2P;
|
|
BlitImage(p->p.Soft,Planes,Data,DataLast,-1,-1);
|
|
|
|
n = p->Buffer.width * p->Buffer.height;
|
|
FlushDCache(Planes[0],n);
|
|
FlushDCache(Planes[1],n/4);
|
|
FlushDCache(Planes[2],n/4);
|
|
|
|
if (p->Scale.format)
|
|
PALMCALL2(API.GE2DScaleBitmap,&p->Scale,&p->Buffer);
|
|
|
|
if (!p->p.Overlay)
|
|
{
|
|
PALMCALL6(API.GE2DBlitBitmap,p->Bits,
|
|
(Coord)(p->p.DstAlignedRect.x + p->Offset.x),
|
|
(Coord)(p->p.DstAlignedRect.y + p->Offset.y),
|
|
(Coord)(p->p.Output.Format.Video.Pitch>>1),(Coord)p->p.Output.Format.Video.Height,
|
|
p->Scale.format? &p->Scale : &p->Buffer);
|
|
}
|
|
|
|
return ERR_NONE;
|
|
}
|
|
|
|
static int Reset(ge2d* p)
|
|
{
|
|
return GetMode(p);
|
|
}
|
|
|
|
static int Create(ge2d* p)
|
|
{
|
|
p->p.Init = (ovlfunc)Init;
|
|
p->p.Done = (ovldone)Done;
|
|
p->p.Reset = (ovlfunc)Reset;
|
|
p->p.Blit = (ovlblit)Blit;
|
|
p->p.Update = (ovlfunc)Update;
|
|
p->p.UpdateShow = (ovlfunc)UpdateOverlay;
|
|
|
|
QueryDesktop(&p->p.Output.Format.Video);
|
|
return ERR_NONE;
|
|
}
|
|
|
|
static const nodedef GE2D =
|
|
{
|
|
sizeof(ge2d)|CF_GLOBAL,
|
|
GE2D_ID,
|
|
OVERLAY_CLASS,
|
|
PRI_DEFAULT+50,
|
|
(nodecreate)Create,
|
|
};
|
|
|
|
void GE2D_Init()
|
|
{
|
|
#if !defined(GE2DEMU)
|
|
Err err;
|
|
|
|
// UInt32 CompanyID;
|
|
// FtrGet(sysFtrCreator, sysFtrNumOEMCompanyID, &CompanyID);
|
|
// if (CompanyID != 'sony')
|
|
// return;
|
|
|
|
err = SysFindModule(sonyGE2DLibType, sonyGE2DLibCreator, 0, 0, &LibRef);
|
|
if (err)
|
|
err = SysLoadModule(sonyGE2DLibType, sonyGE2DLibCreator, 0, 0, &LibRef);
|
|
if (err)
|
|
return;
|
|
|
|
if (SysGetEntryAddresses(LibRef, 0, 22, (void **)(void *)&API) != errNone)
|
|
return;
|
|
|
|
#endif
|
|
|
|
PALMCALL0(API.GE2DLibOpen);
|
|
NodeRegisterClass(&GE2D);
|
|
}
|
|
|
|
void GE2D_Done()
|
|
{
|
|
NodeUnRegisterClass(GE2D_ID);
|
|
if (LibRef)
|
|
{
|
|
PALMCALL0(API.GE2DLibClose);
|
|
//SysUnloadModule(LibRef);
|
|
LibRef = 0;
|
|
}
|
|
}
|
|
|
|
#else
|
|
void GE2D_Init() {}
|
|
void GE2D_Done() {}
|
|
#endif
|