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.
631 lines
27 KiB
C++
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, ¤tOutput) != 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;
|
|
}
|
|
}
|
|
}
|