mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-07-28 18:31:40 +00:00
Add Qt version of statistics viewer
This commit is contained in:
@@ -41,6 +41,7 @@
|
||||
#include "Windows/EventBrowser.h"
|
||||
#include "Windows/MainWindow.h"
|
||||
#include "Windows/PipelineState/PipelineStateViewer.h"
|
||||
#include "Windows/StatisticsViewer.h"
|
||||
#include "Windows/TextureViewer.h"
|
||||
#include "QRDUtils.h"
|
||||
|
||||
@@ -531,6 +532,18 @@ DebugMessageView *CaptureContext::debugMessageView()
|
||||
return m_DebugMessageView;
|
||||
}
|
||||
|
||||
StatisticsViewer *CaptureContext::statisticsViewer()
|
||||
{
|
||||
if(m_StatisticsViewer)
|
||||
return m_StatisticsViewer;
|
||||
|
||||
m_StatisticsViewer = new StatisticsViewer(this, m_MainWindow);
|
||||
m_StatisticsViewer->setObjectName("statisticsViewer");
|
||||
setupDockWindow(m_StatisticsViewer);
|
||||
|
||||
return m_StatisticsViewer;
|
||||
}
|
||||
|
||||
void CaptureContext::showEventBrowser()
|
||||
{
|
||||
m_MainWindow->showEventBrowser();
|
||||
@@ -566,6 +579,11 @@ void CaptureContext::showDebugMessageView()
|
||||
m_MainWindow->showDebugMessageView();
|
||||
}
|
||||
|
||||
void CaptureContext::showStatisticsViewer()
|
||||
{
|
||||
m_MainWindow->showStatisticsViewer();
|
||||
}
|
||||
|
||||
QWidget *CaptureContext::createToolWindow(const QString &objectName)
|
||||
{
|
||||
if(objectName == "textureViewer")
|
||||
@@ -596,6 +614,10 @@ QWidget *CaptureContext::createToolWindow(const QString &objectName)
|
||||
{
|
||||
return debugMessageView();
|
||||
}
|
||||
else if(objectName == "statisticsViewer")
|
||||
{
|
||||
return statisticsViewer();
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -616,6 +638,8 @@ void CaptureContext::windowClosed(QWidget *window)
|
||||
m_MeshPreview = NULL;
|
||||
else if((QWidget *)m_DebugMessageView == window)
|
||||
m_DebugMessageView = NULL;
|
||||
else if((QWidget *)m_StatisticsViewer == window)
|
||||
m_StatisticsViewer = NULL;
|
||||
else
|
||||
qCritical() << "Unrecognised window being closed: " << window;
|
||||
}
|
||||
|
||||
@@ -63,6 +63,7 @@ class BufferViewer;
|
||||
class TextureViewer;
|
||||
class CaptureDialog;
|
||||
class DebugMessageView;
|
||||
class StatisticsViewer;
|
||||
class QProgressDialog;
|
||||
|
||||
class CaptureContext
|
||||
@@ -140,6 +141,7 @@ public:
|
||||
PipelineStateViewer *pipelineViewer();
|
||||
CaptureDialog *captureDialog();
|
||||
DebugMessageView *debugMessageView();
|
||||
StatisticsViewer *statisticsViewer();
|
||||
void setupDockWindow(QWidget *shad);
|
||||
|
||||
bool hasEventBrowser() { return m_EventBrowser != NULL; }
|
||||
@@ -149,6 +151,7 @@ public:
|
||||
bool hasMeshPreview() { return m_MeshPreview != NULL; }
|
||||
bool hasCaptureDialog() { return m_CaptureDialog != NULL; }
|
||||
bool hasDebugMessageView() { return m_DebugMessageView != NULL; }
|
||||
bool hasStatisticsViewer() { return m_StatisticsViewer != NULL; }
|
||||
void showEventBrowser();
|
||||
void showAPIInspector();
|
||||
void showTextureViewer();
|
||||
@@ -156,6 +159,7 @@ public:
|
||||
void showPipelineViewer();
|
||||
void showCaptureDialog();
|
||||
void showDebugMessageView();
|
||||
void showStatisticsViewer();
|
||||
|
||||
QWidget *createToolWindow(const QString &objectName);
|
||||
void windowClosed(QWidget *window);
|
||||
@@ -229,4 +233,5 @@ private:
|
||||
PipelineStateViewer *m_PipelineViewer = NULL;
|
||||
CaptureDialog *m_CaptureDialog = NULL;
|
||||
DebugMessageView *m_DebugMessageView = NULL;
|
||||
StatisticsViewer *m_StatisticsViewer = NULL;
|
||||
};
|
||||
|
||||
@@ -242,7 +242,7 @@ struct ToStr
|
||||
case eResType_Texture2D: return "Texture 2D";
|
||||
case eResType_TextureRect: return "Texture Rect";
|
||||
case eResType_Texture2DArray: return "Texture 2D Array";
|
||||
case eResType_Texture2DMS: return "Texture 2D MS Array";
|
||||
case eResType_Texture2DMS: return "Texture 2D MS";
|
||||
case eResType_Texture2DMSArray: return "Texture 2D MS Array";
|
||||
case eResType_Texture3D: return "Texture 3D";
|
||||
case eResType_TextureCube: return "Texture Cube";
|
||||
@@ -454,13 +454,17 @@ struct Formatter
|
||||
static void setParams(int minFigures, int maxFigures, int expNegCutoff, int expPosCutoff);
|
||||
|
||||
static QString Format(double f, bool hex = false);
|
||||
static QString Format(uint64_t u, bool hex = false)
|
||||
{
|
||||
return QString("%1").arg(u, hex ? 16 : 0, hex ? 16 : 10, QChar('0'));
|
||||
}
|
||||
static QString Format(uint32_t u, bool hex = false)
|
||||
{
|
||||
return QString("%1").arg(u, hex ? 8 : 0, hex ? 16 : 10, QChar('0'));
|
||||
}
|
||||
static QString Format(uint16_t u, bool hex = false)
|
||||
{
|
||||
return QString("%1").arg(u, hex ? 8 : 0, hex ? 16 : 10, QChar('0'));
|
||||
return QString("%1").arg(u, hex ? 4 : 0, hex ? 16 : 10, QChar('0'));
|
||||
}
|
||||
static QString Format(int32_t i, bool hex = false) { return QString::number(i); }
|
||||
private:
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
#include "ConstantBufferPreviewer.h"
|
||||
#include "DebugMessageView.h"
|
||||
#include "EventBrowser.h"
|
||||
#include "StatisticsViewer.h"
|
||||
#include "TextureViewer.h"
|
||||
#include "ui_MainWindow.h"
|
||||
#include "version.h"
|
||||
@@ -1065,6 +1066,16 @@ void MainWindow::on_action_Errors_and_Warnings_triggered()
|
||||
ui->toolWindowManager->addToolWindow(debugMessages, mainToolArea());
|
||||
}
|
||||
|
||||
void MainWindow::on_action_Statistics_Viewer_triggered()
|
||||
{
|
||||
StatisticsViewer *stats = m_Ctx->statisticsViewer();
|
||||
|
||||
if(ui->toolWindowManager->toolWindows().contains(stats))
|
||||
ToolWindowManager::raiseToolWindow(stats);
|
||||
else
|
||||
ui->toolWindowManager->addToolWindow(stats, mainToolArea());
|
||||
}
|
||||
|
||||
void MainWindow::on_action_Resolve_Symbols_triggered()
|
||||
{
|
||||
m_Ctx->Renderer()->AsyncInvoke([this](IReplayRenderer *r) { r->InitResolver(); });
|
||||
|
||||
@@ -79,6 +79,7 @@ public:
|
||||
void showPipelineViewer() { on_action_Pipeline_State_triggered(); }
|
||||
void showCaptureDialog() { on_action_Capture_Log_triggered(); }
|
||||
void showDebugMessageView() { on_action_Errors_and_Warnings_triggered(); }
|
||||
void showStatisticsViewer() { on_action_Statistics_Viewer_triggered(); }
|
||||
private slots:
|
||||
// automatic slots
|
||||
void on_action_Exit_triggered();
|
||||
@@ -93,6 +94,7 @@ private slots:
|
||||
void on_action_Pipeline_State_triggered();
|
||||
void on_action_Capture_Log_triggered();
|
||||
void on_action_Errors_and_Warnings_triggered();
|
||||
void on_action_Statistics_Viewer_triggered();
|
||||
void on_action_Inject_into_Process_triggered();
|
||||
void on_action_Resolve_Symbols_triggered();
|
||||
|
||||
|
||||
@@ -127,6 +127,7 @@
|
||||
<addaction name="action_Mesh_Output"/>
|
||||
<addaction name="action_Errors_and_Warnings"/>
|
||||
<addaction name="action_Timeline"/>
|
||||
<addaction name="action_Statistics_Viewer"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menu_Help">
|
||||
<property name="title">
|
||||
@@ -383,6 +384,11 @@
|
||||
<string>Clear History</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action_Statistics_Viewer">
|
||||
<property name="text">
|
||||
<string>Statisti&cs Viewer</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<layoutdefault spacing="6" margin="11"/>
|
||||
<customwidgets>
|
||||
|
||||
@@ -0,0 +1,822 @@
|
||||
/******************************************************************************
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2017 Baldur Karlsson
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "StatisticsViewer.h"
|
||||
#include <QFontDatabase>
|
||||
#include "ui_StatisticsViewer.h"
|
||||
|
||||
static const int HistogramWidth = 128;
|
||||
static const QString Stars = QString(HistogramWidth, QChar('*'));
|
||||
|
||||
QString Pow2IndexAsReadable(int index)
|
||||
{
|
||||
uint64_t value = 1ULL << index;
|
||||
|
||||
if(value >= (1024 * 1024))
|
||||
{
|
||||
float slice = (float)value / (1024 * 1024);
|
||||
return QString("%1MB").arg(Formatter::Format(slice));
|
||||
}
|
||||
else if(value >= 1024)
|
||||
{
|
||||
float slice = (float)value / 1024;
|
||||
return QString("%1KB").arg(Formatter::Format(slice));
|
||||
}
|
||||
else
|
||||
{
|
||||
return QString("%1B").arg(Formatter::Format((float)value));
|
||||
}
|
||||
}
|
||||
|
||||
int SliceForString(const QString &s, uint32_t value, uint32_t maximum)
|
||||
{
|
||||
if(value == 0 || maximum == 0)
|
||||
return 0;
|
||||
|
||||
float ratio = (float)value / maximum;
|
||||
int slice = (int)(ratio * s.length());
|
||||
return qMax(1, slice);
|
||||
}
|
||||
|
||||
QString CountOrEmpty(uint32_t count)
|
||||
{
|
||||
if(count == 0)
|
||||
return "";
|
||||
else
|
||||
return QString("(%1)").arg(count);
|
||||
}
|
||||
|
||||
QString CreateSimpleIntegerHistogram(const QString &legend, const rdctype::array<uint32_t> &array)
|
||||
{
|
||||
uint32_t maxCount = 0;
|
||||
int maxWithValue = 0;
|
||||
|
||||
for(int o = 0; o < array.count; o++)
|
||||
{
|
||||
uint32_t value = array[o];
|
||||
if(value > 0)
|
||||
maxWithValue = o;
|
||||
maxCount = qMax(maxCount, value);
|
||||
}
|
||||
|
||||
QString text = QString("\n%1:\n").arg(legend);
|
||||
|
||||
for(int o = 0; o <= maxWithValue; o++)
|
||||
{
|
||||
uint32_t count = array[o];
|
||||
int slice = SliceForString(Stars, count, maxCount);
|
||||
text += QString("%1: %2 %3\n").arg(o, 4).arg(Stars.left(slice)).arg(CountOrEmpty(count));
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
void AppendDrawStatistics(QString &statisticsLog, const FetchFrameInfo &frameInfo)
|
||||
{
|
||||
// #mivance see AppendConstantBindStatistics
|
||||
const FetchFrameDrawStats &draws = frameInfo.stats.draws;
|
||||
|
||||
statisticsLog.append("\n*** Draw Statistics ***\n\n");
|
||||
|
||||
statisticsLog.append(QString("Total calls: %1, instanced: %2, indirect: %3\n")
|
||||
.arg(draws.calls)
|
||||
.arg(draws.instanced)
|
||||
.arg(draws.indirect));
|
||||
|
||||
if(draws.instanced > 0)
|
||||
{
|
||||
statisticsLog.append("\nInstance counts:\n");
|
||||
uint32_t maxCount = 0;
|
||||
int maxWithValue = 0;
|
||||
int maximum = draws.counts.count;
|
||||
for(int s = 1; s < maximum; s++)
|
||||
{
|
||||
uint32_t value = draws.counts[s];
|
||||
if(value > 0)
|
||||
maxWithValue = s;
|
||||
maxCount = qMax(maxCount, value);
|
||||
}
|
||||
|
||||
for(int s = 1; s <= maxWithValue; s++)
|
||||
{
|
||||
uint32_t count = draws.counts[s];
|
||||
int slice = SliceForString(Stars, count, maxCount);
|
||||
statisticsLog.append(QString("%1%2: %3 %4\n")
|
||||
.arg((s == maximum - 1) ? ">=" : " ")
|
||||
.arg(s, 2)
|
||||
.arg(Stars.left(slice))
|
||||
.arg(CountOrEmpty(count)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AppendDispatchStatistics(QString &statisticsLog, const FetchFrameInfo &frameInfo)
|
||||
{
|
||||
statisticsLog.append("\n*** Dispatch Statistics ***\n\n");
|
||||
statisticsLog.append(QString("Total calls: %1, indirect: %2\n")
|
||||
.arg(frameInfo.stats.dispatches.calls)
|
||||
.arg(frameInfo.stats.dispatches.indirect));
|
||||
}
|
||||
|
||||
void AppendInputAssemblerStatistics(QString &statisticsLog, const FetchFrameInfo &frameInfo)
|
||||
{
|
||||
const FetchFrameIndexBindStats &indices = frameInfo.stats.indices;
|
||||
const FetchFrameLayoutBindStats &layouts = frameInfo.stats.layouts;
|
||||
|
||||
const FetchFrameVertexBindStats &vertices = frameInfo.stats.vertices;
|
||||
|
||||
statisticsLog.append("\n*** Input Assembler Statistics ***\n\n");
|
||||
|
||||
statisticsLog.append(
|
||||
QString("Total index calls: %1, non-null index sets: %2, null index sets: %3\n")
|
||||
.arg(indices.calls)
|
||||
.arg(indices.sets)
|
||||
.arg(indices.nulls));
|
||||
statisticsLog.append(
|
||||
QString("Total layout calls: %1, non-null layout sets: %2, null layout sets: %3\n")
|
||||
.arg(layouts.calls)
|
||||
.arg(layouts.sets)
|
||||
.arg(layouts.nulls));
|
||||
statisticsLog.append(
|
||||
QString("Total vertex calls: %1, non-null vertex sets: %2, null vertex sets: %3\n")
|
||||
.arg(vertices.calls)
|
||||
.arg(vertices.sets)
|
||||
.arg(vertices.nulls));
|
||||
|
||||
statisticsLog.append(CreateSimpleIntegerHistogram("Aggregate vertex slot counts per invocation",
|
||||
vertices.bindslots));
|
||||
}
|
||||
|
||||
void AppendShaderStatistics(CaptureContext *ctx, QString &statisticsLog,
|
||||
const FetchFrameInfo &frameInfo)
|
||||
{
|
||||
const FetchFrameShaderStats *shaders = frameInfo.stats.shaders;
|
||||
FetchFrameShaderStats totalShadersPerStage = {};
|
||||
for(int s = eShaderStage_First; s < eShaderStage_Count; s++)
|
||||
{
|
||||
totalShadersPerStage.calls += shaders[s].calls;
|
||||
totalShadersPerStage.sets += shaders[s].sets;
|
||||
totalShadersPerStage.nulls += shaders[s].nulls;
|
||||
totalShadersPerStage.redundants += shaders[s].redundants;
|
||||
}
|
||||
|
||||
statisticsLog.append("\n*** Shader Set Statistics ***\n\n");
|
||||
|
||||
for(int s = eShaderStage_First; s < eShaderStage_Count; s++)
|
||||
{
|
||||
statisticsLog.append(QString("%1 calls: %2, non-null shader sets: %3, null shader sets: %4, "
|
||||
"redundant shader sets: %5\n")
|
||||
.arg(ctx->CurPipelineState.Abbrev((ShaderStageType)s))
|
||||
.arg(shaders[s].calls)
|
||||
.arg(shaders[s].sets)
|
||||
.arg(shaders[s].nulls)
|
||||
.arg(shaders[s].redundants));
|
||||
}
|
||||
|
||||
statisticsLog.append(QString("Total calls: %1, non-null shader sets: %2, null shader sets: %3, "
|
||||
"reundant shader sets: %4\n")
|
||||
.arg(totalShadersPerStage.calls)
|
||||
.arg(totalShadersPerStage.sets)
|
||||
.arg(totalShadersPerStage.nulls)
|
||||
.arg(totalShadersPerStage.redundants));
|
||||
}
|
||||
|
||||
void AppendConstantBindStatistics(CaptureContext *ctx, QString &statisticsLog,
|
||||
const FetchFrameInfo &frameInfo)
|
||||
{
|
||||
// #mivance C++-side we guarantee all stages will have the same slots
|
||||
// and sizes count, so pattern off of the first frame's first stage
|
||||
const FetchFrameConstantBindStats &reference = frameInfo.stats.constants[0];
|
||||
|
||||
// #mivance there is probably a way to iterate the fields via
|
||||
// GetType()/GetField() and build a sort of dynamic min/max/average
|
||||
// structure for a given type with known integral types (or arrays
|
||||
// thereof), but given we're heading for a Qt/C++ rewrite of the UI
|
||||
// perhaps best not to dwell too long on that
|
||||
FetchFrameConstantBindStats totalConstantsPerStage[eShaderStage_Count] = {};
|
||||
for(int s = eShaderStage_First; s < eShaderStage_Count; s++)
|
||||
{
|
||||
totalConstantsPerStage[s].bindslots.create(reference.bindslots.count);
|
||||
totalConstantsPerStage[s].sizes.create(reference.sizes.count);
|
||||
}
|
||||
|
||||
{
|
||||
const FetchFrameConstantBindStats *constants = frameInfo.stats.constants;
|
||||
for(int s = eShaderStage_First; s < eShaderStage_Count; s++)
|
||||
{
|
||||
totalConstantsPerStage[s].calls += constants[s].calls;
|
||||
totalConstantsPerStage[s].sets += constants[s].sets;
|
||||
totalConstantsPerStage[s].nulls += constants[s].nulls;
|
||||
|
||||
for(int l = 0; l < constants[s].bindslots.count; l++)
|
||||
totalConstantsPerStage[s].bindslots[l] += constants[s].bindslots[l];
|
||||
|
||||
for(int z = 0; z < constants[s].sizes.count; z++)
|
||||
totalConstantsPerStage[s].sizes[z] += constants[s].sizes[z];
|
||||
}
|
||||
}
|
||||
|
||||
FetchFrameConstantBindStats totalConstantsForAllStages = {};
|
||||
totalConstantsForAllStages.bindslots.create(totalConstantsPerStage[0].bindslots.count);
|
||||
totalConstantsForAllStages.sizes.create(totalConstantsPerStage[0].sizes.count);
|
||||
|
||||
for(int s = eShaderStage_First; s < eShaderStage_Count; s++)
|
||||
{
|
||||
const FetchFrameConstantBindStats &perStage = totalConstantsPerStage[s];
|
||||
totalConstantsForAllStages.calls += perStage.calls;
|
||||
totalConstantsForAllStages.sets += perStage.sets;
|
||||
totalConstantsForAllStages.nulls += perStage.nulls;
|
||||
|
||||
for(int l = 0; l < perStage.bindslots.count; l++)
|
||||
totalConstantsForAllStages.bindslots[l] += perStage.bindslots[l];
|
||||
|
||||
for(int z = 0; z < perStage.sizes.count; z++)
|
||||
totalConstantsForAllStages.sizes[z] += perStage.sizes[z];
|
||||
}
|
||||
|
||||
statisticsLog.append("\n*** Constant Bind Statistics ***\n\n");
|
||||
|
||||
for(int s = eShaderStage_First; s < eShaderStage_Count; s++)
|
||||
{
|
||||
statisticsLog.append(QString("%1 calls: %2, non-null buffer sets: %3, null buffer sets: %4\n")
|
||||
.arg(ctx->CurPipelineState.Abbrev((ShaderStageType)s))
|
||||
.arg(totalConstantsPerStage[s].calls)
|
||||
.arg(totalConstantsPerStage[s].sets)
|
||||
.arg(totalConstantsPerStage[s].nulls));
|
||||
}
|
||||
|
||||
statisticsLog.append(QString("Total calls: %1, non-null buffer sets: %2, null buffer sets: %3\n")
|
||||
.arg(totalConstantsForAllStages.calls)
|
||||
.arg(totalConstantsForAllStages.sets)
|
||||
.arg(totalConstantsForAllStages.nulls));
|
||||
|
||||
statisticsLog.append(CreateSimpleIntegerHistogram(
|
||||
"Aggregate slot counts per invocation across all stages", totalConstantsForAllStages.bindslots));
|
||||
|
||||
statisticsLog.append("\nAggregate constant buffer sizes across all stages:\n");
|
||||
uint32_t maxCount = 0;
|
||||
int maxWithValue = 0;
|
||||
for(int s = 0; s < totalConstantsForAllStages.sizes.count; s++)
|
||||
{
|
||||
uint32_t value = totalConstantsForAllStages.sizes[s];
|
||||
if(value > 0)
|
||||
maxWithValue = s;
|
||||
maxCount = qMax(maxCount, value);
|
||||
}
|
||||
|
||||
for(int s = 0; s <= maxWithValue; s++)
|
||||
{
|
||||
uint32_t count = totalConstantsForAllStages.sizes[s];
|
||||
int slice = SliceForString(Stars, count, maxCount);
|
||||
statisticsLog.append(QString("%1: %2 %3\n")
|
||||
.arg(Pow2IndexAsReadable(s), 8)
|
||||
.arg(Stars.left(slice))
|
||||
.arg(CountOrEmpty(count)));
|
||||
}
|
||||
}
|
||||
|
||||
void AppendSamplerBindStatistics(CaptureContext *ctx, QString &statisticsLog,
|
||||
const FetchFrameInfo &frameInfo)
|
||||
{
|
||||
// #mivance see AppendConstantBindStatistics
|
||||
const FetchFrameSamplerBindStats &reference = frameInfo.stats.samplers[0];
|
||||
|
||||
FetchFrameSamplerBindStats totalSamplersPerStage[eShaderStage_Count] = {};
|
||||
for(int s = eShaderStage_First; s < eShaderStage_Count; s++)
|
||||
{
|
||||
totalSamplersPerStage[s].bindslots.create(reference.bindslots.count);
|
||||
}
|
||||
|
||||
{
|
||||
const FetchFrameSamplerBindStats *samplers = frameInfo.stats.samplers;
|
||||
for(int s = eShaderStage_First; s < eShaderStage_Count; s++)
|
||||
{
|
||||
totalSamplersPerStage[s].calls += samplers[s].calls;
|
||||
totalSamplersPerStage[s].sets += samplers[s].sets;
|
||||
totalSamplersPerStage[s].nulls += samplers[s].nulls;
|
||||
|
||||
for(int l = 0; l < samplers[s].bindslots.count; l++)
|
||||
{
|
||||
totalSamplersPerStage[s].bindslots[l] += samplers[s].bindslots[l];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FetchFrameSamplerBindStats totalSamplersForAllStages = {};
|
||||
totalSamplersForAllStages.bindslots.create(totalSamplersPerStage[0].bindslots.count);
|
||||
|
||||
for(int s = eShaderStage_First; s < eShaderStage_Count; s++)
|
||||
{
|
||||
FetchFrameSamplerBindStats perStage = totalSamplersPerStage[s];
|
||||
totalSamplersForAllStages.calls += perStage.calls;
|
||||
totalSamplersForAllStages.sets += perStage.sets;
|
||||
totalSamplersForAllStages.nulls += perStage.nulls;
|
||||
for(int l = 0; l < perStage.bindslots.count; l++)
|
||||
{
|
||||
totalSamplersForAllStages.bindslots[l] += perStage.bindslots[l];
|
||||
}
|
||||
}
|
||||
|
||||
statisticsLog.append("\n*** Sampler Bind Statistics ***\n\n");
|
||||
|
||||
for(int s = eShaderStage_First; s < eShaderStage_Count; s++)
|
||||
{
|
||||
statisticsLog.append(QString("%1 calls: %2, non-null sampler sets: %3, null sampler sets: %4\n")
|
||||
.arg(ctx->CurPipelineState.Abbrev((ShaderStageType)s))
|
||||
.arg(totalSamplersPerStage[s].calls)
|
||||
.arg(totalSamplersPerStage[s].sets)
|
||||
.arg(totalSamplersPerStage[s].nulls));
|
||||
}
|
||||
|
||||
statisticsLog.append(
|
||||
QString("Total calls: %1, non-null sampler sets: %2, null sampler sets: %3\n")
|
||||
.arg(totalSamplersForAllStages.calls)
|
||||
.arg(totalSamplersForAllStages.sets)
|
||||
.arg(totalSamplersForAllStages.nulls));
|
||||
|
||||
statisticsLog.append(CreateSimpleIntegerHistogram(
|
||||
"Aggregate slot counts per invocation across all stages", totalSamplersForAllStages.bindslots));
|
||||
}
|
||||
|
||||
void AppendResourceBindStatistics(CaptureContext *ctx, QString &statisticsLog,
|
||||
const FetchFrameInfo &frameInfo)
|
||||
{
|
||||
// #mivance see AppendConstantBindStatistics
|
||||
const FetchFrameResourceBindStats &reference = frameInfo.stats.resources[0];
|
||||
|
||||
FetchFrameResourceBindStats totalResourcesPerStage[eShaderStage_Count] = {};
|
||||
for(int s = eShaderStage_First; s < eShaderStage_Count; s++)
|
||||
{
|
||||
totalResourcesPerStage[s].types.create(reference.types.count);
|
||||
totalResourcesPerStage[s].bindslots.create(reference.bindslots.count);
|
||||
}
|
||||
|
||||
{
|
||||
const FetchFrameResourceBindStats *resources = frameInfo.stats.resources;
|
||||
for(int s = eShaderStage_First; s < eShaderStage_Count; s++)
|
||||
{
|
||||
totalResourcesPerStage[s].calls += resources[s].calls;
|
||||
totalResourcesPerStage[s].sets += resources[s].sets;
|
||||
totalResourcesPerStage[s].nulls += resources[s].nulls;
|
||||
|
||||
for(int z = 0; z < resources[s].types.count; z++)
|
||||
{
|
||||
totalResourcesPerStage[s].types[z] += resources[s].types[z];
|
||||
}
|
||||
|
||||
for(int l = 0; l < resources[s].bindslots.count; l++)
|
||||
{
|
||||
totalResourcesPerStage[s].bindslots[l] += resources[s].bindslots[l];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FetchFrameResourceBindStats totalResourcesForAllStages = {};
|
||||
totalResourcesForAllStages.types.create(totalResourcesPerStage[0].types.count);
|
||||
totalResourcesForAllStages.bindslots.create(totalResourcesPerStage[0].bindslots.count);
|
||||
|
||||
for(int s = eShaderStage_First; s < eShaderStage_Count; s++)
|
||||
{
|
||||
FetchFrameResourceBindStats perStage = totalResourcesPerStage[s];
|
||||
totalResourcesForAllStages.calls += perStage.calls;
|
||||
totalResourcesForAllStages.sets += perStage.sets;
|
||||
totalResourcesForAllStages.nulls += perStage.nulls;
|
||||
for(int t = 0; t < perStage.types.count; t++)
|
||||
{
|
||||
totalResourcesForAllStages.types[t] += perStage.types[t];
|
||||
}
|
||||
for(int l = 0; l < perStage.bindslots.count; l++)
|
||||
{
|
||||
totalResourcesForAllStages.bindslots[l] += perStage.bindslots[l];
|
||||
}
|
||||
}
|
||||
|
||||
statisticsLog.append("\n*** Resource Bind Statistics ***\n\n");
|
||||
|
||||
for(int s = eShaderStage_First; s < eShaderStage_Count; s++)
|
||||
{
|
||||
statisticsLog.append(QString("%1 calls: %2 non-null resource sets: %3 null resource sets: %4\n")
|
||||
.arg(ctx->CurPipelineState.Abbrev((ShaderStageType)s))
|
||||
.arg(totalResourcesPerStage[s].calls)
|
||||
.arg(totalResourcesPerStage[s].sets)
|
||||
.arg(totalResourcesPerStage[s].nulls));
|
||||
}
|
||||
|
||||
statisticsLog.append(
|
||||
QString("Total calls: %1 non-null resource sets: %2 null resource sets: %3\n")
|
||||
.arg(totalResourcesForAllStages.calls)
|
||||
.arg(totalResourcesForAllStages.sets)
|
||||
.arg(totalResourcesForAllStages.nulls));
|
||||
|
||||
uint32_t maxCount = 0;
|
||||
int maxWithCount = 0;
|
||||
|
||||
statisticsLog.append("\nResource types across all stages:\n");
|
||||
for(int s = 0; s < totalResourcesForAllStages.types.count; s++)
|
||||
{
|
||||
uint32_t count = totalResourcesForAllStages.types[s];
|
||||
if(count > 0)
|
||||
maxWithCount = s;
|
||||
maxCount = qMax(maxCount, count);
|
||||
}
|
||||
|
||||
for(int s = 0; s <= maxWithCount; s++)
|
||||
{
|
||||
uint32_t count = totalResourcesForAllStages.types[s];
|
||||
int slice = SliceForString(Stars, count, maxCount);
|
||||
ShaderResourceType type = (ShaderResourceType)s;
|
||||
statisticsLog.append(
|
||||
QString("%1: %2 %3\n").arg(ToQStr(type), 20).arg(Stars.left(slice)).arg(CountOrEmpty(count)));
|
||||
}
|
||||
|
||||
statisticsLog.append(CreateSimpleIntegerHistogram(
|
||||
"Aggregate slot counts per invocation across all stages", totalResourcesForAllStages.bindslots));
|
||||
}
|
||||
|
||||
void AppendUpdateStatistics(QString &statisticsLog, const FetchFrameInfo &frameInfo)
|
||||
{
|
||||
// #mivance see AppendConstantBindStatistics
|
||||
const FetchFrameUpdateStats &reference = frameInfo.stats.updates;
|
||||
|
||||
FetchFrameUpdateStats totalUpdates = {};
|
||||
totalUpdates.types.create(reference.types.count);
|
||||
totalUpdates.sizes.create(reference.sizes.count);
|
||||
|
||||
{
|
||||
FetchFrameUpdateStats updates = frameInfo.stats.updates;
|
||||
|
||||
totalUpdates.calls += updates.calls;
|
||||
totalUpdates.clients += updates.clients;
|
||||
totalUpdates.servers += updates.servers;
|
||||
|
||||
for(int t = 0; t < updates.types.count; t++)
|
||||
totalUpdates.types[t] += updates.types[t];
|
||||
|
||||
for(int t = 0; t < updates.sizes.count; t++)
|
||||
totalUpdates.sizes[t] += updates.sizes[t];
|
||||
}
|
||||
|
||||
statisticsLog.append("\n*** Resource Update Statistics ***\n\n");
|
||||
|
||||
statisticsLog.append(
|
||||
QString("Total calls: %1, client-updated memory: %2, server-updated memory: %3\n")
|
||||
.arg(totalUpdates.calls)
|
||||
.arg(totalUpdates.clients)
|
||||
.arg(totalUpdates.servers));
|
||||
|
||||
statisticsLog.append("\nUpdated resource types:\n");
|
||||
uint32_t maxCount = 0;
|
||||
int maxWithValue = 0;
|
||||
for(int s = 1; s < totalUpdates.types.count; s++)
|
||||
{
|
||||
uint32_t value = totalUpdates.types[s];
|
||||
if(value > 0)
|
||||
maxWithValue = s;
|
||||
maxCount = qMax(maxCount, value);
|
||||
}
|
||||
|
||||
for(int s = 1; s <= maxWithValue; s++)
|
||||
{
|
||||
uint32_t count = totalUpdates.types[s];
|
||||
int slice = SliceForString(Stars, count, maxCount);
|
||||
ShaderResourceType type = (ShaderResourceType)s;
|
||||
statisticsLog.append(
|
||||
QString("%1: %2 %3\n").arg(ToQStr(type), 20).arg(Stars.left(slice)).arg(CountOrEmpty(count)));
|
||||
}
|
||||
|
||||
statisticsLog.append("\nUpdated resource sizes:\n");
|
||||
maxCount = 0;
|
||||
maxWithValue = 0;
|
||||
for(int s = 0; s < totalUpdates.sizes.count; s++)
|
||||
{
|
||||
uint32_t value = totalUpdates.sizes[s];
|
||||
if(value > 0)
|
||||
maxWithValue = s;
|
||||
maxCount = qMax(maxCount, value);
|
||||
}
|
||||
|
||||
for(int s = 0; s <= maxWithValue; s++)
|
||||
{
|
||||
uint32_t count = totalUpdates.sizes[s];
|
||||
int slice = SliceForString(Stars, count, maxCount);
|
||||
statisticsLog.append(QString("%1: %2 %3\n")
|
||||
.arg(Pow2IndexAsReadable(s), 8)
|
||||
.arg(Stars.left(slice))
|
||||
.arg(CountOrEmpty(count)));
|
||||
}
|
||||
}
|
||||
|
||||
void AppendBlendStatistics(QString &statisticsLog, const FetchFrameInfo &frameInfo)
|
||||
{
|
||||
FetchFrameBlendStats blends = frameInfo.stats.blends;
|
||||
statisticsLog.append("\n*** Blend Statistics ***\n");
|
||||
statisticsLog.append(
|
||||
QString("Blend calls: %1 non-null sets: %2, null (default) sets: %3, redundant sets: %4\n")
|
||||
.arg(blends.calls)
|
||||
.arg(blends.sets)
|
||||
.arg(blends.nulls)
|
||||
.arg(blends.redundants));
|
||||
}
|
||||
|
||||
void AppendDepthStencilStatistics(QString &statisticsLog, const FetchFrameInfo &frameInfo)
|
||||
{
|
||||
FetchFrameDepthStencilStats depths = frameInfo.stats.depths;
|
||||
statisticsLog.append("\n*** Depth Stencil Statistics ***\n");
|
||||
statisticsLog.append(QString("Depth/stencil calls: %1 non-null sets: %2, null (default) sets: "
|
||||
"%3, redundant sets: %4\n")
|
||||
.arg(depths.calls)
|
||||
.arg(depths.sets)
|
||||
.arg(depths.nulls)
|
||||
.arg(depths.redundants));
|
||||
}
|
||||
|
||||
void AppendRasterizationStatistics(QString &statisticsLog, const FetchFrameInfo &frameInfo)
|
||||
{
|
||||
FetchFrameRasterizationStats rasters = frameInfo.stats.rasters;
|
||||
statisticsLog.append("\n*** Rasterization Statistics ***\n");
|
||||
statisticsLog.append(QString("Rasterization calls: %1 non-null sets: %2, null (default) sets: "
|
||||
"%3, redundant sets: %4\n")
|
||||
.arg(rasters.calls)
|
||||
.arg(rasters.sets)
|
||||
.arg(rasters.nulls)
|
||||
.arg(rasters.redundants));
|
||||
statisticsLog.append(CreateSimpleIntegerHistogram("Viewports set", rasters.viewports));
|
||||
statisticsLog.append(CreateSimpleIntegerHistogram("Scissors set", rasters.rects));
|
||||
}
|
||||
|
||||
void AppendOutputStatistics(QString &statisticsLog, const FetchFrameInfo &frameInfo)
|
||||
{
|
||||
FetchFrameOutputStats outputs = frameInfo.stats.outputs;
|
||||
statisticsLog.append("\n*** Output Statistics ***\n");
|
||||
statisticsLog.append(QString("Output calls: %1 non-null sets: %2, null sets: %3\n")
|
||||
.arg(outputs.calls)
|
||||
.arg(outputs.sets)
|
||||
.arg(outputs.nulls));
|
||||
statisticsLog.append(CreateSimpleIntegerHistogram("Outputs set", outputs.bindslots));
|
||||
}
|
||||
|
||||
void AppendDetailedInformation(CaptureContext *ctx, QString &statisticsLog,
|
||||
const FetchFrameInfo &frameInfo)
|
||||
{
|
||||
if(frameInfo.stats.recorded == 0)
|
||||
return;
|
||||
|
||||
AppendDrawStatistics(statisticsLog, frameInfo);
|
||||
AppendDispatchStatistics(statisticsLog, frameInfo);
|
||||
AppendInputAssemblerStatistics(statisticsLog, frameInfo);
|
||||
AppendShaderStatistics(ctx, statisticsLog, frameInfo);
|
||||
AppendConstantBindStatistics(ctx, statisticsLog, frameInfo);
|
||||
AppendSamplerBindStatistics(ctx, statisticsLog, frameInfo);
|
||||
AppendResourceBindStatistics(ctx, statisticsLog, frameInfo);
|
||||
AppendBlendStatistics(statisticsLog, frameInfo);
|
||||
AppendDepthStencilStatistics(statisticsLog, frameInfo);
|
||||
AppendRasterizationStatistics(statisticsLog, frameInfo);
|
||||
AppendUpdateStatistics(statisticsLog, frameInfo);
|
||||
AppendOutputStatistics(statisticsLog, frameInfo);
|
||||
}
|
||||
|
||||
void CountContributingEvents(const FetchDrawcall &draw, uint32_t &drawCount,
|
||||
uint32_t &dispatchCount, uint32_t &diagnosticCount)
|
||||
{
|
||||
const uint32_t diagnosticMask = eDraw_SetMarker | eDraw_PushMarker | eDraw_PopMarker;
|
||||
uint32_t diagnosticMasked = draw.flags & diagnosticMask;
|
||||
|
||||
if(diagnosticMasked != 0)
|
||||
diagnosticCount += 1;
|
||||
|
||||
if((draw.flags & eDraw_Drawcall) != 0)
|
||||
drawCount += 1;
|
||||
|
||||
if((draw.flags & eDraw_Dispatch) != 0)
|
||||
dispatchCount += 1;
|
||||
|
||||
for(const FetchDrawcall &c : draw.children)
|
||||
CountContributingEvents(c, drawCount, dispatchCount, diagnosticCount);
|
||||
}
|
||||
|
||||
QString AppendAPICallSummary(const FetchFrameInfo &frameInfo, uint numAPICalls)
|
||||
{
|
||||
if(frameInfo.stats.recorded == 0)
|
||||
return "";
|
||||
|
||||
uint numConstantSets = 0;
|
||||
uint numSamplerSets = 0;
|
||||
uint numResourceSets = 0;
|
||||
uint numShaderSets = 0;
|
||||
|
||||
for(int s = eShaderStage_First; s < eShaderStage_Count; s++)
|
||||
{
|
||||
numConstantSets += frameInfo.stats.constants[s].calls;
|
||||
numSamplerSets += frameInfo.stats.samplers[s].calls;
|
||||
numResourceSets += frameInfo.stats.resources[s].calls;
|
||||
numShaderSets += frameInfo.stats.shaders[s].calls;
|
||||
}
|
||||
|
||||
uint numResourceUpdates = frameInfo.stats.updates.calls;
|
||||
uint numIndexVertexSets = (frameInfo.stats.indices.calls + frameInfo.stats.vertices.calls +
|
||||
frameInfo.stats.layouts.calls);
|
||||
uint numBlendSets = frameInfo.stats.blends.calls;
|
||||
uint numDepthStencilSets = frameInfo.stats.depths.calls;
|
||||
uint numRasterizationSets = frameInfo.stats.rasters.calls;
|
||||
uint numOutputSets = frameInfo.stats.outputs.calls;
|
||||
|
||||
QString calls;
|
||||
calls += QString("API calls: %1\n").arg(numAPICalls);
|
||||
calls += QString("\tIndex/vertex bind calls: %1\n").arg(numIndexVertexSets);
|
||||
calls += QString("\tConstant bind calls: %1\n").arg(numConstantSets);
|
||||
calls += QString("\tSampler bind calls: %1\n").arg(numSamplerSets);
|
||||
calls += QString("\tResource bind calls: %1\n").arg(numResourceSets);
|
||||
calls += QString("\tShader set calls: %1\n").arg(numShaderSets);
|
||||
calls += QString("\tBlend set calls: %1\n").arg(numBlendSets);
|
||||
calls += QString("\tDepth/stencil set calls: %1\n").arg(numDepthStencilSets);
|
||||
calls += QString("\tRasterization set calls: %1\n").arg(numRasterizationSets);
|
||||
calls += QString("\tResource update calls: %1\n").arg(numResourceUpdates);
|
||||
calls += QString("\tOutput set calls: %1\n").arg(numOutputSets);
|
||||
return calls;
|
||||
}
|
||||
|
||||
QString GenerateReport(CaptureContext *ctx)
|
||||
{
|
||||
QString statisticsLog;
|
||||
|
||||
const rdctype::array<FetchDrawcall> &curDraws = ctx->CurDrawcalls();
|
||||
|
||||
const FetchDrawcall *lastDraw = &curDraws.back();
|
||||
while(!lastDraw->children.empty())
|
||||
lastDraw = &lastDraw->children.back();
|
||||
|
||||
uint32_t drawCount = 0;
|
||||
uint32_t dispatchCount = 0;
|
||||
uint32_t diagnosticCount = 0;
|
||||
for(const FetchDrawcall &d : curDraws)
|
||||
CountContributingEvents(d, drawCount, dispatchCount, diagnosticCount);
|
||||
|
||||
uint32_t numAPIcalls = lastDraw->eventID - (drawCount + dispatchCount + diagnosticCount);
|
||||
|
||||
int numTextures = ctx->GetTextures().count;
|
||||
int numBuffers = ctx->GetBuffers().count;
|
||||
|
||||
uint64_t IBBytes = 0;
|
||||
uint64_t VBBytes = 0;
|
||||
uint64_t BufBytes = 0;
|
||||
for(const FetchBuffer &b : ctx->GetBuffers())
|
||||
{
|
||||
BufBytes += b.length;
|
||||
|
||||
if((b.creationFlags & eBufferCreate_IB) != 0)
|
||||
IBBytes += b.length;
|
||||
if((b.creationFlags & eBufferCreate_VB) != 0)
|
||||
VBBytes += b.length;
|
||||
}
|
||||
|
||||
uint64_t RTBytes = 0;
|
||||
uint64_t TexBytes = 0;
|
||||
uint64_t LargeTexBytes = 0;
|
||||
|
||||
int numRTs = 0;
|
||||
float texW = 0, texH = 0;
|
||||
float largeTexW = 0, largeTexH = 0;
|
||||
int texCount = 0, largeTexCount = 0;
|
||||
for(const FetchTexture &t : ctx->GetTextures())
|
||||
{
|
||||
if(t.creationFlags & (eTextureCreate_RTV | eTextureCreate_DSV))
|
||||
{
|
||||
numRTs++;
|
||||
|
||||
RTBytes += t.byteSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
texW += (float)t.width;
|
||||
texH += (float)t.height;
|
||||
texCount++;
|
||||
|
||||
TexBytes += t.byteSize;
|
||||
|
||||
if(t.width > 32 && t.height > 32)
|
||||
{
|
||||
largeTexW += (float)t.width;
|
||||
largeTexH += (float)t.height;
|
||||
largeTexCount++;
|
||||
|
||||
LargeTexBytes += t.byteSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
texW /= texCount;
|
||||
texH /= texCount;
|
||||
|
||||
largeTexW /= largeTexCount;
|
||||
largeTexH /= largeTexCount;
|
||||
|
||||
const FetchFrameInfo &frameInfo = ctx->FrameInfo();
|
||||
|
||||
float compressedMB = (float)frameInfo.compressedFileSize / (1024.0f * 1024.0f);
|
||||
float uncompressedMB = (float)frameInfo.uncompressedFileSize / (1024.0f * 1024.0f);
|
||||
float compressRatio = uncompressedMB / compressedMB;
|
||||
float persistentMB = (float)frameInfo.persistentSize / (1024.0f * 1024.0f);
|
||||
float initDataMB = (float)frameInfo.initDataSize / (1024.0f * 1024.0f);
|
||||
|
||||
QString header =
|
||||
QString(
|
||||
"Stats for %1.\n\nFile size: %2MB (%3MB uncompressed, compression ratio %4:1)\n"
|
||||
"Persistent Data (approx): %5MB, Frame-initial data (approx): %6MB\n")
|
||||
.arg(QFileInfo(ctx->LogFilename()).fileName())
|
||||
.arg(compressedMB, 2, 'f', 2)
|
||||
.arg(uncompressedMB, 2, 'f', 2)
|
||||
.arg(compressRatio, 2, 'f', 2)
|
||||
.arg(persistentMB, 2, 'f', 2)
|
||||
.arg(initDataMB, 2, 'f', 2);
|
||||
QString drawList =
|
||||
QString("Draw calls: %1\nDispatch calls: %2\n").arg(drawCount).arg(dispatchCount);
|
||||
QString calls = AppendAPICallSummary(frameInfo, numAPIcalls);
|
||||
QString ratio = QString("API:Draw/Dispatch call ratio: %1\n\n")
|
||||
.arg((float)numAPIcalls / (float)(drawCount + dispatchCount));
|
||||
QString textures = QString(
|
||||
"%1 Textures - %2 MB (%3 MB over 32x32), %4 RTs - %5 MB.\n"
|
||||
"Avg. tex dimension: %6x%7 (%8x%9 over 32x32)\n")
|
||||
.arg(numTextures)
|
||||
.arg((float)TexBytes / (1024.0f * 1024.0f), 2, 'f', 2)
|
||||
.arg((float)LargeTexBytes / (1024.0f * 1024.0f), 2, 'f', 2)
|
||||
.arg(numRTs)
|
||||
.arg((float)RTBytes / (1024.0f * 1024.0f), 2, 'f', 2)
|
||||
.arg(texW)
|
||||
.arg(texH)
|
||||
.arg(largeTexW)
|
||||
.arg(largeTexH);
|
||||
QString buffers = QString("%1 Buffers - %2 MB total %3 MB IBs %4 MB VBs.\n")
|
||||
.arg(numBuffers)
|
||||
.arg((float)BufBytes / (1024.0f * 1024.0f), 2, 'f', 2)
|
||||
.arg((float)IBBytes / (1024.0f * 1024.0f), 2, 'f', 2)
|
||||
.arg((float)VBBytes / (1024.0f * 1024.0f), 2, 'f', 2);
|
||||
QString load = QString("%1 MB - Grand total GPU buffer + texture load.\n")
|
||||
.arg((float)(TexBytes + BufBytes + RTBytes) / (1024.0f * 1024.0f), 2, 'f', 2);
|
||||
|
||||
statisticsLog.append(header);
|
||||
|
||||
statisticsLog.append("\n*** Summary ***\n\n");
|
||||
statisticsLog.append(drawList);
|
||||
statisticsLog.append(calls);
|
||||
statisticsLog.append(ratio);
|
||||
statisticsLog.append(textures);
|
||||
statisticsLog.append(buffers);
|
||||
statisticsLog.append(load);
|
||||
|
||||
AppendDetailedInformation(ctx, statisticsLog, frameInfo);
|
||||
|
||||
return statisticsLog;
|
||||
}
|
||||
|
||||
StatisticsViewer::StatisticsViewer(CaptureContext *ctx, QWidget *parent)
|
||||
: QFrame(parent), ui(new Ui::StatisticsViewer)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
m_Ctx = ctx;
|
||||
|
||||
ui->statistics->setFont(QFontDatabase::systemFont(QFontDatabase::FixedFont));
|
||||
|
||||
m_Ctx->AddLogViewer(this);
|
||||
}
|
||||
|
||||
StatisticsViewer::~StatisticsViewer()
|
||||
{
|
||||
m_Ctx->windowClosed(this);
|
||||
|
||||
m_Ctx->RemoveLogViewer(this);
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void StatisticsViewer::OnLogfileClosed()
|
||||
{
|
||||
ui->statistics->clear();
|
||||
}
|
||||
|
||||
void StatisticsViewer::OnLogfileLoaded()
|
||||
{
|
||||
ui->statistics->setText(GenerateReport(m_Ctx));
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/******************************************************************************
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2017 Baldur Karlsson
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QFrame>
|
||||
#include "Code/CaptureContext.h"
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class StatisticsViewer;
|
||||
}
|
||||
|
||||
class StatisticsViewer : public QFrame, public ILogViewerForm
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit StatisticsViewer(CaptureContext *ctx, QWidget *parent = 0);
|
||||
~StatisticsViewer();
|
||||
|
||||
void OnLogfileLoaded();
|
||||
void OnLogfileClosed();
|
||||
void OnSelectedEventChanged(uint32_t eventID) {}
|
||||
void OnEventChanged(uint32_t eventID) {}
|
||||
private:
|
||||
Ui::StatisticsViewer *ui;
|
||||
CaptureContext *m_Ctx;
|
||||
};
|
||||
@@ -0,0 +1,43 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>StatisticsViewer</class>
|
||||
<widget class="QFrame" name="StatisticsViewer">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>300</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Statistics</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<property name="leftMargin">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QTextEdit" name="statistics">
|
||||
<property name="cursor" stdset="0">
|
||||
<cursorShape>IBeamCursor</cursorShape>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -132,7 +132,8 @@ SOURCES += Code/qrenderdoc.cpp \
|
||||
Code/FormatElement.cpp \
|
||||
Windows/BufferViewer.cpp \
|
||||
Widgets/Extended/RDTableView.cpp \
|
||||
Windows/DebugMessageView.cpp
|
||||
Windows/DebugMessageView.cpp \
|
||||
Windows/StatisticsViewer.cpp
|
||||
|
||||
HEADERS += Code/CaptureContext.h \
|
||||
Code/qprocessinfo.h \
|
||||
@@ -169,7 +170,8 @@ HEADERS += Code/CaptureContext.h \
|
||||
Widgets/BufferFormatSpecifier.h \
|
||||
Windows/BufferViewer.h \
|
||||
Widgets/Extended/RDTableView.h \
|
||||
Windows/DebugMessageView.h
|
||||
Windows/DebugMessageView.h \
|
||||
Windows/StatisticsViewer.h
|
||||
|
||||
FORMS += Windows/Dialogs/AboutDialog.ui \
|
||||
Windows/MainWindow.ui \
|
||||
@@ -190,7 +192,8 @@ FORMS += Windows/Dialogs/AboutDialog.ui \
|
||||
Widgets/BufferFormatSpecifier.ui \
|
||||
Windows/BufferViewer.ui \
|
||||
Windows/ShaderViewer.ui \
|
||||
Windows/DebugMessageView.ui
|
||||
Windows/DebugMessageView.ui \
|
||||
Windows/StatisticsViewer.ui
|
||||
|
||||
RESOURCES += resources.qrc
|
||||
|
||||
|
||||
@@ -520,6 +520,7 @@
|
||||
<ClCompile Include="generated\moc_ScintillaEditBase.cpp" />
|
||||
<ClCompile Include="generated\moc_ScintillaQt.cpp" />
|
||||
<ClCompile Include="generated\moc_ShaderViewer.cpp" />
|
||||
<ClCompile Include="generated\moc_StatisticsViewer.cpp" />
|
||||
<ClCompile Include="generated\moc_TextureGoto.cpp" />
|
||||
<ClCompile Include="generated\moc_TextureSaveDialog.cpp" />
|
||||
<ClCompile Include="generated\moc_TextureViewer.cpp" />
|
||||
@@ -563,6 +564,7 @@
|
||||
<ClCompile Include="Windows\PipelineState\PipelineStateViewer.cpp" />
|
||||
<ClCompile Include="Windows\PipelineState\VulkanPipelineStateViewer.cpp" />
|
||||
<ClCompile Include="Windows\ShaderViewer.cpp" />
|
||||
<ClCompile Include="Windows\StatisticsViewer.cpp" />
|
||||
<ClCompile Include="Windows\TextureViewer.cpp" />
|
||||
<ClCompile Include="3rdparty\toolwindowmanager\ToolWindowManager.cpp">
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
@@ -660,6 +662,7 @@
|
||||
<ClInclude Include="generated\ui_PipelineStateViewer.h" />
|
||||
<ClInclude Include="generated\ui_ResourcePreview.h" />
|
||||
<ClInclude Include="generated\ui_ShaderViewer.h" />
|
||||
<ClInclude Include="generated\ui_StatisticsViewer.h" />
|
||||
<ClInclude Include="generated\ui_TextureSaveDialog.h" />
|
||||
<ClInclude Include="generated\ui_TextureViewer.h" />
|
||||
<ClInclude Include="generated\ui_ThumbnailStrip.h" />
|
||||
@@ -697,6 +700,7 @@
|
||||
<ClInclude Include="Windows\PipelineState\PipelineStateViewer.h" />
|
||||
<ClInclude Include="Windows\PipelineState\VulkanPipelineStateViewer.h" />
|
||||
<ClInclude Include="Windows\ShaderViewer.h" />
|
||||
<ClInclude Include="Windows\StatisticsViewer.h" />
|
||||
<ClInclude Include="Windows\TextureViewer.h" />
|
||||
<ClInclude Include="3rdparty\toolwindowmanager\ToolWindowManager.h" />
|
||||
<ClInclude Include="3rdparty\toolwindowmanager\ToolWindowManagerArea.h" />
|
||||
@@ -722,6 +726,7 @@
|
||||
<None Include="Windows\PipelineState\PipelineStateViewer.ui" />
|
||||
<None Include="Windows\PipelineState\VulkanPipelineStateViewer.ui" />
|
||||
<None Include="Windows\ShaderViewer.ui" />
|
||||
<None Include="Windows\StatisticsViewer.ui" />
|
||||
<None Include="Windows\TextureViewer.ui" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
||||
@@ -472,6 +472,12 @@
|
||||
<ClCompile Include="generated\moc_DebugMessageView.cpp">
|
||||
<Filter>Generated Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="generated\moc_StatisticsViewer.cpp">
|
||||
<Filter>Generated Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Windows\StatisticsViewer.cpp">
|
||||
<Filter>Generated Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="3rdparty\flowlayout\FlowLayout.h">
|
||||
@@ -837,6 +843,12 @@
|
||||
<ClInclude Include="generated\ui_DebugMessageView.h">
|
||||
<Filter>Generated Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="generated\ui_StatisticsViewer.h">
|
||||
<Filter>Generated Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Windows\StatisticsViewer.h">
|
||||
<Filter>Generated Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="resources.qrc">
|
||||
@@ -1074,6 +1086,7 @@
|
||||
<Filter>Windows</Filter>
|
||||
</None>
|
||||
<None Include="Windows\DebugMessageView.ui" />
|
||||
<None Include="Windows\StatisticsViewer.ui" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="generated\ui_AboutDialog.h">
|
||||
|
||||
@@ -126,6 +126,21 @@ struct array
|
||||
return *this;
|
||||
}
|
||||
|
||||
void create(int sz)
|
||||
{
|
||||
Delete();
|
||||
count = sz;
|
||||
if(sz == 0)
|
||||
{
|
||||
elems = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
elems = (T *)allocate(sizeof(T) * count);
|
||||
memset(elems, 0, sizeof(T) * count);
|
||||
}
|
||||
}
|
||||
|
||||
// provide some of the familiar stl interface
|
||||
size_t size() const { return (size_t)count; }
|
||||
void clear() { Delete(); }
|
||||
|
||||
Reference in New Issue
Block a user