天天看點

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  陰溝累死~~