CSDN特别收录 --- DirectDraw中使用Lock()锁定出现的问题

来源:互联网 发布:然则朱文公何以知然 编辑:程序博客网 时间:2024/04/27 15:02

我的程序里有一个实时走波功能,我想加入一个用DirectX7来显示帧动画的模块。SetCooperativeLevel时设置了全屏和排它,然后调用Lock()锁定表面读取图片属性并将图片画到表面上去。
    运行时能看到动画,也能看到没加入新模块之前的走波,就是走波变的不够顺畅,走一下停一下的,感觉有点卡。本人认为是Lock()方法出的问题,请大家给个解决方法。
=========================================

查了资料说IDirectDrawSurface7::Lock  IDirectDrawSurface7::Unlock方法加解锁可以使用the IDirectDrawSurface7::GetDC方法来代替,不知道要怎么修改?我显示帧图片的主要程序如下:
D3DTextr_RestoreAllTextures( m_pd3dDevice );

// Lock the surface and put the stereo signature in it
LPDIRECTDRAWSURFACE7 pSurface = D3DTextr_GetSurface( TEXT(strPictureFile) );

    DDSURFACEDESC2 ddsd;
    ZeroMemory(&ddsd, sizeof(ddsd));
    ddsd.dwSize = sizeof(ddsd);
    pSurface->Lock(NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_DONOTWAIT |DDLOCK_NOSYSLOCK | DDLOCK_WRITEONLY, NULL);

    LPNVSTEREOIMAGEHEADER pStereoImageHeader = (LPNVSTEREOIMAGEHEADER)(((unsigned char *) ddsd.lpSurface) + (ddsd.lPitch * (ddsd.dwHeight - 1)));
    pStereoImageHeader->dwSignature = NVSTEREO_IMAGE_SIGNATURE;

    pStereoImageHeader->dwBPP = ddsd.ddpfPixelFormat.dwRGBBitCount;
#if 0
    // If you want to stretch the source image to fit into the destination surface.
    // ATTN!!! This feature works in Nvidia drivers starting with Rel.40
    //pStereoImageHeader->dwFlags = SIH_SWAP_EYES | SIH_SCALE_TO_FIT;
#else
    pStereoImageHeader->dwFlags = SIH_SWAP_EYES;
#endif
    pStereoImageHeader->dwWidth = ddsd.dwWidth; //The surface has both eyes side by side. The actual displayed width is sdDesc.Width/2
    pStereoImageHeader->dwHeight = ddsd.dwHeight;

pSurface->Unlock(NULL);

// Set up the blit rectangles
RECT rDest = {0, 0, 0, 0};
RECT rSrc = {0, 0, ddsd.dwWidth, ddsd.dwHeight};

    // Adjust the destination rect according to the aspect ratio...
    int nXCenter = m_pDeviceInfo->ddsdFullscreenMode.dwWidth / 2;
    int nYCenter = m_pDeviceInfo->ddsdFullscreenMode.dwHeight / 2;
    int nBltWidth = ddsd.dwWidth / 2;
    float fImageAspect = ((float) nBltWidth) / ((float) ddsd.dwHeight);
    float fDisplayAspect = ((float) m_pDeviceInfo->ddsdFullscreenMode.dwWidth) / ((float) m_pDeviceInfo->ddsdFullscreenMode.dwHeight);
   
    if(fImageAspect > fDisplayAspect) {
        rDest.left = 0;
        rDest.right = m_pDeviceInfo->ddsdFullscreenMode.dwWidth;
       
        int nTmpHeight = (int) ((float) m_pDeviceInfo->ddsdFullscreenMode.dwWidth / fImageAspect);
        rDest.top = nYCenter - (nTmpHeight / 2);
        rDest.bottom = rDest.top + nTmpHeight;
    }
    else {
        rDest.top = 0;
        rDest.bottom = m_pDeviceInfo->ddsdFullscreenMode.dwHeight;
       
        int nTmpWidth = (int) ((float) m_pDeviceInfo->ddsdFullscreenMode.dwHeight * fImageAspect);
        rDest.left = nXCenter - (nTmpWidth / 2);
        rDest.right = rDest.left + nTmpWidth;
    }

// Fill in the blit fx structure
    DDBLTFX DDBltFx;
    memset (&DDBltFx, 0, sizeof (DDBLTFX));
    DDBltFx.dwSize = sizeof (DDBLTFX);
    DDBltFx.dwROP = SRCCOPY;
    DDBltFx.dwFillColor = 0;    // Black

// Clear and Blit to the back buffer and flip
LPDIRECTDRAWSURFACE7 pRenderTarget;
m_pd3dDevice->GetRenderTarget(&pRenderTarget);
pRenderTarget->Blt(NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &DDBltFx); // Clear it
HRESULT hRes = pRenderTarget->Blt(&rDest, pSurface, &rSrc, DDBLT_ROP | DDBLT_WAIT, &DDBltFx);
pRenderTarget->Release();
m_pFramework->ShowFrame();

    return S_OK;
 ===============================================

再问一下IDirectDrawSurface7::Lock 方法锁内存的问题:

上网查资料时看过这样一句话:对创建平面的内存上锁,是保证你的程序和系统不能同时对此内存进行存取.这防止你写入"平面"内存时发生错误.

——用Lock 方法时我的主程序是不是也不能访问内存的?我实时走波的那个功能是不是就受这个的影响?
=================================================

