glamor_copyarea.c 13.3 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
/*
 * 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.
22 23 24 25
 *
 * Authors:
 *    Eric Anholt <eric@anholt.net>
 *    Zhigang Gong <zhigang.gong@linux.intel.com>
26 27 28 29 30 31 32 33
 */

#include "glamor_priv.h"

/** @file glamor_copyarea.c
 *
 * GC CopyArea implementation
 */
34
#ifndef GLAMOR_GLES2
35 36 37
static Bool
glamor_copy_n_to_n_fbo_blit(DrawablePtr src,
			    DrawablePtr dst,
Zhigang Gong's avatar
Zhigang Gong committed
38
			    GCPtr gc, BoxPtr box, int nbox, int dx, int dy)
39
{
Zhigang Gong's avatar
Zhigang Gong committed
40 41 42 43 44 45
	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;
	glamor_screen_private *glamor_priv =
	    glamor_get_screen_private(screen);
Chris Wilson's avatar
Chris Wilson committed
46
	glamor_gl_dispatch *dispatch;
Zhigang Gong's avatar
Zhigang Gong committed
47 48 49 50 51 52
	int dst_x_off, dst_y_off, src_x_off, src_y_off, i;

	if (!glamor_priv->has_fbo_blit) {
		glamor_delayed_fallback(screen,
					"no EXT_framebuffer_blit\n");
		return FALSE;
53
	}
Zhigang Gong's avatar
Zhigang Gong committed
54 55 56 57 58 59 60 61 62 63 64 65
	src_pixmap_priv = glamor_get_pixmap_private(src_pixmap);

	if (gc) {
		if (gc->alu != GXcopy) {
			glamor_delayed_fallback(screen, "non-copy ALU\n");
			return FALSE;
		}
		if (!glamor_pm_is_solid(dst, gc->planemask)) {
			glamor_delayed_fallback(screen,
						"non-solid planemask\n");
			return FALSE;
		}
66 67
	}

Zhigang Gong's avatar
Zhigang Gong committed
68 69 70 71
	if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(src_pixmap_priv)) {
		glamor_delayed_fallback(screen, "no src fbo\n");
		return FALSE;
	}
72

73
	if (glamor_set_destination_pixmap(dst_pixmap))
Zhigang Gong's avatar
Zhigang Gong committed
74 75
		return FALSE;

Chris Wilson's avatar
Chris Wilson committed
76
	dispatch = glamor_get_dispatch(glamor_priv);
Zhigang Gong's avatar
Zhigang Gong committed
77
	dispatch->glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT,
78
				    src_pixmap_priv->fbo->fb);
