~brandontschaefer/+junk/break-x

« back to all changes in this revision

Viewing changes to glamor/glamor_glyphs.c

  • Committer: Brandon Schaefer
  • Date: 2014-09-30 19:38:40 UTC
  • Revision ID: brandon.schaefer@canonical.com-20140930193840-a65z6qk8ze02cgsb
* Init commit to back this up

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright © 2008 Red Hat, Inc.
 
3
 * Partly based on code Copyright © 2000 SuSE, Inc.
 
4
 *
 
5
 * Permission to use, copy, modify, distribute, and sell this software and its
 
6
 * documentation for any purpose is hereby granted without fee, provided that
 
7
 * the above copyright notice appear in all copies and that both that
 
8
 * copyright notice and this permission notice appear in supporting
 
9
 * documentation, and that the name of Red Hat not be used in advertising or
 
10
 * publicity pertaining to distribution of the software without specific,
 
11
 * written prior permission.  Red Hat makes no representations about the
 
12
 * suitability of this software for any purpose.  It is provided "as is"
 
13
 * without express or implied warranty.
 
14
 *
 
15
 * Red Hat DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
 
16
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL Red Hat
 
17
 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 
18
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
 
19
 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
 
20
 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
21
 *
 
22
 * Permission to use, copy, modify, distribute, and sell this software and its
 
23
 * documentation for any purpose is hereby granted without fee, provided that
 
24
 * the above copyright notice appear in all copies and that both that
 
25
 * copyright notice and this permission notice appear in supporting
 
26
 * documentation, and that the name of SuSE not be used in advertising or
 
27
 * publicity pertaining to distribution of the software without specific,
 
28
 * written prior permission.  SuSE makes no representations about the
 
29
 * suitability of this software for any purpose.  It is provided "as is"
 
30
 * without express or implied warranty.
 
31
 *
 
32
 * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
 
33
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE
 
34
 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 
35
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
 
36
 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
 
37
 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
38
 *
 
39
 * Author: Owen Taylor <otaylor@fishsoup.net>
 
40
 * Based on code by: Keith Packard
 
41
 */
 
42
 
 
43
#include <stdlib.h>
 
44
 
 
45
#include "glamor_priv.h"
 
46
 
 
47
#include <mipict.h>
 
48
 
 
49
#if DEBUG_GLYPH_CACHE
 
50
#define DBG_GLYPH_CACHE(a) ErrorF a
 
51
#else
 
52
#define DBG_GLYPH_CACHE(a)
 
53
#endif
 
54
 
 
55
/* Width of the pixmaps we use for the caches; this should be less than
 
56
 * max texture size of the driver; this may need to actually come from
 
57
 * the driver.
 
58
 */
 
59
 
 
60
/* Maximum number of glyphs we buffer on the stack before flushing
 
61
 * rendering to the mask or destination surface.
 
62
 */
 
63
#define GLYPH_BUFFER_SIZE 1024
 
64
 
 
65
#define CACHE_PICTURE_SIZE 1024
 
66
#define GLYPH_MIN_SIZE 8
 
67
#define GLYPH_MAX_SIZE  64
 
68
#define GLYPH_CACHE_SIZE ((CACHE_PICTURE_SIZE) * CACHE_PICTURE_SIZE / (GLYPH_MIN_SIZE * GLYPH_MIN_SIZE))
 
69
#define MASK_CACHE_MAX_SIZE 32
 
70
#define MASK_CACHE_WIDTH (CACHE_PICTURE_SIZE / MASK_CACHE_MAX_SIZE)
 
71
#define MASK_CACHE_MASK ((1LL << (MASK_CACHE_WIDTH)) - 1)
 
72
 
 
73
typedef struct {
 
74
    PicturePtr source;
 
75
    glamor_composite_rect_t rects[GLYPH_BUFFER_SIZE + 4];
 
76
    int count;
 
77
} glamor_glyph_buffer_t;
 
78
 
 
79
struct glamor_glyph {
 
80
    glamor_glyph_cache_t *cache;
 
81
    uint16_t x, y;
 
82
    uint16_t size, pos;
 
83
    unsigned long long left_x1_map, left_x2_map;
 
84
    unsigned long long right_x1_map, right_x2_map;      /* Use to check real intersect or not. */
 
85
    Bool has_edge_map;
 
86
    Bool cached;
 
87
};
 
88
 
 
89
typedef enum {
 
90
    GLAMOR_GLYPH_SUCCESS,       /* Glyph added to render buffer */
 
91
    GLAMOR_GLYPH_FAIL,          /* out of memory, etc */
 
92
    GLAMOR_GLYPH_NEED_FLUSH,    /* would evict a glyph already in the buffer */
 
93
} glamor_glyph_cache_result_t;
 
94
 
 
95
#define NeedsComponent(f) (PICT_FORMAT_A(f) != 0 && PICT_FORMAT_RGB(f) != 0)
 
96
static DevPrivateKeyRec glamor_glyph_key;
 
97
 
 
98
static inline struct glamor_glyph *
 
99
glamor_glyph_get_private(GlyphPtr glyph)
 
100
{
 
101
    return (struct glamor_glyph *) glyph->devPrivates;
 
102
}
 
103
 
 
104
/*
 
105
 * Mask cache is located at the corresponding cache picture's last row.
 
106
 * and is deadicated for the mask picture when do the glyphs_via_mask.
 
107
 *
 
108
 * As we split the glyphs list according to its overlapped or non-overlapped,
 
109
 * we can reduce the length of glyphs to do the glyphs_via_mask to 2 or 3
 
110
 * glyphs one time for most cases. Thus it give us a case to allocate a
 
111
 * small portion of the corresponding cache directly as the mask picture.
 
112
 * Then we can rendering the glyphs to this mask picture, and latter we
 
113
 * can accumulate the second steps, composite the mask to the dest with
 
114
 * the other non-overlapped glyphs's rendering process.
 
115
 * Another major benefit is we now only need to clear a relatively small mask
 
116
 * region then before. It also make us implement a bunch mask picture clearing
 
117
 * algorithm to avoid too frequently small region clearing.
 
118
 *
 
119
 * If there is no any overlapping, this method will not get performance gain.
 
120
 * If there is some overlapping, then this algorithm can get about 15% performance
 
121
 * gain.
 
122
 */
 
123
 
 
124
struct glamor_glyph_mask_cache_entry {
 
125
    int idx;
 
126
    int width;
 
127
    int height;
 
128
    int x;
 
129
    int y;
 
130
};
 
131
 
 
132
static struct glamor_glyph_mask_cache {
 
133
    PixmapPtr pixmap;
 
134
    struct glamor_glyph_mask_cache_entry mcache[MASK_CACHE_WIDTH];
 
135
    unsigned int free_bitmap;
 
136
    unsigned int cleared_bitmap;
 
137
} *mask_cache[GLAMOR_NUM_GLYPH_CACHE_FORMATS] = {
 
138
NULL};
 
139
 
 
140
static void
 
141
clear_mask_cache_bitmap(struct glamor_glyph_mask_cache *maskcache,
 
142
                        unsigned int clear_mask_bits)
 
143
{
 
144
    unsigned int i = 0;
 
145
    BoxRec box[MASK_CACHE_WIDTH];
 
146
    int box_cnt = 0;
 
147
 
 
148
    assert((clear_mask_bits & ~MASK_CACHE_MASK) == 0);
 
149
    for (i = 0; i < MASK_CACHE_WIDTH; i++) {
 
150
        if (clear_mask_bits & (1 << i)) {
 
151
            box[box_cnt].x1 = maskcache->mcache[i].x;
 
152
            box[box_cnt].x2 = maskcache->mcache[i].x + MASK_CACHE_MAX_SIZE;
 
153
            box[box_cnt].y1 = maskcache->mcache[i].y;
 
154
            box[box_cnt].y2 = maskcache->mcache[i].y + MASK_CACHE_MAX_SIZE;
 
155
            box_cnt++;
 
156
        }
 
157
    }
 
158
    glamor_solid_boxes(maskcache->pixmap, box, box_cnt, 0);
 
159
    maskcache->cleared_bitmap |= clear_mask_bits;
 
160
}
 
161
 
 
162
static void
 
163
clear_mask_cache(struct glamor_glyph_mask_cache *maskcache)
 
164
{
 
165
    int x = 0;
 
166
    int cnt = MASK_CACHE_WIDTH;
 
167
    unsigned int i = 0;
 
168
    struct glamor_glyph_mask_cache_entry *mce;
 
169
 
 
170
    glamor_solid(maskcache->pixmap, 0, CACHE_PICTURE_SIZE, CACHE_PICTURE_SIZE,
 
171
                 MASK_CACHE_MAX_SIZE, GXcopy, 0xFFFFFFFF, 0);
 
172
    mce = &maskcache->mcache[0];
 
173
    while (cnt--) {
 
174
        mce->width = 0;
 
175
        mce->height = 0;
 
176
        mce->x = x;
 
177
        mce->y = CACHE_PICTURE_SIZE;
 
178
        mce->idx = i++;
 
179
        x += MASK_CACHE_MAX_SIZE;
 
180
        mce++;
 
181
    }
 
182
    maskcache->free_bitmap = MASK_CACHE_MASK;
 
183
    maskcache->cleared_bitmap = MASK_CACHE_MASK;
 
184
}
 
185
 
 
186
static int
 
187
find_continuous_bits(unsigned int bits, int bits_cnt, unsigned int *pbits_mask)
 
188
{
 
189
    int idx = 0;
 
190
    unsigned int bits_mask;
 
191
 
 
192
    bits_mask = ((1LL << bits_cnt) - 1);
 
193
 
 
194
    if (_X_UNLIKELY(bits_cnt > 56)) {
 
195
        while (bits) {
 
196
            if ((bits & bits_mask) == bits_mask) {
 
197
                *pbits_mask = bits_mask << idx;
 
198
                return idx;
 
199
            }
 
200
            bits >>= 1;
 
201
            idx++;
 
202
        }
 
203
    }
 
204
    else {
 
205
        idx = __fls(bits);
 
206
        while (bits) {
 
207
            unsigned int temp_bits;
 
208
 
 
209
            temp_bits = bits_mask << (idx - bits_cnt + 1);
 
210
            if ((bits & temp_bits) == temp_bits) {
 
211
                *pbits_mask = temp_bits;
 
212
                return (idx - bits_cnt + 1);
 
213
            }
 
214
            /* Find first zero. And clear the tested bit. */
 
215
            bits &= ~(1LL << idx);
 
216
            idx = __fls(~bits);
 
217
            bits &= ~((1LL << idx) - 1);
 
218
            idx--;
 
219
        }
 
220
    }
 
221
    return -1;
 
222
}
 
