Fix integer division order in FBController::markedUpdate (partial updates collapse to full repaints)#63
Conversation
Scaling a partial rect with integer division before multiplying truncates every coordinate to zero, so partial updates collapse to a null QRect and Qt repaints the whole item on each one. Multiply first (the same operand order convertPointToQTFBPixels already uses) and round the far edge up so a scaled rect always covers the source region. A null input rect still yields a null rect, so UPDATE_ALL semantics are unchanged. Fixes asivery#33 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Confirmed on a reMarkable 2, firmware 3.28.0.162: without this fix every One heads-up this fix newly exposes: void FBController::markedUpdate(const QRect &rect) {
isMidPaint = true;
if (rect.isNull()) {
// whole-item request: pass an explicit full rect so later partials union into it
update(QRect(0, 0, qCeil(width()), qCeil(height())));
} else if (_allowScaling && image) {
// ... this PR's scaled-rect math ...
} else {
update(rect);
}
}(Also opened #64 with a complementary |
UPDATE_ALL reaches markedUpdate() as a default-constructed (null) QRect. Passing it through the scaled-rect math would turn it into an empty QRect(0,0,0,0), and forwarding a null to QQuickPaintedItem::update() relies on the 'null means whole item' encoding, which a later partial update() in the same frame can union with and silently narrow. Request the full item explicitly instead, before any scaling. Spotted on-device by @icetingyu (see PR discussion). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Thanks a lot for the on-device confirmation and for catching the null-rect edge case, @icetingyu — you're right on both counts: the null must be guarded before the scaling math, and forwarding it relies on the "null means whole item" encoding that a later partial Pushed exactly that guard: #64 looks like a great complement — happy to rebase on top of it if the maintainer prefers to land that first. |
Fixes #33.
Impact
On a reMarkable 2 this fix dramatically improves writing fluidity and latency for windowed qtfb clients: sustained handwriting stops lagging behind the pen. Before the fix, a stylus app streaming small ink rects hits a ceiling of roughly 70 updates/s, because every partial update degenerates into a full-item repaint; with the fix, partial repaints land as intended and the queue of pending ink disappears. Field-tested on firmware 3.27.3.0 — the difference is immediately visible when writing fast.
The bug
FBController::markedUpdatescales the incoming partial rect with integer division before multiplying:(rect.x() / image->width()) * this->width()For any
rect.x() < image->width()this truncates to 0, so every partial update becomes a nullQRect— and a null rect tells Qt to repaint the whole item. Partial updates still work, but each one costs a full-item repaint.The fix
Multiply before dividing — the same operand order
convertPointToQTFBPixelsalready uses a few lines below — and round the far edge up (qCeil) so a scaled rect always covers the source region instead of clipping its border. A null input rect still yields a null rect, soUPDATE_ALLsemantics are unchanged. Gestures, full refreshes and scaling behave exactly as before.🤖 Generated with Claude Code