Sign in to follow this  
HanSoL0

Dynamic VB Crash Problem

Recommended Posts

I know that this is a problem stemming from my own pathetic ignorance of dynamic vertex buffers, but I've tried a hundred different things and searched these forums for answers and can't seem to get this to work. I'm trying to fix my missile trails, which are dynamically created vertex buffers that create a sort of "ribbon" that follows my missiles. I've had the code working beautifully on all nVidia cards for a while now, and I'm trying to fix a crash-to-desktop problem I'm having on most ATI cards. Here is the code that works on nVidia cards, starting with the VB creation:
// Create the vertex buffer.
if (FAILED(g_pD3Ddevice->CreateVertexBuffer(MAXAMMO * MAX_VAPORTRAIL_SECTIONS * 2 * sizeof(VAPOR_VERTEX), 0, D3DFVF_VAPORVERTEX, D3DPOOL_DEFAULT, &pr_vaporVB)))
{
	MessageBox(NULL, "Vapor trail vertex buffer creation failure.", "Error", MB_OK);
}
And now the actual VB render code:
// Create all of the vertices for the vertex buffer
for (i = 0; i < MAXAMMO; i++)
{
	if (pr_is_active[i])
	{
		for (int c = 0; c < pr_maxVaporTrailSections; c++)
		{
			D3DXVECTOR3 tempvector, laservert0, laservert1;
			D3DXVECTOR3 laserEnd0;
			D3DXVECTOR3 laserEnd1;
			if (c == 0)
			{
				laserEnd0 = tail_positions[i][c+1];
				laserEnd1 = tail_positions[i][c];
			}
			else
			{
				laserEnd0 = tail_positions[i][c];
				laserEnd1 = tail_positions[i][c-1];
			}
			D3DXVECTOR3 firstPart = laserEnd0 - laserEnd1;
			D3DXVECTOR3 lastPart = laserEnd0 - cameraPos;
			D3DXVec3Cross(&tempvector, &firstPart, &lastPart);
			D3DXVec3Normalize(&tempvector, &tempvector);

			laservert0 = laserEnd0 + (tempvector * 1);
			laservert1 = laserEnd0 - (tempvector * 1);

			vaporVerts[(pr_maxVaporTrailSections * i + c) * 2].x				= laservert0.x; 
			vaporVerts[(pr_maxVaporTrailSections * i + c) * 2].y				= laservert0.y;
			vaporVerts[(pr_maxVaporTrailSections * i + c) * 2].z				= laservert0.z;
			vaporVerts[(pr_maxVaporTrailSections * i + c) * 2].diffuse		= 0xFFFFFFFF;
			vaporVerts[(pr_maxVaporTrailSections * i + c) * 2].tu			= 0.0f;
			vaporVerts[(pr_maxVaporTrailSections * i + c) * 2].tv			= (float)(1.0f / (pr_maxVaporTrailSections - 1) * c);

			vaporVerts[((pr_maxVaporTrailSections * i + c) * 2) + 1].x		= laservert1.x; 
			vaporVerts[((pr_maxVaporTrailSections * i + c) * 2) + 1].y		= laservert1.y;
			vaporVerts[((pr_maxVaporTrailSections * i + c) * 2) + 1].z		= laservert1.z;
			vaporVerts[((pr_maxVaporTrailSections * i + c) * 2) + 1].diffuse = 0xFFFFFFFF;
			vaporVerts[((pr_maxVaporTrailSections * i + c) * 2) + 1].tu		= 1.0f;
			vaporVerts[((pr_maxVaporTrailSections * i + c) * 2) + 1].tv		= (float)(1.0f / (pr_maxVaporTrailSections - 1) * c);
		}
	}
}

// Fill the vertex buffer.
VOID* pVertices;
if( FAILED(pr_vaporVB->Lock( 0, sizeof(vaporVerts), (BYTE**)&pVertices, D3DLOCK_DISCARD)))
    MessageBox(NULL, "Billboard vertex buffer locking failure.", "Error", MB_OK);

memcpy(pVertices, vaporVerts, sizeof(vaporVerts));

