glamor_pixmap.c 32.9 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
/*
 * Copyright © 2001 Keith Packard
 * Copyright © 2008 Intel Corporation
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice (including the next
 * paragraph) shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 *
 * Authors:
 *    Eric Anholt <eric@anholt.net>
 *    Zhigang Gong <zhigang.gong@linux.intel.com>
 *
 */

30 31 32 33 34 35 36 37 38 39 40 41 42
#include <stdlib.h>

#include "glamor_priv.h"
/**
 * Sets the offsets to add to coordinates to make them address the same bits in
 * the backing drawable. These coordinates are nonzero only for redirected
 * windows.
 */
void
glamor_get_drawable_deltas(DrawablePtr drawable, PixmapPtr pixmap,
			   int *x, int *y)
{
#ifdef COMPOSITE
Zhigang Gong's avatar
Zhigang Gong committed
43 44 45 46 47
	if (drawable->type == DRAWABLE_WINDOW) {
		*x = -pixmap->screen_x;
		*y = -pixmap->screen_y;
		return;
	}
48 49
#endif

Zhigang Gong's avatar
Zhigang Gong committed
50 51
	*x = 0;
	*y = 0;
52 53
}

54 55 56 57

void
glamor_pixmap_init(ScreenPtr screen)
{
58

59 60
}

61 62 63 64 65
void
glamor_pixmap_fini(ScreenPtr screen)
{
}

66
void
67
glamor_set_destination_pixmap_fbo(glamor_pixmap_fbo * fbo)
68
{
69 70
	glamor_gl_dispatch *dispatch = glamor_get_dispatch(fbo->glamor_priv);
	dispatch->glBindFramebuffer(GL_FRAMEBUFFER, fbo->fb);
71
#ifndef GLAMOR_GLES2
Zhigang Gong's avatar
Zhigang Gong committed
72 73 74 75
	dispatch->glMatrixMode(GL_PROJECTION);
	dispatch->glLoadIdentity();
	dispatch->glMatrixMode(GL_MODELVIEW);
	dispatch->glLoadIdentity();
76
#endif
Zhigang Gong's avatar
Zhigang Gong committed
77
	dispatch->glViewport(0, 0,
78 79 80 81 82
			     fbo->width,
			     fbo->height);

	glamor_put_dispatch(fbo->glamor_priv);
}
83

84 85 86 87
void
glamor_set_destination_pixmap_priv_nc(glamor_pixmap_private * pixmap_priv)
{
	glamor_set_destination_pixmap_fbo(pixmap_priv->fbo);
88 89 90
}

int
Zhigang Gong's avatar
Zhigang Gong committed
91
glamor_set_destination_pixmap_priv(glamor_pixmap_private * pixmap_priv)
92
{
Zhigang Gong's avatar
Zhigang Gong committed
93 94
	if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv))
		return -1;
95

Zhigang Gong's avatar
Zhigang Gong committed
96 97
	glamor_set_destination_pixmap_priv_nc(pixmap_priv);
	return 0;
98 99 100 101 102
}

int
glamor_set_destination_pixmap(PixmapPtr pixmap)
{
Zhigang Gong's avatar
Zhigang Gong committed
103 104 105
	int err;
	glamor_pixmap_private *pixmap_priv =
	    glamor_get_pixmap_private(pixmap);
106

Zhigang Gong's avatar
Zhigang Gong committed
107 108
	err = glamor_set_destination_pixmap_priv(pixmap_priv);
	return err;
109 110 111 112 113
}

Bool
glamor_set_planemask(PixmapPtr pixmap, unsigned long planemask)
{
Zhigang Gong's avatar
Zhigang Gong committed
114 115 116
	if (glamor_pm_is_solid(&pixmap->drawable, planemask)) {
		return GL_TRUE;
	}
117

Zhigang Gong's avatar
Zhigang Gong committed
118 119
	glamor_fallback("unsupported planemask %lx\n", planemask);
	return GL_FALSE;
120 121
}

122
Bool
123
glamor_set_alu(struct glamor_gl_dispatch *dispatch, unsigned char alu)
124
{
125
#ifndef GLAMOR_GLES2
Zhigang Gong's avatar
Zhigang Gong committed
126 127
	if (alu == GXcopy) {
		dispatch->glDisable(GL_COLOR_LOGIC_OP);
128
		return TRUE;
Zhigang Gong's avatar
Zhigang Gong committed
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
	}
	dispatch->glEnable(GL_COLOR_LOGIC_OP);
	switch (alu) {
	case GXclear:
		dispatch->glLogicOp(GL_CLEAR);
		break;
	case GXand:
		dispatch->glLogicOp(GL_AND);
		break;
	case GXandReverse:
		dispatch->glLogicOp(GL_AND_REVERSE);
		break;
	case GXandInverted:
		dispatch->glLogicOp(GL_AND_INVERTED);
		break;
	case GXnoop:
		dispatch->glLogicOp(GL_NOOP);
		break;
	case GXxor:
		dispatch->glLogicOp(GL_XOR);
		break;
	case GXor:
		dispatch->glLogicOp(GL_OR);
		break;
	case GXnor:
		dispatch->glLogicOp(GL_NOR);
		break;
	case GXequiv:
		dispatch->glLogicOp(GL_EQUIV);
		break;
	case GXinvert:
		dispatch->glLogicOp(GL_INVERT);
		break;
	case GXorReverse:
		dispatch->glLogicOp(GL_OR_REVERSE);
		break;
	case GXcopyInverted:
		dispatch->glLogicOp(GL_COPY_INVERTED);
		break;
	case GXorInverted:
		dispatch->glLogicOp(GL_OR_INVERTED);
		break;
	case GXnand:
		dispatch->glLogicOp(GL_NAND);
		break;
	case GXset:
		dispatch->glLogicOp(GL_SET);
		break;
	default:
178 179
		glamor_fallback("unsupported alu %x\n", alu);
		return FALSE;
Zhigang Gong's avatar
Zhigang Gong committed
180
	}
181
#else
182
	if (alu != GXcopy)
183
		return FALSE;
184
#endif
185
	return TRUE;
186 187
}