223
 
 
224
static struct glamor_glyph_mask_cache_entry *
 
225
get_mask_cache(struct glamor_glyph_mask_cache *maskcache, int blocks)
 
226
{
 
227
    int free_cleared_bit, idx = -1;
 
228
    int retry_cnt = 0;
 
229
    unsigned int bits_mask = 0;
 
230
 
 
231
    if (maskcache->free_bitmap == 0)
 
232
        return NULL;
 
233
 retry:
 
234
    free_cleared_bit = maskcache->free_bitmap & maskcache->cleared_bitmap;
 
235
    if (free_cleared_bit && blocks == 1) {
 
236
        idx = __fls(free_cleared_bit);
 
237
        bits_mask = 1 << idx;
 
238
    }
 
239
    else if (free_cleared_bit && blocks > 1) {
 
240
        idx = find_continuous_bits(free_cleared_bit, blocks, &bits_mask);
 
241
    }
 
242
 
 
243
    if (idx < 0) {
 
244
        clear_mask_cache_bitmap(maskcache, maskcache->free_bitmap);
 
245
        if (retry_cnt++ > 2)
 
246
            return NULL;
 
247
        goto retry;
 
248
    }
 
249
 
 
250
    maskcache->cleared_bitmap &= ~bits_mask;
 
251
    maskcache->free_bitmap &= ~bits_mask;
 
252
    DEBUGF("get idx %d free %x clear %x \n",
 
253
           idx, maskcache->free_bitmap, maskcache->cleared_bitmap);
 
254
    return &maskcache->mcache[idx];
 
255
}
 
256
 
 
257
static void
 
258
put_mask_cache_bitmap(struct glamor_glyph_mask_cache *maskcache,
 
259
                      unsigned int bitmap)
 
260
{
 
261
    maskcache->free_bitmap |= bitmap;
 
262
    DEBUGF("put bitmap %x free %x clear %x \n",
 
263
           bitmap, maskcache->free_bitmap, maskcache->cleared_bitmap);
 
264
}
 
265
 
 
266
static void
 
267
glamor_unrealize_glyph_caches(ScreenPtr pScreen)
 
268
{
 
269
    glamor_screen_private *glamor = glamor_get_screen_private(pScreen);
 
270
    int i;
 
271
 
 
272
    if (!glamor->glyph_cache_initialized)
 
273
        return;
 
274
 
 
275
    for (i = 0; i < GLAMOR_NUM_GLYPH_CACHE_FORMATS; i++) {
 
276
        glamor_glyph_cache_t *cache = &glamor->glyphCaches[i];
 
277
 
 
278
        if (cache->picture)
 
279
            FreePicture(cache->picture, 0);
 
280
 
 
281
        if (cache->glyphs)
 
282
            free(cache->glyphs);
 
283
 
 
284
        if (mask_cache[i])
 
285
            free(mask_cache[i]);
 
286
    }
 
287
    glamor->glyph_cache_initialized = FALSE;
 
288
}
 
289
 
 
290
void
 
291
glamor_glyphs_fini(ScreenPtr pScreen)
 
292
{
 
293
    glamor_unrealize_glyph_caches(pScreen);
 
294
}
 
295
 
 
296
/* All caches for a single format share a single pixmap for glyph storage,
 
297
 * allowing mixing glyphs of different sizes without paying a penalty
 
298
 * for switching between source pixmaps. (Note that for a size of font
 
299
 * right at the border between two sizes, we might be switching for almost
 
300
 * every glyph.)
 
301
 *
 
302
 * This function allocates the storage pixmap, and then fills in the
 
303
 * rest of the allocated structures for all caches with the given format.
 
304
 */
 
305
 
 
306
Bool
 
307
glamor_realize_glyph_caches(ScreenPtr pScreen)
 
308
{
 
309
    glamor_screen_private *glamor = glamor_get_screen_private(pScreen);
 
310
 
 
311
    unsigned int formats[] = {
 
312
        PIXMAN_a8,
 
313
        PIXMAN_a8r8g8b8,
 
314
    };
 
315
    int i;
 
316
 
 
317
    memset(glamor->glyphCaches, 0, sizeof(glamor->glyphCaches));
 
318
 
 
319
    for (i = 0; i < sizeof(formats) / sizeof(formats[0]); i++) {
 
320
        glamor_glyph_cache_t *cache = &glamor->glyphCaches[i];
 
321
        PixmapPtr pixmap;
 
322
        PicturePtr picture;
 
323
        XID component_alpha;
 
324
        int depth = PIXMAN_FORMAT_DEPTH(formats[i]);
 
325
        int error;
 
326
        PictFormatPtr pPictFormat =
 
327
            PictureMatchFormat(pScreen, depth, formats[i]);
 
328
        if (!pPictFormat)
 
329
            goto bail;
 
330
 
 
331
        /* Now allocate the pixmap and picture */
 
332
        pixmap = pScreen->CreatePixmap(pScreen,
 
333
                                       CACHE_PICTURE_SIZE,
 
334
                                       CACHE_PICTURE_SIZE + MASK_CACHE_MAX_SIZE,
 
335
                                       depth, GLAMOR_CREATE_NO_LARGE);
 
336
        if (!pixmap)
 
337
            goto bail;
 
338
 
 
339
        component_alpha = NeedsComponent(pPictFormat->format);
 
340
        picture = CreatePicture(0, &pixmap->drawable, pPictFormat,
 
341
                                CPComponentAlpha, &component_alpha,
 
342
                                serverClient, &error);
 
343
 
 
344
        pScreen->DestroyPixmap(pixmap);
 
345
        if (!picture)
 
346
            goto bail;
 
347
 
 
348
        ValidatePicture(picture);
 
349
 
 
350
        cache->picture = picture;
 
351
        cache->glyphs = calloc(sizeof(GlyphPtr), GLYPH_CACHE_SIZE);
 
352
        if (!cache->glyphs)
 
353
            goto bail;
 
354
 
 
355
        cache->evict = rand() % GLYPH_CACHE_SIZE;
 
356
        mask_cache[i] = calloc(1, sizeof(*mask_cache[i]));
 
357
        mask_cache[i]->pixmap = pixmap;
 
358
        clear_mask_cache(mask_cache[i]);
 
359
    }
 
360
    assert(i == GLAMOR_NUM_GLYPH_CACHE_FORMATS);
 
361
 
 
362
    return TRUE;
 
363
 
 
364
 bail:
 
365
    glamor_unrealize_glyph_caches(pScreen);
 
366
    return FALSE;
 
367
}
 
368
 
 
369
/**
 
370
 * Called by glamor_create_screen_resources() to set up the glyph cache.
 
371
 *
 
372
 * This was previously required to be called by the drivers, but not
 
373
 * as of the xserver 1.16 ABI.
 
374
 */
 
375
Bool
 
376
glamor_glyphs_init(ScreenPtr pScreen)
 
377
{
 
378
    glamor_screen_private *glamor = glamor_get_screen_private(pScreen);
 
379
 
 
380
    if (glamor->glyph_cache_initialized)
 
381
        return TRUE;
 
382
 
 
383
    if (!dixRegisterPrivateKey(&glamor_glyph_key,
 
384
                               PRIVATE_GLYPH, sizeof(struct glamor_glyph)))
 
385
        return FALSE;
 
386
 
 
387
    glamor->glyph_cache_initialized = TRUE;
 
388
 
 
389
    return TRUE;
 
390
}
 
391
 
 
392
/* The most efficient thing to way to upload the glyph to the screen
 
393
 * is to use CopyArea; glamor pixmaps are always offscreen.
 
394
 */
 
395
static void
 
396
glamor_glyph_cache_upload_glyph(ScreenPtr screen,
 
397
                                glamor_glyph_cache_t *cache,
 
398
                                GlyphPtr glyph, int x, int y)
 
399
{
 
400
    PicturePtr pGlyphPicture = GlyphPicture(glyph)[screen->myNum];
 
401
    PixmapPtr pGlyphPixmap = (PixmapPtr) pGlyphPicture->pDrawable;
 
402
    PixmapPtr pCachePixmap = (PixmapPtr) cache->picture->pDrawable;
 
403
    PixmapPtr scratch;
 
404
    BoxRec box;
 
405
    GCPtr gc;
 
406
 
 
407
    gc = GetScratchGC(pCachePixmap->drawable.depth, screen);
 
408
    if (!gc)
 
409
        return;
 
410
 
 
411
    ValidateGC(&pCachePixmap->drawable, gc);
 
412
 
 
413
    scratch = pGlyphPixmap;
 
414
    if (pGlyphPixmap->drawable.depth != pCachePixmap->drawable.depth) {
 
415
 
 
416
        scratch = glamor_create_pixmap(screen,
 
417
                                       glyph->info.width,
 
418
                                       glyph->info.height,
 
419
                                       pCachePixmap->drawable.depth, 0);
 
420
        if (scratch) {
 
421
            PicturePtr picture;
 
422
            int error;
 
423
 
 
424
            picture =
 
425
                CreatePicture(0,
 
426
                              &scratch->drawable,
 
427
                              PictureMatchFormat
 
428
                              (screen,
 
429
                               pCachePixmap->drawable.depth,
 
430
                               cache->picture->format),
 
431
                              0, NULL, serverClient, &error);
 
432
            if (picture) {
 
433
                ValidatePicture(picture);
 
434
                glamor_composite(PictOpSrc,
 
435
                                 pGlyphPicture,
 
436
                                 NULL, picture,
 
437
                                 0, 0, 0, 0, 0,
 
438
                                 0, glyph->info.width, glyph->info.height);
 
439
                FreePicture(picture, 0);
 
440
            }
 
441
        }
 
442
        else {
 
443
            scratch = pGlyphPixmap;
 
444
        }
 
445
    }
 
446
 
 
447
    box.x1 = x;
 
448
    box.y1 = y;
 
449
    box.x2 = x + glyph->info.width;
 
450
    box.y2 = y + glyph->info.height;
 
451
    glamor_copy_n_to_n_nf(&scratch->drawable,
 
452
                          &pCachePixmap->drawable, NULL,
 
453
                          &box, 1, -x, -y, FALSE, FALSE, 0, NULL);
 
454
    if (scratch != pGlyphPixmap)
 
455
        screen->DestroyPixmap(scratch);
 
456
 
 
457
    FreeScratchGC(gc);
 
458
}
 
