天天看点

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

我的程序里有一个实时走波功能,我想加入一个用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  阴沟累死~~