Commit 4b571774 authored by Laszlo Agocs's avatar Laszlo Agocs

Add minimal, CBOR-based resource logging

Only complete for Metal atm.

The real nice part here is the inclusion of some additional calculations
(like approximate byte size for textures and such).
parent 2ee22020
......@@ -52,6 +52,14 @@
#include <QRhiMetalInitParams>
#include "examplewindow.h"
#define PROFILE
#ifdef PROFILE
#include <QRhiProfiler>
#include <QFile>
QFile profOut;
#endif
class MetalWindow : public ExampleWindow
{
public:
......@@ -65,7 +73,15 @@ private:
void MetalWindow::init()
{
QRhiMetalInitParams params;
m_r = QRhi::create(QRhi::Metal, &params, QRhi::EnableProfiling);
m_r = QRhi::create(QRhi::Metal, &params
#ifdef PROFILE
, QRhi::EnableProfiling
#endif
);
#ifdef PROFILE
m_r->profiler()->setOutputDevice(&profOut);
#endif
//setSampleCount(4); // enable 4x MSAA (except for the render-to-texture pass)
......@@ -77,6 +93,11 @@ int main(int argc, char **argv)
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
#ifdef PROFILE
profOut.setFileName("rhiprof.cbor");
profOut.open(QIODevice::WriteOnly);
#endif
MetalWindow w;
w.resize(1280, 720);
w.setTitle(QLatin1String("Metal"));
......
......@@ -366,6 +366,21 @@ void QRhiImplementation::textureFormatInfo(QRhiTexture::Format format, const QSi
*byteSize = size.width() * size.height() * bpc;
}
quint32 QRhiImplementation::approxByteSizeForTexture(QRhiTexture::Format format, const QSize &baseSize,
int mipCount, int layerCount)
{
quint32 approxSize = 0;
for (int level = 0; level < mipCount; ++level) {
quint32 byteSize = 0;
const QSize size(qFloor(float(qMax(1, baseSize.width() >> level))),
qFloor(float(qMax(1, baseSize.height() >> level))));
textureFormatInfo(format, size, nullptr, &byteSize);
approxSize += byteSize;
}
approxSize *= layerCount;
return approxSize;
}
QRhi::QRhi()
{
}
......@@ -657,7 +672,7 @@ const QRhiNativeHandles *QRhi::nativeHandles()
return d->nativeHandles();
}
const QRhiProfiler *QRhi::profiler() const
QRhiProfiler *QRhi::profiler()
{
return &d->profiler;
}
......
......@@ -1245,7 +1245,7 @@ public:
// Ownership of the native objects is not transfered.
const QRhiNativeHandles *nativeHandles();
const QRhiProfiler *profiler() const;
QRhiProfiler *profiler();
protected:
QRhi();
......
......@@ -139,6 +139,8 @@ public:
QSize *blockDim) const;
void textureFormatInfo(QRhiTexture::Format format, const QSize &size,
quint32 *bpl, quint32 *byteSize) const;
quint32 approxByteSizeForTexture(QRhiTexture::Format format, const QSize &baseSize,
int mipCount, int layerCount);
QRhiProfilerPrivate *profilerPrivateOrNull()
{
......
......@@ -1323,7 +1323,7 @@ bool QMetalRenderBuffer::build()
[desc release];
QRHI_PROF;
QRHI_PROF_F(newRenderBuffer(this, transientBacking, true));
QRHI_PROF_F(newRenderBuffer(this, transientBacking, false));
lastActiveFrameSlot = -1;
generation += 1;
......
......@@ -36,6 +36,7 @@
#include "qrhiprofiler_p.h"
#include "qrhi_p.h"
#include <QCborStreamWriter>
QT_BEGIN_NAMESPACE
......@@ -49,9 +50,14 @@ QRhiProfiler::~QRhiProfiler()
delete d;
}
const QRhiProfilerStream *QRhiProfiler::stream() const
void QRhiProfiler::setOutputDevice(QIODevice *device)
{
return nullptr; // ###
d->outputDevice = device;
}
void QRhiProfiler::flush()
{
d->flushStream();
}
void QRhiProfiler::addVMemAllocatorStats()
......@@ -60,63 +66,215 @@ void QRhiProfiler::addVMemAllocatorStats()
d->rhiD->sendVMemStatsToProfiler();
}
void QRhiProfilerPrivate::newBuffer(QRhiBuffer *buf, size_t realSize, int backingGpuBufCount, int backingCpuBufCount)
QRhiProfilerPrivate::~QRhiProfilerPrivate()
{
flushStream();
delete writer;
}
bool QRhiProfilerPrivate::ensureStream()
{
if (!outputDevice)
return false;
if (!writer) {
writer = new QCborStreamWriter(outputDevice);
active = false;
}
if (!active) {
writer->startArray();
active = true;
}
return true;
}
void QRhiProfilerPrivate::flushStream()
{
if (!active || !writer)
return;
// CborWriter is unbuffered so all we need to do here is to end the top-level array
writer->endArray();
active = false;
}
#define WRITE_PAIR(a, b) writer->append(a); writer->append(b)
void QRhiProfilerPrivate::newBuffer(QRhiBuffer *buf, quint32 realSize, int backingGpuBufCount, int backingCpuBufCount)
{
if (!ensureStream())
return;
writer->startMap();
WRITE_PAIR(QLatin1String("op"), QRhiProfiler::NewBuffer);
WRITE_PAIR(QLatin1String("buffer"), quint64(quintptr(buf)));
WRITE_PAIR(QLatin1String("type"), buf->type());
WRITE_PAIR(QLatin1String("usage"), buf->usage());
WRITE_PAIR(QLatin1String("logical_size"), buf->size());
WRITE_PAIR(QLatin1String("effective_size"), realSize);
WRITE_PAIR(QLatin1String("backing_gpu_buf_count"), backingGpuBufCount);
WRITE_PAIR(QLatin1String("backing_cpu_buf_count"), backingCpuBufCount);
writer->endMap();
}
void QRhiProfilerPrivate::releaseBuffer(QRhiBuffer *buf)
{
if (!ensureStream())
return;
writer->startMap();
WRITE_PAIR(QLatin1String("op"), QRhiProfiler::ReleaseBuffer);
WRITE_PAIR(QLatin1String("buffer"), quint64(quintptr(buf)));
writer->endMap();
}
void QRhiProfilerPrivate::newBufferStagingArea(QRhiBuffer *buf, int slot, size_t size)
void QRhiProfilerPrivate::newBufferStagingArea(QRhiBuffer *buf, int slot, quint32 size)
{
if (!ensureStream())
return;
writer->startMap();
WRITE_PAIR(QLatin1String("op"), QRhiProfiler::NewBufferStagingArea);
WRITE_PAIR(QLatin1String("buffer"), quint64(quintptr(buf)));
WRITE_PAIR(QLatin1String("slot"), slot);
WRITE_PAIR(QLatin1String("size"), size);
writer->endMap();
}
void QRhiProfilerPrivate::releaseBufferStagingArea(QRhiBuffer *buf, int slot)
{
if (!ensureStream())
return;
writer->startMap();
WRITE_PAIR(QLatin1String("op"), QRhiProfiler::ReleaseBufferStagingArea);
WRITE_PAIR(QLatin1String("buffer"), quint64(quintptr(buf)));
WRITE_PAIR(QLatin1String("slot"), slot);
writer->endMap();
}
void QRhiProfilerPrivate::newRenderBuffer(QRhiRenderBuffer *rb, bool transientBacking, bool winSysBacking)
{
// calc approx size
if (!ensureStream())
return;
writer->startMap();
WRITE_PAIR(QLatin1String("op"), QRhiProfiler::NewRenderBuffer);
WRITE_PAIR(QLatin1String("renderbuffer"), quint64(quintptr(rb)));
const QRhiRenderBuffer::Type type = rb->type();
const QSize sz = rb->pixelSize();
// just make up something, ds is likely D24S8 while color is RGBA8 or similar
const QRhiTexture::Format assumedFormat = type == QRhiRenderBuffer::DepthStencil ? QRhiTexture::D32 : QRhiTexture::RGBA8;
const quint32 byteSize = rhiD->approxByteSizeForTexture(assumedFormat, sz, 1, 1);
WRITE_PAIR(QLatin1String("type"), type);
WRITE_PAIR(QLatin1String("width"), sz.width());
WRITE_PAIR(QLatin1String("height"), sz.height());
WRITE_PAIR(QLatin1String("sample_count"), rb->sampleCount());
WRITE_PAIR(QLatin1String("transient_backing"), transientBacking);
WRITE_PAIR(QLatin1String("winsys_backing"), winSysBacking);
WRITE_PAIR(QLatin1String("approx_byte_size"), byteSize);
writer->endMap();
}
void QRhiProfilerPrivate::releaseRenderBuffer(QRhiRenderBuffer *rb)
{
if (!ensureStream())
return;
writer->startMap();
WRITE_PAIR(QLatin1String("op"), QRhiProfiler::ReleaseRenderBuffer);
WRITE_PAIR(QLatin1String("renderbuffer"), quint64(quintptr(rb)));
writer->endMap();
}
void QRhiProfilerPrivate::newTexture(QRhiTexture *tex, bool owns, int mipCount, int layerCount, int sampleCount)
{
// size_t approxSize = 0;
// for (int i = 0; i < mipLevelCount; ++i) {
// quint32 byteSize = 0;
// rhiD->textureFormatInfo(m_format, size, nullptr, &byteSize);
// approxSize += byteSize;
// }
// const int layerCount = isCube ? 6 : 1;
// approxSize *= layerCount;
if (!ensureStream())
return;
writer->startMap();
WRITE_PAIR(QLatin1String("op"), QRhiProfiler::NewTexture);
WRITE_PAIR(QLatin1String("texture"), quint64(quintptr(tex)));
const QRhiTexture::Format format = tex->format();
const QSize sz = tex->pixelSize();
const quint32 byteSize = rhiD->approxByteSizeForTexture(format, sz, mipCount, layerCount);
WRITE_PAIR(QLatin1String("width"), sz.width());
WRITE_PAIR(QLatin1String("height"), sz.height());
WRITE_PAIR(QLatin1String("format"), format);
WRITE_PAIR(QLatin1String("owns_native_resource"), owns);
WRITE_PAIR(QLatin1String("mip_count"), mipCount);
WRITE_PAIR(QLatin1String("layer_count"), layerCount);
WRITE_PAIR(QLatin1String("effective_sample_count"), sampleCount);
WRITE_PAIR(QLatin1String("approx_byte_size"), byteSize);
writer->endMap();
}
void QRhiProfilerPrivate::releaseTexture(QRhiTexture *tex)
{
if (!ensureStream())
return;
writer->startMap();
WRITE_PAIR(QLatin1String("op"), QRhiProfiler::ReleaseTexture);
WRITE_PAIR(QLatin1String("texture"), quint64(quintptr(tex)));
writer->endMap();
}
void QRhiProfilerPrivate::newTextureStagingArea(QRhiTexture *tex, int slot, size_t size)
void QRhiProfilerPrivate::newTextureStagingArea(QRhiTexture *tex, int slot, quint32 size)
{
if (!ensureStream())
return;
writer->startMap();
WRITE_PAIR(QLatin1String("op"), QRhiProfiler::NewTextureStagingArea);
WRITE_PAIR(QLatin1String("texture"), quint64(quintptr(tex)));
WRITE_PAIR(QLatin1String("slot"), slot);
WRITE_PAIR(QLatin1String("size"), size);
writer->endMap();
}
void QRhiProfilerPrivate::releaseTextureStagingArea(QRhiTexture *tex, int slot)
{
if (!ensureStream())
return;
writer->startMap();
WRITE_PAIR(QLatin1String("op"), QRhiProfiler::ReleaseTextureStagingArea);
WRITE_PAIR(QLatin1String("texture"), quint64(quintptr(tex)));
WRITE_PAIR(QLatin1String("slot"), slot);
writer->endMap();
}
void QRhiProfilerPrivate::resizeSwapChain(QRhiSwapChain *sc, int bufferCount, int sampleCount)
{
// calc approx size
if (!ensureStream())
return;
writer->startMap();
WRITE_PAIR(QLatin1String("op"), QRhiProfiler::ResizeSwapChain);
WRITE_PAIR(QLatin1String("swapchain"), quint64(quintptr(sc)));
const QSize sz = sc->currentPixelSize();
const quint32 byteSize = rhiD->approxByteSizeForTexture(QRhiTexture::BGRA8, sz, 1, 1) * bufferCount;
WRITE_PAIR(QLatin1String("width"), sz.width());
WRITE_PAIR(QLatin1String("height"), sz.height());
WRITE_PAIR(QLatin1String("buffer_count"), bufferCount);
WRITE_PAIR(QLatin1String("effective_sample_count"), sampleCount);
WRITE_PAIR(QLatin1String("approx_total_byte_size"), byteSize);
writer->endMap();
}
void QRhiProfilerPrivate::releaseSwapChain(QRhiSwapChain *sc)
{
if (!ensureStream())
return;
writer->startMap();
WRITE_PAIR(QLatin1String("op"), QRhiProfiler::ReleaseSwapChain);
WRITE_PAIR(QLatin1String("swapchain"), quint64(quintptr(sc)));
writer->endMap();
}
QT_END_NAMESPACE
......@@ -42,15 +42,32 @@
QT_BEGIN_NAMESPACE
class QRhiProfilerPrivate;
class QRhiProfilerStream;
class QIODevice;
class Q_RHI_EXPORT QRhiProfiler
{
public:
enum StreamOp {
NewBuffer = 1,
ReleaseBuffer,
NewBufferStagingArea,
ReleaseBufferStagingArea,
NewRenderBuffer,
ReleaseRenderBuffer,
NewTexture,
ReleaseTexture,
NewTextureStagingArea,
ReleaseTextureStagingArea,
ResizeSwapChain,
ReleaseSwapChain
};
QRhiProfiler();
~QRhiProfiler();
const QRhiProfilerStream *stream() const;
void setOutputDevice(QIODevice *device);
void flush();
void addVMemAllocatorStats();
......
......@@ -46,14 +46,18 @@
QT_BEGIN_NAMESPACE
class QCborStreamWriter;
class QRhiProfilerPrivate
{
public:
static QRhiProfilerPrivate *get(QRhiProfiler *p) { return p->d; }
void newBuffer(QRhiBuffer *buf, size_t realSize, int backingGpuBufCount, int backingCpuBufCount);
~QRhiProfilerPrivate();
void newBuffer(QRhiBuffer *buf, quint32 realSize, int backingGpuBufCount, int backingCpuBufCount);
void releaseBuffer(QRhiBuffer *buf);
void newBufferStagingArea(QRhiBuffer *buf, int slot, size_t size);
void newBufferStagingArea(QRhiBuffer *buf, int slot, quint32 size);
void releaseBufferStagingArea(QRhiBuffer *buf, int slot);
void newRenderBuffer(QRhiRenderBuffer *rb, bool transientBacking, bool winSysBacking);
......@@ -61,14 +65,20 @@ public:
void newTexture(QRhiTexture *tex, bool owns, int mipCount, int layerCount, int sampleCount);
void releaseTexture(QRhiTexture *tex);
void newTextureStagingArea(QRhiTexture *tex, int slot, size_t size);
void newTextureStagingArea(QRhiTexture *tex, int slot, quint32 size);
void releaseTextureStagingArea(QRhiTexture *tex, int slot);
void resizeSwapChain(QRhiSwapChain *sc, int bufferCount, int sampleCount);
void releaseSwapChain(QRhiSwapChain *sc);
bool ensureStream();
void flushStream();
QRhi *rhi = nullptr;
QRhiImplementation *rhiD = nullptr;
QIODevice *outputDevice = nullptr;
QCborStreamWriter *writer = nullptr;
bool active = false;
};
QT_END_NAMESPACE
......
d3d: texture import/export
add a basic resource info (profiler) api
prof api
vk, d3d, gl: tex and other prof
vk: memalloc stats to prof
debug markers, object names, etc.
multiwindow_threaded should demo pulling out the device and importing to another rhi
mtl: reduce set*
......@@ -50,6 +52,7 @@ dxc for d3d as an alternative to fxc?
hlsl -> dxc -> spirv -> spirv-cross hmmm...
+++ done
mtl: buf/tex/rb/sc prof
mtl, gl, vk: texture import/export
rhi native handle getter (device, ...)
imgui example
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment