2017-01-13 27 views
0

Я всегда думал, что нам нужно создать окно, прежде чем мы сможем создать устройство DirectX9. И на самом деле, это, как я понимаю official documentation на методе CreateDevice:DirectX9 без окна устройства

hFocusWindow [в] Тип: HWND (...) Для оконного режима, этот параметр может быть NULL только если член hDeviceWindow из pPresentationParameters установлен до действительного значения, отличного от NULL.

Теперь я просто попробовал, и кажется, что для меня работает следующий кусок кода (например, я получаю правильный указатель на устройство, и я могу использовать его для выполнения рендеринга целевого рендеринга, даже если я не предусматривает какую-либо ручка окна в любое время):

#include <windows.h> 
#include <stdio.h> 
#include <iostream> 
#include <sstream> 
#include <chrono> 
#include <thread> 

#if defined(_MSC_VER) 
    #pragma warning(disable : 4005) 
#endif 

#include <d3d9.h> 
#include <d3dx9.h> 
#include <DxErr.h> 

int (WINAPIV * __vsnprintf)(char *, size_t, const char*, va_list) = _vsnprintf; 

#define DEBUG_MSG(msg) std::cout << msg << std::endl; 
#define ERROR_MSG(msg) std::cout << "[ERROR] " << msg << std::endl; 

#define THROW_MSG(msg) { \ 
    std::ostringstream os; \ 
    os.precision(9); \ 
    os << std::fixed << "[FATAL] " << msg << " (at " << __FILE__ <<":"<<__LINE__<<")"; \ 
    DEBUG_MSG(os.str()); \ 
    throw std::runtime_error(os.str()); \ 
} 

#define CHECK(cond,msg) if(!(cond)) { THROW_MSG(msg); return; } 
#define CHECK_RET(cond,ret,msg) if(!(cond)) { THROW_MSG(msg); return ret; } 
#define CHECK_RESULT(val,msg) { HRESULT hr = (val); if(FAILED(hr)) { THROW_MSG(msg << ", err=" << DXGetErrorString(hr) << ", desc=" << DXGetErrorDescription(hr)); return; } } 
#define CHECK_RESULT_RET(val,ret,msg) { HRESULT hr = (val); if(FAILED(hr)) { THROW_MSG(msg << ", err=" << DXGetErrorString(hr) << ", desc=" << DXGetErrorDescription(hr)); return ret; } } 

#define SAFERELEASE(x) if(x) { x->Release(); x = NULL; } 

IDirect3D9Ex* d3dEx = nullptr; 
IDirect3DDevice9* deviceEx = nullptr; 

IDirect3DSurface9* renderSurface1 = nullptr; 
HANDLE      renderSurfaceHandle1 = nullptr; 
IDirect3DSurface9* renderSurface2 = nullptr; 
HANDLE      renderSurfaceHandle2 = nullptr; 

bool testCycle() { 
    CHECK_RET(d3dEx==nullptr, false,"Invalid D3D context."); 
    CHECK_RET(deviceEx==nullptr, false,"Invalid D3D device."); 

    // Create dedicated device: 
    DEBUG_MSG("Creating Direct3D9Ex context"); 
    CHECK_RESULT_RET(Direct3DCreate9Ex(D3D_SDK_VERSION, (IDirect3D9Ex **)&d3dEx), 
    false, "Cannot create Direct3D9Ex context"); 

    D3DPRESENT_PARAMETERS d3dpp; 
    ZeroMemory(&d3dpp, sizeof(d3dpp)); 
    d3dpp.Windowed = TRUE; 
    d3dpp.BackBufferCount = 1; 
    d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; 
    d3dpp.BackBufferWidth = 200; 
    d3dpp.BackBufferHeight = 200; 
    d3dpp.BackBufferFormat = D3DFMT_A8R8G8B8; 
    d3dpp.hDeviceWindow = NULL; 
    d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; 

    DEBUG_MSG("Creating Device9Ex."); 
    CHECK_RESULT_RET(d3dEx->CreateDevice(0, D3DDEVTYPE_HAL, NULL, 
    D3DCREATE_MULTITHREADED | D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE, 
    &d3dpp, &deviceEx), false, "Cannot create Device9Ex."); 

    DEBUG_MSG("Setting lighting render state"); 
    CHECK_RESULT_RET(deviceEx->SetRenderState(D3DRS_LIGHTING, FALSE), 
    false, "Cannot set lighting render state."); 

    int width = 512; 
    int height = 256; 

    DEBUG_MSG("Creating SDI render surfaces of size "<<width<<"x"<<height); 

    CHECK_RESULT_RET(deviceEx->CreateRenderTarget(width, height, 
              D3DFMT_A8R8G8B8, D3DMULTISAMPLE_NONE, 0, 
              TRUE, &renderSurface1, &renderSurfaceHandle1), 
       false, "Cannot create Render surface 1 for SDIOutput"); 

    CHECK_RESULT_RET(deviceEx->CreateRenderTarget(width, height, 
              D3DFMT_A8R8G8B8, D3DMULTISAMPLE_NONE, 0, 
              TRUE, &renderSurface2, &renderSurfaceHandle2), 
       false, "Cannot create Render surface 2 for SDIOutput"); 

    CHECK_RET(renderSurfaceHandle1 != nullptr, false, "Invalid shared handle for surface 1"); 
    CHECK_RET(renderSurfaceHandle2 != nullptr, false, "Invalid shared handle for surface 2"); 

    DEBUG_MSG("Initial render of SDI surface 1") 
    CHECK_RESULT_RET(deviceEx->SetRenderTarget(0, renderSurface1), false, "Cannot set render target 1"); 
    CHECK_RESULT_RET(deviceEx->BeginScene(),false, "Cannot begin scene 1"); 
    CHECK_RESULT_RET(deviceEx->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(255,0,0), 1.0f, 0), false, "Cannot clear scene 1"); 
    CHECK_RESULT_RET(deviceEx->EndScene(), false, "Cannot end scene 1"); 

    DEBUG_MSG("Initial render of SDI surface 2") 
    CHECK_RESULT_RET(deviceEx->SetRenderTarget(0, renderSurface2), false, "Cannot set render target 2"); 
    CHECK_RESULT_RET(deviceEx->BeginScene(), false, "Cannot begin scene 2"); 
    CHECK_RESULT_RET(deviceEx->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,255,0), 1.0f, 0), false, "Cannot clear scene 2"); 
    CHECK_RESULT_RET(deviceEx->EndScene(), false, "Cannot end scene 2"); 

    DEBUG_MSG("Test cycle performed successfully.") 
    return true; 
} 

