~ubuntu-branches/ubuntu/trusty/xorg-server-lts-utopic/trusty-proposed

« back to all changes in this revision

Viewing changes to glamor/glamor_program.c

  • Committer: Package Import Robot
  • Author(s): Maarten Lankhorst
  • Date: 2015-01-22 10:01:57 UTC
  • Revision ID: package-import@ubuntu.com-20150122100157-3zdz5pof8z66kbmp
Tags: upstream-1.16.0
ImportĀ upstreamĀ versionĀ 1.16.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright Ā© 2014 Keith Packard
 
3
 *
 
4
 * Permission to use, copy, modify, distribute, and sell this software and its
 
5
 * documentation for any purpose is hereby granted without fee, provided that
 
6
 * the above copyright notice appear in all copies and that both that copyright
 
7
 * notice and this permission notice appear in supporting documentation, and
 
8
 * that the name of the copyright holders not be used in advertising or
 
9
 * publicity pertaining to distribution of the software without specific,
 
10
 * written prior permission.  The copyright holders make no representations
 
11
 * about the suitability of this software for any purpose.  It is provided "as
 
12
 * is" without express or implied warranty.
 
13
 *
 
14
 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 
15
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
 
16
 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
 
17
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
 
18
 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
 
19
 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
 
20
 * OF THIS SOFTWARE.
 
21
 */
 
22
 
 
23
#include "glamor_priv.h"
 
24
#include "glamor_transform.h"
 
25
#include "glamor_program.h"
 
26
 
 
27
static Bool
 
28
use_solid(PixmapPtr pixmap, GCPtr gc, glamor_program *prog, void *arg)
 
29
{
 
30
    return glamor_set_solid(pixmap, gc, TRUE, prog->fg_uniform);
 
31
}
 
32
 
 
33
const glamor_facet glamor_fill_solid = {
 
34
    .name = "solid",
 
35
    .fs_exec = "       gl_FragColor = fg;\n",
 
36
    .locations = glamor_program_location_fg,
 
37
    .use = use_solid,
 
38
};
 
39
 
 
40
static Bool
 
41
use_tile(PixmapPtr pixmap, GCPtr gc, glamor_program *prog, void *arg)
 
42
{
 
43
    return glamor_set_tiled(pixmap, gc, prog->fill_offset_uniform, prog->fill_size_uniform);
 
44
}
 
45
 
 
46
static const glamor_facet glamor_fill_tile = {
 
47
    .name = "tile",
 
48
    .vs_exec =  "       fill_pos = (fill_offset + primitive.xy + pos) / fill_size;\n",
 
49
    .fs_exec =  "       gl_FragColor = texture2D(sampler, fill_pos);\n",
 
50
    .locations = glamor_program_location_fill,
 
51
    .use = use_tile,
 
52
};
 
53
 
 
54
#if 0
 
55
static Bool
 
56
use_stipple(PixmapPtr pixmap, GCPtr gc, glamor_program *prog)
 
57
{
 
58
    return glamor_set_stippled(pixmap, gc, prog->fg_uniform, prog->fill_offset_uniform, prog->fill_size_uniform);
 
59
}
 
60
 
 
61
static const glamor_facet glamor_fill_stipple = {
 
62
    .name = "stipple",
 
63
    .version = 130,
 
64
    .vs_exec =  "       fill_pos = fill_offset + primitive.xy + pos;\n";
 
65
    .fs_exec = ("       if (texelFetch(sampler, ivec2(mod(fill_pos,fill_size)), 0).x == 0)\n"
 
66
                "               discard;\n"
 
67
                "       gl_FragColor = fg;\n")
 
68
    .locations = glamor_program_location_fg | glamor_program_location_fill
 
69
    .use = use_stipple,
 
70
};
 
71
 
 
72
static const glamor_facet glamor_fill_opaque_stipple = {
 
73
    .name = "opaque_stipple",
 
74
    .version = 130,
 
75
    .vs_exec =  "       fill_pos = fill_offset + primitive.xy + pos;\n";
 
76
    .fs_exec = ("       if (texelFetch(sampler, ivec2(mod(fill_pos,fill_size)), 0).x == 0)\n"
 
77
                "               gl_FragColor = bg;\n"
 
78
                "       else\n"
 
79
                "               gl_FragColor = fg;\n"),
 
80
    .locations = glamor_program_location_fg | glamor_program_location_bg | glamor_program_location_fill
 
81
    .use = use_opaque_stipple
 
82
};
 