188
void *
189
_glamor_color_convert_a1_a8(void *src_bits, void *dst_bits, int w, int h, int stride, int revert)
190 191 192 193 194
{
	void *bits;
	PictFormatShort dst_format, src_format;
	pixman_image_t *dst_image;
	pixman_image_t *src_image;
195
	int src_stride;
196 197 198 199

	if (revert == REVERT_UPLOADING_A1) {
		src_format = PICT_a1;
		dst_format = PICT_a8;
200
		src_stride = PixmapBytePad(w, 1);
201 202 203
	} else {
		dst_format = PICT_a1;
		src_format = PICT_a8;
204
		src_stride = (((w * 8 + 7) / 8) + 3) & ~3;
205 206 207 208
	}

	dst_image = pixman_image_create_bits(dst_format,
					     w, h,
209
					     dst_bits,
210 211 212 213 214 215 216 217 218
					     stride);
	if (dst_image == NULL) {
		free(bits);
		return NULL;
	}

	src_image = pixman_image_create_bits(src_format,
					     w, h,
					     src_bits,
219
					     src_stride);
220 221 222 223 224 225 226 227 228 229 230 231 232

	if (src_image == NULL) {
		pixman_image_unref(dst_image);
		free(bits);
		return NULL;
	}

	pixman_image_composite(PictOpSrc, src_image, NULL, dst_image,
			       0, 0, 0, 0, 0, 0,
			       w,h);

	pixman_image_unref(src_image);
	pixman_image_unref(dst_image);
233
	return dst_bits;
234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275
}

#define ADJUST_BITS(d, src_bits, dst_bits)	(((dst_bits) == (src_bits)) ? (d) : 				\
							(((dst_bits) > (src_bits)) ? 				\
							  (((d) << ((dst_bits) - (src_bits))) 			\
								   + (( 1 << ((dst_bits) - (src_bits))) >> 1))	\
								:  ((d) >> ((src_bits) - (dst_bits)))))

#define GLAMOR_DO_CONVERT(src, dst, no_alpha, swap,		\
			  a_shift_src, a_bits_src,		\
			  b_shift_src, b_bits_src,		\
			  g_shift_src, g_bits_src,		\
			  r_shift_src, r_bits_src,		\
			  a_shift, a_bits,			\
			  b_shift, b_bits,			\
			  g_shift, g_bits,			\
			  r_shift, r_bits)			\
	{								\
		typeof(src) a,b,g,r;					\
		typeof(src) a_mask_src, b_mask_src, g_mask_src, r_mask_src;\
		a_mask_src = (((1 << (a_bits_src)) - 1) << a_shift_src);\
		b_mask_src = (((1 << (b_bits_src)) - 1) << b_shift_src);\
		g_mask_src = (((1 << (g_bits_src)) - 1) << g_shift_src);\
		r_mask_src = (((1 << (r_bits_src)) - 1) << r_shift_src);\
		if (no_alpha)						\
			a = (a_mask_src) >> (a_shift_src);			\
		else							\
			a = ((src) & (a_mask_src)) >> (a_shift_src);	\
		b = ((src) & (b_mask_src)) >> (b_shift_src);		\
		g = ((src) & (g_mask_src)) >> (g_shift_src);		\
		r = ((src) & (r_mask_src)) >> (r_shift_src);		\
		a = ADJUST_BITS(a, a_bits_src, a_bits);			\
		b = ADJUST_BITS(b, b_bits_src, b_bits);			\
		g = ADJUST_BITS(g, g_bits_src, g_bits);			\
		r = ADJUST_BITS(r, r_bits_src, r_bits);			\
		if (swap == 0)						\
			(*dst) = ((a) << (a_shift)) | ((b) << (b_shift)) | ((g) << (g_shift)) | ((r) << (r_shift)); \
		else 												    \
			(*dst) = ((a) << (a_shift)) | ((r) << (b_shift)) | ((g) << (g_shift)) | ((b) << (r_shift)); \
	}

void *
276
_glamor_color_revert_x2b10g10r10(void *src_bits, void *dst_bits, int w, int h, int stride, int no_alpha, int revert, int swap_rb)
277 278 279 280 281 282
{
	int x,y;
	unsigned int *words, *saved_words, *source_words;
	int swap = !(swap_rb == SWAP_NONE_DOWNLOADING || swap_rb == SWAP_NONE_UPLOADING);

	source_words = src_bits;
283
	words = dst_bits;
284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312
	saved_words = words;

	for (y = 0; y < h; y++)
	{
		DEBUGF("Line %d :  ", y);
		for (x = 0; x < w; x++)
		{
			unsigned int pixel = source_words[x];

			if (revert == REVERT_DOWNLOADING_2_10_10_10)
				GLAMOR_DO_CONVERT(pixel, &words[x], no_alpha, swap,
						  24, 8, 16, 8, 8, 8, 0, 8,
						  30, 2, 20, 10, 10, 10, 0, 10)
			else
				GLAMOR_DO_CONVERT(pixel, &words[x], no_alpha, swap,
						  30, 2, 20, 10, 10, 10, 0, 10,
						  24, 8, 16, 8, 8, 8, 0, 8);
			DEBUGF("%x:%x ", pixel, words[x]);
		}
		DEBUGF("\n");
		words += stride / sizeof(*words);
		source_words += stride / sizeof(*words);
	}
	DEBUGF("\n");
	return saved_words;

}

void *
313
_glamor_color_revert_x1b5g5r5(void *src_bits, void *dst_bits, int w, int h, int stride, int no_alpha, int revert, int swap_rb)
314 315 316 317 318
{
	int x,y;
	unsigned short *words, *saved_words, *source_words;
	int swap = !(swap_rb == SWAP_NONE_DOWNLOADING || swap_rb == SWAP_NONE_UPLOADING);

319
	words = dst_bits;
320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346
	source_words = src_bits;
	saved_words = words;

	for (y = 0; y < h; y++)
	{
		DEBUGF("Line %d :  ", y);
		for (x = 0; x < w; x++)
		{
			unsigned short pixel = source_words[x];

			if (revert == REVERT_DOWNLOADING_1_5_5_5)
				GLAMOR_DO_CONVERT(pixel, &words[x], no_alpha, swap,
						  0, 1, 1, 5, 6, 5, 11, 5,
						  15, 1, 10, 5, 5, 5, 0, 5)
			else
				GLAMOR_DO_CONVERT(pixel, &words[x], no_alpha, swap,
						  15, 1, 10, 5, 5, 5, 0, 5,
						  0, 1, 1, 5, 6, 5, 11, 5);
			DEBUGF("%04x:%04x ", pixel, words[x]);
		}
		DEBUGF("\n");
		words += stride / sizeof(*words);
		source_words += stride / sizeof(*words);
	}
	DEBUGF("\n");
	return saved_words;
}
347

