* @brief Resizes the cache to the widget size and runs the user paint() into it. */
| 771 | * @brief Resizes the cache to the widget size and runs the user paint() into it. |
| 772 | */ |
| 773 | void Widgets::Painter::renderFrame() |
| 774 | { |
| 775 | if (m_rendering) |
| 776 | return; |
| 777 | |
| 778 | m_rendering = true; |
| 779 | |
| 780 | const qreal dpr = qMax<qreal>(1.0, window() ? window()->effectiveDevicePixelRatio() : 1.0); |
| 781 | const QSize logical(qMax(1, int(width())), qMax(1, int(height()))); |
| 782 | const QSize physical(qMax(1, int(std::ceil(logical.width() * dpr))), |
| 783 | qMax(1, int(std::ceil(logical.height() * dpr)))); |
| 784 | |
| 785 | if (physical != m_cacheSize || !qFuzzyCompare(m_cache.devicePixelRatio(), dpr)) { |
| 786 | m_cache = QImage(physical, QImage::Format_ARGB32_Premultiplied); |
| 787 | m_cache.setDevicePixelRatio(dpr); |
| 788 | m_cacheSize = physical; |
| 789 | } |
| 790 | |
| 791 | m_cache.fill(Qt::transparent); |
| 792 | |
| 793 | QPainter qp(&m_cache); |
| 794 | m_ctx->beginFrame(&qp, logical.width(), logical.height()); |
| 795 | |
| 796 | QJSValueList args; |
| 797 | args << m_ctxValue << QJSValue(double(logical.width())) << QJSValue(double(logical.height())); |
| 798 | const auto t0 = std::chrono::steady_clock::now(); |
| 799 | auto r = m_watchdog.call(m_paintFn, args); |
| 800 | const auto dt = |
| 801 | std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - t0) |
| 802 | .count(); |
| 803 | |
| 804 | m_ctx->endFrame(); |
| 805 | qp.end(); |
| 806 | |
| 807 | if (r.isError()) [[unlikely]] { |
| 808 | setLastError(QStringLiteral("paint: ") + r.property(QStringLiteral("message")).toString()); |
| 809 | setRuntimeOk(false); |
| 810 | m_rendering = false; |
| 811 | return; |
| 812 | } |
| 813 | |
| 814 | if (dt > kSlowPaintMs) [[unlikely]] { |
| 815 | if (m_slowPaintStreak < 2) |
| 816 | ++m_slowPaintStreak; |
| 817 | |
| 818 | if (m_slowPaintStreak >= 2 && !m_slowPaintWarned) { |
| 819 | m_slowPaintWarned = true; |
| 820 | setLastError(QStringLiteral("warning: paint() took %1 ms (>%2 ms budget)") |
| 821 | .arg(QString::number(dt), QString::number(kSlowPaintMs))); |
| 822 | } |
| 823 | } else { |
| 824 | m_slowPaintStreak = 0; |
| 825 | } |
| 826 | |
| 827 | m_rendering = false; |
| 828 | } |
| 829 | |
| 830 | //-------------------------------------------------------------------------------------------------- |