add USB/SD hot-swap, video changes, remove un-needed VBA file

This commit is contained in:
dborth 2008-10-28 06:51:58 +00:00
parent 1d17d3f185
commit a68f67903d
4 changed files with 98 additions and 655 deletions

View File

@ -28,75 +28,84 @@
FILE * fatfile; FILE * fatfile;
/**************************************************************************** /****************************************************************************
* fat_is_mounted * MountFAT
* to check whether FAT media are detected. * Attempts to mount the FAT device specified
* Sets libfat to use the device by default
* Enables read-ahead cache for SD/USB
***************************************************************************/ ***************************************************************************/
bool MountFAT(PARTITION_INTERFACE part)
{
bool mounted = fatMountNormalInterface(part, 8);
bool FatIsMounted(PARTITION_INTERFACE partition) { if(mounted)
char prefix[] = "fatX:/"; {
prefix[3] = partition + '0'; fatSetDefaultInterface(part);
DIR_ITER *dir = diropen(prefix); #ifdef HW_RVL
if (dir) { if(part == PI_INTERNAL_SD || part == PI_USBSTORAGE)
dirclose(dir); fatEnableReadAhead (part, 6, 64);
return true; #endif
} }
return false; return mounted;
} }
/**************************************************************************** /****************************************************************************
* changeFATInterface * UnmountFAT
* Checks if the device (method) specified is available, and * Unmounts the FAT device specified
* sets libfat to use the device ***************************************************************************/
void UnmountFAT(PARTITION_INTERFACE part)
{
if(!fatUnmount(part))
fatUnsafeUnmount(part);
}
/****************************************************************************
* UnmountAllFAT
* Unmounts all FAT devices
***************************************************************************/
void UnmountAllFAT()
{
#ifdef HW_RVL
UnmountFAT(PI_INTERNAL_SD);
UnmountFAT(PI_USBSTORAGE);
#endif
UnmountFAT(PI_SDGECKO_A);
UnmountFAT(PI_SDGECKO_B);
}
/****************************************************************************
* ChangeFATInterface
* Unmounts all devices and attempts to mount/configure the device specified
***************************************************************************/ ***************************************************************************/
bool ChangeFATInterface(int method, bool silent) bool ChangeFATInterface(int method, bool silent)
{ {
bool devFound = false; bool mounted = false;
// unmount all FAT devices
UnmountAllFAT();
if(method == METHOD_SD) if(method == METHOD_SD)
{ {
// check which SD device is loaded
#ifdef HW_RVL #ifdef HW_RVL
if (FatIsMounted(PI_INTERNAL_SD)) mounted = MountFAT(PI_INTERNAL_SD); // try Wii internal SD
{
devFound = true;
fatSetDefaultInterface(PI_INTERNAL_SD);
fatEnableReadAhead (PI_INTERNAL_SD, 6, 64);
}
#endif #endif
if (!devFound && FatIsMounted(PI_SDGECKO_A)) if(!mounted) // internal SD not found
{ mounted = MountFAT(PI_SDGECKO_A); // try SD Gecko on slot A
devFound = true; if(!mounted) // internal SD and SD Gecko (on slot A) not found
} mounted = MountFAT(PI_SDGECKO_B); // try SD Gecko on slot B
if(!devFound && FatIsMounted(PI_SDGECKO_B)) if(!mounted && !silent) // no SD device found
{ WaitPrompt ((char *)"SD card not found!");
devFound = true;
}
if(!devFound)
{
if(!silent)
WaitPrompt ((char *)"SD card not found!");
}
} }
else if(method == METHOD_USB) else if(method == METHOD_USB)
{ {
#ifdef HW_RVL #ifdef HW_RVL
if(FatIsMounted(PI_USBSTORAGE)) mounted = MountFAT(PI_USBSTORAGE);
{ if(!mounted && !silent)
devFound = true; WaitPrompt ((char *)"USB drive not found!");
fatSetDefaultInterface(PI_USBSTORAGE);
fatEnableReadAhead (PI_USBSTORAGE, 6, 64);
}
else
{
if(!silent)
WaitPrompt ((char *)"USB flash drive not found!");
}
#endif #endif
} }
return devFound; return mounted;
} }
/*************************************************************************** /***************************************************************************

View File

@ -373,7 +373,7 @@ int FileSelector (int method)
if (!maxfiles) if (!maxfiles)
{ {
WaitPrompt ((char*) "Error reading directory !"); WaitPrompt ((char*) "Error reading directory!");
haverom = 1; // quit menu haverom = 1; // quit menu
} }
} }
@ -384,6 +384,11 @@ int FileSelector (int method)
} }
else // this is a file else // this is a file
{ {
// better do another unmount/remount, just in case
if(method == METHOD_SD || method == METHOD_USB)
if(!ChangeFATInterface(method, NOTSILENT))
return 0;
// 7z file - let's open it up to select a file inside // 7z file - let's open it up to select a file inside
if(IsSz()) if(IsSz())
{ {
@ -391,7 +396,7 @@ int FileSelector (int method)
if(!MakeROMPath(szpath, method)) if(!MakeROMPath(szpath, method))
{ {
WaitPrompt((char*) "Maximum filepath length reached!"); WaitPrompt((char*) "Maximum filepath length reached!");
return -1; return 0;
} }
int szfiles = SzParse(szpath, method); int szfiles = SzParse(szpath, method);
if(szfiles) if(szfiles)

View File

@ -184,10 +184,14 @@ static void draw_init(void)
GX_SetTexCoordGen (GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_IDENTITY); GX_SetTexCoordGen (GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_IDENTITY);
GX_InvalidateTexAll(); GX_SetTevOp (GX_TEVSTAGE0, GX_REPLACE);
GX_SetTevOrder (GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLORNULL);
memset (&view, 0, sizeof (Mtx)); memset (&view, 0, sizeof (Mtx));
guLookAt(view, &cam.pos, &cam.up, &cam.view); guLookAt(view, &cam.pos, &cam.up, &cam.view);
GX_LoadPosMtxImm (view, GX_PNMTX0); GX_LoadPosMtxImm (view, GX_PNMTX0);
GX_InvVtxCache (); // update vertex cache
} }
static void draw_vert(u8 pos, u8 c, f32 s, f32 t) static void draw_vert(u8 pos, u8 c, f32 s, f32 t)
@ -251,9 +255,6 @@ void GX_Start()
guPerspective(p, 60, 1.33F, 10.0F, 1000.0F); guPerspective(p, 60, 1.33F, 10.0F, 1000.0F);
GX_LoadProjectionMtx(p, GX_PERSPECTIVE); GX_LoadProjectionMtx(p, GX_PERSPECTIVE);
GX_SetTevOp(GX_TEVSTAGE0, GX_DECAL);
GX_SetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR0A0);
GX_CopyDisp (xfb[whichfb], GX_TRUE); // reset xfb GX_CopyDisp (xfb[whichfb], GX_TRUE); // reset xfb
} }
@ -327,6 +328,9 @@ void InitialiseVideo ()
xfb[0] = (u32 *) MEM_K0_TO_K1 (SYS_AllocateFramebuffer (vmode)); xfb[0] = (u32 *) MEM_K0_TO_K1 (SYS_AllocateFramebuffer (vmode));
xfb[1] = (u32 *) MEM_K0_TO_K1 (SYS_AllocateFramebuffer (vmode)); xfb[1] = (u32 *) MEM_K0_TO_K1 (SYS_AllocateFramebuffer (vmode));
// A console is always useful while debugging
console_init (xfb[0], 20, 64, vmode->fbWidth, vmode->xfbHeight, vmode->fbWidth * 2);
// Clear framebuffers etc. // Clear framebuffers etc.
VIDEO_ClearFrameBuffer (vmode, xfb[0], COLOR_BLACK); VIDEO_ClearFrameBuffer (vmode, xfb[0], COLOR_BLACK);
VIDEO_ClearFrameBuffer (vmode, xfb[1], COLOR_BLACK); VIDEO_ClearFrameBuffer (vmode, xfb[1], COLOR_BLACK);
@ -370,21 +374,15 @@ void UpdateScaling()
yscale *= GCSettings.ZoomLevel; yscale *= GCSettings.ZoomLevel;
// Set new aspect (now with crap AR hack!) // Set new aspect (now with crap AR hack!)
square[0] = square[9] = (-xscale - 7); square[0] = square[9] = (-xscale - 7);
square[3] = square[6] = (xscale + 7); square[3] = square[6] = ( xscale + 7);
square[1] = square[4] = (yscale + 7); square[1] = square[4] = ( yscale + 7);
square[7] = square[10] = (-yscale - 7); square[7] = square[10] = (-yscale - 7);
GX_InvVtxCache (); // update vertex cache draw_init ();
GX_InitTexObj (&texobj, texturemem, vwidth, vheight, GX_TF_RGB565, GX_CLAMP, GX_CLAMP, GX_FALSE); // initialize the texture obj we are going to use if(updateScaling)
updateScaling--;
if (GCSettings.render == 1)
GX_InitTexObjLOD(&texobj,GX_NEAR,GX_NEAR_MIP_NEAR,2.5,9.0,0.0,GX_FALSE,GX_FALSE,GX_ANISO_1); // original/unfiltered video mode: force texture filtering OFF
GX_LoadTexObj (&texobj, GX_TEXMAP0); // load texture object so its ready to use
updateScaling--;
} }
/**************************************************************************** /****************************************************************************
@ -400,6 +398,7 @@ ResetVideo_Emu ()
rmode = vmode; // same mode as menu rmode = vmode; // same mode as menu
// reconfigure VI
VIDEO_Configure (rmode); VIDEO_Configure (rmode);
VIDEO_ClearFrameBuffer (vmode, xfb[whichfb], COLOR_BLACK); VIDEO_ClearFrameBuffer (vmode, xfb[whichfb], COLOR_BLACK);
VIDEO_Flush(); VIDEO_Flush();
@ -410,21 +409,27 @@ ResetVideo_Emu ()
while (VIDEO_GetNextField()) while (VIDEO_GetNextField())
VIDEO_WaitVSync(); VIDEO_WaitVSync();
// reconfigure GX
GX_SetViewport (0, 0, rmode->fbWidth, rmode->efbHeight, 0, 1); GX_SetViewport (0, 0, rmode->fbWidth, rmode->efbHeight, 0, 1);
GX_SetDispCopyYScale ((f32) rmode->xfbHeight / (f32) rmode->efbHeight); GX_SetDispCopyYScale ((f32) rmode->xfbHeight / (f32) rmode->efbHeight);
GX_SetScissor (0, 0, rmode->fbWidth, rmode->efbHeight); GX_SetScissor (0, 0, rmode->fbWidth, rmode->efbHeight);
GX_SetDispCopySrc (0, 0, rmode->fbWidth, rmode->efbHeight); GX_SetDispCopySrc (0, 0, rmode->fbWidth, rmode->efbHeight);
GX_SetDispCopyDst (rmode->fbWidth, rmode->xfbHeight); GX_SetDispCopyDst (rmode->fbWidth, rmode->xfbHeight);
GX_SetCopyFilter (rmode->aa, rmode->sample_pattern, (GCSettings.render == 0) ? GX_TRUE : GX_FALSE, rmode->vfilter); // AA on only for filtered mode GX_SetCopyFilter (rmode->aa, rmode->sample_pattern, (GCSettings.render == 1) ? GX_TRUE : GX_FALSE, rmode->vfilter); // deflickering filter only for filtered mode
GX_SetFieldMode (rmode->field_rendering, ((rmode->viHeight == 2 * rmode->xfbHeight) ? GX_ENABLE : GX_DISABLE)); GX_SetFieldMode (rmode->field_rendering, ((rmode->viHeight == 2 * rmode->xfbHeight) ? GX_ENABLE : GX_DISABLE));
GX_SetPixelFmt (GX_PF_RGB8_Z24, GX_ZC_LINEAR); GX_SetPixelFmt (GX_PF_RGB8_Z24, GX_ZC_LINEAR);
guPerspective(p, 60, 1.33F, 10.0F, 1000.0F); guPerspective(p, 60, 1.33F, 10.0F, 1000.0F);
GX_LoadProjectionMtx(p, GX_PERSPECTIVE); GX_LoadProjectionMtx(p, GX_PERSPECTIVE);
updateScaling = 20; // reinitialize texture
GX_InvalidateTexAll ();
GX_InitTexObj (&texobj, texturemem, vwidth, vheight, GX_TF_RGB565, GX_CLAMP, GX_CLAMP, GX_FALSE); // initialize the texture obj we are going to use
if (!(GCSettings.render&1))
GX_InitTexObjLOD(&texobj,GX_NEAR,GX_NEAR_MIP_NEAR,2.5,9.0,0.0,GX_FALSE,GX_FALSE,GX_ANISO_1); // original/unfiltered video mode: force texture filtering OFF
// set aspect ratio
updateScaling = 5;
} }
/**************************************************************************** /****************************************************************************
@ -511,6 +516,9 @@ void GX_Render(int width, int height, u8 * buffer, int pitch)
if(updateScaling) if(updateScaling)
UpdateScaling(); UpdateScaling();
// clear texture objects
GX_InvalidateTexAll();
for (h = 0; h < vheight; h += 4) for (h = 0; h < vheight; h += 4)
{ {
for (w = 0; w < (vwidth >> 2); w++) for (w = 0; w < (vwidth >> 2); w++)
@ -539,13 +547,15 @@ void GX_Render(int width, int height, u8 * buffer, int pitch)
} }
} }
// load texture into GX
DCFlushRange(texturemem, texturesize); DCFlushRange(texturemem, texturesize);
GX_InvalidateTexAll (); GX_LoadTexObj (&texobj, GX_TEXMAP0);
// render textured quad
draw_square(view); draw_square(view);
GX_DrawDone(); GX_DrawDone();
// EFB is ready to be copied into XFB
VIDEO_SetNextFramebuffer(xfb[whichfb]); VIDEO_SetNextFramebuffer(xfb[whichfb]);
VIDEO_Flush(); VIDEO_Flush();
copynow = GX_TRUE; copynow = GX_TRUE;
@ -570,12 +580,12 @@ zoom (float speed)
else if (GCSettings.ZoomLevel > 2.0) else if (GCSettings.ZoomLevel > 2.0)
GCSettings.ZoomLevel = 2.0; GCSettings.ZoomLevel = 2.0;
updateScaling = 60; // update video updateScaling = 5; // update video
} }
void void
zoom_reset () zoom_reset ()
{ {
GCSettings.ZoomLevel = 1.0; GCSettings.ZoomLevel = 1.0;
updateScaling = 60; // update video updateScaling = 5; // update video
} }

View File

@ -1,581 +0,0 @@
// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator.
// Copyright (C) 1999-2003 Forgotten
// Copyright (C) 2004 Forgotten and the VBA development team
// 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, 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.
#include "System.h"
#include <stdlib.h>
#include <string.h>
#ifdef MMX
extern "C" bool cpu_mmx;
#endif
/*
* Thanks to Kawaks' Mr. K for the code
Incorporated into vba by Anthony Di Franco
*/
static u8 *frm1 = NULL;
static u8 *frm2 = NULL;
static u8 *frm3 = NULL;
extern int RGB_LOW_BITS_MASK;
extern u32 qRGB_COLOR_MASK[2];
static void Init()
{
frm1 = (u8 *)calloc(322*242,4);
// 1 frame ago
frm2 = (u8 *)calloc(322*242,4);
// 2 frames ago
frm3 = (u8 *)calloc(322*242,4);
// 3 frames ago
}
void InterframeCleanup()
{
if(frm1)
free(frm1);
if(frm2)
free(frm2);
if(frm3)
free(frm3);
frm1 = frm2 = frm3 = NULL;
}
#ifdef MMX
static void SmartIB_MMX(u8 *srcPtr, u32 srcPitch, int width, int height)
{
u16 *src0 = (u16 *)srcPtr;
u16 *src1 = (u16 *)frm1;
u16 *src2 = (u16 *)frm2;
u16 *src3 = (u16 *)frm3;
int count = width >> 2;
for(int i = 0; i < height; i++) {
#ifdef __GNUC__
asm volatile (
"push %4\n"
"movq 0(%5), %%mm7\n" // colorMask
"0:\n"
"movq 0(%0), %%mm0\n" // src0
"movq 0(%1), %%mm1\n" // src1
"movq 0(%2), %%mm2\n" // src2
"movq 0(%3), %%mm3\n" // src3
"movq %%mm0, 0(%3)\n" // src3 = src0
"movq %%mm0, %%mm4\n"
"movq %%mm1, %%mm5\n"
"pcmpeqw %%mm2, %%mm5\n" // src1 == src2 (A)
"pcmpeqw %%mm3, %%mm4\n" // src3 == src0 (B)
"por %%mm5, %%mm4\n" // A | B
"movq %%mm2, %%mm5\n"
"pcmpeqw %%mm0, %%mm5\n" // src0 == src2 (C)
"pcmpeqw %%mm1, %%mm3\n" // src1 == src3 (D)
"por %%mm3, %%mm5\n" // C|D
"pandn %%mm5, %%mm4\n" // (!(A|B))&(C|D)
"movq %%mm0, %%mm2\n"
"pand %%mm7, %%mm2\n" // color & colorMask
"pand %%mm7, %%mm1\n" // src1 & colorMask
"psrlw $1, %%mm2\n" // (color & colorMask) >> 1 (E)
"psrlw $1, %%mm1\n" // (src & colorMask) >> 1 (F)
"paddw %%mm2, %%mm1\n" // E+F
"pand %%mm4, %%mm1\n" // (E+F) & res
"pandn %%mm0, %%mm4\n" // color& !res
"por %%mm1, %%mm4\n"
"movq %%mm4, 0(%0)\n" // src0 = res
"addl $8, %0\n"
"addl $8, %1\n"
"addl $8, %2\n"
"addl $8, %3\n"
"decl %4\n"
"jnz 0b\n"
"pop %4\n"
"emms\n"
: "+r" (src0), "+r" (src1), "+r" (src2), "+r" (src3)
: "r" (count), "r" (qRGB_COLOR_MASK)
);
#else
__asm {
movq mm7, qword ptr [qRGB_COLOR_MASK];
mov eax, src0;
mov ebx, src1;
mov ecx, src2;
mov edx, src3;
mov edi, count;
label0:
movq mm0, qword ptr [eax]; // src0
movq mm1, qword ptr [ebx]; // src1
movq mm2, qword ptr [ecx]; // src2
movq mm3, qword ptr [edx]; // src3
movq qword ptr [edx], mm0; // src3 = src0
movq mm4, mm0;
movq mm5, mm1;
pcmpeqw mm5, mm2; // src1 == src2 (A)
pcmpeqw mm4, mm3; // src3 == src0 (B)
por mm4, mm5; // A | B
movq mm5, mm2;
pcmpeqw mm5, mm0; // src0 == src2 (C)
pcmpeqw mm3, mm1; // src1 == src3 (D)
por mm5, mm3; // C|D
pandn mm4, mm5; // (!(A|B))&(C|D)
movq mm2, mm0;
pand mm2, mm7; // color & colorMask
pand mm1, mm7; // src1 & colorMask
psrlw mm2, 1; // (color & colorMask) >> 1 (E)
psrlw mm1, 1; // (src & colorMask) >> 1 (F)
paddw mm1, mm2; // E+F
pand mm1, mm4; // (E+F) & res
pandn mm4, mm0; // color & !res
por mm4, mm1;
movq qword ptr [eax], mm4; // src0 = res
add eax, 8;
add ebx, 8;
add ecx, 8;
add edx, 8;
dec edi;
jnz label0;
mov src0, eax;
mov src1, ebx;
mov src2, ecx;
mov src3, edx;
emms;
}
#endif
src0+=2;
src1+=2;
src2+=2;
src3+=2;
}
/* Swap buffers around */
u8 *temp = frm1;
frm1 = frm3;
frm3 = frm2;
frm2 = temp;
}
#endif
void SmartIB(u8 *srcPtr, u32 srcPitch, int width, int height)
{
if(frm1 == NULL) {
Init();
}
#ifdef MMX
if(cpu_mmx) {
SmartIB_MMX(srcPtr, srcPitch, width, height);
return;
}
#endif
u16 colorMask = ~RGB_LOW_BITS_MASK;
u16 *src0 = (u16 *)srcPtr;
u16 *src1 = (u16 *)frm1;
u16 *src2 = (u16 *)frm2;
u16 *src3 = (u16 *)frm3;
int sPitch = srcPitch >> 1;
int pos = 0;
for (int j = 0; j < height; j++)
for (int i = 0; i < sPitch; i++) {
u16 color = src0[pos];
src0[pos] =
(src1[pos] != src2[pos]) &&
(src3[pos] != color) &&
((color == src2[pos]) || (src1[pos] == src3[pos]))
? (((color & colorMask) >> 1) + ((src1[pos] & colorMask) >> 1)) :
color;
src3[pos] = color; /* oldest buffer now holds newest frame */
pos++;
}
/* Swap buffers around */
u8 *temp = frm1;
frm1 = frm3;
frm3 = frm2;
frm2 = temp;
}
#ifdef MMX
static void SmartIB32_MMX(u8 *srcPtr, u32 srcPitch, int width, int height)
{
u32 *src0 = (u32 *)srcPtr;
u32 *src1 = (u32 *)frm1;
u32 *src2 = (u32 *)frm2;
u32 *src3 = (u32 *)frm3;
int count = width >> 1;
for(int i = 0; i < height; i++) {
#ifdef __GNUC__
asm volatile (
"push %4\n"
"movq 0(%5), %%mm7\n" // colorMask
"0:\n"
"movq 0(%0), %%mm0\n" // src0
"movq 0(%1), %%mm1\n" // src1
"movq 0(%2), %%mm2\n" // src2
"movq 0(%3), %%mm3\n" // src3
"movq %%mm0, 0(%3)\n" // src3 = src0
"movq %%mm0, %%mm4\n"
"movq %%mm1, %%mm5\n"
"pcmpeqd %%mm2, %%mm5\n" // src1 == src2 (A)
"pcmpeqd %%mm3, %%mm4\n" // src3 == src0 (B)
"por %%mm5, %%mm4\n" // A | B
"movq %%mm2, %%mm5\n"
"pcmpeqd %%mm0, %%mm5\n" // src0 == src2 (C)
"pcmpeqd %%mm1, %%mm3\n" // src1 == src3 (D)
"por %%mm3, %%mm5\n" // C|D
"pandn %%mm5, %%mm4\n" // (!(A|B))&(C|D)
"movq %%mm0, %%mm2\n"
"pand %%mm7, %%mm2\n" // color & colorMask
"pand %%mm7, %%mm1\n" // src1 & colorMask
"psrld $1, %%mm2\n" // (color & colorMask) >> 1 (E)
"psrld $1, %%mm1\n" // (src & colorMask) >> 1 (F)
"paddd %%mm2, %%mm1\n" // E+F
"pand %%mm4, %%mm1\n" // (E+F) & res
"pandn %%mm0, %%mm4\n" // color& !res
"por %%mm1, %%mm4\n"
"movq %%mm4, 0(%0)\n" // src0 = res
"addl $8, %0\n"
"addl $8, %1\n"
"addl $8, %2\n"
"addl $8, %3\n"
"decl %4\n"
"jnz 0b\n"
"pop %4\n"
"emms\n"
: "+r" (src0), "+r" (src1), "+r" (src2), "+r" (src3)
: "r" (count), "r" (qRGB_COLOR_MASK)
);
#else
__asm {
movq mm7, qword ptr [qRGB_COLOR_MASK];
mov eax, src0;
mov ebx, src1;
mov ecx, src2;
mov edx, src3;
mov edi, count;
label0:
movq mm0, qword ptr [eax]; // src0
movq mm1, qword ptr [ebx]; // src1
movq mm2, qword ptr [ecx]; // src2
movq mm3, qword ptr [edx]; // src3
movq qword ptr [edx], mm0; // src3 = src0
movq mm4, mm0;
movq mm5, mm1;
pcmpeqd mm5, mm2; // src1 == src2 (A)
pcmpeqd mm4, mm3; // src3 == src0 (B)
por mm4, mm5; // A | B
movq mm5, mm2;
pcmpeqd mm5, mm0; // src0 == src2 (C)
pcmpeqd mm3, mm1; // src1 == src3 (D)
por mm5, mm3; // C|D
pandn mm4, mm5; // (!(A|B))&(C|D)
movq mm2, mm0;
pand mm2, mm7; // color & colorMask
pand mm1, mm7; // src1 & colorMask
psrld mm2, 1; // (color & colorMask) >> 1 (E)
psrld mm1, 1; // (src & colorMask) >> 1 (F)
paddd mm1, mm2; // E+F
pand mm1, mm4; // (E+F) & res
pandn mm4, mm0; // color & !res
por mm4, mm1;
movq qword ptr [eax], mm4; // src0 = res
add eax, 8;
add ebx, 8;
add ecx, 8;
add edx, 8;
dec edi;
jnz label0;
mov src0, eax;
mov src1, ebx;
mov src2, ecx;
mov src3, edx;
emms;
}
#endif
src0++;
src1++;
src2++;
src3++;
}
/* Swap buffers around */
u8 *temp = frm1;
frm1 = frm3;
frm3 = frm2;
frm2 = temp;
}
#endif
void SmartIB32(u8 *srcPtr, u32 srcPitch, int width, int height)
{
if(frm1 == NULL) {
Init();
}
#ifdef MMX
if(cpu_mmx) {
SmartIB32_MMX(srcPtr, srcPitch, width, height);
return;
}
#endif
u32 *src0 = (u32 *)srcPtr;
u32 *src1 = (u32 *)frm1;
u32 *src2 = (u32 *)frm2;
u32 *src3 = (u32 *)frm3;
u32 colorMask = 0xfefefe;
int sPitch = srcPitch >> 2;
int pos = 0;
for (int j = 0; j < height; j++)
for (int i = 0; i < sPitch; i++) {
u32 color = src0[pos];
src0[pos] =
(src1[pos] != src2[pos]) &&
(src3[pos] != color) &&
((color == src2[pos]) || (src1[pos] == src3[pos]))
? (((color & colorMask) >> 1) + ((src1[pos] & colorMask) >> 1)) :
color;
src3[pos] = color; /* oldest buffer now holds newest frame */
pos++;
}
/* Swap buffers around */
u8 *temp = frm1;
frm1 = frm3;
frm3 = frm2;
frm2 = temp;
}
#ifdef MMX
static void MotionBlurIB_MMX(u8 *srcPtr, u32 srcPitch, int width, int height)
{
u16 *src0 = (u16 *)srcPtr;
u16 *src1 = (u16 *)frm1;
int count = width >> 2;
for(int i = 0; i < height; i++) {
#ifdef __GNUC__
asm volatile (
"push %2\n"
"movq 0(%3), %%mm7\n" // colorMask
"0:\n"
"movq 0(%0), %%mm0\n" // src0
"movq 0(%1), %%mm1\n" // src1
"movq %%mm0, 0(%1)\n" // src1 = src0
"pand %%mm7, %%mm0\n" // color & colorMask
"pand %%mm7, %%mm1\n" // src1 & colorMask
"psrlw $1, %%mm0\n" // (color & colorMask) >> 1 (E)
"psrlw $1, %%mm1\n" // (src & colorMask) >> 1 (F)
"paddw %%mm1, %%mm0\n" // E+F
"movq %%mm0, 0(%0)\n" // src0 = res
"addl $8, %0\n"
"addl $8, %1\n"
"decl %2\n"
"jnz 0b\n"
"pop %2\n"
"emms\n"
: "+r" (src0), "+r" (src1)
: "r" (count), "r" (qRGB_COLOR_MASK)
);
#else
__asm {
movq mm7, qword ptr [qRGB_COLOR_MASK];
mov eax, src0;
mov ebx, src1;
mov edi, count;
label0:
movq mm0, qword ptr [eax]; // src0
movq mm1, qword ptr [ebx]; // src1
movq qword ptr [ebx], mm0; // src1 = src0
pand mm0, mm7; // color & colorMask
pand mm1, mm7; // src1 & colorMask
psrlw mm0, 1; // (color & colorMask) >> 1 (E)
psrlw mm1, 1; // (src & colorMask) >> 1 (F)
paddw mm0, mm1; // E+F
movq qword ptr [eax], mm0; // src0 = res
add eax, 8;
add ebx, 8;
dec edi;
jnz label0;
mov src0, eax;
mov src1, ebx;
emms;
}
#endif
src0+=2;
src1+=2;
}
}
#endif
void MotionBlurIB(u8 *srcPtr, u32 srcPitch, int width, int height)
{
if(frm1 == NULL) {
Init();
}
#ifdef MMX
if(cpu_mmx) {
MotionBlurIB_MMX(srcPtr, srcPitch, width, height);
return;
}
#endif
u16 colorMask = ~RGB_LOW_BITS_MASK;
u16 *src0 = (u16 *)srcPtr;
u16 *src1 = (u16 *)frm1;
int sPitch = srcPitch >> 1;
int pos = 0;
for (int j = 0; j < height; j++)
for (int i = 0; i < sPitch; i++) {
u16 color = src0[pos];
src0[pos] =
(((color & colorMask) >> 1) + ((src1[pos] & colorMask) >> 1));
src1[pos] = color;
pos++;
}
}
#ifdef MMX
static void MotionBlurIB32_MMX(u8 *srcPtr, u32 srcPitch, int width, int height)
{
u32 *src0 = (u32 *)srcPtr;
u32 *src1 = (u32 *)frm1;
int count = width >> 1;
for(int i = 0; i < height; i++) {
#ifdef __GNUC__
asm volatile (
"push %2\n"
"movq 0(%3), %%mm7\n" // colorMask
"0:\n"
"movq 0(%0), %%mm0\n" // src0
"movq 0(%1), %%mm1\n" // src1
"movq %%mm0, 0(%1)\n" // src1 = src0
"pand %%mm7, %%mm0\n" // color & colorMask
"pand %%mm7, %%mm1\n" // src1 & colorMask
"psrld $1, %%mm0\n" // (color & colorMask) >> 1 (E)
"psrld $1, %%mm1\n" // (src & colorMask) >> 1 (F)
"paddd %%mm1, %%mm0\n" // E+F
"movq %%mm0, 0(%0)\n" // src0 = res
"addl $8, %0\n"
"addl $8, %1\n"
"decl %2\n"
"jnz 0b\n"
"pop %2\n"
"emms\n"
: "+r" (src0), "+r" (src1)
: "r" (count), "r" (qRGB_COLOR_MASK)
);
#else
__asm {
movq mm7, qword ptr [qRGB_COLOR_MASK];
mov eax, src0;
mov ebx, src1;
mov edi, count;
label0:
movq mm0, qword ptr [eax]; // src0
movq mm1, qword ptr [ebx]; // src1
movq qword ptr [ebx], mm0; // src1 = src0
pand mm0, mm7; // color & colorMask
pand mm1, mm7; // src1 & colorMask
psrld mm0, 1; // (color & colorMask) >> 1 (E)
psrld mm1, 1; // (src & colorMask) >> 1 (F)
paddd mm0, mm1; // E+F
movq qword ptr [eax], mm0; // src0 = res
add eax, 8;
add ebx, 8;
dec edi;
jnz label0;
mov src0, eax;
mov src1, ebx;
emms;
}
#endif
src0++;
src1++;
}
}
#endif
void MotionBlurIB32(u8 *srcPtr, u32 srcPitch, int width, int height)
{
if(frm1 == NULL) {
Init();
}
#ifdef MMX
if(cpu_mmx) {
MotionBlurIB32_MMX(srcPtr, srcPitch, width, height);
return;
}
#endif
u32 *src0 = (u32 *)srcPtr;
u32 *src1 = (u32 *)frm1;
u32 colorMask = 0xfefefe;
int sPitch = srcPitch >> 2;
int pos = 0;
for (int j = 0; j < height; j++)
for (int i = 0; i < sPitch; i++) {
u32 color = src0[pos];
src0[pos] = (((color & colorMask) >> 1) +
((src1[pos] & colorMask) >> 1));
src1[pos] = color;
pos++;
}
}