DirectX 9: устройство возвращает D3DERR_DEVICENOTRESET после вызова Reset () - PullRequest
0 голосов
/ 06 марта 2020

Я новичок в DirectX, и у меня возникла проблема с DX9. Поэтому я хочу написать функцию для моего D3DClass до ведьмы между полноэкранным и оконным режимом . Мой класс D3D имеет член ID3DXSprite, который в основном использует функцию рисования. Однако я не могу заставить приложение нормально работать после Reset() метода. Вот мой код:

 void SystemClass::ChangeDisplayMode(bool NewMode)
    {
        if (NewMode != CurrentMode) // if the new display mode is difference from the current mode
        {
            CurrentMode = NewMode;
            if (CurrentMode==true) // 1 is fullscreen, 0 is none
            {
                // I have only written the case where the app will change from Windowed to Fullscreen
                auto d3d = m_Graphics->m_D3D; // m_D3D is an D3DClass object
                auto d3dpp = d3d->m_d3dpp;
                auto d3ddev = d3d->m_d3ddev;
                auto sprite = d3d->m_sprite;

                d3dpp.Windowed = false;

                sprite->OnLostDevice();
                d3ddev->Reset(&d3dpp); // My Render() will not render when the CheckDevice() doesn't return D3D_OK, which is why after i call this function, my render will never render again leading to the frontbuffer stuck at the frame before i called this function.
                sprite->OnResetDevice();

                HRESULT result = d3ddev->TestCooperativeLevel();
                if (result == D3DERR_DEVICENOTRESET)
                {
                    Debug("Device no reset"); // The debug printed this, i don't know how to handle this
                }   
            }
        }
    }

Вот мой код, когда я инициализирую D3DClass, который в начале вызывается только один:

bool D3DClass::Initialize(int width, int height, bool fullscreen, HWND hwnd)
{
    m_d3d = Direct3DCreate9(D3D_SDK_VERSION);

    // Present Parameters
    m_d3dpp.Windowed = !fullscreen;
    m_d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
    m_d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8;
    m_d3dpp.BackBufferCount = 1;
    m_d3dpp.BackBufferWidth = width;
    m_d3dpp.BackBufferHeight = height;
    m_d3dpp.hDeviceWindow = hwnd;

    HRESULT result = D3D_OK;

    result = m_d3d->CreateDevice(
            D3DADAPTER_DEFAULT,
            D3DDEVTYPE_HAL,
            hwnd,
            D3DCREATE_SOFTWARE_VERTEXPROCESSING,
            &m_d3dpp,
            &m_d3ddev
    );

    result = m_d3ddev->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &m_backbuffer);
    result = D3DXCreateSprite(m_d3ddev, &m_sprite); // I wonder if we need to call this function again after reset as well, tks

    if (result != D3D_OK) return false;
    return true;
}

Я где-то читал, что мне нужно выпустить все ресурсы до звонка Reset() но я не знаю как это сделать. Вот моя функция загрузки текстуры:

HRESULT D3DClass::LoadTexture(string filepath, Texture* texture) // Texture is a structure which have 2 members which are `D3DIMAGE_INFO` and `IDirect3DTexture9*`
{
    HRESULT result;

    result = D3DXGetImageInfoFromFileA(filepath.c_str(), &texture->t_info);
    if (result != D3D_OK) return result;
    result = D3DXCreateTextureFromFileExA(
        m_d3ddev,
        filepath.c_str(),
        texture->t_info.Width,
        texture->t_info.Height,
        1,
        D3DPOOL_DEFAULT, // If i change this value to D3DPOOL_MANAGED, nothing will be drawn by the sprite, i don't know if it will affect the Reset() method at all
        D3DFMT_UNKNOWN,
        D3DPOOL_MANAGED,
        D3DX_DEFAULT,
        D3DX_DEFAULT,
        D3DCOLOR_XRGB(255, 0, 255),
        &texture->t_info,
        NULL,
        &texture->t_content
    );
    return result;
}

РЕДАКТИРОВАТЬ: Больше информации. Это мой способ обработки ошибки в функции Render(). Я использовал пример кода из здесь .

bool GraphicsClass::Render()
{
    bool result;
    HRESULT hresult;

    hresult = m_D3D->CheckDevice();

    switch (hresult)
    {
    case D3DERR_DEVICELOST:
        // If the device is lost and cannot be reset yet, then sleep for a bit and and try again at the next window loop
        Sleep(20);
        return true; // Stop rendering immediately until device is ready
    case D3DERR_DEVICENOTRESET:
        m_D3D->OnLostDevice();
        m_D3D->m_d3ddev->Reset(&m_D3D->m_d3dpp);
        m_D3D->OnResetDevice();
        return true; // Stop rendering immediately until device is ready
    }

    result = m_D3D->BeginScene(0, 0, 0);
    result = DrawScene(); // Use the m_sprite to draw in this function
    result = m_D3D->EndScene();

    return result;
}
...