Initial commit

This commit is contained in:
2026-04-29 07:19:21 +03:00
commit 9a8cdfa08a
5964 changed files with 1194660 additions and 0 deletions
@@ -0,0 +1,554 @@
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import QtQuick3D
import QtQuick3D.Helpers.impl
Pane {
id: root
property var source: null
property bool resourceDetailsVisible: false
opacity: 0.9
ColumnLayout {
id: layout
RowLayout {
Label {
Layout.fillWidth: true
text: root.source.renderStats.fps + " FPS"
font.pointSize: 14
}
Label {
text: "Details"
}
CheckBox {
checked: root.resourceDetailsVisible
onCheckedChanged: {
resourceDetailsVisible = checked;
}
}
}
component TimeLabel : RowLayout {
id: timeLabel
property alias text: label.text
property real value: 0.0
Label {
id: label
Layout.fillWidth: true
text: "Frame: "
}
Label {
text: timeLabel.value.toFixed(3) + "ms"
}
}
TimeLabel {
text: "Frame: "
value: root.source.renderStats.frameTime
}
TimeLabel {
text: " Sync: "
value: root.source.renderStats.syncTime
}
TimeLabel {
text: " Prep: "
value: root.source.renderStats.renderPrepareTime
}
TimeLabel {
text: " Render: "
value: root.source.renderStats.renderTime
}
TimeLabel {
text: "Max: "
value: root.source.renderStats.maxFrameTime
}
TimeLabel {
text: "GPU: "
value: root.source.renderStats.lastCompletedGpuTime
visible: root.source.renderStats.lastCompletedGpuTime > 0
}
Page {
Layout.fillWidth: true
Layout.minimumWidth: 530
visible: root.resourceDetailsVisible
header: TabBar {
id: tabBar
TabButton {
text: "Summary"
}
TabButton {
text: "Passes"
}
TabButton {
text: "Textures"
}
TabButton {
text: "Meshes"
}
TabButton {
text: "Tools"
}
TabButton {
text: "Shadows"
}
}
StackLayout {
anchors.fill: parent
anchors.margins: 10
currentIndex: tabBar.currentIndex
Pane {
id: summaryPane
ColumnLayout {
Label {
text: "Graphics API: " + root.source.renderStats.graphicsApiName
visible: root.resourceDetailsVisible
}
Label {
text: root.source.renderStats.renderPassCount + " render passes"
visible: root.resourceDetailsVisible
}
Label {
text: root.source.renderStats.drawCallCount + " draw calls"
visible: root.resourceDetailsVisible
}
Label {
text: root.source.renderStats.drawVertexCount + " vertices"
visible: root.resourceDetailsVisible
}
Label {
text: "Image assets: " + (root.source.renderStats.imageDataSize / 1024).toFixed(2) + " KB"
visible: root.resourceDetailsVisible
}
Label {
text: "Mesh assets: " + (root.source.renderStats.meshDataSize / 1024).toFixed(2) + " KB"
visible: root.resourceDetailsVisible
}
Label {
text: "Pipelines: " + root.source.renderStats.pipelineCount
visible: root.resourceDetailsVisible
}
Label {
text: "Material build time: " + root.source.renderStats.materialGenerationTime + " ms"
visible: root.resourceDetailsVisible
}
Label {
text: "Effect build time: " + root.source.renderStats.effectGenerationTime + " ms"
visible: root.resourceDetailsVisible
}
Label {
text: "Pipeline build time: " + root.source.renderStats.pipelineCreationTime + " ms"
visible: root.resourceDetailsVisible
}
Label {
text: root.source.renderStats.vmemAllocCount + " vmem allocs with " + root.source.renderStats.vmemUsedBytes + " bytes"
visible: root.resourceDetailsVisible && root.source.renderStats.vmemAllocCount > 0
}
}
}
Pane {
id: passesPane
RenderStatsPassesModel {
id: passesModel
passData: root.source.renderStats.renderPassDetails
}
ColumnLayout {
anchors.fill: parent
spacing: 0
HorizontalHeaderView {
syncView: passesTableView
resizableColumns: false // otherwise QTBUG-111013 happens
boundsBehavior: Flickable.StopAtBounds
flickableDirection: Flickable.VerticalFlick
}
ListModel {
id: passesHeaderModel
ListElement {
columnWidth: 300 // name
}
ListElement {
columnWidth: 80 // size
}
ListElement {
columnWidth: 60 // vertices
}
ListElement {
columnWidth: 60 // draw calls
}
}
Item {
Layout.fillHeight: true
Layout.fillWidth: true
TableView {
id: passesTableView
anchors.fill: parent
// name, size, vertices, draw calls
property var columnFactors: [58, 14, 12, 12]; // == 96, leave space for the scrollbar
columnWidthProvider: function (column) {
return passesPane.width * (columnFactors[column] / 100.0);
}
boundsBehavior: Flickable.StopAtBounds
flickableDirection: Flickable.VerticalFlick
ScrollBar.vertical: ScrollBar {
parent: passesTableView.parent
anchors.top: passesTableView.top
anchors.bottom: passesTableView.bottom
anchors.left: passesTableView.right
}
clip: true
model: passesModel
columnSpacing: 1
rowSpacing: 1
implicitWidth: parent.width + columnSpacing
implicitHeight: parent.height + rowSpacing
delegate: CustomTableItemDelegate {
required property string display
text: display
color: TableView.view.palette.base
textColor: TableView.view.palette.text
}
}
}
}
}
Pane {
id: texturesPane
RenderStatsTexturesModel {
id: texturesModel
textureData: root.source.renderStats.textureDetails
}
ColumnLayout {
anchors.fill: parent
spacing: 0
HorizontalHeaderView {
syncView: texturesTableView
resizableColumns: false // otherwise QTBUG-111013 happens
boundsBehavior: Flickable.StopAtBounds
flickableDirection: Flickable.VerticalFlick
}
Item {
Layout.fillHeight: true
Layout.fillWidth: true
TableView {
id: texturesTableView
anchors.fill: parent
// name, size, format, miplevels, flags
property var columnFactors: [48, 12, 12, 12, 12]; // == 96, leave space for the scrollbar
columnWidthProvider: function (column) {
return texturesPane.width * (columnFactors[column] / 100.0);
}
boundsBehavior: Flickable.StopAtBounds
flickableDirection: Flickable.VerticalFlick
ScrollBar.vertical: ScrollBar {
parent: texturesTableView.parent
anchors.top: texturesTableView.top
anchors.bottom: texturesTableView.bottom
anchors.left: texturesTableView.right
}
ScrollBar.horizontal: ScrollBar { }
clip: true
model: texturesModel
columnSpacing: 1
rowSpacing: 1
implicitWidth: parent.width + columnSpacing
implicitHeight: parent.height + rowSpacing
delegate: CustomTableItemDelegate {
required property string display
text: display
color: TableView.view.palette.base
textColor: TableView.view.palette.text
}
}
}
}
}
Pane {
id: meshesPane
RenderStatsMeshesModel {
id: meshesModel
meshData: root.source.renderStats.meshDetails
}
ColumnLayout {
anchors.fill: parent
spacing: 0
HorizontalHeaderView {
syncView: meshesTableView
resizableColumns: false // otherwise QTBUG-111013 happens
boundsBehavior: Flickable.StopAtBounds
flickableDirection: Flickable.VerticalFlick
}
Item {
Layout.fillHeight: true
Layout.fillWidth: true
TableView {
id: meshesTableView
anchors.fill: parent
// name, submeshes, vertices, vbufsize, ibufsize
property var columnFactors: [48, 12, 12, 12, 12]; // == 96, leave space for the scrollbar
columnWidthProvider: function (column) {
return meshesPane.width * (columnFactors[column] / 100.0);
}
boundsBehavior: Flickable.StopAtBounds
flickableDirection: Flickable.VerticalFlick
ScrollBar.vertical: ScrollBar {
parent: meshesTableView.parent
anchors.top: meshesTableView.top
anchors.bottom: meshesTableView.bottom
anchors.left: meshesTableView.right
}
clip: true
model: meshesModel
columnSpacing: 1
rowSpacing: 1
implicitWidth: parent.width + columnSpacing
implicitHeight: parent.height + rowSpacing
delegate: CustomTableItemDelegate {
required property string display
text: display
color: TableView.view.palette.base
textColor: TableView.view.palette.text
}
}
}
}
}
Pane {
id: visualizePane
ColumnLayout {
id: visCtrCol
width: parent.width
CheckBox {
text: "Wireframe mode"
onCheckedChanged: root.source.environment.debugSettings.wireframeEnabled = checked
}
RowLayout {
Label {
text: "Material override"
}
ComboBox {
id: materialOverrideComboBox
textRole: "text"
valueRole: "value"
implicitContentWidthPolicy: ComboBox.WidestText
onActivated: root.source.environment.debugSettings.materialOverride = currentValue
Component.onCompleted: materialOverrideComboBox.currentIndex = materialOverrideComboBox.indexOfValue(root.source.environment.debugSettings.materialOverride)
model: [
{ value: DebugSettings.None, text: "None"},
{ value: DebugSettings.BaseColor, text: "Base Color"},
{ value: DebugSettings.Roughness, text: "Roughness"},
{ value: DebugSettings.Metalness, text: "Metalness"},
{ value: DebugSettings.Diffuse, text: "Diffuse"},
{ value: DebugSettings.Specular, text: "Specular"},
{ value: DebugSettings.ShadowOcclusion, text: "Shadow Occlusion"},
{ value: DebugSettings.Emission, text: "Emission"},
{ value: DebugSettings.AmbientOcclusion, text: "Ambient Occlusion"},
{ value: DebugSettings.Normals, text: "Normals"},
{ value: DebugSettings.Tangents, text: "Tangents"},
{ value: DebugSettings.Binormals, text: "Binormals"},
{ value: DebugSettings.F0, text: "F0"}
]
}
}
RowLayout {
spacing: 20
Button {
text: "Release cached resources"
onClicked: root.source.renderStats.releaseCachedResources()
}
Button {
text: "Bake lightmap"
onClicked: root.source.bakeLightmap()
}
Button {
text: "Denoise lightmap"
onClicked: root.source.denoiseLightmap()
}
}
RowLayout {
Label {
text: "Render mode override"
}
ComboBox {
id: renderModeOverrideComboBox
textRole: "text"
valueRole: "value"
implicitContentWidthPolicy: ComboBox.WidestText
onActivated: root.source.renderMode = currentValue
Component.onCompleted: renderModeOverrideComboBox.currentIndex = renderModeOverrideComboBox.indexOfValue(root.source.renderMode)
model: [
{ value: View3D.Offscreen, text: "Offscreen" },
{ value: View3D.Underlay, text: "Underlay" },
{ value: View3D.Overlay, text: "Overlay" },
{ value: View3D.Inline, text: "Inline" }
]
}
}
Label {
text: "View3D logical size is " + root.source.width + "x" + root.source.height
}
Label {
text: "Backing texture pixel size is " + root.source.effectiveTextureSize.width + "x" + root.source.effectiveTextureSize.height
visible: root.source.renderMode === View3D.Offscreen
}
RowLayout {
CheckBox {
id: explicitTextureSizeCheckBox
visible: root.source.renderMode === View3D.Offscreen
text: "Explicit backing texture size"
property real aspectRatio: root.source.width / root.source.height
onCheckedChanged: updateSize()
function updateSize() {
if (!explicitTextureSizeCheckBox.checked) {
root.source.explicitTextureWidth = 0;
root.source.explicitTextureHeight = 0;
return;
}
var newWidth = explicitWidthSlider.value;
var newHeight = explicitHeightSlider.value;
if (keepAspectRatioCheckBox.checked) {
var aspectRatio = explicitTextureSizeCheckBox.aspectRatio;
if (newHeight * aspectRatio <= newWidth)
newWidth = newHeight * aspectRatio;
else
newHeight = newWidth * (1.0 / aspectRatio);
}
root.source.explicitTextureWidth = newWidth;
root.source.explicitTextureHeight = newHeight;
}
Connections {
target: root.source
function onWidthChanged() { explicitTextureSizeCheckBox.updateSize() }
function onHeightChanged() { explicitTextureSizeCheckBox.updateSize() }
}
}
CheckBox {
id: keepAspectRatioCheckBox
visible: root.source.renderMode === View3D.Offscreen && explicitTextureSizeCheckBox.checked
text: "Keep aspect ratio (" + explicitTextureSizeCheckBox.aspectRatio.toFixed(2) + ")"
checked: false
onCheckedChanged: explicitTextureSizeCheckBox.updateSize()
}
}
RowLayout {
visible: root.source.renderMode === View3D.Offscreen && explicitTextureSizeCheckBox.checked
Label {
text: "Width: " + explicitWidthSlider.value.toFixed(0) + " px"
}
Slider {
id: explicitWidthSlider
from: 16
to: 4096
value: 1280
onValueChanged: explicitTextureSizeCheckBox.updateSize()
Layout.maximumWidth: 120
}
Label {
text: "Height: " + explicitHeightSlider.value.toFixed(0) + " px"
}
Slider {
id: explicitHeightSlider
from: 16
to: 4096
value: 720
onValueChanged: explicitTextureSizeCheckBox.updateSize()
Layout.maximumWidth: 120
}
}
}
}
Pane {
id: shadowsPane
ColumnLayout {
width: parent.width
CheckBox {
text: "Draw directional light shadow bounding boxes"
checked: root.source.environment.debugSettings.drawDirectionalLightShadowBoxes
onCheckedChanged: root.source.environment.debugSettings.drawDirectionalLightShadowBoxes = checked
}
CheckBox {
text: "Draw point light shadow bounding boxes"
checked: root.source.environment.debugSettings.drawPointLightShadowBoxes
onCheckedChanged: root.source.environment.debugSettings.drawPointLightShadowBoxes = checked
}
CheckBox {
text: "Draw shadow casting bounding box"
checked: root.source.environment.debugSettings.drawShadowCastingBounds
onCheckedChanged: root.source.environment.debugSettings.drawShadowCastingBounds = checked
}
CheckBox {
text: "Draw shadow receiving bounding box"
checked: root.source.environment.debugSettings.drawShadowReceivingBounds
onCheckedChanged: root.source.environment.debugSettings.drawShadowReceivingBounds = checked
}
CheckBox {
text: "Draw cascades"
checked: root.source.environment.debugSettings.drawCascades
onCheckedChanged: root.source.environment.debugSettings.drawCascades = checked
}
CheckBox {
text: "Draw scene cascade intersection"
checked: root.source.environment.debugSettings.drawSceneCascadeIntersection
onCheckedChanged: root.source.environment.debugSettings.drawSceneCascadeIntersection = checked
}
CheckBox {
text: "Disable Shadow Camera Update"
checked: root.source.environment.debugSettings.disableShadowCameraUpdate
onCheckedChanged: root.source.environment.debugSettings.disableShadowCameraUpdate = checked
}
CheckBox {
text: "Draw Culled Objects"
checked: root.source.environment.debugSettings.drawCulledObjects
onCheckedChanged: root.source.environment.debugSettings.drawCulledObjects = checked
}
}
}
}
}
}
component CustomTableItemDelegate : Rectangle {
property alias text: textLabel.text
property alias textColor: textLabel.color
implicitWidth: 100
implicitHeight: textLabel.implicitHeight + 4
color: palette.base
Label {
id: textLabel
anchors.centerIn: parent
color: palette.text
}
}
function syncVisible() {
if (source) {
source.renderStats.extendedDataCollectionEnabled = visible && resourceDetailsVisible;
if (source.renderStats.extendedDataCollectionEnabled)
source.update();
}
}
Component.onCompleted: syncVisible()
onSourceChanged: syncVisible()
onVisibleChanged: syncVisible()
onResourceDetailsVisibleChanged: syncVisible()
}