348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366
/*
 * This function is to convert an unsupported color format to/from a
 * supported GL format.
 * Here are the current scenarios:
 *
 * @no_alpha:
 * 	If it is set, then we need to wire the alpha value to 1.
 * @revert:
	REVERT_DOWNLOADING_A1		: convert an Alpha8 buffer to a A1 buffer.
	REVERT_UPLOADING_A1		: convert an A1 buffer to an Alpha8 buffer
	REVERT_DOWNLOADING_2_10_10_10 	: convert r10G10b10X2 to X2B10G10R10
	REVERT_UPLOADING_2_10_10_10 	: convert X2B10G10R10 to R10G10B10X2
	REVERT_DOWNLOADING_1_5_5_5  	: convert B5G5R5X1 to X1R5G5B5
	REVERT_UPLOADING_1_5_5_5    	: convert X1R5G5B5 to B5G5R5X1
   @swap_rb: if we have the swap_rb set, then we need to swap the R and B's position.
 *
 */

void *
367
glamor_color_convert_to_bits(void *src_bits, void *dst_bits, int w, int h, int stride, int no_alpha, int revert, int swap_rb)
368 369
{
	if (revert == REVERT_DOWNLOADING_A1 || revert == REVERT_UPLOADING_A1) {
370
		return _glamor_color_convert_a1_a8(src_bits, dst_bits, w, h, stride, revert);
371
	} else if (revert == REVERT_DOWNLOADING_2_10_10_10 || revert == REVERT_UPLOADING_2_10_10_10) {
372
		return _glamor_color_revert_x2b10g10r10(src_bits, dst_bits, w, h, stride, no_alpha, revert, swap_rb);
373
	} else if (revert == REVERT_DOWNLOADING_1_5_5_5 || revert == REVERT_UPLOADING_1_5_5_5) {
374
		return _glamor_color_revert_x1b5g5r5(src_bits, dst_bits, w, h, stride, no_alpha, revert, swap_rb);
375 376
	} else
		ErrorF("convert a non-supported mode %x.\n", revert);
377

378 379
	return NULL;
}
380 381 382 383 384

/**
 * Upload pixmap to a specified texture.
 * This texture may not be the one attached to it.
 **/
385
int in_restore = 0;
Zhigang Gong's avatar
Zhigang Gong committed
386
static void
387 388 389 390 391
__glamor_upload_pixmap_to_texture(PixmapPtr pixmap, int *tex,
				  GLenum format,
				  GLenum type,
				  int x, int y, int w, int h,
				  void *bits, int pbo)
392
{
Zhigang Gong's avatar
Zhigang Gong committed
393 394
	glamor_screen_private *glamor_priv =
	    glamor_get_screen_private(pixmap->drawable.pScreen);
Chris Wilson's avatar
Chris Wilson committed
395
	glamor_gl_dispatch *dispatch;
396 397
	int non_sub = 0;
	int iformat;
Zhigang Gong's avatar
Zhigang Gong committed
398

Chris Wilson's avatar
Chris Wilson committed
399
	dispatch = glamor_get_dispatch(glamor_priv);
400 401 402 403 404 405
	if (*tex == 0) {
		dispatch->glGenTextures(1, tex);
		if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP)
			gl_iformat_for_depth(pixmap->drawable.depth, &iformat);
		else
			iformat = format;
406 407 408
		non_sub = 1;
		assert(x == 0 && y == 0);
	}
409

410
	dispatch->glBindTexture(GL_TEXTURE_2D, *tex);
411 412 413 414
	dispatch->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
				  GL_NEAREST);
	dispatch->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
				  GL_NEAREST);
415
	dispatch->glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
Zhigang Gong's avatar
Zhigang Gong committed
416

417
	if (bits == NULL)
Zhigang Gong's avatar
Zhigang Gong committed
418
		dispatch->glBindBuffer(GL_PIXEL_UNPACK_BUFFER,
419
				       pbo);
420 421 422 423 424 425 426 427 428 429
	if (non_sub)
		dispatch->glTexImage2D(GL_TEXTURE_2D,
				       0, iformat, w, h, 0,
				       format, type,
				       bits);
	else
		dispatch->glTexSubImage2D(GL_TEXTURE_2D,
					  0, x, y, w, h,
					  format, type,
					  bits);
430

431
	if (bits == NULL)
432
		dispatch->glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
Chris Wilson's avatar
Chris Wilson committed
433
	glamor_put_dispatch(glamor_priv);
434 435
}

436 437 438 439 440
static Bool
_glamor_upload_bits_to_pixmap_texture(PixmapPtr pixmap, GLenum format, GLenum type,
				     int no_alpha, int revert,
				     int swap_rb, int x, int y, int w, int h,
				     int stride, void* bits, int pbo)
