3
0

DisplayMapperPass.cpp 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576
  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/Feature/DisplayMapper/DisplayMapperPass.h>
  9. #include <ACES/Aces.h>
  10. #include <Atom/Feature/ACES/AcesDisplayMapperFeatureProcessor.h>
  11. #include <Atom/RPI.Public/Pass/FullscreenTrianglePass.h>
  12. #include <Atom/RPI.Public/Pass/PassFilter.h>
  13. #include <Atom/RPI.Public/Pass/PassFactory.h>
  14. #include <Atom/RPI.Public/Pass/PassSystemInterface.h>
  15. #include <Atom/RPI.Public/Pass/PassUtils.h>
  16. #include <Atom/RPI.Public/Pass/Specific/SwapChainPass.h>
  17. #include <Atom/RPI.Public/RenderPipeline.h>
  18. #include <Atom/RPI.Public/RPIUtils.h>
  19. #include <Atom/RPI.Public/Scene.h>
  20. #include <Atom/RPI.Public/View.h>
  21. #include <Atom/RPI.Reflect/Pass/ComputePassData.h>
  22. #include <Atom/RPI.Reflect/Pass/FullscreenTrianglePassData.h>
  23. #include <Atom/RPI.Reflect/Asset/AssetUtils.h>
  24. #include <Atom/RHI/Factory.h>
  25. #include <Atom/RHI/FrameScheduler.h>
  26. #include <Atom/RHI/DevicePipelineState.h>
  27. #include <AzCore/Asset/AssetCommon.h>
  28. #include <AzCore/Asset/AssetManagerBus.h>
  29. namespace AZ
  30. {
  31. namespace Render
  32. {
  33. RPI::Ptr<DisplayMapperPass> DisplayMapperPass::Create(const RPI::PassDescriptor& descriptor)
  34. {
  35. RPI::Ptr<DisplayMapperPass> pass = aznew DisplayMapperPass(descriptor);
  36. return pass;
  37. }
  38. DisplayMapperPass::DisplayMapperPass(const RPI::PassDescriptor& descriptor)
  39. : RPI::ParentPass(descriptor)
  40. {
  41. const DisplayMapperPassData* passData = RPI::PassUtils::GetPassData<DisplayMapperPassData>(descriptor);
  42. if (passData != nullptr)
  43. {
  44. m_defaultDisplayMapperConfigurationDescriptor = passData->m_config;
  45. m_mergeLdrGradingLut = passData->m_mergeLdrGradingLut;
  46. m_outputTransformOverrideShader = passData->m_outputTransformOverride;
  47. }
  48. else
  49. {
  50. AcesDisplayMapperFeatureProcessor::GetDefaultDisplayMapperConfiguration(m_defaultDisplayMapperConfigurationDescriptor);
  51. }
  52. UpdateDisplayMapperConfiguration();
  53. }
  54. void DisplayMapperPass::ConfigureDisplayParameters()
  55. {
  56. // [GFX TODO] [ATOM-2450] Logic determine the type of display attached and use it to drive the
  57. // display mapper parameters.
  58. if (m_pipelineOutput && m_pipelineOutput->GetAttachment())
  59. {
  60. m_displayBufferFormat = m_pipelineOutput->GetAttachment()->m_descriptor.m_image.m_format;
  61. }
  62. if (m_displayBufferFormat != RHI::Format::Unknown)
  63. {
  64. if (m_acesOutputTransformPass)
  65. {
  66. m_acesOutputTransformPass->SetAcesParameterOverrides(m_displayMapperConfigurationDescriptor.m_acesParameterOverrides);
  67. m_acesOutputTransformPass->SetDisplayBufferFormat(m_displayBufferFormat);
  68. }
  69. if (m_bakeAcesOutputTransformLutPass)
  70. {
  71. m_bakeAcesOutputTransformLutPass->SetDisplayBufferFormat(m_displayBufferFormat);
  72. AZ_Assert(m_acesOutputTransformLutPass != nullptr, "AcesOutputTransformLutPass should be created when baking ACES LUTs.");
  73. m_acesOutputTransformLutPass->SetShaperParams(m_bakeAcesOutputTransformLutPass->GetShaperParams());
  74. }
  75. if (m_outputTransformPass)
  76. {
  77. if (m_displayMapperConfigurationDescriptor.m_operationType == DisplayMapperOperationType::Reinhard ||
  78. m_displayMapperConfigurationDescriptor.m_operationType == DisplayMapperOperationType::AcesFitted ||
  79. m_displayMapperConfigurationDescriptor.m_operationType == DisplayMapperOperationType::AcesFilmic)
  80. {
  81. // When using Reinhard tonemapper, a gamma of 2.2 for the transfer function is used for LDR display,
  82. // and PQ is used for HDR.
  83. if (m_displayBufferFormat == RHI::Format::R8G8B8A8_UNORM ||
  84. m_displayBufferFormat == RHI::Format::B8G8R8A8_UNORM)
  85. {
  86. m_outputTransformPass->SetTransferFunctionType(TransferFunctionType::Gamma22);
  87. }
  88. else
  89. {
  90. m_outputTransformPass->SetTransferFunctionType(TransferFunctionType::PerceptualQuantizer);
  91. }
  92. }
  93. else if (m_displayMapperConfigurationDescriptor.m_operationType == DisplayMapperOperationType::Filmic)
  94. {
  95. m_outputTransformPass->SetTransferFunctionType(TransferFunctionType::None);
  96. }
  97. m_outputTransformPass->SetDisplayBufferFormat(m_displayBufferFormat);
  98. }
  99. }
  100. }
  101. void DisplayMapperPass::BuildInternal()
  102. {
  103. const Name outputName = Name{ "Output" };
  104. Name inputPass = Name{ "Parent" };
  105. Name inputPassAttachment = Name{ "Input" };
  106. if (m_acesOutputTransformPass)
  107. {
  108. m_acesOutputTransformPass->SetInputReferencePassName(inputPass);
  109. m_acesOutputTransformPass->SetInputReferenceAttachmentName(inputPassAttachment);
  110. inputPass = m_acesOutputTransformPassName;
  111. inputPassAttachment = outputName;
  112. }
  113. else if (m_acesOutputTransformLutPass)
  114. {
  115. m_acesOutputTransformLutPass->SetInputReferencePassName(inputPass);
  116. m_acesOutputTransformLutPass->SetInputReferenceAttachmentName(inputPassAttachment);
  117. inputPass = m_acesOutputTransformLutPassName;
  118. inputPassAttachment = outputName;
  119. }
  120. else if (m_displayMapperPassthroughPass)
  121. {
  122. m_displayMapperPassthroughPass->SetInputReferencePassName(inputPass);
  123. m_displayMapperPassthroughPass->SetInputReferenceAttachmentName(inputPassAttachment);
  124. inputPass = m_displayMapperPassthroughPassName;
  125. inputPassAttachment = outputName;
  126. }
  127. else if (m_displayMapperSRGBPass)
  128. {
  129. m_displayMapperSRGBPass->SetInputReferencePassName(inputPass);
  130. m_displayMapperSRGBPass->SetInputReferenceAttachmentName(inputPassAttachment);
  131. inputPass = m_displayMapperSRGBPassName;
  132. inputPassAttachment = outputName;
  133. }
  134. else if (m_outputTransformPass)
  135. {
  136. m_outputTransformPass->SetInputReferencePassName(inputPass);
  137. m_outputTransformPass->SetInputReferenceAttachmentName(inputPassAttachment);
  138. inputPass = m_outputTransformPassName;
  139. inputPassAttachment = outputName;
  140. }
  141. if (m_ldrGradingLookupTablePass)
  142. {
  143. m_ldrGradingLookupTablePass->SetInputReferencePassName(inputPass);
  144. m_ldrGradingLookupTablePass->SetInputReferenceAttachmentName(inputPassAttachment);
  145. }
  146. m_pipelineOutput = FindAttachmentBinding(Name("PipelineOutput"));
  147. ParentPass::BuildInternal();
  148. }
  149. void DisplayMapperPass::InitializeInternal()
  150. {
  151. // Force update on bindings because children of display mapper pass have their outputs connect to
  152. // their parent's output, which is a non-conventional and non-standard workflow. Parent outputs are
  153. // updated after child outputs, so post-build the child outputs do not yet point to the attachments on
  154. // the parent bindings they are connected to. Forcing this refresh sets the attachment on the child output.
  155. for (const RPI::Ptr<Pass>& child : m_children)
  156. {
  157. child->UpdateConnectedBindings();
  158. }
  159. RPI::ParentPass::InitializeInternal();
  160. }
  161. void DisplayMapperPass::FrameBeginInternal(FramePrepareParams params)
  162. {
  163. ConfigureDisplayParameters();
  164. ParentPass::FrameBeginInternal(params);
  165. }
  166. void DisplayMapperPass::FrameEndInternal()
  167. {
  168. UpdateDisplayMapperConfiguration();
  169. ParentPass::FrameEndInternal();
  170. }
  171. void DisplayMapperPass::CreateChildPassesInternal()
  172. {
  173. ClearChildren();
  174. BuildGradingLutTemplate();
  175. CreateGradingAndAcesPasses();
  176. }
  177. AZStd::shared_ptr<RPI::PassTemplate> CreatePassTemplateHelper(
  178. const Name& templateName, const Name& passClass, bool renderToOwnedImage, const Name& ownedImageName, const char* shaderFilePath)
  179. {
  180. auto passTemplate = AZStd::make_shared<RPI::PassTemplate>();
  181. passTemplate->m_name = templateName;
  182. passTemplate->m_passClass = passClass;
  183. // Slots
  184. passTemplate->m_slots.resize(2);
  185. RPI::PassSlot& inSlot = passTemplate->m_slots[0];
  186. inSlot.m_name = "Input";
  187. inSlot.m_slotType = RPI::PassSlotType::Input;
  188. inSlot.m_scopeAttachmentUsage = RHI::ScopeAttachmentUsage::Shader;
  189. inSlot.m_loadStoreAction.m_loadAction = RHI::AttachmentLoadAction::DontCare;
  190. RPI::PassSlot& outSlot = passTemplate->m_slots[1];
  191. outSlot.m_name = "Output";
  192. outSlot.m_slotType = RPI::PassSlotType::Output;
  193. outSlot.m_scopeAttachmentUsage = RHI::ScopeAttachmentUsage::RenderTarget;
  194. outSlot.m_loadStoreAction.m_loadAction = RHI::AttachmentLoadAction::DontCare;
  195. passTemplate->m_connections.resize(1);
  196. RPI::PassConnection& outConnection = passTemplate->m_connections[0];
  197. if (renderToOwnedImage)
  198. {
  199. // If rendering to it's own image attachment
  200. passTemplate->m_imageAttachments.resize(1);
  201. RPI::PassImageAttachmentDesc& imageAttachment = passTemplate->m_imageAttachments[0];
  202. imageAttachment.m_name = ownedImageName;
  203. imageAttachment.m_sizeSource.m_source.m_pass = "This";
  204. imageAttachment.m_sizeSource.m_source.m_attachment = "Input";
  205. imageAttachment.m_formatSource.m_pass = "This";
  206. imageAttachment.m_formatSource.m_attachment = "Input";
  207. imageAttachment.m_imageDescriptor.m_bindFlags = RHI::ImageBindFlags::CopyRead | RHI::ImageBindFlags::Color | RHI::ImageBindFlags::ShaderReadWrite;
  208. outConnection.m_localSlot = "Output";
  209. outConnection.m_attachmentRef.m_pass = "This";
  210. outConnection.m_attachmentRef.m_attachment = ownedImageName;
  211. }
  212. else
  213. {
  214. // Output connection will be the parent's output
  215. outConnection.m_localSlot = "Output";
  216. outConnection.m_attachmentRef.m_pass = "Parent";
  217. outConnection.m_attachmentRef.m_attachment = "Output";
  218. }
  219. AZStd::string azshaderPath = shaderFilePath;
  220. AZ::StringFunc::Path::ReplaceExtension(azshaderPath, "azshader");
  221. Data::AssetId shaderAssetId;
  222. Data::AssetCatalogRequestBus::BroadcastResult(
  223. shaderAssetId, &Data::AssetCatalogRequestBus::Events::GetAssetIdByPath,
  224. azshaderPath.c_str(), azrtti_typeid<RPI::ShaderAsset>(), false);
  225. if (!shaderAssetId.IsValid())
  226. {
  227. AZ_Assert(false, "[DisplayMapperPass] Unable to obtain asset id for %s.", shaderFilePath);
  228. return nullptr;
  229. }
  230. AZStd::shared_ptr<RPI::FullscreenTrianglePassData> passData = AZStd::make_shared<RPI::FullscreenTrianglePassData>();
  231. passData->m_shaderAsset.m_filePath = shaderFilePath;
  232. passData->m_shaderAsset.m_assetId = shaderAssetId;
  233. passTemplate->m_passData = AZStd::move(passData);
  234. return passTemplate;
  235. }
  236. AZStd::shared_ptr<RPI::PassTemplate> CreateBakeAcesLutPassTemplateHelper(
  237. const Name& templateName, const Name& passClass, const char* shaderFilePath)
  238. {
  239. auto passTemplate = AZStd::make_shared<RPI::PassTemplate>();
  240. passTemplate->m_name = templateName;
  241. passTemplate->m_passClass = passClass;
  242. // Slots
  243. passTemplate->m_slots.resize(1);
  244. RPI::PassSlot& outSlot = passTemplate->m_slots[0];
  245. outSlot.m_name = "Output";
  246. outSlot.m_slotType = RPI::PassSlotType::Output;
  247. outSlot.m_scopeAttachmentUsage = RHI::ScopeAttachmentUsage::Shader;
  248. outSlot.m_loadStoreAction.m_loadAction = RHI::AttachmentLoadAction::Clear;
  249. Data::AssetId shaderAssetId;
  250. Data::AssetCatalogRequestBus::BroadcastResult(
  251. shaderAssetId, &Data::AssetCatalogRequestBus::Events::GetAssetIdByPath,
  252. shaderFilePath, azrtti_typeid<RPI::ShaderAsset>(), false);
  253. if (!shaderAssetId.IsValid())
  254. {
  255. AZ_Assert(false, "[DisplayMapperPass] Unable to obtain asset id for %s.", shaderFilePath);
  256. return nullptr;
  257. }
  258. AZStd::shared_ptr<RPI::ComputePassData> passData = AZStd::make_shared<RPI::ComputePassData>();
  259. passData->m_totalNumberOfThreadsX = 32;
  260. passData->m_totalNumberOfThreadsY = 32;
  261. passData->m_totalNumberOfThreadsZ = 32;
  262. passData->m_shaderReference.m_filePath = shaderFilePath;
  263. passData->m_shaderReference.m_assetId = shaderAssetId;
  264. passTemplate->m_passData = AZStd::move(passData);
  265. return passTemplate;
  266. }
  267. /**
  268. * Create a pass templates for HDR and LDR grading passes, and the output transform passes.
  269. */
  270. void DisplayMapperPass::BuildGradingLutTemplate()
  271. {
  272. // Pass template names
  273. const Name acesOutputTransformTemplateName = Name{ "AcesOutputTransformTemplate" };
  274. const Name acesOutputTransformLutTemplateName = Name{ "AcesOutputTransformLutTemplate" };
  275. const Name bakeAcesOutputTransformLutTemplateName = Name{ "BakeAcesOutputTransformLutTemplate" };
  276. const Name displayMapperPassthroughTemplateName = Name{ "DisplayMapperPassthroughTemplate" };
  277. const Name displayMapperSRGBTemplateName = Name{ "DisplayMapperSRGBTemplate" };
  278. const Name hdrGradingLutTemplateName = Name{ "HdrGradingLutTemplate" };
  279. const Name ldrGradingLutTemplateName = Name{ "LdrGradingLutTemplate" };
  280. const Name outputTransformTemplateName = Name{ "OutputTransformTemplate" };
  281. // Pass classes
  282. const Name acesOutputTransformPassClassName = Name{ "AcesOutputTransformPass" };
  283. const Name acesOutputTransformLutPassClassName = Name{ "AcesOutputTransformLutPass" };
  284. const Name bakeAcesOutputTransformLutPassClassName = Name{ "BakeAcesOutputTransformLutPass" };
  285. const Name displayMapperFullScreenPassClassName = Name{ "DisplayMapperFullScreenPass" };
  286. const Name applyShaperLookupTablePassClassName = Name{ "ApplyShaperLookupTablePass" };
  287. const Name outputTransformPassClassName = Name{ "OutputTransformPass" };
  288. // Names of owned image attachments that may be used
  289. const Name hdrGradingImageName = Name{ "HdrGradingImage" };
  290. const Name outputTransformImageName = Name{ "OutputTransformImage" };
  291. const char* acesOuputTransformShaderPath = "Shaders/PostProcessing/DisplayMapper.azshader";
  292. const char* acesOuputTransformLutShaderPath = "Shaders/PostProcessing/AcesOutputTransformLut.azshader";
  293. const char* bakeAcesOuputTransformLutShaderPath = "Shaders/PostProcessing/BakeAcesOutputTransformLutCS.azshader";
  294. const char* passthroughShaderPath = "Shaders/PostProcessing/FullscreenCopy.azshader";
  295. const char* sRGBShaderPath = "Shaders/PostProcessing/DisplayMapperSRGB.azshader";
  296. const char* applyShaperLookupTableShaderFilePath = "Shaders/PostProcessing/ApplyShaperLookupTable.azshader";
  297. const char* outputTransformShaderPath = m_outputTransformOverrideShader.m_assetId.IsValid()
  298. ? m_outputTransformOverrideShader.m_filePath.c_str()
  299. : "Shaders/PostProcessing/OutputTransform.azshader";
  300. // Output transform templates. If there is no LDR grading LUT pass, then the output transform pass is the final pass
  301. // and will render to the DisplayMapper's output attachment. Otherwise, it renders to its own attachment image.
  302. bool useSeparateLdrGradingLutPass = UsesLdrGradingLutPass();
  303. // ACES
  304. m_acesOutputTransformTemplate.reset();
  305. m_acesOutputTransformTemplate = CreatePassTemplateHelper(
  306. acesOutputTransformTemplateName,
  307. acesOutputTransformPassClassName,
  308. useSeparateLdrGradingLutPass,
  309. outputTransformImageName,
  310. acesOuputTransformShaderPath);
  311. // ACES LUT
  312. m_acesOutputTransformLutTemplate.reset();
  313. m_acesOutputTransformLutTemplate = CreatePassTemplateHelper(
  314. acesOutputTransformLutTemplateName,
  315. acesOutputTransformLutPassClassName,
  316. useSeparateLdrGradingLutPass,
  317. outputTransformImageName,
  318. acesOuputTransformLutShaderPath);
  319. // Bake ACES LUT
  320. m_bakeAcesOutputTransformLutTemplate.reset();
  321. m_bakeAcesOutputTransformLutTemplate = CreateBakeAcesLutPassTemplateHelper(
  322. bakeAcesOutputTransformLutTemplateName,
  323. bakeAcesOutputTransformLutPassClassName,
  324. bakeAcesOuputTransformLutShaderPath);
  325. // Passthrough
  326. m_passthroughTemplate.reset();
  327. m_passthroughTemplate = CreatePassTemplateHelper(
  328. displayMapperPassthroughTemplateName,
  329. displayMapperFullScreenPassClassName,
  330. useSeparateLdrGradingLutPass,
  331. outputTransformImageName,
  332. passthroughShaderPath);
  333. // sRGB
  334. m_sRGBTemplate.reset();
  335. m_sRGBTemplate = CreatePassTemplateHelper(
  336. displayMapperSRGBTemplateName,
  337. displayMapperFullScreenPassClassName,
  338. useSeparateLdrGradingLutPass,
  339. outputTransformImageName,
  340. sRGBShaderPath);
  341. // Output Transform
  342. m_outputTransformTemplate.reset();
  343. m_outputTransformTemplate = CreatePassTemplateHelper(
  344. outputTransformTemplateName,
  345. outputTransformPassClassName,
  346. useSeparateLdrGradingLutPass,
  347. outputTransformImageName,
  348. outputTransformShaderPath);
  349. // LDR grading LUT pass, if enabled, is the final pass and so it will render into the DisplayMapper's output attachment.
  350. m_ldrGradingLookupTableTemplate.reset();
  351. m_ldrGradingLookupTableTemplate = CreatePassTemplateHelper(
  352. ldrGradingLutTemplateName, applyShaperLookupTablePassClassName,
  353. false, Name{ "" }, applyShaperLookupTableShaderFilePath);
  354. }
  355. template<typename PassType>
  356. RPI::Ptr<PassType> CreatePassHelper(RPI::PassSystemInterface* passSystem, AZStd::shared_ptr<RPI::PassTemplate> passTemplate, const Name& passName)
  357. {
  358. RPI::Ptr<RPI::Pass> pass = passSystem->CreatePassFromTemplate(passTemplate, passName);
  359. if (!pass)
  360. {
  361. AZ_Assert(false, "[DisplayMapperPass] Unable to create %s.", passName.GetCStr());
  362. return nullptr;
  363. }
  364. RPI::Ptr<PassType> returnPass = static_cast<PassType*>(pass.get());
  365. return AZStd::move(returnPass);
  366. }
  367. void DisplayMapperPass::CreateGradingAndAcesPasses()
  368. {
  369. RPI::PassSystemInterface* passSystem = RPI::PassSystemInterface::Get();
  370. if (m_displayMapperConfigurationDescriptor.m_operationType == DisplayMapperOperationType::Aces)
  371. {
  372. // ACES path
  373. m_acesOutputTransformPass = CreatePassHelper<AcesOutputTransformPass>(passSystem, m_acesOutputTransformTemplate, m_acesOutputTransformPassName);
  374. }
  375. else if (m_displayMapperConfigurationDescriptor.m_operationType == DisplayMapperOperationType::AcesLut)
  376. {
  377. // Aces LUT path
  378. m_bakeAcesOutputTransformLutPass = CreatePassHelper<BakeAcesOutputTransformLutPass>(passSystem, m_bakeAcesOutputTransformLutTemplate, m_bakeAcesOutputTransformLutPassName);
  379. m_acesOutputTransformLutPass = CreatePassHelper<AcesOutputTransformLutPass>(passSystem, m_acesOutputTransformLutTemplate, m_acesOutputTransformLutPassName);
  380. }
  381. else if (m_displayMapperConfigurationDescriptor.m_operationType == DisplayMapperOperationType::Passthrough)
  382. {
  383. // Passthrough
  384. // [GFX TODO][ATOM-4189] Optimize the passthrough function in the DisplayMapper
  385. // Only need to create this if LDR grading LUT pass is not used.
  386. if (!UsesLdrGradingLutPass())
  387. {
  388. m_displayMapperPassthroughPass = CreatePassHelper<DisplayMapperFullScreenPass>(passSystem, m_passthroughTemplate, m_displayMapperPassthroughPassName);
  389. }
  390. }
  391. else if (m_displayMapperConfigurationDescriptor.m_operationType == DisplayMapperOperationType::GammaSRGB)
  392. {
  393. m_displayMapperSRGBPass = CreatePassHelper<DisplayMapperFullScreenPass>(passSystem, m_sRGBTemplate, m_displayMapperSRGBPassName);
  394. }
  395. else if (UsesOutputTransformPass())
  396. {
  397. m_outputTransformPass = CreatePassHelper<OutputTransformPass>(passSystem, m_outputTransformTemplate, m_outputTransformPassName);
  398. ToneMapperType type = ToneMapperType::None;
  399. switch (m_displayMapperConfigurationDescriptor.m_operationType)
  400. {
  401. case DisplayMapperOperationType::Reinhard:
  402. type = ToneMapperType::Reinhard;
  403. break;
  404. case DisplayMapperOperationType::AcesFitted:
  405. type = ToneMapperType::AcesFitted;
  406. break;
  407. case DisplayMapperOperationType::AcesFilmic:
  408. type = ToneMapperType::AcesFilmic;
  409. break;
  410. case DisplayMapperOperationType::Filmic:
  411. type = ToneMapperType::Filmic;
  412. break;
  413. default:
  414. AZ_Assert(false, "Invalid tonemapper type %d", m_displayMapperConfigurationDescriptor.m_operationType);
  415. break;
  416. }
  417. m_outputTransformPass->SetToneMapperType(type);
  418. if (m_displayMapperConfigurationDescriptor.m_ldrGradingLutEnabled &&
  419. m_mergeLdrGradingLut &&
  420. m_displayMapperConfigurationDescriptor.m_ldrColorGradingLut.GetId().IsValid())
  421. {
  422. m_outputTransformPass->SetLutAssetId(m_displayMapperConfigurationDescriptor.m_ldrColorGradingLut.GetId());
  423. }
  424. }
  425. if (UsesLdrGradingLutPass())
  426. {
  427. // ID should be valid, maybe no need to check again here.
  428. if (m_displayMapperConfigurationDescriptor.m_ldrColorGradingLut.GetId().IsValid())
  429. {
  430. // For LDR tonemapping, no need to set the shaper function as the default identity shaper is assumed.
  431. m_ldrGradingLookupTablePass = CreatePassHelper<ApplyShaperLookupTablePass>(passSystem, m_ldrGradingLookupTableTemplate, m_ldrGradingLookupTablePassName);
  432. m_ldrGradingLookupTablePass->SetLutAssetId(m_displayMapperConfigurationDescriptor.m_ldrColorGradingLut.GetId());
  433. }
  434. }
  435. // Add the children as necessary
  436. if (m_acesOutputTransformPass)
  437. {
  438. AddChild(m_acesOutputTransformPass);
  439. }
  440. if (m_bakeAcesOutputTransformLutPass)
  441. {
  442. AddChild(m_bakeAcesOutputTransformLutPass);
  443. }
  444. if (m_acesOutputTransformLutPass)
  445. {
  446. AddChild(m_acesOutputTransformLutPass);
  447. }
  448. if (m_displayMapperPassthroughPass)
  449. {
  450. AddChild(m_displayMapperPassthroughPass);
  451. }
  452. if (m_displayMapperSRGBPass)
  453. {
  454. AddChild(m_displayMapperSRGBPass);
  455. }
  456. if (m_outputTransformPass)
  457. {
  458. AddChild(m_outputTransformPass);
  459. }
  460. if (m_ldrGradingLookupTablePass)
  461. {
  462. AddChild(m_ldrGradingLookupTablePass);
  463. }
  464. }
  465. void DisplayMapperPass::UpdateDisplayMapperConfiguration()
  466. {
  467. // If no configuration is found, then use the default value that was set for the pass.
  468. DisplayMapperConfigurationDescriptor desc = m_defaultDisplayMapperConfigurationDescriptor;
  469. AZ::RPI::Scene* scene = GetScene();
  470. if (scene)
  471. {
  472. AcesDisplayMapperFeatureProcessor* fp = scene->GetFeatureProcessor<AcesDisplayMapperFeatureProcessor>();
  473. if (fp)
  474. {
  475. auto fpDesc = fp->GetDisplayMapperConfiguration();
  476. if (fpDesc)
  477. {
  478. desc = *fpDesc;
  479. // Check to ensure that a valid LUT has been set
  480. if (desc.m_ldrGradingLutEnabled)
  481. {
  482. if (!desc.m_ldrColorGradingLut.GetId().IsValid())
  483. {
  484. desc.m_ldrGradingLutEnabled = false;
  485. }
  486. }
  487. }
  488. }
  489. }
  490. if (desc.m_operationType != m_displayMapperConfigurationDescriptor.m_operationType ||
  491. desc.m_ldrGradingLutEnabled != m_displayMapperConfigurationDescriptor.m_ldrGradingLutEnabled ||
  492. desc.m_ldrColorGradingLut != m_displayMapperConfigurationDescriptor.m_ldrColorGradingLut ||
  493. desc.m_acesParameterOverrides.m_overrideDefaults !=
  494. m_displayMapperConfigurationDescriptor.m_acesParameterOverrides.m_overrideDefaults)
  495. {
  496. m_flags.m_createChildren = true;
  497. QueueForBuildAndInitialization();
  498. }
  499. m_displayMapperConfigurationDescriptor = desc;
  500. }
  501. void DisplayMapperPass::ClearChildren()
  502. {
  503. RemoveChildren();
  504. m_acesOutputTransformPass = nullptr;
  505. m_bakeAcesOutputTransformLutPass = nullptr;
  506. m_acesOutputTransformLutPass = nullptr;
  507. m_displayMapperPassthroughPass = nullptr;
  508. m_displayMapperSRGBPass = nullptr;
  509. m_ldrGradingLookupTablePass = nullptr;
  510. m_outputTransformPass = nullptr;
  511. }
  512. bool DisplayMapperPass::UsesLdrGradingLutPass() const
  513. {
  514. // Merging the ldr color grading is only supported for the OutputTransform pass at the moment.
  515. return m_displayMapperConfigurationDescriptor.m_ldrGradingLutEnabled && !(m_mergeLdrGradingLut && UsesOutputTransformPass());
  516. }
  517. bool DisplayMapperPass::UsesOutputTransformPass() const
  518. {
  519. return m_displayMapperConfigurationDescriptor.m_operationType == DisplayMapperOperationType::Reinhard ||
  520. m_displayMapperConfigurationDescriptor.m_operationType == DisplayMapperOperationType::AcesFitted ||
  521. m_displayMapperConfigurationDescriptor.m_operationType == DisplayMapperOperationType::Filmic ||
  522. m_displayMapperConfigurationDescriptor.m_operationType == DisplayMapperOperationType::AcesFilmic;
  523. }
  524. } // namespace Render
  525. } // namespace AZ