Jump to content
  • Advertisement
Sign in to follow this  
piluve

DX12 Reading from the CPU

This topic is 394 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hello,

I'm working on a system based on Structured Buffers, the idea is that they can be used in the GPU as UAV/SRV and then the data can be read back in the CPU. This system is used to do some queries in my application. 

First I have two main resources:

+ Default Resource: This will be the resource used by the GPU.

+ Upload Resource: In case I want to upload data from the CPU I'll use this as an intermediate

+ Double Buffered ReadBack Resources: I have two Read Back buffers to copy data from the GPU to the CPU.

 

Let me show some code:

const void* OpenReadBuffer()
{
	HRESULT res = S_FALSE;

	if (mFirstUse)
		mFirstUse = false;
	else
		mCbFence.WaitUntilCompleted(renderPlatform);

	// Map from the last frame
	const CD3DX12_RANGE readRange(0, 0);
	res = mBufferReadFront->Map(0, &readRange, reinterpret_cast<void**>(&mReadSrc));
	return mReadSrc;
}

void CloseReadBuffer()
{
	const CD3DX12_RANGE readRange(0, 0);
	mBufferReadFront->Unmap(0, &readRange);
}

void CopyToReadBuffer()
{
	// Schedule a copy for the next frame
	commandList->CopyResource(mBufferReadBack, mBufferDefault);
	
	mCbFence.Signal(renderPlatform);

	// Swap it!
	std::swap(mBufferReadBack, mBufferReadFront);
}

 

This is how I create the different resources:

// Default
D3D12_RESOURCE_FLAGS bufferFlags = computable ? D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS : D3D12_RESOURCE_FLAG_NONE;
res = device->CreateCommittedResource
(
  &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT),
  D3D12_HEAP_FLAG_NONE,
  &CD3DX12_RESOURCE_DESC::Buffer(mTotalSize,bufferFlags),
  D3D12_RESOURCE_STATE_GENERIC_READ,
  nullptr,
  IID_PPV_ARGS(&mBufferDefault)
);

// Upload
res = device->CreateCommittedResource
(
  &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD),
  D3D12_HEAP_FLAG_NONE,
  &CD3DX12_RESOURCE_DESC::Buffer(mTotalSize),
  D3D12_RESOURCE_STATE_GENERIC_READ,
  nullptr,
  IID_PPV_ARGS(&mBufferUpload)
);

// Read Back
res = device->CreateCommittedResource
(
  &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_READBACK),
  D3D12_HEAP_FLAG_NONE,
  &CD3DX12_RESOURCE_DESC::Buffer(mTotalSize),
  D3D12_RESOURCE_STATE_COPY_DEST,
  nullptr,
  IID_PPV_ARGS(&mBufferReadBack)
);

 

I'm using a Fence to be 100% sure that it is synchronised, I could have more that 2 buffers but at the moment I would like to keep it simple.

The values that I get from OpenReadBuffer() are all 0.

If I debug it, it looks like the Read Back Buffers have some valid data.

What could be the issue?

Thanks!

Edited by piluve

Share this post


Link to post
Share on other sites
Advertisement

If you want to specify that you'll read the entire contents of the buffer when calling Map, then you can pass NULL as the "pReadRange" parameter. Passing a range where End <= Begin means that you won't be reading any data, which isn't what you want:

"This indicates the region the CPU might read, and the coordinates are subresource-relative. A null pointer indicates the entire subresource might be read by the CPU. It is valid to specify the CPU won't read any data by passing a range where End is less than or equal to Begin."

Share this post


Link to post
Share on other sites

MJP is "write", but try to not use nullptr for a range, because the debug layer warn it may be a performance issue to map a full resource and an unwanted action. You can just send { 0, size } to mute the message :) 

Share this post


Link to post
Share on other sites

@galop1n and @MJP are correct in that the range is wrong... but that's not your problem. That only matters on systems which don't have cache coherency, which I can pretty much guarantee you're not using.

Since you claim that "while debugging, the data has valid values," I take that to mean that if you use breakpoints and inspect the data, you see correct contents, but if you let the app run normally, you don't. That sounds to me like your synchronization isn't actually working correctly, and when your breakpoint hits, the GPU continues executing and fills in the memory you're inspecting by the time you look at it.

Share this post


Link to post
Share on other sites

Hello @MJP, @galop1n, totally agree, now that you mention it, I mostly always use the same 0,0 range, I will change it just to be nice to the API.

Hi @SoldierOfLight , by debugging I was talking about a GPU debugger (like Visual Studio graphics debugger), I can see that the Read Back buffers had data, but then its al 0 (CPU side).

 

EDIT

I would like to point something, I've checking it and it looks like in most cases, this read back system is working just fine, but I have one case where it is returning invalid data. Could the problem be in other place, like the state of the resources? The thing is, Why I see valid data with the debugger?

Edited by piluve

Share this post


Link to post
Share on other sites

What OS version are you on? I'm currently aware of a bug where mapping a resource can cause it to incorrectly return 0s on some Windows 10 Insider builds. If you map the resource earlier and leave it mapped, does the problem go away?

Share this post


Link to post
Share on other sites

@SoldierOfLight I'm using Windows 10 Pro (with the latest patch I guess), I tried mapping once the ReadBack buffers but getting same results :C. I'll dig around this one that is failing and try to find out why.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!