Почему Direct3D не восстанавливается после отключения монитора в Windows XP? - PullRequest
4 голосов
/ 22 сентября 2009

Появилась интересная ошибка, с которой мне не повезло. В оконной программе Direct3D9, использующей собственный код, я обрабатываю потерянное устройство, используя что-то похожее на следующее:

void MyClass::RecoverFromDeviceLost(LPDIRECT3DDEVICE9 deviceToRecover, D3DPRESENT_PARAMETERS devicePresentParams )
{


    HRESULT hr = deviceToRecover->TestCooperativeLevel();
    if(hr == D3DERR_DEVICELOST ) { 
        //Code to shutdown all D3DPOOL_DEFAULT allocated objects

    }else if(hr == D3DERR_DEVICENOTRESET){

        hr = deviceToRecover->Reset(&devicePresentParams);
        if(SUCCEEDED(hr))
        {
            //Code to rebuild all D3DPOOL_DEFAULT objects

        }

    }

}

Это нормально работает в Vista, но, похоже, имеет серьезные проблемы в XP. Если монитор отключен или отключен от ПК через KVM, я никогда не получу D3DERR_DEVICELOST. Единственное возвращаемое значение из TestCooperativeLevel, которое я когда-либо получаю, это D3DERR_DEVICENOTRESET. И каждый вызов Reset дает D3DERR_INVALIDCALL. Я попытался заставить программу использовать код завершения, выполнив следующее:

...
else if(hr == D3DERR_DEVICENOTRESET){

        hr = deviceToRecover->Reset(&devicePresentParams);
        if(SUCCEEDED(hr))
        {
            //Code to rebuild all D3DPOOL_DEFAULT objects

        }else {
            //Duplicate of code to shutdown all D3DPOOL_DEFAULT objects
        }

    }
...

Но не было никаких изменений. Эта проблема, похоже, касается только Windows XP (до сих пор тестировалась на SP2, SP3). Я использую DXSDK августа 2007 года и не могу обновить в это время. Кто-нибудь видел эту проблему раньше, или есть идеи, почему я не могу перезагрузить свое устройство?

ОБНОВЛЕНИЕ: Я считаю, что нашел решение , но все еще озадачен сбоем второго сегмента кода, указанного выше. После того, как среда выполнения DirectX Debug стала работать поверх удаленной отладки, я понял, что причина сбоя функции сброса заключалась в том, что имелись невыпущенные ресурсы. Однако точно такой же код выпуска, когда он применялся, как показано в ответе, решил проблему. Я проверил, что программа не создает объекты D3DPOOL_DEFAULT между вызовами функции восстановления. Есть ли в структуре Direct3D что-то, что могло бы вызвать проблемы при выполнении сброса, как показано в сегментах кода этого вопроса?

Ответы [ 2 ]

3 голосов
/ 25 сентября 2009

Я закончил тестировать другую программу, которая использует DirectX для графики, просто чтобы увидеть, была ли проблема только с одной программой. Другое приложение восстановилось без проблем после отключения монитора или переключения KVM в Windows XP. Основное различие между двумя программами заключалось в том, что рабочая программа использовала DXUT для управления Direct3d, тогда как я выполнял все ручное управление в той, которая не работала. Прочесав исходный код DXUT, я заметил, что они использовали одноэтапный подход к восстановлению устройства, в котором не использовался D3DERR_DEVICELOST, возвращаемый из TestCooperativeLevel до возвращаемого значения D3DERR_DEVICENOTRESET. Следующий код, похоже, решил проблему:

void MyClass::RecoverFromDeviceLost(LPDIRECT3DDEVICE9 deviceToRecover, D3DPRESENT_PARAMETERS devicePresentParams )
{

    HRESULT hr = deviceToRecover->TestCooperativeLevel();
    if(hr == D3DERR_DEVICELOST ) { 
        //Device is lost and cannot be reset yet
        return;
    }


    //Code to shutdown all D3DPOOL_DEFAULT allocated objects

    hr=deviceToRecover->Reset(&devicePresentParams);
    if(SUCCEEDED(hr)){

        //Code to rebuild all D3DPOOL_DEFAULT objects

    }
}

Этот код имеет побочный эффект сброса несколько раз, если монитор отключен (или KVM-переключатель) в течение длительного периода времени.

2 голосов
/ 22 сентября 2009

Некоторое время назад У меня были похожие симптомы , я разрабатывал приложение для нескольких мониторов. Отключение монитора не представляет собой потерянное устройство DX - «устройство» является программной абстракцией уровня операционной системы, и оно не теряется при отключении монитора.

Если по какой-либо причине вам необходимо обнаружить отключение монитора во время выполнения, даже Win32 API EnumDisplayMonitors будет недостаточно. Как подробно описано в посте , этот API запрашивает кэш драйвера, который по умолчанию обновляется только при «загрузке, входе в систему или открытии панели управления свойствами дисплея». Теперь мы работаем только с nVidia, и они предоставляют возможность принудительного обновления кэша через NvCplRefreshConnectedDevices (ссылка на NvCpl.dll для его использования). Не могу сказать, предоставляет ли ATI аналогичную функциональность, или даже если это необходимо.

И что еще более важно - вы уверены, что случайное событие заставит вас восстановить свои ресурсы? Мое предположение не так.

...