FRHIMemoryPool::FindFreeBlock failing to find free block when AlignedSize ends up larger than size of pool because Alignment is 176

Hey Epic Render friends!

I’m not sure if you can read the callstack above, but the verify in D3D12PoolAllocator.cpp is occasionally failing for me in editor:

verify(TryAllocateInternal(InSize, AllocationAlignment, AllocationResourceType, AllocationData));

Looks like the memory is not being allocated because the requested allocation size is 8MB and the alignment (for some weird reason) is 176 (might be coming from a multiple of stride- but I haven’t dug into it). So, it happily makes a new pool in FRHIPoolAllocator::TryAllocateInternal that should hold the 8MB (and in fact that’s the default size for the pool of this type) but then when it tries to actually allocate from the pool, FRHIMemoryPool::FindFreeBlock calls FRHIMemoryPool::GetAlignedSize which them bumps the size up to 8389120, which is over the size of the pool (8388608) and so allocation fails and then the editor eventually crashes.

Seems like there are some potential fixes here but I’m not sure which is right:

A) when we calculate the size of the pool, take this potential wonkiness into account- that means when FRHIPoolAllocator::TryAllocateInternal calls GetNewPool, instead of passing InSizeInBytes as the size, we need to call FRHIMemoryPool::GetAlignedSize(InSizeInBytes, PoolAlignment, InAllocationAlignment) first to get the actual size to pass into GetNewPool to make sure there is enough space. I think this might end up wasting memory though, so I’m thinking another option is better?

B) figure out a better alignment? The problem from what I see is the stride is 11 and it’s not easy to come up with a power of 2 that’s divisible by 11. heh in fact it’s impossible. Maybe this restriction is not necessary?

going with option A does seem to fix the problem for me for now at least!

Thanks for any input!

Steps to Reproduce
I’m in a situation where when I double click a data table to open it, the editor crashes because of a failure to allocate a d3d12 resource. probably related to other stuff I have in my level

