FD3D12ResourceLocation* FD3D12DynamicRHI::CreateBuffer(FRHICommandListImmediate* RHICmdList, const D3D12_RESOURCE_DESC Desc, uint32 Size, uint32 InUsage, FRHIResourceCreateInfo& CreateInfo, uint32 Alignment)
{
	// Explicitly check that the size is nonzero before allowing CreateBuffer to opaquely fail.
	check(Size > 0);

	const bool bIsDynamic = (InUsage & BUF_AnyDynamic) ? true : false;

	FD3D12ResourceLocation* ResourceLocation = new FD3D12ResourceLocation(GetRHIDevice());

	// If a resource array was provided for the resource, create the resource pre-populated
	D3D12_SUBRESOURCE_DATA InitData = { 0 };
	D3D12_SUBRESOURCE_DATA* pInitData = nullptr;
	if (CreateInfo.ResourceArray)
	{
		check(Size == CreateInfo.ResourceArray->GetResourceDataSize());
		InitData.pData = CreateInfo.ResourceArray->GetResourceData();
		InitData.RowPitch = Size;
		InitData.SlicePitch = 0;
		pInitData = &InitData;
	}

	if (bIsDynamic)
	{
		void* pData = GetRHIDevice()->GetDefaultUploadHeapAllocator().AllocUploadResource(Size, Alignment, ResourceLocation);
		check(ResourceLocation->GetEffectiveBufferSize() == Size);

		if (pInitData)
		{
			// Handle initial data
			FMemory::Memcpy(pData, InitData.pData, Size);
		}
	}
	else
	{
		if (RHICmdList && pInitData)
		{
			// We only need to synchronize when creating default resource buffers (because we need a command list to initialize them)
			FScopedRHIThreadStaller StallRHIThread(*RHICmdList);

			VERIFYD3D11RESULT(GetRHIDevice()->GetDefaultBufferAllocator().AllocDefaultResource(Desc, pInitData, ResourceLocation, Alignment));
		}
		else
		{
			VERIFYD3D11RESULT(GetRHIDevice()->GetDefaultBufferAllocator().AllocDefaultResource(Desc, pInitData, ResourceLocation, Alignment));
		}
		check(ResourceLocation->GetEffectiveBufferSize() == Size);
	}

	if (CreateInfo.ResourceArray)
	{
		// Discard the resource array's contents.
		CreateInfo.ResourceArray->Discard();
	}

	return ResourceLocation;
}
BufferType* FD3D12Adapter::CreateRHIBuffer(FRHICommandListImmediate* RHICmdList,
	const D3D12_RESOURCE_DESC& InDesc,
	uint32 Alignment,
	uint32 Stride,
	uint32 Size,
	uint32 InUsage,
	FRHIResourceCreateInfo& CreateInfo,
	bool SkipCreate)
{
	const bool bIsDynamic = (InUsage & BUF_AnyDynamic) ? true : false;

	BufferType* BufferOut = CreateLinkedObject<BufferType>([&](FD3D12Device* Device)
	{
		BufferType* NewBuffer = new BufferType(Device, Stride, Size, InUsage);
		NewBuffer->BufferAlignment = Alignment;

		if (SkipCreate == false)
		{
			AllocateBuffer(Device, InDesc, Size, InUsage, CreateInfo, Alignment, NewBuffer->ResourceLocation);
		}

		return NewBuffer;
	});

	if (CreateInfo.ResourceArray)
	{
		if (bIsDynamic == false && BufferOut->ResourceLocation.IsValid())
		{
			check(Size == CreateInfo.ResourceArray->GetResourceDataSize());

			// Get an upload heap and initialize data
			FD3D12ResourceLocation SrcResourceLoc(BufferOut->GetParentDevice());
			void* pData = SrcResourceLoc.GetParentDevice()->GetDefaultFastAllocator().Allocate<FD3D12ScopeLock>(Size, 4UL, &SrcResourceLoc);
			check(pData);
			FMemory::Memcpy(pData, CreateInfo.ResourceArray->GetResourceData(), Size);

			const auto& pfnUpdateBuffer = [&]()
			{
				BufferType* CurrentBuffer = BufferOut;
				while (CurrentBuffer != nullptr)
				{
					FD3D12Resource* Destination = CurrentBuffer->ResourceLocation.GetResource();
					FD3D12Device* Device = Destination->GetParentDevice();

					FD3D12CommandListHandle& hCommandList = Device->GetDefaultCommandContext().CommandListHandle;
					// Copy from the temporary upload heap to the default resource
					{
						// Writable structured bufferes are sometimes initialized with inital data which means they sometimes need tracking.
						FConditionalScopeResourceBarrier ConditionalScopeResourceBarrier(hCommandList, Destination, D3D12_RESOURCE_STATE_COPY_DEST, 0);

						Device->GetDefaultCommandContext().numCopies++;
						hCommandList->CopyBufferRegion(
							Destination->GetResource(),
							CurrentBuffer->ResourceLocation.GetOffsetFromBaseOfResource(),
							SrcResourceLoc.GetResource()->GetResource(),
							SrcResourceLoc.GetOffsetFromBaseOfResource(), Size);

						hCommandList.UpdateResidency(Destination);
					}

					CurrentBuffer = CurrentBuffer->GetNextObject();
				}
			};

			//TODO: This should be a deferred op like the buffer lock/unlocks
			// We only need to synchronize when creating default resource buffers (because we need a command list to initialize them)
			if (RHICmdList)
			{
				FScopedRHIThreadStaller StallRHIThread(*RHICmdList);
				pfnUpdateBuffer();
			}
			else
			{
				pfnUpdateBuffer();
			}
		}

		// Discard the resource array's contents.
		CreateInfo.ResourceArray->Discard();
	}

	return BufferOut;
}