summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms/xcb/qxcbbackingstore.cpp
diff options
context:
space:
mode:
authorUli Schlachter <psychon@znc.in>2012-01-15 17:45:14 +0100
committerQt by Nokia <qt-info@nokia.com>2012-01-16 11:01:09 +0100
commit23a372ab8d59cd9b33356a16744313890b544f4f (patch)
tree30ff9f80e1faa0a0ca711cac32cea538bb1df672 /src/plugins/platforms/xcb/qxcbbackingstore.cpp
parentba888bb8c8e6fce76efc855ef81250f2c9426b40 (diff)
xcb: Obey maximum request length when uploading images
When connecting to an X11 server, the server tells the client what its maximum allowed request size is. Larger requests are not permitted. Thus, libxcb verifies that all requests which are sent are smaller than this size limit and possibly kills the connection (without any good error message). Thus, when uploading an image, we could be trying to send more pixel data than fit into a single request. If this would be the case, the code will now use multiple requests where each request only sends a part of the allowed rows. In case all the data fits into a single request, this commit shouldn't change any behavior. Change-Id: I84a4ebfcdb6de7e206015c37e3e33cba3bd309b1 Signed-off-by: Uli Schlachter <psychon@znc.in> Reviewed-by: Robin Burchell <robin+qt@viroteck.net> Reviewed-by: Samuel Rødal <samuel.rodal@nokia.com>
Diffstat (limited to 'src/plugins/platforms/xcb/qxcbbackingstore.cpp')
-rw-r--r--src/plugins/platforms/xcb/qxcbbackingstore.cpp52
1 files changed, 41 insertions, 11 deletions
diff --git a/src/plugins/platforms/xcb/qxcbbackingstore.cpp b/src/plugins/platforms/xcb/qxcbbackingstore.cpp
index 4348ddbae9..ad8b47c25a 100644
--- a/src/plugins/platforms/xcb/qxcbbackingstore.cpp
+++ b/src/plugins/platforms/xcb/qxcbbackingstore.cpp
@@ -182,17 +182,47 @@ void QXcbShmImage::put(xcb_window_t window, const QPoint &target, const QRect &s
source.height(),
false);
} else {
- xcb_image_t *subimage = xcb_image_subimage(m_xcb_image, source.x(), source.y(), source.width(), source.height(),
- 0, 0, 0);
- xcb_image_put(xcb_connection(),
- window,
- m_gc,
- subimage,
- target.x(),
- target.y(),
- 0);
-
- xcb_image_destroy(subimage);
+ // If we upload the whole image in a single chunk, the result might be
+ // larger than the server's maximum request size and stuff breaks.
+ // To work around that, we upload the image in chunks where each chunk
+ // is small enough for a single request.
+ int src_x = source.x();
+ int src_y = source.y();
+ int target_x = target.x();
+ int target_y = target.y();
+ int width = source.width();
+ int height = source.height();
+
+ // We must make sure that each request is not larger than max_req_size.
+ // Each request takes req_size + m_xcb_image->stride * height bytes.
+ uint32_t max_req_size = xcb_get_maximum_request_length(xcb_connection());
+ uint32_t req_size = sizeof(xcb_put_image_request_t);
+ int rows_per_put = (max_req_size - req_size) / m_xcb_image->stride;
+
+ // This assert could trigger if a single row has more pixels than fit in
+ // a single PutImage request. However, max_req_size is guaranteed to be
+ // at least 16384 bytes. That should be enough for quite large images.
+ Q_ASSERT(rows_per_put > 0);
+
+ while (height > 0) {
+ int rows = std::min(height, rows_per_put);
+
+ xcb_image_t *subimage = xcb_image_subimage(m_xcb_image, src_x, src_y, width, rows,
+ 0, 0, 0);
+ xcb_image_put(xcb_connection(),
+ window,
+ m_gc,
+ subimage,
+ target_x,
+ target_y,
+ 0);
+
+ xcb_image_destroy(subimage);
+
+ src_y += rows;
+ target_y += rows;
+ height -= rows;
+ }
}
Q_XCB_NOOP(connection());