Files
core/ASCImageStudio3/AVSImageView5/Tracking/MemoryUtils.h

237 lines
5.1 KiB
C++

#pragma once
namespace MemoryUtils
{
class CMemoryUtils
{
public:
CMemoryUtils()
{
m_bMMXSupported = CheckForMMX();
m_bSSESupported = CheckForSSE();
}
~CMemoryUtils()
{
}
BOOL IsMMXSupported() const
{
return m_bMMXSupported;
}
BOOL IsSSESupported() const
{
return m_bSSESupported;
}
void memset(void *pDest, unsigned char value, int nBytes) const
{
if (!m_bMMXSupported)
{
::memset(pDest, value, nBytes);
return;
}
int nOffset = (int)((reinterpret_cast<ULONG64>(pDest)) % 8);
if (nBytes < 32)
{
::memset(pDest, value, nBytes);
}
else
{
if (nOffset != 0)
{
int nPreBytes = 8-nOffset;
memset(pDest, value, nPreBytes);
pDest = (void*)((BYTE*)pDest + nPreBytes);
nBytes -= nPreBytes;
}
int nLoops = nBytes/64;
unsigned __int64 value8x = value;
value8x = value8x | (value8x<<8);
value8x = value8x | (value8x<<16);
value8x = value8x | (value8x<<32);
if (nLoops > 0)
__asm
{
mov ecx, nLoops
mov edi, pDest
movq mm0, qword ptr value8x
movq mm1, qword ptr value8x
movq mm2, qword ptr value8x
movq mm3, qword ptr value8x
movq mm4, qword ptr value8x
movq mm5, qword ptr value8x
movq mm6, qword ptr value8x
movq mm7, qword ptr value8x
ALIGN 16
MMX_memset_loop:
MOVQ [edi], mm0
MOVQ [edi+8], mm1
MOVQ [edi+16], mm2
MOVQ [edi+24], mm3
MOVQ [edi+32], mm4
MOVQ [edi+40], mm5
MOVQ [edi+48], mm6
MOVQ [edi+56], mm7
ADD edi, 64
dec ecx
jnz MMX_memset_loop
EMMS
}
int nBytesDone = nLoops*64;
int nBytesLeft = nBytes - nBytesDone;
if (nBytesLeft > 0)
::memset((unsigned char *)pDest + nBytesDone, value, nBytesLeft);
}
}
// ýòó ôóíêöèþ íåëüçÿ èñïîëüçîâàòü ïðè ïåðåêðûòèè áëîêîâ ïàìÿòè!
// åñëè íàäî êîïèðîâàòü áëîêè ïàìÿòè ñ ïåðåêðûòèåì íàäî âîñïîëüçîâàòüñÿ
// ñòàíäàðòíûìè ôóíêöèÿìè memcpy() èëè memmove()
void memcpy(void *pDest, void *pSrc, int nBytes) const
{
if (!m_bMMXSupported)
{
::memcpy(pDest, pSrc, nBytes);
return;
}
int nOffsetSrc = (int)((reinterpret_cast<ULONG64>(pSrc)) % 8);
int nOffsetDst = (int)((reinterpret_cast<ULONG64>(pDest)) % 8);
if (nOffsetSrc != nOffsetDst || nBytes < 32)
{
// don't use MMX, since data is not aligned
::memcpy(pDest, pSrc, nBytes);
}
else
{
if (nOffsetSrc != 0)
{
int nPreBytes = 8 - nOffsetSrc;
::memcpy(pDest, pSrc, nPreBytes);
pSrc = (void*)((BYTE*)pSrc + nPreBytes);
pDest = (void*)((BYTE*)pDest + nPreBytes);
nBytes -= nPreBytes;
//assert((((unsigned long)pSrc) % 8)==0);
//assert((((unsigned long)pDest) % 8)==0);
}
int nLoops = nBytes/64;
if (nLoops > 0)
__asm
{
mov ecx, nLoops
mov eax, pSrc
mov edi, pDest
ALIGN 16
MMX_memcpy_loop:
MOVQ mm0, [eax]
MOVQ mm1, [eax+8]
MOVQ mm2, [eax+16]
MOVQ mm3, [eax+24]
MOVQ mm4, [eax+32]
MOVQ mm5, [eax+40]
MOVQ mm6, [eax+48]
MOVQ mm7, [eax+56]
MOVQ [edi], mm0
MOVQ [edi+8], mm1
MOVQ [edi+16], mm2
MOVQ [edi+24], mm3
MOVQ [edi+32], mm4
MOVQ [edi+40], mm5
MOVQ [edi+48], mm6
MOVQ [edi+56], mm7
ADD eax, 64
ADD edi, 64
dec ecx
jnz MMX_memcpy_loop
EMMS
}
int nBytesDone = nLoops*64;
int nBytesLeft = nBytes - nBytesDone;
if (nBytesLeft > 0)
{
::memcpy((unsigned char *)pDest + nBytesDone, (unsigned char *)pSrc + nBytesDone, nBytesLeft);
}
}
}
protected:
BOOL m_bMMXSupported;
BOOL m_bSSESupported;
BOOL CheckForMMX()
{
DWORD dwMMX = 0;
DWORD *pdwMMX = &dwMMX;
__try {
__asm {
mov eax, 1
cpuid
mov edi, pdwMMX
mov dword ptr [edi], edx
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
dwMMX = 0;
}
if (dwMMX & 0x00800000) // check bit 23
return TRUE;
return FALSE;
}
BOOL CheckForSSE()
{
/*
The SSE instruction set was introduced with the Pentium III and features:
* Additional MMX instructions such as min/max
* Prefetch and write-through instructions for optimizing data movement
from and to the L2/L3 caches and main memory
* 8 New 128 bit XMM registers (xmm0..xmm7) and corresponding 32 bit floating point
(single precision) instructions
*/
DWORD dwSSE = 0;
DWORD *pdwSSE = &dwSSE;
__try {
__asm
{
mov eax, 1
cpuid
mov edi, pdwSSE
mov dword ptr [edi], edx
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
dwSSE = 0;
}
if (dwSSE & 0x02000000) // check bit 25
return TRUE;
return FALSE;
}
};
};