Thanks for this report. There’s indeed a bit of a chicken-and-egg issue here with the allocation size changing due to alignment after we’ve decided that the pool can fit the requested size. However, I’m curious where that weird alignment value is coming from. That seems like a bug which triggers this edge case that we normally shouldn’t see. Are you able to set a breakpoint there when the alignment is 176 and see how we got to that value? I can’t see the callstack you mention, I only see the “verify(TryAllocateInternal(…” line in your post.

Thanks for the callstack and sorry for the late reply. I see that it’s an upload buffer, which is an important hint. We’re going to check the code and get back to you ASAP.

Hi,

the alignmnet probably comes from the least common mulitplier of 44 and 16 - the extra alignment of 16 is added for buffers in case they are needed as raw SRVs in ray tracing because those need to be 16 byte aligned. The alignment of 44 is needed if a structured buffer view needs to be created from the buffer because that’s defined in elements instead of offset. See last line of FD3D12Buffer::GetResourceDescAndAlignment.

But there is clearly a bug then when allocating a new pool for this allocation. You’re first suggestion makes sense and is probably the easiest fix - it will allocated more memory than needed but should only happen in very rare cases. Another option is make sure the extra alignment is not added when there is nothing allocated yet in the pool. FRHIMemoryPool::GetAlignedSize could not take the InAllocationAlignment into account when allocated pool size is empty.

Kind regards,

Kenzo

Hi!

Looks like it’s coming from a request to create a vertex buffer with a stride of 44.

[Image Removed]

I’m not sure why the callstack field is never visible to epic folks (I’ve had this problem before- UDN asks for a callstack and then never shows it to people…)

but here it is:

[UnrealEditor-D3D12RHI.dll] FD3D12PoolAllocator::AllocateResource(unsigned int, D3D12_HEAP_TYPE, const FD3D12ResourceDesc &, unsigned long long, unsigned int, ED3D12ResourceStateMode, D3D12_RESOURCE_STATES, const D3D12_CLEAR_VALUE *, const wchar_t *, FD3D12ResourceLocation &) D3D12PoolAllocator.cpp:378 [UnrealEditor-D3D12RHI.dll] FD3D12UploadHeapAllocator::AllocUploadResource(unsigned int, unsigned int, FD3D12ResourceLocation &) D3D12Allocation.cpp:1153 [UnrealEditor-D3D12RHI.dll] FD3D12Adapter::AllocateBuffer(FD3D12Device *, const D3D12_RESOURCE_DESC &, unsigned int, EBufferUsageFlags, ED3D12ResourceStateMode, D3D12_RESOURCE_STATES, unsigned int, FD3D12Buffer *, FD3D12ResourceLocation &, ID3D12ResourceAllocator *, const wchar_t *) D3D12Buffer.cpp:205 [UnrealEditor-D3D12RHI.dll] FD3D12Adapter::CreateRHIBuffer’::18'::<lambda_1>::operator()(FD3D12Device *,FD3D12Buffer *) D3D12Buffer.cpp:265 [Inlined] [UnrealEditor-D3D12RHI.dll] FD3D12LinkedAdapterObject::CreateLinkedObjects(FRHIGPUMask, const FD3D12Adapter::<lambda_1> &, const <lambda_1> &) D3D12RHICommon.h:207 [Inlined] [UnrealEditor-D3D12RHI.dll] FD3D12Adapter::CreateLinkedObject(FRHIGPUMask, const <lambda_1> &) D3D12Adapter.h:397 [UnrealEditor-D3D12RHI.dll] FD3D12Adapter::CreateRHIBuffer(const D3D12_RESOURCE_DESC &, unsigned int, const FRHIBufferDesc &, ED3D12ResourceStateMode, D3D12_RESOURCE_STATES, bool, const FRHIGPUMask &, ID3D12ResourceAllocator *, const wchar_t *, const FName &, const FName &) D3D12Buffer.cpp:250 [UnrealEditor-D3D12RHI.dll] FD3D12DynamicRHI::CreateD3D12Buffer(FRHICommandListBase *, const FRHIBufferDesc &, ERHIAccess, FRHIResourceCreateInfo &, ID3D12ResourceAllocator *, bool) D3D12Buffer.cpp:473 [Inlined] [UnrealEditor-D3D12RHI.dll] FD3D12DynamicRHI::CreateBuffer(FRHICommandListBase &, const FRHIBufferDesc &, ERHIAccess, FRHIResourceCreateInfo &) D3D12Buffer.cpp:427 [UnrealEditor-D3D12RHI.dll] FD3D12DynamicRHI::RHICreateBuffer(FRHICommandListBase &, const FRHIBufferDesc &, ERHIAccess, FRHIResourceCreateInfo &) D3D12Buffer.cpp:414 [UnrealEditor-RenderCore.dll] FRHICommandListBase::CreateBuffer(unsigned int, EBufferUsageFlags, unsigned int, ERHIAccess, FRHIResourceCreateInfo &) RHICommandList.h:776 [UnrealEditor-RenderCore.dll] FRDGBufferPool::CreateBuffer(FRHICommandListBase &, const FRDGBufferDesc &, unsigned int, const wchar_t *) RenderGraphResourcePool.cpp:185 [UnrealEditor-RenderCore.dll] FRDGBufferPool::FindFreeBuffer(FRHICommandListBase &, const FRDGBufferDesc &, const wchar_t *, ERDGPooledBufferAlignment) RenderGraphResourcePool.cpp:159 [Inlined] [UnrealEditor-RenderCore.dll] FRDGBuilder::AllocatePooledBufferRHI(FRHICommandListBase &, FRDGBuffer *) RenderGraphBuilder.cpp:4410 [UnrealEditor-RenderCore.dll] FRDGBuilder::SubmitBufferUploads(FRHICommandListBase &, UE::Tasks::FTaskEvent *) RenderGraphBuilder.cpp:2666 [Inlined] [UnrealEditor-RenderCore.dll] FRDGBuilder::Execute::__l15::<lambda_3>::operator()(FRHICommandListBase &) RenderGraphBuilder.cpp:1862 [Inlined] [UnrealEditor-RenderCore.dll] FRDGBuilder::AddCommandListSetupTask::__l2::<lambda_1>::operator()() RenderGraphBuilder.inl:691 [UnrealEditor-RenderCore.dll] FRDGBuilder::AddCommandListSetupTask<FRDGBuilder::Execute’::15'::<lambda_3>,UE::Tasks::Private::FTaskHandle &>(<lambda_3> &&,UE::Tasks::FPipe *,UE::Tasks::Private::FTaskHandle &,ETaskPriority,bool,ERDGSetupTaskWaitPoint) RenderGraphBuilder.inl:703 [Inlined] [UnrealEditor-RenderCore.dll] FRDGBuilder::AddCommandListSetupTask(<lambda_3> &&, UE::Tasks::Private::FTaskHandle &, ETaskPriority, bool, ERDGSetupTaskWaitPoint) RenderGraphBuilder.inl:651 [UnrealEditor-RenderCore.dll] FRDGBuilder::Execute() RenderGraphBuilder.cpp:1860 [UnrealEditor-SlateRHIRenderer.dll] FSlateRHIRenderer::DrawWindows_RenderThread(FRHICommandListImmediate &, TArrayView<…>, TArrayView<…>) SlateRHIRenderer.cpp:1104 [UnrealEditor-SlateRHIRenderer.dll] FSlateRHIRenderer::DrawWindows_Private’::99'::<lambda_3>::operator()(FRHICommandListImmediate &) SlateRHIRenderer.cpp:1381 [Inlined] [UnrealEditor-RenderCore.dll] UE::Core::Private::Function::TFunctionRefBase::operator()(FRHICommandListImmediate &) Function.h:470 [UnrealEditor-RenderCore.dll] FRenderThreadCommandPipe::EnqueueAndLaunch’::5'::<lambda_1>::operator()() RenderingThread.cpp:1538 [Inlined] [UnrealEditor-RenderCore.dll] UE::Core::Private::Function::TFunctionRefBase::operator()() Function.h:470 [Inlined] [UnrealEditor-RenderCore.dll] TFunctionGraphTaskImpl::DoTaskImpl(TUniqueFunction<…> &, Type, const TRefCountPtr<…> &) TaskGraphInterfaces.h:1710 [Inlined] [UnrealEditor-RenderCore.dll] TFunctionGraphTaskImpl::DoTask(Type, const TRefCountPtr<…> &) TaskGraphInterfaces.h:1703 [UnrealEditor-RenderCore.dll] TGraphTask::ExecuteTask() TaskGraphInterfaces.h:634 [UnrealEditor-Core.dll] UE::Tasks::Private::FTaskBase::TryExecuteTask() TaskPrivate.h:504 [Inlined] [UnrealEditor-Core.dll] FBaseGraphTask::Execute(TArray<…> &, Type, bool) TaskGraphInterfaces.h:482 [UnrealEditor-Core.dll] FNamedTaskThread::ProcessTasksNamedThread(int, bool) TaskGraph.cpp:780 [UnrealEditor-Core.dll] FNamedTaskThread::ProcessTasksUntilQuit(int) TaskGraph.cpp:668 [UnrealEditor-RenderCore.dll] RenderingThreadMain(FEvent *) RenderingThread.cpp:317 [UnrealEditor-RenderCore.dll] FRenderingThread::Run() RenderingThread.cpp:468 [UnrealEditor-Core.dll] FRunnableThreadWin::Run() WindowsRunnableThread.cpp:156 [UnrealEditor-Core.dll] FRunnableThreadWin::GuardedRun() WindowsRunnableThread.cpp:71