How do I render a fullscreen frame with a differen

2019-09-10 04:55发布

问题:

I am in the process of teaching myself DirectX development while going through all the tutorials on http://directxtutorial.com/. I have run into a problem that I believe is related to me having multiple monitors.

My display is 1920 x 1080. When my code runs in its current state my primary monitor becomes black with the cursor in the middle. When I set my SCREEN defines at the top of my code to 1920 x 1080 my program runs fine and displays my sprite with the navy background. When I leave the SCREEN defines as 1440 x 900 and disable my second monitor my program runs fine. This is what leads me to believe there is some issue with my second monitor hosing up things.

Any help would be appreciated!

Below is my current code:

    // include the basic windows header files and the Direct3D header file
    #include <windows.h>
    #include <windowsx.h>
    #include <d3d9.h>
    #include <d3dx9.h>

    // define the screen resolution and keyboard macros
    #define SCREEN_WIDTH  1440
    #define SCREEN_HEIGHT 900
    #define KEY_DOWN(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 1 : 0)
    #define KEY_UP(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 0 : 1)

    // include the Direct3D Library file
    #pragma comment (lib, "d3d9.lib")
    #pragma comment (lib, "d3dx9.lib")

    // global declarations
    LPDIRECT3D9 d3d;    // the pointer to our Direct3D interface
    LPDIRECT3DDEVICE9 d3ddev;    // the pointer to the device class
    LPD3DXSPRITE d3dspt;    // the pointer to our Direct3D Sprite interface
    BOOL stimToggle = TRUE;

    // sprite declarations
    LPDIRECT3DTEXTURE9 sprite;    // the pointer to the sprite

    // function prototypes
    void initD3D(HWND hWnd); // sets up and initializes Direct3D
    void render_frame(void); // renders a single frame
    void cleanD3D(void); // closes Direct3D and releases memory
    void init_input(HWND hWnd);

    // the WindowProc function prototype
    LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);


    // the entry point for any Windows program
    int WINAPI WinMain(HINSTANCE hInstance,
                       HINSTANCE hPrevInstance,
                       LPSTR lpCmdLine,
                       int nCmdShow)
    {
        HWND hWnd;
        WNDCLASSEX wc;

        ZeroMemory(&wc, sizeof(WNDCLASSEX));

        wc.cbSize = sizeof(WNDCLASSEX);
        wc.style = CS_HREDRAW | CS_VREDRAW;
        wc.lpfnWndProc = (WNDPROC)WindowProc;
        wc.hInstance = hInstance;
        wc.hCursor = LoadCursor(NULL, IDC_ARROW);
        wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
        wc.lpszClassName = L"WindowClass1";

        RegisterClassEx(&wc);

        hWnd = CreateWindowEx(NULL,
                              L"WindowClass1",
                              L"Our Direct3D Program",
                              WS_EX_TOPMOST | WS_POPUP,
                              0, 0,
                              SCREEN_WIDTH, SCREEN_HEIGHT,
                              NULL,
                              NULL,
                              hInstance,
                              NULL);

        ShowWindow(hWnd, nCmdShow);

        // set up and initialize Direct3D
        initD3D(hWnd);
        init_input(hWnd);

        // enter the main loop:

        MSG msg;

        while(TRUE)
        {
            //DWORD starting_point = GetTickCount();

            if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
            {
                if (msg.message == WM_QUIT)
                    break;

                TranslateMessage(&msg);
                DispatchMessage(&msg);
            }

            render_frame();

            // check the 'escape' key
            if(KEY_DOWN(VK_ESCAPE))
                PostMessage(hWnd, WM_DESTROY, 0, 0);

            //while ((GetTickCount() - starting_point) < 25);
        }

        // clean up DirectX and COM
        cleanD3D();

        return msg.wParam;
    }


    // this is the main message handler for the program
    LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
        switch(message)
        {
            case WM_DESTROY:
                {
                    PostQuitMessage(0);
                    return 0;
                } break;
            case WM_INPUT:
                {
                    RAWINPUT InputData;

                    UINT DataSize = sizeof(RAWINPUT);
                    GetRawInputData((HRAWINPUT)lParam,
                                    RID_INPUT,
                                    &InputData,
                                    &DataSize,
                                    sizeof(RAWINPUTHEADER));

                    // set the mouse button status
                    if(InputData.data.mouse.usButtonFlags == RI_MOUSE_LEFT_BUTTON_DOWN)
                        stimToggle = FALSE;
                    if(InputData.data.mouse.usButtonFlags == RI_MOUSE_LEFT_BUTTON_UP)
                        stimToggle = TRUE;

                    return 0;
                } break;
        }

        return DefWindowProc (hWnd, message, wParam, lParam);
    }


    // this function initializes and prepares Direct3D for use
    void initD3D(HWND hWnd)
    {
        d3d = Direct3DCreate9(D3D_SDK_VERSION);

        D3DPRESENT_PARAMETERS d3dpp;

        ZeroMemory(&d3dpp, sizeof(d3dpp));
        d3dpp.Windowed = FALSE;
        d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
        d3dpp.hDeviceWindow = hWnd;
        d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8;
        d3dpp.BackBufferWidth = SCREEN_WIDTH;
        d3dpp.BackBufferHeight = SCREEN_HEIGHT;
        d3dpp.BackBufferCount = 1;
        d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
        d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
        d3dpp.EnableAutoDepthStencil = FALSE;

        // create a device class using this information and the info from the d3dpp stuct
        d3d->CreateDevice(D3DADAPTER_DEFAULT,
                          D3DDEVTYPE_HAL,
                          hWnd,
                          D3DCREATE_SOFTWARE_VERTEXPROCESSING,
                          &d3dpp,
                          &d3ddev);


        D3DXCreateSprite(d3ddev, &d3dspt);    // create the Direct3D Sprite object

        D3DXCreateTextureFromFileEx(d3ddev,    // the device pointer
                                    L"ast_sprite.png",    // the new file name
                                    D3DX_DEFAULT,    // default width
                                    D3DX_DEFAULT,    // default height
                                    D3DX_DEFAULT,    // no mip mapping
                                    NULL,    // regular usage
                                    D3DFMT_A8R8G8B8,    // 32-bit pixels with alpha
                                    D3DPOOL_MANAGED,    // typical memory handling
                                    D3DX_DEFAULT,    // no filtering
                                    D3DX_DEFAULT,    // no mip filtering
                                    D3DCOLOR_XRGB(0, 0, 128),    // the hot-pink color key
                                    NULL,    // no image info struct
                                    NULL,    // not using 256 colors
                                    &sprite);    // load to sprite

        return;
    }


    // this is the function used to render a single frame
    void render_frame(void)
    {
        // clear the window to a deep blue
        d3ddev->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 128), 1.0f, 0);

        if(stimToggle)
        {
            d3ddev->BeginScene();    // begins the 3D scene
            d3dspt->Begin(D3DXSPRITE_ALPHABLEND);    // begin sprite drawing

            D3DSURFACE_DESC surfaceDesc;
            sprite->GetLevelDesc(NULL, &surfaceDesc); 

            // draw the sprite
            D3DXVECTOR3 center(surfaceDesc.Width / 2.0f, surfaceDesc.Height / 2.0f, 0.0f);    // center at the upper-left corner
            D3DXVECTOR3 position(SCREEN_WIDTH / 2.0f, SCREEN_HEIGHT / 2.0f, 0.0f);    // position at 50, 50 with no depth
            d3dspt->Draw(sprite, NULL, &center, &position, D3DCOLOR_XRGB(255, 255, 255));

            d3dspt->End();    // end sprite drawing
            d3ddev->EndScene();    // ends the 3D scene
        }

        d3ddev->Present(NULL, NULL, NULL, NULL);

        return;
    }

    // this is the function that initializes the Raw Input API
    void init_input(HWND hWnd)
    {
        RAWINPUTDEVICE Mouse;
        Mouse.usUsage = 0x02;    // register mouse
        Mouse.usUsagePage = 0x01;    // top-level mouse
        Mouse.dwFlags = NULL;    // flags
        Mouse.hwndTarget = hWnd;    // handle to a window

        RegisterRawInputDevices(&Mouse, 1, sizeof(RAWINPUTDEVICE));    // register the device
    }

    // this is the function that cleans up Direct3D and COM
    void cleanD3D(void)
    {
        sprite->Release();
        d3ddev->Release();
        d3d->Release();

        return;
    }