441
{
442 443
	glamor_pixmap_private *pixmap_priv = glamor_get_pixmap_private(pixmap);
	glamor_screen_private *glamor_priv = glamor_get_screen_private(pixmap->drawable.pScreen);
Chris Wilson's avatar
Chris Wilson committed
444
	glamor_gl_dispatch *dispatch;
445
	static float vertices[8];
Zhigang Gong's avatar
Zhigang Gong committed
446 447 448 449 450 451 452 453 454 455 456
	static float texcoords[8] = { 0, 1,
		1, 1,
		1, 0,
		0, 0
	};
	static float texcoords_inv[8] = { 0, 0,
		1, 0,
		1, 1,
		0, 1
	};
	float *ptexcoords;
457
	float dst_xscale, dst_yscale;
458
	GLuint tex = 0;
Zhigang Gong's avatar
Zhigang Gong committed
459
	int need_flip;
460
	int need_free_bits = 0;
461

462
	need_flip = !glamor_priv->yInverted;
Zhigang Gong's avatar
Zhigang Gong committed
463

464 465 466
	if (bits == NULL)
		goto ready_to_upload;

Zhigang Gong's avatar
Zhigang Gong committed
467
	if (revert > REVERT_NORMAL) {
468 469
		/* XXX if we are restoring the pixmap, then we may not need to allocate
		 * new buffer */
470 471 472 473 474 475 476
		void *converted_bits;

		if (pixmap->drawable.depth == 1)
			stride = (((w * 8 + 7) / 8) + 3) & ~3;

		converted_bits = malloc(h * stride);

477 478
		if (converted_bits == NULL)
			return FALSE;
479 480
		bits = glamor_color_convert_to_bits(bits, converted_bits, w, h,
						    stride,
481 482 483 484 485 486 487 488 489 490
						    no_alpha, revert, swap_rb);
		if (bits == NULL) {
			ErrorF("Failed to convert pixmap no_alpha %d, revert mode %d, swap mode %d\n", swap_rb);
			return FALSE;
		}
		no_alpha = 0;
		revert = REVERT_NONE;
		swap_rb = SWAP_NONE_UPLOADING;
		need_free_bits = TRUE;
	}
491

492
ready_to_upload:
Zhigang Gong's avatar
Zhigang Gong committed
493 494
	/* Try fast path firstly, upload the pixmap to the texture attached
	 * to the fbo directly. */
495 496 497 498
	if (no_alpha == 0
	    && revert == REVERT_NONE
	    && swap_rb == SWAP_NONE_UPLOADING
	    && !need_flip) {
499 500 501 502 503
		assert(pixmap_priv->fbo->tex);
		__glamor_upload_pixmap_to_texture(pixmap, &pixmap_priv->fbo->tex,
						  format, type,
						  x, y, w, h,
						  bits, pbo);
504
		return TRUE;
Zhigang Gong's avatar
Zhigang Gong committed
505 506 507 508 509 510 511
	}

	if (need_flip)
		ptexcoords = texcoords;
	else
		ptexcoords = texcoords_inv;

512 513 514
	pixmap_priv_get_scale(pixmap_priv, &dst_xscale, &dst_yscale);
	glamor_set_normalize_vcoords(dst_xscale,
				     dst_yscale,
515 516
				     x, y,
				     x + w, y + h,
517 518 519
				     glamor_priv->yInverted,
				     vertices);

Zhigang Gong's avatar
Zhigang Gong committed
520
	/* Slow path, we need to flip y or wire alpha to 1. */
Chris Wilson's avatar
Chris Wilson committed
521
	dispatch = glamor_get_dispatch(glamor_priv);
Zhigang Gong's avatar
Zhigang Gong committed
522 523 524 525 526 527 528 529 530 531
	dispatch->glVertexAttribPointer(GLAMOR_VERTEX_POS, 2, GL_FLOAT,
					GL_FALSE, 2 * sizeof(float),
					vertices);
	dispatch->glEnableVertexAttribArray(GLAMOR_VERTEX_POS);
	dispatch->glVertexAttribPointer(GLAMOR_VERTEX_SOURCE, 2, GL_FLOAT,
					GL_FALSE, 2 * sizeof(float),
					ptexcoords);
	dispatch->glEnableVertexAttribArray(GLAMOR_VERTEX_SOURCE);

	glamor_set_destination_pixmap_priv_nc(pixmap_priv);
532 533 534 535
	__glamor_upload_pixmap_to_texture(pixmap, &tex,
					  format, type,
					  0, 0, w, h,
					  bits, pbo);
Zhigang Gong's avatar
Zhigang Gong committed
536 537 538 539 540 541 542
	dispatch->glActiveTexture(GL_TEXTURE0);
	dispatch->glBindTexture(GL_TEXTURE_2D, tex);

	dispatch->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
				  GL_NEAREST);
	dispatch->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
				  GL_NEAREST);
543
#ifndef GLAMOR_GLES2
Zhigang Gong's avatar
Zhigang Gong committed
544
	dispatch->glEnable(GL_TEXTURE_2D);
545
#endif
Zhigang Gong's avatar
Zhigang Gong committed
546 547
	dispatch->glUseProgram(glamor_priv->finish_access_prog[no_alpha]);
	dispatch->glUniform1i(glamor_priv->
548 549
			      finish_access_revert[no_alpha],
			      revert);
Zhigang Gong's avatar
Zhigang Gong committed
550
	dispatch->glUniform1i(glamor_priv->finish_access_swap_rb[no_alpha],
551
			      swap_rb);
552

Zhigang Gong's avatar
Zhigang Gong committed
553
	dispatch->glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
554

555
#ifndef GLAMOR_GLES2
Zhigang Gong's avatar
Zhigang Gong committed
556
	dispatch->glDisable(GL_TEXTURE_2D);
557
#endif
Zhigang Gong's avatar
Zhigang Gong committed
558 559 560 561 562
	dispatch->glUseProgram(0);
	dispatch->glDisableVertexAttribArray(GLAMOR_VERTEX_POS);
	dispatch->glDisableVertexAttribArray(GLAMOR_VERTEX_SOURCE);
	dispatch->glDeleteTextures(1, &tex);
	dispatch->glBindFramebuffer(GL_FRAMEBUFFER, 0);
Chris Wilson's avatar
Chris Wilson committed
563 564

	glamor_put_dispatch(glamor_priv);
565 566 567 568 569 570 571

	if (need_free_bits)
		free(bits);
	return TRUE;
}

/*
572
 * Prepare to upload a pixmap to texture memory.
573
 * no_alpha equals 1 means the format needs to wire alpha to 1.
574 575
 * Two condtion need to setup a fbo for a pixmap
 * 1. !yInverted, we need to do flip if we are not yInverted.
576
 * 2. no_alpha != 0, we need to wire the alpha.
577
 * */
578
static int
579
glamor_pixmap_upload_prepare(PixmapPtr pixmap, GLenum format, int no_alpha, int revert, int swap_rb)
580
{
581
	int flag = 0;
582 583 584
	glamor_pixmap_private *pixmap_priv;
	glamor_screen_private *glamor_priv;
	glamor_pixmap_fbo *fbo;
585
	GLenum iformat;
586 587 588

	pixmap_priv = glamor_get_pixmap_private(pixmap);
	glamor_priv = glamor_get_screen_private(pixmap->drawable.pScreen);
Zhigang Gong's avatar
Zhigang Gong committed
589

590 591 592 593 594 595 596 597
	if (pixmap_priv->fbo
	     && (pixmap_priv->fbo->width < pixmap->drawable.width
           || pixmap_priv->fbo->height < pixmap->drawable.height)) {
		fbo = glamor_pixmap_detach_fbo(pixmap_priv);
		glamor_destroy_fbo(fbo);
        }

	if (pixmap_priv->fbo && pixmap_priv->fbo->fb)
598 599
		return 0;

600 601 602 603 604
	if (!(no_alpha
	      || (revert != REVERT_NONE)
	      || (swap_rb != SWAP_NONE_UPLOADING)
	      || !glamor_priv->yInverted)) {
		/* We don't need a fbo, a simple texture uploading should work. */
Zhigang Gong's avatar
Zhigang Gong committed
605

606
		flag = GLAMOR_CREATE_FBO_NO_FBO;
607
	}
Zhigang Gong's avatar
Zhigang Gong committed
608

609 610 611 612
	if ((flag == 0 && pixmap_priv && pixmap_priv->fbo && pixmap_priv->fbo->tex)
	    || (flag != 0 && pixmap_priv && pixmap_priv->fbo && pixmap_priv->fbo->fb))
		return 0;

613 614 615 616 617
	if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP)
		gl_iformat_for_depth(pixmap->drawable.depth, &iformat);
	else
		iformat = format;

