[Glamor] [PATCH 3/5] glamor_download_sub_pixmap_to_cpu: New function to download subregion.

Zhigang Gong zhigang.gong at linux.intel.com
Mon Apr 9 06:42:44 PDT 2012


Prepare to optimize the fallback path. We choose the important
rendering pathes to optimzie it by using shader. For other pathes,
we have to fallback. We may continue to optimize more pathes in
the future, but now we have to face those fallbacks.

The original fallback is very slow and will download/upload the whole
pixmap. From this commit, I will refine it to just download/upload
needed part.

Signed-off-by: Zhigang Gong <zhigang.gong at linux.intel.com>
---
 src/glamor_pixmap.c |  296 ++++++++++++++++++++++++++++++---------------------
 1 files changed, 175 insertions(+), 121 deletions(-)

diff --git a/src/glamor_pixmap.c b/src/glamor_pixmap.c
index bab91af..6b4dc30 100644
--- a/src/glamor_pixmap.c
+++ b/src/glamor_pixmap.c
@@ -867,34 +867,50 @@ glamor_es2_pixmap_read_prepare(PixmapPtr source, int x, int y, int w, int h, GLe
 	return temp_fbo;
 }
 
-/**
- * Move a pixmap to CPU memory.
- * The input data is the pixmap's fbo.
- * The output data is at pixmap->devPrivate.ptr. We always use pbo
- * to read the fbo and then map it to va. If possible, we will use
- * it directly as devPrivate.ptr.
- * If successfully download a fbo to cpu then return TRUE.
- * Otherwise return FALSE.
- **/
-Bool
-glamor_download_pixmap_to_cpu(PixmapPtr pixmap, glamor_access_t access)
+/*
+ * Download a sub region of pixmap to a specified memory region.
+ * The pixmap must have a valid FBO, otherwise return a NULL.
+ * */
+
+void *
+glamor_download_sub_pixmap_to_cpu(PixmapPtr pixmap, int x, int y, int w, int h,
+				  int stride, void *bits, int pbo, glamor_access_t access)
 {
-	glamor_pixmap_private *pixmap_priv =
-	    glamor_get_pixmap_private(pixmap);
-	unsigned int stride, row_length, y;
+	glamor_pixmap_private *pixmap_priv;
+	unsigned int row_length;
 	GLenum format, type, gl_access, gl_usage;
 	int no_alpha, revert, swap_rb;
-	uint8_t *data = NULL, *read;
+	void *data, *read;
 	ScreenPtr screen;
 	glamor_screen_private *glamor_priv =
 	    glamor_get_screen_private(pixmap->drawable.pScreen);
 	glamor_gl_dispatch *dispatch;
 	glamor_pixmap_fbo *temp_fbo = NULL;
 	int need_post_conversion = 0;
+	int need_free_data = 0;
 
+	data = bits;
 	screen = pixmap->drawable.pScreen;
+	pixmap_priv = glamor_get_pixmap_private(pixmap);
 	if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv))
