diff --git a/interface/resources/qml/Stats.qml b/interface/resources/qml/Stats.qml
index 1c5df5c71d..9c55b1ce2d 100644
--- a/interface/resources/qml/Stats.qml
+++ b/interface/resources/qml/Stats.qml
@@ -189,6 +189,15 @@ Item {
Column {
id: octreeCol
spacing: 4; x: 4; y: 4;
+ StatText {
+ text: " Frame timing:"
+ }
+ StatText {
+ text: " Batch: " + root.batchFrameTime.toFixed(1) + " ms"
+ }
+ StatText {
+ text: " GPU: " + root.gpuFrameTime.toFixed(1) + " ms"
+ }
StatText {
text: "Triangles: " + root.triangles +
" / Material Switches: " + root.materialSwitches
diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp
index 16e6461631..8408d2cf46 100644
--- a/interface/src/Application.cpp
+++ b/interface/src/Application.cpp
@@ -1238,7 +1238,10 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
auto glInfo = getGLContextData();
properties["gl_info"] = glInfo;
+ properties["gpu_used_memory"] = (int)BYTES_TO_MB(gpu::Context::getUsedGPUMemory());
properties["gpu_free_memory"] = (int)BYTES_TO_MB(gpu::Context::getFreeGPUMemory());
+ properties["gpu_frame_time"] = (float)(qApp->getGPUContext()->getFrameTimerGPUAverage());
+ properties["batch_frame_time"] = (float)(qApp->getGPUContext()->getFrameTimerBatchAverage());
properties["ideal_thread_count"] = QThread::idealThreadCount();
auto hmdHeadPose = getHMDSensorPose();
diff --git a/interface/src/ui/Stats.cpp b/interface/src/ui/Stats.cpp
index 05632cb1e6..edf72d9758 100644
--- a/interface/src/ui/Stats.cpp
+++ b/interface/src/ui/Stats.cpp
@@ -290,6 +290,12 @@ void Stats::updateStats(bool force) {
STAT_UPDATE(sendingMode, sendingModeResult);
}
+ auto gpuContext = qApp->getGPUContext();
+
+ // Update Frame timing (in ms)
+ STAT_UPDATE(gpuFrameTime, (float)gpuContext->getFrameTimerGPUAverage());
+ STAT_UPDATE(batchFrameTime, (float)gpuContext->getFrameTimerBatchAverage());
+
STAT_UPDATE(gpuBuffers, (int)gpu::Context::getBufferGPUCount());
STAT_UPDATE(gpuBufferMemory, (int)BYTES_TO_MB(gpu::Context::getBufferGPUMemoryUsage()));
STAT_UPDATE(gpuTextures, (int)gpu::Context::getTextureGPUCount());
@@ -302,7 +308,7 @@ void Stats::updateStats(bool force) {
STAT_UPDATE(gpuTextureVirtualMemory, (int)BYTES_TO_MB(gpu::Texture::getTextureGPUVirtualMemoryUsage()));
STAT_UPDATE(gpuTextureFramebufferMemory, (int)BYTES_TO_MB(gpu::Texture::getTextureGPUFramebufferMemoryUsage()));
STAT_UPDATE(gpuTextureSparseMemory, (int)BYTES_TO_MB(gpu::Texture::getTextureGPUSparseMemoryUsage()));
- STAT_UPDATE(gpuSparseTextureEnabled, qApp->getGPUContext()->getBackend()->isTextureManagementSparseEnabled() ? 1 : 0);
+ STAT_UPDATE(gpuSparseTextureEnabled, gpuContext->getBackend()->isTextureManagementSparseEnabled() ? 1 : 0);
STAT_UPDATE(gpuFreeMemory, (int)BYTES_TO_MB(gpu::Context::getFreeGPUMemory()));
STAT_UPDATE(rectifiedTextureCount, (int)RECTIFIED_TEXTURE_COUNT.load());
STAT_UPDATE(decimatedTextureCount, (int)DECIMATED_TEXTURE_COUNT.load());
diff --git a/interface/src/ui/Stats.h b/interface/src/ui/Stats.h
index 76c6effed7..ffa5c08bc6 100644
--- a/interface/src/ui/Stats.h
+++ b/interface/src/ui/Stats.h
@@ -101,6 +101,8 @@ class Stats : public QQuickItem {
STATS_PROPERTY(int, gpuTextureSparseMemory, 0)
STATS_PROPERTY(int, gpuSparseTextureEnabled, 0)
STATS_PROPERTY(int, gpuFreeMemory, 0)
+ STATS_PROPERTY(float, gpuFrameTime, 0)
+ STATS_PROPERTY(float, batchFrameTime, 0)
public:
static Stats* getInstance();
@@ -198,6 +200,8 @@ signals:
void gpuTextureSparseMemoryChanged();
void gpuSparseTextureEnabledChanged();
void gpuFreeMemoryChanged();
+ void gpuFrameTimeChanged();
+ void batchFrameTimeChanged();
void rectifiedTextureCountChanged();
void decimatedTextureCountChanged();
diff --git a/libraries/gpu/src/gpu/Context.cpp b/libraries/gpu/src/gpu/Context.cpp
index ab6bba178a..4344cd4d2c 100644
--- a/libraries/gpu/src/gpu/Context.cpp
+++ b/libraries/gpu/src/gpu/Context.cpp
@@ -34,6 +34,10 @@ void Context::beginFrame(const glm::mat4& renderPose) {
_frameActive = true;
_currentFrame = std::make_shared();
_currentFrame->pose = renderPose;
+
+ if (!_frameRangeTimer) {
+ _frameRangeTimer = std::make_shared();
+ }
}
void Context::appendFrameBatch(Batch& batch) {
@@ -73,10 +77,18 @@ void Context::executeFrame(const FramePointer& frame) const {
consumeFrameUpdates(frame);
_backend->setStereoState(frame->stereoState);
{
+ Batch beginBatch;
+ _frameRangeTimer->begin(beginBatch);
+ _backend->render(beginBatch);
+
// Execute the frame rendering commands
for (auto& batch : frame->batches) {
_backend->render(batch);
}
+
+ Batch endBatch;
+ _frameRangeTimer->end(endBatch);
+ _backend->render(endBatch);
}
}
@@ -127,6 +139,20 @@ void Context::getStats(ContextStats& stats) const {
_backend->getStats(stats);
}
+double Context::getFrameTimerGPUAverage() const {
+ if (_frameRangeTimer) {
+ return _frameRangeTimer->getGPUAverage();
+ }
+ return 0.0;
+}
+
+double Context::getFrameTimerBatchAverage() const {
+ if (_frameRangeTimer) {
+ return _frameRangeTimer->getBatchAverage();
+ }
+ return 0.0;
+}
+
const Backend::TransformCamera& Backend::TransformCamera::recomputeDerived(const Transform& xformView) const {
_projectionInverse = glm::inverse(_projection);
@@ -183,6 +209,10 @@ Size Context::getFreeGPUMemory() {
return _freeGPUMemory.load();
}
+Size Context::getUsedGPUMemory() {
+ return getTextureGPUMemoryUsage() + getBufferGPUMemoryUsage();
+};
+
void Context::incrementBufferGPUCount() {
static std::atomic max { 0 };
auto total = ++_bufferGPUCount;
@@ -349,3 +379,5 @@ void Backend::updateTextureGPUFramebufferMemoryUsage(Resource::Size prevObjectSi
void Backend::updateTextureGPUSparseMemoryUsage(Resource::Size prevObjectSize, Resource::Size newObjectSize) { Context::updateTextureGPUSparseMemoryUsage(prevObjectSize, newObjectSize); }
void Backend::incrementTextureGPUTransferCount() { Context::incrementTextureGPUTransferCount(); }
void Backend::decrementTextureGPUTransferCount() { Context::decrementTextureGPUTransferCount(); }
+
+
diff --git a/libraries/gpu/src/gpu/Context.h b/libraries/gpu/src/gpu/Context.h
index e174e9d728..3564655a3d 100644
--- a/libraries/gpu/src/gpu/Context.h
+++ b/libraries/gpu/src/gpu/Context.h
@@ -205,12 +205,16 @@ public:
void getStats(ContextStats& stats) const;
+ double getFrameTimerGPUAverage() const;
+ double getFrameTimerBatchAverage() const;
+
static uint32_t getBufferGPUCount();
static Size getBufferGPUMemoryUsage();
static uint32_t getTextureGPUCount();
static uint32_t getTextureGPUSparseCount();
static Size getFreeGPUMemory();
+ static Size getUsedGPUMemory();
static Size getTextureGPUMemoryUsage();
static Size getTextureGPUVirtualMemoryUsage();
static Size getTextureGPUFramebufferMemoryUsage();
@@ -223,8 +227,12 @@ protected:
std::shared_ptr _backend;
bool _frameActive { false };
FramePointer _currentFrame;
+ RangeTimerPointer _frameRangeTimer;
StereoState _stereo;
+ double getGPUAverage() const;
+ double getBatchAverage() const;
+
// This function can only be called by "static Shader::makeProgram()"
// makeProgramShader(...) make a program shader ready to be used in a Batch.
// It compiles the sub shaders, link them and defines the Slots and their bindings.