PreviewRenderer.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  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/Utils/FrameCaptureBus.h>
  9. #include <Atom/RPI.Public/Pass/Specific/RenderToTexturePass.h>
  10. #include <Atom/RPI.Public/RPISystemInterface.h>
  11. #include <Atom/RPI.Public/RenderPipeline.h>
  12. #include <Atom/RPI.Public/Scene.h>
  13. #include <Atom/RPI.Public/Shader/ShaderResourceGroup.h>
  14. #include <Atom/RPI.Public/View.h>
  15. #include <Atom/RPI.Reflect/System/RenderPipelineDescriptor.h>
  16. #include <Atom/RPI.Reflect/System/SceneDescriptor.h>
  17. #include <AzCore/Interface/Interface.h>
  18. #include <AzCore/Math/MatrixUtils.h>
  19. #include <AzCore/Math/Transform.h>
  20. #include <AzFramework/Scene/Scene.h>
  21. #include <AzFramework/Scene/SceneSystemInterface.h>
  22. #include <PreviewRenderer/PreviewRenderer.h>
  23. #include <PreviewRenderer/PreviewRendererCaptureState.h>
  24. #include <PreviewRenderer/PreviewRendererIdleState.h>
  25. #include <PreviewRenderer/PreviewRendererLoadState.h>
  26. #include <QImage>
  27. #include <QPixmap>
  28. namespace AtomToolsFramework
  29. {
  30. PreviewRenderer::PreviewRenderer(const AZStd::string& sceneName, const AZStd::string& pipelineName)
  31. {
  32. PreviewerFeatureProcessorProviderBus::Handler::BusConnect();
  33. AZ::SystemTickBus::Handler::BusConnect();
  34. m_entityContext = AZStd::make_unique<AzFramework::EntityContext>();
  35. m_entityContext->InitContext();
  36. // Create and register a scene with all required feature processors
  37. AZStd::vector<AZStd::string> featureProcessors;
  38. PreviewerFeatureProcessorProviderBus::Broadcast(
  39. &PreviewerFeatureProcessorProviderBus::Handler::GetRequiredFeatureProcessors, featureProcessors);
  40. AZ::RPI::SceneDescriptor sceneDesc;
  41. sceneDesc.m_nameId = AZ::Name("PreviewRenderer");
  42. sceneDesc.m_featureProcessorNames.assign(featureProcessors.begin(), featureProcessors.end());
  43. m_scene = AZ::RPI::Scene::CreateScene(sceneDesc);
  44. // Bind m_frameworkScene to the entity context's AzFramework::Scene
  45. auto sceneSystem = AzFramework::SceneSystemInterface::Get();
  46. AZ_Assert(sceneSystem, "Failed to get scene system implementation.");
  47. AZ::Outcome<AZStd::shared_ptr<AzFramework::Scene>, AZStd::string> createSceneOutcome = sceneSystem->CreateScene(sceneName);
  48. AZ_Assert(createSceneOutcome, createSceneOutcome.GetError().c_str());
  49. m_frameworkScene = createSceneOutcome.TakeValue();
  50. m_frameworkScene->SetSubsystem(m_scene);
  51. m_frameworkScene->SetSubsystem(m_entityContext.get());
  52. // Create a render pipeline from the specified asset for the window context and add the pipeline to the scene
  53. AZ::RPI::RenderPipelineDescriptor pipelineDesc;
  54. pipelineDesc.m_mainViewTagName = "MainCamera";
  55. pipelineDesc.m_name = pipelineName;
  56. pipelineDesc.m_rootPassTemplate = "ToolsPipelineRenderToTexture";
  57. pipelineDesc.m_renderSettings.m_multisampleState = AZ::RPI::RPISystemInterface::Get()->GetApplicationMultisampleState();
  58. m_renderPipeline = AZ::RPI::RenderPipeline::CreateRenderPipeline(pipelineDesc);
  59. m_scene->AddRenderPipeline(m_renderPipeline);
  60. m_scene->Activate();
  61. AZ::RPI::RPISystemInterface::Get()->RegisterScene(m_scene);
  62. m_passHierarchy.push_back(pipelineName);
  63. m_passHierarchy.push_back("CopyToSwapChain");
  64. // Connect camera to pipeline's default view after camera entity activated
  65. AZ::Matrix4x4 viewToClipMatrix;
  66. AZ::MakePerspectiveFovMatrixRH(viewToClipMatrix, FieldOfView, AspectRatio, NearDist, FarDist, true);
  67. m_view = AZ::RPI::View::CreateView(AZ::Name("MainCamera"), AZ::RPI::View::UsageCamera);
  68. m_view->SetViewToClipMatrix(viewToClipMatrix);
  69. m_renderPipeline->SetDefaultView(m_view);
  70. m_state.reset(new PreviewRendererIdleState(this));
  71. AZ::Interface<PreviewRendererInterface>::Register(this);
  72. }
  73. PreviewRenderer::~PreviewRenderer()
  74. {
  75. AZ::SystemTickBus::Handler::BusDisconnect();
  76. PreviewerFeatureProcessorProviderBus::Handler::BusDisconnect();
  77. m_state.reset();
  78. m_currentCaptureRequest = {};
  79. m_captureRequestQueue = {};
  80. m_scene->Deactivate();
  81. m_scene->RemoveRenderPipeline(m_renderPipeline->GetId());
  82. AZ::RPI::RPISystemInterface::Get()->UnregisterScene(m_scene);
  83. m_frameworkScene->UnsetSubsystem(m_scene);
  84. m_frameworkScene->UnsetSubsystem(m_entityContext.get());
  85. AZ::Interface<PreviewRendererInterface>::Unregister(this);
  86. }
  87. void PreviewRenderer::AddCaptureRequest(const PreviewRendererCaptureRequest& captureRequest)
  88. {
  89. m_captureRequestQueue.push(captureRequest);
  90. }
  91. AZ::RPI::ScenePtr PreviewRenderer::GetScene() const
  92. {
  93. return m_scene;
  94. }
  95. AZ::RPI::ViewPtr PreviewRenderer::GetView() const
  96. {
  97. return m_view;
  98. }
  99. AZ::Uuid PreviewRenderer::GetEntityContextId() const
  100. {
  101. return m_entityContext->GetContextId();
  102. }
  103. void PreviewRenderer::ProcessCaptureRequests()
  104. {
  105. if (!m_captureRequestQueue.empty())
  106. {
  107. // pop the next request to be rendered from the queue
  108. m_currentCaptureRequest = m_captureRequestQueue.front();
  109. m_captureRequestQueue.pop();
  110. bool canCapture = false;
  111. AZ::Render::FrameCaptureRequestBus::BroadcastResult(canCapture, &AZ::Render::FrameCaptureRequestBus::Events::CanCapture);
  112. // if we're not on a device that can capture, immediately trigger the "failed" state.
  113. if (!canCapture)
  114. {
  115. CancelCaptureRequest();
  116. }
  117. else
  118. {
  119. m_state.reset();
  120. m_state.reset(new PreviewRendererLoadState(this));
  121. }
  122. }
  123. }
  124. void PreviewRenderer::CancelCaptureRequest()
  125. {
  126. if (m_currentCaptureRequest.m_captureFailedCallback)
  127. {
  128. m_currentCaptureRequest.m_captureFailedCallback();
  129. }
  130. EndCapture();
  131. m_state.reset();
  132. m_state.reset(new PreviewRendererIdleState(this));
  133. }
  134. void PreviewRenderer::CompleteCaptureRequest()
  135. {
  136. EndCapture();
  137. m_state.reset();
  138. m_state.reset(new PreviewRendererIdleState(this));
  139. }
  140. void PreviewRenderer::LoadContent()
  141. {
  142. m_currentCaptureRequest.m_content->Load();
  143. }
  144. void PreviewRenderer::UpdateLoadContent()
  145. {
  146. if (m_currentCaptureRequest.m_content->IsReady())
  147. {
  148. m_state.reset();
  149. m_state.reset(new PreviewRendererCaptureState(this));
  150. return;
  151. }
  152. if (m_currentCaptureRequest.m_content->IsError())
  153. {
  154. CancelLoadContent();
  155. return;
  156. }
  157. }
  158. void PreviewRenderer::CancelLoadContent()
  159. {
  160. m_currentCaptureRequest.m_content->ReportErrors();
  161. CancelCaptureRequest();
  162. }
  163. void PreviewRenderer::PoseContent()
  164. {
  165. m_currentCaptureRequest.m_content->Update();
  166. }
  167. AZ::Render::FrameCaptureId PreviewRenderer::StartCapture()
  168. {
  169. auto captureCompleteCallback = m_currentCaptureRequest.m_captureCompleteCallback;
  170. auto captureFailedCallback = m_currentCaptureRequest.m_captureFailedCallback;
  171. auto captureCallback = [captureCompleteCallback, captureFailedCallback](const AZ::RPI::AttachmentReadback::ReadbackResult& result)
  172. {
  173. if (result.m_dataBuffer)
  174. {
  175. if (captureCompleteCallback)
  176. {
  177. captureCompleteCallback(QPixmap::fromImage(QImage(
  178. result.m_dataBuffer.get()->data(),
  179. result.m_imageDescriptor.m_size.m_width,
  180. result.m_imageDescriptor.m_size.m_height,
  181. QImage::Format_RGBA8888)));
  182. }
  183. }
  184. else
  185. {
  186. if (captureFailedCallback)
  187. {
  188. captureFailedCallback();
  189. }
  190. }
  191. };
  192. if (auto renderToTexturePass = azrtti_cast<AZ::RPI::RenderToTexturePass*>(m_renderPipeline->GetRootPass().get()))
  193. {
  194. renderToTexturePass->ResizeOutput(m_currentCaptureRequest.m_size, m_currentCaptureRequest.m_size);
  195. }
  196. m_renderPipeline->AddToRenderTickOnce();
  197. AZ::Render::FrameCaptureOutcome captureOutcome;
  198. AZ::Render::FrameCaptureRequestBus::BroadcastResult(
  199. captureOutcome,
  200. &AZ::Render::FrameCaptureRequestBus::Events::CapturePassAttachmentWithCallback,
  201. captureCallback,
  202. m_passHierarchy,
  203. AZStd::string("Output"), AZ::RPI::PassAttachmentReadbackOption::Output);
  204. AZ_Error("PreviewRenderer", captureOutcome.IsSuccess(),
  205. "Frame capture initialization failed. %s", captureOutcome.GetError().m_errorMessage.c_str());
  206. AZ::Render::FrameCaptureId frameCaptureId = captureOutcome.IsSuccess() ?
  207. captureOutcome.GetValue() : AZ::Render::InvalidFrameCaptureId;
  208. return frameCaptureId;
  209. }
  210. void PreviewRenderer::EndCapture()
  211. {
  212. m_currentCaptureRequest = {};
  213. m_renderPipeline->RemoveFromRenderTick();
  214. }
  215. void PreviewRenderer::OnSystemTick()
  216. {
  217. if (m_state)
  218. {
  219. m_state->Update();
  220. }
  221. }
  222. void PreviewRenderer::GetRequiredFeatureProcessors(AZStd::vector<AZStd::string>& featureProcessors) const
  223. {
  224. featureProcessors.insert(featureProcessors.end(), {
  225. "AZ::Render::TransformServiceFeatureProcessor",
  226. "AZ::Render::MeshFeatureProcessor",
  227. "AZ::Render::SimplePointLightFeatureProcessor",
  228. "AZ::Render::SimpleSpotLightFeatureProcessor",
  229. "AZ::Render::PointLightFeatureProcessor",
  230. // There is currently a bug where having multiple DirectionalLightFeatureProcessors active can result in shadow
  231. // flickering [ATOM-13568]
  232. // as well as continually rebuilding MeshDrawPackets [ATOM-13633]. Lets just disable the directional light FP for now.
  233. // Possibly re-enable with [GFX TODO][ATOM-13639]
  234. // "AZ::Render::DirectionalLightFeatureProcessor",
  235. "AZ::Render::DiskLightFeatureProcessor",
  236. "AZ::Render::CapsuleLightFeatureProcessor",
  237. "AZ::Render::QuadLightFeatureProcessor",
  238. "AZ::Render::DecalTextureArrayFeatureProcessor",
  239. "AZ::Render::ImageBasedLightFeatureProcessor",
  240. "AZ::Render::PostProcessFeatureProcessor",
  241. "AZ::Render::SkyBoxFeatureProcessor" });
  242. }
  243. } // namespace AtomToolsFramework