Avoid exceeding max request length by xcb_put_image.

Bug: angleproject:7954
Change-Id: I87efa1c4149b3e3894aa1fbd5afb4e175b677576
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/70628
Commit-Queue: Roman Lavrov <romanl@google.com>
Reviewed-by: Shahbaz Youssefi <syoussefi@google.com>
Tested-by: Roman Lavrov <romanl@google.com>
Kokoro-Result: kokoro <noreply+kokoro@google.com>
diff --git a/src/WSI/XcbSurfaceKHR.cpp b/src/WSI/XcbSurfaceKHR.cpp
index c5a3d54..37e23df 100644
--- a/src/WSI/XcbSurfaceKHR.cpp
+++ b/src/WSI/XcbSurfaceKHR.cpp
@@ -188,20 +188,26 @@
 		int bytesPerPixel = static_cast<int>(image->getImage()->getFormat(VK_IMAGE_ASPECT_COLOR_BIT).bytes());
 		int width = stride / bytesPerPixel;
 		auto buffer = reinterpret_cast<uint8_t *>(image->getImageMemory()->getOffsetPointer(0));
-		size_t bufferSize = extent.height * stride;
-		libXCB->xcb_put_image(
-		    connection,
-		    XCB_IMAGE_FORMAT_Z_PIXMAP,
-		    window,
-		    gc,
-		    width,
-		    extent.height,
-		    0, 0,  // dst x, y
-		    0,     // left_pad
-		    depth,
-		    bufferSize,  // data_len
-		    buffer       // data
-		);
+		size_t max_request_size = static_cast<size_t>(libXCB->xcb_get_maximum_request_length(connection)) * 4;
+		size_t max_strides = (max_request_size - sizeof(xcb_put_image_request_t)) / stride;
+		for(size_t y = 0; y < extent.height; y += max_strides)
+		{
+			size_t num_strides = std::min(max_strides, extent.height - y);
+			libXCB->xcb_put_image(
+			    connection,
+			    XCB_IMAGE_FORMAT_Z_PIXMAP,
+			    window,
+			    gc,
+			    width,
+			    num_strides,
+			    0, y,                  // dst x, y
+			    0,                     // left_pad
+			    depth,
+			    num_strides * stride,  // data_len
+			    buffer + y * stride    // data
+			);
+		}
+		assert(libXCB->xcb_connection_has_error(connection) == 0);
 	}
 	else
 	{
diff --git a/src/WSI/libXCB.cpp b/src/WSI/libXCB.cpp
index 212884c..e0784cc 100644
--- a/src/WSI/libXCB.cpp
+++ b/src/WSI/libXCB.cpp
@@ -30,6 +30,8 @@
 	getFuncAddress(libxcb, "xcb_copy_area", &xcb_copy_area);
 	getFuncAddress(libxcb, "xcb_free_pixmap", &xcb_free_pixmap);
 	getFuncAddress(libxcb, "xcb_get_extension_data", &xcb_get_extension_data);
+	getFuncAddress(libxcb, "xcb_connection_has_error", &xcb_connection_has_error);
+	getFuncAddress(libxcb, "xcb_get_maximum_request_length", &xcb_get_maximum_request_length);
 
 	getFuncAddress(libshm, "xcb_shm_query_version", &xcb_shm_query_version);
 	getFuncAddress(libshm, "xcb_shm_query_version_reply", &xcb_shm_query_version_reply);
diff --git a/src/WSI/libXCB.hpp b/src/WSI/libXCB.hpp
index ad957ca..2a8a490 100644
--- a/src/WSI/libXCB.hpp
+++ b/src/WSI/libXCB.hpp
@@ -33,6 +33,8 @@
 	xcb_void_cookie_t (*xcb_copy_area)(xcb_connection_t *conn, xcb_drawable_t src_drawable, xcb_drawable_t dst_drawable, xcb_gcontext_t gc, int16_t src_x, int16_t src_y, int16_t dst_x, int16_t dst_y, uint16_t width, uint16_t height);
 	xcb_void_cookie_t (*xcb_free_pixmap)(xcb_connection_t *conn, xcb_pixmap_t pixmap);
 	xcb_query_extension_reply_t *(*xcb_get_extension_data)(xcb_connection_t *c, xcb_extension_t *extension) = nullptr;
+	int	(*xcb_connection_has_error)(xcb_connection_t *c);
+	uint32_t (*xcb_get_maximum_request_length)(xcb_connection_t *c);
 
 	xcb_shm_query_version_cookie_t (*xcb_shm_query_version)(xcb_connection_t *c);
 	xcb_shm_query_version_reply_t *(*xcb_shm_query_version_reply)(xcb_connection_t *c, xcb_shm_query_version_cookie_t cookie, xcb_generic_error_t **e);