CreateVertexBuffer fails

Started by
7 comments, last by langguy 20 years, 8 months ago
I''ve never had this problem before and it seemed to hit me out of nowhere. I was implementing a camera class into my code, when suddenly,
device->CreateVertexBuffer(4096 * sizeof(Vertex), 0, D3DFVF_Vertex, D3DPOOL_DEFAULT, &vbTerrain, NULL 
fails on me. It says that there is an access violation during runtime. I know it isn''t because my device is null, because I''ve tried checking for that immediately before this line, and I set several render states several lines before this call. However, my vertex buffer (vbTerrain) seems to get allocated incorrectly. I can''t ZeroMemory it (that throws an access violation too), and declaring another vertex buffer with a different name yields the same result. I also tried undoing all the changes I made up to before I started implementing the camera class and it still wasn''t working. What could possibly be wrong? Like I said, it just started doing this seemingly for no reason.
Advertisement

Forgive me if I''m being patronising (just in case!), but vbTerrain points to an interface of vertex buffer object. You need to lock the vertex buffer to return a memory pointer you can write to.

As a side note, if you are only writing to the buffer once, you might want to make it static when you create it, ensuring the driver will place it in the most optimal memory.
Perhaps, but that doesn''t really help me now. I can''t lock the vertex buffer before I create it (while it''s still uninitialized).

However, upon further inspection, I saw that the access violation notification labels 0x0f8b0f8a as the culprit, which is my device. I find this kinda odd, because if I call CreateVertexBuffer in the same function as I create my device, it doesn''t throw an error until I try using the vertex buffer outside of that function. Does LPDIRECT3DDEVICE9 have some kind of issue with scope? Here''s my source for creating my device:
LPDIRECT3D9 d3d = NULL;LPDIRECT3DDEVICE9 device = NULL;...bool Init(HWND hwnd){	D3DDISPLAYMODE DisplayMode;	D3DPRESENT_PARAMETERS params;	D3DCAPS9 caps;	ZeroMemory(&params, sizeof(params));	ZeroMemory(&device, sizeof(LPDIRECT3DDEVICE9));	d3d = Direct3DCreate9(D3D_SDK_VERSION);	if(d3d == NULL) return false;	if(FAILED(d3d->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &DisplayMode))) return false;	if(FAILED(d3d->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &caps))) return false;	DWORD vProc = 0;	if(caps.VertexProcessingCaps != 0)		vProc |= D3DCREATE_HARDWARE_VERTEXPROCESSING;	else		vProc |= D3DCREATE_SOFTWARE_VERTEXPROCESSING;	DWORD dwMax = caps.MaxPrimitiveCount;	params.Windowed = true;	params.SwapEffect = D3DSWAPEFFECT_DISCARD;	params.BackBufferCount = 1;	params.BackBufferFormat = DisplayMode.Format;	params.EnableAutoDepthStencil = true;	params.AutoDepthStencilFormat = D3DFMT_D16;	if(FAILED(d3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd, vProc, &params, &device))) return false;	if(device == NULL) return false;	device->SetRenderState(D3DRS_ZENABLE, TRUE);	device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);	device->SetRenderState(D3DRS_LIGHTING, FALSE);	D3DXMATRIXA16 proj;	D3DXMatrixPerspectiveFovLH(&proj, 45.0f, 1.0f, 0.1f, 500.0f);	device->SetTransform(D3DTS_PROJECTION, &proj);		D3DXMATRIXA16 View;	D3DXVECTOR3 Eye(0.0f, 5.0f, -37.0f);	D3DXVECTOR3 LookAt(0.0f, 0.0f, 0.0f);	D3DXVECTOR3 Up(0.0f, 1.0f, 0.0f);	D3DXMatrixLookAtLH(&View, &Eye, &LookAt, &Up);		device->SetTransform(D3DTS_VIEW, &View);	return true;}

Well I guess that method looks ok - except you don''t need to zeromemory the device pointer (just tell it to = 0 and its zeroed as its a pointer).

