DirectX - invalid device. Why ?

Started by
5 comments, last by Buckeye 15 years, 8 months ago
Hi all! I'm writing a short game editor type application and I stumbled upon a wierd phenomenon. When loading a model from an .x file I wanted to compute it's bounding box and to my surprise the vertex buffer lock crashes my app every time. The error is:
Quote: An unhandled exception of type 'System.AccessViolationException' occurred in RAW3D Editor.exe Additional information: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
The same happens when I try calling D3DXCreateBox(). I did some checking and found out that ValidateDevice() returns E_FAIL. Here's the code: R3DDevice.h:

#pragma once

#ifndef R3D_DEVICE_H
#define R3D_DEVICE_H

namespace RAW3DEditor
{
	namespace R3DDirect3D 
	{

		class R3DRenderDevice 
		{

		public:
			R3DRenderDevice();
			void Release();
			void ToggleRendering()		{RenderingEnabled = !RenderingEnabled;};
			void EnableRendering()		{RenderingEnabled = true;};
			void DisableRendering()		{RenderingEnabled = false;};
			bool GetRenderingEnabled()	{return RenderingEnabled;};

		protected:
			~R3DRenderDevice();
			void SetDeviceParameters(int Height, int Width);

		public:
			HRESULT Render();
			HRESULT SetViewport(D3DVIEWPORT9* NewViewport);
			HRESULT InitializeD3D(HWND ParentWindow, int Height, int Width);
			HRESULT SetBackBuffer(int Height, int Width);
			IDirect3DDevice9* GetDevice();
			IDirect3DSurface9* GetBackbuffer();

		private:
			IDirect3D9*             Direct3D;		  
			IDirect3DDevice9*       Direct3DDevice;  
			D3DPRESENT_PARAMETERS	D3DPresentParams; 
			HWND					Window;
			bool					RenderingEnabled;
			FILE*					log;
		};

	}
}

#endif

R3DDevice.cpp:

#include "stdafx.h"

using namespace RAW3DEditor::R3DDirect3D;

R3DRenderDevice::R3DRenderDevice()
{
	SYSTEMTIME LocalTime;
	Direct3D = NULL;
	Direct3DDevice = NULL;
	RenderingEnabled = false;
	_wfopen_s(&log, L"R3DRenderLog.log", L"w");
	GetLocalTime(&LocalTime);
	fwprintf_s(log, L"%02d.%02d.%04d %02d:%02d\n\n", LocalTime.wDay, LocalTime.wMonth, 
			LocalTime.wYear, LocalTime.wHour, LocalTime.wMinute);
	fwprintf_s(log, L"Basic device constructed.\n");
}

R3DRenderDevice::~R3DRenderDevice()
{
	if(Direct3D)
		Direct3D->Release();
	if(Direct3DDevice)
		Direct3DDevice->Release();
	fwprintf_s(log, L"Device shut down.\n");
	fclose(log);
}

HRESULT R3DRenderDevice::SetBackBuffer(int Height, int Width)
{
	HRESULT hr;
	SetDeviceParameters(Height, Width);
	if( SUCCEEDED( hr = Direct3DDevice->Reset(&D3DPresentParams) ) )
		fwprintf_s(log, L"Device successfuly reset for %d by %d.\n", Width, Height);
	else
		fwprintf_s(log, L"Device reset failed for %d by %d.\n", Width, Height);
	return D3D_OK;
}

