[Glamor] [PATCH 2/2] Add the feature of generating linear gradient picture using shader

He Junyan junyan.he at linux.intel.com
Mon Mar 5 00:46:18 PST 2012


Hi zhigang:
about the rel_tex_coord() function to modify the coords of texture,
I do not add here because it may need some modify and check.
I will research and add it next step.

Junyan

> From: Junyan He<junyan.he at linux.intel.com>
>
>   Add the feature of generating linear gradient picture by
>   using shader. This logic will replace the original
>   gradient picture generating manner in glamor which
>   firstly use pixman and then upload to GPU. Compare it
>   to the result generated by pixman, the difference of
>   each color of each pixel is normally 0, sometimes
>   1/255, and 2/255 at most. The pixman use fix int but
>   shader use float, so may have difference. There is just
>   one case that we will fallback. When the picture has
>   transform matrix and the matrix is a projective
>   matrix(which has non 0 at the third column and row.),
>   the shader's coordinate has been normalized and so it
>   is hard to work as what the pixman do. Some logic of
>   pixmap compare has been added to for easing the debug
>   of the pixmap generated by shader.
>
>
> Signed-off-by: Junyan He<junyan.he at linux.intel.com>
> ---
>   src/glamor.c             |    2 +
>   src/glamor_gl_dispatch.c |    4 +-
>   src/glamor_gl_dispatch.h |   15 +-
>   src/glamor_priv.h        |   13 +
>   src/glamor_render.c      |  547 ++++++++++++++++++++++++++++++++++++++++++++++
>   src/glamor_utils.h       |  277 +++++++++++++++++++++++
>   6 files changed, 851 insertions(+), 7 deletions(-)
>
> diff --git a/src/glamor.c b/src/glamor.c
> old mode 100644
> new mode 100755
> index 0d9ba28..532b9ef
> --- a/src/glamor.c
> +++ b/src/glamor.c
> @@ -389,6 +389,7 @@ glamor_init(ScreenPtr screen, unsigned int flags)
>   	glamor_init_tile_shader(screen);
>   	glamor_init_putimage_shaders(screen);
>   	glamor_init_finish_access_shaders(screen);
> +	glamor_init_gradient_shader(screen);
>   	glamor_pixmap_init(screen);
>
>   	glamor_priv->flags = flags;
> @@ -416,6 +417,7 @@ glamor_release_screen_priv(ScreenPtr screen)
>   	glamor_fini_tile_shader(screen);
>   	glamor_fini_putimage_shaders(screen);
>   	glamor_fini_finish_access_shaders(screen);
> +	glamor_fini_gradient_shader(screen);
>   	glamor_pixmap_fini(screen);
>   	free(glamor_priv);
>
> diff --git a/src/glamor_gl_dispatch.c b/src/glamor_gl_dispatch.c
> old mode 100644
> new mode 100755
> index ef0ac43..fc3c5c0
> --- a/src/glamor_gl_dispatch.c
> +++ b/src/glamor_gl_dispatch.c
> @@ -65,10 +65,12 @@ glamor_gl_dispatch_init_impl(struct glamor_gl_dispatch *dispatch,
>
>   	INIT_FUNC(dispatch, glUseProgram, get_proc_address);
>   	INIT_FUNC(dispatch, glUniform1i, get_proc_address);
> +	INIT_FUNC(dispatch, glUniform1f, get_proc_address);
>   	INIT_FUNC(dispatch, glUniform4f, get_proc_address);
> +	INIT_FUNC(dispatch, glUniform4fv, get_proc_address);
>   	INIT_FUNC(dispatch, glUniform1fv, get_proc_address);
>   	INIT_FUNC(dispatch, glUniform2fv, get_proc_address);
> -	INIT_FUNC(dispatch, glUniform4fv, get_proc_address);
> +	INIT_FUNC(dispatch, glUniformMatrix3fv, get_proc_address);
>   	INIT_FUNC(dispatch, glCreateProgram, get_proc_address);
>   	INIT_FUNC(dispatch, glDeleteProgram, get_proc_address);
>   	INIT_FUNC(dispatch, glCreateShader, get_proc_address);
> diff --git a/src/glamor_gl_dispatch.h b/src/glamor_gl_dispatch.h
> old mode 100644
> new mode 100755
> index bd33bcc..6adbde9
> --- a/src/glamor_gl_dispatch.h
> +++ b/src/glamor_gl_dispatch.h
> @@ -60,7 +60,7 @@ typedef struct glamor_gl_dispatch {
>   			      const GLvoid * data, GLenum usage);
>   	GLvoid *(*glMapBuffer) (GLenum target, GLenum access);
>   	GLvoid *(*glMapBufferRange) (GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access);
> -	GLboolean(*glUnmapBuffer) (GLenum target);
> +	GLboolean (*glUnmapBuffer) (GLenum target);
>   	void (*glBindBuffer) (GLenum target, GLuint buffer);
>   	void (*glDeleteBuffers) (GLsizei n, const GLuint * buffers);
>
> @@ -71,7 +71,7 @@ typedef struct glamor_gl_dispatch {
>   	void (*glDeleteFramebuffers) (GLsizei n,
>   				      const GLuint * framebuffers);
>   	void (*glGenFramebuffers) (GLsizei n, GLuint * framebuffers);
> -	 GLenum(*glCheckFramebufferStatus) (GLenum target);
> +	GLenum (*glCheckFramebufferStatus) (GLenum target);
>   	void (*glBlitFramebuffer) (GLint srcX0, GLint srcY0, GLint srcX1,
>   				   GLint srcY1, GLint dstX0, GLint dstY0,
>   				   GLint dstX1, GLint dstY1,
> @@ -92,6 +92,7 @@ typedef struct glamor_gl_dispatch {
>   				const GLint * length);
>   	void (*glUseProgram) (GLuint program);
>   	void (*glUniform1i) (GLint location, GLint v0);
> +	void (*glUniform1f) (GLint location, GLfloat v0);
>   	void (*glUniform4f) (GLint location, GLfloat v0, GLfloat v1,
>   			     GLfloat v2, GLfloat v3);
>   	void (*glUniform1fv) (GLint location, GLsizei count,
> @@ -100,9 +101,11 @@ typedef struct glamor_gl_dispatch {
>   			      const GLfloat * value);
>   	void (*glUniform4fv) (GLint location, GLsizei count,
>   			      const GLfloat * value);
> -	 GLuint(*glCreateProgram) (void);
> -	 GLuint(*glDeleteProgram) (GLuint);
> -	 GLuint(*glCreateShader) (GLenum type);
> +	void (*glUniformMatrix3fv) (GLint location, GLsizei count,
> +		           GLboolean transpose, const GLfloat* value);
> +	GLuint (*glCreateProgram) (void);
> +	GLuint (*glDeleteProgram) (GLuint);
> +	GLuint (*glCreateShader) (GLenum type);
>   	void (*glCompileShader) (GLuint shader);
>   	void (*glAttachShader) (GLuint program, GLuint shader);
>   	void (*glGetShaderiv) (GLuint shader, GLenum pname,
> @@ -113,7 +116,7 @@ typedef struct glamor_gl_dispatch {
>   				GLint * params);
>   	void (*glGetProgramInfoLog) (GLuint program, GLsizei bufSize,
>   				     GLsizei * length, GLchar * infoLog);
> -	 GLint(*glGetUniformLocation) (GLuint program,
> +	GLint (*glGetUniformLocation) (GLuint program,
>   				       const GLchar * name);
>
>   } glamor_gl_dispatch;
> diff --git a/src/glamor_priv.h b/src/glamor_priv.h
> index 1404703..ad68737 100755
> --- a/src/glamor_priv.h
> +++ b/src/glamor_priv.h
> @@ -123,6 +123,13 @@ enum shader_in {
>   	SHADER_IN_COUNT,
>   };
>
> +enum gradient_shader_type {
> +	GRADIENT_SHADER_LINEAR,
> +	GRADIENT_SHADER_RADIAL,
> +	GRADIENT_SHADER_CONICAL,
> +	GRADIENT_SHADER_COUNT,
> +};
> +
>   struct glamor_screen_private;
>   struct glamor_pixmap_private;
>   typedef void (*glamor_pixmap_validate_function_t) (struct
> @@ -221,6 +228,9 @@ typedef struct glamor_screen_private {
>   	GLint tile_prog;
>   	GLint tile_wh;
>
> +	/* glamor gradient */
> +	GLint gradient_prog[GRADIENT_SHADER_COUNT];
> +
>   	/* glamor_putimage */
>   	GLint put_image_xybitmap_prog;
>   	GLint put_image_xybitmap_fg_uniform_location;
> @@ -562,6 +572,9 @@ Bool glamor_tile(PixmapPtr pixmap, PixmapPtr tile,
>   void glamor_init_tile_shader(ScreenPtr screen);
>   void glamor_fini_tile_shader(ScreenPtr screen);
>
> +void glamor_init_gradient_shader(ScreenPtr screen);
> +void glamor_fini_gradient_shader(ScreenPtr screen);
> +
>   /* glamor_triangles.c */
>   void
>
> diff --git a/src/glamor_render.c b/src/glamor_render.c
> old mode 100644
> new mode 100755
> index 9f0b034..f3ed5f9
> --- a/src/glamor_render.c
> +++ b/src/glamor_render.c
> @@ -1275,6 +1275,543 @@ done:
>   	return ret;
>   }
>
> +static GLint
> +_glamor_create_linear_gradient_program(ScreenPtr screen, int stops_count)
> +{
> +	glamor_screen_private *glamor_priv;
> +	glamor_gl_dispatch *dispatch;
> +
> +	GLint gradient_prog = 0;
> +	char *gradient_fs = NULL;
> +	GLint fs_prog, vs_prog;
> +
> +	const char *gradient_vs =
> +	    GLAMOR_DEFAULT_PRECISION
> +	    "attribute vec4 v_position;\n"
> +	    "attribute vec4 v_texcoord;\n"
> +	    "varying vec2 source_texture;\n"
> +	    "\n"
> +	    "void main()\n"
> +	    "{\n"
> +	    "    gl_Position = v_position;\n"
> +	    "    source_texture = v_texcoord.xy;\n"
> +	    "}\n";
> +
> +	const char *gradient_fs_template =
> +	    GLAMOR_DEFAULT_PRECISION
> +	    "uniform mat3 transform_mat;\n"
> +	    "uniform int repeat_type;\n"
> +	    "uniform int hor_ver;\n"
> +	    "uniform int n_stop;\n"
> +	    "uniform float stops[%d];\n"
> +	    "uniform vec4 stop_colors[%d];\n"
> +	    "uniform vec4 pt1;\n"
> +	    "uniform vec4 pt2;\n"
> +	    "uniform float pt_slope;\n"
> +	    "varying vec2 source_texture;\n"
> +	    "\n"
> +	    "vec4 get_color()\n"
> +	    "{\n"
> +	    "    vec3 tmp = vec3(source_texture.x, source_texture.y, 1.0);\n"
> +	    "    float len_percentage;\n"
> +	    "    float distance;\n"
> +	    "    float p1_distance;\n"
> +	    "    float p2_distance;\n"
> +	    "    float y_dist;\n"
> +	    "    float slope = pt_slope; \n"
> +	    "    float new_alpha; \n"
> +	    "    float cos_val;\n"
> +	    "    int i = 0;\n"
> +	    "    int revserse = 0;\n"
> +	    "    vec4 gradient_color;\n"
> +	    "    vec3 source_texture_trans = transform_mat * tmp;\n"
> +	    "    \n"
> +	    "    if(hor_ver == 0) { \n" //Normal case.
> +	    "        cos_val = sqrt(1.0/(slope*slope + 1.0));\n"
> +	    "        y_dist = source_texture_trans.y - source_texture_trans.x*slope;\n"
> +	    "        distance = y_dist * cos_val;\n"
> +	    "        \n"
> +	    "        y_dist = pt1.y - pt1.x*slope;\n"
> +	    "        p1_distance = y_dist * cos_val * source_texture_trans.z;\n"
> +	    "        \n"
> +	    "        y_dist = pt2.y - pt2.x*slope;\n"
> +	    "        p2_distance = y_dist * cos_val * source_texture_trans.z;\n"
> +	    "        \n"
> +	    "    } else if (hor_ver == 1) {\n"//horizontal case.
> +	    "        distance = source_texture_trans.x;\n"
> +	    "        p1_distance = pt1.x * source_texture_trans.z;\n"
> +	    "        p2_distance = pt2.x * source_texture_trans.z;\n"
> +	    "    } else if (hor_ver == 2) {\n"//vertical case.
> +	    "        distance = source_texture_trans.y;\n"
> +	    "        p1_distance = pt1.y * source_texture_trans.z;\n"
> +	    "        p2_distance = pt2.y * source_texture_trans.z;\n"
> +	    "    } \n"
> +	    "    \n"
> +	    "    distance = distance - p1_distance; \n"
> +	    "    \n"
> +	    "    if(repeat_type == %d){\n" // repeat normal
> +	    "        while(distance>  p2_distance - p1_distance) \n"
> +	    "            distance = distance - (p2_distance - p1_distance); \n"
> +	    "        while(distance<  0.0) \n"
> +	    "            distance = distance + (p2_distance - p1_distance); \n"
> +	    "    }\n"
> +	    "    \n"
> +	    "    if(repeat_type == %d) {\n" // repeat reflect
> +	    "        while(distance>  p2_distance - p1_distance) {\n"
> +	    "            distance = distance - (p2_distance - p1_distance); \n"
> +	    "            if(revserse == 0)\n"
> +	    "                revserse = 1;\n"
> +	    "            else\n"
> +	    "                revserse = 0;\n"
> +	    "        }\n"
> +	    "        while(distance<  0.0) {\n"
> +	    "            distance = distance + (p2_distance - p1_distance); \n"
> +	    "            if(revserse == 0)\n"
> +	    "                revserse = 1;\n"
> +	    "            else\n"
> +	    "	             revserse = 0;\n"
> +	    "        }\n"
> +	    "        if(revserse == 1) {\n"
> +	    "            distance = (p2_distance - p1_distance) - distance; \n"
> +	    "        }\n"
> +	    "    }\n"
> +	    "    \n"
> +	    "    len_percentage = distance/(p2_distance - p1_distance);\n"
> +	    "    for(i = 0; i<  n_stop - 1; i++) {\n"
> +	    "        if(len_percentage<  stops[i])\n"
> +	    "            break; \n"
> +	    "    }\n"
> +	    "    \n"
> +	    "    float percentage = (len_percentage - stops[i-1])/(stops[i] - stops[i-1]);\n"
> +	    "    if(stops[i] - stops[i-1]>  2.0)\n"
> +	    "        percentage = 0.0;\n" //For comply with pixman, walker->stepper overflow.
> +	    "    new_alpha = percentage * stop_colors[i].a + \n"
> +	    "                       (1.0-percentage) * stop_colors[i-1].a; \n"
> +	    "    gradient_color = vec4((percentage * stop_colors[i].rgb \n"
> +	    "                          + (1.0-percentage) * stop_colors[i-1].rgb)*new_alpha, \n"
> +	    "                          new_alpha);\n"
> +	    "    \n"
> +	    "    return gradient_color;\n"
> +	    "}\n"
> +	    "\n"
> +	    "void main()\n"
> +	    "{\n"
> +	    "    gl_FragColor = get_color();\n"
> +	    "}\n";
> +
> +	glamor_priv = glamor_get_screen_private(screen);
> +	dispatch = glamor_get_dispatch(glamor_priv);
> +
> +	gradient_prog = dispatch->glCreateProgram();
> +
> +	vs_prog = glamor_compile_glsl_prog(dispatch,
> +	          GL_VERTEX_SHADER, gradient_vs);
> +
> +	XNFasprintf(&gradient_fs,
> +	            gradient_fs_template, stops_count, stops_count,
> +	            PIXMAN_REPEAT_NORMAL, PIXMAN_REPEAT_REFLECT);
> +
> +	fs_prog = glamor_compile_glsl_prog(dispatch,
> +	          GL_FRAGMENT_SHADER, gradient_fs);
> +
> +	free(gradient_fs);
> +
> +	dispatch->glAttachShader(gradient_prog, vs_prog);
> +	dispatch->glAttachShader(gradient_prog, fs_prog);
> +
> +	dispatch->glBindAttribLocation(gradient_prog, GLAMOR_VERTEX_POS, "v_position");
> +	dispatch->glBindAttribLocation(gradient_prog, GLAMOR_VERTEX_SOURCE, "v_texcoord");
> +
> +	glamor_link_glsl_prog(dispatch, gradient_prog);
> +
> +	dispatch->glUseProgram(0);
> +
> +	glamor_put_dispatch(glamor_priv);
> +	return gradient_prog;
> +}
> +
> +#define LINEAR_DEFAULT_STOPS 96 + 2
> +void
> +glamor_init_gradient_shader(ScreenPtr screen)
> +{
> +	glamor_screen_private *glamor_priv;
> +
> +	glamor_priv = glamor_get_screen_private(screen);
> +
> +	glamor_priv->gradient_prog[GRADIENT_SHADER_LINEAR] =
> +	    _glamor_create_linear_gradient_program(screen,
> +	            LINEAR_DEFAULT_STOPS);
> +}
> +
> +void
> +glamor_fini_gradient_shader(ScreenPtr screen)
> +{
> +	glamor_screen_private *glamor_priv;
> +	glamor_gl_dispatch *dispatch;
> +
> +	glamor_priv = glamor_get_screen_private(screen);
> +	dispatch = glamor_get_dispatch(glamor_priv);
> +
> +	dispatch->glDeleteProgram(
> +	    glamor_priv->gradient_prog[GRADIENT_SHADER_LINEAR]);
> +
> +	glamor_put_dispatch(glamor_priv);
> +}
> +
> +static PicturePtr
> +_glamor_generate_linear_gradient_picture(ScreenPtr screen,
> +        PicturePtr src_picture,
> +        int x_source, int y_source,
> +        int width, int height,
> +        PictFormatShort format)
> +{
> +	glamor_screen_private *glamor_priv;
> +	glamor_gl_dispatch *dispatch;
> +	PicturePtr dst_picure;
> +	PixmapPtr pixmap;
> +	glamor_pixmap_private *pixmap_priv;
> +	GLint gradient_prog = 0;
> +	int error;
> +	float pt_distance;
> +	float tex_vertices[8];
> +	int stops_count;
> +	GLint transform_mat_uniform_location;
> +	GLint pt1_uniform_location;
> +	GLint pt2_uniform_location;
> +	GLint n_stop_uniform_location;
> +	GLint stops_uniform_location;
> +	GLint stop_colors_uniform_location;
> +	GLint pt_slope_uniform_location;
> +	GLint repeat_type_uniform_location;
> +	GLint hor_ver_uniform_location;
> +	GLfloat *stop_colors = NULL;
> +	GLfloat *n_stops = NULL;
> +	int i = 0;
> +	int count = 0;
> +	float slope;
> +	GLfloat xscale, yscale;
> +	GLfloat pt1[4], pt2[4];
> +	float vertices[8];
> +	float transform_mat[3][3];
> +	static const float identity_mat[3][3] =
> +	                             {{1.0, 0.0, 0.0},
> +	                              {0.0, 1.0, 0.0},
> +	                              {0.0, 0.0, 1.0}};
> +	GLfloat stop_colors_st[LINEAR_DEFAULT_STOPS];
> +	GLfloat n_stops_st[LINEAR_DEFAULT_STOPS];
> +
> +	/* Create a pixmap with VBO. */
> +	pixmap = glamor_create_pixmap(screen,
> +	                              width, height,
> +	                              PIXMAN_FORMAT_DEPTH(format),
> +	                              GLAMOR_CREATE_PIXMAP_FIXUP);
> +
> +	if (!pixmap)
> +		goto GRADIENT_FAIL;
> +
> +	dst_picure = CreatePicture(0,&pixmap->drawable,
> +	                           PictureMatchFormat(screen,
> +	                                      PIXMAN_FORMAT_DEPTH(format), format),
> +	                           0, 0, serverClient,&error);
> +
> +	/* Release the reference, picture will hold the last one. */
> +	glamor_destroy_pixmap(pixmap);
> +
> +	if (!dst_picure)
> +		goto GRADIENT_FAIL;
> +
> +	ValidatePicture(dst_picure);
> +
> +	glamor_priv = glamor_get_screen_private(screen);
> +	dispatch =  glamor_get_dispatch(glamor_priv);
> +
> +	stops_count = src_picture->pSourcePict->linear.nstops + 2>  LINEAR_DEFAULT_STOPS ?
> +	              src_picture->pSourcePict->linear.nstops + 2 : LINEAR_DEFAULT_STOPS;
> +
> +	/* Because the max value of nstops is unkown, so create a program
> +	   when nstops>  default.*/
> +	if (src_picture->pSourcePict->linear.nstops<= LINEAR_DEFAULT_STOPS) {
> +		gradient_prog = glamor_priv->gradient_prog[GRADIENT_SHADER_LINEAR];
> +	} else {
> +		gradient_prog = _glamor_create_linear_gradient_program(screen,
> +		                src_picture->pSourcePict->linear.nstops);
> +	}
> +
> +	/* Bind all the uniform vars .*/
> +	pt1_uniform_location =
> +	    dispatch->glGetUniformLocation(gradient_prog, "pt1");
> +	pt2_uniform_location =
> +	    dispatch->glGetUniformLocation(gradient_prog, "pt2");
> +	n_stop_uniform_location =
> +	    dispatch->glGetUniformLocation(gradient_prog, "n_stop");
> +	stops_uniform_location =
> +	    dispatch->glGetUniformLocation(gradient_prog, "stops");
> +	stop_colors_uniform_location =
> +	    dispatch->glGetUniformLocation(gradient_prog, "stop_colors");
> +	pt_slope_uniform_location =
> +	    dispatch->glGetUniformLocation(gradient_prog, "pt_slope");
> +	repeat_type_uniform_location =
> +	    dispatch->glGetUniformLocation(gradient_prog, "repeat_type");
> +	hor_ver_uniform_location =
> +	    dispatch->glGetUniformLocation(gradient_prog, "hor_ver");
> +	transform_mat_uniform_location =
> +	    dispatch->glGetUniformLocation(gradient_prog, "transform_mat");
> +
> +	dispatch->glUseProgram(gradient_prog);
> +
> +	dispatch->glUniform1i(repeat_type_uniform_location, src_picture->repeatType);
> +
> +	if (src_picture->transform) {
> +		int r, c;
> +
> +		for (r = 0; r<  3; r++) {
> +			for (c = 0; c<  3; c++) {
> +				if ((r>= 2 || c>= 2)&&  r != c) {
> +					if (transform_mat[r][c]) {
> +						ErrorF("Project matrix change for"
> +						       "linear gradient, FallBack\n");
> +						goto GRADIENT_FAIL;
> +					}
> +				}
> +				transform_mat[r][c] = (float)pixman_fixed_to_double(
> +				            src_picture->transform->matrix[r][c]);
> +			}
> +		}
> +		
> +		dispatch->glUniformMatrix3fv(transform_mat_uniform_location,
> +		                               1, 1,&transform_mat[0][0]);
> +	} else {
> +		dispatch->glUniformMatrix3fv(transform_mat_uniform_location,
> +		                               1, 1,&identity_mat[0][0]);
> +	}
> +
> +	pixmap = glamor_get_drawable_pixmap(dst_picure->pDrawable);
> +	pixmap_priv = glamor_get_pixmap_private(pixmap);
> +
> +	if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv)) { /* should always have here. */
> +		goto GRADIENT_FAIL;
> +	}
> +
> +	glamor_set_destination_pixmap_priv_nc(pixmap_priv);
> +
> +	pixmap_priv_get_scale(pixmap_priv,&xscale,&yscale);
> +
> +	glamor_priv->has_source_coords = 1;
> +	glamor_priv->has_mask_coords = 0;
> +	glamor_setup_composite_vbo(screen, 4*2);
> +
> +	DEBUGF("xscale = %f, yscale = %f,"
> +	       " x_source = %d, y_source = %d, width = %d, height = %d\n",
> +	       xscale, yscale, x_source, y_source, width, height);
> +
> +	glamor_set_normalize_vcoords(xscale, yscale,
> +	        0, 0,
> +	        (INT16)(width), (INT16)(height),
> +	        glamor_priv->yInverted, vertices);
> +
> +	glamor_set_normalize_tcoords(xscale, yscale,
> +	        0, 0,
> +	        (INT16)(width), (INT16)(height),
> +	        glamor_priv->yInverted, tex_vertices);
> +
> +	DEBUGF("vertices -->  leftup : %f X %f, rightup: %f X %f,"
> +	       "rightbottom: %f X %f, leftbottom : %f X %f\n",
> +	       vertices[0], vertices[1], vertices[2], vertices[3],
> +	       vertices[4], vertices[5], vertices[6], vertices[7]);
> +	DEBUGF("tex_vertices -->  leftup : %f X %f, rightup: %f X %f,"
> +	       "rightbottom: %f X %f, leftbottom : %f X %f\n",
> +	       tex_vertices[0], tex_vertices[1], tex_vertices[2], tex_vertices[3],
> +	       tex_vertices[4], tex_vertices[5], tex_vertices[6], tex_vertices[7]);
> +
> +	/* Normalize the PTs. */
> +	glamor_set_normalize_pt(xscale, yscale,
> +	                        pixman_fixed_to_int(src_picture->pSourcePict->linear.p1.x),
> +	                        x_source,
> +	                        pixman_fixed_to_int(src_picture->pSourcePict->linear.p1.y),
> +	                        y_source,
> +	                        glamor_priv->yInverted,
> +	                        pt1);
> +	dispatch->glUniform4fv(pt1_uniform_location, 1, pt1);
> +	DEBUGF("pt1:(%f %f)\n", pt1[0], pt1[1]);
> +
> +	glamor_set_normalize_pt(xscale, yscale,
> +	                        pixman_fixed_to_int(src_picture->pSourcePict->linear.p2.x),
> +	                        x_source,
> +	                        pixman_fixed_to_int(src_picture->pSourcePict->linear.p2.y),
> +	                        y_source,
> +	                        glamor_priv->yInverted,
> +	                        pt2);
> +	dispatch->glUniform4fv(pt2_uniform_location, 1, pt2);
> +	DEBUGF("pt2:(%f %f)\n", pt2[0], pt2[1]);
> +
> +	pt_distance = sqrt((pt2[1] - pt1[1]) * (pt2[1] - pt1[1]) +
> +	                   (pt2[0] - pt1[0]) * (pt2[0] - pt1[0]));
> +
> +	/* Set all the stops and colors to shader. */
> +	if(stops_count>  LINEAR_DEFAULT_STOPS) {
> +		stop_colors = malloc(4 * stops_count * sizeof(float));
> +		if (stop_colors == NULL) {
> +			ErrorF("Failed to allocate stop_colors memory.\n");
> +			exit(1);
> +		}
> +
> +		n_stops = malloc(stops_count * sizeof(float));
> +		if (n_stops == NULL) {
> +			ErrorF("Failed to allocate n_stops memory.\n");
> +			exit(1);
> +		}
> +	} else {
> +		stop_colors = stop_colors_st;
> +		n_stops = n_stops_st;
> +	}
> +
> +	for (i = 1; i<  src_picture->pSourcePict->linear.nstops + 1; i++) {
> +		stop_colors[i*4] = pixman_fixed_to_double(
> +		            src_picture->pSourcePict->linear.stops[i-1].color.red);
> +		stop_colors[i*4+1] = pixman_fixed_to_double(
> +		            src_picture->pSourcePict->linear.stops[i-1].color.green);
> +		stop_colors[i*4+2] = pixman_fixed_to_double(
> +		            src_picture->pSourcePict->linear.stops[i-1].color.blue);
> +		stop_colors[i*4+3] = pixman_fixed_to_double(
> +		            src_picture->pSourcePict->linear.stops[i-1].color.alpha);
> +
> +		n_stops[i] = (GLfloat)pixman_fixed_to_double(
> +		            src_picture->pSourcePict->linear.stops[i-1].x);
> +	}
> +
> +	count = src_picture->pSourcePict->linear.nstops + 2;
> +
> +	switch (src_picture->repeatType) {
> +#define REPEAT_FILL_STOPS(m, n) \
> +		stop_colors[(m)*4 + 0] = stop_colors[(n)*4 + 0]; \
> +		stop_colors[(m)*4 + 1] = stop_colors[(n)*4 + 1]; \
> +		stop_colors[(m)*4 + 2] = stop_colors[(n)*4 + 2]; \
> +		stop_colors[(m)*4 + 3] = stop_colors[(n)*4 + 3];
> +
> +		default:
> +		case PIXMAN_REPEAT_NONE:
> +			stop_colors[0] = 0.0;      //R
> +			stop_colors[1] = 0.0;      //G
> +			stop_colors[2] = 0.0;      //B
> +			stop_colors[3] = 0.0;      //Alpha
> +			n_stops[0] = -(float)INT_MAX;  //should be small enough.
> +
> +			stop_colors[0 + (count-1)*4] = 0.0;      //R
> +			stop_colors[1 + (count-1)*4] = 0.0;      //G
> +			stop_colors[2 + (count-1)*4] = 0.0;      //B
> +			stop_colors[3 + (count-1)*4] = 0.0;      //Alpha
> +			n_stops[count-1] = (float)INT_MAX;  //should be large enough.
> +			break;
> +		case PIXMAN_REPEAT_NORMAL:
> +			REPEAT_FILL_STOPS(0, count - 2);
> +			n_stops[0] = n_stops[count-2] - 1.0;
> +
> +			REPEAT_FILL_STOPS(count - 1, 1);
> +			n_stops[count-1] = n_stops[1] + 1.0;
> +			break;
> +		case PIXMAN_REPEAT_REFLECT:
> +			REPEAT_FILL_STOPS(0, 1);
> +			n_stops[0] = -n_stops[1];
> +
> +			REPEAT_FILL_STOPS(count - 1, count - 2);
> +			n_stops[count-1] = 1.0 + 1.0 - n_stops[count-2];
> +			break;
> +		case PIXMAN_REPEAT_PAD:
> +			REPEAT_FILL_STOPS(0, 1);
> +			n_stops[0] = -(float)INT_MAX;
> +
> +			REPEAT_FILL_STOPS(count - 1, count - 2);
> +			n_stops[count-1] = (float)INT_MAX;
> +			break;
> +#undef REPEAT_FILL_STOPS
> +	}
> +
> +	for (i = 0; i<  count; i++) {
> +		DEBUGF("n_stops[%d] = %f, color = r:%f g:%f b:%f a:%f\n",
> +		        i, n_stops[i],
> +		        stop_colors[i*4], stop_colors[i*4+1],
> +		        stop_colors[i*4+2], stop_colors[i*4+3]);
> +	}
> +
> +	dispatch->glUniform4fv(stop_colors_uniform_location, count, stop_colors);
> +	dispatch->glUniform1fv(stops_uniform_location, count, n_stops);
> +	dispatch->glUniform1i(n_stop_uniform_location, count);
> +
> +	if ((pt2[1] - pt1[1]) / yscale<  1.0) { // The horizontal case.
> +		dispatch->glUniform1i(hor_ver_uniform_location, 1);
> +		DEBUGF("p1.x: %f, p2.x: %f, enter the horizontal case\n",
> +		       pt1[1], pt2[1]);
> +	} else if ((pt2[0] - pt1[0]) / xscale<  1.0) { //The vertical case.
> +		dispatch->glUniform1i(hor_ver_uniform_location, 2);
> +		DEBUGF("p1.y: %f, p2.y: %f, enter the vertical case\n",
> +		       pt1[0], pt2[0]);
> +	} else {
> +		/* The slope need to compute here. In shader, the viewport set will change
> +		   the orginal slope and the slope which is vertical to it will not be correct.*/
> +		slope = - (float)(src_picture->pSourcePict->linear.p2.x - src_picture->pSourcePict->linear.p1.x) /
> +		        (float)(src_picture->pSourcePict->linear.p2.y - src_picture->pSourcePict->linear.p1.y);
> +		slope = slope * yscale / xscale;
> +		dispatch->glUniform1f(pt_slope_uniform_location, slope);
> +		dispatch->glUniform1i(hor_ver_uniform_location, 0);
> +	}
> +
> +	/* set the transform matrix. */	/* Now rendering. */
> +	glamor_emit_composite_rect(screen, tex_vertices, NULL, vertices);
> +
> +	if (glamor_priv->render_nr_verts) {
> +		if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP)
> +			dispatch->glUnmapBuffer(GL_ARRAY_BUFFER);
> +		else {
> +
> +			dispatch->glBindBuffer(GL_ARRAY_BUFFER, glamor_priv->vbo);
> +			dispatch->glBufferData(GL_ARRAY_BUFFER,
> +			        glamor_priv->vbo_offset,
> +			        glamor_priv->vb, GL_DYNAMIC_DRAW);
> +		}
> +
> +		dispatch->glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, NULL);
> +	}
> +
> +	/* Do the clear logic.*/
> +	if(stops_count>  LINEAR_DEFAULT_STOPS) {
> +		free(n_stops);
> +		free(stop_colors);
> +	}
> +	
> +	dispatch->glBindBuffer(GL_ARRAY_BUFFER, 0);
> +	dispatch->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
> +
> +	dispatch->glDisableVertexAttribArray(GLAMOR_VERTEX_POS);
> +	dispatch->glDisableVertexAttribArray(GLAMOR_VERTEX_SOURCE);
> +	dispatch->glUseProgram(0);
> +
> +	if (src_picture->pSourcePict->linear.nstops>  LINEAR_DEFAULT_STOPS)
> +		dispatch->glDeleteProgram(gradient_prog);
> +
> +	glamor_put_dispatch(glamor_priv);
> +	return dst_picure;
> +
> +GRADIENT_FAIL:
> +	if(stops_count>  LINEAR_DEFAULT_STOPS) {
> +		if(n_stops)
> +			free(n_stops);
> +		if(stop_colors)
> +			free(stop_colors);
> +	}
> +	
> +	dispatch->glBindBuffer(GL_ARRAY_BUFFER, 0);
> +	dispatch->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
> +
> +	dispatch->glDisableVertexAttribArray(GLAMOR_VERTEX_POS);
> +	dispatch->glDisableVertexAttribArray(GLAMOR_VERTEX_SOURCE);
> +	dispatch->glUseProgram(0);
> +	if (src_picture->pSourcePict->linear.nstops>  LINEAR_DEFAULT_STOPS)
> +		dispatch->glDeleteProgram(gradient_prog);
> +	glamor_put_dispatch(glamor_priv);
> +	return NULL;
> +}
> +#undef LINEAR_DEFAULT_STOPS
> +
>   static PicturePtr
>   glamor_convert_gradient_picture(ScreenPtr screen,
>   				PicturePtr source,
> @@ -1290,6 +1827,16 @@ glamor_convert_gradient_picture(ScreenPtr screen,
>   	else
>   		format = source->format;
>
> +	if (source->pSourcePict->type == SourcePictTypeLinear) {
> +		dst = _glamor_generate_linear_gradient_picture(screen,
> +		        source, x_source, y_source, width, height, format);
> +
> +		glamor_compare_pictures(screen, source,
> +		         dst, x_source, y_source, width, height,
> +		         0, 3);
> +                return dst;
> +	}
> +
>   	pixmap = glamor_create_pixmap(screen,
>   				      width,
>   				      height,
> diff --git a/src/glamor_utils.h b/src/glamor_utils.h
> old mode 100644
> new mode 100755
> index 4a51ba5..b43dc27
> --- a/src/glamor_utils.h
> +++ b/src/glamor_utils.h
> @@ -119,6 +119,17 @@
>       (vertices)[7] = (vertices)[5];					\
>     } while(0)
>
> +#define glamor_set_normalize_pt(xscale, yscale, x, x_start, y, y_start,     \
> +                                yInverted, pt)                              \
> +    do {                                                                    \
> +        (pt)[0] = t_from_x_coord_x(xscale, x - x_start);                    \
> +        if (yInverted) {                                                    \
> +            (pt)[1] = t_from_x_coord_y_inverted(yscale, y - y_start);       \
> +        } else {                                                            \
> +            (pt)[1] = t_from_x_coord_y(yscale, y - y_start);                \
> +        }                                                                   \
> +        (pt)[3] = (pt)[4] = 0.0;                                            \
> +    } while(0)
>
>   inline static void
>   glamor_calculate_boxes_bound(BoxPtr bound, BoxPtr boxes, int nbox)
> @@ -664,6 +675,272 @@ static inline void glamor_dump_pixmap(PixmapPtr pixmap, int x, int y, int w, int
>   	glamor_finish_access(&pixmap->drawable, GLAMOR_ACCESS_RO);
>   }
>
> +static inline void _glamor_compare_pixmaps(PixmapPtr pixmap1, PixmapPtr pixmap2,
> +                                           int x, int y, int w, int h,
> +                                           PictFormatShort short_format,
> +                                           int all, int diffs)
> +{
> +	int i, j;
> +	unsigned char * p1 = pixmap1->devPrivate.ptr;
> +	unsigned char * p2 = pixmap2->devPrivate.ptr;
> +	int line_need_printed = 0;
> +	int test_code = 0xAABBCCDD;
> +	int little_endian = 0;
> +	unsigned char *p_test;
> +	int bpp = pixmap1->drawable.depth == 8? 1 : 4;
> +
> +	assert(pixmap1->devKind == pixmap2->devKind);
> +	int stride = pixmap1->devKind;
> +
> +	ErrorF("stride:%d, width:%d, height:%d\n", stride, w, h);
> +
> +	p1 = p1 + y * stride + x;
> +	p2 = p2 + y * stride + x;
> +
> +	if(all) {
> +		for (i = 0; i<  h; i++) {
> +			ErrorF("line %3d: ", i);
> +
> +			for (j = 0; j<  stride; j++) {
> +				if(j % bpp == 0)
> +					ErrorF("[%d]%2x:%2x ", j/bpp, p1[j], p2[j]);
> +				else
> +					ErrorF("%2x:%2x ", p1[j], p2[j]);
> +			}
> +
> +			p1 += stride;
> +			p2 += stride;
> +			ErrorF("\n");
> +		}
> +	} else {
> +		if (short_format == PICT_a8r8g8b8) {
> +			p_test = (unsigned char *)&test_code;
> +			little_endian = (*p_test == 0xDD);
> +			bpp = 4;
> +
> +			for (i = 0; i<  h; i++) {
> +				line_need_printed = 0;
> +
> +				for (j = 0; j<  stride; j++) {
> +					if (p1[j] != p2[j]&&  (p1[j] - p2[j]>  diffs || p2[j] - p1[j]>  diffs)) {
> +						if (line_need_printed) {
> +							if(little_endian) {
> +								switch (j % 4) {
> +									case 2:
> +									ErrorF("[%d]RED:%2x:%2x ", j/bpp, p1[j], p2[j]);
> +									break;
> +									case 1:
> +									ErrorF("[%d]GREEN:%2x:%2x ", j/bpp, p1[j], p2[j]);
> +									break;
> +									case 0:
> +									ErrorF("[%d]BLUE:%2x:%2x ", j/bpp, p1[j], p2[j]);
> +									break;
> +									case 3:
> +									ErrorF("[%d]Alpha:%2x:%2x ", j/bpp, p1[j], p2[j]);
> +									break;
> +								}
> +							}else {
> +								switch (j % 4) {
> +									case 1:
> +									ErrorF("[%d]RED:%2x:%2x ", j/bpp, p1[j], p2[j]);
> +									break;
> +									case 2:
> +									ErrorF("[%d]GREEN:%2x:%2x ", j/bpp, p1[j], p2[j]);
> +									break;
> +									case 3:
> +									ErrorF("[%d]BLUE:%2x:%2x ", j/bpp, p1[j], p2[j]);
> +									break;
> +									case 0:
> +									ErrorF("[%d]Alpha:%2x:%2x ", j/bpp, p1[j], p2[j]);
> +									break;
> +								}
> +							}
> +						} else {
> +							line_need_printed = 1;
> +							j = -1;
> +							ErrorF("line %3d: ", i);
> +							continue;
> +						}
> +					}
> +				}
> +
> +				p1 += stride;
> +				p2 += stride;
> +				ErrorF("\n");
> +			}
> +		} //more format can be added here.
> +		else { // the default format, just print.
> +			for (i = 0; i<  h; i++) {
> +				line_need_printed = 0;
> +
> +				for (j = 0; j<  stride; j++) {
> +					if (p1[j] != p2[j]) {
> +						if (line_need_printed) {
> +							ErrorF("[%d]%2x:%2x ", j/bpp, p1[j], p2[j]);
> +						} else {
> +							line_need_printed = 1;
> +							j = -1;
> +							ErrorF("line %3d: ", i);
> +							continue;
> +						}
> +					}
> +				}
> +
> +				p1 += stride;
> +				p2 += stride;
> +				ErrorF("\n");
> +			}
> +		}
> +	}
> +}
> +
> +static inline void glamor_compare_pixmaps(PixmapPtr pixmap1, PixmapPtr pixmap2,
> +                                          int x, int y, int w, int h, int all, int diffs)
> +{
> +	assert(pixmap1->drawable.depth == pixmap2->drawable.depth);
> +
> +	glamor_prepare_access(&pixmap1->drawable, GLAMOR_ACCESS_RO);
> +	glamor_prepare_access(&pixmap2->drawable, GLAMOR_ACCESS_RO);
> +
> +	_glamor_compare_pixmaps(pixmap1, pixmap2, x, y, w, h, -1, all, diffs);
> +
> +	glamor_finish_access(&pixmap1->drawable, GLAMOR_ACCESS_RO);
> +	glamor_finish_access(&pixmap2->drawable, GLAMOR_ACCESS_RO);
> +}
> +
> +/* This function is used to compare two pictures.
> +   If the picture has no drawable, we use fb functions to generate it. */
> +static inline void glamor_compare_pictures( ScreenPtr screen,
> +                                            PicturePtr fst_picture,
> +                                            PicturePtr snd_picture,
> +                                            int x_source, int y_source,
> +                                            int width, int height,
> +                                            int all, int diffs)
> +{
> +	PixmapPtr fst_pixmap;
> +	PixmapPtr snd_pixmap;
> +	int fst_generated, snd_generated;
> +	glamor_pixmap_private *fst_pixmap_priv;
> +	glamor_pixmap_private *snd_pixmap_priv;
> +	int error;
> +	int fst_type = -1;
> +	int snd_type = -1; // -1 represent has drawable.
> +
> +	if (fst_picture->format != snd_picture->format) {
> +		ErrorF("Different picture format can not compare!\n");
> +		return;
> +	}
> +
> +	if (!fst_picture->pDrawable) {
> +		fst_type = fst_picture->pSourcePict->type;
> +	}
> +
> +	if (!snd_picture->pDrawable) {
> +		snd_type = snd_picture->pSourcePict->type;
> +	}
> +
> +	if((fst_type != -1)&&  (snd_type != -1)&&  (fst_type != snd_type)) {
> +		ErrorF("Different picture type will never be same!\n");
> +		return;
> +	}
> +
> +	fst_generated = snd_generated = 0;
> +
> +	if (!fst_picture->pDrawable) {
> +		PicturePtr pixman_pic;
> +		PixmapPtr pixmap = NULL;
> +		PictFormatShort format;
> +
> +		format = fst_picture->format;
> +
> +		pixmap = glamor_create_pixmap(screen,
> +                                      width, height,
> +                                      PIXMAN_FORMAT_DEPTH(format),
> +                                      GLAMOR_CREATE_PIXMAP_CPU);
> +
> +		pixman_pic = CreatePicture(0,
> +&pixmap->drawable,
> +                                   PictureMatchFormat(screen,
> +                                             PIXMAN_FORMAT_DEPTH(format), format),
> +                                   0, 0, serverClient,&error);
> +
> +		fbComposite(PictOpSrc, fst_picture, NULL, pixman_pic, x_source, y_source,
> +		        0, 0, 0, 0, width, height);
> +
> +		glamor_destroy_pixmap(pixmap);
> +
> +		fst_picture = pixman_pic;
> +		fst_generated = 1;
> +	}
> +
> +	if (!snd_picture->pDrawable) {
> +		PicturePtr pixman_pic;
> +		PixmapPtr pixmap = NULL;
> +		PictFormatShort format;
> +
> +		format = snd_picture->format;
> +
> +		pixmap = glamor_create_pixmap(screen,
> +                                      width, height,
> +                                      PIXMAN_FORMAT_DEPTH(format),
> +                                      GLAMOR_CREATE_PIXMAP_CPU);
> +
> +		pixman_pic = CreatePicture(0,
> +&pixmap->drawable,
> +                                   PictureMatchFormat(screen,
> +                                             PIXMAN_FORMAT_DEPTH(format), format),
> +                                   0, 0, serverClient,&error);
> +
> +		fbComposite(PictOpSrc, snd_picture, NULL, pixman_pic, x_source, y_source,
> +		        0, 0, 0, 0, width, height);
> +
> +		glamor_destroy_pixmap(pixmap);
> +
> +		snd_picture = pixman_pic;
> +		snd_generated = 1;
> +	}
> +
> +	fst_pixmap = glamor_get_drawable_pixmap(fst_picture->pDrawable);
> +	snd_pixmap = glamor_get_drawable_pixmap(snd_picture->pDrawable);
> +
> +	if (fst_pixmap->drawable.depth != snd_pixmap->drawable.depth) {
> +		if(fst_generated)
> +			glamor_destroy_picture(fst_picture);
> +		if(snd_generated)
> +			glamor_destroy_picture(snd_picture);
> +
> +		ErrorF("Different pixmap depth can not compare!\n");
> +		return;
> +	}
> +
> +	glamor_prepare_access(&fst_pixmap->drawable, GLAMOR_ACCESS_RO);
> +	glamor_prepare_access(&snd_pixmap->drawable, GLAMOR_ACCESS_RO);
> +
> +	if((fst_type == SourcePictTypeLinear) ||
> +		    (fst_type == SourcePictTypeRadial) ||
> +		    (fst_type == SourcePictTypeConical) ||
> +		    (snd_type == SourcePictTypeLinear) ||
> +		    (snd_type == SourcePictTypeRadial) ||
> +		    (snd_type == SourcePictTypeConical)) {
> +		x_source = y_source = 0;
> +	}
> +
> +	_glamor_compare_pixmaps(fst_pixmap, snd_pixmap,
> +                            x_source, y_source,
> +                            width, height,
> +                            fst_picture->format, all, diffs);
> +
> +	glamor_finish_access(&fst_pixmap->drawable, GLAMOR_ACCESS_RO);
> +	glamor_finish_access(&snd_pixmap->drawable, GLAMOR_ACCESS_RO);
> +
> +	if(fst_generated)
> +		glamor_destroy_picture(fst_picture);
> +	if(snd_generated)
> +		glamor_destroy_picture(snd_picture);
> +
> +	return;
> +}
> +
>   static inline void glamor_make_current(ScreenPtr screen)
>   {
>   	glamor_egl_make_current(screen);


More information about the Glamor mailing list