xref: /OK3568_Linux_fs/external/xserver/glamor/glamor_transform.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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