459
 
 
460
void
 
461
glamor_glyph_unrealize(ScreenPtr screen, GlyphPtr glyph)
 
462
{
 
463
    struct glamor_glyph *priv;
 
464
 
 
465
    /* Use Lookup in case we have not attached to this glyph. */
 
466
    priv = glamor_glyph_get_private(glyph);
 
467
 
 
468
    if (priv->cached)
 
469
        priv->cache->glyphs[priv->pos] = NULL;
 
470
}
 
471
 
 
472
/* Cut and paste from render/glyph.c - probably should export it instead */
 
473
static void
 
474
glamor_glyph_extents(int nlist,
 
475
                     GlyphListPtr list, GlyphPtr *glyphs, BoxPtr extents)
 
476
{
 
477
    int x1, x2, y1, y2;
 
478
    int x, y, n;
 
479
 
 
480
    x1 = y1 = MAXSHORT;
 
481
    x2 = y2 = MINSHORT;
 
482
    x = y = 0;
 
483
    while (nlist--) {
 
484
        x += list->xOff;
 
485
        y += list->yOff;
 
486
        n = list->len;
 
487
        list++;
 
488
        while (n--) {
 
489
            GlyphPtr glyph = *glyphs++;
 
490
            int v;
 
491
 
 
492
            v = x - glyph->info.x;
 
493
            if (v < x1)
 
494
                x1 = v;
 
495
            v += glyph->info.width;
 
496
            if (v > x2)
 
497
                x2 = v;
 
498
 
 
499
            v = y - glyph->info.y;
 
500
            if (v < y1)
 
501
                y1 = v;
 
502
            v += glyph->info.height;
 
503
            if (v > y2)
 
504
                y2 = v;
 
505
 
 
506
            x += glyph->info.xOff;
 
507
            y += glyph->info.yOff;
 
508
        }
 
509
    }
 
510
 
 
511
    extents->x1 = x1 < MINSHORT ? MINSHORT : x1;
 
512
    extents->x2 = x2 > MAXSHORT ? MAXSHORT : x2;
 
513
    extents->y1 = y1 < MINSHORT ? MINSHORT : y1;
 
514
    extents->y2 = y2 > MAXSHORT ? MAXSHORT : y2;
 
515
}
 
516
 
 
517
static void
 
518
glamor_glyph_priv_get_edge_map(GlyphPtr glyph, struct glamor_glyph *priv,
 
519
                               PicturePtr glyph_picture)
 
520
{
 
521
    PixmapPtr glyph_pixmap = (PixmapPtr) glyph_picture->pDrawable;
 
522
    int j;
 
523
    unsigned long long left_x1_map = 0, left_x2_map = 0;
 
524
    unsigned long long right_x1_map = 0, right_x2_map = 0;
 
525
    int bitsPerPixel;
 
526
    int stride;
 
527
    void *bits;
 
528
    int width;
 
529
    unsigned int left_x1_data = 0, left_x2_data = 0;
 
530
    unsigned int right_x1_data = 0, right_x2_data = 0;
 
531
 
 
532
    bitsPerPixel = glyph_pixmap->drawable.bitsPerPixel;
 
533
    stride = glyph_pixmap->devKind;
 
534
    bits = glyph_pixmap->devPrivate.ptr;
 
535
    width = glyph->info.width;
 
536
 
 
537
    if (glyph_pixmap->drawable.width < 2
 
538
        || !(glyph_pixmap->drawable.depth == 8
 
539
             || glyph_pixmap->drawable.depth == 1
 
540
             || glyph_pixmap->drawable.depth == 32)) {
 
541
        priv->has_edge_map = FALSE;
 
542
        return;
 
543
    }
 
544
 
 
545
    left_x1_map = left_x2_map = 0;
 
546
    right_x1_map = right_x2_map = 0;
 
547
 
 
548
    for (j = 0; j < glyph_pixmap->drawable.height; j++) {
 
549
        if (bitsPerPixel == 8) {
 
550
            unsigned char *data;
 
551
 
 
552
            data = (unsigned char *) ((unsigned char *) bits + stride * j);
 
553
            left_x1_data = *data++;
 
554
            left_x2_data = *data;
 
555
            data =
 
556
                (unsigned char *) ((unsigned char *) bits + stride * j + width -
 
557
                                   2);
 
558
            right_x1_data = *data++;
 
559
            right_x2_data = *data;
 
560
        }
 
561
        else if (bitsPerPixel == 32) {
 
562
            left_x1_data = *((unsigned int *) bits + stride / 4 * j);
 
563
            left_x2_data = *((unsigned int *) bits + stride / 4 * j + 1);
 
564
            right_x1_data =
 
565
                *((unsigned int *) bits + stride / 4 * j + width - 2);
 
566
            right_x2_data =
 
567
                *((unsigned int *) bits + stride / 4 * j + width - 1);
 
568
        }
 
569
        else if (bitsPerPixel == 1) {
 
570
            unsigned char temp;
 
571
 
 
572
            temp = *((unsigned char *) glyph_pixmap->devPrivate.ptr
 
573
                     + glyph_pixmap->devKind * j) & 0x3;
 
574
            left_x1_data = temp & 0x1;
 
575
            left_x2_data = temp & 0x2;
 
576
 
 
577
            temp = *((unsigned char *) glyph_pixmap->devPrivate.ptr
 
578
                     + glyph_pixmap->devKind * j
 
579
                     + (glyph_pixmap->drawable.width - 2) / 8);
 
580
            right_x1_data = temp
 
581
                & (1 << ((glyph_pixmap->drawable.width - 2) % 8));
 
582
            temp = *((unsigned char *) glyph_pixmap->devPrivate.ptr
 
583
                     + glyph_pixmap->devKind * j
 
584
                     + (glyph_pixmap->drawable.width - 1) / 8);
 
585
            right_x2_data = temp
 
586
                & (1 << ((glyph_pixmap->drawable.width - 1) % 8));
 
587
        }
 
588
        left_x1_map |= (left_x1_data != 0) << j;
 
589
        left_x2_map |= (left_x2_data != 0) << j;
 
590
        right_x1_map |= (right_x1_data != 0) << j;
 
591
        right_x2_map |= (right_x2_data != 0) << j;
 
592
    }
 
593
 
 
594
    priv->left_x1_map = left_x1_map;
 
595
    priv->left_x2_map = left_x2_map;
 
596
    priv->right_x1_map = right_x1_map;
 
597
    priv->right_x2_map = right_x2_map;
 
598
    priv->has_edge_map = TRUE;
 
599
    return;
 
600
}
 
601
 
 
602
/**
 
603
 * Returns TRUE if the glyphs in the lists intersect.  Only checks based on
 
604
 * bounding box, which appears to be good enough to catch most cases at least.
 
605
 */
 
606
 
 
607
#define INTERSECTED_TYPE_MASK 1
 
608
#define NON_INTERSECTED 0
 
609
#define INTERSECTED 1
 
610
 
 
611
struct glamor_glyph_list {
 
612
    int nlist;
 
613
    GlyphListPtr list;
 
614
    GlyphPtr *glyphs;
 
615
    int type;
 
616
};
 
617
 
 
618
static Bool
 
619
glyph_new_fixed_list(struct glamor_glyph_list *fixed_list,
 
620
                     GlyphPtr *cur_glyphs,
 
621
                     GlyphPtr ** head_glyphs,
 
622
                     GlyphListPtr cur_list,
 
623
                     int cur_pos, int cur_x, int cur_y,
 
624
                     int x1, int y1, int x2, int y2,
 
625
                     GlyphListPtr *head_list,
 
626
                     int *head_pos,
 
627
                     int *head_x,
 
628
                     int *head_y, int *fixed_cnt, int type, BoxPtr prev_extents)
 
629
{
 
630
    int x_off = 0;
 
631
    int y_off = 0;
 
632
    int n_off = 0;
 
633
    int list_cnt;
 
634
 
 
635
    if (type == NON_INTERSECTED) {
 
636
        if (x1 < prev_extents->x2 && x2 > prev_extents->x1
 
637
            && y1 < prev_extents->y2 && y2 > prev_extents->y1)
 
638
            return FALSE;
 
639
        x_off = (*(cur_glyphs - 1))->info.xOff;
 
640
        y_off = (*(cur_glyphs - 1))->info.yOff;
 
641
        n_off = 1;
 
642
    }
 
643
 
 
644
    list_cnt = cur_list - *head_list + 1;
 
645
    if (cur_pos <= n_off) {
 
646
        DEBUGF("break at %d n_off %d\n", cur_pos, n_off);
 
647
        list_cnt--;
 
648
        if (cur_pos < n_off) {
 
649
            /* we overlap with previous list's last glyph. */
 
650
            x_off += cur_list->xOff;
 
651
            y_off += cur_list->yOff;
 
652
            cur_list--;
 
653
            cur_pos = cur_list->len;
 
654
            if (cur_pos <= n_off) {
 
655
                list_cnt--;
 
656
            }
 
657
        }
 
658
    }
 
659
    DEBUGF("got %d lists\n", list_cnt);
 
660
    if (list_cnt != 0) {
 
661
        fixed_list->list = malloc(list_cnt * sizeof(*cur_list));
 
662
        memcpy(fixed_list->list, *head_list, list_cnt * sizeof(*cur_list));
 
663
        fixed_list->list[0].xOff = *head_x;
 
664
        fixed_list->list[0].yOff = *head_y;
 
665
        fixed_list->glyphs = *head_glyphs;
 
666
        fixed_list->type = type & INTERSECTED_TYPE_MASK;
 
667
        fixed_list->nlist = list_cnt;
 
668
        if (cur_list != *head_list) {
 
669
            fixed_list->list[0].len = (*head_list)->len - *head_pos;
 
670
            if (cur_pos != n_off)
 
671
                fixed_list->list[list_cnt - 1].len = cur_pos - n_off;
 
672
        }
 
673
        else
 
674
            fixed_list->list[0].len = cur_pos - *head_pos - n_off;
 
675
        (*fixed_cnt)++;
 
676
    }
 
677
 
 
678
    if (type <= INTERSECTED) {
 
679
        *head_list = cur_list;
 
680
        *head_pos = cur_pos - n_off;
 
681
        *head_x = cur_x - x_off;
 
682
        *head_y = cur_y - y_off;
 
683
        *head_glyphs = cur_glyphs - n_off;
 
684
    }
 
685
    return TRUE;
 
686
}
 
