Repository navigation
perf(shot): reduce X11 screenshot startup overhead - #949
Conversation
Reviewer's GuideReduces X11 screenshot startup overhead by adding a validated scanline conversion path for native 32-bit images and replacing synchronous lscpu execution with direct /proc/cpuinfo parsing, while preserving fallback behavior and adding targeted regression tests plus reproducible component and D-Bus benchmarks. Sequence diagram for optimized X11 screenshot startupsequenceDiagram
participant ScreenGrabber
participant XServer
participant XImageConverter
participant QPixmap
ScreenGrabber->>XServer: XGetImage()
ScreenGrabber->>XImageConverter: toImage(ximg)
alt validated native 32-bit ZPixmap layout
XImageConverter->>XImageConverter: scanline memcpy and force opaque alpha
else other XImage layout
XImageConverter->>XImageConverter: XGetPixel() and setPixel()
end
XImageConverter-->>ScreenGrabber: owned QImage
ScreenGrabber->>QPixmap: fromImage(qimg)
ScreenGrabber->>XServer: XDestroyImage()
ScreenGrabber->>XServer: XCloseDisplay()
Sequence diagram for direct CPU vendor detectionsequenceDiagram
participant Utils
participant ProcCpuInfo as /proc/cpuinfo
participant CpuVendor
Utils->>ProcCpuInfo: open(ReadOnly)
Utils->>CpuVendor: isZhaoxin(cpuInfo)
loop read lines
CpuVendor->>ProcCpuInfo: readLine()
end
CpuVendor-->>Utils: vendor_id == CentaurHauls
Note over Utils,ProcCpuInfo: No lscpu process is spawned
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Hey - I've found 1 issue
Prompt for AI Agents
Please address the comments from this code review:
## Individual Comments
### Comment 1
<location path="src/utils/ximageconverter.cpp" line_range="33-36" />
<code_context>
+
+ for (int y = 0; y < image->height; ++y) {
+ if (direct) {
+ const char *source = image->data + qsizetype(y) * image->bytes_per_line;
+ QRgb *destination = reinterpret_cast<QRgb *>(result.scanLine(y));
+ for (int x = 0; x < image->width; ++x) {
+ quint32 pixel;
+ // memcpy avoids aliasing assumptions about Xlib-owned storage.
+ std::memcpy(&pixel, source + qsizetype(x) * sizeof(pixel), sizeof(pixel));
</code_context>
<issue_to_address>
**Qt 5.6 builds fail**
When the project is built with Qt 5.6–5.9, the `qsizetype` casts in `ximageconverter.cpp` are undefined, so the converter does not compile and the application build fails.
Use an index type available in the supported Qt 5.6–5.9 builds for both pointer offsets.
</issue_to_address>| const char *source = image->data + qsizetype(y) * image->bytes_per_line; | ||
| QRgb *destination = reinterpret_cast<QRgb *>(result.scanLine(y)); | ||
| for (int x = 0; x < image->width; ++x) { | ||
| quint32 pixel; |
There was a problem hiding this comment.
🟠 High · Qt 5.6 builds fail
When the project is built with Qt 5.6–5.9, the qsizetype casts in ximageconverter.cpp are undefined, so the converter does not compile and the application build fails.
Use an index type available in the supported Qt 5.6–5.9 builds for both pointer offsets.
Prompt for AI agents
In `src/utils/ximageconverter.cpp` at lines 33-36:
**Qt 5.6 builds fail**
When the project is built with Qt 5.6–5.9, the `qsizetype` casts in `ximageconverter.cpp` are undefined, so the converter does not compile and the application build fails.
Use an index type available in the supported Qt 5.6–5.9 builds for both pointer offsets.Convert supported native RGB32 XImages by scanline and read CPU vendor metadata directly from procfs. Add pixel regressions and reproducible startup benchmarks. Log: Reduce startup overhead for X11 screenshots
- Convert native RGB32 XImages in place and hand the Xlib buffer to QImage, removing a full-screen allocation and copy. - Relax validation so uncommon layouts take the legacy XGetPixel path instead of being rejected; write fallback pixels via scanLine. - Build ximageconverter only for Qt6, its sole user. - Update stale lscpu references in unit-test comments. Co-Authored-By: Claude <noreply@anthropic.com>
5697feb to
67c91ce
Compare
|
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: hualet, lzwind The full list of commands accepted by this bot can be found here. DetailsNeeds approval from an approver in each of these files:Approvers can indicate their approval by writing |
Ordinary X11 screenshots perform millions of XGetPixel/setPixel calls while preparing the desktop background and synchronously spawn lscpu before showing the selection UI. This change reduces that startup work while preserving capture coordinates and the existing platform tuning parameters.
ximageconverteris built only for Qt6, its sole user.Local performance
X11, Qt6, 2880×1800 physical screen, DPR 1.75; same source baseline and Release options, 11 interleaved runs per variant, new process each time with warm filesystem cache:
The endpoint is the display call returning, not a frame presented by the compositor. Measurements exclude real keyboard dispatch and cold D-Bus activation, and use log receipt times. The benchmark scripts and workload details are in tests/startup/README.md.
Validation and scope
XGetImageitself (~23 ms) is now the dominant capture cost.qmake6 src/src.pro) succeeded; fullscreen-save smoke test produced a valid opaque 2880×1800 PNG.Summary by Sourcery
Optimize X11 screenshot startup by eliminating avoidable image conversion and CPU detection overhead while preserving fallback behavior and capture correctness.
Enhancements:
Build:
Documentation:
Tests: