⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mmxdemodoc.cpp

📁 CPU 多媒体指令(MMX、SSE等)应用实例
💻 CPP
字号:
// MMXDemoDoc.cpp : implementation of the CMMXDemoDoc class
//

#include "stdafx.h"
#include "MMXDemo.h"

#include "MMXDemoDoc.h"
#include "childfrm.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CMMXDemoDoc

IMPLEMENT_DYNCREATE(CMMXDemoDoc, CDocument)

BEGIN_MESSAGE_MAP(CMMXDemoDoc, CDocument)
	//{{AFX_MSG_MAP(CMMXDemoDoc)
	ON_COMMAND(ID_RUNBASIC, OnRunbasic)
	ON_COMMAND(ID_RUNMMX, OnRunmmx)
	ON_COMMAND(ID_RUNOPT, OnRunopt)
	ON_COMMAND(ID_CLEAR, OnClear)
	ON_COMMAND(ID_CHECKSSE, OnChecksse)
	ON_COMMAND(ID_RUNASM, OnRunasm)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CMMXDemoDoc construction/destruction

CMMXDemoDoc::CMMXDemoDoc()
{
	// Set default image size
	m_iWidth = 1024;
	m_iHeight = 1024;

	// Generate 2 source image
	GenerateImage();
}

CMMXDemoDoc::~CMMXDemoDoc()
{
	// delete all generated image
	delete m_pImg;
	delete m_pImg1;
	delete m_pImg2;
}

BOOL CMMXDemoDoc::OnNewDocument()
{
	if (!CDocument::OnNewDocument())
		return FALSE;

	///////////////////////////////////////////////////////////////////
	// This section only prepare 2 additional views for display 
	///////////////////////////////////////////////////////////////////

	// Create view 1 with the current template frame
	CFrameWnd *pFrame=NULL;
	CRuntimeClass* pRuntimeViewClass = RUNTIME_CLASS(CMiniView);
	// Create the frame Window
	pFrame = CreateNewView(pRuntimeViewClass);
	CSize size;
	size.cx = GetSystemMetrics(SM_CXSCREEN);
	size.cy = GetSystemMetrics(SM_CYSCREEN);
	pFrame->SetWindowPos(&CWnd::wndTop, size.cx*2/3, 0, size.cx/3, size.cy/3, SWP_SHOWWINDOW);
	m_pMiniView1 = (CMiniView *) pFrame->GetActiveView();
	m_pMiniView1->m_szText = "Src Image 1";
	m_pMiniView1->m_pImg = m_pImg1;

	// Create view 2 with the current template frame
	// Create the Frame Window
	pFrame = CreateNewView(pRuntimeViewClass);
	pFrame->SetWindowPos(&CWnd::wndTop, size.cx*2/3, size.cy/3, size.cx/3, size.cy/3, SWP_SHOWWINDOW);
	m_pMiniView2 = (CMiniView *) pFrame->GetActiveView();
	m_pMiniView2->m_szText = "Src Image 2";
	m_pMiniView2->m_pImg = m_pImg2;

	return TRUE;
}



/////////////////////////////////////////////////////////////////////////////
// CMMXDemoDoc serialization

void CMMXDemoDoc::Serialize(CArchive& ar)
{
	if (ar.IsStoring())
	{
		// TODO: add storing code here
	}
	else
	{
		// TODO: add loading code here
	}
}

/////////////////////////////////////////////////////////////////////////////
// CMMXDemoDoc diagnostics

#ifdef _DEBUG
void CMMXDemoDoc::AssertValid() const
{
	CDocument::AssertValid();
}

