directx 9 lost direct3d device



  • ich habe ein problem, das wenn ich in meinem projekt z.b. den task manager aufrufe, mein programm ein "lost device" zurück gibt. jetzt habe ich mich ein wenig durchs internet gelesen und bin auch auf eine lösung gestoßen, allerdings weiß ich nicht, wie ich sie genau umsetzen kann/soll.
    so wie ich das verstanden habe, muss ich alle texturen und sprites zuerst aus dem speicher entfernen, dann über das device "Release()" aufrufen, und dann sollte es eigentlich wieder funktionieren. allerdings haut das so nicht so ganz hin. habe danach versucht, das device freizugeben, und neu zu erstellen, funktioniert auch, aber erst nach mehrmaligen durchlauf des codes, und laut task mgr mit einem erheblichen memory leak.
    also wie geht man dabei genau vor?
    hat damit jemand erfahrung?

    mfg



  • Du musst vorm Device Reset alle Ressourcen freigeben, die im DEFAULT Pool liegen.



  • ist geschehen, allerdings gibt mir danach der "Reset()" ein -2005530516 zurück, was auf einen fehler hindeutet 😞

    wenn ich dann über dieses device versuche eine textur zu laden, schlägt es fehl.



  • Welche Meldung liefert denn die D3D Debug Runtime?



  • Direct3D9: (ERROR) :All user created stateblocks must be freed before ResetEx can succeed. ResetEx Fails.
    Direct3D9: (ERROR) :ResetEx failed and ResetEx/TestCooperativeLevel/Release are the only legal APIs to be called subsequently

    ok, d.h. wohl, das ich noch nicht alles released habe...
    jemand nen tipp, was noch anfällt, außer texturen?



  • Hast du vielleicht noch Effekte am Start?



  • nein
    kann es daran liegen, das ich die draw scene nicht ordentlich beenden kann?



  • Naja, die Fehlermeldung sagt was von Stateblocks. Erzeugst du denn selbst welche?



  • zumindest nicht wissentlich^^

    aber laut dem was ich mir eben ergoogled habe, nein, tu ich nicht 🙂



  • Vielleicht benutzt du irgend ein D3DX Objekt und hast vergessen eine Methode a la OnDeviceLost() aufzurufen?
    Stateblock riecht irgendwie nach sowas wie ID3DXFont, ID3DXEffect, D3DXMesh oder so.

    Aber ohne Code können wir nur raten...



  • #include "Direct3D.h"
    #include "RessourceManager.h"
    
    CDirect3D::CDirect3D()
    {
        m_lpD3D                         = NULL;
        m_lpD3DDevice                   = NULL;
        m_lpBackBuffer                  = NULL;
        m_pLogfile                      = CLogfile::Get();
        m_sLogLocationName              = LOGFILE_ENGINE_LOG_NAME + "Direct3D : ";
    
        m_uiSpriteIndex                 = 0;
    }
    
    CDirect3D::~CDirect3D()
    {
        CleanUp();
    }
    
    // Direct3D initialisieren
    bool CDirect3D::Initialize(HWND hWnd, const UINT uiScreenWidth, const UINT uiScreenHeight, const bool bWindowed)
    {
        // create Direct3D object
        if(FAILED(m_lpD3D = Direct3DCreate9(D3D_SDK_VERSION)))
        {
            // can´t create Direct3D Object
            BASIC_LOG(m_sLogLocationName + "Unable to create Direct3D Object.");
            return false;
        }
    
        ZeroMemory(&m_PParams, sizeof(m_PParams));
    
        m_PParams.SwapEffect       = D3DSWAPEFFECT_DISCARD;
        m_PParams.hDeviceWindow    = hWnd;
        m_PParams.Windowed         = bWindowed;
    
        m_PParams.BackBufferWidth  = uiScreenWidth;
        m_PParams.BackBufferHeight = uiScreenHeight;
    
        m_PParams.BackBufferFormat = D3DFMT_X8R8G8B8;
    
        m_PParams.Flags            = D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;
    
        // create direct3D device
        if(FAILED(m_lpD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &m_PParams, &m_lpD3DDevice)))
        {
            // can´t create direct3D device
            ERROR_LOG(m_sLogLocationName + "Unable to create Direct3D Device.");
            return false;
        }
        // pointer for the backbuffer
        if(FAILED(m_lpD3DDevice->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &m_lpBackBuffer)))
        {
            // can´t create backbuffer
            ERROR_LOG(m_sLogLocationName + "Unable to create Direct3D Backbuffer.");
            return false;
        }
        return true;
    }
    
    void CDirect3D::BeginScene(void)
    {
        if (!m_lpD3DDevice)
            return;
    
        m_lpD3DDevice->Clear(0, 0, D3DCLEAR_TARGET, m_ClearColor, 0, 0);
    
        m_lpD3DDevice->BeginScene();
    }
    
    HRESULT CDirect3D::EndScene(void)
    {
        if (!m_lpD3DDevice)
            return S_FALSE;
    
        m_lpD3DDevice->EndScene();
        m_uiSpriteIndex = 0;
    
        return m_lpD3DDevice->Present(0, 0, 0, 0);
    }
    
    HRESULT CDirect3D::ResetDevice(HWND hWnd, const UINT uiScreenWidth, const UINT uiScreenHeight, const bool bWindowed)
    {
        m_PParams.hDeviceWindow    = hWnd;
        m_PParams.Windowed         = bWindowed;
    
        m_PParams.BackBufferWidth  = uiScreenWidth;
        m_PParams.BackBufferHeight = uiScreenHeight;
    
        if (CRessourceManager *pResMgr = CRessourceManager::Get())
        {
            pResMgr->ClearCharsetTextures();
            pResMgr->ClearTileTextures();
        }
    
        HRESULT hr = S_FALSE;
    
        if (m_lpD3DDevice)
            hr = m_lpD3DDevice->Reset(&m_PParams);
    
        return hr;
    }
    
    // release objects
    void CDirect3D::CleanUp(void)
    {
        ReleaseAllSprites();
    
        if(m_lpBackBuffer)
        {
            m_lpBackBuffer->Release();
            m_lpBackBuffer = NULL;
        }
    
        if(m_lpD3DDevice)
        {
            m_lpD3DDevice->Release();
            m_lpD3DDevice = NULL;
        }
    
        if(m_lpD3D)
        {
            m_lpD3D->Release();
            m_lpD3D = NULL;
        }
    }
    

    im moment ist das eben mein direct3d class.
    wenn end scene ein "false" zurück gibt, wird die funktion "resetdevice" abgearbeitet, weil dann klar ist, das ein lost device besteht.
    in clearxxxtextures werden alle geladenen texturen released, sollte also daher keine probleme kommen.





  • 🙂 danke.

    mir war nicht bewusst, das ich den backbuffer auch releasen muss, und alle sprites einmal mit ->OnLostDevice() und nach dem reset mit OnResetDevice() gecalled werden müssen.

    funktioniert jetzt



  • so, wie bereits geschrieben, funktioniert es, aber eine sache macht mich stutzig.
    es brauch in etwa 20 durchläufe, bis mein device resettet wurde, ansonsten gibt er mir

    Direct3D9: (ERROR) :ResetEx fails. D3DERR_DEVICELOST returned.
    Direct3D9: (ERROR) :ResetEx failed and ResetEx/TestCooperativeLevel/Release are the only legal APIs to be called subsequently

    aus.

    wenn ich es step by step deugge geht es sofort, also ist hier eine fehler analyse leicht schwierig.

    im moment sieht meine reset funktion so aus:

    HRESULT CDirect3D::ResetDevice(HWND hWnd, const UINT uiScreenWidth, const UINT uiScreenHeight, const bool bWindowed)
    {
        m_PParams.hDeviceWindow    = hWnd;
        m_PParams.Windowed         = bWindowed;
    
        m_PParams.BackBufferWidth  = uiScreenWidth;
        m_PParams.BackBufferHeight = uiScreenHeight;
    
        /*if (CRessourceManager *pResMgr = CRessourceManager::Get())
        {
            pResMgr->ClearCharsetTextures();
            pResMgr->ClearTileTextures();
        }*/
    
        HRESULT hr = S_FALSE;
    
        // release backbuffer
        if(m_lpBackBuffer)
        {
            m_lpBackBuffer->Release();
            m_lpBackBuffer = NULL;
        }
    
        for (std::vector<LPD3DXSPRITE>::iterator itr = m_SpriteList.begin(); itr != m_SpriteList.end(); ++itr)
        {
            if (*itr)
                (*itr)->OnLostDevice();
        }
    
        // reset d3d device
        if (m_lpD3DDevice)
            hr = m_lpD3DDevice->Reset(&m_PParams);
    
        if (hr == S_OK)
        {
            for (std::vector<LPD3DXSPRITE>::iterator itr = m_SpriteList.begin(); itr != m_SpriteList.end(); ++itr)
            {
                if (*itr)
                    (*itr)->OnResetDevice();
            }
    
            // pointer for the backbuffer
            hr = m_lpD3DDevice->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &m_lpBackBuffer);
            if(hr == S_OK)
                BASIC_LOG(m_sLogLocationName + "Successfully recreate Direct3D Backbuffer.");
            else    // can´t create backbuffer
                ERROR_LOG(m_sLogLocationName + "Unable to recreate Direct3D Backbuffer.");
    
        }
    
        return hr;
    }
    

    das deleten der texturen ist nicht nötig, da sie managed sind, und nicht default, deswegen auskommentiert.

    woran kann das liegen? braucht ein device zeit, um resettet zu werden? alles andere kann ich mir nciht vorstellen, da durch eine andere rückgabe als S_OK durch hr die komplette game loop mehr oder weniger umgangen wird, und eigentlich nicht mehr passiert, als das diese funktion dauerhaft aufgerufen wird.

    mfg





  • ok, danke 🙂
    hat mir dann doch noch sehr geholfen 😛


Anmelden zum Antworten