687
 
 
688
/*
 
689
 * This function detects glyph lists's overlapping.
 
690
 *
 
691
 * If check_fake_overlap is set, then it will check the glyph's left
 
692
 * and right small boxes's real overlapping pixels. And if there is
 
693
 * no real pixel overlapping, then it will not be treated as overlapped
 
694
 * case. And we also can configured it to ignore less than 2 pixels
 
695
 * overlappig.
 
696
 *
 
697
 * This function analyzes all the lists and split the list to multiple
 
698
 * lists which are pure overlapped glyph lists or pure non-overlapped
 
699
 * list if the overlapping only ocurr on the two adjacent glyphs.
 
700
 * Otherwise, it return -1.
 
701
 *
 
702
 **/
 
703
 
 
704
static int
 
705
glamor_glyphs_intersect(int nlist, GlyphListPtr list, GlyphPtr *glyphs,
 
706
                        PictFormatShort mask_format,
 
707
                        ScreenPtr screen, Bool check_fake_overlap,
 
708
                        struct glamor_glyph_list *fixed_list, int fixed_size)
 
709
{
 
710
    int x1, x2, y1, y2;
 
711
    int n;
 
712
    int x, y;
 
713
    BoxPtr extents;
 
714
    BoxRec prev_extents;
 
715
    Bool first = TRUE, first_list = TRUE;
 
716
    Bool need_free_list_region = FALSE;
 
717
    Bool need_free_fixed_list = FALSE;
 
718
    struct glamor_glyph *priv = NULL;
 
719
    Bool in_non_intersected_list = -1;
 
720
    GlyphListPtr head_list;
 
721
    int head_x, head_y, head_pos;
 
722
    int fixed_cnt = 0;
 
723
    GlyphPtr *head_glyphs;
 
724
    GlyphListPtr cur_list = list;
 
725
    RegionRec list_region;
 
726
    RegionRec current_region;
 
727
    BoxRec current_box;
 
728
 
 
729
    if (nlist > 1) {
 
730
        pixman_region_init(&list_region);
 
731
        need_free_list_region = TRUE;
 
732
    }
 
733
 
 
734
    pixman_region_init(&current_region);
 
735
 
 
736
    extents = pixman_region_extents(&current_region);
 
737
 
 
738
    x = 0;
 
739
    y = 0;
 
740
    x1 = x2 = y1 = y2 = 0;
 
741
    n = 0;
 
742
    extents->x1 = 0;
 
743
    extents->y1 = 0;
 
744
    extents->x2 = 0;
 
745
    extents->y2 = 0;
 
746
 
 
747
    head_list = list;
 
748
    DEBUGF("has %d lists.\n", nlist);
 
749
    while (nlist--) {
 
750
        BoxRec left_box, right_box = { 0 };
 
751
        Bool has_left_edge_box = FALSE, has_right_edge_box = FALSE;
 
752
        Bool left_to_right;
 
753
        struct glamor_glyph *left_priv = NULL, *right_priv = NULL;
 
754
 
 
755
        x += list->xOff;
 
756
        y += list->yOff;
 
757
        n = list->len;
 
758
        left_to_right = TRUE;
 
759
        cur_list = list++;
 
760
 
 
761
        if (_X_UNLIKELY(!first_list)) {
 
762
            pixman_region_init_with_extents(&current_region, extents);
 
763
            pixman_region_union(&list_region, &list_region, &current_region);
 
764
            first = TRUE;
 
765
        }
 
766
        else {
 
767
            head_list = cur_list;
 
768
            head_pos = cur_list->len - n;
 
769
            head_x = x;
 
770
            head_y = y;
 
771
            head_glyphs = glyphs;
 
772
        }
 
773
 
 
774
        DEBUGF("current list %p has %d glyphs\n", cur_list, n);
 
775
        while (n--) {
 
776
            GlyphPtr glyph = *glyphs++;
 
777
 
 
778
            DEBUGF("the %dth glyph\n", cur_list->len - n - 1);
 
779
            if (glyph->info.width == 0 || glyph->info.height == 0) {
 
780
                x += glyph->info.xOff;
 
781
                y += glyph->info.yOff;
 
782
                continue;
 
783
            }
 
784
            if (mask_format
 
785
                && mask_format != GlyphPicture(glyph)[screen->myNum]->format) {
 
786
                need_free_fixed_list = TRUE;
 
787
                goto done;
 
788
            }
 
789
 
 
790
            x1 = x - glyph->info.x;
 
791
            if (x1 < MINSHORT)
 
792
                x1 = MINSHORT;
 
793
            y1 = y - glyph->info.y;
 
794
            if (y1 < MINSHORT)
 
795
                y1 = MINSHORT;
 
796
            if (check_fake_overlap)
 
797
                priv = glamor_glyph_get_private(glyph);
 
798
 
 
799
            x2 = x1 + glyph->info.width;
 
800
            y2 = y1 + glyph->info.height;
 
801
 
 
802
            if (x2 > MAXSHORT)
 
803
                x2 = MAXSHORT;
 
804
            if (y2 > MAXSHORT)
 
805
                y2 = MAXSHORT;
 
806
 
 
807
            if (first) {
 
808
                extents->x1 = x1;
 
809
                extents->y1 = y1;
 
810
                extents->x2 = x2;
 
811
                extents->y2 = y2;
 
812
 
 
813
                prev_extents = *extents;
 
814
 
 
815
                first = FALSE;
 
816
                if (check_fake_overlap && priv
 
817
                    && priv->has_edge_map && glyph->info.yOff == 0) {
 
818
                    left_box.x1 = x1;
 
819
                    left_box.x2 = x1 + 1;
 
820
                    left_box.y1 = y1;
 
821
 
 
822
                    right_box.x1 = x2 - 2;
 
823
                    right_box.x2 = x2 - 1;
 
824
                    right_box.y1 = y1;
 
825
                    left_priv = right_priv = priv;
 
826
                    has_left_edge_box = TRUE;
 
827
                    has_right_edge_box = TRUE;
 
828
                }
 
829
            }
 
830
            else {
 
831
                if (_X_UNLIKELY(!first_list)) {
 
832
                    current_box.x1 = x1;
 
833
                    current_box.y1 = y1;
 
834
                    current_box.x2 = x2;
 
835
                    current_box.y2 = y2;
 
836
                    if (pixman_region_contains_rectangle
 
837
                        (&list_region, &current_box) != PIXMAN_REGION_OUT) {
 
838
                        need_free_fixed_list = TRUE;
 
839
                        goto done;
 
840
                    }
 
841
                }
 
842
 
 
843
                if (x1 < extents->x2 && x2 > extents->x1
 
844
                    && y1 < extents->y2 && y2 > extents->y1) {
 
845
 
 
846
                    if (check_fake_overlap &&
 
847
                        (has_left_edge_box || has_right_edge_box)
 
848
                        && priv->has_edge_map && glyph->info.yOff == 0) {
 
849
                        int left_dx, right_dx;
 
850
                        unsigned long long intersected;
 
851
 
 
852
                        left_dx = has_left_edge_box ? 1 : 0;
 
853
                        right_dx = has_right_edge_box ? 1 : 0;
 
854
                        if (x1 + 1 < extents->x2 - right_dx &&
 
855
                            x2 - 1 > extents->x1 + left_dx)
 
856
                            goto real_intersected;
 
857
 
 
858
                        if (left_to_right && has_right_edge_box) {
 
859
                            if (x1 == right_box.x1) {
 
860
                                intersected =
 
861
                                    ((priv->left_x1_map & right_priv->
 
862
                                      right_x1_map)
 
863
                                     | (priv->left_x2_map & right_priv->
 
864
                                        right_x2_map));
 
865
                                if (intersected)
 
866
                                    goto real_intersected;
 
867
                            }
 
868
                            else if (x1 == right_box.x2) {
 
869
                                intersected =
 
870
                                    (priv->left_x1_map & right_priv->
 
871
                                     right_x2_map);
 
872
                                if (intersected) {
 
873
#ifdef  GLYPHS_EDEGE_OVERLAP_LOOSE_CHECK
 
874
                                    /* tolerate with two pixels overlap. */
 
875
                                    intersected &= ~(1 << __fls(intersected));
 
876
                                    if ((intersected & (intersected - 1)))
 
877
#endif
 
878
                                        goto real_intersected;
 
879
                                }
 
880
                            }
 
881
                        }
 
882
                        else if (!left_to_right && has_left_edge_box) {
 
883
                            if (x2 - 1 == left_box.x1) {
 
884
                                intersected =
 
885
                                    (priv->right_x2_map & left_priv->
 
886
                                     left_x1_map);
 
887
                                if (intersected) {
 
888
#ifdef  GLYPHS_EDEGE_OVERLAP_LOOSE_CHECK
 
889
                                    /* tolerate with two pixels overlap. */
 
890
                                    intersected &= ~(1 << __fls(intersected));
 
891
                                    if ((intersected & (intersected - 1)))
 
892
#endif
 
893
                                        goto real_intersected;
 
894
                                }
 
895
                            }
 
896
                            else if (x2 - 1 == right_box.x2) {
 
897
                                if ((priv->right_x1_map & left_priv->
 
898
                                     left_x1_map)
 
899
                                    || (priv->right_x2_map & left_priv->
 
900
                                        left_x2_map))
 
901
                                    goto real_intersected;
 
902
                            }
 
903
                        }
 
904
                        else {
 
905
                            if (x1 < extents->x2 && x1 + 2 > extents->x1)
 
906
                                goto real_intersected;
 
907
                        }
 
908
                        goto non_intersected;
 
909
                    }
 
910
                    else {
 
911
 real_intersected:
 
912
                        DEBUGF("overlap with previous glyph.\n");
 
913
                        if (in_non_intersected_list == 1) {
 
914
                            if (fixed_cnt >= fixed_size) {
 
915
                                need_free_fixed_list = TRUE;
 
916
                                goto done;
 
917
                            }
 
918
                            if (!glyph_new_fixed_list(&fixed_list[fixed_cnt],
 
919
                                                      glyphs - 1,
 
920
                                                      &head_glyphs,
 
921
                                                      cur_list,
 
922
                                                      cur_list->len - (n + 1),
 
923
                                                      x, y, x1, y1, x2, y2,
 
924
                                                      &head_list, &head_pos,
 
925
                                                      &head_x, &head_y,
 
926
                                                      &fixed_cnt,
 
927
                                                      NON_INTERSECTED,
 
928
                                                      &prev_extents)) {
 
929
                                need_free_fixed_list = TRUE;
 
930
                                goto done;
 
931
                            }
 
932
                        }
 
933
 
 
934
                        in_non_intersected_list = 0;
 
935
 
 
936
                    }
 
937
                }
 
938
                else {
 
939
 non_intersected:
 
940
                    DEBUGF("doesn't overlap with previous glyph.\n");
 
941
                    if (in_non_intersected_list == 0) {
 
942
                        if (fixed_cnt >= fixed_size) {
 
943
                            need_free_fixed_list = TRUE;
 
944
                            goto done;
 
945
                        }
 
946
                        if (!glyph_new_fixed_list(&fixed_list[fixed_cnt],
 
947
                                                  glyphs - 1,
 
948
                                                  &head_glyphs,
 
949
                                                  cur_list,
 
950
                                                  cur_list->len - (n + 1), x, y,
 
951
                                                  x1, y1, x2, y2,
 
952
                                                  &head_list,
 
953
                                                  &head_pos,
 
954
                                                  &head_x,
 
955
                                                  &head_y, &fixed_cnt,
 
956
                                                  INTERSECTED, &prev_extents)) {
 
957
                            need_free_fixed_list = TRUE;
 
958
                            goto done;
 
959
                        }
 
960
                    }
 
961
                    in_non_intersected_list = 1;
 
962
                }
 
963
                prev_extents = *extents;
 
964
            }
 
965
 
 
966
            if (check_fake_overlap && priv
 
967
                && priv->has_edge_map && glyph->info.yOff == 0) {
 
968
                if (!has_left_edge_box || x1 < extents->x1) {
 
969
                    left_box.x1 = x1;
 
970
                    left_box.x2 = x1 + 1;
 
971
                    left_box.y1 = y1;
 
972
                    has_left_edge_box = TRUE;
 
973
                    left_priv = priv;
 
974
                }
 
975
 
 
976
                if (!has_right_edge_box || x2 > extents->x2) {
 
977
                    right_box.x1 = x2 - 2;
 
978
                    right_box.x2 = x2 - 1;
 
979
                    right_box.y1 = y1;
 
980
                    has_right_edge_box = TRUE;
 
981
                    right_priv = priv;
 
982
                }
 
983
            }
 
984
 
 
985
            if (x1 < extents->x1)
 
986
                extents->x1 = x1;
 
987
            if (x2 > extents->x2)
 
988
                extents->x2 = x2;
 
989
 
 
990
            if (y1 < extents->y1)
 
991
                extents->y1 = y1;
 
992
            if (y2 > extents->y2)
 
993
                extents->y2 = y2;
 
994
 
 
995
            x += glyph->info.xOff;
 
996
            y += glyph->info.yOff;
 
997
        }
 
998
        first_list = FALSE;
 
999
    }
 
1000
 
 
1001
    if (in_non_intersected_list == 0 && fixed_cnt == 0) {
 
1002
        fixed_cnt = -1;
 
1003
        goto done;
 
1004
    }
 
1005
 
 
1006
    if ((in_non_intersected_list != -1 || head_pos != n) && (fixed_cnt > 0)) {
 
1007
        if (fixed_cnt >= fixed_size) {
 
1008
            need_free_fixed_list = TRUE;
 
1009
            goto done;
 
1010
        }
 
1011
        if (!glyph_new_fixed_list(&fixed_list[fixed_cnt],
 
1012
                                  glyphs - 1,
 
1013
                                  &head_glyphs,
 
1014
                                  cur_list,
 
1015
                                  cur_list->len - (n + 1), x, y,
 
1016
                                  x1, y1, x2, y2,
 
1017
                                  &head_list,
 
1018
                                  &head_pos,
 
1019
                                  &head_x,
 
1020
                                  &head_y, &fixed_cnt,
 
1021
                                  (!in_non_intersected_list) | 0x80,
 
1022
                                  &prev_extents)) {
 
1023
            need_free_fixed_list = TRUE;
 
1024
            goto done;
 
1025
        }
 
1026
    }
 
1027
 
 
1028
 done:
 
1029
    if (need_free_list_region)
 
1030
        pixman_region_fini(&list_region);
 
1031
    pixman_region_fini(&current_region);
 
1032
 
 
1033
    if (need_free_fixed_list && fixed_cnt >= 0) {
 
1034
        while (fixed_cnt--) {
 
1035
            free(fixed_list[fixed_cnt].list);
 
1036
        }
 
1037
    }
 
1038
 
 
1039
    DEBUGF("Got %d fixed list \n", fixed_cnt);
 
1040
    return fixed_cnt;
 
1041
}
 