void CMMXDemoDoc::Dump(CDumpContext& dc) const
{
	CDocument::Dump(dc);
}
#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// CMMXDemoDoc commands
CFrameWnd *CMMXDemoDoc::CreateNewView(CRuntimeClass *pViewClass)
{
	// Get the first view
	POSITION pos = GetFirstViewPosition();
	CMDIChildWnd* pActiveChild = (CMDIChildWnd*)GetNextView(pos);

	// Retrieve document pointer and document template
	CDocument* pDocument = this;
	CDocTemplate* pTemplate = pDocument->GetDocTemplate();
	ASSERT_VALID(pTemplate);
	
	// Create a new view
	CRuntimeClass* pRuntimeViewClass = pViewClass;

	CCreateContext newContext;
	newContext.m_pNewViewClass = pRuntimeViewClass;
	newContext.m_pNewDocTemplate = pTemplate;
	newContext.m_pLastView = NULL;
	newContext.m_pCurrentFrame = pActiveChild;
	newContext.m_pCurrentDoc = this;

	//////////////////////////////////////////////////////
	// Create the frame now
	CRuntimeClass* pFrameClass = RUNTIME_CLASS(CChildFrame);
	CObject* pObject = pFrameClass->CreateObject();
	if (pFrameClass == NULL)
	{
		TRACE0("Error: you must override CDocTemplate::CreateNewFrame.\n");
		ASSERT(FALSE);
		return NULL;
	}
	CFrameWnd* pFrame = (CFrameWnd*)pObject;
	if (pFrame == NULL)
	{
		TRACE1("Warning: Dynamic create of frame %hs failed.\n",
			pFrameClass->m_lpszClassName);
		return NULL;
	}
	ASSERT_KINDOF(CFrameWnd, pFrame);

	// create new from resource
	if (!pFrame->LoadFrame(IDR_MAINFRAME,
			WS_OVERLAPPEDWINDOW | FWS_ADDTOTITLE,   // default frame styles
			NULL, &newContext))
	{
		TRACE0("Warning: CDocTemplate couldn't create a frame.\n");
		// frame will be deleted in PostNcDestroy cleanup
		return NULL;
	}

	// it worked !
	//////////////////////////////////////////////////////
	pTemplate->InitialUpdateFrame(pFrame, pDocument);

	// Get the active view attached to the active MDI child
	// window.
	//CView *pView = (CView *) pFrame->GetActiveView();
	return pFrame;
}

void CMMXDemoDoc::GenerateImage()
{
	int y=0, x=0;

	// generate some pattern for both images. 8 bit per pixel
	m_iSize = m_iWidth * m_iHeight;
	m_pImg = new BYTE[m_iSize];
	m_pImg1 = new BYTE[m_iSize];
	m_pImg2 = new BYTE[m_iSize];

	// Black is 0, white is 255
	memset (m_pImg, 0, m_iSize);		// Set blank image

	// Generate 1st image
	memset (m_pImg1, 0, m_iSize);		// Set vertical line image
	for (y=0; y<m_iHeight; y++)
	{
		for (x=0; x<m_iWidth; x+=10)
		{
			m_pImg1[x+(y*m_iWidth)] = 255;
		}
	}

	// Generate 2nd image, gradient shade of gray image
	for (y=0; y<m_iHeight; y++)
	{
		int iGray = y % 256;
		memset (m_pImg2 + (y*m_iWidth), iGray, m_iWidth);		// everyline has diff shades of gray
	}
}

/////////////////////////////////////////////////////////////////////////////
//
// Comparisons between basic code, optimise code and MMX code
//
/////////////////////////////////////////////////////////////////////////////

// Check the avilability of SSE features
int CheckSSEAvail()
{
	int iAvail = 0;
	
	// The CPU feature flags are bit MMX, FXSR, SSE, SSE2, HHT - 23, 24, 25, 26, 28
	__asm
	{
		mov eax, 1
		cpuid					; execute cpuid detection
		shr edx, 0x1a			; check for bit 25

		jnc noCarryFlag			; compare ON/OFF
		mov [iAvail], 1			; Set Avail to 1

		noCarryFlag:
	}

	return iAvail;
}

// Run add operation using MMX register set
// This function is not optimise with loop unrolling.
// Function is provided as a learning tool.
int MMXAdd(BYTE *d, BYTE *s, int w, int h)
{
	int iCount = w * h;

	// we assume all data in the register is not used by others
	__asm
	{
		// Assign pointers to register
		mov			esi, [s]			; put src addr to esi reg
		mov			edi, [d]			; put dest addr to edi reg
		mov			ecx, [iCount]		; put count to ecx reg
		shr			ecx, 3				; divide count with 8 by shifting 3 bits to right

		codeloop:
		movq		mm0, [esi]			; mov 8 bytes of src data to mmx reg 0
		movq		mm1, [edi]			; mov 8 bytes of dest data to mmx reg 1
		PADDUSB		mm0, mm1			; Add unsigned 8bit saturated to mmx reg 0
		movq		[edi], mm0			; dump back the added 8 bytes of data to dest memory
		add			esi, 8				; add src pointer by 8 bytes
		add			edi, 8				; add dest pointer by 8 bytes

		dec			ecx					; decrement count by 1
		jnz			codeloop			; jump to codeloop if not Zero
		emms							; Restore FPU state to normal

	}

	return 1;
}