void R3DRenderDevice::SetDeviceParameters(int Height, int Width)
{
	D3DFORMAT DetectedDepthFormat, DetectedBackBufferFormat;
	int StencilIndex, SurfaceIndex;
	BufferFormats* AvailableFormats = new BufferFormats();
	HRESULT hr;
	for(SurfaceIndex = AvailableFormats->LBackBufferFormats; SurfaceIndex >= 1; SurfaceIndex--)
		for(StencilIndex = AvailableFormats->LStencilBufferFormats; StencilIndex >= 1; StencilIndex--)
		{
			DetectedBackBufferFormat = AvailableFormats->BackBufferFormats[SurfaceIndex];
			DetectedDepthFormat = AvailableFormats->StencilBufferFormats[StencilIndex];
			if(SUCCEEDED(hr = Direct3D->CheckDeviceFormat( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, 
														   DetectedBackBufferFormat, 
														   D3DUSAGE_DEPTHSTENCIL, 
														   D3DRTYPE_SURFACE, DetectedDepthFormat) ) )
			{
				SurfaceIndex = 0;
				StencilIndex = 0;
			}
		}
	delete AvailableFormats;

	ZeroMemory(&D3DPresentParams, sizeof D3DPRESENT_PARAMETERS);
	D3DPresentParams.BackBufferHeight = Height;
	D3DPresentParams.BackBufferWidth = Width;
    D3DPresentParams.Windowed = TRUE;
	D3DPresentParams.AutoDepthStencilFormat = DetectedDepthFormat;
	D3DPresentParams.EnableAutoDepthStencil = TRUE;
    D3DPresentParams.SwapEffect = D3DSWAPEFFECT_DISCARD;
	D3DPresentParams.MultiSampleType = D3DMULTISAMPLE_NONE;
	D3DPresentParams.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
	D3DPresentParams.BackBufferFormat = DetectedBackBufferFormat;
}

HRESULT R3DRenderDevice::InitializeD3D(HWND ParentWindow, int Height, int Width)
{
	HRESULT hr;
	Window = ParentWindow;
    if( NULL == ( Direct3D = Direct3DCreate9( D3D_SDK_VERSION ) ) )
	{
		fwprintf_s(log, L"Direct3D object creation failed.\n");
        return E_FAIL;
	}

	SetDeviceParameters(Height, Width);

    if( FAILED( Direct3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, Window,
										D3DCREATE_HARDWARE_VERTEXPROCESSING,
										&D3DPresentParams, &Direct3DDevice ) ) )
	{
		fwprintf_s(log, L"Direct3D device creation failed.\n");
        return E_FAIL;
	}

	if( FAILED( hr = Direct3DDevice->ValidateDevice(NULL) ) )
		DXTRACE_ERR( L"Device validation failed", hr );

	fprintf_s(log, "Device initialized.\n");
    return D3D_OK;
}
HRESULT R3DRenderDevice::Render()
{
	if( !Direct3DDevice )
    {
		fwprintf_s(log, L"Scene rendering failed. Device not initialized or invalid.\n");
		return E_FAIL;
	}

	Direct3DDevice->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(255, 255, 255), 1.0f, 0 );
    
    if( SUCCEEDED( Direct3DDevice->BeginScene() ) )
    {

        Direct3DDevice->EndScene();
    }
	else
	{
		fwprintf_s(log, L"Scene rendering failed.\n");
		return E_FAIL;
	}

    Direct3DDevice->Present( NULL, NULL, NULL, NULL );
	return D3D_OK;
}

HRESULT R3DRenderDevice::SetViewport(D3DVIEWPORT9 *NewViewport)
{
	if ( FAILED( Direct3DDevice->SetViewport(NewViewport) ) )
	{
		fwprintf_s(log, L"New viewport has been set successfully\n");
		return E_FAIL;
	}
	return D3D_OK;
}

IDirect3DDevice9* R3DRenderDevice::GetDevice()
{
	return this->Direct3DDevice;
}

IDirect3DSurface9* R3DRenderDevice::GetBackbuffer()
{
	IDirect3DSurface9* Backbuffer;
	HRESULT hr = this->Direct3DDevice->GetBackBuffer( 0, 0, D3DBACKBUFFER_TYPE_MONO, &Backbuffer );
	if(SUCCEEDED(hr))
		fwprintf_s(log, L"Backbuffer surface retrieved successfuly.\n");
	else
		fwprintf_s(log, L"Backbuffer surface could not be retrieved.\n");
	return Backbuffer;
}

void R3DRenderDevice::Release()
{
	this->~R3DRenderDevice();
}

