[Glamor] [PATCH 4/5] fallback_optimize: Prepare for downloading/uploading subregion.

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


Introduced two function glamor_get_sub_pixmap/glamor_put_sub_pixmap,
can easily used to get and put sub region of a big textured pixmap.
And it can use pbo if possible.

To support download a big textured pixmap's sub region to another
pixmap's pbo, we introduce a new type of pixmap GLAMOR_MEMORY_MAP.
This type of pixmap has a valid devPrivate.ptr pointer, and that
pointer points to a pbo mapped address.

Now, we are ready to refine those
glamor_prepare_access/glamor_finish_access pairs.

Signed-off-by: Zhigang Gong <zhigang.gong at linux.intel.com>
---
 src/glamor.c        |    3 +
 src/glamor.h        |    1 +
 src/glamor_fbo.c    |  134 +++++++++++++++++++++++++++++++----
 src/glamor_pixmap.c |  197 +++++++++++++++++++++++++++++++++------------------
 src/glamor_priv.h   |   25 +++++--
 5 files changed, 272 insertions(+), 88 deletions(-)

diff --git a/src/glamor.c b/src/glamor.c
index 8fc3b05..9b1d425 100644
--- a/src/glamor.c
+++ b/src/glamor.c
@@ -155,6 +155,9 @@ glamor_create_pixmap(ScreenPtr screen, int w, int h, int depth,
 	}
 	glamor_set_pixmap_private(pixmap, pixmap_priv);
 
+	if (usage == GLAMOR_CREATE_PIXMAP_MAP)
+		type = GLAMOR_MEMORY_MAP;
+
 	pixmap_priv->container = pixmap;
 	pixmap_priv->glamor_priv = glamor_priv;
 	pixmap_priv->type = type;
diff --git a/src/glamor.h b/src/glamor.h
index 4a4e9bd..c608ed8 100644
--- a/src/glamor.h
+++ b/src/glamor.h
@@ -51,6 +51,7 @@
  */
 typedef enum  glamor_pixmap_type {
 	GLAMOR_MEMORY,
+	GLAMOR_MEMORY_MAP,
 	GLAMOR_TEXTURE_DRM,
 	GLAMOR_SEPARATE_TEXTURE,
 	GLAMOR_DRM_ONLY,
diff --git a/src/glamor_fbo.c b/src/glamor_fbo.c
index b15450a..e9612bd 100644
--- a/src/glamor_fbo.c
+++ b/src/glamor_fbo.c
@@ -132,7 +132,6 @@ glamor_purge_fbo(glamor_pixmap_fbo *fbo)
 	free(fbo);
 }
 
-
 static void
 glamor_pixmap_fbo_cache_put(glamor_pixmap_fbo *fbo)
 {
@@ -165,6 +164,55 @@ glamor_pixmap_fbo_cache_put(glamor_pixmap_fbo *fbo)
 #endif
 }
 
+static void
+glamor_pixmap_ensure_fb(glamor_pixmap_fbo *fbo)
+{
+	glamor_gl_dispatch *dispatch;
+	int status;
+
+	dispatch = glamor_get_dispatch(fbo->glamor_priv);
+
+	if (fbo->fb == 0)
+		dispatch->glGenFramebuffers(1, &fbo->fb);
+	assert(fbo->tex != 0);
+	dispatch->glBindFramebuffer(GL_FRAMEBUFFER, fbo->fb);
+	dispatch->glFramebufferTexture2D(GL_FRAMEBUFFER,
+					 GL_COLOR_ATTACHMENT0,
+					 GL_TEXTURE_2D, fbo->tex,
+					 0);
+	status = dispatch->glCheckFramebufferStatus(GL_FRAMEBUFFER);
+	if (status != GL_FRAMEBUFFER_COMPLETE) {
+		const char *str;
+		switch (status) {
+		case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
+			str = "incomplete attachment";
+			break;
+		case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
+			str = "incomplete/missing attachment";
+			break;
+		case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER:
+			str = "incomplete draw buffer";
+			break;
+		case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER:
+			str = "incomplete read buffer";
+			break;
+		case GL_FRAMEBUFFER_UNSUPPORTED:
+			str = "unsupported";
+			break;
+		case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE:
+			str = "incomplete multiple";
+			break;
+		default:
+			str = "unknown error";
+			break;
+		}
+
+		FatalError("destination is framebuffer incomplete: %s [%#x]\n",
+			   str, status);
+	}
+	glamor_put_dispatch(fbo->glamor_priv);
+}
+
 glamor_pixmap_fbo *
 glamor_create_fbo_from_tex(glamor_screen_private *glamor_priv,
 		  int w, int h, GLenum format, GLint tex, int flag)
