Reading from the CPU

Started by
6 comments, last by piluve 6 years, 8 months ago

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!

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."

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 :) 

@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.

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?

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?

@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.

This topic is closed to new replies.

Advertisement