DebugView.qml 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549
  1. // Copyright (C) 2023 The Qt Company Ltd.
  2. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
  3. import QtQuick
  4. import QtQuick.Controls
  5. import QtQuick.Layouts
  6. import QtQuick3D
  7. import QtQuick3D.Helpers.impl
  8. Pane {
  9. id: root
  10. property var source: null
  11. property bool resourceDetailsVisible: false
  12. opacity: 0.9
  13. ColumnLayout {
  14. id: layout
  15. RowLayout {
  16. Label {
  17. Layout.fillWidth: true
  18. text: root.source.renderStats.fps + " FPS"
  19. font.pointSize: 14
  20. }
  21. Label {
  22. text: "Details"
  23. }
  24. CheckBox {
  25. checked: root.resourceDetailsVisible
  26. onCheckedChanged: {
  27. resourceDetailsVisible = checked;
  28. }
  29. }
  30. }
  31. component TimeLabel : RowLayout {
  32. id: timeLabel
  33. property alias text: label.text
  34. property real value: 0.0
  35. Label {
  36. id: label
  37. Layout.fillWidth: true
  38. text: "Frame: "
  39. }
  40. Label {
  41. text: timeLabel.value.toFixed(3) + "ms"
  42. }
  43. }
  44. TimeLabel {
  45. text: "Frame: "
  46. value: root.source.renderStats.frameTime
  47. }
  48. TimeLabel {
  49. text: " Sync: "
  50. value: root.source.renderStats.syncTime
  51. }
  52. TimeLabel {
  53. text: " Prep: "
  54. value: root.source.renderStats.renderPrepareTime
  55. }
  56. TimeLabel {
  57. text: " Render: "
  58. value: root.source.renderStats.renderTime
  59. }
  60. TimeLabel {
  61. text: "Max: "
  62. value: root.source.renderStats.maxFrameTime
  63. }
  64. TimeLabel {
  65. text: "GPU: "
  66. value: root.source.renderStats.lastCompletedGpuTime
  67. visible: root.source.renderStats.lastCompletedGpuTime > 0
  68. }
  69. Page {
  70. Layout.fillWidth: true
  71. Layout.minimumWidth: 530
  72. visible: root.resourceDetailsVisible
  73. header: TabBar {
  74. id: tabBar
  75. TabButton {
  76. text: "Summary"
  77. }
  78. TabButton {
  79. text: "Passes"
  80. }
  81. TabButton {
  82. text: "Textures"
  83. }
  84. TabButton {
  85. text: "Meshes"
  86. }
  87. TabButton {
  88. text: "Tools"
  89. }
  90. TabButton {
  91. text: "Shadows"
  92. }
  93. }
  94. StackLayout {
  95. anchors.fill: parent
  96. anchors.margins: 10
  97. currentIndex: tabBar.currentIndex
  98. Pane {
  99. id: summaryPane
  100. ColumnLayout {
  101. Label {
  102. text: "Graphics API: " + root.source.renderStats.graphicsApiName
  103. visible: root.resourceDetailsVisible
  104. }
  105. Label {
  106. text: root.source.renderStats.renderPassCount + " render passes"
  107. visible: root.resourceDetailsVisible
  108. }
  109. Label {
  110. text: root.source.renderStats.drawCallCount + " draw calls"
  111. visible: root.resourceDetailsVisible
  112. }
  113. Label {
  114. text: root.source.renderStats.drawVertexCount + " vertices"
  115. visible: root.resourceDetailsVisible
  116. }
  117. Label {
  118. text: "Image assets: " + (root.source.renderStats.imageDataSize / 1024).toFixed(2) + " KB"
  119. visible: root.resourceDetailsVisible
  120. }
  121. Label {
  122. text: "Mesh assets: " + (root.source.renderStats.meshDataSize / 1024).toFixed(2) + " KB"
  123. visible: root.resourceDetailsVisible
  124. }
  125. Label {
  126. text: "Pipelines: " + root.source.renderStats.pipelineCount
  127. visible: root.resourceDetailsVisible
  128. }
  129. Label {
  130. text: "Material build time: " + root.source.renderStats.materialGenerationTime + " ms"
  131. visible: root.resourceDetailsVisible
  132. }
  133. Label {
  134. text: "Effect build time: " + root.source.renderStats.effectGenerationTime + " ms"
  135. visible: root.resourceDetailsVisible
  136. }
  137. Label {
  138. text: "Pipeline build time: " + root.source.renderStats.pipelineCreationTime + " ms"
  139. visible: root.resourceDetailsVisible
  140. }
  141. Label {
  142. text: root.source.renderStats.vmemAllocCount + " vmem allocs with " + root.source.renderStats.vmemUsedBytes + " bytes"
  143. visible: root.resourceDetailsVisible && root.source.renderStats.vmemAllocCount > 0
  144. }
  145. }
  146. }
  147. Pane {
  148. id: passesPane
  149. RenderStatsPassesModel {
  150. id: passesModel
  151. passData: root.source.renderStats.renderPassDetails
  152. }
  153. ColumnLayout {
  154. anchors.fill: parent
  155. spacing: 0
  156. HorizontalHeaderView {
  157. syncView: passesTableView
  158. resizableColumns: false // otherwise QTBUG-111013 happens
  159. boundsBehavior: Flickable.StopAtBounds
  160. flickableDirection: Flickable.VerticalFlick
  161. }
  162. ListModel {
  163. id: passesHeaderModel
  164. ListElement {
  165. columnWidth: 300 // name
  166. }
  167. ListElement {
  168. columnWidth: 80 // size
  169. }
  170. ListElement {
  171. columnWidth: 60 // vertices
  172. }
  173. ListElement {
  174. columnWidth: 60 // draw calls
  175. }
  176. }
  177. Item {
  178. Layout.fillHeight: true
  179. Layout.fillWidth: true
  180. TableView {
  181. id: passesTableView
  182. anchors.fill: parent
  183. // name, size, vertices, draw calls
  184. property var columnFactors: [58, 14, 12, 12]; // == 96, leave space for the scrollbar
  185. columnWidthProvider: function (column) {
  186. return passesPane.width * (columnFactors[column] / 100.0);
  187. }
  188. boundsBehavior: Flickable.StopAtBounds
  189. flickableDirection: Flickable.VerticalFlick
  190. ScrollBar.vertical: ScrollBar {
  191. parent: passesTableView.parent
  192. anchors.top: passesTableView.top
  193. anchors.bottom: passesTableView.bottom
  194. anchors.left: passesTableView.right
  195. }
  196. clip: true
  197. model: passesModel
  198. columnSpacing: 1
  199. rowSpacing: 1
  200. implicitWidth: parent.width + columnSpacing
  201. implicitHeight: parent.height + rowSpacing
  202. delegate: CustomTableItemDelegate {
  203. required property string display
  204. text: display
  205. color: TableView.view.palette.base
  206. textColor: TableView.view.palette.text
  207. }
  208. }
  209. }
  210. }
  211. }
  212. Pane {
  213. id: texturesPane
  214. RenderStatsTexturesModel {
  215. id: texturesModel
  216. textureData: root.source.renderStats.textureDetails
  217. }
  218. ColumnLayout {
  219. anchors.fill: parent
  220. spacing: 0
  221. HorizontalHeaderView {
  222. syncView: texturesTableView
  223. resizableColumns: false // otherwise QTBUG-111013 happens
  224. boundsBehavior: Flickable.StopAtBounds
  225. flickableDirection: Flickable.VerticalFlick
  226. }
  227. Item {
  228. Layout.fillHeight: true
  229. Layout.fillWidth: true
  230. TableView {
  231. id: texturesTableView
  232. anchors.fill: parent
  233. // name, size, format, miplevels, flags
  234. property var columnFactors: [48, 12, 12, 12, 12]; // == 96, leave space for the scrollbar
  235. columnWidthProvider: function (column) {
  236. return texturesPane.width * (columnFactors[column] / 100.0);
  237. }
  238. boundsBehavior: Flickable.StopAtBounds
  239. flickableDirection: Flickable.VerticalFlick
  240. ScrollBar.vertical: ScrollBar {
  241. parent: texturesTableView.parent
  242. anchors.top: texturesTableView.top
  243. anchors.bottom: texturesTableView.bottom
  244. anchors.left: texturesTableView.right
  245. }
  246. ScrollBar.horizontal: ScrollBar { }
  247. clip: true
  248. model: texturesModel
  249. columnSpacing: 1
  250. rowSpacing: 1
  251. implicitWidth: parent.width + columnSpacing
  252. implicitHeight: parent.height + rowSpacing
  253. delegate: CustomTableItemDelegate {
  254. required property string display
  255. text: display
  256. color: TableView.view.palette.base
  257. textColor: TableView.view.palette.text
  258. }
  259. }
  260. }
  261. }
  262. }
  263. Pane {
  264. id: meshesPane
  265. RenderStatsMeshesModel {
  266. id: meshesModel
  267. meshData: root.source.renderStats.meshDetails
  268. }
  269. ColumnLayout {
  270. anchors.fill: parent
  271. spacing: 0
  272. HorizontalHeaderView {
  273. syncView: meshesTableView
  274. resizableColumns: false // otherwise QTBUG-111013 happens
  275. boundsBehavior: Flickable.StopAtBounds
  276. flickableDirection: Flickable.VerticalFlick
  277. }
  278. Item {
  279. Layout.fillHeight: true
  280. Layout.fillWidth: true
  281. TableView {
  282. id: meshesTableView
  283. anchors.fill: parent
  284. // name, submeshes, vertices, vbufsize, ibufsize
  285. property var columnFactors: [48, 12, 12, 12, 12]; // == 96, leave space for the scrollbar
  286. columnWidthProvider: function (column) {
  287. return meshesPane.width * (columnFactors[column] / 100.0);
  288. }
  289. boundsBehavior: Flickable.StopAtBounds
  290. flickableDirection: Flickable.VerticalFlick
  291. ScrollBar.vertical: ScrollBar {
  292. parent: meshesTableView.parent
  293. anchors.top: meshesTableView.top
  294. anchors.bottom: meshesTableView.bottom
  295. anchors.left: meshesTableView.right
  296. }
  297. clip: true
  298. model: meshesModel
  299. columnSpacing: 1
  300. rowSpacing: 1
  301. implicitWidth: parent.width + columnSpacing
  302. implicitHeight: parent.height + rowSpacing
  303. delegate: CustomTableItemDelegate {
  304. required property string display
  305. text: display
  306. color: TableView.view.palette.base
  307. textColor: TableView.view.palette.text
  308. }
  309. }
  310. }
  311. }
  312. }
  313. Pane {
  314. id: visualizePane
  315. ColumnLayout {
  316. id: visCtrCol
  317. width: parent.width
  318. CheckBox {
  319. text: "Wireframe mode"
  320. onCheckedChanged: root.source.environment.debugSettings.wireframeEnabled = checked
  321. }
  322. RowLayout {
  323. Label {
  324. text: "Material override"
  325. }
  326. ComboBox {
  327. id: materialOverrideComboBox
  328. textRole: "text"
  329. valueRole: "value"
  330. implicitContentWidthPolicy: ComboBox.WidestText
  331. onActivated: root.source.environment.debugSettings.materialOverride = currentValue
  332. Component.onCompleted: materialOverrideComboBox.currentIndex = materialOverrideComboBox.indexOfValue(root.source.environment.debugSettings.materialOverride)
  333. model: [
  334. { value: DebugSettings.None, text: "None"},
  335. { value: DebugSettings.BaseColor, text: "Base Color"},
  336. { value: DebugSettings.Roughness, text: "Roughness"},
  337. { value: DebugSettings.Metalness, text: "Metalness"},
  338. { value: DebugSettings.Diffuse, text: "Diffuse"},
  339. { value: DebugSettings.Specular, text: "Specular"},
  340. { value: DebugSettings.ShadowOcclusion, text: "Shadow Occlusion"},
  341. { value: DebugSettings.Emission, text: "Emission"},
  342. { value: DebugSettings.AmbientOcclusion, text: "Ambient Occlusion"},
  343. { value: DebugSettings.Normals, text: "Normals"},
  344. { value: DebugSettings.Tangents, text: "Tangents"},
  345. { value: DebugSettings.Binormals, text: "Binormals"},
  346. { value: DebugSettings.F0, text: "F0"}
  347. ]
  348. }
  349. }
  350. RowLayout {
  351. spacing: 20
  352. Button {
  353. text: "Release cached resources"
  354. onClicked: root.source.renderStats.releaseCachedResources()
  355. }
  356. Button {
  357. text: "Bake lightmap"
  358. onClicked: root.source.bakeLightmap()
  359. }
  360. Button {
  361. text: "Denoise lightmap"
  362. onClicked: root.source.denoiseLightmap()
  363. }
  364. }
  365. RowLayout {
  366. Label {
  367. text: "Render mode override"
  368. }
  369. ComboBox {
  370. id: renderModeOverrideComboBox
  371. textRole: "text"
  372. valueRole: "value"
  373. implicitContentWidthPolicy: ComboBox.WidestText
  374. onActivated: root.source.renderMode = currentValue
  375. Component.onCompleted: renderModeOverrideComboBox.currentIndex = renderModeOverrideComboBox.indexOfValue(root.source.renderMode)
  376. model: [
  377. { value: View3D.Offscreen, text: "Offscreen" },
  378. { value: View3D.Underlay, text: "Underlay" },
  379. { value: View3D.Overlay, text: "Overlay" },
  380. { value: View3D.Inline, text: "Inline" }
  381. ]
  382. }
  383. }
  384. Label {
  385. text: "View3D logical size is " + root.source.width + "x" + root.source.height
  386. }
  387. Label {
  388. text: "Backing texture pixel size is " + root.source.effectiveTextureSize.width + "x" + root.source.effectiveTextureSize.height
  389. visible: root.source.renderMode === View3D.Offscreen
  390. }
  391. RowLayout {
  392. CheckBox {
  393. id: explicitTextureSizeCheckBox
  394. visible: root.source.renderMode === View3D.Offscreen
  395. text: "Explicit backing texture size"
  396. property real aspectRatio: root.source.width / root.source.height
  397. onCheckedChanged: updateSize()
  398. function updateSize() {
  399. if (!explicitTextureSizeCheckBox.checked) {
  400. root.source.explicitTextureWidth = 0;
  401. root.source.explicitTextureHeight = 0;
  402. return;
  403. }
  404. var newWidth = explicitWidthSlider.value;
  405. var newHeight = explicitHeightSlider.value;
  406. if (keepAspectRatioCheckBox.checked) {
  407. var aspectRatio = explicitTextureSizeCheckBox.aspectRatio;
  408. if (newHeight * aspectRatio <= newWidth)
  409. newWidth = newHeight * aspectRatio;
  410. else
  411. newHeight = newWidth * (1.0 / aspectRatio);
  412. }
  413. root.source.explicitTextureWidth = newWidth;
  414. root.source.explicitTextureHeight = newHeight;
  415. }
  416. Connections {
  417. target: root.source
  418. function onWidthChanged() { explicitTextureSizeCheckBox.updateSize() }
  419. function onHeightChanged() { explicitTextureSizeCheckBox.updateSize() }
  420. }
  421. }
  422. CheckBox {
  423. id: keepAspectRatioCheckBox
  424. visible: root.source.renderMode === View3D.Offscreen && explicitTextureSizeCheckBox.checked
  425. text: "Keep aspect ratio (" + explicitTextureSizeCheckBox.aspectRatio.toFixed(2) + ")"
  426. checked: false
  427. onCheckedChanged: explicitTextureSizeCheckBox.updateSize()
  428. }
  429. }
  430. RowLayout {
  431. visible: root.source.renderMode === View3D.Offscreen && explicitTextureSizeCheckBox.checked
  432. Label {
  433. text: "Width: " + explicitWidthSlider.value.toFixed(0) + " px"
  434. }
  435. Slider {
  436. id: explicitWidthSlider
  437. from: 16
  438. to: 4096
  439. value: 1280
  440. onValueChanged: explicitTextureSizeCheckBox.updateSize()
  441. Layout.maximumWidth: 120
  442. }
  443. Label {
  444. text: "Height: " + explicitHeightSlider.value.toFixed(0) + " px"
  445. }
  446. Slider {
  447. id: explicitHeightSlider
  448. from: 16
  449. to: 4096
  450. value: 720
  451. onValueChanged: explicitTextureSizeCheckBox.updateSize()
  452. Layout.maximumWidth: 120
  453. }
  454. }
  455. }
  456. }
  457. Pane {
  458. id: shadowsPane
  459. ColumnLayout {
  460. width: parent.width
  461. CheckBox {
  462. text: "Draw directional light shadow bounding boxes"
  463. checked: root.source.environment.debugSettings.drawDirectionalLightShadowBoxes
  464. onCheckedChanged: root.source.environment.debugSettings.drawDirectionalLightShadowBoxes = checked
  465. }
  466. CheckBox {
  467. text: "Draw point light shadow bounding boxes"
  468. checked: root.source.environment.debugSettings.drawPointLightShadowBoxes
  469. onCheckedChanged: root.source.environment.debugSettings.drawPointLightShadowBoxes = checked
  470. }
  471. CheckBox {
  472. text: "Draw shadow casting bounding box"
  473. checked: root.source.environment.debugSettings.drawShadowCastingBounds
  474. onCheckedChanged: root.source.environment.debugSettings.drawShadowCastingBounds = checked
  475. }
  476. CheckBox {
  477. text: "Draw shadow receiving bounding box"
  478. checked: root.source.environment.debugSettings.drawShadowReceivingBounds
  479. onCheckedChanged: root.source.environment.debugSettings.drawShadowReceivingBounds = checked
  480. }
  481. CheckBox {
  482. text: "Draw cascades"
  483. checked: root.source.environment.debugSettings.drawCascades
  484. onCheckedChanged: root.source.environment.debugSettings.drawCascades = checked
  485. }
  486. CheckBox {
  487. text: "Draw scene cascade intersection"
  488. checked: root.source.environment.debugSettings.drawSceneCascadeIntersection
  489. onCheckedChanged: root.source.environment.debugSettings.drawSceneCascadeIntersection = checked
  490. }
  491. CheckBox {
  492. text: "Disable Shadow Camera Update"
  493. checked: root.source.environment.debugSettings.disableShadowCameraUpdate
  494. onCheckedChanged: root.source.environment.debugSettings.disableShadowCameraUpdate = checked
  495. }
  496. }
  497. }
  498. }
  499. }
  500. }
  501. component CustomTableItemDelegate : Rectangle {
  502. property alias text: textLabel.text
  503. property alias textColor: textLabel.color
  504. implicitWidth: 100
  505. implicitHeight: textLabel.implicitHeight + 4
  506. color: palette.base
  507. Label {
  508. id: textLabel
  509. anchors.centerIn: parent
  510. color: palette.text
  511. }
  512. }
  513. function syncVisible() {
  514. if (source) {
  515. source.renderStats.extendedDataCollectionEnabled = visible && resourceDetailsVisible;
  516. if (source.renderStats.extendedDataCollectionEnabled)
  517. source.update();
  518. }
  519. }
  520. Component.onCompleted: syncVisible()
  521. onSourceChanged: syncVisible()
  522. onVisibleChanged: syncVisible()
  523. onResourceDetailsVisibleChanged: syncVisible()
  524. }