关于图像大范围点阵处理中CPU命中导致速度慢的问题
我在尝试的是一个将图像变形的算法,图像分辨率和屏幕相同(1024*768)或者(1440*900)等。
我用的是ddraw技术,至少绘制效率可以很高。
采用的方法是每次绘制前将原图像缓冲区Lock(m_pImageSurface),同时Lock目标缓冲区(m_pShapeSurface),这样得到两个surface的DESC
DDShapeSurfaceDesc.lpSurface和DDImageSurfaceDesc.lpSurface这2个缓冲区
我采用了分块的变形算法,即将整个屏幕划分成64*64点阵的块,每块在m_pImageSurface上都是标准的正方形,相对应的变形到m_pShapeSurface的变形后的位置上。
现在的问题是,对于点阵块,需要横向和纵向的双重循环(外两层x,y)和点阵内部的64*64的双重循环(内两层i,j),这样一共4层循环。如果里面不写Dst[sDst] = Src[sSrc];一行,帧速从没有循环的约100帧降到约23帧左右。但是加上Dst[sDst] = Src[sSrc];这一行,帧数再次跌到大约1.7帧……这还是我优化了部分算法的,要不只有0.3帧左右。
网上查到的说法,在于可能是CPU的缓存命中问题。我的CPU缓存是6M的,效率都这么低。
有没有更好的办法来处理这个问题?
有2个方面的问题需要解决:
1、4重循环问题是4倍效率。(从100fps->23fps)
2、Dst[sDst] = Src[sSrc];是15倍效率。(从23fps->约1.7fps)
下面贴上主要代码
/* 输入:const CMatrixTemplate* pMatrixTemplate
表示的是变形矩阵,里面保存了图像变形后的每个点的实际位置
*/
HRESULT CImageTemplate::ChangeByShape(const CMatrixTemplate* pMatrixTemplate)
{
//DWORD m_dwScreenWidth;
//DWORD m_dwScreenHeight;
//DWORD m_dwWidthStep;
//DWORD m_dwHeightStep;
//DWORD m_dwKeyPointWidth;
//DWORD m_dwKeyPointHeight;
//POINT** m_ptKeypoint;
DWORD x, y, i, j;
float vx1Step, vy1Step; // 变形矩阵左边线段的从left-top到left-bottom的vx1Step和vy1Step
float vx2Step, vy2Step; // 变形矩阵右边线段的从right-top到right-bottom的vx2Step和vy2Step
float vp1_x, vp1_y;
float vp2_x, vp2_y; // 变形矩阵进行扫描线时时候扫描线左边和右边的2个点
float hxStep, hyStep; // 变形矩阵进行扫描线的时候扫描线左边到右边的2个点的hxStep和hyStep
float cp_x, cp_y;
// 一共有(m_dwKeyPointWidth-1)*(m_dwKeyPointHeight-1)个网格
DWORD sSrc, rSrc, gSrc, bSrc;
DWORD sDst, rDst, gDst, bDst;
FILE* fp = NULL;
fp = fopen("c:\\ddrawdebug.txt", "w+");
char buf[100];
DDSURFACEDESC2 DDImageSurfaceDesc;
DDSURFACEDESC2 DDShapeSurfaceDesc;
memset(&DDImageSurfaceDesc,0,sizeof(DDImageSurfaceDesc) );
DDImageSurfaceDesc.dwSize = sizeof(DDImageSurfaceDesc);
HRESULT hr = m_pImageSurface->GetDDrawSurface()->Lock(&m_rcFrame, &DDImageSurfaceDesc, DDLOCK_SURFACEMEMORYPTR|DDLOCK_WAIT, NULL);
if(FAILED(hr))
{
MessageBox(NULL, GetError(hr), "ERROR", MB_OK);
}
memset(&DDShapeSurfaceDesc,0,sizeof(DDShapeSurfaceDesc) );
DDShapeSurfaceDesc.dwSize = sizeof(DDShapeSurfaceDesc);
hr = m_pShapeSurface->GetDDrawSurface()->Lock(&m_rcFrame, &DDShapeSurfaceDesc, DDLOCK_SURFACEMEMORYPTR|DDLOCK_WRITEONLY, NULL);
if(FAILED(hr))
{
MessageBox(NULL, GetError(hr), "ERROR", MB_OK);
}
DWORD* Dst = (DWORD*)DDShapeSurfaceDesc.lpSurface;
DWORD* Src = (DWORD*)DDImageSurfaceDesc.lpSurface;
DWORD dd2 = DDImageSurfaceDesc.ddpfPixelFormat.dwBumpBitCount;
DWORD dd1 = DDShapeSurfaceDesc.ddpfPixelFormat.dwBumpBitCount;
DWORD imageLineGap = DDImageSurfaceDesc.lPitch >> 2;
DWORD shapeLineGap = DDShapeSurfaceDesc.lPitch >> 2;
DWORD lt, rt, lb, rb;
for(x=0; x<pMatrixTemplate->m_dwKeyPointWidth-1; x++)
{
for(y=0; y<pMatrixTemplate->m_dwKeyPointHeight-1; y++)
{
// 经过变形的每个网格的4个点分别是
// m_ptKeypoint[x+y*m_dwKeyPointWidth] 左上
// m_ptKeypoint[(x+1)+y*m_dwKeyPointWidth] 右上
// m_ptKeypoint[x+(y+1)*m_dwKeyPointWidth] 左下
// m_ptKeypoint[(x+1)+(y+1)*m_dwKeyPointWidth] 右下
// 默认网格的4个点分别是
// x*m_dwWidthStep, y*m_dwHeightStep 左上
// (x+1)*m_dwWidthStep, y*m_dwHeightStep 右上
// x*m_dwWidthStep, (y+1)*m_dwHeightStep 左下
// (x+1)*m_dwWidthStep, (y+1)*m_dwHeightStep 右下
// 里面的大循环是列循环,确定每行左边点和右边点
// 左上角的标准点 (x*m_dwWidthStep, y*m_dwHeightStep)
// 左上角的变形点 m_ptKeypoint[x+y*m_dwKeyPointWidth]
lt = x+y*pMatrixTemplate->m_dwKeyPointWidth;
rt = (x+1)+y*pMatrixTemplate->m_dwKeyPointWidth;
lb = x+(y+1)*pMatrixTemplate->m_dwKeyPointWidth;
rb = (x+1)+(y+1)*pMatrixTemplate->m_dwKeyPointWidth;
vp1_x = pMatrixTemplate->m_ptKeypoint[lt]->x;
vp1_y = pMatrixTemplate->m_ptKeypoint[lt]->y;
vp2_x = pMatrixTemplate->m_ptKeypoint[rt]->x;
vp2_y = pMatrixTemplate->m_ptKeypoint[rt]->y;
vx1Step = (pMatrixTemplate->m_ptKeypoint[lb]->x - pMatrixTemplate->m_ptKeypoint[lt]->x) / (float)pMatrixTemplate->m_dwHeightStep;
vy1Step = (pMatrixTemplate->m_ptKeypoint[lb]->y - pMatrixTemplate->m_ptKeypoint[lt]->y) / (float)pMatrixTemplate->m_dwHeightStep;
vx2Step = (pMatrixTemplate->m_ptKeypoint[rb]->x - pMatrixTemplate->m_ptKeypoint[rt]->x) / (float)pMatrixTemplate->m_dwHeightStep;
vy2Step = (pMatrixTemplate->m_ptKeypoint[rb]->y - pMatrixTemplate->m_ptKeypoint[rt]->y) / (float)pMatrixTemplate->m_dwHeightStep;
for(j=y*pMatrixTemplate->m_dwHeightStep; j<(y+1)*pMatrixTemplate->m_dwHeightStep; j++)
{
hxStep = (vp2_x - vp1_x) / (float)pMatrixTemplate->m_dwWidthStep;
hyStep = (vp2_y - vp1_y) / (float)pMatrixTemplate->m_dwWidthStep;
cp_x = vp1_x;
cp_y = vp1_y;
//i=x*pMatrixTemplate->m_dwWidthStep;
for(i=x*pMatrixTemplate->m_dwWidthStep; i<(x+1)*pMatrixTemplate->m_dwWidthStep; i++)
{
// 将标准点中的每一个点映射到变形点中去。
// 下面是将src的图像(未变形)转换成dst的图像(变形)
// 需要用2个图像的点阵库操作,一个是src的,一个是dst的。
// 4个字节表示一个点的信息
sSrc = i + imageLineGap*j;
sDst = (DWORD)cp_x + shapeLineGap*(DWORD)cp_y;
Dst[sDst] = Src[sSrc]; //问题出在这一行上
cp_x += hxStep;
cp_y += hyStep;
}
vp1_x += vx1Step;
vp1_y += vy1Step;
vp2_x += vx2Step;
vp2_y += vy2Step;
}
}
}
m_pImageSurface->GetDDrawSurface()->Unlock(&m_rcFrame);
m_pShapeSurface->GetDDrawSurface()->Unlock(&m_rcFrame);
return S_OK;
}