Zhigang Gong's avatar
Zhigang Gong committed
79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
	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++) {
		if (glamor_priv->yInverted) {
			dispatch->glBlitFramebuffer((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 {
			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);

			dispatch->glBlitFramebuffer(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);
		}
134
	}
Chris Wilson's avatar
Chris Wilson committed
135
	glamor_put_dispatch(glamor_priv);
Zhigang Gong's avatar
Zhigang Gong committed
136
	return TRUE;
137
}
138
#endif
139

140 141
static Bool
glamor_copy_n_to_n_textured(DrawablePtr src,
Zhigang Gong's avatar
Zhigang Gong committed
142 143
			    DrawablePtr dst,
			    GCPtr gc, BoxPtr box, int nbox, int dx, int dy)
144
{
Zhigang Gong's avatar
Zhigang Gong committed
145 146
	glamor_screen_private *glamor_priv =
	    glamor_get_screen_private(dst->pScreen);
Chris Wilson's avatar
Chris Wilson committed
147
	glamor_gl_dispatch *dispatch;
Zhigang Gong's avatar
Zhigang Gong committed
148 149 150 151 152 153 154 155 156
	PixmapPtr src_pixmap = glamor_get_drawable_pixmap(src);
	PixmapPtr dst_pixmap = glamor_get_drawable_pixmap(dst);
	int i;
	float vertices[8], texcoords[8];
	glamor_pixmap_private *src_pixmap_priv;
	glamor_pixmap_private *dst_pixmap_priv;
	int src_x_off, src_y_off, dst_x_off, dst_y_off;
	enum glamor_pixmap_status src_status = GLAMOR_NONE;
	GLfloat dst_xscale, dst_yscale, src_xscale, src_yscale;
Chris Wilson's avatar
Chris Wilson committed
157
	int alu = GXcopy;
Zhigang Gong's avatar
Zhigang Gong committed
158 159 160 161 162 163

	src_pixmap_priv = glamor_get_pixmap_private(src_pixmap);
	dst_pixmap_priv = glamor_get_pixmap_private(dst_pixmap);

	if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(dst_pixmap_priv)) {
		glamor_delayed_fallback(dst->pScreen, "dst has no fbo.\n");
Chris Wilson's avatar
Chris Wilson committed
164
		return FALSE;
Zhigang Gong's avatar
Zhigang Gong committed
165 166
	}

167
	if (!src_pixmap_priv || !src_pixmap_priv->gl_fbo) {
168
#ifndef GLAMOR_PIXMAP_DYNAMIC_UPLOAD
Zhigang Gong's avatar
Zhigang Gong committed
169
		glamor_delayed_fallback(dst->pScreen, "src has no fbo.\n");
Chris Wilson's avatar
Chris Wilson committed
170
		return FALSE;
171
#else
Zhigang Gong's avatar
Zhigang Gong committed
172 173
		src_status = glamor_upload_pixmap_to_texture(src_pixmap);
		if (src_status != GLAMOR_UPLOAD_DONE)
Chris Wilson's avatar
Chris Wilson committed
174
			return FALSE;
175 176

		src_pixmap_priv = glamor_get_pixmap_private(src_pixmap);
177
#endif
178
	}
Zhigang Gong's avatar
Zhigang Gong committed
179 180 181

	if (gc) {
		if (!glamor_set_planemask(dst_pixmap, gc->planemask))
Chris Wilson's avatar
Chris Wilson committed
182 183
			return FALSE;
		alu = gc->alu;
Zhigang Gong's avatar
Zhigang Gong committed
184
	}
185

Zhigang Gong's avatar
Zhigang Gong committed
186 187
	pixmap_priv_get_scale(dst_pixmap_priv, &dst_xscale, &dst_yscale);
	pixmap_priv_get_scale(src_pixmap_priv, &src_xscale, &src_yscale);
188

Zhigang Gong's avatar
Zhigang Gong committed
189 190
	glamor_get_drawable_deltas(dst, dst_pixmap, &dst_x_off,
				   &dst_y_off);
191

Chris Wilson's avatar
Chris Wilson committed
192 193
	dispatch = glamor_get_dispatch(glamor_priv);

194 195 196 197 198
	if (!glamor_set_alu(dispatch, alu)) {
		glamor_put_dispatch(glamor_priv);
		return FALSE;
	}

Chris Wilson's avatar
Chris Wilson committed
199
	glamor_set_destination_pixmap_priv_nc(dst_pixmap_priv);
Zhigang Gong's avatar
Zhigang Gong committed
200 201 202 203
	dispatch->glVertexAttribPointer(GLAMOR_VERTEX_POS, 2, GL_FLOAT,
					GL_FALSE, 2 * sizeof(float),
					vertices);
	dispatch->glEnableVertexAttribArray(GLAMOR_VERTEX_POS);
204

205 206 207 208 209 210
	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);
211

212 213 214
	dispatch->glActiveTexture(GL_TEXTURE0);
	dispatch->glBindTexture(GL_TEXTURE_2D,
				src_pixmap_priv->fbo->tex);
215
#ifndef GLAMOR_GLES2
216 217 218 219 220 221 222
	dispatch->glEnable(GL_TEXTURE_2D);
	dispatch->glTexParameteri(GL_TEXTURE_2D,
				  GL_TEXTURE_WRAP_S,
				  GL_CLAMP_TO_BORDER);
	dispatch->glTexParameteri(GL_TEXTURE_2D,
				  GL_TEXTURE_WRAP_T,
				  GL_CLAMP_TO_BORDER);
223
#endif
224 225 226 227 228 229
	dispatch->glTexParameteri(GL_TEXTURE_2D,
				  GL_TEXTURE_MIN_FILTER,
				  GL_NEAREST);
	dispatch->glTexParameteri(GL_TEXTURE_2D,
				  GL_TEXTURE_MAG_FILTER,
				  GL_NEAREST);
Zhigang Gong's avatar
Zhigang Gong committed
230

231 232 233 234 235 236 237 238 239 240
	dispatch->glVertexAttribPointer(GLAMOR_VERTEX_SOURCE, 2,
					GL_FLOAT, GL_FALSE,
					2 * sizeof(float),
					texcoords);
	dispatch->glEnableVertexAttribArray(GLAMOR_VERTEX_SOURCE);
	dispatch->glUseProgram(glamor_priv->finish_access_prog[0]);
	dispatch->glUniform1i(glamor_priv->finish_access_revert[0],
			      REVERT_NONE);
	dispatch->glUniform1i(glamor_priv->finish_access_swap_rb[0],
			      SWAP_NONE_UPLOADING);
