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.
292 lines
15 KiB
C++
292 lines
15 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.Reflect/RenderAttachmentLayoutBuilder.h>
|
|
#include <AzCore/std/containers/unordered_map.h>
|
|
|
|
namespace AZ
|
|
{
|
|
namespace RHI
|
|
{
|
|
RenderAttachmentLayoutBuilder::RenderAttachmentLayoutBuilder()
|
|
{
|
|
Reset();
|
|
}
|
|
|
|
ResultCode RenderAttachmentLayoutBuilder::End(RenderAttachmentLayout& builtRenderAttachmentLayout)
|
|
{
|
|
auto& renderAttachmentFormats = builtRenderAttachmentLayout.m_attachmentFormats;
|
|
Format depthStencilFormat = Format::Unknown;
|
|
AZStd::unordered_map<AZ::Name, uint32_t> renderAttachmentsMap;
|
|
// This lambda will handle if the render attachment needs to resolve and will add a resolve attachment if needed.
|
|
auto handleResolveAttachment = [&](const SubpassAttachmentLayoutBuilder::RenderAttachmentEntry& attachment, uint32_t& resolveAttachmentIndex)
|
|
{
|
|
resolveAttachmentIndex = InvalidRenderAttachmentIndex;
|
|
if (!attachment.m_resolveName.IsEmpty())
|
|
{
|
|
AttachmentLoadStoreAction loadStoreAction;
|
|
loadStoreAction.m_loadAction = AttachmentLoadAction::DontCare;
|
|
loadStoreAction.m_storeAction = AttachmentStoreAction::Store;
|
|
auto findResolveIter = renderAttachmentsMap.find(attachment.m_resolveName);
|
|
if (findResolveIter == renderAttachmentsMap.end())
|
|
{
|
|
if (attachment.m_format == Format::Unknown)
|
|
{
|
|
AZ_Assert(false, "Invalid format for resolve attachment %s", attachment.m_name.GetCStr());
|
|
return ResultCode::InvalidArgument;
|
|
}
|
|
resolveAttachmentIndex = builtRenderAttachmentLayout.m_attachmentCount++;
|
|
renderAttachmentsMap[attachment.m_resolveName] = resolveAttachmentIndex;
|
|
renderAttachmentFormats[resolveAttachmentIndex] = attachment.m_format;
|
|
}
|
|
else
|
|
{
|
|
resolveAttachmentIndex = findResolveIter->second;
|
|
}
|
|
|
|
if (attachment.m_format != Format::Unknown && renderAttachmentFormats[resolveAttachmentIndex] != attachment.m_format)
|
|
{
|
|
AZ_Assert(false, "Incompatible format for resolve attachment %s. Expected %d. Actual %d", attachment.m_name.GetCStr(), renderAttachmentFormats[resolveAttachmentIndex], attachment.m_format);
|
|
return ResultCode::InvalidArgument;
|
|
}
|
|
}
|
|
return ResultCode::Success;
|
|
};
|
|
|
|
for (const auto& builder : m_subpassLayoutBuilders)
|
|
{
|
|
SubpassRenderAttachmentLayout& subpassLayout = builtRenderAttachmentLayout.m_subpassLayouts[builtRenderAttachmentLayout.m_subpassCount++];
|
|
subpassLayout.m_rendertargetCount = static_cast<uint32_t>(builder.m_renderTargetAttachments.size());
|
|
subpassLayout.m_subpassInputCount = static_cast<uint32_t>(builder.m_subpassInputAttachments.size());
|
|
|
|
// First add the resolve attachments, so they can be found when adding the MS attachments.
|
|
for (uint32_t i = 0; i < builder.m_renderTargetAttachments.size(); ++i)
|
|
{
|
|
const SubpassAttachmentLayoutBuilder::RenderAttachmentEntry& renderTargetAttachment = builder.m_renderTargetAttachments[i];
|
|
uint32_t resolveAttachmentIndex;
|
|
handleResolveAttachment(renderTargetAttachment, resolveAttachmentIndex);
|
|
}
|
|
|
|
uint32_t resolveAttachmentIndex;
|
|
ResultCode result = handleResolveAttachment(builder.m_depthStencilAttachment, resolveAttachmentIndex);
|
|
|
|
for (uint32_t i = 0; i < builder.m_renderTargetAttachments.size(); ++i)
|
|
{
|
|
const SubpassAttachmentLayoutBuilder::RenderAttachmentEntry& renderTargetAttachment = builder.m_renderTargetAttachments[i];
|
|
uint32_t attachmentIndex = 0;
|
|
// First look if the render target has already been added to the list of attachments.
|
|
auto findIter = renderAttachmentsMap.find(renderTargetAttachment.m_name);
|
|
if (findIter == renderAttachmentsMap.end())
|
|
{
|
|
if (renderTargetAttachment.m_format == Format::Unknown)
|
|
{
|
|
AZ_Assert(false, "Invalid format for rendertarget %s", renderTargetAttachment.m_name.GetCStr());
|
|
return ResultCode::InvalidArgument;
|
|
}
|
|
attachmentIndex = builtRenderAttachmentLayout.m_attachmentCount++;
|
|
renderAttachmentsMap[renderTargetAttachment.m_name] = attachmentIndex;
|
|
renderAttachmentFormats[attachmentIndex] = renderTargetAttachment.m_format;
|
|
}
|
|
else
|
|
{
|
|
attachmentIndex = findIter->second;
|
|
}
|
|
|
|
// Add the use of the attachment to the subpass.
|
|
result = handleResolveAttachment(renderTargetAttachment, resolveAttachmentIndex);
|
|
if (result != ResultCode::Success)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
if (renderTargetAttachment.m_format != Format::Unknown && renderAttachmentFormats[attachmentIndex] != renderTargetAttachment.m_format)
|
|
{
|
|
AZ_Assert(false, "Incompatible format for attachment %s. Expected %d. Actual %d", renderTargetAttachment.m_name.GetCStr(), renderAttachmentFormats[attachmentIndex], renderTargetAttachment.m_format);
|
|
return ResultCode::InvalidArgument;
|
|
}
|
|
|
|
subpassLayout.m_rendertargetDescriptors[i] = RenderAttachmentDescriptor{ attachmentIndex, resolveAttachmentIndex, renderTargetAttachment.m_loadStoreAction };
|
|
}
|
|
|
|
if (!builder.m_depthStencilAttachment.m_name.IsEmpty())
|
|
{
|
|
// Check if the depth/stencil has already been added and if it has, check if the format is the same.
|
|
if (depthStencilFormat != Format::Unknown &&
|
|
builder.m_depthStencilAttachment.m_format != Format::Unknown &&
|
|
depthStencilFormat != builder.m_depthStencilAttachment.m_format)
|
|
{
|
|
AZ_Assert(false, "Invalid depth stencil format. Expected %s. Current %s", ToString(depthStencilFormat), ToString(builder.m_depthStencilAttachment.m_format));
|
|
return ResultCode::InvalidArgument;
|
|
}
|
|
|
|
// Search for the depth/stencil attachment in the list of added attachments.
|
|
uint32_t attachmentIndex = 0;
|
|
auto findIter = renderAttachmentsMap.find(builder.m_depthStencilAttachment.m_name);
|
|
if (findIter == renderAttachmentsMap.end())
|
|
{
|
|
if (builder.m_depthStencilAttachment.m_format == Format::Unknown)
|
|
{
|
|
AZ_Assert(false, "Invalid depth stencil format %s", ToString(builder.m_depthStencilAttachment.m_format));
|
|
return ResultCode::InvalidArgument;
|
|
}
|
|
|
|
depthStencilFormat = builder.m_depthStencilAttachment.m_format;
|
|
attachmentIndex = builtRenderAttachmentLayout.m_attachmentCount++;
|
|
renderAttachmentsMap[builder.m_depthStencilAttachment.m_name] = attachmentIndex;
|
|
renderAttachmentFormats[attachmentIndex] = depthStencilFormat;
|
|
}
|
|
else
|
|
{
|
|
attachmentIndex = findIter->second;
|
|
}
|
|
|
|
result = handleResolveAttachment(builder.m_depthStencilAttachment, resolveAttachmentIndex);
|
|
if (result != ResultCode::Success)
|
|
{
|
|
return result;
|
|
}
|
|
subpassLayout.m_depthStencilDescriptor = RenderAttachmentDescriptor{ attachmentIndex, resolveAttachmentIndex, builder.m_depthStencilAttachment.m_loadStoreAction };
|
|
}
|
|
|
|
// Add the subpass inputs.
|
|
for (uint32_t i = 0; i < builder.m_subpassInputAttachments.size(); ++i)
|
|
{
|
|
auto& subpassInputAttachmentName = builder.m_subpassInputAttachments[i];
|
|
uint32_t attachmentIndex = 0;
|
|
auto findIter = renderAttachmentsMap.find(subpassInputAttachmentName);
|
|
if (findIter == renderAttachmentsMap.end())
|
|
{
|
|
AZ_Assert(false, "Could not find subpassInput %d", subpassInputAttachmentName.GetCStr());
|
|
return ResultCode::InvalidArgument;
|
|
}
|
|
|
|
attachmentIndex += findIter->second;
|
|
subpassLayout.m_subpassInputIndices[i] = attachmentIndex;
|
|
}
|
|
}
|
|
|
|
return ResultCode::Success;
|
|
}
|
|
|
|
void RenderAttachmentLayoutBuilder::Reset()
|
|
{
|
|
m_subpassLayoutBuilders.clear();
|
|
}
|
|
|
|
RenderAttachmentLayoutBuilder::SubpassAttachmentLayoutBuilder* RenderAttachmentLayoutBuilder::AddSubpass()
|
|
{
|
|
m_subpassLayoutBuilders.push_back(SubpassAttachmentLayoutBuilder(static_cast<uint32_t>(m_subpassLayoutBuilders.size())));
|
|
return &m_subpassLayoutBuilders.back();
|
|
}
|
|
|
|
RenderAttachmentLayoutBuilder::SubpassAttachmentLayoutBuilder::SubpassAttachmentLayoutBuilder(uint32_t subpassIndex)
|
|
: m_subpassIndex(subpassIndex)
|
|
{}
|
|
|
|
RenderAttachmentLayoutBuilder::SubpassAttachmentLayoutBuilder* RenderAttachmentLayoutBuilder::SubpassAttachmentLayoutBuilder::RenderTargetAttachment(
|
|
Format format,
|
|
const AZ::Name& name /*= {}*/,
|
|
const AttachmentLoadStoreAction& loadStoreAction /*= AttachmentLoadStoreAction()*/,
|
|
bool resolve /*= false*/)
|
|
{
|
|
AZ::Name attachmentName = name;
|
|
if (attachmentName.IsEmpty())
|
|
{
|
|
// Assign a temp name if it's empty.
|
|
attachmentName = AZStd::string::format("Color%zu_Subpass%d", m_renderTargetAttachments.size(), m_subpassIndex);
|
|
}
|
|
|
|
m_renderTargetAttachments.push_back({ attachmentName, format, loadStoreAction });
|
|
if (resolve)
|
|
{
|
|
return ResolveAttachment(attachmentName);
|
|
}
|
|
return this;
|
|
}
|
|
|
|
RenderAttachmentLayoutBuilder::SubpassAttachmentLayoutBuilder* RenderAttachmentLayoutBuilder::SubpassAttachmentLayoutBuilder::RenderTargetAttachment(
|
|
Format format,
|
|
bool resolve)
|
|
{
|
|
return RenderTargetAttachment(format, {}, AttachmentLoadStoreAction(), resolve);
|
|
}
|
|
|
|
RenderAttachmentLayoutBuilder::SubpassAttachmentLayoutBuilder* RenderAttachmentLayoutBuilder::SubpassAttachmentLayoutBuilder::RenderTargetAttachment(
|
|
const AZ::Name& name,
|
|
bool resolve)
|
|
{
|
|
return RenderTargetAttachment(Format::Unknown, name, AttachmentLoadStoreAction(), resolve);
|
|
}
|
|
|
|
RenderAttachmentLayoutBuilder::SubpassAttachmentLayoutBuilder* RenderAttachmentLayoutBuilder::SubpassAttachmentLayoutBuilder::RenderTargetAttachment(
|
|
const AZ::Name& name,
|
|
const AttachmentLoadStoreAction& loadStoreAction /*= AttachmentLoadStoreAction()*/,
|
|
bool resolve /*= false*/)
|
|
{
|
|
return RenderTargetAttachment(Format::Unknown, name, loadStoreAction, resolve);
|
|
}
|
|
|
|
RenderAttachmentLayoutBuilder::SubpassAttachmentLayoutBuilder* RenderAttachmentLayoutBuilder::SubpassAttachmentLayoutBuilder::ResolveAttachment(
|
|
const AZ::Name& sourceName,
|
|
const AZ::Name& resolveName /*= {}*/)
|
|
{
|
|
AZ::Name attachmentName = resolveName;
|
|
if (attachmentName.IsEmpty())
|
|
{
|
|
// Assign a temp name if it's empty.
|
|
attachmentName = AZStd::string::format("Resolve%zu_Subpass%d", m_renderTargetAttachments.size(), m_subpassIndex);
|
|
}
|
|
|
|
auto findIter = AZStd::find_if(m_renderTargetAttachments.begin(), m_renderTargetAttachments.end(), [sourceName](const RenderAttachmentEntry& entry)
|
|
{
|
|
return entry.m_name == sourceName;
|
|
});
|
|
|
|
if (findIter == m_renderTargetAttachments.end())
|
|
{
|
|
AZ_Assert(false, "Failed to find render target %d to resolve", sourceName.GetCStr());
|
|
return this;
|
|
}
|
|
|
|
(*findIter).m_resolveName = attachmentName;
|
|
return this;
|
|
}
|
|
|
|
RenderAttachmentLayoutBuilder::SubpassAttachmentLayoutBuilder* RenderAttachmentLayoutBuilder::SubpassAttachmentLayoutBuilder::DepthStencilAttachment(
|
|
Format format,
|
|
const AZ::Name& name /*= {}*/,
|
|
const AttachmentLoadStoreAction& loadStoreAction /*= AttachmentLoadStoreAction()*/)
|
|
{
|
|
AZ_Assert(m_depthStencilAttachment.m_format == Format::Unknown || format == m_depthStencilAttachment.m_format, "DepthStencil format has already been set");
|
|
// Assign a temp name if it's empty.
|
|
m_depthStencilAttachment = RenderAttachmentEntry{ name.IsEmpty() ? AZ::Name("DepthStencil") : name, format, loadStoreAction, {} };
|
|
return this;
|
|
}
|
|
|
|
RenderAttachmentLayoutBuilder::SubpassAttachmentLayoutBuilder* RenderAttachmentLayoutBuilder::SubpassAttachmentLayoutBuilder::DepthStencilAttachment(
|
|
const AZ::Name name /*= {}*/,
|
|
const AttachmentLoadStoreAction& loadStoreAction /*= AttachmentLoadStoreAction()*/)
|
|
{
|
|
return DepthStencilAttachment(m_depthStencilAttachment.m_format, name, loadStoreAction);
|
|
}
|
|
|
|
RenderAttachmentLayoutBuilder::SubpassAttachmentLayoutBuilder* RenderAttachmentLayoutBuilder::SubpassAttachmentLayoutBuilder::DepthStencilAttachment(
|
|
const AttachmentLoadStoreAction& loadStoreAction)
|
|
{
|
|
return DepthStencilAttachment(m_depthStencilAttachment.m_format, {}, loadStoreAction);
|
|
}
|
|
|
|
RenderAttachmentLayoutBuilder::SubpassAttachmentLayoutBuilder* RenderAttachmentLayoutBuilder::SubpassAttachmentLayoutBuilder::SubpassInputAttachment(
|
|
const AZ::Name& name)
|
|
{
|
|
m_subpassInputAttachments.push_back(name);
|
|
return this;
|
|
}
|
|
} // namespace RHI
|
|
} // namespace AZ
|