[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