Zhigang Gong's avatar
Zhigang Gong committed
241 242 243 244 245 246 247 248 249 250 251

	for (i = 0; i < nbox; i++) {

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

252 253 254 255 256 257 258 259
		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);
Zhigang Gong's avatar
Zhigang Gong committed
260 261 262 263
		dispatch->glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
	}

	dispatch->glDisableVertexAttribArray(GLAMOR_VERTEX_POS);
264
	dispatch->glDisableVertexAttribArray(GLAMOR_VERTEX_SOURCE);
265
#ifndef GLAMOR_GLES2
266
	dispatch->glDisable(GL_TEXTURE_2D);
267
#endif
Zhigang Gong's avatar
Zhigang Gong committed
268 269
	dispatch->glUseProgram(0);
	/* The source texture is bound to a fbo, we have to flush it here. */
Chris Wilson's avatar
Chris Wilson committed
270
	glamor_put_dispatch(glamor_priv);
Zhigang Gong's avatar
Zhigang Gong committed
271
	return TRUE;
272
}
273

274 275 276 277 278 279 280 281 282 283 284
static Bool 
_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, Bool fallback)
285
{
Zhigang Gong's avatar
Zhigang Gong committed
286 287 288 289
	glamor_access_t dst_access;
	PixmapPtr dst_pixmap, src_pixmap, temp_pixmap = NULL;
	DrawablePtr temp_src = src;
	glamor_pixmap_private *dst_pixmap_priv, *src_pixmap_priv;
Zhigang Gong's avatar
Zhigang Gong committed
290
	glamor_screen_private *glamor_priv;
Zhigang Gong's avatar
Zhigang Gong committed
291 292 293 294 295 296 297
	BoxRec bound;
	ScreenPtr screen;
	int temp_dx = dx;
	int temp_dy = dy;
	int src_x_off, src_y_off, dst_x_off, dst_y_off;
	int i;
	int overlaped = 0;
Zhigang Gong's avatar
Zhigang Gong committed
298
	Bool ret = FALSE;
Zhigang Gong's avatar
Zhigang Gong committed
299

300 301
	if (nbox == 0)
		return TRUE;
Zhigang Gong's avatar
Zhigang Gong committed
302 303 304 305 306
	dst_pixmap = glamor_get_drawable_pixmap(dst);
	dst_pixmap_priv = glamor_get_pixmap_private(dst_pixmap);
	src_pixmap = glamor_get_drawable_pixmap(src);
	src_pixmap_priv = glamor_get_pixmap_private(src_pixmap);
	screen = dst_pixmap->drawable.pScreen;
Zhigang Gong's avatar
Zhigang Gong committed
307 308
	glamor_priv = glamor_get_screen_private(dst->pScreen);

309
	if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(dst_pixmap_priv)) {
Zhigang Gong's avatar
Zhigang Gong committed
310 311 312 313 314
		glamor_fallback("dest pixmap %p has no fbo. \n",
				dst_pixmap);
		goto fail;
	}

315 316 317 318 319
	if (!src_pixmap_priv) {
		glamor_set_pixmap_type(src_pixmap, GLAMOR_MEMORY);
		src_pixmap_priv = glamor_get_pixmap_private(src_pixmap);
	}

Zhigang Gong's avatar
Zhigang Gong committed
320 321 322 323 324
	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);

325
	if (src_pixmap_priv->fbo && src_pixmap_priv->fbo->fb == dst_pixmap_priv->fbo->fb) {
Zhigang Gong's avatar
Zhigang Gong committed
326 327 328 329 330 331 332 333 334 335
		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;
			}
		}
	}
336
#ifndef GLAMOR_GLES2
Zhigang Gong's avatar
Zhigang Gong committed
337 338 339 340
	if ((overlaped
	     || !src_pixmap_priv->gl_tex || !dst_pixmap_priv->gl_tex)
	    && glamor_copy_n_to_n_fbo_blit(src, dst, gc, box, nbox, dx,
					   dy)) {
Zhigang Gong's avatar
Zhigang Gong committed
341
		ret = TRUE;
Zhigang Gong's avatar
Zhigang Gong committed
342 343
		goto done;
	}
