RenderAttachmentLayoutBuilder.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include <Atom/RHI.Reflect/RenderAttachmentLayoutBuilder.h>
  9. #include <AzCore/std/containers/unordered_map.h>
  10. namespace AZ::RHI
  11. {
  12. RenderAttachmentLayoutBuilder::RenderAttachmentLayoutBuilder()
  13. {
  14. Reset();
  15. }
  16. ResultCode RenderAttachmentLayoutBuilder::End(RenderAttachmentLayout& builtRenderAttachmentLayout)
  17. {
  18. auto& renderAttachmentFormats = builtRenderAttachmentLayout.m_attachmentFormats;
  19. Format depthStencilFormat = Format::Unknown;
  20. AZStd::unordered_map<AZ::Name, uint32_t> renderAttachmentsMap;
  21. // This lambda will handle if the render attachment needs to resolve and will add a resolve attachment if needed.
  22. auto handleResolveAttachment = [&](const SubpassAttachmentLayoutBuilder::RenderAttachmentEntry& attachment, uint32_t& resolveAttachmentIndex)
  23. {
  24. resolveAttachmentIndex = InvalidRenderAttachmentIndex;
  25. if (!attachment.m_resolveName.IsEmpty())
  26. {
  27. AttachmentLoadStoreAction loadStoreAction;
  28. loadStoreAction.m_loadAction = AttachmentLoadAction::DontCare;
  29. loadStoreAction.m_storeAction = AttachmentStoreAction::Store;
  30. auto findResolveIter = renderAttachmentsMap.find(attachment.m_resolveName);
  31. if (findResolveIter == renderAttachmentsMap.end())
  32. {
  33. if (attachment.m_format == Format::Unknown)
  34. {
  35. AZ_Assert(false, "Invalid format for resolve attachment %s", attachment.m_name.GetCStr());
  36. return ResultCode::InvalidArgument;
  37. }
  38. resolveAttachmentIndex = builtRenderAttachmentLayout.m_attachmentCount++;
  39. renderAttachmentsMap[attachment.m_resolveName] = resolveAttachmentIndex;
  40. renderAttachmentFormats[resolveAttachmentIndex] = attachment.m_format;
  41. }
  42. else
  43. {
  44. resolveAttachmentIndex = findResolveIter->second;
  45. }
  46. if (attachment.m_format != Format::Unknown && renderAttachmentFormats[resolveAttachmentIndex] != attachment.m_format)
  47. {
  48. AZ_Assert(false, "Incompatible format for resolve attachment %s. Expected %d. Actual %d", attachment.m_name.GetCStr(), renderAttachmentFormats[resolveAttachmentIndex], attachment.m_format);
  49. return ResultCode::InvalidArgument;
  50. }
  51. }
  52. return ResultCode::Success;
  53. };
  54. for (const auto& builder : m_subpassLayoutBuilders)
  55. {
  56. SubpassRenderAttachmentLayout& subpassLayout = builtRenderAttachmentLayout.m_subpassLayouts[builtRenderAttachmentLayout.m_subpassCount++];
  57. subpassLayout.m_rendertargetCount = static_cast<uint32_t>(builder.m_renderTargetAttachments.size());
  58. subpassLayout.m_subpassInputCount = static_cast<uint32_t>(builder.m_subpassInputAttachments.size());
  59. // First add the resolve attachments, so they can be found when adding the MS attachments.
  60. for (uint32_t i = 0; i < builder.m_renderTargetAttachments.size(); ++i)
  61. {
  62. const SubpassAttachmentLayoutBuilder::RenderAttachmentEntry& renderTargetAttachment = builder.m_renderTargetAttachments[i];
  63. uint32_t resolveAttachmentIndex;
  64. handleResolveAttachment(renderTargetAttachment, resolveAttachmentIndex);
  65. }
  66. uint32_t resolveAttachmentIndex;
  67. ResultCode result = handleResolveAttachment(builder.m_depthStencilAttachment, resolveAttachmentIndex);
  68. for (uint32_t i = 0; i < builder.m_renderTargetAttachments.size(); ++i)
  69. {
  70. const SubpassAttachmentLayoutBuilder::RenderAttachmentEntry& renderTargetAttachment = builder.m_renderTargetAttachments[i];
  71. uint32_t attachmentIndex = 0;
  72. // First look if the render target has already been added to the list of attachments.
  73. auto findIter = renderAttachmentsMap.find(renderTargetAttachment.m_name);
  74. if (findIter == renderAttachmentsMap.end())
  75. {
  76. if (renderTargetAttachment.m_format == Format::Unknown)
  77. {
  78. AZ_Assert(false, "Invalid format for rendertarget %s", renderTargetAttachment.m_name.GetCStr());
  79. return ResultCode::InvalidArgument;
  80. }
  81. attachmentIndex = builtRenderAttachmentLayout.m_attachmentCount++;
  82. renderAttachmentsMap[renderTargetAttachment.m_name] = attachmentIndex;
  83. renderAttachmentFormats[attachmentIndex] = renderTargetAttachment.m_format;
  84. }
  85. else
  86. {
  87. attachmentIndex = findIter->second;
  88. }
  89. // Add the use of the attachment to the subpass.
  90. result = handleResolveAttachment(renderTargetAttachment, resolveAttachmentIndex);
  91. if (result != ResultCode::Success)
  92. {
  93. return result;
  94. }
  95. if (renderTargetAttachment.m_format != Format::Unknown && renderAttachmentFormats[attachmentIndex] != renderTargetAttachment.m_format)
  96. {
  97. AZ_Assert(false, "Incompatible format for attachment %s. Expected %d. Actual %d", renderTargetAttachment.m_name.GetCStr(), renderAttachmentFormats[attachmentIndex], renderTargetAttachment.m_format);
  98. return ResultCode::InvalidArgument;
  99. }
  100. subpassLayout.m_rendertargetDescriptors[i] = RenderAttachmentDescriptor{ attachmentIndex, resolveAttachmentIndex, renderTargetAttachment.m_loadStoreAction };
  101. }
  102. if (!builder.m_depthStencilAttachment.m_name.IsEmpty())
  103. {
  104. // Check if the depth/stencil has already been added and if it has, check if the format is the same.
  105. if (depthStencilFormat != Format::Unknown &&
  106. builder.m_depthStencilAttachment.m_format != Format::Unknown &&
  107. depthStencilFormat != builder.m_depthStencilAttachment.m_format)
  108. {
  109. AZ_Assert(false, "Invalid depth stencil format. Expected %s. Current %s", ToString(depthStencilFormat), ToString(builder.m_depthStencilAttachment.m_format));
  110. return ResultCode::InvalidArgument;
  111. }
  112. // Search for the depth/stencil attachment in the list of added attachments.
  113. uint32_t attachmentIndex = 0;
  114. auto findIter = renderAttachmentsMap.find(builder.m_depthStencilAttachment.m_name);
  115. if (findIter == renderAttachmentsMap.end())
  116. {
  117. if (builder.m_depthStencilAttachment.m_format == Format::Unknown)
  118. {
  119. AZ_Assert(false, "Invalid depth stencil format %s", ToString(builder.m_depthStencilAttachment.m_format));
  120. return ResultCode::InvalidArgument;
  121. }
  122. depthStencilFormat = builder.m_depthStencilAttachment.m_format;
  123. attachmentIndex = builtRenderAttachmentLayout.m_attachmentCount++;
  124. renderAttachmentsMap[builder.m_depthStencilAttachment.m_name] = attachmentIndex;
  125. renderAttachmentFormats[attachmentIndex] = depthStencilFormat;
  126. }
  127. else
  128. {
  129. attachmentIndex = findIter->second;
  130. }
  131. result = handleResolveAttachment(builder.m_depthStencilAttachment, resolveAttachmentIndex);
  132. if (result != ResultCode::Success)
  133. {
  134. return result;
  135. }
  136. subpassLayout.m_depthStencilDescriptor = RenderAttachmentDescriptor{ attachmentIndex, resolveAttachmentIndex, builder.m_depthStencilAttachment.m_loadStoreAction };
  137. }
  138. // Add the subpass inputs.
  139. for (uint32_t i = 0; i < builder.m_subpassInputAttachments.size(); ++i)
  140. {
  141. auto& subpassInputAttachmentName = builder.m_subpassInputAttachments[i].m_name;
  142. uint32_t attachmentIndex = 0;
  143. auto findIter = renderAttachmentsMap.find(subpassInputAttachmentName);
  144. if (findIter == renderAttachmentsMap.end())
  145. {
  146. AZ_Assert(false, "Could not find subpassInput %d", subpassInputAttachmentName.GetCStr());
  147. return ResultCode::InvalidArgument;
  148. }
  149. attachmentIndex += findIter->second;
  150. subpassLayout.m_subpassInputDescriptors[i] =
  151. SubpassInputDescriptor{ attachmentIndex, builder.m_subpassInputAttachments[i].m_imageAspects };
  152. }
  153. // Add the shading rate attachment.
  154. if (!builder.m_shadingRateAttachment.m_name.IsEmpty())
  155. {
  156. uint32_t attachmentIndex = 0;
  157. auto findIter = renderAttachmentsMap.find(builder.m_shadingRateAttachment.m_name);
  158. if (findIter == renderAttachmentsMap.end())
  159. {
  160. if (builder.m_shadingRateAttachment.m_format == Format::Unknown)
  161. {
  162. AZ_Assert(false, "Invalid shading rate format %s", ToString(builder.m_shadingRateAttachment.m_format));
  163. return ResultCode::InvalidArgument;
  164. }
  165. attachmentIndex = builtRenderAttachmentLayout.m_attachmentCount++;
  166. renderAttachmentsMap[builder.m_shadingRateAttachment.m_name] = attachmentIndex;
  167. renderAttachmentFormats[attachmentIndex] = builder.m_shadingRateAttachment.m_format;
  168. }
  169. else
  170. {
  171. attachmentIndex = findIter->second;
  172. }
  173. subpassLayout.m_shadingRateDescriptor = RenderAttachmentDescriptor{ attachmentIndex,
  174. InvalidRenderAttachmentIndex,
  175. builder.m_shadingRateAttachment.m_loadStoreAction };
  176. }
  177. }
  178. return ResultCode::Success;
  179. }
  180. void RenderAttachmentLayoutBuilder::Reset()
  181. {
  182. m_subpassLayoutBuilders.clear();
  183. }
  184. RenderAttachmentLayoutBuilder::SubpassAttachmentLayoutBuilder* RenderAttachmentLayoutBuilder::AddSubpass()
  185. {
  186. m_subpassLayoutBuilders.push_back(SubpassAttachmentLayoutBuilder(static_cast<uint32_t>(m_subpassLayoutBuilders.size())));
  187. return &m_subpassLayoutBuilders.back();
  188. }
  189. RenderAttachmentLayoutBuilder::SubpassAttachmentLayoutBuilder::SubpassAttachmentLayoutBuilder(uint32_t subpassIndex)
  190. : m_subpassIndex(subpassIndex)
  191. {}
  192. RenderAttachmentLayoutBuilder::SubpassAttachmentLayoutBuilder* RenderAttachmentLayoutBuilder::SubpassAttachmentLayoutBuilder::RenderTargetAttachment(
  193. Format format,
  194. const AZ::Name& name /*= {}*/,
  195. const AttachmentLoadStoreAction& loadStoreAction /*= AttachmentLoadStoreAction()*/,
  196. bool resolve /*= false*/)
  197. {
  198. AZ::Name attachmentName = name;
  199. if (attachmentName.IsEmpty())
  200. {
  201. // Assign a temp name if it's empty.
  202. attachmentName = AZStd::string::format("Color%zu_Subpass%d", m_renderTargetAttachments.size(), m_subpassIndex);
  203. }
  204. m_renderTargetAttachments.push_back({ attachmentName, format, loadStoreAction });
  205. if (resolve)
  206. {
  207. return ResolveAttachment(attachmentName);
  208. }
  209. return this;
  210. }
  211. RenderAttachmentLayoutBuilder::SubpassAttachmentLayoutBuilder* RenderAttachmentLayoutBuilder::SubpassAttachmentLayoutBuilder::RenderTargetAttachment(
  212. Format format,
  213. bool resolve)
  214. {
  215. return RenderTargetAttachment(format, {}, AttachmentLoadStoreAction(), resolve);
  216. }
  217. RenderAttachmentLayoutBuilder::SubpassAttachmentLayoutBuilder* RenderAttachmentLayoutBuilder::SubpassAttachmentLayoutBuilder::RenderTargetAttachment(
  218. const AZ::Name& name,
  219. bool resolve)
  220. {
  221. return RenderTargetAttachment(Format::Unknown, name, AttachmentLoadStoreAction(), resolve);
  222. }
  223. RenderAttachmentLayoutBuilder::SubpassAttachmentLayoutBuilder* RenderAttachmentLayoutBuilder::SubpassAttachmentLayoutBuilder::RenderTargetAttachment(
  224. const AZ::Name& name,
  225. const AttachmentLoadStoreAction& loadStoreAction /*= AttachmentLoadStoreAction()*/,
  226. bool resolve /*= false*/)
  227. {
  228. return RenderTargetAttachment(Format::Unknown, name, loadStoreAction, resolve);
  229. }
  230. RenderAttachmentLayoutBuilder::SubpassAttachmentLayoutBuilder* RenderAttachmentLayoutBuilder::SubpassAttachmentLayoutBuilder::ResolveAttachment(
  231. const AZ::Name& sourceName,
  232. const AZ::Name& resolveName /*= {}*/)
  233. {
  234. AZ::Name attachmentName = resolveName;
  235. if (attachmentName.IsEmpty())
  236. {
  237. // Assign a temp name if it's empty.
  238. attachmentName = AZStd::string::format("Resolve%zu_Subpass%d", m_renderTargetAttachments.size(), m_subpassIndex);
  239. }
  240. auto findIter = AZStd::find_if(m_renderTargetAttachments.begin(), m_renderTargetAttachments.end(), [sourceName](const RenderAttachmentEntry& entry)
  241. {
  242. return entry.m_name == sourceName;
  243. });
  244. if (findIter == m_renderTargetAttachments.end())
  245. {
  246. AZ_Assert(false, "Failed to find render target %d to resolve", sourceName.GetCStr());
  247. return this;
  248. }
  249. (*findIter).m_resolveName = attachmentName;
  250. return this;
  251. }
  252. RenderAttachmentLayoutBuilder::SubpassAttachmentLayoutBuilder* RenderAttachmentLayoutBuilder::SubpassAttachmentLayoutBuilder::DepthStencilAttachment(
  253. Format format,
  254. const AZ::Name& name /*= {}*/,
  255. const AttachmentLoadStoreAction& loadStoreAction /*= AttachmentLoadStoreAction()*/)
  256. {
  257. AZ_Assert(m_depthStencilAttachment.m_format == Format::Unknown || format == m_depthStencilAttachment.m_format, "DepthStencil format has already been set");
  258. // Assign a temp name if it's empty.
  259. m_depthStencilAttachment = RenderAttachmentEntry{ name.IsEmpty() ? AZ::Name("DepthStencil") : name, format, loadStoreAction, {} };
  260. return this;
  261. }
  262. RenderAttachmentLayoutBuilder::SubpassAttachmentLayoutBuilder* RenderAttachmentLayoutBuilder::SubpassAttachmentLayoutBuilder::DepthStencilAttachment(
  263. const AZ::Name name /*= {}*/,
  264. const AttachmentLoadStoreAction& loadStoreAction /*= AttachmentLoadStoreAction()*/)
  265. {
  266. return DepthStencilAttachment(m_depthStencilAttachment.m_format, name, loadStoreAction);
  267. }
  268. RenderAttachmentLayoutBuilder::SubpassAttachmentLayoutBuilder* RenderAttachmentLayoutBuilder::SubpassAttachmentLayoutBuilder::DepthStencilAttachment(
  269. const AttachmentLoadStoreAction& loadStoreAction)
  270. {
  271. return DepthStencilAttachment(m_depthStencilAttachment.m_format, {}, loadStoreAction);
  272. }
  273. RenderAttachmentLayoutBuilder::SubpassAttachmentLayoutBuilder* RenderAttachmentLayoutBuilder::SubpassAttachmentLayoutBuilder::SubpassInputAttachment(
  274. const AZ::Name& name,
  275. RHI::ImageAspectFlags aspectFlags)
  276. {
  277. m_subpassInputAttachments.push_back(SubpassAttachmentEntry{ name, aspectFlags });
  278. return this;
  279. }
  280. RenderAttachmentLayoutBuilder::SubpassAttachmentLayoutBuilder* RenderAttachmentLayoutBuilder::SubpassAttachmentLayoutBuilder::ShadingRateAttachment(
  281. Format format,
  282. const AZ::Name& name /*= {}*/)
  283. {
  284. AZ_Assert(
  285. m_shadingRateAttachment.m_format == Format::Unknown || format == m_shadingRateAttachment.m_format,
  286. "Shading Rate format has already been set");
  287. // Assign a temp name if it's empty.
  288. m_shadingRateAttachment = RenderAttachmentEntry{
  289. name.IsEmpty() ? AZ::Name(AZStd::string::format("ShadingRate_Subpass%d", m_subpassIndex)) : name,
  290. format,
  291. AttachmentLoadStoreAction(),
  292. {}
  293. };
  294. m_shadingRateAttachment.m_loadStoreAction.m_storeAction = AttachmentStoreAction::DontCare;
  295. return this;
  296. }
  297. }