1042
 
 
1043
static inline unsigned int
 
1044
glamor_glyph_size_to_count(int size)
 
1045
{
 
1046
    size /= GLYPH_MIN_SIZE;
 
1047
    return size * size;
 
1048
}
 
1049
 
 
1050
static inline unsigned int
 
1051
glamor_glyph_count_to_mask(int count)
 
1052
{
 
1053
    return ~(count - 1);
 
1054
}
 
1055
 
 
1056
static inline unsigned int
 
1057
glamor_glyph_size_to_mask(int size)
 
1058
{
 
1059
    return glamor_glyph_count_to_mask(glamor_glyph_size_to_count(size));
 
1060
}
 
1061
 
 
1062
static PicturePtr
 
1063
glamor_glyph_cache(glamor_screen_private *glamor, GlyphPtr glyph, int *out_x,
 
1064
                   int *out_y)
 
1065
{
 
1066
    ScreenPtr screen = glamor->screen;
 
1067
    PicturePtr glyph_picture = GlyphPicture(glyph)[screen->myNum];
 
1068
    glamor_glyph_cache_t *cache =
 
1069
        &glamor->glyphCaches[PICT_FORMAT_RGB(glyph_picture->format) != 0];
 
1070
    struct glamor_glyph *priv = NULL, *evicted_priv = NULL;
 
1071
    int size, mask, pos, s;
 
1072
 
 
1073
    if (glyph->info.width > GLYPH_MAX_SIZE
 
1074
        || glyph->info.height > GLYPH_MAX_SIZE)
 
1075
        return NULL;
 
1076
 
 
1077
    for (size = GLYPH_MIN_SIZE; size <= GLYPH_MAX_SIZE; size *= 2)
 
1078
        if (glyph->info.width <= size && glyph->info.height <= size)
 
1079
            break;
 
1080
 
 
1081
    s = glamor_glyph_size_to_count(size);
 
1082
    mask = glamor_glyph_count_to_mask(s);
 
1083
    pos = (cache->count + s - 1) & mask;
 
1084
 
 
1085
    priv = glamor_glyph_get_private(glyph);
 
1086
    if (pos < GLYPH_CACHE_SIZE) {
 
1087
        cache->count = pos + s;
 
1088
    }
 
1089
    else {
 
1090
        for (s = size; s <= GLYPH_MAX_SIZE; s *= 2) {
 
1091
            int i = cache->evict & glamor_glyph_size_to_mask(s);
 
1092
            GlyphPtr evicted = cache->glyphs[i];
 
1093
 
 
1094
            if (evicted == NULL)
 
1095
                continue;
 
1096
 
 
1097
            evicted_priv = glamor_glyph_get_private(evicted);
 
1098
            assert(evicted_priv->pos == i);
 
1099
            if (evicted_priv->size >= s) {
 
1100
                cache->glyphs[i] = NULL;
 
1101
                evicted_priv->cached = FALSE;
 
1102
                pos = cache->evict & glamor_glyph_size_to_mask(size);
 
1103
            }
 
1104
            else
 
1105
                evicted_priv = NULL;
 
1106
            break;
 
1107
        }
 
1108
        if (evicted_priv == NULL) {
 
1109
            int count = glamor_glyph_size_to_count(size);
 
1110
 
 
1111
            mask = glamor_glyph_count_to_mask(count);
 
1112
            pos = cache->evict & mask;
 
1113
            for (s = 0; s < count; s++) {
 
1114
                GlyphPtr evicted = cache->glyphs[pos + s];
 
1115
 
 
1116
                if (evicted != NULL) {
 
1117
 
 
1118
                    evicted_priv = glamor_glyph_get_private(evicted);
 
1119
 
 
1120
                    assert(evicted_priv->pos == pos + s);
 
1121
                    evicted_priv->cached = FALSE;
 
1122
                    cache->glyphs[pos + s] = NULL;
 
1123
                }
 
1124
            }
 
1125
 
 
1126
        }
 
1127
        /* And pick a new eviction position */
 
1128
        cache->evict = rand() % GLYPH_CACHE_SIZE;
 
1129
    }
 
1130
 
 
1131
    cache->glyphs[pos] = glyph;
 
1132
 
 
1133
    priv->cache = cache;
 
1134
    priv->size = size;
 
1135
    priv->pos = pos;
 
1136
    s = pos / ((GLYPH_MAX_SIZE / GLYPH_MIN_SIZE) *
 
1137
               (GLYPH_MAX_SIZE / GLYPH_MIN_SIZE));
 
1138
    priv->x = s % (CACHE_PICTURE_SIZE / GLYPH_MAX_SIZE) * GLYPH_MAX_SIZE;
 
1139
    priv->y = (s / (CACHE_PICTURE_SIZE / GLYPH_MAX_SIZE)) * GLYPH_MAX_SIZE;
 
1140
    for (s = GLYPH_MIN_SIZE; s < GLYPH_MAX_SIZE; s *= 2) {
 
1141
        if (pos & 1)
 
1142
            priv->x += s;
 
1143
        if (pos & 2)
 
1144
            priv->y += s;
 
1145
        pos >>= 2;
 
1146
    }
 
1147
 
 
1148
    glamor_glyph_cache_upload_glyph(screen, cache, glyph, priv->x, priv->y);
 
1149
#ifndef GLYPHS_NO_EDEGEMAP_OVERLAP_CHECK
 
1150
    if (priv->has_edge_map == FALSE && glyph->info.width >= 2)
 
1151
        glamor_glyph_priv_get_edge_map(glyph, priv, glyph_picture);
 
1152
#endif
 
1153
    priv->cached = TRUE;
 
1154
 
 
1155
    *out_x = priv->x;
 
1156
    *out_y = priv->y;
 
1157
    return cache->picture;
 
1158
}
 
