glamor_copyarea.c 11.7 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
/*
 * Copyright © 2008 Intel Corporation
 * Copyright © 1998 Keith Packard
 *
 * Permission to use, copy, modify, distribute, and sell this software and its
 * documentation for any purpose is hereby granted without fee, provided that
 * the above copyright notice appear in all copies and that both that
 * copyright notice and this permission notice appear in supporting
 * documentation, and that the name of Keith Packard not be used in
 * advertising or publicity pertaining to distribution of the software without
 * specific, written prior permission.  Keith Packard makes no
 * representations about the suitability of this software for any purpose.  It
 * is provided "as is" without express or implied warranty.
 *
 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 * PERFORMANCE OF THIS SOFTWARE.
 */

#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#endif

#include "glamor_priv.h"

/** @file glamor_copyarea.c
 *
 * GC CopyArea implementation
 */
34
#ifndef GLAMOR_GLES2
35
36
37
38
39
40
41
42
43
44
45
46
47
static Bool
glamor_copy_n_to_n_fbo_blit(DrawablePtr src,
			    DrawablePtr dst,
			    GCPtr gc,
			    BoxPtr box,
			    int nbox,
			    int dx,
			    int dy)
{
    ScreenPtr screen = dst->pScreen;
    PixmapPtr dst_pixmap = glamor_get_drawable_pixmap(dst);
    PixmapPtr src_pixmap = glamor_get_drawable_pixmap(src);
    glamor_pixmap_private *src_pixmap_priv;
48
    glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
49
50
    int dst_x_off, dst_y_off, src_x_off, src_y_off, i;

Zhigang Gong's avatar
Zhigang Gong committed
51
    if (!glamor_priv->has_fbo_blit) {
52
	glamor_delayed_fallback(screen,"no EXT_framebuffer_blit\n");
53
	return FALSE;
54
    }
55
56
    src_pixmap_priv = glamor_get_pixmap_private(src_pixmap);

57
58
59
    if (src_pixmap_priv->pending_op.type == GLAMOR_PENDING_FILL) 
      return FALSE;

60
61
    if (gc) {
	if (gc->alu != GXcopy) {
62
	    glamor_delayed_fallback(screen, "non-copy ALU\n");
63
64
65
	    return FALSE;
	}
	if (!glamor_pm_is_solid(dst, gc->planemask)) {
66
	    glamor_delayed_fallback(screen, "non-solid planemask\n");
67
68
69
70
	    return FALSE;
	}
    }

71
72
73
74
    if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(src_pixmap_priv)) {
        glamor_delayed_fallback(screen, "no src fbo\n");
        return FALSE;
    }
75

76
77
78
    if (glamor_set_destination_pixmap(dst_pixmap)) {
	return FALSE;
    }
79
    glamor_validate_pixmap(dst_pixmap);
80

81
    glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, src_pixmap_priv->fb);
82
83
84
85
86
    glamor_get_drawable_deltas(dst, dst_pixmap, &dst_x_off, &dst_y_off);
    glamor_get_drawable_deltas(src, src_pixmap, &src_x_off, &src_y_off);
    src_y_off += dy;

    for (i = 0; i < nbox; i++) {
87
      if(glamor_priv->yInverted) {
Zhigang Gong's avatar
Zhigang Gong committed
88
	glBlitFramebuffer((box[i].x1 + dx + src_x_off),
89
90
91
92
93
94
95
96
97
98
                             (box[i].y1 + src_y_off),
			     (box[i].x2 + dx + src_x_off),
			     (box[i].y2 + src_y_off),
                             (box[i].x1 + dst_x_off),
                             (box[i].y1 + dst_y_off),
			     (box[i].x2 + dst_x_off),
			     (box[i].y2 + dst_y_off),
			     GL_COLOR_BUFFER_BIT,
			     GL_NEAREST);
       } else {
99
100
101
102
103
	int flip_dst_y1 = dst_pixmap->drawable.height - (box[i].y2 + dst_y_off);
	int flip_dst_y2 = dst_pixmap->drawable.height - (box[i].y1 + dst_y_off);
	int flip_src_y1 = src_pixmap->drawable.height - (box[i].y2 + src_y_off);
	int flip_src_y2 = src_pixmap->drawable.height - (box[i].y1 + src_y_off);

Zhigang Gong's avatar
Zhigang Gong committed
104
	glBlitFramebuffer(box[i].x1 + dx + src_x_off,
105
106
107
108
109
110
111
112
113
			     flip_src_y1,
			     box[i].x2 + dx + src_x_off,
			     flip_src_y2,
			     box[i].x1 + dst_x_off,
			     flip_dst_y1,
			     box[i].x2 + dst_x_off,
			     flip_dst_y2,
			     GL_COLOR_BUFFER_BIT,
			     GL_NEAREST);
114
	}
115
116
117
    }
    return TRUE;
}
118
#endif
119

