2011-04-21 45 views
3

我试图使用缓冲区在我的程序中的几个'图层'(线程)之间进行通信,现在我有内部发生了什么的视觉输出,我意识到有一个毁灭性的时间量被吃掉在使用这些缓冲区的过程中。缓冲区通信速度噩梦

下面是关于我的代码中发生了什么的一些说明。

  • 当再现模式在此线程被触发时,它开始与发送尽可能多的点,它可以给它下面
  • 从下侧线的点层(线程)然后被处理并返回到该线程通过下侧线的输出缓冲器
  • 点接收回被映射(现在)如在D3D表面的白色像素

  • 如果我绕过缓冲器并直接把点到表面的像素,只大约需要3秒钟完成整个工作

  • 如果我的手点下来,然后有下层传递右后卫,跳过任何实际的数字处理,整个作业大约需要30分钟(这使得整个程序没用)
  • 改变我的缓冲区的大小对速度没有明显的影响

  • 我本来是用在我的缓冲区互斥体,但在尝试了解决问题

已经消除了他们有什么我可以做不同的解决这是我遇到的速度问题? ...与我处理这些消息的方式有关吗?

这是我的代码 我很抱歉,它是如此混乱。我不得不在这个项目上移动得太快,并且在我一直在尝试的评论中留下了很多片段。

