glamor_program.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387
  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. #include "glamor_priv.h"
  23. #include "glamor_transform.h"
  24. #include "glamor_program.h"
  25. static Bool
  26. use_solid(PixmapPtr pixmap, GCPtr gc, glamor_program *prog, void *arg)
  27. {
  28. return glamor_set_solid(pixmap, gc, TRUE, prog->fg_uniform);
  29. }
  30. const glamor_facet glamor_fill_solid = {
  31. .name = "solid",
  32. .fs_exec = " gl_FragColor = fg;\n",
  33. .locations = glamor_program_location_fg,
  34. .use = use_solid,
  35. };
  36. static Bool
  37. use_tile(PixmapPtr pixmap, GCPtr gc, glamor_program *prog, void *arg)
  38. {
  39. return glamor_set_tiled(pixmap, gc, prog->fill_offset_uniform, prog->fill_size_uniform);
  40. }
  41. static const glamor_facet glamor_fill_tile = {
  42. .name = "tile",
  43. .vs_exec = " fill_pos = (fill_offset + primitive.xy + pos) / fill_size;\n",
  44. .fs_exec = " gl_FragColor = texture2D(sampler, fill_pos);\n",
  45. .locations = glamor_program_location_fill,
  46. .use = use_tile,
  47. };
  48. #if 0
  49. static Bool
  50. use_stipple(PixmapPtr pixmap, GCPtr gc, glamor_program *prog)
  51. {
  52. return glamor_set_stippled(pixmap, gc, prog->fg_uniform, prog->fill_offset_uniform, prog->fill_size_uniform);
  53. }
  54. static const glamor_facet glamor_fill_stipple = {
  55. .name = "stipple",
  56. .version = 130,
  57. .vs_exec = " fill_pos = fill_offset + primitive.xy + pos;\n";
  58. .fs_exec = (" if (texelFetch(sampler, ivec2(mod(fill_pos,fill_size)), 0).x == 0)\n"
  59. " discard;\n"
  60. " gl_FragColor = fg;\n")
  61. .locations = glamor_program_location_fg | glamor_program_location_fill
  62. .use = use_stipple,
  63. };
  64. static const glamor_facet glamor_fill_opaque_stipple = {
  65. .name = "opaque_stipple",
  66. .version = 130,
  67. .vs_exec = " fill_pos = fill_offset + primitive.xy + pos;\n";
  68. .fs_exec = (" if (texelFetch(sampler, ivec2(mod(fill_pos,fill_size)), 0).x == 0)\n"
  69. " gl_FragColor = bg;\n"
  70. " else\n"
  71. " gl_FragColor = fg;\n"),
  72. .locations = glamor_program_location_fg | glamor_program_location_bg | glamor_program_location_fill
  73. .use = use_opaque_stipple
  74. };
  75. #endif
  76. static const glamor_facet *glamor_facet_fill[4] = {
  77. &glamor_fill_solid,
  78. &glamor_fill_tile,
  79. NULL,
  80. NULL,
  81. };
  82. typedef struct {
  83. glamor_program_location location;
  84. const char *vs_vars;
  85. const char *fs_vars;
  86. } glamor_location_var;
  87. static glamor_location_var location_vars[] = {
  88. {
  89. .location = glamor_program_location_fg,
  90. .fs_vars = "uniform vec4 fg;\n"
  91. },
  92. {
  93. .location = glamor_program_location_bg,
  94. .fs_vars = "uniform vec4 bg;\n"
  95. },
  96. {
  97. .location = glamor_program_location_fill,
  98. .vs_vars = ("uniform vec2 fill_offset;\n"
  99. "uniform vec2 fill_size;\n"
  100. "varying vec2 fill_pos;\n"),
  101. .fs_vars = ("uniform sampler2D sampler;\n"
  102. "uniform vec2 fill_size;\n"
  103. "varying vec2 fill_pos;\n")
  104. },
  105. {
  106. .location = glamor_program_location_font,
  107. .fs_vars = "uniform usampler2D font;\n",
  108. },
  109. };
  110. #define NUM_LOCATION_VARS (sizeof location_vars / sizeof location_vars[0])
  111. static char *
  112. add_var(char *cur, const char *add)
  113. {
  114. char *new;
  115. if (!add)
  116. return cur;
  117. new = realloc(cur, strlen(cur) + strlen(add) + 1);
  118. if (!new) {
  119. free(cur);
  120. return NULL;
  121. }
  122. strcat(new, add);
  123. return new;
  124. }
  125. static char *
  126. vs_location_vars(glamor_program_location locations)
  127. {
  128. int l;
  129. char *vars = strdup("");
  130. for (l = 0; vars && l < NUM_LOCATION_VARS; l++)
  131. if (locations & location_vars[l].location)
  132. vars = add_var(vars, location_vars[l].vs_vars);
  133. return vars;
  134. }
  135. static char *
  136. fs_location_vars(glamor_program_location locations)
  137. {
  138. int l;
  139. char *vars = strdup("");
  140. for (l = 0; vars && l < NUM_LOCATION_VARS; l++)
  141. if (locations & location_vars[l].location)
  142. vars = add_var(vars, location_vars[l].fs_vars);
  143. return vars;
  144. }
  145. static const char vs_template[] =
  146. "%s" /* version */
  147. "%s" /* prim vs_vars */
  148. "%s" /* fill vs_vars */
  149. "%s" /* location vs_vars */
  150. GLAMOR_DECLARE_MATRIX
  151. "void main() {\n"
  152. "%s" /* prim vs_exec, outputs 'pos' and gl_Position */
  153. "%s" /* fill vs_exec */
  154. "}\n";
  155. static const char fs_template[] =
  156. "%s" /* version */
  157. GLAMOR_DEFAULT_PRECISION
  158. "%s" /* prim fs_vars */
  159. "%s" /* fill fs_vars */
  160. "%s" /* location fs_vars */
  161. "void main() {\n"
  162. "%s" /* prim fs_exec */
  163. "%s" /* fill fs_exec */
  164. "}\n";
  165. static const char *
  166. str(const char *s)
  167. {
  168. if (!s)
  169. return "";
  170. return s;
  171. }
  172. static const glamor_facet facet_null_fill = {
  173. .name = ""
  174. };
  175. static GLint
  176. glamor_get_uniform(glamor_program *prog,
  177. glamor_program_location location,
  178. const char *name)
  179. {
  180. GLint uniform;
  181. if (location && (prog->locations & location) == 0)
  182. return -2;
  183. uniform = glGetUniformLocation(prog->prog, name);
  184. #if DBG
  185. ErrorF("%s uniform %d\n", name, uniform);
  186. #endif
  187. return uniform;
  188. }
  189. Bool
  190. glamor_build_program(ScreenPtr screen,
  191. glamor_program *prog,
  192. const glamor_facet *prim,
  193. const glamor_facet *fill)
  194. {
  195. glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
  196. glamor_program_location locations = prim->locations;
  197. glamor_program_flag flags = prim->flags;
  198. int version = prim->version;
  199. char *version_string = NULL;
  200. char *fs_vars = NULL;
  201. char *vs_vars = NULL;
  202. char *vs_prog_string;
  203. char *fs_prog_string;
  204. GLint fs_prog, vs_prog;
  205. if (!fill)
  206. fill = &facet_null_fill;
  207. locations |= fill->locations;
  208. flags |= fill->flags;
  209. version = MAX(version, fill->version);
  210. if (version > glamor_priv->glsl_version)
  211. goto fail;
  212. vs_vars = vs_location_vars(locations);
  213. fs_vars = fs_location_vars(locations);
  214. if (!vs_vars)
  215. goto fail;
  216. if (!fs_vars)
  217. goto fail;
  218. if (version) {
  219. if (asprintf(&version_string, "#version %d\n", version) < 0)
  220. version_string = NULL;
  221. if (!version_string)
  222. goto fail;
  223. }
  224. if (asprintf(&vs_prog_string,
  225. vs_template,
  226. str(version_string),
  227. str(prim->vs_vars),
  228. str(fill->vs_vars),
  229. vs_vars,
  230. str(prim->vs_exec),
  231. str(fill->vs_exec)) < 0)
  232. vs_prog_string = NULL;
  233. if (asprintf(&fs_prog_string,
  234. fs_template,
  235. str(version_string),
  236. str(prim->fs_vars),
  237. str(fill->fs_vars),
  238. fs_vars,
  239. str(prim->fs_exec),
  240. str(fill->fs_exec)) < 0)
  241. fs_prog_string = NULL;
  242. if (!vs_prog_string || !fs_prog_string)
  243. goto fail;
  244. #define DBG 0
  245. #if DBG
  246. ErrorF("\nPrograms for %s %s\nVertex shader:\n\n%s\n\nFragment Shader:\n\n%s",
  247. prim->name, fill->name, vs_prog_string, fs_prog_string);
  248. #endif
  249. prog->prog = glCreateProgram();
  250. prog->flags = flags;
  251. prog->locations = locations;
  252. prog->prim_use = prim->use;
  253. prog->fill_use = fill->use;
  254. vs_prog = glamor_compile_glsl_prog(GL_VERTEX_SHADER, vs_prog_string);
  255. fs_prog = glamor_compile_glsl_prog(GL_FRAGMENT_SHADER, fs_prog_string);
  256. free(vs_prog_string);
  257. free(fs_prog_string);
  258. glAttachShader(prog->prog, vs_prog);
  259. glDeleteShader(vs_prog);
  260. glAttachShader(prog->prog, fs_prog);
  261. glDeleteShader(fs_prog);
  262. glBindAttribLocation(prog->prog, GLAMOR_VERTEX_POS, "primitive");
  263. if (prim->source_name) {
  264. #if DBG
  265. ErrorF("Bind GLAMOR_VERTEX_SOURCE to %s\n", prim->source_name);
  266. #endif
  267. glBindAttribLocation(prog->prog, GLAMOR_VERTEX_SOURCE, prim->source_name);
  268. }
  269. glamor_link_glsl_prog(screen, prog->prog, "%s_%s", prim->name, fill->name);
  270. prog->matrix_uniform = glamor_get_uniform(prog, glamor_program_location_none, "v_matrix");
  271. prog->fg_uniform = glamor_get_uniform(prog, glamor_program_location_fg, "fg");
  272. prog->bg_uniform = glamor_get_uniform(prog, glamor_program_location_bg, "bg");
  273. prog->fill_offset_uniform = glamor_get_uniform(prog, glamor_program_location_fill, "fill_offset");
  274. prog->fill_size_uniform = glamor_get_uniform(prog, glamor_program_location_fill, "fill_size");
  275. prog->font_uniform = glamor_get_uniform(prog, glamor_program_location_font, "font");
  276. if (glGetError() != GL_NO_ERROR)
  277. goto fail;
  278. free(version_string);
  279. free(fs_vars);
  280. free(vs_vars);
  281. return TRUE;
  282. fail:
  283. prog->failed = 1;
  284. if (prog->prog) {
  285. glDeleteProgram(prog->prog);
  286. prog->prog = 0;
  287. }
  288. free(version_string);
  289. free(fs_vars);
  290. free(vs_vars);
  291. return FALSE;
  292. }
  293. Bool
  294. glamor_use_program(PixmapPtr pixmap,
  295. GCPtr gc,
  296. glamor_program *prog,
  297. void *arg)
  298. {
  299. glUseProgram(prog->prog);
  300. if (prog->prim_use && !prog->prim_use(pixmap, gc, prog, arg))
  301. return FALSE;
  302. if (prog->fill_use && !prog->fill_use(pixmap, gc, prog, arg))
  303. return FALSE;
  304. return TRUE;
  305. }
  306. glamor_program *
  307. glamor_use_program_fill(PixmapPtr pixmap,
  308. GCPtr gc,
  309. glamor_program_fill *program_fill,
  310. const glamor_facet *prim)
  311. {
  312. ScreenPtr screen = pixmap->drawable.pScreen;
  313. glamor_program *prog = &program_fill->progs[gc->fillStyle];
  314. int fill_style = gc->fillStyle;
  315. const glamor_facet *fill;
  316. if (prog->failed)
  317. return FALSE;
  318. if (!prog->prog) {
  319. fill = glamor_facet_fill[fill_style];
  320. if (!fill)
  321. return NULL;
  322. if (!glamor_build_program(screen, prog, prim, fill))
  323. return NULL;
  324. }
  325. if (!glamor_use_program(pixmap, gc, prog, NULL))
  326. return NULL;
  327. return prog;
  328. }