120
121
122
123
124
125
126
127
static Bool
glamor_copy_n_to_n_textured(DrawablePtr src,
			      DrawablePtr dst,
			      GCPtr gc,
			      BoxPtr box,
			      int nbox,
			      int dx,
			      int dy)
128
{
129
130
    glamor_screen_private *glamor_priv =
	glamor_get_screen_private(dst->pScreen);
131
132
133
    PixmapPtr src_pixmap = glamor_get_drawable_pixmap(src);
    PixmapPtr dst_pixmap = glamor_get_drawable_pixmap(dst);
    int i;
134
    float vertices[8], texcoords[8];
135
    glamor_pixmap_private *src_pixmap_priv;
136
    glamor_pixmap_private *dst_pixmap_priv;
137
    int src_x_off, src_y_off, dst_x_off, dst_y_off;
138
    enum glamor_pixmap_status src_status = GLAMOR_NONE;
139
    GLfloat dst_xscale, dst_yscale, src_xscale, src_yscale;
140
    int flush_needed = 0;
141

142
    src_pixmap_priv = glamor_get_pixmap_private(src_pixmap);
143
    dst_pixmap_priv = glamor_get_pixmap_private(dst_pixmap);
144

145
146
147
    if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(dst_pixmap_priv)) {
        glamor_delayed_fallback(dst->pScreen, "dst has no fbo.\n");
        goto fail;
148
149
    }

150
    if (!src_pixmap_priv->gl_fbo) {
151
152
153
154
155
156
#ifndef GLAMOR_PIXMAP_DYNAMIC_UPLOAD
	glamor_delayed_fallback(dst->pScreen, "src has no fbo.\n");
	goto fail;
#else
        src_status = glamor_upload_pixmap_to_texture(src_pixmap);
	if (src_status != GLAMOR_UPLOAD_DONE) 
157
	goto fail;
158
159
#endif
    }
160
161
    else
      flush_needed = 1;
162
163
164
165

    if (gc) {
	glamor_set_alu(gc->alu);
	if (!glamor_set_planemask(dst_pixmap, gc->planemask))
166
	  goto fail;
167
168
169
170
        if (gc->alu != GXcopy) {
          glamor_set_destination_pixmap_priv_nc(src_pixmap_priv);
          glamor_validate_pixmap(src_pixmap);
        }
171
172
    }

173
    glamor_set_destination_pixmap_priv_nc(dst_pixmap_priv);
174
175
    glamor_validate_pixmap(dst_pixmap);

176
177
178
    pixmap_priv_get_scale(dst_pixmap_priv, &dst_xscale, &dst_yscale);
    pixmap_priv_get_scale(src_pixmap_priv, &src_xscale, &src_yscale);

179
180
    glamor_get_drawable_deltas(dst, dst_pixmap, &dst_x_off, &dst_y_off);

181

182
183
184
185
186

    glVertexAttribPointer(GLAMOR_VERTEX_POS, 2, GL_FLOAT, GL_FALSE, 
                          2 * sizeof(float),
                          vertices);
    glEnableVertexAttribArray(GLAMOR_VERTEX_POS);
187

