xref: /OK3568_Linux_fs/external/xserver/glamor/glamor_program.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * Copyright © 2014 Keith Packard
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * Permission to use, copy, modify, distribute, and sell this software and its
5*4882a593Smuzhiyun  * documentation for any purpose is hereby granted without fee, provided that
6*4882a593Smuzhiyun  * the above copyright notice appear in all copies and that both that copyright
7*4882a593Smuzhiyun  * notice and this permission notice appear in supporting documentation, and
8*4882a593Smuzhiyun  * that the name of the copyright holders not be used in advertising or
9*4882a593Smuzhiyun  * publicity pertaining to distribution of the software without specific,
10*4882a593Smuzhiyun  * written prior permission.  The copyright holders make no representations
11*4882a593Smuzhiyun  * about the suitability of this software for any purpose.  It is provided "as
12*4882a593Smuzhiyun  * is" without express or implied warranty.
13*4882a593Smuzhiyun  *
14*4882a593Smuzhiyun  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15*4882a593Smuzhiyun  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16*4882a593Smuzhiyun  * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17*4882a593Smuzhiyun  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18*4882a593Smuzhiyun  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19*4882a593Smuzhiyun  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
20*4882a593Smuzhiyun  * OF THIS SOFTWARE.
21*4882a593Smuzhiyun  */
22*4882a593Smuzhiyun 
23*4882a593Smuzhiyun #include "glamor_priv.h"
24*4882a593Smuzhiyun #include "glamor_transform.h"
25*4882a593Smuzhiyun #include "glamor_program.h"
26*4882a593Smuzhiyun 
27*4882a593Smuzhiyun static Bool
use_solid(PixmapPtr pixmap,GCPtr gc,glamor_program * prog,void * arg)28*4882a593Smuzhiyun use_solid(PixmapPtr pixmap, GCPtr gc, glamor_program *prog, void *arg)
29*4882a593Smuzhiyun {
30*4882a593Smuzhiyun     return glamor_set_solid(pixmap, gc, TRUE, prog->fg_uniform);
31*4882a593Smuzhiyun }
32*4882a593Smuzhiyun 
33*4882a593Smuzhiyun const glamor_facet glamor_fill_solid = {
34*4882a593Smuzhiyun     .name = "solid",
35*4882a593Smuzhiyun     .fs_exec = "       gl_FragColor = fg;\n",
36*4882a593Smuzhiyun     .locations = glamor_program_location_fg,
37*4882a593Smuzhiyun     .use = use_solid,
38*4882a593Smuzhiyun };
39*4882a593Smuzhiyun 
40*4882a593Smuzhiyun static Bool
use_tile(PixmapPtr pixmap,GCPtr gc,glamor_program * prog,void * arg)41*4882a593Smuzhiyun use_tile(PixmapPtr pixmap, GCPtr gc, glamor_program *prog, void *arg)
42*4882a593Smuzhiyun {
43*4882a593Smuzhiyun     return glamor_set_tiled(pixmap, gc, prog->fill_offset_uniform, prog->fill_size_inv_uniform);
44*4882a593Smuzhiyun }
45*4882a593Smuzhiyun 
46*4882a593Smuzhiyun static const glamor_facet glamor_fill_tile = {
47*4882a593Smuzhiyun     .name = "tile",
48*4882a593Smuzhiyun     .vs_exec =  "       fill_pos = (fill_offset + primitive.xy + pos) * fill_size_inv;\n",
49*4882a593Smuzhiyun     .fs_exec =  "       gl_FragColor = texture2D(sampler, fill_pos);\n",
50*4882a593Smuzhiyun     .locations = glamor_program_location_fillsamp | glamor_program_location_fillpos,
51*4882a593Smuzhiyun     .use = use_tile,
52*4882a593Smuzhiyun };
53*4882a593Smuzhiyun 
54*4882a593Smuzhiyun static Bool
use_stipple(PixmapPtr pixmap,GCPtr gc,glamor_program * prog,void * arg)55*4882a593Smuzhiyun use_stipple(PixmapPtr pixmap, GCPtr gc, glamor_program *prog, void *arg)
56*4882a593Smuzhiyun {
57*4882a593Smuzhiyun     return glamor_set_stippled(pixmap, gc, prog->fg_uniform,
58*4882a593Smuzhiyun                                prog->fill_offset_uniform,
59*4882a593Smuzhiyun                                prog->fill_size_inv_uniform);
60*4882a593Smuzhiyun }
61*4882a593Smuzhiyun 
62*4882a593Smuzhiyun static const glamor_facet glamor_fill_stipple = {
63*4882a593Smuzhiyun     .name = "stipple",
64*4882a593Smuzhiyun     .vs_exec =  "       fill_pos = (fill_offset + primitive.xy + pos) * fill_size_inv;\n",
65*4882a593Smuzhiyun     .fs_exec = ("       float a = texture2D(sampler, fill_pos).w;\n"
66*4882a593Smuzhiyun                 "       if (a == 0.0)\n"
67*4882a593Smuzhiyun                 "               discard;\n"
68*4882a593Smuzhiyun                 "       gl_FragColor = fg;\n"),
69*4882a593Smuzhiyun     .locations = glamor_program_location_fg | glamor_program_location_fillsamp | glamor_program_location_fillpos,
70*4882a593Smuzhiyun     .use = use_stipple,
71*4882a593Smuzhiyun };
72*4882a593Smuzhiyun 
73*4882a593Smuzhiyun static Bool
use_opaque_stipple(PixmapPtr pixmap,GCPtr gc,glamor_program * prog,void * arg)74*4882a593Smuzhiyun use_opaque_stipple(PixmapPtr pixmap, GCPtr gc, glamor_program *prog, void *arg)
75*4882a593Smuzhiyun {
76*4882a593Smuzhiyun     if (!use_stipple(pixmap, gc, prog, arg))
77*4882a593Smuzhiyun         return FALSE;
78*4882a593Smuzhiyun     glamor_set_color(pixmap, gc->bgPixel, prog->bg_uniform);
79*4882a593Smuzhiyun     return TRUE;
80*4882a593Smuzhiyun }
81*4882a593Smuzhiyun 
82*4882a593Smuzhiyun static const glamor_facet glamor_fill_opaque_stipple = {
83*4882a593Smuzhiyun     .name = "opaque_stipple",
84*4882a593Smuzhiyun     .vs_exec =  "       fill_pos = (fill_offset + primitive.xy + pos) * fill_size_inv;\n",
85*4882a593Smuzhiyun     .fs_exec = ("       float a = texture2D(sampler, fill_pos).w;\n"
86*4882a593Smuzhiyun                 "       if (a == 0.0)\n"
87*4882a593Smuzhiyun                 "               gl_FragColor = bg;\n"
88*4882a593Smuzhiyun                 "       else\n"
89*4882a593Smuzhiyun                 "               gl_FragColor = fg;\n"),
90*4882a593Smuzhiyun     .locations = glamor_program_location_fg | glamor_program_location_bg | glamor_program_location_fillsamp | glamor_program_location_fillpos,
91*4882a593Smuzhiyun     .use = use_opaque_stipple
92*4882a593Smuzhiyun };
93*4882a593Smuzhiyun 
94*4882a593Smuzhiyun static const glamor_facet *glamor_facet_fill[4] = {
95*4882a593Smuzhiyun     &glamor_fill_solid,
96*4882a593Smuzhiyun     &glamor_fill_tile,
97*4882a593Smuzhiyun     &glamor_fill_stipple,
98*4882a593Smuzhiyun     &glamor_fill_opaque_stipple,
99*4882a593Smuzhiyun };
100*4882a593Smuzhiyun 
101*4882a593Smuzhiyun typedef struct {
102*4882a593Smuzhiyun     glamor_program_location     location;
103*4882a593Smuzhiyun     const char                  *vs_vars;
104*4882a593Smuzhiyun     const char                  *fs_vars;
105*4882a593Smuzhiyun } glamor_location_var;
106*4882a593Smuzhiyun 
107*4882a593Smuzhiyun static glamor_location_var location_vars[] = {
108*4882a593Smuzhiyun     {
109*4882a593Smuzhiyun         .location = glamor_program_location_fg,
110*4882a593Smuzhiyun         .fs_vars = "uniform vec4 fg;\n"
111*4882a593Smuzhiyun     },
112*4882a593Smuzhiyun     {
113*4882a593Smuzhiyun         .location = glamor_program_location_bg,
114*4882a593Smuzhiyun         .fs_vars = "uniform vec4 bg;\n"
115*4882a593Smuzhiyun     },
116*4882a593Smuzhiyun     {
117*4882a593Smuzhiyun         .location = glamor_program_location_fillsamp,
118*4882a593Smuzhiyun         .fs_vars = "uniform sampler2D sampler;\n"
119*4882a593Smuzhiyun     },
120*4882a593Smuzhiyun     {
121*4882a593Smuzhiyun         .location = glamor_program_location_fillpos,
122*4882a593Smuzhiyun         .vs_vars = ("uniform vec2 fill_offset;\n"
123*4882a593Smuzhiyun                     "uniform vec2 fill_size_inv;\n"
124*4882a593Smuzhiyun                     "varying vec2 fill_pos;\n"),
125*4882a593Smuzhiyun         .fs_vars = ("varying vec2 fill_pos;\n")
126*4882a593Smuzhiyun     },
127*4882a593Smuzhiyun     {
128*4882a593Smuzhiyun         .location = glamor_program_location_font,
129*4882a593Smuzhiyun         .fs_vars = "uniform usampler2D font;\n",
130*4882a593Smuzhiyun     },
131*4882a593Smuzhiyun     {
132*4882a593Smuzhiyun         .location = glamor_program_location_bitplane,
133*4882a593Smuzhiyun         .fs_vars = ("uniform uvec4 bitplane;\n"
134*4882a593Smuzhiyun                     "uniform vec4 bitmul;\n"),
135*4882a593Smuzhiyun     },
136*4882a593Smuzhiyun     {
137*4882a593Smuzhiyun         .location = glamor_program_location_dash,
138*4882a593Smuzhiyun         .vs_vars = "uniform float dash_length;\n",
139*4882a593Smuzhiyun         .fs_vars = "uniform sampler2D dash;\n",
140*4882a593Smuzhiyun     },
141*4882a593Smuzhiyun     {
142*4882a593Smuzhiyun         .location = glamor_program_location_atlas,
143*4882a593Smuzhiyun         .fs_vars = "uniform sampler2D atlas;\n",
144*4882a593Smuzhiyun     },
145*4882a593Smuzhiyun };
146*4882a593Smuzhiyun 
147*4882a593Smuzhiyun static char *
add_var(char * cur,const char * add)148*4882a593Smuzhiyun add_var(char *cur, const char *add)
149*4882a593Smuzhiyun {
150*4882a593Smuzhiyun     char *new;
151*4882a593Smuzhiyun 
152*4882a593Smuzhiyun     if (!add)
153*4882a593Smuzhiyun         return cur;
154*4882a593Smuzhiyun 
155*4882a593Smuzhiyun     new = realloc(cur, strlen(cur) + strlen(add) + 1);
156*4882a593Smuzhiyun     if (!new) {
157*4882a593Smuzhiyun         free(cur);
158*4882a593Smuzhiyun         return NULL;
159*4882a593Smuzhiyun     }
160*4882a593Smuzhiyun     strcat(new, add);
161*4882a593Smuzhiyun     return new;
162*4882a593Smuzhiyun }
163*4882a593Smuzhiyun 
164*4882a593Smuzhiyun static char *
vs_location_vars(glamor_program_location locations)165*4882a593Smuzhiyun vs_location_vars(glamor_program_location locations)
166*4882a593Smuzhiyun {
167*4882a593Smuzhiyun     int l;
168*4882a593Smuzhiyun     char *vars = strdup("");
169*4882a593Smuzhiyun 
170*4882a593Smuzhiyun     for (l = 0; vars && l < ARRAY_SIZE(location_vars); l++)
171*4882a593Smuzhiyun         if (locations & location_vars[l].location)
172*4882a593Smuzhiyun             vars = add_var(vars, location_vars[l].vs_vars);
173*4882a593Smuzhiyun     return vars;
174*4882a593Smuzhiyun }
175*4882a593Smuzhiyun 
176*4882a593Smuzhiyun static char *
fs_location_vars(glamor_program_location locations)177*4882a593Smuzhiyun fs_location_vars(glamor_program_location locations)
178*4882a593Smuzhiyun {
179*4882a593Smuzhiyun     int l;
180*4882a593Smuzhiyun     char *vars = strdup("");
181*4882a593Smuzhiyun 
182*4882a593Smuzhiyun     for (l = 0; vars && l < ARRAY_SIZE(location_vars); l++)
183*4882a593Smuzhiyun         if (locations & location_vars[l].location)
184*4882a593Smuzhiyun             vars = add_var(vars, location_vars[l].fs_vars);
185*4882a593Smuzhiyun     return vars;
186*4882a593Smuzhiyun }
187*4882a593Smuzhiyun 
188*4882a593Smuzhiyun static const char vs_template[] =
189*4882a593Smuzhiyun     "%s"                                /* version */
190*4882a593Smuzhiyun     "%s"                                /* defines */
191*4882a593Smuzhiyun     "%s"                                /* prim vs_vars */
192*4882a593Smuzhiyun     "%s"                                /* fill vs_vars */
193*4882a593Smuzhiyun     "%s"                                /* location vs_vars */
194*4882a593Smuzhiyun     GLAMOR_DECLARE_MATRIX
195*4882a593Smuzhiyun     "void main() {\n"
196*4882a593Smuzhiyun     "%s"                                /* prim vs_exec, outputs 'pos' and gl_Position */
197*4882a593Smuzhiyun     "%s"                                /* fill vs_exec */
198*4882a593Smuzhiyun     "}\n";
199*4882a593Smuzhiyun 
200*4882a593Smuzhiyun static const char fs_template[] =
201*4882a593Smuzhiyun     "%s"                                /* version */
202*4882a593Smuzhiyun     "%s"                                /* prim extensions */
203*4882a593Smuzhiyun     "%s"                                /* fill extensions */
204*4882a593Smuzhiyun     GLAMOR_DEFAULT_PRECISION
205*4882a593Smuzhiyun     "%s"                                /* defines */
206*4882a593Smuzhiyun     "%s"                                /* prim fs_vars */
207*4882a593Smuzhiyun     "%s"                                /* fill fs_vars */
208*4882a593Smuzhiyun     "%s"                                /* location fs_vars */
209*4882a593Smuzhiyun     "void main() {\n"
210*4882a593Smuzhiyun     "%s"                                /* prim fs_exec */
211*4882a593Smuzhiyun     "%s"                                /* fill fs_exec */
212*4882a593Smuzhiyun     "%s"                                /* combine */
213*4882a593Smuzhiyun     "}\n";
214*4882a593Smuzhiyun 
215*4882a593Smuzhiyun static const char *
str(const char * s)216*4882a593Smuzhiyun str(const char *s)
217*4882a593Smuzhiyun {
218*4882a593Smuzhiyun     if (!s)
219*4882a593Smuzhiyun         return "";
220*4882a593Smuzhiyun     return s;
221*4882a593Smuzhiyun }
222*4882a593Smuzhiyun 
223*4882a593Smuzhiyun static const glamor_facet facet_null_fill = {
224*4882a593Smuzhiyun     .name = ""
225*4882a593Smuzhiyun };
226*4882a593Smuzhiyun 
227*4882a593Smuzhiyun #define DBG 0
228*4882a593Smuzhiyun 
229*4882a593Smuzhiyun static GLint
glamor_get_uniform(glamor_program * prog,glamor_program_location location,const char * name)230*4882a593Smuzhiyun glamor_get_uniform(glamor_program               *prog,
231*4882a593Smuzhiyun                    glamor_program_location      location,
232*4882a593Smuzhiyun                    const char                   *name)
233*4882a593Smuzhiyun {
234*4882a593Smuzhiyun     GLint uniform;
235*4882a593Smuzhiyun     if (location && (prog->locations & location) == 0)
236*4882a593Smuzhiyun         return -2;
237*4882a593Smuzhiyun     uniform = glGetUniformLocation(prog->prog, name);
238*4882a593Smuzhiyun #if DBG
239*4882a593Smuzhiyun     ErrorF("%s uniform %d\n", name, uniform);
240*4882a593Smuzhiyun #endif
241*4882a593Smuzhiyun     return uniform;
242*4882a593Smuzhiyun }
243*4882a593Smuzhiyun 
244*4882a593Smuzhiyun Bool
glamor_build_program(ScreenPtr screen,glamor_program * prog,const glamor_facet * prim,const glamor_facet * fill,const char * combine,const char * defines)245*4882a593Smuzhiyun glamor_build_program(ScreenPtr          screen,
246*4882a593Smuzhiyun                      glamor_program     *prog,
247*4882a593Smuzhiyun                      const glamor_facet *prim,
248*4882a593Smuzhiyun                      const glamor_facet *fill,
249*4882a593Smuzhiyun                      const char         *combine,
250*4882a593Smuzhiyun                      const char         *defines)
251*4882a593Smuzhiyun {
252*4882a593Smuzhiyun     glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
253*4882a593Smuzhiyun 
254*4882a593Smuzhiyun     glamor_program_location     locations = prim->locations;
255*4882a593Smuzhiyun     glamor_program_flag         flags = prim->flags;
256*4882a593Smuzhiyun 
257*4882a593Smuzhiyun     int                         version = prim->version;
258*4882a593Smuzhiyun     char                        *version_string = NULL;
259*4882a593Smuzhiyun 
260*4882a593Smuzhiyun     char                        *fs_vars = NULL;
261*4882a593Smuzhiyun     char                        *vs_vars = NULL;
262*4882a593Smuzhiyun 
263*4882a593Smuzhiyun     char                        *vs_prog_string;
264*4882a593Smuzhiyun     char                        *fs_prog_string;
265*4882a593Smuzhiyun 
266*4882a593Smuzhiyun     GLint                       fs_prog, vs_prog;
267*4882a593Smuzhiyun 
268*4882a593Smuzhiyun     if (!fill)
269*4882a593Smuzhiyun         fill = &facet_null_fill;
270*4882a593Smuzhiyun 
271*4882a593Smuzhiyun     locations |= fill->locations;
272*4882a593Smuzhiyun     flags |= fill->flags;
273*4882a593Smuzhiyun     version = MAX(version, fill->version);
274*4882a593Smuzhiyun 
275*4882a593Smuzhiyun     if (version > glamor_priv->glsl_version)
276*4882a593Smuzhiyun         goto fail;
277*4882a593Smuzhiyun 
278*4882a593Smuzhiyun     vs_vars = vs_location_vars(locations);
279*4882a593Smuzhiyun     fs_vars = fs_location_vars(locations);
280*4882a593Smuzhiyun 
281*4882a593Smuzhiyun     if (!vs_vars)
282*4882a593Smuzhiyun         goto fail;
283*4882a593Smuzhiyun     if (!fs_vars)
284*4882a593Smuzhiyun         goto fail;
285*4882a593Smuzhiyun 
286*4882a593Smuzhiyun     if (version && !glamor_priv->is_gles) {
287*4882a593Smuzhiyun         if (asprintf(&version_string, "#version %d\n", version) < 0)
288*4882a593Smuzhiyun             version_string = NULL;
289*4882a593Smuzhiyun         if (!version_string)
290*4882a593Smuzhiyun             goto fail;
291*4882a593Smuzhiyun     }
292*4882a593Smuzhiyun 
293*4882a593Smuzhiyun     if (asprintf(&vs_prog_string,
294*4882a593Smuzhiyun                  vs_template,
295*4882a593Smuzhiyun                  str(version_string),
296*4882a593Smuzhiyun                  str(defines),
297*4882a593Smuzhiyun                  str(prim->vs_vars),
298*4882a593Smuzhiyun                  str(fill->vs_vars),
299*4882a593Smuzhiyun                  vs_vars,
300*4882a593Smuzhiyun                  str(prim->vs_exec),
301*4882a593Smuzhiyun                  str(fill->vs_exec)) < 0)
302*4882a593Smuzhiyun         vs_prog_string = NULL;
303*4882a593Smuzhiyun 
304*4882a593Smuzhiyun     if (asprintf(&fs_prog_string,
305*4882a593Smuzhiyun                  fs_template,
306*4882a593Smuzhiyun                  str(version_string),
307*4882a593Smuzhiyun                  str(prim->fs_extensions),
308*4882a593Smuzhiyun                  str(fill->fs_extensions),
309*4882a593Smuzhiyun                  str(defines),
310*4882a593Smuzhiyun                  str(prim->fs_vars),
311*4882a593Smuzhiyun                  str(fill->fs_vars),
312*4882a593Smuzhiyun                  fs_vars,
313*4882a593Smuzhiyun                  str(prim->fs_exec),
314*4882a593Smuzhiyun                  str(fill->fs_exec),
315*4882a593Smuzhiyun                  str(combine)) < 0)
316*4882a593Smuzhiyun         fs_prog_string = NULL;
317*4882a593Smuzhiyun 
318*4882a593Smuzhiyun     if (!vs_prog_string || !fs_prog_string)
319*4882a593Smuzhiyun         goto fail;
320*4882a593Smuzhiyun 
321*4882a593Smuzhiyun     prog->prog = glCreateProgram();
322*4882a593Smuzhiyun #if DBG
323*4882a593Smuzhiyun     ErrorF("\n\tProgram %d for %s %s\n\tVertex shader:\n\n\t================\n%s\n\n\tFragment Shader:\n\n%s\t================\n",
324*4882a593Smuzhiyun            prog->prog, prim->name, fill->name, vs_prog_string, fs_prog_string);
325*4882a593Smuzhiyun #endif
326*4882a593Smuzhiyun 
327*4882a593Smuzhiyun     prog->flags = flags;
328*4882a593Smuzhiyun     prog->locations = locations;
329*4882a593Smuzhiyun     prog->prim_use = prim->use;
330*4882a593Smuzhiyun     prog->prim_use_render = prim->use_render;
331*4882a593Smuzhiyun     prog->fill_use = fill->use;
332*4882a593Smuzhiyun     prog->fill_use_render = fill->use_render;
333*4882a593Smuzhiyun 
334*4882a593Smuzhiyun     vs_prog = glamor_compile_glsl_prog(GL_VERTEX_SHADER, vs_prog_string);
335*4882a593Smuzhiyun     fs_prog = glamor_compile_glsl_prog(GL_FRAGMENT_SHADER, fs_prog_string);
336*4882a593Smuzhiyun     free(vs_prog_string);
337*4882a593Smuzhiyun     free(fs_prog_string);
338*4882a593Smuzhiyun     glAttachShader(prog->prog, vs_prog);
339*4882a593Smuzhiyun     glDeleteShader(vs_prog);
340*4882a593Smuzhiyun     glAttachShader(prog->prog, fs_prog);
341*4882a593Smuzhiyun     glDeleteShader(fs_prog);
342*4882a593Smuzhiyun     glBindAttribLocation(prog->prog, GLAMOR_VERTEX_POS, "primitive");
343*4882a593Smuzhiyun 
344*4882a593Smuzhiyun     if (prim->source_name) {
345*4882a593Smuzhiyun #if DBG
346*4882a593Smuzhiyun         ErrorF("Bind GLAMOR_VERTEX_SOURCE to %s\n", prim->source_name);
347*4882a593Smuzhiyun #endif
348*4882a593Smuzhiyun         glBindAttribLocation(prog->prog, GLAMOR_VERTEX_SOURCE, prim->source_name);
349*4882a593Smuzhiyun     }
350*4882a593Smuzhiyun     if (prog->alpha == glamor_program_alpha_dual_blend) {
351*4882a593Smuzhiyun         glBindFragDataLocationIndexed(prog->prog, 0, 0, "color0");
352*4882a593Smuzhiyun         glBindFragDataLocationIndexed(prog->prog, 0, 1, "color1");
353*4882a593Smuzhiyun     }
354*4882a593Smuzhiyun 
355*4882a593Smuzhiyun     glamor_link_glsl_prog(screen, prog->prog, "%s_%s", prim->name, fill->name);
356*4882a593Smuzhiyun 
357*4882a593Smuzhiyun     prog->matrix_uniform = glamor_get_uniform(prog, glamor_program_location_none, "v_matrix");
358*4882a593Smuzhiyun     prog->fg_uniform = glamor_get_uniform(prog, glamor_program_location_fg, "fg");
359*4882a593Smuzhiyun     prog->bg_uniform = glamor_get_uniform(prog, glamor_program_location_bg, "bg");
360*4882a593Smuzhiyun     prog->fill_offset_uniform = glamor_get_uniform(prog, glamor_program_location_fillpos, "fill_offset");
361*4882a593Smuzhiyun     prog->fill_size_inv_uniform = glamor_get_uniform(prog, glamor_program_location_fillpos, "fill_size_inv");
362*4882a593Smuzhiyun     prog->font_uniform = glamor_get_uniform(prog, glamor_program_location_font, "font");
363*4882a593Smuzhiyun     prog->bitplane_uniform = glamor_get_uniform(prog, glamor_program_location_bitplane, "bitplane");
364*4882a593Smuzhiyun     prog->bitmul_uniform = glamor_get_uniform(prog, glamor_program_location_bitplane, "bitmul");
365*4882a593Smuzhiyun     prog->dash_uniform = glamor_get_uniform(prog, glamor_program_location_dash, "dash");
366*4882a593Smuzhiyun     prog->dash_length_uniform = glamor_get_uniform(prog, glamor_program_location_dash, "dash_length");
367*4882a593Smuzhiyun     prog->atlas_uniform = glamor_get_uniform(prog, glamor_program_location_atlas, "atlas");
368*4882a593Smuzhiyun 
369*4882a593Smuzhiyun     free(version_string);
370*4882a593Smuzhiyun     free(fs_vars);
371*4882a593Smuzhiyun     free(vs_vars);
372*4882a593Smuzhiyun     return TRUE;
373*4882a593Smuzhiyun fail:
374*4882a593Smuzhiyun     prog->failed = 1;
375*4882a593Smuzhiyun     if (prog->prog) {
376*4882a593Smuzhiyun         glDeleteProgram(prog->prog);
377*4882a593Smuzhiyun         prog->prog = 0;
378*4882a593Smuzhiyun     }
379*4882a593Smuzhiyun     free(version_string);
380*4882a593Smuzhiyun     free(fs_vars);
381*4882a593Smuzhiyun     free(vs_vars);
382*4882a593Smuzhiyun     return FALSE;
383*4882a593Smuzhiyun }
384*4882a593Smuzhiyun 
385*4882a593Smuzhiyun Bool
glamor_use_program(PixmapPtr pixmap,GCPtr gc,glamor_program * prog,void * arg)386*4882a593Smuzhiyun glamor_use_program(PixmapPtr            pixmap,
387*4882a593Smuzhiyun                    GCPtr                gc,
388*4882a593Smuzhiyun                    glamor_program       *prog,
389*4882a593Smuzhiyun                    void                 *arg)
390*4882a593Smuzhiyun {
391*4882a593Smuzhiyun     glUseProgram(prog->prog);
392*4882a593Smuzhiyun 
393*4882a593Smuzhiyun     if (prog->prim_use && !prog->prim_use(pixmap, gc, prog, arg))
394*4882a593Smuzhiyun         return FALSE;
395*4882a593Smuzhiyun 
396*4882a593Smuzhiyun     if (prog->fill_use && !prog->fill_use(pixmap, gc, prog, arg))
397*4882a593Smuzhiyun         return FALSE;
398*4882a593Smuzhiyun 
399*4882a593Smuzhiyun     return TRUE;
400*4882a593Smuzhiyun }
401*4882a593Smuzhiyun 
402*4882a593Smuzhiyun glamor_program *
glamor_use_program_fill(PixmapPtr pixmap,GCPtr gc,glamor_program_fill * program_fill,const glamor_facet * prim)403*4882a593Smuzhiyun glamor_use_program_fill(PixmapPtr               pixmap,
404*4882a593Smuzhiyun                         GCPtr                   gc,
405*4882a593Smuzhiyun                         glamor_program_fill     *program_fill,
406*4882a593Smuzhiyun                         const glamor_facet      *prim)
407*4882a593Smuzhiyun {
408*4882a593Smuzhiyun     ScreenPtr                   screen = pixmap->drawable.pScreen;
409*4882a593Smuzhiyun     glamor_program              *prog = &program_fill->progs[gc->fillStyle];
410*4882a593Smuzhiyun 
411*4882a593Smuzhiyun     int                         fill_style = gc->fillStyle;
412*4882a593Smuzhiyun     const glamor_facet          *fill;
413*4882a593Smuzhiyun 
414*4882a593Smuzhiyun     if (prog->failed)
415*4882a593Smuzhiyun         return FALSE;
416*4882a593Smuzhiyun 
417*4882a593Smuzhiyun     if (!prog->prog) {
418*4882a593Smuzhiyun         fill = glamor_facet_fill[fill_style];
419*4882a593Smuzhiyun         if (!fill)
420*4882a593Smuzhiyun             return NULL;
421*4882a593Smuzhiyun 
422*4882a593Smuzhiyun         if (!glamor_build_program(screen, prog, prim, fill, NULL, NULL))
423*4882a593Smuzhiyun             return NULL;
424*4882a593Smuzhiyun     }
425*4882a593Smuzhiyun 
426*4882a593Smuzhiyun     if (!glamor_use_program(pixmap, gc, prog, NULL))
427*4882a593Smuzhiyun         return NULL;
428*4882a593Smuzhiyun 
429*4882a593Smuzhiyun     return prog;
430*4882a593Smuzhiyun }
431*4882a593Smuzhiyun 
432*4882a593Smuzhiyun static struct blendinfo composite_op_info[] = {
433*4882a593Smuzhiyun     [PictOpClear] = {0, 0, GL_ZERO, GL_ZERO},
434*4882a593Smuzhiyun     [PictOpSrc] = {0, 0, GL_ONE, GL_ZERO},
435*4882a593Smuzhiyun     [PictOpDst] = {0, 0, GL_ZERO, GL_ONE},
436*4882a593Smuzhiyun     [PictOpOver] = {0, 1, GL_ONE, GL_ONE_MINUS_SRC_ALPHA},
437*4882a593Smuzhiyun     [PictOpOverReverse] = {1, 0, GL_ONE_MINUS_DST_ALPHA, GL_ONE},
438*4882a593Smuzhiyun     [PictOpIn] = {1, 0, GL_DST_ALPHA, GL_ZERO},
439*4882a593Smuzhiyun     [PictOpInReverse] = {0, 1, GL_ZERO, GL_SRC_ALPHA},
440*4882a593Smuzhiyun     [PictOpOut] = {1, 0, GL_ONE_MINUS_DST_ALPHA, GL_ZERO},
441*4882a593Smuzhiyun     [PictOpOutReverse] = {0, 1, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA},
442*4882a593Smuzhiyun     [PictOpAtop] = {1, 1, GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA},
443*4882a593Smuzhiyun     [PictOpAtopReverse] = {1, 1, GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA},
444*4882a593Smuzhiyun     [PictOpXor] = {1, 1, GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA},
445*4882a593Smuzhiyun     [PictOpAdd] = {0, 0, GL_ONE, GL_ONE},
446*4882a593Smuzhiyun };
447*4882a593Smuzhiyun 
448*4882a593Smuzhiyun static void
glamor_set_blend(CARD8 op,glamor_program_alpha alpha,PicturePtr dst)449*4882a593Smuzhiyun glamor_set_blend(CARD8 op, glamor_program_alpha alpha, PicturePtr dst)
450*4882a593Smuzhiyun {
451*4882a593Smuzhiyun     glamor_screen_private *glamor_priv = glamor_get_screen_private(dst->pDrawable->pScreen);
452*4882a593Smuzhiyun     GLenum src_blend, dst_blend;
453*4882a593Smuzhiyun     struct blendinfo *op_info;
454*4882a593Smuzhiyun 
455*4882a593Smuzhiyun     switch (alpha) {
456*4882a593Smuzhiyun     case glamor_program_alpha_ca_first:
457*4882a593Smuzhiyun         op = PictOpOutReverse;
458*4882a593Smuzhiyun         break;
459*4882a593Smuzhiyun     case glamor_program_alpha_ca_second:
460*4882a593Smuzhiyun         op = PictOpAdd;
461*4882a593Smuzhiyun         break;
462*4882a593Smuzhiyun     default:
463*4882a593Smuzhiyun         break;
464*4882a593Smuzhiyun     }
465*4882a593Smuzhiyun 
466*4882a593Smuzhiyun     if (!glamor_priv->is_gles)
467*4882a593Smuzhiyun         glDisable(GL_COLOR_LOGIC_OP);
468*4882a593Smuzhiyun 
469*4882a593Smuzhiyun     if (op == PictOpSrc)
470*4882a593Smuzhiyun         return;
471*4882a593Smuzhiyun 
472*4882a593Smuzhiyun     op_info = &composite_op_info[op];
473*4882a593Smuzhiyun 
474*4882a593Smuzhiyun     src_blend = op_info->source_blend;
475*4882a593Smuzhiyun     dst_blend = op_info->dest_blend;
476*4882a593Smuzhiyun 
477*4882a593Smuzhiyun     /* If there's no dst alpha channel, adjust the blend op so that we'll treat
478*4882a593Smuzhiyun      * it as always 1.
479*4882a593Smuzhiyun      */
480*4882a593Smuzhiyun     if (PICT_FORMAT_A(dst->format) == 0 && op_info->dest_alpha) {
481*4882a593Smuzhiyun         if (src_blend == GL_DST_ALPHA)
482*4882a593Smuzhiyun             src_blend = GL_ONE;
483*4882a593Smuzhiyun         else if (src_blend == GL_ONE_MINUS_DST_ALPHA)
484*4882a593Smuzhiyun             src_blend = GL_ZERO;
485*4882a593Smuzhiyun     }
486*4882a593Smuzhiyun 
487*4882a593Smuzhiyun     /* Set up the source alpha value for blending in component alpha mode. */
488*4882a593Smuzhiyun     if (alpha == glamor_program_alpha_dual_blend) {
489*4882a593Smuzhiyun         switch (dst_blend) {
490*4882a593Smuzhiyun         case GL_SRC_ALPHA:
491*4882a593Smuzhiyun             dst_blend = GL_SRC1_COLOR;
492*4882a593Smuzhiyun             break;
493*4882a593Smuzhiyun         case GL_ONE_MINUS_SRC_ALPHA:
494*4882a593Smuzhiyun             dst_blend = GL_ONE_MINUS_SRC1_COLOR;
495*4882a593Smuzhiyun             break;
496*4882a593Smuzhiyun         }
497*4882a593Smuzhiyun     } else if (alpha != glamor_program_alpha_normal) {
498*4882a593Smuzhiyun         switch (dst_blend) {
499*4882a593Smuzhiyun         case GL_SRC_ALPHA:
500*4882a593Smuzhiyun             dst_blend = GL_SRC_COLOR;
501*4882a593Smuzhiyun             break;
502*4882a593Smuzhiyun         case GL_ONE_MINUS_SRC_ALPHA:
503*4882a593Smuzhiyun             dst_blend = GL_ONE_MINUS_SRC_COLOR;
504*4882a593Smuzhiyun             break;
505*4882a593Smuzhiyun         }
506*4882a593Smuzhiyun     }
507*4882a593Smuzhiyun 
508*4882a593Smuzhiyun     glEnable(GL_BLEND);
509*4882a593Smuzhiyun     glBlendFunc(src_blend, dst_blend);
510*4882a593Smuzhiyun }
511*4882a593Smuzhiyun 
512*4882a593Smuzhiyun static Bool
use_source_solid(CARD8 op,PicturePtr src,PicturePtr dst,glamor_program * prog)513*4882a593Smuzhiyun use_source_solid(CARD8 op, PicturePtr src, PicturePtr dst, glamor_program *prog)
514*4882a593Smuzhiyun {
515*4882a593Smuzhiyun     PictSolidFill *solid = &src->pSourcePict->solidFill;
516*4882a593Smuzhiyun     float color[4];
517*4882a593Smuzhiyun 
518*4882a593Smuzhiyun     glamor_get_rgba_from_color(&solid->fullcolor, color);
519*4882a593Smuzhiyun     glamor_set_blend(op, prog->alpha, dst);
520*4882a593Smuzhiyun     glUniform4fv(prog->fg_uniform, 1, color);
521*4882a593Smuzhiyun 
522*4882a593Smuzhiyun     return TRUE;
523*4882a593Smuzhiyun }
524*4882a593Smuzhiyun 
525*4882a593Smuzhiyun static const glamor_facet glamor_source_solid = {
526*4882a593Smuzhiyun     .name = "render_solid",
527*4882a593Smuzhiyun     .fs_exec = "       vec4 source = fg;\n",
528*4882a593Smuzhiyun     .locations = glamor_program_location_fg,
529*4882a593Smuzhiyun     .use_render = use_source_solid,
530*4882a593Smuzhiyun };
531*4882a593Smuzhiyun 
532*4882a593Smuzhiyun static Bool
use_source_picture(CARD8 op,PicturePtr src,PicturePtr dst,glamor_program * prog)533*4882a593Smuzhiyun use_source_picture(CARD8 op, PicturePtr src, PicturePtr dst, glamor_program *prog)
534*4882a593Smuzhiyun {
535*4882a593Smuzhiyun     glamor_set_blend(op, prog->alpha, dst);
536*4882a593Smuzhiyun 
537*4882a593Smuzhiyun     return glamor_set_texture((PixmapPtr) src->pDrawable,
538*4882a593Smuzhiyun                               glamor_picture_red_is_alpha(dst),
539*4882a593Smuzhiyun                               0, 0,
540*4882a593Smuzhiyun                               prog->fill_offset_uniform,
541*4882a593Smuzhiyun                               prog->fill_size_inv_uniform);
542*4882a593Smuzhiyun }
543*4882a593Smuzhiyun 
544*4882a593Smuzhiyun static const glamor_facet glamor_source_picture = {
545*4882a593Smuzhiyun     .name = "render_picture",
546*4882a593Smuzhiyun     .vs_exec =  "       fill_pos = (fill_offset + primitive.xy + pos) * fill_size_inv;\n",
547*4882a593Smuzhiyun     .fs_exec =  "       vec4 source = texture2D(sampler, fill_pos);\n",
548*4882a593Smuzhiyun     .locations = glamor_program_location_fillsamp | glamor_program_location_fillpos,
549*4882a593Smuzhiyun     .use_render = use_source_picture,
550*4882a593Smuzhiyun };
551*4882a593Smuzhiyun 
552*4882a593Smuzhiyun static Bool
use_source_1x1_picture(CARD8 op,PicturePtr src,PicturePtr dst,glamor_program * prog)553*4882a593Smuzhiyun use_source_1x1_picture(CARD8 op, PicturePtr src, PicturePtr dst, glamor_program *prog)
554*4882a593Smuzhiyun {
555*4882a593Smuzhiyun     glamor_set_blend(op, prog->alpha, dst);
556*4882a593Smuzhiyun 
557*4882a593Smuzhiyun     return glamor_set_texture_pixmap((PixmapPtr) src->pDrawable,
558*4882a593Smuzhiyun                                      glamor_picture_red_is_alpha(dst));
559*4882a593Smuzhiyun }
560*4882a593Smuzhiyun 
561*4882a593Smuzhiyun static const glamor_facet glamor_source_1x1_picture = {
562*4882a593Smuzhiyun     .name = "render_picture",
563*4882a593Smuzhiyun     .fs_exec =  "       vec4 source = texture2D(sampler, vec2(0.5));\n",
564*4882a593Smuzhiyun     .locations = glamor_program_location_fillsamp,
565*4882a593Smuzhiyun     .use_render = use_source_1x1_picture,
566*4882a593Smuzhiyun };
567*4882a593Smuzhiyun 
568*4882a593Smuzhiyun static const glamor_facet *glamor_facet_source[glamor_program_source_count] = {
569*4882a593Smuzhiyun     [glamor_program_source_solid] = &glamor_source_solid,
570*4882a593Smuzhiyun     [glamor_program_source_picture] = &glamor_source_picture,
571*4882a593Smuzhiyun     [glamor_program_source_1x1_picture] = &glamor_source_1x1_picture,
572*4882a593Smuzhiyun };
573*4882a593Smuzhiyun 
574*4882a593Smuzhiyun static const char *glamor_combine[] = {
575*4882a593Smuzhiyun     [glamor_program_alpha_normal]    = "       gl_FragColor = source * mask.a;\n",
576*4882a593Smuzhiyun     [glamor_program_alpha_ca_first]  = "       gl_FragColor = source.a * mask;\n",
577*4882a593Smuzhiyun     [glamor_program_alpha_ca_second] = "       gl_FragColor = source * mask;\n",
578*4882a593Smuzhiyun     [glamor_program_alpha_dual_blend] = "      color0 = source * mask;\n"
579*4882a593Smuzhiyun                                         "      color1 = source.a * mask;\n"
580*4882a593Smuzhiyun };
581*4882a593Smuzhiyun 
582*4882a593Smuzhiyun static Bool
glamor_setup_one_program_render(ScreenPtr screen,glamor_program * prog,glamor_program_source source_type,glamor_program_alpha alpha,const glamor_facet * prim,const char * defines)583*4882a593Smuzhiyun glamor_setup_one_program_render(ScreenPtr               screen,
584*4882a593Smuzhiyun                                 glamor_program          *prog,
585*4882a593Smuzhiyun                                 glamor_program_source   source_type,
586*4882a593Smuzhiyun                                 glamor_program_alpha    alpha,
587*4882a593Smuzhiyun                                 const glamor_facet      *prim,
588*4882a593Smuzhiyun                                 const char              *defines)
589*4882a593Smuzhiyun {
590*4882a593Smuzhiyun     if (prog->failed)
591*4882a593Smuzhiyun         return FALSE;
592*4882a593Smuzhiyun 
593*4882a593Smuzhiyun     if (!prog->prog) {
594*4882a593Smuzhiyun         const glamor_facet      *fill = glamor_facet_source[source_type];
595*4882a593Smuzhiyun 
596*4882a593Smuzhiyun         if (!fill)
597*4882a593Smuzhiyun             return FALSE;
598*4882a593Smuzhiyun 
599*4882a593Smuzhiyun         prog->alpha = alpha;
600*4882a593Smuzhiyun         if (!glamor_build_program(screen, prog, prim, fill, glamor_combine[alpha], defines))
601*4882a593Smuzhiyun             return FALSE;
602*4882a593Smuzhiyun     }
603*4882a593Smuzhiyun 
604*4882a593Smuzhiyun     return TRUE;
605*4882a593Smuzhiyun }
606*4882a593Smuzhiyun 
607*4882a593Smuzhiyun glamor_program *
glamor_setup_program_render(CARD8 op,PicturePtr src,PicturePtr mask,PicturePtr dst,glamor_program_render * program_render,const glamor_facet * prim,const char * defines)608*4882a593Smuzhiyun glamor_setup_program_render(CARD8                 op,
609*4882a593Smuzhiyun                             PicturePtr            src,
610*4882a593Smuzhiyun                             PicturePtr            mask,
611*4882a593Smuzhiyun                             PicturePtr            dst,
612*4882a593Smuzhiyun                             glamor_program_render *program_render,
613*4882a593Smuzhiyun                             const glamor_facet    *prim,
614*4882a593Smuzhiyun                             const char            *defines)
615*4882a593Smuzhiyun {
616*4882a593Smuzhiyun     ScreenPtr                   screen = dst->pDrawable->pScreen;
617*4882a593Smuzhiyun     glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
618*4882a593Smuzhiyun     glamor_program_alpha        alpha;
619*4882a593Smuzhiyun     glamor_program_source       source_type;
620*4882a593Smuzhiyun     glamor_program              *prog;
621*4882a593Smuzhiyun 
622*4882a593Smuzhiyun     if (op > ARRAY_SIZE(composite_op_info))
623*4882a593Smuzhiyun         return NULL;
624*4882a593Smuzhiyun 
625*4882a593Smuzhiyun     if (glamor_is_component_alpha(mask)) {
626*4882a593Smuzhiyun         if (glamor_priv->has_dual_blend) {
627*4882a593Smuzhiyun             alpha = glamor_program_alpha_dual_blend;
628*4882a593Smuzhiyun         } else {
629*4882a593Smuzhiyun             /* This only works for PictOpOver */
630*4882a593Smuzhiyun             if (op != PictOpOver)
631*4882a593Smuzhiyun                 return NULL;
632*4882a593Smuzhiyun 
633*4882a593Smuzhiyun             alpha = glamor_program_alpha_ca_first;
634*4882a593Smuzhiyun         }
635*4882a593Smuzhiyun     } else
636*4882a593Smuzhiyun         alpha = glamor_program_alpha_normal;
637*4882a593Smuzhiyun 
638*4882a593Smuzhiyun     if (src->pDrawable) {
639*4882a593Smuzhiyun 
640*4882a593Smuzhiyun         /* Can't do transforms, alphamaps or sourcing from non-pixmaps yet */
641*4882a593Smuzhiyun         if (src->transform || src->alphaMap || src->pDrawable->type != DRAWABLE_PIXMAP)
642*4882a593Smuzhiyun             return NULL;
643*4882a593Smuzhiyun 
644*4882a593Smuzhiyun         if (src->pDrawable->width == 1 && src->pDrawable->height == 1 && src->repeat)
645*4882a593Smuzhiyun             source_type = glamor_program_source_1x1_picture;
646*4882a593Smuzhiyun         else
647*4882a593Smuzhiyun             source_type = glamor_program_source_picture;
648*4882a593Smuzhiyun     } else {
649*4882a593Smuzhiyun         SourcePictPtr   sp = src->pSourcePict;
650*4882a593Smuzhiyun         if (!sp)
651*4882a593Smuzhiyun             return NULL;
652*4882a593Smuzhiyun         switch (sp->type) {
653*4882a593Smuzhiyun         case SourcePictTypeSolidFill:
654*4882a593Smuzhiyun             source_type = glamor_program_source_solid;
655*4882a593Smuzhiyun             break;
656*4882a593Smuzhiyun         default:
657*4882a593Smuzhiyun             return NULL;
658*4882a593Smuzhiyun         }
659*4882a593Smuzhiyun     }
660*4882a593Smuzhiyun 
661*4882a593Smuzhiyun     prog = &program_render->progs[source_type][alpha];
662*4882a593Smuzhiyun     if (!glamor_setup_one_program_render(screen, prog, source_type, alpha, prim, defines))
663*4882a593Smuzhiyun         return NULL;
664*4882a593Smuzhiyun 
665*4882a593Smuzhiyun     if (alpha == glamor_program_alpha_ca_first) {
666*4882a593Smuzhiyun 
667*4882a593Smuzhiyun 	  /* Make sure we can also build the second program before
668*4882a593Smuzhiyun 	   * deciding to use this path.
669*4882a593Smuzhiyun 	   */
670*4882a593Smuzhiyun 	  if (!glamor_setup_one_program_render(screen,
671*4882a593Smuzhiyun 					       &program_render->progs[source_type][glamor_program_alpha_ca_second],
672*4882a593Smuzhiyun 					       source_type, glamor_program_alpha_ca_second, prim,
673*4882a593Smuzhiyun 					       defines))
674*4882a593Smuzhiyun 	      return NULL;
675*4882a593Smuzhiyun     }
676*4882a593Smuzhiyun     return prog;
677*4882a593Smuzhiyun }
678*4882a593Smuzhiyun 
679*4882a593Smuzhiyun Bool
glamor_use_program_render(glamor_program * prog,CARD8 op,PicturePtr src,PicturePtr dst)680*4882a593Smuzhiyun glamor_use_program_render(glamor_program        *prog,
681*4882a593Smuzhiyun                           CARD8                 op,
682*4882a593Smuzhiyun                           PicturePtr            src,
683*4882a593Smuzhiyun                           PicturePtr            dst)
684*4882a593Smuzhiyun {
685*4882a593Smuzhiyun     glUseProgram(prog->prog);
686*4882a593Smuzhiyun 
687*4882a593Smuzhiyun     if (prog->prim_use_render && !prog->prim_use_render(op, src, dst, prog))
688*4882a593Smuzhiyun         return FALSE;
689*4882a593Smuzhiyun 
690*4882a593Smuzhiyun     if (prog->fill_use_render && !prog->fill_use_render(op, src, dst, prog))
691*4882a593Smuzhiyun         return FALSE;
692*4882a593Smuzhiyun     return TRUE;
693*4882a593Smuzhiyun }
694