关于图像大范围点阵处理中CPU命中导致速度慢的问题

kevinmartin 2010-03-05 10:26:36
我在尝试的是一个将图像变形的算法,图像分辨率和屏幕相同(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;
}

...全文
141 7 打赏 收藏 转发到动态 举报
写回复
用AI写文章
7 条回复
切换为时间正序
请发表友善的回复…
发表回复
kevinmartin 2010-03-12
  • 打赏
  • 举报
回复
最后总结:

是我的做法有错误,所以导致的慢的结果。
现在换了思路,通过dx的filter做了一个BufferCB,从里面回调,直接处理pBuffer的数据就可以了,貌似都没有占到多少CPU……

我看我电脑上的视频,640*352的占15%CPU……
kevinmartin 2010-03-07
  • 打赏
  • 举报
回复
继续补充

其实问题并没有直接解决。

问题出在对dx的surface,只要surface上的像素被lock后读取速度总是很慢。后来解决方案为不通过dx的第一个surface,即src_surface,而用其他的方式处理,比如说hdc的方式处理,速度快很多。

谁要分的,来提一下~~~
验证码识别 2010-03-06
  • 打赏
  • 举报
回复
up





up
yanghailun_ 2010-03-05
  • 打赏
  • 举报
回复
竟然问题解决了..
学习一下...
顺便参考楼主解决问题思路...呵呵...楼主加油...
kevinmartin 2010-03-05
  • 打赏
  • 举报
回复
问题已经解决

问题可能出在那个lPitch是far的还是什么显卡的,反正对这个读取非常慢。

我用Bitmap的Lock获取内存的这种指针,再处理就很快了。
ziplj 2010-03-05
  • 打赏
  • 举报
回复
专业的东西看不懂 帮顶
kevinmartin 2010-03-05
  • 打赏
  • 举报
回复
经过与达人的沟通,已经确认到问题症结,是对这个缓冲区进行“读取”操作的时候速度极慢,而写入的时候操作极快。

这到底是怎么回事涅

19,469

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 图形处理/算法
社区管理员
  • 图形处理/算法社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