188
189
190
191
192
    if (GLAMOR_PIXMAP_PRIV_NO_PENDING(src_pixmap_priv)) {
      glamor_get_drawable_deltas(src, src_pixmap, &src_x_off, &src_y_off);
      dx += src_x_off;
      dy += src_y_off;
      pixmap_priv_get_scale(src_pixmap_priv, &src_xscale, &src_yscale);
193

194
195
196
197
198
      glActiveTexture(GL_TEXTURE0);
      glBindTexture(GL_TEXTURE_2D, src_pixmap_priv->tex);
      glEnable(GL_TEXTURE_2D);
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
199
200
201
202
203
 
      glVertexAttribPointer(GLAMOR_VERTEX_SOURCE, 2, GL_FLOAT, GL_FALSE, 
                            2 * sizeof(float),
                            texcoords);
      glEnableVertexAttribArray(GLAMOR_VERTEX_SOURCE);
204
      glUseProgram(glamor_priv->finish_access_prog[0]);
205
206
 
   } 
207
208
209
210
    else {
      GLAMOR_CHECK_PENDING_FILL(glamor_priv, src_pixmap_priv);
   }
 
211
    for (i = 0; i < nbox; i++) {
212

213
214
215
216
217
218
219
220
      glamor_set_normalize_vcoords(dst_xscale, dst_yscale, 
				   box[i].x1 + dst_x_off,
				   box[i].y1 + dst_y_off,
				   box[i].x2 + dst_x_off,
				   box[i].y2 + dst_y_off,
				   glamor_priv->yInverted,
				   vertices);

221
222
223
224
225
226
      if (GLAMOR_PIXMAP_PRIV_NO_PENDING(src_pixmap_priv))
        glamor_set_normalize_tcoords(src_xscale, src_yscale,
	  			     box[i].x1 + dx, box[i].y1 + dy,
				     box[i].x2 + dx, box[i].y2 + dy,
				     glamor_priv->yInverted,
				     texcoords);
227
228

      glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
229
230
    }

231
232
233
234
235
236
    glDisableVertexAttribArray(GLAMOR_VERTEX_POS);
    if (GLAMOR_PIXMAP_PRIV_NO_PENDING(src_pixmap_priv)) {
      glDisableVertexAttribArray(GLAMOR_VERTEX_SOURCE);
      glDisable(GL_TEXTURE_2D);
    }
    glUseProgram(0);
237
238
239
    /* The source texture is bound to a fbo, we have to flush it here. */
    if (flush_needed) 
      glFlush();
240
    return TRUE;
241

242
243
244
245
246
fail:
    glamor_set_alu(GXcopy);
    glamor_set_planemask(dst_pixmap, ~0);
    return FALSE;
}
247

248
249
250
251
252
253
254
255
256
257
258
259
260
void
glamor_copy_n_to_n(DrawablePtr src,
		 DrawablePtr dst,
		 GCPtr gc,
		 BoxPtr box,
		 int nbox,
		 int		dx,
		 int		dy,
		 Bool		reverse,
		 Bool		upsidedown,
		 Pixel		bitplane,
		 void		*closure)
{
261
    glamor_access_t dst_access;
262
    PixmapPtr dst_pixmap, src_pixmap, temp_pixmap = NULL;
263
264
265
266
267
268
    DrawablePtr temp_src = src;
    glamor_pixmap_private *dst_pixmap_priv, *src_pixmap_priv;
    BoxRec bound;
    ScreenPtr screen;
    int temp_dx = dx;
    int temp_dy = dy;
269
270
271
272
    int src_x_off, src_y_off, dst_x_off, dst_y_off;
    int i;
    int overlaped = 0;
    
273
274
    dst_pixmap = glamor_get_drawable_pixmap(dst);
    dst_pixmap_priv = glamor_get_pixmap_private(dst_pixmap);
275
276
    src_pixmap = glamor_get_drawable_pixmap(src);
    src_pixmap_priv = glamor_get_pixmap_private(src_pixmap);
277
278
279
280
281
282
283
    screen = dst_pixmap->drawable.pScreen;

    if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(dst_pixmap_priv)) {
      glamor_fallback("dest pixmap %p has no fbo. \n", dst_pixmap);
      goto fail;
    }