@@ -183,9 +231,18 @@ glamor_create_fbo_from_tex(glamor_screen_private *glamor_priv,
 	fbo->format = format;
 	fbo->glamor_priv = glamor_priv;
 
+	if (flag == GLAMOR_CREATE_PIXMAP_MAP) {
+		glamor_gl_dispatch *dispatch;
+		dispatch = glamor_get_dispatch(glamor_priv);
+		dispatch->glGenBuffers(1, &fbo->pbo);
+		glamor_put_dispatch(glamor_priv);
+		goto done;
+	}
+
 	if (flag != GLAMOR_CREATE_FBO_NO_FBO)
 		glamor_pixmap_ensure_fb(fbo);
 
+done:
 	return fbo;
 }
 
@@ -331,6 +388,28 @@ glamor_destroy_tex_obj(glamor_pixmap_fbo * tex_obj)
 	glamor_pixmap_fbo_cache_put(tex_obj);
 }
 
+int
+_glamor_create_tex(glamor_screen_private *glamor_priv,
+		   int w, int h, GLenum format)
+{
+	glamor_gl_dispatch *dispatch;
+	int tex;
+
+	dispatch = glamor_get_dispatch(glamor_priv);
+	dispatch->glGenTextures(1, &tex);
+	dispatch->glBindTexture(GL_TEXTURE_2D, tex);
+	dispatch->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
+				  GL_NEAREST);
+	dispatch->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
+				  GL_NEAREST);
+	dispatch->glTexImage2D(GL_TEXTURE_2D, 0, format, w, h, 0, format,
+			       GL_UNSIGNED_BYTE, NULL);
+	glamor_put_dispatch(glamor_priv);
+	return tex;
+}
+
+
+
 glamor_pixmap_fbo *
 glamor_create_fbo(glamor_screen_private *glamor_priv,
 		  int w, int h,
@@ -339,7 +418,7 @@ glamor_create_fbo(glamor_screen_private *glamor_priv,
 {
 	glamor_gl_dispatch *dispatch;
 	glamor_pixmap_fbo *fbo;
-	GLint tex;
+	GLint tex = 0;
 	int cache_flag;
 
 	if (!glamor_check_fbo_size(glamor_priv, w, h))
@@ -348,6 +427,9 @@ glamor_create_fbo(glamor_screen_private *glamor_priv,
 	if (flag == GLAMOR_CREATE_FBO_NO_FBO)
 		goto new_fbo;
 
+	if (flag == GLAMOR_CREATE_PIXMAP_MAP)
+		goto no_tex;
+
 	if (flag == GLAMOR_CREATE_PIXMAP_FIXUP)
 		cache_flag = GLAMOR_CACHE_EXACT_SIZE;
 	else
@@ -358,18 +440,9 @@ glamor_create_fbo(glamor_screen_private *glamor_priv,
 	if (fbo)
 		return fbo;
 new_fbo:
-	dispatch = glamor_get_dispatch(glamor_priv);
-	dispatch->glGenTextures(1, &tex);
-	dispatch->glBindTexture(GL_TEXTURE_2D, tex);
-	dispatch->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
-				  GL_NEAREST);
-	dispatch->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
-				  GL_NEAREST);
-	dispatch->glTexImage2D(GL_TEXTURE_2D, 0, format, w, h, 0, format,
-			       GL_UNSIGNED_BYTE, NULL);
-
+	tex = _glamor_create_tex(glamor_priv, w, h, format);
+no_tex:
 	fbo = glamor_create_fbo_from_tex(glamor_priv, w, h, format, tex, flag);
-	glamor_put_dispatch(glamor_priv);
 
 	return fbo;
 }
@@ -424,12 +497,47 @@ glamor_pixmap_attach_fbo(PixmapPtr pixmap, glamor_pixmap_fbo *fbo)
 			/* XXX For the Xephyr only, may be broken now.*/
 			pixmap_priv->gl_tex = 0;
 		}
+	case GLAMOR_MEMORY_MAP:
 		pixmap->devPrivate.ptr = NULL;
 		break;
 	default:
 		break;
 	}
 }
+
+
+Bool
+glamor_pixmap_ensure_fbo(PixmapPtr pixmap, GLenum format, int flag)
+{
+	glamor_screen_private *glamor_priv;
+	glamor_pixmap_private *pixmap_priv;
+	glamor_pixmap_fbo *fbo;
+
+	glamor_priv = glamor_get_screen_private(pixmap->drawable.pScreen);
+	pixmap_priv = glamor_get_pixmap_private(pixmap);
+	if (pixmap_priv == NULL || pixmap_priv->fbo == NULL) {
+
+		fbo = glamor_create_fbo(glamor_priv, pixmap->drawable.width,
+					pixmap->drawable.height,
+					format,
+					flag);
+		if (fbo == NULL)
+			return FALSE;
+
+		glamor_pixmap_attach_fbo(pixmap, fbo);
+	} else {
+		/* We do have a fbo, but it may lack of fb or tex. */
+		if (pixmap_priv->fbo->tex)
+			pixmap_priv->fbo->tex = _glamor_create_tex(glamor_priv, pixmap->drawable.width,
+								   pixmap->drawable.height, format);
+
+		if (flag != GLAMOR_CREATE_FBO_NO_FBO && pixmap_priv->fbo->fb == 0)
+			glamor_pixmap_ensure_fb(pixmap_priv->fbo);
+	}
+
+	pixmap_priv = glamor_get_pixmap_private(pixmap);
+	return TRUE;
+}
 /*
  * XXX how to handle those pending OPs.
  * By default, pending OP is disabled. Maybe we will give up the pending
diff --git a/src/glamor_pixmap.c b/src/glamor_pixmap.c
index 6b4dc30..2fbafdc 100644
--- a/src/glamor_pixmap.c
+++ b/src/glamor_pixmap.c
@@ -622,54 +622,6 @@ _glamor_upload_pixmap_to_texture(PixmapPtr pixmap, GLenum format,
 						    pixmap->devPrivate.ptr);
 }
 
-void
-glamor_pixmap_ensure_fb(glamor_pixmap_fbo *fbo)
-{
-	glamor_gl_dispatch *dispatch;
-	int status;
-
-	dispatch = glamor_get_dispatch(fbo->glamor_priv);
-
-	if (fbo->fb == 0)
-		dispatch->glGenFramebuffers(1, &fbo->fb);
-	assert(fbo->tex != 0);
-	dispatch->glBindFramebuffer(GL_FRAMEBUFFER, fbo->fb);
-	dispatch->glFramebufferTexture2D(GL_FRAMEBUFFER,
-					 GL_COLOR_ATTACHMENT0,
-					 GL_TEXTURE_2D, fbo->tex,
-					 0);
-	status = dispatch->glCheckFramebufferStatus(GL_FRAMEBUFFER);
-	if (status != GL_FRAMEBUFFER_COMPLETE) {
-		const char *str;
-		switch (status) {
-		case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
-			str = "incomplete attachment";
-			break;
-		case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
-			str = "incomplete/missing attachment";
-			break;
-		case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER:
-			str = "incomplete draw buffer";
-			break;
-		case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER:
-			str = "incomplete read buffer";
-			break;
-		case GL_FRAMEBUFFER_UNSUPPORTED:
-			str = "unsupported";
-			break;
-		case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE:
-			str = "incomplete multiple";
-			break;
-		default:
-			str = "unknown error";
-			break;
-		}
-
-		FatalError("destination is framebuffer incomplete: %s [%#x]\n",
-			   str, status);
-	}
-	glamor_put_dispatch(fbo->glamor_priv);
-}
 
 /*
  * Prepare to upload a pixmap to texture memory.
@@ -681,7 +633,7 @@ glamor_pixmap_ensure_fb(glamor_pixmap_fbo *fbo)
 static int
 glamor_pixmap_upload_prepare(PixmapPtr pixmap, GLenum format, int no_alpha, int revert, int swap_rb)
 {
-	int flag;
+	int flag = 0;
 	glamor_pixmap_private *pixmap_priv;
 	glamor_screen_private *glamor_priv;
 	glamor_pixmap_fbo *fbo;
@@ -696,36 +648,38 @@ glamor_pixmap_upload_prepare(PixmapPtr pixmap, GLenum format, int no_alpha, int
 	      || !glamor_priv->yInverted)) {
 		/* We don't need a fbo, a simple texture uploading should work. */
 
-		if (pixmap_priv && pixmap_priv->fbo)
-			return 0;
 		flag = GLAMOR_CREATE_FBO_NO_FBO;
-	} else {
-
-		if (GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv))
-			return 0;
-		flag = 0;
 	}
 
+	if ((flag == 0 && pixmap_priv && pixmap_priv->fbo && pixmap_priv->fbo->tex)
+	    || (flag != 0 && pixmap_priv && pixmap_priv->fbo && pixmap_priv->fbo->fb))
+		return 0;
+
 	if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP)
 		gl_iformat_for_depth(pixmap->drawable.depth, &iformat);
 	else
 		iformat = format;
 
+	if (pixmap_priv == NULL || pixmap_priv->fbo == NULL) {
+
+		fbo = glamor_create_fbo(glamor_priv, pixmap->drawable.width,
+					pixmap->drawable.height,
+					iformat,
+					flag);
+		if (fbo == NULL) {
+			glamor_fallback
+			    ("upload failed, depth %d x %d @depth %d \n",
+			     pixmap->drawable.width, pixmap->drawable.height,
+			     pixmap->drawable.depth);
+			return -1;
+		}
 
-	fbo = glamor_create_fbo(glamor_priv, pixmap->drawable.width,
-				pixmap->drawable.height,
-				iformat,
-				flag);
-	if (fbo == NULL) {
-		glamor_fallback
-		    ("upload failed, depth %d x %d @depth %d \n",
-		     pixmap->drawable.width, pixmap->drawable.height,
-		     pixmap->drawable.depth);
-		return -1;
+		glamor_pixmap_attach_fbo(pixmap, fbo);
+	} else {
+		/* We do have a fbo, but it may lack of fb or tex. */
+		glamor_pixmap_ensure_fbo(pixmap, iformat, flag);
 	}
 
-	glamor_pixmap_attach_fbo(pixmap, fbo);
-
 	return 0;
 }
 
@@ -1180,3 +1134,110 @@ fail:
 
 	return ret;
 }
+
+/*
+ * We may use this function to reduce a large pixmap to a small sub
+ * pixmap. Two scenarios currently:
+ * 1. When fallback a large textured pixmap to CPU but we do need to
+ * do rendering within a small sub region, then we can just get a
+ * sub region.
+ *
+ * 2. When uploading a large pixmap to texture but we only need to
+ * use part of the source/mask picture. As glTexImage2D will be more
+ * efficient to upload a contingent region rather than a sub block
+ * in a large buffer. We use this function to gather the sub region
+ * to a contingent sub pixmap.
+ *
+ * The sub-pixmap must have the same format as the source pixmap.
+ *
+ * */
+PixmapPtr
+glamor_get_sub_pixmap(PixmapPtr pixmap, int x, int y, int w, int h, glamor_access_t access)
+{
+	glamor_screen_private *glamor_priv;
+	PixmapPtr sub_pixmap;
+	glamor_pixmap_private *sub_pixmap_priv, *pixmap_priv;
+	void *data;
+	int pbo;
+	int flag;
+
+	if (access == GLAMOR_ACCESS_WO) {
+		sub_pixmap = glamor_create_pixmap(pixmap->drawable.pScreen, w, h,
+						  pixmap->drawable.depth, GLAMOR_CREATE_PIXMAP_CPU);
+		ErrorF("WO\n");
+		return sub_pixmap;
+	}
+
+	glamor_priv = glamor_get_screen_private(pixmap->drawable.pScreen);
+	pixmap_priv = glamor_get_pixmap_private(pixmap);
+
+	if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv))
+		return NULL;
+
+	if (glamor_priv->gl_flavor == GLAMOR_GL_ES2)
+		flag = GLAMOR_CREATE_PIXMAP_CPU;
+	else
+		flag = GLAMOR_CREATE_PIXMAP_MAP;
+
+	sub_pixmap = glamor_create_pixmap(pixmap->drawable.pScreen, w, h,
+					  pixmap->drawable.depth, flag);
+
+	if (sub_pixmap == NULL)
+		return NULL;
+
+	sub_pixmap_priv = glamor_get_pixmap_private(sub_pixmap);
+	pbo = sub_pixmap_priv ? (sub_pixmap_priv->fbo ? sub_pixmap_priv->fbo->pbo : 0): 0;
+
+	if (pbo)
+		data = NULL;
+	else {
+		data = sub_pixmap->devPrivate.ptr;
+		assert(flag != GLAMOR_CREATE_PIXMAP_MAP);
+	}
+	data = glamor_download_sub_pixmap_to_cpu(pixmap, x, y, w, h, sub_pixmap->devKind,
+						 data, pbo, access);
+	if (pbo) {
+		assert(sub_pixmap->devPrivate.ptr == NULL);
+		sub_pixmap->devPrivate.ptr = data;
+		sub_pixmap_priv->fbo->pbo_valid = 1;
+	}
+#if 0
+	struct pixman_box16 box;
+	PixmapPtr new_sub_pixmap;
+	int dx, dy;
+	box.x1 = 0;
+	box.y1 = 0;
+	box.x2 = w;
+	box.y2 = h;
+
+	dx = x;
+	dy = y;
+
+	new_sub_pixmap = glamor_create_pixmap(pixmap->drawable.pScreen, w, h,
+					      pixmap->drawable.depth, GLAMOR_CREATE_PIXMAP_CPU);
+	glamor_copy_n_to_n(&pixmap->drawable, &new_sub_pixmap, NULL, &box, 1, dx, dy, 0, 0, 0, NULL);
+	glamor_compare_pixmaps(new_sub_pixmap, sub_pixmap, 0, 0, w, h, 1, 1);
+#endif
+
+	return sub_pixmap;
+}
+
+PixmapPtr
+glamor_put_sub_pixmap(PixmapPtr sub_pixmap, PixmapPtr pixmap, int x, int y, int w, int h, glamor_access_t access)
+{
+	struct pixman_box16 box;
+	int dx, dy;
+	box.x1 = x;
+	box.y1 = y;
+	box.x2 = x + w;
+	box.y2 = y + h;
+
+	dx = -(x);
+	dy = -(y);
+
+	glamor_copy_n_to_n(&sub_pixmap->drawable,
+			   &pixmap->drawable,
+			   NULL, &box, 1, dx, dy,
+			   0, 0, 0, NULL);
+	glamor_destroy_pixmap(sub_pixmap);
+}
diff --git a/src/glamor_priv.h b/src/glamor_priv.h
index 3e13ef8..8a6beee 100644
--- a/src/glamor_priv.h
+++ b/src/glamor_priv.h
@@ -145,8 +145,8 @@ enum glamor_gl_flavor {
 
 #define GLAMOR_CREATE_PIXMAP_CPU  0x100
 #define GLAMOR_CREATE_PIXMAP_FIXUP 0x101
-
 #define GLAMOR_CREATE_FBO_NO_FBO   0x103
+#define GLAMOR_CREATE_PIXMAP_MAP 0x104
 
 #define GLAMOR_CREATE_TEXTURE_EXACT_SIZE 0x104
 
@@ -615,15 +615,16 @@ Bool glamor_download_pixmap_to_cpu(PixmapPtr pixmap,
  * must be 1.
  **/
 void glamor_restore_pixmap_to_texture(PixmapPtr pixmap);
+
 /**
- * Ensure to have a fbo has a valid/complete glfbo.
+ * According to the flag,
+ * if the flag is GLAMOR_CREATE_FBO_NO_FBO then just ensure
+ * the fbo has a valid texture. Otherwise, it will ensure
+ * the fbo has valid texture and attach to a valid fb.
  * If the fbo already has a valid glfbo then do nothing.
- * Otherwise, it will generate a new glfbo, and bind
- * the fbo's texture to the glfbo.
- * The fbo must has a valid texture before call this
- * API, othersie, it will trigger a assert.
  */
-void glamor_pixmap_ensure_fb(glamor_pixmap_fbo *fbo);
+Bool
+glamor_pixmap_ensure_fbo(PixmapPtr pixmap, GLenum format, int flag);
 
 /**
  * Upload a pixmap to gl texture. Used by dynamic pixmap
@@ -633,6 +634,16 @@ void glamor_pixmap_ensure_fb(glamor_pixmap_fbo *fbo);
 enum glamor_pixmap_status glamor_upload_pixmap_to_texture(PixmapPtr
 							  pixmap);
 
+
+PixmapPtr
+glamor_get_sub_pixmap(PixmapPtr pixmap, int x, int y,
+		      int w, int h, glamor_access_t access);
+
+PixmapPtr
+glamor_put_sub_pixmap(PixmapPtr sub_pixmap, PixmapPtr pixmap, int x, int y,
+		      int w, int h, glamor_access_t access);
+
+
 /**
  * Upload a picture to gl texture. Similar to the
  * glamor_upload_pixmap_to_texture. Used in rendering.
-- 
1.7.4.4



More information about the Glamor mailing list