Why cant use "current display mode" if desktop=32-bit colour depth?

Started by
8 comments, last by Motocrossdoug 17 years, 6 months ago
I am trying to create a Direct3D WINDOWED device using into presentation parameters the current display settings. If the desktop is set to 16bits colours then everything goes fine: CreateDevice succeeds. But if it is 32 bits, then it gives D3DERR_NOTAVAILABLE, and so does also CheckDeviceType!! Of course i could just be happy with 16-bits colour and warn the user to switch to 16bits mode from within my prog. However i would like to understand why is this going wrong in first place! By the way i tried to enumerate the video card capabilities and i see that only "D3DFMT_R5G6B5" colour format is supported. But if i set the desktop properties to use 32 bits colours, then i get D3DFMT_X8R8G8B8 as expected, but then i cannot use neither R5G6B5 or X8R8G8B8 (curent display setting) to create a device..! What is the problem???? Hereafter the code to reproduce the problem, "Interesting part BEGIN " is the place to watch carefully, thanks for any help! :-))



#include <windows.h> // Include the Windows header file that’s needed for all Windows applications
#include <d3d9.h>    // direct3D_9
#include <d3dx9.h>
#include <dxerr9.h>

#include <stdio.h> 
#include <crtdbg.h>

#pragma comment(lib, "d3d9.lib")  //include d3d libraries to linker
#pragma comment(lib, "d3dx9.lib")  //include d3d libraries to linker
#pragma comment(lib, "dxerr9.lib")

////////////////////
// global variables
////////////////////
HINSTANCE               hInst;              // application instance
HWND                    wndHandle;          // application window handle

LPDIRECT3D9             pD3D;               // the Direct3D Object (interface to create d3d devices, and more)
LPDIRECT3DDEVICE9       pd3dDevice;         // the Direct3D Device (a specific d3d device that matches our system)



// forward declarations
/********************************/
bool initWindow( HINSTANCE hInstance );                 //
LRESULT CALLBACK WndProc( HWND, UINT, WPARAM, LPARAM ); //our callback function

// DirectX functions
/*****************/
bool initDirect3D();    
void render(void);


// This is winmain, the main entry point for Windows applications
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow )
//  --------------
{
    if (!initWindow(hInstance)) // Create/Initialize the window
    {
        MessageBox(NULL, "Unable to create window", "ERROR", MB_OK);
        return false;
    }

    if (!initDirect3D())       //Create/Initialize a direct3D obj
    {
        MessageBox(NULL, "Unable to init Direct3D", "ERROR", MB_OK);
        return false;
    }

    // Main message loop:
    MSG msg; 
    ZeroMemory( &msg, sizeof(msg) );
    while( msg.message!=WM_QUIT )
    {
        // Check the message queue
        if( PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) )
        {
            TranslateMessage( &msg );
            DispatchMessage( &msg );
        }        
        else
        {
            render();
        } 
    }

    // release the device and the direct3D object
    if( pd3dDevice != NULL) 
        pd3dDevice->Release();

    if( pD3D != NULL)
        pD3D->Release();
        
    return (int) msg.wParam;
}


/******************************************************************************
* bool initWindow( HINSTANCE hInstance )
* initWindow (1) registers the window class for the application, (2) creates the window
******************************************************************************/
bool initWindow( HINSTANCE hInstance )
{
    //(1) Define and register a WINDOW CLASS
    WNDCLASSEX wcex;
    // Fill in the WNDCLASSEX structure. This describes how the window will look to the system
    wcex.cbSize = sizeof(WNDCLASSEX);               // the size of the structure
    wcex.style = CS_HREDRAW | CS_VREDRAW;           // the class style
    wcex.lpfnWndProc = (WNDPROC)WndProc;            // the window procedure callback
    wcex.cbClsExtra = 0;                            // extra bytes to allocate for this class
    wcex.cbWndExtra = 0;                            // extra bytes to allocate for this instance
    wcex.hInstance = hInstance;                     // handle to the application instance
    wcex.hCursor = LoadCursor(NULL, IDC_ARROW);     // the default cursor
    
    wcex.hIcon         = LoadIcon(NULL, IDI_APPLICATION);    // icon to associate with the application
    wcex.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);// the background color
    wcex.hIconSm       = LoadIcon(NULL, IDI_WINLOGO);    
    wcex.lpszMenuName  = NULL;                               // the resource name for the menu
    wcex.lpszClassName = "DirectXExample";                   // the class name being created
    
    RegisterClassEx(&wcex);

    // Create the window
    wndHandle = CreateWindow(
        "DirectXExample",                   // the window class to use
        "DirectXExample",                   // the title bar text
        WS_OVERLAPPEDWINDOW | WS_VISIBLE,   // the window style
        CW_USEDEFAULT,                      // the starting x coordinate
        CW_USEDEFAULT,                      // the starting y coordinate
        640,                                // the pixel width of the window
        480,                                // the pixel height of the window
        NULL,                               // the parent window; NULL for desktop
        NULL,                               // the menu for the application; NULL for none
        hInstance,                          // the handle to the application instance
        NULL);                              // no values passed to the window

    // Make sure that the window handle that is created is valid
    if (!wndHandle)
        return false;    

    // Display the window on the screen
    ShowWindow(wndHandle, SW_SHOW);
    UpdateWindow(wndHandle);
    return true;
}

//The window procedure, 'WndProc', handles events from the system that relate to your application.
/******************************************************************************
* LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
* The window procedure
******************************************************************************/
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    // Check any available messages from the queue
    switch (message)
    {
        case WM_DESTROY:
            PostQuitMessage(0);
            break;
    }
    // Always return the message to the DefaultWindowProcedure for further processing
    // The following Line DOES the actual creation, showing of window and HANDLES ANY WINDOW MSG
    return DefWindowProc(hWnd, message, wParam, lParam);
}


/*********************************************************************
* initializes direct3D
*********************************************************************/
bool initDirect3D()
{
    pD3D = NULL;
    pd3dDevice = NULL;

    // create the Direct3D object (if Ok pD3D should get a pointer to an IDirect3D9 interface)
    if( NULL == ( pD3D = Direct3DCreate9( D3D_SDK_VERSION ) ) )
    {
        MessageBox(NULL, "E_FAIL Direct3DCreate9(D3D_SDK_VERSION) = NULL", "Error!",MB_ICONEXCLAMATION | MB_OK);
        return false;
    }

//--***********###########********* Interesting part BEGIN ***********###########*********   
//--***********###########********* Interesting part BEGIN ***********###########*********
    //Get the current display mode (in windowed mode this is the only format we can use)
    D3DDISPLAYMODE d3ddm;
    if(FAILED(pD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &d3ddm)))
    {
        MessageBox(NULL, "FAILED(pD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &d3ddm))", "Error!",MB_ICONEXCLAMATION | MB_OK);        
    }
/////////////
// What the hell! 
/////////////
    //Test if current display mode is actually usable (16bit/32bit colour on desktop)
    HRESULT result1 = pD3D->CheckDeviceType( D3DADAPTER_DEFAULT,           //adapter
                                             D3DDEVTYPE_HAL,               //hw or sw rendering (HAL/REF)
                                             d3ddm.Format,                 //displayFormat
                                             d3ddm.Format,                 //backBuffer format
                                             TRUE );                       //isWindowed
    if (FAILED(result1))
    {
        MessageBox(NULL, DXGetErrorString9(result1), "Error!",MB_ICONEXCLAMATION | MB_OK);
        MessageBox(NULL, "FAILED(Current display format not acceptable! \n Try to change desktop colour settings to 16bits!)", "Error!",MB_ICONEXCLAMATION | MB_OK);        
        exit(0);
    }
//--***********###########********* Interesting part END ***********###########*********   
//--***********###########********* Interesting part END ***********###########*********   

    //fill the presentation parameters structure
    D3DPRESENT_PARAMETERS d3dpp;    

    ZeroMemory( &d3dpp, sizeof(d3dpp) );
    d3dpp.Windowed          = TRUE;
    d3dpp.SwapEffect        = D3DSWAPEFFECT_DISCARD;                              
    d3dpp.BackBufferFormat  = d3ddm.Format;   //16bit-checked with DirectXCapsViewer, supported in all screen sizes and both 2D and 3D
    d3dpp.BackBufferHeight  = d3ddm.Height;
    d3dpp.BackBufferWidth   = d3ddm.Width;    
    d3dpp.BackBufferCount   = 1;
    d3dpp.hDeviceWindow     = wndHandle;

    
    // create a default Direct3D device
    HRESULT result = pD3D->CreateDevice( D3DADAPTER_DEFAULT, //number of the video adapter, primary video adapter = DEFAULT
                                         D3DDEVTYPE_HAL,     //device uses hardware acceleration and rasterization
                                         //D3DDEVTYPE_REF,       //The Microsoft reference rasterizer is used.
                                         wndHandle,            //This is the window to which this device will belong
                                         D3DCREATE_SOFTWARE_VERTEXPROCESSING, //behaviour flag
                                         &d3dpp, 
                                         &pd3dDevice );
    
    if (FAILED(result))
    {
        MessageBox(NULL, DXGetErrorString9(result), "Error!",MB_ICONEXCLAMATION | MB_OK);
        MessageBox(NULL, DXGetErrorDescription9(result), "Error!",MB_ICONEXCLAMATION | MB_OK);
        return false;
    }
    return true;
}

