diff --git a/glamor/glamor_render.c b/glamor/glamor_render.c index 6304167ea..042fabe2d 100644 --- a/glamor/glamor_render.c +++ b/glamor/glamor_render.c @@ -1275,6 +1275,345 @@ done: return ret; } +static GLint +_glamor_create_getcolor_fs_program(ScreenPtr screen, int stops_count, int use_array) +{ + glamor_screen_private *glamor_priv; + glamor_gl_dispatch *dispatch; + + char *gradient_fs = NULL; + GLint gradient_prog = 0; + GLint fs_getcolor_prog; + + const char *gradient_fs_getcolor = + GLAMOR_DEFAULT_PRECISION + "uniform int n_stop;\n" + "uniform float stops[%d];\n" + "uniform vec4 stop_colors[%d];\n" + "vec4 get_color(float stop_len)\n" + "{\n" + " int i = 0;\n" + " float new_alpha; \n" + " vec4 gradient_color;\n" + " float percentage; \n" + " for(i = 0; i < n_stop - 1; i++) {\n" + " if(stop_len < stops[i])\n" + " break; \n" + " }\n" + " \n" + " percentage = (stop_len - 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"; + + /* Because the array access for shader is very slow, the performance is very low + if use array. So use global uniform to replace for it if the number of n_stops is small.*/ + const char *gradient_fs_getcolor_no_array = + GLAMOR_DEFAULT_PRECISION + "uniform int n_stop;\n" + "uniform float stop0;\n" + "uniform float stop1;\n" + "uniform float stop2;\n" + "uniform float stop3;\n" + "uniform float stop4;\n" + "uniform float stop5;\n" + "uniform float stop6;\n" + "uniform float stop7;\n" + "uniform vec4 stop_color0;\n" + "uniform vec4 stop_color1;\n" + "uniform vec4 stop_color2;\n" + "uniform vec4 stop_color3;\n" + "uniform vec4 stop_color4;\n" + "uniform vec4 stop_color5;\n" + "uniform vec4 stop_color6;\n" + "uniform vec4 stop_color7;\n" + "\n" + "vec4 get_color(float stop_len)\n" + "{\n" + " float stop_after;\n" + " float stop_before;\n" + " vec4 stop_color_before;\n" + " vec4 stop_color_after;\n" + " float new_alpha; \n" + " vec4 gradient_color;\n" + " float percentage; \n" + " \n" + " if((stop_len < stop0) && (n_stop >= 1)) {\n" + " stop_color_before = stop_color0;\n" + " stop_color_after = stop_color0;\n" + " stop_after = stop0;\n" + " stop_before = stop0;\n" + " percentage = 0.0;\n" + " } else if((stop_len < stop1) && (n_stop >= 2)) {\n" + " stop_color_before = stop_color0;\n" + " stop_color_after = stop_color1;\n" + " stop_after = stop1;\n" + " stop_before = stop0;\n" + " percentage = (stop_len - stop0)/(stop1 - stop0);\n" + " } else if((stop_len < stop2) && (n_stop >= 3)) {\n" + " stop_color_before = stop_color1;\n" + " stop_color_after = stop_color2;\n" + " stop_after = stop2;\n" + " stop_before = stop1;\n" + " percentage = (stop_len - stop1)/(stop2 - stop1);\n" + " } else if((stop_len < stop3) && (n_stop >= 4)){\n" + " stop_color_before = stop_color2;\n" + " stop_color_after = stop_color3;\n" + " stop_after = stop3;\n" + " stop_before = stop2;\n" + " percentage = (stop_len - stop2)/(stop3 - stop2);\n" + " } else if((stop_len < stop4) && (n_stop >= 5)){\n" + " stop_color_before = stop_color3;\n" + " stop_color_after = stop_color4;\n" + " stop_after = stop4;\n" + " stop_before = stop3;\n" + " percentage = (stop_len - stop3)/(stop4 - stop3);\n" + " } else if((stop_len < stop5) && (n_stop >= 6)){\n" + " stop_color_before = stop_color4;\n" + " stop_color_after = stop_color5;\n" + " stop_after = stop5;\n" + " stop_before = stop4;\n" + " percentage = (stop_len - stop4)/(stop5 - stop4);\n" + " } else if((stop_len < stop6) && (n_stop >= 7)){\n" + " stop_color_before = stop_color5;\n" + " stop_color_after = stop_color6;\n" + " stop_after = stop6;\n" + " stop_before = stop5;\n" + " percentage = (stop_len - stop5)/(stop6 - stop5);\n" + " } else if((stop_len < stop7) && (n_stop >= 8)){\n" + " stop_color_before = stop_color6;\n" + " stop_color_after = stop_color7;\n" + " stop_after = stop7;\n" + " stop_before = stop6;\n" + " percentage = (stop_len - stop6)/(stop7 - stop6);\n" + " } else {\n" + " stop_color_before = stop_color7;\n" + " stop_color_after = stop_color7;\n" + " stop_after = stop7;\n" + " stop_before = stop7;\n" + " percentage = 0.0;\n" + " }\n" + " if(stop_after - stop_before > 2.0)\n" + " percentage = 0.0;\n"//For comply with pixman, walker->stepper overflow. + " new_alpha = percentage * stop_color_after.a + \n" + " (1.0-percentage) * stop_color_before.a; \n" + " gradient_color = vec4((percentage * stop_color_after.rgb \n" + " + (1.0-percentage) * stop_color_before.rgb)*new_alpha, \n" + " new_alpha);\n" + " \n" + " return gradient_color;\n" + "}\n"; + + glamor_priv = glamor_get_screen_private(screen); + dispatch = glamor_get_dispatch(glamor_priv); + + if(use_array) { + XNFasprintf(&gradient_fs, + gradient_fs_getcolor, stops_count, stops_count); + fs_getcolor_prog = glamor_compile_glsl_prog(dispatch, GL_FRAGMENT_SHADER, + gradient_fs); + free(gradient_fs); + } else { + fs_getcolor_prog = glamor_compile_glsl_prog(dispatch, GL_FRAGMENT_SHADER, + gradient_fs_getcolor_no_array); + } + + return fs_getcolor_prog; +} + +static GLint +_glamor_create_radial_gradient_program(ScreenPtr screen, int stops_count, int use_array) +{ + glamor_screen_private *glamor_priv; + glamor_gl_dispatch *dispatch; + + GLint gradient_prog = 0; + char *gradient_fs = NULL; + GLint fs_main_prog, fs_getcolor_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"; + + /* + * Refer to pixman radial gradient. + * + * The problem is given the two circles of c1 and c2 with the radius of r1 and + * r1, we need to caculate the t, which is used to do interpolate with stops, + * using the fomula: + * length((1-t)*c1 + t*c2 - p) = (1-t)*r1 + t*r2 + * expand the fomula with xy coond, get the following: + * sqrt(sqr((1-t)*c1.x + t*c2.x - p.x) + sqr((1-t)*c1.y + t*c2.y - p.y)) + * = (1-t)r1 + t*r2 + * <====> At*t- 2Bt + C = 0 + * where A = sqr(c2.x - c1.x) + sqr(c2.y - c1.y) - sqr(r2 -r1) + * B = (p.x - c1.x)*(c2.x - c1.x) + (p.y - c1.y)*(c2.y - c1.y) + r1*(r2 -r1) + * C = sqr(p.x - c1.x) + sqr(p.y - c1.y) - r1*r1 + * + * solve the fomula and we get the result of + * t = (B + sqrt(B*B - A*C)) / A or + * t = (B - sqrt(B*B - A*C)) / A (quadratic equation have two solutions) + * + * The solution we are going to prefer is the bigger one, unless the + * radius associated to it is negative (or it falls outside the valid t range) + */ + + const char *gradient_fs_template = + GLAMOR_DEFAULT_PRECISION + "uniform mat3 transform_mat;\n" + "uniform int repeat_type;\n" + "uniform float A_value;\n" + "uniform vec2 c1;\n" + "uniform float r1;\n" + "uniform vec2 c2;\n" + "uniform float r2;\n" + "varying vec2 source_texture;\n" + "\n" + "vec4 get_color(float stop_len);\n" + "\n" + "int t_invalid;\n" + "\n" + "float get_stop_len()\n" + "{\n" + " float t = 0.0;\n" + " float sqrt_value;\n" + " int revserse = 0;\n" + " t_invalid = 0;\n" + " \n" + " vec3 tmp = vec3(source_texture.x, source_texture.y, 1.0);\n" + " vec3 source_texture_trans = transform_mat * tmp;\n" + " source_texture_trans.xy = source_texture_trans.xy/source_texture_trans.z;\n" + " float B_value = (source_texture_trans.x - c1.x) * (c2.x - c1.x)\n" + " + (source_texture_trans.y - c1.y) * (c2.y - c1.y)\n" + " + r1 * (r2 - r1);\n" + " float C_value = (source_texture_trans.x - c1.x) * (source_texture_trans.x - c1.x)\n" + " + (source_texture_trans.y - c1.y) * (source_texture_trans.y - c1.y)\n" + " - r1*r1;\n" + " if(abs(A_value) < 0.00001) {\n" + " if(B_value == 0.0) {\n" + " t_invalid = 1;\n" + " return t;\n" + " }\n" + " t = 0.5 * C_value / B_value;" + " } else {\n" + " sqrt_value = B_value * B_value - A_value * C_value;\n" + " if(sqrt_value < 0.0) {\n" + " t_invalid = 1;\n" + " return t;\n" + " }\n" + " sqrt_value = sqrt(sqrt_value);\n" + " t = (B_value + sqrt_value) / A_value;\n" + " }\n" + " if(repeat_type == %d) {\n" // RepeatNone case. + " if((t <= 0.0) || (t > 1.0))\n" + // try another if first one invalid + " t = (B_value - sqrt_value) / A_value;\n" + " \n" + " if((t <= 0.0) || (t > 1.0)) {\n" //still invalid, return. + " t_invalid = 1;\n" + " return t;\n" + " }\n" + " } else {\n" + " if(t * (r2 - r1) <= -1.0 * r1)\n" + // try another if first one invalid + " t = (B_value - sqrt_value) / A_value;\n" + " \n" + " if(t * (r2 -r1) <= -1.0 * r1) {\n" //still invalid, return. + " t_invalid = 1;\n" + " return t;\n" + " }\n" + " }\n" + " \n" + " if(repeat_type == %d){\n" // repeat normal + " while(t > 1.0) \n" + " t = t - 1.0; \n" + " while(t < 0.0) \n" + " t = t + 1.0; \n" + " }\n" + " \n" + " if(repeat_type == %d) {\n" // repeat reflect + " while(t > 1.0) {\n" + " t = t - 1.0; \n" + " if(revserse == 0)\n" + " revserse = 1;\n" + " else\n" + " revserse = 0;\n" + " }\n" + " while(t < 0.0) {\n" + " t = t + 1.0; \n" + " if(revserse == 0)\n" + " revserse = 1;\n" + " else\n" + " revserse = 0;\n" + " }\n" + " if(revserse == 1) {\n" + " t = 1.0 - t; \n" + " }\n" + " }\n" + " \n" + " return t;\n" + "}\n" + "\n" + "void main()\n" + "{\n" + " float stop_len = get_stop_len();\n" + " if(t_invalid == 1) {\n" + " gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0);\n" + " } else {\n" + " gl_FragColor = get_color(stop_len);\n" + " }\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, + PIXMAN_REPEAT_NONE, PIXMAN_REPEAT_NORMAL, PIXMAN_REPEAT_REFLECT); + + fs_main_prog = glamor_compile_glsl_prog(dispatch, + GL_FRAGMENT_SHADER, gradient_fs); + + free(gradient_fs); + + fs_getcolor_prog = _glamor_create_getcolor_fs_program(screen, + stops_count, use_array); + + dispatch->glAttachShader(gradient_prog, vs_prog); + dispatch->glAttachShader(gradient_prog, fs_getcolor_prog); + dispatch->glAttachShader(gradient_prog, fs_main_prog); + + dispatch->glBindAttribLocation(gradient_prog, GLAMOR_VERTEX_POS, "v_positionsition"); + 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; +} + static GLint _glamor_create_linear_gradient_program(ScreenPtr screen, int stops_count, int use_array) { @@ -1283,7 +1622,7 @@ _glamor_create_linear_gradient_program(ScreenPtr screen, int stops_count, int us GLint gradient_prog = 0; char *gradient_fs = NULL; - GLint fs_prog, vs_prog; + GLint fs_main_prog, fs_getcolor_prog, vs_prog; const char *gradient_vs = GLAMOR_DEFAULT_PRECISION @@ -1350,9 +1689,6 @@ _glamor_create_linear_gradient_program(ScreenPtr screen, int stops_count, int us "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" @@ -1361,122 +1697,9 @@ _glamor_create_linear_gradient_program(ScreenPtr screen, int stops_count, int us "uniform float pt_distance;\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 _pt_distance;\n" - " float y_dist;\n" - " float new_alpha; \n" - " int i = n_stop - 1;\n" - " int revserse = 0;\n" - " vec4 gradient_color;\n" - " float percentage; \n" - " vec3 source_texture_trans = transform_mat * tmp;\n" - " \n" - " if(hor_ver == 0) { \n" //Normal case. - " y_dist = source_texture_trans.y - source_texture_trans.x*pt_slope;\n" - " distance = y_dist * cos_val;\n" - " _p1_distance = p1_distance * source_texture_trans.z;\n" - " _pt_distance = pt_distance * source_texture_trans.z;\n" - " \n" - " } else if (hor_ver == 1) {\n"//horizontal case. - " distance = source_texture_trans.x;\n" - " _p1_distance = p1_distance * source_texture_trans.z;\n" - " _pt_distance = pt_distance * source_texture_trans.z;\n" - " } else if (hor_ver == 2) {\n"//vertical case. - " distance = source_texture_trans.y;\n" - " _p1_distance = p1_distance * source_texture_trans.z;\n" - " _pt_distance = pt_distance * source_texture_trans.z;\n" - " } \n" - " \n" - " distance = distance - _p1_distance; \n" - " \n" - " if(repeat_type == %d){\n" // repeat normal - " while(distance > _pt_distance) \n" - " distance = distance - (_pt_distance); \n" - " while(distance < 0.0) \n" - " distance = distance + (_pt_distance); \n" - " }\n" - " \n" - " if(repeat_type == %d) {\n" // repeat reflect - " while(distance > _pt_distance) {\n" - " distance = distance - (_pt_distance); \n" - " if(revserse == 0)\n" - " revserse = 1;\n" - " else\n" - " revserse = 0;\n" - " }\n" - " while(distance < 0.0) {\n" - " distance = distance + (_pt_distance); \n" - " if(revserse == 0)\n" - " revserse = 1;\n" - " else\n" - " revserse = 0;\n" - " }\n" - " if(revserse == 1) {\n" - " distance = (_pt_distance) - distance; \n" - " }\n" - " }\n" - " \n" - " len_percentage = distance/(_pt_distance);\n" - " for(i = 0; i < n_stop - 1; i++) {\n" - " if(len_percentage < stops[i])\n" - " break; \n" - " }\n" - " \n" - " 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" + "vec4 get_color(float stop_len);\n" "\n" - "void main()\n" - "{\n" - " gl_FragColor = get_color();\n" - "}\n"; - - /* Because the array access for shader is very slow, the performance is very low - if use array. So use global uniform to replace for it if the number of n_stops is small.*/ - const char *gradient_fs_no_array_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 stop0;\n" - "uniform float stop1;\n" - "uniform float stop2;\n" - "uniform float stop3;\n" - "uniform float stop4;\n" - "uniform float stop5;\n" - "uniform float stop6;\n" - "uniform float stop7;\n" - "uniform vec4 stop_color0;\n" - "uniform vec4 stop_color1;\n" - "uniform vec4 stop_color2;\n" - "uniform vec4 stop_color3;\n" - "uniform vec4 stop_color4;\n" - "uniform vec4 stop_color5;\n" - "uniform vec4 stop_color6;\n" - "uniform vec4 stop_color7;\n" - "uniform vec4 pt1;\n" - "uniform vec4 pt2;\n" - "uniform float pt_slope;\n" - "uniform float cos_val;\n" - "uniform float p1_distance;\n" - "uniform float pt_distance;\n" - "varying vec2 source_texture;\n" - "\n" - "vec4 get_color()\n" + "float get_stop_len()\n" "{\n" " vec3 tmp = vec3(source_texture.x, source_texture.y, 1.0);\n" " float len_percentage;\n" @@ -1532,7 +1755,7 @@ _glamor_create_linear_gradient_program(ScreenPtr screen, int stops_count, int us " if(revserse == 0)\n" " revserse = 1;\n" " else\n" - " revserse = 0;\n" + " revserse = 0;\n" " }\n" " if(revserse == 1) {\n" " distance = (_pt_distance) - distance; \n" @@ -1540,75 +1763,14 @@ _glamor_create_linear_gradient_program(ScreenPtr screen, int stops_count, int us " }\n" " \n" " len_percentage = distance/(_pt_distance);\n" - " if((len_percentage < stop0) && (n_stop >= 1)) {\n" - " stop_color_before = stop_color0;\n" - " stop_color_after = stop_color0;\n" - " stop_after = stop0;\n" - " stop_before = stop0;\n" - " percentage = 0.0;\n" - " } else if((len_percentage < stop1) && (n_stop >= 2)) {\n" - " stop_color_before = stop_color0;\n" - " stop_color_after = stop_color1;\n" - " stop_after = stop1;\n" - " stop_before = stop0;\n" - " percentage = (len_percentage - stop0)/(stop1 - stop0);\n" - " } else if((len_percentage < stop2) && (n_stop >= 3)) {\n" - " stop_color_before = stop_color1;\n" - " stop_color_after = stop_color2;\n" - " stop_after = stop2;\n" - " stop_before = stop1;\n" - " percentage = (len_percentage - stop1)/(stop2 - stop1);\n" - " } else if((len_percentage < stop3) && (n_stop >= 4)){\n" - " stop_color_before = stop_color2;\n" - " stop_color_after = stop_color3;\n" - " stop_after = stop3;\n" - " stop_before = stop2;\n" - " percentage = (len_percentage - stop2)/(stop3 - stop2);\n" - " } else if((len_percentage < stop4) && (n_stop >= 5)){\n" - " stop_color_before = stop_color3;\n" - " stop_color_after = stop_color4;\n" - " stop_after = stop4;\n" - " stop_before = stop3;\n" - " percentage = (len_percentage - stop3)/(stop4 - stop3);\n" - " } else if((len_percentage < stop5) && (n_stop >= 6)){\n" - " stop_color_before = stop_color4;\n" - " stop_color_after = stop_color5;\n" - " stop_after = stop5;\n" - " stop_before = stop4;\n" - " percentage = (len_percentage - stop4)/(stop5 - stop4);\n" - " } else if((len_percentage < stop6) && (n_stop >= 7)){\n" - " stop_color_before = stop_color5;\n" - " stop_color_after = stop_color6;\n" - " stop_after = stop6;\n" - " stop_before = stop5;\n" - " percentage = (len_percentage - stop5)/(stop6 - stop5);\n" - " } else if((len_percentage < stop7) && (n_stop >= 8)){\n" - " stop_color_before = stop_color6;\n" - " stop_color_after = stop_color7;\n" - " stop_after = stop7;\n" - " stop_before = stop6;\n" - " percentage = (len_percentage - stop6)/(stop7 - stop6);\n" - " } else {\n" - " stop_color_before = stop_color7;\n" - " stop_color_after = stop_color7;\n" - " stop_after = stop7;\n" - " stop_before = stop7;\n" - " percentage = 0.0;\n" - " }\n" - " if(stop_after - stop_before > 2.0)\n" - " percentage = 0.0;\n"//For comply with pixman, walker->stepper overflow. - " new_alpha = percentage * stop_color_after.a + \n" - " (1.0-percentage) * stop_color_before.a; \n" - " gradient_color = vec4((percentage * stop_color_after.rgb \n" - " + (1.0-percentage) * stop_color_before.rgb)*new_alpha, \n" - " new_alpha);\n" " \n" - " return gradient_color;\n" + " return len_percentage;\n" "}\n" "\n" "void main()\n" "{\n" - " gl_FragColor = get_color();\n" + " float stop_len = get_stop_len();\n" + " gl_FragColor = get_color(stop_len);\n" "}\n"; glamor_priv = glamor_get_screen_private(screen); @@ -1617,23 +1779,22 @@ _glamor_create_linear_gradient_program(ScreenPtr screen, int stops_count, int us gradient_prog = dispatch->glCreateProgram(); vs_prog = glamor_compile_glsl_prog(dispatch, - GL_VERTEX_SHADER, gradient_vs); + GL_VERTEX_SHADER, gradient_vs); - if (use_array) { - XNFasprintf(&gradient_fs, - gradient_fs_template, stops_count, stops_count, - PIXMAN_REPEAT_NORMAL, PIXMAN_REPEAT_REFLECT); - } else { - XNFasprintf(&gradient_fs, - gradient_fs_no_array_template, - PIXMAN_REPEAT_NORMAL, PIXMAN_REPEAT_REFLECT); - } - fs_prog = glamor_compile_glsl_prog(dispatch, - GL_FRAGMENT_SHADER, gradient_fs); + XNFasprintf(&gradient_fs, + gradient_fs_template, + PIXMAN_REPEAT_NORMAL, PIXMAN_REPEAT_REFLECT); + + fs_main_prog = glamor_compile_glsl_prog(dispatch, + GL_FRAGMENT_SHADER, gradient_fs); free(gradient_fs); + fs_getcolor_prog = _glamor_create_getcolor_fs_program(screen, + stops_count, use_array); + dispatch->glAttachShader(gradient_prog, vs_prog); - dispatch->glAttachShader(gradient_prog, fs_prog); + dispatch->glAttachShader(gradient_prog, fs_getcolor_prog); + dispatch->glAttachShader(gradient_prog, fs_main_prog); dispatch->glBindAttribLocation(gradient_prog, GLAMOR_VERTEX_POS, "v_position"); dispatch->glBindAttribLocation(gradient_prog, GLAMOR_VERTEX_SOURCE, "v_texcoord"); @@ -1647,6 +1808,7 @@ _glamor_create_linear_gradient_program(ScreenPtr screen, int stops_count, int us } #define LINEAR_DEFAULT_STOPS 6 + 2 +#define RADIAL_DEFAULT_STOPS 6 + 2 void glamor_init_gradient_shader(ScreenPtr screen) @@ -1658,6 +1820,9 @@ glamor_init_gradient_shader(ScreenPtr screen) glamor_priv->gradient_prog[GRADIENT_SHADER_LINEAR] = _glamor_create_linear_gradient_program(screen, LINEAR_DEFAULT_STOPS, 0); + glamor_priv->gradient_prog[GRADIENT_SHADER_RADIAL] = + _glamor_create_radial_gradient_program(screen, + RADIAL_DEFAULT_STOPS, 0); } void @@ -1671,13 +1836,15 @@ glamor_fini_gradient_shader(ScreenPtr screen) dispatch->glDeleteProgram( glamor_priv->gradient_prog[GRADIENT_SHADER_LINEAR]); + dispatch->glDeleteProgram( + glamor_priv->gradient_prog[GRADIENT_SHADER_RADIAL]); glamor_put_dispatch(glamor_priv); } static void _glamor_gradient_convert_trans_matrix(PictTransform *from, float to[3][3], - int width, int height) + int width, int height, int normalize) { /* * Because in the shader program, we normalize all the pixel cood to [0, 1], @@ -1713,20 +1880,20 @@ _glamor_gradient_convert_trans_matrix(PictTransform *from, float to[3][3], to[0][0] = (float)pixman_fixed_to_double(from->matrix[0][0]); to[0][1] = (float)pixman_fixed_to_double(from->matrix[0][1]) - * ((float)height) / ((float)width); + * (normalize ? (((float)height) / ((float)width)) : 1.0); to[0][2] = (float)pixman_fixed_to_double(from->matrix[0][2]) - / ((float)width); + / (normalize ? ((float)width) : 1.0); to[1][0] = (float)pixman_fixed_to_double(from->matrix[1][0]) - * ((float)width) / ((float)height); + * (normalize ? (((float)width) / ((float)height)) : 1.0); to[1][1] = (float)pixman_fixed_to_double(from->matrix[1][1]); to[1][2] = (float)pixman_fixed_to_double(from->matrix[1][2]) - / ((float)height); + / (normalize ? ((float)height) : 1.0); to[2][0] = (float)pixman_fixed_to_double(from->matrix[2][0]) - * ((float)width); + * (normalize ? ((float)width) : 1.0); to[2][1] = (float)pixman_fixed_to_double(from->matrix[2][1]) - * ((float)height); + * (normalize ? ((float)height) : 1.0); to[2][2] = (float)pixman_fixed_to_double(from->matrix[2][2]); DEBUGF("the transform matrix is:\n%f\t%f\t%f\n%f\t%f\t%f\n%f\t%f\t%f\n", @@ -1877,6 +2044,329 @@ _glamor_gradient_set_stops(PicturePtr src_picture, PictGradient * pgradient, return count; } +static PicturePtr +_glamor_generate_radial_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_picture = NULL; + PixmapPtr pixmap = NULL; + glamor_pixmap_private *pixmap_priv; + GLint gradient_prog = 0; + int error; + float tex_vertices[8]; + int stops_count; + int count = 0; + GLfloat *stop_colors = NULL; + GLfloat *n_stops = NULL; + GLfloat xscale, yscale; + 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[RADIAL_DEFAULT_STOPS*4]; + GLfloat n_stops_st[RADIAL_DEFAULT_STOPS]; + GLfloat A_value; + GLfloat cxy[4]; + float c1x, c1y, c2x, c2y, r1, r2; + + GLint transform_mat_uniform_location; + GLint repeat_type_uniform_location; + GLint n_stop_uniform_location; + GLint stops_uniform_location; + GLint stop_colors_uniform_location; + GLint stop0_uniform_location; + GLint stop1_uniform_location; + GLint stop2_uniform_location; + GLint stop3_uniform_location; + GLint stop4_uniform_location; + GLint stop5_uniform_location; + GLint stop6_uniform_location; + GLint stop7_uniform_location; + GLint stop_color0_uniform_location; + GLint stop_color1_uniform_location; + GLint stop_color2_uniform_location; + GLint stop_color3_uniform_location; + GLint stop_color4_uniform_location; + GLint stop_color5_uniform_location; + GLint stop_color6_uniform_location; + GLint stop_color7_uniform_location; + GLint A_value_uniform_location; + GLint c1_uniform_location; + GLint r1_uniform_location; + GLint c2_uniform_location; + GLint r2_uniform_location; + + glamor_priv = glamor_get_screen_private(screen); + dispatch = glamor_get_dispatch(glamor_priv); + + /* 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_picture = 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_picture) + goto GRADIENT_FAIL; + + ValidatePicture(dst_picture); + + stops_count = src_picture->pSourcePict->radial.nstops + 2 > RADIAL_DEFAULT_STOPS ? + src_picture->pSourcePict->radial.nstops + 2 : RADIAL_DEFAULT_STOPS; + + /* Because the max value of nstops is unkown, so create a programwhen nstops > default.*/ + if (src_picture->pSourcePict->radial.nstops + 2 <= RADIAL_DEFAULT_STOPS) { + gradient_prog = glamor_priv->gradient_prog[GRADIENT_SHADER_RADIAL]; + } else { + gradient_prog = _glamor_create_radial_gradient_program(screen, + src_picture->pSourcePict->radial.nstops + 2, 1); + } + + /* Bind all the uniform vars .*/ + transform_mat_uniform_location = + dispatch->glGetUniformLocation(gradient_prog, "transform_mat"); + repeat_type_uniform_location = + dispatch->glGetUniformLocation(gradient_prog, "repeat_type"); + n_stop_uniform_location = + dispatch->glGetUniformLocation(gradient_prog, "n_stop"); + A_value_uniform_location = + dispatch->glGetUniformLocation(gradient_prog, "A_value"); + repeat_type_uniform_location = + dispatch->glGetUniformLocation(gradient_prog, "repeat_type"); + c1_uniform_location = + dispatch->glGetUniformLocation(gradient_prog, "c1"); + r1_uniform_location = + dispatch->glGetUniformLocation(gradient_prog, "r1"); + c2_uniform_location = + dispatch->glGetUniformLocation(gradient_prog, "c2"); + r2_uniform_location = + dispatch->glGetUniformLocation(gradient_prog, "r2"); + + if (src_picture->pSourcePict->radial.nstops + 2 <= RADIAL_DEFAULT_STOPS) { + stop0_uniform_location = + dispatch->glGetUniformLocation(gradient_prog, "stop0"); + stop1_uniform_location = + dispatch->glGetUniformLocation(gradient_prog, "stop1"); + stop2_uniform_location = + dispatch->glGetUniformLocation(gradient_prog, "stop2"); + stop3_uniform_location = + dispatch->glGetUniformLocation(gradient_prog, "stop3"); + stop4_uniform_location = + dispatch->glGetUniformLocation(gradient_prog, "stop4"); + stop5_uniform_location = + dispatch->glGetUniformLocation(gradient_prog, "stop5"); + stop6_uniform_location = + dispatch->glGetUniformLocation(gradient_prog, "stop6"); + stop7_uniform_location = + dispatch->glGetUniformLocation(gradient_prog, "stop7"); + + stop_color0_uniform_location = + dispatch->glGetUniformLocation(gradient_prog, "stop_color0"); + stop_color1_uniform_location = + dispatch->glGetUniformLocation(gradient_prog, "stop_color1"); + stop_color2_uniform_location = + dispatch->glGetUniformLocation(gradient_prog, "stop_color2"); + stop_color3_uniform_location = + dispatch->glGetUniformLocation(gradient_prog, "stop_color3"); + stop_color4_uniform_location = + dispatch->glGetUniformLocation(gradient_prog, "stop_color4"); + stop_color5_uniform_location = + dispatch->glGetUniformLocation(gradient_prog, "stop_color5"); + stop_color6_uniform_location = + dispatch->glGetUniformLocation(gradient_prog, "stop_color6"); + stop_color7_uniform_location = + dispatch->glGetUniformLocation(gradient_prog, "stop_color7"); + } else { + stops_uniform_location = + dispatch->glGetUniformLocation(gradient_prog, "stops"); + stop_colors_uniform_location = + dispatch->glGetUniformLocation(gradient_prog, "stop_colors"); + } + + dispatch->glUseProgram(gradient_prog); + + dispatch->glUniform1i(repeat_type_uniform_location, src_picture->repeatType); + + + if (src_picture->transform) { + _glamor_gradient_convert_trans_matrix(src_picture->transform, + transform_mat, + width, height, 0); + 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]); + } + + if (!_glamor_gradient_set_pixmap_destination(screen, glamor_priv, dst_picture, + &xscale, &yscale, x_source, y_source, + vertices, tex_vertices, 0)) + goto GRADIENT_FAIL; + + /* Set all the stops and colors to shader. */ + if (stops_count > RADIAL_DEFAULT_STOPS) { + stop_colors = malloc(4 * stops_count * sizeof(float)); + if (stop_colors == NULL) { + ErrorF("Failed to allocate stop_colors memory.\n"); + goto GRADIENT_FAIL; + } + + n_stops = malloc(stops_count * sizeof(float)); + if (n_stops == NULL) { + ErrorF("Failed to allocate n_stops memory.\n"); + goto GRADIENT_FAIL; + } + } else { + stop_colors = stop_colors_st; + n_stops = n_stops_st; + } + + count = _glamor_gradient_set_stops(src_picture, &src_picture->pSourcePict->gradient, + stop_colors, n_stops); + + if (src_picture->pSourcePict->linear.nstops + 2 <= LINEAR_DEFAULT_STOPS) { + int j = 0; + dispatch->glUniform4f(stop_color0_uniform_location, stop_colors[4*j+0], stop_colors[4*j+1], + stop_colors[4*j+2], stop_colors[4*j+3]); + j++; + dispatch->glUniform4f(stop_color1_uniform_location, stop_colors[4*j+0], stop_colors[4*j+1], + stop_colors[4*j+2], stop_colors[4*j+3]); + j++; + dispatch->glUniform4f(stop_color2_uniform_location, stop_colors[4*j+0], stop_colors[4*j+1], + stop_colors[4*j+2], stop_colors[4*j+3]); + j++; + dispatch->glUniform4f(stop_color3_uniform_location, stop_colors[4*j+0], stop_colors[4*j+1], + stop_colors[4*j+2], stop_colors[4*j+3]); + j++; + dispatch->glUniform4f(stop_color4_uniform_location, stop_colors[4*j+0], stop_colors[4*j+1], + stop_colors[4*j+2], stop_colors[4*j+3]); + j++; + dispatch->glUniform4f(stop_color5_uniform_location, stop_colors[4*j+0], stop_colors[4*j+1], + stop_colors[4*j+2], stop_colors[4*j+3]); + j++; + dispatch->glUniform4f(stop_color6_uniform_location, stop_colors[4*j+0], stop_colors[4*j+1], + stop_colors[4*j+2], stop_colors[4*j+3]); + j++; + dispatch->glUniform4f(stop_color7_uniform_location, stop_colors[4*j+0], stop_colors[4*j+1], + stop_colors[4*j+2], stop_colors[4*j+3]); + + j = 0; + dispatch->glUniform1f(stop0_uniform_location, n_stops[j++]); + dispatch->glUniform1f(stop1_uniform_location, n_stops[j++]); + dispatch->glUniform1f(stop2_uniform_location, n_stops[j++]); + dispatch->glUniform1f(stop3_uniform_location, n_stops[j++]); + dispatch->glUniform1f(stop4_uniform_location, n_stops[j++]); + dispatch->glUniform1f(stop5_uniform_location, n_stops[j++]); + dispatch->glUniform1f(stop6_uniform_location, n_stops[j++]); + dispatch->glUniform1f(stop7_uniform_location, n_stops[j++]); + dispatch->glUniform1i(n_stop_uniform_location, count); + } else { + dispatch->glUniform4fv(stop_colors_uniform_location, count, stop_colors); + dispatch->glUniform1fv(stops_uniform_location, count, n_stops); + dispatch->glUniform1i(n_stop_uniform_location, count); + } + + c1x = (float)pixman_fixed_to_double(src_picture->pSourcePict->radial.c1.x); + c1y = (float)pixman_fixed_to_double(src_picture->pSourcePict->radial.c1.y); + c2x = (float)pixman_fixed_to_double(src_picture->pSourcePict->radial.c2.x); + c2y = (float)pixman_fixed_to_double(src_picture->pSourcePict->radial.c2.y); + + r1 = (float)pixman_fixed_to_double(src_picture->pSourcePict->radial.c1.radius); + r2 = (float)pixman_fixed_to_double(src_picture->pSourcePict->radial.c2.radius); + + + cxy[0] = c1x; + cxy[1] = c1y; + dispatch->glUniform2fv(c1_uniform_location, 1, cxy); + dispatch->glUniform1f(r1_uniform_location, r1); + + cxy[0] = c2x; + cxy[1] = c2y; + dispatch->glUniform2fv(c2_uniform_location, 1, cxy); + dispatch->glUniform1f(r2_uniform_location, r2); + + A_value = (c2x - c1x) * (c2x - c1x) + (c2y - c1y) * (c2y - c1y) - (r2 - r1) * (r2 - r1); + dispatch->glUniform1f(A_value_uniform_location, A_value); + + DEBUGF("C1:(%f, %f) R1:%f\nC2:(%f, %f) R2:%f\nA = %f\n", + c1x, c1y, r1, c2x, c2y, r2, A_value); + + 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 > RADIAL_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->radial.nstops + 2 > RADIAL_DEFAULT_STOPS) + dispatch->glDeleteProgram(gradient_prog); + + glamor_put_dispatch(glamor_priv); + return dst_picture; + +GRADIENT_FAIL: + if (dst_picture) { + FreePicture(dst_picture, 0); + } + + if (stops_count > RADIAL_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->radial.nstops + 2 > RADIAL_DEFAULT_STOPS) + dispatch->glDeleteProgram(gradient_prog); + glamor_put_dispatch(glamor_priv); + return NULL; +} + static PicturePtr _glamor_generate_linear_gradient_picture(ScreenPtr screen, PicturePtr src_picture, @@ -1905,8 +2395,8 @@ _glamor_generate_linear_gradient_picture(ScreenPtr screen, 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}}; + {0.0, 1.0, 0.0}, + {0.0, 0.0, 1.0}}; GLfloat stop_colors_st[LINEAR_DEFAULT_STOPS*4]; GLfloat n_stops_st[LINEAR_DEFAULT_STOPS]; @@ -2046,7 +2536,7 @@ _glamor_generate_linear_gradient_picture(ScreenPtr screen, if (src_picture->transform) { _glamor_gradient_convert_trans_matrix(src_picture->transform, transform_mat, - width, height); + width, height, 1); dispatch->glUniformMatrix3fv(transform_mat_uniform_location, 1, 1, &transform_mat[0][0]); } else { @@ -2258,6 +2748,9 @@ glamor_convert_gradient_picture(ScreenPtr screen, if (source->pSourcePict->type == SourcePictTypeLinear) { dst = _glamor_generate_linear_gradient_picture(screen, source, x_source, y_source, width, height, format); + } else if (source->pSourcePict->type == SourcePictTypeRadial) { + dst = _glamor_generate_radial_gradient_picture(screen, + source, x_source, y_source, width, height, format); } if (dst) {