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