618 619 620 621 622 623 624 625 626 627 628 629 630
	if (pixmap_priv == NULL || pixmap_priv->fbo == NULL) {

		fbo = glamor_create_fbo(glamor_priv, pixmap->drawable.width,
					pixmap->drawable.height,
					iformat,
					flag);
		if (fbo == NULL) {
			glamor_fallback
			    ("upload failed, depth %d x %d @depth %d \n",
			     pixmap->drawable.width, pixmap->drawable.height,
			     pixmap->drawable.depth);
			return -1;
		}
631

632 633 634 635
		glamor_pixmap_attach_fbo(pixmap, fbo);
	} else {
		/* We do have a fbo, but it may lack of fb or tex. */
		glamor_pixmap_ensure_fbo(pixmap, iformat, flag);
636
	}
637

Zhigang Gong's avatar
Zhigang Gong committed
638
	return 0;
639
}
Zhigang Gong's avatar
Zhigang Gong committed
640

641 642 643
Bool
glamor_upload_sub_pixmap_to_texture(PixmapPtr pixmap, int x, int y, int w, int h,
				    int stride, void *bits, int pbo)
644
{
Zhigang Gong's avatar
Zhigang Gong committed
645
	GLenum format, type;
646
	int no_alpha, revert, swap_rb;
Zhigang Gong's avatar
Zhigang Gong committed
647 648 649

	if (glamor_get_tex_format_type_from_pixmap(pixmap,
						   &format,
650 651 652 653
						   &type,
						   &no_alpha,
						   &revert,
						   &swap_rb, 1)) {
Zhigang Gong's avatar
Zhigang Gong committed
654 655
		glamor_fallback("Unknown pixmap depth %d.\n",
				pixmap->drawable.depth);
656
		return TRUE;
Zhigang Gong's avatar
Zhigang Gong committed
657
	}
658
	if (glamor_pixmap_upload_prepare(pixmap, format, no_alpha, revert, swap_rb))
659 660 661 662 663
		return FALSE;

	return _glamor_upload_bits_to_pixmap_texture(pixmap, format, type, no_alpha, revert, swap_rb,
						     x, y, w, h, stride, bits, pbo);
}
664

665 666 667 668 669 670
enum glamor_pixmap_status
glamor_upload_pixmap_to_texture(PixmapPtr pixmap)
{
	glamor_pixmap_private *pixmap_priv;
	void *data;
	int pbo;
671
	int ret;
672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689

	pixmap_priv = glamor_get_pixmap_private(pixmap);

	if (pixmap_priv
	    && (pixmap_priv->fbo)
	    && (pixmap_priv->fbo->pbo_valid)) {
		data = NULL;
		pbo = pixmap_priv->fbo->pbo;
	} else {
		data = pixmap->devPrivate.ptr;
		pbo = 0;
	}

	if (glamor_upload_sub_pixmap_to_texture(pixmap, 0, 0,
						pixmap->drawable.width,
						pixmap->drawable.height,
						pixmap->devKind,
						data, pbo))
690
		ret = GLAMOR_UPLOAD_DONE;
691
	else
692
		ret = GLAMOR_UPLOAD_FAILED;
Zhigang Gong's avatar
Zhigang Gong committed
693

694
	return ret;
695 696 697 698 699
}

void
glamor_restore_pixmap_to_texture(PixmapPtr pixmap)
{
700
	if (glamor_upload_pixmap_to_texture(pixmap) != GLAMOR_UPLOAD_DONE)
701 702
		LogMessage(X_WARNING, "Failed to restore pixmap to texture.\n",
			   pixmap->drawable.pScreen->myNum);
703 704
}

705
/*
706
 * as gles2 only support a very small set of color format and
707 708
 * type when do glReadPixel,
 * Before we use glReadPixels to get back a textured pixmap,
709 710 711 712
 * Use shader to convert it to a supported format and thus
 * get a new temporary pixmap returned.
 * */

713
glamor_pixmap_fbo *
714
glamor_es2_pixmap_read_prepare(PixmapPtr source, int x, int y, int w, int h, GLenum format,
715 716
			       GLenum type, int no_alpha, int revert, int swap_rb)

