3
0

ShaderManagementConsoleWindow.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  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/RPI.Edit/Shader/ShaderSourceData.h>
  9. #include <Atom/RPI.Edit/Shader/ShaderVariantListSourceData.h>
  10. #include <Atom/RPI.Edit/Common/AssetUtils.h>
  11. #include <Atom/RPI.Reflect/Shader/ShaderAsset.h>
  12. #include <AtomToolsFramework/Document/AtomToolsDocumentRequestBus.h>
  13. #include <AtomToolsFramework/Document/AtomToolsDocumentSystemRequestBus.h>
  14. #include <AzToolsFramework/API/EditorAssetSystemAPI.h>
  15. #include <AzToolsFramework/UI/UICore/WidgetHelpers.h>
  16. #include <AzCore/Utils/Utils.h>
  17. #include <Data/ShaderVariantStatisticData.h>
  18. #include <Document/ShaderManagementConsoleDocumentRequestBus.h>
  19. #include <Window/ShaderManagementConsoleWindow.h>
  20. #include <Window/ShaderManagementConsoleStatisticView.h>
  21. #include <ShaderManagementConsoleRequestBus.h>
  22. #include <QFileDialog>
  23. #include <QMenu>
  24. #include <QProgressDialog>
  25. #include <QUrl>
  26. #include <QWindow>
  27. #include <QMessageBox>
  28. #include <QMenuBar>
  29. namespace ShaderManagementConsole
  30. {
  31. ShaderManagementConsoleWindow::ShaderManagementConsoleWindow(const AZ::Crc32& toolId, QWidget* parent)
  32. : Base(toolId, "ShaderManagementConsoleWindow", parent)
  33. {
  34. m_assetBrowser->GetSearchWidget()->ClearTypeFilter();
  35. m_assetBrowser->GetSearchWidget()->SetTypeFilterVisible(false);
  36. m_assetBrowser->SetFileTypeFilters({
  37. { "Material", { "material" }, true },
  38. { "Material Type", { "materialtype" }, true },
  39. { "Shader", { "shader" }, true },
  40. { "Shader Template", { "shader.template" }, true },
  41. { "Shader Variant List", { "shadervariantlist" }, true },
  42. { "AZSL", { "azsl", "azsli", "srgi" }, true },
  43. });
  44. m_documentInspector = new AtomToolsFramework::AtomToolsDocumentInspector(m_toolId, this);
  45. m_documentInspector->SetDocumentSettingsPrefix("/O3DE/Atom/ShaderManagementConsole/DocumentInspector");
  46. AddDockWidget("Inspector", m_documentInspector, Qt::RightDockWidgetArea);
  47. SetDockWidgetVisible("Inspector", false);
  48. OnDocumentOpened(AZ::Uuid::CreateNull());
  49. this->setContextMenuPolicy(Qt::CustomContextMenu);
  50. this->connect(this, &QTableWidget::customContextMenuRequested, this, &ShaderManagementConsoleWindow::ShowContextMenu);
  51. }
  52. void ShaderManagementConsoleWindow::ShowContextMenu(const QPoint& pos)
  53. {
  54. QMenu contextMenu(tr("Context menu"), this);
  55. UpdateRecentFileMenu();
  56. contextMenu.insertMenu(0, m_menuOpenRecent);
  57. contextMenu.exec(mapToGlobal(pos));
  58. }
  59. void ShaderManagementConsoleWindow::OnDocumentOpened(const AZ::Uuid& documentId)
  60. {
  61. Base::OnDocumentOpened(documentId);
  62. m_documentInspector->SetDocumentId(documentId);
  63. }
  64. AZStd::string ShaderManagementConsoleWindow::GetSaveDocumentParams(const AZStd::string& initialPath, const AZ::Uuid& documentId) const
  65. {
  66. // Get shader file path
  67. AZ::IO::Path shaderFullPath;
  68. AZ::RPI::ShaderVariantListSourceData shaderVariantList{};
  69. ShaderManagementConsoleDocumentRequestBus::EventResult(
  70. shaderVariantList,
  71. documentId,
  72. &ShaderManagementConsoleDocumentRequestBus::Events::GetShaderVariantListSourceData);
  73. shaderFullPath = AZ::RPI::AssetUtils::ResolvePathReference(initialPath, shaderVariantList.m_shaderFilePath);
  74. QMessageBox msgBox;
  75. msgBox.setText("Where do you want to save the list?");
  76. QPushButton* projectBtn = msgBox.addButton(QObject::tr("Save to project"), QMessageBox::ActionRole);
  77. QPushButton* engineBtn = msgBox.addButton(QObject::tr("Save to engine"), QMessageBox::ActionRole);
  78. msgBox.addButton(QObject::tr("Cancel"), QMessageBox::RejectRole);
  79. msgBox.exec();
  80. AZ::IO::Path result;
  81. if (msgBox.clickedButton() == projectBtn)
  82. {
  83. AZ::IO::FixedMaxPath projectPath = AZ::Utils::GetProjectPath();
  84. AZ::IO::Path relativePath, rootFolder;
  85. bool pathFound = false;
  86. AzToolsFramework::AssetSystemRequestBus::BroadcastResult(
  87. pathFound,
  88. &AzToolsFramework::AssetSystemRequestBus::Events::GenerateRelativeSourcePath,
  89. shaderFullPath.Native(),
  90. relativePath.Native(),
  91. rootFolder.Native());
  92. if (pathFound)
  93. {
  94. relativePath.ReplaceExtension("shadervariantlist");
  95. projectPath /= AZ::IO::Path ("ShaderVariants") / relativePath;
  96. result = projectPath.LexicallyNormal();
  97. }
  98. else
  99. {
  100. AZ_Error("ShaderManagementConsoleWindow", false, "Can not find a relative path from the shader: '%s'.", shaderFullPath.c_str());
  101. }
  102. }
  103. else if(msgBox.clickedButton() == engineBtn)
  104. {
  105. shaderFullPath.ReplaceExtension("shadervariantlist");
  106. result = shaderFullPath;
  107. }
  108. return result.Native();
  109. }
  110. void ShaderManagementConsoleWindow::ErrorMessageBoxesForDocumentVerification(const DocumentVerificationResult& verification)
  111. {
  112. if (verification.m_hasRedundantVariants)
  113. {
  114. QMessageBox::critical(
  115. this, tr("QC fail"), tr("Some variants are redundant. Use the recompaction feature before saving."), QMessageBox::Ok);
  116. }
  117. if (verification.m_hasRootLike)
  118. {
  119. QMessageBox::critical(
  120. this,
  121. tr("QC fail"),
  122. tr("Variant with id %1 is root-like (all options dynamic). Remove it or use recompaction feature before saving.")
  123. .arg(verification.m_rootLikeStableId),
  124. QMessageBox::Ok);
  125. }
  126. if (verification.m_hasStableIdJump)
  127. {
  128. QMessageBox::critical(
  129. this,
  130. tr("QC fail"),
  131. tr("Stable id %1 isn't compact. Use the recompaction feature before saving.").arg(verification.faultyId),
  132. QMessageBox::Ok);
  133. }
  134. }
  135. void ShaderManagementConsoleWindow::CreateMenus(QMenuBar* menuBar)
  136. {
  137. Base::CreateMenus(menuBar);
  138. QAction* verifyAction = new QAction(tr("Verify Variantlist invariants"), m_menuFile);
  139. QObject::connect(verifyAction, &QAction::triggered, this, [this](){
  140. DocumentVerificationResult verification;
  141. ShaderManagementConsoleDocumentRequestBus::EventResult(
  142. verification, GetCurrentDocumentId(), &ShaderManagementConsoleDocumentRequestBus::Events::Verify);
  143. ErrorMessageBoxesForDocumentVerification(verification);
  144. if (verification.AllGood())
  145. {
  146. QMessageBox::information(
  147. this, tr("QC pass"), tr("All good"), QMessageBox::Ok);
  148. }
  149. });
  150. m_menuFile->insertAction(m_menuFile->actions().back(), verifyAction);
  151. QAction* compactAction = new QAction(tr("Run Compaction"), m_menuFile);
  152. QObject::connect(
  153. verifyAction,
  154. &QAction::triggered,
  155. this,
  156. [this]()
  157. {
  158. AtomToolsFramework::AtomToolsDocumentRequestBus::Event(
  159. GetCurrentDocumentId(), &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::BeginEdit);
  160. ShaderManagementConsoleDocumentRequestBus::Event(
  161. GetCurrentDocumentId(), &ShaderManagementConsoleDocumentRequestBus::Events::DefragmentVariantList);
  162. AtomToolsFramework::AtomToolsDocumentRequestBus::Event(
  163. GetCurrentDocumentId(), &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::EndEdit);
  164. });
  165. m_menuFile->insertAction(m_menuFile->actions().back(), compactAction);
  166. // Add statistics button
  167. QAction* action = new QAction(tr("Generate Shader Variant Statistics..."), m_menuFile);
  168. QObject::connect(action, &QAction::triggered, this, &ShaderManagementConsoleWindow::GenerateStatisticView);
  169. m_menuFile->insertAction(m_menuFile->actions().back(), action);
  170. }
  171. void ShaderManagementConsoleWindow::GenerateStatisticView()
  172. {
  173. AZStd::vector<AZ::Data::AssetId> materialAssetIdList;
  174. ShaderManagementConsoleRequestBus::BroadcastResult(
  175. materialAssetIdList, &ShaderManagementConsoleRequestBus::Events::GetAllMaterialAssetIds);
  176. QProgressDialog progressDialog(AzToolsFramework::GetActiveWindow());
  177. progressDialog.setWindowModality(Qt::WindowModal);
  178. progressDialog.setMaximum(static_cast<int>(materialAssetIdList.size()));
  179. progressDialog.setMaximumWidth(400);
  180. progressDialog.setMaximumHeight(100);
  181. progressDialog.setWindowTitle(tr("Gather information from material assets"));
  182. progressDialog.setLabelText(tr("Gather shader variant information..."));
  183. ShaderVariantStatisticData statisticData;
  184. for (int i = 0; i < materialAssetIdList.size(); ++i)
  185. {
  186. AZStd::vector<AZ::RPI::ShaderCollection::Item> shaderItemList;
  187. ShaderManagementConsoleRequestBus::BroadcastResult(
  188. shaderItemList, &ShaderManagementConsoleRequestBus::Events::GetMaterialInstanceShaderItems, materialAssetIdList[i]);
  189. for (auto& shaderItem : shaderItemList)
  190. {
  191. AZ::RPI::ShaderVariantId shaderVariantId = shaderItem.GetShaderVariantId();
  192. if (!shaderVariantId.IsEmpty())
  193. {
  194. if (statisticData.m_shaderVariantUsage.find(shaderVariantId) == statisticData.m_shaderVariantUsage.end())
  195. {
  196. // Variant not found
  197. statisticData.m_shaderVariantUsage[shaderVariantId].m_count = 1;
  198. }
  199. else
  200. {
  201. statisticData.m_shaderVariantUsage[shaderVariantId].m_count += 1;
  202. }
  203. AZ::RPI::ShaderOptionGroup shaderOptionGroup = shaderItem.GetShaderOptionGroup();
  204. statisticData.m_shaderVariantUsage[shaderVariantId].m_shaderOptionGroup = shaderOptionGroup;
  205. for (auto& shaderOptionDescriptor : shaderOptionGroup.GetShaderOptionDescriptors())
  206. {
  207. AZ::Name optionName = shaderOptionDescriptor.GetName();
  208. AZ::RPI::ShaderOptionValue optionValue = shaderOptionGroup.GetValue(optionName);
  209. if (!optionValue.IsValid())
  210. {
  211. continue;
  212. }
  213. AZ::Name valueName = shaderOptionDescriptor.GetValueName(optionValue);
  214. if (statisticData.m_shaderOptionUsage.find(optionName) == statisticData.m_shaderOptionUsage.end())
  215. {
  216. // Option Not found
  217. statisticData.m_shaderOptionUsage[optionName][valueName] = 1;
  218. }
  219. else
  220. {
  221. if (statisticData.m_shaderOptionUsage[optionName].find(valueName) ==
  222. statisticData.m_shaderOptionUsage[optionName].end())
  223. {
  224. // Value not found
  225. statisticData.m_shaderOptionUsage[optionName][valueName] = 1;
  226. }
  227. else
  228. {
  229. statisticData.m_shaderOptionUsage[optionName][valueName] += 1;
  230. }
  231. }
  232. }
  233. }
  234. }
  235. progressDialog.setValue(i);
  236. if (progressDialog.wasCanceled())
  237. {
  238. return;
  239. }
  240. }
  241. progressDialog.close();
  242. if (m_statisticView)
  243. {
  244. delete m_statisticView;
  245. m_statisticView = nullptr;
  246. }
  247. m_statisticView = new ShaderManagementConsoleStatisticView(statisticData, nullptr);
  248. m_statisticView->setWindowTitle(tr("Shader Variant Statistic View"));
  249. m_statisticView->show();
  250. }
  251. void ShaderManagementConsoleWindow::closeEvent(QCloseEvent* closeEvent)
  252. {
  253. if (m_statisticView)
  254. {
  255. m_statisticView->close();
  256. delete m_statisticView;
  257. m_statisticView = nullptr;
  258. }
  259. Base::closeEvent(closeEvent);
  260. }
  261. } // namespace ShaderManagementConsole
  262. #include <Window/moc_ShaderManagementConsoleWindow.cpp>