3
0

UiRenderer.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519
  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 "UiRenderer.h"
  9. #include "LyShinePassDataBus.h"
  10. #include <Atom/RPI.Public/Image/ImageSystemInterface.h>
  11. #include <Atom/RPI.Public/DynamicDraw/DynamicDrawInterface.h>
  12. #include <Atom/RPI.Public/RPISystemInterface.h>
  13. #include <Atom/RPI.Public/RPIUtils.h>
  14. #include <Atom/RPI.Reflect/Asset/AssetUtils.h>
  15. #include <Atom/Bootstrap/DefaultWindowBus.h>
  16. #include <Atom/RPI.Public/ViewportContextBus.h>
  17. #include <Atom/RPI.Public/RenderPipeline.h>
  18. #include <Atom/RPI.Public/Pass/RasterPass.h>
  19. #include <AzCore/Debug/Trace.h>
  20. #include <AzCore/Math/MatrixUtils.h>
  21. #include <AzCore/Settings/SettingsRegistry.h>
  22. #include <LyShine/IDraw2d.h>
  23. ////////////////////////////////////////////////////////////////////////////////////////////////////
  24. // PUBLIC MEMBER FUNCTIONS
  25. ////////////////////////////////////////////////////////////////////////////////////////////////////
  26. ////////////////////////////////////////////////////////////////////////////////////////////////////
  27. UiRenderer::UiRenderer(AZ::RPI::ViewportContextPtr viewportContext)
  28. : m_viewportContext(viewportContext)
  29. {
  30. // Use bootstrap scene event to indicate when the RPI has fully
  31. // initialized with all assets loaded and is ready to be used
  32. AZ::Render::Bootstrap::NotificationBus::Handler::BusConnect();
  33. }
  34. ////////////////////////////////////////////////////////////////////////////////////////////////////
  35. UiRenderer::~UiRenderer()
  36. {
  37. AZ::Render::Bootstrap::NotificationBus::Handler::BusDisconnect();
  38. if (m_viewportContext)
  39. {
  40. AZ::RPI::RPISystemInterface::Get()->UnregisterScene(m_viewportContext->GetRenderScene());
  41. }
  42. m_dynamicDraw = nullptr;
  43. }
  44. bool UiRenderer::IsReady()
  45. {
  46. return m_isRPIReady;
  47. }
  48. void UiRenderer::OnBootstrapSceneReady(AZ::RPI::Scene* bootstrapScene)
  49. {
  50. // At this point the RPI is ready for use
  51. // Load the UI shader
  52. const char* uiShaderFilepath = "LyShine/Shaders/LyShineUI.azshader";
  53. AZ::Data::Instance<AZ::RPI::Shader> uiShader = AZ::RPI::LoadCriticalShader(uiShaderFilepath);
  54. // Create scene to be used by the dynamic draw context
  55. if (m_viewportContext)
  56. {
  57. // Create a new scene based on the user specified viewport context
  58. m_ownedScene = CreateScene(m_viewportContext);
  59. m_scene = m_ownedScene.get();
  60. }
  61. else
  62. {
  63. // No viewport context specified, use default scene
  64. m_scene = bootstrapScene;
  65. }
  66. // Create a dynamic draw context for UI Canvas drawing for the scene
  67. m_dynamicDraw = CreateDynamicDrawContext(uiShader);
  68. if (m_dynamicDraw && m_dynamicDraw->IsReady())
  69. {
  70. // Cache shader data such as input indices for later use
  71. CacheShaderData(m_dynamicDraw);
  72. m_isRPIReady = true;
  73. }
  74. else
  75. {
  76. AZ_Error(LogName, false, "Failed to create or initialize a dynamic draw context for LyShine. \
  77. This can happen if the LyShine pass hasn't been added to the main render pipeline.");
  78. }
  79. }
  80. AZ::RPI::ScenePtr UiRenderer::CreateScene(AZStd::shared_ptr<AZ::RPI::ViewportContext> viewportContext)
  81. {
  82. // Create and register a scene with feature processors defined in the viewport settings
  83. AZ::RPI::SceneDescriptor sceneDesc;
  84. sceneDesc.m_nameId = AZ::Name("UiRenderer");
  85. auto settingsRegistry = AZ::SettingsRegistry::Get();
  86. const char* viewportSettingPath = "/O3DE/Editor/Viewport/UI/Scene";
  87. bool sceneDescLoaded = settingsRegistry->GetObject(sceneDesc, viewportSettingPath);
  88. AZ::RPI::ScenePtr atomScene = AZ::RPI::Scene::CreateScene(sceneDesc);
  89. if (!sceneDescLoaded)
  90. {
  91. AZ_Warning("UiRenderer", false, "Settings registry is missing the scene settings for this viewport, so all feature processors will be enabled. "
  92. "To enable only a minimal set, add the specific list of feature processors with a registry path of '%s'.", viewportSettingPath);
  93. atomScene->EnableAllFeatureProcessors();
  94. }
  95. // Assign the new scene to the specified viewport context
  96. viewportContext->SetRenderScene(atomScene);
  97. const char* pipelineAssetPath = "passes/MainRenderPipeline.azasset"; // [LYSHINE_ATOM_TODO][GHI #6272] Use a custom UI pipeline
  98. AZStd::optional<AZ::RPI::RenderPipelineDescriptor> renderPipelineDesc =
  99. AZ::RPI::GetRenderPipelineDescriptorFromAsset(pipelineAssetPath, AZStd::string::format("_%i", viewportContext->GetId()));
  100. AZ_Assert(renderPipelineDesc.has_value(), "Invalid render pipeline descriptor from asset %s", pipelineAssetPath);
  101. const AZ::RHI::MultisampleState multiSampleState = AZ::RPI::RPISystemInterface::Get()->GetApplicationMultisampleState();
  102. renderPipelineDesc.value().m_renderSettings.m_multisampleState = multiSampleState;
  103. AZ_Printf("UiRenderer", "UI renderer starting with multi sample %d", multiSampleState.m_samples);
  104. auto renderPipeline = AZ::RPI::RenderPipeline::CreateRenderPipelineForWindow(renderPipelineDesc.value(), *viewportContext->GetWindowContext().get());
  105. atomScene->AddRenderPipeline(renderPipeline);
  106. atomScene->Activate();
  107. // Register the scene
  108. AZ::RPI::RPISystemInterface::Get()->RegisterScene(atomScene);
  109. return atomScene;
  110. }
  111. AZ::RHI::Ptr<AZ::RPI::DynamicDrawContext> UiRenderer::CreateDynamicDrawContext(
  112. AZ::Data::Instance<AZ::RPI::Shader> uiShader)
  113. {
  114. AZ::RHI::Ptr<AZ::RPI::DynamicDrawContext> dynamicDraw = AZ::RPI::DynamicDrawInterface::Get()->CreateDynamicDrawContext();
  115. // Initialize the dynamic draw context
  116. dynamicDraw->InitShader(uiShader);
  117. dynamicDraw->InitVertexFormat(
  118. { { "POSITION", AZ::RHI::Format::R32G32_FLOAT },
  119. { "COLOR", AZ::RHI::Format::B8G8R8A8_UNORM },
  120. { "TEXCOORD", AZ::RHI::Format::R32G32_FLOAT },
  121. { "BLENDINDICES", AZ::RHI::Format::R16G16_UINT } }
  122. );
  123. dynamicDraw->AddDrawStateOptions(AZ::RPI::DynamicDrawContext::DrawStateOptions::StencilState
  124. | AZ::RPI::DynamicDrawContext::DrawStateOptions::BlendMode);
  125. dynamicDraw->SetOutputScope(m_scene);
  126. dynamicDraw->EndInit();
  127. return dynamicDraw;
  128. }
  129. AZStd::shared_ptr<AZ::RPI::ViewportContext> UiRenderer::GetViewportContext()
  130. {
  131. if (!m_viewportContext)
  132. {
  133. // Return the default viewport context
  134. auto viewContextManager = AZ::Interface<AZ::RPI::ViewportContextRequestsInterface>::Get();
  135. auto defaultViewportContext = viewContextManager->GetViewportContextByName(viewContextManager->GetDefaultViewportContextName());
  136. return defaultViewportContext;
  137. }
  138. // Return the user specified viewport context
  139. return m_viewportContext;
  140. }
  141. void UiRenderer::CacheShaderData(const AZ::RHI::Ptr<AZ::RPI::DynamicDrawContext>& dynamicDraw)
  142. {
  143. // Cache draw srg input indices
  144. static const char textureIndexName[] = "m_texture";
  145. static const char worldToProjIndexName[] = "m_worldToProj";
  146. static const char isClampIndexName[] = "m_isClamp";
  147. AZ::Data::Instance<AZ::RPI::ShaderResourceGroup> drawSrg = dynamicDraw->NewDrawSrg();
  148. const AZ::RHI::ShaderResourceGroupLayout* layout = drawSrg->GetLayout();
  149. m_uiShaderData.m_imageInputIndex = layout->FindShaderInputImageIndex(AZ::Name(textureIndexName));
  150. AZ_Error(LogName, m_uiShaderData.m_imageInputIndex.IsValid(), "Failed to find shader input constant %s.",
  151. textureIndexName);
  152. m_uiShaderData.m_viewProjInputIndex = layout->FindShaderInputConstantIndex(AZ::Name(worldToProjIndexName));
  153. AZ_Error(LogName, m_uiShaderData.m_viewProjInputIndex.IsValid(), "Failed to find shader input constant %s.",
  154. worldToProjIndexName);
  155. m_uiShaderData.m_isClampInputIndex = layout->FindShaderInputConstantIndex(AZ::Name(isClampIndexName));
  156. AZ_Error(LogName, m_uiShaderData.m_isClampInputIndex.IsValid(), "Failed to find shader input constant %s.",
  157. isClampIndexName);
  158. // Cache shader variants that will be used
  159. AZ::RPI::ShaderOptionList shaderOptionsTextureLinear;
  160. shaderOptionsTextureLinear.push_back(AZ::RPI::ShaderOption(AZ::Name("o_alphaTest"), AZ::Name("false")));
  161. shaderOptionsTextureLinear.push_back(AZ::RPI::ShaderOption(AZ::Name("o_srgbWrite"), AZ::Name("true")));
  162. shaderOptionsTextureLinear.push_back(AZ::RPI::ShaderOption(AZ::Name("o_modulate"), AZ::Name("Modulate::None")));
  163. m_uiShaderData.m_shaderVariantTextureLinear = dynamicDraw->UseShaderVariant(shaderOptionsTextureLinear);
  164. AZ::RPI::ShaderOptionList shaderOptionsTextureSrgb;
  165. shaderOptionsTextureSrgb.push_back(AZ::RPI::ShaderOption(AZ::Name("o_alphaTest"), AZ::Name("false")));
  166. shaderOptionsTextureSrgb.push_back(AZ::RPI::ShaderOption(AZ::Name("o_srgbWrite"), AZ::Name("false")));
  167. shaderOptionsTextureSrgb.push_back(AZ::RPI::ShaderOption(AZ::Name("o_modulate"), AZ::Name("Modulate::None")));
  168. m_uiShaderData.m_shaderVariantTextureSrgb = dynamicDraw->UseShaderVariant(shaderOptionsTextureSrgb);
  169. AZ::RPI::ShaderOptionList shaderVariantAlphaTestMask;
  170. shaderVariantAlphaTestMask.push_back(AZ::RPI::ShaderOption(AZ::Name("o_alphaTest"), AZ::Name("true")));
  171. shaderVariantAlphaTestMask.push_back(AZ::RPI::ShaderOption(AZ::Name("o_srgbWrite"), AZ::Name("false")));
  172. shaderVariantAlphaTestMask.push_back(AZ::RPI::ShaderOption(AZ::Name("o_modulate"), AZ::Name("Modulate::None")));
  173. m_uiShaderData.m_shaderVariantAlphaTestMask = dynamicDraw->UseShaderVariant(shaderVariantAlphaTestMask);
  174. AZ::RPI::ShaderOptionList shaderVariantGradientMask;
  175. shaderVariantGradientMask.push_back(AZ::RPI::ShaderOption(AZ::Name("o_alphaTest"), AZ::Name("false")));
  176. shaderVariantGradientMask.push_back(AZ::RPI::ShaderOption(AZ::Name("o_srgbWrite"), AZ::Name("false")));
  177. shaderVariantGradientMask.push_back(AZ::RPI::ShaderOption(AZ::Name("o_modulate"), AZ::Name("Modulate::Alpha")));
  178. m_uiShaderData.m_shaderVariantGradientMask = dynamicDraw->UseShaderVariant(shaderVariantGradientMask);
  179. }
  180. ////////////////////////////////////////////////////////////////////////////////////////////////////
  181. void UiRenderer::BeginUiFrameRender()
  182. {
  183. #ifndef _RELEASE
  184. if (m_debugTextureDataRecordLevel > 0)
  185. {
  186. m_texturesUsedInFrame.clear();
  187. }
  188. #endif
  189. }
  190. ////////////////////////////////////////////////////////////////////////////////////////////////////
  191. void UiRenderer::EndUiFrameRender()
  192. {
  193. }
  194. ////////////////////////////////////////////////////////////////////////////////////////////////////
  195. void UiRenderer::BeginCanvasRender()
  196. {
  197. m_stencilRef = 0;
  198. // Set base state
  199. m_baseState.ResetToDefault();
  200. }
  201. ////////////////////////////////////////////////////////////////////////////////////////////////////
  202. void UiRenderer::EndCanvasRender()
  203. {
  204. }
  205. ////////////////////////////////////////////////////////////////////////////////////////////////////
  206. AZ::RHI::Ptr<AZ::RPI::DynamicDrawContext> UiRenderer::GetDynamicDrawContext()
  207. {
  208. return m_dynamicDraw;
  209. }
  210. ////////////////////////////////////////////////////////////////////////////////////////////////////
  211. AZ::RHI::Ptr<AZ::RPI::DynamicDrawContext> UiRenderer::CreateDynamicDrawContextForRTT(const AZStd::string& rttName)
  212. {
  213. // find the rtt pass with the specified name
  214. AZ::RPI::RasterPass* rttPass = nullptr;
  215. AZ::RPI::SceneId sceneId = m_scene->GetId();
  216. LyShinePassRequestBus::EventResult(rttPass, sceneId, &LyShinePassRequestBus::Events::GetRttPass, rttName);
  217. if (!rttPass)
  218. {
  219. return nullptr;
  220. }
  221. AZ::RHI::Ptr<AZ::RPI::DynamicDrawContext> dynamicDraw = AZ::RPI::DynamicDrawInterface::Get()->CreateDynamicDrawContext();
  222. // Initialize the dynamic draw context
  223. dynamicDraw->InitShader(m_dynamicDraw->GetShader());
  224. dynamicDraw->InitVertexFormat(
  225. { { "POSITION", AZ::RHI::Format::R32G32_FLOAT },
  226. { "COLOR", AZ::RHI::Format::B8G8R8A8_UNORM },
  227. { "TEXCOORD", AZ::RHI::Format::R32G32_FLOAT },
  228. { "BLENDINDICES", AZ::RHI::Format::R16G16_UINT } }
  229. );
  230. dynamicDraw->AddDrawStateOptions(AZ::RPI::DynamicDrawContext::DrawStateOptions::StencilState
  231. | AZ::RPI::DynamicDrawContext::DrawStateOptions::BlendMode);
  232. dynamicDraw->SetOutputScope(rttPass);
  233. dynamicDraw->InitDrawListTag(rttPass->GetDrawListTag());
  234. dynamicDraw->EndInit();
  235. return dynamicDraw;
  236. }
  237. ////////////////////////////////////////////////////////////////////////////////////////////////////
  238. const UiRenderer::UiShaderData& UiRenderer::GetUiShaderData()
  239. {
  240. return m_uiShaderData;
  241. }
  242. ////////////////////////////////////////////////////////////////////////////////////////////////////
  243. AZ::Matrix4x4 UiRenderer::GetModelViewProjectionMatrix()
  244. {
  245. auto viewportContext = GetViewportContext();
  246. auto windowContext = viewportContext->GetWindowContext();
  247. const AZ::RHI::Viewport& viewport = windowContext->GetViewport();
  248. const float viewX = viewport.m_minX;
  249. const float viewY = viewport.m_minY;
  250. const float viewWidth = viewport.m_maxX - viewport.m_minX;
  251. const float viewHeight = viewport.m_maxY - viewport.m_minY;
  252. const float zf = viewport.m_minZ;
  253. const float zn = viewport.m_maxZ;
  254. AZ::Matrix4x4 modelViewProjMat;
  255. AZ::MakeOrthographicMatrixRH(modelViewProjMat, viewX, viewX + viewWidth, viewY + viewHeight, viewY, zn, zf);
  256. return modelViewProjMat;
  257. }
  258. ////////////////////////////////////////////////////////////////////////////////////////////////////
  259. AZ::Vector2 UiRenderer::GetViewportSize()
  260. {
  261. auto viewportContext = GetViewportContext();
  262. if (!viewportContext)
  263. {
  264. return AZ::Vector2::CreateZero();
  265. }
  266. auto windowContext = viewportContext->GetWindowContext();
  267. const AZ::RHI::Viewport& viewport = windowContext->GetViewport();
  268. const float viewWidth = viewport.m_maxX - viewport.m_minX;
  269. const float viewHeight = viewport.m_maxY - viewport.m_minY;
  270. return AZ::Vector2(viewWidth, viewHeight);
  271. }
  272. ////////////////////////////////////////////////////////////////////////////////////////////////////
  273. UiRenderer::BaseState UiRenderer::GetBaseState()
  274. {
  275. return m_baseState;
  276. }
  277. ////////////////////////////////////////////////////////////////////////////////////////////////////
  278. void UiRenderer::SetBaseState(BaseState state)
  279. {
  280. m_baseState = state;
  281. }
  282. ////////////////////////////////////////////////////////////////////////////////////////////////////
  283. AZ::RPI::ShaderVariantId UiRenderer::GetCurrentShaderVariant()
  284. {
  285. AZ::RPI::ShaderVariantId variantId = m_uiShaderData.m_shaderVariantTextureLinear;
  286. if (m_baseState.m_useAlphaTest)
  287. {
  288. variantId = m_uiShaderData.m_shaderVariantAlphaTestMask;
  289. }
  290. else if (m_baseState.m_modulateAlpha)
  291. {
  292. variantId = m_uiShaderData.m_shaderVariantGradientMask;
  293. }
  294. else if (!m_baseState.m_useAlphaTest && m_baseState.m_srgbWrite)
  295. {
  296. variantId = m_uiShaderData.m_shaderVariantTextureLinear;
  297. }
  298. else if (!m_baseState.m_useAlphaTest && !m_baseState.m_srgbWrite)
  299. {
  300. variantId = m_uiShaderData.m_shaderVariantTextureSrgb;
  301. }
  302. else
  303. {
  304. AZ_Error(LogName, 0, "Unsupported shader variant.");
  305. }
  306. return variantId;
  307. }
  308. ////////////////////////////////////////////////////////////////////////////////////////////////////
  309. uint32_t UiRenderer::GetStencilRef()
  310. {
  311. return m_stencilRef;
  312. }
  313. ////////////////////////////////////////////////////////////////////////////////////////////////////
  314. void UiRenderer::SetStencilRef(uint32_t stencilRef)
  315. {
  316. m_stencilRef = stencilRef;
  317. }
  318. ////////////////////////////////////////////////////////////////////////////////////////////////////
  319. void UiRenderer::IncrementStencilRef()
  320. {
  321. ++m_stencilRef;
  322. }
  323. ////////////////////////////////////////////////////////////////////////////////////////////////////
  324. void UiRenderer::DecrementStencilRef()
  325. {
  326. --m_stencilRef;
  327. }
  328. #ifndef _RELEASE
  329. ////////////////////////////////////////////////////////////////////////////////////////////////////
  330. void UiRenderer::DebugSetRecordingOptionForTextureData(int recordingOption)
  331. {
  332. m_debugTextureDataRecordLevel = recordingOption;
  333. }
  334. ////////////////////////////////////////////////////////////////////////////////////////////////////
  335. void UiRenderer::DebugDisplayTextureData(int recordingOption)
  336. {
  337. if (recordingOption > 0)
  338. {
  339. // compute the total area of all the textures, also create a vector that we can sort by area
  340. AZStd::vector<AZStd::pair<AZ::Data::Instance<AZ::RPI::Image>, uint32_t>> textures;
  341. int totalArea = 0;
  342. int totalDataSize = 0;
  343. for (AZ::Data::Instance<AZ::RPI::Image> image : m_texturesUsedInFrame)
  344. {
  345. const AZ::RHI::ImageDescriptor& imageDescriptor = image->GetRHIImage()->GetDescriptor();
  346. AZ::RHI::Size size = imageDescriptor.m_size;
  347. int area = size.m_width * size.m_height;
  348. uint32_t dataSize = AZ::RHI::GetFormatSize(imageDescriptor.m_format) * area;
  349. totalArea += area;
  350. totalDataSize += dataSize;
  351. textures.push_back(AZStd::pair<AZ::Data::Instance<AZ::RPI::Image>, uint32_t>(image, dataSize));
  352. }
  353. // sort the vector by data size
  354. std::sort( textures.begin( ), textures.end( ), [ ]( const AZStd::pair<AZ::Data::Instance<AZ::RPI::Image>, uint32_t> lhs, const AZStd::pair<AZ::Data::Instance<AZ::RPI::Image>, uint32_t> rhs )
  355. {
  356. return lhs.second > rhs.second;
  357. });
  358. IDraw2d* draw2d = Draw2dHelper::GetDefaultDraw2d();
  359. // setup to render lines of text for the debug display
  360. float dpiScale = GetViewportContext()->GetDpiScalingFactor();
  361. float xOffset = 20.0f * dpiScale;
  362. float yOffset = 20.0f * dpiScale;
  363. auto blackTexture = AZ::RPI::ImageSystemInterface::Get()->GetSystemImage(AZ::RPI::SystemImage::Black);
  364. float textOpacity = 1.0f;
  365. float backgroundRectOpacity = 0.0f; // 0.75f; // [GHI #6515] Reenable background rect
  366. const float fontSize = 8.0f;
  367. const float lineSpacing = 20.0f * dpiScale;
  368. const AZ::Vector3 white(1,1,1);
  369. const AZ::Vector3 red(1,0.3f,0.3f);
  370. const AZ::Vector3 blue(0.3f,0.3f,1);
  371. int xDim, yDim;
  372. if (totalArea > 2048 * 2048)
  373. {
  374. xDim = 4096;
  375. yDim = totalArea / 4096;
  376. }
  377. else
  378. {
  379. xDim = 2048;
  380. yDim = totalArea / 2048;
  381. }
  382. float totalDataSizeMB = static_cast<float>(totalDataSize) / (1024.0f * 1024.0f);
  383. // local function to write a line of text (with a background rect) and increment Y offset
  384. AZStd::function<void(const char*, const AZ::Vector3&)> WriteLine = [&](const char* buffer, const AZ::Vector3& color)
  385. {
  386. IDraw2d::TextOptions textOptions = draw2d->GetDefaultTextOptions();
  387. textOptions.color = color;
  388. AZ::Vector2 textSize = draw2d->GetTextSize(buffer, fontSize, &textOptions);
  389. AZ::Vector2 rectTopLeft = AZ::Vector2(xOffset - 2, yOffset);
  390. AZ::Vector2 rectSize = AZ::Vector2(textSize.GetX() + 4, lineSpacing);
  391. draw2d->DrawImage(blackTexture, rectTopLeft, rectSize, backgroundRectOpacity);
  392. draw2d->DrawText(buffer, AZ::Vector2(xOffset, yOffset), fontSize, textOpacity, &textOptions);
  393. yOffset += lineSpacing;
  394. };
  395. size_t numTexturesUsedInFrame = m_texturesUsedInFrame.size();
  396. char buffer[200];
  397. sprintf_s(buffer, "There are %zu unique UI textures rendered in this frame, the total texture area is %d (%d x %d), total data size is %d (%.2f MB)",
  398. numTexturesUsedInFrame, totalArea, xDim, yDim, totalDataSize, totalDataSizeMB);
  399. WriteLine(buffer, white);
  400. sprintf_s(buffer, "Dimensions Data Size Format Texture name");
  401. WriteLine(buffer, blue);
  402. for (auto texture : textures)
  403. {
  404. AZ::Data::Instance<AZ::RPI::Image> image = texture.first;
  405. const AZ::RHI::ImageDescriptor& imageDescriptor = image->GetRHIImage()->GetDescriptor();
  406. uint32_t width = imageDescriptor.m_size.m_width;
  407. uint32_t height = imageDescriptor.m_size.m_height;
  408. uint32_t dataSize = texture.second;
  409. const char* displayName = "Unnamed Texture";
  410. AZStd::string imagePath;
  411. // Check if the image has been assigned a name (ex. if it's an attachment image or a cpu generated image)
  412. const AZ::Name& imageName = image->GetRHIImage()->GetName();
  413. if (!imageName.IsEmpty())
  414. {
  415. displayName = imageName.GetCStr();
  416. }
  417. else
  418. {
  419. // Use the image's asset path as the display name
  420. AZ::Data::AssetCatalogRequestBus::BroadcastResult(imagePath,
  421. &AZ::Data::AssetCatalogRequests::GetAssetPathById, image->GetAssetId());
  422. if (!imagePath.empty())
  423. {
  424. displayName = imagePath.c_str();
  425. }
  426. }
  427. sprintf_s(buffer, "%4u x %4u, %9u %19s %s",
  428. width, height, dataSize, AZ::RHI::ToString(imageDescriptor.m_format), displayName);
  429. WriteLine(buffer, white);
  430. }
  431. }
  432. }
  433. void UiRenderer::DebugUseTexture(AZ::Data::Instance<AZ::RPI::Image> image)
  434. {
  435. if (m_debugTextureDataRecordLevel > 0)
  436. {
  437. m_texturesUsedInFrame.insert(image);
  438. }
  439. }
  440. #endif