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
26
27 /*
28 * Set up rendering to target the specified drawable, computing an
29 * appropriate transform for the vertex shader to convert
30 * drawable-relative coordinates into pixmap-relative coordinates. If
31 * requested, the offset from pixmap origin coordinates back to window
32 * system coordinates will be returned in *p_off_x, *p_off_y so that
33 * clipping computations can be adjusted as appropriate
34 */
35
36 Bool
glamor_set_destination_drawable(DrawablePtr drawable,int box_index,Bool do_drawable_translate,Bool center_offset,GLint matrix_uniform_location,int * p_off_x,int * p_off_y)37 glamor_set_destination_drawable(DrawablePtr drawable,
38 int box_index,
39 Bool do_drawable_translate,
40 Bool center_offset,
41 GLint matrix_uniform_location,
42 int *p_off_x,
43 int *p_off_y)
44 {
45 ScreenPtr screen = drawable->pScreen;
46 glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
47 PixmapPtr pixmap = glamor_get_drawable_pixmap(drawable);
48 glamor_pixmap_private *pixmap_priv = glamor_get_pixmap_private(pixmap);
49 int off_x, off_y;
50 BoxPtr box = glamor_pixmap_box_at(pixmap_priv, box_index);
51 int w = box->x2 - box->x1;
52 int h = box->y2 - box->y1;
53 float scale_x = 2.0f / (float) w;
54 float scale_y = 2.0f / (float) h;
55 float center_adjust = 0.0f;
56 glamor_pixmap_fbo *pixmap_fbo;
57
58 pixmap_fbo = glamor_pixmap_fbo_at(pixmap_priv, box_index);
59 if (!pixmap_fbo)
60 return FALSE;
61
62 glamor_get_drawable_deltas(drawable, pixmap, &off_x, &off_y);
63
64 off_x -= box->x1;
65 off_y -= box->y1;
66
67 if (p_off_x) {
68 *p_off_x = off_x;
69 *p_off_y = off_y;
70 }
71
72 /* A tricky computation to find the right value for the two linear functions
73 * that transform rendering coordinates to pixmap coordinates
74 *
75 * pixmap_x = render_x + drawable->x + off_x
76 * pixmap_y = render_y + drawable->y + off_y
77 *
78 * gl_x = pixmap_x * 2 / width - 1
79 * gl_y = pixmap_y * 2 / height - 1
80 *
81 * gl_x = (render_x + drawable->x + off_x) * 2 / width - 1
82 *
83 * gl_x = (render_x) * 2 / width + (drawable->x + off_x) * 2 / width - 1
84 */
85
86 if (do_drawable_translate) {
87 off_x += drawable->x;
88 off_y += drawable->y;
89 }
90
91 /*
92 * To get GL_POINTS drawn in the right spot, we need to adjust the
93 * coordinates by 1/2 a pixel.
94 */
95 if (center_offset)
96 center_adjust = 0.5f;
97
98 glUniform4f(matrix_uniform_location,
99 scale_x, (off_x + center_adjust) * scale_x - 1.0f,
100 scale_y, (off_y + center_adjust) * scale_y - 1.0f);
101
102 glamor_set_destination_pixmap_fbo(glamor_priv, pixmap_fbo,
103 0, 0, w, h);
104
105 return TRUE;
106 }
107
108 /*
109 * Set up for solid rendering to the specified pixmap using alu, fg and planemask
110 * from the specified GC. Load the target color into the specified uniform
111 */
112
113 void
glamor_set_color_depth(ScreenPtr pScreen,int depth,CARD32 pixel,GLint uniform)114 glamor_set_color_depth(ScreenPtr pScreen,
115 int depth,
116 CARD32 pixel,
117 GLint uniform)
118 {
119 glamor_screen_private *glamor_priv = glamor_get_screen_private(pScreen);
120 float color[4];
121
122 glamor_get_rgba_from_pixel(pixel,
123 &color[0], &color[1], &color[2], &color[3],
124 glamor_priv->formats[depth].render_format);
125
126 if ((depth <= 8) && glamor_priv->formats[8].format == GL_RED)
127 color[0] = color[3];
128
129 glUniform4fv(uniform, 1, color);
130 }
131
132 Bool
glamor_set_solid(PixmapPtr pixmap,GCPtr gc,Bool use_alu,GLint uniform)133 glamor_set_solid(PixmapPtr pixmap,
134 GCPtr gc,
135 Bool use_alu,
136 GLint uniform)
137 {
138 CARD32 pixel;
139 int alu = use_alu ? gc->alu : GXcopy;
140
141 if (!glamor_set_planemask(gc->depth, gc->planemask))
142 return FALSE;
143
144 pixel = gc->fgPixel;
145
146 if (!glamor_set_alu(pixmap->drawable.pScreen, alu)) {
147 switch (gc->alu) {
148 case GXclear:
149 pixel = 0;
150 break;
151 case GXcopyInverted:
152 pixel = ~pixel;
153 break;
154 case GXset:
155 pixel = ~0 & gc->planemask;
156 break;
157 default:
158 return FALSE;
159 }
160 }
161 glamor_set_color(pixmap, pixel, uniform);
162
163 return TRUE;
164 }
165
166 Bool
glamor_set_texture_pixmap(PixmapPtr texture,Bool destination_red)167 glamor_set_texture_pixmap(PixmapPtr texture, Bool destination_red)
168 {
169 glamor_pixmap_private *texture_priv;
170
171 texture_priv = glamor_get_pixmap_private(texture);
172
173 if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(texture_priv))
174 return FALSE;
175
176 if (glamor_pixmap_priv_is_large(texture_priv))
177 return FALSE;
178
179 glamor_bind_texture(glamor_get_screen_private(texture->drawable.pScreen),
180 GL_TEXTURE0,
181 texture_priv->fbo, destination_red);
182
183 /* we're not setting the sampler uniform here as we always use
184 * GL_TEXTURE0, and the default value for uniforms is zero. So,
185 * save a bit of CPU time by taking advantage of that.
186 */
187 return TRUE;
188 }
189
190 Bool
glamor_set_texture(PixmapPtr texture,Bool destination_red,int off_x,int off_y,GLint offset_uniform,GLint size_inv_uniform)191 glamor_set_texture(PixmapPtr texture,
192 Bool destination_red,
193 int off_x,
194 int off_y,
195 GLint offset_uniform,
196 GLint size_inv_uniform)
197 {
198 if (!glamor_set_texture_pixmap(texture, destination_red))
199 return FALSE;
200
201 glUniform2f(offset_uniform, off_x, off_y);
202 glUniform2f(size_inv_uniform, 1.0f/texture->drawable.width, 1.0f/texture->drawable.height);
203 return TRUE;
204 }
205
206 Bool
glamor_set_tiled(PixmapPtr pixmap,GCPtr gc,GLint offset_uniform,GLint size_inv_uniform)207 glamor_set_tiled(PixmapPtr pixmap,
208 GCPtr gc,
209 GLint offset_uniform,
210 GLint size_inv_uniform)
211 {
212 if (!glamor_set_alu(pixmap->drawable.pScreen, gc->alu))
213 return FALSE;
214
215 if (!glamor_set_planemask(gc->depth, gc->planemask))
216 return FALSE;
217
218 return glamor_set_texture(gc->tile.pixmap,
219 TRUE,
220 -gc->patOrg.x,
221 -gc->patOrg.y,
222 offset_uniform,
223 size_inv_uniform);
224 }
225
226 static PixmapPtr
glamor_get_stipple_pixmap(GCPtr gc)227 glamor_get_stipple_pixmap(GCPtr gc)
228 {
229 glamor_gc_private *gc_priv = glamor_get_gc_private(gc);
230 ScreenPtr screen = gc->pScreen;
231 PixmapPtr bitmap;
232 PixmapPtr pixmap;
233 GCPtr scratch_gc;
234 ChangeGCVal changes[2];
235
236 if (gc_priv->stipple)
237 return gc_priv->stipple;
238
239 bitmap = gc->stipple;
240 if (!bitmap)
241 goto bail;
242
243 pixmap = glamor_create_pixmap(screen,
244 bitmap->drawable.width,
245 bitmap->drawable.height,
246 8, GLAMOR_CREATE_NO_LARGE);
247 if (!pixmap)
248 goto bail;
249
250 scratch_gc = GetScratchGC(8, screen);
251 if (!scratch_gc)
252 goto bail_pixmap;
253
254 changes[0].val = 0xff;
255 changes[1].val = 0x00;
256 if (ChangeGC(NullClient, scratch_gc,
257 GCForeground|GCBackground, changes) != Success)
258 goto bail_gc;
259 ValidateGC(&pixmap->drawable, scratch_gc);
260
261 (*scratch_gc->ops->CopyPlane)(&bitmap->drawable,
262 &pixmap->drawable,
263 scratch_gc,
264 0, 0,
265 bitmap->drawable.width,
266 bitmap->drawable.height,
267 0, 0, 0x1);
268
269 FreeScratchGC(scratch_gc);
270 gc_priv->stipple = pixmap;
271
272 glamor_track_stipple(gc);
273
274 return pixmap;
275
276 bail_gc:
277 FreeScratchGC(scratch_gc);
278 bail_pixmap:
279 glamor_destroy_pixmap(pixmap);
280 bail:
281 return NULL;
282 }
283
284 Bool
glamor_set_stippled(PixmapPtr pixmap,GCPtr gc,GLint fg_uniform,GLint offset_uniform,GLint size_uniform)285 glamor_set_stippled(PixmapPtr pixmap,
286 GCPtr gc,
287 GLint fg_uniform,
288 GLint offset_uniform,
289 GLint size_uniform)
290 {
291 PixmapPtr stipple;
292
293 stipple = glamor_get_stipple_pixmap(gc);
294 if (!stipple)
295 return FALSE;
296
297 if (!glamor_set_solid(pixmap, gc, TRUE, fg_uniform))
298 return FALSE;
299
300 return glamor_set_texture(stipple,
301 FALSE,
302 -gc->patOrg.x,
303 -gc->patOrg.y,
304 offset_uniform,
305 size_uniform);
306 }
307