1159
 
 
1160
typedef void (*glyphs_flush_func) (void *arg);
 
1161
struct glyphs_flush_dst_arg {
 
1162
    CARD8 op;
 
1163
    PicturePtr src;
 
1164
    PicturePtr dst;
 
1165
    glamor_glyph_buffer_t *buffer;
 
1166
    int x_src, y_src;
 
1167
    int x_dst, y_dst;
 
1168
};
 
1169
 
 
1170
static struct glyphs_flush_dst_arg dst_arg;
 
1171
static struct glyphs_flush_mask_arg mask_arg;
 
1172
static glamor_glyph_buffer_t dst_buffer;
 
1173
static glamor_glyph_buffer_t mask_buffer;
 
1174
unsigned long long mask_glyphs_cnt = 0;
 
1175
unsigned long long dst_glyphs_cnt = 0;
 
1176
 
 
1177
#define GLYPHS_DST_MODE_VIA_MASK                0
 
1178
#define GLYPHS_DST_MODE_VIA_MASK_CACHE          1
 
1179
#define GLYPHS_DST_MODE_TO_DST                  2
 
1180
#define GLYPHS_DST_MODE_MASK_TO_DST             3
 
1181
 
 
1182
struct glyphs_flush_mask_arg {
 
1183
    PicturePtr mask;
 
1184
    glamor_glyph_buffer_t *buffer;
 
1185
    struct glamor_glyph_mask_cache *maskcache;
 
1186
    unsigned int used_bitmap;
 
1187
};
 
1188
 
 
1189
static void
 
1190
glamor_glyphs_flush_mask(struct glyphs_flush_mask_arg *arg)
 
1191
{
 
1192
    if (arg->buffer->count > 0) {
 
1193
#ifdef RENDER
 
1194
        glamor_composite_glyph_rects(PictOpAdd, arg->buffer->source,
 
1195
                                     NULL, arg->mask,
 
1196
                                     arg->buffer->count, arg->buffer->rects);
 
1197
#endif
 
1198
    }
 
1199
    arg->buffer->count = 0;
 
1200
    arg->buffer->source = NULL;
 
1201
 
 
1202
}
 
1203
 
 
1204
static void
 
1205
glamor_glyphs_flush_dst(struct glyphs_flush_dst_arg *arg)
 
1206
{
 
1207
    if (!arg->buffer)
 
1208
        return;
 
1209
 
 
1210
    if (mask_buffer.count > 0) {
 
1211
        glamor_glyphs_flush_mask(&mask_arg);
 
1212
    }
 
1213
    if (mask_arg.used_bitmap) {
 
1214
        put_mask_cache_bitmap(mask_arg.maskcache, mask_arg.used_bitmap);
 
1215
        mask_arg.used_bitmap = 0;
 
1216
    }
 
1217
 
 
1218
    if (arg->buffer->count > 0) {
 
1219
        glamor_composite_glyph_rects(arg->op, arg->src,
 
1220
                                     arg->buffer->source, arg->dst,
 
1221
                                     arg->buffer->count,
 
1222
                                     &arg->buffer->rects[0]);
 
1223
        arg->buffer->count = 0;
 
1224
        arg->buffer->source = NULL;
 
1225
    }
 
1226
}
 
1227
 
 
1228
static glamor_glyph_cache_result_t
 
1229
glamor_buffer_glyph(glamor_screen_private *glamor_priv,
 
1230
                    glamor_glyph_buffer_t *buffer,
 
1231
                    PictFormatShort format,
 
1232
                    GlyphPtr glyph, struct glamor_glyph *priv,
 
1233
                    int x_glyph, int y_glyph,
 
1234
                    int dx, int dy, int w, int h,
 
1235
                    int glyphs_dst_mode,
 
1236
                    glyphs_flush_func glyphs_flush, void *flush_arg)
 
1237
{
 
1238
    ScreenPtr screen = glamor_priv->screen;
 
1239
    glamor_composite_rect_t *rect;
 
1240
    PicturePtr source;
 
1241
    int x, y;
 
1242
    glamor_glyph_cache_t *cache;
 
1243
 
 
1244
    if (glyphs_dst_mode != GLYPHS_DST_MODE_MASK_TO_DST)
 
1245
        priv = glamor_glyph_get_private(glyph);
 
1246
 
 
1247
    if (PICT_FORMAT_BPP(format) == 1)
 
1248
        format = PICT_a8;
 
1249
 
 
1250
    cache = &glamor_priv->glyphCaches[PICT_FORMAT_RGB(format) != 0];
 
1251
 
 
1252
    if (buffer->source && buffer->source != cache->picture && glyphs_flush) {
 
1253
        (*glyphs_flush) (flush_arg);
 
1254
        glyphs_flush = NULL;
 
1255
    }
 
1256
 
 
1257
    if (buffer->count == GLYPH_BUFFER_SIZE && glyphs_flush) {
 
1258
        (*glyphs_flush) (flush_arg);
 
1259
        glyphs_flush = NULL;
 
1260
    }
 
1261
 
 
1262
    if (priv && priv->cached) {
 
1263
        rect = &buffer->rects[buffer->count++];
 
1264
        rect->x_src = priv->x + dx;
 
1265
        rect->y_src = priv->y + dy;
 
1266
        if (buffer->source == NULL)
 
1267
            buffer->source = priv->cache->picture;
 
1268
        if (glyphs_dst_mode <= GLYPHS_DST_MODE_VIA_MASK_CACHE)
 
1269
            assert(priv->cache->glyphs[priv->pos] == glyph);
 
1270
    }
 
1271
    else {
 
1272
        assert(glyphs_dst_mode != GLYPHS_DST_MODE_MASK_TO_DST);
 
1273
        if (glyphs_flush)
 
1274
            (*glyphs_flush) (flush_arg);
 
1275
        source = glamor_glyph_cache(glamor_priv, glyph, &x, &y);
 
1276
 
 
1277
        if (source != NULL) {
 
1278
            rect = &buffer->rects[buffer->count++];
 
1279
            rect->x_src = x + dx;
 
1280
            rect->y_src = y + dy;
 
1281
            if (buffer->source == NULL)
 
1282
                buffer->source = source;
 
1283
            if (glyphs_dst_mode == GLYPHS_DST_MODE_VIA_MASK_CACHE) {
 
1284
                /* mode 1 means we are using global mask cache,
 
1285
                 * thus we have to composite from the cache picture
 
1286
                 * to the cache picture, we need a flush here to make
 
1287
                 * sure latter we get the corret glyphs data.*/
 
1288
                glamor_make_current(glamor_priv);
 
1289
                glFlush();
 
1290
            }
 
1291
        }
 
1292
        else {
 
1293
            /* Couldn't find the glyph in the cache, use the glyph picture directly */
 
1294
            source = GlyphPicture(glyph)[screen->myNum];
 
1295
            if (buffer->source && buffer->source != source && glyphs_flush)
 
1296
                (*glyphs_flush) (flush_arg);
 
1297
            buffer->source = source;
 
1298
 
 
1299
            rect = &buffer->rects[buffer->count++];
 
1300
            rect->x_src = 0 + dx;
 
1301
            rect->y_src = 0 + dy;
 
1302
        }
 
1303
        priv = glamor_glyph_get_private(glyph);
 
1304
    }
 
1305
 
 
1306
    rect->x_dst = x_glyph;
 
1307
    rect->y_dst = y_glyph;
 
1308
    if (glyphs_dst_mode != GLYPHS_DST_MODE_MASK_TO_DST) {
 
1309
        rect->x_dst -= glyph->info.x;
 
1310
        rect->y_dst -= glyph->info.y;
 
1311
    }
 
1312
    rect->width = w;
 
1313
    rect->height = h;
 
1314
    if (glyphs_dst_mode > GLYPHS_DST_MODE_VIA_MASK_CACHE) {
 
1315
        rect->x_mask = rect->x_src;
 
1316
        rect->y_mask = rect->y_src;
 
1317
        rect->x_src = dst_arg.x_src + rect->x_dst - dst_arg.x_dst;
 
1318
        rect->y_src = dst_arg.y_src + rect->y_dst - dst_arg.y_dst;
 
1319
    }
 
1320
 
 
1321
    return GLAMOR_GLYPH_SUCCESS;
 
1322
}
 
1323
 
 
1324
static void
 
1325
glamor_buffer_glyph_clip(glamor_screen_private *glamor_priv,
 
1326
                         BoxPtr rects,
 
1327
                         int nrect, PictFormatShort format,
 
1328
                         GlyphPtr glyph, struct glamor_glyph *priv,
 
1329
                         int glyph_x, int glyph_y,
 
1330
                         int glyph_dx, int glyph_dy,
 
1331
                         int width, int height,
 
1332
                         int glyphs_mode,
 
1333
                         glyphs_flush_func flush_func, void *arg)
 
1334
{
 
1335
    int i;
 
1336
 
 
1337
    for (i = 0; i < nrect; i++) {
 
1338
        int dst_x, dst_y;
 
1339
        int dx, dy;
 
1340
        int x2, y2;
 
1341
 
 
1342
        dst_x = glyph_x - glyph_dx;
 
1343
        dst_y = glyph_y - glyph_dy;
 
1344
        x2 = dst_x + width;
 
1345
        y2 = dst_y + height;
 
1346
        dx = dy = 0;
 
1347
        if (rects[i].y1 >= y2)
 
1348
            break;
 
1349
 
 
1350
        if (dst_x < rects[i].x1)
 
1351
            dx = rects[i].x1 - dst_x, dst_x = rects[i].x1;
 
1352
        if (x2 > rects[i].x2)
 
1353
            x2 = rects[i].x2;
 
1354
        if (dst_y < rects[i].y1)
 
1355
            dy = rects[i].y1 - dst_y, dst_y = rects[i].y1;
 
1356
        if (y2 > rects[i].y2)
 
1357
            y2 = rects[i].y2;
 
1358
        if (dst_x < x2 && dst_y < y2) {
 
1359
 
 
1360
            glamor_buffer_glyph(glamor_priv,
 
1361
                                &dst_buffer,
 
1362
                                format,
 
1363
                                glyph, priv,
 
1364
                                dst_x + glyph_dx,
 
1365
                                dst_y + glyph_dy,
 
1366
                                dx, dy,
 
1367
                                x2 - dst_x, y2 - dst_y,
 
1368
                                glyphs_mode, flush_func, arg);
 
1369
        }
 
1370
    }
 
1371
}
 
