123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387 |
- /*
- * Copyright © 2014 Keith Packard
- *
- * Permission to use, copy, modify, distribute, and sell this software and its
- * documentation for any purpose is hereby granted without fee, provided that
- * the above copyright notice appear in all copies and that both that copyright
- * notice and this permission notice appear in supporting documentation, and
- * that the name of the copyright holders not be used in advertising or
- * publicity pertaining to distribution of the software without specific,
- * written prior permission. The copyright holders make no representations
- * about the suitability of this software for any purpose. It is provided "as
- * is" without express or implied warranty.
- *
- * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
- * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
- * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
- * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
- * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
- * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
- * OF THIS SOFTWARE.
- */
- #include "glamor_priv.h"
- #include "glamor_transform.h"
- #include "glamor_program.h"
- static Bool
- use_solid(PixmapPtr pixmap, GCPtr gc, glamor_program *prog, void *arg)
- {
- return glamor_set_solid(pixmap, gc, TRUE, prog->fg_uniform);
- }
- const glamor_facet glamor_fill_solid = {
- .name = "solid",
- .fs_exec = " gl_FragColor = fg;\n",
- .locations = glamor_program_location_fg,
- .use = use_solid,
- };
- static Bool
- use_tile(PixmapPtr pixmap, GCPtr gc, glamor_program *prog, void *arg)
- {
- return glamor_set_tiled(pixmap, gc, prog->fill_offset_uniform, prog->fill_size_uniform);
- }
- static const glamor_facet glamor_fill_tile = {
- .name = "tile",
- .vs_exec = " fill_pos = (fill_offset + primitive.xy + pos) / fill_size;\n",
- .fs_exec = " gl_FragColor = texture2D(sampler, fill_pos);\n",
- .locations = glamor_program_location_fill,
- .use = use_tile,
- };
- #if 0
- static Bool
- use_stipple(PixmapPtr pixmap, GCPtr gc, glamor_program *prog)
- {
- return glamor_set_stippled(pixmap, gc, prog->fg_uniform, prog->fill_offset_uniform, prog->fill_size_uniform);
- }
- static const glamor_facet glamor_fill_stipple = {
- .name = "stipple",
- .version = 130,
- .vs_exec = " fill_pos = fill_offset + primitive.xy + pos;\n";
- .fs_exec = (" if (texelFetch(sampler, ivec2(mod(fill_pos,fill_size)), 0).x == 0)\n"
- " discard;\n"
- " gl_FragColor = fg;\n")
- .locations = glamor_program_location_fg | glamor_program_location_fill
- .use = use_stipple,
- };
- static const glamor_facet glamor_fill_opaque_stipple = {
- .name = "opaque_stipple",
- .version = 130,
- .vs_exec = " fill_pos = fill_offset + primitive.xy + pos;\n";
- .fs_exec = (" if (texelFetch(sampler, ivec2(mod(fill_pos,fill_size)), 0).x == 0)\n"
- " gl_FragColor = bg;\n"
- " else\n"
- " gl_FragColor = fg;\n"),
- .locations = glamor_program_location_fg | glamor_program_location_bg | glamor_program_location_fill
- .use = use_opaque_stipple
- };
- #endif
- static const glamor_facet *glamor_facet_fill[4] = {
- &glamor_fill_solid,
- &glamor_fill_tile,
- NULL,
- NULL,
- };
- typedef struct {
- glamor_program_location location;
- const char *vs_vars;
- const char *fs_vars;
- } glamor_location_var;
- static glamor_location_var location_vars[] = {
- {
- .location = glamor_program_location_fg,
- .fs_vars = "uniform vec4 fg;\n"
- },
- {
- .location = glamor_program_location_bg,
- .fs_vars = "uniform vec4 bg;\n"
- },
- {
- .location = glamor_program_location_fill,
- .vs_vars = ("uniform vec2 fill_offset;\n"
- "uniform vec2 fill_size;\n"
- "varying vec2 fill_pos;\n"),
- .fs_vars = ("uniform sampler2D sampler;\n"
- "uniform vec2 fill_size;\n"
- "varying vec2 fill_pos;\n")
- },
- {
- .location = glamor_program_location_font,
- .fs_vars = "uniform usampler2D font;\n",
- },
- };
- #define NUM_LOCATION_VARS (sizeof location_vars / sizeof location_vars[0])
- static char *
- add_var(char *cur, const char *add)
- {
- char *new;
- if (!add)
- return cur;
- new = realloc(cur, strlen(cur) + strlen(add) + 1);
- if (!new) {
- free(cur);
- return NULL;
- }
- strcat(new, add);
- return new;
- }
- static char *
- vs_location_vars(glamor_program_location locations)
- {
- int l;
- char *vars = strdup("");
- for (l = 0; vars && l < NUM_LOCATION_VARS; l++)
- if (locations & location_vars[l].location)
- vars = add_var(vars, location_vars[l].vs_vars);
- return vars;
- }
- static char *
- fs_location_vars(glamor_program_location locations)
- {
- int l;
- char *vars = strdup("");
- for (l = 0; vars && l < NUM_LOCATION_VARS; l++)
- if (locations & location_vars[l].location)
- vars = add_var(vars, location_vars[l].fs_vars);
- return vars;
- }
- static const char vs_template[] =
- "%s" /* version */
- "%s" /* prim vs_vars */
- "%s" /* fill vs_vars */
- "%s" /* location vs_vars */
- GLAMOR_DECLARE_MATRIX
- "void main() {\n"
- "%s" /* prim vs_exec, outputs 'pos' and gl_Position */
- "%s" /* fill vs_exec */
- "}\n";
- static const char fs_template[] =
- "%s" /* version */
- GLAMOR_DEFAULT_PRECISION
- "%s" /* prim fs_vars */
- "%s" /* fill fs_vars */
- "%s" /* location fs_vars */
- "void main() {\n"
- "%s" /* prim fs_exec */
- "%s" /* fill fs_exec */
- "}\n";
- static const char *
- str(const char *s)
- {
- if (!s)
- return "";
- return s;
- }
- static const glamor_facet facet_null_fill = {
- .name = ""
- };
- static GLint
- glamor_get_uniform(glamor_program *prog,
- glamor_program_location location,
- const char *name)
- {
- GLint uniform;
- if (location && (prog->locations & location) == 0)
- return -2;
- uniform = glGetUniformLocation(prog->prog, name);
- #if DBG
- ErrorF("%s uniform %d\n", name, uniform);
- #endif
- return uniform;
- }
- Bool
- glamor_build_program(ScreenPtr screen,
- glamor_program *prog,
- const glamor_facet *prim,
- const glamor_facet *fill)
- {
- glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
- glamor_program_location locations = prim->locations;
- glamor_program_flag flags = prim->flags;
- int version = prim->version;
- char *version_string = NULL;
- char *fs_vars = NULL;
- char *vs_vars = NULL;
- char *vs_prog_string;
- char *fs_prog_string;
- GLint fs_prog, vs_prog;
- if (!fill)
- fill = &facet_null_fill;
- locations |= fill->locations;
- flags |= fill->flags;
- version = MAX(version, fill->version);
- if (version > glamor_priv->glsl_version)
- goto fail;
- vs_vars = vs_location_vars(locations);
- fs_vars = fs_location_vars(locations);
- if (!vs_vars)
- goto fail;
- if (!fs_vars)
- goto fail;
- if (version) {
- if (asprintf(&version_string, "#version %d\n", version) < 0)
- version_string = NULL;
- if (!version_string)
- goto fail;
- }
- if (asprintf(&vs_prog_string,
- vs_template,
- str(version_string),
- str(prim->vs_vars),
- str(fill->vs_vars),
- vs_vars,
- str(prim->vs_exec),
- str(fill->vs_exec)) < 0)
- vs_prog_string = NULL;
- if (asprintf(&fs_prog_string,
- fs_template,
- str(version_string),
- str(prim->fs_vars),
- str(fill->fs_vars),
- fs_vars,
- str(prim->fs_exec),
- str(fill->fs_exec)) < 0)
- fs_prog_string = NULL;
- if (!vs_prog_string || !fs_prog_string)
- goto fail;
- #define DBG 0
- #if DBG
- ErrorF("\nPrograms for %s %s\nVertex shader:\n\n%s\n\nFragment Shader:\n\n%s",
- prim->name, fill->name, vs_prog_string, fs_prog_string);
- #endif
- prog->prog = glCreateProgram();
- prog->flags = flags;
- prog->locations = locations;
- prog->prim_use = prim->use;
- prog->fill_use = fill->use;
- vs_prog = glamor_compile_glsl_prog(GL_VERTEX_SHADER, vs_prog_string);
- fs_prog = glamor_compile_glsl_prog(GL_FRAGMENT_SHADER, fs_prog_string);
- free(vs_prog_string);
- free(fs_prog_string);
- glAttachShader(prog->prog, vs_prog);
- glDeleteShader(vs_prog);
- glAttachShader(prog->prog, fs_prog);
- glDeleteShader(fs_prog);
- glBindAttribLocation(prog->prog, GLAMOR_VERTEX_POS, "primitive");
- if (prim->source_name) {
- #if DBG
- ErrorF("Bind GLAMOR_VERTEX_SOURCE to %s\n", prim->source_name);
- #endif
- glBindAttribLocation(prog->prog, GLAMOR_VERTEX_SOURCE, prim->source_name);
- }
- glamor_link_glsl_prog(screen, prog->prog, "%s_%s", prim->name, fill->name);
- prog->matrix_uniform = glamor_get_uniform(prog, glamor_program_location_none, "v_matrix");
- prog->fg_uniform = glamor_get_uniform(prog, glamor_program_location_fg, "fg");
- prog->bg_uniform = glamor_get_uniform(prog, glamor_program_location_bg, "bg");
- prog->fill_offset_uniform = glamor_get_uniform(prog, glamor_program_location_fill, "fill_offset");
- prog->fill_size_uniform = glamor_get_uniform(prog, glamor_program_location_fill, "fill_size");
- prog->font_uniform = glamor_get_uniform(prog, glamor_program_location_font, "font");
- if (glGetError() != GL_NO_ERROR)
- goto fail;
- free(version_string);
- free(fs_vars);
- free(vs_vars);
- return TRUE;
- fail:
- prog->failed = 1;
- if (prog->prog) {
- glDeleteProgram(prog->prog);
- prog->prog = 0;
- }
- free(version_string);
- free(fs_vars);
- free(vs_vars);
- return FALSE;
- }
- Bool
- glamor_use_program(PixmapPtr pixmap,
- GCPtr gc,
- glamor_program *prog,
- void *arg)
- {
- glUseProgram(prog->prog);
- if (prog->prim_use && !prog->prim_use(pixmap, gc, prog, arg))
- return FALSE;
- if (prog->fill_use && !prog->fill_use(pixmap, gc, prog, arg))
- return FALSE;
- return TRUE;
- }
- glamor_program *
- glamor_use_program_fill(PixmapPtr pixmap,
- GCPtr gc,
- glamor_program_fill *program_fill,
- const glamor_facet *prim)
- {
- ScreenPtr screen = pixmap->drawable.pScreen;
- glamor_program *prog = &program_fill->progs[gc->fillStyle];
- int fill_style = gc->fillStyle;
- const glamor_facet *fill;
- if (prog->failed)
- return FALSE;
- if (!prog->prog) {
- fill = glamor_facet_fill[fill_style];
- if (!fill)
- return NULL;
- if (!glamor_build_program(screen, prog, prim, fill))
- return NULL;
- }
- if (!glamor_use_program(pixmap, gc, prog, NULL))
- return NULL;
- return prog;
- }
|