| 48 | PainterProfilingReplayer::~PainterProfilingReplayer() = default; |
| 49 | |
| 50 | void PainterProfilingReplayer::profile(const PaintBuffer &buffer) |
| 51 | { |
| 52 | const auto sourceSize = buffer.boundingRect().size().toSize(); |
| 53 | if (sourceSize.width() <= 0 || sourceSize.height() <= 0) |
| 54 | return; |
| 55 | |
| 56 | const auto ratio = buffer.devicePixelRatioF(); |
| 57 | QImage image(sourceSize * ratio, QImage::Format_ARGB32); // TODO use the right format, this has considerable impact on performance! |
| 58 | image.setDevicePixelRatio(ratio); |
| 59 | image.fill(Qt::transparent); |
| 60 | QPainter p(&image); |
| 61 | |
| 62 | Replayer replayer(&buffer, &p); |
| 63 | auto d = buffer.data(); |
| 64 | const auto cmdSize = d->commands.size(); |
| 65 | const auto runs = 5; |
| 66 | std::unique_ptr<double[]> samples(new double[cmdSize * runs]); |
| 67 | for (int run = 0; run < runs; ++run) { |
| 68 | for (int i = 0; i < cmdSize; ++i) { |
| 69 | const auto &cmd = d->commands.at(i); |
| 70 | QElapsedTimer t; |
| 71 | t.start(); |
| 72 | replayer.process(cmd); |
| 73 | samples[i * runs + run] = t.nsecsElapsed(); |
| 74 | } |
| 75 | } |
| 76 | |
| 77 | m_costs.reserve(cmdSize); |
| 78 | for (int i = 0; i < cmdSize; ++i) { |
| 79 | std::nth_element(samples.get() + i * runs, samples.get() + i * runs + runs / 2, samples.get() + i * runs + runs); |
| 80 | m_costs.push_back(samples[i * runs + runs / 2]); |
| 81 | } |
| 82 | const auto sum = std::accumulate(m_costs.constBegin(), m_costs.constEnd(), 0.0); |
| 83 | std::for_each(m_costs.begin(), m_costs.end(), [sum](double &c) { c = 100.0 * c / sum; }); |
| 84 | } |
| 85 | |
| 86 | QVector<double> PainterProfilingReplayer::costs() const |
| 87 | { |