The code that requests device creation is

this->Device = new R3DRenderDevice;
this->Device->InitializeD3D(ClientHWND, ClientHeight, ClientWidth);

Where ClientHWND is the window handle for a class derived form System::Windows::Forms::Panel and the other two parameters represent the size of the panel. The D3Dobject creation does not encounter any errors and neither does the device creation. I can also reset the device and even some basic drawing works too but when I try to validate the function returns E_FAIL and locking buffers or creating primitives gives the AccessViolationException at runtime. What's happening ?
Advertisement
What do the Debug runtimes tell you?

Quote:
Direct3D9: (WARN) :D3D Unsupported for the adapter format passed to CheckDeviceFormat
Direct3D9: (WARN) :D3D Unsupported for the adapter format passed to CheckDeviceFormat
Direct3D9: (WARN) :D3D Unsupported for the adapter format passed to CheckDeviceFormat
Direct3D9: (WARN) :D3D Unsupported for the adapter format passed to CheckDeviceFormat
Direct3D9: (WARN) :D3D Unsupported for the adapter format passed to CheckDeviceFormat
Direct3D9: (WARN) :D3D Unsupported for the adapter format passed to CheckDeviceFormat
Direct3D9: (WARN) :D3D Unsupported for the adapter format passed to CheckDeviceFormat
Direct3D9: (WARN) :D3D Unsupported for the adapter format passed to CheckDeviceFormat
Direct3D9: (WARN) :D3D Unsupported for the adapter format passed to CheckDeviceFormat
Direct3D9: (ERROR) :D3DFMT_UNKNOWN is not a valid format.
Direct3D9: (INFO) :======================= Hal HWVP device selected

Direct3D9: (INFO) :HalDevice Driver style b

Direct3D9: :BackBufferCount not specified, considered default 1
Direct3D9: :DoneExclusiveMode
Direct3D9: (INFO) :Using FF to VS converter

Direct3D9: (INFO) :Using FF to PS converter

D3D9 Helper: Warning: Default value for D3DRS_POINTSIZE_MAX is 2.19902e+012f, not 4.91616e-316f. This is ok.
Direct3D9: (ERROR) :Invalid vertex declaration.

D3D9 Helper: IDirect3DDevice9::ValidateDevice failed: E_FAIL
.\Sources\R3DDevice.cpp(94): Device validation failed hr=E_FAIL (0x80004005)
D3DX: Unicode support: 1


This is pretty weird. I have a procedure that checks for valid formats in R3DDevice.cpp and it seems to stop at D3DFMT_UNKNOWN. Invalid vertex declaration ? D3DRS_POINTSIZE_MAX ? Does it have something to do with D3DPRESENT_PARAMETERS ?
Quote:Original post by Alex Hrin

Quote:
Direct3D9: (WARN) :D3D Unsupported for the adapter format passed to CheckDeviceFormat
Direct3D9: (WARN) :D3D Unsupported for the adapter format passed to CheckDeviceFormat
Direct3D9: (WARN) :D3D Unsupported for the adapter format passed to CheckDeviceFormat
Direct3D9: (WARN) :D3D Unsupported for the adapter format passed to CheckDeviceFormat
Direct3D9: (WARN) :D3D Unsupported for the adapter format passed to CheckDeviceFormat
Direct3D9: (WARN) :D3D Unsupported for the adapter format passed to CheckDeviceFormat
Direct3D9: (WARN) :D3D Unsupported for the adapter format passed to CheckDeviceFormat
Direct3D9: (WARN) :D3D Unsupported for the adapter format passed to CheckDeviceFormat
Direct3D9: (WARN) :D3D Unsupported for the adapter format passed to CheckDeviceFormat
Direct3D9: (ERROR) :D3DFMT_UNKNOWN is not a valid format.
Direct3D9: (INFO) :======================= Hal HWVP device selected

Direct3D9: (INFO) :HalDevice Driver style b