83
#endif
 
84
 
 
85
static const glamor_facet *glamor_facet_fill[4] = {
 
86
    &glamor_fill_solid,
 
87
    &glamor_fill_tile,
 
88
    NULL,
 
89
    NULL,
 
90
};
 
91
 
 
92
typedef struct {
 
93
    glamor_program_location     location;
 
94
    const char                  *vs_vars;
 
95
    const char                  *fs_vars;
 
96
} glamor_location_var;
 
97
 
 
98
static glamor_location_var location_vars[] = {
 
99
    {
 
100
        .location = glamor_program_location_fg,
 
101
        .fs_vars = "uniform vec4 fg;\n"
 
102
    },
 
103
    {
 
104
        .location = glamor_program_location_bg,
 
105
        .fs_vars = "uniform vec4 bg;\n"
 
106
    },
 
107
    {
 
108
        .location = glamor_program_location_fill,
 
109
        .vs_vars = ("uniform vec2 fill_offset;\n"
 
110
                    "uniform vec2 fill_size;\n"
 
111
                    "varying vec2 fill_pos;\n"),
 
112
        .fs_vars = ("uniform sampler2D sampler;\n"
 
113
                    "uniform vec2 fill_size;\n"
 
114
                    "varying vec2 fill_pos;\n")
 
115
    },
 
116
    {
 
117
        .location = glamor_program_location_font,
 
118
        .fs_vars = "uniform usampler2D font;\n",
 
119
    },
 
120
};
 
121
 
 
122
#define NUM_LOCATION_VARS       (sizeof location_vars / sizeof location_vars[0])
 
123
 
 
124
static char *
 
125
add_var(char *cur, const char *add)
 
126
{
 
127
    char *new;
 
128
 
 
129
    if (!add)
 
130
        return cur;
 
131
 
 
132
    new = realloc(cur, strlen(cur) + strlen(add) + 1);
 
133
    if (!new) {
 
134
        free(cur);
 
135
        return NULL;
 
136
    }
 
137
    strcat(new, add);
 
138
    return new;
 
139
}
 
140
 
 
141
static char *
 
142
vs_location_vars(glamor_program_location locations)
 
143
{
 
144
    int l;
 
145
    char *vars = strdup("");
 
146
 
 
147
    for (l = 0; vars && l < NUM_LOCATION_VARS; l++)
 
148
        if (locations & location_vars[l].location)
 
149
            vars = add_var(vars, location_vars[l].vs_vars);
 
150
    return vars;
 
151
}
 
152
 
 
153
static char *
 
154
fs_location_vars(glamor_program_location locations)
 
155
{
 
156
    int l;
 
157
    char *vars = strdup("");
 
158
 
 
159
    for (l = 0; vars && l < NUM_LOCATION_VARS; l++)
 
160
        if (locations & location_vars[l].location)
 
161
            vars = add_var(vars, location_vars[l].fs_vars);
 
162
    return vars;
 
163
}
 
164
 
 
165
static const char vs_template[] =
 
166
    "%s"                                /* version */
 
167
    "%s"                                /* prim vs_vars */
 
168
    "%s"                                /* fill vs_vars */
 
169
    "%s"                                /* location vs_vars */
 
170
    GLAMOR_DECLARE_MATRIX
 
171
    "void main() {\n"
 
172
    "%s"                                /* prim vs_exec, outputs 'pos' and gl_Position */
 
173
    "%s"                                /* fill vs_exec */
 
174
    "}\n";
 
175
 
 
176
static const char fs_template[] =
 
177
    "%s"                                /* version */
 
178
    GLAMOR_DEFAULT_PRECISION
 
179
    "%s"                                /* prim fs_vars */
 
180
    "%s"                                /* fill fs_vars */
 
181
    "%s"                                /* location fs_vars */
 
182
    "void main() {\n"
 
