Advertisement

D3D12 Vertex buffer isnt uploading correctly to GPU

Started by December 19, 2023 07:46 PM
4 comments, last by songs_made_right 10 months, 3 weeks ago

I have been having an issue where my default heap is only recieving the first vertex of my vertex array, I am uploading the vertex correctly its just the other 2 vertices for some reason are not copying over

Code for making the two heaps and sending over the vertex data

Resource::Resource(IDXGInterface* IDXGinterface, UINT64 BufferSize) : m_IDXGinterface(IDXGinterface)
{

	// m_ResourceDesc is stored elsewhere
	m_ResourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
	m_ResourceDesc.Alignment = 0;
	m_ResourceDesc.Width = BufferSize;
	m_ResourceDesc.Height = 1;
	m_ResourceDesc.DepthOrArraySize = 1;
	m_ResourceDesc.MipLevels = 1;
	m_ResourceDesc.Format = DXGI_FORMAT_UNKNOWN;
	m_ResourceDesc.SampleDesc.Count = 1;
	m_ResourceDesc.SampleDesc.Quality = 0;
	m_ResourceDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
	m_ResourceDesc.Flags = D3D12_RESOURCE_FLAG_NONE;

	D3D12_HEAP_PROPERTIES heapProp;
	heapProp.Type = D3D12_HEAP_TYPE_DEFAULT;
	heapProp.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
	heapProp.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
	heapProp.CreationNodeMask = 1;
	heapProp.VisibleNodeMask = 1;


	// default heap that will store the vertex data has it's interface stored elsewhere
	IDXGinterface->m_Device->CreateCommittedResource(&heapProp, D3D12_HEAP_FLAG_NONE, &m_ResourceDesc, D3D12_RESOURCE_STATE_COPY_DEST, nullptr, IID_PPV_ARGS(&m_DestRes));
	
	IDXGinterface->m_Device->GetCopyableFootprints(&m_ResourceDesc, 0, 1, 0, m_Layouts, m_NumRows, m_RowSizeInBytes, m_TotalSizeInBytes);

	m_DestRes->SetName(L"Buffer resource heap");
}

void Resource::SendToResource(const void* pBufferData, CommandQueue* CmdQueue)
{
	

	D3D12_RANGE range;
	range.Begin = 0;
	range.End = 0;

	D3D12_HEAP_PROPERTIES heapProp;
	heapProp.Type = D3D12_HEAP_TYPE_UPLOAD;
	heapProp.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
	heapProp.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
	heapProp.CreationNodeMask = 1;
	heapProp.VisibleNodeMask = 1;
	

	// Upload heap is also stored elsewhere
	m_IDXGinterface->m_Device->CreateCommittedResource(&heapProp, D3D12_HEAP_FLAG_NONE, &m_ResourceDesc, D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&m_uploadHeap));

	m_uploadHeap->SetName(L"Vertex buffer upload heap");

	BYTE* pData;
	ThrowIfFailed(m_uploadHeap->Map(0, NULL, reinterpret_cast<void**>(&pData)));

	memcpy(pData, pBufferData, sizeof(pBufferData));

	m_uploadHeap->Unmap(0, nullptr);

	size_t s = sizeof(pBufferData);

	

	// I am thinking the error is here but I cannot figure out what it would be
	CmdQueue->CopyBufferRegion(m_DestRes.Get(), 0, m_uploadHeap.Get(), 0, sizeof(pBufferData));
	
	CmdQueue->SetTransitionResourceBarrier(m_DestRes, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER);
}

The vertex data is stored on an array of type Vertex which the definition of Vertex is

struct Vertex
{
	Vector3 position;
};	

Vector3 is my custom Vector class with the following layout

class Vector3
{
public:
	float v[3] = { 0, 0, 0 };
} // there are additional mathematical operations but I did not include them

I was using RenderDoc to debug my program as honestly I have try so many different things and just cant figure it out. this lead to the conclusion that maybe im uploading into the buffer wrong as looking at the vertex data only the first entry in my vertex array is being sent over

For contex the vertex shader adds 1.0 to each vertex's w component

Any help would be apperciated, and I will provide any addition information if needed, please be nice as I am trying my best and I really just wanna figure this out thanks in advance 🙂

songs_made_right said:
memcpy(pData, pBufferData, sizeof(pBufferData));

sizeof gives you the size of the variable, not it's content.

sizeof(pBufferData) => sizeof(const void*) => 8 (or 4, if you are still stuck on 32 bit).

I suspect you are used to sizeof returning the byte-size of an array, when you actually give it an array-variable?

int[10] x = { …};
sizeof(x); // => returns sizeof(int) * 10

This only works because the compiler can see the exact array extend from the variable (int[10]), once you switch to a pointer, you lose that information.

Thus, you are only copying over the first 8 bytes from the buffer instead of it's size. You need to pass in the size of what pBufferData points to, preferable with something like https://en.cppreference.com/w/cpp/container/span​ if you care about code-design/safety - or just an additional parameter if you don't.

Advertisement

@Juliean Thank you so much! turns out that was the issue, how embarassing haha, well im just glad its fixed now at least. I had a feeling it might've been the sizeof but I just never got around to trying it. atleast it is over now and I can move on with my life

I'd strongly consider revising that interface so it doesn't take a void*. That's a paradigm from the 80's and early 90's, and is extremely prone to bugs, like the one discovered above.

Usually you'll pass a pointer or reference to a container object, like your IDXGInterface* in the earlier function. You shouldn't ever need to cast like you do with dynamic_cast in your code, that's a typical sign of a serious design flaw. Build your interfaces and systems to take specific interface types or classes, and any function that accepts a pointer or reference to a base class should be built in a way that they can use an unknown derived class without knowing it or changing anything.

@frob That makes sense! ill will keep that in mind in the future!

This topic is closed to new replies.

Advertisement