glamor_picture.c revision 35c4bbdf
1/*
2 * Copyright © 2009 Intel Corporation
3 * Copyright © 1998 Keith Packard
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
14 * Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 * IN THE SOFTWARE.
23 *
24 * Authors:
25 *    Zhigang Gong <zhigang.gong@gmail.com>
26 *
27 */
28
29#include <stdlib.h>
30
31#include "glamor_priv.h"
32#include "mipict.h"
33
34/*
35 * Map picture's format to the correct gl texture format and type.
36 * no_alpha is used to indicate whehter we need to wire alpha to 1.
37 *
38 * Although opengl support A1/GL_BITMAP, we still don't use it
39 * here, it seems that mesa has bugs when uploading a A1 bitmap.
40 *
41 * Return 0 if find a matched texture type. Otherwise return -1.
42 **/
43static int
44glamor_get_tex_format_type_from_pictformat_gl(ScreenPtr pScreen,
45                                              PictFormatShort format,
46                                              GLenum *tex_format,
47                                              GLenum *tex_type,
48                                              int *no_alpha,
49                                              int *revert,
50                                              int *swap_rb, int is_upload)
51{
52    glamor_screen_private *glamor_priv = glamor_get_screen_private(pScreen);
53    *no_alpha = 0;
54    *revert = REVERT_NONE;
55    *swap_rb = is_upload ? SWAP_NONE_UPLOADING : SWAP_NONE_DOWNLOADING;
56    switch (format) {
57    case PICT_a1:
58        *tex_format = glamor_priv->one_channel_format;
59        *tex_type = GL_UNSIGNED_BYTE;
60        *revert = is_upload ? REVERT_UPLOADING_A1 : REVERT_DOWNLOADING_A1;
61        break;
62    case PICT_b8g8r8x8:
63        *no_alpha = 1;
64    case PICT_b8g8r8a8:
65        *tex_format = GL_BGRA;
66        *tex_type = GL_UNSIGNED_INT_8_8_8_8;
67        break;
68
69    case PICT_x8r8g8b8:
70        *no_alpha = 1;
71    case PICT_a8r8g8b8:
72        *tex_format = GL_BGRA;
73        *tex_type = GL_UNSIGNED_INT_8_8_8_8_REV;
74        break;
75    case PICT_x8b8g8r8:
76        *no_alpha = 1;
77    case PICT_a8b8g8r8:
78        *tex_format = GL_RGBA;
79        *tex_type = GL_UNSIGNED_INT_8_8_8_8_REV;
80        break;
81    case PICT_x2r10g10b10:
82        *no_alpha = 1;
83    case PICT_a2r10g10b10:
84        *tex_format = GL_BGRA;
85        *tex_type = GL_UNSIGNED_INT_2_10_10_10_REV;
86        break;
87    case PICT_x2b10g10r10:
88        *no_alpha = 1;
89    case PICT_a2b10g10r10:
90        *tex_format = GL_RGBA;
91        *tex_type = GL_UNSIGNED_INT_2_10_10_10_REV;
92        break;
93
94    case PICT_r5g6b5:
95        *tex_format = GL_RGB;
96        *tex_type = GL_UNSIGNED_SHORT_5_6_5;
97        break;
98    case PICT_b5g6r5:
99        *tex_format = GL_RGB;
100        *tex_type = GL_UNSIGNED_SHORT_5_6_5_REV;
101        break;
102    case PICT_x1b5g5r5:
103        *no_alpha = 1;
104    case PICT_a1b5g5r5:
105        *tex_format = GL_RGBA;
106        *tex_type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
107        break;
108
109    case PICT_x1r5g5b5:
110        *no_alpha = 1;
111    case PICT_a1r5g5b5:
112        *tex_format = GL_BGRA;
113        *tex_type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
114        break;
115    case PICT_a8:
116        *tex_format = glamor_priv->one_channel_format;
117        *tex_type = GL_UNSIGNED_BYTE;
118        break;
119    case PICT_x4r4g4b4:
120        *no_alpha = 1;
121    case PICT_a4r4g4b4:
122        *tex_format = GL_BGRA;
123        *tex_type = GL_UNSIGNED_SHORT_4_4_4_4_REV;
124        break;
125
126    case PICT_x4b4g4r4:
127        *no_alpha = 1;
128    case PICT_a4b4g4r4:
129        *tex_format = GL_RGBA;
130        *tex_type = GL_UNSIGNED_SHORT_4_4_4_4_REV;
131        break;
132
133    default:
134        return -1;
135    }
136    return 0;
137}
138
139#define IS_LITTLE_ENDIAN  (IMAGE_BYTE_ORDER == LSBFirst)
140
141static int
142glamor_get_tex_format_type_from_pictformat_gles2(ScreenPtr pScreen,
143                                                 PictFormatShort format,
144                                                 GLenum *tex_format,
145                                                 GLenum *tex_type,
146                                                 int *no_alpha,
147                                                 int *revert,
148                                                 int *swap_rb, int is_upload)
149{
150    glamor_screen_private *glamor_priv = glamor_get_screen_private(pScreen);
151    int need_swap_rb = 0;
152
153    *no_alpha = 0;
154    *revert = IS_LITTLE_ENDIAN ? REVERT_NONE : REVERT_NORMAL;
155
156    switch (format) {
157    case PICT_b8g8r8x8:
158        *no_alpha = 1;
159    case PICT_b8g8r8a8:
160        *tex_format = GL_RGBA;
161        *tex_type = GL_UNSIGNED_BYTE;
162        need_swap_rb = 1;
163        *revert = IS_LITTLE_ENDIAN ? REVERT_NORMAL : REVERT_NONE;
164        break;
165
166    case PICT_x8r8g8b8:
167        *no_alpha = 1;
168    case PICT_a8r8g8b8:
169        *tex_format = GL_RGBA;
170        *tex_type = GL_UNSIGNED_BYTE;
171        need_swap_rb = 1;
172        break;
173
174    case PICT_x8b8g8r8:
175        *no_alpha = 1;
176    case PICT_a8b8g8r8:
177        *tex_format = GL_RGBA;
178        *tex_type = GL_UNSIGNED_BYTE;
179        break;
180
181    case PICT_x2r10g10b10:
182        *no_alpha = 1;
183    case PICT_a2r10g10b10:
184        *tex_format = GL_RGBA;
185        /* glReadPixmap doesn't support GL_UNSIGNED_INT_10_10_10_2.
186         * we have to use GL_UNSIGNED_BYTE and do the conversion in
187         * shader latter.*/
188        *tex_type = GL_UNSIGNED_BYTE;
189        if (is_upload == 1) {
190            if (!IS_LITTLE_ENDIAN)
191                *revert = REVERT_UPLOADING_10_10_10_2;
192            else
193                *revert = REVERT_UPLOADING_2_10_10_10;
194        }
195        else {
196            if (!IS_LITTLE_ENDIAN) {
197                *revert = REVERT_DOWNLOADING_10_10_10_2;
198            }
199            else {
200                *revert = REVERT_DOWNLOADING_2_10_10_10;
201            }
202        }
203        need_swap_rb = 1;
204
205        break;
206
207    case PICT_x2b10g10r10:
208        *no_alpha = 1;
209    case PICT_a2b10g10r10:
210        *tex_format = GL_RGBA;
211        *tex_type = GL_UNSIGNED_BYTE;
212        if (is_upload == 1) {
213            if (!IS_LITTLE_ENDIAN)
214                *revert = REVERT_UPLOADING_10_10_10_2;
215            else
216                *revert = REVERT_UPLOADING_2_10_10_10;
217        }
218        else {
219            if (!IS_LITTLE_ENDIAN) {
220                *revert = REVERT_DOWNLOADING_10_10_10_2;
221            }
222            else {
223                *revert = REVERT_DOWNLOADING_2_10_10_10;
224            }
225        }
226        break;
227
228    case PICT_r5g6b5:
229        *tex_format = GL_RGB;
230        *tex_type = GL_UNSIGNED_SHORT_5_6_5;
231        *revert = IS_LITTLE_ENDIAN ? REVERT_NONE : REVERT_NORMAL;
232
233        break;
234
235    case PICT_b5g6r5:
236        *tex_format = GL_RGB;
237        *tex_type = GL_UNSIGNED_SHORT_5_6_5;
238        need_swap_rb = IS_LITTLE_ENDIAN ? 1 : 0;
239        break;
240
241    case PICT_x1b5g5r5:
242        *no_alpha = 1;
243    case PICT_a1b5g5r5:
244        *tex_format = GL_RGBA;
245        *tex_type = GL_UNSIGNED_SHORT_5_5_5_1;
246        if (IS_LITTLE_ENDIAN) {
247            *revert =
248                is_upload ? REVERT_UPLOADING_1_5_5_5 :
249                REVERT_DOWNLOADING_1_5_5_5;
250        }
251        else
252            *revert = REVERT_NONE;
253        break;
254
255    case PICT_x1r5g5b5:
256        *no_alpha = 1;
257    case PICT_a1r5g5b5:
258        *tex_format = GL_RGBA;
259        *tex_type = GL_UNSIGNED_SHORT_5_5_5_1;
260        if (IS_LITTLE_ENDIAN) {
261            *revert =
262                is_upload ? REVERT_UPLOADING_1_5_5_5 :
263                REVERT_DOWNLOADING_1_5_5_5;
264        }
265        else
266            *revert = REVERT_NONE;
267        need_swap_rb = 1;
268        break;
269
270    case PICT_a1:
271        *tex_format = glamor_priv->one_channel_format;
272        *tex_type = GL_UNSIGNED_BYTE;
273        *revert = is_upload ? REVERT_UPLOADING_A1 : REVERT_DOWNLOADING_A1;
274        break;
275
276    case PICT_a8:
277        *tex_format = glamor_priv->one_channel_format;
278        *tex_type = GL_UNSIGNED_BYTE;
279        *revert = REVERT_NONE;
280        break;
281
282    case PICT_x4r4g4b4:
283        *no_alpha = 1;
284    case PICT_a4r4g4b4:
285        *tex_format = GL_RGBA;
286        *tex_type = GL_UNSIGNED_SHORT_4_4_4_4;
287        *revert = IS_LITTLE_ENDIAN ? REVERT_NORMAL : REVERT_NONE;
288        need_swap_rb = 1;
289        break;
290
291    case PICT_x4b4g4r4:
292        *no_alpha = 1;
293    case PICT_a4b4g4r4:
294        *tex_format = GL_RGBA;
295        *tex_type = GL_UNSIGNED_SHORT_4_4_4_4;
296        *revert = IS_LITTLE_ENDIAN ? REVERT_NORMAL : REVERT_NONE;
297        break;
298
299    default:
300        LogMessageVerb(X_INFO, 0,
301                       "fail to get matched format for %x \n", format);
302        return -1;
303    }
304
305    if (need_swap_rb)
306        *swap_rb = is_upload ? SWAP_UPLOADING : SWAP_DOWNLOADING;
307    else
308        *swap_rb = is_upload ? SWAP_NONE_UPLOADING : SWAP_NONE_DOWNLOADING;
309    return 0;
310}
311
312static int
313glamor_get_tex_format_type_from_pixmap(PixmapPtr pixmap,
314                                       PictFormatShort pict_format,
315                                       GLenum *format,
316                                       GLenum *type,
317                                       int *no_alpha,
318                                       int *revert, int *swap_rb, int is_upload)
319{
320    glamor_screen_private *glamor_priv =
321        glamor_get_screen_private(pixmap->drawable.pScreen);
322
323    if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP) {
324        return glamor_get_tex_format_type_from_pictformat_gl(pixmap->drawable.pScreen,
325                                                             pict_format,
326                                                             format, type,
327                                                             no_alpha,
328                                                             revert,
329                                                             swap_rb,
330                                                             is_upload);
331    } else {
332        return glamor_get_tex_format_type_from_pictformat_gles2(pixmap->drawable.pScreen,
333                                                                pict_format,
334                                                                format, type,
335                                                                no_alpha,
336                                                                revert,
337                                                                swap_rb,
338                                                                is_upload);
339    }
340}
341
342static void *
343_glamor_color_convert_a1_a8(void *src_bits, void *dst_bits, int w, int h,
344                            int stride, int revert)
345{
346    PictFormatShort dst_format, src_format;
347    pixman_image_t *dst_image;
348    pixman_image_t *src_image;
349    int src_stride;
350
351    if (revert == REVERT_UPLOADING_A1) {
352        src_format = PICT_a1;
353        dst_format = PICT_a8;
354        src_stride = PixmapBytePad(w, 1);
355    }
356    else {
357        dst_format = PICT_a1;
358        src_format = PICT_a8;
359        src_stride = (((w * 8 + 7) / 8) + 3) & ~3;
360    }
361
362    dst_image = pixman_image_create_bits(dst_format, w, h, dst_bits, stride);
363    if (dst_image == NULL) {
364        return NULL;
365    }
366
367    src_image = pixman_image_create_bits(src_format,
368                                         w, h, src_bits, src_stride);
369
370    if (src_image == NULL) {
371        pixman_image_unref(dst_image);
372        return NULL;
373    }
374
375    pixman_image_composite(PictOpSrc, src_image, NULL, dst_image,
376                           0, 0, 0, 0, 0, 0, w, h);
377
378    pixman_image_unref(src_image);
379    pixman_image_unref(dst_image);
380    return dst_bits;
381}
382
383#define ADJUST_BITS(d, src_bits, dst_bits)	(((dst_bits) == (src_bits)) ? (d) : 				\
384							(((dst_bits) > (src_bits)) ? 				\
385							  (((d) << ((dst_bits) - (src_bits))) 			\
386								   + (( 1 << ((dst_bits) - (src_bits))) >> 1))	\
387								:  ((d) >> ((src_bits) - (dst_bits)))))
388
389#define GLAMOR_DO_CONVERT(src, dst, no_alpha, swap,		\
390			  a_shift_src, a_bits_src,		\
391			  b_shift_src, b_bits_src,		\
392			  g_shift_src, g_bits_src,		\
393			  r_shift_src, r_bits_src,		\
394			  a_shift, a_bits,			\
395			  b_shift, b_bits,			\
396			  g_shift, g_bits,			\
397			  r_shift, r_bits)			\
398	do {								\
399		typeof(src) a,b,g,r;					\
400		typeof(src) a_mask_src, b_mask_src, g_mask_src, r_mask_src;\
401		a_mask_src = (((1 << (a_bits_src)) - 1) << a_shift_src);\
402		b_mask_src = (((1 << (b_bits_src)) - 1) << b_shift_src);\
403		g_mask_src = (((1 << (g_bits_src)) - 1) << g_shift_src);\
404		r_mask_src = (((1 << (r_bits_src)) - 1) << r_shift_src);\
405		if (no_alpha)						\
406			a = (a_mask_src) >> (a_shift_src);			\
407		else							\
408			a = ((src) & (a_mask_src)) >> (a_shift_src);	\
409		b = ((src) & (b_mask_src)) >> (b_shift_src);		\
410		g = ((src) & (g_mask_src)) >> (g_shift_src);		\
411		r = ((src) & (r_mask_src)) >> (r_shift_src);		\
412		a = ADJUST_BITS(a, a_bits_src, a_bits);			\
413		b = ADJUST_BITS(b, b_bits_src, b_bits);			\
414		g = ADJUST_BITS(g, g_bits_src, g_bits);			\
415		r = ADJUST_BITS(r, r_bits_src, r_bits);			\
416		if (swap == 0)						\
417			(*dst) = ((a) << (a_shift)) | ((b) << (b_shift)) | ((g) << (g_shift)) | ((r) << (r_shift)); \
418		else 												    \
419			(*dst) = ((a) << (a_shift)) | ((r) << (b_shift)) | ((g) << (g_shift)) | ((b) << (r_shift)); \
420	} while (0)
421
422static void *
423_glamor_color_revert_x2b10g10r10(void *src_bits, void *dst_bits, int w, int h,
424                                 int stride, int no_alpha, int revert,
425                                 int swap_rb)
426{
427    int x, y;
428    unsigned int *words, *saved_words, *source_words;
429    int swap = !(swap_rb == SWAP_NONE_DOWNLOADING ||
430                 swap_rb == SWAP_NONE_UPLOADING);
431
432    source_words = src_bits;
433    words = dst_bits;
434    saved_words = words;
435
436    for (y = 0; y < h; y++) {
437        DEBUGF("Line %d :  ", y);
438        for (x = 0; x < w; x++) {
439            unsigned int pixel = source_words[x];
440
441            if (revert == REVERT_DOWNLOADING_2_10_10_10)
442                GLAMOR_DO_CONVERT(pixel, &words[x], no_alpha, swap,
443                                  24, 8, 16, 8, 8, 8, 0, 8,
444                                  30, 2, 20, 10, 10, 10, 0, 10);
445            else
446                GLAMOR_DO_CONVERT(pixel, &words[x], no_alpha, swap,
447                                  30, 2, 20, 10, 10, 10, 0, 10,
448                                  24, 8, 16, 8, 8, 8, 0, 8);
449            DEBUGF("%x:%x ", pixel, words[x]);
450        }
451        DEBUGF("\n");
452        words += stride / sizeof(*words);
453        source_words += stride / sizeof(*words);
454    }
455    DEBUGF("\n");
456    return saved_words;
457
458}
459
460static void *
461_glamor_color_revert_x1b5g5r5(void *src_bits, void *dst_bits, int w, int h,
462                              int stride, int no_alpha, int revert, int swap_rb)
463{
464    int x, y;
465    unsigned short *words, *saved_words, *source_words;
466    int swap = !(swap_rb == SWAP_NONE_DOWNLOADING ||
467                 swap_rb == SWAP_NONE_UPLOADING);
468
469    words = dst_bits;
470    source_words = src_bits;
471    saved_words = words;
472
473    for (y = 0; y < h; y++) {
474        DEBUGF("Line %d :  ", y);
475        for (x = 0; x < w; x++) {
476            unsigned short pixel = source_words[x];
477
478            if (revert == REVERT_DOWNLOADING_1_5_5_5)
479                GLAMOR_DO_CONVERT(pixel, &words[x], no_alpha, swap,
480                                  0, 1, 1, 5, 6, 5, 11, 5,
481                                  15, 1, 10, 5, 5, 5, 0, 5);
482            else
483                GLAMOR_DO_CONVERT(pixel, &words[x], no_alpha, swap,
484                                  15, 1, 10, 5, 5, 5, 0, 5,
485                                  0, 1, 1, 5, 6, 5, 11, 5);
486            DEBUGF("%04x:%04x ", pixel, words[x]);
487        }
488        DEBUGF("\n");
489        words += stride / sizeof(*words);
490        source_words += stride / sizeof(*words);
491    }
492    DEBUGF("\n");
493    return saved_words;
494}
495
496/*
497 * This function is to convert an unsupported color format to/from a
498 * supported GL format.
499 * Here are the current scenarios:
500 *
501 * @no_alpha:
502 * 	If it is set, then we need to wire the alpha value to 1.
503 * @revert:
504	REVERT_DOWNLOADING_A1		: convert an Alpha8 buffer to a A1 buffer.
505	REVERT_UPLOADING_A1		: convert an A1 buffer to an Alpha8 buffer
506	REVERT_DOWNLOADING_2_10_10_10 	: convert r10G10b10X2 to X2B10G10R10
507	REVERT_UPLOADING_2_10_10_10 	: convert X2B10G10R10 to R10G10B10X2
508	REVERT_DOWNLOADING_1_5_5_5  	: convert B5G5R5X1 to X1R5G5B5
509	REVERT_UPLOADING_1_5_5_5    	: convert X1R5G5B5 to B5G5R5X1
510   @swap_rb: if we have the swap_rb set, then we need to swap the R and B's position.
511 *
512 */
513
514static void *
515glamor_color_convert_to_bits(void *src_bits, void *dst_bits, int w, int h,
516                             int stride, int no_alpha, int revert, int swap_rb)
517{
518    if (revert == REVERT_DOWNLOADING_A1 || revert == REVERT_UPLOADING_A1) {
519        return _glamor_color_convert_a1_a8(src_bits, dst_bits, w, h, stride,
520                                           revert);
521    }
522    else if (revert == REVERT_DOWNLOADING_2_10_10_10 ||
523             revert == REVERT_UPLOADING_2_10_10_10) {
524        return _glamor_color_revert_x2b10g10r10(src_bits, dst_bits, w, h,
525                                                stride, no_alpha, revert,
526                                                swap_rb);
527    }
528    else if (revert == REVERT_DOWNLOADING_1_5_5_5 ||
529             revert == REVERT_UPLOADING_1_5_5_5) {
530        return _glamor_color_revert_x1b5g5r5(src_bits, dst_bits, w, h, stride,
531                                             no_alpha, revert, swap_rb);
532    }
533    else
534        ErrorF("convert a non-supported mode %x.\n", revert);
535
536    return NULL;
537}
538
539/**
540 * Upload pixmap to a specified texture.
541 * This texture may not be the one attached to it.
542 **/
543static Bool
544__glamor_upload_pixmap_to_texture(PixmapPtr pixmap, unsigned int *tex,
545                                  GLenum format,
546                                  GLenum type,
547                                  int x, int y, int w, int h,
548                                  void *bits, int pbo)
549{
550    glamor_screen_private *glamor_priv =
551        glamor_get_screen_private(pixmap->drawable.pScreen);
552    int non_sub = 0;
553    unsigned int iformat = 0;
554
555    glamor_make_current(glamor_priv);
556    if (*tex == 0) {
557        glGenTextures(1, tex);
558        if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP)
559            iformat = gl_iformat_for_pixmap(pixmap);
560        else
561            iformat = format;
562        non_sub = 1;
563        assert(x == 0 && y == 0);
564    }
565
566    glBindTexture(GL_TEXTURE_2D, *tex);
567    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
568    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
569    glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
570
571    assert(pbo || bits != 0);
572    if (bits == NULL) {
573        glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo);
574        glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
575    }
576    glamor_priv->suppress_gl_out_of_memory_logging = true;
577    if (non_sub)
578        glTexImage2D(GL_TEXTURE_2D, 0, iformat, w, h, 0, format, type, bits);
579    else
580        glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, format, type, bits);
581    glamor_priv->suppress_gl_out_of_memory_logging = false;
582    if (glGetError() == GL_OUT_OF_MEMORY) {
583        if (non_sub) {
584            glDeleteTextures(1, tex);
585            *tex = 0;
586        }
587        return FALSE;
588    }
589
590    if (bits == NULL)
591        glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
592
593    return TRUE;
594}
595
596static Bool
597_glamor_upload_bits_to_pixmap_texture(PixmapPtr pixmap, GLenum format,
598                                      GLenum type, int no_alpha, int revert,
599                                      int swap_rb, int x, int y, int w, int h,
600                                      int stride, void *bits, int pbo)
601{
602    ScreenPtr screen = pixmap->drawable.pScreen;
603    glamor_pixmap_private *pixmap_priv = glamor_get_pixmap_private(pixmap);
604    glamor_screen_private *glamor_priv =
605        glamor_get_screen_private(pixmap->drawable.pScreen);
606    float dst_xscale, dst_yscale;
607    GLuint tex = 0;
608    int need_free_bits = 0;
609
610    if (bits == NULL)
611        goto ready_to_upload;
612
613    if (revert > REVERT_NORMAL) {
614        /* XXX if we are restoring the pixmap, then we may not need to allocate
615         * new buffer */
616        void *converted_bits;
617
618        if (pixmap->drawable.depth == 1)
619            stride = (((w * 8 + 7) / 8) + 3) & ~3;
620
621        converted_bits = xallocarray(h, stride);
622
623        if (converted_bits == NULL)
624            return FALSE;
625        bits = glamor_color_convert_to_bits(bits, converted_bits, w, h,
626                                            stride, no_alpha, revert, swap_rb);
627        if (bits == NULL) {
628            free(converted_bits);
629            ErrorF("Failed to convert pixmap no_alpha %d,"
630                   "revert mode %d, swap mode %d\n", no_alpha, revert, swap_rb);
631            return FALSE;
632        }
633        no_alpha = 0;
634        revert = REVERT_NONE;
635        swap_rb = SWAP_NONE_UPLOADING;
636        need_free_bits = TRUE;
637    }
638
639 ready_to_upload:
640
641    /* Try fast path firstly, upload the pixmap to the texture attached
642     * to the fbo directly. */
643    if (no_alpha == 0
644        && revert == REVERT_NONE && swap_rb == SWAP_NONE_UPLOADING
645#ifdef WALKAROUND_LARGE_TEXTURE_MAP
646        && glamor_pixmap_priv_is_small(pixmap_priv)
647#endif
648        ) {
649        int fbo_x_off, fbo_y_off;
650
651        assert(pixmap_priv->fbo->tex);
652        pixmap_priv_get_fbo_off(pixmap_priv, &fbo_x_off, &fbo_y_off);
653
654        assert(x + fbo_x_off >= 0 && y + fbo_y_off >= 0);
655        assert(x + fbo_x_off + w <= pixmap_priv->fbo->width);
656        assert(y + fbo_y_off + h <= pixmap_priv->fbo->height);
657        if (!__glamor_upload_pixmap_to_texture(pixmap, &pixmap_priv->fbo->tex,
658                                               format, type,
659                                               x + fbo_x_off, y + fbo_y_off,
660                                               w, h,
661                                               bits, pbo)) {
662            if (need_free_bits)
663                free(bits);
664            return FALSE;
665        }
666    } else {
667        static const float texcoords_inv[8] = { 0, 0,
668                                                1, 0,
669                                                1, 1,
670                                                0, 1
671        };
672        GLfloat *v;
673        char *vbo_offset;
674
675        v = glamor_get_vbo_space(screen, 16 * sizeof(GLfloat), &vbo_offset);
676
677        pixmap_priv_get_dest_scale(pixmap, pixmap_priv, &dst_xscale, &dst_yscale);
678        glamor_set_normalize_vcoords(pixmap_priv, dst_xscale,
679                                     dst_yscale,
680                                     x, y,
681                                     x + w, y + h,
682                                     v);
683        /* Slow path, we need to flip y or wire alpha to 1. */
684        glamor_make_current(glamor_priv);
685
686        if (!__glamor_upload_pixmap_to_texture(pixmap, &tex,
687                                               format, type, 0, 0, w, h, bits,
688                                               pbo)) {
689            if (need_free_bits)
690                free(bits);
691            return FALSE;
692        }
693
694        memcpy(&v[8], texcoords_inv, 8 * sizeof(GLfloat));
695
696        glVertexAttribPointer(GLAMOR_VERTEX_POS, 2, GL_FLOAT,
697                              GL_FALSE, 2 * sizeof(float), vbo_offset);
698        glEnableVertexAttribArray(GLAMOR_VERTEX_POS);
699        glVertexAttribPointer(GLAMOR_VERTEX_SOURCE, 2, GL_FLOAT,
700                              GL_FALSE, 2 * sizeof(float), vbo_offset + 8 * sizeof(GLfloat));
701        glEnableVertexAttribArray(GLAMOR_VERTEX_SOURCE);
702
703        glamor_put_vbo_space(screen);
704        glamor_set_destination_pixmap_priv_nc(glamor_priv, pixmap, pixmap_priv);
705        glamor_set_alu(screen, GXcopy);
706        glActiveTexture(GL_TEXTURE0);
707        glBindTexture(GL_TEXTURE_2D, tex);
708
709        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
710        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
711        glUseProgram(glamor_priv->finish_access_prog[no_alpha]);
712        glUniform1i(glamor_priv->finish_access_revert[no_alpha], revert);
713        glUniform1i(glamor_priv->finish_access_swap_rb[no_alpha], swap_rb);
714
715        glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
716
717        glDisableVertexAttribArray(GLAMOR_VERTEX_POS);
718        glDisableVertexAttribArray(GLAMOR_VERTEX_SOURCE);
719        glDeleteTextures(1, &tex);
720        glBindFramebuffer(GL_FRAMEBUFFER, 0);
721    }
722
723    if (need_free_bits)
724        free(bits);
725    return TRUE;
726}
727
728/*
729 * Prepare to upload a pixmap to texture memory.
730 * no_alpha equals 1 means the format needs to wire alpha to 1.
731 */
732static int
733glamor_pixmap_upload_prepare(PixmapPtr pixmap, GLenum format, int no_alpha,
734                             int revert, int swap_rb)
735{
736    int flag = 0;
737    glamor_pixmap_private *pixmap_priv;
738    glamor_screen_private *glamor_priv;
739    glamor_pixmap_fbo *fbo;
740    GLenum iformat;
741
742    pixmap_priv = glamor_get_pixmap_private(pixmap);
743    glamor_priv = glamor_get_screen_private(pixmap->drawable.pScreen);
744
745    if (pixmap_priv->gl_fbo != GLAMOR_FBO_UNATTACHED)
746        return 0;
747
748    if (pixmap_priv->fbo
749        && (pixmap_priv->fbo->width < pixmap->drawable.width
750            || pixmap_priv->fbo->height < pixmap->drawable.height)) {
751        fbo = glamor_pixmap_detach_fbo(pixmap_priv);
752        glamor_destroy_fbo(glamor_priv, fbo);
753    }
754
755    if (pixmap_priv->fbo && pixmap_priv->fbo->fb)
756        return 0;
757
758    if (!(no_alpha || (revert == REVERT_NORMAL)
759          || (swap_rb != SWAP_NONE_UPLOADING))) {
760        /* We don't need a fbo, a simple texture uploading should work. */
761
762        flag = GLAMOR_CREATE_FBO_NO_FBO;
763    }
764
765    if ((flag == GLAMOR_CREATE_FBO_NO_FBO
766         && pixmap_priv->fbo && pixmap_priv->fbo->tex))
767        return 0;
768
769    if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP)
770        iformat = gl_iformat_for_pixmap(pixmap);
771    else
772        iformat = format;
773
774    if (!glamor_pixmap_ensure_fbo(pixmap, iformat, flag))
775        return -1;
776
777    return 0;
778}
779
780/*
781 * upload sub region to a large region.
782 * */
783static void
784glamor_put_bits(char *dst_bits, int dst_stride, char *src_bits,
785                int src_stride, int bpp, int x, int y, int w, int h)
786{
787    int j;
788    int byte_per_pixel;
789
790    byte_per_pixel = bpp / 8;
791    src_bits += y * src_stride + (x * byte_per_pixel);
792
793    for (j = y; j < y + h; j++) {
794        memcpy(dst_bits, src_bits, w * byte_per_pixel);
795        src_bits += src_stride;
796        dst_bits += dst_stride;
797    }
798}
799
800static Bool
801glamor_upload_sub_pixmap_to_texture(PixmapPtr pixmap, int x, int y, int w,
802                                    int h, int stride, void *bits, int pbo,
803                                    PictFormatShort pict_format)
804{
805    ScreenPtr screen = pixmap->drawable.pScreen;
806    glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
807    GLenum format, type;
808    int no_alpha, revert, swap_rb;
809    glamor_pixmap_private *pixmap_priv;
810    Bool force_clip;
811
812    if (glamor_get_tex_format_type_from_pixmap(pixmap,
813                                               pict_format,
814                                               &format,
815                                               &type,
816                                               &no_alpha,
817                                               &revert, &swap_rb, 1)) {
818        glamor_fallback("Unknown pixmap depth %d.\n", pixmap->drawable.depth);
819        return FALSE;
820    }
821    if (glamor_pixmap_upload_prepare(pixmap, format, no_alpha, revert, swap_rb))
822        return FALSE;
823
824    pixmap_priv = glamor_get_pixmap_private(pixmap);
825    force_clip = glamor_priv->gl_flavor != GLAMOR_GL_DESKTOP
826        && !glamor_check_fbo_size(glamor_priv, w, h);
827
828    if (glamor_pixmap_priv_is_large(pixmap_priv) || force_clip) {
829        RegionRec region;
830        BoxRec box;
831        int n_region;
832        glamor_pixmap_clipped_regions *clipped_regions;
833        void *sub_bits;
834        int i, j;
835
836        sub_bits = xallocarray(h, stride);
837        if (sub_bits == NULL)
838            return FALSE;
839        box.x1 = x;
840        box.y1 = y;
841        box.x2 = x + w;
842        box.y2 = y + h;
843        RegionInitBoxes(&region, &box, 1);
844        if (!force_clip)
845            clipped_regions =
846                glamor_compute_clipped_regions(pixmap, &region, &n_region,
847                                               0, 0, 0);
848        else
849            clipped_regions =
850                glamor_compute_clipped_regions_ext(pixmap, &region,
851                                                   &n_region,
852                                                   pixmap_priv->block_w,
853                                                   pixmap_priv->block_h,
854                                                   0,
855                                                   0);
856        DEBUGF("prepare upload %dx%d to a large pixmap %p\n", w, h, pixmap);
857        for (i = 0; i < n_region; i++) {
858            BoxPtr boxes;
859            int nbox;
860            int temp_stride;
861            void *temp_bits;
862
863            assert(pbo == 0);
864
865            glamor_set_pixmap_fbo_current(pixmap_priv, clipped_regions[i].block_idx);
866
867            boxes = RegionRects(clipped_regions[i].region);
868            nbox = RegionNumRects(clipped_regions[i].region);
869            DEBUGF("split to %d boxes\n", nbox);
870            for (j = 0; j < nbox; j++) {
871                temp_stride = PixmapBytePad(boxes[j].x2 - boxes[j].x1,
872                                            pixmap->drawable.depth);
873
874                if (boxes[j].x1 == x && temp_stride == stride) {
875                    temp_bits = (char *) bits + (boxes[j].y1 - y) * stride;
876                }
877                else {
878                    temp_bits = sub_bits;
879                    glamor_put_bits(temp_bits, temp_stride, bits, stride,
880                                    pixmap->drawable.bitsPerPixel,
881                                    boxes[j].x1 - x, boxes[j].y1 - y,
882                                    boxes[j].x2 - boxes[j].x1,
883                                    boxes[j].y2 - boxes[j].y1);
884                }
885                DEBUGF("upload x %d y %d w %d h %d temp stride %d \n",
886                       boxes[j].x1 - x, boxes[j].y1 - y,
887                       boxes[j].x2 - boxes[j].x1,
888                       boxes[j].y2 - boxes[j].y1, temp_stride);
889                if (_glamor_upload_bits_to_pixmap_texture
890                    (pixmap, format, type, no_alpha, revert, swap_rb,
891                     boxes[j].x1, boxes[j].y1, boxes[j].x2 - boxes[j].x1,
892                     boxes[j].y2 - boxes[j].y1, temp_stride, temp_bits,
893                     pbo) == FALSE) {
894                    RegionUninit(&region);
895                    free(sub_bits);
896                    assert(0);
897                    return FALSE;
898                }
899            }
900            RegionDestroy(clipped_regions[i].region);
901        }
902        free(sub_bits);
903        free(clipped_regions);
904        RegionUninit(&region);
905        return TRUE;
906    }
907    else
908        return _glamor_upload_bits_to_pixmap_texture(pixmap, format, type,
909                                                     no_alpha, revert, swap_rb,
910                                                     x, y, w, h, stride, bits,
911                                                     pbo);
912}
913
914/* Upload picture to texture.  We may need to flip the y axis or
915 * wire alpha to 1. So we may conditional create fbo for the picture.
916 * */
917enum glamor_pixmap_status
918glamor_upload_picture_to_texture(PicturePtr picture)
919{
920    PixmapPtr pixmap;
921
922    assert(picture->pDrawable);
923    pixmap = glamor_get_drawable_pixmap(picture->pDrawable);
924
925    if (glamor_upload_sub_pixmap_to_texture(pixmap, 0, 0,
926                                            pixmap->drawable.width,
927                                            pixmap->drawable.height,
928                                            pixmap->devKind,
929                                            pixmap->devPrivate.ptr, 0,
930                                            picture->format))
931        return GLAMOR_UPLOAD_DONE;
932    else
933        return GLAMOR_UPLOAD_FAILED;
934}
935