-		return TRUE;
+		return NULL;
+
+	switch (access) {
+	case GLAMOR_ACCESS_RO:
+		gl_access = GL_READ_ONLY;
+		gl_usage = GL_STREAM_READ;
+		break;
+	case GLAMOR_ACCESS_WO:
+		return bits;
+	case GLAMOR_ACCESS_RW:
+		gl_access = GL_READ_WRITE;
+		gl_usage = GL_DYNAMIC_DRAW;
+		break;
+	default:
+		ErrorF("Glamor: Invalid access code. %d\n", access);
+		assert(0);
+	}
+
 	if (glamor_get_tex_format_type_from_pixmap(pixmap,
 						   &format,
 						   &type,
@@ -904,64 +920,44 @@ glamor_download_pixmap_to_cpu(PixmapPtr pixmap, glamor_access_t access)
 		ErrorF("Unknown pixmap depth %d.\n",
 		       pixmap->drawable.depth);
 		assert(0);	// Should never happen.
-		return FALSE;
+		return NULL;
 	}
 
-	glamor_debug_output(GLAMOR_DEBUG_TEXTURE_DOWNLOAD,
-			    "Downloading pixmap %p  %dx%d depth%d\n",
-			    pixmap,
-			    pixmap->drawable.width,
-			    pixmap->drawable.height,
-			    pixmap->drawable.depth);
-
-	stride = pixmap->devKind;
-
 	glamor_set_destination_pixmap_priv_nc(pixmap_priv);
 	/* XXX we may don't need to validate it on GPU here,
 	 * we can just validate it on CPU. */
 	glamor_validate_pixmap(pixmap);
 
-
 	need_post_conversion = (revert > REVERT_NORMAL);
+	if (need_post_conversion) {
+		if (pixmap->drawable.depth == 1) {
+			stride = (((w * 8 + 7) / 8) + 3) & ~3;
+			data = malloc(stride * h);
+			if (data == NULL)
+				return NULL;
+			need_free_data = 1;
+		}
+	}
 
 	if (glamor_priv->gl_flavor == GLAMOR_GL_ES2
 	    && !need_post_conversion
 	    && (swap_rb != SWAP_NONE_DOWNLOADING || revert != REVERT_NONE)) {
-		 if (!(temp_fbo = glamor_es2_pixmap_read_prepare(pixmap, 0, 0,
-								 pixmap->drawable.width, pixmap->drawable.height, format,
-								 type, no_alpha,
+		 if (!(temp_fbo = glamor_es2_pixmap_read_prepare(pixmap, x, y, w, h,
+								 format, type, no_alpha,
 								 revert, swap_rb)))
-			return FALSE;
-	}
-	switch (access) {
-	case GLAMOR_ACCESS_RO:
-		gl_access = GL_READ_ONLY;
-		gl_usage = GL_STREAM_READ;
-		break;
-	case GLAMOR_ACCESS_WO:
-		data = malloc(stride * pixmap->drawable.height);
-		goto done;
-		break;
-	case GLAMOR_ACCESS_RW:
-		gl_access = GL_READ_WRITE;
-		gl_usage = GL_DYNAMIC_DRAW;
-		break;
-	default:
-		ErrorF("Glamor: Invalid access code. %d\n", access);
-		assert(0);
+			return NULL;
+		x = 0;
+		y = 0;
 	}
-	if (glamor_priv->gl_flavor == GLAMOR_GL_ES2) {
-		data = malloc(stride * pixmap->drawable.height);
-	}
-	row_length = (stride * 8) / pixmap->drawable.bitsPerPixel;
+
 
 	dispatch = glamor_get_dispatch(glamor_priv);
 	if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP) {
+		row_length = (stride * 8) / pixmap->drawable.bitsPerPixel;
 		dispatch->glPixelStorei(GL_PACK_ALIGNMENT, 1);
 		dispatch->glPixelStorei(GL_PACK_ROW_LENGTH, row_length);
 	} else {
 		dispatch->glPixelStorei(GL_PACK_ALIGNMENT, 4);
-		//  dispatch->glPixelStorei(GL_PACK_ROW_LENGTH, 0);
 	}
 	if (glamor_priv->has_pack_invert || glamor_priv->yInverted) {
 
@@ -971,66 +967,50 @@ glamor_download_pixmap_to_cpu(PixmapPtr pixmap, glamor_access_t access)
 			dispatch->glPixelStorei(GL_PACK_INVERT_MESA, 1);
 		}
 
-		if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP) {
-			if (pixmap_priv->fbo->pbo == 0)
-				dispatch->glGenBuffers(1,
-						       &pixmap_priv->fbo->pbo);
-			dispatch->glBindBuffer(GL_PIXEL_PACK_BUFFER,
-					       pixmap_priv->fbo->pbo);
+		if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP && data == NULL) {
+			assert(pbo > 0);
+			dispatch->glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo);
 			dispatch->glBufferData(GL_PIXEL_PACK_BUFFER,
 					       stride *
-					       pixmap->drawable.height,
+					       h,
 					       NULL, gl_usage);
-			dispatch->glReadPixels(0, 0, row_length,
-					       pixmap->drawable.height,
-					       format, type, 0);
-			data = dispatch->glMapBuffer(GL_PIXEL_PACK_BUFFER,
-						     gl_access);
-			pixmap_priv->fbo->pbo_valid = TRUE;
-
-			if (!glamor_priv->yInverted) {
-				assert(glamor_priv->gl_flavor ==
-				       GLAMOR_GL_DESKTOP);
-				dispatch->glPixelStorei
-				    (GL_PACK_INVERT_MESA, 0);
-			}
-			dispatch->glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
+		}
 
-		} else {
-			dispatch->glReadPixels(0, 0,
-					       pixmap->drawable.width,
-					       pixmap->drawable.height,
-					       format, type, data);
+		dispatch->glReadPixels(x, y, w, h, format, type, data);
+
+		if (!glamor_priv->yInverted) {
+			assert(glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP);
+			dispatch->glPixelStorei(GL_PACK_INVERT_MESA, 0);
 		}
-	} else {
-		data = malloc(stride * pixmap->drawable.height);
-		assert(data);
-		if (access != GLAMOR_ACCESS_WO) {
-			if (pixmap_priv->fbo->pbo == 0)
-				dispatch->glGenBuffers(1,
-						       &pixmap_priv->fbo->pbo);
-			dispatch->glBindBuffer(GL_PIXEL_PACK_BUFFER,
-					       pixmap_priv->fbo->pbo);
-			dispatch->glBufferData(GL_PIXEL_PACK_BUFFER,
-					       stride *
-					       pixmap->drawable.height,
-					       NULL, GL_STREAM_READ);
-			dispatch->glReadPixels(0, 0, row_length,
-					       pixmap->drawable.height,
-					       format, type, 0);
-			read = dispatch->glMapBuffer(GL_PIXEL_PACK_BUFFER,
-						     GL_READ_ONLY);
-
-			for (y = 0; y < pixmap->drawable.height; y++)
-				memcpy(data + y * stride,
-				       read + (pixmap->drawable.height -
-					       y - 1) * stride, stride);
-			dispatch->glUnmapBuffer(GL_PIXEL_PACK_BUFFER);
+		if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP && bits == NULL) {
+			bits = dispatch->glMapBuffer(GL_PIXEL_PACK_BUFFER,
+						     gl_access);
 			dispatch->glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
-			pixmap_priv->fbo->pbo_valid = FALSE;
-			dispatch->glDeleteBuffers(1, &pixmap_priv->fbo->pbo);
-			pixmap_priv->fbo->pbo = 0;
 		}
+	} else {
+		int temp_pbo;
+		int yy;
+
+		dispatch = glamor_get_dispatch(glamor_priv);
+		dispatch->glGenBuffers(1, &temp_pbo);
+		dispatch->glBindBuffer(GL_PIXEL_PACK_BUFFER,
+				       temp_pbo);
+		dispatch->glBufferData(GL_PIXEL_PACK_BUFFER,
+				       stride *
+				       pixmap->drawable.height,
+				       NULL, GL_STREAM_READ);
+		dispatch->glReadPixels(0, 0, row_length,
+				       pixmap->drawable.height,
+				       format, type, 0);
+		read = dispatch->glMapBuffer(GL_PIXEL_PACK_BUFFER,
+					     GL_READ_ONLY);
+		for (yy = 0; yy < pixmap->drawable.height; yy++)
+			memcpy(data + yy * stride,
+			       read + (pixmap->drawable.height -
+			       yy - 1) * stride, stride);
+		dispatch->glUnmapBuffer(GL_PIXEL_PACK_BUFFER);
+		dispatch->glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
+		dispatch->glDeleteBuffers(1, &temp_pbo);
 	}
 
 	dispatch->glBindFramebuffer(GL_FRAMEBUFFER, 0);