怎么没人关注呢,回复有用者加分~~~                                    /////////////////////////汗了  !!-_-!!
=================================

怎么刷新的?
====================================================

来到m_pFramework->ShowFrame();这里就刷新了。
HRESULT CD3DFramework7::ShowFrame()
{
    if( NULL == m_pddsFrontBuffer )
        return D3DFWERR_NOTINITIALIZED;

    if( m_bIsFullscreen )
    {
        // We are in fullscreen mode, so perform a flip.
        if( m_bIsStereo )
            return m_pddsFrontBuffer->Flip( NULL, DDFLIP_WAIT | DDFLIP_STEREO );
        else
            return m_pddsFrontBuffer->Flip( NULL, DDFLIP_WAIT );
    }
    else
    {
        // We are in windowed mode, so perform a blit.
        return m_pddsFrontBuffer->Blt( &m_rcScreenRect, m_pddsBackBuffer,
                                       NULL, DDBLT_WAIT, NULL );
    }
}
==========================================

我是说你2楼的代码是在哪里被调用的?
================================================

是在InitDeviceObjects这个函数里被调用的,而这个函数在下面被调用

HRESULT CD3DApplication::Initialize3DEnvironment()
{
    HRESULT hr;
    DWORD   dwFrameworkFlags = 0L;
    dwFrameworkFlags |= ( !m_pDeviceInfo->bWindowed ? D3DFW_FULLSCREEN : 0L );
    dwFrameworkFlags |= (  m_pDeviceInfo->bStereo   ? D3DFW_STEREO     : 0L );
    dwFrameworkFlags |= (  m_bAppUseZBuffer         ? D3DFW_ZBUFFER    : 0L );

    // Initialize the D3D framework
    if( SUCCEEDED( hr = m_pFramework->Initialize( m_hWnd,
                     m_pDeviceInfo->pDriverGUID, m_pDeviceInfo->pDeviceGUID,
                     &m_pDeviceInfo->ddsdFullscreenMode, dwFrameworkFlags ) ) )
    {
        m_pDD        = m_pFramework->GetDirectDraw();
        m_pD3D       = m_pFramework->GetDirect3D();
        m_pd3dDevice = m_pFramework->GetD3DDevice();

        m_pddsRenderTarget     = m_pFramework->GetRenderSurface();
        m_pddsRenderTargetLeft = m_pFramework->GetRenderSurfaceLeft();

        m_ddsdRenderTarget.dwSize = sizeof(m_ddsdRenderTarget);
        m_pddsRenderTarget->GetSurfaceDesc( &m_ddsdRenderTarget );

        // Let the app run its startup code which creates the 3d scene.
        if( SUCCEEDED( hr = InitDeviceObjects() ) )——————————————调用处
            return S_OK;
        else
        {
            DeleteDeviceObjects();
            m_pFramework->DestroyObjects();
        }
    }

    // If we get here, the first initialization passed failed. If that was with a
    // hardware device, try again using a software rasterizer instead.
    if( m_pDeviceInfo->bHardware )
    {
        // Try again with a software rasterizer
        DisplayFrameworkError( hr, MSGWARN_SWITCHEDTOSOFTWARE );
        D3DEnum_SelectDefaultDevice( &m_pDeviceInfo, D3DENUM_SOFTWAREONLY );
        return Initialize3DEnvironment();
    }

    return hr;
}

===============================================

好惨,自己来顶
==============================================

怎么还没人来呀?能帮解决的再加一百分
============================================

代码太长了,估计没多少人愿意看。
DirectDraw的绘图效率挺高的,如果是系统卡的话,那就是你每次绘图的时候做的操作过多了,如果是画面卡的话,那就是你没有及时刷新屏幕。
问题应该不在Lock上,LZ方向错误。单从你的函数名InitDeviceObjects就似乎是说此函数只在初始化时运行一次,如果真是这样的话,画面又怎么可能及时刷新呢?
=====================================

不是画面卡,是在运行过程中,非主画面的东西感觉有点卡

Lock锁的是整个内存吗?
加100分了
========================================

不是整个内存,只是那个表面自己部分的内存,虽然没有尝试过开两个线程去同时访问这块内存,不过我猜想Lock他的实现可能是这样的:
1、初始时某个信号量为1。
2、Lock时先等待这个信号量,如果为1则减到0并返回这块内存的首地址,如果为0则一直等待。
3、Unlock时将此信号加1。
以上只是猜想,因为自己做多线程的内存互斥访问的时候,也经常使用类似伎俩,所以Lock的实现未必真是如我所说,不过它绝对不是锁整个内存。

===================================

不过如果你是把桌面或整个应用程序的主窗口的表面给锁了,那么他们自己的绘图肯定绘不上去了。
=========================================

我运行第一次InitDeviceObjects()的时候不再让它运行我的实时画波功能就正常,而只要我再一次调用画波就不正确了,而且断断续续的
===============================================

我也觉得是你理解错了,Lock一般是在刷新的时候用于填充画面的。
==================================================

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

==================================================

我顶你个肺啊!以我现在的水平还看不懂!不是语法不明白,就是不了解这个DirectX平台,学完MFC才能开始了解这个平台,不过学完MFC的时候应当要考本科了,计算机图形学留在大学研究啦~~~TMD

//程序注释还是E文的哈~~

//The commentary for the program  is  阴沟累死~~