glamor_copyarea.c 11.5 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
35
36
37
38
39
40
41
42
43
44
45
46
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;
47
    glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
48
49
50
    int dst_x_off, dst_y_off, src_x_off, src_y_off, i;

    if (!GLEW_EXT_framebuffer_blit) {
51
	glamor_delayed_fallback(screen,"no EXT_framebuffer_blit\n");
52
	return FALSE;
53
    }
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
82
83
84
85
86
    glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, src_pixmap_priv->fb);

    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
88
89
90
91
92
93
94
95
96
97
98
      if(glamor_priv->yInverted) {
	glBlitFramebufferEXT((box[i].x1 + dx + src_x_off),
                             (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
104
105
106
107
108
109
110
111
112
113
	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);

	glBlitFramebufferEXT(box[i].x1 + dx + src_x_off,
			     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
118
    }
    return TRUE;
}

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

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

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

149
    if (!src_pixmap_priv->gl_fbo) {
150
151
152
153
154
155
#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) 
156
	goto fail;
157
158
#endif
    }
159
160
    else
      flush_needed = 1;
161
162
163
164

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

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

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

178

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

181
182
183

    glVertexPointer(2, GL_FLOAT, sizeof(float) * 2, vertices);
    glEnableClientState(GL_VERTEX_ARRAY);
184

185
186
187
188
189
190
191
192
193
194
195
196
197
198
    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);
      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);

      glClientActiveTexture(GL_TEXTURE0);
      glTexCoordPointer(2, GL_FLOAT, sizeof(float) * 2, texcoords);
      glEnableClientState(GL_TEXTURE_COORD_ARRAY);
199
      glUseProgram(glamor_priv->finish_access_prog[0]);
200
201
202
203
204
    } 
    else {
      GLAMOR_CHECK_PENDING_FILL(glamor_priv, src_pixmap_priv);
   }
 
205
    for (i = 0; i < nbox; i++) {
206

207
208
209
210
211
212
213
214
      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);

215
216
217
218
219
220
      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);
221
222

      glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
223
224
    }

225
    glUseProgram(0);
226
227

    glDisableClientState(GL_VERTEX_ARRAY);
228
229
230
231
    if (GLAMOR_PIXMAP_PRIV_NO_PENDING(src_pixmap_priv)) {
      glDisableClientState(GL_TEXTURE_COORD_ARRAY);
      glDisable(GL_TEXTURE_2D);
    }
232
233
234
    /* The source texture is bound to a fbo, we have to flush it here. */
    if (flush_needed) 
      glFlush();
235
    return TRUE;
236

237
238
239
240
241
fail:
    glamor_set_alu(GXcopy);
    glamor_set_planemask(dst_pixmap, ~0);
    return FALSE;
}
242

243
244
245
246
247
248
249
250
251
252
253
254
255
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)
{
256
    glamor_access_t dst_access;
257
    PixmapPtr dst_pixmap, src_pixmap, temp_pixmap = NULL;
258
259
260
261
262
263
    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;
264
265
266
267
    int src_x_off, src_y_off, dst_x_off, dst_y_off;
    int i;
    int overlaped = 0;
    
268
269
    dst_pixmap = glamor_get_drawable_pixmap(dst);
    dst_pixmap_priv = glamor_get_pixmap_private(dst_pixmap);
270
271
    src_pixmap = glamor_get_drawable_pixmap(src);
    src_pixmap_priv = glamor_get_pixmap_private(src_pixmap);
272
273
274
275
276
277
278
    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;
    }

279
280
281
282
283
284
285
286
287
288
289
290
291
292
    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;
         }
        }
293
    }
294
    /* XXX need revisit to handle overlapped area copying. */
295

Zhigang Gong's avatar
Zhigang Gong committed
296
297
    if ((overlaped 
          || !src_pixmap_priv->gl_tex  || !dst_pixmap_priv->gl_tex )
298
        && glamor_copy_n_to_n_fbo_blit(src, dst, gc, box, nbox, dx, dy)) {
299
        goto done;
300
	return;
301
    }
302
303
304
305
306
307
308
309
310
311
312
313

    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);
314
      if (!temp_pixmap)
315
316
	goto fail;
      glamor_transform_boxes(box, nbox, -bound.x1, -bound.y1);
317
      temp_src = &temp_pixmap->drawable;
318
319
320
321
322
323
324
      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;
325
    }
326
327
328
329
330
    else {
      temp_dx = dx;
      temp_dy = dy;
      temp_src = src;
    }
331

332
333
334
    if (glamor_copy_n_to_n_textured(temp_src, dst, gc, box, nbox, temp_dx, temp_dy)) {
        goto done;
    }
335

336
337
    
 fail:
338
    glamor_report_delayed_fallbacks(src->pScreen);
339
    glamor_report_delayed_fallbacks(dst->pScreen);
340

341
    glamor_fallback("from %p to %p (%c,%c)\n", src, dst,
342
343
		    glamor_get_drawable_location(src),
		    glamor_get_drawable_location(dst));
344
345
346
347
348
349

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

350
    if (glamor_prepare_access(dst, GLAMOR_ACCESS_RW)) {
351
352
	if (dst == src 
            || glamor_prepare_access(src, GLAMOR_ACCESS_RO)) {
353
354
355
	    fbCopyNtoN(src, dst, gc, box, nbox,
		       dx, dy, reverse, upsidedown, bitplane,
		       closure);
356
357
            if (dst != src)
	      glamor_finish_access(src);
358
359
360
	}
	glamor_finish_access(dst);
    }
361
362
363
364

done:
    glamor_clear_delayed_fallbacks(src->pScreen);
    glamor_clear_delayed_fallbacks(dst->pScreen);
365
366
367
    if (temp_src != src) {
      (*screen->DestroyPixmap)(temp_pixmap);
    }
368
369
370
371
372
373
374
375
376
377
378
379
380
}

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;
}