PreviewRenderer.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  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. uint32_t numRegisteredScenes = AZ::RPI::RPISystemInterface::Get()->GetNumScenes();
  58. //If there are existing registered scenes use the msaa settings set by them
  59. //otherwise broadcast default settings.
  60. if (numRegisteredScenes > 0)
  61. {
  62. pipelineDesc.m_renderSettings.m_multisampleState = AZ::RPI::RPISystemInterface::Get()->GetApplicationMultisampleState();
  63. }
  64. else
  65. {
  66. AZ::RPI::RPISystemInterface::Get()->SetApplicationMultisampleState(pipelineDesc.m_renderSettings.m_multisampleState);
  67. }
  68. m_renderPipeline = AZ::RPI::RenderPipeline::CreateRenderPipeline(pipelineDesc);
  69. m_scene->AddRenderPipeline(m_renderPipeline);
  70. m_scene->Activate();
  71. AZ::RPI::RPISystemInterface::Get()->RegisterScene(m_scene);
  72. m_passHierarchy.push_back(pipelineName);
  73. m_passHierarchy.push_back("CopyToSwapChain");
  74. // Connect camera to pipeline's default view after camera entity activated
  75. AZ::Matrix4x4 viewToClipMatrix;
  76. AZ::MakePerspectiveFovMatrixRH(viewToClipMatrix, FieldOfView, AspectRatio, NearDist, FarDist, true);
  77. m_view = AZ::RPI::View::CreateView(AZ::Name("MainCamera"), AZ::RPI::View::UsageCamera);
  78. m_view->SetViewToClipMatrix(viewToClipMatrix);
  79. m_renderPipeline->SetDefaultView(m_view);
  80. m_state.reset(new PreviewRendererIdleState(this));
  81. AZ::Interface<PreviewRendererInterface>::Register(this);
  82. }
  83. PreviewRenderer::~PreviewRenderer()
  84. {
  85. AZ::SystemTickBus::Handler::BusDisconnect();
  86. PreviewerFeatureProcessorProviderBus::Handler::BusDisconnect();
  87. m_state.reset();
  88. m_currentCaptureRequest = {};
  89. m_captureRequestQueue = {};
  90. m_scene->Deactivate();
  91. m_scene->RemoveRenderPipeline(m_renderPipeline->GetId());
  92. AZ::RPI::RPISystemInterface::Get()->UnregisterScene(m_scene);
  93. m_frameworkScene->UnsetSubsystem(m_scene);
  94. m_frameworkScene->UnsetSubsystem(m_entityContext.get());
  95. AZ::Interface<PreviewRendererInterface>::Unregister(this);
  96. }
  97. void PreviewRenderer::AddCaptureRequest(const PreviewRendererCaptureRequest& captureRequest)
  98. {
  99. m_captureRequestQueue.push(captureRequest);
  100. }
  101. AZ::RPI::ScenePtr PreviewRenderer::GetScene() const
  102. {
  103. return m_scene;
  104. }
  105. AZ::RPI::ViewPtr PreviewRenderer::GetView() const
  106. {
  107. return m_view;
  108. }
  109. AZ::Uuid PreviewRenderer::GetEntityContextId() const
  110. {
  111. return m_entityContext->GetContextId();
  112. }
  113. void PreviewRenderer::ProcessCaptureRequests()
  114. {
  115. if (!m_captureRequestQueue.empty())
  116. {
  117. // pop the next request to be rendered from the queue
  118. m_currentCaptureRequest = m_captureRequestQueue.front();
  119. m_captureRequestQueue.pop();
  120. bool canCapture = false;
  121. AZ::Render::FrameCaptureRequestBus::BroadcastResult(canCapture, &AZ::Render::FrameCaptureRequestBus::Events::CanCapture);
  122. // if we're not on a device that can capture, immediately trigger the "failed" state.
  123. if (!canCapture)
  124. {
  125. CancelCaptureRequest();
  126. }
  127. else
  128. {
  129. m_state.reset();
  130. m_state.reset(new PreviewRendererLoadState(this));
  131. }
  132. }
  133. }
  134. void PreviewRenderer::CancelCaptureRequest()
  135. {
  136. if (m_currentCaptureRequest.m_captureFailedCallback)
  137. {
  138. m_currentCaptureRequest.m_captureFailedCallback();
  139. }
  140. EndCapture();
  141. m_state.reset();
  142. m_state.reset(new PreviewRendererIdleState(this));
  143. }
  144. void PreviewRenderer::CompleteCaptureRequest()
  145. {
  146. EndCapture();
  147. m_state.reset();
  148. m_state.reset(new PreviewRendererIdleState(this));
  149. }
  150. void PreviewRenderer::LoadContent()
  151. {
  152. m_currentCaptureRequest.m_content->Load();
  153. }
  154. void PreviewRenderer::UpdateLoadContent()
  155. {
  156. if (m_currentCaptureRequest.m_content->IsReady())
  157. {
  158. m_state.reset();
  159. m_state.reset(new PreviewRendererCaptureState(this));
  160. return;
  161. }
  162. if (m_currentCaptureRequest.m_content->IsError())
  163. {
  164. CancelLoadContent();
  165. return;
  166. }
  167. }
  168. void PreviewRenderer::CancelLoadContent()
  169. {
  170. m_currentCaptureRequest.m_content->ReportErrors();
  171. CancelCaptureRequest();
  172. }
  173. void PreviewRenderer::PoseContent()
  174. {
  175. m_currentCaptureRequest.m_content->Update();
  176. }
  177. AZ::Render::FrameCaptureId PreviewRenderer::StartCapture()
  178. {
  179. auto captureCompleteCallback = m_currentCaptureRequest.m_captureCompleteCallback;
  180. auto captureFailedCallback = m_currentCaptureRequest.m_captureFailedCallback;
  181. auto captureCallback = [captureCompleteCallback, captureFailedCallback](const AZ::RPI::AttachmentReadback::ReadbackResult& result)
  182. {
  183. if (result.m_dataBuffer)
  184. {
  185. if (captureCompleteCallback)
  186. {
  187. captureCompleteCallback(QPixmap::fromImage(QImage(
  188. result.m_dataBuffer.get()->data(),
  189. result.m_imageDescriptor.m_size.m_width,
  190. result.m_imageDescriptor.m_size.m_height,
  191. QImage::Format_RGBA8888)));
  192. }
  193. }
  194. else
  195. {
  196. if (captureFailedCallback)
  197. {
  198. captureFailedCallback();
  199. }
  200. }
  201. };
  202. if (auto renderToTexturePass = azrtti_cast<AZ::RPI::RenderToTexturePass*>(m_renderPipeline->GetRootPass().get()))
  203. {
  204. renderToTexturePass->ResizeOutput(m_currentCaptureRequest.m_size, m_currentCaptureRequest.m_size);
  205. }
  206. m_renderPipeline->AddToRenderTickOnce();
  207. AZ::Render::FrameCaptureOutcome captureOutcome;
  208. AZ::Render::FrameCaptureRequestBus::BroadcastResult(
  209. captureOutcome,
  210. &AZ::Render::FrameCaptureRequestBus::Events::CapturePassAttachmentWithCallback,
  211. captureCallback,
  212. m_passHierarchy,
  213. AZStd::string("Output"), AZ::RPI::PassAttachmentReadbackOption::Output);
  214. AZ_Error("PreviewRenderer", captureOutcome.IsSuccess(),
  215. "Frame capture initialization failed. %s", captureOutcome.GetError().m_errorMessage.c_str());
  216. AZ::Render::FrameCaptureId frameCaptureId = captureOutcome.IsSuccess() ?
  217. captureOutcome.GetValue() : AZ::Render::InvalidFrameCaptureId;
  218. return frameCaptureId;
  219. }
  220. void PreviewRenderer::EndCapture()
  221. {
  222. m_currentCaptureRequest = {};
  223. m_renderPipeline->RemoveFromRenderTick();
  224. }
  225. void PreviewRenderer::OnSystemTick()
  226. {
  227. if (m_state)
  228. {
  229. m_state->Update();
  230. }
  231. }
  232. void PreviewRenderer::GetRequiredFeatureProcessors(AZStd::vector<AZStd::string>& featureProcessors) const
  233. {
  234. featureProcessors.insert(featureProcessors.end(), {
  235. "AZ::Render::TransformServiceFeatureProcessor",
  236. "AZ::Render::MeshFeatureProcessor",
  237. "AZ::Render::SimplePointLightFeatureProcessor",
  238. "AZ::Render::SimpleSpotLightFeatureProcessor",
  239. "AZ::Render::PointLightFeatureProcessor",
  240. // There is currently a bug where having multiple DirectionalLightFeatureProcessors active can result in shadow
  241. // flickering [ATOM-13568]
  242. // as well as continually rebuilding MeshDrawPackets [ATOM-13633]. Lets just disable the directional light FP for now.
  243. // Possibly re-enable with [GFX TODO][ATOM-13639]
  244. // "AZ::Render::DirectionalLightFeatureProcessor",
  245. "AZ::Render::DiskLightFeatureProcessor",
  246. "AZ::Render::CapsuleLightFeatureProcessor",
  247. "AZ::Render::QuadLightFeatureProcessor",
  248. "AZ::Render::DecalTextureArrayFeatureProcessor",
  249. "AZ::Render::ImageBasedLightFeatureProcessor",
  250. "AZ::Render::PostProcessFeatureProcessor",
  251. "AZ::Render::SkyBoxFeatureProcessor" });
  252. }
  253. } // namespace AtomToolsFramework