So my guess is your vertex buffer pointer is out of scope somewhere. Of course, its always possible that the device is being invalidated by a mode change or "resize" operation.
I tried changing that ZeroMemory line to device = 0;, but that didn''t seem to help. I don''t think my vertex buffer is out of scope, because my device, vertex buffer, and a few other D3D-related objects are global (I know this isn''t good practice but I didn''t feel like making everything object-oriented at my first crack at index buffers).
Well really we need more code, because what you''ve shown isn''t the whole story. You need to post what happens in your message loop, because resizing the display can invalidate device objects, which might cause the kind of issue you speak of.
Here's my code, but I can't even get it to render one frame before CreateVertexBuffer fails:
// TerrainViewer.cpp : Defines the entry point for the application.//#include "stdafx.h"#include "TerrainViewer.h"#include "d3d9.h"#include "d3dx9.h"#include "CCamera.h"#pragma comment(lib, "d3d9.lib")#pragma comment(lib, "d3dx9.lib")#define D3DFVF_Vertex (D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX1)#define MAX_LOADSTRING 100// Global Variables:HINSTANCE hInst;								// current instanceTCHAR szTitle[MAX_LOADSTRING];					// The title bar textTCHAR szWindowClass[MAX_LOADSTRING];			// the main window class name// Forward declarations of functions included in this code module:ATOM				MyRegisterClass(HINSTANCE hInstance);BOOL				InitInstance(HINSTANCE, int);LRESULT CALLBACK	WndProc(HWND, UINT, WPARAM, LPARAM);LRESULT CALLBACK	About(HWND, UINT, WPARAM, LPARAM);HWND				hWindow;// Direct3D objectsLPDIRECT3D9 d3d = NULL;LPDIRECT3DDEVICE9 device = NULL;LPDIRECT3DVERTEXBUFFER9 vbTerrain;LPDIRECT3DINDEXBUFFER9 ibTerrain = NULL;// GlobalsWORD sIndices[(6 * 63 * 63)];	//these are the order in which to draw the vertices// Function declarationsbool Init(HWND hwnd);void Frame();void ShutDown();bool InitTerrain();void GetInput();struct Vertex{	float x, y, z;	D3DCOLOR diffuse;	float u, v;};Vertex TerrainData[64 * 64];//these are the actual vertices int APIENTRY _tWinMain(HINSTANCE hInstance,                     HINSTANCE hPrevInstance,                     LPTSTR    lpCmdLine,                     int       nCmdShow){ 	// TODO: Place code here.	MSG msg;	HACCEL hAccelTable;	// Initialize global strings	LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);	LoadString(hInstance, IDC_TERRAINVIEWER, szWindowClass, MAX_LOADSTRING);	MyRegisterClass(hInstance);	// Perform application initialization:	if (!InitInstance (hInstance, nCmdShow)) 	{		return FALSE;	}	hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_TERRAINVIEWER);	bool bCont = Init(hWindow);	while(bCont)	{		PeekMessage(&msg, NULL, NULL, NULL, PM_REMOVE);		if(msg.message == WM_QUIT)			bCont = false;		else		{			Frame();			TranslateMessage(&msg);			DispatchMessage(&msg);		}	}	ShutDown();	return 0;}////  FUNCTION: MyRegisterClass()////  PURPOSE: Registers the window class.////  COMMENTS:////    This function and its usage are only necessary if you want this code//    to be compatible with Win32 systems prior to the 'RegisterClassEx'//    function that was added to Windows 95. It is important to call this function//    so that the application will get 'well formed' small icons associated//    with it.//ATOM MyRegisterClass(HINSTANCE hInstance){	WNDCLASSEX wcex;	wcex.cbSize = sizeof(WNDCLASSEX); 	wcex.style			= CS_HREDRAW | CS_VREDRAW;	wcex.lpfnWndProc	= (WNDPROC)WndProc;	wcex.cbClsExtra		= 0;	wcex.cbWndExtra		= 0;	wcex.hInstance		= hInstance;	wcex.hIcon			= LoadIcon(hInstance, (LPCTSTR)IDI_TERRAINVIEWER);	wcex.hCursor		= LoadCursor(NULL, IDC_ARROW);	wcex.hbrBackground	= (HBRUSH)(COLOR_WINDOW+1);	wcex.lpszMenuName	= (LPCTSTR)IDC_TERRAINVIEWER;	wcex.lpszClassName	= szWindowClass;	wcex.hIconSm		= LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL);	return RegisterClassEx(&wcex);}////   FUNCTION: InitInstance(HANDLE, int)////   PURPOSE: Saves instance handle and creates main window////   COMMENTS:////        In this function, we save the instance handle in a global variable and//        create and display the main program window.//BOOL InitInstance(HINSTANCE hInstance, int nCmdShow){   HWND hWnd;   hInst = hInstance; // Store instance handle in our global variable   hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,      CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);   hWindow = hWnd;   if (!hWnd)   {      return FALSE;   }   ShowWindow(hWnd, nCmdShow);   UpdateWindow(hWnd);   return TRUE;}////  FUNCTION: WndProc(HWND, unsigned, WORD, LONG)////  PURPOSE:  Processes messages for the main window.////  WM_COMMAND	- process the application menu//  WM_PAINT	- Paint the main window//  WM_DESTROY	- post a quit message and return////LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam){	int wmId, wmEvent;	PAINTSTRUCT ps;	HDC hdc;	switch (message) 	{	case WM_COMMAND:		wmId    = LOWORD(wParam); 		wmEvent = HIWORD(wParam); 		// Parse the menu selections:		switch (wmId)		{		case IDM_ABOUT:			DialogBox(hInst, (LPCTSTR)IDD_ABOUTBOX, hWnd, (DLGPROC)About);			break;		case IDM_EXIT:			DestroyWindow(hWnd);			break;		default:			return DefWindowProc(hWnd, message, wParam, lParam);		}		break;	case WM_PAINT:		hdc = BeginPaint(hWnd, &ps);		// TODO: Add any drawing code here...		EndPaint(hWnd, &ps);		break;	case WM_DESTROY:		PostQuitMessage(0);		break;	default:		return DefWindowProc(hWnd, message, wParam, lParam);	}	return 0;}// Message handler for about box.LRESULT CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam){	switch (message)	{	case WM_INITDIALOG:		return TRUE;	case WM_COMMAND:		if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) 		{			EndDialog(hDlg, LOWORD(wParam));			return TRUE;		}		break;	}	return FALSE;}bool Init(HWND hwnd){	D3DDISPLAYMODE DisplayMode;	D3DPRESENT_PARAMETERS params;	D3DCAPS9 caps;	ZeroMemory(¶ms, sizeof(params));	//ZeroMemory(&device, sizeof(LPDIRECT3DDEVICE9));	device = 0;	d3d = Direct3DCreate9(D3D_SDK_VERSION);	if(d3d == NULL) return false;	if(FAILED(d3d->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &DisplayMode))) return false;	if(FAILED(d3d->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &caps))) return false;	DWORD vProc = 0;	if(caps.VertexProcessingCaps != 0)		vProc |= D3DCREATE_HARDWARE_VERTEXPROCESSING;	else		vProc |= D3DCREATE_SOFTWARE_VERTEXPROCESSING;	DWORD dwMax = caps.MaxPrimitiveCount;	params.Windowed = true;	params.SwapEffect = D3DSWAPEFFECT_DISCARD;	params.BackBufferCount = 1;	params.BackBufferFormat = DisplayMode.Format;	params.EnableAutoDepthStencil = true;	params.AutoDepthStencilFormat = D3DFMT_D16;	if(FAILED(d3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd, vProc, ¶ms, &device))) return false;	if(device == NULL) return false;	device->SetRenderState(D3DRS_ZENABLE, TRUE);	device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);	device->SetRenderState(D3DRS_LIGHTING, FALSE);	if(!InitTerrain())		return false;	D3DXMATRIXA16 proj;	D3DXMatrixPerspectiveFovLH(&proj, 45.0f, 1.0f, 0.1f, 500.0f);	device->SetTransform(D3DTS_PROJECTION, &proj);		D3DXMATRIXA16 View;	D3DXVECTOR3 Eye(0.0f, 5.0f, -37.0f);	D3DXVECTOR3 LookAt(0.0f, 0.0f, 0.0f);	D3DXVECTOR3 Up(0.0f, 1.0f, 0.0f);	D3DXMatrixLookAtLH(&View, &Eye, &LookAt, &Up);		device->SetTransform(D3DTS_VIEW, &View);	Camera.SetCamera(0.0f, 10.0f, -36.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f);	return true;}void Frame(){	device->Clear(0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);	device->BeginScene();	device->SetStreamSource(0, vbTerrain, 0, sizeof(Vertex));	device->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 64 * 64, 0, 2 * 63 * 63);	device->EndScene();	device->Present(NULL, NULL, NULL, NULL);}void ShutDown(){	if(device != NULL)	{		device->Release();		device = NULL;	}	if(d3d != NULL)	{		d3d->Release();		d3d = NULL;	}	if(vbTerrain != NULL)	{		vbTerrain->Release();		vbTerrain = NULL;	}	if(ibTerrain != NULL)	{		ibTerrain->Release();		ibTerrain = NULL;	}}bool InitTerrain(){	int nCount = 0;	ZeroMemory(TerrainData, sizeof(TerrainData));	for(int i = 0; i < 64; i++)	{		for(int j = 0; j < 64; j++)		{			nHeightArray[i][j] = 0;			Vertex vTemp = {(float)(-32 + i), 0, (float)(-32 + j), D3DCOLOR_XRGB(255, 255, 255), 0.0f, 0.0f};			TerrainData[nCount++] = vTemp;		}	}	nCount = 0;	ZeroMemory(sIndices, sizeof(sIndices));	for(int i = 0; i < 4032; i += 64)	{		for(int j = 0; j < 64; j++)		{			sIndices[nCount++] = i + j;			sIndices[nCount++] = i + j + 1;			sIndices[nCount++] = i + j + 64;			sIndices[nCount++] = i + j + 64 + 1;			sIndices[nCount++] = i + j + 64;			sIndices[nCount++] = i + j + 1;		}	}		//Create Vertex Buffer	vbTerrain = NULL;	//ZeroMemory(vbTerrain, sizeof(vbTerrain));	if(FAILED(device->CreateVertexBuffer(4096 * sizeof(Vertex), 0, D3DFVF_Vertex, D3DPOOL_DEFAULT, &vbTerrain, NULL)))		return false;	Vertex *Vertices;	if(FAILED(vbTerrain->Lock(0, sizeof(TerrainData), (void**)&Vertices, 0)))		return false;	memcpy(Vertices, TerrainData, sizeof(TerrainData));	vbTerrain->Unlock();	//Create Index Buffer	int nIndexListSize = sizeof(WORD) * nCount;	if(FAILED(device->CreateIndexBuffer(nIndexListSize, 0, D3DFMT_INDEX16, D3DPOOL_DEFAULT, &ibTerrain, NULL)))		return false;	VOID* indices;	if(FAILED(ibTerrain->Lock(0, 0, (VOID**)&indices, 0)))		return false;	memcpy(indices, sIndices, sizeof(sIndices));	ibTerrain->Unlock();	device->SetIndices(ibTerrain);	device->SetFVF(D3DFVF_Vertex);	device->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME);	return true;}