1372
 
 
1373
static void
 
1374
glamor_glyphs_via_mask(CARD8 op,
 
1375
                       PicturePtr src,
 
1376
                       PicturePtr dst,
 
1377
                       PictFormatPtr mask_format,
 
1378
                       INT16 x_src,
 
1379
                       INT16 y_src,
 
1380
                       int nlist, GlyphListPtr list, GlyphPtr *glyphs,
 
1381
                       Bool use_mask_cache)
 
1382
{
 
1383
    PixmapPtr mask_pixmap = 0;
 
1384
    PicturePtr mask;
 
1385
    ScreenPtr screen = dst->pDrawable->pScreen;
 
1386
    int width = 0, height = 0;
 
1387
    int x, y;
 
1388
    int x_dst = list->xOff, y_dst = list->yOff;
 
1389
    int n;
 
1390
    GlyphPtr glyph;
 
1391
    int error;
 
1392
    BoxRec extents = { 0, 0, 0, 0 };
 
1393
    XID component_alpha;
 
1394
    glamor_screen_private *glamor_priv;
 
1395
    int need_free_mask = FALSE;
 
1396
    glamor_glyph_buffer_t buffer;
 
1397
    struct glyphs_flush_mask_arg arg;
 
1398
    glamor_glyph_buffer_t *pmask_buffer;
 
1399
    struct glyphs_flush_mask_arg *pmask_arg;
 
1400
    struct glamor_glyph_mask_cache_entry *mce = NULL;
 
1401
    struct glamor_glyph_mask_cache *maskcache;
 
1402
    glamor_glyph_cache_t *cache;
 
1403
    int glyphs_dst_mode;
 
1404
 
 
1405
    glamor_glyph_extents(nlist, list, glyphs, &extents);
 
1406
 
 
1407
    if (extents.x2 <= extents.x1 || extents.y2 <= extents.y1)
 
1408
        return;
 
1409
    glamor_priv = glamor_get_screen_private(screen);
 
1410
    width = extents.x2 - extents.x1;
 
1411
    height = extents.y2 - extents.y1;
 
1412
 
 
1413
    if (mask_format->depth == 1) {
 
1414
        PictFormatPtr a8Format = PictureMatchFormat(screen, 8, PICT_a8);
 
1415
 
 
1416
        if (a8Format)
 
1417
            mask_format = a8Format;
 
1418
    }
 
1419
 
 
1420
    cache = &glamor_priv->glyphCaches
 
1421
        [PICT_FORMAT_RGB(mask_format->format) != 0];
 
1422
    maskcache = mask_cache[PICT_FORMAT_RGB(mask_format->format) != 0];
 
1423
 
 
1424
    x = -extents.x1;
 
1425
    y = -extents.y1;
 
1426
    if (!use_mask_cache || width > (CACHE_PICTURE_SIZE / 4)
 
1427
        || height > MASK_CACHE_MAX_SIZE) {
 
1428
 new_mask_pixmap:
 
1429
        mask_pixmap = glamor_create_pixmap(screen, width, height,
 
1430
                                           mask_format->depth,
 
1431
                                           CREATE_PIXMAP_USAGE_SCRATCH);
 
1432
        if (!mask_pixmap) {
 
1433
            glamor_destroy_pixmap(mask_pixmap);
 
1434
            return;
 
1435
        }
 
1436
        glamor_solid(mask_pixmap, 0, 0, width, height, GXcopy, 0xFFFFFFFF, 0);
 
1437
        component_alpha = NeedsComponent(mask_format->format);
 
1438
        mask = CreatePicture(0, &mask_pixmap->drawable,
 
1439
                             mask_format, CPComponentAlpha,
 
1440
                             &component_alpha, serverClient, &error);
 
1441
        if (!mask)
 
1442
            return;
 
1443
        need_free_mask = TRUE;
 
1444
        pmask_arg = &arg;
 
1445
        pmask_buffer = &buffer;
 
1446
        pmask_buffer->count = 0;
 
1447
        pmask_buffer->source = NULL;
 
1448
        pmask_arg->used_bitmap = 0;
 
1449
        glyphs_dst_mode = GLYPHS_DST_MODE_VIA_MASK;
 
1450
    }
 
1451
    else {
 
1452
        int retry_cnt = 0;
 
1453
 
 
1454
 retry:
 
1455
        mce = get_mask_cache(maskcache,
 
1456
                             (width + MASK_CACHE_MAX_SIZE -
 
1457
                              1) / MASK_CACHE_MAX_SIZE);
 
1458
 
 
1459
        if (mce == NULL) {
 
1460
            glamor_glyphs_flush_dst(&dst_arg);
 
1461
            retry_cnt++;
 
1462
            if (retry_cnt > 2) {
 
1463
                assert(0);
 
1464
                goto new_mask_pixmap;
 
1465
            }
 
1466
            goto retry;
 
1467
        }
 
1468
 
 
1469
        mask = cache->picture;
 
1470
        x += mce->x;
 
1471
        y += mce->y;
 
1472
        mce->width = (width + MASK_CACHE_MAX_SIZE - 1) / MASK_CACHE_MAX_SIZE;
 
1473
        mce->height = 1;
 
1474
        if (mask_arg.mask && mask_arg.mask != mask && mask_buffer.count != 0)
 
1475
            glamor_glyphs_flush_dst(&dst_arg);
 
1476
        pmask_arg = &mask_arg;
 
1477
        pmask_buffer = &mask_buffer;
 
1478
        pmask_arg->maskcache = maskcache;
 
1479
        glyphs_dst_mode = GLYPHS_DST_MODE_VIA_MASK_CACHE;
 
1480
    }
 
1481
    pmask_arg->mask = mask;
 
1482
    pmask_arg->buffer = pmask_buffer;
 
1483
    while (nlist--) {
 
1484
        x += list->xOff;
 
1485
        y += list->yOff;
 
1486
        n = list->len;
 
1487
        mask_glyphs_cnt += n;
 
1488
        while (n--) {
 
1489
            glyph = *glyphs++;
 
1490
            if (glyph->info.width > 0 && glyph->info.height > 0) {
 
1491
                glyphs_flush_func flush_func;
 
1492
                void *temp_arg;
 
1493
 
 
1494
                if (need_free_mask) {
 
1495
                    if (pmask_buffer->count)
 
1496
                        flush_func =
 
1497
                            (glyphs_flush_func) glamor_glyphs_flush_mask;
 
1498
                    else
 
1499
                        flush_func = NULL;
 
1500
                    temp_arg = pmask_arg;
 
1501
                }
 
1502
                else {
 
1503
                    /* If we are using global mask cache, then we need to
 
1504
                     * flush dst instead of mask. As some dst depends on the
 
1505
                     * previous mask result. Just flush mask can't get all previous's
 
1506
                     * overlapped glyphs.*/
 
1507
                    if (dst_buffer.count || mask_buffer.count)
 
1508
                        flush_func =
 
1509
                            (glyphs_flush_func) glamor_glyphs_flush_dst;
 
1510
                    else
 
1511
                        flush_func = NULL;
 
1512
                    temp_arg = &dst_arg;
 
1513
                }
 
1514
                glamor_buffer_glyph(glamor_priv, pmask_buffer,
 
1515
                                    mask_format->format,
 
1516
                                    glyph, NULL, x, y,
 
1517
                                    0, 0,
 
1518
                                    glyph->info.width, glyph->info.height,
 
1519
                                    glyphs_dst_mode,
 
1520
                                    flush_func, (void *) temp_arg);
 
1521
            }
 
1522
            x += glyph->info.xOff;
 
1523
            y += glyph->info.yOff;
 
1524
        }
 
1525
        list++;
 
1526
    }
 
1527
 
 
1528
    x = extents.x1;
 
1529
    y = extents.y1;
 
1530
    if (need_free_mask) {
 
1531
        glamor_glyphs_flush_mask(pmask_arg);
 
1532
        CompositePicture(op,
 
1533
                         src,
 
1534
                         mask,
 
1535
                         dst,
 
1536
                         x_src + x - x_dst,
 
1537
                         y_src + y - y_dst, 0, 0, x, y, width, height);
 
1538
        FreePicture(mask, 0);
 
1539
        glamor_destroy_pixmap(mask_pixmap);
 
1540
    }
 
1541
    else {
 
1542
        struct glamor_glyph priv;
 
1543
        glyphs_flush_func flush_func;
 
1544
        BoxPtr rects;
 
1545
        int nrect;
 
1546
 
 
1547
        priv.cache = cache;
 
1548
        priv.x = mce->x;
 
1549
        priv.y = mce->y;
 
1550
        priv.cached = TRUE;
 
1551
        rects = REGION_RECTS(dst->pCompositeClip);
 
1552
        nrect = REGION_NUM_RECTS(dst->pCompositeClip);
 
1553
 
 
1554
        pmask_arg->used_bitmap |= ((1 << mce->width) - 1) << mce->idx;
 
1555
        dst_arg.op = op;
 
1556
        dst_arg.src = src;
 
1557
        dst_arg.dst = dst;
 
1558
        dst_arg.buffer = &dst_buffer;
 
1559
        dst_arg.x_src = x_src;
 
1560
        dst_arg.y_src = y_src;
 
1561
        dst_arg.x_dst = x_dst;
 
1562
        dst_arg.y_dst = y_dst;
 
1563
 
 
1564
        if (dst_buffer.source == NULL) {
 
1565
            dst_buffer.source = cache->picture;
 
1566
        }
 
1567
        else if (dst_buffer.source != cache->picture) {
 
1568
            glamor_glyphs_flush_dst(&dst_arg);
 
1569
            dst_buffer.source = cache->picture;
 
1570
        }
 
1571
 
 
1572
        x += dst->pDrawable->x;
 
1573
        y += dst->pDrawable->y;
 
1574
 
 
1575
        if (dst_buffer.count || mask_buffer.count)
 
1576
            flush_func = (glyphs_flush_func) glamor_glyphs_flush_dst;
 
1577
        else
 
1578
            flush_func = NULL;
 
1579
 
 
1580
        glamor_buffer_glyph_clip(glamor_priv,
 
1581
                                 rects, nrect,
 
1582
                                 mask_format->format,
 
1583
                                 NULL, &priv,
 
1584
                                 x, y,
 
1585
                                 0, 0,
 
1586
                                 width, height,
 
1587
                                 GLYPHS_DST_MODE_MASK_TO_DST,
 
1588
                                 flush_func, (void *) &dst_arg);
 
1589
    }
 
1590
}
 