284
285
286
287
288
289
290
291
292
293
294
295
296
297
    glamor_get_drawable_deltas(src, src_pixmap, &src_x_off, &src_y_off);
    glamor_get_drawable_deltas(dst, dst_pixmap, &dst_x_off, &dst_y_off);

    if (src_pixmap_priv->fb == dst_pixmap_priv->fb) {
      int x_shift = abs(src_x_off - dx - dst_x_off);
      int y_shift = abs(src_y_off - dy - dst_y_off);
      for ( i = 0; i < nbox; i++)
        {
         if (x_shift < abs(box[i].x2 - box[i].x1) 
            && y_shift < abs(box[i].y2 - box[i].y1)) {
           overlaped = 1;
           break;
         }
        }
298
    }
299
    /* XXX need revisit to handle overlapped area copying. */
300

301
#ifndef GLAMOR_GLES2
Zhigang Gong's avatar
Zhigang Gong committed
302
303
    if ((overlaped 
          || !src_pixmap_priv->gl_tex  || !dst_pixmap_priv->gl_tex )
304
        && glamor_copy_n_to_n_fbo_blit(src, dst, gc, box, nbox, dx, dy)) {
305
        goto done;
306
	return;
307
    }
308
#endif
309
310
311
312
313
314
315
316
317
318
319
    glamor_calculate_boxes_bound(&bound, box, nbox);

    if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(src_pixmap_priv) 
	&& ((bound.x2 - bound.x1) * (bound.y2 - bound.y1)
	    * 4 > src_pixmap->drawable.width * src_pixmap->drawable.height)) {

      temp_pixmap = (*screen->CreatePixmap)(screen,
					 bound.x2 - bound.x1,
					 bound.y2 - bound.y1,
					 src_pixmap->drawable.depth,
					 GLAMOR_CREATE_PIXMAP_CPU);
320
      if (!temp_pixmap)
321
322
	goto fail;
      glamor_transform_boxes(box, nbox, -bound.x1, -bound.y1);
323
      temp_src = &temp_pixmap->drawable;
324
325
326
327
328
329
330
      fbCopyNtoN(src, temp_src, gc, box, nbox,
		 temp_dx + bound.x1, temp_dy + bound.y1, 
		 reverse, upsidedown, bitplane,
		 closure);
      glamor_transform_boxes(box, nbox, bound.x1, bound.y1);
      temp_dx = -bound.x1;
      temp_dy = -bound.y1;
331
    }
332
333
334
335
336
    else {
      temp_dx = dx;
      temp_dy = dy;
      temp_src = src;
    }
337

338
339
340
    if (glamor_copy_n_to_n_textured(temp_src, dst, gc, box, nbox, temp_dx, temp_dy)) {
        goto done;
    }
341

342
343
    
 fail:
344
    glamor_report_delayed_fallbacks(src->pScreen);
345
    glamor_report_delayed_fallbacks(dst->pScreen);
346

347
    glamor_fallback("from %p to %p (%c,%c)\n", src, dst,
348
349
		    glamor_get_drawable_location(src),
		    glamor_get_drawable_location(dst));
350
351
352
353
354
355

    if (gc && gc->alu != GXcopy)
      dst_access = GLAMOR_ACCESS_RW;
    else
      dst_access = GLAMOR_ACCESS_WO;

356
    if (glamor_prepare_access(dst, GLAMOR_ACCESS_RW)) {
357
358
	if (dst == src 
            || glamor_prepare_access(src, GLAMOR_ACCESS_RO)) {
359
360
361
	    fbCopyNtoN(src, dst, gc, box, nbox,
		       dx, dy, reverse, upsidedown, bitplane,
		       closure);
362
363
            if (dst != src)
	      glamor_finish_access(src);
364
365
366
	}
	glamor_finish_access(dst);
    }
367
368
369
370

done:
    glamor_clear_delayed_fallbacks(src->pScreen);
    glamor_clear_delayed_fallbacks(dst->pScreen);
371
372
373
    if (temp_src != src) {
      (*screen->DestroyPixmap)(temp_pixmap);
    }
374
375
376
377
378
379
380
381
382
383
384
385
386
}

RegionPtr
glamor_copy_area(DrawablePtr src, DrawablePtr dst, GCPtr gc,
		 int srcx, int srcy, int width, int height, int dstx, int dsty)
{
    RegionPtr region;
    region = miDoCopy(src, dst, gc,
		      srcx, srcy, width, height,
		      dstx, dsty, glamor_copy_n_to_n, 0, NULL);

    return region;
}