717
{
Zhigang Gong's avatar
Zhigang Gong committed
718 719 720
	glamor_pixmap_private *source_priv;
	glamor_screen_private *glamor_priv;
	ScreenPtr screen;
721
	glamor_pixmap_fbo *temp_fbo;
Zhigang Gong's avatar
Zhigang Gong committed
722
	glamor_gl_dispatch *dispatch;
723 724 725
	float temp_xscale, temp_yscale, source_xscale, source_yscale;
	static float vertices[8];
	static float texcoords[8];
Zhigang Gong's avatar
Zhigang Gong committed
726 727 728 729 730

	screen = source->drawable.pScreen;

	glamor_priv = glamor_get_screen_private(screen);
	source_priv = glamor_get_pixmap_private(source);
731
	temp_fbo = glamor_create_fbo(glamor_priv,
732
				     w, h,
733 734 735 736
				     format,
				     0);
	if (temp_fbo == NULL)
		return NULL;
Zhigang Gong's avatar
Zhigang Gong committed
737

Chris Wilson's avatar
Chris Wilson committed
738
	dispatch = glamor_get_dispatch(glamor_priv);
739 740
	temp_xscale = 1.0 / temp_fbo->width;
	temp_yscale = 1.0 / temp_fbo->height;
741

742 743 744
	glamor_set_normalize_vcoords(temp_xscale,
				     temp_yscale,
				     0, 0,
745
				     w, h,
746 747
				     glamor_priv->yInverted,
				     vertices);
Zhigang Gong's avatar
Zhigang Gong committed
748 749 750 751 752 753

	dispatch->glVertexAttribPointer(GLAMOR_VERTEX_POS, 2, GL_FLOAT,
					GL_FALSE, 2 * sizeof(float),
					vertices);
	dispatch->glEnableVertexAttribArray(GLAMOR_VERTEX_POS);

754 755 756
	pixmap_priv_get_scale(source_priv, &source_xscale, &source_yscale);
	glamor_set_normalize_tcoords(source_xscale,
				     source_yscale,
757 758
				     x, y,
				     x + w, y + h,
759 760 761
				     glamor_priv->yInverted,
				     texcoords);

Zhigang Gong's avatar
Zhigang Gong committed
762 763 764 765 766 767
	dispatch->glVertexAttribPointer(GLAMOR_VERTEX_SOURCE, 2, GL_FLOAT,
					GL_FALSE, 2 * sizeof(float),
					texcoords);
	dispatch->glEnableVertexAttribArray(GLAMOR_VERTEX_SOURCE);

	dispatch->glActiveTexture(GL_TEXTURE0);
768
	dispatch->glBindTexture(GL_TEXTURE_2D, source_priv->fbo->tex);
769 770 771 772 773 774
	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
775

776
	glamor_set_destination_pixmap_fbo(temp_fbo);
Zhigang Gong's avatar
Zhigang Gong committed
777 778
	dispatch->glUseProgram(glamor_priv->finish_access_prog[no_alpha]);
	dispatch->glUniform1i(glamor_priv->
779 780
			      finish_access_revert[no_alpha],
			      revert);
Zhigang Gong's avatar
Zhigang Gong committed
781 782 783 784 785 786 787 788
	dispatch->glUniform1i(glamor_priv->finish_access_swap_rb[no_alpha],
			      swap_rb);

	dispatch->glDrawArrays(GL_TRIANGLE_FAN, 0, 4);

	dispatch->glDisableVertexAttribArray(GLAMOR_VERTEX_POS);
	dispatch->glDisableVertexAttribArray(GLAMOR_VERTEX_SOURCE);
	dispatch->glUseProgram(0);
Chris Wilson's avatar
Chris Wilson committed
789
	glamor_put_dispatch(glamor_priv);
790
	return temp_fbo;
791
}
Zhigang Gong's avatar
Zhigang Gong committed
792

793 794 795 796 797 798 799 800
/*
 * Download a sub region of pixmap to a specified memory region.
 * The pixmap must have a valid FBO, otherwise return a NULL.
 * */

void *
glamor_download_sub_pixmap_to_cpu(PixmapPtr pixmap, int x, int y, int w, int h,
				  int stride, void *bits, int pbo, glamor_access_t access)
801
{
802
	glamor_pixmap_private *pixmap_priv;
Zhigang Gong's avatar
Zhigang Gong committed
803
	GLenum format, type, gl_access, gl_usage;
804
	int no_alpha, revert, swap_rb;
805
	void *data, *read;
Zhigang Gong's avatar
Zhigang Gong committed
806 807 808
	ScreenPtr screen;
	glamor_screen_private *glamor_priv =
	    glamor_get_screen_private(pixmap->drawable.pScreen);
Chris Wilson's avatar
Chris Wilson committed
809
	glamor_gl_dispatch *dispatch;
810
	glamor_pixmap_fbo *temp_fbo = NULL;
811
	int need_post_conversion = 0;
812
	int need_free_data = 0;
Zhigang Gong's avatar
Zhigang Gong committed
813

814
	data = bits;
Zhigang Gong's avatar
Zhigang Gong committed
815
	screen = pixmap->drawable.pScreen;
816
	pixmap_priv = glamor_get_pixmap_private(pixmap);
817
	if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv))
818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835
		return NULL;

	switch (access) {
	case GLAMOR_ACCESS_RO:
		gl_access = GL_READ_ONLY;
		gl_usage = GL_STREAM_READ;
		break;
	case GLAMOR_ACCESS_WO:
		return bits;
	case GLAMOR_ACCESS_RW:
		gl_access = GL_READ_WRITE;
		gl_usage = GL_DYNAMIC_DRAW;
		break;
	default:
		ErrorF("Glamor: Invalid access code. %d\n", access);
		assert(0);
	}

Zhigang Gong's avatar
Zhigang Gong committed
836 837
	if (glamor_get_tex_format_type_from_pixmap(pixmap,
						   &format,
838 839 840 841
						   &type,
						   &no_alpha,
						   &revert,
						   &swap_rb, 0)) {
Zhigang Gong's avatar
Zhigang Gong committed
842 843 844
		ErrorF("Unknown pixmap depth %d.\n",
		       pixmap->drawable.depth);
		assert(0);	// Should never happen.
845
		return NULL;
Zhigang Gong's avatar
Zhigang Gong committed
846 847 848 849
	}

	glamor_set_destination_pixmap_priv_nc(pixmap_priv);

850
	need_post_conversion = (revert > REVERT_NORMAL);
851 852
	if (need_post_conversion) {
		if (pixmap->drawable.depth == 1) {
853 854 855
			int temp_stride;
			temp_stride = (((w * 8 + 7) / 8) + 3) & ~3;
			data = malloc(temp_stride * h);
856 857 858 859 860
			if (data == NULL)
				return NULL;
			need_free_data = 1;
		}
	}
861

Zhigang Gong's avatar
Zhigang Gong committed
862
	if (glamor_priv->gl_flavor == GLAMOR_GL_ES2
863
	    && !need_post_conversion
864
	    && (swap_rb != SWAP_NONE_DOWNLOADING || revert != REVERT_NONE)) {
865 866
		 if (!(temp_fbo = glamor_es2_pixmap_read_prepare(pixmap, x, y, w, h,
								 format, type, no_alpha,
867 868
								 revert, swap_rb))) {
			free(data);
869
			return NULL;
870
		}
871 872
		x = 0;
		y = 0;
Zhigang Gong's avatar
Zhigang Gong committed
873
	}
874

Chris Wilson's avatar
Chris Wilson committed
875
	dispatch = glamor_get_dispatch(glamor_priv);
876 877
	dispatch->glPixelStorei(GL_PACK_ALIGNMENT, 4);

Zhigang Gong's avatar
Zhigang Gong committed
878 879 880 881 882 883 884 885
	if (glamor_priv->has_pack_invert || glamor_priv->yInverted) {

		if (!glamor_priv->yInverted) {
			assert(glamor_priv->gl_flavor ==
			       GLAMOR_GL_DESKTOP);
			dispatch->glPixelStorei(GL_PACK_INVERT_MESA, 1);
		}

886 887 888
		if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP && data == NULL) {
			assert(pbo > 0);
			dispatch->glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo);