DWORD WINAPI CONTROLSUBSYSTEM::InternalExProcedure(__in LPVOID lpSelf) 
{ 
    XMSG xmsg; 
    LPCONTROLSUBSYSTEM lpThis = ((LPCONTROLSUBSYSTEM)lpSelf); 
    BOOL bStall; 

    BOOL bRendering = FALSE; 
    UINT64 iOutstandingPoints = 0; // points that are out being tested 
    UINT64 iPointsDone = 0; 
    UINT64 iPointsTotal = 0; 

    BOOL bAssigning; 
    DOUBLE dNextX; 
    DOUBLE dNextY; 

    while(1) 
    { 
     if(lpThis->hwTargetWindow!=NULL && lpThis->d3ddev!=NULL) 
     { 
      lpThis->d3ddev->Clear(0,NULL,D3DCLEAR_TARGET,D3DCOLOR_XRGB(0,0,0),1.0f,0); 
      if(lpThis->d3ddev->BeginScene()) 
      { 
       lpThis->d3ddev->StretchRect(lpThis->sfRenderingCanvas,NULL,lpThis->sfBackBuffer,NULL,D3DTEXF_NONE); 
       lpThis->d3ddev->EndScene(); 
      } 
      lpThis->d3ddev->Present(NULL,NULL,NULL,NULL); 
     } 

     //bStall = TRUE; 
     // read input buffer 
     if(lpThis->bfInBuffer.PeekMessage(&xmsg)) 
     { 
      bStall = FALSE; 

      if(HIBYTE(xmsg.wType)==HIBYTE(CONT_MSG)) 
      { 
       // take message off 
       lpThis->bfInBuffer.GetMessage(&xmsg); 
       // double check consistency 
       if(HIBYTE(xmsg.wType)==HIBYTE(CONT_MSG)) 
       { 
        switch(LOBYTE(xmsg.wType)) 
        { 
        case SETRESOLUTION_MSG: 
         lpThis->iAreaWidth = (UINT)xmsg.dptPoint.X; 
         lpThis->iAreaHeight = (UINT)xmsg.dptPoint.Y; 
         lpThis->sfRenderingCanvas->Release(); 
         if(lpThis->d3ddev->CreateOffscreenPlainSurface(
          (UINT)xmsg.dptPoint.X,(UINT)xmsg.dptPoint.Y, 
          D3DFMT_X8R8G8B8, 
          D3DPOOL_DEFAULT, 
          &(lpThis->sfRenderingCanvas), 
          NULL)!=D3D_OK) 
         { 
          MessageBox(NULL,"Error resizing surface.","ERROR",MB_ICONERROR); 
         } 
         else 
         { 
          D3DLOCKED_RECT lrt; 
          if(D3D_OK == lpThis->sfRenderingCanvas->LockRect(&lrt,NULL,0)) 
          { 
           lpThis->iPitch = lrt.Pitch; 
           VOID *data; 
           data = lrt.pBits; 
           ZeroMemory(data,lpThis->iPitch*lpThis->iAreaHeight); 
           lpThis->sfRenderingCanvas->UnlockRect(); 

           MessageBox(NULL,"Surface Resized","yay",0); 
          } 
          else 
          { 
           MessageBox(NULL,"Error resizing surface.","ERROR",MB_ICONERROR); 
          } 
         } 
         break; 
        case SETCOLORMETHOD_MSG: 
         break; 
        case SAVESNAPSHOT_MSG: 
         lpThis->SaveSnapshot(); 
         break; 
        case FORCERENDER_MSG: 
         bRendering = TRUE; 
         iPointsTotal = lpThis->iAreaHeight*lpThis->iPitch; 
         iPointsDone = 0; 

         MessageBox(NULL,"yay, render something!",":o",0); 
         break; 
        default: 
         break; 
        } 
       }// else, lost this message 
      } 
      else 
      { 
       if(HIBYTE(xmsg.wType)==HIBYTE(MATH_MSG)) 
       { 
        XMSG xmsg2; 
        switch(LOBYTE(xmsg.wType)) 
        { 
        case RESETFRAME_MSG: 
        case ZOOMIN_MSG: 
        case ZOOMOUT_MSG: 
        case PANUP_MSG: 
        case PANDOWN_MSG: 
        case PANLEFT_MSG: 
        case PANRIGHT_MSG: 
         // tell self to start a render 
         xmsg2.wType = CONT_MSG|FORCERENDER_MSG; 
         if(lpThis->bfInBuffer.PutMessage(&xmsg2)) 
         { 
          // pass it down 
          while(!lpThis->lplrSubordinate->PutMessage(&xmsg)); 
          // message passed so pull it from buffer 
          lpThis->bfInBuffer.GetMessage(&xmsg); 
         } 
         break; 
        default: 
         // pass it down 
         if(lpThis->lplrSubordinate->PutMessage(&xmsg)) 
         { 
          // message passed so pull it from buffer 
          lpThis->bfInBuffer.GetMessage(&xmsg); 
         } 
         break; 
        } 
       } 
       else if(lpThis->lplrSubordinate!=NULL) 
       // pass message down 
       { 
        if(lpThis->lplrSubordinate->PutMessage(&xmsg)) 
        { 
         // message passed so pull it from buffer 
         lpThis->bfInBuffer.GetMessage(&xmsg); 
        } 
       } 
      } 
     } 
     // read output buffer from subordinate 
     if(lpThis->lplrSubordinate!=NULL && lpThis->lplrSubordinate->PeekMessage(&xmsg)) 
     { 
      bStall = FALSE; 
      if(xmsg.wType==(REPLY_MSG|TESTPOINT_MSG)) 
      { 
       // got point test back 
       D3DLOCKED_RECT lrt; 
       if(D3D_OK == lpThis->sfRenderingCanvas->LockRect(&lrt,NULL,0)) 
       { 
        INT pitch = lrt.Pitch; 
        VOID *data; 
        data = lrt.pBits; 
        INT Y=dRound((xmsg.dptPoint.Y/(DOUBLE)100)*((DOUBLE)lpThis->iAreaHeight)); 
        INT X=dRound((xmsg.dptPoint.X/(DOUBLE)100)*((DOUBLE)pitch)); 

        // decide color 
        if(xmsg.iNum==0) 
         ((WORD *)data)[X+Y*pitch] = 0xFFFFFFFF; 
        else 
         ((WORD *)data)[X+Y*pitch] = 0xFFFFFFFF; 

        // message handled so remove from buffer 
        lpThis->lplrSubordinate->GetMessage(&xmsg); 

        lpThis->sfRenderingCanvas->UnlockRect(); 
       } 
      } 
      else if(lpThis->bfOutBuffer.PutMessage(&xmsg)) 
      { 
       // message sent so pull the real one off the buffer 
       lpThis->lplrSubordinate->GetMessage(&xmsg); 
      } 
     } 
     if(bRendering && lpThis->lplrSubordinate!=NULL) 
     { 
      bAssigning = TRUE; 
      while(bAssigning) 
      { 
       dNextX = 100*((DOUBLE)(iPointsDone%lpThis->iPitch))/((DOUBLE)lpThis->iPitch); 
       dNextY = 100*(DOUBLE)((INT)(iPointsDone/lpThis->iPitch))/(DOUBLE)(lpThis->iAreaHeight); 
       xmsg.dptPoint.X = dNextX; 
       xmsg.dptPoint.Y = dNextY; 
       // 
       //xmsg.iNum = 0; 
       //xmsg.wType = REPLY_MSG|TESTPOINT_MSG; 
       // 
       xmsg.wType = MATH_MSG|TESTPOINT_MSG; 

       /*D3DLOCKED_RECT lrt; 
       if(D3D_OK == lpThis->sfRenderingCanvas->LockRect(&lrt,NULL,0)) 
       { 
        INT pitch = lrt.Pitch; 
        VOID *data; 
        data = lrt.pBits; 
        INT Y=dRound((dNextY/(DOUBLE)100)*((DOUBLE)lpThis->iAreaHeight)); 
        INT X=dRound((dNextX/(DOUBLE)100)*((DOUBLE)pitch)); 
        ((WORD *)data)[X+Y*pitch] = 0xFFFFFFFF; 
        lpThis->sfRenderingCanvas->UnlockRect(); 
       } 
       iPointsDone++; 
       if(iPointsDone>=iPointsTotal) 
       { 
        MessageBox(NULL,"done rendering","",0); 
        bRendering = FALSE; 
        bAssigning = FALSE; 
       } 
       */ 
       if(lpThis->lplrSubordinate->PutMessage(&xmsg)) 
       { 
        bStall = FALSE; 
        iPointsDone++; 
        if(iPointsDone>=iPointsTotal) 
        { 
         MessageBox(NULL,"done rendering","",0); 
         bRendering = FALSE; 
         bAssigning = FALSE; 
        } 
       } 
       else 
       { 
        bAssigning = FALSE; 
       } 
      } 
     } 

     //if(bStall) 
      //Sleep(10); 
    } 

    return 0; 
} 
} 