344
#endif
Zhigang Gong's avatar
Zhigang Gong committed
345 346 347 348 349 350 351 352 353
	glamor_calculate_boxes_bound(&bound, box, nbox);

	/*  Overlaped indicate the src and dst are the same pixmap. */
	if (overlaped || (!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))) {

354 355 356 357 358 359 360
		temp_pixmap = glamor_create_pixmap(screen,
						   bound.x2 - bound.x1,
						   bound.y2 - bound.y1,
						   src_pixmap->
						   drawable.depth,
						   overlaped ? 0 :
						   GLAMOR_CREATE_PIXMAP_CPU);
Zhigang Gong's avatar
Zhigang Gong committed
361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385
		if (!temp_pixmap)
			goto fail;
		glamor_transform_boxes(box, nbox, -bound.x1, -bound.y1);
		temp_src = &temp_pixmap->drawable;

		if (overlaped)
			glamor_copy_n_to_n_textured(src, temp_src, gc, box,
						    nbox,
						    temp_dx + bound.x1,
						    temp_dy + bound.y1);
		else
			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;
	} else {
		temp_dx = dx;
		temp_dy = dy;
		temp_src = src;
	}

	if (glamor_copy_n_to_n_textured
	    (temp_src, dst, gc, box, nbox, temp_dx, temp_dy)) {
Zhigang Gong's avatar
Zhigang Gong committed
386
		ret = TRUE;
Zhigang Gong's avatar
Zhigang Gong committed
387 388 389 390 391
		goto done;
	}


      fail:
392
	
393 394
	if (!fallback 
	    && glamor_ddx_fallback_check_pixmap(src)
Zhigang Gong's avatar
Zhigang Gong committed
395
	    && glamor_ddx_fallback_check_pixmap(dst))
396 397
		goto done;

398 399 400 401 402 403 404
	if (src_pixmap_priv->type == GLAMOR_DRM_ONLY
	    || dst_pixmap_priv->type == GLAMOR_DRM_ONLY) {
		LogMessage(X_WARNING,
			   "Access a DRM only pixmap is not allowed within glamor.\n",
			   dst->pScreen->myNum);
		return TRUE;
	}
Zhigang Gong's avatar
Zhigang Gong committed
405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423
	glamor_report_delayed_fallbacks(src->pScreen);
	glamor_report_delayed_fallbacks(dst->pScreen);

	glamor_fallback("from %p to %p (%c,%c)\n", src, dst,
			glamor_get_drawable_location(src),
			glamor_get_drawable_location(dst));

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

	if (glamor_prepare_access(dst, GLAMOR_ACCESS_RW)) {
		if (dst == src
		    || glamor_prepare_access(src, GLAMOR_ACCESS_RO)) {
			fbCopyNtoN(src, dst, gc, box, nbox,
				   dx, dy, reverse, upsidedown, bitplane,
				   closure);
			if (dst != src)
424
				glamor_finish_access(src, GLAMOR_ACCESS_RO);
Zhigang Gong's avatar
Zhigang Gong committed
425
		}
426
		glamor_finish_access(dst, GLAMOR_ACCESS_RW);
Zhigang Gong's avatar
Zhigang Gong committed
427
	}
Zhigang Gong's avatar
Zhigang Gong committed
428
	ret = TRUE;
Zhigang Gong's avatar
Zhigang Gong committed
429 430 431 432

      done:
	glamor_clear_delayed_fallbacks(src->pScreen);
	glamor_clear_delayed_fallbacks(dst->pScreen);
433 434
	if (temp_src != src)
		glamor_destroy_pixmap(temp_pixmap);
435
	return ret;
436 437 438 439
}

RegionPtr
glamor_copy_area(DrawablePtr src, DrawablePtr dst, GCPtr gc,
Zhigang Gong's avatar
Zhigang Gong committed
440 441
		 int srcx, int srcy, int width, int height, int dstx,
		 int dsty)
442
{
Zhigang Gong's avatar
Zhigang Gong committed
443 444 445 446
	RegionPtr region;
	region = miDoCopy(src, dst, gc,
			  srcx, srcy, width, height,
			  dstx, dsty, glamor_copy_n_to_n, 0, NULL);
447

Zhigang Gong's avatar
Zhigang Gong committed
448
	return region;
449
}
450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482

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)
{
	_glamor_copy_n_to_n(src, dst, gc, box, nbox, dx, 
			    dy, reverse, upsidedown, bitplane, closure, TRUE);
}

Bool
glamor_copy_n_to_n_nf(DrawablePtr src,
		   DrawablePtr dst,
		   GCPtr gc,
		   BoxPtr box,
		   int nbox,
		   int dx,
		   int dy,
		   Bool reverse,
		   Bool upsidedown, Pixel bitplane, 
		   void *closure)
{
	return _glamor_copy_n_to_n(src, dst, gc, box, nbox, dx, 
				    dy, reverse, upsidedown, bitplane, closure, FALSE);
}