1591
 
 
1592
static void
 
1593
glamor_glyphs_to_dst(CARD8 op,
 
1594
                     PicturePtr src,
 
1595
                     PicturePtr dst,
 
1596
                     INT16 x_src,
 
1597
                     INT16 y_src,
 
1598
                     int nlist, GlyphListPtr list, GlyphPtr *glyphs)
 
1599
{
 
1600
    ScreenPtr screen = dst->pDrawable->pScreen;
 
1601
    int x = 0, y = 0;
 
1602
    int x_dst = list->xOff, y_dst = list->yOff;
 
1603
    int n;
 
1604
    GlyphPtr glyph;
 
1605
    BoxPtr rects;
 
1606
    int nrect;
 
1607
    glamor_screen_private *glamor_priv;
 
1608
 
 
1609
    rects = REGION_RECTS(dst->pCompositeClip);
 
1610
    nrect = REGION_NUM_RECTS(dst->pCompositeClip);
 
1611
 
 
1612
    glamor_priv = glamor_get_screen_private(screen);
 
1613
 
 
1614
    dst_arg.op = op;
 
1615
    dst_arg.src = src;
 
1616
    dst_arg.dst = dst;
 
1617
    dst_arg.buffer = &dst_buffer;
 
1618
    dst_arg.x_src = x_src;
 
1619
    dst_arg.y_src = y_src;
 
1620
    dst_arg.x_dst = x_dst;
 
1621
    dst_arg.y_dst = y_dst;
 
1622
 
 
1623
    x = dst->pDrawable->x;
 
1624
    y = dst->pDrawable->y;
 
1625
 
 
1626
    while (nlist--) {
 
1627
        x += list->xOff;
 
1628
        y += list->yOff;
 
1629
        n = list->len;
 
1630
        dst_glyphs_cnt += n;
 
1631
        while (n--) {
 
1632
            glyph = *glyphs++;
 
1633
 
 
1634
            if (glyph->info.width > 0 && glyph->info.height > 0) {
 
1635
                glyphs_flush_func flush_func;
 
1636
 
 
1637
                if (dst_buffer.count || mask_buffer.count)
 
1638
                    flush_func = (glyphs_flush_func) glamor_glyphs_flush_dst;
 
1639
                else
 
1640
                    flush_func = NULL;
 
1641
                glamor_buffer_glyph_clip(glamor_priv,
 
1642
                                         rects, nrect,
 
1643
                                         (GlyphPicture(glyph)[screen->myNum])->
 
1644
                                         format, glyph, NULL, x, y,
 
1645
                                         glyph->info.x, glyph->info.y,
 
1646
                                         glyph->info.width, glyph->info.height,
 
1647
                                         GLYPHS_DST_MODE_TO_DST, flush_func,
 
1648
                                         (void *) &dst_arg);
 
1649
            }
 
1650
 
 
1651
            x += glyph->info.xOff;
 
1652
            y += glyph->info.yOff;
 
1653
        }
 
1654
        list++;
 
1655
    }
 
1656
}
 
1657
 
 
1658
#define MAX_FIXED_SIZE
 
1659
static void
 
1660
glamor_glyphs_reset_buffer(glamor_glyph_buffer_t *buffer)
 
1661
{
 
1662
    buffer->count = 0;
 
1663
    buffer->source = NULL;
 
1664
}
 
1665
 
 
1666
static Bool
 
1667
_glamor_glyphs(CARD8 op,
 
1668
               PicturePtr src,
 
1669
               PicturePtr dst,
 
1670
               PictFormatPtr mask_format,
 
1671
               INT16 x_src,
 
1672
               INT16 y_src, int nlist, GlyphListPtr list,
 
1673
               GlyphPtr *glyphs, Bool fallback)
 
1674
{
 
1675
    PictFormatShort format;
 
1676
    int fixed_size, fixed_cnt = 0;
 
1677
    struct glamor_glyph_list *fixed_list = NULL;
 
1678
    Bool need_free_list = FALSE;
 
1679
 
 
1680
#ifndef GLYPHS_NO_EDEGEMAP_OVERLAP_CHECK
 
1681
    Bool check_fake_overlap = TRUE;
 
1682
 
 
1683
    if (!(op == PictOpOver || op == PictOpAdd || op == PictOpXor)) {
 
1684
        /* C = (0,0,0,0) D = glyphs , SRC = A, DEST = B (faked overlapped glyphs, overlapped with (0,0,0,0)).
 
1685
         * For those op, (A IN (C ADD D)) OP B !=  (A IN D) OP ((A IN C) OP B)
 
1686
         *              or (A IN (D ADD C)) OP B != (A IN C) OP ((A IN D) OP B)
 
1687
         * We need to split the faked regions to three or two, and composite the disoverlapped small
 
1688
         * boxes one by one. For other Ops, it's safe to composite the whole box.  */
 
1689
        check_fake_overlap = FALSE;
 
1690
    }
 
1691
#else
 
1692
    Bool check_fake_overlap = FALSE;
 
1693
#endif
 
1694
    if (mask_format)
 
1695
        format = mask_format->depth << 24 | mask_format->format;
 
1696
    else
 
1697
        format = 0;
 
1698
 
 
1699
    fixed_size = 32;
 
1700
    glamor_glyphs_reset_buffer(&dst_buffer);
 
1701
 
 
1702
    if (!mask_format || (((nlist == 1 && list->len == 1) || op == PictOpAdd)
 
1703
                         && (dst->format ==
 
1704
                             ((mask_format->depth << 24) | mask_format->
 
1705
                              format)))) {
 
1706
        glamor_glyphs_to_dst(op, src, dst, x_src, y_src, nlist, list, glyphs);
 
1707
        goto last_flush;
 
1708
    }
 
1709
 
 
1710
    glamor_glyphs_reset_buffer(&mask_buffer);
 
1711
 
 
1712
    /* We have mask_format. Need to check the real overlap or not. */
 
1713
    format = mask_format->depth << 24 | mask_format->format;
 
1714
 
 
1715
    fixed_list = calloc(fixed_size, sizeof(*fixed_list));
 
1716
    if (_X_UNLIKELY(fixed_list == NULL))
 
1717
        fixed_size = 0;
 
1718
    fixed_cnt = glamor_glyphs_intersect(nlist, list, glyphs,
 
1719
                                        format, dst->pDrawable->pScreen,
 
1720
                                        check_fake_overlap,
 
1721
                                        fixed_list, fixed_size);
 
1722
    if (fixed_cnt == 0)
 
1723
        mask_format = NULL;
 
1724
    need_free_list = TRUE;
 
1725
 
 
1726
    if (fixed_cnt <= 0) {
 
1727
        if (mask_format == NULL) {
 
1728
            glamor_glyphs_to_dst(op, src, dst, x_src, y_src, nlist,
 
1729
                                 list, glyphs);
 
1730
            goto last_flush;
 
1731
        }
 
1732
        else {
 
1733
            glamor_glyphs_via_mask(op, src, dst, mask_format,
 
1734
                                   x_src, y_src, nlist, list, glyphs, FALSE);
 
1735
            goto free_fixed_list;
 
1736
        }
 
1737
    }
 
1738
    else {
 
1739
 
 
1740
        /* We have splitted the original list to serval list, some are overlapped
 
1741
         * and some are non-overlapped. For the non-overlapped, we render it to
 
1742
         * dst directly. For the overlapped, we render it to mask picture firstly,
 
1743
         * then render the mask to dst. If we can use mask cache which is in the
 
1744
         * glyphs cache's last row, we can accumulate the rendering of mask to dst
 
1745
         * with the other dst_buffer's rendering operations thus can reduce the call
 
1746
         * of glDrawElements.
 
1747
         *
 
1748
         * */
 
1749
        struct glamor_glyph_list *saved_list;
 
1750
 
 
1751
        saved_list = fixed_list;
 
1752
        mask_arg.used_bitmap = 0;
 
1753
        while (fixed_cnt--) {
 
1754
            if (fixed_list->type == NON_INTERSECTED) {
 
1755
                glamor_glyphs_to_dst(op, src, dst,
 
1756
                                     x_src, y_src,
 
1757
                                     fixed_list->nlist,
 
1758
                                     fixed_list->list, fixed_list->glyphs);
 
1759
            }
 
1760
            else
 
1761
                glamor_glyphs_via_mask(op, src, dst,
 
1762
                                       mask_format, x_src, y_src,
 
1763
                                       fixed_list->nlist,
 
1764
                                       fixed_list->list,
 
1765
                                       fixed_list->glyphs, TRUE);
 
1766
 
 
1767
            free(fixed_list->list);
 
1768
            fixed_list++;
 
1769
        }
 
1770
        free(saved_list);
 
1771
        need_free_list = FALSE;
 
1772
    }
 
1773
 
 
1774
 last_flush:
 
1775
    if (dst_buffer.count || mask_buffer.count)
 
1776
        glamor_glyphs_flush_dst(&dst_arg);
 
1777
 free_fixed_list:
 
1778
    if (need_free_list) {
 
1779
        assert(fixed_cnt <= 0);
 
1780
        free(fixed_list);
 
1781
    }
 
1782
    return TRUE;
 
1783
}
 
1784
 
 
1785
void
 
1786
glamor_glyphs(CARD8 op,
 
1787
              PicturePtr src,
 
1788
              PicturePtr dst,
 
1789
              PictFormatPtr mask_format,
 
1790
              INT16 x_src,
 
1791
              INT16 y_src, int nlist, GlyphListPtr list, GlyphPtr *glyphs)
 
1792
{
 
1793
    _glamor_glyphs(op, src, dst, mask_format, x_src,
 
1794
                   y_src, nlist, list, glyphs, TRUE);
 
1795
}
 
1796
 
 
1797
Bool
 
1798
glamor_glyphs_nf(CARD8 op,
 
1799
                 PicturePtr src,
 
1800
                 PicturePtr dst,
 
1801
                 PictFormatPtr mask_format,
 
1802
                 INT16 x_src,
 
1803
                 INT16 y_src, int nlist, GlyphListPtr list, GlyphPtr *glyphs)
 
1804
{
 
1805
    return _glamor_glyphs(op, src, dst, mask_format, x_src,
 
1806
                          y_src, nlist, list, glyphs, FALSE);
 
1807
}