@@ -1039,27 +1019,101 @@ glamor_download_pixmap_to_cpu(PixmapPtr pixmap, glamor_access_t access)
 	if (need_post_conversion) {
 		/* As OpenGL desktop version never enters here.
 		 * Don't need to consider if the pbo is valid.*/
-		int stride;
-		assert(pixmap_priv->fbo->pbo_valid == 0);
-
-		/* Only A1 <--> A8 conversion need to adjust the stride value. */
-		if (pixmap->drawable.depth == 1)
-			stride = (((pixmap->drawable.width * 8 + 7) / 8) + 3) & ~3;
-		else
-			stride = pixmap->devKind;
-		glamor_color_convert_to_bits(data, data, pixmap->drawable.width,
-					     pixmap->drawable.height,
-					     stride, no_alpha,
-					     revert, swap_rb);
+		bits = glamor_color_convert_to_bits(data, bits,
+						    w, h,
+						    stride, no_alpha,
+						    revert, swap_rb);
 	}
 
       done:
 
-	pixmap_priv->gl_fbo = GLAMOR_FBO_DOWNLOADED;
-	pixmap->devPrivate.ptr = data;
-
 	if (temp_fbo != NULL)
 		glamor_destroy_fbo(temp_fbo);
+	if (need_free_data)
+		free(data);
+
+	return bits;
+}
+
+
+/**
+ * Move a pixmap to CPU memory.
+ * The input data is the pixmap's fbo.
+ * The output data is at pixmap->devPrivate.ptr. We always use pbo
+ * to read the fbo and then map it to va. If possible, we will use
+ * it directly as devPrivate.ptr.
+ * If successfully download a fbo to cpu then return TRUE.
+ * Otherwise return FALSE.
+ **/
+Bool
+glamor_download_pixmap_to_cpu(PixmapPtr pixmap, glamor_access_t access)
+{
+	glamor_pixmap_private *pixmap_priv =
+	    glamor_get_pixmap_private(pixmap);
+	unsigned int stride, row_length, y;
+	GLenum format, type, gl_access, gl_usage;
+	int no_alpha, revert, swap_rb;
+	void *data = NULL, *dst;
+	ScreenPtr screen;
+	glamor_screen_private *glamor_priv =
+	    glamor_get_screen_private(pixmap->drawable.pScreen);
+	glamor_gl_dispatch *dispatch;
+	int pbo = 0;
+
+	screen = pixmap->drawable.pScreen;
+	if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv))
+		return TRUE;
+
+	glamor_debug_output(GLAMOR_DEBUG_TEXTURE_DOWNLOAD,
+			    "Downloading pixmap %p  %dx%d depth%d\n",
+			    pixmap,
+			    pixmap->drawable.width,
+			    pixmap->drawable.height,
+			    pixmap->drawable.depth);
+
+	stride = pixmap->devKind;
+
+	if (access == GLAMOR_ACCESS_WO
+	    || glamor_priv->gl_flavor == GLAMOR_GL_ES2
+	    || (!glamor_priv->has_pack_invert && !glamor_priv->yInverted)) {
+		data = malloc(stride * pixmap->drawable.height);
+	} else {
+		dispatch = glamor_get_dispatch(glamor_priv);
+		if (pixmap_priv->fbo->pbo == 0)
+			dispatch->glGenBuffers(1,
+					       &pixmap_priv->fbo->pbo);
+		dispatch->glBindBuffer(GL_PIXEL_PACK_BUFFER,
+				       pixmap_priv->fbo->pbo);
+		dispatch->glBufferData(GL_PIXEL_PACK_BUFFER,
+				       stride *
+				       pixmap->drawable.height,
+				       NULL, gl_usage);
+		dispatch->glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
+		glamor_put_dispatch(glamor_priv);
+		pbo = pixmap_priv->fbo->pbo;
+		glamor_put_dispatch(glamor_priv);
+	}
+
+	dst = glamor_download_sub_pixmap_to_cpu(pixmap, 0, 0,
+						pixmap->drawable.width,
+						pixmap->drawable.height,
+						pixmap->devKind,
+						data, pbo, access);
+
+	if (!dst) {
+		if (data)
+			free(data);
+		return FALSE;
+	}
+
+	if (pbo != 0)
+		pixmap_priv->fbo->pbo_valid = 1;
+
+	pixmap_priv->gl_fbo = GLAMOR_FBO_DOWNLOADED;
+
+      done:
+
+	pixmap->devPrivate.ptr = dst;
 
 	return TRUE;
 }
-- 
1.7.4.4



More information about the Glamor mailing list