Stubs.h 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433
  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 <Atom/RHI.Reflect/ShaderStageFunction.h>
  10. #include <Atom/RHI/Device.h>
  11. #include <Atom/RHI/FrameGraphCompiler.h>
  12. #include <Atom/RHI/FrameGraphExecuter.h>
  13. #include <Atom/RHI/FrameGraphInterface.h>
  14. #include <Atom/RHI/Scope.h>
  15. #include <Atom/RHI/DeviceBufferView.h>
  16. #include <Atom/RHI/DeviceBuffer.h>
  17. #include <Atom/RHI/DeviceBufferPool.h>
  18. #include <Atom/RHI/DeviceFence.h>
  19. #include <Atom/RHI/DeviceImage.h>
  20. #include <Atom/RHI/DeviceImagePool.h>
  21. #include <Atom/RHI/DeviceIndirectBufferSignature.h>
  22. #include <Atom/RHI/DeviceIndirectBufferWriter.h>
  23. #include <Atom/RHI/DevicePipelineLibrary.h>
  24. #include <Atom/RHI/DevicePipelineState.h>
  25. #include <Atom/RHI/DeviceQuery.h>
  26. #include <Atom/RHI/DeviceQueryPool.h>
  27. #include <Atom/RHI/DeviceShaderResourceGroup.h>
  28. #include <Atom/RHI/DeviceShaderResourceGroupPool.h>
  29. #include <Atom/RHI/DeviceStreamingImagePool.h>
  30. #include <Atom/RHI/DeviceSwapChain.h>
  31. #include <Atom/RHI/DeviceTransientAttachmentPool.h>
  32. namespace UnitTest
  33. {
  34. namespace StubRHI
  35. {
  36. class PhysicalDevice
  37. : public AZ::RHI::PhysicalDevice
  38. {
  39. public:
  40. AZ_CLASS_ALLOCATOR(PhysicalDevice, AZ::SystemAllocator);
  41. static AZ::RHI::PhysicalDeviceList Enumerate();
  42. private:
  43. PhysicalDevice();
  44. };
  45. class Device
  46. : public AZ::RHI::Device
  47. {
  48. public:
  49. AZ_CLASS_ALLOCATOR(Device, AZ::SystemAllocator);
  50. Device();
  51. private:
  52. AZ::RHI::ResultCode InitInternal([[maybe_unused]] AZ::RHI::PhysicalDevice&) override { return AZ::RHI::ResultCode::Success; }
  53. AZ::RHI::ResultCode InitInternalBindlessSrg([[maybe_unused]] const AZ::RHI::BindlessSrgDescriptor& bindlessSrgDesc) override { return AZ::RHI::ResultCode::Success;}
  54. void ShutdownInternal() override {}
  55. AZ::RHI::ResultCode BeginFrameInternal() override { return AZ::RHI::ResultCode::Success;}
  56. void EndFrameInternal() override {}
  57. void WaitForIdleInternal() override {}
  58. void CompileMemoryStatisticsInternal(AZ::RHI::MemoryStatisticsBuilder&) override {}
  59. void UpdateCpuTimingStatisticsInternal() const override {}
  60. AZStd::chrono::microseconds GpuTimestampToMicroseconds([[maybe_unused]] uint64_t gpuTimestamp, [[maybe_unused]] AZ::RHI::HardwareQueueClass queueClass) const override
  61. {
  62. return AZStd::chrono::microseconds();
  63. }
  64. AZStd::pair<uint64_t, uint64_t> GetCalibratedTimestamp([[maybe_unused]] AZ::RHI::HardwareQueueClass queueClass) override
  65. {
  66. return { 0ull, AZStd::chrono::microseconds().count() };
  67. };
  68. void FillFormatsCapabilitiesInternal([[maybe_unused]] FormatCapabilitiesList& formatsCapabilities) override {}
  69. AZ::RHI::ResultCode InitializeLimits() override { return AZ::RHI::ResultCode::Success; }
  70. void PreShutdown() override {}
  71. AZ::RHI::ResourceMemoryRequirements GetResourceMemoryRequirements([[maybe_unused]] const AZ::RHI::ImageDescriptor& descriptor) override { return AZ::RHI::ResourceMemoryRequirements{}; };
  72. AZ::RHI::ResourceMemoryRequirements GetResourceMemoryRequirements([[maybe_unused]] const AZ::RHI::BufferDescriptor& descriptor) override { return AZ::RHI::ResourceMemoryRequirements{}; };
  73. void ObjectCollectionNotify([[maybe_unused]] AZ::RHI::ObjectCollectorNotifyFunction notifyFunction) override {}
  74. AZ::RHI::ShadingRateImageValue ConvertShadingRate([[maybe_unused]] AZ::RHI::ShadingRate rate) const override
  75. {
  76. return AZ::RHI::ShadingRateImageValue{};
  77. }
  78. };
  79. class ImageView
  80. : public AZ::RHI::DeviceImageView
  81. {
  82. public:
  83. AZ_CLASS_ALLOCATOR(ImageView, AZ::SystemAllocator);
  84. private:
  85. AZ::RHI::ResultCode InitInternal(AZ::RHI::Device&, const AZ::RHI::DeviceResource&) override { return AZ::RHI::ResultCode::Success; }
  86. AZ::RHI::ResultCode InvalidateInternal() override { return AZ::RHI::ResultCode::Success; }
  87. void ShutdownInternal() override {}
  88. };
  89. class Image
  90. : public AZ::RHI::DeviceImage
  91. {
  92. public:
  93. AZ_CLASS_ALLOCATOR(Image, AZ::SystemAllocator);
  94. private:
  95. void GetSubresourceLayoutsInternal(
  96. const AZ::RHI::ImageSubresourceRange&, AZ::RHI::DeviceImageSubresourceLayout*, size_t*) const override
  97. {
  98. }
  99. bool IsStreamableInternal() const override {return true;};
  100. };
  101. class BufferView
  102. : public AZ::RHI::DeviceBufferView
  103. {
  104. public:
  105. AZ_CLASS_ALLOCATOR(BufferView, AZ::SystemAllocator);
  106. private:
  107. AZ::RHI::ResultCode InitInternal(AZ::RHI::Device&, const AZ::RHI::DeviceResource&) override { return AZ::RHI::ResultCode::Success; }
  108. AZ::RHI::ResultCode InvalidateInternal() override { return AZ::RHI::ResultCode::Success; }
  109. void ShutdownInternal() override {}
  110. };
  111. class Buffer
  112. : public AZ::RHI::DeviceBuffer
  113. {
  114. friend class BufferPool;
  115. public:
  116. AZ_CLASS_ALLOCATOR(Buffer, AZ::SystemAllocator);
  117. bool IsMapped() const { return m_isMapped; }
  118. void* Map()
  119. {
  120. m_isMapped = true;
  121. return m_data.data();
  122. }
  123. void Unmap()
  124. {
  125. m_isMapped = false;
  126. }
  127. const AZStd::vector<uint8_t>& GetData() const
  128. {
  129. return m_data;
  130. }
  131. private:
  132. bool m_isMapped = false;
  133. AZStd::vector<uint8_t> m_data;
  134. };
  135. class BufferPool
  136. : public AZ::RHI::DeviceBufferPool
  137. {
  138. public:
  139. AZ_CLASS_ALLOCATOR(BufferPool, AZ::SystemAllocator);
  140. private:
  141. AZ::RHI::ResultCode InitInternal(AZ::RHI::Device&, const AZ::RHI::BufferPoolDescriptor&) override { return AZ::RHI::ResultCode::Success;}
  142. AZ::RHI::ResultCode InitBufferInternal(AZ::RHI::DeviceBuffer& bufferBase, const AZ::RHI::BufferDescriptor& descriptor) override
  143. {
  144. AZ_Assert(IsInitialized(), "Buffer Pool is not initialized");
  145. Buffer& buffer = static_cast<Buffer&>(bufferBase);
  146. buffer.m_data.resize(descriptor.m_byteCount);
  147. return AZ::RHI::ResultCode::Success;
  148. }
  149. void ShutdownResourceInternal(AZ::RHI::DeviceResource& resourceBase) override
  150. {
  151. Buffer& buffer = static_cast<Buffer&>(resourceBase);
  152. buffer.m_data.clear();
  153. }
  154. AZ::RHI::ResultCode MapBufferInternal(const AZ::RHI::DeviceBufferMapRequest& request, AZ::RHI::DeviceBufferMapResponse& response) override
  155. {
  156. Buffer& buffer = static_cast<Buffer&>(*request.m_buffer);
  157. response.m_data = buffer.Map();
  158. return AZ::RHI::ResultCode::Success;
  159. }
  160. void UnmapBufferInternal(AZ::RHI::DeviceBuffer& bufferBase) override
  161. {
  162. Buffer& buffer = static_cast<Buffer&>(bufferBase);
  163. buffer.Unmap();
  164. }
  165. AZ::RHI::ResultCode OrphanBufferInternal(AZ::RHI::DeviceBuffer&) override { return AZ::RHI::ResultCode::Success; }
  166. AZ::RHI::ResultCode StreamBufferInternal([[maybe_unused]] const AZ::RHI::DeviceBufferStreamRequest& request) override { return AZ::RHI::ResultCode::Success; }
  167. void ComputeFragmentation() const override {}
  168. };
  169. class ImagePool
  170. : public AZ::RHI::DeviceImagePool
  171. {
  172. public:
  173. AZ_CLASS_ALLOCATOR(ImagePool, AZ::SystemAllocator);
  174. private:
  175. AZ::RHI::ResultCode InitInternal(AZ::RHI::Device&, const AZ::RHI::ImagePoolDescriptor&) override { return AZ::RHI::ResultCode::Success; }
  176. void ShutdownInternal() override {}
  177. AZ::RHI::ResultCode UpdateImageContentsInternal(const AZ::RHI::DeviceImageUpdateRequest&) override { return AZ::RHI::ResultCode::Success; }
  178. AZ::RHI::ResultCode InitImageInternal(const AZ::RHI::DeviceImageInitRequest&) override
  179. {
  180. return AZ::RHI::ResultCode::Success;
  181. }
  182. void ShutdownResourceInternal(AZ::RHI::DeviceResource&) override {}
  183. };
  184. class StreamingImagePool
  185. : public AZ::RHI::DeviceStreamingImagePool
  186. {
  187. public:
  188. AZ_CLASS_ALLOCATOR(StreamingImagePool, AZ::SystemAllocator);
  189. void ComputeFragmentation() const override {}
  190. private:
  191. AZ::RHI::ResultCode InitImageInternal([[maybe_unused]] const AZ::RHI::DeviceStreamingImageInitRequest& request) override { return AZ::RHI::ResultCode::Success; }
  192. void ShutdownInternal() override {}
  193. void ShutdownResourceInternal(AZ::RHI::DeviceResource&) override {}
  194. AZ::RHI::ResultCode ExpandImageInternal(const AZ::RHI::DeviceStreamingImageExpandRequest&) override { return AZ::RHI::ResultCode::Success; }
  195. AZ::RHI::ResultCode TrimImageInternal(AZ::RHI::DeviceImage&, uint32_t) override { return AZ::RHI::ResultCode::Success; }
  196. };
  197. class SwapChain
  198. : public AZ::RHI::DeviceSwapChain
  199. {
  200. public:
  201. AZ_CLASS_ALLOCATOR(SwapChain, AZ::SystemAllocator);
  202. private:
  203. AZ::RHI::ResultCode InitInternal(AZ::RHI::Device&, const AZ::RHI::SwapChainDescriptor&, [[maybe_unused]] AZ::RHI::SwapChainDimensions* outNativeDimensions) override { return AZ::RHI::ResultCode::Success; }
  204. AZ::RHI::ResultCode InitImageInternal(const InitImageRequest&) override { return AZ::RHI::ResultCode::Success; }
  205. AZ::RHI::ResultCode ResizeInternal([[maybe_unused]] const AZ::RHI::SwapChainDimensions& dimensions, [[maybe_unused]] AZ::RHI::SwapChainDimensions* nativeDimensions) override { return AZ::RHI::ResultCode::Success; };
  206. uint32_t PresentInternal() override { return 0; };
  207. };
  208. class Fence
  209. : public AZ::RHI::DeviceFence
  210. {
  211. public:
  212. AZ_CLASS_ALLOCATOR(Fence, AZ::SystemAllocator);
  213. private:
  214. AZ::RHI::ResultCode InitInternal(AZ::RHI::Device&, AZ::RHI::FenceState, [[maybe_unused]] bool usedForWaitingOnDevice) override
  215. {
  216. return AZ::RHI::ResultCode::Success;
  217. }
  218. void ShutdownInternal() override {}
  219. void SignalOnCpuInternal() override {}
  220. void WaitOnCpuInternal() const override {};
  221. void ResetInternal() override {}
  222. AZ::RHI::FenceState GetFenceStateInternal() const override { return AZ::RHI::FenceState::Reset; }
  223. };
  224. class ShaderResourceGroupPool
  225. : public AZ::RHI::DeviceShaderResourceGroupPool
  226. {
  227. public:
  228. AZ_CLASS_ALLOCATOR(ShaderResourceGroupPool, AZ::SystemAllocator);
  229. private:
  230. AZ::RHI::ResultCode InitInternal(AZ::RHI::Device&, const AZ::RHI::ShaderResourceGroupPoolDescriptor&) override { return AZ::RHI::ResultCode::Success; }
  231. AZ::RHI::ResultCode InitGroupInternal(AZ::RHI::DeviceShaderResourceGroup&) override { return AZ::RHI::ResultCode::Success; }
  232. AZ::RHI::ResultCode CompileGroupInternal(AZ::RHI::DeviceShaderResourceGroup&,const AZ::RHI::DeviceShaderResourceGroupData&) override { return AZ::RHI::ResultCode::Success; }
  233. };
  234. class ShaderResourceGroup
  235. : public AZ::RHI::DeviceShaderResourceGroup
  236. {
  237. public:
  238. AZ_CLASS_ALLOCATOR(ShaderResourceGroup, AZ::SystemAllocator);
  239. };
  240. class PipelineLibrary
  241. : public AZ::RHI::DevicePipelineLibrary
  242. {
  243. public:
  244. AZ_CLASS_ALLOCATOR(PipelineLibrary, AZ::SystemAllocator);
  245. private:
  246. AZ::RHI::ResultCode InitInternal(AZ::RHI::Device&, [[maybe_unused]] const AZ::RHI::DevicePipelineLibraryDescriptor& descriptor) override { return AZ::RHI::ResultCode::Success; }
  247. void ShutdownInternal() override {}
  248. AZ::RHI::ResultCode MergeIntoInternal(AZStd::span<const AZ::RHI::DevicePipelineLibrary* const>) override { return AZ::RHI::ResultCode::Success; }
  249. AZ::RHI::ConstPtr<AZ::RHI::PipelineLibraryData> GetSerializedDataInternal() const override { return nullptr; }
  250. bool SaveSerializedDataInternal([[maybe_unused]] const AZStd::string& filePath) const { return true;}
  251. };
  252. class ShaderStageFunction
  253. : public AZ::RHI::ShaderStageFunction
  254. {
  255. public:
  256. AZ_RTTI(ShaderStageFunction, "{644DBC98-C864-488C-BBA8-0137C210C1E2}", AZ::RHI::ShaderStageFunction);
  257. AZ_CLASS_ALLOCATOR(ShaderStageFunction, AZ::SystemAllocator);
  258. private:
  259. AZ::RHI::ResultCode FinalizeInternal() override { return AZ::RHI::ResultCode::Success; }
  260. };
  261. class PipelineState
  262. : public AZ::RHI::DevicePipelineState
  263. {
  264. public:
  265. AZ_CLASS_ALLOCATOR(PipelineState, AZ::SystemAllocator);
  266. private:
  267. AZ::RHI::ResultCode InitInternal(AZ::RHI::Device&, const AZ::RHI::PipelineStateDescriptorForDraw&, AZ::RHI::DevicePipelineLibrary*) override { return AZ::RHI::ResultCode::Success; }
  268. AZ::RHI::ResultCode InitInternal(AZ::RHI::Device&, const AZ::RHI::PipelineStateDescriptorForDispatch&, AZ::RHI::DevicePipelineLibrary*) override { return AZ::RHI::ResultCode::Success; }
  269. AZ::RHI::ResultCode InitInternal(AZ::RHI::Device&, const AZ::RHI::PipelineStateDescriptorForRayTracing&, AZ::RHI::DevicePipelineLibrary*) override { return AZ::RHI::ResultCode::Success; }
  270. void ShutdownInternal() override {}
  271. };
  272. class Scope
  273. : public AZ::RHI::Scope
  274. {
  275. public:
  276. AZ_CLASS_ALLOCATOR(Scope, AZ::SystemAllocator);
  277. private:
  278. void InitInternal() override {}
  279. void ActivateInternal() override {}
  280. void CompileInternal() override {}
  281. void DeactivateInternal() override {}
  282. void ShutdownInternal() override {}
  283. };
  284. class FrameGraphCompiler
  285. : public AZ::RHI::FrameGraphCompiler
  286. {
  287. public:
  288. AZ_CLASS_ALLOCATOR(FrameGraphCompiler, AZ::SystemAllocator);
  289. private:
  290. AZ::RHI::ResultCode InitInternal() override { return AZ::RHI::ResultCode::Success; }
  291. AZ::RHI::MessageOutcome CompileInternal(const AZ::RHI::FrameGraphCompileRequest&) override { return AZ::Success(); }
  292. void ShutdownInternal() override {}
  293. };
  294. class FrameGraphExecuter
  295. : public AZ::RHI::FrameGraphExecuter
  296. {
  297. public:
  298. AZ_CLASS_ALLOCATOR(FrameGraphExecuter, AZ::SystemAllocator);
  299. private:
  300. AZ::RHI::ResultCode InitInternal(const AZ::RHI::FrameGraphExecuterDescriptor&) override { return AZ::RHI::ResultCode::Success; }
  301. void BeginInternal(const AZ::RHI::FrameGraph&) override {}
  302. void ExecuteGroupInternal(AZ::RHI::FrameGraphExecuteGroup&) override {}
  303. void EndInternal() override {}
  304. void ShutdownInternal() override {}
  305. };
  306. class TransientAttachmentPool
  307. : public AZ::RHI::DeviceTransientAttachmentPool
  308. {
  309. public:
  310. AZ_CLASS_ALLOCATOR(TransientAttachmentPool, AZ::SystemAllocator);
  311. private:
  312. AZ::RHI::ResultCode InitInternal(AZ::RHI::Device&, const AZ::RHI::TransientAttachmentPoolDescriptor&) override { return AZ::RHI::ResultCode::Success; }
  313. void BeginInternal([[maybe_unused]] const AZ::RHI::TransientAttachmentPoolCompileFlags flags, [[maybe_unused]] const AZ::RHI::TransientAttachmentStatistics::MemoryUsage* memoryHint) override {}
  314. AZ::RHI::DeviceImage* ActivateImage(const AZ::RHI::TransientImageDescriptor&) override { return nullptr; }
  315. AZ::RHI::DeviceBuffer* ActivateBuffer(const AZ::RHI::TransientBufferDescriptor&) override { return nullptr; }
  316. void DeactivateBuffer(const AZ::RHI::AttachmentId&) override {}
  317. void DeactivateImage(const AZ::RHI::AttachmentId&) override {}
  318. void EndInternal() override {}
  319. void ShutdownInternal() override {}
  320. };
  321. class Query
  322. : public AZ::RHI::DeviceQuery
  323. {
  324. friend class QueryPool;
  325. public:
  326. AZ_CLASS_ALLOCATOR(Query, AZ::SystemAllocator);
  327. private:
  328. AZ::RHI::ResultCode BeginInternal([[maybe_unused]] AZ::RHI::CommandList& commandList, [[maybe_unused]] AZ::RHI::QueryControlFlags flags) override { return AZ::RHI::ResultCode::Success; }
  329. AZ::RHI::ResultCode EndInternal([[maybe_unused]] AZ::RHI::CommandList& commandList) override { return AZ::RHI::ResultCode::Success; }
  330. AZ::RHI::ResultCode WriteTimestampInternal([[maybe_unused]] AZ::RHI::CommandList& commandList) override { return AZ::RHI::ResultCode::Success; };
  331. };
  332. class QueryPool
  333. : public AZ::RHI::DeviceQueryPool
  334. {
  335. public:
  336. AZ_CLASS_ALLOCATOR(QueryPool, AZ::SystemAllocator);
  337. private:
  338. AZ::RHI::ResultCode InitInternal([[maybe_unused]] AZ::RHI::Device& device, [[maybe_unused]] const AZ::RHI::QueryPoolDescriptor& descriptor) override { return AZ::RHI::ResultCode::Success; }
  339. AZ::RHI::ResultCode InitQueryInternal([[maybe_unused]] AZ::RHI::DeviceQuery& query) override { return AZ::RHI::ResultCode::Success; }
  340. AZ::RHI::ResultCode GetResultsInternal(
  341. [[maybe_unused]] uint32_t startIndex,
  342. [[maybe_unused]] uint32_t queryCount,
  343. [[maybe_unused]] uint64_t* results,
  344. [[maybe_unused]] uint32_t resultsCount,
  345. [[maybe_unused]] AZ::RHI::QueryResultFlagBits flags) override
  346. { return AZ::RHI::ResultCode::Success; }
  347. };
  348. class IndirectBufferWriter
  349. : public AZ::RHI::DeviceIndirectBufferWriter
  350. {
  351. public:
  352. AZ_CLASS_ALLOCATOR(IndirectBufferWriter, AZ::ThreadPoolAllocator);
  353. private:
  354. void SetVertexViewInternal([[maybe_unused]] AZ::RHI::IndirectCommandIndex index, [[maybe_unused]] const AZ::RHI::DeviceStreamBufferView& view) override {}
  355. void SetIndexViewInternal([[maybe_unused]] AZ::RHI::IndirectCommandIndex index, [[maybe_unused]] const AZ::RHI::DeviceIndexBufferView& view) override {}
  356. void DrawInternal([[maybe_unused]] AZ::RHI::IndirectCommandIndex index, [[maybe_unused]] const AZ::RHI::DrawLinear& arguments, [[maybe_unused]] const AZ::RHI::DrawInstanceArguments& drawInstanceArgs) override {}
  357. void DrawIndexedInternal([[maybe_unused]] AZ::RHI::IndirectCommandIndex index, [[maybe_unused]] const AZ::RHI::DrawIndexed& arguments, [[maybe_unused]] const AZ::RHI::DrawInstanceArguments& drawInstanceArgs) override {}
  358. void DispatchInternal([[maybe_unused]] AZ::RHI::IndirectCommandIndex index, [[maybe_unused]] const AZ::RHI::DispatchDirect& arguments) override {}
  359. void SetRootConstantsInternal([[maybe_unused]] AZ::RHI::IndirectCommandIndex index, [[maybe_unused]] const uint8_t* data, [[maybe_unused]] uint32_t byteSize) override {}
  360. };
  361. class IndirectBufferSignature
  362. : public AZ::RHI::DeviceIndirectBufferSignature
  363. {
  364. public:
  365. AZ_CLASS_ALLOCATOR(IndirectBufferSignature, AZ::ThreadPoolAllocator);
  366. private:
  367. AZ::RHI::ResultCode InitInternal([[maybe_unused]] AZ::RHI::Device& device, [[maybe_unused]] const AZ::RHI::DeviceIndirectBufferSignatureDescriptor& descriptor) override { return AZ::RHI::ResultCode::Success; }
  368. uint32_t GetByteStrideInternal() const override { return 0; }
  369. uint32_t GetOffsetInternal([[maybe_unused]] AZ::RHI::IndirectCommandIndex index) const override { return 0; }
  370. void ShutdownInternal() override {}
  371. };
  372. }
  373. }