Zhigang Gong's avatar
Zhigang Gong committed
889 890
			dispatch->glBufferData(GL_PIXEL_PACK_BUFFER,
					       stride *
891
					       h,
Zhigang Gong's avatar
Zhigang Gong committed
892
					       NULL, gl_usage);
893
		}
Zhigang Gong's avatar
Zhigang Gong committed
894

895 896 897 898 899
		dispatch->glReadPixels(x, y, w, h, format, type, data);

		if (!glamor_priv->yInverted) {
			assert(glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP);
			dispatch->glPixelStorei(GL_PACK_INVERT_MESA, 0);
Zhigang Gong's avatar
Zhigang Gong committed
900
		}
901 902 903
		if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP && bits == NULL) {
			bits = dispatch->glMapBuffer(GL_PIXEL_PACK_BUFFER,
						     gl_access);
Zhigang Gong's avatar
Zhigang Gong committed
904 905
			dispatch->glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
		}
906 907 908 909 910 911 912 913 914 915
	} else {
		int temp_pbo;
		int yy;

		dispatch = glamor_get_dispatch(glamor_priv);
		dispatch->glGenBuffers(1, &temp_pbo);
		dispatch->glBindBuffer(GL_PIXEL_PACK_BUFFER,
				       temp_pbo);
		dispatch->glBufferData(GL_PIXEL_PACK_BUFFER,
				       stride *
916
				       h,
917
				       NULL, GL_STREAM_READ);
918
		dispatch->glReadPixels(0, 0, w, h,
919 920 921 922 923
				       format, type, 0);
		read = dispatch->glMapBuffer(GL_PIXEL_PACK_BUFFER,
					     GL_READ_ONLY);
		for (yy = 0; yy < pixmap->drawable.height; yy++)
			memcpy(data + yy * stride,
924
			       read + (h - yy - 1) * stride, stride);
925 926 927
		dispatch->glUnmapBuffer(GL_PIXEL_PACK_BUFFER);
		dispatch->glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
		dispatch->glDeleteBuffers(1, &temp_pbo);
Zhigang Gong's avatar
Zhigang Gong committed
928 929 930
	}

	dispatch->glBindFramebuffer(GL_FRAMEBUFFER, 0);
Chris Wilson's avatar
Chris Wilson committed
931
	glamor_put_dispatch(glamor_priv);
932 933 934 935

	if (need_post_conversion) {
		/* As OpenGL desktop version never enters here.
		 * Don't need to consider if the pbo is valid.*/
936 937
		bits = glamor_color_convert_to_bits(data, bits,
						    w, h,
938 939
						    stride,
						    no_alpha,
940
						    revert, swap_rb);
941 942
	}

Zhigang Gong's avatar
Zhigang Gong committed
943
      done:
944

945 946
	if (temp_fbo != NULL)
		glamor_destroy_fbo(temp_fbo);
947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967
	if (need_free_data)
		free(data);

	return bits;
}


/**
 * Move a pixmap to CPU memory.
 * The input data is the pixmap's fbo.
 * The output data is at pixmap->devPrivate.ptr. We always use pbo
 * to read the fbo and then map it to va. If possible, we will use
 * it directly as devPrivate.ptr.
 * If successfully download a fbo to cpu then return TRUE.
 * Otherwise return FALSE.
 **/
Bool
glamor_download_pixmap_to_cpu(PixmapPtr pixmap, glamor_access_t access)
{
	glamor_pixmap_private *pixmap_priv =
	    glamor_get_pixmap_private(pixmap);
968
	unsigned int stride, y;
969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003
	GLenum format, type, gl_access, gl_usage;
	int no_alpha, revert, swap_rb;
	void *data = NULL, *dst;
	ScreenPtr screen;
	glamor_screen_private *glamor_priv =
	    glamor_get_screen_private(pixmap->drawable.pScreen);
	glamor_gl_dispatch *dispatch;
	int pbo = 0;

	screen = pixmap->drawable.pScreen;
	if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv))
		return TRUE;

	glamor_debug_output(GLAMOR_DEBUG_TEXTURE_DOWNLOAD,
			    "Downloading pixmap %p  %dx%d depth%d\n",
			    pixmap,
			    pixmap->drawable.width,
			    pixmap->drawable.height,
			    pixmap->drawable.depth);

	stride = pixmap->devKind;

	if (access == GLAMOR_ACCESS_WO
	    || glamor_priv->gl_flavor == GLAMOR_GL_ES2
	    || (!glamor_priv->has_pack_invert && !glamor_priv->yInverted)) {
		data = malloc(stride * pixmap->drawable.height);
	} else {
		dispatch = glamor_get_dispatch(glamor_priv);
		if (pixmap_priv->fbo->pbo == 0)
			dispatch->glGenBuffers(1,
					       &pixmap_priv->fbo->pbo);
		glamor_put_dispatch(glamor_priv);
		pbo = pixmap_priv->fbo->pbo;
	}

1004 1005 1006 1007 1008 1009
	if (pixmap_priv->type == GLAMOR_TEXTURE_DRM) {
		stride = PixmapBytePad(pixmap->drawable.width, pixmap->drawable.depth);
		pixmap_priv->drm_stride = pixmap->devKind;
		pixmap->devKind = stride;
	}

1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029
	dst = glamor_download_sub_pixmap_to_cpu(pixmap, 0, 0,
						pixmap->drawable.width,
						pixmap->drawable.height,
						pixmap->devKind,
						data, pbo, access);

	if (!dst) {
		if (data)
			free(data);
		return FALSE;
	}

	if (pbo != 0)
		pixmap_priv->fbo->pbo_valid = 1;

	pixmap_priv->gl_fbo = GLAMOR_FBO_DOWNLOADED;

      done:

	pixmap->devPrivate.ptr = dst;
Zhigang Gong's avatar
Zhigang Gong committed
1030 1031

	return TRUE;
1032
}
1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095