/*********************************************************************
* render
*********************************************************************/
void render(void)
{
    // check to make sure we have a valid Direct3D Device
    if( NULL == pd3dDevice )
        return;

    // Clear the backbuffer to a blue color
    pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,0,255), 1.0f, 0 );

    // Present the backbuffer contents to the display
    pd3dDevice->Present( NULL, NULL, NULL, NULL );
}




Advertisement
This is not unusal for some devices, they simply don't support Direct3D in 32 bpp modes, only 2D acceleration via DirectDraw.
.
What garphics card do you have? I know older cards used to have some odd restrictions like this in windowed mode...
Hey guys, thanks for your posts. Well, my video card is a "3dfx Voodoo 3",
quite old indeed, but i experience the same identical problem at work, where
there's an intel integrated video card. None of them supports 32bpp. But even
then, why can the windows desktop be set at 32bpp and everything else work just
fine? Mah!..

Cheers
I'm guessin' Windows is 2D, so 32bit isn't so hard as 32bit 3D? =]

I guess the integrated gfx at work are pretty old too...
Hi Motocrossdoug, well.. you are right indeed about the 2D takes up less resources.. Actually i just need to do 2D graphics, but I'm forced to create a direct3D device anyways i'm afraid.
..by the way, if someone knows a way to force the desktop colour depth to 16 bits, that would be great too! I heard that you need to have full screen access to set the display mode you want independently of the desktop settings, but maybe there's a workaround. Any idea from someone that did this already is welcome.

Cheers
d3dpp.Windowed          = TRUE;d3dpp.SwapEffect        = D3DSWAPEFFECT_DISCARD;                              d3dpp.BackBufferFormat  = D3DFMT_UNKNOWNd3dpp.BackBufferHeight  = 0;d3dpp.BackBufferWidth   = 0;    d3dpp.BackBufferCount   = 1;d3dpp.hDeviceWindow     = wndHandle;


Try this change and get rid of the GetAdapterDisplayMode and CheckDeviceType functions and see how that goes as that's the way I do it and get 32bpp for windowed apps.

After a little poking around on archive.org, looking at long past 3dfx.com pages, I found a FAQ for the Voodoo 3:

16. Why doesn't Voodoo3 support 32b rendering, or large textures, or 32b textures?

There are two reasons: frame rate and image quality. Frame rate is the single most important feature that a gaming platform can provide, and not just average frame rate but sustained frame rate. How many times have you been wiped out in a death match when your frame rate suddenly drops as a number of characters and weapons enter the scene? 32bpp rendering with full 32bpp frame buffer accesses requires twice the memory bandwidth of 16bpp frame buffer accesses regardless of the graphics engine: Higher bandwidth requirement means lower frame rate. As for image quality, we have gone to great lengths to make games look great in 16bpp mode. We actually do the rendering calculations internally at 32 bits to have full precision with the 16-bit operands. Then, instead of simply truncating the results to 16 bits for saving in the frame buffer, we use a proprietary filtering algorithm that retains nearly the full precision of the color value. The result is something that rivals ANY full 32-bit rendering. Except it goes a lot faster. We think that is what gamers are looking for.

.
Ahahaha, I like that they claim that their 16 bit rivals any 32 bit setup... regardless of how good the algorithm and calculations are, 16 bit color is 16 bit color, you can tell the difference...

As far as a solution... If you only need 2D, and want 32bit support, it may be possible to not have to set up a 3D environment using DX7, before DirectDraw and Direct3D were unified (that was 8, right? <.<). Well, I'm uncertain of the specifics of this, but I think it should be possible...

As for forcing the desktop into a certain bit-depth, I did a quick search of the MSDN (probably not the best place, but eh... hoping for a clean function >.>) and found nothin'. I'd imagine the only way to do it would be to tell Windows to change it before you create the device and things... I'm pretty sure you can't do it yourself so long as Windows is managing the screen.

This topic is closed to new replies.

Advertisement