You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
o3de/Gems/Atom/RHI/DX12/Code/Source/RHI/Device.cpp

631 lines
27 KiB
C++

/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include <Atom/RHI/RHISystemInterface.h>
#include <RHI/Device.h>
#include <RHI/PhysicalDevice.h>
#include <RHI/Conversions.h>
#include <RHI/DescriptorContext.h>
#include <RHI/Fence.h>
#include <Atom/RHI/MemoryStatisticsBuilder.h>
#include <Atom/RHI.Reflect/DX12/PlatformLimitsDescriptor.h>
#include <AzCore/Debug/EventTrace.h>
#include <AzCore/std/parallel/lock.h>
#include <AzCore/std/string/conversions.h>
#include <AzCore/std/smart_ptr/make_shared.h>
#include <AzCore/Utils/TypeHash.h>
namespace AZ
{
namespace DX12
{
namespace Platform
{
void DeviceShutdownInternal(ID3D12DeviceX* device);
void DeviceCompileMemoryStatisticsInternal(RHI::MemoryStatisticsBuilder& builder, IDXGIAdapterX* dxgiAdapter);
}
RHI::Ptr<Device> Device::Create()
{
return aznew Device();
}
RHI::ResultCode Device::InitInternal(RHI::PhysicalDevice& physicalDevice)
{
RHI::ResultCode resultCode = InitSubPlatform(physicalDevice);
if (resultCode != RHI::ResultCode::Success)
{
return resultCode;
}
InitFeatures();
return RHI::ResultCode::Success;
}
RHI::ResultCode Device::PostInitInternal(const RHI::DeviceDescriptor& descriptor)
{
m_allocationInfoCache.SetInitFunction([](auto& cache) { cache.set_capacity(64); });
{
ReleaseQueue::Descriptor releaseQueueDescriptor;
releaseQueueDescriptor.m_collectLatency = descriptor.m_frameCountMax - 1;
m_releaseQueue.Init(releaseQueueDescriptor);
}
m_descriptorContext = AZStd::make_shared<DescriptorContext>();
RHI::ConstPtr<RHI::PlatformLimitsDescriptor> rhiDescriptor = descriptor.m_platformLimitsDescriptor;
if (RHI::ConstPtr<PlatformLimitsDescriptor> platLimitsDesc = azrtti_cast<const PlatformLimitsDescriptor*>(rhiDescriptor))
{
m_descriptorContext->Init(m_dx12Device.get(), platLimitsDesc);
}
else
{
AZ_Assert(false, "Missing PlatformLimits config file for DX12 backend");
}
{
CommandListAllocator::Descriptor commandListAllocatorDescriptor;
commandListAllocatorDescriptor.m_device = this;
commandListAllocatorDescriptor.m_frameCountMax = descriptor.m_frameCountMax;
commandListAllocatorDescriptor.m_descriptorContext = m_descriptorContext;
m_commandListAllocator.Init(commandListAllocatorDescriptor);
}
{
StagingMemoryAllocator::Descriptor allocatorDesc;
allocatorDesc.m_device = this;
allocatorDesc.m_mediumPageSizeInBytes = static_cast<uint32_t>(RHI::RHISystemInterface::Get()->GetPlatformLimitsDescriptor()->m_platformDefaultValues.m_mediumStagingBufferPageSizeInBytes);
allocatorDesc.m_largePageSizeInBytes = static_cast<uint32_t>(RHI::RHISystemInterface::Get()->GetPlatformLimitsDescriptor()->m_platformDefaultValues.m_largestStagingBufferPageSizeInBytes);
allocatorDesc.m_collectLatency = descriptor.m_frameCountMax;
m_stagingMemoryAllocator.Init(allocatorDesc);
}
m_pipelineLayoutCache.Init(*this);
m_commandQueueContext.Init(*this);
m_asyncUploadQueue.Init(*this, AsyncUploadQueue::Descriptor(RHI::RHISystemInterface::Get()->GetPlatformLimitsDescriptor()->m_platformDefaultValues.m_asyncQueueStagingBufferSizeInBytes));
m_samplerCache.SetCapacity(SamplerCacheCapacity);
return RHI::ResultCode::Success;
}
void Device::PreShutdown()
{
// Any containers that maintain references to DeviceObjects need to be cleared here to ensure the device
// refcount reaches 0 before shutdown.
m_samplerCache.Clear();
m_commandListAllocator.Shutdown();
m_asyncUploadQueue.Shutdown();
m_commandQueueContext.Shutdown();
}
void Device::ShutdownInternal()
{
m_allocationInfoCache.Clear();
m_stagingMemoryAllocator.Shutdown();
m_pipelineLayoutCache.Shutdown();
m_descriptorContext = nullptr;
m_releaseQueue.Shutdown();
m_dxgiFactory = nullptr;
m_dxgiAdapter = nullptr;
Platform::DeviceShutdownInternal(m_dx12Device.get());
m_dx12Device = nullptr;
}
void Device::InitFeatures()
{
m_features.m_tessellationShader = true;
m_features.m_geometryShader = true;
m_features.m_computeShader = true;
m_features.m_independentBlend = true;
m_features.m_dualSourceBlending = true;
m_features.m_customResolvePositions = true;
m_features.m_queryTypesMask[static_cast<uint32_t>(RHI::HardwareQueueClass::Graphics)] = RHI::QueryTypeFlags::All;
m_features.m_queryTypesMask[static_cast<uint32_t>(RHI::HardwareQueueClass::Compute)] = RHI::QueryTypeFlags::PipelineStatistics | RHI::QueryTypeFlags::Timestamp;
D3D12_FEATURE_DATA_D3D12_OPTIONS3 options3;
GetDevice()->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS3, &options3, sizeof(options3));
if (options3.CopyQueueTimestampQueriesSupported)
{
m_features.m_queryTypesMask[static_cast<uint32_t>(RHI::HardwareQueueClass::Copy)] = RHI::QueryTypeFlags::Timestamp;
}
m_features.m_predication = true;
m_features.m_occlusionQueryPrecise = true;
m_features.m_indirectCommandTier = RHI::IndirectCommandTiers::Tier2;
m_features.m_indirectDrawCountBufferSupported = true;
m_features.m_indirectDispatchCountBufferSupported = true;
m_features.m_indirectDrawStartInstanceLocationSupported = true;
#ifdef AZ_DX12_DXR_SUPPORT
D3D12_FEATURE_DATA_D3D12_OPTIONS5 options5;
GetDevice()->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS5, &options5, sizeof(options5));
m_features.m_rayTracing = options5.RaytracingTier != D3D12_RAYTRACING_TIER_NOT_SUPPORTED;
#else
m_features.m_rayTracing = false;
#endif
m_features.m_unboundedArrays = true;
m_limits.m_maxImageDimension1D = D3D12_REQ_TEXTURE1D_U_DIMENSION;
m_limits.m_maxImageDimension2D = D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION;
m_limits.m_maxImageDimension3D = D3D12_REQ_TEXTURE3D_U_V_OR_W_DIMENSION;
m_limits.m_maxImageDimensionCube = D3D12_REQ_TEXTURECUBE_DIMENSION;
m_limits.m_maxImageArraySize = D3D12_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION;
m_limits.m_minConstantBufferViewOffset = D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT;
m_limits.m_maxIndirectDrawCount = static_cast<uint32_t>(-1);
m_limits.m_maxIndirectDispatchCount = static_cast<uint32_t>(-1);
}
void Device::CompileMemoryStatisticsInternal(RHI::MemoryStatisticsBuilder& builder)
{
Platform::DeviceCompileMemoryStatisticsInternal(builder, m_dxgiAdapter.get());
m_stagingMemoryAllocator.ReportMemoryUsage(builder);
}
void Device::UpdateCpuTimingStatisticsInternal(RHI::CpuTimingStatistics& cpuTimingStatistics) const
{
m_commandQueueContext.UpdateCpuTimingStatistics(cpuTimingStatistics);
}
void Device::BeginFrameInternal()
{
m_commandQueueContext.Begin();
}
void Device::EndFrameInternal()
{
AZ_TRACE_METHOD();
m_commandQueueContext.End();
m_commandListAllocator.Collect();
m_descriptorContext->GarbageCollect();
m_stagingMemoryAllocator.GarbageCollect();
m_releaseQueue.Collect();
}
void Device::WaitForIdleInternal()
{
m_commandQueueContext.WaitForIdle();
m_releaseQueue.Collect(true);
}
AZStd::chrono::microseconds Device::GpuTimestampToMicroseconds(uint64_t gpuTimestamp, RHI::HardwareQueueClass queueClass) const
{
auto durationInSeconds = AZStd::chrono::duration<double>(double(gpuTimestamp) / m_commandQueueContext.GetCommandQueue(queueClass).GetGpuTimestampFrequency());
return AZStd::chrono::microseconds(durationInSeconds);
}
void Device::FillFormatsCapabilitiesInternal(FormatCapabilitiesList& formatsCapabilities)
{
for (uint32_t i = 0; i < formatsCapabilities.size(); ++i)
{
RHI::FormatCapabilities& flags = formatsCapabilities[i];
D3D12_FEATURE_DATA_FORMAT_SUPPORT support{};
support.Format = ConvertFormat(static_cast<RHI::Format>(i), false);
GetDevice()->CheckFeatureSupport(D3D12_FEATURE_FORMAT_SUPPORT, &support, sizeof(support));
flags = RHI::FormatCapabilities::None;
if (RHI::CheckBitsAll(support.Support1, D3D12_FORMAT_SUPPORT1_IA_VERTEX_BUFFER))
{
flags |= RHI::FormatCapabilities::VertexBuffer;
}
if (RHI::CheckBitsAll(support.Support1, D3D12_FORMAT_SUPPORT1_IA_INDEX_BUFFER))
{
flags |= RHI::FormatCapabilities::IndexBuffer;
}
if (RHI::CheckBitsAll(support.Support1, D3D12_FORMAT_SUPPORT1_RENDER_TARGET))
{
flags |= RHI::FormatCapabilities::RenderTarget;
}
if (RHI::CheckBitsAll(support.Support1, D3D12_FORMAT_SUPPORT1_DEPTH_STENCIL))
{
flags |= RHI::FormatCapabilities::DepthStencil;
}
if (RHI::CheckBitsAll(support.Support1, D3D12_FORMAT_SUPPORT1_BLENDABLE))
{
flags |= RHI::FormatCapabilities::Blend;
}
if (RHI::CheckBitsAll(support.Support1, D3D12_FORMAT_SUPPORT1_SHADER_SAMPLE))
{
flags |= RHI::FormatCapabilities::Sample;
}
if (RHI::CheckBitsAll(support.Support2, D3D12_FORMAT_SUPPORT2_UAV_TYPED_LOAD))
{
flags |= RHI::FormatCapabilities::TypedLoadBuffer;
}
if (RHI::CheckBitsAll(support.Support2, D3D12_FORMAT_SUPPORT2_UAV_TYPED_STORE))
{
flags |= RHI::FormatCapabilities::TypedStoreBuffer;
}
if (RHI::CheckBitsAll(support.Support2, D3D12_FORMAT_SUPPORT2_UAV_ATOMIC_ADD))
{
flags |= RHI::FormatCapabilities::AtomicBuffer;
}
}
}
RHI::ResourceMemoryRequirements Device::GetResourceMemoryRequirements(const RHI::ImageDescriptor& descriptor)
{
D3D12_RESOURCE_ALLOCATION_INFO allocationInfo;
GetImageAllocationInfo(descriptor, allocationInfo);
RHI::ResourceMemoryRequirements memoryRequirements;
memoryRequirements.m_alignmentInBytes = allocationInfo.Alignment;
memoryRequirements.m_sizeInBytes = allocationInfo.SizeInBytes;
return memoryRequirements;
}
RHI::ResourceMemoryRequirements Device::GetResourceMemoryRequirements(const RHI::BufferDescriptor& descriptor)
{
RHI::ResourceMemoryRequirements memoryRequirements;
memoryRequirements.m_alignmentInBytes = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
memoryRequirements.m_sizeInBytes = RHI::AlignUp<size_t>(descriptor.m_byteCount, memoryRequirements.m_alignmentInBytes);
return memoryRequirements;
}
void Device::ObjectCollectionNotify(RHI::ObjectCollectorNotifyFunction notifyFunction)
{
m_releaseQueue.Notify(notifyFunction);
}
//AZStd::vector<RHI::Format> Device::GetValidSwapChainImageFormats(const RHI::WindowHandle& windowHandle) const
//{
// AZStd::vector<RHI::Format> formatsList;
// // Follows Microsoft's HDR sample code for determining if the connected display supports HDR.
// // Enumerates all of the detected displays and determines which one has the largest intersection with the
// // region of the window handle parameter.
// // If the display for this region supports wide color gamut, then a wide color gamut format is added to
// // the list of supported formats.
// // https://github.com/microsoft/DirectX-Graphics-Samples/blob/master/Samples/UWP/D3D12HDR/src/D3D12HDR.cpp
// HWND hWnd = reinterpret_cast<HWND>(windowHandle.GetIndex());
// RECT windowRect = {};
// GetWindowRect(hWnd, &windowRect);
// UINT outputIndex = 0;
// Microsoft::WRL::ComPtr<IDXGIOutput> bestOutput;
// Microsoft::WRL::ComPtr<IDXGIOutput> currentOutput;
// RECT intersectRect;
// int bestIntersectionArea = -1;
// while (m_dxgiAdapter->EnumOutputs(outputIndex, &currentOutput) != DXGI_ERROR_NOT_FOUND)
// {
// // Get the rectangle bounds of current output
// DXGI_OUTPUT_DESC outputDesc;
// currentOutput->GetDesc(&outputDesc);
// RECT outputRect = outputDesc.DesktopCoordinates;
// int intersectionArea = 0;
// if (IntersectRect(&intersectRect, &windowRect, &outputRect))
// {
// intersectionArea = (intersectRect.bottom - intersectRect.top) * (intersectRect.right - intersectRect.left);
// }
// if (intersectionArea > bestIntersectionArea)
// {
// bestOutput = currentOutput;
// bestIntersectionArea = intersectionArea;
// }
// outputIndex++;
// }
// Microsoft::WRL::ComPtr<IDXGIOutput6> output6;
// HRESULT hr = bestOutput.As(&output6);
// AZ_Assert(S_OK == hr, "Failed to get IDXGIOutput6 structure.");
// DXGI_OUTPUT_DESC1 outputDesc;
// output6->GetDesc1(&outputDesc);
// if (outputDesc.ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020)
// {
// // HDR is supported
// formatsList.push_back(RHI::Format::R10G10B10A2_UNORM);
// }
// // Fallback default 8-bit format
// formatsList.push_back(RHI::Format::R8G8B8A8_UNORM);
// return formatsList;
//}
MemoryView Device::CreateImageCommitted(
const RHI::ImageDescriptor& imageDescriptor,
const RHI::ClearValue* optimizedClearValue,
D3D12_RESOURCE_STATES initialState,
D3D12_HEAP_TYPE heapType)
{
AZ_TRACE_METHOD();
D3D12_RESOURCE_DESC resourceDesc;
ConvertImageDescriptor(imageDescriptor, resourceDesc);
CD3DX12_HEAP_PROPERTIES heapProperties(heapType);
// Clear values only apply when the image is a render target or depth stencil.
const bool isOutputMergerAttachment =
RHI::CheckBitsAny(imageDescriptor.m_bindFlags, RHI::ImageBindFlags::Color | RHI::ImageBindFlags::DepthStencil);
D3D12_CLEAR_VALUE clearValue;
if (isOutputMergerAttachment && optimizedClearValue)
{
clearValue = ConvertClearValue(imageDescriptor.m_format, *optimizedClearValue);
}
Microsoft::WRL::ComPtr<ID3D12Resource> resource;
AssertSuccess(m_dx12Device->CreateCommittedResource(
&heapProperties, D3D12_HEAP_FLAG_NONE, &resourceDesc, initialState, (isOutputMergerAttachment && optimizedClearValue) ? &clearValue : nullptr, IID_GRAPHICS_PPV_ARGS(resource.GetAddressOf())));
D3D12_RESOURCE_ALLOCATION_INFO allocationInfo;
GetImageAllocationInfo(imageDescriptor, allocationInfo);
return MemoryView(resource.Get(), 0, allocationInfo.SizeInBytes, allocationInfo.Alignment, MemoryViewType::Image);
}
MemoryView Device::CreateBufferCommitted(
const RHI::BufferDescriptor& bufferDescriptor,
D3D12_RESOURCE_STATES initialState,
D3D12_HEAP_TYPE heapType)
{
D3D12_RESOURCE_DESC resourceDesc;
ConvertBufferDescriptor(bufferDescriptor, resourceDesc);
CD3DX12_HEAP_PROPERTIES heapProperties(heapType);
#ifdef AZ_DX12_DXR_SUPPORT
if (initialState == D3D12_RESOURCE_STATE_RAYTRACING_ACCELERATION_STRUCTURE)
{
resourceDesc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
}
#endif
Microsoft::WRL::ComPtr<ID3D12Resource> resource;
AssertSuccess(m_dx12Device->CreateCommittedResource(
&heapProperties, D3D12_HEAP_FLAG_NONE, &resourceDesc, initialState, nullptr, IID_GRAPHICS_PPV_ARGS(resource.GetAddressOf())));
D3D12_RESOURCE_ALLOCATION_INFO allocationInfo;
allocationInfo.Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
allocationInfo.SizeInBytes = RHI::AlignUp(resourceDesc.Width, D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT);
return MemoryView(resource.Get(), 0, allocationInfo.SizeInBytes, allocationInfo.Alignment, MemoryViewType::Buffer);
}
MemoryView Device::CreateBufferPlaced(
const RHI::BufferDescriptor& bufferDescriptor,
D3D12_RESOURCE_STATES initialState,
ID3D12Heap* heap,
size_t heapByteOffset)
{
D3D12_RESOURCE_DESC resourceDesc;
ConvertBufferDescriptor(bufferDescriptor, resourceDesc);
D3D12_RESOURCE_ALLOCATION_INFO allocationInfo;
allocationInfo.Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
allocationInfo.SizeInBytes = RHI::AlignUp(resourceDesc.Width, D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT);
Microsoft::WRL::ComPtr<ID3D12Resource> resource;
AssertSuccess(m_dx12Device->CreatePlacedResource(
heap, heapByteOffset, &resourceDesc, initialState, nullptr, IID_GRAPHICS_PPV_ARGS(resource.GetAddressOf())));
return MemoryView(resource.Get(), 0, allocationInfo.SizeInBytes, allocationInfo.Alignment, MemoryViewType::Buffer);
}
static uint64_t GetPlacedTextureAlignment(const RHI::ImageDescriptor& imageDescriptor)
{
return (imageDescriptor.m_multisampleState.m_samples > 1)
? D3D12_DEFAULT_MSAA_RESOURCE_PLACEMENT_ALIGNMENT
: D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
}
MemoryView Device::CreateImagePlaced(
const RHI::ImageDescriptor& imageDescriptor,
const RHI::ClearValue* optimizedClearValue,
D3D12_RESOURCE_STATES initialState,
ID3D12Heap* heap,
size_t heapByteOffset)
{
D3D12_RESOURCE_DESC resourceDesc;
ConvertImageDescriptor(imageDescriptor, resourceDesc);
D3D12_RESOURCE_ALLOCATION_INFO allocationInfo{};
GetPlacedImageAllocationInfo(imageDescriptor, allocationInfo);
allocationInfo.Alignment = GetPlacedTextureAlignment(imageDescriptor);
if (resourceDesc.Alignment == 0)
{
resourceDesc.Alignment = allocationInfo.Alignment;
}
// Clear values only apply when the image is a render target or depth stencil.
const bool isOutputMergerAttachment =
RHI::CheckBitsAny(imageDescriptor.m_bindFlags, RHI::ImageBindFlags::Color | RHI::ImageBindFlags::DepthStencil);
D3D12_CLEAR_VALUE clearValue;
if (isOutputMergerAttachment && optimizedClearValue)
{
clearValue = ConvertClearValue(imageDescriptor.m_format, *optimizedClearValue);
if (RHI::CheckBitsAny(imageDescriptor.m_bindFlags, RHI::ImageBindFlags::DepthStencil))
{
clearValue.Format = GetDSVFormat(clearValue.Format);
}
}
Microsoft::WRL::ComPtr<ID3D12Resource> resource;
AssertSuccess(m_dx12Device->CreatePlacedResource(
heap,heapByteOffset, &resourceDesc,initialState, (isOutputMergerAttachment && optimizedClearValue) ? &clearValue : nullptr, IID_GRAPHICS_PPV_ARGS(resource.GetAddressOf())));
return MemoryView(resource.Get(), 0, allocationInfo.SizeInBytes, allocationInfo.Alignment, MemoryViewType::Image);
}
MemoryView Device::CreateImageReserved(
const RHI::ImageDescriptor& imageDescriptor,
D3D12_RESOURCE_STATES initialState,
ImageTileLayout& imageTileLayout)
{
D3D12_RESOURCE_DESC resourceDesc;
ConvertImageDescriptor(imageDescriptor, resourceDesc);
resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_64KB_UNDEFINED_SWIZZLE;
AZ_Assert(
RHI::CheckBitsAny(imageDescriptor.m_bindFlags, RHI::ImageBindFlags::Color | RHI::ImageBindFlags::DepthStencil) == false,
"Reserved resources are not supported for color / depth stencil images.");
Microsoft::WRL::ComPtr<ID3D12Resource> resource;
AssertSuccess(m_dx12Device->CreateReservedResource(
&resourceDesc, initialState, nullptr, IID_GRAPHICS_PPV_ARGS(resource.GetAddressOf())));
uint32_t subresourceCount = resourceDesc.MipLevels * resourceDesc.DepthOrArraySize;
imageTileLayout.m_subresourceTiling.resize(subresourceCount);
uint32_t tileCount = 0;
D3D12_TILE_SHAPE tileShape;
D3D12_PACKED_MIP_INFO packedMipInfo;
m_dx12Device->GetResourceTiling(
resource.Get(), &tileCount, &packedMipInfo, &tileShape, &subresourceCount, 0, imageTileLayout.m_subresourceTiling.data());
imageTileLayout.m_tileSize = RHI::Size(tileShape.WidthInTexels, tileShape.HeightInTexels, tileShape.DepthInTexels);
imageTileLayout.m_tileCount = tileCount;
imageTileLayout.m_tileCountPacked = packedMipInfo.NumTilesForPackedMips;
imageTileLayout.m_tileCountStandard = tileCount - imageTileLayout.m_tileCountPacked;
imageTileLayout.m_mipCount = packedMipInfo.NumStandardMips + packedMipInfo.NumPackedMips;
imageTileLayout.m_mipCountStandard = packedMipInfo.NumStandardMips;
imageTileLayout.m_mipCountPacked = packedMipInfo.NumPackedMips;
D3D12_RESOURCE_ALLOCATION_INFO allocationInfo;
GetImageAllocationInfo(imageDescriptor, allocationInfo);
return MemoryView(resource.Get(), 0, allocationInfo.SizeInBytes, allocationInfo.Alignment, MemoryViewType::Image);
}
void Device::GetImageAllocationInfo(
const RHI::ImageDescriptor& descriptor,
D3D12_RESOURCE_ALLOCATION_INFO& info)
{
auto& allocationInfoCache = m_allocationInfoCache.GetStorage();
const uint64_t hash = static_cast<uint64_t>(descriptor.GetHash());
auto it = allocationInfoCache.get(hash);
if (it != allocationInfoCache.end())
{
info = it->second;
}
else
{
D3D12_RESOURCE_DESC resourceDesc;
ConvertImageDescriptor(descriptor, resourceDesc);
info = m_dx12Device->GetResourceAllocationInfo(0, 1, &resourceDesc);
AZ_Assert(info.SizeInBytes != uint64_t(-1), "Device::GetImageAllocationInfo - DX12 failed to get allocation info for the provided resource description.");
allocationInfoCache.emplace(hash, info);
}
}
void Device::GetPlacedImageAllocationInfo(
const RHI::ImageDescriptor& descriptor,
D3D12_RESOURCE_ALLOCATION_INFO& info)
{
GetImageAllocationInfo(descriptor, info);
info.Alignment = AZStd::max<uint64_t>(info.Alignment, GetPlacedTextureAlignment(descriptor));
}
void Device::QueueForRelease(RHI::Ptr<ID3D12Object> dx12Object)
{
m_releaseQueue.QueueForCollect(AZStd::move(dx12Object));
}
void Device::QueueForRelease(const MemoryView& memoryView)
{
m_releaseQueue.QueueForCollect(memoryView.GetMemory());
}
MemoryView Device::AcquireStagingMemory(size_t size, size_t alignment)
{
return m_stagingMemoryAllocator.Allocate(size, alignment);
}
CommandList* Device::AcquireCommandList(RHI::HardwareQueueClass hardwareQueueClass)
{
return m_commandListAllocator.Allocate(hardwareQueueClass);
}
RHI::ConstPtr<PipelineLayout> Device::AcquirePipelineLayout(const RHI::PipelineLayoutDescriptor& descriptor)
{
return m_pipelineLayoutCache.Allocate(descriptor);
}
ID3D12DeviceX* Device::GetDevice()
{
return m_dx12Device.get();
}
RHI::ConstPtr<Sampler> Device::AcquireSampler(const RHI::SamplerState& state)
{
auto hash = static_cast<uint64_t>(state.GetHash());
AZStd::lock_guard<AZStd::mutex> lock(m_samplerCacheMutex);
Sampler* sampler = m_samplerCache.Find(hash);
if (!sampler)
{
RHI::Ptr<Sampler> samplerPtr = Sampler::Create();
samplerPtr->Init(*this, state);
m_samplerCache.Insert(hash, samplerPtr);
sampler = samplerPtr.get();
}
return RHI::ConstPtr<Sampler>(sampler);
}
const PhysicalDevice& Device::GetPhysicalDevice() const
{
return static_cast<const PhysicalDevice&>(Base::GetPhysicalDevice());
}
MemoryPageAllocator& Device::GetConstantMemoryPageAllocator()
{
return m_stagingMemoryAllocator.GetMediumPageAllocator();
}
CommandQueueContext& Device::GetCommandQueueContext()
{
return m_commandQueueContext;
}
AsyncUploadQueue& Device::GetAsyncUploadQueue()
{
return m_asyncUploadQueue;
}
DescriptorContext& Device::GetDescriptorContext()
{
return *m_descriptorContext;
}
bool Device::IsAftermathInitialized() const
{
return m_isAftermathInitialized;
}
}
}