pr_vaporVB->Unlock();
It's that blasted memcpy line that crashes almost all the ATI cards I've tested it on, but this code run PERFECTLY on every nVidia card I've tested. I know ATI cards are more finicky about the correct parameters being in the DirectX calls, but I can't find where I'm going wrong. None of the DirectX calls are failing, and that memcpy operation crashes the game to the desktop. I could be doing this whole dynamic VB in the completely wrong way... Any ideas?

Share this post


Link to post
Share on other sites
When you create your VB, you need to specify D3DUSAGE_DYNAMIC as the Usage parameter. Otherwise, as the docs say, using either D3DLOCK_DISCARD or D3DLOCK_NOOVERWRITE when you lock the buffer should be invalid. nVidia is apparently just lazy when it comes to checking things like that.

Share this post


Link to post
Share on other sites
Oh, woops, I missed that. Thanks for the tip. However, this didn't seem to fix the problem, and now the memcpy operation crashes on both nVidia cards and ATI cards. [oh]

Share this post


Link to post
Share on other sites
Bummer. I've looked, but I can't see anything else. All your sizes look healthy, no off-by-one errors or similar that I can see. I suppose vaporVerts is an array on the stack, not dynamically allocated. Otherwise, sizeof(vaporVerts) would cause a problem. Of course, if that were the problem, then you wouldn't actually be able to see anything anyway, on either card. (I'm assuming that you had it running, and running correctly on nVidia cards previous to this.)

Share this post


Link to post
Share on other sites
Yes, vaporVerts is indeed an appropriately sized array created on the stack. Yeah, the frustrating part is that it did work perfectly before on nVidia cards (and it looked so cool! [smile]). What kinds of things could possibly cause memcpy to fail? Is there an alternative to this whole algorithm, perhaps one that eliminates the need to even use memcpy?

Share this post


Link to post
Share on other sites
Well, since you're using D3DLOCK_DISCARD, you should be able to lock the VB without stalling the GPU, so you could lock the VB before the loop, write the vertices directly into the VB, and then unlock at the end of the loop. D3DLOCK_DISCARD will, if necessary, create an alternate VB in memory for you to write to, while keeping the original as it was, in case the GPU is still using it. Then, when the original data is no longer needed, and the VB is unlocked, the GPU will get the new data. It's called DISCARD because you don't have access to the original data, due to the possibility of getting a new chunk of memory.

Share this post


Link to post
Share on other sites
I'm worried, though, that if it crashes on memcpy(), then simply avoiding memcpy() won't fix the real issue, whatever it may be. But it might be worth a try, I suppose.

Share this post


Link to post
Share on other sites
Oh, terrific. Please forgive my ignorance, but how would I write directly to the VB? Is this correct?

if( FAILED(pr_vaporVB->Lock( 0, sizeof(vaporVerts), (BYTE**)&vaporVerts, D3DLOCK_DISCARD)))
MessageBox(NULL, "Vapor trail vertex buffer locking failure.", "Error", MB_OK);

// fill the vaporVerts array like normal here, in the loop

pr_vaporVB->Unlock();

Share this post


Link to post
Share on other sites
You don't even need an allocated (heap or stack) array. Just a pointer. Then you provide the address of that pointer to Lock(), and access that pointer like an array, since Lock() will actually point you to already allocated memory.


VAPOR_VERTEX* pVertices;
if( FAILED(pr_vaporVB->Lock( 0, MAXAMMO * MAX_VAPORTRAIL_SECTIONS * 2 * sizeof(VAPOR_VERTEX), (VOID**)&pVertices, D3DLOCK_DISCARD)))
MessageBox(NULL, "Vapor trail vertex buffer locking failure.", "Error", MB_OK);

// fill the pVertices, as though it was an array, like normal here, in the loop

pr_vaporVB->Unlock();

Share this post


Link to post
Share on other sites
Yay! Agony, you rock my socks off. I was able to email the new .exe to my friend, and that algorithm worked perfectly on his nVidia card, and I bet it'll work on the ATI cards now that the memcpy is gone. Won't be able to try that until I get home from work, though. Thanks again! You rule. [grin]

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this