How to ensure page fault?
The buffer and its heap is released soon after creation, so the descriptor points to an incorrect address, which triggers the page fault.
Couldn't some subsequent allocation get or overlap that address?
Have you tried passing a root uav and just using some unlikely address (e.g., -1)?
Unfortunately you are right, there is no guarantee that the address won't be reused by some other resource and valid, so the crash will not happen.
I tried accessing the resource with various offsets, even gigabytes above its beginning, and it was even worse - it didn't crash at all. Accessing resources out of bounds is not an error in D3D12, maybe that is why. (Tested on RTX 3080, driver 537.13)
So, this solution is hacky and unreliable, as I said in README, but I don't know anything better. If you do, please provide a description or a pull request.
Yeah, fair enough.
I did a quick test and the gpu addresses seem to be recycled pretty quickly (not sure if this is implementation specific, but tested on an intel arc fwiw):
ID3D12Resource* upload = nullptr;
ID3D12Resource* readback = nullptr;
ID3D12Resource* uav1 = nullptr;
{
D3D12_HEAP_PROPERTIES props{ D3D12_HEAP_TYPE_UPLOAD };
D3D12_RESOURCE_DESC desc{};
desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
desc.Width = 4096;
desc.Height = 1;
desc.DepthOrArraySize = 1;
desc.MipLevels = 1;
desc.SampleDesc.Count = 1;
desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
CHECK_HR(device->CreateCommittedResource(&props, D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_COMMON, nullptr, IID_PPV_ARGS(&upload)));
props.Type = D3D12_HEAP_TYPE_DEFAULT;
desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
ID3D12Resource* uav0 = nullptr;
CHECK_HR(device->CreateCommittedResource(&props, D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_COPY_DEST, nullptr, IID_PPV_ARGS(&uav0)));
CHECK_HR(device->CreateCommittedResource(&props, D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_COPY_DEST, nullptr, IID_PPV_ARGS(&uav1)));
printf("upload: 0x%llx\n", upload->GetGPUVirtualAddress());
printf("uav0: 0x%llx\n", uav0->GetGPUVirtualAddress());
printf("uav1: 0x%llx\n", uav1->GetGPUVirtualAddress());
if (uav0->Release() != 0) {
printf("error: uav0 refcount unexpected.\n");
return 1;
}
props.Type = D3D12_HEAP_TYPE_READBACK;
desc.Flags = D3D12_RESOURCE_FLAG_NONE;
CHECK_HR(device->CreateCommittedResource(&props, D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_COMMON, nullptr, IID_PPV_ARGS(&readback)));
printf("readback: 0x%llx\n", readback->GetGPUVirtualAddress());
}
upload: 0xffffb80200000000
uav0: 0xffffb80200010000
uav1: 0xffffb80200020000
readback: 0xffffb80200010000
Anyway, my idea was to use a root uav parameter instead of a descriptor table, to give more flexibility in passing bad addresses e.g.:
cmdList->SetComputeRootSignature(rootSignature);
cmdList->SetComputeRootUnorderedAccessView(0, (D3D12_GPU_VIRTUAL_ADDRESS) 0xfffffffffffffff0ull);
cmdList->Dispatch(1, 1, 1);
But so far everything I pass seems to be happily ignored, no seg faults.
Unlike descriptors, an address passed like this is known to the CPU, so it can be validated and reported as incorrect by D3D Debug Layer, possibly also rejected by D3D12 runtime. This may be the reason it doesn't crash.