Direct3D9: :BackBufferCount not specified, considered default 1
Direct3D9: :DoneExclusiveMode
Direct3D9: (INFO) :Using FF to VS converter

Direct3D9: (INFO) :Using FF to PS converter

D3D9 Helper: Warning: Default value for D3DRS_POINTSIZE_MAX is 2.19902e+012f, not 4.91616e-316f. This is ok.
Direct3D9: (ERROR) :Invalid vertex declaration.

D3D9 Helper: IDirect3DDevice9::ValidateDevice failed: E_FAIL
.\Sources\R3DDevice.cpp(94): Device validation failed hr=E_FAIL (0x80004005)
D3DX: Unicode support: 1


This is pretty weird. I have a procedure that checks for valid formats in R3DDevice.cpp and it seems to stop at D3DFMT_UNKNOWN. Invalid vertex declaration ? D3DRS_POINTSIZE_MAX ? Does it have something to do with D3DPRESENT_PARAMETERS ?
The unknown format error message means you're passing D3DFMT_UNKNOWN as a format somewhere. Double check everywhere you pass D3DFORMAT in and make sure it's not D3DFMT_UNKNOWN.

The invalid vertex declaration means that you haven't called IDirect3DDevice9::SetFVF() or IDirect3DDevice9::SetVertexDeclaration() with a valid value. That seems to be why ValidateDevice() is failing (As a guess).

The pointsize thing is nothing to worry about; I believe NVidia drivers set the default value of that to a different value than usual. You can just ignore it.
It may not be the cause of your problem, but your format checking loop only checks for success. If your loop does not find a compatible format, you end up with whatever stencilindex=1 and surfaceindex=1 are, even if they're not compatible.

Please don't PM me with questions. Post them in the forums for everyone's benefit, and I can embarrass myself publicly.

You don't forget how to play when you grow old; you grow old when you forget how to play.

I checked some other things around here and found what is maybe a deeper level of the problem. IDirect3DDevice9::SetFVF() or Direct3DDevice9::SetVertexDeclaration() are probably being called by D3DXLoadMeshFromX() when it tries to load the mesh but I checked for D3DFORMAT and D3DPRESENT_PARAMETERS should receive D3DFMT_D24S8 (75) for the DepthStencilFormat and D3DFMT_X8R8G8B8 (22) for the backbuffer format.
Those are the values the loop returns. In the image below it can clearly be seen that even after the execution of:

ZeroMemory(&D3DPresentParams, sizeof D3DPRESENT_PARAMETERS);D3DPresentParams.BackBufferHeight = Height;D3DPresentParams.BackBufferWidth = Width;D3DPresentParams.Windowed = TRUE;D3DPresentParams.AutoDepthStencilFormat = DetectedDepthFormat;


D3DPresentParams.AutoDepthStencilFormat is 585 (and I can't imagine why since this is the only time the code modifies it) even though it should take on DetectedDepthFormat's value (the watch on the lower left pretty much speaks for itself ). D3DPresentParams is not a pointer and this is the first portion of the code that uses it. It seems that it can't take on new values.

D3DPRESENT_PARAMETERS

Sorry for the stupid question but do I have to call IDirect3DDevice9::SetFVF() before validating the device ? I never did it before and it seemed to work fine until now.

About the loop only returning success: yes, I know it's incomplete but for now I only want it to work. I'm testing it on a ATI RadeonHD 2900XT and those structures (BackBufferFormats[] and StencilBufferFormats[]) hold all values listed in the SDK for backbuffers and stencil buffers so it has a very slim chance of not finding anything for now.
Quote:do I have to call IDirect3DDevice9::SetFVF() before validating the device ?

You shouldn't. In fact, it'd be difficult since you haven't created the device yet (I assume)! [smile]

EDIT: Also, D3DFMT_UNKNOWN has a value of 0, not 585. Somethings amiss.

Please don't PM me with questions. Post them in the forums for everyone's benefit, and I can embarrass myself publicly.

You don't forget how to play when you grow old; you grow old when you forget how to play.

This topic is closed to new replies.

Advertisement