183
    "%s"                                /* prim fs_exec */
 
184
    "%s"                                /* fill fs_exec */
 
185
    "}\n";
 
186
 
 
187
static const char *
 
188
str(const char *s)
 
189
{
 
190
    if (!s)
 
191
        return "";
 
192
    return s;
 
193
}
 
194
 
 
195
static const glamor_facet facet_null_fill = {
 
196
    .name = ""
 
197
};
 
198
 
 
199
static GLint
 
200
glamor_get_uniform(glamor_program               *prog,
 
201
                   glamor_program_location      location,
 
202
                   const char                   *name)
 
203
{
 
204
    GLint uniform;
 
205
    if (location && (prog->locations & location) == 0)
 
206
        return -2;
 
207
    uniform = glGetUniformLocation(prog->prog, name);
 
208
#if DBG
 
209
    ErrorF("%s uniform %d\n", name, uniform);
 
210
#endif
 
211
    return uniform;
 
212
}
 
213
 
 
214
Bool
 
215
glamor_build_program(ScreenPtr          screen,
 
216
                     glamor_program     *prog,
 
217
                     const glamor_facet *prim,
 
218
                     const glamor_facet *fill)
 
219
{
 
220
    glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
 
221
 
 
222
    glamor_program_location     locations = prim->locations;
 
223
    glamor_program_flag         flags = prim->flags;
 
224
 
 
225
    int                         version = prim->version;
 
226
    char                        *version_string = NULL;
 
227
 
 
228
    char                        *fs_vars = NULL;
 
229
    char                        *vs_vars = NULL;
 
230
 
 
231
    char                        *vs_prog_string;
 
232
    char                        *fs_prog_string;
 
233
 
 
234
    GLint                       fs_prog, vs_prog;
 
235
 
 
236
    if (!fill)
 
237
        fill = &facet_null_fill;
 
238
 
 
239
    locations |= fill->locations;
 
240
    flags |= fill->flags;
 
241
    version = MAX(version, fill->version);
 
242
 
 
243
    if (version > glamor_priv->glsl_version)
 
244
        goto fail;
 
245
 
 
246
    vs_vars = vs_location_vars(locations);
 
247
    fs_vars = fs_location_vars(locations);
 
248
 
 
249
    if (!vs_vars)
 
250
        goto fail;
 
251
    if (!fs_vars)
 
252
        goto fail;
 
253
 
 
254
    if (version) {
 
255
        if (asprintf(&version_string, "#version %d\n", version) < 0)
 
256
            version_string = NULL;
 
257
        if (!version_string)
 
258
            goto fail;
 
259
    }
 
260
 
 
261
    if (asprintf(&vs_prog_string,
 
262
                 vs_template,
 
263
                 str(version_string),
 
264
                 str(prim->vs_vars),
 
265
                 str(fill->vs_vars),
 
266
                 vs_vars,
 
267
                 str(prim->vs_exec),
 
268
                 str(fill->vs_exec)) < 0)
 
269
        vs_prog_string = NULL;
 
270
 
 
271
    if (asprintf(&fs_prog_string,
 
272
                 fs_template,
 
273
                 str(version_string),
 
274
                 str(prim->fs_vars),
 
275
                 str(fill->fs_vars),
 
276
                 fs_vars,
 
277
                 str(prim->fs_exec),
 
278
                 str(fill->fs_exec)) < 0)
 
279
        fs_prog_string = NULL;
 
280
 
 
281
    if (!vs_prog_string || !fs_prog_string)
 
282
        goto fail;
 
283
 
 
284
#define DBG 0
 
285
#if DBG
 
286
    ErrorF("\nPrograms for %s %s\nVertex shader:\n\n%s\n\nFragment Shader:\n\n%s",
 
287
           prim->name, fill->name, vs_prog_string, fs_prog_string);
 
288
#endif
 
289
 
 
290
    prog->prog = glCreateProgram();
 
291
    prog->flags = flags;
 
292
    prog->locations = locations;
 
293
    prog->prim_use = prim->use;
 
294
    prog->fill_use = fill->use;
 
295
 
 
296
    vs_prog = glamor_compile_glsl_prog(GL_VERTEX_SHADER, vs_prog_string);
 
297
    fs_prog = glamor_compile_glsl_prog(GL_FRAGMENT_SHADER, fs_prog_string);
 
298
    free(vs_prog_string);
 
299
    free(fs_prog_string);
 
300
    glAttachShader(prog->prog, vs_prog);
 
301
    glDeleteShader(vs_prog);
 
302
    glAttachShader(prog->prog, fs_prog);
 
303
    glDeleteShader(fs_prog);
 
304
    glBindAttribLocation(prog->prog, GLAMOR_VERTEX_POS, "primitive");
 
305
 
 
306
    if (prim->source_name) {
 
307
#if DBG
 
308
        ErrorF("Bind GLAMOR_VERTEX_SOURCE to %s\n", prim->source_name);
 
309
#endif
 
310
        glBindAttribLocation(prog->prog, GLAMOR_VERTEX_SOURCE, prim->source_name);
 
311
    }
 
312
 
 
313
    glamor_link_glsl_prog(screen, prog->prog, "%s_%s", prim->name, fill->name);
 
314
 
 
315
    prog->matrix_uniform = glamor_get_uniform(prog, glamor_program_location_none, "v_matrix");
 
316
    prog->fg_uniform = glamor_get_uniform(prog, glamor_program_location_fg, "fg");
 
317
    prog->bg_uniform = glamor_get_uniform(prog, glamor_program_location_bg, "bg");
 
318
    prog->fill_offset_uniform = glamor_get_uniform(prog, glamor_program_location_fill, "fill_offset");
 
319
    prog->fill_size_uniform = glamor_get_uniform(prog, glamor_program_location_fill, "fill_size");
 
320
    prog->font_uniform = glamor_get_uniform(prog, glamor_program_location_font, "font");
 
321
 
 
322
    if (glGetError() != GL_NO_ERROR)
 
323
        goto fail;
 
324
 
 
325
    free(version_string);
 
326
    free(fs_vars);
 
327
    free(vs_vars);
 
328
    return TRUE;
 
329
fail:
 
330
    prog->failed = 1;
 
331
    if (prog->prog) {
 
332
        glDeleteProgram(prog->prog);
 
333
        prog->prog = 0;
 
334
    }
 
335
    free(version_string);
 
336
    free(fs_vars);
 
337
    free(vs_vars);
 
338
    return FALSE;
 
339
}
 
