Utils.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  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 <Utils/Utils.h>
  9. #include <AzCore/IO/SystemFile.h>
  10. #include <AzCore/Settings/SettingsRegistryMergeUtils.h>
  11. #include <AtomCore/Instance/InstanceDatabase.h>
  12. #include <Atom/RHI/RHISystemInterface.h>
  13. #include <Atom/RPI.Public/RenderPipeline.h>
  14. #include <Atom/RPI.Public/RPISystemInterface.h>
  15. #include <Atom/RPI.Public/Scene.h>
  16. #include <Atom/RPI.Public/Image/ImageSystemInterface.h>
  17. #include <Atom/RPI.Reflect/Asset/AssetUtils.h>
  18. #include <Atom/RPI.Reflect/Image/StreamingImageAssetCreator.h>
  19. #include <Atom/RPI.Reflect/Image/ImageMipChainAssetCreator.h>
  20. #include <Atom/Utils/DdsFile.h>
  21. #ifdef AZ_PROFILE_TELEMETRY
  22. #include <RADTelemetry/ProfileTelemetryBus.h>
  23. #endif
  24. #include <AzFramework/CommandLine/CommandLine.h>
  25. #include <AzFramework/API/ApplicationAPI.h>
  26. #include <AzFramework/Windowing/NativeWindow.h>
  27. #include <AzCore/Asset/AssetCommon.h>
  28. #include <AzCore/PlatformIncl.h>
  29. #include <AzCore/IO/SystemFile.h>
  30. #include <AzCore/IO/Path/Path.h>
  31. #include <Automation/ScriptRepeaterBus.h>
  32. namespace AtomSampleViewer
  33. {
  34. namespace Utils
  35. {
  36. AZ::RHI::Ptr<AZ::RHI::Device> GetRHIDevice()
  37. {
  38. using namespace AZ;
  39. auto* rhiSystem = RHI::RHISystemInterface::Get();
  40. AZ_Assert(rhiSystem, "Failed to retrieve rhi system.");
  41. return rhiSystem->GetDevice();
  42. }
  43. bool AssetEntryNameGetter(void* data, int index, const char** outName)
  44. {
  45. const AssetEntry* assetEntries = reinterpret_cast<const AssetEntry*>(data);
  46. *outName = assetEntries[index].m_name.c_str();
  47. return true;
  48. }
  49. void ToggleRadTMCapture()
  50. {
  51. #ifdef AZ_PROFILE_TELEMETRY
  52. using namespace RADTelemetry;
  53. using MaskType = AZ::Debug::ProfileCategoryPrimitiveType;
  54. // Set all the category bits "below" Detailed by default
  55. static const MaskType defaultCaptureMask = AZ_PROFILE_CAT_TO_RAD_CAPFLAGS(FirstDetailedCategory) - 1;
  56. static const char* s_telemetryAddress = "127.0.0.1";
  57. static int32_t s_telemetryPort = 4719;
  58. static MaskType s_telemetryCaptureMask = defaultCaptureMask;
  59. static int32_t s_memCaptureEnabled = 0;
  60. ProfileTelemetryRequestBus::Broadcast(&ProfileTelemetryRequestBus::Events::SetAddress, s_telemetryAddress, s_telemetryPort);
  61. const MaskType fullCaptureMask = s_telemetryCaptureMask | (s_memCaptureEnabled ? AZ_PROFILE_CAT_TO_RAD_CAPFLAGS(MemoryReserved) : 0);
  62. ProfileTelemetryRequestBus::Broadcast(&ProfileTelemetryRequestBus::Events::SetCaptureMask, fullCaptureMask);
  63. ProfileTelemetryRequestBus::Broadcast(&ProfileTelemetryRequestBus::Events::ToggleEnabled);
  64. #endif // AZ_PROFILE_TELEMETRY
  65. }
  66. DefaultIBL::~DefaultIBL()
  67. {
  68. Reset();
  69. }
  70. void DefaultIBL::PreloadAssets()
  71. {
  72. const constexpr char* DiffuseAssetPath = "textures/sampleenvironment/examplespecularhdr_cm_ibldiffuse.dds.streamingimage";
  73. const constexpr char* SpecularAssetPath = "textures/sampleenvironment/examplespecularhdr_cm_iblspecular.dds.streamingimage";
  74. auto assertTraceLevel = AZ::RPI::AssetUtils::TraceLevel::Assert;
  75. if (!m_diffuseImageAsset.IsReady())
  76. {
  77. m_diffuseImageAsset = AZ::RPI::AssetUtils::GetAssetByProductPath<AZ::RPI::StreamingImageAsset>(DiffuseAssetPath, assertTraceLevel);
  78. m_diffuseImageAsset.QueueLoad();
  79. m_diffuseImageAsset.BlockUntilLoadComplete();
  80. }
  81. if (!m_specularImageAsset.IsReady())
  82. {
  83. m_specularImageAsset = AZ::RPI::AssetUtils::GetAssetByProductPath<AZ::RPI::StreamingImageAsset>(SpecularAssetPath, assertTraceLevel);
  84. m_specularImageAsset.QueueLoad();
  85. m_specularImageAsset.BlockUntilLoadComplete();
  86. }
  87. }
  88. void DefaultIBL::Init(AZ::RPI::Scene* scene)
  89. {
  90. PreloadAssets();
  91. m_featureProcessor = scene->GetFeatureProcessor<AZ::Render::ImageBasedLightFeatureProcessorInterface>();
  92. AZ_Assert(m_featureProcessor, "Unabled to find ImageBasedLightFeatureProcessorInterface on scene.");
  93. m_featureProcessor->SetDiffuseImage(m_diffuseImageAsset);
  94. m_featureProcessor->SetSpecularImage(m_specularImageAsset);
  95. }
  96. void DefaultIBL::SetExposure(float exposure)
  97. {
  98. m_featureProcessor->SetExposure(exposure);
  99. }
  100. void DefaultIBL::Reset()
  101. {
  102. if (m_featureProcessor)
  103. {
  104. m_featureProcessor->Reset();
  105. m_featureProcessor = nullptr;
  106. }
  107. }
  108. void ResizeClientArea(uint32_t width, uint32_t height, const AzFramework::WindowPosOptions& options)
  109. {
  110. AzFramework::NativeWindowHandle windowHandle = nullptr;
  111. AzFramework::WindowSystemRequestBus::BroadcastResult(
  112. windowHandle,
  113. &AzFramework::WindowSystemRequestBus::Events::GetDefaultWindowHandle);
  114. AzFramework::WindowSize clientAreaSize = {width, height};
  115. AzFramework::WindowRequestBus::Event(windowHandle, &AzFramework::WindowRequestBus::Events::ResizeClientArea, clientAreaSize, options);
  116. AzFramework::WindowSize newWindowSize;
  117. AzFramework::WindowRequestBus::EventResult(newWindowSize, windowHandle, &AzFramework::WindowRequests::GetClientAreaSize);
  118. AZ_Error("ResizeClientArea", newWindowSize.m_width == width && newWindowSize.m_height == height,
  119. "Requested window resize to %ux%u but got %ux%u. This display resolution is too low or desktop scaling is too high.",
  120. width, height, newWindowSize.m_width, newWindowSize.m_height);
  121. }
  122. bool SupportsToggleFullScreenOfDefaultWindow()
  123. {
  124. return AzFramework::NativeWindow::CanToggleFullScreenStateOfDefaultWindow();
  125. }
  126. void ToggleFullScreenOfDefaultWindow()
  127. {
  128. AzFramework::NativeWindow::ToggleFullScreenStateOfDefaultWindow();
  129. }
  130. void ReportScriptableAction(const char* formatStr, ...)
  131. {
  132. va_list args;
  133. va_start(args, formatStr);
  134. ScriptRepeaterRequestBus::Broadcast(&ScriptRepeaterRequests::ReportScriptableAction, AZStd::string::format_arg(formatStr, args));
  135. va_end(args);
  136. }
  137. AZ::Data::Instance<AZ::RPI::StreamingImage> GetSolidColorCubemap(uint32_t color)
  138. {
  139. constexpr uint32_t width = 4;
  140. constexpr uint32_t height = 4;
  141. const AZStd::string assetName = AZStd::string::format("SolidColorBackground_%u", color);
  142. const AZ::Data::InstanceId instanceId = AZ::Data::InstanceId::CreateName(assetName.c_str());
  143. // Check for existing image of the same color
  144. AZ::Data::Instance<AZ::RPI::StreamingImage> existingImage =
  145. AZ::Data::InstanceDatabase<AZ::RPI::StreamingImage>::Instance().Find(instanceId);
  146. if (existingImage)
  147. {
  148. return existingImage;
  149. }
  150. // Build a new cubemap.
  151. AZ::RHI::Size imageSize = AZ::RHI::Size(width, height, 1);
  152. const uint32_t pixelSize = sizeof(uint32_t);
  153. const uint32_t pixelDataSize = width * height * pixelSize;
  154. AZStd::array<uint32_t, width* height> pixels;
  155. for (uint32_t& pixelColor : pixels)
  156. {
  157. pixelColor = color;
  158. }
  159. // Create a new streaming image
  160. AZ::RPI::StreamingImageAssetCreator imageCreator;
  161. imageCreator.Begin(AZ::Data::AssetId(instanceId.GetGuid(), 0));
  162. int32_t arraySize = 6;
  163. AZ::RHI::Format format = AZ::RHI::Format::R8G8B8A8_UNORM_SRGB;
  164. AZ::RHI::ImageBindFlags bindFlag = AZ::RHI::ImageBindFlags::ShaderRead;
  165. AZ::RHI::ImageDescriptor imageDesc = AZ::RHI::ImageDescriptor::Create2DArray(bindFlag, width, height, static_cast<uint16_t>(arraySize), format);
  166. imageDesc.m_mipLevels = 1;
  167. imageDesc.m_isCubemap = true;
  168. imageCreator.SetImageDescriptor(imageDesc);
  169. imageCreator.SetImageViewDescriptor(AZ::RHI::ImageViewDescriptor::CreateCubemap());
  170. // Create the mip chain
  171. AZ::RPI::ImageMipChainAssetCreator mipChainCreator;
  172. mipChainCreator.Begin(AZ::Data::AssetId(instanceId.GetGuid(), 1), 1, 6);
  173. uint32_t pitch = width * pixelSize;
  174. AZ::RHI::DeviceImageSubresourceLayout layout;
  175. layout.m_bytesPerImage = pixelDataSize;
  176. layout.m_rowCount = layout.m_bytesPerImage / pitch;
  177. layout.m_size = AZ::RHI::Size(width, height, 1);
  178. layout.m_bytesPerRow = pitch;
  179. mipChainCreator.BeginMip(layout);
  180. for (uint32_t i = 0; i < 6; ++i)
  181. {
  182. mipChainCreator.AddSubImage(pixels.data(), pixelDataSize);
  183. }
  184. mipChainCreator.EndMip();
  185. AZ::Data::Asset<AZ::RPI::ImageMipChainAsset> mipChainAsset;
  186. mipChainCreator.End(mipChainAsset);
  187. imageCreator.AddMipChainAsset(*mipChainAsset);
  188. // Finalize streaming image asset
  189. AZ::Data::Asset<AZ::RPI::StreamingImageAsset> imageAsset;
  190. imageCreator.End(imageAsset);
  191. return AZ::Data::InstanceDatabase<AZ::RPI::StreamingImage>::Instance().FindOrCreate(instanceId, imageAsset);
  192. }
  193. AZStd::string ResolvePath(const AZStd::string& path)
  194. {
  195. char resolvedPath[AZ_MAX_PATH_LEN] = {0};
  196. AZ::IO::FileIOBase::GetInstance()->ResolvePath(path.c_str(), resolvedPath, AZ_MAX_PATH_LEN);
  197. return resolvedPath;
  198. }
  199. bool IsFileUnderFolder(AZStd::string filePath, AZStd::string folder)
  200. {
  201. AzFramework::StringFunc::Path::Normalize(filePath);
  202. AzFramework::StringFunc::Path::Normalize(folder);
  203. AZStd::to_lower(filePath.begin(), filePath.end());
  204. AZStd::to_lower(folder.begin(), folder.end());
  205. auto relativePath = AZ::IO::FixedMaxPath(filePath.c_str()).LexicallyRelative(folder.c_str());
  206. if (!relativePath.empty() && !relativePath.Native().starts_with(".."))
  207. {
  208. return true;
  209. }
  210. return false;
  211. }
  212. bool RunDiffTool(const AZStd::string& filePathA, const AZStd::string& filePathB)
  213. {
  214. // First let's try to use the user's favorite diff tool.
  215. static constexpr AZStd::string_view DiffToolPathKey = "/O3DE/External/DiffTool";
  216. AZStd::string diffToolPath;
  217. if (auto registry = AZ::SettingsRegistry::Get())
  218. {
  219. registry->Get(diffToolPath, DiffToolPathKey);
  220. }
  221. if (!diffToolPath.empty())
  222. {
  223. // Does the executable exist?
  224. if (AZ::IO::SystemFile::Exists(diffToolPath.c_str()))
  225. {
  226. return RunDiffTool_Impl(diffToolPath, filePathA, filePathB);
  227. }
  228. AZ_Warning(
  229. "ASV::RunDiffTool", false, "The user's diff tool <%s> doesn't exist. Will use the platform default <%s>.\n",
  230. diffToolPath.c_str(), GetDefaultDiffToolPath_Impl().c_str());
  231. }
  232. // If the key doesn't exist in the registry, or the user specified executable doesn't exist, then
  233. // use the platform default.
  234. diffToolPath = GetDefaultDiffToolPath_Impl();
  235. if (!diffToolPath.empty())
  236. {
  237. // Does the executable exist?
  238. if (AZ::IO::SystemFile::Exists(diffToolPath.c_str()))
  239. {
  240. return RunDiffTool_Impl(diffToolPath, filePathA, filePathB);
  241. }
  242. AZ_Warning(
  243. "ASV::RunDiffTool", false,
  244. "The platform default diff tool <%s> doesn't exist.\n"
  245. "You can customize the tool path in the settings registry key: %s.\n",
  246. diffToolPath.c_str(),
  247. DiffToolPathKey.data());
  248. }
  249. else
  250. {
  251. AZ_Warning(
  252. "ASV::RunDiffTool", false,
  253. "No default diff tool has been defined for the current platform.\n"
  254. "You can customize the tool path in the settings registry key: %s.\n",
  255. DiffToolPathKey.data());
  256. }
  257. return false;
  258. }
  259. } // namespace Utils
  260. } // namespace AtomSampleViewer