[edited by - langguy on August 18, 2003 4:34:56 PM]

Ok, well I''ve got some problems with your code, the first of which is you are more or less ALWAYS going to get an error when you shutdown, because you are deleting your device before you go and delete the vertex buffer. So for starters that could be cleaned up. Secondly, try handling a WM_SIZE message in your message loop. This message should basically shutdown, then recreate the device context and all of the device dependant objects you own.

The thing is, its possible to invalidate device objects on WM_SIZE messages. Basically you are not guaranteed any given IDirect3DDevice9 pointer is valid after this operation.
okay, I changed the order in which my objects are released....but I'm not gonna start worrying about handling WM_SIZE quite yet.

While writing this reply, I found out what's crashing my program:

for(int i = 0; i < 4032; i += 64){	for(int j = 0; j < 64; j++)	{		sIndices[nCount++] = i + j;		sIndices[nCount++] = i + j + 1;		sIndices[nCount++] = i + j + 64;		sIndices[nCount++] = i + j + 64 + 1;		sIndices[nCount++] = i + j + 64;		sIndices[nCount++] = i + j + 1;	}}  

If I comment out one of these "sIndices[nCount++] = ..." lines, my code proceeds as it should (minus the fact my index buffer isn't completely filled.) This is kinda odd, because this block of code doesn't seem to have anything to do with whether device and vbTerrain are valid or not.

EDIT: Yes! I fixed it! I changed j < 64; to j < 63;. I guess I was writing my indices beyond the memory for sIndices and into device and vbTerrain!

[edited by - langguy on August 18, 2003 5:27:47 PM]

This topic is closed to new replies.

Advertisement