(仍然习惯这个论坛的代码块的东西)

编辑:

下面是我认为是在概念上类似于一个例子,虽然这个例子消耗它在生产中的消息同一个线程。

#include <Windows.h> 
#include "BUFFER.h" 

int main() 
{ 
BUFFER myBuffer; 

INT jobsTotal = 1024*768; 
INT currentJob = 0; 
INT jobsOut = 0; 
XMSG xmsg; 

while(1) 
{ 
    if(myBuffer.PeekMessage(&xmsg)) 
    { 
     // do something with message 
     // ... 

     // if successful, remove message 
     myBuffer.GetMessage(&xmsg); 
     jobsOut--; 
    } 

    while(currentJob<jobsTotal) 
    { 
     if(myBuffer.PutMessage(&xmsg)) 
     { 
      currentJob++; 
      jobsOut++; 
     } 
     else 
     { 
      // buffer is full at the moment 
      // stop for now and put more on later 
      break; 
     } 
    } 

    if(currentJob==jobsTotal && jobsOut==0) 
    { 
     MessageBox(NULL,"done","",0); 
     break; 
    } 
} 

return 0; 
} 

该示例还运行约3秒钟,而不是30分钟。

顺便说一句,如果有人知道为什么Visual Studio一直试图让我说PeekMessageA和GetMessageA而不是我定义的实际名称,那也很好。

+0

你知道,我真的很想帮助,但是你已经有了大量的代码,这有点复杂和无关紧要,不完整。如果可以将它提取到显示问题的最小应用程序,您会得到更好的回应。 – Arelius 2011-04-21 06:42:44

+1

PeekMessageA等的原因是你已经包含了'windows.h'头文件,这个头文件将'PeekMessage'定义为'PeekMessageA'或'PeekMessageW'的宏,这取决于你的unicode设置。你可以(1)和它一起生活,(2)使用不与Win32 API重叠的不同名称,(3)分隔你的Win32代码,它必须包含你的缓冲区代码中的windows.h,而不包括windows。h在使用缓冲区的同一个文件中,或者(4)'#undef'这些宏,并且在你想要Win32函数的任何时候使用完整的名称':: PeekMessageA'。 – 2011-04-21 13:20:39

回答

2

锁定和解锁整个矩形以更改单个点可能效率不高,您可能更适合生成要修改的点的列表,然后锁定矩形一次,迭代该列表并修改所有点,然后解锁矩形。

当你锁定rect时,你正在有效地拖延对它的并发访问,所以它就像GPU在这方面的互斥体 - 然后你只修改一个像素。对每个像素重复这样做会不断拖延GPU。您可以使用D3DLOCK_NOSYSLOCK来避免这种情况,但我不确定它是否会在您的程序的较大范围内很好地播放。

我显然不完全确定你的算法的目标是什么,但如果你试图平行处理D3D表面上的像素,那么我认为最好的方法将通过GPU上的着色器。

在基本上在系统内存中生成一个数组的地方,在每个点/像素的基础上用“输入”值填充它,然后从数组中生成GPU上的纹理。接下来,将纹理绘制为全屏四边形,然后使用像素着色器将其渲染到某个渲染目标。着色器可以编码,以您喜欢的任何方式处理每个点,GPU将负责优化并行化。然后,您从该渲染目标生成一个新纹理,然后将该纹理复制到系统内存数组中。然后您可以从该阵列中提取所有输出。您还可以将渲染目标结果中的多个着色器应用回渲染目标,以根据需要对多个转换进行流水线处理。

+0

我试过评论锁定矩形和编辑表面的部分,因为我也想知道这是否有帮助。它对速度没有明显的影响。 – 2011-04-21 11:16:45

1

一对夫妇的注意事项:

  • 不要写你自己的messape传递代码。它可能是正确和缓慢的,或者是快速和错误的。设计快速的代码需要很多经验,然后让它无错误是非常困难的,因为调试线程代码很困难。 Win32提供了几个高效的线程安全队列:SList和窗口消息队列。

  • 您的设计以最糟糕的方式分解工作。即使在最好的情况下,在线程之间传递信息也很昂贵,因为它会导致数据和同步对象上的缓存争用。把你的工作分成独立的非交互(或最小化交互)数据集和给予每个独立的线程,然后负责处理数据集的所有阶段是更好的。

0

不投票。

这很可能是问题的核心。你有一个任务持续呼叫peekmessage,可能在那里找不到任何东西。这只会吃掉所有可用的CPU。任何想要发布消息的任务都不太可能获得任何CPU时间来实现此目标。

我不记得你是如何通过windows消息队列(可能是WaitMessage或某些变体)实现这一点的,但通常你可以通过计数信号来实现这一点。当消费者需要数据时,它会等待信号灯发出信号。当生产者有数据时,它发出信号。

0

我设法通过重新设计整个事情来解决它

现在通过巨大的有效载荷,而不是单独的任务

(我的海报)