340
 
 
341
Bool
 
342
glamor_use_program(PixmapPtr            pixmap,
 
343
                   GCPtr                gc,
 
344
                   glamor_program       *prog,
 
345
                   void                 *arg)
 
346
{
 
347
    glUseProgram(prog->prog);
 
348
 
 
349
    if (prog->prim_use && !prog->prim_use(pixmap, gc, prog, arg))
 
350
        return FALSE;
 
351
 
 
352
    if (prog->fill_use && !prog->fill_use(pixmap, gc, prog, arg))
 
353
        return FALSE;
 
354
 
 
355
    return TRUE;
 
356
}
 
357
 
 
358
glamor_program *
 
359
glamor_use_program_fill(PixmapPtr               pixmap,
 
360
                        GCPtr                   gc,
 
361
                        glamor_program_fill     *program_fill,
 
362
                        const glamor_facet      *prim)
 
363
{
 
364
    ScreenPtr                   screen = pixmap->drawable.pScreen;
 
365
    glamor_program              *prog = &program_fill->progs[gc->fillStyle];
 
366
 
 
367
    int                         fill_style = gc->fillStyle;
 
368
    const glamor_facet          *fill;
 
369
 
 
370
    if (prog->failed)
 
371
        return FALSE;
 
372
 
 
373
    if (!prog->prog) {
 
374
        fill = glamor_facet_fill[fill_style];
 
375
        if (!fill)
 
376
            return NULL;
 
377
 
 
378
        if (!glamor_build_program(screen, prog, prim, fill))
 
379
            return NULL;
 
380
    }
 
381
 
 
382
    if (!glamor_use_program(pixmap, gc, prog, NULL))
 
383
        return NULL;
 
384
 
 
385
    return prog;
 
386
}