EDIT: Here is my debug information from my Output window.

Direct3D9: (INFO) :======================= Hal SWVP device selected

Direct3D9: (INFO) :HalDevice Driver Style b

Direct3D9: :Subclassing window 00680b0a
Direct3D9: :StartExclusiveMode
Direct3D9: :WM_DISPLAYCHANGE: 1440x900x32
Direct3D9: (ERROR) :Lost due to display uniqueness change
Prototype.exe has triggered a breakpoint.

This is where it triggers the breakpoint. When I click continue, the rest of the below is displayed.

Direct3D9: (INFO) :Using FF to PS converter

Direct3D9: (INFO) :Enabling multi-processor optimizations
Direct3D9: (INFO) :DDI threading started

Direct3D9: (INFO) :Using FF to VS converter in software vertex processing

Direct3D9: (ERROR) :************************************************************
Direct3D9: (ERROR) :ASSERTION FAILED! File s:\gfx_aug09\windows\directx\dxg\inactive\d3d9\d3d\fw\lhbatchfilter.cpp Line 3466: pArgs->Flags.Discard
Direct3D9: (ERROR) :************************************************************
Direct3D9: (ERROR) :************************************************************
Direct3D9: (ERROR) :ASSERTION FAILED! File s:\gfx_aug09\windows\directx\dxg\inactive\d3d9\d3d\fw\lhbatchfilter.cpp Line 3466: pArgs->Flags.Discard
Direct3D9: (ERROR) :************************************************************
Direct3D9: (ERROR) :************************************************************
Direct3D9: (ERROR) :ASSERTION FAILED! File s:\gfx_aug09\windows\directx\dxg\inactive\d3d9\d3d\fw\lhbatchfilter.cpp Line 3466: pArgs->Flags.Discard
Direct3D9: (ERROR) :************************************************************
D3D9 Helper: Warning: Default value for D3DRS_POINTSIZE_MAX is 2.19902e+012f, not 4.16345e-316f.  This is ok.
Direct3D9: :WM_ACTIVATEAPP: BEGIN Activating app pid=00003c58, tid=00005888
Direct3D9: :*** Active state changing
Direct3D9: :WM_ACTIVATEAPP: DONE Activating app pid=00003c58, tid=00005888
Direct3D9: :WM_ACTIVATEAPP: BEGIN Activating app pid=00003c58, tid=00005888
Direct3D9: :*** Already activated
Direct3D9: :WM_ACTIVATEAPP: DONE Activating app pid=00003c58, tid=00005888
Direct3D9: :WM_ACTIVATEAPP: BEGIN Activating app pid=00003c58, tid=00005888
Direct3D9: :*** Already activated
Direct3D9: :WM_ACTIVATEAPP: DONE Activating app pid=00003c58, tid=00005888

回答1:

  1. Identify which monitor is primary monitor, by default, DirectX will output to the primary monitor.

  2. Make sure the resolution you set is available for the monitor you are rendering to. if you use an unsupported resolution, DirectX will failed when creating device.

[Edit], use the following code if you don't want to hard-code the screen resolution.

    // Get max display resolution and set it as back buffer size

    D3DDISPLAYMODE displayMode ;
    d3d->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &displayMode) ;

    int width = displayMode.Width;
    int height = displayMode.Height;

    d3dpp.BackBufferWidth = width;
    d3dpp.BackBufferHeight = height;
  1. Turn on debug mode, since you are using DirectX 9.0, this can be simply done by using DirectX control panel, it is C:\Program Files\Microsoft DirectX SDK (June 2010)\Utilities\bin\x86\dxcpl.exe, this might be a different if you install DirectX SDK in another location. with debug mode turn on, you will get lots of helpful information in the output window which will help you to solve most of your problems.