135c4bbdfSmrg/* 235c4bbdfSmrg * Copyright © 2014 Keith Packard 335c4bbdfSmrg * 435c4bbdfSmrg * Permission to use, copy, modify, distribute, and sell this software and its 535c4bbdfSmrg * documentation for any purpose is hereby granted without fee, provided that 635c4bbdfSmrg * the above copyright notice appear in all copies and that both that copyright 735c4bbdfSmrg * notice and this permission notice appear in supporting documentation, and 835c4bbdfSmrg * that the name of the copyright holders not be used in advertising or 935c4bbdfSmrg * publicity pertaining to distribution of the software without specific, 1035c4bbdfSmrg * written prior permission. The copyright holders make no representations 1135c4bbdfSmrg * about the suitability of this software for any purpose. It is provided "as 1235c4bbdfSmrg * is" without express or implied warranty. 1335c4bbdfSmrg * 1435c4bbdfSmrg * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 1535c4bbdfSmrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 1635c4bbdfSmrg * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 1735c4bbdfSmrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 1835c4bbdfSmrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 1935c4bbdfSmrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 2035c4bbdfSmrg * OF THIS SOFTWARE. 2135c4bbdfSmrg */ 2235c4bbdfSmrg 2335c4bbdfSmrg#include "glamor_priv.h" 2435c4bbdfSmrg#include "glamor_program.h" 2535c4bbdfSmrg#include "glamor_transform.h" 2635c4bbdfSmrg#include "glamor_transfer.h" 2735c4bbdfSmrg#include "glamor_prepare.h" 2835c4bbdfSmrg 2935c4bbdfSmrgstatic const char dash_vs_vars[] = 3035c4bbdfSmrg "attribute vec3 primitive;\n" 3135c4bbdfSmrg "varying float dash_offset;\n"; 3235c4bbdfSmrg 3335c4bbdfSmrgstatic const char dash_vs_exec[] = 3435c4bbdfSmrg " dash_offset = primitive.z / dash_length;\n" 351b5d61b8Smrg " vec2 pos = vec2(0,0);\n" 3635c4bbdfSmrg GLAMOR_POS(gl_Position, primitive.xy); 3735c4bbdfSmrg 3835c4bbdfSmrgstatic const char dash_fs_vars[] = 3935c4bbdfSmrg "varying float dash_offset;\n"; 4035c4bbdfSmrg 4135c4bbdfSmrgstatic const char on_off_fs_exec[] = 4235c4bbdfSmrg " float pattern = texture2D(dash, vec2(dash_offset, 0.5)).w;\n" 4335c4bbdfSmrg " if (pattern == 0.0)\n" 4435c4bbdfSmrg " discard;\n"; 4535c4bbdfSmrg 4635c4bbdfSmrg/* XXX deal with stippled double dashed lines once we have stippling support */ 4735c4bbdfSmrgstatic const char double_fs_exec[] = 4835c4bbdfSmrg " float pattern = texture2D(dash, vec2(dash_offset, 0.5)).w;\n" 4935c4bbdfSmrg " if (pattern == 0.0)\n" 5035c4bbdfSmrg " gl_FragColor = bg;\n" 5135c4bbdfSmrg " else\n" 5235c4bbdfSmrg " gl_FragColor = fg;\n"; 5335c4bbdfSmrg 5435c4bbdfSmrg 5535c4bbdfSmrgstatic const glamor_facet glamor_facet_on_off_dash_lines = { 5635c4bbdfSmrg .version = 130, 5735c4bbdfSmrg .name = "poly_lines_on_off_dash", 5835c4bbdfSmrg .vs_vars = dash_vs_vars, 5935c4bbdfSmrg .vs_exec = dash_vs_exec, 6035c4bbdfSmrg .fs_vars = dash_fs_vars, 6135c4bbdfSmrg .fs_exec = on_off_fs_exec, 6235c4bbdfSmrg .locations = glamor_program_location_dash, 6335c4bbdfSmrg}; 6435c4bbdfSmrg 6535c4bbdfSmrgstatic const glamor_facet glamor_facet_double_dash_lines = { 6635c4bbdfSmrg .version = 130, 6735c4bbdfSmrg .name = "poly_lines_double_dash", 6835c4bbdfSmrg .vs_vars = dash_vs_vars, 6935c4bbdfSmrg .vs_exec = dash_vs_exec, 7035c4bbdfSmrg .fs_vars = dash_fs_vars, 7135c4bbdfSmrg .fs_exec = double_fs_exec, 7235c4bbdfSmrg .locations = (glamor_program_location_dash| 7335c4bbdfSmrg glamor_program_location_fg| 7435c4bbdfSmrg glamor_program_location_bg), 7535c4bbdfSmrg}; 7635c4bbdfSmrg 7735c4bbdfSmrgstatic PixmapPtr 7835c4bbdfSmrgglamor_get_dash_pixmap(GCPtr gc) 7935c4bbdfSmrg{ 8035c4bbdfSmrg glamor_gc_private *gc_priv = glamor_get_gc_private(gc); 8135c4bbdfSmrg ScreenPtr screen = gc->pScreen; 8235c4bbdfSmrg PixmapPtr pixmap; 8335c4bbdfSmrg int offset; 8435c4bbdfSmrg int d; 8535c4bbdfSmrg uint32_t pixel; 8635c4bbdfSmrg GCPtr scratch_gc; 8735c4bbdfSmrg 8835c4bbdfSmrg if (gc_priv->dash) 8935c4bbdfSmrg return gc_priv->dash; 9035c4bbdfSmrg 9135c4bbdfSmrg offset = 0; 9235c4bbdfSmrg for (d = 0; d < gc->numInDashList; d++) 9335c4bbdfSmrg offset += gc->dash[d]; 9435c4bbdfSmrg 9535c4bbdfSmrg pixmap = glamor_create_pixmap(screen, offset, 1, 8, 0); 9635c4bbdfSmrg if (!pixmap) 9735c4bbdfSmrg goto bail; 9835c4bbdfSmrg 9935c4bbdfSmrg scratch_gc = GetScratchGC(8, screen); 10035c4bbdfSmrg if (!scratch_gc) 10135c4bbdfSmrg goto bail_pixmap; 10235c4bbdfSmrg 10335c4bbdfSmrg pixel = 0xffffffff; 10435c4bbdfSmrg offset = 0; 10535c4bbdfSmrg for (d = 0; d < gc->numInDashList; d++) { 10635c4bbdfSmrg xRectangle rect; 10735c4bbdfSmrg ChangeGCVal changes; 10835c4bbdfSmrg 10935c4bbdfSmrg changes.val = pixel; 11035c4bbdfSmrg (void) ChangeGC(NullClient, scratch_gc, 11135c4bbdfSmrg GCForeground, &changes); 11235c4bbdfSmrg ValidateGC(&pixmap->drawable, scratch_gc); 11335c4bbdfSmrg rect.x = offset; 11435c4bbdfSmrg rect.y = 0; 11535c4bbdfSmrg rect.width = gc->dash[d]; 11635c4bbdfSmrg rect.height = 1; 11735c4bbdfSmrg scratch_gc->ops->PolyFillRect (&pixmap->drawable, scratch_gc, 1, &rect); 11835c4bbdfSmrg offset += gc->dash[d]; 11935c4bbdfSmrg pixel = ~pixel; 12035c4bbdfSmrg } 12135c4bbdfSmrg FreeScratchGC(scratch_gc); 12235c4bbdfSmrg 12335c4bbdfSmrg gc_priv->dash = pixmap; 12435c4bbdfSmrg return pixmap; 12535c4bbdfSmrg 12635c4bbdfSmrgbail_pixmap: 12735c4bbdfSmrg glamor_destroy_pixmap(pixmap); 12835c4bbdfSmrgbail: 12935c4bbdfSmrg return NULL; 13035c4bbdfSmrg} 13135c4bbdfSmrg 13235c4bbdfSmrgstatic glamor_program * 13335c4bbdfSmrgglamor_dash_setup(DrawablePtr drawable, GCPtr gc) 13435c4bbdfSmrg{ 13535c4bbdfSmrg ScreenPtr screen = drawable->pScreen; 13635c4bbdfSmrg glamor_screen_private *glamor_priv = glamor_get_screen_private(screen); 13735c4bbdfSmrg PixmapPtr pixmap = glamor_get_drawable_pixmap(drawable); 13835c4bbdfSmrg glamor_pixmap_private *pixmap_priv = glamor_get_pixmap_private(pixmap); 13935c4bbdfSmrg PixmapPtr dash_pixmap; 14035c4bbdfSmrg glamor_pixmap_private *dash_priv; 14135c4bbdfSmrg glamor_program *prog; 14235c4bbdfSmrg 14335c4bbdfSmrg if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv)) 14435c4bbdfSmrg goto bail; 14535c4bbdfSmrg 14635c4bbdfSmrg if (gc->lineWidth != 0) 14735c4bbdfSmrg goto bail; 14835c4bbdfSmrg 14935c4bbdfSmrg dash_pixmap = glamor_get_dash_pixmap(gc); 1501b5d61b8Smrg dash_priv = glamor_get_pixmap_private(dash_pixmap); 15135c4bbdfSmrg 15235c4bbdfSmrg if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(dash_priv)) 15335c4bbdfSmrg goto bail; 15435c4bbdfSmrg 15535c4bbdfSmrg glamor_make_current(glamor_priv); 15635c4bbdfSmrg 15735c4bbdfSmrg switch (gc->lineStyle) { 15835c4bbdfSmrg case LineOnOffDash: 15935c4bbdfSmrg prog = glamor_use_program_fill(pixmap, gc, 16035c4bbdfSmrg &glamor_priv->on_off_dash_line_progs, 16135c4bbdfSmrg &glamor_facet_on_off_dash_lines); 16235c4bbdfSmrg if (!prog) 16335c4bbdfSmrg goto bail; 16435c4bbdfSmrg break; 16535c4bbdfSmrg case LineDoubleDash: 16635c4bbdfSmrg if (gc->fillStyle != FillSolid) 16735c4bbdfSmrg goto bail; 16835c4bbdfSmrg 16935c4bbdfSmrg prog = &glamor_priv->double_dash_line_prog; 17035c4bbdfSmrg 17135c4bbdfSmrg if (!prog->prog) { 17235c4bbdfSmrg if (!glamor_build_program(screen, prog, 17335c4bbdfSmrg &glamor_facet_double_dash_lines, 17435c4bbdfSmrg NULL, NULL, NULL)) 17535c4bbdfSmrg goto bail; 17635c4bbdfSmrg } 17735c4bbdfSmrg 17835c4bbdfSmrg if (!glamor_use_program(pixmap, gc, prog, NULL)) 17935c4bbdfSmrg goto bail; 18035c4bbdfSmrg 18135c4bbdfSmrg glamor_set_color(pixmap, gc->fgPixel, prog->fg_uniform); 18235c4bbdfSmrg glamor_set_color(pixmap, gc->bgPixel, prog->bg_uniform); 18335c4bbdfSmrg break; 18435c4bbdfSmrg 18535c4bbdfSmrg default: 18635c4bbdfSmrg goto bail; 18735c4bbdfSmrg } 18835c4bbdfSmrg 18935c4bbdfSmrg 19035c4bbdfSmrg /* Set the dash pattern as texture 1 */ 19135c4bbdfSmrg 19235c4bbdfSmrg glamor_bind_texture(glamor_priv, GL_TEXTURE1, dash_priv->fbo, FALSE); 19335c4bbdfSmrg glUniform1i(prog->dash_uniform, 1); 19435c4bbdfSmrg glUniform1f(prog->dash_length_uniform, dash_pixmap->drawable.width); 19535c4bbdfSmrg 19635c4bbdfSmrg return prog; 19735c4bbdfSmrg 19835c4bbdfSmrgbail: 19935c4bbdfSmrg return NULL; 20035c4bbdfSmrg} 20135c4bbdfSmrg 20235c4bbdfSmrgstatic void 20335c4bbdfSmrgglamor_dash_loop(DrawablePtr drawable, GCPtr gc, glamor_program *prog, 20435c4bbdfSmrg int n, GLenum mode) 20535c4bbdfSmrg{ 20635c4bbdfSmrg PixmapPtr pixmap = glamor_get_drawable_pixmap(drawable); 20735c4bbdfSmrg glamor_pixmap_private *pixmap_priv = glamor_get_pixmap_private(pixmap); 20835c4bbdfSmrg int box_index; 20935c4bbdfSmrg int off_x, off_y; 21035c4bbdfSmrg 21135c4bbdfSmrg glEnable(GL_SCISSOR_TEST); 21235c4bbdfSmrg 21335c4bbdfSmrg glamor_pixmap_loop(pixmap_priv, box_index) { 21435c4bbdfSmrg int nbox = RegionNumRects(gc->pCompositeClip); 21535c4bbdfSmrg BoxPtr box = RegionRects(gc->pCompositeClip); 21635c4bbdfSmrg 21735c4bbdfSmrg glamor_set_destination_drawable(drawable, box_index, TRUE, TRUE, 21835c4bbdfSmrg prog->matrix_uniform, &off_x, &off_y); 21935c4bbdfSmrg 22035c4bbdfSmrg while (nbox--) { 22135c4bbdfSmrg glScissor(box->x1 + off_x, 22235c4bbdfSmrg box->y1 + off_y, 22335c4bbdfSmrg box->x2 - box->x1, 22435c4bbdfSmrg box->y2 - box->y1); 22535c4bbdfSmrg box++; 22635c4bbdfSmrg glDrawArrays(mode, 0, n); 22735c4bbdfSmrg } 22835c4bbdfSmrg } 22935c4bbdfSmrg 23035c4bbdfSmrg glDisable(GL_SCISSOR_TEST); 23135c4bbdfSmrg glDisableVertexAttribArray(GLAMOR_VERTEX_POS); 23235c4bbdfSmrg} 23335c4bbdfSmrg 23435c4bbdfSmrgstatic int 23535c4bbdfSmrgglamor_line_length(short x1, short y1, short x2, short y2) 23635c4bbdfSmrg{ 23735c4bbdfSmrg return max(abs(x2 - x1), abs(y2 - y1)); 23835c4bbdfSmrg} 23935c4bbdfSmrg 24035c4bbdfSmrgBool 24135c4bbdfSmrgglamor_poly_lines_dash_gl(DrawablePtr drawable, GCPtr gc, 24235c4bbdfSmrg int mode, int n, DDXPointPtr points) 24335c4bbdfSmrg{ 24435c4bbdfSmrg ScreenPtr screen = drawable->pScreen; 24535c4bbdfSmrg glamor_program *prog; 24635c4bbdfSmrg short *v; 24735c4bbdfSmrg char *vbo_offset; 24835c4bbdfSmrg int add_last; 24935c4bbdfSmrg int dash_pos; 25035c4bbdfSmrg int prev_x, prev_y; 25135c4bbdfSmrg int i; 25235c4bbdfSmrg 25335c4bbdfSmrg if (n < 2) 25435c4bbdfSmrg return TRUE; 25535c4bbdfSmrg 25635c4bbdfSmrg if (!(prog = glamor_dash_setup(drawable, gc))) 25735c4bbdfSmrg return FALSE; 25835c4bbdfSmrg 25935c4bbdfSmrg add_last = 0; 26035c4bbdfSmrg if (gc->capStyle != CapNotLast) 26135c4bbdfSmrg add_last = 1; 26235c4bbdfSmrg 26335c4bbdfSmrg /* Set up the vertex buffers for the points */ 26435c4bbdfSmrg 26535c4bbdfSmrg v = glamor_get_vbo_space(drawable->pScreen, 26635c4bbdfSmrg (n + add_last) * 3 * sizeof (short), 26735c4bbdfSmrg &vbo_offset); 26835c4bbdfSmrg 26935c4bbdfSmrg glEnableVertexAttribArray(GLAMOR_VERTEX_POS); 27035c4bbdfSmrg glVertexAttribPointer(GLAMOR_VERTEX_POS, 3, GL_SHORT, GL_FALSE, 27135c4bbdfSmrg 3 * sizeof (short), vbo_offset); 27235c4bbdfSmrg 27335c4bbdfSmrg dash_pos = gc->dashOffset; 27435c4bbdfSmrg prev_x = prev_y = 0; 27535c4bbdfSmrg for (i = 0; i < n; i++) { 27635c4bbdfSmrg int this_x = points[i].x; 27735c4bbdfSmrg int this_y = points[i].y; 27835c4bbdfSmrg if (i) { 27935c4bbdfSmrg if (mode == CoordModePrevious) { 28035c4bbdfSmrg this_x += prev_x; 28135c4bbdfSmrg this_y += prev_y; 28235c4bbdfSmrg } 28335c4bbdfSmrg dash_pos += glamor_line_length(prev_x, prev_y, 28435c4bbdfSmrg this_x, this_y); 28535c4bbdfSmrg } 28635c4bbdfSmrg v[0] = prev_x = this_x; 28735c4bbdfSmrg v[1] = prev_y = this_y; 28835c4bbdfSmrg v[2] = dash_pos; 28935c4bbdfSmrg v += 3; 29035c4bbdfSmrg } 29135c4bbdfSmrg 29235c4bbdfSmrg if (add_last) { 29335c4bbdfSmrg v[0] = prev_x + 1; 29435c4bbdfSmrg v[1] = prev_y; 29535c4bbdfSmrg v[2] = dash_pos + 1; 29635c4bbdfSmrg } 29735c4bbdfSmrg 29835c4bbdfSmrg glamor_put_vbo_space(screen); 29935c4bbdfSmrg 30035c4bbdfSmrg glamor_dash_loop(drawable, gc, prog, n + add_last, GL_LINE_STRIP); 30135c4bbdfSmrg 30235c4bbdfSmrg return TRUE; 30335c4bbdfSmrg} 30435c4bbdfSmrg 30535c4bbdfSmrgstatic short * 30635c4bbdfSmrgglamor_add_segment(short *v, short x1, short y1, short x2, short y2, 30735c4bbdfSmrg int dash_start, int dash_end) 30835c4bbdfSmrg{ 30935c4bbdfSmrg v[0] = x1; 31035c4bbdfSmrg v[1] = y1; 31135c4bbdfSmrg v[2] = dash_start; 31235c4bbdfSmrg 31335c4bbdfSmrg v[3] = x2; 31435c4bbdfSmrg v[4] = y2; 31535c4bbdfSmrg v[5] = dash_end; 31635c4bbdfSmrg return v + 6; 31735c4bbdfSmrg} 31835c4bbdfSmrg 31935c4bbdfSmrgBool 32035c4bbdfSmrgglamor_poly_segment_dash_gl(DrawablePtr drawable, GCPtr gc, 32135c4bbdfSmrg int nseg, xSegment *segs) 32235c4bbdfSmrg{ 32335c4bbdfSmrg ScreenPtr screen = drawable->pScreen; 32435c4bbdfSmrg glamor_program *prog; 32535c4bbdfSmrg short *v; 32635c4bbdfSmrg char *vbo_offset; 32735c4bbdfSmrg int dash_start = gc->dashOffset; 32835c4bbdfSmrg int add_last; 32935c4bbdfSmrg int i; 33035c4bbdfSmrg 33135c4bbdfSmrg if (!(prog = glamor_dash_setup(drawable, gc))) 33235c4bbdfSmrg return FALSE; 33335c4bbdfSmrg 33435c4bbdfSmrg add_last = 0; 33535c4bbdfSmrg if (gc->capStyle != CapNotLast) 33635c4bbdfSmrg add_last = 1; 33735c4bbdfSmrg 33835c4bbdfSmrg /* Set up the vertex buffers for the points */ 33935c4bbdfSmrg 34035c4bbdfSmrg v = glamor_get_vbo_space(drawable->pScreen, 34135c4bbdfSmrg (nseg<<add_last) * 6 * sizeof (short), 34235c4bbdfSmrg &vbo_offset); 34335c4bbdfSmrg 34435c4bbdfSmrg glEnableVertexAttribArray(GLAMOR_VERTEX_POS); 34535c4bbdfSmrg glVertexAttribPointer(GLAMOR_VERTEX_POS, 3, GL_SHORT, GL_FALSE, 34635c4bbdfSmrg 3 * sizeof (short), vbo_offset); 34735c4bbdfSmrg 34835c4bbdfSmrg for (i = 0; i < nseg; i++) { 34935c4bbdfSmrg int dash_end = dash_start + glamor_line_length(segs[i].x1, segs[i].y1, 35035c4bbdfSmrg segs[i].x2, segs[i].y2); 35135c4bbdfSmrg v = glamor_add_segment(v, 35235c4bbdfSmrg segs[i].x1, segs[i].y1, 35335c4bbdfSmrg segs[i].x2, segs[i].y2, 35435c4bbdfSmrg dash_start, dash_end); 35535c4bbdfSmrg if (add_last) 35635c4bbdfSmrg v = glamor_add_segment(v, 35735c4bbdfSmrg segs[i].x2, segs[i].y2, 35835c4bbdfSmrg segs[i].x2 + 1, segs[i].y2, 35935c4bbdfSmrg dash_end, dash_end + 1); 36035c4bbdfSmrg } 36135c4bbdfSmrg 36235c4bbdfSmrg glamor_put_vbo_space(screen); 36335c4bbdfSmrg 36435c4bbdfSmrg glamor_dash_loop(drawable, gc, prog, nseg << (1 + add_last), GL_LINES); 36535c4bbdfSmrg 36635c4bbdfSmrg return TRUE; 36735c4bbdfSmrg} 368