FrameCaptureSystemComponent.h 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  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. #pragma once
  9. #include <AzCore/Component/Component.h>
  10. #include <AzCore/Component/TickBus.h>
  11. #include <AzCore/std/containers/deque.h>
  12. #include <AzCore/std/smart_ptr/shared_ptr.h>
  13. #include <AzCore/std/parallel/shared_mutex.h>
  14. #include <AzCore/std/parallel/atomic.h>
  15. #include <Atom/Feature/Utils/FrameCaptureBus.h>
  16. #include <Atom/Feature/Utils/FrameCaptureTestBus.h>
  17. #include <Atom/RPI.Public/Pass/AttachmentReadback.h>
  18. namespace AZ
  19. {
  20. namespace Render
  21. {
  22. //! System component to handle FrameCaptureRequestBus.
  23. class FrameCaptureSystemComponent final
  24. : public AZ::Component
  25. , public FrameCaptureRequestBus::Handler
  26. , public FrameCaptureTestRequestBus::Handler
  27. , public AZ::SystemTickBus::Handler
  28. {
  29. public:
  30. AZ_COMPONENT(FrameCaptureSystemComponent, "{53931220-19E7-4DE4-AF29-C4BB16E251D1}");
  31. static void Reflect(AZ::ReflectContext* context);
  32. void Activate() override;
  33. void Deactivate() override;
  34. // FrameCaptureRequestBus overrides ...
  35. bool CanCapture() const override;
  36. FrameCaptureOutcome CaptureScreenshot(const AZStd::string& imagePath) override;
  37. FrameCaptureOutcome CaptureScreenshotForWindow(const AZStd::string& imagePath, AzFramework::NativeWindowHandle windowHandle) override;
  38. FrameCaptureOutcome CaptureScreenshotWithPreview(const AZStd::string& imagePath) override;
  39. FrameCaptureOutcome CapturePassAttachment(
  40. const AZStd::string& imagePath,
  41. const AZStd::vector<AZStd::string>& passHierarchy,
  42. const AZStd::string& slotName,
  43. RPI::PassAttachmentReadbackOption option) override;
  44. FrameCaptureOutcome CapturePassAttachmentWithCallback(
  45. RPI::AttachmentReadback::CallbackFunction callback,
  46. const AZStd::vector<AZStd::string>& passHierarchy,
  47. const AZStd::string& slotName,
  48. RPI::PassAttachmentReadbackOption option) override;
  49. // FrameCaptureTestRequestBus overrides ...
  50. void SetScreenshotFolder(const AZStd::string& screenshotFolder) override;
  51. void SetTestEnvPath(const AZStd::string& envPath) override;
  52. void SetOfficialBaselineImageFolder(const AZStd::string& baselineFolder) override;
  53. void SetLocalBaselineImageFolder(const AZStd::string& baselineFolder) override;
  54. FrameCapturePathOutcome BuildScreenshotFilePath(
  55. const AZStd::string& imageName, bool useEnvPath) override;
  56. FrameCapturePathOutcome BuildOfficialBaselineFilePath(
  57. const AZStd::string& imageName, bool useEnvPath) override;
  58. FrameCapturePathOutcome BuildLocalBaselineFilePath(
  59. const AZStd::string& imageName, bool useEnvPath) override;
  60. FrameCaptureComparisonOutcome CompareScreenshots(
  61. const AZStd::string& filePathA,
  62. const AZStd::string& filePathB,
  63. float minDiffFilter) override;
  64. private:
  65. // Wrap the state necessary for 1 capture
  66. struct CaptureState
  67. {
  68. CaptureState(uint32_t captureId);
  69. CaptureState(CaptureState&& rhs);
  70. void Reset();
  71. AZStd::shared_ptr<AZ::RPI::AttachmentReadback> m_readback;
  72. AZStd::string m_outputFilePath;
  73. AZStd::atomic<FrameCaptureResult> m_result = FrameCaptureResult::None; // use atomic as this is written and read on different threads.
  74. AZStd::string m_latestCaptureInfo;
  75. };
  76. // Handle to wrap an index into the allCaptures CaptureState list
  77. // Provides utility functions to check it's safe to use the CaptureState Ptr (vector isn't being resized)
  78. class CaptureHandle
  79. {
  80. public:
  81. CaptureHandle(FrameCaptureSystemComponent* frameCaptureSystemComponent, uint32_t captureStateIndex);
  82. CaptureHandle() = delete;
  83. static CaptureHandle Null();
  84. // match AZStd::mutex function names so scoped_lock works
  85. void lock();
  86. void unlock();
  87. CaptureState* GetCaptureState();
  88. uint32_t GetCaptureStateIndex() {return m_captureStateIndex;}
  89. bool IsValid() {return m_captureStateIndex != InvalidCaptureHandle;};
  90. bool IsNull() {return m_captureStateIndex == InvalidCaptureHandle;};
  91. private:
  92. static constexpr uint32_t InvalidCaptureHandle = InvalidFrameCaptureId;
  93. FrameCaptureSystemComponent* const m_frameCaptureSystemComponent;
  94. const uint32_t m_captureStateIndex = InvalidCaptureHandle;
  95. };
  96. friend CaptureHandle;
  97. AZ::Outcome<CaptureHandle, FrameCaptureError> ScreenshotPreparation(
  98. const AZStd::string& imagePath,
  99. AZ::RPI::AttachmentReadback::CallbackFunction callbackFunction);
  100. FrameCaptureOutcome InternalCaptureScreenshot(
  101. const AZStd::string& imagePath,
  102. AzFramework::NativeWindowHandle windowHandle);
  103. FrameCaptureOutcome InternalCapturePassAttachment(
  104. const AZStd::string& outputFilePath,
  105. AZ::RPI::AttachmentReadback::CallbackFunction callbackFunction,
  106. const AZStd::vector<AZStd::string>& passHierarchy,
  107. const AZStd::string& slotName,
  108. RPI::PassAttachmentReadbackOption option);
  109. void CaptureAttachmentCallback(const AZ::RPI::AttachmentReadback::ReadbackResult& readbackResult);
  110. CaptureHandle InitCapture();
  111. // SystemTickBus overrides ...
  112. void OnSystemTick() override;
  113. AZStd::string ResolvePath(const AZStd::string& filePath);
  114. AZStd::shared_mutex m_handleLock; // Use a shared_mutex so we can protect against the allCaptures vector being resized and moving the CaptureStates in memory.
  115. AZStd::deque<CaptureHandle> m_idleCaptures; // fifo for idle captures
  116. AZStd::deque<CaptureHandle> m_inProgressCaptures; // uses a deque so we can maintain order, order created == order OnFrameCaptureFinished sent
  117. AZStd::vector<CaptureState> m_allCaptures;
  118. AZStd::string m_screenshotFolder;
  119. AZStd::string m_testEnvPath;
  120. AZStd::string m_officialBaselineImageFolder;
  121. AZStd::string m_localBaselineImageFolder;
  122. };
  123. }
  124. }