// a representation in assembly language on how OnRunOpt() may look like
int AsmAdd(BYTE *d, BYTE *s, int w, int h)
{
	int iCount = w * h;

	// we assume all data in the register is not used by others
	__asm
	{
		// Assign pointers to register
		mov			esi, [s]			; put src addr to esi reg
		mov			edi, [d]			; put dest addr to edi reg
		mov			ecx, [iCount]		; put count to ecx reg

		codeloop:
		mov			al, [edi]			; mov a byte of src data to low word of eax register
		add			al, [esi];			; Add 8 bit from dest ptr to al
		jc			nosave				; jump if carry flag on
		mov			[edi], al
		nosave:
		inc			esi
		inc			edi
		dec			ecx					; decrement count by 1
		jnz			codeloop			; jump to codeloop if not Zero

	}

	return 1;
}

// This function demonstrates common practise.
// Programmers use array index to access memory.
// Total operations count for every cycle (inner loop) more than 10
void CMMXDemoDoc::OnRunbasic() 
{
	int x=0, y=0, i=0, iGray=0;

	// Start timing
	m_el.Begin();

	// Add 2 image using direct memory access
	// Assume both image are same size
	for (y=0; y<m_iHeight; y++)
	{
		for (x=0; x<m_iWidth; x++)
		{
			// calc index
			i = x + y*m_iWidth;
			// add 2 pixels
			iGray = m_pImg1[i] + m_pImg2[i];
			// keep saturation value
			if (iGray > 255) iGray = 255;
			// Save to destination image
			m_pImg[i] = iGray;
		}
	}

	// this code is an improved version from the above which uses only 1 loop
	/*for (i=0; i<m_iSize; i++)
	{
		// add 2 pixels
		iGray = m_pImg1[i] + m_pImg2[i];
		// keep saturation value
		if (iGray > 255) iGray = 255;
		m_pImg[i] = iGray;
	}*/

	// End Timing
	m_el.End();

	// Force redraw
	UpdateAllViews(0);
}

// MMX operation perform 8 additions in parallel every iteration
void CMMXDemoDoc::OnRunmmx() 
{
	// Begin timing
	m_el.Begin();

	// Copy from img1 to tmp
	memcpy(m_pImg, m_pImg1, m_iSize);
	// add img2 to tmp
	MMXAdd(m_pImg, m_pImg2, m_iWidth, m_iHeight);
	
	// End Timing
	m_el.End();

	// Force redraw
	UpdateAllViews(0);
}

// Enhance functions by using pointer arithmetics.
// Pointer access must be sequential.
void CMMXDemoDoc::OnRunopt() 
{
	// Begin timing
	m_el.Begin();

	// Precalculate the pointers
	BYTE *pSrc = m_pImg2;
	BYTE *pSrcEnd = m_pImg2 + m_iSize;
	BYTE *pDest = m_pImg;
	int iGray;

	// Copy from img1 to tmp
	memcpy(m_pImg, m_pImg1, m_iSize);
	
	// loop each pixel and Add
	while (pSrc < pSrcEnd)
	{
		iGray = *pDest + *pSrc;
		if (iGray > 255) iGray=255;
		*pDest = iGray;
		pSrc++;
		pDest++;
	}

	// End Timing
	m_el.End();

	// Force redraw
	UpdateAllViews(0);
}

void CMMXDemoDoc::OnClear() 
{
	// Clear data
	memset(m_pImg, 0, m_iSize);

	// Force redraw
	UpdateAllViews(0);
}

// Check out Part 2 or the articles if your system support SSE
void CMMXDemoDoc::OnChecksse() 
{
	// Check now
	if (CheckSSEAvail())
		AfxMessageBox("SSE Present");
	else
		AfxMessageBox("SSE is not available");
}

void CMMXDemoDoc::OnRunasm() 
{
	// Begin timing
	m_el.Begin();

	// Copy from img1 to tmp
	memcpy(m_pImg, m_pImg1, m_iSize);
	// add img2 to tmp
	AsmAdd(m_pImg, m_pImg2, m_iWidth, m_iHeight);
	
	// End Timing
	m_el.End();

	// Force redraw
	UpdateAllViews(0);
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -