[Glamor] [PATCH v3 3/5] gles2: Fixed color conversion for the formats except 1555 and 2101010.

Zhigang Gong zhigang.gong at linux.intel.com
Thu Apr 5 08:08:27 PDT 2012


This patch fixed two major problems when we do the color convesion with
GLES2.

1. lack of necessary formats in FBO pool.
GLES2 has three different possible texture formats, GL_RGBA,
GL_BGRA and GL_ALPHA. Previous implementation only has one bucket
for all the three formats which may reuse a incorrect texture format
when do the cache lookup. After this fix, we can enable fbo safely
when running with GLES2.

2. Refine the format matching method in
glamor_get_tex_format_type_from_pictformat.
If both revertion and swap_rb are needed, for example use GL_RGBA
to represent PICT_b8g8r8a8. Then the downloading and uploading should
be handled differently.

    The picture's format is PICT_b8g8r8a8,
    Then the expecting color layout is as below (little endian):
    0   1       2       3   : address
    a   r       g       b

    Now the in GLES2 the supported color format is GL_RGBA, type is
    GL_UNSIGNED_TYPE, then we need to shuffle the fragment
    color as :
        frag_color = sample(texture).argb;
    before we use glReadPixel to get it back.

    For the uploading process, the shuffle is a revert shuffle.
    We still use GL_RGBA, GL_UNSIGNED_BYTE to upload the color
    to a texture, then let's see
    0   1       2       3   : address
    a   r       g       b   : correct colors
    R   G       B       A   : GL_RGBA with GL_UNSIGNED_BYTE

    Now we need to shuffle again, the mapping rule is
    r = G, g = B, b = A, a = R. Then the uploading shuffle is as
    below:
        frag_color = sample(texture).gbar;

After this commit, gles2 version can pass render check with all
the formats except those 1555/2101010.

Signed-off-by: Zhigang Gong <zhigang.gong at linux.intel.com>
---
 src/glamor.c          |   12 +++-
 src/glamor_copyarea.c |   10 +--
 src/glamor_core.c     |  115 ++++++++++++++++++++++---------
 src/glamor_fbo.c      |   56 +++++++---------
 src/glamor_getimage.c |   29 +++++---
 src/glamor_getspans.c |   31 +++++---
 src/glamor_pixmap.c   |  181 ++++++++++++++++++++++++++-----------------------
 src/glamor_priv.h     |   19 +++--
 src/glamor_putimage.c |   13 ++--
 src/glamor_setspans.c |    7 ++-
 src/glamor_utils.h    |  115 +++++++++++++++++++++++--------
 11 files changed, 365 insertions(+), 223 deletions(-)

diff --git a/src/glamor.c b/src/glamor.c
index 532b9ef..8fc3b05 100644
--- a/src/glamor.c
+++ b/src/glamor.c
@@ -84,6 +84,7 @@ glamor_set_pixmap_texture(PixmapPtr pixmap, unsigned int tex)
 	glamor_pixmap_private *pixmap_priv;
 	glamor_screen_private *glamor_priv;
 	glamor_pixmap_fbo *fbo;
+	GLenum format;
 
 	glamor_priv = glamor_get_screen_private(screen);
 	pixmap_priv = glamor_get_pixmap_private(pixmap);
@@ -93,9 +94,10 @@ glamor_set_pixmap_texture(PixmapPtr pixmap, unsigned int tex)
 		glamor_destroy_fbo(fbo);
 	}
 
+	gl_iformat_for_depth(pixmap->drawable.depth, &format);
 	fbo = glamor_create_fbo_from_tex(glamor_priv, pixmap->drawable.width,
 					 pixmap->drawable.height,
-					 pixmap->drawable.depth, tex, 0);
+					 format, tex, 0);
 
 	if (fbo == NULL) {
 		ErrorF("XXX fail to create fbo.\n");
@@ -133,11 +135,14 @@ glamor_create_pixmap(ScreenPtr screen, int w, int h, int depth,
 	glamor_pixmap_fbo *fbo;
 	int pitch;
 	int flag;
+	GLenum format;
 
 	if (w > 32767 || h > 32767)
 		return NullPixmap;
 
-	if (usage == GLAMOR_CREATE_PIXMAP_CPU || (w == 0 && h == 0))
+	if (usage == GLAMOR_CREATE_PIXMAP_CPU
+	    || (w == 0 && h == 0)
+	    || !glamor_check_pixmap_fbo_depth(depth))
 		return fbCreatePixmap(screen, w, h, depth, usage);
 	else
 		pixmap = fbCreatePixmap(screen, 0, 0, depth, usage);
@@ -154,7 +159,8 @@ glamor_create_pixmap(ScreenPtr screen, int w, int h, int depth,
 	pixmap_priv->glamor_priv = glamor_priv;
 	pixmap_priv->type = type;
 
-	fbo = glamor_create_fbo(glamor_priv, w, h, depth, usage);
+	gl_iformat_for_depth(depth, &format);
+	fbo = glamor_create_fbo(glamor_priv, w, h, format, usage);
 
 	if (fbo == NULL) {
 		fbDestroyPixmap(pixmap);
diff --git a/src/glamor_copyarea.c b/src/glamor_copyarea.c
index 87b53a9..b488037 100644
--- a/src/glamor_copyarea.c
+++ b/src/glamor_copyarea.c
@@ -239,12 +239,10 @@ glamor_copy_n_to_n_textured(DrawablePtr src,
 						texcoords);
 		dispatch->glEnableVertexAttribArray(GLAMOR_VERTEX_SOURCE);
 		dispatch->glUseProgram(glamor_priv->finish_access_prog[0]);
-		dispatch->
-		    glUniform1i(glamor_priv->finish_access_no_revert[0],
-				1);
-		dispatch->
-		    glUniform1i(glamor_priv->finish_access_swap_rb[0], 0);
-
+		dispatch->glUniform1i(glamor_priv->finish_access_revert[0],
+				      REVERT_NONE);
+		dispatch->glUniform1i(glamor_priv->finish_access_swap_rb[0],
+				      SWAP_NONE_UPLOADING);
 	} else {
 		GLAMOR_CHECK_PENDING_FILL(dispatch, glamor_priv,
 					  src_pixmap_priv);
diff --git a/src/glamor_core.c b/src/glamor_core.c
index 0376388..f9c1db2 100644
--- a/src/glamor_core.c
+++ b/src/glamor_core.c
@@ -107,6 +107,35 @@ glamor_prepare_access(DrawablePtr drawable, glamor_access_t access)
 	return glamor_download_pixmap_to_cpu(pixmap, access);
 }
 
+/*
+ *  When downloading a unsupported color format to CPU memory,
+    we need to shuffle the color elements and then use a supported
+    color format to read it back to CPU memory.
+
+    For an example, the picture's format is PICT_b8g8r8a8,
+    Then the expecting color layout is as below (little endian):
+    0	1	2	3   : address
+    a	r	g	b
+
+    Now the in GLES2 the supported color format is GL_RGBA, type is
+    GL_UNSIGNED_TYPE, then we need to shuffle the fragment
+    color as :
+	frag_color = sample(texture).argb;
+    before we use glReadPixel to get it back.
+
+    For the uploading process, the shuffle is a revert shuffle.
+    We still use GL_RGBA, GL_UNSIGNED_BYTE to upload the color
+    to a texture, then let's see
+    0	1	2	3   : address
+    a	r	g	b   : correct colors
+    R	G	B	A   : GL_RGBA with GL_UNSIGNED_BYTE
+
+    Now we need to shuffle again, the mapping rule is
+    r = G, g = B, b = A, a = R. Then the uploading shuffle is as
+    below:
+	frag_color = sample(texture).gbar;
+*/
+
 void
 glamor_init_finish_access_shaders(ScreenPtr screen)
 {
@@ -121,53 +150,67 @@ glamor_init_finish_access_shaders(ScreenPtr screen)
 	    "	gl_Position = v_position;\n"
 	    "	source_texture = v_texcoord0.xy;\n" "}\n";
 
-	const char *fs_source =
+	const char *common_source =
 	    GLAMOR_DEFAULT_PRECISION
 	    "varying vec2 source_texture;\n"
 	    "uniform sampler2D sampler;\n"
-	    "uniform int no_revert;\n"
+	    "uniform int revert;\n"
 	    "uniform int swap_rb;\n"
+
+	    "#define REVERT_NONE       			0\n"
+	    "#define REVERT_NORMAL     			1\n"
+	    "#define SWAP_NONE_DOWNLOADING  		0\n"
+	    "#define SWAP_DOWNLOADING  			1\n"
+	    "#define SWAP_UPLOADING	  		2\n"
+	    "#define SWAP_NONE_UPLOADING		3\n";
+
+	const char *fs_source =
 	    "void main()\n"
 	    "{\n"
-	    "   if (no_revert == 1) \n"
+	    "   if (revert == REVERT_NONE) \n"
 	    "    { \n"
-	    "     if (swap_rb == 1)   \n"
-	    "	  gl_FragColor = texture2D(sampler, source_texture).bgra;\n"
+	    "     if ((swap_rb != SWAP_NONE_DOWNLOADING) && (swap_rb != SWAP_NONE_UPLOADING))   \n"
+	    "	  	gl_FragColor = texture2D(sampler, source_texture).bgra;\n"
 	    "     else \n"
-	    "	  gl_FragColor = texture2D(sampler, source_texture).rgba;\n"
+	    "	  	gl_FragColor = texture2D(sampler, source_texture).rgba;\n"
 	    "    } \n"
 	    "   else \n"
 	    "    { \n"
-	    "     if (swap_rb == 1)   \n"
-	    "	    gl_FragColor = texture2D(sampler, source_texture).argb;\n"
-	    "     else \n"
-	    "	    gl_FragColor = texture2D(sampler, source_texture).abgr;\n"
+	    "     if (swap_rb == SWAP_DOWNLOADING)   \n"
+	    "	  	gl_FragColor = texture2D(sampler, source_texture).argb;\n"
+	    "     else if (swap_rb == SWAP_NONE_DOWNLOADING)\n"
+	    "	  	gl_FragColor = texture2D(sampler, source_texture).abgr;\n"
+	    "     else if (swap_rb == SWAP_UPLOADING)\n"
+	    "	  	gl_FragColor = texture2D(sampler, source_texture).gbar;\n"
+	    "     else if (swap_rb == SWAP_NONE_UPLOADING)\n"
+	    "	  	gl_FragColor = texture2D(sampler, source_texture).abgr;\n"
 	    "    } \n" "}\n";
 
 	const char *set_alpha_source =
-	    GLAMOR_DEFAULT_PRECISION
-	    "varying vec2 source_texture;\n"
-	    "uniform sampler2D sampler;\n"
-	    "uniform int no_revert;\n"
-	    "uniform int swap_rb;\n"
 	    "void main()\n"
 	    "{\n"
-	    "   if (no_revert == 1) \n"
+	    "   if (revert == REVERT_NONE) \n"
 	    "    { \n"
-	    "     if (swap_rb == 1)   \n"
-	    "	  gl_FragColor = vec4(texture2D(sampler, source_texture).bgr, 1);\n"
+	    "     if ((swap_rb != SWAP_NONE_DOWNLOADING) && (swap_rb != SWAP_NONE_UPLOADING))   \n"
+	    "	  	gl_FragColor = vec4(texture2D(sampler, source_texture).bgr, 1);\n"
 	    "     else \n"
-	    "	  gl_FragColor = vec4(texture2D(sampler, source_texture).rgb, 1);\n"
+	    "	  	gl_FragColor = vec4(texture2D(sampler, source_texture).rgb, 1);\n"
 	    "    } \n"
 	    "   else \n"
 	    "    { \n"
-	    "     if (swap_rb == 1)   \n"
-	    "	  gl_FragColor = vec4(1,  texture2D(sampler, source_texture).rgb);\n"
-	    "     else \n"
-	    "	  gl_FragColor = vec4(1, texture2D(sampler, source_texture).bgr);\n"
-	    "    } \n" "}\n";
+	    "     if (swap_rb == SWAP_DOWNLOADING)   \n"
+	    "	  	gl_FragColor = vec4(1, texture2D(sampler, source_texture).rgb);\n"
+	    "     else if (swap_rb == SWAP_NONE_DOWNLOADING)\n"
+	    "	  	gl_FragColor = vec4(1, texture2D(sampler, source_texture).bgr);\n"
+	    "     else if (swap_rb == SWAP_UPLOADING)\n"
+	    "	  	gl_FragColor = vec4(texture2D(sampler, source_texture).gba, 1);\n"
+	    "     else if (swap_rb == SWAP_NONE_UPLOADING)\n"
+	    "	  	gl_FragColor = vec4(texture2D(sampler, source_texture).abg, 1);\n"
+	    "    } \n"
+	    "}\n";
 	GLint fs_prog, vs_prog, avs_prog, set_alpha_prog;
 	GLint sampler_uniform_location;
+	char *source;
 
 	glamor_priv = glamor_get_screen_private(screen);
 	dispatch =  glamor_get_dispatch(glamor_priv);
@@ -176,8 +219,12 @@ glamor_init_finish_access_shaders(ScreenPtr screen)
 
 	vs_prog = glamor_compile_glsl_prog(dispatch, GL_VERTEX_SHADER,
 				     vs_source);
+
+	XNFasprintf(&source, "%s%s", common_source, fs_source);
 	fs_prog = glamor_compile_glsl_prog(dispatch, GL_FRAGMENT_SHADER,
-				     fs_source);
+				     source);
+	free(source);
+
 	dispatch->glAttachShader(glamor_priv->finish_access_prog[0],
 				 vs_prog);
 	dispatch->glAttachShader(glamor_priv->finish_access_prog[0],
@@ -185,8 +232,12 @@ glamor_init_finish_access_shaders(ScreenPtr screen)
 
 	avs_prog = glamor_compile_glsl_prog(dispatch, GL_VERTEX_SHADER,
 				     vs_source);
+
+	XNFasprintf(&source, "%s%s", common_source, set_alpha_source);
 	set_alpha_prog = glamor_compile_glsl_prog(dispatch, GL_FRAGMENT_SHADER,
-				     set_alpha_source);
+						  source);
+	free(source);
+
 	dispatch->glAttachShader(glamor_priv->finish_access_prog[1],
 				 avs_prog);
 	dispatch->glAttachShader(glamor_priv->finish_access_prog[1],
@@ -208,10 +259,10 @@ glamor_init_finish_access_shaders(ScreenPtr screen)
 	glamor_link_glsl_prog(dispatch,
 			      glamor_priv->finish_access_prog[1]);
 
-	glamor_priv->finish_access_no_revert[0] =
+	glamor_priv->finish_access_revert[0] =
 	    dispatch->
 	    glGetUniformLocation(glamor_priv->finish_access_prog[0],
-				 "no_revert");
+				 "revert");
 
 	glamor_priv->finish_access_swap_rb[0] =
 	    dispatch->
@@ -223,14 +274,14 @@ glamor_init_finish_access_shaders(ScreenPtr screen)
 				 "sampler");
 	dispatch->glUseProgram(glamor_priv->finish_access_prog[0]);
 	dispatch->glUniform1i(sampler_uniform_location, 0);
-	dispatch->glUniform1i(glamor_priv->finish_access_no_revert[0], 1);
+	dispatch->glUniform1i(glamor_priv->finish_access_revert[0], 0);
 	dispatch->glUniform1i(glamor_priv->finish_access_swap_rb[0], 0);
 	dispatch->glUseProgram(0);
 
-	glamor_priv->finish_access_no_revert[1] =
+	glamor_priv->finish_access_revert[1] =
 	    dispatch->
 	    glGetUniformLocation(glamor_priv->finish_access_prog[1],
-				 "no_revert");
+				 "revert");
 	glamor_priv->finish_access_swap_rb[1] =
 	    dispatch->
 	    glGetUniformLocation(glamor_priv->finish_access_prog[1],
@@ -240,7 +291,7 @@ glamor_init_finish_access_shaders(ScreenPtr screen)
 	    glGetUniformLocation(glamor_priv->finish_access_prog[1],
 				 "sampler");
 	dispatch->glUseProgram(glamor_priv->finish_access_prog[1]);
-	dispatch->glUniform1i(glamor_priv->finish_access_no_revert[1], 1);
+	dispatch->glUniform1i(glamor_priv->finish_access_revert[1], 0);
 	dispatch->glUniform1i(sampler_uniform_location, 0);
 	dispatch->glUniform1i(glamor_priv->finish_access_swap_rb[1], 0);
 	dispatch->glUseProgram(0);
diff --git a/src/glamor_fbo.c b/src/glamor_fbo.c
index d212bd4..b15450a 100644
--- a/src/glamor_fbo.c
+++ b/src/glamor_fbo.c
@@ -62,18 +62,6 @@ inline static int cache_hbucket(int size)
 		order = CACHE_BUCKET_HCOUNT - 1;
 	return order;
 }
-inline static int cache_format(GLenum format)
-{
-	switch (format) {
-#if 0
-	case GL_ALPHA:
-		return 1;
-#endif
-	case GL_RGBA:
-	default:
-		return 0;
-	}
-}
 
 glamor_pixmap_fbo *
 glamor_pixmap_fbo_cache_get(glamor_screen_private *glamor_priv,
@@ -82,23 +70,27 @@ glamor_pixmap_fbo_cache_get(glamor_screen_private *glamor_priv,
 	struct xorg_list *cache;
 	glamor_pixmap_fbo *fbo_entry;
 	int size;
+	int n_format;
 #ifdef NO_FBO_CACHE
 	return NULL;
 #else
+	n_format = cache_format(format);
+	if (n_format == -1)
+		return NULL;
 	if (!(flag & GLAMOR_CACHE_TEXTURE))
-		cache = &glamor_priv->fbo_cache[cache_format(format)]
+		cache = &glamor_priv->fbo_cache[n_format]
 					       [cache_wbucket(w)]
 					       [cache_hbucket(h)];
 	else
-		cache = &glamor_priv->tex_cache[cache_format(format)]
+		cache = &glamor_priv->tex_cache[n_format]
 					       [cache_wbucket(w)]
 					       [cache_hbucket(h)];
 	if (!(flag & GLAMOR_CACHE_EXACT_SIZE)) {
 		xorg_list_for_each_entry(fbo_entry, cache, list) {
 			if (fbo_entry->width >= w && fbo_entry->height >= h) {
 
-				DEBUGF("Request w %d h %d \n", w, h);
-				DEBUGF("got cache entry %p w %d h %d fbo %d tex %d\n",
+				DEBUGF("Request w %d h %d format %x \n", w, h, format);
+				DEBUGF("got cache entry %p w %d h %d fbo %d tex %d format %x\n",
 					fbo_entry, fbo_entry->width, fbo_entry->height,
 					fbo_entry->fb, fbo_entry->tex);
 				xorg_list_del(&fbo_entry->list);
@@ -110,10 +102,11 @@ glamor_pixmap_fbo_cache_get(glamor_screen_private *glamor_priv,
 		xorg_list_for_each_entry(fbo_entry, cache, list) {
 			if (fbo_entry->width == w && fbo_entry->height == h) {
 
-				DEBUGF("Request w %d h %d \n", w, h);
-				DEBUGF("got cache entry %p w %d h %d fbo %d tex %d\n",
+				DEBUGF("Request w %d h %d format %x \n", w, h, format);
+				DEBUGF("got cache entry %p w %d h %d fbo %d tex %d format %x\n",
 					fbo_entry, fbo_entry->width, fbo_entry->height,
-					fbo_entry->fb, fbo_entry->tex);
+					fbo_entry->fb, fbo_entry->tex, fbo_entry->format);
+				assert(format == fbo_entry->format);
 				xorg_list_del(&fbo_entry->list);
 				return fbo_entry;
 			}
@@ -144,21 +137,25 @@ static void
 glamor_pixmap_fbo_cache_put(glamor_pixmap_fbo *fbo)
 {
 	struct xorg_list *cache;
+	int n_format;
+
 #ifdef NO_FBO_CACHE
 	glamor_purge_fbo(fbo);
 	return;
 #else
-	if (fbo->fb == 0) {
+	n_format = cache_format(fbo->format);
+
+	if (fbo->fb == 0 || n_format == -1) {
 		glamor_purge_fbo(fbo);
 		return;
 	}
 
 	if (fbo->fb)
-		cache = &fbo->glamor_priv->fbo_cache[cache_format(fbo->format)]
+		cache = &fbo->glamor_priv->fbo_cache[n_format]
 						    [cache_wbucket(fbo->width)]
 						    [cache_hbucket(fbo->height)];
 	else
-		cache = &fbo->glamor_priv->tex_cache[cache_format(fbo->format)]
+		cache = &fbo->glamor_priv->tex_cache[n_format]
 						    [cache_wbucket(fbo->width)]
 						    [cache_hbucket(fbo->height)];
 	DEBUGF("Put cache entry %p to cache %p w %d h %d format %x fbo %d tex %d \n", fbo, cache,
@@ -170,17 +167,15 @@ glamor_pixmap_fbo_cache_put(glamor_pixmap_fbo *fbo)
 
 glamor_pixmap_fbo *
 glamor_create_fbo_from_tex(glamor_screen_private *glamor_priv,
-		  int w, int h, int depth, GLint tex, int flag)
+		  int w, int h, GLenum format, GLint tex, int flag)
 {
 	glamor_pixmap_fbo *fbo;
-	GLenum format;
 
 	fbo = calloc(1, sizeof(*fbo));
 	if (fbo == NULL)
 		return NULL;
 
 	xorg_list_init(&fbo->list);
-	gl_iformat_for_depth(depth, &format);
 
 	fbo->tex = tex;
 	fbo->width = w;
@@ -338,19 +333,18 @@ glamor_destroy_tex_obj(glamor_pixmap_fbo * tex_obj)
 
 glamor_pixmap_fbo *
 glamor_create_fbo(glamor_screen_private *glamor_priv,
-		  int w, int h, int depth, int flag)
+		  int w, int h,
+		  GLenum format,
+		  int flag)
 {
 	glamor_gl_dispatch *dispatch;
 	glamor_pixmap_fbo *fbo;
-	GLenum format;
 	GLint tex;
 	int cache_flag;
 
-	if (!glamor_check_fbo_size(glamor_priv, w, h)
-	    || !glamor_check_fbo_depth(depth))
+	if (!glamor_check_fbo_size(glamor_priv, w, h))
 		return NULL;
 
-	gl_iformat_for_depth(depth, &format);
 	if (flag == GLAMOR_CREATE_FBO_NO_FBO)
 		goto new_fbo;
 
@@ -374,7 +368,7 @@ new_fbo:
 	dispatch->glTexImage2D(GL_TEXTURE_2D, 0, format, w, h, 0, format,
 			       GL_UNSIGNED_BYTE, NULL);
 
-	fbo = glamor_create_fbo_from_tex(glamor_priv, w, h, depth, tex, flag);
+	fbo = glamor_create_fbo_from_tex(glamor_priv, w, h, format, tex, flag);
 	glamor_put_dispatch(glamor_priv);
 
 	return fbo;
diff --git a/src/glamor_getimage.c b/src/glamor_getimage.c
index efbd1ba..b1093e8 100644
--- a/src/glamor_getimage.c
+++ b/src/glamor_getimage.c
@@ -39,10 +39,11 @@ _glamor_get_image(DrawablePtr drawable, int x, int y, int w, int h,
 	struct glamor_screen_private *glamor_priv;
 	int x_off, y_off;
 	GLenum tex_format, tex_type;
-	int no_alpha, no_revert;
-	PixmapPtr temp_pixmap = NULL;
+	int no_alpha, revert;
+	glamor_pixmap_fbo *temp_fbo = NULL;
 	glamor_gl_dispatch * dispatch;
 	Bool ret = FALSE;
+	int swap_rb;
 
 	goto fall_back;
 
@@ -69,7 +70,9 @@ _glamor_get_image(DrawablePtr drawable, int x, int y, int w, int h,
 						   &tex_format,
 						   &tex_type,
 						   &no_alpha,
-						   &no_revert)) {
+						   &revert,
+						   &swap_rb,
+						   0)) {
 		glamor_fallback("unknown depth. %d \n", drawable->depth);
 		goto fall_back;
 	}
@@ -78,14 +81,16 @@ _glamor_get_image(DrawablePtr drawable, int x, int y, int w, int h,
 	glamor_validate_pixmap(pixmap);
 
 	if (glamor_priv->gl_flavor == GLAMOR_GL_ES2
-	    && (glamor_tex_format_is_readable(format) || !no_revert)) {
+	    && ( swap_rb != SWAP_NONE_DOWNLOADING
+		 || revert != REVERT_NONE)) {
 		/* XXX prepare whole pixmap is not efficient. */
-		temp_pixmap =
-		    glamor_es2_pixmap_read_prepare(pixmap, &tex_format,
-						   &tex_type, no_alpha,
-						   no_revert);
-		pixmap_priv = glamor_get_pixmap_private(temp_pixmap);
-		glamor_set_destination_pixmap_priv_nc(pixmap_priv);
+		temp_fbo =
+		    glamor_es2_pixmap_read_prepare(pixmap, tex_format,
+						   tex_type, no_alpha,
+						   revert, swap_rb);
+		if (temp_fbo == NULL)
+			goto fall_back;
+
 	}
 
 	int row_length = PixmapBytePad(w, drawable->depth);
@@ -113,8 +118,8 @@ _glamor_get_image(DrawablePtr drawable, int x, int y, int w, int h,
 				       tex_format,
 				       tex_type, d);
 	glamor_put_dispatch(glamor_priv);
-	if (temp_pixmap)
-		glamor_destroy_pixmap(temp_pixmap);
+	if (temp_fbo)
+		glamor_destroy_fbo(temp_fbo);
 
 	ret = TRUE;
 
diff --git a/src/glamor_getspans.c b/src/glamor_getspans.c
index 91030a3..8341df4 100644
--- a/src/glamor_getspans.c
+++ b/src/glamor_getspans.c
@@ -35,17 +35,18 @@ _glamor_get_spans(DrawablePtr drawable,
 {
 	PixmapPtr pixmap = glamor_get_drawable_pixmap(drawable);
 	GLenum format, type;
-	int no_alpha, no_revert;
+	int no_alpha, revert;
 	glamor_screen_private *glamor_priv =
 	    glamor_get_screen_private(drawable->pScreen);
 	glamor_pixmap_private *pixmap_priv =
 	    glamor_get_pixmap_private(pixmap);
 	glamor_gl_dispatch *dispatch;
-	PixmapPtr temp_pixmap = NULL;
+	glamor_pixmap_fbo *temp_fbo = NULL;
 	int i;
 	uint8_t *readpixels_dst = (uint8_t *) dst;
 	int x_off, y_off;
 	Bool ret = FALSE;
+	int swap_rb;
 
 	if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv)) {
 		glamor_fallback("pixmap has no fbo.\n");
@@ -55,24 +56,29 @@ _glamor_get_spans(DrawablePtr drawable,
 	if (glamor_get_tex_format_type_from_pixmap(pixmap,
 						   &format,
 						   &type, &no_alpha,
-						   &no_revert)) {
+						   &revert, &swap_rb, 0)) {
 		glamor_fallback("unknown depth. %d \n", drawable->depth);
 		goto fail;
 	}
 
+	if (revert > REVERT_NORMAL)
+		goto fail;
+
 	glamor_set_destination_pixmap_priv_nc(pixmap_priv);
 	glamor_validate_pixmap(pixmap);
 
 	if (glamor_priv->gl_flavor == GLAMOR_GL_ES2
-	    && (!glamor_tex_format_is_readable(format) || !no_revert)) {
+	    && ( swap_rb != SWAP_NONE_DOWNLOADING
+		 || revert != REVERT_NONE)) {
 
 		/* XXX prepare whole pixmap is not efficient. */
-		temp_pixmap =
-		    glamor_es2_pixmap_read_prepare(pixmap, &format,
-						   &type, no_alpha,
-						   no_revert);
-		pixmap_priv = glamor_get_pixmap_private(temp_pixmap);
-		glamor_set_destination_pixmap_priv_nc(pixmap_priv);
+		temp_fbo =
+		    glamor_es2_pixmap_read_prepare(pixmap, format,
+						   type, no_alpha,
+						   revert, swap_rb);
+		if (temp_fbo == NULL)
+			goto fail;
+
 	}
 
 	glamor_get_drawable_deltas(drawable, pixmap, &x_off, &y_off);
@@ -94,8 +100,8 @@ _glamor_get_spans(DrawablePtr drawable,
 		    PixmapBytePad(widths[i], drawable->depth);
 	}
 	glamor_put_dispatch(glamor_priv);
-	if (temp_pixmap)
-		glamor_destroy_pixmap(temp_pixmap);
+	if (temp_fbo)
+		glamor_destroy_fbo(temp_fbo);
 
 	ret = TRUE;
 	goto done;
@@ -105,6 +111,7 @@ fail:
 	    && glamor_ddx_fallback_check_pixmap(drawable))
 		goto done;
 
+	ret = TRUE;
 	glamor_fallback("from %p (%c)\n", drawable,
 			glamor_get_drawable_location(drawable));
 	if (glamor_prepare_access(drawable, GLAMOR_ACCESS_RO)) {
diff --git a/src/glamor_pixmap.c b/src/glamor_pixmap.c
index 7f4a90b..0570a9a 100644
--- a/src/glamor_pixmap.c
+++ b/src/glamor_pixmap.c
@@ -89,10 +89,10 @@ glamor_validate_pixmap(PixmapPtr pixmap)
 }
 
 void
-glamor_set_destination_pixmap_priv_nc(glamor_pixmap_private * pixmap_priv)
+glamor_set_destination_pixmap_fbo(glamor_pixmap_fbo * fbo)
 {
-	glamor_gl_dispatch *dispatch = glamor_get_dispatch(pixmap_priv->glamor_priv);
-	dispatch->glBindFramebuffer(GL_FRAMEBUFFER, pixmap_priv->fbo->fb);
+	glamor_gl_dispatch *dispatch = glamor_get_dispatch(fbo->glamor_priv);
+	dispatch->glBindFramebuffer(GL_FRAMEBUFFER, fbo->fb);
 #ifndef GLAMOR_GLES2
 	dispatch->glMatrixMode(GL_PROJECTION);
 	dispatch->glLoadIdentity();
@@ -100,10 +100,16 @@ glamor_set_destination_pixmap_priv_nc(glamor_pixmap_private * pixmap_priv)
 	dispatch->glLoadIdentity();
 #endif
 	dispatch->glViewport(0, 0,
-			     pixmap_priv->fbo->width,
-			     pixmap_priv->fbo->height);
+			     fbo->width,
+			     fbo->height);
+
+	glamor_put_dispatch(fbo->glamor_priv);
+}
 
-	glamor_put_dispatch(pixmap_priv->glamor_priv);
+void
+glamor_set_destination_pixmap_priv_nc(glamor_pixmap_private * pixmap_priv)
+{
+	glamor_set_destination_pixmap_fbo(pixmap_priv->fbo);
 }
 
 int
@@ -280,9 +286,8 @@ __glamor_upload_pixmap_to_texture(PixmapPtr pixmap, GLenum format,
  * */
 
 static void
-_glamor_upload_pixmap_to_texture(PixmapPtr pixmap, GLenum format,
-				 GLenum type, int no_alpha, int no_revert,
-				 int flip)
+_glamor_upload_pixmap_to_texture(PixmapPtr pixmap, GLenum format, GLenum type,
+				int no_alpha, int revert, int swap_rb)
 {
 
 	glamor_pixmap_private *pixmap_priv =
@@ -308,7 +313,7 @@ _glamor_upload_pixmap_to_texture(PixmapPtr pixmap, GLenum format,
 
 	if (!pixmap_priv)
 		return;
-	need_flip = (flip && !glamor_priv->yInverted);
+	need_flip = !glamor_priv->yInverted;
 
 	glamor_debug_output(GLAMOR_DEBUG_TEXTURE_DYNAMIC_UPLOAD,
 			    "Uploading pixmap %p  %dx%d depth%d.\n",
@@ -319,7 +324,11 @@ _glamor_upload_pixmap_to_texture(PixmapPtr pixmap, GLenum format,
 
 	/* Try fast path firstly, upload the pixmap to the texture attached
 	 * to the fbo directly. */
-	if (no_alpha == 0 && no_revert == 1 && !need_flip) {
+	if (no_alpha == 0
+	    && revert == REVERT_NONE
+	    && swap_rb == SWAP_NONE_UPLOADING
+	    && !need_flip) {
+
 		__glamor_upload_pixmap_to_texture(pixmap, format, type,
 						  pixmap_priv->fbo->tex, 1);
 		return;
@@ -365,10 +374,10 @@ _glamor_upload_pixmap_to_texture(PixmapPtr pixmap, GLenum format,
 #endif
 	dispatch->glUseProgram(glamor_priv->finish_access_prog[no_alpha]);
 	dispatch->glUniform1i(glamor_priv->
-			      finish_access_no_revert[no_alpha],
-			      no_revert);
+			      finish_access_revert[no_alpha],
+			      revert);
 	dispatch->glUniform1i(glamor_priv->finish_access_swap_rb[no_alpha],
-			      0);
+			      swap_rb);
 
 	dispatch->glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
 
@@ -441,18 +450,22 @@ glamor_pixmap_ensure_fb(glamor_pixmap_fbo *fbo)
  * 2. no_alpha != 0, we need to wire the alpha.
  * */
 static int
-glamor_pixmap_upload_prepare(PixmapPtr pixmap, int no_alpha, int no_revert)
+glamor_pixmap_upload_prepare(PixmapPtr pixmap, GLenum format, int no_alpha, int revert, int swap_rb)
 {
 	int flag;
 	glamor_pixmap_private *pixmap_priv;
 	glamor_screen_private *glamor_priv;
-	GLenum format;
 	glamor_pixmap_fbo *fbo;
+	GLenum iformat;
 
 	pixmap_priv = glamor_get_pixmap_private(pixmap);
 	glamor_priv = glamor_get_screen_private(pixmap->drawable.pScreen);
 
-	if (!(no_alpha || !no_revert || !glamor_priv->yInverted)) {
+	if (!(no_alpha
+	      || (revert != REVERT_NONE)
+	      || (swap_rb != SWAP_NONE_UPLOADING)
+	      || !glamor_priv->yInverted)) {
+		/* We don't need a fbo, a simple texture uploading should work. */
 
 		if (pixmap_priv && pixmap_priv->fbo)
 			return 0;
@@ -464,9 +477,15 @@ glamor_pixmap_upload_prepare(PixmapPtr pixmap, int no_alpha, int no_revert)
 		flag = 0;
 	}
 
+	if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP)
+		gl_iformat_for_depth(pixmap->drawable.depth, &iformat);
+	else
+		iformat = format;
+
+
 	fbo = glamor_create_fbo(glamor_priv, pixmap->drawable.width,
 				pixmap->drawable.height,
-				pixmap->drawable.depth,
+				iformat,
 				flag);
 	if (fbo == NULL) {
 		glamor_fallback
@@ -485,20 +504,24 @@ enum glamor_pixmap_status
 glamor_upload_pixmap_to_texture(PixmapPtr pixmap)
 {
 	GLenum format, type;
-	int no_alpha, no_revert;
+	int no_alpha, revert, swap_rb;
 
 	if (glamor_get_tex_format_type_from_pixmap(pixmap,
 						   &format,
-						   &type, &no_alpha,
-						   &no_revert)) {
+						   &type,
+						   &no_alpha,
+						   &revert,
+						   &swap_rb, 1)) {
 		glamor_fallback("Unknown pixmap depth %d.\n",
 				pixmap->drawable.depth);
 		return GLAMOR_UPLOAD_FAILED;
 	}
-	if (glamor_pixmap_upload_prepare(pixmap, no_alpha, no_revert))
+
+	if (glamor_pixmap_upload_prepare(pixmap, format, no_alpha, revert, swap_rb))
 		return GLAMOR_UPLOAD_FAILED;
+
 	_glamor_upload_pixmap_to_texture(pixmap, format, type, no_alpha,
-					 no_revert, 1);
+					 revert, swap_rb);
 	return GLAMOR_UPLOAD_DONE;
 }
 
@@ -523,21 +546,19 @@ void
 glamor_restore_pixmap_to_texture(PixmapPtr pixmap)
 {
 	GLenum format, type;
-	int no_alpha, no_revert;
+	int no_alpha, revert, swap_rb;
 
 	if (glamor_get_tex_format_type_from_pixmap(pixmap,
 						   &format,
 						   &type, &no_alpha,
-						   &no_revert)) {
+						   &revert, &swap_rb, 1)) {
 		ErrorF("Unknown pixmap depth %d.\n",
 		       pixmap->drawable.depth);
 		assert(0);
 	}
 
-	in_restore = 1;
 	_glamor_upload_pixmap_to_texture(pixmap, format, type, no_alpha,
-					 no_revert, 1);
-	in_restore = 0;
+					 revert, swap_rb);
 }
 
 /* 
@@ -548,65 +569,56 @@ glamor_restore_pixmap_to_texture(PixmapPtr pixmap)
  * get a new temporary pixmap returned.
  * */
 
-PixmapPtr
-glamor_es2_pixmap_read_prepare(PixmapPtr source, GLenum * format,
-			       GLenum * type, int no_alpha, int no_revert)
+glamor_pixmap_fbo *
+glamor_es2_pixmap_read_prepare(PixmapPtr source, GLenum format,
+			       GLenum type, int no_alpha, int revert, int swap_rb)
+
 {
 	glamor_pixmap_private *source_priv;
 	glamor_screen_private *glamor_priv;
 	ScreenPtr screen;
-	PixmapPtr temp_pixmap;
-	glamor_pixmap_private *temp_pixmap_priv;
+	glamor_pixmap_fbo *temp_fbo;
 	glamor_gl_dispatch *dispatch;
-	static float vertices[8] = { -1, -1,
-		1, -1,
-		1, 1,
-		-1, 1
-	};
-	static float texcoords[8] = { 0, 0,
-		1, 0,
-		1, 1,
-		0, 1
-	};
-
-	int swap_rb = 0;
+	float temp_xscale, temp_yscale, source_xscale, source_yscale;
+	static float vertices[8];
+	static float texcoords[8];
 
 	screen = source->drawable.pScreen;
 
 	glamor_priv = glamor_get_screen_private(screen);
 	source_priv = glamor_get_pixmap_private(source);
-	if (*format == GL_BGRA) {
-		*format = GL_RGBA;
-		swap_rb = 1;
-	}
-
-
-	temp_pixmap = glamor_create_pixmap (screen,
-					    source->drawable.width,
-					    source->drawable.height,
-					    source->drawable.depth, 0);
-
-	temp_pixmap_priv = glamor_get_pixmap_private(temp_pixmap);
+	temp_fbo = glamor_create_fbo(glamor_priv,
+				     source->drawable.width,
+				     source->drawable.height,
+				     format,
+				     0);
+	if (temp_fbo == NULL)
+		return NULL;
 
 	dispatch = glamor_get_dispatch(glamor_priv);
-	dispatch->glBindTexture(GL_TEXTURE_2D, temp_pixmap_priv->fbo->tex);
-	dispatch->glTexParameteri(GL_TEXTURE_2D,
-				  GL_TEXTURE_MIN_FILTER,
-				  GL_NEAREST);
-	dispatch->glTexParameteri(GL_TEXTURE_2D,
-				  GL_TEXTURE_MAG_FILTER,
-				  GL_NEAREST);
+	temp_xscale = 1.0 / temp_fbo->width;
+	temp_yscale = 1.0 / temp_fbo->height;
 
-	dispatch->glTexImage2D(GL_TEXTURE_2D, 0, *format,
-			       source->drawable.width,
-			       source->drawable.height, 0, *format, *type,
-			       NULL);
+	glamor_set_normalize_vcoords(temp_xscale,
+				     temp_yscale,
+				     0, 0,
+				     source->drawable.width, source->drawable.height,
+				     glamor_priv->yInverted,
+				     vertices);
 
 	dispatch->glVertexAttribPointer(GLAMOR_VERTEX_POS, 2, GL_FLOAT,
 					GL_FALSE, 2 * sizeof(float),
 					vertices);
 	dispatch->glEnableVertexAttribArray(GLAMOR_VERTEX_POS);
 
+	pixmap_priv_get_scale(source_priv, &source_xscale, &source_yscale);
+	glamor_set_normalize_tcoords(source_xscale,
+				     source_yscale,
+				     0, 0,
+				     source->drawable.width, source->drawable.height,
+				     glamor_priv->yInverted,
+				     texcoords);
+
 	dispatch->glVertexAttribPointer(GLAMOR_VERTEX_SOURCE, 2, GL_FLOAT,
 					GL_FALSE, 2 * sizeof(float),
 					texcoords);
@@ -621,12 +633,11 @@ glamor_es2_pixmap_read_prepare(PixmapPtr source, GLenum * format,
 				  GL_TEXTURE_MAG_FILTER,
 				  GL_NEAREST);
 
-	glamor_set_destination_pixmap_priv_nc(temp_pixmap_priv);
-
+	glamor_set_destination_pixmap_fbo(temp_fbo);
 	dispatch->glUseProgram(glamor_priv->finish_access_prog[no_alpha]);
 	dispatch->glUniform1i(glamor_priv->
-			      finish_access_no_revert[no_alpha],
-			      no_revert);
+			      finish_access_revert[no_alpha],
+			      revert);
 	dispatch->glUniform1i(glamor_priv->finish_access_swap_rb[no_alpha],
 			      swap_rb);
 
@@ -636,7 +647,7 @@ glamor_es2_pixmap_read_prepare(PixmapPtr source, GLenum * format,
 	dispatch->glDisableVertexAttribArray(GLAMOR_VERTEX_SOURCE);
 	dispatch->glUseProgram(0);
 	glamor_put_dispatch(glamor_priv);
-	return temp_pixmap;
+	return temp_fbo;
 }
 
 
@@ -656,21 +667,23 @@ glamor_download_pixmap_to_cpu(PixmapPtr pixmap, glamor_access_t access)
 	    glamor_get_pixmap_private(pixmap);
 	unsigned int stride, row_length, y;
 	GLenum format, type, gl_access, gl_usage;
-	int no_alpha, no_revert;
+	int no_alpha, revert, swap_rb;
 	uint8_t *data = NULL, *read;
-	PixmapPtr temp_pixmap = NULL;
 	ScreenPtr screen;
 	glamor_screen_private *glamor_priv =
 	    glamor_get_screen_private(pixmap->drawable.pScreen);
 	glamor_gl_dispatch *dispatch;
+	glamor_pixmap_fbo *temp_fbo = NULL;
 
 	screen = pixmap->drawable.pScreen;
 	if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv))
 		return TRUE;
 	if (glamor_get_tex_format_type_from_pixmap(pixmap,
 						   &format,
-						   &type, &no_alpha,
-						   &no_revert)) {
+						   &type,
+						   &no_alpha,
+						   &revert,
+						   &swap_rb, 0)) {
 		ErrorF("Unknown pixmap depth %d.\n",
 		       pixmap->drawable.depth);
 		assert(0);	// Should never happen.
@@ -692,11 +705,11 @@ glamor_download_pixmap_to_cpu(PixmapPtr pixmap, glamor_access_t access)
 	glamor_validate_pixmap(pixmap);
 
 	if (glamor_priv->gl_flavor == GLAMOR_GL_ES2
-	    && (!glamor_tex_format_is_readable(format) || !no_revert)) {
-		temp_pixmap =
-		    glamor_es2_pixmap_read_prepare(pixmap, &format,
-						   &type, no_alpha,
-						   no_revert);
+	    && (swap_rb != SWAP_NONE_DOWNLOADING || revert != REVERT_NONE)) {
+		 if (!(temp_fbo = glamor_es2_pixmap_read_prepare(pixmap, format,
+								 type, no_alpha,
+								 revert, swap_rb)))
+			return FALSE;
 	}
 	switch (access) {
 	case GLAMOR_ACCESS_RO:
@@ -807,8 +820,8 @@ glamor_download_pixmap_to_cpu(PixmapPtr pixmap, glamor_access_t access)
 	pixmap_priv->gl_fbo = GLAMOR_FBO_DOWNLOADED;
 	pixmap->devPrivate.ptr = data;
 
-	if (temp_pixmap)
-		glamor_destroy_pixmap(temp_pixmap);
+	if (temp_fbo != NULL)
+		glamor_destroy_fbo(temp_fbo);
 
 	return TRUE;
 }
diff --git a/src/glamor_priv.h b/src/glamor_priv.h
index ad68737..b32ce29 100644
--- a/src/glamor_priv.h
+++ b/src/glamor_priv.h
@@ -182,7 +182,12 @@ struct glamor_saved_procs {
 	UnrealizeGlyphProcPtr unrealize_glyph;
 };
 
+#ifdef GLAMOR_GLES2
+#define CACHE_FORMAT_COUNT 3
+#else
 #define CACHE_FORMAT_COUNT 1
+#endif
+
 #define CACHE_BUCKET_WCOUNT 4
 #define CACHE_BUCKET_HCOUNT 4
 
@@ -221,7 +226,7 @@ typedef struct glamor_screen_private {
 
 	/* shaders to restore a texture to another texture.*/
 	GLint finish_access_prog[2];
-	GLint finish_access_no_revert[2];
+	GLint finish_access_revert[2];
 	GLint finish_access_swap_rb[2];
 
 	/* glamor_tile */
@@ -395,9 +400,9 @@ Bool glamor_destroy_pixmap(PixmapPtr pixmap);
 glamor_pixmap_fbo* glamor_pixmap_detach_fbo(glamor_pixmap_private *pixmap_priv);
 void glamor_pixmap_attach_fbo(PixmapPtr pixmap, glamor_pixmap_fbo *fbo);
 glamor_pixmap_fbo * glamor_create_fbo_from_tex(glamor_screen_private *glamor_priv,
-					       int w, int h, int depth, GLint tex, int flag);
+					       int w, int h, GLenum format, GLint tex, int flag);
 glamor_pixmap_fbo * glamor_create_fbo(glamor_screen_private *glamor_priv,
-				      int w, int h, int depth, int flag);
+				      int w, int h, GLenum format, int flag);
 void glamor_destroy_fbo(glamor_pixmap_fbo *fbo);
 void glamor_purge_fbo(glamor_pixmap_fbo *fbo);
 
@@ -451,6 +456,7 @@ void glamor_get_color_4f_from_pixel(PixmapPtr pixmap,
 int glamor_set_destination_pixmap(PixmapPtr pixmap);
 int glamor_set_destination_pixmap_priv(glamor_pixmap_private *
 				       pixmap_priv);
+void glamor_set_destination_pixmap_fbo(glamor_pixmap_fbo *);
 
 /* nc means no check. caller must ensure this pixmap has valid fbo.
  * usually use the GLAMOR_PIXMAP_PRIV_HAS_FBO firstly. 
@@ -458,10 +464,9 @@ int glamor_set_destination_pixmap_priv(glamor_pixmap_private *
 void glamor_set_destination_pixmap_priv_nc(glamor_pixmap_private *
 					   pixmap_priv);
 
-
-PixmapPtr
-glamor_es2_pixmap_read_prepare(PixmapPtr source, GLenum * format,
-			       GLenum * type, int no_alpha, int no_revert);
+glamor_pixmap_fbo *
+glamor_es2_pixmap_read_prepare(PixmapPtr source, GLenum format,
+			       GLenum type, int no_alpha, int revert, int swap_rb);
 
 void glamor_set_alu(struct glamor_gl_dispatch *dispatch,
 		    unsigned char alu);
diff --git a/src/glamor_putimage.c b/src/glamor_putimage.c
index 75e5b4c..e38c45a 100644
--- a/src/glamor_putimage.c
+++ b/src/glamor_putimage.c
@@ -264,8 +264,9 @@ _glamor_put_image(DrawablePtr drawable, GCPtr gc, int depth, int x, int y,
 	float vertices[8], texcoords[8];
 	GLfloat xscale, yscale, txscale, tyscale;
 	GLuint tex;
-	int no_alpha, no_revert;
+	int no_alpha, revert;
 	Bool ret = FALSE;
+	int swap_rb;
 
 	if (image_format == XYBitmap) {
 		assert(depth == 1);
@@ -289,7 +290,9 @@ _glamor_put_image(DrawablePtr drawable, GCPtr gc, int depth, int x, int y,
 	if (glamor_get_tex_format_type_from_pixmap(pixmap,
 						   &format,
 						   &type, &no_alpha,
-						   &no_revert)) {
+						   &revert,
+						   &swap_rb,
+						   1)) {
 		glamor_fallback("unknown depth. %d \n", drawable->depth);
 		goto fail;
 	}
@@ -341,10 +344,10 @@ _glamor_put_image(DrawablePtr drawable, GCPtr gc, int depth, int x, int y,
 #endif
 	dispatch->glUseProgram(glamor_priv->finish_access_prog[no_alpha]);
 	dispatch->glUniform1i(glamor_priv->
-			      finish_access_no_revert[no_alpha],
-			      no_revert);
+			      finish_access_revert[no_alpha],
+			      revert);
 	dispatch->glUniform1i(glamor_priv->finish_access_swap_rb[no_alpha],
-			      0);
+			      swap_rb);
 
 	x += drawable->x;
 	y += drawable->y;
diff --git a/src/glamor_setspans.c b/src/glamor_setspans.c
index a947169..b6847a9 100644
--- a/src/glamor_setspans.c
+++ b/src/glamor_setspans.c
@@ -38,12 +38,13 @@ _glamor_set_spans(DrawablePtr drawable, GCPtr gc, char *src,
 	    glamor_get_screen_private(drawable->pScreen);
 	glamor_gl_dispatch *dispatch;
 	GLenum format, type;
-	int no_alpha, no_revert, i;
+	int no_alpha, revert, i;
 	uint8_t *drawpixels_src = (uint8_t *) src;
 	RegionPtr clip = fbGetCompositeClip(gc);
 	BoxRec *pbox;
 	int x_off, y_off;
 	Bool ret = FALSE;
+	int swap_rb;
 
 	dest_pixmap_priv = glamor_get_pixmap_private(dest_pixmap);
 	if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(dest_pixmap_priv)) {
@@ -59,7 +60,9 @@ _glamor_set_spans(DrawablePtr drawable, GCPtr gc, char *src,
 	if (glamor_get_tex_format_type_from_pixmap(dest_pixmap,
 						   &format,
 						   &type, &no_alpha,
-						   &no_revert)) {
+						   &revert,
+						   &swap_rb,
+						   1)) {
 		glamor_fallback("unknown depth. %d \n", drawable->depth);
 		goto fail;
 	}
diff --git a/src/glamor_utils.h b/src/glamor_utils.h
index 29b7b12..c08d96f 100644
--- a/src/glamor_utils.h
+++ b/src/glamor_utils.h
@@ -194,14 +194,14 @@ glamor_transform_boxes(BoxPtr boxes, int nbox, int dx, int dy)
                                                     && (_w_) < _glamor_->max_fbo_size  \
                                                     && (_h_) < _glamor_->max_fbo_size)
 
-#define glamor_check_fbo_depth(_depth_) (			\
-                                         _depth_ == 8		\
-	                                 || _depth_ == 15	\
-                                         || _depth_ == 16	\
-                                         || _depth_ == 24	\
-                                         || _depth_ == 30	\
-                                         || _depth_ == 32)
-
+/* For 1bpp pixmap, we don't store it as texture. */
+#define glamor_check_pixmap_fbo_depth(_depth_) (			\
+                                         	_depth_ == 8		\
+						|| _depth_ == 15	\
+						|| _depth_ == 16	\
+						|| _depth_ == 24	\
+						|| _depth_ == 30	\
+						|| _depth_ == 32)
 
 #define GLAMOR_PIXMAP_PRIV_IS_PICTURE(pixmap_priv) (pixmap_priv && pixmap_priv->is_picture == 1)
 #define GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv)    (pixmap_priv && pixmap_priv->gl_fbo == GLAMOR_FBO_NORMAL)
@@ -286,6 +286,14 @@ format_for_pixmap(PixmapPtr pixmap)
 	return pict_format;
 }
 
+
+#define REVERT_NONE       		0
+#define REVERT_NORMAL     		1
+#define SWAP_NONE_DOWNLOADING  	0
+#define SWAP_DOWNLOADING  	1
+#define SWAP_UPLOADING	  	2
+#define SWAP_NONE_UPLOADING	3
+
 /*
  * Map picture's format to the correct gl texture format and type.
  * no_alpha is used to indicate whehter we need to wire alpha to 1. 
@@ -297,10 +305,15 @@ static inline int
 glamor_get_tex_format_type_from_pictformat(PictFormatShort format,
 					   GLenum * tex_format,
 					   GLenum * tex_type,
-					   int *no_alpha, int *no_revert)
+					   int *no_alpha,
+					   int *revert,
+					   int *swap_rb,
+					   int is_upload)
+
 {
 	*no_alpha = 0;
-	*no_revert = 1;
+	*revert = REVERT_NONE;
+	*swap_rb = is_upload ? SWAP_NONE_UPLOADING : SWAP_NONE_DOWNLOADING;
 	switch (format) {
 	case PICT_a1:
 		*tex_format = GL_COLOR_INDEX;
@@ -385,6 +398,18 @@ glamor_get_tex_format_type_from_pictformat(PictFormatShort format,
 	}
 	return 0;
 }
+
+/* Currently, we use RGBA to represent all formats. */
+inline static int cache_format(GLenum format)
+{
+	switch (format) {
+	case GL_RGBA:
+		return 0;
+	default:
+		return -1;
+	}
+}
+
 #else
 #define IS_LITTLE_ENDIAN  (IMAGE_BYTE_ORDER == LSBFirst)
 
@@ -392,25 +417,32 @@ static inline int
 glamor_get_tex_format_type_from_pictformat(PictFormatShort format,
 					   GLenum * tex_format,
 					   GLenum * tex_type,
-					   int *no_alpha, int *no_revert)
+					   int *no_alpha,
+					   int *revert,
+					   int *swap_rb,
+					   int is_upload)
 {
+	int need_swap_rb = 0;
+
 	*no_alpha = 0;
-	*no_revert = IS_LITTLE_ENDIAN;
+	*revert = IS_LITTLE_ENDIAN ? REVERT_NONE : REVERT_NORMAL;
 
 	switch (format) {
 	case PICT_b8g8r8x8:
 		*no_alpha = 1;
 	case PICT_b8g8r8a8:
-		*tex_format = GL_BGRA;
+		*tex_format = GL_RGBA;
 		*tex_type = GL_UNSIGNED_BYTE;
-		*no_revert = !IS_LITTLE_ENDIAN;
+		need_swap_rb = 1;
+		*revert = IS_LITTLE_ENDIAN ? REVERT_NORMAL : REVERT_NONE;
 		break;
 
 	case PICT_x8r8g8b8:
 		*no_alpha = 1;
 	case PICT_a8r8g8b8:
-		*tex_format = GL_BGRA;
+		*tex_format = GL_RGBA;
 		*tex_type = GL_UNSIGNED_BYTE;
+		need_swap_rb = 1;
 		break;
 
 	case PICT_x8b8g8r8:
@@ -425,7 +457,7 @@ glamor_get_tex_format_type_from_pictformat(PictFormatShort format,
 	case PICT_a2r10g10b10:
 		*tex_format = GL_BGRA;
 		*tex_type = GL_UNSIGNED_INT_10_10_10_2;
-		*no_revert = TRUE;
+		*revert = REVERT_NONE;
 		break;
 
 	case PICT_x2b10g10r10:
@@ -433,19 +465,20 @@ glamor_get_tex_format_type_from_pictformat(PictFormatShort format,
 	case PICT_a2b10g10r10:
 		*tex_format = GL_RGBA;
 		*tex_type = GL_UNSIGNED_INT_10_10_10_2;
-		*no_revert = TRUE;
+		*revert = REVERT_NONE;
 		break;
 
 	case PICT_r5g6b5:
 		*tex_format = GL_RGB;
 		*tex_type = GL_UNSIGNED_SHORT_5_6_5;
-		*no_revert = TRUE;
+		*revert = IS_LITTLE_ENDIAN ? REVERT_NONE : REVERT_NORMAL;
+
 		break;
 
 	case PICT_b5g6r5:
 		*tex_format = GL_RGB;
 		*tex_type = GL_UNSIGNED_SHORT_5_6_5;
-		*no_revert = FALSE;
+		need_swap_rb = IS_LITTLE_ENDIAN ? 1 : 0;;
 		break;
 
 	case PICT_x1b5g5r5:
@@ -453,7 +486,7 @@ glamor_get_tex_format_type_from_pictformat(PictFormatShort format,
 	case PICT_a1b5g5r5:
 		*tex_format = GL_RGBA;
 		*tex_type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
-		*no_revert = TRUE;
+		*revert = REVERT_NONE;
 		break;
 
 	case PICT_x1r5g5b5:
@@ -461,29 +494,30 @@ glamor_get_tex_format_type_from_pictformat(PictFormatShort format,
 	case PICT_a1r5g5b5:
 		*tex_format = GL_BGRA;
 		*tex_type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
-		*no_revert = TRUE;
+		*revert = REVERT_NONE;
 		break;
 
 	case PICT_a8:
 		*tex_format = GL_ALPHA;
 		*tex_type = GL_UNSIGNED_BYTE;
-		*no_revert = TRUE;
+		*revert = REVERT_NONE;
 		break;
 
 	case PICT_x4r4g4b4:
 		*no_alpha = 1;
 	case PICT_a4r4g4b4:
-		*tex_format = GL_BGRA;
-		*tex_type = GL_UNSIGNED_SHORT_4_4_4_4_REV;
-		*no_revert = TRUE;
+		*tex_format = GL_RGBA;
+		*tex_type = GL_UNSIGNED_SHORT_4_4_4_4;
+		*revert = IS_LITTLE_ENDIAN ? REVERT_NORMAL : REVERT_NONE;
+		need_swap_rb = 1;
 		break;
 
 	case PICT_x4b4g4r4:
 		*no_alpha = 1;
 	case PICT_a4b4g4r4:
 		*tex_format = GL_RGBA;
-		*tex_type = GL_UNSIGNED_SHORT_4_4_4_4_REV;
-		*no_revert = TRUE;
+		*tex_type = GL_UNSIGNED_SHORT_4_4_4_4;
+		*revert = IS_LITTLE_ENDIAN ? REVERT_NORMAL : REVERT_NONE;
 		break;
 
 	default:
@@ -492,9 +526,27 @@ glamor_get_tex_format_type_from_pictformat(PictFormatShort format,
 			       format);
 		return -1;
 	}
+
+	if (need_swap_rb)
+		*swap_rb = is_upload ? SWAP_UPLOADING : SWAP_DOWNLOADING;
+	else
+		*swap_rb = is_upload ? SWAP_NONE_UPLOADING : SWAP_NONE_DOWNLOADING;
 	return 0;
 }
 
+inline static int cache_format(GLenum format)
+{
+	switch (format) {
+	case GL_ALPHA:
+		return 2;
+	case GL_RGB:
+		return 1;
+	case GL_RGBA:
+		return 0;
+	default:
+		return -1;
+	}
+}
 
 #endif
 
@@ -503,7 +555,10 @@ static inline int
 glamor_get_tex_format_type_from_pixmap(PixmapPtr pixmap,
 				       GLenum * format,
 				       GLenum * type,
-				       int *no_alpha, int *no_revert)
+				       int *no_alpha,
+				       int *revert,
+				       int *swap_rb,
+				       int is_upload)
 {
 	glamor_pixmap_private *pixmap_priv;
 	PictFormatShort pict_format;
@@ -517,7 +572,9 @@ glamor_get_tex_format_type_from_pixmap(PixmapPtr pixmap,
 	return glamor_get_tex_format_type_from_pictformat(pict_format,
 							  format, type,
 							  no_alpha,
-							  no_revert);
+							  revert,
+							  swap_rb,
+							  is_upload);
 }
 
 
-- 
1.7.4.4



More information about the Glamor mailing list