void releaseResources() 
{ 
    DEBUG_MSG("Releasing resources."); 

    SAFERELEASE(renderSurface1); 
    SAFERELEASE(renderSurface2); 
    renderSurfaceHandle1 = nullptr; 
    renderSurfaceHandle2 = nullptr; 

    SAFERELEASE(deviceEx); 
    SAFERELEASE(d3dEx); 
} 

#ifdef WINDOWS_APP 
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) { 
#else 
int main(int argc, char *argv[]) { 
#endif 

    testCycle(); 
    releaseResources(); 

    DEBUG_MSG("Exiting."); 
    return 0; 
} 

Итак, кто имеет начало объяснений по этому поводу, является документацией неправильно или я пропускаю точку? :-)

ответ

0

Документов уже сказать вам, что происходит:

Per MSDN

Для применения в оконном режиме, эта ручка будет цель по умолчанию окна Представить. Если этот дескриптор равен NULL, будет сделано окно фокусировки.

Так оно использует любое окно, находящееся в фокусе, в то время, когда вы звоните Present.

Обратите внимание, что эта двусмысленность была исправлена ​​для Direct3D 10 или более поздней версии через DXGI. Ручка окна нужна только для создания цепочек подкачки, а устройство Direct3D может быть создано независимо от цепочки подкачки (если только вы не используете несколько неуклюжую вспомогательную функцию D3D11CreateDeviceAndSwapChain, которая выполняет обе операции одновременно). См. Anatomy of Direct3D 11 Create Device.

+0

Это более подходящий ответ, и я могу теперь понять, что происходит: API DirectX должен выбрать окно, сфокусированное в данный момент, как вы сообщили. Нужно было бы сделать некоторые тесты, чтобы проверить, может быть, но это достаточно хорошо для меня. Спасибо за вашу помощь ! :-) – ultimamanu

+1

Для полноты на этом: я все равно пытался запустить мое устройство DirectX с NULL-окном в любом случае, и в этом случае я заметил, что поверхности, которые я генерировал, затем каким-то образом «испортились» с помощью содержимое моего рабочего стола! ... Так что это устройство не кажется должным образом «изолированным» в моем случае, и эта настройка для меня не подходит. – ultimamanu

+0

@Chuck Walbourn Действительно ли это окно * в фокусе в момент, когда вы называете 'Present' *, или это окно, которое вы указали как' hFocusWindow' в вызове 'CreateDevice'? – phimuemue

0

В документации указано, что вы должны делать, но точно не указывает, что может произойти, если вы нарушите правила.

Возможно, это сработает для вас, но вам надоело тестировать его на установке с несколькими мониторами? Или пока работает другое приложение DirectX? И это всего лишь два случайных варианта.

+1

Ну, я согласен, что это предельный случай, и это поведение четко не определено, но в то же время я также считаю, что DirectX API совершенно ясен, когда дело доходит до уведомления об ошибке: вы вызываете функцию DirectX, и вы получаете HRESULT, если это успех, то, очевидно, вы можете предположить, что ваша операция преуспела. Если вы нарушаете какое-либо правило, то вам не следует добиваться успеха вообще ... – ultimamanu

+0

@ EmmanuelRoche: Нет, извините, это не строго гарантировано. Microsoft не зла и проверяет параметры, когда это легко и быстро, но некоторые ошибки на вашей стороне не могут быть легко обнаружены и не приведут к возврату ошибки. – MSalters