2 * Copyright © 2014 Keith Packard
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.
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
23 #include "glamor_priv.h"
24 #include "glamor_program.h"
25 #include "glamor_transform.h"
26 #include "glamor_transfer.h"
27 #include "glamor_prepare.h"
29 static const char dash_vs_vars
[] =
30 "in vec3 primitive;\n"
31 "out float dash_offset;\n";
33 static const char dash_vs_exec
[] =
34 " dash_offset = primitive.z / dash_length;\n"
35 " vec2 pos = vec2(0,0);\n"
36 GLAMOR_POS(gl_Position
, primitive
.xy
);
38 static const char dash_fs_vars
[] =
39 "in float dash_offset;\n";
41 static const char on_off_fs_exec
[] =
42 " float pattern = texture(dash, vec2(dash_offset, 0.5)).w;\n"
43 " if (pattern == 0.0)\n"
46 /* XXX deal with stippled double dashed lines once we have stippling support */
47 static const char double_fs_exec
[] =
48 " float pattern = texture(dash, vec2(dash_offset, 0.5)).w;\n"
49 " if (pattern == 0.0)\n"
52 " frag_color = fg;\n";
55 static const glamor_facet glamor_facet_on_off_dash_lines
= {
57 .name
= "poly_lines_on_off_dash",
58 .vs_vars
= dash_vs_vars
,
59 .vs_exec
= dash_vs_exec
,
60 .fs_vars
= dash_fs_vars
,
61 .fs_exec
= on_off_fs_exec
,
62 .locations
= glamor_program_location_dash
,
65 static const glamor_facet glamor_facet_double_dash_lines
= {
67 .name
= "poly_lines_double_dash",
68 .vs_vars
= dash_vs_vars
,
69 .vs_exec
= dash_vs_exec
,
70 .fs_vars
= dash_fs_vars
,
71 .fs_exec
= double_fs_exec
,
72 .locations
= (glamor_program_location_dash
|
73 glamor_program_location_fg
|
74 glamor_program_location_bg
),
78 glamor_get_dash_pixmap(GCPtr gc
)
80 glamor_gc_private
*gc_priv
= glamor_get_gc_private(gc
);
81 ScreenPtr screen
= gc
->pScreen
;
92 for (d
= 0; d
< gc
->numInDashList
; d
++)
93 offset
+= gc
->dash
[d
];
95 pixmap
= glamor_create_pixmap(screen
, offset
, 1, 8, 0);
99 scratch_gc
= GetScratchGC(8, screen
);
105 for (d
= 0; d
< gc
->numInDashList
; d
++) {
110 (void) ChangeGC(NullClient
, scratch_gc
,
111 GCForeground
, &changes
);
112 ValidateGC(&pixmap
->drawable
, scratch_gc
);
115 rect
.width
= gc
->dash
[d
];
117 scratch_gc
->ops
->PolyFillRect (&pixmap
->drawable
, scratch_gc
, 1, &rect
);
118 offset
+= gc
->dash
[d
];
121 FreeScratchGC(scratch_gc
);
123 gc_priv
->dash
= pixmap
;
127 glamor_destroy_pixmap(pixmap
);
132 static glamor_program
*
133 glamor_dash_setup(DrawablePtr drawable
, GCPtr gc
)
135 ScreenPtr screen
= drawable
->pScreen
;
136 glamor_screen_private
*glamor_priv
= glamor_get_screen_private(screen
);
137 PixmapPtr pixmap
= glamor_get_drawable_pixmap(drawable
);
138 glamor_pixmap_private
*pixmap_priv
= glamor_get_pixmap_private(pixmap
);
139 PixmapPtr dash_pixmap
;
140 glamor_pixmap_private
*dash_priv
;
141 glamor_program
*prog
;
143 if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv
))
146 if (gc
->lineWidth
!= 0)
149 dash_pixmap
= glamor_get_dash_pixmap(gc
);
150 dash_priv
= glamor_get_pixmap_private(dash_pixmap
);
152 if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(dash_priv
))
155 glamor_make_current(glamor_priv
);
157 switch (gc
->lineStyle
) {
159 prog
= glamor_use_program_fill(drawable
, gc
,
160 &glamor_priv
->on_off_dash_line_progs
,
161 &glamor_facet_on_off_dash_lines
);
166 if (gc
->fillStyle
!= FillSolid
)
169 prog
= &glamor_priv
->double_dash_line_prog
;
172 if (!glamor_build_program(screen
, prog
,
173 &glamor_facet_double_dash_lines
,
178 if (!glamor_use_program(drawable
, gc
, prog
, NULL
))
181 glamor_set_color(drawable
, gc
->fgPixel
, prog
->fg_uniform
);
182 glamor_set_color(drawable
, gc
->bgPixel
, prog
->bg_uniform
);
190 /* Set the dash pattern as texture 1 */
192 glamor_bind_texture(glamor_priv
, GL_TEXTURE1
, dash_priv
->fbo
, FALSE
);
193 glUniform1i(prog
->dash_uniform
, 1);
194 glUniform1f(prog
->dash_length_uniform
, dash_pixmap
->drawable
.width
);
203 glamor_dash_loop(DrawablePtr drawable
, GCPtr gc
, glamor_program
*prog
,
206 PixmapPtr pixmap
= glamor_get_drawable_pixmap(drawable
);
207 glamor_pixmap_private
*pixmap_priv
= glamor_get_pixmap_private(pixmap
);
211 glEnable(GL_SCISSOR_TEST
);
213 glamor_pixmap_loop(pixmap_priv
, box_index
) {
214 int nbox
= RegionNumRects(gc
->pCompositeClip
);
215 BoxPtr box
= RegionRects(gc
->pCompositeClip
);
217 glamor_set_destination_drawable(drawable
, box_index
, TRUE
, TRUE
,
218 prog
->matrix_uniform
, &off_x
, &off_y
);
221 glScissor(box
->x1
+ off_x
,
226 glDrawArrays(mode
, 0, n
);
230 glDisable(GL_SCISSOR_TEST
);
231 glDisableVertexAttribArray(GLAMOR_VERTEX_POS
);
235 glamor_line_length(short x1
, short y1
, short x2
, short y2
)
237 return max(abs(x2
- x1
), abs(y2
- y1
));
241 glamor_poly_lines_dash_gl(DrawablePtr drawable
, GCPtr gc
,
242 int mode
, int n
, DDXPointPtr points
)
244 ScreenPtr screen
= drawable
->pScreen
;
245 glamor_program
*prog
;
256 if (!(prog
= glamor_dash_setup(drawable
, gc
)))
260 if (gc
->capStyle
!= CapNotLast
)
263 /* Set up the vertex buffers for the points */
265 v
= glamor_get_vbo_space(drawable
->pScreen
,
266 (n
+ add_last
) * 3 * sizeof (short),
269 glEnableVertexAttribArray(GLAMOR_VERTEX_POS
);
270 glVertexAttribPointer(GLAMOR_VERTEX_POS
, 3, GL_SHORT
, GL_FALSE
,
271 3 * sizeof (short), vbo_offset
);
273 dash_pos
= gc
->dashOffset
;
275 for (i
= 0; i
< n
; i
++) {
276 int this_x
= points
[i
].x
;
277 int this_y
= points
[i
].y
;
279 if (mode
== CoordModePrevious
) {
283 dash_pos
+= glamor_line_length(prev_x
, prev_y
,
286 v
[0] = prev_x
= this_x
;
287 v
[1] = prev_y
= this_y
;
298 glamor_put_vbo_space(screen
);
300 glamor_dash_loop(drawable
, gc
, prog
, n
+ add_last
, GL_LINE_STRIP
);
306 glamor_add_segment(short *v
, short x1
, short y1
, short x2
, short y2
,
307 int dash_start
, int dash_end
)
320 glamor_poly_segment_dash_gl(DrawablePtr drawable
, GCPtr gc
,
321 int nseg
, xSegment
*segs
)
323 ScreenPtr screen
= drawable
->pScreen
;
324 glamor_program
*prog
;
327 int dash_start
= gc
->dashOffset
;
331 if (!(prog
= glamor_dash_setup(drawable
, gc
)))
335 if (gc
->capStyle
!= CapNotLast
)
338 /* Set up the vertex buffers for the points */
340 v
= glamor_get_vbo_space(drawable
->pScreen
,
341 (nseg
<<add_last
) * 6 * sizeof (short),
344 glEnableVertexAttribArray(GLAMOR_VERTEX_POS
);
345 glVertexAttribPointer(GLAMOR_VERTEX_POS
, 3, GL_SHORT
, GL_FALSE
,
346 3 * sizeof (short), vbo_offset
);
348 for (i
= 0; i
< nseg
; i
++) {
349 int dash_end
= dash_start
+ glamor_line_length(segs
[i
].x1
, segs
[i
].y1
,
350 segs
[i
].x2
, segs
[i
].y2
);
351 v
= glamor_add_segment(v
,
352 segs
[i
].x1
, segs
[i
].y1
,
353 segs
[i
].x2
, segs
[i
].y2
,
354 dash_start
, dash_end
);
356 v
= glamor_add_segment(v
,
357 segs
[i
].x2
, segs
[i
].y2
,
358 segs
[i
].x2
+ 1, segs
[i
].y2
,
359 dash_end
, dash_end
+ 1);
362 glamor_put_vbo_space(screen
);
364 glamor_dash_loop(drawable
, gc
, prog
, nseg
<< (1 + add_last
), GL_LINES
);