/* fixup a fbo to the exact size as the pixmap. */
Bool
glamor_fixup_pixmap_priv(ScreenPtr screen, glamor_pixmap_private *pixmap_priv)
{
	glamor_screen_private *glamor_priv;
	glamor_pixmap_fbo *old_fbo;
	glamor_pixmap_fbo *new_fbo = NULL;
	PixmapPtr scratch = NULL;
	glamor_pixmap_private *scratch_priv;
	DrawablePtr drawable;
	GCPtr gc = NULL;
	int ret = FALSE;

	drawable = &pixmap_priv->container->drawable;

	if (pixmap_priv->container->drawable.width == pixmap_priv->fbo->width
	    && pixmap_priv->container->drawable.height == pixmap_priv->fbo->height)
		return	TRUE;

	old_fbo = pixmap_priv->fbo;
	glamor_priv = pixmap_priv->glamor_priv;

	if (!old_fbo)
		return FALSE;

	gc = GetScratchGC(drawable->depth, screen);
	if (!gc)
		goto fail;

	scratch = glamor_create_pixmap(screen, drawable->width, drawable->height,
				       drawable->depth,
				       GLAMOR_CREATE_PIXMAP_FIXUP);

	scratch_priv = glamor_get_pixmap_private(scratch);

	if (!scratch_priv || !scratch_priv->fbo)
		goto fail;

	ValidateGC(&scratch->drawable, gc);
	glamor_copy_area(drawable,
			 &scratch->drawable,
			 gc, 0, 0,
			 drawable->width, drawable->height,
			 0, 0);
	old_fbo = glamor_pixmap_detach_fbo(pixmap_priv);
	new_fbo = glamor_pixmap_detach_fbo(scratch_priv);
	glamor_pixmap_attach_fbo(pixmap_priv->container, new_fbo);
	glamor_pixmap_attach_fbo(scratch, old_fbo);

	DEBUGF("old %dx%d type %d\n",
		drawable->width, drawable->height, pixmap_priv->type);
	DEBUGF("copy tex %d  %dx%d to tex %d %dx%d \n",
		old_fbo->tex, old_fbo->width, old_fbo->height, new_fbo->tex, new_fbo->width, new_fbo->height);
	ret = TRUE;
fail:
	if (gc)
		FreeScratchGC(gc);
	if (scratch)
		glamor_destroy_pixmap(scratch);

	return ret;
}
1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122

/*
 * We may use this function to reduce a large pixmap to a small sub
 * pixmap. Two scenarios currently:
 * 1. When fallback a large textured pixmap to CPU but we do need to
 * do rendering within a small sub region, then we can just get a
 * sub region.
 *
 * 2. When uploading a large pixmap to texture but we only need to
 * use part of the source/mask picture. As glTexImage2D will be more
 * efficient to upload a contingent region rather than a sub block
 * in a large buffer. We use this function to gather the sub region
 * to a contingent sub pixmap.
 *
 * The sub-pixmap must have the same format as the source pixmap.
 *
 * */
PixmapPtr
glamor_get_sub_pixmap(PixmapPtr pixmap, int x, int y, int w, int h, glamor_access_t access)
{
	glamor_screen_private *glamor_priv;
	PixmapPtr sub_pixmap;
	glamor_pixmap_private *sub_pixmap_priv, *pixmap_priv;
	void *data;
	int pbo;
	int flag;

1123 1124 1125
	assert(x >= 0 && y >= 0);
	w = (x + w) > pixmap->drawable.width ? (pixmap->drawable.width - x) : w;
	h = (y + h) > pixmap->drawable.height ? (pixmap->drawable.height - y) : h;
1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151
	if (access == GLAMOR_ACCESS_WO) {
		sub_pixmap = glamor_create_pixmap(pixmap->drawable.pScreen, w, h,
						  pixmap->drawable.depth, GLAMOR_CREATE_PIXMAP_CPU);
		ErrorF("WO\n");
		return sub_pixmap;
	}

	glamor_priv = glamor_get_screen_private(pixmap->drawable.pScreen);
	pixmap_priv = glamor_get_pixmap_private(pixmap);

	if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv))
		return NULL;
	if (glamor_priv->gl_flavor == GLAMOR_GL_ES2)
		flag = GLAMOR_CREATE_PIXMAP_CPU;
	else
		flag = GLAMOR_CREATE_PIXMAP_MAP;

	sub_pixmap = glamor_create_pixmap(pixmap->drawable.pScreen, w, h,
					  pixmap->drawable.depth, flag);

	if (sub_pixmap == NULL)
		return NULL;

	sub_pixmap_priv = glamor_get_pixmap_private(sub_pixmap);
	pbo = sub_pixmap_priv ? (sub_pixmap_priv->fbo ? sub_pixmap_priv->fbo->pbo : 0): 0;

1152 1153 1154 1155 1156
	if (pixmap_priv->is_picture) {
		sub_pixmap_priv->pict_format = pixmap_priv->pict_format;
		sub_pixmap_priv->is_picture = pixmap_priv->is_picture;
	}

1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193
	if (pbo)
		data = NULL;
	else {
		data = sub_pixmap->devPrivate.ptr;
		assert(flag != GLAMOR_CREATE_PIXMAP_MAP);
	}
	data = glamor_download_sub_pixmap_to_cpu(pixmap, x, y, w, h, sub_pixmap->devKind,
						 data, pbo, access);
	if (pbo) {
		assert(sub_pixmap->devPrivate.ptr == NULL);
		sub_pixmap->devPrivate.ptr = data;
		sub_pixmap_priv->fbo->pbo_valid = 1;
	}
#if 0
	struct pixman_box16 box;
	PixmapPtr new_sub_pixmap;
	int dx, dy;
	box.x1 = 0;
	box.y1 = 0;
	box.x2 = w;
	box.y2 = h;

	dx = x;
	dy = y;

	new_sub_pixmap = glamor_create_pixmap(pixmap->drawable.pScreen, w, h,
					      pixmap->drawable.depth, GLAMOR_CREATE_PIXMAP_CPU);
	glamor_copy_n_to_n(&pixmap->drawable, &new_sub_pixmap, NULL, &box, 1, dx, dy, 0, 0, 0, NULL);
	glamor_compare_pixmaps(new_sub_pixmap, sub_pixmap, 0, 0, w, h, 1, 1);
#endif

	return sub_pixmap;
}

PixmapPtr
glamor_put_sub_pixmap(PixmapPtr sub_pixmap, PixmapPtr pixmap, int x, int y, int w, int h, glamor_access_t access)
{
1194 1195 1196
	void *bits;
	int pbo;
	glamor_pixmap_private *sub_pixmap_priv;
1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207
	if (access != GLAMOR_ACCESS_RO) {
		sub_pixmap_priv = glamor_get_pixmap_private(sub_pixmap);
		if (sub_pixmap_priv
		    && sub_pixmap_priv->fbo
		    && sub_pixmap_priv->fbo->pbo_valid) {
			bits = NULL;
			pbo = sub_pixmap_priv->fbo->pbo;
		} else {
			bits = sub_pixmap->devPrivate.ptr;
			pbo = 0;
		}
1208 1209 1210 1211

		assert(x >= 0 && y >= 0);