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/RPI/Code/Source/RPI.Public/Pass/PassAttachment.cpp

290 lines
14 KiB
C++

/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <math.h>
#include <AzFramework/StringFunc/StringFunc.h>
#include <Atom/RHI/RHIUtils.h>
#include <Atom/RHI.Reflect/Bits.h>
#include <Atom/RPI.Public/Pass/PassAttachment.h>
#include <Atom/RPI.Public/RenderPipeline.h>
#include <Atom/RPI.Reflect/Pass/PassName.h>
namespace AZ
{
namespace RPI
{
// --- PassAttachment ---
PassAttachment::PassAttachment(const PassImageAttachmentDesc& attachmentDesc)
{
m_name = attachmentDesc.m_name;
m_lifetime = attachmentDesc.m_lifetime;
m_generateFullMipChain = attachmentDesc.m_generateFullMipChain;
m_descriptor = RHI::UnifiedAttachmentDescriptor(attachmentDesc.m_imageDescriptor);
ValidateDeviceFormats(attachmentDesc.m_formatFallbacks);
}
PassAttachment::PassAttachment(const PassBufferAttachmentDesc& attachmentDesc)
{
m_descriptor = RHI::UnifiedAttachmentDescriptor(attachmentDesc.m_bufferDescriptor);
m_name = attachmentDesc.m_name;
m_lifetime = attachmentDesc.m_lifetime;
}
Ptr<PassAttachment> PassAttachment::Clone() const
{
Ptr<PassAttachment> clone = aznew PassAttachment();
clone->m_name = this->m_name;
clone->m_descriptor = this->m_descriptor;
clone->m_lifetime = this->m_lifetime;
clone->m_formatSource = this->m_formatSource;
clone->m_multisampleSource = this->m_multisampleSource;
clone->m_sizeSource = this->m_sizeSource;
clone->m_sizeMultipliers = this->m_sizeMultipliers;
clone->m_arraySizeSource = this->m_arraySizeSource;
clone->m_generateFullMipChain = this->m_generateFullMipChain;
return clone;
}
void PassAttachment::ValidateDeviceFormats(const AZStd::vector<RHI::Format>& formatFallbacks, RHI::FormatCapabilities capabilities)
{
if (m_descriptor.m_type == RHI::AttachmentType::Image)
{
RHI::Format format = m_descriptor.m_image.m_format;
capabilities |= RHI::FormatCapabilities::Sample;
AZStd::string formatLocation = AZStd::string::format("PassAttachment [%s]", m_name.GetCStr());
m_descriptor.m_image.m_format = RHI::ValidateFormat(format, formatLocation.c_str(), formatFallbacks);
}
}
RHI::AttachmentId PassAttachment::GetAttachmentId() const
{
AZ_Warning("PassSystem", !m_path.IsEmpty(), "PassAttachment::GetAttachmentId(): Trying to get AttachmentId without a valid path. Make sure you call ComputePathName.");
return m_path;
}
RHI::AttachmentType PassAttachment::GetAttachmentType() const
{
return m_descriptor.m_type;
}
void PassAttachment::ComputePathName(const Name& passPath)
{
m_path = RHI::AttachmentId(ConcatPassString(passPath, m_name));
}
const RHI::TransientImageDescriptor PassAttachment::GetTransientImageDescriptor() const
{
AZ_Assert(m_lifetime == RHI::AttachmentLifetimeType::Transient,
"Error, building a transient image descriptor from non-transient pass attachment with path: %s",
m_path.GetCStr());
AZ_Assert(m_descriptor.m_type == RHI::AttachmentType::Image,
"Error, building a transient image descriptor for an attachment that is not an image: %s",
m_path.GetCStr());
return RHI::TransientImageDescriptor(GetAttachmentId(), m_descriptor.m_image);
}
const RHI::TransientBufferDescriptor PassAttachment::GetTransientBufferDescriptor() const
{
AZ_Assert(m_lifetime == RHI::AttachmentLifetimeType::Transient,
"Error, building a transient image descriptor from non-transient pass attachment with path: %s",
m_path.GetCStr());
AZ_Assert(m_descriptor.m_type == RHI::AttachmentType::Buffer,
"Error, building a transient buffer descriptor for an attachment that is not a buffer: %s",
m_path.GetCStr());
return RHI::TransientBufferDescriptor(GetAttachmentId(), m_descriptor.m_buffer);
}
void PassAttachment::Update(bool updateImportedAttachments)
{
if (m_descriptor.m_type == RHI::AttachmentType::Image && (m_lifetime == RHI::AttachmentLifetimeType::Transient || updateImportedAttachments == true))
{
if (m_settingFlags.m_getFormatFromPipeline && m_renderPipelineSource)
{
m_descriptor.m_image.m_format = m_renderPipelineSource->GetRenderSettings().m_format;
}
else if (m_formatSource && m_formatSource->m_attachment)
{
m_descriptor.m_image.m_format = m_formatSource->m_attachment->m_descriptor.m_image.m_format;
}
if (m_settingFlags.m_getMultisampleStateFromPipeline && m_renderPipelineSource)
{
m_descriptor.m_image.m_multisampleState = m_renderPipelineSource->GetRenderSettings().m_multisampleState;
}
else if (m_multisampleSource && m_multisampleSource->m_attachment)
{
m_descriptor.m_image.m_multisampleState = m_multisampleSource->m_attachment->m_descriptor.m_image.m_multisampleState;
}
if (m_settingFlags.m_getSizeFromPipeline && m_renderPipelineSource)
{
RHI::Size sourceSize = m_renderPipelineSource->GetRenderSettings().m_size;
m_descriptor.m_image.m_size = m_sizeMultipliers.ApplyModifiers(sourceSize);
}
else if(m_sizeSource && m_sizeSource->m_attachment)
{
RHI::Size sourceSize = m_sizeSource->m_attachment->m_descriptor.m_image.m_size;
m_descriptor.m_image.m_size = m_sizeMultipliers.ApplyModifiers(sourceSize);
}
if (m_arraySizeSource && m_arraySizeSource->m_attachment)
{
uint16_t arraySize = m_arraySizeSource->m_attachment->m_descriptor.m_image.m_arraySize;
m_descriptor.m_image.m_arraySize = arraySize;
}
if (m_generateFullMipChain)
{
uint32_t width = m_descriptor.m_image.m_size.m_width;
uint32_t height = m_descriptor.m_image.m_size.m_height;
double maxDimension = static_cast<double>(AZStd::max(width, height));
double mipMapLevels = floor(log2(maxDimension)) + 1;
m_descriptor.m_image.m_mipLevels = static_cast<uint16_t>(mipMapLevels);
}
}
}
void PassAttachment::OnAttached(const PassAttachmentBinding& binding)
{
// Auto-infer image and buffer bind flags...
if (GetAttachmentType() == RHI::AttachmentType::Image)
{
m_descriptor.m_image.m_bindFlags |= RHI::GetImageBindFlags(binding.m_scopeAttachmentUsage, binding.GetAttachmentAccess());
}
else if (GetAttachmentType() == RHI::AttachmentType::Buffer)
{
bool isInputAssembly = RHI::CheckBitsAny(m_descriptor.m_buffer.m_bindFlags, RHI::BufferBindFlags::InputAssembly | RHI::BufferBindFlags::DynamicInputAssembly);
bool isConstant = RHI::CheckBitsAny(m_descriptor.m_buffer.m_bindFlags, RHI::BufferBindFlags::Constant);
// Since InputAssembly and Constant cannot be inferred they are set manually. If those flags are set we don't want to add inferred flags on top as it may have a performance penalty
if (!isInputAssembly && !isConstant)
{
m_descriptor.m_buffer.m_bindFlags |= RHI::GetBufferBindFlags(binding.m_scopeAttachmentUsage, binding.GetAttachmentAccess());
}
}
}
// --- PassBinding ---
PassAttachmentBinding::PassAttachmentBinding(const PassSlot& slot)
{
m_name = slot.m_name;
m_shaderInputName = slot.m_shaderInputName;
m_shaderInputArrayIndex = slot.m_shaderInputArrayIndex;
m_slotType = slot.m_slotType;
m_scopeAttachmentUsage = slot.m_scopeAttachmentUsage;
m_unifiedScopeDesc.m_loadStoreAction = slot.m_loadStoreAction;
if (slot.m_imageViewDesc != nullptr)
{
m_unifiedScopeDesc.SetAsImage(*slot.m_imageViewDesc);
}
else if (slot.m_bufferViewDesc != nullptr)
{
m_unifiedScopeDesc.SetAsBuffer(*slot.m_bufferViewDesc);
}
ValidateDeviceFormats(slot.m_formatFallbacks);
}
void PassAttachmentBinding::ValidateDeviceFormats(const AZStd::vector<RHI::Format>& formatFallbacks)
{
RHI::FormatCapabilities capabilities = RHI::GetCapabilities(m_scopeAttachmentUsage, GetAttachmentAccess(), m_unifiedScopeDesc.GetType());
if (m_unifiedScopeDesc.GetType() == RHI::AttachmentType::Buffer)
{
RHI::BufferViewDescriptor& bufferViewDesc = m_unifiedScopeDesc.GetBufferViewDescriptor();
RHI::Format format = bufferViewDesc.m_elementFormat;
AZStd::string formatLocation = AZStd::string::format("BufferViewDescriptor on PassAttachmentBinding [%s]", m_name.GetCStr());
bufferViewDesc.m_elementFormat = RHI::ValidateFormat(format, formatLocation.c_str(), formatFallbacks, capabilities);
}
else if (m_unifiedScopeDesc.GetType() == RHI::AttachmentType::Image)
{
RHI::ImageViewDescriptor& imageViewDesc = m_unifiedScopeDesc.GetImageViewDescriptor();
RHI::Format format = imageViewDesc.m_overrideFormat;
AZStd::string formatLocation = AZStd::string::format("ImageViewDescriptor on PassAttachmentBinding [%s]", m_name.GetCStr());
imageViewDesc.m_overrideFormat = RHI::ValidateFormat(format, formatLocation.c_str(), formatFallbacks, capabilities);
}
}
RHI::ScopeAttachmentAccess PassAttachmentBinding::GetAttachmentAccess() const
{
RHI::ScopeAttachmentAccess access = RPI::GetAttachmentAccess(m_slotType);
access = AdjustAccessBasedOnUsage(access, m_scopeAttachmentUsage);
return access;
}
void PassAttachmentBinding::SetAttachment(const Ptr<PassAttachment>& attachment)
{
m_attachment = attachment;
m_unifiedScopeDesc.m_attachmentId = attachment->GetAttachmentId();
// setup scope descriptors for transient attachments if they weren't set in slot
if (m_unifiedScopeDesc.GetType() == RHI::AttachmentType::Uninitialized)
{
if (attachment->m_lifetime == RHI::AttachmentLifetimeType::Transient)
{
if (attachment->GetAttachmentType() == RHI::AttachmentType::Buffer)
{
//AZ_Assert(false, "Transient buffer's buffer view need to be set in slot");
m_unifiedScopeDesc.SetAsBuffer(RHI::BufferViewDescriptor());
}
else if (attachment->GetAttachmentType() == RHI::AttachmentType::Image)
{
m_unifiedScopeDesc.SetAsImage(RHI::ImageViewDescriptor());
}
}
else if (attachment->m_lifetime == RHI::AttachmentLifetimeType::Imported)
{
if (attachment->m_importedResource)
{
if (attachment->GetAttachmentType() == RHI::AttachmentType::Buffer)
{
Buffer* buffer = static_cast<Buffer*>(attachment->m_importedResource.get());
m_unifiedScopeDesc.SetAsBuffer(buffer->GetBufferViewDescriptor());
}
else if (attachment->GetAttachmentType() == RHI::AttachmentType::Image)
{
AttachmentImage* image = static_cast<AttachmentImage*>(attachment->m_importedResource.get());
m_unifiedScopeDesc.SetAsImage(image->GetImageView()->GetDescriptor());
}
}
else
{
AZ_Assert(false, "Imported pass attachment should have the m_importedResource set");
}
}
}
RHI::FormatCapabilities capabilities = RHI::GetCapabilities(m_scopeAttachmentUsage, GetAttachmentAccess(), m_unifiedScopeDesc.GetType());
m_attachment->ValidateDeviceFormats(AZStd::vector<RHI::Format>(), capabilities);
m_attachment->OnAttached(*this);
AZ_Error("PassSystem", m_unifiedScopeDesc.GetType() == attachment->GetAttachmentType(),
"Attachment must have same type as unified scope descriptor");
}
} // namespace RPI
} // namespace AZ