diff --git a/examples/utilities/tools/render/PlotPerf.qml b/examples/utilities/tools/render/PlotPerf.qml index dc5c16bf79..00b7848936 100644 --- a/examples/utilities/tools/render/PlotPerf.qml +++ b/examples/utilities/tools/render/PlotPerf.qml @@ -13,8 +13,8 @@ import QtQuick.Controls 1.4 Item { id: root - width: 400 height: 100 + property string title property var config property string parameters @@ -24,14 +24,15 @@ Item { property var valueScale: +inputs[0] property var valueUnit: inputs[1] property var valueNumDigits: inputs[2] + property var input_VALUE_OFFSET: 3 property var valueMax : 1 property var _values : new Array() property var tick : 0 function createValues() { - if (inputs.length > 3) { - for (var i = 3; i < inputs.length; i++) { + if (inputs.length > input_VALUE_OFFSET) { + for (var i = input_VALUE_OFFSET; i < inputs.length; i++) { var varProps = inputs[i].split("-") _values.push( { value: varProps[1], @@ -83,25 +84,26 @@ Item { } } onTriggerChanged: pullFreshValues() - + Canvas { id: mycanvas - width: 300 - height: 100 + anchors.fill:parent onPaint: { + var lineHeight = 12; + function displayValue(val) { return (val / root.valueScale).toFixed(root.valueNumDigits) + " " + root.valueUnit } function pixelFromVal(val) { - return height * (1 - (0.9) * val / valueMax); + return lineHeight + (height - lineHeight) * (1 - (0.9) * val / valueMax); } function plotValueHistory(ctx, valHistory, color) { var widthStep= width / (valHistory.length - 1); ctx.beginPath(); ctx.strokeStyle= color; // Green path - ctx.lineWidth="4"; + ctx.lineWidth="2"; ctx.moveTo(0, pixelFromVal(valHistory[i])); for (var i = 1; i < valHistory.length; i++) { @@ -110,21 +112,38 @@ Item { ctx.stroke(); } - function plotValueLegend(ctx, val, num) { - var lineHeight = 12; - ctx.font="14px Verdana"; - ctx.fillStyle = val.color; - ctx.fillText(displayValue(val.valueHistory[val.valueHistory.length -1]), 0, height - num * lineHeight); + function displayValueLegend(ctx, val, num) { + ctx.fillStyle = val.color; + var bestValue = val.valueHistory[val.valueHistory.length -1]; + ctx.textAlign = "right"; + ctx.fillText(displayValue(bestValue), width, height - num * lineHeight); + ctx.textAlign = "left"; + ctx.fillText(val.label, 0, height - num * lineHeight); } + + function displayTitle(ctx, text, maxVal) { + ctx.fillStyle = "grey"; + ctx.textAlign = "right"; + ctx.fillText(displayValue(maxVal), width, lineHeight); + + ctx.fillStyle = "white"; + ctx.textAlign = "left"; + ctx.fillText(text, 0, lineHeight); + } + var ctx = getContext("2d"); ctx.clearRect(0, 0, width, height); ctx.fillStyle = Qt.rgba(0, 0, 0, 0.4); ctx.fillRect(0, 0, width, height); + ctx.font="12px Verdana"; + for (var i = 0; i < _values.length; i++) { plotValueHistory(ctx, _values[i].valueHistory, _values[i].color) - plotValueLegend(ctx, _values[i], i) + displayValueLegend(ctx, _values[i], i) } + + displayTitle(ctx, title, valueMax) } } } diff --git a/examples/utilities/tools/render/renderStats.js b/examples/utilities/tools/render/renderStats.js index da12ad1b31..2e8487ca34 100644 --- a/examples/utilities/tools/render/renderStats.js +++ b/examples/utilities/tools/render/renderStats.js @@ -14,7 +14,8 @@ var qml = Script.resolvePath('stats.qml'); var window = new OverlayWindow({ title: 'Render Stats', source: qml, - width: 300 + width: 300, + height: 200 }); window.setPosition(500, 50); window.closed.connect(function() { Script.stop(); }); \ No newline at end of file diff --git a/examples/utilities/tools/render/stats.qml b/examples/utilities/tools/render/stats.qml index 6edd3b7ae0..47c0f98568 100644 --- a/examples/utilities/tools/render/stats.qml +++ b/examples/utilities/tools/render/stats.qml @@ -13,20 +13,39 @@ import QtQuick.Controls 1.4 Column { + id: statsUI + width: 300 spacing: 8 Column { - spacing: 4 + spacing: 8 - id: stats property var config: Render.getConfig("Stats") + id: stats PlotPerf { + title: "Num Buffers" + width:statsUI.width config: stats.config - parameters: "1::0:num Textures-numTextures-blue:num GPU Textures-numGPUTextures-green" + parameters: "1::0:CPU-numBuffers-#00B4EF:GPU-numGPUBuffers-#1AC567" } PlotPerf { + title: "Memory Usage" + width:statsUI.width config: stats.config - parameters: "1048576:Mb:1:Sysmem-textureSysmemUsage-blue:Vidmem-textureVidmemUsage-green" + parameters: "1048576:Mb:1:CPU-bufferSysmemUsage-#00B4EF:GPU-bufferVidmemUsage-#1AC567" + } + + PlotPerf { + title: "Num Textures" + width:statsUI.width + config: stats.config + parameters: "1::0:CPU-numTextures-#00B4EF:GPU-numGPUTextures-#1AC567:Frame-numFrameTextures-#E2334D" + } + PlotPerf { + title: "Memory Usage" + width:statsUI.width + config: stats.config + parameters: "1048576:Mb:1:CPU-textureSysmemUsage-#00B4EF:GPU-textureVidmemUsage-#1AC567" } } } diff --git a/libraries/gpu/src/gpu/Context.cpp b/libraries/gpu/src/gpu/Context.cpp index dd26ab2823..6148994a1b 100644 --- a/libraries/gpu/src/gpu/Context.cpp +++ b/libraries/gpu/src/gpu/Context.cpp @@ -74,6 +74,11 @@ void Context::downloadFramebuffer(const FramebufferPointer& srcFramebuffer, cons _backend->downloadFramebuffer(srcFramebuffer, region, destImage); } + +void Context::getStats(ContextStats& stats) const { + _backend->getStats(stats); +} + const Backend::TransformCamera& Backend::TransformCamera::recomputeDerived(const Transform& xformView) const { _projectionInverse = glm::inverse(_projection); diff --git a/libraries/gpu/src/gpu/Context.h b/libraries/gpu/src/gpu/Context.h index d584f54acc..c4ad35020a 100644 --- a/libraries/gpu/src/gpu/Context.h +++ b/libraries/gpu/src/gpu/Context.h @@ -27,6 +27,21 @@ class QImage; namespace gpu { +struct ContextStats { +public: + int _ISNumFormatChanges = 0; + int _ISNumInputBufferChanges = 0; + int _ISNumIndexBufferChanges = 0; + + int _RSNumTextureBounded = 0; + + int _DSNumDrawcalls = 0; + int _DSNumTriangles = 0; + + ContextStats() {} + ContextStats(const ContextStats& stats) = default; +}; + struct StereoState { bool _enable{ false }; bool _skybox{ false }; @@ -100,9 +115,11 @@ public: return reinterpret_cast(object.gpuObject.getGPUObject()); } + void getStats(ContextStats& stats) const { stats = _stats; } protected: StereoState _stereo; + ContextStats _stats; }; class Context { @@ -125,6 +142,7 @@ public: ~Context(); void render(Batch& batch); + void enableStereo(bool enable = true); bool isStereo(); void setStereoProjections(const mat4 eyeProjections[2]); @@ -137,6 +155,9 @@ public: // It s here for convenience to easily capture a snapshot void downloadFramebuffer(const FramebufferPointer& srcFramebuffer, const Vec4i& region, QImage& destImage); + // Repporting stats of the context + void getStats(ContextStats& stats) const; + protected: Context(const Context& context); diff --git a/libraries/gpu/src/gpu/GLBackend.h b/libraries/gpu/src/gpu/GLBackend.h index d93962f5a1..c8e3be81d1 100644 --- a/libraries/gpu/src/gpu/GLBackend.h +++ b/libraries/gpu/src/gpu/GLBackend.h @@ -67,6 +67,8 @@ public: GLBuffer(); ~GLBuffer(); + + void setSize(GLuint size); }; static GLBuffer* syncGPUObject(const Buffer& buffer); static GLuint getBufferID(const Buffer& buffer); @@ -234,26 +236,11 @@ public: void do_setStateBlend(State::BlendFunction blendFunction); void do_setStateColorWriteMask(uint32 mask); - - // Repporting stats of the context - class Stats { - public: - int _ISNumFormatChanges = 0; - int _ISNumInputBufferChanges = 0; - int _ISNumIndexBufferChanges = 0; - - Stats() {} - Stats(const Stats& stats) = default; - }; - - void getStats(Stats& stats) const { stats = _stats; } - + protected: void renderPassTransfer(Batch& batch); void renderPassDraw(Batch& batch); - Stats _stats; - // Draw Stage void do_draw(Batch& batch, size_t paramOffset); void do_drawIndexed(Batch& batch, size_t paramOffset); diff --git a/libraries/gpu/src/gpu/GLBackendBuffer.cpp b/libraries/gpu/src/gpu/GLBackendBuffer.cpp index 49aeeca38e..56dd907b2e 100755 --- a/libraries/gpu/src/gpu/GLBackendBuffer.cpp +++ b/libraries/gpu/src/gpu/GLBackendBuffer.cpp @@ -16,12 +16,29 @@ GLBackend::GLBuffer::GLBuffer() : _stamp(0), _buffer(0), _size(0) -{} +{ + Buffer::_numGPUBuffers++; +} GLBackend::GLBuffer::~GLBuffer() { if (_buffer != 0) { glDeleteBuffers(1, &_buffer); } + Buffer::_bufferVideoMemoryUsage.fetch_sub(_size); + Buffer::_numGPUBuffers--; +} + +void GLBackend::GLBuffer::setSize(GLuint size) { + if (_size == size) { + return; + } + if (size > _size) { + Buffer::_bufferVideoMemoryUsage.fetch_add(size - _size); + } else { + Buffer::_bufferVideoMemoryUsage.fetch_sub(_size - size); + } + + _size = size; } GLBackend::GLBuffer* GLBackend::syncGPUObject(const Buffer& buffer) { @@ -46,7 +63,7 @@ GLBackend::GLBuffer* GLBackend::syncGPUObject(const Buffer& buffer) { glBufferData(GL_ARRAY_BUFFER, buffer.getSysmem().getSize(), buffer.getSysmem().readData(), GL_DYNAMIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, 0); object->_stamp = buffer.getSysmem().getStamp(); - object->_size = (GLuint)buffer.getSysmem().getSize(); + object->setSize((GLuint)buffer.getSysmem().getSize()); //} (void) CHECK_GL_ERROR(); diff --git a/libraries/gpu/src/gpu/GLBackendPipeline.cpp b/libraries/gpu/src/gpu/GLBackendPipeline.cpp index 8c9647e0f2..046f1ff0e5 100755 --- a/libraries/gpu/src/gpu/GLBackendPipeline.cpp +++ b/libraries/gpu/src/gpu/GLBackendPipeline.cpp @@ -251,6 +251,9 @@ void GLBackend::do_setResourceTexture(Batch& batch, size_t paramOffset) { return; } + // One more True texture bound + _stats._RSNumTextureBounded++; + // Always make sure the GLObject is in sync GLTexture* object = GLBackend::syncGPUObject(*resourceTexture); if (object) { diff --git a/libraries/gpu/src/gpu/Resource.cpp b/libraries/gpu/src/gpu/Resource.cpp index 197263f392..d0527d6d3a 100644 --- a/libraries/gpu/src/gpu/Resource.cpp +++ b/libraries/gpu/src/gpu/Resource.cpp @@ -232,19 +232,66 @@ Resource::Size Resource::Sysmem::append(Size size, const Byte* bytes) { return 0; } +std::atomic Buffer::_numBuffers{ 0 }; +std::atomic Buffer::_numGPUBuffers{ 0 }; +std::atomic Buffer::_bufferSystemMemoryUsage{ 0 }; +std::atomic Buffer::_bufferVideoMemoryUsage{ 0 }; + + +int Buffer::getCurrentNumBuffers() { + return _numBuffers.load(); +} + +Buffer::Size Buffer::getCurrentSystemMemoryUsage() { + return _bufferSystemMemoryUsage.load(); +} + +int Buffer::getCurrentNumGPUBuffers() { + return _numGPUBuffers.load(); +} + +Buffer::Size Buffer::getCurrentVideoMemoryUsage() { + return _bufferVideoMemoryUsage.load(); +} + +void Buffer::addSystemMemoryUsage(Size memorySize) { + _bufferSystemMemoryUsage.fetch_add(memorySize); +} +void Buffer::subSystemMemoryUsage(Size memorySize) { + _bufferSystemMemoryUsage.fetch_sub(memorySize); +} + +void Buffer::updateSystemMemoryUsage(Size prevObjectSize, Size newObjectSize) { + if (prevObjectSize == newObjectSize) { + return; + } + if (prevObjectSize > newObjectSize) { + subSystemMemoryUsage(prevObjectSize - newObjectSize); + } else { + addSystemMemoryUsage(newObjectSize - prevObjectSize); + } +} + + Buffer::Buffer() : Resource(), _sysmem(new Sysmem()) { + _numBuffers++; + } Buffer::Buffer(Size size, const Byte* bytes) : Resource(), _sysmem(new Sysmem(size, bytes)) { + _numBuffers++; + Buffer::updateSystemMemoryUsage(0, _sysmem->getSize()); } Buffer::Buffer(const Buffer& buf) : Resource(), _sysmem(new Sysmem(buf.getSysmem())) { + _numBuffers++; + Buffer::updateSystemMemoryUsage(0, _sysmem->getSize()); } Buffer& Buffer::operator=(const Buffer& buf) { @@ -253,18 +300,27 @@ Buffer& Buffer::operator=(const Buffer& buf) { } Buffer::~Buffer() { + _numBuffers--; + if (_sysmem) { + Buffer::updateSystemMemoryUsage(_sysmem->getSize(), 0); delete _sysmem; _sysmem = NULL; } } Buffer::Size Buffer::resize(Size size) { - return editSysmem().resize(size); + auto prevSize = editSysmem().getSize(); + auto newSize = editSysmem().resize(size); + Buffer::updateSystemMemoryUsage(prevSize, newSize); + return newSize; } Buffer::Size Buffer::setData(Size size, const Byte* data) { - return editSysmem().setData(size, data); + auto prevSize = editSysmem().getSize(); + auto newSize = editSysmem().setData(size, data); + Buffer::updateSystemMemoryUsage(prevSize, newSize); + return newSize; } Buffer::Size Buffer::setSubData(Size offset, Size size, const Byte* data) { @@ -272,6 +328,9 @@ Buffer::Size Buffer::setSubData(Size offset, Size size, const Byte* data) { } Buffer::Size Buffer::append(Size size, const Byte* data) { - return editSysmem().append( size, data); + auto prevSize = editSysmem().getSize(); + auto newSize = editSysmem().append( size, data); + Buffer::updateSystemMemoryUsage(prevSize, newSize); + return newSize; } diff --git a/libraries/gpu/src/gpu/Resource.h b/libraries/gpu/src/gpu/Resource.h index 3517b67203..d40e9131a1 100644 --- a/libraries/gpu/src/gpu/Resource.h +++ b/libraries/gpu/src/gpu/Resource.h @@ -16,6 +16,7 @@ #include "Format.h" #include +#include #include #ifdef _DEBUG @@ -109,7 +110,21 @@ protected: }; class Buffer : public Resource { + static std::atomic _numBuffers; + static std::atomic _bufferSystemMemoryUsage; public: + static std::atomic _numGPUBuffers; + static std::atomic _bufferVideoMemoryUsage; +private: + static void addSystemMemoryUsage(Size memorySize); + static void subSystemMemoryUsage(Size memorySize); + static void updateSystemMemoryUsage(Size prevObjectSize, Size newObjectSize); + +public: + static int getCurrentNumBuffers(); + static Size getCurrentSystemMemoryUsage(); + static int getCurrentNumGPUBuffers(); + static Size getCurrentVideoMemoryUsage(); Buffer(); Buffer(Size size, const Byte* bytes); diff --git a/libraries/gpu/src/gpu/Texture.cpp b/libraries/gpu/src/gpu/Texture.cpp index 7a0e198ec9..cb0ef20c6c 100755 --- a/libraries/gpu/src/gpu/Texture.cpp +++ b/libraries/gpu/src/gpu/Texture.cpp @@ -57,13 +57,6 @@ void Texture::updateSystemMemoryUsage(Size prevObjectSize, Size newObjectSize) { } } -void Texture::addVideoMemoryUsage(Size memorySize) { - _textureVideoMemoryUsage.fetch_add(memorySize); -} -void Texture::subVideoMemoryUsage(Size memorySize) { - _textureVideoMemoryUsage.fetch_sub(memorySize); -} - uint8 Texture::NUM_FACES_PER_TYPE[NUM_TYPES] = {1, 1, 1, 6}; Texture::Pixels::Pixels(const Element& format, Size size, const Byte* bytes) : diff --git a/libraries/gpu/src/gpu/Texture.h b/libraries/gpu/src/gpu/Texture.h index 06b0077458..087f305224 100755 --- a/libraries/gpu/src/gpu/Texture.h +++ b/libraries/gpu/src/gpu/Texture.h @@ -15,7 +15,6 @@ #include //min max and more #include -#include #include @@ -149,9 +148,6 @@ private: static void subSystemMemoryUsage(Size memorySize); static void updateSystemMemoryUsage(Size prevObjectSize, Size newObjectSize); - static void addVideoMemoryUsage(Size memorySize); - static void subVideoMemoryUsage(Size memorySize); - public: static int getCurrentNumTextures(); diff --git a/libraries/render/src/render/Engine.cpp b/libraries/render/src/render/Engine.cpp index 2118c3c734..b4ee713e74 100644 --- a/libraries/render/src/render/Engine.cpp +++ b/libraries/render/src/render/Engine.cpp @@ -67,10 +67,22 @@ void EngineStats::run(const SceneContextPointer& sceneContext, const RenderConte // Update the stats auto config = std::static_pointer_cast(renderContext->jobConfig); + config->numBuffers = gpu::Buffer::getCurrentNumBuffers(); + config->numGPUBuffers = gpu::Buffer::getCurrentNumGPUBuffers(); + config->bufferSysmemUsage = gpu::Buffer::getCurrentSystemMemoryUsage(); + config->bufferVidmemUsage = gpu::Buffer::getCurrentVideoMemoryUsage(); + config->numTextures = gpu::Texture::getCurrentNumTextures(); - config->textureSysmemUsage = gpu::Texture::getCurrentSystemMemoryUsage(); config->numGPUTextures = gpu::Texture::getCurrentNumGPUTextures(); + config->textureSysmemUsage = gpu::Texture::getCurrentSystemMemoryUsage(); config->textureVidmemUsage = gpu::Texture::getCurrentVideoMemoryUsage(); + gpu::ContextStats gpuStats(_gpuStats); + renderContext->args->_context->getStats(_gpuStats); + + config->numFrameTextures = _gpuStats._RSNumTextureBounded - gpuStats._RSNumTextureBounded; + + config->numFrameTriangles = _gpuStats._DSNumTriangles - gpuStats._DSNumTriangles; + config->emitDirty(); } diff --git a/libraries/render/src/render/Engine.h b/libraries/render/src/render/Engine.h index 71c52c5910..4fd29b5d66 100644 --- a/libraries/render/src/render/Engine.h +++ b/libraries/render/src/render/Engine.h @@ -13,10 +13,10 @@ #define hifi_render_Engine_h #include +#include #include "Context.h" #include "Task.h" - namespace render { // The render engine holds all render tasks, and is itself a render task. @@ -53,18 +53,33 @@ namespace render { // A simple job collecting global stats on the Engine / Scene / GPU class EngineStatsConfig : public Job::Config{ Q_OBJECT - Q_PROPERTY(int numTextures MEMBER numTextures NOTIFY dirty) - Q_PROPERTY(int numGPUTextures MEMBER numGPUTextures NOTIFY dirty) + + Q_PROPERTY(int numBuffers MEMBER numBuffers NOTIFY dirty) + Q_PROPERTY(int numGPUBuffers MEMBER numGPUBuffers NOTIFY dirty) + Q_PROPERTY(qint64 bufferSysmemUsage MEMBER bufferSysmemUsage NOTIFY dirty) + Q_PROPERTY(qint64 bufferVidmemUsage MEMBER bufferVidmemUsage NOTIFY dirty) + + Q_PROPERTY(int numTextures MEMBER numTextures NOTIFY dirty) + Q_PROPERTY(int numGPUTextures MEMBER numGPUTextures NOTIFY dirty) Q_PROPERTY(qint64 textureSysmemUsage MEMBER textureSysmemUsage NOTIFY dirty) Q_PROPERTY(qint64 textureVidmemUsage MEMBER textureVidmemUsage NOTIFY dirty) + Q_PROPERTY(int numFrameTextures MEMBER numFrameTextures NOTIFY dirty) public: EngineStatsConfig() : Job::Config(true) {} + int numBuffers{ 0 }; + int numGPUBuffers{ 0 }; + qint64 bufferSysmemUsage{ 0 }; + qint64 bufferVidmemUsage{ 0 }; + int numTextures{ 0 }; int numGPUTextures{ 0 }; qint64 textureSysmemUsage{ 0 }; qint64 textureVidmemUsage{ 0 }; + int numFrameTriangles{ 0 }; + int numFrameTextures{ 0 }; + void emitDirty() { emit dirty(); } signals: @@ -78,6 +93,8 @@ namespace render { EngineStats() {} + gpu::ContextStats _gpuStats; + void configure(const Config& configuration) {} void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext); };